diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..7ab3cb079 --- /dev/null +++ b/.clang-format @@ -0,0 +1,97 @@ +--- +Language: Cpp +# BasedOnStyle: Google +# More info: https://clang.llvm.org/docs/ClangFormatStyleOptions.html +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: GNU +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Merge +IncludeCategories: + - Regex: '^.*.h"' + Priority: 1 + - Regex: '^.*(boost|gflags|glog|gnsssdr|gpstk|gtest|gnuradio|pmt|uhd|volk)/' + Priority: 2 + - Regex: '^.*(armadillo|matio|pugixml)' + Priority: 2 + - Regex: '.*' + Priority: 3 + - Regex: '^<.*\.h>' + Priority: 4 + - Regex: '^<.*' + Priority: 5 +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..50fa566d0 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,3 @@ +--- +Checks: '-*,boost-use-to-string,cert-dcl21-cpp,cert-dcl58-cpp,cert-env33-c,cert-err52-cpp,cert-err60-cpp,cert-flp30-c,clang-analyzer-cplusplus*,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-build-namespaces,google-runtime-int,google-runtime-references,llvm-header-guard,misc-misplaced-const,misc-new-delete-overloads,misc-non-copyable-objects,misc-static-assert,misc-throw-by-value-catch-by-reference,misc-uniqueptr-reset-release,modernize-deprecated-headers,modernize-loop-convert,modernize-pass-by-value,modernize-raw-string-literal,modernize-use-auto,modernize-use-bool-literals,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-noexcept,modernize-use-nullptr,modernize-use-using,performance-faster-string-find,performance-inefficient-algorithm,performance-move-const-arg,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,readability-container-size-empty,readability-named-parameter,readability-non-const-parameter,readability-string-compare' +HeaderFilterRegex: '.*' diff --git a/.gitignore b/.gitignore index 2d1eebded..a128f1558 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ docs/latex docs/GNSS-SDR_manual.pdf src/tests/data/output.dat thirdparty/ +.settings .project .cproject +.idea +cmake-build-debug/ /install .DS_Store diff --git a/AUTHORS b/AUTHORS index 451c4a971..6f98d2038 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,57 +1,58 @@ -GNSS-SDR Authorship ------------------------------------------------------------------------------- - -The GNSS-SDR project is hosted and sponsored by the Centre Tecnologic de -Telecomunicacions de Catalunya (CTTC), a non-profit research foundation located -in Castelldefels (40.396764 N, 3.713379 E), 20 km south of Barcelona, Spain. -GNSS-SDR is the by-product of GNSS research conducted at the Communications -Systems Division of CTTC, and it is the combined effort of students, -software engineers and researchers from different institutions around the World. - -Contact Information ------------------------------------------------------------------------------- - GNSS-SDR Homepage - ---------------------------- - http://gnss-sdr.org - - - CTTC Homepage - ---------------------------- - http://www.cttc.cat - - - Mailing Lists - ---------------------------- - gnss-sdr-developers@lists.sourceforge.net - http://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers - - - Email - ---------------------------- - Inquiries beyond the mailing list can be sent to carles.fernandez@cttc.cat - - -List of authors ------------------------------------------------------------------------------- -Carles Fernandez-Prades carles.fernandez@cttc.cat Project manager -Javier Arribas javier.arribas@cttc.cat Developer -Luis Esteve Elfau luis@epsilon-formacion.com Developer -Pau Closas pau.closas@cttc.cat Consultant -Carlos Aviles carlos.avilesr@googlemail.com Developer -David Pubill david.pubill@cttc.cat Developer -Mara Branzanti mara.branzanti@gmail.com Developer -Marc Molina marc.molina.pena@gmail.com Developer -Daniel Fehr daniel.co@bluewin.ch Developer -Marc Sales marcsales92@gmail.com Developer -Damian Miralles dmiralles2009@gmail.com Developer -Andres Cecilia Luque a.cecilia.luque@gmail.com Developer -Leonardo Tonetto tonetto.dev@gmail.com Contributor -Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor -Fran Fabra fabra@ice.csic.es Contributor -Cillian O'Driscoll cillian.odriscoll@gmail.com Contributor -Ignacio Paniego ignacio.paniego@gmail.com Web design -Eva Puchol eva.puchol@gmail.com Web developer -Carlos Paniego carpanie@hotmail.com Artwork - - - +GNSS-SDR Authorship +------------------------------------------------------------------------------ + +The GNSS-SDR project is hosted and sponsored by the Centre Tecnològic de +Telecomunicacions de Catalunya (CTTC), a non-profit research foundation located +in Castelldefels (41.27504 N, 1.987709 E), 20 km south of Barcelona, Spain. +GNSS-SDR is the by-product of GNSS research conducted at the Communications +Systems Division of CTTC, and it is the combined effort of students, +software engineers and researchers from different institutions around the World. + +Contact Information +------------------------------------------------------------------------------ + GNSS-SDR Homepage + ---------------------------- + https://gnss-sdr.org + + + CTTC Homepage + ---------------------------- + http://www.cttc.cat + + + Mailing Lists + ---------------------------- + gnss-sdr-developers@lists.sourceforge.net + https://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers + + + Email + ---------------------------- + Inquiries beyond the mailing list can be sent to carles.fernandez@cttc.cat + + +List of authors +------------------------------------------------------------------------------ +Carles Fernández-Prades carles.fernandez@cttc.cat Project manager +Javier Arribas javier.arribas@cttc.es Developer +Luis Esteve Elfau luis@epsilon-formacion.com Developer +Antonio Ramos antonio.ramosdet@gmail.com Developer +Marc Majoral marc.majoral@cttc.cat Developer +Jordi Vilà-Valls jordi.vila@cttc.cat Consultant +Pau Closas pau.closas@northeastern.edu Consultant +Álvaro Cebrián Juan acebrianjuan@gmail.com Contributor +Andres Cecilia Luque a.cecilia.luque@gmail.com Contributor +Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor +Carlos Avilés carlos.avilesr@googlemail.com Contributor +Cillian O'Driscoll cillian.odriscoll@gmail.com Contributor +Damian Miralles dmiralles2009@gmail.com Contributor +Daniel Fehr daniel.co@bluewin.ch Contributor +David Pubill david.pubill@cttc.cat Contributor +Fran Fabra fabra@ice.csic.es Contributor +Gabriel Araujo gabriel.araujo.5000@gmail.com Contributor +Gerald LaMountain gerald@gece.neu.edu Contributor +Leonardo Tonetto tonetto.dev@gmail.com Contributor +Mara Branzanti mara.branzanti@gmail.com Contributor +Marc Molina marc.molina.pena@gmail.com Contributor +Marc Sales marcsales92@gmail.com Contributor +Carlos Paniego carpanie@hotmail.com Artwork diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ea7c79ba..10cb6b119 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # ######################################################################## @@ -21,7 +21,8 @@ ######################################################################## if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(WARNING "In-tree build is bad practice. Try 'cd build && cmake ../' ") -endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) +endif() + cmake_minimum_required(VERSION 2.8) project(gnss-sdr CXX C) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) @@ -30,23 +31,28 @@ file(RELATIVE_PATH RELATIVE_CMAKE_CALL ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRE if(NOT CMAKE_PREFIX_PATH) if(DEFINED ENV{PYBOMBS_PREFIX}) set(CMAKE_PREFIX_PATH $ENV{PYBOMBS_PREFIX}) - endif(DEFINED ENV{PYBOMBS_PREFIX}) + endif() if(DEFINED ENV{SNAP}) set(CMAKE_PREFIX_PATH $ENV{SNAP}) - endif(DEFINED ENV{SNAP}) -endif(NOT CMAKE_PREFIX_PATH) + endif() +endif() ######################################################################## # Determine optional blocks/libraries to be built (default: not built) -# Enable them here or at the command line by doing 'cmake -DENABLE_XXX=ON ../' +# Enable them at the command line by doing 'cmake -DENABLE_XXX=ON ../' ######################################################################## # Support of optional RF front-ends -option(ENABLE_OSMOSDR "Enable the use of OsmoSDR and other front-ends (RTL-based dongles, HackRF, bladeRF, etc.) as signal source (experimental)" OFF) +option(ENABLE_UHD "Enable the use of UHD (driver for all USRP devices)" ON) +option(ENABLE_OSMOSDR "Enable the use of OsmoSDR and other front-ends (RTL-based dongles, HackRF, bladeRF, etc.) as signal source" OFF) option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNURadio driver" OFF) option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal source (experimental)" OFF) option(ENABLE_GN3S "Enable the use of the GN3S dongle as signal source (experimental)" OFF) +option(ENABLE_PLUTOSDR "Enable the use of ADALM-PLUTO Evaluation Boards (Analog Devices Inc.), requires gr-iio" OFF) +option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requires gr-iio" OFF) +option(ENABLE_AD9361 "Enable the use of AD9361 directo to FPGA hardware, requires libiio" OFF) +option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) # Performance analysis tools option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF) @@ -56,6 +62,7 @@ option(ENABLE_GPROF "Enable the use of the GNU profiler tool 'gprof'" OFF) option(ENABLE_PROFILING "Enable execution of volk_gnsssdr_profile at the end of the building" OFF) option(ENABLE_OPENCL "Enable building of processing blocks implemented with OpenCL (experimental)" OFF) option(ENABLE_CUDA "Enable building of processing blocks implemented with CUDA (experimental, requires CUDA SDK)" OFF) +option(ENABLE_FPGA "Enable building of processing blocks implemented with FPGA (experimental, requires EZDMA driver)" OFF) # Building and packaging options option(ENABLE_GENERIC_ARCH "Builds a portable binary" OFF) @@ -65,17 +72,22 @@ option(ENABLE_OWN_ARMADILLO "Download and build Armadillo locally" OFF) option(ENABLE_LOG "Enable logging" ON) if(ENABLE_PACKAGING) set(ENABLE_GENERIC_ARCH ON) -endif(ENABLE_PACKAGING) +endif() # Testing option(ENABLE_UNIT_TESTING "Build unit tests" ON) +option(ENABLE_UNIT_TESTING_MINIMAL "Build a minimal set of unit tests" OFF) option(ENABLE_UNIT_TESTING_EXTRA "Download external files and build extra unit tests" OFF) option(ENABLE_SYSTEM_TESTING "Build system tests" OFF) option(ENABLE_SYSTEM_TESTING_EXTRA "Download external tools and build extra system tests" OFF) if(ENABLE_SYSTEM_TESTING_EXTRA) set(ENABLE_SYSTEM_TESTING ON) -endif(ENABLE_SYSTEM_TESTING_EXTRA) +endif() option(ENABLE_OWN_GPSTK "Force to download, build and link GPSTk for system tests, even if it is already installed" OFF) +option(ENABLE_INSTALL_TESTS "Install QA code system-wide" OFF) +if(ENABLE_FPGA) + set(ENABLE_INSTALL_TESTS ON) +endif() @@ -86,28 +98,27 @@ set(THIS_IS_A_RELEASE ON) # only related to version name, no further implicati if(NOT ${THIS_IS_A_RELEASE}) # Get the current working branch execute_process( - COMMAND git rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE ) - # Get the latest abbreviated commit hash of the working branch execute_process( - COMMAND git log -1 --format=%h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND git log -1 --format=%h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE ) -endif(NOT ${THIS_IS_A_RELEASE}) +endif() set(VERSION_INFO_MAJOR_VERSION 0) -set(VERSION_INFO_API_COMPAT 0) +set(VERSION_INFO_API_COMPAT 0) if(${THIS_IS_A_RELEASE}) - set(VERSION_INFO_MINOR_VERSION 9) -else(${THIS_IS_A_RELEASE}) - set(VERSION_INFO_MINOR_VERSION 9.git-${GIT_BRANCH}-${GIT_COMMIT_HASH}) -endif(${THIS_IS_A_RELEASE}) + set(VERSION_INFO_MINOR_VERSION 10) +else() + set(VERSION_INFO_MINOR_VERSION 10.git-${GIT_BRANCH}-${GIT_COMMIT_HASH}) +endif() set(VERSION ${VERSION_INFO_MAJOR_VERSION}.${VERSION_INFO_API_COMPAT}.${VERSION_INFO_MINOR_VERSION}) @@ -118,181 +129,281 @@ set(VERSION ${VERSION_INFO_MAJOR_VERSION}.${VERSION_INFO_API_COMPAT}.${VERSION_I ######################################################################## include(ExternalProject) # Detect 64-bits machine -if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - set(ARCH_64BITS TRUE) -endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCH_64BITS TRUE) +endif() set(OS_IS_MACOSX "") set(OS_IS_LINUX "") # Detect Linux Distribution if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(OperatingSystem "Linux") - set(OS_IS_LINUX TRUE) - if(ARCH_64BITS) - set(ARCH_ "(64 bits)") - else(ARCH_64BITS) - set(ARCH_ "(32 bits)") - endif(ARCH_64BITS) - if(EXISTS "/etc/lsb-release") - execute_process(COMMAND cat /etc/lsb-release - COMMAND grep DISTRIB_ID - COMMAND awk -F= "{ print $2 }" - COMMAND tr "\n" " " - COMMAND sed "s/ //" - OUTPUT_VARIABLE LINUX_DISTRIBUTION - RESULT_VARIABLE LINUX_ID_RESULT - ) - execute_process(COMMAND cat /etc/lsb-release - COMMAND grep DISTRIB_RELEASE - COMMAND awk -F= "{ print $2 }" - COMMAND tr "\n" " " - COMMAND sed "s/ //" - OUTPUT_VARIABLE LINUX_VER - RESULT_VARIABLE LINUX_VER_RESULT - ) - endif(EXISTS "/etc/lsb-release") - if(NOT LINUX_DISTRIBUTION) - if(EXISTS "/etc/linuxmint/info") - set(LINUX_DISTRIBUTION "LinuxMint") - execute_process(COMMAND cat /etc/linuxmint/info - COMMAND grep -m1 RELEASE - COMMAND awk -F= "{ print $2 }" - COMMAND tr "\n" " " - COMMAND sed "s/ //" - OUTPUT_VARIABLE LINUX_VER - RESULT_VARIABLE LINUX_VER_RESULT - ) - endif(EXISTS "/etc/linuxmint/info") - endif(NOT LINUX_DISTRIBUTION) - if(NOT LINUX_DISTRIBUTION) - if(EXISTS "/etc/os-release") - execute_process(COMMAND cat /etc/os-release - COMMAND grep -m1 NAME - COMMAND awk -F= "{ print $2 }" - COMMAND tr "\n" " " - COMMAND sed "s/ //" - OUTPUT_VARIABLE LINUX_DISTRIBUTION - RESULT_VARIABLE LINUX_ID_RESULT - ) - execute_process(COMMAND cat /etc/os-release - COMMAND grep VERSION_ID - COMMAND awk -F= "{ print $2 }" - COMMAND tr "\n" " " - COMMAND sed "s/ //" - OUTPUT_VARIABLE LINUX_VER - RESULT_VARIABLE LINUX_VER_RESULT - ) - if(${LINUX_DISTRIBUTION} MATCHES "Debian") - set(LINUX_DISTRIBUTION "Debian") - file(READ /etc/debian_version LINUX_VER) - endif(${LINUX_DISTRIBUTION} MATCHES "Debian") - endif(EXISTS "/etc/os-release") - endif(NOT LINUX_DISTRIBUTION) - if(NOT LINUX_DISTRIBUTION) - if(EXISTS "/etc/redhat-release") - set(LINUX_DISTRIBUTION "Red Hat") - file (READ /etc/redhat-release LINUX_VER) - endif(EXISTS "/etc/redhat-release") - endif(NOT LINUX_DISTRIBUTION) - if(NOT LINUX_DISTRIBUTION) - if(EXISTS "/etc/debian_version") - set(LINUX_DISTRIBUTION "Debian") - file (READ /etc/debian_version LINUX_VER) - endif(EXISTS "/etc/debian_version") - endif(NOT LINUX_DISTRIBUTION) - if(NOT LINUX_DISTRIBUTION) - set(LINUX_DISTRIBUTION "Generic") - set(LINUX_VER "Unknown") - endif(NOT LINUX_DISTRIBUTION) - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on ${LINUX_DISTRIBUTION} GNU/Linux Release ${LINUX_VER} ${ARCH_}") -endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(OperatingSystem "Linux") + set(OS_IS_LINUX TRUE) + if(ARCH_64BITS) + set(ARCH_ "(64 bits)") + else() + set(ARCH_ "(32 bits)") + endif() + if(EXISTS "/etc/lsb-release") + execute_process(COMMAND cat /etc/lsb-release + COMMAND grep DISTRIB_ID + COMMAND awk -F= "{ print $2 }" + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_DISTRIBUTION + RESULT_VARIABLE LINUX_ID_RESULT + ) + execute_process(COMMAND cat /etc/lsb-release + COMMAND grep DISTRIB_RELEASE + COMMAND awk -F= "{ print $2 }" + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_VER + RESULT_VARIABLE LINUX_VER_RESULT + ) + endif() + if(NOT LINUX_DISTRIBUTION) + if(EXISTS "/etc/linuxmint/info") + set(LINUX_DISTRIBUTION "LinuxMint") + execute_process(COMMAND cat /etc/linuxmint/info + COMMAND grep -m1 RELEASE + COMMAND awk -F= "{ print $2 }" + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_VER + RESULT_VARIABLE LINUX_VER_RESULT + ) + endif() + endif() + if(NOT LINUX_DISTRIBUTION) + if(EXISTS "/etc/os-release") + execute_process(COMMAND cat /etc/os-release + COMMAND grep -m1 NAME + COMMAND awk -F= "{ print $2 }" + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_DISTRIBUTION + RESULT_VARIABLE LINUX_ID_RESULT + ) + execute_process(COMMAND cat /etc/os-release + COMMAND grep VERSION_ID + COMMAND awk -F= "{ print $2 }" + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_VER + RESULT_VARIABLE LINUX_VER_RESULT + ) + if(${LINUX_DISTRIBUTION} MATCHES "Debian") + set(LINUX_DISTRIBUTION "Debian") + file(READ /etc/debian_version LINUX_VER) + endif() + endif() + endif() + if(NOT LINUX_DISTRIBUTION) + if(EXISTS "/etc/redhat-release") + set(LINUX_DISTRIBUTION "Red Hat") + file(READ /etc/redhat-release LINUX_VER) + endif() + endif() + if(NOT LINUX_DISTRIBUTION) + if(EXISTS "/etc/debian_version") + set(LINUX_DISTRIBUTION "Debian") + file(READ /etc/debian_version LINUX_VER) + endif() + endif() + if(NOT LINUX_DISTRIBUTION) + set(LINUX_DISTRIBUTION "Generic") + set(LINUX_VER "Unknown") + endif() + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on ${LINUX_DISTRIBUTION} GNU/Linux Release ${LINUX_VER} ${ARCH_}") +endif() +if(NOT LINUX_DISTRIBUTION) + set(LINUX_DISTRIBUTION "Unknown") +endif() -# Detect Mac OS X Version +# Detect macOS / Mac OS X Version if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(OperatingSystem "Mac OS X") - set(OS_IS_MACOSX TRUE) - exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) - string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) - if(${DARWIN_VERSION} MATCHES "16") - set(MACOS_SIERRA TRUE) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on macOS Sierra 10.12") - endif(${DARWIN_VERSION} MATCHES "16") - if(${DARWIN_VERSION} MATCHES "15") - set(MACOSX_EL_CAPITAN TRUE) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.11 El Capitan") - endif(${DARWIN_VERSION} MATCHES "15") - if(${DARWIN_VERSION} MATCHES "14") - set(MACOSX_YOSEMITE TRUE) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.10 Yosemite") - endif(${DARWIN_VERSION} MATCHES "14") - if(${DARWIN_VERSION} MATCHES "13") - set(MACOSX_MAVERICKS TRUE) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION="com.apple.compilers.llvm.clang.1_0") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.9 Mavericks") - endif(${DARWIN_VERSION} MATCHES "13") - if(${DARWIN_VERSION} MATCHES "12") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.8 Mountain Lion") - endif(${DARWIN_VERSION} MATCHES "12") - if(${DARWIN_VERSION} MATCHES "11") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.7 Lion") - endif(${DARWIN_VERSION} MATCHES "11") - if(${DARWIN_VERSION} MATCHES "10") - message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.6 Snow Leopard") - endif(${DARWIN_VERSION} MATCHES "10") -endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(OperatingSystem "Mac OS X") + set(OS_IS_MACOSX TRUE) + execute_process(COMMAND uname -v OUTPUT_VARIABLE DARWIN_VERSION) + string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) + if(${DARWIN_VERSION} MATCHES "18") + set(MACOS_MOJAVE TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on macOS Mojave 10.14") + endif() + if(${DARWIN_VERSION} MATCHES "17") + set(MACOS_HIGH_SIERRA TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on macOS High Sierra 10.13") + endif() + if(${DARWIN_VERSION} MATCHES "16") + set(MACOS_SIERRA TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on macOS Sierra 10.12") + endif() + if(${DARWIN_VERSION} MATCHES "15") + set(MACOSX_EL_CAPITAN TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.11 El Capitan") + endif() + if(${DARWIN_VERSION} MATCHES "14") + set(MACOSX_YOSEMITE TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.10 Yosemite") + endif() + if(${DARWIN_VERSION} MATCHES "13") + set(MACOSX_MAVERICKS TRUE) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION="com.apple.compilers.llvm.clang.1_0") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.9 Mavericks") + endif() + if(${DARWIN_VERSION} MATCHES "12") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.8 Mountain Lion") + endif() + if(${DARWIN_VERSION} MATCHES "11") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.7 Lion") + endif() + if(${DARWIN_VERSION} MATCHES "10") + message(STATUS "Configuring GNSS-SDR v${VERSION} to be built on Mac OS X 10.6 Snow Leopard") + endif() +endif() -#select the release build type by default to get optimization flags +# Define extra build types and select Release by default to get optimization flags +include(GnsssdrBuildTypes) +# Available options: +# - None: nothing set +# - Debug: -O2 -g +# - Release: -O3 +# - RelWithDebInfo: -O3 -g +# - MinSizeRel: -Os +# - Coverage: -Wall -pedantic -pthread -g -O0 -fprofile-arcs -ftest-coverage +# - NoOptWithASM: -O0 -g -save-temps +# - O2WithASM: -O2 -g -save-temps +# - O3WithASM: -O3 -g -save-temps +# - ASAN: -Wall -Wextra -g -O2 -fsanitize=address -fno-omit-frame-pointer if(NOT CMAKE_BUILD_TYPE) - if(ENABLE_GPERFTOOLS OR ENABLE_GPROF) - set(CMAKE_BUILD_TYPE "RelWithDebInfo") - message(STATUS "Build type not specified: defaulting to RelWithDebInfo.") - else(ENABLE_GPERFTOOLS OR ENABLE_GPROF) - set(CMAKE_BUILD_TYPE "Release") - message(STATUS "Build type not specified: defaulting to Release.") - endif(ENABLE_GPERFTOOLS OR ENABLE_GPROF) -else(NOT CMAKE_BUILD_TYPE) - message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.") -endif(NOT CMAKE_BUILD_TYPE) + if(ENABLE_GPERFTOOLS OR ENABLE_GPROF) + set(CMAKE_BUILD_TYPE "RelWithDebInfo") + message(STATUS "Build type not specified: defaulting to RelWithDebInfo.") + else() + set(CMAKE_BUILD_TYPE "Release") + message(STATUS "Build type not specified: defaulting to Release.") + endif() +else() + message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.") +endif() +gnsssdr_check_build_type(${CMAKE_BUILD_TYPE}) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") -# Append -O2 optimization flag for Debug builds -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O2") +# allow 'large' files in 32 bit builds +if(UNIX) + add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES) +endif() + +# Determine if we are using make or ninja +if(CMAKE_MAKE_PROGRAM MATCHES "make") + set(CMAKE_MAKE_PROGRAM_PRETTY_NAME "make") +endif() +if(CMAKE_MAKE_PROGRAM MATCHES "ninja") + set(CMAKE_MAKE_PROGRAM_PRETTY_NAME "ninja") +endif() +if(NOT CMAKE_MAKE_PROGRAM_PRETTY_NAME) + set(CMAKE_MAKE_PROGRAM_PRETTY_NAME "${CMAKE_MAKE_PROGRAM}") +endif() ################################################################################ -# Checkout cmake version +# Minimum required versions ################################################################################ -if(CMAKE_VERSION VERSION_LESS 2.8.8) - message(STATUS "Your CMake version is too old and does not support some features required by GNSS-SDR. CMake version must be at least 2.8.8. For more information check https://github.com/joakimkarlsson/bandit/issues/40") - message(FATAL_ERROR "Fatal error: CMake >= 2.8.8 required.") -endif(CMAKE_VERSION VERSION_LESS 2.8.8) +set(GNSSSDR_CMAKE_MIN_VERSION "2.8.8") +set(GNSSSDR_GCC_MIN_VERSION "4.7.2") +set(GNSSSDR_CLANG_MIN_VERSION "3.4.0") +set(GNSSSDR_APPLECLANG_MIN_VERSION "500") +set(GNSSSDR_GNURADIO_MIN_VERSION "3.7.3") +set(GNSSSDR_BOOST_MIN_VERSION "1.45") +set(GNSSSDR_PYTHON_MIN_VERSION "2.7") +set(GNSSSDR_PYTHON3_MIN_VERSION "3.4") +set(GNSSSDR_MAKO_MIN_VERSION "0.4.2") +set(GNSSSDR_ARMADILLO_MIN_VERSION "5.300.0") +set(GNSSSDR_MATIO_MIN_VERSION "1.5.3") ################################################################################ -# Checkout compiler version +# Versions to download and build (but not installed) if not found ################################################################################ -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) - message(STATUS "Your GCC version is too old and does not support some C++11 features required by GNSS-SDR. GCC version must be at least 4.7") - if(${LINUX_DISTRIBUTION} MATCHES "Ubuntu") - if(${LINUX_VER} MATCHES "12.04") - message(STATUS "For instructions on how to upgrade GCC, check http://askubuntu.com/a/271561") - endif(${LINUX_VER} MATCHES "12.04") - endif(${LINUX_DISTRIBUTION} MATCHES "Ubuntu") - message(FATAL_ERROR "Fatal error: GCC >= 4.7 required.") - endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) -endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") +set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.2") +set(GNSSSDR_GLOG_LOCAL_VERSION "0.3.5") +set(GNSSSDR_ARMADILLO_LOCAL_VERSION "9.200.x") +set(GNSSSDR_GTEST_LOCAL_VERSION "1.8.1") +set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master") +set(GNSSSDR_GPSTK_LOCAL_VERSION "2.10.6") +set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.13") +set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.9") + +if(CMAKE_VERSION VERSION_LESS "3.0.2") # Fix for CentOS 7 + set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.1") +endif() + + + +################################################################################ +# Check CMake version +################################################################################ +if(CMAKE_VERSION VERSION_LESS ${GNSSSDR_CMAKE_MIN_VERSION}) + message(STATUS "Your CMake version is too old and does not support some features required by GNSS-SDR. CMake version must be at least ${GNSSSDR_CMAKE_MIN_VERSION}.") + message(FATAL_ERROR "Fatal error: CMake >= ${GNSSSDR_CMAKE_MIN_VERSION} required.") +endif() + + + +################################################################################ +# Check compiler version +################################################################################ +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${GNSSSDR_GCC_MIN_VERSION}) + message(STATUS "Your GCC version is too old and does not support some C++ features required by GNSS-SDR. GCC version must be at least ${GNSSSDR_GCC_MIN_VERSION}") + message(FATAL_ERROR "Fatal error: GCC >= ${GNSSSDR_GCC_MIN_VERSION} required.") + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + execute_process(COMMAND + ${CMAKE_CXX_COMPILER} -v + RESULT_VARIABLE _res ERROR_VARIABLE _err + ERROR_STRIP_TRAILING_WHITESPACE) + if(${_res} STREQUAL "0") + # output is in error stream + string(REGEX MATCH "^Apple.*" IS_APPLE ${_err}) + if("${IS_APPLE}" STREQUAL "") + set(MIN_VERSION ${GNSSSDR_CLANG_MIN_VERSION}) + set(APPLE_STR "") + # retrieve the compiler's version from it + string(REGEX MATCH "clang version [0-9.]+" CLANG_OTHER_VERSION ${_err}) + string(REGEX MATCH "[0-9.]+" CLANG_VERSION ${CLANG_OTHER_VERSION}) + else() + set(MIN_VERSION ${GNSSSDR_APPLECLANG_MIN_VERSION}) + set(APPLE_STR "Apple ") + # retrieve the compiler's version from it + string(REGEX MATCH "(clang-[0-9.]+)" CLANG_APPLE_VERSION ${_err}) + string(REGEX MATCH "[0-9.]+" CLANG_VERSION ${CLANG_APPLE_VERSION}) + endif() + if(${CLANG_VERSION} VERSION_LESS "${MIN_VERSION}") + message(WARNING "\nThe compiler selected to build GNSS-SDR (${APPLE_STR}Clang version ${CLANG_VERSION} : ${CMAKE_CXX_COMPILER}) is older than that officially supported (${MIN_VERSION} minimum). This build may or not work. We highly recommend using Apple Clang version ${APPLECLANG_MIN_VERSION} or more recent, or Clang version ${CLANG_MIN_VERSION} or more recent.") + endif() + else() + message(WARNING "\nCannot determine the version of the compiler selected to build GNSS-SDR (${APPLE_STR}Clang : ${CMAKE_CXX_COMPILER}). This build may or not work. We highly recommend using Apple Clang version ${APPLECLANG_MIN_VERSION} or more recent, or Clang version ${CLANG_MIN_VERSION} or more recent.") + endif() +endif() @@ -302,10 +413,10 @@ endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if(NOT OS_IS_MACOSX) if(CMAKE_CROSSCOMPILING) set(IS_ARM TRUE) - else(CMAKE_CROSSCOMPILING) + else() include(TestForARM) - endif(CMAKE_CROSSCOMPILING) -endif(NOT OS_IS_MACOSX) + endif() +endif() @@ -313,18 +424,27 @@ endif(NOT OS_IS_MACOSX) # Check for availability of SSE ################################################################################ if(NOT ENABLE_GENERIC_ARCH) - include(TestForSSE) -endif(NOT ENABLE_GENERIC_ARCH) + include(TestForSSE) +endif() -############################### -# Find a thread library -############################### -if(OS_IS_LINUX) +################################################################################ +# Find the POSIX thread (pthread) libraries +################################################################################ +if(CMAKE_VERSION VERSION_LESS 3.1) find_package(Threads REQUIRED) - link_libraries(${CMAKE_THREAD_LIBS_INIT}) -endif(OS_IS_LINUX) + set(THREAD_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) +else() + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + if(CMAKE_CROSSCOMPILING) + set(THREADS_PREFER_PTHREAD_FLAG FALSE) + else() + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + endif() + find_package(Threads REQUIRED) + set(THREAD_LIBRARIES Threads::Threads) +endif() @@ -335,37 +455,37 @@ enable_testing() if(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) if(EXISTS $ENV{GTEST_DIR}) set(GTEST_DIR $ENV{GTEST_DIR}) - endif(EXISTS $ENV{GTEST_DIR}) + endif() if(GTEST_DIR) message(STATUS "Googletest root folder set at ${GTEST_DIR}") find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS ${GTEST_DIR}) if(LIBGTEST_DEV_DIR) - message (STATUS "Googletest has been found.") - else(LIBGTEST_DEV_DIR) - message (FATAL_ERROR " Googletest source code has not been found at ${GTEST_DIR}.") - endif(LIBGTEST_DEV_DIR) + message(STATUS "Googletest has been found.") + else() + message(FATAL_ERROR " Googletest source code has not been found at ${GTEST_DIR}.") + endif() find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS ${GTEST_DIR}/include) - else(GTEST_DIR) - find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS /usr/src/gtest /opt/local/src/gtest-1.7.0) + else() + find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS /usr/src/googletest/googletest /usr/src/gtest /usr/include/gtest /opt/local/src/gtest-1.7.0) find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS /usr/include /opt/local/src/gtest-1.7.0/include) if(LIBGTEST_DEV_DIR) - message (STATUS "Googletest (libgtest-dev package) has been found.") - else(LIBGTEST_DEV_DIR) - message (STATUS " Googletest has not been found.") - message (STATUS " Googletest will be downloaded and built automatically ") - message (STATUS " when doing 'make'. ") - endif(LIBGTEST_DEV_DIR) - endif(GTEST_DIR) -endif(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) + message(STATUS "Googletest package has been found.") + else() + message(STATUS " Googletest has not been found.") + message(STATUS " Googletest v${GNSSSDR_GTEST_LOCAL_VERSION} will be downloaded and built automatically ") + message(STATUS " when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'. ") + endif() + endif() +endif() ################################################################################ -# Boost - http://www.boost.org +# Boost - https://www.boost.org ################################################################################ if(UNIX AND EXISTS "/usr/lib64") list(APPEND BOOST_LIBRARYDIR "/usr/lib64") # Fedora 64-bit fix -endif(UNIX AND EXISTS "/usr/lib64") +endif() set(Boost_ADDITIONAL_VERSIONS "1.45.0" "1.45" "1.46.0" "1.46" "1.48.0" "1.48" "1.49.0" "1.49" "1.50.0" "1.50" "1.51.0" "1.51" "1.53.0" "1.53" "1.54.0" "1.54" @@ -373,58 +493,59 @@ set(Boost_ADDITIONAL_VERSIONS "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" "1.70.0" "1.70" "1.71.0" "1.71" "1.72.0" "1.72" "1.73.0" "1.73" "1.74.0" "1.74" + "1.75.0" "1.75" "1.76.0" "1.76" "1.77.0" "1.77" "1.78.0" "1.78" "1.79.0" "1.79" + "1.80.0" "1.80" "1.81.0" "1.81" "1.82.0" "1.82" "1.83.0" "1.83" "1.84.0" "1.84" ) set(Boost_USE_MULTITHREAD ON) set(Boost_USE_STATIC_LIBS OFF) -find_package(Boost COMPONENTS date_time system filesystem thread serialization chrono unit_test_framework program_options REQUIRED) +find_package(Boost COMPONENTS date_time system filesystem thread serialization chrono REQUIRED) if(NOT Boost_FOUND) - message(FATAL_ERROR "Fatal error: Boost (version >=1.45.0) required.") -endif(NOT Boost_FOUND) + message(FATAL_ERROR "Fatal error: Boost (version >=${GNSSSDR_BOOST_MIN_VERSION}) required.") +endif() ################################################################################ -# GNU Radio - http://gnuradio.org +# GNU Radio - https://gnuradio.org ################################################################################ set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG BLOCKS FFT FILTER PMT) -find_package(Gnuradio) +find_package(GNURADIO) if(PC_GNURADIO_RUNTIME_VERSION) - if(PC_GNURADIO_RUNTIME_VERSION VERSION_LESS 3.7.3) - set(GNURADIO_RUNTIME_FOUND) - message(STATUS "The GNU Radio version installed in your system is too old.") - endif(PC_GNURADIO_RUNTIME_VERSION VERSION_LESS 3.7.3) -endif(PC_GNURADIO_RUNTIME_VERSION) + if(PC_GNURADIO_RUNTIME_VERSION VERSION_LESS ${GNSSSDR_GNURADIO_MIN_VERSION}) + set(GNURADIO_RUNTIME_FOUND) + message(STATUS "The GNU Radio version installed in your system is too old.") + endif() +endif() if(NOT GNURADIO_RUNTIME_FOUND) - message(STATUS "CMake cannot find GNU Radio >= 3.7.3") - if(OS_IS_LINUX) - message("Go to https://github.com/gnuradio/pybombs") - message("and follow the instructions to install GNU Radio in your system.") - message(FATAL_ERROR "GNU Radio 3.7.3 or later is required to build gnss-sdr") - endif(OS_IS_LINUX) - if(OS_IS_MACOSX) - message("You can install it easily via Macports:") - message(" sudo port install gnuradio ") - message("Alternatively, you can use homebrew:") - message(" brew tap odrisci/gnuradio") - message(" brew install gnuradio" ) - message(FATAL_ERROR "GNU Radio 3.7.3 or later is required to build gnss-sdr") - endif(OS_IS_MACOSX) -endif(NOT GNURADIO_RUNTIME_FOUND) + message(STATUS "CMake cannot find GNU Radio >= ${GNSSSDR_GNURADIO_MIN_VERSION}") + if(OS_IS_LINUX) + message("Go to https://github.com/gnuradio/pybombs") + message("and follow the instructions to install GNU Radio in your system.") + message(FATAL_ERROR "GNU Radio ${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") + endif() + if(OS_IS_MACOSX) + message("You can install it easily via Macports:") + message(" sudo port install gnuradio ") + message("Alternatively, you can use homebrew:") + message(" brew install gnuradio") + message(FATAL_ERROR "GNU Radio ${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") + endif() +endif() if(NOT GNURADIO_ANALOG_FOUND) - message(FATAL_ERROR "*** The gnuradio-analog library v3.7.3 or later is required to build gnss-sdr") + message(FATAL_ERROR "*** The gnuradio-analog library v${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") endif() if(NOT GNURADIO_BLOCKS_FOUND) - message(FATAL_ERROR "*** The gnuradio-blocks library v3.7.3 or later is required to build gnss-sdr") + message(FATAL_ERROR "*** The gnuradio-blocks library v${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") endif() if(NOT GNURADIO_FILTER_FOUND) - message(FATAL_ERROR "*** The gnuradio-filter library v3.7.3 or later is required to build gnss-sdr") + message(FATAL_ERROR "*** The gnuradio-filter library v${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") endif() if(NOT GNURADIO_FFT_FOUND) - message(FATAL_ERROR "*** The gnuradio-fft library v3.7.3 or later is required to build gnss-sdr") + message(FATAL_ERROR "*** The gnuradio-fft library v${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") endif() if(NOT GNURADIO_PMT_FOUND) - message(FATAL_ERROR "*** The gnuradio-pmt library v3.7.3 or later is required to build gnss-sdr") + message(FATAL_ERROR "*** The gnuradio-pmt library v${GNSSSDR_GNURADIO_MIN_VERSION} or later is required to build gnss-sdr") endif() @@ -432,128 +553,163 @@ endif() ################################################################################ # VOLK - Vector-Optimized Library of Kernels ################################################################################ -find_package(Volk) +find_package(VOLK) if(NOT VOLK_FOUND) message(FATAL_ERROR "*** VOLK is required to build gnss-sdr") endif() +################################################################################ +# Log4cpp - http://log4cpp.sourceforge.net/ +################################################################################ +find_package(LOG4CPP) +if(NOT LOG4CPP_FOUND) + message(FATAL_ERROR "*** Log4cpp is required to build gnss-sdr") +endif() + + + ################################################################################ # volk_gnsssdr module - GNSS-SDR's own VOLK library ################################################################################ -find_package(VolkGnssSdr) - -if(NOT VOLK_GNSSSDR_FOUND) - message(STATUS " volk_gnsssdr will be built along with gnss-sdr when doing 'make'") +find_package(VOLKGNSSSDR) +if(NOT VOLKGNSSSDR_FOUND) + message(STATUS " volk_gnsssdr will be built along with gnss-sdr when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'") ############################### # Find Python required modules ############################### - include(SetupPython) #sets PYTHON_EXECUTABLE and PYTHON_DASH_B - GNSSSDR_PYTHON_CHECK_MODULE("python >= 2.7" sys "sys.version.split()[0] >= '2.7'" PYTHON_MIN_VER_FOUND) - GNSSSDR_PYTHON_CHECK_MODULE("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) - GNSSSDR_PYTHON_CHECK_MODULE("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + include(SetupPython) # sets PYTHON_EXECUTABLE and search for required modules if(NOT PYTHON_MIN_VER_FOUND) - message(FATAL_ERROR "Python 2.7 or greater required to build VOLK_GNSSSDR") + message(FATAL_ERROR "Python ${GNSSSDR_PYTHON_MIN_VERSION} or greater required to build VOLK_GNSSSDR") + endif() + + if(${PYTHON3}) + set(PYTHON_NAME "python3") + else() + set(PYTHON_NAME "python") endif() # Mako if(NOT MAKO_FOUND) - message(STATUS "Mako templates not found. See http://www.makotemplates.org/ ") + message(STATUS "Mako template library not found. See http://www.makotemplates.org/ ") message(STATUS " You can try to install it by typing:") if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo yum install python-mako") + message(STATUS " sudo yum install ${PYTHON_NAME}-mako") elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(STATUS " sudo zypper install python-Mako") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo apt-get install python-mako") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " sudo zypper install ${PYTHON_NAME}-Mako") + else() + message(STATUS " sudo apt-get install ${PYTHON_NAME}-mako") + endif() message(FATAL_ERROR "Mako templates required to build VOLK_GNSSSDR") - endif(NOT MAKO_FOUND) + endif() # Six if(NOT SIX_FOUND) message(STATUS "python-six not found. See https://pythonhosted.org/six/ ") message(STATUS " You can try to install it by typing:") if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo yum install python-six") + message(STATUS " sudo yum install ${PYTHON_NAME}-six") elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(STATUS " sudo zypper install python-six") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo apt-get install python-six") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " sudo zypper install ${PYTHON_NAME}-six") + else() + message(STATUS " sudo apt-get install ${PYTHON_NAME}-six") + endif() message(FATAL_ERROR "six - python 2 and 3 compatibility library required to build VOLK_GNSSSDR") - endif(NOT SIX_FOUND) + endif() + set(READ_ENVIRO "") if(ENABLE_PACKAGING) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) - set(STRIP_VOLK_GNSSSDR_PROFILE "-DENABLE_STRIP=ON") - endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) - endif(ENABLE_PACKAGING) + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) + set(STRIP_VOLK_GNSSSDR_PROFILE "-DENABLE_STRIP=ON -DCMAKE_VERBOSE_MAKEFILE=ON") + endif() + if(NOT DEFINED ENV{PROTECT_PASSWORDS}) + set(READ_ENVIRO ${CMAKE_COMMAND} -E environment) + endif() + endif() - set(VOLK_GNSSSDR_BUILD_COMMAND "make") + set(VOLK_GNSSSDR_BUILD_COMMAND "${CMAKE_MAKE_PROGRAM}") if(PYTHON_EXECUTABLE) set(USE_THIS_PYTHON "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}") - endif(PYTHON_EXECUTABLE) + endif() if(OS_IS_MACOSX) if(CMAKE_GENERATOR STREQUAL Xcode) set(VOLK_GNSSSDR_BUILD_COMMAND "xcodebuild" "-configuration" "Debug" "-target") - endif(CMAKE_GENERATOR STREQUAL Xcode) - endif(OS_IS_MACOSX) + endif() + endif() - set(CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - set(C_FLAGS "${CMAKE_C_FLAGS} -std=c11") - if(CMAKE_CROSSCOMPILING) - set(VOLK_GNSSSDR_COMPILER "") - else(CMAKE_CROSSCOMPILING) + if(CMAKE_CROSSCOMPILING) + set(VOLK_GNSSSDR_COMPILER "") + else() set(VOLK_GNSSSDR_COMPILER -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) - endif(CMAKE_CROSSCOMPILING) + endif() set(VOLK_GNSSSDR_CMAKE_ARGS ${VOLK_GNSSSDR_COMPILER} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install - -DENABLE_STATIC_LIBS=ON - -DENABLE_PROFILING=${ENABLE_PROFILING} - -DCMAKE_CXX_FLAGS=${CXX_FLAGS} - -DCMAKE_C_FLAGS=${C_FLAGS} - -DCMAKE_INCLUDE_PATH=${Boost_INCLUDE_DIR} - ${STRIP_VOLK_GNSSSDR_PROFILE} - ${USE_THIS_PYTHON} ) + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install + -DENABLE_STATIC_LIBS=ON + -DENABLE_PROFILING=${ENABLE_PROFILING} + -DCMAKE_INCLUDE_PATH=${Boost_INCLUDE_DIR} + -DENABLE_ORC=OFF + ${STRIP_VOLK_GNSSSDR_PROFILE} + ${USE_THIS_PYTHON}) if(EXISTS $ENV{OECORE_TARGET_SYSROOT}) - set(VOLK_GNSSSDR_CMAKE_ARGS ${VOLK_GNSSSDR_CMAKE_ARGS} - -DENABLE_ORC=OFF - -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/Toolchains/oe-sdk_cross.cmake - -DCROSSCOMPILE_MULTILIB=TRUE ) - endif(EXISTS $ENV{OECORE_TARGET_SYSROOT}) - ExternalProject_Add(volk_gnsssdr_module - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/build - CMAKE_ARGS ${VOLK_GNSSSDR_CMAKE_ARGS} - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - PATCH_COMMAND "" - BUILD_COMMAND ${VOLK_GNSSSDR_BUILD_COMMAND} volk_gnsssdr_profile - INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install - ) + set(VOLK_GNSSSDR_CMAKE_ARGS ${VOLK_GNSSSDR_CMAKE_ARGS} + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/Toolchains/oe-sdk_cross.cmake + -DCROSSCOMPILE_MULTILIB=TRUE) + endif() + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(volk_gnsssdr_module + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/build + CMAKE_ARGS ${READ_ENVIRO} ${VOLK_GNSSSDR_CMAKE_ARGS} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + PATCH_COMMAND "" + BUILD_COMMAND ${READ_ENVIRO} ${VOLK_GNSSSDR_BUILD_COMMAND} volk_gnsssdr_profile + INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install + ) + else() + ExternalProject_Add(volk_gnsssdr_module + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/build + CMAKE_ARGS ${READ_ENVIRO} ${VOLK_GNSSSDR_CMAKE_ARGS} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + PATCH_COMMAND "" + BUILD_COMMAND ${READ_ENVIRO} ${VOLK_GNSSSDR_BUILD_COMMAND} volk_gnsssdr_profile + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/lib/${CMAKE_FIND_LIBRARY_PREFIXES}volk_gnsssdr${CMAKE_STATIC_LIBRARY_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/bin/volk_gnsssdr_profile + INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install + ) + endif() find_package(ORC) if(NOT ORC_FOUND) - set(ORC_LIBRARIES "") - set(ORC_INCLUDE_DIRS "") - endif(NOT ORC_FOUND) + set(ORC_LIBRARIES "") + set(ORC_INCLUDE_DIRS "") + endif() add_library(volk_gnsssdr UNKNOWN IMPORTED) - set_property(TARGET volk_gnsssdr PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/lib/libvolk_gnsssdr.a) + set_property(TARGET volk_gnsssdr PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/lib/libvolk_gnsssdr${CMAKE_STATIC_LIBRARY_SUFFIX}) set(VOLK_GNSSSDR_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/build/include/;${CMAKE_CURRENT_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include;${ORC_INCLUDE_DIRS}") set(VOLK_GNSSSDR_LIBRARIES volk_gnsssdr ${ORC_LIBRARIES}) - add_custom_command(TARGET volk_gnsssdr_module POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/bin/volk_gnsssdr_profile - ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr_profile) + if(CMAKE_VERSION VERSION_LESS 3.2) + add_custom_command(TARGET volk_gnsssdr_module POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/bin/volk_gnsssdr_profile + ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr_profile) + else() + add_custom_command(TARGET volk_gnsssdr_module POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/bin/volk_gnsssdr_profile + ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr_profile + BYPRODUCTS ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr_profile) + endif() add_custom_command(TARGET volk_gnsssdr_module POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr_module/install/bin/volk_gnsssdr-config-info - ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr-config-info) -endif(NOT VOLK_GNSSSDR_FOUND) + ${CMAKE_SOURCE_DIR}/install/volk_gnsssdr-config-info) +endif() @@ -561,43 +717,57 @@ endif(NOT VOLK_GNSSSDR_FOUND) # gflags - https://github.com/gflags/gflags ################################################################################ set(LOCAL_GFLAGS false) -set(gflags_RELEASE 2.2.0) -find_package(GFlags) -if (NOT GFlags_FOUND) - message (STATUS " gflags library has not been found.") - message (STATUS " gflags will be downloaded and built automatically ") - message (STATUS " when doing 'make'. ") +find_package(GFLAGS) +if(NOT GFLAGS_FOUND) + message(STATUS " gflags library has not been found.") + message(STATUS " gflags v${GNSSSDR_GFLAGS_LOCAL_VERSION} will be downloaded and built automatically ") + message(STATUS " when doing 'make'. ") - ExternalProject_Add( - gflags-${gflags_RELEASE} - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE} - GIT_REPOSITORY git://github.com/gflags/gflags.git - GIT_TAG v${gflags_RELEASE} - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gflags/gflags-${gflags_RELEASE} - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE} - CMAKE_ARGS -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_gflags_nothreads_LIB=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - BUILD_COMMAND make - UPDATE_COMMAND "" - PATCH_COMMAND "" - INSTALL_COMMAND "" - ) + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + GIT_REPOSITORY git://github.com/gflags/gflags.git + GIT_TAG v${GNSSSDR_GFLAGS_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gflags/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + CMAKE_ARGS -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_gflags_nothreads_LIB=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add(gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + GIT_REPOSITORY git://github.com/gflags/gflags.git + GIT_TAG v${GNSSSDR_GFLAGS_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gflags/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} + CMAKE_ARGS -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_gflags_nothreads_LIB=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gflags${CMAKE_STATIC_LIBRARY_SUFFIX} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + endif() - set(GFlags_INCLUDE_DIRS - ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE}/include CACHE PATH "Local Gflags headers" - ) + set(GFlags_INCLUDE_DIRS + ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/include CACHE PATH "Local Gflags headers" + ) - add_library(gflags UNKNOWN IMPORTED) - set_property(TARGET gflags PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gflags.a) - add_dependencies(gflags gflags-${gflags_RELEASE}) - set(GFlags_LIBS gflags) - file(GLOB GFlags_SHARED_LIBS "${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gflags${CMAKE_SHARED_LIBRARY_SUFFIX}*") - set(GFlags_LIBRARY gflags-${gflags_RELEASE}) - set(GFlags_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE}/lib ) - link_directories(${GFlags_LIBRARY_PATH}) - set(GFlags_lib ${GFlags_LIBS} CACHE FILEPATH "Local Gflags library") - set(GFlags_LIBRARY_PATH ${GFlags_LIBS}) - set(LOCAL_GFLAGS true CACHE STRING "GFlags downloaded and built automatically" FORCE) -endif(NOT GFlags_FOUND) + add_library(gflags UNKNOWN IMPORTED) + set_property(TARGET gflags PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gflags${CMAKE_STATIC_LIBRARY_SUFFIX}) + add_dependencies(gflags gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}) + set(GFlags_LIBS gflags) + file(GLOB GFlags_SHARED_LIBS "${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gflags${CMAKE_SHARED_LIBRARY_SUFFIX}*") + set(GFlags_LIBRARY gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}) + set(GFlags_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/lib) + link_directories(${GFlags_LIBRARY_PATH}) + set(GFlags_lib ${GFlags_LIBS} CACHE FILEPATH "Local Gflags library") + set(GFlags_LIBRARY_PATH ${GFlags_LIBS}) + set(LOCAL_GFLAGS true CACHE STRING "GFlags downloaded and built automatically" FORCE) +endif() @@ -605,34 +775,34 @@ endif(NOT GFlags_FOUND) # glog - https://github.com/google/glog ################################################################################ if(NOT ${ENABLE_OWN_GLOG}) - find_package(GLOG) - if(GLOG_INCLUDE_DIRS) + find_package(GLOG) + if(GLOG_INCLUDE_DIRS) set(GLOG_FOUND ON) - endif(GLOG_INCLUDE_DIRS) -endif(NOT ${ENABLE_OWN_GLOG}) -set(glog_RELEASE 0.3.4) -if (NOT GLOG_FOUND OR ${LOCAL_GFLAGS}) - message (STATUS " glog library has not been found") - if(NOT GFlags_FOUND) - message(STATUS " or it is likely not linked to gflags.") - endif(NOT GFlags_FOUND) - message (STATUS " glog will be downloaded and built automatically ") - message (STATUS " when doing 'make'. ") - if(NOT ${LOCAL_GFLAGS}) - add_library(gflags-${gflags_RELEASE} UNKNOWN IMPORTED) - set_property(TARGET gflags-${gflags_RELEASE} PROPERTY IMPORTED_LOCATION "${GFlags_LIBS}") - endif(NOT ${LOCAL_GFLAGS}) - set(TARGET_GFLAGS gflags-${gflags_RELEASE}) - if(${LOCAL_GFLAGS}) - set(GFLAGS_LIBRARIES_TO_LINK ${GFlags_SHARED_LIBS}) - set(GFLAGS_LIBRARY_DIR_TO_LINK ${CMAKE_CURRENT_BINARY_DIR}/gflags-${gflags_RELEASE}/lib) - else(${LOCAL_GFLAGS}) - set(GFLAGS_LIBRARIES_TO_LINK ${GFlags_LIBS}) - set(GFLAGS_LIBRARY_DIR_TO_LINK ${GFlags_LIBRARY_DIRS}) - endif(${LOCAL_GFLAGS}) + endif() +endif() +set(glog_RELEASE ${GNSSSDR_GLOG_LOCAL_VERSION}) +if(NOT GLOG_FOUND OR ${LOCAL_GFLAGS}) + message(STATUS " glog library has not been found") + if(NOT GFLAGS_FOUND) + message(STATUS " or it is likely not linked to gflags.") + endif() + message(STATUS " glog v${GNSSSDR_GLOG_LOCAL_VERSION} will be downloaded and built automatically ") + message(STATUS " when doing 'make'. ") + if(NOT ${LOCAL_GFLAGS}) + add_library(gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} UNKNOWN IMPORTED) + set_property(TARGET gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION} PROPERTY IMPORTED_LOCATION "${GFlags_LIBS}") + endif() + set(TARGET_GFLAGS gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}) + if(${LOCAL_GFLAGS}) + set(GFLAGS_LIBRARIES_TO_LINK ${GFlags_SHARED_LIBS}) + set(GFLAGS_LIBRARY_DIR_TO_LINK ${CMAKE_CURRENT_BINARY_DIR}/gflags-${GNSSSDR_GFLAGS_LOCAL_VERSION}/lib) + else() + set(GFLAGS_LIBRARIES_TO_LINK ${GFlags_LIBS}) + set(GFLAGS_LIBRARY_DIR_TO_LINK ${GFlags_LIBRARY_DIRS}) + endif() - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/tmp/configure_with_gflags + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/tmp/configure_with_gflags "#!/bin/sh export CPPFLAGS=-I${GFlags_INCLUDE_DIRS} export LDFLAGS=-L${GFLAGS_LIBRARY_DIR_TO_LINK} @@ -640,376 +810,467 @@ export LIBS=\"${GFLAGS_LIBRARIES_TO_LINK} -lc++\" export CXXFLAGS=\"-stdlib=libc++\" export CC=clang export CXX=clang++ -cd ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE}/ +cd ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/ aclocal automake --add-missing autoreconf -vfi -cd ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE} -${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE}/configure") +cd ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} +${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/configure") - else("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/tmp/configure_with_gflags + else() + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/tmp/configure_with_gflags "#!/bin/sh export CPPFLAGS=-I${GFlags_INCLUDE_DIRS} export LDFLAGS=-L${GFLAGS_LIBRARY_DIR_TO_LINK} export LIBS=${GFLAGS_LIBRARIES_TO_LINK} -cd ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE}/ +cd ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/ aclocal automake --add-missing autoreconf -vfi -cd ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE} -${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE}/configure") +cd ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} +${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/configure") + endif() - endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + file(COPY ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/tmp/configure_with_gflags + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ + GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - file(COPY ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/tmp/configure_with_gflags - DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE} - FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ - GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + set(GLOG_CONFIGURE ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/configure_with_gflags) - set(GLOG_CONFIGURE ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/configure_with_gflags) - - # Ensure that aclocal and libtool are present - if(OS_IS_LINUX) - if(EXISTS "/usr/bin/libtoolize") - if(EXISTS "/usr/bin/aclocal-1.15" OR EXISTS "/usr/bin/aclocal-1.14" OR EXISTS "/usr/bin/aclocal-1.11" OR EXISTS "/usr/bin/aclocal-1.10") - # Everything ok, we can move on - else(EXISTS "/usr/bin/aclocal-1.15" OR EXISTS "/usr/bin/aclocal-1.14" OR EXISTS "/usr/bin/aclocal-1.11" OR EXISTS "/usr/bin/aclocal-1.10") - message(" aclocal has not been found.") - message(" You can try to install it by typing:") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo yum groupinstall 'Development Tools'") - elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(" sudo zypper install automake") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo apt-get install automake") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(FATAL_ERROR "aclocal is required to build glog from source") - endif(EXISTS "/usr/bin/aclocal-1.15" OR EXISTS "/usr/bin/aclocal-1.14" OR EXISTS "/usr/bin/aclocal-1.11" OR EXISTS "/usr/bin/aclocal-1.10") - else(EXISTS "/usr/bin/libtoolize") - message(" libtool has not been found.") - message(" You can try to install it by typing:") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo yum groupinstall 'Development Tools'") - elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(" sudo zypper install libtoool") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo apt-get install libtool") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(FATAL_ERROR "libtool is required to build glog from source") - endif(EXISTS "/usr/bin/libtoolize") - endif(OS_IS_LINUX) + # Ensure that aclocal and libtool are present + if(OS_IS_LINUX) + if(EXISTS "/usr/bin/libtoolize") + if(EXISTS "/usr/bin/aclocal" OR EXISTS "/usr/bin/aclocal-1.16" OR EXISTS "/usr/bin/aclocal-1.15" OR EXISTS "/usr/bin/aclocal-1.14" OR EXISTS "/usr/bin/aclocal-1.13" OR EXISTS "/usr/bin/aclocal-1.11" OR EXISTS "/usr/bin/aclocal-1.10") + # Everything ok, we can move on + else() + message(" aclocal has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum groupinstall 'Development Tools'") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(" sudo zypper install automake") + else() + message(" sudo apt-get install automake") + endif() + message(FATAL_ERROR "aclocal is required to build glog from source") + endif() + else() + message(" libtool has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum groupinstall 'Development Tools'") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(" sudo zypper install libtoool") + else() + message(" sudo apt-get install libtool") + endif() + message(FATAL_ERROR "libtool is required to build glog from source") + endif() + endif() - ExternalProject_Add( - glog-${glog_RELEASE} - DEPENDS ${TARGET_GFLAGS} - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE} - GIT_REPOSITORY https://github.com/google/glog/ - GIT_TAG v${glog_RELEASE} - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE} - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE} - CONFIGURE_COMMAND ${GLOG_CONFIGURE} --prefix= - BUILD_COMMAND make - UPDATE_COMMAND "" - PATCH_COMMAND "" - INSTALL_COMMAND "" - ) + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(glog-${GNSSSDR_GLOG_LOCAL_VERSION} + DEPENDS ${TARGET_GFLAGS} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/google/glog/ + GIT_TAG v${GNSSSDR_GLOG_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + CONFIGURE_COMMAND ${GLOG_CONFIGURE} --prefix= + BUILD_COMMAND "${CMAKE_MAKE_PROGRAM}" + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add(glog-${GNSSSDR_GLOG_LOCAL_VERSION} + DEPENDS ${TARGET_GFLAGS} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/google/glog/ + GIT_TAG v${GNSSSDR_GLOG_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION} + CONFIGURE_COMMAND ${GLOG_CONFIGURE} --prefix= + BUILD_COMMAND "${CMAKE_MAKE_PROGRAM}" + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/.libs/${CMAKE_FIND_LIBRARY_PREFIXES}glog${CMAKE_STATIC_LIBRARY_SUFFIX} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + endif() - # Set up variables - set(GLOG_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${glog_RELEASE}/src/ - ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/src - ) - set(GLOG_LIBRARIES - ${CMAKE_CURRENT_BINARY_DIR}/glog-${glog_RELEASE}/.libs/${CMAKE_FIND_LIBRARY_PREFIXES}glog.a - ) - set(LOCAL_GLOG true CACHE STRING "Glog downloaded and built automatically" FORCE) -else(NOT GLOG_FOUND OR ${LOCAL_GFLAGS}) - add_library(glog-${glog_RELEASE} UNKNOWN IMPORTED) - set_property(TARGET glog-${glog_RELEASE} PROPERTY IMPORTED_LOCATION "${GLOG_LIBRARIES}") -endif(NOT GLOG_FOUND OR ${LOCAL_GFLAGS}) + # Set up variables + set(GLOG_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glog/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/src/ + ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/src + ) + set(GLOG_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/glog-${GNSSSDR_GLOG_LOCAL_VERSION}/.libs/${CMAKE_FIND_LIBRARY_PREFIXES}glog${CMAKE_STATIC_LIBRARY_SUFFIX} + ) + set(LOCAL_GLOG true CACHE STRING "Glog downloaded and built automatically" FORCE) +else() + add_library(glog-${GNSSSDR_GLOG_LOCAL_VERSION} UNKNOWN IMPORTED) + set_property(TARGET glog-${GNSSSDR_GLOG_LOCAL_VERSION} PROPERTY IMPORTED_LOCATION "${GLOG_LIBRARIES}") +endif() if(NOT ENABLE_LOG) - message(STATUS "Logging is not enabled") - add_definitions(-DGOOGLE_STRIP_LOG=1) -endif(NOT ENABLE_LOG) + message(STATUS "Logging is not enabled") + add_definitions(-DGOOGLE_STRIP_LOG=1) +endif() + + + +############################################################################# +# Check that BLAS (Basic Linear Algebra Subprograms) is found in the system +# See http://www.netlib.org/blas/ +############################################################################# +find_library(BLAS blas) +if(NOT BLAS) + message(" The BLAS library has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum install blas-devel") + else() + message(" sudo apt-get install libblas-dev") + endif() + message(FATAL_ERROR "BLAS is required to build gnss-sdr") +endif() + + + +############################################################################# +# Check that LAPACK (Linear Algebra PACKage) is found in the system +# See http://www.netlib.org/lapack/ +############################################################################# +find_library(LAPACK lapack) +if(NOT LAPACK) + message(" The LAPACK library has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum install lapack-devel") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(" sudo zypper install lapack-devel") + else() + message(" sudo apt-get install liblapack-dev") + endif() + message(FATAL_ERROR "LAPACK is required to build gnss-sdr") +endif() ################################################################################ # Armadillo - http://arma.sourceforge.net/ ################################################################################ -if(OS_IS_LINUX) - ############################################################################# - # Check that LAPACK is found in the system - # LAPACK is required for matrix decompositions (eg. SVD) and matrix inverse. - ############################################################################# - find_library(LAPACK lapack) - if(NOT LAPACK) - message(" The LAPACK library has not been found.") - message(" You can try to install it by typing:") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo yum install lapack-devel") - elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(" sudo zypper install lapack-devel") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo apt-get install liblapack-dev") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - if(IS_ARM) - message(WARNING "LAPACK is recommended to build gnss-sdr") - set(LAPACK "") - else(IS_ARM) - message(FATAL_ERROR "LAPACK is required to build gnss-sdr") - endif(IS_ARM) - endif(NOT LAPACK) - ############################################################################# - # Check that BLAS is found in the system - # BLAS is used for matrix multiplication. - # Without BLAS, matrix multiplication will still work, but might be slower. - ############################################################################# - find_library(BLAS blas) - if(NOT BLAS) - message(" The BLAS library has not been found.") - message(" You can try to install it by typing:") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo yum install blas-devel") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo apt-get install libopenblas-dev") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - if(IS_ARM) - message(WARNING "BLAS is recommended to build gnss-sdr") - set(BLAS "") - else(IS_ARM) - message(FATAL_ERROR "BLAS is required to build gnss-sdr") - endif(IS_ARM) - endif(NOT BLAS) +find_package(Armadillo) +if(ARMADILLO_FOUND) + if(${ARMADILLO_VERSION_STRING} VERSION_LESS ${GNSSSDR_ARMADILLO_MIN_VERSION}) + set(ARMADILLO_FOUND false) + set(ENABLE_OWN_ARMADILLO true) + endif() +endif() + +if(NOT ARMADILLO_FOUND OR ENABLE_OWN_ARMADILLO) + message(STATUS " Armadillo has not been found.") + message(STATUS " Armadillo ${GNSSSDR_ARMADILLO_LOCAL_VERSION} will be downloaded and built automatically") + message(STATUS " when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'. ") + set(armadillo_BRANCH ${GNSSSDR_ARMADILLO_LOCAL_VERSION}) + set(armadillo_RELEASE ${armadillo_BRANCH}) + ############################################# # Check if GFORTRAN is found in the system ############################################# - find_library(GFORTRAN NAMES gfortran - PATHS /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib/i386 - /usr/lib/gcc/x86_64-linux-gnu - /usr/lib/gcc/i686-linux-gnu - /usr/lib/gcc/i386-linux-gnu - /usr/lib/gcc/x86_64-linux-gnu/4.6 # Ubuntu 12.04 - /usr/lib/gcc/i686-linux-gnu/4.6 - /usr/lib/gcc/x86_64-linux-gnu/4.7 - /usr/lib/gcc/i686-linux-gnu/4.7 - /usr/lib/gcc/x86_64-linux-gnu/4.8 - /usr/lib/gcc/i686-linux-gnu/4.8 - /usr/lib/gcc/x86_64-linux-gnu/4.9 - /usr/lib/gcc/i686-linux-gnu/4.9 - /usr/lib/gcc/x86_64-redhat-linux/4.7.2 # Fedora 18 - /usr/lib/gcc/i686-redhat-linux/4.7.2 - /usr/lib/gcc/x86_64-redhat-linux/4.8.1 # Fedora 19 - /usr/lib/gcc/x86_64-redhat-linux/4.8.3 # Fedora 20 - /usr/lib/gcc/x86_64-redhat-linux/4.9.1 # Fedora 21 - /usr/lib/gcc/i686-redhat-linux/4.8.1 - /usr/lib/gcc/i686-redhat-linux/4.8.3 - /usr/lib/gcc/i686-redhat-linux/4.9.1 - /usr/lib/gcc/x86_64-redhat-linux/4.4.4 # CentOS 6 - /usr/lib/gcc/i686-redhat-linux/4.4.4 - /usr/lib/gcc/x86_64-redhat-linux/4.8.2 - /usr/lib/gcc/i686-redhat-linux/4.8.2 - /usr/lib/gcc/i586-suse-linux/4.8 # OpenSUSE 13.1 - /usr/lib/gcc/i586-suse-linux/4.9 - /usr/lib/gcc/x86_64-suse-linux/4.8 - /usr/lib/gcc/x86_64-suse-linux/4.9 - /usr/lib/gcc/i486-linux-gnu # Debian 7 - /usr/lib/gcc/i486-linux-gnu/4.4 - /usr/lib/gcc/i486-linux-gnu/4.6 - /usr/lib/gcc/i486-linux-gnu/4.7 - /usr/lib/gcc/i486-linux-gnu/4.8 - /usr/lib/gcc/i486-linux-gnu/4.9 - /usr/lib/gcc/i586-linux-gnu/4.9 - /usr/lib/gcc/arm-linux-gnueabihf/4.4 # Debian armhf - /usr/lib/gcc/arm-linux-gnueabihf/4.5 - /usr/lib/gcc/arm-linux-gnueabihf/4.6 - /usr/lib/gcc/arm-linux-gnueabihf/4.7 - /usr/lib/gcc/arm-linux-gnueabihf/4.8 - /usr/lib/gcc/arm-linux-gnueabihf/4.9 - /usr/lib/gcc/aarch64-linux-gnu/4.9 # Debian arm64 - /usr/lib/gcc/arm-linux-gnueabi/4.7 # Debian armel - /usr/lib/gcc/arm-linux-gnueabi/4.9 - /usr/lib/gcc/x86_64-linux-gnu/5 - /usr/lib/gcc/i686-linux-gnu/5 - /usr/lib/gcc/arm-linux-gnueabi/5 - /usr/lib/gcc/arm-linux-gnueabihf/5 - /usr/lib/gcc/aarch64-linux-gnu/5 - /usr/lib/gcc/x86_64-linux-gnu/6 # Ubuntu 16.10 - /usr/lib/gcc/alpha-linux-gnu/6 - /usr/lib/gcc/aarch64-linux-gnu/6 - /usr/lib/gcc/arm-linux-gnueabi/6 - /usr/lib/gcc/arm-linux-gnueabihf/6 - /usr/lib/gcc/hppa-linux-gnu/6 - /usr/lib/gcc/i686-gnu/6 - /usr/lib/gcc/i686-linux-gnu/6 - /usr/lib/gcc/x86_64-kfreebsd-gnu/6 - /usr/lib/gcc/i686-kfreebsd-gnu/6 - /usr/lib/gcc/m68k-linux-gnu/6 - /usr/lib/gcc/mips-linux-gnu/6 - /usr/lib/gcc/mips64el-linux-gnuabi64/6 - /usr/lib/gcc/mipsel-linux-gnu/6 - /usr/lib/gcc/powerpc-linux-gnu/6 - /usr/lib/gcc/powerpc-linux-gnuspe/6 - /usr/lib/gcc/powerpc64-linux-gnu/6 - /usr/lib/gcc/powerpc64le-linux-gnu/6 - /usr/lib/gcc/s390x-linux-gnu/6 - /usr/lib/gcc/sparc64-linux-gnu/6 - /usr/lib/gcc/x86_64-linux-gnux32/6 - /usr/lib/gcc/sh4-linux-gnu/6 - ) + if(NOT OS_IS_MACOSX) + find_package(GFORTRAN) + if(NOT GFORTRAN) + message(STATUS "The gfortran library has not been found.") + message(STATUS " You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " sudo yum install gcc-fortran") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(STATUS " sudo zypper install gcc-fortran") + else() + message(STATUS " sudo apt-get install gfortran") + endif() + message(FATAL_ERROR "gfortran is required to build gnss-sdr") + endif() + endif() + + ############################################# + # Download and build Armadillo + ############################################# + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(armadillo-${armadillo_RELEASE} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} + GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git + GIT_TAG ${armadillo_BRANCH} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/armadillo/armadillo-${armadillo_RELEASE} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} + CMAKE_ARGS -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DBUILD_SHARED_LIBS=OFF -DCMAKE_CXX_FLAGS=-std=c++11 + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + UPDATE_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add(armadillo-${armadillo_RELEASE} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} + GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git + GIT_TAG ${armadillo_BRANCH} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/armadillo/armadillo-${armadillo_RELEASE} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} + CMAKE_ARGS -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DBUILD_SHARED_LIBS=OFF -DCMAKE_CXX_FLAGS=-std=c++11 + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE}/${CMAKE_FIND_LIBRARY_PREFIXES}armadillo${CMAKE_STATIC_LIBRARY_SUFFIX} + UPDATE_COMMAND "" + INSTALL_COMMAND "" + ) + endif() + + # Set up variables + ExternalProject_Get_Property(armadillo-${armadillo_RELEASE} binary_dir) + set(ARMADILLO_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/armadillo/armadillo-${armadillo_RELEASE}/include) if(NOT GFORTRAN) - message(STATUS "The gfortran library has not been found.") - message(STATUS " You can try to install it by typing:") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo yum install gcc-fortran") - elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(STATUS " sudo zypper install gcc-fortran") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo apt-get install gfortran") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - endif(NOT GFORTRAN) -endif(OS_IS_LINUX) - -find_package(Armadillo) -if(NOT ARMADILLO_FOUND OR ENABLE_OWN_ARMADILLO) - message(STATUS " Armadillo has not been found.") - message(STATUS " Armadillo will be downloaded and built automatically ") - message(STATUS " when doing 'make'. ") - - if(CMAKE_VERSION VERSION_LESS 3.1) - # ExternalProject in CMake > 3.1 cannot open .xz files - set(armadillo_RELEASE 6.700.7) - set(armadillo_MD5 "8116185e1d7391eed3bf6c500f81b4d8") - set(ARMA_FILE_EXTENSION "gz") - else(CMAKE_VERSION VERSION_LESS 3.1) - set(armadillo_RELEASE 7.600.2) - set(armadillo_MD5 "8dee8bc37f7cb29323c20c4104126b5c") - set(ARMA_FILE_EXTENSION "xz") - endif(CMAKE_VERSION VERSION_LESS 3.1) - - ExternalProject_Add( - armadillo-${armadillo_RELEASE} - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} - URL http://sourceforge.net/projects/arma/files/armadillo-${armadillo_RELEASE}.tar.${ARMA_FILE_EXTENSION} - DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/download/armadillo-${armadillo_RELEASE} - URL_MD5 ${armadillo_MD5} - CMAKE_ARGS -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DBUILD_SHARED_LIBS=OFF - BUILD_IN_SOURCE 1 - BUILD_COMMAND make - UPDATE_COMMAND "" - INSTALL_COMMAND "" - ) - - # Set up variables - ExternalProject_Get_Property(armadillo-${armadillo_RELEASE} binary_dir) - set(ARMADILLO_INCLUDE_DIRS ${binary_dir}/include ) - find_library(LAPACK NAMES lapack HINTS /usr/lib /usr/local/lib /usr/lib64) - if(OS_IS_MACOSX) - find_library(BLAS blas) - endif(OS_IS_MACOSX) - find_package(OpenBLAS) - if(OPENBLAS_FOUND) - set(BLAS ${OPENBLAS}) - endif(OPENBLAS_FOUND) - if(NOT GFORTRAN) - set(GFORTRAN "") - endif(NOT GFORTRAN) - set(ARMADILLO_LIBRARIES ${BLAS} ${LAPACK} ${GFORTRAN} ${binary_dir}/${CMAKE_FIND_LIBRARY_PREFIXES}armadillo.a) - set(LOCAL_ARMADILLO true CACHE STRING "Armadillo downloaded and built automatically" FORCE) - # Save a copy at the thirdparty folder - file(COPY ${CMAKE_CURRENT_BINARY_DIR}/armadillo-${armadillo_RELEASE} - DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/armadillo - ) - set(ARMADILLO_VERSION_STRING ${armadillo_RELEASE}) -else(NOT ARMADILLO_FOUND OR ENABLE_OWN_ARMADILLO) - set(armadillo_RELEASE ${ARMADILLO_VERSION_STRING}) - add_library(armadillo-${armadillo_RELEASE} UNKNOWN IMPORTED) - set_property(TARGET armadillo-${armadillo_RELEASE} PROPERTY IMPORTED_LOCATION "${ARMADILLO_LIBRARIES}") -endif(NOT ARMADILLO_FOUND OR ENABLE_OWN_ARMADILLO) + set(GFORTRAN "") + endif() + set(ARMADILLO_LIBRARIES ${BLAS} ${LAPACK} ${GFORTRAN} ${binary_dir}/${CMAKE_FIND_LIBRARY_PREFIXES}armadillo${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(LOCAL_ARMADILLO true CACHE STRING "Armadillo downloaded and built automatically" FORCE) + set(ARMADILLO_VERSION_STRING ${armadillo_RELEASE}) +else() + set(armadillo_RELEASE ${ARMADILLO_VERSION_STRING}) + add_library(armadillo-${armadillo_RELEASE} UNKNOWN IMPORTED) + set_property(TARGET armadillo-${armadillo_RELEASE} PROPERTY IMPORTED_LOCATION "${ARMADILLO_LIBRARIES}") +endif() ################################################################################ -# GnuTLS - http://www.gnutls.org/ +# GnuTLS - https://www.gnutls.org/ ################################################################################ find_package(GnuTLS) find_library(GNUTLS_OPENSSL_LIBRARY NAMES gnutls-openssl libgnutls-openssl.so.27 - HINTS /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib64 - /opt/local/lib - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - ) + HINTS /usr/lib + /usr/lib64 + /usr/local/lib + /usr/local/lib64 + /opt/local/lib + /usr/lib/x86_64-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/i386-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/i386-gnu + /usr/lib/i686-gnu + /usr/lib/i686-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i686-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/sh4-linux-gnu +) if(NOT GNUTLS_OPENSSL_LIBRARY) - message(STATUS "Looking for OpenSSL instead...") - find_package(OpenSSL) - if(OPENSSL_FOUND) + message(STATUS "Looking for OpenSSL instead...") + find_package(OpenSSL) + if(OPENSSL_FOUND) set(GNUTLS_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) set(GNUTLS_LIBRARIES "") set(GNUTLS_OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY}) - else(OPENSSL_FOUND) - message(" The GnuTLS library with openssl compatibility enabled has not been found.") - message(" You can try to install the required libraries by typing:") - if(OS_IS_LINUX) + else() + message(" The GnuTLS library with openssl compatibility enabled has not been found.") + message(" You can try to install the required libraries by typing:") + if(OS_IS_LINUX) if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") message(" sudo yum install openssl-devel") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + else() message(" sudo apt-get install libgnutls-openssl-dev") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - endif(OS_IS_LINUX) - if(OS_IS_MACOSX) + endif() + endif() + if(OS_IS_MACOSX) message(" sudo port install gnutls") - endif(OS_IS_MACOSX) - message(FATAL_ERROR "GnuTLS libraries with openssl compatibility are required to build gnss-sdr") - endif(OPENSSL_FOUND) -endif(NOT GNUTLS_OPENSSL_LIBRARY) + endif() + message(FATAL_ERROR "GnuTLS libraries with openssl compatibility are required to build gnss-sdr") + endif() +endif() +######################################################################## +# Matio - https://github.com/tbeu/matio +######################################################################## +find_package(MATIO) +if(NOT MATIO_FOUND OR MATIO_VERSION_STRING VERSION_LESS ${GNSSSDR_MATIO_MIN_VERSION}) + if(MATIO_FOUND) + message(STATUS " Matio installed version (${MATIO_VERSION_STRING}) is too old (>= ${GNSSSDR_MATIO_MIN_VERSION} is required).") + endif() + message(STATUS " Matio v${GNSSSDR_MATIO_LOCAL_VERSION} will be downloaded and built automatically") + message(STATUS " when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'. ") + find_package(ZLIB) + if(ZLIB_FOUND) + get_filename_component(ZLIB_BASE_DIR ${ZLIB_INCLUDE_DIRS} DIRECTORY) + if(OS_IS_LINUX) + if(NOT EXISTS "/usr/bin/libtoolize") + message(" libtool has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum groupinstall 'Development Tools'") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(" sudo zypper install libtoool") + else() + message(" sudo apt-get install libtool") + endif() + message(FATAL_ERROR "libtool is required to build matio from source") + endif() + if(EXISTS "/usr/bin/aclocal" OR + EXISTS "/usr/bin/aclocal-1.16" OR + EXISTS "/usr/bin/aclocal-1.15" OR + EXISTS "/usr/bin/aclocal-1.14" OR + EXISTS "/usr/bin/aclocal-1.13" OR + EXISTS "/usr/bin/aclocal-1.11" OR + EXISTS "/usr/bin/aclocal-1.10") + message(STATUS "Automake found.") + else() + message(" aclocal has not been found.") + message(" You can try to install it by typing:") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum groupinstall 'Development Tools'") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(" sudo zypper install automake") + else() + message(" sudo apt-get install automake") + endif() + message(FATAL_ERROR "aclocal is required to build matio from source") + endif() + endif() + find_package(HDF5) + if(HDF5_FOUND) + list(GET HDF5_LIBRARIES 0 HDF5_FIRST_DIR) + get_filename_component(HDF5_BASE_DIR2 ${HDF5_FIRST_DIR} DIRECTORY) + get_filename_component(HDF5_BASE_DIR ${HDF5_BASE_DIR2} DIRECTORY) + if(OS_IS_MACOSX) + if(EXISTS /opt/local/include/hdf5.h) + set(HDF5_BASE_DIR /opt/local) + endif() + if(EXISTS /usr/local/include/hdf5.h) + set(HDF5_BASE_DIR /usr/local) + endif() + endif() + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(matio-${GNSSSDR_MATIO_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/matio + GIT_REPOSITORY https://github.com/tbeu/matio + GIT_TAG v${GNSSSDR_MATIO_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION} + UPDATE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION}/autogen.sh + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION}/configure --with-hdf5=${HDF5_BASE_DIR} --with-zlib=${ZLIB_BASE_DIR} --with-default-file-ver=7.3 --enable-mat73=yes --prefix= + BUILD_COMMAND make + ) + else() + ExternalProject_Add(matio-${GNSSSDR_MATIO_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/matio + GIT_REPOSITORY https://github.com/tbeu/matio + GIT_TAG v${GNSSSDR_MATIO_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION} + UPDATE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION}/autogen.sh + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/matio/matio-${GNSSSDR_MATIO_LOCAL_VERSION}/configure --with-hdf5=${HDF5_BASE_DIR} --with-zlib=${ZLIB_BASE_DIR} --with-default-file-ver=7.3 --enable-mat73=yes --prefix= + BUILD_COMMAND make + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/matio/lib/${CMAKE_FIND_LIBRARY_PREFIXES}matio${CMAKE_STATIC_LIBRARY_SUFFIX} + ) + endif() + set(MATIO_LIBRARIES ${CMAKE_CURRENT_BINARY_DIR}/matio/lib/${CMAKE_FIND_LIBRARY_PREFIXES}matio${CMAKE_STATIC_LIBRARY_SUFFIX} ${HDF5_LIBRARIES} ${ZLIB_LIBRARIES}) + set(MATIO_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/matio/include) + set(MATIO_LOCAL true) + else() + message(STATUS " The hdf5 library has not been found in your system.") + message(STATUS " Please try to install it by doing:") + if(OS_IS_MACOSX) + message(STATUS " $ sudo port install hdf5") + message(STATUS " or") + message(STATUS " $ brew install hdf5") + endif() + if(OS_IS_LINUX) + message(STATUS " $ sudo apt-get install libhdf5-dev") + endif() + message(FATAL_ERROR "*** The hdf5 library is required to build gnss-sdr") + endif() + else() + message(FATAL_ERROR "*** The zlib library is required to build gnss-sdr") + endif() +endif() + + + +################################################################################ +# PugiXML - https://pugixml.org/ +################################################################################ +find_package(PUGIXML QUIET) +if(PUGIXML_FOUND) + message(STATUS "PugiXML has been found.") +else() + message(STATUS " PugiXML v${GNSSSDR_PUGIXML_LOCAL_VERSION} will be downloaded and built automatically when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'.") + set(PUGIXML_COMPILER -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}) + set(TOOLCHAIN_ARG "") + if(EXISTS $ENV{OECORE_TARGET_SYSROOT}) + set(PUGIXML_COMPILER "") + set(TOOLCHAIN_ARG "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/Toolchains/oe-sdk_cross.cmake") + endif() + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/zeux/pugixml + GIT_TAG v${GNSSSDR_PUGIXML_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/pugixml/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + CMAKE_ARGS ${PUGIXML_COMPILER} ${TOOLCHAIN_ARG} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add(pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/zeux/pugixml + GIT_TAG v${GNSSSDR_PUGIXML_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/pugixml/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION} + CMAKE_ARGS ${PUGIXML_COMPILER} ${TOOLCHAIN_ARG} + UPDATE_COMMAND "" + PATCH_COMMAND "" + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION}/${CMAKE_FIND_LIBRARY_PREFIXES}pugixml${CMAKE_STATIC_LIBRARY_SUFFIX} + INSTALL_COMMAND "" + ) + endif() + set(PUGIXML_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION}/${CMAKE_FIND_LIBRARY_PREFIXES}pugixml${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(PUGIXML_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/pugixml/pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION}/src) + set(PUGIXML_LOCAL true) +endif() + + ################################################################################ # USRP Hardware Driver (UHD) - OPTIONAL ################################################################################ -find_package(UHD) -if(NOT UHD_FOUND) - set(ENABLE_UHD OFF) - message(STATUS " The USRP Hardware Driver (UHD) signal source will not be built,") - message(STATUS " so all USRP-based front-ends will not be usable.") - message(STATUS " Please check http://files.ettus.com/manual/") -else(NOT UHD_FOUND) - set(GR_REQUIRED_COMPONENTS UHD) - find_package(Gnuradio) - set(ENABLE_UHD ON) -endif(NOT UHD_FOUND) - +if(ENABLE_UHD) + find_package(UHD) + if(NOT UHD_FOUND) + set(ENABLE_UHD OFF) + message(STATUS " The USRP Hardware Driver (UHD) signal source will not be built,") + message(STATUS " so all USRP-based front-ends will not be usable.") + message(STATUS " Please check https://files.ettus.com/manual/") + else() + set(GR_REQUIRED_COMPONENTS UHD) + find_package(Gnuradio) + endif() +endif() ################################################################################ @@ -1017,62 +1278,62 @@ endif(NOT UHD_FOUND) ################################################################################ find_package(Doxygen) if(DOXYGEN_FOUND) - message(STATUS "Doxygen found.") - message(STATUS "You can build the documentation with 'make doc'." ) - message(STATUS "When done, point your browser to ${CMAKE_BINARY_DIR}/html/index.html") - set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) - file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) - file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) - find_package(LATEX) - if (PDFLATEX_COMPILER) - set(GENERATE_PDF_DOCUMENTATION "YES") - set(GNSSSDR_USE_MATHJAX "NO") - else(PDFLATEX_COMPILER) - set(GENERATE_PDF_DOCUMENTATION "NO") - set(GNSSSDR_USE_MATHJAX "YES") - endif(PDFLATEX_COMPILER) - configure_file(${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.in - ${CMAKE_BINARY_DIR}/docs/doxygen/Doxyfile - @ONLY - ) - add_custom_target(doc - ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/docs/doxygen/Doxyfile - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen." VERBATIM - ) - if(LATEX_COMPILER) - message(STATUS "'make pdfmanual' will generate a manual at ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf") - add_custom_target(pdfmanual - COMMAND ${CMAKE_MAKE_PROGRAM} - COMMAND ${CMAKE_COMMAND} -E copy refman.pdf ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf - COMMAND ${CMAKE_MAKE_PROGRAM} clean - DEPENDS doc - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/docs/latex - COMMENT "Generating PDF manual with Doxygen." VERBATIM - ) - endif(LATEX_COMPILER) - message(STATUS "'make doc-clean' will clean the documentation.") - add_custom_target(doc-clean - COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/docs/html - COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/docs/latex - COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf - COMMENT "Cleaning documentation." VERBATIM - ) -else(DOXYGEN_FOUND) - message(STATUS " Doxygen has not been found in your system.") - message(STATUS " You can get nice code documentation by using it!") - message(STATUS " Get it from http://www.stack.nl/~dimitri/doxygen/index.html") - if(OS_IS_LINUX) - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" or simply by doing 'sudo yum install doxygen-latex'.") - else(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" or simply by doing 'sudo apt-get install doxygen-latex'.") - endif(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - endif(OS_IS_LINUX) - if(OS_IS_MACOSX) - message(STATUS " or simply by doing 'sudo port install doxygen +latex'.") - endif(OS_IS_MACOSX) -endif(DOXYGEN_FOUND) + message(STATUS "Doxygen found.") + message(STATUS "You can build the documentation with '${CMAKE_MAKE_PROGRAM_PRETTY_NAME} doc'.") + message(STATUS "When done, point your browser to ${CMAKE_BINARY_DIR}/html/index.html") + set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) + file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) + file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) + find_package(LATEX) + if(PDFLATEX_COMPILER) + set(GENERATE_PDF_DOCUMENTATION "YES") + set(GNSSSDR_USE_MATHJAX "NO") + else() + set(GENERATE_PDF_DOCUMENTATION "NO") + set(GNSSSDR_USE_MATHJAX "YES") + endif() + configure_file(${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.in + ${CMAKE_BINARY_DIR}/docs/doxygen/Doxyfile + @ONLY + ) + add_custom_target(doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/docs/doxygen/Doxyfile + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen." VERBATIM + ) + if(LATEX_COMPILER) + message(STATUS "'${CMAKE_MAKE_PROGRAM_PRETTY_NAME} pdfmanual' will generate a manual at ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf") + add_custom_target(pdfmanual + COMMAND ${CMAKE_MAKE_PROGRAM} + COMMAND ${CMAKE_COMMAND} -E copy refman.pdf ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf + COMMAND ${CMAKE_MAKE_PROGRAM} clean + DEPENDS doc + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/docs/latex + COMMENT "Generating PDF manual with Doxygen." VERBATIM + ) + endif() + message(STATUS "'${CMAKE_MAKE_PROGRAM_PRETTY_NAME} doc-clean' will clean the documentation.") + add_custom_target(doc-clean + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/docs/html + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/docs/latex + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/docs/GNSS-SDR_manual.pdf + COMMENT "Cleaning documentation." VERBATIM + ) +else() + message(STATUS " Doxygen has not been found in your system.") + message(STATUS " You can get nice code documentation by using it!") + message(STATUS " Get it from http://www.stack.nl/~dimitri/doxygen/index.html") + if(OS_IS_LINUX) + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " or simply by doing 'sudo yum install doxygen-latex'.") + else() + message(STATUS " or simply by doing 'sudo apt-get install doxygen-latex'.") + endif() + endif() + if(OS_IS_MACOSX) + message(STATUS " or simply by doing 'sudo port install doxygen +latex'.") + endif() +endif() @@ -1080,28 +1341,28 @@ endif(DOXYGEN_FOUND) # OpenCL (OPTIONAL) ############################################################################### if(ENABLE_OPENCL) - find_package(OpenCL) + find_package(OPENCL) if($ENV{DISABLE_OPENCL}) set(DISABLE_OPENCL TRUE) - endif($ENV{DISABLE_OPENCL}) + endif() if(DISABLE_OPENCL) set(OPENCL_FOUND FALSE) - else(DISABLE_OPENCL) + else() if(OPENCL_FOUND) message(STATUS "OpenCL has been found and will be used by some processing blocks") message(STATUS "You can disable OpenCL use by doing 'cmake -DENABLE_OPENCL=OFF ../' ") - endif(OPENCL_FOUND) - endif(DISABLE_OPENCL) + endif() + endif() if(ENABLE_GENERIC_ARCH) set(OPENCL_FOUND FALSE) message(STATUS "ENABLE_GENERIC_ARCH is set to ON so the use of OpenCL has been disabled.") - endif(ENABLE_GENERIC_ARCH) + endif() if(NOT OPENCL_FOUND) message(STATUS "Processing blocks using OpenCL will not be built.") - endif(NOT OPENCL_FOUND) -else(ENABLE_OPENCL) + endif() +else() set(OPENCL_FOUND FALSE) -endif(ENABLE_OPENCL) +endif() @@ -1109,18 +1370,43 @@ endif(ENABLE_OPENCL) # CUDA (OPTIONAL) ############################################################################### if($ENV{CUDA_GPU_ACCEL}) - message(STATUS "CUDA_GPU_ACCEL environment variable found." ) + message(STATUS "CUDA_GPU_ACCEL environment variable found.") set(ENABLE_CUDA ON) -endif($ENV{CUDA_GPU_ACCEL}) +endif() if(ENABLE_CUDA) - FIND_PACKAGE(CUDA REQUIRED) - message(STATUS "NVIDIA CUDA GPU Acceleration will be enabled." ) - message(STATUS "You can disable it with 'cmake -DENABLE_CUDA=OFF ../'" ) -else(ENABLE_CUDA) - message(STATUS "NVIDIA CUDA GPU Acceleration will be not enabled." ) - message(STATUS "Enable it with 'cmake -DENABLE_CUDA=ON ../' to add support for GPU-based acceleration using CUDA." ) -endif(ENABLE_CUDA) + find_package(CUDA REQUIRED) + message(STATUS "NVIDIA CUDA GPU Acceleration will be enabled.") + message(STATUS "You can disable it with 'cmake -DENABLE_CUDA=OFF ../'") +else() + message(STATUS "NVIDIA CUDA GPU Acceleration will be not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_CUDA=ON ../' to add support for GPU-based acceleration using CUDA.") +endif() + + + +############################################################################### +# CUSTOM UDP PACKET SOURCE (OPTIONAL) +############################################################################### +if(ENABLE_RAW_UDP) + message(STATUS "High-optimized custom UDP ip packet source will be enabled.") + message(STATUS "You can disable it with 'cmake -DENABLE_RAW_UDP=OFF ../'") +else() + message(STATUS "High-optimized custom UDP ip packet source will be enabled.") + message(STATUS "You can disable it with 'cmake -DENABLE_RAW_UDP=OFF ../'") +endif() + + +############################################################################### +# FPGA (OPTIONAL) +############################################################################### +if(ENABLE_FPGA) + message(STATUS "FPGA Acceleration will be enabled.") + message(STATUS "You can disable it with 'cmake -DENABLE_FPGA=OFF ../'") +else() + message(STATUS "Fpga Acceleration will be not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_FPGA=ON ../' to add support for GPU-based acceleration using the FPGA.") +endif() @@ -1128,68 +1414,77 @@ endif(ENABLE_CUDA) # Setup of optional drivers ################################################################################ if($ENV{GN3S_DRIVER}) - message(STATUS "GN3S_DRIVER environment variable found." ) + message(STATUS "GN3S_DRIVER environment variable found.") set(ENABLE_GN3S ON) -endif($ENV{GN3S_DRIVER}) +endif() if(GN3S_DRIVER) set(ENABLE_GN3S ON) -endif(GN3S_DRIVER) +endif() if(ENABLE_GN3S) - message(STATUS "The GN3S driver will be compiled.") - message(STATUS "You can disable it with 'cmake -DENABLE_GN3S=OFF ../'" ) -else(ENABLE_GN3S) - message(STATUS "The (optional and experimental) GN3S driver is not enabled." ) - message(STATUS "Enable it with 'cmake -DENABLE_GN3S=ON ../' to add support for the GN3S dongle." ) -endif(ENABLE_GN3S) + message(STATUS "The GN3S driver will be compiled.") + message(STATUS "You can disable it with 'cmake -DENABLE_GN3S=OFF ../'") +else() + message(STATUS "The (optional and experimental) GN3S driver is not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_GN3S=ON ../' to add support for the GN3S dongle.") +endif() if($ENV{RAW_ARRAY_DRIVER}) - message(STATUS "RAW_ARRAY_DRIVER environment variable found." ) + message(STATUS "RAW_ARRAY_DRIVER environment variable found.") set(ENABLE_ARRAY ON) -endif($ENV{RAW_ARRAY_DRIVER}) +endif() if(RAW_ARRAY_DRIVER) set(ENABLE_ARRAY ON) -endif(RAW_ARRAY_DRIVER) +endif() if(ENABLE_ARRAY) - message(STATUS "CTTC's Antenna Array front-end driver will be compiled." ) - message(STATUS "You can disable it with 'cmake -DENABLE_ARRAY=OFF ../'" ) + message(STATUS "CTTC's Antenna Array front-end driver will be compiled.") + message(STATUS "You can disable it with 'cmake -DENABLE_ARRAY=OFF ../'") # copy firmware to install folder # Build project gr-dbfcttc -else(ENABLE_ARRAY) - message(STATUS "The (optional) CTTC's Antenna Array front-end driver is not enabled." ) - message(STATUS "Enable it with 'cmake -DENABLE_ARRAY=ON ../' to add support for the CTTC experimental array front-end." ) -endif(ENABLE_ARRAY) +else() + message(STATUS "The (optional) CTTC's Antenna Array front-end driver is not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_ARRAY=ON ../' to add support for the CTTC experimental array front-end.") +endif() if($ENV{RTLSDR_DRIVER}) - message(STATUS "RTLSDR_DRIVER environment variable found." ) + message(STATUS "RTLSDR_DRIVER environment variable found.") set(ENABLE_OSMOSDR ON) -endif($ENV{RTLSDR_DRIVER}) +endif() if(ENABLE_OSMOSDR) - message(STATUS "The driver for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based dongles, etc.) will be compiled." ) - message(STATUS "You can disable it with 'cmake -DENABLE_OSMOSDR=OFF ../'" ) -else(ENABLE_OSMOSDR) - message(STATUS "The (optional) driver for OsmoSDR and related front-ends is not enabled." ) - message(STATUS "Enable it with 'cmake -DENABLE_OSMOSDR=ON ../' to add support for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based USB dongles, etc.)" ) -endif(ENABLE_OSMOSDR) + find_package(GROSMOSDR) + if(GROSMOSDR_FOUND) + message(STATUS "The driver for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based dongles, etc.) will be compiled.") + message(STATUS "You can disable it with 'cmake -DENABLE_OSMOSDR=OFF ../'") + else() + if(ENABLE_PACKAGING) + message(WARNING "gr-osmosdr has not been found. Source blocks depending on it will NOT be built.") + else() + message(FATAL_ERROR "gr-osmosdr required to build gnss-sdr with the optional OSMOSDR driver") + endif() + endif() +else() + message(STATUS "The (optional) driver for OsmoSDR and related front-ends is not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_OSMOSDR=ON ../' to add support for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based USB dongles, etc.)") +endif() if($ENV{FLEXIBAND_DRIVER}) - message(STATUS "FLEXIBAND_DRIVER environment variable found." ) + message(STATUS "FLEXIBAND_DRIVER environment variable found.") set(ENABLE_FLEXIBAND ON) -endif($ENV{FLEXIBAND_DRIVER}) +endif() if(FLEXIBAND_DRIVER) set(ENABLE_FLEXIBAND ON) -endif(FLEXIBAND_DRIVER) +endif() if(ENABLE_FLEXIBAND) - message(STATUS "CTTC's Antenna Array front-end driver will be compiled." ) - message(STATUS "You can disable it with 'cmake -DENABLE_FLEXIBAND=OFF ../'" ) -else(ENABLE_FLEXIBAND) - message(STATUS "The (optional) Teleorbit Flexiband front-end driver adapter is not enabled." ) - message(STATUS "Enable it with 'cmake -DENABLE_FLEXIBAND=ON ../' to add support for the Teleorbit Flexiband front-end." ) -endif(ENABLE_FLEXIBAND) + message(STATUS "The Teleorbit Flexiband front-end source will be compiled.") + message(STATUS "You can disable it with 'cmake -DENABLE_FLEXIBAND=OFF ../'") +else() + message(STATUS "The (optional) Teleorbit Flexiband front-end driver adapter is not enabled.") + message(STATUS "Enable it with 'cmake -DENABLE_FLEXIBAND=ON ../' to add support for the Teleorbit Flexiband front-end.") +endif() @@ -1197,28 +1492,28 @@ endif(ENABLE_FLEXIBAND) # GPerftools - https://github.com/gperftools/gperftools (OPTIONAL) ################################################################################ if(ENABLE_GPERFTOOLS) - find_package(Gperftools) - if ( NOT GPERFTOOLS_FOUND ) + find_package(GPERFTOOLS) + if(NOT GPERFTOOLS_FOUND) message(STATUS "Although ENABLE_GPERFTOOLS has been set to ON, GPerftools has not been found.") message(STATUS "Binaries will be compiled without 'tcmalloc' and 'profiler' libraries.") message(STATUS "You can install GPerftools from https://github.com/gperftools/gperftools") - else( NOT GPERFTOOLS_FOUND ) - message(STATUS "GPerftools libraries found." ) + else() + message(STATUS "GPerftools libraries found.") message(STATUS "Binaries will be compiled with 'tcmalloc' and 'profiler' libraries.") - endif( NOT GPERFTOOLS_FOUND ) -endif(ENABLE_GPERFTOOLS) + endif() +endif() if(ENABLE_GPERFTOOLS) # Set GPerftools related flags if it is available - # See http://gperftools.googlecode.com/svn/trunk/README + # See https://github.com/gperftools/gperftools/blob/master/README if(GPERFTOOLS_FOUND) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") - endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) + endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -fno-builtin") - endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - endif(GPERFTOOLS_FOUND) -endif(ENABLE_GPERFTOOLS) + endif() + endif() +endif() @@ -1226,63 +1521,123 @@ endif(ENABLE_GPERFTOOLS) # GNU gprof (OPTIONAL) - https://sourceware.org/binutils/docs/gprof/ ######################################################################## if(ENABLE_GPROF) - #if(CMAKE_COMPILER_IS_GNUCXX) - set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -pg") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") - #endif(CMAKE_COMPILER_IS_GNUCXX) -endif(ENABLE_GPROF) - + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -pg") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") +endif() ######################################################################## # Set compiler flags ######################################################################## -# Enable C++11 support in GCC -if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) - set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11 -Wall -Wextra") #Add warning flags: For "-Wall" see http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html -endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) +# Support of C++17 is still not possible due to pm_remez.h (solved in GNU Radio 3.8) +# Enable C++14 support in GCC >= 6.1.1 +# Fallback to C++11 when using GCC < 6.1.1 +if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.1.1") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + # if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + # else(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0.0") + # set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++17") + # endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0.0") + endif() + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -Wall -Wextra") #Add warning flags: For "-Wall" see https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html +endif() + +# Support of C++17 is still not possible due to pm_remez.h (solved in GNU Radio 3.8) +# Enable C++14 support in Clang >= 3.5.0 or AppleClang >= 600 +# Fallback to C++11 if older version if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11 -stdlib=libc++") - if(CMAKE_BUILD_TYPE MATCHES "Release") - set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -Wno-unused-private-field") - endif(CMAKE_BUILD_TYPE MATCHES "Release") -endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(OS_IS_MACOSX) + # See https://trac.macports.org/wiki/XcodeVersionInfo for Apple Clang version equivalences + if(CLANG_VERSION VERSION_LESS "600") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + # if(CLANG_VERSION VERSION_LESS "900") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + # else(CLANG_VERSION VERSION_LESS "900") + # set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++17") + # endif(CLANG_VERSION VERSION_LESS "900") + endif() + else() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + # if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + # else(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0.0") + # set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++17") + # endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0.0") + endif() + endif() + + if(OS_IS_MACOSX) + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -stdlib=libc++") + endif() +endif() + +if(NOT ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND NOT WIN32) + if(NOT (CMAKE_VERSION VERSION_LESS "3.1")) + set(CMAKE_C_STANDARD 11) + set(CMAKE_CXX_STANDARD 14) + endif() +endif() # Processor-architecture related flags -# See http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options -if (NOT ARCH_COMPILER_FLAGS) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) - if(OS_IS_MACOSX) - set(ARCH_COMPILER_FLAGS "-march=corei7 -mfpmath=sse") - else(OS_IS_MACOSX) - if(NOT ${ENABLE_GENERIC_ARCH}) - if(IS_ARM) # ARM-specific options (https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html) - if(NOT CMAKE_CROSSCOMPILING) - if(ARM_VERSION STREQUAL "arm") - # Unknown arm version - try our best to detect - set(ARCH_COMPILER_FLAGS "-mcpu=native") - else(ARM_VERSION STREQUAL "arm") - set(ARCH_COMPILER_FLAGS "-march=${ARM_VERSION}") - endif(ARM_VERSION STREQUAL "arm") - endif(NOT CMAKE_CROSSCOMPILING) - else(IS_ARM) - set(ARCH_COMPILER_FLAGS "-march=native -mfpmath=sse") - endif(IS_ARM) - endif(NOT ${ENABLE_GENERIC_ARCH}) - endif(OS_IS_MACOSX) - endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) -endif (NOT ARCH_COMPILER_FLAGS) +# See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html +if(NOT ARCH_COMPILER_FLAGS) + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) + if(OS_IS_MACOSX) + set(ARCH_COMPILER_FLAGS "-march=corei7 -mfpmath=sse") + else() + if(NOT ${ENABLE_GENERIC_ARCH}) + if(IS_ARM) # ARM-specific options (https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html) + if(NOT CMAKE_CROSSCOMPILING) + if(ARM_VERSION STREQUAL "arm") + # Unknown arm version - try our best to detect + set(ARCH_COMPILER_FLAGS "-mcpu=native") + else() + set(ARCH_COMPILER_FLAGS "-march=${ARM_VERSION}") + endif() + endif() + else() + set(ARCH_COMPILER_FLAGS "-march=native -mfpmath=sse") + endif() + endif() + endif() + endif() +endif() set(MY_CXX_FLAGS "${MY_CXX_FLAGS} ${ARCH_COMPILER_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_FLAGS}") -if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) - #http://gcc.gnu.org/wiki/Visibility +if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) + # https://gcc.gnu.org/wiki/Visibility add_definitions(-fvisibility=hidden) -endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) +endif() +######################################################################## +# clang-tidy https://clang.llvm.org/extra/clang-tidy/index.html +######################################################################## +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(NOT (CMAKE_VERSION VERSION_LESS "3.6")) + find_program( + CLANG_TIDY_EXE + NAMES "clang-tidy" + DOC "Path to clang-tidy executable" + ) + if(NOT CLANG_TIDY_EXE) + message(STATUS "clang-tidy not found.") + else() + message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") + set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-checks=*") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + endif() + endif() +endif() + ######################################################################## # Create uninstall target @@ -1301,4 +1656,3 @@ add_custom_target(uninstall # Add subdirectories (in order of deps) ######################################################################## add_subdirectory(src) - diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 33e45b9d5..8db189904 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -68,7 +68,7 @@ members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] +available at [https://contributor-covenant.org/version/1/4][version] -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12cc1328f..06f37b0a2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ GitHub](https://github.com/join). GitHub](https://github.com/gnss-sdr/gnss-sdr/fork). This will copy the whole gnss-sdr repository to your personal account. - 3. Then, go to your favourite working folder in your computer and + 3. Then, go to your favorite working folder in your computer and clone your forked repository by typing (replacing ```YOUR_USERNAME``` by the actual username of your GitHub account): @@ -75,7 +75,7 @@ the actual username of your GitHub account): 4. Your forked repository https://github.com/YOUR_USERNAME/gnss-sdr will receive the default name of `origin`. You can also add the original -gnss-sdr repository, which is usually called `upstream`: +gnss-sdr repository, which is usually referred to as `upstream`: $ cd gnss-sdr $ git remote add upstream https://github.com/gnss-sdr/gnss-sdr.git @@ -128,6 +128,8 @@ $ git pull --rebase upstream next ### How to submit a pull request +Before submitting your code, please be sure to [apply clang-format](https://gnss-sdr.org/coding-style/#use-tools-for-automated-code-formatting). + When the contribution is ready, you can [submit a pull request](https://github.com/gnss-sdr/gnss-sdr/compare/). Head to your GitHub repository, switch to your `my_feature` branch, and click the @@ -144,24 +146,24 @@ accepted: * Avoid platform-dependent code. If your code require external dependencies, they must be available as packages in [Debian OldStable](https://wiki.debian.org/DebianOldStable). * Write tests. - * Follow our [coding style guide](http://gnss-sdr.org/coding-style/). + * Follow our [coding style guide](https://gnss-sdr.org/coding-style/). * Write a descriptive and detailed summary. Please consider that reviewing pull requests is hard, so include as much information as possible to make your pull request's intent clear. For more details about Git usage, please check out [our -tutorial](http://gnss-sdr.org/docs/tutorials/using-git/). +tutorial](https://gnss-sdr.org/docs/tutorials/using-git/). ## Contributing to the website -The content of http://gnss-sdr.org lives in a GitHub repository at +The content of https://gnss-sdr.org lives in a GitHub repository at https://github.com/gnss-sdr/geniuss-place You can fork that repository, reproduce the entire website on your computer using [Jekyll](https://jekyllrb.com/), do changes and submit pull requests, just as explained above. For more details, please check -out [how to contribute](http://gnss-sdr.org/contribute/). +out [how to contribute](https://gnss-sdr.org/contribute/). Last but not the least, you can leave your comments on the website. @@ -171,6 +173,6 @@ Last but not the least, you can leave your comments on the website. ![GeNiuSS -contributes](http://gnss-sdr.org/assets/images/geniuss-contribute.png) +contributes](https://gnss-sdr.org/assets/images/geniuss-contribute.png) Thanks for your contribution to GNSS-SDR! diff --git a/COPYING b/COPYING index 818433ecc..8859f3d09 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found. 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 . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/MANIFEST.md b/MANIFEST.md index 487b88be4..ea64ec678 100644 --- a/MANIFEST.md +++ b/MANIFEST.md @@ -5,6 +5,7 @@ tags: - gnss - gps - Galileo + - Glonass author: - Carles Fernandez-Prades - Javier Arribas @@ -17,15 +18,15 @@ dependencies: - gflags - glog - gnutls + - matio license: GPLv3+ repo: https://github.com/gnss-sdr/gnss-sdr website: https://gnss-sdr.org icon: https://gnss-sdr.org/assets/images/logo400x400.jpg --- -Global Navigation Satellite Systems receiver defined by software. It performs all the signal -processing from raw signal samples up to the computation of the Position-Velocity-Time solution, -including code and phase observables. It is able to work with raw data files or, if there is -computational power enough, in real time with suitable radiofrequency front-ends. This software +Global Navigation Satellite Systems receiver defined by software. It performs all the signal +processing from raw signal samples up to the computation of the Position-Velocity-Time solution, +including code and phase observables. It is able to work with raw data files or, if there is +computational power enough, in real time with suitable radiofrequency front-ends. This software is mainly developed at [CTTC](http://www.cttc.es "Centre Tecnologic de Telecomunicacions de Catalunya") with contributions from around the world. More info at [gnss-sdr.org](https://gnss-sdr.org "GNSS-SDR's Homepage"). - diff --git a/README.md b/README.md index 3d7c7104d..184f67102 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,38 @@ -![](./docs/doxygen/images/gnss-sdr_logo.png) +[![](./docs/doxygen/images/gnss-sdr_logo.png)](https://gnss-sdr.org "GNSS-SDR website") + +[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) **Welcome to GNSS-SDR!** -Visit [gnss-sdr.org](http://gnss-sdr.org "GNSS-SDR's Homepage") for more information about this open source GNSS software defined receiver. +This program is a software-defined receiver which is able to process (that is, to perform detection, synchronization, demodulation and decoding of the navigation message, computation of observables and, finally, computation of position fixes) the following Global Navigation Satellite System's signals: -If you have questions about GNSS-SDR, please [subscribe to the gnss-sdr-developers mailing list](http://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers "Subscribe to the gnss-sdr-developers mailing list" ) and post your questions there. +In the L1 band: + - 🛰 GPS L1 C/A (centered at 1575.42 MHz) :white_check_mark: + - 🛰 Galileo E1b/c (centered at 1575.42 MHz) :white_check_mark: + - 🛰 GLONASS L1 C/A (centered at 1601.72 MHz) :white_check_mark: + +In the L2 band: + - 🛰 GPS L2C (centered at 1227.60 MHz) :white_check_mark: + - 🛰 GLONASS L2 C/A (centered at 1246 MHz) :white_check_mark: + +In the L5 band: + - 🛰 GPS L5 (centered at 1176.45 MHz) :white_check_mark: + - 🛰 Galileo E5a (centered at 1176.45 MHz) :white_check_mark: + +GNSS-SDR provides interfaces for a wide range of radio frequency front-ends and raw sample file formats, generates processing outputs in standard formats, allows for the full inspection of the whole signal processing chain, and offers a framework for the development of new features. Please visit [https://gnss-sdr.org](https://gnss-sdr.org "GNSS-SDR website") for more information about this open source software-defined GNSS receiver. # How to build GNSS-SDR -This section describes how to set up the compilation environment in GNU/Linux or [macOS / Mac OS X](#macosx), and to build GNSS-SDR. See also our [build and install page](http://gnss-sdr.org/build-and-install/ "GNSS-SDR's Build and Install"). +This section describes how to set up the compilation environment in GNU/Linux or [macOS / Mac OS X](#macosx), and to build GNSS-SDR. See also our [build and install page](https://gnss-sdr.org/build-and-install/ "GNSS-SDR's Build and Install"). GNU/Linux ---------- - * Tested distributions: Ubuntu 14.04 LTS and [above](http://packages.ubuntu.com/search?keywords=gnss-sdr), Debian 8.0 "jessie" and [above](https://packages.debian.org/search?searchon=names&keywords=gnss-sdr), Linaro 15.03 - * Known to work but not continually tested: Arch Linux, Fedora, and openSUSE + * Tested distributions: Ubuntu 14.04 LTS and above; Debian 8.0 "jessie" and above; Fedora 26 and above; CentOS 7; Arch Linux. * Supported microprocessor architectures: * i386: Intel x86 instruction set (32-bit microprocessors). * amd64: also known as x86-64, the 64-bit version of the x86 instruction set, originally created by AMD and implemented by AMD, Intel, VIA and others. @@ -39,38 +53,76 @@ Before building GNSS-SDR, you need to install all the required dependencies. The ### Alternative 1: Install dependencies using software packages -If you want to start building and running GNSS-SDR as quick and easy as possible, the best option is to install all the required dependencies as binary packages. If you are using Debian 8, Ubuntu 14.10 or above, this can be done by copying and pasting the following line in a terminal: +If you want to start building and running GNSS-SDR as quick and easy as possible, the best option is to install all the required dependencies as binary packages. + +#### Debian / Ubuntu + +If you are using Debian 8, Ubuntu 14.10 or above, this can be done by copying and pasting the following line in a terminal: ~~~~~~ $ sudo apt-get install build-essential cmake git libboost-dev libboost-date-time-dev \ libboost-system-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev \ - libboost-serialization-dev libboost-program-options-dev libboost-test-dev \ - liblog4cpp5-dev libuhd-dev gnuradio-dev gr-osmosdr libblas-dev liblapack-dev \ - libarmadillo-dev libgflags-dev libgoogle-glog-dev libgnutls-openssl-dev libgtest-dev \ - python-mako python-six + libboost-serialization-dev liblog4cpp5-dev libuhd-dev gnuradio-dev gr-osmosdr \ + libblas-dev liblapack-dev libarmadillo-dev libgflags-dev libgoogle-glog-dev \ + libgnutls-openssl-dev libpcap-dev python-mako python-six libmatio-dev libpugixml-dev \ + libgtest-dev ~~~~~~ -Alternatively, and starting from Ubuntu 16.04 LTS, you can install all the required dependencies by adding the line +Please note that the required files from `libgtest-dev` were moved to `googletest` in Debian 9 "stretch" and Ubuntu 18.04 "bionic", and moved back again to `libgtest-dev` in Debian 10 "buster" and Ubuntu 18.10 "cosmic". + +**Note for Ubuntu 14.04 LTS "trusty" users:** you will need to build from source and install GNU Radio manually, as explained below, since GNSS-SDR requires `gnuradio-dev` >= 3.7.3, and Ubuntu 14.04 came with 3.7.2. Install all the packages above BUT EXCEPT `libuhd-dev`, `gnuradio-dev` and `gr-osmosdr` (and remove them if they are already installed in your machine), and install those dependencies using PyBOMBS. The same applies to `libmatio-dev`: Ubuntu 14.04 came with 1.5.2 and the minimum required version is 1.5.3. Please do not install the `libmatio-dev` package and install `libtool`, `automake` and `libhdf5-dev` instead. A recent version of the library will be downloaded and built automatically if CMake does not find it installed. + +**Note for Debian 8 "jessie" users:** please see the note about `libmatio-dev` above. Install `libtool`, `automake` and `libhdf5-dev` instead. + +Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). + + +#### Fedora + +If you are using Fedora 26 or above, the required software dependencies can be installed by doing: ~~~~~~ -deb-src http://us.archive.ubuntu.com/ubuntu/ xenial universe +$ sudo yum install make automake gcc gcc-c++ kernel-devel cmake git boost-devel \ + boost-date-time boost-system boost-filesystem boost-thread boost-chrono \ + boost-serialization log4cpp-devel gnuradio-devel gr-osmosdr-devel \ + blas-devel lapack-devel matio-devel armadillo-devel gflags-devel \ + glog-devel openssl-devel libpcap-devel python-mako python-six pugixml-devel ~~~~~~ -to your ```/etc/apt/sources.list``` file and doing: +Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). + +#### CentOS + +If you are using CentOS 7, you can install the dependencies via Extra Packages for Enterprise Linux ([EPEL](https://fedoraproject.org/wiki/EPEL)): ~~~~~~ -$ sudo apt-get update -$ sudo apt-get build-dep gnss-sdr +$ sudo yum install wget +$ wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm +$ sudo rpm -Uvh epel-release-latest-7.noarch.rpm +$ sudo yum install make automake gcc gcc-c++ kernel-devel libtool \ + hdf5-devel cmake git boost-devel boost-date-time boost-system \ + boost-filesystem boost-thread boost-chrono boost-serialization \ + log4cpp-devel gnuradio-devel gr-osmosdr-devel blas-devel lapack-devel \ + armadillo-devel openssl-devel libpcap-devel python-mako python-six pugixml-devel ~~~~~~ -Once you have installed these packages, you can jump directly to [how to download the source code and build GNSS-SDR](#download-and-build-linux). +Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). -Note for Ubuntu 14.04 LTS "trusty" users: you will need to build from source and install GNU Radio manually, as explained below, since GNSS-SDR requires gnuradio-dev >= 3.7.3, and Ubuntu 14.04 came with 3.7.2. Install all the packages above BUT EXCEPT ```libuhd-dev```, ```gnuradio-dev``` and ```gr-osmosdr``` (and remove them if they are already installed in your machine), and install those dependencies using PyBOMBS. +#### Arch Linux +If you are using Arch Linux (with base-devel group installed): + +~~~~~~ +$ pacman -S cmake git boost boost-libs log4cpp libvolk gnuradio gnuradio-osmosdr \ + blas lapack gflags google-glog openssl pugixml python-mako python-six \ + libmatio libpcap gtest +~~~~~~ + +Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). ### Alternative 2: Install dependencies using PyBOMBS -This option is adequate if you are interested in development, in working with the most recent versions of software dependencies, want more fine tuning on the installed versions, or simply in building everything from the scratch just for the fun of it. In such cases, we recommend to use [PyBOMBS](http://gnuradio.org/pybombs "Python Build Overlay Managed Bundle System wiki") (Python Build Overlay Managed Bundle System), GNU Radio's meta-package manager tool that installs software from source, or whatever the local package manager is, that automatically does all the work for you. Please take a look at the configuration options and general PyBOMBS usage at https://github.com/gnuradio/pybombs. Here we provide a quick step-by-step tutorial. +This option is adequate if you are interested in development, in working with the most recent versions of software dependencies, want more fine tuning on the installed versions, or simply in building everything from the scratch just for the fun of it. In such cases, we recommend to use [PyBOMBS](https://github.com/gnuradio/pybombs "Python Build Overlay Managed Bundle System") (Python Build Overlay Managed Bundle System), GNU Radio's meta-package manager tool that installs software from source, or whatever the local package manager is, that automatically does all the work for you. Please take a look at the configuration options and general PyBOMBS usage at https://github.com/gnuradio/pybombs. Here we provide a quick step-by-step tutorial. First of all, install some basic packages: @@ -84,11 +136,16 @@ Download, build and install PyBOMBS: $ sudo pip install git+https://github.com/gnuradio/pybombs.git ~~~~~~ -Add some software recipes (i.e., instructions on how to install software dependencies): +Apply a configuration: ~~~~~~ -$ pybombs recipes add gr-recipes git+https://github.com/gnuradio/gr-recipes.git -$ pybombs recipes add gr-etcetera git+https://github.com/gnuradio/gr-etcetera.git +$ pybombs auto-config +~~~~~~ + +Add list of default recipes: + +~~~~~~ +$ pybombs recipes add-defaults ~~~~~~ Download, build and install GNU Radio, related drivers and some other extra modules into the directory ```/path/to/prefix``` (replace this path by your preferred one, for instance ```$HOME/sdr```): @@ -112,7 +169,7 @@ $ pybombs install gnss-sdr By default, PyBOMBS installs the ‘next’ branch of GNSS-SDR development, which is the most recent version of the source code. This behaviour can be modified by altering the corresponding recipe at ```$HOME/.pybombs/recipes/gr-recipes/gnss-sdr.lwr``` -In case you do not want to use PyBOMBS and prefer to build and install GNSS-SDR step by step (i.e., cloning the repository and doing the usual ```cmake .. && make && make install``` dance), Armadillo, GFlags, Glog and GunTLS can be installed either by using PyBOMBS: +In case you do not want to use PyBOMBS and prefer to build and install GNSS-SDR step by step (i.e., cloning the repository and doing the usual ```cmake .. && make && make install``` dance), Armadillo, GFlags, Glog and GnuTLS can be installed either by using PyBOMBS: ~~~~~~ $ pybombs install armadillo gflags glog gnutls @@ -126,27 +183,28 @@ or manually as explained below, and then please follow instructions on how to [d #### Install [Armadillo](http://arma.sourceforge.net/ "Armadillo's Homepage"), a C++ linear algebra library: ~~~~~~ -$ sudo apt-get install libopenblas-dev liblapack-dev # For Debian/Ubuntu/LinuxMint +$ sudo apt-get install libblas-dev liblapack-dev # For Debian/Ubuntu/LinuxMint $ sudo yum install lapack-devel blas-devel # For Fedora/CentOS/RHEL $ sudo zypper install lapack-devel blas-devel # For OpenSUSE -$ wget http://sourceforge.net/projects/arma/files/armadillo-7.600.2.tar.xz -$ tar xvfz armadillo-7.600.2.tar.xz -$ cd armadillo-7.600.2 +$ sudo pacman -S blas lapack # For Arch Linux +$ wget https://sourceforge.net/projects/arma/files/armadillo-9.100.5.tar.xz +$ tar xvfz armadillo-9.100.5.tar.xz +$ cd armadillo-9.100.5 $ cmake . $ make $ sudo make install ~~~~~~ -The full stop separated from ```cmake``` by a space is important. [CMake](http://www.cmake.org/ "CMake's Homepage") will figure out what other libraries are currently installed and will modify Armadillo's configuration correspondingly. CMake will also generate a run-time armadillo library, which is a combined alias for all the relevant libraries present on your system (eg. BLAS, LAPACK and ATLAS). +The full stop separated from ```cmake``` by a space is important. [CMake](https://cmake.org/ "CMake's Homepage") will figure out what other libraries are currently installed and will modify Armadillo's configuration correspondingly. CMake will also generate a run-time armadillo library, which is a combined alias for all the relevant libraries present on your system (eg. BLAS, LAPACK and ATLAS). #### Install [Gflags](https://github.com/gflags/gflags "Gflags' Homepage"), a commandline flags processing module for C++: ~~~~~~ -$ wget https://github.com/gflags/gflags/archive/v2.2.0.tar.gz -$ tar xvfz v2.2.0.tar.gz -$ cd gflags-2.2.0 +$ wget https://github.com/gflags/gflags/archive/v2.2.2.tar.gz +$ tar xvfz v2.2.2.tar.gz +$ cd gflags-2.2.2 $ cmake -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF -DBUILD_gflags_nothreads_LIB=OFF . $ make $ sudo make install @@ -158,9 +216,9 @@ $ sudo ldconfig #### Install [Glog](https://github.com/google/glog "Glog's Homepage"), a library that implements application-level logging: ~~~~~~ -$ wget https://github.com/google/glog/archive/v0.3.4.tar.gz -$ tar xvfz v0.3.4.tar.gz -$ cd glog-0.3.4 +$ wget https://github.com/google/glog/archive/v0.3.5.tar.gz +$ tar xvfz v0.3.5.tar.gz +$ cd glog-0.3.5 $ ./configure $ make $ sudo make install @@ -172,28 +230,30 @@ $ sudo ldconfig #### Build the [Google C++ Testing Framework](https://github.com/google/googletest "Googletest Homepage"), also known as Google Test: ~~~~~~ -$ wget https://github.com/google/googletest/archive/release-1.8.0.zip -$ unzip release-1.8.0.zip -$ cd googletest-release-1.8.0 -$ cmake -DBUILD_GTEST=ON -DBUILD_GMOCK=OFF . +$ wget https://github.com/google/googletest/archive/release-1.8.1.zip +$ unzip release-1.8.1.zip +$ cd googletest-release-1.8.1 +$ cmake -DINSTALL_GTEST=OFF -DBUILD_GMOCK=OFF . $ make ~~~~~~ Please **DO NOT install** Google Test (do *not* type ```sudo make install```). Every user needs to compile his tests using the same compiler flags used to compile the installed Google Test libraries; otherwise he may run into undefined behaviors (i.e. the tests can behave strangely and may even crash for no obvious reasons). The reason is that C++ has this thing called the One-Definition Rule: if two C++ source files contain different definitions of the same class/function/variable, and you link them together, you violate the rule. The linker may or may not catch the error (in many cases it is not required by the C++ standard to catch the violation). If it does not, you get strange run-time behaviors that are unexpected and hard to debug. If you compile Google Test and your test code using different compiler flags, they may see different definitions of the same class/function/variable (e.g. due to the use of ```#if``` in Google Test). Therefore, for your sanity, we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests. The building system of GNSS-SDR does the compilation and linking of googletest to its own tests; it is only required that you tell the system where the googletest folder that you downloaded resides. Just add to your ```$HOME/.bashrc``` file the following line: ~~~~~~ -export GTEST_DIR=/home/username/googletest-release-1.8.0/googletest +export GTEST_DIR=/home/username/googletest-release-1.8.1/googletest ~~~~~~ -changing `/home/username/googletest-release-1.8.0/googletest` by the actual directory where you built googletest. +changing `/home/username/googletest-release-1.8.1/googletest` by the actual directory where you built googletest. -#### Install the [GnuTLS library](http://www.gnutls.org/ "GnuTLS's Homepage"): +#### Install the [GnuTLS](https://www.gnutls.org/ "GnuTLS's Homepage") or [OpenSSL](https://www.openssl.org/ "OpenSSL's Homepage") libraries: ~~~~~~ $ sudo apt-get install libgnutls-openssl-dev # For Debian/Ubuntu/LinuxMint -$ sudo yum install libgnutls-openssl-devel # For Fedora/CentOS/RHEL +$ sudo yum install openssl-devel # For Fedora/CentOS/RHEL +$ sudo zypper install openssl-devel # For OpenSUSE +$ sudo pacman -S openssl # For Arch Linux ~~~~~~ In case the GnuTLS library with openssl extensions package is not available in your GNU/Linux distribution, GNSS-SDR can also work well with OpenSSL. @@ -230,7 +290,7 @@ By default, you will be in the 'master' branch of the Git repository, which corr $ git checkout next ~~~~~~ -More information about GNSS-SDR-specific Git usage and pointers to further readings can be found at our [Git tutorial](http://gnss-sdr.org/docs/tutorials/using-git/ "Using Git"). +More information about GNSS-SDR-specific Git usage and pointers to further readings can be found at our [Git tutorial](https://gnss-sdr.org/docs/tutorials/using-git/ "Using Git"). ### Build and install GNSS-SDR @@ -248,7 +308,7 @@ $ cmake ../ $ make ~~~~~~ -By default, CMake will build the Release version, meaning that the compiler will generate a fast, optimized executable. This is the recommended build type when using a RF front-end and you need to attain real time. If working with a file (and thus without real-time constraints), you may want to obtain more information about the internals of the receiver, as well as more fine-grained logging. This can be done by building the Debug version, by doing: +By default, CMake will build the Release version, meaning that the compiler will generate a fast, optimized executable. This is the recommended build type when using an RF front-end and you need to attain real time. If working with a file (and thus without real-time constraints), you may want to obtain more information about the internals of the receiver, as well as more fine-grained logging. This can be done by building the Debug version, by doing: ~~~~~~ $ cmake -DCMAKE_BUILD_TYPE=Debug ../ @@ -291,7 +351,7 @@ GNSS-SDR comes with a library which is a module of the Vector-Optimized Library If you are using Eclipse as your development environment, CMake can create the project for you. Type: ~~~~~~ -$ cmake -G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DECLIPSE_CDT4_GENERATE_SOURCE_PROJECT=TRUE -DCMAKE_ECLIPSE_VERSION=3.7 -DCMAKE_ECLIPSE_MAKE_ARGUMENTS=-j8 ../ +$ cmake -G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DECLIPSE_GENERATE_SOURCE_PROJECT=TRUE -DCMAKE_ECLIPSE_VERSION=4.5 . ~~~~~~ and then import the created project file into Eclipse: @@ -368,7 +428,52 @@ $ sudo make install (in order to disable the `Osmosdr_Signal_Source` compilation, you can pass `DENABLE_OSMOSDR=OFF` to cmake and build GNSS-SDR again). +###### Build FMCOMMS2 based SDR Hardware support (OPTIONAL): +Install the [libiio](https://github.com/analogdevicesinc/libiio.git) (>=v0.11), [libad9361](https://github.com/analogdevicesinc/libad9361-iio.git) (>=v0.1-1) libraries and [gr-iio](https://github.com/analogdevicesinc/gr-iio.git) (>v0.3) gnuradio block: + +~~~~~~ +$ sudo apt-get install libxml2-dev bison flex +$ git clone https://github.com/analogdevicesinc/libiio.git +$ cd libiio +$ mkdir build +$ cd build +$ cmake .. +$ make && sudo make install && sudo ldconfig +$ cd ../.. +$ git clone https://github.com/analogdevicesinc/libad9361-iio.git +$ cd libad9361-iio +$ mkdir build +$ cd build +$ cmake .. +$ make && sudo make install && sudo ldconfig +$ cd ../.. +$ git clone https://github.com/analogdevicesinc/gr-iio.git +$ cd gr-iio +$ mkdir build +$ cd build +$ cmake -DCMAKE_INSTALL_PREFIX=/usr .. +$ make && sudo make install && sudo ldconfig +$ cd ../.. +~~~~~~ + +Then configure GNSS-SDR to build the `Fmcomms2_Signal_Source` implementation: + +~~~~~~ +$ cd gnss-sdr/build +$ cmake -DENABLE_FMCOMMS2=ON ../ +$ make +$ sudo make install +~~~~~~ + +or configure it to build `Plutosdr_Signal_Source`: +~~~~~~ +$ cmake -DENABLE_PLUTOSDR=ON ../ +$ make +$ sudo make install +~~~~~~ + +With `Fmcomms2_Signal_Source` you can use any SDR hardware based on [FMCOMMS2](https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz), including the ADALM-PLUTO (PlutoSdr) by configuring correctly the .conf file. The `Plutosdr_Signal_Source` offers a simpler manner to use the ADALM-PLUTO because implements only a subset of FMCOMMS2's parameters valid for those devices. ###### Build OpenCL support (OPTIONAL): @@ -406,15 +511,13 @@ $ sudo make install Using this option, all SIMD instructions are exclusively accessed via VOLK, which automatically includes versions of each function for different SIMD instruction sets, then detects at runtime which to use, or if there are none, substitutes a generic, non-SIMD implementation. +More details can be found in our tutorial about [GNSS-SDR configuration options at building time](https://gnss-sdr.org/docs/tutorials/using-git/ "Configuration options at building time"). macOS and Mac OS X --------- - -### macOS Sierra, Mac OS X 10.11 (El Capitan), 10.10 (Yosemite) and 10.9 (Mavericks). - -If you still have not installed [Xcode](http://developer.apple.com/xcode/ "Xcode"), do it now from the App Store (it's free). You will also need the Xcode Command Line Tools. Launch the Terminal, found in /Applications/Utilities/, and type: +GNSS-SDR can be built on MacOS or Mac OS X, starting from 10.9 (Mavericks) and including 10.14 (Mojave). If you still have not installed [Xcode](https://developer.apple.com/xcode/ "Xcode"), do it now from the App Store (it's free). You will also need the Xcode Command Line Tools. Launch the Terminal, found in /Applications/Utilities/, and type: ~~~~~~ $ xcode-select --install @@ -428,9 +531,9 @@ $ sudo xcodebuild -license Software pre-requisites can be installed using either [Macports](#macports) or [Homebrew](#homebrew). -####Macports +#### Macports -First, [install Macports](http://www.macports.org/install.php). If you are upgrading from a previous installation, please follow the [migration rules](http://trac.macports.org/wiki/Migration). +First, [install Macports](https://www.macports.org/install.php). If you are upgrading from a previous installation, please follow the [migration rules](https://trac.macports.org/wiki/Migration). In a terminal, type: @@ -444,6 +547,8 @@ $ sudo port install gnutls $ sudo port install google-glog +gflags $ sudo port install py27-mako $ sudo port install py27-six +$ sudo port install matio +$ sudo port install pugixml ~~~~~~ You also might need to activate a Python installation. The list of installed versions can be retrieved with: @@ -452,7 +557,7 @@ You also might need to activate a Python installation. The list of installed ver $ port select list python ~~~~~~ -and you can activate a certain version (2.7 works well) by typing: +and you can activate a certain version by typing: ~~~~~~ $ sudo port select --set python python27 @@ -460,15 +565,32 @@ $ sudo port select --set python python27 #### Homebrew -Instructions for installing GNU Radio using [homebrew](http://www.brew.sh) can be found [here](http://github.com/odrisci/homebrew-gnuradio) - please ensure to install all dependencies as required. +First, install [Homebrew](https://brew.sh/). Paste this in a terminal prompt: -Install Armadillo and dependencies: +~~~~~~ +$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +~~~~~~ + +The script explains what it will do and then pauses before it does it. There are more installation options [here](https://docs.brew.sh/Installation.html). + +Install pip: + +~~~~~~ +$ sudo easy_install pip +~~~~~~ + +Install the required dependencies: ~~~~~~ $ brew tap homebrew/science $ brew install cmake hdf5 arpack superlu $ brew install armadillo $ brew install glog gflags gnutls +$ brew install gnuradio +$ brew install libmatio +$ brew install pugixml +$ pip install mako +$ pip install six ~~~~~~ #### Build GNSS-SDR @@ -506,7 +628,7 @@ GNSS-SDR comes with a library which is a module of the Vector-Optimized Library ###### Other package managers -GNU Radio and other dependencies can also be installed using other package managers than Macports, such as [Fink](http://www.finkproject.org/ "Fink") or [Homebrew](http://brew.sh/ "Homebrew"). Since the version of Python that ships with OS X is great for learning but it is not good for development, you could have another Python executable in a non-standard location. If that is the case, you need to inform GNSS-SDR's configuration system by defining the `PYTHON_EXECUTABLE` variable as: +GNU Radio and other dependencies can also be installed using other package managers than Macports, such as [Fink](http://www.finkproject.org/ "Fink") or [Homebrew](https://brew.sh/ "Homebrew"). Since the version of Python that ships with OS X is great for learning but it is not good for development, you could have another Python executable in a non-standard location. If that is the case, you need to inform GNSS-SDR's configuration system by defining the `PYTHON_EXECUTABLE` variable as: ~~~~~~ cmake -DPYTHON_EXECUTABLE=/path/to/bin/python ../ @@ -525,10 +647,11 @@ The CMake script will create Makefiles that download, build and link Armadillo, Other builds --------- +* **Docker container**: A technology providing operating-system-level virtualization to build, ship, and run distributed applications, whether on laptops, data center VMs, or the cloud. Visit [https://github.com/carlesfernandez/docker-gnsssdr](https://github.com/carlesfernandez/docker-gnsssdr) or [https://github.com/carlesfernandez/docker-pybombs-gnsssdr](https://github.com/carlesfernandez/docker-pybombs-gnsssdr) for instructions. -* **Snap packages**: [Snaps](http://snapcraft.io) are universal Linux packages aimed to work on any distribution or device, from IoT devices to servers, desktops to mobile devices. Visit [https://github.com/carlesfernandez/snapcraft-sandbox](https://github.com/carlesfernandez/snapcraft-sandbox) for instructions. +* **Snap packages**: [Snaps](https://snapcraft.io) are universal Linux packages aimed to work on any distribution or device, from IoT devices to servers, desktops to mobile devices. Visit [https://github.com/carlesfernandez/snapcraft-sandbox](https://github.com/carlesfernandez/snapcraft-sandbox) for instructions. -* **GNSS-SDR in embedded platforms**: we provide a Software Development Kit (SDK) based on [OpenEmbedded](http://www.openembedded.org/wiki/Main_Page) for cross-compiling GNSS-SDR in your desktop computer and for producing executables that can run in embedded platforms, such as a Zedboard or a Raspberry Pi 3. Visit [Cross-compiling GNSS-SDR](http://gnss-sdr.org/docs/tutorials/cross-compiling/) for instructions. +* **GNSS-SDR in embedded platforms**: we provide a Software Development Kit (SDK) based on [OpenEmbedded](http://www.openembedded.org/wiki/Main_Page) for cross-compiling GNSS-SDR in your desktop computer and for producing executables that can run in embedded platforms, such as a Zedboard or a Raspberry Pi 3. Visit [Cross-compiling GNSS-SDR](https://gnss-sdr.org/docs/tutorials/cross-compiling/) for instructions. Updating GNSS-SDR @@ -560,9 +683,9 @@ Before rebuilding the source code, it is safe (and recommended) to remove the re $ rm -rf gnss-sdr/build/* ~~~~~~ -If you are interested in contributing to the development of GNSS-SDR, please check out [how to do it](http://gnss-sdr.org/contribute/ "How to contribute to GNSS-SDR source code"). +If you are interested in contributing to the development of GNSS-SDR, please check out [how to do it](https://gnss-sdr.org/contribute/ "How to contribute to GNSS-SDR source code"). -There is a more controlled way to upgrade your repository, which is to use the Git commands ```fetch``` and ```merge```, as described in our [Git Tutorial](http://gnss-sdr.org/docs/tutorials/using-git/ "Using Git"). +There is a more controlled way to upgrade your repository, which is to use the Git commands ```fetch``` and ```merge```, as described in our [Git Tutorial](https://gnss-sdr.org/docs/tutorials/using-git/ "Using Git"). @@ -574,32 +697,31 @@ Getting started 1. After building the code, you will find the ```gnss-sdr``` executable file at gnss-sdr/install. You can make it available everywhere else by ```sudo make install```. Run the profilers ```volk_profile``` and ```volk_gnsssdr_profile``` for testing all available VOLK kernels for each architecture supported by your processor. This only has to be done once. 2. In post-processing mode, you have to provide a captured GNSS signal file. 1. The signal file can be easily recorded using the GNU Radio file sink in ```gr_complex``` mode. - 2. You will need a GPS active antenna, a [USRP](http://www.ettus.com/product) and a suitable USRP daughter board to receive GPS L1 C/A signals. GNSS-SDR require to have at least 2 MHz of bandwidth in 1.57542 GHz. (remember to enable the DC bias with the daughter board jumper). + 2. You will need a GPS active antenna, a [USRP](https://www.ettus.com/product) and a suitable USRP daughter board to receive GPS L1 C/A signals. GNSS-SDR require to have at least 2 MHz of bandwidth in 1.57542 GHz. (remember to enable the DC bias with the daughter board jumper). We use a [DBSRX2](https://www.ettus.com/product/details/DBSRX2) to do the task, but you can try the newer Ettus' daughter boards as well. 3. The easiest way to capture a signal file is to use the GNU Radio Companion GUI. Only two blocks are needed: a USRP signal source connected to complex float file sink. You need to tune the USRP central frequency and decimation factor using USRP signal source properties box. We suggest using a decimation factor of 20 if you use the USRP2. This will give you 100/20 = 5 MSPS which will be enough to receive GPS L1 C/A signals. The front-end gain should also be configured. In our test with the DBSRX2 we obtained good results with ```G=50```. - 4. Capture at least 80 seconds of signal in open sky conditions. During the process, be aware of USRP driver buffer underuns messages. If your hard disk is not fast enough to write data at this speed you can capture to a virtual RAM drive. 80 seconds of signal at 5 MSPS occupies less than 3 Gbytes using ```gr_complex```. - 5. If you have no access to a RF front-end, you can download a sample raw data file (that contains GPS and Galileo signals) from [here](http://sourceforge.net/projects/gnss-sdr/files/data/). + 4. Capture at least 80 seconds of signal in open sky conditions. During the process, be aware of USRP driver buffer underruns messages. If your hard disk is not fast enough to write data at this speed you can capture to a virtual RAM drive. 80 seconds of signal at 5 MSPS occupies less than 3 Gbytes using ```gr_complex```. + 5. If you have no access to an RF front-end, you can download a sample raw data file (that contains GPS and Galileo signals) from [here](https://sourceforge.net/projects/gnss-sdr/files/data/). 3. You are ready to configure the receiver to use your captured file among other parameters: 1. The default configuration file resides at [/usr/local/share/gnss-sdr/conf/default.conf](./conf/gnss-sdr.conf). 2. You need to review/modify at least the following settings: * ```SignalSource.filename=``` (absolute or relative route to your GNSS signal captured file) - * ```GNSS-SDR.internal_fs_hz=``` (captured file sampling rate in Hz) - * ```SignalSource.sampling_frequency=``` (captured file sampling rate in Hz) - * ```SignalConditioner.sample_freq_in=``` (captured file sampling rate in Hz) - * ```SignalConditioner.sample_freq_out=``` (captured file sampling rate in Hz) - * ```TelemetryDecoder.fs_in=``` (captured file sampling rate in Hz) + * ```GNSS-SDR.internal_fs_sps=``` (captured file sampling rate in samples per second) + * ```SignalSource.sampling_frequency=``` (captured file sampling rate in samples per second) + * ```SignalConditioner.sample_freq_in=``` (captured file sampling rate in samples per second) + * ```SignalConditioner.sample_freq_out=``` (captured file sampling rate in samples per second) 3. The configuration file has in-line documentation, you can try to tune the number of channels and several receiver parameters. Store your .conf file in some working directory of your choice. 4. Run the receiver invoking the configuration by ```$ gnss-sdr --config_file=/path/to/my_receiver.conf``` The program reports the current status in text mode, directly to the terminal window. If all goes well, and GNSS-SDR is able to successfully track and decode at least 4 satellites, you will get PVT fixes. The program will write .kml, .geojson and RINEX files in the folder from which ```gnss-sdr``` was run. In addition to the console output, GNSS-SDR also writes log files at /tmp/ (configurable with the commandline flag ```./gnss-sdr --log_dir=/path/to/log```). -For more information, check out our [quick start guide](http://gnss-sdr.org/quick-start-guide/). +For more information, check out our [quick start guide](https://gnss-sdr.org/quick-start-guide/). Using GNSS-SDR ============== -With GNSS-SDR, you can define you own receiver, work with captured raw data or from a RF front-end, dump into files intermediate signals, or tune every single algorithm used in the signal processing. All the configuration is done in a single file. Those configuration files reside at the [gnss-sdr/conf/](./conf/) folder (or at /usr/local/share/gnss-sdr/conf if you installed the program). By default, the executable ```gnss-sdr``` will read the configuration available at ```gnss-sdr/conf/gnss-sdr.conf``` (or at (usr/local/share/gnss-sdr/conf/default.conf if you installed the program). You can edit that file to fit your needs, or even better, define a new ```my_receiver.conf``` file with your own configuration. This new receiver can be generated by invoking gnss-sdr with the ```--config_file``` flag pointing to your configuration file: +With GNSS-SDR, you can define your own receiver, work with captured raw data or from an RF front-end, dump into files intermediate signals, or tune every single algorithm used in the signal processing. All the configuration is done in a single file. Those configuration files reside at the [gnss-sdr/conf/](./conf/) folder (or at /usr/local/share/gnss-sdr/conf if you installed the program). By default, the executable ```gnss-sdr``` will read the configuration available at ```gnss-sdr/conf/gnss-sdr.conf``` (or at (usr/local/share/gnss-sdr/conf/default.conf if you installed the program). You can edit that file to fit your needs, or even better, define a new ```my_receiver.conf``` file with your own configuration. This new receiver can be generated by invoking gnss-sdr with the ```--config_file``` flag pointing to your configuration file: ~~~~~~ $ gnss-sdr --config_file=/path/to/my_receiver.conf @@ -645,15 +767,15 @@ The name of these parameters can be anything but one reserved word: implementati SignalConditioner.implementation=Pass_Through ~~~~~~ -Since the configuration is just a set of property names and values without any meaning or syntax, the system is very versatile and easily extendable. Adding new properties to the system only implies modifications in the classes that will make use of these properties. In addition, the configuration files are not checked against any strict syntax so it is always in a correct status (as long as it contains pairs of property names and values in the [INI format](http://en.wikipedia.org/wiki/INI_file)). +Since the configuration is just a set of property names and values without any meaning or syntax, the system is very versatile and easily extendable. Adding new properties to the system only implies modifications in the classes that will make use of these properties. In addition, the configuration files are not checked against any strict syntax so it is always in a correct status (as long as it contains pairs of property names and values in the [INI format](https://en.wikipedia.org/wiki/INI_file)). ### GNSS block factory -Hence, the application defines a simple accessor class to fetch the configuration pairs of values and passes them to a factory class called [GNSSBlockFactory](./src/core/receiver/gnss_block_factory.h). This factory decides, according to the configuration, which class needs to be instantiated and which parameters should be passed to the constructor. Hence, the factory encapsulates the complexity of blocks' instantiation. With that approach, adding a new block that requires new parameters will be as simple as adding the block class and modifying the factory to be able to instantiate it. This loose coupling between the blocks' implementations and the syntax of the configuration enables extending the application capacities in a high degree. It also allows to produce fully customized receivers, for instance a testbed for acquisition algorithms, and to place observers at any point of the receiver chain. +Hence, the application defines a simple accessor class to fetch the configuration pairs of values and passes them to a factory class called [GNSSBlockFactory](./src/core/receiver/gnss_block_factory.h). This factory decides, according to the configuration, which class needs to be instantiated and which parameters should be passed to the constructor. Hence, the factory encapsulates the complexity of blocks' instantiation. With that approach, adding a new block that requires new parameters will be as simple as adding the block class and modifying the factory to be able to instantiate it. This loose coupling between the blocks' implementations and the syntax of the configuration enables extending the application capacities in a high degree. It also allows producing fully customized receivers, for instance a testbed for acquisition algorithms, and to place observers at any point of the receiver chain. -More information can be found at the [Control Plane page](http://gnss-sdr.org/docs/control-plane/). +More information can be found at the [Control Plane page](https://gnss-sdr.org/docs/control-plane/). Signal Processing plane @@ -665,9 +787,9 @@ GNU Radio's class ```gr::basic_block``` is the abstract base class for all signa A signal processing flow is constructed by creating a tree of hierarchical blocks, which at any level may also contain terminal nodes that actually implement signal processing functions. -Class ```gr::top_block``` is the top-level hierarchical block representing a flowgraph. It defines GNU Radio runtime functions used during the execution of the program: run(), start(), stop(), wait(), etc. A a subclass called [GNSSBlockInterface](./src/core/interfaces/gnss_block_interface.h) is the common interface for all the GNSS-SDR modules. It defines pure virtual methods, that are required to be implemented by a derived class. +Class ```gr::top_block``` is the top-level hierarchical block representing a flowgraph. It defines GNU Radio runtime functions used during the execution of the program: run(), start(), stop(), wait(), etc. A subclass called [GNSSBlockInterface](./src/core/interfaces/gnss_block_interface.h) is the common interface for all the GNSS-SDR modules. It defines pure virtual methods, that are required to be implemented by a derived class. -Subclassing GNSSBlockInterface, we defined interfaces for the GNSS receiver blocks depicted in the figure above. This hierarchy provides the definition of different algorithms and different implementations, which will be instantiated according to the configuration. This strategy allows multiple implementations sharing a common interface, achieving the objective of decoupling interfaces from implementations: it defines a family of algorithms, encapsulates each one, and makes them interchangeable. Hence, we let the algorithm vary independently from the program that uses it. +Subclassing GNSSBlockInterface, we defined interfaces for the GNSS receiver blocks depicted in the figure above. This hierarchy provides the definition of different algorithms and different implementations, which will be instantiated according to the configuration. This strategy allows multiple implementations sharing a common interface, achieving the objective of decoupling interfaces from implementations: it defines a family of algorithms, encapsulates each one, and makes them interchangeable. Hence, we let the algorithm vary independently of the program that uses it. Internally, GNSS-SDR makes use of the complex data types defined by [VOLK](http://libvolk.org/ "Vector-Optimized Library of Kernels home"). They are fundamental for handling sample streams in which samples are complex numbers with real and imaginary components of 8, 16 or 32 bits, common formats delivered by GNSS (and generic SDR) radio frequency front-ends. The following list shows the data type names that GNSS-SDR exposes through the configuration file: @@ -681,13 +803,13 @@ Internally, GNSS-SDR makes use of the complex data types defined by [VOLK](http: - **`gr_complex`**: Complex samples, with real and imaginary parts of type `float`. C++ type name: `std::complex`. -More information about the available processing blocks and their configuration parameters can be found at the [Signal Processing Blocks documentation page](http://gnss-sdr.org/docs/sp-blocks/). +More information about the available processing blocks and their configuration parameters can be found at the [Signal Processing Blocks documentation page](https://gnss-sdr.org/docs/sp-blocks/). ### Signal Source The input of a software receiver are the raw bits that come out from the front-end's analog-to-digital converter (ADC). Those bits can be read from a file stored in the hard disk or directly in real-time from a hardware device through USB or Ethernet buses. -The Signal Source module is in charge of implementing the hardware driver, that is, the portion of the code that communicates with the RF front-end and receives the samples coming from the ADC. This communication is usually performed through USB or Ethernet buses. Since real-time processing requires a highly optimized implementation of the whole receiver, this module also allows to read samples from a file stored in a hard disk, and thus processing without time constraints. Relevant parameters of those samples are the intermediate frequency (or baseband I&Q components), the sampling rate and number of bits per sample, that must be specified by the user in the configuration file. +The Signal Source module is in charge of implementing the hardware driver, that is, the portion of the code that communicates with the RF front-end and receives the samples coming from the ADC. This communication is usually performed through USB or Ethernet buses. Since real-time processing requires a highly optimized implementation of the whole receiver, this module also allows reading samples from a file stored in a hard disk, and thus processing without time constraints. Relevant parameters of those samples are the intermediate frequency (or baseband I&Q components), the sampling rate and number of bits per sample, that must be specified by the user in the configuration file. This module also performs bit-depth adaptation, since most of the existing RF front-ends provide samples quantized with 2 or 3 bits, while operations inside the processor are performed on 32- or 64-bit words, depending on its architecture. Although there are implementations of the most intensive computational processes (mainly correlation) that take advantage of specific data types and architectures for the sake of efficiency, the approach is processor-specific and hardly portable. We suggest to keep signal samples in standard data types and letting the compiler select the best library version (implemented using SIMD or any other processor-specific technology) of the required routines for a given processor. @@ -700,14 +822,13 @@ The user can configure the receiver for reading from a file, setting in the conf SignalSource.implementation=File_Signal_Source SignalSource.filename=/home/user/gnss-sdr/data/my_capture.dat SignalSource.item_type=gr_complex -SignalSource.sampling_frequency=4000000 ; Sampling frequency in [Hz] -SignalSource.freq=1575420000 ; RF front-end center frequency in [Hz] +SignalSource.sampling_frequency=4000000 ; Sampling frequency in samples per second (Sps) ~~~~~~ -Type ```gr_complex``` refers to a GNU Radio typedef equivalent to ```std::complex```. In order to save some storage space, you might wanted to store your signal in a more efficient format such as an I/Q interleaved ```short`` integer sample stream. In that case, change the corresponding line to: +Type ```gr_complex``` refers to a GNU Radio typedef equivalent to ```std::complex```. In order to save some storage space, you might want to store your signal in a more efficient format such as an I/Q interleaved ```short`` integer sample stream. In that case, change the corresponding line to: ~~~~~~ -SignalSource.item_type=short +SignalSource.item_type=ishort ~~~~~~ In this latter case, you will need to convert the interleaved I/Q samples to a complex stream via Data Type Adapter block (see below). @@ -728,7 +849,7 @@ Sometimes, samples are stored in files with a format which is not in the list of Within a byte the samples may be packed in big endian ```big_endian_bytes=true``` (if the most significant byte value is stored at the memory location with the lowest address, the next byte value in significance is stored at the following memory location, and so on) or little endian ```big_endian_bytes=false``` (if the least significant byte value is at the lowest address, and the other bytes follow in increasing order of significance). If the order is big endian then the most significant two bits will form the first sample output, otherwise the least significant two bits will be used. -Additionally the samples may be either real ```sample_type=real```, or complex. If the sample type is complex, then the samples are either stored in the order: real, imag, real, imag, ... ```sample_type=iq``` or in the order: imag, real, imag, real, ... ```sample_type=qi```. +Additionally, the samples may be either real ```sample_type=real```, or complex. If the sample type is complex, then the samples are either stored in the order: real, imag, real, imag, ... ```sample_type=iq``` or in the order: imag, real, imag, real, ... ```sample_type=qi```. Finally, if the data is stored as shorts ```item_type=short```, then it may be stored in either big endian ```big_endian_items=true``` or little endian ```big_endian_items=false```. If the shorts are big endian then the 2nd byte in each short is output first. @@ -757,7 +878,7 @@ SignalSource.big_endian_bytes=false ***Example: UHD Signal Source*** -The user may prefer to use a [UHD](http://code.ettus.com/redmine/ettus/projects/uhd/wiki)-compatible RF front-end and try real-time processing. For instance, for a USRP1 + DBSRX daughterboard, use: +The user may prefer to use a [UHD](https://files.ettus.com/manual/)-compatible RF front-end and try real-time processing. For instance, for a USRP1 + DBSRX daughterboard, use: ~~~~~~ ;######### SIGNAL_SOURCE CONFIG ############ @@ -770,7 +891,7 @@ SignalSource.subdevice=B:0 ; UHD subdevice specification (for USRP1 use A:0 or B ~~~~~~ -***Example: Configuring the USRP X300 with two front-ends for receiving signals in L1 and L2 bands*** +***Example: Configuring the USRP X300/X310 with two front-ends for receiving signals in L1 and L2 bands*** ~~~~~~ ;######### SIGNAL_SOURCE CONFIG ############ @@ -796,7 +917,7 @@ SignalSource.dump1=false ***Example: OsmoSDR-compatible Signal Source*** -[OsmoSDR](http://sdr.osmocom.org/trac) is a small form-factor, inexpensive software defined radio project. It provides a driver for several front-ends, such as [RTL-based dongles](http://sdr.osmocom.org/trac/wiki/rtl-sdr), HackRF, bladeRF, etc. Note that not all the OsmoSDR-compatible devices can work as radio frequency front-ends for proper GNSS signal reception, please check the specifications. For suitable RF front-ends, you can use: +[OsmoSDR](http://sdr.osmocom.org/trac) is a small form-factor, inexpensive software defined radio project. It provides a driver for several front-ends, such as [RTL-based dongles](https://www.rtl-sdr.com/tag/v3/), [HackRF](https://greatscottgadgets.com/hackrf/), [bladeRF](https://www.nuand.com/), [LimeSDR](https://myriadrf.org/projects/limesdr/), [etc](https://github.com/osmocom/gr-osmosdr/blob/master/README). Note that not all the OsmoSDR-compatible devices can work as radio frequency front-ends for proper GNSS signal reception, please check the specifications. For suitable RF front-ends, you can use: ~~~~~~ ;######### SIGNAL_SOURCE CONFIG ############ @@ -807,9 +928,23 @@ SignalSource.freq=1575420000 SignalSource.rf_gain=40 SignalSource.if_gain=30 SignalSource.enable_throttle_control=false -SignalSource.osmosdr_args=rtl_tcp,offset_tune=1 +SignalSource.osmosdr_args=hackrf,bias=1 ~~~~~~ +For [RTL-SDR Blog V3](https://www.rtl-sdr.com/tag/v3/) dongles, the arguments are: + +~~~~~~ +SignalSource.osmosdr_args=rtl,bias=1 +~~~~~~ + + +and for [LimeSDR](https://myriadrf.org/projects/limesdr/): + +~~~~~~ +SignalSource.osmosdr_args=driver=lime,soapy=0 +~~~~~~ + + In case of using a Zarlink's RTL2832 based DVB-T receiver, you can even use the ```rtl_tcp``` I/Q server in order to use the USB dongle remotely. In a terminal, type: ~~~~~~ @@ -862,7 +997,7 @@ SignalSource.dump1=false ~~~~~~ -More documentation and examples are available at the [Signal Source Blocks page](http://gnss-sdr.org/docs/sp-blocks/signal-source/). +More documentation and examples are available at the [Signal Source Blocks page](https://gnss-sdr.org/docs/sp-blocks/signal-source/). ### Signal Conditioner @@ -876,14 +1011,14 @@ If your signal source is providing baseband signal samples of type ```gr_complex SignalConditioner.implementation=Pass_Through ~~~~~~ -If you need to adapt some aspect of you signal, you can enable the Signal Conditioner and configure three internal blocks: a data type adpater, an input signal and a resampler. +If you need to adapt some aspect of your signal, you can enable the Signal Conditioner and configure three internal blocks: a data type adapter, an input signal and a resampler. ~~~~~~ ;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ~~~~~~ -More documentation at the [Signal Conditioner Blocks page](http://gnss-sdr.org/docs/sp-blocks/signal-conditioner/). +More documentation at the [Signal Conditioner Blocks page](https://gnss-sdr.org/docs/sp-blocks/signal-conditioner/). #### Data type adapter @@ -895,11 +1030,11 @@ This block changes the type of input data samples. If your signal source deliver DataTypeAdapter.implementation=Ishort_To_Complex ~~~~~~ -More documentation at the [Data Type Adapter Blocks page](http://gnss-sdr.org/docs/sp-blocks/data-type-adapter/). +More documentation at the [Data Type Adapter Blocks page](https://gnss-sdr.org/docs/sp-blocks/data-type-adapter/). #### Input filter -This block filters the input data. It can be combined with frequency translation for IF signals. The computation of the filter taps is based on parameters of GNU Radio's function [pm_remez](http://gnuradio.org/doc/doxygen/pm__remez_8h.html), that calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. +This block filters the input data. It can be combined with frequency translation for IF signals. The computation of the filter taps is based on parameters of GNU Radio's function [pm_remez](https://gnuradio.org/doc/doxygen/pm__remez_8h.html), that calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired response on those bands, and the weight given to the error in those bands. The block can be configured like this: @@ -950,11 +1085,11 @@ InputFilter.IF=0 InputFilter.decimation_factor=1 ~~~~~~ -More documentation at the [Input Filter Blocks page](http://gnss-sdr.org/docs/sp-blocks/input-filter/). +More documentation at the [Input Filter Blocks page](https://gnss-sdr.org/docs/sp-blocks/input-filter/). #### Resampler -This block resamples the input data stream. The ```Direct_Resampler``` block implements a nearest neigbourhood interpolation: +This block resamples the input data stream. The ```Direct_Resampler``` block implements a nearest neighbourhood interpolation: ~~~~~~ ;######### RESAMPLER CONFIG ############ @@ -968,20 +1103,24 @@ Resampler.sample_freq_in=8000000 ; sample frequency of the input signal Resampler.sample_freq_out=4000000 ; desired sample frequency of the output signal ~~~~~~ -More documentation at the [Resampler Blocks page](http://gnss-sdr.org/docs/sp-blocks/resampler/). +More documentation at the [Resampler Blocks page](https://gnss-sdr.org/docs/sp-blocks/resampler/). ### Channel -A channel encapsulates all signal processing devoted to a single satellite. Thus, it is a large composite object which encapsulates the acquisition, tracking and navigation data decoding modules. As a composite object, it can be treated as a single entity, meaning that it can be easily replicated. Since the number of channels is selectable by the user in the configuration file, this approach helps improving the scalability and maintainability of the receiver. +A channel encapsulates all signal processing devoted to a single satellite. Thus, it is a large composite object which encapsulates the acquisition, tracking and navigation data decoding modules. As a composite object, it can be treated as a single entity, meaning that it can be easily replicated. Since the number of channels is selectable by the user in the configuration file, this approach helps to improve the scalability and maintainability of the receiver. Each channel must be assigned to a GNSS signal, according to the following identifiers: | **Signal** | **Identifier** | |:------------------|:---------------:| | GPS L1 C/A | 1C | +| Galileo E1b/c | 1B | +| Glonass L1 C/A | 1G | | GPS L2 L2C(M) | 2S | -| Galileo E1B | 1B | -| Galileo E5a (I+Q) | 5X | +| Glonass L2 C/A | 2G | +| GPS L5 | L5 | +| Galileo E5a | 5X | + Example: Eight GPS L1 C/A channels. @@ -1010,17 +1149,17 @@ Channel6.signal=1B ; Channel7.signal=1B ; ~~~~~~ -This module is also in charge of managing the interplay between acquisition and tracking. Acquisition can be initialized in several ways, depending on the prior information available (called cold start when the receiver has no information about its position nor the satellites almanac; warm start when a rough location and the approximate time of day are available, and the receiver has a recently recorded almanac broadcast; or hot start when the receiver was tracking a satellite and the signal line of sight broke for a short period of time, but the ephemeris and almanac data is still valid, or this information is provided by other means), and an acquisition process can finish deciding that the satellite is not present, that longer integration is needed in order to confirm the presence of the satellite, or declaring the satellite present. In the latter case, acquisition process should stop and trigger the tracking module with coarse estimations of the synchronization parameters. The mathematical abstraction used to design this logic is known as finite state machine (FSM), that is a behavior model composed of a finite number of states, transitions between those states, and actions. For the implementation, we use the [Boost.Statechart library](http://www.boost.org/libs/statechart/doc/tutorial.html), which provides desirable features such as support for asynchronous state machines, multi-threading, type-safety, error handling and compile-time validation. +This module is also in charge of managing the interplay between acquisition and tracking. Acquisition can be initialized in several ways, depending on the prior information available (called cold start when the receiver has no information about its position nor the satellites' almanac; warm start when a rough location and the approximate time of day are available, and the receiver has a recently recorded almanac broadcast; or hot start when the receiver was tracking a satellite and the signal line of sight broke for a short period of time, but the ephemeris and almanac data is still valid, or this information is provided by other means), and an acquisition process can finish deciding that the satellite is not present, that longer integration is needed in order to confirm the presence of the satellite, or declaring the satellite present. In the latter case, acquisition process should stop and trigger the tracking module with coarse estimations of the synchronization parameters. The mathematical abstraction used to design this logic is known as finite state machine (FSM), that is a behavior model composed of a finite number of states, transitions between those states, and actions. The abstract class [ChannelInterface](./src/core/interfaces/channel_interface.h) represents an interface to a channel GNSS block. Check [Channel](./src/algorithms/channel/adapters/channel.h) for an actual implementation. -More documentation at the [Channels page](http://gnss-sdr.org/docs/sp-blocks/channels/). +More documentation at the [Channels page](https://gnss-sdr.org/docs/sp-blocks/channels/). #### Acquisition -The first task of a GNSS receiver is to detect the presence or absence of in-view satellites. This is done by the acquisition system process, which also provides a coarse estimation of two signal parameters: the frequency shift with respect to the nominal IF frequency, and a delay term which allows the receiver to create a local code aligned with the incoming code. [AcquisitionInterface](./src/core/interfaces/acquisition_interface.h) is the common interface for all the acquisition algorithms and their corresponding implementations. Algorithms' interface, that may vary depending on the use of information external to the receiver, such as in Assisted GNSS, is defined in classes referred to as *adapters*. These adapters wrap the GNU Radio blocks interface into a compatible interface expected by AcquisitionInterface. This allows the use of existing GNU Radio blocks derived from ```gr::block```, and ensures that newly developed implementations will also be reusable in other GNU Radio-based applications. Moreover, it adds still another layer of abstraction, since each given acquisition algorithm can have different implementations (for instance using different numerical libraries). In such a way, implementations can be continuously improved without having any impact neither on the algorithm interface nor the general acquisition interface. +The first task of a GNSS receiver is to detect the presence or absence of in-view satellites. This is done by the acquisition system process, which also provides a coarse estimation of two signal parameters: the frequency shift with respect to the nominal frequency, and a delay term which allows the receiver to create a local code aligned with the incoming code. [AcquisitionInterface](./src/core/interfaces/acquisition_interface.h) is the common interface for all the acquisition algorithms and their corresponding implementations. Algorithms' interface, that may vary depending on the use of information external to the receiver, such as in Assisted GNSS, is defined in classes referred to as *adapters*. These adapters wrap the GNU Radio blocks interface into a compatible interface expected by AcquisitionInterface. This allows the use of existing GNU Radio blocks derived from ```gr::block```, and ensures that newly developed implementations will also be reusable in other GNU Radio-based applications. Moreover, it adds still another layer of abstraction, since each given acquisition algorithm can have different implementations (for instance using different numerical libraries). In such a way, implementations can be continuously improved without having any impact neither on the algorithm interface nor the general acquisition interface. Check [GpsL1CaPcpsAcquisition](./src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.h) and [GalileoE1PcpsAmbiguousAcquisition](./src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.h) for examples of adapters from a Parallel Code Phase Search (PCPS) acquisition block, and [pcps_acquisition_cc](./src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h) for an example of a block implementation. The source code of all the available acquisition algorithms is located at: @@ -1033,14 +1172,13 @@ Check [GpsL1CaPcpsAcquisition](./src/algorithms/acquisition/adapters/gps_l1_ca_p |---------gnuradio_blocks <- Signal processing blocks implementation ~~~~~~ -The user can select a given implementation for the algorithm to be used in each receiver channel, as well as their parameters, in the configuration file. For a GPS l1 C/A receiver: +The user can select a given implementation for the algorithm to be used in each receiver channel, as well as their parameters, in the configuration file. For a GPS L1 C/A receiver: ~~~~~~ ;######### ACQUISITION GLOBAL CONFIG ############ Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition ; Acquisition algorithm selection for this channel Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 ; Signal intermediate frequency in [Hz] -Acquisition_1C.sampled_ms=1 ; Signal block duration for the acquisition signal detection [ms] +Acquisition_1C.coherent_integration_time_ms=1 ; Signal block duration for the acquisition signal detection [ms] Acquisition_1C.threshold=0.005 ; Acquisition threshold Acquisition_1C.pfa=0.0001 ; Acquisition false alarm probability. This option overrides the threshold option. ; Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] @@ -1056,8 +1194,7 @@ and, for Galileo E1B channels: ;######### GALILEO ACQUISITION CONFIG ############ Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition Acquisition_1B.item_type=gr_complex -Acquisition_1B.if=0 -Acquisition_1B.sampled_ms=4 +Acquisition_1B.coherent_integration_time_ms=4 Acquisition_1B.pfa=0.0000008 Acquisition_1B.doppler_max=15000 Acquisition_1B.doppler_step=125 @@ -1065,7 +1202,7 @@ Acquisition_1B.dump=false Acquisition_1B.dump_filename=./acq_dump.dat ~~~~~~ -More documentation at the [Acquisition Blocks page](http://gnss-sdr.org/docs/sp-blocks/acquisition/). +More documentation at the [Acquisition Blocks page](https://gnss-sdr.org/docs/sp-blocks/acquisition/). #### Tracking @@ -1115,12 +1252,12 @@ Tracking_1B.dump=false Tracking_1B.dump_filename=../data/veml_tracking_ch_ ~~~~~~ -More documentation at the [Tracking Blocks page](http://gnss-sdr.org/docs/sp-blocks/tracking/). +More documentation at the [Tracking Blocks page](https://gnss-sdr.org/docs/sp-blocks/tracking/). #### Decoding of the navigation message -Most of GNSS signal links are modulated by a navigation message containing the time the message was transmitted, orbital parameters of satellites (also known as ephemeris) and an almanac (information about the general system health, rough orbits of all satellites in the network as well as data related to error correction). Navigation data bits are structured in words, pages, subframes, frames and superframes. Sometimes, bits corresponding to a single parameter are spread over different words, and values extracted from different frames are required for proper decoding. Some words are for synchronization purposes, others for error control an others contain actual information. There are also error control mechanisms, from parity checks to forward error correction (FEC) encoding and interleaving, depending on the system. All this decoding complexity is managed by a finite state machine implemented with the [Boost.Statechart library](http://www.boost.org/libs/statechart/doc/tutorial.html). +Most of GNSS signal links are modulated by a navigation message containing the time the message was transmitted, orbital parameters of satellites (also known as ephemeris) and an almanac (information about the general system health, rough orbits of all satellites in the network as well as data related to error correction). Navigation data bits are structured in words, pages, subframes, frames and superframes. Sometimes, bits corresponding to a single parameter are spread over different words, and values extracted from different frames are required for proper decoding. Some words are for synchronization purposes, others for error control and others contain actual information. There are also error control mechanisms, from parity checks to forward error correction (FEC) encoding and interleaving, depending on the system. All this decoding complexity is managed by a finite state machine. The common interface is [TelemetryDecoderInterface](./src/core/interfaces/telemetry_decoder_interface.h). Check [GpsL1CaTelemetryDecoder](./src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.h) for an example of the GPS L1 NAV message decoding adapter, and [gps_l1_ca_telemetry_decoder_cc](./src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.h) for an actual implementation of a signal processing block. Configuration example: @@ -1137,15 +1274,13 @@ In case you are configuring a multi-system receiver, you will need to decimate t ;######### TELEMETRY DECODER GPS L1 CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=4; ;######### TELEMETRY DECODER GALILEO E1B CONFIG ############ TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=1; ~~~~~~ -More documentation at the [Telemetry Decoder Blocks page](http://gnss-sdr.org/docs/sp-blocks/telemetry-decoder/). +More documentation at the [Telemetry Decoder Blocks page](https://gnss-sdr.org/docs/sp-blocks/telemetry-decoder/). #### Observables @@ -1154,25 +1289,7 @@ GNSS systems provide different kinds of observations. The most commonly used are The common interface is [ObservablesInterface](./src/core/interfaces/observables_interface.h). -Configuration example for GPS L1 C/A signals: - -~~~~~~ -;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables -Observables.dump=false -Observables.dump_filename=./observables.dat -~~~~~~ - -For Galileo E1B receivers: - -~~~~~~ -;######### OBSERVABLES CONFIG ############ -Observables.implementation=Galileo_E1B_Observables -Observables.dump=false -Observables.dump_filename=./observables.dat -~~~~~~ - -For hybrid GPS L1 / Galileo E1B receivers: +Configuration example: ~~~~~~ ;######### OBSERVABLES CONFIG ############ @@ -1181,80 +1298,55 @@ Observables.dump=false Observables.dump_filename=./observables.dat ~~~~~~ -More documentation at the [Observables Blocks page](http://gnss-sdr.org/docs/sp-blocks/observables/). +More documentation at the [Observables Blocks page](https://gnss-sdr.org/docs/sp-blocks/observables/). #### Computation of Position, Velocity and Time -Although data processing for obtaining high-accuracy PVT solutions is out of the scope of GNSS-SDR, we provide a module that can compute simple least square solutions (stored in GIS-friendly formats such as [GeoJSON](http://geojson.org/geojson-spec.html) and [KML](http://www.opengeospatial.org/standards/kml), or transmitted via serial port as [NMEA 0183](https://en.wikipedia.org/wiki/NMEA_0183) messages), and leaves room for more sophisticated positioning methods by storing observables and navigation data in [RINEX](https://en.wikipedia.org/wiki/RINEX) files (v2.11 or v3.02), and generating [RTCM](http://www.rtcm.org "Radio Technical Commission for Maritime Services") 3.2 messages that can be disseminated through the Internet in real time. +Although data processing for obtaining high-accuracy PVT solutions is out of the scope of GNSS-SDR, we provide a module that can compute position fixes (stored in GIS-friendly formats such as [GeoJSON](https://tools.ietf.org/html/rfc7946), [GPX](http://www.topografix.com/gpx.asp) and [KML](http://www.opengeospatial.org/standards/kml), or transmitted via serial port as [NMEA 0183](https://en.wikipedia.org/wiki/NMEA_0183) messages), and leaves room for more sophisticated positioning methods by storing observables and navigation data in [RINEX](https://en.wikipedia.org/wiki/RINEX) files (v2.11 or v3.02), and generating [RTCM](http://www.rtcm.org "Radio Technical Commission for Maritime Services") 3.2 messages that can be disseminated through the Internet in real time. The common interface is [PvtInterface](./src/core/interfaces/pvt_interface.h). -Configuration example for GPS L1 C/A signals: +Configuration example: ~~~~~~ ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=10 ; Number of PVT observations in the moving average algorithm -PVT.flag_averaging=true ; Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.output_rate_ms=100 ; Period in [ms] between two PVT outputs -PVT.display_rate_ms=500 ; Position console print (std::out) interval [ms]. -PVT.dump=false ; Enables the PVT internal binary data file logging [true] or [false] -PVT.dump_filename=./PVT ; Log path and filename without extension of GeoJSON and KML files +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen +PVT.rinex_version=2 ; options: 2 or 3 +PVT.output_rate_ms=100 ; Period in [ms] between two PVT outputs +PVT.display_rate_ms=500 ; Position console print (std::out) interval [ms]. PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea ; NMEA log path and filename -PVT.flag_nmea_tty_port=true ; Enables the NMEA log to a serial TTY port +PVT.flag_nmea_tty_port=false ; Enables the NMEA log to a serial TTY port PVT.nmea_dump_devname=/dev/pts/4 ; serial device descriptor for NMEA logging -PVT.flag_rtcm_server=false ; Enables or disables a TCP/IP server dispatching RTCM messages -PVT.flag_rtcm_tty_port=true ; Enables the RTCM log to a serial TTY port +PVT.flag_rtcm_server=true ; Enables or disables a TCP/IP server dispatching RTCM messages +PVT.flag_rtcm_tty_port=false ; Enables the RTCM log to a serial TTY port PVT.rtcm_dump_devname=/dev/pts/1 ; serial device descriptor for RTCM logging +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 ~~~~~~ -For Galileo E1B receivers: - -~~~~~~ -;######### PVT CONFIG ############ -PVT.implementation=GALILEO_E1_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false -PVT.output_rate_ms=100; -PVT.display_rate_ms=500; -PVT.dump=false -PVT.dump_filename=./PVT -PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea ; NMEA log path and filename -PVT.flag_nmea_tty_port=true ; Enables the NMEA log to a serial TTY port -PVT.nmea_dump_devname=/dev/pts/4 ; serial device descriptor for NMEA logging -PVT.flag_rtcm_server=false ; Enables or disables a TCP/IP server dispatching RTCM messages -PVT.flag_rtcm_tty_port=true ; Enables the RTCM log to a serial TTY port -PVT.rtcm_dump_devname=/dev/pts/1 ; serial device descriptor for RTCM logging -~~~~~~ - - -For hybrid GPS L1 / Galileo E1B receivers: - -~~~~~~ -;######### PVT CONFIG ############ -PVT.implementation=Hybrid_PVT -PVT.averaging_depth=10 -PVT.flag_averaging=false -PVT.output_rate_ms=100; -PVT.display_rate_ms=500; -PVT.dump=false -PVT.dump_filename=./PVT -~~~~~~ **Notes on the output formats:** - * **GeoJSON** is a geospatial data interchange format based on JavaScript Object Notation (JSON) supported by numerous mapping and GIS software packages, including [OpenLayers](http://openlayers.org), [Leaflet](http://leafletjs.com), [MapServer](http://www.mapserver.org), [GeoServer](http://geoserver.org), [GeoDjango](https://www.djangoproject.com), [GDAL](http://www.gdal.org), and [CartoDB](https://cartodb.com). It is also possible to use GeoJSON with [PostGIS](http://postgis.net) and [Mapnik](http://mapnik.org), both of which handle the format via the GDAL OGR conversion library. The [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/) v3 directly supports the [integration of GeoJSON data layers](https://developers.google.com/maps/documentation/javascript/examples/layer-data-simple), and [GitHub also supports GeoJSON rendering](https://github.com/blog/1528-there-s-a-map-for-that). + * **GeoJSON** is a geospatial data interchange format based on JavaScript Object Notation (JSON) supported by numerous mapping and GIS software packages, including [OpenLayers](https://openlayers.org), [Leaflet](https://leafletjs.com), [MapServer](http://www.mapserver.org), [GeoServer](http://geoserver.org), [GeoDjango](https://www.djangoproject.com), [GDAL](http://www.gdal.org), and [CartoDB](https://cartodb.com). It is also possible to use GeoJSON with [PostGIS](https://postgis.net/) and [Mapnik](http://mapnik.org), both of which handle the format via the GDAL OGR conversion library. The [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/) v3 directly supports the [integration of GeoJSON data layers](https://developers.google.com/maps/documentation/javascript/examples/layer-data-simple), and [GitHub also supports GeoJSON rendering](https://github.com/blog/1528-there-s-a-map-for-that). - * **KML** (Keyhole Markup Language) is an XML grammar used to encode and transport representations of geographic data for display in an earth browser. KML is an open standard officially named the OpenGIS KML Encoding Standard (OGC KML), and it is maintained by the Open Geospatial Consortium, Inc. (OGC). KML files can be displayed in geobrowsers such as [Google Earth](https://www.google.com/earth/), [Marble](https://marble.kde.org), [osgEarth](http://osgearth.org), or used with the [NASA World Wind SDK for Java](http://worldwind.arc.nasa.gov/java/). + * **KML** (Keyhole Markup Language) is an XML grammar used to encode and transport representations of geographic data for display in an earth browser. KML is an open standard officially named the OpenGIS KML Encoding Standard (OGC KML), and it is maintained by the Open Geospatial Consortium, Inc. (OGC). KML files can be displayed in geobrowsers such as [Google Earth](https://www.google.com/earth/), [Marble](https://marble.kde.org), [osgEarth](http://osgearth.org), or used with the [NASA World Wind SDK for Java](https://worldwind.arc.nasa.gov/java/). - * **NMEA 0183** is a combined electrical and data specification for communication between marine electronics such as echo sounder, sonars, anemometer, gyrocompass, autopilot, GPS receivers and many other types of instruments. It has been defined by, and is controlled by, the U.S. [National Marine Electronics Association](http://www.nmea.org/). The NMEA 0183 standard uses a simple ASCII, serial communications protocol that defines how data are transmitted in a *sentence* from one *talker* to multiple *listeners* at a time. Through the use of intermediate expanders, a talker can have a unidirectional conversation with a nearly unlimited number of listeners, and using multiplexers, multiple sensors can talk to a single computer port. At the application layer, the standard also defines the contents of each sentence (message) type, so that all listeners can parse messages accurately. Those messages can be sent through the serial port (that could be for instance a Bluetooth link) and be used/displayed by a number of software applications such as [gpsd](http://www.catb.org/gpsd/ "The UNIX GPS daemon"), [JOSM](https://josm.openstreetmap.de/ "The Java OpenStreetMap Editor"), [OpenCPN](http://opencpn.org/ocpn/ "Open Chart Plotter Navigator"), and many others (and maybe running on other devices). + * **GPX** (the GPS Exchange Format) is a light-weight XML data format for the interchange of GPS data (waypoints, routes, and tracks) between applications and Web services on the Internet. The format is open and can be used without the need to pay license fees, and it is supported by a [large list of software tools](http://www.topografix.com/gpx_resources.asp). - * **RINEX** (Receiver Independent Exchange Format) is an interchange format for raw satellite navigation system data, covering observables and the information contained in the navigation message broadcast by GNSS satellites. This allows the user to post-process the received data to produce a more accurate result (usually with other data unknown to the original receiver, such as better models of the atmospheric conditions at time of measurement). RINEX files can be used by software packages such as [GPSTk](http://www.gpstk.org), [RTKLIB](http://www.rtklib.com/) and [gLAB](http://gage14.upc.es/gLAB/). GNSS-SDR by default generates RINEX version [3.02](https://igscb.jpl.nasa.gov/igscb/data/format/rinex302.pdf). If [2.11](https://igscb.jpl.nasa.gov/igscb/data/format/rinex211.txt) is needed, it can be requested through a commandline flag when invoking the software receiver: + * **NMEA 0183** is a combined electrical and data specification for communication between marine electronics such as echo sounder, sonars, anemometer, gyrocompass, autopilot, GPS receivers and many other types of instruments. It has been defined by, and is controlled by, the U.S. [National Marine Electronics Association](http://www.nmea.org/). The NMEA 0183 standard uses a simple ASCII, serial communications protocol that defines how data are transmitted in a *sentence* from one *talker* to multiple *listeners* at a time. Through the use of intermediate expanders, a talker can have a unidirectional conversation with a nearly unlimited number of listeners, and using multiplexers, multiple sensors can talk to a single computer port. At the application layer, the standard also defines the contents of each sentence (message) type, so that all listeners can parse messages accurately. Those messages can be sent through the serial port (that could be for instance a Bluetooth link) and be used/displayed by a number of software applications such as [gpsd](http://www.catb.org/gpsd/ "The UNIX GPS daemon"), [JOSM](https://josm.openstreetmap.de/ "The Java OpenStreetMap Editor"), [OpenCPN](https://opencpn.org/ "Open Chart Plotter Navigator"), and many others (and maybe running on other devices). + + * **RINEX** (Receiver Independent Exchange Format) is an interchange format for raw satellite navigation system data, covering observables and the information contained in the navigation message broadcast by GNSS satellites. This allows the user to post-process the received data to produce a more accurate result (usually with other data unknown to the original receiver, such as better models of the atmospheric conditions at time of measurement). RINEX files can be used by software packages such as [GPSTk](http://www.gpstk.org), [RTKLIB](http://www.rtklib.com/) and [gLAB](http://gage14.upc.es/gLAB/). GNSS-SDR by default generates RINEX version [3.02](https://igscb.jpl.nasa.gov/igscb/data/format/rinex302.pdf). If [2.11](https://igscb.jpl.nasa.gov/igscb/data/format/rinex211.txt) is needed, it can be requested through the `rinex_version` parameter in the configuration file: ~~~~~~ -$ gnss-sdr --RINEX_version=2 +PVT.rinex_version=2 ~~~~~~ -* **RTCM SC-104** provides standards that define the data structure for differential GNSS correction information for a variety of differential correction applications. Developed by the Radio Technical Commission for Maritime Services ([RTCM](http://www.rtcm.org/overview.php#Standards "Radio Technical Commission for Maritime Services")), they have become an industry standard for communication of correction information. GNSS-SDR implements RTCM version 3.2, defined in the document *RTCM 10403.2, Differential GNSS (Global Navigation Satellite Systems) Services - Version 3* (February 1, 2013), which can be [purchased online](https://ssl29.pair.com/dmarkle/puborder.php?show=3 "RTCM Online Publication Order Form"). By default, the generated RTCM binary messages are dumped into a text file in hexadecimal format. However, GNSS-SDR is equipped with a TCP/IP server, acting as an NTRIP source that can feed an NTRIP server. NTRIP (Networked Transport of RTCM via Internet Protocol) is an open standard protocol that can be freely download from [BKG](http://igs.bkg.bund.de/root_ftp/NTRIP/documentation/NtripDocumentation.pdf "Networked Transport of RTCM via Internet Protocol (Ntrip) Version 1.0"), and it is designed for disseminating differential correction data (*e.g.* in the RTCM-104 format) or other kinds of GNSS streaming data to stationary or mobile users over the Internet. The TCP/IP server can be enabled by setting ```PVT.flag_rtcm_server=true``` in the configuration file, and will be active during the execution of the software receiver. By default, the server will operate on port 2101 (which is the recommended port for RTCM services according to the Internet Assigned Numbers Authority, [IANA](http://www.iana.org/assignments/service-names-port-numbers "Service Name and Transport Protocol Port Number Registry")), and will identify the Reference Station with ID=1234. This behaviour can be changed in the configuration file: +* **RTCM SC-104** provides standards that define the data structure for differential GNSS correction information for a variety of differential correction applications. Developed by the Radio Technical Commission for Maritime Services ([RTCM](http://www.rtcm.org/differential-global-navigation-satellite--dgnss--standards.html "Radio Technical Commission for Maritime Services")), they have become an industry standard for communication of correction information. GNSS-SDR implements RTCM version 3.2, defined in the document *RTCM 10403.2, Differential GNSS (Global Navigation Satellite Systems) Services - Version 3* (February 1, 2013), which can be [purchased online](https://ssl29.pair.com/dmarkle/puborder.php?show=3 "RTCM Online Publication Order Form"). By default, the generated RTCM binary messages are dumped into a text file in hexadecimal format. However, GNSS-SDR is equipped with a TCP/IP server, acting as an NTRIP source that can feed an NTRIP server. NTRIP (Networked Transport of RTCM via Internet Protocol) is an open standard protocol that can be freely downloaded from [BKG](https://igs.bkg.bund.de/root_ftp/NTRIP/documentation/NtripDocumentation.pdf "Networked Transport of RTCM via Internet Protocol (Ntrip) Version 1.0"), and it is designed for disseminating differential correction data (*e.g.* in the RTCM-104 format) or other kinds of GNSS streaming data to stationary or mobile users over the Internet. The TCP/IP server can be enabled by setting ```PVT.flag_rtcm_server=true``` in the configuration file, and will be active during the execution of the software receiver. By default, the server will operate on port 2101 (which is the recommended port for RTCM services according to the Internet Assigned Numbers Authority, [IANA](https://www.iana.org/assignments/service-names-port-numbers/ "Service Name and Transport Protocol Port Number Registry")), and will identify the Reference Station with ID=1234. This behaviour can be changed in the configuration file: ~~~~~~ PVT.flag_rtcm_server=true PVT.rtcm_tcp_port=2102 @@ -1265,13 +1357,13 @@ PVT.rtcm_station_id=1111 In order to get well-formatted GeoJSON, KML and RINEX files, always terminate ```gnss-sdr``` execution by pressing key ```q``` and then key ```ENTER```. Those files will be automatically deleted if no position fix have been obtained during the execution of the software receiver. -More documentation at the [PVT Blocks page](http://gnss-sdr.org/docs/sp-blocks/pvt/). +More documentation at the [PVT Blocks page](https://gnss-sdr.org/docs/sp-blocks/pvt/). About the software license ========================== -GNSS-SDR is released under the [General Public License (GPL) v3](http://www.gnu.org/licenses/gpl.html), thus securing practical usability, inspection, and continuous improvement by the research community, allowing the discussion based on tangible code and the analysis of results obtained with real signals. The GPL implies that: +GNSS-SDR is released under the [General Public License (GPL) v3](https://www.gnu.org/licenses/gpl.html), thus securing practical usability, inspection, and continuous improvement by the research community, allowing the discussion based on tangible code and the analysis of results obtained with real signals. The GPL implies that: 1. Copies may be distributed free of charge or for money, but the source code has to be shipped or provided free of charge (or at cost price) on demand. The receiver of the source code has the same rights meaning he can share copies free of charge or resell. 2. The licensed material may be analyzed or modified. @@ -1288,7 +1380,7 @@ Publications and Credits If you use GNSS-SDR to produce a research paper or Thesis, we would appreciate if you reference the following article to credit the GNSS-SDR project: - * C. Fernández-Prades, J. Arribas, P. Closas, C. Avilés, and L. Esteve, [GNSS-SDR: an open source tool for researchers and developers](http://www.cttc.es/publication/gnss-sdr-an-open-source-tool-for-researchers-and-developers/), in Proc. of the ION GNSS 2011 Conference, Portland, Oregon, Sept. 19-23, 2011. + * C. Fernández-Prades, J. Arribas, P. Closas, C. Avilés, and L. Esteve, [GNSS-SDR: an open source tool for researchers and developers](http://www.cttc.es/publication/gnss-sdr-an-open-source-tool-for-researchers-and-developers/), in Proceedings of the 24th International Technical Meeting of The Satellite Division of the Institute of Navigation (ION GNSS), Portland, Oregon, Sept. 19-23, 2011, pp. 780-794. For LaTeX users, this is the BibTeX entry for your convenience: @@ -1296,27 +1388,28 @@ For LaTeX users, this is the BibTeX entry for your convenience: @INPROCEEDINGS{GNSS-SDR11, AUTHOR = {C.~{Fern\'{a}ndez--Prades} and J.~Arribas and P.~Closas and C.~Avil\'{e}s and L.~Esteve}, TITLE = {{GNSS-SDR}: An Open Source Tool For Researchers and Developers}, - BOOKTITLE = {Proc. of the ION GNSS 2011 Conference}, + BOOKTITLE = {Proc. 24th Intl. Tech. Meeting Sat. Div. Inst. Navig.}, YEAR = {2011}, - address = {Portland, Oregon}, - month = {Sept.} } + PAGES = {780--794}, + ADDRESS = {Portland, Oregon}, + MONTH = {Sept.} } ~~~~~~ -There is a list of papers related to GNSS-SDR in our [publications page](http://gnss-sdr.org/publications/ "Publications"). +There is a list of papers related to GNSS-SDR in our [publications page](https://gnss-sdr.org/publications/ "Publications"). Ok, now what? ============= -In order to start using GNSS-SDR, you may want to populate ```gnss-sdr/data``` folder (or anywhere else on your system) with raw data files. By "raw data" we mean the output of a Radio Frequency front-end's Analog-to-Digital converter. GNSS-SDR needs signal samples already in baseband or in passband, at a suitable intemediate frequency (on the order of MHz). Prepare your configuration file, and then you are ready for running ```gnss-sdr --config_file=your_configuration.conf```, and seeing how the file is processed. +In order to start using GNSS-SDR, you may want to populate ```gnss-sdr/data``` folder (or anywhere else on your system) with raw data files. By "raw data" we mean the output of a Radio Frequency front-end's Analog-to-Digital converter. GNSS-SDR needs signal samples already in baseband or in passband, at a suitable intermediate frequency (on the order of MHz). Prepare your configuration file, and then you are ready for running ```gnss-sdr --config_file=your_configuration.conf```, and seeing how the file is processed. -Another interesting option is working in real-time with a RF front-end. We provide drivers for UHD-compatible hardware such as the [USRP family](http://www.ettus.com/product), for OsmoSDR and other front-ends (HackRF, bladeRF), for the GN3S v2 USB dongle and for some DVB-T USB dongles. Start with a low number of channels and then increase it in order to test how many channels your processor can handle in real-time. +Another interesting option is working in real-time with an RF front-end. We provide drivers for UHD-compatible hardware such as the [USRP family](https://www.ettus.com/product), for OsmoSDR and other front-ends (HackRF, bladeRF, LimeSDR), for the GN3S v2 USB dongle and for some DVB-T USB dongles. Start with a low number of channels and then increase it in order to test how many channels your processor can handle in real-time. -You can find more information at the [GNSS-SDR Documentation page](http://gnss-sdr.org/docs/) or directly asking to the [GNSS-SDR Developers mailing list](http://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers). +You can find more information at the [GNSS-SDR Documentation page](https://gnss-sdr.org/docs/) or directly asking to the [GNSS-SDR Developers mailing list](https://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers). -You are also very welcome to contribute to the project, there are many ways to [participate in GNSS-SDR](http://gnss-sdr.org/contribute/). If you need some special feature not yet implemented, the Developer Team would love to be hired for developing it. Please do not hesitate to [contact them](http://gnss-sdr.org/team/). +You are also very welcome to contribute to the project, there are many ways to [participate in GNSS-SDR](https://gnss-sdr.org/contribute/). If you need some special feature not yet implemented, the Developer Team would love to be hired for developing it. Please do not hesitate to [contact them](https://gnss-sdr.org/team/). **Enjoy GNSS-SDR!** diff --git a/cmake/Modules/CMakeParseArgumentsCopy.cmake b/cmake/Modules/CMakeParseArgumentsCopy.cmake deleted file mode 100644 index 7ce4c49ae..000000000 --- a/cmake/Modules/CMakeParseArgumentsCopy.cmake +++ /dev/null @@ -1,138 +0,0 @@ -# CMAKE_PARSE_ARGUMENTS( args...) -# -# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for -# parsing the arguments given to that macro or function. -# It processes the arguments and defines a set of variables which hold the -# values of the respective options. -# -# The argument contains all options for the respective macro, -# i.e. keywords which can be used when calling the macro without any value -# following, like e.g. the OPTIONAL keyword of the install() command. -# -# The argument contains all keywords for this macro -# which are followed by one value, like e.g. DESTINATION keyword of the -# install() command. -# -# The argument contains all keywords for this macro -# which can be followed by more than one value, like e.g. the TARGETS or -# FILES keywords of the install() command. -# -# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the -# keywords listed in , and -# a variable composed of the given -# followed by "_" and the name of the respective keyword. -# These variables will then hold the respective value from the argument list. -# For the keywords this will be TRUE or FALSE. -# -# All remaining arguments are collected in a variable -# _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether -# your macro was called with unrecognized parameters. -# -# As an example here a my_install() macro, which takes similar arguments as the -# real install() command: -# -# function(MY_INSTALL) -# set(options OPTIONAL FAST) -# set(oneValueArgs DESTINATION RENAME) -# set(multiValueArgs TARGETS CONFIGURATIONS) -# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) -# ... -# -# Assume my_install() has been called like this: -# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) -# -# After the cmake_parse_arguments() call the macro will have set the following -# variables: -# MY_INSTALL_OPTIONAL = TRUE -# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() -# MY_INSTALL_DESTINATION = "bin" -# MY_INSTALL_RENAME = "" (was not used) -# MY_INSTALL_TARGETS = "foo;bar" -# MY_INSTALL_CONFIGURATIONS = "" (was not used) -# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" -# -# You can the continue and process these variables. -# -# Keywords terminate lists of values, e.g. if directly after a one_value_keyword -# another recognized keyword follows, this is interpreted as the beginning of -# the new option. -# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in -# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would -# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. - -#============================================================================= -# Copyright 2010 Alexander Neundorf -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) - return() -endif() -set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) - - -function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) - # first set all result variables to empty/FALSE - foreach(arg_name ${_singleArgNames} ${_multiArgNames}) - set(${prefix}_${arg_name}) - endforeach(arg_name) - - foreach(option ${_optionNames}) - set(${prefix}_${option} FALSE) - endforeach(option) - - set(${prefix}_UNPARSED_ARGUMENTS) - - set(insideValues FALSE) - set(currentArgName) - - # now iterate over all arguments and fill the result variables - foreach(currentArg ${ARGN}) - list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword - list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword - list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword - - if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) - if(insideValues) - if("${insideValues}" STREQUAL "SINGLE") - set(${prefix}_${currentArgName} ${currentArg}) - set(insideValues FALSE) - elseif("${insideValues}" STREQUAL "MULTI") - list(APPEND ${prefix}_${currentArgName} ${currentArg}) - endif() - else(insideValues) - list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) - endif(insideValues) - else() - if(NOT ${optionIndex} EQUAL -1) - set(${prefix}_${currentArg} TRUE) - set(insideValues FALSE) - elseif(NOT ${singleArgIndex} EQUAL -1) - set(currentArgName ${currentArg}) - set(${prefix}_${currentArgName}) - set(insideValues "SINGLE") - elseif(NOT ${multiArgIndex} EQUAL -1) - set(currentArgName ${currentArg}) - set(${prefix}_${currentArgName}) - set(insideValues "MULTI") - endif() - endif() - - endforeach(currentArg) - - # propagate the result variables to the caller: - foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) - set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) - endforeach(arg_name) - set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) - -endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/cmake/Modules/FindGFORTRAN.cmake b/cmake/Modules/FindGFORTRAN.cmake new file mode 100644 index 000000000..f19ccd77a --- /dev/null +++ b/cmake/Modules/FindGFORTRAN.cmake @@ -0,0 +1,150 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +find_library(GFORTRAN NAMES gfortran + PATHS /usr/lib + /usr/lib64 + /usr/local/lib + /usr/local/lib/i386 + /usr/lib/gcc/x86_64-linux-gnu + /usr/lib/gcc/i686-linux-gnu + /usr/lib/gcc/i386-linux-gnu + /usr/lib/gcc/x86_64-linux-gnu/4.6 # Ubuntu 12.04 + /usr/lib/gcc/i686-linux-gnu/4.6 + /usr/lib/gcc/x86_64-linux-gnu/4.7 + /usr/lib/gcc/i686-linux-gnu/4.7 + /usr/lib/gcc/x86_64-linux-gnu/4.8 + /usr/lib/gcc/i686-linux-gnu/4.8 + /usr/lib/gcc/x86_64-linux-gnu/4.9 + /usr/lib/gcc/i686-linux-gnu/4.9 + /usr/lib/gcc/x86_64-redhat-linux/4.7.2 # Fedora 18 + /usr/lib/gcc/i686-redhat-linux/4.7.2 + /usr/lib/gcc/x86_64-redhat-linux/4.8.1 # Fedora 19 + /usr/lib/gcc/x86_64-redhat-linux/4.8.3 # Fedora 20 + /usr/lib/gcc/x86_64-redhat-linux/4.9.1 # Fedora 21 + /usr/lib/gcc/i686-redhat-linux/4.8.1 + /usr/lib/gcc/i686-redhat-linux/4.8.3 + /usr/lib/gcc/i686-redhat-linux/4.9.1 + /usr/lib/gcc/x86_64-redhat-linux/4.4.4 # CentOS 6 + /usr/lib/gcc/i686-redhat-linux/4.4.4 + /usr/lib/gcc/x86_64-redhat-linux/4.8.2 + /usr/lib/gcc/i686-redhat-linux/4.8.2 + /usr/lib/gcc/x86_64-redhat-linux/7 + /usr/lib/gcc/i686-redhat-linux/7 + /usr/lib/gcc/armv7hl-redhat-linux-gnueabi/7 + /usr/lib/gcc/aarch64-redhat-linux/7 + /usr/lib/gcc/i586-suse-linux/4.8 # OpenSUSE 13.1 + /usr/lib/gcc/i586-suse-linux/4.9 + /usr/lib/gcc/x86_64-suse-linux/4.8 + /usr/lib/gcc/x86_64-suse-linux/4.9 + /usr/lib/gcc/i486-linux-gnu # Debian 7 + /usr/lib/gcc/i486-linux-gnu/4.4 + /usr/lib/gcc/i486-linux-gnu/4.6 + /usr/lib/gcc/i486-linux-gnu/4.7 + /usr/lib/gcc/i486-linux-gnu/4.8 + /usr/lib/gcc/i486-linux-gnu/4.9 + /usr/lib/gcc/i586-linux-gnu/4.9 + /usr/lib/gcc/arm-linux-gnueabihf/4.4 # Debian armhf + /usr/lib/gcc/arm-linux-gnueabihf/4.5 + /usr/lib/gcc/arm-linux-gnueabihf/4.6 + /usr/lib/gcc/arm-linux-gnueabihf/4.7 + /usr/lib/gcc/arm-linux-gnueabihf/4.8 + /usr/lib/gcc/arm-linux-gnueabihf/4.9 + /usr/lib/gcc/aarch64-linux-gnu/4.9 # Debian arm64 + /usr/lib/gcc/arm-linux-gnueabi/4.7 # Debian armel + /usr/lib/gcc/arm-linux-gnueabi/4.9 + /usr/lib/gcc/x86_64-linux-gnu/5 + /usr/lib/gcc/i686-linux-gnu/5 + /usr/lib/gcc/arm-linux-gnueabi/5 + /usr/lib/gcc/arm-linux-gnueabihf/5 + /usr/lib/gcc/aarch64-linux-gnu/5 + /usr/lib/gcc/x86_64-linux-gnu/6 # Ubuntu 16.10 + /usr/lib/gcc/alpha-linux-gnu/6 + /usr/lib/gcc/aarch64-linux-gnu/6 + /usr/lib/gcc/arm-linux-gnueabi/6 + /usr/lib/gcc/arm-linux-gnueabihf/6 + /usr/lib/gcc/hppa-linux-gnu/6 + /usr/lib/gcc/i686-gnu/6 + /usr/lib/gcc/i686-linux-gnu/6 + /usr/lib/gcc/x86_64-kfreebsd-gnu/6 + /usr/lib/gcc/i686-kfreebsd-gnu/6 + /usr/lib/gcc/m68k-linux-gnu/6 + /usr/lib/gcc/mips-linux-gnu/6 + /usr/lib/gcc/mips64el-linux-gnuabi64/6 + /usr/lib/gcc/mipsel-linux-gnu/6 + /usr/lib/gcc/powerpc-linux-gnu/6 + /usr/lib/gcc/powerpc-linux-gnuspe/6 + /usr/lib/gcc/powerpc64-linux-gnu/6 + /usr/lib/gcc/powerpc64le-linux-gnu/6 + /usr/lib/gcc/s390x-linux-gnu/6 + /usr/lib/gcc/sparc64-linux-gnu/6 + /usr/lib/gcc/x86_64-linux-gnux32/6 + /usr/lib/gcc/sh4-linux-gnu/6 + /usr/lib/gcc/x86_64-linux-gnu/7 # Debian 9 Buster + /usr/lib/gcc/alpha-linux-gnu/7 + /usr/lib/gcc/aarch64-linux-gnu/7 + /usr/lib/gcc/arm-linux-gnueabi/7 + /usr/lib/gcc/arm-linux-gnueabihf/7 + /usr/lib/gcc/hppa-linux-gnu/7 + /usr/lib/gcc/i686-gnu/7 + /usr/lib/gcc/i686-linux-gnu/7 + /usr/lib/gcc/x86_64-kfreebsd-gnu/7 + /usr/lib/gcc/i686-kfreebsd-gnu/7 + /usr/lib/gcc/m68k-linux-gnu/7 + /usr/lib/gcc/mips-linux-gnu/7 + /usr/lib/gcc/mips64el-linux-gnuabi64/7 + /usr/lib/gcc/mipsel-linux-gnu/7 + /usr/lib/gcc/powerpc-linux-gnu/7 + /usr/lib/gcc/powerpc-linux-gnuspe/7 + /usr/lib/gcc/powerpc64-linux-gnu/7 + /usr/lib/gcc/powerpc64le-linux-gnu/7 + /usr/lib/gcc/s390x-linux-gnu/7 + /usr/lib/gcc/sparc64-linux-gnu/7 + /usr/lib/gcc/x86_64-linux-gnux32/7 + /usr/lib/gcc/sh4-linux-gnu/7 + /usr/lib/x86_64-linux-gnu # libgfortran4 + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/aarch64-linux-gnu + /usr/lib/i386-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/alpha-linux-gnu + /usr/lib/gcc/x86_64-linux-gnu/8 # libgfortran8 + /usr/lib/gcc/aarch64-linux-gnu/8 + /usr/lib/gcc/arm-linux-gnueabihf/8 + /usr/lib/gcc/i686-linux-gnu/8 + /usr/lib/gcc/powerpc64le-linux-gnu/8 + /usr/lib/gcc/s390x-linux-gnu/8 + /usr/lib/gcc/alpha-linux-gnu/8 + ${GFORTRAN_ROOT}/lib + $ENV{GFORTRAN_ROOT}/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GFORTRAN DEFAULT_MSG GFORTRAN) diff --git a/cmake/Modules/FindGFlags.cmake b/cmake/Modules/FindGFlags.cmake deleted file mode 100644 index 1aff218f5..000000000 --- a/cmake/Modules/FindGFlags.cmake +++ /dev/null @@ -1,89 +0,0 @@ -# - Try to find GFlags -# -# The following variables are optionally searched for defaults -# GFlags_ROOT_DIR: Base directory where all GFlags components are found -# -# The following are set after configuration is done: -# GFlags_FOUND -# GFlags_INCLUDE_DIRS -# GFlags_LIBS -# GFlags_LIBRARY_DIRS - -# - Try to find GFlags -# -# -# The following are set after configuration is done: -# GFlags_FOUND -# GFlags_INCLUDE_DIRS -# GFlags_LIBS -# GFlags_LIBRARY_DIRS -cmake_minimum_required(VERSION 2.6) - -if(APPLE) - FIND_PATH(GFlags_ROOT_DIR - libgflags.dylib - PATHS - /opt/local/lib - /usr/local/lib - ) -else(APPLE) - FIND_PATH(GFlags_ROOT_DIR - libgflags.so - HINTS - /usr/local/lib - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib64 - /usr/lib - ) -endif(APPLE) - -IF(GFlags_ROOT_DIR) - # We are testing only a couple of files in the include directories - FIND_PATH(GFlags_INCLUDE_DIRS - gflags/gflags.h - HINTS - /opt/local/include - /usr/local/include - /usr/include - ${GFlags_ROOT_DIR}/src - ) - - # Find the libraries - SET(GFlags_LIBRARY_DIRS ${GFlags_ROOT_DIR}) - - FIND_LIBRARY(GFlags_lib gflags ${GFlags_LIBRARY_DIRS}) - - # set up include and link directory - include_directories(${GFlags_INCLUDE_DIRS}) - link_directories(${GFlags_LIBRARY_DIRS}) - message(STATUS "gflags library found at ${GFlags_lib}") - SET(GFlags_LIBS ${GFlags_lib}) - SET(GFlags_FOUND true) - MARK_AS_ADVANCED(GFlags_INCLUDE_DIRS) -ELSE(GFlags_ROOT_DIR) - MESSAGE(STATUS "Cannot find gflags") - SET(GFlags_FOUND false) -ENDIF(GFlags_ROOT_DIR) - diff --git a/cmake/Modules/FindGLOG.cmake b/cmake/Modules/FindGLOG.cmake index 68b012c8d..2d8f154f3 100644 --- a/cmake/Modules/FindGLOG.cmake +++ b/cmake/Modules/FindGLOG.cmake @@ -1,3 +1,20 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + # - Try to find the Google Glog library # # This module defines the following variables @@ -11,20 +28,20 @@ # GLOG_ROOT - Can be set to Glog install path or Windows build path # -if (NOT DEFINED GLOG_ROOT) - set (GLOG_ROOT /usr /usr/local) -endif (NOT DEFINED GLOG_ROOT) +if(NOT DEFINED GLOG_ROOT) + set(GLOG_ROOT /usr /usr/local) +endif() if(MSVC) - set(LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/Release) -else(MSVC) - set (LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/lib) -endif(MSVC) + set(LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/Release) +else() + set(LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/lib) +endif() macro(_FIND_GLOG_LIBRARIES _var) - find_library(${_var} - NAMES ${ARGN} - PATHS ${LIB_PATHS} + find_library(${_var} + NAMES ${ARGN} + PATHS ${LIB_PATHS} /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu @@ -51,48 +68,52 @@ macro(_FIND_GLOG_LIBRARIES _var) /usr/lib/alpha-linux-gnu /usr/lib64 /usr/lib + ${GLOG_ROOT}/lib + $ENV{GLOG_ROOT}/lib + ${GLOG_ROOT}/lib64 + $ENV{GLOG_ROOT}/lib64 PATH_SUFFIXES lib ) - mark_as_advanced(${_var}) + mark_as_advanced(${_var}) endmacro() macro(_GLOG_APPEND_LIBRARIES _list _release) set(_debug ${_release}_DEBUG) if(${_debug}) - set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}}) + set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}}) else() - set(${_list} ${${_list}} ${${_release}}) + set(${_list} ${${_list}} ${${_release}}) endif() endmacro() if(MSVC) - find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h - PATHS - ${GLOG_ROOT}/src/windows - ${GLOG_ROOT}/src/windows/glog - ) -else(MSVC) - # Linux/OS X builds - find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h - PATHS - ${GLOG_ROOT}/include/glog - /usr/include/glog - /opt/local/include/glog # default location in Macports - ) -endif(MSVC) + find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h + PATHS + ${GLOG_ROOT}/src/windows + ${GLOG_ROOT}/src/windows/glog + ) +else() + # Linux/OS X builds + find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h + PATHS + ${GLOG_ROOT}/include/glog + /usr/include/glog + /opt/local/include/glog # default location in Macports + ) +endif() # Find the libraries if(MSVC) - _FIND_GLOG_LIBRARIES(GLOG_LIBRARIES libglog.lib) -else(MSVC) - # Linux/OS X builds - if(UNIX) - _FIND_GLOG_LIBRARIES(GLOG_LIBRARIES libglog.so) - endif(UNIX) - if(APPLE) - _FIND_GLOG_LIBRARIES(GLOG_LIBRARIES libglog.dylib) - endif(APPLE) -endif(MSVC) + _find_glog_libraries(GLOG_LIBRARIES libglog.lib) +else() + # Linux/OS X builds + if(UNIX) + _find_glog_libraries(GLOG_LIBRARIES libglog.so) + endif() + if(APPLE) + _find_glog_libraries(GLOG_LIBRARIES libglog.dylib) + endif() +endif() if(GLOG_FOUND) message(STATUS "glog library found at ${GLOG_LIBRARIES}") @@ -100,21 +121,20 @@ endif() # handle the QUIETLY and REQUIRED arguments and set GLOG_FOUND to TRUE if # all listed variables are TRUE -include("${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake") -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Glog DEFAULT_MSG - GLOG_LIBRARIES) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLOG DEFAULT_MSG GLOG_LIBRARIES) if(MSVC) - string(REGEX REPLACE "/glog$" "" VAR_WITHOUT ${GLOG_INCLUDE_DIR}) - string(REGEX REPLACE "/windows$" "" VAR_WITHOUT ${VAR_WITHOUT}) - set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS} "${VAR_WITHOUT}") - string(REGEX REPLACE "/libglog.lib" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) -else(MSVC) - # Linux/OS X builds - set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) - string(REGEX REPLACE "/libglog.so" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) -endif(MSVC) + string(REGEX REPLACE "/glog$" "" VAR_WITHOUT ${GLOG_INCLUDE_DIR}) + string(REGEX REPLACE "/windows$" "" VAR_WITHOUT ${VAR_WITHOUT}) + set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS} "${VAR_WITHOUT}") + string(REGEX REPLACE "/libglog.lib" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) +else() + # Linux/OS X builds + set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) + string(REGEX REPLACE "/libglog.so" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) +endif() if(GLOG_FOUND) - # _GLOG_APPEND_LIBRARIES(GLOG GLOG_LIBRARIES) + # _GLOG_APPEND_LIBRARIES(GLOG GLOG_LIBRARIES) endif() diff --git a/cmake/Modules/FindGNSSSIMULATOR.cmake b/cmake/Modules/FindGNSSSIMULATOR.cmake new file mode 100644 index 000000000..66aa9176a --- /dev/null +++ b/cmake/Modules/FindGNSSSIMULATOR.cmake @@ -0,0 +1,30 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +find_program(SW_GENERATOR_BIN gnss_sim + PATHS /usr/bin + /usr/local/bin + /opt/local/bin + ${CMAKE_INSTALL_PREFIX}/bin + ${GNSSSIMULATOR_ROOT}/bin + $ENV{GNSSSIMULATOR_ROOT}/bin + PATH_SUFFIXES bin +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GNSSSIMULATOR DEFAULT_MSG SW_GENERATOR_BIN) +mark_as_advanced(SW_GENERATOR_BIN) diff --git a/cmake/Modules/FindGnuradio.cmake b/cmake/Modules/FindGNURADIO.cmake similarity index 50% rename from cmake/Modules/FindGnuradio.cmake rename to cmake/Modules/FindGNURADIO.cmake index 44ae95722..7f5deb3ab 100644 --- a/cmake/Modules/FindGnuradio.cmake +++ b/cmake/Modules/FindGNURADIO.cmake @@ -1,16 +1,32 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ######################################################################## # Find GNU Radio ######################################################################## -INCLUDE(FindPkgConfig) -INCLUDE(FindPackageHandleStandardArgs) +include(FindPkgConfig) +include(FindPackageHandleStandardArgs) -# if GR_REQUIRED_COMPONENTS is not defined, it will be set to the following list +# if GR_REQUIRED_COMPONENTS is not defined, it will be set to the following list if(NOT GR_REQUIRED_COMPONENTS) set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG BLOCKS DIGITAL FFT FILTER PMT FEC TRELLIS UHD) endif() - # Allows us to use all .cmake files in this directory list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_LIST_DIR}) @@ -18,18 +34,17 @@ list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_LIST_DIR}) set(GNURADIO_ALL_LIBRARIES "") set(GNURADIO_ALL_INCLUDE_DIRS "") -MACRO(LIST_CONTAINS var value) - SET(${var}) - FOREACH(value2 ${ARGN}) - IF (${value} STREQUAL ${value2}) - SET(${var} TRUE) - ENDIF(${value} STREQUAL ${value2}) - ENDFOREACH(value2) -ENDMACRO(LIST_CONTAINS) +macro(LIST_CONTAINS var value) + set(${var}) + foreach(value2 ${ARGN}) + if(${value} STREQUAL ${value2}) + set(${var} TRUE) + endif() + endforeach() +endmacro() function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) - - LIST_CONTAINS(REQUIRED_MODULE ${EXTVAR} ${GR_REQUIRED_COMPONENTS}) + list_contains(REQUIRED_MODULE ${EXTVAR} ${GR_REQUIRED_COMPONENTS}) if(NOT REQUIRED_MODULE) #message("Ignoring GNU Radio Module ${EXTVAR}") return() @@ -38,7 +53,7 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) message(STATUS "Checking for GNU Radio Module: ${EXTVAR}") # check for .pc hints - PKG_CHECK_MODULES(PC_GNURADIO_${EXTVAR} ${PCNAME}) + pkg_check_modules(PC_GNURADIO_${EXTVAR} ${PCNAME}) if(NOT PC_GNURADIO_${EXTVAR}_FOUND) set(PC_GNURADIO_${EXTVAR}_LIBRARIES ${LIBFILE}) @@ -50,29 +65,29 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) set(PC_LIBDIR ${PC_GNURADIO_${EXTVAR}_LIBDIR}) # look for include files - FIND_PATH( - ${INCVAR_NAME} + find_path(${INCVAR_NAME} NAMES ${INCFILE} HINTS $ENV{GNURADIO_RUNTIME_DIR}/include - ${PC_INCDIR} - ${CMAKE_INSTALL_PREFIX}/include - ${GNURADIO_INSTALL_PREFIX}/include + ${PC_INCDIR} + ${CMAKE_INSTALL_PREFIX}/include + ${GNURADIO_INSTALL_PREFIX}/include PATHS /usr/local/include /usr/include ${GNURADIO_INSTALL_PREFIX}/include + ${GNURADIO_ROOT}/include + $ENV{GNURADIO_ROOT}/include ) # look for libs foreach(libname ${PC_GNURADIO_${EXTVAR}_LIBRARIES}) - FIND_LIBRARY( - ${LIBVAR_NAME}_${libname} + find_library(${LIBVAR_NAME}_${libname} NAMES ${libname} ${libname}-${PC_GNURADIO_RUNTIME_VERSION} HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib - ${PC_LIBDIR} - ${CMAKE_INSTALL_PREFIX}/lib/ - ${CMAKE_INSTALL_PREFIX}/lib64/ - ${GNURADIO_INSTALL_PREFIX}/lib/ - ${GNURADIO_INSTALL_PREFIX}/lib64 + ${PC_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + ${GNURADIO_INSTALL_PREFIX}/lib + ${GNURADIO_INSTALL_PREFIX}/lib64 PATHS /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu @@ -100,9 +115,13 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) /usr/lib64 /usr/lib ${GNURADIO_INSTALL_PREFIX}/lib + ${GNURADIO_ROOT}/lib + $ENV{GNURADIO_ROOT}/lib + ${GNURADIO_ROOT}/lib64 + $ENV{GNURADIO_ROOT}/lib64 ) - list(APPEND ${LIBVAR_NAME} ${${LIBVAR_NAME}_${libname}}) - endforeach(libname) + list(APPEND ${LIBVAR_NAME} ${${LIBVAR_NAME}_${libname}}) + endforeach() set(${LIBVAR_NAME} ${${LIBVAR_NAME}} PARENT_SCOPE) @@ -114,43 +133,42 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) set(GNURADIO_ALL_INCLUDE_DIRS ${GNURADIO_ALL_INCLUDE_DIRS} ${GNURADIO_${EXTVAR}_INCLUDE_DIRS} PARENT_SCOPE) set(GNURADIO_ALL_LIBRARIES ${GNURADIO_ALL_LIBRARIES} ${GNURADIO_${EXTVAR}_LIBRARIES} PARENT_SCOPE) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_${EXTVAR} DEFAULT_MSG GNURADIO_${EXTVAR}_LIBRARIES GNURADIO_${EXTVAR}_INCLUDE_DIRS) + find_package_handle_standard_args(GNURADIO_${EXTVAR} DEFAULT_MSG GNURADIO_${EXTVAR}_LIBRARIES GNURADIO_${EXTVAR}_INCLUDE_DIRS) message(STATUS "GNURADIO_${EXTVAR}_FOUND = ${GNURADIO_${EXTVAR}_FOUND}") set(GNURADIO_${EXTVAR}_FOUND ${GNURADIO_${EXTVAR}_FOUND} PARENT_SCOPE) # generate an error if the module is missing if(NOT GNURADIO_${EXTVAR}_FOUND) - message(STATUS "Required GNU Radio Component: ${EXTVAR} missing!") + message(STATUS "Required GNU Radio Component: ${EXTVAR} missing!") endif() - MARK_AS_ADVANCED(GNURADIO_${EXTVAR}_LIBRARIES GNURADIO_${EXTVAR}_INCLUDE_DIRS) - + mark_as_advanced(GNURADIO_${EXTVAR}_LIBRARIES GNURADIO_${EXTVAR}_INCLUDE_DIRS) endfunction() -GR_MODULE(RUNTIME gnuradio-runtime gnuradio/top_block.h gnuradio-runtime) -GR_MODULE(ANALOG gnuradio-analog gnuradio/analog/api.h gnuradio-analog) -GR_MODULE(AUDIO gnuradio-audio gnuradio/audio/api.h gnuradio-audio) -GR_MODULE(BLOCKS gnuradio-blocks gnuradio/blocks/api.h gnuradio-blocks) -GR_MODULE(CHANNELS gnuradio-channels gnuradio/channels/api.h gnuradio-channels) -GR_MODULE(DIGITAL gnuradio-digital gnuradio/digital/api.h gnuradio-digital) -GR_MODULE(FCD gnuradio-fcd gnuradio/fcd_api.h gnuradio-fcd) -GR_MODULE(FEC gnuradio-fec gnuradio/fec/api.h gnuradio-fec) -GR_MODULE(FFT gnuradio-fft gnuradio/fft/api.h gnuradio-fft) -GR_MODULE(FILTER gnuradio-filter gnuradio/filter/api.h gnuradio-filter) -GR_MODULE(NOAA gnuradio-noaa gnuradio/noaa/api.h gnuradio-noaa) -GR_MODULE(PAGER gnuradio-pager gnuradio/pager/api.h gnuradio-pager) -GR_MODULE(QTGUI gnuradio-qtgui gnuradio/qtgui/api.h gnuradio-qtgui) -GR_MODULE(TRELLIS gnuradio-trellis gnuradio/trellis/api.h gnuradio-trellis) -GR_MODULE(UHD gnuradio-uhd gnuradio/uhd/api.h gnuradio-uhd) -GR_MODULE(VOCODER gnuradio-vocoder gnuradio/vocoder/api.h gnuradio-vocoder) -GR_MODULE(WAVELET gnuradio-wavelet gnuradio/wavelet/api.h gnuradio-wavelet) -GR_MODULE(WXGUI gnuradio-wxgui gnuradio/wxgui/api.h gnuradio-wxgui) -GR_MODULE(PMT gnuradio-runtime pmt/pmt.h gnuradio-pmt) +gr_module(RUNTIME gnuradio-runtime gnuradio/top_block.h gnuradio-runtime) +gr_module(ANALOG gnuradio-analog gnuradio/analog/api.h gnuradio-analog) +gr_module(AUDIO gnuradio-audio gnuradio/audio/api.h gnuradio-audio) +gr_module(BLOCKS gnuradio-blocks gnuradio/blocks/api.h gnuradio-blocks) +gr_module(CHANNELS gnuradio-channels gnuradio/channels/api.h gnuradio-channels) +gr_module(DIGITAL gnuradio-digital gnuradio/digital/api.h gnuradio-digital) +gr_module(FCD gnuradio-fcd gnuradio/fcd_api.h gnuradio-fcd) +gr_module(FEC gnuradio-fec gnuradio/fec/api.h gnuradio-fec) +gr_module(FFT gnuradio-fft gnuradio/fft/api.h gnuradio-fft) +gr_module(FILTER gnuradio-filter gnuradio/filter/api.h gnuradio-filter) +gr_module(NOAA gnuradio-noaa gnuradio/noaa/api.h gnuradio-noaa) +gr_module(PAGER gnuradio-pager gnuradio/pager/api.h gnuradio-pager) +gr_module(QTGUI gnuradio-qtgui gnuradio/qtgui/api.h gnuradio-qtgui) +gr_module(TRELLIS gnuradio-trellis gnuradio/trellis/api.h gnuradio-trellis) +gr_module(UHD gnuradio-uhd gnuradio/uhd/api.h gnuradio-uhd) +gr_module(VOCODER gnuradio-vocoder gnuradio/vocoder/api.h gnuradio-vocoder) +gr_module(WAVELET gnuradio-wavelet gnuradio/wavelet/api.h gnuradio-wavelet) +gr_module(WXGUI gnuradio-wxgui gnuradio/wxgui/api.h gnuradio-wxgui) +gr_module(PMT gnuradio-runtime pmt/pmt.h gnuradio-pmt) list(REMOVE_DUPLICATES GNURADIO_ALL_INCLUDE_DIRS) list(REMOVE_DUPLICATES GNURADIO_ALL_LIBRARIES) - # Trick to find out that GNU Radio is >= 3.7.4 if pkgconfig is not present +# Trick to find out that GNU Radio is >= 3.7.4 if pkgconfig is not present if(NOT PC_GNURADIO_RUNTIME_VERSION) find_file(GNURADIO_VERSION_GREATER_THAN_373 NAMES gnuradio/blocks/tsb_vector_sink_f.h @@ -160,8 +178,25 @@ if(NOT PC_GNURADIO_RUNTIME_VERSION) PATHS /usr/local/include /usr/include ${GNURADIO_INSTALL_PREFIX}/include + ${GNURADIO_ROOT}/include + $ENV{GNURADIO_ROOT}/include ) - if(GNURADIO_VERSION_GREATER_THAN_373) - set(PC_GNURADIO_RUNTIME_VERSION "3.7.4+") - endif(GNURADIO_VERSION_GREATER_THAN_373) -endif(NOT PC_GNURADIO_RUNTIME_VERSION) \ No newline at end of file + if(GNURADIO_VERSION_GREATER_THAN_373) + set(PC_GNURADIO_RUNTIME_VERSION "3.7.4+") + endif() + + find_file(GNURADIO_VERSION_GREATER_THAN_38 + NAMES gnuradio/filter/mmse_resampler_cc.h + HINTS $ENV{GNURADIO_RUNTIME_DIR}/include + ${CMAKE_INSTALL_PREFIX}/include + ${GNURADIO_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include + ${GNURADIO_INSTALL_PREFIX}/include + ${GNURADIO_ROOT}/include + $ENV{GNURADIO_ROOT}/include + ) + if(GNURADIO_VERSION_GREATER_THAN_38) + set(PC_GNURADIO_RUNTIME_VERSION "3.8.0+") + endif() +endif() diff --git a/cmake/Modules/FindGPSTK.cmake b/cmake/Modules/FindGPSTK.cmake index fffe17877..f5ecb667e 100644 --- a/cmake/Modules/FindGPSTK.cmake +++ b/cmake/Modules/FindGPSTK.cmake @@ -1,24 +1,49 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + # - Find gpstk library # Find the native gpstk includes and library # This module defines # GPSTK_INCLUDE_DIR, where to find Rinex3ObsBase.hpp, etc. -# GPSTK_LIBRARIES, libraries to link against to use GPSTK. # GPSTK_FOUND, If false, do not try to use GPSTK. -# also defined, but not for general use are # GPSTK_LIBRARY, where to find the GPSTK library. -FIND_PATH(GPSTK_INCLUDE_DIR Rinex3ObsBase.hpp) +find_path(GPSTK_INCLUDE_DIR gpstk/Rinex3ObsBase.hpp + HINTS /usr/include + /usr/local/include + /opt/local/include + ${GPSTK_ROOT}/include + $ENV{GPSTK_ROOT}/include +) -SET(GPSTK_NAMES ${GPSTK_NAMES} gpstk libgpstk) -FIND_LIBRARY(GPSTK_LIBRARY NAMES ${GPSTK_NAMES} ) +set(GPSTK_NAMES ${GPSTK_NAMES} gpstk libgpstk) -# handle the QUIETLY and REQUIRED arguments and set GPSTK_FOUND to TRUE if +find_library(GPSTK_LIBRARY NAMES ${GPSTK_NAMES} + HINTS /usr/lib + /usr/local/lib + /opt/local/lib + ${GPSTK_ROOT}/lib + $ENV{GPSTK_ROOT}/lib + ${GPSTK_ROOT}/lib64 + $ENV{GPSTK_ROOT}/lib64 +) + +# handle the QUIETLY and REQUIRED arguments and set GPSTK_FOUND to TRUE if # all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GPSTK DEFAULT_MSG GPSTK_LIBRARY GPSTK_INCLUDE_DIR) - -IF(GPSTK_FOUND) - SET( GPSTK_LIBRARIES ${GPSTK_LIBRARY} ) -ENDIF(GPSTK_FOUND) - -MARK_AS_ADVANCED(GPSTK_INCLUDE_DIR GPSTK_LIBRARY) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GPSTK DEFAULT_MSG GPSTK_LIBRARY GPSTK_INCLUDE_DIR) +mark_as_advanced(GPSTK_INCLUDE_DIR GPSTK_LIBRARY GPSTK_INCLUDE_DIR) diff --git a/cmake/Modules/FindGRIIO.cmake b/cmake/Modules/FindGRIIO.cmake new file mode 100644 index 000000000..6d341e7fd --- /dev/null +++ b/cmake/Modules/FindGRIIO.cmake @@ -0,0 +1,72 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +include(FindPkgConfig) +pkg_check_modules(PC_IIO gnuradio-iio) + +find_path(IIO_INCLUDE_DIRS + NAMES gnuradio/iio/api.h + HINTS $ENV{IIO_DIR}/include + ${PC_IIO_INCLUDEDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/include + /usr/local/include + /usr/include + ${GRIIO_ROOT}/include + $ENV{GRIIO_ROOT}/include +) + +find_library(IIO_LIBRARIES + NAMES gnuradio-iio + HINTS $ENV{IIO_DIR}/lib + ${PC_IIO_LIBDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/hppa-linux-gnu + /usr/lib/i686-gnu + /usr/lib/i686-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i686-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/sh4-linux-gnu + ${GRIIO_ROOT}/lib + $ENV{GRIIO_ROOT}/lib + ${GRIIO_ROOT}/lib64 + $ENV{GRIIO_ROOT}/lib64 +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GRIIO DEFAULT_MSG IIO_LIBRARIES IIO_INCLUDE_DIRS) +mark_as_advanced(IIO_LIBRARIES IIO_INCLUDE_DIRS) diff --git a/cmake/Modules/FindGrOsmoSDR.cmake b/cmake/Modules/FindGROSMOSDR.cmake similarity index 50% rename from cmake/Modules/FindGrOsmoSDR.cmake rename to cmake/Modules/FindGROSMOSDR.cmake index a67e1817e..48379ed76 100644 --- a/cmake/Modules/FindGrOsmoSDR.cmake +++ b/cmake/Modules/FindGROSMOSDR.cmake @@ -1,8 +1,25 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + # Tries to find gr-osmosdr. # # Usage of this module as follows: # -# find_package(GrOsmoSDR) +# find_package(GROSMOSDR) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: @@ -17,23 +34,29 @@ # GROSMOSDR_LIBRARIES The gr-osmosdr libraries (gnuradio-osmosdr) # GROSMOSDR_INCLUDE_DIR The location of gr-osmosdr headers -if(NOT GROSMOSDR_FOUND) - pkg_check_modules (GROSMOSDR_PKG gnuradio-osmosdr) - find_path(GROSMOSDR_INCLUDE_DIR - NAMES osmosdr/source.h - osmosdr/api.h - PATHS +include(FindPkgConfig) +pkg_check_modules(GROSMOSDR_PKG gnuradio-osmosdr) + +find_path(GROSMOSDR_INCLUDE_DIR + NAMES + osmosdr/source.h + osmosdr/api.h + PATHS ${GROSMOSDR_PKG_INCLUDE_DIRS} /usr/include /usr/local/include - ) + /opt/local/include + ${GROSMOSDR_ROOT}/include + $ENV{GROSMOSDR_ROOT}/include +) - find_library(GROSMOSDR_LIBRARIES - NAMES gnuradio-osmosdr - PATHS +find_library(GROSMOSDR_LIBRARIES + NAMES gnuradio-osmosdr + PATHS ${GROSMOSDR_PKG_LIBRARY_DIRS} /usr/lib /usr/local/lib + /opt/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/lib/arm-linux-gnueabihf @@ -58,16 +81,12 @@ if(NOT GROSMOSDR_FOUND) /usr/lib/x86_64-linux-gnux32 /usr/lib/alpha-linux-gnu /usr/lib64 - ) + ${GROSMOSDR_ROOT}/lib + $ENV{GROSMOSDR_ROOT}/lib + ${GROSMOSDR_ROOT}/lib64 + $ENV{GROSMOSDR_ROOT}/lib64 +) - if(GROSMOSDR_INCLUDE_DIR AND GROSMOSDR_LIBRARIES) - set(GROSMOSDR_FOUND TRUE CACHE INTERNAL "gnuradio-osmosdr found") - message(STATUS "Found gnuradio-osmosdr: ${GROSMOSDR_INCLUDE_DIR}, ${GROSMOSDR_LIBRARIES}") - else(GROSMOSDR_INCLUDE_DIR AND GROSMOSDR_LIBRARIES) - set(GROSMOSDR_FOUND FALSE CACHE INTERNAL "gnuradio-osmosdr found") - message(STATUS "gnuradio-osmosdr not found.") - endif(GROSMOSDR_INCLUDE_DIR AND GROSMOSDR_LIBRARIES) - -mark_as_advanced(GROSMOSDR_INCLUDE_DIR GROSMOSDR_LIBRARIES) - -endif(NOT GROSMOSDR_FOUND) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GROSMOSDR DEFAULT_MSG GROSMOSDR_LIBRARIES GROSMOSDR_INCLUDE_DIR) +mark_as_advanced(GROSMOSDR_LIBRARIES GROSMOSDR_INCLUDE_DIR) diff --git a/cmake/Modules/FindGperftools.cmake b/cmake/Modules/FindGperftools.cmake deleted file mode 100644 index 5a97a29c5..000000000 --- a/cmake/Modules/FindGperftools.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# Tries to find Gperftools. -# -# Usage of this module as follows: -# -# find_package(Gperftools) -# -# Variables used by this module, they can change the default behaviour and need -# to be set before calling find_package: -# -# Gperftools_ROOT_DIR Set this variable to the root installation of -# Gperftools if the module has problems finding -# the proper installation path. -# -# Variables defined by this module: -# -# GPERFTOOLS_FOUND System has Gperftools libs/headers -# GPERFTOOLS_LIBRARIES The Gperftools libraries (tcmalloc & profiler) -# GPERFTOOLS_INCLUDE_DIR The location of Gperftools headers - -find_library(GPERFTOOLS_TCMALLOC - NAMES tcmalloc - HINTS ${Gperftools_ROOT_DIR}/lib) - -find_library(GPERFTOOLS_PROFILER - NAMES profiler - HINTS ${Gperftools_ROOT_DIR}/lib) - -find_library(GPERFTOOLS_TCMALLOC_AND_PROFILER - NAMES tcmalloc_and_profiler - HINTS ${Gperftools_ROOT_DIR}/lib) - -find_path(GPERFTOOLS_INCLUDE_DIR - NAMES gperftools/heap-profiler.h - HINTS ${Gperftools_ROOT_DIR}/include) - -set(GPERFTOOLS_LIBRARIES ${GPERFTOOLS_TCMALLOC_AND_PROFILER}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - Gperftools - DEFAULT_MSG - GPERFTOOLS_LIBRARIES - GPERFTOOLS_INCLUDE_DIR -) - -mark_as_advanced( - Gperftools_ROOT_DIR - GPERFTOOLS_TCMALLOC - GPERFTOOLS_PROFILER - GPERFTOOLS_TCMALLOC_AND_PROFILER - GPERFTOOLS_LIBRARIES - GPERFTOOLS_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/FindGrDbfcttc.cmake b/cmake/Modules/FindGrDbfcttc.cmake deleted file mode 100644 index 5624f8003..000000000 --- a/cmake/Modules/FindGrDbfcttc.cmake +++ /dev/null @@ -1,33 +0,0 @@ -######################################################################## -# Find GR-DBFCTTC Module -######################################################################## - -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_GR_DBFCTTC gr-dbfcttc) - -FIND_PATH( - GR_DBFCTTC_INCLUDE_DIRS - NAMES dbfcttc/api.h - HINTS $ENV{GR_DBFCTTC_DIR}/include - ${PC_GR_DBFCTTC_INCLUDEDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/include - /usr/include - /usr/local/include -) - -FIND_LIBRARY( - GR_DBFCTTC_LIBRARIES - NAMES gnuradio-dbfcttc - HINTS $ENV{GR_DBFCTTC_DIR}/lib - ${PC_GR_DBFCTTC_LIBDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib64 -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GR_DBFCTTC DEFAULT_MSG GR_DBFCTTC_LIBRARIES GR_DBFCTTC_INCLUDE_DIRS) -MARK_AS_ADVANCED(GR_DBFCTTC_LIBRARIES GR_DBFCTTC_INCLUDE_DIRS) diff --git a/cmake/Modules/FindGrGN3S.cmake b/cmake/Modules/FindGrGN3S.cmake deleted file mode 100644 index 0f1c2cbc5..000000000 --- a/cmake/Modules/FindGrGN3S.cmake +++ /dev/null @@ -1,33 +0,0 @@ -######################################################################## -# Find GR-GN3S Module -######################################################################## - -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_GR_GN3S gr-gn3s) - -FIND_PATH( - GR_GN3S_INCLUDE_DIRS - NAMES gn3s/gn3s_api.h - HINTS $ENV{GR_GN3S_DIR}/include - ${PC_GR_GN3S_INCLUDEDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/include - /usr/local/include - /usr/include -) - -FIND_LIBRARY( - GR_GN3S_LIBRARIES - NAMES gr-gn3s - HINTS $ENV{GR_GN3S_DIR}/lib - ${PC_GR_GN3S_LIBDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GR_GN3S DEFAULT_MSG GR_GN3S_LIBRARIES GR_GN3S_INCLUDE_DIRS) -MARK_AS_ADVANCED(GR_GN3S_LIBRARIES GR_GN3S_INCLUDE_DIRS) diff --git a/cmake/Modules/FindLIBIIO.cmake b/cmake/Modules/FindLIBIIO.cmake new file mode 100644 index 000000000..a76180ca2 --- /dev/null +++ b/cmake/Modules/FindLIBIIO.cmake @@ -0,0 +1,76 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +include(FindPkgConfig) +pkg_check_modules(PC_LIBIIO libiio) + +find_path( + LIBIIO_INCLUDE_DIRS + NAMES iio.h + HINTS $ENV{LIBIIO_DIR}/include + ${PC_LIBIIO_INCLUDEDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/include + /usr/local/include + /usr/include + /opt/local/include + ${LIBIIO_ROOT}/include + $ENV{LIBIIO_ROOT}/include +) + +find_library( + LIBIIO_LIBRARIES + NAMES iio libiio.so.0 + HINTS $ENV{LIBIIO_DIR}/lib + ${PC_LIBIIO_LIBDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/hppa-linux-gnu + /usr/lib/i686-gnu + /usr/lib/i686-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i686-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/sh4-linux-gnu + /Library/Frameworks/iio.framework/ + ${LIBIIO_ROOT}/lib + $ENV{LIBIIO_ROOT}/lib + ${LIBIIO_ROOT}/lib64 + $ENV{LIBIIO_ROOT}/lib64 +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LIBIIO DEFAULT_MSG LIBIIO_LIBRARIES LIBIIO_INCLUDE_DIRS) +mark_as_advanced(LIBIIO_LIBRARIES LIBIIO_INCLUDE_DIRS) diff --git a/cmake/Modules/FindLOG4CPP.cmake b/cmake/Modules/FindLOG4CPP.cmake new file mode 100644 index 000000000..283c3ddf9 --- /dev/null +++ b/cmake/Modules/FindLOG4CPP.cmake @@ -0,0 +1,92 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +# - Find Log4cpp +# Find the native LOG4CPP includes and library +# +# LOG4CPP_INCLUDE_DIR - where to find LOG4CPP.h, etc. +# LOG4CPP_LIBRARIES - List of libraries when using LOG4CPP. +# LOG4CPP_FOUND - True if LOG4CPP found. + + +if(LOG4CPP_INCLUDE_DIR) + # Already in cache, be silent + set(LOG4CPP_FIND_QUIETLY TRUE) +endif() + +find_path(LOG4CPP_INCLUDE_DIR log4cpp/Category.hh + /opt/local/include + /usr/local/include + /usr/include + ${LOG4CPP_ROOT}/include + $ENV{LOG4CPP_ROOT}/include +) + +set(LOG4CPP_NAMES log4cpp) +find_library(LOG4CPP_LIBRARY + NAMES ${LOG4CPP_NAMES} + HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib + ${PC_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib/ + PATHS /usr/local/lib + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/i386-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/alpha-linux-gnu + /usr/lib64 + /usr/lib + /usr/local/lib + /opt/local/lib + ${LOG4CPP_ROOT}/lib + $ENV{LOG4CPP_ROOT}/lib + ${LOG4CPP_ROOT}/lib64 + $ENV{LOG4CPP_ROOT}/lib64 +) + +if(LOG4CPP_INCLUDE_DIR AND LOG4CPP_LIBRARY) + set(LOG4CPP_FOUND TRUE) + set(LOG4CPP_LIBRARIES ${LOG4CPP_LIBRARY} CACHE INTERNAL "" FORCE) + set(LOG4CPP_INCLUDE_DIRS ${LOG4CPP_INCLUDE_DIR} CACHE INTERNAL "" FORCE) +else() + set(LOG4CPP_FOUND FALSE CACHE INTERNAL "" FORCE) + set(LOG4CPP_LIBRARY "" CACHE INTERNAL "" FORCE) + set(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE) + set(LOG4CPP_INCLUDE_DIR "" CACHE INTERNAL "" FORCE) + set(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LOG4CPP DEFAULT_MSG LOG4CPP_INCLUDE_DIRS LOG4CPP_LIBRARIES) diff --git a/cmake/Modules/FindLibOsmoSDR.cmake b/cmake/Modules/FindLibOsmoSDR.cmake deleted file mode 100644 index d024e0629..000000000 --- a/cmake/Modules/FindLibOsmoSDR.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# Tries to find libosmosdr. -# -# Usage of this module as follows: -# -# find_package(LibOsmoSDR) -# -# -# Variables defined by this module: -# -# LIBOSMOSDR_FOUND System has libosmosdr libs/headers -# LIBOSMOSDR_LIBRARIES The libosmosdr libraries -# LIBOSMOSDR_INCLUDE_DIR The location of libosmosdr headers - - -if(NOT LIBOSMOSDR_FOUND) - pkg_check_modules (LIBOSMOSDR_PKG libosmosdr) - find_path(LIBOSMOSDR_INCLUDE_DIR NAMES osmosdr.h - PATHS - ${LIBOSMOSDR_PKG_INCLUDE_DIRS} - /usr/include - /usr/local/include - ) - - find_library(LIBOSMOSDR_LIBRARIES NAMES osmosdr - PATHS - ${LIBOSMOSDR_PKG_LIBRARY_DIRS} - /usr/lib - /usr/local/lib - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib64 - ) - - if(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES) - set(LIBOSMOSDR_FOUND TRUE CACHE INTERNAL "libosmosdr found") - message(STATUS "Found libosmosdr: ${LIBOSMOSDR_INCLUDE_DIR}, ${LIBOSMOSDR_LIBRARIES}") - else(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES) - set(LIBOSMOSDR_FOUND FALSE CACHE INTERNAL "libosmosdr found") - message(STATUS "libosmosdr not found.") - endif(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES) - -mark_as_advanced(LIBOSMOSDR_INCLUDE_DIR LIBOSMOSDR_LIBRARIES) - -endif(NOT LIBOSMOSDR_FOUND) diff --git a/cmake/Modules/FindMATIO.cmake b/cmake/Modules/FindMATIO.cmake new file mode 100644 index 000000000..08facf069 --- /dev/null +++ b/cmake/Modules/FindMATIO.cmake @@ -0,0 +1,129 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +# FindMATIO +# +# Try to find MATIO library +# +# Once done this will define: +# +# MATIO_FOUND - True if MATIO found. +# MATIO_LIBRARIES - MATIO libraries. +# MATIO_INCLUDE_DIRS - where to find matio.h, etc.. +# MATIO_VERSION_STRING - version number as a string (e.g.: "1.3.4") +# +#============================================================================= +# Copyright 2015 Avtech Scientific +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= +# + +# Look for the header file. +find_path(MATIO_INCLUDE_DIR + NAMES matio.h + HINTS + ${MATIO_ROOT}/include + $ENV{MATIO_ROOT}/include + DOC "The MATIO include directory" +) + +# Look for the library. +find_library(MATIO_LIBRARY + NAMES matio + HINTS + ${MATIO_ROOT}/lib + $ENV{MATIO_ROOT}/lib + ${MATIO_ROOT}/lib64 + $ENV{MATIO_ROOT}/lib64 + DOC "The MATIO library" +) + +if(MATIO_INCLUDE_DIR) + # --------------------------------------------------- + # Extract version information from MATIO + # --------------------------------------------------- + + # If the file is missing, set all values to 0 + set(MATIO_MAJOR_VERSION 0) + set(MATIO_MINOR_VERSION 0) + set(MATIO_RELEASE_LEVEL 0) + + # new versions of MATIO have `matio_pubconf.h` + if(EXISTS ${MATIO_INCLUDE_DIR}/matio_pubconf.h) + set(MATIO_CONFIG_FILE "matio_pubconf.h") + else() + set(MATIO_CONFIG_FILE "matioConfig.h") + endif() + + if(MATIO_CONFIG_FILE) + + # Read and parse MATIO config header file for version number + file(STRINGS "${MATIO_INCLUDE_DIR}/${MATIO_CONFIG_FILE}" _matio_HEADER_CONTENTS REGEX "#define MATIO_((MAJOR|MINOR)_VERSION)|(RELEASE_LEVEL) ") + + foreach(line ${_matio_HEADER_CONTENTS}) + if(line MATCHES "#define ([A-Z_]+) ([0-9]+)") + set("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") + endif() + endforeach() + + unset(_matio_HEADER_CONTENTS) + endif() + + set(MATIO_VERSION_STRING "${MATIO_MAJOR_VERSION}.${MATIO_MINOR_VERSION}.${MATIO_RELEASE_LEVEL}") +endif() + +mark_as_advanced(MATIO_INCLUDE_DIR MATIO_LIBRARY) + +# handle the QUIETLY and REQUIRED arguments and set MATIO_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MATIO REQUIRED_VARS MATIO_LIBRARY MATIO_INCLUDE_DIR VERSION_VAR MATIO_VERSION_STRING) + +if(MATIO_FOUND) + set(MATIO_LIBRARIES ${MATIO_LIBRARY}) + set(MATIO_INCLUDE_DIRS ${MATIO_INCLUDE_DIR}) +else() + set(MATIO_LIBRARIES) + set(MATIO_INCLUDE_DIRS) +endif() diff --git a/cmake/Modules/FindORC.cmake b/cmake/Modules/FindORC.cmake index 9d0da9ee2..fea12b98f 100644 --- a/cmake/Modules/FindORC.cmake +++ b/cmake/Modules/FindORC.cmake @@ -1,49 +1,75 @@ -FIND_PACKAGE(PkgConfig) -PKG_CHECK_MODULES(PC_ORC "orc-0.4 > 0.4.22") +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . -FIND_PROGRAM(ORCC_EXECUTABLE orcc - HINTS ${PC_ORC_TOOLSDIR} - PATHS ${ORC_ROOT}/bin ${CMAKE_INSTALL_PREFIX}/bin) +find_package(PkgConfig) +pkg_check_modules(PC_ORC "orc-0.4 > 0.4.22") -FIND_PATH(ORC_INCLUDE_DIR NAMES orc/orc.h - HINTS ${PC_ORC_INCLUDEDIR} - PATHS ${ORC_ROOT}/include/orc-0.4 ${CMAKE_INSTALL_PREFIX}/include/orc-0.4) - - -FIND_PATH(ORC_LIBRARY_DIR NAMES ${CMAKE_SHARED_LIBRARY_PREFIX}orc-0.4${CMAKE_SHARED_LIBRARY_SUFFIX} - HINTS ${PC_ORC_LIBDIR} - /usr/local/lib - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib64 - /usr/lib - PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - -FIND_LIBRARY(ORC_LIB orc-0.4 - HINTS ${PC_ORC_LIBRARY_DIRS} - PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - -LIST(APPEND ORC_LIBRARY - ${ORC_LIB} +find_program(ORCC_EXECUTABLE orcc + HINTS ${PC_ORC_TOOLSDIR} + PATHS ${ORC_ROOT}/bin + ${CMAKE_INSTALL_PREFIX}/bin ) +find_path(ORC_INCLUDE_DIR + NAMES orc/orc.h + HINTS ${PC_ORC_INCLUDEDIR} + PATHS ${ORC_ROOT}/include/orc-0.4 + ${CMAKE_INSTALL_PREFIX}/include/orc-0.4 +) -SET(ORC_INCLUDE_DIRS ${ORC_INCLUDE_DIR}) -SET(ORC_LIBRARIES ${ORC_LIBRARY}) -SET(ORC_LIBRARY_DIRS ${ORC_LIBRARY_DIR}) +find_path(ORC_LIBRARY_DIR + NAMES ${CMAKE_SHARED_LIBRARY_PREFIX}orc-0.4${CMAKE_SHARED_LIBRARY_SUFFIX} + HINTS ${PC_ORC_LIBDIR} + /usr/local/lib + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib64 + /usr/lib + ${ORC_ROOT}/lib + $ENV{ORC_ROOT}/lib + PATHS + ${ORC_ROOT}/lib${LIB_SUFFIX} + ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} +) -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(ORC "orc files" ORC_LIBRARY ORC_INCLUDE_DIR ORCC_EXECUTABLE) +find_library(ORC_LIB orc-0.4 + HINTS ${PC_ORC_LIBRARY_DIRS} + PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} + ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} +) -mark_as_advanced(ORC_INCLUDE_DIR ORC_LIBRARY ORCC_EXECUTABLE) \ No newline at end of file +list(APPEND ORC_LIBRARY ${ORC_LIB}) + +set(ORC_INCLUDE_DIRS ${ORC_INCLUDE_DIR}) +set(ORC_LIBRARIES ${ORC_LIBRARY}) +set(ORC_LIBRARY_DIRS ${ORC_LIBRARY_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ORC "orc files" ORC_LIBRARY ORC_INCLUDE_DIR ORCC_EXECUTABLE) + +mark_as_advanced(ORC_INCLUDE_DIR ORC_LIBRARY ORCC_EXECUTABLE) diff --git a/cmake/Modules/FindOpenBLAS.cmake b/cmake/Modules/FindOpenBLAS.cmake deleted file mode 100644 index d8751b216..000000000 --- a/cmake/Modules/FindOpenBLAS.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# - Try to find OpenBLAS library (not headers!) -# -# The following environment variable is optionally searched -# OPENBLAS_HOME: Base directory where all OpenBlas components are found - -SET(OPEN_BLAS_SEARCH_PATHS /lib/ - /lib64/ - /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib64 - /opt/OpenBLAS/lib - /opt/local/lib - /usr/lib/openblas-base - $ENV{OPENBLAS_HOME}/lib - ) - -FIND_LIBRARY(OPENBLAS NAMES openblas PATHS ${OPEN_BLAS_SEARCH_PATHS}) - -IF (OPENBLAS) - SET(OPENBLAS_FOUND ON) - MESSAGE(STATUS "Found OpenBLAS") -ENDIF (OPENBLAS) - -MARK_AS_ADVANCED(OPENBLAS) diff --git a/cmake/Modules/FindOpenCL.cmake b/cmake/Modules/FindOpenCL.cmake deleted file mode 100644 index 1229090a9..000000000 --- a/cmake/Modules/FindOpenCL.cmake +++ /dev/null @@ -1,99 +0,0 @@ -# -# This file taken from FindOpenCL project @ http://gitorious.com/findopencl -# -# - Try to find OpenCL -# This module tries to find an OpenCL implementation on your system. It supports -# AMD / ATI, Apple and NVIDIA implementations, but shoudl work, too. -# -# Once done this will define -# OPENCL_FOUND - system has OpenCL -# OPENCL_INCLUDE_DIRS - the OpenCL include directory -# OPENCL_LIBRARIES - link these to use OpenCL -# -# WIN32 should work, but is untested - -FIND_PACKAGE( PackageHandleStandardArgs ) - -SET (OPENCL_VERSION_STRING "0.1.0") -SET (OPENCL_VERSION_MAJOR 0) -SET (OPENCL_VERSION_MINOR 1) -SET (OPENCL_VERSION_PATCH 0) - -IF (APPLE) - - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") - FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") - -ELSE (APPLE) - - IF (WIN32) - - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h) - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp) - - # The AMD SDK currently installs both x86 and x86_64 libraries - # This is only a hack to find out architecture - IF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) - SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86_64") - SET(OPENCL_LIB_DIR "$ENV{ATIINTERNALSTREAMSDKROOT}/lib/x86_64") - ELSE (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") - SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86") - SET(OPENCL_LIB_DIR "$ENV{ATIINTERNALSTREAMSDKROOT}/lib/x86") - ENDIF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) - - # find out if the user asked for a 64-bit build, and use the corresponding - # 64 or 32 bit NVIDIA library paths to the search: - STRING(REGEX MATCH "Win64" ISWIN64 ${CMAKE_GENERATOR}) - IF("${ISWIN64}" STREQUAL "Win64") - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/x64) - ELSE("${ISWIN64}" STREQUAL "Win64") - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/Win32) - ENDIF("${ISWIN64}" STREQUAL "Win64") - - GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) - - # On Win32 search relative to the library - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) - - ELSE (WIN32) - - # Unix style platforms - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL - ENV LD_LIBRARY_PATH - ) - - GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH) - GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) - - # The AMD SDK currently does not place its headers - # in /usr/include, therefore also search relative - # to the library - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") - - ENDIF (WIN32) - -ENDIF (APPLE) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS ) - -IF( _OPENCL_CPP_INCLUDE_DIRS ) - SET( OPENCL_HAS_CPP_BINDINGS TRUE ) - LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} ) - # This is often the same, so clean up - LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS ) -ENDIF( _OPENCL_CPP_INCLUDE_DIRS ) - -MARK_AS_ADVANCED( - OPENCL_INCLUDE_DIRS -) - -IF( OPENCL_INCLUDE_DIRS AND OPENCL_LIBRARIES ) - SET( OPENCL_FOUND TRUE ) - add_definitions( -DOPENCL=1 ) -ELSE( OPENCL_INCLUDE_DIRS AND OPENCL_LIBRARIES ) - SET( OPENCL_FOUND FALSE ) - add_definitions( -DOPENCL=0 ) -ENDIF( OPENCL_INCLUDE_DIRS AND OPENCL_LIBRARIES ) diff --git a/cmake/Modules/FindPCAP.cmake b/cmake/Modules/FindPCAP.cmake new file mode 100644 index 000000000..af746c852 --- /dev/null +++ b/cmake/Modules/FindPCAP.cmake @@ -0,0 +1,122 @@ +################################################################### +# +# Copyright (c) 2006 Frederic Heem, +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the Telsey nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +################################################################### +# - Find pcap +# Find the PCAP includes and library +# http://www.tcpdump.org/ +# +# The environment variable PCAPDIR allows to specficy where to find +# libpcap in non standard location. +# +# PCAP_INCLUDE_DIRS - where to find pcap.h, etc. +# PCAP_LIBRARIES - List of libraries when using pcap. +# PCAP_FOUND - True if pcap found. + + +if(EXISTS $ENV{PCAPDIR}) + find_path(PCAP_INCLUDE_DIR + NAMES + pcap/pcap.h + pcap.h + PATHS + $ENV{PCAPDIR} + ${PCAP_ROOT}/include + $ENV{PCAP_ROOT}/include + NO_DEFAULT_PATH + ) + find_library(PCAP_LIBRARY + NAMES + pcap + PATHS + $ENV{PCAPDIR} + ${PCAP_ROOT}/lib + $ENV{PCAP_ROOT}/lib + NO_DEFAULT_PATH + ) +else() + find_path(PCAP_INCLUDE_DIR + NAMES + pcap/pcap.h + pcap.h + HINTS + ${PCAP_ROOT}/include + $ENV{PCAP_ROOT}/include + ) + find_library(PCAP_LIBRARY + NAMES + pcap + HINTS + ${PCAP_ROOT}/lib + $ENV{PCAP_ROOT}/lib + ) +endif() + +set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) +set(PCAP_LIBRARIES ${PCAP_LIBRARY}) + +if(PCAP_INCLUDE_DIRS) + message(STATUS "Pcap include dirs set to ${PCAP_INCLUDE_DIRS}") +else() + message(FATAL " Pcap include dirs cannot be found") +endif() + +if(PCAP_LIBRARIES) + message(STATUS "Pcap library set to ${PCAP_LIBRARIES}") +else() + message(FATAL "Pcap library cannot be found") +endif() + +#Functions +include(CheckFunctionExists) +set(CMAKE_REQUIRED_INCLUDES ${PCAP_INCLUDE_DIRS}) +set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARIES}) +check_function_exists("pcap_breakloop" HAVE_PCAP_BREAKLOOP) +check_function_exists("pcap_datalink_name_to_val" HAVE_PCAP_DATALINK_NAME_TO_VAL) +check_function_exists("pcap_datalink_val_to_name" HAVE_PCAP_DATALINK_VAL_TO_NAME) +check_function_exists("pcap_findalldevs" HAVE_PCAP_FINDALLDEVS) +check_function_exists("pcap_freecode" HAVE_PCAP_FREECODE) +check_function_exists("pcap_get_selectable_fd" HAVE_PCAP_GET_SELECTABLE_FD) +check_function_exists("pcap_lib_version" HAVE_PCAP_LIB_VERSION) +check_function_exists("pcap_list_datalinks" HAVE_PCAP_LIST_DATALINKS) +check_function_exists("pcap_open_dead" HAVE_PCAP_OPEN_DEAD) +check_function_exists("pcap_set_datalink" HAVE_PCAP_SET_DATALINK) + +mark_as_advanced( + PCAP_LIBRARIES + PCAP_INCLUDE_DIRS +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PCAP DEFAULT_MSG PCAP_INCLUDE_DIRS PCAP_LIBRARIES) diff --git a/cmake/Modules/FindPUGIXML.cmake b/cmake/Modules/FindPUGIXML.cmake new file mode 100644 index 000000000..236a4c95a --- /dev/null +++ b/cmake/Modules/FindPUGIXML.cmake @@ -0,0 +1,75 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +# Find the pugixml XML parsing library. +# +# Sets the usual variables expected for find_package scripts: +# +# PUGIXML_INCLUDE_DIR - header location +# PUGIXML_LIBRARIES - library to link against +# PUGIXML_FOUND - true if pugixml was found. + +find_path(PUGIXML_INCLUDE_DIR + NAMES pugixml.hpp + PATHS ${PUGIXML_HOME}/include + /usr/include + /usr/local/include + /opt/local/include + ${PUGIXML_ROOT}/include + $ENV{PUGIXML_ROOT}/include +) + +find_library(PUGIXML_LIBRARY + NAMES pugixml + PATHS ${PUGIXML_HOME}/lib + /usr/lib/x86_64-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/i386-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/local/lib + /opt/local/lib + /usr/lib + /usr/lib64 + /usr/local/lib64 + ${PUGIXML_ROOT}/lib + $ENV{PUGIXML_ROOT}/lib + ${PUGIXML_ROOT}/lib64 + $ENV{PUGIXML_ROOT}/lib64 +) + +# Support the REQUIRED and QUIET arguments, and set PUGIXML_FOUND if found. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PUGIXML DEFAULT_MSG PUGIXML_LIBRARY + PUGIXML_INCLUDE_DIR) + +if(PUGIXML_FOUND) + set(PUGIXML_LIBRARIES ${PUGIXML_LIBRARY}) + if(NOT PUGIXML_FIND_QUIETLY) + message(STATUS "PugiXML include = ${PUGIXML_INCLUDE_DIR}") + message(STATUS "PugiXML library = ${PUGIXML_LIBRARY}") + endif() +else() + message(STATUS "PugiXML not found.") +endif() + +mark_as_advanced(PUGIXML_LIBRARY PUGIXML_INCLUDE_DIR) diff --git a/cmake/Modules/FindTeleorbit.cmake b/cmake/Modules/FindTeleorbit.cmake deleted file mode 100644 index 0d2d3c505..000000000 --- a/cmake/Modules/FindTeleorbit.cmake +++ /dev/null @@ -1,29 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_TELEORBIT teleorbit) - -FIND_PATH( - TELEORBIT_INCLUDE_DIRS - NAMES teleorbit/api.h - HINTS $ENV{TELEORBIT_DIR}/include - ${PC_TELEORBIT_INCLUDEDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/include - /usr/local/include - /usr/include -) - -FIND_LIBRARY( - TELEORBIT_LIBRARIES - NAMES gnuradio-teleorbit - HINTS $ENV{TELEORBIT_DIR}/lib - ${PC_TELEORBIT_LIBDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(TELEORBIT DEFAULT_MSG TELEORBIT_LIBRARIES TELEORBIT_INCLUDE_DIRS) -MARK_AS_ADVANCED(TELEORBIT_LIBRARIES TELEORBIT_INCLUDE_DIRS) diff --git a/cmake/Modules/FindUHD.cmake b/cmake/Modules/FindUHD.cmake index 3534e6b87..31d299937 100644 --- a/cmake/Modules/FindUHD.cmake +++ b/cmake/Modules/FindUHD.cmake @@ -1,25 +1,42 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ######################################################################## # Find the library for the USRP Hardware Driver ######################################################################## -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_UHD uhd) +include(FindPkgConfig) +pkg_check_modules(PC_UHD uhd) -FIND_PATH( - UHD_INCLUDE_DIRS +find_path(UHD_INCLUDE_DIRS NAMES uhd/config.hpp HINTS $ENV{UHD_DIR}/include - ${PC_UHD_INCLUDEDIR} + ${PC_UHD_INCLUDEDIR} PATHS /usr/local/include /usr/include ${GNURADIO_INSTALL_PREFIX}/include + ${UHD_ROOT}/include + $ENV{UHD_ROOT}/include ) -FIND_LIBRARY( - UHD_LIBRARIES +find_library(UHD_LIBRARIES NAMES uhd HINTS $ENV{UHD_DIR}/lib - ${PC_UHD_LIBDIR} + ${PC_UHD_LIBDIR} PATHS /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu @@ -47,8 +64,12 @@ FIND_LIBRARY( /usr/lib64 /usr/lib ${GNURADIO_INSTALL_PREFIX}/lib + ${UHD_ROOT}/lib + $ENV{UHD_ROOT}/lib + ${UHD_ROOT}/lib64 + $ENV{UHD_ROOT}/lib64 ) -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(UHD DEFAULT_MSG UHD_LIBRARIES UHD_INCLUDE_DIRS) -MARK_AS_ADVANCED(UHD_LIBRARIES UHD_INCLUDE_DIRS) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(UHD DEFAULT_MSG UHD_LIBRARIES UHD_INCLUDE_DIRS) +mark_as_advanced(UHD_LIBRARIES UHD_INCLUDE_DIRS) diff --git a/cmake/Modules/FindVolk.cmake b/cmake/Modules/FindVOLK.cmake similarity index 54% rename from cmake/Modules/FindVolk.cmake rename to cmake/Modules/FindVOLK.cmake index 9621e16f7..97191179c 100644 --- a/cmake/Modules/FindVolk.cmake +++ b/cmake/Modules/FindVOLK.cmake @@ -1,22 +1,39 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ######################################################################## # Find VOLK (Vector-Optimized Library of Kernels) ######################################################################## -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_VOLK volk) +include(FindPkgConfig) +pkg_check_modules(PC_VOLK volk) -FIND_PATH( - VOLK_INCLUDE_DIRS +find_path(VOLK_INCLUDE_DIRS NAMES volk/volk.h HINTS $ENV{VOLK_DIR}/include ${PC_VOLK_INCLUDEDIR} PATHS /usr/local/include /usr/include ${CMAKE_INSTALL_PREFIX}/include + ${VOLK_ROOT}/include + $ENV{VOLK_ROOT}/include ) -FIND_LIBRARY( - VOLK_LIBRARIES +find_library(VOLK_LIBRARIES NAMES volk HINTS $ENV{VOLK_DIR}/lib ${PC_VOLK_LIBDIR} @@ -48,9 +65,12 @@ FIND_LIBRARY( /usr/lib/alpha-linux-gnu /usr/lib64 ${CMAKE_INSTALL_PREFIX}/lib + ${VOLK_ROOT}/lib + $ENV{VOLK_ROOT}/lib + ${VOLK_ROOT}/lib64 + $ENV{VOLK_ROOT}/lib64 ) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) -MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_VERSION) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) +mark_as_advanced(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_VERSION) diff --git a/cmake/Modules/FindVolkGnssSdr.cmake b/cmake/Modules/FindVolkGnssSdr.cmake deleted file mode 100644 index b5890966b..000000000 --- a/cmake/Modules/FindVolkGnssSdr.cmake +++ /dev/null @@ -1,32 +0,0 @@ -######################################################################## -# Find VOLK (Vector-Optimized Library of Kernels) GNSS-SDR library -######################################################################## - -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_VOLK_GNSSSDR volk_gnsssdr) - -FIND_PATH( - VOLK_GNSSSDR_INCLUDE_DIRS - NAMES volk_gnsssdr/volk_gnsssdr.h - HINTS $ENV{VOLK_GNSSSDR_DIR}/include - ${PC_VOLK_GNSSSDR_INCLUDEDIR} - PATHS /usr/local/include - /usr/include - ${GNURADIO_INSTALL_PREFIX}/include -) - -FIND_LIBRARY( - VOLK_GNSSSDR_LIBRARIES - NAMES volk_gnsssdr - HINTS $ENV{VOLK_GNSSSDR_DIR}/lib - ${PC_VOLK_GNSSSDR_LIBDIR} - PATHS /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 - ${GNURADIO_INSTALL_PREFIX}/lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK_GNSSSDR DEFAULT_MSG VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) -MARK_AS_ADVANCED(VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) \ No newline at end of file diff --git a/cmake/Modules/GnsssdrBuildTypes.cmake b/cmake/Modules/GnsssdrBuildTypes.cmake new file mode 100644 index 000000000..a80cd0c6b --- /dev/null +++ b/cmake/Modules/GnsssdrBuildTypes.cmake @@ -0,0 +1,219 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +if(DEFINED __INCLUDED_GNSSSDR_BUILD_TYPES_CMAKE) + return() +endif() +set(__INCLUDED_GNSSSDR_BUILD_TYPES_CMAKE TRUE) + +# Standard CMake Build Types and their basic CFLAGS: +# - None: nothing set +# - Debug: -O2 -g +# - Release: -O3 +# - RelWithDebInfo: -O3 -g +# - MinSizeRel: -Os + +# Additional Build Types, defined below: +# - NoOptWithASM: -O0 -g -save-temps +# - O2WithASM: -O2 -g -save-temps +# - O3WithASM: -O3 -g -save-temps + +# Defines the list of acceptable cmake build types. When adding a new +# build type below, make sure to add it to this list. +list(APPEND AVAIL_BUILDTYPES + None Debug Release RelWithDebInfo MinSizeRel + Coverage NoOptWithASM O2WithASM O3WithASM ASAN +) + +######################################################################## +# GNSSSDR_CHECK_BUILD_TYPE(build type) +# +# Use this to check that the build type set in CMAKE_BUILD_TYPE on the +# commandline is one of the valid build types used by this project. It +# checks the value set in the cmake interface against the list of +# known build types in AVAIL_BUILDTYPES. If the build type is found, +# the function exits immediately. If nothing is found by the end of +# checking all available build types, we exit with an error and list +# the avialable build types. +######################################################################## +function(GNSSSDR_CHECK_BUILD_TYPE settype) + string(TOUPPER ${settype} _settype) + foreach(btype ${AVAIL_BUILDTYPES}) + string(TOUPPER ${btype} _btype) + if(${_settype} STREQUAL ${_btype}) + return() # found it; exit cleanly + endif() + endforeach() + # Build type not found; error out + message(FATAL_ERROR "Build type '${settype}' not valid, must be one of: ${AVAIL_BUILDTYPES}") +endfunction() + + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=Coverage +# +# This type uses no optimization (-O0), outputs debug symbols (-g) and +# outputs all intermediary files the build system produces, including +# all assembly (.s) files. Look in the build directory for these +# files. +# NOTE: This is not defined on Windows systems. +######################################################################## +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_COVERAGE "-Wall -pedantic -pthread -g -O0 -fprofile-arcs -ftest-coverage" CACHE STRING + "Flags used by the C++ compiler during Coverage builds." FORCE) + set(CMAKE_C_FLAGS_COVERAGE "-Wall -pedantic -pthread -g -O0 -fprofile-arcs -ftest-coverage" CACHE STRING + "Flags used by the C compiler during Coverage builds." FORCE) + set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "-W" CACHE STRING + "Flags used for linking binaries during Coverage builds." FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "-W" CACHE STRING + "Flags used by the shared lib linker during Coverage builds." FORCE) + + mark_as_advanced( + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE) +endif() + + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=NoOptWithASM +# +# This type uses no optimization (-O0), outputs debug symbols (-g) and +# outputs all intermediary files the build system produces, including +# all assembly (.s) files. Look in the build directory for these +# files. +# NOTE: This is not defined on Windows systems. +######################################################################## +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_NOOPTWITHASM "-Wall -save-temps -g -O0" CACHE STRING + "Flags used by the C++ compiler during NoOptWithASM builds." FORCE) + set(CMAKE_C_FLAGS_NOOPTWITHASM "-Wall -save-temps -g -O0" CACHE STRING + "Flags used by the C compiler during NoOptWithASM builds." FORCE) + set(CMAKE_EXE_LINKER_FLAGS_NOOPTWITHASM + "-W" CACHE STRING + "Flags used for linking binaries during NoOptWithASM builds." FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_NOOPTWITHASM + "-W" CACHE STRING + "Flags used by the shared lib linker during NoOptWithASM builds." FORCE) + + mark_as_advanced( + CMAKE_CXX_FLAGS_NOOPTWITHASM + CMAKE_C_FLAGS_NOOPTWITHASM + CMAKE_EXE_LINKER_FLAGS_NOOPTWITHASM + CMAKE_SHARED_LINKER_FLAGS_NOOPTWITHASM) +endif() + + + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=O2WithASM +# +# This type uses level 2 optimization (-O2), outputs debug symbols +# (-g) and outputs all intermediary files the build system produces, +# including all assembly (.s) files. Look in the build directory for +# these files. +# NOTE: This is not defined on Windows systems. +######################################################################## + +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_O2WITHASM "-Wall -save-temps -g -O2" CACHE STRING + "Flags used by the C++ compiler during O2WithASM builds." FORCE) + set(CMAKE_C_FLAGS_O2WITHASM "-Wall -save-temps -g -O2" CACHE STRING + "Flags used by the C compiler during O2WithASM builds." FORCE) + set(CMAKE_EXE_LINKER_FLAGS_O2WITHASM + "-W" CACHE STRING + "Flags used for linking binaries during O2WithASM builds." FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_O2WITHASM + "-W" CACHE STRING + "Flags used by the shared lib linker during O2WithASM builds." FORCE) + + mark_as_advanced( + CMAKE_CXX_FLAGS_O2WITHASM + CMAKE_C_FLAGS_O2WITHASM + CMAKE_EXE_LINKER_FLAGS_O2WITHASM + CMAKE_SHARED_LINKER_FLAGS_O2WITHASM) +endif() + + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=O3WithASM +# +# This type uses level 3 optimization (-O3), outputs debug symbols +# (-g) and outputs all intermediary files the build system produces, +# including all assembly (.s) files. Look in the build directory for +# these files. +# NOTE: This is not defined on Windows systems. +######################################################################## + +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_O3WITHASM "-Wall -save-temps -g -O3" CACHE STRING + "Flags used by the C++ compiler during O3WithASM builds." FORCE) + set(CMAKE_C_FLAGS_O3WITHASM "-Wall -save-temps -g -O3" CACHE STRING + "Flags used by the C compiler during O3WithASM builds." FORCE) + set(CMAKE_EXE_LINKER_FLAGS_O3WITHASM + "-W" CACHE STRING + "Flags used for linking binaries during O3WithASM builds." FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_O3WITHASM + "-W" CACHE STRING + "Flags used by the shared lib linker during O3WithASM builds." FORCE) + + mark_as_advanced( + CMAKE_CXX_FLAGS_O3WITHASM + CMAKE_C_FLAGS_O3WITHASM + CMAKE_EXE_LINKER_FLAGS_O3WITHASM + CMAKE_SHARED_LINKER_FLAGS_O3WITHASM) +endif() + + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=ASAN +# +# This type creates an address sanitized build (-fsanitize=address) +# and defaults to the DebugParanoid linker flags. +# NOTE: This is not defined on Windows systems. +######################################################################## +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_ASAN "-Wall -Wextra -g -O2 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING + "Flags used by the C++ compiler during Address Sanitized builds." FORCE) + set(CMAKE_C_FLAGS_ASAN "-Wall -Wextra -g -O2 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING + "Flags used by the C compiler during Address Sanitized builds." FORCE) + set(CMAKE_EXE_LINKER_FLAGS_ASAN + "-W" CACHE STRING + "Flags used for linking binaries during Address Sanitized builds." FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_ASAN + "-W" CACHE STRING + "Flags used by the shared lib linker during Address Sanitized builds." FORCE) + + mark_as_advanced( + CMAKE_CXX_FLAGS_ASAN + CMAKE_C_FLAGS_ASAN + CMAKE_EXE_LINKER_FLAGS_ASAN + CMAKE_SHARED_LINKER_ASAN) +endif() diff --git a/cmake/Modules/SetupPython.cmake b/cmake/Modules/SetupPython.cmake index d3c2b3a12..f3d59c900 100644 --- a/cmake/Modules/SetupPython.cmake +++ b/cmake/Modules/SetupPython.cmake @@ -1,51 +1,20 @@ -######################################################################## -# Setup the python interpreter: -# This allows the user to specify a specific interpreter, -# or finds the interpreter via the built-in cmake module. -######################################################################## -#this allows the user to override PYTHON_EXECUTABLE -if(PYTHON_EXECUTABLE) +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . - set(PYTHONINTERP_FOUND TRUE) - -#otherwise if not set, try to automatically find it -else(PYTHON_EXECUTABLE) - - #use the built-in find script - set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6) - find_package(PythonInterp 2) - - #and if that fails use the find program routine - if(NOT PYTHONINTERP_FOUND) - find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python3) - if(PYTHON_EXECUTABLE) - set(PYTHONINTERP_FOUND TRUE) - endif(PYTHON_EXECUTABLE) - endif(NOT PYTHONINTERP_FOUND) - -endif(PYTHON_EXECUTABLE) - -if (CMAKE_CROSSCOMPILING) - set(QA_PYTHON_EXECUTABLE "/usr/bin/python") -else (CMAKE_CROSSCOMPILING) - set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) -endif(CMAKE_CROSSCOMPILING) - -#make the path to the executable appear in the cmake gui -set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") -set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests") - -#make sure we can use -B with python (introduced in 2.6) -if(PYTHON_EXECUTABLE) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -B -c "" - OUTPUT_QUIET ERROR_QUIET - RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT - ) - if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) - set(PYTHON_DASH_B "-B") - endif() -endif(PYTHON_EXECUTABLE) ######################################################################## # Check for the existence of a python module: @@ -54,25 +23,97 @@ endif(PYTHON_EXECUTABLE) # - cmd an additional command to run # - have the result variable to set ######################################################################## -macro(GNSSSDR_PYTHON_CHECK_MODULE desc mod cmd have) - message(STATUS "Python checking for ${desc}") +macro(GNSSSDR_PYTHON_CHECK_MODULE_RAW desc python_code have) execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c " -######################################### -try: import ${mod} -except: - try: ${mod} - except: exit(-1) -try: assert ${cmd} -except: exit(-1) -#########################################" - RESULT_VARIABLE ${have} + COMMAND ${PYTHON_EXECUTABLE} -c "${python_code}" + OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE return_code ) - if(${have} EQUAL 0) + if(return_code EQUAL 0) message(STATUS "Python checking for ${desc} - found") set(${have} TRUE) - else(${have} EQUAL 0) + else() message(STATUS "Python checking for ${desc} - not found") set(${have} FALSE) - endif(${have} EQUAL 0) -endmacro(GNSSSDR_PYTHON_CHECK_MODULE) + endif() +endmacro() + +macro(GNSSSDR_PYTHON_CHECK_MODULE desc mod cmd have) + gnsssdr_python_check_module_raw( + "${desc}" " +######################################### +try: + import ${mod} + assert ${cmd} +except (ImportError, AssertionError): exit(-1) +except: pass +#########################################" + "${have}") +endmacro() + + +######################################################################## +# Setup the python interpreter: +# This allows the user to specify a specific interpreter, +# or finds the interpreter via the built-in cmake module. +######################################################################## + +if(CMAKE_VERSION VERSION_LESS 3.12) + if(PYTHON_EXECUTABLE) + message(STATUS "User set python executable ${PYTHON_EXECUTABLE}") + string(FIND "${PYTHON_EXECUTABLE}" "python3" IS_PYTHON3) + if(IS_PYTHON3 EQUAL -1) + find_package(PythonInterp ${GNSSSDR_PYTHON_MIN_VERSION} REQUIRED) + else() + find_package(PythonInterp ${GNSSSDR_PYTHON3_MIN_VERSION} REQUIRED) + endif() + gnsssdr_python_check_module("python >= ${GNSSSDR_PYTHON_MIN_VERSION}" sys "sys.version.split()[0] >= '${GNSSSDR_PYTHON_MIN_VERSION}'" PYTHON_MIN_VER_FOUND) + gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND) + gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + else() + message(STATUS "PYTHON_EXECUTABLE not set - trying by default python2") + message(STATUS "Use -DPYTHON_EXECUTABLE=/path/to/python3 to build for python3.") + find_package(PythonInterp ${GNSSSDR_PYTHON_MIN_VERSION}) + if(NOT PYTHONINTERP_FOUND) + message(STATUS "python2 not found - trying with python3") + find_package(PythonInterp ${GNSSSDR_PYTHON3_MIN_VERSION} REQUIRED) + endif() + gnsssdr_python_check_module("python >= ${GNSSSDR_PYTHON_MIN_VERSION}" sys "sys.version.split()[0] >= '${GNSSSDR_PYTHON_MIN_VERSION}'" PYTHON_MIN_VER_FOUND) + gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND) + gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + endif() + find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT) +else() + find_package(Python3 COMPONENTS Interpreter) + if(Python3_FOUND) + set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + set(PYTHON_VERSION_MAJOR ${Python3_VERSION_MAJOR}) + gnsssdr_python_check_module("python >= ${GNSSSDR_PYTHON_MIN_VERSION}" sys "sys.version.split()[0] >= '${GNSSSDR_PYTHON_MIN_VERSION}'" PYTHON_MIN_VER_FOUND) + gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND) + gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + endif() + if(NOT Python3_FOUND OR NOT MAKO_FOUND OR NOT SIX_FOUND) + find_package(Python2 COMPONENTS Interpreter) + if(Python2_FOUND) + set(PYTHON_EXECUTABLE ${Python2_EXECUTABLE}) + set(PYTHON_VERSION_MAJOR ${Python2_VERSION_MAJOR}) + gnsssdr_python_check_module("python >= ${GNSSSDR_PYTHON_MIN_VERSION}" sys "sys.version.split()[0] >= '${GNSSSDR_PYTHON_MIN_VERSION}'" PYTHON_MIN_VER_FOUND) + gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND) + gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + endif() + endif() +endif() + +if(${PYTHON_VERSION_MAJOR} VERSION_EQUAL 3) + set(PYTHON3 TRUE) +endif() + +if(CMAKE_CROSSCOMPILING) + set(QA_PYTHON_EXECUTABLE "/usr/bin/python") +else() + set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) +endif() + +# make the path to the executable appear in the cmake gui +set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") +set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests") diff --git a/cmake/Modules/TestForARM.cmake b/cmake/Modules/TestForARM.cmake index 437a75e1a..05a5c172e 100644 --- a/cmake/Modules/TestForARM.cmake +++ b/cmake/Modules/TestForARM.cmake @@ -1,12 +1,29 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ############################################################################## -# check if the compiler defines the architecture as ARM and set the +# check if the compiler defines the architecture as ARM and set the # version, if found. # # - Anthony Arnold ############################################################################## -if (__TEST_FOR_ARM_INCLUDED) - return () +if(__TEST_FOR_ARM_INCLUDED) + return() endif() set(__TEST_FOR_ARM_INCLUDED TRUE) @@ -14,27 +31,27 @@ set(__TEST_FOR_ARM_INCLUDED TRUE) # output variable if found. function(check_arm_version ppdef input_string version output_var) string(REGEX MATCH "${ppdef}" _VERSION_MATCH "${input_string}") - if (NOT _VERSION_MATCH STREQUAL "") + if(NOT _VERSION_MATCH STREQUAL "") set(${output_var} "${version}" PARENT_SCOPE) - endif(NOT _VERSION_MATCH STREQUAL "") + endif() endfunction() message(STATUS "Checking for ARM") -set (IS_ARM NO) -set (ARM_VERSION "") +set(IS_ARM NO) +set(ARM_VERSION "") -if (CMAKE_COMPILER_IS_GNUCXX) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") execute_process(COMMAND echo "int main(){}" COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} -dM -E - OUTPUT_VARIABLE TEST_FOR_ARM_RESULTS) string(REGEX MATCH "__arm" ARM_FOUND "${TEST_FOR_ARM_RESULTS}") if(ARM_FOUND STREQUAL "") - string(REGEX MATCH "__aarch64" ARM_FOUND "${TEST_FOR_ARM_RESULTS}") - endif(ARM_FOUND STREQUAL "") + string(REGEX MATCH "__aarch64" ARM_FOUND "${TEST_FOR_ARM_RESULTS}") + endif() - if (NOT ARM_FOUND STREQUAL "") + if(NOT ARM_FOUND STREQUAL "") set(IS_ARM YES) message(STATUS "ARM system detected") @@ -66,22 +83,21 @@ if (CMAKE_COMPILER_IS_GNUCXX) check_arm_version("__ARM_ARCH_8A" ${TEST_FOR_ARM_RESULTS} "armv8-a" ARM_VERSION) # anything else just define as arm - if (ARM_VERSION STREQUAL "") + if(ARM_VERSION STREQUAL "") message(STATUS "Couldn't detect ARM version. Setting to 'arm'") set(ARM_VERSION "arm") - else (ARM_VERSION STREQUAL "") + else() message(STATUS "ARM version ${ARM_VERSION} detected") - endif (ARM_VERSION STREQUAL "") - - else (NOT ARM_FOUND STREQUAL "") - message(STATUS "System is not ARM") - endif(NOT ARM_FOUND STREQUAL "") + endif() + else() + message(STATUS "System is not ARM") + endif() -else (CMAKE_COMPILE_IS_GNUCXX) +else() # TODO: Other compilers message(STATUS "Not detecting ARM on non-GNUCXX compiler. Defaulting to false") message(STATUS "If you are compiling for ARM, set IS_ARM=ON manually") -endif(CMAKE_COMPILER_IS_GNUCXX) +endif() set(IS_ARM ${IS_ARM} CACHE BOOL "Compiling for ARM") set(ARM_VERSION ${ARM_VERSION} CACHE STRING "ARM version") diff --git a/cmake/Modules/TestForSSE.cmake b/cmake/Modules/TestForSSE.cmake index 1280f83b3..23b2d16a8 100644 --- a/cmake/Modules/TestForSSE.cmake +++ b/cmake/Modules/TestForSSE.cmake @@ -1,24 +1,41 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + + ############################################################################### # Test for availability of SSE # # - Anthony Arnold ############################################################################### - -function (test_for_sse h_file result_var name) - if (NOT DEFINED ${result_var}) +function(test_for_sse h_file result_var name) + if(NOT DEFINED ${result_var}) execute_process(COMMAND echo "#include <${h_file}>" - COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} -c -x c++ - - RESULT_VARIABLE COMPILE_RESULT - OUTPUT_QUIET ERROR_QUIET) + COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} -c -x c++ - + RESULT_VARIABLE COMPILE_RESULT + OUTPUT_QUIET ERROR_QUIET) set(detected 0) - if (COMPILE_RESULT EQUAL 0) + if(COMPILE_RESULT EQUAL 0) message(STATUS "Detected ${name}") set(detected 1) - endif(COMPILE_RESULT EQUAL 0) + endif() set(${result_var} ${detected} CACHE INTERNAL "${name} Available") - endif (NOT DEFINED ${result_var}) -endfunction(test_for_sse) + endif() +endfunction() message(STATUS "Testing for SIMD extensions") diff --git a/cmake/Toolchains/oe-sdk_cross.cmake b/cmake/Toolchains/oe-sdk_cross.cmake index 06f589c34..dd7aedf5f 100644 --- a/cmake/Toolchains/oe-sdk_cross.cmake +++ b/cmake/Toolchains/oe-sdk_cross.cmake @@ -1,20 +1,37 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ########################################################## # Toolchain file for Open Embedded ########################################################## -set( CMAKE_SYSTEM_NAME Linux ) +set(CMAKE_SYSTEM_NAME Linux) string(REGEX MATCH "sysroots/([a-zA-Z0-9]+)" CMAKE_SYSTEM_PROCESSOR $ENV{SDKTARGETSYSROOT}) string(REGEX REPLACE "sysroots/" "" CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}) -set( CMAKE_CXX_FLAGS $ENV{CXXFLAGS} CACHE STRING "" FORCE ) -set( CMAKE_C_FLAGS $ENV{CFLAGS} CACHE STRING "" FORCE ) #same flags for C sources -set( CMAKE_LDFLAGS_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE ) #same flags for C sources -set( CMAKE_LIBRARY_PATH $ENV{OECORE_TARGET_SYSROOT}/usr/lib ) +set(CMAKE_CXX_FLAGS $ENV{CXXFLAGS} CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS $ENV{CFLAGS} CACHE STRING "" FORCE) # same flags for C sources +set(CMAKE_LDFLAGS_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE) # same flags for C sources +set(CMAKE_LIBRARY_PATH $ENV{OECORE_TARGET_SYSROOT}/usr/lib) -set( CMAKE_FIND_ROOT_PATH $ENV{OECORE_TARGET_SYSROOT} $ENV{OECORE_NATIVE_SYSROOT} ) -set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) -set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +set(CMAKE_FIND_ROOT_PATH $ENV{OECORE_TARGET_SYSROOT} $ENV{OECORE_NATIVE_SYSROOT}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set ( ORC_INCLUDE_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/include/orc-0.4 ) -set ( ORC_LIBRARY_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/lib ) +set(ORC_INCLUDE_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/include/orc-0.4) +set(ORC_LIBRARY_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/lib) diff --git a/cmake/Toolchains/zynq-7000.cmake b/cmake/Toolchains/zynq-7000.cmake index 9ce876e56..18cb416fa 100644 --- a/cmake/Toolchains/zynq-7000.cmake +++ b/cmake/Toolchains/zynq-7000.cmake @@ -1,3 +1,20 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + ########################################################## # Toolchain file for Zynq-7000 devices ########################################################## @@ -23,4 +40,4 @@ set(CMAKE_CXX_FLAGS ${ZYNQ_FLAGS} CACHE STRING "" FORCE) set(CMAKE_LIBRARY_PATH ${CMAKE_SYSROOT}/usr/lib ${CMAKE_SYSROOT}/usr/lib/arm-linux-gnueabihf) -set(CMAKE_INSTALL_PREFIX ${CMAKE_SYSROOT}/usr CACHE STRING "" FORCE) \ No newline at end of file +set(CMAKE_INSTALL_PREFIX ${CMAKE_SYSROOT}/usr CACHE STRING "" FORCE) diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in index 2c34c8199..a0004acc5 100644 --- a/cmake/cmake_uninstall.cmake.in +++ b/cmake/cmake_uninstall.cmake.in @@ -1,21 +1,38 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") -endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif() file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - exec_program( - "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove \"$ENV{DESTDIR}${file}\" OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval - ) + RESULT_VARIABLE rm_retval + ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") - endif(NOT "${rm_retval}" STREQUAL 0) - else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + endif() + else() message(STATUS "File $ENV{DESTDIR}${file} does not exist.") - endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) \ No newline at end of file + endif() +endforeach() diff --git a/conf/front-end-cal.conf b/conf/front-end-cal.conf index 6f9d898d4..8a2b55cb5 100644 --- a/conf/front-end-cal.conf +++ b/conf/front-end-cal.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Default configuration file ; You can define your own front-end calibration tool configuration and invoke it by doing ; ./front-end-cal --config_file=my_GNSS_SDR_configuration.conf @@ -18,13 +21,13 @@ GNSS-SDR.init_altitude_m=10 ; Mozoncillo ;GNSS-SDR.init_latitude_deg=41.14534824586196 -;GNSS-SDR.init_longitude_deg=-4.187125019737464 +;GNSS-SDR.init_longitude_deg=-4.187125019737464 ;GNSS-SDR.init_altitude_m=900 ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 ;######### SUPL RRLP GPS assistance configuration ##### ; Check http://www.mcc-mnc.com/ @@ -36,41 +39,38 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=217 -GNSS-SDR.SUPL_MNS=7 +GNSS-SDR.SUPL_MNC=7 GNSS-SDR.SUPL_LAC=861 GNSS-SDR.SUPL_CI=40184 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] or [Osmosdr_Signal_Source] SignalSource.implementation=Osmosdr_Signal_Source - -SignalSource.AGC_enabled=false - -;#filename: path to file with the captured GNSS signal samples to be processed -;SignalSource.filename=/datalogger/signals/RTL-SDR/cap_-90dBm_IF15_RF40_EzCap.dat -SignalSource.filename=/datalogger/signals/Agilent/New York/2msps.dat -;SignalSource.filename=/datalogger/signals/RTL-SDR/geo/pmt4_no_amp.dat -;SignalSource.filename=/datalogger/signals/RTL-SDR/geo/pmt4_no_amp_mini.dat -;SignalSource.filename=/datalogger/signals/RTL-SDR/mozoncillo/cap_mozon_ezcap.dat - +;#freq: RF front-end center frequency in [Hz] +SignalSource.freq=1575420000 ;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;#sampling_frequency: Original Signal sampling frequency in [Hz] +;#sampling_frequency: Original Signal sampling frequency in samples per second SignalSource.sampling_frequency=2000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#gain: Front-end Gain in [dB] -SignalSource.gain=40 +;#gain: Front-end Gain in [dB] +SignalSource.gain=40 SignalSource.rf_gain=40 SignalSource.if_gain=30 +SignalSource.AGC_enabled=false -;#subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0) -SignalSource.subdevice=B:0 +;# Please note that the new RTL-SDR Blog V3 dongles ship a < 1 PPM +;# temperature compensated oscillator (TCXO), which is well suited for GNSS +;# signal processing, and a 4.5 V powered bias-tee to feed an active antenna. +;# Whether the bias-tee is turned off before reception depends on which version +;# of gr-osmosdr was used when compiling GNSS-SDR. With an old version +;# (for example, v0.1.4-8), the utility rtl_biast may be used to switch the +;# bias-tee, and then call gnss-sdr. +;# See https://github.com/rtlsdrblog/rtl_biast +;# After reception the bias-tee is switched off automatically by the program. +;# With newer versions of gr-osmosdr (>= 0.1.4-13), the bias-tee can be +;# activated by uncommenting the following line: +;SignalSource.osmosdr_args=rtl,bias=1 -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. +;#samples: Number of samples to be processed. Notice that 0 means infinite samples. SignalSource.samples=0 ;#repeat: Repeat the processing file. @@ -82,7 +82,7 @@ SignalSource.dump=false SignalSource.dump_filename=../data/signal_source.dat ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. +;## It holds blocks to change data type, filter and resample input data. ;#implementation: Use [Pass_Through] or [Signal_Conditioner] ;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks @@ -90,7 +90,7 @@ SignalSource.dump_filename=../data/signal_source.dat SignalConditioner.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. +;## Changes the type of input data. ;#implementation: Use [Ishort_To_Complex] or [Pass_Through] DataTypeAdapter.implementation=Pass_Through ;#dump: Dump the filtered data to a file. @@ -108,20 +108,15 @@ DataTypeAdapter.dump_filename=../data/data_type_adapter.dat InputFilter.implementation=Freq_Xlating_Fir_Filter -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. +;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. ;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. +;#This function calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, +;#the desired response on those bands, and the weight given to the error in those bands. -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. +;#input_item_type: Type and resolution for input signal samples. InputFilter.input_item_type=gr_complex -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. +;#outut_item_type: Type and resolution for output filtered signal samples. InputFilter.output_item_type=gr_complex ;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. @@ -156,7 +151,7 @@ InputFilter.ampl2_end=0.0 InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 -;#filter_type: one of "bandpass", "hilbert" or "differentiator" +;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass ;#grid_density: determines how accurately the filter will be constructed. @@ -171,6 +166,12 @@ InputFilter.IF=0 InputFilter.decimation_factor=1 +;#dump: Dump the filtered data to a file. +InputFilter.dump=false + +;#dump_filename: Log path and filename. +InputFilter.dump_filename=../data/input_filter.dat + ;######### RESAMPLER CONFIG ############ ;## Resamples the input data. ;#implementation: Use [Pass_Through] or [Direct_Resampler] @@ -178,15 +179,9 @@ InputFilter.decimation_factor=1 Resampler.implementation=Pass_Through ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition.dump=false -;#filename: Log path and filename -Acquisition.dump_filename=./acq_dump.dat +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler ;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Acquisition.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition.if=0 ;#sampled_ms: Signal block duration for the acquisition signal detection [ms] Acquisition.sampled_ms=1 ;#threshold: Acquisition threshold @@ -199,4 +194,7 @@ Acquisition.doppler_min=-100000 Acquisition.doppler_step=500 ;#maximum dwells Acquisition.max_dwells=15 - +;#dump: Enable or disable the acquisition internal data file logging [true] or [false] +Acquisition.dump=false +;#filename: Log path and filename +Acquisition.dump_filename=./acq_dump.dat diff --git a/conf/gnss-sdr-kalman-bayes.conf b/conf/gnss-sdr-kalman-bayes.conf new file mode 100644 index 000000000..051d080de --- /dev/null +++ b/conf/gnss-sdr-kalman-bayes.conf @@ -0,0 +1,63 @@ +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 +GNSS-SDR.internal_fs_hz=2000000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/home/glamountain/gnss-sdr/data/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat +SignalSource.item_type=ishort +SignalSource.sampling_frequency=4000000 +SignalSource.freq=1575420000 +SignalSource.samples=0 + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ishort_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Direct_Resampler +Resampler.sample_freq_in=4000000 +Resampler.sample_freq_out=2000000 +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 +Channel.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=0.008 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=../data/kalman/acq_dump + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_KF_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.dump=true +Tracking_1C.dump_filename=../data/kalman/epl_tracking_ch_ +Tracking_1C.bce_run = true; +Tracking_1C.p_transient = 0; +Tracking_1C.s_transient = 100; + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=GPS_L1_CA_Observables + +;######### PVT CONFIG ############ +PVT.implementation=GPS_L1_CA_PVT +PVT.averaging_depth=100 +PVT.flag_averaging=true +PVT.output_rate_ms=10 +PVT.display_rate_ms=500 diff --git a/conf/gnss-sdr.conf b/conf/gnss-sdr.conf index 88a66f3ee..353bdb2fd 100644 --- a/conf/gnss-sdr.conf +++ b/conf/gnss-sdr.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Default configuration file ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf @@ -6,8 +9,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,173 +23,68 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. SignalSource.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner -;SignalConditioner.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Ishort_To_Complex -;DataTypeAdapter.implementation=Pass_Through ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. +InputFilter.implementation=Pass_Through ; or Fir_Filter -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of GNU Radio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired response on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.44 InputFilter.band2_begin=0.55 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter.sampling_frequency=4000000 InputFilter.IF=0 - +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neighborhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resampled data to a file. Resampler.dump=false -;#dump_filename: Log path and filename. Resampler.dump_filename=../data/resampler.dat -;#item_type: Type and resolution for each of the signal samples. -Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal -Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=2000000 - ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS L1 C/A satellite channels. Channels_1C.count=6 -;#count: Number of available Galileo E1B satellite channels. Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#if the option is disabled by default is assigned "1C" GPS L1 C/A -Channel.signal=1C - - ;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options ;######### CHANNEL 0 CONFIG ############ ;Channel0.signal=1C -;#satellite: Satellite PRN ID for this channel. Disable this option for random search ;Channel0.satellite=11 ;######### CHANNEL 1 CONFIG ############ @@ -194,115 +92,52 @@ Channel.signal=1C ;Channel1.satellite=18 ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler -;#threshold: Acquisition threshold +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.005 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_1C.doppler_min=-10000 -;#doppler_step Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 -;#maximum dwells Acquisition_1C.max_dwells=5 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=45.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=45.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=3.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=100 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.AR_GPS=PPP-AR ; options: OFF, Continuous, Instantaneous, Fix-and-Hold, PPP-AR PVT.output_rate_ms=10 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms <= display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump, ".kml" and ".geojson" to GIS-friendly formats. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea - -;#flag_nmea_tty_port: Enables or disables the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=true - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - -;#flag_rtcm_server: Enables or disables a TCP/IP server transmitting RTCM 3.2 messages (accepts multiple clients, port 2101 by default) PVT.flag_rtcm_server=true - -;#flag_rtcm_tty_port: Enables or disables the RTCM log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_rtcm_tty_port=false - -;#rtcm_dump_devname: serial device descriptor for RTCM logging PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false - - +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GLONASS_L1_CA_GPS_L1_CA_ibyte.conf b/conf/gnss-sdr_GLONASS_L1_CA_GPS_L1_CA_ibyte.conf new file mode 100644 index 000000000..88c8741b6 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L1_CA_GPS_L1_CA_ibyte.conf @@ -0,0 +1,140 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 +Receiver.sources_count=2 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource0.implementation=File_Signal_Source +SignalSource0.filename=/archive/NT1065_L1_20160923_fs6625e6_if60e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource0.item_type=ibyte +SignalSource0.sampling_frequency=6625000 +SignalSource0.samples=0 +SignalSource0.dump=false; +SignalSource0.dump_filename=/archive/signal_glonass.bin + +SignalSource1.implementation=File_Signal_Source +SignalSource1.filename=/archive/NT1065_GLONASS_L1_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource1.item_type=ibyte +SignalSource1.sampling_frequency=6625000 +SignalSource1.samples=0 +SignalSource1.dump=false; +SignalSource1.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner +DataTypeAdapter0.implementation=Ibyte_To_Complex +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.70 +InputFilter0.band2_begin=0.80 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.sampling_frequency=6625000 +InputFilter0.IF=60000 +Resampler0.implementation=Direct_Resampler +Resampler0.sample_freq_in=6625000 +Resampler0.sample_freq_out=6625000 +Resampler0.item_type=gr_complex + +SignalConditioner1.implementation=Signal_Conditioner +DataTypeAdapter1.implementation=Ibyte_To_Complex +InputFilter1.implementation=Pass_Through +InputFilter1.item_type=gr_complex +Resampler1.implementation=Pass_Through +Resampler1.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels.in_acquisition=1 +Channels_1G.count=5 +Channels_1C.count=5 + +;# Defining GLONASS satellites +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=1 +Channel6.RF_channel_ID=1 +Channel7.RF_channel_ID=1 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=0.0 +Acquisition_1C.pfa=0.00001 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false; +Acquisition_1C.dump_filename=/archive/gps_acquisition.dat +;Acquisition_1C.coherent_integration_time_ms=10 + +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.00001 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=false; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_1G.coherent_integration_time_ms=10 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.early_late_space_chips=0.5 +Tracking_1C.pll_bw_hz=20.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dump=false; +Tracking_1C.dump_filename=/archive/gps_tracking_ch_ + +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=25.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.dump=false; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false; +Observables.dump_filename=/archive/gnss_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GLONASS_L1_CA_GPS_L2C_ibyte.conf b/conf/gnss-sdr_GLONASS_L1_CA_GPS_L2C_ibyte.conf new file mode 100644 index 000000000..435194b75 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L1_CA_GPS_L2C_ibyte.conf @@ -0,0 +1,141 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 +Receiver.sources_count=2 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource0.implementation=File_Signal_Source +SignalSource0.filename=/archive/NT1065_L2_20160923_fs6625e6_if60e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource0.item_type=ibyte +SignalSource0.sampling_frequency=6625000 +SignalSource0.samples=0 +SignalSource0.dump=false; +SignalSource0.dump_filename=/archive/signal_glonass.bin + +SignalSource1.implementation=File_Signal_Source +SignalSource1.filename=/archive/NT1065_GLONASS_L1_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource1.item_type=ibyte +SignalSource1.sampling_frequency=6625000 +SignalSource1.samples=0 +SignalSource1.dump=false; +SignalSource1.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner +DataTypeAdapter0.implementation=Ibyte_To_Complex +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.70 +InputFilter0.band2_begin=0.80 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.sampling_frequency=6625000 +InputFilter0.IF=60000 +Resampler0.implementation=Pass_Through +Resampler0.item_type=gr_complex + +SignalConditioner1.implementation=Signal_Conditioner +DataTypeAdapter1.implementation=Ibyte_To_Complex +InputFilter1.implementation=Pass_Through +InputFilter1.item_type=gr_complex +Resampler1.implementation=Pass_Through +Resampler1.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels.in_acquisition=5 +Channels_2S.count=5 +Channels_1G.count=5 + +;# Defining GLONASS satellites +Channel0.RF_channel_ID=0 +Channel0.signal=2S +Channel1.RF_channel_ID=0 +Channel1.signal=2S +Channel2.RF_channel_ID=0 +Channel2.signal=2S +Channel3.RF_channel_ID=0 +Channel3.signal=2S +Channel4.RF_channel_ID=0 +Channel4.signal=2S +Channel5.RF_channel_ID=1 +Channel6.RF_channel_ID=1 +Channel7.RF_channel_ID=1 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.threshold=0.0 +Acquisition_2S.pfa=0.00001 +Acquisition_2S.doppler_max=10000 +Acquisition_2S.doppler_step=60 +Acquisition_2S.max_dwells=1 + +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.00001 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=false; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking +Tracking_2S.item_type=gr_complex +Tracking_2S.early_late_space_chips=0.5 +Tracking_2S.pll_bw_hz=2.0; +Tracking_2S.dll_bw_hz=0.250; +Tracking_2S.order=2; +Tracking_2S.dump=false; +Tracking_2S.dump_filename=/archive/gps_tracking_ch_ + +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=25.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.dump=false; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder +TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false; +Observables.dump_filename=/archive/gnss_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=3 diff --git a/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf b/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf new file mode 100644 index 000000000..1e4b6a24b --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf @@ -0,0 +1,80 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/media/dmiralles/Seagate Backup Plus Drive/GNSS Data/NT1065_GLONASS_L1_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE ; <- PUT YOUR FILE HERE +SignalSource.item_type=ibyte +SignalSource.sampling_frequency=6625000 +SignalSource.samples=0 +SignalSource.dump=false; +SignalSource.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channel.signal=1G +Channels.in_acquisition=1 +Channels_1G.count=5 + +Channel0.satellite=24 ; k= +Channel1.satellite=1 ; k=1 +Channel2.satellite=2 ; k=-4 +Channel3.satellite=20 ; k=-5 +Channel4.satellite=21 ; k=4 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.0001 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=true; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_1G.coherent_integration_time_ms=1 +;Acquisition_1G.max_dwells = 5 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=25.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.dump=true; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=true; +Observables.dump_filename=/archive/glo_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GLONASS_L1_CA_ibyte_coh_trk.conf b/conf/gnss-sdr_GLONASS_L1_CA_ibyte_coh_trk.conf new file mode 100644 index 000000000..6e30d5566 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L1_CA_ibyte_coh_trk.conf @@ -0,0 +1,84 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/archive/NT1065_GLONASS_L1_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=ibyte +SignalSource.sampling_frequency=6625000 +SignalSource.samples=0 +SignalSource.dump=false; +SignalSource.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channel.signal=1G +Channels.in_acquisition=2 +Channels_1G.count=8 + +;Channel0.satellite=24 ; k=2 +;Channel1.satellite=1 ; k=1 +;Channel2.satellite=2 ; k=-4 +;Channel3.satellite=20 ; k=-5 +;Channel4.satellite=21 ; k=4 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.0001 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=false; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_1G.coherent_integration_time_ms=1 +;Acquisition_1G.max_dwells = 5 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=40.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.pll_bw_narrow_hz = 25.0; +Tracking_1G.dll_bw_narrow_hz = 2.0; +Tracking_1G.extend_correlation_ms = 1; +Tracking_1G.dump=false; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=/archive/glo_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GLONASS_L2_CA_GPS_L1_CA_ibyte.conf b/conf/gnss-sdr_GLONASS_L2_CA_GPS_L1_CA_ibyte.conf new file mode 100644 index 000000000..3c56e6132 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L2_CA_GPS_L1_CA_ibyte.conf @@ -0,0 +1,141 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 +Receiver.sources_count=2 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource0.implementation=File_Signal_Source +SignalSource0.filename=/media/dmiralles/Seagate Backup Plus Drive/GNSS Data/NT1065_L1_20160923_fs6625e6_if60e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource0.item_type=ibyte +SignalSource0.sampling_frequency=6625000 +SignalSource0.samples=0 +SignalSource0.dump=false; +SignalSource0.dump_filename=/archive/signal_glonass.bin + +SignalSource1.implementation=File_Signal_Source +SignalSource1.filename=/media/dmiralles/Seagate Backup Plus Drive/GNSS Data/NT1065_GLONASS_L2_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource1.item_type=ibyte +SignalSource1.sampling_frequency=6625000 +SignalSource1.samples=0 +SignalSource1.dump=false; +SignalSource1.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner +DataTypeAdapter0.implementation=Ibyte_To_Complex +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.70 +InputFilter0.band2_begin=0.80 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.sampling_frequency=6625000 +InputFilter0.IF=60000 +Resampler0.implementation=Direct_Resampler +Resampler0.sample_freq_in=6625000 +Resampler0.sample_freq_out=6625000 +Resampler0.item_type=gr_complex + +SignalConditioner1.implementation=Signal_Conditioner +DataTypeAdapter1.implementation=Ibyte_To_Complex +InputFilter1.implementation=Pass_Through +InputFilter1.item_type=gr_complex +Resampler1.implementation=Pass_Through +Resampler1.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels.in_acquisition=1 +Channels_2G.count=5 +Channels_1C.count=5 + +;# Defining GLONASS satellites +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=1 +Channel6.RF_channel_ID=1 +Channel7.RF_channel_ID=1 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=0.0 +Acquisition_1C.pfa=0.00001 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false; +Acquisition_1C.dump_filename=/archive/gps_acquisition.dat +;Acquisition_1C.coherent_integration_time_ms=10 + +Acquisition_2G.implementation=GLONASS_L2_CA_PCPS_Acquisition +Acquisition_2G.item_type=gr_complex +Acquisition_2G.threshold=0.0 +Acquisition_2G.pfa=0.00001 +Acquisition_2G.doppler_max=10000 +Acquisition_2G.doppler_step=250 +Acquisition_2G.dump=false; +Acquisition_2G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_2G.coherent_integration_time_ms=10 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.early_late_space_chips=0.5 +Tracking_1C.pll_bw_hz=20.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dump=false; +Tracking_1C.dump_filename=/archive/gps_tracking_ch_ + +Tracking_2G.implementation=GLONASS_L2_CA_DLL_PLL_Tracking +Tracking_2G.item_type=gr_complex +Tracking_2G.early_late_space_chips=0.5 +Tracking_2G.pll_bw_hz=25.0; +Tracking_2G.dll_bw_hz=2.0; +Tracking_2G.dump=false; +Tracking_2G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_2G.implementation=GLONASS_L2_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false; +Observables.dump_filename=/archive/gnss_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GLONASS_L2_CA_GPS_L2C_ibyte.conf b/conf/gnss-sdr_GLONASS_L2_CA_GPS_L2C_ibyte.conf new file mode 100644 index 000000000..10df72ae2 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L2_CA_GPS_L2C_ibyte.conf @@ -0,0 +1,142 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 +Receiver.sources_count=2 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource0.implementation=File_Signal_Source +SignalSource0.filename=/archive/NT1065_L2_20160923_fs6625e6_if60e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource0.item_type=ibyte +SignalSource0.sampling_frequency=6625000 +SignalSource0.samples=0 +SignalSource0.dump=false; +SignalSource0.dump_filename=/archive/signal_glonass.bin + +SignalSource1.implementation=File_Signal_Source +SignalSource1.filename=/archive/NT1065_GLONASS_L2_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource1.item_type=ibyte +SignalSource1.sampling_frequency=6625000 +SignalSource1.samples=0 +SignalSource1.dump=false; +SignalSource1.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner +DataTypeAdapter0.implementation=Ibyte_To_Complex +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.70 +InputFilter0.band2_begin=0.80 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.sampling_frequency=6625000 +InputFilter0.IF=60000 +Resampler0.implementation=Pass_Through +Resampler0.item_type=gr_complex + +SignalConditioner1.implementation=Signal_Conditioner +DataTypeAdapter1.implementation=Ibyte_To_Complex +InputFilter1.implementation=Pass_Through +InputFilter1.item_type=gr_complex +Resampler1.implementation=Pass_Through +Resampler1.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels.in_acquisition=5 +Channels_2S.count=5 +Channels_2G.count=5 + +;# Defining GLONASS satellites +Channel0.RF_channel_ID=0 +Channel0.signal=2S +Channel1.RF_channel_ID=0 +Channel1.signal=2S +Channel2.RF_channel_ID=0 +Channel2.signal=2S +Channel3.RF_channel_ID=0 +Channel3.signal=2S +Channel4.RF_channel_ID=0 +Channel4.signal=2S +Channel5.RF_channel_ID=1 +Channel6.RF_channel_ID=1 +Channel7.RF_channel_ID=1 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.threshold=0.0 +Acquisition_2S.pfa=0.00001 +Acquisition_2S.doppler_max=10000 +Acquisition_2S.doppler_step=60 +Acquisition_2S.max_dwells=1 + +Acquisition_2G.implementation=GLONASS_L2_CA_PCPS_Acquisition +Acquisition_2G.item_type=gr_complex +Acquisition_2G.threshold=0.0 +Acquisition_2G.pfa=0.00001 +Acquisition_2G.doppler_max=10000 +Acquisition_2G.doppler_step=250 +Acquisition_2G.dump=false; +Acquisition_2G.dump_filename=/archive/glo_acquisition.dat + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking +Tracking_2S.item_type=gr_complex +Tracking_2S.early_late_space_chips=0.5 +Tracking_2S.pll_bw_hz=2.0; +Tracking_2S.dll_bw_hz=0.250; +Tracking_2S.order=2; +Tracking_2S.dump=false; +Tracking_2S.dump_filename=/archive/gps_tracking_ch_ + +Tracking_2G.implementation=GLONASS_L2_CA_DLL_PLL_Tracking +Tracking_2G.item_type=gr_complex +Tracking_2G.early_late_space_chips=0.5 +Tracking_2G.pll_bw_hz=25.0; +Tracking_2G.dll_bw_hz=3.0; +Tracking_2G.dump=false; +Tracking_2G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder +TelemetryDecoder_2G.implementation=GLONASS_L2_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false; +Observables.dump_filename=/archive/gnss_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=3 diff --git a/conf/gnss-sdr_GLONASS_L2_CA_ibyte.conf b/conf/gnss-sdr_GLONASS_L2_CA_ibyte.conf new file mode 100644 index 000000000..39b6fa5ab --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L2_CA_ibyte.conf @@ -0,0 +1,74 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/media/dmiralles/Seagate Backup Plus Drive/GNSS Data/NT1065_GLONASS_L2_20160831_fs6625e6_60e3_schar_1m.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=ibyte +SignalSource.sampling_frequency=6625000 +SignalSource.samples=0 +SignalSource.dump=false; +SignalSource.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channel.signal=2G +Channels.in_acquisition=1 +Channels_2G.count=5 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_2G.implementation=GLONASS_L2_CA_PCPS_Acquisition +Acquisition_2G.item_type=gr_complex +Acquisition_2G.threshold=0.0 +Acquisition_2G.pfa=0.0001 +Acquisition_2G.doppler_max=10000 +Acquisition_2G.doppler_step=250 +Acquisition_2G.dump=true; +Acquisition_2G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_2G.coherent_integration_time_ms=1 +;Acquisition_2G.max_dwells = 5 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_2G.implementation=GLONASS_L2_CA_DLL_PLL_Tracking +Tracking_2G.item_type=gr_complex +Tracking_2G.early_late_space_chips=0.5 +Tracking_2G.pll_bw_hz=20.0; +Tracking_2G.dll_bw_hz=2.0; +Tracking_2G.dump=true; +Tracking_2G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_2G.implementation=GLONASS_L2_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=true; +Observables.dump_filename=/archive/glo_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GLONASS_L2_CA_ibyte_coh_trk.conf b/conf/gnss-sdr_GLONASS_L2_CA_ibyte_coh_trk.conf new file mode 100644 index 000000000..6e30d5566 --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L2_CA_ibyte_coh_trk.conf @@ -0,0 +1,84 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/archive/NT1065_GLONASS_L1_20160923_fs6625e6_if0e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=ibyte +SignalSource.sampling_frequency=6625000 +SignalSource.samples=0 +SignalSource.dump=false; +SignalSource.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channel.signal=1G +Channels.in_acquisition=2 +Channels_1G.count=8 + +;Channel0.satellite=24 ; k=2 +;Channel1.satellite=1 ; k=1 +;Channel2.satellite=2 ; k=-4 +;Channel3.satellite=20 ; k=-5 +;Channel4.satellite=21 ; k=4 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.0001 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=false; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_1G.coherent_integration_time_ms=1 +;Acquisition_1G.max_dwells = 5 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=40.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.pll_bw_narrow_hz = 25.0; +Tracking_1G.dll_bw_narrow_hz = 2.0; +Tracking_1G.extend_correlation_ms = 1; +Tracking_1G.dump=false; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=/archive/glo_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GPS_L1_2ch_fmcomms2_realtime.conf b/conf/gnss-sdr_GPS_L1_2ch_fmcomms2_realtime.conf new file mode 100644 index 000000000..cd3345904 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_2ch_fmcomms2_realtime.conf @@ -0,0 +1,115 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [Sps]. +GNSS-SDR.internal_fs_sps=7000000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Fmcomms2_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.device_address=192.168.0.4 +SignalSource.sampling_frequency=7000000 +SignalSource.freq=1575420000 +SignalSource.bandwidth=4000000 +SignalSource.RF_channels=2 +SignalSource.rx1_enable=true +SignalSource.rx2_enable=true +SignalSource.gain_mode_rx1=slow_attack +SignalSource.gain_mode_rx2=slow_attack +SignalSource.rf_port_select=A_BALANCED +SignalSource.gain_rx1=64 +SignalSource.gain_rx2=64 +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=../data/signal_source.dat +SignalSource.enable_throttle_control=false +SignalSource.enable_dds_lo=false +SignalSource.freq_rf_tx_hz=1260000000 +SignalSource.freq_dds_tx_hz=1000 +SignalSource.scale_dds_dbfs=0.0 +SignalSource.phase_dds_deg=0.0 +SignalSource.tx_attenuation_db=0.0 + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Pass_Through +SignalConditioner1.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 + +;# CHANNEL CONNECTION +Channel0.RF_channel_ID=0 +Channel0.signal=1C +Channel1.RF_channel_ID=0 +Channel1.signal=1C +Channel2.RF_channel_ID=0 +Channel2.signal=1C +Channel3.RF_channel_ID=0 +Channel3.signal=1C +Channel4.RF_channel_ID=1 +Channel4.signal=1C +Channel5.RF_channel_ID=1 +Channel5.signal=1C +Channel6.RF_channel_ID=1 +Channel6.signal=1C +Channel7.RF_channel_ID=1 +Channel7.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=20 +Acquisition_1C.use_CFAR_algorithm=false +Acquisition_1C.blocking=true +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ +Tracking_1C.pll_bw_hz=35.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.early_late_space_chips=0.5; + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_2ch_udp.conf b/conf/gnss-sdr_GPS_L1_2ch_udp.conf new file mode 100644 index 000000000..6dd703fa6 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_2ch_udp.conf @@ -0,0 +1,103 @@ +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [Sps]. +GNSS-SDR.internal_fs_sps=13250000 ;//66.25/5 +;GNSS-SDR.internal_fs_sps=6625000 ;//66.25/10 +;GNSS-SDR.internal_fs_sps=3312500 ;//66.25/20 +;GNSS-SDR.internal_fs_sps=2650000 ;//66.25/25 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Custom_UDP_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.origin_address=0.0.0.0 +SignalSource.capture_device=eth0 +SignalSource.port=1234 +SignalSource.payload_bytes=1472 +;SignalSource.sample_type=cbyte +SignalSource.sample_type=c4bits +SignalSource.IQ_swap=false +SignalSource.RF_channels=1 +SignalSource.channels_in_udp=2 +SignalSource.dump=false +SignalSource.dump_filename=./signal_source.dat + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Pass_Through +;SignalConditioner0.implementation=Pass_Through +;SignalConditioner1.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 + +;# CHANNEL CONNECTION +Channel.signal=1C +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=0 +Channel6.RF_channel_ID=0 +Channel7.RF_channel_ID=0 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + +;Channel0.signal=1C +;Channel1.RF_channel_ID=1 +;Channel1.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=17 +Acquisition_1C.use_CFAR_algorithm=false +Acquisition_1C.blocking=false +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ +Tracking_1C.pll_bw_hz=35.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.early_late_space_chips=0.5; + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_CA_ibyte.conf b/conf/gnss-sdr_GPS_L1_CA_ibyte.conf new file mode 100644 index 000000000..c4a38223d --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_CA_ibyte.conf @@ -0,0 +1,92 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/archive/NT1065_L1_20160923_fs6625e6_if60e3_schar.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=ibyte +;SignalSource.samples=66250000 +SignalSource.samples=0 +SignalSource.dump=false; + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Freq_Xlating_Fir_Filter +InputFilter.item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.taps_item_type=float +InputFilter.number_of_taps=5 +InputFilter.number_of_bands=2 +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.70 +InputFilter.band2_begin=0.80 +InputFilter.band2_end=1.0 +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 +InputFilter.filter_type=bandpass +InputFilter.grid_density=16 +InputFilter.sampling_frequency=6625000 +InputFilter.IF=60000 +Resampler.implementation=Direct_Resampler +Resampler.sample_freq_in=6625000 +Resampler.sample_freq_out=6625000 +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channel.signal=1C +Channels.in_acquisition=1 +Channels_1C.count=6 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=0.01 +;Acquisition_1C.pfa=0.00001 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false; +Acquisition_1C.dump_filename=/archive/gps_acquisition.dat +;Acquisition_1C.coherent_integration_time_ms=10 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.early_late_space_chips=0.5 +Tracking_1C.pll_bw_hz=25.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.dump=false; +Tracking_1C.dump_filename=/archive/gps_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=true; +Observables.dump_filename=/archive/gps_observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1045_rate_ms=5000 +PVT.rtcm_MT1097_rate_ms=1000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=3 diff --git a/conf/gnss-sdr_GPS_L1_FPGA.conf b/conf/gnss-sdr_GPS_L1_FPGA.conf new file mode 100644 index 000000000..70ec83ed5 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_FPGA.conf @@ -0,0 +1,84 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 + + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Pass_Through +SignalSource.filename=/datalogger/signals/Agilent/New York/4msps.dat ; <- PUT YOUR FILE HERE +SignalSource.item_type=ishort +SignalSource.sampling_frequency=4000000 +SignalSource.freq=1575420000 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=../data/signal_source.dat +SignalSource.enable_throttle_control=false +SignalSource.enable_FPGA=true + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Pass_Through +SignalConditioner.item_type=cshort +SignalConditioner.enable_FPGA=true + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 +Channel.signal=1C +Channel.enable_FPGA=true + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fpga +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat +Acquisition_1C.item_type=cshort +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.select_queue_Fpga=0; +Acquisition_1C.threshold=0.005 +;Acquisition_1C.pfa=0.01 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=500 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga +Tracking_1C.item_type=cshort +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ +Tracking_1C.pll_bw_hz=45.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=GPS_L1_CA_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=GPS_L1_CA_PVT +PVT.averaging_depth=100 +PVT.flag_averaging=false +PVT.output_rate_ms=10 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_GN3S_realtime.conf b/conf/gnss-sdr_GPS_L1_GN3S_realtime.conf index a1caf56c4..9982a1cbd 100644 --- a/conf/gnss-sdr_GPS_L1_GN3S_realtime.conf +++ b/conf/gnss-sdr_GPS_L1_GN3S_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,16 +8,16 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2727933.33 ; 8183800/3 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2727933.33 ; 8183800/3 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) +;#implementation: ;#Notes for GN3S source: ; - The front-end sampling frequency is fixed to 8.1838 MSPS (8183800 Hz). ; - The baseband signal is shifted to an IF of 38400 Hz. It should be corrected with the signal conditioner block -GNSS-SDR.internal_fs_hz=2727933.33 ; 8183800/3 +GNSS-SDR.internal_fs_sps=2727933.33 ; 8183800/3 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=GN3S_Signal_Source @@ -66,40 +69,38 @@ Channels.in_acquisition=1 Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.008 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=45.0; Tracking_1C.dll_bw_hz=2.0; Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10 PVT.display_rate_ms=500 PVT.dump_filename=./PVT @@ -110,4 +111,3 @@ PVT.dump=false PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - diff --git a/conf/gnss-sdr_GPS_L1_LimeSDR.conf b/conf/gnss-sdr_GPS_L1_LimeSDR.conf new file mode 100644 index 000000000..c465a41ca --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_LimeSDR.conf @@ -0,0 +1,109 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=2000000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Osmosdr_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.sampling_frequency=2000000 +;# LimeSDR RX1 antennas: NONE,LNAH,LNAL,LNAW +SignalSource.antenna=LNAW +SignalSource.freq=1575420000 +SignalSource.gain=40 +SignalSource.rf_gain=40 +SignalSource.if_gain=30 +SignalSource.AGC_enabled=false +SignalSource.samples=0 +SignalSource.repeat=false +;# Next line enables the LimeSDR +SignalSource.osmosdr_args=driver=lime,soapy=0 +SignalSource.enable_throttle_control=false +SignalSource.dump=false +SignalSource.dump_filename=./signal_source.dat + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Pass_Through + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Freq_Xlating_Fir_Filter +InputFilter.decimation_factor=1 +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.taps_item_type=float +InputFilter.number_of_taps=5 +InputFilter.number_of_bands=2 +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.85 +InputFilter.band2_begin=0.9 +InputFilter.band2_end=1.0 +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 +InputFilter.filter_type=bandpass +InputFilter.grid_density=16 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + +;######### RESAMPLER CONFIG ############ +Resampler.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 +Channel.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler +Acquisition_1C.item_type=gr_complex +Acquisition_1C.sampled_ms=1 +Acquisition_1C.threshold=0.015 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_min=-10000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=GPS_L1_CA_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + +;######### PVT CONFIG ############ +;PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.iono_model=Broadcast +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=true +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GPS_L1_SPIR.conf b/conf/gnss-sdr_GPS_L1_SPIR.conf index 38a4ce838..f6fa9a076 100644 --- a/conf/gnss-sdr_GPS_L1_SPIR.conf +++ b/conf/gnss-sdr_GPS_L1_SPIR.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,123 +8,48 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Spir_File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/dtalogger/signals/spir/data/20Secs/20Secs_L1.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=int - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=80000000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Pass_Through DataTypeAdapter.item_type=float ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter InputFilter.implementation=Freq_Xlating_Fir_Filter -;InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter.dump=false - -;#dump_filename: Log path and filename. InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=float - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.45 InputFilter.band2_begin=0.55 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter.sampling_frequency=80000000 InputFilter.IF=10164 InputFilter.decimation_factor=20 @@ -130,182 +57,79 @@ InputFilter.decimation_factor=20 ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler.sample_freq_in=80000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler.sample_freq_out=4000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=10 -;#count: Number of available Galileo satellite channels. Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "1B" Galileo E1B Channel.signal=1C -;Galileo FM3 -> PRN 19 -;Galileo FM4 -> PRN 20 ;######### CHANNEL 0 CONFIG ############ - -;Channel0.signal=1B -;#satellite: Satellite PRN ID for this channel. Disable this option to random search ;Channel0.satellite=20 ;######### CHANNEL 1 CONFIG ############ -;Channel1.signal=1B ;Channel1.satellite=12 ;######### CHANNEL 2 CONFIG ############ -;Channel2.signal=1B -;#satellite: Satellite PRN ID for this channel. Disable this option to random search ;Channel2.satellite=11 ;######### CHANNEL 3 CONFIG ############ -;Channel3.signal=1B ;Channel3.satellite=19 ;######### ACQUISITION GLOBAL CONFIG ############ -_1C -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler -;#threshold: Acquisition threshold +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.005 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_min=-10000 -;#doppler_step Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 -;#maximum dwells Acquisition_1C.max_dwells=5 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat -;######### ACQUISITION CHANNELS CONFIG ###### - -;######### ACQUISITION CH 0 CONFIG ############ - -;#repeat_satellite: Use only jointly with the satellite PRN ID option. The default value is false -;Acquisition0.repeat_satellite = true -;Acquisition1.repeat_satellite = true -;Acquisition2.repeat_satellite = true -;Acquisition3.repeat_satellite = true - -;#cboc: Only for [Galileo_E1_PCPS_Ambiguous_Acquisition]. This option allows you to choose between acquiring with CBOC signal [true] or sinboc(1,1) signal [false]. -;#Use only if GNSS-SDR.internal_fs_hz is greater than or equal to 6138000 -Acquisition0.cboc=false - - -;######### ACQUISITION CH 1 CONFIG ############ -Acquisition1.cboc=false ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=20.0; +Tracking_1C.order=3; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=20.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +;#implementation: +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=100 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +;#implementation: Position Velocity and Time (PVT) implementation algorithm +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=500 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# RINEX, KML, and NMEA output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=true; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf b/conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf index 04e1d2786..f437366bf 100644 --- a/conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf +++ b/conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Configuration file for using USRP X300 as a RF front-end for GPS L1 signals. ; Set SignalSource.device_address to the IP address of your device ; and run: @@ -7,8 +10,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -21,175 +24,71 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -; # implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=UHD_Signal_Source - -; # When left empty, the device discovery routines will search all vailable transports on the system (ethernet, usb...) SignalSource.device_address=192.168.40.2 ; <- PUT THE IP ADDRESS OF YOUR USRP HERE - -; # item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -;SignalSource.item_type=gr_complex SignalSource.item_type=cshort - -; # sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -; # freq: RF front-end center frequency in [Hz] SignalSource.freq=1575420000 - -; # gain: Front-end Gain in [dB] SignalSource.gain=40 - -; # subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0) SignalSource.subdevice=A:0 - -; # samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -; # repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -; # dump: Dump the Signal source data to a file. Disable this option in this version SignalSource.dump=false SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner -;SignalConditioner.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Pass_Through DataTypeAdapter.item_type=cshort -;DataTypeAdapter.item_type=cbyte ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter -;InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=cshort - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=11 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.48 InputFilter.band2_begin=0.52 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter.sampling_frequency=4000000 InputFilter.IF=0 - +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resampled data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler.sample_freq_out=4000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#count: Number of available Galileo satellite channels. Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#system: GPS, GLONASS, GALILEO, SBAS or COMPASS -;#if the option is disabled by default is assigned GPS -;Channel.system=GPS Channel.signal=1C -;#if the option is disabled by default is assigned "1C" GPS L1 C/A ;Channel0.signal=1C ;Channel1.signal=1C @@ -204,136 +103,54 @@ Channel.signal=1C ;Channel10.signal=1C ;Channel11.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - -;######### CHANNEL 0 CONFIG ############ - -;Channel0.system=GPS -;Channel0.signal=1C - -;#satellite: Satellite PRN ID for this channel. Disable this option to random search -;Channel0.satellite=11 - -;######### CHANNEL 1 CONFIG ############ - -;Channel1.system=GPS -;Channel1.signal=1C -;Channel1.satellite=18 - - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.01 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.00001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=8000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] (should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=30.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=30.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=4.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_USRP_realtime.conf b/conf/gnss-sdr_GPS_L1_USRP_realtime.conf index 8fcb655f8..323feec08 100644 --- a/conf/gnss-sdr_GPS_L1_USRP_realtime.conf +++ b/conf/gnss-sdr_GPS_L1_USRP_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Configuration file for using USRP 1 as a RF front-end for GPS L1 signals. ; Run: ; gnss-sdr --config_file=/path/to/gnss-sdr_GPS_L1_USRP_realtime.conf @@ -6,8 +9,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,362 +23,95 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=UHD_Signal_Source - -;#When left empty, the device discovery routines will search all available transports on the system (ethernet, usb...) ;SignalSource.device_address=192.168.40.2 ; <- PUT THE IP ADDRESS OF YOUR USRP HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=2000000 - -;#freq: RF front-end center frequency in [Hz] SignalSource.freq=1575420000 - -;#gain: Front-end Gain in [dB] SignalSource.gain=60 - -;#subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0) SignalSource.subdevice=A:0 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version SignalSource.dump=false - SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;SignalConditioner.implementation=Signal_Conditioner SignalConditioner.implementation=Pass_Through -;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block -DataTypeAdapter.implementation=Pass_Through - -;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. -InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=2000000 -InputFilter.IF=0 - - - -;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler -Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal -Resampler.sample_freq_in=8000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=2000000 - ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_GPS.count=6 -;#count: Number of available Galileo satellite channels. -Channels_Galileo.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver +Channels_1C.count=6 +Channels_1B.count=0 Channels.in_acquisition=1 -;#system: GPS, GLONASS, GALILEO, SBAS or COMPASS -;#if the option is disabled by default is assigned GPS -Channel.system=GPS + ;#signal: ;# "1C" GPS L1 C/A -;# "1P" GPS L1 P -;# "1W" GPS L1 Z-tracking and similar (AS on) -;# "1Y" GPS L1 Y -;# "1M" GPS L1 M -;# "1N" GPS L1 codeless -;# "2C" GPS L2 C/A -;# "2D" GPS L2 L1(C/A)+(P2-P1) semi-codeless -;# "2S" GPS L2 L2C (M) -;# "2L" GPS L2 L2C (L) -;# "2X" GPS L2 L2C (M+L) -;# "2P" GPS L2 P -;# "2W" GPS L2 Z-tracking and similar (AS on) -;# "2Y" GPS L2 Y -;# "2M" GPS GPS L2 M -;# "2N" GPS L2 codeless -;# "5I" GPS L5 I -;# "5Q" GPS L5 Q -;# "5X" GPS L5 I+Q -;# "1C" GLONASS G1 C/A -;# "1P" GLONASS G1 P -;# "2C" GLONASS G2 C/A (Glonass M) -;# "2P" GLONASS G2 P -;# "1A" GALILEO E1 A (PRS) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "1C" GALILEO E1 C (no data) -;# "1X" GALILEO E1 B+C -;# "1Z" GALILEO E1 A+B+C -;# "5I" GALILEO E5a I (F/NAV OS) -;# "5Q" GALILEO E5a Q (no data) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q -;# "7I" GALILEO E5b I -;# "7Q" GALILEO E5b Q -;# "7X" GALILEO E5b I+Q -;# "8I" GALILEO E5 I -;# "8Q" GALILEO E5 Q -;# "8X" GALILEO E5 I+Q -;# "6A" GALILEO E6 A -;# "6B" GALILEO E6 B -;# "6C" GALILEO E6 C -;# "6X" GALILEO E6 B+C -;# "6Z" GALILEO E6 A+B+C -;# "1C" SBAS L1 C/A -;# "5I" SBAS L5 I -;# "5Q" SBAS L5 Q -;# "5X" SBAS L5 I+Q -;# "2I" COMPASS E2 I -;# "2Q" COMPASS E2 Q -;# "2X" COMPASS E2 IQ -;# "7I" COMPASS E5b I -;# "7Q" COMPASS E5b Q -;# "7X" COMPASS E5b IQ -;# "6I" COMPASS E6 I -;# "6Q" COMPASS E6 Q -;# "6X" COMPASS E6 IQ -;#if the option is disabled by default is assigned "1C" GPS L1 C/A +;# "L5" GPS L5 + Channel.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - -;######### CHANNEL 0 CONFIG ############ - -Channel0.system=GPS -Channel0.signal=1C - -;#satellite: Satellite PRN ID for this channel. Disable this option to random search -Channel0.satellite=11 - -;######### CHANNEL 1 CONFIG ############ - -Channel1.system=GPS -Channel1.signal=1C -Channel1.satellite=18 - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_GPS.dump=false -;#filename: Log path and filename -Acquisition_GPS.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_GPS.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_GPS.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_GPS.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_GPS.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. -Acquisition_GPS.threshold=0.01 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -;Acquisition_GPS.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_GPS.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] -Acquisition_GPS.doppler_step=500 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] (should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) -Acquisition_GPS.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true -Acquisition_GPS.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.01 +;Acquisition_1C.pfa=0.0001 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.bit_transition_flag=false +Acquisition_1C.max_dwells=1 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=30.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] -Tracking_GPS.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. -Tracking_GPS.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_GPS.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_GPS.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_GPS.dump_filename=./tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_GPS.pll_bw_hz=50.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_GPS.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_GPS.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_GPS.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A -TelemetryDecoder_GPS.implementation=GPS_L1_CA_Telemetry_Decoder -TelemetryDecoder_GPS.dump=false -;#decimation factor -TelemetryDecoder_GPS.decimation_factor=1; +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +;#implementation: Position Velocity and Time (PVT) implementation: +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_acq_QuickSync.conf b/conf/gnss-sdr_GPS_L1_acq_QuickSync.conf index cc3ba40a9..fd7b5d8ff 100644 --- a/conf/gnss-sdr_GPS_L1_acq_QuickSync.conf +++ b/conf/gnss-sdr_GPS_L1_acq_QuickSync.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,290 +8,99 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] or [Rtlsdr_Signal_Source] SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. -;#Use gr_complex for 32 bits float I/Q or short for I/Q interleaved short integer. -;#If short is selected you should have to instantiate the Ishort_To_Complex data_type_adapter. - SignalSource.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: Use [Ishort_To_Complex] or [Pass_Through] DataTypeAdapter.implementation=Ishort_To_Complex -;#dump: Dump the filtered data to a file. DataTypeAdapter.dump=false -;#dump_filename: Log path and filename. DataTypeAdapter.dump_filename=../data/data_type_adapter.dat ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -;InputFilter.band1_end=0.8 -InputFilter.band1_end=0.85 -InputFilter.band2_begin=0.90 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=4000000 -InputFilter.IF=0 - +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler.sample_freq_out=4000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available satellite channels. Channels_1C.count=5 -;#in_acquisition: Number of channels simultaneously acquiring Channels.in_acquisition=1 -;######### CHANNEL 0 CONFIG ############ -Channel0.signal=1C -Channel0.satellite=1 -Channel0.repeat_satellite=false - -;######### CHANNEL 1 CONFIG ############ -Channel1.signal=1C -Channel1.satellite=11 -Channel1.repeat_satellite=false - -;######### CHANNEL 2 CONFIG ############ -Channel2.signal=1C -Channel2.satellite=17 -Channel2.repeat_satellite=false - -;######### CHANNEL 3 CONFIG ############ -Channel3.signal=1C -Channel3.satellite=20 -Channel3.repeat_satellite=false - -;######### CHANNEL 4 CONFIG ############ -Channel4.signal=1C -Channel4.satellite=32 -Channel4.repeat_satellite=false - ;######### ACQUISITION GLOBAL CONFIG ############_1C - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=true -;#filename: Log path and filename -;Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent-integration_time_ms=4 - Acquisition_1C.implementation=GPS_L1_CA_PCPS_QuickSync_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent-integration_time_ms=4 +Acquisition_1C.dump=true +;Acquisition_1C.dump_filename=./acq_dump.dat + ;######### ACQUISITION CHANNELS CONFIG ###### -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_QuickSync_Acquisition -;#threshold: Acquisition threshold Acquisition_1C.threshold=0.4 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#repeat_satellite: Use only jointly with the satellte PRN ID option. ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=50.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5 Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=50.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=4.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A. TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea PVT.flag_nmea_tty_port=true PVT.nmea_dump_devname=/dev/pts/4 PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_bladeRF.conf b/conf/gnss-sdr_GPS_L1_bladeRF.conf new file mode 100644 index 000000000..80e9ddda8 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_bladeRF.conf @@ -0,0 +1,108 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=2000000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Osmosdr_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.sampling_frequency=2000000 +SignalSource.freq=1575420000 +;# RF Gain: LNA Gain {0, 3, 6} +SignalSource.gain=6 +;# IF Gain: N/A +SignalSource.rf_gain=40 +;# BB Gain: RX VGA1 + VGA2 [5, 60] +SignalSource.if_gain=48 +SignalSource.AGC_enabled=false +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.osmosdr_args=bladerf=0 ; This line enables the bladeRF +SignalSource.enable_throttle_control=false +SignalSource.dump=false +SignalSource.dump_filename=./signal_source.dat + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Pass_Through + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Freq_Xlating_Fir_Filter +InputFilter.decimation_factor=1 +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.taps_item_type=float +InputFilter.number_of_taps=5 +InputFilter.number_of_bands=2 +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.85 +InputFilter.band2_begin=0.9 +InputFilter.band2_end=1.0 +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 +InputFilter.filter_type=bandpass +InputFilter.grid_density=16 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + +;######### RESAMPLER CONFIG ############ +Resampler.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=1 +Channel.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.015 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + +;######### PVT CONFIG ############ +;PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.iono_model=Broadcast +PVT.trop_model=Saastamoinen +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.rtcm_tcp_port=2101 +PVT.rtcm_MT1019_rate_ms=5000 +PVT.rtcm_MT1077_rate_ms=1000 +PVT.rinex_version=2 diff --git a/conf/gnss-sdr_GPS_L1_fmcomms2_realtime.conf b/conf/gnss-sdr_GPS_L1_fmcomms2_realtime.conf new file mode 100644 index 000000000..b2d0604bb --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_fmcomms2_realtime.conf @@ -0,0 +1,133 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=2000000 + + +;######### SUPL RRLP GPS assistance configuration ##### +; Check http://www.mcc-mnc.com/ +; On Android: https://play.google.com/store/apps/details?id=net.its_here.cellidinfo&hl=en +GNSS-SDR.SUPL_gps_enabled=false +GNSS-SDR.SUPL_read_gps_assistance_xml=false +GNSS-SDR.SUPL_gps_ephemeris_server=supl.google.com +GNSS-SDR.SUPL_gps_ephemeris_port=7275 +GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com +GNSS-SDR.SUPL_gps_acquisition_port=7275 +GNSS-SDR.SUPL_MCC=244 +GNSS-SDR.SUPL_MNC=5 +GNSS-SDR.SUPL_LAC=0x59e2 +GNSS-SDR.SUPL_CI=0x31b0 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Fmcomms2_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.device_address=10.42.0.196 +SignalSource.sampling_frequency=2000000 +SignalSource.freq=1575420000 +SignalSource.bandwidth=2000000 +SignalSource.rx1_enable=true +SignalSource.gain_mode_rx1=manual +SignalSource.rf_port_select=A_BALANCED +SignalSource.gain_rx1=64 +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=../data/signal_source.dat +SignalSource.enable_throttle_control=false + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Pass_Through + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Freq_Xlating_Fir_Filter +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.taps_item_type=float +InputFilter.number_of_taps=5 +InputFilter.number_of_bands=2 +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.45 +InputFilter.band2_begin=0.55 +InputFilter.band2_end=1.0 +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 +InputFilter.filter_type=bandpass +InputFilter.grid_density=16 +InputFilter.sampling_frequency=2000000 +InputFilter.IF=0; IF deviation due to front-end LO inaccuracies [Hz] + +;######### RESAMPLER CONFIG ############ +Resampler.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=5 +Channels.in_acquisition=1 +Channel.signal=1C + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.015 +;Acquisition_1C.pfa=0.0001 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_gr_complex.conf b/conf/gnss-sdr_GPS_L1_gr_complex.conf index 14b57ff0a..7f83c666c 100644 --- a/conf/gnss-sdr_GPS_L1_gr_complex.conf +++ b/conf/gnss-sdr_GPS_L1_gr_complex.conf @@ -1,76 +1,91 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf -; + [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=File_Signal_Source -SignalSource.filename=/datalogger/signals/Agilent/New York/4msps.dat ; <- PUT YOUR FILE HERE -SignalSource.item_type=gr_complex +SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE +SignalSource.item_type=ishort SignalSource.sampling_frequency=4000000 SignalSource.freq=1575420000 -SignalSource.samples=250000000 +SignalSource.samples=0 SignalSource.repeat=false -SignalSource.dump=false -SignalSource.dump_filename=../data/signal_source.dat SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -SignalConditioner.implementation=Pass_Through +SignalConditioner.implementation=Signal_Conditioner + +DataTypeAdapter.implementation=Ishort_To_Complex +DataTypeAdapter.dump=false +DataTypeAdapter.dump_filename=../data/DataTypeAdapter.dat + +InputFilter.implementation=Pass_Through +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex + +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex ;######### CHANNELS GLOBAL CONFIG ############ -Channels_1C.count=8 +Channels_1C.count=5 Channels.in_acquisition=1 Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -Acquisition_1C.threshold=0.005 +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.008 ;Acquisition_1C.pfa=0.01 Acquisition_1C.doppler_max=10000 -Acquisition_1C.doppler_step=500 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + ;######### TRACKING GLOBAL CONFIG ############ -Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ -Tracking_1C.pll_bw_hz=45.0; -Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dump=true +Tracking_1C.dump_filename=epl_tracking_ch_ +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=4.0; Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_c + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false -PVT.output_rate_ms=10 -PVT.display_rate_ms=500 +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=1 +PVT.display_rate_ms=100 PVT.dump_filename=./PVT PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; PVT.flag_nmea_tty_port=false; @@ -79,4 +94,3 @@ PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=false - diff --git a/conf/gnss-sdr_GPS_L1_gr_complex_gpu.conf b/conf/gnss-sdr_GPS_L1_gr_complex_gpu.conf index 885bebd88..33c3a07b6 100644 --- a/conf/gnss-sdr_GPS_L1_gr_complex_gpu.conf +++ b/conf/gnss-sdr_GPS_L1_gr_complex_gpu.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,16 +8,14 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=File_Signal_Source SignalSource.filename=/datalogger/signals/Agilent/New York/4msps.dat ; <- PUT YOUR FILE HERE SignalSource.item_type=gr_complex -SignalSource.sampling_frequency=4000000 -SignalSource.freq=1575420000 SignalSource.samples=250000000 SignalSource.repeat=false SignalSource.dump=false @@ -33,42 +34,43 @@ Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.005 ;Acquisition_1C.pfa=0.01 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + ;######### TRACKING GLOBAL CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking_GPU Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 Tracking_1C.dump=false Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=45.0; Tracking_1C.dll_bw_hz=2.0; Tracking_1C.order=3; + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10 PVT.display_rate_ms=500 PVT.dump_filename=./PVT @@ -79,4 +81,3 @@ PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=false - diff --git a/conf/gnss-sdr_GPS_L1_ishort.conf b/conf/gnss-sdr_GPS_L1_ishort.conf index 95abfc06b..373049a25 100644 --- a/conf/gnss-sdr_GPS_L1_ishort.conf +++ b/conf/gnss-sdr_GPS_L1_ishort.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,18 +8,17 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 ;######### CONTROL_THREAD CONFIG ############ ControlThread.wait_for_flowgraph=false ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=File_Signal_Source -SignalSource.filename=/Users/carlesfernandez/Documents/workspace/code2/trunk/data/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ;/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE +SignalSource.filename=/archive/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE SignalSource.item_type=ishort SignalSource.sampling_frequency=4000000 -SignalSource.freq=1575420000 SignalSource.samples=0 SignalSource.repeat=false SignalSource.dump=false @@ -27,68 +29,59 @@ SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ SignalConditioner.implementation=Signal_Conditioner -;DataTypeAdapter.implementation=Ishort_To_Complex DataTypeAdapter.implementation=Ishort_To_Cshort InputFilter.implementation=Pass_Through -;InputFilter.input_item_type=gr_complex -;InputFilter.output_item_type=gr_complex InputFilter.item_type=cshort -;Resampler.implementation=Pass_Through -;Resampler.item_type=gr_complex Resampler.implementation=Direct_Resampler Resampler.sample_freq_in=4000000 Resampler.sample_freq_out=2000000 -;Resampler.item_type=gr_complex Resampler.item_type=cshort ;######### CHANNELS GLOBAL CONFIG ############ Channels_1C.count=8 Channels.in_acquisition=1 Channel.signal=1C -;Channel.item_type=cshort ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=cshort -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=cshort +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.008 ;Acquisition_1C.pfa=0.000001 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=250 -Acquisition_1C.tong_init_val=2 -Acquisition_1C.tong_max_val=10 -Acquisition_1C.tong_max_dwells=20 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat +Acquisition_1C.blocking=false; ;######### TRACKING GLOBAL CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking Tracking_1C.item_type=cshort -Tracking_1C.if=0 -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=40.0; Tracking_1C.dll_bw_hz=4.0; Tracking_1C.order=3; +Tracking_1C.dump=false; +Tracking_1C.dump_filename=./epl_tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables -Observables.dump=false +Observables.implementation=Hybrid_Observables +Observables.dump=true Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false -PVT.output_rate_ms=10 +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 PVT.display_rate_ms=500 PVT.dump_filename=./PVT PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; diff --git a/conf/gnss-sdr_GPS_L1_nsr.conf b/conf/gnss-sdr_GPS_L1_nsr.conf index f7d4358d3..4b0b05ae2 100644 --- a/conf/gnss-sdr_GPS_L1_nsr.conf +++ b/conf/gnss-sdr_GPS_L1_nsr.conf @@ -1,5 +1,8 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Sample configuration file for IFEN SX-NSR software receiver front-end -; http://www.ifen.com/products/sx-scientific-gnss-solutions/nsr-software-receiver.html +; https://www.ifen.com/products/sx3-gnss-software-receiver/ ; This sample configuration is able to process directly .sream binary files ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf @@ -8,8 +11,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2560000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2560000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -22,16 +25,15 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=Nsr_File_Signal_Source -SignalSource.filename=/datalogger/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE +SignalSource.filename=/home/javier/Descargas/RoofTop_FE0_Band1.stream ; <- PUT YOUR FILE HERE SignalSource.item_type=byte SignalSource.sampling_frequency=20480000 -SignalSource.freq=1575420000 SignalSource.samples=0 SignalSource.repeat=false SignalSource.dump=false @@ -68,7 +70,8 @@ InputFilter.band2_error=1.0 InputFilter.filter_type=bandpass InputFilter.grid_density=16 InputFilter.sampling_frequency=20480000 -InputFilter.IF=5499998.47412109 +#InputFilter.IF=5499998.47412109 +InputFilter.IF=5679999.2370605494 InputFilter.decimation_factor=8 @@ -80,51 +83,74 @@ Resampler.item_type=gr_complex ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_1C.count=8 +Channels_1C.count=0 +Channels_2S.count=8 Channels.in_acquisition=1 -Channel.signal=1C ;######### GPS ACQUISITION CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.scoherent_integration_time_ms=1 Acquisition_1C.threshold=0.0075 ;Acquisition_1C.pfa=0.01 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.coherent_integration_time_ms=20 +Acquisition_2S.threshold=0.00045 +Acquisition_2S.doppler_max=5000 +Acquisition_2S.doppler_step=100 +Acquisition_2S.bit_transition_flag=false +Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat ;######### TRACKING GPS CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=45.0; Tracking_1C.dll_bw_hz=2.0; Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + +;######### GPS L2C GENERIC TRACKING CONFIG ############ +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking +Tracking_2S.item_type=gr_complex +Tracking_2S.pll_bw_hz=1.5; +Tracking_2S.dll_bw_hz=0.4; +Tracking_2S.order=2; +Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=true +Tracking_2S.dump_filename=../data/epl_tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder +TelemetryDecoder_2S.dump=false + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false -PVT.output_rate_ms=10 +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 PVT.display_rate_ms=500 PVT.dump_filename=./PVT PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; @@ -134,4 +160,3 @@ PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=true - diff --git a/conf/gnss-sdr_GPS_L1_nsr_kf.conf b/conf/gnss-sdr_GPS_L1_nsr_kf.conf new file mode 100644 index 000000000..d2a84cd9f --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_nsr_kf.conf @@ -0,0 +1,211 @@ +; Default configuration file +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +;GNSS-SDR.internal_fs_sps=6826700 +GNSS-SDR.internal_fs_sps=2560000 +;GNSS-SDR.internal_fs_sps=4096000 +;GNSS-SDR.internal_fs_sps=5120000 + +;######### SIGNAL_SOURCE CONFIG ############ +;#implementation: Use [File_Signal_Source] [Nsr_File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) +SignalSource.implementation=Nsr_File_Signal_Source + +;#filename: path to file with the captured GNSS signal samples to be processed +SignalSource.filename=/home/javier/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE + +;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.item_type=byte + +;#sampling_frequency: Original Signal sampling frequency in [Hz] +SignalSource.sampling_frequency=20480000 + +;#freq: RF front-end center frequency in [Hz] +SignalSource.freq=1575420000 + +;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. +SignalSource.samples=0 + +;#repeat: Repeat the processing file. Disable this option in this version +SignalSource.repeat=false + +;#dump: Dump the Signal source data to a file. Disable this option in this version +SignalSource.dump=false + +SignalSource.dump_filename=../data/signal_source.dat + + +;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. +; it helps to not overload the CPU, but the processing time will be longer. +SignalSource.enable_throttle_control=false + + +;######### SIGNAL_CONDITIONER CONFIG ############ +;## It holds blocks to change data type, filter and resample input data. + +;#implementation: Use [Pass_Through] or [Signal_Conditioner] +;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks +;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +;## Changes the type of input data. +;#implementation: [Pass_Through] disables this block +DataTypeAdapter.implementation=Pass_Through +DataTypeAdapter.item_type=float + +;######### INPUT_FILTER CONFIG ############ +;## Filter the input data. Can be combined with frequency translation for IF signals + +;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] +;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation +;# that shifts IF down to zero Hz. + +InputFilter.implementation=Freq_Xlating_Fir_Filter + +;#dump: Dump the filtered data to a file. +InputFilter.dump=false + +;#dump_filename: Log path and filename. +InputFilter.dump_filename=../data/input_filter.dat + +;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. +;#These options are based on parameters of gnuradio's function: gr_remez. +;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse +;#reponse given a set of band edges, the desired reponse on those bands, +;#and the weight given to the error in those bands. + +;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. +InputFilter.input_item_type=float + +;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. +InputFilter.output_item_type=gr_complex + +;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. +InputFilter.taps_item_type=float + +;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time +InputFilter.number_of_taps=5 + +;#number_of _bands: Number of frequency bands in the filter. +InputFilter.number_of_bands=2 + +;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. +;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) +;#The number of band_begin and band_end elements must match the number of bands + +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.45 +InputFilter.band2_begin=0.55 +InputFilter.band2_end=1.0 + +;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. +;#The number of ampl_begin and ampl_end elements must match the number of bands + +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 + +;#band_error: weighting applied to each band (usually 1). +;#The number of band_error elements must match the number of bands +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 + +;#filter_type: one of "bandpass", "hilbert" or "differentiator" +InputFilter.filter_type=bandpass + +;#grid_density: determines how accurately the filter will be constructed. +;The minimum value is 16; higher values are slower to compute the filter. +InputFilter.grid_density=16 + +;# Original sampling frequency stored in the signal file +InputFilter.sampling_frequency=20480000 + +;#The following options are used only in Freq_Xlating_Fir_Filter implementation. +;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz + +InputFilter.IF=5499998.47412109 + +;# Decimation factor after the frequency tranaslating block +InputFilter.decimation_factor=8 + + +;######### RESAMPLER CONFIG ############ +;## Resamples the input data. + +;#implementation: Use [Pass_Through] or [Direct_Resampler] +;#[Pass_Through] disables this block +;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation +Resampler.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +;#count: Number of available GPS satellite channels. +Channels_1C.count=8 +Channels.in_acquisition=1 +#Channel.signal=1C + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat +Acquisition_1C.item_type=gr_complex +Acquisition_1C.if=0 +Acquisition_1C.sampled_ms=1 +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +;#use_CFAR_algorithm: If enabled, acquisition estimates the input signal power to implement CFAR detection algorithms +;#notice that this affects the Acquisition threshold range! +Acquisition_1C.use_CFAR_algorithm=false; +;#threshold: Acquisition threshold +Acquisition_1C.threshold=10 +;Acquisition_1C.pfa=0.01 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=100 + + +;######### TRACKING GPS CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_KF_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.if=0 +Tracking_1C.dump=true +Tracking_1C.dump_filename=../data/epl_tracking_ch_ +Tracking_1C.pll_bw_hz=15.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false +TelemetryDecoder_1C.decimation_factor=1; + +;######### OBSERVABLES CONFIG ############ +;#implementation: +Observables.implementation=Hybrid_Observables + +;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.dump=false + +;#dump_filename: Log path and filename. +Observables.dump_filename=./observables.dat + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=true diff --git a/conf/gnss-sdr_GPS_L1_nsr_twobit_packed.conf b/conf/gnss-sdr_GPS_L1_nsr_twobit_packed.conf index 06cbb8e7d..dfe6e331a 100644 --- a/conf/gnss-sdr_GPS_L1_nsr_twobit_packed.conf +++ b/conf/gnss-sdr_GPS_L1_nsr_twobit_packed.conf @@ -1,5 +1,8 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Sample configuration file for IFEN SX-NSR software receiver front-end -; http://www.ifen.com/products/sx-scientific-gnss-solutions/nsr-software-receiver.html +; https://www.ifen.com/products/sx3-gnss-software-receiver/ ; This sample configuration is able to process directly .sream binary files ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf @@ -8,8 +11,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2560000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2560000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -22,7 +25,7 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 @@ -46,7 +49,6 @@ SignalSource.big_endian_bytes=false ; This setting specifies which of the three cases holds for this data file SignalSource.sample_type=real SignalSource.sampling_frequency=20480000 -SignalSource.freq=1575420000 SignalSource.samples=0 SignalSource.repeat=false SignalSource.dump=false @@ -95,50 +97,49 @@ Resampler.item_type=gr_complex ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 Channels.in_acquisition=1 Channel.signal=1C ;######### GPS ACQUISITION CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.sampled_ms=1 Acquisition_1C.threshold=0.0075 ;Acquisition_1C.pfa=0.01 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GPS CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=45.0; Tracking_1C.dll_bw_hz=2.0; Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10 PVT.display_rate_ms=500 PVT.dump_filename=./PVT @@ -149,4 +150,3 @@ PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=true - diff --git a/conf/gnss-sdr_GPS_L1_plutosdr_realtime.conf b/conf/gnss-sdr_GPS_L1_plutosdr_realtime.conf new file mode 100644 index 000000000..872f56bf4 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_plutosdr_realtime.conf @@ -0,0 +1,102 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [sps]. +;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE +; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ +GNSS-SDR.internal_fs_sps=2000000 + + +;######### SUPL RRLP GPS assistance configuration ##### +; Check http://www.mcc-mnc.com/ +; On Android: https://play.google.com/store/apps/details?id=net.its_here.cellidinfo&hl=en +GNSS-SDR.SUPL_gps_enabled=false +GNSS-SDR.SUPL_read_gps_assistance_xml=false +GNSS-SDR.SUPL_gps_ephemeris_server=supl.google.com +GNSS-SDR.SUPL_gps_ephemeris_port=7275 +GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com +GNSS-SDR.SUPL_gps_acquisition_port=7275 +GNSS-SDR.SUPL_MCC=244 +GNSS-SDR.SUPL_MNC=5 +GNSS-SDR.SUPL_LAC=0x59e2 +GNSS-SDR.SUPL_CI=0x31b0 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Plutosdr_Signal_Source +SignalSource.item_type=gr_complex +SignalSource.device_address=192.168.2.1 +SignalSource.sampling_frequency=3000000 +SignalSource.freq=1575420000 +SignalSource.bandwidth=2600000 +SignalSource.gain_mode=manual +SignalSource.gain=30 +SignalSource.samples=0 +SignalSource.buffer_size=65000 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=./capture.dat +SignalSource.enable_throttle_control=false + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Direct_Resampler +Resampler.sample_freq_in=4000000 +Resampler.sample_freq_out=2000000 +Resampler.item_type=gr_complex + + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Pass_Through +DataTypeAdapter.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=6 +Channels.in_acquisition=1 +Channel.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=0.008 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=4.0; + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_pulse_blanking_gr_complex.conf b/conf/gnss-sdr_GPS_L1_pulse_blanking_gr_complex.conf new file mode 100644 index 000000000..618341f48 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_pulse_blanking_gr_complex.conf @@ -0,0 +1,110 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 + +;######### CONTROL_THREAD CONFIG ############ +ControlThread.wait_for_flowgraph=false + +;######### SUPL RRLP GPS assistance configuration ##### +GNSS-SDR.SUPL_gps_enabled=false +GNSS-SDR.SUPL_read_gps_assistance_xml=true +GNSS-SDR.SUPL_gps_ephemeris_server=supl.nokia.com +GNSS-SDR.SUPL_gps_ephemeris_port=7275 +GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com +GNSS-SDR.SUPL_gps_acquisition_port=7275 +GNSS-SDR.SUPL_MCC=244 +GNSS-SDR.SUPL_MNC=5 +GNSS-SDR.SUPL_LAC=0x59e2 +GNSS-SDR.SUPL_CI=0x31b0 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/home/javier/signals/signal_source_int.dat +SignalSource.item_type=gr_complex +SignalSource.sampling_frequency=2000000 +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=dump.dat +SignalSource.enable_throttle_control=false + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Pulse_Blanking_Filter +InputFilter.Pfa=0.001 +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=8 +Channels.in_acquisition=8 +Channel.signal=1C + + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.use_CFAR_algorithm=false; +Acquisition_1C.threshold=20 +;Acquisition_1C.pfa=0.01 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### TRACKING GPS CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.extend_correlation_ms=10 +Tracking_1C.pll_bw_hz=35; +Tracking_1C.pll_bw_narrow_hz=30; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dll_bw_narrow_hz=1.5; +Tracking_1C.fll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.dump=true +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=true +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=1 +PVT.display_rate_ms=100 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/conf/gnss-sdr_GPS_L1_rtl_tcp_realtime.conf b/conf/gnss-sdr_GPS_L1_rtl_tcp_realtime.conf index 946176ce3..4b91a9344 100644 --- a/conf/gnss-sdr_GPS_L1_rtl_tcp_realtime.conf +++ b/conf/gnss-sdr_GPS_L1_rtl_tcp_realtime.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,10 +8,10 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. ;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE ; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ -GNSS-SDR.internal_fs_hz=1200000 +GNSS-SDR.internal_fs_sps=1200000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -22,137 +24,55 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5_1C +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] [Osmosdr_Signal_Source] +;#implementation SignalSource.implementation=RtlTcp_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -SignalSource.item_type=gr_complex - -;#sampling_frequency: Original Signal sampling frequency in [Hz] -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ SignalSource.sampling_frequency=1200000 - -;#freq: RF front-end center frequency in [Hz] SignalSource.freq=1575420000 - -;#gain: Front-end overall gain Gain in [dB] SignalSource.gain=40 - -;#rf_gain: Front-end RF stage gain in [dB] SignalSource.rf_gain=40 - -;#rf_gain: Front-end IF stage gain in [dB] SignalSource.if_gain=30 - -;#AGC_enabled: Front-end AGC enabled or disabled SignalSource.AGC_enabled = false - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version SignalSource.dump=false - SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false - -;#Address of the rtl_tcp server (IPv6 allowed) SignalSource.address=127.0.0.1 - -;#Port of the rtl_tcp server SignalSource.port=1234 - -;# Set to true if I/Q samples come swapped SignalSource.swap_iq=false -;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks +;######### SIGNAL_CONDITIONER CONFIG ############ SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Pass_Through ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter.dump=false - -;#dump_filename: Log path and filename. InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.45 InputFilter.band2_begin=0.55 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 ;#The following options are used only in Freq_Xlating_Fir_Filter implementation. @@ -160,133 +80,70 @@ InputFilter.grid_density=16 ;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE ; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter.sampling_frequency=1200000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter.IF=80558 + ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. -;# DISABLED IN THE RTL-SDR REALTIME -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block Resampler.implementation=Pass_Through + ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=4 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler -;#threshold: Acquisition threshold +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms =1 Acquisition_1C.threshold=0.015 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_min=-10000 -;#doppler_step Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 -;#maximum dwells Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] [GPS_L1_CA_DLL_PLL_Optim_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +;#implementation: +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +;#implementation: Position Velocity and Time (PVT) implementation: +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=true +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_rtlsdr_realtime.conf b/conf/gnss-sdr_GPS_L1_rtlsdr_realtime.conf index 51f75907f..2cec70e8c 100644 --- a/conf/gnss-sdr_GPS_L1_rtlsdr_realtime.conf +++ b/conf/gnss-sdr_GPS_L1_rtlsdr_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,10 +8,10 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. ;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE ; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ -GNSS-SDR.internal_fs_hz=1999898 +GNSS-SDR.internal_fs_sps=1999898 ;######### SUPL RRLP GPS assistance configuration ##### @@ -21,15 +24,14 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=Osmosdr_Signal_Source -;SignalSource.filename=/media/DATALOGGER_/signals/RTL-SDR/geo/pmt4.dat SignalSource.item_type=gr_complex -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE +; FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE ; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ SignalSource.sampling_frequency=2000000 SignalSource.freq=1575420000 @@ -43,6 +45,19 @@ SignalSource.dump=false SignalSource.dump_filename=../data/signal_source.dat SignalSource.enable_throttle_control=false +;# Please note that the new RTL-SDR Blog V3 dongles ship a < 1 PPM +;# temperature compensated oscillator (TCXO), which is well suited for GNSS +;# signal processing, and a 4.5 V powered bias-tee to feed an active antenna. +;# Whether the bias-tee is turned off before reception depends on which version +;# of gr-osmosdr was used when compiling GNSS-SDR. With an old version +;# (for example, v0.1.4-8), the utility rtl_biast may be used to switch the +;# bias-tee, and then call gnss-sdr. +;# See https://github.com/rtlsdrblog/rtl_biast +;# After reception the bias-tee is switched off automatically by the program. +;# With newer versions of gr-osmosdr (>= 0.1.4-13), the bias-tee can be +;# activated by uncommenting the following line: +;SignalSource.osmosdr_args=rtl,bias=1 + ;######### SIGNAL_CONDITIONER CONFIG ############ SignalConditioner.implementation=Signal_Conditioner @@ -76,10 +91,6 @@ InputFilter.sampling_frequency=1999898 InputFilter.IF=80558 ; IF deviation due to front-end LO inaccuracies [Hz] ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. -;# DISABLED IN THE RTL-SDR REALTIME -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block Resampler.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ @@ -89,24 +100,22 @@ Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.015 ;Acquisition_1C.pfa=0.0001 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_min=-10000 Acquisition_1C.doppler_step=500 Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 Tracking_1C.dump=false Tracking_1C.dump_filename=./tracking_ch_ Tracking_1C.pll_bw_hz=40.0; @@ -114,26 +123,23 @@ Tracking_1C.dll_bw_hz=2.0; Tracking_1C.order=3; Tracking_1C.early_late_space_chips=0.5; + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 PVT.display_rate_ms=500 PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L1_two_bits_cpx.conf b/conf/gnss-sdr_GPS_L1_two_bits_cpx.conf index 0f2521786..b58fc57ba 100644 --- a/conf/gnss-sdr_GPS_L1_two_bits_cpx.conf +++ b/conf/gnss-sdr_GPS_L1_two_bits_cpx.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=3200000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=3200000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -19,7 +22,7 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 @@ -28,7 +31,6 @@ SignalSource.implementation=Two_Bit_Cpx_File_Signal_Source SignalSource.filename=/datalogger/captures/ajith/test1_two_cpx_live.dat ; <- PUT YOUR FILE HERE SignalSource.item_type=byte SignalSource.sampling_frequency=19200000 -SignalSource.freq=1575420000 SignalSource.samples=0 SignalSource.repeat=false SignalSource.dump=false @@ -45,8 +47,6 @@ DataTypeAdapter.item_type=gr_complex ;######### INPUT_FILTER CONFIG ############ InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.dump=false -InputFilter.dump_filename=../data/input_filter.dat InputFilter.input_item_type=gr_complex InputFilter.output_item_type=gr_complex InputFilter.taps_item_type=float @@ -67,6 +67,9 @@ InputFilter.grid_density=16 InputFilter.sampling_frequency=19200000 InputFilter.IF=4024000 InputFilter.decimation_factor=6 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + ;######### RESAMPLER CONFIG ############ Resampler.implementation=Pass_Through @@ -82,46 +85,45 @@ Channel.signal=1C ;######### GPS ACQUISITION CONFIG ############ -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.sampled_ms=1 Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fine_Doppler +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.007 ;Acquisition_1C.pfa=0.0001 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_min=-10000 Acquisition_1C.doppler_step=500 Acquisition_1C.max_dwells=15 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GPS CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=true -Tracking_1C.dump_filename=./tracking_ch_ Tracking_1C.pll_bw_hz=40.0; Tracking_1C.dll_bw_hz=1.5; Tracking_1C.order=3; +Tracking_1C.dump=true +Tracking_1C.dump_filename=./tracking_ch ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10 PVT.display_rate_ms=500 PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L2C_USRP1_realtime.conf b/conf/gnss-sdr_GPS_L2C_USRP1_realtime.conf index 3b2629bdd..cce644be9 100644 --- a/conf/gnss-sdr_GPS_L2C_USRP1_realtime.conf +++ b/conf/gnss-sdr_GPS_L2C_USRP1_realtime.conf @@ -1,12 +1,16 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Configuration file for using USRP1 as a RF front-end for GPS L2C signals ; Run: ; gnss-sdr --config_file=/path/to/gnss-sdr_GPS_L2C_USRP1_realtime.conf ; + [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -19,7 +23,7 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 @@ -46,79 +50,30 @@ DataTypeAdapter.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.45 InputFilter.band2_begin=0.55 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter.sampling_frequency=20000000 - InputFilter.IF=-1600000 - -;# Decimation factor after the frequency tranaslating block InputFilter.decimation_factor=1 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + ;######### RESAMPLER CONFIG ############ Resampler.implementation=Pass_Through @@ -130,9 +85,7 @@ Resampler.sample_freq_out=2000000 ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_2S.count=1 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 Channel.signal=2S @@ -151,36 +104,33 @@ Channel7.signal=2S ;Channel11.signal=2S - ;######### ACQUISITION GLOBAL CONFIG ############ - -;# GPS L2C M -Acquisition_2S.dump=false -Acquisition_2S.dump_filename=./acq_dump.dat -Acquisition_2S.item_type=gr_complex -Acquisition_2S.if=0 Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex Acquisition_2S.threshold=0.0013 ;Acquisition_2S.pfa=0.001 Acquisition_2S.doppler_max=10000 -Acquisition_2S.doppler_min=-10000 Acquisition_2S.doppler_step=100 Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat + +;######### TRACKING GLOBAL CONFIG ############ Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking Tracking_2S.item_type=gr_complex -Tracking_2S.if=0 -Tracking_2S.dump=true -Tracking_2S.dump_filename=./tracking_ch_ Tracking_2S.pll_bw_hz=1.5; Tracking_2S.dll_bw_hz=0.3; Tracking_2S.order=3; Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=true +Tracking_2S.dump_filename=./tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder TelemetryDecoder_2S.dump=false -TelemetryDecoder_2S.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############. Observables.implementation=Hybrid_Observables @@ -189,9 +139,10 @@ Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=Hybrid_PVT -PVT.averaging_depth=10 -PVT.flag_averaging=true +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 PVT.display_rate_ms=500 PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_GPS_L2C_USRP_X300_realtime.conf b/conf/gnss-sdr_GPS_L2C_USRP_X300_realtime.conf index 838b7d505..49868f37a 100644 --- a/conf/gnss-sdr_GPS_L2C_USRP_X300_realtime.conf +++ b/conf/gnss-sdr_GPS_L2C_USRP_X300_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Configuration file for using USRP X300 as a RF front-end for GPS L2C signals ; Set SignalSource.device_address to the IP address of your device ; and run: @@ -7,8 +10,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SUPL RRLP GPS assistance configuration ##### ; Check http://www.mcc-mnc.com/ @@ -20,7 +23,7 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 @@ -50,8 +53,6 @@ DataTypeAdapter.item_type=cshort ;######### INPUT_FILTER CONFIG ############ InputFilter.implementation=Fir_Filter -InputFilter.dump=false -InputFilter.dump_filename=../data/input_filter.dat InputFilter.input_item_type=cshort InputFilter.output_item_type=gr_complex InputFilter.taps_item_type=float @@ -76,6 +77,9 @@ InputFilter.grid_density=16 InputFilter.sampling_frequency=4000000 InputFilter.IF=0 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + ;######### RESAMPLER CONFIG ############ Resampler.implementation=Pass_Through Resampler.dump=false @@ -86,9 +90,7 @@ Resampler.sample_freq_out=4000000 ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_2S.count=1 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 Channel.signal=2S @@ -106,37 +108,35 @@ Channel7.signal=2S ;Channel10.signal=2S ;Channel11.signal=2S - - ;######### ACQUISITION GLOBAL CONFIG ############ ;# GPS L2C M -Acquisition_2S.dump=false -Acquisition_2S.dump_filename=./acq_dump.dat -Acquisition_2S.item_type=gr_complex -Acquisition_2S.if=0 Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex Acquisition_2S.threshold=0.0015 ;Acquisition_2S.pfa=0.001 Acquisition_2S.doppler_max=5000 Acquisition_2S.doppler_min=-5000 Acquisition_2S.doppler_step=60 Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat + Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking Tracking_2S.item_type=gr_complex -Tracking_2S.if=0 -Tracking_2S.dump=true -Tracking_2S.dump_filename=./tracking_ch_ Tracking_2S.pll_bw_hz=2.0; Tracking_2S.dll_bw_hz=0.25; Tracking_2S.order=2; Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=true +Tracking_2S.dump_filename=./tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder TelemetryDecoder_2S.dump=true -TelemetryDecoder_2S.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############. Observables.implementation=Hybrid_Observables @@ -145,12 +145,12 @@ Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=Hybrid_PVT -PVT.averaging_depth=10 -PVT.flag_averaging=true +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 PVT.display_rate_ms=500 -PVT.dump_filename=./PVT PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; PVT.flag_nmea_tty_port=false; PVT.nmea_dump_devname=/dev/pts/4 @@ -158,3 +158,4 @@ PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Galileo_E1_USRP_X300_realtime.conf b/conf/gnss-sdr_Galileo_E1_USRP_X300_realtime.conf index 5fbe59f95..2207039da 100644 --- a/conf/gnss-sdr_Galileo_E1_USRP_X300_realtime.conf +++ b/conf/gnss-sdr_Galileo_E1_USRP_X300_realtime.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; Configuration file for using USRP X300 as a RF front-end for Galileo E1 signals. ; Set SignalSource.device_address to the IP address of your device ; and run: @@ -7,8 +10,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ @@ -24,59 +27,65 @@ SignalSource.dump=false SignalSource.dump_filename=../data/signal_source.dat SignalSource.enable_throttle_control=false + ;######### SIGNAL_CONDITIONER CONFIG ############ SignalConditioner.implementation=Pass_Through + ;######### CHANNELS GLOBAL CONFIG ###### Channels_1B.count=4 Channels.in_acquisition=1 Channel.signal=1B + ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1B.dump=false -Acquisition_1B.dump_filename=./acq_dump.dat -Acquisition_1B.item_type=gr_complex -Acquisition_1B.if=0 -Acquisition_1B.sampled_ms=4 Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=1 Acquisition_1B.pfa=0.000008 Acquisition_1B.doppler_max=6000 Acquisition_1B.doppler_step=250 Acquisition_1B.cboc=false +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GLOBAL CONFIG ############ Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking Tracking_1B.item_type=gr_complex -Tracking_1B.if=0 -Tracking_1B.dump=false -Tracking_1B.dump_filename=../data/veml_tracking_ch_ Tracking_1B.pll_bw_hz=20.0; Tracking_1B.dll_bw_hz=2.0; Tracking_1B.order=3; Tracking_1B.early_late_space_chips=0.15; Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ + ;######### TELEMETRY DECODER CONFIG ############ TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=Galileo_E1B_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat + ;######### PVT CONFIG ############ -PVT.implementation=GALILEO_E1_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; PVT.display_rate_ms=500; -PVT.dump=false -PVT.dump_filename=./PVT PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea PVT.flag_nmea_tty_port=true PVT.nmea_dump_devname=/dev/pts/4 PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Galileo_E1_acq_QuickSync.conf b/conf/gnss-sdr_Galileo_E1_acq_QuickSync.conf index 59059be2b..8ed21451f 100644 --- a/conf/gnss-sdr_Galileo_E1_acq_QuickSync.conf +++ b/conf/gnss-sdr_Galileo_E1_acq_QuickSync.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,288 +8,91 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] or [Rtlsdr_Signal_Source] SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. -;#Use gr_complex for 32 bits float I/Q or ishort for I/Q interleaved short integer. -;#If ishort is selected you should have to instantiate the Ishort_To_Complex data_type_adapter. SignalSource.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: Use [Ishort_To_Complex] or [Pass_Through] DataTypeAdapter.implementation=Ishort_To_Complex -;#dump: Dump the filtered data to a file. DataTypeAdapter.dump=false -;#dump_filename: Log path and filename. DataTypeAdapter.dump_filename=../data/data_type_adapter.dat ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. -InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -#used for gps -InputFilter.band1_begin=0.0 -;InputFilter.band1_end=0.8 -InputFilter.band1_end=0.85 -InputFilter.band2_begin=0.90 -InputFilter.band2_end=1.0 - -#used for galileo -InputFilter.band1_begin=0.0 -;InputFilter.band1_end=0.8 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=4000000 -InputFilter.IF=0 - - ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. Resampler.dump=false -;#dump_filename: Log path and filename. Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex -;#sample_freq_in: the sample frequency of the input signal -Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=4000000 - ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available satellite channels. Channels_1B.count=4 -;#in_acquisition: Number of channels simultaneously acquiring Channels.in_acquisition=1 Channel.signal=1B ;######### ACQUISITION GLOBAL CONFIG ############ -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.coherent_integration_time_ms=4 - Acquisition_1B.implementation=Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition - -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 Acquisition_1B.threshold=0.05 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms]; Acquisition_1B.coherent_integration_time_ms=8 - Acquisition_1B.cboc=false +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=true - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. +Tracking_1B.pll_bw_hz=20.0; +Tracking_1B.dll_bw_hz=2.0; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false Tracking_1B.dump_filename=../data/veml_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1B.pll_bw_hz=20.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo -Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] -Tracking_1B.very_early_late_space_chips=0.6; - ;######### TELEMETRY DECODER CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A or [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false ;######### OBSERVABLES CONFIG ############ -;#implementation: -Observables.implementation=Galileo_E1B_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: -PVT.implementation=GALILEO_E1_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=100 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. PVT.dump_filename=./PVT - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump, ".kml" and ".geojson" to GIS-friendly formats. PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enables or disables the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=true; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - -;#flag_rtcm_server: Enables or disables a TCP/IP server transmitting RTCM 3.2 messages (accepts multiple clients, port 2101 by default) PVT.flag_rtcm_server=false; - -;#flag_rtcm_tty_port: Enables or disables the RTCM log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_rtcm_tty_port=false; - -;#rtcm_dump_devname: serial device descriptor for RTCM logging PVT.rtcm_dump_devname=/dev/pts/1 diff --git a/conf/gnss-sdr_Galileo_E1_ishort.conf b/conf/gnss-sdr_Galileo_E1_ishort.conf index e26cdf15f..ff0f52a5a 100644 --- a/conf/gnss-sdr_Galileo_E1_ishort.conf +++ b/conf/gnss-sdr_Galileo_E1_ishort.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,291 +8,100 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed -SignalSource.filename=/Users/carlesfernandez/Documents/workspace/code2/trunk/data/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ;/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. +SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE SignalSource.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. -SignalSource.enable_throttle_control=false +SignalSource.enable_throttle_control=true ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Ishort_To_Complex ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of GNU Radio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired response on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. InputFilter.output_item_type=gr_complex -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=4000000 -InputFilter.IF=0 - - - ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neighborhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resampled data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler.sample_freq_out=4000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available Galileo satellite channels. Channels_1B.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 Channel.signal=1B + ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_1B.pfa=0.000002 -;#doppler_max: Maximum expected Doppler shift [Hz] +Acquisition_1B.pfa=0.00001 Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 - -;######### ACQUISITION CHANNELS CONFIG ###### - -;######### ACQUISITION CH 0 CONFIG ############ - -;#repeat_satellite: Use only jointly with the satellite PRN ID option. The default value is false -;Acquisition_1B0.repeat_satellite = true -;Acquisition_1B1.repeat_satellite = true -;Acquisition_1B2.repeat_satellite = true -;Acquisition_1B3.repeat_satellite = true - -;#cboc: Only for [Galileo_E1_PCPS_Ambiguous_Acquisition]. This option allows you to choose between acquiring with CBOC signal [true] or sinboc(1,1) signal [false]. -;#Use only if GNSS-SDR.internal_fs_hz is greater than or equal to 6138000 Acquisition_1B.cboc=false - +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat +Acquisition_1B.blocking=false ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_FLL_PLL_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1B.dll_bw_hz=2.0; - -;#fll_bw_hz: FLL loop filter bandwidth [Hz] -Tracking_1B.fll_bw_hz=10.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo +Tracking_1B.dump=true +Tracking_1B.dump_filename=./veml_tracking_ch_ +Tracking_1B.pll_bw_hz=20.0; +Tracking_1B.dll_bw_hz=3.0; Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.track_pilot=true +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A or [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=Galileo_E1B_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GALILEO_E1_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=100 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump, ".kml" and ".geojson" to GIS-friendly formats. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enables or disables the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) -PVT.flag_nmea_tty_port=true; - -;#nmea_dump_devname: serial device descriptor for NMEA logging +PVT.flag_nmea_tty_port=true PVT.nmea_dump_devname=/dev/pts/4 - -;#flag_rtcm_server: Enables or disables a TCP/IP server transmitting RTCM 3.2 messages (accepts multiple clients, port 2101 by default) PVT.flag_rtcm_server=true; PVT.rtcm_tcp_port=2101 PVT.rtcm_MT1045_rate_ms=5000 PVT.rtcm_MSM_rate_ms=1000 - -;#flag_rtcm_tty_port: Enables or disables the RTCM log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_rtcm_tty_port=false; - -;#rtcm_dump_devname: serial device descriptor for RTCM logging PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Galileo_E1_nsr.conf b/conf/gnss-sdr_Galileo_E1_nsr.conf index a4b37d02e..b95b2a972 100644 --- a/conf/gnss-sdr_Galileo_E1_nsr.conf +++ b/conf/gnss-sdr_Galileo_E1_nsr.conf @@ -1,3 +1,6 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -5,11 +8,11 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -;GNSS-SDR.internal_fs_hz=6826700 -GNSS-SDR.internal_fs_hz=2560000 -;GNSS-SDR.internal_fs_hz=4096000 -;GNSS-SDR.internal_fs_hz=5120000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +;GNSS-SDR.internal_fs_sps=6826700 +GNSS-SDR.internal_fs_sps=2560000 +;GNSS-SDR.internal_fs_sps=4096000 +;GNSS-SDR.internal_fs_sps=5120000 ;######### SIGNAL_SOURCE CONFIG ############ @@ -17,21 +20,14 @@ SignalSource.implementation=Nsr_File_Signal_Source SignalSource.filename=/datalogger/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE SignalSource.item_type=byte SignalSource.sampling_frequency=20480000 -SignalSource.freq=1575420000 SignalSource.samples=0 ; 0 means the entire file SignalSource.repeat=false SignalSource.dump=false SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ @@ -40,8 +36,6 @@ DataTypeAdapter.item_type=float ;######### INPUT_FILTER CONFIG ############ InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.dump=false -InputFilter.dump_filename=../data/input_filter.dat InputFilter.input_item_type=float InputFilter.output_item_type=gr_complex InputFilter.taps_item_type=float @@ -65,6 +59,8 @@ InputFilter.grid_density=16 InputFilter.sampling_frequency=20480000 InputFilter.IF=5499998.47412109 InputFilter.decimation_factor=8 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ @@ -78,43 +74,45 @@ Channel.signal=1B ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_1B.dump=false -Acquisition_1B.dump_filename=./acq_dump.dat -Acquisition_1B.item_type=gr_complex -Acquisition_1B.if=0 -Acquisition_1B.sampled_ms=4 Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 Acquisition_1B.pfa=0.0000008 Acquisition_1B.doppler_max=15000 Acquisition_1B.doppler_step=125 -Acquisition_1B.cboc=false ; This option allows you to choose between acquiring with CBOC signal [true] or sinboc(1,1) signal [false]. Use only if GNSS-SDR.internal_fs_hz is greater than or equal to 6138000 +Acquisition_1B.cboc=false ; This option allows you to choose between acquiring with CBOC signal [true] or sinboc(1,1) signal [false]. Use only if GNSS-SDR.internal_fs_sps is greater than or equal to 6138000 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GLOBAL CONFIG ############ Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking Tracking_1B.item_type=gr_complex -Tracking_1B.if=0 -Tracking_1B.dump=false -Tracking_1B.dump_filename=../data/veml_tracking_ch_ Tracking_1B.pll_bw_hz=20.0; Tracking_1B.dll_bw_hz=2.0; Tracking_1B.order=3; Tracking_1B.early_late_space_chips=0.15; Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ + ;######### TELEMETRY DECODER CONFIG ############ TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=Galileo_E1B_Observables +Observables.implementation=Hybrid_Observables Observables.dump=true Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GALILEO_E1_PVT -PVT.averaging_depth=1 -PVT.flag_averaging=false +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 PVT.display_rate_ms=500 PVT.dump=true diff --git a/conf/gnss-sdr_Galileo_E5a.conf b/conf/gnss-sdr_Galileo_E5a.conf index fd4cfe55f..81dddd613 100644 --- a/conf/gnss-sdr_Galileo_E5a.conf +++ b/conf/gnss-sdr_Galileo_E5a.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=32000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=32000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,184 +22,38 @@ GNSS-SDR.internal_fs_hz=32000000 ;GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com ;GNSS-SDR.SUPL_gps_acquisition_port=7275 ;GNSS-SDR.SUPL_MCC=244 -;GNSS-SDR.SUPL_MNS=5 +;GNSS-SDR.SUPL_MNC=5 ;GNSS-SDR.SUPL_LAC=0x59e2 ;GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/ifen/32MS_complex.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=32000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1176450000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;SignalConditioner.implementation=Signal_Conditioner SignalConditioner.implementation=Pass_Through -;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block -DataTypeAdapter.implementation=Pass_Through - -;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. -InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=32000000 -InputFilter.IF=0 - - - -;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler -Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. -Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal -Resampler.sample_freq_in=8000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=4000000 - ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available satellite channels. Channels_5X.count=1 -;#in_acquisition: Number of channels simultaneously acquiring Channels.in_acquisition=1 -;#system: GPS, GLONASS, Galileo, SBAS or Compass -;#if the option is disabled by default is assigned GPS -Channel.signal=5X ;######### SPECIFIC CHANNELS CONFIG ###### ;#The following options are specific to each channel and overwrite the generic options ;######### CHANNEL 0 CONFIG ############ - -Channel0.signal=5X - -;#satellite: Satellite PRN ID for this channel. Disable this option to random search -Channel0.satellite=19 -;Channel0.repeat_satellite=true +;Channel0.satellite=19 ;######### CHANNEL 1 CONFIG ############ - -;Channel1.system=Galileo -;Channel1.signal=5Q ;Channel1.satellite=12 ;######### CHANNEL 2 CONFIG ############ - -;Channel2.system=Galileo -;Channel2.signal=5Q ;Channel2.satellite=11 ;######### CHANNEL 3 CONFIG ############ @@ -207,129 +63,57 @@ Channel0.satellite=19 ;Channel3.satellite=20 ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_5X.dump=true -;#filename: Log path and filename -Acquisition_5X.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_5X.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_5X.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_5X.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_5X.implementation=Galileo_E5a_Noncoherent_IQ_Acquisition_CAF -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_5X.item_type=gr_complex +Acquisition_5X.coherent_integration_time_ms=1 Acquisition_5X.threshold=0.001 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_5X.pfa=0.0003 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_5X.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_5X.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] (should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_5X.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_5X.max_dwells=1 - -;#CAF filter: **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz Acquisition_5X.CAF_window_hz=0 -;#Zero_padding: **Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. -;#If set to 1 it is ON, if set to 0 it is OFF. Acquisition_5X.Zero_padding=0 +Acquisition_5X.dump=false +Acquisition_5X.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: Tracking_5X.implementation=Galileo_E5a_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_5X.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_5X.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_5X.dump=true - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. +Tracking_5X.pll_bw_hz=20.0; +Tracking_5X.dll_bw_hz=20.0; +Tracking_5X.pll_bw_narrow_hz=2.0; +Tracking_5X.dll_bw_narrow_hz=5.0; +Tracking_5X.order=2; +Tracking_5X.early_late_space_chips=0.5; +Tracking_5X.dump=false Tracking_5X.dump_filename=./tracking_ch_ -;#pll_bw_hz_init: **Only for E5a** PLL loop filter bandwidth during initialization [Hz] -Tracking_5X.pll_bw_hz_init=20.0; -;#dll_bw_hz_init: **Only for E5a** DLL loop filter bandwidth during initialization [Hz] -Tracking_5X.dll_bw_hz_init=20.0; -;#dll_ti_ms: **Only for E5a** loop filter integration time after initialization (secondary code delay search)[ms] -;Tracking_5X.ti_ms=3; -Tracking_5X.ti_ms=1; - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -;Tracking.pll_bw_hz=5.0; -Tracking_5X.pll_bw_hz=20.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -;Tracking.dll_bw_hz=2.0; -Tracking_5X.dll_bw_hz=20.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_5X.order=2; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_5X.early_late_space_chips=0.5; ;######### TELEMETRY DECODER CONFIG ############ -;#implementation: TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder TelemetryDecoder_5X.dump=false + ;######### OBSERVABLES CONFIG ############ -;#implementation: -;Use [Galileo_E1B_Observables] for E5a also. -Observables.implementation=Galileo_E1B_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: -;Use [GALILEO_E1_PVT] for E5a also. -PVT.implementation=GALILEO_E1_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=100 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=true; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Galileo_E5a_IFEN_CTTC.conf b/conf/gnss-sdr_Galileo_E5a_IFEN_CTTC.conf index f5c045cc6..26d01617d 100644 --- a/conf/gnss-sdr_Galileo_E5a_IFEN_CTTC.conf +++ b/conf/gnss-sdr_Galileo_E5a_IFEN_CTTC.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=50000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=50000000 ;######### SUPL RRLP GPS assistance configuration ##### ; Check http://www.mcc-mnc.com/ @@ -19,7 +21,7 @@ GNSS-SDR.internal_fs_hz=50000000 ;GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com ;GNSS-SDR.SUPL_gps_acquisition_port=7275 ;GNSS-SDR.SUPL_MCC=244 -;GNSS-SDR.SUPL_MNS=5 +;GNSS-SDR.SUPL_MNC=5 ;GNSS-SDR.SUPL_LAC=0x59e2 ;GNSS-SDR.SUPL_CI=0x31b0 @@ -28,7 +30,6 @@ SignalSource.implementation=File_Signal_Source SignalSource.filename=/datalogger/signals/ifen/Galileo_E5ab_IFEN_CTTC_run1.dat ; <- PUT YOUR FILE HERE SignalSource.item_type=gr_complex SignalSource.sampling_frequency=50000000 -SignalSource.freq=1176450000 SignalSource.samples=0 SignalSource.repeat=false SignalSource.dump=false @@ -44,8 +45,6 @@ DataTypeAdapter.implementation=Pass_Through ;######### INPUT_FILTER CONFIG ############ InputFilter.implementation=Freq_Xlating_Fir_Filter -InputFilter.dump=false -InputFilter.dump_filename=../data/input_filter.dat InputFilter.input_item_type=gr_complex InputFilter.output_item_type=gr_complex InputFilter.taps_item_type=float @@ -66,6 +65,8 @@ InputFilter.grid_density=16 InputFilter.sampling_frequency=50000000 InputFilter.IF=-15345000 InputFilter.decimation_factor=1 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ @@ -75,7 +76,7 @@ Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -Channels_5X.count=1 +Channels_5X.count=8 Channels.in_acquisition=1 Channel.signal=5X @@ -84,28 +85,25 @@ Channel.signal=5X ;######### CHANNEL 0 CONFIG ############ Channel0.signal=5X -Channel0.satellite=19 +;Channel0.satellite=19 ;Channel0.repeat_satellite=true ;######### CHANNEL 1 CONFIG ############ Channel1.signal=5X -Channel1.satellite=12 +;Channel1.satellite=12 ;######### CHANNEL 2 CONFIG ############ Channel2.signal=5X -Channel2.satellite=11 +;Channel2.satellite=11 ;######### CHANNEL 3 CONFIG ############ Channel3.signal=5X -Channel3.satellite=20 +;Channel3.satellite=20 ;######### ACQUISITION GLOBAL CONFIG ############ -Acquisition_5X.dump=false -Acquisition_5X.dump_filename=./acq_dump.dat -Acquisition_5X.item_type=gr_complex -Acquisition_5X.if=0 -Acquisition_5X.coherent_integration_time_ms=1 Acquisition_5X.implementation=Galileo_E5a_Noncoherent_IQ_Acquisition_CAF +Acquisition_5X.item_type=gr_complex +Acquisition_5X.coherent_integration_time_ms=1 Acquisition_5X.threshold=0.002 Acquisition_5X.doppler_max=10000 Acquisition_5X.doppler_step=250 @@ -113,36 +111,39 @@ Acquisition_5X.bit_transition_flag=false Acquisition_5X.max_dwells=1 Acquisition_5X.CAF_window_hz=0 ; **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz Acquisition_5X.Zero_padding=0 ; **Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. +Acquisition_5X.dump=false +Acquisition_5X.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ Tracking_5X.implementation=Galileo_E5a_DLL_PLL_Tracking Tracking_5X.item_type=gr_complex -Tracking_5X.if=0 -Tracking_5X.dump=false -Tracking_5X.dump_filename=./tracking_ch_ -Tracking_5X.pll_bw_hz_init=20.0; **Only for E5a** PLL loop filter bandwidth during initialization [Hz] -Tracking_5X.dll_bw_hz_init=20.0; **Only for E5a** DLL loop filter bandwidth during initialization [Hz] -Tracking_5X.ti_ms=1; **Only for E5a** loop filter integration time after initialization (secondary code delay search)[ms] Tracking_5X.pll_bw_hz=20.0; Tracking_5X.dll_bw_hz=20.0; +Tracking_5X.pll_bw_narrow_hz=20.0; +Tracking_5X.dll_bw_narrow_hz=20.0; Tracking_5X.order=2; Tracking_5X.early_late_space_chips=0.5; +Tracking_5X.dump=false +Tracking_5X.dump_filename=./tracking_ch_ + ;######### TELEMETRY DECODER CONFIG ############ TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder TelemetryDecoder_5X.dump=false + ;######### OBSERVABLES CONFIG ############ -Observables.implementation=Galileo_E1B_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -PVT.implementation=GALILEO_E1_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=true +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=OFF ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=OFF ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 PVT.dump=false PVT.dump_filename=./PVT @@ -152,4 +153,3 @@ PVT.nmea_dump_devname=/dev/pts/4 PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - diff --git a/conf/gnss-sdr_Hybrid_byte.conf b/conf/gnss-sdr_Hybrid_byte.conf index d4b2a6a16..b7f4e58ff 100644 --- a/conf/gnss-sdr_Hybrid_byte.conf +++ b/conf/gnss-sdr_Hybrid_byte.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,163 +8,58 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=20000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=20000000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed -SignalSource.filename=/datalogger/signals/Fraunhofer/L125_III1b_210s_L1.bin ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.filename=/media/javier/Extreme 500/fraunhofer/L125_III1b_210s_L1.bin ; <- PUT YOUR FILE HERE SignalSource.item_type=byte - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=20000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Ibyte_To_Complex ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=20000000 -InputFilter.IF=0 - +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler.sample_freq_in=20000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler.sample_freq_out=20000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_1C.count=8 -;#count: Number of available Galileo satellite channels. -Channels_1B.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver +Channels_1C.count=10 +Channels_1B.count=10 Channels.in_acquisition=1 ;#signal: +;# "1C" GPS L1 C/A +;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) +;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 + ;#if the option is disabled by default is assigned "1C" GPS L1 C/A +Channel0.signal=1C Channel1.signal=1C Channel2.signal=1C Channel3.signal=1C @@ -178,158 +75,86 @@ Channel12.signal=1B Channel13.signal=1B Channel14.signal=1B Channel15.signal=1B - +Channel16.signal=1B +Channel17.signal=1B +Channel18.signal=1B +Channel19.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold -Acquisition_1C.threshold=0.0060 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] -Acquisition_1C.doppler_step=500 +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=18 +Acquisition_1C.use_CFAR_algorithm=false +Acquisition_1C.blocking=true +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold -;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_1B.pfa=0.0000008 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] +Acquisition_1B.item_type=gr_complex +Acquisition_1B.threshold=25 +Acquisition_1B.use_CFAR_algorithm=false +Acquisition_1B.blocking=true +Acquisition_1B.doppler_max=5000 Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] -Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.extend_correlation_ms=1 +Tracking_1C.pll_bw_hz=40; +Tracking_1C.pll_bw_narrow_hz=30; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dll_bw_narrow_hz=1.5; +Tracking_1C.order=2; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=45.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=4.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] +Tracking_1B.dll_bw_hz=3.0; Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=4; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. +;#implementation: Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] -PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=10; PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - +PVT.elevation_mask=15; PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump=false PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Hybrid_byte_sim.conf b/conf/gnss-sdr_Hybrid_byte_sim.conf index df7ae450a..cd5ce2f3c 100644 --- a/conf/gnss-sdr_Hybrid_byte_sim.conf +++ b/conf/gnss-sdr_Hybrid_byte_sim.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,170 +8,49 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2600000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed -SignalSource.filename=/datalogger/signals/gnss-sim/signal_out.bin ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.filename=/Users/carlesfernandez/git/cttc/build/signal_out.bin ; <- PUT YOUR FILE HERE SignalSource.item_type=byte - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version SignalSource.dump=false - SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block -DataTypeAdapter.implementation=Ibyte_To_Cshort +DataTypeAdapter.implementation=Ibyte_To_Complex DataTypeAdapter.dump=false -;#dump_filename: Log path and filename. DataTypeAdapter.dump_filename=../data/DataTypeAdapter.dat ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter.dump=false - -;#dump_filename: Log path and filename. InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. -InputFilter.input_item_type=cshort - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter.output_item_type=cshort - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=4000000 -InputFilter.IF=0 - +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. -Resampler.item_type=cshort - -;#sample_freq_in: the sample frequency of the input signal -Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=4000000 +Resampler.item_type = gr_complex; ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_1C.count=12 -;#count: Number of available Galileo satellite channels. +Channels_1C.count=11 Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 - -;#IMPORTANT: When cshort is used as input type for Acq and Trk, please set the Channel type to cshort here -;#item_type: Type and resolution for each of the signal samples. -Channel.item_type=cshort ;#signal: -;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel1.signal=1C Channel2.signal=1C Channel3.signal=1C @@ -188,158 +69,76 @@ Channel15.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=cshort -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#use_CFAR_algorithm: If enabled, acquisition estimates the input signal power to implement CFAR detection algorithms -;#notice that this affects the Acquisition threshold range! +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.use_CFAR_algorithm=false; -;#threshold: Acquisition threshold -Acquisition_1C.threshold=11 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] +Acquisition_1C.threshold=15 ;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=6000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=100 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=cshort -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.pfa=0.0000008 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] -Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. -Tracking_1C.item_type=cshort - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1C.dump_filename=../data/epl_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=20.0; Tracking_1C.dll_bw_hz=1.5; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1C.order=3; + ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. -Tracking_1B.item_type=cshort - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1B.item_type=gr_complex Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder -TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump=false PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Hybrid_gr_complex.conf b/conf/gnss-sdr_Hybrid_gr_complex.conf index a0f10bdb4..14fee756d 100644 --- a/conf/gnss-sdr_Hybrid_gr_complex.conf +++ b/conf/gnss-sdr_Hybrid_gr_complex.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,154 +8,28 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4092000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4092000 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] [Nsr_File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/sim/GPS_sim1.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4092000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Pass_Through -;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block -DataTypeAdapter.implementation=Pass_Through -DataTypeAdapter.item_type=gr_complex - -;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - -InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. -InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;# Original sampling frequency stored in the signal file -InputFilter.sampling_frequency=4092000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block -InputFilter.decimation_factor=8 - - -;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -Resampler.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=1 -;#count: Number of available Galileo satellite channels. Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) -;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "5X" GALILEO E5a I+Q - ;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel0.signal=1C Channel1.signal=1B @@ -174,171 +50,81 @@ Channel15.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.use_CFAR_algorithm=false; -;#threshold: Acquisition threshold Acquisition_1C.threshold=30 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=5000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=100 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.pfa=0.0000002 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1C.dump=true - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1C.dump_filename=../data/epl_tracking_ch_ - -;# Extended correlation after telemetry bit synchronization -;# Valid values are: [1,2,4,5,10,20] (integer divisors of the GPS L1 CA bit period (20 ms) ) -;# Longer integration period require more stable front-end LO - Tracking_1C.extend_correlation_ms=10 - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1C.pll_bw_hz=40; Tracking_1C.pll_bw_narrow_hz=25; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1C.dll_bw_hz=2.0; - Tracking_1C.dll_bw_narrow_hz=2.0; - -;#fll_bw_hz: FLL loop filter bandwidth [Hz] -Tracking_1C.fll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1C.order=3; +Tracking_1C.dump=true +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_FLL_PLL_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1B.dll_bw_hz=2.0; - -;#fll_bw_hz: FLL loop filter bandwidth [Hz] Tracking_1B.fll_bw_hz=10.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=4; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B_factor=4; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Hybrid_ishort.conf b/conf/gnss-sdr_Hybrid_ishort.conf index e326d475f..c634009f3 100644 --- a/conf/gnss-sdr_Hybrid_ishort.conf +++ b/conf/gnss-sdr_Hybrid_ishort.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,160 +22,44 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) +;#implementation SignalSource.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. SignalSource.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource.dump=false - -SignalSource.dump_filename=../data/signal_source.dat - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Ishort_To_Complex ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - -;InputFilter.implementation=Fir_Filter -;InputFilter.implementation=Freq_Xlating_Fir_Filter InputFilter.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter.band1_begin=0.0 -InputFilter.band1_end=0.45 -InputFilter.band2_begin=0.55 -InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter.ampl1_begin=1.0 -InputFilter.ampl1_end=1.0 -InputFilter.ampl2_begin=0.0 -InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter.band1_error=1.0 -InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter.sampling_frequency=4000000 -InputFilter.IF=0 - - ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation -;Resampler.implementation=Direct_Resampler Resampler.implementation=Pass_Through - -;#dump: Dump the resamplered data to a file. -Resampler.dump=false -;#dump_filename: Log path and filename. -Resampler.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signalq -Resampler.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal -Resampler.sample_freq_out=4000000 +Resampler.dump=false +Resampler.dump_filename=../data/resampler.dat ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=0 -;#count: Number of available Galileo satellite channels. Channels_1B.count=5 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 ;#signal: @@ -191,155 +77,76 @@ Channel6.signal=1B Channel7.signal=1B - ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.0075 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.pfa=0.0000008; 0.0000008 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 Acquisition_1B.cboc=false; +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=50.0; +Tracking_1C.dll_bw_hz=5.0; +Tracking_1C.order=3; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=50.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=5.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=20.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=4; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 @@ -348,6 +155,5 @@ PVT.rtcm_MT1045_rate_ms=5000 ; Period (in ms) of Galileo ephemeris messages. 0 m PVT.rtcm_MT1045_rate_ms=5000 ; Period (in ms) of GPS ephemeris messages. 0 mutes this message PVT.rtcm_MT1097_rate_ms=1000 ; Period (in ms) of Galileo observables. 0 mutes this message PVT.rtcm_MT1077_rate_ms=1000 ; Period (in ms) of GPS observables. 0 mutes this message - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump=false PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_Hybrid_nsr.conf b/conf/gnss-sdr_Hybrid_nsr.conf index a87f44cc3..9f65ead4b 100644 --- a/conf/gnss-sdr_Hybrid_nsr.conf +++ b/conf/gnss-sdr_Hybrid_nsr.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,157 +8,70 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -;GNSS-SDR.internal_fs_hz=6826700 -GNSS-SDR.internal_fs_hz=2560000 -;GNSS-SDR.internal_fs_hz=4096000 -;GNSS-SDR.internal_fs_hz=5120000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2560000 + ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] [Nsr_File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Nsr_File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed -SignalSource.filename=/datalogger/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.filename=/home/javier/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE SignalSource.item_type=byte - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=20480000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource.samples=0 - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false - -;#dump: Dump the Signal source data to a file. Disable this option in this version SignalSource.dump=false - SignalSource.dump_filename=../data/signal_source.dat - - -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false ;######### SIGNAL_CONDITIONER CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter.implementation=Pass_Through DataTypeAdapter.item_type=float ;######### INPUT_FILTER CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - InputFilter.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. -InputFilter.dump=false - -;#dump_filename: Log path and filename. -InputFilter.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter.input_item_type=float - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter.band1_begin=0.0 InputFilter.band1_end=0.45 InputFilter.band2_begin=0.55 InputFilter.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter.ampl1_begin=1.0 InputFilter.ampl1_end=1.0 InputFilter.ampl2_begin=0.0 InputFilter.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter.band1_error=1.0 InputFilter.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter.grid_density=16 - -;# Original sampling frequency stored in the signal file InputFilter.sampling_frequency=20480000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block InputFilter.decimation_factor=8 +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat ;######### RESAMPLER CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation Resampler.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_1C.count=8 -;#count: Number of available Galileo satellite channels. -Channels_1B.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver +Channels_1C.count=10 +Channels_1B.count=10 Channels.in_acquisition=1 ;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel0.signal=1C @@ -167,175 +82,95 @@ Channel4.signal=1C Channel5.signal=1C Channel6.signal=1C Channel7.signal=1C -Channel8.signal=1B -Channel9.signal=1B +Channel8.signal=1C +Channel9.signal=1C Channel10.signal=1B Channel11.signal=1B Channel12.signal=1B Channel13.signal=1B Channel14.signal=1B Channel15.signal=1B +Channel16.signal=1B +Channel17signal=1B +Channel18.signal=1B +Channel19.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold -Acquisition_1C.threshold=0.0075 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=25 +Acquisition_1C.use_CFAR_algorithm=false +Acquisition_1C.blocking=true Acquisition_1C.doppler_max=5000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold -;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_1B.pfa=0.0000002 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] -Acquisition_1B.doppler_step=125 +Acquisition_1B.item_type=gr_complex +Acquisition_1B.threshold=25 +Acquisition_1B.use_CFAR_algorithm=false +Acquisition_1B.blocking=true +Acquisition_1B.doppler_max=5000 +Acquisition_1B.doppler_step=250 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1C.dump=true - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. +Tracking_1C.extend_correlation_ms=1 +Tracking_1C.pll_bw_hz=40; +Tracking_1C.pll_bw_narrow_hz=30; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.dll_bw_narrow_hz=1.5; +Tracking_1C.order=2; +Tracking_1C.dump=false Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;# Extended correlation after telemetry bit synchronization -;# Valid values are: [1,2,4,5,10,20] (integer divisors of the GPS L1 CA bit period (20 ms) ) -;# Longer integration period require more stable front-end LO - -Tracking_1C.extend_correlation_ms=1 - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] - -Tracking_1C.pll_bw_hz=40; -Tracking_1C.pll_bw_narrow_hz=20; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=2.0; -Tracking_1C.dll_bw_narrow_hz=1.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] +Tracking_1B.pll_bw_hz=20.0; Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=4; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B_factor=4; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. +;#implementation: Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=10; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - +PVT.elevation_mask=20; PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump=false PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_galileo_E1_extended_correlator_byte.conf b/conf/gnss-sdr_galileo_E1_extended_correlator_byte.conf new file mode 100644 index 000000000..366299f74 --- /dev/null +++ b/conf/gnss-sdr_galileo_E1_extended_correlator_byte.conf @@ -0,0 +1,141 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=20000000 + + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/media/javier/SISTEMA/signals/fraunhofer/L125_III1b_210s_L1.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=byte +SignalSource.sampling_frequency=20000000 +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.enable_throttle_control=false + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Ibyte_To_Complex + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Pass_Through + +;######### RESAMPLER CONFIG ############ +Resampler.implementation=Pass_Through + + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=0 +Channels_1B.count=8 + +Channels.in_acquisition=1 + +Channel1.signal=1B +Channel2.signal=1B +Channel3.signal=1B +Channel4.signal=1B +Channel5.signal=1B +Channel6.signal=1B +Channel7.signal=1B +Channel8.signal=1B +Channel9.signal=1B +Channel10.signal=1B +Channel11.signal=1B +Channel12.signal=1B +Channel13.signal=1B +Channel14.signal=1B +Channel15.signal=1B + + +;######### GPS ACQUISITION CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.scoherent_integration_time_ms=1 +Acquisition_1C.use_CFAR_algorithm=false; +Acquisition_1C.threshold=18 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### GALILEO ACQUISITION CONFIG ############ +Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 +Acquisition_1B.acquire_pilot=true +Acquisition_1B.use_CFAR_algorithm=false +Acquisition_1B.threshold=21 +Acquisition_1B.doppler_max=5000 +Acquisition_1B.doppler_step=125 +Acquisition_1B.bit_transition_flag=true +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=../data/acq_dump.dat + + +;######### TRACKING GPS CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=30.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + + +;######### TRACKING GALILEO CONFIG ############ +Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking +Tracking_1B.item_type=gr_complex +Tracking_1B.track_pilot=true +Tracking_1B.pll_bw_hz=4.0; +Tracking_1B.dll_bw_hz=0.5; +Tracking_1B.pll_bw_narrow_hz=2.0; +Tracking_1B.dll_bw_narrow_hz=0.25; +Tracking_1B.extend_correlation_symbols=4; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.early_late_space_narrow_chips=0.06; +Tracking_1B.very_early_late_space_narrow_chips=0.25; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +;######### TELEMETRY DECODER GALILEO CONFIG ############ +TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder +TelemetryDecoder_1B.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100; +PVT.display_rate_ms=500; +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_galileo_E1_extended_correlator_labsat.conf b/conf/gnss-sdr_galileo_E1_extended_correlator_labsat.conf new file mode 100644 index 000000000..2a63b36b6 --- /dev/null +++ b/conf/gnss-sdr_galileo_E1_extended_correlator_labsat.conf @@ -0,0 +1,169 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_sps=5456000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Labsat_Signal_Source +SignalSource.selected_channel=1 +;#filename: path to file with the captured GNSS signal samples to be processed +;# Labsat sile source automatically increments the file name when the signal is split in several files +;# the adapter adds "_0000.LS3" to this base path and filename. Next file will be "_0001.LS3" and so on +;# in this example, the first file complete path will be ../signals/GPS_025_0000.LS3 +SignalSource.filename=../signals/GPS_025 ; <- PUT YOUR FILE HERE +SignalSource.item_type=gr_complex +SignalSource.sampling_frequency=16368000 +SignalSource.samples=0 +SignalSource.repeat=false +SignalSource.dump=false +SignalSource.dump_filename=../data/signal_source.dat +SignalSource.enable_throttle_control=false + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ +DataTypeAdapter.implementation=Pass_Through +DataTypeAdapter.item_type=gr_complex + +;######### INPUT_FILTER CONFIG ############ +InputFilter.implementation=Freq_Xlating_Fir_Filter +InputFilter.dump=false +InputFilter.dump_filename=../data/input_filter.dat + +InputFilter.input_item_type=gr_complex +InputFilter.output_item_type=gr_complex +InputFilter.taps_item_type=float +InputFilter.number_of_taps=5 +InputFilter.number_of_bands=2 + +InputFilter.band1_begin=0.0 +InputFilter.band1_end=0.45 +InputFilter.band2_begin=0.55 +InputFilter.band2_end=1.0 + +InputFilter.ampl1_begin=1.0 +InputFilter.ampl1_end=1.0 +InputFilter.ampl2_begin=0.0 +InputFilter.ampl2_end=0.0 + +InputFilter.band1_error=1.0 +InputFilter.band2_error=1.0 + +InputFilter.filter_type=bandpass +InputFilter.grid_density=16 +InputFilter.sampling_frequency=16368000 +InputFilter.IF=0 +InputFilter.decimation_factor=3 + + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=0 +Channels_1B.count=6 +Channels.in_acquisition=1 + +Channel0.signal=1B +Channel1.signal=1B +Channel2.signal=1B +Channel3.signal=1B +Channel4.signal=1B +Channel5.signal=1B +Channel6.signal=1B +Channel7.signal=1B +Channel8.signal=1B +Channel9.signal=1B +Channel10.signal=1B +Channel11.signal=1B +Channel12.signal=1B +Channel13.signal=1B +Channel14.signal=1B +Channel15.signal=1B + + +;######### GPS ACQUISITION CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.use_CFAR_algorithm=false; +Acquisition_1C.threshold=22 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + +;######### GALILEO ACQUISITION CONFIG ############ +Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 +Acquisition_1B.acquire_pilot=true +Acquisition_1B.use_CFAR_algorithm=false +Acquisition_1B.threshold=22 +Acquisition_1B.doppler_max=5000 +Acquisition_1B.doppler_step=125 +Acquisition_1B.bit_transition_flag=true +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=../data/acq_dump.dat + + +;######### TRACKING GPS CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + +;######### TRACKING GALILEO CONFIG ############ +Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking +Tracking_1B.item_type=gr_complex +Tracking_1B.track_pilot=true +Tracking_1B.pll_bw_hz=7.5; +Tracking_1B.dll_bw_hz=0.5; +Tracking_1B.pll_bw_narrow_hz=2.5; +Tracking_1B.dll_bw_narrow_hz=0.25; +Tracking_1B.extend_correlation_symbols=4; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.early_late_space_narrow_chips=0.15; +Tracking_1B.very_early_late_space_narrow_chips=0.30; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +;######### TELEMETRY DECODER GALILEO CONFIG ############ +TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder +TelemetryDecoder_1B.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100; +PVT.display_rate_ms=500; +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_bin_file_III_1a.conf b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_bin_file_III_1a.conf index 7879cb02c..c395a5f3c 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_bin_file_III_1a.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_bin_file_III_1a.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### ; Check http://www.mcc-mnc.com/ @@ -19,39 +21,25 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - SignalSource.flag_read_file=true SignalSource.signal_file=/datalogger/signals/Fraunhofer/L125_III1b_210s.usb ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=1 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -59,88 +47,34 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter0.IF=0; -;#-205000 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -149,25 +83,15 @@ DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 1 CONFIG ############ InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -176,28 +100,17 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 ;# CHANNEL CONNECTION @@ -211,131 +124,61 @@ Channel6.RF_channel_ID=0 Channel7.RF_channel_ID=0 ;#signal: -;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.use_CFAR_algorithm=false; -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. Acquisition_1C.threshold=15 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1C.dump=true - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1C.dump_filename=../data/epl_tracking_ch_ - Tracking_1C.extend_correlation_ms=10 - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1C.pll_bw_hz=40.0; Tracking_1C.pll_bw_narrow_hz=35; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1C.dll_bw_hz=2.0; Tracking_1C.dll_bw_narrow_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=true +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1a.conf b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1a.conf index 2808b251d..134bfa457 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1a.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1a.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,36 +22,23 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1a.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=1 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -57,87 +46,34 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter0.IF=-205000 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -146,25 +82,15 @@ DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 1 CONFIG ############ InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -173,37 +99,20 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) -;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "5X" GALILEO E5a I+Q - ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 Channel1.RF_channel_ID=0 @@ -226,123 +135,54 @@ Channel6.signal=1C Channel7.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.012 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=3.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1b.conf b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1b.conf index f7a56a6ff..9552ebabe 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_III_1b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,36 +22,24 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=1 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - ;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -57,87 +47,33 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ -InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter0.IF=-205000 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -146,25 +82,15 @@ DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 1 CONFIG ############ InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -173,36 +99,19 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) -;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "5X" GALILEO E5a I+Q - ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 Channel1.RF_channel_ID=0 @@ -224,123 +133,55 @@ Channel5.signal=1C Channel6.signal=1C Channel7.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.012 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=3.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_II_3b.conf b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_II_3b.conf index 9bd32b4ca..f1e5d264b 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_II_3b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_II_3b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,36 +22,23 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_II-3b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=1 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -57,87 +46,34 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=40000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter0.IF=-205000 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=16 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -146,25 +82,15 @@ DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 1 CONFIG ############ InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -173,35 +99,26 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;# signal: +;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 @@ -214,7 +131,6 @@ Channel6.RF_channel_ID=0 Channel7.RF_channel_ID=0 ;#signal: -;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel0.signal=1C Channel1.signal=1C Channel2.signal=1C @@ -225,123 +141,54 @@ Channel6.signal=1C Channel7.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.012 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=3.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_I_1b.conf b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_I_1b.conf index 65cc26133..201fff1ab 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_I_1b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_Flexiband_realtime_I_1b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=5000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=5000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,36 +22,23 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_I-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=1 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -57,87 +46,34 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=40000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter0.IF=-205000 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -146,25 +82,15 @@ DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 1 CONFIG ############ InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -173,36 +99,19 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=4 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) -;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "5X" GALILEO E5a I+Q - ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 Channel1.RF_channel_ID=0 @@ -214,129 +123,60 @@ Channel3.RF_channel_ID=0 ;Channel7.RF_channel_ID=0 ;#signal: -;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel0.signal=1C Channel1.signal=1C Channel2.signal=1C Channel3.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.011 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=3.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_L2_Flexiband_realtime_III_1b.conf b/conf/gnss-sdr_multichannel_GPS_L1_L2_Flexiband_realtime_III_1b.conf index 3f54ad14d..48eabee34 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_L2_Flexiband_realtime_III_1b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_L2_Flexiband_realtime_III_1b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,32 +22,20 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=2 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;###################################################### @@ -53,7 +43,6 @@ SignalSource.usb_packet_buffer=128 ;###################################################### ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -61,85 +50,31 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] -;# WARNING: Fraunhofer front-end hardwareconfigurations can difer. Signals available on http://www.iis.fraunhofer.de/de/ff/lok/leist/test/flexiband.html are centered on 0 Hz, ALL BANDS. InputFilter0.IF=-205000 -;#InputFilter0.IF=0 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;###################################################### @@ -147,7 +82,6 @@ Resampler0.implementation=Pass_Through ;###################################################### ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -155,90 +89,35 @@ DataTypeAdapter1.implementation=Pass_Through DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter1.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter_ch1.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter1.band1_begin=0.0 InputFilter1.band1_end=0.45 InputFilter1.band2_begin=0.55 InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter1.ampl1_begin=1.0 InputFilter1.ampl1_end=1.0 InputFilter1.ampl2_begin=0.0 InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter1.band1_error=1.0 InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter1.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter1.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] -;# WARNING: Fraunhofer front-end hardwareconfigurations can difer. Signals available on http://www.iis.fraunhofer.de/de/ff/lok/leist/test/flexiband.html are centered on 0 Hz, ALL BANDS. InputFilter1.IF=100000 -;#InputFilter1.IF=0 - -;# Decimation factor after the frequency tranaslating block InputFilter1.decimation_factor=8 ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -247,38 +126,26 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 Channels_2S.count=8 -;#count: Number of available Galileo satellite channels. -;Channels_Galileo.count=0 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 - ;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;# CHANNEL CONNECTION @@ -356,138 +223,82 @@ Channel15.RF_channel_ID=1 Channel15.signal=2S -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.008 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=5000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] - Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=true -Tracking_1C.dump_filename=./tracking_ch_ Tracking_1C.pll_bw_hz=40.0; Tracking_1C.dll_bw_hz=3.0; Tracking_1C.order=3; Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=true +Tracking_1C.dump_filename=./tracking_ch_ + ;# GPS L2C M -Acquisition_2S.dump=false -Acquisition_2S.dump_filename=./acq_dump.dat -Acquisition_2S.item_type=gr_complex -Acquisition_2S.if=0 Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex Acquisition_2S.threshold=0.0005 ;Acquisition_2S.pfa=0.001 Acquisition_2S.doppler_max=5000 Acquisition_2S.doppler_min=-5000 Acquisition_2S.doppler_step=30 Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking Tracking_2S.item_type=gr_complex -Tracking_2S.if=0 -Tracking_2S.dump=true -Tracking_2S.dump_filename=./tracking_ch_ Tracking_2S.pll_bw_hz=1.5; Tracking_2S.dll_bw_hz=0.3; Tracking_2S.order=3; Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=true +Tracking_2S.dump_filename=./tracking_ch_ + ;######### TELEMETRY DECODER GPS L1 CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=20; ;######### TELEMETRY DECODER GPS L2 CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L2 M TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder TelemetryDecoder_2S.dump=false -TelemetryDecoder_2S.decimation_factor=1; ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A.Mixed_Observables Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_L2_Galileo_E1B_Flexiband_bin_file_III_1b.conf b/conf/gnss-sdr_multichannel_GPS_L1_L2_Galileo_E1B_Flexiband_bin_file_III_1b.conf index 6932bd009..7c19ebc2c 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_L2_Galileo_E1B_Flexiband_bin_file_III_1b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_L2_Galileo_E1B_Flexiband_bin_file_III_1b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=2500000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=2500000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,35 +22,22 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - SignalSource.flag_read_file=true SignalSource.signal_file=/datalogger/signals/Fraunhofer/L125_III1b_210s.usb ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file SignalSource.RF_channels=2 - ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;###################################################### @@ -56,7 +45,6 @@ SignalSource.usb_packet_buffer=128 ;###################################################### ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -64,85 +52,31 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] -;# WARNING: Fraunhofer front-end hardwareconfigurations can difer. Signals available on http://www.iis.fraunhofer.de/de/ff/lok/leist/test/flexiband.html are centered on 0 Hz, ALL BANDS. -;#InputFilter0.IF=-205000 InputFilter0.IF=0 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;###################################################### @@ -150,7 +84,6 @@ Resampler0.implementation=Pass_Through ;###################################################### ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -158,90 +91,35 @@ DataTypeAdapter1.implementation=Pass_Through DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter1.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter_ch1.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter1.band1_begin=0.0 InputFilter1.band1_end=0.45 InputFilter1.band2_begin=0.55 InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter1.ampl1_begin=1.0 InputFilter1.ampl1_end=1.0 InputFilter1.ampl2_begin=0.0 InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter1.band1_error=1.0 InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter1.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter1.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] -;# WARNING: Fraunhofer front-end hardware configurations can differ. Signals available at http://www.iis.fraunhofer.de/de/ff/lok/leist/test/flexiband.html are centered on 0 Hz, ALL BANDS. -;#InputFilter1.IF=100000 InputFilter1.IF=0 - -;# Decimation factor after the frequency translating block InputFilter1.decimation_factor=8 ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner2.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ @@ -250,37 +128,28 @@ DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter2.dump=false - -;#dump_filename: Log path and filename. InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex ;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. Resampler2.implementation=Pass_Through -;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. +;######### CHANNELS GLOBAL CONFIG ############. Channels_1C.count=2 Channels_1B.count=4 Channels_2S.count=4 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 ;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;# CHANNEL CONNECTION @@ -302,49 +171,23 @@ Channel14.RF_channel_ID=1 Channel15.RF_channel_ID=1 -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.008 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.0001 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=5000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=250 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] - Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 Tracking_1C.dump=false Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=40.0; @@ -353,148 +196,82 @@ Tracking_1C.order=3; Tracking_1C.early_late_space_chips=0.5; ;# GPS L2C M -Acquisition_2S.dump=false -Acquisition_2S.dump_filename=./acq_dump.dat -Acquisition_2S.item_type=gr_complex -Acquisition_2S.if=0 Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex Acquisition_2S.threshold=0.0005 ;Acquisition_2S.pfa=0.001 Acquisition_2S.doppler_max=5000 Acquisition_2S.doppler_min=-5000 Acquisition_2S.doppler_step=30 Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking Tracking_2S.item_type=gr_complex -Tracking_2S.if=0 -Tracking_2S.dump=true -Tracking_2S.dump_filename=../data/epl_tracking_ch_ Tracking_2S.pll_bw_hz=1.5; Tracking_2S.dll_bw_hz=0.3; Tracking_2S.order=3; Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=true +Tracking_2S.dump_filename=../data/epl_tracking_ch_ ;# GALILEO E1B - - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.pfa=0.0000005 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=5000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=./veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; - +Tracking_1B.dump=false +Tracking_1B.dump_filename=./veml_tracking_ch_ ;######### TELEMETRY DECODER GPS L1 CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=20; ;######### TELEMETRY DECODER GPS L2 CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L2 M TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder TelemetryDecoder_2S.dump=false -TelemetryDecoder_2S.decimation_factor=1; ;######### TELEMETRY DECODER GALILEO E1B CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=5; ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=100 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L1_USRP_X300_realtime.conf b/conf/gnss-sdr_multichannel_GPS_L1_USRP_X300_realtime.conf index b5e865ea8..63746aea4 100644 --- a/conf/gnss-sdr_multichannel_GPS_L1_USRP_X300_realtime.conf +++ b/conf/gnss-sdr_multichannel_GPS_L1_USRP_X300_realtime.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,265 +22,75 @@ GNSS-SDR.SUPL_1C_ephemeris_port=7275 GNSS-SDR.SUPL_1C_acquisition_server=supl.google.com GNSS-SDR.SUPL_1C_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) +;#implementation SignalSource.implementation=UHD_Signal_Source - -;#When left empty, the device discovery routines will search all vailable transports on the system (ethernet, usb...) SignalSource.device_address=192.168.40.2 ; <- PUT THE IP ADDRESS OF YOUR USRP HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource.item_type=gr_complex - -;#RF_channels: Number of RF channels present in the frontend device (i.e. USRP with two frontends) SignalSource.RF_channels=2 - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource.sampling_frequency=4000000 - -;#subdevice: UHD subdevice specification (for USRP dual frontend use A:0 or B:0 or A:0 B:0) SignalSource.subdevice=A:0 B:0 ;######### RF Channels specific settings ###### - ;## RF CHANNEL 0 ## -;#freq: RF front-end center frequency in [Hz] SignalSource.freq0=1575420000 - -;#gain: Front-end Gain in [dB] SignalSource.gain0=50 - -;#samples: Number of samples to be processed. Notice that 0 indicates no limit SignalSource.samples0=0 -;#dump: Dump the Signal source RF channel data to a file. Disable this option in this version -SignalSource.dump0=false - -SignalSource.dump_filename0=../data/signal_source0.dat - ;## RF CHANNEL 1 ## -;#freq: RF front-end center frequency in [Hz] SignalSource.freq1=1575420000 - -;#gain: Front-end Gain in [dB] SignalSource.gain1=50 - -;#samples: Number of samples to be processed. Notice that 0 indicates no limit SignalSource.samples1=0 -;#dump: Dump the Signal source RF channel data to a file. Disable this option in this version -SignalSource.dump1=false - -SignalSource.dump_filename1=../data/signal_source1.dat - ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner0.implementation=Pass_Through ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - InputFilter0.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter0.band1_begin=0.0 -InputFilter0.band1_end=0.45 -InputFilter0.band2_begin=0.55 -InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter0.ampl1_begin=1.0 -InputFilter0.ampl1_end=1.0 -InputFilter0.ampl2_begin=0.0 -InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter0.band1_error=1.0 -InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter0.grid_density=16 - -;# Original sampling frequency stored in the signal file -InputFilter0.sampling_frequency=20480000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter0.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block -InputFilter0.decimation_factor=8 - ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation Resampler0.implementation=Pass_Through -;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks +;######### SIGNAL_CONDITIONER 1 CONFIG ############ SignalConditioner1.implementation=Pass_Through + ;######### INPUT_FILTER 1 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter1.band1_begin=0.0 -InputFilter1.band1_end=0.45 -InputFilter1.band2_begin=0.55 -InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter1.ampl1_begin=1.0 -InputFilter1.ampl1_end=1.0 -InputFilter1.ampl2_begin=0.0 -InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter1.band1_error=1.0 -InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter1.grid_density=16 - -;# Original sampling frequency stored in the signal file -InputFilter1.sampling_frequency=20480000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter1.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter1.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block -InputFilter1.decimation_factor=8 - - ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation Resampler1.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=4 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 ;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 @@ -288,129 +100,60 @@ Channel3.RF_channel_ID=1 ;#signal: -;#if the option is disabled by default is assigned "1C" GPS L1 C/A Channel0.signal=1C Channel1.signal=1C Channel2.signal=1C Channel3.signal=1C -;######### SPECIFIC CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - ;######### ACQUISITION GLOBAL CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.coherent_integration_time_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold. It will be ignored if pfa is defined. +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.01 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=8000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 -;#bit_transition_flag: Enable or disable a strategy to deal with bit transitions in GPS signals: process two dwells and take -;#maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] -;#(should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition]) Acquisition_1C.bit_transition_flag=false -;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true Acquisition_1C.max_dwells=1 - - -;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### TRACKING GLOBAL CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=./tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=40.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=4.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] -Tracking_1C.early_late_space_chips=0.5; ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. -Observables.implementation=GPS_L1_CA_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +Observables.implementation=Hybrid_Observables Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=GPS_L1_CA_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=true PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b.conf b/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b.conf index bfc6b40c9..9c2a86def 100644 --- a/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b.conf +++ b/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,8 +8,8 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=5000000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=5000000 ;######### SUPL RRLP GPS assistance configuration ##### @@ -20,35 +22,22 @@ GNSS-SDR.SUPL_gps_ephemeris_port=7275 GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com GNSS-SDR.SUPL_gps_acquisition_port=7275 GNSS-SDR.SUPL_MCC=244 -GNSS-SDR.SUPL_MNS=5 +GNSS-SDR.SUPL_MNC=5 GNSS-SDR.SUPL_LAC=0x59e2 GNSS-SDR.SUPL_CI=0x31b0 ;######### SIGNAL_SOURCE CONFIG ############ -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource.implementation=Flexiband_Signal_Source - SignalSource.flag_read_file=true -SignalSource.signal_file=/datalogger/signals/Fraunhofer/L125_III1b_210s.usb ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.signal_file=/media/javier/SISTEMA/signals/fraunhofer/L125_III1b_210s.usb ; <- PUT YOUR FILE HERE SignalSource.item_type=gr_complex - -;# FPGA firmware file SignalSource.firmware_file=flexiband_III-1b.bit - -;#RF_channels: Number of RF channels present in the frontend device, must agree the FPGA firmware file -SignalSource.RF_channels=2 - +SignalSource.RF_channels=1 ;#frontend channels gain. Not usable yet! SignalSource.gain1=0 SignalSource.gain2=0 SignalSource.gain3=0 - -;#frontend channels AGC SignalSource.AGC=true - -;# USB 3.0 packet buffer size (number of SuperSpeed packets) SignalSource.usb_packet_buffer=128 ;###################################################### @@ -56,7 +45,6 @@ SignalSource.usb_packet_buffer=128 ;###################################################### ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ @@ -64,84 +52,31 @@ DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter_ch0.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter0.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] -;#InputFilter0.IF=-205000 InputFilter0.IF=0 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=4 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. Resampler0.implementation=Pass_Through ;###################################################### @@ -149,7 +84,6 @@ Resampler0.implementation=Pass_Through ;###################################################### ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. SignalConditioner1.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ @@ -157,276 +91,271 @@ DataTypeAdapter1.implementation=Pass_Through DataTypeAdapter1.item_type=gr_complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter1.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter_ch1.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, -;#the desired reponse on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter1.band1_begin=0.0 InputFilter1.band1_end=0.45 InputFilter1.band2_begin=0.55 InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter1.ampl1_begin=1.0 InputFilter1.ampl1_end=1.0 InputFilter1.ampl2_begin=0.0 InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter1.band1_error=1.0 InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter1.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz -;FOR USE GNSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE -; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/ InputFilter1.sampling_frequency=20000000 -;# IF deviation due to front-end LO inaccuracies [HZ] InputFilter1.IF=0 - -;# Decimation factor after the frequency tranaslating block InputFilter1.decimation_factor=4 ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. Resampler1.implementation=Pass_Through + +;###################################################### +;######### RF CHANNEL 2 SIGNAL CONDITIONER ############ +;###################################################### + ;######### SIGNAL_CONDITIONER 2 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. -SignalConditioner2.implementation=Pass_Through +SignalConditioner2.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 2 CONFIG ############ DataTypeAdapter2.implementation=Pass_Through DataTypeAdapter2.item_type=gr_complex ;######### INPUT_FILTER 2 CONFIG ############ -InputFilter2.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. +InputFilter2.implementation=Freq_Xlating_Fir_Filter InputFilter2.dump=false - -;#dump_filename: Log path and filename. -InputFilter2.dump_filename=../data/input_filter.dat - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. +InputFilter2.dump_filename=../data/input_filter_ch2.dat InputFilter2.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter2.output_item_type=gr_complex +InputFilter2.taps_item_type=float +InputFilter2.number_of_taps=5 +InputFilter2.number_of_bands=2 +InputFilter2.band1_begin=0.0 +InputFilter2.band1_end=0.45 +InputFilter2.band2_begin=0.55 +InputFilter2.band2_end=1.0 +InputFilter2.ampl1_begin=1.0 +InputFilter2.ampl1_end=1.0 +InputFilter2.ampl2_begin=0.0 +InputFilter2.ampl2_end=0.0 +InputFilter2.band1_error=1.0 +InputFilter2.band2_error=1.0 +InputFilter2.filter_type=bandpass +InputFilter2.grid_density=16 +InputFilter2.sampling_frequency=40000000 +InputFilter2.IF=0 +InputFilter2.decimation_factor=8 -;######### RESAMPLER CONFIG 2 ############ -;## Resamples the input data. + +;######### RESAMPLER CONFIG 1 ############ Resampler2.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_1C.count=1 -Channels_2S.count=8 +Channels_1C.count=0 +Channels_1B.count=10 +Channels_2S.count=0 +Channels_5X.count=0 -;#GPS.prns=7,8 - -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;# signal: +;#signal: ;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) ;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) ;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 ;# CHANNEL NUMBERING ORDER: GPS L1 C/A, GPS L2 L2C (M), GALILEO E1 B, GALILEO E5a ;# CHANNEL CONNECTION + Channel0.RF_channel_ID=0 -Channel1.RF_channel_ID=1 -Channel2.RF_channel_ID=1 -Channel3.RF_channel_ID=1 -Channel4.RF_channel_ID=1 -Channel5.RF_channel_ID=1 -Channel6.RF_channel_ID=1 -Channel7.RF_channel_ID=1 -Channel8.RF_channel_ID=1 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=0 +Channel6.RF_channel_ID=0 +Channel7.RF_channel_ID=0 +Channel8.RF_channel_ID=0 +Channel9.RF_channel_ID=0 +Channel10.RF_channel_ID=0 +Channel11.RF_channel_ID=0 +Channel12.RF_channel_ID=0 +Channel13.RF_channel_ID=0 +Channel14.RF_channel_ID=0 +Channel15.RF_channel_ID=0 +Channel16.RF_channel_ID=0 +Channel17.RF_channel_ID=0 +Channel18.RF_channel_ID=0 +Channel19.RF_channel_ID=0 +Channel20.RF_channel_ID=0 +Channel21.RF_channel_ID=0 +Channel22.RF_channel_ID=0 +Channel23.RF_channel_ID=0 +Channel24.RF_channel_ID=0 +Channel25.RF_channel_ID=0 +Channel26.RF_channel_ID=0 +Channel27.RF_channel_ID=0 +Channel28.RF_channel_ID=0 +Channel29.RF_channel_ID=0 +Channel30.RF_channel_ID=2 +Channel31.RF_channel_ID=2 +Channel32.RF_channel_ID=2 +Channel33.RF_channel_ID=2 +Channel34.RF_channel_ID=2 +Channel35.RF_channel_ID=2 +Channel36.RF_channel_ID=2 +Channel37.RF_channel_ID=2 +Channel38.RF_channel_ID=2 +Channel39.RF_channel_ID=2 +;######### ACQUISITION CONFIG ###### -;######### ACQUISITION GENERIC CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options - -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=gr_complex -Acquisition_1C.if=0 -Acquisition_1C.coherent_integration_time_ms=1 +;# GPS L1 CA Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 Acquisition_1C.threshold=0.005 Acquisition_1C.doppler_max=5000 Acquisition_1C.doppler_step=250 Acquisition_1C.bit_transition_flag=false Acquisition_1C.max_dwells=1 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat +;# Galileo E1 +Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 +;Acquisition_1B.threshold=0 +Acquisition_1B.pfa=0.0000002 +Acquisition_1B.doppler_max=5000 +Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + + +;# GPS L2C M +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.threshold=0.00074 +;Acquisition_2S.pfa=0.001 +Acquisition_2S.doppler_max=5000 +Acquisition_2S.doppler_min=-5000 +Acquisition_2S.doppler_step=60 +Acquisition_2S.max_dwells=1 Acquisition_2S.dump=false Acquisition_2S.dump_filename=./acq_dump.dat -Acquisition_2S.item_type=gr_complex -Acquisition_2S.if=0 -Acquisition_2S.coherent_integration_time_ms=1 -Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition -Acquisition_2S.threshold=0.0005 -Acquisition_2S.doppler_max=5000 -Acquisition_2S.doppler_step=100 -Acquisition_2S.bit_transition_flag=false -Acquisition_2S.max_dwells=1 -;# channel specific config -Acquisition_2S1.dump=false -Acquisition_2S1.dump_filename=./acq_dump.dat -Acquisition_2S1.item_type=gr_complex -Acquisition_2S1.if=0 -Acquisition_2S1.coherent_integration_time_ms=1 -Acquisition_2S1.implementation=GPS_L2_M_PCPS_Acquisition -Acquisition_2S1.threshold=0.0005 -Acquisition_2S1.doppler_max=5000 -Acquisition_2S1.doppler_step=100 -Acquisition_2S1.bit_transition_flag=false -Acquisition_2S1.max_dwells=1 +;# GALILEO E5a +Acquisition_5X.implementation=Galileo_E5a_Noncoherent_IQ_Acquisition_CAF +Acquisition_5X.item_type=gr_complex +Acquisition_5X.coherent_integration_time_ms=1 +Acquisition_5X.threshold=0.009 +Acquisition_5X.doppler_max=5000 +Acquisition_5X.doppler_step=125 +Acquisition_5X.bit_transition_flag=false +Acquisition_5X.max_dwells=1 +Acquisition_5X.CAF_window_hz=0 ; **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz +Acquisition_5X.Zero_padding=0 ; **Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. +Acquisition_5X.dump=false +Acquisition_5X.dump_filename=./acq_dump.dat ;######### TRACKING CONFIG ############ - ;######### GPS L1 C/A GENERIC TRACKING CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.item_type=gr_complex -Tracking_1C.if=0 -Tracking_1C.dump=true -Tracking_1C.dump_filename=../data/epl_tracking_ch_ Tracking_1C.pll_bw_hz=40.0; Tracking_1C.dll_bw_hz=3.0; Tracking_1C.order=3; Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + + +;######### GALILEO E1 TRK CONFIG ############ +Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking +Tracking_1B.item_type=gr_complex +Tracking_1B.pll_bw_hz=15.0; +Tracking_1B.dll_bw_hz=2.0; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### GPS L2C GENERIC TRACKING CONFIG ############ Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking Tracking_2S.item_type=gr_complex -Tracking_2S.if=0 -Tracking_2S.dump=true -Tracking_2S.dump_filename=../data/epl_tracking_ch_ Tracking_2S.pll_bw_hz=2.0; -Tracking_2S.dll_bw_hz=0.5; +Tracking_2S.dll_bw_hz=0.25; Tracking_2S.order=2; Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=false +Tracking_2S.dump_filename=./tracking_ch_ -;######### GPS L2C SPECIFIC CHANNEL TRACKING CONFIG ############ -Tracking_2S1.implementation=GPS_L2_M_DLL_PLL_Tracking -Tracking_2S1.item_type=gr_complex -Tracking_2S1.if=0 -Tracking_2S1.dump=true -Tracking_2S1.dump_filename=../data/epl_tracking_ch_ -Tracking_2S1.pll_bw_hz=2.0; -Tracking_2S1.dll_bw_hz=0.5; -Tracking_2S1.order=2; -Tracking_2S1.early_late_space_chips=0.5; + +;######### GALILEO E5 TRK CONFIG ############ +Tracking_5X.implementation=Galileo_E5a_DLL_PLL_Tracking +Tracking_5X.item_type=gr_complex +Tracking_5X.pll_bw_hz_init=20.0; **Only for E5a** PLL loop filter bandwidth during initialization [Hz] +Tracking_5X.dll_bw_hz_init=20.0; **Only for E5a** DLL loop filter bandwidth during initialization [Hz] +Tracking_5X.ti_ms=1; **Only for E5a** loop filter integration time after initialization (secondary code delay search)[ms] +Tracking_5X.pll_bw_hz=20.0; +Tracking_5X.dll_bw_hz=20.0; +Tracking_5X.order=2; +Tracking_5X.early_late_space_chips=0.5; +Tracking_5X.dump=false +Tracking_5X.dump_filename=./tracking_ch_ ;######### TELEMETRY DECODER CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -TelemetryDecoder_1C.decimation_factor=20; + +TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder +TelemetryDecoder_1B.dump=false TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder TelemetryDecoder_2S.dump=false -TelemetryDecoder_2S.decimation_factor=1; + +TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder +TelemetryDecoder_5X.dump=false ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=true - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. -PVT.display_rate_ms=500 - -;# KML, GeoJSON, NMEA and RTCM output configuration - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. -PVT.dump_filename=./PVT - -;#nmea_dump_filename: NMEA log path and filename +PVT.display_rate_ms=100 PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; - -;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) PVT.flag_nmea_tty_port=false; - -;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b_real.conf b/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b_real.conf new file mode 100644 index 000000000..a52349af1 --- /dev/null +++ b/conf/gnss-sdr_multichannel_GPS_L2_M_Flexiband_bin_file_III_1b_real.conf @@ -0,0 +1,256 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=5000000 + + +;######### SUPL RRLP GPS assistance configuration ##### +; Check http://www.mcc-mnc.com/ +; On Android: https://play.google.com/store/apps/details?id=net.its_here.cellidinfo&hl=en +GNSS-SDR.SUPL_gps_enabled=false +GNSS-SDR.SUPL_read_gps_assistance_xml=true +GNSS-SDR.SUPL_gps_ephemeris_server=supl.google.com +GNSS-SDR.SUPL_gps_ephemeris_port=7275 +GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com +GNSS-SDR.SUPL_gps_acquisition_port=7275 +GNSS-SDR.SUPL_MCC=244 +GNSS-SDR.SUPL_MNC=5 +GNSS-SDR.SUPL_LAC=0x59e2 +GNSS-SDR.SUPL_CI=0x31b0 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Flexiband_Signal_Source +SignalSource.flag_read_file=true +SignalSource.signal_file=/home/javier/signals/20140923_20-24-17_L125_roof_210s.usb ; <- PUT YOUR FILE HERE +SignalSource.item_type=gr_complex +SignalSource.firmware_file=flexiband_III-1b.bit +SignalSource.RF_channels=2 +;#frontend channels gain. Not usable yet! +SignalSource.gain1=0 +SignalSource.gain2=0 +SignalSource.gain3=0 +SignalSource.AGC=true +SignalSource.usb_packet_buffer=128 + +;###################################################### +;######### RF CHANNEL 0 SIGNAL CONDITIONER ############ +;###################################################### + +;######### SIGNAL_CONDITIONER 0 CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER 0 CONFIG ############ +DataTypeAdapter0.implementation=Pass_Through +DataTypeAdapter0.item_type=gr_complex + +;######### INPUT_FILTER 0 CONFIG ############ +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.dump=false +InputFilter0.dump_filename=../data/input_filter_ch0.dat +InputFilter0.input_item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.45 +InputFilter0.band2_begin=0.55 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.IF=0 +InputFilter0.decimation_factor=4 + +;######### RESAMPLER CONFIG 0 ############ +Resampler0.implementation=Pass_Through + +;###################################################### +;######### RF CHANNEL 1 SIGNAL CONDITIONER ############ +;###################################################### + +;######### SIGNAL_CONDITIONER 1 CONFIG ############ +SignalConditioner1.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER 1 CONFIG ############ +DataTypeAdapter1.implementation=Pass_Through +DataTypeAdapter1.item_type=gr_complex + +;######### INPUT_FILTER 0 CONFIG ############ +InputFilter1.implementation=Freq_Xlating_Fir_Filter +InputFilter1.dump=false +InputFilter1.dump_filename=../data/input_filter_ch1.dat +InputFilter1.input_item_type=gr_complex +InputFilter1.output_item_type=gr_complex +InputFilter1.taps_item_type=float +InputFilter1.number_of_taps=5 +InputFilter1.number_of_bands=2 +InputFilter1.band1_begin=0.0 +InputFilter1.band1_end=0.45 +InputFilter1.band2_begin=0.55 +InputFilter1.band2_end=1.0 +InputFilter1.ampl1_begin=1.0 +InputFilter1.ampl1_end=1.0 +InputFilter1.ampl2_begin=0.0 +InputFilter1.ampl2_end=0.0 +InputFilter1.band1_error=1.0 +InputFilter1.band2_error=1.0 +InputFilter1.filter_type=bandpass +InputFilter1.grid_density=16 +InputFilter1.sampling_frequency=20000000 +InputFilter1.IF=0 +InputFilter1.decimation_factor=4 + + +;######### RESAMPLER CONFIG 1 ############ +Resampler1.implementation=Pass_Through + +;######### SIGNAL_CONDITIONER 2 CONFIG ############ +SignalConditioner2.implementation=Pass_Through + +;######### DATA_TYPE_ADAPTER 2 CONFIG ############ +DataTypeAdapter2.implementation=Pass_Through +DataTypeAdapter2.item_type=gr_complex + +;######### INPUT_FILTER 2 CONFIG ############ +InputFilter2.implementation=Pass_Through +InputFilter2.dump=false +InputFilter2.dump_filename=../data/input_filter.dat +InputFilter2.input_item_type=gr_complex +InputFilter2.output_item_type=gr_complex + +;######### RESAMPLER CONFIG 2 ############ +Resampler2.implementation=Pass_Through + + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=10 +Channels_2S.count=4 + +;#GPS.prns=7,8 + +Channels.in_acquisition=1 + +;#signal: +;# "1C" GPS L1 C/A +;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) +;# "1G" GLONASS L1 C/A +;# "2S" GPS L2 L2C (M) +;# "5X" GALILEO E5a I+Q +;# "L5" GPS L5 +;# CHANNEL NUMBERING ORDER: GPS L1 C/A, GPS L2 L2C (M), GALILEO E1 B, GALILEO E5a + +;# CHANNEL CONNECTION +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=0 +Channel6.RF_channel_ID=0 +Channel7.RF_channel_ID=0 +Channel8.RF_channel_ID=0 +Channel9.RF_channel_ID=0 +Channel10.RF_channel_ID=1 +Channel11.RF_channel_ID=1 +Channel12.RF_channel_ID=1 +Channel13.RF_channel_ID=1 +Channel14.RF_channel_ID=1 +Channel15.RF_channel_ID=1 +Channel16.RF_channel_ID=1 +Channel17.RF_channel_ID=1 +Channel18.RF_channel_ID=1 +Channel19.RF_channel_ID=1 + + +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.005 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.bit_transition_flag=false +Acquisition_1C.max_dwells=1 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;# GPS L2C M +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.threshold=0.00074 +;Acquisition_2S.pfa=0.001 +Acquisition_2S.doppler_max=5000 +Acquisition_2S.doppler_min=-5000 +Acquisition_2S.doppler_step=60 +Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat + + +;######### TRACKING CONFIG ############ +;######### GPS L1 C/A GENERIC TRACKING CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=40.0; +Tracking_1C.dll_bw_hz=3.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + + +;######### GPS L2C GENERIC TRACKING CONFIG ############ +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking +Tracking_2S.item_type=gr_complex +Tracking_2S.pll_bw_hz=2.0; +Tracking_2S.dll_bw_hz=0.25; +Tracking_2S.order=2; +Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=false +Tracking_2S.dump_filename=./tracking_ch_ + + +;######### TELEMETRY DECODER CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder +TelemetryDecoder_2S.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=true +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=100 +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multichannel_all_in_one_Flexiband_bin_file_III_1b.conf b/conf/gnss-sdr_multichannel_all_in_one_Flexiband_bin_file_III_1b.conf new file mode 100644 index 000000000..a3e23b001 --- /dev/null +++ b/conf/gnss-sdr_multichannel_all_in_one_Flexiband_bin_file_III_1b.conf @@ -0,0 +1,382 @@ +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=5000000 + + +;######### SUPL RRLP GPS assistance configuration ##### +; Check http://www.mcc-mnc.com/ +; On Android: https://play.google.com/store/apps/details?id=net.its_here.cellidinfo&hl=en +GNSS-SDR.SUPL_gps_enabled=false +GNSS-SDR.SUPL_read_gps_assistance_xml=true +GNSS-SDR.SUPL_gps_ephemeris_server=supl.google.com +GNSS-SDR.SUPL_gps_ephemeris_port=7275 +GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com +GNSS-SDR.SUPL_gps_acquisition_port=7275 +GNSS-SDR.SUPL_MCC=244 +GNSS-SDR.SUPL_MNC=5 +GNSS-SDR.SUPL_LAC=0x59e2 +GNSS-SDR.SUPL_CI=0x31b0 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=Flexiband_Signal_Source +SignalSource.flag_read_file=true +SignalSource.signal_file=/media/javier/SISTEMA/signals/fraunhofer/L125_III1b_210s.usb ; <- PUT YOUR FILE HERE +SignalSource.item_type=gr_complex +SignalSource.firmware_file=flexiband_III-1b.bit +SignalSource.RF_channels=3 +;#frontend channels gain. Not usable yet! +SignalSource.gain1=0 +SignalSource.gain2=0 +SignalSource.gain3=0 +SignalSource.AGC=true +SignalSource.usb_packet_buffer=128 + +;###################################################### +;######### RF CHANNEL 0 SIGNAL CONDITIONER ############ +;###################################################### + +;######### SIGNAL_CONDITIONER 0 CONFIG ############ +SignalConditioner0.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER 0 CONFIG ############ +DataTypeAdapter0.implementation=Pass_Through +DataTypeAdapter0.item_type=gr_complex + +;######### INPUT_FILTER 0 CONFIG ############ +InputFilter0.implementation=Freq_Xlating_Fir_Filter +InputFilter0.dump=false +InputFilter0.dump_filename=../data/input_filter_ch0.dat +InputFilter0.input_item_type=gr_complex +InputFilter0.output_item_type=gr_complex +InputFilter0.taps_item_type=float +InputFilter0.number_of_taps=5 +InputFilter0.number_of_bands=2 +InputFilter0.band1_begin=0.0 +InputFilter0.band1_end=0.45 +InputFilter0.band2_begin=0.55 +InputFilter0.band2_end=1.0 +InputFilter0.ampl1_begin=1.0 +InputFilter0.ampl1_end=1.0 +InputFilter0.ampl2_begin=0.0 +InputFilter0.ampl2_end=0.0 +InputFilter0.band1_error=1.0 +InputFilter0.band2_error=1.0 +InputFilter0.filter_type=bandpass +InputFilter0.grid_density=16 +InputFilter0.IF=0 +InputFilter0.decimation_factor=4 + +;######### RESAMPLER CONFIG 0 ############ +Resampler0.implementation=Pass_Through + + +;###################################################### +;######### RF CHANNEL 1 SIGNAL CONDITIONER ############ +;###################################################### + +;######### SIGNAL_CONDITIONER 1 CONFIG ############ +SignalConditioner1.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER 1 CONFIG ############ +DataTypeAdapter1.implementation=Pass_Through +DataTypeAdapter1.item_type=gr_complex + +;######### INPUT_FILTER 1 CONFIG ############ +InputFilter1.implementation=Freq_Xlating_Fir_Filter +InputFilter1.dump=false +InputFilter1.dump_filename=../data/input_filter_ch1.dat +InputFilter1.input_item_type=gr_complex +InputFilter1.output_item_type=gr_complex +InputFilter1.taps_item_type=float +InputFilter1.number_of_taps=5 +InputFilter1.number_of_bands=2 +InputFilter1.band1_begin=0.0 +InputFilter1.band1_end=0.45 +InputFilter1.band2_begin=0.55 +InputFilter1.band2_end=1.0 +InputFilter1.ampl1_begin=1.0 +InputFilter1.ampl1_end=1.0 +InputFilter1.ampl2_begin=0.0 +InputFilter1.ampl2_end=0.0 +InputFilter1.band1_error=1.0 +InputFilter1.band2_error=1.0 +InputFilter1.filter_type=bandpass +InputFilter1.grid_density=16 +InputFilter1.IF=0 +InputFilter1.decimation_factor=4 + +;######### RESAMPLER CONFIG 1 ############ +Resampler1.implementation=Pass_Through + + +;###################################################### +;######### RF CHANNEL 2 SIGNAL CONDITIONER ############ +;###################################################### + +;######### SIGNAL_CONDITIONER 2 CONFIG ############ +SignalConditioner2.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER 2 CONFIG ############ +DataTypeAdapter2.implementation=Pass_Through +DataTypeAdapter2.item_type=gr_complex + +;######### INPUT_FILTER 2 CONFIG ############ +InputFilter2.implementation=Freq_Xlating_Fir_Filter +InputFilter2.dump=false +InputFilter2.dump_filename=../data/input_filter_ch2.dat +InputFilter2.input_item_type=gr_complex +InputFilter2.output_item_type=gr_complex +InputFilter2.taps_item_type=float +InputFilter2.number_of_taps=5 +InputFilter2.number_of_bands=2 +InputFilter2.band1_begin=0.0 +InputFilter2.band1_end=0.45 +InputFilter2.band2_begin=0.55 +InputFilter2.band2_end=1.0 +InputFilter2.ampl1_begin=1.0 +InputFilter2.ampl1_end=1.0 +InputFilter2.ampl2_begin=0.0 +InputFilter2.ampl2_end=0.0 +InputFilter2.band1_error=1.0 +InputFilter2.band2_error=1.0 +InputFilter2.filter_type=bandpass +InputFilter2.grid_density=16 +InputFilter2.IF=0 +InputFilter2.decimation_factor=8 + + +;######### RESAMPLER CONFIG 2 ############ +Resampler2.implementation=Pass_Through + + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=10 +Channels_1B.count=10 +Channels_2S.count=10 +Channels_5X.count=2 +Channels_L5.count=2 + +;#GPS.prns=7,8 +;Channels.in_acquisition=2 + +;# CHANNEL CONNECTION + +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=0 +Channel6.RF_channel_ID=0 +Channel7.RF_channel_ID=0 +Channel8.RF_channel_ID=0 +Channel9.RF_channel_ID=0 +Channel10.RF_channel_ID=1 +Channel11.RF_channel_ID=1 +Channel12.RF_channel_ID=1 +Channel13.RF_channel_ID=1 +Channel14.RF_channel_ID=1 +Channel15.RF_channel_ID=1 +Channel16.RF_channel_ID=1 +Channel17.RF_channel_ID=1 +Channel18.RF_channel_ID=1 +Channel19.RF_channel_ID=1 +Channel20.RF_channel_ID=0 +Channel21.RF_channel_ID=0 +Channel22.RF_channel_ID=0 +Channel23.RF_channel_ID=0 +Channel24.RF_channel_ID=0 +Channel25.RF_channel_ID=0 +Channel26.RF_channel_ID=0 +Channel27.RF_channel_ID=0 +Channel28.RF_channel_ID=0 +Channel29.RF_channel_ID=0 +Channel30.RF_channel_ID=2 +Channel31.RF_channel_ID=2 +Channel32.RF_channel_ID=2 +Channel33.RF_channel_ID=2 +Channel34.RF_channel_ID=2 +Channel35.RF_channel_ID=2 +Channel36.RF_channel_ID=2 +Channel37.RF_channel_ID=2 +Channel38.RF_channel_ID=2 +Channel39.RF_channel_ID=2 +Channel40.RF_channel_ID=2 +Channel41.RF_channel_ID=2 +Channel42.RF_channel_ID=2 + +;Channel20.satellite=7 + + +;# GPS L1 CA +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.005 +Acquisition_1C.doppler_max=5000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.bit_transition_flag=false +Acquisition_1C.max_dwells=1 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;# Galileo E1 +Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 +;Acquisition_1B.threshold=0 +Acquisition_1B.pfa=0.0000002 +Acquisition_1B.doppler_max=5000 +Acquisition_1B.doppler_step=125 +Acquisition_1B.dump_filename=./acq_dump.dat + + +;# GPS L2C M +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition +Acquisition_2S.item_type=gr_complex +Acquisition_2S.threshold=0.00074 +;Acquisition_2S.pfa=0.001 +Acquisition_2S.doppler_max=5000 +Acquisition_2S.doppler_min=-5000 +Acquisition_2S.doppler_step=60 +Acquisition_2S.max_dwells=1 +Acquisition_2S.dump=false +Acquisition_2S.dump_filename=./acq_dump.dat + + +;# GALILEO E5a +Acquisition_5X.implementation=Galileo_E5a_Noncoherent_IQ_Acquisition_CAF +Acquisition_5X.item_type=gr_complex +Acquisition_5X.coherent_integration_time_ms=1 +Acquisition_5X.threshold=0.009 +Acquisition_5X.doppler_max=5000 +Acquisition_5X.doppler_step=125 +Acquisition_5X.bit_transition_flag=false +Acquisition_5X.max_dwells=1 +Acquisition_5X.CAF_window_hz=0 ; **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz +Acquisition_5X.Zero_padding=0 ; **Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. +Acquisition_5X.dump=false +Acquisition_5X.dump_filename=./acq_dump.dat + + +;# GPS L5 +Acquisition_L5.implementation=GPS_L5i_PCPS_Acquisition +Acquisition_L5.item_type=gr_complex +Acquisition_L5.threshold=0.00074 +;Acquisition_L5.pfa=0.001 +Acquisition_L5.doppler_max=5000 +Acquisition_L5.doppler_min=-5000 +Acquisition_L5.doppler_step=125 +Acquisition_L5.max_dwells=1 +Acquisition_L5.dump=false +Acquisition_L5.dump_filename=./acq_dump.dat + + + +;######### TRACKING CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=35.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; +Tracking_1C.early_late_space_chips=0.5; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ + +;######### GALILEO E1 TRK CONFIG ############ +Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking +Tracking_1B.item_type=gr_complex +Tracking_1B.pll_bw_hz=15.0; +Tracking_1B.dll_bw_hz=2.0; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ + + +;######### GPS L2C GENERIC TRACKING CONFIG ############ +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking +Tracking_2S.item_type=gr_complex +Tracking_2S.pll_bw_hz=2.0; +Tracking_2S.dll_bw_hz=0.25; +Tracking_2S.order=2; +Tracking_2S.early_late_space_chips=0.5; +Tracking_2S.dump=false +Tracking_2S.dump_filename=./tracking_ch_ + +;######### GALILEO E5 TRK CONFIG ############ +Tracking_5X.implementation=Galileo_E5a_DLL_PLL_Tracking +Tracking_5X.item_type=gr_complex +Tracking_5X.track_pilot=true +Tracking_5X.pll_bw_hz=15.0; +Tracking_5X.dll_bw_hz=2.0; +Tracking_5X.pll_bw_narrow_hz=5.0; +Tracking_5X.dll_bw_narrow_hz=1.0; +Tracking_5X.order=2; +Tracking_5X.early_late_space_chips=0.5; +Tracking_5X.dump=false +Tracking_5X.dump_filename=./tracking_ch_ + +;######### GALILEO E5 TRK CONFIG ############ +Tracking_L5.implementation=GPS_L5_DLL_PLL_Tracking +Tracking_L5.item_type=gr_complex +Tracking_L5.track_pilot=true +Tracking_L5.pll_bw_hz=15.0; +Tracking_L5.dll_bw_hz=2.0; +Tracking_L5.pll_bw_narrow_hz=4.0; +Tracking_L5.dll_bw_narrow_hz=1.0; +Tracking_L5.order=2; +Tracking_L5.early_late_space_chips=0.5; +Tracking_L5.dump=false +Tracking_L5.dump_filename=./tracking_ch_ + + +;######### TELEMETRY DECODER CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + +TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder +TelemetryDecoder_1B.dump=false + +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder +TelemetryDecoder_2S.dump=false + +TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder +TelemetryDecoder_5X.dump=false + +TelemetryDecoder_L5.implementation=GPS_L5_Telemetry_Decoder +TelemetryDecoder_L5.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=10 +PVT.display_rate_ms=100 +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false +PVT.dump_filename=./PVT diff --git a/conf/gnss-sdr_multisource_Hybrid_ishort.conf b/conf/gnss-sdr_multisource_Hybrid_ishort.conf index 00d85930f..3394aff23 100644 --- a/conf/gnss-sdr_multisource_Hybrid_ishort.conf +++ b/conf/gnss-sdr_multisource_Hybrid_ishort.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -6,291 +8,80 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -GNSS-SDR.internal_fs_hz=4000000 -Receiver.sources_count=2 -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. -SignalSource.enable_throttle_control=false +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=4000000 -;#repeat: Repeat the processing file. Disable this option in this version +Receiver.sources_count=2 + +SignalSource.enable_throttle_control=false SignalSource.repeat=false ;######### SIGNAL_SOURCE 0 CONFIG ############ - -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource0.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource0.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. SignalSource0.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource0.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource0.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource0.samples=0 -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource0.dump=false - -SignalSource0.dump_filename=../data/signal_source.dat ;######### SIGNAL_SOURCE 1 CONFIG ############ - -;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource1.implementation=File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource1.filename=/datalogger/signals/CTTC/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN/2013_04_04_GNSS_SIGNAL_at_CTTC_SPAIN.dat ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. SignalSource1.item_type=ishort - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource1.sampling_frequency=4000000 - -;#freq: RF front-end center frequency in [Hz] SignalSource1.freq=1575420000 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource1.samples=0 -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource1.dump=false - -SignalSource1.dump_filename=../data/signal_source.dat - ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter0.implementation=Ishort_To_Complex ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter0.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of GNU Radio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired response on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter0.taps_item_type=float -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter0.band1_begin=0.0 -InputFilter0.band1_end=0.45 -InputFilter0.band2_begin=0.55 -InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter0.ampl1_begin=1.0 -InputFilter0.ampl1_end=1.0 -InputFilter0.ampl2_begin=0.0 -InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter0.band1_error=1.0 -InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter0.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter0.sampling_frequency=4000000 -InputFilter0.IF=0 ;######### RESAMPLER 1 CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neighborhood interpolation - Resampler1.implementation=Pass_Through - -;#dump: Dump the resampled data to a file. Resampler1.dump=false -;#dump_filename: Log path and filename. Resampler1.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Resampler1.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler1.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler1.sample_freq_out=4000000 ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner1.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ -;## Changes the type of input data. Please disable it in this version. -;#implementation: [Pass_Through] disables this block DataTypeAdapter1.implementation=Ishort_To_Complex ;######### INPUT_FILTER 1 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Pass_Through] disables this block -;#[Fir_Filter] enables a FIR Filter -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz. - InputFilter1.implementation=Pass_Through - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false -;#dump_filename: Log path and filename. -InputFilter1.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of GNU Radio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired response on those bands, and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. -InputFilter1.input_item_type=gr_complex - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. -InputFilter1.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. -InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time -InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. -InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - -InputFilter1.band1_begin=0.0 -InputFilter1.band1_end=0.45 -InputFilter1.band2_begin=0.55 -InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - -InputFilter1.ampl1_begin=1.0 -InputFilter1.ampl1_end=1.0 -InputFilter1.ampl2_begin=0.0 -InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands -InputFilter1.band1_error=1.0 -InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" -InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. -InputFilter1.grid_density=16 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter1.IF is the intermediate frequency (in Hz) shifted down to zero Hz - -InputFilter1.sampling_frequency=4000000 -InputFilter1.IF=0 ;######### RESAMPLER 1 CONFIG ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neighborhood interpolation - Resampler1.implementation=Pass_Through - -;#dump: Dump the resampled data to a file. Resampler1.dump=false -;#dump_filename: Log path and filename. -Resampler1.dump_filename=../data/resampler.dat - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +Resampler1.dump_filename=../data/resampler.dat. Resampler1.item_type=gr_complex - -;#sample_freq_in: the sample frequency of the input signal Resampler1.sample_freq_in=4000000 - -;#sample_freq_out: the desired sample frequency of the output signal Resampler1.sample_freq_out=4000000 ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. -Channels_GPS.count=2 -;#count: Number of available Galileo satellite channels. -Channels_Galileo.count=2 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver +Channels_1C.count=2 +Channels_1B.count=2 Channels.in_acquisition=1 -;#system: GPS, GLONASS, GALILEO, SBAS or COMPASS -;#if the option is disabled by default is assigned GPS -Channel.system=GPS, Galileo + ;# CHANNEL CONNECTION Channel0.RF_channel_ID=0 @@ -303,155 +94,74 @@ Channel.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_GPS.dump=false -;#filename: Log path and filename -Acquisition_GPS.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_GPS.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_GPS.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_GPS.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_GPS.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold -Acquisition_GPS.threshold=0.0075 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -;Acquisition_GPS.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_GPS.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] -Acquisition_GPS.doppler_step=500 +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.coherent_integration_time_ms=1 +Acquisition_1C.threshold=0.0075 +;Acquisition_1C.pfa=0.01 +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ +Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 +;Acquisition_1B.threshold=0 +Acquisition_1B.pfa=0.0000008 +Acquisition_1B.doppler_max=15000 +Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_Galileo.dump=false -;#filename: Log path and filename -Acquisition_Galileo.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_Galileo.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_Galileo.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_Galileo.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_Galileo.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold -;Acquisition_Galileo.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] -Acquisition_Galileo.pfa=0.0000008 -;#doppler_max: Maximum expected Doppler shift [Hz] -Acquisition_Galileo.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] -Acquisition_Galileo.doppler_step=125 ;######### TRACKING GPS CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.pll_bw_hz=45.0; +Tracking_1C.dll_bw_hz=4.0; +Tracking_1C.order=3; +Tracking_1C.dump=false +Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] -Tracking_GPS.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. -Tracking_GPS.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_GPS.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_GPS.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_GPS.dump_filename=../data/epl_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_GPS.pll_bw_hz=45.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_GPS.dll_bw_hz=4.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_GPS.order=3; ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [Galileo_E1_DLL_PLL_VEML_Tracking] -Tracking_Galileo.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. -Tracking_Galileo.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_Galileo.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_Galileo.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_Galileo.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_Galileo.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_Galileo.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_Galileo.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo -Tracking_Galileo.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] -Tracking_Galileo.very_early_late_space_chips=0.6; +Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking +Tracking_1B.item_type=gr_complex +Tracking_1B.pll_bw_hz=15.0; +Tracking_1B.dll_bw_hz=2.0; +Tracking_1B.order=3; +Tracking_1B.early_late_space_chips=0.15; +Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A -TelemetryDecoder_GPS.implementation=GPS_L1_CA_Telemetry_Decoder -TelemetryDecoder_GPS.dump=false -;#decimation factor -TelemetryDecoder_GPS.decimation_factor=4; +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B -TelemetryDecoder_Galileo.implementation=Galileo_E1B_Telemetry_Decoder -TelemetryDecoder_Galileo.dump=false +TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder +TelemetryDecoder_1B.dump=false ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic PVT.output_rate_ms=100; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. PVT.dump_filename=./PVT +PVT.dump=false diff --git a/conf/gnss-sdr_multisource_Hybrid_nsr.conf b/conf/gnss-sdr_multisource_Hybrid_nsr.conf index 5ced6c5a5..aecb783a6 100644 --- a/conf/gnss-sdr_multisource_Hybrid_nsr.conf +++ b/conf/gnss-sdr_multisource_Hybrid_nsr.conf @@ -1,4 +1,6 @@ -; Default configuration file +; This is a GNSS-SDR configuration file +; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/ + ; You can define your own receiver and invoke it by doing ; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf ; @@ -8,286 +10,108 @@ Receiver.sources_count=2 ;######### GLOBAL OPTIONS ################## -;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz]. -;GNSS-SDR.internal_fs_hz=6826700 -GNSS-SDR.internal_fs_hz=2560000 -;GNSS-SDR.internal_fs_hz=4096000 -;GNSS-SDR.internal_fs_hz=5120000 +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +;GNSS-SDR.internal_fs_sps=6826700 +GNSS-SDR.internal_fs_sps=2560000 +;GNSS-SDR.internal_fs_sps=4096000 +;GNSS-SDR.internal_fs_sps=5120000 -;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. -; it helps to not overload the CPU, but the processing time will be longer. SignalSource.enable_throttle_control=false - -;#repeat: Repeat the processing file. Disable this option in this version SignalSource.repeat=false ;######### SIGNAL_SOURCE 0 CONFIG ############ -;#implementation: Use [File_Signal_Source] [Nsr_File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource0.implementation=Nsr_File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource0.filename=/datalogger/signals/ifen/E1L1_FE0_Band0.stream ; <- PUT YOUR FILE HERE - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource0.item_type=byte - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource0.sampling_frequency=20480000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource0.freq=1575420000 - -;#subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0) -SignalSource0.subdevice=B:0 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource0.samples=0 -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource0.dump=false - -SignalSource0.dump_filename=../data/signal_source.dat ;######### SIGNAL_SOURCE 1 CONFIG ############ -;#implementation: Use [File_Signal_Source] [Nsr_File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) SignalSource1.implementation=Nsr_File_Signal_Source - -;#filename: path to file with the captured GNSS signal samples to be processed SignalSource1.filename=/datalogger/signals/ifen/E1L1_FE0_Band0.stream - -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. SignalSource1.item_type=byte - -;#sampling_frequency: Original Signal sampling frequency in [Hz] SignalSource1.sampling_frequency=20480000 - -;#freq: RF front-end center frequency in [Hz] -SignalSource1.freq=1575420000 - -;#subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0) -SignalSource1.subdevice=B:0 - -;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. SignalSource1.samples=0 -;#dump: Dump the Signal source data to a file. Disable this option in this version -SignalSource1.dump=false - -SignalSource1.dump_filename=../data/signal_source.dat - ;######### SIGNAL_CONDITIONER 0 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner0.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 0 CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.item_type=float ;######### INPUT_FILTER 0 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - InputFilter0.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter0.dump=false - -;#dump_filename: Log path and filename. InputFilter0.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter0.input_item_type=float - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter0.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter0.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter0.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter0.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter0.band1_begin=0.0 InputFilter0.band1_end=0.45 InputFilter0.band2_begin=0.55 InputFilter0.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter0.ampl1_begin=1.0 InputFilter0.ampl1_end=1.0 InputFilter0.ampl2_begin=0.0 InputFilter0.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter0.band1_error=1.0 InputFilter0.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter0.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter0.grid_density=16 - -;# Original sampling frequency stored in the signal file InputFilter0.sampling_frequency=20480000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter0.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter0.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block InputFilter0.decimation_factor=8 ;######### RESAMPLER CONFIG 0 ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation Resampler0.implementation=Pass_Through ;######### SIGNAL_CONDITIONER 1 CONFIG ############ -;## It holds blocks to change data type, filter and resample input data. - -;#implementation: Use [Pass_Through] or [Signal_Conditioner] -;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks -;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks SignalConditioner1.implementation=Signal_Conditioner ;######### DATA_TYPE_ADAPTER 1 CONFIG ############ -;## Changes the type of input data. -;#implementation: [Pass_Through] disables this block DataTypeAdapter1.implementation=Pass_Through DataTypeAdapter1.item_type=float ;######### INPUT_FILTER 1 CONFIG ############ -;## Filter the input data. Can be combined with frequency translation for IF signals - -;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter] -;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation -;# that shifts IF down to zero Hz. - InputFilter1.implementation=Freq_Xlating_Fir_Filter - -;#dump: Dump the filtered data to a file. InputFilter1.dump=false - -;#dump_filename: Log path and filename. InputFilter1.dump_filename=../data/input_filter.dat - -;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation. -;#These options are based on parameters of gnuradio's function: gr_remez. -;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse -;#reponse given a set of band edges, the desired reponse on those bands, -;#and the weight given to the error in those bands. - -;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version. InputFilter1.input_item_type=float - -;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version. InputFilter1.output_item_type=gr_complex - -;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version. InputFilter1.taps_item_type=float - -;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time InputFilter1.number_of_taps=5 - -;#number_of _bands: Number of frequency bands in the filter. InputFilter1.number_of_bands=2 - -;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...]. -;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2) -;#The number of band_begin and band_end elements must match the number of bands - InputFilter1.band1_begin=0.0 InputFilter1.band1_end=0.45 InputFilter1.band2_begin=0.55 InputFilter1.band2_end=1.0 - -;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...]. -;#The number of ampl_begin and ampl_end elements must match the number of bands - InputFilter1.ampl1_begin=1.0 InputFilter1.ampl1_end=1.0 InputFilter1.ampl2_begin=0.0 InputFilter1.ampl2_end=0.0 - -;#band_error: weighting applied to each band (usually 1). -;#The number of band_error elements must match the number of bands InputFilter1.band1_error=1.0 InputFilter1.band2_error=1.0 - -;#filter_type: one of "bandpass", "hilbert" or "differentiator" InputFilter1.filter_type=bandpass - -;#grid_density: determines how accurately the filter will be constructed. -;The minimum value is 16; higher values are slower to compute the filter. InputFilter1.grid_density=16 - -;# Original sampling frequency stored in the signal file InputFilter1.sampling_frequency=20480000 - -;#The following options are used only in Freq_Xlating_Fir_Filter implementation. -;#InputFilter1.IF is the intermediate frequency (in Hz) shifted down to zero Hz - InputFilter1.IF=5499998.47412109 - -;# Decimation factor after the frequency tranaslating block InputFilter1.decimation_factor=8 ;######### RESAMPLER CONFIG 1 ############ -;## Resamples the input data. - -;#implementation: Use [Pass_Through] or [Direct_Resampler] -;#[Pass_Through] disables this block -;#[Direct_Resampler] enables a resampler that implements a nearest neigbourhood interpolation Resampler1.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -;#count: Number of available GPS satellite channels. Channels_1C.count=8 -;#count: Number of available Galileo satellite channels. Channels_1B.count=8 -;#in_acquisition: Number of channels simultaneously acquiring for the whole receiver Channels.in_acquisition=1 -;#signal: -;# "1C" GPS L1 C/A -;# "2S" GPS L2 L2C (M) -;# "1B" GALILEO E1 B (I/NAV OS/CS/SoL) -;# "5X" GALILEO E5a I+Q - ;# SOURCE CONNECTION Channel0.RF_channel_ID=0 Channel1.RF_channel_ID=0 @@ -328,156 +152,78 @@ Channel15.signal=1B ;######### GPS ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1C.dump=false -;#filename: Log path and filename -Acquisition_1C.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1C.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1C.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1C.sampled_ms=1 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition -;#threshold: Acquisition threshold +Acquisition_1C.item_type=gr_complex +Acquisition_1C.scoherent_integration_time_ms=1 Acquisition_1C.threshold=0.0075 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] ;Acquisition_1C.pfa=0.01 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1C.doppler_max=10000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1C.doppler_step=500 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat ;######### GALILEO ACQUISITION CONFIG ############ - -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] -Acquisition_1B.dump=false -;#filename: Log path and filename -Acquisition_1B.dump_filename=./acq_dump.dat -;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. -Acquisition_1B.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] -Acquisition_1B.if=0 -;#sampled_ms: Signal block duration for the acquisition signal detection [ms] -Acquisition_1B.sampled_ms=4 -;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition -;#threshold: Acquisition threshold +Acquisition_1B.item_type=gr_complex +Acquisition_1B.coherent_integration_time_ms=4 ;Acquisition_1B.threshold=0 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition_1B.pfa=0.0000002 -;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition_1B.doppler_max=15000 -;#doppler_max: Doppler step in the grid search [Hz] Acquisition_1B.doppler_step=125 +Acquisition_1B.dump=false +Acquisition_1B.dump_filename=./acq_dump.dat + ;######### TRACKING GPS CONFIG ############ - -;#implementation: Selected tracking algorithm: [GPS_L1_CA_DLL_PLL_Tracking] or [GPS_L1_CA_DLL_PLL_C_Aid_Tracking] or [GPS_L1_CA_TCP_CONNECTOR_Tracking] or [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking -;#item_type: Type and resolution for each of the signal samples. Tracking_1C.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1C.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +Tracking_1C.pll_bw_hz=45.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.order=3; Tracking_1C.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. Tracking_1C.dump_filename=../data/epl_tracking_ch_ -;#pll_bw_hz: PLL loop filter bandwidth [Hz] -Tracking_1C.pll_bw_hz=45.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] -Tracking_1C.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] -Tracking_1C.order=3; ;######### TRACKING GALILEO CONFIG ############ - -;#implementation: Selected tracking algorithm: [Galileo_E1_DLL_PLL_VEML_Tracking] Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking -;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking_1B.item_type=gr_complex - -;#sampling_frequency: Signal Intermediate Frequency in [Hz] -Tracking_1B.if=0 - -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] -Tracking_1B.dump=false - -;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. -Tracking_1B.dump_filename=../data/veml_tracking_ch_ - -;#pll_bw_hz: PLL loop filter bandwidth [Hz] Tracking_1B.pll_bw_hz=15.0; - -;#dll_bw_hz: DLL loop filter bandwidth [Hz] Tracking_1B.dll_bw_hz=2.0; - -;#order: PLL/DLL loop filter order [2] or [3] Tracking_1B.order=3; - -;#early_late_space_chips: correlator early-late space [chips]. Use [0.5] for GPS and [0.15] for Galileo Tracking_1B.early_late_space_chips=0.15; - -;#very_early_late_space_chips: only for [Galileo_E1_DLL_PLL_VEML_Tracking], correlator very early-late space [chips]. Use [0.6] Tracking_1B.very_early_late_space_chips=0.6; +Tracking_1B.dump=false +Tracking_1B.dump_filename=../data/veml_tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ -;#implementation: Use [GPS_L1_CA_Telemetry_Decoder] for GPS L1 C/A TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false -;#decimation factor -TelemetryDecoder_1C.decimation_factor=1; + ;######### TELEMETRY DECODER GALILEO CONFIG ############ -;#implementation: Use [Galileo_E1B_Telemetry_Decoder] for Galileo E1B TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder -TelemetryDecoder_1B.dump=false -TelemetryDecoder_1B.decimation_factor=4; ;######### OBSERVABLES CONFIG ############ -;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=Hybrid_Observables - -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false - -;#dump_filename: Log path and filename. Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ -;#implementation: Position Velocity and Time (PVT) implementation algorithm: Use [GPS_L1_CA_PVT] in this version. -PVT.implementation=Hybrid_PVT - -;#averaging_depth: Number of PVT observations in the moving average algorithm -PVT.averaging_depth=10 - -;#flag_average: Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] -PVT.flag_averaging=false - -;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time (for GPS CA L1 is 1ms) [ms] -PVT.output_rate_ms=10; - -;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. -PVT.display_rate_ms=500; - -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] -PVT.dump=false - +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=true; +PVT.nmea_dump_devname=/dev/pts/4 PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 - -;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump=false PVT.dump_filename=./PVT diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index b4e04e2c1..a6cc9eef2 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,12 @@ -:+1::tada: Hello, and thanks for contributing to [GNSS-SDR](http://gnss-sdr.org)! :tada::+1: +:+1::tada: Hello, and thanks for contributing to [GNSS-SDR](https://gnss-sdr.org)! :tada::+1: Before submitting your pull request, please make sure the following is done: 1. You undertake the [Contributor Covenant Code of Conduct](https://github.com/gnss-sdr/gnss-sdr/blob/master/CODE_OF_CONDUCT.md). 2. If you are a first-time contributor, after your pull request you will be asked to sign an Individual Contributor License Agreement ([CLA](https://en.wikipedia.org/wiki/Contributor_License_Agreement)) before your code gets accepted into `master`. This license is for your protection as a Contributor as well as for the protection of [CTTC](http://www.cttc.es/); it does not change your rights to use your own contributions for any other purpose. Except for the license granted therein to CTTC and recipients of software distributed by CTTC, you reserve all right, title, and interest in and to your contributions. The information you provide in that CLA will be maintained in accordance with [CTTC's privacy policy](http://www.cttc.es/privacy/). 3. You have read the [Contributing Guidelines](https://github.com/gnss-sdr/gnss-sdr/blob/master/CONTRIBUTING.md). - 4. You have read the [coding style guide](http://gnss-sdr.org/coding-style/). - 5. You have forked the [gnss-sdr upstream repository](https://github.com/gnss-sdr/gnss-sdr) and have created your branch from `next` (or any other currently living branch in the upstream repository). - 6. Please include a description of your changes here. + 4. You have read the [coding style guide](https://gnss-sdr.org/coding-style/). + 5. Specifically, you have read [about clang-format](https://gnss-sdr.org/coding-style/#use-tools-for-automated-code-formatting) and you have applied it. + 6. You have forked the [gnss-sdr upstream repository](https://github.com/gnss-sdr/gnss-sdr) and have created your branch from `next` (or any other currently living branch in the upstream repository). + 7. Please include a description of your changes here. -**Please feel free to delete this line and the above text once you have read it and in case you want to go on with your pull request.** \ No newline at end of file +**Please feel free to delete this line and the above text once you have read it and in case you want to go on with your pull request, and explain your intend below.** diff --git a/docs/changelog b/docs/changelog new file mode 100644 index 000000000..f9effa7d2 --- /dev/null +++ b/docs/changelog @@ -0,0 +1,417 @@ +## [0.0.10](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.10) + +This release has several improvements in different dimensions, addition of new features and bug fixes: + +### Improvements in Accuracy: + +- Part of the RTKLIB core library has been integrated into GNSS-SDR. There is now a single PVT block implementation which makes use of RTKLIB to deliver PVT solutions, including Single and PPP navigation modes. +- Fixed CN0 estimation for other correlation times than 1 ms. +- Improved computation of tracking parameters and GNSS observables. +- Other minor bug fixes. + + +### Improvements in Availability: + +- Internal Finite State Machines rewritten for improved continuity in delivering position fixes. This fixes a bug that was stalling the receiver after about six hours of continuous operation. +- Redesign of the time counter for enhanced continuity. +- Improved flow graph in multi-system configurations: the receiver does not get stalled anymore if no signal is found from the first system. +- Improved acquisition and tracking sensitivity. +- Added mechanisms for Assisted GNSS, thus shortening the Time-To-First-Fix. Provision of data via XML files or via SUPL v1.0. Documented at https://gnss-sdr.org/docs/sp-blocks/global-parameters/ +- Other minor bug fixes. + + +### Improvements in Efficiency: + +- Added the possibility of non-blocking acquisition, which works well when using real-time data from an RF front-end. +- Improved flow graph in multi-band configurations: satellites acquired in one band are immediately searched in others. +- Complex local codes have been replaced by real codes, alleviating the computational burden. +- New volk_gnsssdr kernels: volk_gnsssdr_16i_xn_resampler_16i_xn.h, volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h, volk_gnsssdr_32f_xn_resampler_32f_xn.h, volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h +- Some AVX2 implementations added to the volk_gnsssdr library. +- Improvement in C++ usage: Use of const container calls when result is immediately converted to a const iterator. Using these members removes an implicit conversion from iterator to const_iterator. +- Output printers can be shut down, with some savings in memory and storage requirements. +- A number of code optimizations here and there. + + +### Improvements in Flexibility: + +- A number of new parameters have been exposed to the configuration system. +- Possibility to choose Pilot or Data component for tracking of GPS L5 and Galileo E5a signals. +- Enabled extended coherent integration times for signal tracking. +- Configurable coherent and/or non-coherent signal acquisition. +- Some configuration parameters can now be overridden by commandline flags for easier use in scripts. + + +### Improvements in Interoperability: + +- Added the GPS L5 receiver chain. +- Added the GLONASS L1 SP receiver chain. +- Added the GLONASS L2 SP receiver chain. +- Improvements in the Galileo E5a and GPS L2C receiver chains. +- Updated list of available GNSS satellites. +- Added five more signal sources: "Fmcomms2_Signal_Source" (requires gr-iio), "Plutosdr_Signal Source" (requires gr-iio), "Spir_GSS6450_File_Signal_Source", "Labsat_Signal_Source" and "Custom_UDP_Signal_Source" (requires libpcap). Documented in https://gnss-sdr.org/docs/sp-blocks/signal-source/ +- Improved support for BladeRF, HackRF and RTL-SDR front-ends. +- Added tools for the interaction with front-ends based on the AD9361 chipset. +- Intermediate results are now saved in MAT-file format (.mat), readable from Matlab/Octave and from Python via h5py. +- Added the GPX output format. +- Improvements in the generation of KML files. +- Improvements in the NMEA output. The receiver can produce GPGGA, GPRMC, GPGSA, GPGSV, GAGSA and GAGSV sentences. +- Improvements in the RTCM server stability. +- Improvements in the correctness of generated RINEX files. +- The receiver can read and make use of Galileo almanac XML files published by the European GNSS Service Centre at https://www.gsc-europa.eu/system-status/almanac-data +- Own-defined XML schemas for navigation data published at https://github.com/gnss-sdr/gnss-sdr/tree/next/docs/xml-schemas +- Added program rinex2assist to convert RINEX navigation files into XML files usable for Assisted GNSS. Only available building from source. See https://github.com/gnss-sdr/gnss-sdr/tree/next/src/utils/rinex2assist + + +### Improvements in Maintainability: + +- Setup of a Continuous Integration system that checks building and runs QA code in a wide range of GNU/Linux distributions (Arch Linux, CentOS, Debian, Fedora, OpenSUSE, Ubuntu) and releases. See https://gitlab.com/gnss-sdr/gnss-sdr +- Creation of multi-system processing blocks, drastically reducing code duplication and maintainability time. +- Automated code formatting with clang-format. This tool is widely available and easy to integrate into many code editors, and it also can be used from the command line. It cuts time spent on adhering to the project's code formatting style. +- Improvement in C++ usage: C-style casts have been replaced by C++ casts. C-style casts are difficult to search for. C++ casts provide compile time checking ability and express programmers' intent better, so they are safer and clearer. +- Improvement in C++ usage: The override special identifier is now used when overriding a virtual function. This helps the compiler to check for type changes in the base class, making the detection of errors easier. +- Improvement in C++ usage: A number of unused includes have been removed. Order of includes set to: local (in-source) headers, then library headers, then system headers. This helps to detect missing includes. +- Improvement in C++ usage: Enhanced const correctness. Misuses of those variables are detected by the compiler. +- Improved code with clang-tidy and generation of a compile_commands.json file containing the exact compiler calls for all translation units of the project in machine-readable form if clang-tidy is detected. +- Applied some style rules to CMake scripts. +- Minimal versions of dependencies identified and detected. + + +### Improvements in Portability: + +- Several CMake scripts improvements, more verbose outputs in case of errors. Building configuration has been documented in https://gnss-sdr.org/docs/tutorials/configuration-options-building-time/ +- Improved SDK for cross-compilation in embedded devices. Documented in https://gnss-sdr.org/docs/tutorials/cross-compiling/ +- Improved control over minimum required versions for core dependencies. +- The software builds with C++11, C++14 and C++17 standards. +- The software can now be built using GCC >= 4.7.2 or LLVM/Clang >= 3.4.0 compilers on GNU/Linux, and with Clang/AppleClang on MacOS. +- The Ninja build system can be used in replacement of make. +- The volk_gnsssdr library can be built using Python 2.7+ or Python 3.6+. +- The volk_gnsssdr library is now ready for AArch64 NEON instructions. +- Improved detection of required and optional dependencies in many GNU/Linux distributions and processor architectures. +- Improvement in C++ usage: The library has been replaced by the more modern and portable (except for the interaction with RTKLIB). +- Improvement in C++ usage: The library has been replaced by the more modern and portable for file handling. +- Improvement in C++ usage: C++ libraries preferred over C libraries (e.g., instead of , instead of ). +- Fix compatibility with Boost 1.67 (closes Debian bug #911882 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=911882) +- Fixes required by Debian packaging. +- Fixes required by Macports packaging. +- A downside in portability: BLAS and LAPACK libraries are now required even in ARM devices. +- A downside in portability: the matio library >= 1.5.3 is a new required dependency. If not found, it is downloaded and built automatically at building time, but this requires libtool, automake and hdf5 already installed in the system. +- A downside in portability: the PugiXML library is a new required dependency. If not found, it is downloaded and built automatically at building time. + + +### Improvements in Reliability: + +- Introduced 3 new Input Filter implementations for pulsed and narrowband interference mitigation: `Pulse_Blanking_Filter`, `Notch_Filter` and `Notch_Filter_Lite`. Documented in https://gnss-sdr.org/docs/sp-blocks/input-filter/ +- Improved flow graph stability. +- Introduction of high-integrity C++ practices into the source code and included in the coding style guide. See https://gnss-sdr.org/coding-style/ +- Fixed a number of defects detected by Coverity Scan. +- Improvement of QA code and addition of a number of new tests. Documented at https://gnss-sdr.org/docs/tutorials/testing-software-receiver-2/ +- Improvement in C++ usage: rand() function replaced by library. +- Improvement in C++ usage: strlen and strncpy have been replaced by safer C++ counterparts. +- Improvement in C++ usage: Some destructors have been fixed, avoiding segmentation faults when exiting the program. +- Website switched from http to https. Links in the source tree switched when available. + + +### Improvements in Reproducibility: + +- Setup of a Continuous Reproducibility system at GitLab for the automatic reproduction of experiments. The concept was introduced in https://ieeexplore.ieee.org/document/8331069/ Example added in the src/utils/reproducibility/ieee-access18/ folder. +- Fixes of Lintian warnings related to build reproducibility. + + +### Improvements in Scalability: + +- Improvements in multi-system, multi-band receiver configurations. The receiver now accepts any number of channels and systems in the three available bands. +- All possible combinations of signals and integration times are now accepted by the Observables block. + + +### Improvements in Testability: + +- Several Unit Tests added. Documentation of testing concepts and available tests at https://gnss-sdr.org/docs/tutorials/testing-software-receiver/ +- New extra unit test AcquisitionPerformanceTest checks the performance of Acquisition blocks. +- New extra unit test TrackingPullInTest checks acquisition to tracking transition. +- New extra unit test HybridObservablesTest checks the generation of observables. +- Improved system testing: position_test accepts a wide list of parameters and can be used with external files. +- Receiver channels can now be fixed to a given satellite. +- Testing integrated in a Continuous Reproducibility system (see above). +- Improved CTest support in volk_gnsssdr. + + +### Improvements in Usability: + +- All Observables block implementations have been merged into a single implementation for all kinds of GNSS signals, making it easier to configure. +- All PVT block implementations have been merged into a single implementation for all kinds of GNSS signals, making it easier to configure. +- Misleading parameter name GNSS-SDR.internal_fs_hz has been replaced by GNSS-SDR.internal_fs_sps. The old parameter name is still read. If found, a warning is provided to the user. The old name will be removed in future releases. +- Updated and improved online documentation of processing blocks at https://gnss-sdr.org/docs/sp-blocks/ +- Improved documentation of required dependency packages in several GNU/Linux distributions. +- Dump and output files can now be stored anywhere. +- Parameter names with the same role have been harmonized within different block implementations. +- Added a changelog, a code of conduct, a contributing guide and a pull-request template in the source tree. +- Added colors to the commandline user interface. +- Updated manfiles. +- Updated examples of configuration files under the conf/ folder. + + + +See the definitions of concepts and metrics at https://gnss-sdr.org/design-forces/ + + + + +## [0.0.9](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.9) + +DOI: https://doi.org/10.5281/zenodo.291371 + +This release has several improvements, addition of new features and bug fixes in many dimensions: + +### Improvements in Accuracy: + +- Major rewriting in the generation of pseudoranges. +- Fixed bug in Galileo E5a/I codes. +- Fixed bug in Galileo E1 correlator spacing. +- Fixed bug that was causing errors in receivers above the troposphere. +- Fixed 16-bit complex resampler. +- Improved time tracking algorithm. +- Added Bancroft's algorithm implementation for PVT initialization. + + +### Improvements in Availability: + +- Improved numerical stability of the PVT solution. The infamous bug that was causing apparently random error peaks has finally been fixed. + + +### Improvements in Efficiency: + +- VOLK_GNSSSDR: Added NEON,AVX and unaligned protokernels for volk_gnsssdr_32f_index_max_32 kernel. +- VOLK_GNSSSDR: Added volk_gnsssdr-config-info to the list of generated executables. + + +### Improvements in Flexibility: + +- Added maximum number of dwells in the Tong algorithm. + + +### Improvements in Interoperability: + +- Added six new Galileo satellites: FM7, FM10, FM11, FM12, FM13, FM14. +- The Hybrid_Observables and Hybrid_PVT implementations can now handle more types of GNSS signals. +- The RINEX printer can now print L2C and E5a observables and navigation files, including multiband configurations. +- Added RTCM 3.2 output to more receiver configurations. + + +### Improvements in Maintainability: + +- The VOLK_GNSSSDR library can now be built with Python 3. Switched dependencies for VOLK_GNSSDR: from (old, python2.7-only) python-cheetah templates to Python3 friendly python-mako and python-six. So, Python-cheetah dependency has been dropped, and python-mako and python-six have been added. +- If suitable versions of gflags, glog, armadillo or googletest are not found in the system, they will be downloaded and built at compile time (versions 2.2.0, 0.3.4, 7.600.2 and 1.8.0, respectively). +- Fixed more than 30 defects detected by Coverity Scan. +- Added CMake Python finder and module checker. +- Deleted files related to CPack. +- Fixes, updates and improvements in the documentation. +- Improvements in CMake scripts: General code cleaning and addition of comments. Improved user information in case of failure. Improved detection of dependencies in more processor architectures (e.g. aarch64). + + +### Improvements in Marketability: + +- Reduced time from a commit to deployment (see virtualization mechanisms in Portability). + + +### Improvements in Portability: + +- Now GNSS-SDR can be run in virtual environments through snap packages (see https://github.com/carlesfernandez/snapcraft-sandbox) and docker images (see https://github.com/carlesfernandez/docker-gnsssdr). +- Now GNSS-SDR is adapted to cross-compiling environments for embedded devices (see https://github.com/carlesfernandez/oe-gnss-sdr-manifest). +- BLAS and LAPACK libraries are no longer mandatory on ARM devices. + + +### Improvements in Scalability: + +- Fixed bug in acquisition with rata rates higher than 16 Msps in 4ms code periods. + + +### Improvements in Testability: + +- Major QA source code refactoring: they has been split into src/tests/unit-tests and src/tests/system-tests folders. They are optionally built with the ENABLE_UNIT_TESTING=ON (unit testing QA code), ENABLE_UNIT_TESTING_EXTRA=ON (unit tests that require extra files downloaded at configure time), ENABLE_SYSTEM_TESTING=ON (system tests, such as measurement of Time-To-First-Fix) and ENABLE_SYSTEM_TESTING_EXTRA=ON (extra system test requiring external tools, automatically downloaded and built at building time) configuration flags. The EXTRA options also download and build a custom software-defined signal generator and version 2.9 of GPSTk, if not already found on the system. Download and local link of version 2.9 can be forced by ENABLE_OWN_GPSTK=ON building configuration flag. Only ENABLE_UNIT_TESTING is set to ON by default. +- Unit tests added: CPU_multicorrelator_test and GPU_multicorrelator_test measure computer performance in multicorrelator setups. +- Unit tests added: GpsL1CADllPllTracking and GpsL1CATelemetryDecoderTest. +- System test added: ttff_gps_l1 performs a set of cold / assisted runs of the software receiver and computes statistics about the obtained Time To First Fix. +- System test added: obs_gps_l1_system_test uses an external software-defined signal generator to produce raw digital GNSS signal from a RINEX navigation file and a position (static or dynamic), processes it with GNSS-SDR, and then compares the RINEX observation file produced by the software receiver to that produced by the signal generator. +- Software Development Kit provided for embedded devices (see https://gnss-sdr.org/docs/tutorials/cross-compiling/). + +### Improvements in Usability: + +- Now the block factory automatically detects Channel input data type, so it is no longer required to specify Channel.input_type in the configuration. An error raises if Acquisition and Tracking Blocks are not configured with the same input data type. +- Block names changed from L2_M to L2C. +- Documentation available at https://gnss-sdr.org/docs/ +- Improved tools for compilation, execution and testing in embedded devices. + + + +See the definitions of concepts and metrics at https://gnss-sdr.org/design-forces/ + + + + +## [0.0.8](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.8) + +DOI: https://doi.org/10.5281/zenodo.57022 + +This is a maintenance and bug fix release with no relevant new features with respect to v0.0.7. The main changes are: + +- Fixed a bug that broke building when using latest VOLK release +- Updated PYBOMBS instructions +- Added Tests for FFT length +- Added Tests for CUDA-based tracking +- Added Tests for SIMD-based tracking +- Improved CUDA-based correlation. +- Updated documentation +- Fixed building in mips and powerpc architectures. +- gr-gn3s and gr-dbfcttc moved to its own repository. +- Improved package reproducibility +- VOLK_GNSSSDR: Fixed a bug in AVX2 puppet +- VOLK_GNSSSDR: can now be built using the C98 standard +- VOLK_GNSSSDR: Fixed a bug that broke building when linking to Boost in some configurations. +- VOLK_GNSSSDR: Added an option to trigger profiling at building time. +- VOLK_GNSSSDR: Fix the CMake-based check for posix_memalign. + + + + +## [0.0.7](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.7) + +DOI: https://doi.org/10.5281/zenodo.51521 + +This release has several improvements, addition of new features and bug fixes: + +- Improvements in receiver design: Internal block communication has been redesigned to accommodate the addition of new signals, and now upstream and downstream communication within blocks is implemented through the GNU Radio block’s asynchronous message passing system, leading to a more scalable, more robust and cleaner design. +- Improvements in receiver design: Correlators have been rewritten to take full advantage of VOLK and VOLK_GNSSSDR, and they are of general use for any tracking block. Their API now admit an arbitrary number of correlators, spaced in an arbitrary manner, in 16ic and 32fc versions. +- Improvements in receiver design: Block adapters are now all managed by smart pointers, ensuring better memory management. +- Improvements in processing speed: The VOLK_GNSSSDR library has been rewritten, following current VOLK standards and adding a number of new kernels. This approach addresses both efficiency and portability. Now the library provides the key kernels for GNSS signal processing in 16ic and 32fc versions, including SSE2, SSE3, SSE4.1, AVX, AV2 and NEON implementations. Please execute volk_gnsssdr_profile and volk_profile to use the fastest implementation for your host machine. +- New source block: Two_Bit_Packed_File_Signal_Source. This block takes 2 bit samples that have been packed into bytes or shorts as input and generates a byte for each sample. +- Fixes in SUPL assistance (supl.nokia.com removed). +- Improvements in acquisition: Added a non CFAR PCPS acquisition algorithm based on the estimation of the post correlation noise floor. If enabled as an option in the acquisition configuration, it allows setting more stable thresholds in the presence of non-gaussian front-end noise (which is the usual behavior of front-ends.) +- Fixes in acquisition: Fixed mismatch between the config files and the acquisition code in the specification of the IF. Fixed a bug in the length of the FFT of local codes. +- Improvements in tracking sensitivity: Added configuration option to customize the extension of the GPS L1 CA correlation length after bit synchronization (options are: [1,2,4,5,10,20] ms). Only available in the GPS_L1_CA_DLL_PLL_C_Aid_Tracking implementation. +- New tracking block introduced: GPS_L1_CA_DLL_PLL_C_Aid_Tracking is a GPS L1 C/A carrier PLL and code DLL with optional carrier-aid feedback. It is available in both 32 bits gr_complex input samples and in 16 bits short int complex samples. The gr_complex version has also the capability to extend the coherent correlation period from 1ms to 20ms using telemetry symbol synchronization. +- Increased resolution in CN0 estimator internal variables. +- Fixed a bug in computation of GPS L1 C/A carrier phase observable. +- Fixed a bug in the internal state machine that was blocking the receiver after a few hours of usage. Now the receiver can work continually (tested for more than one week, no known limit). +- New tracking block introduced: GPS_L1_CA_DLL_PLL_Tracking_GPU is a GPS L1 C/A carrier PLL and code DLL that uses the CUDA-compatible GPU to compute carrier wipe off and correlation operations, alleviating the CPU load. +- Obsolete/buggy blocks removed: GPS_L1_CA_DLL_FLL_PLL_Tracking, GPS_L1_CA_DLL_PLL_Optim_Tracking. +- Added a RTCM printer and TCP server in PVT blocks (still experimental). The receiver is now able to stream data in real time, serving RTCM 3.2 messages to multiple clients. For instance, it can act as a Ntrip Source feeding a Ntrip Server, or to be used as data input in RTKLIB, obtaining Precise Point Positioning fixes in real-time. The TCP port, Station ID, and rate of MT1019/MT1045 and MSM can be configured. GPS_L1_CA_PVT serves MT1019 (GPS Ephemeris) and MSM7 (MT1077, full GPS pseudoranges, phase ranges, phase range rates and CNR - high resolution) messages, while GALILEO_E1_PVT serves MT1045 (Galileo ephemeris) and MSM7 (MT1097, full Galileo pseudoranges, phase ranges, phase range rates and CNR - high resolution). +- Added a GeoJSON printer. Basic (least-squares) position fixes can be now also stored in this format, in addition to KML. +- Obsolete block removed: output filter. +- QA code migrated to the new asynchronous message passing system. +- Improvements in documentation: update of README.md file, addition of documentation for the VOLK_GNSSSDR library, updated links to new ICDs. +- Improvements in documentation: Satellite identification updated to current constellation status. +- Updated and cleaner console output. Now Galileo satellites have the ‘E’ identifier in their PRN number. +- Several improvements in CMake scripts allow to build GNSS-SDR in Linux Debian (Jessie, Stretch and Sid), Ubuntu (from 12.04 to 16.04), including amd64, i386, armhf and arm64 architectures, and possibly in other GNU/Linux distributions, as well as in Mac OS X 10.9 to 10.11. It also works well with CMake 3.5 (some problems solved with VOLK_GNSSSDR as a sub-project). +- The software can link either against OpenSSL or against GnuTLS with openssl extensions, whatever it is available. This allows buildings in distributions such as Fedora or ArchLinux, while being compatible with binary distribution through Debian packages. +- Fixed a number of defects detected by Coverity Scan. +- Some fixes required by Debian licensing and packaging system. +- Added a CGRAN (http://www.cgran.org/) manifest +- Lots of code cleaning and fixes of typos and small bugs. + + + + +## [0.0.6](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.6) + +This release has several improvements and bug fixes: + +- Added initial support to multi-band, multi-source configurations (multiple signal sources and signal conditioners). +- Updated configuration files to new notation. Old and new configuration notations still compatible. +- Added skeleton for mixed (multi-frequency and multi-system) observables block. +- Faster local carrier update (25% of improvement). +- Added initial support to GPS L2C real time tracking and decoding of CNAV message with NSL STEREO v2, Fraunhofer’s Flexiband, and USRPx front-ends (the latter requiring external clock). +- Added initial support to select the frontend clock reference source in UHD signal source (i.e. internal or external clock reference). +- Added 2 bits complex file source for GNSS-SDR GSoC 2015 signal sampler designed by Ajith Peter. +- Added a new rtl_tcp signal source, remote access to RTL2832U-based dongles via TCP. +- Always build front-end-cal, a calibration tool for some DVB-T receivers based on the Realtek's RTL2832U chipset. +- Fixed bug in UTC time computation for GPS signals. +- Updated satellite identification for GPS and Galileo. +- Defined ‘cbyte’ as a new input data type (std::complex) +- Adding a new data_type_adapter, from interleaved short to std::complex +- Adding a filter for complex short streams. +- Adding a fir_filter for std::complex (aka cbyte). It converts the data type to floats, filters, and converts back to cbyte. +- Added a resampler for cbytes and cshorts. +- First working version of a GPS tracking block implementation using CUDA with multi-GPU device support. +- Updating RINEX obs header when leap second is available. +- Updating RINEX nav file when IONO and UTC data are available. +- Include Signal Strength Indicator in RINEX observable files. +- Tests fixed. +- Fixed more than 200 code defects detected by Coverity Scan. +- Updated documentation. +- Updated documentation and CMake scripts for the GN3S v2 driver (Linux-only) +- Armadillo version automatically downloaded and built if it is not present in the system is now 5.400.3. +- Updated old links from googlecode to new links at GitHub for Google Test, gflags, glog and gperftools. +- gfortran is no longer a required package, but it is used if available. +- Added an option to remove logging. +- Enabled cross-compilation for ARM devices. +- Lots of code cleaning. + + + + +## [0.0.5](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.5) + +This release has several improvements and bug fixes: + +- Now GNSS-SDR can be installed on the system with the usual ‘cmake ../ && make && sudo make install’. +- Added volk_gnsssdr library, a volk-like library implementing some specific kernels and ensuring portable executables. It comes with a ‘volk_gnsssdr_profile’ executable, in the fashion of volk_profile. Volk and volk_gnsssdr are compatible and can be mixed together. This is expected to enable faster execution of the software receiver in upcoming versions. +- The former ‘rtlsdr_signal_source’ has been replaced by a more general ‘osmosdr_signal_source’ compatible with all those front-ends accessible by the OsmoSDR driver (bladeRF, hackRF, etc.) in addition to RTL-based dongles. +- Added manpages when binaries gnss-sdr, volk_gnsssdr_profile and front-end-cal are installed. +- Now GNSS-SDR can be built on i386, amd64, armhf, armel and arm64 architectures. +- Now GNSS-SDR builds on Ubuntu 14.04 and 14.10, Debian jessie/sid and Mac OS X 10.9 and 10.10. +- Improved detection of dependencies, specially when installed as .deb packages. +- Added a ‘check' target with some minimal tests. +- Added support for interleaved I/Q byte-size sample files. +- Minor bug fixes, updated documentation and code cleaning. + + + + +## [0.0.4](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.4) + +This release has several improvements and bug fixes: + +- Added hybrid processing GPS L1 C/A and Galileo E1B, providing position fixes make use of observables for both constellations. +- Added implementations of the QuickSync algorithm for GPS L1 C/A and Galileo E1 acquisition. +- Added processing blocks for Galileo E5a: Acquisition, Tracking, Telemetry_Decoder (experimental) +- New configuration files allow to configure GPS and Galileo channels in the same receiver. +- Added tropospheric corrections to GPS and Galileo PVT solution. +- Improved precision obtained by changing some variables from float to double. +- New building options: ENABLE_GN3S, ENABLE_RTLSDR and ENABLE_ARRAY and ENABLE_OPENCL. +- Improved documentation on how to enable optional drivers. +- Fixed bug in memory alignment that caused problems with high data rates. +- Added ENABLE_GENERIC_ARCH, an option to build the binary without detecting the SIMD instruction set present in the compiling machine, so it can be executed in other machines without those specific sets. +- Added ENABLE_GPERFTOOLS, which links the executable to tcmalloc and profiler if Gperftools is available on the system. +- Added carrier phase, Doppler shift and signal strength observables to the RINEX files. Static PPP solutions are available for GPS with RTKLIB via RINEX files. +- The executable now produces RINEX files version 3.02 of Galileo Observables, Navigation data, and mixed (GPS/Galileo) observables and nav data. RINEX 3.02 is the default version of RINEX files. +- Armadillo version updated to 4.400.2 +- Armadillo now uses OpenBLAS instead of BLAS if the former is available on the system. +- Some raw pointers have been changed to smart pointers. +- Minor bug fixes and code cleaning. + + + + +## [0.0.3](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.3) + +This release has several improvements and bug fixes, completing the transition from Subversion to Git. The main changes are: + +- Created some missing directories lost in the SVN to Git transition. +- New C++11-ized block factory, flow graph and tests, resulting in better memory management and fewer segmentation faults. Several raw pointers converted to smart pointers. +- Reorganization of assistance data input and output. +- Fixed memory leak when talking to SUPL servers. +- Improved retrieval of assistance data. +- Fixing an error in a constant value related to Galileo. +- Inform users if the temporal folder is not /tmp. +- Fixes and additions to the documentation. +- README in markdown language so it looks better in Git repositories. +- Fixed a bug that prevented the update of all shared map structures (ephemeris, iono parameters, etc…). +- The configuration script now throws error if GCC is older than 4.7 or Boost is older than 1.45 +- Improved detection / downloading & building if missing of Gflags and Glog. +- Improved detection / downloading & building if missing of Armadillo and related dependencies. +- Fixes many warnings that appeared when using CMake 3.0. +- Improved detection of GTEST_DIR variable. +- Include header files in libraries so IDEs such as Xcode can display them. + + +Enjoy it! diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in index ab11a667f..28b3c9d2a 100644 --- a/docs/doxygen/Doxyfile.in +++ b/docs/doxygen/Doxyfile.in @@ -21,7 +21,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -129,7 +129,7 @@ INLINE_INHERITED_MEMB = NO # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is @@ -551,7 +551,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -623,7 +623,7 @@ INPUT = @top_srcdir@/src @top_srcdir@/docs/doxygen/other # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -703,7 +703,7 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = @top_srcdir@/docs/doxygen/images/ +IMAGE_PATH = @top_srcdir@/docs/doxygen/images/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -791,12 +791,12 @@ REFERENCES_LINK_SOURCE = YES # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. -SOURCE_TOOLTIPS = YES +SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -875,7 +875,7 @@ HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -901,7 +901,7 @@ HTML_COLORSTYLE_GAMMA = 80 # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = NO # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to @@ -925,8 +925,6 @@ HTML_DYNAMIC_SECTIONS = NO # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. GENERATE_DOCSET = NO @@ -1123,7 +1121,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the +# (see https://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and @@ -1133,7 +1131,7 @@ USE_MATHJAX = @GNSSSDR_USE_MATHJAX@ # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# https://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1149,7 +1147,7 @@ MATHJAX_FORMAT = HTML-CSS # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdnjs.com/libraries/mathjax/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1160,11 +1158,11 @@ MATHJAX_EXTENSIONS = # 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. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript @@ -1194,7 +1192,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1207,7 +1205,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1358,7 +1356,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1677,7 +1675,7 @@ DOT_FONTSIZE = 10 # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index edb07f998..324a98fac 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # /*! \mainpage @@ -23,12 +23,12 @@ Welcome to GNSS-SDR! -GNSS-SDR is an open-source GNSS software receiver freely available to the research community. This project provides a common framework for GNSS signal processing which can operate in a variety of computer platforms. This tool is intended to foster collaboration, increase awareness, and reduce development costs in the field of GNSS receiver design and customized use of GNSS signals. +GNSS-SDR is an open-source GNSS software receiver freely available to the research community. This project provides a common framework for GNSS signal processing which can operate in a variety of computer platforms. This tool is intended to foster collaboration, increase awareness, and reduce development costs in the field of GNSS receiver design and customized use of GNSS signals. For details about GNSS-SDR and using it, please see the main project page or browse the code at the Sourceforge project page. You could be also interested in -subscribing to the mailing list. +href="https://gnss-sdr.org" target="_blank">main project page or browse the code at the Sourceforge project page. You could be also interested in +subscribing to the mailing list. \section toc Contents \li \ref overview @@ -56,25 +56,25 @@ More details on GNSS-SDR signal processing blocks: \section overview Overview -GNSS-SDR provides an interface to different suitable RF front-ends and implements all the receiver chain up to the navigation solution. -Its design allows any kind of customization, including interchangeability of signal sources, signal processing algorithms, -interoperability with other systems, output formats, and offers interfaces to all the intermediate signals, parameters and variables. -The goal is to write efficient and truly reusable code, easy to read and maintain, with fewer bugs, and producing highly optimized executables -in a variety of hardware platforms and operating systems. In that sense, the challenge consists of defining a gentle balance within level -of abstraction and performance. GNSS-SDR runs in a personal computer and provides interfaces through USB and Ethernet +GNSS-SDR provides an interface to different suitable RF front-ends and implements all the receiver chain up to the navigation solution. +Its design allows any kind of customization, including interchangeability of signal sources, signal processing algorithms, +interoperability with other systems, output formats, and offers interfaces to all the intermediate signals, parameters and variables. +The goal is to write efficient and truly reusable code, easy to read and maintain, with fewer bugs, and producing highly optimized executables +in a variety of hardware platforms and operating systems. In that sense, the challenge consists of defining a gentle balance within level +of abstraction and performance. GNSS-SDR runs in a personal computer and provides interfaces through USB and Ethernet buses to a variety of either commercially available or custom-made RF front-ends, adapting the processing algorithms to different sampling frequencies, intermediate - frequencies and sample resolutions. This makes possible rapid prototyping of specific receivers intended, for instance, to geodetic applications, - observation of the ionospheric impact on navigation signals, GNSS reflectometry, signal quality monitoring, or carrier-phase based navigation techniques. + frequencies and sample resolutions. This makes possible rapid prototyping of specific receivers intended, for instance, to geodetic applications, + observation of the ionospheric impact on navigation signals, GNSS reflectometry, signal quality monitoring, or carrier-phase based navigation techniques. \image html overview.png \image latex overview.png "Overview" width=12cm As signal inputs, it accepts: \li Raw data file captured with a data grabber (digitized at some intermediate frequency or directly at baseband). -\li Any suitable RF configuration that can be driven by the Universal Software Radio Peripheral Hardware Driver (UHD). -This includes all current and future Ettus Research products. The USRP1 + DBSRX 2.2 daughterboard is an example of working configuration for GPS L1 C/A and Galileo E1B and E1C signals. -\li The GN3S v2 USB dongle (GN3S v3 might work with small modifications). -\li Experimentally, with some USB DVB-T dongles based on the Realtek RTL2832U chipset. +\li Any suitable RF configuration that can be driven by the Universal Software Radio Peripheral Hardware Driver (UHD). +This includes all current and future Ettus Research products. The USRP1 + DBSRX 2.2 daughterboard is an example of working configuration for GPS L1 C/A and Galileo E1B and E1C signals. +\li The GN3S v2 USB dongle (GN3S v3 might work with small modifications). +\li Experimentally, with some USB DVB-T dongles based on the Realtek RTL2832U chipset. \li For mathematical representations of the targeted signals, check out the \ref the_signal_model page. As outputs, it provides: @@ -85,22 +85,22 @@ As outputs, it provides: \li Position, Velocity and Time solution in KML format and NMEA -\section build Building GNSS-SDR +\section build Building GNSS-SDR -In principle, GNSS-SDR can be built in any Unix-like system. In practice, it depends on being able to install all the required dependencies. See the building guide page for details about the project's -dependencies and build process. Mainly, it consists on installing GNU Radio plus some few more libraries: +In principle, GNSS-SDR can be built in any Unix-like system. In practice, it depends on being able to install all the required dependencies. See the building guide page for details about the project's +dependencies and build process. Mainly, it consists on installing GNU Radio plus some few more libraries: -\li Gflags, a library that implements commandline flags processing, -\li Glog, a library that implements application-level logging, +\li Gflags, a library that implements commandline flags processing, +\li Glog, a library that implements application-level logging, \li Armadillo, a C++ linear algebra library, -\li Googletest, Google's framework for writing C++ tests (requires definition of the GTEST_DIR variable), +\li Googletest, Google's framework for writing C++ tests (requires definition of the GTEST_DIR variable), and, optionally, -\li Gperftools, which provides fast, multi-threaded malloc() and performance analysis tools. +\li Gperftools, which provides fast, multi-threaded malloc() and performance analysis tools. After all dependencies are installed, clone the GNSS-SDR repository: \verbatim -$ git clone git://git.code.sf.net/p/gnss-sdr/cttc gnss-sdr +$ git clone https://github.com/gnss-sdr/gnss-sdr \endverbatim This will create a folder named gnss-sdr with the following structure: @@ -111,7 +111,7 @@ This will create a folder named gnss-sdr with the following structure: |---conf <- Configuration files. Each file represents one receiver. |---data <- Populate this folder with your captured data. |---docs <- Contains documentation-related files - |---install <- Executables + |---install <- Executables |---src <- Source code folder |-----algorithms |-------PVT @@ -136,7 +136,7 @@ This will create a folder named gnss-sdr with the following structure: |-----utils <- some utilities (e.g. Matlab scripts) \endverbatim -You are now ready to build GNSS-SDR by using CMake as building tool: +You are now ready to build GNSS-SDR by using CMake as building tool: \verbatim $ cd gnss-sdr/build $ cmake ../ @@ -149,8 +149,8 @@ You can run them from that folder, but if you prefer to install gnss-sdr on your $ sudo make install \endverbatim -This will make a copy of the conf/ folder into /usr/local/share/gnss-sdr/conf for your reference. -We suggest to create a working directory at your preferred location and store your own configuration and data files there. +This will make a copy of the conf/ folder into /usr/local/share/gnss-sdr/conf for your reference. +We suggest to create a working directory at your preferred location and store your own configuration and data files there. You can create the documentation by doing: @@ -158,7 +158,7 @@ You can create the documentation by doing: $ make doc \endverbatim -from the gnss-sdr/build folder. In both cases, Doxygen will generate HTML documentation that can be +from the gnss-sdr/build folder. In both cases, Doxygen will generate HTML documentation that can be retrieved pointing your browser of preference to gnss-sdr/docs/html/index.html. There are two more extra targets available. From the gnss-sdr/build folder: @@ -201,20 +201,20 @@ $ sudo make uninstall $ rm -rf * \endverbatim -You can also check The Git Book for more information about Git usage. +You can also check The Git Book for more information about Git usage. \section using_gnss-sdr Using GNSS-SDR With GNSS-SDR, you can define you own receiver, work with captured raw data or from a RF front-end, dump into files intermediate signals, or tune every single algorithm used in the \ref signal_processing. All the configuration is done in a single file. Those configuration files reside at the gnss-sdr/conf folder. By default, the executable gnss-sdr will read the configuration -available at gnss-sdr/conf/gnss-sdr.conf. You can edit that file to fit your needs, or even better, define a new my_receiver.conf file with your own configuration. +available at gnss-sdr/conf/gnss-sdr.conf. You can edit that file to fit your needs, or even better, define a new my_receiver.conf file with your own configuration. This new receiver can be done by invoking gnss-sdr with the --config_file flag pointing to your configuration file: \verbatim $ gnss-sdr --config_file=../conf/my_receiver.conf \endverbatim You can see a guide of available implementations at gnss-sdr/conf/master.conf. That folder contains other working examples as well. If you have a working -configuration and want to share it will others, please email it to the GNSS-SDR developers mailing list +configuration and want to share it will others, please email it to the GNSS-SDR developers mailing list and we will be happy to upload it to the server. You can use a single configuration file for processing @@ -224,41 +224,41 @@ $ gnss-sdr --config_file=../conf/my_receiver.conf --signal_source=../data/my_cap \endverbatim This will override the SignalSource.filename specified in the configuration file. -You can get a complete list of available commandline flags by doing: +You can get a complete list of available commandline flags by doing: \verbatim $ gnss-sdr --help \endverbatim -For general usage of commandline flags, see how to use Google Commandline Flags. + \section control_plane Control plane -GNSS-SDR's main method initializes the logging library, processes the command line flags, if any, provided by the user and instantiates a ControlThread object. -Its constructor reads the configuration file, creates a control queue and creates a flowgraph according to the configuration. Then, the program's main method -calls the run() method of the instantiated object, an action that connects the flowgraph and starts running it. After that, and until a stop message is received, -it reads control messages sent by the receiver's modules through a safe-thread queue and processes them. Finally, when a stop message is received, the main +GNSS-SDR's main method initializes the logging library, processes the command line flags, if any, provided by the user and instantiates a ControlThread object. +Its constructor reads the configuration file, creates a control queue and creates a flowgraph according to the configuration. Then, the program's main method +calls the run() method of the instantiated object, an action that connects the flowgraph and starts running it. After that, and until a stop message is received, +it reads control messages sent by the receiver's modules through a safe-thread queue and processes them. Finally, when a stop message is received, the main method executes the destructor of the ControlThread object, which deallocates memory, does other cleanup and exits the program. -The GNSSFlowgraph class is responsible for preparing the graph of blocks according to the configuration, running it, modifying it during run-time and stopping it. -Blocks are identified by its role. This class knows which roles it has to instantiate and how to connect them. -It relies on the configuration to get the correct instances of the roles it needs and then it applies the connections between GNU Radio blocks to make the -graph ready to be started. The complexity related to managing the blocks and the data stream is handled by GNU Radio's gr::top_block class. GNSSFlowgraph wraps -the gr::top_block instance so we can take advantage of the \ref gnss_block_factory, the configuration system and the processing blocks. This class is also responsible -for applying changes to the configuration of the flowgraph during run-time, dynamically reconfiguring channels: it selects the strategy for selecting satellites. -This can range from a sequential search over all the satellites' ID to smarter approaches that determine what are the satellites most likely in-view based on rough +The GNSSFlowgraph class is responsible for preparing the graph of blocks according to the configuration, running it, modifying it during run-time and stopping it. +Blocks are identified by its role. This class knows which roles it has to instantiate and how to connect them. +It relies on the configuration to get the correct instances of the roles it needs and then it applies the connections between GNU Radio blocks to make the +graph ready to be started. The complexity related to managing the blocks and the data stream is handled by GNU Radio's gr::top_block class. GNSSFlowgraph wraps +the gr::top_block instance so we can take advantage of the \ref gnss_block_factory, the configuration system and the processing blocks. This class is also responsible +for applying changes to the configuration of the flowgraph during run-time, dynamically reconfiguring channels: it selects the strategy for selecting satellites. +This can range from a sequential search over all the satellites' ID to smarter approaches that determine what are the satellites most likely in-view based on rough estimations of the receiver position in order to avoid searching satellites in the other side of the Earth. The Control Plane is in charge of creating a flowgraph according to the configuration and then managing the modules. Configuration allows users to define in an easy way their own -custom receiver by specifying the flowgraph (type of signal source, number of channels, algorithms to be used for each channel and each module, strategies for -satellite selection, type of output format, etc.). Since it is difficult to foresee what future module implementations will be needed in terms of configuration, -we used a very simple approach that can be extended without a major impact in the code. This can be achieved by simply mapping the names of the variables in the +custom receiver by specifying the flowgraph (type of signal source, number of channels, algorithms to be used for each channel and each module, strategies for +satellite selection, type of output format, etc.). Since it is difficult to foresee what future module implementations will be needed in terms of configuration, +we used a very simple approach that can be extended without a major impact in the code. This can be achieved by simply mapping the names of the variables in the modules with the names of the parameters in the configuration. \subsection configuration Configuration -Properties are passed around within the program using the ConfigurationInterface class. There are two implementations of this interface: FileConfiguration and -InMemoryConfiguration. FileConfiguration reads the properties (pairs of property name and value) from a file and stores them internally. InMemoryConfiguration does -not read from a file; it remains empty after instantiation and property values and names are set using the set property method. FileConfiguration is intended to be -used in the actual GNSS-SDR application whereas InMemoryConfiguration is intended to be used in tests to avoid file-dependency in the file system. Classes that -need to read configuration parameters will receive instances of ConfigurationInterface from where they will fetch the values. For instance, parameters related +Properties are passed around within the program using the ConfigurationInterface class. There are two implementations of this interface: FileConfiguration and +InMemoryConfiguration. FileConfiguration reads the properties (pairs of property name and value) from a file and stores them internally. InMemoryConfiguration does +not read from a file; it remains empty after instantiation and property values and names are set using the set property method. FileConfiguration is intended to be +used in the actual GNSS-SDR application whereas InMemoryConfiguration is intended to be used in tests to avoid file-dependency in the file system. Classes that +need to read configuration parameters will receive instances of ConfigurationInterface from where they will fetch the values. For instance, parameters related to SignalSource should look like this: \verbatim @@ -266,80 +266,80 @@ SignalSource.parameter1=value1 SignalSource.parameter2=value2 \endverbatim -The name of these parameters can be anything but one reserved word: implementation. This parameter indicates in its value the name of the class that has to be instantiated -by the factory for that role. For instance, if our signal source is providing data already at baseband and thus we want to use the implementation Pass_Through for module SignalConditioner, the corresponding line in the +The name of these parameters can be anything but one reserved word: implementation. This parameter indicates in its value the name of the class that has to be instantiated +by the factory for that role. For instance, if our signal source is providing data already at baseband and thus we want to use the implementation Pass_Through for module SignalConditioner, the corresponding line in the configuration file would be \verbatim SignalConditioner.implementation=Pass_Through \endverbatim -Since the configuration is just a set of property names and values without any meaning or syntax, the system is very versatile and easily extendable. Adding new -properties to the system only implies modifications in the classes that will make use of these properties. In addition, the configuration files are not checked -against any strict syntax so it is always in a correct status (as long as it contains pairs of property names and values in INI format). +Since the configuration is just a set of property names and values without any meaning or syntax, the system is very versatile and easily extendable. Adding new +properties to the system only implies modifications in the classes that will make use of these properties. In addition, the configuration files are not checked +against any strict syntax so it is always in a correct status (as long as it contains pairs of property names and values in INI format). \subsection gnss_block_factory GNSS block factory -Hence, the application defines a simple accessor class to fetch the configuration pairs of values and passes them to a factory class called GNSSBlockFactory. -This factory decides, according to the configuration, which class needs to be instantiated and which parameters should be passed to the constructor. Hence, the factory -encapsulates the complexity of blocks' instantiation. With that approach, adding a new block that requires new parameters will be as simple as adding the block -class and modifying the factory to be able to instantiate it. This loose coupling between the blocks' implementations and the syntax of the configuration -enables extending the application capacities in a high degree. It also allows to produce fully customized receivers, for instance a testbed for acquisition +Hence, the application defines a simple accessor class to fetch the configuration pairs of values and passes them to a factory class called GNSSBlockFactory. +This factory decides, according to the configuration, which class needs to be instantiated and which parameters should be passed to the constructor. Hence, the factory +encapsulates the complexity of blocks' instantiation. With that approach, adding a new block that requires new parameters will be as simple as adding the block +class and modifying the factory to be able to instantiate it. This loose coupling between the blocks' implementations and the syntax of the configuration +enables extending the application capacities in a high degree. It also allows to produce fully customized receivers, for instance a testbed for acquisition algorithms, and to place observers at any point of the receiver chain. \section signal_processing Signal Processing plane -GNU Radio's class gr::basic_block is the abstract base class for all signal processing blocks, a bare abstraction of an entity that has a name and a set of -inputs and outputs. It is never instantiated directly; rather, this is the abstract parent class of both gr::hier_block2, which is a recursive container that -adds or removes processing or hierarchical blocks to the internal graph, and gr::block, which is the abstract base class for all the processing blocks. +GNU Radio's class gr::basic_block is the abstract base class for all signal processing blocks, a bare abstraction of an entity that has a name and a set of +inputs and outputs. It is never instantiated directly; rather, this is the abstract parent class of both gr::hier_block2, which is a recursive container that +adds or removes processing or hierarchical blocks to the internal graph, and gr::block, which is the abstract base class for all the processing blocks. \image html ClassHierarchy.png \image latex ClassHierarchy.png "Class hierarchy of signal processing blocks" width=12cm -A signal processing flow is constructed by creating a tree of hierarchical blocks, which at any level may also contain terminal nodes that actually implement signal +A signal processing flow is constructed by creating a tree of hierarchical blocks, which at any level may also contain terminal nodes that actually implement signal processing functions. -Class gr::top_block is the top-level hierarchical block representing a flowgraph. It defines GNU Radio runtime functions used during the execution of the -program: run(), start(), stop(), wait(), etc. A a subclass called GNSSBlockInterface is the common interface for all the GNSS-SDR modules. It defines pure virtual +Class gr::top_block is the top-level hierarchical block representing a flowgraph. It defines GNU Radio runtime functions used during the execution of the +program: run(), start(), stop(), wait(), etc. A a subclass called GNSSBlockInterface is the common interface for all the GNSS-SDR modules. It defines pure virtual methods, that are required to be implemented by a derived class. -Subclassing GNSSBlockInterface, we defined interfaces for the GNSS receiver blocks depicted in the figure above. This hierarchy provides the definition of different -algorithms and different implementations, which will be instantiated according to the configuration. This strategy allows -multiple implementations sharing a common interface, achieving the objective of decoupling interfaces from implementations: it defines a family of algorithms, encapsulates each one, +Subclassing GNSSBlockInterface, we defined interfaces for the GNSS receiver blocks depicted in the figure above. This hierarchy provides the definition of different +algorithms and different implementations, which will be instantiated according to the configuration. This strategy allows +multiple implementations sharing a common interface, achieving the objective of decoupling interfaces from implementations: it defines a family of algorithms, encapsulates each one, and makes them interchangeable. Hence, we let the algorithm vary independently from the program that uses it. \subsection signal_source Signal Source -The input of a software receiver are the raw bits that come out from the front-end's analog-to-digital converter (ADC). -Those bits can be read from a file stored in the hard disk or directly in real-time from a hardware device through USB or Ethernet buses. +The input of a software receiver are the raw bits that come out from the front-end's analog-to-digital converter (ADC). +Those bits can be read from a file stored in the hard disk or directly in real-time from a hardware device through USB or Ethernet buses. -The Signal Source module is in charge of implementing the hardware driver, that is, the portion of the code that communicates with the RF front-end and receives -the samples coming from the ADC. This communication is usually performed through USB or Ethernet buses. Since real-time processing requires a highly optimized -implementation of the whole receiver, this module also allows to read samples from a file stored in a hard disk, and thus processing without time constraints. -Relevant parameters of those samples are the intermediate frequency (or baseband I&Q components), the sampling rate and number of bits per sample, that must be +The Signal Source module is in charge of implementing the hardware driver, that is, the portion of the code that communicates with the RF front-end and receives +the samples coming from the ADC. This communication is usually performed through USB or Ethernet buses. Since real-time processing requires a highly optimized +implementation of the whole receiver, this module also allows to read samples from a file stored in a hard disk, and thus processing without time constraints. +Relevant parameters of those samples are the intermediate frequency (or baseband I&Q components), the sampling rate and number of bits per sample, that must be specified by the user in the configuration file. This module also performs bit-depth adaptation, since most of the existing RF front-ends provide samples quantized with 2 or 3 bits, while operations inside - the processor are performed on 32- or 64-bit words, depending on its architecture. Although there are implementations of the most intensive computational - processes (mainly correlation) that take advantage of specific data types and architectures for the sake of - efficiency, the approach is processor-specific and hardly portable. We suggest to keep signal samples in standard data types and letting the compiler + the processor are performed on 32- or 64-bit words, depending on its architecture. Although there are implementations of the most intensive computational + processes (mainly correlation) that take advantage of specific data types and architectures for the sake of + efficiency, the approach is processor-specific and hardly portable. We suggest to keep signal samples in standard data types and letting the compiler select the best library version (implemented using SIMD or any other processor-specific technology) of the required routines for a given processor. - + Example: FileSignalSource -The user can configure the receiver for reading from a file, setting in the configuration file the data file location, sample format, +The user can configure the receiver for reading from a file, setting in the configuration file the data file location, sample format, and the sampling frequency and intermediate frequency at what the signal was originally captured. - + \verbatim ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=File_Signal_Source SignalSource.filename=/home/user/gnss-sdr/data/my_capture.dat SignalSource.item_type=gr_complex SignalSource.sampling_frequency=4000000 ; Sampling frequency in [Hz] -SignalSource.freq=1575420000 ; RF front-end center frequency in [Hz] -\endverbatim +SignalSource.freq=1575420000 ; RF front-end center frequency in [Hz] +\endverbatim Example: UhdSignalSource @@ -349,7 +349,7 @@ The user may prefer to use a UHD-compatible RF front-end and try real-time proce SignalSource.implementation=UHD_Signal_Source SignalSource.item_type=gr_complex SignalSource.sampling_frequency=4000000 ; Sampling frequency in [Hz] -SignalSource.freq=1575420000 ; RF front-end center frequency in [Hz] +SignalSource.freq=1575420000 ; RF front-end center frequency in [Hz] SignalSource.gain=60 ; Front-end gain in dB SignalSource.subdevice=B:0 ; UHD subdevice specification (for USRP1 use A:0 or B:0) \endverbatim @@ -358,8 +358,8 @@ Other examples are available at gnss-sdr/conf. \subsection signal_conditioner Signal Conditioner The signal conditioner is in charge of resampling the signal and delivering a reference sample rate to the downstream processing blocks, acting as - a facade between the signal source and the synchronization channels, providing a simplified interface to the input signal. - In case of multiband front-ends, this module would be in charge of providing a separated data stream for each band. + a facade between the signal source and the synchronization channels, providing a simplified interface to the input signal. + In case of multiband front-ends, this module would be in charge of providing a separated data stream for each band. \subsection channel Channel @@ -368,31 +368,28 @@ A channel encapsulates all signal processing devoted to a single satellite. Thus channels is selectable by the user in the configuration file, this approach helps improving the scalability and maintainability of the receiver. This module is also in charge of managing the interplay between acquisition and tracking. Acquisition can be initialized in several ways, depending on -the prior information available (called cold start when the receiver has no information about its position nor the satellites almanac; warm start when -a rough location and the approximate time of day are available, and the receiver has a recently recorded almanac broadcast; or hot start when the receiver +the prior information available (called cold start when the receiver has no information about its position nor the satellites almanac; warm start when +a rough location and the approximate time of day are available, and the receiver has a recently recorded almanac broadcast; or hot start when the receiver was tracking a satellite and the signal line of sight broke for a short period of time, but the ephemeris and almanac data is still valid, or this information -is provided by other means), and an acquisition process can finish deciding that the satellite is not present, that longer integration is needed in order to +is provided by other means), and an acquisition process can finish deciding that the satellite is not present, that longer integration is needed in order to confirm the presence of the satellite, or declaring the satellite present. In the latter case, acquisition process should stop and trigger the tracking module -with coarse estimations of the synchronization parameters. The mathematical abstraction used to design this logic is known as finite state machine (FSM), that is -a behavior model composed of a finite number of states, transitions between those states, and actions. For the implementation, we used the -Boost.Statechart library, -which provides desirable features such as support for asynchronous state machines, multi-threading, type-safety, error handling and compile-time validation. - +with coarse estimations of the synchronization parameters. + The abstract class ChannelInterface represents an interface to a channel GNSS block. Check Channel for an actual implementation. - + \subsubsection acquisition Acquisition -The first task of a GNSS receiver is to detect the presence or absence of in-view satellites. This is done by the acquisition system process, which also provides a coarse estimation of two signal parameters: the frequency shift +The first task of a GNSS receiver is to detect the presence or absence of in-view satellites. This is done by the acquisition system process, which also provides a coarse estimation of two signal parameters: the frequency shift with respect to the nominal IF frequency, and a delay term which allows the receiver to create a local code aligned with the incoming code. -AcquisitionInterface is the common interface for all the acquisition algorithms and their corresponding implementations. Algorithms' interface, that may vary -depending on the use of information external to the receiver, such as in Assisted GNSS, is defined in classes referred to as adapters. -These adapters wrap the GNU Radio blocks interface into a compatible interface expected by AcquisitionInterface. This allows the use of existing GNU Radio blocks -derived from gr::block, and ensures that newly developed implementations will also be reusable in other GNU Radio-based applications. +AcquisitionInterface is the common interface for all the acquisition algorithms and their corresponding implementations. Algorithms' interface, that may vary +depending on the use of information external to the receiver, such as in Assisted GNSS, is defined in classes referred to as adapters. +These adapters wrap the GNU Radio blocks interface into a compatible interface expected by AcquisitionInterface. This allows the use of existing GNU Radio blocks +derived from gr::block, and ensures that newly developed implementations will also be reusable in other GNU Radio-based applications. Moreover, it adds still another layer of abstraction, since each given acquisition algorithm can have different implementations (for instance using different numerical libraries). In such a way, implementations can be continuously improved without having any impact neither on the algorithm interface nor the general acquisition interface. Check GpsL1CaPcpsAcquisition and GalileoE1PcpsAmbiguousAcquisition for examples of adapters from a Parallel Code Phase Search (PCPS) acquisition block, and pcps_acquisition_cc for an example of a block implementation. The source code of all the available acquisition algorithms is located at: - + \verbatim |-gnss-sdr |---src @@ -406,13 +403,13 @@ The user can select a given implementation for the algorithm to be used in each \verbatim ;######### ACQUISITION GLOBAL CONFIG ############ -;#dump: Enable or disable the acquisition internal data file logging [true] or [false] +;#dump: Enable or disable the acquisition internal data file logging [true] or [false] Acquisition.dump=false ;#filename: Log path and filename Acquisition.dump_filename=./acq_dump.dat ;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. Acquisition.item_type=gr_complex -;#if: Signal intermediate frequency in [Hz] +;#if: Signal intermediate frequency in [Hz] Acquisition.if=0 ;#sampled_ms: Signal block duration for the acquisition signal detection [ms] Acquisition.sampled_ms=1 @@ -420,8 +417,8 @@ Acquisition.sampled_ms=1 Acquisition.implementation=GPS_L1_CA_PCPS_Acquisition ;#threshold: Acquisition threshold Acquisition.threshold=0.005 -;#pfa: Acquisition false alarm probability. This option overrides the threshold option. -;Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] +;#pfa: Acquisition false alarm probability. This option overrides the threshold option. +;Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition] Acquisition.pfa=0.0001 ;#doppler_max: Maximum expected Doppler shift [Hz] Acquisition.doppler_max=10000 @@ -429,7 +426,7 @@ Acquisition.doppler_max=10000 Acquisition.doppler_step=500 ;######### ACQUISITION CHANNELS CONFIG ###### -;#The following options are specific to each channel and overwrite the generic options +;#The following options are specific to each channel and overwrite the generic options ;######### ACQUISITION CH 0 CONFIG ############ @@ -455,12 +452,12 @@ Acquisition.doppler_step=500 \subsubsection tracking Tracking When a satellite is declared present, the parameters estimated by the acquisition module are then fed to the receiver tracking module, which represents the second stage of the signal processing unit, aiming to perform a local search for accurate estimates of code delay and carrier phase, and following their eventual - variations. + variations. -Again, a class hierarchy consisting of a TrackingInterface class and subclasses implementing algorithms provides a way of testing different approaches, -with full access to their parameters. Check GpsL1CaDllPllTracking or GalileoE1DllPllVemlTracking for examples of adapters, and Gps_L1_Ca_Dll_Pll_Tracking_cc for an example +Again, a class hierarchy consisting of a TrackingInterface class and subclasses implementing algorithms provides a way of testing different approaches, +with full access to their parameters. Check GpsL1CaDllPllTracking or GalileoE1DllPllVemlTracking for examples of adapters, and Gps_L1_Ca_Dll_Pll_Tracking_cc for an example of a signal processing block implementation. There are also available some useful classes and functions for signal tracking; take a look at Correlator, lock_detectors.h, tracking_discriminators.h or -tracking_2nd_DLL_filter.h. +tracking_2nd_DLL_filter.h. The source code of all the available tracking algorithms is located at: \verbatim @@ -482,10 +479,10 @@ Tracking.implementation=GPS_L1_CA_DLL_PLL_Tracking ;#item_type: Type and resolution for each of the signal samples. Use only [gr_complex] in this version. Tracking.item_type=gr_complex -;#sampling_frequency: Signal Intermediate Frequency in [Hz] +;#sampling_frequency: Signal Intermediate Frequency in [Hz] Tracking.if=0 -;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] +;#dump: Enable or disable the Tracking internal binary data file logging [true] or [false] Tracking.dump=false ;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number. @@ -508,12 +505,12 @@ Tracking.early_late_space_chips=0.5; \endverbatim \subsubsection decoding Decoding of the navigation message -Most of GNSS signal links are modulated by a navigation message containing the time the message was transmitted, orbital parameters of satellites -(also known as ephemeris) and an almanac (information about the general system health, rough orbits of all satellites in the network as well as data related to -error correction). Navigation data bits are structured in words, pages, subframes, frames and superframes. Sometimes, bits corresponding to a single parameter are -spread over different words, and values extracted from different frames are required for proper decoding. Some words are for synchronization purposes, others for -error control an others contain actual information. There are also error control mechanisms, from parity checks to forward error correction (FEC) encoding and -interleaving, depending on the system. All this decoding complexity is managed by a finite state machine implemented with the Boost.Statechart library. +Most of GNSS signal links are modulated by a navigation message containing the time the message was transmitted, orbital parameters of satellites +(also known as ephemeris) and an almanac (information about the general system health, rough orbits of all satellites in the network as well as data related to +error correction). Navigation data bits are structured in words, pages, subframes, frames and superframes. Sometimes, bits corresponding to a single parameter are +spread over different words, and values extracted from different frames are required for proper decoding. Some words are for synchronization purposes, others for +error control an others contain actual information. There are also error control mechanisms, from parity checks to forward error correction (FEC) encoding and +interleaving, depending on the system. The common interface is TelemetryDecoderInterface. Check GpsL1CaTelemetryDecoder for an example of the GPS L1 NAV message decoding adapter, and gps_l1_ca_telemetry_decoder_cc for an actual implementation of a signal processing block. Configuration example: @@ -527,13 +524,13 @@ TelemetryDecoder.dump=false See the \ref reference_docs for more information about the signal format. \subsection observables Observables -GNSS systems provide different kinds of observations. The most commonly used are the code observations, also called pseudoranges. The pseudo comes from +GNSS systems provide different kinds of observations. The most commonly used are the code observations, also called pseudoranges. The pseudo comes from the fact that on the receiver side the clock error is unknown and thus the measurement is not a pure range observation. High accuracy applications also use the carrier phase observations, which are based on measuring the difference between the carrier phase transmitted by the GNSS satellites and the phase of the carrier generated in the receiver. Both observables are computed from the outputs of the tracking module and the decoding of the navigation message. This module collects all the data provided by every tracked channel, aligns all received data into a coherent set, and computes the observables. -The common interface is ObservablesInterface. +The common interface is ObservablesInterface. Configuration example: \verbatim @@ -541,7 +538,7 @@ Configuration example: ;#implementation: Use [GPS_L1_CA_Observables] for GPS L1 C/A. Observables.implementation=GPS_L1_CA_Observables -;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] +;#dump: Enable or disable the Observables internal binary data file logging [true] or [false] Observables.dump=false ;#dump_filename: Log path and filename. @@ -567,24 +564,24 @@ PVT.flag_nmea_tty_port=true; ;#nmea_dump_devname: serial device descriptor for NMEA logging PVT.nmea_dump_devname=/dev/pts/4 -;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] +;#dump: Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump=false \endverbatim This implementation allows tuning of the following parameters: \verbatim PVT.averaging_depth=10 ; Number of PVT observations in the moving average algorithm -PVT.flag_averaging=true ; Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] +PVT.flag_averaging=true ; Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false] PVT.output_rate_ms=100 ; Period in [ms] between two PVT outputs PVT.display_rate_ms=500 ; Position console print (std::out) interval [ms]. -PVT.dump=false ; Enable or disable the PVT internal binary data file logging [true] or [false] +PVT.dump=false ; Enable or disable the PVT internal binary data file logging [true] or [false] PVT.dump_filename=./PVT ; Log path and filename without extension. \endverbatim \section license About the software license -GNSS-SDR is released under the General Public License (GPL) v3, thus securing practical usability, inspection, -and continuous improvement by the research community, allowing the discussion based on tangible code and the analysis of results obtained with real signals. +GNSS-SDR is released under the General Public License (GPL) v3, thus securing practical usability, inspection, +and continuous improvement by the research community, allowing the discussion based on tangible code and the analysis of results obtained with real signals. The GPL implies that: \li Copies may be distributed free of charge or for money, but the source code has to be shipped or provided free of charge (or at cost price) on demand. The receiver of the source code has the same rights meaning he can share copies free of charge or resell. @@ -600,8 +597,8 @@ If you use GNSS-SDR to produce a research paper or Thesis, we would appreciate i \li \anchor Navitec2012 C. Fernández-Prades, J. Arribas, L. Esteve, D. Pubill, P. Closas, An Open Source Galileo E1 Software Receiver, in Proc. of the 6th ESA Workshop on Satellite Navigation Technologies (NAVITEC 2012), ESTEC, Noordwijk, The Netherlands, Dec. 2012. \li J. Arribas, GNSS Array-based Acquisition: Theory and Implementation, PhD Thesis, Universitat Politècnica de Catalunya, Barcelona, Spain, June 2012. -\li C. Fernández-Prades, J. Arribas, P. Closas, C. Avilés, and L. Esteve, GNSS-SDR: an open source tool for researchers and developers, in Proc. of the ION GNSS 2011 Conference, Portland, Oregon, Sept. 19-23, 2011. -\li C. Fernández-Prades, C. Avilés, L. Esteve, J. Arribas, and P. Closas, Design patterns for GNSS software receivers, in Proc. of the 5th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2010), ESTEC, Noordwijk, The Netherlands, Dec. 2010. DOI:10.1109/NAVITEC.2010.5707981 +\li C. Fernández-Prades, J. Arribas, P. Closas, C. Avilés, and L. Esteve, GNSS-SDR: an open source tool for researchers and developers, in Proc. of the ION GNSS 2011 Conference, Portland, Oregon, Sept. 19-23, 2011. +\li C. Fernández-Prades, C. Avilés, L. Esteve, J. Arribas, and P. Closas, Design patterns for GNSS software receivers, in Proc. of the 5th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2010), ESTEC, Noordwijk, The Netherlands, Dec. 2010. DOI:10.1109/NAVITEC.2010.5707981 For LaTeX users, these are the BibTeX cites for your convenience: @@ -609,12 +606,12 @@ For LaTeX users, these are the BibTeX cites for your convenience: @INPROCEEDINGS{GNSS-SDR12 author = {C.~{Fern\'{a}ndez--Prades} and J.~Arribas and L.~Esteve and D.~Pubill and P.~Closas}, title = {An Open Source {G}alileo {E1} Software Receiver}, - booktitle = {Proc. of the 6th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2012)}, - year = {2012}, - address = {ESTEC, Noordwijk, The Netherlands}, + booktitle = {Proc. of the 6th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2012)}, + year = {2012}, + address = {ESTEC, Noordwijk, The Netherlands}, month = {Dec.} } \endverbatim - + \verbatim @PHDTHESIS{Arribas12, author = {J.~Arribas}, @@ -624,48 +621,45 @@ For LaTeX users, these are the BibTeX cites for your convenience: address = {Barcelona, Spain}, month = {June} } \endverbatim - + \verbatim -@INPROCEEDINGS{GNSS-SDR11, - AUTHOR = {C.~{Fern\'{a}ndez--Prades} and J.~Arribas and P.~Closas and C.~Avil\'{e}s and L.~Esteve}, - TITLE = {{GNSS-SDR}: An Open Source Tool For Researchers and Developers}, - BOOKTITLE = {Proc. of the ION GNSS 2011 Conference}, - YEAR = {2011}, - address = {Portland, Oregon}, - month = {Sept.} } +@INPROCEEDINGS{GNSS-SDR11, + AUTHOR = {C.~{Fern\'{a}ndez--Prades} and J.~Arribas and P.~Closas and C.~Avil\'{e}s and L.~Esteve}, + TITLE = {{GNSS-SDR}: An Open Source Tool For Researchers and Developers}, + BOOKTITLE = {Proc. of the ION GNSS 2011 Conference}, + YEAR = {2011}, + address = {Portland, Oregon}, + month = {Sept.} } \endverbatim - + \verbatim -@INPROCEEDINGS{GNSS-SDR10, - AUTHOR = {C.~{Fern\'{a}ndez--Prades} and C.~Avil\'{e}s and L.~Esteve and J.~Arribas and P.~Closas}, - TITLE = {Design patterns for {GNSS} software receivers}, - BOOKTITLE = {Proc. of the 5th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2010)}, - YEAR = {2010}, - address = {ESTEC, Noordwijk, The Netherlands}, - month = {Dec.}, - note = {DOI:10.1109/NAVITEC.2010.5707981} } +@INPROCEEDINGS{GNSS-SDR10, + AUTHOR = {C.~{Fern\'{a}ndez--Prades} and C.~Avil\'{e}s and L.~Esteve and J.~Arribas and P.~Closas}, + TITLE = {Design patterns for {GNSS} software receivers}, + BOOKTITLE = {Proc. of the 5th ESA Workshop on Satellite Navigation Technologies (NAVITEC'2010)}, + YEAR = {2010}, + address = {ESTEC, Noordwijk, The Netherlands}, + month = {Dec.}, + note = {DOI:10.1109/NAVITEC.2010.5707981} } \endverbatim \section now_what Ok, now what? -In order to start using GNSS-SDR, you may want to populate gnss-sdr/data folder (or anywhere else on your system) with raw data files. By "raw data" we mean the output -of a Radio Frequency front-end's Analog-to_Digital converter. GNSS-SDR needs signal samples already in baseband or in passband, at a suitable intemediate frequency (on the order of MHz). +In order to start using GNSS-SDR, you may want to populate gnss-sdr/data folder (or anywhere else on your system) with raw data files. By "raw data" we mean the output +of a Radio Frequency front-end's Analog-to_Digital converter. GNSS-SDR needs signal samples already in baseband or in passband, at a suitable intemediate frequency (on the order of MHz). Prepare your configuration file, and then you are ready for going to the gnss-sdr/install folder, running ./gnss-sdr, and see how the file is processed. Please ask the Developer Team for a signal sample if you need one, and they will do their best ;-) Another interesting option is working in real-time with a RF front-end. We provide drivers for UHD-compatible hardware (see \ref signal_source), for the GN3S v2 USB dongle and for some DVB-T USB dongles. Start with a low number of channels and then increase it in order to test how many channels your processor can handle in real-time. -You can find more information at the GNSS-SDR Documentation page or directly asking to the -GNSS-SDR Developers mailing list. - -You are also very welcome to contribute to the project, there are many ways to participate in GNSS-SDR. -If you need some special feature not yet implemented, the Developer Team would love to be hired for developing it. -Please do not hesitate to contact them. +You can find more information at the GNSS-SDR Documentation page or directly asking to the +GNSS-SDR Developers mailing list. -Enjoy GNSS-SDR! +You are also very welcome to contribute to the project, there are many ways to participate in GNSS-SDR. +If you need some special feature not yet implemented, the Developer Team would love to be hired for developing it. +Please do not hesitate to contact them. + +Enjoy GNSS-SDR! The Developer Team. */ - - - diff --git a/docs/doxygen/other/reference_docs.dox b/docs/doxygen/other/reference_docs.dox index 3759c876a..8b3f8564d 100644 --- a/docs/doxygen/other/reference_docs.dox +++ b/docs/doxygen/other/reference_docs.dox @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # /*! \page reference_docs Reference Documents @@ -21,32 +21,32 @@ \section icd Interface Control Documents \subsection gps GPS -All the current GPS Interface Control Documents can be downloaded from GPS.gov, the official U.S. Government webpage for GPS. +All the current GPS Interface Control Documents can be downloaded from GPS.gov, the official U.S. Government webpage for GPS. -\li GPS L1 and L2C: Global Positioning System Directorate, Interface Specification IS-GPS-200 Revision H. September, 2013. -\li GPS L1C (available with first Block III launch): Global Positioning System Directorate, Interface Specification IS-GPS-800 Revision D. September, 2013. -\li GPS L5 (first Block IIF satellite launched on May, 2010): Global Positioning System Directorate, Interface Specification IS-GPS-705 Revision D. September, 2013. +\li GPS L1 and L2C: Global Positioning System Directorate, Interface Specification IS-GPS-200 Revision H. September, 2013. +\li GPS L1C (available with first Block III launch): Global Positioning System Directorate, Interface Specification IS-GPS-800 Revision D. September, 2013. +\li GPS L5 (first Block IIF satellite launched on May, 2010): Global Positioning System Directorate, Interface Specification IS-GPS-705 Revision D. September, 2013. \subsection glonass GLONASS -Official GLONASS webpage: Information-analytical centre official website. +Official GLONASS webpage: Information-analytical centre official website. \li Standard Accuracy (ST) signals at L1 and L2: Russian Institute of Space Device Engineering, Global Navigation Satellite System GLONASS. Interface Control Document. Navigational radiosignal in bands L1, L2. Edition 5.1, Moscow, Russia, 2008 \subsection galileo Galileo -Check the Galileo website of the European Commission and the -Galileo website of the European Space Agency. +Check the Galileo website of the European Commission and the +Galileo website of the European Space Agency. There is a website with Galileo constellation status information from the International GNSS Service. -\li Galileo E5, E6, and E1: European GNSS (Galileo) Open Service. Signal In Space Interface Control Document. Ref: OS SIS ICD, Issue 1.2, European Commission, Nov. 2015. +\li Galileo E5, E6, and E1: European GNSS (Galileo) Open Service. Signal In Space Interface Control Document. Ref: OS SIS ICD, Issue 1.2, European Commission, Nov. 2015. \li European GNSS (Galileo) Open Service Signal-In-Space Operational Status Definition, European Commission, Sept. 2015. -The European Commission is granting free access to the technical information on the future Galileo open service signal, i.e. the specifications manufacturers -and developers need to process data received from satellites. This document informs receiver manufacturers, application developers and service providers on how +The European Commission is granting free access to the technical information on the future Galileo open service signal, i.e. the specifications manufacturers +and developers need to process data received from satellites. This document informs receiver manufacturers, application developers and service providers on how to use the future Galileo system and what they can expect in terms of performance. \subsection beidou BeiDou @@ -65,20 +65,20 @@ Open Service Signal (Version 2.0). China Satellite Navigation Office, December 2 \li EGNOS Open Service (OS) Service Definition Document. Ref: EGN-SDD OS, Revision 2.2, European GNSS Agency (GSA), Feb. 12, 2015. This is a complementary document to the RTCA DO229D, mentioned above. It describes the scope of services provided by the EGNOS Open Service to be used by end-users or Application Specific Service Providers. It details the general conditions relating to the use of the EGNOS service, a technical description of the Signal-in-Space (SIS), the reference receiver, environmental conditions, the service performance achieved and aspects relating to service provision. -\li EGNOS Safety of Life Service Definition Document. Ref: EGN-SDD SoL, Revision 3.0, European GNSS Agency (GSA), Sep. 22, 2015. The EGNOS Safety of Life (SoL) Service is provided openly and is freely accessible without any direct charge and is tailored to safety-critical transport applications in various domains, in particular for aviation applications. The service is thus compliant with the aviation APV-I (Approach with Vertical Guidance) requirements, as defined by ICAO in Annex 10, but may support also applications in other SoL domains. +\li EGNOS Safety of Life Service Definition Document. Ref: EGN-SDD SoL, Revision 3.0, European GNSS Agency (GSA), Sep. 22, 2015. The EGNOS Safety of Life (SoL) Service is provided openly and is freely accessible without any direct charge and is tailored to safety-critical transport applications in various domains, in particular for aviation applications. The service is thus compliant with the aviation APV-I (Approach with Vertical Guidance) requirements, as defined by ICAO in Annex 10, but may support also applications in other SoL domains. \li EGNOS Data Access Service (EDAS) Service Definition Document, Rf: EGN-SDD EDAS, V2.1, European GNSS Agency (GSA), Dec. 19, 2014. -More information about EGNOS can be found through the EGNOS Portal. +More information about EGNOS can be found through the EGNOS Portal. \section standards Other Standards \subsection rinex RINEX -The final output of a navigation receiver is usually its position, speed or other related physical quantities. However, the calculation of those quantities -are based on a series of measurements from one or more satellite constellations. Although receivers calculate positions in real time, in many cases it is -interesting to store intermediate measures for later post-processing. RINEX is the standard format that allows the management and disposal of the measures +The final output of a navigation receiver is usually its position, speed or other related physical quantities. However, the calculation of those quantities +are based on a series of measurements from one or more satellite constellations. Although receivers calculate positions in real time, in many cases it is +interesting to store intermediate measures for later post-processing. RINEX is the standard format that allows the management and disposal of the measures generated by a receiver, as well as their off-line processing by a multitude of applications. -\li The most common version at present is RINEX: The Receiver Independent Exchange Format Version 2.11, which enables storage of measurements from pseudorange, carrier-phase and Doppler systems for GPS or GLONASS, +\li The most common version at present is RINEX: The Receiver Independent Exchange Format Version 2.11, which enables storage of measurements from pseudorange, carrier-phase and Doppler systems for GPS or GLONASS, along with data from EGNOS and WAAS satellite based augmentation systems (SBAS). \li The most recent version is RINEX: The Receiver Independent Exchange Format Version 3.01 published in June, 2009. @@ -88,11 +88,11 @@ It includes Galileo and improves the handling of multi-constellation data files. \subsection nmea NMEA -The National Marine Electronics Association released the NMEA 0183 Interface Standard, which defines electrical signal requirements, data transmission protocol and time, +The National Marine Electronics Association released the NMEA 0183 Interface Standard, which defines electrical signal requirements, data transmission protocol and time, and specific sentence formats for a 4800-baud serial data bus. The standard is available for purchase. \subsection kml KML -KML is an XML language focused on geographic visualization, including annotation of maps and images. Geographic visualization includes not only the presentation of graphical data on the globe, but also the control of the user's navigation in the sense of where to go and where to look. +KML is an XML language focused on geographic visualization, including annotation of maps and images. Geographic visualization includes not only the presentation of graphical data on the globe, but also the control of the user's navigation in the sense of where to go and where to look. Google submitted KML (formerly Keyhole Markup Language) to the Open Geospatial Consortium (OGC) to be evolved within the OGC consensus process with the following goal: KML Version 2.2 has been adopted as an OGC implementation standard. \li Open Geospatial Consortium, Inc., OGC KML Version 2.2.0, April 2008. @@ -100,33 +100,33 @@ Google submitted KML (formerly Keyhole Markup Language) to the Open Geospatial C \subsection cxx C++ Standards -In 1998, the C++ standards committee (the ISO/IEC JTC1/SC22/WG21 working group) -standardized C++ and published the international standard ISO/IEC 14882:1998 (informally known as C++98). A technical corrigendum was approved in 2003, +In 1998, the C++ standards committee (the ISO/IEC JTC1/SC22/WG21 working group) +standardized C++ and published the international standard ISO/IEC 14882:1998 (informally known as C++98). A technical corrigendum was approved in 2003, and the standard was published again as the ISO/IEC 14882:2003. -Published ISO and IEC standards can be purchased from a member body of ISO or IEC. Free copies of the C++ standard Committee Drafts -were made public before the official standard was released. +Published ISO and IEC standards can be purchased from a member body of ISO or IEC. Free copies of the C++ standard Committee Drafts +were made public before the official standard was released. -In 2005, a technical report, called the Library Technical Report 1 -(often known as TR1 for short), was released. While not an official part of the standard, it specified a number of extensions to the standard library, -which were expected to be included in the next version of C++. The linked document is officially a draft, but that is due only to procedural issues; +In 2005, a technical report, called the Library Technical Report 1 +(often known as TR1 for short), was released. While not an official part of the standard, it specified a number of extensions to the standard library, +which were expected to be included in the next version of C++. The linked document is officially a draft, but that is due only to procedural issues; the content did not change. Scott Meyers provides more TR1 information. Some ISO/IEC standards are publicly available, for instance: ISO/IEC TR 18015:2006 Technical Report on C++ Performance. -The standard for the next version of the language (previously known as C++0x) was finally -published with the name of C++11 in September, 2011, as the ISO/IEC 14882:2011 Standard. GCC, the GNU Compiler Collection, -provides partial C++11 support. Bjarne Stroustrup maintains a C++11 FAQ. +The standard for the next version of the language (previously known as C++0x) was finally +published with the name of C++11 in September, 2011, as the ISO/IEC 14882:2011 Standard. GCC, the GNU Compiler Collection, +provides partial C++11 support. Bjarne Stroustrup maintains a C++11 FAQ. \li The most recent public draft of the Standard for Programming Language C++ was published in Feb. 2011. \subsection protocols Positioning protocols in wireless communication networks -Cellular industry location standards first appeared in the late 1990s, with the 3rd generation partnership project (3GPP) radio resource location services protocol (RRLP) technical specification 44.031 positioning protocol for GSM networks. -Today, RRLP is the de facto standardized protocol to carry GNSS assistance data to GNSS-enabled mobile devices, and the term "3GPP specification" now covers all GSM (including GPRS and EDGE), -W-CDMA and LTE (including LTE-A) specifications. Precisely, the label "LTE-A" is applied to networks compliant with LTE Release 10 and beyond, which fulfill the requirements issued by -the International Telecommunication Union Radiocommunication Sector (ITU-R) in the global standard for international mobile telecommunications (IMT Advanced, also referred to as 4G) +Cellular industry location standards first appeared in the late 1990s, with the 3rd generation partnership project (3GPP) radio resource location services protocol (RRLP) technical specification 44.031 positioning protocol for GSM networks. +Today, RRLP is the de facto standardized protocol to carry GNSS assistance data to GNSS-enabled mobile devices, and the term "3GPP specification" now covers all GSM (including GPRS and EDGE), +W-CDMA and LTE (including LTE-A) specifications. Precisely, the label "LTE-A" is applied to networks compliant with LTE Release 10 and beyond, which fulfill the requirements issued by +the International Telecommunication Union Radiocommunication Sector (ITU-R) in the global standard for international mobile telecommunications (IMT Advanced, also referred to as 4G) access technologies. Control plane protocols: @@ -139,12 +139,12 @@ User plane protocols: \li Open Mobile Alliance (OMA), Secure User Plane Location Architecture Version 1 (SUPL 1.0), June 2007. \li Open Mobile Alliance (OMA), Secure User Plane Location Architecture Version 2 (SUPL 2.0), April 2012. -LTE Release 9 introduced extension hooks in LPP messages, so that the bodies external to 3GPP could extend the LPP feature set. OMA LPP extensions (LPPe), supported in SUPL 3.0, build on top of the 3GPP LPP reusing its procedures and data types. +LTE Release 9 introduced extension hooks in LPP messages, so that the bodies external to 3GPP could extend the LPP feature set. OMA LPP extensions (LPPe), supported in SUPL 3.0, build on top of the 3GPP LPP reusing its procedures and data types. Check the OMA Location Working Group (WG) webpage for updated information about LPP Extensions (LPPe) Specification. -\li The OMA Mobile Location Protocol (MLP) V3.1 is an application-level protocol for getting the position of mobile stations (mobile phones, wireless personal digital assistants, etc.) independent -of underlying network technology. The MLP serves as the interface between a Location Server and a Location Services (LCS) Client. +\li The OMA Mobile Location Protocol (MLP) V3.1 is an application-level protocol for getting the position of mobile stations (mobile phones, wireless personal digital assistants, etc.) independent +of underlying network technology. The MLP serves as the interface between a Location Server and a Location Services (LCS) Client. This specification defines the core set of operations that a Location Server should be able to perform. -*/ \ No newline at end of file +*/ diff --git a/docs/doxygen/other/signal_model.dox b/docs/doxygen/other/signal_model.dox index 5d40b7f65..de02c8e19 100644 --- a/docs/doxygen/other/signal_model.dox +++ b/docs/doxygen/other/signal_model.dox @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # /*! \page the_signal_model Signal model @@ -21,46 +21,46 @@ \section gnss_signal_model GNSS signal model This page describes signals transmitted by GNSS space vehicles. Signal models are mathematical representations -of the electromagnetic waves that are exciting the receiver's antenna. The current induced by those waves is then amplified, filtered and downconverted to a suitable frequency (can be at some intermediate frequency or +of the electromagnetic waves that are exciting the receiver's antenna. The current induced by those waves is then amplified, filtered and downconverted to a suitable frequency (can be at some intermediate frequency or directly to baseband), and then converted to 0s and 1s by the Analog-to-Digital Converter (ADC). That is the job of the Radio Frequency front-end, which at its output delivers a stream of -digital samples. Those samples constitute the input of a software receiver, so for GNSS-SDR the signal models described below can be seen as the rules of the game. +digital samples. Those samples constitute the input of a software receiver, so for GNSS-SDR the signal models described below can be seen as the rules of the game. -GNSS' space vehicles are modern versions of lighthouses, but with better visibility. Each satellite is a reference point, and if we know our distance to several reference points, +GNSS' space vehicles are modern versions of lighthouses, but with better visibility. Each satellite is a reference point, and if we know our distance to several reference points, we can compute our location, just as mariners do when they see a couple of lighthouses. For each in-view satellite \f$i\f$ of system \f$s\f$, we can write: \f{equation}{\label{eq:pseudorange} \rho_i = \sqrt{ \left(x^{\text{Tx}}_i - x \right)^2 + \left(y^{\text{Tx}}_i - y \right)^2 + \left(z^{\text{Tx}}_i - z \right)^2}+c\Delta t^{(s)}+\sigma_{e}, \f} - where \f$\left(x^{\text{Tx}}_i, y^{\text{Tx}}_i, z^{\text{Tx}}_i\right)\f$ is the satellite's position (known from the navigation message), \f$(x,y,z)\f$ the receiver's position, - and \f$\sigma_e\f$ gathers other sources of error. Since the receiver needs to estimate its own 3D position (three spatial unknowns) and its clock deviation with respect to - the satellites' time basis, at least \f$3+N_s\f$ satellites must be seen by the receiver at the same time, where \f$N_s\f$ is the number of different navigation systems available - (in-view) at a given time. Each received satellite signal, once synchronized and demodulated at the receiver, defines one equation such as the one defined above, - forming a set of nonlinear equations that can be solved algebraically by means of the Bancroft algorithm or - numerically, resorting to multidimensional Newton-Raphson and weighted least square methods. When a priori information is added we resort to Bayesian estimation, a problem - that can be solved recursively by a Kalman filter or any of its variants. The problem can be further expanded by adding other unknowns (for instance, parameters of ionospheric and - tropospheric models), sources of information from other systems, mapping information, and even motion models of the receiver. In the design of multi-constellation GNSS receivers, - the vector of unknowns can also include the receiver clock offset with respect to each system in order to take advantage of a higher number of in-view satellites and using them + where \f$\left(x^{\text{Tx}}_i, y^{\text{Tx}}_i, z^{\text{Tx}}_i\right)\f$ is the satellite's position (known from the navigation message), \f$(x,y,z)\f$ the receiver's position, + and \f$\sigma_e\f$ gathers other sources of error. Since the receiver needs to estimate its own 3D position (three spatial unknowns) and its clock deviation with respect to + the satellites' time basis, at least \f$3+N_s\f$ satellites must be seen by the receiver at the same time, where \f$N_s\f$ is the number of different navigation systems available + (in-view) at a given time. Each received satellite signal, once synchronized and demodulated at the receiver, defines one equation such as the one defined above, + forming a set of nonlinear equations that can be solved algebraically by means of the Bancroft algorithm or + numerically, resorting to multidimensional Newton-Raphson and weighted least square methods. When a priori information is added we resort to Bayesian estimation, a problem + that can be solved recursively by a Kalman filter or any of its variants. The problem can be further expanded by adding other unknowns (for instance, parameters of ionospheric and + tropospheric models), sources of information from other systems, mapping information, and even motion models of the receiver. In the design of multi-constellation GNSS receivers, + the vector of unknowns can also include the receiver clock offset with respect to each system in order to take advantage of a higher number of in-view satellites and using them jointly in the navigation solution, therefore increasing accuracy. -The analytic representation of a signal received from a GNSS satellite can be generically expressed as +The analytic representation of a signal received from a GNSS satellite can be generically expressed as \f{equation}{\label{eq:analytic} r(t)=\alpha(t) s_{T} \left(t-\tau(t)\right)e^{-j2 \pi f_d(t) }e^{j 2 \pi f_c t}+n(t)~, \f} - where \f$\alpha(t)\f$ is the amplitude, \f$s_{T}(t)\f$ is the complex baseband transmitted signal, \f$\tau(t)\f$ is the time-varying delay, \f$f_d(t)=f_c \tau(t)\f$ is the Doppler shift, \f$f_c\f$ is - the carrier frequency, and \f$n(t)\f$ is a noise term. These signals arrive to the Earth's surface at extremely low power (e.g. \f$-158.5\f$ dBW for GPS L1 C/A-code, \f$-157\f$ dBW - for Galileo E1), well below the noise floor. In order to estimate its distances to satellites, the receiver must correlate time-aligned replicas of the corresponding pseudorandom - code with the incoming signal, in a process called despreading that provides processing gain only to the signal of interest. After a coarse and fine estimation stages of the - synchronization parameters (usually known as acquisition and tracking, respectively), signal processing output is in form of observables: - - i) the pseudorange (code) measurement, + where \f$\alpha(t)\f$ is the amplitude, \f$s_{T}(t)\f$ is the complex baseband transmitted signal, \f$\tau(t)\f$ is the time-varying delay, \f$f_d(t)=f_c \tau(t)\f$ is the Doppler shift, \f$f_c\f$ is + the carrier frequency, and \f$n(t)\f$ is a noise term. These signals arrive to the Earth's surface at extremely low power (e.g. \f$-158.5\f$ dBW for GPS L1 C/A-code, \f$-157\f$ dBW + for Galileo E1), well below the noise floor. In order to estimate its distances to satellites, the receiver must correlate time-aligned replicas of the corresponding pseudorandom + code with the incoming signal, in a process called despreading that provides processing gain only to the signal of interest. After a coarse and fine estimation stages of the + synchronization parameters (usually known as acquisition and tracking, respectively), signal processing output is in form of observables: + + i) the pseudorange (code) measurement, equivalent to the difference of the time of reception (expressed -in the time frame of the receiver) and the time of transmission (expressed in the time frame of the satellite) of a distinct satellite signal; and optionally +in the time frame of the receiver) and the time of transmission (expressed in the time frame of the satellite) of a distinct satellite signal; and optionally -ii) the carrier-phase measurement, actually being a measurement on the beat frequency between the received carrier of the satellite signal and a receiver-generated reference frequency. -Carrier phase measurements are ambiguous, in the sense that the integer number of carrier wavelengths between satellite and the receiver's antenna is unknown. -Techniques such as Least-square AMBiguity Decorrelation Approach (LAMBDA) or -Multi Carrier Ambiguity Resolution (MCAR) can be applied to resolve such ambiguity and provide an accurate estimation of the distance between the satellite and the receiver. +ii) the carrier-phase measurement, actually being a measurement on the beat frequency between the received carrier of the satellite signal and a receiver-generated reference frequency. +Carrier phase measurements are ambiguous, in the sense that the integer number of carrier wavelengths between satellite and the receiver's antenna is unknown. +Techniques such as Least-square AMBiguity Decorrelation Approach (LAMBDA) or +Multi Carrier Ambiguity Resolution (MCAR) can be applied to resolve such ambiguity and provide an accurate estimation of the distance between the satellite and the receiver. -Then, depending on the required accuracy, the navigation solution can range from pseudorange-only, computationally low demanding, and limited accuracy least squares methods to sophisticated combinations of code and +Then, depending on the required accuracy, the navigation solution can range from pseudorange-only, computationally low demanding, and limited accuracy least squares methods to sophisticated combinations of code and phase observables at different frequencies for high demanding applications such as surveying, geodesy, and geophysics. @@ -74,7 +74,7 @@ and civilian users on a continuous, worldwide basis. Two GPS services are provid the Precise Positioning Service (PPS), available primarily to the military of the United States and its allies, and the Standard Positioning Service (SPS) open to civilian users. -\li GPS L1. Defined at Interface Specification IS-GPS-200 Revision F, this band is centered at \f$f_{\text{GPS L1}}=1575.42\f$ MHz. The complex baseband transmitted signal can be written as +\li GPS L1. Defined at Interface Specification IS-GPS-200 Revision F, this band is centered at \f$f_{\text{GPS L1}}=1575.42\f$ MHz. The complex baseband transmitted signal can be written as \f{equation}{ s^{\text{(GPS L1)}}_{T}(t)=e_{L1I}(t) + j e_{L1Q}(t)~, \f} @@ -83,30 +83,30 @@ s^{\text{(GPS L1)}}_{T}(t)=e_{L1I}(t) + j e_{L1Q}(t)~, e_{L1I}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{NAV}}\Big[ [l]_{204600}\Big] \oplus C_{\text{P(Y)}}\Big[ |l|_{L_{\text{P(Y)}}} \Big] p(t - lT_{c,\text{P(Y)}})~,\label{eq:L1CAI}\\ e_{L1Q}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{NAV}}\Big[ [l]_{20460} \Big] \oplus C_{\text{C/A}} \Big[ |l|_{1023} \Big] p(t - lT_{c,\text{C/A}})~,\label{eq:L1CA} \f} - where \f$\oplus\f$ is the exclusive-or operation (modulo-2 addition), \f$|l|_{L}\f$ means \f$l\f$ modulo \f$L\f$, \f$[l]_{L}\f$ means the integer part of \f$\frac{l}{L}\f$, - \f$D_{\text{NAV}}\f$ is the GPS navigation message bit sequence, transmitted at \f$50\f$ bps, \f$T_{c,\text{P(Y)}}=\frac{1}{10.23}\f$ \f$\mu\f$s, \f$T_{c,\text{C/A}}=\frac{1}{1.023}\f$ \f$\mu\f$s, - \f$L_{\text{P(Y)}}=6.1871 \cdot 10^{12}\f$, and \f$p(t)\f$ is a rectangular pulse of a chip-period duration centered at \f$t=0\f$ and filtered at the transmitter. - According to the chip rate, the binary phase-shift keying modulations in the equations above are denoted as BPSK(10) and BPSK(1), respectively. The precision P codes (named Y codes whenever - the anti-spoofing mode is activated, encrypting the code and thus denying non-U.S. military users) are sequences of \f$7\f$ days in length. Regarding the modernization plans for GPS, it - is worthwhile to mention that there is a new civilian-use signal planned, called L1C and defined at Interface Specification IS-GPS-800 Revision B, - to be broadcast on the same L1 frequency that currently contains the C/A signal. The L1C will be available with first Block III launch, currently scheduled for 2013. The implementation will + where \f$\oplus\f$ is the exclusive-or operation (modulo-2 addition), \f$|l|_{L}\f$ means \f$l\f$ modulo \f$L\f$, \f$[l]_{L}\f$ means the integer part of \f$\frac{l}{L}\f$, + \f$D_{\text{NAV}}\f$ is the GPS navigation message bit sequence, transmitted at \f$50\f$ bps, \f$T_{c,\text{P(Y)}}=\frac{1}{10.23}\f$ \f$\mu\f$s, \f$T_{c,\text{C/A}}=\frac{1}{1.023}\f$ \f$\mu\f$s, + \f$L_{\text{P(Y)}}=6.1871 \cdot 10^{12}\f$, and \f$p(t)\f$ is a rectangular pulse of a chip-period duration centered at \f$t=0\f$ and filtered at the transmitter. + According to the chip rate, the binary phase-shift keying modulations in the equations above are denoted as BPSK(10) and BPSK(1), respectively. The precision P codes (named Y codes whenever + the anti-spoofing mode is activated, encrypting the code and thus denying non-U.S. military users) are sequences of \f$7\f$ days in length. Regarding the modernization plans for GPS, it + is worthwhile to mention that there is a new civilian-use signal planned, called L1C and defined at Interface Specification IS-GPS-800 Revision B, + to be broadcast on the same L1 frequency that currently contains the C/A signal. The L1C will be available with first Block III launch, currently scheduled for 2013. The implementation will provide C/A code to ensure backward compatibility. -\li GPS L2C. Defined at Interface Specification IS-GPS-200 Revision F, is only available on -Block IIR-M and subsequent satellite blocks. Centered at \f$f_{\text{GPS L2}}=1227.60\f$ MHz, the signal structure is the same than in (\ref{eq:GPSL1}), with the precision code in the In-phase +\li GPS L2C. Defined at Interface Specification IS-GPS-200 Revision F, is only available on +Block IIR-M and subsequent satellite blocks. Centered at \f$f_{\text{GPS L2}}=1227.60\f$ MHz, the signal structure is the same than in (\ref{eq:GPSL1}), with the precision code in the In-phase component, just as in (\ref{eq:L1CAI}) but with an optional presence of the navigation message \f$D_{\text{NAV}}\f$. For the Quadrature-phase component, three options are defined: \f{align}{ e_{L2CQ}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{CNAV}} \Big[ [l]_{10230} \Big] \oplus \left( C_{\text{CL}} \Big[ |l|_{L_{\text{CL}}} \Big] p_{\text{\tiny{1/2}}} \left( t - lT_{c,L2C} \right) + \right.\\ {} &+ \left. C_{\text{CM}} \Big[ |l|_{L_{\text{CM}}} \Big] p_{\text{\tiny{1/2}}}\left(t - \left(l+\frac{3}{4}\right)T_{c,L2C}\right) \right),\\ e_{L2CQ}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{NAV}} \Big[ [l]_{20460} \Big] \oplus C_{\text{C/A}} \Big[ |l|_{1023} \Big] p \left(t - lT_{c,\text{C/A}}\right) \text{, or}\\ e_{L2CQ}(t)=& \sum_{l=-\infty}^{\infty}C_{\text{C/A}} \Big[ |l|_{1023} \Big] p(t - lT_{c,\text{C/A}})~, \f} - where \f$T_{c,L2C}=\frac{1}{511.5}\f$ ms and \f$p_{\text{\tiny{1/2}}}(t)\f$ is a rectangular pulse of half chip-period duration, thus time-multiplexing both codes. The civilian long - code \f$C_{\text{CL}}\f$ is \f$L_{\text{CL}}=767250\f$ chips long, repeating every \f$1.5\f$ s, while the civilian moderate code \f$C_{\text{CM}}\f$ is \f$L_{\text{CL}}=10230\f$ chips - long and its repeats every \f$20\f$ ms. The CNAV data is an upgraded version of the original NAV navigation message, containing higher precision representation and nominally more accurate + where \f$T_{c,L2C}=\frac{1}{511.5}\f$ ms and \f$p_{\text{\tiny{1/2}}}(t)\f$ is a rectangular pulse of half chip-period duration, thus time-multiplexing both codes. The civilian long + code \f$C_{\text{CL}}\f$ is \f$L_{\text{CL}}=767250\f$ chips long, repeating every \f$1.5\f$ s, while the civilian moderate code \f$C_{\text{CM}}\f$ is \f$L_{\text{CL}}=10230\f$ chips + long and its repeats every \f$20\f$ ms. The CNAV data is an upgraded version of the original NAV navigation message, containing higher precision representation and nominally more accurate data than the NAV data. It is transmitted at \f$25\f$ bps with forward error correction (FEC) encoding, resulting in \f$50\f$ sps. -\li GPS L5. The GPS L5 link, defined at Interface Specification IS-GPS-705 Revision B, is only available +\li GPS L5. The GPS L5 link, defined at Interface Specification IS-GPS-705 Revision B, is only available in Block IIF (first satellite launched on May, 2010) and subsequent satellite blocks. Centered at \f$f_{\text{GPS L5}}=1176.45\f$ MHz, this signal in space can be written as: \f{equation}{ s^{\text{(GPS L5)}}_{T}(t)=e_{L5I}(t) +j e_{L5Q}(t)~, @@ -129,9 +129,9 @@ Eight satellites are equally spaced in each plane with \f$45^o\f$ argument of la the orbital planes have an argument of latitude displacement of \f$15^o\f$ relative to each other. -GLONASS civil signal-in-space is defined at Interface Control Document. Navigational radiosignal in bands L1, L2. Edition 5.1. -This system makes use of a frequency-division multiple access (FDMA) signal structure, transmitting in two bands: \f$f^{(k)}_{GLO L1}=1602+k \cdot 0.5625\f$ MHz and \f$f^{(k)}_{GLO L2}=1246+k \cdot 0.4375\f$ MHz, -where \f$k\in \left\{ -7,-6,\cdots,5,6\right\}\f$ is the channel number. Satellites in opposite points of an orbit plane transmit signals on equal frequencies, as these satellites will never be +GLONASS civil signal-in-space is defined at Interface Control Document. Navigational radiosignal in bands L1, L2. Edition 5.1. +This system makes use of a frequency-division multiple access (FDMA) signal structure, transmitting in two bands: \f$f^{(k)}_{GLO L1}=1602+k \cdot 0.5625\f$ MHz and \f$f^{(k)}_{GLO L2}=1246+k \cdot 0.4375\f$ MHz, +where \f$k\in \left\{ -7,-6,\cdots,5,6\right\}\f$ is the channel number. Satellites in opposite points of an orbit plane transmit signals on equal frequencies, as these satellites will never be in view simultaneously by a ground-based user. @@ -144,18 +144,18 @@ s^{\text{(GLO L1)}}_{T}(t)=e_{L1I}(t) + j e_{L1Q}(t)~, e_{L1I}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{GNAV}}\Big[ [l]_{102200}\Big] \oplus C_{\text{HP}} \Big[ |l|_{L_{\text{HP}}} \Big] p(t - lT_{c,\text{HP}})~,\\ e_{L1Q}(t) =& \sum_{l=-\infty}^{\infty} D_{\text{GNAV}}\Big[ [l]_{10220} \Big] \oplus C_{\text{SP}} \Big[ |l|_{511} \Big] p(t - lT_{c,\text{SP}})~, \f} - where \f$T_{c,\text{HP}}=\frac{1}{5.11}\f$ \f$\mu\f$s, \f$T_{c,\text{SP}}=\frac{1}{0.511}\f$ \f$\mu\f$s, and \f$L_{\text{HP}}=3.3554\cdot 10^7\f$. The navigation - message \f$D_{\text{GNAV}}\f$ is transmitted at \f$50\f$ bps. Details of its content and structure, as well as the generation of the \f$C_{\text{SP}}\f$ code, can be found at - the ICD. The usage of the HP signal should be agreed with the Russian Federation Defense + where \f$T_{c,\text{HP}}=\frac{1}{5.11}\f$ \f$\mu\f$s, \f$T_{c,\text{SP}}=\frac{1}{0.511}\f$ \f$\mu\f$s, and \f$L_{\text{HP}}=3.3554\cdot 10^7\f$. The navigation + message \f$D_{\text{GNAV}}\f$ is transmitted at \f$50\f$ bps. Details of its content and structure, as well as the generation of the \f$C_{\text{SP}}\f$ code, can be found at + the ICD. The usage of the HP signal should be agreed with the Russian Federation Defense Ministry, and no more details have been disclosed. \li GLONASS L2. Beginning with the second generation of satellites, called GLONASS-M and first launched in 2001, a second civil signal is available using the same SP code than the one in the L1 band. -The use of FDMA techniques, in which the same code is used to broadcast navigation signals on different frequencies, and the placement of civil GLONASS transmissions on frequencies close to \f$1600\f$ MHz, -well above the GPS L1 band, have complicated the design of combined GLONASS/GPS receivers, particularly low-cost equipment for mass-market applications. Future plans of modernization are -intended to increase compatibility and interoperability with other GNSS, and include the addition of a code-division multiple access (CDMA) structure, and possibly binary offset carrier (BOC) -modulation, beginning with the third civil signal in the L3 band (\f$1197.648 - 1212.255\f$ MHz). Russia is implementing the new signals on the next-generation GLONASS-K satellites, with a +The use of FDMA techniques, in which the same code is used to broadcast navigation signals on different frequencies, and the placement of civil GLONASS transmissions on frequencies close to \f$1600\f$ MHz, +well above the GPS L1 band, have complicated the design of combined GLONASS/GPS receivers, particularly low-cost equipment for mass-market applications. Future plans of modernization are +intended to increase compatibility and interoperability with other GNSS, and include the addition of a code-division multiple access (CDMA) structure, and possibly binary offset carrier (BOC) +modulation, beginning with the third civil signal in the L3 band (\f$1197.648 - 1212.255\f$ MHz). Russia is implementing the new signals on the next-generation GLONASS-K satellites, with a first prototype successfully launched into orbit on February 26, 2011. @@ -173,9 +173,9 @@ period of \f$14\f$ hours. The Control segment full infrastructure will be compos Galileo's Open Service is defined at Signal In Space Interface Control Document. Ref: OS SIS ICD, Issue 1.1, where the following signal structures are specified: -\li Galileo E1. This band, centered at \f$f_{\text{Gal E1}}=1575.420\f$ MHz and with a reference bandwidth of \f$24.5520\f$ MHz, uses the so-called composite binary offset carrier +\li Galileo E1. This band, centered at \f$f_{\text{Gal E1}}=1575.420\f$ MHz and with a reference bandwidth of \f$24.5520\f$ MHz, uses the so-called composite binary offset carrier CBOC(6,1,\f$\frac{1}{11}\f$) modulation, defined in baseband as: -\f{align}{ +\f{align}{ s^{\text{(Gal E1)}}_{T}(t)=&\frac{1}{\sqrt{2}} \Big( e_{E1B}(t)\left( \alpha sc_A(t)+ \beta sc_B(t) \right)+ \\ {}& - e_{E1C}(t) \left( \alpha sc_A(t)- \beta sc_B(t) \right) \Big)~,\label{eq:CBOC} \f} @@ -192,8 +192,8 @@ In case of channel \f$C\f$, it is a pilot (dataless) channel with a secondary co \f{align}{ \nonumber e_{E1C}(t)&= \sum_{m=-\infty}^{+\infty}C_{E1Cs}\Big[|m|_{25}\Big] \oplus \sum_{l=1}^{4092}C_{E1Cp}\Big[ l \Big] \cdot \\ {}& \; \; \cdot p(t-mT_{c,E1Cs}-lT_{c,E1Cp})~,\label{eq:E1C} \f} - with \f$T_{c,E1B}=T_{c,E1Cp}=\frac{1}{1.023}\f$ \f$\mu\f$s and \f$T_{c,E1Cs}=4\f$ ms. The \f$C_{E1B}\f$ and \f$C_{E1Cp}\f$ primary codes are pseudorandom memory code sequences defined at - Annex C.7 and C.8 of OS SIS ICD. The binary + with \f$T_{c,E1B}=T_{c,E1Cp}=\frac{1}{1.023}\f$ \f$\mu\f$s and \f$T_{c,E1Cs}=4\f$ ms. The \f$C_{E1B}\f$ and \f$C_{E1Cp}\f$ primary codes are pseudorandom memory code sequences defined at + Annex C.7 and C.8 of OS SIS ICD. The binary sequence of the secondary code \f$C_{E1Cs}\f$ is 0011100000001010110110010. This band also contains another component, Galileo E1A, intended for the Public Regulated Service (PRS). It uses a BOC(15,2.5) modulation with cosine-shaped subcarrier \f$f_{s,E1A}=15.345\f$ MHz and \f$T_{c, E1A}=\frac{1}{2.5575}\f$ \f$\mu\f$s. The PRS spreading codes and the structure of the navigation message have not been made public. @@ -207,19 +207,19 @@ s_{T}^{\text{(Gal E6)}}(t) = \frac{1}{\sqrt{2}}\left(e_{E6B}(t)-e_{E6C}(t)\right \nonumber e_{E6B}(t) =& \sum_{m=-\infty}^{+\infty} D_{\text{C/NAV}} \Big[ [l]_{5115}\Big] \oplus C_{E6B}\Big[|l|_{L_{E6B}}\Big] \cdot \\ {}& \cdot p(t - lT_{c,E6}),\\ \nonumber e_{E6C}(t) =& \sum_{m=-\infty}^{+\infty}C_{E6Cs}\Big[|m|_{100}\Big] \oplus \sum_{l=1}^{L_{E6C}}C_{E6Cp}\Big[ l \Big] \cdot \\ {}& \cdot p(t-mT_{c,E6s} -lT_{c,E6p}), \f} - where \f$D_{\text{C/NAV}}\f$ is the C/NAV navigation data stream, which is modulated with the encrypted ranging code \f$C_{E6B}\f$ with chip period \f$T_{c,E6}=\frac{1}{5.115}\f$ \f$\mu\f$s, thus - being a BPSK(5) modulation. Codes \f$C_{E6B}\f$ and primary codes \f$C_{E6Cs}\f$ and their respective lengths, \f$L_{E6B}\f$ and \f$L_{E6C}\f$, have not been published. The secondary codes - for the pilot component, \f$C_{E6Cs}\f$, are available at the OS SIS ICD. + where \f$D_{\text{C/NAV}}\f$ is the C/NAV navigation data stream, which is modulated with the encrypted ranging code \f$C_{E6B}\f$ with chip period \f$T_{c,E6}=\frac{1}{5.115}\f$ \f$\mu\f$s, thus + being a BPSK(5) modulation. Codes \f$C_{E6B}\f$ and primary codes \f$C_{E6Cs}\f$ and their respective lengths, \f$L_{E6B}\f$ and \f$L_{E6C}\f$, have not been published. The secondary codes + for the pilot component, \f$C_{E6Cs}\f$, are available at the OS SIS ICD. The receiver reference bandwidth for this signal is \f$40.920\f$ MHz. This band also contains another component, Galileo E6A, intended for PRS. \li Galileo E5. Centered at \f$f_{\text{Gal E5}}=1191.795\f$ MHz and with a total bandwidth of \f$51.150\f$ MHz, its signal structure deserves some analysis. The AltBOC modulation can be generically expressed as \f{equation}{\label{AltBOC} s^{\text{AltBOC}}(t)=x_1(t)v^{*}(t)+x_2(t)v(t)~, \f} - where \f$v(t)=\frac{1}{\sqrt{2}}\left( \text{sign}\left( \cos (2 \pi f_s t)\right)+j \text{sign}\left( \sin (2 \pi f_s t)\right)\right)\f$ is the single side-band - subcarrier, \f$f_s\f$ is the subcarrier frequency, \f$(\cdot)^{*}\f$ stands for the conjugate operation, and \f$x_1(t)\f$ and \f$x_2(t)\f$ are QPSK signals. - The resulting waveform does not exhibit constant envelope. In case of Galileo, the need for high efficiency of the satellites' onboard High Power Amplifier (HPA) has pushed - a modification on the signal in order to make it envelope-constant and thus use the HPA at saturation. This can be done by adding some inter-modulation products to the expression + where \f$v(t)=\frac{1}{\sqrt{2}}\left( \text{sign}\left( \cos (2 \pi f_s t)\right)+j \text{sign}\left( \sin (2 \pi f_s t)\right)\right)\f$ is the single side-band + subcarrier, \f$f_s\f$ is the subcarrier frequency, \f$(\cdot)^{*}\f$ stands for the conjugate operation, and \f$x_1(t)\f$ and \f$x_2(t)\f$ are QPSK signals. + The resulting waveform does not exhibit constant envelope. In case of Galileo, the need for high efficiency of the satellites' onboard High Power Amplifier (HPA) has pushed + a modification on the signal in order to make it envelope-constant and thus use the HPA at saturation. This can be done by adding some inter-modulation products to the expression above, coming up with the following definition: \f{align}{ @@ -260,9 +260,9 @@ receiver. The single subcarrier \f$sc_s(t)\f$ and the product subcarrier \f$sc_p sc_p(t)=& -\frac{\sqrt{2}}{4}\text{sign} \left( \cos \left( 2 \pi f_s t - \frac{\pi}{4}\right) \right)+\\ \nonumber {}&+ \frac{1}{2}\text{sign} \Big( \cos \left( 2 \pi f_s t \right) \Big)+\\ {} &-\frac{\sqrt{2}}{4}\text{sign} \left( \cos \left( 2 \pi f_s t + \frac{\pi}{4}\right) \right)~, \f} - with a subcarrier frequency of \f$f_s=15.345\f$ MHz, thus defining an AltBOC(15,10) modulation. The QPSK(10) signal \f$e_{E5a}(t)\f$ defined above is shifted + with a subcarrier frequency of \f$f_s=15.345\f$ MHz, thus defining an AltBOC(15,10) modulation. The QPSK(10) signal \f$e_{E5a}(t)\f$ defined above is shifted to \f$f_{\text{Gal E5a}}\doteq f_{\text{Gal E5}}-f_s=1176.450\f$ MHz, while \f$e_{E5b}(t)\f$ is shifted to \f$f_{\text{Gal E5b}}\doteq f_{\text{Gal E5}}+f_s=1207.140\f$ MHz. - Thus, we can bandpass filter around \f$f_{\text{Gal E5a}}\f$ and get a good approximation of a QPSK(10) signal, with very low energy components of \f$e_{E5b}(t)\f$, \f$ \bar{e}_{E5a}(t)\f$, + Thus, we can bandpass filter around \f$f_{\text{Gal E5a}}\f$ and get a good approximation of a QPSK(10) signal, with very low energy components of \f$e_{E5b}(t)\f$, \f$ \bar{e}_{E5a}(t)\f$, and \f$ \bar{e}_{E5b}(t)\f$: \f{equation}{ s_{T}^{\text{(Gal E5a)}}(t) \simeq e_{E5aI}(t)+je_{E5aQ}(t). @@ -273,9 +273,9 @@ The same applies to \f$e_{E5b}(t)\f$, allowing an independent reception of two Q This text is an except of the following paper: -\li C. Fernández-Prades, L. Lo Presti, E. Falleti, Satellite Radiolocalization From GPS to GNSS and Beyond: Novel Technologies and Applications for Civil Mass-Market. +\li C. Fernández-Prades, L. Lo Presti, E. Falleti, Satellite Radiolocalization From GPS to GNSS and Beyond: Novel Technologies and Applications for Civil Mass-Market. Proceedings of the IEEE. Vol 99, No. 11, pp. 1882-1904. November, 2011. DOI: 10.1109/JPROC.2011.2158032 - - -*/ \ No newline at end of file + + +*/ diff --git a/docs/manpage/front-end-cal-manpage b/docs/manpage/front-end-cal-manpage index 13d639c57..940a4b0ee 100644 --- a/docs/manpage/front-end-cal-manpage +++ b/docs/manpage/front-end-cal-manpage @@ -17,9 +17,9 @@ The crystal oscillator that ships with the RTL2832U family devices exhibits limi \fBfront\-end\-cal\fR takes the following options: .TP \fB\-config_file=\fR\fI\fR Set the configuration file. -.TP +.TP \fB\-signal_source=\fR\fI\fR If defined, path to the file containing the signal samples (overrides the data file specified in the configuration file). -.TP +.TP \fB\-log_dir=\fR\fI\fR If defined, overrides the default directory where logs are saved. .TP \fB\-version\fR Print program version and exit. @@ -32,10 +32,10 @@ Example of configuration file available at: ${prefix}/share/gnss\-sdr/conf/front \.TP [1] C. Fernandez\-Prades, J. Arribas, P. Closas, \fITurning a Television into a GNSS Receiver\fR, in Proceedings of ION GNSS+, 15\-16 September 2013, Nashville, Tennessee (USA). A draft copy is freely available at http://www.cttc.es/publication/turning\-a\-television\-into\-a\-gnss\-receiver/ \.TP -Check http://gnss\\-sdr.org for more information. +Check https://gnss\-sdr.org for more information. .SH BUGS No known bugs. .SH AUTHOR Javier Arribas (javier.arribas@cttc.es) \.TP -This software has been developed at CTTC (Centre Tecnologic de Telecomunicacions de Catalunya, http://www.cttc.es) with contributions from around the world. \ No newline at end of file +This software has been developed at CTTC (Centre Tecnologic de Telecomunicacions de Catalunya, http://www.cttc.es) with contributions from around the world. diff --git a/docs/manpage/gnss-sdr-manpage b/docs/manpage/gnss-sdr-manpage index 668b6bf3d..90f7d1a8e 100644 --- a/docs/manpage/gnss-sdr-manpage +++ b/docs/manpage/gnss-sdr-manpage @@ -1,37 +1,79 @@ .\" Manpage for gnss\-sdr. .\" Contact carles.fernandez@cttc.es to correct errors or typos. -.TH gnss\-sdr 1 "05 Feb 2017" "0.0.9" "gnss\-sdr man page" +.TH gnss\-sdr 1 "12 Dec 2018" "0.0.10" "gnss\-sdr man page" .SH NAME \fBgnss\-sdr\fR \- GNSS Software Defined Receiver. .SH SYNOPSIS -\fBgnss\-sdr \-config_file=\fR\fI\fR [OPTION]... +\fBgnss\-sdr \-c=\fR\fI\fR [OPTION]... .SH DESCRIPTION -\fBgnss\-sdr\fR is a Global Navigation Satellite Systems Software Defined Receiver written in C++. It implements all the signal processing chain, taking as input raw samples coming from the output of an Analog\-to\-Digital Converter, and processing them up to the computation of the Position\-Velocity\-Time solution, including the generation of code and phase measurements. +\fBgnss\-sdr\fR is a Global Navigation Satellite Systems Software Defined Receiver written in C++. It implements all the signal processing chain, taking as input raw samples coming from the output of an Analog\-to\-Digital Converter, and processing them up to the computation of the Position\-Velocity\-Time solution, including the generation of code and phase measurements. \.TP \fBgnss\-sdr\fR is able to work with raw data files or, if there is computational power enough, in real time with suitable radio frequency front\-ends. The whole receiver is defined in a single configuration file, and therefore users can define theirs. +\.TP +There is some flexibility in how flags may be specified. The following examples are equivalent: +\.RS 8 +\.TP +gnss\-sdr \-c=/home/user/rx.conf +\.TP +gnss\-sdr \-\-c=/home/user/rx.conf +\.TP +gnss\-sdr \-c /home/user/rx.conf +\.TP +gnss\-sdr \-\-c /home/user/rx.conf +\.RE .SH OPTIONS \fBgnss\-sdr\fR takes the following options: .TP -\fB\-config_file=\fR\fI\fR Set the configuration file. -.TP -\fB\-signal_source=\fR\fI\fR If defined, path to the file containing the signal samples (overrides the data file specified in the configuration file). -.TP -\fB\-log_dir=\fR\fI\fR If defined, overrides the default directory where logs are saved. +\fB\-c=\fR\fI\fR or \fB\-config_file=\fR\fI\fR +Set the configuration file. This flag is mandatory. .TP -\fB\-RINEX_version=\fI\fR Specifies the RINEX version (2.11 or 3.02). Default: "3.02". +\fB\-s=\fR\fI\fR or \fB\-signal_source=\fR\fI\fR +If defined, path to the file containing the signal samples (overrides the data file specified in the configuration file). .TP -\fB\-version\fR Print program version and exit. +\fB\-log_dir=\fR\fI\fR +If defined, overrides the default directory where logs are saved. .TP -\fB\-help\fR Print all the available commandline flags and exit. +\fB\-doppler_max=\fR\fI\fR +If defined, maximum Doppler value in the search grid, in Hz (overrides the configuration file). +.TP +\fB\-doppler_step=\fR\fI\fR +If defined, sets the frequency step in the search grid, in Hz (overrides the configuration file). +.TP +\fB\-cn0_samples=\fR\fI\fR +Number of correlators outputs (one per integration time) used for CN0 estimation. It defaults to 20 outputs. +.TP +\fB\-cn0_min=\fR\fI\fR +Minimum valid CN0 (in dB-Hz). It defaults to 25 dB-Hz. If set, it overrides the configuration file. +.TP +\fB\-max_lock_fail=\fR\fI\fR +Maximum number of lock failures before dropping a satellite. It defaults to 50 failures. If set, it overrides the configuration file. +.TP +\fB\-carrier_lock_th=\fR\fI\fR +Carrier lock error threshold (in rad). It defaults to 0.85 rad (48.7 degrees). If set, it overrides the configuration file. +.TP +\fB\-dll_bw_hz=\fR\fI\fR +If defined, bandwidth of the DLL low pass filter, in Hz (overrides the configuration file). +.TP +\fB\-pll_bw_hz=\fR\fI\fR +If defined, bandwidth of the PLL low pass filter, in Hz (overrides the configuration file). +.TP +\fB\-RINEX_version=\fI\fR +If defined, specifies the RINEX version (2.11 or 3.02). Default: "3.02". Overrides the configuration file. +.TP +\fB\-version\fR +Print program version and exit. +.TP +\fB\-help\fR +Print all the available commandline flags and exit. .SH SEE ALSO .BR volk_gnsssdr_profile (1) \.TP Examples of configuration files available at: ${prefix}/share/gnss\-sdr/conf, where ${prefix} uses to be /usr or /usr/local. \.TP -Check http://gnss\-sdr.org for more information. +Check https://gnss\-sdr.org for more information. .SH BUGS Please report bugs at https://github.com/gnss-sdr/gnss-sdr/issues .SH AUTHOR Carles Fernandez\-Prades (carles.fernandez@cttc.es) \.TP -This software package has been developed at CTTC (Centre Tecnologic de Telecomunicacions de Catalunya, http://www.cttc.es) with contributions from around the world. \ No newline at end of file +This software package has been developed at CTTC (Centre Tecnologic de Telecomunicacions de Catalunya, http://www.cttc.es) with contributions from around the world. diff --git a/docs/xml-schemas/README.md b/docs/xml-schemas/README.md new file mode 100644 index 000000000..007d520c0 --- /dev/null +++ b/docs/xml-schemas/README.md @@ -0,0 +1,35 @@ +# XML Schemas for Assisted GNSS-SDR + +GNSS-SDR can read assistance data from [Extensible Markup Language (XML)](https://www.w3.org/XML/) files for faster [Time-To-First-Fix](https://gnss-sdr.org/design-forces/availability/#time-to-first-fix-ttff), and can store navigation data decoded from GNSS signals in the same format. This folder provides XML Schemas which describe those XML files structure. + +[XSD (XML Schema Definition)](https://www.w3.org/XML/Schema) is a World Wide Web Consortium (W3C) recommendation that specifies how to formally describe the elements in an XML document. + + +GPS L1 C/A +---------- + + - [ephemeris_map.xsd](./ephemeris_map.xsd) - GPS NAV message ephemeris parameters. + - [iono_model.xsd](./iono_model.xsd) - GPS NAV message ionospheric model parameters. + - [utc_model.xsd](./utc_model.xsd) - GPS NAV message UTC model parameters. + - [gps_almanac_map.xsd](./gps_almanac_map.xsd) - GPS NAV message almanac. + + +GPS L2C and L5 +-------------- + + - [cnav_ephemeris_map.xsd](./cnav_ephemeris_map.xsd) - GPS CNAV message ephemeris parameters. + + +Galileo +------- + + - [gal_ephemeris_map.xsd](./gal_ephemeris_map.xsd) - Galileo ephemeris parameters. + - [gal_iono_model.xsd](./gal_iono_model.xsd) - Galileo ionospheric model parameters. + - [gal_utc_model.xsd](./gal_utc_model.xsd) - Galileo UTC model parameters. + - [gal_almanac_map.xsd](./gal_almanac_map.xsd) - Galileo almanac. + +------- + +Please check https://gnss-sdr.org/docs/sp-blocks/global-parameters/ for more information about the usage of XML files in GNSS-SDR. + +You could find useful the utility program [rinex2assist](https://github.com/gnss-sdr/gnss-sdr/tree/next/src/utils/rinex2assist) for the generation of compatible XML files from recent, publicly available RINEX navigation data files. diff --git a/docs/xml-schemas/cnav_ephemeris_map.xsd b/docs/xml-schemas/cnav_ephemeris_map.xsd new file mode 100644 index 000000000..2ada62f13 --- /dev/null +++ b/docs/xml-schemas/cnav_ephemeris_map.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/ephemeris_map.xsd b/docs/xml-schemas/ephemeris_map.xsd new file mode 100644 index 000000000..4290bbed5 --- /dev/null +++ b/docs/xml-schemas/ephemeris_map.xsd @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/gal_almanac_map.xsd b/docs/xml-schemas/gal_almanac_map.xsd new file mode 100644 index 000000000..8512bfc64 --- /dev/null +++ b/docs/xml-schemas/gal_almanac_map.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/gal_ephemeris_map.xsd b/docs/xml-schemas/gal_ephemeris_map.xsd new file mode 100644 index 000000000..fe307412e --- /dev/null +++ b/docs/xml-schemas/gal_ephemeris_map.xsd @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/gal_iono_model.xsd b/docs/xml-schemas/gal_iono_model.xsd new file mode 100644 index 000000000..69b22aad4 --- /dev/null +++ b/docs/xml-schemas/gal_iono_model.xsd @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/gal_utc_model.xsd b/docs/xml-schemas/gal_utc_model.xsd new file mode 100644 index 000000000..3cc38107c --- /dev/null +++ b/docs/xml-schemas/gal_utc_model.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/gps_almanac_map.xsd b/docs/xml-schemas/gps_almanac_map.xsd new file mode 100644 index 000000000..86b9d2a2d --- /dev/null +++ b/docs/xml-schemas/gps_almanac_map.xsd @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/iono_model.xsd b/docs/xml-schemas/iono_model.xsd new file mode 100644 index 000000000..26cda74bd --- /dev/null +++ b/docs/xml-schemas/iono_model.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/xml-schemas/utc_model.xsd b/docs/xml-schemas/utc_model.xsd new file mode 100644 index 000000000..c02015ead --- /dev/null +++ b/docs/xml-schemas/utc_model.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fbce5e499..83c519fd5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(algorithms) @@ -21,5 +21,5 @@ add_subdirectory(core) add_subdirectory(main) if(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) add_subdirectory(tests) -endif(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) +endif() add_subdirectory(utils) diff --git a/src/algorithms/CMakeLists.txt b/src/algorithms/CMakeLists.txt index d6f0521dc..2b10446e8 100644 --- a/src/algorithms/CMakeLists.txt +++ b/src/algorithms/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(acquisition) diff --git a/src/algorithms/PVT/CMakeLists.txt b/src/algorithms/PVT/CMakeLists.txt index 763852ca2..96259341c 100644 --- a/src/algorithms/PVT/CMakeLists.txt +++ b/src/algorithms/PVT/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) diff --git a/src/algorithms/PVT/adapters/CMakeLists.txt b/src/algorithms/PVT/adapters/CMakeLists.txt index 3a7e524dd..d8c055506 100644 --- a/src/algorithms/PVT/adapters/CMakeLists.txt +++ b/src/algorithms/PVT/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,31 +13,44 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(PVT_ADAPTER_SOURCES - gps_l1_ca_pvt.cc - galileo_e1_pvt.cc - hybrid_pvt.cc + +if(Boost_VERSION LESS 105800) + add_definitions(-DOLD_BOOST=1) +endif() + +set(PVT_ADAPTER_SOURCES + rtklib_pvt.cc +) + +set(PVT_ADAPTER_HEADERS + rtklib_pvt.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${ARMADILLO_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${ARMADILLO_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB PVT_ADAPTER_HEADERS "*.h") -list(SORT PVT_ADAPTER_HEADERS) add_library(pvt_adapters ${PVT_ADAPTER_SOURCES} ${PVT_ADAPTER_HEADERS}) + source_group(Headers FILES ${PVT_ADAPTER_HEADERS}) -target_link_libraries(pvt_adapters pvt_gr_blocks ${ARMADILLO_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES}) + +target_link_libraries(pvt_adapters + pvt_gr_blocks + ${ARMADILLO_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} +) diff --git a/src/algorithms/PVT/adapters/galileo_e1_pvt.cc b/src/algorithms/PVT/adapters/galileo_e1_pvt.cc deleted file mode 100644 index e2c75df27..000000000 --- a/src/algorithms/PVT/adapters/galileo_e1_pvt.cc +++ /dev/null @@ -1,141 +0,0 @@ -/*! - * \file galileo_e1_pvt.cc - * \brief Implementation of an adapter of a GALILEO E1 PVT solver block to a - * PvtInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "galileo_e1_pvt.h" -#include -#include -#include "configuration_interface.h" - - -using google::LogMessage; - -GalileoE1Pvt::GalileoE1Pvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - // dump parameters - std::string default_dump_filename = "./pvt.dat"; - std::string default_nmea_dump_filename = "./nmea_pvt.nmea"; - std::string default_nmea_dump_devname = "/dev/tty1"; - std::string default_rtcm_dump_devname = "/dev/pts/1"; - DLOG(INFO) << "role " << role; - - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - - // moving average depth parameters - int averaging_depth = configuration->property(role + ".averaging_depth", 10); - bool flag_averaging = configuration->property(role + ".flag_averaging", false); - - // output rate - int output_rate_ms = configuration->property(role + ".output_rate_ms", 500); - - // display rate - int display_rate_ms = configuration->property(role + ".display_rate_ms", 500); - - // NMEA Printer settings - bool flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false); - std::string nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename); - std::string nmea_dump_devname = configuration->property(role + ".nmea_dump_devname", default_nmea_dump_devname); - - // RTCM Printer settings - bool flag_rtcm_tty_port = configuration->property(role + ".flag_rtcm_tty_port", false); - std::string rtcm_dump_devname = configuration->property(role + ".rtcm_dump_devname", default_rtcm_dump_devname); - bool flag_rtcm_server = configuration->property(role + ".flag_rtcm_server", false); - unsigned short rtcm_tcp_port = configuration->property(role + ".rtcm_tcp_port", 2101); - unsigned short rtcm_station_id = configuration->property(role + ".rtcm_station_id", 1234); - // RTCM message rates: least common multiple with output_rate_ms - int rtcm_MT1045_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1045_rate_ms", 5000), output_rate_ms); - int rtcm_MSM_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MSM_rate_ms", 1000), output_rate_ms); - std::map rtcm_msg_rate_ms; - rtcm_msg_rate_ms[1045] = rtcm_MT1045_rate_ms; - for (int k = 1091; k < 1098; k++) // All Galileo MSM - { - rtcm_msg_rate_ms[k] = rtcm_MSM_rate_ms; - } - - // make PVT object - pvt_ = galileo_e1_make_pvt_cc(in_streams_, - dump_, - dump_filename_, - averaging_depth, - flag_averaging, - output_rate_ms, - display_rate_ms, - flag_nmea_tty_port, - nmea_dump_filename, - nmea_dump_devname, - flag_rtcm_server, - flag_rtcm_tty_port, - rtcm_tcp_port, - rtcm_station_id, - rtcm_msg_rate_ms, - rtcm_dump_devname); - - DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")"; -} - - -GalileoE1Pvt::~GalileoE1Pvt() -{} - - -void GalileoE1Pvt::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - -void GalileoE1Pvt::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - -gr::basic_block_sptr GalileoE1Pvt::get_left_block() -{ - return pvt_; -} - - -gr::basic_block_sptr GalileoE1Pvt::get_right_block() -{ - return pvt_; -} - diff --git a/src/algorithms/PVT/adapters/gps_l1_ca_pvt.cc b/src/algorithms/PVT/adapters/gps_l1_ca_pvt.cc deleted file mode 100644 index ba244b5ae..000000000 --- a/src/algorithms/PVT/adapters/gps_l1_ca_pvt.cc +++ /dev/null @@ -1,250 +0,0 @@ -/*! - * \file gps_l1_ca_pvt.cc - * \brief Implementation of an adapter of a GPS L1 C/A PVT solver block to a - * PvtInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "gps_l1_ca_pvt.h" -#include -#include -#include -#include -#include -#include "configuration_interface.h" - -using google::LogMessage; - -GpsL1CaPvt::GpsL1CaPvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - // dump parameters - std::string default_dump_filename = "./pvt.dat"; - std::string default_nmea_dump_filename = "./nmea_pvt.nmea"; - std::string default_nmea_dump_devname = "/dev/tty1"; - std::string default_rtcm_dump_devname = "/dev/pts/1"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - // moving average depth parameters - int averaging_depth = configuration->property(role + ".averaging_depth", 10); - bool flag_averaging = configuration->property(role + ".flag_averaging", false); - - // output rate - int output_rate_ms = configuration->property(role + ".output_rate_ms", 500); - - // display rate - int display_rate_ms = configuration->property(role + ".display_rate_ms", 500); - - // NMEA Printer settings - bool flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false); - std::string nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename); - std::string nmea_dump_devname = configuration->property(role + ".nmea_dump_devname", default_nmea_dump_devname); - - // RTCM Printer settings - bool flag_rtcm_tty_port = configuration->property(role + ".flag_rtcm_tty_port", false); - std::string rtcm_dump_devname = configuration->property(role + ".rtcm_dump_devname", default_rtcm_dump_devname); - bool flag_rtcm_server = configuration->property(role + ".flag_rtcm_server", false); - unsigned short rtcm_tcp_port = configuration->property(role + ".rtcm_tcp_port", 2101); - unsigned short rtcm_station_id = configuration->property(role + ".rtcm_station_id", 1234); - // RTCM message rates: least common multiple with output_rate_ms - int rtcm_MT1019_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1019_rate_ms", 5000), output_rate_ms); - int rtcm_MSM_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MSM_rate_ms", 1000), output_rate_ms); - std::map rtcm_msg_rate_ms; - rtcm_msg_rate_ms[1019] = rtcm_MT1019_rate_ms; - for (int k = 1071; k < 1078; k++) // All GPS MSM - { - rtcm_msg_rate_ms[k] = rtcm_MSM_rate_ms; - } - - // getting names from the config file, if available - // default filename for assistance data - const std::string eph_default_xml_filename = "./gps_ephemeris.xml"; - eph_xml_filename_= configuration->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename); - - //const std::string utc_default_xml_filename = "./gps_utc_model.xml"; - //const std::string iono_default_xml_filename = "./gps_iono.xml"; - //const std::string ref_time_default_xml_filename = "./gps_ref_time.xml"; - //const std::string ref_location_default_xml_filename = "./gps_ref_location.xml"; - - //std::string utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_utc_model.xml", utc_default_xml_filename); - //std::string iono_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_iono_xml", iono_default_xml_filename); - //std::string ref_time_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_time_xml", ref_time_default_xml_filename); - //std::string ref_location_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_location_xml", ref_location_default_xml_filename); - - // RINEX version - int conf_rinex_version; - conf_rinex_version = configuration->property(role + ".rinex_version", 0); - - // make PVT object - pvt_ = gps_l1_ca_make_pvt_cc(in_streams_, - dump_, - dump_filename_, - averaging_depth, - flag_averaging, - output_rate_ms, - display_rate_ms, - flag_nmea_tty_port, - nmea_dump_filename, - nmea_dump_devname, - flag_rtcm_server, - flag_rtcm_tty_port, - rtcm_tcp_port, - rtcm_station_id, - rtcm_msg_rate_ms, - rtcm_dump_devname, - conf_rinex_version ); - - DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")"; -} - - -bool GpsL1CaPvt::save_assistance_to_XML() -{ - // return variable (true == succeeded) - bool ret = false; - - LOG(INFO) << "SUPL: Try to save GPS ephemeris to XML file " << eph_xml_filename_; - std::map eph_map = pvt_->get_GPS_L1_ephemeris_map(); - - if (eph_map.size() > 0) - { - try - { - std::ofstream ofs(eph_xml_filename_.c_str(), std::ofstream::trunc | std::ofstream::out); - boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", eph_map); - ofs.close(); - LOG(INFO) << "Saved GPS L1 Ephemeris map data"; - } - catch (std::exception& e) - { - LOG(WARNING) << e.what(); - return false; - } - return true; - } - else - { - LOG(WARNING) << "Failed to save Ephemeris, map is empty"; - return false; - } - // Only try to save {utc, iono, ref time, ref location} if SUPL is enabled - // bool enable_gps_supl_assistance = configuration_->property("GNSS-SDR.SUPL_gps_enabled", false); - // if (enable_gps_supl_assistance == true) - // { - // // try to save utc model xml file - // std::map utc_copy = global_gps_utc_model_map.get_map_copy(); - // if (supl_client_acquisition_.save_utc_map_xml(utc_xml_filename, utc_copy) == true) - // { - // LOG(INFO) << "SUPL: Successfully saved UTC Model XML file"; - // //ret = true; - // } - // else - // { - // LOG(INFO) << "SUPL: Error while trying to save utc XML file"; - // //ret = false; - // } - // // try to save iono model xml file - // std::map iono_copy = global_gps_iono_map.get_map_copy(); - // if (supl_client_acquisition_.save_iono_map_xml(iono_xml_filename, iono_copy) == true) - // { - // LOG(INFO) << "SUPL: Successfully saved IONO Model XML file"; - // //ret = true; - // } - // else - // { - // LOG(INFO) << "SUPL: Error while trying to save iono XML file"; - // //ret = false; - // } - // // try to save ref time xml file - // std::map ref_time_copy = global_gps_ref_time_map.get_map_copy(); - // if (supl_client_acquisition_.save_ref_time_map_xml(ref_time_xml_filename, ref_time_copy) == true) - // { - // LOG(INFO) << "SUPL: Successfully saved Ref Time XML file"; - // //ret = true; - // } - // else - // { - // LOG(INFO) << "SUPL: Error while trying to save ref time XML file"; - // //ref = false; - // } - // // try to save ref location xml file - // std::map ref_location_copy = global_gps_ref_location_map.get_map_copy(); - // if (supl_client_acquisition_.save_ref_location_map_xml(ref_location_xml_filename, ref_location_copy) == true) - // { - // LOG(INFO) << "SUPL: Successfully saved Ref Location XML file"; - // //ref = true; - // } - // else - // { - // LOG(INFO) << "SUPL: Error while trying to save ref location XML file"; - // //ret = false; - // } - // } - return ret; -} - - -GpsL1CaPvt::~GpsL1CaPvt() -{ - save_assistance_to_XML(); -} - - -void GpsL1CaPvt::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - -void GpsL1CaPvt::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - - -gr::basic_block_sptr GpsL1CaPvt::get_left_block() -{ - return pvt_; -} - - -gr::basic_block_sptr GpsL1CaPvt::get_right_block() -{ - return pvt_; -} diff --git a/src/algorithms/PVT/adapters/gps_l1_ca_pvt.h b/src/algorithms/PVT/adapters/gps_l1_ca_pvt.h deleted file mode 100644 index 4787f94bd..000000000 --- a/src/algorithms/PVT/adapters/gps_l1_ca_pvt.h +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * \file gps_l1_ca_pvt.h - * \brief Interface of an adapter of a GPS L1 C/A PVT solver block to a - * PvtInterface - * Position Velocity and Time - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - - -#ifndef GNSS_SDR_GPS_L1_CA_PVT_H_ -#define GNSS_SDR_GPS_L1_CA_PVT_H_ - -#include -#include "pvt_interface.h" -#include "gps_l1_ca_pvt_cc.h" - - -class ConfigurationInterface; - -/*! - * \brief This class implements a PvtInterface for GPS L1 C/A - */ -class GpsL1CaPvt : public PvtInterface -{ -public: - GpsL1CaPvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - - virtual ~GpsL1CaPvt(); - - std::string role() - { - return role_; - } - - //! Returns "GPS_L1_CA_PVT" - std::string implementation() - { - return "GPS_L1_CA_PVT"; - } - - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation. Returns sizeof(gr_complex) - size_t item_size() - { - return sizeof(gr_complex); - } - -private: - gps_l1_ca_pvt_cc_sptr pvt_; - bool dump_; - std::string dump_filename_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; - - std::string eph_xml_filename_; - bool save_assistance_to_XML(); -}; - -#endif diff --git a/src/algorithms/PVT/adapters/hybrid_pvt.cc b/src/algorithms/PVT/adapters/hybrid_pvt.cc deleted file mode 100644 index 98b7a3836..000000000 --- a/src/algorithms/PVT/adapters/hybrid_pvt.cc +++ /dev/null @@ -1,237 +0,0 @@ -/*! - * \file hybrid_pvt.cc - * \brief Implementation of an adapter of a GALILEO E1 PVT solver block to a - * PvtInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "hybrid_pvt.h" -#include -#include -#include -#include -#include -#include "configuration_interface.h" - - -using google::LogMessage; - -HybridPvt::HybridPvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - // dump parameters - std::string default_dump_filename = "./pvt.dat"; - std::string default_nmea_dump_filename = "./nmea_pvt.nmea"; - std::string default_nmea_dump_devname = "/dev/tty1"; - std::string default_rtcm_dump_devname = "/dev/pts/1"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - - // moving average depth parameters - int averaging_depth = configuration->property(role + ".averaging_depth", 10); - bool flag_averaging = configuration->property(role + ".flag_averaging", false); - - // output rate - int output_rate_ms = configuration->property(role + ".output_rate_ms", 500); - - // display rate - int display_rate_ms = configuration->property(role + ".display_rate_ms", 500); - - // NMEA Printer settings - bool flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false); - std::string nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename); - std::string nmea_dump_devname = configuration->property(role + ".nmea_dump_devname", default_nmea_dump_devname); - - // RTCM Printer settings - bool flag_rtcm_tty_port = configuration->property(role + ".flag_rtcm_tty_port", false); - std::string rtcm_dump_devname = configuration->property(role + ".rtcm_dump_devname", default_rtcm_dump_devname); - bool flag_rtcm_server = configuration->property(role + ".flag_rtcm_server", false); - unsigned short rtcm_tcp_port = configuration->property(role + ".rtcm_tcp_port", 2101); - unsigned short rtcm_station_id = configuration->property(role + ".rtcm_station_id", 1234); - // RTCM message rates: least common multiple with output_rate_ms - int rtcm_MT1019_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1019_rate_ms", 5000), output_rate_ms); - int rtcm_MT1045_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1045_rate_ms", 5000), output_rate_ms); - int rtcm_MSM_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MSM_rate_ms", 1000), output_rate_ms); - int rtcm_MT1077_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1077_rate_ms", rtcm_MSM_rate_ms), output_rate_ms); - int rtcm_MT1097_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1097_rate_ms", rtcm_MSM_rate_ms), output_rate_ms); - std::map rtcm_msg_rate_ms; - rtcm_msg_rate_ms[1019] = rtcm_MT1019_rate_ms; - rtcm_msg_rate_ms[1045] = rtcm_MT1045_rate_ms; - for (int k = 1071; k < 1078; k++) // All GPS MSM - { - rtcm_msg_rate_ms[k] = rtcm_MT1077_rate_ms; - } - for (int k = 1091; k < 1098; k++) // All Galileo MSM - { - rtcm_msg_rate_ms[k] = rtcm_MT1097_rate_ms; - } - // getting names from the config file, if available - // default filename for assistance data - const std::string eph_default_xml_filename = "./gps_ephemeris.xml"; - const std::string utc_default_xml_filename = "./gps_utc_model.xml"; - const std::string iono_default_xml_filename = "./gps_iono.xml"; - const std::string ref_time_default_xml_filename = "./gps_ref_time.xml"; - const std::string ref_location_default_xml_filename = "./gps_ref_location.xml"; - eph_xml_filename_ = configuration->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename); - //std::string utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_utc_model.xml", utc_default_xml_filename); - //std::string iono_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_iono_xml", iono_default_xml_filename); - //std::string ref_time_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_time_xml", ref_time_default_xml_filename); - //std::string ref_location_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_location_xml", ref_location_default_xml_filename); - - // Infer the type of receiver - /* - * TYPE | RECEIVER - * 0 | Unknown - * 1 | GPS L1 C/A - * 2 | GPS L2C - * 3 | GPS L5 - * 4 | Galileo E1B - * 5 | Galileo E5a - * 6 | Galileo E5b - * 7 | GPS L1 C/A + GPS L2C - * 8 | GPS L1 C/A + GPS L5 - * 9 | GPS L1 C/A + Galileo E1B - * 10 | GPS L1 C/A + Galileo E5a - * 11 | GPS L1 C/A + Galileo E5b - * 12 | Galileo E1B + GPS L2C - * 13 | Galileo E1B + GPS L5 - * 14 | Galileo E1B + Galileo E5a - * 15 | Galileo E1B + Galileo E5b - * 16 | GPS L2C + GPS L5 - * 17 | GPS L2C + Galileo E5a - * 18 | GPS L2C + Galileo E5b - * 19 | GPS L5 + Galileo E5a - * 20 | GPS L5 + Galileo E5b - * 21 | GPS L1 C/A + Galileo E1B + GPS L2C - * 22 | GPS L1 C/A + Galileo E1B + GPS L5 - */ - int gps_1C_count = configuration->property("Channels_1C.count", 0); - int gps_2S_count = configuration->property("Channels_2S.count", 0); - int gal_1B_count = configuration->property("Channels_1B.count", 0); - int gal_E5a_count = configuration->property("Channels_5X.count", 0); // GPS L5 or Galileo E5a ? - int gal_E5b_count = configuration->property("Channels_7X.count", 0); - - unsigned int type_of_receiver = 0; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 1; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 2; - - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 4; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 5; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 6; - - if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 7; - //if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 8; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 9; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 10; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 11; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 12; - //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 13; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 14; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 15; - //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 16; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 17; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 18; - //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 19; - //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 20; - if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 21; - //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count = 0)) type_of_receiver = 22; - - // make PVT object - pvt_ = hybrid_make_pvt_cc(in_streams_, dump_, dump_filename_, averaging_depth, flag_averaging, output_rate_ms, display_rate_ms, flag_nmea_tty_port, nmea_dump_filename, nmea_dump_devname, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_msg_rate_ms, rtcm_dump_devname, type_of_receiver); - DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")"; -} - - -bool HybridPvt::save_assistance_to_XML() -{ - LOG(INFO) << "SUPL: Try to save GPS ephemeris to XML file " << eph_xml_filename_; - std::map eph_map = pvt_->get_GPS_L1_ephemeris_map(); - - if (eph_map.size() > 0) - { - try - { - std::ofstream ofs(eph_xml_filename_.c_str(), std::ofstream::trunc | std::ofstream::out); - boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", eph_map); - ofs.close(); - LOG(INFO) << "Saved GPS L1 Ephemeris map data"; - } - catch (std::exception& e) - { - LOG(WARNING) << e.what(); - return false; - } - return true; // return variable (true == succeeded) - } - else - { - LOG(WARNING) << "Failed to save Ephemeris, map is empty"; - return false; - } -} - - -HybridPvt::~HybridPvt() -{ - save_assistance_to_XML(); -} - - -void HybridPvt::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - -void HybridPvt::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - - -gr::basic_block_sptr HybridPvt::get_left_block() -{ - return pvt_; -} - - -gr::basic_block_sptr HybridPvt::get_right_block() -{ - return pvt_; // this is a sink, nothing downstream -} diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc new file mode 100644 index 000000000..cd9ecbd26 --- /dev/null +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -0,0 +1,595 @@ +/*! + * \file rtklib_pvt.cc + * \brief Interface of a Position Velocity and Time computation block + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "rtklib_pvt.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "pvt_conf.h" +#include +#include +#include +#include +#if OLD_BOOST +#include +namespace bc = boost::math; +#else +#include +namespace bc = boost::integer; +#endif + + +using google::LogMessage; + + +RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(std::move(role)), + in_streams_(in_streams), + out_streams_(out_streams) +{ + Pvt_Conf pvt_output_parameters = Pvt_Conf(); + // dump parameters + std::string default_dump_filename = "./pvt.dat"; + std::string default_nmea_dump_filename = "./nmea_pvt.nmea"; + std::string default_nmea_dump_devname = "/dev/tty1"; + std::string default_rtcm_dump_devname = "/dev/pts/1"; + DLOG(INFO) << "role " << role; + pvt_output_parameters.dump = configuration->property(role + ".dump", false); + pvt_output_parameters.dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + pvt_output_parameters.dump_mat = configuration->property(role + ".dump_mat", true); + + // output rate + pvt_output_parameters.output_rate_ms = configuration->property(role + ".output_rate_ms", 500); + + // display rate + pvt_output_parameters.display_rate_ms = configuration->property(role + ".display_rate_ms", 500); + + // NMEA Printer settings + pvt_output_parameters.flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false); + pvt_output_parameters.nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename); + std::string nmea_dump_devname = configuration->property(role + ".nmea_dump_devname", default_nmea_dump_devname); + + // RINEX version + pvt_output_parameters.rinex_version = configuration->property(role + ".rinex_version", 3); + if (FLAGS_RINEX_version == "3.01") + { + pvt_output_parameters.rinex_version = 3; + } + else if (FLAGS_RINEX_version == "3.02") + { + pvt_output_parameters.rinex_version = 3; + } + else if (FLAGS_RINEX_version == "3") + { + pvt_output_parameters.rinex_version = 3; + } + else if (FLAGS_RINEX_version == "2.11") + { + pvt_output_parameters.rinex_version = 2; + } + else if (FLAGS_RINEX_version == "2.10") + { + pvt_output_parameters.rinex_version = 2; + } + else if (FLAGS_RINEX_version == "2") + { + pvt_output_parameters.rinex_version = 2; + } + pvt_output_parameters.rinexobs_rate_ms = bc::lcm(configuration->property(role + ".rinexobs_rate_ms", 1000), pvt_output_parameters.output_rate_ms); + pvt_output_parameters.rinexnav_rate_ms = bc::lcm(configuration->property(role + ".rinexnav_rate_ms", 6000), pvt_output_parameters.output_rate_ms); + + // RTCM Printer settings + pvt_output_parameters.flag_rtcm_tty_port = configuration->property(role + ".flag_rtcm_tty_port", false); + pvt_output_parameters.rtcm_dump_devname = configuration->property(role + ".rtcm_dump_devname", default_rtcm_dump_devname); + pvt_output_parameters.flag_rtcm_server = configuration->property(role + ".flag_rtcm_server", false); + pvt_output_parameters.rtcm_tcp_port = configuration->property(role + ".rtcm_tcp_port", 2101); + pvt_output_parameters.rtcm_station_id = configuration->property(role + ".rtcm_station_id", 1234); + // RTCM message rates: least common multiple with output_rate_ms + int rtcm_MT1019_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1019_rate_ms", 5000), pvt_output_parameters.output_rate_ms); + int rtcm_MT1020_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1020_rate_ms", 5000), pvt_output_parameters.output_rate_ms); + int rtcm_MT1045_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1045_rate_ms", 5000), pvt_output_parameters.output_rate_ms); + int rtcm_MSM_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MSM_rate_ms", 1000), pvt_output_parameters.output_rate_ms); + int rtcm_MT1077_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1077_rate_ms", rtcm_MSM_rate_ms), pvt_output_parameters.output_rate_ms); + int rtcm_MT1087_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1087_rate_ms", rtcm_MSM_rate_ms), pvt_output_parameters.output_rate_ms); + int rtcm_MT1097_rate_ms = bc::lcm(configuration->property(role + ".rtcm_MT1097_rate_ms", rtcm_MSM_rate_ms), pvt_output_parameters.output_rate_ms); + //std::map rtcm_msg_rate_ms; + pvt_output_parameters.rtcm_msg_rate_ms[1019] = rtcm_MT1019_rate_ms; + pvt_output_parameters.rtcm_msg_rate_ms[1020] = rtcm_MT1020_rate_ms; + pvt_output_parameters.rtcm_msg_rate_ms[1045] = rtcm_MT1045_rate_ms; + for (int k = 1071; k < 1078; k++) // All GPS MSM + { + pvt_output_parameters.rtcm_msg_rate_ms[k] = rtcm_MT1077_rate_ms; + } + for (int k = 1081; k < 1088; k++) // All GLONASS MSM + { + pvt_output_parameters.rtcm_msg_rate_ms[k] = rtcm_MT1087_rate_ms; + } + for (int k = 1091; k < 1098; k++) // All Galileo MSM + { + pvt_output_parameters.rtcm_msg_rate_ms[k] = rtcm_MT1097_rate_ms; + } + + // Infer the type of receiver + /* + * TYPE | RECEIVER + * 0 | Unknown + * 1 | GPS L1 C/A + * 2 | GPS L2C + * 3 | GPS L5 + * 4 | Galileo E1B + * 5 | Galileo E5a + * 6 | Galileo E5b + * 7 | GPS L1 C/A + GPS L2C + * 8 | GPS L1 C/A + GPS L5 + * 9 | GPS L1 C/A + Galileo E1B + * 10 | GPS L1 C/A + Galileo E5a + * 11 | GPS L1 C/A + Galileo E5b + * 12 | Galileo E1B + GPS L2C + * 13 | Galileo E1B + GPS L5 + * 14 | Galileo E1B + Galileo E5a + * 15 | Galileo E1B + Galileo E5b + * 16 | GPS L2C + GPS L5 + * 17 | GPS L2C + Galileo E5a + * 18 | GPS L2C + Galileo E5b + * 19 | GPS L5 + Galileo E5a + * 20 | GPS L5 + Galileo E5b + * 21 | GPS L1 C/A + Galileo E1B + GPS L2C + * 22 | GPS L1 C/A + Galileo E1B + GPS L5 + * 23 | GLONASS L1 C/A + * 24 | GLONASS L2 C/A + * 25 | GLONASS L1 C/A + GLONASS L2 C/A + * 26 | GPS L1 C/A + GLONASS L1 C/A + * 27 | Galileo E1B + GLONASS L1 C/A + * 28 | GPS L2C + GLONASS L1 C/A + */ + int gps_1C_count = configuration->property("Channels_1C.count", 0); + int gps_2S_count = configuration->property("Channels_2S.count", 0); + int gps_L5_count = configuration->property("Channels_L5.count", 0); + int gal_1B_count = configuration->property("Channels_1B.count", 0); + int gal_E5a_count = configuration->property("Channels_5X.count", 0); + int gal_E5b_count = configuration->property("Channels_7X.count", 0); + int glo_1G_count = configuration->property("Channels_1G.count", 0); + int glo_2G_count = configuration->property("Channels_2G.count", 0); + + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 1; // L1 + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 2; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 3; // L5 + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 4; // E1 + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 5; // E5a + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 6; + + if ((gps_1C_count != 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 7; + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 8; // L1+L5 + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 9; // L1+E1 + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 10; + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 11; + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 12; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count != 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 13; // L5+E5a + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 14; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 15; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) pvt_output_parameters.type_of_receiver = 16; + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 17; + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 18; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) pvt_output_parameters.type_of_receiver = 19; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) pvt_output_parameters.type_of_receiver = 20; + if ((gps_1C_count != 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 21; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count = 0)) pvt_output_parameters.type_of_receiver = 22; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0)) pvt_output_parameters.type_of_receiver = 23; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count != 0)) pvt_output_parameters.type_of_receiver = 24; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0) && (glo_2G_count != 0)) pvt_output_parameters.type_of_receiver = 25; + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 26; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 27; + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 28; + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count != 0)) pvt_output_parameters.type_of_receiver = 29; + if ((gps_1C_count == 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count != 0)) pvt_output_parameters.type_of_receiver = 30; + if ((gps_1C_count == 0) && (gps_2S_count != 0) && (gps_L5_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count != 0)) pvt_output_parameters.type_of_receiver = 31; + + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count != 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 32; // L1+E1+L5+E5a + if ((gps_1C_count != 0) && (gps_2S_count == 0) && (gps_L5_count == 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2G_count == 0)) pvt_output_parameters.type_of_receiver = 33; // L1+E1+E5a + + // RTKLIB PVT solver options + // Settings 1 + int positioning_mode = -1; + std::string default_pos_mode("Single"); + std::string positioning_mode_str = configuration->property(role + ".positioning_mode", default_pos_mode); // (PMODE_XXX) see src/algorithms/libs/rtklib/rtklib.h + if (positioning_mode_str == "Single") positioning_mode = PMODE_SINGLE; + if (positioning_mode_str == "Static") positioning_mode = PMODE_STATIC; + if (positioning_mode_str == "Kinematic") positioning_mode = PMODE_KINEMA; + if (positioning_mode_str == "PPP_Static") positioning_mode = PMODE_PPP_STATIC; + if (positioning_mode_str == "PPP_Kinematic") positioning_mode = PMODE_PPP_KINEMA; + + if (positioning_mode == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of positioning mode." << std::endl; + std::cout << "positioning_mode possible values: Single / Static / Kinematic / PPP_Static / PPP_Kinematic" << std::endl; + std::cout << "positioning_mode specified value: " << positioning_mode_str << std::endl; + std::cout << "Setting positioning_mode to Single" << std::endl; + positioning_mode = PMODE_SINGLE; + } + + int num_bands = 0; + + if ((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) num_bands = 1; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gps_2S_count > 0) || (glo_2G_count > 0))) num_bands = 2; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0) || (gps_L5_count > 0))) num_bands = 2; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gps_2S_count > 0) || (glo_2G_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0) || (gps_L5_count > 0))) num_bands = 3; + + int number_of_frequencies = configuration->property(role + ".num_bands", num_bands); /* (1:L1, 2:L1+L2, 3:L1+L2+L5) */ + if ((number_of_frequencies < 1) || (number_of_frequencies > 3)) + { + //warn user and set the default + number_of_frequencies = num_bands; + } + + double elevation_mask = configuration->property(role + ".elevation_mask", 15.0); + if ((elevation_mask < 0.0) || (elevation_mask > 90.0)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Elevation Mask. Setting to default value of 15.0 degrees"; + elevation_mask = 15.0; + } + + int dynamics_model = configuration->property(role + ".dynamics_model", 0); /* dynamics model (0:none, 1:velocity, 2:accel) */ + if ((dynamics_model < 0) || (dynamics_model > 2)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Dynamics Model configuration. Setting to default value of (0:none)"; + dynamics_model = 0; + } + + std::string default_iono_model("OFF"); + std::string iono_model_str = configuration->property(role + ".iono_model", default_iono_model); /* (IONOOPT_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + int iono_model = -1; + if (iono_model_str == "OFF") iono_model = IONOOPT_OFF; + if (iono_model_str == "Broadcast") iono_model = IONOOPT_BRDC; + if (iono_model_str == "SBAS") iono_model = IONOOPT_SBAS; + if (iono_model_str == "Iono-Free-LC") iono_model = IONOOPT_IFLC; + if (iono_model_str == "Estimate_STEC") iono_model = IONOOPT_EST; + if (iono_model_str == "IONEX") iono_model = IONOOPT_TEC; + if (iono_model == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of ionospheric model." << std::endl; + std::cout << "iono_model possible values: OFF / Broadcast / SBAS / Iono-Free-LC / Estimate_STEC / IONEX" << std::endl; + std::cout << "iono_model specified value: " << iono_model_str << std::endl; + std::cout << "Setting iono_model to OFF" << std::endl; + iono_model = IONOOPT_OFF; /* 0: ionosphere option: correction off */ + } + + std::string default_trop_model("OFF"); + int trop_model = -1; + std::string trop_model_str = configuration->property(role + ".trop_model", default_trop_model); /* (TROPOPT_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + if (trop_model_str == "OFF") trop_model = TROPOPT_OFF; + if (trop_model_str == "Saastamoinen") trop_model = TROPOPT_SAAS; + if (trop_model_str == "SBAS") trop_model = TROPOPT_SBAS; + if (trop_model_str == "Estimate_ZTD") trop_model = TROPOPT_EST; + if (trop_model_str == "Estimate_ZTD_Grad") trop_model = TROPOPT_ESTG; + if (trop_model == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of tropospheric model." << std::endl; + std::cout << "trop_model possible values: OFF / Saastamoinen / SBAS / Estimate_ZTD / Estimate_ZTD_Grad" << std::endl; + std::cout << "trop_model specified value: " << trop_model_str << std::endl; + std::cout << "Setting trop_model to OFF" << std::endl; + trop_model = TROPOPT_OFF; + } + + /* RTKLIB positioning options */ + int sat_PCV = 0; /* Set whether the satellite antenna PCV (phase center variation) model is used or not. This feature requires a Satellite Antenna PCV File. */ + int rec_PCV = 0; /* Set whether the receiver antenna PCV (phase center variation) model is used or not. This feature requires a Receiver Antenna PCV File. */ + + /* Set whether the phase windup correction for PPP modes is applied or not. Only applicable to PPP‐* modes.*/ + int phwindup = configuration->property(role + ".phwindup", 0); + + /* Set whether the GPS Block IIA satellites in eclipse are excluded or not. + The eclipsing Block IIA satellites often degrade the PPP solutions due to unpredicted behavior of yaw‐attitude. Only applicable to PPP‐* modes.*/ + int reject_GPS_IIA = configuration->property(role + ".reject_GPS_IIA", 0); + + /* Set whether RAIM (receiver autonomous integrity monitoring) FDE (fault detection and exclusion) feature is enabled or not. + In case of RAIM FDE enabled, a satellite is excluded if SSE (sum of squared errors) of residuals is over a threshold. + The excluded satellite is selected to indicate the minimum SSE. */ + int raim_fde = configuration->property(role + ".raim_fde", 0); + + int earth_tide = configuration->property(role + ".earth_tide", 0); + + int nsys = 0; + if ((gps_1C_count > 0) || (gps_2S_count > 0) || (gps_L5_count > 0)) nsys += SYS_GPS; + if ((gal_1B_count > 0) || (gal_E5a_count > 0) || (gal_E5b_count > 0)) nsys += SYS_GAL; + if ((glo_1G_count > 0) || (glo_2G_count > 0)) nsys += SYS_GLO; + int navigation_system = configuration->property(role + ".navigation_system", nsys); /* (SYS_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + if ((navigation_system < 1) || (navigation_system > 255)) /* GPS: 1 SBAS: 2 GPS+SBAS: 3 Galileo: 8 Galileo+GPS: 9 GPS+SBAS+Galileo: 11 All: 255 */ + { + //warn user and set the default + LOG(WARNING) << "Erroneous Navigation System. Setting to default value of (0:none)"; + navigation_system = nsys; + } + + // Settings 2 + std::string default_gps_ar("Continuous"); + std::string integer_ambiguity_resolution_gps_str = configuration->property(role + ".AR_GPS", default_gps_ar); /* Integer Ambiguity Resolution mode for GPS (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + int integer_ambiguity_resolution_gps = -1; + if (integer_ambiguity_resolution_gps_str == "OFF") integer_ambiguity_resolution_gps = ARMODE_OFF; + if (integer_ambiguity_resolution_gps_str == "Continuous") integer_ambiguity_resolution_gps = ARMODE_CONT; + if (integer_ambiguity_resolution_gps_str == "Instantaneous") integer_ambiguity_resolution_gps = ARMODE_INST; + if (integer_ambiguity_resolution_gps_str == "Fix-and-Hold") integer_ambiguity_resolution_gps = ARMODE_FIXHOLD; + if (integer_ambiguity_resolution_gps_str == "PPP-AR") integer_ambiguity_resolution_gps = ARMODE_PPPAR; + if (integer_ambiguity_resolution_gps == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of GPS ambiguity resolution method." << std::endl; + std::cout << "AR_GPS possible values: OFF / Continuous / Instantaneous / Fix-and-Hold / PPP-AR" << std::endl; + std::cout << "AR_GPS specified value: " << integer_ambiguity_resolution_gps_str << std::endl; + std::cout << "Setting AR_GPS to OFF" << std::endl; + integer_ambiguity_resolution_gps = ARMODE_OFF; + } + + int integer_ambiguity_resolution_glo = configuration->property(role + ".AR_GLO", 1); /* Integer Ambiguity Resolution mode for GLONASS (0:off,1:on,2:auto cal,3:ext cal) */ + if ((integer_ambiguity_resolution_glo < 0) || (integer_ambiguity_resolution_glo > 3)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for GLONASS . Setting to default value of (1:on)"; + integer_ambiguity_resolution_glo = 1; + } + + int integer_ambiguity_resolution_bds = configuration->property(role + ".AR_DBS", 1); /* Integer Ambiguity Resolution mode for BEIDOU (0:off,1:on) */ + if ((integer_ambiguity_resolution_bds < 0) || (integer_ambiguity_resolution_bds > 1)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for BEIDOU . Setting to default value of (1:on)"; + integer_ambiguity_resolution_bds = 1; + } + + double min_ratio_to_fix_ambiguity = configuration->property(role + ".min_ratio_to_fix_ambiguity", 3.0); /* Set the integer ambiguity validation threshold for ratio‐test, + which uses the ratio of squared residuals of the best integer vector to the second‐best vector. */ + + int min_lock_to_fix_ambiguity = configuration->property(role + ".min_lock_to_fix_ambiguity", 0); /* Set the minimum lock count to fix integer ambiguity.FLAGS_RINEX_version. + If the lock count is less than the value, the ambiguity is excluded from the fixed integer vector. */ + + double min_elevation_to_fix_ambiguity = configuration->property(role + ".min_elevation_to_fix_ambiguity", 0.0); /* Set the minimum elevation (deg) to fix integer ambiguity. + If the elevation of the satellite is less than the value, the ambiguity is excluded from the fixed integer vector. */ + + int outage_reset_ambiguity = configuration->property(role + ".outage_reset_ambiguity", 5); /* Set the outage count to reset ambiguity. If the data outage count is over the value, the estimated ambiguity is reset to the initial value. */ + + double slip_threshold = configuration->property(role + ".slip_threshold", 0.05); /* set the cycle‐slip threshold (m) of geometry‐free LC carrier‐phase difference between epochs */ + + double threshold_reject_gdop = configuration->property(role + ".threshold_reject_gdop", 30.0); /* reject threshold of GDOP. If the GDOP is over the value, the observable is excluded for the estimation process as an outlier. */ + + double threshold_reject_innovation = configuration->property(role + ".threshold_reject_innovation", 30.0); /* reject threshold of innovation (m). If the innovation is over the value, the observable is excluded for the estimation process as an outlier. */ + + int number_filter_iter = configuration->property(role + ".number_filter_iter", 1); /* Set the number of iteration in the measurement update of the estimation filter. + If the baseline length is very short like 1 m, the iteration may be effective to handle + the nonlinearity of measurement equation. */ + + /// Statistics + double bias_0 = configuration->property(role + ".bias_0", 30.0); + + double iono_0 = configuration->property(role + ".iono_0", 0.03); + + double trop_0 = configuration->property(role + ".trop_0", 0.3); + + double sigma_bias = configuration->property(role + ".sigma_bias", 1e-4); /* Set the process noise standard deviation of carrier‐phase + bias (ambiguity) (cycle/sqrt(s)) */ + + double sigma_iono = configuration->property(role + ".sigma_iono", 1e-3); /* Set the process noise standard deviation of vertical ionospheric delay per 10 km baseline (m/sqrt(s)). */ + + double sigma_trop = configuration->property(role + ".sigma_trop", 1e-4); /* Set the process noise standard deviation of zenith tropospheric delay (m/sqrt(s)). */ + + double sigma_acch = configuration->property(role + ".sigma_acch", 1e-1); /* Set the process noise standard deviation of the receiver acceleration as + the horizontal component. (m/s2/sqrt(s)). If Receiver Dynamics is set to OFF, they are not used. */ + + double sigma_accv = configuration->property(role + ".sigma_accv", 1e-2); /* Set the process noise standard deviation of the receiver acceleration as + the vertical component. (m/s2/sqrt(s)). If Receiver Dynamics is set to OFF, they are not used. */ + + double sigma_pos = configuration->property(role + ".sigma_pos", 0.0); + + double code_phase_error_ratio_l1 = configuration->property(role + ".code_phase_error_ratio_l1", 100.0); + double code_phase_error_ratio_l2 = configuration->property(role + ".code_phase_error_ratio_l2", 100.0); + double code_phase_error_ratio_l5 = configuration->property(role + ".code_phase_error_ratio_l5", 100.0); + double carrier_phase_error_factor_a = configuration->property(role + ".carrier_phase_error_factor_a", 0.003); + double carrier_phase_error_factor_b = configuration->property(role + ".carrier_phase_error_factor_b", 0.003); + + snrmask_t snrmask = {{}, {{}, {}}}; + + prcopt_t rtklib_configuration_options = { + positioning_mode, /* positioning mode (PMODE_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + 0, /* solution type (0:forward,1:backward,2:combined) */ + number_of_frequencies, /* number of frequencies (1:L1, 2:L1+L2, 3:L1+L2+L5)*/ + navigation_system, /* navigation system */ + elevation_mask * D2R, /* elevation mask angle (degrees) */ + snrmask, /* snrmask_t snrmask SNR mask */ + 0, /* satellite ephemeris/clock (EPHOPT_XXX) */ + integer_ambiguity_resolution_gps, /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + integer_ambiguity_resolution_glo, /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */ + integer_ambiguity_resolution_bds, /* BeiDou AR mode (0:off,1:on) */ + outage_reset_ambiguity, /* obs outage count to reset bias */ + min_lock_to_fix_ambiguity, /* min lock count to fix ambiguity */ + 10, /* min fix count to hold ambiguity */ + 1, /* max iteration to resolve ambiguity */ + iono_model, /* ionosphere option (IONOOPT_XXX) */ + trop_model, /* troposphere option (TROPOPT_XXX) */ + dynamics_model, /* dynamics model (0:none, 1:velocity, 2:accel) */ + earth_tide, /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */ + number_filter_iter, /* number of filter iteration */ + 0, /* code smoothing window size (0:none) */ + 0, /* interpolate reference obs (for post mission) */ + 0, /* sbssat_t sbssat SBAS correction options */ + 0, /* sbsion_t sbsion[MAXBAND+1] SBAS satellite selection (0:all) */ + 0, /* rover position for fixed mode */ + 0, /* base position for relative mode */ + /* 0:pos in prcopt, 1:average of single pos, */ + /* 2:read from file, 3:rinex header, 4:rtcm pos */ + {code_phase_error_ratio_l1, code_phase_error_ratio_l2, code_phase_error_ratio_l5}, /* eratio[NFREQ] code/phase error ratio */ + {100.0, carrier_phase_error_factor_a, carrier_phase_error_factor_b, 0.0, 1.0}, /* err[5]: measurement error factor [0]:reserved, [1-3]:error factor a/b/c of phase (m) , [4]:doppler frequency (hz) */ + {bias_0, iono_0, trop_0}, /* std[3]: initial-state std [0]bias,[1]iono [2]trop*/ + {sigma_bias, sigma_iono, sigma_trop, sigma_acch, sigma_accv, sigma_pos}, /* prn[6] process-noise std */ + 5e-12, /* sclkstab: satellite clock stability (sec/sec) */ + {min_ratio_to_fix_ambiguity, 0.9999, 0.25, 0.1, 0.05, 0.0, 0.0, 0.0}, /* thresar[8]: AR validation threshold */ + min_elevation_to_fix_ambiguity, /* elevation mask of AR for rising satellite (deg) */ + 0.0, /* elevation mask to hold ambiguity (deg) */ + slip_threshold, /* slip threshold of geometry-free phase (m) */ + 30.0, /* max difference of time (sec) */ + threshold_reject_innovation, /* reject threshold of innovation (m) */ + threshold_reject_gdop, /* reject threshold of gdop */ + {}, /* double baseline[2] baseline length constraint {const,sigma} (m) */ + {}, /* double ru[3] rover position for fixed mode {x,y,z} (ecef) (m) */ + {}, /* double rb[3] base position for relative mode {x,y,z} (ecef) (m) */ + {"", ""}, /* char anttype[2][MAXANT] antenna types {rover,base} */ + {{}, {}}, /* double antdel[2][3] antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */ + {}, /* pcv_t pcvr[2] receiver antenna parameters {rov,base} */ + {}, /* unsigned char exsats[MAXSAT] excluded satellites (1:excluded, 2:included) */ + 0, /* max averaging epoches */ + 0, /* initialize by restart */ + 1, /* output single by dgps/float/fix/ppp outage */ + {"", ""}, /* char rnxopt[2][256] rinex options {rover,base} */ + {sat_PCV, rec_PCV, phwindup, reject_GPS_IIA, raim_fde}, /* posopt[6] positioning options [0]: satellite and receiver antenna PCV model; [1]: interpolate antenna parameters; [2]: apply phase wind-up correction for PPP modes; [3]: exclude measurements of GPS Block IIA satellites satellite [4]: RAIM FDE (fault detection and exclusion) [5]: handle day-boundary clock jump */ + 0, /* solution sync mode (0:off,1:on) */ + {{}, {}}, /* odisp[2][6*11] ocean tide loading parameters {rov,base} */ + {{}, {{}, {}}, {{}, {}}, {}, {}}, /* exterr_t exterr extended receiver error model */ + 0, /* disable L2-AR */ + {} /* char pppopt[256] ppp option "-GAP_RESION=" default gap to reset iono parameters (ep) */ + }; + + rtkinit(&rtk, &rtklib_configuration_options); + + // Outputs + bool default_output_enabled = configuration->property(role + ".output_enabled", true); + pvt_output_parameters.output_enabled = default_output_enabled; + pvt_output_parameters.rinex_output_enabled = configuration->property(role + ".rinex_output_enabled", default_output_enabled); + pvt_output_parameters.gpx_output_enabled = configuration->property(role + ".gpx_output_enabled", default_output_enabled); + pvt_output_parameters.geojson_output_enabled = configuration->property(role + ".geojson_output_enabled", default_output_enabled); + pvt_output_parameters.kml_output_enabled = configuration->property(role + ".kml_output_enabled", default_output_enabled); + pvt_output_parameters.xml_output_enabled = configuration->property(role + ".xml_output_enabled", default_output_enabled); + pvt_output_parameters.nmea_output_file_enabled = configuration->property(role + ".nmea_output_file_enabled", default_output_enabled); + pvt_output_parameters.rtcm_output_file_enabled = configuration->property(role + ".rtcm_output_file_enabled", default_output_enabled); + + std::string default_output_path = configuration->property(role + ".output_path", std::string(".")); + pvt_output_parameters.output_path = default_output_path; + pvt_output_parameters.rinex_output_path = configuration->property(role + ".rinex_output_path", default_output_path); + pvt_output_parameters.gpx_output_path = configuration->property(role + ".gpx_output_path", default_output_path); + pvt_output_parameters.geojson_output_path = configuration->property(role + ".geojson_output_path", default_output_path); + pvt_output_parameters.kml_output_path = configuration->property(role + ".kml_output_path", default_output_path); + pvt_output_parameters.xml_output_path = configuration->property(role + ".xml_output_path", default_output_path); + pvt_output_parameters.nmea_output_file_path = configuration->property(role + ".nmea_output_file_path", default_output_path); + pvt_output_parameters.rtcm_output_file_path = configuration->property(role + ".rtcm_output_file_path", default_output_path); + + // make PVT object + pvt_ = rtklib_make_pvt_cc(in_streams_, pvt_output_parameters, rtk); + DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")"; + if (out_streams_ > 0) + { + LOG(ERROR) << "The PVT block does not have an output stream"; + } +} + + +RtklibPvt::~RtklibPvt() +{ + rtkfree(&rtk); +} + + +bool RtklibPvt::get_latest_PVT(double* longitude_deg, + double* latitude_deg, + double* height_m, + double* ground_speed_kmh, + double* course_over_ground_deg, + time_t* UTC_time) +{ + return pvt_->get_latest_PVT(longitude_deg, + latitude_deg, + height_m, + ground_speed_kmh, + course_over_ground_deg, + UTC_time); +} + + +void RtklibPvt::clear_ephemeris() +{ + pvt_->clear_ephemeris(); +} + + +std::map RtklibPvt::get_gps_ephemeris() const +{ + return pvt_->get_gps_ephemeris_map(); +} + + +std::map RtklibPvt::get_galileo_ephemeris() const +{ + return pvt_->get_galileo_ephemeris_map(); +} + + +std::map RtklibPvt::get_gps_almanac() const +{ + return pvt_->get_gps_almanac_map(); +} + + +std::map RtklibPvt::get_galileo_almanac() const +{ + return pvt_->get_galileo_almanac_map(); +} + + +void RtklibPvt::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect internally + DLOG(INFO) << "nothing to connect internally"; +} + + +void RtklibPvt::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect +} + + +gr::basic_block_sptr RtklibPvt::get_left_block() +{ + return pvt_; +} + + +gr::basic_block_sptr RtklibPvt::get_right_block() +{ + return pvt_; // this is a sink, nothing downstream +} diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.h b/src/algorithms/PVT/adapters/rtklib_pvt.h new file mode 100644 index 000000000..41235471b --- /dev/null +++ b/src/algorithms/PVT/adapters/rtklib_pvt.h @@ -0,0 +1,103 @@ +/*! + * \file rtklib_pvt.h + * \brief Interface of a Position Velocity and Time computation block + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_RTKLIB_PVT_H_ +#define GNSS_SDR_RTKLIB_PVT_H_ + +#include "pvt_interface.h" +#include "rtklib_pvt_cc.h" +#include + + +class ConfigurationInterface; + +/*! + * \brief This class implements a PvtInterface for the RTKLIB PVT block + */ +class RtklibPvt : public PvtInterface +{ +public: + RtklibPvt(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~RtklibPvt(); + + inline std::string role() override + { + return role_; + } + + //! Returns "RTKLIB_PVT" + inline std::string implementation() override + { + return "RTKLIB_PVT"; + } + + void clear_ephemeris() override; + std::map get_gps_ephemeris() const override; + std::map get_galileo_ephemeris() const override; + std::map get_gps_almanac() const override; + std::map get_galileo_almanac() const override; + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline void reset() override + { + return; + } + + //! All blocks must have an item_size() function implementation. Returns sizeof(gr_complex) + inline size_t item_size() override + { + return sizeof(gr_complex); + } + + bool get_latest_PVT(double* longitude_deg, + double* latitude_deg, + double* height_m, + double* ground_speed_kmh, + double* course_over_ground_deg, + time_t* UTC_time) override; + +private: + rtklib_pvt_cc_sptr pvt_; + rtk_t rtk{}; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif diff --git a/src/algorithms/PVT/gnuradio_blocks/CMakeLists.txt b/src/algorithms/PVT/gnuradio_blocks/CMakeLists.txt index 1eb1eaf1c..eb58c0894 100644 --- a/src/algorithms/PVT/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/PVT/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,30 +13,37 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(PVT_GR_BLOCKS_SOURCES - gps_l1_ca_pvt_cc.cc - galileo_e1_pvt_cc.cc - hybrid_pvt_cc.cc + +if(Boost_VERSION LESS 105800) + add_definitions(-DOLD_BOOST=1) +endif() + +set(PVT_GR_BLOCKS_SOURCES + rtklib_pvt_cc.cc +) + +set(PVT_GR_BLOCKS_HEADERS + rtklib_pvt_cc.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${ARMADILLO_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${ARMADILLO_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB PVT_GR_BLOCKS_HEADERS "*.h") -list(SORT PVT_GR_BLOCKS_HEADERS) add_library(pvt_gr_blocks ${PVT_GR_BLOCKS_SOURCES} ${PVT_GR_BLOCKS_HEADERS}) source_group(Headers FILES ${PVT_GR_BLOCKS_HEADERS}) target_link_libraries(pvt_gr_blocks pvt_lib ${ARMADILLO_LIBRARIES}) diff --git a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc deleted file mode 100644 index e7c1f9813..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc +++ /dev/null @@ -1,424 +0,0 @@ -/*! - * \file galileo_e1_pvt_cc.cc - * \brief Implementation of a Position Velocity and Time computation block for GPS L1 C/A - * \author Javier Arribas, 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e1_pvt_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "concurrent_map.h" - -using google::LogMessage; - - -galileo_e1_pvt_cc_sptr galileo_e1_make_pvt_cc(unsigned int nchannels, bool dump, std::string dump_filename, int averaging_depth, - bool flag_averaging, int output_rate_ms, int display_rate_ms, bool flag_nmea_tty_port, std::string nmea_dump_filename, - std::string nmea_dump_devname, bool flag_rtcm_server, bool flag_rtcm_tty_port, unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, std::map rtcm_msg_rate_ms, std::string rtcm_dump_devname) -{ - return galileo_e1_pvt_cc_sptr(new galileo_e1_pvt_cc(nchannels, dump, dump_filename, averaging_depth, - flag_averaging, output_rate_ms, display_rate_ms, flag_nmea_tty_port, nmea_dump_filename, nmea_dump_devname, - flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_msg_rate_ms, rtcm_dump_devname)); -} - - -void galileo_e1_pvt_cc::msg_handler_telemetry(pmt::pmt_t msg) -{ - try { - if( pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo EPHEMERIS ### - std::shared_ptr galileo_eph; - galileo_eph = boost::any_cast>(pmt::any_ref(msg)); - // insert new ephemeris record - DLOG(INFO) << "Galileo New Ephemeris record inserted in global map with TOW =" << galileo_eph->TOW_5 - << ", GALILEO Week Number =" << galileo_eph->WN_5 - << " and Ephemeris IOD = " << galileo_eph->IOD_ephemeris; - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->galileo_ephemeris_map[galileo_eph->i_satellite_PRN] = *galileo_eph; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo IONO ### - std::shared_ptr galileo_iono; - galileo_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->galileo_iono = *galileo_iono; - DLOG(INFO) << "New IONO record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo UTC MODEL ### - std::shared_ptr galileo_utc_model; - galileo_utc_model = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->galileo_utc_model = *galileo_utc_model; - DLOG(INFO) << "New UTC record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo Almanac ### - std::shared_ptr galileo_almanac; - galileo_almanac = boost::any_cast>(pmt::any_ref(msg)); - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->galileo_almanac = *galileo_almanac; - DLOG(INFO) << "New Galileo Almanac has arrived "; - } - else - { - LOG(WARNING) << "msg_handler_telemetry unknown object type!"; - } - - } - catch(boost::bad_any_cast& e) - { - LOG(WARNING) << "msg_handler_telemetry Bad any cast!\n"; - } -} - - -galileo_e1_pvt_cc::galileo_e1_pvt_cc(unsigned int nchannels, bool dump, std::string dump_filename, int averaging_depth, - bool flag_averaging, int output_rate_ms, int display_rate_ms, bool flag_nmea_tty_port, std::string nmea_dump_filename, std::string nmea_dump_devname, - bool flag_rtcm_server, bool flag_rtcm_tty_port, unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, std::map rtcm_msg_rate_ms, std::string rtcm_dump_devname) : - gr::block("galileo_e1_pvt_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), gr::io_signature::make(0, 0, sizeof(gr_complex))) -{ - d_output_rate_ms = output_rate_ms; - d_display_rate_ms = display_rate_ms; - d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - std::string dump_ls_pvt_filename = dump_filename; - - // GPS Ephemeris data message port in - this->message_port_register_in(pmt::mp("telemetry")); - this->set_msg_handler(pmt::mp("telemetry"), boost::bind(&galileo_e1_pvt_cc::msg_handler_telemetry, this, _1)); - - //initialize kml_printer - std::string kml_dump_filename; - kml_dump_filename = d_dump_filename; - d_kml_dump = std::make_shared(); - d_kml_dump->set_headers(kml_dump_filename); - - //initialize geojson_printer - std::string geojson_dump_filename; - geojson_dump_filename = d_dump_filename; - d_geojson_printer = std::make_shared(); - d_geojson_printer->set_headers(geojson_dump_filename); - - //initialize nmea_printer - d_nmea_printer = std::make_shared(nmea_dump_filename, flag_nmea_tty_port, nmea_dump_devname); - - //initialize rtcm_printer - std::string rtcm_dump_filename; - rtcm_dump_filename = d_dump_filename; - unsigned short _port = rtcm_tcp_port; - unsigned short _station_id = rtcm_station_id; - d_rtcm_printer = std::make_shared(rtcm_dump_filename, flag_rtcm_server, flag_rtcm_tty_port, _port, _station_id, rtcm_dump_devname); - if(rtcm_msg_rate_ms.find(1045) != rtcm_msg_rate_ms.end()) - { - d_rtcm_MT1045_rate_ms = rtcm_msg_rate_ms[1045]; - } - else - { - d_rtcm_MT1045_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set - } - if(rtcm_msg_rate_ms.find(1091) != rtcm_msg_rate_ms.end()) // whatever between 1091 and 1097 - { - d_rtcm_MSM_rate_ms = rtcm_msg_rate_ms[1091]; - } - else - { - d_rtcm_MSM_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set - } - b_rtcm_writing_started = false; - - d_dump_filename.append("_raw.dat"); - dump_ls_pvt_filename.append("_ls_pvt.dat"); - d_averaging_depth = averaging_depth; - d_flag_averaging = flag_averaging; - - d_ls_pvt = std::make_shared(nchannels, dump_ls_pvt_filename, d_dump); - d_ls_pvt->set_averaging_depth(d_averaging_depth); - - d_sample_counter = 0; - d_last_sample_nav_output = 0; - d_rx_time = 0.0; - - b_rinex_header_written = false; - b_rinex_header_updated = false; - - rp = std::make_shared(); - - d_last_status_print_seg = 0; - - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception opening PVT dump file " << e.what(); - } - } - } - - // Create Sys V message queue - first_fix = true; - sysv_msg_key = 1101; - int msgflg = IPC_CREAT | 0666; - if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) - { - std::cout << "GNSS-SDR can not create message queues!" << std::endl; - throw new std::exception(); - } -} - - - -galileo_e1_pvt_cc::~galileo_e1_pvt_cc() -{ - msgctl(sysv_msqid, IPC_RMID, NULL); -} - - -void galileo_e1_pvt_cc::print_receiver_status(Gnss_Synchro** channels_synchronization_data) -{ - // Print the current receiver status using std::cout every second - int current_rx_seg = floor(channels_synchronization_data[0][0].Tracking_timestamp_secs); - if ( current_rx_seg != d_last_status_print_seg) - { - d_last_status_print_seg = current_rx_seg; - std::cout << "Current input signal time = " << current_rx_seg << " [s]" << std::endl << std::flush; - //DLOG(INFO) << "GPS L1 C/A Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) - // << ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]" << std::endl; - } -} - - -bool galileo_e1_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) -{ - /* Fill Sys V message structures */ - int msgsend_size; - ttff_msgbuf msg; - msg.ttff = ttff.ttff; - msgsend_size = sizeof(msg.ttff); - msg.mtype = 1; /* default message ID */ - - /* SEND SOLUTION OVER A MESSAGE QUEUE */ - /* non-blocking Sys V message send */ - msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); - return true; -} - -int galileo_e1_pvt_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items __attribute__((unused))) -{ - d_sample_counter++; - - std::map gnss_observables_map; - - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; //Get the input pointer - - print_receiver_status(in); - - // ############ 1. READ PSEUDORANGES #### - for (unsigned int i = 0; i < d_nchannels; i++) - { - if (in[i][0].Flag_valid_pseudorange == true) - { - gnss_observables_map.insert(std::pair(in[i][0].PRN, in[i][0])); // store valid pseudoranges in a map - d_rx_time = in[i][0].d_TOW_at_current_symbol; // all the channels have the same RX timestamp (common RX time pseudoranges) - if(d_ls_pvt->galileo_ephemeris_map.size() > 0) - { - std::map::iterator tmp_eph_iter = d_ls_pvt->galileo_ephemeris_map.find(in[i][0].PRN); - if(tmp_eph_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->lock_time(d_ls_pvt->galileo_ephemeris_map.find(in[i][0].PRN)->second, d_rx_time, in[i][0]); // keep track of locking time - } - } - } - } - - // ############ 2 COMPUTE THE PVT ################################ - if (gnss_observables_map.size() > 0 and d_ls_pvt->galileo_ephemeris_map.size() > 0) - { - // compute on the fly PVT solution - if ((d_sample_counter % d_output_rate_ms) == 0) - { - bool pvt_result; - pvt_result = d_ls_pvt->get_PVT(gnss_observables_map, d_rx_time, d_flag_averaging); - - if (pvt_result == true) - { - // correct the observable to account for the receiver clock offset - for (std::map::iterator it = gnss_observables_map.begin(); it != gnss_observables_map.end(); ++it) - { - it->second.Pseudorange_m = it->second.Pseudorange_m - d_ls_pvt->d_rx_dt_s * GPS_C_m_s; - } - if( first_fix == true) - { - std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - ttff_msgbuf ttff; - ttff.mtype = 1; - ttff.ttff = d_sample_counter; - send_sys_v_ttff_msg(ttff); - first_fix = false; - } - d_kml_dump->print_position(d_ls_pvt, d_flag_averaging); - d_geojson_printer->print_position(d_ls_pvt, d_flag_averaging); - d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging); - - if (!b_rinex_header_written) - { - std::map::iterator galileo_ephemeris_iter; - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(b_rinex_header_written) // Put here another condition to separate annotations (e.g 30 s) - { - // Limit the RINEX navigation output rate to 1/6 seg - // Notice that d_sample_counter period is 4ms (for Galileo correlators) - if ((d_sample_counter - d_last_sample_nav_output) >= 6000) - { - rp->log_rinex_nav(rp->navGalFile, d_ls_pvt->galileo_ephemeris_map); - d_last_sample_nav_output = d_sample_counter; - } - std::map::iterator galileo_ephemeris_iter; - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - - if(b_rtcm_writing_started) - { - if((d_sample_counter % (d_rtcm_MT1045_rate_ms / 4) ) == 0) - { - for(std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); gal_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(gal_ephemeris_iter->second); - } - } - if((d_sample_counter % (d_rtcm_MSM_rate_ms / 4) ) == 0) - { - std::map::iterator gal_ephemeris_iter; - gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - if(!b_rtcm_writing_started) // the first time - { - for(std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); gal_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(gal_ephemeris_iter->second); - } - - std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - - if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - } - } - - // DEBUG MESSAGE: Display position in console output - if (((d_sample_counter % d_display_rate_ms) == 0) and d_ls_pvt->b_valid_position == true) - { - std::cout << "Galileo Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - - LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]"; - - LOG(INFO) << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " is HDOP = " << d_ls_pvt->d_HDOP << " VDOP = " - << d_ls_pvt->d_VDOP <<" TDOP = " << d_ls_pvt->d_TDOP - << " GDOP = " << d_ls_pvt->d_GDOP; - } - - // MULTIPLEXED FILE RECORDING - Record results to file - if(d_dump == true) - { - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels; i++) - { - tmp_double = in[i][0].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = 0; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - d_dump_file.write((char*)&d_rx_time, sizeof(double)); - } - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - } - - consume_each(1); //one by one - return 1; -} - - diff --git a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h deleted file mode 100644 index 6a16dd566..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h +++ /dev/null @@ -1,155 +0,0 @@ -/*! - * \file galileo_e1_pvt_cc.h - * \brief Interface of a Position Velocity and Time computation block for Galileo E1 - * \author Javier Arribas, 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E1_PVT_CC_H -#define GNSS_SDR_GALILEO_E1_PVT_CC_H - -#include -#include -#include -#include -#include -#include -#include -#include "nmea_printer.h" -#include "kml_printer.h" -#include "rinex_printer.h" -#include "geojson_printer.h" -#include "rtcm_printer.h" -#include "galileo_e1_ls_pvt.h" - - -class galileo_e1_pvt_cc; - -typedef boost::shared_ptr galileo_e1_pvt_cc_sptr; - -galileo_e1_pvt_cc_sptr galileo_e1_make_pvt_cc(unsigned int n_channels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname); - -/*! - * \brief This class implements a block that computes the PVT solution with Galileo E1 signals - */ -class galileo_e1_pvt_cc : public gr::block -{ -private: - friend galileo_e1_pvt_cc_sptr galileo_e1_make_pvt_cc(unsigned int nchannels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname); - galileo_e1_pvt_cc(unsigned int nchannels, - bool dump, std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname); - - void msg_handler_telemetry(pmt::pmt_t msg); - - bool d_dump; - bool b_rinex_header_written; - bool b_rinex_header_updated; - bool b_rtcm_writing_started; - - void print_receiver_status(Gnss_Synchro** channels_synchronization_data); - int d_last_status_print_seg; //for status printer - - unsigned int d_nchannels; - std::string d_dump_filename; - std::ofstream d_dump_file; - int d_averaging_depth; - bool d_flag_averaging; - int d_output_rate_ms; - int d_display_rate_ms; - long unsigned int d_sample_counter; - long unsigned int d_last_sample_nav_output; - int d_rtcm_MT1045_rate_ms; - int d_rtcm_MSM_rate_ms; - - std::shared_ptr rp; - std::shared_ptr d_kml_dump; - std::shared_ptr d_nmea_printer; - std::shared_ptr d_geojson_printer; - std::shared_ptr d_rtcm_printer; - - double d_rx_time; - std::shared_ptr d_ls_pvt; - - bool first_fix; - key_t sysv_msg_key; - int sysv_msqid; - typedef struct { - long mtype;//required by sys v message - double ttff; - } ttff_msgbuf; - bool send_sys_v_ttff_msg(ttff_msgbuf ttff); - -public: - ~galileo_e1_pvt_cc (); //!< Default destructor - - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); //!< PVT Signal Processing -}; - -#endif diff --git a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc deleted file mode 100644 index dddb3ee16..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc +++ /dev/null @@ -1,505 +0,0 @@ -/*! - * \file gps_l1_ca_pvt_cc.cc - * \brief Implementation of a Position Velocity and Time computation block for GPS L1 C/A - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_pvt_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "concurrent_map.h" -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" - -using google::LogMessage; - -gps_l1_ca_pvt_cc_sptr -gps_l1_ca_make_pvt_cc(unsigned int nchannels, - bool dump, std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - int rinex_version) -{ - return gps_l1_ca_pvt_cc_sptr(new gps_l1_ca_pvt_cc(nchannels, - dump, - dump_filename, - averaging_depth, - flag_averaging, - output_rate_ms, - display_rate_ms, - flag_nmea_tty_port, - nmea_dump_filename, - nmea_dump_devname, - flag_rtcm_server, - flag_rtcm_tty_port, - rtcm_tcp_port, - rtcm_station_id, - rtcm_msg_rate_ms, - rtcm_dump_devname, - rinex_version)); -} - - -void gps_l1_ca_pvt_cc::msg_handler_telemetry(pmt::pmt_t msg) -{ - try { - if( pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS EPHEMERIS ### - std::shared_ptr gps_eph; - gps_eph = boost::any_cast>(pmt::any_ref(msg)); - DLOG(INFO) << "Ephemeris record has arrived from SAT ID " - << gps_eph->i_satellite_PRN << " (Block " - << gps_eph->satelliteBlock[gps_eph->i_satellite_PRN] << ")" - << "inserted with Toe="<< gps_eph->d_Toe<<" and GPS Week=" - << gps_eph->i_GPS_week; - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->gps_ephemeris_map[gps_eph->i_satellite_PRN] = *gps_eph; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS IONO ### - std::shared_ptr gps_iono; - gps_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_iono = *gps_iono; - DLOG(INFO) << "New IONO record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS UTC MODEL ### - std::shared_ptr gps_utc_model; - gps_utc_model = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_utc_model = *gps_utc_model; - DLOG(INFO) << "New UTC record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### SBAS IONO ### - std::shared_ptr sbas_iono; - sbas_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->sbas_iono = *sbas_iono; - DLOG(INFO) << "New SBAS IONO record has arrived "; - } - - //TODO: add SBAS correction maps here - //d_ls_pvt->sbas_sat_corr_map = global_sbas_sat_corr_map.get_map_copy(); - //d_ls_pvt->sbas_ephemeris_map = global_sbas_ephemeris_map.get_map_copy(); - - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - std::shared_ptr sbas_raw_msg_ptr; - sbas_raw_msg_ptr = boost::any_cast>(pmt::any_ref(msg)); - Sbas_Raw_Msg sbas_raw_msg = *sbas_raw_msg_ptr; - // read SBAS raw messages directly from queue and write them into rinex file - // create the header of not yet done - if(!b_rinex_sbs_header_written) - { - rp->rinex_sbs_header(rp->sbsFile); - b_rinex_sbs_header_written = true; - } - - // Define the RX time of the SBAS message by using the GPS time. - // It has only an effect if there has not been yet a SBAS MT12 available - // when the message was received. - if(sbas_raw_msg.get_rx_time_obj().is_related() == false - && gnss_observables_map.size() > 0 - && d_ls_pvt->gps_ephemeris_map.size() > 0) - { - // doesn't matter which channel/satellite we choose - Gnss_Synchro gs = gnss_observables_map.begin()->second; - Gps_Ephemeris eph = d_ls_pvt->gps_ephemeris_map.begin()->second; - - double relative_rx_time = gs.Tracking_timestamp_secs; - int gps_week = eph.i_GPS_week; - double gps_sec = gs.d_TOW_at_current_symbol; - - Sbas_Time_Relation time_rel(relative_rx_time, gps_week, gps_sec); - sbas_raw_msg.relate(time_rel); - } - - // send the message to the rinex logger if it has a valid GPS time stamp - if(sbas_raw_msg.get_rx_time_obj().is_related()) - { - rp->log_rinex_sbs(rp->sbsFile, sbas_raw_msg); - } - } - else - { - LOG(WARNING) << "msg_handler_telemetry unknown object type!"; - } - } - catch(boost::bad_any_cast& e) - { - LOG(WARNING) << "msg_handler_telemetry Bad any cast!\n"; - } -} - - -std::map gps_l1_ca_pvt_cc::get_GPS_L1_ephemeris_map() -{ - return d_ls_pvt->gps_ephemeris_map; -} - -bool gps_l1_ca_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) -{ - /* Fill Sys V message structures */ - int msgsend_size; - ttff_msgbuf msg; - msg.ttff = ttff.ttff; - msgsend_size = sizeof(msg.ttff); - msg.mtype = 1; /* default message ID */ - - /* SEND SOLUTION OVER A MESSAGE QUEUE */ - /* non-blocking Sys V message send */ - msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); - return true; -} - -gps_l1_ca_pvt_cc::gps_l1_ca_pvt_cc(unsigned int nchannels, - bool dump, std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - int rinex_version) : - gr::block("gps_l1_ca_pvt_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), - gr::io_signature::make(0, 0, sizeof(gr_complex)) ) -{ - d_output_rate_ms = output_rate_ms; - d_display_rate_ms = display_rate_ms; - d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - std::string dump_ls_pvt_filename = dump_filename; - - // GPS Ephemeris data message port in - this->message_port_register_in(pmt::mp("telemetry")); - this->set_msg_handler(pmt::mp("telemetry"), - boost::bind(&gps_l1_ca_pvt_cc::msg_handler_telemetry, this, _1)); - - // initialize kml_printer - std::string kml_dump_filename; - kml_dump_filename = d_dump_filename; - d_kml_printer = std::make_shared(); - d_kml_printer->set_headers(kml_dump_filename); - - // initialize geojson_printer - std::string geojson_dump_filename; - geojson_dump_filename = d_dump_filename; - d_geojson_printer = std::make_shared(); - d_geojson_printer->set_headers(geojson_dump_filename); - - // initialize nmea_printer - d_nmea_printer = std::make_shared(nmea_dump_filename, flag_nmea_tty_port, nmea_dump_devname); - - // initialize rtcm_printer - std::string rtcm_dump_filename; - rtcm_dump_filename = d_dump_filename; - d_rtcm_tcp_port = rtcm_tcp_port; - d_rtcm_station_id = rtcm_station_id; - d_rtcm_printer = std::make_shared(rtcm_dump_filename, flag_rtcm_server, flag_rtcm_tty_port, d_rtcm_tcp_port, d_rtcm_station_id, rtcm_dump_devname); - if(rtcm_msg_rate_ms.find(1019) != rtcm_msg_rate_ms.end()) - { - d_rtcm_MT1019_rate_ms = rtcm_msg_rate_ms[1019]; - } - else - { - d_rtcm_MT1019_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set - } - if(rtcm_msg_rate_ms.find(1071) != rtcm_msg_rate_ms.end()) // whatever between 1071 and 1077 - { - d_rtcm_MSM_rate_ms = rtcm_msg_rate_ms[1071]; - } - else - { - d_rtcm_MSM_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set - } - b_rtcm_writing_started = false; - - d_dump_filename.append("_raw.dat"); - dump_ls_pvt_filename.append("_ls_pvt.dat"); - d_averaging_depth = averaging_depth; - d_flag_averaging = flag_averaging; - - d_ls_pvt = std::make_shared((int)nchannels, dump_ls_pvt_filename, d_dump); - d_ls_pvt->set_averaging_depth(d_averaging_depth); - - d_sample_counter = 0; - d_last_sample_nav_output = 0; - d_rx_time = 0.0; - - d_last_status_print_seg = 0; - - b_rinex_header_written = false; - b_rinex_header_updated = false; - b_rinex_sbs_header_written = false; - rp = std::make_shared(rinex_version); - - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure & e) - { - LOG(INFO) << "Exception opening PVT dump file " << e.what(); - } - } - } - - // Create Sys V message queue - first_fix = true; - sysv_msg_key = 1101; - int msgflg = IPC_CREAT | 0666; - if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) - { - std::cout << "GNSS-SDR can not create message queues!" << std::endl; - throw new std::exception(); - } -} - - -gps_l1_ca_pvt_cc::~gps_l1_ca_pvt_cc() -{ - msgctl(sysv_msqid, IPC_RMID, NULL); -} - - -void gps_l1_ca_pvt_cc::print_receiver_status(Gnss_Synchro** channels_synchronization_data) -{ - // Print the current receiver status using std::cout every second - int current_rx_seg = floor(channels_synchronization_data[0][0].Tracking_timestamp_secs); - if ( current_rx_seg!= d_last_status_print_seg) - { - d_last_status_print_seg = current_rx_seg; - std::cout << "Current input signal time = " << current_rx_seg << " [s]" << std::endl << std::flush; - //DLOG(INFO) << "GPS L1 C/A Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) - // << ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]"; - } -} - - -int gps_l1_ca_pvt_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items __attribute__((unused))) -{ - gnss_observables_map.clear(); - d_sample_counter++; - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; // Get the input pointer - - print_receiver_status(in); - - // ############ 1. READ PSEUDORANGES #### - for (unsigned int i = 0; i < d_nchannels; i++) - { - if (in[i][0].Flag_valid_pseudorange == true) - { - gnss_observables_map.insert(std::pair(in[i][0].PRN, in[i][0])); // store valid pseudoranges in a map - d_rx_time = in[i][0].d_TOW_at_current_symbol; // all the channels have the same RX timestamp (common RX time pseudoranges) - if(d_ls_pvt->gps_ephemeris_map.size() > 0) - { - std::map::iterator tmp_eph_iter = d_ls_pvt->gps_ephemeris_map.find(in[i][0].PRN); - if(tmp_eph_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->lock_time(d_ls_pvt->gps_ephemeris_map.find(in[i][0].PRN)->second, d_rx_time, in[i][0]); // keep track of locking time - } - } - } - } - - // ############ 2 COMPUTE THE PVT ################################ - if (gnss_observables_map.size() > 0 and d_ls_pvt->gps_ephemeris_map.size() > 0) - { - // compute on the fly PVT solution - if ((d_sample_counter % d_output_rate_ms) == 0) - { - bool pvt_result; - pvt_result = d_ls_pvt->get_PVT(gnss_observables_map, d_rx_time, d_flag_averaging); - if (pvt_result == true) - { - // correct the observable to account for the receiver clock offset - for (std::map::iterator it = gnss_observables_map.begin(); it != gnss_observables_map.end(); ++it) - { - it->second.Pseudorange_m = it->second.Pseudorange_m - d_ls_pvt->d_rx_dt_s * GPS_C_m_s; - } - if(first_fix == true) - { - std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - ttff_msgbuf ttff; - ttff.mtype = 1; - ttff.ttff = d_sample_counter; - send_sys_v_ttff_msg(ttff); - first_fix = false; - } - d_kml_printer->print_position(d_ls_pvt, d_flag_averaging); - d_geojson_printer->print_position(d_ls_pvt, d_flag_averaging); - d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging); - - if (!b_rinex_header_written) - { - std::map::iterator gps_ephemeris_iter; - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model); - b_rinex_header_written = true; // do not write header anymore - } - } - if(b_rinex_header_written) - { - // Limit the RINEX navigation output rate to 1/6 seg - // Notice that d_sample_counter period is 1ms (for GPS correlators) - if ((d_sample_counter - d_last_sample_nav_output) >= 6000) - { - rp->log_rinex_nav(rp->navFile, d_ls_pvt->gps_ephemeris_map); - d_last_sample_nav_output = d_sample_counter; - } - std::map::iterator gps_ephemeris_iter; - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->gps_utc_model.d_A0 != 0)) - { - rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_utc_model); - rp->update_nav_header(rp->navFile, d_ls_pvt->gps_utc_model, d_ls_pvt->gps_iono); - b_rinex_header_updated = true; - } - } - if(b_rtcm_writing_started) - { - if((d_sample_counter % d_rtcm_MT1019_rate_ms) == 0) - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - } - if((d_sample_counter % d_rtcm_MSM_rate_ms) == 0) - { - std::map::iterator gps_ephemeris_iter; - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - - if(!b_rtcm_writing_started) // the first time - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - - std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - } - } - - // DEBUG MESSAGE: Display position in console output - if (((d_sample_counter % d_display_rate_ms) == 0) and d_ls_pvt->b_valid_position == true) - { - std::cout << "Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - - LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]"; - - LOG(INFO) << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " is HDOP = " << d_ls_pvt->d_HDOP << " VDOP = " - << d_ls_pvt->d_VDOP <<" TDOP = " << d_ls_pvt->d_TDOP << " GDOP = " << d_ls_pvt->d_GDOP; - } - // MULTIPLEXED FILE RECORDING - Record results to file - if(d_dump == true) - { - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels ; i++) - { - tmp_double = in[i][0].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = 0; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - d_dump_file.write((char*)&d_rx_time, sizeof(double)); - } - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - } - - consume_each(1); //one by one - return 1; -} diff --git a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h deleted file mode 100644 index 07f9d8607..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h +++ /dev/null @@ -1,170 +0,0 @@ -/*! - * \file gps_l1_ca_pvt_cc.h - * \brief Interface of a Position Velocity and Time computation block for GPS L1 C/A - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GPS_L1_CA_PVT_CC_H -#define GNSS_SDR_GPS_L1_CA_PVT_CC_H - -#include -#include -#include -#include -#include -#include -#include "nmea_printer.h" -#include "kml_printer.h" -#include "rinex_printer.h" -#include "geojson_printer.h" -#include "rtcm_printer.h" -#include "gps_l1_ca_ls_pvt.h" - - -class gps_l1_ca_pvt_cc; - -typedef boost::shared_ptr gps_l1_ca_pvt_cc_sptr; - -gps_l1_ca_pvt_cc_sptr gps_l1_ca_make_pvt_cc(unsigned int n_channels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - int rinex_version -); - -/*! - * \brief This class implements a block that computes the PVT solution - */ -class gps_l1_ca_pvt_cc : public gr::block -{ -private: - friend gps_l1_ca_pvt_cc_sptr gps_l1_ca_make_pvt_cc(unsigned int nchannels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - int rinex_version); - gps_l1_ca_pvt_cc(unsigned int nchannels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - int rinex_version); - - void msg_handler_telemetry(pmt::pmt_t msg); - - bool d_dump; - bool b_rinex_header_written; - bool b_rinex_sbs_header_written; - bool b_rinex_header_updated; - bool b_rtcm_writing_started; - unsigned short d_rtcm_tcp_port; - unsigned short d_rtcm_station_id; - int d_rtcm_MT1019_rate_ms; - int d_rtcm_MSM_rate_ms; - - void print_receiver_status(Gnss_Synchro** channels_synchronization_data); - int d_last_status_print_seg; //for status printer - - unsigned int d_nchannels; - std::string d_dump_filename; - std::ofstream d_dump_file; - int d_averaging_depth; - bool d_flag_averaging; - int d_output_rate_ms; - int d_display_rate_ms; - long unsigned int d_sample_counter; - long unsigned int d_last_sample_nav_output; - - std::shared_ptr rp; - std::shared_ptr d_kml_printer; - std::shared_ptr d_nmea_printer; - std::shared_ptr d_geojson_printer; - std::shared_ptr d_rtcm_printer; - double d_rx_time; - std::shared_ptr d_ls_pvt; - - std::map gnss_observables_map; - - bool first_fix; - key_t sysv_msg_key; - int sysv_msqid; - typedef struct { - long mtype;//required by sys v message - double ttff; - } ttff_msgbuf; - bool send_sys_v_ttff_msg(ttff_msgbuf ttff); - -public: - - /*! - * \brief Get latest set of GPS L1 ephemeris from PVT block - * - * It is used to save the assistance data at the receiver shutdown - */ - std::map get_GPS_L1_ephemeris_map(); - - ~gps_l1_ca_pvt_cc (); //!< Default destructor - - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); //!< PVT Signal Processing -}; - -#endif diff --git a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc deleted file mode 100644 index 946a4e925..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc +++ /dev/null @@ -1,1032 +0,0 @@ -/*! - * \file hybrid_pvt_cc.cc - * \brief Implementation of a Position Velocity and Time computation block for GPS L1 C/A - * \author Javier Arribas, 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "hybrid_pvt_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "concurrent_map.h" - -using google::LogMessage; - -hybrid_pvt_cc_sptr -hybrid_make_pvt_cc(unsigned int nchannels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - const unsigned int type_of_receiver) -{ - return hybrid_pvt_cc_sptr(new hybrid_pvt_cc(nchannels, - dump, - dump_filename, - averaging_depth, - flag_averaging, - output_rate_ms, - display_rate_ms, - flag_nmea_tty_port, - nmea_dump_filename, - nmea_dump_devname, - flag_rtcm_server, - flag_rtcm_tty_port, - rtcm_tcp_port, - rtcm_station_id, - rtcm_msg_rate_ms, - rtcm_dump_devname, - type_of_receiver)); -} - - -void hybrid_pvt_cc::msg_handler_telemetry(pmt::pmt_t msg) -{ - try { - if( pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS EPHEMERIS ### - std::shared_ptr gps_eph; - gps_eph = boost::any_cast>(pmt::any_ref(msg)); - DLOG(INFO) << "Ephemeris record has arrived from SAT ID " - << gps_eph->i_satellite_PRN << " (Block " - << gps_eph->satelliteBlock[gps_eph->i_satellite_PRN] << ")" - << "inserted with Toe="<< gps_eph->d_Toe<<" and GPS Week=" - << gps_eph->i_GPS_week; - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->gps_ephemeris_map[gps_eph->i_satellite_PRN] = *gps_eph; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS IONO ### - std::shared_ptr gps_iono; - gps_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_iono = *gps_iono; - DLOG(INFO) << "New IONO record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS UTC MODEL ### - std::shared_ptr gps_utc_model; - gps_utc_model = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_utc_model = *gps_utc_model; - DLOG(INFO) << "New UTC record has arrived "; - } - - if( pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo EPHEMERIS ### - std::shared_ptr galileo_eph; - galileo_eph = boost::any_cast>(pmt::any_ref(msg)); - // insert new ephemeris record - DLOG(INFO) << "Galileo New Ephemeris record inserted in global map with TOW =" << galileo_eph->TOW_5 - << ", GALILEO Week Number =" << galileo_eph->WN_5 - << " and Ephemeris IOD = " << galileo_eph->IOD_ephemeris; - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->galileo_ephemeris_map[galileo_eph->i_satellite_PRN] = *galileo_eph; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo IONO ### - std::shared_ptr galileo_iono; - galileo_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->galileo_iono = *galileo_iono; - DLOG(INFO) << "New IONO record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo UTC MODEL ### - std::shared_ptr galileo_utc_model; - galileo_utc_model = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->galileo_utc_model = *galileo_utc_model; - DLOG(INFO) << "New UTC record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### Galileo Almanac ### - std::shared_ptr galileo_almanac; - galileo_almanac = boost::any_cast>(pmt::any_ref(msg)); - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->galileo_almanac = *galileo_almanac; - DLOG(INFO) << "New Galileo Almanac has arrived "; - } - - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS CNAV message ### - std::shared_ptr gps_cnav_ephemeris; - gps_cnav_ephemeris = boost::any_cast>(pmt::any_ref(msg)); - // update/insert new ephemeris record to the global ephemeris map - d_ls_pvt->gps_cnav_ephemeris_map[gps_cnav_ephemeris->i_satellite_PRN] = *gps_cnav_ephemeris; - DLOG(INFO) << "New GPS CNAV ephemeris record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS CNAV IONO ### - std::shared_ptr gps_cnav_iono; - gps_cnav_iono = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_cnav_iono = *gps_cnav_iono; - DLOG(INFO) << "New CNAV IONO record has arrived "; - } - else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) - { - // ### GPS CNAV UTC MODEL ### - std::shared_ptr gps_cnav_utc_model; - gps_cnav_utc_model = boost::any_cast>(pmt::any_ref(msg)); - d_ls_pvt->gps_cnav_utc_model = *gps_cnav_utc_model; - DLOG(INFO) << "New CNAV UTC record has arrived "; - } - else - { - LOG(WARNING) << "msg_handler_telemetry unknown object type!"; - } - - } - catch(boost::bad_any_cast& e) - { - LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; - } -} - - -std::map hybrid_pvt_cc::get_GPS_L1_ephemeris_map() -{ - return d_ls_pvt->gps_ephemeris_map; -} - - -hybrid_pvt_cc::hybrid_pvt_cc(unsigned int nchannels, bool dump, std::string dump_filename, - int averaging_depth, bool flag_averaging, int output_rate_ms, int display_rate_ms, bool flag_nmea_tty_port, - std::string nmea_dump_filename, std::string nmea_dump_devname, - bool flag_rtcm_server, bool flag_rtcm_tty_port, unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, std::map rtcm_msg_rate_ms, std::string rtcm_dump_devname, const unsigned int type_of_receiver) : - gr::block("hybrid_pvt_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) - -{ - d_output_rate_ms = output_rate_ms; - d_display_rate_ms = display_rate_ms; - d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - std::string dump_ls_pvt_filename = dump_filename; - type_of_rx = type_of_receiver; - - // GPS Ephemeris data message port in - this->message_port_register_in(pmt::mp("telemetry")); - this->set_msg_handler(pmt::mp("telemetry"), boost::bind(&hybrid_pvt_cc::msg_handler_telemetry, this, _1)); - - //initialize kml_printer - std::string kml_dump_filename; - kml_dump_filename = d_dump_filename; - d_kml_dump = std::make_shared(); - d_kml_dump->set_headers(kml_dump_filename); - - //initialize geojson_printer - std::string geojson_dump_filename; - geojson_dump_filename = d_dump_filename; - d_geojson_printer = std::make_shared(); - d_geojson_printer->set_headers(geojson_dump_filename); - - //initialize nmea_printer - d_nmea_printer = std::make_shared(nmea_dump_filename, flag_nmea_tty_port, nmea_dump_devname); - - //initialize rtcm_printer - std::string rtcm_dump_filename; - rtcm_dump_filename = d_dump_filename; - d_rtcm_printer = std::make_shared(rtcm_dump_filename, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_dump_devname); - if(rtcm_msg_rate_ms.find(1019) != rtcm_msg_rate_ms.end()) - { - d_rtcm_MT1019_rate_ms = rtcm_msg_rate_ms[1019]; - } - else - { - d_rtcm_MT1019_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set - } - if(rtcm_msg_rate_ms.find(1045) != rtcm_msg_rate_ms.end()) - { - d_rtcm_MT1045_rate_ms = rtcm_msg_rate_ms[1045]; - } - else - { - d_rtcm_MT1045_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set - } - if(rtcm_msg_rate_ms.find(1077) != rtcm_msg_rate_ms.end()) // whatever between 1071 and 1077 - { - d_rtcm_MT1077_rate_ms = rtcm_msg_rate_ms[1077]; - } - else - { - d_rtcm_MT1077_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set - } - if(rtcm_msg_rate_ms.find(1097) != rtcm_msg_rate_ms.end()) // whatever between 1091 and 1097 - { - d_rtcm_MT1097_rate_ms = rtcm_msg_rate_ms[1097]; - d_rtcm_MSM_rate_ms = rtcm_msg_rate_ms[1097]; - } - else - { - d_rtcm_MT1097_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set - d_rtcm_MSM_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set - } - b_rtcm_writing_started = false; - - d_dump_filename.append("_raw.dat"); - dump_ls_pvt_filename.append("_ls_pvt.dat"); - d_averaging_depth = averaging_depth; - d_flag_averaging = flag_averaging; - - d_ls_pvt = std::make_shared((int)nchannels, dump_ls_pvt_filename, d_dump); - d_ls_pvt->set_averaging_depth(d_averaging_depth); - - d_sample_counter = 0; - d_last_sample_nav_output = 0; - d_rx_time = 0.0; - d_TOW_at_curr_symbol_constellation = 0.0; - b_rinex_header_written = false; - b_rinex_header_updated = false; - rp = std::make_shared(); - - d_last_status_print_seg = 0; - - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception opening PVT dump file " << e.what(); - } - } - } - - // Create Sys V message queue - first_fix = true; - sysv_msg_key = 1101; - int msgflg = IPC_CREAT | 0666; - if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) - { - std::cout << "GNSS-SDR can not create message queues!" << std::endl; - throw new std::exception(); - } -} - - - -hybrid_pvt_cc::~hybrid_pvt_cc() -{ - msgctl(sysv_msqid, IPC_RMID, NULL); -} - - - -bool hybrid_pvt_cc::observables_pairCompare_min(const std::pair& a, const std::pair& b) -{ - return (a.second.Pseudorange_m) < (b.second.Pseudorange_m); -} - - -void hybrid_pvt_cc::print_receiver_status(Gnss_Synchro** channels_synchronization_data) -{ - // Print the current receiver status using std::cout every second - int current_rx_seg = floor(channels_synchronization_data[0][0].Tracking_timestamp_secs); - if ( current_rx_seg != d_last_status_print_seg) - { - d_last_status_print_seg = current_rx_seg; - std::cout << "Current input signal time = " << current_rx_seg << " [s]" << std::endl << std::flush; - //DLOG(INFO) << "GPS L1 C/A Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) - // << ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]" << std::endl; - } -} - - -bool hybrid_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) -{ - /* Fill Sys V message structures */ - int msgsend_size; - ttff_msgbuf msg; - msg.ttff = ttff.ttff; - msgsend_size = sizeof(msg.ttff); - msg.mtype = 1; /* default message ID */ - - /* SEND SOLUTION OVER A MESSAGE QUEUE */ - /* non-blocking Sys V message send */ - msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); - return true; -} - - -int hybrid_pvt_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items __attribute__((unused))) -{ - d_sample_counter++; - unsigned int gps_channel = 0; - unsigned int gal_channel = 0; - - gnss_observables_map.clear(); - - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; //Get the input pointer - - print_receiver_status(in); - - // ############ 1. READ PSEUDORANGES #### - for (unsigned int i = 0; i < d_nchannels; i++) - { - if (in[i][0].Flag_valid_pseudorange == true) - { - gnss_observables_map.insert(std::pair(i, in[i][0])); // store valid observables in a map. - //d_rx_time = in[i][0].d_TOW_at_current_symbol; // all the channels have the same RX timestamp (common RX time pseudoranges) - d_TOW_at_curr_symbol_constellation = in[i][0].d_TOW_at_current_symbol; // d_TOW_at_current_symbol not corrected by delta t (just for debug) - d_rx_time = in[i][0].d_TOW_hybrid_at_current_symbol; // hybrid rx time, all the channels have the same RX timestamp (common RX time pseudoranges) - if(d_ls_pvt->gps_ephemeris_map.size() > 0) - { - std::map::iterator tmp_eph_iter = d_ls_pvt->gps_ephemeris_map.find(in[i][0].PRN); - if(tmp_eph_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->lock_time(d_ls_pvt->gps_ephemeris_map.find(in[i][0].PRN)->second, d_rx_time, in[i][0]); // keep track of locking time - } - } - if(d_ls_pvt->galileo_ephemeris_map.size() > 0) - { - std::map::iterator tmp_eph_iter = d_ls_pvt->galileo_ephemeris_map.find(in[i][0].PRN); - if(tmp_eph_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->lock_time(d_ls_pvt->galileo_ephemeris_map.find(in[i][0].PRN)->second, d_rx_time, in[i][0]); // keep track of locking time - } - } - if(d_ls_pvt->gps_cnav_ephemeris_map.size() > 0) - { - std::map::iterator tmp_eph_iter = d_ls_pvt->gps_cnav_ephemeris_map.find(in[i][0].PRN); - if(tmp_eph_iter != d_ls_pvt->gps_cnav_ephemeris_map.end()) - { - d_rtcm_printer->lock_time(d_ls_pvt->gps_cnav_ephemeris_map.find(in[i][0].PRN)->second, d_rx_time, in[i][0]); // keep track of locking time - } - } - } - } - - std::map::iterator galileo_ephemeris_iter; - std::map::iterator gps_ephemeris_iter; - std::map::iterator gps_cnav_ephemeris_iter; - std::map::iterator gnss_observables_iter; - - /* - * TYPE | RECEIVER - * 0 | Unknown - * 1 | GPS L1 C/A - * 2 | GPS L2C - * 3 | GPS L5 - * 4 | Galileo E1B - * 5 | Galileo E5a - * 6 | Galileo E5b - * 7 | GPS L1 C/A + GPS L2C - * 8 | GPS L1 C/A + GPS L5 - * 9 | GPS L1 C/A + Galileo E1B - * 10 | GPS L1 C/A + Galileo E5a - * 11 | GPS L1 C/A + Galileo E5b - * 12 | Galileo E1B + GPS L2C - * 13 | Galileo E1B + GPS L5 - * 14 | Galileo E1B + Galileo E5a - * 15 | Galileo E1B + Galileo E5b - * 16 | GPS L2C + GPS L5 - * 17 | GPS L2C + Galileo E5a - * 18 | GPS L2C + Galileo E5b - * 19 | GPS L5 + Galileo E5a - * 20 | GPS L5 + Galileo E5b - * 21 | GPS L1 C/A + Galileo E1B + GPS L2C - * 22 | GPS L1 C/A + Galileo E1B + GPS L5 - */ - - // ############ 2 COMPUTE THE PVT ################################ - if (gnss_observables_map.size() > 0) - { - // compute on the fly PVT solution - if ((d_sample_counter % d_output_rate_ms) == 0) - { - bool pvt_result; - pvt_result = d_ls_pvt->get_PVT(gnss_observables_map, d_rx_time, d_flag_averaging); - - if (pvt_result == true) - { - // correct the observable to account for the receiver clock offset - for (std::map::iterator it = gnss_observables_map.begin(); it != gnss_observables_map.end(); ++it) - { - it->second.Pseudorange_m = it->second.Pseudorange_m - d_ls_pvt->d_rx_dt_s * GPS_C_m_s; - } - if(first_fix == true) - { - std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - ttff_msgbuf ttff; - ttff.mtype = 1; - ttff.ttff = d_sample_counter; - send_sys_v_ttff_msg(ttff); - first_fix = false; - } - d_kml_dump->print_position(d_ls_pvt, d_flag_averaging); - d_geojson_printer->print_position(d_ls_pvt, d_flag_averaging); - d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging); - - // ####################### RINEX FILES ################# - if (!b_rinex_header_written) // & we have utc data in nav message! - { - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.begin(); - - if(type_of_rx == 1) // GPS L1 C/A only - { - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 2) // GPS L2C only - { - if (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navFile, d_ls_pvt->gps_cnav_iono, d_ls_pvt->gps_cnav_utc_model); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 4) // Galileo E1B only - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 5) // Galileo E5a only - { - std::string signal("5X"); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, signal); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 6) // Galileo E5b only - { - std::string signal("7X"); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, signal); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 7) // GPS L1 C/A + GPS L2C - { - if ((gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end())) - { - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time); - rp->rinex_nav_header(rp->navFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model); - b_rinex_header_written = true; // do not write header anymore - } - } - - if(type_of_rx == 9) // GPS L1 C/A + Galileo E1B - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) ) - { - std::string gal_signal("1B"); - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); - rp->rinex_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 10) // GPS L1 C/A + Galileo E5a - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) ) - { - std::string gal_signal("5X"); - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); - rp->rinex_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 11) // GPS L1 C/A + Galileo E5b - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) ) - { - std::string gal_signal("7X"); - rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); - rp->rinex_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 14) // Galileo E1B + Galileo E5a - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) ) - { - std::string gal_signal("1B 5X"); - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gal_signal); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - if(type_of_rx == 15) // Galileo E1B + Galileo E5b - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) ) - { - std::string gal_signal("1B 7X"); - rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gal_signal); - rp->rinex_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_written = true; // do not write header anymore - } - } - } - if(b_rinex_header_written) // The header is already written, we can now log the navigation message data - { - // Limit the RINEX navigation output rate - // Notice that d_sample_counter period is 4ms (for Galileo correlators) - if ((d_sample_counter - d_last_sample_nav_output) >= 6000) - { - if(type_of_rx == 1) // GPS L1 C/A only - { - rp->log_rinex_nav(rp->navFile, d_ls_pvt->gps_ephemeris_map); - } - if(type_of_rx == 2) // GPS L2C only - { - rp->log_rinex_nav(rp->navFile, d_ls_pvt->gps_cnav_ephemeris_map); - } - if( (type_of_rx == 4) || (type_of_rx == 5) || (type_of_rx == 6) ) // Galileo - { - rp->log_rinex_nav(rp->navGalFile, d_ls_pvt->galileo_ephemeris_map); - } - if(type_of_rx == 7) // GPS L1 C/A + GPS L2C - { - rp->log_rinex_nav(rp->navFile, d_ls_pvt->gps_cnav_ephemeris_map); - } - if((type_of_rx == 9) || (type_of_rx == 10) || (type_of_rx == 11)) // GPS L1 C/A + Galileo - { - rp->log_rinex_nav(rp->navMixFile, d_ls_pvt->gps_ephemeris_map, d_ls_pvt->galileo_ephemeris_map); - } - if((type_of_rx == 14) || (type_of_rx == 15)) // Galileo E1B + Galileo E5a - { - rp->log_rinex_nav(rp->navGalFile, d_ls_pvt->galileo_ephemeris_map); - } - - d_last_sample_nav_output = d_sample_counter; - } - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.begin(); - - // Log observables into the RINEX file - if(type_of_rx == 1) // GPS L1 C/A only - { - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->gps_utc_model.d_A0 != 0)) - { - rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_utc_model); - rp->update_nav_header(rp->navFile, d_ls_pvt->gps_utc_model, d_ls_pvt->gps_iono); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 2) // GPS L2C only - { - if (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->gps_cnav_utc_model.d_A0 != 0)) - { - rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_cnav_utc_model); - rp->update_nav_header(rp->navFile, d_ls_pvt->gps_cnav_utc_model, d_ls_pvt->gps_cnav_iono); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 4) // Galileo E1B only - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B"); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 5) // Galileo E5a only - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "5X"); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 6) // Galileo E5b only - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "7X"); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 7) // GPS L1 C/A + GPS L2C - { - if( (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end()) ) - { - rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->gps_utc_model.d_A0 != 0)) - { - rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_utc_model); - rp->update_nav_header(rp->navFile, d_ls_pvt->gps_utc_model, d_ls_pvt->gps_iono); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 9) // GPS L1 C/A + Galileo E1B - { - if ((galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) ) - { - rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); - } - if (!b_rinex_header_updated && (d_ls_pvt->gps_utc_model.d_A0 != 0)) - { - rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_utc_model); - rp->update_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 14) // Galileo E1B + Galileo E5a - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B 5X"); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - if(type_of_rx == 15) // Galileo E1B + Galileo E5b - { - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B 7X"); - } - if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) - { - rp->update_nav_header(rp->navGalFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac); - rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); - b_rinex_header_updated = true; - } - } - } - - // ####################### RTCM MESSAGES ################# - if(b_rtcm_writing_started) - { - if(type_of_rx == 1) // GPS L1 C/A - { - if((d_sample_counter % d_rtcm_MT1019_rate_ms) == 0) - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - } - if((d_sample_counter % d_rtcm_MSM_rate_ms) == 0) - { - std::map::iterator gps_ephemeris_iter; - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - if((type_of_rx == 4) || (type_of_rx == 5) || (type_of_rx == 6) || (type_of_rx == 14) || (type_of_rx == 15)) // Galileo - { - if((d_sample_counter % (d_rtcm_MT1045_rate_ms / 4) ) == 0) - { - for(std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); gal_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(gal_ephemeris_iter->second); - } - } - if((d_sample_counter % (d_rtcm_MSM_rate_ms / 4) ) == 0) - { - std::map::iterator gal_ephemeris_iter; - gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - if(type_of_rx == 7) // GPS L1 C/A + GPS L2C - { - if((d_sample_counter % d_rtcm_MT1019_rate_ms) == 0) - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - } - if((d_sample_counter % d_rtcm_MSM_rate_ms) == 0) - { - std::map::iterator gps_ephemeris_iter; - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - std::map::iterator gps_cnav_ephemeris_iter; - gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.begin(); - if ((gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end()) ) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - if(type_of_rx == 9) // GPS L1 C/A + Galileo E1B - { - if(((d_sample_counter % (d_rtcm_MT1019_rate_ms / 4)) == 0) && (d_rtcm_MT1019_rate_ms != 0)) - { - for(gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - } - if(((d_sample_counter % (d_rtcm_MT1045_rate_ms / 4)) == 0) && (d_rtcm_MT1045_rate_ms != 0)) - { - for(galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); galileo_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(galileo_ephemeris_iter->second); - } - } - if(((d_sample_counter % (d_rtcm_MT1097_rate_ms / 4) ) == 0) || ((d_sample_counter % (d_rtcm_MT1077_rate_ms / 4) ) == 0)) - { - //gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.end(); - //galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.end(); - unsigned int i = 0; - for (gnss_observables_iter = gnss_observables_map.begin(); gnss_observables_iter != gnss_observables_map.end(); gnss_observables_iter++) - { - std::string system(&gnss_observables_iter->second.System, 1); - if(gps_channel == 0) - { - if(system.compare("G") == 0) - { - // This is a channel with valid GPS signal - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - gps_channel = i; - } - } - } - if(gal_channel == 0) - { - if(system.compare("E") == 0) - { - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - gal_channel = i; - } - } - } - i++; - } - if(((d_sample_counter % (d_rtcm_MT1097_rate_ms / 4) ) == 0) && (d_rtcm_MT1097_rate_ms != 0) ) - { - - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - if(((d_sample_counter % (d_rtcm_MT1077_rate_ms / 4) ) == 0) && (d_rtcm_MT1077_rate_ms != 0) ) - { - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - } - } - } - } - - if(!b_rtcm_writing_started) // the first time - { - if(type_of_rx == 1) // GPS L1 C/A - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - - std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - - if((type_of_rx == 4) || (type_of_rx == 5) || (type_of_rx == 6) || (type_of_rx == 14) || (type_of_rx == 15)) // Galileo - { - for(std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); gal_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(gal_ephemeris_iter->second); - } - - std::map::iterator gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); - - if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - if(type_of_rx == 7) // GPS L1 C/A + GPS L2C - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - - std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); - std::map::iterator gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.begin(); - - if ((gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.end())) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - if(type_of_rx == 9) // GPS L1 C/A + Galileo E1B - { - if(d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 - { - for(std::map::iterator gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); - } - } - if(d_rtcm_MT1045_rate_ms != 0) - { - for(galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); galileo_ephemeris_iter++ ) - { - d_rtcm_printer->Print_Rtcm_MT1045(galileo_ephemeris_iter->second); - } - } - - unsigned int i = 0; - for (gnss_observables_iter = gnss_observables_map.begin(); gnss_observables_iter != gnss_observables_map.end(); gnss_observables_iter++) - { - std::string system(&gnss_observables_iter->second.System, 1); - if(gps_channel == 0) - { - if(system.compare("G") == 0) - { - // This is a channel with valid GPS signal - gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) - { - gps_channel = i; - } - } - } - if(gal_channel == 0) - { - if(system.compare("E") == 0) - { - galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) - { - gal_channel = i; - } - } - } - i++; - } - - if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end() && (d_rtcm_MT1077_rate_ms != 0)) - { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - - if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end() && (d_rtcm_MT1097_rate_ms != 0) ) - { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); - } - b_rtcm_writing_started = true; - } - } - } - } - - // DEBUG MESSAGE: Display position in console output - if (((d_sample_counter % d_display_rate_ms) == 0) and d_ls_pvt->b_valid_position == true) - { - std::cout << "Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC using "<< d_ls_pvt->d_valid_observations<<" observations is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; - - LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC using "<< d_ls_pvt->d_valid_observations<<" observations is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d - << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]"; - - /* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) - << " UTC using "<< d_ls_pvt->d_valid_observations<<" observations is HDOP = " << d_ls_pvt->d_HDOP << " VDOP = " - << d_ls_pvt->d_VDOP <<" TDOP = " << d_ls_pvt->d_TDOP - << " GDOP = " << d_ls_pvt->d_GDOP << std::endl; */ - } - - // MULTIPLEXED FILE RECORDING - Record results to file - if(d_dump == true) - { - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels; i++) - { - tmp_double = in[i][0].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = 0; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - d_dump_file.write((char*)&d_rx_time, sizeof(double)); - } - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - } - - consume_each(1); //one by one - return 1; -} diff --git a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h deleted file mode 100644 index 1865a6e1f..000000000 --- a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h +++ /dev/null @@ -1,172 +0,0 @@ -/*! - * \file hybrid_pvt_cc.h - * \brief Interface of a Position Velocity and Time computation block for Galileo E1 - * \author Javier Arribas, 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_HYBRID_PVT_CC_H -#define GNSS_SDR_HYBRID_PVT_CC_H - -#include -#include -#include -#include -#include -#include -#include -#include "nmea_printer.h" -#include "kml_printer.h" -#include "geojson_printer.h" -#include "rinex_printer.h" -#include "rtcm_printer.h" -#include "hybrid_ls_pvt.h" - - -class hybrid_pvt_cc; - -typedef boost::shared_ptr hybrid_pvt_cc_sptr; - -hybrid_pvt_cc_sptr hybrid_make_pvt_cc(unsigned int n_channels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - const unsigned int type_of_receiver); - -/*! - * \brief This class implements a block that computes the PVT solution with Galileo E1 signals - */ -class hybrid_pvt_cc : public gr::block -{ -private: - friend hybrid_pvt_cc_sptr hybrid_make_pvt_cc(unsigned int nchannels, - bool dump, - std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - const unsigned int type_of_receiver); - hybrid_pvt_cc(unsigned int nchannels, - bool dump, std::string dump_filename, - int averaging_depth, - bool flag_averaging, - int output_rate_ms, - int display_rate_ms, - bool flag_nmea_tty_port, - std::string nmea_dump_filename, - std::string nmea_dump_devname, - bool flag_rtcm_server, - bool flag_rtcm_tty_port, - unsigned short rtcm_tcp_port, - unsigned short rtcm_station_id, - std::map rtcm_msg_rate_ms, - std::string rtcm_dump_devname, - const unsigned int type_of_receiver); - - void msg_handler_telemetry(pmt::pmt_t msg); - - bool d_dump; - bool b_rinex_header_written; - bool b_rinex_header_updated; - bool b_rtcm_writing_started; - int d_rtcm_MT1045_rate_ms; - int d_rtcm_MT1019_rate_ms; - int d_rtcm_MT1077_rate_ms; - int d_rtcm_MT1097_rate_ms; - int d_rtcm_MSM_rate_ms; - - void print_receiver_status(Gnss_Synchro** channels_synchronization_data); - int d_last_status_print_seg; //for status printer - - unsigned int d_nchannels; - std::string d_dump_filename; - std::ofstream d_dump_file; - int d_averaging_depth; - bool d_flag_averaging; - int d_output_rate_ms; - int d_display_rate_ms; - long unsigned int d_sample_counter; - long unsigned int d_last_sample_nav_output; - - std::shared_ptr rp; - std::shared_ptr d_kml_dump; - std::shared_ptr d_nmea_printer; - std::shared_ptr d_geojson_printer; - std::shared_ptr d_rtcm_printer; - double d_rx_time; - double d_TOW_at_curr_symbol_constellation; - std::shared_ptr d_ls_pvt; - std::map gnss_observables_map; - bool observables_pairCompare_min(const std::pair& a, const std::pair& b); - - unsigned int type_of_rx; - - bool first_fix; - key_t sysv_msg_key; - int sysv_msqid; - typedef struct { - long mtype;//required by sys v message - double ttff; - } ttff_msgbuf; - bool send_sys_v_ttff_msg(ttff_msgbuf ttff); - -public: - /*! - * \brief Get latest set of GPS L1 ephemeris from PVT block - * - * It is used to save the assistance data at the receiver shutdown - */ - std::map get_GPS_L1_ephemeris_map(); - - ~hybrid_pvt_cc (); //!< Default destructor - - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); //!< PVT Signal Processing -}; - -#endif diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc new file mode 100644 index 000000000..d6fed9a30 --- /dev/null +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc @@ -0,0 +1,2923 @@ +/*! + * \file rtklib_pvt_cc.cc + * \brief Interface of a Position Velocity and Time computation block + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "rtklib_pvt_cc.h" +#include "display.h" +#include "galileo_almanac.h" +#include "galileo_almanac_helper.h" +#include "gnss_sdr_create_directory.h" +#include "pvt_conf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if OLD_BOOST +#include +namespace bc = boost::math; +#else +#include +namespace bc = boost::integer; +#endif + +using google::LogMessage; + + +rtklib_pvt_cc_sptr rtklib_make_pvt_cc(uint32_t nchannels, + const Pvt_Conf& conf_, + const rtk_t& rtk) +{ + return rtklib_pvt_cc_sptr(new rtklib_pvt_cc(nchannels, + conf_, + rtk)); +} + + +void rtklib_pvt_cc::msg_handler_telemetry(pmt::pmt_t msg) +{ + try + { + // ************* GPS telemetry ***************** + if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS EPHEMERIS ### + std::shared_ptr gps_eph; + gps_eph = boost::any_cast>(pmt::any_ref(msg)); + DLOG(INFO) << "Ephemeris record has arrived from SAT ID " + << gps_eph->i_satellite_PRN << " (Block " + << gps_eph->satelliteBlock[gps_eph->i_satellite_PRN] << ")" + << "inserted with Toe=" << gps_eph->d_Toe << " and GPS Week=" + << gps_eph->i_GPS_week; + // update/insert new ephemeris record to the global ephemeris map + d_pvt_solver->gps_ephemeris_map[gps_eph->i_satellite_PRN] = *gps_eph; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS IONO ### + std::shared_ptr gps_iono; + gps_iono = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->gps_iono = *gps_iono; + DLOG(INFO) << "New IONO record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS UTC MODEL ### + std::shared_ptr gps_utc_model; + gps_utc_model = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->gps_utc_model = *gps_utc_model; + DLOG(INFO) << "New UTC record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS CNAV message ### + std::shared_ptr gps_cnav_ephemeris; + gps_cnav_ephemeris = boost::any_cast>(pmt::any_ref(msg)); + // update/insert new ephemeris record to the global ephemeris map + d_pvt_solver->gps_cnav_ephemeris_map[gps_cnav_ephemeris->i_satellite_PRN] = *gps_cnav_ephemeris; + DLOG(INFO) << "New GPS CNAV ephemeris record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS CNAV IONO ### + std::shared_ptr gps_cnav_iono; + gps_cnav_iono = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->gps_cnav_iono = *gps_cnav_iono; + DLOG(INFO) << "New CNAV IONO record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS CNAV UTC MODEL ### + std::shared_ptr gps_cnav_utc_model; + gps_cnav_utc_model = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->gps_cnav_utc_model = *gps_cnav_utc_model; + DLOG(INFO) << "New CNAV UTC record has arrived "; + } + + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GPS ALMANAC ### + std::shared_ptr gps_almanac; + gps_almanac = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->gps_almanac_map[gps_almanac->i_satellite_PRN] = *gps_almanac; + DLOG(INFO) << "New GPS almanac record has arrived "; + } + + // **************** Galileo telemetry ******************** + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### Galileo EPHEMERIS ### + std::shared_ptr galileo_eph; + galileo_eph = boost::any_cast>(pmt::any_ref(msg)); + // insert new ephemeris record + DLOG(INFO) << "Galileo New Ephemeris record inserted in global map with TOW =" << galileo_eph->TOW_5 + << ", GALILEO Week Number =" << galileo_eph->WN_5 + << " and Ephemeris IOD = " << galileo_eph->IOD_ephemeris; + // update/insert new ephemeris record to the global ephemeris map + d_pvt_solver->galileo_ephemeris_map[galileo_eph->i_satellite_PRN] = *galileo_eph; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### Galileo IONO ### + std::shared_ptr galileo_iono; + galileo_iono = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->galileo_iono = *galileo_iono; + DLOG(INFO) << "New IONO record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### Galileo UTC MODEL ### + std::shared_ptr galileo_utc_model; + galileo_utc_model = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->galileo_utc_model = *galileo_utc_model; + DLOG(INFO) << "New UTC record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### Galileo Almanac ### + std::shared_ptr galileo_almanac_helper; + galileo_almanac_helper = boost::any_cast>(pmt::any_ref(msg)); + + Galileo_Almanac sv1 = galileo_almanac_helper->get_almanac(1); + Galileo_Almanac sv2 = galileo_almanac_helper->get_almanac(2); + Galileo_Almanac sv3 = galileo_almanac_helper->get_almanac(3); + + if (sv1.i_satellite_PRN != 0) d_pvt_solver->galileo_almanac_map[sv1.i_satellite_PRN] = sv1; + if (sv2.i_satellite_PRN != 0) d_pvt_solver->galileo_almanac_map[sv2.i_satellite_PRN] = sv2; + if (sv3.i_satellite_PRN != 0) d_pvt_solver->galileo_almanac_map[sv3.i_satellite_PRN] = sv3; + DLOG(INFO) << "New Galileo Almanac data have arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### Galileo Almanac ### + std::shared_ptr galileo_alm; + galileo_alm = boost::any_cast>(pmt::any_ref(msg)); + // update/insert new almanac record to the global almanac map + d_pvt_solver->galileo_almanac_map[galileo_alm->i_satellite_PRN] = *galileo_alm; + } + + // **************** GLONASS GNAV Telemetry ************************** + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GLONASS GNAV EPHEMERIS ### + std::shared_ptr glonass_gnav_eph; + glonass_gnav_eph = boost::any_cast>(pmt::any_ref(msg)); + // TODO Add GLONASS with gps week number and tow, + // insert new ephemeris record + DLOG(INFO) << "GLONASS GNAV New Ephemeris record inserted in global map with TOW =" << glonass_gnav_eph->d_TOW + << ", Week Number =" << glonass_gnav_eph->d_WN + << " and Ephemeris IOD in UTC = " << glonass_gnav_eph->compute_GLONASS_time(glonass_gnav_eph->d_t_b) + << " from SV = " << glonass_gnav_eph->i_satellite_slot_number; + // update/insert new ephemeris record to the global ephemeris map + d_pvt_solver->glonass_gnav_ephemeris_map[glonass_gnav_eph->i_satellite_PRN] = *glonass_gnav_eph; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GLONASS GNAV UTC MODEL ### + std::shared_ptr glonass_gnav_utc_model; + glonass_gnav_utc_model = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->glonass_gnav_utc_model = *glonass_gnav_utc_model; + DLOG(INFO) << "New GLONASS GNAV UTC record has arrived "; + } + else if (pmt::any_ref(msg).type() == typeid(std::shared_ptr)) + { + // ### GLONASS GNAV Almanac ### + std::shared_ptr glonass_gnav_almanac; + glonass_gnav_almanac = boost::any_cast>(pmt::any_ref(msg)); + d_pvt_solver->glonass_gnav_almanac = *glonass_gnav_almanac; + DLOG(INFO) << "New GLONASS GNAV Almanac has arrived " + << ", GLONASS GNAV Slot Number =" << glonass_gnav_almanac->d_n_A; + } + else + { + LOG(WARNING) << "msg_handler_telemetry unknown object type!"; + } + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + } +} + + +std::map rtklib_pvt_cc::get_gps_ephemeris_map() const +{ + return d_pvt_solver->gps_ephemeris_map; +} + + +std::map rtklib_pvt_cc::get_gps_almanac_map() const +{ + return d_pvt_solver->gps_almanac_map; +} + + +std::map rtklib_pvt_cc::get_galileo_ephemeris_map() const +{ + return d_pvt_solver->galileo_ephemeris_map; +} + + +std::map rtklib_pvt_cc::get_galileo_almanac_map() const +{ + return d_pvt_solver->galileo_almanac_map; +} + + +void rtklib_pvt_cc::clear_ephemeris() +{ + d_pvt_solver->gps_ephemeris_map.clear(); + d_pvt_solver->gps_almanac_map.clear(); + d_pvt_solver->galileo_ephemeris_map.clear(); + d_pvt_solver->galileo_almanac_map.clear(); +} + + +rtklib_pvt_cc::rtklib_pvt_cc(uint32_t nchannels, + const Pvt_Conf& conf_, + const rtk_t& rtk) : gr::sync_block("rtklib_pvt_cc", + gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), + gr::io_signature::make(0, 0, 0)) +{ + d_output_rate_ms = conf_.output_rate_ms; + d_display_rate_ms = conf_.display_rate_ms; + d_dump = conf_.dump; + d_dump_mat = conf_.dump_mat and d_dump; + d_dump_filename = conf_.dump_filename; + std::string dump_ls_pvt_filename = conf_.dump_filename; + if (d_dump) + { + std::string dump_path; + // Get path + if (d_dump_filename.find_last_of("/") != std::string::npos) + { + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of("/") + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of("/")); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "pvt"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of(".") != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of(".")); + } + dump_ls_pvt_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + dump_ls_pvt_filename.append(".dat"); + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump file for the PVT block. Wrong permissions?" << std::endl; + d_dump = false; + } + } + + d_nchannels = nchannels; + + type_of_rx = conf_.type_of_receiver; + + // GPS Ephemeris data message port in + this->message_port_register_in(pmt::mp("telemetry")); + this->set_msg_handler(pmt::mp("telemetry"), boost::bind(&rtklib_pvt_cc::msg_handler_telemetry, this, _1)); + + // initialize kml_printer + std::string kml_dump_filename; + kml_dump_filename = d_dump_filename; + d_kml_output_enabled = conf_.kml_output_enabled; + if (d_kml_output_enabled) + { + d_kml_dump = std::make_shared(conf_.kml_output_path); + d_kml_dump->set_headers(kml_dump_filename); + } + else + { + d_kml_dump = nullptr; + } + + // initialize gpx_printer + std::string gpx_dump_filename; + gpx_dump_filename = d_dump_filename; + d_gpx_output_enabled = conf_.gpx_output_enabled; + if (d_gpx_output_enabled) + { + d_gpx_dump = std::make_shared(conf_.gpx_output_path); + d_gpx_dump->set_headers(gpx_dump_filename); + } + else + { + d_gpx_dump = nullptr; + } + + // initialize geojson_printer + std::string geojson_dump_filename; + geojson_dump_filename = d_dump_filename; + + d_geojson_output_enabled = conf_.geojson_output_enabled; + if (d_geojson_output_enabled) + { + d_geojson_printer = std::make_shared(conf_.geojson_output_path); + d_geojson_printer->set_headers(geojson_dump_filename); + } + else + { + d_geojson_printer = nullptr; + } + + // initialize nmea_printer + d_nmea_output_file_enabled = (conf_.nmea_output_file_enabled or conf_.flag_nmea_tty_port); + if (d_nmea_output_file_enabled) + { + d_nmea_printer = std::make_shared(conf_.nmea_dump_filename, conf_.nmea_output_file_enabled, conf_.flag_nmea_tty_port, conf_.nmea_dump_devname, conf_.nmea_output_file_path); + } + else + { + d_nmea_printer = nullptr; + } + + // initialize rtcm_printer + std::string rtcm_dump_filename; + rtcm_dump_filename = d_dump_filename; + if (conf_.flag_rtcm_server or conf_.flag_rtcm_tty_port or conf_.rtcm_output_file_enabled) + { + d_rtcm_printer = std::make_shared(rtcm_dump_filename, conf_.rtcm_output_file_enabled, conf_.flag_rtcm_server, conf_.flag_rtcm_tty_port, conf_.rtcm_tcp_port, conf_.rtcm_station_id, conf_.rtcm_dump_devname, true, conf_.rtcm_output_file_path); + std::map rtcm_msg_rate_ms = conf_.rtcm_msg_rate_ms; + if (rtcm_msg_rate_ms.find(1019) != rtcm_msg_rate_ms.end()) + { + d_rtcm_MT1019_rate_ms = rtcm_msg_rate_ms[1019]; + } + else + { + d_rtcm_MT1019_rate_ms = bc::lcm(5000, d_output_rate_ms); // default value if not set + } + if (rtcm_msg_rate_ms.find(1020) != rtcm_msg_rate_ms.end()) + { + d_rtcm_MT1020_rate_ms = rtcm_msg_rate_ms[1020]; + } + else + { + d_rtcm_MT1020_rate_ms = bc::lcm(5000, d_output_rate_ms); // default value if not set + } + if (rtcm_msg_rate_ms.find(1045) != rtcm_msg_rate_ms.end()) + { + d_rtcm_MT1045_rate_ms = rtcm_msg_rate_ms[1045]; + } + else + { + d_rtcm_MT1045_rate_ms = bc::lcm(5000, d_output_rate_ms); // default value if not set + } + if (rtcm_msg_rate_ms.find(1077) != rtcm_msg_rate_ms.end()) // whatever between 1071 and 1077 + { + d_rtcm_MT1077_rate_ms = rtcm_msg_rate_ms[1077]; + } + else + { + d_rtcm_MT1077_rate_ms = bc::lcm(1000, d_output_rate_ms); // default value if not set + } + if (rtcm_msg_rate_ms.find(1087) != rtcm_msg_rate_ms.end()) // whatever between 1081 and 1087 + { + d_rtcm_MT1087_rate_ms = rtcm_msg_rate_ms[1087]; + } + else + { + d_rtcm_MT1087_rate_ms = bc::lcm(1000, d_output_rate_ms); // default value if not set + } + if (rtcm_msg_rate_ms.find(1097) != rtcm_msg_rate_ms.end()) // whatever between 1091 and 1097 + { + d_rtcm_MT1097_rate_ms = rtcm_msg_rate_ms[1097]; + d_rtcm_MSM_rate_ms = rtcm_msg_rate_ms[1097]; + } + else + { + d_rtcm_MT1097_rate_ms = bc::lcm(1000, d_output_rate_ms); // default value if not set + d_rtcm_MSM_rate_ms = bc::lcm(1000, d_output_rate_ms); // default value if not set + } + b_rtcm_writing_started = false; + b_rtcm_enabled = true; + } + else + { + d_rtcm_MT1019_rate_ms = 0; + d_rtcm_MT1045_rate_ms = 0; + d_rtcm_MT1020_rate_ms = 0; + d_rtcm_MT1077_rate_ms = 0; + d_rtcm_MT1087_rate_ms = 0; + d_rtcm_MT1097_rate_ms = 0; + d_rtcm_MSM_rate_ms = 0; + b_rtcm_enabled = false; + b_rtcm_writing_started = false; + d_rtcm_printer = nullptr; + } + + // initialize RINEX printer + b_rinex_header_written = false; + b_rinex_header_updated = false; + b_rinex_output_enabled = conf_.rinex_output_enabled; + d_rinex_version = conf_.rinex_version; + if (b_rinex_output_enabled) + { + rp = std::make_shared(d_rinex_version, conf_.rinex_output_path); + } + else + { + rp = nullptr; + } + d_rinexobs_rate_ms = conf_.rinexobs_rate_ms; + d_rinexnav_rate_ms = conf_.rinexnav_rate_ms; + + // XML printer + d_xml_storage = conf_.xml_output_enabled; + if (d_xml_storage) + { + xml_base_path = conf_.xml_output_path; + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(xml_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(xml_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + xml_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + xml_base_path = p.string(); + } + if (xml_base_path != ".") + { + std::cout << "XML files will be stored at " << xml_base_path << std::endl; + } + + xml_base_path = xml_base_path + boost::filesystem::path::preferred_separator; + } + + d_pvt_solver = std::make_shared(static_cast(nchannels), dump_ls_pvt_filename, d_dump, d_dump_mat, rtk); + d_pvt_solver->set_averaging_depth(1); + + d_rx_time = 0.0; + + d_last_status_print_seg = 0; + + // Create Sys V message queue + first_fix = true; + sysv_msg_key = 1101; + int msgflg = IPC_CREAT | 0666; + if ((sysv_msqid = msgget(sysv_msg_key, msgflg)) == -1) + { + std::cout << "GNSS-SDR can not create message queues!" << std::endl; + throw std::exception(); + } + start = std::chrono::system_clock::now(); +} + + +rtklib_pvt_cc::~rtklib_pvt_cc() +{ + msgctl(sysv_msqid, IPC_RMID, NULL); + if (d_xml_storage) + { + // save GPS L2CM ephemeris to XML file + std::string file_name = xml_base_path + "gps_cnav_ephemeris.xml"; + if (d_pvt_solver->gps_cnav_ephemeris_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_cnav_ephemeris_map", d_pvt_solver->gps_cnav_ephemeris_map); + LOG(INFO) << "Saved GPS L2CM or L5 Ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS L2CM or L5 Ephemeris, map is empty"; + } + + // save GPS L1 CA ephemeris to XML file + file_name = xml_base_path + "gps_ephemeris.xml"; + if (d_pvt_solver->gps_ephemeris_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", d_pvt_solver->gps_ephemeris_map); + LOG(INFO) << "Saved GPS L1 CA Ephemeris map data"; + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS L1 CA Ephemeris, map is empty"; + } + + // save Galileo E1 ephemeris to XML file + file_name = xml_base_path + "gal_ephemeris.xml"; + if (d_pvt_solver->galileo_ephemeris_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", d_pvt_solver->galileo_ephemeris_map); + LOG(INFO) << "Saved Galileo E1 Ephemeris map data"; + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save Galileo E1 Ephemeris, map is empty"; + } + + // save GLONASS GNAV ephemeris to XML file + file_name = xml_base_path + "eph_GLONASS_GNAV.xml"; + if (d_pvt_solver->glonass_gnav_ephemeris_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", d_pvt_solver->glonass_gnav_ephemeris_map); + LOG(INFO) << "Saved GLONASS GNAV Ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GLONASS GNAV Ephemeris, map is empty"; + } + + // Save GPS UTC model parameters + file_name = xml_base_path + "gps_utc_model.xml"; + if (d_pvt_solver->gps_utc_model.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_utc_model", d_pvt_solver->gps_utc_model); + LOG(INFO) << "Saved GPS UTC model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS UTC model parameters, not valid data"; + } + + // Save Galileo UTC model parameters + file_name = xml_base_path + "gal_utc_model.xml"; + if (d_pvt_solver->galileo_utc_model.Delta_tLS_6 != 0.0) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", d_pvt_solver->galileo_utc_model); + LOG(INFO) << "Saved Galileo UTC model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save Galileo UTC model parameters, not valid data"; + } + + // Save GPS iono parameters + file_name = xml_base_path + "gps_iono.xml"; + if (d_pvt_solver->gps_iono.valid == true) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_iono_model", d_pvt_solver->gps_iono); + LOG(INFO) << "Saved GPS ionospheric model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS ionospheric model parameters, not valid data"; + } + + // Save GPS CNAV iono parameters + file_name = xml_base_path + "gps_cnav_iono.xml"; + if (d_pvt_solver->gps_cnav_iono.valid == true) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_cnav_iono_model", d_pvt_solver->gps_cnav_iono); + LOG(INFO) << "Saved GPS CNAV ionospheric model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS CNAV ionospheric model parameters, not valid data"; + } + + // Save Galileo iono parameters + file_name = xml_base_path + "gal_iono.xml"; + if (d_pvt_solver->galileo_iono.ai0_5 != 0.0) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", d_pvt_solver->galileo_iono); + LOG(INFO) << "Saved Galileo ionospheric model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save Galileo ionospheric model parameters, not valid data"; + } + + // save GPS almanac to XML file + file_name = xml_base_path + "gps_almanac.xml"; + if (d_pvt_solver->gps_almanac_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gps_almanac_map", d_pvt_solver->gps_almanac_map); + LOG(INFO) << "Saved GPS almanac map data"; + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS almanac, map is empty"; + } + + // Save Galileo almanac + file_name = xml_base_path + "gal_almanac.xml"; + if (d_pvt_solver->galileo_almanac_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_almanac_map", d_pvt_solver->galileo_almanac_map); + LOG(INFO) << "Saved Galileo almanac data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save Galileo almanac, not valid data"; + } + + // Save GPS CNAV UTC model parameters + file_name = xml_base_path + "gps_cnav_utc_model.xml"; + if (d_pvt_solver->gps_cnav_utc_model.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_cnav_utc_model", d_pvt_solver->gps_cnav_utc_model); + LOG(INFO) << "Saved GPS CNAV UTC model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GPS CNAV UTC model parameters, not valid data"; + } + + // save GLONASS GNAV ephemeris to XML file + file_name = xml_base_path + "glo_gnav_ephemeris.xml"; + if (d_pvt_solver->glonass_gnav_ephemeris_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", d_pvt_solver->glonass_gnav_ephemeris_map); + LOG(INFO) << "Saved GLONASS GNAV ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GLONASS GNAV ephemeris, map is empty"; + } + + // save GLONASS UTC model parameters to XML file + file_name = xml_base_path + "glo_utc_model.xml"; + if (d_pvt_solver->glonass_gnav_utc_model.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gnav_utc_model", d_pvt_solver->glonass_gnav_utc_model); + LOG(INFO) << "Saved GLONASS UTC model parameters"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(INFO) << "Failed to save GLONASS GNAV ephemeris, not valid data"; + } + } +} + + +bool rtklib_pvt_cc::observables_pairCompare_min(const std::pair& a, const std::pair& b) +{ + return (a.second.Pseudorange_m) < (b.second.Pseudorange_m); +} + + +bool rtklib_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) +{ + // Fill Sys V message structures + int msgsend_size; + ttff_msgbuf msg; + msg.ttff = ttff.ttff; + msgsend_size = sizeof(msg.ttff); + msg.mtype = 1; // default message ID + + // SEND SOLUTION OVER A MESSAGE QUEUE + // non-blocking Sys V message send + msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); + return true; +} + + +bool rtklib_pvt_cc::save_gnss_synchro_map_xml(const std::string& file_name) +{ + if (gnss_observables_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gnss_synchro_map", gnss_observables_map); + LOG(INFO) << "Saved gnss_sychro map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + return true; + } + + LOG(WARNING) << "Failed to save gnss_synchro, map is empty"; + return false; +} + + +bool rtklib_pvt_cc::load_gnss_synchro_map_xml(const std::string& file_name) +{ + // load from xml (boost serialize) + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gnss_observables_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gnss_synchro_map", gnss_observables_map); + //std::cout << "Loaded gnss_synchro map data with " << gnss_synchro_map.size() << " pseudoranges" << std::endl; + } + catch (std::exception& e) + { + std::cout << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool rtklib_pvt_cc::get_latest_PVT(double* longitude_deg, + double* latitude_deg, + double* height_m, + double* ground_speed_kmh, + double* course_over_ground_deg, + time_t* UTC_time) +{ + gr::thread::scoped_lock lock(d_setlock); + if (d_pvt_solver->is_valid_position()) + { + *latitude_deg = d_pvt_solver->get_latitude(); + *longitude_deg = d_pvt_solver->get_longitude(); + *height_m = d_pvt_solver->get_height(); + *ground_speed_kmh = d_pvt_solver->get_speed_over_ground() * 3600.0 / 1000.0; + *course_over_ground_deg = d_pvt_solver->get_course_over_ground(); + *UTC_time = to_time_t(d_pvt_solver->get_position_UTC_time()); + + return true; + } + + return false; +} + + +int rtklib_pvt_cc::work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + gr::thread::scoped_lock l(d_setlock); + + for (int32_t epoch = 0; epoch < noutput_items; epoch++) + { + bool flag_display_pvt = false; + bool flag_compute_pvt_output = false; + bool flag_write_RTCM_1019_output = false; + bool flag_write_RTCM_1020_output = false; + bool flag_write_RTCM_1045_output = false; + bool flag_write_RTCM_MSM_output = false; + bool flag_write_RINEX_obs_output = false; + bool flag_write_RINEX_nav_output = false; + + gnss_observables_map.clear(); + const Gnss_Synchro** in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + // ############ 1. READ PSEUDORANGES #### + for (uint32_t i = 0; i < d_nchannels; i++) + { + if (in[i][epoch].Flag_valid_pseudorange) + { + std::map::const_iterator tmp_eph_iter_gps = d_pvt_solver->gps_ephemeris_map.find(in[i][epoch].PRN); + std::map::const_iterator tmp_eph_iter_gal = d_pvt_solver->galileo_ephemeris_map.find(in[i][epoch].PRN); + std::map::const_iterator tmp_eph_iter_cnav = d_pvt_solver->gps_cnav_ephemeris_map.find(in[i][epoch].PRN); + std::map::const_iterator tmp_eph_iter_glo_gnav = d_pvt_solver->glonass_gnav_ephemeris_map.find(in[i][epoch].PRN); + if (((tmp_eph_iter_gps->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "1C")) or + ((tmp_eph_iter_cnav->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "2S")) or + ((tmp_eph_iter_gal->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "1B")) or + ((tmp_eph_iter_gal->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "5X")) or + ((tmp_eph_iter_glo_gnav->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "1G")) or + ((tmp_eph_iter_glo_gnav->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "2G")) or + ((tmp_eph_iter_cnav->second.i_satellite_PRN == in[i][epoch].PRN) and (std::string(in[i][epoch].Signal) == "L5"))) + { + // store valid observables in a map. + gnss_observables_map.insert(std::pair(i, in[i][epoch])); + } + if (b_rtcm_enabled) + { + try + { + if (d_pvt_solver->gps_ephemeris_map.empty() == false) + { + if (tmp_eph_iter_gps != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->lock_time(d_pvt_solver->gps_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time + } + } + if (d_pvt_solver->galileo_ephemeris_map.empty() == false) + { + if (tmp_eph_iter_gal != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->lock_time(d_pvt_solver->galileo_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time + } + } + if (d_pvt_solver->gps_cnav_ephemeris_map.empty() == false) + { + if (tmp_eph_iter_cnav != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + d_rtcm_printer->lock_time(d_pvt_solver->gps_cnav_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time + } + } + if (d_pvt_solver->glonass_gnav_ephemeris_map.empty() == false) + { + if (tmp_eph_iter_glo_gnav != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->lock_time(d_pvt_solver->glonass_gnav_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time + } + } + } + catch (const boost::exception& ex) + { + std::cout << "RTCM boost exception: " << boost::diagnostic_information(ex) << std::endl; + LOG(ERROR) << "RTCM boost exception: " << boost::diagnostic_information(ex); + } + catch (const std::exception& ex) + { + std::cout << "RTCM std exception: " << ex.what() << std::endl; + LOG(ERROR) << "RTCM std exception: " << ex.what(); + } + } + } + } + + // ############ 2 COMPUTE THE PVT ################################ + if (gnss_observables_map.empty() == false) + { + double current_RX_time = gnss_observables_map.begin()->second.RX_time; + auto current_RX_time_ms = static_cast(current_RX_time * 1000.0); + if (current_RX_time_ms % d_output_rate_ms == 0) + { + flag_compute_pvt_output = true; + d_rx_time = current_RX_time; + // std::cout.precision(17); + // std::cout << "current_RX_time: " << current_RX_time << " map time: " << gnss_observables_map.begin()->second.RX_time << std::endl; + } + + // compute on the fly PVT solution + if (flag_compute_pvt_output == true) + { + // receiver clock correction is disabled to be coherent with the RINEX and RTCM standard + // std::cout << TEXT_RED << "(internal) accumulated RX clock offset: " << d_pvt_solver->get_time_offset_s() << "[s]" << TEXT_RESET << std::endl; + // for (std::map::iterator it = gnss_observables_map.begin(); it != gnss_observables_map.cend(); ++it) + // { + // todo: check if it has effect to correct the receiver time for the internal pvt solution + // take into account that the RINEX obs with the RX time (integer ms) CAN NOT be corrected to keep the coherence in obs time + // it->second.Pseudorange_m = it->second.Pseudorange_m - d_pvt_solver->get_time_offset_s() * GPS_C_m_s; + // } + + if (d_pvt_solver->get_PVT(gnss_observables_map, false)) + { + //Optional debug code: export observables snapshot for rtklib unit testing + //std::cout << "step 1: save gnss_synchro map" << std::endl; + //save_gnss_synchro_map_xml("./gnss_synchro_map.xml"); + //getchar(); //stop the execution + //end debug + if (d_display_rate_ms != 0) + { + if (current_RX_time_ms % d_display_rate_ms == 0) + { + flag_display_pvt = true; + } + } + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + if (current_RX_time_ms % d_rtcm_MT1019_rate_ms == 0) + { + flag_write_RTCM_1019_output = true; + } + } + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + if (current_RX_time_ms % d_rtcm_MT1020_rate_ms == 0) + { + flag_write_RTCM_1020_output = true; + } + } + if (d_rtcm_MT1045_rate_ms != 0) + { + if (current_RX_time_ms % d_rtcm_MT1045_rate_ms == 0) + { + flag_write_RTCM_1045_output = true; + } + } + // TODO: RTCM 1077, 1087 and 1097 are not used, so, disable the output rates + // if (current_RX_time_ms % d_rtcm_MT1077_rate_ms==0 and d_rtcm_MT1077_rate_ms != 0) + // { + // last_RTCM_1077_output_time = current_RX_time; + // } + // if (current_RX_time_ms % d_rtcm_MT1087_rate_ms==0 and d_rtcm_MT1087_rate_ms != 0) + // { + // last_RTCM_1087_output_time = current_RX_time; + // } + // if (current_RX_time_ms % d_rtcm_MT1097_rate_ms==0 and d_rtcm_MT1097_rate_ms != 0) + // { + // last_RTCM_1097_output_time = current_RX_time; + // } + if (d_rtcm_MSM_rate_ms != 0) + { + if (current_RX_time_ms % d_rtcm_MSM_rate_ms == 0) + { + flag_write_RTCM_MSM_output = true; + } + } + if (d_rinexobs_rate_ms != 0) + { + if (current_RX_time_ms % static_cast(d_rinexobs_rate_ms) == 0) + { + flag_write_RINEX_obs_output = true; + } + } + if (d_rinexnav_rate_ms != 0) + { + if (current_RX_time_ms % static_cast(d_rinexnav_rate_ms) == 0) + { + flag_write_RINEX_nav_output = true; + } + } + + if (first_fix == true) + { + std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_pvt_solver->get_position_UTC_time()) + << " UTC is Lat = " << d_pvt_solver->get_latitude() << " [deg], Long = " << d_pvt_solver->get_longitude() + << " [deg], Height= " << d_pvt_solver->get_height() << " [m]" << std::endl; + ttff_msgbuf ttff; + ttff.mtype = 1; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + ttff.ttff = elapsed_seconds.count(); + send_sys_v_ttff_msg(ttff); + first_fix = false; + } + if (d_kml_output_enabled) d_kml_dump->print_position(d_pvt_solver, false); + if (d_gpx_output_enabled) d_gpx_dump->print_position(d_pvt_solver, false); + if (d_geojson_output_enabled) d_geojson_printer->print_position(d_pvt_solver, false); + if (d_nmea_output_file_enabled) d_nmea_printer->Print_Nmea_Line(d_pvt_solver, false); + + /* + * TYPE | RECEIVER + * 0 | Unknown + * 1 | GPS L1 C/A + * 2 | GPS L2C + * 3 | GPS L5 + * 4 | Galileo E1B + * 5 | Galileo E5a + * 6 | Galileo E5b + * 7 | GPS L1 C/A + GPS L2C + * 8 | GPS L1 C/A + GPS L5 + * 9 | GPS L1 C/A + Galileo E1B + * 10 | GPS L1 C/A + Galileo E5a + * 11 | GPS L1 C/A + Galileo E5b + * 12 | Galileo E1B + GPS L2C + * 13 | Galileo E1B + GPS L5 + * 14 | Galileo E1B + Galileo E5a + * 15 | Galileo E1B + Galileo E5b + * 16 | GPS L2C + GPS L5 + * 17 | GPS L2C + Galileo E5a + * 18 | GPS L2C + Galileo E5b + * 19 | GPS L5 + Galileo E5a + * 20 | GPS L5 + Galileo E5b + * 21 | GPS L1 C/A + Galileo E1B + GPS L2C + * 22 | GPS L1 C/A + Galileo E1B + GPS L5 + * 23 | GLONASS L1 C/A + * 24 | GLONASS L2 C/A + * 25 | GLONASS L1 C/A + GLONASS L2 C/A + * 26 | GPS L1 C/A + GLONASS L1 C/A + * 27 | Galileo E1B + GLONASS L1 C/A + * 28 | GPS L2C + GLONASS L1 C/A + * 29 | GPS L1 C/A + GLONASS L2 C/A + * 30 | Galileo E1B + GLONASS L2 C/A + * 31 | GPS L2C + GLONASS L2 C/A + * 32 | GPS L1 C/A + Galileo E1B + GPS L5 + Galileo E5a + */ + + // ####################### RINEX FILES ################# + if (b_rinex_output_enabled) + { + std::map::const_iterator galileo_ephemeris_iter; + std::map::const_iterator gps_ephemeris_iter; + std::map::const_iterator gps_cnav_ephemeris_iter; + std::map::const_iterator glonass_gnav_ephemeris_iter; + if (!b_rinex_header_written) // & we have utc data in nav message! + { + galileo_ephemeris_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + gps_ephemeris_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + gps_cnav_ephemeris_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + glonass_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + switch (type_of_rx) + { + case 1: // GPS L1 C/A only + if (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, d_rx_time); + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 2: // GPS L2C only + if (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + std::string signal("2S"); + rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 3: // GPS L5 only + if (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + std::string signal("L5"); + rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 4: // Galileo E1B only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time); + rp->rinex_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 5: // Galileo E5a only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + std::string signal("5X"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 6: // Galileo E5b only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + std::string signal("7X"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 7: // GPS L1 C/A + GPS L2C + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + std::string signal("1C 2S"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 8: // GPS L1 + GPS L5 + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + std::string signal("1C L5"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 9: // GPS L1 C/A + Galileo E1B + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + std::string gal_signal("1B"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 10: // GPS L1 C/A + Galileo E5a + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + std::string gal_signal("5X"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 11: // GPS L1 C/A + Galileo E5b + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + std::string gal_signal("7X"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 13: // L5+E5a + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + std::string gal_signal("5X"); + std::string gps_signal("L5"); + rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gps_signal, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 14: // Galileo E1B + Galileo E5a + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string gal_signal("1B 5X"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 15: // Galileo E1B + Galileo E5b + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string gal_signal("1B 7X"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 23: // GLONASS L1 C/A only + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + std::string signal("1G"); + rp->rinex_obs_header(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, glonass_gnav_ephemeris_iter->second); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 24: // GLONASS L2 C/A only + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + std::string signal("2G"); + rp->rinex_obs_header(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, glonass_gnav_ephemeris_iter->second); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 25: // GLONASS L1 C/A + GLONASS L2 C/A + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + std::string signal("1G 2G"); + rp->rinex_obs_header(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, glonass_gnav_ephemeris_iter->second); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 26: // GPS L1 C/A + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + std::string glo_signal("1G"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal); + if (d_rinex_version == 3) + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + if (d_rinex_version == 2) + { + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model); + rp->rinex_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, glonass_gnav_ephemeris_iter->second); + } + b_rinex_header_written = true; // do not write header anymore + } + break; + case 27: // Galileo E1B + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string glo_signal("1G"); + std::string gal_signal("1B"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 28: // GPS L2C + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + std::string glo_signal("1G"); + rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 29: // GPS L1 C/A + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + std::string glo_signal("2G"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal); + if (d_rinex_version == 3) + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + if (d_rinex_version == 2) + { + rp->rinex_nav_header(rp->navFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model); + rp->rinex_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, glonass_gnav_ephemeris_iter->second); + } + b_rinex_header_written = true; // do not write header anymore + } + break; + case 30: // Galileo E1B + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string glo_signal("2G"); + std::string gal_signal("1B"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 31: // GPS L2C + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + std::string glo_signal("2G"); + rp->rinex_obs_header(rp->obsFile, gps_cnav_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 32: // L1+E1+L5+E5a + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and + (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) and + (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string gal_signal("1B 5X"); + std::string gps_signal("1C L5"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gps_signal, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + case 33: // L1+E1+E5a + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and + (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + std::string gal_signal("1B 5X"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_written = true; // do not write header anymore + } + break; + default: + break; + } + } + if (b_rinex_header_written) // The header is already written, we can now log the navigation message data + { + if (flag_write_RINEX_nav_output) + { + switch (type_of_rx) + { + case 1: // GPS L1 C/A only + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_ephemeris_map); + break; + case 2: // GPS L2C only + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_cnav_ephemeris_map); + break; + case 3: // GPS L5 only + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_cnav_ephemeris_map); + break; + case 4: + case 5: + case 6: + rp->log_rinex_nav(rp->navGalFile, d_pvt_solver->galileo_ephemeris_map); + break; + case 7: // GPS L1 C/A + GPS L2C + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_cnav_ephemeris_map); + break; + case 8: // L1+L5 + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_ephemeris_map); + break; + case 9: + case 10: + case 11: + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_ephemeris_map, d_pvt_solver->galileo_ephemeris_map); + break; + case 13: // L5+E5a + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_cnav_ephemeris_map, d_pvt_solver->galileo_ephemeris_map); + break; + case 14: + case 15: + rp->log_rinex_nav(rp->navGalFile, d_pvt_solver->galileo_ephemeris_map); + break; + case 23: + case 24: + case 25: + rp->log_rinex_nav(rp->navGloFile, d_pvt_solver->glonass_gnav_ephemeris_map); + break; + case 26: // GPS L1 C/A + GLONASS L1 C/A + if (d_rinex_version == 3) + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + if (d_rinex_version == 2) + { + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_ephemeris_map); + rp->log_rinex_nav(rp->navGloFile, d_pvt_solver->glonass_gnav_ephemeris_map); + } + break; + case 27: // Galileo E1B + GLONASS L1 C/A + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->galileo_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + break; + case 28: // GPS L2C + GLONASS L1 C/A + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_cnav_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + break; + case 29: // GPS L1 C/A + GLONASS L2 C/A + if (d_rinex_version == 3) + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + if (d_rinex_version == 2) + { + rp->log_rinex_nav(rp->navFile, d_pvt_solver->gps_ephemeris_map); + rp->log_rinex_nav(rp->navGloFile, d_pvt_solver->glonass_gnav_ephemeris_map); + } + break; + case 30: // Galileo E1B + GLONASS L2 C/A + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->galileo_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + break; + case 31: // GPS L2C + GLONASS L2 C/A + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_cnav_ephemeris_map, d_pvt_solver->glonass_gnav_ephemeris_map); + break; + case 32: // L1+E1+L5+E5a + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_ephemeris_map, d_pvt_solver->galileo_ephemeris_map); + break; + case 33: // L1+E1+E5a + rp->log_rinex_nav(rp->navMixFile, d_pvt_solver->gps_ephemeris_map, d_pvt_solver->galileo_ephemeris_map); + break; + default: + break; + } + } + galileo_ephemeris_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + gps_ephemeris_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + gps_cnav_ephemeris_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + glonass_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + + // Log observables into the RINEX file + if (flag_write_RINEX_obs_output) + { + switch (type_of_rx) + { + case 1: // GPS L1 C/A only + if (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_utc_model, d_pvt_solver->gps_iono); + b_rinex_header_updated = true; + } + break; + case 2: // GPS L2C only + if (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->gps_cnav_iono); + b_rinex_header_updated = true; + } + break; + case 3: // GPS L5 + if (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->gps_cnav_iono); + b_rinex_header_updated = true; + } + break; + case 4: // Galileo E1B only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B"); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 5: // Galileo E5a only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "5X"); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 6: // Galileo E5b only + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "7X"); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 7: // GPS L1 C/A + GPS L2C + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_utc_model, d_pvt_solver->gps_iono); + b_rinex_header_updated = true; + } + break; + case 8: // L1+L5 + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and ((d_pvt_solver->gps_cnav_utc_model.d_A0 != 0) or (d_pvt_solver->gps_utc_model.d_A0 != 0))) + { + if (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->gps_cnav_iono); + } + else + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navFile, d_pvt_solver->gps_utc_model, d_pvt_solver->gps_iono); + } + b_rinex_header_updated = true; + } + break; + case 9: // GPS L1 C/A + Galileo E1B + if ((galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 13: // L5+E5a + if ((gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0) and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->gps_cnav_iono, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 14: // Galileo E1B + Galileo E5a + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B 5X"); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 15: // Galileo E1B + Galileo E5b + if (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1B 7X"); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_nav_header(rp->navGalFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; + } + break; + case 23: // GLONASS L1 C/A only + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1C"); + } + if (!b_rinex_header_updated and (d_pvt_solver->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_pvt_solver->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + break; + case 24: // GLONASS L2 C/A only + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "2C"); + } + if (!b_rinex_header_updated and (d_pvt_solver->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navGloFile, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_pvt_solver->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + break; + case 25: // GLONASS L1 C/A + GLONASS L2 C/A + if (glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1C 2C"); + } + if (!b_rinex_header_updated and (d_pvt_solver->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navMixFile, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_pvt_solver->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + break; + case 26: // GPS L1 C/A + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 27: // Galileo E1B + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 28: // GPS L2C + GLONASS L1 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 29: // GPS L1 C/A + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 30: // Galileo E1B + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->galileo_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 31: // GPS L2C + GLONASS L2 C/A + if ((glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_cnav_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_iono, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->glonass_gnav_utc_model, d_pvt_solver->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 32: // L1+E1+L5+E5a + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_ephemeris_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and ((d_pvt_solver->gps_cnav_utc_model.d_A0 != 0) or (d_pvt_solver->gps_utc_model.d_A0 != 0)) and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + if (d_pvt_solver->gps_cnav_utc_model.d_A0 != 0) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_cnav_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_cnav_utc_model, d_pvt_solver->gps_cnav_iono, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + } + else + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + } + b_rinex_header_updated = true; // do not write header anymore + } + break; + case 33: // L1+E1+E5a + if ((gps_ephemeris_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (galileo_ephemeris_iter != d_pvt_solver->galileo_ephemeris_map.cend())) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated and (d_pvt_solver->gps_utc_model.d_A0 != 0) and (d_pvt_solver->galileo_utc_model.A0_6 != 0)) + { + rp->update_obs_header(rp->obsFile, d_pvt_solver->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_pvt_solver->gps_iono, d_pvt_solver->gps_utc_model, d_pvt_solver->galileo_iono, d_pvt_solver->galileo_utc_model); + b_rinex_header_updated = true; // do not write header anymore + } + break; + default: + break; + } + } + } + } + + // ####################### RTCM MESSAGES ################# + try + { + if (b_rtcm_writing_started and b_rtcm_enabled) + { + switch (type_of_rx) + { + case 1: // GPS L1 C/A + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 4: + case 5: + case 6: + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 7: // GPS L1 C/A + GPS L2C + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + if ((gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, gps_cnav_eph_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 8: // L1+L5 + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + if ((gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, gps_cnav_eph_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 9: // GPS L1 C/A + Galileo E1B + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + int gps_channel = 0; + int gal_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (gal_channel == 0) + { + if (system == "E") + { + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 13: // L5+E5a + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + + if (flag_write_RTCM_MSM_output and d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + int gal_channel = 0; + int gps_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (gal_channel == 0) + { + if (system == "E") + { + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + } + + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend() and (d_rtcm_MT1097_rate_ms != 0)) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend() and (d_rtcm_MT1077_rate_ms != 0)) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, gps_cnav_eph_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 14: + case 15: + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 23: + case 24: + case 25: + if (flag_write_RTCM_1020_output == true) + { + for (std::map::const_iterator glonass_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_ephemeris_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_ephemeris_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator glo_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + if (glo_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glo_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 26: // GPS L1 C/A + GLONASS L1 C/A + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_1020_output == true) + { + for (std::map::const_iterator glonass_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_ephemeris_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_ephemeris_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + int gps_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 27: // GLONASS L1 C/A + Galileo E1B + if (flag_write_RTCM_1020_output == true) + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + int gal_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + // This is a channel with valid GPS signal + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 29: // GPS L1 C/A + GLONASS L2 C/A + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_1020_output == true) + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + int gps_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 30: // GLONASS L2 C/A + Galileo E1B + if (flag_write_RTCM_1020_output == true) + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + int gal_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + // This is a channel with valid GPS signal + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + case 32: // L1+E1+L5+E5a + if (flag_write_RTCM_1019_output == true) + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (flag_write_RTCM_1045_output == true) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (flag_write_RTCM_MSM_output == true) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + int gal_channel = 0; + int gps_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + // This is a channel with valid GPS signal + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + if (gps_channel == 0) + { + if (system == "G") + { + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + break; + default: + break; + } + } + + if (!b_rtcm_writing_started and b_rtcm_enabled) // the first time + { + switch (type_of_rx) + { + case 1: // GPS L1 C/A + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 4: + case 5: + case 6: + if (d_rtcm_MT1045_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 7: // GPS L1 C/A + GPS L2C + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + if ((gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, gps_cnav_eph_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 8: // L1+L5 + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator gps_cnav_eph_iter = d_pvt_solver->gps_cnav_ephemeris_map.cbegin(); + if ((gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) and (gps_cnav_eph_iter != d_pvt_solver->gps_cnav_ephemeris_map.cend())) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, gps_cnav_eph_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 9: // GPS L1 C/A + Galileo E1B + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MT1045_rate_ms != 0) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + int gps_channel = 0; + int gal_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (gal_channel == 0) + { + if (system == "E") + { + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + + case 13: // L5+E5a + if (d_rtcm_MT1045_rate_ms != 0) + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + int gal_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + } + + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend() and (d_rtcm_MT1097_rate_ms != 0)) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 14: + case 15: + if (d_rtcm_MT1045_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 23: + case 24: + case 25: + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator glo_gnav_ephemeris_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + if (glo_gnav_ephemeris_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glo_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 26: // GPS L1 C/A + GLONASS L1 C/A + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + int gps_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 27: // GLONASS L1 C/A + Galileo E1B + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (d_rtcm_MT1045_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + int gal_channel = 0; + int glo_channel = 0; + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + // This is a channel with valid GPS signal + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 29: // GPS L1 C/A + GLONASS L2 C/A + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + std::map::const_iterator gnss_observables_iter; + int gps_channel = 0; + int glo_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 30: // GLONASS L2 C/A + Galileo E1B + if (d_rtcm_MT1020_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend(); glonass_gnav_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_eph_iter->second, d_pvt_solver->glonass_gnav_utc_model); + } + } + if (d_rtcm_MT1045_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + int gal_channel = 0; + int glo_channel = 0; + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.cbegin(); + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gal_channel == 0) + { + if (system == "E") + { + // This is a channel with valid GPS signal + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + if (glo_channel == 0) + { + if (system == "R") + { + glonass_gnav_eph_iter = d_pvt_solver->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + glo_channel = 1; + } + } + } + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (glonass_gnav_eph_iter != d_pvt_solver->glonass_gnav_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_eph_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + case 32: // L1+E1+L5+E5a + if (d_rtcm_MT1019_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend(); gps_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_eph_iter->second); + } + } + if (d_rtcm_MT1045_rate_ms != 0) // allows deactivating messages by setting rate = 0 + { + for (std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend(); gal_eph_iter++) + { + d_rtcm_printer->Print_Rtcm_MT1045(gal_eph_iter->second); + } + } + if (d_rtcm_MSM_rate_ms != 0) + { + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.cbegin(); + std::map::const_iterator gps_eph_iter = d_pvt_solver->gps_ephemeris_map.cbegin(); + int gps_channel = 0; + int gal_channel = 0; + for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if (gps_channel == 0) + { + if (system == "G") + { + // This is a channel with valid GPS signal + gps_eph_iter = d_pvt_solver->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + gps_channel = 1; + } + } + } + if (gal_channel == 0) + { + if (system == "E") + { + gal_eph_iter = d_pvt_solver->galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + gal_channel = 1; + } + } + } + } + if (gps_eph_iter != d_pvt_solver->gps_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_eph_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + if (gal_eph_iter != d_pvt_solver->galileo_ephemeris_map.cend()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_eph_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + b_rtcm_writing_started = true; + break; + default: + break; + } + } + } + catch (const boost::exception& ex) + { + std::cout << "RTCM boost exception: " << boost::diagnostic_information(ex) << std::endl; + LOG(ERROR) << "RTCM boost exception: " << boost::diagnostic_information(ex); + } + catch (const std::exception& ex) + { + std::cout << "RTCM std exception: " << ex.what() << std::endl; + LOG(ERROR) << "RTCM std exception: " << ex.what(); + } + } + } + + // DEBUG MESSAGE: Display position in console output + if (d_pvt_solver->is_valid_position() and flag_display_pvt) + { + std::streamsize ss = std::cout.precision(); // save current precision + std::cout.setf(std::ios::fixed, std::ios::floatfield); + auto facet = new boost::posix_time::time_facet("%Y-%b-%d %H:%M:%S.%f %z"); + std::cout.imbue(std::locale(std::cout.getloc(), facet)); + + std::cout << TEXT_BOLD_GREEN + << "Position at " << d_pvt_solver->get_position_UTC_time() + << " UTC using " << d_pvt_solver->get_num_valid_observations() + << std::fixed << std::setprecision(9) + << " observations is Lat = " << d_pvt_solver->get_latitude() << " [deg], Long = " << d_pvt_solver->get_longitude() + << std::fixed << std::setprecision(3) + << " [deg], Height = " << d_pvt_solver->get_height() << " [m]" << TEXT_RESET << std::endl; + std::cout << std::setprecision(ss); + DLOG(INFO) << "RX clock offset: " << d_pvt_solver->get_time_offset_s() << "[s]"; + + // boost::posix_time::ptime p_time; + // gtime_t rtklib_utc_time = gpst2time(adjgpsweek(d_pvt_solver->gps_ephemeris_map.cbegin()->second.i_GPS_week), d_rx_time); + // p_time = boost::posix_time::from_time_t(rtklib_utc_time.time); + // p_time += boost::posix_time::microseconds(round(rtklib_utc_time.sec * 1e6)); + // std::cout << TEXT_MAGENTA << "Observable RX time (GPST) " << boost::posix_time::to_simple_string(p_time) << TEXT_RESET << std::endl; + + DLOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_pvt_solver->get_position_UTC_time()) + << " UTC using " << d_pvt_solver->get_num_valid_observations() << " observations is Lat = " << d_pvt_solver->get_latitude() << " [deg], Long = " << d_pvt_solver->get_longitude() + << " [deg], Height = " << d_pvt_solver->get_height() << " [m]"; + + /* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_pvt_solver->get_position_UTC_time()) + << " UTC using "<< d_pvt_solver->get_num_valid_observations() <<" observations is HDOP = " << d_pvt_solver->get_hdop() << " VDOP = " + << d_pvt_solver->get_vdop() + << " GDOP = " << d_pvt_solver->get_gdop() << std::endl; */ + } + } + } + + return noutput_items; +} diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h new file mode 100644 index 000000000..3aec0b868 --- /dev/null +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h @@ -0,0 +1,186 @@ +/*! + * \file rtklib_pvt_cc.h + * \brief Interface of a Position Velocity and Time computation block + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_RTKLIB_PVT_CC_H +#define GNSS_SDR_RTKLIB_PVT_CC_H + +#include "geojson_printer.h" +#include "gps_ephemeris.h" +#include "gpx_printer.h" +#include "kml_printer.h" +#include "nmea_printer.h" +#include "pvt_conf.h" +#include "rinex_printer.h" +#include "rtcm_printer.h" +#include "rtklib_solver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class rtklib_pvt_cc; + +typedef boost::shared_ptr rtklib_pvt_cc_sptr; + +rtklib_pvt_cc_sptr rtklib_make_pvt_cc(uint32_t n_channels, + const Pvt_Conf& conf_, + const rtk_t& rtk); + +/*! + * \brief This class implements a block that computes the PVT solution using the RTKLIB integrated library + */ +class rtklib_pvt_cc : public gr::sync_block +{ +private: + friend rtklib_pvt_cc_sptr rtklib_make_pvt_cc(uint32_t nchannels, + const Pvt_Conf& conf_, + const rtk_t& rtk); + + void msg_handler_telemetry(pmt::pmt_t msg); + + bool d_dump; + bool d_dump_mat; + bool b_rinex_output_enabled; + bool b_rinex_header_written; + bool b_rinex_header_updated; + double d_rinex_version; + int32_t d_rinexobs_rate_ms; + int32_t d_rinexnav_rate_ms; + + bool b_rtcm_writing_started; + bool b_rtcm_enabled; + int32_t d_rtcm_MT1045_rate_ms; //!< Galileo Broadcast Ephemeris + int32_t d_rtcm_MT1019_rate_ms; //!< GPS Broadcast Ephemeris (orbits) + int32_t d_rtcm_MT1020_rate_ms; //!< GLONASS Broadcast Ephemeris (orbits) + int32_t d_rtcm_MT1077_rate_ms; //!< The type 7 Multiple Signal Message format for the USA’s GPS system, popular + int32_t d_rtcm_MT1087_rate_ms; //!< GLONASS MSM7. The type 7 Multiple Signal Message format for the Russian GLONASS system + int32_t d_rtcm_MT1097_rate_ms; //!< Galileo MSM7. The type 7 Multiple Signal Message format for Europe’s Galileo system + int32_t d_rtcm_MSM_rate_ms; + + int32_t d_last_status_print_seg; //for status printer + + uint32_t d_nchannels; + std::string d_dump_filename; + + int32_t d_output_rate_ms; + int32_t d_display_rate_ms; + + std::shared_ptr rp; + std::shared_ptr d_kml_dump; + std::shared_ptr d_gpx_dump; + std::shared_ptr d_nmea_printer; + std::shared_ptr d_geojson_printer; + std::shared_ptr d_rtcm_printer; + double d_rx_time; + + bool d_geojson_output_enabled; + bool d_gpx_output_enabled; + bool d_kml_output_enabled; + bool d_nmea_output_file_enabled; + + std::shared_ptr d_pvt_solver; + + std::map gnss_observables_map; + bool observables_pairCompare_min(const std::pair& a, const std::pair& b); + + uint32_t type_of_rx; + + bool first_fix; + key_t sysv_msg_key; + int sysv_msqid; + typedef struct + { + long mtype; //required by sys v message + double ttff; + } ttff_msgbuf; + bool send_sys_v_ttff_msg(ttff_msgbuf ttff); + std::chrono::time_point start, end; + + bool save_gnss_synchro_map_xml(const std::string& file_name); //debug helper function + + bool load_gnss_synchro_map_xml(const std::string& file_name); //debug helper function + + bool d_xml_storage; + std::string xml_base_path; + + inline std::time_t to_time_t(boost::posix_time::ptime pt) + { + return (pt - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); + } + + +public: + rtklib_pvt_cc(uint32_t nchannels, + const Pvt_Conf& conf_, + const rtk_t& rtk); + + /*! + * \brief Get latest set of ephemeris from PVT block + * + */ + std::map get_gps_ephemeris_map() const; + + std::map get_gps_almanac_map() const; + + std::map get_galileo_ephemeris_map() const; + + std::map get_galileo_almanac_map() const; + + /*! + * \brief Clear all ephemeris information and the almanacs for GPS and Galileo + * + */ + void clear_ephemeris(); + + /*! + * \brief Get the latest Position WGS84 [deg], Ground Velocity, Course over Ground, and UTC Time, if available + */ + bool get_latest_PVT(double* longitude_deg, + double* latitude_deg, + double* height_m, + double* ground_speed_kmh, + double* course_over_ground_deg, + time_t* UTC_time); + + ~rtklib_pvt_cc(); //!< Default destructor + + int work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); //!< PVT Signal Processing +}; + +#endif diff --git a/src/algorithms/PVT/libs/CMakeLists.txt b/src/algorithms/PVT/libs/CMakeLists.txt index b3b323d16..25a4c592a 100644 --- a/src/algorithms/PVT/libs/CMakeLists.txt +++ b/src/algorithms/PVT/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,38 +13,81 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -add_definitions( -DGNSS_SDR_VERSION="${VERSION}" ) +add_definitions(-DGNSS_SDR_VERSION="${VERSION}") -set(PVT_LIB_SOURCES - pvt_solution.cc - ls_pvt.cc - gps_l1_ca_ls_pvt.cc - galileo_e1_ls_pvt.cc - hybrid_ls_pvt.cc - kml_printer.cc - rinex_printer.cc - nmea_printer.cc - rtcm_printer.cc - geojson_printer.cc +set(PVT_LIB_SOURCES + pvt_solution.cc + ls_pvt.cc + hybrid_ls_pvt.cc + kml_printer.cc + gpx_printer.cc + rinex_printer.cc + nmea_printer.cc + rtcm_printer.cc + geojson_printer.cc + rtklib_solver.cc + pvt_conf.cc +) + +set(PVT_LIB_HEADERS + pvt_solution.h + ls_pvt.h + hybrid_ls_pvt.h + kml_printer.h + gpx_printer.h + rinex_printer.h + nmea_printer.h + rtcm_printer.h + geojson_printer.h + rtklib_solver.h + pvt_conf.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/adapters - ${Boost_INCLUDE_DIRS} - ${ARMADILLO_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${Boost_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} ) -file(GLOB PVT_LIB_HEADERS "*.h") + list(SORT PVT_LIB_HEADERS) +list(SORT PVT_LIB_SOURCES) + add_library(pvt_lib ${PVT_LIB_SOURCES} ${PVT_LIB_HEADERS}) source_group(Headers FILES ${PVT_LIB_HEADERS}) -add_dependencies(pvt_lib armadillo-${armadillo_RELEASE} glog-${glog_RELEASE}) -target_link_libraries(pvt_lib ${Boost_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${ARMADILLO_LIBRARIES}) + +if(MATIO_FOUND) + add_dependencies(pvt_lib + glog-${glog_RELEASE} + armadillo-${armadillo_RELEASE} + ) +else() + add_dependencies(pvt_lib + glog-${glog_RELEASE} + armadillo-${armadillo_RELEASE} + matio-${GNSSSDR_MATIO_LOCAL_VERSION} + ) +endif() + +target_link_libraries(pvt_lib + rtklib_lib + gnss_sdr_flags + gnss_sp_libs + ${Boost_LIBRARIES} + ${GLOG_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${BLAS} + ${LAPACK} + ${MATIO_LIBRARIES} +) diff --git a/src/algorithms/PVT/libs/galileo_e1_ls_pvt.cc b/src/algorithms/PVT/libs/galileo_e1_ls_pvt.cc deleted file mode 100644 index 48b7d4db7..000000000 --- a/src/algorithms/PVT/libs/galileo_e1_ls_pvt.cc +++ /dev/null @@ -1,257 +0,0 @@ -/*! - * \file galileo_e1_ls_pvt.cc - * \brief Implementation of a Least Squares Position, Velocity, and Time - * (PVT) solver, based on K.Borre's Matlab receiver. - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e1_ls_pvt.h" -#include -#include "Galileo_E1.h" - - -using google::LogMessage; - -galileo_e1_ls_pvt::galileo_e1_ls_pvt(int nchannels, std::string dump_filename, bool flag_dump_to_file) : Ls_Pvt() -{ - // init empty ephemeris for all the available GNSS channels - d_nchannels = nchannels; - d_ephemeris = new Galileo_Navigation_Message[nchannels]; - d_dump_filename = dump_filename; - d_flag_dump_enabled = flag_dump_to_file; - d_galileo_current_time = 0; - d_flag_averaging = false; - - // ############# ENABLE DATA FILE LOG ################# - if (d_flag_dump_enabled == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT lib dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception opening PVT lib dump file " << e.what(); - } - } - } -} - - -galileo_e1_ls_pvt::~galileo_e1_ls_pvt() -{ - d_dump_file.close(); - delete[] d_ephemeris; -} - - - -bool galileo_e1_ls_pvt::get_PVT(std::map gnss_pseudoranges_map, double galileo_current_time, bool flag_averaging) -{ - std::map::iterator gnss_pseudoranges_iter; - std::map::iterator galileo_ephemeris_iter; - - arma::vec W; // channels weight vector - arma::vec obs; // pseudoranges observation vector - arma::mat satpos; // satellite positions matrix - - int Galileo_week_number = 0; - double utc = 0.0; - double GST = 0.0; - double TX_time_corrected_s = 0.0; - double SV_clock_bias_s = 0.0; - - d_flag_averaging = flag_averaging; - - // ******************************************************************************** - // ****** PREPARE THE LEAST SQUARES DATA (SV POSITIONS MATRIX AND OBS VECTORS) **** - // ******************************************************************************** - int valid_obs = 0; //valid observations counter - - for(gnss_pseudoranges_iter = gnss_pseudoranges_map.begin(); - gnss_pseudoranges_iter != gnss_pseudoranges_map.end(); - gnss_pseudoranges_iter++) - { - // 1- find the ephemeris for the current SV observation. The SV PRN ID is the map key - galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_pseudoranges_iter->first); - if (galileo_ephemeris_iter != galileo_ephemeris_map.end()) - { - /*! - * \todo Place here the satellite CN0 (power level, or weight factor) - */ - W.resize(valid_obs + 1, 1); - W(valid_obs) = 1; - - // COMMON RX TIME PVT ALGORITHM - double Rx_time = galileo_current_time; - double Tx_time = Rx_time - gnss_pseudoranges_iter->second.Pseudorange_m / GALILEO_C_m_s; - - // 2- compute the clock drift using the clock model (broadcast) for this SV, including relativistic effect - SV_clock_bias_s = galileo_ephemeris_iter->second.sv_clock_drift(Tx_time); - - // 3- compute the current ECEF position for this SV using corrected TX time - TX_time_corrected_s = Tx_time - SV_clock_bias_s; - galileo_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); - - //store satellite positions in a matrix - satpos.resize(3, valid_obs + 1); - satpos(0, valid_obs) = galileo_ephemeris_iter->second.d_satpos_X; - satpos(1, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Y; - satpos(2, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Z; - - // 4- fill the observations vector with the corrected pseudoranges - obs.resize(valid_obs + 1, 1); - obs(valid_obs) = gnss_pseudoranges_iter->second.Pseudorange_m + SV_clock_bias_s * GALILEO_C_m_s - d_rx_dt_s * GALILEO_C_m_s; - d_visible_satellites_IDs[valid_obs] = galileo_ephemeris_iter->second.i_satellite_PRN; - d_visible_satellites_CN0_dB[valid_obs] = gnss_pseudoranges_iter->second.CN0_dB_hz; - - - Galileo_week_number = galileo_ephemeris_iter->second.WN_5; //for GST - GST = galileo_ephemeris_map.find(gnss_pseudoranges_iter->first)->second.Galileo_System_Time(Galileo_week_number, galileo_current_time); - - // SV ECEF DEBUG OUTPUT - DLOG(INFO) << "ECEF satellite SV ID=" << galileo_ephemeris_iter->second.i_satellite_PRN - << " X=" << galileo_ephemeris_iter->second.d_satpos_X - << " [m] Y=" << galileo_ephemeris_iter->second.d_satpos_Y - << " [m] Z=" << galileo_ephemeris_iter->second.d_satpos_Z - << " [m] PR_obs=" << obs(valid_obs) << " [m]"; - - valid_obs++; - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV "<< gnss_pseudoranges_iter->first; - } - } - - // ******************************************************************************** - // ****** SOLVE LEAST SQUARES****************************************************** - // ******************************************************************************** - d_valid_observations = valid_obs; - LOG(INFO) << "Galileo PVT: valid observations=" << valid_obs; - - if (valid_obs >= 4) - { - arma::vec rx_position_and_time; - DLOG(INFO) << "satpos=" << satpos; - DLOG(INFO) << "obs="<< obs; - DLOG(INFO) << "W=" << W; - try - { - // check if this is the initial position computation - if (d_rx_dt_s == 0) - { - // execute Bancroft's algorithm to estimate initial receiver position and time - DLOG(INFO) << " Executing Bancroft algorithm..."; - rx_position_and_time = bancroftPos(satpos.t(), obs); - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s = rx_position_and_time(3) / GALILEO_C_m_s; // save time for the next iteration [meters]->[seconds] - } - // Execute WLS using previous position as the initialization point - rx_position_and_time = leastSquarePos(satpos, obs, W); - - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s += rx_position_and_time(3) / GALILEO_C_m_s; // accumulate the rx time error for the next iteration [meters]->[seconds] - - // Compute Gregorian time - utc = galileo_utc_model.GST_to_UTC_time(GST, Galileo_week_number); - // get time string Gregorian calendar - boost::posix_time::time_duration t = boost::posix_time::seconds(utc); - // 22 August 1999 00:00 last Galileo start GST epoch (ICD sec 5.1.2) - boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); - d_position_UTC_time = p_time; - - DLOG(INFO) << "Galileo Position at TOW=" << galileo_current_time << " in ECEF (X,Y,Z) = " << rx_position_and_time; - - cart2geo(static_cast(rx_position_and_time(0)), static_cast(rx_position_and_time(1)), static_cast(rx_position_and_time(2)), 4); - d_rx_dt_s = rx_position_and_time(3)/GALILEO_C_m_s; // Convert RX time offset from meters to seconds - DLOG(INFO) << "Galileo Position at " << boost::posix_time::to_simple_string(p_time) - << " is Lat = " << d_latitude_d << " [deg], Long = " << d_longitude_d - << " [deg], Height= " << d_height_m << " [m]" << " RX time offset= " << d_rx_dt_s << " [s]"; - - // ###### Compute DOPs ######## - compute_DOP(); - - // ######## LOG FILE ######### - if(d_flag_dump_enabled == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - // PVT GPS time - tmp_double = galileo_current_time; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position East [m] - tmp_double = rx_position_and_time(0); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position North [m] - tmp_double = rx_position_and_time(1); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position Up [m] - tmp_double = rx_position_and_time(2); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // User clock offset [s] - tmp_double = rx_position_and_time(3); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Latitude [deg] - tmp_double = d_latitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Longitude [deg] - tmp_double = d_longitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Height [m] - tmp_double = d_height_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing PVT LS dump file "<< e.what(); - } - } - - // MOVING AVERAGE PVT - galileo_e1_ls_pvt::pos_averaging(flag_averaging); - } - catch(const std::exception & e) - { - d_rx_dt_s = 0; //reset rx time estimation - LOG(WARNING) << "Problem with the solver, invalid solution!" << e.what(); - b_valid_position = false; - } - } - else - { - b_valid_position = false; - } - return b_valid_position; -} - diff --git a/src/algorithms/PVT/libs/galileo_e1_ls_pvt.h b/src/algorithms/PVT/libs/galileo_e1_ls_pvt.h deleted file mode 100644 index 2220847e5..000000000 --- a/src/algorithms/PVT/libs/galileo_e1_ls_pvt.h +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * \file galileo_e1_ls_pvt.h - * \brief Interface of a Least Squares Position, Velocity, and Time (PVT) - * solver, based on K.Borre's Matlab receiver. - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E1_LS_PVT_H_ -#define GNSS_SDR_GALILEO_E1_LS_PVT_H_ - -#include -#include -#include -#include -#include "ls_pvt.h" -#include "galileo_navigation_message.h" -#include "gnss_synchro.h" -#include "galileo_ephemeris.h" -#include "galileo_utc_model.h" - - -/*! - * \brief This class implements a simple PVT Least Squares solution - */ -class galileo_e1_ls_pvt : public Ls_Pvt -{ -public: - galileo_e1_ls_pvt(int nchannels,std::string dump_filename, bool flag_dump_to_file); - ~galileo_e1_ls_pvt(); - - bool get_PVT(std::map gnss_pseudoranges_map, double galileo_current_time, bool flag_averaging); - - int d_nchannels; //!< Number of available channels for positioning - - Galileo_Navigation_Message* d_ephemeris; - std::map galileo_ephemeris_map; //!< Map storing new Galileo_Ephemeris - Galileo_Utc_Model galileo_utc_model; - Galileo_Iono galileo_iono; - Galileo_Almanac galileo_almanac; - - double d_galileo_current_time; - - bool d_flag_dump_enabled; - bool d_flag_averaging; - - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif diff --git a/src/algorithms/PVT/libs/geojson_printer.cc b/src/algorithms/PVT/libs/geojson_printer.cc index 997992934..7f4da17c1 100644 --- a/src/algorithms/PVT/libs/geojson_printer.cc +++ b/src/algorithms/PVT/libs/geojson_printer.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,80 +24,113 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "geojson_printer.h" -#include +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem +#include #include #include -#include -GeoJSON_Printer::GeoJSON_Printer() + +GeoJSON_Printer::GeoJSON_Printer(const std::string& base_path) { first_pos = true; + geojson_base_path = base_path; + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(geojson_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(geojson_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + geojson_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + geojson_base_path = p.string(); + } + if (geojson_base_path != ".") + { + std::cout << "GeoJSON files will be stored at " << geojson_base_path << std::endl; + } + + geojson_base_path = geojson_base_path + boost::filesystem::path::preferred_separator; } - -GeoJSON_Printer::~GeoJSON_Printer () +GeoJSON_Printer::~GeoJSON_Printer() { GeoJSON_Printer::close_file(); } -bool GeoJSON_Printer::set_headers(std::string filename, bool time_tag_name) +bool GeoJSON_Printer::set_headers(const std::string& filename, bool time_tag_name) { - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); + boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); + tm timeinfo = boost::posix_time::to_tm(pt); if (time_tag_name) { std::stringstream strm0; - const int year = timeinfo->tm_year - 100; + const int year = timeinfo.tm_year - 100; strm0 << year; - const int month = timeinfo->tm_mon + 1; - if(month < 10) + const int month = timeinfo.tm_mon + 1; + if (month < 10) { strm0 << "0"; } strm0 << month; - const int day = timeinfo->tm_mday; - if(day < 10) + const int day = timeinfo.tm_mday; + if (day < 10) { strm0 << "0"; } strm0 << day << "_"; - const int hour = timeinfo->tm_hour; - if(hour < 10) + const int hour = timeinfo.tm_hour; + if (hour < 10) { strm0 << "0"; } strm0 << hour; - const int min = timeinfo->tm_min; - if(min < 10) + const int min = timeinfo.tm_min; + if (min < 10) { strm0 << "0"; } strm0 << min; - const int sec = timeinfo->tm_sec; - if(sec < 10) + const int sec = timeinfo.tm_sec; + if (sec < 10) { strm0 << "0"; } strm0 << sec; - filename_ = filename + "_" + strm0.str() + ".geojson"; + filename_ = filename + "_" + strm0.str() + ".geojson"; } else { filename_ = filename + ".geojson"; } + filename_ = geojson_base_path + filename_; geojson_file.open(filename_.c_str()); @@ -107,29 +140,25 @@ bool GeoJSON_Printer::set_headers(std::string filename, bool time_tag_name) DLOG(INFO) << "GeoJSON printer writing on " << filename.c_str(); // Set iostream numeric format and precision - geojson_file.setf(geojson_file.fixed, geojson_file.floatfield); + geojson_file.setf(geojson_file.std::ofstream::fixed, geojson_file.std::ofstream::floatfield); geojson_file << std::setprecision(14); // Writing the header geojson_file << "{" << std::endl; - geojson_file << " \"type\": \"Feature\"," << std::endl; + geojson_file << R"( "type": "Feature",)" << std::endl; geojson_file << " \"properties\": {" << std::endl; - geojson_file << " \"name\": \"Locations generated by GNSS-SDR\" " << std::endl; + geojson_file << R"( "name": "Locations generated by GNSS-SDR" )" << std::endl; geojson_file << " }," << std::endl; - - geojson_file << " \"geometry\": {" << std::endl; - geojson_file << " \"type\": \"MultiPoint\"," << std::endl; + geojson_file << R"( "type": "MultiPoint",)" << std::endl; geojson_file << " \"coordinates\": [" << std::endl; return true; } - else - { - return false; - } -} + std::cout << "File " << filename_ << " cannot be saved. Wrong permissions?" << std::endl; + return false; +} bool GeoJSON_Printer::print_position(const std::shared_ptr& position, bool print_average_values) @@ -138,19 +167,19 @@ bool GeoJSON_Printer::print_position(const std::shared_ptr& positi double longitude; double height; - std::shared_ptr position_ = position; + const std::shared_ptr& position_ = position; if (print_average_values == false) { - latitude = position_->d_latitude_d; - longitude = position_->d_longitude_d; - height = position_->d_height_m; + latitude = position_->get_latitude(); + longitude = position_->get_longitude(); + height = position_->get_height(); } else { - latitude = position_->d_avg_latitude_d; - longitude = position_->d_avg_longitude_d; - height = position_->d_avg_height_m; + latitude = position_->get_avg_latitude(); + longitude = position_->get_avg_longitude(); + height = position_->get_avg_height(); } if (geojson_file.is_open()) @@ -167,14 +196,10 @@ bool GeoJSON_Printer::print_position(const std::shared_ptr& positi } return true; } - else - { - return false; - } + return false; } - bool GeoJSON_Printer::close_file() { if (geojson_file.is_open()) @@ -188,15 +213,9 @@ bool GeoJSON_Printer::close_file() // if nothing is written, erase the file if (first_pos == true) { - if(remove(filename_.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(filename_.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } - return true; } - else - { - return false; - } + return false; } - - diff --git a/src/algorithms/PVT/libs/geojson_printer.h b/src/algorithms/PVT/libs/geojson_printer.h index b286e164a..b9bdcdb28 100644 --- a/src/algorithms/PVT/libs/geojson_printer.h +++ b/src/algorithms/PVT/libs/geojson_printer.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,10 @@ #ifndef GNSS_SDR_GEOJSON_PRINTER_H_ #define GNSS_SDR_GEOJSON_PRINTER_H_ +#include "pvt_solution.h" #include #include #include -#include "pvt_solution.h" /*! @@ -50,10 +50,12 @@ private: std::ofstream geojson_file; bool first_pos; std::string filename_; + std::string geojson_base_path; + public: - GeoJSON_Printer(); + GeoJSON_Printer(const std::string& base_path = "."); ~GeoJSON_Printer(); - bool set_headers(std::string filename, bool time_tag_name = true); + bool set_headers(const std::string& filename, bool time_tag_name = true); bool print_position(const std::shared_ptr& position, bool print_average_values); bool close_file(); }; diff --git a/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.cc b/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.cc deleted file mode 100644 index a0d197dc8..000000000 --- a/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.cc +++ /dev/null @@ -1,260 +0,0 @@ -/*! - * \file gps_l1_ca_ls_pvt.cc - * \brief Implementation of a Least Squares Position, Velocity, and Time - * (PVT) solver, based on K.Borre's Matlab receiver. - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "gps_l1_ca_ls_pvt.h" -#include -#include - - -using google::LogMessage; - - -gps_l1_ca_ls_pvt::gps_l1_ca_ls_pvt(int nchannels, std::string dump_filename, bool flag_dump_to_file) : Ls_Pvt() -{ - // init empty ephemeris for all the available GNSS channels - d_nchannels = nchannels; - d_ephemeris = new Gps_Navigation_Message[nchannels]; - d_dump_filename = dump_filename; - d_flag_dump_enabled = flag_dump_to_file; - d_flag_averaging = false; - d_GPS_current_time = 0; - - // ############# ENABLE DATA FILE LOG ################# - if (d_flag_dump_enabled == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT lib dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception opening PVT lib dump file " << e.what(); - } - } - } -} - - - -gps_l1_ca_ls_pvt::~gps_l1_ca_ls_pvt() -{ - d_dump_file.close(); - delete[] d_ephemeris; -} - - - -bool gps_l1_ca_ls_pvt::get_PVT(std::map gnss_pseudoranges_map, double GPS_current_time, bool flag_averaging) -{ - std::map::iterator gnss_pseudoranges_iter; - std::map::iterator gps_ephemeris_iter; - - arma::vec W; // channels weight vector - arma::vec obs; // pseudoranges observation vector - arma::mat satpos; // satellite positions matrix - - int GPS_week = 0; - double utc = 0.0; - double TX_time_corrected_s; - double SV_clock_bias_s = 0.0; - - d_flag_averaging = flag_averaging; - - // ******************************************************************************** - // ****** PREPARE THE LEAST SQUARES DATA (SV POSITIONS MATRIX AND OBS VECTORS) **** - // ******************************************************************************** - int valid_obs = 0; //valid observations counter - for(gnss_pseudoranges_iter = gnss_pseudoranges_map.begin(); - gnss_pseudoranges_iter != gnss_pseudoranges_map.end(); - gnss_pseudoranges_iter++) - { - // 1- find the ephemeris for the current SV observation. The SV PRN ID is the map key - gps_ephemeris_iter = gps_ephemeris_map.find(gnss_pseudoranges_iter->first); - if (gps_ephemeris_iter != gps_ephemeris_map.end()) - { - /*! - * \todo Place here the satellite CN0 (power level, or weight factor) - */ - W.resize(valid_obs + 1, 1); - W(valid_obs) = 1; - - // COMMON RX TIME PVT ALGORITHM MODIFICATION (Like RINEX files) - // first estimate of transmit time - double Rx_time = GPS_current_time; - double Tx_time = Rx_time - gnss_pseudoranges_iter->second.Pseudorange_m / GPS_C_m_s; - - // 2- compute the clock drift using the clock model (broadcast) for this SV, not including relativistic effect - SV_clock_bias_s = gps_ephemeris_iter->second.sv_clock_drift(Tx_time); //- gps_ephemeris_iter->second.d_TGD; - - // 3- compute the current ECEF position for this SV using corrected TX time and obtain clock bias including relativistic effect - TX_time_corrected_s = Tx_time - SV_clock_bias_s; - double dtr = gps_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); - - //store satellite positions in a matrix - satpos.resize(3, valid_obs + 1); - satpos(0, valid_obs) = gps_ephemeris_iter->second.d_satpos_X; - satpos(1, valid_obs) = gps_ephemeris_iter->second.d_satpos_Y; - satpos(2, valid_obs) = gps_ephemeris_iter->second.d_satpos_Z; - - // 4- fill the observations vector with the corrected pseudoranges - obs.resize(valid_obs + 1, 1); - obs(valid_obs) = gnss_pseudoranges_iter->second.Pseudorange_m + dtr * GPS_C_m_s - d_rx_dt_s * GPS_C_m_s; - d_visible_satellites_IDs[valid_obs] = gps_ephemeris_iter->second.i_satellite_PRN; - d_visible_satellites_CN0_dB[valid_obs] = gnss_pseudoranges_iter->second.CN0_dB_hz; - - // SV ECEF DEBUG OUTPUT - DLOG(INFO) << "(new)ECEF satellite SV ID=" << gps_ephemeris_iter->second.i_satellite_PRN - << " X=" << gps_ephemeris_iter->second.d_satpos_X - << " [m] Y=" << gps_ephemeris_iter->second.d_satpos_Y - << " [m] Z=" << gps_ephemeris_iter->second.d_satpos_Z - << " [m] PR_obs=" << obs(valid_obs) << " [m]"; - - valid_obs++; - // compute the UTC time for this SV (just to print the associated UTC timestamp) - GPS_week = gps_ephemeris_iter->second.i_GPS_week; - utc = gps_utc_model.utc_time(TX_time_corrected_s, GPS_week); - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_pseudoranges_iter->first; - } - } - - // ******************************************************************************** - // ****** SOLVE LEAST SQUARES****************************************************** - // ******************************************************************************** - d_valid_observations = valid_obs; - LOG(INFO) << "(new)PVT: valid observations=" << valid_obs; - - if (valid_obs >= 4) - { - arma::vec rx_position_and_time; - DLOG(INFO) << "satpos=" << satpos; - DLOG(INFO) << "obs=" << obs; - DLOG(INFO) << "W=" << W; - - try - { - // check if this is the initial position computation - if (d_rx_dt_s == 0) - { - // execute Bancroft's algorithm to estimate initial receiver position and time - DLOG(INFO) << " Executing Bancroft algorithm..."; - rx_position_and_time = bancroftPos(satpos.t(), obs); - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s = rx_position_and_time(3) / GPS_C_m_s; // save time for the next iteration [meters]->[seconds] - } - - // Execute WLS using previous position as the initialization point - rx_position_and_time = leastSquarePos(satpos, obs, W); - - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s += rx_position_and_time(3) / GPS_C_m_s; // accumulate the rx time error for the next iteration [meters]->[seconds] - - DLOG(INFO) << "(new)Position at TOW=" << GPS_current_time << " in ECEF (X,Y,Z,t[meters]) = " << rx_position_and_time; - DLOG(INFO) << "Accumulated rx clock error=" << d_rx_dt_s << " clock error for this iteration=" << rx_position_and_time(3) / GPS_C_m_s << " [s]"; - - cart2geo(static_cast(rx_position_and_time(0)), static_cast(rx_position_and_time(1)), static_cast(rx_position_and_time(2)), 4); - - // Compute UTC time and print PVT solution - double secondsperweek = 604800.0; // number of seconds in one week (7*24*60*60) - boost::posix_time::time_duration t = boost::posix_time::seconds(utc + secondsperweek * static_cast(GPS_week)); - // 22 August 1999 last GPS time roll over - boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); - d_position_UTC_time = p_time; - DLOG(INFO) << "Position at " << boost::posix_time::to_simple_string(p_time) - << " is Lat = " << d_latitude_d << " [deg], Long = " << d_longitude_d - << " [deg], Height= " << d_height_m << " [m]" << " RX time offset= " << d_rx_dt_s << " [s]"; - - // ###### Compute DOPs ######## - compute_DOP(); - - // ######## LOG FILE ######### - if(d_flag_dump_enabled == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - // PVT GPS time - tmp_double = GPS_current_time; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position East [m] - tmp_double = d_rx_pos(0); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position North [m] - tmp_double = d_rx_pos(1); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // ECEF User Position Up [m] - tmp_double = d_rx_pos(2); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // User clock offset [s] - tmp_double = d_rx_dt_s; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Latitude [deg] - tmp_double = d_latitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Longitude [deg] - tmp_double = d_longitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - // GEO user position Height [m] - tmp_double = d_height_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing PVT LS dump file " << e.what(); - } - } - - // MOVING AVERAGE PVT - pos_averaging(flag_averaging); - - } - catch(const std::exception & e) - { - d_rx_dt_s = 0; //reset rx time estimation - LOG(WARNING) << "Problem with the solver, invalid solution!" << e.what(); - b_valid_position = false; - } - } - else - { - b_valid_position = false; - } - return b_valid_position; -} - - diff --git a/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.h b/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.h deleted file mode 100644 index c926d24c4..000000000 --- a/src/algorithms/PVT/libs/gps_l1_ca_ls_pvt.h +++ /dev/null @@ -1,81 +0,0 @@ -/*! - * \file gps_l1_ca_ls_pvt.h - * \brief Interface of a Least Squares Position, Velocity, and Time (PVT) - * solver for GPS L1 C/A, based on K.Borre's Matlab receiver. - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GPS_L1_CA_LS_PVT_H_ -#define GNSS_SDR_GPS_L1_CA_LS_PVT_H_ - -#include -#include -#include -#include "ls_pvt.h" -#include "GPS_L1_CA.h" -#include "gnss_synchro.h" -#include "gps_ephemeris.h" -#include "gps_navigation_message.h" -#include "gps_utc_model.h" -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_satellite_correction.h" -#include "sbas_ephemeris.h" - - -/*! - * \brief This class implements a simple PVT Least Squares solution for GPS L1 C/A signals - */ -class gps_l1_ca_ls_pvt : public Ls_Pvt -{ -public: - gps_l1_ca_ls_pvt(int nchannels, std::string dump_filename, bool flag_dump_to_file); - ~gps_l1_ca_ls_pvt(); - - bool get_PVT(std::map gnss_pseudoranges_map, double GPS_current_time, bool flag_averaging); - int d_nchannels; //!< Number of available channels for positioning - - Gps_Navigation_Message* d_ephemeris; - - // new ephemeris storage - std::map gps_ephemeris_map; //!< Map storing new Gps_Ephemeris - Gps_Utc_Model gps_utc_model; - Gps_Iono gps_iono; - - Sbas_Ionosphere_Correction sbas_iono; - std::map sbas_sat_corr_map; - std::map sbas_ephemeris_map; - - double d_GPS_current_time; - - bool d_flag_dump_enabled; - bool d_flag_averaging; - - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif diff --git a/src/algorithms/PVT/libs/gpx_printer.cc b/src/algorithms/PVT/libs/gpx_printer.cc new file mode 100644 index 000000000..7ca86052a --- /dev/null +++ b/src/algorithms/PVT/libs/gpx_printer.cc @@ -0,0 +1,226 @@ +/*! + * \file gpx_printer.cc + * \brief Implementation of a class that prints PVT information to a gpx file + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gpx_printer.h" +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem +#include +#include + +using google::LogMessage; + + +Gpx_Printer::Gpx_Printer(const std::string& base_path) +{ + positions_printed = false; + indent = " "; + gpx_base_path = base_path; + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(gpx_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(gpx_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + gpx_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + gpx_base_path = p.string(); + } + if (gpx_base_path != ".") + { + std::cout << "GPX files will be stored at " << gpx_base_path << std::endl; + } + + gpx_base_path = gpx_base_path + boost::filesystem::path::preferred_separator; +} + + +bool Gpx_Printer::set_headers(const std::string& filename, bool time_tag_name) +{ + boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); + tm timeinfo = boost::posix_time::to_tm(pt); + + if (time_tag_name) + { + std::stringstream strm0; + const int year = timeinfo.tm_year - 100; + strm0 << year; + const int month = timeinfo.tm_mon + 1; + if (month < 10) + { + strm0 << "0"; + } + strm0 << month; + const int day = timeinfo.tm_mday; + if (day < 10) + { + strm0 << "0"; + } + strm0 << day << "_"; + const int hour = timeinfo.tm_hour; + if (hour < 10) + { + strm0 << "0"; + } + strm0 << hour; + const int min = timeinfo.tm_min; + if (min < 10) + { + strm0 << "0"; + } + strm0 << min; + const int sec = timeinfo.tm_sec; + if (sec < 10) + { + strm0 << "0"; + } + strm0 << sec; + + gpx_filename = filename + "_" + strm0.str() + ".gpx"; + } + else + { + gpx_filename = filename + ".gpx"; + } + + gpx_filename = gpx_base_path + gpx_filename; + gpx_file.open(gpx_filename.c_str()); + + if (gpx_file.is_open()) + { + DLOG(INFO) << "GPX printer writing on " << filename.c_str(); + // Set iostream numeric format and precision + gpx_file.setf(gpx_file.std::ofstream::fixed, gpx_file.std::ofstream::floatfield); + gpx_file << std::setprecision(14); + gpx_file << R"()" << std::endl + << R"(" << std::endl + << indent << "" << std::endl + << indent << indent << "Position fixes computed by GNSS-SDR v" << GNSS_SDR_VERSION << "" << std::endl + << indent << indent << "GNSS-SDR position log generated at " << pt << " (local time)" << std::endl + << indent << indent << "" << std::endl; + return true; + } + std::cout << "File " << gpx_filename << " cannot be saved. Wrong permissions?" << std::endl; + return false; +} + + +bool Gpx_Printer::print_position(const std::shared_ptr& position, bool print_average_values) +{ + double latitude; + double longitude; + double height; + + positions_printed = true; + const std::shared_ptr& position_ = position; + + double speed_over_ground = position_->get_speed_over_ground(); // expressed in m/s + double course_over_ground = position_->get_course_over_ground(); // expressed in deg + + double hdop = position_->get_hdop(); + double vdop = position_->get_vdop(); + double pdop = position_->get_pdop(); + std::string utc_time = to_iso_extended_string(position_->get_position_UTC_time()); + if (utc_time.length() < 23) utc_time += "."; + utc_time.resize(23, '0'); // time up to ms + utc_time.append("Z"); // UTC time zone + + if (print_average_values == false) + { + latitude = position_->get_latitude(); + longitude = position_->get_longitude(); + height = position_->get_height(); + } + else + { + latitude = position_->get_avg_latitude(); + longitude = position_->get_avg_longitude(); + height = position_->get_avg_height(); + } + + if (gpx_file.is_open()) + { + gpx_file << indent << indent << indent << "" << height << "" + << "" + << "" << hdop << "" << vdop << "" << pdop << "" + << "" + << "" << speed_over_ground << "" + << "" << course_over_ground << "" + << "" << std::endl; + return true; + } + return false; +} + + +bool Gpx_Printer::close_file() +{ + if (gpx_file.is_open()) + { + gpx_file << indent << indent << "" << std::endl + << indent << "" << std::endl + << ""; + gpx_file.close(); + return true; + } + return false; +} + + +Gpx_Printer::~Gpx_Printer() +{ + close_file(); + if (!positions_printed) + { + if (remove(gpx_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary GPX file"; + } +} diff --git a/src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.h b/src/algorithms/PVT/libs/gpx_printer.h similarity index 53% rename from src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.h rename to src/algorithms/PVT/libs/gpx_printer.h index f5d6dfeca..27e9fe4ff 100644 --- a/src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.h +++ b/src/algorithms/PVT/libs/gpx_printer.h @@ -1,13 +1,12 @@ /*! - * \file kml_printer.h - * \brief Interface of a class that prints PVT information to a kml file - * for GPSTK data structures - * \author Javier Arribas, 2012. jarribas(at)cttc.es + * \file gpx_printer.h + * \brief Interface of a class that prints PVT information to a gpx file + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,35 +24,42 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_KML_PRINTER_H_ -#define GNSS_SDR_KML_PRINTER_H_ +#ifndef GNSS_SDR_GPX_PRINTER_H_ +#define GNSS_SDR_GPX_PRINTER_H_ -#include +#include "pvt_solution.h" +#include "rtklib_solver.h" #include -#include "gpstk/Position.hpp" +#include +#include /*! - * \brief Prints PVT information to OGC KML format file (can be viewed with Google Earth) + * \brief Prints PVT information to GPX format file * - * See http://www.opengeospatial.org/standards/kml + * See http://www.topografix.com/gpx.asp */ -class Kml_Printer_gpstk +class Gpx_Printer { private: - std::ofstream kml_file; + std::ofstream gpx_file; + bool positions_printed; + std::string gpx_filename; + std::string indent; + std::string gpx_base_path; + public: - bool set_headers(std::string filename); - bool print_position(gpstk::Position position); + Gpx_Printer(const std::string& base_path = "."); + ~Gpx_Printer(); + bool set_headers(const std::string& filename, bool time_tag_name = true); + bool print_position(const std::shared_ptr& position, bool print_average_values); bool close_file(); - Kml_Printer_gpstk(); - ~Kml_Printer_gpstk(); }; #endif diff --git a/src/algorithms/PVT/libs/hybrid_ls_pvt.cc b/src/algorithms/PVT/libs/hybrid_ls_pvt.cc index 09fc2b65f..5fbc52ab8 100644 --- a/src/algorithms/PVT/libs/hybrid_ls_pvt.cc +++ b/src/algorithms/PVT/libs/hybrid_ls_pvt.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,14 +24,18 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "hybrid_ls_pvt.h" -#include +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" #include "Galileo_E1.h" +#include +#include +#include using google::LogMessage; @@ -40,274 +44,287 @@ hybrid_ls_pvt::hybrid_ls_pvt(int nchannels, std::string dump_filename, bool flag { // init empty ephemeris for all the available GNSS channels d_nchannels = nchannels; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_flag_dump_enabled = flag_dump_to_file; d_galileo_current_time = 0; count_valid_position = 0; - d_flag_averaging = false; + this->set_averaging_flag(false); // ############# ENABLE DATA FILE LOG ################# if (d_flag_dump_enabled == true) - { - if (d_dump_file.is_open() == false) { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "PVT lib dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception opening PVT lib dump file " << e.what(); - } + if (d_dump_file.is_open() == false) + { + try + { + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "PVT lib dump enabled Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure& e) + { + LOG(WARNING) << "Exception opening PVT lib dump file " << e.what(); + } + } } - } } hybrid_ls_pvt::~hybrid_ls_pvt() { - d_dump_file.close(); + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception& ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } } -bool hybrid_ls_pvt::get_PVT(std::map gnss_observables_map, double hybrid_current_time, bool flag_averaging) +bool hybrid_ls_pvt::get_PVT(std::map gnss_observables_map, double hybrid_current_time, bool flag_averaging) { - std::map::iterator gnss_observables_iter; - std::map::iterator galileo_ephemeris_iter; - std::map::iterator gps_ephemeris_iter; - std::map::iterator gps_cnav_ephemeris_iter; + std::map::iterator gnss_observables_iter; + std::map::iterator galileo_ephemeris_iter; + std::map::iterator gps_ephemeris_iter; + std::map::iterator gps_cnav_ephemeris_iter; - arma::vec W; // channels weight vector - arma::vec obs; // pseudoranges observation vector - arma::mat satpos; // satellite positions matrix + arma::vec W; // channels weight vector + arma::vec obs; // pseudoranges observation vector + arma::mat satpos; // satellite positions matrix int Galileo_week_number = 0; int GPS_week = 0; double utc = 0.0; double GST = 0.0; + double secondsperweek = 604800.0; + //double utc_tx_corrected = 0.0; //utc computed at tx_time_corrected, added for Galileo constellation (in GPS utc is directly computed at TX_time_corrected_s) double TX_time_corrected_s = 0.0; double SV_clock_bias_s = 0.0; - d_flag_averaging = flag_averaging; + this->set_averaging_flag(flag_averaging); // ******************************************************************************** // ****** PREPARE THE LEAST SQUARES DATA (SV POSITIONS MATRIX AND OBS VECTORS) **** // ******************************************************************************** - int valid_obs = 0; //valid observations counter + int valid_obs = 0; //valid observations counter - for(gnss_observables_iter = gnss_observables_map.begin(); - gnss_observables_iter != gnss_observables_map.end(); - gnss_observables_iter++) + for (gnss_observables_iter = gnss_observables_map.begin(); + gnss_observables_iter != gnss_observables_map.end(); + gnss_observables_iter++) { - switch(gnss_observables_iter->second.System) - { - case 'E': + switch (gnss_observables_iter->second.System) { - // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key - galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (galileo_ephemeris_iter != galileo_ephemeris_map.end()) - { - /*! + case 'E': + { + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.end()) + { + /*! * \todo Place here the satellite CN0 (power level, or weight factor) */ - W.resize(valid_obs + 1, 1); - W(valid_obs) = 1; + W.resize(valid_obs + 1, 1); + W(valid_obs) = 1; - // COMMON RX TIME PVT ALGORITHM - double Rx_time = hybrid_current_time; - double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GALILEO_C_m_s; + // COMMON RX TIME PVT ALGORITHM + double Rx_time = hybrid_current_time; + double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GALILEO_C_m_s; - // 2- compute the clock drift using the clock model (broadcast) for this SV - SV_clock_bias_s = galileo_ephemeris_iter->second.sv_clock_drift(Tx_time); + // 2- compute the clock drift using the clock model (broadcast) for this SV + SV_clock_bias_s = galileo_ephemeris_iter->second.sv_clock_drift(Tx_time); - // 3- compute the current ECEF position for this SV using corrected TX time - TX_time_corrected_s = Tx_time - SV_clock_bias_s; - galileo_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); + // 3- compute the current ECEF position for this SV using corrected TX time + TX_time_corrected_s = Tx_time - SV_clock_bias_s; + galileo_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); - //store satellite positions in a matrix - satpos.resize(3, valid_obs + 1); - satpos(0, valid_obs) = galileo_ephemeris_iter->second.d_satpos_X; - satpos(1, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Y; - satpos(2, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Z; + //store satellite positions in a matrix + satpos.resize(3, valid_obs + 1); + satpos(0, valid_obs) = galileo_ephemeris_iter->second.d_satpos_X; + satpos(1, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Y; + satpos(2, valid_obs) = galileo_ephemeris_iter->second.d_satpos_Z; - // 4- fill the observations vector with the corrected observables - obs.resize(valid_obs + 1, 1); - obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + SV_clock_bias_s * GALILEO_C_m_s - d_rx_dt_s * GALILEO_C_m_s; - d_visible_satellites_IDs[valid_obs] = galileo_ephemeris_iter->second.i_satellite_PRN; - d_visible_satellites_CN0_dB[valid_obs] = gnss_observables_iter->second.CN0_dB_hz; + // 4- fill the observations vector with the corrected observables + obs.resize(valid_obs + 1, 1); + obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + SV_clock_bias_s * GALILEO_C_m_s - this->get_time_offset_s() * GALILEO_C_m_s; - Galileo_week_number = galileo_ephemeris_iter->second.WN_5; //for GST - GST = galileo_ephemeris_iter->second.Galileo_System_Time(Galileo_week_number, hybrid_current_time); + Galileo_week_number = galileo_ephemeris_iter->second.WN_5; //for GST + GST = galileo_ephemeris_iter->second.Galileo_System_Time(Galileo_week_number, hybrid_current_time); - // SV ECEF DEBUG OUTPUT - DLOG(INFO) << "ECEF satellite SV ID=" << galileo_ephemeris_iter->second.i_satellite_PRN - << " X=" << galileo_ephemeris_iter->second.d_satpos_X - << " [m] Y=" << galileo_ephemeris_iter->second.d_satpos_Y - << " [m] Z=" << galileo_ephemeris_iter->second.d_satpos_Z - << " [m] PR_obs=" << obs(valid_obs) << " [m]"; + // SV ECEF DEBUG OUTPUT + DLOG(INFO) << "ECEF satellite SV ID=" << galileo_ephemeris_iter->second.i_satellite_PRN + << " X=" << galileo_ephemeris_iter->second.d_satpos_X + << " [m] Y=" << galileo_ephemeris_iter->second.d_satpos_Y + << " [m] Z=" << galileo_ephemeris_iter->second.d_satpos_Z + << " [m] PR_obs=" << obs(valid_obs) << " [m]"; - valid_obs++; - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; - } - break; - } - case 'G': - { - // 1 GPS - find the ephemeris for the current GPS SV observation. The SV PRN ID is the map key - std::string sig_(gnss_observables_iter->second.Signal); - if(sig_.compare("1C") == 0) - { - gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (gps_ephemeris_iter != gps_ephemeris_map.end()) - { - /*! + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + break; + } + case 'G': + { + // 1 GPS - find the ephemeris for the current GPS SV observation. The SV PRN ID is the map key + std::string sig_(gnss_observables_iter->second.Signal); + if (sig_ == "1C") + { + gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != gps_ephemeris_map.end()) + { + /*! * \todo Place here the satellite CN0 (power level, or weight factor) */ - W.resize(valid_obs + 1, 1); - W(valid_obs) = 1; + W.resize(valid_obs + 1, 1); + W(valid_obs) = 1; - // COMMON RX TIME PVT ALGORITHM MODIFICATION (Like RINEX files) - // first estimate of transmit time - double Rx_time = hybrid_current_time; - double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GPS_C_m_s; + // COMMON RX TIME PVT ALGORITHM MODIFICATION (Like RINEX files) + // first estimate of transmit time + double Rx_time = hybrid_current_time; + double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GPS_C_m_s; - // 2- compute the clock drift using the clock model (broadcast) for this SV, not including relativistic effect - SV_clock_bias_s = gps_ephemeris_iter->second.sv_clock_drift(Tx_time); //- gps_ephemeris_iter->second.d_TGD; + // 2- compute the clock drift using the clock model (broadcast) for this SV, not including relativistic effect + SV_clock_bias_s = gps_ephemeris_iter->second.sv_clock_drift(Tx_time); //- gps_ephemeris_iter->second.d_TGD; - // 3- compute the current ECEF position for this SV using corrected TX time and obtain clock bias including relativistic effect - TX_time_corrected_s = Tx_time - SV_clock_bias_s; - double dtr = gps_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); + // 3- compute the current ECEF position for this SV using corrected TX time and obtain clock bias including relativistic effect + TX_time_corrected_s = Tx_time - SV_clock_bias_s; + double dtr = gps_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); - //store satellite positions in a matrix - satpos.resize(3, valid_obs + 1); - satpos(0, valid_obs) = gps_ephemeris_iter->second.d_satpos_X; - satpos(1, valid_obs) = gps_ephemeris_iter->second.d_satpos_Y; - satpos(2, valid_obs) = gps_ephemeris_iter->second.d_satpos_Z; + //store satellite positions in a matrix + satpos.resize(3, valid_obs + 1); + satpos(0, valid_obs) = gps_ephemeris_iter->second.d_satpos_X; + satpos(1, valid_obs) = gps_ephemeris_iter->second.d_satpos_Y; + satpos(2, valid_obs) = gps_ephemeris_iter->second.d_satpos_Z; - // 4- fill the observations vector with the corrected pseudoranges - obs.resize(valid_obs + 1, 1); - obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + dtr * GPS_C_m_s - d_rx_dt_s * GPS_C_m_s; - d_visible_satellites_IDs[valid_obs] = gps_ephemeris_iter->second.i_satellite_PRN; - d_visible_satellites_CN0_dB[valid_obs] = gnss_observables_iter->second.CN0_dB_hz; + // 4- fill the observations vector with the corrected pseudoranges + // compute code bias: TGD for single frequency + // See IS-GPS-200E section 20.3.3.3.3.2 + double sqrt_Gamma = GPS_L1_FREQ_HZ / GPS_L2_FREQ_HZ; + double Gamma = sqrt_Gamma * sqrt_Gamma; + double P1_P2 = (1.0 - Gamma) * (gps_ephemeris_iter->second.d_TGD * GPS_C_m_s); + double Code_bias_m = P1_P2 / (1.0 - Gamma); + obs.resize(valid_obs + 1, 1); + obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + dtr * GPS_C_m_s - Code_bias_m - this->get_time_offset_s() * GPS_C_m_s; - // SV ECEF DEBUG OUTPUT - DLOG(INFO) << "(new)ECEF satellite SV ID=" << gps_ephemeris_iter->second.i_satellite_PRN - << " X=" << gps_ephemeris_iter->second.d_satpos_X - << " [m] Y=" << gps_ephemeris_iter->second.d_satpos_Y - << " [m] Z=" << gps_ephemeris_iter->second.d_satpos_Z - << " [m] PR_obs=" << obs(valid_obs) << " [m]"; + // SV ECEF DEBUG OUTPUT + LOG(INFO) << "(new)ECEF GPS L1 CA satellite SV ID=" << gps_ephemeris_iter->second.i_satellite_PRN + << " TX Time corrected=" << TX_time_corrected_s << " X=" << gps_ephemeris_iter->second.d_satpos_X + << " [m] Y=" << gps_ephemeris_iter->second.d_satpos_Y + << " [m] Z=" << gps_ephemeris_iter->second.d_satpos_Z + << " [m] PR_obs=" << obs(valid_obs) << " [m]"; - valid_obs++; - // compute the UTC time for this SV (just to print the associated UTC timestamp) - GPS_week = gps_ephemeris_iter->second.i_GPS_week; - utc = gps_utc_model.utc_time(TX_time_corrected_s, GPS_week); - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->first; - } - } - if(sig_.compare("2S") == 0) - { - gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (gps_cnav_ephemeris_iter != gps_cnav_ephemeris_map.end()) - { - /*! + valid_obs++; + // compute the UTC time for this SV (just to print the associated UTC timestamp) + GPS_week = gps_ephemeris_iter->second.i_GPS_week; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->first; + } + } + if (sig_ == "2S") + { + gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_cnav_ephemeris_iter != gps_cnav_ephemeris_map.end()) + { + /*! * \todo Place here the satellite CN0 (power level, or weight factor) */ - W.resize(valid_obs + 1, 1); - W(valid_obs) = 1; + W.resize(valid_obs + 1, 1); + W(valid_obs) = 1; - // COMMON RX TIME PVT ALGORITHM MODIFICATION (Like RINEX files) - // first estimate of transmit time - double Rx_time = hybrid_current_time; - double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GPS_C_m_s; + // COMMON RX TIME PVT ALGORITHM MODIFICATION (Like RINEX files) + // first estimate of transmit time + double Rx_time = hybrid_current_time; + double Tx_time = Rx_time - gnss_observables_iter->second.Pseudorange_m / GPS_C_m_s; - // 2- compute the clock drift using the clock model (broadcast) for this SV - SV_clock_bias_s = gps_cnav_ephemeris_iter->second.sv_clock_drift(Tx_time); + // 2- compute the clock drift using the clock model (broadcast) for this SV + SV_clock_bias_s = gps_cnav_ephemeris_iter->second.sv_clock_drift(Tx_time); - // 3- compute the current ECEF position for this SV using corrected TX time - TX_time_corrected_s = Tx_time - SV_clock_bias_s; - gps_cnav_ephemeris_iter->second.satellitePosition(TX_time_corrected_s); + // 3- compute the current ECEF position for this SV using corrected TX time + TX_time_corrected_s = Tx_time - SV_clock_bias_s; + //std::cout<<"TX time["<second.i_satellite_PRN<<"]="<second.satellitePosition(TX_time_corrected_s); - //store satellite positions in a matrix - satpos.resize(3, valid_obs + 1); - satpos(0, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_X; - satpos(1, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_Y; - satpos(2, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_Z; + //store satellite positions in a matrix + satpos.resize(3, valid_obs + 1); + satpos(0, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_X; + satpos(1, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_Y; + satpos(2, valid_obs) = gps_cnav_ephemeris_iter->second.d_satpos_Z; - // 4- fill the observations vector with the corrected observables - obs.resize(valid_obs + 1, 1); - obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + SV_clock_bias_s * GPS_C_m_s; - d_visible_satellites_IDs[valid_obs] = gps_cnav_ephemeris_iter->second.i_satellite_PRN; - d_visible_satellites_CN0_dB[valid_obs] = gnss_observables_iter->second.CN0_dB_hz; + // 4- fill the observations vector with the corrected observables + obs.resize(valid_obs + 1, 1); + obs(valid_obs) = gnss_observables_iter->second.Pseudorange_m + dtr * GPS_C_m_s + SV_clock_bias_s * GPS_C_m_s; - GPS_week = gps_cnav_ephemeris_iter->second.i_GPS_week; + GPS_week = gps_cnav_ephemeris_iter->second.i_GPS_week; + GPS_week = GPS_week % 1024; //Necessary due to the increase of WN bits in CNAV message (10 in GPS NAV and 13 in CNAV) - // SV ECEF DEBUG OUTPUT - DLOG(INFO) << "(new)ECEF satellite SV ID=" << gps_cnav_ephemeris_iter->second.i_satellite_PRN - << " X=" << gps_cnav_ephemeris_iter->second.d_satpos_X - << " [m] Y=" << gps_cnav_ephemeris_iter->second.d_satpos_Y - << " [m] Z=" << gps_cnav_ephemeris_iter->second.d_satpos_Z - << " [m] PR_obs=" << obs(valid_obs) << " [m]"; + // SV ECEF DEBUG OUTPUT + LOG(INFO) << "(new)ECEF GPS L2M satellite SV ID=" << gps_cnav_ephemeris_iter->second.i_satellite_PRN + << " TX Time corrected=" << TX_time_corrected_s + << " X=" << gps_cnav_ephemeris_iter->second.d_satpos_X + << " [m] Y=" << gps_cnav_ephemeris_iter->second.d_satpos_Y + << " [m] Z=" << gps_cnav_ephemeris_iter->second.d_satpos_Z + << " [m] PR_obs=" << obs(valid_obs) << " [m]"; - valid_obs++; - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; - } - } + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + break; + } + default: + DLOG(INFO) << "Hybrid observables: Unknown GNSS"; break; } - default : - DLOG(INFO) << "Hybrid observables: Unknown GNSS"; - break; - } } // ******************************************************************************** // ****** SOLVE LEAST SQUARES****************************************************** // ******************************************************************************** - d_valid_observations = valid_obs; + this->set_num_valid_observations(valid_obs); LOG(INFO) << "HYBRID PVT: valid observations=" << valid_obs; - if(valid_obs >= 4) + if (valid_obs >= 4) { arma::vec rx_position_and_time; DLOG(INFO) << "satpos=" << satpos; DLOG(INFO) << "obs=" << obs; DLOG(INFO) << "W=" << W; try - { + { // check if this is the initial position computation - if (d_rx_dt_s == 0) + if (this->get_time_offset_s() == 0) { // execute Bancroft's algorithm to estimate initial receiver position and time DLOG(INFO) << " Executing Bancroft algorithm..."; rx_position_and_time = bancroftPos(satpos.t(), obs); - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s = rx_position_and_time(3) / GPS_C_m_s; // save time for the next iteration [meters]->[seconds] + this->set_rx_pos(rx_position_and_time.rows(0, 2)); // save ECEF position for the next iteration + this->set_time_offset_s(rx_position_and_time(3) / GPS_C_m_s); // save time for the next iteration [meters]->[seconds] } // Execute WLS using previous position as the initialization point rx_position_and_time = leastSquarePos(satpos, obs, W); - d_rx_pos = rx_position_and_time.rows(0, 2); // save ECEF position for the next iteration - d_rx_dt_s += rx_position_and_time(3) / GPS_C_m_s; // accumulate the rx time error for the next iteration [meters]->[seconds] + this->set_rx_pos(rx_position_and_time.rows(0, 2)); // save ECEF position for the next iteration + this->set_time_offset_s(this->get_time_offset_s() + rx_position_and_time(3) / GPS_C_m_s); // accumulate the rx time error for the next iteration [meters]->[seconds] DLOG(INFO) << "Hybrid Position at TOW=" << hybrid_current_time << " in ECEF (X,Y,Z,t[meters]) = " << rx_position_and_time; - DLOG(INFO) << "Accumulated rx clock error=" << d_rx_dt_s << " clock error for this iteration=" << rx_position_and_time(3) / GPS_C_m_s << " [s]"; + DLOG(INFO) << "Accumulated rx clock error=" << this->get_time_offset_s() << " clock error for this iteration=" << rx_position_and_time(3) / GPS_C_m_s << " [s]"; - double secondsperweek = 604800.0; // Compute GST and Gregorian time - if( GST != 0.0) + if (GST != 0.0) { utc = galileo_utc_model.GST_to_UTC_time(GST, Galileo_week_number); } @@ -317,71 +334,69 @@ bool hybrid_ls_pvt::get_PVT(std::map gnss_observables_map, dou } // get time string Gregorian calendar - boost::posix_time::time_duration t = boost::posix_time::seconds(utc); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast(utc * 1000.0)); // NOLINT(google-runtime-int) // 22 August 1999 00:00 last Galileo start GST epoch (ICD sec 5.1.2) boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); - d_position_UTC_time = p_time; + this->set_position_UTC_time(p_time); cart2geo(static_cast(rx_position_and_time(0)), static_cast(rx_position_and_time(1)), static_cast(rx_position_and_time(2)), 4); DLOG(INFO) << "Hybrid Position at " << boost::posix_time::to_simple_string(p_time) - << " is Lat = " << d_latitude_d << " [deg], Long = " << d_longitude_d - << " [deg], Height= " << d_height_m << " [m]" << " RX time offset= " << d_rx_dt_s << " [s]"; - - // ###### Compute DOPs ######## - hybrid_ls_pvt::compute_DOP(); + << " is Lat = " << this->get_latitude() << " [deg], Long = " << this->get_longitude() + << " [deg], Height= " << this->get_height() << " [m]" + << " RX time offset= " << this->get_time_offset_s() << " [s]"; // ######## LOG FILE ######### - if(d_flag_dump_enabled == true) + if (d_flag_dump_enabled == true) { // MULTIPLEXED FILE RECORDING - Record results to file try - { + { double tmp_double; // PVT GPS time tmp_double = hybrid_current_time; - d_dump_file.write((char*)&tmp_double, sizeof(double)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // ECEF User Position East [m] tmp_double = rx_position_and_time(0); - d_dump_file.write((char*)&tmp_double, sizeof(double)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // ECEF User Position North [m] tmp_double = rx_position_and_time(1); - d_dump_file.write((char*)&tmp_double, sizeof(double)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // ECEF User Position Up [m] tmp_double = rx_position_and_time(2); - d_dump_file.write((char*)&tmp_double, sizeof(double)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // User clock offset [s] tmp_double = rx_position_and_time(3); - d_dump_file.write((char*)&tmp_double, sizeof(double)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // GEO user position Latitude [deg] - tmp_double = d_latitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); + tmp_double = this->get_latitude(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // GEO user position Longitude [deg] - tmp_double = d_longitude_d; - d_dump_file.write((char*)&tmp_double, sizeof(double)); + tmp_double = this->get_longitude(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); // GEO user position Height [m] - tmp_double = d_height_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } + tmp_double = this->get_height(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } catch (const std::ifstream::failure& e) - { + { LOG(WARNING) << "Exception writing PVT LS dump file " << e.what(); - } + } } // MOVING AVERAGE PVT - pos_averaging(flag_averaging); - } - catch(const std::exception & e) - { - d_rx_dt_s = 0; //reset rx time estimation + this->perform_pos_averaging(); + } + catch (const std::exception& e) + { + this->set_time_offset_s(0.0); //reset rx time estimation LOG(WARNING) << "Problem with the solver, invalid solution!" << e.what(); - b_valid_position = false; - } + this->set_valid_position(false); + } } else { - b_valid_position = false; + this->set_valid_position(false); } - return b_valid_position; + return this->is_valid_position(); } diff --git a/src/algorithms/PVT/libs/hybrid_ls_pvt.h b/src/algorithms/PVT/libs/hybrid_ls_pvt.h index 6cc9fe76f..8a9c2b590 100644 --- a/src/algorithms/PVT/libs/hybrid_ls_pvt.h +++ b/src/algorithms/PVT/libs/hybrid_ls_pvt.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,33 +32,40 @@ #ifndef GNSS_SDR_HYBRID_LS_PVT_H_ #define GNSS_SDR_HYBRID_LS_PVT_H_ +#include "galileo_almanac.h" +#include "galileo_navigation_message.h" +#include "gnss_synchro.h" +#include "gps_cnav_navigation_message.h" +#include "gps_navigation_message.h" +#include "ls_pvt.h" +#include "rtklib_rtkcmn.h" #include -#include #include #include -#include "ls_pvt.h" -#include "galileo_navigation_message.h" -#include "gps_navigation_message.h" -#include "gps_cnav_navigation_message.h" -#include "gnss_synchro.h" - /*! * \brief This class implements a simple PVT Least Squares solution */ class hybrid_ls_pvt : public Ls_Pvt { +private: + int count_valid_position; + bool d_flag_dump_enabled; + std::string d_dump_filename; + std::ofstream d_dump_file; + int d_nchannels; // Number of available channels for positioning + double d_galileo_current_time; + public: - hybrid_ls_pvt(int nchannels,std::string dump_filename, bool flag_dump_to_file); + hybrid_ls_pvt(int nchannels, std::string dump_filename, bool flag_dump_to_file); ~hybrid_ls_pvt(); - bool get_PVT(std::map gnss_observables_map, double hybrid_current_time, bool flag_averaging); - int d_nchannels; //!< Number of available channels for positioning + bool get_PVT(std::map gnss_observables_map, double Rx_time, bool flag_averaging); + + std::map galileo_ephemeris_map; //!< Map storing new Galileo_Ephemeris + std::map gps_ephemeris_map; //!< Map storing new GPS_Ephemeris + std::map gps_cnav_ephemeris_map; - std::map galileo_ephemeris_map; //!< Map storing new Galileo_Ephemeris - std::map gps_ephemeris_map; //!< Map storing new GPS_Ephemeris - std::map gps_cnav_ephemeris_map; - Galileo_Utc_Model galileo_utc_model; Galileo_Iono galileo_iono; Galileo_Almanac galileo_almanac; @@ -68,16 +75,6 @@ public: Gps_CNAV_Iono gps_cnav_iono; Gps_CNAV_Utc_Model gps_cnav_utc_model; - - double d_galileo_current_time; - - int count_valid_position; - - bool d_flag_dump_enabled; - bool d_flag_averaging; - - std::string d_dump_filename; - std::ofstream d_dump_file; }; #endif diff --git a/src/algorithms/PVT/libs/kml_printer.cc b/src/algorithms/PVT/libs/kml_printer.cc index dd457db45..76018ba35 100644 --- a/src/algorithms/PVT/libs/kml_printer.cc +++ b/src/algorithms/PVT/libs/kml_printer.cc @@ -2,11 +2,12 @@ * \file kml_printer.cc * \brief Implementation of a class that prints PVT information to a kml file * \author Javier Arribas, 2011. jarribas(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,111 +25,193 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "kml_printer.h" -#include -#include +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem #include +#include using google::LogMessage; -bool Kml_Printer::set_headers(std::string filename, bool time_tag_name) -{ - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); +Kml_Printer::Kml_Printer(const std::string& base_path) +{ + positions_printed = false; + indent = " "; + kml_base_path = base_path; + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(kml_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(kml_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + kml_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + kml_base_path = p.string(); + } + if (kml_base_path != ".") + { + std::cout << "KML files will be stored at " << kml_base_path << std::endl; + } + + kml_base_path = kml_base_path + boost::filesystem::path::preferred_separator; + + boost::filesystem::path tmp_base_path = boost::filesystem::temp_directory_path(); + boost::filesystem::path tmp_filename = boost::filesystem::unique_path(); + boost::filesystem::path tmp_file = tmp_base_path / tmp_filename; + + tmp_file_str = tmp_file.string(); + + point_id = 0; +} + + +bool Kml_Printer::set_headers(const std::string& filename, bool time_tag_name) +{ + boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); + tm timeinfo = boost::posix_time::to_tm(pt); + if (time_tag_name) { - - std::stringstream strm0; - const int year = timeinfo->tm_year - 100; + const int year = timeinfo.tm_year - 100; strm0 << year; - const int month = timeinfo->tm_mon + 1; - if(month < 10) + const int month = timeinfo.tm_mon + 1; + if (month < 10) { strm0 << "0"; } strm0 << month; - const int day = timeinfo->tm_mday; - if(day < 10) + const int day = timeinfo.tm_mday; + if (day < 10) { strm0 << "0"; } strm0 << day << "_"; - const int hour = timeinfo->tm_hour; - if(hour < 10) + const int hour = timeinfo.tm_hour; + if (hour < 10) { strm0 << "0"; } strm0 << hour; - const int min = timeinfo->tm_min; - if(min < 10) + const int min = timeinfo.tm_min; + if (min < 10) { strm0 << "0"; } strm0 << min; - const int sec = timeinfo->tm_sec; - if(sec < 10) + const int sec = timeinfo.tm_sec; + if (sec < 10) { strm0 << "0"; } strm0 << sec; - kml_filename = filename + "_" + strm0.str() + ".kml"; + kml_filename = filename + "_" + strm0.str() + ".kml"; } else { kml_filename = filename + ".kml"; } + kml_filename = kml_base_path + kml_filename; kml_file.open(kml_filename.c_str()); - if (kml_file.is_open()) + + tmp_file.open(tmp_file_str.c_str()); + + if (kml_file.is_open() && tmp_file.is_open()) { DLOG(INFO) << "KML printer writing on " << filename.c_str(); // Set iostream numeric format and precision - kml_file.setf(kml_file.fixed, kml_file.floatfield); + kml_file.setf(kml_file.std::ofstream::fixed, kml_file.std::ofstream::floatfield); kml_file << std::setprecision(14); - kml_file << "" << std::endl - << "" << std::endl - << " " << std::endl - << " GNSS Track" << std::endl - << " GNSS-SDR Receiver position log file created at " << asctime (timeinfo) - << " " << std::endl - << "" << std::endl - << "" << std::endl - << "GNSS-SDR PVT" << std::endl - << "GNSS-SDR position log" << std::endl - << "#yellowLineGreenPoly" << std::endl - << "" << std::endl - << "0" << std::endl - << "1" << std::endl - << "absolute" << std::endl - << "" << std::endl; + + tmp_file.setf(tmp_file.std::ofstream::fixed, tmp_file.std::ofstream::floatfield); + tmp_file << std::setprecision(14); + + kml_file << R"()" << std::endl + << R"()" << std::endl + << indent << "" << std::endl + << indent << indent << "GNSS Track" << std::endl + << indent << indent << "" << std::endl + << indent << indent << indent << indent << "GNSS-SDR Receiver position log file created at " << pt << "" << std::endl + << indent << indent << indent << indent << "https://gnss-sdr.org/" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << "]]>" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "normal" << std::endl + << indent << indent << indent << indent << "#track_n" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "highlight" << std::endl + << indent << indent << indent << indent << "#track_h" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << indent << indent << "Points" << std::endl; + return true; } - else - { - return false; - } + std::cout << "File " << kml_filename << " cannot be saved. Wrong permissions?" << std::endl; + return false; } - -bool Kml_Printer::print_position(const std::shared_ptr& position, bool print_average_values) +bool Kml_Printer::print_position(const std::shared_ptr& position, bool print_average_values) { double latitude; double longitude; @@ -136,67 +219,109 @@ bool Kml_Printer::print_position(const std::shared_ptr& position, positions_printed = true; - std::shared_ptr position_ = position; + const std::shared_ptr& position_ = position; + + double speed_over_ground = position_->get_speed_over_ground(); // expressed in m/s + double course_over_ground = position_->get_course_over_ground(); // expressed in deg + + double hdop = position_->get_hdop(); + double vdop = position_->get_vdop(); + double pdop = position_->get_pdop(); + std::string utc_time = to_iso_extended_string(position_->get_position_UTC_time()); + if (utc_time.length() < 23) utc_time += "."; + utc_time.resize(23, '0'); // time up to ms + utc_time.append("Z"); // UTC time zone if (print_average_values == false) { - latitude = position_->d_latitude_d; - longitude = position_->d_longitude_d; - height = position_->d_height_m; + latitude = position_->get_latitude(); + longitude = position_->get_longitude(); + height = position_->get_height(); } else { - latitude = position_->d_avg_latitude_d; - longitude = position_->d_avg_longitude_d; - height = position_->d_avg_height_m; + latitude = position_->get_avg_latitude(); + longitude = position_->get_avg_longitude(); + height = position_->get_avg_height(); } - if (kml_file.is_open()) + if (kml_file.is_open() && tmp_file.is_open()) { - kml_file << longitude << "," << latitude << "," << height << std::endl; + point_id++; + kml_file << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "" << point_id << "" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << indent << indent << "Time:" << utc_time << "" << std::endl + << indent << indent << indent << indent << indent << indent << "Longitude:" << longitude << "deg" << std::endl + << indent << indent << indent << indent << indent << indent << "Latitude:" << latitude << "deg" << std::endl + << indent << indent << indent << indent << indent << indent << "Altitude:" << height << "m" << std::endl + << indent << indent << indent << indent << indent << indent << "Speed:" << speed_over_ground << "m/s" << std::endl + << indent << indent << indent << indent << indent << indent << "Course:" << course_over_ground << "deg" << std::endl + << indent << indent << indent << indent << indent << indent << "HDOP:" << hdop << "" << std::endl + << indent << indent << indent << indent << indent << indent << "VDOP:" << vdop << "" << std::endl + << indent << indent << indent << indent << indent << indent << "PDOP:" << pdop << "" << std::endl + << indent << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "]]>" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << indent << "" << utc_time << "" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "#track" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << indent << "absolute" << std::endl + << indent << indent << indent << indent << indent << "" << longitude << "," << latitude << "," << height << "" << std::endl + << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << "" << std::endl; + + tmp_file << indent << indent << indent << indent << indent + << longitude << "," << latitude << "," << height << std::endl; + return true; } - else - { - return false; - } + return false; } bool Kml_Printer::close_file() { - if (kml_file.is_open()) + if (kml_file.is_open() && tmp_file.is_open()) { + tmp_file.close(); - kml_file << "" << std::endl - << "" << std::endl - << "" << std::endl - << "" << std::endl + kml_file << indent << indent << "" + << indent << indent << "" << std::endl + << indent << indent << indent << "Path" << std::endl + << indent << indent << indent << "#yellowLineGreenPoly" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << indent << indent << "0" << std::endl + << indent << indent << indent << indent << "1" << std::endl + << indent << indent << indent << indent << "absolute" << std::endl + << indent << indent << indent << indent << "" << std::endl; + + // Copy the contents of tmp_file into kml_file + std::ifstream src(tmp_file_str, std::ios::binary); + kml_file << src.rdbuf(); + + kml_file << indent << indent << indent << indent << "" << std::endl + << indent << indent << indent << "" << std::endl + << indent << indent << "" << std::endl + << indent << "" << std::endl << ""; + kml_file.close(); + return true; } - else - { - return false; - } + return false; } - -Kml_Printer::Kml_Printer () -{ - positions_printed = false; -} - - - -Kml_Printer::~Kml_Printer () +Kml_Printer::~Kml_Printer() { close_file(); - if(!positions_printed) + if (!positions_printed) { - if(remove(kml_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary KML file"; + if (remove(kml_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary KML file"; } } - diff --git a/src/algorithms/PVT/libs/kml_printer.h b/src/algorithms/PVT/libs/kml_printer.h index 7a08a9166..7909ad619 100644 --- a/src/algorithms/PVT/libs/kml_printer.h +++ b/src/algorithms/PVT/libs/kml_printer.h @@ -2,11 +2,11 @@ * \file kml_printer.h * \brief Interface of a class that prints PVT information to a kml file * \author Javier Arribas, 2011. jarribas(at)cttc.es - * + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,11 +33,12 @@ #ifndef GNSS_SDR_KML_PRINTER_H_ #define GNSS_SDR_KML_PRINTER_H_ -#include +#include "pvt_solution.h" +#include "rtklib_solver.h" #include #include #include -#include "pvt_solution.h" + /*! * \brief Prints PVT information to OGC KML format file (can be viewed with Google Earth) @@ -48,13 +49,19 @@ class Kml_Printer { private: std::ofstream kml_file; + std::ofstream tmp_file; bool positions_printed; std::string kml_filename; + std::string kml_base_path; + std::string tmp_file_str; + unsigned int point_id; + std::string indent; + public: - Kml_Printer(); + Kml_Printer(const std::string& base_path = std::string(".")); ~Kml_Printer(); - bool set_headers(std::string filename, bool time_tag_name = true); - bool print_position(const std::shared_ptr& position, bool print_average_values); + bool set_headers(const std::string& filename, bool time_tag_name = true); + bool print_position(const std::shared_ptr& position, bool print_average_values); bool close_file(); }; diff --git a/src/algorithms/PVT/libs/ls_pvt.cc b/src/algorithms/PVT/libs/ls_pvt.cc index f8055241d..9077dcd68 100644 --- a/src/algorithms/PVT/libs/ls_pvt.cc +++ b/src/algorithms/PVT/libs/ls_pvt.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,17 +24,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ls_pvt.h" +#include "GPS_L1_CA.h" +#include "geofunctions.h" +#include #include #include -#include "GPS_L1_CA.h" -#include -#include using google::LogMessage; @@ -42,9 +42,9 @@ using google::LogMessage; Ls_Pvt::Ls_Pvt() : Pvt_Solution() { - } + arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) { // BANCROFT Calculation of preliminary coordinates for a GPS receiver based on pseudoranges @@ -71,7 +71,7 @@ arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) // 6995655.459 -23537808.269 -9927906.485 24222112.972 ]; // Solution: 596902.683 -4847843.316 4088216.740 - arma::vec pos = arma::zeros(4,1); + arma::vec pos = arma::zeros(4, 1); arma::mat B_pass = arma::zeros(obs.size(), 4); B_pass.submat(0, 0, obs.size() - 1, 2) = satpos; B_pass.col(3) = obs; @@ -82,27 +82,27 @@ arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) for (int iter = 0; iter < 2; iter++) { B = B_pass; - int m = arma::size(B,0); + int m = arma::size(B, 0); for (int i = 0; i < m; i++) { - int x = B(i,0); - int y = B(i,1); + int x = B(i, 0); + int y = B(i, 1); if (iter == 0) { traveltime = 0.072; } else { - int z = B(i,2); + int z = B(i, 2); double rho = (x - pos(0)) * (x - pos(0)) + (y - pos(1)) * (y - pos(1)) + (z - pos(2)) * (z - pos(2)); traveltime = sqrt(rho) / GPS_C_m_s; } double angle = traveltime * 7.292115147e-5; double cosa = cos(angle); double sina = sin(angle); - B(i,0) = cosa * x + sina * y; - B(i,1) = -sina * x + cosa * y; - }// % i-loop + B(i, 0) = cosa * x + sina * y; + B(i, 1) = -sina * x + cosa * y; + } // % i-loop if (m > 3) { @@ -112,8 +112,8 @@ arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) { BBB = arma::inv(B); } - arma::vec e = arma::ones(m,1); - arma::vec alpha = arma::zeros(m,1); + arma::vec e = arma::ones(m, 1); + arma::vec alpha = arma::zeros(m, 1); for (int i = 0; i < m; i++) { alpha(i) = lorentz(B.row(i).t(), B.row(i).t()) / 2.0; @@ -125,24 +125,24 @@ arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) double c = lorentz(BBBalpha, BBBalpha); double root = sqrt(b * b - a * c); arma::vec r = {(-b - root) / a, (-b + root) / a}; - arma::mat possible_pos = arma::zeros(4,2); + arma::mat possible_pos = arma::zeros(4, 2); for (int i = 0; i < 2; i++) { possible_pos.col(i) = r(i) * BBBe + BBBalpha; - possible_pos(3,i) = -possible_pos(3,i); + possible_pos(3, i) = -possible_pos(3, i); } - arma::vec abs_omc = arma::zeros(2,1); + arma::vec abs_omc = arma::zeros(2, 1); for (int j = 0; j < m; j++) { for (int i = 0; i < 2; i++) { - double c_dt = possible_pos(3,i); - double calc = arma::norm(satpos.row(i).t() - possible_pos.col(i).rows(0,2)) + c_dt; + double c_dt = possible_pos(3, i); + double calc = arma::norm(satpos.row(i).t() - possible_pos.col(i).rows(0, 2)) + c_dt; double omc = obs(j) - calc; abs_omc(i) = std::abs(omc); } - } // % j-loop + } // % j-loop // discrimination between roots if (abs_omc(0) > abs_omc(1)) @@ -153,7 +153,7 @@ arma::vec Ls_Pvt::bancroftPos(const arma::mat& satpos, const arma::vec& obs) { pos = possible_pos.col(0); } - } // % iter loop + } // % iter loop return pos; } @@ -168,11 +168,11 @@ double Ls_Pvt::lorentz(const arma::vec& x, const arma::vec& y) // M = diag([1 1 1 -1]); // p = x'*M*y; - return(x(0) * y(0) + x(1) * y(1) + x(2) * y(2) - x(3) * y(3)); + return (x(0) * y(0) + x(1) * y(1) + x(2) * y(2) - x(3) * y(3)); } -arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs, const arma::vec & w_vec) +arma::vec Ls_Pvt::leastSquarePos(const arma::mat& satpos, const arma::vec& obs, const arma::vec& w_vec) { /* Computes the Least Squares Solution. * Inputs: @@ -186,21 +186,18 @@ arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs */ //=== Initialization ======================================================= - int nmbOfIterations = 10; // TODO: include in config + int nmbOfIterations = 10; // TODO: include in config int nmbOfSatellites; - nmbOfSatellites = satpos.n_cols; //Armadillo + nmbOfSatellites = satpos.n_cols; // Armadillo arma::mat w = arma::zeros(nmbOfSatellites, nmbOfSatellites); - w.diag() = w_vec; //diagonal weight matrix + w.diag() = w_vec; //diagonal weight matrix - arma::vec pos = {d_rx_pos(0), d_rx_pos(0), d_rx_pos(0), 0}; // time error in METERS (time x speed) + arma::vec rx_pos = this->get_rx_pos(); + arma::vec pos = {rx_pos(0), rx_pos(1), rx_pos(2), 0}; // time error in METERS (time x speed) arma::mat A; arma::mat omc; - arma::mat az; - arma::mat el; A = arma::zeros(nmbOfSatellites, 4); omc = arma::zeros(nmbOfSatellites, 1); - az = arma::zeros(1, nmbOfSatellites); - el = arma::zeros(1, nmbOfSatellites); arma::mat X = satpos; arma::vec Rot_X; double rho2; @@ -209,7 +206,6 @@ arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs double dlambda; double dphi; double h; - arma::mat mat_tmp; arma::vec x; //=== Iteratively find receiver position =================================== @@ -220,31 +216,33 @@ arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs if (iter == 0) { //--- Initialize variables at the first iteration -------------- - Rot_X = X.col(i); //Armadillo + Rot_X = X.col(i); //Armadillo trop = 0.0; } else { //--- Update equations ----------------------------------------- rho2 = (X(0, i) - pos(0)) * - (X(0, i) - pos(0)) + (X(1, i) - pos(1)) * - (X(1, i) - pos(1)) + (X(2, i) - pos(2)) * - (X(2, i) - pos(2)); + (X(0, i) - pos(0)) + + (X(1, i) - pos(1)) * + (X(1, i) - pos(1)) + + (X(2, i) - pos(2)) * + (X(2, i) - pos(2)); traveltime = sqrt(rho2) / GPS_C_m_s; //--- Correct satellite position (do to earth rotation) -------- - Rot_X = Ls_Pvt::rotateSatellite(traveltime, X.col(i)); //armadillo + Rot_X = Ls_Pvt::rotateSatellite(traveltime, X.col(i)); //armadillo //--- Find DOA and range of satellites - Ls_Pvt::topocent(&d_visible_satellites_Az[i], - &d_visible_satellites_El[i], - &d_visible_satellites_Distance[i], - pos.subvec(0,2), - Rot_X - pos.subvec(0, 2)); - if(traveltime < 0.1 && nmbOfSatellites > 3) + double* azim = nullptr; + double* elev = nullptr; + double* dist = nullptr; + topocent(azim, elev, dist, pos.subvec(0, 2), Rot_X - pos.subvec(0, 2)); + + if (traveltime < 0.1 && nmbOfSatellites > 3) { //--- Find receiver's height - Ls_Pvt::togeod(&dphi, &dlambda, &h, 6378137.0, 298.257223563, pos(0), pos(1), pos(2)); + togeod(&dphi, &dlambda, &h, 6378137.0, 298.257223563, pos(0), pos(1), pos(2)); // Add troposphere correction if the receiver is below the troposphere if (h > 15000) { @@ -254,36 +252,33 @@ arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs else { //--- Find delay due to troposphere (in meters) - Ls_Pvt::tropo(&trop, sin(d_visible_satellites_El[i] * GPS_PI / 180.0), h / 1000.0, 1013.0, 293.0, 50.0, 0.0, 0.0, 0.0); - if(trop > 5.0 ) trop = 0.0; //check for erratic values + Ls_Pvt::tropo(&trop, sin(*elev * GPS_PI / 180.0), h / 1000.0, 1013.0, 293.0, 50.0, 0.0, 0.0, 0.0); + if (trop > 5.0) trop = 0.0; //check for erratic values } } } //--- Apply the corrections ---------------------------------------- - omc(i) = (obs(i) - norm(Rot_X - pos.subvec(0, 2), 2) - pos(3) - trop); // Armadillo + omc(i) = (obs(i) - norm(Rot_X - pos.subvec(0, 2), 2) - pos(3) - trop); // Armadillo //--- Construct the A matrix --------------------------------------- //Armadillo - A(i,0) = (-(Rot_X(0) - pos(0))) / obs(i); - A(i,1) = (-(Rot_X(1) - pos(1))) / obs(i); - A(i,2) = (-(Rot_X(2) - pos(2))) / obs(i); - A(i,3) = 1.0; + A(i, 0) = (-(Rot_X(0) - pos(0))) / obs(i); + A(i, 1) = (-(Rot_X(1) - pos(1))) / obs(i); + A(i, 2) = (-(Rot_X(2) - pos(2))) / obs(i); + A(i, 3) = 1.0; } //--- Find position update --------------------------------------------- - x = arma::solve(w*A, w*omc); // Armadillo + x = arma::solve(w * A, w * omc); // Armadillo //--- Apply position update -------------------------------------------- pos = pos + x; - if (arma::norm(x,2) < 1e-4) + if (arma::norm(x, 2) < 1e-4) { - break; // exit the loop because we assume that the LS algorithm has converged (err < 0.1 cm) + break; // exit the loop because we assume that the LS algorithm has converged (err < 0.1 cm) } } - //-- compute the Dilution Of Precision values - d_Q = arma::inv(arma::htrans(A) * A); - // check the consistency of the PVT solution if (((fabs(pos(3)) * 1000.0) / GPS_C_m_s) > GPS_STARTOFFSET_ms * 2) { @@ -292,5 +287,3 @@ arma::vec Ls_Pvt::leastSquarePos(const arma::mat & satpos, const arma::vec & obs } return pos; } - - diff --git a/src/algorithms/PVT/libs/ls_pvt.h b/src/algorithms/PVT/libs/ls_pvt.h index 9332c198c..78ad9deef 100644 --- a/src/algorithms/PVT/libs/ls_pvt.h +++ b/src/algorithms/PVT/libs/ls_pvt.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -45,20 +45,20 @@ private: /*! * \brief Computes the Lorentz inner product between two vectors */ - double lorentz(const arma::vec & x,const arma::vec & y); + double lorentz(const arma::vec& x, const arma::vec& y); + public: Ls_Pvt(); /*! * \brief Computes the initial position solution based on the Bancroft algorithm */ - arma::vec bancroftPos(const arma::mat & satpos, const arma::vec & obs); + arma::vec bancroftPos(const arma::mat& satpos, const arma::vec& obs); /*! * \brief Computes the Weighted Least Squares position solution */ - arma::vec leastSquarePos(const arma::mat & satpos, const arma::vec & obs, const arma::vec & w_vec); - + arma::vec leastSquarePos(const arma::mat& satpos, const arma::vec& obs, const arma::vec& w_vec); }; #endif diff --git a/src/algorithms/PVT/libs/nmea_printer.cc b/src/algorithms/PVT/libs/nmea_printer.cc index e502dab75..2470b1819 100644 --- a/src/algorithms/PVT/libs/nmea_printer.cc +++ b/src/algorithms/PVT/libs/nmea_printer.cc @@ -1,5 +1,5 @@ /*! - * \file kml_printer.cc + * \file nmea_printer.cc * \brief Implementation of a NMEA 2.1 printer for GNSS-SDR * This class provides a implementation of a subset of the NMEA-0183 standard for interfacing * marine electronic devices as defined by the National Marine Electronics Association (NMEA). @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,37 +28,81 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "nmea_printer.h" +#include "rtklib_solution.h" +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem +#include +#include #include #include -#include -#include -#include - using google::LogMessage; -//DEFINE_string(NMEA_version, "2.1", "Specifies the NMEA version (2.1)"); -Nmea_Printer::Nmea_Printer(std::string filename, bool flag_nmea_tty_port, std::string nmea_dump_devname) +Nmea_Printer::Nmea_Printer(const std::string& filename, bool flag_nmea_output_file, bool flag_nmea_tty_port, std::string nmea_dump_devname, const std::string& base_path) { - nmea_filename = filename; - nmea_file_descriptor.open(nmea_filename.c_str(), std::ios::out); - if (nmea_file_descriptor.is_open()) + nmea_base_path = base_path; + d_flag_nmea_output_file = flag_nmea_output_file; + if (d_flag_nmea_output_file == true) { - DLOG(INFO) << "NMEA printer writing on " << nmea_filename.c_str(); + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(nmea_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(nmea_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + nmea_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + nmea_base_path = p.string(); + } + + if ((nmea_base_path != ".") and (d_flag_nmea_output_file == true)) + { + std::cout << "NMEA files will be stored at " << nmea_base_path << std::endl; + } + + nmea_base_path = nmea_base_path + boost::filesystem::path::preferred_separator; + + nmea_filename = nmea_base_path + filename; + + nmea_file_descriptor.open(nmea_filename.c_str(), std::ios::out); + if (nmea_file_descriptor.is_open()) + { + DLOG(INFO) << "NMEA printer writing on " << nmea_filename.c_str(); + } + else + { + std::cout << "File " << nmea_filename << " cannot be saved. Wrong permissions?" << std::endl; + } } - nmea_devname = nmea_dump_devname; + nmea_devname = std::move(nmea_dump_devname); if (flag_nmea_tty_port == true) { - nmea_dev_descriptor = init_serial(nmea_devname.c_str()); + nmea_dev_descriptor = init_serial(nmea_devname); if (nmea_dev_descriptor != -1) { DLOG(INFO) << "NMEA printer writing on " << nmea_devname.c_str(); @@ -72,8 +116,6 @@ Nmea_Printer::Nmea_Printer(std::string filename, bool flag_nmea_tty_port, std::s } - - Nmea_Printer::~Nmea_Printer() { if (nmea_file_descriptor.is_open()) @@ -84,29 +126,29 @@ Nmea_Printer::~Nmea_Printer() } - - -int Nmea_Printer::init_serial (std::string serial_device) +int Nmea_Printer::init_serial(const std::string& serial_device) { /*! * Opens the serial device and sets the default baud rate for a NMEA transmission (9600,8,N,1) */ int fd = 0; - struct termios options; - long BAUD; - long DATABITS; - long STOPBITS; - long PARITYON; - long PARITY; + struct termios options + { + }; + int64_t BAUD; + int64_t DATABITS; + int64_t STOPBITS; + int64_t PARITYON; + int64_t PARITY; - fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); - if (fd == -1) return fd; //failed to open TTY port + fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC); + if (fd == -1) return fd; // failed to open TTY port - if(fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O - tcgetattr(fd, &options); // read serial port options + if (fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O + tcgetattr(fd, &options); // read serial port options - BAUD = B9600; - //BAUD = B38400; + BAUD = B9600; + // BAUD = B38400; DATABITS = CS8; STOPBITS = 0; PARITYON = 0; @@ -114,7 +156,7 @@ int Nmea_Printer::init_serial (std::string serial_device) options.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD; // enable receiver, set 8 bit data, ignore control lines - //options.c_cflag |= (CLOCAL | CREAD | CS8); + // options.c_cflag |= (CLOCAL | CREAD | CS8); options.c_iflag = IGNPAR; // set the new port options @@ -123,8 +165,7 @@ int Nmea_Printer::init_serial (std::string serial_device) } - -void Nmea_Printer::close_serial () +void Nmea_Printer::close_serial() { if (nmea_dev_descriptor != -1) { @@ -133,7 +174,7 @@ void Nmea_Printer::close_serial () } -bool Nmea_Printer::Print_Nmea_Line(const std::shared_ptr& pvt_data, bool print_average_values) +bool Nmea_Printer::Print_Nmea_Line(const std::shared_ptr& pvt_data, bool print_average_values) { std::string GPRMC; std::string GPGGA; @@ -146,51 +187,54 @@ bool Nmea_Printer::Print_Nmea_Line(const std::shared_ptr& pvt_data // generate the NMEA sentences - //GPRMC + // GPRMC GPRMC = get_GPRMC(); - //GPGGA (Global Positioning System Fixed Data) + // GPGGA (Global Positioning System Fixed Data) GPGGA = get_GPGGA(); - //GPGSA + // GPGSA GPGSA = get_GPGSA(); - //GPGSV + // GPGSV GPGSV = get_GPGSV(); // write to log file - try - { - //GPRMC - nmea_file_descriptor << GPRMC; - //GPGGA (Global Positioning System Fixed Data) - nmea_file_descriptor << GPGGA; - //GPGSA - nmea_file_descriptor << GPGSA; - //GPGSV - nmea_file_descriptor << GPGSV; - } - catch(std::exception ex) - { - DLOG(INFO) << "NMEA printer can not write on output file" << nmea_filename.c_str();; - } - - //write to serial device - if (nmea_dev_descriptor!=-1) + if (d_flag_nmea_output_file) { - if(write(nmea_dev_descriptor, GPRMC.c_str(), GPRMC.length()) == -1) + try + { + // GPRMC + nmea_file_descriptor << GPRMC; + // GPGGA (Global Positioning System Fixed Data) + nmea_file_descriptor << GPGGA; + // GPGSA + nmea_file_descriptor << GPGSA; + // GPGSV + nmea_file_descriptor << GPGSV; + } + catch (const std::exception& ex) + { + DLOG(INFO) << "NMEA printer can not write on output file" << nmea_filename.c_str(); + } + } + + // write to serial device + if (nmea_dev_descriptor != -1) + { + if (write(nmea_dev_descriptor, GPRMC.c_str(), GPRMC.length()) == -1) { DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str(); return false; } - if(write(nmea_dev_descriptor, GPGGA.c_str(), GPGGA.length()) == -1) + if (write(nmea_dev_descriptor, GPGGA.c_str(), GPGGA.length()) == -1) { DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str(); return false; } - if(write(nmea_dev_descriptor, GPGSA.c_str(), GPGSA.length()) == -1) + if (write(nmea_dev_descriptor, GPGSA.c_str(), GPGSA.length()) == -1) { DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str(); return false; } - if(write(nmea_dev_descriptor, GPGSV.c_str(), GPGSV.length()) == -1) + if (write(nmea_dev_descriptor, GPGSV.c_str(), GPGSV.length()) == -1) { DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str(); return false; @@ -200,28 +244,26 @@ bool Nmea_Printer::Print_Nmea_Line(const std::shared_ptr& pvt_data } - char Nmea_Printer::checkSum(std::string sentence) { char check = 0; // iterate over the string, XOR each byte with the total sum: - for (unsigned int c = 0; c < sentence.length(); c++) + for (char c : sentence) { - check = char(check ^ sentence.at(c)); + check = char(check ^ c); } // return the result return check; } - std::string Nmea_Printer::latitude_to_hm(double lat) { bool north; if (lat < 0.0) { north = false; - lat = -lat ; + lat = -lat; } else { @@ -230,15 +272,16 @@ std::string Nmea_Printer::latitude_to_hm(double lat) int deg = static_cast(lat); double mins = lat - static_cast(deg); - mins *= 60.0 ; + mins *= 60.0; std::ostringstream out_string; out_string.setf(std::ios::fixed, std::ios::floatfield); out_string.fill('0'); out_string.width(2); out_string << deg; - out_string.width(6); - out_string.precision(4); - out_string << mins; + out_string.width(2); + out_string << static_cast(mins) << "."; + out_string.width(4); + out_string << static_cast((mins - static_cast(static_cast(mins))) * 1e4); if (north == true) { @@ -252,14 +295,13 @@ std::string Nmea_Printer::latitude_to_hm(double lat) } - std::string Nmea_Printer::longitude_to_hm(double longitude) { bool east; if (longitude < 0.0) { east = false; - longitude = -longitude ; + longitude = -longitude; } else { @@ -267,15 +309,16 @@ std::string Nmea_Printer::longitude_to_hm(double longitude) } int deg = static_cast(longitude); double mins = longitude - static_cast(deg); - mins *= 60.0 ; + mins *= 60.0; std::ostringstream out_string; out_string.setf(std::ios::fixed, std::ios::floatfield); out_string.width(3); out_string.fill('0'); out_string << deg; - out_string.width(6); - out_string.precision(4); - out_string << mins; + out_string.width(2); + out_string << static_cast(mins) << "."; + out_string.width(4); + out_string << static_cast((mins - static_cast(static_cast(mins))) * 1e4); if (east == true) { @@ -289,10 +332,9 @@ std::string Nmea_Printer::longitude_to_hm(double longitude) } - std::string Nmea_Printer::get_UTC_NMEA_time(boost::posix_time::ptime d_position_UTC_time) { - //UTC Time: hhmmss.sss + // UTC Time: hhmmss.sss std::stringstream sentence_str; boost::posix_time::time_duration td = d_position_UTC_time.time_of_day(); @@ -304,427 +346,78 @@ std::string Nmea_Printer::get_UTC_NMEA_time(boost::posix_time::ptime d_position_ utc_hours = td.hours(); utc_mins = td.minutes(); utc_seconds = td.seconds(); - utc_milliseconds = td.total_milliseconds() - td.total_seconds()*1000; + utc_milliseconds = td.total_milliseconds() - td.total_seconds() * 1000; - if (utc_hours < 10) sentence_str << "0"; // two digits for hours + if (utc_hours < 10) sentence_str << "0"; // two digits for hours sentence_str << utc_hours; - if (utc_mins < 10) sentence_str << "0"; // two digits for minutes + if (utc_mins < 10) sentence_str << "0"; // two digits for minutes sentence_str << utc_mins; - if (utc_seconds < 10) sentence_str << "0"; // two digits for seconds + if (utc_seconds < 10) sentence_str << "0"; // two digits for seconds sentence_str << utc_seconds; if (utc_milliseconds < 10) { - sentence_str << ".00"; // three digits for ms + sentence_str << ".00"; // three digits for ms sentence_str << utc_milliseconds; } else if (utc_milliseconds < 100) { - sentence_str << ".0"; // three digits for ms + sentence_str << ".0"; // three digits for ms sentence_str << utc_milliseconds; } else { - sentence_str << "."; // three digits for ms + sentence_str << "."; // three digits for ms sentence_str << utc_milliseconds; } return sentence_str.str(); } - std::string Nmea_Printer::get_GPRMC() { // Sample -> $GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,*10 - bool valid_fix = d_PVT_data->b_valid_position; - - // ToDo: Compute speed and course over ground - double speed_over_ground_knots = 0; - double course_over_ground_deg = 0; - - //boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time(); - std::stringstream sentence_str; - - //GPRMC (RMC-Recommended,Minimum Specific GNSS Data) - std::string sentence_header; - sentence_header = "$GPRMC,"; - sentence_str << sentence_header; - - //UTC Time: hhmmss.sss - sentence_str << get_UTC_NMEA_time(d_PVT_data->d_position_UTC_time); - - //Status: A: data valid, V: data NOT valid - - if (valid_fix == true) - { - sentence_str << ",A"; - } - else - { - sentence_str << ",V"; - }; - - if (print_avg_pos == true) - { - // Latitude ddmm.mmmm,(N or S) - sentence_str << "," << latitude_to_hm(d_PVT_data->d_avg_latitude_d); - // longitude dddmm.mmmm,(E or W) - sentence_str << "," << longitude_to_hm(d_PVT_data->d_avg_longitude_d); - } - else - { - // Latitude ddmm.mmmm,(N or S) - sentence_str << "," << latitude_to_hm(d_PVT_data->d_latitude_d); - // longitude dddmm.mmmm,(E or W) - sentence_str << "," << longitude_to_hm(d_PVT_data->d_longitude_d); - } - - //Speed over ground (knots) - sentence_str << ","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.precision(2); - sentence_str << speed_over_ground_knots; - - //course over ground (degrees) - sentence_str << ","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.precision(2); - sentence_str << course_over_ground_deg; - - // Date ddmmyy - boost::gregorian::date sentence_date = d_PVT_data->d_position_UTC_time.date(); - unsigned int year = sentence_date.year(); - unsigned int day = sentence_date.day(); - unsigned int month = sentence_date.month(); - - sentence_str << ","; - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << day; - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << month; - - std::stringstream year_strs; - year_strs << std::dec << year; - sentence_str << std::dec << year_strs.str().substr(2); - - //Magnetic Variation (degrees) - // ToDo: Implement magnetic compass - sentence_str << ","; - - //Magnetic Variation (E or W) - // ToDo: Implement magnetic compass - sentence_str << ","; - - // Checksum - char checksum; - std::string tmpstr; - tmpstr = sentence_str.str(); - checksum = checkSum(tmpstr.substr(1)); - sentence_str << "*"; - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << std::hex << static_cast(checksum); - - // end NMEA sentence - sentence_str << "\r\n"; + unsigned char buff[1024] = {0}; + outnmea_rmc(buff, &d_PVT_data->pvt_sol); + sentence_str << buff; return sentence_str.str(); } - std::string Nmea_Printer::get_GPGSA() { - //$GPGSA,A,3,07,02,26,27,09,04,15, , , , , ,1.8,1.0,1.5*33 + // $GPGSA,A,3,07,02,26,27,09,04,15, , , , , ,1.8,1.0,1.5*33 // GSA-GNSS DOP and Active Satellites - bool valid_fix = d_PVT_data->b_valid_position; - int n_sats_used = d_PVT_data->d_valid_observations; - double pdop = d_PVT_data->d_PDOP; - double hdop = d_PVT_data->d_HDOP; - double vdop = d_PVT_data->d_VDOP; - std::stringstream sentence_str; - std::string sentence_header; - sentence_header = "$GPGSA,"; - sentence_str << sentence_header; - - // mode1: - // (M) Manual-forced to operate in 2D or 3D mode - // (A) Automatic-allowed to automatically switch 2D/3D - std::string mode1 = "M"; - sentence_str << mode1; - - // mode2: - // 1 fix not available - // 2 fix 2D - // 3 fix 3D - if (valid_fix==true) - { - sentence_str << ",3"; - } - else - { - sentence_str << ",1"; - }; - - // Used satellites - for (int i=0; i<12; i++) - { - sentence_str << ","; - if (i < n_sats_used) - { - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << d_PVT_data->d_visible_satellites_IDs[i]; - } - } - - // PDOP - sentence_str << ","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.width(2); - sentence_str.precision(1); - sentence_str.fill('0'); - sentence_str << pdop; - //HDOP - sentence_str<<","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.width(2); - sentence_str.precision(1); - sentence_str.fill('0'); - sentence_str << hdop; - //VDOP - sentence_str << ","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.width(2); - sentence_str.precision(1); - sentence_str.fill('0'); - sentence_str << vdop; - - // Checksum - char checksum; - std::string tmpstr; - tmpstr = sentence_str.str(); - checksum = checkSum(tmpstr.substr(1)); - sentence_str << "*"; - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << std::hex << static_cast(checksum); - - // end NMEA sentence - sentence_str << "\r\n"; + unsigned char buff[1024] = {0}; + outnmea_gsa(buff, &d_PVT_data->pvt_sol, d_PVT_data->pvt_ssat); + sentence_str << buff; return sentence_str.str(); } - - std::string Nmea_Printer::get_GPGSV() { // GSV-GNSS Satellites in View + // $GPGSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71 // Notice that NMEA 2.1 only supports 12 channels - int n_sats_used = d_PVT_data->d_valid_observations; std::stringstream sentence_str; - std::stringstream frame_str; - std::string sentence_header; - sentence_header = "$GPGSV,"; - char checksum; - std::string tmpstr; - - // 1st step: How many GPGSV frames we need? (up to 3) - // Each frame contains up to 4 satellites - int n_frames; - n_frames = std::ceil((static_cast(n_sats_used)) / 4.0); - - // generate the frames - int current_satellite = 0; - for (int i=1; i<(n_frames+1); i++) - { - frame_str.str(""); - frame_str << sentence_header; - - // number of messages - frame_str << n_frames; - - // message number - frame_str << ","; - frame_str << i; - - // total number of satellites in view - frame_str << ","; - frame_str.width(2); - frame_str.fill('0'); - frame_str << std::dec << n_sats_used; - - //satellites info - for (int j=0; j<4; j++) - { - // write satellite info - frame_str << ","; - frame_str.width(2); - frame_str.fill('0'); - frame_str << std::dec << d_PVT_data->d_visible_satellites_IDs[current_satellite]; - - frame_str << ","; - frame_str.width(2); - frame_str.fill('0'); - frame_str << std::dec << static_cast(d_PVT_data->d_visible_satellites_El[current_satellite]); - - frame_str << ","; - frame_str.width(3); - frame_str.fill('0'); - frame_str << std::dec << static_cast(d_PVT_data->d_visible_satellites_Az[current_satellite]); - - frame_str << ","; - frame_str.width(2); - frame_str.fill('0'); - frame_str << std::dec << static_cast(d_PVT_data->d_visible_satellites_CN0_dB[current_satellite]); - - current_satellite++; - - if (current_satellite == n_sats_used) - { - break; - } - } - - // frame checksum - tmpstr = frame_str.str(); - checksum = checkSum(tmpstr.substr(1)); - frame_str << "*"; - frame_str.width(2); - frame_str.fill('0'); - frame_str << std::hex << static_cast(checksum); - - // end NMEA sentence - frame_str << "\r\n"; - - //add frame to sentence - sentence_str << frame_str.str(); - } + unsigned char buff[1024] = {0}; + outnmea_gsv(buff, &d_PVT_data->pvt_sol, d_PVT_data->pvt_ssat); + sentence_str << buff; return sentence_str.str(); - //$GPGSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71 } - - - std::string Nmea_Printer::get_GPGGA() { - //boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time(); - bool valid_fix = d_PVT_data->b_valid_position; - int n_channels = d_PVT_data->d_valid_observations;//d_nchannels - double hdop = d_PVT_data->d_HDOP; - double MSL_altitude; - - if (d_PVT_data->d_flag_averaging == true) - { - MSL_altitude = d_PVT_data->d_avg_height_m; - } - else - { - MSL_altitude = d_PVT_data->d_height_m; - } - std::stringstream sentence_str; - - //GPGGA (Global Positioning System Fixed Data) - std::string sentence_header; - sentence_header = "$GPGGA,"; - sentence_str << sentence_header; - - //UTC Time: hhmmss.sss - sentence_str << get_UTC_NMEA_time(d_PVT_data->d_position_UTC_time); - - if (d_PVT_data->d_flag_averaging == true) - { - // Latitude ddmm.mmmm,(N or S) - sentence_str << "," << latitude_to_hm(d_PVT_data->d_avg_latitude_d); - // longitude dddmm.mmmm,(E or W) - sentence_str << "," << longitude_to_hm(d_PVT_data->d_avg_longitude_d); - } - else - { - // Latitude ddmm.mmmm,(N or S) - sentence_str << "," << latitude_to_hm(d_PVT_data->d_latitude_d); - // longitude dddmm.mmmm,(E or W) - sentence_str << "," << longitude_to_hm(d_PVT_data->d_longitude_d); - } - - // Position fix indicator - // 0 - Fix not available or invalid - // 1 - GPS SPS Mode, fix valid - // 2 - Differential GPS, SPS Mode, fix valid - // 3-5 - Not supported - // 6 - Dead Reckoning Mode, fix valid - // ToDo: Update PVT module to identify the fix mode - - if (valid_fix == true) - { - sentence_str << ",1"; - } - else - { - sentence_str << ",0"; - } - - // Number of satellites used in PVT - sentence_str << ","; - if (n_channels < 10) - { - sentence_str << '0' << n_channels; - } - else - { - sentence_str << n_channels; - } - - // HDOP - sentence_str << ","; - sentence_str.setf(std::ios::fixed, std::ios::floatfield); - sentence_str.width(2); - sentence_str.precision(1); - sentence_str.fill('0'); - sentence_str << hdop; - - // MSL Altitude - sentence_str << ","; - sentence_str.precision(1); - sentence_str << MSL_altitude; - sentence_str << ",M"; - - // Geoid-to-ellipsoid separation. Ellipsoid altitude = MSL Altitude + Geoid Separation. - // ToDo: Compute this value - sentence_str << ","; - sentence_str << "0.0"; - sentence_str << ",M"; - - // Age of Diff. Corr. (Seconds) Null fields when DGPS is not used - // Diff. Ref. Station ID (0000) - // ToDo: Implement this fields for Differential GPS - sentence_str << ","; - sentence_str << "0.0,0000"; - - // Checksum - char checksum; - std::string tmpstr; - tmpstr = sentence_str.str(); - checksum = checkSum(tmpstr.substr(1)); - sentence_str << "*"; - sentence_str.width(2); - sentence_str.fill('0'); - sentence_str << std::hex << static_cast(checksum); - - // end NMEA sentence - sentence_str << "\r\n"; + unsigned char buff[1024] = {0}; + outnmea_gga(buff, &d_PVT_data->pvt_sol); + sentence_str << buff; return sentence_str.str(); - //$GPGGA,104427.591,5920.7009,N,01803.2938,E,1,05,3.3,78.2,M,23.2,M,0.0,0000*4A + // $GPGGA,104427.591,5920.7009,N,01803.2938,E,1,05,3.3,78.2,M,23.2,M,0.0,0000*4A } - - - diff --git a/src/algorithms/PVT/libs/nmea_printer.h b/src/algorithms/PVT/libs/nmea_printer.h index 8e594547e..c73ef91ff 100644 --- a/src/algorithms/PVT/libs/nmea_printer.h +++ b/src/algorithms/PVT/libs/nmea_printer.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,11 +36,9 @@ #ifndef GNSS_SDR_NMEA_PRINTER_H_ #define GNSS_SDR_NMEA_PRINTER_H_ - -#include +#include "rtklib_solver.h" #include #include -#include "pvt_solution.h" /*! @@ -55,12 +53,12 @@ public: /*! * \brief Default constructor. */ - Nmea_Printer(std::string filename, bool flag_nmea_tty_port, std::string nmea_dump_filename); + Nmea_Printer(const std::string& filename, bool flag_nmea_output_file, bool flag_nmea_tty_port, std::string nmea_dump_devname, const std::string& base_path = "."); /*! * \brief Print NMEA PVT and satellite info to the initialized device */ - bool Print_Nmea_Line(const std::shared_ptr& position, bool print_average_values); + bool Print_Nmea_Line(const std::shared_ptr& pvt_data, bool print_average_values); /*! * \brief Default destructor. @@ -68,22 +66,24 @@ public: ~Nmea_Printer(); private: - std::string nmea_filename; // String with the NMEA log filename - std::ofstream nmea_file_descriptor; // Output file stream for NMEA log file + std::string nmea_filename; // String with the NMEA log filename + std::string nmea_base_path; + std::ofstream nmea_file_descriptor; // Output file stream for NMEA log file std::string nmea_devname; - int nmea_dev_descriptor; // NMEA serial device descriptor (i.e. COM port) - std::shared_ptr d_PVT_data; - int init_serial(std::string serial_device); //serial port control + int nmea_dev_descriptor; // NMEA serial device descriptor (i.e. COM port) + std::shared_ptr d_PVT_data; + int init_serial(const std::string& serial_device); //serial port control void close_serial(); - std::string get_GPGGA(); // fix data - std::string get_GPGSV(); // satellite data - std::string get_GPGSA(); // overall satellite reception data - std::string get_GPRMC(); // minimum recommended data + std::string get_GPGGA(); // fix data + std::string get_GPGSV(); // satellite data + std::string get_GPGSA(); // overall satellite reception data + std::string get_GPRMC(); // minimum recommended data std::string get_UTC_NMEA_time(boost::posix_time::ptime d_position_UTC_time); std::string longitude_to_hm(double longitude); std::string latitude_to_hm(double lat); char checkSum(std::string sentence); bool print_avg_pos; + bool d_flag_nmea_output_file; }; #endif diff --git a/src/algorithms/PVT/libs/pvt_conf.cc b/src/algorithms/PVT/libs/pvt_conf.cc new file mode 100644 index 000000000..0f528f438 --- /dev/null +++ b/src/algorithms/PVT/libs/pvt_conf.cc @@ -0,0 +1,70 @@ +/*! + * \file pvt_conf.cc + * \brief Class that contains all the configuration parameters for a PVT block + * \author Carles Fernandez, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "pvt_conf.h" + +Pvt_Conf::Pvt_Conf() +{ + type_of_receiver = 0U; + output_rate_ms = 0; + display_rate_ms = 0; + + rinex_version = 0; + rinexobs_rate_ms = 0; + rinexnav_rate_ms = 0; + + dump = false; + dump_mat = true; + + flag_nmea_tty_port = false; + + flag_rtcm_server = false; + flag_rtcm_tty_port = false; + rtcm_tcp_port = 0U; + rtcm_station_id = 0U; + + output_enabled = true; + rinex_output_enabled = true; + gpx_output_enabled = true; + geojson_output_enabled = true; + nmea_output_file_enabled = true; + kml_output_enabled = true; + xml_output_enabled = true; + rtcm_output_file_enabled = true; + + output_path = std::string("."); + rinex_output_path = std::string("."); + gpx_output_path = std::string("."); + geojson_output_path = std::string("."); + nmea_output_file_path = std::string("."); + kml_output_path = std::string("."); + xml_output_path = std::string("."); + rtcm_output_file_path = std::string("."); +} diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h new file mode 100644 index 000000000..f5e9af10e --- /dev/null +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -0,0 +1,86 @@ +/*! + * \file pvt_conf.h + * \brief Class that contains all the configuration parameters for the PVT block + * \author Carles Fernandez, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PVT_CONF_H_ +#define GNSS_SDR_PVT_CONF_H_ + +#include +#include +#include +#include + +class Pvt_Conf +{ +public: + uint32_t type_of_receiver; + int32_t output_rate_ms; + int32_t display_rate_ms; + + int32_t rinex_version; + int32_t rinexobs_rate_ms; + int32_t rinexnav_rate_ms; + std::map rtcm_msg_rate_ms; + + bool dump; + bool dump_mat; + std::string dump_filename; + + bool flag_nmea_tty_port; + std::string nmea_dump_filename; + std::string nmea_dump_devname; + + bool flag_rtcm_server; + bool flag_rtcm_tty_port; + uint16_t rtcm_tcp_port; + uint16_t rtcm_station_id; + std::string rtcm_dump_devname; + + bool output_enabled; + bool rinex_output_enabled; + bool gpx_output_enabled; + bool geojson_output_enabled; + bool nmea_output_file_enabled; + bool kml_output_enabled; + bool xml_output_enabled; + bool rtcm_output_file_enabled; + + std::string output_path; + std::string rinex_output_path; + std::string gpx_output_path; + std::string geojson_output_path; + std::string nmea_output_file_path; + std::string kml_output_path; + std::string xml_output_path; + std::string rtcm_output_file_path; + + Pvt_Conf(); +}; + +#endif diff --git a/src/algorithms/PVT/libs/pvt_solution.cc b/src/algorithms/PVT/libs/pvt_solution.cc index 69ebd6e6d..b1366a751 100644 --- a/src/algorithms/PVT/libs/pvt_solution.cc +++ b/src/algorithms/PVT/libs/pvt_solution.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,44 +24,40 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pvt_solution.h" -#include #include "GPS_L1_CA.h" -#include +#include "geofunctions.h" #include +#include using google::LogMessage; -DEFINE_bool(tropo, true, "Apply tropospheric correction"); Pvt_Solution::Pvt_Solution() { d_latitude_d = 0.0; d_longitude_d = 0.0; d_height_m = 0.0; + d_speed_over_ground_m_s = 0.0; + d_course_over_ground_d = 0.0; d_avg_latitude_d = 0.0; d_avg_longitude_d = 0.0; d_avg_height_m = 0.0; - d_GDOP = 0.0; - d_PDOP = 0.0; - d_HDOP = 0.0; - d_VDOP = 0.0; - d_TDOP = 0.0; d_flag_averaging = false; b_valid_position = false; d_averaging_depth = 0; d_valid_observations = 0; - d_rx_pos = arma::zeros(3,1); + d_rx_pos = arma::zeros(3, 1); d_rx_dt_s = 0.0; } -arma::vec Pvt_Solution::rotateSatellite(double const traveltime, const arma::vec & X_sat) +arma::vec Pvt_Solution::rotateSatellite(double const traveltime, const arma::vec &X_sat) { /* * Returns rotated satellite ECEF coordinates due to Earth @@ -80,16 +76,9 @@ arma::vec Pvt_Solution::rotateSatellite(double const traveltime, const arma::vec omegatau = OMEGA_EARTH_DOT * traveltime; //--- Build a rotation matrix ---------------------------------------------- - arma::mat R3 = arma::zeros(3,3); - R3(0, 0) = cos(omegatau); - R3(0, 1) = sin(omegatau); - R3(0, 2) = 0.0; - R3(1, 0) = -sin(omegatau); - R3(1, 1) = cos(omegatau); - R3(1, 2) = 0.0; - R3(2, 0) = 0.0; - R3(2, 1) = 0.0; - R3(2, 2) = 1; + arma::mat R3 = {{cos(omegatau), sin(omegatau), 0.0}, + {-sin(omegatau), cos(omegatau), 0.0}, + {0.0, 0.0, 1.0}}; //--- Do the rotation ------------------------------------------------------ arma::vec X_sat_rot; @@ -114,7 +103,7 @@ int Pvt_Solution::cart2geo(double X, double Y, double Z, int elipsoid_selection) const double a[5] = {6378388.0, 6378160.0, 6378135.0, 6378137.0, 6378137.0}; const double f[5] = {1.0 / 297.0, 1.0 / 298.247, 1.0 / 298.26, 1.0 / 298.257222101, 1.0 / 298.257223563}; - double lambda = atan2(Y, X); + double lambda = atan2(Y, X); double ex2 = (2.0 - f[elipsoid_selection]) * f[elipsoid_selection] / ((1.0 - f[elipsoid_selection]) * (1.0 - f[elipsoid_selection])); double c = a[elipsoid_selection] * sqrt(1.0 + ex2); double phi = atan(Z / ((sqrt(X * X + Y * Y) * (1.0 - (2.0 - f[elipsoid_selection])) * f[elipsoid_selection]))); @@ -127,12 +116,12 @@ int Pvt_Solution::cart2geo(double X, double Y, double Z, int elipsoid_selection) { oldh = h; N = c / sqrt(1 + ex2 * (cos(phi) * cos(phi))); - phi = atan(Z / ((sqrt(X * X + Y * Y) * (1.0 - (2.0 - f[elipsoid_selection]) * f[elipsoid_selection] * N / (N + h) )))); + phi = atan(Z / ((sqrt(X * X + Y * Y) * (1.0 - (2.0 - f[elipsoid_selection]) * f[elipsoid_selection] * N / (N + h))))); h = sqrt(X * X + Y * Y) / cos(phi) - N; iterations = iterations + 1; if (iterations > 100) { - LOG(WARNING) << "Failed to approximate h with desired precision. h-oldh= " << h - oldh; + DLOG(WARNING) << "Failed to approximate h with desired precision. h-oldh= " << h - oldh; break; } } @@ -140,125 +129,7 @@ int Pvt_Solution::cart2geo(double X, double Y, double Z, int elipsoid_selection) d_latitude_d = phi * 180.0 / GPS_PI; d_longitude_d = lambda * 180.0 / GPS_PI; d_height_m = h; - return 0; -} - - -int Pvt_Solution::togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z) -{ - /* Subroutine to calculate geodetic coordinates latitude, longitude, - height given Cartesian coordinates X,Y,Z, and reference ellipsoid - values semi-major axis (a) and the inverse of flattening (finv). - - The output units of angular quantities will be in decimal degrees - (15.5 degrees not 15 deg 30 min). The output units of h will be the - same as the units of X,Y,Z,a. - - Inputs: - a - semi-major axis of the reference ellipsoid - finv - inverse of flattening of the reference ellipsoid - X,Y,Z - Cartesian coordinates - - Outputs: - dphi - latitude - dlambda - longitude - h - height above reference ellipsoid - - Based in a Matlab function by Kai Borre - */ - - *h = 0; - double tolsq = 1.e-10; // tolerance to accept convergence - int maxit = 10; // max number of iterations - double rtd = 180.0 / GPS_PI; - - // compute square of eccentricity - double esq; - if (finv < 1.0E-20) - { - esq = 0.0; - } - else - { - esq = (2.0 - 1.0 / finv) / finv; - } - - // first guess - double P = sqrt(X * X + Y * Y); // P is distance from spin axis - - //direct calculation of longitude - if (P > 1.0E-20) - { - *dlambda = atan2(Y, X) * rtd; - } - else - { - *dlambda = 0.0; - } - - // correct longitude bound - if (*dlambda < 0) - { - *dlambda = *dlambda + 360.0; - } - - double r = sqrt(P * P + Z * Z); // r is distance from origin (0,0,0) - - double sinphi; - if (r > 1.0E-20) - { - sinphi = Z/r; - } - else - { - sinphi = 0.0; - } - *dphi = asin(sinphi); - - // initial value of height = distance from origin minus - // approximate distance from origin to surface of ellipsoid - if (r < 1.0E-20) - { - *h = 0; - return 1; - } - - *h = r - a * (1 - sinphi * sinphi/finv); - - // iterate - double cosphi; - double N_phi; - double dP; - double dZ; - double oneesq = 1.0 - esq; - - for (int i = 0; i < maxit; i++) - { - sinphi = sin(*dphi); - cosphi = cos(*dphi); - - // compute radius of curvature in prime vertical direction - N_phi = a / sqrt(1 - esq * sinphi * sinphi); - - // compute residuals in P and Z - dP = P - (N_phi + (*h)) * cosphi; - dZ = Z - (N_phi * oneesq + (*h)) * sinphi; - - // update height and latitude - *h = *h + (sinphi * dZ + cosphi * dP); - *dphi = *dphi + (cosphi * dZ - sinphi * dP)/(N_phi + (*h)); - - // test for convergence - if ((dP * dP + dZ * dZ) < tolsq) - { - break; - } - if (i == (maxit - 1)) - { - LOG(WARNING) << "The computation of geodetic coordinates did not converge"; - } - } - *dphi = (*dphi) * rtd; + //todo: refactor this class. Mix of duplicated functions, use either RTKLIB geodetic functions or geofunctions.h return 0; } @@ -287,61 +158,66 @@ int Pvt_Solution::tropo(double *ddr_m, double sinel, double hsta_km, double p_mb Translated to C++ by Carles Fernandez from a Matlab implementation by Kai Borre */ - const double a_e = 6378.137; // semi-major axis of earth ellipsoid - const double b0 = 7.839257e-5; + const double a_e = 6378.137; // semi-major axis of earth ellipsoid + const double b0 = 7.839257e-5; const double tlapse = -6.5; - const double em = -978.77 / (2.8704e6 * tlapse * 1.0e-5); + const double em = -978.77 / (2.8704e6 * tlapse * 1.0e-5); - double tkhum = t_kel + tlapse * (hhum_km - htkel_km); - double atkel = 7.5 * (tkhum - 273.15) / (237.3 + tkhum - 273.15); - double e0 = 0.0611 * hum * pow(10, atkel); - double tksea = t_kel - tlapse * htkel_km; - double tkelh = tksea + tlapse * hhum_km; - double e0sea = e0 * pow((tksea / tkelh), (4 * em)); - double tkelp = tksea + tlapse * hp_km; - double psea = p_mb * pow((tksea / tkelp), em); + double tkhum = t_kel + tlapse * (hhum_km - htkel_km); + double atkel = 7.5 * (tkhum - 273.15) / (237.3 + tkhum - 273.15); + double e0 = 0.0611 * hum * pow(10, atkel); + double tksea = t_kel - tlapse * htkel_km; + double tkelh = tksea + tlapse * hhum_km; + double e0sea = e0 * pow((tksea / tkelh), (4 * em)); + double tkelp = tksea + tlapse * hp_km; + double psea = p_mb * pow((tksea / tkelp), em); - if(sinel < 0) { sinel = 0.0; } + if (sinel < 0) + { + sinel = 0.0; + } - double tropo_delay = 0.0; - bool done = false; - double refsea = 77.624e-6 / tksea; - double htop = 1.1385e-5 / refsea; - refsea = refsea * psea; - double ref = refsea * pow(((htop - hsta_km) / htop), 4); + double tropo_delay = 0.0; + bool done = false; + double refsea = 77.624e-6 / tksea; + double htop = 1.1385e-5 / refsea; + refsea = refsea * psea; + double ref = refsea * pow(((htop - hsta_km) / htop), 4); double a; double b; double rtop; - while(1) + while (true) { rtop = pow((a_e + htop), 2) - pow((a_e + hsta_km), 2) * (1 - pow(sinel, 2)); // check to see if geometry is crazy - if(rtop < 0) { rtop = 0; } + if (rtop < 0) + { + rtop = 0; + } rtop = sqrt(rtop) - (a_e + hsta_km) * sinel; - a = -sinel / (htop - hsta_km); - b = -b0 * (1 - pow(sinel,2)) / (htop - hsta_km); + a = -sinel / (htop - hsta_km); + b = -b0 * (1 - pow(sinel, 2)) / (htop - hsta_km); arma::vec rn = arma::vec(8); rn.zeros(); - for(int i = 0; i<8; i++) + for (int i = 0; i < 8; i++) { - rn(i) = pow(rtop, (i+1+1)); - + rn(i) = pow(rtop, (i + 1 + 1)); } - arma::rowvec alpha = {2 * a, 2 * pow(a, 2) + 4 * b /3, a * (pow(a, 2) + 3 * b), - pow(a, 4)/5 + 2.4 * pow(a, 2) * b + 1.2 * pow(b, 2), 2 * a * b * (pow(a, 2) + 3 * b)/3, - pow(b, 2) * (6 * pow(a, 2) + 4 * b) * 1.428571e-1, 0, 0}; + arma::rowvec alpha = {2 * a, 2 * pow(a, 2) + 4 * b / 3, a * (pow(a, 2) + 3 * b), + pow(a, 4) / 5 + 2.4 * pow(a, 2) * b + 1.2 * pow(b, 2), 2 * a * b * (pow(a, 2) + 3 * b) / 3, + pow(b, 2) * (6 * pow(a, 2) + 4 * b) * 1.428571e-1, 0, 0}; - if(pow(b, 2) > 1.0e-35) + if (pow(b, 2) > 1.0e-35) { - alpha(6) = a * pow(b, 3) /2; + alpha(6) = a * pow(b, 3) / 2; alpha(7) = pow(b, 4) / 9; } @@ -350,159 +226,40 @@ int Pvt_Solution::tropo(double *ddr_m, double sinel, double hsta_km, double p_mb dr = dr + aux_(0, 0); tropo_delay = tropo_delay + dr * ref * 1000; - if(done == true) + if (done == true) { *ddr_m = tropo_delay; break; } - done = true; - refsea = (371900.0e-6 / tksea - 12.92e-6) / tksea; - htop = 1.1385e-5 * (1255 / tksea + 0.05) / refsea; - ref = refsea * e0sea * pow(((htop - hsta_km) / htop), 4); + done = true; + refsea = (371900.0e-6 / tksea - 12.92e-6) / tksea; + htop = 1.1385e-5 * (1255 / tksea + 0.05) / refsea; + ref = refsea * e0sea * pow(((htop - hsta_km) / htop), 4); } return 0; } -int Pvt_Solution::topocent(double *Az, double *El, double *D, const arma::vec & x, const arma::vec & dx) -{ - /* Transformation of vector dx into topocentric coordinate - system with origin at x - Inputs: - x - vector origin coordinates (in ECEF system [X; Y; Z;]) - dx - vector ([dX; dY; dZ;]). - Outputs: - D - vector length. Units like the input - Az - azimuth from north positive clockwise, degrees - El - elevation angle, degrees - - Based on a Matlab function by Kai Borre - */ - - double lambda; - double phi; - double h; - double dtr = GPS_PI / 180.0; - double a = 6378137.0; // semi-major axis of the reference ellipsoid WGS-84 - double finv = 298.257223563; // inverse of flattening of the reference ellipsoid WGS-84 - - // Transform x into geodetic coordinates - Pvt_Solution::togeod(&phi, &lambda, &h, a, finv, x(0), x(1), x(2)); - - double cl = cos(lambda * dtr); - double sl = sin(lambda * dtr); - double cb = cos(phi * dtr); - double sb = sin(phi * dtr); - - arma::mat F = arma::zeros(3,3); - - F(0,0) = -sl; - F(0,1) = -sb * cl; - F(0,2) = cb * cl; - - F(1,0) = cl; - F(1,1) = -sb * sl; - F(1,2) = cb * sl; - - F(2,0) = 0; - F(2,1) = cb; - F(2,2) = sb; - - arma::vec local_vector; - - local_vector = arma::htrans(F) * dx; - - double E = local_vector(0); - double N = local_vector(1); - double U = local_vector(2); - - double hor_dis; - hor_dis = sqrt(E * E + N * N); - - if (hor_dis < 1.0E-20) - { - *Az = 0; - *El = 90; - } - else - { - *Az = atan2(E, N) / dtr; - *El = atan2(U, hor_dis) / dtr; - } - - if (*Az < 0) - { - *Az = *Az + 360.0; - } - - *D = sqrt(dx(0) * dx(0) + dx(1) * dx(1) + dx(2) * dx(2)); - return 0; -} - - - -int Pvt_Solution::compute_DOP() -{ - // ###### Compute DOPs ######## - - // 1- Rotation matrix from ECEF coordinates to ENU coordinates - // ref: http://www.navipedia.net/index.php/Transformations_between_ECEF_and_ENU_coordinates - arma::mat F = arma::zeros(3,3); - F(0,0) = -sin(GPS_TWO_PI * (d_longitude_d/360.0)); - F(0,1) = -sin(GPS_TWO_PI * (d_latitude_d/360.0)) * cos(GPS_TWO_PI * (d_longitude_d/360.0)); - F(0,2) = cos(GPS_TWO_PI * (d_latitude_d/360.0)) * cos(GPS_TWO_PI * (d_longitude_d/360.0)); - - F(1,0) = cos((GPS_TWO_PI * d_longitude_d)/360.0); - F(1,1) = -sin((GPS_TWO_PI * d_latitude_d)/360.0) * sin((GPS_TWO_PI * d_longitude_d)/360.0); - F(1,2) = cos((GPS_TWO_PI * d_latitude_d/360.0)) * sin((GPS_TWO_PI * d_longitude_d)/360.0); - - F(2,0) = 0; - F(2,1) = cos((GPS_TWO_PI * d_latitude_d)/360.0); - F(2,2) = sin((GPS_TWO_PI * d_latitude_d/360.0)); - - // 2- Apply the rotation to the latest covariance matrix (available in ECEF from LS) - arma::mat Q_ECEF = d_Q.submat(0, 0, 2, 2); - arma::mat DOP_ENU = arma::zeros(3, 3); - - try - { - DOP_ENU = arma::htrans(F) * Q_ECEF * F; - d_GDOP = sqrt(arma::trace(DOP_ENU)); // Geometric DOP - d_PDOP = sqrt(DOP_ENU(0, 0) + DOP_ENU(1, 1) + DOP_ENU(2, 2));// PDOP - d_HDOP = sqrt(DOP_ENU(0, 0) + DOP_ENU(1, 1)); // HDOP - d_VDOP = sqrt(DOP_ENU(2, 2)); // VDOP - d_TDOP = sqrt(d_Q(3, 3)); // TDOP - } - catch(std::exception& ex) - { - d_GDOP = -1; // Geometric DOP - d_PDOP = -1; // PDOP - d_HDOP = -1; // HDOP - d_VDOP = -1; // VDOP - d_TDOP = -1; // TDOP - } - return 0; - -} - - - - -int Pvt_Solution::set_averaging_depth(int depth) +void Pvt_Solution::set_averaging_depth(int depth) { d_averaging_depth = depth; - return 0; } -int Pvt_Solution::pos_averaging(bool flag_averaring) +void Pvt_Solution::set_averaging_flag(bool flag) +{ + d_flag_averaging = flag; +} + + +void Pvt_Solution::perform_pos_averaging() { // MOVING AVERAGE PVT - bool avg = flag_averaring; + bool avg = d_flag_averaging; if (avg == true) { - if (d_hist_longitude_d.size() == (unsigned int)d_averaging_depth) + if (d_hist_longitude_d.size() == static_cast(d_averaging_depth)) { // Pop oldest value d_hist_longitude_d.pop_back(); @@ -520,7 +277,7 @@ int Pvt_Solution::pos_averaging(bool flag_averaring) { d_avg_latitude_d = d_avg_latitude_d + d_hist_latitude_d.at(i); d_avg_longitude_d = d_avg_longitude_d + d_hist_longitude_d.at(i); - d_avg_height_m = d_avg_height_m + d_hist_height_m.at(i); + d_avg_height_m = d_avg_height_m + d_hist_height_m.at(i); } d_avg_latitude_d = d_avg_latitude_d / static_cast(d_averaging_depth); d_avg_longitude_d = d_avg_longitude_d / static_cast(d_averaging_depth); @@ -545,6 +302,133 @@ int Pvt_Solution::pos_averaging(bool flag_averaring) { b_valid_position = true; } - return 0; } + +double Pvt_Solution::get_time_offset_s() const +{ + return d_rx_dt_s; +} + + +void Pvt_Solution::set_time_offset_s(double offset) +{ + d_rx_dt_s = offset; +} + + +double Pvt_Solution::get_latitude() const +{ + return d_latitude_d; +} + + +double Pvt_Solution::get_longitude() const +{ + return d_longitude_d; +} + + +double Pvt_Solution::get_height() const +{ + return d_height_m; +} + + +double Pvt_Solution::get_speed_over_ground() const +{ + return d_speed_over_ground_m_s; +} + + +void Pvt_Solution::set_speed_over_ground(double speed_m_s) +{ + d_speed_over_ground_m_s = speed_m_s; +} + + +void Pvt_Solution::set_course_over_ground(double cog_deg) +{ + d_course_over_ground_d = cog_deg; +} + + +double Pvt_Solution::get_course_over_ground() const +{ + return d_course_over_ground_d; +} + + +double Pvt_Solution::get_avg_latitude() const +{ + return d_avg_latitude_d; +} + + +double Pvt_Solution::get_avg_longitude() const +{ + return d_avg_longitude_d; +} + + +double Pvt_Solution::get_avg_height() const +{ + return d_avg_height_m; +} + + +bool Pvt_Solution::is_averaging() const +{ + return d_flag_averaging; +} + + +bool Pvt_Solution::is_valid_position() const +{ + return b_valid_position; +} + + +void Pvt_Solution::set_valid_position(bool is_valid) +{ + b_valid_position = is_valid; +} + + +void Pvt_Solution::set_rx_pos(const arma::vec &pos) +{ + d_rx_pos = pos; + d_latitude_d = d_rx_pos(0); + d_longitude_d = d_rx_pos(1); + d_height_m = d_rx_pos(2); +} + + +arma::vec Pvt_Solution::get_rx_pos() const +{ + return d_rx_pos; +} + + +boost::posix_time::ptime Pvt_Solution::get_position_UTC_time() const +{ + return d_position_UTC_time; +} + + +void Pvt_Solution::set_position_UTC_time(const boost::posix_time::ptime &pt) +{ + d_position_UTC_time = pt; +} + + +int Pvt_Solution::get_num_valid_observations() const +{ + return d_valid_observations; +} + + +void Pvt_Solution::set_num_valid_observations(int num) +{ + d_valid_observations = num; +} diff --git a/src/algorithms/PVT/libs/pvt_solution.h b/src/algorithms/PVT/libs/pvt_solution.h index 3b0681391..116cd771e 100644 --- a/src/algorithms/PVT/libs/pvt_solution.h +++ b/src/algorithms/PVT/libs/pvt_solution.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,11 +33,12 @@ #define GNSS_SDR_PVT_SOLUTION_H_ -#include #include #include +#include -#define PVT_MAX_CHANNELS 24 +const unsigned int PVT_MAX_CHANNELS = 90; +const unsigned int PVT_MAX_PRN = 127; // 126 is SBAS /*! * \brief Base class for a PVT solution @@ -45,52 +46,71 @@ */ class Pvt_Solution { -public: - Pvt_Solution(); +private: + double d_rx_dt_s; // RX time offset [s] - double d_latitude_d; //!< RX position Latitude WGS84 [deg] - double d_longitude_d; //!< RX position Longitude WGS84 [deg] - double d_height_m; //!< RX position height WGS84 [m] + double d_latitude_d; // RX position Latitude WGS84 [deg] + double d_longitude_d; // RX position Longitude WGS84 [deg] + double d_height_m; // RX position height WGS84 [m] + double d_speed_over_ground_m_s; // RX speed over ground [m/s] + double d_course_over_ground_d; // RX course over ground [deg] - arma::vec d_rx_pos; - double d_rx_dt_s; //!< RX time offset [s] - - boost::posix_time::ptime d_position_UTC_time; + double d_avg_latitude_d; // Averaged latitude in degrees + double d_avg_longitude_d; // Averaged longitude in degrees + double d_avg_height_m; // Averaged height [m] bool b_valid_position; - int d_valid_observations; //!< Number of valid pseudorange observations (valid satellites) - int d_visible_satellites_IDs[PVT_MAX_CHANNELS] = {}; //!< Array with the IDs of the valid satellites - double d_visible_satellites_El[PVT_MAX_CHANNELS] = {}; //!< Array with the LOS Elevation of the valid satellites - double d_visible_satellites_Az[PVT_MAX_CHANNELS] = {}; //!< Array with the LOS Azimuth of the valid satellites - double d_visible_satellites_Distance[PVT_MAX_CHANNELS] = {}; //!< Array with the LOS Distance of the valid satellites - double d_visible_satellites_CN0_dB[PVT_MAX_CHANNELS] = {}; //!< Array with the IDs of the valid satellites - - //averaging - int d_averaging_depth; //!< Length of averaging window std::deque d_hist_latitude_d; std::deque d_hist_longitude_d; std::deque d_hist_height_m; - double d_avg_latitude_d; //!< Averaged latitude in degrees - double d_avg_longitude_d; //!< Averaged longitude in degrees - double d_avg_height_m; //!< Averaged height [m] - int pos_averaging(bool flag_averaging); - - // DOP estimations - arma::mat d_Q; - double d_GDOP; - double d_PDOP; - double d_HDOP; - double d_VDOP; - double d_TDOP; - int compute_DOP(); //!< Compute Dilution Of Precision parameters - bool d_flag_averaging; + int d_averaging_depth; // Length of averaging window - int set_averaging_depth(int depth); + arma::vec d_rx_pos; + boost::posix_time::ptime d_position_UTC_time; + int d_valid_observations; - arma::vec rotateSatellite(double traveltime, const arma::vec & X_sat); +public: + Pvt_Solution(); + + double get_time_offset_s() const; //!< Get RX time offset [s] + void set_time_offset_s(double offset); //!< Set RX time offset [s] + + double get_latitude() const; //!< Get RX position Latitude WGS84 [deg] + double get_longitude() const; //!< Get RX position Longitude WGS84 [deg] + double get_height() const; //!< Get RX position height WGS84 [m] + + double get_speed_over_ground() const; //!< Get RX speed over ground [m/s] + void set_speed_over_ground(double speed_m_s); //!< Set RX speed over ground [m/s] + + double get_course_over_ground() const; //!< Get RX course over ground [deg] + void set_course_over_ground(double cog_deg); //!< Set RX course over ground [deg] + + double get_avg_latitude() const; //!< Get RX position averaged Latitude WGS84 [deg] + double get_avg_longitude() const; //!< Get RX position averaged Longitude WGS84 [deg] + double get_avg_height() const; //!< Get RX position averaged height WGS84 [m] + + void set_rx_pos(const arma::vec &pos); //!< Set position: Latitude [deg], longitude [deg], height [m] + arma::vec get_rx_pos() const; + + bool is_valid_position() const; + void set_valid_position(bool is_valid); + + boost::posix_time::ptime get_position_UTC_time() const; + void set_position_UTC_time(const boost::posix_time::ptime &pt); + + int get_num_valid_observations() const; //!< Get the number of valid pseudorange observations (valid satellites) + void set_num_valid_observations(int num); //!< Set the number of valid pseudorange observations (valid satellites) + + //averaging + void perform_pos_averaging(); + void set_averaging_depth(int depth); //!< Set length of averaging window + bool is_averaging() const; + void set_averaging_flag(bool flag); + + arma::vec rotateSatellite(double traveltime, const arma::vec &X_sat); /*! * \brief Conversion of Cartesian coordinates (X,Y,Z) to geographical @@ -107,44 +127,9 @@ public: * 4 - World Geodetic System 1984. * */ - int cart2geo(double X, double Y, double Z, int elipsoid_selection); + int cart2geo(double X, double Y, double Z, int elipsoid_selection); - /*! - * \brief Transformation of vector dx into topocentric coordinate system with origin at x - * - * \param[in] x Vector origin coordinates (in ECEF system [X; Y; Z;]) - * \param[in] dx Vector ([dX; dY; dZ;]). - * - * \param[out] D Vector length. Units like the input - * \param[out] Az Azimuth from north positive clockwise, degrees - * \param[out] El Elevation angle, degrees - * - * Based on a Matlab function by Kai Borre - */ - int topocent(double *Az, double *El, double *D, const arma::vec & x, const arma::vec & dx); - - /*! - * \brief Subroutine to calculate geodetic coordinates latitude, longitude, - * height given Cartesian coordinates X,Y,Z, and reference ellipsoid - * values semi-major axis (a) and the inverse of flattening (finv). - * - * The output units of angular quantities will be in decimal degrees - * (15.5 degrees not 15 deg 30 min). The output units of h will be the - * same as the units of X,Y,Z,a. - * - * \param[in] a - semi-major axis of the reference ellipsoid - * \param[in] finv - inverse of flattening of the reference ellipsoid - * \param[in] X,Y,Z - Cartesian coordinates - * - * \param[out] dphi - latitude - * \param[out] dlambda - longitude - * \param[out] h - height above reference ellipsoid - * - * Based in a Matlab function by Kai Borre - */ - int togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z); - - /*! + /*! * \brief Tropospheric correction * * \param[in] sinel - sin of elevation angle of satellite @@ -167,7 +152,7 @@ public: * * Translated to C++ by Carles Fernandez from a Matlab implementation by Kai Borre */ - int tropo(double *ddr_m, double sinel, double hsta_km, double p_mb, double t_kel, double hum, double hp_km, double htkel_km, double hhum_km); + int tropo(double *ddr_m, double sinel, double hsta_km, double p_mb, double t_kel, double hum, double hp_km, double htkel_km, double hhum_km); }; #endif diff --git a/src/algorithms/PVT/libs/rinex_printer.cc b/src/algorithms/PVT/libs/rinex_printer.cc index 51d1bad0c..cb7065e97 100644 --- a/src/algorithms/PVT/libs/rinex_printer.cc +++ b/src/algorithms/PVT/libs/rinex_printer.cc @@ -5,7 +5,7 @@ * \author Carles Fernandez Prades, 2011. cfernandez(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,47 +23,86 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "rinex_printer.h" -#include // for getlogin_r() -#include // for min and max -#include // for floor -#include // for getenv() -#include -#include -#include -#include -#include -#include #include #include #include -#include +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem #include +#include // for min and max +#include // for floor +#include // for getenv() +#include +#include +#include +#include // for getlogin_r() +#include +#include using google::LogMessage; -DEFINE_string(RINEX_version, "3.02", "Specifies the RINEX version (2.11 or 3.02)"); - -Rinex_Printer::Rinex_Printer(int conf_version) +Rinex_Printer::Rinex_Printer(int32_t conf_version, const std::string& base_path) { - navfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_GPS_NAV"); - obsfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_OBS"); - sbsfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_SBAS"); - navGalfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_GAL_NAV"); - navMixfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_MIXED_NAV"); + std::string base_rinex_path = base_path; + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(base_rinex_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(base_rinex_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + base_rinex_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + base_rinex_path = p.string(); + } + if (base_rinex_path != ".") + { + std::cout << "RINEX files will be stored at " << base_rinex_path << std::endl; + } + + navfilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_GPS_NAV"); + obsfilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_OBS"); + sbsfilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_SBAS"); + navGalfilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_GAL_NAV"); + navMixfilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_MIXED_NAV"); + navGlofilename = base_rinex_path + boost::filesystem::path::preferred_separator + Rinex_Printer::createFilename("RINEX_FILE_TYPE_GLO_NAV"); Rinex_Printer::navFile.open(navfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::obsFile.open(obsfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::sbsFile.open(sbsfilename, std::ios::out | std::ios::app); Rinex_Printer::navGalFile.open(navGalfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::navMixFile.open(navMixfilename, std::ios::out | std::ios::in | std::ios::app); + Rinex_Printer::navGloFile.open(navGlofilename, std::ios::out | std::ios::in | std::ios::app); + + if (!Rinex_Printer::navFile.is_open() or !Rinex_Printer::obsFile.is_open() or + !Rinex_Printer::sbsFile.is_open() or !Rinex_Printer::navGalFile.is_open() or + !Rinex_Printer::navMixFile.is_open() or !Rinex_Printer::navGloFile.is_open()) + { + std::cout << "RINEX files cannot be saved. Wrong permissions?" << std::endl; + } // RINEX v3.02 codes satelliteSystem["GPS"] = "G"; @@ -73,52 +112,52 @@ Rinex_Printer::Rinex_Printer(int conf_version) satelliteSystem["Beidou"] = "C"; satelliteSystem["Mixed"] = "M"; - observationCode["GPS_L1_CA"] = "1C"; // "1C" GPS L1 C/A - observationCode["GPS_L1_P"] = "1P"; // "1P" GPS L1 P - observationCode["GPS_L1_Z_TRACKING"] = "1W"; // "1W" GPS L1 Z-tracking and similar (AS on) - observationCode["GPS_L1_Y"] = "1Y"; // "1Y" GPS L1 Y - observationCode["GPS_L1_M "] = "1M"; // "1M" GPS L1 M - observationCode["GPS_L1_CODELESS"] = "1N"; // "1N" GPS L1 codeless - observationCode["GPS_L2_CA"] = "2C"; // "2C" GPS L2 C/A - observationCode["L2_SEMI_CODELESS"] = "2D"; // "2D" GPS L2 L1(C/A)+(P2-P1) semi-codeless - observationCode["GPS_L2_L2CM"] = "2S"; // "2S" GPS L2 L2C (M) - observationCode["GPS_L2_L2CL"] = "2L"; // "2L" GPS L2 L2C (L) - observationCode["GPS_L2_L2CML"] = "2X"; // "2X" GPS L2 L2C (M+L) - observationCode["GPS_L2_P"] = "2P"; // "2P" GPS L2 P - observationCode["GPS_L2_Z_TRACKING"] = "2W"; // "2W" GPS L2 Z-tracking and similar (AS on) - observationCode["GPS_L2_Y"] = "2Y"; // "2Y" GPS L2 Y - observationCode["GPS_L2_M"] = "2M"; // "2M" GPS GPS L2 M - observationCode["GPS_L2_codeless"] = "2N"; // "2N" GPS L2 codeless - observationCode["GPS_L5_I"] = "5I"; // "5I" GPS L5 I - observationCode["GPS_L5_Q"] = "5Q"; // "5Q" GPS L5 Q - observationCode["GPS_L5_IQ"] = "5X"; // "5X" GPS L5 I+Q - observationCode["GLONASS_G1_CA"] = "1C"; // "1C" GLONASS G1 C/A - observationCode["GLONASS_G1_P"] = "1P"; // "1P" GLONASS G1 P - observationCode["GLONASS_G2_CA"] = "2C"; // "2C" GLONASS G2 C/A (Glonass M) - observationCode["GLONASS_G2_P"] = "2P"; // "2P" GLONASS G2 P - observationCode["GALILEO_E1_A"] = "1A"; // "1A" GALILEO E1 A (PRS) - observationCode["GALILEO_E1_B"] = "1B"; // "1B" GALILEO E1 B (I/NAV OS/CS/SoL) - observationCode["GALILEO_E1_C"] = "1C"; // "1C" GALILEO E1 C (no data) - observationCode["GALILEO_E1_BC"] = "1X"; // "1X" GALILEO E1 B+C - observationCode["GALILEO_E1_ABC"] = "1Z"; // "1Z" GALILEO E1 A+B+C - observationCode["GALILEO_E5a_I"] = "5I"; // "5I" GALILEO E5a I (F/NAV OS) - observationCode["GALILEO_E5a_Q"] = "5Q"; // "5Q" GALILEO E5a Q (no data) - observationCode["GALILEO_E5a_IQ"] = "5X"; // "5X" GALILEO E5a I+Q - observationCode["GALILEO_E5b_I"] = "7I"; // "7I" GALILEO E5b I - observationCode["GALILEO_E5b_Q"] = "7Q"; // "7Q" GALILEO E5b Q - observationCode["GALILEO_E5b_IQ"] = "7X"; // "7X" GALILEO E5b I+Q - observationCode["GALILEO_E5_I"] = "8I"; // "8I" GALILEO E5 I - observationCode["GALILEO_E5_Q"] = "8Q"; // "8Q" GALILEO E5 Q - observationCode["GALILEO_E5_IQ"] = "8X"; // "8X" GALILEO E5 I+Q - observationCode["GALILEO_E56_A"] = "6A"; // "6A" GALILEO E6 A - observationCode["GALILEO_E56_B"] = "6B"; // "6B" GALILEO E6 B - observationCode["GALILEO_E56_B"] = "6C"; // "6C" GALILEO E6 C - observationCode["GALILEO_E56_BC"] = "6X"; // "6X" GALILEO E6 B+C - observationCode["GALILEO_E56_ABC"] = "6Z"; // "6Z" GALILEO E6 A+B+C - observationCode["SBAS_L1_CA"] = "1C"; // "1C" SBAS L1 C/A - observationCode["SBAS_L5_I"] = "5I"; // "5I" SBAS L5 I - observationCode["SBAS_L5_Q"] = "5Q"; // "5Q" SBAS L5 Q - observationCode["SBAS_L5_IQ"] = "5X"; // "5X" SBAS L5 I+Q + observationCode["GPS_L1_CA"] = "1C"; // "1C" GPS L1 C/A + observationCode["GPS_L1_P"] = "1P"; // "1P" GPS L1 P + observationCode["GPS_L1_Z_TRACKING"] = "1W"; // "1W" GPS L1 Z-tracking and similar (AS on) + observationCode["GPS_L1_Y"] = "1Y"; // "1Y" GPS L1 Y + observationCode["GPS_L1_M "] = "1M"; // "1M" GPS L1 M + observationCode["GPS_L1_CODELESS"] = "1N"; // "1N" GPS L1 codeless + observationCode["GPS_L2_CA"] = "2C"; // "2C" GPS L2 C/A + observationCode["L2_SEMI_CODELESS"] = "2D"; // "2D" GPS L2 L1(C/A)+(P2-P1) semi-codeless + observationCode["GPS_L2_L2CM"] = "2S"; // "2S" GPS L2 L2C (M) + observationCode["GPS_L2_L2CL"] = "2L"; // "2L" GPS L2 L2C (L) + observationCode["GPS_L2_L2CML"] = "2X"; // "2X" GPS L2 L2C (M+L) + observationCode["GPS_L2_P"] = "2P"; // "2P" GPS L2 P + observationCode["GPS_L2_Z_TRACKING"] = "2W"; // "2W" GPS L2 Z-tracking and similar (AS on) + observationCode["GPS_L2_Y"] = "2Y"; // "2Y" GPS L2 Y + observationCode["GPS_L2_M"] = "2M"; // "2M" GPS GPS L2 M + observationCode["GPS_L2_codeless"] = "2N"; // "2N" GPS L2 codeless + observationCode["GPS_L5_I"] = "5I"; // "5I" GPS L5 I + observationCode["GPS_L5_Q"] = "5Q"; // "5Q" GPS L5 Q + observationCode["GPS_L5_IQ"] = "5X"; // "5X" GPS L5 I+Q + observationCode["GLONASS_G1_CA"] = "1C"; // "1C" GLONASS G1 C/A + observationCode["GLONASS_G1_P"] = "1P"; // "1P" GLONASS G1 P + observationCode["GLONASS_G2_CA"] = "2C"; // "2C" GLONASS G2 C/A (Glonass M) + observationCode["GLONASS_G2_P"] = "2P"; // "2P" GLONASS G2 P + observationCode["GALILEO_E1_A"] = "1A"; // "1A" GALILEO E1 A (PRS) + observationCode["GALILEO_E1_B"] = "1B"; // "1B" GALILEO E1 B (I/NAV OS/CS/SoL) + observationCode["GALILEO_E1_C"] = "1C"; // "1C" GALILEO E1 C (no data) + observationCode["GALILEO_E1_BC"] = "1X"; // "1X" GALILEO E1 B+C + observationCode["GALILEO_E1_ABC"] = "1Z"; // "1Z" GALILEO E1 A+B+C + observationCode["GALILEO_E5a_I"] = "5I"; // "5I" GALILEO E5a I (F/NAV OS) + observationCode["GALILEO_E5a_Q"] = "5Q"; // "5Q" GALILEO E5a Q (no data) + observationCode["GALILEO_E5a_IQ"] = "5X"; // "5X" GALILEO E5a I+Q + observationCode["GALILEO_E5b_I"] = "7I"; // "7I" GALILEO E5b I + observationCode["GALILEO_E5b_Q"] = "7Q"; // "7Q" GALILEO E5b Q + observationCode["GALILEO_E5b_IQ"] = "7X"; // "7X" GALILEO E5b I+Q + observationCode["GALILEO_E5_I"] = "8I"; // "8I" GALILEO E5 I + observationCode["GALILEO_E5_Q"] = "8Q"; // "8Q" GALILEO E5 Q + observationCode["GALILEO_E5_IQ"] = "8X"; // "8X" GALILEO E5 I+Q + observationCode["GALILEO_E56_A"] = "6A"; // "6A" GALILEO E6 A + observationCode["GALILEO_E56_B"] = "6B"; // "6B" GALILEO E6 B + observationCode["GALILEO_E56_B"] = "6C"; // "6C" GALILEO E6 C + observationCode["GALILEO_E56_BC"] = "6X"; // "6X" GALILEO E6 B+C + observationCode["GALILEO_E56_ABC"] = "6Z"; // "6Z" GALILEO E6 A+B+C + observationCode["SBAS_L1_CA"] = "1C"; // "1C" SBAS L1 C/A + observationCode["SBAS_L5_I"] = "5I"; // "5I" SBAS L5 I + observationCode["SBAS_L5_Q"] = "5Q"; // "5Q" SBAS L5 Q + observationCode["SBAS_L5_IQ"] = "5X"; // "5X" SBAS L5 I+Q observationCode["COMPASS_E2_I"] = "2I"; observationCode["COMPASS_E2_Q"] = "2Q"; observationCode["COMPASS_E2_IQ"] = "2X"; @@ -141,88 +180,64 @@ Rinex_Printer::Rinex_Printer(int conf_version) observationType["DOPPLER_v2"] = "D"; observationType["SIGNAL_STRENGTH_v2"] = "S"; observationCode["GPS_L1_CA_v2"] = "1"; + observationCode["GLONASS_G1_CA_v2"] = "1"; - if ( FLAGS_RINEX_version.compare("3.01") == 0 ) - { - version = 3; - stringVersion = "3.01"; - } - else if ( FLAGS_RINEX_version.compare("3.02") == 0 ) - { - version = 3; - stringVersion = "3.02"; - } - else if ( FLAGS_RINEX_version.compare("3") == 0 ) - { - version = 3; - stringVersion = "3.02"; - } - else if ( FLAGS_RINEX_version.compare("2.11") == 0 ) - { - version = 2; - stringVersion = "2.11"; - } - else if ( FLAGS_RINEX_version.compare("2.10") == 0 ) - { - version = 2; - stringVersion = "2.10"; - } - else if ( FLAGS_RINEX_version.compare("2") == 0 ) + if (conf_version == 2) { version = 2; stringVersion = "2.11"; } else { - LOG(WARNING) << "Unknown RINEX version " << FLAGS_RINEX_version << " (must be 2.11 or 3.02). Using 3.02"; version = 3; stringVersion = "3.02"; } - if(conf_version != 0) - { - if(conf_version == 2) - version = 2; - stringVersion = "2.11"; - } - - numberTypesObservations = 4; // Number of available types of observable in the system + numberTypesObservations = 4; // Number of available types of observable in the system + fake_cnav_iode = 1; } Rinex_Printer::~Rinex_Printer() { // close RINEX files - long posn, poso, poss, posng, posmn; + int64_t posn, poso, poss, posng, posmn, posnr; posn = navFile.tellp(); poso = obsFile.tellp(); poss = sbsFile.tellp(); posng = navGalFile.tellp(); posmn = navMixFile.tellp(); + posnr = navGloFile.tellp(); + Rinex_Printer::navFile.close(); Rinex_Printer::obsFile.close(); Rinex_Printer::sbsFile.close(); Rinex_Printer::navGalFile.close(); + Rinex_Printer::navGloFile.close(); // If nothing written, erase the files. if (posn == 0) { - if(remove(navfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(navfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } if (poso == 0) { - if(remove(obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } if (poss == 0) { - if(remove(sbsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(sbsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } if (posng == 0) { - if(remove(navGalfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(navGalfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } if (posmn == 0) { - if(remove(navMixfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(navMixfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + } + if (posnr == 0) + { + if (remove(navGlofilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } } @@ -232,23 +247,23 @@ void Rinex_Printer::lengthCheck(const std::string& line) if (line.length() != 80) { LOG(ERROR) << "Bad defined RINEX line: " - << line.length() << " characters (must be 80)" << std::endl - << line << std::endl - << "----|---1|0---|---2|0---|---3|0---|---4|0---|---5|0---|---6|0---|---7|0---|---8|" << std::endl; + << line.length() << " characters (must be 80)" << std::endl + << line << std::endl + << "----|---1|0---|---2|0---|---3|0---|---4|0---|---5|0---|---6|0---|---7|0---|---8|" << std::endl; } } -std::string Rinex_Printer::createFilename(std::string type) +std::string Rinex_Printer::createFilename(const std::string& type) { - const std::string stationName = "GSDR"; // 4-character station name designator + const std::string stationName = "GSDR"; // 4-character station name designator boost::gregorian::date today = boost::gregorian::day_clock::local_day(); - const int dayOfTheYear = today.day_of_year(); + const int32_t dayOfTheYear = today.day_of_year(); std::stringstream strm0; - if (dayOfTheYear < 100) strm0 << "0"; // three digits for day of the year - if (dayOfTheYear < 10) strm0 << "0"; // three digits for day of the year + if (dayOfTheYear < 100) strm0 << "0"; // three digits for day of the year + if (dayOfTheYear < 10) strm0 << "0"; // three digits for day of the year strm0 << dayOfTheYear; - std::string dayOfTheYearTag=strm0.str(); + std::string dayOfTheYearTag = strm0.str(); std::map fileType; fileType.insert(std::pair("RINEX_FILE_TYPE_OBS", "O")); // O - Observation file. @@ -264,7 +279,7 @@ std::string Rinex_Printer::createFilename(std::string type) boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); tm pt_tm = boost::posix_time::to_tm(pt); - int local_hour = pt_tm.tm_hour; + int32_t local_hour = pt_tm.tm_hour; std::stringstream strm; strm << local_hour; @@ -296,14 +311,14 @@ std::string Rinex_Printer::createFilename(std::string type) std::string hourTag = Hmap[strm.str()]; - int local_minute = pt_tm.tm_min; + int32_t local_minute = pt_tm.tm_min; std::stringstream strm2; - if (local_minute<10) strm2 << "0"; // at least two digits for minutes + if (local_minute < 10) strm2 << "0"; // at least two digits for minutes strm2 << local_minute; std::string minTag = strm2.str(); - int local_year = pt_tm.tm_year - 100; // 2012 is 112 + int32_t local_year = pt_tm.tm_year - 100; // 2012 is 112 std::stringstream strm3; strm3 << local_year; std::string yearTag = strm3.str(); @@ -322,7 +337,7 @@ std::string Rinex_Printer::getLocalTime() line += std::string(12, ' '); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -339,22 +354,22 @@ std::string Rinex_Printer::getLocalTime() tm pt_tm = boost::local_time::to_tm(pt); std::stringstream strmHour; - int utc_hour = pt_tm.tm_hour; - if (utc_hour < 10) strmHour << "0"; // two digits for hours + int32_t utc_hour = pt_tm.tm_hour; + if (utc_hour < 10) strmHour << "0"; // two digits for hours strmHour << utc_hour; std::stringstream strmMin; - int utc_minute = pt_tm.tm_min; - if (utc_minute < 10) strmMin << "0"; // two digits for minutes + int32_t utc_minute = pt_tm.tm_min; + if (utc_minute < 10) strmMin << "0"; // two digits for minutes strmMin << utc_minute; if (version == 2) { - int day = pt_tm.tm_mday; - line += Rinex_Printer::rightJustify(boost::lexical_cast(day), 2); + int32_t day = pt_tm.tm_mday; + line += Rinex_Printer::rightJustify(std::to_string(day), 2); line += std::string("-"); - std::map months; + std::map months; months[0] = "JAN"; months[1] = "FEB"; months[2] = "MAR"; @@ -370,7 +385,7 @@ std::string Rinex_Printer::getLocalTime() line += months[pt_tm.tm_mon]; line += std::string("-"); - line += boost::lexical_cast(pt_tm.tm_year - 100); + line += std::to_string(pt_tm.tm_year - 100); line += std::string(1, ' '); line += strmHour.str(); line += std::string(":"); @@ -386,8 +401,8 @@ std::string Rinex_Printer::getLocalTime() line += strmMin.str(); std::stringstream strm2; - int utc_seconds = pt_tm.tm_sec; - if (utc_seconds < 10) strm2 << "0"; // two digits for seconds + int32_t utc_seconds = pt_tm.tm_sec; + if (utc_seconds < 10) strm2 << "0"; // two digits for seconds strm2 << utc_seconds; line += strm2.str(); line += std::string(1, ' '); @@ -398,12 +413,477 @@ std::string Rinex_Printer::getLocalTime() } -void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono, const Galileo_Utc_Model& utc_model, const Galileo_Almanac& galileo_almanac) +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Ephemeris& glonass_gnav_eph) { std::string line; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("R: GLONASS"); + line += std::string(10, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GLONASS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction + if (version == 3) + { + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GLGP"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 2) + { + // Set reference time and its clock corrections + boost::posix_time::ptime p_utc_ref_time = glonass_gnav_eph.glot_to_utc(glonass_gnav_eph.d_t_b, 0.0); + std::string timestring = boost::posix_time::to_iso_string(p_utc_ref_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + + line.clear(); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += std::string(3, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 19, 2), 19); + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("CORR TO SYSTEM TIME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + std::string line; stringVersion = "3.02"; version = 3; + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GPSA"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 1 + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GLGP"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 3 + line.clear(); + line += std::string("GPUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono& gps_iono, const Gps_CNAV_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + std::string line; + stringVersion = "3.02"; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GPSA"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 1 + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GLGP"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 3 + line.clear(); + line += std::string("GPUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + //Avoid compiler warning, there is not time system correction between Galileo and GLONASS + if (galileo_utc_model.A_0G_10) + { + } + std::string line; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GAL "); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction + line.clear(); + line += std::string("GAUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 1 + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLS_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLSF_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_LSF_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.DN_6), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono, const Galileo_Utc_Model& utc_model) +{ + std::string line; + // -------- Line 1 line = std::string(5, ' '); line += stringVersion; @@ -442,12 +922,11 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- Line ionospheric info 1 line.clear(); line += std::string("GAL "); @@ -462,14 +941,13 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- Line system time correction line.clear(); line += std::string("GAUT"); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A0_6, 16, 2), 18); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A1_6, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.t0t_6), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.WNot_6), 5); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.t0t_6), 7); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.WNot_6), 5); line += std::string(10, ' '); line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); Rinex_Printer::lengthCheck(line); @@ -478,23 +956,22 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono // -------- Line system time correction 2 line.clear(); line += std::string("GPGA"); - line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_0G_10, 16, 2), 18); - line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_1G_10, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.t_0G_10), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.WN_0G_10), 5); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A_0G_10, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A_1G_10, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.t_0G_10), 7); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.WN_0G_10), 5); line += std::string(10, ' '); line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- Line 6 leap seconds // For leap second information, see http://www.endruntechnologies.com/leap.htm line.clear(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.Delta_tLS_6), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.Delta_tLSF_6), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.WN_LSF_6), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.DN_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.Delta_tLS_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.Delta_tLSF_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.WN_LSF_6), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.DN_6), 6); line += std::string(36, ' '); line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); Rinex_Printer::lengthCheck(line); @@ -509,7 +986,7 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono } -void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono & iono, const Gps_CNAV_Utc_Model & utc_model) +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono& iono, const Gps_CNAV_Utc_Model& utc_model) { std::string line; @@ -551,7 +1028,7 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono & io // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -587,8 +1064,8 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono & io line += std::string("GPUT"); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 /* if ( SBAS ) { line += string(1, ' '); @@ -607,10 +1084,142 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono & io // -------- Line 6 leap seconds // For leap second information, see http://www.endruntechnologies.com/leap.htm line.clear(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_CNAV_Iono& iono, const Gps_CNAV_Utc_Model& utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model) +{ + std::string line; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GAL "); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 2 + line.clear(); + line += std::string("GPSA"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha0, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha1, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha2, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha3, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 3 + line.clear(); + line += std::string("GPSB"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta0, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta1, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta2, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta3, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction + line.clear(); + line += std::string("GAUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GPUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line += std::string(36, ' '); line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); Rinex_Printer::lengthCheck(line); @@ -640,7 +1249,7 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co line += std::string(25, ' '); } - if (version == 3 ) + if (version == 3) { line += std::string("N: GNSS NAV DATA"); line += std::string(4, ' '); @@ -648,7 +1257,6 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co line += std::string("G: GPS"); line += std::string(14, ' '); // ... - } line += std::string("RINEX VERSION / TYPE"); @@ -681,7 +1289,7 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -746,8 +1354,8 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co line += std::string(3, ' '); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 18, 2), 19); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 18, 2), 19); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 9); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 9); // valid until 2019 + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 9); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 9); // valid until 2019 line += std::string(1, ' '); line += Rinex_Printer::leftJustify("DELTA-UTC: A0,A1,T,W", 20); } @@ -757,8 +1365,8 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co line += std::string("GPUT"); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 /* if ( SBAS ) { line += string(1, ' '); @@ -778,23 +1386,22 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co // -------- Line 6 leap seconds // For leap second information, see http://www.endruntechnologies.com/leap.htm line.clear(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); if (version == 2) { line += std::string(54, ' '); } if (version == 3) { - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line += std::string(36, ' '); } line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- End of Header line.clear(); line += std::string(60, ' '); @@ -804,11 +1411,9 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& iono, co } -void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Galileo_Almanac& galileo_almanac) +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model) { std::string line; - stringVersion = "3.02"; - version = 3; // -------- Line 1 line = std::string(5, ' '); @@ -848,12 +1453,11 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- Line ionospheric info 1 line.clear(); line += std::string("GAL "); @@ -886,8 +1490,8 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono line += std::string("GAUT"); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.t0t_6), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WNot_6), 5); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); line += std::string(10, ' '); line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); Rinex_Printer::lengthCheck(line); @@ -896,10 +1500,10 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono // -------- Line system time correction 2 line.clear(); line += std::string("GPGA"); - line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_0G_10, 16, 2), 18); - line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_1G_10, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.t_0G_10), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.WN_0G_10), 5); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_0G_10, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_1G_10, 15, 2), 16); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t_0G_10), 7); + line += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_0G_10), 5); line += std::string(10, ' '); line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); Rinex_Printer::lengthCheck(line); @@ -910,21 +1514,20 @@ void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono line += std::string("GPUT"); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_t_OT), 7); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 line += std::string(10, ' '); line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- Line 6 leap seconds // For leap second information, see http://www.endruntechnologies.com/leap.htm line.clear(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LS), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_LSF), 6); - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_DN), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); line += std::string(36, ' '); line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); Rinex_Printer::lengthCheck(line); @@ -948,7 +1551,7 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) line = std::string(5, ' '); line += std::string("2.10"); line += std::string(11, ' '); - line += Rinex_Printer::leftJustify("B SBAS DATA",20); + line += Rinex_Printer::leftJustify("B SBAS DATA", 20); line += std::string(20, ' '); line += std::string("RINEX VERSION / TYPE"); @@ -960,7 +1563,7 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) line += Rinex_Printer::leftJustify("GNSS-SDR", 20); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -975,24 +1578,24 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) boost::local_time::local_date_time pt = boost::local_time::local_sec_clock::local_time(zone); tm pt_tm = boost::local_time::to_tm(pt); std::stringstream strYear; - int utc_year = pt.date().year(); - utc_year -= 2000; // two digits for year + int32_t utc_year = pt.date().year(); + utc_year -= 2000; // two digits for year strYear << utc_year; std::stringstream strMonth; - int utc_month = pt.date().month().as_number(); - if (utc_month < 10) strMonth << "0"; // two digits for months + int32_t utc_month = pt.date().month().as_number(); + if (utc_month < 10) strMonth << "0"; // two digits for months strMonth << utc_month; std::stringstream strmDay; - int utc_day = pt.date().day().as_number(); - if (utc_day < 10) strmDay << "0"; // two digits for days + int32_t utc_day = pt.date().day().as_number(); + if (utc_day < 10) strmDay << "0"; // two digits for days strmDay << utc_day; std::stringstream strmHour; - int utc_hour = pt_tm.tm_hour; - if (utc_hour < 10) strmHour << "0"; // two digits for hours + int32_t utc_hour = pt_tm.tm_hour; + if (utc_hour < 10) strmHour << "0"; // two digits for hours strmHour << utc_hour; std::stringstream strmMin; - int utc_minute = pt_tm.tm_min; - if (utc_minute < 10) strmMin << "0"; // two digits for minutes + int32_t utc_minute = pt_tm.tm_min; + if (utc_minute < 10) strmMin << "0"; // two digits for minutes strmMin << utc_minute; std::string time_str; time_str += strmDay.str(); @@ -1033,7 +1636,7 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) // -------- Line COMMENT 2 line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -1047,23 +1650,98 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) } -void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& utc_model, const Galileo_Almanac& galileo_almanac) +void Rinex_Printer::update_nav_header(std::fstream& out, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) { + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning std::vector data; std::string line_aux; - long pos = out.tellp(); + int64_t pos = out.tellp(); out.seekp(0); data.clear(); bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) + { + line_aux.clear(); + + if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLGP", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLGP"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navGlofilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navGlofilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC info." << std::endl; +} + + +void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& utc_model) +{ + std::vector data; + std::string line_aux; + + int64_t pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while (!out.eof()) + { + std::getline(out, line_str); + + if (!no_more_finds) { line_aux.clear(); @@ -1085,8 +1763,8 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& gal line_aux += std::string("GAUT"); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A0_6, 16, 2), 18); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A1_6, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.t0t_6), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.WNot_6), 5); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.t0t_6), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.WNot_6), 5); line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); @@ -1094,20 +1772,20 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& gal else if ((line_str.find("GPGA", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) { line_aux += std::string("GPGA"); - line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_0G_10, 16, 2), 18); - line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_1G_10, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.t_0G_10), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.WN_0G_10), 5); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A_0G_10, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.A_1G_10, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.t_0G_10), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.WN_0G_10), 5); line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); } else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) { - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.Delta_tLS_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.Delta_tLSF_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.WN_LSF_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.DN_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.Delta_tLS_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.Delta_tLSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.WN_LSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.DN_6), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -1121,7 +1799,6 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& gal { data.push_back(line_str); } - } else { @@ -1132,7 +1809,7 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& gal out.close(); out.open(navGalfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -1148,18 +1825,18 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Utc_Model& ut std::vector data; std::string line_aux; - long pos = out.tellp(); + int64_t pos = out.tellp(); out.seekp(0); data.clear(); bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) { line_aux.clear(); @@ -1192,15 +1869,15 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Utc_Model& ut line_aux += std::string(3, ' '); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 18, 2), 19); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 18, 2), 19); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 9); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 9); // valid until 2019 + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 9); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 9); // valid until 2019 line_aux += std::string(1, ' '); line_aux += Rinex_Printer::leftJustify("DELTA-UTC: A0,A1,T,W", 20); data.push_back(line_aux); } else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) { - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); line_aux += std::string(54, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -1247,18 +1924,18 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Utc_Model& ut line_aux += std::string("GPUT"); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); } else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) { - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -1283,7 +1960,7 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Utc_Model& ut out.close(); out.open(navfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -1294,23 +1971,23 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Utc_Model& ut } -void Rinex_Printer::update_nav_header(std::fstream & out, const Gps_CNAV_Utc_Model & utc_model, const Gps_CNAV_Iono & iono ) +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_CNAV_Utc_Model& utc_model, const Gps_CNAV_Iono& iono) { std::vector data; std::string line_aux; - long pos = out.tellp(); + int64_t pos = out.tellp(); out.seekp(0); data.clear(); bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) { line_aux.clear(); @@ -1343,18 +2020,18 @@ void Rinex_Printer::update_nav_header(std::fstream & out, const Gps_CNAV_Utc_Mod line_aux += std::string("GPUT"); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_t_OT), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); } else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) { - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -1378,7 +2055,7 @@ void Rinex_Printer::update_nav_header(std::fstream & out, const Gps_CNAV_Utc_Mod out.close(); out.open(navfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -1389,23 +2066,152 @@ void Rinex_Printer::update_nav_header(std::fstream & out, const Gps_CNAV_Utc_Mod } -void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Galileo_Almanac& galileo_almanac) +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_CNAV_Utc_Model& utc_model, const Gps_CNAV_Iono& iono, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model) { std::vector data; std::string line_aux; - long pos = out.tellp(); + int64_t pos = out.tellp(); out.seekp(0); data.clear(); bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) + { + line_aux.clear(); + if ((line_str.find("GAL", 0) != std::string::npos) && (line_str.find("IONOSPHERIC CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAL "); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPSA", 0) != std::string::npos) && (line_str.find("IONOSPHERIC CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPSA"); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha0, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha1, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha2, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_alpha3, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPSB", 0) != std::string::npos) && (line_str.find("IONOSPHERIC CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPSB"); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta0, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta1, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta2, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(iono.d_beta3, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + + else if ((line_str.find("GAUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPGA", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPGA"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_0G_10, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_1G_10, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t_0G_10), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_0G_10), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("GPUT", 0) != std::string::npos) + { + line_aux += std::string("GPUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A0, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(utc_model.d_A1, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + } + else + { + data.push_back(line_str); + } + } + out.close(); + out.open(navfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model) +{ + std::vector data; + std::string line_aux; + + int64_t pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while (!out.eof()) + { + std::getline(out, line_str); + + if (!no_more_finds) { line_aux.clear(); @@ -1451,8 +2257,8 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion line_aux += std::string("GPUT"); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_t_OT), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); @@ -1462,8 +2268,8 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion line_aux += std::string("GAUT"); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.t0t_6), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WNot_6), 5); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); @@ -1471,20 +2277,20 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion else if ((line_str.find("GPGA", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) { line_aux += std::string("GPGA"); - line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_0G_10, 16, 2), 18); - line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_almanac.A_1G_10, 15, 2), 16); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.t_0G_10), 7); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_almanac.WN_0G_10), 5); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_0G_10, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A_1G_10, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t_0G_10), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_0G_10), 5); line_aux += std::string(10, ' '); line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); data.push_back(line_aux); } else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) { - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LS), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_DN), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -1498,7 +2304,6 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion { data.push_back(line_str); } - } else { @@ -1509,7 +2314,7 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion out.close(); out.open(navMixfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -1520,31 +2325,349 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion } -void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + std::vector data; + std::string line_aux; + + int64_t pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while (!out.eof()) + { + std::getline(out, line_str); + + if (!no_more_finds) + { + line_aux.clear(); + + if (line_str.find("GPSA", 0) != std::string::npos) + { + line_aux += std::string("GPSA"); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLGP", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLGP"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_CNAV_Iono& gps_iono, const Gps_CNAV_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + std::vector data; + std::string line_aux; + + int64_t pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while (!out.eof()) + { + std::getline(out, line_str); + + if (!no_more_finds) + { + line_aux.clear(); + + if (line_str.find("GPSA", 0) != std::string::npos) + { + line_aux += std::string("GPSA"); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLGP", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLGP"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(gps_utc_model.i_DN), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + +void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if (glonass_gnav_almanac.i_satellite_freq_channel) + { + } //Avoid compiler warning + //Avoid compiler warning, there is not time system correction between Galileo and GLONASS + if (galileo_utc_model.A_0G_10) + { + } + std::vector data; + std::string line_aux; + + int64_t pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while (!out.eof()) + { + std::getline(out, line_str); + + if (!no_more_finds) + { + line_aux.clear(); + + if ((line_str.find("GAL", 0) != std::string::npos) && (line_str.find("IONOSPHERIC CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAL "); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GAUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.t0t_6), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WNot_6), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 7); + line_aux += Rinex_Printer::rightJustify(std::to_string(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLS_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_LSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.DN_6), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) { std::string line; - std::map::const_iterator gps_ephemeris_iter; + std::map::const_iterator gps_ephemeris_iter; - for(gps_ephemeris_iter = eph_map.begin(); - gps_ephemeris_iter != eph_map.end(); - gps_ephemeris_iter++) - { + for (gps_ephemeris_iter = eph_map.cbegin(); + gps_ephemeris_iter != eph_map.cend(); + gps_ephemeris_iter++) + { // -------- SV / EPOCH / SV CLK boost::posix_time::ptime p_utc_time = Rinex_Printer::compute_GPS_time(gps_ephemeris_iter->second, gps_ephemeris_iter->second.d_Toc); std::string timestring = boost::posix_time::to_iso_string(p_utc_time); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); - std::string seconds (timestring, 13, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + std::string seconds(timestring, 13, 2); if (version == 2) { - line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_ephemeris_iter->second.i_satellite_PRN), 2); + line += Rinex_Printer::rightJustify(std::to_string(gps_ephemeris_iter->second.i_satellite_PRN), 2); line += std::string(1, ' '); - std::string year (timestring, 2, 2); + std::string year(timestring, 2, 2); line += year; line += std::string(1, ' '); - if(boost::lexical_cast(month) < 10) + if (boost::lexical_cast(month) < 10) { line += std::string(1, ' '); line += std::string(month, 1, 1); @@ -1554,7 +2677,7 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(day) < 10) + if (boost::lexical_cast(day) < 10) { line += std::string(1, ' '); line += std::string(day, 1, 1); @@ -1564,7 +2687,7 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(hour) < 10) + if (boost::lexical_cast(hour) < 10) { line += std::string(1, ' '); line += std::string(hour, 1, 1); @@ -1574,7 +2697,7 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(minutes) < 10) + if (boost::lexical_cast(minutes) < 10) { line += std::string(1, ' '); line += std::string(minutes, 1, 1); @@ -1584,7 +2707,7 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(seconds) < 10) + if (boost::lexical_cast(seconds) < 10) { line += std::string(1, ' '); line += std::string(seconds, 1, 1); @@ -1597,7 +2720,7 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map 16) { - std::string decimal (timestring, 16, 1); + std::string decimal(timestring, 16, 1); } line += decimal; line += std::string(1, ' '); @@ -1611,9 +2734,9 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.i_satellite_PRN < 10) line += std::string("0"); - line += boost::lexical_cast(gps_ephemeris_iter->second.i_satellite_PRN); - std::string year (timestring, 0, 4); + if (gps_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); + line += std::to_string(gps_ephemeris_iter->second.i_satellite_PRN); + std::string year(timestring, 0, 4); line += std::string(1, ' '); line += year; line += std::string(1, ' '); @@ -1636,7 +2759,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(gps_ephemeris_iter->second.i_code_on_L2), 18, 2); line += std::string(1, ' '); - double GPS_week_continuous_number = static_cast(gps_ephemeris_iter->second.i_GPS_week + 1024); // valid until April 7, 2019 (check http://www.colorado.edu/geography/gcraft/notes/gps/gpseow.htm) + auto GPS_week_continuous_number = static_cast(gps_ephemeris_iter->second.i_GPS_week + 1024); // valid until April 7, 2019 (check http://www.colorado.edu/geography/gcraft/notes/gps/gpseow.htm) line += Rinex_Printer::doub2for(GPS_week_continuous_number, 18, 2); line += std::string(1, ' '); line += Rinex_Printer::doub2for(static_cast(gps_ephemeris_iter->second.i_code_on_L2), 18, 2); @@ -1799,7 +2914,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN).compare("IIA")) + if (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN) == "IIA") { // Block II/IIA (Table 20-XI IS-GPS-200E ) - if ( (gps_ephemeris_iter->second.d_IODC > 239) && (gps_ephemeris_iter->second.d_IODC < 248) ) curve_fit_interval = 8; - if ( ( (gps_ephemeris_iter->second.d_IODC > 247) && (gps_ephemeris_iter->second.d_IODC < 256) ) || (gps_ephemeris_iter->second.d_IODC == 496) ) curve_fit_interval = 14; - if ( (gps_ephemeris_iter->second.d_IODC > 496) && (gps_ephemeris_iter->second.d_IODC < 504) ) curve_fit_interval = 26; - if ( (gps_ephemeris_iter->second.d_IODC > 503) && (gps_ephemeris_iter->second.d_IODC < 511) ) curve_fit_interval = 50; - if ( ( (gps_ephemeris_iter->second.d_IODC > 751) && (gps_ephemeris_iter->second.d_IODC < 757) ) || (gps_ephemeris_iter->second.d_IODC == 511) ) curve_fit_interval = 74; - if ( gps_ephemeris_iter->second.d_IODC == 757 ) curve_fit_interval = 98; + if ((gps_ephemeris_iter->second.d_IODC > 239) && (gps_ephemeris_iter->second.d_IODC < 248)) curve_fit_interval = 8; + if (((gps_ephemeris_iter->second.d_IODC > 247) && (gps_ephemeris_iter->second.d_IODC < 256)) || (gps_ephemeris_iter->second.d_IODC == 496)) curve_fit_interval = 14; + if ((gps_ephemeris_iter->second.d_IODC > 496) && (gps_ephemeris_iter->second.d_IODC < 504)) curve_fit_interval = 26; + if ((gps_ephemeris_iter->second.d_IODC > 503) && (gps_ephemeris_iter->second.d_IODC < 511)) curve_fit_interval = 50; + if (((gps_ephemeris_iter->second.d_IODC > 751) && (gps_ephemeris_iter->second.d_IODC < 757)) || (gps_ephemeris_iter->second.d_IODC == 511)) curve_fit_interval = 74; + if (gps_ephemeris_iter->second.d_IODC == 757) curve_fit_interval = 98; } - if ((gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN).compare("IIR") == 0) || - (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN).compare("IIR-M") == 0) || - (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN).compare("IIF") == 0) || - (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN).compare("IIIA") == 0) ) + if ((gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN) == "IIR") || + (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN) == "IIR-M") || + (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN) == "IIF") || + (gps_ephemeris_iter->second.satelliteBlock.at(gps_ephemeris_iter->second.i_satellite_PRN) == "IIIA")) { // Block IIR/IIR-M/IIF/IIIA (Table 20-XII IS-GPS-200E ) - if ( (gps_ephemeris_iter->second.d_IODC > 239) && (gps_ephemeris_iter->second.d_IODC < 248)) curve_fit_interval = 8; - if ( ( (gps_ephemeris_iter->second.d_IODC > 247) && (gps_ephemeris_iter->second.d_IODC < 256)) || (gps_ephemeris_iter->second.d_IODC == 496) ) curve_fit_interval = 14; - if ( ( (gps_ephemeris_iter->second.d_IODC > 496) && (gps_ephemeris_iter->second.d_IODC < 504)) || ( (gps_ephemeris_iter->second.d_IODC > 1020) && (gps_ephemeris_iter->second.d_IODC < 1024) ) ) curve_fit_interval = 26; + if ((gps_ephemeris_iter->second.d_IODC > 239) && (gps_ephemeris_iter->second.d_IODC < 248)) curve_fit_interval = 8; + if (((gps_ephemeris_iter->second.d_IODC > 247) && (gps_ephemeris_iter->second.d_IODC < 256)) || (gps_ephemeris_iter->second.d_IODC == 496)) curve_fit_interval = 14; + if (((gps_ephemeris_iter->second.d_IODC > 496) && (gps_ephemeris_iter->second.d_IODC < 504)) || ((gps_ephemeris_iter->second.d_IODC > 1020) && (gps_ephemeris_iter->second.d_IODC < 1024))) curve_fit_interval = 26; } line += Rinex_Printer::doub2for(curve_fit_interval, 18, 2); line += std::string(1, ' '); - line += std::string(18, ' '); // spare + line += std::string(18, ' '); // spare line += std::string(1, ' '); - line += std::string(18, ' '); // spare + line += std::string(18, ' '); // spare if (version == 2) { line += std::string(1, ' '); @@ -1851,27 +2965,27 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) { std::string line; - std::map::const_iterator gps_ephemeris_iter; + std::map::const_iterator gps_ephemeris_iter; - for(gps_ephemeris_iter = eph_map.begin(); - gps_ephemeris_iter != eph_map.end(); - gps_ephemeris_iter++) + for (gps_ephemeris_iter = eph_map.cbegin(); + gps_ephemeris_iter != eph_map.cend(); + gps_ephemeris_iter++) { // -------- SV / EPOCH / SV CLK boost::posix_time::ptime p_utc_time = Rinex_Printer::compute_GPS_time(gps_ephemeris_iter->second, gps_ephemeris_iter->second.d_Toc); std::string timestring = boost::posix_time::to_iso_string(p_utc_time); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); - std::string seconds (timestring, 13, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + std::string seconds(timestring, 13, 2); line += satelliteSystem["GPS"]; - if (gps_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); - line += boost::lexical_cast(gps_ephemeris_iter->second.i_satellite_PRN); - std::string year (timestring, 0, 4); + if (gps_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); + line += std::to_string(gps_ephemeris_iter->second.i_satellite_PRN); + std::string year(timestring, 0, 4); line += std::string(1, ' '); line += year; line += std::string(1, ' '); @@ -1893,13 +3007,20 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.d_Toe1 == gps_ephemeris_iter->second.d_Toe2) && (gps_ephemeris_iter->second.d_Toe1 == gps_ephemeris_iter->second.d_Toc))) // Toe1: Toe in message type 10, Toe2: Toe in message type 11 + { + // Toe1: Toe in message type 10, Toe2: Toe in message type 11, + fake_cnav_iode = fake_cnav_iode + 1; + if (fake_cnav_iode == 240) fake_cnav_iode = 1; + } + + line += Rinex_Printer::doub2for(fake_cnav_iode, 18, 2); line += std::string(1, ' '); line += Rinex_Printer::doub2for(gps_ephemeris_iter->second.d_Crs, 18, 2); line += std::string(1, ' '); @@ -1909,7 +3030,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.d_Cus, 18, 2); line += std::string(1, ' '); - const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 163 + const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 163 double sqrt_A = sqrt(A_REF + gps_ephemeris_iter->second.d_DELTA_A); line += Rinex_Printer::doub2for(sqrt_A, 18, 2); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- BROADCAST ORBIT - 3 line.clear(); line += std::string(5, ' '); @@ -1939,7 +3058,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.d_OMEGA, 18, 2); line += std::string(1, ' '); - const double OMEGA_DOT_REF = -2.6e-9; // semicircles / s, see IS-GPS-200H pp. 164 + const double OMEGA_DOT_REF = -2.6e-9; // semicircles / s, see IS-GPS-200H pp. 164 double OMEGA_DOT = OMEGA_DOT_REF + gps_ephemeris_iter->second.d_DELTA_OMEGA_DOT; line += Rinex_Printer::doub2for(OMEGA_DOT, 18, 2); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- BROADCAST ORBIT - 5 line.clear(); line += std::string(5, ' '); line += Rinex_Printer::doub2for(gps_ephemeris_iter->second.d_IDOT, 18, 2); line += std::string(1, ' '); // No data flag for L2 P code + double my_zero = 0.0; line += Rinex_Printer::doub2for(my_zero, 18, 2); line += std::string(1, ' '); - double GPS_week_continuous_number = static_cast(gps_ephemeris_iter->second.i_GPS_week + 1024); // valid until April 7, 2019 (check http://www.colorado.edu/geography/gcraft/notes/gps/gpseow.htm) + auto GPS_week_continuous_number = static_cast(gps_ephemeris_iter->second.i_GPS_week + 1024); // valid until April 7, 2019 (check http://www.colorado.edu/geography/gcraft/notes/gps/gpseow.htm) line += Rinex_Printer::doub2for(GPS_week_continuous_number, 18, 2); line += std::string(1, ' '); line += Rinex_Printer::doub2for(my_zero, 18, 2); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- BROADCAST ORBIT - 6 line.clear(); line += std::string(5, ' '); @@ -1981,23 +3098,22 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.d_TGD, 18, 2); line += std::string(1, ' '); - // no IODC in CNAV, so we set it to zero - line += Rinex_Printer::doub2for(my_zero, 18, 2); + // no IODC in CNAV, so we fake it (see above) + line += Rinex_Printer::doub2for(fake_cnav_iode, 18, 2); Rinex_Printer::lengthCheck(line); out << line << std::endl; - // -------- BROADCAST ORBIT - 7 line.clear(); line += std::string(5, ' '); line += Rinex_Printer::doub2for(gps_ephemeris_iter->second.d_TOW, 18, 2); line += std::string(1, ' '); - double curve_fit_interval = 3; /// ?? Not defined in CNAV + double curve_fit_interval = 3; /// ?? Not defined in CNAV line += Rinex_Printer::doub2for(curve_fit_interval, 18, 2); line += std::string(1, ' '); - line += std::string(18, ' '); // spare + line += std::string(18, ' '); // spare line += std::string(1, ' '); - line += std::string(18, ' '); // spare + line += std::string(18, ' '); // spare Rinex_Printer::lengthCheck(line); out << line << std::endl; line.clear(); @@ -2005,28 +3121,28 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) { std::string line; - std::map::const_iterator galileo_ephemeris_iter; + std::map::const_iterator galileo_ephemeris_iter; line.clear(); - for(galileo_ephemeris_iter = eph_map.begin(); - galileo_ephemeris_iter != eph_map.end(); - galileo_ephemeris_iter++) + for (galileo_ephemeris_iter = eph_map.cbegin(); + galileo_ephemeris_iter != eph_map.cend(); + galileo_ephemeris_iter++) { // -------- SV / EPOCH / SV CLK boost::posix_time::ptime p_utc_time = Rinex_Printer::compute_Galileo_time(galileo_ephemeris_iter->second, galileo_ephemeris_iter->second.t0e_1); std::string timestring = boost::posix_time::to_iso_string(p_utc_time); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); - std::string seconds (timestring, 13, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + std::string seconds(timestring, 13, 2); line += satelliteSystem["Galileo"]; - if (galileo_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); - line += boost::lexical_cast(galileo_ephemeris_iter->second.i_satellite_PRN); - std::string year (timestring, 0, 4); + if (galileo_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); + line += std::to_string(galileo_ephemeris_iter->second.i_satellite_PRN); + std::string year(timestring, 0, 4); line += std::string(1, ' '); line += year; line += std::string(1, ' '); @@ -2049,7 +3165,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map(data_source_INAV), 18, 2); line += std::string(1, ' '); - double GST_week = static_cast(galileo_ephemeris_iter->second.WN_5); - double num_GST_rollovers = floor((GST_week + 1024.0) / 4096.0 ); + auto GST_week = static_cast(galileo_ephemeris_iter->second.WN_5); + double num_GST_rollovers = floor((GST_week + 1024.0) / 4096.0); double Galileo_week_continuous_number = GST_week + 1024.0 + num_GST_rollovers * 4096.0; line += Rinex_Printer::doub2for(Galileo_week_continuous_number, 18, 2); line += std::string(1, ' '); @@ -2126,7 +3237,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::mapsecond.E1B_HS_5 == 0) E1B_HS = "00"; - if(galileo_ephemeris_iter->second.E1B_HS_5 == 1) E1B_HS = "01"; - if(galileo_ephemeris_iter->second.E1B_HS_5 == 2) E1B_HS = "10"; - if(galileo_ephemeris_iter->second.E1B_HS_5 == 3) E1B_HS = "11"; - if(galileo_ephemeris_iter->second.E5b_HS_5 == 0) E5B_HS = "00"; - if(galileo_ephemeris_iter->second.E5b_HS_5 == 1) E5B_HS = "01"; - if(galileo_ephemeris_iter->second.E5b_HS_5 == 2) E5B_HS = "10"; - if(galileo_ephemeris_iter->second.E5b_HS_5 == 3) E5B_HS = "11"; + if (galileo_ephemeris_iter->second.E1B_HS_5 == 0) E1B_HS = "00"; + if (galileo_ephemeris_iter->second.E1B_HS_5 == 1) E1B_HS = "01"; + if (galileo_ephemeris_iter->second.E1B_HS_5 == 2) E1B_HS = "10"; + if (galileo_ephemeris_iter->second.E1B_HS_5 == 3) E1B_HS = "11"; + if (galileo_ephemeris_iter->second.E5b_HS_5 == 0) E5B_HS = "00"; + if (galileo_ephemeris_iter->second.E5b_HS_5 == 1) E5B_HS = "01"; + if (galileo_ephemeris_iter->second.E5b_HS_5 == 2) E5B_HS = "10"; + if (galileo_ephemeris_iter->second.E5b_HS_5 == 3) E5B_HS = "11"; - if(E1B_HS == "11") LOG(WARNING) << "Signal Component currently in Test"; - if(E1B_HS == "10") LOG(WARNING) << "Signal will be out of service"; - if(E1B_HS == "01") LOG(WARNING) << "Signal out of service"; + if (E1B_HS == "11") LOG(WARNING) << "Signal Component currently in Test"; + if (E1B_HS == "10") LOG(WARNING) << "Signal will be out of service"; + if (E1B_HS == "01") LOG(WARNING) << "Signal out of service"; E1B_HS = "00"; // *************** CHANGE THIS WHEN GALILEO SIGNAL IS VALID - std::string E1B_DVS = boost::lexical_cast(galileo_ephemeris_iter->second.E1B_DVS_5); - if(E1B_DVS == "1") LOG(WARNING) << "Navigation data without guarantee"; - E1B_DVS = "0"; // *************** CHANGE THIS WHEN GALILEO SIGNAL IS VALID + std::string E1B_DVS = std::to_string(galileo_ephemeris_iter->second.E1B_DVS_5); + if (E1B_DVS == "1") LOG(WARNING) << "Navigation data without guarantee"; + E1B_DVS = "0"; // *************** CHANGE THIS WHEN GALILEO SIGNAL IS VALID - std::string SVhealth_str = E5B_HS + boost::lexical_cast(galileo_ephemeris_iter->second.E5b_DVS_5) - + "11" + "1" + E1B_DVS + E1B_HS - + boost::lexical_cast(galileo_ephemeris_iter->second.E1B_DVS_5); - SVhealth_str = "000000000"; // *************** CHANGE THIS WHEN GALILEO SIGNAL IS VALID - int SVhealth = Rinex_Printer::toInt(SVhealth_str, 9); + std::string SVhealth_str = E5B_HS + std::to_string(galileo_ephemeris_iter->second.E5b_DVS_5) + "11" + "1" + E1B_DVS + E1B_HS + std::to_string(galileo_ephemeris_iter->second.E1B_DVS_5); + SVhealth_str = "000000000"; // *************** CHANGE THIS WHEN GALILEO SIGNAL IS VALID + int32_t SVhealth = Rinex_Printer::toInt(SVhealth_str, 9); line += Rinex_Printer::doub2for(static_cast(SVhealth), 18, 2); line += std::string(1, ' '); line += Rinex_Printer::doub2for(galileo_ephemeris_iter->second.BGD_E1E5a_5, 18, 2); @@ -2166,7 +3274,6 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& galileo_eph_map) +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) +{ + std::string line; + std::map::const_iterator glonass_gnav_ephemeris_iter; + + for (glonass_gnav_ephemeris_iter = eph_map.cbegin(); + glonass_gnav_ephemeris_iter != eph_map.cend(); + glonass_gnav_ephemeris_iter++) + { + // -------- SV / EPOCH / SV CLK + boost::posix_time::ptime p_utc_time = glonass_gnav_ephemeris_iter->second.glot_to_utc(glonass_gnav_ephemeris_iter->second.d_t_b, 0.0); + std::string timestring = boost::posix_time::to_iso_string(p_utc_time); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + std::string seconds(timestring, 13, 2); + if (version == 2) + { + line += Rinex_Printer::rightJustify(std::to_string(glonass_gnav_ephemeris_iter->second.i_satellite_PRN), 2); + line += std::string(1, ' '); + std::string year(timestring, 2, 2); + line += year; + line += std::string(1, ' '); + if (boost::lexical_cast(month) < 10) + { + line += std::string(1, ' '); + line += std::string(month, 1, 1); + } + else + { + line += month; + } + line += std::string(1, ' '); + if (boost::lexical_cast(day) < 10) + { + line += std::string(1, ' '); + line += std::string(day, 1, 1); + } + else + { + line += day; + } + line += std::string(1, ' '); + if (boost::lexical_cast(hour) < 10) + { + line += std::string(1, ' '); + line += std::string(hour, 1, 1); + } + else + { + line += hour; + } + line += std::string(1, ' '); + if (boost::lexical_cast(minutes) < 10) + { + line += std::string(1, ' '); + line += std::string(minutes, 1, 1); + } + else + { + line += minutes; + } + line += std::string(1, ' '); + if (boost::lexical_cast(seconds) < 10) + { + line += std::string(1, ' '); + line += std::string(seconds, 1, 1); + } + else + { + line += seconds; + } + line += std::string(1, '.'); + std::string decimal = std::string("0"); + if (timestring.size() > 16) + { + std::string decimal(timestring, 16, 1); + } + line += decimal; + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(-glonass_gnav_ephemeris_iter->second.d_tau_c, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_gamma_n, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_t_k, 18, 2); + line += std::string(1, ' '); + } + if (version == 3) + { + line += satelliteSystem["GLONASS"]; + if (glonass_gnav_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); + line += std::to_string(glonass_gnav_ephemeris_iter->second.i_satellite_PRN); + std::string year(timestring, 0, 4); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + line += std::string(1, ' '); + line += seconds; + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(-glonass_gnav_ephemeris_iter->second.d_tau_n, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(+glonass_gnav_ephemeris_iter->second.d_gamma_n, 18, 2); + line += std::string(1, ' '); + //TODO need to define this here. what is nd + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_t_k + p_utc_time.date().day_of_week() * 86400, 18, 2); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- BROADCAST ORBIT - 1 + line.clear(); + // TODO Why is this happening here?. The extra space maybe is intended to help with readability + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Xn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VXn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AXn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_B_n, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- BROADCAST ORBIT - 2 + line.clear(); + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Yn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VYn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AYn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.i_satellite_freq_channel, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- BROADCAST ORBIT - 3 + line.clear(); + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Zn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VZn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AZn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_E_n, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + line.clear(); + } +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& galileo_eph_map) { version = 3; stringVersion = "3.02"; @@ -2193,6 +3497,1355 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_cnav_eph_map, const std::map& galileo_eph_map) +{ + version = 3; + stringVersion = "3.02"; + Rinex_Printer::log_rinex_nav(out, gps_cnav_eph_map); + Rinex_Printer::log_rinex_nav(out, galileo_eph_map); +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& glonass_gnav_eph_map) +{ + Rinex_Printer::log_rinex_nav(out, gps_eph_map); + Rinex_Printer::log_rinex_nav(out, glonass_gnav_eph_map); +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& glonass_gnav_eph_map) +{ + Rinex_Printer::log_rinex_nav(out, gps_eph_map); + Rinex_Printer::log_rinex_nav(out, glonass_gnav_eph_map); +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& galileo_eph_map, const std::map& glonass_gnav_eph_map) +{ + version = 3; + stringVersion = "3.02"; + Rinex_Printer::log_rinex_nav(out, galileo_eph_map); + Rinex_Printer::log_rinex_nav(out, glonass_gnav_eph_map); +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Glonass_Gnav_Ephemeris& eph, const double d_TOW_first_observation, const std::string& glonass_bands) +{ + if (eph.d_m) + { + } //Avoid compiler warning + std::string line; + std::map::const_iterator glonass_gnav_ephemeris_iter; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["GLONASS"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + if (version == 2) + { + line += Rinex_Printer::leftJustify("BLANK OR G = GPS, R = GLONASS, E = GALILEO, M = MIXED", 60); + } + if (version == 3) + { + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + } + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GLONASS OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + if (version == 2) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER NUMBER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 3) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + if (version == 3) + { + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = 4; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + + std::string signal_ = "1G"; + std::size_t found_1G = glonass_bands.find(signal_); + signal_ = "2G"; + std::size_t found_2G = glonass_bands.find(signal_); + + if (found_1G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G1_CA"]; + } + + if (found_2G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G2_CA"]; + } + + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 2) + { + // -------- SYS / OBS TYPES + line.clear(); + std::stringstream strm; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 6); + // per type of observation + // GLONASS L1 C/A PSEUDORANGE + line += Rinex_Printer::rightJustify(observationType["PSEUDORANGE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 PHASE + line += Rinex_Printer::rightJustify(observationType["CARRIER_PHASE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS DOPPLER L1 + line += Rinex_Printer::rightJustify(observationType["DOPPLER_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 SIGNAL STRENGTH + line += Rinex_Printer::rightJustify(observationType["SIGNAL_STRENGTH_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("# / TYPES OF OBSERV", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- Signal Strength units (Only version 3) + if (version == 3) + { + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- TIME OF FIRST OBS + boost::posix_time::ptime p_utc_time = Rinex_Printer::compute_UTC_time(eph, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_utc_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double intpart = 0; + double seconds = p_utc_time.time_of_day().seconds() + modf(d_TOW_first_observation, &intpart); + line.clear(); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GLO"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS SLOT / FRQ # (On;y version 3) + if (version == 3) + { + // -------- GLONASS SLOT / FRQ # + // TODO Need to provide system with list of all satellites and update this accordingly + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(0), 3); // Number of satellites in list + line += std::string(1, ' '); + line += satelliteSystem["GLONASS"]; + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Slot Number + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Frequency Number + line += std::string(1, ' '); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS SLOT / FRQ #", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS CODE/PHS/BIS + // No GLONASS Phase bias correction used to align code and phase observations. + line.clear(); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS COD/PHS/BIS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- END OF HEADER + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double d_TOW_first_observation, const std::string& glonass_bands) +{ + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed + std::string line; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GPS/GLO) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME / TYPE + if (version == 2) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER NUMBER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 3) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- Line MARKER TYPE + line.clear(); + line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + if (version == 3) + { + // one line per available system + line.clear(); + line += satelliteSystem["GPS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = 4; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + // per type of observation + // GPS L1 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L1_CA"]; + // GPS DOPPLER L1 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 CA SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L1_CA"]; + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // Find GLONASS Signal in Mixed file + uint32_t number_of_observations_glo = 0; + std::string signal_("1G"); + std::size_t found_1G = glonass_bands.find(signal_); + if (found_1G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + signal_ = "2G"; + std::size_t found_2G = glonass_bands.find(signal_); + if (found_2G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + line.clear(); + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_glo), 3); + if (found_1G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G1_CA"]; + } + if (found_2G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G2_CA"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 2) + { + // -------- SYS / OBS TYPES + line.clear(); + std::stringstream strm; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 6); + // per type of observation + // GLONASS L1 C/A PSEUDORANGE + line += Rinex_Printer::rightJustify(observationType["PSEUDORANGE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 PHASE + line += Rinex_Printer::rightJustify(observationType["CARRIER_PHASE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS DOPPLER L1 + line += Rinex_Printer::rightJustify(observationType["DOPPLER_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 SIGNAL STRENGTH + line += Rinex_Printer::rightJustify(observationType["SIGNAL_STRENGTH_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("# / TYPES OF OBSERV", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- Signal Strength units (only version 3) + if (version == 3) + { + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GPS"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS SLOT / FRQ # (On;y version 3) + if (version == 3) + { + // -------- GLONASS SLOT / FRQ # + // TODO Need to provide system with list of all satellites and update this accordingly + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(0), 3); // Number of satellites in list + line += std::string(1, ' '); + line += satelliteSystem["GLONASS"]; + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Slot Number + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Frequency Number + line += std::string(1, ' '); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS SLOT / FRQ #", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS CODE/PHS/BIS + // No GLONASS Phase bias correction used to align code and phase observations. + line.clear(); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS COD/PHS/BIS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_CNAV_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double d_TOW_first_observation, const std::string& glonass_bands) +{ + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed + std::string line; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GPS/GLO) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NUMBER / TYPE + if (version == 2) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER NUMBER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + if (version == 3) + { + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + line += satelliteSystem["GPS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = 4; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + // per type of observation + // GPS L1 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L1 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS DOPPLER L1 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L1 CA SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L2_L2CM"]; + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // Find GLONASS Signal in Mixed file + uint32_t number_of_observations_glo = 0; + std::string signal_("1G"); + std::size_t found_1G = glonass_bands.find(signal_); + if (found_1G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + signal_ = "2G"; + std::size_t found_2G = glonass_bands.find(signal_); + if (found_2G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + line.clear(); + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_glo), 3); + if (found_1G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G1_CA"]; + } + if (found_2G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G2_CA"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units (only version 3) + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GPS"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS SLOT / FRQ # + // TODO Need to provide system with list of all satellites and update this accordingly + line.clear(); + line += Rinex_Printer::rightJustify(std::to_string(0), 3); // Number of satellites in list + line += std::string(1, ' '); + line += satelliteSystem["GLONASS"]; + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Slot Number + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(std::to_string(0), 2); // Frequency Number + line += std::string(1, ' '); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS SLOT / FRQ #", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS CODE/PHS/BIS + // No GLONASS Phase bias correction used to align code and phase observations. + line.clear(); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS COD/PHS/BIS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& galileo_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double d_TOW_first_observation, const std::string& galileo_bands, const std::string& glonass_bands) +{ + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed + std::string line; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += "3.02"; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GALILEO/GLONASS) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + line.clear(); + line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + line.clear(); + uint32_t number_of_observations_gal = 0; + std::string signal_("1B"); + std::size_t found_1B = galileo_bands.find(signal_); + if (found_1B != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "5X"; + std::size_t found_5X = galileo_bands.find(signal_); + if (found_5X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + + line.clear(); + signal_ = "7X"; + std::size_t found_7X = galileo_bands.find(signal_); + if (found_7X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + + + line += satelliteSystem["Galileo"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_gal), 3); + + if (found_1B != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E1_B"]; + } + + if (found_5X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5a_IQ"]; + } + + if (found_7X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5b_IQ"]; + } + + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + line.clear(); + uint32_t number_of_observations_glo = 0; + signal_ = "1G"; + std::size_t found_1G = glonass_bands.find(signal_); + if (found_1G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + signal_ = "2G"; + std::size_t found_2G = glonass_bands.find(signal_); + if (found_2G != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_glo), 3); + + if (found_1G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_L1_CA"]; + } + + if (found_2G != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_L2_CA"]; + } + + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_galileo_time = Rinex_Printer::compute_Galileo_time(galileo_eph, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_galileo_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double galileo_t = d_TOW_first_observation; + double seconds = fmod(galileo_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("Galileo"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph, const double d_TOW_first_observation) { std::string line; @@ -2248,14 +4901,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line MARKER NAME line.clear(); - line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, line += Rinex_Printer::leftJustify("MARKER NAME", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2272,7 +4925,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph line.clear(); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -2282,17 +4935,17 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph username = "UNKNOWN USER"; } line += leftJustify(username, 20); - line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line REC / TYPE VERS line.clear(); - line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property - line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property - if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); lengthCheck(line); @@ -2301,7 +4954,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph // -------- ANTENNA TYPE line.clear(); line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property - line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property line += std::string(20, ' '); line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); Rinex_Printer::lengthCheck(line); @@ -2340,8 +4993,8 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph // --------- WAVELENGHT FACTOR // put here real data! line.clear(); - line +=Rinex_Printer::rightJustify("1",6); - line +=Rinex_Printer::rightJustify("1",6); + line += Rinex_Printer::rightJustify("1", 6); + line += Rinex_Printer::rightJustify("1", 6); line += std::string(48, ' '); line += Rinex_Printer::leftJustify("WAVELENGTH FACT L1/2", 20); Rinex_Printer::lengthCheck(line); @@ -2377,7 +5030,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph line += observationType["SIGNAL_STRENGTH"]; line += observationCode["GPS_L1_CA"]; - line += std::string(60-line.size(), ' '); + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2403,7 +5056,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph // GPS L1 SIGNAL STRENGTH line += Rinex_Printer::rightJustify(observationType["SIGNAL_STRENGTH_v2"], 5); line += observationCode["GPS_L1_CA_v2"]; - line += std::string(60-line.size(), ' '); + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("# / TYPES OF OBSERV", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2422,13 +5075,13 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph // -------- TIME OF FIRST OBS line.clear(); - boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph,d_TOW_first_observation); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, d_TOW_first_observation); std::string timestring = boost::posix_time::to_iso_string(p_gps_time); - std::string year (timestring, 0, 4); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); double gps_t = d_TOW_first_observation; double seconds = fmod(gps_t, 60); line += Rinex_Printer::rightJustify(year, 6); @@ -2454,7 +5107,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph } -void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeris & eph, const double d_TOW_first_observation) +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_CNAV_Ephemeris& eph, const double d_TOW_first_observation, const std::string& gps_bands) { std::string line; @@ -2502,14 +5155,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line MARKER NAME line.clear(); - line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, line += Rinex_Printer::leftJustify("MARKER NAME", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2526,7 +5179,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri line.clear(); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -2536,17 +5189,17 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri username = "UNKNOWN USER"; } line += leftJustify(username, 20); - line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line REC / TYPE VERS line.clear(); - line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property - line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property - if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); lengthCheck(line); @@ -2555,7 +5208,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri // -------- ANTENNA TYPE line.clear(); line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property - line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property line += std::string(20, ' '); line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); Rinex_Printer::lengthCheck(line); @@ -2592,31 +5245,67 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri // -------- SYS / OBS TYPES // one line per available system line.clear(); + uint32_t number_of_observations_gps = 0; + std::string signal_("2S"); + std::size_t found_2S = gps_bands.find(signal_); + if (found_2S != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "L5"; + std::size_t found_L5 = gps_bands.find(signal_); + if (found_L5 != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } line += satelliteSystem["GPS"]; line += std::string(2, ' '); std::stringstream strm; - numberTypesObservations = 4; + numberTypesObservations = number_of_observations_gps; strm << numberTypesObservations; line += Rinex_Printer::rightJustify(strm.str(), 3); // per type of observation - // GPS L2 PSEUDORANGE - line += std::string(1, ' '); - line += observationType["PSEUDORANGE"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS L2 PHASE - line += std::string(1, ' '); - line += observationType["CARRIER_PHASE"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS DOPPLER L2 - line += std::string(1, ' '); - line += observationType["DOPPLER"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS L2 SIGNAL STRENGTH - line += std::string(1, ' '); - line += observationType["SIGNAL_STRENGTH"]; - line += observationCode["GPS_L2_L2CM"]; - line += std::string(60-line.size(), ' '); + if (found_2S != std::string::npos) + { + // GPS L2 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS DOPPLER L2 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L2_L2CM"]; + } + + if (found_L5 != std::string::npos) + { + // GPS L5 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L5_Q"]; + // GPS DOPPLER L5 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L5_Q"]; + } + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2631,13 +5320,13 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri // -------- TIME OF FIRST OBS line.clear(); - boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph,d_TOW_first_observation); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, d_TOW_first_observation); std::string timestring = boost::posix_time::to_iso_string(p_gps_time); - std::string year (timestring, 0, 4); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); double gps_t = d_TOW_first_observation; double seconds = fmod(gps_t, 60); line += Rinex_Printer::rightJustify(year, 6); @@ -2663,9 +5352,11 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_CNAV_Ephemeri } -void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & eph, const Gps_CNAV_Ephemeris & eph_cnav, const double d_TOW_first_observation) +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph, const Gps_CNAV_Ephemeris& eph_cnav, const double d_TOW_first_observation, const std::string& gps_bands) { - if(eph_cnav.d_i_0){} // avoid warning, not needed + if (eph_cnav.d_i_0) + { + } // avoid warning, not needed std::string line; // -------- Line 1 @@ -2712,14 +5403,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line MARKER NAME line.clear(); - line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, line += Rinex_Printer::leftJustify("MARKER NAME", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2736,7 +5427,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e line.clear(); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -2746,17 +5437,17 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e username = "UNKNOWN USER"; } line += leftJustify(username, 20); - line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line REC / TYPE VERS line.clear(); - line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property - line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property - if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); lengthCheck(line); @@ -2765,7 +5456,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e // -------- ANTENNA TYPE line.clear(); line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property - line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property line += std::string(20, ' '); line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); Rinex_Printer::lengthCheck(line); @@ -2802,47 +5493,91 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e // -------- SYS / OBS TYPES // one line per available system line.clear(); + uint32_t number_of_observations_gps = 0; + std::string signal_("1C"); + std::size_t found_1C = gps_bands.find(signal_); + if (found_1C != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "2S"; + std::size_t found_2S = gps_bands.find(signal_); + if (found_2S != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "L5"; + std::size_t found_L5 = gps_bands.find(signal_); + if (found_L5 != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } line += satelliteSystem["GPS"]; line += std::string(2, ' '); std::stringstream strm; - numberTypesObservations = 8; + numberTypesObservations = number_of_observations_gps; strm << numberTypesObservations; line += Rinex_Printer::rightJustify(strm.str(), 3); // per type of observation - // GPS L1 PSEUDORANGE - line += std::string(1, ' '); - line += observationType["PSEUDORANGE"]; - line += observationCode["GPS_L1_CA"]; - // GPS L1 PHASE - line += std::string(1, ' '); - line += observationType["CARRIER_PHASE"]; - line += observationCode["GPS_L1_CA"]; - // GPS DOPPLER L1 - line += std::string(1, ' '); - line += observationType["DOPPLER"]; - line += observationCode["GPS_L1_CA"]; - // GPS L1 CA SIGNAL STRENGTH - line += std::string(1, ' '); - line += observationType["SIGNAL_STRENGTH"]; - line += observationCode["GPS_L1_CA"]; - // GPS L2 PSEUDORANGE - line += std::string(1, ' '); - line += observationType["PSEUDORANGE"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS L2 PHASE - line += std::string(1, ' '); - line += observationType["CARRIER_PHASE"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS DOPPLER L2 - line += std::string(1, ' '); - line += observationType["DOPPLER"]; - line += observationCode["GPS_L2_L2CM"]; - // GPS L2 SIGNAL STRENGTH - line += std::string(1, ' '); - line += observationType["SIGNAL_STRENGTH"]; - line += observationCode["GPS_L2_L2CM"]; + if (found_1C != std::string::npos) + { + // GPS L1 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L1_CA"]; + // GPS DOPPLER L1 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 CA SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L1_CA"]; + } + if (found_2S != std::string::npos) + { + // GPS L2 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS DOPPLER L2 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L2_L2CM"]; + } - line += std::string(60-line.size(), ' '); + if (found_L5 != std::string::npos) + { + // GPS L5 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L5_Q"]; + // GPS DOPPLER L5 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L5_Q"]; + } + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2857,13 +5592,13 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e // -------- TIME OF FIRST OBS line.clear(); - boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph,d_TOW_first_observation); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, d_TOW_first_observation); std::string timestring = boost::posix_time::to_iso_string(p_gps_time); - std::string year (timestring, 0, 4); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); double gps_t = d_TOW_first_observation; double seconds = fmod(gps_t, 60); line += Rinex_Printer::rightJustify(year, 6); @@ -2889,7 +5624,673 @@ void Rinex_Printer::rinex_obs_header(std::fstream & out, const Gps_Ephemeris & e } -void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& eph, const double d_TOW_first_observation, const std::string bands) +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& eph_cnav, const Galileo_Ephemeris& galileo_eph, const double d_TOW_first_observation, const std::string& gps_bands, const std::string& galileo_bands) +{ + std::string line; + version = 3; + if (eph_cnav.d_e_eccentricity == 0) + { + // avoid warning + } + if (galileo_eph.e_1 == 0) + { + // avoid warning + } + + // -------- Line 1 + line = std::string(5, ' '); + line += "3.02"; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GPS/GALILEO) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + //line.clear(); + //line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + //line += std::string(40, ' '); + //line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + //Rinex_Printer::lengthCheck(line); + //out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + uint32_t number_of_observations_gps = 0; + std::string signal_("1C"); + std::size_t found_1C = gps_bands.find(signal_); + if (found_1C != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "2S"; + std::size_t found_2S = gps_bands.find(signal_); + if (found_2S != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "L5"; + std::size_t found_L5 = gps_bands.find(signal_); + if (found_L5 != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + line += satelliteSystem["GPS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = number_of_observations_gps; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + // per type of observation + if (found_1C != std::string::npos) + { + // GPS L1 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L1_CA"]; + // GPS DOPPLER L1 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 CA SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L1_CA"]; + } + if (found_2S != std::string::npos) + { + // GPS L2 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS DOPPLER L2 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L2_L2CM"]; + } + if (found_L5 != std::string::npos) + { + // GPS L5 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L5_Q"]; + // GPS DOPPLER L5 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L5_Q"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + line.clear(); + uint32_t number_of_observations_gal = 0; + signal_ = "1B"; + std::size_t found_1B = galileo_bands.find(signal_); + if (found_1B != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "5X"; + std::size_t found_5X = galileo_bands.find(signal_); + if (found_5X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "7X"; + std::size_t found_7X = galileo_bands.find(signal_); + if (found_7X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + line += satelliteSystem["Galileo"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_gal), 3); + if (found_1B != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E1_B"]; + } + if (found_5X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5a_IQ"]; + } + if (found_7X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5b_IQ"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GPS"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_CNAV_Ephemeris& eph_cnav, const Galileo_Ephemeris& galileo_eph, const double d_TOW_first_observation, const std::string& gps_bands, const std::string& galileo_bands) +{ + std::string line; + version = 3; + if (galileo_eph.e_1 == 0) + { + // avoid warning + } + // -------- Line 1 + line = std::string(5, ' '); + line += "3.02"; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GPS/GALILEO) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + //line.clear(); + //line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + //line += std::string(40, ' '); + //line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + //Rinex_Printer::lengthCheck(line); + //out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + uint32_t number_of_observations_gps = 0; + std::string signal_("2S"); + std::size_t found_2S = gps_bands.find(signal_); + if (found_2S != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + signal_ = "L5"; + std::size_t found_L5 = gps_bands.find(signal_); + if (found_L5 != std::string::npos) + { + number_of_observations_gps = number_of_observations_gps + 4; + } + line += satelliteSystem["GPS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = number_of_observations_gps; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + // per type of observation + if (found_2S != std::string::npos) + { + // GPS L2 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS DOPPLER L2 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L2_L2CM"]; + // GPS L2 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L2_L2CM"]; + } + if (found_L5 != std::string::npos) + { + // GPS L5 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L5_Q"]; + // GPS DOPPLER L5 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L5_Q"]; + // GPS L5 SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L5_Q"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + line.clear(); + uint32_t number_of_observations_gal = 0; + signal_ = "1B"; + std::size_t found_1B = galileo_bands.find(signal_); + if (found_1B != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "5X"; + std::size_t found_5X = galileo_bands.find(signal_); + if (found_5X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "7X"; + std::size_t found_7X = galileo_bands.find(signal_); + if (found_7X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + line += satelliteSystem["Galileo"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_gal), 3); + if (found_1B != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E1_B"]; + } + if (found_5X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5a_IQ"]; + } + if (found_7X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5b_IQ"]; + } + line += std::string(60 - line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph_cnav, d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GPS"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& eph, const double d_TOW_first_observation, const std::string& bands) { std::string line; version = 3; @@ -2938,14 +6339,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line MARKER NAME line.clear(); - line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, line += Rinex_Printer::leftJustify("MARKER NAME", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -2962,7 +6363,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line.clear(); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -2972,17 +6373,17 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& username = "UNKNOWN USER"; } line += leftJustify(username, 20); - line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line REC / TYPE VERS line.clear(); - line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property - line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property - if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); lengthCheck(line); @@ -2991,7 +6392,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& // -------- ANTENNA TYPE line.clear(); line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property - line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property line += std::string(20, ' '); line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); Rinex_Printer::lengthCheck(line); @@ -3027,16 +6428,16 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& // -------- SYS / OBS TYPES // one line per available system - unsigned int number_of_observations = 0; + uint32_t number_of_observations = 0; std::string signal_("1B"); std::size_t found_1B = bands.find(signal_); - if(found_1B != std::string::npos) + if (found_1B != std::string::npos) { number_of_observations = number_of_observations + 4; } signal_ = "5X"; std::size_t found_5X = bands.find(signal_); - if(found_5X != std::string::npos) + if (found_5X != std::string::npos) { number_of_observations = number_of_observations + 4; } @@ -3044,7 +6445,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line.clear(); signal_ = "7X"; std::size_t found_7X = bands.find(signal_); - if(found_7X != std::string::npos) + if (found_7X != std::string::npos) { number_of_observations = number_of_observations + 4; } @@ -3055,7 +6456,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line += std::string(2, ' '); line += Rinex_Printer::rightJustify(std::to_string(number_of_observations), 3); - if(found_1B != std::string::npos) + if (found_1B != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3071,7 +6472,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line += observationCode["GALILEO_E1_B"]; } - if(found_5X != std::string::npos) + if (found_5X != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3087,7 +6488,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line += observationCode["GALILEO_E5a_IQ"]; } - if(found_7X != std::string::npos) + if (found_7X != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3103,7 +6504,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line += observationCode["GALILEO_E5b_IQ"]; } - line += std::string(60-line.size(), ' '); + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -3119,12 +6520,12 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& // -------- TIME OF FIRST OBS line.clear(); boost::posix_time::ptime p_galileo_time = Rinex_Printer::compute_Galileo_time(eph, d_TOW_first_observation); - std::string timestring=boost::posix_time::to_iso_string(p_galileo_time); - std::string year (timestring, 0, 4); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string timestring = boost::posix_time::to_iso_string(p_galileo_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); double galileo_t = d_TOW_first_observation; double seconds = fmod(galileo_t, 60); line += Rinex_Printer::rightJustify(year, 6); @@ -3150,9 +6551,11 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& } -void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps_eph, const Galileo_Ephemeris& galileo_eph, const double d_TOW_first_observation, const std::string galileo_bands) +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps_eph, const Galileo_Ephemeris& galileo_eph, const double d_TOW_first_observation, const std::string& galileo_bands) { - if(galileo_eph.e_1){} // avoid warning, not needed + if (galileo_eph.e_1) + { + } // avoid warning, not needed std::string line; version = 3; @@ -3200,14 +6603,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps // -------- Line COMMENT line.clear(); - line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("See https://gnss-sdr.org", 60); line += Rinex_Printer::leftJustify("COMMENT", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line MARKER NAME line.clear(); - line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, line += Rinex_Printer::leftJustify("MARKER NAME", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -3224,7 +6627,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line.clear(); std::string username; char c_username[20] = {0}; - int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + int32_t nGet = getlogin_r(c_username, sizeof(c_username) - 1); if (nGet == 0) { username = c_username; @@ -3234,17 +6637,17 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps username = "UNKNOWN USER"; } line += leftJustify(username, 20); - line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; // -------- Line REC / TYPE VERS line.clear(); - line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property - line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property - if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + if (gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); lengthCheck(line); @@ -3253,7 +6656,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps // -------- ANTENNA TYPE line.clear(); line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property - line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property line += std::string(20, ' '); line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); Rinex_Printer::lengthCheck(line); @@ -3313,22 +6716,22 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line += std::string(1, ' '); line += observationType["SIGNAL_STRENGTH"]; line += observationCode["GPS_L1_CA"]; - line += std::string(60-line.size(), ' '); + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; line.clear(); - unsigned int number_of_observations_gal = 0; + uint32_t number_of_observations_gal = 0; std::string signal_("1B"); std::size_t found_1B = galileo_bands.find(signal_); - if(found_1B != std::string::npos) + if (found_1B != std::string::npos) { number_of_observations_gal = number_of_observations_gal + 4; } signal_ = "5X"; std::size_t found_5X = galileo_bands.find(signal_); - if(found_5X != std::string::npos) + if (found_5X != std::string::npos) { number_of_observations_gal = number_of_observations_gal + 4; } @@ -3336,17 +6739,16 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line.clear(); signal_ = "7X"; std::size_t found_7X = galileo_bands.find(signal_); - if(found_7X != std::string::npos) + if (found_7X != std::string::npos) { number_of_observations_gal = number_of_observations_gal + 4; } - line += satelliteSystem["Galileo"]; line += std::string(2, ' '); line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_gal), 3); - if(found_1B != std::string::npos) + if (found_1B != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3362,7 +6764,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line += observationCode["GALILEO_E1_B"]; } - if(found_5X != std::string::npos) + if (found_5X != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3378,7 +6780,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line += observationCode["GALILEO_E5a_IQ"]; } - if(found_7X != std::string::npos) + if (found_7X != std::string::npos) { line += std::string(1, ' '); line += observationType["PSEUDORANGE"]; @@ -3394,7 +6796,7 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps line += observationCode["GALILEO_E5b_IQ"]; } - line += std::string(60-line.size(), ' '); + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); out << line << std::endl; @@ -3410,12 +6812,12 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps // -------- TIME OF FIRST OBS line.clear(); boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, d_TOW_first_observation); - std::string timestring=boost::posix_time::to_iso_string(p_gps_time); - std::string year (timestring, 0, 4); - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year(timestring, 0, 4); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); double gps_t = d_TOW_first_observation; double seconds = fmod(gps_t, 60); line += Rinex_Printer::rightJustify(year, 6); @@ -3439,6 +6841,15 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps } +void Rinex_Printer::update_obs_header(std::fstream& out __attribute__((unused)), const Glonass_Gnav_Utc_Model& utc_model) +{ + if (utc_model.d_N_4) + { + // do nothing + } +} + + void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_Utc_Model& utc_model) { std::vector data; @@ -3450,20 +6861,20 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_Utc_Model& ut bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) { line_aux.clear(); if (version == 2) { - if (line_str.find("TIME OF FIRST OBS", 59) != std::string::npos) // TIME OF FIRST OBS last header annotation might change in the future + if (line_str.find("TIME OF FIRST OBS", 59) != std::string::npos) // TIME OF FIRST OBS last header annotation might change in the future { data.push_back(line_str); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); line_aux += std::string(54, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -3484,10 +6895,10 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_Utc_Model& ut if (line_str.find("TIME OF FIRST OBS", 59) != std::string::npos) { data.push_back(line_str); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -3512,7 +6923,7 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_Utc_Model& ut out.close(); out.open(obsfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -3533,20 +6944,20 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_CNAV_Utc_Mode bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) { line_aux.clear(); if (line_str.find("TIME OF FIRST OBS", 59) != std::string::npos) { data.push_back(line_str); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LS), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.d_DeltaT_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_WN_LSF), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(utc_model.i_DN), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(utc_model.i_DN), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -3560,7 +6971,6 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_CNAV_Utc_Mode { data.push_back(line_str); } - } else { @@ -3571,7 +6981,7 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_CNAV_Utc_Mode out.close(); out.open(obsfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } @@ -3592,21 +7002,21 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Galileo_Utc_Model bool no_more_finds = false; std::string line_str; - while(!out.eof()) + while (!out.eof()) { std::getline(out, line_str); - if(!no_more_finds) + if (!no_more_finds) { line_aux.clear(); if (line_str.find("TIME OF FIRST OBS", 59) != std::string::npos) { data.push_back(line_str); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLS_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLSF_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WN_LSF_6), 6); - line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.DN_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLS_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.Delta_tLSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.WN_LSF_6), 6); + line_aux += Rinex_Printer::rightJustify(std::to_string(galileo_utc_model.DN_6), 6); line_aux += std::string(36, ' '); line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); data.push_back(line_aux); @@ -3620,7 +7030,6 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Galileo_Utc_Model { data.push_back(line_str); } - } else { @@ -3631,40 +7040,46 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Galileo_Utc_Model out.close(); out.open(obsfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < (int) data.size() - 1; i++) + for (int32_t i = 0; i < static_cast(data.size()) - 1; i++) { out << data[i] << std::endl; } out.close(); - out.open(obsfilename, std::ios::out | std::ios::in |std::ios::app); + out.open(obsfilename, std::ios::out | std::ios::in | std::ios::app); out.seekp(0, std::ios_base::end); } -void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, const double obs_time, const std::map& observables) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Glonass_Gnav_Ephemeris& eph, const double obs_time, const std::map& observables, const std::string& glonass_band) { // RINEX observations timestamps are GPS timestamps. std::string line; + double int_sec = 0; - boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, obs_time); - std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + // Avoid compiler warning + if (!glonass_band.empty()) + { + } + + boost::posix_time::ptime p_glonass_time = Rinex_Printer::compute_UTC_time(eph, obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_glonass_time); //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); //double gps_t = eph.sv_clock_correction(obs_time); - double gps_t = obs_time; - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + double utc_sec = modf(obs_time, &int_sec) + p_glonass_time.time_of_day().seconds(); if (version == 2) { line.clear(); - std::string year (timestring, 2, 2); + std::string year(timestring, 2, 2); line += std::string(1, ' '); line += year; line += std::string(1, ' '); - if (month.compare(0, 1 , "0") == 0) + if (month.compare(0, 1, "0") == 0) { line += std::string(1, ' '); line += month.substr(1, 1); @@ -3674,7 +7089,249 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, c line += month; } line += std::string(1, ' '); - if (day.compare(0, 1 , "0") == 0) + if (day.compare(0, 1, "0") == 0) + { + line += std::string(1, ' '); + line += day.substr(1, 1); + } + else + { + line += day; + } + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + line += std::string(1, ' '); + if (utc_sec < 10) + { + line += std::string(1, ' '); + } + line += Rinex_Printer::asString(utc_sec, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + //Number of satellites observed in current epoch + int32_t numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + line += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += std::to_string(static_cast(observables_iter->second.PRN)); + } + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + line.clear(); + // GLONASS L1 PSEUDORANGE + line += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GLONASS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GLONASS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GLONASS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //GLONASS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } + + if (version == 3) + { + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + // Add extra 0 if seconds are < 10 + if (utc_sec < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(utc_sec, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + int32_t numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + lineObs += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); + //lineObs += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GLONASS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + //GLONASS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double gps_obs_time, const std::map& observables) +{ + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed + std::string line; + + // -------- EPOCH record + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, gps_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = gps_obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + if (version == 2) + { + line.clear(); + std::string year(timestring, 2, 2); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + if (month.compare(0, 1, "0") == 0) + { + line += std::string(1, ' '); + line += month.substr(1, 1); + } + else + { + line += month; + } + line += std::string(1, ' '); + if (day.compare(0, 1, "0") == 0) { line += std::string(1, ' '); line += day.substr(1, 1); @@ -3697,88 +7354,10 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, c line += std::string(2, ' '); // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event line += std::string(1, '0'); - //Number of satellites observed in current epoch - int numSatellitesObserved = 0; - std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) - { - numSatellitesObserved++; - } - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) - { - line += satelliteSystem["GPS"]; - if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); - line += boost::lexical_cast(static_cast(observables_iter->second.PRN)); - } - // Receiver clock offset (optional) - //line += rightJustify(asString(clockOffset, 12), 15); - line += std::string(80 - line.size(), ' '); - Rinex_Printer::lengthCheck(line); - out << line << std::endl; - - - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) - { - std::string lineObs; - lineObs.clear(); - line.clear(); - // GPS L1 PSEUDORANGE - line += std::string(2, ' '); - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); - - //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! - if (lli == 0) - { - lineObs += std::string(1, ' '); - } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - - // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - // GPS L1 CA PHASE - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); - if (lli == 0) - { - lineObs += std::string(1, ' '); - } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - // GPS L1 CA DOPPLER - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); - if (lli == 0) - { - lineObs += std::string(1, ' '); - } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - //GPS L1 SIGNAL STRENGTH - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); - if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); - out << lineObs << std::endl; - } } - if (version == 3) { - std::string year (timestring, 0, 4); + std::string year(timestring, 0, 4); line += std::string(1, '>'); line += std::string(1, ' '); line += year; @@ -3795,112 +7374,265 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, c double seconds = fmod(gps_t, 60); // Add extra 0 if seconds are < 10 if (seconds < 10) - { - line += std::string(1, '0'); - } + { + line += std::string(1, '0'); + } line += Rinex_Printer::asString(seconds, 7); line += std::string(2, ' '); // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event line += std::string(1, '0'); + } - //Number of satellites observed in current epoch - int numSatellitesObserved = 0; - std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + //Number of satellites observed in current epoch + //Get maps with observations + std::map observablesG1C; + std::map observablesR1C; + std::map observablesR2C; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_ == "R") && (sig_ == "1G")) { - numSatellitesObserved++; + observablesR1C.insert(std::pair(observables_iter->first, observables_iter->second)); } - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); - - - // Receiver clock offset (optional) - //line += rightJustify(asString(clockOffset, 12), 15); - - line += std::string(80 - line.size(), ' '); - Rinex_Printer::lengthCheck(line); - out << line << std::endl; - - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + if ((system_ == "R") && (sig_ == "2G")) { - std::string lineObs; - lineObs.clear(); - lineObs += satelliteSystem["GPS"]; - if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); - //lineObs += std::string(2, ' '); - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + observablesR2C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "1C")) + { + observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_glo_map; + std::set available_glo_prns; + std::set::iterator it; + for (observables_iter = observablesR1C.cbegin(); + observables_iter != observablesR1C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + for (observables_iter = observablesR2C.cbegin(); + observables_iter != observablesR2C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + int32_t numGloSatellitesObserved = available_glo_prns.size(); + int32_t numGpsSatellitesObserved = observablesG1C.size(); + int32_t numSatellitesObserved = numGloSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + if (version == 2) + { + // Add list of GPS satellites + for (observables_iter = observablesG1C.cbegin(); + observables_iter != observablesG1C.cend(); + observables_iter++) + { + line += satelliteSystem["GPS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += std::to_string(static_cast(observables_iter->second.PRN)); + } + // Add list of GLONASS L1 satellites + for (observables_iter = observablesR1C.cbegin(); + observables_iter != observablesR1C.cend(); + observables_iter++) + { + line += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += std::to_string(static_cast(observables_iter->second.PRN)); + } + // Add list of GLONASS L2 satellites + for (observables_iter = observablesR2C.cbegin(); + observables_iter != observablesR2C.cend(); + observables_iter++) + { + line += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += std::to_string(static_cast(observables_iter->second.PRN)); + } + } + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- OBSERVATION record + std::string s; + std::string lineObs; + for (observables_iter = observablesG1C.cbegin(); + observables_iter != observablesG1C.cend(); + observables_iter++) + { + lineObs.clear(); + + s.assign(1, observables_iter->second.System); + if (version == 3) + { + // Specify system only if in version 3 + if (s == "G") lineObs += satelliteSystem["GPS"]; + if (s == "R") lineObs += satelliteSystem["GLONASS"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); + } + + // Pseudorange Measurements + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_glo_prns.begin(); + it != available_glo_prns.end(); + it++) + { + lineObs.clear(); + if (version == 3) + { + lineObs += satelliteSystem["GLONASS"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + } + ret = total_glo_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + /// \todo Need to account for pseudorange correction for glonass + //double leap_seconds = Rinex_Printer::get_leap_second(glonass_gnav_eph, gps_obs_time); + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - // GPS L1 CA PHASE - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + // GLONASS CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GLONASS_TWO_PI), 3), 14); if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - // GPS L1 CA DOPPLER - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + // GLONASS DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); - - //GPS L1 SIGNAL STRENGTH - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); - - if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); - out << lineObs << std::endl; + // GLONASS SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); } + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; } } -void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & eph, double obs_time, const std::map & observables) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double gps_obs_time, const std::map& observables) { - // RINEX observations timestamps are GPS timestamps. + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed std::string line; - boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, obs_time); + // -------- EPOCH record + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, gps_obs_time); std::string timestring = boost::posix_time::to_iso_string(p_gps_time); //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); //double gps_t = eph.sv_clock_correction(obs_time); - double gps_t = obs_time; + double gps_t = gps_obs_time; - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); - std::string year (timestring, 0, 4); + std::string year(timestring, 0, 4); line += std::string(1, '>'); line += std::string(1, ' '); line += year; @@ -3926,15 +7658,304 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & line += std::string(1, '0'); //Number of satellites observed in current epoch - int numSatellitesObserved = 0; - std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + //Get maps with observations + std::map observablesG2S; + std::map observablesR1C; + std::map observablesR2C; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { - numSatellitesObserved++; + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_ == "R") && (sig_ == "1G")) + { + observablesR1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "R") && (sig_ == "2G")) + { + observablesR2C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "2S")) + { + observablesG2S.insert(std::pair(observables_iter->first, observables_iter->second)); + } } - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + + std::multimap total_glo_map; + std::set available_glo_prns; + std::set::iterator it; + for (observables_iter = observablesR1C.cbegin(); + observables_iter != observablesR1C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + for (observables_iter = observablesR2C.cbegin(); + observables_iter != observablesR2C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + int32_t numGloSatellitesObserved = available_glo_prns.size(); + int32_t numGpsSatellitesObserved = observablesG2S.size(); + int32_t numSatellitesObserved = numGloSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- OBSERVATION record + std::string s; + std::string lineObs; + for (observables_iter = observablesG2S.cbegin(); + observables_iter != observablesG2S.cend(); + observables_iter++) + { + lineObs.clear(); + + s.assign(1, observables_iter->second.System); + // Specify system only if in version 3 + if (s == "G") lineObs += satelliteSystem["GPS"]; + if (s == "R") lineObs += satelliteSystem["GLONASS"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); + + // Pseudorange Measurements + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_glo_prns.begin(); + it != available_glo_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["GLONASS"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + + ret = total_glo_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + /// \todo Need to account for pseudorange correction for glonass + //double leap_seconds = Rinex_Printer::get_leap_second(glonass_gnav_eph, gps_obs_time); + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GLONASS_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& galileo_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double galileo_obs_time, const std::map& observables) +{ + if (glonass_gnav_eph.d_m) + { + } // avoid warning, not needed + std::string line; + + boost::posix_time::ptime p_galileo_time = Rinex_Printer::compute_Galileo_time(galileo_eph, galileo_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_galileo_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double galileo_t = galileo_obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(galileo_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + + //Get maps with observations + std::map observablesE1B; + std::map observablesR1C; + std::map observablesR2C; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_ == "R") && (sig_ == "1G")) + { + observablesR1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "R") && (sig_ == "2G")) + { + observablesR2C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "E") && (sig_ == "1B")) + { + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_glo_map; + std::set available_glo_prns; + std::set::iterator it; + for (observables_iter = observablesR1C.cbegin(); + observables_iter != observablesR1C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + for (observables_iter = observablesR2C.cbegin(); + observables_iter != observablesR2C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if (it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + int32_t numGloSatellitesObserved = available_glo_prns.size(); + int32_t numGalSatellitesObserved = observablesE1B.size(); + int32_t numSatellitesObserved = numGalSatellitesObserved + numGloSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); // Receiver clock offset (optional) //line += rightJustify(asString(clockOffset, 12), 15); @@ -3943,45 +7964,469 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & Rinex_Printer::lengthCheck(line); out << line << std::endl; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + std::string s; + std::string lineObs; + for (observables_iter = observablesE1B.cbegin(); + observables_iter != observablesE1B.cend(); + observables_iter++) + { + lineObs.clear(); + + s.assign(1, observables_iter->second.System); + if (s == "E") lineObs += satelliteSystem["Galileo"]; + if (s == "R") lineObs += satelliteSystem["GLONASS"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_glo_prns.begin(); + it != available_glo_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["Galileo"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + ret = total_glo_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GLONASS_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, const double obs_time, const std::map& observables) +{ + // RINEX observations timestamps are GPS timestamps. + std::string line; + + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + if (version == 2) + { + line.clear(); + std::string year(timestring, 2, 2); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + if (month.compare(0, 1, "0") == 0) + { + line += std::string(1, ' '); + line += month.substr(1, 1); + } + else + { + line += month; + } + line += std::string(1, ' '); + if (day.compare(0, 1, "0") == 0) + { + line += std::string(1, ' '); + line += day.substr(1, 1); + } + else + { + line += day; + } + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + line += std::string(1, ' '); + double second_ = fmod(gps_t, 60); + if (second_ < 10) + { + line += std::string(1, ' '); + } + line += Rinex_Printer::asString(second_, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + //Number of satellites observed in current epoch + int32_t numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + line += satelliteSystem["GPS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += std::to_string(static_cast(observables_iter->second.PRN)); + } + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + line.clear(); + // GPS L1 PSEUDORANGE + line += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GPS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + // else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GPS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //GPS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } + + if (version == 3) + { + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(gps_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + int32_t numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + lineObs += satelliteSystem["GPS"]; + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); + //lineObs += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GPS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GPS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + //GPS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& eph, double obs_time, const std::map& observables) +{ + // RINEX observations timestamps are GPS timestamps. + std::string line; + + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(gps_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + int32_t numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string lineObs; lineObs.clear(); lineObs += satelliteSystem["GPS"]; - if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); //lineObs += std::string(2, ' '); //GPS L2 PSEUDORANGE lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // GPS L2 PHASE - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // GPS L2 DOPPLER lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); @@ -3989,12 +8434,12 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); //GPS L2 SIGNAL STRENGTH lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); @@ -4005,9 +8450,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & } -void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, const Gps_CNAV_Ephemeris & eph_cnav, double obs_time, const std::map & observables) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, const Gps_CNAV_Ephemeris& eph_cnav, double obs_time, const std::map& observables) { - if(eph_cnav.d_i_0){} // avoid warning, not needed + if (eph_cnav.d_i_0) + { + } // avoid warning, not needed // RINEX observations timestamps are GPS timestamps. std::string line; @@ -4017,12 +8464,12 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, //double gps_t = eph.sv_clock_correction(obs_time); double gps_t = obs_time; - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); - std::string year (timestring, 0, 4); + std::string year(timestring, 0, 4); line += std::string(1, '>'); line += std::string(1, ' '); line += year; @@ -4050,84 +8497,108 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, //Number of satellites observed in current epoch //Get maps with GPS L1 and L2 observations - std::map observablesL1; - std::map observablesL2; - std::map::const_iterator observables_iter; - std::map::const_iterator observables_iter2; + std::map observablesL1; + std::map observablesL2; + std::map observablesL5; + std::map::const_iterator observables_iter; - std::multimap total_mmap; - std::multimap::iterator mmap_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + std::multimap total_mmap; + std::multimap::iterator mmap_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_ == "G") && (sig_ == "1C")) { - observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); - total_mmap.insert(std::pair(observables_iter->second.PRN, observables_iter->second)); + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + total_mmap.insert(std::pair(observables_iter->second.PRN, observables_iter->second)); } - if((system_.compare("G") == 0) && (sig_.compare("2S") == 0)) + if ((system_ == "G") && (sig_ == "2S")) { - observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); mmap_iter = total_mmap.find(observables_iter->second.PRN); - if(mmap_iter == total_mmap.end()) + if (mmap_iter == total_mmap.end()) { Gnss_Synchro gs = Gnss_Synchro(); - total_mmap.insert(std::pair(observables_iter->second.PRN, gs)); + total_mmap.insert(std::pair(observables_iter->second.PRN, gs)); } - total_mmap.insert(std::pair(observables_iter->second.PRN, observables_iter->second)); + total_mmap.insert(std::pair(observables_iter->second.PRN, observables_iter->second)); + } + + if ((system_ == "G") && (sig_ == "L5")) + { + observablesL5.insert(std::pair(observables_iter->first, observables_iter->second)); + mmap_iter = total_mmap.find(observables_iter->second.PRN); + if (mmap_iter == total_mmap.end()) + { + Gnss_Synchro gs = Gnss_Synchro(); + total_mmap.insert(std::pair(observables_iter->second.PRN, gs)); + } + total_mmap.insert(std::pair(observables_iter->second.PRN, observables_iter->second)); } } // Fill with zeros satellites with L1 obs but not L2 - std::multimap mmap_aux; + std::multimap mmap_aux; mmap_aux = total_mmap; - for(mmap_iter = mmap_aux.begin(); - mmap_iter != mmap_aux.end(); - mmap_iter++) + for (mmap_iter = mmap_aux.begin(); + mmap_iter != mmap_aux.end(); + mmap_iter++) { - if((total_mmap.count(mmap_iter->second.PRN)) == 1 && (mmap_iter->second.PRN != 0)) + if ((total_mmap.count(mmap_iter->second.PRN)) == 1 && (mmap_iter->second.PRN != 0)) { Gnss_Synchro gs = Gnss_Synchro(); std::string sys = "G"; gs.System = *sys.c_str(); std::string sig = "2S"; - std::memcpy((void*)gs.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); gs.PRN = mmap_iter->second.PRN; - total_mmap.insert(std::pair(mmap_iter->second.PRN, gs)); + total_mmap.insert(std::pair(mmap_iter->second.PRN, gs)); } } - std::set available_prns; - std::set::iterator it; - for(observables_iter = observablesL1.begin(); - observables_iter != observablesL1.end(); - observables_iter++) + std::set available_prns; + std::set::iterator it; + for (observables_iter = observablesL1.cbegin(); + observables_iter != observablesL1.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; + uint32_t prn_ = observables_iter->second.PRN; it = available_prns.find(prn_); - if(it == available_prns.end()) + if (it == available_prns.end()) { available_prns.insert(prn_); } } - for(observables_iter = observablesL2.begin(); - observables_iter != observablesL2.end(); - observables_iter++) + for (observables_iter = observablesL2.cbegin(); + observables_iter != observablesL2.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; + uint32_t prn_ = observables_iter->second.PRN; it = available_prns.find(prn_); - if(it == available_prns.end()) + if (it == available_prns.end()) { available_prns.insert(prn_); } } - int numSatellitesObserved = available_prns.size(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + for (observables_iter = observablesL5.cbegin(); + observables_iter != observablesL5.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + it = available_prns.find(prn_); + if (it == available_prns.end()) + { + available_prns.insert(prn_); + } + } + + int32_t numSatellitesObserved = available_prns.size(); + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); // Receiver clock offset (optional) //line += rightJustify(asString(clockOffset, 12), 15); line += std::string(80 - line.size(), ' '); @@ -4135,34 +8606,34 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, out << line << std::endl; std::string lineObs; - std::pair ::iterator, std::multimap::iterator> ret; - for(it = available_prns.begin(); - it != available_prns.end(); - it++) + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_prns.begin(); + it != available_prns.end(); + it++) { lineObs.clear(); lineObs += satelliteSystem["GPS"]; - if (static_cast(*it) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(*it)); + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); ret = total_mmap.equal_range(*it); - for (std::multimap::iterator iter = ret.first; iter != ret.second; ++iter) + for (auto iter = ret.first; iter != ret.second; ++iter) { lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + // else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // GPS CARRIER PHASE lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); @@ -4170,11 +8641,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // GPS DOPPLER lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); @@ -4182,11 +8653,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // GPS SIGNAL STRENGTH lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); @@ -4198,7 +8669,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, } -void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& eph, double obs_time, const std::map& observables, const std::string galileo_bands) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& eph, double obs_time, const std::map& observables, const std::string& galileo_bands) { // RINEX observations timestamps are Galileo timestamps. // See http://gage14.upc.es/gLAB/HTML/Observation_Rinex_v3.01.html @@ -4210,12 +8681,12 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep //double gps_t = eph.sv_clock_correction(obs_time); double galileo_t = obs_time; - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); - std::string year (timestring, 0, 4); + std::string year(timestring, 0, 4); line += std::string(1, '>'); line += std::string(1, ' '); line += year; @@ -4243,131 +8714,131 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep //Number of satellites observed in current epoch //Get maps with Galileo observations - std::map observablesE1B; - std::map observablesE5A; - std::map observablesE5B; - std::map::const_iterator observables_iter; + std::map observablesE1B; + std::map observablesE5A; + std::map observablesE5B; + std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("E") == 0) && (sig_.compare("1B") == 0)) + if ((system_ == "E") && (sig_ == "1B")) { - observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("E") == 0) && (sig_.compare("5X") == 0)) + if ((system_ == "E") && (sig_ == "5X")) { - observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("E") == 0) && (sig_.compare("7X") == 0)) + if ((system_ == "E") && (sig_ == "7X")) { - observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } } std::size_t found_1B = galileo_bands.find("1B"); std::size_t found_E5a = galileo_bands.find("5X"); std::size_t found_E5b = galileo_bands.find("7X"); - std::multimap total_map; - std::set available_prns; - std::set::iterator it; - if(found_1B != std::string::npos) - { - for(observables_iter = observablesE1B.begin(); - observables_iter != observablesE1B.end(); - observables_iter++) - { - unsigned int prn_ = observables_iter->second.PRN; - total_map.insert(std::pair(prn_, observables_iter->second)); - it = available_prns.find(prn_); - if(it == available_prns.end()) - { - available_prns.insert(prn_); - } - } - } - if(found_E5a != std::string::npos) - { - for(observables_iter = observablesE5A.begin(); - observables_iter != observablesE5A.end(); - observables_iter++) - { - unsigned int prn_ = observables_iter->second.PRN; - it = available_prns.find(prn_); - if(it == available_prns.end()) - { - available_prns.insert(prn_); - if(found_1B != std::string::npos) + std::multimap total_map; + std::set available_prns; + std::set::iterator it; + if (found_1B != std::string::npos) + { + for (observables_iter = observablesE1B.cbegin(); + observables_iter != observablesE1B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_map.insert(std::pair(prn_, observables_iter->second)); + it = available_prns.find(prn_); + if (it == available_prns.end()) { - Gnss_Synchro gs = Gnss_Synchro(); - std::string sys = "E"; - gs.System = *sys.c_str(); - std::string sig = "1B"; - std::memcpy((void*)gs.Signal, sig.c_str(), 3); - gs.PRN = prn_; - total_map.insert(std::pair(prn_, gs)); + available_prns.insert(prn_); } - } - total_map.insert(std::pair(prn_, observables_iter->second)); - } - } - if(found_E5b != std::string::npos) - { - for(observables_iter = observablesE5B.begin(); - observables_iter != observablesE5B.end(); - observables_iter++) - { - unsigned int prn_ = observables_iter->second.PRN; - it = available_prns.find(prn_); - if(it == available_prns.end()) - { - available_prns.insert(prn_); - if(found_1B != std::string::npos) + } + } + if (found_E5a != std::string::npos) + { + for (observables_iter = observablesE5A.cbegin(); + observables_iter != observablesE5A.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + it = available_prns.find(prn_); + if (it == available_prns.end()) { - Gnss_Synchro gs = Gnss_Synchro(); - std::string sys = "E"; - gs.System = *sys.c_str(); - std::string sig = "1B"; - std::memcpy((void*)gs.Signal, sig.c_str(), 3); - gs.PRN = prn_; - total_map.insert(std::pair(prn_, gs)); + available_prns.insert(prn_); + if (found_1B != std::string::npos) + { + Gnss_Synchro gs = Gnss_Synchro(); + std::string sys = "E"; + gs.System = *sys.c_str(); + std::string sig = "1B"; + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); + gs.PRN = prn_; + total_map.insert(std::pair(prn_, gs)); + } } - if(found_E5a != std::string::npos) + total_map.insert(std::pair(prn_, observables_iter->second)); + } + } + if (found_E5b != std::string::npos) + { + for (observables_iter = observablesE5B.cbegin(); + observables_iter != observablesE5B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + it = available_prns.find(prn_); + if (it == available_prns.end()) { - Gnss_Synchro gs = Gnss_Synchro(); - std::string sys = "E"; - gs.System = *sys.c_str(); - std::string sig = "5X"; - std::memcpy((void*)gs.Signal, sig.c_str(), 3); - gs.PRN = prn_; - total_map.insert(std::pair(prn_, gs)); - } - } - else - { - // if 5X is listed but empty - if(found_E5a != std::string::npos) - { - if( (total_map.count(prn_)) == 1) + available_prns.insert(prn_); + if (found_1B != std::string::npos) + { + Gnss_Synchro gs = Gnss_Synchro(); + std::string sys = "E"; + gs.System = *sys.c_str(); + std::string sig = "1B"; + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); + gs.PRN = prn_; + total_map.insert(std::pair(prn_, gs)); + } + if (found_E5a != std::string::npos) { Gnss_Synchro gs = Gnss_Synchro(); std::string sys = "E"; gs.System = *sys.c_str(); std::string sig = "5X"; - std::memcpy((void*)gs.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); gs.PRN = prn_; - total_map.insert(std::pair(prn_, gs)); + total_map.insert(std::pair(prn_, gs)); } - } - } - total_map.insert(std::pair(prn_, observables_iter->second)); - } - } - int numSatellitesObserved = available_prns.size(); - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + } + else + { + // if 5X is listed but empty + if (found_E5a != std::string::npos) + { + if ((total_map.count(prn_)) == 1) + { + Gnss_Synchro gs = Gnss_Synchro(); + std::string sys = "E"; + gs.System = *sys.c_str(); + std::string sig = "5X"; + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); + gs.PRN = prn_; + total_map.insert(std::pair(prn_, gs)); + } + } + } + total_map.insert(std::pair(prn_, observables_iter->second)); + } + } + int32_t numSatellitesObserved = available_prns.size(); + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); // Receiver clock offset (optional) //line += rightJustify(asString(clockOffset, 12), 15); line += std::string(80 - line.size(), ' '); @@ -4375,34 +8846,34 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep out << line << std::endl; std::string lineObs; - std::pair ::iterator, std::multimap::iterator> ret; - for(it = available_prns.begin(); - it != available_prns.end(); - it++) + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_prns.begin(); + it != available_prns.end(); + it++) { lineObs.clear(); lineObs += satelliteSystem["Galileo"]; - if (static_cast(*it) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(*it)); + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); ret = total_map.equal_range(*it); - for (std::multimap::iterator iter = ret.first; iter != ret.second; ++iter) + for (auto iter = ret.first; iter != ret.second; ++iter) { lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo CARRIER PHASE lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); @@ -4410,11 +8881,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo DOPPLER lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); @@ -4422,11 +8893,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo SIGNAL STRENGTH lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); @@ -4438,9 +8909,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep } -void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables) { - if(galileo_eph.e_1){} // avoid warning, not needed + if (galileo_eph.e_1) + { + } // avoid warning, not needed std::string line; boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, gps_obs_time); @@ -4449,12 +8922,12 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep //double gps_t = eph.sv_clock_correction(obs_time); double gps_t = gps_obs_time; - std::string month (timestring, 4, 2); - std::string day (timestring, 6, 2); - std::string hour (timestring, 9, 2); - std::string minutes (timestring, 11, 2); + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); - std::string year (timestring, 0, 4); + std::string year(timestring, 0, 4); line += std::string(1, '>'); line += std::string(1, ' '); line += year; @@ -4472,7 +8945,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep // Add extra 0 if seconds are < 10 if (seconds < 10) { - line +=std::string(1, '0'); + line += std::string(1, '0'); } line += Rinex_Printer::asString(seconds, 7); line += std::string(2, ' '); @@ -4482,82 +8955,82 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep //Number of satellites observed in current epoch //Get maps with observations - std::map observablesG1C; - std::map observablesE1B; - std::map observablesE5A; - std::map observablesE5B; - std::map::const_iterator observables_iter; + std::map observablesG1C; + std::map observablesE1B; + std::map observablesE5A; + std::map observablesE5B; + std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("E") == 0) && (sig_.compare("1B") == 0)) + if ((system_ == "E") && (sig_ == "1B")) { - observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("E") == 0) && (sig_.compare("5X") == 0)) + if ((system_ == "E") && (sig_ == "5X")) { - observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("E") == 0) && (sig_.compare("7X") == 0)) + if ((system_ == "E") && (sig_ == "7X")) { - observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_ == "G") && (sig_ == "1C")) { - observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); } } - std::multimap total_gal_map; - std::set available_gal_prns; - std::set::iterator it; - for(observables_iter = observablesE1B.begin(); - observables_iter != observablesE1B.end(); - observables_iter++) + std::multimap total_gal_map; + std::set available_gal_prns; + std::set::iterator it; + for (observables_iter = observablesE1B.cbegin(); + observables_iter != observablesE1B.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; - total_gal_map.insert(std::pair(prn_, observables_iter->second)); + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); it = available_gal_prns.find(prn_); - if(it == available_gal_prns.end()) + if (it == available_gal_prns.end()) { available_gal_prns.insert(prn_); } } - for(observables_iter = observablesE5A.begin(); - observables_iter != observablesE5A.end(); - observables_iter++) + for (observables_iter = observablesE5A.cbegin(); + observables_iter != observablesE5A.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; - total_gal_map.insert(std::pair(prn_, observables_iter->second)); + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); it = available_gal_prns.find(prn_); - if(it == available_gal_prns.end()) + if (it == available_gal_prns.end()) { available_gal_prns.insert(prn_); } } - for(observables_iter = observablesE5B.begin(); - observables_iter != observablesE5B.end(); - observables_iter++) + for (observables_iter = observablesE5B.cbegin(); + observables_iter != observablesE5B.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; - total_gal_map.insert(std::pair(prn_, observables_iter->second)); + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); it = available_gal_prns.find(prn_); - if(it == available_gal_prns.end()) + if (it == available_gal_prns.end()) { available_gal_prns.insert(prn_); } } - int numGalSatellitesObserved = available_gal_prns.size(); - int numGpsSatellitesObserved = observablesG1C.size(); - int numSatellitesObserved = numGalSatellitesObserved + numGpsSatellitesObserved; - line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + int32_t numGalSatellitesObserved = available_gal_prns.size(); + int32_t numGpsSatellitesObserved = observablesG1C.size(); + int32_t numSatellitesObserved = numGalSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); // Receiver clock offset (optional) //line += rightJustify(asString(clockOffset, 12), 15); @@ -4568,45 +9041,45 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep std::string s; std::string lineObs; - for(observables_iter = observablesG1C.begin(); - observables_iter != observablesG1C.end(); - observables_iter++) + for (observables_iter = observablesG1C.cbegin(); + observables_iter != observablesG1C.cend(); + observables_iter++) { lineObs.clear(); s.assign(1, observables_iter->second.System); - if(s.compare("G") == 0) lineObs += satelliteSystem["GPS"]; - if(s.compare("E") == 0) lineObs += satelliteSystem["Galileo"]; // should not happen - if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + if (s == "G") lineObs += satelliteSystem["GPS"]; + if (s == "E") lineObs += satelliteSystem["Galileo"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(observables_iter->second.PRN)); lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // PHASE - lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads / GPS_TWO_PI, 3), 14); if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // DOPPLER lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); @@ -4614,11 +9087,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // SIGNAL STRENGTH lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); @@ -4627,34 +9100,34 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep out << lineObs << std::endl; } - std::pair ::iterator, std::multimap::iterator> ret; - for(it = available_gal_prns.begin(); - it != available_gal_prns.end(); - it++) + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_gal_prns.begin(); + it != available_gal_prns.end(); + it++) { lineObs.clear(); lineObs += satelliteSystem["Galileo"]; - if (static_cast(*it) < 10) lineObs += std::string(1, '0'); - lineObs += boost::lexical_cast(static_cast(*it)); + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); ret = total_gal_map.equal_range(*it); - for (std::multimap::iterator iter = ret.first; iter != ret.second; ++iter) + for (auto iter = ret.first; iter != ret.second; ++iter) { lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); //Loss of lock indicator (LLI) - int lli = 0; // Include in the observation!! + int32_t lli = 0; // Include in the observation!! if (lli == 0) { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } // Signal Strength Indicator (SSI) - int ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo CARRIER PHASE lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); @@ -4662,11 +9135,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo DOPPLER lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); @@ -4674,11 +9147,11 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep { lineObs += std::string(1, ' '); } - else - { - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); - } - lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); // Galileo SIGNAL STRENGTH lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); @@ -4690,29 +9163,626 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep } -void Rinex_Printer::to_date_time(int gps_week, int gps_tow, int &year, int &month, int &day, int &hour, int &minute, int &second) +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables) +{ + if (galileo_eph.e_1) + { + } // avoid warning, not needed + std::string line; + + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(eph, gps_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = gps_obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(gps_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + + //Get maps with observations + std::map observablesG2S; + std::map observablesGL5; + std::map observablesE1B; + std::map observablesE5A; + std::map observablesE5B; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_ == "E") && (sig_ == "1B")) + { + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "E") && (sig_ == "5X")) + { + observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "E") && (sig_ == "7X")) + { + observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "2S")) + { + observablesG2S.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "L5")) + { + observablesGL5.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_gps_map; + std::multimap total_gal_map; + std::set available_gal_prns; + std::set available_gps_prns; + std::set::iterator it; + for (observables_iter = observablesE1B.cbegin(); + observables_iter != observablesE1B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesE5A.cbegin(); + observables_iter != observablesE5A.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesE5B.cbegin(); + observables_iter != observablesE5B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesG2S.cbegin(); + observables_iter != observablesG2S.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gps_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gps_prns.find(prn_); + if (it == available_gps_prns.end()) + { + available_gps_prns.insert(prn_); + } + } + + for (observables_iter = observablesGL5.cbegin(); + observables_iter != observablesGL5.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gps_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gps_prns.find(prn_); + if (it == available_gps_prns.end()) + { + available_gps_prns.insert(prn_); + } + } + + int32_t numGalSatellitesObserved = available_gal_prns.size(); + int32_t numGpsSatellitesObserved = available_gps_prns.size(); + int32_t numSatellitesObserved = numGalSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + std::string s; + std::string lineObs; + + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_gps_prns.begin(); + it != available_gps_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["GPS"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + ret = total_gps_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + out << lineObs << std::endl; + } + + for (it = available_gal_prns.begin(); + it != available_gal_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["Galileo"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + ret = total_gal_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + //if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& gps_cnav_eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables) +{ + if (galileo_eph.e_1) + { + } // avoid warning, not needed + if (gps_cnav_eph.d_e_eccentricity) + { + } // avoid warning, not needed + std::string line; + + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, gps_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = gps_obs_time; + + std::string month(timestring, 4, 2); + std::string day(timestring, 6, 2); + std::string hour(timestring, 9, 2); + std::string minutes(timestring, 11, 2); + + std::string year(timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(gps_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + + //Get maps with observations + std::map observablesG2S; + std::map observablesGL5; + std::map observablesG1C; + std::map observablesE1B; + std::map observablesE5A; + std::map observablesE5B; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_ == "E") && (sig_ == "1B")) + { + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "E") && (sig_ == "5X")) + { + observablesE5A.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "E") && (sig_ == "7X")) + { + observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "2S")) + { + observablesG2S.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "L5")) + { + observablesGL5.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_ == "G") && (sig_ == "1C")) + { + observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_gps_map; + std::multimap total_gal_map; + std::set available_gal_prns; + std::set available_gps_prns; + std::set::iterator it; + for (observables_iter = observablesE1B.cbegin(); + observables_iter != observablesE1B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesE5A.cbegin(); + observables_iter != observablesE5A.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesE5B.cbegin(); + observables_iter != observablesE5B.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + + for (observables_iter = observablesG1C.cbegin(); + observables_iter != observablesG1C.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gps_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gps_prns.find(prn_); + if (it == available_gps_prns.end()) + { + available_gps_prns.insert(prn_); + } + } + + for (observables_iter = observablesG2S.cbegin(); + observables_iter != observablesG2S.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gps_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gps_prns.find(prn_); + if (it == available_gps_prns.end()) + { + available_gps_prns.insert(prn_); + } + } + + for (observables_iter = observablesGL5.cbegin(); + observables_iter != observablesGL5.cend(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + total_gps_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gps_prns.find(prn_); + if (it == available_gps_prns.end()) + { + available_gps_prns.insert(prn_); + } + } + + int32_t numGalSatellitesObserved = available_gal_prns.size(); + int32_t numGpsSatellitesObserved = available_gps_prns.size(); + int32_t numSatellitesObserved = numGalSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + std::string s; + std::string lineObs; + + std::pair::iterator, std::multimap::iterator> ret; + for (it = available_gps_prns.begin(); + it != available_gps_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["GPS"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + ret = total_gps_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + out << lineObs << std::endl; + } + + for (it = available_gal_prns.begin(); + it != available_gal_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["Galileo"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += std::to_string(static_cast(*it)); + ret = total_gal_map.equal_range(*it); + for (auto iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int32_t lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + + // Signal Strength Indicator (SSI) + int32_t ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + //else + // { + // lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + // } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // Galileo SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + //if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + +void Rinex_Printer::to_date_time(int32_t gps_week, int32_t gps_tow, int& year, int& month, int& day, int& hour, int& minute, int& second) { // represents GPS time (week, TOW) in the date time format of the Gregorian calendar. // -> Leap years are considered, but leap seconds are not. - int days_per_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int32_t days_per_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // seconds in a not leap year - const int secs_per_day = 24*60*60; - const int secs_per_week = 7*secs_per_day; - const int secs_per_normal_year = 365*secs_per_day; - const int secs_per_leap_year = secs_per_normal_year + secs_per_day; + const int32_t secs_per_day = 24 * 60 * 60; + const int32_t secs_per_week = 7 * secs_per_day; + const int32_t secs_per_normal_year = 365 * secs_per_day; + const int32_t secs_per_leap_year = secs_per_normal_year + secs_per_day; // the GPS epoch is 06.01.1980 00:00, i.e. midnight 5. / 6. January 1980 // -> seconds since then - int secs_since_gps_epoch = gps_week*secs_per_week + gps_tow; + int32_t secs_since_gps_epoch = gps_week * secs_per_week + gps_tow; // find year, consider leap years bool is_leap_year; - int remaining_secs = secs_since_gps_epoch + 5*secs_per_day; - for (int y = 1980; true ; y++) + int32_t remaining_secs = secs_since_gps_epoch + 5 * secs_per_day; + for (int32_t y = 1980; true; y++) { - is_leap_year = y%4 == 0 && (y%100 != 0 || y%400 == 0); - int secs_in_year_y = is_leap_year ? secs_per_leap_year : secs_per_normal_year; + is_leap_year = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); + int32_t secs_in_year_y = is_leap_year ? secs_per_leap_year : secs_per_normal_year; if (secs_in_year_y <= remaining_secs) { @@ -4728,10 +9798,10 @@ void Rinex_Printer::to_date_time(int gps_week, int gps_tow, int &year, int &mont } // find month - for (int m = 1; true ; m++) + for (int32_t m = 1; true; m++) { - int secs_in_month_m = days_per_month[m-1]*secs_per_day; - if (is_leap_year && m == 2 ) // consider February of leap year + int32_t secs_in_month_m = days_per_month[m - 1] * secs_per_day; + if (is_leap_year && m == 2) // consider February of leap year { secs_in_month_m += secs_per_day; } @@ -4749,104 +9819,104 @@ void Rinex_Printer::to_date_time(int gps_week, int gps_tow, int &year, int &mont //std::cout << "month: m=" << m << " secs_in_month_m="<< secs_in_month_m << " remaining_secs="<< remaining_secs << std::endl; } - day = remaining_secs/secs_per_day+1; - remaining_secs = remaining_secs%secs_per_day; + day = remaining_secs / secs_per_day + 1; + remaining_secs = remaining_secs % secs_per_day; - hour = remaining_secs/(60*60); - remaining_secs = remaining_secs%(60*60); + hour = remaining_secs / (60 * 60); + remaining_secs = remaining_secs % (60 * 60); - minute = remaining_secs/60; - second = remaining_secs%60; + minute = remaining_secs / 60; + second = remaining_secs % 60; } -void Rinex_Printer::log_rinex_sbs(std::fstream& out, const Sbas_Raw_Msg& sbs_message) +//void Rinex_Printer::log_rinex_sbs(std::fstream& out, const Sbas_Raw_Msg& sbs_message) +//{ +// // line 1: PRN / EPOCH / RCVR +// std::stringstream line1; +// +// // SBAS PRN +// line1 << sbs_message.get_prn(); +// line1 << " "; +// +// // gps time of reception +// int32_t gps_week; +// double gps_sec; +// if(sbs_message.get_rx_time_obj().get_gps_time(gps_week, gps_sec)) +// { +// int32_t year; +// int32_t month; +// int32_t day; +// int32_t hour; +// int32_t minute; +// int32_t second; +// +// double gps_sec_one_digit_precicion = round(gps_sec *10)/10; // to prevent rounding towards 60.0sec in the stream output +// int32_t gps_tow = trunc(gps_sec_one_digit_precicion); +// double sub_sec = gps_sec_one_digit_precicion - double(gps_tow); +// +// to_date_time(gps_week, gps_tow, year, month, day, hour, minute, second); +// line1 << asFixWidthString(year, 2, '0') << " " << asFixWidthString(month, 2, '0') << " " << asFixWidthString(day, 2, '0') << " " << asFixWidthString(hour, 2, '0') << " " << asFixWidthString(minute, 2, '0') << " " << rightJustify(asString(double(second)+sub_sec,1),4,' '); +// } +// else +// { +// line1 << std::string(19, ' '); +// } +// line1 << " "; +// +// // band +// line1 << "L1"; +// line1 << " "; +// +// // Length of data message (bytes) +// line1 << asFixWidthString(sbs_message.get_msg().size(), 3, ' '); +// line1 << " "; +// // File-internal receiver index +// line1 << " 0"; +// line1 << " "; +// // Transmission System Identifier +// line1 << "SBA"; +// line1 << std::string(35, ' '); +// lengthCheck(line1.str()); +// out << line1.str() << std::endl; +// +// // DATA RECORD - 1 +// std::stringstream line2; +// line2 << " "; +// // Message frame identifier +// if (sbs_message.get_msg_type() < 10) line2 << " "; +// line2 << sbs_message.get_msg_type(); +// line2 << std::string(4, ' '); +// // First 18 bytes of message (hex) +// std::vector msg = sbs_message.get_msg(); +// for (size_t i = 0; i < 18 && i < msg.size(); ++i) +// { +// line2 << std::hex << std::setfill('0') << std::setw(2); +// line2 << int(msg[i]) << " "; +// } +// line2 << std::string(19, ' '); +// lengthCheck(line2.str()); +// out << line2.str() << std::endl; +// +// // DATA RECORD - 2 +// std::stringstream line3; +// line3 << std::string(7, ' '); +// // Remaining bytes of message (hex) +// for (size_t i = 18; i < 36 && i < msg.size(); ++i) +// { +// line3 << std::hex << std::setfill('0') << std::setw(2); +// line3 << int(msg[i]) << " "; +// } +// line3 << std::string(31, ' '); +// lengthCheck(line3.str()); +// out << line3.str() << std::endl; +//} + + +int32_t Rinex_Printer::signalStrength(const double snr) { - // line 1: PRN / EPOCH / RCVR - std::stringstream line1; - - // SBAS PRN - line1 << sbs_message.get_prn(); - line1 << " "; - - // gps time of reception - int gps_week; - double gps_sec; - if(sbs_message.get_rx_time_obj().get_gps_time(gps_week, gps_sec)) - { - int year; - int month; - int day; - int hour; - int minute; - int second; - - double gps_sec_one_digit_precicion = round(gps_sec *10)/10; // to prevent rounding towards 60.0sec in the stream output - int gps_tow = trunc(gps_sec_one_digit_precicion); - double sub_sec = gps_sec_one_digit_precicion - double(gps_tow); - - to_date_time(gps_week, gps_tow, year, month, day, hour, minute, second); - line1 << asFixWidthString(year, 2, '0') << " " << asFixWidthString(month, 2, '0') << " " << asFixWidthString(day, 2, '0') << " " << asFixWidthString(hour, 2, '0') << " " << asFixWidthString(minute, 2, '0') << " " << rightJustify(asString(double(second)+sub_sec,1),4,' '); - } - else - { - line1 << std::string(19, ' '); - } - line1 << " "; - - // band - line1 << "L1"; - line1 << " "; - - // Length of data message (bytes) - line1 << asFixWidthString(sbs_message.get_msg().size(), 3, ' '); - line1 << " "; - // File-internal receiver index - line1 << " 0"; - line1 << " "; - // Transmission System Identifier - line1 << "SBA"; - line1 << std::string(35, ' '); - lengthCheck(line1.str()); - out << line1.str() << std::endl; - - // DATA RECORD - 1 - std::stringstream line2; - line2 << " "; - // Message frame identifier - if (sbs_message.get_msg_type() < 10) line2 << " "; - line2 << sbs_message.get_msg_type(); - line2 << std::string(4, ' '); - // First 18 bytes of message (hex) - std::vector msg = sbs_message.get_msg(); - for (size_t i = 0; i < 18 && i < msg.size(); ++i) - { - line2 << std::hex << std::setfill('0') << std::setw(2); - line2 << int(msg[i]) << " "; - } - line2 << std::string(19, ' '); - lengthCheck(line2.str()); - out << line2.str() << std::endl; - - // DATA RECORD - 2 - std::stringstream line3; - line3 << std::string(7, ' '); - // Remaining bytes of message (hex) - for (size_t i = 18; i < 36 && i < msg.size(); ++i) - { - line3 << std::hex << std::setfill('0') << std::setw(2); - line3 << int(msg[i]) << " "; - } - line3 << std::string(31, ' '); - lengthCheck(line3.str()); - out << line3.str() << std::endl; -} - - -int Rinex_Printer::signalStrength(const double snr) -{ - int ss; - ss = int ( std::min( std::max( int (floor(snr/6)) , 1), 9) ); + int32_t ss; + ss = int(std::min(std::max(int(floor(snr / 6)), 1), 9)); return ss; } @@ -4856,7 +9926,7 @@ boost::posix_time::ptime Rinex_Printer::compute_UTC_time(const Gps_Navigation_Me // if we are processing a file -> wait to leap second to resolve the ambiguity else take the week from the local system time //: idea resolve the ambiguity with the leap second http://www.colorado.edu/geography/gcraft/notes/gps/gpseow.htm const double utc_t = nav_msg.utc_time(nav_msg.d_TOW); - boost::posix_time::time_duration t = boost::posix_time::millisec((utc_t + 604800 * static_cast(nav_msg.i_GPS_week)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((utc_t + 604800 * static_cast(nav_msg.i_GPS_week)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } @@ -4869,20 +9939,20 @@ boost::posix_time::ptime Rinex_Printer::compute_GPS_time(const Gps_Ephemeris& ep // (see Pag. 17 in http://igscb.jpl.nasa.gov/igscb/data/format/rinex300.pdf) // --??? No time correction here, since it will be done in the RINEX processor const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } -boost::posix_time::ptime Rinex_Printer::compute_GPS_time(const Gps_CNAV_Ephemeris & eph, const double obs_time) +boost::posix_time::ptime Rinex_Printer::compute_GPS_time(const Gps_CNAV_Ephemeris& eph, const double obs_time) { // The RINEX v2.11 v3.00 format uses GPS time for the observations epoch, not UTC time, thus, no leap seconds needed here. // (see Section 3 in http://igscb.jpl.nasa.gov/igscb/data/format/rinex211.txt) // (see Pag. 17 in http://igscb.jpl.nasa.gov/igscb/data/format/rinex300.pdf) // --??? No time correction here, since it will be done in the RINEX processor const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } @@ -4894,12 +9964,94 @@ boost::posix_time::ptime Rinex_Printer::compute_Galileo_time(const Galileo_Ephem // (see Pag. 17 in http://igscb.jpl.nasa.gov/igscb/data/format/rinex301.pdf) // --??? No time correction here, since it will be done in the RINEX processor double galileo_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((galileo_t + 604800 * static_cast(eph.WN_5)) * 1000); // + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((galileo_t + 604800 * static_cast(eph.WN_5)) * 1000)); // boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } +boost::posix_time::ptime Rinex_Printer::compute_UTC_time(const Glonass_Gnav_Ephemeris& eph, const double obs_time) +{ + double tod = 0.0; + double glot2utc = 3 * 3600; + double obs_time_glot = 0.0; + int32_t i = 0; + + // Get observation time in nearly GLONASS time. Correction for leap seconds done at the end + obs_time_glot = obs_time + glot2utc; + + // Get seconds of day in glonass time + tod = fmod(obs_time_glot, 86400); + + // Form date and time duration types + boost::posix_time::time_duration t1(0, 0, tod); + boost::gregorian::date d1(eph.d_yr, 1, 1); + boost::gregorian::days d2(eph.d_N_T - 1); + boost::posix_time::ptime glo_time(d1 + d2, t1); + + // Convert to utc + boost::posix_time::time_duration t2(0, 0, glot2utc); + boost::posix_time::ptime utc_time = glo_time - t2; + + // Adjust for leap second correction + for (i = 0; GLONASS_LEAP_SECONDS[i][0] > 0; i++) + { + boost::posix_time::time_duration t3(GLONASS_LEAP_SECONDS[i][3], GLONASS_LEAP_SECONDS[i][4], GLONASS_LEAP_SECONDS[i][5]); + boost::gregorian::date d3(GLONASS_LEAP_SECONDS[i][0], GLONASS_LEAP_SECONDS[i][1], GLONASS_LEAP_SECONDS[i][2]); + boost::posix_time::ptime ls_time(d3, t3); + if (utc_time >= ls_time) + { + // We subtract the leap second when going from gpst to utc, values store as negatives + utc_time = utc_time + boost::posix_time::time_duration(0, 0, GLONASS_LEAP_SECONDS[i][6]); + break; + } + } + + return utc_time; +} + +double Rinex_Printer::get_leap_second(const Glonass_Gnav_Ephemeris& eph, const double gps_obs_time) +{ + double tod = 0.0; + double glot2utc = 3 * 3600; + double obs_time_glot = 0.0; + int32_t i = 0; + double leap_second = 0; + + // Get observation time in nearly GLONASS time. Correction for leap seconds done at the end + obs_time_glot = gps_obs_time + glot2utc; + + // Get seconds of day in glonass time + tod = fmod(obs_time_glot, 86400); + + // Form date and time duration types + boost::posix_time::time_duration t1(0, 0, tod); + boost::gregorian::date d1(eph.d_yr, 1, 1); + boost::gregorian::days d2(eph.d_N_T - 1); + boost::posix_time::ptime glo_time(d1 + d2, t1); + + // Convert to utc + boost::posix_time::time_duration t2(0, 0, glot2utc); + boost::posix_time::ptime utc_time = glo_time - t2; + + // Adjust for leap second correction + for (i = 0; GLONASS_LEAP_SECONDS[i][0] > 0; i++) + { + boost::posix_time::time_duration t3(GLONASS_LEAP_SECONDS[i][3], GLONASS_LEAP_SECONDS[i][4], GLONASS_LEAP_SECONDS[i][5]); + boost::gregorian::date d3(GLONASS_LEAP_SECONDS[i][0], GLONASS_LEAP_SECONDS[i][1], GLONASS_LEAP_SECONDS[i][2]); + boost::posix_time::ptime ls_time(d3, t3); + if (utc_time >= ls_time) + { + // We subtract the leap second when going from gpst to utc + leap_second = fabs(GLONASS_LEAP_SECONDS[i][6]); + break; + } + } + + return leap_second; +} + + /* enum RINEX_enumMarkerType { diff --git a/src/algorithms/PVT/libs/rinex_printer.h b/src/algorithms/PVT/libs/rinex_printer.h index 0d1dc940e..331b35946 100644 --- a/src/algorithms/PVT/libs/rinex_printer.h +++ b/src/algorithms/PVT/libs/rinex_printer.h @@ -25,7 +25,7 @@ * \author Carles Fernandez Prades, 2011. cfernandez(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,7 +43,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -51,20 +51,21 @@ #ifndef GNSS_SDR_RINEX_PRINTER_H_ #define GNSS_SDR_RINEX_PRINTER_H_ -#include -#include -#include -#include // for stringstream -#include // for setprecision -#include -#include -#include "gps_navigation_message.h" -#include "gps_cnav_navigation_message.h" -#include "galileo_navigation_message.h" -#include "sbas_telemetry_data.h" +#include "GLONASS_L1_L2_CA.h" #include "GPS_L1_CA.h" #include "Galileo_E1.h" +#include "galileo_navigation_message.h" +#include "glonass_gnav_navigation_message.h" #include "gnss_synchro.h" +#include "gps_cnav_navigation_message.h" +#include "gps_navigation_message.h" +#include +#include +#include +#include // for setprecision +#include +#include // for stringstream +#include class Sbas_Raw_Msg; @@ -76,174 +77,314 @@ class Rinex_Printer { public: /*! - * \brief Default constructor. Creates GPS Navigation and Observables RINEX files and their headers + * \brief Default constructor. Creates GNSS Navigation and Observables RINEX files and their headers */ - Rinex_Printer(int version = 0); + Rinex_Printer(int version = 0, const std::string& base_path = "."); /*! - * \brief Default destructor. Closes GPS Navigation and Observables RINEX files + * \brief Default destructor. Closes GNSS Navigation and Observables RINEX files */ ~Rinex_Printer(); - std::fstream obsFile ; // & eph_map); + void log_rinex_nav(std::fstream& out, const std::map& eph_map); /*! * \brief Writes data from the GPS L2 navigation message into the RINEX file */ - void log_rinex_nav(std::fstream & out, const std::map & eph_map); + void log_rinex_nav(std::fstream& out, const std::map& eph_map); /*! * \brief Writes data from the Galileo navigation message into the RINEX file */ - void log_rinex_nav(std::fstream & out, const std::map & eph_map); + void log_rinex_nav(std::fstream& out, const std::map& eph_map); /*! * \brief Writes data from the Mixed (GPS/Galileo) navigation message into the RINEX file */ - void log_rinex_nav(std::fstream & out, const std::map & gps_eph_map, const std::map & galileo_eph_map); + void log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& galileo_eph_map); + + /*! + * \brief Writes data from the Mixed (GPS/Galileo) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream& out, const std::map& gps_cnav_eph_map, const std::map& galileo_eph_map); + + /*! + * \brief Writes data from the GLONASS GNAV navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream& out, const std::map& eph_map); + + /*! + * \brief Writes data from the Mixed (GPS/GLONASS GNAV) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& glonass_gnav_eph_map); + + /*! + * \brief Writes data from the Mixed (GPS/GLONASS GNAV) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream& out, const std::map& gps_cnav_eph_map, const std::map& glonass_gnav_eph_map); + + /*! + * \brief Writes data from the Mixed (Galileo/ GLONASS GNAV) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream& out, const std::map& galileo_eph_map, const std::map& glonass_gnav_eph_map); /*! * \brief Writes GPS L1 observables into the RINEX file */ - void log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, double obs_time, const std::map & observables); + void log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, double obs_time, const std::map& observables); /*! * \brief Writes GPS L2 observables into the RINEX file */ - void log_rinex_obs(std::fstream & out, const Gps_CNAV_Ephemeris & eph, double obs_time, const std::map & observables); + void log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& eph, double obs_time, const std::map& observables); /*! * \brief Writes dual frequency GPS L1 and L2 observables into the RINEX file */ - void log_rinex_obs(std::fstream & out, const Gps_Ephemeris & eph, const Gps_CNAV_Ephemeris & eph_cnav, double obs_time, const std::map & observables); + void log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, const Gps_CNAV_Ephemeris& eph_cnav, double obs_time, const std::map& observables); /*! * \brief Writes Galileo observables into the RINEX file. Example: galileo_bands("1B"), galileo_bands("1B 5X"), galileo_bands("5X"), ... Default: "1B". */ - void log_rinex_obs(std::fstream & out, const Galileo_Ephemeris & eph, double obs_time, const std::map & observables, const std::string galileo_bands = "1B"); + void log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& eph, double obs_time, const std::map& observables, const std::string& galileo_bands = "1B"); /*! * \brief Writes Mixed GPS / Galileo observables into the RINEX file */ - void log_rinex_obs(std::fstream & out, const Gps_Ephemeris & gps_eph, const Galileo_Ephemeris & galileo_eph, const double gps_obs_time, const std::map & observables); + void log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Galileo_Ephemeris& galileo_eph, const double gps_obs_time, const std::map& observables); + + /*! + * \brief Writes Mixed GPS / Galileo observables into the RINEX file + */ + void log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables); + + /*! + * \brief Writes Mixed GPS / Galileo observables into the RINEX file + */ + void log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& gps_cnav_eph, const Galileo_Ephemeris& galileo_eph, double gps_obs_time, const std::map& observables); + + /*! + * \brief Writes GLONASS GNAV observables into the RINEX file. Example: glonass_bands("1C"), galileo_bands("1B 5X"), galileo_bands("5X"), ... Default: "1B". + */ + void log_rinex_obs(std::fstream& out, const Glonass_Gnav_Ephemeris& eph, double obs_time, const std::map& observables, const std::string& glonass_bands = "1C"); + + /*! + * \brief Writes Mixed GPS L1 C/A - GLONASS observables into the RINEX file + */ + void log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double gps_obs_time, const std::map& observables); + + /*! + * \brief Writes Mixed GPS L2C - GLONASS observables into the RINEX file + */ + void log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& gps_cnav_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double gps_obs_time, const std::map& observables); + + /*! + * \brief Writes Mixed Galileo/GLONASS observables into the RINEX file + */ + void log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& galileo_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double gps_obs_time, const std::map& observables); /*! * \brief Represents GPS time in the date time format. Leap years are considered, but leap seconds are not. */ - void to_date_time(int gps_week, int gps_tow, int & year, int & month, int & day, int & hour, int & minute, int & second); + void to_date_time(int gps_week, int gps_tow, int& year, int& month, int& day, int& hour, int& minute, int& second); /*! * \brief Writes raw SBAS messages into the RINEX file */ - void log_rinex_sbs(std::fstream & out, const Sbas_Raw_Msg & sbs_message); + //void log_rinex_sbs(std::fstream & out, const Sbas_Raw_Msg & sbs_message); - void update_nav_header(std::fstream & out, const Gps_Utc_Model & gps_utc, const Gps_Iono & gps_iono); + void update_nav_header(std::fstream& out, const Gps_Utc_Model& gps_utc, const Gps_Iono& gps_iono); - void update_nav_header(std::fstream & out, const Gps_CNAV_Utc_Model & utc_model, const Gps_CNAV_Iono & iono); + void update_nav_header(std::fstream& out, const Gps_CNAV_Utc_Model& utc_model, const Gps_CNAV_Iono& iono); - void update_nav_header(std::fstream & out, const Gps_Iono & gps_iono, const Gps_Utc_Model & gps_utc_model, const Galileo_Iono & galileo_iono, const Galileo_Utc_Model & galileo_utc_model, const Galileo_Almanac& galileo_almanac); + void update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model); - void update_nav_header(std::fstream & out, const Galileo_Iono & galileo_iono, const Galileo_Utc_Model & utc_model, const Galileo_Almanac & galileo_almanac); + void update_nav_header(std::fstream& out, const Gps_CNAV_Utc_Model& utc_model, const Gps_CNAV_Iono& iono, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model); - void update_obs_header(std::fstream & out, const Gps_Utc_Model & utc_model); + void update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& utc_model); - void update_obs_header(std::fstream & out, const Gps_CNAV_Utc_Model & utc_model); + void update_nav_header(std::fstream& out, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac); - void update_obs_header(std::fstream & out, const Galileo_Utc_Model & galileo_utc_model); + void update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac); - std::map satelliteSystem; // observationType; // observationCode; // satelliteSystem; // observationType; // observationCode; // 0.87654E-0004 or -0.1234E00005. */ - inline std::string & sci2for(std::string & aStr, - const std::string::size_type startPos = 0, - const std::string::size_type length = std::string::npos, - const std::string::size_type expLen = 3, - const bool checkSwitch = true); + inline std::string& sci2for(std::string& aStr, + const std::string::size_type startPos = 0, + const std::string::size_type length = std::string::npos, + const std::string::size_type expLen = 3, + const bool checkSwitch = true); /* @@ -389,10 +534,10 @@ private: * that check. * @return a string containing \a d in FORTRAN notation. */ - inline std::string doub2for(const double & d, - const std::string::size_type length, - const std::string::size_type expLen, - const bool checkSwitch = true); + inline std::string doub2for(const double& d, + const std::string::size_type length, + const std::string::size_type expLen, + const bool checkSwitch = true); /* @@ -400,9 +545,9 @@ private: * @param s string containing a number. * @return double representation of string. */ - inline double asDouble(const std::string & s) + inline double asDouble(const std::string& s) { - return strtod(s.c_str(), 0); + return strtod(s.c_str(), nullptr); } @@ -411,11 +556,11 @@ private: /* * Convert a string to an integer. * @param s string containing a number. - * @return long integer representation of string. + * @return int64_t integer representation of string. */ - inline long asInt(const std::string & s) + inline int64_t asInt(const std::string& s) { - return strtol(s.c_str(), 0, 10); + return strtol(s.c_str(), nullptr, 10); } @@ -426,7 +571,7 @@ private: * @return string representation of \a x. */ inline std::string asString(const double x, - const std::string::size_type precision = 17); + const std::string::size_type precision = 17); /* @@ -436,7 +581,7 @@ private: * @return string representation of \a x. */ inline std::string asString(const long double x, - const std::string::size_type precision = 21); + const std::string::size_type precision = 21); /* @@ -445,26 +590,26 @@ private: * @param x object to turn into a string. * @return string representation of \a x. */ - template inline std::string asString(const X x); + template + inline std::string asString(const X x); inline std::string asFixWidthString(const int x, const int width, char fill_digit); }; - // Implementation of inline functions (modified versions from GPSTk http://www.gpstk.org) -inline std::string & Rinex_Printer::leftJustify(std::string & s, - const std::string::size_type length, - const char pad) +inline std::string& Rinex_Printer::leftJustify(std::string& s, + const std::string::size_type length, + const char pad) { - if(length < s.length()) + if (length < s.length()) { s = s.substr(0, length); } else { - s.append(length-s.length(), pad); + s.append(length - s.length(), pad); } return s; } @@ -472,27 +617,26 @@ inline std::string & Rinex_Printer::leftJustify(std::string & s, // if the string is bigger than length, truncate it from the left. // otherwise, add pad characters to its left. -inline std::string & Rinex_Printer::rightJustify(std::string & s, - const std::string::size_type length, - const char pad) +inline std::string& Rinex_Printer::rightJustify(std::string& s, + const std::string::size_type length, + const char pad) { - if(length < s.length()) + if (length < s.length()) { - s = s.substr(s.length()-length, std::string::npos); + s = s.substr(s.length() - length, std::string::npos); } else { - s.insert((std::string::size_type)0, length-s.length(), pad); + s.insert(static_cast(0), length - s.length(), pad); } return s; } - -inline std::string Rinex_Printer::doub2for(const double & d, - const std::string::size_type length, - const std::string::size_type expLen, - const bool checkSwitch) +inline std::string Rinex_Printer::doub2for(const double& d, + const std::string::size_type length, + const std::string::size_type expLen, + const bool checkSwitch) { short exponentLength = expLen; @@ -507,11 +651,11 @@ inline std::string Rinex_Printer::doub2for(const double & d, } -inline std::string Rinex_Printer::doub2sci(const double & d, - const std::string::size_type length, - const std::string::size_type expLen, - const bool showSign, - const bool checkSwitch) +inline std::string Rinex_Printer::doub2sci(const double& d, + const std::string::size_type length, + const std::string::size_type expLen, + const bool showSign, + const bool checkSwitch) { std::string toReturn; short exponentLength = expLen; @@ -538,19 +682,19 @@ inline std::string Rinex_Printer::doub2sci(const double & d, } -inline std::string & Rinex_Printer::sci2for(std::string & aStr, - const std::string::size_type startPos, - const std::string::size_type length, - const std::string::size_type expLen, - const bool checkSwitch) +inline std::string& Rinex_Printer::sci2for(std::string& aStr, + const std::string::size_type startPos, + const std::string::size_type length, + const std::string::size_type expLen, + const bool checkSwitch) { std::string::size_type idx = aStr.find('.', startPos); int expAdd = 0; std::string exp; - long iexp; + int64_t iexp; //If checkSwitch is false, always redo the exponential. Otherwise, //set it to false. - bool redoexp =! checkSwitch; + bool redoexp = !checkSwitch; // Check for decimal place within specified boundaries if ((idx <= 0) || (idx >= (startPos + length - expLen - 1))) @@ -602,35 +746,34 @@ inline std::string & Rinex_Printer::sci2for(std::string & aStr, if (iexp < 0) { aStr += "-"; - iexp -= iexp*2; + iexp -= iexp * 2; } else aStr += "+"; - aStr += Rinex_Printer::rightJustify(asString(iexp),expLen,'0'); + aStr += Rinex_Printer::rightJustify(asString(iexp), expLen, '0'); } // if the number is positive, append a space // (if it's negative, there's a leading '-' if (aStr[0] == '.') { - aStr.insert((std::string::size_type)0, 1, ' '); + aStr.insert(static_cast(0), 1, ' '); } //If checkSwitch is false, add on one leading zero to the string if (!checkSwitch) { - aStr.insert((std::string::size_type)1, 1, '0'); + aStr.insert(static_cast(1), 1, '0'); } return aStr; } // end sci2for - inline std::string asString(const long double x, const std::string::size_type precision) { std::ostringstream ss; - ss << std::fixed << std::setprecision(precision) << x ; + ss << std::fixed << std::setprecision(precision) << x; return ss.str(); } @@ -651,9 +794,9 @@ inline std::string Rinex_Printer::asFixWidthString(const int x, const int width, } -inline long asInt(const std::string & s) +inline int64_t asInt(const std::string& s) { - return strtol(s.c_str(), 0, 10); + return strtol(s.c_str(), nullptr, 10); } @@ -661,16 +804,17 @@ inline int Rinex_Printer::toInt(std::string bitString, int sLength) { int tempInt; int num = 0; - for(int i = 0; i < sLength; i++) - { - tempInt = bitString[i]-'0'; - num |= (1 << (sLength - 1 - i)) * tempInt; - } + for (int i = 0; i < sLength; i++) + { + tempInt = bitString[i] - '0'; + num |= (1 << (sLength - 1 - i)) * tempInt; + } return num; } -template inline std::string Rinex_Printer::asString(const X x) +template +inline std::string Rinex_Printer::asString(const X x) { std::ostringstream ss; ss << x; diff --git a/src/algorithms/PVT/libs/rtcm_printer.cc b/src/algorithms/PVT/libs/rtcm_printer.cc index be889e406..da32c0e9b 100644 --- a/src/algorithms/PVT/libs/rtcm_printer.cc +++ b/src/algorithms/PVT/libs/rtcm_printer.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,80 +26,124 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "rtcm_printer.h" -#include -#include -#include -#include // for O_RDWR -#include // for tcgetattr -#include +#include +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem #include +#include +#include // for O_RDWR +#include +#include // for tcgetattr +#include + using google::LogMessage; -Rtcm_Printer::Rtcm_Printer(std::string filename, bool flag_rtcm_server, bool flag_rtcm_tty_port, unsigned short rtcm_tcp_port, unsigned short rtcm_station_id, std::string rtcm_dump_devname, bool time_tag_name) +Rtcm_Printer::Rtcm_Printer(const std::string& filename, bool flag_rtcm_file_dump, bool flag_rtcm_server, bool flag_rtcm_tty_port, uint16_t rtcm_tcp_port, uint16_t rtcm_station_id, const std::string& rtcm_dump_devname, bool time_tag_name, const std::string& base_path) { - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); + boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); + tm timeinfo = boost::posix_time::to_tm(pt); + d_rtcm_file_dump = flag_rtcm_file_dump; + rtcm_base_path = base_path; + if (d_rtcm_file_dump) + { + boost::filesystem::path full_path(boost::filesystem::current_path()); + const boost::filesystem::path p(rtcm_base_path); + if (!boost::filesystem::exists(p)) + { + std::string new_folder; + for (auto& folder : boost::filesystem::path(rtcm_base_path)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + std::cout << "Could not create the " << new_folder << " folder." << std::endl; + rtcm_base_path = full_path.string(); + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + } + else + { + rtcm_base_path = p.string(); + } + if (rtcm_base_path != ".") + { + std::cout << "RTCM binary file will be stored at " << rtcm_base_path << std::endl; + } + + rtcm_base_path = rtcm_base_path + boost::filesystem::path::preferred_separator; + } if (time_tag_name) { std::stringstream strm0; - const int year = timeinfo->tm_year - 100; + const int32_t year = timeinfo.tm_year - 100; strm0 << year; - const int month = timeinfo->tm_mon + 1; - if(month < 10) + const int32_t month = timeinfo.tm_mon + 1; + if (month < 10) { strm0 << "0"; } strm0 << month; - const int day = timeinfo->tm_mday; - if(day < 10) + const int32_t day = timeinfo.tm_mday; + if (day < 10) { strm0 << "0"; } strm0 << day << "_"; - const int hour = timeinfo->tm_hour; - if(hour < 10) + const int32_t hour = timeinfo.tm_hour; + if (hour < 10) { strm0 << "0"; } strm0 << hour; - const int min = timeinfo->tm_min; - if(min < 10) + const int32_t min = timeinfo.tm_min; + if (min < 10) { strm0 << "0"; } strm0 << min; - const int sec = timeinfo->tm_sec; - if(sec < 10) + const int32_t sec = timeinfo.tm_sec; + if (sec < 10) { strm0 << "0"; } strm0 << sec; - rtcm_filename = filename + "_" + strm0.str() + ".rtcm"; + rtcm_filename = filename + "_" + strm0.str() + ".rtcm"; } else { rtcm_filename = filename + ".rtcm"; } - - rtcm_file_descriptor.open(rtcm_filename.c_str(), std::ios::out); - if (rtcm_file_descriptor.is_open()) + rtcm_filename = rtcm_base_path + rtcm_filename; + if (d_rtcm_file_dump) { - DLOG(INFO) << "RTCM printer writing on " << rtcm_filename.c_str(); + rtcm_file_descriptor.open(rtcm_filename.c_str(), std::ios::out); + if (rtcm_file_descriptor.is_open()) + { + DLOG(INFO) << "RTCM printer writing on " << rtcm_filename.c_str(); + } + else + { + std::cout << "File " << rtcm_filename << "cannot be saved. Wrong permissions?" << std::endl; + } } - rtcm_devname = rtcm_dump_devname; + rtcm_devname = std::move(rtcm_dump_devname); if (flag_rtcm_tty_port == true) { rtcm_dev_descriptor = init_serial(rtcm_devname.c_str()); @@ -118,7 +162,7 @@ Rtcm_Printer::Rtcm_Printer(std::string filename, bool flag_rtcm_server, bool fla rtcm = std::make_shared(port); - if(flag_rtcm_server) + if (flag_rtcm_server) { rtcm->run_server(); } @@ -127,36 +171,36 @@ Rtcm_Printer::Rtcm_Printer(std::string filename, bool flag_rtcm_server, bool fla Rtcm_Printer::~Rtcm_Printer() { - if(rtcm->is_server_running()) + if (rtcm->is_server_running()) { try - { + { rtcm->stop_server(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { + } + catch (const std::exception& ex) + { LOG(WARNING) << "STD exception: " << ex.what(); - } + } } if (rtcm_file_descriptor.is_open()) { - long pos; + int64_t pos; pos = rtcm_file_descriptor.tellp(); rtcm_file_descriptor.close(); if (pos == 0) { - if(remove(rtcm_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary RTCM file"; + if (remove(rtcm_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary RTCM file"; } } close_serial(); } -bool Rtcm_Printer::Print_Rtcm_MT1001(const Gps_Ephemeris& gps_eph, double obs_time, const std::map & observables) +bool Rtcm_Printer::Print_Rtcm_MT1001(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables) { std::string m1001 = rtcm->print_MT1001(gps_eph, obs_time, observables, station_id); Rtcm_Printer::Print_Message(m1001); @@ -164,7 +208,7 @@ bool Rtcm_Printer::Print_Rtcm_MT1001(const Gps_Ephemeris& gps_eph, double obs_ti } -bool Rtcm_Printer::Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map & observables) +bool Rtcm_Printer::Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables) { std::string m1002 = rtcm->print_MT1002(gps_eph, obs_time, observables, station_id); Rtcm_Printer::Print_Message(m1002); @@ -172,7 +216,7 @@ bool Rtcm_Printer::Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_ti } -bool Rtcm_Printer::Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables) +bool Rtcm_Printer::Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map& observables) { std::string m1003 = rtcm->print_MT1003(gps_eph, cnav_eph, obs_time, observables, station_id); Rtcm_Printer::Print_Message(m1003); @@ -180,7 +224,7 @@ bool Rtcm_Printer::Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNA } -bool Rtcm_Printer::Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables) +bool Rtcm_Printer::Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map& observables) { std::string m1003 = rtcm->print_MT1004(gps_eph, cnav_eph, obs_time, observables, station_id); Rtcm_Printer::Print_Message(m1003); @@ -188,7 +232,39 @@ bool Rtcm_Printer::Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNA } -bool Rtcm_Printer::Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph) +bool Rtcm_Printer::Print_Rtcm_MT1009(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables) +{ + std::string m1009 = rtcm->print_MT1009(glonass_gnav_eph, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1009); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables) +{ + std::string m1010 = rtcm->print_MT1010(glonass_gnav_eph, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1010); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables) +{ + std::string m1011 = rtcm->print_MT1011(glonass_gnav_ephL1, glonass_gnav_ephL2, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1011); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables) +{ + std::string m1012 = rtcm->print_MT1012(glonass_gnav_ephL1, glonass_gnav_ephL2, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1012); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1019(const Gps_Ephemeris& gps_eph) { std::string m1019 = rtcm->print_MT1019(gps_eph); Rtcm_Printer::Print_Message(m1019); @@ -196,7 +272,15 @@ bool Rtcm_Printer::Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph) } -bool Rtcm_Printer::Print_Rtcm_MT1045(const Galileo_Ephemeris & gal_eph) +bool Rtcm_Printer::Print_Rtcm_MT1020(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + std::string m1020 = rtcm->print_MT1020(glonass_gnav_eph, glonass_gnav_utc_model); + Rtcm_Printer::Print_Message(m1020); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1045(const Galileo_Ephemeris& gal_eph) { std::string m1045 = rtcm->print_MT1045(gal_eph); Rtcm_Printer::Print_Message(m1045); @@ -204,45 +288,46 @@ bool Rtcm_Printer::Print_Rtcm_MT1045(const Galileo_Ephemeris & gal_eph) } -bool Rtcm_Printer::Print_Rtcm_MSM(unsigned int msm_number, const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +bool Rtcm_Printer::Print_Rtcm_MSM(uint32_t msm_number, const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { std::string msm; - if(msm_number == 1) + if (msm_number == 1) { - msm = rtcm->print_MSM_1(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_1(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 2) + else if (msm_number == 2) { - msm = rtcm->print_MSM_2(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_2(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 3) + else if (msm_number == 3) { - msm = rtcm->print_MSM_3(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_3(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 4) + else if (msm_number == 4) { - msm = rtcm->print_MSM_4(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_4(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 5) + else if (msm_number == 5) { - msm = rtcm->print_MSM_5(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_5(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 6) + else if (msm_number == 6) { - msm = rtcm->print_MSM_6(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_6(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } - else if(msm_number == 7) + else if (msm_number == 7) { - msm = rtcm->print_MSM_7(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_7(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else { @@ -254,26 +339,26 @@ bool Rtcm_Printer::Print_Rtcm_MSM(unsigned int msm_number, const Gps_Ephemeris & } -int Rtcm_Printer::init_serial(std::string serial_device) +int Rtcm_Printer::init_serial(const std::string& serial_device) { /* * Opens the serial device and sets the default baud rate for a RTCM transmission (9600,8,N,1) */ - int fd = 0; + int32_t fd = 0; struct termios options; - long BAUD; - long DATABITS; - long STOPBITS; - long PARITYON; - long PARITY; + int64_t BAUD; + int64_t DATABITS; + int64_t STOPBITS; + int64_t PARITYON; + int64_t PARITY; - fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC); if (fd == -1) return fd; // failed to open TTY port - if(fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O - tcgetattr(fd, &options); // read serial port options + if (fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O + tcgetattr(fd, &options); // read serial port options - BAUD = B9600; + BAUD = B9600; //BAUD = B38400; DATABITS = CS8; STOPBITS = 0; @@ -300,26 +385,29 @@ void Rtcm_Printer::close_serial() } -bool Rtcm_Printer::Print_Message(const std::string & message) +bool Rtcm_Printer::Print_Message(const std::string& message) { //write to file - try - { - rtcm_file_descriptor << message << std::endl; - } - catch(std::exception ex) - { - DLOG(INFO) << "RTCM printer can not write on output file" << rtcm_filename.c_str(); - return false; - } + if (d_rtcm_file_dump) + { + try + { + rtcm_file_descriptor << message << std::endl; + } + catch (const std::exception& ex) + { + DLOG(INFO) << "RTCM printer cannot write on the output file " << rtcm_filename.c_str(); + return false; + } + } //write to serial device if (rtcm_dev_descriptor != -1) { - if(write(rtcm_dev_descriptor, message.c_str(), message.length()) == -1) + if (write(rtcm_dev_descriptor, message.c_str(), message.length()) == -1) { - DLOG(INFO) << "RTCM printer cannot write on serial device" << rtcm_devname.c_str(); - std::cout << "RTCM printer cannot write on serial device" << rtcm_devname.c_str() << std::endl; + DLOG(INFO) << "RTCM printer cannot write on serial device " << rtcm_devname.c_str(); + std::cout << "RTCM printer cannot write on serial device " << rtcm_devname.c_str() << std::endl; return false; } } @@ -334,19 +422,25 @@ std::string Rtcm_Printer::print_MT1005_test() } -unsigned int Rtcm_Printer::lock_time(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro) +uint32_t Rtcm_Printer::lock_time(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { return rtcm->lock_time(eph, obs_time, gnss_synchro); } -unsigned int Rtcm_Printer::lock_time(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro) +uint32_t Rtcm_Printer::lock_time(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { return rtcm->lock_time(eph, obs_time, gnss_synchro); } -unsigned int Rtcm_Printer::lock_time(const Galileo_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro) +uint32_t Rtcm_Printer::lock_time(const Galileo_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + return rtcm->lock_time(eph, obs_time, gnss_synchro); +} + + +uint32_t Rtcm_Printer::lock_time(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { return rtcm->lock_time(eph, obs_time, gnss_synchro); } diff --git a/src/algorithms/PVT/libs/rtcm_printer.h b/src/algorithms/PVT/libs/rtcm_printer.h index 0b59001e6..aca7197bb 100644 --- a/src/algorithms/PVT/libs/rtcm_printer.h +++ b/src/algorithms/PVT/libs/rtcm_printer.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,10 +34,10 @@ #ifndef GNSS_SDR_RTCM_PRINTER_H_ #define GNSS_SDR_RTCM_PRINTER_H_ -#include // std::ofstream -#include // std::cout -#include // std::shared_ptr #include "rtcm.h" +#include // std::ofstream +#include // std::shared_ptr + /*! * \brief This class provides a implementation of a subset of the RTCM Standard 10403.2 messages @@ -48,47 +48,112 @@ public: /*! * \brief Default constructor. */ - Rtcm_Printer(std::string filename, bool flag_rtcm_server, bool flag_rtcm_tty_port, unsigned short rtcm_tcp_port, unsigned short rtcm_station_id, std::string rtcm_dump_filename, bool time_tag_name = true); + Rtcm_Printer(const std::string& filename, bool flag_rtcm_file_dump, bool flag_rtcm_server, bool flag_rtcm_tty_port, uint16_t rtcm_tcp_port, uint16_t rtcm_station_id, const std::string& rtcm_dump_filename, bool time_tag_name = true, const std::string& base_path = "."); /*! * \brief Default destructor. */ ~Rtcm_Printer(); - bool Print_Rtcm_MT1001(const Gps_Ephemeris& gps_eph, double obs_time, const std::map & observables); - bool Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map & observables); - bool Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables); - bool Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables); - bool Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph); //& observables); + bool Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables); + bool Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map& observables); + bool Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map& observables); + /*! + * \brief Prints L1-Only GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1009(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables); + /*! + * \brief Prints Extended L1-Only GLONASS RTK Observables + * \details This GLONASS message type is used when only L1 data is present and bandwidth is very tight, often 1012 is used in such cases. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables); + /*! + * \brief Prints L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_ephL1 GLONASS L1 GNAV Broadcast Ephemeris for satellite + * \param glonass_gnav_ephL2 GLONASS L2 GNAV Broadcast Ephemeris for satellite + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables); + /*! + * \brief Prints Extended L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is the most common observational message type, with L1/L2/SNR content. This is one of the most common messages found. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_ephL1 GLONASS L1 GNAV Broadcast Ephemeris for satellite + * \param glonass_gnav_ephL2 GLONASS L2 GNAV Broadcast Ephemeris for satellite + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables); - bool Print_Rtcm_MSM(unsigned int msm_number, const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + bool Print_Rtcm_MT1019(const Gps_Ephemeris& gps_eph); //& observables, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); + + std::string print_MT1005_test(); // rtcm; - bool Print_Message(const std::string & message); + bool Print_Message(const std::string& message); + bool d_rtcm_file_dump; }; #endif diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc new file mode 100644 index 000000000..b304881ff --- /dev/null +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -0,0 +1,963 @@ +/*! + * \file rtklib_solver.cc + * \brief PVT solver based on rtklib library functions adapted to the GNSS-SDR + * data flow and structures + * \authors
    + *
  • 2017, Javier Arribas + *
  • 2017, Carles Fernandez + *
  • 2007-2013, T. Takasu + *
+ * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * -----------------------------------------------------------------------*/ + +#include "rtklib_solver.h" +#include "GLONASS_L1_L2_CA.h" +#include "GPS_L1_CA.h" +#include "Galileo_E1.h" +#include "rtklib_conversions.h" +#include "rtklib_solution.h" +#include +#include +#include + + +using google::LogMessage; + +rtklib_solver::rtklib_solver(int nchannels, std::string dump_filename, bool flag_dump_to_file, bool flag_dump_to_mat, const rtk_t &rtk) +{ + // init empty ephemeris for all the available GNSS channels + d_nchannels = nchannels; + d_dump_filename = std::move(dump_filename); + d_flag_dump_enabled = flag_dump_to_file; + d_flag_dump_mat_enabled = flag_dump_to_mat; + count_valid_position = 0; + this->set_averaging_flag(false); + rtk_ = rtk; + for (double &i : dop_) i = 0.0; + pvt_sol = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, '0', '0', '0', 0, 0, 0}; + ssat_t ssat0 = {0, 0, {0.0}, {0.0}, {0.0}, {'0'}, {'0'}, {'0'}, {'0'}, {'0'}, {}, {}, {}, {}, 0.0, 0.0, 0.0, 0.0, {{{0, 0}}, {{0, 0}}}, {{}, {}}}; + for (auto &i : pvt_ssat) + { + i = ssat0; + } + // ############# ENABLE DATA FILE LOG ################# + if (d_flag_dump_enabled == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "PVT lib dump enabled Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception opening RTKLIB dump file " << e.what(); + } + } + } +} + +bool rtklib_solver::save_matfile() +{ + // READ DUMP FILE + std::string dump_filename = d_dump_filename; + std::ifstream::pos_type size; + int32_t number_of_double_vars = 21; + int32_t number_of_uint32_vars = 2; + int32_t number_of_uint8_vars = 3; + int32_t number_of_float_vars = 2; + int32_t epoch_size_bytes = sizeof(double) * number_of_double_vars + + sizeof(uint32_t) * number_of_uint32_vars + + sizeof(uint8_t) * number_of_uint8_vars + + sizeof(float) * number_of_float_vars; + std::ifstream dump_file; + std::cout << "Generating .mat file for " << dump_filename << std::endl; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return false; + } + // count number of epochs and rewind + int64_t num_epoch = 0LL; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return false; + } + + auto *TOW_at_current_symbol_ms = new uint32_t[num_epoch]; + auto *week = new uint32_t[num_epoch]; + auto *RX_time = new double[num_epoch]; + auto *user_clk_offset = new double[num_epoch]; + auto *pos_x = new double[num_epoch]; + auto *pos_y = new double[num_epoch]; + auto *pos_z = new double[num_epoch]; + auto *vel_x = new double[num_epoch]; + auto *vel_y = new double[num_epoch]; + auto *vel_z = new double[num_epoch]; + auto *cov_xx = new double[num_epoch]; + auto *cov_yy = new double[num_epoch]; + auto *cov_zz = new double[num_epoch]; + auto *cov_xy = new double[num_epoch]; + auto *cov_yz = new double[num_epoch]; + auto *cov_zx = new double[num_epoch]; + auto *latitude = new double[num_epoch]; + auto *longitude = new double[num_epoch]; + auto *height = new double[num_epoch]; + auto *valid_sats = new uint8_t[num_epoch]; + auto *solution_status = new uint8_t[num_epoch]; + auto *solution_type = new uint8_t[num_epoch]; + auto *AR_ratio_factor = new float[num_epoch]; + auto *AR_ratio_threshold = new float[num_epoch]; + auto *gdop = new double[num_epoch]; + auto *pdop = new double[num_epoch]; + auto *hdop = new double[num_epoch]; + auto *vdop = new double[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&TOW_at_current_symbol_ms[i]), sizeof(uint32_t)); + dump_file.read(reinterpret_cast(&week[i]), sizeof(uint32_t)); + dump_file.read(reinterpret_cast(&RX_time[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&user_clk_offset[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&pos_x[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&pos_y[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&pos_z[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&vel_x[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&vel_y[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&vel_z[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_xx[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_yy[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_zz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_xy[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_yz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&cov_zx[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&latitude[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&longitude[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&height[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&valid_sats[i]), sizeof(uint8_t)); + dump_file.read(reinterpret_cast(&solution_status[i]), sizeof(uint8_t)); + dump_file.read(reinterpret_cast(&solution_type[i]), sizeof(uint8_t)); + dump_file.read(reinterpret_cast(&AR_ratio_factor[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&AR_ratio_threshold[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&gdop[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&pdop[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&hdop[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&vdop[i]), sizeof(double)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] TOW_at_current_symbol_ms; + delete[] week; + delete[] RX_time; + delete[] user_clk_offset; + delete[] pos_x; + delete[] pos_y; + delete[] pos_z; + delete[] vel_x; + delete[] vel_y; + delete[] vel_z; + delete[] cov_xx; + delete[] cov_yy; + delete[] cov_zz; + delete[] cov_xy; + delete[] cov_yz; + delete[] cov_zx; + delete[] latitude; + delete[] longitude; + delete[] height; + delete[] valid_sats; + delete[] solution_status; + delete[] solution_type; + delete[] AR_ratio_factor; + delete[] AR_ratio_threshold; + delete[] gdop; + delete[] pdop; + delete[] hdop; + delete[] vdop; + + return false; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("TOW_at_current_symbol_ms", MAT_C_UINT32, MAT_T_UINT32, 2, dims, TOW_at_current_symbol_ms, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("week", MAT_C_UINT32, MAT_T_UINT32, 2, dims, week, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("RX_time", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, RX_time, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("user_clk_offset", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, user_clk_offset, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("pos_x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, pos_x, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("pos_y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, pos_y, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("pos_z", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, pos_z, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("vel_x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, vel_x, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("vel_y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, vel_y, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("vel_z", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, vel_z, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_xx", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_xx, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_yy", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_yy, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_zz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_zz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_xy", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_xy, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_yz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_yz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("cov_zx", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, cov_zx, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("latitude", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, latitude, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("longitude", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, longitude, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("height", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, height, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("valid_sats", MAT_C_UINT8, MAT_T_UINT8, 2, dims, valid_sats, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("solution_status", MAT_C_UINT8, MAT_T_UINT8, 2, dims, solution_status, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("solution_type", MAT_C_UINT8, MAT_T_UINT8, 2, dims, solution_type, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("AR_ratio_factor", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, AR_ratio_factor, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("AR_ratio_threshold", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, AR_ratio_threshold, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("gdop", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, gdop, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("pdop", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, pdop, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("hdop", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, hdop, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("vdop", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, vdop, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + + Mat_Close(matfp); + delete[] TOW_at_current_symbol_ms; + delete[] week; + delete[] RX_time; + delete[] user_clk_offset; + delete[] pos_x; + delete[] pos_y; + delete[] pos_z; + delete[] vel_x; + delete[] vel_y; + delete[] vel_z; + delete[] cov_xx; + delete[] cov_yy; + delete[] cov_zz; + delete[] cov_xy; + delete[] cov_yz; + delete[] cov_zx; + delete[] latitude; + delete[] longitude; + delete[] height; + delete[] valid_sats; + delete[] solution_status; + delete[] solution_type; + delete[] AR_ratio_factor; + delete[] AR_ratio_threshold; + delete[] gdop; + delete[] pdop; + delete[] hdop; + delete[] vdop; + + return true; +} + +rtklib_solver::~rtklib_solver() +{ + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the RTKLIB dump file " << ex.what(); + } + } + if (d_flag_dump_mat_enabled) + { + save_matfile(); + } +} + + +double rtklib_solver::get_gdop() const +{ + return dop_[0]; +} + + +double rtklib_solver::get_pdop() const +{ + return dop_[1]; +} + + +double rtklib_solver::get_hdop() const +{ + return dop_[2]; +} + + +double rtklib_solver::get_vdop() const +{ + return dop_[3]; +} + + +bool rtklib_solver::get_PVT(const std::map &gnss_observables_map, bool flag_averaging) +{ + std::map::const_iterator gnss_observables_iter; + std::map::const_iterator galileo_ephemeris_iter; + std::map::const_iterator gps_ephemeris_iter; + std::map::const_iterator gps_cnav_ephemeris_iter; + std::map::const_iterator glonass_gnav_ephemeris_iter; + const Glonass_Gnav_Utc_Model gnav_utc = this->glonass_gnav_utc_model; + + this->set_averaging_flag(flag_averaging); + + // ******************************************************************************** + // ****** PREPARE THE DATA (SV EPHEMERIS AND OBSERVATIONS) ************************ + // ******************************************************************************** + int valid_obs = 0; // valid observations counter + int glo_valid_obs = 0; // GLONASS L1/L2 valid observations counter + + obsd_t obs_data[MAXOBS]; + eph_t eph_data[MAXOBS]; + geph_t geph_data[MAXOBS]; + + // Workaround for NAV/CNAV clash problem + bool gps_dual_band = false; + bool band1 = false; + bool band2 = false; + for (gnss_observables_iter = gnss_observables_map.cbegin(); + gnss_observables_iter != gnss_observables_map.cend(); + ++gnss_observables_iter) + { + switch (gnss_observables_iter->second.System) + { + case 'G': + { + std::string sig_(gnss_observables_iter->second.Signal); + if (sig_ == "1C") + { + band1 = true; + } + if (sig_ == "2S") + { + band2 = true; + } + } + break; + default: + { + } + } + } + if (band1 == true and band2 == true) gps_dual_band = true; + + for (gnss_observables_iter = gnss_observables_map.cbegin(); + gnss_observables_iter != gnss_observables_map.cend(); + ++gnss_observables_iter) // CHECK INCONSISTENCY when combining GLONASS + other system + { + switch (gnss_observables_iter->second.System) + { + case 'E': + { + std::string sig_(gnss_observables_iter->second.Signal); + // Galileo E1 + if (sig_ == "1B") + { + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) + { + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 0); + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + + // Galileo E5 + if (sig_ == "5X") + { + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) + { + bool found_E1_obs = false; + for (int i = 0; i < valid_obs; i++) + { + if (eph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN + NSATGPS + NSATGLO))) + { + obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(obs_data[i + glo_valid_obs], + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 2); // Band 3 (L5/E5) + found_E1_obs = true; + break; + } + } + if (!found_E1_obs) + { + // insert Galileo E5 obs as new obs and also insert its ephemeris + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + auto default_code_ = static_cast(CODE_NONE); + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, + {default_code_, default_code_, default_code_}, + {}, {0.0, 0.0, 0.0}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 2); // Band 3 (L5/E5) + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + break; + } + case 'G': + { + // GPS L1 + // 1 GPS - find the ephemeris for the current GPS SV observation. The SV PRN ID is the map key + std::string sig_(gnss_observables_iter->second.Signal); + if (sig_ == "1C") + { + gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != gps_ephemeris_map.cend()) + { + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(gps_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + gps_ephemeris_iter->second.i_GPS_week, + 0); + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->first; + } + } + // GPS L2 (todo: solve NAV/CNAV clash) + if ((sig_ == "2S") and (gps_dual_band == false)) + { + gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_cnav_ephemeris_iter != gps_cnav_ephemeris_map.cend()) + { + // 1. Find the same satellite in GPS L1 band + gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != gps_ephemeris_map.cend()) + { + /* By the moment, GPS L2 observables are not used in pseudorange computations if GPS L1 is available + // 2. If found, replace the existing GPS L1 ephemeris with the GPS L2 ephemeris + // (more precise!), and attach the L2 observation to the L1 observation in RTKLIB structure + for (int i = 0; i < valid_obs; i++) + { + if (eph_data[i].sat == static_cast(gnss_observables_iter->second.PRN)) + { + eph_data[i] = eph_to_rtklib(gps_cnav_ephemeris_iter->second); + obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(obs_data[i + glo_valid_obs], + gnss_observables_iter->second, + eph_data[i].week, + 1); // Band 2 (L2) + break; + } + } + */ + } + else + { + // 3. If not found, insert the GPS L2 ephemeris and the observation + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(gps_cnav_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + auto default_code_ = static_cast(CODE_NONE); + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, + {default_code_, default_code_, default_code_}, + {}, {0.0, 0.0, 0.0}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + gps_cnav_ephemeris_iter->second.i_GPS_week, + 1); // Band 2 (L2) + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + // GPS L5 + if (sig_ == "L5") + { + gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_cnav_ephemeris_iter != gps_cnav_ephemeris_map.cend()) + { + // 1. Find the same satellite in GPS L1 band + gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != gps_ephemeris_map.cend()) + { + // 2. If found, replace the existing GPS L1 ephemeris with the GPS L5 ephemeris + // (more precise!), and attach the L5 observation to the L1 observation in RTKLIB structure + for (int i = 0; i < valid_obs; i++) + { + if (eph_data[i].sat == static_cast(gnss_observables_iter->second.PRN)) + { + eph_data[i] = eph_to_rtklib(gps_cnav_ephemeris_iter->second); + obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(obs_data[i], + gnss_observables_iter->second, + gps_cnav_ephemeris_iter->second.i_GPS_week, + 2); // Band 3 (L5) + break; + } + } + } + else + { + // 3. If not found, insert the GPS L5 ephemeris and the observation + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(gps_cnav_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + auto default_code_ = static_cast(CODE_NONE); + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, + {default_code_, default_code_, default_code_}, + {}, {0.0, 0.0, 0.0}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + gps_cnav_ephemeris_iter->second.i_GPS_week, + 2); // Band 3 (L5) + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + break; + } + case 'R': //TODO This should be using rtk lib nomenclature + { + std::string sig_(gnss_observables_iter->second.Signal); + // GLONASS GNAV L1 + if (sig_ == "1G") + { + // 1 Glo - find the ephemeris for the current GLONASS SV observation. The SV Slot Number (PRN ID) is the map key + glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != glonass_gnav_ephemeris_map.cend()) + { + // convert ephemeris from GNSS-SDR class to RTKLIB structure + geph_data[glo_valid_obs] = eph_to_rtklib(glonass_gnav_ephemeris_iter->second, gnav_utc); + // convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + glonass_gnav_ephemeris_iter->second.d_WN, + 0); // Band 0 (L1) + glo_valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + // GLONASS GNAV L2 + if (sig_ == "2G") + { + // 1 GLONASS - find the ephemeris for the current GLONASS SV observation. The SV PRN ID is the map key + glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != glonass_gnav_ephemeris_map.cend()) + { + bool found_L1_obs = false; + for (int i = 0; i < glo_valid_obs; i++) + { + if (geph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN + NSATGPS))) + { + obs_data[i + valid_obs] = insert_obs_to_rtklib(obs_data[i + valid_obs], + gnss_observables_iter->second, + glonass_gnav_ephemeris_iter->second.d_WN, + 1); //Band 1 (L2) + found_L1_obs = true; + break; + } + } + if (!found_L1_obs) + { + // insert GLONASS GNAV L2 obs as new obs and also insert its ephemeris + // convert ephemeris from GNSS-SDR class to RTKLIB structure + geph_data[glo_valid_obs] = eph_to_rtklib(glonass_gnav_ephemeris_iter->second, gnav_utc); + // convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + glonass_gnav_ephemeris_iter->second.d_WN, + 1); // Band 1 (L2) + glo_valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + break; + } + default: + DLOG(INFO) << "Hybrid observables: Unknown GNSS"; + break; + } + } + + // ********************************************************************** + // ****** SOLVE PVT****************************************************** + // ********************************************************************** + + this->set_valid_position(false); + if ((valid_obs + glo_valid_obs) > 3) + { + int result = 0; + nav_t nav_data; + nav_data.eph = eph_data; + nav_data.geph = geph_data; + nav_data.n = valid_obs; + nav_data.ng = glo_valid_obs; + + for (auto &i : nav_data.lam) + { + i[0] = SPEED_OF_LIGHT / FREQ1; // L1/E1 + i[1] = SPEED_OF_LIGHT / FREQ2; // L2 + i[2] = SPEED_OF_LIGHT / FREQ5; // L5/E5 + } + + result = rtkpos(&rtk_, obs_data, valid_obs + glo_valid_obs, &nav_data); + + if (result == 0) + { + LOG(INFO) << "RTKLIB rtkpos error"; + DLOG(INFO) << "RTKLIB rtkpos error message: " << rtk_.errbuf; + this->set_time_offset_s(0.0); // reset rx time estimation + this->set_num_valid_observations(0); + } + else + { + this->set_num_valid_observations(rtk_.sol.ns); // record the number of valid satellites used by the PVT solver + pvt_sol = rtk_.sol; + // DOP computation + unsigned int used_sats = 0; + for (unsigned int i = 0; i < MAXSAT; i++) + { + pvt_ssat[i] = rtk_.ssat[i]; + if (rtk_.ssat[i].vs == 1) + { + used_sats++; + } + } + + std::vector azel; + azel.reserve(used_sats * 2); + unsigned int index_aux = 0; + for (auto &i : rtk_.ssat) + { + if (i.vs == 1) + { + azel[2 * index_aux] = i.azel[0]; + azel[2 * index_aux + 1] = i.azel[1]; + index_aux++; + } + } + + if (index_aux > 0) dops(index_aux, azel.data(), 0.0, dop_.data()); + this->set_valid_position(true); + arma::vec rx_position_and_time(4); + rx_position_and_time(0) = pvt_sol.rr[0]; // [m] + rx_position_and_time(1) = pvt_sol.rr[1]; // [m] + rx_position_and_time(2) = pvt_sol.rr[2]; // [m] + + //todo: fix this ambiguity in the RTKLIB units in receiver clock offset! + if (rtk_.opt.mode == PMODE_SINGLE) + { + rx_position_and_time(3) = pvt_sol.dtr[0]; // if the RTKLIB solver is set to SINGLE, the dtr is already expressed in [s] + } + else + { + rx_position_and_time(3) = pvt_sol.dtr[0] / GPS_C_m_s; // the receiver clock offset is expressed in [meters], so we convert it into [s] + } + this->set_rx_pos(rx_position_and_time.rows(0, 2)); // save ECEF position for the next iteration + + //compute Ground speed and COG + double ground_speed_ms = 0.0; + double pos[3]; + double enuv[3]; + ecef2pos(pvt_sol.rr, pos); + ecef2enu(pos, &pvt_sol.rr[3], enuv); + this->set_speed_over_ground(norm_rtk(enuv, 2)); + double new_cog; + if (ground_speed_ms >= 1.0) + { + new_cog = atan2(enuv[0], enuv[1]) * R2D; + if (new_cog < 0.0) new_cog += 360.0; + this->set_course_over_ground(new_cog); + } + + //observable fix: + //double offset_s = this->get_time_offset_s(); + //this->set_time_offset_s(offset_s + (rx_position_and_time(3) / GPS_C_m_s)); // accumulate the rx time error for the next iteration [meters]->[seconds] + this->set_time_offset_s(rx_position_and_time(3)); + + DLOG(INFO) << "RTKLIB Position at RX TOW = " << gnss_observables_map.begin()->second.RX_time + << " in ECEF (X,Y,Z,t[meters]) = " << rx_position_and_time; + + boost::posix_time::ptime p_time; + // gtime_t rtklib_utc_time = gpst2utc(pvt_sol.time); //Corrected RX Time (Non integer multiply of 1 ms of granularity) + // Uncorrected RX Time (integer multiply of 1 ms and the same observables time reported in RTCM and RINEX) + gtime_t rtklib_time = gpst2time(adjgpsweek(nav_data.eph[0].week), gnss_observables_map.begin()->second.RX_time); + gtime_t rtklib_utc_time = gpst2utc(rtklib_time); + p_time = boost::posix_time::from_time_t(rtklib_utc_time.time); + p_time += boost::posix_time::microseconds(static_cast(round(rtklib_utc_time.sec * 1e6))); // NOLINT(google-runtime-int) + this->set_position_UTC_time(p_time); + cart2geo(static_cast(rx_position_and_time(0)), static_cast(rx_position_and_time(1)), static_cast(rx_position_and_time(2)), 4); + + DLOG(INFO) << "RTKLIB Position at " << boost::posix_time::to_simple_string(p_time) + << " is Lat = " << this->get_latitude() << " [deg], Long = " << this->get_longitude() + << " [deg], Height= " << this->get_height() << " [m]" + << " RX time offset= " << this->get_time_offset_s() << " [s]"; + + // ######## LOG FILE ######### + if (d_flag_dump_enabled == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint32_t tmp_uint32; + // TOW + tmp_uint32 = gnss_observables_map.begin()->second.TOW_at_current_symbol_ms; + d_dump_file.write(reinterpret_cast(&tmp_uint32), sizeof(uint32_t)); + // WEEK + tmp_uint32 = adjgpsweek(nav_data.eph[0].week); + d_dump_file.write(reinterpret_cast(&tmp_uint32), sizeof(uint32_t)); + // PVT GPS time + tmp_double = gnss_observables_map.begin()->second.RX_time; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // User clock offset [s] + tmp_double = rx_position_and_time(3); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + + // ECEF POS X,Y,X [m] + ECEF VEL X,Y,X [m/s] (6 x double) + tmp_double = pvt_sol.rr[0]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.rr[1]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.rr[2]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.rr[3]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.rr[4]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.rr[5]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + + // position variance/covariance (m^2) {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} (6 x double) + tmp_double = pvt_sol.qr[0]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.qr[1]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.qr[2]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.qr[3]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.qr[4]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = pvt_sol.qr[5]; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + + // GEO user position Latitude [deg] + tmp_double = get_latitude(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // GEO user position Longitude [deg] + tmp_double = get_longitude(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // GEO user position Height [m] + tmp_double = get_height(); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + + // NUMBER OF VALID SATS + d_dump_file.write(reinterpret_cast(&pvt_sol.ns), sizeof(uint8_t)); + // RTKLIB solution status + d_dump_file.write(reinterpret_cast(&pvt_sol.stat), sizeof(uint8_t)); + // RTKLIB solution type (0:xyz-ecef,1:enu-baseline) + d_dump_file.write(reinterpret_cast(&pvt_sol.type), sizeof(uint8_t)); + // AR ratio factor for validation + d_dump_file.write(reinterpret_cast(&pvt_sol.ratio), sizeof(float)); + // AR ratio threshold for validation + d_dump_file.write(reinterpret_cast(&pvt_sol.thres), sizeof(float)); + + // GDOP / PDOP/ HDOP/ VDOP + d_dump_file.write(reinterpret_cast(&dop_[0]), sizeof(double)); + d_dump_file.write(reinterpret_cast(&dop_[1]), sizeof(double)); + d_dump_file.write(reinterpret_cast(&dop_[2]), sizeof(double)); + d_dump_file.write(reinterpret_cast(&dop_[3]), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing RTKLIB dump file " << e.what(); + } + } + } + } + return is_valid_position(); +} diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h new file mode 100644 index 000000000..73a96166d --- /dev/null +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -0,0 +1,122 @@ +/*! + * \file rtklib_solver.h + * \brief PVT solver based on rtklib library functions adapted to the GNSS-SDR + * data flow and structures + * \authors
    + *
  • 2017, Javier Arribas + *
  • 2017, Carles Fernandez + *
  • 2007-2013, T. Takasu + *
+ * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * -------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_SOLVER_H_ +#define GNSS_SDR_RTKLIB_SOLVER_H_ + + +#include "galileo_almanac.h" +#include "galileo_navigation_message.h" +#include "glonass_gnav_navigation_message.h" +#include "gnss_synchro.h" +#include "gps_cnav_navigation_message.h" +#include "gps_navigation_message.h" +#include "pvt_solution.h" +#include "rtklib_rtkpos.h" +#include +#include +#include +#include + + +/*! + * \brief This class implements a simple PVT Least Squares solution + */ +class rtklib_solver : public Pvt_Solution +{ +private: + rtk_t rtk_; + std::string d_dump_filename; + std::ofstream d_dump_file; + bool save_matfile(); + + bool d_flag_dump_enabled; + bool d_flag_dump_mat_enabled; + int d_nchannels; // Number of available channels for positioning + std::array dop_; + +public: + sol_t pvt_sol; + ssat_t pvt_ssat[MAXSAT]; + rtklib_solver(int nchannels, std::string dump_filename, bool flag_dump_to_file, bool flag_dump_to_mat, const rtk_t& rtk); + ~rtklib_solver(); + + bool get_PVT(const std::map& gnss_observables_map, bool flag_averaging); + double get_hdop() const; + double get_vdop() const; + double get_pdop() const; + double get_gdop() const; + + std::map galileo_ephemeris_map; //!< Map storing new Galileo_Ephemeris + std::map gps_ephemeris_map; //!< Map storing new GPS_Ephemeris + std::map gps_cnav_ephemeris_map; //!< Map storing new GPS_CNAV_Ephemeris + std::map glonass_gnav_ephemeris_map; //!< Map storing new GLONASS GNAV Ephemeris + + Galileo_Utc_Model galileo_utc_model; + Galileo_Iono galileo_iono; + std::map galileo_almanac_map; + + Gps_Utc_Model gps_utc_model; + Gps_Iono gps_iono; + std::map gps_almanac_map; + + Gps_CNAV_Iono gps_cnav_iono; + Gps_CNAV_Utc_Model gps_cnav_utc_model; + + Glonass_Gnav_Utc_Model glonass_gnav_utc_model; //!< Map storing GLONASS GNAV UTC Model + Glonass_Gnav_Almanac glonass_gnav_almanac; //!< Map storing GLONASS GNAV Almanac Model + + int count_valid_position; +}; + +#endif diff --git a/src/algorithms/acquisition/CMakeLists.txt b/src/algorithms/acquisition/CMakeLists.txt index 3c52a9e01..96259341c 100644 --- a/src/algorithms/acquisition/CMakeLists.txt +++ b/src/algorithms/acquisition/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,9 +13,9 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) add_subdirectory(gnuradio_blocks) - +add_subdirectory(libs) diff --git a/src/algorithms/acquisition/adapters/CMakeLists.txt b/src/algorithms/acquisition/adapters/CMakeLists.txt index 1ead04df8..ee0046970 100644 --- a/src/algorithms/acquisition/adapters/CMakeLists.txt +++ b/src/algorithms/acquisition/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,49 +13,102 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(ACQ_ADAPTER_SOURCES gps_l1_ca_pcps_acquisition.cc - gps_l1_ca_pcps_multithread_acquisition.cc gps_l1_ca_pcps_assisted_acquisition.cc gps_l1_ca_pcps_acquisition_fine_doppler.cc gps_l1_ca_pcps_tong_acquisition.cc gps_l1_ca_pcps_quicksync_acquisition.cc gps_l2_m_pcps_acquisition.cc + gps_l5i_pcps_acquisition.cc galileo_e1_pcps_ambiguous_acquisition.cc galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc galileo_e1_pcps_quicksync_ambiguous_acquisition.cc galileo_e1_pcps_tong_ambiguous_acquisition.cc galileo_e1_pcps_8ms_ambiguous_acquisition.cc galileo_e5a_noncoherent_iq_acquisition_caf.cc + galileo_e5a_pcps_acquisition.cc + glonass_l1_ca_pcps_acquisition.cc + glonass_l2_ca_pcps_acquisition.cc ) +set(ACQ_ADAPTER_HEADERS + gps_l1_ca_pcps_acquisition.h + gps_l1_ca_pcps_assisted_acquisition.h + gps_l1_ca_pcps_acquisition_fine_doppler.h + gps_l1_ca_pcps_tong_acquisition.h + gps_l1_ca_pcps_quicksync_acquisition.h + gps_l2_m_pcps_acquisition.h + gps_l5i_pcps_acquisition.h + galileo_e1_pcps_ambiguous_acquisition.h + galileo_e1_pcps_cccwsr_ambiguous_acquisition.h + galileo_e1_pcps_quicksync_ambiguous_acquisition.h + galileo_e1_pcps_tong_ambiguous_acquisition.h + galileo_e1_pcps_8ms_ambiguous_acquisition.h + galileo_e5a_noncoherent_iq_acquisition_caf.h + galileo_e5a_pcps_acquisition.h + glonass_l1_ca_pcps_acquisition.h + glonass_l2_ca_pcps_acquisition.h +) + +if(ENABLE_FPGA) + set(ACQ_ADAPTER_SOURCES ${ACQ_ADAPTER_SOURCES} + gps_l1_ca_pcps_acquisition_fpga.cc + gps_l2_m_pcps_acquisition_fpga.cc + galileo_e1_pcps_ambiguous_acquisition_fpga.cc + galileo_e5a_pcps_acquisition_fpga.cc + gps_l5i_pcps_acquisition_fpga.cc + ) + set(ACQ_ADAPTER_HEADERS ${ACQ_ADAPTER_HEADERS} + gps_l1_ca_pcps_acquisition_fpga.h + gps_l2_m_pcps_acquisition_fpga.h + galileo_e1_pcps_ambiguous_acquisition_fpga.h + galileo_e5a_pcps_acquisition_fpga.h + gps_l5i_pcps_acquisition_fpga.h + ) +endif() if(OPENCL_FOUND) - set(ACQ_ADAPTER_SOURCES ${ACQ_ADAPTER_SOURCES} gps_l1_ca_pcps_opencl_acquisition.cc) -endif(OPENCL_FOUND) + set(ACQ_ADAPTER_SOURCES + ${ACQ_ADAPTER_SOURCES} + gps_l1_ca_pcps_opencl_acquisition.cc + ) + set(ACQ_ADAPTER_HEADERS ${ACQ_ADAPTER_HEADERS} + gps_l1_ca_pcps_opencl_acquisition.h + ) +endif() include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${GNURADIO_BLOCKS_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${GNURADIO_BLOCKS_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} ) -file(GLOB ACQ_ADAPTER_HEADERS "*.h") list(SORT ACQ_ADAPTER_HEADERS) +list(SORT ACQ_ADAPTER_SOURCES) add_library(acq_adapters ${ACQ_ADAPTER_SOURCES} ${ACQ_ADAPTER_HEADERS}) -source_group(Headers FILES ${ACQ_ADAPTER_HEADERS}) -target_link_libraries(acq_adapters gnss_sp_libs acq_gr_blocks ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES}) - +source_group(Headers FILES ${ACQ_ADAPTER_HEADERS}) +target_link_libraries(acq_adapters + acquisition_lib + gnss_sp_libs + gnss_sdr_flags + acq_gr_blocks + ${Boost_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} +) diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.cc index d6859919c..7af5d228f 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_pcps_8ms_ambiguous_acquisition.h" -#include -#include -#include -#include "galileo_e1_signal_processing.h" #include "Galileo_E1.h" #include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE1Pcps8msAmbiguousAcquisition::GalileoE1Pcps8msAmbiguousAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -51,62 +55,68 @@ GalileoE1Pcps8msAmbiguousAcquisition::GalileoE1Pcps8msAmbiguousAcquisition( DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", - default_item_type); + default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 4); if (sampled_ms_ % 4 != 0) { - sampled_ms_ = (int)(sampled_ms_/4) * 4; + sampled_ms_ = static_cast(sampled_ms_ / 4) * 4; LOG(WARNING) << "coherent_integration_time should be multiple of " - << "Galileo code length (4 ms). coherent_integration_time = " - << sampled_ms_ << " ms will be used."; + << "Galileo code length (4 ms). coherent_integration_time = " + << sampled_ms_ << " ms will be used."; } max_dwells_ = configuration_->property(role + ".max_dwells", 1); dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); + default_dump_filename); //--- Find number of samples per spreading code (4 ms) ----------------- - code_length_ = round( - fs_in_ - / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS)); + fs_in_ / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); - vector_length_ = code_length_ * (int)(sampled_ms_/4); + vector_length_ = code_length_ * static_cast(sampled_ms_ / 4); int samples_per_ms = code_length_ / 4; code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = galileo_pcps_8ms_make_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, samples_per_ms, code_length_, - dump_, dump_filename_); + doppler_max_, fs_in_, samples_per_ms, code_length_, + dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); DLOG(INFO) << "stream_to_vector(" - << stream_to_vector_->unique_id() << ")"; + << stream_to_vector_->unique_id() << ")"; DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() - << ")"; + << ")"; } else { item_size_ = sizeof(gr_complex); LOG(WARNING) << item_type_ << " unknown acquisition item type"; } - + channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -116,10 +126,15 @@ GalileoE1Pcps8msAmbiguousAcquisition::~GalileoE1Pcps8msAmbiguousAcquisition() } +void GalileoE1Pcps8msAmbiguousAcquisition::stop_acquisition() +{ +} + + void GalileoE1Pcps8msAmbiguousAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -128,11 +143,11 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_channel(unsigned int channel) void GalileoE1Pcps8msAmbiguousAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); + if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -143,7 +158,7 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_threshold(threshold_); } @@ -154,7 +169,7 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_doppler_max(unsigned int doppler_ { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -164,7 +179,7 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_doppler_max(unsigned int doppler_ void GalileoE1Pcps8msAmbiguousAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } @@ -172,10 +187,10 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_doppler_step(unsigned int doppler void GalileoE1Pcps8msAmbiguousAcquisition::set_gnss_synchro( - Gnss_Synchro* gnss_synchro) + Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -184,41 +199,37 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_gnss_synchro( signed int GalileoE1Pcps8msAmbiguousAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GalileoE1Pcps8msAmbiguousAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GalileoE1Pcps8msAmbiguousAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { bool cboc = configuration_->property( - "Acquisition" + boost::lexical_cast(channel_) - + ".cboc", false); + "Acquisition" + std::to_string(channel_) + ".cboc", false); - std::complex * code = new std::complex[code_length_]; + auto* code = new std::complex[code_length_]; galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); + cboc, gnss_synchro_->PRN, fs_in_, 0, false); - for (unsigned int i = 0; i < sampled_ms_/4; i++) + for (unsigned int i = 0; i < sampled_ms_ / 4; i++) { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); } acquisition_cc_->set_local_code(code_); @@ -230,7 +241,7 @@ void GalileoE1Pcps8msAmbiguousAcquisition::set_local_code() void GalileoE1Pcps8msAmbiguousAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -239,19 +250,19 @@ void GalileoE1Pcps8msAmbiguousAcquisition::reset() float GalileoE1Pcps8msAmbiguousAcquisition::calculate_threshold(float pfa) { unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; - unsigned int ncells = vector_length_*frequency_bins; + unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); - double val = pow(1.0 - pfa,exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + double val = pow(1.0 - pfa, exponent); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -259,7 +270,7 @@ float GalileoE1Pcps8msAmbiguousAcquisition::calculate_threshold(float pfa) void GalileoE1Pcps8msAmbiguousAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -268,7 +279,7 @@ void GalileoE1Pcps8msAmbiguousAcquisition::connect(gr::top_block_sptr top_block) void GalileoE1Pcps8msAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -285,4 +296,3 @@ gr::basic_block_sptr GalileoE1Pcps8msAmbiguousAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.h index 75c25b0a7..ce9cd440b 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_8ms_ambiguous_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,12 +32,11 @@ #ifndef GNSS_SDR_GALILEO_E1_PCPS_8MS_AMBIGUOUS_ACQUISITION_H_ #define GNSS_SDR_GALILEO_E1_PCPS_8MS_AMBIGUOUS_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" #include "galileo_pcps_8ms_acquisition_cc.h" - +#include "gnss_synchro.h" +#include +#include class ConfigurationInterface; @@ -45,16 +44,17 @@ class ConfigurationInterface; * \brief Adapts a PCPS 8ms acquisition block to an * AcquisitionInterface for Galileo E1 Signals */ -class GalileoE1Pcps8msAmbiguousAcquisition: public AcquisitionInterface +class GalileoE1Pcps8msAmbiguousAcquisition : public AcquisitionInterface { public: GalileoE1Pcps8msAmbiguousAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1Pcps8msAmbiguousAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -62,66 +62,77 @@ public: /*! * \brief Returns "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for Galileo E1 PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_state(int state __attribute__((unused))) override{}; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + private: ConfigurationInterface* configuration_; @@ -137,12 +148,11 @@ private: unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.cc index 6f184c25e..79e25061c 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,87 +24,127 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_pcps_ambiguous_acquisition.h" -#include +#include "Galileo_E1.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" #include #include -#include "galileo_e1_signal_processing.h" -#include "Galileo_E1.h" -#include "configuration_interface.h" + using google::LogMessage; + GalileoE1PcpsAmbiguousAcquisition::GalileoE1PcpsAmbiguousAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "../data/acquisition.dat"; + std::string default_dump_filename = "./acquisition.mat"; DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); - dump_ = configuration_->property(role + ".dump", false); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters_.fs_in = fs_in_; doppler_max_ = configuration_->property(role + ".doppler_max", 5000); - sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 4); - - if (sampled_ms_ % 4 != 0) + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters_.doppler_max = doppler_max_; + acq_parameters_.ms_per_code = 4; + sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", acq_parameters_.ms_per_code); + acq_parameters_.sampled_ms = sampled_ms_; + if ((acq_parameters_.sampled_ms % acq_parameters_.ms_per_code) != 0) { - sampled_ms_ = (int)(sampled_ms_ / 4) * 4; - LOG(WARNING) << "coherent_integration_time should be multiple of " - << "Galileo code length (4 ms). coherent_integration_time = " - << sampled_ms_ << " ms will be used."; + LOG(WARNING) << "Parameter coherent_integration_time_ms should be a multiple of 4. Setting it to 4"; + acq_parameters_.sampled_ms = acq_parameters_.ms_per_code; + } + bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + acq_parameters_.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters_.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + acquire_pilot_ = configuration_->property(role + ".acquire_pilot", false); //will be true in future versions + max_dwells_ = configuration_->property(role + ".max_dwells", 1); + acq_parameters_.max_dwells = max_dwells_; + dump_ = configuration_->property(role + ".dump", false); + acq_parameters_.dump = dump_; + acq_parameters_.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters_.blocking = blocking_; + dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + acq_parameters_.dump_filename = dump_filename_; + + acq_parameters_.use_automatic_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + if (acq_parameters_.use_automatic_resampler == true and item_type_ != "gr_complex") + { + LOG(WARNING) << "Galileo E1 acqisition disabled the automatic resampler feature because its item_type is not set to gr_complex"; + acq_parameters_.use_automatic_resampler = false; + } + if (acq_parameters_.use_automatic_resampler) + { + if (acq_parameters_.fs_in > Galileo_E1_OPT_ACQ_FS_HZ) + { + acq_parameters_.resampler_ratio = floor(static_cast(acq_parameters_.fs_in) / Galileo_E1_OPT_ACQ_FS_HZ); + uint32_t decimation = acq_parameters_.fs_in / Galileo_E1_OPT_ACQ_FS_HZ; + while (acq_parameters_.fs_in % decimation > 0) + { + decimation--; + }; + acq_parameters_.resampler_ratio = decimation; + acq_parameters_.resampled_fs = acq_parameters_.fs_in / static_cast(acq_parameters_.resampler_ratio); + } + //--- Find number of samples per spreading code (4 ms) ----------------- + code_length_ = static_cast(std::floor(static_cast(acq_parameters_.resampled_fs) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(acq_parameters_.resampled_fs) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / Galileo_E1_CODE_CHIP_RATE_HZ) * static_cast(acq_parameters_.resampled_fs))); + } + else + { + //--- Find number of samples per spreading code (4 ms) ----------------- + code_length_ = static_cast(std::floor(static_cast(fs_in_) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / Galileo_E1_CODE_CHIP_RATE_HZ) * static_cast(acq_parameters_.fs_in))); } - bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions - - max_dwells_ = configuration_->property(role + ".max_dwells", 1); - - dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - - //--- Find number of samples per spreading code (4 ms) ----------------- - code_length_ = round(fs_in_ / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); - int samples_per_ms = round(code_length_ / 4.0); - vector_length_ = sampled_ms_ * samples_per_ms; - - if( bit_transition_flag_ ) + acq_parameters_.samples_per_code = acq_parameters_.samples_per_ms * static_cast(Galileo_E1_CODE_PERIOD_MS); + vector_length_ = sampled_ms_ * acq_parameters_.samples_per_ms; + if (bit_transition_flag_) { vector_length_ *= 2; } code_ = new gr_complex[vector_length_]; - if (item_type_.compare("cshort") == 0 ) + if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); - acquisition_sc_ = pcps_make_acquisition_sc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, samples_per_ms, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_sc_->unique_id() << ")"; - - }else{ - item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, samples_per_ms, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() << ")"; } + else + { + item_size_ = sizeof(gr_complex); + } + acq_parameters_.it_size = item_size_; + acq_parameters_.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters_.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters_.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters_.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acquisition_ = pcps_make_acquisition(acq_parameters_); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; - stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - - if (item_type_.compare("cbyte") == 0) + if (item_type_ == "cbyte") { cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); float_to_complex_ = gr::blocks::float_to_complex::make(); @@ -113,7 +153,15 @@ GalileoE1PcpsAmbiguousAcquisition::GalileoE1PcpsAmbiguousAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -123,27 +171,25 @@ GalileoE1PcpsAmbiguousAcquisition::~GalileoE1PcpsAmbiguousAcquisition() } +void GalileoE1PcpsAmbiguousAcquisition::stop_acquisition() +{ +} + + void GalileoE1PcpsAmbiguousAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_channel(channel_); - } - else - { - acquisition_cc_->set_channel(channel_); - } + acquisition_->set_channel(channel_); } void GalileoE1PcpsAmbiguousAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); + if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -154,14 +200,7 @@ void GalileoE1PcpsAmbiguousAcquisition::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_threshold(threshold_); - } - else - { - acquisition_cc_->set_threshold(threshold_); - } + acquisition_->set_threshold(threshold_); } @@ -169,14 +208,7 @@ void GalileoE1PcpsAmbiguousAcquisition::set_doppler_max(unsigned int doppler_max { doppler_max_ = doppler_max; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_max(doppler_max_); - } - else - { - acquisition_cc_->set_doppler_max(doppler_max_); - } + acquisition_->set_doppler_max(doppler_max_); } @@ -184,14 +216,7 @@ void GalileoE1PcpsAmbiguousAcquisition::set_doppler_step(unsigned int doppler_st { doppler_step_ = doppler_step; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_step(doppler_step_); - } - else - { - acquisition_cc_->set_doppler_step(doppler_step_); - } + acquisition_->set_doppler_step(doppler_step_); } @@ -199,116 +224,98 @@ void GalileoE1PcpsAmbiguousAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_sync { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_gnss_synchro(gnss_synchro_); - } - else - { - acquisition_cc_->set_gnss_synchro(gnss_synchro_); - } + acquisition_->set_gnss_synchro(gnss_synchro_); } signed int GalileoE1PcpsAmbiguousAcquisition::mag() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_->mag(); - } - else - { - return acquisition_cc_->mag(); - } + return acquisition_->mag(); } void GalileoE1PcpsAmbiguousAcquisition::init() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->init(); - } - else - { - acquisition_cc_->init(); - } - - set_local_code(); + acquisition_->init(); + //set_local_code(); } void GalileoE1PcpsAmbiguousAcquisition::set_local_code() { bool cboc = configuration_->property( - "Acquisition" + boost::lexical_cast(channel_) - + ".cboc", false); + "Acquisition" + std::to_string(channel_) + ".cboc", false); - std::complex * code = new std::complex[code_length_]; + auto* code = new std::complex[code_length_]; - galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); - - for (unsigned int i = 0; i < sampled_ms_ / 4; i++) + if (acquire_pilot_ == true) { - memcpy(&(code_[i*code_length_]), code, sizeof(gr_complex)*code_length_); - } - - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_local_code(code_); + //set local signal generator to Galileo E1 pilot component (1C) + char pilot_signal[3] = "1C"; + if (acq_parameters_.use_automatic_resampler) + { + galileo_e1_code_gen_complex_sampled(code, pilot_signal, + cboc, gnss_synchro_->PRN, acq_parameters_.resampled_fs, 0, false); + } + else + { + galileo_e1_code_gen_complex_sampled(code, pilot_signal, + cboc, gnss_synchro_->PRN, fs_in_, 0, false); + } } else { - acquisition_cc_->set_local_code(code_); + if (acq_parameters_.use_automatic_resampler) + { + galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, + cboc, gnss_synchro_->PRN, acq_parameters_.resampled_fs, 0, false); + } + else + { + galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, + cboc, gnss_synchro_->PRN, fs_in_, 0, false); + } } + + for (unsigned int i = 0; i < sampled_ms_ / 4; i++) + { + memcpy(&(code_[i * code_length_]), code, sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); delete[] code; } void GalileoE1PcpsAmbiguousAcquisition::reset() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_active(true); - } - else - { - acquisition_cc_->set_active(true); - } + acquisition_->set_active(true); } void GalileoE1PcpsAmbiguousAcquisition::set_state(int state) { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_state(state); - } - else - { - acquisition_cc_->set_state(state); - } + acquisition_->set_state(state); } float GalileoE1PcpsAmbiguousAcquisition::calculate_threshold(float pfa) { unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } - DLOG(INFO) <<"Channel "<connect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to connect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->connect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to connect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->connect(float_to_complex_, 0, acquisition_, 0); } else { @@ -340,22 +348,19 @@ void GalileoE1PcpsAmbiguousAcquisition::connect(gr::top_block_sptr top_block) void GalileoE1PcpsAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->disconnect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { - // Since a byte-based acq implementation is not available, - // we just convert cshorts to gr_complex top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); } else { @@ -366,35 +371,30 @@ void GalileoE1PcpsAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisition::get_left_block() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cshort") == 0) + if (item_type_ == "cshort") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cbyte") == 0) + if (item_type_ == "cbyte") { return cbyte_to_float_x2_; } - else - { - LOG(WARNING) << item_type_ << " unknown acquisition item type"; - return nullptr; - } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; } gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisition::get_right_block() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_; - } - else - { - return acquisition_cc_; - } + return acquisition_; } +void GalileoE1PcpsAmbiguousAcquisition::set_resampler_latency(uint32_t latency_samples) +{ + acquisition_->set_resampler_latency(latency_samples); +} diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.h index b98bcbcb6..ee4538022 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,15 +32,14 @@ #ifndef GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_H_ #define GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_H_ -#include -#include -#include -#include "gnss_synchro.h" +#include "acq_conf.h" #include "acquisition_interface.h" -#include "pcps_acquisition_cc.h" -#include "pcps_acquisition_sc.h" #include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include #include +#include class ConfigurationInterface; @@ -49,16 +48,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an * AcquisitionInterface for Galileo E1 Signals */ -class GalileoE1PcpsAmbiguousAcquisition: public AcquisitionInterface +class GalileoE1PcpsAmbiguousAcquisition : public AcquisitionInterface { public: GalileoE1PcpsAmbiguousAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1PcpsAmbiguousAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -66,77 +66,89 @@ public: /*! * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_PCPS_Ambiguous_Acquisition"; } - size_t item_size() + + size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for Galileo E1 PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ + + void set_resampler_latency(uint32_t latency_samples) override; + private: ConfigurationInterface* configuration_; - pcps_acquisition_cc_sptr acquisition_cc_; - pcps_acquisition_sc_sptr acquisition_sc_; - gr::blocks::stream_to_vector::sptr stream_to_vector_; + Acq_Conf acq_parameters_; + pcps_acquisition_sptr acquisition_; gr::blocks::float_to_complex::sptr float_to_complex_; complex_byte_to_float_x2_sptr cbyte_to_float_x2_; size_t item_size_; @@ -145,18 +157,19 @@ private: unsigned int code_length_; bool bit_transition_flag_; bool use_CFAR_algorithm_flag_; + bool acquire_pilot_; unsigned int channel_; float threshold_; unsigned int doppler_max_; unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; + bool blocking_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc new file mode 100644 index 000000000..6097ce61d --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc @@ -0,0 +1,557 @@ +/*! + * \file galileo_e1_pcps_ambiguous_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E1 Signals + * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" +#include "Galileo_E1.h" +#include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include +#include + + +using google::LogMessage; + + +GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + //printf("top acq constructor start\n"); + pcpsconf_fpga_t acq_parameters; + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + DLOG(INFO) << "role " << role; + + // item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in; + //if_ = configuration_->property(role + ".if", 0); + //acq_parameters.freq = if_; + + // dump_ = configuration_->property(role + ".dump", false); + // acq_parameters.dump = dump_; + // blocking_ = configuration_->property(role + ".blocking", true); + // acq_parameters.blocking = blocking_; + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + //unsigned int sampled_ms = 4; + //acq_parameters.sampled_ms = sampled_ms; + unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 4); + acq_parameters.sampled_ms = sampled_ms; + + // bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + // acq_parameters.bit_transition_flag = bit_transition_flag_; + // use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + // acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + acquire_pilot_ = configuration_->property(role + ".acquire_pilot", false); //will be true in future versions + + // max_dwells_ = configuration_->property(role + ".max_dwells", 1); + // acq_parameters.max_dwells = max_dwells_; + // dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + // acq_parameters.dump_filename = dump_filename_; + //--- Find number of samples per spreading code (4 ms) ----------------- + auto code_length = static_cast(std::round(static_cast(fs_in) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS))); + //acq_parameters.samples_per_code = code_length_; + //int samples_per_ms = static_cast(std::round(static_cast(fs_in_) * 0.001)); + //acq_parameters.samples_per_ms = samples_per_ms; + //unsigned int vector_length = sampled_ms * samples_per_ms; + + // if (bit_transition_flag_) + // { + // vector_length_ *= 2; + // } + + //printf("fs_in = %d\n", fs_in); + //printf("Galileo_E1_B_CODE_LENGTH_CHIPS = %f\n", Galileo_E1_B_CODE_LENGTH_CHIPS); + //printf("Galileo_E1_CODE_CHIP_RATE_HZ = %f\n", Galileo_E1_CODE_CHIP_RATE_HZ); + //printf("acq adapter code_length = %d\n", code_length); + acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total; + //printf("acq adapter nsamples_total (= vector_length) = %d\n", vector_length); + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.select_queue_Fpga = select_queue_Fpga; + std::string default_device_name = "/dev/uio0"; + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total / sampled_ms; + acq_parameters.samples_per_code = nsamples_total; + + // compute all the GALILEO E1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT + auto* code = new std::complex[nsamples_total]; // buffer for the local code + auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * Galileo_E1_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32 + float max; // temporary maxima search + + //int tmp_re, tmp_im; + + for (unsigned int PRN = 1; PRN <= Galileo_E1_NUMBER_OF_CODES; PRN++) + { + //code_ = new gr_complex[vector_length_]; + + bool cboc = false; // cboc is set to 0 when using the FPGA + + //std::complex* code = new std::complex[code_length_]; + + if (acquire_pilot_ == true) + { + //printf("yes acquiring pilot!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1\n"); + //set local signal generator to Galileo E1 pilot component (1C) + char pilot_signal[3] = "1C"; + galileo_e1_code_gen_complex_sampled(code, pilot_signal, + cboc, PRN, fs_in, 0, false); + } + else + { + char data_signal[3] = "1B"; + galileo_e1_code_gen_complex_sampled(code, data_signal, + cboc, PRN, fs_in, 0, false); + } + + // for (unsigned int i = 0; i < sampled_ms / 4; i++) + // { + // //memcpy(&(code_[i * code_length_]), code, sizeof(gr_complex) * code_length_); + // memcpy(&(d_all_fft_codes_[i * code_length_]), code, sizeof(gr_complex) * code_length_); + // } + + + // // debug + // char filename[25]; + // FILE *fid; + // sprintf(filename,"gal_prn%d.txt", PRN); + // fid = fopen(filename, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid, "%f\n", code[kk].real()); + // fprintf(fid, "%f\n", code[kk].imag()); + // } + // fclose(fid); + + + // // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = std::complex(0.0, 0.0); + //code[s] = 0; + } + + memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + + // // debug + // char filename[25]; + // FILE *fid; + // sprintf(filename,"fft_gal_prn%d.txt", PRN); + // fid = fopen(filename, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid, "%f\n", fft_codes_padded[kk].real()); + // fprintf(fid, "%f\n", fft_codes_padded[kk].imag()); + // } + // fclose(fid); + + + // normalize the code + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(4096*fft_codes_padded[i].real() * (pow(2, 3) - 1) / max)), + // static_cast(floor(4096*fft_codes_padded[i].imag() * (pow(2, 3) - 1) / max))); + // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(1024*fft_codes_padded[i].real() * (pow(2, 5) - 1) / max)), + // static_cast(floor(1024*fft_codes_padded[i].imag() * (pow(2, 5) - 1) / max))); + // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), + // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); + // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(16*fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), + // static_cast(floor(16*fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + + // tmp_re = static_cast(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)); + // tmp_im = static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max)); + + // if (tmp_re > 127) + // { + // tmp_re = 127; + // } + // if (tmp_re < -128) + // { + // tmp_re = -128; + // } + // if (tmp_im > 127) + // { + // tmp_im = 127; + // } + // if (tmp_im < -128) + // { + // tmp_im = -128; + // } + // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(tmp_re), static_cast(tmp_im)); + // + } + + // // debug + // char filename2[25]; + // FILE *fid2; + // sprintf(filename2,"fft_gal_prn%d_norm.txt", PRN); + // fid2 = fopen(filename2, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); + // } + // fclose(fid2); + } + + + // for (unsigned int PRN = 1; PRN <= Galileo_E1_NUMBER_OF_CODES; PRN++) + // { + // // debug + // char filename2[25]; + // FILE *fid2; + // sprintf(filename2,"fft_gal_prn%d_norm_last.txt", PRN); + // fid2 = fopen(filename2, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); + // } + // fclose(fid2); + // } + + //acq_parameters + + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + // stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); + // DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; + + // if (item_type_.compare("cbyte") == 0) + // { + // cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + // float_to_complex_ = gr::blocks::float_to_complex::make(); + // } + + channel_ = 0; + //threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + //printf("top acq constructor end\n"); +} + + +GalileoE1PcpsAmbiguousAcquisitionFpga::~GalileoE1PcpsAmbiguousAcquisitionFpga() +{ + //printf("top acq destructor start\n"); + //delete[] code_; + delete[] d_all_fft_codes_; + //printf("top acq destructor end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::stop_acquisition() +{ +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_channel(unsigned int channel) +{ + //printf("top acq set channel start\n"); + channel_ = channel; + acquisition_fpga_->set_channel(channel_); + //printf("top acq set channel end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_threshold(float threshold) +{ + //printf("top acq set threshold start\n"); + // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. + // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. + + // float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); + // + // if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); + // + // if (pfa == 0.0) + // { + // threshold_ = threshold; + // } + // else + // { + // threshold_ = calculate_threshold(pfa); + // } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; + acquisition_fpga_->set_threshold(threshold); + // acquisition_fpga_->set_threshold(threshold_); + //printf("top acq set threshold end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_doppler_max(unsigned int doppler_max) +{ + //printf("top acq set doppler max start\n"); + doppler_max_ = doppler_max; + + acquisition_fpga_->set_doppler_max(doppler_max_); + //printf("top acq set doppler max end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_doppler_step(unsigned int doppler_step) +{ + //printf("top acq set doppler step start\n"); + doppler_step_ = doppler_step; + + acquisition_fpga_->set_doppler_step(doppler_step_); + //printf("top acq set doppler step end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + //printf("top acq set gnss synchro start\n"); + gnss_synchro_ = gnss_synchro; + + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); + //printf("top acq set gnss synchro end\n"); +} + + +signed int GalileoE1PcpsAmbiguousAcquisitionFpga::mag() +{ + // printf("top acq mag start\n"); + return acquisition_fpga_->mag(); + //printf("top acq mag end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::init() +{ + // printf("top acq init start\n"); + acquisition_fpga_->init(); + // printf("top acq init end\n"); + //set_local_code(); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_local_code() +{ + // printf("top acq set local code start\n"); + // bool cboc = configuration_->property( + // "Acquisition" + boost::lexical_cast(channel_) + ".cboc", false); + // + // std::complex* code = new std::complex[code_length_]; + // + // if (acquire_pilot_ == true) + // { + // //set local signal generator to Galileo E1 pilot component (1C) + // char pilot_signal[3] = "1C"; + // galileo_e1_code_gen_complex_sampled(code, pilot_signal, + // cboc, gnss_synchro_->PRN, fs_in_, 0, false); + // } + // else + // { + // galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, + // cboc, gnss_synchro_->PRN, fs_in_, 0, false); + // } + // + // + // for (unsigned int i = 0; i < sampled_ms_ / 4; i++) + // { + // memcpy(&(code_[i * code_length_]), code, sizeof(gr_complex) * code_length_); + // } + + //acquisition_fpga_->set_local_code(code_); + acquisition_fpga_->set_local_code(); + // delete[] code; + // printf("top acq set local code end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::reset() +{ + // printf("top acq reset start\n"); + acquisition_fpga_->set_active(true); + // printf("top acq reset end\n"); +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::set_state(int state) +{ + // printf("top acq set state start\n"); + acquisition_fpga_->set_state(state); + // printf("top acq set state end\n"); +} + + +//float GalileoE1PcpsAmbiguousAcquisitionFpga::calculate_threshold(float pfa) +//{ +// unsigned int frequency_bins = 0; +// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) +// { +// frequency_bins++; +// } +// +// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; +// +// unsigned int ncells = vector_length_ * frequency_bins; +// double exponent = 1 / static_cast(ncells); +// double val = pow(1.0 - pfa, exponent); +// double lambda = double(vector_length_); +// boost::math::exponential_distribution mydist(lambda); +// float threshold = static_cast(quantile(mydist, val)); +// +// return threshold; +//} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::connect(gr::top_block_sptr top_block) +{ + // printf("top acq connect\n"); + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + + // nothing to connect +} + + +void GalileoE1PcpsAmbiguousAcquisitionFpga::disconnect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // // Since a byte-based acq implementation is not available, + // // we just convert cshorts to gr_complex + // top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + + // nothing to disconnect + // printf("top acq disconnect\n"); +} + + +gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisitionFpga::get_left_block() +{ + // printf("top acq get left block start\n"); + // if (item_type_.compare("gr_complex") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cshort") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // return cbyte_to_float_x2_; + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; + // } + // printf("top acq get left block end\n"); +} + + +gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisitionFpga::get_right_block() +{ + // printf("top acq get right block start\n"); + return acquisition_fpga_; + // printf("top acq get right block end\n"); +} diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h new file mode 100644 index 000000000..09391ddb8 --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h @@ -0,0 +1,183 @@ +/*! + * \file galileo_e1_pcps_ambiguous_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E1 Signals + * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an + * AcquisitionInterface for Galileo E1 Signals + */ +class GalileoE1PcpsAmbiguousAcquisitionFpga : public AcquisitionInterface +{ +public: + GalileoE1PcpsAmbiguousAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GalileoE1PcpsAmbiguousAcquisitionFpga(); + + inline std::string role() override + { + // printf("top acq role\n"); + return role_; + } + + /*! + * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition" + */ + inline std::string implementation() override + { + // printf("top acq implementation\n"); + return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"; + } + + size_t item_size() override + { + // printf("top acq item size\n"); + size_t item_size = sizeof(lv_16sc_t); + return item_size; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for Galileo E1 PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + //pcps_acquisition_sptr acquisition_; + pcps_acquisition_fpga_sptr acquisition_fpga_; + gr::blocks::stream_to_vector::sptr stream_to_vector_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + // size_t item_size_; + // std::string item_type_; + //unsigned int vector_length_; + //unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + bool acquire_pilot_; + unsigned int channel_; + //float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + //unsigned int sampled_ms_; + unsigned int max_dwells_; + //long fs_in_; + //long if_; + bool dump_; + bool blocking_; + std::string dump_filename_; + //std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + //float calculate_threshold(float pfa); + + // extra for the FPGA + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts +}; + +#endif /* GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc index 690e3879d..76869f266 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_pcps_cccwsr_ambiguous_acquisition.h" -#include -#include -#include -#include "galileo_e1_signal_processing.h" #include "Galileo_E1.h" #include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE1PcpsCccwsrAmbiguousAcquisition::GalileoE1PcpsCccwsrAmbiguousAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -52,50 +56,49 @@ GalileoE1PcpsCccwsrAmbiguousAcquisition::GalileoE1PcpsCccwsrAmbiguousAcquisition item_type_ = configuration_->property(role + ".item_type", default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 4); if (sampled_ms_ % 4 != 0) { sampled_ms_ = static_cast(sampled_ms_ / 4) * 4; LOG(WARNING) << "coherent_integration_time should be multiple of " - << "Galileo code length (4 ms). coherent_integration_time = " - << sampled_ms_ << " ms will be used."; + << "Galileo code length (4 ms). coherent_integration_time = " + << sampled_ms_ << " ms will be used."; } max_dwells_ = configuration_->property(role + ".max_dwells", 1); dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); + default_dump_filename); //--- Find number of samples per spreading code (4 ms) ----------------- code_length_ = round( - fs_in_ - / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS)); + fs_in_ / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); vector_length_ = code_length_ * static_cast(sampled_ms_ / 4); int samples_per_ms = code_length_ / 4; - code_data_ = new gr_complex[vector_length_]; + code_data_ = new gr_complex[vector_length_]; code_pilot_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_cccwsr_make_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, samples_per_ms, code_length_, - dump_, dump_filename_); + doppler_max_, fs_in_, samples_per_ms, code_length_, + dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); DLOG(INFO) << "stream_to_vector(" - << stream_to_vector_->unique_id() << ")"; + << stream_to_vector_->unique_id() << ")"; DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() - << ")"; + << ")"; } else { @@ -106,7 +109,15 @@ GalileoE1PcpsCccwsrAmbiguousAcquisition::GalileoE1PcpsCccwsrAmbiguousAcquisition channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -117,10 +128,15 @@ GalileoE1PcpsCccwsrAmbiguousAcquisition::~GalileoE1PcpsCccwsrAmbiguousAcquisitio } +void GalileoE1PcpsCccwsrAmbiguousAcquisition::stop_acquisition() +{ +} + + void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -129,7 +145,7 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_channel(unsigned int channel) void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_threshold(float threshold) { - // float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + // float pfa = configuration_->property(role_+ std::to_string(channel_) + ".pfa", 0.0); // if(pfa==0.0) pfa = configuration_->property(role_+".pfa", 0.0); @@ -144,9 +160,9 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_threshold(float threshold) threshold_ = threshold; - DLOG(INFO) <<"Channel "<set_threshold(threshold_); } @@ -157,7 +173,7 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_doppler_max(unsigned int doppl { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -167,17 +183,17 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_doppler_max(unsigned int doppl void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } } void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_gnss_synchro( - Gnss_Synchro* gnss_synchro) + Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -186,43 +202,39 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_gnss_synchro( signed int GalileoE1PcpsCccwsrAmbiguousAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GalileoE1PcpsCccwsrAmbiguousAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { bool cboc = configuration_->property( - "Acquisition" + boost::lexical_cast(channel_) - + ".cboc", false); + "Acquisition" + std::to_string(channel_) + ".cboc", false); char signal[3]; strcpy(signal, "1B"); galileo_e1_code_gen_complex_sampled(code_data_, signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); + cboc, gnss_synchro_->PRN, fs_in_, 0, false); strcpy(signal, "1C"); galileo_e1_code_gen_complex_sampled(code_pilot_, signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); + cboc, gnss_synchro_->PRN, fs_in_, 0, false); acquisition_cc_->set_local_code(code_data_, code_pilot_); } @@ -231,7 +243,7 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_local_code() void GalileoE1PcpsCccwsrAmbiguousAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -243,27 +255,27 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisition::set_state(int state) } - float GalileoE1PcpsCccwsrAmbiguousAcquisition::calculate_threshold(float pfa) { - if(pfa){ /* Not implemented*/}; + if (pfa) + { /* Not implemented*/ + }; return 0.0; } void GalileoE1PcpsCccwsrAmbiguousAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } - } void GalileoE1PcpsCccwsrAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -280,4 +292,3 @@ gr::basic_block_sptr GalileoE1PcpsCccwsrAmbiguousAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.h index 228b4a527..4e472c112 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_cccwsr_ambiguous_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,12 +32,11 @@ #ifndef GNSS_SDR_GALILEO_E1_PCPS_CCCWSR_AMBIGUOUS_ACQUISITION_H_ #define GNSS_SDR_GALILEO_E1_PCPS_CCCWSR_AMBIGUOUS_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_cccwsr_acquisition_cc.h" - +#include +#include class ConfigurationInterface; @@ -45,16 +44,17 @@ class ConfigurationInterface; * \brief Adapts a PCPS CCCWSR acquisition block to an AcquisitionInterface * for Galileo E1 Signals */ -class GalileoE1PcpsCccwsrAmbiguousAcquisition: public AcquisitionInterface +class GalileoE1PcpsCccwsrAmbiguousAcquisition : public AcquisitionInterface { public: GalileoE1PcpsCccwsrAmbiguousAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1PcpsCccwsrAmbiguousAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -62,68 +62,76 @@ public: /*! * \brief Returns "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of CCCWSR algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; @@ -140,13 +148,12 @@ private: unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_data_; - std::complex * code_pilot_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_data_; + std::complex* code_pilot_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.cc index e6be855d2..b409eee0b 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_pcps_quicksync_ambiguous_acquisition.h" -#include -#include -#include -#include "galileo_e1_signal_processing.h" #include "Galileo_E1.h" #include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE1PcpsQuickSyncAmbiguousAcquisition::GalileoE1PcpsQuickSyncAmbiguousAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -51,50 +55,47 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::GalileoE1PcpsQuickSyncAmbiguousAcqui DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", - default_item_type); + default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 8); /*--- Find number of samples per spreading code (4 ms) -----------------*/ code_length_ = round( - fs_in_ - / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS)); + fs_in_ / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); int samples_per_ms = round(code_length_ / 4.0); - /*Calculate the folding factor value based on the formula described in the paper. This may be a bug, but acquisition also work by variying the folding factor at va- lues different that the expressed in the paper. In adition, it is important to point - out that by making the folding factor smaller we were able to get QuickSync work with + out that by making the folding factor smaller we were able to get QuickSync work with Galileo. Future work should be directed to test this asumption statistically.*/ - //folding_factor_ = (unsigned int)ceil(sqrt(log2(code_length_))); + //folding_factor_ = static_cast(ceil(sqrt(log2(code_length_)))); folding_factor_ = configuration_->property(role + ".folding_factor", 2); - if (sampled_ms_ % (folding_factor_*4) != 0) + if (sampled_ms_ % (folding_factor_ * 4) != 0) { LOG(WARNING) << "QuickSync Algorithm requires a coherent_integration_time" - << " multiple of "<<(folding_factor_*4)<<"ms, Value entered " - <(folding_factor_ * 4); } else { - sampled_ms_ = (int)(sampled_ms_/(folding_factor_*4)) * (folding_factor_*4); + sampled_ms_ = static_cast(sampled_ms_ / (folding_factor_ * 4)) * (folding_factor_ * 4); } LOG(WARNING) << "coherent_integration_time should be multiple of " - << "Galileo code length (4 ms). coherent_integration_time = " - << sampled_ms_ << " ms will be used."; - + << "Galileo code length (4 ms). coherent_integration_time = " + << sampled_ms_ << " ms will be used."; } // vector_length_ = (sampled_ms_/folding_factor_) * code_length_; vector_length_ = sampled_ms_ * samples_per_ms; @@ -110,27 +111,27 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::GalileoE1PcpsQuickSyncAmbiguousAcqui } dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); + default_dump_filename); code_ = new gr_complex[code_length_]; LOG(INFO) << "Vector Length: " << vector_length_ - << ", Samples per ms: " << samples_per_ms - << ", Folding factor: " << folding_factor_ - << ", Sampled ms: " << sampled_ms_ - << ", Code Length: " << code_length_; - if (item_type_.compare("gr_complex") == 0) + << ", Samples per ms: " << samples_per_ms + << ", Folding factor: " << folding_factor_ + << ", Sampled ms: " << sampled_ms_ + << ", Code Length: " << code_length_; + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_quicksync_make_acquisition_cc(folding_factor_, - sampled_ms_, max_dwells_, doppler_max_, if_, fs_in_, - samples_per_ms, code_length_, bit_transition_flag_, - dump_, dump_filename_); + sampled_ms_, max_dwells_, doppler_max_, fs_in_, + samples_per_ms, code_length_, bit_transition_flag_, + dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, - vector_length_); + vector_length_); DLOG(INFO) << "stream_to_vector_quicksync(" - << stream_to_vector_->unique_id() << ")"; + << stream_to_vector_->unique_id() << ")"; DLOG(INFO) << "acquisition_quicksync(" << acquisition_cc_->unique_id() - << ")"; + << ")"; } else { @@ -141,7 +142,15 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::GalileoE1PcpsQuickSyncAmbiguousAcqui channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -151,26 +160,28 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::~GalileoE1PcpsQuickSyncAmbiguousAcqu } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_channel(unsigned int channel) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::stop_acquisition() +{ +} + + +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_threshold(float threshold) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_threshold(float threshold) { + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa==0.0) pfa = configuration_->property(role_+".pfa", 0.0); - - if(pfa==0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -179,43 +190,40 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_threshold(float threshold) threshold_ = calculate_threshold(pfa); } - DLOG(INFO) <<"Channel "<set_threshold(threshold_); } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_doppler_max(unsigned int doppler_max) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_doppler_step(unsigned int doppler_step) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_gnss_synchro( - Gnss_Synchro* gnss_synchro) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_gnss_synchro( + Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -225,59 +233,52 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_gnss_synchro( signed int GalileoE1PcpsQuickSyncAmbiguousAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::init() +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_local_code() +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { bool cboc = configuration_->property( - "Acquisition" + boost::lexical_cast(channel_) - + ".cboc", false); + "Acquisition" + std::to_string(channel_) + ".cboc", false); - std::complex * code = new std::complex[code_length_]; + auto* code = new std::complex[code_length_]; galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); + cboc, gnss_synchro_->PRN, fs_in_, 0, false); - - for (unsigned int i = 0; i < (sampled_ms_/(folding_factor_*4)); i++) - { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); - } - - // memcpy(code_, code,sizeof(gr_complex)*code_length_); + + for (unsigned int i = 0; i < (sampled_ms_ / (folding_factor_ * 4)); i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } + + // memcpy(code_, code,sizeof(gr_complex)*code_length_); acquisition_cc_->set_local_code(code_); delete[] code; - code = NULL; + code = nullptr; } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::reset() +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -285,18 +286,17 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisition::reset() void GalileoE1PcpsQuickSyncAmbiguousAcquisition::set_state(int state) { - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_state(state); - } + if (item_type_ == "gr_complex") + { + acquisition_cc_->set_state(state); + } } - float GalileoE1PcpsQuickSyncAmbiguousAcquisition::calculate_threshold(float pfa) { unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } @@ -307,27 +307,25 @@ float GalileoE1PcpsQuickSyncAmbiguousAcquisition::calculate_threshold(float pfa) double exponent = 1.0 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); double lambda = static_cast(code_length_) / static_cast(folding_factor_); - boost::math::exponential_distribution mydist (lambda); - float threshold = static_cast(quantile(mydist,val)); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::connect(gr::top_block_sptr top_block) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } } -void -GalileoE1PcpsQuickSyncAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) +void GalileoE1PcpsQuickSyncAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -344,4 +342,3 @@ gr::basic_block_sptr GalileoE1PcpsQuickSyncAmbiguousAcquisition::get_right_block { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.h index 847419692..981cf46a6 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_quicksync_ambiguous_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,11 +32,11 @@ #ifndef GNSS_SDR_GALILEO_E1_PCPS_QUICKSYNC_AMBIGUOUS_ACQUISITION_H_ #define GNSS_SDR_GALILEO_E1_PCPS_QUICKSYNC_AMBIGUOUS_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_quicksync_acquisition_cc.h" +#include +#include class ConfigurationInterface; @@ -45,16 +45,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an * AcquisitionInterface for Galileo E1 Signals */ -class GalileoE1PcpsQuickSyncAmbiguousAcquisition: public AcquisitionInterface +class GalileoE1PcpsQuickSyncAmbiguousAcquisition : public AcquisitionInterface { public: GalileoE1PcpsQuickSyncAmbiguousAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1PcpsQuickSyncAmbiguousAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -62,71 +63,79 @@ public: /*! * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for Galileo E1 PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; @@ -144,12 +153,11 @@ private: unsigned int sampled_ms_; unsigned int max_dwells_; unsigned int folding_factor_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.cc index dae111573..20418f7ef 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_pcps_tong_ambiguous_acquisition.h" -#include -#include -#include -#include "galileo_e1_signal_processing.h" #include "Galileo_E1.h" #include "configuration_interface.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE1PcpsTongAmbiguousAcquisition::GalileoE1PcpsTongAmbiguousAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -51,21 +55,21 @@ GalileoE1PcpsTongAmbiguousAcquisition::GalileoE1PcpsTongAmbiguousAcquisition( DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", - default_item_type); + default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 4); if (sampled_ms_ % 4 != 0) { - sampled_ms_ = (int)(sampled_ms_/4) * 4; + sampled_ms_ = static_cast(sampled_ms_ / 4) * 4; LOG(WARNING) << "coherent_integration_time should be multiple of " - << "Galileo code length (4 ms). coherent_integration_time = " - << sampled_ms_ << " ms will be used."; - + << "Galileo code length (4 ms). coherent_integration_time = " + << sampled_ms_ << " ms will be used."; } tong_init_val_ = configuration->property(role + ".tong_init_val", 1); @@ -73,33 +77,31 @@ GalileoE1PcpsTongAmbiguousAcquisition::GalileoE1PcpsTongAmbiguousAcquisition( tong_max_dwells_ = configuration->property(role + ".tong_max_dwells", tong_max_val_ + 1); dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); + default_dump_filename); //--- Find number of samples per spreading code (4 ms) ----------------- code_length_ = round( - fs_in_ - / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS)); + fs_in_ / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); - vector_length_ = code_length_ * (int)(sampled_ms_/4); + vector_length_ = code_length_ * static_cast(sampled_ms_ / 4); int samples_per_ms = code_length_ / 4; code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_tong_make_acquisition_cc(sampled_ms_, doppler_max_, - if_, fs_in_, samples_per_ms, code_length_, tong_init_val_, - tong_max_val_, tong_max_dwells_, dump_, dump_filename_); + fs_in_, samples_per_ms, code_length_, tong_init_val_, + tong_max_val_, tong_max_dwells_, dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); DLOG(INFO) << "stream_to_vector(" - << stream_to_vector_->unique_id() << ")"; + << stream_to_vector_->unique_id() << ")"; DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() - << ")"; + << ")"; } else { @@ -110,7 +112,15 @@ GalileoE1PcpsTongAmbiguousAcquisition::GalileoE1PcpsTongAmbiguousAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -120,10 +130,15 @@ GalileoE1PcpsTongAmbiguousAcquisition::~GalileoE1PcpsTongAmbiguousAcquisition() } +void GalileoE1PcpsTongAmbiguousAcquisition::stop_acquisition() +{ +} + + void GalileoE1PcpsTongAmbiguousAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -132,12 +147,11 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_channel(unsigned int channel) void GalileoE1PcpsTongAmbiguousAcquisition::set_threshold(float threshold) { + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa == 0.0) pfa = configuration_->property(role_+".pfa", 0.0); - - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -146,9 +160,9 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_threshold(float threshold) threshold_ = calculate_threshold(pfa); } - DLOG(INFO) <<"Channel "<set_threshold(threshold_); } @@ -159,7 +173,7 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_doppler_max(unsigned int doppler { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -169,19 +183,18 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_doppler_max(unsigned int doppler void GalileoE1PcpsTongAmbiguousAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } - } void GalileoE1PcpsTongAmbiguousAcquisition::set_gnss_synchro( - Gnss_Synchro* gnss_synchro) + Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -190,41 +203,37 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_gnss_synchro( signed int GalileoE1PcpsTongAmbiguousAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GalileoE1PcpsTongAmbiguousAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GalileoE1PcpsTongAmbiguousAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { bool cboc = configuration_->property( - "Acquisition" + boost::lexical_cast(channel_) - + ".cboc", false); + "Acquisition" + std::to_string(channel_) + ".cboc", false); - std::complex * code = new std::complex[code_length_]; + auto* code = new std::complex[code_length_]; galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, - cboc, gnss_synchro_->PRN, fs_in_, 0, false); + cboc, gnss_synchro_->PRN, fs_in_, 0, false); - for (unsigned int i = 0; i < sampled_ms_/4; i++) + for (unsigned int i = 0; i < sampled_ms_ / 4; i++) { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); } acquisition_cc_->set_local_code(code_); @@ -236,7 +245,7 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_local_code() void GalileoE1PcpsTongAmbiguousAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -251,7 +260,7 @@ void GalileoE1PcpsTongAmbiguousAcquisition::set_state(int state) float GalileoE1PcpsTongAmbiguousAcquisition::calculate_threshold(float pfa) { unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } @@ -260,10 +269,10 @@ float GalileoE1PcpsTongAmbiguousAcquisition::calculate_threshold(float pfa) unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); - double val = pow(1.0-pfa,exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + double val = pow(1.0 - pfa, exponent); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -271,7 +280,7 @@ float GalileoE1PcpsTongAmbiguousAcquisition::calculate_threshold(float pfa) void GalileoE1PcpsTongAmbiguousAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -280,7 +289,7 @@ void GalileoE1PcpsTongAmbiguousAcquisition::connect(gr::top_block_sptr top_block void GalileoE1PcpsTongAmbiguousAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -297,4 +306,3 @@ gr::basic_block_sptr GalileoE1PcpsTongAmbiguousAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.h index dd7b7db34..95fbaee0b 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_tong_ambiguous_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,12 +32,11 @@ #ifndef GNSS_SDR_GALILEO_E1_PCPS_TONG_AMBIGUOUS_ACQUISITION_H_ #define GNSS_SDR_GALILEO_E1_PCPS_TONG_AMBIGUOUS_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_tong_acquisition_cc.h" - +#include +#include class ConfigurationInterface; @@ -45,16 +44,17 @@ class ConfigurationInterface; * \brief Adapts a PCPS Tong acquisition block to an AcquisitionInterface * for Galileo E1 Signals */ -class GalileoE1PcpsTongAmbiguousAcquisition: public AcquisitionInterface +class GalileoE1PcpsTongAmbiguousAcquisition : public AcquisitionInterface { public: GalileoE1PcpsTongAmbiguousAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1PcpsTongAmbiguousAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -62,71 +62,79 @@ public: /*! * \brief Returns "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of TONG algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for Galileo E1 TONG acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; @@ -144,12 +152,11 @@ private: unsigned int tong_init_val_; unsigned int tong_max_val_; unsigned int tong_max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.cc b/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.cc index e7701a513..c6c4f663d 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.cc +++ b/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,25 +30,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e5a_noncoherent_iq_acquisition_caf.h" -#include -#include -#include -#include "galileo_e5_signal_processing.h" #include "Galileo_E5a.h" #include "configuration_interface.h" +#include "galileo_e5_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE5aNoncoherentIQAcquisitionCaf::GalileoE5aNoncoherentIQAcquisitionCaf( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -58,12 +62,13 @@ GalileoE5aNoncoherentIQAcquisitionCaf::GalileoE5aNoncoherentIQAcquisitionCaf( item_type_ = configuration_->property(role + ".item_type", default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); - CAF_window_hz_ = configuration_->property(role + ".CAF_window_hz",0); - Zero_padding = configuration_->property(role + ".Zero_padding",0); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + CAF_window_hz_ = configuration_->property(role + ".CAF_window_hz", 0); + Zero_padding = configuration_->property(role + ".Zero_padding", 0); sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); if (sampled_ms_ > 3) { @@ -83,12 +88,12 @@ GalileoE5aNoncoherentIQAcquisitionCaf::GalileoE5aNoncoherentIQAcquisitionCaf( bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); //--- Find number of samples per spreading code (1ms)------------------------- - code_length_ = round(fs_in_ / Galileo_E5a_CODE_CHIP_RATE_HZ * Galileo_E5a_CODE_LENGTH_CHIPS); + code_length_ = round(static_cast(fs_in_) / Galileo_E5a_CODE_CHIP_RATE_HZ * static_cast(Galileo_E5a_CODE_LENGTH_CHIPS)); vector_length_ = code_length_ * sampled_ms_; - codeI_= new gr_complex[vector_length_]; - codeQ_= new gr_complex[vector_length_]; + codeI_ = new gr_complex[vector_length_]; + codeQ_ = new gr_complex[vector_length_]; both_signal_components = false; std::string sig_ = configuration_->property("Channel.signal", std::string("5X")); @@ -96,23 +101,31 @@ GalileoE5aNoncoherentIQAcquisitionCaf::GalileoE5aNoncoherentIQAcquisitionCaf( { both_signal_components = true; } - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, bit_transition_flag_, - dump_, dump_filename_, both_signal_components, CAF_window_hz_,Zero_padding); + doppler_max_, fs_in_, code_length_, code_length_, bit_transition_flag_, + dump_, dump_filename_, both_signal_components, CAF_window_hz_, Zero_padding); } else { item_size_ = sizeof(gr_complex); - LOG(WARNING) << item_type_ << " unknown acquisition item type"; + LOG(WARNING) << item_type_ << " unknown acquisition item type"; } channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -123,10 +136,15 @@ GalileoE5aNoncoherentIQAcquisitionCaf::~GalileoE5aNoncoherentIQAcquisitionCaf() } +void GalileoE5aNoncoherentIQAcquisitionCaf::stop_acquisition() +{ +} + + void GalileoE5aNoncoherentIQAcquisitionCaf::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -135,12 +153,11 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_channel(unsigned int channel) void GalileoE5aNoncoherentIQAcquisitionCaf::set_threshold(float threshold) { + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - float pfa = configuration_->property(role_+ boost::lexical_cast(channel_) + ".pfa", 0.0); + if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -151,7 +168,7 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_threshold(threshold_); } @@ -162,7 +179,7 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_max(unsigned int doppler { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -172,7 +189,7 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_max(unsigned int doppler void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } @@ -180,10 +197,10 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_step(unsigned int dopple void GalileoE5aNoncoherentIQAcquisitionCaf::set_gnss_synchro( - Gnss_Synchro* gnss_synchro) + Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -192,59 +209,56 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_gnss_synchro( signed int GalileoE5aNoncoherentIQAcquisitionCaf::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GalileoE5aNoncoherentIQAcquisitionCaf::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GalileoE5aNoncoherentIQAcquisitionCaf::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - std::complex* codeI = new std::complex[code_length_]; - std::complex* codeQ = new std::complex[code_length_]; + auto* codeI = new std::complex[code_length_]; + auto* codeQ = new std::complex[code_length_]; if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X') { char a[3]; - strcpy(a,"5I"); + strcpy(a, "5I"); galileo_e5_a_code_gen_complex_sampled(codeI, a, - gnss_synchro_->PRN, fs_in_, 0); + gnss_synchro_->PRN, fs_in_, 0); - strcpy(a,"5Q"); + strcpy(a, "5Q"); galileo_e5_a_code_gen_complex_sampled(codeQ, a, - gnss_synchro_->PRN, fs_in_, 0); + gnss_synchro_->PRN, fs_in_, 0); } else { galileo_e5_a_code_gen_complex_sampled(codeI, gnss_synchro_->Signal, - gnss_synchro_->PRN, fs_in_, 0); + gnss_synchro_->PRN, fs_in_, 0); } // WARNING: 3ms are coherently integrated. Secondary sequence (1,1,1) // is generated, and modulated in the 'block'. - if (Zero_padding == 0) // if no zero_padding + if (Zero_padding == 0) // if no zero_padding { for (unsigned int i = 0; i < sampled_ms_; i++) { - memcpy(&(codeI_[i*code_length_]), codeI, - sizeof(gr_complex)*code_length_); + memcpy(&(codeI_[i * code_length_]), codeI, + sizeof(gr_complex) * code_length_); if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X') { - memcpy(&(codeQ_[i*code_length_]), codeQ, - sizeof(gr_complex)*code_length_); + memcpy(&(codeQ_[i * code_length_]), codeQ, + sizeof(gr_complex) * code_length_); } } } @@ -252,26 +266,24 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_local_code() { // 1ms code + 1ms zero padding memcpy(&(codeI_[0]), codeI, - sizeof(gr_complex)*code_length_); + sizeof(gr_complex) * code_length_); if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X') { memcpy(&(codeQ_[0]), codeQ, - sizeof(gr_complex)*code_length_); + sizeof(gr_complex) * code_length_); } } - acquisition_cc_->set_local_code(codeI_,codeQ_); + acquisition_cc_->set_local_code(codeI_, codeQ_); delete[] codeI; delete[] codeQ; - } - } void GalileoE5aNoncoherentIQAcquisitionCaf::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -282,7 +294,7 @@ float GalileoE5aNoncoherentIQAcquisitionCaf::calculate_threshold(float pfa) { //Calculate the threshold unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } @@ -290,9 +302,9 @@ float GalileoE5aNoncoherentIQAcquisitionCaf::calculate_threshold(float pfa) unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -306,14 +318,18 @@ void GalileoE5aNoncoherentIQAcquisitionCaf::set_state(int state) void GalileoE5aNoncoherentIQAcquisitionCaf::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally } void GalileoE5aNoncoherentIQAcquisitionCaf::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect internally } diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.h b/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.h index e2a867c63..3e4d936aa 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.h +++ b/src/algorithms/acquisition/adapters/galileo_e5a_noncoherent_iq_acquisition_caf.h @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,24 +38,24 @@ #ifndef GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_ #define GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" #include "galileo_e5a_noncoherent_iq_acquisition_caf_cc.h" +#include "gnss_synchro.h" +#include class ConfigurationInterface; -class GalileoE5aNoncoherentIQAcquisitionCaf: public AcquisitionInterface +class GalileoE5aNoncoherentIQAcquisitionCaf : public AcquisitionInterface { public: GalileoE5aNoncoherentIQAcquisitionCaf(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE5aNoncoherentIQAcquisitionCaf(); - std::string role() + inline std::string role() override { return role_; } @@ -63,79 +63,85 @@ public: /*! * \brief Returns "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF"; } - size_t item_size() + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local Galileo E5a code for PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If set to 1, ensures that acquisition starts at the * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr acquisition_cc_; - gr::blocks::stream_to_vector::sptr stream_to_vector_; size_t item_size_; std::string item_type_; unsigned int vector_length_; @@ -147,16 +153,15 @@ private: unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; int Zero_padding; int CAF_window_hz_; - std::complex * codeI_; - std::complex * codeQ_; + std::complex* codeI_; + std::complex* codeQ_; bool both_signal_components; - Gnss_Synchro * gnss_synchro_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.cc new file mode 100644 index 000000000..4b7abfc8f --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.cc @@ -0,0 +1,358 @@ +/*! + * \file galileo_e5a_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_e5a_pcps_acquisition.h" +#include "Galileo_E5a.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "galileo_e5_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include +#include + + +using google::LogMessage; + + +GalileoE5aPcpsAcquisition::GalileoE5aPcpsAcquisition(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + DLOG(INFO) << "Role " << role; + + item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters_.fs_in = fs_in_; + acq_pilot_ = configuration_->property(role + ".acquire_pilot", false); + acq_iq_ = configuration_->property(role + ".acquire_iq", false); + if (acq_iq_) + { + acq_pilot_ = false; + } + dump_ = configuration_->property(role + ".dump", false); + acq_parameters_.dump = dump_; + acq_parameters_.dump_channel = configuration_->property(role + ".dump_channel", 0); + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters_.doppler_max = doppler_max_; + sampled_ms_ = 1; + max_dwells_ = configuration_->property(role + ".max_dwells", 1); + acq_parameters_.max_dwells = max_dwells_; + dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + acq_parameters_.dump_filename = dump_filename_; + bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + acq_parameters_.bit_transition_flag = bit_transition_flag_; + use_CFAR_ = configuration_->property(role + ".use_CFAR_algorithm", false); + acq_parameters_.use_CFAR_algorithm_flag = use_CFAR_; + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters_.blocking = blocking_; + + + acq_parameters_.use_automatic_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + if (acq_parameters_.use_automatic_resampler == true and item_type_ != "gr_complex") + { + LOG(WARNING) << "Galileo E5a acquisition disabled the automatic resampler feature because its item_type is not set to gr_complex"; + acq_parameters_.use_automatic_resampler = false; + } + if (acq_parameters_.use_automatic_resampler) + { + if (acq_parameters_.fs_in > Galileo_E5a_OPT_ACQ_FS_HZ) + { + acq_parameters_.resampler_ratio = floor(static_cast(acq_parameters_.fs_in) / Galileo_E5a_OPT_ACQ_FS_HZ); + uint32_t decimation = acq_parameters_.fs_in / Galileo_E5a_OPT_ACQ_FS_HZ; + while (acq_parameters_.fs_in % decimation > 0) + { + decimation--; + }; + acq_parameters_.resampler_ratio = decimation; + acq_parameters_.resampled_fs = acq_parameters_.fs_in / static_cast(acq_parameters_.resampler_ratio); + } + + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(acq_parameters_.resampled_fs) / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(acq_parameters_.resampled_fs) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / Galileo_E5a_CODE_CHIP_RATE_HZ) * static_cast(acq_parameters_.resampled_fs))); + } + else + { + acq_parameters_.resampled_fs = fs_in_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(fs_in_) / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / Galileo_E5a_CODE_CHIP_RATE_HZ) * static_cast(acq_parameters_.fs_in))); + } + + //--- Find number of samples per spreading code (1ms)------------------------- + code_length_ = static_cast(std::round(static_cast(fs_in_) / Galileo_E5a_CODE_CHIP_RATE_HZ * static_cast(Galileo_E5a_CODE_LENGTH_CHIPS))); + vector_length_ = code_length_ * sampled_ms_; + + code_ = new gr_complex[vector_length_]; + + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + } + else if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } + acq_parameters_.it_size = item_size_; + acq_parameters_.sampled_ms = sampled_ms_; + acq_parameters_.ms_per_code = 1; + acq_parameters_.samples_per_code = acq_parameters_.samples_per_ms * static_cast(GALILEO_E5a_CODE_PERIOD_MS); + acq_parameters_.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters_.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters_.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters_.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acquisition_ = pcps_make_acquisition(acq_parameters_); + + channel_ = 0; + threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } +} + + +GalileoE5aPcpsAcquisition::~GalileoE5aPcpsAcquisition() +{ + delete[] code_; +} + + +void GalileoE5aPcpsAcquisition::stop_acquisition() +{ +} + + +void GalileoE5aPcpsAcquisition::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_->set_channel(channel_); +} + + +void GalileoE5aPcpsAcquisition::set_threshold(float threshold) +{ + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); + + if (pfa == 0.0) + { + pfa = configuration_->property(role_ + ".pfa", 0.0); + } + + if (pfa == 0.0) + { + threshold_ = threshold; + } + + else + { + threshold_ = calculate_threshold(pfa); + } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + acquisition_->set_threshold(threshold_); +} + + +void GalileoE5aPcpsAcquisition::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + acquisition_->set_doppler_max(doppler_max_); +} + + +void GalileoE5aPcpsAcquisition::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + acquisition_->set_doppler_step(doppler_step_); +} + + +void GalileoE5aPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + acquisition_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GalileoE5aPcpsAcquisition::mag() +{ + return acquisition_->mag(); +} + + +void GalileoE5aPcpsAcquisition::init() +{ + acquisition_->init(); +} + + +void GalileoE5aPcpsAcquisition::set_local_code() +{ + auto* code = new gr_complex[code_length_]; + char signal_[3]; + + if (acq_iq_) + { + strcpy(signal_, "5X"); + } + else if (acq_pilot_) + { + strcpy(signal_, "5Q"); + } + else + { + strcpy(signal_, "5I"); + } + + if (acq_parameters_.use_automatic_resampler) + { + galileo_e5_a_code_gen_complex_sampled(code, signal_, gnss_synchro_->PRN, acq_parameters_.resampled_fs, 0); + } + else + { + galileo_e5_a_code_gen_complex_sampled(code, signal_, gnss_synchro_->PRN, fs_in_, 0); + } + + for (unsigned int i = 0; i < sampled_ms_; i++) + { + memcpy(code_ + (i * code_length_), code, sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); + delete[] code; +} + + +void GalileoE5aPcpsAcquisition::reset() +{ + acquisition_->set_active(true); +} + + +float GalileoE5aPcpsAcquisition::calculate_threshold(float pfa) +{ + unsigned int frequency_bins = 0; + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) + { + frequency_bins++; + } + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; + unsigned int ncells = vector_length_ * frequency_bins; + double exponent = 1 / static_cast(ncells); + double val = pow(1.0 - pfa, exponent); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); + + return threshold; +} + + +void GalileoE5aPcpsAcquisition::set_state(int state) +{ + acquisition_->set_state(state); +} + + +void GalileoE5aPcpsAcquisition::connect(gr::top_block_sptr top_block __attribute__((unused))) +{ + if (item_type_ == "gr_complex") + { + // nothing to connect + } + else if (item_type_ == "cshort") + { + // nothing to connect + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +void GalileoE5aPcpsAcquisition::disconnect(gr::top_block_sptr top_block __attribute__((unused))) +{ + if (item_type_ == "gr_complex") + { + // nothing to disconnect + } + else if (item_type_ == "cshort") + { + // nothing to disconnect + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +gr::basic_block_sptr GalileoE5aPcpsAcquisition::get_left_block() +{ + return acquisition_; +} + + +gr::basic_block_sptr GalileoE5aPcpsAcquisition::get_right_block() +{ + return acquisition_; +} + +void GalileoE5aPcpsAcquisition::set_resampler_latency(uint32_t latency_samples) +{ + acquisition_->set_resampler_latency(latency_samples); +} diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.h b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.h new file mode 100644 index 000000000..5a4d71fc1 --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition.h @@ -0,0 +1,180 @@ +/*! + * \file galileo_e5a_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GALILEO_E5A_PCPS_ACQUISITION_H_ +#define GALILEO_E5A_PCPS_ACQUISITION_H_ + + +#include "acquisition_interface.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include + +class ConfigurationInterface; + +class GalileoE5aPcpsAcquisition : public AcquisitionInterface +{ +public: + GalileoE5aPcpsAcquisition(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GalileoE5aPcpsAcquisition(); + + inline std::string role() override + { + return role_; + } + + inline std::string implementation() override + { + return "Galileo_E5a_Pcps_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local Galileo E5a code for PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ + + void set_resampler_latency(uint32_t latency_samples) override; + +private: + float calculate_threshold(float pfa); + + ConfigurationInterface* configuration_; + + pcps_acquisition_sptr acquisition_; + Acq_Conf acq_parameters_; + size_t item_size_; + + std::string item_type_; + std::string dump_filename_; + std::string role_; + + bool bit_transition_flag_; + bool dump_; + bool acq_pilot_; + bool use_CFAR_; + bool blocking_; + bool acq_iq_; + + unsigned int vector_length_; + unsigned int code_length_; + unsigned int channel_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int sampled_ms_; + unsigned int max_dwells_; + unsigned int in_streams_; + unsigned int out_streams_; + + int64_t fs_in_; + + float threshold_; + + /* + std::complex* codeI_; + std::complex* codeQ_; + */ + + gr_complex* code_; + + Gnss_Synchro* gnss_synchro_; +}; +#endif /* GALILEO_E5A_PCPS_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc new file mode 100644 index 000000000..0559ddc7e --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc @@ -0,0 +1,410 @@ +/*! + * \file galileo_e5a_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_e5a_pcps_acquisition_fpga.h" +#include "Galileo_E5a.h" +#include "configuration_interface.h" +#include "galileo_e5_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include +#include + + +using google::LogMessage; + + +GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + //printf("creating the E5A acquisition"); + pcpsconf_fpga_t acq_parameters; + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + DLOG(INFO) << "Role " << role; + + //item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); + int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in; + //acq_parameters.freq = 0; + + + //dump_ = configuration_->property(role + ".dump", false); + //acq_parameters.dump = dump_; + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + unsigned int sampled_ms = 1; + //max_dwells_ = configuration_->property(role + ".max_dwells", 1); + //acq_parameters.max_dwells = max_dwells_; + //dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + //acq_parameters.dump_filename = dump_filename_; + //bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + //acq_parameters.bit_transition_flag = bit_transition_flag_; + //use_CFAR_ = configuration_->property(role + ".use_CFAR_algorithm", false); + //acq_parameters.use_CFAR_algorithm_flag = use_CFAR_; + //blocking_ = configuration_->property(role + ".blocking", true); + //acq_parameters.blocking = blocking_; + //--- Find number of samples per spreading code (1ms)------------------------- + + acq_pilot_ = configuration_->property(role + ".acquire_pilot", false); + acq_iq_ = configuration_->property(role + ".acquire_iq", false); + if (acq_iq_) + { + acq_pilot_ = false; + } + + auto code_length = static_cast(std::round(static_cast(fs_in) / Galileo_E5a_CODE_CHIP_RATE_HZ * static_cast(Galileo_E5a_CODE_LENGTH_CHIPS))); + acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total; + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); + //printf("select_queue_Fpga = %d\n", select_queue_Fpga); + acq_parameters.select_queue_Fpga = select_queue_Fpga; + std::string default_device_name = "/dev/uio0"; + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total / sampled_ms; + acq_parameters.samples_per_code = nsamples_total; + + //vector_length_ = code_length_ * sampled_ms_; + + // compute all the GALILEO E5 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT + auto* code = new std::complex[nsamples_total]; // buffer for the local code + auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * Galileo_E5a_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32 + float max; // temporary maxima search + + //printf("creating the E5A acquisition CONT"); + //printf("nsamples_total = %d\n", nsamples_total); + + for (unsigned int PRN = 1; PRN <= Galileo_E5a_NUMBER_OF_CODES; PRN++) + { + // gr_complex* code = new gr_complex[code_length_]; + char signal_[3]; + + if (acq_iq_) + { + strcpy(signal_, "5X"); + } + else if (acq_pilot_) + { + strcpy(signal_, "5Q"); + } + else + { + strcpy(signal_, "5I"); + } + + + galileo_e5_a_code_gen_complex_sampled(code, signal_, PRN, fs_in, 0); + + // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = std::complex(0.0, 0.0); + //code[s] = 0; + } + + memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + } + } + + + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + + //code_ = new gr_complex[vector_length_]; + + // if (item_type_.compare("gr_complex") == 0) + // { + // item_size_ = sizeof(gr_complex); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // item_size_ = sizeof(lv_16sc_t); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + //acq_parameters.it_size = item_size_; + //acq_parameters.samples_per_code = code_length_; + //acq_parameters.samples_per_ms = code_length_; + //acq_parameters.sampled_ms = sampled_ms_; + //acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + //acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + //acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); + //acquisition_ = pcps_make_acquisition(acq_parameters); + //acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + //DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + //stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); + channel_ = 0; + //threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + //printf("creating the E5A acquisition end"); +} + + +GalileoE5aPcpsAcquisitionFpga::~GalileoE5aPcpsAcquisitionFpga() +{ + //delete[] code_; + delete[] d_all_fft_codes_; +} + + +void GalileoE5aPcpsAcquisitionFpga::stop_acquisition() +{ +} + + +void GalileoE5aPcpsAcquisitionFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + //acquisition_->set_channel(channel_); + acquisition_fpga_->set_channel(channel_); +} + + +void GalileoE5aPcpsAcquisitionFpga::set_threshold(float threshold) +{ + // float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); + // + // if (pfa == 0.0) + // { + // pfa = configuration_->property(role_ + ".pfa", 0.0); + // } + // + // if (pfa == 0.0) + // { + // threshold_ = threshold; + // } + // + // else + // { + // threshold_ = calculate_threshold(pfa); + // } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; + + //acquisition_->set_threshold(threshold_); + acquisition_fpga_->set_threshold(threshold); +} + + +void GalileoE5aPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + //acquisition_->set_doppler_max(doppler_max_); + acquisition_fpga_->set_doppler_max(doppler_max_); +} + + +void GalileoE5aPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + //acquisition_->set_doppler_step(doppler_step_); + acquisition_fpga_->set_doppler_step(doppler_step_); +} + + +void GalileoE5aPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + //acquisition_->set_gnss_synchro(gnss_synchro_); + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GalileoE5aPcpsAcquisitionFpga::mag() +{ + //return acquisition_->mag(); + return acquisition_fpga_->mag(); +} + + +void GalileoE5aPcpsAcquisitionFpga::init() +{ + //acquisition_->init(); + acquisition_fpga_->init(); +} + + +void GalileoE5aPcpsAcquisitionFpga::set_local_code() +{ + // gr_complex* code = new gr_complex[code_length_]; + // char signal_[3]; + // + // if (acq_iq_) + // { + // strcpy(signal_, "5X"); + // } + // else if (acq_pilot_) + // { + // strcpy(signal_, "5Q"); + // } + // else + // { + // strcpy(signal_, "5I"); + // } + // + // galileo_e5_a_code_gen_complex_sampled(code, signal_, gnss_synchro_->PRN, fs_in_, 0); + // + // for (unsigned int i = 0; i < sampled_ms_; i++) + // { + // memcpy(code_ + (i * code_length_), code, sizeof(gr_complex) * code_length_); + // } + + //acquisition_->set_local_code(code_); + acquisition_fpga_->set_local_code(); + // delete[] code; +} + + +void GalileoE5aPcpsAcquisitionFpga::reset() +{ + //acquisition_->set_active(true); + acquisition_fpga_->set_active(true); +} + + +//float GalileoE5aPcpsAcquisitionFpga::calculate_threshold(float pfa) +//{ +// unsigned int frequency_bins = 0; +// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) +// { +// frequency_bins++; +// } +// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; +// unsigned int ncells = vector_length_ * frequency_bins; +// double exponent = 1 / static_cast(ncells); +// double val = pow(1.0 - pfa, exponent); +// double lambda = double(vector_length_); +// boost::math::exponential_distribution mydist(lambda); +// float threshold = static_cast(quantile(mydist, val)); +// +// return threshold; +//} + + +void GalileoE5aPcpsAcquisitionFpga::set_state(int state) +{ + //acquisition_->set_state(state); + acquisition_fpga_->set_state(state); +} + + +void GalileoE5aPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } +} + + +void GalileoE5aPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } +} + + +gr::basic_block_sptr GalileoE5aPcpsAcquisitionFpga::get_left_block() +{ + //return stream_to_vector_; + return nullptr; +} + + +gr::basic_block_sptr GalileoE5aPcpsAcquisitionFpga::get_right_block() +{ + //return acquisition_; + return acquisition_fpga_; +} diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h new file mode 100644 index 000000000..79f0d2836 --- /dev/null +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h @@ -0,0 +1,183 @@ +/*! + * \file galileo_e5a_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ +#define GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ + + +#include "acquisition_interface.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" +#include +#include +#include + +class ConfigurationInterface; + +class GalileoE5aPcpsAcquisitionFpga : public AcquisitionInterface +{ +public: + GalileoE5aPcpsAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GalileoE5aPcpsAcquisitionFpga(); + + inline std::string role() override + { + return role_; + } + + inline std::string implementation() override + { + return "Galileo_E5a_Pcps_Acquisition_Fpga"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local Galileo E5a code for PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + //float calculate_threshold(float pfa); + + ConfigurationInterface* configuration_; + + pcps_acquisition_fpga_sptr acquisition_fpga_; + gr::blocks::stream_to_vector::sptr stream_to_vector_; + + size_t item_size_; + + std::string item_type_; + std::string dump_filename_; + std::string role_; + + bool bit_transition_flag_; + bool dump_; + bool acq_pilot_; + bool use_CFAR_; + bool blocking_; + bool acq_iq_; + + unsigned int vector_length_; + unsigned int code_length_; + unsigned int channel_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int sampled_ms_; + unsigned int max_dwells_; + unsigned int in_streams_; + unsigned int out_streams_; + + int64_t fs_in_; + + + float threshold_; + + /* + std::complex* codeI_; + std::complex* codeQ_; + */ + + gr_complex* code_; + + Gnss_Synchro* gnss_synchro_; + + // extra for the FPGA + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts +}; +#endif /* GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc new file mode 100644 index 000000000..050190ee7 --- /dev/null +++ b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc @@ -0,0 +1,339 @@ +/*! + * \file glonass_l1_ca_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Glonass L1 C/A signals + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_pcps_acquisition.h" +#include "GLONASS_L1_L2_CA.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "glonass_l1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include + + +using google::LogMessage; + + +GlonassL1CaPcpsAcquisition::GlonassL1CaPcpsAcquisition( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + Acq_Conf acq_parameters = Acq_Conf(); + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./data/acquisition.dat"; + + DLOG(INFO) << "role " << role; + + item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in_; + acq_parameters.samples_per_chip = static_cast(ceil(GLONASS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters.fs_in))); + dump_ = configuration_->property(role + ".dump", false); + acq_parameters.dump = dump_; + acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters.blocking = blocking_; + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms_; + bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + acq_parameters.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + max_dwells_ = configuration_->property(role + ".max_dwells", 1); + acq_parameters.max_dwells = max_dwells_; + dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + acq_parameters.dump_filename = dump_filename_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::round(static_cast(fs_in_) / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS))); + + vector_length_ = code_length_ * sampled_ms_; + + if (bit_transition_flag_) + { + vector_length_ *= 2; + } + + code_ = new gr_complex[vector_length_]; + + if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + } + else + { + item_size_ = sizeof(gr_complex); + } + acq_parameters.it_size = item_size_; + acq_parameters.sampled_ms = sampled_ms_; + acq_parameters.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters.ms_per_code = 1; + acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast(GLONASS_L1_CA_CODE_PERIOD * 1000.0); + acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acquisition_ = pcps_make_acquisition(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; + + if (item_type_ == "cbyte") + { + cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + float_to_complex_ = gr::blocks::float_to_complex::make(); + } + + channel_ = 0; + threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } +} + + +GlonassL1CaPcpsAcquisition::~GlonassL1CaPcpsAcquisition() +{ + delete[] code_; +} + + +void GlonassL1CaPcpsAcquisition::stop_acquisition() +{ +} + + +void GlonassL1CaPcpsAcquisition::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_->set_channel(channel_); +} + + +void GlonassL1CaPcpsAcquisition::set_threshold(float threshold) +{ + float pfa = configuration_->property(role_ + ".pfa", 0.0); + + if (pfa == 0.0) + { + threshold_ = threshold; + } + else + { + threshold_ = calculate_threshold(pfa); + } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + acquisition_->set_threshold(threshold_); +} + + +void GlonassL1CaPcpsAcquisition::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + + acquisition_->set_doppler_max(doppler_max_); +} + + +void GlonassL1CaPcpsAcquisition::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + + acquisition_->set_doppler_step(doppler_step_); +} + + +void GlonassL1CaPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + + acquisition_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GlonassL1CaPcpsAcquisition::mag() +{ + return acquisition_->mag(); +} + + +void GlonassL1CaPcpsAcquisition::init() +{ + acquisition_->init(); + + set_local_code(); +} + + +void GlonassL1CaPcpsAcquisition::set_local_code() +{ + auto* code = new std::complex[code_length_]; + + glonass_l1_ca_code_gen_complex_sampled(code, /* gnss_synchro_->PRN,*/ fs_in_, 0); + + for (unsigned int i = 0; i < sampled_ms_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); + delete[] code; +} + + +void GlonassL1CaPcpsAcquisition::reset() +{ + acquisition_->set_active(true); +} + + +void GlonassL1CaPcpsAcquisition::set_state(int state) +{ + acquisition_->set_state(state); +} + + +float GlonassL1CaPcpsAcquisition::calculate_threshold(float pfa) +{ + //Calculate the threshold + unsigned int frequency_bins = 0; + /* + for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + { + frequency_bins++; + } + */ + + frequency_bins = (2 * doppler_max_ + doppler_step_) / doppler_step_; + + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; + unsigned int ncells = vector_length_ * frequency_bins; + double exponent = 1 / static_cast(ncells); + double val = pow(1.0 - pfa, exponent); + auto lambda = static_cast(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); + + return threshold; +} + + +void GlonassL1CaPcpsAcquisition::connect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to connect + } + else if (item_type_ == "cshort") + { + // nothing to connect + } + else if (item_type_ == "cbyte") + { + top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->connect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +void GlonassL1CaPcpsAcquisition::disconnect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to disconnect + } + else if (item_type_ == "cshort") + { + // nothing to disconnect + } + else if (item_type_ == "cbyte") + { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex + top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +gr::basic_block_sptr GlonassL1CaPcpsAcquisition::get_left_block() +{ + if (item_type_ == "gr_complex") + { + return acquisition_; + } + if (item_type_ == "cshort") + { + return acquisition_; + } + if (item_type_ == "cbyte") + { + return cbyte_to_float_x2_; + } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; +} + + +gr::basic_block_sptr GlonassL1CaPcpsAcquisition::get_right_block() +{ + return acquisition_; +} diff --git a/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.h b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.h new file mode 100644 index 000000000..17affc67c --- /dev/null +++ b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.h @@ -0,0 +1,172 @@ +/*! + * \file glonass_l1_ca_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Glonass L1 C/A signals + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_PCPS_ACQUISITION_H_ +#define GNSS_SDR_GLONASS_L1_CA_PCPS_ACQUISITION_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include +#include + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L1 C/A signals + */ +class GlonassL1CaPcpsAcquisition : public AcquisitionInterface +{ +public: + GlonassL1CaPcpsAcquisition(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL1CaPcpsAcquisition(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GLONASS_L1_CA_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GLONASS_L1_CA_PCPS_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + pcps_acquisition_sptr acquisition_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + size_t item_size_; + std::string item_type_; + unsigned int vector_length_; + unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + unsigned int channel_; + float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int sampled_ms_; + unsigned int max_dwells_; + int64_t fs_in_; + bool dump_; + bool blocking_; + std::string dump_filename_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + + float calculate_threshold(float pfa); +}; + +#endif /* GNSS_SDR_GLONASS_L1_CA_PCPS_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.cc new file mode 100644 index 000000000..93aa9736d --- /dev/null +++ b/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.cc @@ -0,0 +1,338 @@ +/*! + * \file glonass_l2_ca_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Glonass L2 C/A signals + * \author Damian Miralles, 2018, dmiralles2009@gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_pcps_acquisition.h" +#include "GLONASS_L1_L2_CA.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "glonass_l2_signal_processing.h" +#include "gnss_sdr_flags.h" +#include +#include + + +using google::LogMessage; + + +GlonassL2CaPcpsAcquisition::GlonassL2CaPcpsAcquisition( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + Acq_Conf acq_parameters = Acq_Conf(); + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./data/acquisition.dat"; + + DLOG(INFO) << "role " << role; + + item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in_; + acq_parameters.samples_per_chip = static_cast(ceil(GLONASS_L2_CA_CHIP_PERIOD * static_cast(acq_parameters.fs_in))); + dump_ = configuration_->property(role + ".dump", false); + acq_parameters.dump = dump_; + acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters.blocking = blocking_; + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); + bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + acq_parameters.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + max_dwells_ = configuration_->property(role + ".max_dwells", 1); + acq_parameters.max_dwells = max_dwells_; + + dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + acq_parameters.dump_filename = dump_filename_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::round(static_cast(fs_in_) / (GLONASS_L2_CA_CODE_RATE_HZ / GLONASS_L2_CA_CODE_LENGTH_CHIPS))); + + vector_length_ = code_length_ * sampled_ms_; + + if (bit_transition_flag_) + { + vector_length_ *= 2; + } + + code_ = new gr_complex[vector_length_]; + + if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + } + else + { + item_size_ = sizeof(gr_complex); + } + acq_parameters.it_size = item_size_; + acq_parameters.sampled_ms = sampled_ms_; + acq_parameters.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters.ms_per_code = 1; + acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast(GLONASS_L2_CA_CODE_PERIOD * 1000.0); + acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acquisition_ = pcps_make_acquisition(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; + + if (item_type_ == "cbyte") + { + cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + float_to_complex_ = gr::blocks::float_to_complex::make(); + } + + channel_ = 0; + threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } +} + + +GlonassL2CaPcpsAcquisition::~GlonassL2CaPcpsAcquisition() +{ + delete[] code_; +} + + +void GlonassL2CaPcpsAcquisition::stop_acquisition() +{ +} + + +void GlonassL2CaPcpsAcquisition::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_->set_channel(channel_); +} + + +void GlonassL2CaPcpsAcquisition::set_threshold(float threshold) +{ + float pfa = configuration_->property(role_ + ".pfa", 0.0); + + if (pfa == 0.0) + { + threshold_ = threshold; + } + else + { + threshold_ = calculate_threshold(pfa); + } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + acquisition_->set_threshold(threshold_); +} + + +void GlonassL2CaPcpsAcquisition::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + + acquisition_->set_doppler_max(doppler_max_); +} + + +void GlonassL2CaPcpsAcquisition::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + + acquisition_->set_doppler_step(doppler_step_); +} + + +void GlonassL2CaPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + + acquisition_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GlonassL2CaPcpsAcquisition::mag() +{ + return acquisition_->mag(); +} + + +void GlonassL2CaPcpsAcquisition::init() +{ + acquisition_->init(); + + set_local_code(); +} + + +void GlonassL2CaPcpsAcquisition::set_local_code() +{ + auto* code = new std::complex[code_length_]; + + glonass_l2_ca_code_gen_complex_sampled(code, /* gnss_synchro_->PRN,*/ fs_in_, 0); + + for (unsigned int i = 0; i < sampled_ms_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); + delete[] code; +} + + +void GlonassL2CaPcpsAcquisition::reset() +{ + acquisition_->set_active(true); +} + + +void GlonassL2CaPcpsAcquisition::set_state(int state) +{ + acquisition_->set_state(state); +} + + +float GlonassL2CaPcpsAcquisition::calculate_threshold(float pfa) +{ + //Calculate the threshold + unsigned int frequency_bins = 0; + /* + for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + { + frequency_bins++; + } + */ + + frequency_bins = (2 * doppler_max_ + doppler_step_) / doppler_step_; + + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; + unsigned int ncells = vector_length_ * frequency_bins; + double exponent = 1 / static_cast(ncells); + double val = pow(1.0 - pfa, exponent); + auto lambda = static_cast(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); + + return threshold; +} + + +void GlonassL2CaPcpsAcquisition::connect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to connect + } + else if (item_type_ == "cshort") + { + // nothing to connect + } + else if (item_type_ == "cbyte") + { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex + top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->connect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +void GlonassL2CaPcpsAcquisition::disconnect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to disconnect + } + else if (item_type_ == "cshort") + { + // nothing to disconnect + } + else if (item_type_ == "cbyte") + { + top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +gr::basic_block_sptr GlonassL2CaPcpsAcquisition::get_left_block() +{ + if (item_type_ == "gr_complex") + { + return acquisition_; + } + if (item_type_ == "cshort") + { + return acquisition_; + } + if (item_type_ == "cbyte") + { + return cbyte_to_float_x2_; + } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; +} + + +gr::basic_block_sptr GlonassL2CaPcpsAcquisition::get_right_block() +{ + return acquisition_; +} diff --git a/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.h b/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.h new file mode 100644 index 000000000..ad99d9d5a --- /dev/null +++ b/src/algorithms/acquisition/adapters/glonass_l2_ca_pcps_acquisition.h @@ -0,0 +1,171 @@ +/*! + * \file glonass_l2_ca_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Glonass L2 C/A signals + * \author Damian Miralles, 2018, dmiralles2009@gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_PCPS_ACQUISITION_H_ +#define GNSS_SDR_GLONASS_L2_CA_PCPS_ACQUISITION_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include +#include + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GLONASS L2 C/A signals + */ +class GlonassL2CaPcpsAcquisition : public AcquisitionInterface +{ +public: + GlonassL2CaPcpsAcquisition(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL2CaPcpsAcquisition(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GLONASS_L2_CA_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GLONASS_L2_CA_PCPS_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GLONASS L2/CA PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + pcps_acquisition_sptr acquisition_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + size_t item_size_; + std::string item_type_; + unsigned int vector_length_; + unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + unsigned int channel_; + float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int sampled_ms_; + unsigned int max_dwells_; + int64_t fs_in_; + bool dump_; + bool blocking_; + std::string dump_filename_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + + float calculate_threshold(float pfa); +}; + +#endif /* GNSS_SDR_GLONASS_L2_CA_PCPS_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.cc index 8ae477856..ce0ea4065 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.cc @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,79 +28,116 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_acquisition.h" +#include "GPS_L1_CA.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" #include #include -#include "gps_sdr_signal_processing.h" -#include "GPS_L1_CA.h" -#include "configuration_interface.h" using google::LogMessage; + GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./data/acquisition.dat"; + std::string default_dump_filename = "./acquisition.mat"; DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", default_item_type); - - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters_.fs_in = fs_in_; dump_ = configuration_->property(role + ".dump", false); + acq_parameters_.dump = dump_; + acq_parameters_.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters_.blocking = blocking_; doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters_.doppler_max = doppler_max_; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); - + acq_parameters_.sampled_ms = sampled_ms_; + acq_parameters_.ms_per_code = 1; bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - use_CFAR_algorithm_flag_=configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions - + acq_parameters_.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters_.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; max_dwells_ = configuration_->property(role + ".max_dwells", 1); - + acq_parameters_.max_dwells = max_dwells_; dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - - //--- Find number of samples per spreading code ------------------------- - code_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - - vector_length_ = code_length_ * sampled_ms_; - - if( bit_transition_flag_ ) + acq_parameters_.dump_filename = dump_filename_; + acq_parameters_.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters_.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters_.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters_.use_automatic_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + if (acq_parameters_.use_automatic_resampler == true and item_type_ != "gr_complex") { - vector_length_ *= 2; + LOG(WARNING) << "GPS L1 CA acquisition disabled the automatic resampler feature because its item_type is not set to gr_complex"; + acq_parameters_.use_automatic_resampler = false; + } + if (acq_parameters_.use_automatic_resampler) + { + if (acq_parameters_.fs_in > GPS_L1_CA_OPT_ACQ_FS_HZ) + { + acq_parameters_.resampler_ratio = floor(static_cast(acq_parameters_.fs_in) / GPS_L1_CA_OPT_ACQ_FS_HZ); + uint32_t decimation = acq_parameters_.fs_in / GPS_L1_CA_OPT_ACQ_FS_HZ; + while (acq_parameters_.fs_in % decimation > 0) + { + decimation--; + }; + acq_parameters_.resampler_ratio = decimation; + acq_parameters_.resampled_fs = acq_parameters_.fs_in / static_cast(acq_parameters_.resampler_ratio); + } + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(acq_parameters_.resampled_fs) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(acq_parameters_.resampled_fs) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters_.resampled_fs))); + } + else + { + acq_parameters_.resampled_fs = fs_in_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(fs_in_) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters_.fs_in))); } + acq_parameters_.samples_per_code = acq_parameters_.samples_per_ms * static_cast(GPS_L1_CA_CODE_PERIOD * 1000.0); + vector_length_ = std::floor(acq_parameters_.sampled_ms * acq_parameters_.samples_per_ms) * (acq_parameters_.bit_transition_flag ? 2 : 1); code_ = new gr_complex[vector_length_]; - if (item_type_.compare("cshort") == 0 ) + if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); - acquisition_sc_ = pcps_make_acquisition_sc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_sc_->unique_id() << ")"; - - }else{ - item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() << ")"; + } + else + { + item_size_ = sizeof(gr_complex); } - stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - - if (item_type_.compare("cbyte") == 0) + acq_parameters_.it_size = item_size_; + acq_parameters_.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acquisition_ = pcps_make_acquisition(acq_parameters_); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; + + if (item_type_ == "cbyte") { cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); float_to_complex_ = gr::blocks::float_to_complex::make(); @@ -109,7 +146,15 @@ GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -119,18 +164,15 @@ GpsL1CaPcpsAcquisition::~GpsL1CaPcpsAcquisition() } +void GpsL1CaPcpsAcquisition::stop_acquisition() +{ +} + + void GpsL1CaPcpsAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_channel(channel_); - } - else - { - acquisition_cc_->set_channel(channel_); - } - + acquisition_->set_channel(channel_); } @@ -138,7 +180,7 @@ void GpsL1CaPcpsAcquisition::set_threshold(float threshold) { float pfa = configuration_->property(role_ + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -149,15 +191,7 @@ void GpsL1CaPcpsAcquisition::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_threshold(threshold_); - } - else - { - acquisition_cc_->set_threshold(threshold_); - } + acquisition_->set_threshold(threshold_); } @@ -165,14 +199,7 @@ void GpsL1CaPcpsAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_max(doppler_max_); - } - else - { - acquisition_cc_->set_doppler_max(doppler_max_); - } + acquisition_->set_doppler_max(doppler_max_); } @@ -180,118 +207,70 @@ void GpsL1CaPcpsAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_step(doppler_step_); - } - else - { - acquisition_cc_->set_doppler_step(doppler_step_); - } - + acquisition_->set_doppler_step(doppler_step_); } + void GpsL1CaPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_gnss_synchro(gnss_synchro_); - } - else - { - acquisition_cc_->set_gnss_synchro(gnss_synchro_); - } + acquisition_->set_gnss_synchro(gnss_synchro_); } signed int GpsL1CaPcpsAcquisition::mag() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_->mag(); - } - else - { - return acquisition_cc_->mag(); - } + return acquisition_->mag(); } void GpsL1CaPcpsAcquisition::init() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->init(); - } - else - { - acquisition_cc_->init(); - } - - set_local_code(); + acquisition_->init(); } void GpsL1CaPcpsAcquisition::set_local_code() { + auto* code = new std::complex[code_length_]; - std::complex* code = new std::complex[code_length_]; - - gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); - - for (unsigned int i = 0; i < sampled_ms_; i++) + if (acq_parameters_.use_automatic_resampler) { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); - } - - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_local_code(code_); + gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, acq_parameters_.resampled_fs, 0); } else { - acquisition_cc_->set_local_code(code_); + gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); + } + for (unsigned int i = 0; i < sampled_ms_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); } + acquisition_->set_local_code(code_); delete[] code; } void GpsL1CaPcpsAcquisition::reset() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_active(true); - } - else - { - acquisition_cc_->set_active(true); - } + acquisition_->set_active(true); } void GpsL1CaPcpsAcquisition::set_state(int state) { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_state(state); - } - else - { - acquisition_cc_->set_state(state); - } + acquisition_->set_state(state); } - float GpsL1CaPcpsAcquisition::calculate_threshold(float pfa) { //Calculate the threshold unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } @@ -299,9 +278,9 @@ float GpsL1CaPcpsAcquisition::calculate_threshold(float pfa) unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -309,20 +288,21 @@ float GpsL1CaPcpsAcquisition::calculate_threshold(float pfa) void GpsL1CaPcpsAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to connect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->connect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to connect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->connect(float_to_complex_, 0, acquisition_, 0); } else { @@ -333,22 +313,19 @@ void GpsL1CaPcpsAcquisition::connect(gr::top_block_sptr top_block) void GpsL1CaPcpsAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->disconnect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { - // Since a byte-based acq implementation is not available, - // we just convert cshorts to gr_complex top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); } else { @@ -359,35 +336,30 @@ void GpsL1CaPcpsAcquisition::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr GpsL1CaPcpsAcquisition::get_left_block() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cshort") == 0) + if (item_type_ == "cshort") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cbyte") == 0) + if (item_type_ == "cbyte") { return cbyte_to_float_x2_; } - else - { - LOG(WARNING) << item_type_ << " unknown acquisition item type"; - return nullptr; - } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; } gr::basic_block_sptr GpsL1CaPcpsAcquisition::get_right_block() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_; - } - else - { - return acquisition_cc_; - } + return acquisition_; } +void GpsL1CaPcpsAcquisition::set_resampler_latency(uint32_t latency_samples) +{ + acquisition_->set_resampler_latency(latency_samples); +} diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.h index a32cc81a4..efca26bdd 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,16 +36,14 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_H_ -#include -#include -#include -#include "gnss_synchro.h" +#include "acq_conf.h" #include "acquisition_interface.h" -#include "pcps_acquisition_cc.h" -#include "pcps_acquisition_sc.h" #include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include #include - +#include class ConfigurationInterface; @@ -54,16 +52,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface * for GPS L1 C/A signals */ -class GpsL1CaPcpsAcquisition: public AcquisitionInterface +class GpsL1CaPcpsAcquisition : public AcquisitionInterface { public: GpsL1CaPcpsAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -71,77 +70,89 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ + + void set_resampler_latency(uint32_t latency_samples) override; + private: ConfigurationInterface* configuration_; - pcps_acquisition_cc_sptr acquisition_cc_; - pcps_acquisition_sc_sptr acquisition_sc_; - gr::blocks::stream_to_vector::sptr stream_to_vector_; + pcps_acquisition_sptr acquisition_; + Acq_Conf acq_parameters_; gr::blocks::float_to_complex::sptr float_to_complex_; complex_byte_to_float_x2_sptr cbyte_to_float_x2_; size_t item_size_; @@ -156,12 +167,12 @@ private: unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; + bool blocking_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc index 254e71369..4e16b54ec 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,51 +27,64 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_acquisition_fine_doppler.h" -#include -#include "gps_sdr_signal_processing.h" #include "GPS_L1_CA.h" +#include "acq_conf.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include using google::LogMessage; + GpsL1CaPcpsAcquisitionFineDoppler::GpsL1CaPcpsAcquisitionFineDoppler( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./data/acquisition.dat"; + std::string default_dump_filename = "./acquisition.mat"; DLOG(INFO) << "role " << role; + Acq_Conf acq_parameters = Acq_Conf(); item_type_ = configuration->property(role + ".item_type", default_item_type); - fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in_; + acq_parameters.samples_per_chip = static_cast(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters.fs_in))); dump_ = configuration->property(role + ".dump", false); + acq_parameters.dump = dump_; dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + acq_parameters.dump_filename = dump_filename_; doppler_max_ = configuration->property(role + ".doppler_max", 5000); - doppler_min_ = configuration->property(role + ".doppler_min", -5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; sampled_ms_ = configuration->property(role + ".coherent_integration_time_ms", 1); - max_dwells_= configuration->property(role + ".max_dwells", 1); - - //--- Find number of samples per spreading code ------------------------- - vector_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + acq_parameters.sampled_ms = sampled_ms_; + max_dwells_ = configuration->property(role + ".max_dwells", 1); + acq_parameters.max_dwells = max_dwells_; + acq_parameters.blocking_on_standby = configuration->property(role + ".blocking_on_standby", false); + + //--- Find number of samples per spreading code ------------------------- + vector_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + acq_parameters.samples_per_ms = vector_length_; code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(max_dwells_,sampled_ms_, - doppler_max_, doppler_min_, if_, fs_in_, vector_length_, - dump_, dump_filename_); + acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(acq_parameters); } else { @@ -82,7 +95,15 @@ GpsL1CaPcpsAcquisitionFineDoppler::GpsL1CaPcpsAcquisitionFineDoppler( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -92,6 +113,11 @@ GpsL1CaPcpsAcquisitionFineDoppler::~GpsL1CaPcpsAcquisitionFineDoppler() } +void GpsL1CaPcpsAcquisitionFineDoppler::stop_acquisition() +{ +} + + void GpsL1CaPcpsAcquisitionFineDoppler::set_channel(unsigned int channel) { channel_ = channel; @@ -129,14 +155,14 @@ void GpsL1CaPcpsAcquisitionFineDoppler::set_gnss_synchro(Gnss_Synchro* gnss_sync signed int GpsL1CaPcpsAcquisitionFineDoppler::mag() { - return acquisition_cc_->mag(); + return acquisition_cc_->mag(); } void GpsL1CaPcpsAcquisitionFineDoppler::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } @@ -153,16 +179,26 @@ void GpsL1CaPcpsAcquisitionFineDoppler::reset() } +void GpsL1CaPcpsAcquisitionFineDoppler::set_state(int state) +{ + acquisition_cc_->set_state(state); +} + + void GpsL1CaPcpsAcquisitionFineDoppler::connect(boost::shared_ptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } void GpsL1CaPcpsAcquisitionFineDoppler::disconnect(boost::shared_ptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -177,4 +213,3 @@ boost::shared_ptr GpsL1CaPcpsAcquisitionFineDoppler::get_right_ { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h index 0b6796a8b..b1b64d6eb 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,12 +34,10 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_ -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_acquisition_fine_doppler_cc.h" - - +#include class ConfigurationInterface; @@ -47,16 +45,17 @@ class ConfigurationInterface; * \brief This class Adapts a PCPS acquisition block with fine Doppler estimation to an AcquisitionInterface for * GPS L1 C/A signals */ -class GpsL1CaPcpsAcquisitionFineDoppler: public AcquisitionInterface +class GpsL1CaPcpsAcquisitionFineDoppler : public AcquisitionInterface { public: GpsL1CaPcpsAcquisitionFineDoppler(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsAcquisitionFineDoppler(); - std::string role() + inline std::string role() override { return role_; } @@ -64,63 +63,76 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_Acquisition_Fine_Doppler" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_Acquisition_Fine_Doppler"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(boost::shared_ptr top_block); - void disconnect(boost::shared_ptr top_block); - boost::shared_ptr get_left_block(); - boost::shared_ptr get_right_block(); + void connect(boost::shared_ptr top_block) override; + void disconnect(boost::shared_ptr top_block) override; + boost::shared_ptr get_left_block() override; + boost::shared_ptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: pcps_acquisition_fine_doppler_cc_sptr acquisition_cc_; @@ -131,15 +143,13 @@ private: float threshold_; int doppler_max_; unsigned int doppler_step_; - int doppler_min_; unsigned int sampled_ms_; int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc new file mode 100644 index 000000000..6ddfa4616 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc @@ -0,0 +1,279 @@ +/*! + * \file gps_l1_ca_pcps_acquisition_fpga.cc + * \brief Adapts a PCPS acquisition block to an FPGA AcquisitionInterface + * for GPS L1 C/A signals + * \authors
    + *
  • Marc Majoral, 2018. mmajoral(at)cttc.es + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena(at)gmail.com + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include +#include +#include + + +#define NUM_PRNs 32 + +using google::LogMessage; + + +GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + pcpsconf_fpga_t acq_parameters; + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + + DLOG(INFO) << "role " << role; + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + //fs_in = fs_in/2.0; // downampling filter + //printf("####### DEBUG Acq: fs_in = %d\n", fs_in); + acq_parameters.fs_in = fs_in; + acq_parameters.samples_per_code = static_cast(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters.fs_in))); + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms; + auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total; + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.select_queue_Fpga = select_queue_Fpga; + std::string default_device_name = "/dev/uio0"; + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total / sampled_ms; + acq_parameters.samples_per_code = nsamples_total; + + // compute all the GPS L1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + auto* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT + // allocate memory to compute all the PRNs and compute all the possible codes + auto* code = new std::complex[nsamples_total]; // buffer for the local code + auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 + float max; // temporary maxima search + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0); // generate PRN code + // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = std::complex(0.0, 0.0); + //code[s] = 0; + } + int offset = 0; + memcpy(fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + + + // // debug + // char filename[25]; + // FILE *fid; + // sprintf(filename,"fft_gps_prn%d.txt", PRN); + // fid = fopen(filename, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid, "%f\n", fft_codes_padded[kk].real()); + // fprintf(fid, "%f\n", fft_codes_padded[kk].imag()); + // } + // fclose(fid); + + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), + // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), + // static_cast(16*floor(fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + // static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + } + + + //// // debug + // char filename2[25]; + // FILE *fid2; + // sprintf(filename2,"fft_gps_prn%d_norm_new.txt", PRN); + // fid2 = fopen(filename2, "w"); + // for (unsigned int kk=0;kk< nsamples_total; kk++) + // { + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); + // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); + // } + // fclose(fid2); + } + + //acq_parameters + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + channel_ = 0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; +} + + +GpsL1CaPcpsAcquisitionFpga::~GpsL1CaPcpsAcquisitionFpga() +{ + delete[] d_all_fft_codes_; +} + + +void GpsL1CaPcpsAcquisitionFpga::stop_acquisition() +{ +} + + +void GpsL1CaPcpsAcquisitionFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_fpga_->set_channel(channel_); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_threshold(float threshold) +{ + // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. + // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; + acquisition_fpga_->set_threshold(threshold); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + acquisition_fpga_->set_doppler_max(doppler_max_); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + acquisition_fpga_->set_doppler_step(doppler_step_); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GpsL1CaPcpsAcquisitionFpga::mag() +{ + return acquisition_fpga_->mag(); +} + + +void GpsL1CaPcpsAcquisitionFpga::init() +{ + acquisition_fpga_->init(); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_local_code() +{ + acquisition_fpga_->set_local_code(); +} + + +void GpsL1CaPcpsAcquisitionFpga::reset() +{ + acquisition_fpga_->set_active(true); +} + + +void GpsL1CaPcpsAcquisitionFpga::set_state(int state) +{ + acquisition_fpga_->set_state(state); +} + +void GpsL1CaPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) +{ + // nothing to connect +} + + +void GpsL1CaPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) +{ + // nothing to disconnect +} + + +gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_left_block() +{ + return nullptr; +} + + +gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_right_block() +{ + return acquisition_fpga_; +} diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h new file mode 100644 index 000000000..015de1d39 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h @@ -0,0 +1,158 @@ +/*! + * \file gps_l1_ca_pcps_acquisition_fpga.h + * \brief Adapts a PCPS acquisition block that uses the FPGA to + * an AcquisitionInterface for GPS L1 C/A signals + * \authors
    + *
  • Marc Majoral, 2018. mmajoral(at)cttc.es + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena(at)gmail.com + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ + +#include "acquisition_interface.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" +#include +#include + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L1 C/A signals + */ +class GpsL1CaPcpsAcquisitionFpga : public AcquisitionInterface +{ +public: + GpsL1CaPcpsAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL1CaPcpsAcquisitionFpga(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GPS_L1_CA_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GPS_L1_CA_PCPS_Acquisition_Fpga"; + } + + inline size_t item_size() override + { + size_t item_size = sizeof(lv_16sc_t); + return item_size; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + pcps_acquisition_fpga_sptr acquisition_fpga_; + unsigned int channel_; + unsigned int doppler_max_; + unsigned int doppler_step_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts +}; + +#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.cc index beb45c323..fb7a140b7 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,23 +27,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_assisted_acquisition.h" -#include -#include "gps_sdr_signal_processing.h" #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include + using google::LogMessage; + GpsL1CaPcpsAssistedAcquisition::GpsL1CaPcpsAssistedAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_item_type = "gr_complex"; std::string default_dump_filename = "./data/acquisition.dat"; @@ -51,28 +57,27 @@ GpsL1CaPcpsAssistedAcquisition::GpsL1CaPcpsAssistedAcquisition( DLOG(INFO) << "role " << role; item_type_ = configuration->property(role + ".item_type", default_item_type); - fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration->property(role + ".dump", false); doppler_max_ = configuration->property(role + ".doppler_max", 5000); - doppler_min_ = configuration->property(role + ".doppler_min", -5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + doppler_min_ = configuration->property(role + ".doppler_min", -doppler_max_); sampled_ms_ = configuration->property(role + ".coherent_integration_time_ms", 1); - max_dwells_= configuration->property(role + ".max_dwells", 1); + max_dwells_ = configuration->property(role + ".max_dwells", 1); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); //--- Find number of samples per spreading code ------------------------- - vector_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + vector_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_make_assisted_acquisition_cc(max_dwells_, sampled_ms_, - doppler_max_, doppler_min_, if_, fs_in_, vector_length_, - dump_, dump_filename_); - + doppler_max_, doppler_min_, fs_in_, vector_length_, + dump_, dump_filename_); } else { @@ -83,7 +88,15 @@ GpsL1CaPcpsAssistedAcquisition::GpsL1CaPcpsAssistedAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -93,6 +106,11 @@ GpsL1CaPcpsAssistedAcquisition::~GpsL1CaPcpsAssistedAcquisition() } +void GpsL1CaPcpsAssistedAcquisition::stop_acquisition() +{ +} + + void GpsL1CaPcpsAssistedAcquisition::set_channel(unsigned int channel) { channel_ = channel; @@ -130,14 +148,14 @@ void GpsL1CaPcpsAssistedAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro signed int GpsL1CaPcpsAssistedAcquisition::mag() { - return acquisition_cc_->mag(); + return acquisition_cc_->mag(); } void GpsL1CaPcpsAssistedAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GpsL1CaPcpsAssistedAcquisition::set_local_code() @@ -154,14 +172,18 @@ void GpsL1CaPcpsAssistedAcquisition::reset() void GpsL1CaPcpsAssistedAcquisition::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } void GpsL1CaPcpsAssistedAcquisition::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -176,4 +198,3 @@ gr::basic_block_sptr GpsL1CaPcpsAssistedAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.h index d2faf3f51..04b653440 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_assisted_acquisition.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,12 +34,10 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_ASSISTED_ACQUISITION_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_ASSISTED_ACQUISITION_H_ -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_assisted_acquisition_cc.h" - - +#include class ConfigurationInterface; @@ -47,16 +45,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface * for GPS L1 C/A signals */ -class GpsL1CaPcpsAssistedAcquisition: public AcquisitionInterface +class GpsL1CaPcpsAssistedAcquisition : public AcquisitionInterface { public: GpsL1CaPcpsAssistedAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsAssistedAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -64,63 +63,72 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_Assisted_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_Assisted_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; + void set_state(int state __attribute__((unused))) override{}; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: pcps_assisted_acquisition_cc_sptr acquisition_cc_; @@ -135,12 +143,11 @@ private: int doppler_min_; unsigned int sampled_ms_; int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.cc deleted file mode 100644 index 9bd8f8b3e..000000000 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.cc +++ /dev/null @@ -1,286 +0,0 @@ -/*! - * \file gps_l1_ca_pcps_multithread_acquisition.cc - * \brief Adapts a multithread PCPS acquisition block to an - * AcquisitionInterface for GPS L1 C/A signals - * \author Marc Molina, 2013. marc.molina.pena(at)gmail.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_pcps_multithread_acquisition.h" -#include -#include -#include "gps_sdr_signal_processing.h" -#include "GPS_L1_CA.h" -#include "configuration_interface.h" - - -using google::LogMessage; - -GpsL1CaPcpsMultithreadAcquisition::GpsL1CaPcpsMultithreadAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) -{ - configuration_ = configuration; - std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./data/acquisition.dat"; - - DLOG(INFO) << "role " << role; - - item_type_ = configuration_->property(role + ".item_type", - default_item_type); - - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration_->property(role + ".if", 0); - dump_ = configuration_->property(role + ".dump", false); - doppler_max_ = configuration->property(role + ".doppler_max", 5000); - sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); - - bit_transition_flag_ = configuration_->property("Acquisition.bit_transition_flag", false); - - if (!bit_transition_flag_) - { - max_dwells_ = configuration_->property(role + ".max_dwells", 1); - } - else - { - max_dwells_ = 2; - } - - dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); - - //--- Find number of samples per spreading code ------------------------- - code_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - - vector_length_ = code_length_ * sampled_ms_; - - code_ = new gr_complex[vector_length_]; - - if (item_type_.compare("gr_complex") == 0) - { - item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_multithread_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, dump_, dump_filename_); - - stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - - DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() - << ")"; - DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() - << ")"; - } - else - { - item_size_ = sizeof(gr_complex); - LOG(WARNING) << item_type_ << " unknown acquisition item type"; - } - - channel_ = 0; - threshold_ = 0.0; - doppler_step_ = 0; - gnss_synchro_ = 0; -} - - -GpsL1CaPcpsMultithreadAcquisition::~GpsL1CaPcpsMultithreadAcquisition() -{ - delete[] code_; -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_channel(unsigned int channel) -{ - channel_ = channel; - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_channel(channel_); - } -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_threshold(float threshold) -{ - float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); - - if(pfa == 0.0) - { - pfa = configuration_->property(role_+".pfa", 0.0); - } - if(pfa == 0.0) - { - threshold_ = threshold; - } - else - { - threshold_ = calculate_threshold(pfa); - } - - DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_threshold(threshold_); - } -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_doppler_max(unsigned int doppler_max) -{ - doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_doppler_max(doppler_max_); - } -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_doppler_step(unsigned int doppler_step) -{ - doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_doppler_step(doppler_step_); - } - -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) -{ - gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_gnss_synchro(gnss_synchro_); - } -} - - -signed int GpsL1CaPcpsMultithreadAcquisition::mag() -{ - if (item_type_.compare("gr_complex") == 0) - { - return acquisition_cc_->mag(); - } - else - { - return 0; - } -} - - -void GpsL1CaPcpsMultithreadAcquisition::init() -{ - acquisition_cc_->init(); - set_local_code(); -} - - -void GpsL1CaPcpsMultithreadAcquisition::set_local_code() -{ - if (item_type_.compare("gr_complex") == 0) - { - std::complex* code = new std::complex[code_length_]; - - gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); - - for (unsigned int i = 0; i < sampled_ms_; i++) - { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); - } - - acquisition_cc_->set_local_code(code_); - - delete[] code; - } -} - - -void GpsL1CaPcpsMultithreadAcquisition::reset() -{ - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_active(true); - } -} - - -float GpsL1CaPcpsMultithreadAcquisition::calculate_threshold(float pfa) -{ - //Calculate the threshold - - unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) - { - frequency_bins++; - } - - DLOG(INFO) << "Channel "<< channel_ << " Pfa = " << pfa; - - unsigned int ncells = vector_length_ * frequency_bins; - double exponent = 1 / static_cast(ncells); - double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); - - return threshold; -} - - -void GpsL1CaPcpsMultithreadAcquisition::connect(gr::top_block_sptr top_block) -{ - if (item_type_.compare("gr_complex") == 0) - { - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); - } - -} - - -void GpsL1CaPcpsMultithreadAcquisition::disconnect(gr::top_block_sptr top_block) -{ - if (item_type_.compare("gr_complex") == 0) - { - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); - } -} - - -gr::basic_block_sptr GpsL1CaPcpsMultithreadAcquisition::get_left_block() -{ - return stream_to_vector_; -} - - -gr::basic_block_sptr GpsL1CaPcpsMultithreadAcquisition::get_right_block() -{ - return acquisition_cc_; -} - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.h deleted file mode 100644 index 8b1f1af0a..000000000 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_multithread_acquisition.h +++ /dev/null @@ -1,155 +0,0 @@ -/*! - * \file gps_l1_ca_pcps_multithread_acquisition.h - * \brief Adapts a multithread PCPS acquisition block to an - * AcquisitionInterface for GPS L1 C/A signals - * \author Marc Molina, 2013. marc.molina.pena(at)gmail.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GPS_L1_CA_PCPS_MULTITHREAD_ACQUISITION_H_ -#define GNSS_SDR_GPS_L1_CA_PCPS_MULTITHREAD_ACQUISITION_H_ - -#include -#include -#include "gnss_synchro.h" -#include "acquisition_interface.h" -#include "pcps_multithread_acquisition_cc.h" - - - -class ConfigurationInterface; - -/*! - * \brief This class adapts a multithread PCPS acquisition block to an - * AcquisitionInterface for GPS L1 C/A signals - */ -class GpsL1CaPcpsMultithreadAcquisition: public AcquisitionInterface -{ -public: - GpsL1CaPcpsMultithreadAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); - - virtual ~GpsL1CaPcpsMultithreadAcquisition(); - - std::string role() - { - return role_; - } - - /*! - * \brief Returns "GPS_L1_CA_PCPS_Multithread_Acquisition" - */ - std::string implementation() - { - return "GPS_L1_CA_PCPS_Multithread_Acquisition"; - } - size_t item_size() - { - return item_size_; - } - - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to efficiently exchange synchronization data between acquisition and - * tracking blocks - */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); - - /*! - * \brief Set acquisition channel unique ID - */ - void set_channel(unsigned int channel); - - /*! - * \brief Set statistics threshold of PCPS algorithm - */ - void set_threshold(float threshold); - - /*! - * \brief Set maximum Doppler off grid search - */ - void set_doppler_max(unsigned int doppler_max); - - /*! - * \brief Set Doppler steps for the grid search - */ - void set_doppler_step(unsigned int doppler_step); - - /*! - * \brief Initializes acquisition algorithm. - */ - void init(); - - /*! - * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. - */ - void set_local_code(); - - /*! - * \brief Returns the maximum peak of grid search - */ - signed int mag(); - - /*! - * \brief Restart acquisition algorithm - */ - void reset(); - -private: - ConfigurationInterface* configuration_; - pcps_multithread_acquisition_cc_sptr acquisition_cc_; - gr::blocks::stream_to_vector::sptr stream_to_vector_; - size_t item_size_; - std::string item_type_; - unsigned int vector_length_; - unsigned int code_length_; - bool bit_transition_flag_; - unsigned int channel_; - float threshold_; - unsigned int doppler_max_; - unsigned int doppler_step_; - unsigned int sampled_ms_; - unsigned int max_dwells_; - long fs_in_; - long if_; - bool dump_; - std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; - - float calculate_threshold(float pfa); -}; - -#endif /* GNSS_SDR_GPS_L1_CA_PCPS_MULTITHREAD_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.cc index ba2c6b68c..1fd9b109f 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,24 +24,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_opencl_acquisition.h" -#include -#include -#include "gps_sdr_signal_processing.h" #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include +#include + using google::LogMessage; + GpsL1CaPcpsOpenClAcquisition::GpsL1CaPcpsOpenClAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -50,12 +56,13 @@ GpsL1CaPcpsOpenClAcquisition::GpsL1CaPcpsOpenClAcquisition( DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", - default_item_type); + default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); bit_transition_flag_ = configuration_->property("Acquisition.bit_transition_flag", false); @@ -70,22 +77,21 @@ GpsL1CaPcpsOpenClAcquisition::GpsL1CaPcpsOpenClAcquisition( } dump_filename_ = configuration_->property(role + ".dump_filename", - default_dump_filename); + default_dump_filename); //--- Find number of samples per spreading code ------------------------- - code_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + code_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); vector_length_ = code_length_ * sampled_ms_; code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_make_opencl_acquisition_cc(sampled_ms_, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, dump_, dump_filename_); + doppler_max_, fs_in_, code_length_, code_length_, + bit_transition_flag_, dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); @@ -101,7 +107,15 @@ GpsL1CaPcpsOpenClAcquisition::GpsL1CaPcpsOpenClAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -111,10 +125,15 @@ GpsL1CaPcpsOpenClAcquisition::~GpsL1CaPcpsOpenClAcquisition() } +void GpsL1CaPcpsOpenClAcquisition::stop_acquisition() +{ +} + + void GpsL1CaPcpsOpenClAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -123,13 +142,13 @@ void GpsL1CaPcpsOpenClAcquisition::set_channel(unsigned int channel) void GpsL1CaPcpsOpenClAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { pfa = configuration_->property(role_ + ".pfa", 0.0); } - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -140,7 +159,7 @@ void GpsL1CaPcpsOpenClAcquisition::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_threshold(threshold_); } @@ -150,7 +169,7 @@ void GpsL1CaPcpsOpenClAcquisition::set_threshold(float threshold) void GpsL1CaPcpsOpenClAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -160,18 +179,17 @@ void GpsL1CaPcpsOpenClAcquisition::set_doppler_max(unsigned int doppler_max) void GpsL1CaPcpsOpenClAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } - } void GpsL1CaPcpsOpenClAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -180,7 +198,7 @@ void GpsL1CaPcpsOpenClAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) signed int GpsL1CaPcpsOpenClAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } @@ -194,22 +212,22 @@ signed int GpsL1CaPcpsOpenClAcquisition::mag() void GpsL1CaPcpsOpenClAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GpsL1CaPcpsOpenClAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - std::complex* code = new std::complex[code_length_]; + auto* code = new std::complex[code_length_]; gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); for (unsigned int i = 0; i < sampled_ms_; i++) { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); } acquisition_cc_->set_local_code(code_); @@ -221,7 +239,7 @@ void GpsL1CaPcpsOpenClAcquisition::set_local_code() void GpsL1CaPcpsOpenClAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -233,7 +251,7 @@ float GpsL1CaPcpsOpenClAcquisition::calculate_threshold(float pfa) //Calculate the threshold unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } @@ -243,9 +261,9 @@ float GpsL1CaPcpsOpenClAcquisition::calculate_threshold(float pfa) unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -253,7 +271,7 @@ float GpsL1CaPcpsOpenClAcquisition::calculate_threshold(float pfa) void GpsL1CaPcpsOpenClAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -262,7 +280,7 @@ void GpsL1CaPcpsOpenClAcquisition::connect(gr::top_block_sptr top_block) void GpsL1CaPcpsOpenClAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -279,4 +297,3 @@ gr::basic_block_sptr GpsL1CaPcpsOpenClAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.h index 9eea40659..a7dbe1bc9 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_opencl_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,13 +32,11 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_OPENCL_ACQUISITION_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_OPENCL_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" +#include "gnss_synchro.h" #include "pcps_opencl_acquisition_cc.h" - - +#include +#include class ConfigurationInterface; @@ -46,16 +44,17 @@ class ConfigurationInterface; * \brief This class adapts an OpenCL PCPS acquisition block to an * AcquisitionInterface for GPS L1 C/A signals */ -class GpsL1CaPcpsOpenClAcquisition: public AcquisitionInterface +class GpsL1CaPcpsOpenClAcquisition : public AcquisitionInterface { public: GpsL1CaPcpsOpenClAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsOpenClAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -63,66 +62,75 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_OpenCl_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_OpenCl_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; + void set_state(int state __attribute__((unused))) override{}; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; @@ -139,12 +147,11 @@ private: unsigned int doppler_step_; unsigned int sampled_ms_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.cc index f732b5aba..a3d896ccc 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,26 +25,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_quicksync_acquisition.h" -#include -#include -#include "gps_sdr_signal_processing.h" #include "GPS_L1_CA.h" #include "configuration_interface.h" - +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include +#include using google::LogMessage; + GpsL1CaPcpsQuickSyncAcquisition::GpsL1CaPcpsQuickSyncAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -53,40 +57,38 @@ GpsL1CaPcpsQuickSyncAcquisition::GpsL1CaPcpsQuickSyncAcquisition( DLOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 4); - //--- Find number of samples per spreading code ------------------------- - code_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - + code_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); /*Calculate the folding factor value based on the calculations*/ - unsigned int temp = (unsigned int)ceil(sqrt(log2(code_length_))); + auto temp = static_cast(ceil(sqrt(log2(code_length_)))); folding_factor_ = configuration_->property(role + ".folding_factor", temp); - if ( sampled_ms_ % folding_factor_ != 0) + if (sampled_ms_ % folding_factor_ != 0) { LOG(WARNING) << "QuickSync Algorithm requires a coherent_integration_time" - << " multiple of " << folding_factor_ << "ms, Value entered " - << sampled_ms_ << " ms"; - if(sampled_ms_ < folding_factor_) + << " multiple of " << folding_factor_ << "ms, Value entered " + << sampled_ms_ << " ms"; + if (sampled_ms_ < folding_factor_) { - sampled_ms_ = (int) folding_factor_; + sampled_ms_ = static_cast(folding_factor_); } else { - sampled_ms_ = (int)(sampled_ms_/folding_factor_) * folding_factor_; + sampled_ms_ = static_cast(sampled_ms_ / folding_factor_) * folding_factor_; } - LOG(WARNING) <<" Coherent_integration_time of " - << sampled_ms_ << " ms will be used instead."; - + LOG(WARNING) << " Coherent_integration_time of " + << sampled_ms_ << " ms will be used instead."; } + vector_length_ = code_length_ * sampled_ms_; bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); @@ -105,22 +107,22 @@ GpsL1CaPcpsQuickSyncAcquisition::GpsL1CaPcpsQuickSyncAcquisition( code_ = new gr_complex[code_length_](); /*Object relevant information for debugging*/ LOG(INFO) << "Implementation: " << this->implementation() - << ", Vector Length: " << vector_length_ - << ", Samples per ms: " << samples_per_ms - << ", Folding factor: " << folding_factor_ - << ", Sampled ms: " << sampled_ms_ - << ", Code Length: " << code_length_; + << ", Vector Length: " << vector_length_ + << ", Samples per ms: " << samples_per_ms + << ", Folding factor: " << folding_factor_ + << ", Sampled ms: " << sampled_ms_ + << ", Code Length: " << code_length_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); acquisition_cc_ = pcps_quicksync_make_acquisition_cc(folding_factor_, - sampled_ms_, max_dwells_,doppler_max_, if_, fs_in_, - samples_per_ms, code_length_,bit_transition_flag_, - dump_, dump_filename_); + sampled_ms_, max_dwells_, doppler_max_, fs_in_, + samples_per_ms, code_length_, bit_transition_flag_, + dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, - code_length_*folding_factor_); + code_length_ * folding_factor_); DLOG(INFO) << "stream_to_vector_quicksync(" << stream_to_vector_->unique_id() << ")"; DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() << ")"; @@ -134,7 +136,15 @@ GpsL1CaPcpsQuickSyncAcquisition::GpsL1CaPcpsQuickSyncAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -144,10 +154,15 @@ GpsL1CaPcpsQuickSyncAcquisition::~GpsL1CaPcpsQuickSyncAcquisition() } +void GpsL1CaPcpsQuickSyncAcquisition::stop_acquisition() +{ +} + + void GpsL1CaPcpsQuickSyncAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_channel(channel_); } @@ -156,14 +171,13 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_channel(unsigned int channel) void GpsL1CaPcpsQuickSyncAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_ + - boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { pfa = configuration_->property(role_ + ".pfa", 0.0); } - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -172,9 +186,9 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_threshold(float threshold) threshold_ = calculate_threshold(pfa); } - DLOG(INFO) << "Channel "<< channel_ << " Threshold = " << threshold_; + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_threshold(threshold_); } @@ -184,7 +198,7 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_threshold(float threshold) void GpsL1CaPcpsQuickSyncAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -194,7 +208,7 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_doppler_max(unsigned int doppler_max) void GpsL1CaPcpsQuickSyncAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } @@ -204,7 +218,7 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_doppler_step(unsigned int doppler_step void GpsL1CaPcpsQuickSyncAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -213,38 +227,33 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchr signed int GpsL1CaPcpsQuickSyncAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GpsL1CaPcpsQuickSyncAcquisition::init() { acquisition_cc_->init(); - set_local_code(); - + //set_local_code(); } void GpsL1CaPcpsQuickSyncAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - std::complex* code = new std::complex[code_length_](); + auto* code = new std::complex[code_length_](); gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); - - for (unsigned int i = 0; i < (sampled_ms_/folding_factor_); i++) + for (unsigned int i = 0; i < (sampled_ms_ / folding_factor_); i++) { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); } //memcpy(code_, code,sizeof(gr_complex)*code_length_); @@ -257,15 +266,16 @@ void GpsL1CaPcpsQuickSyncAcquisition::set_local_code() void GpsL1CaPcpsQuickSyncAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } } + void GpsL1CaPcpsQuickSyncAcquisition::set_state(int state) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_state(state); } @@ -276,17 +286,17 @@ float GpsL1CaPcpsQuickSyncAcquisition::calculate_threshold(float pfa) { //Calculate the threshold unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } - DLOG(INFO) << "Channel " << channel_<< " Pfa = " << pfa; + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; unsigned int ncells = (code_length_ / folding_factor_) * frequency_bins; double exponent = 1.0 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); double lambda = static_cast(code_length_) / static_cast(folding_factor_); - boost::math::exponential_distribution mydist (lambda); - float threshold = static_cast(quantile(mydist,val)); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -294,17 +304,16 @@ float GpsL1CaPcpsQuickSyncAcquisition::calculate_threshold(float pfa) void GpsL1CaPcpsQuickSyncAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } - } void GpsL1CaPcpsQuickSyncAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -321,5 +330,3 @@ gr::basic_block_sptr GpsL1CaPcpsQuickSyncAcquisition::get_right_block() { return acquisition_cc_; } - - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.h index 2e32df150..482db0f44 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_quicksync_acquisition.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,14 +33,12 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_QUICKSYNC_ACQUISITION_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_QUICKSYNC_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" -#include "pcps_quicksync_acquisition_cc.h" #include "configuration_interface.h" - - +#include "gnss_synchro.h" +#include "pcps_quicksync_acquisition_cc.h" +#include +#include class ConfigurationInterface; @@ -48,16 +46,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface * for GPS L1 C/A signals */ -class GpsL1CaPcpsQuickSyncAcquisition: public AcquisitionInterface +class GpsL1CaPcpsQuickSyncAcquisition : public AcquisitionInterface { public: GpsL1CaPcpsQuickSyncAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsQuickSyncAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -65,71 +64,80 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_QuickSync_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_QuickSync_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for GPS L1/CA PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + private: ConfigurationInterface* configuration_; pcps_quicksync_acquisition_cc_sptr acquisition_cc_; @@ -146,18 +154,16 @@ private: unsigned int sampled_ms_; unsigned int max_dwells_; unsigned int folding_factor_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; float calculate_threshold(float pfa); - }; #endif /* GNSS_SDR_GPS_L1_CA_PCPS_QUICKSYNC_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.cc index e7a4bdb65..0b3a627ba 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_pcps_tong_acquisition.h" -#include -#include -#include "gps_sdr_signal_processing.h" #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include +#include using google::LogMessage; + GpsL1CaPcpsTongAcquisition::GpsL1CaPcpsTongAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; @@ -52,10 +57,11 @@ GpsL1CaPcpsTongAcquisition::GpsL1CaPcpsTongAcquisition( item_type_ = configuration_->property(role + ".item_type", default_item_type); - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump_ = configuration_->property(role + ".dump", false); doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1); tong_init_val_ = configuration->property(role + ".tong_init_val", 1); @@ -65,19 +71,18 @@ GpsL1CaPcpsTongAcquisition::GpsL1CaPcpsTongAcquisition( dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); //--- Find number of samples per spreading code ------------------------- - code_length_ = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + code_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); vector_length_ = code_length_ * sampled_ms_; code_ = new gr_complex[vector_length_]; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_tong_make_acquisition_cc(sampled_ms_, doppler_max_, if_, fs_in_, - code_length_, code_length_, tong_init_val_, tong_max_val_, tong_max_dwells_, - dump_, dump_filename_); + acquisition_cc_ = pcps_tong_make_acquisition_cc(sampled_ms_, doppler_max_, fs_in_, + code_length_, code_length_, tong_init_val_, tong_max_val_, tong_max_dwells_, + dump_, dump_filename_); stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); @@ -93,7 +98,15 @@ GpsL1CaPcpsTongAcquisition::GpsL1CaPcpsTongAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -103,25 +116,30 @@ GpsL1CaPcpsTongAcquisition::~GpsL1CaPcpsTongAcquisition() } +void GpsL1CaPcpsTongAcquisition::stop_acquisition() +{ +} + + void GpsL1CaPcpsTongAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_channel(channel_); - } + if (item_type_ == "gr_complex") + { + acquisition_cc_->set_channel(channel_); + } } void GpsL1CaPcpsTongAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { - pfa = configuration_->property(role_+".pfa", 0.0); + pfa = configuration_->property(role_ + ".pfa", 0.0); } - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -132,7 +150,7 @@ void GpsL1CaPcpsTongAcquisition::set_threshold(float threshold) DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_threshold(threshold_); } @@ -142,7 +160,7 @@ void GpsL1CaPcpsTongAcquisition::set_threshold(float threshold) void GpsL1CaPcpsTongAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_max(doppler_max_); } @@ -152,18 +170,17 @@ void GpsL1CaPcpsTongAcquisition::set_doppler_max(unsigned int doppler_max) void GpsL1CaPcpsTongAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_doppler_step(doppler_step_); } - } void GpsL1CaPcpsTongAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_gnss_synchro(gnss_synchro_); } @@ -172,47 +189,44 @@ void GpsL1CaPcpsTongAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) signed int GpsL1CaPcpsTongAcquisition::mag() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return acquisition_cc_->mag(); } - else - { - return 0; - } + return 0; } void GpsL1CaPcpsTongAcquisition::init() { acquisition_cc_->init(); - set_local_code(); + //set_local_code(); } void GpsL1CaPcpsTongAcquisition::set_local_code() { - if (item_type_.compare("gr_complex") == 0) - { - std::complex* code = new std::complex[code_length_]; + if (item_type_ == "gr_complex") + { + auto* code = new std::complex[code_length_]; - gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); + gps_l1_ca_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_, 0); - for (unsigned int i = 0; i < sampled_ms_; i++) - { - memcpy(&(code_[i*code_length_]), code, - sizeof(gr_complex)*code_length_); - } + for (unsigned int i = 0; i < sampled_ms_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } - acquisition_cc_->set_local_code(code_); + acquisition_cc_->set_local_code(code_); - delete[] code; - } + delete[] code; + } } void GpsL1CaPcpsTongAcquisition::reset() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { acquisition_cc_->set_active(true); } @@ -221,10 +235,10 @@ void GpsL1CaPcpsTongAcquisition::reset() void GpsL1CaPcpsTongAcquisition::set_state(int state) { - if (item_type_.compare("gr_complex") == 0) - { - acquisition_cc_->set_state(state); - } + if (item_type_ == "gr_complex") + { + acquisition_cc_->set_state(state); + } } @@ -232,19 +246,19 @@ float GpsL1CaPcpsTongAcquisition::calculate_threshold(float pfa) { //Calculate the threshold unsigned int frequency_bins = 0; - for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_) + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) { frequency_bins++; } - DLOG(INFO) << "Channel "<< channel_ <<" Pfa = "<< pfa; + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1 / static_cast(ncells); - double val = pow(1.0 - pfa,exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist, val); + double val = pow(1.0 - pfa, exponent); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -252,17 +266,16 @@ float GpsL1CaPcpsTongAcquisition::calculate_threshold(float pfa) void GpsL1CaPcpsTongAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); } - } void GpsL1CaPcpsTongAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); } @@ -279,4 +292,3 @@ gr::basic_block_sptr GpsL1CaPcpsTongAcquisition::get_right_block() { return acquisition_cc_; } - diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.h index a43dd3e99..63e89b8a5 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_tong_acquisition.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,12 +32,12 @@ #ifndef GNSS_SDR_GPS_L1_CA_TONG_ACQUISITION_H_ #define GNSS_SDR_GPS_L1_CA_TONG_ACQUISITION_H_ -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" -#include "pcps_tong_acquisition_cc.h" #include "configuration_interface.h" +#include "gnss_synchro.h" +#include "pcps_tong_acquisition_cc.h" +#include +#include class ConfigurationInterface; @@ -45,16 +45,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS Tong acquisition block to an * AcquisitionInterface for GPS L1 C/A signals */ -class GpsL1CaPcpsTongAcquisition: public AcquisitionInterface +class GpsL1CaPcpsTongAcquisition : public AcquisitionInterface { public: GpsL1CaPcpsTongAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaPcpsTongAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -62,71 +63,79 @@ public: /*! * \brief Returns "GPS_L1_CA_PCPS_Tong_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_PCPS_Tong_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of TONG algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for GPS L1/CA TONG acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; @@ -144,12 +153,11 @@ private: unsigned int tong_init_val_; unsigned int tong_max_val_; unsigned int tong_max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc index baf00ff1f..dcf663121 100644 --- a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,80 +26,122 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l2_m_pcps_acquisition.h" +#include "GPS_L2C.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_l2c_signal.h" #include #include -#include "gps_l2c_signal.h" -#include "GPS_L2C.h" -#include "configuration_interface.h" using google::LogMessage; + GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { configuration_ = configuration; std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./data/acquisition.dat"; + std::string default_dump_filename = "./acquisition.mat"; LOG(INFO) << "role " << role; item_type_ = configuration_->property(role + ".item_type", default_item_type); - //float pfa = configuration_->property(role + ".pfa", 0.0); - - fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - if_ = configuration_->property(role + ".if", 0); + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters_.fs_in = fs_in_; dump_ = configuration_->property(role + ".dump", false); + acq_parameters_.dump = dump_; + acq_parameters_.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters_.blocking = blocking_; doppler_max_ = configuration->property(role + ".doppler_max", 5000); - + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters_.doppler_max = doppler_max_; bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - use_CFAR_algorithm_flag_=configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions - + acq_parameters_.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters_.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; max_dwells_ = configuration_->property(role + ".max_dwells", 1); - + acq_parameters_.max_dwells = max_dwells_; dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - - //--- Find number of samples per spreading code ------------------------- - code_length_ = round(static_cast(fs_in_) - / (GPS_L2_M_CODE_RATE_HZ / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS))); - - vector_length_ = code_length_; - - if( bit_transition_flag_ ) + acq_parameters_.dump_filename = dump_filename_; + acq_parameters_.ms_per_code = 20; + acq_parameters_.sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", acq_parameters_.ms_per_code); + if ((acq_parameters_.sampled_ms % acq_parameters_.ms_per_code) != 0) { - vector_length_ *= 2; + LOG(WARNING) << "Parameter coherent_integration_time_ms should be a multiple of 20. Setting it to 20"; + acq_parameters_.sampled_ms = acq_parameters_.ms_per_code; } + acq_parameters_.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters_.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters_.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters_.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acq_parameters_.use_automatic_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + if (acq_parameters_.use_automatic_resampler == true and item_type_ != "gr_complex") + { + LOG(WARNING) << "GPS L2CM acquisition disabled the automatic resampler feature because its item_type is not set to gr_complex"; + acq_parameters_.use_automatic_resampler = false; + } + if (acq_parameters_.use_automatic_resampler) + { + if (acq_parameters_.fs_in > GPS_L2C_OPT_ACQ_FS_HZ) + { + acq_parameters_.resampler_ratio = floor(static_cast(acq_parameters_.fs_in) / GPS_L2C_OPT_ACQ_FS_HZ); + uint32_t decimation = acq_parameters_.fs_in / GPS_L2C_OPT_ACQ_FS_HZ; + while (acq_parameters_.fs_in % decimation > 0) + { + decimation--; + }; + acq_parameters_.resampler_ratio = decimation; + acq_parameters_.resampled_fs = acq_parameters_.fs_in / static_cast(acq_parameters_.resampler_ratio); + } + + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(acq_parameters_.resampled_fs) / (GPS_L2_M_CODE_RATE_HZ / GPS_L2_M_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(acq_parameters_.resampled_fs) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / GPS_L2_M_CODE_RATE_HZ) * static_cast(acq_parameters_.resampled_fs))); + } + else + { + acq_parameters_.resampled_fs = fs_in_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / GPS_L2_M_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / GPS_L2_M_CODE_RATE_HZ) * static_cast(acq_parameters_.fs_in))); + } + + acq_parameters_.samples_per_code = acq_parameters_.samples_per_ms * static_cast(GPS_L2_M_PERIOD * 1000.0); + vector_length_ = acq_parameters_.sampled_ms * acq_parameters_.samples_per_ms * (acq_parameters_.bit_transition_flag ? 2 : 1); code_ = new gr_complex[vector_length_]; - if (item_type_.compare("cshort") == 0 ) + if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); - acquisition_sc_ = pcps_make_acquisition_sc(1, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_sc_->unique_id() << ")"; - - }else{ - item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_acquisition_cc(1, max_dwells_, - doppler_max_, if_, fs_in_, code_length_, code_length_, - bit_transition_flag_, use_CFAR_algorithm_flag_, dump_, dump_filename_); - DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id() << ")"; + } + else + { + item_size_ = sizeof(gr_complex); } - stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - - if (item_type_.compare("cbyte") == 0) + acq_parameters_.it_size = item_size_; + acquisition_ = pcps_make_acquisition(acq_parameters_); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; + + if (item_type_ == "cbyte") { cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); float_to_complex_ = gr::blocks::float_to_complex::make(); @@ -108,7 +150,16 @@ GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition( channel_ = 0; threshold_ = 0.0; doppler_step_ = 0; - gnss_synchro_ = 0; + gnss_synchro_ = nullptr; + num_codes_ = acq_parameters_.sampled_ms / acq_parameters_.ms_per_code; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } } @@ -118,29 +169,27 @@ GpsL2MPcpsAcquisition::~GpsL2MPcpsAcquisition() } +void GpsL2MPcpsAcquisition::stop_acquisition() +{ +} + + void GpsL2MPcpsAcquisition::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_channel(channel_); - } - else - { - acquisition_cc_->set_channel(channel_); - } + acquisition_->set_channel(channel_); } void GpsL2MPcpsAcquisition::set_threshold(float threshold) { - float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - if(pfa == 0.0) + if (pfa == 0.0) { pfa = configuration_->property(role_ + ".pfa", 0.0); } - if(pfa == 0.0) + if (pfa == 0.0) { threshold_ = threshold; } @@ -149,16 +198,9 @@ void GpsL2MPcpsAcquisition::set_threshold(float threshold) threshold_ = calculate_threshold(pfa); } - DLOG(INFO) << "Channel " << channel_ <<" Threshold = " << threshold_; + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_threshold(threshold_); - } - else - { - acquisition_cc_->set_threshold(threshold_); - } + acquisition_->set_threshold(threshold_); } @@ -166,14 +208,7 @@ void GpsL2MPcpsAcquisition::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_max(doppler_max_); - } - else - { - acquisition_cc_->set_doppler_max(doppler_max_); - } + acquisition_->set_doppler_max(doppler_max_); } @@ -183,14 +218,7 @@ void GpsL2MPcpsAcquisition::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_doppler_step(doppler_step_); - } - else - { - acquisition_cc_->set_doppler_step(doppler_step_); - } + acquisition_->set_doppler_step(doppler_step_); } @@ -198,99 +226,60 @@ void GpsL2MPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_gnss_synchro(gnss_synchro_); - } - else - { - acquisition_cc_->set_gnss_synchro(gnss_synchro_); - } + acquisition_->set_gnss_synchro(gnss_synchro_); } signed int GpsL2MPcpsAcquisition::mag() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_->mag(); - } - else - { - return acquisition_cc_->mag(); - } + return acquisition_->mag(); } void GpsL2MPcpsAcquisition::init() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->init(); - } - else - { - acquisition_cc_->init(); - } - - set_local_code(); + acquisition_->init(); + //set_local_code(); } void GpsL2MPcpsAcquisition::set_local_code() { + auto* code = new std::complex[code_length_]; - gps_l2c_m_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_); - - if (item_type_.compare("cshort") == 0) + + if (acq_parameters_.use_automatic_resampler) { - acquisition_sc_->set_local_code(code_); + gps_l2c_m_code_gen_complex_sampled(code, gnss_synchro_->PRN, acq_parameters_.resampled_fs); } else { - acquisition_cc_->set_local_code(code_); + gps_l2c_m_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_); } - -// //debug -// std::ofstream d_dump_file; -// std::stringstream filename; -// std::streamsize n = 2 * sizeof(float) * (code_length_); // complex file write -// filename.str(""); -// filename << "../data/local_prn_sampled.dat"; -// d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); -// d_dump_file.write((char*)code_, n); -// d_dump_file.close(); - // } + + for (unsigned int i = 0; i < num_codes_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); + delete[] code; } void GpsL2MPcpsAcquisition::reset() { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_active(true); - } - else - { - acquisition_cc_->set_active(true); - } + acquisition_->set_active(true); } void GpsL2MPcpsAcquisition::set_state(int state) { - if (item_type_.compare("cshort") == 0) - { - acquisition_sc_->set_state(state); - } - else - { - acquisition_cc_->set_state(state); - } + acquisition_->set_state(state); } - float GpsL2MPcpsAcquisition::calculate_threshold(float pfa) { //Calculate the threshold @@ -299,13 +288,13 @@ float GpsL2MPcpsAcquisition::calculate_threshold(float pfa) { frequency_bins++; } - DLOG(INFO) << "Channel " << channel_<< " Pfa = " << pfa; + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; unsigned int ncells = vector_length_ * frequency_bins; double exponent = 1.0 / static_cast(ncells); double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist (lambda); - float threshold = (float)quantile(mydist,val); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); return threshold; } @@ -313,20 +302,21 @@ float GpsL2MPcpsAcquisition::calculate_threshold(float pfa) void GpsL2MPcpsAcquisition::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to connect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->connect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to connect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->connect(float_to_complex_, 0, acquisition_, 0); } else { @@ -337,22 +327,19 @@ void GpsL2MPcpsAcquisition::connect(gr::top_block_sptr top_block) void GpsL2MPcpsAcquisition::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { - top_block->disconnect(stream_to_vector_, 0, acquisition_sc_, 0); + // nothing to disconnect } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { - // Since a byte-based acq implementation is not available, - // we just convert cshorts to gr_complex top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); - top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); } else { @@ -363,35 +350,29 @@ void GpsL2MPcpsAcquisition::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr GpsL2MPcpsAcquisition::get_left_block() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cshort") == 0) + if (item_type_ == "cshort") { - return stream_to_vector_; + return acquisition_; } - else if (item_type_.compare("cbyte") == 0) + if (item_type_ == "cbyte") { return cbyte_to_float_x2_; } - else - { - LOG(WARNING) << item_type_ << " unknown acquisition item type"; - return nullptr; - } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; } gr::basic_block_sptr GpsL2MPcpsAcquisition::get_right_block() { - if (item_type_.compare("cshort") == 0) - { - return acquisition_sc_; - } - else - { - return acquisition_cc_; - } + return acquisition_; +} +void GpsL2MPcpsAcquisition::set_resampler_latency(uint32_t latency_samples) +{ + acquisition_->set_resampler_latency(latency_samples); } - diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.h b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.h index 308a1a590..da1c7ef6e 100644 --- a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.h +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,16 +34,13 @@ #ifndef GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_H_ #define GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_H_ -#include -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" -#include "pcps_acquisition_cc.h" -#include "pcps_acquisition_sc.h" #include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include #include - +#include class ConfigurationInterface; @@ -52,16 +49,17 @@ class ConfigurationInterface; * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface * for GPS L2 M signals */ -class GpsL2MPcpsAcquisition: public AcquisitionInterface +class GpsL2MPcpsAcquisition : public AcquisitionInterface { public: GpsL2MPcpsAcquisition(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL2MPcpsAcquisition(); - std::string role() + inline std::string role() override { return role_; } @@ -69,77 +67,89 @@ public: /*! * \brief Returns "GPS_L2_M_PCPS_Acquisition" */ - std::string implementation() + inline std::string implementation() override { return "GPS_L2_M_PCPS_Acquisition"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; /*! * \brief Set acquisition channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set statistics threshold of PCPS algorithm */ - void set_threshold(float threshold); + void set_threshold(float threshold) override; /*! * \brief Set maximum Doppler off grid search */ - void set_doppler_max(unsigned int doppler_max); + void set_doppler_max(unsigned int doppler_max) override; /*! * \brief Set Doppler steps for the grid search */ - void set_doppler_step(unsigned int doppler_step); + void set_doppler_step(unsigned int doppler_step) override; /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init() override; /*! * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. */ - void set_local_code(); + void set_local_code() override; /*! * \brief Returns the maximum peak of grid search */ - signed int mag(); + signed int mag() override; /*! * \brief Restart acquisition algorithm */ - void reset(); + void reset() override; /*! * \brief If state = 1, it forces the block to start acquiring from the first sample */ - void set_state(int state); + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ + + void set_resampler_latency(uint32_t latency_samples) override; + private: ConfigurationInterface* configuration_; - pcps_acquisition_cc_sptr acquisition_cc_; - pcps_acquisition_sc_sptr acquisition_sc_; - gr::blocks::stream_to_vector::sptr stream_to_vector_; + pcps_acquisition_sptr acquisition_; + Acq_Conf acq_parameters_; gr::blocks::float_to_complex::sptr float_to_complex_; complex_byte_to_float_x2_sptr cbyte_to_float_x2_; size_t item_size_; @@ -153,15 +163,16 @@ private: unsigned int doppler_max_; unsigned int doppler_step_; unsigned int max_dwells_; - long fs_in_; - long if_; + int64_t fs_in_; bool dump_; + bool blocking_; std::string dump_filename_; - std::complex * code_; - Gnss_Synchro * gnss_synchro_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; + unsigned int num_codes_; float calculate_threshold(float pfa); }; diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.cc new file mode 100644 index 000000000..c3cd96275 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.cc @@ -0,0 +1,404 @@ +/*! + * \file gps_l2_m_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * GPS L2 M signals + * \authors
    + *
  • Javier Arribas, 2015. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l2_m_pcps_acquisition_fpga.h" +#include "GPS_L2C.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_l2c_signal.h" +#include +#include + +#define NUM_PRNs 32 + +using google::LogMessage; + + +GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + //pcpsconf_t acq_parameters; + pcpsconf_fpga_t acq_parameters; + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + LOG(INFO) << "role " << role; + + item_type_ = configuration_->property(role + ".item_type", default_item_type); + //float pfa = configuration_->property(role + ".pfa", 0.0); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in_; + //if_ = configuration_->property(role + ".if", 0); + //acq_parameters.freq = if_; + //dump_ = configuration_->property(role + ".dump", false); + //acq_parameters.dump = dump_; + //blocking_ = configuration_->property(role + ".blocking", true); + //acq_parameters.blocking = blocking_; + doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + //bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + //acq_parameters.bit_transition_flag = bit_transition_flag_; + //use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + //acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + //max_dwells_ = configuration_->property(role + ".max_dwells", 1); + //acq_parameters.max_dwells = max_dwells_; + //dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + //acq_parameters.dump_filename = dump_filename_; + //--- Find number of samples per spreading code ------------------------- + //code_length_ = std::round(static_cast(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS))); + + acq_parameters.sampled_ms = 20; + unsigned code_length = std::round(static_cast(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS))); + acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total; + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.select_queue_Fpga = select_queue_Fpga; + std::string default_device_name = "/dev/uio0"; + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total / acq_parameters.sampled_ms; + //acq_parameters.samples_per_ms = static_cast(std::round(static_cast(fs_in_) * 0.001)); + acq_parameters.samples_per_code = nsamples_total; + + // compute all the GPS L1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + auto* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT + // allocate memory to compute all the PRNs and compute all the possible codes + auto* code = new std::complex[nsamples_total]; // buffer for the local code + auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 + float max; // temporary maxima search + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + gps_l2c_m_code_gen_complex_sampled(code, PRN, fs_in_); + // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = std::complex(0.0, 0.0); + //code[s] = 0; + } + memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); + } + } + + //acq_parameters + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + channel_ = 0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + + + // vector_length_ = code_length_; + // + // if (bit_transition_flag_) + // { + // vector_length_ *= 2; + // } + + // code_ = new gr_complex[vector_length_]; + // + // if (item_type_.compare("cshort") == 0) + // { + // item_size_ = sizeof(lv_16sc_t); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // } + //acq_parameters.samples_per_ms = static_cast(std::round(static_cast(fs_in_) * 0.001)); + //acq_parameters.samples_per_code = code_length_; + //acq_parameters.it_size = item_size_; + //acq_parameters.sampled_ms = 20; + //acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + //acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + //acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", true); + //acquisition_ = pcps_make_acquisition(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + // stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); + // DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; + // + // if (item_type_.compare("cbyte") == 0) + // { + // cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + // float_to_complex_ = gr::blocks::float_to_complex::make(); + // } + + // channel_ = 0; + threshold_ = 0.0; + // doppler_step_ = 0; + // gnss_synchro_ = 0; +} + + +GpsL2MPcpsAcquisitionFpga::~GpsL2MPcpsAcquisitionFpga() +{ + //delete[] code_; + delete[] d_all_fft_codes_; +} + + +void GpsL2MPcpsAcquisitionFpga::stop_acquisition() +{ +} + + +void GpsL2MPcpsAcquisitionFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_fpga_->set_channel(channel_); +} + + +void GpsL2MPcpsAcquisitionFpga::set_threshold(float threshold) +{ + // float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); + // + // if (pfa == 0.0) + // { + // pfa = configuration_->property(role_ + ".pfa", 0.0); + // } + // if (pfa == 0.0) + // { + // threshold_ = threshold; + // } + // else + // { + // threshold_ = calculate_threshold(pfa); + // } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + acquisition_fpga_->set_threshold(threshold_); +} + + +void GpsL2MPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + + acquisition_fpga_->set_doppler_max(doppler_max_); +} + + +// Be aware that Doppler step should be set to 2/(3T) Hz, where T is the coherent integration time (GPS L2 period is 0.02s) +// Doppler bin minimum size= 33 Hz +void GpsL2MPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + + acquisition_fpga_->set_doppler_step(doppler_step_); +} + + +void GpsL2MPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GpsL2MPcpsAcquisitionFpga::mag() +{ + return acquisition_fpga_->mag(); +} + + +void GpsL2MPcpsAcquisitionFpga::init() +{ + acquisition_fpga_->init(); + //set_local_code(); +} + + +void GpsL2MPcpsAcquisitionFpga::set_local_code() +{ + //gps_l2c_m_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_); + + //acquisition_fpga_->set_local_code(code_); + acquisition_fpga_->set_local_code(); +} + + +void GpsL2MPcpsAcquisitionFpga::reset() +{ + acquisition_fpga_->set_active(true); +} + +void GpsL2MPcpsAcquisitionFpga::set_state(int state) +{ + acquisition_fpga_->set_state(state); +} + + +//float GpsL2MPcpsAcquisitionFpga::calculate_threshold(float pfa) +//{ +// //Calculate the threshold +// unsigned int frequency_bins = 0; +// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) +// { +// frequency_bins++; +// } +// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; +// unsigned int ncells = vector_length_ * frequency_bins; +// double exponent = 1.0 / static_cast(ncells); +// double val = pow(1.0 - pfa, exponent); +// double lambda = double(vector_length_); +// boost::math::exponential_distribution mydist(lambda); +// float threshold = static_cast(quantile(mydist, val)); +// +// return threshold; +//} + + +void GpsL2MPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->connect(stream_to_vector_, 0, acquisition_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + + // nothing to connect +} + + +void GpsL2MPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // // Since a byte-based acq implementation is not available, + // // we just convert cshorts to gr_complex + // top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + + // nothing to disconnect +} + + +gr::basic_block_sptr GpsL2MPcpsAcquisitionFpga::get_left_block() +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cshort") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // return cbyte_to_float_x2_; + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // return nullptr; + // } + return nullptr; +} + + +gr::basic_block_sptr GpsL2MPcpsAcquisitionFpga::get_right_block() +{ + return acquisition_fpga_; +} diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h new file mode 100644 index 000000000..102911d3d --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h @@ -0,0 +1,179 @@ +/*! + * \file gps_l2_m_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * GPS L2 M signals + * \authors
    + *
  • Javier Arribas, 2015. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L2 M signals + */ +class GpsL2MPcpsAcquisitionFpga : public AcquisitionInterface +{ +public: + GpsL2MPcpsAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL2MPcpsAcquisitionFpga(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GPS_L2_M_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GPS_L2_M_PCPS_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + //pcps_acquisition_sptr acquisition_; + pcps_acquisition_fpga_sptr acquisition_fpga_; + gr::blocks::stream_to_vector::sptr stream_to_vector_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + size_t item_size_; + std::string item_type_; + unsigned int vector_length_; + unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + unsigned int channel_; + float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int max_dwells_; + int64_t fs_in_; + //long if_; + bool dump_; + bool blocking_; + std::string dump_filename_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts + + //float calculate_threshold(float pfa); +}; + +#endif /* GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.cc new file mode 100644 index 000000000..f436da1d4 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.cc @@ -0,0 +1,371 @@ +/*! + * \file gps_l5i_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an Acquisition Interface for + * GPS L5i signals + * \authors
    + *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l5i_pcps_acquisition.h" +#include "GPS_L5.h" +#include "acq_conf.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_l5_signal.h" +#include +#include + + +using google::LogMessage; + + +GpsL5iPcpsAcquisition::GpsL5iPcpsAcquisition( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + LOG(INFO) << "role " << role; + + item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters_.fs_in = fs_in_; + dump_ = configuration_->property(role + ".dump", false); + acq_parameters_.dump = dump_; + acq_parameters_.dump_channel = configuration_->property(role + ".dump_channel", 0); + blocking_ = configuration_->property(role + ".blocking", true); + acq_parameters_.blocking = blocking_; + doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters_.doppler_max = doppler_max_; + bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + acq_parameters_.bit_transition_flag = bit_transition_flag_; + use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + acq_parameters_.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + max_dwells_ = configuration_->property(role + ".max_dwells", 1); + acq_parameters_.max_dwells = max_dwells_; + dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + acq_parameters_.dump_filename = dump_filename_; + acq_parameters_.sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + + if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + } + else + { + item_size_ = sizeof(gr_complex); + } + + acq_parameters_.ms_per_code = 1; + acq_parameters_.it_size = item_size_; + num_codes_ = acq_parameters_.sampled_ms; + acq_parameters_.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + acq_parameters_.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + acq_parameters_.make_2_steps = configuration_->property(role + ".make_two_steps", false); + acq_parameters_.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false); + acq_parameters_.use_automatic_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + if (acq_parameters_.use_automatic_resampler == true and item_type_ != "gr_complex") + { + LOG(WARNING) << "GPS L5 acquisition disabled the automatic resampler feature because its item_type is not set to gr_complex"; + acq_parameters_.use_automatic_resampler = false; + } + if (acq_parameters_.use_automatic_resampler) + { + if (acq_parameters_.fs_in > GPS_L5_OPT_ACQ_FS_HZ) + { + acq_parameters_.resampler_ratio = floor(static_cast(acq_parameters_.fs_in) / GPS_L5_OPT_ACQ_FS_HZ); + uint32_t decimation = acq_parameters_.fs_in / GPS_L5_OPT_ACQ_FS_HZ; + while (acq_parameters_.fs_in % decimation > 0) + { + decimation--; + }; + acq_parameters_.resampler_ratio = decimation; + acq_parameters_.resampled_fs = acq_parameters_.fs_in / static_cast(acq_parameters_.resampler_ratio); + } + + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(acq_parameters_.resampled_fs) / (GPS_L5i_CODE_RATE_HZ / GPS_L5i_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(acq_parameters_.resampled_fs) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / GPS_L5i_CODE_RATE_HZ) * static_cast(acq_parameters_.resampled_fs))); + } + else + { + acq_parameters_.resampled_fs = fs_in_; + //--- Find number of samples per spreading code ------------------------- + code_length_ = static_cast(std::floor(static_cast(fs_in_) / (GPS_L5i_CODE_RATE_HZ / GPS_L5i_CODE_LENGTH_CHIPS))); + acq_parameters_.samples_per_ms = static_cast(fs_in_) * 0.001; + acq_parameters_.samples_per_chip = static_cast(ceil((1.0 / GPS_L5i_CODE_RATE_HZ) * static_cast(acq_parameters_.fs_in))); + } + + acq_parameters_.samples_per_code = acq_parameters_.samples_per_ms * static_cast(GPS_L5i_PERIOD * 1000.0); + vector_length_ = std::floor(acq_parameters_.sampled_ms * acq_parameters_.samples_per_ms) * (acq_parameters_.bit_transition_flag ? 2 : 1); + code_ = new gr_complex[vector_length_]; + acquisition_ = pcps_make_acquisition(acq_parameters_); + DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")"; + + if (item_type_ == "cbyte") + { + cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + float_to_complex_ = gr::blocks::float_to_complex::make(); + } + + channel_ = 0; + threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 0) + { + LOG(ERROR) << "This implementation does not provide an output stream"; + } +} + + +GpsL5iPcpsAcquisition::~GpsL5iPcpsAcquisition() +{ + delete[] code_; +} + + +void GpsL5iPcpsAcquisition::stop_acquisition() +{ +} + + +void GpsL5iPcpsAcquisition::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_->set_channel(channel_); +} + + +void GpsL5iPcpsAcquisition::set_threshold(float threshold) +{ + float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); + + if (pfa == 0.0) + { + pfa = configuration_->property(role_ + ".pfa", 0.0); + } + if (pfa == 0.0) + { + threshold_ = threshold; + } + else + { + threshold_ = calculate_threshold(pfa); + } + + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + acquisition_->set_threshold(threshold_); +} + + +void GpsL5iPcpsAcquisition::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + + acquisition_->set_doppler_max(doppler_max_); +} + + +// Be aware that Doppler step should be set to 2/(3T) Hz, where T is the coherent integration time (GPS L2 period is 0.02s) +// Doppler bin minimum size= 33 Hz +void GpsL5iPcpsAcquisition::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + + acquisition_->set_doppler_step(doppler_step_); +} + + +void GpsL5iPcpsAcquisition::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + + acquisition_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GpsL5iPcpsAcquisition::mag() +{ + return acquisition_->mag(); +} + + +void GpsL5iPcpsAcquisition::init() +{ + acquisition_->init(); +} + +void GpsL5iPcpsAcquisition::set_local_code() +{ + auto* code = new std::complex[code_length_]; + + + if (acq_parameters_.use_automatic_resampler) + { + gps_l5i_code_gen_complex_sampled(code, gnss_synchro_->PRN, acq_parameters_.resampled_fs); + } + else + { + gps_l5i_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_); + } + + for (unsigned int i = 0; i < num_codes_; i++) + { + memcpy(&(code_[i * code_length_]), code, + sizeof(gr_complex) * code_length_); + } + + acquisition_->set_local_code(code_); + delete[] code; +} + + +void GpsL5iPcpsAcquisition::reset() +{ + acquisition_->set_active(true); +} + +void GpsL5iPcpsAcquisition::set_state(int state) +{ + acquisition_->set_state(state); +} + + +float GpsL5iPcpsAcquisition::calculate_threshold(float pfa) +{ + //Calculate the threshold + unsigned int frequency_bins = 0; + for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) + { + frequency_bins++; + } + DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; + unsigned int ncells = vector_length_ * frequency_bins; + double exponent = 1.0 / static_cast(ncells); + double val = pow(1.0 - pfa, exponent); + auto lambda = double(vector_length_); + boost::math::exponential_distribution mydist(lambda); + auto threshold = static_cast(quantile(mydist, val)); + + return threshold; +} + + +void GpsL5iPcpsAcquisition::connect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to connect + } + else if (item_type_ == "cshort") + { + // nothing to connect + } + else if (item_type_ == "cbyte") + { + // Since a byte-based acq implementation is not available, + // we just convert cshorts to gr_complex + top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->connect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +void GpsL5iPcpsAcquisition::disconnect(gr::top_block_sptr top_block) +{ + if (item_type_ == "gr_complex") + { + // nothing to disconnect + } + else if (item_type_ == "cshort") + { + // nothing to disconnect + } + else if (item_type_ == "cbyte") + { + top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + top_block->disconnect(float_to_complex_, 0, acquisition_, 0); + } + else + { + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + } +} + + +gr::basic_block_sptr GpsL5iPcpsAcquisition::get_left_block() +{ + if (item_type_ == "gr_complex") + { + return acquisition_; + } + if (item_type_ == "cshort") + { + return acquisition_; + } + if (item_type_ == "cbyte") + { + return cbyte_to_float_x2_; + } + + LOG(WARNING) << item_type_ << " unknown acquisition item type"; + return nullptr; +} + + +gr::basic_block_sptr GpsL5iPcpsAcquisition::get_right_block() +{ + return acquisition_; +} + +void GpsL5iPcpsAcquisition::set_resampler_latency(uint32_t latency_samples) +{ + acquisition_->set_resampler_latency(latency_samples); +} diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.h b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.h new file mode 100644 index 000000000..af8cabb81 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition.h @@ -0,0 +1,179 @@ +/*! + * \file gps_l5i_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * GPS L5i signals + * \authors
    + *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_H_ +#define GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition.h" +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L5i signals + */ +class GpsL5iPcpsAcquisition : public AcquisitionInterface +{ +public: + GpsL5iPcpsAcquisition(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL5iPcpsAcquisition(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GPS_L5i_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GPS_L5i_PCPS_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ + + void set_resampler_latency(uint32_t latency_samples) override; + +private: + ConfigurationInterface* configuration_; + pcps_acquisition_sptr acquisition_; + Acq_Conf acq_parameters_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + size_t item_size_; + std::string item_type_; + unsigned int vector_length_; + unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + unsigned int channel_; + float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int max_dwells_; + int64_t fs_in_; + bool dump_; + bool blocking_; + std::string dump_filename_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int num_codes_; + unsigned int in_streams_; + unsigned int out_streams_; + + float calculate_threshold(float pfa); +}; + +#endif /* GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc new file mode 100644 index 000000000..f90c77040 --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc @@ -0,0 +1,410 @@ +/*! + * \file gps_l5i pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an Acquisition Interface for + * GPS L5i signals + * \authors
    + *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l5i_pcps_acquisition_fpga.h" +#include "GPS_L5.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gps_l5_signal.h" +#include +#include + +#define NUM_PRNs 32 + +using google::LogMessage; + + +GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga( + ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + //printf("L5 ACQ CLASS CREATED\n"); + pcpsconf_fpga_t acq_parameters; + configuration_ = configuration; + std::string default_item_type = "gr_complex"; + std::string default_dump_filename = "./acquisition.mat"; + + LOG(INFO) << "role " << role; + + //item_type_ = configuration_->property(role + ".item_type", default_item_type); + + int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); + int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in; + //if_ = configuration_->property(role + ".if", 0); + //acq_parameters.freq = if_; + //dump_ = configuration_->property(role + ".dump", false); + //acq_parameters.dump = dump_; + //blocking_ = configuration_->property(role + ".blocking", true); + //acq_parameters.blocking = blocking_; + doppler_max_ = configuration->property(role + ".doppler_max", 5000); + if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; + acq_parameters.doppler_max = doppler_max_; + //acq_parameters.sampled_ms = 1; + unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms; + + //printf("L5 ACQ CLASS MID 0\n"); + + //bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); + //acq_parameters.bit_transition_flag = bit_transition_flag_; + //use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions + //acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; + //max_dwells_ = configuration_->property(role + ".max_dwells", 1); + //acq_parameters.max_dwells = max_dwells_; + //dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); + //acq_parameters.dump_filename = dump_filename_; + //--- Find number of samples per spreading code ------------------------- + auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L5i_CODE_RATE_HZ / static_cast(GPS_L5i_CODE_LENGTH_CHIPS)))); + acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total; + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); + acq_parameters.select_queue_Fpga = select_queue_Fpga; + std::string default_device_name = "/dev/uio0"; + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total; + acq_parameters.samples_per_code = nsamples_total; + //printf("L5 ACQ CLASS MID 01\n"); + // compute all the GPS L5 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + auto* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT + //printf("L5 ACQ CLASS MID 02\n"); + auto* code = new gr_complex[vector_length]; + //printf("L5 ACQ CLASS MID 03\n"); + auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + //printf("L5 ACQ CLASS MID 04\n"); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 + + //printf("L5 ACQ CLASS MID 1 vector_length = %d\n", vector_length); + + float max; // temporary maxima search + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + //printf("L5 ACQ CLASS processing PRN = %d\n", PRN); + gps_l5i_code_gen_complex_sampled(code, PRN, fs_in); + //printf("L5 ACQ CLASS processing PRN = %d (cont) \n", PRN); + // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = std::complex(0.0, 0.0); + //code[s] = 0; + } + memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), + // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), + // static_cast(16*floor(fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); + //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + // static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + } + } + + + //printf("L5 ACQ CLASS MID 2\n"); + + //acq_parameters + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + // vector_length_ = code_length_; + // + // if (bit_transition_flag_) + // { + // vector_length_ *= 2; + // } + // + // code_ = new gr_complex[vector_length_]; + // + // if (item_type_.compare("cshort") == 0) + // { + // item_size_ = sizeof(lv_16sc_t); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // } + // acq_parameters.samples_per_code = code_length_; + // acq_parameters.samples_per_ms = code_length_; + // acq_parameters.it_size = item_size_; + //acq_parameters.sampled_ms = 1; + // acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); + // acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); + // acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); + // acquisition_fpga_ = pcps_make_acquisition(acq_parameters); + // DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + // stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); + // DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; + // + // if (item_type_.compare("cbyte") == 0) + // { + // cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); + // float_to_complex_ = gr::blocks::float_to_complex::make(); + // } + + channel_ = 0; + // threshold_ = 0.0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + //printf("L5 ACQ CLASS FINISHED\n"); +} + + +GpsL5iPcpsAcquisitionFpga::~GpsL5iPcpsAcquisitionFpga() +{ + //delete[] code_; + delete[] d_all_fft_codes_; +} + + +void GpsL5iPcpsAcquisitionFpga::stop_acquisition() +{ +} + + +void GpsL5iPcpsAcquisitionFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + acquisition_fpga_->set_channel(channel_); +} + + +void GpsL5iPcpsAcquisitionFpga::set_threshold(float threshold) +{ + // float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); + // + // if (pfa == 0.0) + // { + // pfa = configuration_->property(role_ + ".pfa", 0.0); + // } + // if (pfa == 0.0) + // { + // threshold_ = threshold; + // } + // else + // { + // threshold_ = calculate_threshold(pfa); + // } + + // DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; + + // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. + // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; + acquisition_fpga_->set_threshold(threshold); +} + + +void GpsL5iPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) +{ + doppler_max_ = doppler_max; + acquisition_fpga_->set_doppler_max(doppler_max_); +} + + +// Be aware that Doppler step should be set to 2/(3T) Hz, where T is the coherent integration time (GPS L2 period is 0.02s) +// Doppler bin minimum size= 33 Hz +void GpsL5iPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) +{ + doppler_step_ = doppler_step; + acquisition_fpga_->set_doppler_step(doppler_step_); +} + + +void GpsL5iPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) +{ + gnss_synchro_ = gnss_synchro; + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); +} + + +signed int GpsL5iPcpsAcquisitionFpga::mag() +{ + return acquisition_fpga_->mag(); +} + + +void GpsL5iPcpsAcquisitionFpga::init() +{ + acquisition_fpga_->init(); +} + +void GpsL5iPcpsAcquisitionFpga::set_local_code() +{ + acquisition_fpga_->set_local_code(); +} + + +void GpsL5iPcpsAcquisitionFpga::reset() +{ + acquisition_fpga_->set_active(true); +} + +void GpsL5iPcpsAcquisitionFpga::set_state(int state) +{ + acquisition_fpga_->set_state(state); +} + + +//float GpsL5iPcpsAcquisitionFpga::calculate_threshold(float pfa) +//{ +// //Calculate the threshold +// unsigned int frequency_bins = 0; +// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) +// { +// frequency_bins++; +// } +// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; +// unsigned int ncells = vector_length_ * frequency_bins; +// double exponent = 1.0 / static_cast(ncells); +// double val = pow(1.0 - pfa, exponent); +// double lambda = double(vector_length_); +// boost::math::exponential_distribution mydist(lambda); +// float threshold = static_cast(quantile(mydist, val)); +// +// return threshold; +//} + + +void GpsL5iPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + // nothing to connect +} + + +void GpsL5iPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cshort") == 0) + // { + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // // Since a byte-based acq implementation is not available, + // // we just convert cshorts to gr_complex + // top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); + // top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); + // top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); + // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // } + // nothing to disconnect +} + + +gr::basic_block_sptr GpsL5iPcpsAcquisitionFpga::get_left_block() +{ + // if (item_type_.compare("gr_complex") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cshort") == 0) + // { + // return stream_to_vector_; + // } + // else if (item_type_.compare("cbyte") == 0) + // { + // return cbyte_to_float_x2_; + // } + // else + // { + // LOG(WARNING) << item_type_ << " unknown acquisition item type"; + // return nullptr; + // } + return nullptr; +} + + +gr::basic_block_sptr GpsL5iPcpsAcquisitionFpga::get_right_block() +{ + return acquisition_fpga_; +} diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h new file mode 100644 index 000000000..bc0a04c4c --- /dev/null +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h @@ -0,0 +1,179 @@ +/*! + * \file GPS_L5i_PCPS_Acquisition.h + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * GPS L5i signals + * \authors
    + *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ + +#include "acquisition_interface.h" +#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L5i signals + */ +class GpsL5iPcpsAcquisitionFpga : public AcquisitionInterface +{ +public: + GpsL5iPcpsAcquisitionFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL5iPcpsAcquisitionFpga(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "GPS_L5i_PCPS_Acquisition" + */ + inline std::string implementation() override + { + return "GPS_L5i_PCPS_Acquisition"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + /*! + * \brief Set acquisition channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set statistics threshold of PCPS algorithm + */ + void set_threshold(float threshold) override; + + /*! + * \brief Set maximum Doppler off grid search + */ + void set_doppler_max(unsigned int doppler_max) override; + + /*! + * \brief Set Doppler steps for the grid search + */ + void set_doppler_step(unsigned int doppler_step) override; + + /*! + * \brief Initializes acquisition algorithm. + */ + void init() override; + + /*! + * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. + */ + void set_local_code() override; + + /*! + * \brief Returns the maximum peak of grid search + */ + signed int mag() override; + + /*! + * \brief Restart acquisition algorithm + */ + void reset() override; + + /*! + * \brief If state = 1, it forces the block to start acquiring from the first sample + */ + void set_state(int state) override; + + /*! + * \brief Stop running acquisition + */ + void stop_acquisition() override; + + void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; + +private: + ConfigurationInterface* configuration_; + //pcps_acquisition_sptr acquisition_; + pcps_acquisition_fpga_sptr acquisition_fpga_; + gr::blocks::stream_to_vector::sptr stream_to_vector_; + gr::blocks::float_to_complex::sptr float_to_complex_; + complex_byte_to_float_x2_sptr cbyte_to_float_x2_; + size_t item_size_; + std::string item_type_; + unsigned int vector_length_; + unsigned int code_length_; + bool bit_transition_flag_; + bool use_CFAR_algorithm_flag_; + unsigned int channel_; + float threshold_; + unsigned int doppler_max_; + unsigned int doppler_step_; + unsigned int max_dwells_; + int64_t fs_in_; + //long if_; + bool dump_; + bool blocking_; + std::string dump_filename_; + std::complex* code_; + Gnss_Synchro* gnss_synchro_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts + + float calculate_threshold(float pfa); +}; + +#endif /* GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt b/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt index 945d5e2cc..60825d6f0 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,14 +13,12 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(ACQ_GR_BLOCKS_SOURCES - pcps_acquisition_cc.cc - pcps_acquisition_sc.cc - pcps_multithread_acquisition_cc.cc + pcps_acquisition.cc pcps_assisted_acquisition_cc.cc pcps_acquisition_fine_doppler_cc.cc pcps_tong_acquisition_cc.cc @@ -28,40 +26,85 @@ set(ACQ_GR_BLOCKS_SOURCES pcps_quicksync_acquisition_cc.cc galileo_pcps_8ms_acquisition_cc.cc galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc -) - -if(OPENCL_FOUND) - set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_opencl_acquisition_cc.cc) -endif(OPENCL_FOUND) - -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} ) +set(ACQ_GR_BLOCKS_HEADERS + pcps_acquisition.h + pcps_assisted_acquisition_cc.h + pcps_acquisition_fine_doppler_cc.h + pcps_tong_acquisition_cc.h + pcps_cccwsr_acquisition_cc.h + pcps_quicksync_acquisition_cc.h + galileo_pcps_8ms_acquisition_cc.h + galileo_e5a_noncoherent_iq_acquisition_caf_cc.h +) + +if(ENABLE_FPGA) + set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_acquisition_fpga.cc) + set(ACQ_GR_BLOCKS_HEADERS ${ACQ_GR_BLOCKS_HEADERS} pcps_acquisition_fpga.h) +endif() if(OPENCL_FOUND) - include_directories( ${OPENCL_INCLUDE_DIRS} ) + set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_opencl_acquisition_cc.cc) + set(ACQ_GR_BLOCKS_HEADERS ${ACQ_GR_BLOCKS_HEADERS} pcps_opencl_acquisition_cc.h) +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} +) + +if(OPENCL_FOUND) + include_directories(${OPENCL_INCLUDE_DIRS}) if(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") - else(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) - endif(OS_IS_MACOSX) -endif(OPENCL_FOUND) + set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") + else() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) + endif() +endif() -file(GLOB ACQ_GR_BLOCKS_HEADERS "*.h") list(SORT ACQ_GR_BLOCKS_HEADERS) +list(SORT ACQ_GR_BLOCKS_SOURCES) add_library(acq_gr_blocks ${ACQ_GR_BLOCKS_SOURCES} ${ACQ_GR_BLOCKS_HEADERS}) -source_group(Headers FILES ${ACQ_GR_BLOCKS_HEADERS}) -target_link_libraries(acq_gr_blocks gnss_sp_libs gnss_system_parameters ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_FFT_LIBRARIES} ${VOLK_LIBRARIES} ${VOLK_GNSSSDR_LIBRARIES} ${OPT_LIBRARIES}) +source_group(Headers FILES ${ACQ_GR_BLOCKS_HEADERS}) -if(NOT VOLK_GNSSSDR_FOUND) +if(ENABLE_FPGA) + target_link_libraries(acq_gr_blocks + acquisition_lib + gnss_sp_libs + gnss_system_parameters + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${VOLK_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${OPT_LIBRARIES} + ${OPT_ACQUISITION_LIBRARIES} + ) +else() + target_link_libraries(acq_gr_blocks + gnss_sp_libs + gnss_system_parameters + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${VOLK_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${OPT_LIBRARIES} + ${MATIO_LIBRARIES} + ${OPT_ACQUISITION_LIBRARIES} + ) +endif() + +if(NOT VOLKGNSSSDR_FOUND) add_dependencies(acq_gr_blocks volk_gnsssdr_module) -endif(NOT VOLK_GNSSSDR_FOUND) +endif() diff --git a/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc index d62fefd6b..c884bcf34 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,59 +30,60 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e5a_noncoherent_iq_acquisition_caf_cc.h" -#include -#include +#include "control_message_factory.h" #include +#include #include #include -#include "control_message_factory.h" +#include +#include using google::LogMessage; galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr galileo_e5a_noncoherentIQ_make_acquisition_caf_cc( - unsigned int sampled_ms, - unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename, - bool both_signal_components_, - int CAF_window_hz_, - int Zero_padding_) + unsigned int sampled_ms, + unsigned int max_dwells, + unsigned int doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename, + bool both_signal_components_, + int CAF_window_hz_, + int Zero_padding_) { - return galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr( - new galileo_e5a_noncoherentIQ_acquisition_caf_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, bit_transition_flag, dump, dump_filename, both_signal_components_, CAF_window_hz_, Zero_padding_)); + new galileo_e5a_noncoherentIQ_acquisition_caf_cc(sampled_ms, max_dwells, doppler_max, fs_in, samples_per_ms, + samples_per_code, bit_transition_flag, dump, std::move(dump_filename), both_signal_components_, CAF_window_hz_, Zero_padding_)); } + galileo_e5a_noncoherentIQ_acquisition_caf_cc::galileo_e5a_noncoherentIQ_acquisition_caf_cc( - unsigned int sampled_ms, - unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename, - bool both_signal_components_, - int CAF_window_hz_, - int Zero_padding_) : - gr::block("galileo_e5a_noncoherentIQ_acquisition_caf_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) + unsigned int sampled_ms, + unsigned int max_dwells, + unsigned int doppler_max, + int64_t fs_in, + int samples_per_ms, + int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename, + bool both_signal_components_, + int CAF_window_hz_, + int Zero_padding_) : gr::block("galileo_e5a_noncoherentIQ_acquisition_caf_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(0, 0, sizeof(gr_complex))) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -106,42 +107,42 @@ galileo_e5a_noncoherentIQ_acquisition_caf_cc::galileo_e5a_noncoherentIQ_acquisit d_both_signal_components = both_signal_components_; d_CAF_window_hz = CAF_window_hz_; - d_inbuffer = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_fft_code_I_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitudeIA = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_inbuffer = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_fft_code_I_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitudeIA = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); if (d_both_signal_components == true) { - d_fft_code_Q_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitudeQA = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_code_Q_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitudeQA = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); } else { - d_fft_code_Q_A = 0; - d_magnitudeQA = 0; + d_fft_code_Q_A = nullptr; + d_magnitudeQA = nullptr; } // IF COHERENT INTEGRATION TIME > 1 if (d_sampled_ms > 1) { - d_fft_code_I_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitudeIB = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_code_I_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitudeIB = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); if (d_both_signal_components == true) { - d_fft_code_Q_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitudeQB = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_code_Q_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitudeQB = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); } else { - d_fft_code_Q_B = 0; - d_magnitudeQB = 0; + d_fft_code_Q_B = nullptr; + d_magnitudeQB = nullptr; } } else { - d_fft_code_I_B = 0; - d_magnitudeIB = 0; - d_fft_code_Q_B = 0; - d_magnitudeQB = 0; + d_fft_code_I_B = nullptr; + d_magnitudeIB = nullptr; + d_fft_code_Q_B = nullptr; + d_magnitudeQB = nullptr; } // Direct FFT @@ -152,23 +153,24 @@ galileo_e5a_noncoherentIQ_acquisition_caf_cc::galileo_e5a_noncoherentIQ_acquisit // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_doppler_resolution = 0; d_threshold = 0; d_doppler_step = 250; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; - d_CAF_vector = 0; - d_CAF_vector_I = 0; - d_CAF_vector_Q = 0; + d_CAF_vector = nullptr; + d_CAF_vector_I = nullptr; + d_CAF_vector_Q = nullptr; d_channel = 0; d_gr_stream_buffer = 0; } + galileo_e5a_noncoherentIQ_acquisition_caf_cc::~galileo_e5a_noncoherentIQ_acquisition_caf_cc() { if (d_num_doppler_bins > 0) @@ -219,27 +221,27 @@ galileo_e5a_noncoherentIQ_acquisition_caf_cc::~galileo_e5a_noncoherentIQ_acquisi } -void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_local_code(std::complex * codeI, std::complex * codeQ ) +void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_local_code(std::complex *codeI, std::complex *codeQ) { // DATA SIGNAL // Three replicas of data primary code. CODE A: (1,1,1) - memcpy(d_fft_if->get_inbuf(), codeI, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), codeI, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_code_I_A,d_fft_if->get_outbuf(),d_fft_size); + volk_32fc_conjugate_32fc(d_fft_code_I_A, d_fft_if->get_outbuf(), d_fft_size); // SAME FOR PILOT SIGNAL if (d_both_signal_components == true) { // Three replicas of pilot primary code. CODE A: (1,1,1) - memcpy(d_fft_if->get_inbuf(), codeQ, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), codeQ, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_code_Q_A,d_fft_if->get_outbuf(),d_fft_size); + volk_32fc_conjugate_32fc(d_fft_code_Q_A, d_fft_if->get_outbuf(), d_fft_size); } // IF INTEGRATION TIME > 1 code, we need to evaluate the other possible combination // Note: max integration time allowed = 3ms (dealt in adapter) @@ -247,39 +249,40 @@ void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_local_code(std::complexget_inbuf())[0], - &codeI[0], gr_complex(-1,0), - d_samples_per_code); + &codeI[0], gr_complex(-1, 0), + d_samples_per_code); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_code_I_B,d_fft_if->get_outbuf(),d_fft_size); + volk_32fc_conjugate_32fc(d_fft_code_I_B, d_fft_if->get_outbuf(), d_fft_size); if (d_both_signal_components == true) { // PILOT CODE B: First replica is inverted (0,1,1) volk_32fc_s32fc_multiply_32fc(&(d_fft_if->get_inbuf())[0], - &codeQ[0], gr_complex(-1,0), - d_samples_per_code); - d_fft_if->execute(); // We need the FFT of local code + &codeQ[0], gr_complex(-1, 0), + d_samples_per_code); + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_code_Q_B,d_fft_if->get_outbuf(),d_fft_size); + volk_32fc_conjugate_32fc(d_fft_code_Q_B, d_fft_if->get_outbuf(), d_fft_size); } } } + void galileo_e5a_noncoherentIQ_acquisition_caf_cc::init() { d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_doppler_step = 0U; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_mag = 0.0; d_input_power = 0.0; const double GALILEO_TWO_PI = 6.283185307179600; @@ -287,22 +290,22 @@ void galileo_e5a_noncoherentIQ_acquisition_caf_cc::init() // Count the number of bins d_num_doppler_bins = 0; for (int doppler = static_cast(-d_doppler_max); - doppler <= static_cast(d_doppler_max); - doppler += d_doppler_step) + doppler <= static_cast(d_doppler_max); + doppler += d_doppler_step) { d_num_doppler_bins++; } // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_bins]; for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = GALILEO_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + float phase_step_rad = GALILEO_TWO_PI * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); } /* CAF Filtering to resolve doppler ambiguity. Phase and quadrature must be processed @@ -310,17 +313,16 @@ void galileo_e5a_noncoherentIQ_acquisition_caf_cc::init() // if (d_CAF_filter) if (d_CAF_window_hz > 0) { - d_CAF_vector = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); - d_CAF_vector_I = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); + d_CAF_vector = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); + d_CAF_vector_I = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); if (d_both_signal_components == true) { - d_CAF_vector_Q = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); + d_CAF_vector_Q = static_cast(volk_gnsssdr_malloc(d_num_doppler_bins * sizeof(float), volk_gnsssdr_get_alignment())); } } } - void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_state(int state) { d_state = state; @@ -328,14 +330,16 @@ void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_state(int state) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_well_count = 0; d_mag = 0.0; d_input_power = 0.0; d_test_statistics = 0.0; } else if (d_state == 0) - {} + { + } else { LOG(ERROR) << "State can only be set to 0 or 1"; @@ -343,11 +347,9 @@ void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_state(int state) } - - -int galileo_e5a_noncoherentIQ_acquisition_caf_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) +int galileo_e5a_noncoherentIQ_acquisition_caf_cc::general_work(int noutput_items __attribute__((unused)), + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { /* * By J.Arribas, L.Esteve, M.Molina and M.Sales @@ -361,7 +363,7 @@ int galileo_e5a_noncoherentIQ_acquisition_caf_cc::general_work(int noutput_items * 7. Declare positive or negative acquisition using a message port */ - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL /* States: 0 Stop Channel * 1 Load the buffer until it reaches fft_size * 2 Acquisition algorithm @@ -369,448 +371,472 @@ int galileo_e5a_noncoherentIQ_acquisition_caf_cc::general_work(int noutput_items * 4 Negative acquisition */ switch (d_state) - { - case 0: { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - d_state = 1; - } - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); + case 0: + { + if (d_active) + { + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_state = 1; + } + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); - break; - } - case 1: - { - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - unsigned int buff_increment; - if (ninput_items[0] + d_buffer_count <= d_fft_size) - { - buff_increment = ninput_items[0]; - } - else - { - buff_increment = (d_fft_size - d_buffer_count); - } - memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex) * buff_increment); - // If buffer will be full in next iteration - if (d_buffer_count >= d_fft_size - d_gr_stream_buffer) - { - d_state = 2; - } - d_buffer_count += buff_increment; - d_sample_counter += buff_increment; // sample counter - consume_each(buff_increment); - break; - } - case 2: - { - // Fill last part of the buffer and reset counter - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - if (d_buffer_count < d_fft_size) - { - memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex)*(d_fft_size-d_buffer_count)); - } - d_sample_counter += d_fft_size-d_buffer_count; // sample counter + break; + } + case 1: + { + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer + unsigned int buff_increment; + if ((ninput_items[0] + d_buffer_count) <= d_fft_size) + { + buff_increment = ninput_items[0]; + } + else + { + buff_increment = d_fft_size - d_buffer_count; + } + memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex) * buff_increment); + // If buffer will be full in next iteration + if (d_buffer_count >= (d_fft_size - d_gr_stream_buffer)) + { + d_state = 2; + } + d_buffer_count += buff_increment; + d_sample_counter += static_cast(buff_increment); // sample counter + consume_each(buff_increment); + break; + } + case 2: + { + // Fill last part of the buffer and reset counter + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer + if (d_buffer_count < d_fft_size) + { + memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex) * (d_fft_size - d_buffer_count)); + } + d_sample_counter += static_cast(d_fft_size - d_buffer_count); // sample counter - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - uint32_t indext_IA = 0; - uint32_t indext_IB = 0; - uint32_t indext_QA = 0; - uint32_t indext_QB = 0; - float magt = 0.0; - float magt_IA = 0.0; - float magt_IB = 0.0; - float magt_QA = 0.0; - float magt_QB = 0.0; - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - d_input_power = 0.0; - d_mag = 0.0; - d_well_count++; + // initialize acquisition algorithm + int doppler; + uint32_t indext = 0; + uint32_t indext_IA = 0; + uint32_t indext_IB = 0; + uint32_t indext_QA = 0; + uint32_t indext_QB = 0; + float magt = 0.0; + float magt_IA = 0.0; + float magt_IB = 0.0; + float magt_QA = 0.0; + float magt_QB = 0.0; + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + d_input_power = 0.0; + d_mag = 0.0; + d_well_count++; - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; - // 1- Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitudeIA, d_inbuffer, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitudeIA, d_fft_size); - d_input_power /= static_cast(d_fft_size); + // 1- Compute the input signal power estimation + volk_32fc_magnitude_squared_32f(d_magnitudeIA, d_inbuffer, d_fft_size); + volk_32f_accumulator_s32f(&d_input_power, d_magnitudeIA, d_fft_size); + d_input_power /= static_cast(d_fft_size); - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps + // 2- Doppler frequency search loop + for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), d_inbuffer, + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), d_inbuffer, d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); + // 3- Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); - // CODE IA - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code reference using SIMD operations with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + // CODE IA + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd code reference using SIMD operations with VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_code_I_A, d_fft_size); - // compute the inverse FFT - d_ifft->execute(); + // compute the inverse FFT + d_ifft->execute(); - // Search maximum - volk_32fc_magnitude_squared_32f(d_magnitudeIA, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_IA, d_magnitudeIA, d_fft_size); - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt_IA = d_magnitudeIA[indext_IA] / (fft_normalization_factor * fft_normalization_factor); + // Search maximum + volk_32fc_magnitude_squared_32f(d_magnitudeIA, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_IA, d_magnitudeIA, d_fft_size); + // Normalize the maximum value to correct the scale factor introduced by FFTW + magt_IA = d_magnitudeIA[indext_IA] / (fft_normalization_factor * fft_normalization_factor); - if (d_both_signal_components == true) - { - // REPEAT FOR ALL CODES. CODE_QA - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + if (d_both_signal_components == true) + { + // REPEAT FOR ALL CODES. CODE_QA + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_code_Q_A, d_fft_size); - d_ifft->execute(); - volk_32fc_magnitude_squared_32f(d_magnitudeQA, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_QA, d_magnitudeQA, d_fft_size); - magt_QA = d_magnitudeQA[indext_QA] / (fft_normalization_factor * fft_normalization_factor); - } - if (d_sampled_ms > 1) // If Integration time > 1 code - { - // REPEAT FOR ALL CODES. CODE_IB - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_ifft->execute(); + volk_32fc_magnitude_squared_32f(d_magnitudeQA, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_QA, d_magnitudeQA, d_fft_size); + magt_QA = d_magnitudeQA[indext_QA] / (fft_normalization_factor * fft_normalization_factor); + } + if (d_sampled_ms > 1) // If Integration time > 1 code + { + // REPEAT FOR ALL CODES. CODE_IB + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_code_I_B, d_fft_size); - d_ifft->execute(); - volk_32fc_magnitude_squared_32f(d_magnitudeIB, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_IB, d_magnitudeIB, d_fft_size); - magt_IB = d_magnitudeIB[indext_IB] / (fft_normalization_factor * fft_normalization_factor); + d_ifft->execute(); + volk_32fc_magnitude_squared_32f(d_magnitudeIB, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_IB, d_magnitudeIB, d_fft_size); + magt_IB = d_magnitudeIB[indext_IB] / (fft_normalization_factor * fft_normalization_factor); - if (d_both_signal_components == true) - { - // REPEAT FOR ALL CODES. CODE_QB - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + if (d_both_signal_components == true) + { + // REPEAT FOR ALL CODES. CODE_QB + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_code_Q_B, d_fft_size); - d_ifft->execute(); - volk_32fc_magnitude_squared_32f(d_magnitudeQB, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_QB, d_magnitudeQB, d_fft_size); - magt_QB = d_magnitudeIB[indext_QB] / (fft_normalization_factor * fft_normalization_factor); - } - } + d_ifft->execute(); + volk_32fc_magnitude_squared_32f(d_magnitudeQB, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_QB, d_magnitudeQB, d_fft_size); + magt_QB = d_magnitudeIB[indext_QB] / (fft_normalization_factor * fft_normalization_factor); + } + } - // Integrate noncoherently the two best combinations (I² + Q²) - // and store the result in the I channel. - // If CAF filter to resolve doppler ambiguity is needed, - // peak is stored before non-coherent integration. - if (d_sampled_ms > 1) // T_integration > 1 code - { - if (magt_IA >= magt_IB) - { - // if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IA;} - if (d_CAF_window_hz > 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA];} - if (d_both_signal_components) - { - // Integrate non-coherently I+Q - if (magt_QA >= magt_QB) - { - // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} - if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];} - for (unsigned int i=0; i 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB];} - for (unsigned int i=0; i 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIB[indext_IB];} - if (d_both_signal_components) - { - // Integrate non-coherently I+Q - if (magt_QA >= magt_QB) - { - //if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} - if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];} - for (unsigned int i=0; i 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB];} - for (unsigned int i=0; i 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA];} - if (d_both_signal_components) - { - // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} - if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];} - // NON-Coherent integration of only 1 code - for (unsigned int i=0; i 1) // T_integration > 1 code + { + if (magt_IA >= magt_IB) + { + // if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IA;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA]; + } + if (d_both_signal_components) + { + // Integrate non-coherently I+Q + if (magt_QA >= magt_QB) + { + // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA]; + } + for (unsigned int i = 0; i < d_fft_size; i++) + { + d_magnitudeIA[i] += d_magnitudeQA[i]; + } + } + else + { + // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QB;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB]; + } + for (unsigned int i = 0; i < d_fft_size; i++) + { + d_magnitudeIA[i] += d_magnitudeQB[i]; + } + } + } + volk_gnsssdr_32f_index_max_32u(&indext, d_magnitudeIA, d_fft_size); + magt = d_magnitudeIA[indext] / (fft_normalization_factor * fft_normalization_factor); + } + else + { + // if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IB;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_I[doppler_index] = d_magnitudeIB[indext_IB]; + } + if (d_both_signal_components) + { + // Integrate non-coherently I+Q + if (magt_QA >= magt_QB) + { + //if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA]; + } + for (unsigned int i = 0; i < d_fft_size; i++) + { + d_magnitudeIB[i] += d_magnitudeQA[i]; + } + } + else + { + // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QB;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB]; + } + for (unsigned int i = 0; i < d_fft_size; i++) + { + d_magnitudeIB[i] += d_magnitudeQB[i]; + } + } + } + volk_gnsssdr_32f_index_max_32u(&indext, d_magnitudeIB, d_fft_size); + magt = d_magnitudeIB[indext] / (fft_normalization_factor * fft_normalization_factor); + } + } + else + { + // if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IA;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA]; + } + if (d_both_signal_components) + { + // if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;} + if (d_CAF_window_hz > 0) + { + d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA]; + } + // NON-Coherent integration of only 1 code + for (unsigned int i = 0; i < d_fft_size; i++) + { + d_magnitudeIA[i] += d_magnitudeQA[i]; + } + } + volk_gnsssdr_32f_index_max_32u(&indext, d_magnitudeIA, d_fft_size); + magt = d_magnitudeIA[indext] / (fft_normalization_factor * fft_normalization_factor); + } - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - // In case that d_bit_transition_flag = true, we compare the potentially - // new maximum test statistics (d_mag/d_input_power) with the value in - // d_test_statistics. When the second dwell is being processed, the value - // of d_mag/d_input_power could be lower than d_test_statistics (i.e, - // the maximum test statistics in the previous dwell is greater than - // current d_mag/d_input_power). Note that d_test_statistics is not - // restarted between consecutive dwells in multidwell operation. - if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + // 4- record the maximum peak and the associated synchronization parameters + if (d_mag < magt) + { + d_mag = magt; + // In case that d_bit_transition_flag = true, we compare the potentially + // new maximum test statistics (d_mag/d_input_power) with the value in + // d_test_statistics. When the second dwell is being processed, the value + // of d_mag/d_input_power could be lower than d_test_statistics (i.e, + // the maximum test statistics in the previous dwell is greater than + // current d_mag/d_input_power). Note that d_test_statistics is not + // restarted between consecutive dwells in multidwell operation. + if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) + { + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; + // 5- Compute the test statistics and compare to the threshold + d_test_statistics = d_mag / d_input_power; + } + } - // 5- Compute the test statistics and compare to the threshold - d_test_statistics = d_mag / d_input_power; - } - } + // Record results to file if required + if (d_dump) + { + std::stringstream filename; + std::streamsize n = sizeof(float) * (d_fft_size); // noncomplex file write + filename.str(""); + filename << "../data/test_statistics_E5a_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + if (d_sampled_ms > 1) // If integration time > 1 code + { + if (magt_IA >= magt_IB) + { + d_dump_file.write(reinterpret_cast(d_magnitudeIA), n); + } + else + { + d_dump_file.write(reinterpret_cast(d_magnitudeIB), n); + } + } + else + { + d_dump_file.write(reinterpret_cast(d_magnitudeIA), n); + } + d_dump_file.close(); + } + } + // std::cout << "d_mag " << d_mag << ".d_sample_counter " << d_sample_counter << ". acq delay " << d_gnss_synchro->Acq_delay_samples<< " indext "<< indext << std::endl; + // 6 OPTIONAL: CAF filter to avoid Doppler ambiguity in bit transition. + if (d_CAF_window_hz > 0) + { + int CAF_bins_half; + auto *accum = static_cast(volk_gnsssdr_malloc(sizeof(float), volk_gnsssdr_get_alignment())); + CAF_bins_half = d_CAF_window_hz / (2 * d_doppler_step); + float weighting_factor; + weighting_factor = 0.5 / static_cast(CAF_bins_half); + // weighting_factor = 0; + // std::cout << "weighting_factor " << weighting_factor << std::endl; + // Initialize first iterations + for (int doppler_index = 0; doppler_index < CAF_bins_half; doppler_index++) + { + d_CAF_vector[doppler_index] = 0; + // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], d_CAF_vector_I, CAF_bins_half+doppler_index+1); + for (int i = 0; i < CAF_bins_half + doppler_index + 1; i++) + { + d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * static_cast((doppler_index - i))); + } + // d_CAF_vector[doppler_index] /= CAF_bins_half+doppler_index+1; + d_CAF_vector[doppler_index] /= 1 + CAF_bins_half + doppler_index - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * doppler_index * (doppler_index + 1) / 2; // triangles = [n*(n+1)/2] + if (d_both_signal_components) + { + accum[0] = 0; + // volk_32f_accumulator_s32f_a(&accum[0], d_CAF_vector_Q, CAF_bins_half+doppler_index+1); + for (int i = 0; i < CAF_bins_half + doppler_index + 1; i++) + { + accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * static_cast(abs(doppler_index - i))); + } + // accum[0] /= CAF_bins_half+doppler_index+1; + accum[0] /= 1 + CAF_bins_half + doppler_index - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * doppler_index * (doppler_index + 1) / 2; // triangles = [n*(n+1)/2] + d_CAF_vector[doppler_index] += accum[0]; + } + } + // Body loop + for (unsigned int doppler_index = CAF_bins_half; doppler_index < d_num_doppler_bins - CAF_bins_half; doppler_index++) + { + d_CAF_vector[doppler_index] = 0; + // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], 2*CAF_bins_half+1); + for (int i = doppler_index - CAF_bins_half; i < static_cast(doppler_index + CAF_bins_half + 1); i++) + { + d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * static_cast((doppler_index - i))); + } + // d_CAF_vector[doppler_index] /= 2*CAF_bins_half+1; + d_CAF_vector[doppler_index] /= 1 + 2 * CAF_bins_half - 2 * weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2; + if (d_both_signal_components) + { + accum[0] = 0; + // volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], 2*CAF_bins_half); + for (int i = doppler_index - CAF_bins_half; i < static_cast(doppler_index + CAF_bins_half + 1); i++) + { + accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * static_cast((doppler_index - i))); + } + // accum[0] /= 2*CAF_bins_half+1; + accum[0] /= 1 + 2 * CAF_bins_half - 2 * weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2; + d_CAF_vector[doppler_index] += accum[0]; + } + } + // Final iterations + for (int doppler_index = d_num_doppler_bins - CAF_bins_half; doppler_index < static_cast(d_num_doppler_bins); doppler_index++) + { + d_CAF_vector[doppler_index] = 0; + // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index)); + for (int i = doppler_index - CAF_bins_half; i < static_cast(d_num_doppler_bins); i++) + { + d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * (abs(doppler_index - i))); + } + // d_CAF_vector[doppler_index] /= CAF_bins_half+(d_num_doppler_bins-doppler_index); + d_CAF_vector[doppler_index] /= 1 + CAF_bins_half + (d_num_doppler_bins - doppler_index - 1) - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * (d_num_doppler_bins - doppler_index - 1) * (d_num_doppler_bins - doppler_index) / 2; + if (d_both_signal_components) + { + accum[0] = 0; + // volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index)); + for (int i = doppler_index - CAF_bins_half; i < static_cast(d_num_doppler_bins); i++) + { + accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * (abs(doppler_index - i))); + } + // accum[0] /= CAF_bins_half+(d_num_doppler_bins-doppler_index); + accum[0] /= 1 + CAF_bins_half + (d_num_doppler_bins - doppler_index - 1) - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * (d_num_doppler_bins - doppler_index - 1) * (d_num_doppler_bins - doppler_index) / 2; + d_CAF_vector[doppler_index] += accum[0]; + } + } - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = sizeof(float) * (d_fft_size); // noncomplex file write - filename.str(""); - filename << "../data/test_statistics_E5a_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - if (d_sampled_ms > 1) // If integration time > 1 code - { - if (magt_IA >= magt_IB) - { - d_dump_file.write((char*)d_magnitudeIA, n); - } - else - { - d_dump_file.write((char*)d_magnitudeIB, n); - } - } - else - { - d_dump_file.write((char*)d_magnitudeIA, n); - } - d_dump_file.close(); - } - } - // std::cout << "d_mag " << d_mag << ".d_sample_counter " << d_sample_counter << ". acq delay " << d_gnss_synchro->Acq_delay_samples<< " indext "<< indext << std::endl; - // 6 OPTIONAL: CAF filter to avoid Doppler ambiguity in bit transition. - if (d_CAF_window_hz > 0) - { - int CAF_bins_half; - float* accum = static_cast(volk_gnsssdr_malloc(sizeof(float), volk_gnsssdr_get_alignment())); - CAF_bins_half = d_CAF_window_hz / (2 * d_doppler_step); - float weighting_factor; - weighting_factor = 0.5 / static_cast(CAF_bins_half); - // weighting_factor = 0; - // std::cout << "weighting_factor " << weighting_factor << std::endl; - // Initialize first iterations - for (int doppler_index = 0; doppler_index < CAF_bins_half; doppler_index++) - { - d_CAF_vector[doppler_index] = 0; - // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], d_CAF_vector_I, CAF_bins_half+doppler_index+1); - for (int i = 0; i < CAF_bins_half + doppler_index + 1; i++) - { - d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * static_cast((doppler_index - i))); - } - // d_CAF_vector[doppler_index] /= CAF_bins_half+doppler_index+1; - d_CAF_vector[doppler_index] /= 1 + CAF_bins_half + doppler_index - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * doppler_index * (doppler_index + 1) / 2; // triangles = [n*(n+1)/2] - if (d_both_signal_components) - { - accum[0] = 0; - // volk_32f_accumulator_s32f_a(&accum[0], d_CAF_vector_Q, CAF_bins_half+doppler_index+1); - for (int i = 0; i < CAF_bins_half + doppler_index + 1; i++) - { - accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * static_cast(abs(doppler_index - i))); - } - // accum[0] /= CAF_bins_half+doppler_index+1; - accum[0] /= 1 + CAF_bins_half + doppler_index - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * doppler_index * (doppler_index + 1) / 2; // triangles = [n*(n+1)/2] - d_CAF_vector[doppler_index] += accum[0]; - } - } - // Body loop - for (unsigned int doppler_index = CAF_bins_half; doppler_index < d_num_doppler_bins - CAF_bins_half; doppler_index++) - { - d_CAF_vector[doppler_index] = 0; - // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], 2*CAF_bins_half+1); - for (int i = doppler_index - CAF_bins_half; i < static_cast(doppler_index + CAF_bins_half + 1); i++) - { - d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * static_cast((doppler_index - i))); - } - // d_CAF_vector[doppler_index] /= 2*CAF_bins_half+1; - d_CAF_vector[doppler_index] /= 1 + 2 * CAF_bins_half - 2 * weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2; - if (d_both_signal_components) - { - accum[0] = 0; - // volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], 2*CAF_bins_half); - for (int i = doppler_index-CAF_bins_half; i < static_cast(doppler_index + CAF_bins_half + 1); i++) - { - accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * static_cast((doppler_index - i))); - } - // accum[0] /= 2*CAF_bins_half+1; - accum[0] /= 1 + 2 * CAF_bins_half - 2 * weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2; - d_CAF_vector[doppler_index] += accum[0]; - } - } - // Final iterations - for (int doppler_index = d_num_doppler_bins - CAF_bins_half; doppler_index < static_cast(d_num_doppler_bins); doppler_index++) - { - d_CAF_vector[doppler_index] = 0; - // volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index)); - for (int i = doppler_index - CAF_bins_half; i < static_cast(d_num_doppler_bins); i++) - { - d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1 - weighting_factor * (abs(doppler_index - i))); - } - // d_CAF_vector[doppler_index] /= CAF_bins_half+(d_num_doppler_bins-doppler_index); - d_CAF_vector[doppler_index] /= 1 + CAF_bins_half + (d_num_doppler_bins - doppler_index - 1) - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * (d_num_doppler_bins - doppler_index - 1) * (d_num_doppler_bins - doppler_index) / 2; - if (d_both_signal_components) - { - accum[0] = 0; - // volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index)); - for (int i = doppler_index-CAF_bins_half; i < static_cast(d_num_doppler_bins); i++) - { - accum[0] += d_CAF_vector_Q[i] * (1 - weighting_factor * (abs(doppler_index - i))); - } - // accum[0] /= CAF_bins_half+(d_num_doppler_bins-doppler_index); - accum[0] /= 1 + CAF_bins_half + (d_num_doppler_bins - doppler_index - 1) - weighting_factor * CAF_bins_half * (CAF_bins_half + 1) / 2 - weighting_factor * (d_num_doppler_bins - doppler_index - 1) * (d_num_doppler_bins - doppler_index) / 2; - d_CAF_vector[doppler_index] += accum[0]; - } - } + // Recompute the maximum doppler peak + volk_gnsssdr_32f_index_max_32u(&indext, d_CAF_vector, d_num_doppler_bins); + doppler = -static_cast(d_doppler_max) + d_doppler_step * indext; + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + // Dump if required, appended at the end of the file + if (d_dump) + { + std::stringstream filename; + std::streamsize n = sizeof(float) * (d_num_doppler_bins); // noncomplex file write + filename.str(""); + filename << "../data/test_statistics_E5a_sat_" << d_gnss_synchro->PRN << "_CAF.dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + d_dump_file.write(reinterpret_cast(d_CAF_vector), n); + d_dump_file.close(); + } + volk_gnsssdr_free(accum); + } - // Recompute the maximum doppler peak - volk_gnsssdr_32f_index_max_32u(&indext, d_CAF_vector, d_num_doppler_bins); - doppler = -static_cast(d_doppler_max) + d_doppler_step * indext; - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - // Dump if required, appended at the end of the file - if (d_dump) - { - std::stringstream filename; - std::streamsize n = sizeof(float) * (d_num_doppler_bins); // noncomplex file write - filename.str(""); - filename << "../data/test_statistics_E5a_sat_" << d_gnss_synchro->PRN << "_CAF.dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_CAF_vector, n); - d_dump_file.close(); - } - volk_gnsssdr_free(accum); - } + if (d_well_count == d_max_dwells) + { + if (d_test_statistics > d_threshold) + { + d_state = 3; // Positive acquisition + } + else + { + d_state = 4; // Negative acquisition + } + } + else + { + d_state = 1; + } - if (d_well_count == d_max_dwells) - { - if (d_test_statistics > d_threshold) - { - d_state = 3; // Positive acquisition - } - else - { - d_state = 4; // Negative acquisition - } - } - else - { - d_state = 1; - } + consume_each(d_fft_size - d_buffer_count); + d_buffer_count = 0; + break; + } + case 3: + { + // 7.1- Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; - consume_each(d_fft_size - d_buffer_count); - d_buffer_count = 0; - break; + d_active = false; + d_state = 0; + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + break; + } + case 4: + { + // 7.2- Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + break; + } } - case 3: - { - // 7.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - d_active = false; - d_state = 0; - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - break; - } - case 4: - { - // 7.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - break; - } - } - - return noutput_items; + return 0; } - diff --git a/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.h b/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.h index d4d3b31d4..352dc938c 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/galileo_e5a_noncoherent_iq_acquisition_caf_cc.h @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,12 +38,12 @@ #ifndef GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_ #define GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_ +#include "gnss_synchro.h" +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" class galileo_e5a_noncoherentIQ_acquisition_caf_cc; @@ -51,15 +51,15 @@ typedef boost::shared_ptr galileo_ galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(unsigned int sampled_ms, - unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename, - bool both_signal_components_, - int CAF_window_hz_, - int Zero_padding_); + unsigned int max_dwells, + unsigned int doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename, + bool both_signal_components_, + int CAF_window_hz_, + int Zero_padding_); /*! * \brief This class implements a Parallel Code Phase Search Acquisition. @@ -67,40 +67,39 @@ galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(unsigned int sampled_ms, * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", * Algorithm 1, for a pseudocode description of this implementation. */ -class galileo_e5a_noncoherentIQ_acquisition_caf_cc: public gr::block +class galileo_e5a_noncoherentIQ_acquisition_caf_cc : public gr::block { private: friend galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr galileo_e5a_noncoherentIQ_make_acquisition_caf_cc( - unsigned int sampled_ms, - unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename, - bool both_signal_components_, - int CAF_window_hz_, - int Zero_padding_); + unsigned int sampled_ms, + unsigned int max_dwells, + unsigned int doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename, + bool both_signal_components_, + int CAF_window_hz_, + int Zero_padding_); galileo_e5a_noncoherentIQ_acquisition_caf_cc( - unsigned int sampled_ms, - unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename, - bool both_signal_components_, - int CAF_window_hz_, - int Zero_padding_); + unsigned int sampled_ms, + unsigned int max_dwells, + unsigned int doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename, + bool both_signal_components_, + int CAF_window_hz_, + int Zero_padding_); void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); - float estimate_input_power(gr_complex *in ); + int doppler_offset); + float estimate_input_power(gr_complex* in); - long d_fs_in; - long d_freq; + int64_t d_fs_in; int d_samples_per_ms; int d_sampled_ms; int d_samples_per_code; @@ -112,7 +111,7 @@ private: unsigned int d_max_dwells; unsigned int d_well_count; unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; unsigned int d_num_doppler_bins; gr_complex* d_fft_code_I_A; @@ -122,7 +121,7 @@ private: gr_complex* d_inbuffer; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; + Gnss_Synchro* d_gnss_synchro; unsigned int d_code_phase; float d_doppler_freq; float d_mag; @@ -138,14 +137,14 @@ private: int d_state; bool d_dump; bool d_both_signal_components; -// bool d_CAF_filter; + // bool d_CAF_filter; int d_CAF_window_hz; float* d_CAF_vector; float* d_CAF_vector_I; float* d_CAF_vector_Q; -// double* d_CAF_vector; -// double* d_CAF_vector_I; -// double* d_CAF_vector_Q; + // double* d_CAF_vector; + // double* d_CAF_vector_I; + // double* d_CAF_vector_Q; unsigned int d_channel; std::string d_dump_filename; unsigned int d_buffer_count; @@ -155,98 +154,96 @@ public: /*! * \brief Default destructor. */ - ~galileo_e5a_noncoherentIQ_acquisition_caf_cc(); + ~galileo_e5a_noncoherentIQ_acquisition_caf_cc(); - /*! + /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + d_gnss_synchro = p_gnss_synchro; + } - /*! + /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() - { - return d_mag; - } + inline unsigned int mag() const + { + return d_mag; + } - /*! + /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init(); - /*! + /*! * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code, std::complex * codeQ); + void set_local_code(std::complex* code, std::complex* codeQ); - /*! + /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) - { - d_active = active; - } + inline void set_active(bool active) + { + d_active = active; + } - /*! + /*! * \brief If set to 1, ensures that acquisition starts at the * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int state); - /*! + /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } + inline void set_channel(unsigned int channel) + { + d_channel = channel; + } - /*! + /*! * \brief Set statistics threshold of PCPS algorithm. * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } + inline void set_threshold(float threshold) + { + d_threshold = threshold; + } - /*! + /*! * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } + inline void set_doppler_max(unsigned int doppler_max) + { + d_doppler_max = doppler_max; + } - /*! + /*! * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } + inline void set_doppler_step(unsigned int doppler_step) + { + d_doppler_step = doppler_step; + } - - /*! + /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); }; #endif /* GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_ */ diff --git a/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.cc index b2ebba1df..275b8aad0 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,47 +24,52 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_pcps_8ms_acquisition_cc.h" -#include +#include "control_message_factory.h" #include #include #include #include -#include "control_message_factory.h" +#include +#include using google::LogMessage; galileo_pcps_8ms_acquisition_cc_sptr galileo_pcps_8ms_make_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename) + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, std::string dump_filename) { - return galileo_pcps_8ms_acquisition_cc_sptr( - new galileo_pcps_8ms_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, dump, dump_filename)); + new galileo_pcps_8ms_acquisition_cc(sampled_ms, max_dwells, doppler_max, fs_in, samples_per_ms, + samples_per_code, dump, std::move(dump_filename))); } galileo_pcps_8ms_acquisition_cc::galileo_pcps_8ms_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename) : - gr::block("galileo_pcps_8ms_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename) : gr::block("galileo_pcps_8ms_acquisition_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), + gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -77,9 +82,9 @@ galileo_pcps_8ms_acquisition_cc::galileo_pcps_8ms_acquisition_cc( d_input_power = 0.0; d_num_doppler_bins = 0; - d_fft_code_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_fft_code_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_code_A = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_fft_code_B = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -89,24 +94,25 @@ galileo_pcps_8ms_acquisition_cc::galileo_pcps_8ms_acquisition_cc( // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_doppler_resolution = 0; d_threshold = 0; d_doppler_step = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; d_channel = 0; } + galileo_pcps_8ms_acquisition_cc::~galileo_pcps_8ms_acquisition_cc() { if (d_num_doppler_bins > 0) { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) + for (uint32_t i = 0; i < d_num_doppler_bins; i++) { volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); } @@ -126,79 +132,82 @@ galileo_pcps_8ms_acquisition_cc::~galileo_pcps_8ms_acquisition_cc() } } -void galileo_pcps_8ms_acquisition_cc::set_local_code(std::complex * code) + +void galileo_pcps_8ms_acquisition_cc::set_local_code(std::complex *code) { // code A: two replicas of a primary code - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_code_A, d_fft_if->get_outbuf(), d_fft_size); // code B: two replicas of a primary code; the second replica is inverted. volk_32fc_s32fc_multiply_32fc(&(d_fft_if->get_inbuf())[d_samples_per_code], - &code[d_samples_per_code], gr_complex(-1,0), - d_samples_per_code); + &code[d_samples_per_code], gr_complex(-1, 0), + d_samples_per_code); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_code_B, d_fft_if->get_outbuf(), d_fft_size); } + void galileo_pcps_8ms_acquisition_cc::init() { d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_mag = 0.0; d_input_power = 0.0; const double GALILEO_TWO_PI = 6.283185307179600; // Count the number of bins d_num_doppler_bins = 0; - for (int doppler = static_cast(-d_doppler_max); - doppler <= static_cast(d_doppler_max); + for (auto doppler = static_cast(-d_doppler_max); + doppler <= static_cast(d_doppler_max); doppler += d_doppler_step) - { - d_num_doppler_bins++; - } + { + d_num_doppler_bins++; + } // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_bins]; + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = static_cast(GALILEO_TWO_PI) * (d_freq + doppler) / static_cast(d_fs_in); + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + float phase_step_rad = static_cast(GALILEO_TWO_PI) * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); } } -void galileo_pcps_8ms_acquisition_cc::set_state(int state) +void galileo_pcps_8ms_acquisition_cc::set_state(int32_t state) { d_state = state; if (d_state == 1) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_well_count = 0; d_mag = 0.0; d_input_power = 0.0; d_test_statistics = 0.0; } else if (d_state == 0) - {} + { + } else { LOG(ERROR) << "State can only be set to 0 or 1"; @@ -206,218 +215,217 @@ void galileo_pcps_8ms_acquisition_cc::set_state(int state) } - int galileo_pcps_8ms_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int32_t acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL switch (d_state) - { - case 0: { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - - d_state = 1; - } - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - break; - } - - case 1: - { - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - uint32_t indext_A = 0; - uint32_t indext_B = 0; - float magt = 0.0; - float magt_A = 0.0; - float magt_B = 0.0; - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - d_input_power = 0.0; - d_mag = 0.0; - - d_sample_counter += d_fft_size; // sample counter - - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - // 1- Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= static_cast(d_fft_size); - - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code A reference using SIMD operations with - // VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_code_A, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Search maximum - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_A, d_magnitude, d_fft_size); - - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt_A = d_magnitude[indext_A] / (fft_normalization_factor * fft_normalization_factor); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code B reference using SIMD operations with - // VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_code_B, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Search maximum - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_B, d_magnitude, d_fft_size); - - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt_B = d_magnitude[indext_B] / (fft_normalization_factor * fft_normalization_factor); - - // Take the greater magnitude - if (magt_A >= magt_B) + case 0: + { + if (d_active) { - magt = magt_A; - indext = indext_A; - } - else - { - magt = magt_B; - indext = indext_B; + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + + d_state = 1; } - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - } + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } + break; + } - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; + case 1: + { + // initialize acquisition algorithm + int32_t doppler; + uint32_t indext = 0; + uint32_t indext_A = 0; + uint32_t indext_B = 0; + float magt = 0.0; + float magt_A = 0.0; + float magt_B = 0.0; + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + d_input_power = 0.0; + d_mag = 0.0; - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition - } + d_sample_counter += static_cast(d_fft_size); // sample counter - consume_each(1); + d_well_count++; - break; + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; + + // 1- Compute the input signal power estimation + volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); + volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); + d_input_power /= static_cast(d_fft_size); + + // 2- Doppler frequency search loop + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, + d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + + // 3- Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd code A reference using SIMD operations with + // VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_fft_if->get_outbuf(), d_fft_code_A, d_fft_size); + + // compute the inverse FFT + d_ifft->execute(); + + // Search maximum + volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_A, d_magnitude, d_fft_size); + + // Normalize the maximum value to correct the scale factor introduced by FFTW + magt_A = d_magnitude[indext_A] / (fft_normalization_factor * fft_normalization_factor); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd code B reference using SIMD operations with + // VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_fft_if->get_outbuf(), d_fft_code_B, d_fft_size); + + // compute the inverse FFT + d_ifft->execute(); + + // Search maximum + volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_B, d_magnitude, d_fft_size); + + // Normalize the maximum value to correct the scale factor introduced by FFTW + magt_B = d_magnitude[indext_B] / (fft_normalization_factor * fft_normalization_factor); + + // Take the greater magnitude + if (magt_A >= magt_B) + { + magt = magt_A; + indext = indext_A; + } + else + { + magt = magt_B; + indext = indext_B; + } + + // 4- record the maximum peak and the associated synchronization parameters + if (d_mag < magt) + { + d_mag = magt; + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; + } + + // Record results to file if required + if (d_dump) + { + std::stringstream filename; + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + filename.str(""); + filename << "../data/test_statistics_" << d_gnss_synchro->System + << "_" << d_gnss_synchro->Signal << "_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + d_dump_file.write(reinterpret_cast(d_ifft->get_outbuf()), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.close(); + } + } + + // 5- Compute the test statistics and compare to the threshold + //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; + d_test_statistics = d_mag / d_input_power; + + if (d_test_statistics > d_threshold) + { + d_state = 2; // Positive acquisition + } + else if (d_well_count == d_max_dwells) + { + d_state = 3; // Negative acquisition + } + + consume_each(1); + + break; + } + + case 2: + { + // 6.1- Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += d_fft_size * ninput_items[0]; // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } + + case 3: + { + // 6.2- Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } } - case 2: - { - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - return noutput_items; } diff --git a/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.h index 332b91083..d9f794d1e 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/galileo_pcps_8ms_acquisition_cc.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,67 +32,81 @@ #ifndef GNSS_SDR_PCPS_8MS_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_8MS_ACQUISITION_CC_H_ +#include "gnss_synchro.h" +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" class galileo_pcps_8ms_acquisition_cc; typedef boost::shared_ptr galileo_pcps_8ms_acquisition_cc_sptr; galileo_pcps_8ms_acquisition_cc_sptr -galileo_pcps_8ms_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); +galileo_pcps_8ms_make_acquisition_cc(uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition for * Galileo E1 signals with coherent integration time = 8 ms (two codes) */ -class galileo_pcps_8ms_acquisition_cc: public gr::block +class galileo_pcps_8ms_acquisition_cc : public gr::block { private: friend galileo_pcps_8ms_acquisition_cc_sptr - galileo_pcps_8ms_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); + galileo_pcps_8ms_make_acquisition_cc( + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename); + galileo_pcps_8ms_acquisition_cc( + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename); - galileo_pcps_8ms_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); + void calculate_magnitudes( + gr_complex* fft_begin, + int32_t doppler_shift, + int32_t doppler_offset); - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); - - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - unsigned int d_doppler_resolution; + int64_t d_fs_in; + int32_t d_samples_per_ms; + int32_t d_samples_per_code; + uint32_t d_doppler_resolution; float d_threshold; std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint32_t d_doppler_max; + uint32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_max_dwells; + uint32_t d_well_count; + uint32_t d_fft_size; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; + uint32_t d_num_doppler_bins; gr_complex* d_fft_code_A; gr_complex* d_fft_code_B; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_mag; float* d_magnitude; @@ -100,9 +114,9 @@ private: float d_test_statistics; std::ofstream d_dump_file; bool d_active; - int d_state; + int32_t d_state; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; public: @@ -116,7 +130,7 @@ public: * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { d_gnss_synchro = p_gnss_synchro; } @@ -124,7 +138,7 @@ public: /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() + inline uint32_t mag() const { return d_mag; } @@ -138,14 +152,14 @@ public: * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) + inline void set_active(bool active) { d_active = active; } @@ -155,13 +169,13 @@ public: * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int32_t state); /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) + inline void set_channel(uint32_t channel) { d_channel = channel; } @@ -171,7 +185,7 @@ public: * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) + inline void set_threshold(float threshold) { d_threshold = threshold; } @@ -180,7 +194,7 @@ public: * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) + inline void set_doppler_max(uint32_t doppler_max) { d_doppler_max = doppler_max; } @@ -189,7 +203,7 @@ public: * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) + inline void set_doppler_step(uint32_t doppler_step) { d_doppler_step = doppler_step; } @@ -197,9 +211,9 @@ public: /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); }; #endif /* GNSS_SDR_PCPS_8MS_ACQUISITION_CC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.cc new file mode 100644 index 000000000..d95bb24cb --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.cc @@ -0,0 +1,1025 @@ +/*! + * \file pcps_acquisition.cc + * \brief This class implements a Parallel Code Phase Search Acquisition + * \authors
    + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena@gmail.com + *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "pcps_acquisition.h" +#include "GLONASS_L1_L2_CA.h" // for GLONASS_TWO_PI +#include "GPS_L1_CA.h" // for GPS_TWO_PI +#include "gnss_sdr_create_directory.h" +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + +pcps_acquisition_sptr pcps_make_acquisition(const Acq_Conf& conf_) +{ + return pcps_acquisition_sptr(new pcps_acquisition(conf_)); +} + + +pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acquisition", + gr::io_signature::make(1, 1, conf_.it_size), + gr::io_signature::make(0, 0, conf_.it_size)) +{ + this->message_port_register_out(pmt::mp("events")); + + acq_parameters = conf_; + d_sample_counter = 0ULL; // SAMPLE COUNTER + d_active = false; + d_positive_acq = 0; + d_state = 0; + d_old_freq = 0LL; + d_num_noncoherent_integrations_counter = 0U; + d_consumed_samples = acq_parameters.sampled_ms * acq_parameters.samples_per_ms * (acq_parameters.bit_transition_flag ? 2 : 1); + if (acq_parameters.sampled_ms == acq_parameters.ms_per_code) + { + d_fft_size = d_consumed_samples; + } + else + { + d_fft_size = d_consumed_samples * 2; + } + // d_fft_size = next power of two? //// + d_mag = 0; + d_input_power = 0.0; + d_num_doppler_bins = 0U; + d_threshold = 0.0; + d_doppler_step = 0U; + d_doppler_center_step_two = 0.0; + d_test_statistics = 0.0; + d_channel = 0U; + if (conf_.it_size == sizeof(gr_complex)) + { + d_cshort = false; + } + else + { + d_cshort = true; + } + + // COD: + // Experimenting with the overlap/save technique for handling bit trannsitions + // The problem: Circular correlation is asynchronous with the received code. + // In effect the first code phase used in the correlation is the current + // estimate of the code phase at the start of the input buffer. If this is 1/2 + // of the code period a bit transition would move all the signal energy into + // adjacent frequency bands at +/- 1/T where T is the integration time. + // + // We can avoid this by doing linear correlation, effectively doubling the + // size of the input buffer and padding the code with zeros. + if (acq_parameters.bit_transition_flag) + { + d_fft_size = d_consumed_samples * 2; + acq_parameters.max_dwells = 1; // Activation of acq_parameters.bit_transition_flag invalidates the value of acq_parameters.max_dwells + } + + d_tmp_buffer = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_input_signal = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // Direct FFT + d_fft_if = new gr::fft::fft_complex(d_fft_size, true); + + // Inverse FFT + d_ifft = new gr::fft::fft_complex(d_fft_size, false); + + d_gnss_synchro = nullptr; + d_grid_doppler_wipeoffs = nullptr; + d_grid_doppler_wipeoffs_step_two = nullptr; + d_magnitude_grid = nullptr; + d_worker_active = false; + d_data_buffer = static_cast(volk_gnsssdr_malloc(d_consumed_samples * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + if (d_cshort) + { + d_data_buffer_sc = static_cast(volk_gnsssdr_malloc(d_consumed_samples * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + } + else + { + d_data_buffer_sc = nullptr; + } + grid_ = arma::fmat(); + narrow_grid_ = arma::fmat(); + d_step_two = false; + d_num_doppler_bins_step2 = acq_parameters.num_doppler_bins_step2; + + d_samplesPerChip = acq_parameters.samples_per_chip; + d_buffer_count = 0U; + // todo: CFAR statistic not available for non-coherent integration + if (acq_parameters.max_dwells == 1) + { + d_use_CFAR_algorithm_flag = acq_parameters.use_CFAR_algorithm_flag; + } + else + { + d_use_CFAR_algorithm_flag = false; + } + d_dump_number = 0LL; + d_dump_channel = acq_parameters.dump_channel; + d_dump = acq_parameters.dump; + d_dump_filename = acq_parameters.dump_filename; + if (d_dump) + { + std::string dump_path; + // Get path + if (d_dump_filename.find_last_of('/') != std::string::npos) + { + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/')); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "acquisition"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.')); + } + d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump file for the Acquisition block. Wrong permissions?" << std::endl; + d_dump = false; + } + } +} + +pcps_acquisition::~pcps_acquisition() +{ + if (d_num_doppler_bins > 0) + { + for (uint32_t i = 0; i < d_num_doppler_bins; i++) + { + volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); + volk_gnsssdr_free(d_magnitude_grid[i]); + } + delete[] d_grid_doppler_wipeoffs; + delete[] d_magnitude_grid; + } + if (acq_parameters.make_2_steps) + { + for (uint32_t i = 0; i < d_num_doppler_bins_step2; i++) + { + volk_gnsssdr_free(d_grid_doppler_wipeoffs_step_two[i]); + } + delete[] d_grid_doppler_wipeoffs_step_two; + } + volk_gnsssdr_free(d_fft_codes); + volk_gnsssdr_free(d_magnitude); + volk_gnsssdr_free(d_tmp_buffer); + volk_gnsssdr_free(d_input_signal); + delete d_ifft; + delete d_fft_if; + volk_gnsssdr_free(d_data_buffer); + if (d_cshort) + { + volk_gnsssdr_free(d_data_buffer_sc); + } +} + + +void pcps_acquisition::set_resampler_latency(uint32_t latency_samples) +{ + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + acq_parameters.resampler_latency_samples = latency_samples; +} + +void pcps_acquisition::set_local_code(std::complex* code) +{ + // reset the intermediate frequency + d_old_freq = 0LL; + // This will check if it's fdma, if yes will update the intermediate frequency and the doppler grid + if (is_fdma()) + { + update_grid_doppler_wipeoffs(); + } + // COD + // Here we want to create a buffer that looks like this: + // [ 0 0 0 ... 0 c_0 c_1 ... c_L] + // where c_i is the local code and there are L zeros and L chips + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + if (acq_parameters.bit_transition_flag) + { + int32_t offset = d_fft_size / 2; + std::fill_n(d_fft_if->get_inbuf(), offset, gr_complex(0.0, 0.0)); + memcpy(d_fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * offset); + } + else + { + if (acq_parameters.sampled_ms == acq_parameters.ms_per_code) + { + memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_consumed_samples); + } + else + { + std::fill_n(d_fft_if->get_inbuf(), d_fft_size - d_consumed_samples, gr_complex(0.0, 0.0)); + memcpy(d_fft_if->get_inbuf() + d_consumed_samples, code, sizeof(gr_complex) * d_consumed_samples); + } + } + + d_fft_if->execute(); // We need the FFT of local code + volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); +} + + +bool pcps_acquisition::is_fdma() +{ + // Dealing with FDMA system + if (strcmp(d_gnss_synchro->Signal, "1G") == 0) + { + d_old_freq += DFRQ1_GLO * GLONASS_PRN.at(d_gnss_synchro->PRN); + LOG(INFO) << "Trying to acquire SV PRN " << d_gnss_synchro->PRN << " with freq " << d_old_freq << " in Glonass Channel " << GLONASS_PRN.at(d_gnss_synchro->PRN) << std::endl; + return true; + } + if (strcmp(d_gnss_synchro->Signal, "2G") == 0) + { + d_old_freq += DFRQ2_GLO * GLONASS_PRN.at(d_gnss_synchro->PRN); + LOG(INFO) << "Trying to acquire SV PRN " << d_gnss_synchro->PRN << " with freq " << d_old_freq << " in Glonass Channel " << GLONASS_PRN.at(d_gnss_synchro->PRN) << std::endl; + return true; + } + return false; +} + + +void pcps_acquisition::update_local_carrier(gr_complex* carrier_vector, int32_t correlator_length_samples, float freq) +{ + float phase_step_rad; + if (acq_parameters.use_automatic_resampler) + { + phase_step_rad = GPS_TWO_PI * freq / static_cast(acq_parameters.resampled_fs); + } + else + { + phase_step_rad = GPS_TWO_PI * freq / static_cast(acq_parameters.fs_in); + } + float _phase[1]; + _phase[0] = 0.0; + volk_gnsssdr_s32f_sincos_32fc(carrier_vector, -phase_step_rad, _phase, correlator_length_samples); +} + + +void pcps_acquisition::init() +{ + d_gnss_synchro->Flag_valid_acquisition = false; + d_gnss_synchro->Flag_valid_symbol_output = false; + d_gnss_synchro->Flag_valid_pseudorange = false; + d_gnss_synchro->Flag_valid_word = false; + d_gnss_synchro->Acq_doppler_step = 0U; + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_mag = 0.0; + d_input_power = 0.0; + + d_num_doppler_bins = static_cast(std::ceil(static_cast(static_cast(acq_parameters.doppler_max) - static_cast(-acq_parameters.doppler_max)) / static_cast(d_doppler_step))); + + // Create the carrier Doppler wipeoff signals + if (d_grid_doppler_wipeoffs == nullptr) d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; + if (acq_parameters.make_2_steps && (d_grid_doppler_wipeoffs_step_two == nullptr)) + { + d_grid_doppler_wipeoffs_step_two = new gr_complex*[d_num_doppler_bins_step2]; + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins_step2; doppler_index++) + { + d_grid_doppler_wipeoffs_step_two[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + } + } + + if (d_magnitude_grid == nullptr) + { + d_magnitude_grid = new float*[d_num_doppler_bins]; + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude_grid[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + } + } + + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + for (uint32_t k = 0; k < d_fft_size; k++) + { + d_magnitude_grid[doppler_index][k] = 0.0; + } + int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * doppler_index; + update_local_carrier(d_grid_doppler_wipeoffs[doppler_index], d_fft_size, d_old_freq + doppler); + } + + d_worker_active = false; + + if (d_dump) + { + uint32_t effective_fft_size = (acq_parameters.bit_transition_flag ? (d_fft_size / 2) : d_fft_size); + grid_ = arma::fmat(effective_fft_size, d_num_doppler_bins, arma::fill::zeros); + narrow_grid_ = arma::fmat(effective_fft_size, d_num_doppler_bins_step2, arma::fill::zeros); + } +} + + +void pcps_acquisition::update_grid_doppler_wipeoffs() +{ + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * doppler_index; + update_local_carrier(d_grid_doppler_wipeoffs[doppler_index], d_fft_size, d_old_freq + doppler); + } +} + + +void pcps_acquisition::update_grid_doppler_wipeoffs_step2() +{ + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins_step2; doppler_index++) + { + float doppler = (static_cast(doppler_index) - static_cast(floor(d_num_doppler_bins_step2 / 2.0))) * acq_parameters.doppler_step2; + update_local_carrier(d_grid_doppler_wipeoffs_step_two[doppler_index], d_fft_size, d_doppler_center_step_two + doppler); + } +} + + +void pcps_acquisition::set_state(int32_t state) +{ + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_state = state; + if (d_state == 1) + { + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_active = true; + } + else if (d_state == 0) + { + } + else + { + LOG(ERROR) << "State can only be set to 0 or 1"; + } +} + + +void pcps_acquisition::send_positive_acquisition() +{ + // Declare positive acquisition using a message port + // 0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "positive acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + d_positive_acq = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); +} + + +void pcps_acquisition::send_negative_acquisition() +{ + // Declare negative acquisition using a message port + // 0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "negative acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + d_positive_acq = 0; + this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); +} + + +void pcps_acquisition::dump_results(int32_t effective_fft_size) +{ + d_dump_number++; + std::string filename = d_dump_filename; + filename.append("_"); + filename.append(1, d_gnss_synchro->System); + filename.append("_"); + filename.append(1, d_gnss_synchro->Signal[0]); + filename.append(1, d_gnss_synchro->Signal[1]); + filename.append("_ch_"); + filename.append(std::to_string(d_channel)); + filename.append("_"); + filename.append(std::to_string(d_dump_number)); + filename.append("_sat_"); + filename.append(std::to_string(d_gnss_synchro->PRN)); + filename.append(".mat"); + + mat_t* matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (matfp == nullptr) + { + std::cout << "Unable to create or open Acquisition dump file" << std::endl; + //acq_parameters.dump = false; + } + else + { + size_t dims[2] = {static_cast(effective_fft_size), static_cast(d_num_doppler_bins)}; + matvar_t* matvar = Mat_VarCreate("acq_grid", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, grid_.memptr(), 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + dims[0] = static_cast(1); + dims[1] = static_cast(1); + matvar = Mat_VarCreate("doppler_max", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &acq_parameters.doppler_max, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("doppler_step", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_doppler_step, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("d_positive_acq", MAT_C_INT32, MAT_T_INT32, 1, dims, &d_positive_acq, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + auto aux = static_cast(d_gnss_synchro->Acq_doppler_hz); + matvar = Mat_VarCreate("acq_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + aux = static_cast(d_gnss_synchro->Acq_delay_samples); + matvar = Mat_VarCreate("acq_delay_samples", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("test_statistic", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_test_statistics, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("threshold", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_threshold, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("input_power", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_input_power, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("sample_counter", MAT_C_UINT64, MAT_T_UINT64, 1, dims, &d_sample_counter, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_gnss_synchro->PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("num_dwells", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_num_noncoherent_integrations_counter, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + if (acq_parameters.make_2_steps) + { + dims[0] = static_cast(effective_fft_size); + dims[1] = static_cast(d_num_doppler_bins_step2); + matvar = Mat_VarCreate("acq_grid_narrow", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, narrow_grid_.memptr(), 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + dims[0] = static_cast(1); + dims[1] = static_cast(1); + matvar = Mat_VarCreate("doppler_step_narrow", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &acq_parameters.doppler_step2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + aux = d_doppler_center_step_two - static_cast(floor(d_num_doppler_bins_step2 / 2.0)) * acq_parameters.doppler_step2; + matvar = Mat_VarCreate("doppler_grid_narrow_min", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + + Mat_Close(matfp); + } +} + + +float pcps_acquisition::max_to_input_power_statistic(uint32_t& indext, int32_t& doppler, float input_power, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step) +{ + float grid_maximum = 0.0; + uint32_t index_doppler = 0U; + uint32_t tmp_intex_t = 0U; + uint32_t index_time = 0U; + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + + // Find the correlation peak and the carrier frequency + for (uint32_t i = 0; i < num_doppler_bins; i++) + { + volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_magnitude_grid[i], d_fft_size); + if (d_magnitude_grid[i][tmp_intex_t] > grid_maximum) + { + grid_maximum = d_magnitude_grid[i][tmp_intex_t]; + index_doppler = i; + index_time = tmp_intex_t; + } + } + indext = index_time; + if (!d_step_two) + { + doppler = -static_cast(doppler_max) + doppler_step * static_cast(index_doppler); + } + else + { + doppler = static_cast(d_doppler_center_step_two + (static_cast(index_doppler) - static_cast(floor(d_num_doppler_bins_step2 / 2.0))) * acq_parameters.doppler_step2); + } + + float magt = grid_maximum / (fft_normalization_factor * fft_normalization_factor); + return magt / input_power; +} + + +float pcps_acquisition::first_vs_second_peak_statistic(uint32_t& indext, int32_t& doppler, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step) +{ + // Look for correlation peaks in the results + // Find the highest peak and compare it to the second highest peak + // The second peak is chosen not closer than 1 chip to the highest peak + + float firstPeak = 0.0; + uint32_t index_doppler = 0U; + uint32_t tmp_intex_t = 0U; + uint32_t index_time = 0U; + + // Find the correlation peak and the carrier frequency + for (uint32_t i = 0; i < num_doppler_bins; i++) + { + volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_magnitude_grid[i], d_fft_size); + if (d_magnitude_grid[i][tmp_intex_t] > firstPeak) + { + firstPeak = d_magnitude_grid[i][tmp_intex_t]; + index_doppler = i; + index_time = tmp_intex_t; + } + } + indext = index_time; + + if (!d_step_two) + { + doppler = -static_cast(doppler_max) + doppler_step * static_cast(index_doppler); + } + else + { + doppler = static_cast(d_doppler_center_step_two + (static_cast(index_doppler) - static_cast(floor(d_num_doppler_bins_step2 / 2.0))) * acq_parameters.doppler_step2); + } + + // Find 1 chip wide code phase exclude range around the peak + int32_t excludeRangeIndex1 = index_time - d_samplesPerChip; + int32_t excludeRangeIndex2 = index_time + d_samplesPerChip; + + // Correct code phase exclude range if the range includes array boundaries + if (excludeRangeIndex1 < 0) + { + excludeRangeIndex1 = d_fft_size + excludeRangeIndex1; + } + else if (excludeRangeIndex2 >= static_cast(d_fft_size)) + { + excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size; + } + + int32_t idx = excludeRangeIndex1; + memcpy(d_tmp_buffer, d_magnitude_grid[index_doppler], d_fft_size); + do + { + d_tmp_buffer[idx] = 0.0; + idx++; + if (idx == static_cast(d_fft_size)) idx = 0; + } + while (idx != excludeRangeIndex2); + + // Find the second highest correlation peak in the same freq. bin --- + volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_tmp_buffer, d_fft_size); + float secondPeak = d_tmp_buffer[tmp_intex_t]; + + // Compute the test statistics and compare to the threshold + return firstPeak / secondPeak; +} + + +void pcps_acquisition::acquisition_core(uint64_t samp_count) +{ + gr::thread::scoped_lock lk(d_setlock); + + // Initialize acquisition algorithm + int32_t doppler = 0; + uint32_t indext = 0U; + int32_t effective_fft_size = (acq_parameters.bit_transition_flag ? d_fft_size / 2 : d_fft_size); + if (d_cshort) + { + volk_gnsssdr_16ic_convert_32fc(d_data_buffer, d_data_buffer_sc, d_consumed_samples); + } + memcpy(d_input_signal, d_data_buffer, d_consumed_samples * sizeof(gr_complex)); + if (d_fft_size > d_consumed_samples) + { + for (uint32_t i = d_consumed_samples; i < d_fft_size; i++) + { + d_input_signal[i] = gr_complex(0.0, 0.0); + } + } + const gr_complex* in = d_input_signal; // Get the input samples pointer + + d_input_power = 0.0; + d_mag = 0.0; + d_num_noncoherent_integrations_counter++; + + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << samp_count << ", threshold: " + << d_threshold << ", doppler_max: " << acq_parameters.doppler_max + << ", doppler_step: " << d_doppler_step + << ", use_CFAR_algorithm_flag: " << (d_use_CFAR_algorithm_flag ? "true" : "false"); + + lk.unlock(); + + if (d_use_CFAR_algorithm_flag or acq_parameters.bit_transition_flag) + { + // Compute the input signal power estimation + volk_32fc_magnitude_squared_32f(d_tmp_buffer, in, d_fft_size); + volk_32f_accumulator_s32f(&d_input_power, d_tmp_buffer, d_fft_size); + d_input_power /= static_cast(d_fft_size); + } + + // Doppler frequency grid loop + if (!d_step_two) + { + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // Remove Doppler + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + + // Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); + + // Multiply carrier wiped--off, Fourier transformed incoming signal with the local FFT'd code reference + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); + + // Compute the inverse FFT + d_ifft->execute(); + + // Compute squared magnitude (and accumulate in case of non-coherent integration) + size_t offset = (acq_parameters.bit_transition_flag ? effective_fft_size : 0); + if (d_num_noncoherent_integrations_counter == 1) + { + volk_32fc_magnitude_squared_32f(d_magnitude_grid[doppler_index], d_ifft->get_outbuf() + offset, effective_fft_size); + } + else + { + volk_32fc_magnitude_squared_32f(d_tmp_buffer, d_ifft->get_outbuf() + offset, effective_fft_size); + volk_32f_x2_add_32f(d_magnitude_grid[doppler_index], d_magnitude_grid[doppler_index], d_tmp_buffer, effective_fft_size); + } + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + memcpy(grid_.colptr(doppler_index), d_magnitude_grid[doppler_index], sizeof(float) * effective_fft_size); + } + } + + // Compute the test statistic + if (d_use_CFAR_algorithm_flag) + { + d_test_statistics = max_to_input_power_statistic(indext, doppler, d_input_power, d_num_doppler_bins, acq_parameters.doppler_max, d_doppler_step); + } + else + { + d_test_statistics = first_vs_second_peak_statistic(indext, doppler, d_num_doppler_bins, acq_parameters.doppler_max, d_doppler_step); + } + if (acq_parameters.use_automatic_resampler) + { + //take into account the acquisition resampler ratio + d_gnss_synchro->Acq_delay_samples = static_cast(std::fmod(static_cast(indext), acq_parameters.samples_per_code)) * acq_parameters.resampler_ratio; + d_gnss_synchro->Acq_delay_samples -= static_cast(acq_parameters.resampler_latency_samples); //account the resampler filter latency + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = rint(static_cast(samp_count) * acq_parameters.resampler_ratio); + } + else + { + d_gnss_synchro->Acq_delay_samples = static_cast(std::fmod(static_cast(indext), acq_parameters.samples_per_code)); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = samp_count; + } + } + else + { + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins_step2; doppler_index++) + { + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs_step_two[doppler_index], d_fft_size); + + // Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd code reference using SIMD operations with VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); + + // compute the inverse FFT + d_ifft->execute(); + + size_t offset = (acq_parameters.bit_transition_flag ? effective_fft_size : 0); + if (d_num_noncoherent_integrations_counter == 1) + { + volk_32fc_magnitude_squared_32f(d_magnitude_grid[doppler_index], d_ifft->get_outbuf() + offset, effective_fft_size); + } + else + { + volk_32fc_magnitude_squared_32f(d_tmp_buffer, d_ifft->get_outbuf() + offset, effective_fft_size); + volk_32f_x2_add_32f(d_magnitude_grid[doppler_index], d_magnitude_grid[doppler_index], d_tmp_buffer, effective_fft_size); + } + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + memcpy(narrow_grid_.colptr(doppler_index), d_magnitude_grid[doppler_index], sizeof(float) * effective_fft_size); + } + } + // Compute the test statistic + if (d_use_CFAR_algorithm_flag) + { + d_test_statistics = max_to_input_power_statistic(indext, doppler, d_input_power, d_num_doppler_bins_step2, static_cast(d_doppler_center_step_two - (static_cast(d_num_doppler_bins_step2) / 2.0) * acq_parameters.doppler_step2), acq_parameters.doppler_step2); + } + else + { + d_test_statistics = first_vs_second_peak_statistic(indext, doppler, d_num_doppler_bins_step2, static_cast(d_doppler_center_step_two - (static_cast(d_num_doppler_bins_step2) / 2.0) * acq_parameters.doppler_step2), acq_parameters.doppler_step2); + } + + if (acq_parameters.use_automatic_resampler) + { + //take into account the acquisition resampler ratio + d_gnss_synchro->Acq_delay_samples = static_cast(std::fmod(static_cast(indext), acq_parameters.samples_per_code)) * acq_parameters.resampler_ratio; + d_gnss_synchro->Acq_delay_samples -= static_cast(acq_parameters.resampler_latency_samples); //account the resampler filter latency + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = rint(static_cast(samp_count) * acq_parameters.resampler_ratio); + d_gnss_synchro->Acq_doppler_step = acq_parameters.doppler_step2; + } + else + { + d_gnss_synchro->Acq_delay_samples = static_cast(std::fmod(static_cast(indext), acq_parameters.samples_per_code)); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = samp_count; + d_gnss_synchro->Acq_doppler_step = acq_parameters.doppler_step2; + } + } + + lk.lock(); + if (!acq_parameters.bit_transition_flag) + { + if (d_test_statistics > d_threshold) + { + d_active = false; + if (acq_parameters.make_2_steps) + { + if (d_step_two) + { + send_positive_acquisition(); + d_step_two = false; + d_state = 0; // Positive acquisition + } + else + { + d_step_two = true; // Clear input buffer and make small grid acquisition + d_num_noncoherent_integrations_counter = 0; + d_positive_acq = 0; + d_state = 0; + } + } + else + { + send_positive_acquisition(); + d_state = 0; // Positive acquisition + } + } + else + { + d_buffer_count = 0; + d_state = 1; + } + + if (d_num_noncoherent_integrations_counter == acq_parameters.max_dwells) + { + if (d_state != 0) send_negative_acquisition(); + d_state = 0; + d_active = false; + d_step_two = false; + } + } + else + { + d_active = false; + if (d_test_statistics > d_threshold) + { + if (acq_parameters.make_2_steps) + { + if (d_step_two) + { + send_positive_acquisition(); + d_step_two = false; + d_state = 0; // Positive acquisition + } + else + { + d_step_two = true; // Clear input buffer and make small grid acquisition + d_num_noncoherent_integrations_counter = 0U; + d_state = 0; + } + } + else + { + send_positive_acquisition(); + d_state = 0; // Positive acquisition + } + } + else + { + d_state = 0; // Negative acquisition + d_step_two = false; + send_negative_acquisition(); + } + } + d_worker_active = false; + + if ((d_num_noncoherent_integrations_counter == acq_parameters.max_dwells) or (d_positive_acq == 1)) + { + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + pcps_acquisition::dump_results(effective_fft_size); + } + d_num_noncoherent_integrations_counter = 0U; + d_positive_acq = 0; + // Reset grid + for (uint32_t i = 0; i < d_num_doppler_bins; i++) + { + for (uint32_t k = 0; k < d_fft_size; k++) + { + d_magnitude_grid[i][k] = 0.0; + } + } + } +} + +// Called by gnuradio to enable drivers, etc for i/o devices. +bool pcps_acquisition::start() +{ + d_sample_counter = 0ULL; + return true; +} + +int pcps_acquisition::general_work(int noutput_items __attribute__((unused)), + gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + /* + * By J.Arribas, L.Esteve and M.Molina + * Acquisition strategy (Kay Borre book + CFAR threshold): + * 1. Compute the input signal power estimation + * 2. Doppler serial search loop + * 3. Perform the FFT-based circular convolution (parallel time search) + * 4. Record the maximum peak and the associated synchronization parameters + * 5. Compute the test statistics and compare to the threshold + * 6. Declare positive or negative acquisition using a message port + */ + gr::thread::scoped_lock lk(d_setlock); + if (!d_active or d_worker_active) + { + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(ninput_items[0]); + consume_each(ninput_items[0]); + } + if (d_step_two) + { + d_doppler_center_step_two = static_cast(d_gnss_synchro->Acq_doppler_hz); + update_grid_doppler_wipeoffs_step2(); + d_state = 0; + d_active = true; + } + return 0; + } + + switch (d_state) + { + case 0: + { + // Restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_state = 1; + d_buffer_count = 0U; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + } + break; + } + case 1: + { + uint32_t buff_increment; + if (d_cshort) + { + const auto* in = reinterpret_cast(input_items[0]); // Get the input samples pointer + if ((ninput_items[0] + d_buffer_count) <= d_consumed_samples) + { + buff_increment = ninput_items[0]; + } + else + { + buff_increment = d_consumed_samples - d_buffer_count; + } + memcpy(&d_data_buffer_sc[d_buffer_count], in, sizeof(lv_16sc_t) * buff_increment); + } + else + { + const auto* in = reinterpret_cast(input_items[0]); // Get the input samples pointer + if ((ninput_items[0] + d_buffer_count) <= d_consumed_samples) + { + buff_increment = ninput_items[0]; + } + else + { + buff_increment = d_consumed_samples - d_buffer_count; + } + memcpy(&d_data_buffer[d_buffer_count], in, sizeof(gr_complex) * buff_increment); + } + + // If buffer will be full in next iteration + if (d_buffer_count >= d_consumed_samples) + { + d_state = 2; + } + d_buffer_count += buff_increment; + d_sample_counter += static_cast(buff_increment); + consume_each(buff_increment); + break; + } + case 2: + { + // Copy the data to the core and let it know that new data is available + if (acq_parameters.blocking) + { + lk.unlock(); + acquisition_core(d_sample_counter); + } + else + { + gr::thread::thread d_worker(&pcps_acquisition::acquisition_core, this, d_sample_counter); + d_worker_active = true; + } + consume_each(0); + d_buffer_count = 0U; + break; + } + } + return 0; +} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.h new file mode 100644 index 000000000..c403b7d50 --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition.h @@ -0,0 +1,250 @@ +/*! + * \file pcps_acquisition.h + * \brief This class implements a Parallel Code Phase Search Acquisition + * + * Acquisition strategy (Kay Borre book + CFAR threshold). + *
    + *
  1. Compute the input signal power estimation + *
  2. Doppler serial search loop + *
  3. Perform the FFT-based circular convolution (parallel time search) + *
  4. Record the maximum peak and the associated synchronization parameters + *
  5. Compute the test statistics and compare to the threshold + *
  6. Declare positive or negative acquisition using a message queue + *
+ * + * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach", Birkhauser, 2007. pp 81-84 + * + * \authors
    + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena@gmail.com + *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
  • Antonio Ramos, 2017. antonio.ramos@cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PCPS_ACQUISITION_H_ +#define GNSS_SDR_PCPS_ACQUISITION_H_ + +#include "acq_conf.h" +#include "gnss_synchro.h" +#include +#include +#include +#include +#include + + +class pcps_acquisition; + +typedef boost::shared_ptr pcps_acquisition_sptr; + +pcps_acquisition_sptr +pcps_make_acquisition(const Acq_Conf& conf_); + +/*! + * \brief This class implements a Parallel Code Phase Search Acquisition. + * + * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", + * Algorithm 1, for a pseudocode description of this implementation. + */ +class pcps_acquisition : public gr::block +{ +private: + friend pcps_acquisition_sptr + pcps_make_acquisition(const Acq_Conf& conf_); + + pcps_acquisition(const Acq_Conf& conf_); + + void update_local_carrier(gr_complex* carrier_vector, int32_t correlator_length_samples, float freq); + void update_grid_doppler_wipeoffs(); + void update_grid_doppler_wipeoffs_step2(); + bool is_fdma(); + + void acquisition_core(uint64_t samp_count); + + void send_negative_acquisition(); + + void send_positive_acquisition(); + + void dump_results(int32_t effective_fft_size); + + float first_vs_second_peak_statistic(uint32_t& indext, int32_t& doppler, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step); + float max_to_input_power_statistic(uint32_t& indext, int32_t& doppler, float input_power, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step); + + bool start(); + + + Acq_Conf acq_parameters; + bool d_active; + bool d_worker_active; + bool d_cshort; + bool d_step_two; + bool d_use_CFAR_algorithm_flag; + int32_t d_positive_acq; + float d_threshold; + float d_mag; + float d_input_power; + float d_test_statistics; + float* d_magnitude; + float** d_magnitude_grid; + float* d_tmp_buffer; + gr_complex* d_input_signal; + uint32_t d_samplesPerChip; + int64_t d_old_freq; + int32_t d_state; + uint32_t d_channel; + uint32_t d_doppler_step; + float d_doppler_center_step_two; + uint32_t d_num_noncoherent_integrations_counter; + uint32_t d_fft_size; + uint32_t d_consumed_samples; + uint32_t d_num_doppler_bins; + uint64_t d_sample_counter; + gr_complex** d_grid_doppler_wipeoffs; + gr_complex** d_grid_doppler_wipeoffs_step_two; + gr_complex* d_fft_codes; + gr_complex* d_data_buffer; + lv_16sc_t* d_data_buffer_sc; + gr::fft::fft_complex* d_fft_if; + gr::fft::fft_complex* d_ifft; + Gnss_Synchro* d_gnss_synchro; + arma::fmat grid_; + arma::fmat narrow_grid_; + uint32_t d_num_doppler_bins_step2; + int64_t d_dump_number; + uint32_t d_dump_channel; + uint32_t d_buffer_count; + bool d_dump; + std::string d_dump_filename; + +public: + ~pcps_acquisition(); + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to exchange synchronization data between acquisition and tracking blocks. + * \param p_gnss_synchro Satellite information shared by the processing blocks. + */ + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_gnss_synchro = p_gnss_synchro; + } + + /*! + * \brief Returns the maximum peak of grid search. + */ + inline uint32_t mag() const + { + return d_mag; + } + + /*! + * \brief Initializes acquisition algorithm and reserves memory. + */ + void init(); + + /*! + * \brief Sets local code for PCPS acquisition algorithm. + * \param code - Pointer to the PRN code. + */ + void set_local_code(std::complex* code); + + /*! + * \brief Starts acquisition algorithm, turning from standby mode to + * active mode + * \param active - bool that activates/deactivates the block. + */ + inline void set_active(bool active) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_active = active; + } + + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int32_t state); + + /*! + * \brief Set acquisition channel unique ID + * \param channel - receiver channel. + */ + inline void set_channel(uint32_t channel) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_channel = channel; + } + + /*! + * \brief Set statistics threshold of PCPS algorithm. + * \param threshold - Threshold for signal detection (check \ref Navitec2012, + * Algorithm 1, for a definition of this threshold). + */ + inline void set_threshold(float threshold) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_threshold = threshold; + } + + /*! + * \brief Set maximum Doppler grid search + * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. + */ + inline void set_doppler_max(uint32_t doppler_max) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + acq_parameters.doppler_max = doppler_max; + } + + /*! + * \brief Set Doppler steps for the grid search + * \param doppler_step - Frequency bin of the search grid [Hz]. + */ + inline void set_doppler_step(uint32_t doppler_step) + { + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_doppler_step = doppler_step; + } + + + void set_resampler_latency(uint32_t latency_samples); + + /*! + * \brief Parallel Code Phase Search Acquisition signal processing. + */ + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +#endif /* GNSS_SDR_PCPS_ACQUISITION_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc deleted file mode 100644 index c7910ff97..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc +++ /dev/null @@ -1,502 +0,0 @@ -/*! - * \file pcps_acquisition_cc.cc - * \brief This class implements a Parallel Code Phase Search Acquisition - * \authors
    - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena@gmail.com - *
- * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "pcps_acquisition_cc.h" -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI - - -using google::LogMessage; - -pcps_acquisition_cc_sptr pcps_make_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename) -{ - return pcps_acquisition_cc_sptr( - new pcps_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, bit_transition_flag, use_CFAR_algorithm_flag, dump, dump_filename)); -} - - -pcps_acquisition_cc::pcps_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename) : - gr::block("pcps_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms * ( bit_transition_flag ? 2 : 1 )), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms * ( bit_transition_flag ? 2 : 1 )) ) -{ - this->message_port_register_out(pmt::mp("events")); - - d_sample_counter = 0; // SAMPLE COUNTER - d_active = false; - d_state = 0; - d_freq = freq; - d_fs_in = fs_in; - d_samples_per_ms = samples_per_ms; - d_samples_per_code = samples_per_code; - d_sampled_ms = sampled_ms; - d_max_dwells = max_dwells; - d_well_count = 0; - d_doppler_max = doppler_max; - d_fft_size = d_sampled_ms * d_samples_per_ms; - d_mag = 0; - d_input_power = 0.0; - d_num_doppler_bins = 0; - d_bit_transition_flag = bit_transition_flag; - d_use_CFAR_algorithm_flag = use_CFAR_algorithm_flag; - d_threshold = 0.0; - d_doppler_step = 0; - d_code_phase = 0; - d_test_statistics = 0.0; - d_channel = 0; - d_doppler_freq = 0.0; - - //set_relative_rate( 1.0/d_fft_size ); - - // COD: - // Experimenting with the overlap/save technique for handling bit trannsitions - // The problem: Circular correlation is asynchronous with the received code. - // In effect the first code phase used in the correlation is the current - // estimate of the code phase at the start of the input buffer. If this is 1/2 - // of the code period a bit transition would move all the signal energy into - // adjacent frequency bands at +/- 1/T where T is the integration time. - // - // We can avoid this by doing linear correlation, effectively doubling the - // size of the input buffer and padding the code with zeros. - if( d_bit_transition_flag ) - { - d_fft_size *= 2; - d_max_dwells = 1; //Activation of d_bit_transition_flag invalidates the value of d_max_dwells - } - - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - - // Direct FFT - d_fft_if = new gr::fft::fft_complex(d_fft_size, true); - - // Inverse FFT - d_ifft = new gr::fft::fft_complex(d_fft_size, false); - - // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; - - d_gnss_synchro = 0; - d_grid_doppler_wipeoffs = 0; -} - - -pcps_acquisition_cc::~pcps_acquisition_cc() -{ - if (d_num_doppler_bins > 0) - { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) - { - volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); - } - delete[] d_grid_doppler_wipeoffs; - } - - volk_gnsssdr_free(d_fft_codes); - volk_gnsssdr_free(d_magnitude); - - delete d_ifft; - delete d_fft_if; - - if (d_dump) - { - d_dump_file.close(); - } -} - - -void pcps_acquisition_cc::set_local_code(std::complex * code) -{ - // COD - // Here we want to create a buffer that looks like this: - // [ 0 0 0 ... 0 c_0 c_1 ... c_L] - // where c_i is the local code and there are L zeros and L chips - if( d_bit_transition_flag ) - { - int offset = d_fft_size/2; - std::fill_n( d_fft_if->get_inbuf(), offset, gr_complex( 0.0, 0.0 ) ); - memcpy(d_fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * offset); - } - else - { - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); - } - - d_fft_if->execute(); // We need the FFT of local code - volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); -} - - -void pcps_acquisition_cc::update_local_carrier(gr_complex* carrier_vector, int correlator_length_samples, float freq) -{ - float phase_step_rad = GPS_TWO_PI * freq / static_cast(d_fs_in); - float _phase[1]; - _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(carrier_vector, - phase_step_rad, _phase, correlator_length_samples); -} - - -void pcps_acquisition_cc::init() -{ - d_gnss_synchro->Flag_valid_acquisition = false; - d_gnss_synchro->Flag_valid_symbol_output = false; - d_gnss_synchro->Flag_valid_pseudorange = false; - d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_mag = 0.0; - d_input_power = 0.0; - - d_num_doppler_bins = ceil( static_cast(static_cast(d_doppler_max) - static_cast(-d_doppler_max)) / static_cast(d_doppler_step)); - - // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - update_local_carrier(d_grid_doppler_wipeoffs[doppler_index], d_fft_size, d_freq + doppler); - } -} - - -void pcps_acquisition_cc::set_state(int state) -{ - d_state = state; - if (d_state == 1) - { - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - } - else if (d_state == 0) - {} - else - { - LOG(ERROR) << "State can only be set to 0 or 1"; - } -} - - -int pcps_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) -{ - /* - * By J.Arribas, L.Esteve and M.Molina - * Acquisition strategy (Kay Borre book + CFAR threshold): - * 1. Compute the input signal power estimation - * 2. Doppler serial search loop - * 3. Perform the FFT-based circular convolution (parallel time search) - * 4. Record the maximum peak and the associated synchronization parameters - * 5. Compute the test statistics and compare to the threshold - * 6. Declare positive or negative acquisition using a message port - */ - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - - switch (d_state) - { - case 0: - { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - - d_state = 1; - } - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - //DLOG(INFO) << "Consumed " << ninput_items[0] << " items"; - - break; - } - - case 1: - { - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - float magt = 0.0; - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - - int effective_fft_size = ( d_bit_transition_flag ? d_fft_size/2 : d_fft_size ); - - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - - d_input_power = 0.0; - d_mag = 0.0; - - d_sample_counter += d_fft_size; // sample counter - - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - if (d_use_CFAR_algorithm_flag == true) - { - // 1- (optional) Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= static_cast(d_fft_size); - } - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code reference using SIMD operations with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Search maximum - size_t offset = ( d_bit_transition_flag ? effective_fft_size : 0 ); - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf() + offset, effective_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude, effective_fft_size); - magt = d_magnitude[indext]; - - if (d_use_CFAR_algorithm_flag == true) - { - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt = d_magnitude[indext] / (fft_normalization_factor * fft_normalization_factor); - } - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - - if (d_use_CFAR_algorithm_flag == false) - { - // Search grid noise floor approximation for this doppler line - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, effective_fft_size); - d_input_power = (d_input_power - d_mag) / (effective_fft_size - 1); - } - - // In case that d_bit_transition_flag = true, we compare the potentially - // new maximum test statistics (d_mag/d_input_power) with the value in - // d_test_statistics. When the second dwell is being processed, the value - // of d_mag/d_input_power could be lower than d_test_statistics (i.e, - // the maximum test statistics in the previous dwell is greater than - // current d_mag/d_input_power). Note that d_test_statistics is not - // restarted between consecutive dwells in multidwell operation. - - if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; - } - } - - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - - boost::filesystem::path p = d_dump_filename; - filename << p.parent_path().string() - << boost::filesystem::path::preferred_separator - << p.stem().string() - << "_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" - << doppler - << p.extension().string(); - - DLOG(INFO) << "Writing ACQ out to " << filename.str(); - - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } - - if (!d_bit_transition_flag) - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition - } - } - else - { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else - { - d_state = 3; // Negative acquisition - } - } - } - - consume_each(1); - - DLOG(INFO) << "Done. Consumed 1 item."; - - break; - } - - case 2: - { - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - - return noutput_items; -} - - -//void pcps_acquisition_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -//{ - //// COD: - //// For zero-padded case we need one extra code period - //if( d_bit_transition_flag ) - //{ - //ninput_items_required[0] = noutput_items*(d_samples_per_code * d_max_dwells + d_samples_per_code); - //} - //else - //{ - //ninput_items_required[0] = noutput_items*d_fft_size*d_max_dwells; - //} -//} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h deleted file mode 100644 index a0ab23131..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h +++ /dev/null @@ -1,230 +0,0 @@ -/*! - * \file pcps_acquisition_cc.h - * \brief This class implements a Parallel Code Phase Search Acquisition - * - * Acquisition strategy (Kay Borre book + CFAR threshold). - *
    - *
  1. Compute the input signal power estimation - *
  2. Doppler serial search loop - *
  3. Perform the FFT-based circular convolution (parallel time search) - *
  4. Record the maximum peak and the associated synchronization parameters - *
  5. Compute the test statistics and compare to the threshold - *
  6. Declare positive or negative acquisition using a message queue - *
- * - * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkha user, 2007. pp 81-84 - * - * \authors
    - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena@gmail.com - *
- * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_PCPS_ACQUISITION_CC_H_ -#define GNSS_SDR_PCPS_ACQUISITION_CC_H_ - -#include -#include -#include -#include -#include -#include "gnss_synchro.h" - -class pcps_acquisition_cc; - -typedef boost::shared_ptr pcps_acquisition_cc_sptr; - -pcps_acquisition_cc_sptr -pcps_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - -/*! - * \brief This class implements a Parallel Code Phase Search Acquisition. - * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. - */ -class pcps_acquisition_cc: public gr::block -{ -private: - friend pcps_acquisition_cc_sptr - pcps_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - - pcps_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - - void update_local_carrier(gr_complex* carrier_vector, int correlator_length_samples, float freq); - - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - //unsigned int d_doppler_resolution; - float d_threshold; - std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; - gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; - gr_complex* d_fft_codes; - gr::fft::fft_complex* d_fft_if; - gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; - float d_doppler_freq; - float d_mag; - float* d_magnitude; - float d_input_power; - float d_test_statistics; - bool d_bit_transition_flag; - bool d_use_CFAR_algorithm_flag; - std::ofstream d_dump_file; - bool d_active; - int d_state; - bool d_dump; - unsigned int d_channel; - std::string d_dump_filename; - -public: - /*! - * \brief Default destructor. - */ - ~pcps_acquisition_cc(); - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to exchange synchronization data between acquisition and tracking blocks. - * \param p_gnss_synchro Satellite information shared by the processing blocks. - */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } - - /*! - * \brief Returns the maximum peak of grid search. - */ - unsigned int mag() - { - return d_mag; - } - - /*! - * \brief Initializes acquisition algorithm. - */ - void init(); - - /*! - * \brief Sets local code for PCPS acquisition algorithm. - * \param code - Pointer to the PRN code. - */ - void set_local_code(std::complex * code); - - /*! - * \brief Starts acquisition algorithm, turning from standby mode to - * active mode - * \param active - bool that activates/deactivates the block. - */ - void set_active(bool active) - { - d_active = active; - } - - /*! - * \brief If set to 1, ensures that acquisition starts at the - * first available sample. - * \param state - int=1 forces start of acquisition - */ - void set_state(int state); - - /*! - * \brief Set acquisition channel unique ID - * \param channel - receiver channel. - */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } - - /*! - * \brief Set statistics threshold of PCPS algorithm. - * \param threshold - Threshold for signal detection (check \ref Navitec2012, - * Algorithm 1, for a definition of this threshold). - */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } - - /*! - * \brief Set maximum Doppler grid search - * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. - */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } - - /*! - * \brief Set Doppler steps for the grid search - * \param doppler_step - Frequency bin of the search grid [Hz]. - */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } - - /*! - * \brief Parallel Code Phase Search Acquisition signal processing. - */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* GNSS_SDR_PCPS_ACQUISITION_CC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc index 6200efeda..51b821e36 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,64 +25,57 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_acquisition_fine_doppler_cc.h" -#include // std::rotate -#include +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_create_directory.h" +#include "gps_sdr_signal_processing.h" +#include #include #include +#include #include #include -#include "concurrent_map.h" -#include "gps_sdr_signal_processing.h" -#include "control_message_factory.h" -#include "GPS_L1_CA.h" +#include // std::rotate, std::fill_n +#include + using google::LogMessage; -pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) +pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc(const Acq_Conf &conf_) { - return pcps_acquisition_fine_doppler_cc_sptr( - new pcps_acquisition_fine_doppler_cc(max_dwells, sampled_ms, doppler_max, doppler_min, freq, - fs_in, samples_per_ms, dump, dump_filename)); + new pcps_acquisition_fine_doppler_cc(conf_)); } - -pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) : - gr::block("pcps_acquisition_fine_doppler_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) +pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(const Acq_Conf &conf_) + : gr::block("pcps_acquisition_fine_doppler_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(0, 0, sizeof(gr_complex))) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + acq_parameters = conf_; + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; - d_freq = freq; - d_fs_in = fs_in; - d_samples_per_ms = samples_per_ms; - d_sampled_ms = sampled_ms; - d_config_doppler_max = doppler_max; - d_config_doppler_min = doppler_min; - d_fft_size = d_sampled_ms * d_samples_per_ms; + d_fs_in = conf_.fs_in; + d_samples_per_ms = conf_.samples_per_ms; + d_config_doppler_max = conf_.doppler_max; + d_fft_size = d_samples_per_ms; // HS Acquisition - d_max_dwells = max_dwells; + d_max_dwells = conf_.max_dwells; d_gnuradio_forecast_samples = d_fft_size; - d_input_power = 0.0; d_state = 0; - d_carrier = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_carrier = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + + d_10_ms_buffer = static_cast(volk_gnsssdr_malloc(50 * d_samples_per_ms * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -91,21 +84,73 @@ pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc( d_ifft = new gr::fft::fft_complex(d_fft_size, false); // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; + d_dump = conf_.dump; + d_dump_filename = conf_.dump_filename; - d_doppler_resolution = 0; + if (d_dump) + { + std::string dump_path; + // Get path + if (d_dump_filename.find_last_of('/') != std::string::npos) + { + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/')); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "acquisition"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.')); + } + d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump file for the Acquisition block. Wrong permissions?" << std::endl; + d_dump = false; + } + } + + d_n_samples_in_buffer = 0; d_threshold = 0; d_num_doppler_points = 0; d_doppler_step = 0; - d_grid_data = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_data = nullptr; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; d_well_count = 0; d_channel = 0; + d_positive_acq = 0; + d_dump_number = 0; + d_dump_channel = 0; // this implementation can only produce dumps in channel 0 + //todo: migrate config parameters to the unified acquisition config class +} + + +// Finds next power of two +// for n. If n itself is a +// power of two then returns n +unsigned int pcps_acquisition_fine_doppler_cc::nextPowerOf2(unsigned int n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; } void pcps_acquisition_fine_doppler_cc::set_doppler_step(unsigned int doppler_step) @@ -113,16 +158,23 @@ void pcps_acquisition_fine_doppler_cc::set_doppler_step(unsigned int doppler_ste d_doppler_step = doppler_step; // Create the search grid array - d_num_doppler_points = floor(std::abs(d_config_doppler_max - d_config_doppler_min) / d_doppler_step); + d_num_doppler_points = floor(std::abs(2 * d_config_doppler_max) / d_doppler_step); - d_grid_data = new float*[d_num_doppler_points]; + d_grid_data = new float *[d_num_doppler_points]; for (int i = 0; i < d_num_doppler_points; i++) { - d_grid_data[i] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_grid_data[i] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); } + + if (d_dump) + { + grid_ = arma::fmat(d_fft_size, d_num_doppler_points, arma::fill::zeros); + } + update_carrier_wipeoff(); } + void pcps_acquisition_fine_doppler_cc::free_grid_memory() { for (int i = 0; i < d_num_doppler_points; i++) @@ -134,53 +186,48 @@ void pcps_acquisition_fine_doppler_cc::free_grid_memory() delete d_grid_doppler_wipeoffs; } + pcps_acquisition_fine_doppler_cc::~pcps_acquisition_fine_doppler_cc() { volk_gnsssdr_free(d_carrier); volk_gnsssdr_free(d_fft_codes); volk_gnsssdr_free(d_magnitude); + volk_gnsssdr_free(d_10_ms_buffer); delete d_ifft; delete d_fft_if; - if (d_dump) - { - d_dump_file.close(); - } free_grid_memory(); } - -void pcps_acquisition_fine_doppler_cc::set_local_code(std::complex * code) +void pcps_acquisition_fine_doppler_cc::set_local_code(std::complex *code) { - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); } + void pcps_acquisition_fine_doppler_cc::init() { d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_input_power = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_state = 0; - } -void pcps_acquisition_fine_doppler_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) + +void pcps_acquisition_fine_doppler_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = d_gnuradio_forecast_samples ; //set the required available samples in each call + ninput_items_required[0] = d_gnuradio_forecast_samples; //set the required available samples in each call } } @@ -190,6 +237,7 @@ void pcps_acquisition_fine_doppler_cc::reset_grid() d_well_count = 0; for (int i = 0; i < d_num_doppler_points; i++) { + //todo: use memset here for (unsigned int j = 0; j < d_fft_size; j++) { d_grid_data[i][j] = 0.0; @@ -203,73 +251,93 @@ void pcps_acquisition_fine_doppler_cc::update_carrier_wipeoff() // create the carrier Doppler wipeoff signals int doppler_hz; float phase_step_rad; - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_points]; + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_points]; for (int doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) { - doppler_hz = d_config_doppler_min + d_doppler_step*doppler_index; + doppler_hz = d_doppler_step * doppler_index - d_config_doppler_max; // doppler search steps // compute the carrier doppler wipe-off signal and store it - phase_step_rad = static_cast(GPS_TWO_PI) * ( d_freq + doppler_hz ) / static_cast(d_fs_in); + phase_step_rad = static_cast(GPS_TWO_PI) * doppler_hz / static_cast(d_fs_in); d_grid_doppler_wipeoffs[doppler_index] = new gr_complex[d_fft_size]; float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); } } -double pcps_acquisition_fine_doppler_cc::search_maximum() + +double pcps_acquisition_fine_doppler_cc::compute_CAF() { - float magt = 0.0; - float fft_normalization_factor; + float firstPeak = 0.0; int index_doppler = 0; uint32_t tmp_intex_t = 0; uint32_t index_time = 0; - for (int i=0;i magt) + if (d_grid_data[i][tmp_intex_t] > firstPeak) { - magt = d_grid_data[i][tmp_intex_t]; - //std::cout<(d_fft_size) * static_cast(d_fft_size); - magt = magt / (fft_normalization_factor * fft_normalization_factor); + // -- - Find 1 chip wide code phase exclude range around the peak + uint32_t samplesPerChip = ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(this->d_fs_in)); + int32_t excludeRangeIndex1 = index_time - samplesPerChip; + int32_t excludeRangeIndex2 = index_time + samplesPerChip; + + // -- - Correct code phase exclude range if the range includes array boundaries + if (excludeRangeIndex1 < 0) + { + excludeRangeIndex1 = d_fft_size + excludeRangeIndex1; + } + else if (excludeRangeIndex2 >= static_cast(d_fft_size)) + { + excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size; + } + + int32_t idx = excludeRangeIndex1; + do + { + d_grid_data[index_doppler][idx] = 0.0; + idx++; + if (idx == static_cast(d_fft_size)) idx = 0; + } + while (idx != excludeRangeIndex2); + + //--- Find the second highest correlation peak in the same freq. bin --- + volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_grid_data[index_doppler], d_fft_size); + float secondPeak = d_grid_data[index_doppler][tmp_intex_t]; // 5- Compute the test statistics and compare to the threshold - d_test_statistics = magt/(d_input_power*std::sqrt(d_well_count)); + d_test_statistics = firstPeak / secondPeak; // 4- record the maximum peak and the associated synchronization parameters d_gnss_synchro->Acq_delay_samples = static_cast(index_time); - d_gnss_synchro->Acq_doppler_hz = static_cast(index_doppler * d_doppler_step + d_config_doppler_min); + d_gnss_synchro->Acq_doppler_hz = static_cast(index_doppler * d_doppler_step - d_config_doppler_max); d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out - | std::ios::binary); - d_dump_file.write((char*)d_grid_data[index_doppler], n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } + d_gnss_synchro->Acq_doppler_step = d_doppler_step; return d_test_statistics; } + float pcps_acquisition_fine_doppler_cc::estimate_input_power(gr_vector_const_void_star &input_items) { - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer // Compute the input signal power estimation float power = 0; volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); @@ -278,27 +346,27 @@ float pcps_acquisition_fine_doppler_cc::estimate_input_power(gr_vector_const_voi return power; } + int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_const_void_star &input_items) { // initialize acquisition algorithm - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_config_doppler_max - << ", doppler_step: " << d_doppler_step; - - + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_config_doppler_max + << ", doppler_step: " << d_doppler_step; // 2- Doppler frequency search loop - float* p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + auto *p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); for (int doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) { // doppler search steps // Perform the carrier wipe-off volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + // 3- Perform the FFT-based convolution (parallel time search) // Compute the FFT of the carrier wiped--off incoming signal d_fft_if->execute(); @@ -311,30 +379,38 @@ int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_cons d_ifft->execute(); // save the grid matrix delay file - volk_32fc_magnitude_squared_32f(p_tmp_vector, d_ifft->get_outbuf(), d_fft_size); - const float* old_vector = d_grid_data[doppler_index]; - volk_32f_x2_add_32f(d_grid_data[doppler_index], old_vector, p_tmp_vector, d_fft_size); - + //accumulate grid values + volk_32f_x2_add_32f(d_grid_data[doppler_index], d_grid_data[doppler_index], p_tmp_vector, d_fft_size); } volk_gnsssdr_free(p_tmp_vector); return d_fft_size; + //debug + // std::cout << "iff=["; + // for (int n = 0; n < d_fft_size; n++) + // { + // std::cout << std::real(d_ifft->get_outbuf()[n]) << "+" << std::imag(d_ifft->get_outbuf()[n]) << "i,"; + // } + // std::cout << "]\n"; + // getchar(); } -int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star &input_items) + +int pcps_acquisition_fine_doppler_cc::estimate_Doppler() { - // Direct FFT - int zero_padding_factor = 2; - int fft_size_extended = d_fft_size * zero_padding_factor; - gr::fft::fft_complex *fft_operator = new gr::fft::fft_complex(fft_size_extended, true); - + int zero_padding_factor = 8; + int prn_replicas = 10; + int signal_samples = prn_replicas * d_fft_size; + //int fft_size_extended = nextPowerOf2(signal_samples * zero_padding_factor); + int fft_size_extended = signal_samples * zero_padding_factor; + auto *fft_operator = new gr::fft::fft_complex(fft_size_extended, true); //zero padding the entire vector - memset(fft_operator->get_inbuf(), 0, fft_size_extended * sizeof(gr_complex)); + std::fill_n(fft_operator->get_inbuf(), fft_size_extended, gr_complex(0.0, 0.0)); //1. generate local code aligned with the acquisition code phase estimation - gr_complex *code_replica = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + auto *code_replica = static_cast(volk_gnsssdr_malloc(signal_samples * sizeof(gr_complex), volk_gnsssdr_get_alignment())); gps_l1_ca_code_gen_complex_sampled(code_replica, d_gnss_synchro->PRN, d_fs_in, 0); @@ -346,16 +422,18 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star std::rotate(code_replica, code_replica + (d_fft_size - shift_index), code_replica + d_fft_size - 1); } + for (int n = 0; n < prn_replicas - 1; n++) + { + memcpy(&code_replica[(n + 1) * d_fft_size], code_replica, d_fft_size * sizeof(gr_complex)); + } //2. Perform code wipe-off - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - - volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), in, code_replica, d_fft_size); + volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), d_10_ms_buffer, code_replica, signal_samples); // 3. Perform the FFT (zero padded!) fft_operator->execute(); // 4. Compute the magnitude and find the maximum - float* p_tmp_vector = static_cast(volk_gnsssdr_malloc(fft_size_extended * sizeof(float), volk_gnsssdr_get_alignment())); + auto *p_tmp_vector = static_cast(volk_gnsssdr_malloc(fft_size_extended * sizeof(float), volk_gnsssdr_get_alignment())); volk_32fc_magnitude_squared_32f(p_tmp_vector, fft_operator->get_outbuf(), fft_size_extended); @@ -364,11 +442,11 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star //case even int counter = 0; + auto *fftFreqBins = new float[fft_size_extended]; - float fftFreqBins[fft_size_extended]; - memset(fftFreqBins, 0, fft_size_extended * sizeof(float)); + std::fill_n(fftFreqBins, fft_size_extended, 0.0); - for (int k=0; k < (fft_size_extended / 2); k++) + for (int k = 0; k < (fft_size_extended / 2); k++) { fftFreqBins[counter] = ((static_cast(d_fs_in) / 2.0) * static_cast(k)) / (static_cast(fft_size_extended) / 2.0); counter++; @@ -376,7 +454,7 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star for (int k = fft_size_extended / 2; k > 0; k--) { - fftFreqBins[counter] = ((-static_cast(d_fs_in) / 2) * static_cast(k)) / (static_cast(fft_size_extended) / 2.0); + fftFreqBins[counter] = ((-static_cast(d_fs_in) / 2.0) * static_cast(k)) / (static_cast(fft_size_extended) / 2.0); counter++; } @@ -384,56 +462,61 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star if (std::abs(fftFreqBins[tmp_index_freq] - d_gnss_synchro->Acq_doppler_hz) < 1000) { d_gnss_synchro->Acq_doppler_hz = static_cast(fftFreqBins[tmp_index_freq]); - //std::cout<<"FFT maximum present at "<PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write((char*)code_replica, n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); - // - // filename.str(""); - // filename << "../data/signal_prn_" << d_gnss_synchro->PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write((char*)in, n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); - // - // - // n = sizeof(float) * (fft_size_extended); - // filename.str(""); - // filename << "../data/fft_prn_" << d_gnss_synchro->PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write((char*)p_tmp_vector, n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); + DLOG(INFO) << "Error estimating fine frequency Doppler"; } - // free memory!! delete fft_operator; volk_gnsssdr_free(code_replica); volk_gnsssdr_free(p_tmp_vector); + delete[] fftFreqBins; return d_fft_size; } -int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, - gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) +// Called by gnuradio to enable drivers, etc for i/o devices. +bool pcps_acquisition_fine_doppler_cc::start() { + d_sample_counter = 0ULL; + return true; +} + +void pcps_acquisition_fine_doppler_cc::set_state(int state) +{ + //gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_state = state; + + if (d_state == 1) + { + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_test_statistics = 0.0; + d_active = true; + reset_grid(); + } + else if (d_state == 0) + { + } + else + { + LOG(ERROR) << "State can only be set to 0 or 1"; + } +} + + +int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, + gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) +{ /*! * TODO: High sensitivity acquisition algorithm: * State Mechine: @@ -448,86 +531,204 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, * S5. Negative_Acq: Send message and stop acq -> S0 */ + int samples_remaining; switch (d_state) - { - case 0: // S0. StandBy - //DLOG(INFO) <<"S0"<= d_max_dwells) - { - d_state = 2; - } - break; - case 2: // Compute test statistics and decide - //DLOG(INFO) <<"S2"< d_threshold) - { - d_state = 3; //perform fine doppler estimation - } - else - { - d_state = 5; //negative acquisition - } - break; + { + case 0: // S0. StandBy + if (d_active == true) + { + reset_grid(); + d_n_samples_in_buffer = 0; + d_state = 1; + } + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(d_fft_size); // sample counter + consume_each(d_fft_size); + } + break; + case 1: // S1. ComputeGrid + compute_and_accumulate_grid(input_items); + memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast(input_items[0]), d_fft_size * sizeof(gr_complex)); + d_n_samples_in_buffer += d_fft_size; + d_well_count++; + if (d_well_count >= d_max_dwells) + { + d_state = 2; + } + d_sample_counter += static_cast(d_fft_size); // sample counter + consume_each(d_fft_size); + break; + case 2: // Compute test statistics and decide + d_test_statistics = compute_CAF(); + if (d_test_statistics > d_threshold) + { + d_state = 3; //perform fine doppler estimation + } + else + { + d_state = 5; //negative acquisition + d_n_samples_in_buffer = 0; + } + break; + case 3: // Fine doppler estimation + samples_remaining = 10 * d_samples_per_ms - d_n_samples_in_buffer; - - case 3: // Fine doppler estimation - //DLOG(INFO) <<"S3"<System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); - d_state = 0; - break; - case 5: // Negative_Acq - //DLOG(INFO) <<"S5"<System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); - d_state = 0; - break; - default: - d_state = 0; - break; - } - - //DLOG(INFO)<<"d_sample_counter="< noutput_items) + { + memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast(input_items[0]), noutput_items * sizeof(gr_complex)); + d_n_samples_in_buffer += noutput_items; + d_sample_counter += static_cast(noutput_items); // sample counter + consume_each(noutput_items); + } + else + { + if (samples_remaining > 0) + { + memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast(input_items[0]), samples_remaining * sizeof(gr_complex)); + d_sample_counter += static_cast(samples_remaining); // sample counter + consume_each(samples_remaining); + } + estimate_Doppler(); //disabled in repo + d_n_samples_in_buffer = 0; + d_state = 4; + } + break; + case 4: // Positive_Acq + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + d_positive_acq = 1; + d_active = false; + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + dump_results(d_fft_size); + } + // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); + d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(noutput_items); // sample counter + consume_each(noutput_items); + } + break; + case 5: // Negative_Acq + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + d_positive_acq = 0; + d_active = false; + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + dump_results(d_fft_size); + } + // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); + d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(noutput_items); // sample counter + consume_each(noutput_items); + } + break; + default: + d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += static_cast(noutput_items); // sample counter + consume_each(noutput_items); + } + break; + } + return 0; +} + +void pcps_acquisition_fine_doppler_cc::dump_results(int effective_fft_size) +{ + d_dump_number++; + std::string filename = d_dump_filename; + filename.append("_"); + filename.append(1, d_gnss_synchro->System); + filename.append("_"); + filename.append(1, d_gnss_synchro->Signal[0]); + filename.append(1, d_gnss_synchro->Signal[1]); + filename.append("_ch_"); + filename.append(std::to_string(d_channel)); + filename.append("_"); + filename.append(std::to_string(d_dump_number)); + filename.append("_sat_"); + filename.append(std::to_string(d_gnss_synchro->PRN)); + filename.append(".mat"); + + mat_t *matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (matfp == nullptr) + { + std::cout << "Unable to create or open Acquisition dump file" << std::endl; + d_dump = false; + } + else + { + size_t dims[2] = {static_cast(effective_fft_size), static_cast(d_num_doppler_points)}; + matvar_t *matvar = Mat_VarCreate("acq_grid", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, grid_.memptr(), 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + dims[0] = static_cast(1); + dims[1] = static_cast(1); + matvar = Mat_VarCreate("doppler_max", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_config_doppler_max, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("doppler_step", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_doppler_step, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("d_positive_acq", MAT_C_INT32, MAT_T_INT32, 1, dims, &d_positive_acq, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + auto aux = static_cast(d_gnss_synchro->Acq_doppler_hz); + matvar = Mat_VarCreate("acq_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + aux = static_cast(d_gnss_synchro->Acq_delay_samples); + matvar = Mat_VarCreate("acq_delay_samples", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("test_statistic", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_test_statistics, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("threshold", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_threshold, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + aux = 0.0; + matvar = Mat_VarCreate("input_power", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("sample_counter", MAT_C_UINT64, MAT_T_UINT64, 1, dims, &d_sample_counter, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_gnss_synchro->PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + Mat_Close(matfp); + } } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h index f5dbe6061..d92ed1db7 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h @@ -1,8 +1,9 @@ /*! * \file pcps_acquisition_fine_doppler_acquisition_cc.h * \brief This class implements a Parallel Code Phase Search Acquisition with multi-dwells and fine Doppler estimation + * for GPS L1 C/A signal * - * Acquisition strategy (Kay Borre book + CFAR threshold). + * Acquisition strategy (Kay Borre book). *
    *
  1. Compute the input signal power estimation *
  2. Doppler serial search loop @@ -14,7 +15,7 @@ * * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkha user, 2007. pp 81-84 + * Approach", Birkhauser, 2007. pp 81-84 * * \authors
      *
    • Javier Arribas, 2013. jarribas(at)cttc.es @@ -22,7 +23,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -40,7 +41,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,73 +49,59 @@ #ifndef GNSS_SDR_PCPS_ACQUISITION_FINE_DOPPLER_CC_H_ #define GNSS_SDR_PCPS_ACQUISITION_FINE_DOPPLER_CC_H_ +#include "acq_conf.h" +#include "gnss_synchro.h" +#include +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" class pcps_acquisition_fine_doppler_cc; typedef boost::shared_ptr -pcps_acquisition_fine_doppler_cc_sptr; + pcps_acquisition_fine_doppler_cc_sptr; pcps_acquisition_fine_doppler_cc_sptr -pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, int samples_per_ms, - bool dump, std::string dump_filename); +pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_); /*! * \brief This class implements a Parallel Code Phase Search Acquisition. * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. */ - -class pcps_acquisition_fine_doppler_cc: public gr::block +class pcps_acquisition_fine_doppler_cc : public gr::block { private: friend pcps_acquisition_fine_doppler_cc_sptr - pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); + pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_); + pcps_acquisition_fine_doppler_cc(const Acq_Conf& conf_); - pcps_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); - - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); - - int compute_and_accumulate_grid(gr_vector_const_void_star &input_items); - int estimate_Doppler(gr_vector_const_void_star &input_items); - float estimate_input_power(gr_vector_const_void_star &input_items); - double search_maximum(); + int compute_and_accumulate_grid(gr_vector_const_void_star& input_items); + int estimate_Doppler(); + float estimate_input_power(gr_vector_const_void_star& input_items); + double compute_CAF(); void reset_grid(); void update_carrier_wipeoff(); void free_grid_memory(); + bool start(); + Acq_Conf acq_parameters; long d_fs_in; - long d_freq; int d_samples_per_ms; int d_max_dwells; - unsigned int d_doppler_resolution; int d_gnuradio_forecast_samples; float d_threshold; std::string d_satellite_str; int d_config_doppler_max; - int d_config_doppler_min; int d_num_doppler_points; int d_doppler_step; - unsigned int d_sampled_ms; unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint64_t d_sample_counter; gr_complex* d_carrier; gr_complex* d_fft_codes; + gr_complex* d_10_ms_buffer; float* d_magnitude; float** d_grid_data; @@ -122,20 +109,25 @@ private: gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; + Gnss_Synchro* d_gnss_synchro; unsigned int d_code_phase; float d_doppler_freq; - float d_input_power; float d_test_statistics; - std::ofstream d_dump_file; + int d_positive_acq; + int d_state; bool d_active; int d_well_count; + int d_n_samples_in_buffer; bool d_dump; unsigned int d_channel; std::string d_dump_filename; + arma ::fmat grid_; + int64_t d_dump_number; + unsigned int d_dump_channel; + public: /*! * \brief Default destructor. @@ -147,7 +139,7 @@ public: * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { d_gnss_synchro = p_gnss_synchro; } @@ -155,7 +147,7 @@ public: /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() + inline unsigned int mag() const { return d_test_statistics; } @@ -169,14 +161,14 @@ public: * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) + inline void set_active(bool active) { d_active = active; } @@ -185,9 +177,10 @@ public: * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) + inline void set_channel(unsigned int channel) { d_channel = channel; + d_dump_channel = d_channel; } /*! @@ -195,7 +188,7 @@ public: * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) + inline void set_threshold(float threshold) { d_threshold = threshold; } @@ -204,7 +197,7 @@ public: * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) + inline void set_doppler_max(unsigned int doppler_max) { d_config_doppler_max = doppler_max; } @@ -215,16 +208,29 @@ public: */ void set_doppler_step(unsigned int doppler_step); + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int state); /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + /*! + * \brief Obtains the next power of 2 greater or equal to the input parameter + * \param n - Integer value to obtain the next power of 2. + */ + unsigned int nextPowerOf2(unsigned int n); + + void dump_results(int effective_fft_size); }; #endif /* pcps_acquisition_fine_doppler_cc*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc new file mode 100644 index 000000000..ffb4d2452 --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc @@ -0,0 +1,353 @@ +/*! + * \file pcps_acquisition_fpga.cc + * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA + * + * Note: The CFAR algorithm is not implemented in the FPGA. + * Note 2: The bit transition flag is not implemented in the FPGA + * + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2011. jarribas(at)cttc.es + *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
      • Marc Molina, 2013. marc.molina.pena@gmail.com + *
      • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
      + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "pcps_acquisition_fpga.h" +#include +#include +#include + + +#define AQ_DOWNSAMPLING_DELAY 40 // delay due to the downsampling filter in the acquisition + +using google::LogMessage; + +pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_) +{ + return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(std::move(conf_))); +} + + +pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block("pcps_acquisition_fpga", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) +{ + // printf("acq constructor start\n"); + this->message_port_register_out(pmt::mp("events")); + + acq_parameters = std::move(conf_); + d_sample_counter = 0ULL; // SAMPLE COUNTER + d_active = false; + d_state = 0; + //d_fft_size = acq_parameters.sampled_ms * acq_parameters.samples_per_ms; + d_fft_size = acq_parameters.samples_per_code; + d_mag = 0; + d_input_power = 0.0; + d_num_doppler_bins = 0U; + d_threshold = 0.0; + d_doppler_step = 0U; + d_test_statistics = 0.0; + d_channel = 0U; + d_gnss_synchro = nullptr; + + //printf("zzzz acq_parameters.code_length = %d\n", acq_parameters.code_length); + //printf("zzzz acq_parameters.samples_per_ms = %d\n", acq_parameters.samples_per_ms); + //printf("zzzz d_fft_size = %d\n", d_fft_size); + + // this one works we don't know why + // acquisition_fpga = std::make_shared + // (acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, acq_parameters.samples_per_ms, + // acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); + + // this one is the one it should be but it doesn't work + acquisition_fpga = std::make_shared(acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, d_fft_size, + acq_parameters.fs_in, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); + + // acquisition_fpga = std::make_shared + // (acq_parameters.device_name, acq_parameters.samples_per_code, acq_parameters.doppler_max, acq_parameters.samples_per_code, + // acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); + + // debug + //debug_d_max_absolute = 0.0; + //debug_d_input_power_absolute = 0.0; + // printf("acq constructor end\n"); +} + + +pcps_acquisition_fpga::~pcps_acquisition_fpga() +{ + // printf("acq destructor start\n"); + acquisition_fpga->free(); + // printf("acq destructor end\n"); +} + + +void pcps_acquisition_fpga::set_local_code() +{ + // printf("acq set local code start\n"); + acquisition_fpga->set_local_code(d_gnss_synchro->PRN); + // printf("acq set local code end\n"); +} + + +void pcps_acquisition_fpga::init() +{ + // printf("acq init start\n"); + d_gnss_synchro->Flag_valid_acquisition = false; + d_gnss_synchro->Flag_valid_symbol_output = false; + d_gnss_synchro->Flag_valid_pseudorange = false; + d_gnss_synchro->Flag_valid_word = false; + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_num_doppler_bins = static_cast(std::ceil(static_cast(static_cast(acq_parameters.doppler_max) - static_cast(-acq_parameters.doppler_max)) / static_cast(d_doppler_step))); + + acquisition_fpga->init(); + // printf("acq init end\n"); +} + + +void pcps_acquisition_fpga::set_state(int32_t state) +{ + // printf("acq set state start\n"); + d_state = state; + if (d_state == 1) + { + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0; + //d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_active = true; + } + else if (d_state == 0) + { + } + else + { + LOG(ERROR) << "State can only be set to 0 or 1"; + } + // printf("acq set state end\n"); +} + + +void pcps_acquisition_fpga::send_positive_acquisition() +{ + // printf("acq send positive acquisition start\n"); + // 6.1- Declare positive acquisition using a message port + //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "positive acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + + this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); + // printf("acq send positive acquisition end\n"); +} + + +void pcps_acquisition_fpga::send_negative_acquisition() +{ + // printf("acq send negative acquisition start\n"); + // 6.2- Declare negative acquisition using a message port + //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "negative acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + + this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); + // printf("acq send negative acquisition end\n"); +} + + +void pcps_acquisition_fpga::set_active(bool active) +{ + // printf("acq set active start\n"); + d_active = active; + + // initialize acquisition algorithm + uint32_t indext = 0U; + float magt = 0.0; + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + + d_input_power = 0.0; + d_mag = 0.0; + + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << acq_parameters.doppler_max + << ", doppler_step: " << d_doppler_step + // no CFAR algorithm in the FPGA + << ", use_CFAR_algorithm_flag: false"; + + uint64_t initial_sample; + float input_power_all = 0.0; + float input_power_computed = 0.0; + + float temp_d_input_power; + + // loop through acquisition + /* + for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps + int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * doppler_index; + + //acquisition_fpga->set_phase_step(doppler_index); + acquisition_fpga->set_doppler_sweep_debug(1, doppler_index); + acquisition_fpga->run_acquisition(); // runs acquisition and waits until it is finished + acquisition_fpga->read_acquisition_results(&indext, &magt, + &initial_sample, &d_input_power, &d_doppler_index); + d_sample_counter = initial_sample; + + if (d_mag < magt) + { + d_mag = magt; + + temp_d_input_power = d_input_power; + + input_power_all = d_input_power / (d_fft_size - 1); + input_power_computed = (d_input_power - d_mag) / (d_fft_size - 1); + d_input_power = (d_input_power - d_mag) / (d_fft_size - 1); + + d_gnss_synchro->Acq_delay_samples = static_cast(indext % acq_parameters.samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + + d_test_statistics = (d_mag / d_input_power); // correction_factor; + } + + // In the case of the FPGA the option of dumping the results of the acquisition to a file is not available + // because the IFFT vector is not available + } +*/ + + // debug + //acquisition_fpga->block_samples(); + + // run loop in hw + //printf("LAUNCH ACQ\n"); + acquisition_fpga->set_doppler_sweep(d_num_doppler_bins); + acquisition_fpga->run_acquisition(); + acquisition_fpga->read_acquisition_results(&indext, &magt, + &initial_sample, &d_input_power, &d_doppler_index); + //printf("READ ACQ RESULTS\n"); + + // debug + //acquisition_fpga->unblock_samples(); + + d_mag = magt; + + + // debug + debug_d_max_absolute = magt; + debug_d_input_power_absolute = d_input_power; + debug_indext = indext; + debug_doppler_index = d_doppler_index; + + // temp_d_input_power = d_input_power; + + d_input_power = (d_input_power - d_mag) / (d_fft_size - 1); + int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * d_doppler_index; + //d_gnss_synchro->Acq_delay_samples = static_cast(2*(indext % (2*acq_parameters.samples_per_code))); + d_gnss_synchro->Acq_delay_samples = static_cast(indext % acq_parameters.samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_sample_counter = initial_sample; + //d_gnss_synchro->Acq_samplestamp_samples = 2*d_sample_counter - 81; // delay due to the downsampling filter in the acquisition + //d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter - 40; // delay due to the downsampling filter in the acquisition + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; // delay due to the downsampling filter in the acquisition + d_test_statistics = (d_mag / d_input_power); //* correction_factor; + + // debug + // if (d_gnss_synchro->Acq_delay_samples > acq_parameters.code_length) + // { + // printf("d_gnss_synchro->Acq_samplestamp_samples = %d\n", d_gnss_synchro->Acq_samplestamp_samples); + // printf("d_gnss_synchro->Acq_delay_samples = %f\n", d_gnss_synchro->Acq_delay_samples); + // } + + // if (temp_d_input_power > debug_d_input_power_absolute) + // { + // debug_d_max_absolute = d_mag; + // debug_d_input_power_absolute = temp_d_input_power; + // } + // printf ("max debug_d_max_absolute = %f\n", debug_d_max_absolute); + // printf ("debug_d_input_power_absolute = %f\n", debug_d_input_power_absolute); + + // printf("&&&&& d_test_statistics = %f\n", d_test_statistics); + // printf("&&&&& debug_d_max_absolute =%f\n",debug_d_max_absolute); + // printf("&&&&& debug_d_input_power_absolute =%f\n",debug_d_input_power_absolute); + // printf("&&&&& debug_indext = %d\n",debug_indext); + // printf("&&&&& debug_doppler_index = %d\n",debug_doppler_index); + + if (d_test_statistics > d_threshold) + { + d_active = false; + // printf("##### d_test_statistics = %f\n", d_test_statistics); + // printf("##### debug_d_max_absolute =%f\n",debug_d_max_absolute); + // printf("##### debug_d_input_power_absolute =%f\n",debug_d_input_power_absolute); + // printf("##### initial_sample = %llu\n",initial_sample); + // printf("##### debug_doppler_index = %d\n",debug_doppler_index); + send_positive_acquisition(); + d_state = 0; // Positive acquisition + } + else + { + d_state = 0; + d_active = false; + send_negative_acquisition(); + } + + // printf("acq set active end\n"); +} + + +int pcps_acquisition_fpga::general_work(int noutput_items __attribute__((unused)), + gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + // the general work is not used with the acquisition that uses the FPGA + return noutput_items; +} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h new file mode 100644 index 000000000..abf8f6b06 --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h @@ -0,0 +1,230 @@ +/*! + * \file pcps_acquisition_fpga.h + * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA. + * + * Note: The CFAR algorithm is not implemented in the FPGA. + * Note 2: The bit transition flag is not implemented in the FPGA + * + * Acquisition strategy (Kay Borre book + CFAR threshold). + *
        + *
      1. Compute the input signal power estimation + *
      2. Doppler serial search loop + *
      3. Perform the FFT-based circular convolution (parallel time search) + *
      4. Record the maximum peak and the associated synchronization parameters + *
      5. Compute the test statistics and compare to the threshold + *
      6. Declare positive or negative acquisition using a message queue + *
      + * + * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach", Birkhauser, 2007. pp 81-84 + * + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2011. jarribas(at)cttc.es + *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
      • Marc Molina, 2013. marc.molina.pena@gmail.com + *
      • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
      • Antonio Ramos, 2017. antonio.ramos@cttc.es + *
      + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_PCPS_ACQUISITION_FPGA_H_ + + +#include "fpga_acquisition.h" +#include "gnss_synchro.h" +#include + +typedef struct +{ + /* pcps acquisition configuration */ + uint32_t sampled_ms; + uint32_t doppler_max; + int64_t fs_in; + int32_t samples_per_ms; + int32_t samples_per_code; + int32_t code_length; + uint32_t select_queue_Fpga; + std::string device_name; + lv_16sc_t* all_fft_codes; // memory that contains all the code ffts + +} pcpsconf_fpga_t; + +class pcps_acquisition_fpga; + +typedef boost::shared_ptr pcps_acquisition_fpga_sptr; + +pcps_acquisition_fpga_sptr +pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_); + +/*! + * \brief This class implements a Parallel Code Phase Search Acquisition that uses the FPGA. + * + * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", + * Algorithm 1, for a pseudocode description of this implementation. + */ +class pcps_acquisition_fpga : public gr::block +{ +private: + friend pcps_acquisition_fpga_sptr + + pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_); + + pcps_acquisition_fpga(pcpsconf_fpga_t conf_); + + void send_negative_acquisition(); + + void send_positive_acquisition(); + + pcpsconf_fpga_t acq_parameters; + bool d_active; + float d_threshold; + float d_mag; + float d_input_power; + uint32_t d_doppler_index; + float d_test_statistics; + int32_t d_state; + uint32_t d_channel; + uint32_t d_doppler_step; + uint32_t d_fft_size; + uint32_t d_num_doppler_bins; + uint64_t d_sample_counter; + Gnss_Synchro* d_gnss_synchro; + std::shared_ptr acquisition_fpga; + + // debug + float debug_d_max_absolute; + float debug_d_input_power_absolute; + int32_t debug_indext; + int32_t debug_doppler_index; + +public: + ~pcps_acquisition_fpga(); + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to exchange synchronization data between acquisition and tracking blocks. + * \param p_gnss_synchro Satellite information shared by the processing blocks. + */ + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + // printf("acq set gnss synchro start\n"); + d_gnss_synchro = p_gnss_synchro; + // printf("acq set gnss synchro end\n"); + } + + /*! + * \brief Returns the maximum peak of grid search. + */ + inline uint32_t mag() const + { + // printf("acq dmag start\n"); + return d_mag; + // printf("acq dmag end\n"); + } + + /*! + * \brief Initializes acquisition algorithm. + */ + void init(); + + /*! + * \brief Sets local code for PCPS acquisition algorithm. + * \param code - Pointer to the PRN code. + */ + void set_local_code(); + + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int32_t state); + + /*! + * \brief Starts acquisition algorithm, turning from standby mode to + * active mode + * \param active - bool that activates/deactivates the block. + */ + void set_active(bool active); + + /*! + * \brief Set acquisition channel unique ID + * \param channel - receiver channel. + */ + inline void set_channel(uint32_t channel) + { + d_channel = channel; + } + + /*! + * \brief Set statistics threshold of PCPS algorithm. + * \param threshold - Threshold for signal detection (check \ref Navitec2012, + * Algorithm 1, for a definition of this threshold). + */ + inline void set_threshold(float threshold) + { + // printf("acq set threshold start\n"); + d_threshold = threshold; + // printf("acq set threshold end\n"); + } + + /*! + * \brief Set maximum Doppler grid search + * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. + */ + inline void set_doppler_max(uint32_t doppler_max) + { + // printf("acq set doppler max start\n"); + acq_parameters.doppler_max = doppler_max; + acquisition_fpga->set_doppler_max(doppler_max); + // printf("acq set doppler max end\n"); + } + + /*! + * \brief Set Doppler steps for the grid search + * \param doppler_step - Frequency bin of the search grid [Hz]. + */ + inline void set_doppler_step(uint32_t doppler_step) + { + // printf("acq set doppler step start\n"); + d_doppler_step = doppler_step; + acquisition_fpga->set_doppler_step(doppler_step); + // printf("acq set doppler step end\n"); + } + + /*! + * \brief Parallel Code Phase Search Acquisition signal processing. + */ + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +#endif /* GNSS_SDR_PCPS_ACQUISITION_FPGA_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc deleted file mode 100644 index 40201b0ba..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc +++ /dev/null @@ -1,488 +0,0 @@ -/*! - * \file pcps_acquisition_sc.cc - * \brief This class implements a Parallel Code Phase Search Acquisition - * \authors
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
      • Marc Molina, 2013. marc.molina.pena@gmail.com - *
      - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "pcps_acquisition_sc.h" -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI - -using google::LogMessage; - -pcps_acquisition_sc_sptr pcps_make_acquisition_sc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename) -{ - - return pcps_acquisition_sc_sptr( - new pcps_acquisition_sc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, bit_transition_flag, use_CFAR_algorithm_flag, dump, dump_filename)); -} - -pcps_acquisition_sc::pcps_acquisition_sc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename) : - gr::block("pcps_acquisition_sc", - gr::io_signature::make(1, 1, sizeof(lv_16sc_t) * sampled_ms * samples_per_ms * ( bit_transition_flag ? 2 : 1 )), - gr::io_signature::make(0, 0, 0)) -{ - this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER - d_active = false; - d_state = 0; - d_freq = freq; - d_fs_in = fs_in; - d_samples_per_ms = samples_per_ms; - d_samples_per_code = samples_per_code; - d_sampled_ms = sampled_ms; - d_max_dwells = max_dwells; - d_well_count = 0; - d_doppler_max = doppler_max; - d_fft_size = d_sampled_ms * d_samples_per_ms; - d_mag = 0; - d_input_power = 0.0; - d_num_doppler_bins = 0; - d_bit_transition_flag = bit_transition_flag; - d_use_CFAR_algorithm_flag = use_CFAR_algorithm_flag; - d_threshold = 0.0; - d_doppler_step = 250; - d_code_phase = 0; - d_test_statistics = 0.0; - d_channel = 0; - d_doppler_freq = 0.0; - - //set_relative_rate( 1.0/d_fft_size ); - - // COD: - // Experimenting with the overlap/save technique for handling bit trannsitions - // The problem: Circular correlation is asynchronous with the received code. - // In effect the first code phase used in the correlation is the current - // estimate of the code phase at the start of the input buffer. If this is 1/2 - // of the code period a bit transition would move all the signal energy into - // adjacent frequency bands at +/- 1/T where T is the integration time. - // - // We can avoid this by doing linear correlation, effectively doubling the - // size of the input buffer and padding the code with zeros. - if( d_bit_transition_flag ) - { - d_fft_size *= 2; - d_max_dwells = 1; - } - - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - //temporary storage for the input conversion from 16sc to float 32fc - d_in_32fc = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - // Direct FFT - d_fft_if = new gr::fft::fft_complex(d_fft_size, true); - - // Inverse FFT - d_ifft = new gr::fft::fft_complex(d_fft_size, false); - - // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; - - d_gnss_synchro = 0; - d_grid_doppler_wipeoffs = 0; -} - - -pcps_acquisition_sc::~pcps_acquisition_sc() -{ - if (d_num_doppler_bins > 0) - { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) - { - volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); - } - delete[] d_grid_doppler_wipeoffs; - } - - volk_gnsssdr_free(d_fft_codes); - volk_gnsssdr_free(d_magnitude); - volk_gnsssdr_free(d_in_32fc); - - delete d_ifft; - delete d_fft_if; - - if (d_dump) - { - d_dump_file.close(); - } -} - - -void pcps_acquisition_sc::set_local_code(std::complex * code) -{ - // COD - // Here we want to create a buffer that looks like this: - // [ 0 0 0 ... 0 c_0 c_1 ... c_L] - // where c_i is the local code and there are L zeros and L chips - int offset = 0; - if( d_bit_transition_flag ) - { - std::fill_n( d_fft_if->get_inbuf(), d_samples_per_code, gr_complex( 0.0, 0.0 ) ); - offset = d_samples_per_code; - } - memcpy(d_fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * d_samples_per_code); - d_fft_if->execute(); // We need the FFT of local code - volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); -} - - -void pcps_acquisition_sc::update_local_carrier(gr_complex* carrier_vector, int correlator_length_samples, float freq) -{ - float phase_step_rad = GPS_TWO_PI * freq / static_cast(d_fs_in); - float _phase[1]; - _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(carrier_vector, - phase_step_rad, _phase, correlator_length_samples); -} - - -void pcps_acquisition_sc::init() -{ - d_gnss_synchro->Flag_valid_acquisition = false; - d_gnss_synchro->Flag_valid_symbol_output = false; - d_gnss_synchro->Flag_valid_pseudorange = false; - d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_mag = 0.0; - d_input_power = 0.0; - - d_num_doppler_bins = ceil( static_cast(static_cast(d_doppler_max) - static_cast(-d_doppler_max)) / static_cast(d_doppler_step)); - - // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - update_local_carrier(d_grid_doppler_wipeoffs[doppler_index], d_fft_size, d_freq + doppler); - } -} - - - -void pcps_acquisition_sc::set_state(int state) -{ - d_state = state; - if (d_state == 1) - { - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - } - else if (d_state == 0) - {} - else - { - LOG(ERROR) << "State can only be set to 0 or 1"; - } -} - -int pcps_acquisition_sc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) -{ - /* - * By J.Arribas, L.Esteve and M.Molina - * Acquisition strategy (Kay Borre book + CFAR threshold): - * 1. Compute the input signal power estimation - * 2. Doppler serial search loop - * 3. Perform the FFT-based circular convolution (parallel time search) - * 4. Record the maximum peak and the associated synchronization parameters - * 5. Compute the test statistics and compare to the threshold - * 6. Declare positive or negative acquisition using a message port - */ - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - - switch (d_state) - { - case 0: - { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - - d_state = 1; - } - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - //DLOG(INFO) << "Consumed " << ninput_items[0] << " items"; - - break; - } - - case 1: - { - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - float magt = 0.0; - const lv_16sc_t *in = (const lv_16sc_t *)input_items[0]; //Get the input samples pointer - int effective_fft_size = ( d_bit_transition_flag ? d_fft_size/2 : d_fft_size ); - - //TODO: optimize the signal processing chain to not use gr_complex. This is a temporary solution - volk_gnsssdr_16ic_convert_32fc(d_in_32fc,in,effective_fft_size); - - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - - d_mag = 0.0; - - d_sample_counter += d_fft_size; // sample counter - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - if (d_use_CFAR_algorithm_flag == true) - { - // 1- (optional) Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, d_in_32fc, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= static_cast(d_fft_size); - } - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), d_in_32fc, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code reference using SIMD operations with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Search maximum - size_t offset = ( d_bit_transition_flag ? effective_fft_size : 0 ); - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf() + offset, effective_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude, effective_fft_size); - magt = d_magnitude[indext]; - - if (d_use_CFAR_algorithm_flag == true) - { - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt = d_magnitude[indext] / (fft_normalization_factor * fft_normalization_factor); - } - - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - - if (d_use_CFAR_algorithm_flag == false) - { - // Search grid noise floor approximation for this doppler line - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, effective_fft_size); - d_input_power = (d_input_power - d_mag) / (effective_fft_size - 1); - } - - // In case that d_bit_transition_flag = true, we compare the potentially - // new maximum test statistics (d_mag/d_input_power) with the value in - // d_test_statistics. When the second dwell is being processed, the value - // of d_mag/d_input_power could be lower than d_test_statistics (i.e, - // the maximum test statistics in the previous dwell is greater than - // current d_mag/d_input_power). Note that d_test_statistics is not - // restarted between consecutive dwells in multidwell operation. - - if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - - // 5- Compute the test statistics and compare to the threshold - d_test_statistics = d_mag / d_input_power; - //std::cout<<"d_input_power="<Acq_doppler_hz ="<Acq_doppler_hz <System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" - << doppler - << p.extension().string(); - - DLOG(INFO) << "Writing ACQ out to " << filename.str(); - - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } - - if (!d_bit_transition_flag) - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition - } - } - else - { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else - { - d_state = 3; // Negative acquisition - } - } - } - - consume_each(1); - - DLOG(INFO) << "Done. Consumed 1 item."; - - break; - } - - case 2: - { - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - - return noutput_items; -} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.h deleted file mode 100644 index bc13941f3..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.h +++ /dev/null @@ -1,234 +0,0 @@ -/*! - * \file pcps_acquisition_sc.h - * \brief This class implements a Parallel Code Phase Search Acquisition - * - * Acquisition strategy (Kay Borre book + CFAR threshold). - *
        - *
      1. Compute the input signal power estimation - *
      2. Doppler serial search loop - *
      3. Perform the FFT-based circular convolution (parallel time search) - *
      4. Record the maximum peak and the associated synchronization parameters - *
      5. Compute the test statistics and compare to the threshold - *
      6. Declare positive or negative acquisition using a message port - *
      - * - * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkha user, 2007. pp 81-84 - * - * \authors
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
      • Marc Molina, 2013. marc.molina.pena@gmail.com - *
      - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_PCPS_ACQUISITION_SC_H_ -#define GNSS_SDR_PCPS_ACQUISITION_SC_H_ - -#include -#include -#include -#include -#include -#include "gnss_synchro.h" - -class pcps_acquisition_sc; - -typedef boost::shared_ptr pcps_acquisition_sc_sptr; - -pcps_acquisition_sc_sptr -pcps_make_acquisition_sc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - -/*! - * \brief This class implements a Parallel Code Phase Search Acquisition. - * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. - */ -class pcps_acquisition_sc: public gr::block -{ -private: - friend pcps_acquisition_sc_sptr - pcps_make_acquisition_sc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - - pcps_acquisition_sc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - bool dump, - std::string dump_filename); - - void update_local_carrier(gr_complex* carrier_vector, - int correlator_length_samples, - float freq); - - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - //unsigned int d_doppler_resolution; - float d_threshold; - std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; - gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; - gr_complex* d_fft_codes; - gr_complex* d_in_32fc; - gr::fft::fft_complex* d_fft_if; - gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; - float d_doppler_freq; - float d_mag; - float* d_magnitude; - float d_input_power; - float d_test_statistics; - bool d_bit_transition_flag; - bool d_use_CFAR_algorithm_flag; - std::ofstream d_dump_file; - bool d_active; - int d_state; - bool d_dump; - unsigned int d_channel; - std::string d_dump_filename; - -public: - /*! - * \brief Default destructor. - */ - ~pcps_acquisition_sc(); - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to exchange synchronization data between acquisition and tracking blocks. - * \param p_gnss_synchro Satellite information shared by the processing blocks. - */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } - - /*! - * \brief Returns the maximum peak of grid search. - */ - unsigned int mag() - { - return d_mag; - } - - /*! - * \brief Initializes acquisition algorithm. - */ - void init(); - - /*! - * \brief Sets local code for PCPS acquisition algorithm. - * \param code - Pointer to the PRN code. - */ - void set_local_code(std::complex * code); - - /*! - * \brief Starts acquisition algorithm, turning from standby mode to - * active mode - * \param active - bool that activates/deactivates the block. - */ - void set_active(bool active) - { - d_active = active; - } - - /*! - * \brief If set to 1, ensures that acquisition starts at the - * first available sample. - * \param state - int=1 forces start of acquisition - */ - void set_state(int state); - - /*! - * \brief Set acquisition channel unique ID - * \param channel - receiver channel. - */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } - - /*! - * \brief Set statistics threshold of PCPS algorithm. - * \param threshold - Threshold for signal detection (check \ref Navitec2012, - * Algorithm 1, for a definition of this threshold). - */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } - - /*! - * \brief Set maximum Doppler grid search - * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. - */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } - - /*! - * \brief Set Doppler steps for the grid search - * \param doppler_step - Frequency bin of the search grid [Hz]. - */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } - - - /*! - * \brief Parallel Code Phase Search Acquisition signal processing. - */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* GNSS_SDR_PCPS_ACQUISITION_SC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.cc index 5504e6676..b01652ec3 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,50 +25,48 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_assisted_acquisition_cc.h" -#include +#include "GPS_L1_CA.h" +#include "concurrent_map.h" +#include "control_message_factory.h" +#include "gps_acq_assist.h" #include #include #include #include -#include "concurrent_map.h" -#include "control_message_factory.h" -#include "gps_acq_assist.h" -#include "GPS_L1_CA.h" +#include +#include extern concurrent_map global_gps_acq_assist_map; using google::LogMessage; pcps_assisted_acquisition_cc_sptr pcps_make_assisted_acquisition_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) + int32_t max_dwells, uint32_t sampled_ms, int32_t doppler_max, int32_t doppler_min, + int64_t fs_in, int32_t samples_per_ms, bool dump, + std::string dump_filename) { return pcps_assisted_acquisition_cc_sptr( - new pcps_assisted_acquisition_cc(max_dwells, sampled_ms, doppler_max, doppler_min, freq, - fs_in, samples_per_ms, dump, dump_filename)); + new pcps_assisted_acquisition_cc(max_dwells, sampled_ms, doppler_max, doppler_min, + fs_in, samples_per_ms, dump, std::move(dump_filename))); } - pcps_assisted_acquisition_cc::pcps_assisted_acquisition_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) : - gr::block("pcps_assisted_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) + int32_t max_dwells, uint32_t sampled_ms, int32_t doppler_max, int32_t doppler_min, + int64_t fs_in, int32_t samples_per_ms, bool dump, + std::string dump_filename) : gr::block("pcps_assisted_acquisition_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(0, 0, sizeof(gr_complex))) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_sampled_ms = sampled_ms; @@ -77,12 +75,12 @@ pcps_assisted_acquisition_cc::pcps_assisted_acquisition_cc( d_fft_size = d_sampled_ms * d_samples_per_ms; // HS Acquisition d_max_dwells = max_dwells; - d_gnuradio_forecast_samples = d_fft_size*4; + d_gnuradio_forecast_samples = d_fft_size * 4; d_input_power = 0.0; d_state = 0; d_disable_assist = false; - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_carrier = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_carrier = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -92,7 +90,7 @@ pcps_assisted_acquisition_cc::pcps_assisted_acquisition_cc( // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_doppler_resolution = 0; d_threshold = 0; @@ -100,9 +98,9 @@ pcps_assisted_acquisition_cc::pcps_assisted_acquisition_cc( d_doppler_min = 0; d_num_doppler_points = 0; d_doppler_step = 0; - d_grid_data = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_data = nullptr; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; @@ -111,17 +109,15 @@ pcps_assisted_acquisition_cc::pcps_assisted_acquisition_cc( } - -void pcps_assisted_acquisition_cc::set_doppler_step(unsigned int doppler_step) +void pcps_assisted_acquisition_cc::set_doppler_step(uint32_t doppler_step) { d_doppler_step = doppler_step; } - void pcps_assisted_acquisition_cc::free_grid_memory() { - for (int i = 0; i < d_num_doppler_points; i++) + for (int32_t i = 0; i < d_num_doppler_points; i++) { delete[] d_grid_data[i]; delete[] d_grid_doppler_wipeoffs[i]; @@ -130,7 +126,6 @@ void pcps_assisted_acquisition_cc::free_grid_memory() } - pcps_assisted_acquisition_cc::~pcps_assisted_acquisition_cc() { volk_gnsssdr_free(d_carrier); @@ -144,57 +139,52 @@ pcps_assisted_acquisition_cc::~pcps_assisted_acquisition_cc() } - -void pcps_assisted_acquisition_cc::set_local_code(std::complex * code) +void pcps_assisted_acquisition_cc::set_local_code(std::complex *code) { - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); } - void pcps_assisted_acquisition_cc::init() { d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_input_power = 0.0; d_state = 0; - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); } - -void pcps_assisted_acquisition_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void pcps_assisted_acquisition_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = d_gnuradio_forecast_samples ; //set the required available samples in each call + ninput_items_required[0] = d_gnuradio_forecast_samples; //set the required available samples in each call } } - void pcps_assisted_acquisition_cc::get_assistance() { Gps_Acq_Assist gps_acq_assisistance; - if (global_gps_acq_assist_map.read(this->d_gnss_synchro->PRN, gps_acq_assisistance)==true) + if (global_gps_acq_assist_map.read(this->d_gnss_synchro->PRN, gps_acq_assisistance) == true) { //TODO: use the LO tolerance here if (gps_acq_assisistance.dopplerUncertainty >= 1000) { - d_doppler_max = gps_acq_assisistance.d_Doppler0 + gps_acq_assisistance.dopplerUncertainty*2; - d_doppler_min = gps_acq_assisistance.d_Doppler0 - gps_acq_assisistance.dopplerUncertainty*2; + d_doppler_max = gps_acq_assisistance.d_Doppler0 + gps_acq_assisistance.dopplerUncertainty * 2; + d_doppler_min = gps_acq_assisistance.d_Doppler0 - gps_acq_assisistance.dopplerUncertainty * 2; } else { @@ -202,24 +192,23 @@ void pcps_assisted_acquisition_cc::get_assistance() d_doppler_min = gps_acq_assisistance.d_Doppler0 - 1000; } this->d_disable_assist = false; - std::cout << "Acq assist ENABLED for GPS SV "<< this->d_gnss_synchro->PRN <<" (Doppler max,Doppler min)=(" + std::cout << "Acq assist ENABLED for GPS SV " << this->d_gnss_synchro->PRN << " (Doppler max,Doppler min)=(" << d_doppler_max << "," << d_doppler_min << ")" << std::endl; } else { this->d_disable_assist = true; - std::cout << "Acq assist DISABLED for GPS SV "<< this->d_gnss_synchro->PRN << std::endl; + std::cout << "Acq assist DISABLED for GPS SV " << this->d_gnss_synchro->PRN << std::endl; } } - void pcps_assisted_acquisition_cc::reset_grid() { d_well_count = 0; - for (int i = 0; i < d_num_doppler_points; i++) + for (int32_t i = 0; i < d_num_doppler_points; i++) { - for (unsigned int j = 0; j < d_fft_size; j++) + for (uint32_t j = 0; j < d_fft_size; j++) { d_grid_data[i][j] = 0.0; } @@ -227,7 +216,6 @@ void pcps_assisted_acquisition_cc::reset_grid() } - void pcps_assisted_acquisition_cc::redefine_grid() { if (this->d_disable_assist == true) @@ -238,42 +226,41 @@ void pcps_assisted_acquisition_cc::redefine_grid() // Create the search grid array d_num_doppler_points = floor(std::abs(d_doppler_max - d_doppler_min) / d_doppler_step); - d_grid_data = new float*[d_num_doppler_points]; - for (int i = 0; i < d_num_doppler_points; i++) + d_grid_data = new float *[d_num_doppler_points]; + for (int32_t i = 0; i < d_num_doppler_points; i++) { d_grid_data[i] = new float[d_fft_size]; } // create the carrier Doppler wipeoff signals - int doppler_hz; + int32_t doppler_hz; float phase_step_rad; - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_points]; - for (int doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_points]; + for (int32_t doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) { - doppler_hz = d_doppler_min + d_doppler_step*doppler_index; + doppler_hz = d_doppler_min + d_doppler_step * doppler_index; // doppler search steps // compute the carrier doppler wipe-off signal and store it phase_step_rad = static_cast(GPS_TWO_PI) * doppler_hz / static_cast(d_fs_in); d_grid_doppler_wipeoffs[doppler_index] = new gr_complex[d_fft_size]; float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); } } - double pcps_assisted_acquisition_cc::search_maximum() { float magt = 0.0; float fft_normalization_factor; - int index_doppler = 0; + int32_t index_doppler = 0; uint32_t tmp_intex_t = 0; uint32_t index_time = 0; - for (int i=0;i magt) { magt = d_grid_data[i][index_time]; @@ -293,18 +280,19 @@ double pcps_assisted_acquisition_cc::search_maximum() d_gnss_synchro->Acq_delay_samples = static_cast(index_time); d_gnss_synchro->Acq_doppler_hz = static_cast(index_doppler * d_doppler_step + d_doppler_min); d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; // Record results to file if required if (d_dump) { std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write filename.str(""); filename << "../data/test_statistics_" << d_gnss_synchro->System << "_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat"; + << d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat"; d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_grid_data[index_doppler], n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.write(reinterpret_cast(d_grid_data[index_doppler]), n); //write directly |abs(x)|^2 in this Doppler bin? d_dump_file.close(); } @@ -312,28 +300,26 @@ double pcps_assisted_acquisition_cc::search_maximum() } - float pcps_assisted_acquisition_cc::estimate_input_power(gr_vector_const_void_star &input_items) { - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer // 1- Compute the input signal power estimation - float* p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + auto *p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); volk_32fc_magnitude_squared_32f(p_tmp_vector, in, d_fft_size); - const float* p_const_tmp_vector = p_tmp_vector; + const float *p_const_tmp_vector = p_tmp_vector; float power; volk_32f_accumulator_s32f(&power, p_const_tmp_vector, d_fft_size); volk_gnsssdr_free(p_tmp_vector); - return ( power / static_cast(d_fft_size)); + return (power / static_cast(d_fft_size)); } - -int pcps_assisted_acquisition_cc::compute_and_accumulate_grid(gr_vector_const_void_star &input_items) +int32_t pcps_assisted_acquisition_cc::compute_and_accumulate_grid(gr_vector_const_void_star &input_items) { // initialize acquisition algorithm - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer DLOG(INFO) << "Channel: " << d_channel << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " @@ -343,9 +329,9 @@ int pcps_assisted_acquisition_cc::compute_and_accumulate_grid(gr_vector_const_vo << ", doppler_step: " << d_doppler_step; // 2- Doppler frequency search loop - float* p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + auto *p_tmp_vector = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - for (int doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) + for (int32_t doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++) { // doppler search steps // Perform the carrier wipe-off @@ -363,7 +349,7 @@ int pcps_assisted_acquisition_cc::compute_and_accumulate_grid(gr_vector_const_vo // save the grid matrix delay file volk_32fc_magnitude_squared_32f(p_tmp_vector, d_ifft->get_outbuf(), d_fft_size); - const float* old_vector = d_grid_data[doppler_index]; + const float *old_vector = d_grid_data[doppler_index]; volk_32f_x2_add_32f(d_grid_data[doppler_index], old_vector, p_tmp_vector, d_fft_size); } volk_gnsssdr_free(p_tmp_vector); @@ -371,10 +357,9 @@ int pcps_assisted_acquisition_cc::compute_and_accumulate_grid(gr_vector_const_vo } - int pcps_assisted_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { /*! * TODO: High sensitivity acquisition algorithm: @@ -394,102 +379,102 @@ int pcps_assisted_acquisition_cc::general_work(int noutput_items, */ switch (d_state) - { - case 0: // S0. StandBy - if (d_active == true) d_state = 1; - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - break; - case 1: // S1. GetAssist - get_assistance(); - redefine_grid(); - reset_grid(); - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - d_state = 2; - break; - case 2: // S2. ComputeGrid - int consumed_samples; - consumed_samples = compute_and_accumulate_grid(input_items); - d_well_count++; - if (d_well_count >= d_max_dwells) - { - d_state=3; - } - d_sample_counter += consumed_samples; - consume_each(consumed_samples); - break; - case 3: // Compute test statistics and decide - d_input_power = estimate_input_power(input_items); - d_test_statistics = search_maximum(); - if (d_test_statistics > d_threshold) - { - d_state = 5; - } - else - { - if (d_disable_assist == false) - { - d_disable_assist = true; - std::cout << "Acq assist DISABLED for GPS SV "<< this->d_gnss_synchro->PRN << std::endl; - d_state = 4; - } - else - { - d_state = 6; - } - } - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - break; - case 4: // RedefineGrid - free_grid_memory(); - redefine_grid(); - reset_grid(); - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - d_state = 2; - break; - case 5: // Positive_Acq - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - d_active = false; - // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCESS 2=ACQ_FAIL - this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); - free_grid_memory(); - // consume samples to not block the GNU Radio flowgraph - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - d_state = 0; - break; - case 6: // Negative_Acq - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - d_active = false; - // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCESS 2=ACQ_FAIL - this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); - free_grid_memory(); - // consume samples to not block the GNU Radio flowgraph - d_sample_counter += ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - d_state = 0; - break; - default: - d_state = 0; - break; - } + { + case 0: // S0. StandBy + if (d_active == true) d_state = 1; + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + break; + case 1: // S1. GetAssist + get_assistance(); + redefine_grid(); + reset_grid(); + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + d_state = 2; + break; + case 2: // S2. ComputeGrid + int32_t consumed_samples; + consumed_samples = compute_and_accumulate_grid(input_items); + d_well_count++; + if (d_well_count >= d_max_dwells) + { + d_state = 3; + } + d_sample_counter += static_cast(consumed_samples); + consume_each(consumed_samples); + break; + case 3: // Compute test statistics and decide + d_input_power = estimate_input_power(input_items); + d_test_statistics = search_maximum(); + if (d_test_statistics > d_threshold) + { + d_state = 5; + } + else + { + if (d_disable_assist == false) + { + d_disable_assist = true; + std::cout << "Acq assist DISABLED for GPS SV " << this->d_gnss_synchro->PRN << std::endl; + d_state = 4; + } + else + { + d_state = 6; + } + } + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + break; + case 4: // RedefineGrid + free_grid_memory(); + redefine_grid(); + reset_grid(); + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + d_state = 2; + break; + case 5: // Positive_Acq + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "input signal power " << d_input_power; + d_active = false; + // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCESS 2=ACQ_FAIL + this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); + free_grid_memory(); + // consume samples to not block the GNU Radio flowgraph + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + d_state = 0; + break; + case 6: // Negative_Acq + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "input signal power " << d_input_power; + d_active = false; + // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCESS 2=ACQ_FAIL + this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); + free_grid_memory(); + // consume samples to not block the GNU Radio flowgraph + d_sample_counter += static_cast(ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + d_state = 0; + break; + default: + d_state = 0; + break; + } return noutput_items; } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.h index d090c04e6..d582821c6 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_assisted_acquisition_cc.h @@ -14,7 +14,7 @@ * * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkha user, 2007. pp 81-84 + * Approach", Birkhauser, 2007. pp 81-84 * * \authors
        *
      • Javier Arribas, 2013. jarribas(at)cttc.es @@ -22,7 +22,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -40,7 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,22 +48,27 @@ #ifndef GNSS_SDR_PCPS_ASSISTED_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_ASSISTED_ACQUISITION_CC_H_ +#include "gnss_synchro.h" +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" class pcps_assisted_acquisition_cc; typedef boost::shared_ptr -pcps_assisted_acquisition_cc_sptr; + pcps_assisted_acquisition_cc_sptr; pcps_assisted_acquisition_cc_sptr -pcps_make_assisted_acquisition_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, int samples_per_ms, - bool dump, std::string dump_filename); +pcps_make_assisted_acquisition_cc( + int32_t max_dwells, + uint32_t sampled_ms, + int32_t doppler_max, + int32_t doppler_min, + int64_t fs_in, + int32_t samples_per_ms, + bool dump, std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition. @@ -71,49 +76,48 @@ pcps_make_assisted_acquisition_cc(int max_dwells, unsigned int sampled_ms, * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", * Algorithm 1, for a pseudocode description of this implementation. */ -class pcps_assisted_acquisition_cc: public gr::block +class pcps_assisted_acquisition_cc : public gr::block { private: friend pcps_assisted_acquisition_cc_sptr - pcps_make_assisted_acquisition_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); + pcps_make_assisted_acquisition_cc(int32_t max_dwells, uint32_t sampled_ms, + int32_t doppler_max, int32_t doppler_min, int64_t fs_in, + int32_t samples_per_ms, bool dump, + std::string dump_filename); - pcps_assisted_acquisition_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long freq, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); + pcps_assisted_acquisition_cc(int32_t max_dwells, uint32_t sampled_ms, + int32_t doppler_max, int32_t doppler_min, int64_t fs_in, + int32_t samples_per_ms, bool dump, + std::string dump_filename); - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + void calculate_magnitudes(gr_complex* fft_begin, int32_t doppler_shift, + int32_t doppler_offset); - int compute_and_accumulate_grid(gr_vector_const_void_star &input_items); - float estimate_input_power(gr_vector_const_void_star &input_items); + int32_t compute_and_accumulate_grid(gr_vector_const_void_star& input_items); + float estimate_input_power(gr_vector_const_void_star& input_items); double search_maximum(); void get_assistance(); void reset_grid(); void redefine_grid(); void free_grid_memory(); - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_max_dwells; - unsigned int d_doppler_resolution; - int d_gnuradio_forecast_samples; + int64_t d_fs_in; + int32_t d_samples_per_ms; + int32_t d_max_dwells; + uint32_t d_doppler_resolution; + int32_t d_gnuradio_forecast_samples; float d_threshold; std::string d_satellite_str; - int d_doppler_max; - int d_doppler_min; - int d_config_doppler_max; - int d_config_doppler_min; + int32_t d_doppler_max; + int32_t d_doppler_min; + int32_t d_config_doppler_max; + int32_t d_config_doppler_min; - int d_num_doppler_points; - int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_fft_size; - unsigned long int d_sample_counter; + int32_t d_num_doppler_points; + int32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_fft_size; + uint64_t d_sample_counter; gr_complex* d_carrier; gr_complex* d_fft_codes; @@ -122,18 +126,18 @@ private: gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_input_power; float d_test_statistics; std::ofstream d_dump_file; - int d_state; + int32_t d_state; bool d_active; bool d_disable_assist; - int d_well_count; + int32_t d_well_count; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; @@ -148,7 +152,7 @@ public: * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { d_gnss_synchro = p_gnss_synchro; } @@ -156,7 +160,7 @@ public: /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() + inline uint32_t mag() const { return d_test_statistics; } @@ -170,14 +174,14 @@ public: * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) + inline void set_active(bool active) { d_active = active; } @@ -186,7 +190,7 @@ public: * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) + inline void set_channel(uint32_t channel) { d_channel = channel; } @@ -196,7 +200,7 @@ public: * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) + inline void set_threshold(float threshold) { d_threshold = threshold; } @@ -205,7 +209,7 @@ public: * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) + inline void set_doppler_max(uint32_t doppler_max) { d_doppler_max = doppler_max; } @@ -214,17 +218,16 @@ public: * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step); - + void set_doppler_step(uint32_t doppler_step); /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); }; #endif /* GNSS_SDR_PCPS_assisted_acquisition_cc_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.cc index e03d6c2d5..99841b5b6 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,48 +29,54 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_cccwsr_acquisition_cc.h" -#include +#include "GPS_L1_CA.h" // GPS_TWO_PI +#include "control_message_factory.h" #include #include #include #include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI - +#include +#include using google::LogMessage; pcps_cccwsr_acquisition_cc_sptr pcps_cccwsr_make_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename) + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, std::string dump_filename) { return pcps_cccwsr_acquisition_cc_sptr( - new pcps_cccwsr_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, - samples_per_ms, samples_per_code, dump, dump_filename)); + new pcps_cccwsr_acquisition_cc(sampled_ms, max_dwells, doppler_max, fs_in, + samples_per_ms, samples_per_code, dump, std::move(dump_filename))); } + pcps_cccwsr_acquisition_cc::pcps_cccwsr_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename) : - gr::block("pcps_cccwsr_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename) : gr::block("pcps_cccwsr_acquisition_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), + gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -83,13 +89,13 @@ pcps_cccwsr_acquisition_cc::pcps_cccwsr_acquisition_cc( d_input_power = 0.0; d_num_doppler_bins = 0; - d_fft_code_data = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_fft_code_pilot = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_data_correlation = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_pilot_correlation = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_correlation_plus = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_correlation_minus = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_code_data = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_fft_code_pilot = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_data_correlation = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_pilot_correlation = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_correlation_plus = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_correlation_minus = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -99,13 +105,13 @@ pcps_cccwsr_acquisition_cc::pcps_cccwsr_acquisition_cc( // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_doppler_resolution = 0; d_threshold = 0; d_doppler_step = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; @@ -116,7 +122,7 @@ pcps_cccwsr_acquisition_cc::~pcps_cccwsr_acquisition_cc() { if (d_num_doppler_bins > 0) { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) + for (uint32_t i = 0; i < d_num_doppler_bins; i++) { volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); } @@ -140,21 +146,21 @@ pcps_cccwsr_acquisition_cc::~pcps_cccwsr_acquisition_cc() } } -void pcps_cccwsr_acquisition_cc::set_local_code(std::complex* code_data, - std::complex* code_pilot) +void pcps_cccwsr_acquisition_cc::set_local_code(std::complex *code_data, + std::complex *code_pilot) { // Data code (E1B) memcpy(d_fft_if->get_inbuf(), code_data, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_code_data,d_fft_if->get_outbuf(),d_fft_size); + volk_32fc_conjugate_32fc(d_fft_code_data, d_fft_if->get_outbuf(), d_fft_size); // Pilot code (E1C) memcpy(d_fft_if->get_inbuf(), code_pilot, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code, volk_32fc_conjugate_32fc(d_fft_code_pilot, d_fft_if->get_outbuf(), d_fft_size); @@ -166,53 +172,54 @@ void pcps_cccwsr_acquisition_cc::init() d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_mag = 0.0; d_input_power = 0.0; // Count the number of bins d_num_doppler_bins = 0; - for (int doppler = static_cast(-d_doppler_max); - doppler <= static_cast(d_doppler_max); + for (auto doppler = static_cast(-d_doppler_max); + doppler <= static_cast(d_doppler_max); doppler += d_doppler_step) - { - d_num_doppler_bins++; - } + { + d_num_doppler_bins++; + } // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_bins]; + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + float phase_step_rad = GPS_TWO_PI * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); } } -void pcps_cccwsr_acquisition_cc::set_state(int state) +void pcps_cccwsr_acquisition_cc::set_state(int32_t state) { d_state = state; if (d_state == 1) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_well_count = 0; d_mag = 0.0; d_input_power = 0.0; d_test_statistics = 0.0; } else if (d_state == 0) - {} + { + } else { LOG(ERROR) << "State can only be set to 0 or 1"; @@ -221,227 +228,228 @@ void pcps_cccwsr_acquisition_cc::set_state(int state) int pcps_cccwsr_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int32_t acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL switch (d_state) - { - case 0: { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - - d_state = 1; - } - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - break; - } - case 1: - { - // initialize acquisition algorithm - int doppler; - - uint32_t indext = 0; - uint32_t indext_plus = 0; - uint32_t indext_minus = 0; - float magt = 0.0; - float magt_plus = 0.0; - float magt_minus = 0.0; - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - - d_sample_counter += d_fft_size; // sample counter - - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - // 1- Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= static_cast(d_fft_size); - - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd data code reference (E1B) using SIMD operations - // with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_code_data, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Copy the result of the correlation between wiped--off signal and data code in - // d_data_correlation. - memcpy(d_data_correlation, d_ifft->get_outbuf(), sizeof(gr_complex)*d_fft_size); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd pilot code reference (E1C) using SIMD operations - // with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_code_pilot, d_fft_size); - - // Compute the inverse FFT - d_ifft->execute(); - - // Copy the result of the correlation between wiped--off signal and pilot code in - // d_data_correlation. - memcpy(d_pilot_correlation, d_ifft->get_outbuf(), sizeof(gr_complex)*d_fft_size); - - for (unsigned int i = 0; i < d_fft_size; i++) - { - d_correlation_plus[i] = std::complex( - d_data_correlation[i].real() - d_pilot_correlation[i].imag(), - d_data_correlation[i].imag() + d_pilot_correlation[i].real()); - - d_correlation_minus[i] = std::complex( - d_data_correlation[i].real() + d_pilot_correlation[i].imag(), - d_data_correlation[i].imag() - d_pilot_correlation[i].real()); - } - - volk_32fc_magnitude_squared_32f(d_magnitude, d_correlation_plus, d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_plus, d_magnitude, d_fft_size); - magt_plus = d_magnitude[indext_plus] / (fft_normalization_factor * fft_normalization_factor); - - volk_32fc_magnitude_squared_32f(d_magnitude, d_correlation_minus, d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext_minus, d_magnitude, d_fft_size); - magt_minus = d_magnitude[indext_minus] / (fft_normalization_factor * fft_normalization_factor); - - if (magt_plus >= magt_minus) + case 0: + { + if (d_active) { - magt = magt_plus; - indext = indext_plus; - } - else - { - magt = magt_minus; - indext = indext_minus; + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + + d_state = 1; } - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - } + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } + break; + } + case 1: + { + // initialize acquisition algorithm + int32_t doppler; - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; + uint32_t indext = 0; + uint32_t indext_plus = 0; + uint32_t indext_minus = 0; + float magt = 0.0; + float magt_plus = 0.0; + float magt_minus = 0.0; + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - // 6- Declare positive or negative acquisition using a message port - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition - } + d_sample_counter += static_cast(d_fft_size); // sample counter - consume_each(1); + d_well_count++; - break; + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; + + // 1- Compute the input signal power estimation + volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); + volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); + d_input_power /= static_cast(d_fft_size); + + // 2- Doppler frequency search loop + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps + + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, + d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + + // 3- Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd data code reference (E1B) using SIMD operations + // with VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_fft_if->get_outbuf(), d_fft_code_data, d_fft_size); + + // compute the inverse FFT + d_ifft->execute(); + + // Copy the result of the correlation between wiped--off signal and data code in + // d_data_correlation. + memcpy(d_data_correlation, d_ifft->get_outbuf(), sizeof(gr_complex) * d_fft_size); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd pilot code reference (E1C) using SIMD operations + // with VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_fft_if->get_outbuf(), d_fft_code_pilot, d_fft_size); + + // Compute the inverse FFT + d_ifft->execute(); + + // Copy the result of the correlation between wiped--off signal and pilot code in + // d_data_correlation. + memcpy(d_pilot_correlation, d_ifft->get_outbuf(), sizeof(gr_complex) * d_fft_size); + + for (uint32_t i = 0; i < d_fft_size; i++) + { + d_correlation_plus[i] = std::complex( + d_data_correlation[i].real() - d_pilot_correlation[i].imag(), + d_data_correlation[i].imag() + d_pilot_correlation[i].real()); + + d_correlation_minus[i] = std::complex( + d_data_correlation[i].real() + d_pilot_correlation[i].imag(), + d_data_correlation[i].imag() - d_pilot_correlation[i].real()); + } + + volk_32fc_magnitude_squared_32f(d_magnitude, d_correlation_plus, d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_plus, d_magnitude, d_fft_size); + magt_plus = d_magnitude[indext_plus] / (fft_normalization_factor * fft_normalization_factor); + + volk_32fc_magnitude_squared_32f(d_magnitude, d_correlation_minus, d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext_minus, d_magnitude, d_fft_size); + magt_minus = d_magnitude[indext_minus] / (fft_normalization_factor * fft_normalization_factor); + + if (magt_plus >= magt_minus) + { + magt = magt_plus; + indext = indext_plus; + } + else + { + magt = magt_minus; + indext = indext_minus; + } + + // 4- record the maximum peak and the associated synchronization parameters + if (d_mag < magt) + { + d_mag = magt; + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; + } + + // Record results to file if required + if (d_dump) + { + std::stringstream filename; + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + filename.str(""); + filename << "../data/test_statistics_" << d_gnss_synchro->System + << "_" << d_gnss_synchro->Signal << "_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + d_dump_file.write(reinterpret_cast(d_ifft->get_outbuf()), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.close(); + } + } + + // 5- Compute the test statistics and compare to the threshold + //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; + d_test_statistics = d_mag / d_input_power; + + // 6- Declare positive or negative acquisition using a message port + if (d_test_statistics > d_threshold) + { + d_state = 2; // Positive acquisition + } + else if (d_well_count == d_max_dwells) + { + d_state = 3; // Negative acquisition + } + + consume_each(1); + + break; + } + + case 2: + { + // 6.1- Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } + + case 3: + { + // 6.2- Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } } - case 2: - { - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - return noutput_items; } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.h index cc34f1abd..85050cc21 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_cccwsr_acquisition_cc.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,12 +37,12 @@ #ifndef GNSS_SDR_PCPS_CCCWSR_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_CCCWSR_ACQUISITION_CC_H_ +#include "gnss_synchro.h" +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" class pcps_cccwsr_acquisition_cc; @@ -50,54 +50,58 @@ class pcps_cccwsr_acquisition_cc; typedef boost::shared_ptr pcps_cccwsr_acquisition_cc_sptr; pcps_cccwsr_acquisition_cc_sptr -pcps_cccwsr_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); +pcps_cccwsr_make_acquisition_cc( + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool dump, + std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition with * Coherent Channel Combining With Sign Recovery scheme. */ -class pcps_cccwsr_acquisition_cc: public gr::block +class pcps_cccwsr_acquisition_cc : public gr::block { private: friend pcps_cccwsr_acquisition_cc_sptr - pcps_cccwsr_make_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); + pcps_cccwsr_make_acquisition_cc(uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int32_t samples_per_ms, int32_t samples_per_code, + bool dump, std::string dump_filename); - pcps_cccwsr_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool dump, std::string dump_filename); + pcps_cccwsr_acquisition_cc(uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int32_t samples_per_ms, int32_t samples_per_code, + bool dump, std::string dump_filename); - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + void calculate_magnitudes(gr_complex* fft_begin, int32_t doppler_shift, + int32_t doppler_offset); - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - unsigned int d_doppler_resolution; + int64_t d_fs_in; + int32_t d_samples_per_ms; + int32_t d_samples_per_code; + uint32_t d_doppler_resolution; float d_threshold; std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint32_t d_doppler_max; + uint32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_max_dwells; + uint32_t d_well_count; + uint32_t d_fft_size; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; + uint32_t d_num_doppler_bins; gr_complex* d_fft_code_data; gr_complex* d_fft_code_pilot; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_mag; float* d_magnitude; @@ -109,107 +113,107 @@ private: float d_test_statistics; std::ofstream d_dump_file; bool d_active; - int d_state; + int32_t d_state; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; public: /*! * \brief Default destructor. */ - ~pcps_cccwsr_acquisition_cc(); + ~pcps_cccwsr_acquisition_cc(); /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + d_gnss_synchro = p_gnss_synchro; + } - /*! + /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() - { - return d_mag; - } + inline uint32_t mag() const + { + return d_mag; + } - /*! + /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init(); - /*! + /*! * \brief Sets local code for CCCWSR acquisition algorithm. * \param data_code - Pointer to the data PRN code. * \param pilot_code - Pointer to the pilot PRN code. */ - void set_local_code(std::complex * code_data, std::complex * code_pilot); + void set_local_code(std::complex* code_data, std::complex* code_pilot); - /*! + /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) - { - d_active = active; - } + inline void set_active(bool active) + { + d_active = active; + } - /*! + /*! * \brief If set to 1, ensures that acquisition starts at the * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int32_t state); - /*! + /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } + inline void set_channel(uint32_t channel) + { + d_channel = channel; + } - /*! + /*! * \brief Set statistics threshold of CCCWSR algorithm. * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } + inline void set_threshold(float threshold) + { + d_threshold = threshold; + } - /*! + /*! * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } + inline void set_doppler_max(uint32_t doppler_max) + { + d_doppler_max = doppler_max; + } - /*! + /*! * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } + inline void set_doppler_step(uint32_t doppler_step) + { + d_doppler_step = doppler_step; + } - /*! + /*! * \brief Coherent Channel Combining With Sign Recovery Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); }; #endif /* GNSS_SDR_PCPS_CCCWSR_ACQUISITION_CC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.cc deleted file mode 100644 index 2cf411d32..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.cc +++ /dev/null @@ -1,479 +0,0 @@ -/*! - * \file pcps_multithread_acquisition_cc.cc - * \brief This class implements a Parallel Code Phase Search Acquisition - * \authors
          - *
        • Javier Arribas, 2011. jarribas(at)cttc.es - *
        • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
        • Marc Molina, 2013. marc.molina.pena@gmail.com - *
        - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "pcps_multithread_acquisition_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI - -using google::LogMessage; - -pcps_multithread_acquisition_cc_sptr pcps_make_multithread_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename) -{ - - return pcps_multithread_acquisition_cc_sptr( - new pcps_multithread_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, bit_transition_flag, dump, dump_filename)); -} - -pcps_multithread_acquisition_cc::pcps_multithread_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename) : - gr::block("pcps_multithread_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) -{ - this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER - d_active = false; - d_state = 0; - d_core_working = false; - d_freq = freq; - d_fs_in = fs_in; - d_samples_per_ms = samples_per_ms; - d_samples_per_code = samples_per_code; - d_sampled_ms = sampled_ms; - d_max_dwells = max_dwells; - d_well_count = 0; - d_doppler_max = doppler_max; - d_fft_size = d_sampled_ms * d_samples_per_ms; - d_mag = 0; - d_input_power = 0.0; - d_num_doppler_bins = 0; - d_bit_transition_flag = bit_transition_flag; - d_in_dwell_count = 0; - - d_in_buffer = new gr_complex*[d_max_dwells]; - - //todo: do something if posix_memalign fails - for (unsigned int i = 0; i < d_max_dwells; i++) - { - d_in_buffer[i] = static_cast(volk_malloc(d_fft_size * sizeof(gr_complex), volk_get_alignment())); - } - d_fft_codes = static_cast(volk_malloc(d_fft_size * sizeof(gr_complex), volk_get_alignment())); - d_magnitude = static_cast(volk_malloc(d_fft_size * sizeof(float), volk_get_alignment())); - - // Direct FFT - d_fft_if = new gr::fft::fft_complex(d_fft_size, true); - - // Inverse FFT - d_ifft = new gr::fft::fft_complex(d_fft_size, false); - - // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; - - d_doppler_resolution = 0; - d_threshold = 0; - d_doppler_step = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; - d_code_phase = 0; - d_doppler_freq = 0; - d_test_statistics = 0; - d_channel = 0; -} - -pcps_multithread_acquisition_cc::~pcps_multithread_acquisition_cc() -{ - if (d_num_doppler_bins > 0) - { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) - { - volk_free(d_grid_doppler_wipeoffs[i]); - } - delete[] d_grid_doppler_wipeoffs; - } - - for (unsigned int i = 0; i < d_max_dwells; i++) - { - volk_free(d_in_buffer[i]); - } - delete[] d_in_buffer; - - volk_free(d_fft_codes); - volk_free(d_magnitude); - - delete d_ifft; - delete d_fft_if; - - if (d_dump) - { - d_dump_file.close(); - } -} - -void pcps_multithread_acquisition_cc::init() -{ - d_gnss_synchro->Flag_valid_acquisition = false; - d_gnss_synchro->Flag_valid_symbol_output = false; - d_gnss_synchro->Flag_valid_pseudorange = false; - d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_mag = 0.0; - d_input_power = 0.0; - - // Count the number of bins - d_num_doppler_bins = 0; - for (int doppler = (int)(-d_doppler_max); - doppler <= (int)d_doppler_max; - doppler += d_doppler_step) - { - d_num_doppler_bins++; - } - - // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_malloc(d_fft_size * sizeof(gr_complex), volk_get_alignment())); - int doppler = -(int)d_doppler_max + d_doppler_step * doppler_index; - float phase_step_rad = static_cast(GPS_TWO_PI) * (d_freq + doppler) / static_cast(d_fs_in); - float _phase[1]; - _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); - } -} - -void pcps_multithread_acquisition_cc::set_local_code(std::complex * code) -{ - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size); - - d_fft_if->execute(); // We need the FFT of local code - - //Conjugate the local code - volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); -} - -void pcps_multithread_acquisition_cc::acquisition_core() -{ - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - float magt = 0.0; - float fft_normalization_factor = (float)d_fft_size * (float)d_fft_size; - gr_complex* in = d_in_buffer[d_well_count]; - unsigned long int samplestamp = d_sample_counter_buffer[d_well_count]; - - d_input_power = 0.0; - d_mag = 0.0; - - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - // 1- Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= (float)d_fft_size; - - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - - doppler = -(int)d_doppler_max + d_doppler_step*doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code reference using SIMD operations with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Search maximum - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude, d_fft_size); - - // Normalize the maximum value to correct the scale factor introduced by FFTW - magt = d_magnitude[indext] / (fft_normalization_factor * fft_normalization_factor); - - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - - // In case that d_bit_transition_flag = true, we compare the potentially - // new maximum test statistics (d_mag/d_input_power) with the value in - // d_test_statistics. When the second dwell is being processed, the value - // of d_mag/d_input_power could be lower than d_test_statistics (i.e, - // the maximum test statistics in the previous dwell is greater than - // current d_mag/d_input_power). Note that d_test_statistics is not - // restarted between consecutive dwells in multidwell operation. - if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = (double)(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = (double)doppler; - d_gnss_synchro->Acq_samplestamp_samples = samplestamp; - - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; - } - } - - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } - - if (!d_bit_transition_flag) - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition - } - } - else - { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else - { - d_state = 3; // Negative acquisition - } - } - } - - d_core_working = false; -} - - - -void pcps_multithread_acquisition_cc::set_state(int state) -{ - d_state = state; - if (d_state == 1) - { - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - d_in_dwell_count = 0; - d_sample_counter_buffer.clear(); - } - else if (d_state == 0) - {} - else - { - LOG(ERROR) << "State can only be set to 0 or 1"; - } -} - - - -int pcps_multithread_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) -{ - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - - switch (d_state) - { - case 0: - { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - d_in_dwell_count = 0; - d_sample_counter_buffer.clear(); - - d_state = 1; - } - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - - break; - } - - case 1: - { - if (d_in_dwell_count < d_max_dwells) - { - // Fill internal buffer with d_max_dwells signal blocks. This step ensures that - // consecutive signal blocks will be processed in multi-dwell operation. This is - // essential when d_bit_transition_flag = true. - unsigned int num_dwells = std::min((int)(d_max_dwells-d_in_dwell_count),ninput_items[0]); - for (unsigned int i = 0; i < num_dwells; i++) - { - memcpy(d_in_buffer[d_in_dwell_count++], (gr_complex*)input_items[i], - sizeof(gr_complex)*d_fft_size); - d_sample_counter += d_fft_size; - d_sample_counter_buffer.push_back(d_sample_counter); - } - - if (ninput_items[0] > (int)num_dwells) - { - d_sample_counter += d_fft_size * (ninput_items[0]-num_dwells); - } - } - else - { - // We already have d_max_dwells consecutive blocks in the internal buffer, - // just skip input blocks. - d_sample_counter += d_fft_size * ninput_items[0]; - } - - // We create a new thread to process next block if the following - // conditions are fulfilled: - // 1. There are new blocks in d_in_buffer that have not been processed yet - // (d_well_count < d_in_dwell_count). - // 2. No other acquisition_core thead is working (!d_core_working). - // 3. d_state==1. We need to check again d_state because it can be modified at any - // moment by the external thread (may have changed since checked in the switch()). - // If the external thread has already declared positive (d_state=2) or negative - // (d_state=3) acquisition, we don't have to process next block!! - if ((d_well_count < d_in_dwell_count) && !d_core_working && d_state==1) - { - d_core_working = true; - boost::thread(&pcps_multithread_acquisition_cc::acquisition_core, this); - } - - break; - } - - case 2: - { - // Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - - consume_each(ninput_items[0]); - - return noutput_items; -} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.h deleted file mode 100644 index 30c10d190..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_multithread_acquisition_cc.h +++ /dev/null @@ -1,241 +0,0 @@ -/*! - * \file pcps_multithread_acquisition_cc.h - * \brief This class implements a Parallel Code Phase Search Acquisition - * - * Acquisition strategy (Kay Borre book + CFAR threshold). - *
          - *
        1. Compute the input signal power estimation - *
        2. Doppler serial search loop - *
        3. Perform the FFT-based circular convolution (parallel time search) - *
        4. Record the maximum peak and the associated synchronization parameters - *
        5. Compute the test statistics and compare to the threshold - *
        6. Declare positive or negative acquisition using a message port - *
        - * - * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkha user, 2007. pp 81-84 - * - * \authors
          - *
        • Javier Arribas, 2011. jarribas(at)cttc.es - *
        • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
        • Marc Molina, 2013. marc.molina.pena@gmail.com - *
        - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_PCPS_MULTITHREAD_ACQUISITION_CC_H_ -#define GNSS_SDR_PCPS_MULTITHREAD_ACQUISITION_CC_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "gnss_synchro.h" - -class pcps_multithread_acquisition_cc; - -typedef boost::shared_ptr pcps_multithread_acquisition_cc_sptr; - -pcps_multithread_acquisition_cc_sptr -pcps_make_multithread_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); - -/*! - * \brief This class implements a Parallel Code Phase Search Acquisition. - * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. - */ -class pcps_multithread_acquisition_cc: public gr::block -{ -private: - friend pcps_multithread_acquisition_cc_sptr - pcps_make_multithread_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); - - - pcps_multithread_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); - - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); - - - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - unsigned int d_doppler_resolution; - float d_threshold; - std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; - gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; - gr_complex* d_fft_codes; - gr::fft::fft_complex* d_fft_if; - gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; - float d_doppler_freq; - float d_mag; - float* d_magnitude; - float d_input_power; - float d_test_statistics; - bool d_bit_transition_flag; - std::ofstream d_dump_file; - bool d_active; - int d_state; - bool d_core_working; - bool d_dump; - unsigned int d_channel; - std::string d_dump_filename; - gr_complex** d_in_buffer; - std::vector d_sample_counter_buffer; - unsigned int d_in_dwell_count; - -public: - /*! - * \brief Default destructor. - */ - ~pcps_multithread_acquisition_cc(); - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to exchange synchronization data between acquisition and tracking blocks. - * \param p_gnss_synchro Satellite information shared by the processing blocks. - */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } - - /*! - * \brief Returns the maximum peak of grid search. - */ - unsigned int mag() - { - return d_mag; - } - - /*! - * \brief Initializes acquisition algorithm. - */ - void init(); - - /*! - * \brief Sets local code for PCPS acquisition algorithm. - * \param code - Pointer to the PRN code. - */ - void set_local_code(std::complex * code); - - /*! - * \brief Starts acquisition algorithm, turning from standby mode to - * active mode - * \param active - bool that activates/deactivates the block. - */ - void set_active(bool active) - { - d_active = active; - } - - /*! - * \brief If set to 1, ensures that acquisition starts at the - * first available sample. - * \param state - int=1 forces start of acquisition - */ - void set_state(int state); - - /*! - * \brief Set acquisition channel unique ID - * \param channel - receiver channel. - */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } - - /*! - * \brief Set statistics threshold of PCPS algorithm. - * \param threshold - Threshold for signal detection (check \ref Navitec2012, - * Algorithm 1, for a definition of this threshold). - */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } - - /*! - * \brief Set maximum Doppler grid search - * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. - */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } - - /*! - * \brief Set Doppler steps for the grid search - * \param doppler_step - Frequency bin of the search grid [Hz]. - */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } - - - /*! - * \brief Parallel Code Phase Search Acquisition signal processing. - */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - void acquisition_core(); -}; - -#endif /* GNSS_SDR_PCPS_MULTITHREAD_ACQUISITION_CC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.cc index b0a17c830..0944b9ed8 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.cc @@ -25,7 +25,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,59 +43,61 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_opencl_acquisition_cc.h" -#include -#include -#include -#include +#include "GPS_L1_CA.h" //GPS_TWO_PI +#include "control_message_factory.h" +#include "opencl/fft_base_kernels.h" +#include "opencl/fft_internal.h" #include #include #include #include -#include "control_message_factory.h" -#include "fft_base_kernels.h" -#include "fft_internal.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI +#include +#include +#include +#include +#include using google::LogMessage; pcps_opencl_acquisition_cc_sptr pcps_make_opencl_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename) + uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename) { - return pcps_opencl_acquisition_cc_sptr( - new pcps_opencl_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms, - samples_per_code, bit_transition_flag, dump, dump_filename)); + new pcps_opencl_acquisition_cc(sampled_ms, max_dwells, doppler_max, fs_in, samples_per_ms, + samples_per_code, bit_transition_flag, dump, std::move(dump_filename))); } + pcps_opencl_acquisition_cc::pcps_opencl_acquisition_cc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename) : - gr::block("pcps_opencl_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int samples_per_ms, + int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename) : gr::block("pcps_opencl_acquisition_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), + gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; d_core_working = false; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -112,51 +114,49 @@ pcps_opencl_acquisition_cc::pcps_opencl_acquisition_cc( d_in_dwell_count = 0; d_cl_fft_batch_size = 1; - d_in_buffer = new gr_complex*[d_max_dwells]; - for (unsigned int i = 0; i < d_max_dwells; i++) + d_in_buffer = new gr_complex *[d_max_dwells]; + for (uint32_t i = 0; i < d_max_dwells; i++) { - d_in_buffer[i] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_in_buffer[i] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); } - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size_pow2 * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_zero_vector = static_cast(volk_gnsssdr_malloc((d_fft_size_pow2 - d_fft_size) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size_pow2 * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_zero_vector = static_cast(volk_gnsssdr_malloc((d_fft_size_pow2 - d_fft_size) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (unsigned int i = 0; i < (d_fft_size_pow2-d_fft_size); i++) + for (uint32_t i = 0; i < (d_fft_size_pow2 - d_fft_size); i++) { - d_zero_vector[i] = gr_complex(0.0,0.0); + d_zero_vector[i] = gr_complex(0.0, 0.0); } d_opencl = init_opencl_environment("math_kernel.cl"); if (d_opencl != 0) - { - // Direct FFT - d_fft_if = new gr::fft::fft_complex(d_fft_size, true); + { + // Direct FFT + d_fft_if = new gr::fft::fft_complex(d_fft_size, true); - // Inverse FFT - d_ifft = new gr::fft::fft_complex(d_fft_size, false); - } + // Inverse FFT + d_ifft = new gr::fft::fft_complex(d_fft_size, false); + } // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; - + d_dump_filename = std::move(dump_filename); } - pcps_opencl_acquisition_cc::~pcps_opencl_acquisition_cc() { if (d_num_doppler_bins > 0) { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) + for (uint32_t i = 0; i < d_num_doppler_bins; i++) { volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); } delete[] d_grid_doppler_wipeoffs; } - for (unsigned int i = 0; i < d_max_dwells; i++) + for (uint32_t i = 0; i < d_max_dwells; i++) { volk_gnsssdr_free(d_in_buffer[i]); } @@ -174,7 +174,7 @@ pcps_opencl_acquisition_cc::~pcps_opencl_acquisition_cc() delete d_cl_buffer_2; delete d_cl_buffer_magnitude; delete d_cl_buffer_fft_codes; - if(d_num_doppler_bins > 0) + if (d_num_doppler_bins > 0) { delete[] d_cl_buffer_grid_doppler_wipeoffs; } @@ -194,20 +194,19 @@ pcps_opencl_acquisition_cc::~pcps_opencl_acquisition_cc() } - -int pcps_opencl_acquisition_cc::init_opencl_environment(std::string kernel_filename) +int pcps_opencl_acquisition_cc::init_opencl_environment(const std::string &kernel_filename) { //get all platforms (drivers) std::vector all_platforms; cl::Platform::get(&all_platforms); - if(all_platforms.size()==0) - { - std::cout << "No OpenCL platforms found. Check OpenCL installation!" << std::endl; - return 1; - } + if (all_platforms.size() == 0) + { + std::cout << "No OpenCL platforms found. Check OpenCL installation!" << std::endl; + return 1; + } - d_cl_platform = all_platforms[0]; //get default platform + d_cl_platform = all_platforms[0]; //get default platform std::cout << "Using platform: " << d_cl_platform.getInfo() << std::endl; @@ -215,11 +214,11 @@ int pcps_opencl_acquisition_cc::init_opencl_environment(std::string kernel_filen std::vector gpu_devices; d_cl_platform.getDevices(CL_DEVICE_TYPE_GPU, &gpu_devices); - if(gpu_devices.size()==0) - { - std::cout << "No GPU devices found. Check OpenCL installation!" << std::endl; - return 2; - } + if (gpu_devices.size() == 0) + { + std::cout << "No GPU devices found. Check OpenCL installation!" << std::endl; + return 2; + } d_cl_device = gpu_devices[0]; @@ -240,64 +239,62 @@ int pcps_opencl_acquisition_cc::init_opencl_environment(std::string kernel_filen cl::Program::Sources sources; - sources.push_back({kernel_code.c_str(),kernel_code.length()}); + sources.push_back({kernel_code.c_str(), kernel_code.length()}); - cl::Program program(context,sources); - if(program.build(device)!=CL_SUCCESS) - { - std::cout << " Error building: " - << program.getBuildInfo(device[0]) - << std::endl; - return 3; - } + cl::Program program(context, sources); + if (program.build(device) != CL_SUCCESS) + { + std::cout << " Error building: " + << program.getBuildInfo(device[0]) + << std::endl; + return 3; + } d_cl_program = program; // create buffers on the device - d_cl_buffer_in = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex)*d_fft_size); - d_cl_buffer_fft_codes = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex)*d_fft_size_pow2); - d_cl_buffer_1 = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex)*d_fft_size_pow2); - d_cl_buffer_2 = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex)*d_fft_size_pow2); - d_cl_buffer_magnitude = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(float)*d_fft_size); + d_cl_buffer_in = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex) * d_fft_size); + d_cl_buffer_fft_codes = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex) * d_fft_size_pow2); + d_cl_buffer_1 = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex) * d_fft_size_pow2); + d_cl_buffer_2 = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex) * d_fft_size_pow2); + d_cl_buffer_magnitude = new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(float) * d_fft_size); //create queue to which we will push commands for the device. - d_cl_queue = new cl::CommandQueue(d_cl_context,d_cl_device); + d_cl_queue = new cl::CommandQueue(d_cl_context, d_cl_device); //create FFT plan cl_int err; clFFT_Dim3 dim = {d_fft_size_pow2, 1, 1}; d_cl_fft_plan = clFFT_CreatePlan(d_cl_context(), dim, clFFT_1D, - clFFT_InterleavedComplexFormat, &err); + clFFT_InterleavedComplexFormat, &err); if (err != 0) - { - delete d_cl_queue; - delete d_cl_buffer_in; - delete d_cl_buffer_1; - delete d_cl_buffer_2; - delete d_cl_buffer_magnitude; - delete d_cl_buffer_fft_codes; + { + delete d_cl_queue; + delete d_cl_buffer_in; + delete d_cl_buffer_1; + delete d_cl_buffer_2; + delete d_cl_buffer_magnitude; + delete d_cl_buffer_fft_codes; - std::cout << "Error creating OpenCL FFT plan." << std::endl; - return 4; - } + std::cout << "Error creating OpenCL FFT plan." << std::endl; + return 4; + } return 0; } - void pcps_opencl_acquisition_cc::init() { d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_mag = 0.0; d_input_power = 0.0; @@ -306,82 +303,83 @@ void pcps_opencl_acquisition_cc::init() for (int doppler = static_cast(-d_doppler_max); doppler <= static_cast(d_doppler_max); doppler += d_doppler_step) - { - d_num_doppler_bins++; - } - - // Create the carrier Doppler wipeoff signals - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - if (d_opencl == 0) { - d_cl_buffer_grid_doppler_wipeoffs = new cl::Buffer*[d_num_doppler_bins]; + d_num_doppler_bins++; } - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + // Create the carrier Doppler wipeoff signals + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_bins]; + if (d_opencl == 0) { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_cl_buffer_grid_doppler_wipeoffs = new cl::Buffer *[d_num_doppler_bins]; + } + + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = static_cast(GPS_TWO_PI) * (d_freq + doppler) / static_cast(d_fs_in); + float phase_step_rad = static_cast(GPS_TWO_PI) * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); if (d_opencl == 0) { d_cl_buffer_grid_doppler_wipeoffs[doppler_index] = - new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex)*d_fft_size); + new cl::Buffer(d_cl_context, CL_MEM_READ_WRITE, sizeof(gr_complex) * d_fft_size); d_cl_queue->enqueueWriteBuffer(*(d_cl_buffer_grid_doppler_wipeoffs[doppler_index]), - CL_TRUE, 0, sizeof(gr_complex)*d_fft_size, - d_grid_doppler_wipeoffs[doppler_index]); + CL_TRUE, 0, sizeof(gr_complex) * d_fft_size, + d_grid_doppler_wipeoffs[doppler_index]); } } // zero padding in buffer_1 (FFT input) if (d_opencl == 0) - { - d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_1, CL_TRUE, sizeof(gr_complex)*d_fft_size, - sizeof(gr_complex)*(d_fft_size_pow2 - d_fft_size), d_zero_vector); - } + { + d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_1, CL_TRUE, sizeof(gr_complex) * d_fft_size, + sizeof(gr_complex) * (d_fft_size_pow2 - d_fft_size), d_zero_vector); + } } -void pcps_opencl_acquisition_cc::set_local_code(std::complex * code) + +void pcps_opencl_acquisition_cc::set_local_code(std::complex *code) { - if(d_opencl == 0) + if (d_opencl == 0) { d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_2, CL_TRUE, 0, - sizeof(gr_complex)*d_fft_size, code); + sizeof(gr_complex) * d_fft_size, code); - d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_2, CL_TRUE, sizeof(gr_complex)*d_fft_size, - sizeof(gr_complex)*(d_fft_size_pow2 - 2*d_fft_size), - d_zero_vector); + d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_2, CL_TRUE, sizeof(gr_complex) * d_fft_size, + sizeof(gr_complex) * (d_fft_size_pow2 - 2 * d_fft_size), + d_zero_vector); - d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_2, CL_TRUE, sizeof(gr_complex) - *(d_fft_size_pow2 - d_fft_size), - sizeof(gr_complex)*d_fft_size, code); + d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_2, CL_TRUE, sizeof(gr_complex) * (d_fft_size_pow2 - d_fft_size), + sizeof(gr_complex) * d_fft_size, code); clFFT_ExecuteInterleaved((*d_cl_queue)(), d_cl_fft_plan, d_cl_fft_batch_size, - clFFT_Forward, (*d_cl_buffer_2)(), (*d_cl_buffer_2)(), - 0, NULL, NULL); + clFFT_Forward, (*d_cl_buffer_2)(), (*d_cl_buffer_2)(), + 0, nullptr, nullptr); //Conjucate the local code cl::Kernel kernel = cl::Kernel(d_cl_program, "conj_vector"); - kernel.setArg(0, *d_cl_buffer_2); //input - kernel.setArg(1, *d_cl_buffer_fft_codes); //output + kernel.setArg(0, *d_cl_buffer_2); //input + kernel.setArg(1, *d_cl_buffer_fft_codes); //output d_cl_queue->enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(d_fft_size_pow2), cl::NullRange); } else { - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); } } + void pcps_opencl_acquisition_cc::acquisition_core_volk() { // initialize acquisition algorithm @@ -389,8 +387,8 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() uint32_t indext = 0; float magt = 0.0; float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - gr_complex* in = d_in_buffer[d_well_count]; - unsigned long int samplestamp = d_sample_counter_buffer[d_well_count]; + gr_complex *in = d_in_buffer[d_well_count]; + uint64_t samplestamp = d_sample_counter_buffer[d_well_count]; d_input_power = 0.0; d_mag = 0.0; @@ -398,10 +396,10 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() d_well_count++; DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; // 1- Compute the input signal power estimation volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); @@ -409,13 +407,13 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() d_input_power /= static_cast(d_fft_size); // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { // doppler search steps doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + d_grid_doppler_wipeoffs[doppler_index], d_fft_size); // 3- Perform the FFT-based convolution (parallel time search) // Compute the FFT of the carrier wiped--off incoming signal @@ -424,7 +422,7 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() // Multiply carrier wiped--off, Fourier transformed incoming signal // with the local FFT'd code reference using SIMD operations with VOLK library volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); + d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); // compute the inverse FFT d_ifft->execute(); @@ -449,28 +447,29 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() // current d_mag/d_input_power). Note that d_test_statistics is not // restarted between consecutive dwells in multidwell operation. if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = samplestamp; + { + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = samplestamp; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; - } + // 5- Compute the test statistics and compare to the threshold + //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; + d_test_statistics = d_mag / d_input_power; + } } // Record results to file if required if (d_dump) { std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write filename.str(""); filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + << "_" << d_gnss_synchro->Signal << "_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.write(reinterpret_cast(d_ifft->get_outbuf()), n); //write directly |abs(x)|^2 in this Doppler bin? d_dump_file.close(); } } @@ -479,24 +478,24 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() { if (d_test_statistics > d_threshold) { - d_state = 2; // Positive acquisition + d_state = 2; // Positive acquisition } else if (d_well_count == d_max_dwells) { - d_state = 3; // Negative acquisition + d_state = 3; // Negative acquisition } } else { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 + if (d_well_count == d_max_dwells) // d_max_dwells = 2 { if (d_test_statistics > d_threshold) { - d_state = 2; // Positive acquisition + d_state = 2; // Positive acquisition } else { - d_state = 3; // Negative acquisition + d_state = 3; // Negative acquisition } } } @@ -504,36 +503,37 @@ void pcps_opencl_acquisition_cc::acquisition_core_volk() d_core_working = false; } + void pcps_opencl_acquisition_cc::acquisition_core_opencl() { // initialize acquisition algorithm int doppler; uint32_t indext = 0; float magt = 0.0; - float fft_normalization_factor = (static_cast(d_fft_size_pow2) * static_cast(d_fft_size)); //This works, but I am not sure why. - gr_complex* in = d_in_buffer[d_well_count]; - unsigned long int samplestamp = d_sample_counter_buffer[d_well_count]; + float fft_normalization_factor = (static_cast(d_fft_size_pow2) * static_cast(d_fft_size)); //This works, but I am not sure why. + gr_complex *in = d_in_buffer[d_well_count]; + uint64_t samplestamp = d_sample_counter_buffer[d_well_count]; d_input_power = 0.0; d_mag = 0.0; // write input vector in buffer of OpenCL device - d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_in, CL_TRUE, 0, sizeof(gr_complex)*d_fft_size, in); + d_cl_queue->enqueueWriteBuffer(*d_cl_buffer_in, CL_TRUE, 0, sizeof(gr_complex) * d_fft_size, in); d_well_count++; -// struct timeval tv; -// long long int begin = 0; -// long long int end = 0; + // struct timeval tv; + // long long int begin = 0; + // long long int end = 0; -// gettimeofday(&tv, NULL); -// begin = tv.tv_sec *1e6 + tv.tv_usec; + // gettimeofday(&tv, NULL); + // begin = tv.tv_sec *1e6 + tv.tv_usec; DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; // 1- Compute the input signal power estimation volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); @@ -543,53 +543,53 @@ void pcps_opencl_acquisition_cc::acquisition_core_opencl() cl::Kernel kernel; // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { // doppler search steps - doppler = -static_cast(d_doppler_max) + d_doppler_step*doppler_index; + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; //Multiply input signal with doppler wipe-off kernel = cl::Kernel(d_cl_program, "mult_vectors"); - kernel.setArg(0, *d_cl_buffer_in); //input 1 - kernel.setArg(1, *d_cl_buffer_grid_doppler_wipeoffs[doppler_index]); //input 2 - kernel.setArg(2, *d_cl_buffer_1); //output - d_cl_queue->enqueueNDRangeKernel(kernel,cl::NullRange, cl::NDRange(d_fft_size), - cl::NullRange); + kernel.setArg(0, *d_cl_buffer_in); //input 1 + kernel.setArg(1, *d_cl_buffer_grid_doppler_wipeoffs[doppler_index]); //input 2 + kernel.setArg(2, *d_cl_buffer_1); //output + d_cl_queue->enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(d_fft_size), + cl::NullRange); // In the previous operation, we store the result in the first d_fft_size positions // of d_cl_buffer_1. The rest d_fft_size_pow2-d_fft_size already have zeros // (zero-padding is made in init() for optimization purposes). clFFT_ExecuteInterleaved((*d_cl_queue)(), d_cl_fft_plan, d_cl_fft_batch_size, - clFFT_Forward,(*d_cl_buffer_1)(), (*d_cl_buffer_2)(), - 0, NULL, NULL); + clFFT_Forward, (*d_cl_buffer_1)(), (*d_cl_buffer_2)(), + 0, nullptr, nullptr); // Multiply carrier wiped--off, Fourier transformed incoming signal // with the local FFT'd code reference kernel = cl::Kernel(d_cl_program, "mult_vectors"); - kernel.setArg(0, *d_cl_buffer_2); //input 1 - kernel.setArg(1, *d_cl_buffer_fft_codes); //input 2 - kernel.setArg(2, *d_cl_buffer_2); //output + kernel.setArg(0, *d_cl_buffer_2); //input 1 + kernel.setArg(1, *d_cl_buffer_fft_codes); //input 2 + kernel.setArg(2, *d_cl_buffer_2); //output d_cl_queue->enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(d_fft_size_pow2), - cl::NullRange); + cl::NullRange); // compute the inverse FFT clFFT_ExecuteInterleaved((*d_cl_queue)(), d_cl_fft_plan, d_cl_fft_batch_size, - clFFT_Inverse, (*d_cl_buffer_2)(), (*d_cl_buffer_2)(), - 0, NULL, NULL); + clFFT_Inverse, (*d_cl_buffer_2)(), (*d_cl_buffer_2)(), + 0, nullptr, nullptr); // Compute magnitude kernel = cl::Kernel(d_cl_program, "magnitude_squared"); - kernel.setArg(0, *d_cl_buffer_2); //input 1 - kernel.setArg(1, *d_cl_buffer_magnitude); //output + kernel.setArg(0, *d_cl_buffer_2); //input 1 + kernel.setArg(1, *d_cl_buffer_magnitude); //output d_cl_queue->enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(d_fft_size), - cl::NullRange); + cl::NullRange); // This is the only function that blocks this thread until all previously enqueued // OpenCL commands are completed. d_cl_queue->enqueueReadBuffer(*d_cl_buffer_magnitude, CL_TRUE, 0, - sizeof(float)*d_fft_size,d_magnitude); + sizeof(float) * d_fft_size, d_magnitude); // Search maximum // @TODO: find an efficient way to search the maximum with OpenCL in the GPU. @@ -611,58 +611,59 @@ void pcps_opencl_acquisition_cc::acquisition_core_opencl() // current d_mag/d_input_power). Note that d_test_statistics is not // restarted between consecutive dwells in multidwell operation. if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = samplestamp; + { + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = samplestamp; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; - // 5- Compute the test statistics and compare to the threshold - //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; - d_test_statistics = d_mag / d_input_power; - } + // 5- Compute the test statistics and compare to the threshold + //d_test_statistics = 2 * d_fft_size * d_mag / d_input_power; + d_test_statistics = d_mag / d_input_power; + } } // Record results to file if required if (d_dump) { std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write filename.str(""); filename << "../data/test_statistics_" << d_gnss_synchro->System << "_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.write(reinterpret_cast(d_ifft->get_outbuf()), n); //write directly |abs(x)|^2 in this Doppler bin? d_dump_file.close(); } } -// gettimeofday(&tv, NULL); -// end = tv.tv_sec *1e6 + tv.tv_usec; -// std::cout << "Acq time = " << (end-begin) << " us" << std::endl; + // gettimeofday(&tv, NULL); + // end = tv.tv_sec *1e6 + tv.tv_usec; + // std::cout << "Acq time = " << (end-begin) << " us" << std::endl; if (!d_bit_transition_flag) { if (d_test_statistics > d_threshold) { - d_state = 2; // Positive acquisition + d_state = 2; // Positive acquisition } else if (d_well_count == d_max_dwells) { - d_state = 3; // Negative acquisition + d_state = 3; // Negative acquisition } } else { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 + if (d_well_count == d_max_dwells) // d_max_dwells = 2 { if (d_test_statistics > d_threshold) { - d_state = 2; // Positive acquisition + d_state = 2; // Positive acquisition } else { - d_state = 3; // Negative acquisition + d_state = 3; // Negative acquisition } } } @@ -678,7 +679,8 @@ void pcps_opencl_acquisition_cc::set_state(int state) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_well_count = 0; d_mag = 0.0; d_input_power = 0.0; @@ -687,145 +689,148 @@ void pcps_opencl_acquisition_cc::set_state(int state) d_sample_counter_buffer.clear(); } else if (d_state == 0) - {} + { + } else { LOG(ERROR) << "State can only be set to 0 or 1"; } } + int pcps_opencl_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL switch (d_state) - { - case 0: { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - d_in_dwell_count = 0; - d_sample_counter_buffer.clear(); + case 0: + { + if (d_active) + { + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_in_dwell_count = 0; + d_sample_counter_buffer.clear(); - d_state = 1; - } + d_state = 1; + } - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter - break; + break; + } + + case 1: + { + if (d_in_dwell_count < d_max_dwells) + { + // Fill internal buffer with d_max_dwells signal blocks. This step ensures that + // consecutive signal blocks will be processed in multi-dwell operation. This is + // essential when d_bit_transition_flag = true. + uint32_t num_dwells = std::min(static_cast(d_max_dwells - d_in_dwell_count), ninput_items[0]); + for (uint32_t i = 0; i < num_dwells; i++) + { + memcpy(d_in_buffer[d_in_dwell_count++], static_cast(input_items[i]), + sizeof(gr_complex) * d_fft_size); + d_sample_counter += static_cast(d_fft_size); + d_sample_counter_buffer.push_back(d_sample_counter); + } + + if (ninput_items[0] > static_cast(num_dwells)) + { + d_sample_counter += static_cast(d_fft_size * (ninput_items[0] - num_dwells)); + } + } + else + { + // We already have d_max_dwells consecutive blocks in the internal buffer, + // just skip input blocks. + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); + } + + // We create a new thread to process next block if the following + // conditions are fulfilled: + // 1. There are new blocks in d_in_buffer that have not been processed yet + // (d_well_count < d_in_dwell_count). + // 2. No other acquisition_core thead is working (!d_core_working). + // 3. d_state==1. We need to check again d_state because it can be modified at any + // moment by the external thread (may have changed since checked in the switch()). + // If the external thread has already declared positive (d_state=2) or negative + // (d_state=3) acquisition, we don't have to process next block!! + if ((d_well_count < d_in_dwell_count) && !d_core_working && d_state == 1) + { + d_core_working = true; + if (d_opencl == 0) + { // Use OpenCL implementation + boost::thread(&pcps_opencl_acquisition_cc::acquisition_core_opencl, this); + } + else + { // Use Volk implementation + boost::thread(&pcps_opencl_acquisition_cc::acquisition_core_volk, this); + } + } + + break; + } + + case 2: + { + // Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } + + case 3: + { + // Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } } - case 1: - { - if (d_in_dwell_count < d_max_dwells) - { - // Fill internal buffer with d_max_dwells signal blocks. This step ensures that - // consecutive signal blocks will be processed in multi-dwell operation. This is - // essential when d_bit_transition_flag = true. - unsigned int num_dwells = std::min(static_cast(d_max_dwells-d_in_dwell_count), ninput_items[0]); - for (unsigned int i = 0; i < num_dwells; i++) - { - memcpy(d_in_buffer[d_in_dwell_count++], (gr_complex*)input_items[i], - sizeof(gr_complex)*d_fft_size); - d_sample_counter += d_fft_size; - d_sample_counter_buffer.push_back(d_sample_counter); - } - - if (ninput_items[0] > static_cast(num_dwells)) - { - d_sample_counter += d_fft_size * (ninput_items[0] - num_dwells); - } - } - else - { - // We already have d_max_dwells consecutive blocks in the internal buffer, - // just skip input blocks. - d_sample_counter += d_fft_size * ninput_items[0]; - } - - // We create a new thread to process next block if the following - // conditions are fulfilled: - // 1. There are new blocks in d_in_buffer that have not been processed yet - // (d_well_count < d_in_dwell_count). - // 2. No other acquisition_core thead is working (!d_core_working). - // 3. d_state==1. We need to check again d_state because it can be modified at any - // moment by the external thread (may have changed since checked in the switch()). - // If the external thread has already declared positive (d_state=2) or negative - // (d_state=3) acquisition, we don't have to process next block!! - if ((d_well_count < d_in_dwell_count) && !d_core_working && d_state == 1) - { - d_core_working = true; - if (d_opencl == 0) - { // Use OpenCL implementation - boost::thread(&pcps_opencl_acquisition_cc::acquisition_core_opencl, this); - } - else - { // Use Volk implementation - boost::thread(&pcps_opencl_acquisition_cc::acquisition_core_volk, this); - } - } - - break; - } - - case 2: - { - // Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - consume_each(ninput_items[0]); return noutput_items; diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.h index 33559cb3b..20b53d082 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_opencl_acquisition_cc.h @@ -25,7 +25,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,7 +43,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -51,19 +51,20 @@ #ifndef GNSS_SDR_PCPS_OPENCL_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_OPENCL_ACQUISITION_CC_H_ +#include "gnss_synchro.h" +#include "opencl/fft_internal.h" +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include "fft_internal.h" -#include "gnss_synchro.h" #ifdef __APPLE__ - #include "cl.hpp" +#include "opencl/cl.hpp" #else - #include +#include #endif class pcps_opencl_acquisition_cc; @@ -71,12 +72,12 @@ class pcps_opencl_acquisition_cc; typedef boost::shared_ptr pcps_opencl_acquisition_cc_sptr; pcps_opencl_acquisition_cc_sptr -pcps_make_opencl_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); +pcps_make_opencl_acquisition_cc(uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition. @@ -84,52 +85,51 @@ pcps_make_opencl_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", * Algorithm 1, for a pseudocode description of this implementation. */ -class pcps_opencl_acquisition_cc: public gr::block +class pcps_opencl_acquisition_cc : public gr::block { private: friend pcps_opencl_acquisition_cc_sptr - pcps_make_opencl_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); + pcps_make_opencl_acquisition_cc(uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); - pcps_opencl_acquisition_cc(unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); + pcps_opencl_acquisition_cc(uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int samples_per_ms, int samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + int doppler_offset); - int init_opencl_environment(std::string kernel_filename); + int init_opencl_environment(const std::string& kernel_filename); - long d_fs_in; - long d_freq; + int64_t d_fs_in; int d_samples_per_ms; int d_samples_per_code; - unsigned int d_doppler_resolution; + uint32_t d_doppler_resolution; float d_threshold; std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned int d_fft_size_pow2; + uint32_t d_doppler_max; + uint32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_max_dwells; + uint32_t d_well_count; + uint32_t d_fft_size; + uint32_t d_fft_size_pow2; int* d_max_doppler_indexs; - unsigned long int d_sample_counter; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; + uint32_t d_num_doppler_bins; gr_complex* d_fft_codes; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_mag; float* d_magnitude; @@ -141,12 +141,12 @@ private: int d_state; bool d_core_working; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; gr_complex* d_zero_vector; gr_complex** d_in_buffer; - std::vector d_sample_counter_buffer; - unsigned int d_in_dwell_count; + std::vector d_sample_counter_buffer; + uint32_t d_in_dwell_count; cl::Platform d_cl_platform; cl::Device d_cl_device; @@ -168,101 +168,101 @@ public: /*! * \brief Default destructor. */ - ~pcps_opencl_acquisition_cc(); + ~pcps_opencl_acquisition_cc(); - /*! + /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + d_gnss_synchro = p_gnss_synchro; + } - /*! + /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() - { - return d_mag; - } + inline uint32_t mag() const + { + return d_mag; + } - /*! + /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init(); - /*! + /*! * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); - /*! + /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) - { - d_active = active; - } + inline void set_active(bool active) + { + d_active = active; + } - /*! + /*! * \brief If set to 1, ensures that acquisition starts at the * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int state); - /*! + /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } + inline void set_channel(uint32_t channel) + { + d_channel = channel; + } - /*! + /*! * \brief Set statistics threshold of PCPS algorithm. * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } + inline void set_threshold(float threshold) + { + d_threshold = threshold; + } - /*! + /*! * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } + inline void set_doppler_max(uint32_t doppler_max) + { + d_doppler_max = doppler_max; + } - /*! + /*! * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } + inline void set_doppler_step(uint32_t doppler_step) + { + d_doppler_step = doppler_step; + } - /*! + /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); - void acquisition_core_volk(); + void acquisition_core_volk(); - void acquisition_core_opencl(); + void acquisition_core_opencl(); }; #endif diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.cc index 1d5bd8566..11c13a979 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,60 +23,63 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_quicksync_acquisition_cc.h" -#include -#include -#include +#include "GPS_L1_CA.h" +#include "control_message_factory.h" #include +#include #include #include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" +#include +#include +#include using google::LogMessage; pcps_quicksync_acquisition_cc_sptr pcps_quicksync_make_acquisition_cc( - unsigned int folding_factor, - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename) + uint32_t folding_factor, + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename) { return pcps_quicksync_acquisition_cc_sptr( - new pcps_quicksync_acquisition_cc( - folding_factor, - sampled_ms, max_dwells, doppler_max, - freq, fs_in, samples_per_ms, - samples_per_code, - bit_transition_flag, - dump, dump_filename)); + new pcps_quicksync_acquisition_cc( + folding_factor, + sampled_ms, max_dwells, doppler_max, + fs_in, samples_per_ms, + samples_per_code, + bit_transition_flag, + dump, std::move(dump_filename))); } pcps_quicksync_acquisition_cc::pcps_quicksync_acquisition_cc( - unsigned int folding_factor, - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, std::string dump_filename): - gr::block("pcps_quicksync_acquisition_cc", - gr::io_signature::make(1, 1, (sizeof(gr_complex)*sampled_ms * samples_per_ms )), - gr::io_signature::make(0, 0, (sizeof(gr_complex)*sampled_ms * samples_per_ms ))) + uint32_t folding_factor, + uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int32_t samples_per_ms, int32_t samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename) : gr::block("pcps_quicksync_acquisition_cc", + gr::io_signature::make(1, 1, (sizeof(gr_complex) * sampled_ms * samples_per_ms)), + gr::io_signature::make(0, 0, (sizeof(gr_complex) * sampled_ms * samples_per_ms))) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -97,7 +100,7 @@ pcps_quicksync_acquisition_cc::pcps_quicksync_acquisition_cc( d_magnitude = static_cast(volk_gnsssdr_malloc(d_samples_per_code * d_folding_factor * sizeof(float), volk_gnsssdr_get_alignment())); d_magnitude_folded = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - d_possible_delay = new unsigned int[d_folding_factor]; + d_possible_delay = new uint32_t[d_folding_factor]; d_corr_output_f = new float[d_folding_factor]; /*Create the d_code signal , which would store the values of the code in its @@ -111,18 +114,18 @@ pcps_quicksync_acquisition_cc::pcps_quicksync_acquisition_cc( // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); - d_corr_acumulator = 0; - d_signal_folded = 0; + d_corr_acumulator = nullptr; + d_signal_folded = nullptr; d_code_folded = new gr_complex[d_fft_size](); d_noise_floor_power = 0; d_doppler_resolution = 0; d_threshold = 0; d_doppler_step = 0; - d_grid_doppler_wipeoffs = 0; - d_fft_if2 = 0; - d_gnss_synchro = 0; + d_grid_doppler_wipeoffs = nullptr; + d_fft_if2 = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; @@ -138,7 +141,7 @@ pcps_quicksync_acquisition_cc::~pcps_quicksync_acquisition_cc() //DLOG(INFO) << "START DESTROYER"; if (d_num_doppler_bins > 0) { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) + for (uint32_t i = 0; i < d_num_doppler_bins; i++) { volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); } @@ -176,18 +179,17 @@ void pcps_quicksync_acquisition_cc::set_local_code(std::complex* code) /*perform folding of the code by the factorial factor parameter. Notice that folding of the code in the time stage would result in a downsampled spectrum in the frequency domain after applying the fftw operation*/ - for (unsigned int i = 0; i < d_folding_factor; i++) + for (uint32_t i = 0; i < d_folding_factor; i++) { - std::transform ((code + i * d_fft_size), (code + ((i + 1) * d_fft_size)) , - d_fft_if->get_inbuf(), d_fft_if->get_inbuf(), - std::plus()); + std::transform((code + i * d_fft_size), (code + ((i + 1) * d_fft_size)), + d_fft_if->get_inbuf(), d_fft_if->get_inbuf(), + std::plus()); } - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); - } @@ -197,66 +199,68 @@ void pcps_quicksync_acquisition_cc::init() d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; //DLOG(INFO) << "START init"; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_mag = 0.0; d_input_power = 0.0; - - if(d_doppler_step == 0) d_doppler_step = 250; + + if (d_doppler_step == 0) d_doppler_step = 250; // Count the number of bins d_num_doppler_bins = 0; - for (int doppler = static_cast(-d_doppler_max); - doppler <= static_cast(d_doppler_max); - doppler += d_doppler_step) + for (auto doppler = static_cast(-d_doppler_max); + doppler <= static_cast(d_doppler_max); + doppler += d_doppler_step) { d_num_doppler_bins++; } // Create the carrier Doppler wipeoff signals d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_samples_per_code * d_folding_factor * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + float phase_step_rad = GPS_TWO_PI * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_samples_per_code * d_folding_factor); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_samples_per_code * d_folding_factor); } // DLOG(INFO) << "end init"; } -void pcps_quicksync_acquisition_cc::set_state(int state) - { - d_state = state; - if (d_state == 1) - { - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; - d_active = 1; - } - else if (d_state == 0) - {} - else - { - LOG(ERROR) << "State can only be set to 0 or 1"; - } - } +void pcps_quicksync_acquisition_cc::set_state(int32_t state) +{ + d_state = state; + if (d_state == 1) + { + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_active = true; + } + else if (d_state == 0) + { + } + else + { + LOG(ERROR) << "State can only be set to 0 or 1"; + } +} int pcps_quicksync_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) { /* * By J.Arribas, L.Esteve and M.Molina @@ -269,316 +273,314 @@ int pcps_quicksync_acquisition_cc::general_work(int noutput_items, * 6. Declare positive or negative acquisition using a message queue */ //DLOG(INFO) << "START GENERAL WORK"; - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int32_t acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL //std::cout<<"general_work in quicksync gnuradio block"<Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; + case 0: + { + //DLOG(INFO) << "START CASE 0"; + if (d_active) + { + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; - d_state = 1; - } + d_state = 1; + } - d_sample_counter += d_sampled_ms * d_samples_per_ms * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - //DLOG(INFO) << "END CASE 0"; - break; - } + d_sample_counter += static_cast(d_sampled_ms * d_samples_per_ms * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + //DLOG(INFO) << "END CASE 0"; + break; + } - case 1: - { - /* initialize acquisition implementing the QuickSync algorithm*/ - //DLOG(INFO) << "START CASE 1"; - int doppler; - uint32_t indext = 0; - float magt = 0.0; - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer + case 1: + { + /* initialize acquisition implementing the QuickSync algorithm*/ + //DLOG(INFO) << "START CASE 1"; + int32_t doppler; + uint32_t indext = 0; + float magt = 0.0; + const auto* in = reinterpret_cast(input_items[0]); //Get the input samples pointer - gr_complex* in_temp = static_cast(volk_gnsssdr_malloc(d_samples_per_code * d_folding_factor * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - gr_complex* in_temp_folded = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + auto* in_temp = static_cast(volk_gnsssdr_malloc(d_samples_per_code * d_folding_factor * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + auto* in_temp_folded = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - /*Create a signal to store a signal of size 1ms, to perform correlation + /*Create a signal to store a signal of size 1ms, to perform correlation in time. No folding on this data is required*/ - gr_complex* in_1code = static_cast(volk_gnsssdr_malloc(d_samples_per_code * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + auto* in_1code = static_cast(volk_gnsssdr_malloc(d_samples_per_code * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - /*Stores the values of the correlation output between the local code + /*Stores the values of the correlation output between the local code and the signal with doppler shift corrected */ - gr_complex* corr_output = static_cast(volk_gnsssdr_malloc(d_samples_per_code * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + auto* corr_output = static_cast(volk_gnsssdr_malloc(d_samples_per_code * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - /*Stores a copy of the folded version of the signal.This is used for - the FFT operations in future steps of excecution*/ - // gr_complex in_folded[d_fft_size]; - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + /*Stores a copy of the folded version of the signal.This is used for + the FFT operations in future steps of execution*/ + // gr_complex in_folded[d_fft_size]; + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - d_input_power = 0.0; - d_mag = 0.0; - d_test_statistics = 0.0; - d_noise_floor_power = 0.0; + d_input_power = 0.0; + d_mag = 0.0; + d_test_statistics = 0.0; + d_noise_floor_power = 0.0; - d_sample_counter += d_sampled_ms * d_samples_per_ms; // sample counter + d_sample_counter += static_cast(d_sampled_ms * d_samples_per_ms); // sample counter - d_well_count++; + d_well_count++; - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " - << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,algorithm: pcps_quicksync_acquisition" - << " ,folding factor: " << d_folding_factor - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step << ", Signal Size: " - << d_samples_per_code * d_folding_factor; + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " + << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,algorithm: pcps_quicksync_acquisition" + << " ,folding factor: " << d_folding_factor + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step << ", Signal Size: " + << d_samples_per_code * d_folding_factor; - /* 1- Compute the input signal power estimation. This operation is + /* 1- Compute the input signal power estimation. This operation is being performed in a signal of size nxp */ - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_samples_per_code * d_folding_factor); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_samples_per_code * d_folding_factor); - d_input_power /= static_cast(d_samples_per_code * d_folding_factor); + volk_32fc_magnitude_squared_32f(d_magnitude, in, d_samples_per_code * d_folding_factor); + volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_samples_per_code * d_folding_factor); + d_input_power /= static_cast(d_samples_per_code * d_folding_factor); - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - /*Ensure that the signal is going to start with all samples + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + /*Ensure that the signal is going to start with all samples at zero. This is done to avoid over acumulation when performing the folding process to be stored in d_fft_if->get_inbuf()*/ - d_signal_folded = new gr_complex[d_fft_size](); - memcpy( d_fft_if->get_inbuf(), d_signal_folded, sizeof(gr_complex) * (d_fft_size)); + d_signal_folded = new gr_complex[d_fft_size](); + memcpy(d_fft_if->get_inbuf(), d_signal_folded, sizeof(gr_complex) * (d_fft_size)); - /*Doppler search steps and then multiplication of the incoming + /*Doppler search steps and then multiplication of the incoming signal with the doppler wipeoffs to eliminate frequency offset */ - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - /*Perform multiplication of the incoming signal with the + /*Perform multiplication of the incoming signal with the complex exponential vector. This removes the frequency doppler shift offset*/ - volk_32fc_x2_multiply_32fc(in_temp, in, + volk_32fc_x2_multiply_32fc(in_temp, in, d_grid_doppler_wipeoffs[doppler_index], d_samples_per_code * d_folding_factor); - /*Perform folding of the carrier wiped-off incoming signal. Since + /*Perform folding of the carrier wiped-off incoming signal. Since superlinear method is being used the folding factor in the incoming raw data signal is of d_folding_factor^2*/ - for ( int i = 0; i < static_cast(d_folding_factor * d_folding_factor); i++) - { - std::transform ((in_temp + i * d_fft_size), - (in_temp + ((i + 1) * d_fft_size)) , + for (int32_t i = 0; i < static_cast(d_folding_factor * d_folding_factor); i++) + { + std::transform((in_temp + i * d_fft_size), + (in_temp + ((i + 1) * d_fft_size)), d_fft_if->get_inbuf(), d_fft_if->get_inbuf(), std::plus()); - } + } - /* 3- Perform the FFT-based convolution (parallel time search) + /* 3- Perform the FFT-based convolution (parallel time search) Compute the FFT of the carrier wiped--off incoming signal*/ - d_fft_if->execute(); + d_fft_if->execute(); - /*Multiply carrier wiped--off, Fourier transformed incoming + /*Multiply carrier wiped--off, Fourier transformed incoming signal with the local FFT'd code reference using SIMD operations with VOLK library*/ - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); - /* compute the inverse FFT of the aliased signal*/ - d_ifft->execute(); + /* compute the inverse FFT of the aliased signal*/ + d_ifft->execute(); - /* Compute the magnitude and get the maximum value with its + /* Compute the magnitude and get the maximum value with its index position*/ - volk_32fc_magnitude_squared_32f(d_magnitude_folded, + volk_32fc_magnitude_squared_32f(d_magnitude_folded, d_ifft->get_outbuf(), d_fft_size); - /* Normalize the maximum value to correct the scale factor + /* Normalize the maximum value to correct the scale factor introduced by FFTW*/ - //volk_32f_s32f_multiply_32f_a(d_magnitude_folded,d_magnitude_folded, - // (1 / (fft_normalization_factor * fft_normalization_factor)), d_fft_size); - volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude_folded, d_fft_size); + //volk_32f_s32f_multiply_32f_a(d_magnitude_folded,d_magnitude_folded, + // (1 / (fft_normalization_factor * fft_normalization_factor)), d_fft_size); + volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude_folded, d_fft_size); - magt = d_magnitude_folded[indext] / (fft_normalization_factor * fft_normalization_factor); + magt = d_magnitude_folded[indext] / (fft_normalization_factor * fft_normalization_factor); - delete[] d_signal_folded; + delete[] d_signal_folded; - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; + // 4- record the maximum peak and the associated synchronization parameters + if (d_mag < magt) + { + d_mag = magt; - /* In case that d_bit_transition_flag = true, we compare the potentially + /* In case that d_bit_transition_flag = true, we compare the potentially new maximum test statistics (d_mag/d_input_power) with the value in d_test_statistics. When the second dwell is being processed, the value of d_mag/d_input_power could be lower than d_test_statistics (i.e, the maximum test statistics in the previous dwell is greater than current d_mag/d_input_power). Note that d_test_statistics is not restarted between consecutive dwells in multidwell operation.*/ - if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) - { - unsigned int detected_delay_samples_folded = 0; - detected_delay_samples_folded = (indext % d_samples_per_code); - gr_complex complex_acumulator[100]; - //gr_complex complex_acumulator[d_folding_factor]; + if (d_test_statistics < (d_mag / d_input_power) || !d_bit_transition_flag) + { + uint32_t detected_delay_samples_folded = 0; + detected_delay_samples_folded = (indext % d_samples_per_code); + gr_complex complex_acumulator[100]; + //gr_complex complex_acumulator[d_folding_factor]; - for (int i = 0; i < static_cast(d_folding_factor); i++) - { - d_possible_delay[i] = detected_delay_samples_folded + (i) * d_fft_size; - } + for (int32_t i = 0; i < static_cast(d_folding_factor); i++) + { + d_possible_delay[i] = detected_delay_samples_folded + (i)*d_fft_size; + } - for ( int i = 0; i < static_cast(d_folding_factor); i++) - { - - /*Copy a signal of 1 code length into suggested buffer. + for (int32_t i = 0; i < static_cast(d_folding_factor); i++) + { + /*Copy a signal of 1 code length into suggested buffer. The copied signal must have doppler effect corrected*/ - memcpy(in_1code,&in_temp[d_possible_delay[i]], + memcpy(in_1code, &in_temp[d_possible_delay[i]], sizeof(gr_complex) * (d_samples_per_code)); - /*Perform multiplication of the unmodified local + /*Perform multiplication of the unmodified local generated code with the incoming signal with doppler effect corrected and accumulates its value. This is indeed correlation in time for an specific value of a shift*/ - volk_32fc_x2_multiply_32fc(corr_output, in_1code, d_code, d_samples_per_code); + volk_32fc_x2_multiply_32fc(corr_output, in_1code, d_code, d_samples_per_code); - for(int j = 0; j < d_samples_per_code; j++) - { - complex_acumulator[i] += (corr_output[j]); - } + for (int32_t j = 0; j < d_samples_per_code; j++) + { + complex_acumulator[i] += (corr_output[j]); + } + } + /*Obtain maximun value of correlation given the possible delay selected */ + volk_32fc_magnitude_squared_32f(d_corr_output_f, complex_acumulator, d_folding_factor); + volk_gnsssdr_32f_index_max_32u(&indext, d_corr_output_f, d_folding_factor); - } - /*Obtain maximun value of correlation given the possible delay selected */ - volk_32fc_magnitude_squared_32f(d_corr_output_f, complex_acumulator, d_folding_factor); - volk_gnsssdr_32f_index_max_32u(&indext, d_corr_output_f, d_folding_factor); + /*Now save the real code phase in the gnss_syncro block for use in other stages*/ + d_gnss_synchro->Acq_delay_samples = static_cast(d_possible_delay[indext]); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; - /*Now save the real code phase in the gnss_syncro block for use in other stages*/ - d_gnss_synchro->Acq_delay_samples = static_cast(d_possible_delay[indext]); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + /* 5- Compute the test statistics and compare to the threshold d_test_statistics = 2 * d_fft_size * d_mag / d_input_power;*/ + d_test_statistics = d_mag / d_input_power; + //delete complex_acumulator; + } + } - /* 5- Compute the test statistics and compare to the threshold d_test_statistics = 2 * d_fft_size * d_mag / d_input_power;*/ - d_test_statistics = d_mag / d_input_power; - //delete complex_acumulator; - } - } - - // Record results to file if required - if (d_dump) - { - /*Since QuickSYnc performs a folded correlation in frequency by means - of the FFT, it is esential to also keep the values obtained from the + // Record results to file if required + if (d_dump) + { + /*Since QuickSYnc performs a folded correlation in frequency by means + of the FFT, it is essential to also keep the values obtained from the possible delay to show how it is maximize*/ - std::stringstream filename; - std::streamsize n = sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - << "_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_magnitude_folded, n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } + std::stringstream filename; + std::streamsize n = sizeof(float) * (d_fft_size); // complex file write + filename.str(""); + filename << "../data/test_statistics_" << d_gnss_synchro->System + << "_" << d_gnss_synchro->Signal << "_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + d_dump_file.write(reinterpret_cast(d_magnitude_folded), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.close(); + } + } - if (!d_bit_transition_flag) - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition + if (!d_bit_transition_flag) + { + if (d_test_statistics > d_threshold) + { + d_state = 2; // Positive acquisition + } + else if (d_well_count == d_max_dwells) + { + d_state = 3; // Negative acquisition + } + } + else + { + if (d_well_count == d_max_dwells) // d_max_dwells = 2 + { + if (d_test_statistics > d_threshold) + { + d_state = 2; // Positive acquisition + } + else + { + d_state = 3; // Negative acquisition + } + } + } - } - else if (d_well_count == d_max_dwells) - { - d_state = 3; // Negative acquisition + volk_gnsssdr_free(in_temp); + volk_gnsssdr_free(in_temp_folded); + volk_gnsssdr_free(in_1code); + volk_gnsssdr_free(corr_output); + consume_each(1); - } - } - else - { - if (d_well_count == d_max_dwells) // d_max_dwells = 2 - { - if (d_test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - } - else - { - d_state = 3; // Negative acquisition - } - } - } + break; + } - volk_gnsssdr_free(in_temp); - volk_gnsssdr_free(in_temp_folded); - volk_gnsssdr_free(in_1code); - volk_gnsssdr_free(corr_output); - consume_each(1); + case 2: + { + //DLOG(INFO) << "START CASE 2"; + // 6.1- Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "folding factor " << d_folding_factor; + DLOG(INFO) << "possible delay correlation output"; + for (int32_t i = 0; i < static_cast(d_folding_factor); i++) DLOG(INFO) << d_possible_delay[i] << "\t\t\t" << d_corr_output_f[i]; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude folded " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; - break; + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_sampled_ms * d_samples_per_ms * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + //DLOG(INFO) << "END CASE 2"; + break; + } + + case 3: + { + //DLOG(INFO) << "START CASE 3"; + // 6.2- Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "folding factor " << d_folding_factor; + DLOG(INFO) << "possible delay corr output"; + for (int32_t i = 0; i < static_cast(d_folding_factor); i++) DLOG(INFO) << d_possible_delay[i] << "\t\t\t" << d_corr_output_f[i]; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude folded " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_sampled_ms * d_samples_per_ms * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + //DLOG(INFO) << "END CASE 3"; + break; + } } - - case 2: - { - //DLOG(INFO) << "START CASE 2"; - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "folding factor " << d_folding_factor; - DLOG(INFO) << "possible delay correlation output"; - for (int i = 0; i < static_cast(d_folding_factor); i++) DLOG(INFO) << d_possible_delay[i] << "\t\t\t" << d_corr_output_f[i]; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude folded " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_sampled_ms * d_samples_per_ms * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - //DLOG(INFO) << "END CASE 2"; - break; - } - - case 3: - { - //DLOG(INFO) << "START CASE 3"; - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "folding factor "<(d_folding_factor); i++) DLOG(INFO) << d_possible_delay[i] << "\t\t\t" << d_corr_output_f[i]; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude folded " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_sampled_ms * d_samples_per_ms * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - //DLOG(INFO) << "END CASE 3"; - break; - } - } return noutput_items; } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.h index 9538dffa4..1e8e07a05 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_quicksync_acquisition_cc.h @@ -25,7 +25,7 @@ * * ------------------------------------------------------------------------- * -* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,7 +43,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License -* along with GNSS-SDR. If not, see . +* along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -51,29 +51,33 @@ #ifndef GNSS_SDR_PCPS_QUICKSYNC_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_QUICKSYNC_ACQUISITION_CC_H_ -#include -#include -#include -#include -#include -#include -#include -#include #include "gnss_synchro.h" +#include +#include +#include +#include +#include +#include +#include +#include class pcps_quicksync_acquisition_cc; typedef boost::shared_ptr -pcps_quicksync_acquisition_cc_sptr; + pcps_quicksync_acquisition_cc_sptr; pcps_quicksync_acquisition_cc_sptr -pcps_quicksync_make_acquisition_cc(unsigned int folding_factor, - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); +pcps_quicksync_make_acquisition_cc( + uint32_t folding_factor, + uint32_t sampled_ms, + uint32_t max_dwells, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition with @@ -82,61 +86,60 @@ pcps_quicksync_make_acquisition_cc(unsigned int folding_factor, * Check \ref Navitec2012 "Faster GPS via the Sparse Fourier Transform", * for details of its implementation and functionality. */ -class pcps_quicksync_acquisition_cc: public gr::block +class pcps_quicksync_acquisition_cc : public gr::block { private: friend pcps_quicksync_acquisition_cc_sptr - pcps_quicksync_make_acquisition_cc(unsigned int folding_factor, - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); + pcps_quicksync_make_acquisition_cc(uint32_t folding_factor, + uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int32_t samples_per_ms, int32_t samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); - pcps_quicksync_acquisition_cc(unsigned int folding_factor, - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, - int samples_per_ms, int samples_per_code, - bool bit_transition_flag, - bool dump, - std::string dump_filename); + pcps_quicksync_acquisition_cc(uint32_t folding_factor, + uint32_t sampled_ms, uint32_t max_dwells, + uint32_t doppler_max, int64_t fs_in, + int32_t samples_per_ms, int32_t samples_per_code, + bool bit_transition_flag, + bool dump, + std::string dump_filename); - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + void calculate_magnitudes(gr_complex* fft_begin, int32_t doppler_shift, + int32_t doppler_offset); gr_complex* d_code; - unsigned int d_folding_factor; // also referred in the paper as 'p' + uint32_t d_folding_factor; // also referred in the paper as 'p' float* d_corr_acumulator; - unsigned int* d_possible_delay; + uint32_t* d_possible_delay; float* d_corr_output_f; float* d_magnitude_folded; gr_complex* d_signal_folded; gr_complex* d_code_folded; float d_noise_floor_power; - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - unsigned int d_doppler_resolution; + int64_t d_fs_in; + int32_t d_samples_per_ms; + int32_t d_samples_per_code; + uint32_t d_doppler_resolution; float d_threshold; std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint32_t d_doppler_max; + uint32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_max_dwells; + uint32_t d_well_count; + uint32_t d_fft_size; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; + uint32_t d_num_doppler_bins; gr_complex* d_fft_codes; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_fft_if2; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_mag; float* d_magnitude; @@ -145,9 +148,9 @@ private: bool d_bit_transition_flag; std::ofstream d_dump_file; bool d_active; - int d_state; + int32_t d_state; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; public: @@ -161,7 +164,7 @@ public: * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { d_gnss_synchro = p_gnss_synchro; } @@ -169,7 +172,7 @@ public: /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() + inline uint32_t mag() const { return d_mag; } @@ -183,14 +186,14 @@ public: * \brief Sets local code for PCPS acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) + inline void set_active(bool active) { d_active = active; } @@ -200,13 +203,13 @@ public: * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int32_t state); /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) + inline void set_channel(uint32_t channel) { d_channel = channel; } @@ -216,7 +219,7 @@ public: * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) + inline void set_threshold(float threshold) { d_threshold = threshold; } @@ -225,7 +228,7 @@ public: * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) + inline void set_doppler_max(uint32_t doppler_max) { d_doppler_max = doppler_max; } @@ -234,18 +237,17 @@ public: * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) + inline void set_doppler_step(uint32_t doppler_step) { d_doppler_step = doppler_step; } - /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); }; #endif /* GNSS_SDR_PCPS_ACQUISITION_CC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.cc index 8810a23d0..dced14810 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.cc @@ -25,7 +25,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,49 +43,57 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pcps_tong_acquisition_cc.h" -#include +#include "GPS_L1_CA.h" // for GPS_TWO_PI +#include "control_message_factory.h" #include #include #include #include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI +#include +#include using google::LogMessage; pcps_tong_acquisition_cc_sptr pcps_tong_make_acquisition_cc( - unsigned int sampled_ms, unsigned int doppler_max, - long freq, long fs_in, int samples_per_ms, - int samples_per_code, unsigned int tong_init_val, - unsigned int tong_max_val, unsigned int tong_max_dwells, - bool dump, std::string dump_filename) + uint32_t sampled_ms, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + uint32_t tong_init_val, + uint32_t tong_max_val, + uint32_t tong_max_dwells, + bool dump, std::string dump_filename) { return pcps_tong_acquisition_cc_sptr( - new pcps_tong_acquisition_cc(sampled_ms, doppler_max, freq, fs_in, samples_per_ms, samples_per_code, - tong_init_val, tong_max_val, tong_max_dwells, dump, dump_filename)); + new pcps_tong_acquisition_cc(sampled_ms, doppler_max, fs_in, samples_per_ms, samples_per_code, + tong_init_val, tong_max_val, tong_max_dwells, dump, std::move(dump_filename))); } pcps_tong_acquisition_cc::pcps_tong_acquisition_cc( - unsigned int sampled_ms, unsigned int doppler_max, - long freq, long fs_in, int samples_per_ms, - int samples_per_code, unsigned int tong_init_val, - unsigned int tong_max_val, unsigned int tong_max_dwells, - bool dump, std::string dump_filename) : - gr::block("pcps_tong_acquisition_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), - gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) + uint32_t sampled_ms, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + uint32_t tong_init_val, + uint32_t tong_max_val, + uint32_t tong_max_dwells, + bool dump, + std::string dump_filename) : gr::block("pcps_tong_acquisition_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex) * sampled_ms * samples_per_ms), + gr::io_signature::make(0, 0, sizeof(gr_complex) * sampled_ms * samples_per_ms)) { this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER + d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - d_freq = freq; d_fs_in = fs_in; d_samples_per_ms = samples_per_ms; d_samples_per_code = samples_per_code; @@ -101,8 +109,8 @@ pcps_tong_acquisition_cc::pcps_tong_acquisition_cc( d_input_power = 0.0; d_num_doppler_bins = 0; - d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -112,14 +120,14 @@ pcps_tong_acquisition_cc::pcps_tong_acquisition_cc( // For dumping samples into a file d_dump = dump; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); d_doppler_resolution = 0; d_threshold = 0; d_doppler_step = 0; - d_grid_data = 0; - d_grid_doppler_wipeoffs = 0; - d_gnss_synchro = 0; + d_grid_data = nullptr; + d_grid_doppler_wipeoffs = nullptr; + d_gnss_synchro = nullptr; d_code_phase = 0; d_doppler_freq = 0; d_test_statistics = 0; @@ -130,7 +138,7 @@ pcps_tong_acquisition_cc::~pcps_tong_acquisition_cc() { if (d_num_doppler_bins > 0) { - for (unsigned int i = 0; i < d_num_doppler_bins; i++) + for (uint32_t i = 0; i < d_num_doppler_bins; i++) { volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]); volk_gnsssdr_free(d_grid_data[i]); @@ -151,11 +159,11 @@ pcps_tong_acquisition_cc::~pcps_tong_acquisition_cc() } } -void pcps_tong_acquisition_cc::set_local_code(std::complex * code) +void pcps_tong_acquisition_cc::set_local_code(std::complex *code) { - memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size); + memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); - d_fft_if->execute(); // We need the FFT of local code + d_fft_if->execute(); // We need the FFT of local code //Conjugate the local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); @@ -167,69 +175,70 @@ void pcps_tong_acquisition_cc::init() d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Flag_preamble = false; - + d_gnss_synchro->Acq_doppler_step = 0U; d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; d_mag = 0.0; d_input_power = 0.0; // Count the number of bins d_num_doppler_bins = 0; - for (int doppler = static_cast(-d_doppler_max); - doppler <= static_cast(d_doppler_max); + for (auto doppler = static_cast(-d_doppler_max); + doppler <= static_cast(d_doppler_max); doppler += d_doppler_step) - { - d_num_doppler_bins++; - } + { + d_num_doppler_bins++; + } // Create the carrier Doppler wipeoff signals and allocate data grid. - d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins]; - d_grid_data = new float*[d_num_doppler_bins]; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_bins]; + d_grid_data = new float *[d_num_doppler_bins]; + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { - d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_grid_doppler_wipeoffs[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - int doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + float phase_step_rad = GPS_TWO_PI * doppler / static_cast(d_fs_in); float _phase[1]; _phase[0] = 0; - volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], - phase_step_rad, _phase, d_fft_size); + volk_gnsssdr_s32f_sincos_32fc(d_grid_doppler_wipeoffs[doppler_index], -phase_step_rad, _phase, d_fft_size); - d_grid_data[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_grid_data[doppler_index] = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); - for (unsigned int i = 0; i < d_fft_size; i++) + for (uint32_t i = 0; i < d_fft_size; i++) { d_grid_data[doppler_index][i] = 0; } } } -void pcps_tong_acquisition_cc::set_state(int state) +void pcps_tong_acquisition_cc::set_state(int32_t state) { d_state = state; if (d_state == 1) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; d_dwell_count = 0; d_tong_count = d_tong_init_val; d_mag = 0.0; d_input_power = 0.0; d_test_statistics = 0.0; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) { - for (unsigned int i = 0; i < d_fft_size; i++) + for (uint32_t i = 0; i < d_fft_size; i++) { d_grid_data[doppler_index][i] = 0; } } } else if (d_state == 0) - {} + { + } else { LOG(ERROR) << "State can only be set to 0 or 1"; @@ -237,211 +246,213 @@ void pcps_tong_acquisition_cc::set_state(int state) } int pcps_tong_acquisition_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items __attribute__((unused))) { - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + int32_t acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL switch (d_state) - { - case 0: { - if (d_active) - { - //restart acquisition variables - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_dwell_count = 0; - d_tong_count = d_tong_init_val; - d_mag = 0.0; - d_input_power = 0.0; - d_test_statistics = 0.0; + case 0: + { + if (d_active) + { + //restart acquisition variables + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0ULL; + d_gnss_synchro->Acq_doppler_step = 0U; + d_dwell_count = 0; + d_tong_count = d_tong_init_val; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - for (unsigned int i = 0; i < d_fft_size; i++) - { - d_grid_data[doppler_index][i] = 0; - } - } + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + for (uint32_t i = 0; i < d_fft_size; i++) + { + d_grid_data[doppler_index][i] = 0; + } + } - d_state = 1; - } + d_state = 1; + } - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); - break; + break; + } + + case 1: + { + // initialize acquisition algorithm + int32_t doppler; + uint32_t indext = 0; + float magt = 0.0; + const auto *in = reinterpret_cast(input_items[0]); //Get the input samples pointer + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + d_input_power = 0.0; + d_mag = 0.0; + + d_sample_counter += static_cast(d_fft_size); // sample counter + + d_dwell_count++; + + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << d_doppler_max + << ", doppler_step: " << d_doppler_step; + + // 1- Compute the input signal power estimation + volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); + volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); + d_input_power /= static_cast(d_fft_size); + + // 2- Doppler frequency search loop + for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps + + doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + + volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, + d_grid_doppler_wipeoffs[doppler_index], d_fft_size); + + // 3- Perform the FFT-based convolution (parallel time search) + // Compute the FFT of the carrier wiped--off incoming signal + d_fft_if->execute(); + + // Multiply carrier wiped--off, Fourier transformed incoming signal + // with the local FFT'd code reference using SIMD operations with VOLK library + volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), + d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); + + // compute the inverse FFT + d_ifft->execute(); + + // Compute magnitude + volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); + + // Compute vector of test statistics corresponding to current doppler index. + volk_32f_s32f_multiply_32f(d_magnitude, d_magnitude, + 1 / (fft_normalization_factor * fft_normalization_factor * d_input_power), + d_fft_size); + + // Accumulate test statistics in d_grid_data. + volk_32f_x2_add_32f(d_grid_data[doppler_index], d_magnitude, d_grid_data[doppler_index], d_fft_size); + + // Search maximum + volk_gnsssdr_32f_index_max_32u(&indext, d_grid_data[doppler_index], d_fft_size); + + magt = d_grid_data[doppler_index][indext]; + + // 4- record the maximum peak and the associated synchronization parameters + if (d_mag < magt) + { + d_mag = magt; + d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + d_gnss_synchro->Acq_doppler_step = d_doppler_step; + } + + // Record results to file if required + if (d_dump) + { + std::stringstream filename; + std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write + filename.str(""); + filename << "../data/test_statistics_" << d_gnss_synchro->System + << "_" << d_gnss_synchro->Signal << "_sat_" + << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; + d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); + d_dump_file.write(reinterpret_cast(d_ifft->get_outbuf()), n); //write directly |abs(x)|^2 in this Doppler bin? + d_dump_file.close(); + } + } + + // 5- Compute the test statistics and compare to the threshold + d_test_statistics = d_mag; + + if (d_test_statistics > d_threshold * d_dwell_count) + { + d_tong_count++; + if (d_tong_count == d_tong_max_val) + { + d_state = 2; // Positive acquisition + } + } + else + { + d_tong_count--; + if (d_tong_count == 0) + { + d_state = 3; // Negative acquisition + } + } + + if (d_dwell_count >= d_tong_max_dwells) + { + d_state = 3; // Negative acquisition + } + consume_each(1); + + break; + } + + case 2: + { + // 6.1- Declare positive acquisition using a message port + DLOG(INFO) << "positive acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 1; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } + + case 3: + { + // 6.2- Declare negative acquisition using a message port + DLOG(INFO) << "negative acquisition"; + DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; + DLOG(INFO) << "sample_stamp " << d_sample_counter; + DLOG(INFO) << "test statistics value " << d_test_statistics; + DLOG(INFO) << "test statistics threshold " << d_threshold; + DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; + DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; + DLOG(INFO) << "magnitude " << d_mag; + DLOG(INFO) << "input signal power " << d_input_power; + + d_active = false; + d_state = 0; + + d_sample_counter += static_cast(d_fft_size * ninput_items[0]); // sample counter + consume_each(ninput_items[0]); + + acquisition_message = 2; + this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); + + break; + } } - case 1: - { - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - float magt = 0.0; - const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - d_input_power = 0.0; - d_mag = 0.0; - - d_sample_counter += d_fft_size; // sample counter - - d_dwell_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN - << " ,sample stamp: " << d_sample_counter << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - // 1- Compute the input signal power estimation - volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size); - volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - d_input_power /= static_cast(d_fft_size); - - // 2- Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, - d_grid_doppler_wipeoffs[doppler_index], d_fft_size); - - // 3- Perform the FFT-based convolution (parallel time search) - // Compute the FFT of the carrier wiped--off incoming signal - d_fft_if->execute(); - - // Multiply carrier wiped--off, Fourier transformed incoming signal - // with the local FFT'd code reference using SIMD operations with VOLK library - volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), - d_fft_if->get_outbuf(), d_fft_codes, d_fft_size); - - // compute the inverse FFT - d_ifft->execute(); - - // Compute magnitude - volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf(), d_fft_size); - - // Compute vector of test statistics corresponding to current doppler index. - volk_32f_s32f_multiply_32f(d_magnitude, d_magnitude, - 1/(fft_normalization_factor*fft_normalization_factor*d_input_power), - d_fft_size); - - // Accumulate test statistics in d_grid_data. - volk_32f_x2_add_32f(d_grid_data[doppler_index], d_magnitude, d_grid_data[doppler_index], d_fft_size); - - // Search maximum - volk_gnsssdr_32f_index_max_32u(&indext, d_grid_data[doppler_index], d_fft_size); - - magt = d_grid_data[doppler_index][indext]; - - // 4- record the maximum peak and the associated synchronization parameters - if (d_mag < magt) - { - d_mag = magt; - d_gnss_synchro->Acq_delay_samples = static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - } - - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - <<"_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - } - - // 5- Compute the test statistics and compare to the threshold - d_test_statistics = d_mag; - - if (d_test_statistics > d_threshold * d_dwell_count) - { - d_tong_count++; - if (d_tong_count == d_tong_max_val) - { - d_state = 2; // Positive acquisition - } - } - else - { - d_tong_count--; - if (d_tong_count == 0) - { - d_state = 3; // Negative acquisition - } - } - - if(d_dwell_count >= d_tong_max_dwells) - { - d_state = 3; // Negative acquisition - } - consume_each(1); - - break; - } - - case 2: - { - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - - case 3: - { - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << d_test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << d_input_power; - - d_active = false; - d_state = 0; - - d_sample_counter += d_fft_size * ninput_items[0]; // sample counter - consume_each(ninput_items[0]); - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), pmt::from_long(acquisition_message)); - - break; - } - } - return noutput_items; } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.h index 03b20b372..f4cb31068 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_tong_acquisition_cc.h @@ -25,7 +25,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,7 +43,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -51,72 +51,78 @@ #ifndef GNSS_SDR_PCPS_TONG_ACQUISITION_CC_H_ #define GNSS_SDR_PCPS_TONG_ACQUISITION_CC_H_ +#include "gnss_synchro.h" +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" + class pcps_tong_acquisition_cc; typedef boost::shared_ptr pcps_tong_acquisition_cc_sptr; pcps_tong_acquisition_cc_sptr -pcps_tong_make_acquisition_cc(unsigned int sampled_ms, unsigned int doppler_max, - long freq, long fs_in, int samples_per_ms, - int samples_per_code, unsigned int tong_init_val, - unsigned int tong_max_val, unsigned int tong_max_dwells, - bool dump, std::string dump_filename); +pcps_tong_make_acquisition_cc( + uint32_t sampled_ms, + uint32_t doppler_max, + int64_t fs_in, + int32_t samples_per_ms, + int32_t samples_per_code, + uint32_t tong_init_val, + uint32_t tong_max_val, + uint32_t tong_max_dwells, + bool dump, + std::string dump_filename); /*! * \brief This class implements a Parallel Code Phase Search Acquisition with * Tong algorithm. */ -class pcps_tong_acquisition_cc: public gr::block +class pcps_tong_acquisition_cc : public gr::block { private: friend pcps_tong_acquisition_cc_sptr - pcps_tong_make_acquisition_cc(unsigned int sampled_ms, unsigned int doppler_max, - long freq, long fs_in, int samples_per_ms, - int samples_per_code, unsigned int tong_init_val, - unsigned int tong_max_val, unsigned int tong_max_dwells, - bool dump, std::string dump_filename); + pcps_tong_make_acquisition_cc(uint32_t sampled_ms, uint32_t doppler_max, + int64_t fs_in, int32_t samples_per_ms, + int32_t samples_per_code, uint32_t tong_init_val, + uint32_t tong_max_val, uint32_t tong_max_dwells, + bool dump, std::string dump_filename); - pcps_tong_acquisition_cc(unsigned int sampled_ms, unsigned int doppler_max, - long freq, long fs_in, int samples_per_ms, - int samples_per_code, unsigned int tong_init_val, - unsigned int tong_max_val, unsigned int tong_max_dwells, - bool dump, std::string dump_filename); + pcps_tong_acquisition_cc(uint32_t sampled_ms, uint32_t doppler_max, + int64_t fs_in, int32_t samples_per_ms, + int32_t samples_per_code, uint32_t tong_init_val, + uint32_t tong_max_val, uint32_t tong_max_dwells, + bool dump, std::string dump_filename); - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + void calculate_magnitudes(gr_complex* fft_begin, int32_t doppler_shift, + int32_t doppler_offset); - long d_fs_in; - long d_freq; - int d_samples_per_ms; - int d_samples_per_code; - unsigned int d_doppler_resolution; + int64_t d_fs_in; + int32_t d_samples_per_ms; + int32_t d_samples_per_code; + uint32_t d_doppler_resolution; float d_threshold; std::string d_satellite_str; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_sampled_ms; - unsigned int d_dwell_count; - unsigned int d_tong_count; - unsigned int d_tong_init_val; - unsigned int d_tong_max_val; - unsigned int d_tong_max_dwells; - unsigned int d_fft_size; - unsigned long int d_sample_counter; + uint32_t d_doppler_max; + uint32_t d_doppler_step; + uint32_t d_sampled_ms; + uint32_t d_dwell_count; + uint32_t d_tong_count; + uint32_t d_tong_init_val; + uint32_t d_tong_max_val; + uint32_t d_tong_max_dwells; + uint32_t d_fft_size; + uint64_t d_sample_counter; gr_complex** d_grid_doppler_wipeoffs; - unsigned int d_num_doppler_bins; + uint32_t d_num_doppler_bins; gr_complex* d_fft_codes; float** d_grid_data; gr::fft::fft_complex* d_fft_if; gr::fft::fft_complex* d_ifft; - Gnss_Synchro *d_gnss_synchro; - unsigned int d_code_phase; + Gnss_Synchro* d_gnss_synchro; + uint32_t d_code_phase; float d_doppler_freq; float d_mag; float* d_magnitude; @@ -124,107 +130,106 @@ private: float d_test_statistics; std::ofstream d_dump_file; bool d_active; - int d_state; + int32_t d_state; bool d_dump; - unsigned int d_channel; + uint32_t d_channel; std::string d_dump_filename; public: /*! * \brief Default destructor. */ - ~pcps_tong_acquisition_cc(); + ~pcps_tong_acquisition_cc(); - /*! + /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to exchange synchronization data between acquisition and tracking blocks. * \param p_gnss_synchro Satellite information shared by the processing blocks. */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + d_gnss_synchro = p_gnss_synchro; + } - /*! + /*! * \brief Returns the maximum peak of grid search. */ - unsigned int mag() - { - return d_mag; - } + inline uint32_t mag() const + { + return d_mag; + } - /*! + /*! * \brief Initializes acquisition algorithm. */ - void init(); + void init(); - /*! + /*! * \brief Sets local code for TONG acquisition algorithm. * \param code - Pointer to the PRN code. */ - void set_local_code(std::complex * code); + void set_local_code(std::complex* code); - /*! + /*! * \brief Starts acquisition algorithm, turning from standby mode to * active mode * \param active - bool that activates/deactivates the block. */ - void set_active(bool active) - { - d_active = active; - } + inline void set_active(bool active) + { + d_active = active; + } - /*! + /*! * \brief If set to 1, ensures that acquisition starts at the * first available sample. * \param state - int=1 forces start of acquisition */ - void set_state(int state); + void set_state(int32_t state); - /*! + /*! * \brief Set acquisition channel unique ID * \param channel - receiver channel. */ - void set_channel(unsigned int channel) - { - d_channel = channel; - } + inline void set_channel(uint32_t channel) + { + d_channel = channel; + } - /*! + /*! * \brief Set statistics threshold of TONG algorithm. * \param threshold - Threshold for signal detection (check \ref Navitec2012, * Algorithm 1, for a definition of this threshold). */ - void set_threshold(float threshold) - { - d_threshold = threshold; - } + inline void set_threshold(float threshold) + { + d_threshold = threshold; + } - /*! + /*! * \brief Set maximum Doppler grid search * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. */ - void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - } + inline void set_doppler_max(uint32_t doppler_max) + { + d_doppler_max = doppler_max; + } - /*! + /*! * \brief Set Doppler steps for the grid search * \param doppler_step - Frequency bin of the search grid [Hz]. */ - void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - } + inline void set_doppler_step(uint32_t doppler_step) + { + d_doppler_step = doppler_step; + } - - /*! + /*! * \brief Parallel Code Phase Search Acquisition signal processing. */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); }; #endif /* GNSS_SDR_PCPS_TONG_ACQUISITION_CC_H_ */ diff --git a/src/algorithms/acquisition/libs/CMakeLists.txt b/src/algorithms/acquisition/libs/CMakeLists.txt new file mode 100644 index 000000000..c3f368be6 --- /dev/null +++ b/src/algorithms/acquisition/libs/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + +if(ENABLE_FPGA) + set(ACQUISITION_LIB_SOURCES fpga_acquisition.cc) + set(ACQUISITION_LIB_HEADERS fpga_acquisition.h) + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${VOLK_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ) +endif() + +set(ACQUISITION_LIB_HEADERS ${ACQUISITION_LIB_HEADERS} acq_conf.h) +set(ACQUISITION_LIB_SOURCES ${ACQUISITION_LIB_SOURCES} acq_conf.cc) + +list(SORT ACQUISITION_LIB_HEADERS) +list(SORT ACQUISITION_LIB_SOURCES) + +add_library(acquisition_lib + ${ACQUISITION_LIB_SOURCES} + ${ACQUISITION_LIB_HEADERS} +) + +source_group(Headers FILES ${ACQUISITION_LIB_HEADERS}) + +target_link_libraries(acquisition_lib + ${VOLK_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} +) + +if(VOLKGNSSSDR_FOUND) + add_dependencies(acquisition_lib glog-${glog_RELEASE}) +else() + add_dependencies(acquisition_lib glog-${glog_RELEASE} volk_gnsssdr_module) +endif() diff --git a/src/algorithms/acquisition/libs/acq_conf.cc b/src/algorithms/acquisition/libs/acq_conf.cc new file mode 100644 index 000000000..8e8d48d5e --- /dev/null +++ b/src/algorithms/acquisition/libs/acq_conf.cc @@ -0,0 +1,60 @@ +/*! + * \file acq_conf.cc + * \brief Class that contains all the configuration parameters for generic + * acquisition block based on the PCPS algoritm. + * \author Carles Fernandez, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "acq_conf.h" + +Acq_Conf::Acq_Conf() +{ + /* PCPS acquisition configuration */ + sampled_ms = 0U; + ms_per_code = 0U; + max_dwells = 0U; + samples_per_chip = 0U; + doppler_max = 0U; + num_doppler_bins_step2 = 0U; + doppler_step2 = 0.0; + fs_in = 0LL; + samples_per_ms = 0.0; + samples_per_code = 0.0; + bit_transition_flag = false; + use_CFAR_algorithm_flag = false; + dump = false; + blocking = false; + make_2_steps = false; + dump_filename = ""; + dump_channel = 0U; + it_size = sizeof(char); + blocking_on_standby = false; + use_automatic_resampler = false; + resampler_ratio = 1.0; + resampled_fs = 0LL; + resampler_latency_samples = 0U; +} diff --git a/src/algorithms/acquisition/libs/acq_conf.h b/src/algorithms/acquisition/libs/acq_conf.h new file mode 100644 index 000000000..af81d8806 --- /dev/null +++ b/src/algorithms/acquisition/libs/acq_conf.h @@ -0,0 +1,70 @@ +/*! + * \file acq_conf.cc + * \brief Class that contains all the configuration parameters for generic + * acquisition block based on the PCPS algoritm. + * \author Carles Fernandez, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ACQ_CONF_H_ +#define GNSS_SDR_ACQ_CONF_H_ + +#include +#include +#include + +class Acq_Conf +{ +public: + /* PCPS Acquisition configuration */ + uint32_t sampled_ms; + uint32_t ms_per_code; + uint32_t samples_per_chip; + uint32_t max_dwells; + uint32_t doppler_max; + uint32_t num_doppler_bins_step2; + float doppler_step2; + int64_t fs_in; + float samples_per_ms; + float samples_per_code; + bool bit_transition_flag; + bool use_CFAR_algorithm_flag; + bool dump; + bool blocking; + bool blocking_on_standby; // enable it only for unit testing to avoid sample consume on idle status + bool make_2_steps; + bool use_automatic_resampler; + float resampler_ratio; + int64_t resampled_fs; + uint32_t resampler_latency_samples; + std::string dump_filename; + uint32_t dump_channel; + size_t it_size; + + Acq_Conf(); +}; + +#endif diff --git a/src/algorithms/acquisition/libs/fpga_acquisition.cc b/src/algorithms/acquisition/libs/fpga_acquisition.cc new file mode 100644 index 000000000..5618d072b --- /dev/null +++ b/src/algorithms/acquisition/libs/fpga_acquisition.cc @@ -0,0 +1,424 @@ +/*! + * \file fpga_acquisition.cc + * \brief High optimized FPGA vector correlator class + * \authors
          + *
        • Marc Majoral, 2018. mmajoral(at)cttc.cat + *
        + * + * Class that controls and executes a high optimized acquisition HW + * accelerator in the FPGA + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fpga_acquisition.h" +#include "GPS_L1_CA.h" +#include "gps_sdr_signal_processing.h" +#include +#include // libraries used by the GIPO +#include +#include // libraries used by the GIPO +#include + + +#define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map +#define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31); +#define RESET_ACQUISITION 2 // command to reset the multicorrelator +#define LAUNCH_ACQUISITION 1 // command to launch the multicorrelator +#define TEST_REG_SANITY_CHECK 0x55AA // value to check the presence of the test register (to detect the hw) +#define LOCAL_CODE_CLEAR_MEM 0x10000000 // command to clear the internal memory of the multicorrelator +#define MEM_LOCAL_CODE_WR_ENABLE 0x0C000000 // command to enable the ENA and WR pins of the internal memory of the multicorrelator +#define POW_2_2 4 // 2^2 (used for the conversion of floating point numbers to integers) +#define POW_2_29 536870912 // 2^29 (used for the conversion of floating point numbers to integers) +#define SELECT_LSB 0x00FF // value to select the least significant byte +#define SELECT_MSB 0XFF00 // value to select the most significant byte +#define SELECT_16_BITS 0xFFFF // value to select 16 bits +#define SHL_8_BITS 256 // value used to shift a value 8 bits to the left + +// 12-bits +//#define SELECT_LSBits 0x0FFF +//#define SELECT_MSBbits 0x00FFF000 +//#define SELECT_24_BITS 0x00FFFFFF +//#define SHL_12_BITS 4096 +// 16-bits +#define SELECT_LSBits 0x0FFFF +#define SELECT_MSBbits 0xFFFF0000 +#define SELECT_32_BITS 0xFFFFFFFF +#define SHL_16_BITS 65536 + + +bool fpga_acquisition::init() +{ + // configure the acquisition with the main initialization values + fpga_acquisition::configure_acquisition(); + return true; +} + + +bool fpga_acquisition::set_local_code(uint32_t PRN) +{ + // select the code with the chosen PRN + fpga_acquisition::fpga_configure_acquisition_local_code( + &d_all_fft_codes[d_nsamples_total * (PRN - 1)]); + + //fpga_acquisition::fpga_configure_acquisition_local_code( + // &d_all_fft_codes[0]); + + return true; +} + + +fpga_acquisition::fpga_acquisition(std::string device_name, + uint32_t nsamples, + uint32_t doppler_max, + uint32_t nsamples_total, int64_t fs_in, + uint32_t sampled_ms, uint32_t select_queue, + lv_16sc_t *all_fft_codes) +{ + //printf("AAA- sampled_ms = %d\n ", sampled_ms); + + uint32_t vector_length = nsamples_total; // * sampled_ms; + + //printf("AAA- vector_length = %d\n ", vector_length); + // initial values + d_device_name = std::move(device_name); + //d_freq = freq; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_nsamples = nsamples; // number of samples not including padding + d_select_queue = select_queue; + d_nsamples_total = nsamples_total; + d_doppler_max = doppler_max; + d_doppler_step = 0; + d_fd = 0; // driver descriptor + d_map_base = nullptr; // driver memory map + d_all_fft_codes = all_fft_codes; + + // open communication with HW accelerator + if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << d_device_name; + std::cout << "Acq: cannot open deviceio" << d_device_name << std::endl; + } + d_map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0)); + + if (d_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; + std::cout << "Acq: cannot map deviceio" << d_device_name << std::endl; + } + + // sanity check : check test register + uint32_t writeval = TEST_REG_SANITY_CHECK; + uint32_t readval; + readval = fpga_acquisition::fpga_acquisition_test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Acquisition test register sanity check failed"; + } + else + { + LOG(INFO) << "Acquisition test register sanity check success!"; + //std::cout << "Acquisition test register sanity check success!" << std::endl; + } + fpga_acquisition::reset_acquisition(); + DLOG(INFO) << "Acquisition FPGA class created"; +} + + +fpga_acquisition::~fpga_acquisition() +{ + close_device(); +} + + +bool fpga_acquisition::free() +{ + return true; +} + + +uint32_t fpga_acquisition::fpga_acquisition_test_register(uint32_t writeval) +{ + uint32_t readval; + // write value to test register + d_map_base[15] = writeval; + // read value from test register + readval = d_map_base[15]; + // return read value + return readval; +} + + +void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) +{ + uint32_t local_code; + uint32_t k, tmp, tmp2; + uint32_t fft_data; + + // clear memory address counter + //d_map_base[6] = LOCAL_CODE_CLEAR_MEM; + d_map_base[9] = LOCAL_CODE_CLEAR_MEM; + // write local code + for (k = 0; k < d_vector_length; k++) + { + tmp = fft_local_code[k].real(); + tmp2 = fft_local_code[k].imag(); + //tmp = k; + //tmp2 = k; + + //local_code = (tmp & SELECT_LSB) | ((tmp2 * SHL_8_BITS) & SELECT_MSB); // put together the real part and the imaginary part + //fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_16_BITS); + //local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_12_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part + local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_16_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part + //fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_24_BITS); + fft_data = local_code & SELECT_32_BITS; + d_map_base[6] = fft_data; + + + //printf("debug local code %d real = %d imag = %d local_code = %d fft_data = %d\n", k, tmp, tmp2, local_code, fft_data); + //printf("debug local code %d real = 0x%08X imag = 0x%08X local_code = 0x%08X fft_data = 0x%08X\n", k, tmp, tmp2, local_code, fft_data); + } + //printf("d_vector_length = %d\n", d_vector_length); + //while(1); +} + + +void fpga_acquisition::run_acquisition(void) +{ + // enable interrupts + int32_t reenable = 1; + write(d_fd, reinterpret_cast(&reenable), sizeof(int32_t)); + // launch the acquisition process + //printf("launchin acquisition ...\n"); + d_map_base[8] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process + + int32_t irq_count; + ssize_t nb; + // wait for interrupt + nb = read(d_fd, &irq_count, sizeof(irq_count)); + //printf("interrupt received\n"); + if (nb != sizeof(irq_count)) + { + printf("acquisition module Read failed to retrieve 4 bytes!\n"); + printf("acquisition module Interrupt number %d\n", irq_count); + } +} + + +void fpga_acquisition::set_doppler_sweep(uint32_t num_sweeps) +{ + float phase_step_rad_real; + float phase_step_rad_int_temp; + int32_t phase_step_rad_int; + //int32_t doppler = static_cast(-d_doppler_max) + d_doppler_step * doppler_index; + auto doppler = static_cast(-d_doppler_max); + //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); + // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing + // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) + // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) + // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + // avoid saturation of the fixed point representation in the fpga + // (only the positive value can saturate due to the 2's complement representation) + + //printf("AAA phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real); + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + //printf("AAA phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real); + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + //printf("AAA writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int); + d_map_base[3] = phase_step_rad_int; + + // repeat the calculation with the doppler step + doppler = static_cast(d_doppler_step); + phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + //printf("AAA phase_step_rad_real for doppler step = %f\n", phase_step_rad_real); + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + //printf("AAA phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real); + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + //printf("AAA writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int); + d_map_base[4] = phase_step_rad_int; + //printf("AAA writing num sweeps to d map base 5 = %d\n", num_sweeps); + d_map_base[5] = num_sweeps; +} + +void fpga_acquisition::set_doppler_sweep_debug(uint32_t num_sweeps, uint32_t doppler_index) +{ + float phase_step_rad_real; + float phase_step_rad_int_temp; + int32_t phase_step_rad_int; + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + //int32_t doppler = static_cast(-d_doppler_max); + //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); + // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing + // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) + // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) + // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + // avoid saturation of the fixed point representation in the fpga + // (only the positive value can saturate due to the 2's complement representation) + + //printf("AAAh phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real); + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + //printf("AAAh phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real); + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + //printf("AAAh writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int); + d_map_base[3] = phase_step_rad_int; + + // repeat the calculation with the doppler step + doppler = static_cast(d_doppler_step); + phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + //printf("AAAh phase_step_rad_real for doppler step = %f\n", phase_step_rad_real); + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + //printf("AAAh phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real); + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + //printf("AAAh writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int); + d_map_base[4] = phase_step_rad_int; + //printf("AAAh writing num sweeps to d map base 5 = %d\n", num_sweeps); + d_map_base[5] = num_sweeps; +} + + +void fpga_acquisition::configure_acquisition() +{ + //printf("AAA d_select_queue = %d\n", d_select_queue); + d_map_base[0] = d_select_queue; + //printf("AAA writing d_vector_length = %d to d map base 1\n ", d_vector_length); + d_map_base[1] = d_vector_length; + //printf("AAA writing d_nsamples = %d to d map base 2\n ", d_nsamples); + d_map_base[2] = d_nsamples; + //printf("AAA writing LOG2 d_vector_length = %d to d map base 7\n ", (int)log2((float)d_vector_length)); + d_map_base[7] = static_cast(log2(static_cast(d_vector_length))); // log2 FFTlength + //printf("acquisition debug vector length = %d\n", d_vector_length); + //printf("acquisition debug vector length = %d\n", (int)log2((float)d_vector_length)); +} + + +void fpga_acquisition::set_phase_step(uint32_t doppler_index) +{ + float phase_step_rad_real; + float phase_step_rad_int_temp; + int32_t phase_step_rad_int; + int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; + //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); + // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing + // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) + // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) + // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + // avoid saturation of the fixed point representation in the fpga + // (only the positive value can saturate due to the 2's complement representation) + //printf("AAA+ phase_step_rad_real = %f\n", phase_step_rad_real); + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + //printf("AAA+ phase_step_rad_real after checking = %f\n", phase_step_rad_real); + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + //printf("writing phase_step_rad_int = %d to d_map_base 3\n", phase_step_rad_int); + d_map_base[3] = phase_step_rad_int; +} + + +void fpga_acquisition::read_acquisition_results(uint32_t *max_index, + float *max_magnitude, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index) +{ + uint64_t initial_sample_tmp = 0; + + uint32_t readval = 0; + uint64_t readval_long = 0; + uint64_t readval_long_shifted = 0; + readval = d_map_base[1]; + initial_sample_tmp = readval; + readval_long = d_map_base[2]; + readval_long_shifted = readval_long << 32; // 2^32 + initial_sample_tmp = initial_sample_tmp + readval_long_shifted; // 2^32 + //printf("----------------------------------------------------------------> acq initial sample TOTAL = %llu\n", initial_sample_tmp); + *initial_sample = initial_sample_tmp; + readval = d_map_base[6]; + *max_magnitude = static_cast(readval); + //printf("read max_magnitude dmap 2 = %d\n", readval); + readval = d_map_base[4]; + *power_sum = static_cast(readval); + //printf("read power sum dmap 4 = %d\n", readval); + readval = d_map_base[5]; // read doppler index + *doppler_index = readval; + //printf("read doppler_index dmap 5 = %d\n", readval); + readval = d_map_base[3]; + *max_index = readval; + //printf("read max index dmap 3 = %d\n", readval); +} + + +void fpga_acquisition::block_samples() +{ + d_map_base[14] = 1; // block the samples +} + + +void fpga_acquisition::unblock_samples() +{ + d_map_base[14] = 0; // unblock the samples +} + + +void fpga_acquisition::close_device() +{ + auto *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + close(d_fd); +} + + +void fpga_acquisition::reset_acquisition(void) +{ + d_map_base[8] = RESET_ACQUISITION; // writing a 2 to d_map_base[8] resets the multicorrelator +} diff --git a/src/algorithms/acquisition/libs/fpga_acquisition.h b/src/algorithms/acquisition/libs/fpga_acquisition.h new file mode 100644 index 000000000..c23e6b5d5 --- /dev/null +++ b/src/algorithms/acquisition/libs/fpga_acquisition.h @@ -0,0 +1,110 @@ +/*! + * \file fpga_acquisition.h + * \brief High optimized FPGA vector correlator class + * \authors
          + *
        • Marc Majoral, 2018. mmajoral(at)cttc.cat + *
        + * + * Class that controls and executes a high optimized acquisition HW + * accelerator in the FPGA + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FPGA_ACQUISITION_H_ +#define GNSS_SDR_FPGA_ACQUISITION_H_ + +#include +#include +#include + +/*! + * \brief Class that implements carrier wipe-off and correlators. + */ +class fpga_acquisition +{ +public: + fpga_acquisition(std::string device_name, + uint32_t nsamples, + uint32_t doppler_max, + uint32_t nsamples_total, + int64_t fs_in, + uint32_t sampled_ms, + uint32_t select_queue, + lv_16sc_t *all_fft_codes); + + ~fpga_acquisition(); + bool init(); + bool set_local_code(uint32_t PRN); + bool free(); + void set_doppler_sweep(uint32_t num_sweeps); + void set_doppler_sweep_debug(uint32_t num_sweeps, uint32_t doppler_index); + void run_acquisition(void); + void set_phase_step(uint32_t doppler_index); + void read_acquisition_results(uint32_t *max_index, float *max_magnitude, + uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index); + void block_samples(); + void unblock_samples(); + + /*! + * \brief Set maximum Doppler grid search + * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. + */ + void set_doppler_max(uint32_t doppler_max) + { + d_doppler_max = doppler_max; + } + + /*! + * \brief Set Doppler steps for the grid search + * \param doppler_step - Frequency bin of the search grid [Hz]. + */ + void set_doppler_step(uint32_t doppler_step) + { + d_doppler_step = doppler_step; + } + +private: + int64_t d_fs_in; + // data related to the hardware module and the driver + int32_t d_fd; // driver descriptor + volatile uint32_t *d_map_base; // driver memory map + lv_16sc_t *d_all_fft_codes; // memory that contains all the code ffts + uint32_t d_vector_length; // number of samples incluing padding and number of ms + uint32_t d_nsamples_total; // number of samples including padding + uint32_t d_nsamples; // number of samples not including padding + uint32_t d_select_queue; // queue selection + std::string d_device_name; // HW device name + uint32_t d_doppler_max; // max doppler + uint32_t d_doppler_step; // doppler step + // FPGA private functions + uint32_t fpga_acquisition_test_register(uint32_t writeval); + void fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]); + void configure_acquisition(); + void reset_acquisition(void); + void close_device(); +}; + +#endif /* GNSS_SDR_FPGA_ACQUISITION_H_ */ diff --git a/src/algorithms/channel/CMakeLists.txt b/src/algorithms/channel/CMakeLists.txt index 053a2b67f..cd5604218 100644 --- a/src/algorithms/channel/CMakeLists.txt +++ b/src/algorithms/channel/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,8 +13,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) -add_subdirectory(libs) \ No newline at end of file +add_subdirectory(libs) diff --git a/src/algorithms/channel/adapters/CMakeLists.txt b/src/algorithms/channel/adapters/CMakeLists.txt index b3efdcff7..65591834c 100644 --- a/src/algorithms/channel/adapters/CMakeLists.txt +++ b/src/algorithms/channel/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,25 +13,35 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(CHANNEL_ADAPTER_SOURCES channel.cc) +set(CHANNEL_ADAPTER_HEADERS channel.h) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} +) + +add_library(channel_adapters + ${CHANNEL_ADAPTER_SOURCES} + ${CHANNEL_ADAPTER_HEADERS} ) -file(GLOB CHANNEL_ADAPTER_HEADERS "*.h") -list(SORT CHANNEL_ADAPTER_HEADERS) -add_library(channel_adapters ${CHANNEL_ADAPTER_SOURCES} ${CHANNEL_ADAPTER_HEADERS}) source_group(Headers FILES ${CHANNEL_ADAPTER_HEADERS}) -target_link_libraries(channel_adapters channel_fsm ${GNURADIO_RUNTIME_LIBRARIES} ${Boost_LIBRARIES}) + +target_link_libraries(channel_adapters + channel_fsm + ${GNURADIO_RUNTIME_LIBRARIES} + ${Boost_LIBRARIES} + gnss_sdr_flags +) diff --git a/src/algorithms/channel/adapters/channel.cc b/src/algorithms/channel/adapters/channel.cc index c60a23d9c..946f17a65 100644 --- a/src/algorithms/channel/adapters/channel.cc +++ b/src/algorithms/channel/adapters/channel.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,108 +24,101 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #include "channel.h" -//#include -#include -#include -//#include "channel_interface.h" -//#include "acquisition_interface.h" -//#include "tracking_interface.h" -//#include "telemetry_decoder_interface.h" #include "configuration_interface.h" -//#include "channel_msg_receiver_cc.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; // Constructor -Channel::Channel(ConfigurationInterface *configuration, unsigned int channel, - std::shared_ptr pass_through, std::shared_ptr acq, - std::shared_ptr trk, std::shared_ptr nav, - std::string role, std::string implementation, boost::shared_ptr queue) +Channel::Channel(ConfigurationInterface* configuration, uint32_t channel, std::shared_ptr acq, + std::shared_ptr trk, std::shared_ptr nav, + std::string role, std::string implementation, gr::msg_queue::sptr queue) { - pass_through_ = pass_through; - acq_ = acq; - trk_ = trk; - nav_ = nav; - role_ = role; - implementation_ = implementation; + acq_ = std::move(acq); + trk_ = std::move(trk); + nav_ = std::move(nav); + role_ = std::move(role); + implementation_ = std::move(implementation); channel_ = channel; - queue_ = queue; + queue_ = std::move(queue); + channel_fsm_ = std::make_shared(); + flag_enable_fpga = configuration->property("Channel.enable_FPGA", false); acq_->set_channel(channel_); trk_->set_channel(channel_); nav_->set_channel(channel_); + gnss_synchro_ = Gnss_Synchro(); gnss_synchro_.Channel_ID = channel_; acq_->set_gnss_synchro(&gnss_synchro_); trk_->set_gnss_synchro(&gnss_synchro_); + // Provide a warning to the user about the change of parameter name + if (channel_ == 0) + { + int64_t deprecation_warning = configuration->property("GNSS-SDR.internal_fs_hz", 0); + if (deprecation_warning != 0) + { + std::cout << "WARNING: The global parameter name GNSS-SDR.internal_fs_hz has been DEPRECATED." << std::endl; + std::cout << "WARNING: Please replace it by GNSS-SDR.internal_fs_sps in your configuration file." << std::endl; + } + } + // IMPORTANT: Do not change the order between set_doppler_step and set_threshold - unsigned int doppler_step = configuration->property("Acquisition_" + implementation_ + boost::lexical_cast(channel_) + ".doppler_step" ,0); - if(doppler_step == 0) doppler_step = configuration->property("Acquisition_" + implementation_+".doppler_step", 500); - DLOG(INFO) << "Channel "<< channel_ << " Doppler_step = " << doppler_step; + uint32_t doppler_step = configuration->property("Acquisition_" + implementation_ + std::to_string(channel_) + ".doppler_step", 0); + if (doppler_step == 0) doppler_step = configuration->property("Acquisition_" + implementation_ + ".doppler_step", 500); + if (FLAGS_doppler_step != 0) doppler_step = static_cast(FLAGS_doppler_step); + DLOG(INFO) << "Channel " << channel_ << " Doppler_step = " << doppler_step; acq_->set_doppler_step(doppler_step); - float threshold = configuration->property("Acquisition_" + implementation_ + boost::lexical_cast(channel_) + ".threshold", 0.0); - if(threshold == 0.0) threshold = configuration->property("Acquisition_" + implementation_ + ".threshold", 0.0); + float threshold = configuration->property("Acquisition_" + implementation_ + std::to_string(channel_) + ".threshold", 0.0); + if (threshold == 0.0) threshold = configuration->property("Acquisition_" + implementation_ + ".threshold", 0.0); acq_->set_threshold(threshold); acq_->init(); - repeat_ = configuration->property("Acquisition_" + implementation_ + boost::lexical_cast(channel_) + ".repeat_satellite", false); + repeat_ = configuration->property("Acquisition_" + implementation_ + std::to_string(channel_) + ".repeat_satellite", false); DLOG(INFO) << "Channel " << channel_ << " satellite repeat = " << repeat_; - channel_fsm_.set_acquisition(acq_); - channel_fsm_.set_tracking(trk_); - channel_fsm_.set_channel(channel_); - channel_fsm_.set_queue(queue_); + channel_fsm_->set_acquisition(acq_); + channel_fsm_->set_tracking(trk_); + channel_fsm_->set_channel(channel_); + channel_fsm_->set_queue(queue_); connected_ = false; gnss_signal_ = Gnss_Signal(implementation_); - channel_msg_rx = channel_msg_receiver_make_cc(&channel_fsm_, repeat_); - + channel_msg_rx = channel_msg_receiver_make_cc(channel_fsm_, repeat_); } + // Destructor -Channel::~Channel() -{ - channel_fsm_.terminate(); -} +Channel::~Channel() = default; + void Channel::connect(gr::top_block_sptr top_block) { - if (connected_) - { - LOG(WARNING) << "channel already connected internally"; - return; - } - pass_through_->connect(top_block); acq_->connect(top_block); trk_->connect(top_block); nav_->connect(top_block); //Synchronous ports - top_block->connect(pass_through_->get_right_block(), 0, acq_->get_left_block(), 0); - DLOG(INFO) << "pass_through_ -> acquisition"; - top_block->connect(pass_through_->get_right_block(), 0, trk_->get_left_block(), 0); - DLOG(INFO) << "pass_through_ -> tracking"; top_block->connect(trk_->get_right_block(), 0, nav_->get_left_block(), 0); DLOG(INFO) << "tracking -> telemetry_decoder"; // Message ports - top_block->msg_connect(nav_->get_left_block(), pmt::mp("preamble_timestamp_s"), trk_->get_right_block(), pmt::mp("preamble_timestamp_s")); - DLOG(INFO) << "MSG FEEDBACK CHANNEL telemetry_decoder -> tracking"; - - //std::cout<<"has port: "<get_right_block()->has_msg_port(pmt::mp("events"))<msg_connect(acq_->get_right_block(), pmt::mp("events"), channel_msg_rx, pmt::mp("events")); top_block->msg_connect(trk_->get_right_block(), pmt::mp("events"), channel_msg_rx, pmt::mp("events")); @@ -140,10 +133,9 @@ void Channel::disconnect(gr::top_block_sptr top_block) LOG(WARNING) << "Channel already disconnected internally"; return; } - top_block->disconnect(pass_through_->get_right_block(), 0, acq_->get_left_block(), 0); - top_block->disconnect(pass_through_->get_right_block(), 0, trk_->get_left_block(), 0); + top_block->disconnect(trk_->get_right_block(), 0, nav_->get_left_block(), 0); - pass_through_->disconnect(top_block); + acq_->disconnect(top_block); trk_->disconnect(top_block); nav_->disconnect(top_block); @@ -153,9 +145,19 @@ void Channel::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr Channel::get_left_block() { - return pass_through_->get_left_block(); + LOG(ERROR) << "Deprecated call to get_left_block() in channel interface"; + return nullptr; } +gr::basic_block_sptr Channel::get_left_block_trk() +{ + return trk_->get_left_block(); +} + +gr::basic_block_sptr Channel::get_left_block_acq() +{ + return acq_->get_left_block(); +} gr::basic_block_sptr Channel::get_right_block() { @@ -165,11 +167,12 @@ gr::basic_block_sptr Channel::get_right_block() void Channel::set_signal(const Gnss_Signal& gnss_signal) { + std::lock_guard lk(mx); gnss_signal_ = gnss_signal; std::string str_aux = gnss_signal_.get_signal_str(); - const char * str = str_aux.c_str(); // get a C style null terminated string - std::memcpy((void*)gnss_synchro_.Signal, str, 3); // copy string into synchro char array: 2 char + null - gnss_synchro_.Signal[2] = 0; // make sure that string length is only two characters + const char* str = str_aux.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_.Signal), str, 3); // copy string into synchro char array: 2 char + null + gnss_synchro_.Signal[2] = 0; // make sure that string length is only two characters gnss_synchro_.PRN = gnss_signal_.get_satellite().get_PRN(); gnss_synchro_.System = gnss_signal_.get_satellite().get_system_short().c_str()[0]; acq_->set_local_code(); @@ -177,8 +180,28 @@ void Channel::set_signal(const Gnss_Signal& gnss_signal) } -void Channel::start_acquisition() +void Channel::stop_channel() { - channel_fsm_.Event_start_acquisition(); + std::lock_guard lk(mx); + bool result = channel_fsm_->Event_stop_channel(); + if (!result) + { + LOG(WARNING) << "Invalid channel event"; + return; + } + DLOG(INFO) + << "Channel stop_channel()"; } +void Channel::start_acquisition() +{ + std::lock_guard lk(mx); + bool result = false; + result = channel_fsm_->Event_start_acquisition(); + if (!result) + { + LOG(WARNING) << "Invalid channel event"; + return; + } + DLOG(INFO) << "Channel start_acquisition()"; +} diff --git a/src/algorithms/channel/adapters/channel.h b/src/algorithms/channel/adapters/channel.h index 0d2a30431..9eda9e474 100644 --- a/src/algorithms/channel/adapters/channel.h +++ b/src/algorithms/channel/adapters/channel.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,14 +35,15 @@ #ifndef GNSS_SDR_CHANNEL_H_ #define GNSS_SDR_CHANNEL_H_ -#include -#include -#include -#include -#include "channel_interface.h" #include "channel_fsm.h" -#include "gnss_synchro.h" +#include "channel_interface.h" #include "channel_msg_receiver_cc.h" +#include "gnss_synchro.h" +#include +#include +#include +#include +#include class ConfigurationInterface; class AcquisitionInterface; @@ -55,52 +56,53 @@ class TelemetryDecoderInterface; * their interaction through a Finite State Machine * */ -class Channel: public ChannelInterface +class Channel : public ChannelInterface { - public: //! Constructor - Channel(ConfigurationInterface *configuration, unsigned int channel, - std::shared_ptr pass_through, std::shared_ptr acq, - std::shared_ptr trk, std::shared_ptr nav, - std::string role, std::string implementation, - boost::shared_ptr queue); + Channel(ConfigurationInterface* configuration, uint32_t channel, std::shared_ptr acq, + std::shared_ptr trk, std::shared_ptr nav, + std::string role, std::string implementation, gr::msg_queue::sptr queue); //! Virtual destructor virtual ~Channel(); - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string role(){ return role_; } + void connect(gr::top_block_sptr top_block) override; //!< connects the tracking block to the top_block and to the telemetry + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; //!< gets the gnuradio tracking block pointer + gr::basic_block_sptr get_left_block_trk() override; //!< gets the gnuradio tracking block pointer + gr::basic_block_sptr get_left_block_acq() override; //!< gets the gnuradio tracking block pointer + gr::basic_block_sptr get_right_block() override; + + inline std::string role() override { return role_; } //! Returns "Channel" - std::string implementation(){ return implementation_; } - size_t item_size(){ return 0; } - Gnss_Signal get_signal() const { return gnss_signal_; } - std::shared_ptr acquisition(){ return acq_; } - std::shared_ptr tracking(){ return trk_; } - std::shared_ptr telemetry(){ return nav_; } - void start_acquisition(); //!< Start the State Machine - void set_signal(const Gnss_Signal& gnss_signal_); //!< Sets the channel GNSS signal + inline std::string implementation() override { return implementation_; } + inline size_t item_size() override { return 0; } + inline Gnss_Signal get_signal() const override { return gnss_signal_; } + void start_acquisition() override; //!< Start the State Machine + void stop_channel() override; //!< Stop the State Machine + void set_signal(const Gnss_Signal& gnss_signal_) override; //!< Sets the channel GNSS signal + inline std::shared_ptr acquisition() { return acq_; } + inline std::shared_ptr tracking() { return trk_; } + inline std::shared_ptr telemetry() { return nav_; } void msg_handler_events(pmt::pmt_t msg); - private: channel_msg_receiver_cc_sptr channel_msg_rx; - std::shared_ptr pass_through_; std::shared_ptr acq_; std::shared_ptr trk_; std::shared_ptr nav_; std::string role_; std::string implementation_; - unsigned int channel_; + bool flag_enable_fpga; + uint32_t channel_; Gnss_Synchro gnss_synchro_; Gnss_Signal gnss_signal_; bool connected_; bool repeat_; - ChannelFsm channel_fsm_; - boost::shared_ptr queue_; + std::shared_ptr channel_fsm_; + gr::msg_queue::sptr queue_; + std::mutex mx; }; #endif /*GNSS_SDR_CHANNEL_H_*/ diff --git a/src/algorithms/channel/libs/CMakeLists.txt b/src/algorithms/channel/libs/CMakeLists.txt index 40dfdbe26..70bee59f9 100644 --- a/src/algorithms/channel/libs/CMakeLists.txt +++ b/src/algorithms/channel/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,31 +13,36 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(CHANNEL_FSM_SOURCES - channel_fsm.cc +set(CHANNEL_FSM_SOURCES + channel_fsm.cc channel_msg_receiver_cc.cc - ) - -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB CHANNEL_FSM_HEADERS "*.h") +set(CHANNEL_FSM_HEADERS + channel_fsm.h + channel_msg_receiver_cc.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} +) + list(SORT CHANNEL_FSM_HEADERS) +list(SORT CHANNEL_FSM_SOURCES) + add_library(channel_fsm ${CHANNEL_FSM_SOURCES} ${CHANNEL_FSM_HEADERS}) source_group(Headers FILES ${CHANNEL_FSM_HEADERS}) add_dependencies(channel_fsm glog-${glog_RELEASE}) target_link_libraries(channel_fsm gnss_rx) - diff --git a/src/algorithms/channel/libs/channel_fsm.cc b/src/algorithms/channel/libs/channel_fsm.cc index 187d419f4..968ea2393 100644 --- a/src/algorithms/channel/libs/channel_fsm.cc +++ b/src/algorithms/channel/libs/channel_fsm.cc @@ -1,11 +1,12 @@ /*! * \file channel_fsm.cc - * \brief Implementation of a State Machine for channel using boost::statechart - * \author Luis Esteve, 2011. luis(at)epsilon-formacion.com + * \brief Implementation of a State Machine for channel + * \authors Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * Luis Esteve, 2011. luis(at)epsilon-formacion.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,188 +24,171 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "channel_fsm.h" -#include -#include -#include -#include -#include -#include -#include #include "control_message_factory.h" +#include - -struct Ev_channel_start_acquisition: sc::event -{}; - -struct Ev_channel_valid_acquisition: sc::event -{}; - -struct Ev_channel_failed_acquisition_repeat: sc::event -{}; - -struct Ev_channel_failed_acquisition_no_repeat: sc::event -{}; - -struct Ev_channel_failed_tracking_standby: sc::event -{}; - -//struct Ev_channel_failed_tracking_reacq: sc::event -//{}; - -struct channel_idle_fsm_S0: public sc::state -{ -public: - // sc::transition(event, next state) - typedef sc::transition reactions; - channel_idle_fsm_S0(my_context ctx) : my_base(ctx) - { - //std::cout << "Enter Channel_Idle_S0 " << std::endl; - } -}; - - -struct channel_acquiring_fsm_S1: public sc::state -{ -public: - typedef mpl::list, - sc::transition, - sc::transition > reactions; - - channel_acquiring_fsm_S1(my_context ctx) : my_base(ctx) - { - //std::cout << "Enter Channel_Acq_S1 " << std::endl; - context ().start_acquisition(); - } - ~channel_acquiring_fsm_S1() - { - //std::cout << "Exit Channel_Acq_S1 " << std::endl; - } -}; - - -struct channel_tracking_fsm_S2: public sc::state -{ -public: - typedef mpl::list, - sc::transition> reactions; - - channel_tracking_fsm_S2(my_context ctx) : my_base(ctx) - { - //std::cout << "Enter Channel_tracking_S2 " << std::endl; - context ().start_tracking(); - } - - ~channel_tracking_fsm_S2() - { - //std::cout << "Exit Channel_tracking_S2 " << std::endl; - context ().notify_stop_tracking(); - } - -}; - - -struct channel_waiting_fsm_S3: public sc::state -{ -public: - typedef sc::transition reactions; - - channel_waiting_fsm_S3(my_context ctx) : - my_base(ctx) - { - //std::cout << "Enter Channel_waiting_S3 " << std::endl; - context ().request_satellite(); - } - // ~channel_waiting_fsm_S3(){} -}; - - +using google::LogMessage; ChannelFsm::ChannelFsm() { acq_ = nullptr; trk_ = nullptr; - channel_ = 0; - initiate(); //start the FSM + channel_ = 0U; + d_state = 0U; } - -ChannelFsm::ChannelFsm(std::shared_ptr acquisition) : - acq_(acquisition) +ChannelFsm::ChannelFsm(std::shared_ptr acquisition) : acq_(std::move(acquisition)) { trk_ = nullptr; - channel_ = 0; - initiate(); //start the FSM + channel_ = 0U; + d_state = 0U; } - -void ChannelFsm::Event_start_acquisition() +bool ChannelFsm::Event_stop_channel() { - this->process_event(Ev_channel_start_acquisition()); - //std::cout<<"Ev_channel_start_acquisition launched"< lk(mx); + DLOG(INFO) << "CH = " << channel_ << ". Ev stop channel"; + switch (d_state) + { + case 0: //already in stanby + break; + case 1: //acquisition + d_state = 0; + stop_acquisition(); + break; + case 2: //tracking + d_state = 0; + stop_tracking(); + break; + default: + break; + } + return true; } - -void ChannelFsm::Event_valid_acquisition() +bool ChannelFsm::Event_start_acquisition() { - this->process_event(Ev_channel_valid_acquisition()); + std::lock_guard lk(mx); + if ((d_state == 1) || (d_state == 2)) + { + return false; + } + d_state = 1; + start_acquisition(); + DLOG(INFO) << "CH = " << channel_ << ". Ev start acquisition"; + return true; } -void ChannelFsm::Event_failed_acquisition_repeat() +bool ChannelFsm::Event_valid_acquisition() { - this->process_event(Ev_channel_failed_acquisition_repeat()); + std::lock_guard lk(mx); + if (d_state != 1) + { + return false; + } + d_state = 2; + start_tracking(); + DLOG(INFO) << "CH = " << channel_ << ". Ev valid acquisition"; + return true; } -void ChannelFsm::Event_failed_acquisition_no_repeat() + +bool ChannelFsm::Event_failed_acquisition_repeat() { - this->process_event(Ev_channel_failed_acquisition_no_repeat()); + std::lock_guard lk(mx); + if (d_state != 1) + { + return false; + } + d_state = 1; + start_acquisition(); + DLOG(INFO) << "CH = " << channel_ << ". Ev failed acquisition repeat"; + return true; } -// Something is wrong here, we are using a memory after it ts freed -void ChannelFsm::Event_failed_tracking_standby() +bool ChannelFsm::Event_failed_acquisition_no_repeat() { - this->process_event(Ev_channel_failed_tracking_standby()); + std::lock_guard lk(mx); + if (d_state != 1) + { + return false; + } + d_state = 3; + request_satellite(); + DLOG(INFO) << "CH = " << channel_ << ". Ev failed acquisition no repeat"; + return true; +} + + +bool ChannelFsm::Event_failed_tracking_standby() +{ + std::lock_guard lk(mx); + if (d_state != 2) + { + return false; + } + d_state = 0U; + notify_stop_tracking(); + DLOG(INFO) << "CH = " << channel_ << ". Ev failed tracking standby"; + return true; } -//void ChannelFsm::Event_failed_tracking_reacq() { -// this->process_event(Ev_channel_failed_tracking_reacq()); -//} void ChannelFsm::set_acquisition(std::shared_ptr acquisition) { - acq_ = acquisition; + std::lock_guard lk(mx); + acq_ = std::move(acquisition); } + void ChannelFsm::set_tracking(std::shared_ptr tracking) { - trk_ = tracking; + std::lock_guard lk(mx); + trk_ = std::move(tracking); } -void ChannelFsm::set_queue(boost::shared_ptr queue) + +void ChannelFsm::set_queue(gr::msg_queue::sptr queue) { - queue_ = queue; + std::lock_guard lk(mx); + queue_ = std::move(queue); } -void ChannelFsm::set_channel(unsigned int channel) + +void ChannelFsm::set_channel(uint32_t channel) { + std::lock_guard lk(mx); channel_ = channel; } + +void ChannelFsm::stop_acquisition() +{ + acq_->stop_acquisition(); +} + +void ChannelFsm::stop_tracking() +{ + trk_->stop_tracking(); +} + + void ChannelFsm::start_acquisition() { acq_->reset(); } + void ChannelFsm::start_tracking() { trk_->start_tracking(); @@ -215,6 +199,7 @@ void ChannelFsm::start_tracking() } } + void ChannelFsm::request_satellite() { std::unique_ptr cmf(new ControlMessageFactory()); @@ -224,6 +209,7 @@ void ChannelFsm::request_satellite() } } + void ChannelFsm::notify_stop_tracking() { std::unique_ptr cmf(new ControlMessageFactory()); diff --git a/src/algorithms/channel/libs/channel_fsm.h b/src/algorithms/channel/libs/channel_fsm.h index 868388b7b..2ecc6eb20 100644 --- a/src/algorithms/channel/libs/channel_fsm.h +++ b/src/algorithms/channel/libs/channel_fsm.h @@ -1,12 +1,12 @@ /*! * \file channel_fsm.h - * \brief Interface of the State Machine for channel using boost::statechart - * \author Luis Esteve, 2011. luis(at)epsilon-formacion.com - * + * \brief Interface of the State Machine for channel + * \authors Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * Luis Esteve, 2011. luis(at)epsilon-formacion.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,26 +32,19 @@ #ifndef GNSS_SDR_CHANNEL_FSM_H #define GNSS_SDR_CHANNEL_FSM_H - -#include -#include #include "acquisition_interface.h" -#include "tracking_interface.h" #include "telemetry_decoder_interface.h" +#include "tracking_interface.h" +#include +#include +#include +#include -namespace sc = boost::statechart; -namespace mpl = boost::mpl; - -struct channel_idle_fsm_S0; -struct channel_acquiring_fsm_S1; -struct channel_tracking_fsm_S2; -struct channel_waiting_fsm_S3; - /*! - * \brief This class implements a State Machine for channel using boost::statechart + * \brief This class implements a State Machine for channel */ -class ChannelFsm: public sc::state_machine +class ChannelFsm { public: ChannelFsm(); @@ -59,26 +52,31 @@ public: void set_acquisition(std::shared_ptr acquisition); void set_tracking(std::shared_ptr tracking); - void set_queue(boost::shared_ptr queue); - void set_channel(unsigned int channel); + void set_queue(gr::msg_queue::sptr queue); + void set_channel(uint32_t channel); + + //FSM EVENTS + bool Event_start_acquisition(); + bool Event_valid_acquisition(); + bool Event_stop_channel(); + bool Event_failed_acquisition_repeat(); + bool Event_failed_acquisition_no_repeat(); + bool Event_failed_tracking_standby(); + +private: void start_acquisition(); void start_tracking(); + void stop_acquisition(); + void stop_tracking(); void request_satellite(); void notify_stop_tracking(); - //FSM EVENTS - void Event_start_acquisition(); - void Event_valid_acquisition(); - void Event_failed_acquisition_repeat(); - void Event_failed_acquisition_no_repeat(); - //void Event_gps_failed_tracking_reacq(); - void Event_failed_tracking_standby(); - -private: std::shared_ptr acq_; std::shared_ptr trk_; - boost::shared_ptr queue_; - unsigned int channel_; + gr::msg_queue::sptr queue_; + uint32_t channel_; + uint32_t d_state; + std::mutex mx; }; #endif /*GNSS_SDR_CHANNEL_FSM_H*/ diff --git a/src/algorithms/channel/libs/channel_msg_receiver_cc.cc b/src/algorithms/channel/libs/channel_msg_receiver_cc.cc index 61b409c5c..82333e6a7 100644 --- a/src/algorithms/channel/libs/channel_msg_receiver_cc.cc +++ b/src/algorithms/channel/libs/channel_msg_receiver_cc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,75 +23,75 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "channel_msg_receiver_cc.h" +#include #include #include -#include +#include using google::LogMessage; -channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(ChannelFsm* channel_fsm, bool repeat) +channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(std::shared_ptr channel_fsm, bool repeat) { - return channel_msg_receiver_cc_sptr(new channel_msg_receiver_cc(channel_fsm, repeat)); + return channel_msg_receiver_cc_sptr(new channel_msg_receiver_cc(std::move(channel_fsm), repeat)); } + void channel_msg_receiver_cc::msg_handler_events(pmt::pmt_t msg) { + bool result = false; try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(std::move(msg)); switch (message) - { - case 1: //positive acquisition - //DLOG(INFO) << "Channel " << channel_ << " ACQ SUCCESS satellite " << - // gnss_synchro_.System << " " << gnss_synchro_.PRN; - d_channel_fsm->Event_valid_acquisition(); - break; - case 2: //negative acquisition - //DLOG(INFO) << "Channel " << channel_ - // << " ACQ FAILED satellite " << gnss_synchro_.System << " " << gnss_synchro_.PRN; - if (d_repeat == true) - { - d_channel_fsm->Event_failed_acquisition_repeat(); - } - else - { - d_channel_fsm->Event_failed_acquisition_no_repeat(); - } - break; - case 3: // tracking loss of lock event - d_channel_fsm->Event_failed_tracking_standby(); - break; - default: - LOG(WARNING) << "Default case, invalid message."; - break; - } - } - catch(boost::bad_any_cast& e) - { + { + case 1: // positive acquisition + result = d_channel_fsm->Event_valid_acquisition(); + break; + case 2: // negative acquisition + if (d_repeat == true) + { + result = d_channel_fsm->Event_failed_acquisition_repeat(); + } + else + { + result = d_channel_fsm->Event_failed_acquisition_no_repeat(); + } + break; + case 3: // tracking loss of lock event + result = d_channel_fsm->Event_failed_tracking_standby(); + break; + default: + LOG(WARNING) << "Default case, invalid message."; + break; + } + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; - } + } + if (!result) + { + LOG(WARNING) << "msg_handler_telemetry invalid event"; + } } -channel_msg_receiver_cc::channel_msg_receiver_cc(ChannelFsm* channel_fsm, bool repeat) : - gr::block("channel_msg_receiver_cc", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +channel_msg_receiver_cc::channel_msg_receiver_cc(std::shared_ptr channel_fsm, bool repeat) : gr::block("channel_msg_receiver_cc", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&channel_msg_receiver_cc::msg_handler_events, this, _1)); - d_channel_fsm = channel_fsm; + d_channel_fsm = std::move(channel_fsm); d_repeat = repeat; } -channel_msg_receiver_cc::~channel_msg_receiver_cc() -{} - +channel_msg_receiver_cc::~channel_msg_receiver_cc() = default; diff --git a/src/algorithms/channel/libs/channel_msg_receiver_cc.h b/src/algorithms/channel/libs/channel_msg_receiver_cc.h index 195d41e7c..7fc172923 100644 --- a/src/algorithms/channel/libs/channel_msg_receiver_cc.h +++ b/src/algorithms/channel/libs/channel_msg_receiver_cc.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,14 +31,14 @@ #ifndef GNSS_SDR_CHANNEL_MSG_RECEIVER_CC_H #define GNSS_SDR_CHANNEL_MSG_RECEIVER_CC_H -#include #include "channel_fsm.h" +#include class channel_msg_receiver_cc; typedef boost::shared_ptr channel_msg_receiver_cc_sptr; -channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(ChannelFsm* channel_fsm, bool repeat); +channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(std::shared_ptr channel_fsm, bool repeat); /*! * \brief GNU Radio block that receives asynchronous channel messages from acquisition and tracking blocks @@ -46,15 +46,14 @@ channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(ChannelFsm* channel_fs class channel_msg_receiver_cc : public gr::block { private: - ChannelFsm* d_channel_fsm; - bool d_repeat; // todo: change FSM to include repeat value - friend channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(ChannelFsm* channel_fsm, bool repeat); + std::shared_ptr d_channel_fsm; + bool d_repeat; // todo: change FSM to include repeat value + friend channel_msg_receiver_cc_sptr channel_msg_receiver_make_cc(std::shared_ptr channel_fsm, bool repeat); void msg_handler_events(pmt::pmt_t msg); - channel_msg_receiver_cc(ChannelFsm* channel_fsm, bool repeat); + channel_msg_receiver_cc(std::shared_ptr channel_fsm, bool repeat); public: - ~channel_msg_receiver_cc (); //!< Default destructor - + ~channel_msg_receiver_cc(); //!< Default destructor }; #endif diff --git a/src/algorithms/conditioner/CMakeLists.txt b/src/algorithms/conditioner/CMakeLists.txt index c0a4a7a48..166f27d36 100644 --- a/src/algorithms/conditioner/CMakeLists.txt +++ b/src/algorithms/conditioner/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,8 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) -#add_subdirectory(gnuradio_blocks) \ No newline at end of file diff --git a/src/algorithms/conditioner/adapters/CMakeLists.txt b/src/algorithms/conditioner/adapters/CMakeLists.txt index 371a78dc8..38d606824 100644 --- a/src/algorithms/conditioner/adapters/CMakeLists.txt +++ b/src/algorithms/conditioner/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,29 +13,35 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(COND_ADAPTER_SOURCES - signal_conditioner.cc - array_signal_conditioner.cc +set(COND_ADAPTER_SOURCES + signal_conditioner.cc + array_signal_conditioner.cc +) + +set(COND_ADAPTER_HEADERS + signal_conditioner.h + array_signal_conditioner.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB COND_ADAPTER_HEADERS "*.h") list(SORT COND_ADAPTER_HEADERS) +list(SORT COND_ADAPTER_SOURCES) + add_library(conditioner_adapters ${COND_ADAPTER_SOURCES} ${COND_ADAPTER_HEADERS}) source_group(Headers FILES ${COND_ADAPTER_HEADERS}) -add_dependencies(conditioner_adapters glog-${glog_RELEASE}) \ No newline at end of file +add_dependencies(conditioner_adapters glog-${glog_RELEASE}) diff --git a/src/algorithms/conditioner/adapters/array_signal_conditioner.cc b/src/algorithms/conditioner/adapters/array_signal_conditioner.cc index 7e378516d..55970c4d7 100644 --- a/src/algorithms/conditioner/adapters/array_signal_conditioner.cc +++ b/src/algorithms/conditioner/adapters/array_signal_conditioner.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,32 +24,39 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "array_signal_conditioner.h" #include +#include using google::LogMessage; // Constructor ArraySignalConditioner::ArraySignalConditioner(ConfigurationInterface *configuration, - std::shared_ptr data_type_adapt, std::shared_ptr in_filt, - std::shared_ptr res, std::string role, std::string implementation) : - data_type_adapt_(data_type_adapt), - in_filt_(in_filt), res_(res), role_(role), implementation_(implementation) + std::shared_ptr data_type_adapt, + std::shared_ptr in_filt, + std::shared_ptr res, + std::string role, + std::string implementation) : data_type_adapt_(std::move(data_type_adapt)), + in_filt_(std::move(in_filt)), + res_(std::move(res)), + role_(std::move(role)), + implementation_(std::move(implementation)) { connected_ = false; - if(configuration){ }; + if (configuration) + { + }; } // Destructor -ArraySignalConditioner::~ArraySignalConditioner() -{} +ArraySignalConditioner::~ArraySignalConditioner() = default; void ArraySignalConditioner::connect(gr::top_block_sptr top_block) @@ -68,7 +75,7 @@ void ArraySignalConditioner::connect(gr::top_block_sptr top_block) //DLOG(INFO) << "data_type_adapter -> input_filter"; top_block->connect(in_filt_->get_right_block(), 0, - res_->get_left_block(), 0); + res_->get_left_block(), 0); DLOG(INFO) << "Array input_filter -> resampler"; @@ -76,7 +83,6 @@ void ArraySignalConditioner::connect(gr::top_block_sptr top_block) } - void ArraySignalConditioner::disconnect(gr::top_block_sptr top_block) { if (!connected_) @@ -88,7 +94,7 @@ void ArraySignalConditioner::disconnect(gr::top_block_sptr top_block) //top_block->disconnect(data_type_adapt_->get_right_block(), 0, // in_filt_->get_left_block(), 0); top_block->disconnect(in_filt_->get_right_block(), 0, - res_->get_left_block(), 0); + res_->get_left_block(), 0); //data_type_adapt_->disconnect(top_block); in_filt_->disconnect(top_block); @@ -105,9 +111,7 @@ gr::basic_block_sptr ArraySignalConditioner::get_left_block() } - gr::basic_block_sptr ArraySignalConditioner::get_right_block() { return res_->get_right_block(); } - diff --git a/src/algorithms/conditioner/adapters/array_signal_conditioner.h b/src/algorithms/conditioner/adapters/array_signal_conditioner.h index d0f100402..76809be53 100644 --- a/src/algorithms/conditioner/adapters/array_signal_conditioner.h +++ b/src/algorithms/conditioner/adapters/array_signal_conditioner.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,9 +33,9 @@ #define GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_H_ -#include -#include #include "gnss_block_interface.h" +#include +#include class ConfigurationInterface; @@ -47,30 +47,30 @@ class TelemetryDecoderInterface; * \brief This class wraps blocks to change data_type_adapter, input_filter and resampler * to be applied to the input flow of sampled signal. */ -class ArraySignalConditioner: public GNSSBlockInterface +class ArraySignalConditioner : public GNSSBlockInterface { public: //! Constructor ArraySignalConditioner(ConfigurationInterface *configuration, - std::shared_ptr data_type_adapt, std::shared_ptr in_filt, - std::shared_ptr res, std::string role, std::string implementation); + std::shared_ptr data_type_adapt, std::shared_ptr in_filt, + std::shared_ptr res, std::string role, std::string implementation); //! Virtual destructor virtual ~ArraySignalConditioner(); - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; - std::string role(){ return role_; } - //! Returns "Signal_Conditioner" - std::string implementation(){ return "Array_Signal_Conditioner"; } - size_t item_size(){ return 0; } + inline std::string role() override { return role_; } + //! Returns "Array_Signal_Conditioner" + inline std::string implementation() override { return "Array_Signal_Conditioner"; } + inline size_t item_size() override { return 0; } - std::shared_ptr data_type_adapter(){ return data_type_adapt_; } - std::shared_ptr input_filter(){ return in_filt_; } - std::shared_ptr resampler(){ return res_; } + inline std::shared_ptr data_type_adapter() { return data_type_adapt_; } + inline std::shared_ptr input_filter() { return in_filt_; } + inline std::shared_ptr resampler() { return res_; } private: std::shared_ptr data_type_adapt_; @@ -79,7 +79,6 @@ private: std::string role_; std::string implementation_; bool connected_; - //bool stop_; }; #endif /*GNSS_SDR_SIGNAL_CONDITIONER_H_*/ diff --git a/src/algorithms/conditioner/adapters/signal_conditioner.cc b/src/algorithms/conditioner/adapters/signal_conditioner.cc index 962b0dac7..e55ba9e1a 100644 --- a/src/algorithms/conditioner/adapters/signal_conditioner.cc +++ b/src/algorithms/conditioner/adapters/signal_conditioner.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,32 +24,39 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "signal_conditioner.h" #include +#include using google::LogMessage; // Constructor SignalConditioner::SignalConditioner(ConfigurationInterface *configuration, - std::shared_ptr data_type_adapt, std::shared_ptr in_filt, - std::shared_ptr res, std::string role, std::string implementation) : - data_type_adapt_(data_type_adapt), - in_filt_(in_filt), res_(res), role_(role), implementation_(implementation) + std::shared_ptr data_type_adapt, + std::shared_ptr in_filt, + std::shared_ptr res, + std::string role, + std::string implementation) : data_type_adapt_(std::move(data_type_adapt)), + in_filt_(std::move(in_filt)), + res_(std::move(res)), + role_(std::move(role)), + implementation_(std::move(implementation)) { connected_ = false; - if(configuration){ }; + if (configuration) + { + }; } // Destructor -SignalConditioner::~SignalConditioner() -{} +SignalConditioner::~SignalConditioner() = default; void SignalConditioner::connect(gr::top_block_sptr top_block) @@ -81,9 +88,9 @@ void SignalConditioner::disconnect(gr::top_block_sptr top_block) } top_block->disconnect(data_type_adapt_->get_right_block(), 0, - in_filt_->get_left_block(), 0); + in_filt_->get_left_block(), 0); top_block->disconnect(in_filt_->get_right_block(), 0, - res_->get_left_block(), 0); + res_->get_left_block(), 0); data_type_adapt_->disconnect(top_block); in_filt_->disconnect(top_block); @@ -98,8 +105,8 @@ gr::basic_block_sptr SignalConditioner::get_left_block() return data_type_adapt_->get_left_block(); } + gr::basic_block_sptr SignalConditioner::get_right_block() { return res_->get_right_block(); } - diff --git a/src/algorithms/conditioner/adapters/signal_conditioner.h b/src/algorithms/conditioner/adapters/signal_conditioner.h index de830368d..85dc8396c 100644 --- a/src/algorithms/conditioner/adapters/signal_conditioner.h +++ b/src/algorithms/conditioner/adapters/signal_conditioner.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,8 @@ #ifndef GNSS_SDR_SIGNAL_CONDITIONER_H_ #define GNSS_SDR_SIGNAL_CONDITIONER_H_ -#include #include "gnss_block_interface.h" - +#include class ConfigurationInterface; class AcquisitionInterface; @@ -45,30 +44,31 @@ class TelemetryDecoderInterface; * \brief This class wraps blocks to change data_type_adapter, input_filter and resampler * to be applied to the input flow of sampled signal. */ -class SignalConditioner: public GNSSBlockInterface +class SignalConditioner : public GNSSBlockInterface { public: //! Constructor SignalConditioner(ConfigurationInterface *configuration, - std::shared_ptr data_type_adapt, std::shared_ptr in_filt, - std::shared_ptr res, std::string role, std::string implementation); + std::shared_ptr data_type_adapt, std::shared_ptr in_filt, + std::shared_ptr res, std::string role, std::string implementation); //! Virtual destructor virtual ~SignalConditioner(); - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; - std::string role(){ return role_; } - //! Returns "Signal_Conditioner" - std::string implementation(){ return "Signal_Conditioner"; } - size_t item_size(){ return 0; } + inline std::string role() override { return role_; } - std::shared_ptr data_type_adapter(){ return data_type_adapt_; } - std::shared_ptr input_filter(){ return in_filt_; } - std::shared_ptr resampler(){ return res_; } + inline std::string implementation() override { return "Signal_Conditioner"; } //!< Returns "Signal_Conditioner" + + inline size_t item_size() override { return 0; } + + inline std::shared_ptr data_type_adapter() { return data_type_adapt_; } + inline std::shared_ptr input_filter() { return in_filt_; } + inline std::shared_ptr resampler() { return res_; } private: std::shared_ptr data_type_adapt_; @@ -77,7 +77,6 @@ private: std::string role_; std::string implementation_; bool connected_; - //bool stop_; }; #endif /*GNSS_SDR_SIGNAL_CONDITIONER_H_*/ diff --git a/src/algorithms/data_type_adapter/CMakeLists.txt b/src/algorithms/data_type_adapter/CMakeLists.txt index 5724f1d42..1c15cc0ca 100644 --- a/src/algorithms/data_type_adapter/CMakeLists.txt +++ b/src/algorithms/data_type_adapter/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -14,9 +14,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) add_subdirectory(gnuradio_blocks) - diff --git a/src/algorithms/data_type_adapter/adapters/CMakeLists.txt b/src/algorithms/data_type_adapter/adapters/CMakeLists.txt index 659ebf728..1977f7a5a 100644 --- a/src/algorithms/data_type_adapter/adapters/CMakeLists.txt +++ b/src/algorithms/data_type_adapter/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,34 +13,52 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(DATATYPE_ADAPTER_SOURCES +set(DATATYPE_ADAPTER_SOURCES byte_to_short.cc ibyte_to_cbyte.cc ibyte_to_complex.cc ibyte_to_cshort.cc ishort_to_cshort.cc - ishort_to_complex.cc - ) - -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ishort_to_complex.cc +) + +set(DATATYPE_ADAPTER_HEADERS + byte_to_short.h + ibyte_to_cbyte.h + ibyte_to_complex.h + ibyte_to_cshort.h + ishort_to_cshort.h + ishort_to_complex.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) -file(GLOB DATATYPE_ADAPTER_HEADERS "*.h") list(SORT DATATYPE_ADAPTER_HEADERS) -add_library(datatype_adapters ${DATATYPE_ADAPTER_SOURCES} ${DATATYPE_ADAPTER_HEADERS}) +list(SORT DATATYPE_ADAPTER_SOURCES) + +add_library(datatype_adapters + ${DATATYPE_ADAPTER_SOURCES} + ${DATATYPE_ADAPTER_HEADERS} +) + source_group(Headers FILES ${DATATYPE_ADAPTER_HEADERS}) add_dependencies(datatype_adapters glog-${glog_RELEASE}) -target_link_libraries(datatype_adapters data_type_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES}) - +target_link_libraries(datatype_adapters + data_type_gr_blocks + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} +) diff --git a/src/algorithms/data_type_adapter/adapters/byte_to_short.cc b/src/algorithms/data_type_adapter/adapters/byte_to_short.cc index 75df4f1e3..b89fec1ed 100644 --- a/src/algorithms/data_type_adapter/adapters/byte_to_short.cc +++ b/src/algorithms/data_type_adapter/adapters/byte_to_short.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,21 +23,22 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "byte_to_short.h" -#include #include "configuration_interface.h" +#include +#include +#include + using google::LogMessage; ByteToShort::ByteToShort(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "byte"; std::string default_output_item_type = "short"; @@ -50,7 +51,7 @@ ByteToShort::ByteToShort(ConfigurationInterface* configuration, std::string role dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); - size_t item_size = sizeof(short); + size_t item_size = sizeof(int16_t); gr_char_to_short_ = gr::blocks::char_to_short::make(); @@ -61,11 +62,18 @@ ByteToShort::ByteToShort(ConfigurationInterface* configuration, std::string role DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -ByteToShort::~ByteToShort() -{} +ByteToShort::~ByteToShort() = default; void ByteToShort::connect(gr::top_block_sptr top_block) @@ -90,16 +98,13 @@ void ByteToShort::disconnect(gr::top_block_sptr top_block) } - gr::basic_block_sptr ByteToShort::get_left_block() { return gr_char_to_short_; } - gr::basic_block_sptr ByteToShort::get_right_block() { return gr_char_to_short_; } - diff --git a/src/algorithms/data_type_adapter/adapters/byte_to_short.h b/src/algorithms/data_type_adapter/adapters/byte_to_short.h index ff241d5ce..9b90f1d3b 100644 --- a/src/algorithms/data_type_adapter/adapters/byte_to_short.h +++ b/src/algorithms/data_type_adapter/adapters/byte_to_short.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,10 @@ #ifndef GNSS_SDR_BYTE_TO_SHORT_H_ #define GNSS_SDR_BYTE_TO_SHORT_H_ -#include +#include "gnss_block_interface.h" #include #include -#include "gnss_block_interface.h" - +#include class ConfigurationInterface; @@ -43,33 +42,35 @@ class ConfigurationInterface; * \brief Adapts an 8-bits sample stream (IF) to a short int stream (IF) * */ -class ByteToShort: public GNSSBlockInterface +class ByteToShort : public GNSSBlockInterface { public: ByteToShort(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + std::string role, unsigned int in_streams, + unsigned int out_streams); virtual ~ByteToShort(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Byte_To_Short" - std::string implementation() + inline std::string implementation() override { return "Byte_To_Short"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: gr::blocks::char_to_short::sptr gr_char_to_short_; @@ -85,4 +86,3 @@ private: }; #endif - diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.cc b/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.cc index 8dc47c8ad..5cfbd4186 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.cc +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,22 +24,20 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ibyte_to_cbyte.h" -#include -#include #include "configuration_interface.h" +#include +#include using google::LogMessage; -IbyteToCbyte::IbyteToCbyte(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) +IbyteToCbyte::IbyteToCbyte(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "byte"; std::string default_output_item_type = "lv_8sc_t"; @@ -51,6 +49,7 @@ IbyteToCbyte::IbyteToCbyte(ConfigurationInterface* configuration, std::string ro dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); size_t item_size = sizeof(lv_8sc_t); @@ -63,18 +62,48 @@ IbyteToCbyte::IbyteToCbyte(ConfigurationInterface* configuration, std::string ro DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (inverted_spectrum) + { + conjugate_ic_ = make_conjugate_ic(); + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -IbyteToCbyte::~IbyteToCbyte() -{} +IbyteToCbyte::~IbyteToCbyte() = default; void IbyteToCbyte::connect(gr::top_block_sptr top_block) { if (dump_) { - top_block->connect(ibyte_to_cbyte_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->connect(ibyte_to_cbyte_, 0, conjugate_ic_, 0); + top_block->connect(conjugate_ic_, 0, file_sink_, 0); + } + else + { + top_block->connect(ibyte_to_cbyte_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->connect(ibyte_to_cbyte_, 0, conjugate_ic_, 0); + } + else + { + DLOG(INFO) << "Nothing to connect internally"; + } } } @@ -83,21 +112,37 @@ void IbyteToCbyte::disconnect(gr::top_block_sptr top_block) { if (dump_) { - top_block->disconnect(ibyte_to_cbyte_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->disconnect(ibyte_to_cbyte_, 0, conjugate_ic_, 0); + top_block->disconnect(conjugate_ic_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(ibyte_to_cbyte_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->disconnect(ibyte_to_cbyte_, 0, conjugate_ic_, 0); + } } } - gr::basic_block_sptr IbyteToCbyte::get_left_block() { return ibyte_to_cbyte_; } - gr::basic_block_sptr IbyteToCbyte::get_right_block() { + if (inverted_spectrum) + { + return conjugate_ic_; + } return ibyte_to_cbyte_; } - diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.h b/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.h index 5eafe5587..3fb202a1a 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.h +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_cbyte.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,11 +32,11 @@ #ifndef GNSS_SDR_IBYTE_TO_CBYTE_H_ #define GNSS_SDR_IBYTE_TO_CBYTE_H_ -#include -#include +#include "conjugate_ic.h" #include "gnss_block_interface.h" #include "interleaved_byte_to_complex_byte.h" - +#include +#include class ConfigurationInterface; @@ -48,29 +48,31 @@ class IbyteToCbyte : public GNSSBlockInterface { public: IbyteToCbyte(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, unsigned int in_streams, + unsigned int out_streams); virtual ~IbyteToCbyte(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Ibyte_To_Cbyte" - std::string implementation() + inline std::string implementation() override { return "Ibyte_To_Cbyte"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: interleaved_byte_to_complex_byte_sptr ibyte_to_cbyte_; @@ -83,6 +85,8 @@ private: unsigned int in_streams_; unsigned int out_streams_; gr::blocks::file_sink::sptr file_sink_; + conjugate_ic_sptr conjugate_ic_; + bool inverted_spectrum; }; #endif diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.cc b/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.cc index 6119ebd9f..cd8c14850 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.cc +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,21 +23,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ibyte_to_complex.h" -#include #include "configuration_interface.h" +#include using google::LogMessage; -IbyteToComplex::IbyteToComplex(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) +IbyteToComplex::IbyteToComplex(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "byte"; std::string default_output_item_type = "gr_complex"; @@ -49,6 +47,7 @@ IbyteToComplex::IbyteToComplex(ConfigurationInterface* configuration, std::strin dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); size_t item_size = sizeof(gr_complex); @@ -56,23 +55,53 @@ IbyteToComplex::IbyteToComplex(ConfigurationInterface* configuration, std::strin DLOG(INFO) << "data_type_adapter_(" << gr_interleaved_char_to_complex_->unique_id() << ")"; + if (inverted_spectrum) + { + conjugate_cc_ = make_conjugate_cc(); + } if (dump_) { DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -IbyteToComplex::~IbyteToComplex() -{} +IbyteToComplex::~IbyteToComplex() = default; void IbyteToComplex::connect(gr::top_block_sptr top_block) { if (dump_) { - top_block->connect(gr_interleaved_char_to_complex_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->connect(gr_interleaved_char_to_complex_, 0, conjugate_cc_, 0); + top_block->connect(conjugate_cc_, 0, file_sink_, 0); + } + else + { + top_block->connect(gr_interleaved_char_to_complex_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->connect(gr_interleaved_char_to_complex_, 0, conjugate_cc_, 0); + } + else + { + DLOG(INFO) << "Nothing to connect internally"; + } } } @@ -81,22 +110,37 @@ void IbyteToComplex::disconnect(gr::top_block_sptr top_block) { if (dump_) { - top_block->disconnect(gr_interleaved_char_to_complex_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->disconnect(gr_interleaved_char_to_complex_, 0, conjugate_cc_, 0); + top_block->disconnect(conjugate_cc_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(gr_interleaved_char_to_complex_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->disconnect(gr_interleaved_char_to_complex_, 0, conjugate_cc_, 0); + } } } - gr::basic_block_sptr IbyteToComplex::get_left_block() { return gr_interleaved_char_to_complex_; } - gr::basic_block_sptr IbyteToComplex::get_right_block() { + if (inverted_spectrum) + { + return conjugate_cc_; + } return gr_interleaved_char_to_complex_; } - - diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.h b/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.h index 228e15435..9271689bc 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.h +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_complex.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,12 +31,12 @@ #ifndef GNSS_SDR_IBYTE_TO_COMPLEX_H_ #define GNSS_SDR_IBYTE_TO_COMPLEX_H_ -#include -#include -#include -#include "gnss_synchro.h" +#include "conjugate_cc.h" #include "gnss_block_interface.h" - +#include "gnss_synchro.h" +#include +#include +#include class ConfigurationInterface; @@ -44,33 +44,35 @@ class ConfigurationInterface; * \brief Adapts an I/Q interleaved byte integer sample stream to a gr_complex (float) stream * */ -class IbyteToComplex: public GNSSBlockInterface +class IbyteToComplex : public GNSSBlockInterface { public: IbyteToComplex(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, unsigned int in_streams, + unsigned int out_streams); virtual ~IbyteToComplex(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Ibyte_To_Complex" - std::string implementation() + inline std::string implementation() override { return "Ibyte_To_Complex"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex_; @@ -83,8 +85,8 @@ private: unsigned int in_streams_; unsigned int out_streams_; gr::blocks::file_sink::sptr file_sink_; + conjugate_cc_sptr conjugate_cc_; + bool inverted_spectrum; }; #endif - - diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.cc b/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.cc index 206f824cc..f4c8b6207 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.cc +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,22 +24,21 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ibyte_to_cshort.h" +#include "configuration_interface.h" #include #include -#include "configuration_interface.h" + using google::LogMessage; -IbyteToCshort::IbyteToCshort(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) +IbyteToCshort::IbyteToCshort(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "byte"; std::string default_output_item_type = "cshort"; @@ -51,30 +50,57 @@ IbyteToCshort::IbyteToCshort(ConfigurationInterface* configuration, std::string dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); size_t item_size = sizeof(lv_16sc_t); interleaved_byte_to_complex_short_ = make_interleaved_byte_to_complex_short(); - DLOG(INFO) << "data_type_adapter_(" << interleaved_byte_to_complex_short_->unique_id()<<")"; + DLOG(INFO) << "data_type_adapter_(" << interleaved_byte_to_complex_short_->unique_id() << ")"; if (dump_) { DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (inverted_spectrum) + { + conjugate_sc_ = make_conjugate_sc(); + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -IbyteToCshort::~IbyteToCshort() -{} +IbyteToCshort::~IbyteToCshort() = default; void IbyteToCshort::connect(gr::top_block_sptr top_block) { if (dump_) { - top_block->connect(interleaved_byte_to_complex_short_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->connect(interleaved_byte_to_complex_short_, 0, conjugate_sc_, 0); + top_block->connect(conjugate_sc_, 0, file_sink_, 0); + } + else + { + top_block->connect(interleaved_byte_to_complex_short_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->connect(interleaved_byte_to_complex_short_, 0, conjugate_sc_, 0); + } } } @@ -83,22 +109,37 @@ void IbyteToCshort::disconnect(gr::top_block_sptr top_block) { if (dump_) { - top_block->disconnect(interleaved_byte_to_complex_short_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->disconnect(interleaved_byte_to_complex_short_, 0, conjugate_sc_, 0); + top_block->disconnect(conjugate_sc_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(interleaved_byte_to_complex_short_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->disconnect(interleaved_byte_to_complex_short_, 0, conjugate_sc_, 0); + } } } - gr::basic_block_sptr IbyteToCshort::get_left_block() { return interleaved_byte_to_complex_short_; } - gr::basic_block_sptr IbyteToCshort::get_right_block() { + if (inverted_spectrum) + { + return conjugate_sc_; + } return interleaved_byte_to_complex_short_; } - - diff --git a/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.h b/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.h index a5a716aff..9e7c5b74b 100644 --- a/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.h +++ b/src/algorithms/data_type_adapter/adapters/ibyte_to_cshort.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,11 @@ #ifndef GNSS_SDR_IBYTE_TO_CSHORT_H_ #define GNSS_SDR_IBYTE_TO_CSHORT_H_ -#include -#include +#include "conjugate_sc.h" #include "gnss_block_interface.h" #include "interleaved_byte_to_complex_short.h" - +#include +#include class ConfigurationInterface; @@ -44,33 +44,35 @@ class ConfigurationInterface; * \brief Adapts a short integer (16 bits) interleaved sample stream into a std::complex stream * */ -class IbyteToCshort: public GNSSBlockInterface +class IbyteToCshort : public GNSSBlockInterface { public: IbyteToCshort(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, unsigned int in_streams, + unsigned int out_streams); virtual ~IbyteToCshort(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Ibyte_To_Cshort" - std::string implementation() + inline std::string implementation() override { return "Ibyte_To_Cshort"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: interleaved_byte_to_complex_short_sptr interleaved_byte_to_complex_short_; @@ -83,7 +85,8 @@ private: unsigned int in_streams_; unsigned int out_streams_; gr::blocks::file_sink::sptr file_sink_; + conjugate_sc_sptr conjugate_sc_; + bool inverted_spectrum; }; #endif - diff --git a/src/algorithms/data_type_adapter/adapters/ishort_to_complex.cc b/src/algorithms/data_type_adapter/adapters/ishort_to_complex.cc index e87dc1f59..918dbd8a3 100644 --- a/src/algorithms/data_type_adapter/adapters/ishort_to_complex.cc +++ b/src/algorithms/data_type_adapter/adapters/ishort_to_complex.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,21 +23,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ishort_to_complex.h" -#include #include "configuration_interface.h" +#include using google::LogMessage; -IshortToComplex::IshortToComplex(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) +IshortToComplex::IshortToComplex(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "short"; std::string default_output_item_type = "gr_complex"; @@ -49,6 +47,7 @@ IshortToComplex::IshortToComplex(ConfigurationInterface* configuration, std::str dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); size_t item_size = sizeof(gr_complex); @@ -56,27 +55,53 @@ IshortToComplex::IshortToComplex(ConfigurationInterface* configuration, std::str DLOG(INFO) << "data_type_adapter_(" << gr_interleaved_short_to_complex_->unique_id() << ")"; + if (inverted_spectrum) + { + conjugate_cc_ = make_conjugate_cc(); + } if (dump_) { DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -IshortToComplex::~IshortToComplex() -{} +IshortToComplex::~IshortToComplex() = default; void IshortToComplex::connect(gr::top_block_sptr top_block) { if (dump_) { - top_block->connect(gr_interleaved_short_to_complex_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->connect(gr_interleaved_short_to_complex_, 0, conjugate_cc_, 0); + top_block->connect(conjugate_cc_, 0, file_sink_, 0); + } + else + { + top_block->connect(gr_interleaved_short_to_complex_, 0, file_sink_, 0); + } } else { - DLOG(INFO) << "Nothing to connect internally"; + if (inverted_spectrum) + { + top_block->connect(gr_interleaved_short_to_complex_, 0, conjugate_cc_, 0); + } + else + { + DLOG(INFO) << "Nothing to connect internally"; + } } } @@ -85,22 +110,37 @@ void IshortToComplex::disconnect(gr::top_block_sptr top_block) { if (dump_) { - top_block->disconnect(gr_interleaved_short_to_complex_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->disconnect(gr_interleaved_short_to_complex_, 0, conjugate_cc_, 0); + top_block->disconnect(conjugate_cc_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(gr_interleaved_short_to_complex_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->disconnect(gr_interleaved_short_to_complex_, 0, conjugate_cc_, 0); + } } } - gr::basic_block_sptr IshortToComplex::get_left_block() { return gr_interleaved_short_to_complex_; } - gr::basic_block_sptr IshortToComplex::get_right_block() { + if (inverted_spectrum) + { + return conjugate_cc_; + } return gr_interleaved_short_to_complex_; } - - diff --git a/src/algorithms/data_type_adapter/adapters/ishort_to_complex.h b/src/algorithms/data_type_adapter/adapters/ishort_to_complex.h index e12b23bdc..73d1133a8 100644 --- a/src/algorithms/data_type_adapter/adapters/ishort_to_complex.h +++ b/src/algorithms/data_type_adapter/adapters/ishort_to_complex.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,11 @@ #ifndef GNSS_SDR_ISHORT_TO_COMPLEX_H_ #define GNSS_SDR_ISHORT_TO_COMPLEX_H_ -#include -#include -#include +#include "conjugate_cc.h" #include "gnss_block_interface.h" - +#include +#include +#include class ConfigurationInterface; @@ -43,33 +43,35 @@ class ConfigurationInterface; * \brief Adapts an I/Q interleaved short integer sample stream to a gr_complex (float) stream * */ -class IshortToComplex: public GNSSBlockInterface +class IshortToComplex : public GNSSBlockInterface { public: IshortToComplex(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, unsigned int in_streams, + unsigned int out_streams); virtual ~IshortToComplex(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Ishort_To_Complex" - std::string implementation() + inline std::string implementation() override { return "Ishort_To_Complex"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: gr::blocks::interleaved_short_to_complex::sptr gr_interleaved_short_to_complex_; @@ -82,7 +84,8 @@ private: unsigned int in_streams_; unsigned int out_streams_; gr::blocks::file_sink::sptr file_sink_; + conjugate_cc_sptr conjugate_cc_; + bool inverted_spectrum; }; #endif - diff --git a/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.cc b/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.cc index 503341d08..c6a7d7490 100644 --- a/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.cc +++ b/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,22 +24,20 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "ishort_to_cshort.h" +#include "configuration_interface.h" #include #include -#include "configuration_interface.h" using google::LogMessage; -IshortToCshort::IshortToCshort(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) +IshortToCshort::IshortToCshort(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_input_item_type = "short"; std::string default_output_item_type = "cshort"; @@ -51,6 +49,7 @@ IshortToCshort::IshortToCshort(ConfigurationInterface* configuration, std::strin dump_ = config_->property(role_ + ".dump", false); dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); size_t item_size = sizeof(lv_16sc_t); @@ -63,22 +62,48 @@ IshortToCshort::IshortToCshort(ConfigurationInterface* configuration, std::strin DLOG(INFO) << "Dumping output into file " << dump_filename_; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (inverted_spectrum) + { + conjugate_sc_ = make_conjugate_sc(); + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -IshortToCshort::~IshortToCshort() -{} +IshortToCshort::~IshortToCshort() = default; void IshortToCshort::connect(gr::top_block_sptr top_block) { if (dump_) { - top_block->connect(interleaved_short_to_complex_short_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->connect(interleaved_short_to_complex_short_, 0, conjugate_sc_, 0); + top_block->connect(conjugate_sc_, 0, file_sink_, 0); + } + else + { + top_block->connect(interleaved_short_to_complex_short_, 0, file_sink_, 0); + } } else { - DLOG(INFO) << "Nothing to connect internally"; + if (inverted_spectrum) + { + top_block->connect(interleaved_short_to_complex_short_, 0, conjugate_sc_, 0); + } + else + { + DLOG(INFO) << "Nothing to connect internally"; + } } } @@ -87,22 +112,37 @@ void IshortToCshort::disconnect(gr::top_block_sptr top_block) { if (dump_) { - top_block->disconnect(interleaved_short_to_complex_short_, 0, file_sink_, 0); + if (inverted_spectrum) + { + top_block->disconnect(interleaved_short_to_complex_short_, 0, conjugate_sc_, 0); + top_block->disconnect(conjugate_sc_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(interleaved_short_to_complex_short_, 0, file_sink_, 0); + } + } + else + { + if (inverted_spectrum) + { + top_block->disconnect(interleaved_short_to_complex_short_, 0, conjugate_sc_, 0); + } } } - gr::basic_block_sptr IshortToCshort::get_left_block() { return interleaved_short_to_complex_short_; } - gr::basic_block_sptr IshortToCshort::get_right_block() { + if (inverted_spectrum) + { + return conjugate_sc_; + } return interleaved_short_to_complex_short_; } - - diff --git a/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.h b/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.h index 9cc5ae959..925065a1d 100644 --- a/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.h +++ b/src/algorithms/data_type_adapter/adapters/ishort_to_cshort.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,11 @@ #ifndef GNSS_SDR_ISHORT_TO_CSHORT_H_ #define GNSS_SDR_ISHORT_TO_CSHORT_H_ -#include -#include +#include "conjugate_sc.h" #include "gnss_block_interface.h" #include "interleaved_short_to_complex_short.h" - +#include +#include class ConfigurationInterface; @@ -44,33 +44,35 @@ class ConfigurationInterface; * \brief Adapts a short integer (16 bits) interleaved sample stream into a std::complex stream * */ -class IshortToCshort: public GNSSBlockInterface +class IshortToCshort : public GNSSBlockInterface { public: IshortToCshort(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + const std::string& role, unsigned int in_streams, + unsigned int out_streams); virtual ~IshortToCshort(); - std::string role() + inline std::string role() override { return role_; } + //! Returns "Ishort_To_Cshort" - std::string implementation() + inline std::string implementation() override { return "Ishort_To_Cshort"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: interleaved_short_to_complex_short_sptr interleaved_short_to_complex_short_; @@ -83,7 +85,8 @@ private: unsigned int in_streams_; unsigned int out_streams_; gr::blocks::file_sink::sptr file_sink_; + conjugate_sc_sptr conjugate_sc_; + bool inverted_spectrum; }; #endif - diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/CMakeLists.txt b/src/algorithms/data_type_adapter/gnuradio_blocks/CMakeLists.txt index 111c87cf4..b4f429db9 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,24 +13,39 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(DATA_TYPE_GR_BLOCKS_SOURCES - interleaved_byte_to_complex_byte.cc - interleaved_short_to_complex_short.cc - interleaved_byte_to_complex_short.cc +set(DATA_TYPE_GR_BLOCKS_SOURCES + interleaved_byte_to_complex_byte.cc + interleaved_short_to_complex_short.cc + interleaved_byte_to_complex_short.cc +) + +set(DATA_TYPE_GR_BLOCKS_HEADERS + interleaved_byte_to_complex_byte.h + interleaved_short_to_complex_short.h + interleaved_byte_to_complex_short.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) -file(GLOB DATA_TYPE_GR_BLOCKS_HEADERS "*.h") list(SORT DATA_TYPE_GR_BLOCKS_HEADERS) -add_library(data_type_gr_blocks ${DATA_TYPE_GR_BLOCKS_SOURCES} ${DATA_TYPE_GR_BLOCKS_HEADERS}) +list(SORT DATA_TYPE_GR_BLOCKS_SOURCES) + +add_library(data_type_gr_blocks + ${DATA_TYPE_GR_BLOCKS_SOURCES} + ${DATA_TYPE_GR_BLOCKS_HEADERS} +) + source_group(Headers FILES ${DATA_TYPE_GR_BLOCKS_HEADERS}) -target_link_libraries(data_type_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES} ${VOLK_LIBRARIES}) \ No newline at end of file + +target_link_libraries(data_type_gr_blocks + ${GNURADIO_RUNTIME_LIBRARIES} + ${VOLK_LIBRARIES} +) diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.cc b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.cc index 38a7380e6..c5c854334 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.cc +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,11 +40,10 @@ interleaved_byte_to_complex_byte_sptr make_interleaved_byte_to_complex_byte() } - interleaved_byte_to_complex_byte::interleaved_byte_to_complex_byte() : sync_decimator("interleaved_byte_to_complex_byte", - gr::io_signature::make (1, 1, sizeof(int8_t)), - gr::io_signature::make (1, 1, sizeof(lv_8sc_t)), // lv_8sc_t is a Volk's typedef for std::complex - 2) + gr::io_signature::make(1, 1, sizeof(int8_t)), + gr::io_signature::make(1, 1, sizeof(lv_8sc_t)), // lv_8sc_t is a Volk's typedef for std::complex + 2) { const int alignment_multiple = volk_get_alignment() / sizeof(lv_8sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -52,15 +51,15 @@ interleaved_byte_to_complex_byte::interleaved_byte_to_complex_byte() : sync_deci int interleaved_byte_to_complex_byte::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const int8_t *in = (const int8_t *) input_items[0]; - lv_8sc_t *out = (lv_8sc_t *) output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); // This could be put into a Volk kernel int8_t real_part; int8_t imag_part; - for(int number = 0; number < noutput_items; number++) + for (int number = 0; number < noutput_items; number++) { // lv_cmake(r, i) defined at volk/volk_complex.h real_part = *in++; diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.h b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.h index d650c2f8b..c9ce17b4a 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.h +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_byte.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -45,16 +45,17 @@ interleaved_byte_to_complex_byte_sptr make_interleaved_byte_to_complex_byte(); * \brief This class adapts an 8-bits interleaved sample stream * into a 16-bits complex stream (std::complex) */ -class interleaved_byte_to_complex_byte : public gr::sync_decimator +class interleaved_byte_to_complex_byte : public gr::sync_decimator { private: friend interleaved_byte_to_complex_byte_sptr make_interleaved_byte_to_complex_byte(); + public: interleaved_byte_to_complex_byte(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.cc b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.cc index 273c51205..b6e5368b8 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.cc +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,11 +40,10 @@ interleaved_byte_to_complex_short_sptr make_interleaved_byte_to_complex_short() } - interleaved_byte_to_complex_short::interleaved_byte_to_complex_short() : sync_decimator("interleaved_byte_to_complex_short", - gr::io_signature::make (1, 1, sizeof(int8_t)), - gr::io_signature::make (1, 1, sizeof(lv_16sc_t)), // lv_16sc_t is a Volk's typedef for std::complex - 2) + gr::io_signature::make(1, 1, sizeof(int8_t)), + gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), // lv_16sc_t is a Volk's typedef for std::complex + 2) { const int alignment_multiple = volk_get_alignment() / sizeof(lv_16sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -52,20 +51,20 @@ interleaved_byte_to_complex_short::interleaved_byte_to_complex_short() : sync_de int interleaved_byte_to_complex_short::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const int8_t *in = (const int8_t *) input_items[0]; - lv_16sc_t *out = (lv_16sc_t *) output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); // This could be put into a Volk kernel int8_t real_part; int8_t imag_part; - for(int number = 0; number < noutput_items; number++) + for (int number = 0; number < noutput_items; number++) { // lv_cmake(r, i) defined at volk/volk_complex.h real_part = *in++; imag_part = *in++; - *out++ = lv_cmake((int16_t)real_part, (int16_t)imag_part); + *out++ = lv_cmake(static_cast(real_part), static_cast(imag_part)); } return noutput_items; } diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.h b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.h index 386e1fd85..5eab0f314 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.h +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_byte_to_complex_short.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,12 +48,13 @@ class interleaved_byte_to_complex_short : public gr::sync_decimator { private: friend interleaved_byte_to_complex_short_sptr make_interleaved_byte_to_complex_short(); + public: interleaved_byte_to_complex_short(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.cc b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.cc index a6dc2798d..bf88a2ea5 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.cc +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,11 +40,10 @@ interleaved_short_to_complex_short_sptr make_interleaved_short_to_complex_short( } - interleaved_short_to_complex_short::interleaved_short_to_complex_short() : sync_decimator("interleaved_short_to_complex_short", - gr::io_signature::make (1, 1, sizeof(int16_t)), - gr::io_signature::make (1, 1, sizeof(lv_16sc_t)), // lv_16sc_t is a Volk's typedef for std::complex - 2) + gr::io_signature::make(1, 1, sizeof(int16_t)), + gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), // lv_16sc_t is a Volk's typedef for std::complex + 2) { const int alignment_multiple = volk_get_alignment() / sizeof(lv_16sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -52,15 +51,15 @@ interleaved_short_to_complex_short::interleaved_short_to_complex_short() : sync_ int interleaved_short_to_complex_short::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const int16_t *in = (const int16_t *) input_items[0]; - lv_16sc_t *out = (lv_16sc_t *) output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); // This could be put into a Volk kernel int16_t real_part; int16_t imag_part; - for(int number = 0; number < noutput_items; number++) + for (int number = 0; number < noutput_items; number++) { // lv_cmake(r, i) defined at volk/volk_complex.h real_part = *in++; diff --git a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.h b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.h index d85735ae5..10287459a 100644 --- a/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.h +++ b/src/algorithms/data_type_adapter/gnuradio_blocks/interleaved_short_to_complex_short.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,12 +48,13 @@ class interleaved_short_to_complex_short : public gr::sync_decimator { private: friend interleaved_short_to_complex_short_sptr make_interleaved_short_to_complex_short(); + public: interleaved_short_to_complex_short(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/input_filter/CMakeLists.txt b/src/algorithms/input_filter/CMakeLists.txt index 20a0f5449..1841d3dfc 100644 --- a/src/algorithms/input_filter/CMakeLists.txt +++ b/src/algorithms/input_filter/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,8 +13,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) -add_subdirectory(gnuradio_blocks) \ No newline at end of file +add_subdirectory(gnuradio_blocks) diff --git a/src/algorithms/input_filter/adapters/CMakeLists.txt b/src/algorithms/input_filter/adapters/CMakeLists.txt index a4cb2b869..8153c6c3c 100644 --- a/src/algorithms/input_filter/adapters/CMakeLists.txt +++ b/src/algorithms/input_filter/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,30 +13,57 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(INPUT_FILTER_ADAPTER_SOURCES - fir_filter.cc - freq_xlating_fir_filter.cc - beamformer_filter.cc +set(INPUT_FILTER_ADAPTER_SOURCES + fir_filter.cc + freq_xlating_fir_filter.cc + beamformer_filter.cc + pulse_blanking_filter.cc + notch_filter.cc + notch_filter_lite.cc +) + +set(INPUT_FILTER_ADAPTER_HEADERS + fir_filter.h + freq_xlating_fir_filter.h + beamformer_filter.h + pulse_blanking_filter.h + notch_filter.h + notch_filter_lite.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) -file(GLOB INPUT_FILTER_ADAPTER_HEADERS "*.h") +if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.13.4") + add_definitions(-DGR_GREATER_38=1) +endif() + list(SORT INPUT_FILTER_ADAPTER_HEADERS) -add_library(input_filter_adapters ${INPUT_FILTER_ADAPTER_SOURCES} ${INPUT_FILTER_ADAPTER_HEADERS}) +list(SORT INPUT_FILTER_ADAPTER_SOURCES) + +add_library(input_filter_adapters + ${INPUT_FILTER_ADAPTER_SOURCES} + ${INPUT_FILTER_ADAPTER_HEADERS} +) + source_group(Headers FILES ${INPUT_FILTER_ADAPTER_HEADERS}) add_dependencies(input_filter_adapters glog-${glog_RELEASE} gnss_sp_libs) -target_link_libraries(input_filter_adapters input_filter_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} gnss_sp_libs) +target_link_libraries(input_filter_adapters + input_filter_gr_blocks + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + gnss_sp_libs +) diff --git a/src/algorithms/input_filter/adapters/beamformer_filter.cc b/src/algorithms/input_filter/adapters/beamformer_filter.cc index 8b1797f0e..52c19352d 100644 --- a/src/algorithms/input_filter/adapters/beamformer_filter.cc +++ b/src/algorithms/input_filter/adapters/beamformer_filter.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,24 +23,23 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "beamformer_filter.h" -#include -#include #include "beamformer.h" #include "configuration_interface.h" +#include +#include using google::LogMessage; BeamformerFilter::BeamformerFilter( - ConfigurationInterface* configuration, std::string role, - unsigned int in_stream, unsigned int out_stream) : - role_(role), in_stream_(in_stream), out_stream_(out_stream) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_stream, unsigned int out_stream) : role_(role), in_stream_(in_stream), out_stream_(out_stream) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/input_filter.dat"; @@ -49,18 +48,17 @@ BeamformerFilter::BeamformerFilter( DLOG(INFO) << "dump_ is " << dump_; dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); beamformer_ = make_beamformer(); DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "resampler(" << beamformer_->unique_id() << ")"; - } else { LOG(WARNING) << item_type_ - << " unrecognized item type for beamformer"; + << " unrecognized item type for beamformer"; item_size_ = sizeof(gr_complex); } if (dump_) @@ -70,11 +68,18 @@ BeamformerFilter::BeamformerFilter( DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; } samples_ = 0; + if (in_stream_ > 8) + { + LOG(ERROR) << "This implementation only supports eight input streams"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -BeamformerFilter::~BeamformerFilter() {} - +BeamformerFilter::~BeamformerFilter() = default; void BeamformerFilter::connect(gr::top_block_sptr top_block) diff --git a/src/algorithms/input_filter/adapters/beamformer_filter.h b/src/algorithms/input_filter/adapters/beamformer_filter.h index b23d293cd..c97c32732 100644 --- a/src/algorithms/input_filter/adapters/beamformer_filter.h +++ b/src/algorithms/input_filter/adapters/beamformer_filter.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,9 @@ #ifndef GNSS_SDR_BEAMFORMER_FILTER_H_ #define GNSS_SDR_BEAMFORMER_FILTER_H_ -#include -#include #include "gnss_block_interface.h" +#include +#include class ConfigurationInterface; @@ -42,31 +42,35 @@ class ConfigurationInterface; * \brief Interface of an adapter of a direct resampler conditioner block * to a SignalConditionerInterface */ -class BeamformerFilter: public GNSSBlockInterface +class BeamformerFilter : public GNSSBlockInterface { public: BeamformerFilter(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream); + const std::string& role, unsigned int in_stream, + unsigned int out_stream); virtual ~BeamformerFilter(); - std::string role() + + inline std::string role() override { return role_; } + //! returns "Direct_Resampler" - std::string implementation() + inline std::string implementation() override { return "Beamformer_Filter"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string role_; diff --git a/src/algorithms/input_filter/adapters/fir_filter.cc b/src/algorithms/input_filter/adapters/fir_filter.cc index 8112251b4..b436b1407 100644 --- a/src/algorithms/input_filter/adapters/fir_filter.cc +++ b/src/algorithms/input_filter/adapters/fir_filter.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,29 +24,27 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "fir_filter.h" -#include -#include -#include -#include #include "configuration_interface.h" +#include +#include +#include +#include + using google::LogMessage; FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) { size_t item_size; (*this).init(); - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(1, taps_); @@ -57,8 +55,7 @@ FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "cshort")) { item_size = sizeof(lv_16sc_t); cshort_to_float_x2_ = make_cshort_to_float_x2(); @@ -75,8 +72,7 @@ FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); cshort_to_float_x2_ = make_cshort_to_float_x2(); @@ -92,8 +88,7 @@ FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); @@ -111,8 +106,7 @@ FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "cbyte")) { item_size = sizeof(lv_8sc_t); cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); @@ -137,19 +131,23 @@ FirFilter::FirFilter(ConfigurationInterface* configuration, std::string role, { LOG(ERROR) << " Unknown item type conversion"; } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - -FirFilter::~FirFilter() -{} - +FirFilter::~FirFilter() = default; void FirFilter::connect(gr::top_block_sptr top_block) { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { if (dump_) { @@ -160,8 +158,7 @@ void FirFilter::connect(gr::top_block_sptr top_block) DLOG(INFO) << "Nothing to connect internally"; } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "cshort")) { top_block->connect(cshort_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->connect(cshort_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -174,8 +171,7 @@ void FirFilter::connect(gr::top_block_sptr top_block) top_block->connect(short_x2_to_cshort_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "gr_complex")) { top_block->connect(cbyte_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->connect(cbyte_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -186,8 +182,7 @@ void FirFilter::connect(gr::top_block_sptr top_block) top_block->connect(float_to_complex_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "cbyte")) { top_block->connect(cbyte_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->connect(cbyte_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -200,8 +195,7 @@ void FirFilter::connect(gr::top_block_sptr top_block) top_block->connect(char_x2_cbyte_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "gr_complex")) { top_block->connect(cshort_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->connect(cshort_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -219,19 +213,16 @@ void FirFilter::connect(gr::top_block_sptr top_block) } - void FirFilter::disconnect(gr::top_block_sptr top_block) { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->disconnect(fir_filter_ccf_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "gr_complex")) { top_block->disconnect(fir_filter_fff_2_, 0, float_to_complex_, 1); top_block->disconnect(fir_filter_fff_1_, 0, float_to_complex_, 0); @@ -242,8 +233,7 @@ void FirFilter::disconnect(gr::top_block_sptr top_block) top_block->disconnect(float_to_complex_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "cshort")) { top_block->disconnect(cshort_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->disconnect(cshort_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -256,8 +246,7 @@ void FirFilter::disconnect(gr::top_block_sptr top_block) top_block->disconnect(short_x2_to_cshort_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "cbyte")) { top_block->disconnect(float_to_char_2_, 0, char_x2_cbyte_, 1); top_block->disconnect(float_to_char_1_, 0, char_x2_cbyte_, 0); @@ -270,8 +259,7 @@ void FirFilter::disconnect(gr::top_block_sptr top_block) top_block->disconnect(char_x2_cbyte_, 0, file_sink_, 0); } } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "gr_complex")) { top_block->disconnect(cshort_to_float_x2_, 0, fir_filter_fff_1_, 0); top_block->disconnect(cshort_to_float_x2_, 1, fir_filter_fff_2_, 0); @@ -289,31 +277,25 @@ void FirFilter::disconnect(gr::top_block_sptr top_block) } - gr::basic_block_sptr FirFilter::get_left_block() { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { return fir_filter_ccf_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("cshort") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "cshort")) { return cshort_to_float_x2_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "gr_complex")) { return cbyte_to_float_x2_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "cbyte")) { return cbyte_to_float_x2_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "gr_complex")) { return cshort_to_float_x2_; } @@ -325,31 +307,25 @@ gr::basic_block_sptr FirFilter::get_left_block() } - gr::basic_block_sptr FirFilter::get_right_block() { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { return fir_filter_ccf_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("cshort") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "cshort")) { return short_x2_to_cshort_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "gr_complex")) { return float_to_complex_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cbyte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cbyte") && (output_item_type_ == "cbyte")) { return char_x2_cbyte_; } - else if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("cshort") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "cshort") && (output_item_type_ == "gr_complex")) { return float_to_complex_; } @@ -361,7 +337,6 @@ gr::basic_block_sptr FirFilter::get_right_block() } - void FirFilter::init() { std::string default_input_item_type = "gr_complex"; @@ -370,9 +345,9 @@ void FirFilter::init() std::string default_dump_filename = "../data/input_filter.dat"; int default_number_of_taps = 6; unsigned int default_number_of_bands = 2; - std::vector default_bands = { 0.0, 0.4, 0.6, 1.0 }; - std::vector default_ampl = { 1.0, 1.0, 0.0, 0.0 }; - std::vector default_error_w = { 1.0, 1.0 }; + std::vector default_bands = {0.0, 0.4, 0.6, 1.0}; + std::vector default_ampl = {1.0, 1.0, 0.0, 0.0}; + std::vector default_error_w = {1.0, 1.0}; std::string default_filter_type = "bandpass"; int default_grid_density = 16; @@ -393,23 +368,23 @@ void FirFilter::init() double option_value; for (unsigned int i = 0; i < number_of_bands; i++) { - option = ".band" + boost::lexical_cast(i + 1) + "_begin"; + option = ".band" + std::to_string(i + 1) + "_begin"; option_value = config_->property(role_ + option, default_bands[i]); bands.push_back(option_value); - option = ".band" + boost::lexical_cast(i + 1) + "_end"; + option = ".band" + std::to_string(i + 1) + "_end"; option_value = config_->property(role_ + option, default_bands[i]); bands.push_back(option_value); - option = ".ampl" + boost::lexical_cast(i + 1) + "_begin"; + option = ".ampl" + std::to_string(i + 1) + "_begin"; option_value = config_->property(role_ + option, default_bands[i]); ampl.push_back(option_value); - option = ".ampl" + boost::lexical_cast(i + 1) + "_end"; + option = ".ampl" + std::to_string(i + 1) + "_end"; option_value = config_->property(role_ + option, default_bands[i]); ampl.push_back(option_value); - option = ".band" + boost::lexical_cast(i + 1) + "_error"; + option = ".band" + std::to_string(i + 1) + "_error"; option_value = config_->property(role_ + option, default_bands[i]); error_w.push_back(option_value); } @@ -423,8 +398,8 @@ void FirFilter::init() // those bands, and the weight given to the error in those bands. std::vector taps_d = gr::filter::pm_remez(number_of_taps - 1, bands, ampl, error_w, filter_type, grid_density); taps_.reserve(taps_d.size()); - for (std::vector::iterator it = taps_d.begin(); it != taps_d.end(); it++) + for (double& it : taps_d) { - taps_.push_back(float(*it)); + taps_.push_back(float(it)); } } diff --git a/src/algorithms/input_filter/adapters/fir_filter.h b/src/algorithms/input_filter/adapters/fir_filter.h index 958266cbe..85626f2cc 100644 --- a/src/algorithms/input_filter/adapters/fir_filter.h +++ b/src/algorithms/input_filter/adapters/fir_filter.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,21 +33,25 @@ #ifndef GNSS_SDR_FIR_FILTER_H_ #define GNSS_SDR_FIR_FILTER_H_ -#include -#include -#include -#include +#include "byte_x2_to_complex_byte.h" +#include "complex_byte_to_float_x2.h" +#include "cshort_to_float_x2.h" +#include "gnss_block_interface.h" +#include "short_x2_to_cshort.h" #include #include #include #include +#include +#ifdef GR_GREATER_38 +#include +#else #include #include -#include "gnss_block_interface.h" -#include "complex_byte_to_float_x2.h" -#include "byte_x2_to_complex_byte.h" -#include "short_x2_to_cshort.h" -#include "cshort_to_float_x2.h" +#endif +#include +#include +#include class ConfigurationInterface; @@ -59,35 +63,38 @@ class ConfigurationInterface; * given a set of band edges, the desired response on those bands, and the weight given * to the error in those bands. */ -class FirFilter: public GNSSBlockInterface +class FirFilter : public GNSSBlockInterface { public: //! Constructor FirFilter(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + std::string role, + unsigned int in_streams, + unsigned int out_streams); //! Destructor virtual ~FirFilter(); - std::string role() + + inline std::string role() override { return role_; } //! Returns "Fir_Filter" - std::string implementation() + inline std::string implementation() override { return "Fir_Filter"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: gr::filter::fir_filter_ccf::sptr fir_filter_ccf_; @@ -97,7 +104,7 @@ private: std::string input_item_type_; std::string output_item_type_; std::string taps_item_type_; - std::vector taps_; + std::vector taps_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; @@ -114,7 +121,6 @@ private: gr::blocks::float_to_short::sptr float_to_short_1_; gr::blocks::float_to_short::sptr float_to_short_2_; short_x2_to_cshort_sptr short_x2_to_cshort_; - }; #endif diff --git a/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc b/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc index d5690f07e..9e904d2e8 100644 --- a/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc +++ b/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc @@ -1,11 +1,12 @@ /*! * \file freq_xlating_fir_filter.cc - * \brief Adapts a gnuradio gr_freq_xlating_fir_filter designed with gr_remez + * \brief Adapts a gnuradio gr_freq_xlating_fir_filter designed with gr_remez or gr_firdes * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * Antonio Ramos, 2017. antonio.ramos(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,92 +24,159 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "freq_xlating_fir_filter.h" -#include -#include -#include -#include -#include #include "configuration_interface.h" +#include +#include +#include +#include +#include +#include using google::LogMessage; FreqXlatingFirFilter::FreqXlatingFirFilter(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - config_(configuration), role_(role), in_streams_(in_streams), - out_streams_(out_streams) + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) { - size_t item_size; - (*this).init(); - int decimation_factor; + std::string default_input_item_type = "gr_complex"; + std::string default_output_item_type = "gr_complex"; + std::string default_taps_item_type = "float"; + std::string default_dump_filename = "../data/input_filter.dat"; + double default_intermediate_freq = 0.0; + double default_sampling_freq = 4000000.0; + int default_number_of_taps = 6; + unsigned int default_number_of_bands = 2; + std::vector default_bands = {0.0, 0.4, 0.6, 1.0}; + std::vector default_ampl = {1.0, 1.0, 0.0, 0.0}; + std::vector default_error_w = {1.0, 1.0}; + std::string default_filter_type = "bandpass"; + int default_grid_density = 16; int default_decimation_factor = 1; - decimation_factor = config_->property(role_ + ".decimation_factor", default_decimation_factor); - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + DLOG(INFO) << "role " << role_; + + input_item_type_ = config_->property(role_ + ".input_item_type", default_input_item_type); + output_item_type_ = config_->property(role_ + ".output_item_type", default_output_item_type); + taps_item_type_ = config_->property(role_ + ".taps_item_type", default_taps_item_type); + dump_ = config_->property(role_ + ".dump", false); + dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + intermediate_freq_ = config_->property(role_ + ".IF", default_intermediate_freq); + sampling_freq_ = config_->property(role_ + ".sampling_frequency", default_sampling_freq); + int number_of_taps = config_->property(role_ + ".number_of_taps", default_number_of_taps); + unsigned int number_of_bands = config_->property(role_ + ".number_of_bands", default_number_of_bands); + std::string filter_type = config_->property(role_ + ".filter_type", default_filter_type); + decimation_factor_ = config_->property(role_ + ".decimation_factor", default_decimation_factor); + + if (filter_type != "lowpass") { - item_size = sizeof(gr_complex); //output - input_size_ = sizeof(gr_complex); //input - freq_xlating_fir_filter_ccf_ = gr::filter::freq_xlating_fir_filter_ccf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + std::vector taps_d; + std::vector bands; + std::vector ampl; + std::vector error_w; + std::string option; + double option_value; + + for (unsigned int i = 0; i < number_of_bands; i++) + { + option = ".band" + std::to_string(i + 1) + "_begin"; + option_value = config_->property(role_ + option, default_bands[i]); + bands.push_back(option_value); + + option = ".band" + std::to_string(i + 1) + "_end"; + option_value = config_->property(role_ + option, default_bands[i]); + bands.push_back(option_value); + + option = ".ampl" + std::to_string(i + 1) + "_begin"; + option_value = config_->property(role_ + option, default_bands[i]); + ampl.push_back(option_value); + + option = ".ampl" + std::to_string(i + 1) + "_end"; + option_value = config_->property(role_ + option, default_bands[i]); + ampl.push_back(option_value); + + option = ".band" + std::to_string(i + 1) + "_error"; + option_value = config_->property(role_ + option, default_bands[i]); + error_w.push_back(option_value); + } + + int grid_density = config_->property(role_ + ".grid_density", default_grid_density); + taps_d = gr::filter::pm_remez(number_of_taps - 1, bands, ampl, error_w, filter_type, grid_density); + taps_.reserve(taps_d.size()); + for (double& it : taps_d) + { + taps_.push_back(static_cast(it)); + } + } + else + { + double default_bw = (sampling_freq_ / decimation_factor_) / 2; + double bw_ = config_->property(role_ + ".bw", default_bw); + double default_tw = bw_ / 10.0; + double tw_ = config_->property(role_ + ".tw", default_tw); + taps_ = gr::filter::firdes::low_pass(1.0, sampling_freq_, bw_, tw_); + } + + size_t item_size; + + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) + { + item_size = sizeof(gr_complex); //output + input_size_ = sizeof(gr_complex); //input + freq_xlating_fir_filter_ccf_ = gr::filter::freq_xlating_fir_filter_ccf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_ccf_->unique_id() << ")"; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("float") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "float") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); - input_size_ = sizeof(float); //input - freq_xlating_fir_filter_fcf_ = gr::filter::freq_xlating_fir_filter_fcf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + input_size_ = sizeof(float); //input + freq_xlating_fir_filter_fcf_ = gr::filter::freq_xlating_fir_filter_fcf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_fcf_->unique_id() << ")"; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); - input_size_ = sizeof(int16_t); //input - freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + input_size_ = sizeof(int16_t); //input + freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_scf_->unique_id() << ")"; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "cshort")) { item_size = sizeof(lv_16sc_t); - input_size_ = sizeof(int16_t); //input - freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + input_size_ = sizeof(int16_t); //input + freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_scf_->unique_id() << ")"; complex_to_float_ = gr::blocks::complex_to_float::make(); float_to_short_1_ = gr::blocks::float_to_short::make(); float_to_short_2_ = gr::blocks::float_to_short::make(); short_x2_to_cshort_ = make_short_x2_to_cshort(); } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "gr_complex")) { item_size = sizeof(gr_complex); - input_size_ = sizeof(int8_t); //input + input_size_ = sizeof(int8_t); //input gr_char_to_short_ = gr::blocks::char_to_short::make(); - freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_scf_->unique_id() << ")"; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "cbyte")) { item_size = sizeof(lv_8sc_t); - input_size_ = sizeof(int8_t); //input + input_size_ = sizeof(int8_t); //input gr_char_to_short_ = gr::blocks::char_to_short::make(); - freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor, taps_, intermediate_freq_, sampling_freq_); + freq_xlating_fir_filter_scf_ = gr::filter::freq_xlating_fir_filter_scf::make(decimation_factor_, taps_, intermediate_freq_, sampling_freq_); DLOG(INFO) << "input_filter(" << freq_xlating_fir_filter_scf_->unique_id() << ")"; complex_to_complex_byte_ = make_complex_float_to_complex_byte(); } else { LOG(ERROR) << " Unknown input filter input/output item type conversion"; - item_size = sizeof(gr_complex); //avoids uninitialization - input_size_ = sizeof(gr_complex); //avoids uninitialization + item_size = sizeof(gr_complex); //avoids uninitialization + input_size_ = sizeof(gr_complex); //avoids uninitialization } if (dump_) @@ -117,43 +185,44 @@ FreqXlatingFirFilter::FreqXlatingFirFilter(ConfigurationInterface* configuration std::cout << "Dumping output into file " << dump_filename_ << std::endl; file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - -FreqXlatingFirFilter::~FreqXlatingFirFilter() -{} - +FreqXlatingFirFilter::~FreqXlatingFirFilter() = default; void FreqXlatingFirFilter::connect(gr::top_block_sptr top_block) { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->connect(freq_xlating_fir_filter_ccf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("float") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "float") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->connect(freq_xlating_fir_filter_fcf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->connect(freq_xlating_fir_filter_scf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "cshort")) { top_block->connect(freq_xlating_fir_filter_scf_, 0, complex_to_float_, 0); top_block->connect(complex_to_float_, 0, float_to_short_1_, 0); @@ -165,8 +234,7 @@ void FreqXlatingFirFilter::connect(gr::top_block_sptr top_block) top_block->connect(short_x2_to_cshort_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "gr_complex")) { top_block->connect(gr_char_to_short_, 0, freq_xlating_fir_filter_scf_, 0); if (dump_) @@ -174,8 +242,7 @@ void FreqXlatingFirFilter::connect(gr::top_block_sptr top_block) top_block->connect(freq_xlating_fir_filter_scf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "cbyte")) { top_block->connect(gr_char_to_short_, 0, freq_xlating_fir_filter_scf_, 0); top_block->connect(freq_xlating_fir_filter_scf_, 0, complex_to_complex_byte_, 0); @@ -191,35 +258,30 @@ void FreqXlatingFirFilter::connect(gr::top_block_sptr top_block) } - void FreqXlatingFirFilter::disconnect(gr::top_block_sptr top_block) { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->disconnect(freq_xlating_fir_filter_ccf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("float") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "float") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->disconnect(freq_xlating_fir_filter_fcf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "gr_complex")) { if (dump_) { top_block->disconnect(freq_xlating_fir_filter_scf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("cshort") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "cshort")) { top_block->disconnect(freq_xlating_fir_filter_scf_, 0, complex_to_float_, 0); top_block->disconnect(complex_to_float_, 0, float_to_short_1_, 0); @@ -231,8 +293,7 @@ void FreqXlatingFirFilter::disconnect(gr::top_block_sptr top_block) top_block->disconnect(short_x2_to_cshort_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "gr_complex")) { top_block->disconnect(gr_char_to_short_, 0, freq_xlating_fir_filter_scf_, 0); if (dump_) @@ -240,8 +301,7 @@ void FreqXlatingFirFilter::disconnect(gr::top_block_sptr top_block) top_block->disconnect(freq_xlating_fir_filter_scf_, 0, file_sink_, 0); } } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "cbyte")) { top_block->disconnect(gr_char_to_short_, 0, freq_xlating_fir_filter_scf_, 0); top_block->disconnect(freq_xlating_fir_filter_scf_, 0, complex_to_complex_byte_, 0); @@ -259,33 +319,27 @@ void FreqXlatingFirFilter::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr FreqXlatingFirFilter::get_left_block() { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_ccf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("float") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "float") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_fcf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_scf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("cshort") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "cshort")) { return freq_xlating_fir_filter_scf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "gr_complex")) { return gr_char_to_short_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "cbyte")) { return gr_char_to_short_; } @@ -299,33 +353,27 @@ gr::basic_block_sptr FreqXlatingFirFilter::get_left_block() gr::basic_block_sptr FreqXlatingFirFilter::get_right_block() { - if ((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("gr_complex") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "gr_complex") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_ccf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("float") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "float") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_fcf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_scf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("short") == 0) - && (output_item_type_.compare("cshort") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "short") && (output_item_type_ == "cshort")) { return short_x2_to_cshort_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("gr_complex") == 0)) + if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "gr_complex")) { return freq_xlating_fir_filter_scf_; } - else if((taps_item_type_.compare("float") == 0) && (input_item_type_.compare("byte") == 0) - && (output_item_type_.compare("cbyte") == 0)) + else if ((taps_item_type_ == "float") && (input_item_type_ == "byte") && (output_item_type_ == "cbyte")) { return complex_to_complex_byte_; } @@ -335,75 +383,3 @@ gr::basic_block_sptr FreqXlatingFirFilter::get_right_block() LOG(ERROR) << " Unknown input filter input/output item type conversion"; } } - - -void FreqXlatingFirFilter::init() -{ - std::string default_input_item_type = "gr_complex"; - std::string default_output_item_type = "gr_complex"; - std::string default_taps_item_type = "float"; - std::string default_dump_filename = "../data/input_filter.dat"; - double default_intermediate_freq = 0; - double default_sampling_freq = 4000000; - int default_number_of_taps = 6; - unsigned int default_number_of_bands = 2; - std::vector default_bands = { 0.0, 0.4, 0.6, 1.0 }; - std::vector default_ampl = { 1.0, 1.0, 0.0, 0.0 }; - std::vector default_error_w = { 1.0, 1.0 }; - std::string default_filter_type = "bandpass"; - int default_grid_density = 16; - - DLOG(INFO) << "role " << role_; - - input_item_type_ = config_->property(role_ + ".input_item_type", default_input_item_type); - output_item_type_ = config_->property(role_ + ".output_item_type", default_output_item_type); - taps_item_type_ = config_->property(role_ + ".taps_item_type", default_taps_item_type); - dump_ = config_->property(role_ + ".dump", false); - dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); - intermediate_freq_ = config_->property(role_ + ".IF", default_intermediate_freq); - sampling_freq_ = config_->property(role_ + ".sampling_frequency", default_sampling_freq); - int number_of_taps = config_->property(role_ + ".number_of_taps", default_number_of_taps); - unsigned int number_of_bands = config_->property(role_ + ".number_of_bands", default_number_of_bands); - - std::vector bands; - std::vector ampl; - std::vector error_w; - std::string option; - double option_value; - - for (unsigned int i = 0; i < number_of_bands; i++) - { - option = ".band" + boost::lexical_cast(i + 1) + "_begin"; - option_value = config_->property(role_ + option, default_bands[i]); - bands.push_back(option_value); - - option = ".band" + boost::lexical_cast(i + 1) + "_end"; - option_value = config_->property(role_ + option, default_bands[i]); - bands.push_back(option_value); - - option = ".ampl" + boost::lexical_cast(i + 1) + "_begin"; - option_value = config_->property(role_ + option, default_bands[i]); - ampl.push_back(option_value); - - option = ".ampl" + boost::lexical_cast(i + 1) + "_end"; - option_value = config_->property(role_ + option, default_bands[i]); - ampl.push_back(option_value); - - option = ".band" + boost::lexical_cast(i + 1) + "_error"; - option_value = config_->property(role_ + option, default_bands[i]); - error_w.push_back(option_value); - } - - std::string filter_type = config_->property(role_ + ".filter_type", default_filter_type); - int grid_density = config_->property(role_ + ".grid_density", default_grid_density); - - std::vector taps_d = gr::filter::pm_remez(number_of_taps - 1, bands, ampl, - error_w, filter_type, grid_density); - - taps_.reserve(taps_d.size()); - for (std::vector::iterator it = taps_d.begin(); it != taps_d.end(); it++) - { - taps_.push_back(float(*it)); - //std::cout<<"TAP="<. + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,18 +33,22 @@ #ifndef GNSS_SDR_FREQ_XLATING_FIR_FILTER_H_ #define GNSS_SDR_FREQ_XLATING_FIR_FILTER_H_ -#include -#include +#include "complex_float_to_complex_byte.h" +#include "gnss_block_interface.h" +#include "short_x2_to_cshort.h" +#ifdef GR_GREATER_38 +#include +#else #include #include #include -#include -#include +#endif #include +#include +#include #include -#include "gnss_block_interface.h" -#include "short_x2_to_cshort.h" -#include "complex_float_to_complex_byte.h" +#include +#include class ConfigurationInterface; @@ -60,45 +64,49 @@ class ConfigurationInterface; * given a set of band edges, the desired response on those bands, and the weight given * to the error in those bands. */ -class FreqXlatingFirFilter: public GNSSBlockInterface +class FreqXlatingFirFilter : public GNSSBlockInterface { public: FreqXlatingFirFilter(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, - unsigned int out_streams); + std::string role, unsigned int in_streams, + unsigned int out_streams); virtual ~FreqXlatingFirFilter(); - std::string role() + + inline std::string role() override { return role_; } //! Returns "Freq_Xlating_Fir_Filter" - std::string implementation() + inline std::string implementation() override { return "Freq_Xlating_Fir_Filter"; } - size_t item_size() + + inline size_t item_size() override { return 0; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: gr::filter::freq_xlating_fir_filter_ccf::sptr freq_xlating_fir_filter_ccf_; gr::filter::freq_xlating_fir_filter_fcf::sptr freq_xlating_fir_filter_fcf_; gr::filter::freq_xlating_fir_filter_scf::sptr freq_xlating_fir_filter_scf_; ConfigurationInterface* config_; + int decimation_factor_; bool dump_; std::string dump_filename_; std::string input_item_type_; size_t input_size_; std::string output_item_type_; std::string taps_item_type_; - std::vector taps_; + std::vector taps_; double intermediate_freq_; double sampling_freq_; std::string role_; @@ -111,7 +119,6 @@ private: gr::blocks::float_to_short::sptr float_to_short_2_; short_x2_to_cshort_sptr short_x2_to_cshort_; complex_float_to_complex_byte_sptr complex_to_complex_byte_; - void init(); }; -#endif // GNSS_SDR_FREQ_XLATING_FIR_FILTER_H_ +#endif // GNSS_SDR_FREQ_XLATING_FIR_FILTER_H_ diff --git a/src/algorithms/input_filter/adapters/notch_filter.cc b/src/algorithms/input_filter/adapters/notch_filter.cc new file mode 100644 index 000000000..c9264e0f7 --- /dev/null +++ b/src/algorithms/input_filter/adapters/notch_filter.cc @@ -0,0 +1,130 @@ +/*! + * \file notch_filter.cc + * \brief Adapts a gnuradio gr_notch_filter + * \author Antonio Ramos, 2017. antonio.ramosdet(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "notch_filter.h" +#include "configuration_interface.h" +#include "notch_cc.h" +#include +#include + + +using google::LogMessage; + +NotchFilter::NotchFilter(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + size_t item_size_; + float pfa; + float default_pfa = 0.001; + float p_c_factor; + float default_p_c_factor = 0.9; + int length_; + int default_length_ = 32; + int n_segments_est; + int default_n_segments_est = 12500; + int n_segments_reset; + int default_n_segments_reset = 5000000; + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/input_filter.dat"; + item_type_ = configuration->property(role + ".item_type", default_item_type); + dump_ = configuration->property(role + ".dump", false); + DLOG(INFO) << "dump_ is " << dump_; + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + pfa = configuration->property(role + ".pfa", default_pfa); + p_c_factor = configuration->property(role + ".p_c_factor", default_p_c_factor); + length_ = configuration->property(role + ".length", default_length_); + n_segments_est = configuration->property(role + ".segments_est", default_n_segments_est); + n_segments_reset = configuration->property(role + ".segments_reset", default_n_segments_reset); + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + notch_filter_ = make_notch_filter(pfa, p_c_factor, length_, n_segments_est, n_segments_reset); + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "input filter(" << notch_filter_->unique_id() << ")"; + } + else + { + LOG(WARNING) << item_type_ << " unrecognized item type for notch filter"; + item_size_ = sizeof(gr_complex); + } + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +NotchFilter::~NotchFilter() = default; + + +void NotchFilter::connect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->connect(notch_filter_, 0, file_sink_, 0); + DLOG(INFO) << "connected notch filter output to file sink"; + } + else + { + DLOG(INFO) << "nothing to connect internally"; + } +} + + +void NotchFilter::disconnect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->disconnect(notch_filter_, 0, file_sink_, 0); + } +} + + +gr::basic_block_sptr NotchFilter::get_left_block() +{ + return notch_filter_; +} + + +gr::basic_block_sptr NotchFilter::get_right_block() +{ + return notch_filter_; +} diff --git a/src/algorithms/PVT/adapters/galileo_e1_pvt.h b/src/algorithms/input_filter/adapters/notch_filter.h similarity index 57% rename from src/algorithms/PVT/adapters/galileo_e1_pvt.h rename to src/algorithms/input_filter/adapters/notch_filter.h index 3614c123a..c0e1f9510 100644 --- a/src/algorithms/PVT/adapters/galileo_e1_pvt.h +++ b/src/algorithms/input_filter/adapters/notch_filter.h @@ -1,12 +1,13 @@ /*! - * \file galileo_e1_pvt.h - * \brief Interface of an adapter of a GALILEO E1 PVT solver block to a - * PvtInterface. - * \author Javier Arribas, 2013. jarribas(at)cttc.es + * \file notch_filter.h + * \brief Adapter of a multistate Notch filter + * \author Antonio Ramos, 2017. antonio.ramosdet(at)gmail.com + * + * Detailed description of the file here if needed. * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,71 +25,58 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#ifndef GNSS_SDR_NOTCH_FILTER_H_ +#define GNSS_SDR_NOTCH_FILTER_H_ - -#ifndef GNSS_SDR_GALILEO_E1_PVT_H_ -#define GNSS_SDR_GALILEO_E1_PVT_H_ - +#include "gnss_block_interface.h" +#include "notch_cc.h" +#include #include -#include "pvt_interface.h" -#include "galileo_e1_pvt_cc.h" - +#include class ConfigurationInterface; -/*! - * \brief This class implements a PvtInterface for Galileo E1 - */ -class GalileoE1Pvt : public PvtInterface +class NotchFilter : public GNSSBlockInterface { public: - GalileoE1Pvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - - virtual ~GalileoE1Pvt(); + NotchFilter(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_streams, + unsigned int out_streams); + virtual ~NotchFilter(); std::string role() { return role_; } - //! Returns "GALILEO_E1_PVT" + //! Returns "Notch_Filter" std::string implementation() { - return "GALILEO_E1_PVT"; + return "Notch_Filter"; + } + size_t item_size() + { + return 0; } - void connect(gr::top_block_sptr top_block); void disconnect(gr::top_block_sptr top_block); gr::basic_block_sptr get_left_block(); gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation. Returns sizeof(gr_complex) - size_t item_size() - { - return sizeof(gr_complex); - } - private: - galileo_e1_pvt_cc_sptr pvt_; bool dump_; - //unsigned int fs_in_; std::string dump_filename_; std::string role_; + std::string item_type_; unsigned int in_streams_; unsigned int out_streams_; + gr::blocks::file_sink::sptr file_sink_; + notch_sptr notch_filter_; }; -#endif +#endif //GNSS_SDR_NOTCH_FILTER_H_ diff --git a/src/algorithms/input_filter/adapters/notch_filter_lite.cc b/src/algorithms/input_filter/adapters/notch_filter_lite.cc new file mode 100644 index 000000000..3c83369d5 --- /dev/null +++ b/src/algorithms/input_filter/adapters/notch_filter_lite.cc @@ -0,0 +1,137 @@ +/*! + * \file notch_filter_lite.cc + * \brief Adapts a gnuradio gr_notch_filter_lite + * \author Antonio Ramos, 2017. antonio.ramosdet(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "notch_filter_lite.h" +#include "configuration_interface.h" +#include "notch_lite_cc.h" +#include +#include +#include + +using google::LogMessage; + +NotchFilterLite::NotchFilterLite(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + size_t item_size_; + float p_c_factor; + float default_p_c_factor = 0.9; + float pfa; + float default_pfa = 0.001; + int length_; + int default_length_ = 32; + int n_segments_est; + int default_n_segments_est = 12500; + int n_segments_reset; + int default_n_segments_reset = 5000000; + float default_samp_freq = 4000000; + float samp_freq = configuration->property("SignalSource.sampling_frequency", default_samp_freq); + float default_coeff_rate = samp_freq * 0.1; + float coeff_rate; + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/input_filter.dat"; + item_type_ = configuration->property(role + ".item_type", default_item_type); + dump_ = configuration->property(role + ".dump", false); + DLOG(INFO) << "dump_ is " << dump_; + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + p_c_factor = configuration->property(role + ".p_c_factor", default_p_c_factor); + pfa = configuration->property(role + ".pfa", default_pfa); + coeff_rate = configuration->property(role + ".coeff_rate", default_coeff_rate); + length_ = configuration->property(role + ".length", default_length_); + n_segments_est = configuration->property(role + ".segments_est", default_n_segments_est); + n_segments_reset = configuration->property(role + ".segments_reset", default_n_segments_reset); + int n_segments_coeff = static_cast((samp_freq / coeff_rate) / static_cast(length_)); + n_segments_coeff = std::max(1, n_segments_coeff); + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + notch_filter_lite_ = make_notch_filter_lite(p_c_factor, pfa, length_, n_segments_est, n_segments_reset, n_segments_coeff); + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "input filter(" << notch_filter_lite_->unique_id() << ")"; + } + else + { + LOG(WARNING) << item_type_ << " unrecognized item type for notch filter"; + item_size_ = sizeof(gr_complex); + } + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +NotchFilterLite::~NotchFilterLite() = default; + + +void NotchFilterLite::connect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->connect(notch_filter_lite_, 0, file_sink_, 0); + DLOG(INFO) << "connected notch filter output to file sink"; + } + else + { + DLOG(INFO) << "nothing to connect internally"; + } +} + + +void NotchFilterLite::disconnect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->disconnect(notch_filter_lite_, 0, file_sink_, 0); + } +} + + +gr::basic_block_sptr NotchFilterLite::get_left_block() +{ + return notch_filter_lite_; +} + + +gr::basic_block_sptr NotchFilterLite::get_right_block() +{ + return notch_filter_lite_; +} diff --git a/src/algorithms/PVT/adapters/hybrid_pvt.h b/src/algorithms/input_filter/adapters/notch_filter_lite.h similarity index 57% rename from src/algorithms/PVT/adapters/hybrid_pvt.h rename to src/algorithms/input_filter/adapters/notch_filter_lite.h index c2a5c30d3..d8352706d 100644 --- a/src/algorithms/PVT/adapters/hybrid_pvt.h +++ b/src/algorithms/input_filter/adapters/notch_filter_lite.h @@ -1,12 +1,13 @@ /*! - * \file hybrid_pvt.h - * \brief Interface of an adapter of a GALILEO E1 PVT solver block to a - * PvtInterface. - * \author Javier Arribas, 2013. jarribas(at)cttc.es + * \file notch_filter_lite.h + * \brief Adapts a light version of a multistate notch filter + * \author Antonio Ramos, 2017. antonio.ramosdet(at)gmail.com + * + * Detailed description of the file here if needed. * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,73 +25,58 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#ifndef GNSS_SDR_NOTCH_FILTER_LITE_H_ +#define GNSS_SDR_NOTCH_FILTER_LITE_H_ - -#ifndef GNSS_SDR_HYBRID_PVT_H_ -#define GNSS_SDR_HYBRID_PVT_H_ - +#include "gnss_block_interface.h" +#include "notch_lite_cc.h" +#include #include -#include "pvt_interface.h" -#include "hybrid_pvt_cc.h" - +#include class ConfigurationInterface; -/*! - * \brief This class implements a PvtInterface for Galileo E1 - */ -class HybridPvt : public PvtInterface +class NotchFilterLite : public GNSSBlockInterface { public: - HybridPvt(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - - virtual ~HybridPvt(); + NotchFilterLite(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_streams, + unsigned int out_streams); + virtual ~NotchFilterLite(); std::string role() { return role_; } - //! Returns "Hybrid_Pvt" + //! Returns "Notch_Filter_Lite" std::string implementation() { - return "Hybrid_PVT"; + return "Notch_Filter_Lite"; + } + size_t item_size() + { + return 0; } - void connect(gr::top_block_sptr top_block); void disconnect(gr::top_block_sptr top_block); gr::basic_block_sptr get_left_block(); gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation. Returns sizeof(gr_complex) - size_t item_size() - { - return sizeof(gr_complex); - } - private: - hybrid_pvt_cc_sptr pvt_; bool dump_; std::string dump_filename_; std::string role_; + std::string item_type_; unsigned int in_streams_; unsigned int out_streams_; - - std::string eph_xml_filename_; - bool save_assistance_to_XML(); + gr::blocks::file_sink::sptr file_sink_; + notch_lite_sptr notch_filter_lite_; }; -#endif +#endif //GNSS_SDR_NOTCH_FILTER_LITE_H_ diff --git a/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc b/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc new file mode 100644 index 000000000..fffdefe9f --- /dev/null +++ b/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc @@ -0,0 +1,176 @@ +/*! + * \file pulse_blanking_filter.cc + * \brief Instantiates the GNSS-SDR pulse blanking filter + * \author Javier Arribas 2017 + * Antonio Ramos 2017 + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "pulse_blanking_filter.h" +#include "configuration_interface.h" +#include +#include +#include +#include +#include +#include + +using google::LogMessage; + +PulseBlankingFilter::PulseBlankingFilter(ConfigurationInterface* configuration, std::string role, + unsigned int in_streams, unsigned int out_streams) : config_(configuration), role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) +{ + size_t item_size; + xlat_ = false; + std::string default_input_item_type = "gr_complex"; + std::string default_output_item_type = "gr_complex"; + std::string default_dump_filename = "../data/input_filter.dat"; + + DLOG(INFO) << "role " << role_; + + input_item_type_ = config_->property(role_ + ".input_item_type", default_input_item_type); + output_item_type_ = config_->property(role_ + ".output_item_type", default_output_item_type); + dump_ = config_->property(role_ + ".dump", false); + dump_filename_ = config_->property(role_ + ".dump_filename", default_dump_filename); + float default_pfa_ = 0.04; + float pfa = config_->property(role_ + ".pfa", default_pfa_); + int default_length_ = 32; + int length_ = config_->property(role_ + ".length", default_length_); + int default_n_segments_est = 12500; + int n_segments_est = config_->property(role_ + ".segments_est", default_n_segments_est); + int default_n_segments_reset = 5000000; + int n_segments_reset = config_->property(role_ + ".segments_reset", default_n_segments_reset); + if (input_item_type_ == "gr_complex") + { + item_size = sizeof(gr_complex); //output + input_size_ = sizeof(gr_complex); //input + pulse_blanking_cc_ = make_pulse_blanking_cc(pfa, length_, n_segments_est, n_segments_reset); + } + else + { + LOG(ERROR) << " Unknown input filter input/output item type conversion"; + item_size = sizeof(gr_complex); //avoids uninitialization + input_size_ = sizeof(gr_complex); //avoids uninitialization + } + double default_if = 0.0; + double if_aux = config_->property(role_ + ".if", default_if); + double if_ = config_->property(role_ + ".IF", if_aux); + if (std::abs(if_) > 1.0) + { + xlat_ = true; + double default_sampling_freq = 4000000.0; + double sampling_freq_ = config_->property(role_ + ".sampling_frequency", default_sampling_freq); + double default_bw = 2000000.0; + double bw_ = config_->property(role_ + ".bw", default_bw); + double default_tw = bw_ / 10.0; + double tw_ = config_->property(role_ + ".tw", default_tw); + const std::vector taps = gr::filter::firdes::low_pass(1.0, sampling_freq_, bw_, tw_); + freq_xlating_ = gr::filter::freq_xlating_fir_filter_ccf::make(1, taps, if_, sampling_freq_); + } + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + std::cout << "Dumping output into file " << dump_filename_ << std::endl; + file_sink_ = gr::blocks::file_sink::make(item_size, dump_filename_.c_str()); + } + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +PulseBlankingFilter::~PulseBlankingFilter() = default; + + +void PulseBlankingFilter::connect(gr::top_block_sptr top_block) +{ + if (input_item_type_ == "gr_complex") + { + if (dump_) + { + top_block->connect(pulse_blanking_cc_, 0, file_sink_, 0); + } + if (xlat_) + { + top_block->connect(freq_xlating_, 0, pulse_blanking_cc_, 0); + } + } + + else + { + LOG(ERROR) << " Unknown input filter input/output item type conversion"; + } +} + + +void PulseBlankingFilter::disconnect(gr::top_block_sptr top_block) +{ + if (input_item_type_ == "gr_complex") + { + if (dump_) + { + top_block->disconnect(pulse_blanking_cc_, 0, file_sink_, 0); + } + if (xlat_) + { + top_block->disconnect(freq_xlating_, 0, pulse_blanking_cc_, 0); + } + } + else + { + LOG(ERROR) << " Unknown input filter input/output item type conversion"; + } +} + + +gr::basic_block_sptr PulseBlankingFilter::get_left_block() +{ + if (input_item_type_ == "gr_complex") + { + if (xlat_) + { + return freq_xlating_; + } + return pulse_blanking_cc_; + } + LOG(ERROR) << " Unknown input filter input/output item type conversion"; + return nullptr; +} + + +gr::basic_block_sptr PulseBlankingFilter::get_right_block() +{ + if (input_item_type_ == "gr_complex") + { + return pulse_blanking_cc_; + } + LOG(ERROR) << " Unknown input filter input/output item type conversion"; + return nullptr; +} diff --git a/src/algorithms/input_filter/adapters/pulse_blanking_filter.h b/src/algorithms/input_filter/adapters/pulse_blanking_filter.h new file mode 100644 index 000000000..87f8c4994 --- /dev/null +++ b/src/algorithms/input_filter/adapters/pulse_blanking_filter.h @@ -0,0 +1,93 @@ +/*! + * \file pulse_blanking_filter.h + * \brief Instantiates the GNSS-SDR pulse blanking filter + * \author Javier Arribas 2017 + * Antonio Ramos 2017 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PULSE_BLANKING_FILTER_H_ +#define GNSS_SDR_PULSE_BLANKING_FILTER_H_ + +#include "gnss_block_interface.h" +#include "pulse_blanking_cc.h" +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include + +class ConfigurationInterface; + +class PulseBlankingFilter : public GNSSBlockInterface +{ +public: + PulseBlankingFilter(ConfigurationInterface* configuration, + std::string role, unsigned int in_streams, + unsigned int out_streams); + + virtual ~PulseBlankingFilter(); + + inline std::string role() override + { + return role_; + } + + //! Returns "Pulse_Blanking_Filter" + inline std::string implementation() override + { + return "Pulse_Blanking_Filter"; + } + + inline size_t item_size() override + { + return 0; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + ConfigurationInterface* config_; + bool dump_; + bool xlat_; + std::string dump_filename_; + std::string input_item_type_; + size_t input_size_; + std::string output_item_type_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + gr::blocks::file_sink::sptr file_sink_; + pulse_blanking_cc_sptr pulse_blanking_cc_; + gr::filter::freq_xlating_fir_filter_ccf::sptr freq_xlating_; +}; + +#endif // GNSS_SDR_PULSE_BLANKING_FILTER_H_ diff --git a/src/algorithms/input_filter/gnuradio_blocks/CMakeLists.txt b/src/algorithms/input_filter/gnuradio_blocks/CMakeLists.txt index ff87ecb74..8a4aefc11 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/input_filter/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,24 +13,49 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(INPUT_FILTER_GR_BLOCKS_SOURCES - beamformer.cc +set(INPUT_FILTER_GR_BLOCKS_SOURCES + beamformer.cc + pulse_blanking_cc.cc + notch_cc.cc + notch_lite_cc.cc +) + +set(INPUT_FILTER_GR_BLOCKS_HEADERS + beamformer.h + pulse_blanking_cc.h + notch_cc.h + notch_lite_cc.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${GNURADIO_BLOCKS_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${GNURADIO_BLOCKS_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} ) -file(GLOB INPUT_FILTER_GR_BLOCKS_HEADERS "*.h") list(SORT INPUT_FILTER_GR_BLOCKS_HEADERS) -add_library(input_filter_gr_blocks ${INPUT_FILTER_GR_BLOCKS_SOURCES} ${INPUT_FILTER_GR_BLOCKS_HEADERS}) +list(SORT INPUT_FILTER_GR_BLOCKS_SOURCES) + +add_library(input_filter_gr_blocks + ${INPUT_FILTER_GR_BLOCKS_SOURCES} + ${INPUT_FILTER_GR_BLOCKS_HEADERS}) + source_group(Headers FILES ${INPUT_FILTER_GR_BLOCKS_HEADERS}) -target_link_libraries(input_filter_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES}) + +target_link_libraries(input_filter_gr_blocks + ${GNURADIO_FILTER_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${LOG4CPP_LIBRARIES}) + +if(NOT VOLKGNSSSDR_FOUND) + add_dependencies(input_filter_gr_blocks volk_gnsssdr_module glog-${glog_RELEASE}) +else() + add_dependencies(input_filter_gr_blocks glog-${glog_RELEASE}) +endif() diff --git a/src/algorithms/input_filter/gnuradio_blocks/beamformer.cc b/src/algorithms/input_filter/gnuradio_blocks/beamformer.cc index 47a61a877..6f53c6099 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/beamformer.cc +++ b/src/algorithms/input_filter/gnuradio_blocks/beamformer.cc @@ -5,7 +5,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,16 +23,16 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "beamformer.h" -#include -#include #include +#include + #define GNSS_SDR_BEAMFORMER_CHANNELS 8 @@ -43,17 +43,19 @@ beamformer_sptr make_beamformer() beamformer::beamformer() -: gr::sync_block("beamformer", - gr::io_signature::make(GNSS_SDR_BEAMFORMER_CHANNELS, GNSS_SDR_BEAMFORMER_CHANNELS,sizeof(gr_complex)), - gr::io_signature::make(1, 1,sizeof(gr_complex))) + : gr::sync_block("beamformer", + gr::io_signature::make(GNSS_SDR_BEAMFORMER_CHANNELS, GNSS_SDR_BEAMFORMER_CHANNELS, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) { //initialize weight vector - if (posix_memalign((void**)&weight_vector, 16, GNSS_SDR_BEAMFORMER_CHANNELS * sizeof(gr_complex)) == 0){}; - - for (int i = 0; i< GNSS_SDR_BEAMFORMER_CHANNELS; i++) + if (posix_memalign(reinterpret_cast(&weight_vector), 16, GNSS_SDR_BEAMFORMER_CHANNELS * sizeof(gr_complex)) == 0) { - weight_vector[i]=gr_complex(1,0); + }; + + for (int i = 0; i < GNSS_SDR_BEAMFORMER_CHANNELS; i++) + { + weight_vector[i] = gr_complex(1, 0); } } @@ -64,10 +66,10 @@ beamformer::~beamformer() } -int beamformer::work(int noutput_items,gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) +int beamformer::work(int noutput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - gr_complex *out = (gr_complex *) output_items[0]; + auto *out = reinterpret_cast(output_items[0]); // channel output buffers // gr_complex *ch1 = (gr_complex *) input_items[0]; // gr_complex *ch2 = (gr_complex *) input_items[1]; @@ -81,12 +83,12 @@ int beamformer::work(int noutput_items,gr_vector_const_void_star &input_items, // NON-VOLK beamforming operation //TODO: Implement VOLK SIMD-accelerated beamformer! gr_complex sum; - for(int n = 0; n < noutput_items; n++) + for (int n = 0; n < noutput_items; n++) { - sum = gr_complex(0,0); + sum = gr_complex(0, 0); for (int i = 0; i < GNSS_SDR_BEAMFORMER_CHANNELS; i++) { - sum = sum + ((gr_complex*)input_items[i])[n] * weight_vector[i]; + sum = sum + (reinterpret_cast(input_items[i]))[n] * weight_vector[i]; } out[n] = sum; } diff --git a/src/algorithms/input_filter/gnuradio_blocks/beamformer.h b/src/algorithms/input_filter/gnuradio_blocks/beamformer.h index 271b9da6f..8236b11d3 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/beamformer.h +++ b/src/algorithms/input_filter/gnuradio_blocks/beamformer.h @@ -5,7 +5,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -41,19 +41,19 @@ beamformer_sptr make_beamformer(); /*! * \brief This class implements a real-time software-defined spatial filter using the CTTC GNSS experimental antenna array input and a set of dynamically reloadable weights */ -class beamformer: public gr::sync_block +class beamformer : public gr::sync_block { private: friend beamformer_sptr make_beamformer_sptr(); - gr_complex* weight_vector; + gr_complex *weight_vector; public: beamformer(); ~beamformer(); - int work (int noutput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc new file mode 100644 index 000000000..3a3c9f8a3 --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc @@ -0,0 +1,154 @@ +/*! + * \file notch_cc.cc + * \brief Implements a multi state notch filter algorithm + * \author Antonio Ramos (antonio.ramosdet(at)gmail.com) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "notch_cc.h" +#include +#include +#include +#include +#include +#include + +using google::LogMessage; + +notch_sptr make_notch_filter(float pfa, float p_c_factor, + int32_t length_, int32_t n_segments_est, int32_t n_segments_reset) +{ + return notch_sptr(new Notch(pfa, p_c_factor, length_, n_segments_est, n_segments_reset)); +} + + +Notch::Notch(float pfa, + float p_c_factor, + int32_t length_, + int32_t n_segments_est, + int32_t n_segments_reset) : gr::block("Notch", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + const int32_t alignment_multiple = volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1, alignment_multiple)); + set_history(2); + this->pfa = pfa; + noise_pow_est = 0.0; + this->p_c_factor = gr_complex(p_c_factor, 0.0); + this->length_ = length_; // Set the number of samples per segment + filter_state_ = false; // Initial state of the filter + n_deg_fred = 2 * length_; // Number of dregrees of freedom + n_segments = 0; + this->n_segments_est = n_segments_est; // Set the number of segments for noise power estimation + this->n_segments_reset = n_segments_reset; // Set the period (in segments) when the noise power is estimated + z_0 = gr_complex(0.0, 0.0); + boost::math::chi_squared_distribution my_dist_(n_deg_fred); + thres_ = boost::math::quantile(boost::math::complement(my_dist_, pfa)); + c_samples = static_cast(volk_malloc(length_ * sizeof(gr_complex), volk_get_alignment())); + angle_ = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); + power_spect = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); + last_out = gr_complex(0.0, 0.0); + d_fft = std::unique_ptr(new gr::fft::fft_complex(length_, true)); +} + + +Notch::~Notch() +{ + volk_free(c_samples); + volk_free(angle_); + volk_free(power_spect); +} + + +void Notch::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for (int &aux : ninput_items_required) + { + aux = length_; + } +} + + +int Notch::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t index_out = 0; + float sig2dB = 0.0; + float sig2lin = 0.0; + lv_32fc_t dot_prod_; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + in++; + while ((index_out + length_) < noutput_items) + { + if ((n_segments < n_segments_est) && (filter_state_ == false)) + { + memcpy(d_fft->get_inbuf(), in, sizeof(gr_complex) * length_); + d_fft->execute(); + volk_32fc_s32f_power_spectrum_32f(power_spect, d_fft->get_outbuf(), 1.0, length_); + volk_32f_s32f_calc_spectral_noise_floor_32f(&sig2dB, power_spect, 15.0, length_); + sig2lin = std::pow(10.0, (sig2dB / 10.0)) / (static_cast(n_deg_fred)); + noise_pow_est = (static_cast(n_segments) * noise_pow_est + sig2lin) / (static_cast(n_segments + 1)); + memcpy(out, in, sizeof(gr_complex) * length_); + } + else + { + volk_32fc_x2_conjugate_dot_prod_32fc(&dot_prod_, in, in, length_); + if ((lv_creal(dot_prod_) / noise_pow_est) > thres_) + { + if (filter_state_ == false) + { + filter_state_ = true; + last_out = gr_complex(0, 0); + } + volk_32fc_x2_multiply_conjugate_32fc(c_samples, in, (in - 1), length_); + volk_32fc_s32f_atan2_32f(angle_, c_samples, static_cast(1.0), length_); + for (int32_t aux = 0; aux < length_; aux++) + { + z_0 = std::exp(gr_complex(0, 1) * (*(angle_ + aux))); + *(out + aux) = *(in + aux) - z_0 * (*(in + aux - 1)) + p_c_factor * z_0 * last_out; + last_out = *(out + aux); + } + } + else + { + if (n_segments > n_segments_reset) + { + n_segments = 0; + } + filter_state_ = false; + memcpy(out, in, sizeof(gr_complex) * length_); + } + } + index_out += length_; + n_segments++; + in += length_; + out += length_; + } + consume_each(index_out); + return index_out; +} diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h new file mode 100644 index 000000000..ab8f3b693 --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h @@ -0,0 +1,83 @@ +/*! + * \file notch_cc.h + * \brief Implements a notch filter algorithm + * \author Antonio Ramos (antonio.ramosdet(at)gmail.com) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_NOTCH_H_ +#define GNSS_SDR_NOTCH_H_ + +#include +#include +#include +#include +#include + +class Notch; + +typedef boost::shared_ptr notch_sptr; + +notch_sptr make_notch_filter(float pfa, float p_c_factor, + int32_t length_, int32_t n_segments_est, int32_t n_segments_reset); + +/*! + * \brief This class implements a real-time software-defined multi state notch filter + */ + +class Notch : public gr::block +{ +private: + float pfa; + float noise_pow_est; + float thres_; + int32_t length_; + int32_t n_deg_fred; + uint32_t n_segments; + uint32_t n_segments_est; + uint32_t n_segments_reset; + bool filter_state_; + gr_complex last_out; + gr_complex z_0; + gr_complex p_c_factor; + gr_complex *c_samples; + float *angle_; + float *power_spect; + std::unique_ptr d_fft; + +public: + Notch(float pfa, float p_c_factor, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset); + + ~Notch(); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif //GNSS_SDR_NOTCH_H_ diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc new file mode 100644 index 000000000..03a3639db --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc @@ -0,0 +1,166 @@ +/*! + * \file notch_lite_cc.cc + * \brief Implements a multi state notch filter algorithm + * \author Antonio Ramos (antonio.ramosdet(at)gmail.com) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "notch_lite_cc.h" +#include +#include +#include +#include +#include +#include + +using google::LogMessage; + +notch_lite_sptr make_notch_filter_lite(float p_c_factor, float pfa, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset, int32_t n_segments_coeff) +{ + return notch_lite_sptr(new NotchLite(p_c_factor, pfa, length_, n_segments_est, n_segments_reset, n_segments_coeff)); +} + + +NotchLite::NotchLite(float p_c_factor, + float pfa, + int32_t length_, + int32_t n_segments_est, + int32_t n_segments_reset, + int32_t n_segments_coeff) : gr::block("NotchLite", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + const int32_t alignment_multiple = volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1, alignment_multiple)); + set_history(2); + this->p_c_factor = gr_complex(p_c_factor, 0.0); + this->n_segments_est = n_segments_est; + this->n_segments_reset = n_segments_reset; + this->n_segments_coeff_reset = n_segments_coeff; + this->n_segments_coeff = 0; + this->length_ = length_; + set_output_multiple(length_); + this->pfa = pfa; + n_segments = 0; + n_deg_fred = 2 * length_; + noise_pow_est = 0.0; + filter_state_ = false; + z_0 = gr_complex(0.0, 0.0); + last_out = gr_complex(0.0, 0.0); + boost::math::chi_squared_distribution my_dist_(n_deg_fred); + thres_ = boost::math::quantile(boost::math::complement(my_dist_, pfa)); + c_samples1 = gr_complex(0.0, 0.0); + c_samples2 = gr_complex(0.0, 0.0); + angle1 = 0.0; + angle2 = 0.0; + power_spect = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); + d_fft = std::unique_ptr(new gr::fft::fft_complex(length_, true)); +} + + +NotchLite::~NotchLite() +{ + volk_free(power_spect); +} + + +void NotchLite::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for (int &aux : ninput_items_required) + { + aux = length_; + } +} + + +int NotchLite::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t index_out = 0; + float sig2dB = 0.0; + float sig2lin = 0.0; + lv_32fc_t dot_prod_; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + in++; + while ((index_out + length_) < noutput_items) + { + if ((n_segments < n_segments_est) && (filter_state_ == false)) + { + memcpy(d_fft->get_inbuf(), in, sizeof(gr_complex) * length_); + d_fft->execute(); + volk_32fc_s32f_power_spectrum_32f(power_spect, d_fft->get_outbuf(), 1.0, length_); + volk_32f_s32f_calc_spectral_noise_floor_32f(&sig2dB, power_spect, 15.0, length_); + sig2lin = std::pow(10.0, (sig2dB / 10.0)) / static_cast(n_deg_fred); + noise_pow_est = (static_cast(n_segments) * noise_pow_est + sig2lin) / static_cast(n_segments + 1); + memcpy(out, in, sizeof(gr_complex) * length_); + } + else + { + volk_32fc_x2_conjugate_dot_prod_32fc(&dot_prod_, in, in, length_); + if ((lv_creal(dot_prod_) / noise_pow_est) > thres_) + { + if (filter_state_ == false) + { + filter_state_ = true; + last_out = gr_complex(0, 0); + n_segments_coeff = 0; + } + if (n_segments_coeff == 0) + { + volk_32fc_x2_multiply_conjugate_32fc(&c_samples1, (in + 1), in, 1); + volk_32fc_s32f_atan2_32f(&angle1, &c_samples1, static_cast(1.0), 1); + volk_32fc_x2_multiply_conjugate_32fc(&c_samples2, (in + length_ - 1), (in + length_ - 2), 1); + volk_32fc_s32f_atan2_32f(&angle2, &c_samples2, static_cast(1.0), 1); + float angle_ = (angle1 + angle2) / 2.0; + z_0 = std::exp(gr_complex(0, 1) * angle_); + } + for (int32_t aux = 0; aux < length_; aux++) + { + *(out + aux) = *(in + aux) - z_0 * (*(in + aux - 1)) + p_c_factor * z_0 * last_out; + last_out = *(out + aux); + } + n_segments_coeff++; + n_segments_coeff = n_segments_coeff % n_segments_coeff_reset; + } + else + { + if (n_segments > n_segments_reset) + { + n_segments = 0; + } + filter_state_ = false; + memcpy(out, in, sizeof(gr_complex) * length_); + } + } + index_out += length_; + n_segments++; + in += length_; + out += length_; + } + consume_each(index_out); + return index_out; +} diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h new file mode 100644 index 000000000..c312c2b98 --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h @@ -0,0 +1,86 @@ +/*! + * \file notch_lite_cc.h + * \brief Implements a notch filter light algorithm + * \author Antonio Ramos (antonio.ramosdet(at)gmail.com) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_NOTCH_LITE_H_ +#define GNSS_SDR_NOTCH_LITE_H_ + +#include +#include +#include +#include +#include + +class NotchLite; + +typedef boost::shared_ptr notch_lite_sptr; + +notch_lite_sptr make_notch_filter_lite(float p_c_factor, float pfa, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset, int32_t n_segments_coeff); + +/*! + * \brief This class implements a real-time software-defined multi state notch filter light version + */ + +class NotchLite : public gr::block +{ +private: + int32_t length_; + int32_t n_segments; + int32_t n_segments_est; + int32_t n_segments_reset; + int32_t n_segments_coeff_reset; + int32_t n_segments_coeff; + int32_t n_deg_fred; + float pfa; + float thres_; + float noise_pow_est; + bool filter_state_; + gr_complex last_out; + gr_complex z_0; + gr_complex p_c_factor; + gr_complex c_samples1; + gr_complex c_samples2; + float angle1; + float angle2; + float *power_spect; + std::unique_ptr d_fft; + +public: + NotchLite(float p_c_factor, float pfa, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset, int32_t n_segments_coeff); + + ~NotchLite(); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif //GNSS_SDR_NOTCH_LITE_H_ diff --git a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc new file mode 100644 index 000000000..02c98fb5c --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc @@ -0,0 +1,131 @@ +/*! + * \file pulse_blanking_cc.cc + * \brief Implements a pulse blanking algorithm + * \author Javier Arribas (jarribas(at)cttc.es) + * Antonio Ramos (antonio.ramosdet(at)gmail.com) + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "pulse_blanking_cc.h" +#include +#include +#include +#include +#include + +using google::LogMessage; + +pulse_blanking_cc_sptr make_pulse_blanking_cc(float pfa, int32_t length_, + int32_t n_segments_est, int32_t n_segments_reset) +{ + return pulse_blanking_cc_sptr(new pulse_blanking_cc(pfa, length_, n_segments_est, n_segments_reset)); +} + + +pulse_blanking_cc::pulse_blanking_cc(float pfa, + int32_t length_, + int32_t n_segments_est, + int32_t n_segments_reset) : gr::block("pulse_blanking_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + const int32_t alignment_multiple = volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1, alignment_multiple)); + this->pfa = pfa; + this->length_ = length_; + last_filtered = false; + n_segments = 0; + this->n_segments_est = n_segments_est; + this->n_segments_reset = n_segments_reset; + noise_power_estimation = 0.0; + n_deg_fred = 2 * length_; + boost::math::chi_squared_distribution my_dist_(n_deg_fred); + thres_ = boost::math::quantile(boost::math::complement(my_dist_, pfa)); + zeros_ = static_cast(volk_malloc(length_ * sizeof(gr_complex), volk_get_alignment())); + for (int32_t aux = 0; aux < length_; aux++) + { + zeros_[aux] = gr_complex(0.0, 0.0); + } +} + + +pulse_blanking_cc::~pulse_blanking_cc() +{ + volk_free(zeros_); +} + + +void pulse_blanking_cc::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for (int &aux : ninput_items_required) + { + aux = length_; + } +} + + +int pulse_blanking_cc::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + auto *magnitude = static_cast(volk_malloc(noutput_items * sizeof(float), volk_get_alignment())); + volk_32fc_magnitude_squared_32f(magnitude, in, noutput_items); + int32_t sample_index = 0; + float segment_energy; + while ((sample_index + length_) < noutput_items) + { + volk_32f_accumulator_s32f(&segment_energy, (magnitude + sample_index), length_); + if ((n_segments < n_segments_est) && (last_filtered == false)) + { + noise_power_estimation = (static_cast(n_segments) * noise_power_estimation + segment_energy / static_cast(n_deg_fred)) / static_cast(n_segments + 1); + memcpy(out, in, sizeof(gr_complex) * length_); + } + else + { + if ((segment_energy / noise_power_estimation) > thres_) + { + memcpy(out, zeros_, sizeof(gr_complex) * length_); + last_filtered = true; + } + else + { + memcpy(out, in, sizeof(gr_complex) * length_); + last_filtered = false; + if (n_segments > n_segments_reset) + { + n_segments = 0; + } + } + } + in += length_; + out += length_; + sample_index += length_; + n_segments++; + } + volk_free(magnitude); + consume_each(sample_index); + return sample_index; +} diff --git a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h new file mode 100644 index 000000000..4d0f72f00 --- /dev/null +++ b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h @@ -0,0 +1,70 @@ +/*! + * \file pulse_blanking_cc.h + * \brief Implements a pulse blanking algorithm + * \author Javier Arribas (jarribas(at)cttc.es) + * Antonio Ramos (antonio.ramosdet(at)gmail.com) + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PULSE_BLANKING_H_ +#define GNSS_SDR_PULSE_BLANKING_H_ + +#include +#include +#include + +class pulse_blanking_cc; + +typedef boost::shared_ptr pulse_blanking_cc_sptr; + +pulse_blanking_cc_sptr make_pulse_blanking_cc(float pfa, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset); + + +class pulse_blanking_cc : public gr::block +{ +private: + int32_t length_; + int32_t n_segments; + int32_t n_segments_est; + int32_t n_segments_reset; + int32_t n_deg_fred; + bool last_filtered; + float noise_power_estimation; + float thres_; + float pfa; + gr_complex *zeros_; + +public: + pulse_blanking_cc(float pfa, int32_t length_, int32_t n_segments_est, int32_t n_segments_reset); + + ~pulse_blanking_cc(); + + int general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); +}; + +#endif diff --git a/src/algorithms/libs/CMakeLists.txt b/src/algorithms/libs/CMakeLists.txt index f0a62912f..0907ba030 100644 --- a/src/algorithms/libs/CMakeLists.txt +++ b/src/algorithms/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,16 +13,21 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # +add_subdirectory(rtklib) set(GNSS_SPLIBS_SOURCES - gps_l2c_signal.cc + gps_l2c_signal.cc + gps_l5_signal.cc galileo_e1_signal_processing.cc gnss_sdr_valve.cc + gnss_sdr_sample_counter.cc gnss_signal_processing.cc gps_sdr_signal_processing.cc + glonass_l1_signal_processing.cc + glonass_l2_signal_processing.cc pass_through.cc galileo_e5_signal_processing.cc complex_byte_to_float_x2.cc @@ -30,55 +35,115 @@ set(GNSS_SPLIBS_SOURCES cshort_to_float_x2.cc short_x2_to_cshort.cc complex_float_to_complex_byte.cc + conjugate_cc.cc + conjugate_sc.cc + conjugate_ic.cc + gnss_sdr_create_directory.cc + geofunctions.cc ) +set(GNSS_SPLIBS_HEADERS + gps_l2c_signal.h + gps_l5_signal.h + galileo_e1_signal_processing.h + gnss_sdr_valve.h + gnss_sdr_sample_counter.h + gnss_signal_processing.h + gps_sdr_signal_processing.h + glonass_l1_signal_processing.h + glonass_l2_signal_processing.h + pass_through.h + galileo_e5_signal_processing.h + complex_byte_to_float_x2.h + byte_x2_to_complex_byte.h + cshort_to_float_x2.h + short_x2_to_cshort.h + complex_float_to_complex_byte.h + conjugate_cc.h + conjugate_sc.h + conjugate_ic.h + gnss_sdr_create_directory.h + gnss_circular_deque.h + geofunctions.h +) + +if(ENABLE_FPGA) + set(GNSS_SPLIBS_SOURCES + ${GNSS_SPLIBS_SOURCES} + gnss_sdr_time_counter.cc + gnss_sdr_fpga_sample_counter.cc + ) + set(GNSS_SPLIBS_HEADERS + ${GNSS_SPLIBS_HEADERS} + gnss_sdr_time_counter.h + gnss_sdr_fpga_sample_counter.h + ) +endif() if(OPENCL_FOUND) set(GNSS_SPLIBS_SOURCES ${GNSS_SPLIBS_SOURCES} - fft_execute.cc # Needs OpenCL - fft_setup.cc # Needs OpenCL - fft_kernelstring.cc # Needs OpenCL + opencl/fft_execute.cc # Needs OpenCL + opencl/fft_setup.cc # Needs OpenCL + opencl/fft_kernelstring.cc # Needs OpenCL ) -endif(OPENCL_FOUND) +endif() include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${GNURADIO_BLOCKS_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${GNURADIO_BLOCKS_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} ) if(OPENCL_FOUND) - include_directories( ${OPENCL_INCLUDE_DIRS} ) + include_directories(${OPENCL_INCLUDE_DIRS}) if(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") - else(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) - endif(OS_IS_MACOSX) -endif(OPENCL_FOUND) + set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") + else() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) + endif() +endif() + +add_definitions(-DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}") -file(GLOB GNSS_SPLIBS_HEADERS "*.h") list(SORT GNSS_SPLIBS_HEADERS) +list(SORT GNSS_SPLIBS_SOURCES) + add_library(gnss_sp_libs ${GNSS_SPLIBS_SOURCES} ${GNSS_SPLIBS_HEADERS}) source_group(Headers FILES ${GNSS_SPLIBS_HEADERS}) -target_link_libraries(gnss_sp_libs ${GNURADIO_RUNTIME_LIBRARIES} - ${VOLK_LIBRARIES} ${ORC_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${OPT_LIBRARIES} - gnss_rx +target_link_libraries(gnss_sp_libs + ${GNURADIO_RUNTIME_LIBRARIES} + ${VOLK_LIBRARIES} ${ORC_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + ${GFlags_LIBS} + ${ARMADILLO_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${OPT_LIBRARIES} + gnss_rx ) -if(NOT VOLK_GNSSSDR_FOUND) - add_dependencies(gnss_sp_libs volk_gnsssdr_module) -endif(NOT VOLK_GNSSSDR_FOUND) +if(NOT VOLKGNSSSDR_FOUND) + add_dependencies(gnss_sp_libs volk_gnsssdr_module + armadillo-${armadillo_RELEASE}) +else() + add_dependencies(gnss_sp_libs armadillo-${armadillo_RELEASE}) +endif() + +if(${GFLAGS_GREATER_20}) + add_definitions(-DGFLAGS_GREATER_2_0=1) +endif() + +add_library(gnss_sdr_flags gnss_sdr_flags.cc gnss_sdr_flags.h) +source_group(Headers FILES gnss_sdr_flags.h) +target_link_libraries(gnss_sdr_flags ${GFlags_LIBS}) diff --git a/src/algorithms/libs/byte_x2_to_complex_byte.cc b/src/algorithms/libs/byte_x2_to_complex_byte.cc index c0da81b6c..a3a78c067 100644 --- a/src/algorithms/libs/byte_x2_to_complex_byte.cc +++ b/src/algorithms/libs/byte_x2_to_complex_byte.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,10 +40,9 @@ byte_x2_to_complex_byte_sptr make_byte_x2_to_complex_byte() } - byte_x2_to_complex_byte::byte_x2_to_complex_byte() : sync_block("byte_x2_to_complex_byte", - gr::io_signature::make (2, 2, sizeof(int8_t)), // int8_t, defined in stdint.h and included in volk.h (signed char) - gr::io_signature::make (1, 1, sizeof(lv_8sc_t))) // lv_8sc_t is a Volk's typedef for std::complex + gr::io_signature::make(2, 2, sizeof(int8_t)), // int8_t, defined in stdint.h and included in volk.h (signed char) + gr::io_signature::make(1, 1, sizeof(lv_8sc_t))) // lv_8sc_t is a Volk's typedef for std::complex { const int alignment_multiple = volk_get_alignment() / sizeof(lv_8sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -51,16 +50,16 @@ byte_x2_to_complex_byte::byte_x2_to_complex_byte() : sync_block("byte_x2_to_comp int byte_x2_to_complex_byte::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const int8_t *in0 = (const int8_t *) input_items[0]; - const int8_t *in1 = (const int8_t *) input_items[1]; - lv_8sc_t *out = (lv_8sc_t *) output_items[0]; + const auto *in0 = reinterpret_cast(input_items[0]); + const auto *in1 = reinterpret_cast(input_items[1]); + auto *out = reinterpret_cast(output_items[0]); // This could be put into a volk kernel int8_t real_part; int8_t imag_part; - for(int number = 0; number < noutput_items; number++) + for (int number = 0; number < noutput_items; number++) { // lv_cmake(r, i) defined at volk/volk_complex.h real_part = *in0++; diff --git a/src/algorithms/libs/byte_x2_to_complex_byte.h b/src/algorithms/libs/byte_x2_to_complex_byte.h index a46f4c544..c7e49bc98 100644 --- a/src/algorithms/libs/byte_x2_to_complex_byte.h +++ b/src/algorithms/libs/byte_x2_to_complex_byte.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,12 +49,13 @@ class byte_x2_to_complex_byte : public gr::sync_block { private: friend byte_x2_to_complex_byte_sptr make_byte_x2_to_complex_byte(); + public: byte_x2_to_complex_byte(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/libs/cl.hpp b/src/algorithms/libs/cl.hpp deleted file mode 100644 index 0480e3116..000000000 --- a/src/algorithms/libs/cl.hpp +++ /dev/null @@ -1,12305 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008-2013 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -/*! \file - * - * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and - * OpenCL 1.2 (rev 15) - * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes - * - * Additions and fixes from: - * Brian Cole, March 3rd 2010 and April 2012 - * Matt Gruenke, April 2012. - * Bruce Merry, February 2013. - * - * \version 1.2.5 - * \date June 2013 - * - * Optional extension support - * - * cl - * cl_ext_device_fission - * #define USE_CL_DEVICE_FISSION - */ - -/*! \mainpage - * \section intro Introduction - * For many large applications C++ is the language of choice and so it seems - * reasonable to define C++ bindings for OpenCL. - * - * - * The interface is contained with a single C++ header file \em cl.hpp and all - * definitions are contained within the namespace \em cl. There is no additional - * requirement to include \em cl.h and to use either the C++ or original C - * bindings it is enough to simply include \em cl.hpp. - * - * The bindings themselves are lightweight and correspond closely to the - * underlying C API. Using the C++ bindings introduces no additional execution - * overhead. - * - * For detail documentation on the bindings see: - * - * The OpenCL C++ Wrapper API 1.2 (revision 09) - * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf - * - * \section example Example - * - * The following example shows a general use case for the C++ - * bindings, including support for the optional exception feature and - * also the supplied vector and string classes, see following sections for - * decriptions of these features. - * - * \code - * #define __CL_ENABLE_EXCEPTIONS - * - * #if defined(__APPLE__) || defined(__MACOSX) - * #include - * #else - * #include - * #endif - * #include - * #include - * #include - * - * const char * helloStr = "__kernel void " - * "hello(void) " - * "{ " - * " " - * "} "; - * - * int - * main(void) - * { - * cl_int err = CL_SUCCESS; - * try { - * - * std::vector platforms; - * cl::Platform::get(&platforms); - * if (platforms.size() == 0) { - * std::cout << "Platform size 0\n"; - * return -1; - * } - * - * cl_context_properties properties[] = - * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; - * cl::Context context(CL_DEVICE_TYPE_CPU, properties); - * - * std::vector devices = context.getInfo(); - * - * cl::Program::Sources source(1, - * std::make_pair(helloStr,strlen(helloStr))); - * cl::Program program_ = cl::Program(context, source); - * program_.build(devices); - * - * cl::Kernel kernel(program_, "hello", &err); - * - * cl::Event event; - * cl::CommandQueue queue(context, devices[0], 0, &err); - * queue.enqueueNDRangeKernel( - * kernel, - * cl::NullRange, - * cl::NDRange(4,4), - * cl::NullRange, - * NULL, - * &event); - * - * event.wait(); - * } - * catch (cl::Error err) { - * std::cerr - * << "ERROR: " - * << err.what() - * << "(" - * << err.err() - * << ")" - * << std::endl; - * } - * - * return EXIT_SUCCESS; - * } - * - * \endcode - * - */ -#ifndef CL_HPP_ -#define CL_HPP_ - -#ifdef _WIN32 - -#include -#include -#include -#include - -#if defined(__CL_ENABLE_EXCEPTIONS) -#include -#endif // #if defined(__CL_ENABLE_EXCEPTIONS) - -#pragma push_macro("max") -#undef max -#if defined(USE_DX_INTEROP) -#include -#include -#endif -#endif // _WIN32 - -// -#if defined(USE_CL_DEVICE_FISSION) -#include -#endif - -#if defined(__APPLE__) || defined(__MACOSX) -#include -#include -#include -#else -#include -#include -#endif // !__APPLE__ - -// To avoid accidentally taking ownership of core OpenCL types -// such as cl_kernel constructors are made explicit -// under OpenCL 1.2 -#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS explicit -#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS -#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - -// Define deprecated prefixes and suffixes to ensure compilation -// in case they are not pre-defined -#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) - -#if !defined(CL_CALLBACK) -#define CL_CALLBACK -#endif //CL_CALLBACK - -#include -#include - -#if !defined(__NO_STD_VECTOR) -#include -#endif - -#if !defined(__NO_STD_STRING) -#include -#endif - -#if defined(linux) || defined(__APPLE__) || defined(__MACOSX) -#include - -#include -#include -#endif // linux - -#include - - -/*! \namespace cl - * - * \brief The OpenCL C++ bindings are defined within this namespace. - * - */ -namespace cl { - -class Memory; - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __INIT_CL_EXT_FCN_PTR(name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddress(#name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - -#if defined(CL_VERSION_1_2) -#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddressForPlatform(platform, #name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - -class Program; -class Device; -class Context; -class CommandQueue; -class Memory; -class Buffer; - -#if defined(__CL_ENABLE_EXCEPTIONS) -/*! \brief Exception class - * - * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. - */ -class Error : public std::exception -{ -private: - cl_int err_; - const char * errStr_; -public: - /*! \brief Create a new CL error exception for a given error code - * and corresponding message. - * - * \param err error code value. - * - * \param errStr a descriptive string that must remain in scope until - * handling of the exception has concluded. If set, it - * will be returned by what(). - */ - Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) - {} - - ~Error() throw() {} - - /*! \brief Get error string associated with exception - * - * \return A memory pointer to the error message string. - */ - virtual const char * what() const throw () - { - if (errStr_ == NULL) { - return "empty"; - } - else { - return errStr_; - } - } - - /*! \brief Get error code associated with exception - * - * \return The error code. - */ - cl_int err(void) const { return err_; } -}; - -#define __ERR_STR(x) #x -#else -#define __ERR_STR(x) NULL -#endif // __CL_ENABLE_EXCEPTIONS - - -namespace detail -{ -#if defined(__CL_ENABLE_EXCEPTIONS) -static inline cl_int errHandler ( - cl_int err, - const char * errStr = NULL) -{ - if (err != CL_SUCCESS) { - throw Error(err, errStr); - } - return err; -} -#else -static inline cl_int errHandler (cl_int err, const char * errStr = NULL) -{ - (void) errStr; // suppress unused variable warning - return err; -} -#endif // __CL_ENABLE_EXCEPTIONS -} - - - -//! \cond DOXYGEN_DETAIL -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) -#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) -#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) -#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) -#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) -#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) -#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) -#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) -#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) -#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) -#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) -#if defined(CL_VERSION_1_2) -#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) -#endif // #if defined(CL_VERSION_1_2) -#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) -#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) -#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) -#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) - -#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) -#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) -#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) - -#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) -#define __COPY_ERR __ERR_STR(cl::copy) -#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) -#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) -#if defined(CL_VERSION_1_2) -#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) -#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) -#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) -#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) - -#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) -#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) -#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) -#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) - -#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) -#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) -#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) -#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) -#if defined(CL_VERSION_1_2) -#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) -#endif // #if defined(CL_VERSION_1_2) -#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) -#if defined(CL_VERSION_1_2) -#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) - -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) - -#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) -#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) -#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) -#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) -#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) -#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) -#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) -#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) -#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) -#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) -#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) -#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) -#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) -#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) -#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) -#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) -#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) -#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) -#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) -#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) -#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) -#endif // #if defined(CL_VERSION_1_2) - -#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) -#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) - - -#define __RETAIN_ERR __ERR_STR(Retain Object) -#define __RELEASE_ERR __ERR_STR(Release Object) -#define __FLUSH_ERR __ERR_STR(clFlush) -#define __FINISH_ERR __ERR_STR(clFinish) -#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) - -/** - * CL 1.2 version that uses device fission. - */ -#if defined(CL_VERSION_1_2) -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) -#else -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) -#endif // #if defined(CL_VERSION_1_2) - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) -#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) -#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) -#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) -#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) -#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) -#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) -#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) -#endif // #if defined(CL_VERSION_1_1) - -#endif // __CL_USER_OVERRIDE_ERROR_STRINGS -//! \endcond - -/** - * CL 1.2 marker and barrier commands - */ -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) -#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) -#endif // #if defined(CL_VERSION_1_2) - -#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) -typedef std::string STRING_CLASS; -#elif !defined(__USE_DEV_STRING) - -/*! \class string - * \brief Simple string class, that provides a limited subset of std::string - * functionality but avoids many of the issues that come with that class. - - * \note Deprecated. Please use std::string as default or - * re-define the string class to match the std::string - * interface by defining STRING_CLASS - */ -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -{ -private: - ::size_t size_; - char * str_; -public: - //! \brief Constructs an empty string, allocating no memory. - string(void) : size_(0), str_(NULL) - { - } - - /*! \brief Constructs a string populated from an arbitrary value of - * specified size. - * - * An extra '\0' is added, in case none was contained in str. - * - * \param str the initial value of the string instance. Note that '\0' - * characters receive no special treatment. If NULL, - * the string is left empty, with a size of 0. - * - * \param size the number of characters to copy from str. - */ - string(const char * str, ::size_t size) : - size_(size), - str_(NULL) - { - if( size > 0 ) { - str_ = new char[size_+1]; - if (str_ != NULL) { - memcpy(str_, str, size_ * sizeof(char)); - str_[size_] = '\0'; - } - else { - size_ = 0; - } - } - } - - /*! \brief Constructs a string populated from a null-terminated value. - * - * \param str the null-terminated initial value of the string instance. - * If NULL, the string is left empty, with a size of 0. - */ - string(const char * str) : - size_(0), - str_(NULL) - { - if( str ) { - size_= ::strlen(str); - } - if( size_ > 0 ) { - str_ = new char[size_ + 1]; - if (str_ != NULL) { - memcpy(str_, str, (size_ + 1) * sizeof(char)); - } - } - } - - void resize( ::size_t n ) - { - if( size_ == n ) { - return; - } - if (n == 0) { - if( str_ ) { - delete [] str_; - } - str_ = NULL; - size_ = 0; - } - else { - char *newString = new char[n + 1]; - int copySize = n; - if( size_ < n ) { - copySize = size_; - } - size_ = n; - - if(str_) { - memcpy(newString, str_, (copySize + 1) * sizeof(char)); - } - if( copySize < size_ ) { - memset(newString + copySize, 0, size_ - copySize); - } - newString[size_] = '\0'; - - delete [] str_; - str_ = newString; - } - } - - const char& operator[] ( ::size_t pos ) const - { - return str_[pos]; - } - - char& operator[] ( ::size_t pos ) - { - return str_[pos]; - } - - /*! \brief Copies the value of another string to this one. - * - * \param rhs the string to copy. - * - * \returns a reference to the modified instance. - */ - string& operator=(const string& rhs) - { - if (this == &rhs) { - return *this; - } - - if( str_ != NULL ) { - delete [] str_; - str_ = NULL; - size_ = 0; - } - - if (rhs.size_ == 0 || rhs.str_ == NULL) { - str_ = NULL; - size_ = 0; - } - else { - str_ = new char[rhs.size_ + 1]; - size_ = rhs.size_; - - if (str_ != NULL) { - memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); - } - else { - size_ = 0; - } - } - - return *this; - } - - /*! \brief Constructs a string by copying the value of another instance. - * - * \param rhs the string to copy. - */ - string(const string& rhs) : - size_(0), - str_(NULL) - { - *this = rhs; - } - - //! \brief Destructor - frees memory used to hold the current value. - ~string() - { - delete[] str_; - str_ = NULL; - } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t size(void) const { return size_; } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t length(void) const { return size(); } - - /*! \brief Returns a pointer to the private copy held by this instance, - * or "" if empty/unset. - */ - const char * c_str(void) const { return (str_) ? str_ : "";} -}; -typedef cl::string STRING_CLASS; -#endif // #elif !defined(__USE_DEV_STRING) - -#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) -#define VECTOR_CLASS std::vector -#elif !defined(__USE_DEV_VECTOR) -#define VECTOR_CLASS cl::vector - -#if !defined(__MAX_DEFAULT_VECTOR_SIZE) -#define __MAX_DEFAULT_VECTOR_SIZE 10 -#endif - -/*! \class vector - * \brief Fixed sized vector implementation that mirroring - * - * \note Deprecated. Please use std::vector as default or - * re-define the vector class to match the std::vector - * interface by defining VECTOR_CLASS - - * \note Not recommended for use with custom objects as - * current implementation will construct N elements - * - * std::vector functionality. - * \brief Fixed sized vector compatible with std::vector. - * - * \note - * This differs from std::vector<> not just in memory allocation, - * but also in terms of when members are constructed, destroyed, - * and assigned instead of being copy constructed. - * - * \param T type of element contained in the vector. - * - * \param N maximum size of the vector. - */ -template -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -{ -private: - T data_[N]; - unsigned int size_; - -public: - //! \brief Constructs an empty vector with no memory allocated. - vector() : - size_(static_cast(0)) - {} - - //! \brief Deallocates the vector's memory and destroys all of its elements. - ~vector() - { - clear(); - } - - //! \brief Returns the number of elements currently contained. - unsigned int size(void) const - { - return size_; - } - - /*! \brief Empties the vector of all elements. - * \note - * This does not deallocate memory but will invoke destructors - * on contained elements. - */ - void clear() - { - while(!empty()) { - pop_back(); - } - } - - /*! \brief Appends an element after the last valid element. - * Calling this on a vector that has reached capacity will throw an - * exception if exceptions are enabled. - */ - void push_back (const T& x) - { - if (size() < N) { - new (&data_[size_]) T(x); - size_++; - } else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Removes the last valid element from the vector. - * Calling this on an empty vector will throw an exception - * if exceptions are enabled. - */ - void pop_back(void) - { - if (size_ != 0) { - --size_; - data_[size_].~T(); - } else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Constructs with a value copied from another. - * - * \param vec the vector to copy. - */ - vector(const vector& vec) : - size_(vec.size_) - { - if (size_ != 0) { - assign(vec.begin(), vec.end()); - } - } - - /*! \brief Constructs with a specified number of initial elements. - * - * \param size number of initial elements. - * - * \param val value of initial elements. - */ - vector(unsigned int size, const T& val = T()) : - size_(0) - { - for (unsigned int i = 0; i < size; i++) { - push_back(val); - } - } - - /*! \brief Overwrites the current content with that copied from another - * instance. - * - * \param rhs vector to copy. - * - * \returns a reference to this. - */ - vector& operator=(const vector& rhs) - { - if (this == &rhs) { - return *this; - } - - if (rhs.size_ != 0) { - assign(rhs.begin(), rhs.end()); - } else { - clear(); - } - - return *this; - } - - /*! \brief Tests equality against another instance. - * - * \param vec the vector against which to compare. - */ - bool operator==(vector &vec) - { - if (size() != vec.size()) { - return false; - } - - for( unsigned int i = 0; i < size(); ++i ) { - if( operator[](i) != vec[i] ) { - return false; - } - } - return true; - } - - //! \brief Conversion operator to T*. - operator T* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const T* () const { return data_; } - - //! \brief Tests whether this instance has any elements. - bool empty (void) const - { - return size_==0; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int max_size (void) const - { - return N; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int capacity () const - { - return N; - } - - /*! \brief Returns a reference to a given element. - * - * \param index which element to access. * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - T& operator[](int index) - { - return data_[index]; - } - - /*! \brief Returns a const reference to a given element. - * - * \param index which element to access. - * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - const T& operator[](int index) const - { - return data_[index]; - } - - /*! \brief Assigns elements of the vector based on a source iterator range. - * - * \param start Beginning iterator of source range - * \param end Enditerator of source range - * - * \note - * Will throw an exception if exceptions are enabled and size exceeded. - */ - template - void assign(I start, I end) - { - clear(); - while(start != end) { - push_back(*start); - start++; - } - } - - /*! \class iterator - * \brief Const iterator class for vectors - */ - class iterator - { - private: - const vector *vec_; - int index_; - - /** - * Internal iterator constructor to capture reference - * to the vector it iterates over rather than taking - * the vector by copy. - */ - iterator (const vector &vec, int index) : - vec_(&vec) - { - if( !vec.empty() ) { - index_ = index; - } else { - index_ = -1; - } - } - - public: - iterator(void) : - index_(-1), - vec_(NULL) - { - } - - iterator(const iterator& rhs) : - vec_(rhs.vec_), - index_(rhs.index_) - { - } - - ~iterator(void) {} - - static iterator begin(const cl::vector &vec) - { - iterator i(vec, 0); - - return i; - } - - static iterator end(const cl::vector &vec) - { - iterator i(vec, vec.size()); - - return i; - } - - bool operator==(iterator i) - { - return ((vec_ == i.vec_) && - (index_ == i.index_)); - } - - bool operator!=(iterator i) - { - return (!(*this==i)); - } - - iterator& operator++() - { - ++index_; - return *this; - } - - iterator operator++(int) - { - iterator retVal(*this); - ++index_; - return retVal; - } - - iterator& operator--() - { - --index_; - return *this; - } - - iterator operator--(int) - { - iterator retVal(*this); - --index_; - return retVal; - } - - const T& operator *() const - { - return (*vec_)[index_]; - } - }; - - iterator begin(void) - { - return iterator::begin(*this); - } - - iterator begin(void) const - { - return iterator::begin(*this); - } - - iterator end(void) - { - return iterator::end(*this); - } - - iterator end(void) const - { - return iterator::end(*this); - } - - T& front(void) - { - return data_[0]; - } - - T& back(void) - { - return data_[size_]; - } - - const T& front(void) const - { - return data_[0]; - } - - const T& back(void) const - { - return data_[size_-1]; - } -}; -#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) - - - - - -namespace detail { -#define __DEFAULT_NOT_INITIALIZED 1 -#define __DEFAULT_BEING_INITIALIZED 2 -#define __DEFAULT_INITIALIZED 4 - - /* - * Compare and exchange primitives are needed for handling of defaults - */ - inline int compare_exchange(volatile int * dest, int exchange, int comparand) - { -#ifdef _WIN32 - return (int)(InterlockedCompareExchange( - (volatile long*)dest, - (long)exchange, - (long)comparand)); -#elif defined(__APPLE__) || defined(__MACOSX) - return OSAtomicOr32Orig((uint32_t)exchange, (volatile uint32_t*)dest); -#else // !_WIN32 || defined(__APPLE__) || defined(__MACOSX) - return (__sync_val_compare_and_swap( - dest, - comparand, - exchange)); -#endif // !_WIN32 - } - - inline void fence() { _mm_mfence(); } -}; // namespace detail - - -/*! \brief class used to interface between C++ and - * OpenCL C calls that require arrays of size_t values, whose - * size is known statically. - */ -template -class size_t -{ -private: - ::size_t data_[N]; - -public: - //! \brief Initialize size_t to all 0s - size_t() - { - for( int i = 0; i < N; ++i ) { - data_[i] = 0; - } - } - - ::size_t& operator[](int index) - { - return data_[index]; - } - - const ::size_t& operator[](int index) const - { - return data_[index]; - } - - //! \brief Conversion operator to T*. - operator ::size_t* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const ::size_t* () const { return data_; } -}; - -namespace detail { - -// Generic getInfoHelper. The final parameter is used to guide overload -// resolution: the actual parameter passed is an int, which makes this -// a worse conversion sequence than a specialization that declares the -// parameter as an int. -template -inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) -{ - return f(name, sizeof(T), param, NULL); -} - -// Specialized getInfoHelper for VECTOR_CLASS params -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - T* value = (T*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - param->assign(&value[0], &value[required/sizeof(T)]); - return CL_SUCCESS; -} - -/* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - typename T::cl_type * value = (typename T::cl_type *) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t elements = required / sizeof(typename T::cl_type); - param->assign(&value[0], &value[elements]); - for (::size_t i = 0; i < elements; i++) - { - if (value[i] != NULL) - { - err = (*param)[i].retain(); - if (err != CL_SUCCESS) { - return err; - } - } - } - return CL_SUCCESS; -} - -// Specialized for getInfo -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) -{ - cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); - - if (err != CL_SUCCESS) { - return err; - } - - return CL_SUCCESS; -} - -// Specialized GetInfoHelper for STRING_CLASS params -template -inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - char* value = (char*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - *param = value; - return CL_SUCCESS; -} - -// Specialized GetInfoHelper for cl::size_t params -template -inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t* value = (::size_t*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - for(int i = 0; i < N; ++i) { - (*param)[i] = value[i]; - } - - return CL_SUCCESS; -} - -template struct ReferenceHandler; - -/* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ -template -inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) -{ - typename T::cl_type value; - cl_int err = f(name, sizeof(value), &value, NULL); - if (err != CL_SUCCESS) { - return err; - } - *param = value; - if (value != NULL) - { - err = param->retain(); - if (err != CL_SUCCESS) { - return err; - } - } - return CL_SUCCESS; -} - -#define __PARAM_NAME_INFO_1_0(F) \ - F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ - F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ - F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ - F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ - F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ - F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ - F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ - F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ - F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ - F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ - F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ - F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ - \ - F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ - F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ - F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ - F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_uint) \ - \ - F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ - \ - F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ - F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ - F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ - F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ - F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ - \ - F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ - F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ - F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ - F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ - F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ - \ - F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ - F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ - F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ - F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ - F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ - \ - F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ - F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ - F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ - F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ - F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ - F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ - \ - F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ - F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ - F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ - F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ - \ - F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ - F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ - F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ - F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) - -#if defined(CL_VERSION_1_1) -#define __PARAM_NAME_INFO_1_1(F) \ - F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ - F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ - \ - F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ - F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ - \ - F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) -#endif // CL_VERSION_1_1 - - -#if defined(CL_VERSION_1_2) -#define __PARAM_NAME_INFO_1_2(F) \ - F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ - \ - F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ - F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ - \ - F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ - \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ - \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ - F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ - F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) -#endif // #if defined(CL_VERSION_1_2) - -#if defined(USE_CL_DEVICE_FISSION) -#define __PARAM_NAME_DEVICE_FISSION(F) \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ - F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) -#endif // USE_CL_DEVICE_FISSION - -template -struct param_traits {}; - -#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ -struct token; \ -template<> \ -struct param_traits \ -{ \ - enum { value = param_name }; \ - typedef T param_type; \ -}; - -__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) -#if defined(CL_VERSION_1_1) -__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 -#if defined(CL_VERSION_1_2) -__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 - -#if defined(USE_CL_DEVICE_FISSION) -__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); -#endif // USE_CL_DEVICE_FISSION - -#ifdef CL_PLATFORM_ICD_SUFFIX_KHR -__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) -#endif - -#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) -#endif - -#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) -#endif -#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) -#endif - -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) -#endif -#ifdef CL_DEVICE_WARP_SIZE_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) -#endif -#ifdef CL_DEVICE_GPU_OVERLAP_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) -#endif -#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) -#endif -#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) -#endif - -// Convenience functions - -template -inline cl_int -getInfo(Func f, cl_uint name, T* param) -{ - return getInfoHelper(f, name, param, 0); -} - -template -struct GetInfoFunctor0 -{ - Func f_; const Arg0& arg0_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { return f_(arg0_, param, size, value, size_ret); } -}; - -template -struct GetInfoFunctor1 -{ - Func f_; const Arg0& arg0_; const Arg1& arg1_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { return f_(arg0_, arg1_, param, size, value, size_ret); } -}; - -template -inline cl_int -getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) -{ - GetInfoFunctor0 f0 = { f, arg0 }; - return getInfoHelper(f0, name, param, 0); -} - -template -inline cl_int -getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) -{ - GetInfoFunctor1 f0 = { f, arg0, arg1 }; - return getInfoHelper(f0, name, param, 0); -} - -template -struct ReferenceHandler -{ }; - -#if defined(CL_VERSION_1_2) -/** - * OpenCL 1.2 devices do have retain/release. - */ -template <> -struct ReferenceHandler -{ - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int retain(cl_device_id device) - { return ::clRetainDevice(device); } - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int release(cl_device_id device) - { return ::clReleaseDevice(device); } -}; -#else // #if defined(CL_VERSION_1_2) -/** - * OpenCL 1.1 devices do not have retain/release. - */ -template <> -struct ReferenceHandler -{ - // cl_device_id does not have retain(). - static cl_int retain(cl_device_id) - { return CL_SUCCESS; } - // cl_device_id does not have release(). - static cl_int release(cl_device_id) - { return CL_SUCCESS; } -}; -#endif // #if defined(CL_VERSION_1_2) - -template <> -struct ReferenceHandler -{ - // cl_platform_id does not have retain(). - static cl_int retain(cl_platform_id) - { return CL_SUCCESS; } - // cl_platform_id does not have release(). - static cl_int release(cl_platform_id) - { return CL_SUCCESS; } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_context context) - { return ::clRetainContext(context); } - static cl_int release(cl_context context) - { return ::clReleaseContext(context); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_command_queue queue) - { return ::clRetainCommandQueue(queue); } - static cl_int release(cl_command_queue queue) - { return ::clReleaseCommandQueue(queue); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_mem memory) - { return ::clRetainMemObject(memory); } - static cl_int release(cl_mem memory) - { return ::clReleaseMemObject(memory); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_sampler sampler) - { return ::clRetainSampler(sampler); } - static cl_int release(cl_sampler sampler) - { return ::clReleaseSampler(sampler); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_program program) - { return ::clRetainProgram(program); } - static cl_int release(cl_program program) - { return ::clReleaseProgram(program); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_kernel kernel) - { return ::clRetainKernel(kernel); } - static cl_int release(cl_kernel kernel) - { return ::clReleaseKernel(kernel); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_event event) - { return ::clRetainEvent(event); } - static cl_int release(cl_event event) - { return ::clReleaseEvent(event); } -}; - - -// Extracts version number with major in the upper 16 bits, minor in the lower 16 -static cl_uint getVersion(const char *versionInfo) -{ - int highVersion = 0; - int lowVersion = 0; - int index = 7; - while(versionInfo[index] != '.' ) { - highVersion *= 10; - highVersion += versionInfo[index]-'0'; - ++index; - } - ++index; - while(versionInfo[index] != ' ' ) { - lowVersion *= 10; - lowVersion += versionInfo[index]-'0'; - ++index; - } - return (highVersion << 16) | lowVersion; -} - -static cl_uint getPlatformVersion(cl_platform_id platform) -{ - ::size_t size = 0; - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); - char *versionInfo = (char *) alloca(size); - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); - return getVersion(versionInfo); -} - -static cl_uint getDevicePlatformVersion(cl_device_id device) -{ - cl_platform_id platform; - clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); - return getPlatformVersion(platform); -} - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -static cl_uint getContextPlatformVersion(cl_context context) -{ - // The platform cannot be queried directly, so we first have to grab a - // device and obtain its context - ::size_t size = 0; - clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); - if (size == 0) - return 0; - cl_device_id *devices = (cl_device_id *) alloca(size); - clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); - return getDevicePlatformVersion(devices[0]); -} -#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - -template -class Wrapper -{ -public: - typedef T cl_type; - -protected: - cl_type object_; - -public: - Wrapper() : object_(NULL) { } - - Wrapper(const cl_type &obj) : object_(obj) { } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - - Wrapper& operator = (const Wrapper& rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - return *this; - } - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - -protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - cl_int retain() const - { - return ReferenceHandler::retain(object_); - } - - cl_int release() const - { - return ReferenceHandler::release(object_); - } -}; - -template <> -class Wrapper -{ -public: - typedef cl_device_id cl_type; - -protected: - cl_type object_; - bool referenceCountable_; - - static bool isReferenceCountable(cl_device_id device) - { - bool retVal = false; - if (device != NULL) { - int version = getDevicePlatformVersion(device); - if(version > ((1 << 16) + 1)) { - retVal = true; - } - } - return retVal; - } - -public: - Wrapper() : object_(NULL), referenceCountable_(false) - { - } - - Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) - { - referenceCountable_ = isReferenceCountable(obj); - } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - referenceCountable_ = isReferenceCountable(object_); - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - - Wrapper& operator = (const Wrapper& rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - referenceCountable_ = rhs.referenceCountable_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - return *this; - } - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - referenceCountable_ = isReferenceCountable(object_); - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - -protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - template - friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); - - cl_int retain() const - { - if( referenceCountable_ ) { - return ReferenceHandler::retain(object_); - } - else { - return CL_SUCCESS; - } - } - - cl_int release() const - { - if( referenceCountable_ ) { - return ReferenceHandler::release(object_); - } - else { - return CL_SUCCESS; - } - } -}; - -} // namespace detail -//! \endcond - -/*! \stuct ImageFormat - * \brief Adds constructors and member functions for cl_image_format. - * - * \see cl_image_format - */ -struct ImageFormat : public cl_image_format -{ - //! \brief Default constructor - performs no initialization. - ImageFormat(){} - - //! \brief Initializing constructor. - ImageFormat(cl_channel_order order, cl_channel_type type) - { - image_channel_order = order; - image_channel_data_type = type; - } - - //! \brief Assignment operator. - ImageFormat& operator = (const ImageFormat& rhs) - { - if (this != &rhs) { - this->image_channel_data_type = rhs.image_channel_data_type; - this->image_channel_order = rhs.image_channel_order; - } - return *this; - } -}; - -/*! \brief Class interface for cl_device_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_device_id - */ -class Device : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Device() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device(const Device& device) : detail::Wrapper(device) { } - - /*! \brief Constructor from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device(const cl_device_id &device) : detail::Wrapper(device) { } - - /*! \brief Returns the first device on the default context. - * - * \see Context::getDefault() - */ - static Device getDefault(cl_int * err = NULL); - - /*! \brief Assignment operator from Device. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device& operator = (const Device& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device& operator = (const cl_device_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetDeviceInfo(). - template - cl_int getInfo(cl_device_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetDeviceInfo, object_, name, param), - __GET_DEVICE_INFO_ERR); - } - - //! \brief Wrapper for clGetDeviceInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_device_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /** - * CL 1.2 version - */ -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clCreateSubDevicesEXT(). - cl_int createSubDevices( - const cl_device_partition_property * properties, - VECTOR_CLASS* devices) - { - cl_uint n = 0; - cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = clCreateSubDevices(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(CL_VERSION_1_2) - -/** - * CL 1.1 version that uses device fission. - */ -#if defined(CL_VERSION_1_1) -#if defined(USE_CL_DEVICE_FISSION) - cl_int createSubDevices( - const cl_device_partition_property_ext * properties, - VECTOR_CLASS* devices) - { - typedef CL_API_ENTRY cl_int - ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( - cl_device_id /*in_device*/, - const cl_device_partition_property_ext * /* properties */, - cl_uint /*num_entries*/, - cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; - __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); - - cl_uint n = 0; - cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(USE_CL_DEVICE_FISSION) -#endif // #if defined(CL_VERSION_1_1) -}; - -/*! \brief Class interface for cl_platform_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_platform_id - */ -class Platform : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Platform() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform(const Platform& platform) : detail::Wrapper(platform) { } - - /*! \brief Constructor from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform(const cl_platform_id &platform) : detail::Wrapper(platform) { } - - /*! \brief Assignment operator from Platform. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform& operator = (const Platform& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform& operator = (const cl_platform_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetPlatformInfo(). - cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetPlatformInfo, object_, name, param), - __GET_PLATFORM_INFO_ERR); - } - - //! \brief Wrapper for clGetPlatformInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_platform_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of devices for this platform. - * - * Wraps clGetDeviceIDs(). - */ - cl_int getDevices( - cl_device_type type, - VECTOR_CLASS* devices) const - { - cl_uint n = 0; - if( devices == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = ::clGetDeviceIDs(object_, type, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - -#if defined(USE_DX_INTEROP) - /*! \brief Get the list of available D3D10 devices. - * - * \param d3d_device_source. - * - * \param d3d_object. - * - * \param d3d_device_set. - * - * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device - * values returned in devices can be used to identify a specific OpenCL - * device. If \a devices argument is NULL, this argument is ignored. - * - * \return One of the following values: - * - CL_SUCCESS if the function is executed successfully. - * - * The application can query specific capabilities of the OpenCL device(s) - * returned by cl::getDevices. This can be used by the application to - * determine which device(s) to use. - * - * \note In the case that exceptions are enabled and a return value - * other than CL_SUCCESS is generated, then cl::Error exception is - * generated. - */ - cl_int getDevices( - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - VECTOR_CLASS* devices) const - { - typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( - cl_platform_id platform, - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint* num_devices); - - if( devices == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - - static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; - __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); - - cl_uint n = 0; - cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - 0, - NULL, - &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - n, - ids, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif - - /*! \brief Gets a list of available platforms. - * - * Wraps clGetPlatformIDs(). - */ - static cl_int get( - VECTOR_CLASS* platforms) - { - cl_uint n = 0; - - if( platforms == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - platforms->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static cl_int get( - Platform * platform) - { - cl_uint n = 0; - - if( platform == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - *platform = ids[0]; - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform, returning it by value. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static Platform get( - cl_int * errResult = NULL) - { - Platform platform; - cl_uint n = 0; - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - if (errResult != NULL) { - *errResult = err; - } - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - if (errResult != NULL) { - *errResult = err; - } - - return ids[0]; - } - - static Platform getDefault( - cl_int *errResult = NULL ) - { - return get(errResult); - } - - -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clUnloadCompiler(). - cl_int - unloadCompiler() - { - return ::clUnloadPlatformCompiler(object_); - } -#endif // #if defined(CL_VERSION_1_2) -}; // class Platform - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -/** - * Unload the OpenCL compiler. - * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. - */ -inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int -UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -inline cl_int -UnloadCompiler() -{ - return ::clUnloadCompiler(); -} -#endif // #if defined(CL_VERSION_1_1) - -/*! \brief Class interface for cl_context. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_context as the original. For details, see - * clRetainContext() and clReleaseContext(). - * - * \see cl_context - */ -class Context - : public detail::Wrapper -{ -private: - static volatile int default_initialized_; - static Context default_; - static volatile cl_int default_error_; -public: - /*! \brief Destructor. - * - * This calls clReleaseContext() on the value held by this instance. - */ - ~Context() { } - - /*! \brief Constructs a context including a list of specified devices. - * - * Wraps clCreateContext(). - */ - Context( - const VECTOR_CLASS& devices, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateContext( - properties, (cl_uint) numDevices, - deviceIDs, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - Context( - const Device& device, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - cl_device_id deviceID = device(); - - object_ = ::clCreateContext( - properties, 1, - &deviceID, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a context including all devices of a specified type. - * - * Wraps clCreateContextFromType(). - */ - Context( - cl_device_type type, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - -#if !defined(__APPLE__) || !defined(__MACOS) - cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0 }; - if (properties == NULL) { - prop[1] = (cl_context_properties)Platform::get(&error)(); - if (error != CL_SUCCESS) { - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - return; - } - } - - properties = &prop[0]; - } -#endif - object_ = ::clCreateContextFromType( - properties, type, notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. - * - * \note All calls to this function return the same cl_context as the first. - */ - static Context getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while(default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - default_ = Context( - CL_DEVICE_TYPE_DEFAULT, - NULL, - NULL, - NULL, - &error); - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - //! \brief Default constructor - initializes to NULL. - Context() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This calls clRetainContext() on the parameter's cl_context. - */ - Context(const Context& context) : detail::Wrapper(context) { } - - /*! \brief Constructor from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_context - * into the new Context object. - */ - __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) { } - - /*! \brief Assignment operator from Context. - * - * This calls clRetainContext() on the parameter and clReleaseContext() on - * the previous value held by this instance. - */ - Context& operator = (const Context& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseContext() on the value previously held by this instance. - */ - Context& operator = (const cl_context& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetContextInfo(). - template - cl_int getInfo(cl_context_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetContextInfo, object_, name, param), - __GET_CONTEXT_INFO_ERR); - } - - //! \brief Wrapper for clGetContextInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_context_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of supported image formats. - * - * Wraps clGetSupportedImageFormats(). - */ - cl_int getSupportedImageFormats( - cl_mem_flags flags, - cl_mem_object_type type, - VECTOR_CLASS* formats) const - { - cl_uint numEntries; - cl_int err = ::clGetSupportedImageFormats( - object_, - flags, - type, - 0, - NULL, - &numEntries); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - ImageFormat* value = (ImageFormat*) - alloca(numEntries * sizeof(ImageFormat)); - err = ::clGetSupportedImageFormats( - object_, - flags, - type, - numEntries, - (cl_image_format*) value, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - formats->assign(&value[0], &value[numEntries]); - return CL_SUCCESS; - } -}; - -inline Device Device::getDefault(cl_int * err) -{ - cl_int error; - Device device; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - device = context.getInfo()[0]; - if (err != NULL) { - *err = CL_SUCCESS; - } - } - - return device; -} - - -#ifdef _WIN32 -__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -__declspec(selectany) Context Context::default_; -__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; -#else -__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -__attribute__((weak)) Context Context::default_; -__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; -#endif - -/*! \brief Class interface for cl_event. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_event as the original. For details, see - * clRetainEvent() and clReleaseEvent(). - * - * \see cl_event - */ -class Event : public detail::Wrapper -{ -public: - /*! \brief Destructor. - * - * This calls clReleaseEvent() on the value held by this instance. - */ - ~Event() { } - - //! \brief Default constructor - initializes to NULL. - Event() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This calls clRetainEvent() on the parameter's cl_event. - */ - Event(const Event& event) : detail::Wrapper(event) { } - - /*! \brief Constructor from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_event - * into the new Event object. - */ - Event(const cl_event& event) : detail::Wrapper(event) { } - - /*! \brief Assignment operator from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseEvent() on the value previously held by this instance. - */ - Event& operator = (const Event& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_event. - * - * This calls clRetainEvent() on the parameter and clReleaseEvent() on - * the previous value held by this instance. - */ - Event& operator = (const cl_event& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetEventInfo(). - template - cl_int getInfo(cl_event_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetEventInfo, object_, name, param), - __GET_EVENT_INFO_ERR); - } - - //! \brief Wrapper for clGetEventInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_event_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - //! \brief Wrapper for clGetEventProfilingInfo(). - template - cl_int getProfilingInfo(cl_profiling_info name, T* param) const - { - return detail::errHandler(detail::getInfo( - &::clGetEventProfilingInfo, object_, name, param), - __GET_EVENT_PROFILE_INFO_ERR); - } - - //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. - template typename - detail::param_traits::param_type - getProfilingInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_profiling_info, name>::param_type param; - cl_int result = getProfilingInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Blocks the calling thread until this event completes. - * - * Wraps clWaitForEvents(). - */ - cl_int wait() const - { - return detail::errHandler( - ::clWaitForEvents(1, &object_), - __WAIT_FOR_EVENTS_ERR); - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a user callback function for a specific command execution status. - * - * Wraps clSetEventCallback(). - */ - cl_int setCallback( - cl_int type, - void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetEventCallback( - object_, - type, - pfn_notify, - user_data), - __SET_EVENT_CALLBACK_ERR); - } -#endif - - /*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ - static cl_int - waitForEvents(const VECTOR_CLASS& events) - { - return detail::errHandler( - ::clWaitForEvents( - (cl_uint) events.size(), (cl_event*)&events.front()), - __WAIT_FOR_EVENTS_ERR); - } -}; - -#if defined(CL_VERSION_1_1) -/*! \brief Class interface for user events (a subset of cl_event's). - * - * See Event for details about copy semantics, etc. - */ -class UserEvent : public Event -{ -public: - /*! \brief Constructs a user event on a given context. - * - * Wraps clCreateUserEvent(). - */ - UserEvent( - const Context& context, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateUserEvent( - context(), - &error); - - detail::errHandler(error, __CREATE_USER_EVENT_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - UserEvent() : Event() { } - - //! \brief Copy constructor - performs shallow copy. - UserEvent(const UserEvent& event) : Event(event) { } - - //! \brief Assignment Operator - performs shallow copy. - UserEvent& operator = (const UserEvent& rhs) - { - if (this != &rhs) { - Event::operator=(rhs); - } - return *this; - } - - /*! \brief Sets the execution status of a user event object. - * - * Wraps clSetUserEventStatus(). - */ - cl_int setStatus(cl_int status) - { - return detail::errHandler( - ::clSetUserEventStatus(object_,status), - __SET_USER_EVENT_STATUS_ERR); - } -}; -#endif - -/*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ -inline static cl_int -WaitForEvents(const VECTOR_CLASS& events) -{ - return detail::errHandler( - ::clWaitForEvents( - (cl_uint) events.size(), (cl_event*)&events.front()), - __WAIT_FOR_EVENTS_ERR); -} - -/*! \brief Class interface for cl_mem. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_mem as the original. For details, see - * clRetainMemObject() and clReleaseMemObject(). - * - * \see cl_mem - */ -class Memory : public detail::Wrapper -{ -public: - - /*! \brief Destructor. - * - * This calls clReleaseMemObject() on the value held by this instance. - */ - ~Memory() {} - - //! \brief Default constructor - initializes to NULL. - Memory() : detail::Wrapper() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainMemObject() on the parameter's cl_mem. - */ - Memory(const Memory& memory) : detail::Wrapper(memory) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_mem - * into the new Memory object. - */ - __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) { } - - /*! \brief Assignment operator from Memory. - * - * This calls clRetainMemObject() on the parameter and clReleaseMemObject() - * on the previous value held by this instance. - */ - Memory& operator = (const Memory& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseMemObject() on the value previously held by this instance. - */ - Memory& operator = (const cl_mem& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetMemObjectInfo(). - template - cl_int getInfo(cl_mem_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetMemObjectInfo, object_, name, param), - __GET_MEM_OBJECT_INFO_ERR); - } - - //! \brief Wrapper for clGetMemObjectInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_mem_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a callback function to be called when the memory object - * is no longer needed. - * - * Wraps clSetMemObjectDestructorCallback(). - * - * Repeated calls to this function, for a given cl_mem value, will append - * to the list of functions called (in reverse order) when memory object's - * resources are freed and the memory object is deleted. - * - * \note - * The registered callbacks are associated with the underlying cl_mem - * value - not the Memory class instance. - */ - cl_int setDestructorCallback( - void (CL_CALLBACK * pfn_notify)(cl_mem, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetMemObjectDestructorCallback( - object_, - pfn_notify, - user_data), - __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); - } -#endif - -}; - -// Pre-declare copy functions -class Buffer; -template< typename IteratorType > -cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); -template< typename IteratorType > -cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); - -/*! \brief Class interface for Buffer Memory Objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Buffer : public Memory -{ -public: - - /*! \brief Constructs a Buffer in a specified context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - */ - Buffer( - const Context& context, - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a Buffer in the default context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - * - * \see Context::getDefault() - */ - Buffer( - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(err); - - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! - * \brief Construct a Buffer from a host container via iterators. - * If useHostPtr is specified iterators must be random access. - */ - template< typename IteratorType > - Buffer( - IteratorType startIterator, - IteratorType endIterator, - bool readOnly, - bool useHostPtr = false, - cl_int* err = NULL) - { - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - cl_mem_flags flags = 0; - if( readOnly ) { - flags |= CL_MEM_READ_ONLY; - } - else { - flags |= CL_MEM_READ_WRITE; - } - if( useHostPtr ) { - flags |= CL_MEM_USE_HOST_PTR; - } - - ::size_t size = sizeof(DataType)*(endIterator - startIterator); - - Context context = Context::getDefault(err); - - if( useHostPtr ) { - object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); - } else { - object_ = ::clCreateBuffer(context(), flags, size, 0, &error); - } - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - if( !useHostPtr ) { - error = cl::copy(startIterator, endIterator, *this); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - } - - //! \brief Default constructor - initializes to NULL. - Buffer() : Memory() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Buffer(const Buffer& buffer) : Memory(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) { } - - /*! \brief Assignment from Buffer - performs shallow copy. - * - * See Memory for further details. - */ - Buffer& operator = (const Buffer& rhs) - { - if (this != &rhs) { - Memory::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Buffer& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - -#if defined(CL_VERSION_1_1) - /*! \brief Creates a new buffer object from this. - * - * Wraps clCreateSubBuffer(). - */ - Buffer createSubBuffer( - cl_mem_flags flags, - cl_buffer_create_type buffer_create_type, - const void * buffer_create_info, - cl_int * err = NULL) - { - Buffer result; - cl_int error; - result.object_ = ::clCreateSubBuffer( - object_, - flags, - buffer_create_type, - buffer_create_info, - &error); - - detail::errHandler(error, __CREATE_SUBBUFFER_ERR); - if (err != NULL) { - *err = error; - } - - return result; - } -#endif -}; - -#if defined (USE_DX_INTEROP) -/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. - * - * This is provided to facilitate interoperability with Direct3D. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class BufferD3D10 : public Buffer -{ -public: - typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( - cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, - cl_int* errcode_ret); - - /*! \brief Constructs a BufferD3D10, in a specified context, from a - * given ID3D10Buffer. - * - * Wraps clCreateFromD3D10BufferKHR(). - */ - BufferD3D10( - const Context& context, - cl_mem_flags flags, - ID3D10Buffer* bufobj, - cl_int * err = NULL) - { - static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; - -#if defined(CL_VERSION_1_2) - vector props = context.getInfo(); - cl_platform platform = -1; - for( int i = 0; i < props.size(); ++i ) { - if( props[i] == CL_CONTEXT_PLATFORM ) { - platform = props[i+1]; - } - } - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); -#endif - - cl_int error; - object_ = pfn_clCreateFromD3D10BufferKHR( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferD3D10() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10(const BufferD3D10& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferD3D10 - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10& operator = (const BufferD3D10& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } -}; -#endif - -/*! \brief Class interface for GL Buffer Memory Objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class BufferGL : public Buffer -{ -public: - /*! \brief Constructs a BufferGL in a specified context, from a given - * GL buffer. - * - * Wraps clCreateFromGLBuffer(). - */ - BufferGL( - const Context& context, - cl_mem_flags flags, - GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLBuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferGL() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL(const BufferGL& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferGL - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL& operator = (const BufferGL& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_,type,gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } -}; - -/*! \brief Class interface for GL Render Buffer Memory Objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class BufferRenderGL : public Buffer -{ -public: - /*! \brief Constructs a BufferRenderGL in a specified context, from a given - * GL Renderbuffer. - * - * Wraps clCreateFromGLRenderbuffer(). - */ - BufferRenderGL( - const Context& context, - cl_mem_flags flags, - GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLRenderbuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferRenderGL() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL(const BufferGL& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferGL - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL& operator = (const BufferRenderGL& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_,type,gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } -}; - -/*! \brief C++ base class for Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image : public Memory -{ -protected: - //! \brief Default constructor - initializes to NULL. - Image() : Memory() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image(const Image& image) : Memory(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) { } - - /*! \brief Assignment from Image - performs shallow copy. - * - * See Memory for further details. - */ - Image& operator = (const Image& rhs) - { - if (this != &rhs) { - Memory::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - -public: - //! \brief Wrapper for clGetImageInfo(). - template - cl_int getImageInfo(cl_image_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetImageInfo, object_, name, param), - __GET_IMAGE_INFO_ERR); - } - - //! \brief Wrapper for clGetImageInfo() that returns by value. - template typename - detail::param_traits::param_type - getImageInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_image_info, name>::param_type param; - cl_int result = getImageInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -}; - -#if defined(CL_VERSION_1_2) -/*! \brief Class interface for 1D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image1D : public Image -{ -public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image1D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D; - desc.image_width = width; - desc.image_row_pitch = 0; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image1D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image1D(const Image1D& image1D) : Image(image1D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) { } - - /*! \brief Assignment from Image1D - performs shallow copy. - * - * See Memory for further details. - */ - Image1D& operator = (const Image1D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image1D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; - -/*! \class Image1DBuffer - * \brief Image interface for 1D buffer images. - */ -class Image1DBuffer : public Image -{ -public: - Image1DBuffer( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - const Buffer &buffer, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER; - desc.image_width = width; - desc.image_row_pitch = 0; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = buffer(); - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - NULL, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DBuffer() { } - - Image1DBuffer(const Image1DBuffer& image1D) : Image(image1D) { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) { } - - Image1DBuffer& operator = (const Image1DBuffer& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image1DBuffer& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; - -/*! \class Image1DArray - * \brief Image interface for arrays of 1D images. - */ -class Image1DArray : public Image -{ -public: - Image1DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t rowPitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY; - desc.image_array_size = arraySize; - desc.image_width = width; - desc.image_row_pitch = rowPitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DArray() { } - - Image1DArray(const Image1DArray& imageArray) : Image(imageArray) { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image1DArray& operator = (const Image1DArray& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image1DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; -#endif // #if defined(CL_VERSION_1_2) - - -/*! \brief Class interface for 2D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image2D : public Image -{ -public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image2D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t row_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE2D; - desc.image_width = width; - desc.image_height = height; - desc.image_row_pitch = row_pitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage2D( - context(), flags,&format, width, height, row_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE2D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image2D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image2D(const Image2D& image2D) : Image(image2D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) { } - - /*! \brief Assignment from Image2D - performs shallow copy. - * - * See Memory for further details. - */ - Image2D& operator = (const Image2D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; - - -#if !defined(CL_VERSION_1_2) -/*! \brief Class interface for GL 2D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. - */ -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D -{ -public: - /*! \brief Constructs an Image2DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture2D(). - */ - Image2DGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture2D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); - if (err != NULL) { - *err = error; - } - - } - - //! \brief Default constructor - initializes to NULL. - Image2DGL() : Image2D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL(const Image2DGL& image) : Image2D(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) { } - - /*! \brief Assignment from Image2DGL - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL& operator = (const Image2DGL& rhs) - { - if (this != &rhs) { - Image2D::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL& operator = (const cl_mem& rhs) - { - Image2D::operator=(rhs); - return *this; - } -}; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) -/*! \class Image2DArray - * \brief Image interface for arrays of 2D images. - */ -class Image2DArray : public Image -{ -public: - Image2DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t height, - ::size_t rowPitch, - ::size_t slicePitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; - desc.image_array_size = arraySize; - desc.image_width = width; - desc.image_height = height; - desc.image_row_pitch = rowPitch; - desc.image_slice_pitch = slicePitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image2DArray() { } - - Image2DArray(const Image2DArray& imageArray) : Image(imageArray) { } - - __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image2DArray& operator = (const Image2DArray& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image2DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; -#endif // #if defined(CL_VERSION_1_2) - -/*! \brief Class interface for 3D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image3D : public Image -{ -public: - /*! \brief Constructs a 3D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image3D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t depth, - ::size_t row_pitch = 0, - ::size_t slice_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE3D; - desc.image_width = width; - desc.image_height = height; - desc.image_depth = depth; - desc.image_row_pitch = row_pitch; - desc.image_slice_pitch = slice_pitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage3D( - context(), flags, &format, width, height, depth, row_pitch, - slice_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE3D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image3D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image3D(const Image3D& image3D) : Image(image3D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) { } - - /*! \brief Assignment from Image3D - performs shallow copy. - * - * See Memory for further details. - */ - Image3D& operator = (const Image3D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; - -#if !defined(CL_VERSION_1_2) -/*! \brief Class interface for GL 3D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image3DGL : public Image3D -{ -public: - /*! \brief Constructs an Image3DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture3D(). - */ - Image3DGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture3D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image3DGL() : Image3D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL(const Image3DGL& image) : Image3D(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) { } - - /*! \brief Assignment from Image3DGL - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL& operator = (const Image3DGL& rhs) - { - if (this != &rhs) { - Image3D::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL& operator = (const cl_mem& rhs) - { - Image3D::operator=(rhs); - return *this; - } -}; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) -/*! \class ImageGL - * \brief general image interface for GL interop. - * We abstract the 2D and 3D GL images into a single instance here - * that wraps all GL sourced images on the grounds that setup information - * was performed by OpenCL anyway. - */ -class ImageGL : public Image -{ -public: - ImageGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); - if (err != NULL) { - *err = error; - } - } - - ImageGL() : Image() { } - - ImageGL(const ImageGL& image) : Image(image) { } - - __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) { } - - ImageGL& operator = (const ImageGL& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - ImageGL& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } -}; -#endif // #if defined(CL_VERSION_1_2) - -/*! \brief Class interface for cl_sampler. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_sampler as the original. For details, see - * clRetainSampler() and clReleaseSampler(). - * - * \see cl_sampler - */ -class Sampler : public detail::Wrapper -{ -public: - /*! \brief Destructor. - * - * This calls clReleaseSampler() on the value held by this instance. - */ - ~Sampler() { } - - //! \brief Default constructor - initializes to NULL. - Sampler() { } - - /*! \brief Constructs a Sampler in a specified context. - * - * Wraps clCreateSampler(). - */ - Sampler( - const Context& context, - cl_bool normalized_coords, - cl_addressing_mode addressing_mode, - cl_filter_mode filter_mode, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateSampler( - context(), - normalized_coords, - addressing_mode, - filter_mode, - &error); - - detail::errHandler(error, __CREATE_SAMPLER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainSampler() on the parameter's cl_sampler. - */ - Sampler(const Sampler& sampler) : detail::Wrapper(sampler) { } - - /*! \brief Constructor from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_sampler - * into the new Sampler object. - */ - Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) { } - - /*! \brief Assignment operator from Sampler. - * - * This calls clRetainSampler() on the parameter and clReleaseSampler() - * on the previous value held by this instance. - */ - Sampler& operator = (const Sampler& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseSampler() on the value previously held by this instance. - */ - Sampler& operator = (const cl_sampler& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetSamplerInfo(). - template - cl_int getInfo(cl_sampler_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetSamplerInfo, object_, name, param), - __GET_SAMPLER_INFO_ERR); - } - - //! \brief Wrapper for clGetSamplerInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_sampler_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -}; - -class Program; -class CommandQueue; -class Kernel; - -//! \brief Class interface for specifying NDRange values. -class NDRange -{ -private: - size_t<3> sizes_; - cl_uint dimensions_; - -public: - //! \brief Default constructor - resulting range has zero dimensions. - NDRange() - : dimensions_(0) - { } - - //! \brief Constructs one-dimensional range. - NDRange(::size_t size0) - : dimensions_(1) - { - sizes_[0] = size0; - } - - //! \brief Constructs two-dimensional range. - NDRange(::size_t size0, ::size_t size1) - : dimensions_(2) - { - sizes_[0] = size0; - sizes_[1] = size1; - } - - //! \brief Constructs three-dimensional range. - NDRange(::size_t size0, ::size_t size1, ::size_t size2) - : dimensions_(3) - { - sizes_[0] = size0; - sizes_[1] = size1; - sizes_[2] = size2; - } - - /*! \brief Conversion operator to const ::size_t *. - * - * \returns a pointer to the size of the first dimension. - */ - operator const ::size_t*() const { - return (const ::size_t*) sizes_; - } - - //! \brief Queries the number of dimensions in the range. - ::size_t dimensions() const { return dimensions_; } -}; - -//! \brief A zero-dimensional range. -static const NDRange NullRange; - -//! \brief Local address wrapper for use with Kernel::setArg -struct LocalSpaceArg -{ - ::size_t size_; -}; - -namespace detail { - -template -struct KernelArgumentHandler -{ - static ::size_t size(const T&) { return sizeof(T); } - static T* ptr(T& value) { return &value; } -}; - -template <> -struct KernelArgumentHandler -{ - static ::size_t size(const LocalSpaceArg& value) { return value.size_; } - static void* ptr(LocalSpaceArg&) { return NULL; } -}; - -} -//! \endcond - -/*! __local - * \brief Helper function for generating LocalSpaceArg objects. - * Deprecated. Replaced with Local. - */ -inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg -__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -inline LocalSpaceArg -__local(::size_t size) -{ - LocalSpaceArg ret = { size }; - return ret; -} - -/*! Local - * \brief Helper function for generating LocalSpaceArg objects. - */ -inline LocalSpaceArg -Local(::size_t size) -{ - LocalSpaceArg ret = { size }; - return ret; -} - -//class KernelFunctor; - -/*! \brief Class interface for cl_kernel. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_kernel as the original. For details, see - * clRetainKernel() and clReleaseKernel(). - * - * \see cl_kernel - */ -class Kernel : public detail::Wrapper -{ -public: - inline Kernel(const Program& program, const char* name, cl_int* err = NULL); - - /*! \brief Destructor. - * - * This calls clReleaseKernel() on the value held by this instance. - */ - ~Kernel() { } - - //! \brief Default constructor - initializes to NULL. - Kernel() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainKernel() on the parameter's cl_kernel. - */ - Kernel(const Kernel& kernel) : detail::Wrapper(kernel) { } - - /*! \brief Constructor from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_kernel - * into the new Kernel object. - */ - __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) { } - - /*! \brief Assignment operator from Kernel. - * - * This calls clRetainKernel() on the parameter and clReleaseKernel() - * on the previous value held by this instance. - */ - Kernel& operator = (const Kernel& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseKernel() on the value previously held by this instance. - */ - Kernel& operator = (const cl_kernel& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - template - cl_int getInfo(cl_kernel_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelInfo, object_, name, param), - __GET_KERNEL_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_2) - template - cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), - __GET_KERNEL_ARG_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getArgInfo(cl_uint argIndex, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_arg_info, name>::param_type param; - cl_int result = getArgInfo(argIndex, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -#endif // #if defined(CL_VERSION_1_2) - - template - cl_int getWorkGroupInfo( - const Device& device, cl_kernel_work_group_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetKernelWorkGroupInfo, object_, device(), name, param), - __GET_KERNEL_WORK_GROUP_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getWorkGroupInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_work_group_info, name>::param_type param; - cl_int result = getWorkGroupInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int setArg(cl_uint index, T value) - { - return detail::errHandler( - ::clSetKernelArg( - object_, - index, - detail::KernelArgumentHandler::size(value), - detail::KernelArgumentHandler::ptr(value)), - __SET_KERNEL_ARGS_ERR); - } - - cl_int setArg(cl_uint index, ::size_t size, void* argPtr) - { - return detail::errHandler( - ::clSetKernelArg(object_, index, size, argPtr), - __SET_KERNEL_ARGS_ERR); - } -}; - -/*! \class Program - * \brief Program interface that implements cl_program. - */ -class Program : public detail::Wrapper -{ -public: - typedef VECTOR_CLASS > Binaries; - typedef VECTOR_CLASS > Sources; - - Program( - const STRING_CLASS& source, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - Context context = Context::getDefault(err); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const STRING_CLASS& source, - bool build, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - Context context = Context::getDefault(err); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const STRING_CLASS& source, - bool build = false, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const Sources& sources, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t n = (::size_t)sources.size(); - ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); - const char** strings = (const char**) alloca(n * sizeof(const char*)); - - for (::size_t i = 0; i < n; ++i) { - strings[i] = sources[(int)i].first; - lengths[i] = sources[(int)i].second; - } - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)n, strings, lengths, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - if (err != NULL) { - *err = error; - } - } - - /** - * Construct a program object from a list of devices and a per-device list of binaries. - * \param context A valid OpenCL context in which to construct the program. - * \param devices A vector of OpenCL device objects for which the program will be created. - * \param binaries A vector of pairs of a pointer to a binary object and its length. - * \param binaryStatus An optional vector that on completion will be resized to - * match the size of binaries and filled with values to specify if each binary - * was successfully loaded. - * Set to CL_SUCCESS if the binary was successfully loaded. - * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. - * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. - * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: - * CL_INVALID_CONTEXT if context is not a valid context. - * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; - * or if any entry in binaries is NULL or has length 0. - * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. - * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. - * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const Binaries& binaries, - VECTOR_CLASS* binaryStatus = NULL, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t numDevices = devices.size(); - - // Catch size mismatch early and return - if(binaries.size() != numDevices) { - error = CL_INVALID_VALUE; - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - return; - } - - ::size_t* lengths = (::size_t*) alloca(numDevices * sizeof(::size_t)); - const unsigned char** images = (const unsigned char**) alloca(numDevices * sizeof(const unsigned char**)); - - for (::size_t i = 0; i < numDevices; ++i) { - images[i] = (const unsigned char*)binaries[i].first; - lengths[i] = binaries[(int)i].second; - } - - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - if(binaryStatus) { - binaryStatus->resize(numDevices); - } - - object_ = ::clCreateProgramWithBinary( - context(), (cl_uint) devices.size(), - deviceIDs, - lengths, images, binaryStatus != NULL - ? &binaryStatus->front() - : NULL, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - } - - -#if defined(CL_VERSION_1_2) - /** - * Create program using builtin kernels. - * \param kernelNames Semi-colon separated list of builtin kernel names - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const STRING_CLASS& kernelNames, - cl_int* err = NULL) - { - cl_int error; - - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateProgramWithBuiltInKernels( - context(), - (cl_uint) devices.size(), - deviceIDs, - kernelNames.c_str(), - &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) - - Program() { } - - Program(const Program& program) : detail::Wrapper(program) { } - - __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) { } - - Program& operator = (const Program& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - Program& operator = (const cl_program& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - cl_int build( - const VECTOR_CLASS& devices, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - return detail::errHandler( - ::clBuildProgram( - object_, - (cl_uint) - devices.size(), - deviceIDs, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - - cl_int build( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clBuildProgram( - object_, - 0, - NULL, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - -#if defined(CL_VERSION_1_2) - cl_int compile( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clCompileProgram( - object_, - 0, - NULL, - options, - 0, - NULL, - NULL, - notifyFptr, - data), - __COMPILE_PROGRAM_ERR); - } -#endif - - template - cl_int getInfo(cl_program_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetProgramInfo, object_, name, param), - __GET_PROGRAM_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int getBuildInfo( - const Device& device, cl_program_build_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetProgramBuildInfo, object_, device(), name, param), - __GET_PROGRAM_BUILD_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getBuildInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_build_info, name>::param_type param; - cl_int result = getBuildInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int createKernels(VECTOR_CLASS* kernels) - { - cl_uint numKernels; - cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); - err = ::clCreateKernelsInProgram( - object_, numKernels, (cl_kernel*) value, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - kernels->assign(&value[0], &value[numKernels]); - return CL_SUCCESS; - } -}; - -#if defined(CL_VERSION_1_2) -inline Program linkProgram( - Program input1, - Program input2, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) -{ - cl_int err_local = CL_SUCCESS; - - cl_program programs[2] = { input1(), input2() }; - - Context ctx = input1.getInfo(); - - cl_program prog = ::clLinkProgram( - ctx(), - 0, - NULL, - options, - 2, - programs, - notifyFptr, - data, - &err_local); - - detail::errHandler(err_local,__COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = err_local; - } - - return Program(prog); -} - -inline Program linkProgram( - VECTOR_CLASS inputPrograms, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) -{ - cl_int err_local = CL_SUCCESS; - - cl_program * programs = (cl_program*) alloca(inputPrograms.size() * sizeof(cl_program)); - - if (programs != NULL) { - for (unsigned int i = 0; i < inputPrograms.size(); i++) { - programs[i] = inputPrograms[i](); - } - } - - cl_program prog = ::clLinkProgram( - Context::getDefault()(), - 0, - NULL, - options, - (cl_uint)inputPrograms.size(), - programs, - notifyFptr, - data, - &err_local); - - detail::errHandler(err_local,__COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = err_local; - } - - return Program(prog); -} -#endif - -template<> -inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const -{ - VECTOR_CLASS< ::size_t> sizes = getInfo(); - VECTOR_CLASS binaries; - for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) - { - char *ptr = NULL; - if (*s != 0) - ptr = new char[*s]; - binaries.push_back(ptr); - } - - cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); - if (err != NULL) { - *err = result; - } - return binaries; -} - -inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) -{ - cl_int error; - - object_ = ::clCreateKernel(program(), name, &error); - detail::errHandler(error, __CREATE_KERNEL_ERR); - - if (err != NULL) { - *err = error; - } - -} - -/*! \class CommandQueue - * \brief CommandQueue interface for cl_command_queue. - */ -class CommandQueue : public detail::Wrapper -{ -private: - static volatile int default_initialized_; - static CommandQueue default_; - static volatile cl_int default_error_; -public: - CommandQueue( - cl_command_queue_properties properties, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - } - - CommandQueue( - const Context& context, - const Device& device, - cl_command_queue_properties properties = 0, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - static CommandQueue getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while(default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - default_ = CommandQueue(context, device, 0, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - CommandQueue() { } - - CommandQueue(const CommandQueue& commandQueue) : detail::Wrapper(commandQueue) { } - - CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) { } - - CommandQueue& operator = (const CommandQueue& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - CommandQueue& operator = (const cl_command_queue& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - template - cl_int getInfo(cl_command_queue_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetCommandQueueInfo, object_, name, param), - __GET_COMMAND_QUEUE_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_command_queue_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBuffer( - object_, src(), dst(), src_offset, dst_offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferRect( - object_, - src(), - dst(), - (const ::size_t *)src_origin, - (const ::size_t *)dst_origin, - (const ::size_t *)region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill a buffer object with a pattern - * of a given size. The pattern is specified a as vector. - * \tparam PatternType The datatype of the pattern field. - * The pattern type must be an accepted OpenCL data type. - */ - template - cl_int enqueueFillBuffer( - const Buffer& buffer, - PatternType pattern, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillBuffer( - object_, - buffer(), - static_cast(&pattern), - sizeof(PatternType), - offset, - size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImage( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *)dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA floating-point color value if - * the image channel data type is not an unnormalized signed or - * unsigned data type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_float4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA signed integer color value if - * the image channel data type is an unnormalized signed integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_int4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA unsigned integer color value if - * the image channel data type is an unnormalized unsigned integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_uint4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImageToBuffer( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *) region, dst_offset, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferToImage( - object_, src(), dst(), src_offset, - (const ::size_t *) dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_int error; - void * result = ::clEnqueueMapBuffer( - object_, buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (cl_event*) event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - return result; - } - - void* enqueueMapImage( - const Image& buffer, - cl_bool blocking, - cl_map_flags flags, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t * row_pitch, - ::size_t * slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_int error; - void * result = ::clEnqueueMapImage( - object_, buffer(), blocking, flags, - (const ::size_t *) origin, (const ::size_t *) region, - row_pitch, slice_pitch, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (cl_event*) event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - return result; - } - - cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - object_, memory(), mapped_ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueues a marker command which waits for either a list of events to complete, - * or all previously enqueued commands to complete. - * - * Enqueues a marker command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command returns an event which can be waited on, - * i.e. this event can be waited on to insure that all events either in the event_wait_list - * or all previously enqueued commands, queued before this command to command_queue, - * have completed. - */ - cl_int enqueueMarkerWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueMarkerWithWaitList( - object_, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_MARKER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * A synchronization point that enqueues a barrier operation. - * - * Enqueues a barrier command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command blocks command execution, that is, any - * following commands enqueued after it do not execute until it completes. This command - * returns an event which can be waited on, i.e. this event can be waited on to insure that - * all events either in the event_wait_list or all previously enqueued commands, queued - * before this command to command_queue, have completed. - */ - cl_int enqueueBarrierWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueBarrierWithWaitList( - object_, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_BARRIER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueues a command to indicate with which device a set of memory objects - * should be associated. - */ - cl_int enqueueMigrateMemObjects( - const VECTOR_CLASS &memObjects, - cl_mem_migration_flags flags, - const VECTOR_CLASS* events = NULL, - Event* event = NULL - ) - { - cl_event tmp; - - cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); - for( int i = 0; i < (int)memObjects.size(); ++i ) { - localMemObjects[i] = memObjects[i](); - } - - - cl_int err = detail::errHandler( - ::clEnqueueMigrateMemObjects( - object_, - (cl_uint)memObjects.size(), - static_cast(localMemObjects), - flags, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueNDRangeKernel( - const Kernel& kernel, - const NDRange& offset, - const NDRange& global, - const NDRange& local = NullRange, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNDRangeKernel( - object_, kernel(), (cl_uint) global.dimensions(), - offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, - (const ::size_t*) global, - local.dimensions() != 0 ? (const ::size_t*) local : NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NDRANGE_KERNEL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueTask( - const Kernel& kernel, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueTask( - object_, kernel(), - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_TASK_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueNativeKernel( - void (CL_CALLBACK *userFptr)(void *), - std::pair args, - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* mem_locs = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) - ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) - : NULL; - - if (mems != NULL) { - for (unsigned int i = 0; i < mem_objects->size(); i++) { - mems[i] = ((*mem_objects)[i])(); - } - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNativeKernel( - object_, userFptr, args.first, args.second, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - mems, - (mem_locs != NULL) ? (const void **) &mem_locs->front() : NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NATIVE_KERNEL); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueMarker(object_, (cl_event*) event), - __ENQUEUE_MARKER_ERR); - } - - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueWaitForEvents( - object_, - (cl_uint) events.size(), - (const cl_event*) &events.front()), - __ENQUEUE_WAIT_FOR_EVENTS_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int enqueueAcquireGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueAcquireGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReleaseGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined (USE_DX_INTEROP) -typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); -typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); - - cl_int enqueueAcquireD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); -#endif - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueAcquireD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_2) -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_1) - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueReleaseD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueBarrier(object_), - __ENQUEUE_BARRIER_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int flush() const - { - return detail::errHandler(::clFlush(object_), __FLUSH_ERR); - } - - cl_int finish() const - { - return detail::errHandler(::clFinish(object_), __FINISH_ERR); - } -}; - -#ifdef _WIN32 -__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -__declspec(selectany) CommandQueue CommandQueue::default_; -__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#else -__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -__attribute__((weak)) CommandQueue CommandQueue::default_; -__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#endif - -inline cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); -} - -inline cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); -} - -inline void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - void * result = ::clEnqueueMapBuffer( - queue(), buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (cl_event*) event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - return result; -} - -inline cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (error != CL_SUCCESS) { - return error; - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - queue(), memory(), mapped_ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; -} - -inline cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); -} - -/** - * Blocking copy operation between iterators and a buffer. - */ -template< typename IteratorType > -inline cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator-startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if( error != CL_SUCCESS ) { - return error; - } -#if defined(_MSC_VER) - std::copy( - startIterator, - endIterator, - stdext::checked_array_iterator( - pointer, length)); -#else - std::copy(startIterator, endIterator, pointer); -#endif - Event endEvent; - error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if( error != CL_SUCCESS ) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; -} - -/** - * Blocking copy operation between iterators and a buffer. - */ -template< typename IteratorType > -inline cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator-startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if( error != CL_SUCCESS ) { - return error; - } - std::copy(pointer, pointer + length, startIterator); - Event endEvent; - error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if( error != CL_SUCCESS ) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; -} - -#if defined(CL_VERSION_1_1) -inline cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferRect( - src, - dst, - src_origin, - dst_origin, - region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - events, - event); -} -#endif - -inline cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImage( - src, - dst, - src_origin, - dst_origin, - region, - events, - event); -} - -inline cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImageToBuffer( - src, - dst, - src_origin, - region, - dst_offset, - events, - event); -} - -inline cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferToImage( - src, - dst, - src_offset, - dst_origin, - region, - events, - event); -} - - -inline cl_int flush(void) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.flush(); -} - -inline cl_int finish(void) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - - return queue.finish(); -} - -// Kernel Functor support -// New interface as of September 2011 -// Requires the C++11 std::tr1::function (note do not support TR1) -// Visual Studio 2010 and GCC 4.2 - -struct EnqueueArgs -{ - CommandQueue queue_; - const NDRange offset_; - const NDRange global_; - const NDRange local_; - VECTOR_CLASS events_; - - EnqueueArgs(NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(Event e, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } -}; - -namespace detail { - -class NullType {}; - -template -struct SetArg -{ - static void set (Kernel kernel, T0 arg) - { - kernel.setArg(index, arg); - } -}; - -template -struct SetArg -{ - static void set (Kernel, NullType) - { - } -}; - -template < - typename T0, typename T1, typename T2, typename T3, - typename T4, typename T5, typename T6, typename T7, - typename T8, typename T9, typename T10, typename T11, - typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, - typename T20, typename T21, typename T22, typename T23, - typename T24, typename T25, typename T26, typename T27, - typename T28, typename T29, typename T30, typename T31 -> -class KernelFunctorGlobal -{ -private: - Kernel kernel_; - -public: - KernelFunctorGlobal( - Kernel kernel) : - kernel_(kernel) - {} - - KernelFunctorGlobal( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - kernel_(program, name.c_str(), err) - {} - - Event operator() ( - const EnqueueArgs& args, - T0 t0, - T1 t1 = NullType(), - T2 t2 = NullType(), - T3 t3 = NullType(), - T4 t4 = NullType(), - T5 t5 = NullType(), - T6 t6 = NullType(), - T7 t7 = NullType(), - T8 t8 = NullType(), - T9 t9 = NullType(), - T10 t10 = NullType(), - T11 t11 = NullType(), - T12 t12 = NullType(), - T13 t13 = NullType(), - T14 t14 = NullType(), - T15 t15 = NullType(), - T16 t16 = NullType(), - T17 t17 = NullType(), - T18 t18 = NullType(), - T19 t19 = NullType(), - T20 t20 = NullType(), - T21 t21 = NullType(), - T22 t22 = NullType(), - T23 t23 = NullType(), - T24 t24 = NullType(), - T25 t25 = NullType(), - T26 t26 = NullType(), - T27 t27 = NullType(), - T28 t28 = NullType(), - T29 t29 = NullType(), - T30 t30 = NullType(), - T31 t31 = NullType() - ) - { - Event event; - SetArg<0, T0>::set(kernel_, t0); - SetArg<1, T1>::set(kernel_, t1); - SetArg<2, T2>::set(kernel_, t2); - SetArg<3, T3>::set(kernel_, t3); - SetArg<4, T4>::set(kernel_, t4); - SetArg<5, T5>::set(kernel_, t5); - SetArg<6, T6>::set(kernel_, t6); - SetArg<7, T7>::set(kernel_, t7); - SetArg<8, T8>::set(kernel_, t8); - SetArg<9, T9>::set(kernel_, t9); - SetArg<10, T10>::set(kernel_, t10); - SetArg<11, T11>::set(kernel_, t11); - SetArg<12, T12>::set(kernel_, t12); - SetArg<13, T13>::set(kernel_, t13); - SetArg<14, T14>::set(kernel_, t14); - SetArg<15, T15>::set(kernel_, t15); - SetArg<16, T16>::set(kernel_, t16); - SetArg<17, T17>::set(kernel_, t17); - SetArg<18, T18>::set(kernel_, t18); - SetArg<19, T19>::set(kernel_, t19); - SetArg<20, T20>::set(kernel_, t20); - SetArg<21, T21>::set(kernel_, t21); - SetArg<22, T22>::set(kernel_, t22); - SetArg<23, T23>::set(kernel_, t23); - SetArg<24, T24>::set(kernel_, t24); - SetArg<25, T25>::set(kernel_, t25); - SetArg<26, T26>::set(kernel_, t26); - SetArg<27, T27>::set(kernel_, t27); - SetArg<28, T28>::set(kernel_, t28); - SetArg<29, T29>::set(kernel_, t29); - SetArg<30, T30>::set(kernel_, t30); - SetArg<31, T31>::set(kernel_, t31); - - args.queue_.enqueueNDRangeKernel( - kernel_, - args.offset_, - args.global_, - args.local_, - &args.events_, - &event); - - return event; - } - -}; - -//------------------------------------------------------------------------------------------------------ - - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30, - typename T31> -struct functionImplementation_ -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30, - T31 arg31) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30, - arg31); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3); - } - - -}; - -template< - typename T0, - typename T1, - typename T2> -struct functionImplementation_ -< T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2); - } - - -}; - -template< - typename T0, - typename T1> -struct functionImplementation_ -< T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1) - { - return functor_( - enqueueArgs, - arg0, - arg1); - } - - -}; - -template< - typename T0> -struct functionImplementation_ -< T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0) - { - return functor_( - enqueueArgs, - arg0); - } - - -}; - - - - - -} // namespace detail - -//---------------------------------------------------------------------------------------------- - -template < - typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, - typename T3 = detail::NullType, typename T4 = detail::NullType, - typename T5 = detail::NullType, typename T6 = detail::NullType, - typename T7 = detail::NullType, typename T8 = detail::NullType, - typename T9 = detail::NullType, typename T10 = detail::NullType, - typename T11 = detail::NullType, typename T12 = detail::NullType, - typename T13 = detail::NullType, typename T14 = detail::NullType, - typename T15 = detail::NullType, typename T16 = detail::NullType, - typename T17 = detail::NullType, typename T18 = detail::NullType, - typename T19 = detail::NullType, typename T20 = detail::NullType, - typename T21 = detail::NullType, typename T22 = detail::NullType, - typename T23 = detail::NullType, typename T24 = detail::NullType, - typename T25 = detail::NullType, typename T26 = detail::NullType, - typename T27 = detail::NullType, typename T28 = detail::NullType, - typename T29 = detail::NullType, typename T30 = detail::NullType, - typename T31 = detail::NullType -> -struct make_kernel : - public detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - > -{ -public: - typedef detail::KernelFunctorGlobal< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - > FunctorType; - - make_kernel( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - >( - FunctorType(program, name, err)) - {} - - make_kernel( - const Kernel kernel) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - >( - FunctorType(kernel)) - {} -}; - - -//---------------------------------------------------------------------------------------------------------------------- - -#undef __ERR_STR -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#undef __GET_DEVICE_INFO_ERR -#undef __GET_PLATFORM_INFO_ERR -#undef __GET_DEVICE_IDS_ERR -#undef __GET_CONTEXT_INFO_ERR -#undef __GET_EVENT_INFO_ERR -#undef __GET_EVENT_PROFILE_INFO_ERR -#undef __GET_MEM_OBJECT_INFO_ERR -#undef __GET_IMAGE_INFO_ERR -#undef __GET_SAMPLER_INFO_ERR -#undef __GET_KERNEL_INFO_ERR -#undef __GET_KERNEL_ARG_INFO_ERR -#undef __GET_KERNEL_WORK_GROUP_INFO_ERR -#undef __GET_PROGRAM_INFO_ERR -#undef __GET_PROGRAM_BUILD_INFO_ERR -#undef __GET_COMMAND_QUEUE_INFO_ERR - -#undef __CREATE_CONTEXT_ERR -#undef __CREATE_CONTEXT_FROM_TYPE_ERR -#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR - -#undef __CREATE_BUFFER_ERR -#undef __CREATE_SUBBUFFER_ERR -#undef __CREATE_IMAGE2D_ERR -#undef __CREATE_IMAGE3D_ERR -#undef __CREATE_SAMPLER_ERR -#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR - -#undef __CREATE_USER_EVENT_ERR -#undef __SET_USER_EVENT_STATUS_ERR -#undef __SET_EVENT_CALLBACK_ERR -#undef __SET_PRINTF_CALLBACK_ERR - -#undef __WAIT_FOR_EVENTS_ERR - -#undef __CREATE_KERNEL_ERR -#undef __SET_KERNEL_ARGS_ERR -#undef __CREATE_PROGRAM_WITH_SOURCE_ERR -#undef __CREATE_PROGRAM_WITH_BINARY_ERR -#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR -#undef __BUILD_PROGRAM_ERR -#undef __CREATE_KERNELS_IN_PROGRAM_ERR - -#undef __CREATE_COMMAND_QUEUE_ERR -#undef __SET_COMMAND_QUEUE_PROPERTY_ERR -#undef __ENQUEUE_READ_BUFFER_ERR -#undef __ENQUEUE_WRITE_BUFFER_ERR -#undef __ENQUEUE_READ_BUFFER_RECT_ERR -#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR -#undef __ENQEUE_COPY_BUFFER_ERR -#undef __ENQEUE_COPY_BUFFER_RECT_ERR -#undef __ENQUEUE_READ_IMAGE_ERR -#undef __ENQUEUE_WRITE_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR -#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR -#undef __ENQUEUE_MAP_BUFFER_ERR -#undef __ENQUEUE_MAP_IMAGE_ERR -#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR -#undef __ENQUEUE_NDRANGE_KERNEL_ERR -#undef __ENQUEUE_TASK_ERR -#undef __ENQUEUE_NATIVE_KERNEL - -#undef __CL_EXPLICIT_CONSTRUCTORS - -#undef __UNLOAD_COMPILER_ERR -#endif //__CL_USER_OVERRIDE_ERROR_STRINGS - -#undef __CL_FUNCTION_TYPE - -// Extensions -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_VERSION_1_1) -#undef __INIT_CL_EXT_FCN_PTR -#endif // #if defined(CL_VERSION_1_1) -#undef __CREATE_SUB_DEVICES - -#if defined(USE_CL_DEVICE_FISSION) -#undef __PARAM_NAME_DEVICE_FISSION -#endif // USE_CL_DEVICE_FISSION - -#undef __DEFAULT_NOT_INITIALIZED -#undef __DEFAULT_BEING_INITIALIZED -#undef __DEFAULT_INITIALIZED - -} // namespace cl - -#ifdef _WIN32 -#pragma pop_macro("max") -#endif // _WIN32 - -#endif // CL_HPP_ diff --git a/src/algorithms/libs/complex_byte_to_float_x2.cc b/src/algorithms/libs/complex_byte_to_float_x2.cc index 0bcdcc909..04f4a54b2 100644 --- a/src/algorithms/libs/complex_byte_to_float_x2.cc +++ b/src/algorithms/libs/complex_byte_to_float_x2.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,10 +40,9 @@ complex_byte_to_float_x2_sptr make_complex_byte_to_float_x2() } - complex_byte_to_float_x2::complex_byte_to_float_x2() : sync_block("complex_byte_to_float_x2", - gr::io_signature::make (1, 1, sizeof(lv_8sc_t)), // lv_8sc_t is a Volk's typedef for std::complex - gr::io_signature::make (2, 2, sizeof(float))) + gr::io_signature::make(1, 1, sizeof(lv_8sc_t)), // lv_8sc_t is a Volk's typedef for std::complex + gr::io_signature::make(2, 2, sizeof(float))) { const int alignment_multiple = volk_get_alignment() / sizeof(float); set_alignment(std::max(1, alignment_multiple)); @@ -51,12 +50,12 @@ complex_byte_to_float_x2::complex_byte_to_float_x2() : sync_block("complex_byte_ int complex_byte_to_float_x2::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const lv_8sc_t *in = (const lv_8sc_t *) input_items[0]; - float *out0 = (float*) output_items[0]; - float *out1 = (float*) output_items[1]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out0 = reinterpret_cast(output_items[0]); + auto *out1 = reinterpret_cast(output_items[1]); const float scalar = 1; volk_8ic_s32f_deinterleave_32f_x2(out0, out1, in, scalar, noutput_items); return noutput_items; diff --git a/src/algorithms/libs/complex_byte_to_float_x2.h b/src/algorithms/libs/complex_byte_to_float_x2.h index 6883f7d39..74c2e9c55 100644 --- a/src/algorithms/libs/complex_byte_to_float_x2.h +++ b/src/algorithms/libs/complex_byte_to_float_x2.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,12 +49,13 @@ class complex_byte_to_float_x2 : public gr::sync_block { private: friend complex_byte_to_float_x2_sptr make_complex_byte_to_float_x2(); + public: complex_byte_to_float_x2(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/libs/complex_float_to_complex_byte.cc b/src/algorithms/libs/complex_float_to_complex_byte.cc index 9b659e506..d7106bedd 100644 --- a/src/algorithms/libs/complex_float_to_complex_byte.cc +++ b/src/algorithms/libs/complex_float_to_complex_byte.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,9 +31,7 @@ #include "complex_float_to_complex_byte.h" #include -#include -#include "volk_gnsssdr/volk_gnsssdr.h" - +#include complex_float_to_complex_byte_sptr make_complex_float_to_complex_byte() @@ -42,22 +40,21 @@ complex_float_to_complex_byte_sptr make_complex_float_to_complex_byte() } - complex_float_to_complex_byte::complex_float_to_complex_byte() : sync_block("complex_float_to_complex_byte", - gr::io_signature::make (1, 1, sizeof(gr_complex)), - gr::io_signature::make (1, 1, sizeof(lv_8sc_t))) // lv_8sc_t is a Volk's typedef for std::complex + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(lv_8sc_t))) // lv_8sc_t is a Volk's typedef for std::complex { - const int alignment_multiple = volk_get_alignment() / sizeof(lv_8sc_t); + const int alignment_multiple = volk_gnsssdr_get_alignment() / sizeof(lv_8sc_t); set_alignment(std::max(1, alignment_multiple)); } int complex_float_to_complex_byte::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const gr_complex *in = (const gr_complex *) input_items[0]; - lv_8sc_t *out = (lv_8sc_t*) output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); volk_gnsssdr_32fc_convert_8ic(out, in, noutput_items); return noutput_items; } diff --git a/src/algorithms/libs/complex_float_to_complex_byte.h b/src/algorithms/libs/complex_float_to_complex_byte.h index 50f50564b..74eb0b5c3 100644 --- a/src/algorithms/libs/complex_float_to_complex_byte.h +++ b/src/algorithms/libs/complex_float_to_complex_byte.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -47,12 +47,13 @@ class complex_float_to_complex_byte : public gr::sync_block { private: friend complex_float_to_complex_byte_sptr make_complex_float_to_complex_byte(); + public: complex_float_to_complex_byte(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/libs/conjugate_cc.cc b/src/algorithms/libs/conjugate_cc.cc new file mode 100644 index 000000000..67077ba23 --- /dev/null +++ b/src/algorithms/libs/conjugate_cc.cc @@ -0,0 +1,59 @@ +/*! + * \file conjugate_cc.cc + * \brief Conjugate a stream of gr_complex + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "conjugate_cc.h" +#include +#include + + +conjugate_cc_sptr make_conjugate_cc() +{ + return conjugate_cc_sptr(new conjugate_cc()); +} + + +conjugate_cc::conjugate_cc() : gr::sync_block("conjugate_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1, alignment_multiple)); +} + + +int conjugate_cc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + volk_32fc_conjugate_32fc(out, in, noutput_items); + return noutput_items; +} diff --git a/src/algorithms/libs/conjugate_cc.h b/src/algorithms/libs/conjugate_cc.h new file mode 100644 index 000000000..a04cd2410 --- /dev/null +++ b/src/algorithms/libs/conjugate_cc.h @@ -0,0 +1,60 @@ +/*! + * \file conjugate_cc.h + * \brief Conjugate a stream of gr_complex + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CONJUGATE_CC_H_ +#define GNSS_SDR_CONJUGATE_CC_H_ + +#include +#include + +class conjugate_cc; + +typedef boost::shared_ptr conjugate_cc_sptr; + +conjugate_cc_sptr make_conjugate_cc(); + +/*! + * \brief This class adapts a std::complex stream + * into two 32-bits (float) streams + */ +class conjugate_cc : public gr::sync_block +{ +private: + friend conjugate_cc_sptr make_conjugate_cc(); + +public: + conjugate_cc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/src/algorithms/libs/conjugate_ic.cc b/src/algorithms/libs/conjugate_ic.cc new file mode 100644 index 000000000..d3d00932e --- /dev/null +++ b/src/algorithms/libs/conjugate_ic.cc @@ -0,0 +1,59 @@ +/*! + * \file conjugate_ic.cc + * \brief Conjugate a stream of lv_8sc_t ( std::complex ) + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "conjugate_ic.h" +#include +#include + + +conjugate_ic_sptr make_conjugate_ic() +{ + return conjugate_ic_sptr(new conjugate_ic()); +} + + +conjugate_ic::conjugate_ic() : gr::sync_block("conjugate_ic", + gr::io_signature::make(1, 1, sizeof(lv_8sc_t)), + gr::io_signature::make(1, 1, sizeof(lv_8sc_t))) +{ + const int alignment_multiple = volk_gnsssdr_get_alignment() / sizeof(lv_8sc_t); + set_alignment(std::max(1, alignment_multiple)); +} + + +int conjugate_ic::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + volk_gnsssdr_8ic_conjugate_8ic(out, in, noutput_items); + return noutput_items; +} diff --git a/src/algorithms/libs/conjugate_ic.h b/src/algorithms/libs/conjugate_ic.h new file mode 100644 index 000000000..4b51f86da --- /dev/null +++ b/src/algorithms/libs/conjugate_ic.h @@ -0,0 +1,60 @@ +/*! + * \file conjugate_ic.h + * \brief Conjugate a stream of lv_8sc_t ( std::complex ) + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CONJUGATE_IC_H_ +#define GNSS_SDR_CONJUGATE_IC_H_ + +#include +#include + +class conjugate_ic; + +typedef boost::shared_ptr conjugate_ic_sptr; + +conjugate_ic_sptr make_conjugate_ic(); + +/*! + * \brief This class adapts a std::complex stream + * into two 32-bits (float) streams + */ +class conjugate_ic : public gr::sync_block +{ +private: + friend conjugate_ic_sptr make_conjugate_ic(); + +public: + conjugate_ic(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/src/algorithms/libs/conjugate_sc.cc b/src/algorithms/libs/conjugate_sc.cc new file mode 100644 index 000000000..e23f1c1a4 --- /dev/null +++ b/src/algorithms/libs/conjugate_sc.cc @@ -0,0 +1,59 @@ +/*! + * \file conjugate_sc.h + * \brief Conjugate a stream of lv_16sc_t ( std::complex ) + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "conjugate_sc.h" +#include +#include + + +conjugate_sc_sptr make_conjugate_sc() +{ + return conjugate_sc_sptr(new conjugate_sc()); +} + + +conjugate_sc::conjugate_sc() : gr::sync_block("conjugate_sc", + gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(lv_16sc_t))) +{ + const int alignment_multiple = volk_gnsssdr_get_alignment() / sizeof(lv_16sc_t); + set_alignment(std::max(1, alignment_multiple)); +} + + +int conjugate_sc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + volk_gnsssdr_16ic_conjugate_16ic(out, in, noutput_items); + return noutput_items; +} diff --git a/src/algorithms/libs/conjugate_sc.h b/src/algorithms/libs/conjugate_sc.h new file mode 100644 index 000000000..019d16dcb --- /dev/null +++ b/src/algorithms/libs/conjugate_sc.h @@ -0,0 +1,60 @@ +/*! + * \file conjugate_sc.h + * \brief Conjugate a stream of lv_16sc_t ( std::complex ) + * \author Carles Fernandez Prades, cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CONJUGATE_SC_H_ +#define GNSS_SDR_CONJUGATE_SC_H_ + +#include +#include + +class conjugate_sc; + +typedef boost::shared_ptr conjugate_sc_sptr; + +conjugate_sc_sptr make_conjugate_sc(); + +/*! + * \brief This class adapts a std::complex stream + * into two 32-bits (float) streams + */ +class conjugate_sc : public gr::sync_block +{ +private: + friend conjugate_sc_sptr make_conjugate_sc(); + +public: + conjugate_sc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/src/algorithms/libs/cshort_to_float_x2.cc b/src/algorithms/libs/cshort_to_float_x2.cc index 861f1c010..cfde3f79c 100644 --- a/src/algorithms/libs/cshort_to_float_x2.cc +++ b/src/algorithms/libs/cshort_to_float_x2.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,10 +40,9 @@ cshort_to_float_x2_sptr make_cshort_to_float_x2() } - cshort_to_float_x2::cshort_to_float_x2() : sync_block("cshort_to_float_x2", - gr::io_signature::make (1, 1, sizeof(lv_16sc_t)), // lv_8sc_t is a Volk's typedef for std::complex - gr::io_signature::make (2, 2, sizeof(float))) + gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), // lv_8sc_t is a Volk's typedef for std::complex + gr::io_signature::make(2, 2, sizeof(float))) { const int alignment_multiple = volk_get_alignment() / sizeof(lv_16sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -51,12 +50,12 @@ cshort_to_float_x2::cshort_to_float_x2() : sync_block("cshort_to_float_x2", int cshort_to_float_x2::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const lv_16sc_t *in = (const lv_16sc_t *) input_items[0]; - float *out0 = (float*) output_items[0]; - float *out1 = (float*) output_items[1]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out0 = reinterpret_cast(output_items[0]); + auto *out1 = reinterpret_cast(output_items[1]); const float scalar = 1; volk_16ic_s32f_deinterleave_32f_x2(out0, out1, in, scalar, noutput_items); return noutput_items; diff --git a/src/algorithms/libs/cshort_to_float_x2.h b/src/algorithms/libs/cshort_to_float_x2.h index c15662ed8..7a235e68a 100644 --- a/src/algorithms/libs/cshort_to_float_x2.h +++ b/src/algorithms/libs/cshort_to_float_x2.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,12 +49,13 @@ class cshort_to_float_x2 : public gr::sync_block { private: friend cshort_to_float_x2_sptr make_cshort_to_float_x2(); + public: cshort_to_float_x2(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/libs/fft_base_kernels.h b/src/algorithms/libs/fft_base_kernels.h deleted file mode 100644 index 101795697..000000000 --- a/src/algorithms/libs/fft_base_kernels.h +++ /dev/null @@ -1,277 +0,0 @@ - -// -// File: fft_base_kernels.h -// -// Version: <1.0> -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") -// in consideration of your agreement to the following terms, and your use, -// installation, modification or redistribution of this Apple software -// constitutes acceptance of these terms. If you do not agree with these -// terms, please do not use, install, modify or redistribute this Apple -// software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non - exclusive -// license, under Apple's copyrights in this original Apple software ( the -// "Apple Software" ), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and / or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following text -// and disclaimers in all such redistributions of the Apple Software. Neither -// the name, trademarks, service marks or logos of Apple Inc. may be used to -// endorse or promote products derived from the Apple Software without specific -// prior written permission from Apple. Except as expressly stated in this -// notice, no other rights or licenses, express or implied, are granted by -// Apple herein, including but not limited to any patent rights that may be -// infringed by your derivative works or by other works in which the Apple -// Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION -// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION -// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER -// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR -// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -#ifndef __CL_FFT_BASE_KERNELS_ -#define __CL_FFT_BASE_KERNELS_ - -#include - -using namespace std; - -static string baseKernels = string( - "#ifndef M_PI\n" - "#define M_PI 0x1.921fb54442d18p+1\n" - "#endif\n" - "#define complexMul(a,b) ((float2)(mad(-(a).y, (b).y, (a).x * (b).x), mad((a).y, (b).x, (a).x * (b).y)))\n" - "#define conj(a) ((float2)((a).x, -(a).y))\n" - "#define conjTransp(a) ((float2)(-(a).y, (a).x))\n" - "\n" - "#define fftKernel2(a,dir) \\\n" - "{ \\\n" - " float2 c = (a)[0]; \\\n" - " (a)[0] = c + (a)[1]; \\\n" - " (a)[1] = c - (a)[1]; \\\n" - "}\n" - "\n" - "#define fftKernel2S(d1,d2,dir) \\\n" - "{ \\\n" - " float2 c = (d1); \\\n" - " (d1) = c + (d2); \\\n" - " (d2) = c - (d2); \\\n" - "}\n" - "\n" - "#define fftKernel4(a,dir) \\\n" - "{ \\\n" - " fftKernel2S((a)[0], (a)[2], dir); \\\n" - " fftKernel2S((a)[1], (a)[3], dir); \\\n" - " fftKernel2S((a)[0], (a)[1], dir); \\\n" - " (a)[3] = (float2)(dir)*(conjTransp((a)[3])); \\\n" - " fftKernel2S((a)[2], (a)[3], dir); \\\n" - " float2 c = (a)[1]; \\\n" - " (a)[1] = (a)[2]; \\\n" - " (a)[2] = c; \\\n" - "}\n" - "\n" - "#define fftKernel4s(a0,a1,a2,a3,dir) \\\n" - "{ \\\n" - " fftKernel2S((a0), (a2), dir); \\\n" - " fftKernel2S((a1), (a3), dir); \\\n" - " fftKernel2S((a0), (a1), dir); \\\n" - " (a3) = (float2)(dir)*(conjTransp((a3))); \\\n" - " fftKernel2S((a2), (a3), dir); \\\n" - " float2 c = (a1); \\\n" - " (a1) = (a2); \\\n" - " (a2) = c; \\\n" - "}\n" - "\n" - "#define bitreverse8(a) \\\n" - "{ \\\n" - " float2 c; \\\n" - " c = (a)[1]; \\\n" - " (a)[1] = (a)[4]; \\\n" - " (a)[4] = c; \\\n" - " c = (a)[3]; \\\n" - " (a)[3] = (a)[6]; \\\n" - " (a)[6] = c; \\\n" - "}\n" - "\n" - "#define fftKernel8(a,dir) \\\n" - "{ \\\n" - " const float2 w1 = (float2)(0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f); \\\n" - " const float2 w3 = (float2)(-0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f); \\\n" - " float2 c; \\\n" - " fftKernel2S((a)[0], (a)[4], dir); \\\n" - " fftKernel2S((a)[1], (a)[5], dir); \\\n" - " fftKernel2S((a)[2], (a)[6], dir); \\\n" - " fftKernel2S((a)[3], (a)[7], dir); \\\n" - " (a)[5] = complexMul(w1, (a)[5]); \\\n" - " (a)[6] = (float2)(dir)*(conjTransp((a)[6])); \\\n" - " (a)[7] = complexMul(w3, (a)[7]); \\\n" - " fftKernel2S((a)[0], (a)[2], dir); \\\n" - " fftKernel2S((a)[1], (a)[3], dir); \\\n" - " fftKernel2S((a)[4], (a)[6], dir); \\\n" - " fftKernel2S((a)[5], (a)[7], dir); \\\n" - " (a)[3] = (float2)(dir)*(conjTransp((a)[3])); \\\n" - " (a)[7] = (float2)(dir)*(conjTransp((a)[7])); \\\n" - " fftKernel2S((a)[0], (a)[1], dir); \\\n" - " fftKernel2S((a)[2], (a)[3], dir); \\\n" - " fftKernel2S((a)[4], (a)[5], dir); \\\n" - " fftKernel2S((a)[6], (a)[7], dir); \\\n" - " bitreverse8((a)); \\\n" - "}\n" - "\n" - "#define bitreverse4x4(a) \\\n" - "{ \\\n" - " float2 c; \\\n" - " c = (a)[1]; (a)[1] = (a)[4]; (a)[4] = c; \\\n" - " c = (a)[2]; (a)[2] = (a)[8]; (a)[8] = c; \\\n" - " c = (a)[3]; (a)[3] = (a)[12]; (a)[12] = c; \\\n" - " c = (a)[6]; (a)[6] = (a)[9]; (a)[9] = c; \\\n" - " c = (a)[7]; (a)[7] = (a)[13]; (a)[13] = c; \\\n" - " c = (a)[11]; (a)[11] = (a)[14]; (a)[14] = c; \\\n" - "}\n" - "\n" - "#define fftKernel16(a,dir) \\\n" - "{ \\\n" - " const float w0 = 0x1.d906bcp-1f; \\\n" - " const float w1 = 0x1.87de2ap-2f; \\\n" - " const float w2 = 0x1.6a09e6p-1f; \\\n" - " fftKernel4s((a)[0], (a)[4], (a)[8], (a)[12], dir); \\\n" - " fftKernel4s((a)[1], (a)[5], (a)[9], (a)[13], dir); \\\n" - " fftKernel4s((a)[2], (a)[6], (a)[10], (a)[14], dir); \\\n" - " fftKernel4s((a)[3], (a)[7], (a)[11], (a)[15], dir); \\\n" - " (a)[5] = complexMul((a)[5], (float2)(w0, dir*w1)); \\\n" - " (a)[6] = complexMul((a)[6], (float2)(w2, dir*w2)); \\\n" - " (a)[7] = complexMul((a)[7], (float2)(w1, dir*w0)); \\\n" - " (a)[9] = complexMul((a)[9], (float2)(w2, dir*w2)); \\\n" - " (a)[10] = (float2)(dir)*(conjTransp((a)[10])); \\\n" - " (a)[11] = complexMul((a)[11], (float2)(-w2, dir*w2)); \\\n" - " (a)[13] = complexMul((a)[13], (float2)(w1, dir*w0)); \\\n" - " (a)[14] = complexMul((a)[14], (float2)(-w2, dir*w2)); \\\n" - " (a)[15] = complexMul((a)[15], (float2)(-w0, dir*-w1)); \\\n" - " fftKernel4((a), dir); \\\n" - " fftKernel4((a) + 4, dir); \\\n" - " fftKernel4((a) + 8, dir); \\\n" - " fftKernel4((a) + 12, dir); \\\n" - " bitreverse4x4((a)); \\\n" - "}\n" - "\n" - "#define bitreverse32(a) \\\n" - "{ \\\n" - " float2 c1, c2; \\\n" - " c1 = (a)[2]; (a)[2] = (a)[1]; c2 = (a)[4]; (a)[4] = c1; c1 = (a)[8]; (a)[8] = c2; c2 = (a)[16]; (a)[16] = c1; (a)[1] = c2; \\\n" - " c1 = (a)[6]; (a)[6] = (a)[3]; c2 = (a)[12]; (a)[12] = c1; c1 = (a)[24]; (a)[24] = c2; c2 = (a)[17]; (a)[17] = c1; (a)[3] = c2; \\\n" - " c1 = (a)[10]; (a)[10] = (a)[5]; c2 = (a)[20]; (a)[20] = c1; c1 = (a)[9]; (a)[9] = c2; c2 = (a)[18]; (a)[18] = c1; (a)[5] = c2; \\\n" - " c1 = (a)[14]; (a)[14] = (a)[7]; c2 = (a)[28]; (a)[28] = c1; c1 = (a)[25]; (a)[25] = c2; c2 = (a)[19]; (a)[19] = c1; (a)[7] = c2; \\\n" - " c1 = (a)[22]; (a)[22] = (a)[11]; c2 = (a)[13]; (a)[13] = c1; c1 = (a)[26]; (a)[26] = c2; c2 = (a)[21]; (a)[21] = c1; (a)[11] = c2; \\\n" - " c1 = (a)[30]; (a)[30] = (a)[15]; c2 = (a)[29]; (a)[29] = c1; c1 = (a)[27]; (a)[27] = c2; c2 = (a)[23]; (a)[23] = c1; (a)[15] = c2; \\\n" - "}\n" - "\n" - "#define fftKernel32(a,dir) \\\n" - "{ \\\n" - " fftKernel2S((a)[0], (a)[16], dir); \\\n" - " fftKernel2S((a)[1], (a)[17], dir); \\\n" - " fftKernel2S((a)[2], (a)[18], dir); \\\n" - " fftKernel2S((a)[3], (a)[19], dir); \\\n" - " fftKernel2S((a)[4], (a)[20], dir); \\\n" - " fftKernel2S((a)[5], (a)[21], dir); \\\n" - " fftKernel2S((a)[6], (a)[22], dir); \\\n" - " fftKernel2S((a)[7], (a)[23], dir); \\\n" - " fftKernel2S((a)[8], (a)[24], dir); \\\n" - " fftKernel2S((a)[9], (a)[25], dir); \\\n" - " fftKernel2S((a)[10], (a)[26], dir); \\\n" - " fftKernel2S((a)[11], (a)[27], dir); \\\n" - " fftKernel2S((a)[12], (a)[28], dir); \\\n" - " fftKernel2S((a)[13], (a)[29], dir); \\\n" - " fftKernel2S((a)[14], (a)[30], dir); \\\n" - " fftKernel2S((a)[15], (a)[31], dir); \\\n" - " (a)[17] = complexMul((a)[17], (float2)(0x1.f6297cp-1f, dir*0x1.8f8b84p-3f)); \\\n" - " (a)[18] = complexMul((a)[18], (float2)(0x1.d906bcp-1f, dir*0x1.87de2ap-2f)); \\\n" - " (a)[19] = complexMul((a)[19], (float2)(0x1.a9b662p-1f, dir*0x1.1c73b4p-1f)); \\\n" - " (a)[20] = complexMul((a)[20], (float2)(0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f)); \\\n" - " (a)[21] = complexMul((a)[21], (float2)(0x1.1c73b4p-1f, dir*0x1.a9b662p-1f)); \\\n" - " (a)[22] = complexMul((a)[22], (float2)(0x1.87de2ap-2f, dir*0x1.d906bcp-1f)); \\\n" - " (a)[23] = complexMul((a)[23], (float2)(0x1.8f8b84p-3f, dir*0x1.f6297cp-1f)); \\\n" - " (a)[24] = complexMul((a)[24], (float2)(0x0p+0f, dir*0x1p+0f)); \\\n" - " (a)[25] = complexMul((a)[25], (float2)(-0x1.8f8b84p-3f, dir*0x1.f6297cp-1f)); \\\n" - " (a)[26] = complexMul((a)[26], (float2)(-0x1.87de2ap-2f, dir*0x1.d906bcp-1f)); \\\n" - " (a)[27] = complexMul((a)[27], (float2)(-0x1.1c73b4p-1f, dir*0x1.a9b662p-1f)); \\\n" - " (a)[28] = complexMul((a)[28], (float2)(-0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f)); \\\n" - " (a)[29] = complexMul((a)[29], (float2)(-0x1.a9b662p-1f, dir*0x1.1c73b4p-1f)); \\\n" - " (a)[30] = complexMul((a)[30], (float2)(-0x1.d906bcp-1f, dir*0x1.87de2ap-2f)); \\\n" - " (a)[31] = complexMul((a)[31], (float2)(-0x1.f6297cp-1f, dir*0x1.8f8b84p-3f)); \\\n" - " fftKernel16((a), dir); \\\n" - " fftKernel16((a) + 16, dir); \\\n" - " bitreverse32((a)); \\\n" - "}\n\n" - ); - -static string twistKernelInterleaved = string( - "__kernel void \\\n" - "clFFT_1DTwistInterleaved(__global float2 *in, unsigned int startRow, unsigned int numCols, unsigned int N, unsigned int numRowsToProcess, int dir) \\\n" - "{ \\\n" - " float2 a, w; \\\n" - " float ang; \\\n" - " unsigned int j; \\\n" - " unsigned int i = get_global_id(0); \\\n" - " unsigned int startIndex = i; \\\n" - " \\\n" - " if(i < numCols) \\\n" - " { \\\n" - " for(j = 0; j < numRowsToProcess; j++) \\\n" - " { \\\n" - " a = in[startIndex]; \\\n" - " ang = 2.0f * M_PI * dir * i * (startRow + j) / N; \\\n" - " w = (float2)(native_cos(ang), native_sin(ang)); \\\n" - " a = complexMul(a, w); \\\n" - " in[startIndex] = a; \\\n" - " startIndex += numCols; \\\n" - " } \\\n" - " } \\\n" - "} \\\n" - ); - -static string twistKernelPlannar = string( - "__kernel void \\\n" - "clFFT_1DTwistSplit(__global float *in_real, __global float *in_imag , unsigned int startRow, unsigned int numCols, unsigned int N, unsigned int numRowsToProcess, int dir) \\\n" - "{ \\\n" - " float2 a, w; \\\n" - " float ang; \\\n" - " unsigned int j; \\\n" - " unsigned int i = get_global_id(0); \\\n" - " unsigned int startIndex = i; \\\n" - " \\\n" - " if(i < numCols) \\\n" - " { \\\n" - " for(j = 0; j < numRowsToProcess; j++) \\\n" - " { \\\n" - " a = (float2)(in_real[startIndex], in_imag[startIndex]); \\\n" - " ang = 2.0f * M_PI * dir * i * (startRow + j) / N; \\\n" - " w = (float2)(native_cos(ang), native_sin(ang)); \\\n" - " a = complexMul(a, w); \\\n" - " in_real[startIndex] = a.x; \\\n" - " in_imag[startIndex] = a.y; \\\n" - " startIndex += numCols; \\\n" - " } \\\n" - " } \\\n" - "} \\\n" - ); - - - -#endif diff --git a/src/algorithms/libs/fft_execute.cc b/src/algorithms/libs/fft_execute.cc deleted file mode 100644 index 6416e163e..000000000 --- a/src/algorithms/libs/fft_execute.cc +++ /dev/null @@ -1,405 +0,0 @@ - -// -// File: fft_execute.cpp -// -// Version: <1.0> -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") -// in consideration of your agreement to the following terms, and your use, -// installation, modification or redistribution of this Apple software -// constitutes acceptance of these terms. If you do not agree with these -// terms, please do not use, install, modify or redistribute this Apple -// software.¬ -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non - exclusive -// license, under Apple's copyrights in this original Apple software ( the -// "Apple Software" ), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and / or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following text -// and disclaimers in all such redistributions of the Apple Software. Neither -// the name, trademarks, service marks or logos of Apple Inc. may be used to -// endorse or promote products derived from the Apple Software without specific -// prior written permission from Apple. Except as expressly stated in this -// notice, no other rights or licenses, express or implied, are granted by -// Apple herein, including but not limited to any patent rights that may be -// infringed by your derivative works or by other works in which the Apple -// Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION -// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION -// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER -// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR -// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -#include "fft_internal.h" -#include "clFFT.h" -#include -#include -#include - -#define max(a,b) (((a)>(b)) ? (a) : (b)) -#define min(a,b) (((a)<(b)) ? (a) : (b)) - -static cl_int -allocateTemporaryBufferInterleaved(cl_fft_plan *plan, cl_uint batchSize) -{ - cl_int err = CL_SUCCESS; - if(plan->temp_buffer_needed && plan->last_batch_size != batchSize) - { - plan->last_batch_size = batchSize; - size_t tmpLength = plan->n.x * plan->n.y * plan->n.z * batchSize * 2 * sizeof(cl_float); - - if(plan->tempmemobj) - clReleaseMemObject(plan->tempmemobj); - - plan->tempmemobj = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, NULL, &err); - } - return err; -} - -static cl_int -allocateTemporaryBufferPlannar(cl_fft_plan *plan, cl_uint batchSize) -{ - cl_int err = CL_SUCCESS; - cl_int terr; - if(plan->temp_buffer_needed && plan->last_batch_size != batchSize) - { - plan->last_batch_size = batchSize; - size_t tmpLength = plan->n.x * plan->n.y * plan->n.z * batchSize * sizeof(cl_float); - - if(plan->tempmemobj_real) - clReleaseMemObject(plan->tempmemobj_real); - - if(plan->tempmemobj_imag) - clReleaseMemObject(plan->tempmemobj_imag); - - plan->tempmemobj_real = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, NULL, &err); - plan->tempmemobj_imag = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, NULL, &terr); - err |= terr; - } - return err; -} - -void -getKernelWorkDimensions(cl_fft_plan *plan, cl_fft_kernel_info *kernelInfo, cl_int *batchSize, size_t *gWorkItems, size_t *lWorkItems) -{ - *lWorkItems = kernelInfo->num_workitems_per_workgroup; - int numWorkGroups = kernelInfo->num_workgroups; - int numXFormsPerWG = kernelInfo->num_xforms_per_workgroup; - - switch(kernelInfo->dir) - { - case cl_fft_kernel_x: - *batchSize *= (plan->n.y * plan->n.z); - numWorkGroups = (*batchSize % numXFormsPerWG) ? (*batchSize/numXFormsPerWG + 1) : (*batchSize/numXFormsPerWG); - numWorkGroups *= kernelInfo->num_workgroups; - break; - case cl_fft_kernel_y: - *batchSize *= plan->n.z; - numWorkGroups *= *batchSize; - break; - case cl_fft_kernel_z: - numWorkGroups *= *batchSize; - break; - } - - *gWorkItems = numWorkGroups * *lWorkItems; -} - -cl_int -clFFT_ExecuteInterleaved( cl_command_queue queue, clFFT_Plan Plan, cl_int batchSize, clFFT_Direction dir, - cl_mem data_in, cl_mem data_out, - cl_int num_events, cl_event *event_list, cl_event *event ) -{ - int s; - cl_fft_plan *plan = (cl_fft_plan *) Plan; - if(plan->format != clFFT_InterleavedComplexFormat) - return CL_INVALID_VALUE; - - cl_int err; - size_t gWorkItems, lWorkItems; - int inPlaceDone; - - cl_int isInPlace = data_in == data_out ? 1 : 0; - - if((err = allocateTemporaryBufferInterleaved(plan, batchSize)) != CL_SUCCESS) - return err; - - cl_mem memObj[3]; - memObj[0] = data_in; - memObj[1] = data_out; - memObj[2] = plan->tempmemobj; - cl_fft_kernel_info *kernelInfo = plan->kernel_info; - int numKernels = plan->num_kernels; - - int numKernelsOdd = numKernels & 1; - int currRead = 0; - int currWrite = 1; - - // at least one external dram shuffle (transpose) required - if(plan->temp_buffer_needed) - { - // in-place transform - if(isInPlace) - { - inPlaceDone = 0; - currRead = 1; - currWrite = 2; - } - else - { - currWrite = (numKernels & 1) ? 1 : 2; - } - - while(kernelInfo) - { - if( isInPlace && numKernelsOdd && !inPlaceDone && kernelInfo->in_place_possible) - { - currWrite = currRead; - inPlaceDone = 1; - } - - s = batchSize; - getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); - err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_int), &dir); - err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_int), &s); - - err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, NULL, &gWorkItems, &lWorkItems, 0, NULL, NULL); - if(err) - return err; - - currRead = (currWrite == 1) ? 1 : 2; - currWrite = (currWrite == 1) ? 2 : 1; - - kernelInfo = kernelInfo->next; - } - } - // no dram shuffle (transpose required) transform - // all kernels can execute in-place. - else { - - while(kernelInfo) - { - s = batchSize; - getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); - err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_int), &dir); - err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_int), &s); - - err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, NULL, &gWorkItems, &lWorkItems, 0, NULL, NULL); - if(err) - return err; - - currRead = 1; - currWrite = 1; - - kernelInfo = kernelInfo->next; - } - } - - return err; -} - -cl_int -clFFT_ExecutePlannar( cl_command_queue queue, clFFT_Plan Plan, cl_int batchSize, clFFT_Direction dir, - cl_mem data_in_real, cl_mem data_in_imag, cl_mem data_out_real, cl_mem data_out_imag, - cl_int num_events, cl_event *event_list, cl_event *event) -{ - int s; - cl_fft_plan *plan = (cl_fft_plan *) Plan; - - if(plan->format != clFFT_SplitComplexFormat) - return CL_INVALID_VALUE; - - cl_int err; - size_t gWorkItems, lWorkItems; - int inPlaceDone; - - cl_int isInPlace = ((data_in_real == data_out_real) && (data_in_imag == data_out_imag)) ? 1 : 0; - - if((err = allocateTemporaryBufferPlannar(plan, batchSize)) != CL_SUCCESS) - return err; - - cl_mem memObj_real[3]; - cl_mem memObj_imag[3]; - memObj_real[0] = data_in_real; - memObj_real[1] = data_out_real; - memObj_real[2] = plan->tempmemobj_real; - memObj_imag[0] = data_in_imag; - memObj_imag[1] = data_out_imag; - memObj_imag[2] = plan->tempmemobj_imag; - - cl_fft_kernel_info *kernelInfo = plan->kernel_info; - int numKernels = plan->num_kernels; - - int numKernelsOdd = numKernels & 1; - int currRead = 0; - int currWrite = 1; - - // at least one external dram shuffle (transpose) required - if(plan->temp_buffer_needed) - { - // in-place transform - if(isInPlace) - { - inPlaceDone = 0; - currRead = 1; - currWrite = 2; - } - else - { - currWrite = (numKernels & 1) ? 1 : 2; - } - - while(kernelInfo) - { - if( isInPlace && numKernelsOdd && !inPlaceDone && kernelInfo->in_place_possible) - { - currWrite = currRead; - inPlaceDone = 1; - } - - s = batchSize; - getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); - err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj_real[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj_imag[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_mem), &memObj_real[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_mem), &memObj_imag[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 4, sizeof(cl_int), &dir); - err |= clSetKernelArg(kernelInfo->kernel, 5, sizeof(cl_int), &s); - - err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, NULL, &gWorkItems, &lWorkItems, 0, NULL, NULL); - if(err) - return err; - - currRead = (currWrite == 1) ? 1 : 2; - currWrite = (currWrite == 1) ? 2 : 1; - - kernelInfo = kernelInfo->next; - } - } - // no dram shuffle (transpose required) transform - else { - - while(kernelInfo) - { - s = batchSize; - getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); - err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj_real[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj_imag[currRead]); - err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_mem), &memObj_real[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_mem), &memObj_imag[currWrite]); - err |= clSetKernelArg(kernelInfo->kernel, 4, sizeof(cl_int), &dir); - err |= clSetKernelArg(kernelInfo->kernel, 5, sizeof(cl_int), &s); - - err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, NULL, &gWorkItems, &lWorkItems, 0, NULL, NULL); - if(err) - return err; - - currRead = 1; - currWrite = 1; - - kernelInfo = kernelInfo->next; - } - } - - return err; -} - -cl_int -clFFT_1DTwistInterleaved(clFFT_Plan Plan, cl_command_queue queue, cl_mem array, - unsigned numRows, unsigned numCols, unsigned startRow, unsigned rowsToProcess, clFFT_Direction dir) -{ - cl_fft_plan *plan = (cl_fft_plan *) Plan; - - unsigned int N = numRows*numCols; - unsigned int nCols = numCols; - unsigned int sRow = startRow; - unsigned int rToProcess = rowsToProcess; - int d = dir; - int err = 0; - - cl_device_id device_id; - err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, sizeof(cl_device_id), &device_id, NULL); - if(err) - return err; - - size_t gSize; - err = clGetKernelWorkGroupInfo(plan->twist_kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &gSize, NULL); - if(err) - return err; - - gSize = min(128, gSize); - size_t numGlobalThreads[1] = { max(numCols / gSize, 1)*gSize }; - size_t numLocalThreads[1] = { gSize }; - - err |= clSetKernelArg(plan->twist_kernel, 0, sizeof(cl_mem), &array); - err |= clSetKernelArg(plan->twist_kernel, 1, sizeof(unsigned int), &sRow); - err |= clSetKernelArg(plan->twist_kernel, 2, sizeof(unsigned int), &nCols); - err |= clSetKernelArg(plan->twist_kernel, 3, sizeof(unsigned int), &N); - err |= clSetKernelArg(plan->twist_kernel, 4, sizeof(unsigned int), &rToProcess); - err |= clSetKernelArg(plan->twist_kernel, 5, sizeof(int), &d); - - err |= clEnqueueNDRangeKernel(queue, plan->twist_kernel, 1, NULL, numGlobalThreads, numLocalThreads, 0, NULL, NULL); - - return err; -} - -cl_int -clFFT_1DTwistPlannar(clFFT_Plan Plan, cl_command_queue queue, cl_mem array_real, cl_mem array_imag, - unsigned numRows, unsigned numCols, unsigned startRow, unsigned rowsToProcess, clFFT_Direction dir) -{ - cl_fft_plan *plan = (cl_fft_plan *) Plan; - - unsigned int N = numRows*numCols; - unsigned int nCols = numCols; - unsigned int sRow = startRow; - unsigned int rToProcess = rowsToProcess; - int d = dir; - int err = 0; - - cl_device_id device_id; - err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, sizeof(cl_device_id), &device_id, NULL); - if(err) - return err; - - size_t gSize; - err = clGetKernelWorkGroupInfo(plan->twist_kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &gSize, NULL); - if(err) - return err; - - gSize = min(128, gSize); - size_t numGlobalThreads[1] = { max(numCols / gSize, 1)*gSize }; - size_t numLocalThreads[1] = { gSize }; - - err |= clSetKernelArg(plan->twist_kernel, 0, sizeof(cl_mem), &array_real); - err |= clSetKernelArg(plan->twist_kernel, 1, sizeof(cl_mem), &array_imag); - err |= clSetKernelArg(plan->twist_kernel, 2, sizeof(unsigned int), &sRow); - err |= clSetKernelArg(plan->twist_kernel, 3, sizeof(unsigned int), &nCols); - err |= clSetKernelArg(plan->twist_kernel, 4, sizeof(unsigned int), &N); - err |= clSetKernelArg(plan->twist_kernel, 5, sizeof(unsigned int), &rToProcess); - err |= clSetKernelArg(plan->twist_kernel, 6, sizeof(int), &d); - - err |= clEnqueueNDRangeKernel(queue, plan->twist_kernel, 1, NULL, numGlobalThreads, numLocalThreads, 0, NULL, NULL); - - return err; -} - diff --git a/src/algorithms/libs/fft_internal.h b/src/algorithms/libs/fft_internal.h deleted file mode 100644 index 5b797a3a0..000000000 --- a/src/algorithms/libs/fft_internal.h +++ /dev/null @@ -1,163 +0,0 @@ - -// -// File: fft_internal.h -// -// Version: <1.0> -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") -// in consideration of your agreement to the following terms, and your use, -// installation, modification or redistribution of this Apple software -// constitutes acceptance of these terms. If you do not agree with these -// terms, please do not use, install, modify or redistribute this Apple -// software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non - exclusive -// license, under Apple's copyrights in this original Apple software ( the -// "Apple Software" ), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and / or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following text -// and disclaimers in all such redistributions of the Apple Software. Neither -// the name, trademarks, service marks or logos of Apple Inc. may be used to -// endorse or promote products derived from the Apple Software without specific -// prior written permission from Apple. Except as expressly stated in this -// notice, no other rights or licenses, express or implied, are granted by -// Apple herein, including but not limited to any patent rights that may be -// infringed by your derivative works or by other works in which the Apple -// Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION -// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION -// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER -// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR -// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -#ifndef __CLFFT_INTERNAL_H -#define __CLFFT_INTERNAL_H - -#include "clFFT.h" -#include -#include -#include - -using namespace std; - -typedef enum kernel_dir_t -{ - cl_fft_kernel_x, - cl_fft_kernel_y, - cl_fft_kernel_z -}cl_fft_kernel_dir; - -typedef struct kernel_info_t -{ - cl_kernel kernel; - char *kernel_name; - unsigned lmem_size; - unsigned num_workgroups; - unsigned num_xforms_per_workgroup; - unsigned num_workitems_per_workgroup; - cl_fft_kernel_dir dir; - int in_place_possible; - kernel_info_t *next; -}cl_fft_kernel_info; - -typedef struct -{ - // context in which fft resources are created and kernels are executed - cl_context context; - - // size of signal - clFFT_Dim3 n; - - // dimension of transform ... must be either 1D, 2D or 3D - clFFT_Dimension dim; - - // data format ... must be either interleaved or plannar - clFFT_DataFormat format; - - // string containing kernel source. Generated at runtime based on - // n, dim, format and other parameters - string *kernel_string; - - // CL program containing source and kernel this particular - // n, dim, data format - cl_program program; - - // linked list of kernels which needs to be executed for this fft - cl_fft_kernel_info *kernel_info; - - // number of kernels - int num_kernels; - - // twist kernel for virtualizing fft of very large sizes that do not - // fit in GPU global memory - cl_kernel twist_kernel; - - // flag indicating if temporary intermediate buffer is needed or not. - // this depends on fft kernels being executed and if transform is - // in-place or out-of-place. e.g. Local memory fft (say 1D 1024 ... - // one that does not require global transpose do not need temporary buffer) - // 2D 1024x1024 out-of-place fft however do require intermediate buffer. - // If temp buffer is needed, its allocation is lazy i.e. its not allocated - // until its needed - cl_int temp_buffer_needed; - - // Batch size is runtime parameter and size of temporary buffer (if needed) - // depends on batch size. Allocation of temporary buffer is lazy i.e. its - // only created when needed. Once its created at first call of clFFT_Executexxx - // it is not allocated next time if next time clFFT_Executexxx is called with - // batch size different than the first call. last_batch_size caches the last - // batch size with which this plan is used so that we dont keep allocating/deallocating - // temp buffer if same batch size is used again and again. - unsigned last_batch_size; - - // temporary buffer for interleaved plan - cl_mem tempmemobj; - - // temporary buffer for planner plan. Only one of tempmemobj or - // (tempmemobj_real, tempmemobj_imag) pair is valid (allocated) depending - // data format of plan (plannar or interleaved) - cl_mem tempmemobj_real, tempmemobj_imag; - - // Maximum size of signal for which local memory transposed based - // fft is sufficient i.e. no global mem transpose (communication) - // is needed - unsigned max_localmem_fft_size; - - // Maximum work items per work group allowed. This, along with max_radix below controls - // maximum local memory being used by fft kernels of this plan. Set to 256 by default - unsigned max_work_item_per_workgroup; - - // Maximum base radix for local memory fft ... this controls the maximum register - // space used by work items. Currently defaults to 16 - unsigned max_radix; - - // Device depended parameter that tells how many work-items need to be read consecutive - // values to make sure global memory access by work-items of a work-group result in - // coalesced memory access to utilize full bandwidth e.g. on NVidia tesla, this is 16 - unsigned min_mem_coalesce_width; - - // Number of local memory banks. This is used to geneate kernel with local memory - // transposes with appropriate padding to avoid bank conflicts to local memory - // e.g. on NVidia it is 16. - unsigned num_local_mem_banks; -}cl_fft_plan; - -void FFT1D(cl_fft_plan *plan, cl_fft_kernel_dir dir); - -#endif diff --git a/src/algorithms/libs/fft_kernelstring.cc b/src/algorithms/libs/fft_kernelstring.cc deleted file mode 100644 index 7847ce959..000000000 --- a/src/algorithms/libs/fft_kernelstring.cc +++ /dev/null @@ -1,1257 +0,0 @@ - -// -// File: fft_kernelstring.cpp -// -// Version: <1.0> -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") -// in consideration of your agreement to the following terms, and your use, -// installation, modification or redistribution of this Apple software -// constitutes acceptance of these terms. If you do not agree with these -// terms, please do not use, install, modify or redistribute this Apple -// software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non - exclusive -// license, under Apple's copyrights in this original Apple software ( the -// "Apple Software" ), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and / or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following text -// and disclaimers in all such redistributions of the Apple Software. Neither -// the name, trademarks, service marks or logos of Apple Inc. may be used to -// endorse or promote products derived from the Apple Software without specific -// prior written permission from Apple. Except as expressly stated in this -// notice, no other rights or licenses, express or implied, are granted by -// Apple herein, including but not limited to any patent rights that may be -// infringed by your derivative works or by other works in which the Apple -// Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION -// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION -// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER -// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR -// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "fft_internal.h" -#include "clFFT.h" - -using namespace std; - -#define max(A,B) ((A) > (B) ? (A) : (B)) -#define min(A,B) ((A) < (B) ? (A) : (B)) - -static string -num2str(int num) -{ - char temp[200]; - sprintf(temp, "%d", num); - return string(temp); -} - -// For any n, this function decomposes n into factors for loacal memory tranpose -// based fft. Factors (radices) are sorted such that the first one (radixArray[0]) -// is the largest. This base radix determines the number of registers used by each -// work item and product of remaining radices determine the size of work group needed. -// To make things concrete with and example, suppose n = 1024. It is decomposed into -// 1024 = 16 x 16 x 4. Hence kernel uses float2 a[16], for local in-register fft and -// needs 16 x 4 = 64 work items per work group. So kernel first performance 64 length -// 16 ffts (64 work items working in parallel) following by transpose using local -// memory followed by again 64 length 16 ffts followed by transpose using local memory -// followed by 256 length 4 ffts. For the last step since with size of work group is -// 64 and each work item can array for 16 values, 64 work items can compute 256 length -// 4 ffts by each work item computing 4 length 4 ffts. -// Similarly for n = 2048 = 8 x 8 x 8 x 4, each work group has 8 x 8 x 4 = 256 work -// iterms which each computes 256 (in-parallel) length 8 ffts in-register, followed -// by transpose using local memory, followed by 256 length 8 in-register ffts, followed -// by transpose using local memory, followed by 256 length 8 in-register ffts, followed -// by transpose using local memory, followed by 512 length 4 in-register ffts. Again, -// for the last step, each work item computes two length 4 in-register ffts and thus -// 256 work items are needed to compute all 512 ffts. -// For n = 32 = 8 x 4, 4 work items first compute 4 in-register -// lenth 8 ffts, followed by transpose using local memory followed by 8 in-register -// length 4 ffts, where each work item computes two length 4 ffts thus 4 work items -// can compute 8 length 4 ffts. However if work group size of say 64 is choosen, -// each work group can compute 64/ 4 = 16 size 32 ffts (batched transform). -// Users can play with these parameters to figure what gives best performance on -// their particular device i.e. some device have less register space thus using -// smaller base radix can avoid spilling ... some has small local memory thus -// using smaller work group size may be required etc - -static void -getRadixArray(unsigned int n, unsigned int *radixArray, unsigned int *numRadices, unsigned int maxRadix) -{ - if(maxRadix > 1) - { - maxRadix = min(n, maxRadix); - unsigned int cnt = 0; - while(n > maxRadix) - { - radixArray[cnt++] = maxRadix; - n /= maxRadix; - } - radixArray[cnt++] = n; - *numRadices = cnt; - return; - } - - switch(n) - { - case 2: - *numRadices = 1; - radixArray[0] = 2; - break; - - case 4: - *numRadices = 1; - radixArray[0] = 4; - break; - - case 8: - *numRadices = 1; - radixArray[0] = 8; - break; - - case 16: - *numRadices = 2; - radixArray[0] = 8; radixArray[1] = 2; - break; - - case 32: - *numRadices = 2; - radixArray[0] = 8; radixArray[1] = 4; - break; - - case 64: - *numRadices = 2; - radixArray[0] = 8; radixArray[1] = 8; - break; - - case 128: - *numRadices = 3; - radixArray[0] = 8; radixArray[1] = 4; radixArray[2] = 4; - break; - - case 256: - *numRadices = 4; - radixArray[0] = 4; radixArray[1] = 4; radixArray[2] = 4; radixArray[3] = 4; - break; - - case 512: - *numRadices = 3; - radixArray[0] = 8; radixArray[1] = 8; radixArray[2] = 8; - break; - - case 1024: - *numRadices = 3; - radixArray[0] = 16; radixArray[1] = 16; radixArray[2] = 4; - break; - case 2048: - *numRadices = 4; - radixArray[0] = 8; radixArray[1] = 8; radixArray[2] = 8; radixArray[3] = 4; - break; - default: - *numRadices = 0; - return; - } -} - -static void -insertHeader(string &kernelString, string &kernelName, clFFT_DataFormat dataFormat) -{ - if(dataFormat == clFFT_SplitComplexFormat) - kernelString += string("__kernel void ") + kernelName + string("(__global float *in_real, __global float *in_imag, __global float *out_real, __global float *out_imag, int dir, int S)\n"); - else - kernelString += string("__kernel void ") + kernelName + string("(__global float2 *in, __global float2 *out, int dir, int S)\n"); -} - -static void -insertVariables(string &kStream, int maxRadix) -{ - kStream += string(" int i, j, r, indexIn, indexOut, index, tid, bNum, xNum, k, l;\n"); - kStream += string(" int s, ii, jj, offset;\n"); - kStream += string(" float2 w;\n"); - kStream += string(" float ang, angf, ang1;\n"); - kStream += string(" __local float *lMemStore, *lMemLoad;\n"); - kStream += string(" float2 a[") + num2str(maxRadix) + string("];\n"); - kStream += string(" int lId = get_local_id( 0 );\n"); - kStream += string(" int groupId = get_group_id( 0 );\n"); -} - -static void -formattedLoad(string &kernelString, int aIndex, int gIndex, clFFT_DataFormat dataFormat) -{ - if(dataFormat == clFFT_InterleavedComplexFormat) - kernelString += string(" a[") + num2str(aIndex) + string("] = in[") + num2str(gIndex) + string("];\n"); - else - { - kernelString += string(" a[") + num2str(aIndex) + string("].x = in_real[") + num2str(gIndex) + string("];\n"); - kernelString += string(" a[") + num2str(aIndex) + string("].y = in_imag[") + num2str(gIndex) + string("];\n"); - } -} - -static void -formattedStore(string &kernelString, int aIndex, int gIndex, clFFT_DataFormat dataFormat) -{ - if(dataFormat == clFFT_InterleavedComplexFormat) - kernelString += string(" out[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("];\n"); - else - { - kernelString += string(" out_real[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("].x;\n"); - kernelString += string(" out_imag[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("].y;\n"); - } -} - -static int -insertGlobalLoadsAndTranspose(string &kernelString, int N, int numWorkItemsPerXForm, int numXFormsPerWG, int R0, int mem_coalesce_width, clFFT_DataFormat dataFormat) -{ - int log2NumWorkItemsPerXForm = (int) log2(numWorkItemsPerXForm); - int groupSize = numWorkItemsPerXForm * numXFormsPerWG; - int i, j; - int lMemSize = 0; - - if(numXFormsPerWG > 1) - kernelString += string(" s = S & ") + num2str(numXFormsPerWG - 1) + string(";\n"); - - if(numWorkItemsPerXForm >= mem_coalesce_width) - { - if(numXFormsPerWG > 1) - { - kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm-1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); - kernelString += string(" if( !s || (groupId < get_num_groups(0)-1) || (jj < s) ) {\n"); - kernelString += string(" offset = mad24( mad24(groupId, ") + num2str(numXFormsPerWG) + string(", jj), ") + num2str(N) + string(", ii );\n"); - if(dataFormat == clFFT_InterleavedComplexFormat) - { - kernelString += string(" in += offset;\n"); - kernelString += string(" out += offset;\n"); - } - else - { - kernelString += string(" in_real += offset;\n"); - kernelString += string(" in_imag += offset;\n"); - kernelString += string(" out_real += offset;\n"); - kernelString += string(" out_imag += offset;\n"); - } - for(i = 0; i < R0; i++) - formattedLoad(kernelString, i, i*numWorkItemsPerXForm, dataFormat); - kernelString += string(" }\n"); - } - else - { - kernelString += string(" ii = lId;\n"); - kernelString += string(" jj = 0;\n"); - kernelString += string(" offset = mad24(groupId, ") + num2str(N) + string(", ii);\n"); - if(dataFormat == clFFT_InterleavedComplexFormat) - { - kernelString += string(" in += offset;\n"); - kernelString += string(" out += offset;\n"); - } - else - { - kernelString += string(" in_real += offset;\n"); - kernelString += string(" in_imag += offset;\n"); - kernelString += string(" out_real += offset;\n"); - kernelString += string(" out_imag += offset;\n"); - } - for(i = 0; i < R0; i++) - formattedLoad(kernelString, i, i*numWorkItemsPerXForm, dataFormat); - } - } - else if( N >= mem_coalesce_width ) - { - int numInnerIter = N / mem_coalesce_width; - int numOuterIter = numXFormsPerWG / ( groupSize / mem_coalesce_width ); - - kernelString += string(" ii = lId & ") + num2str(mem_coalesce_width - 1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str((int)log2(mem_coalesce_width)) + string(";\n"); - kernelString += string(" lMemStore = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - kernelString += string(" offset = mad24( groupId, ") + num2str(numXFormsPerWG) + string(", jj);\n"); - kernelString += string(" offset = mad24( offset, ") + num2str(N) + string(", ii );\n"); - if(dataFormat == clFFT_InterleavedComplexFormat) - { - kernelString += string(" in += offset;\n"); - kernelString += string(" out += offset;\n"); - } - else - { - kernelString += string(" in_real += offset;\n"); - kernelString += string(" in_imag += offset;\n"); - kernelString += string(" out_real += offset;\n"); - kernelString += string(" out_imag += offset;\n"); - } - - kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); - for(i = 0; i < numOuterIter; i++ ) - { - kernelString += string(" if( jj < s ) {\n"); - for(j = 0; j < numInnerIter; j++ ) - formattedLoad(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * ( groupSize / mem_coalesce_width ) * N, dataFormat); - kernelString += string(" }\n"); - if(i != numOuterIter - 1) - kernelString += string(" jj += ") + num2str(groupSize / mem_coalesce_width) + string(";\n"); - } - kernelString += string("}\n "); - kernelString += string("else {\n"); - for(i = 0; i < numOuterIter; i++ ) - { - for(j = 0; j < numInnerIter; j++ ) - formattedLoad(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * ( groupSize / mem_coalesce_width ) * N, dataFormat); - } - kernelString += string("}\n"); - - kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm - 1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); - kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii);\n"); - - for( i = 0; i < numOuterIter; i++ ) - { - for( j = 0; j < numInnerIter; j++ ) - { - kernelString += string(" lMemStore[") + num2str(j * mem_coalesce_width + i * ( groupSize / mem_coalesce_width ) * (N + numWorkItemsPerXForm )) + string("] = a[") + - num2str(i * numInnerIter + j) + string("].x;\n"); - } - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < R0; i++ ) - kernelString += string(" a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < numOuterIter; i++ ) - { - for( j = 0; j < numInnerIter; j++ ) - { - kernelString += string(" lMemStore[") + num2str(j * mem_coalesce_width + i * ( groupSize / mem_coalesce_width ) * (N + numWorkItemsPerXForm )) + string("] = a[") + - num2str(i * numInnerIter + j) + string("].y;\n"); - } - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < R0; i++ ) - kernelString += string(" a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; - } - else - { - kernelString += string(" offset = mad24( groupId, ") + num2str(N * numXFormsPerWG) + string(", lId );\n"); - if(dataFormat == clFFT_InterleavedComplexFormat) - { - kernelString += string(" in += offset;\n"); - kernelString += string(" out += offset;\n"); - } - else - { - kernelString += string(" in_real += offset;\n"); - kernelString += string(" in_imag += offset;\n"); - kernelString += string(" out_real += offset;\n"); - kernelString += string(" out_imag += offset;\n"); - } - - kernelString += string(" ii = lId & ") + num2str(N-1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str((int)log2(N)) + string(";\n"); - kernelString += string(" lMemStore = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - - kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); - for( i = 0; i < R0; i++ ) - { - kernelString += string(" if(jj < s )\n"); - formattedLoad(kernelString, i, i*groupSize, dataFormat); - if(i != R0 - 1) - kernelString += string(" jj += ") + num2str(groupSize / N) + string(";\n"); - } - kernelString += string("}\n"); - kernelString += string("else {\n"); - for( i = 0; i < R0; i++ ) - { - formattedLoad(kernelString, i, i*groupSize, dataFormat); - } - kernelString += string("}\n"); - - if(numWorkItemsPerXForm > 1) - { - kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm - 1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); - kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - } - else - { - kernelString += string(" ii = 0;\n"); - kernelString += string(" jj = lId;\n"); - kernelString += string(" lMemLoad = sMem + mul24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(");\n"); - } - - - for( i = 0; i < R0; i++ ) - kernelString += string(" lMemStore[") + num2str(i * ( groupSize / N ) * ( N + numWorkItemsPerXForm )) + string("] = a[") + num2str(i) + string("].x;\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < R0; i++ ) - kernelString += string(" a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < R0; i++ ) - kernelString += string(" lMemStore[") + num2str(i * ( groupSize / N ) * ( N + numWorkItemsPerXForm )) + string("] = a[") + num2str(i) + string("].y;\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < R0; i++ ) - kernelString += string(" a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; - } - - return lMemSize; -} - -static int -insertGlobalStoresAndTranspose(string &kernelString, int N, int maxRadix, int Nr, int numWorkItemsPerXForm, int numXFormsPerWG, int mem_coalesce_width, clFFT_DataFormat dataFormat) -{ - int groupSize = numWorkItemsPerXForm * numXFormsPerWG; - int i, j, k, ind; - int lMemSize = 0; - int numIter = maxRadix / Nr; - string indent = string(""); - - if( numWorkItemsPerXForm >= mem_coalesce_width ) - { - if(numXFormsPerWG > 1) - { - kernelString += string(" if( !s || (groupId < get_num_groups(0)-1) || (jj < s) ) {\n"); - indent = string(" "); - } - for(i = 0; i < maxRadix; i++) - { - j = i % numIter; - k = i / numIter; - ind = j * Nr + k; - formattedStore(kernelString, ind, i*numWorkItemsPerXForm, dataFormat); - } - if(numXFormsPerWG > 1) - kernelString += string(" }\n"); - } - else if( N >= mem_coalesce_width ) - { - int numInnerIter = N / mem_coalesce_width; - int numOuterIter = numXFormsPerWG / ( groupSize / mem_coalesce_width ); - - kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - kernelString += string(" ii = lId & ") + num2str(mem_coalesce_width - 1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str((int)log2(mem_coalesce_width)) + string(";\n"); - kernelString += string(" lMemStore = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - - for( i = 0; i < maxRadix; i++ ) - { - j = i % numIter; - k = i / numIter; - ind = j * Nr + k; - kernelString += string(" lMemLoad[") + num2str(i*numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].x;\n"); - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < numOuterIter; i++ ) - for( j = 0; j < numInnerIter; j++ ) - kernelString += string(" a[") + num2str(i*numInnerIter + j) + string("].x = lMemStore[") + num2str(j*mem_coalesce_width + i*( groupSize / mem_coalesce_width )*(N + numWorkItemsPerXForm)) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < maxRadix; i++ ) - { - j = i % numIter; - k = i / numIter; - ind = j * Nr + k; - kernelString += string(" lMemLoad[") + num2str(i*numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].y;\n"); - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < numOuterIter; i++ ) - for( j = 0; j < numInnerIter; j++ ) - kernelString += string(" a[") + num2str(i*numInnerIter + j) + string("].y = lMemStore[") + num2str(j*mem_coalesce_width + i*( groupSize / mem_coalesce_width )*(N + numWorkItemsPerXForm)) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); - for(i = 0; i < numOuterIter; i++ ) - { - kernelString += string(" if( jj < s ) {\n"); - for(j = 0; j < numInnerIter; j++ ) - formattedStore(kernelString, i*numInnerIter + j, j*mem_coalesce_width + i*(groupSize/mem_coalesce_width)*N, dataFormat); - kernelString += string(" }\n"); - if(i != numOuterIter - 1) - kernelString += string(" jj += ") + num2str(groupSize / mem_coalesce_width) + string(";\n"); - } - kernelString += string("}\n"); - kernelString += string("else {\n"); - for(i = 0; i < numOuterIter; i++ ) - { - for(j = 0; j < numInnerIter; j++ ) - formattedStore(kernelString, i*numInnerIter + j, j*mem_coalesce_width + i*(groupSize/mem_coalesce_width)*N, dataFormat); - } - kernelString += string("}\n"); - - lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; - } - else - { - kernelString += string(" lMemLoad = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - - kernelString += string(" ii = lId & ") + num2str(N - 1) + string(";\n"); - kernelString += string(" jj = lId >> ") + num2str((int) log2(N)) + string(";\n"); - kernelString += string(" lMemStore = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); - - for( i = 0; i < maxRadix; i++ ) - { - j = i % numIter; - k = i / numIter; - ind = j * Nr + k; - kernelString += string(" lMemLoad[") + num2str(i*numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].x;\n"); - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < maxRadix; i++ ) - kernelString += string(" a[") + num2str(i) + string("].x = lMemStore[") + num2str(i*( groupSize / N )*( N + numWorkItemsPerXForm )) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < maxRadix; i++ ) - { - j = i % numIter; - k = i / numIter; - ind = j * Nr + k; - kernelString += string(" lMemLoad[") + num2str(i*numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].y;\n"); - } - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - for( i = 0; i < maxRadix; i++ ) - kernelString += string(" a[") + num2str(i) + string("].y = lMemStore[") + num2str(i*( groupSize / N )*( N + numWorkItemsPerXForm )) + string("];\n"); - kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); - - kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); - for( i = 0; i < maxRadix; i++ ) - { - kernelString += string(" if(jj < s ) {\n"); - formattedStore(kernelString, i, i*groupSize, dataFormat); - kernelString += string(" }\n"); - if( i != maxRadix - 1) - kernelString += string(" jj +=") + num2str(groupSize / N) + string(";\n"); - } - kernelString += string("}\n"); - kernelString += string("else {\n"); - for( i = 0; i < maxRadix; i++ ) - { - formattedStore(kernelString, i, i*groupSize, dataFormat); - } - kernelString += string("}\n"); - - lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; - } - - return lMemSize; -} - -static void -insertfftKernel(string &kernelString, int Nr, int numIter) -{ - int i; - for(i = 0; i < numIter; i++) - { - kernelString += string(" fftKernel") + num2str(Nr) + string("(a+") + num2str(i*Nr) + string(", dir);\n"); - } -} - -static void -insertTwiddleKernel(string &kernelString, int Nr, int numIter, int Nprev, int len, int numWorkItemsPerXForm) -{ - int z, k; - int logNPrev = (int)log2(Nprev); - - for(z = 0; z < numIter; z++) - { - if(z == 0) - { - if(Nprev > 1) - kernelString += string(" angf = (float) (ii >> ") + num2str(logNPrev) + string(");\n"); - else - kernelString += string(" angf = (float) ii;\n"); - } - else - { - if(Nprev > 1) - kernelString += string(" angf = (float) ((") + num2str(z*numWorkItemsPerXForm) + string(" + ii) >>") + num2str(logNPrev) + string(");\n"); - else - kernelString += string(" angf = (float) (") + num2str(z*numWorkItemsPerXForm) + string(" + ii);\n"); - } - - for(k = 1; k < Nr; k++) { - int ind = z*Nr + k; - //float fac = (float) (2.0 * M_PI * (double) k / (double) len); - kernelString += string(" ang = dir * ( 2.0f * M_PI * ") + num2str(k) + string(".0f / ") + num2str(len) + string(".0f )") + string(" * angf;\n"); - kernelString += string(" w = (float2)(native_cos(ang), native_sin(ang));\n"); - kernelString += string(" a[") + num2str(ind) + string("] = complexMul(a[") + num2str(ind) + string("], w);\n"); - } - } -} - -static int -getPadding(int numWorkItemsPerXForm, int Nprev, int numWorkItemsReq, int numXFormsPerWG, int Nr, int numBanks, int *offset, int *midPad) -{ - if((numWorkItemsPerXForm <= Nprev) || (Nprev >= numBanks)) - *offset = 0; - else { - int numRowsReq = ((numWorkItemsPerXForm < numBanks) ? numWorkItemsPerXForm : numBanks) / Nprev; - int numColsReq = 1; - if(numRowsReq > Nr) - numColsReq = numRowsReq / Nr; - numColsReq = Nprev * numColsReq; - *offset = numColsReq; - } - - if(numWorkItemsPerXForm >= numBanks || numXFormsPerWG == 1) - *midPad = 0; - else { - int bankNum = ( (numWorkItemsReq + *offset) * Nr ) & (numBanks - 1); - if( bankNum >= numWorkItemsPerXForm ) - *midPad = 0; - else - *midPad = numWorkItemsPerXForm - bankNum; - } - - int lMemSize = ( numWorkItemsReq + *offset) * Nr * numXFormsPerWG + *midPad * (numXFormsPerWG - 1); - return lMemSize; -} - - -static void -insertLocalStores(string &kernelString, int numIter, int Nr, int numWorkItemsPerXForm, int numWorkItemsReq, int offset, string &comp) -{ - int z, k; - - for(z = 0; z < numIter; z++) { - for(k = 0; k < Nr; k++) { - int index = k*(numWorkItemsReq + offset) + z*numWorkItemsPerXForm; - kernelString += string(" lMemStore[") + num2str(index) + string("] = a[") + num2str(z*Nr + k) + string("].") + comp + string(";\n"); - } - } - kernelString += string(" barrier(CLK_LOCAL_MEM_FENCE);\n"); -} - -static void -insertLocalLoads(string &kernelString, int n, int Nr, int Nrn, int Nprev, int Ncurr, int numWorkItemsPerXForm, int numWorkItemsReq, int offset, string &comp) -{ - int numWorkItemsReqN = n / Nrn; - int interBlockHNum = max( Nprev / numWorkItemsPerXForm, 1 ); - int interBlockHStride = numWorkItemsPerXForm; - int vertWidth = max(numWorkItemsPerXForm / Nprev, 1); - vertWidth = min( vertWidth, Nr); - int vertNum = Nr / vertWidth; - int vertStride = ( n / Nr + offset ) * vertWidth; - int iter = max( numWorkItemsReqN / numWorkItemsPerXForm, 1); - int intraBlockHStride = (numWorkItemsPerXForm / (Nprev*Nr)) > 1 ? (numWorkItemsPerXForm / (Nprev*Nr)) : 1; - intraBlockHStride *= Nprev; - - int stride = numWorkItemsReq / Nrn; - int i; - for(i = 0; i < iter; i++) { - int ii = i / (interBlockHNum * vertNum); - int zz = i % (interBlockHNum * vertNum); - int jj = zz % interBlockHNum; - int kk = zz / interBlockHNum; - int z; - for(z = 0; z < Nrn; z++) { - int st = kk * vertStride + jj * interBlockHStride + ii * intraBlockHStride + z * stride; - kernelString += string(" a[") + num2str(i*Nrn + z) + string("].") + comp + string(" = lMemLoad[") + num2str(st) + string("];\n"); - } - } - kernelString += string(" barrier(CLK_LOCAL_MEM_FENCE);\n"); -} - -static void -insertLocalLoadIndexArithmatic(string &kernelString, int Nprev, int Nr, int numWorkItemsReq, int numWorkItemsPerXForm, int numXFormsPerWG, int offset, int midPad) -{ - int Ncurr = Nprev * Nr; - int logNcurr = (int)log2(Ncurr); - int logNprev = (int)log2(Nprev); - int incr = (numWorkItemsReq + offset) * Nr + midPad; - - if(Ncurr < numWorkItemsPerXForm) - { - if(Nprev == 1) - kernelString += string(" j = ii & ") + num2str(Ncurr - 1) + string(";\n"); - else - kernelString += string(" j = (ii & ") + num2str(Ncurr - 1) + string(") >> ") + num2str(logNprev) + string(";\n"); - - if(Nprev == 1) - kernelString += string(" i = ii >> ") + num2str(logNcurr) + string(";\n"); - else - kernelString += string(" i = mad24(ii >> ") + num2str(logNcurr) + string(", ") + num2str(Nprev) + string(", ii & ") + num2str(Nprev - 1) + string(");\n"); - } - else - { - if(Nprev == 1) - kernelString += string(" j = ii;\n"); - else - kernelString += string(" j = ii >> ") + num2str(logNprev) + string(";\n"); - if(Nprev == 1) - kernelString += string(" i = 0;\n"); - else - kernelString += string(" i = ii & ") + num2str(Nprev - 1) + string(";\n"); - } - - if(numXFormsPerWG > 1) - kernelString += string(" i = mad24(jj, ") + num2str(incr) + string(", i);\n"); - - kernelString += string(" lMemLoad = sMem + mad24(j, ") + num2str(numWorkItemsReq + offset) + string(", i);\n"); -} - -static void -insertLocalStoreIndexArithmatic(string &kernelString, int numWorkItemsReq, int numXFormsPerWG, int Nr, int offset, int midPad) -{ - if(numXFormsPerWG == 1) { - kernelString += string(" lMemStore = sMem + ii;\n"); - } - else { - kernelString += string(" lMemStore = sMem + mad24(jj, ") + num2str((numWorkItemsReq + offset)*Nr + midPad) + string(", ii);\n"); - } -} - - -static void -createLocalMemfftKernelString(cl_fft_plan *plan) -{ - unsigned int radixArray[10]; - unsigned int numRadix; - - unsigned int n = plan->n.x; - - assert(n <= plan->max_work_item_per_workgroup * plan->max_radix && "signal lenght too big for local mem fft\n"); - - getRadixArray(n, radixArray, &numRadix, 0); - assert(numRadix > 0 && "no radix array supplied\n"); - - if(n/radixArray[0] > plan->max_work_item_per_workgroup) - getRadixArray(n, radixArray, &numRadix, plan->max_radix); - - assert(radixArray[0] <= plan->max_radix && "max radix choosen is greater than allowed\n"); - assert(n/radixArray[0] <= plan->max_work_item_per_workgroup && "required work items per xform greater than maximum work items allowed per work group for local mem fft\n"); - - unsigned int tmpLen = 1; - unsigned int i; - for(i = 0; i < numRadix; i++) - { - assert( radixArray[i] && !( (radixArray[i] - 1) & radixArray[i] ) ); - tmpLen *= radixArray[i]; - } - assert(tmpLen == n && "product of radices choosen doesnt match the length of signal\n"); - - int offset, midPad; - string localString(""), kernelName(""); - - clFFT_DataFormat dataFormat = plan->format; - string *kernelString = plan->kernel_string; - - - cl_fft_kernel_info **kInfo = &plan->kernel_info; - int kCount = 0; - - while(*kInfo) - { - kInfo = &(*kInfo)->next; - kCount++; - } - - kernelName = string("fft") + num2str(kCount); - - *kInfo = (cl_fft_kernel_info *) malloc(sizeof(cl_fft_kernel_info)); - (*kInfo)->kernel = 0; - (*kInfo)->lmem_size = 0; - (*kInfo)->num_workgroups = 0; - (*kInfo)->num_workitems_per_workgroup = 0; - (*kInfo)->dir = cl_fft_kernel_x; - (*kInfo)->in_place_possible = 1; - (*kInfo)->next = NULL; - (*kInfo)->kernel_name = (char *) malloc(sizeof(char)*(kernelName.size()+1)); - strcpy((*kInfo)->kernel_name, kernelName.c_str()); - - unsigned int numWorkItemsPerXForm = n / radixArray[0]; - unsigned int numWorkItemsPerWG = numWorkItemsPerXForm <= 64 ? 64 : numWorkItemsPerXForm; - assert(numWorkItemsPerWG <= plan->max_work_item_per_workgroup); - int numXFormsPerWG = numWorkItemsPerWG / numWorkItemsPerXForm; - (*kInfo)->num_workgroups = 1; - (*kInfo)->num_xforms_per_workgroup = numXFormsPerWG; - (*kInfo)->num_workitems_per_workgroup = numWorkItemsPerWG; - - unsigned int *N = radixArray; - unsigned int maxRadix = N[0]; - unsigned int lMemSize = 0; - - insertVariables(localString, maxRadix); - - lMemSize = insertGlobalLoadsAndTranspose(localString, n, numWorkItemsPerXForm, numXFormsPerWG, maxRadix, plan->min_mem_coalesce_width, dataFormat); - (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; - - string xcomp = string("x"); - string ycomp = string("y"); - - unsigned int Nprev = 1; - unsigned int len = n; - unsigned int r; - for(r = 0; r < numRadix; r++) - { - int numIter = N[0] / N[r]; - int numWorkItemsReq = n / N[r]; - int Ncurr = Nprev * N[r]; - insertfftKernel(localString, N[r], numIter); - - if(r < (numRadix - 1)) { - insertTwiddleKernel(localString, N[r], numIter, Nprev, len, numWorkItemsPerXForm); - lMemSize = getPadding(numWorkItemsPerXForm, Nprev, numWorkItemsReq, numXFormsPerWG, N[r], plan->num_local_mem_banks, &offset, &midPad); - (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; - insertLocalStoreIndexArithmatic(localString, numWorkItemsReq, numXFormsPerWG, N[r], offset, midPad); - insertLocalLoadIndexArithmatic(localString, Nprev, N[r], numWorkItemsReq, numWorkItemsPerXForm, numXFormsPerWG, offset, midPad); - insertLocalStores(localString, numIter, N[r], numWorkItemsPerXForm, numWorkItemsReq, offset, xcomp); - insertLocalLoads(localString, n, N[r], N[r+1], Nprev, Ncurr, numWorkItemsPerXForm, numWorkItemsReq, offset, xcomp); - insertLocalStores(localString, numIter, N[r], numWorkItemsPerXForm, numWorkItemsReq, offset, ycomp); - insertLocalLoads(localString, n, N[r], N[r+1], Nprev, Ncurr, numWorkItemsPerXForm, numWorkItemsReq, offset, ycomp); - Nprev = Ncurr; - len = len / N[r]; - } - } - - lMemSize = insertGlobalStoresAndTranspose(localString, n, maxRadix, N[numRadix - 1], numWorkItemsPerXForm, numXFormsPerWG, plan->min_mem_coalesce_width, dataFormat); - (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; - - insertHeader(*kernelString, kernelName, dataFormat); - *kernelString += string("{\n"); - if((*kInfo)->lmem_size) - *kernelString += string(" __local float sMem[") + num2str((*kInfo)->lmem_size) + string("];\n"); - *kernelString += localString; - *kernelString += string("}\n"); -} - -// For n larger than what can be computed using local memory fft, global transposes -// multiple kernel launces is needed. For these sizes, n can be decomposed using -// much larger base radices i.e. say n = 262144 = 128 x 64 x 32. Thus three kernel -// launches will be needed, first computing 64 x 32, length 128 ffts, second computing -// 128 x 32 length 64 ffts, and finally a kernel computing 128 x 64 length 32 ffts. -// Each of these base radices can futher be divided into factors so that each of these -// base ffts can be computed within one kernel launch using in-register ffts and local -// memory transposes i.e for the first kernel above which computes 64 x 32 ffts on length -// 128, 128 can be decomposed into 128 = 16 x 8 i.e. 8 work items can compute 8 length -// 16 ffts followed by transpose using local memory followed by each of these eight -// work items computing 2 length 8 ffts thus computing 16 length 8 ffts in total. This -// means only 8 work items are needed for computing one length 128 fft. If we choose -// work group size of say 64, we can compute 64/8 = 8 length 128 ffts within one -// work group. Since we need to compute 64 x 32 length 128 ffts in first kernel, this -// means we need to launch 64 x 32 / 8 = 256 work groups with 64 work items in each -// work group where each work group is computing 8 length 128 ffts where each length -// 128 fft is computed by 8 work items. Same logic can be applied to other two kernels -// in this example. Users can play with difference base radices and difference -// decompositions of base radices to generates different kernels and see which gives -// best performance. Following function is just fixed to use 128 as base radix - -void -getGlobalRadixInfo(int n, int *radix, int *R1, int *R2, int *numRadices) -{ - int baseRadix = min(n, 128); - - int numR = 0; - int N = n; - while(N > baseRadix) - { - N /= baseRadix; - numR++; - } - - for(int i = 0; i < numR; i++) - radix[i] = baseRadix; - - radix[numR] = N; - numR++; - *numRadices = numR; - - for(int i = 0; i < numR; i++) - { - int B = radix[i]; - if(B <= 8) - { - R1[i] = B; - R2[i] = 1; - continue; - } - - int r1 = 2; - int r2 = B / r1; - while(r2 > r1) - { - r1 *=2; - r2 = B / r1; - } - R1[i] = r1; - R2[i] = r2; - } -} - -static void -createGlobalFFTKernelString(cl_fft_plan *plan, int n, int BS, cl_fft_kernel_dir dir, int vertBS) -{ - int i, j, k, t; - int radixArr[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int R1Arr[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int R2Arr[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int radix, R1, R2; - int numRadices; - - int maxThreadsPerBlock = plan->max_work_item_per_workgroup; - int maxArrayLen = plan->max_radix; - int batchSize = plan->min_mem_coalesce_width; - clFFT_DataFormat dataFormat = plan->format; - int vertical = (dir == cl_fft_kernel_x) ? 0 : 1; - - getGlobalRadixInfo(n, radixArr, R1Arr, R2Arr, &numRadices); - - int numPasses = numRadices; - - string localString(""), kernelName(""); - string *kernelString = plan->kernel_string; - cl_fft_kernel_info **kInfo = &plan->kernel_info; - int kCount = 0; - - while(*kInfo) - { - kInfo = &(*kInfo)->next; - kCount++; - } - - int N = n; - int m = (int)log2(n); - int Rinit = vertical ? BS : 1; - batchSize = vertical ? min(BS, batchSize) : batchSize; - int passNum; - - for(passNum = 0; passNum < numPasses; passNum++) - { - - localString.clear(); - kernelName.clear(); - - radix = radixArr[passNum]; - R1 = R1Arr[passNum]; - R2 = R2Arr[passNum]; - - int strideI = Rinit; - for(i = 0; i < numPasses; i++) - if(i != passNum) - strideI *= radixArr[i]; - - int strideO = Rinit; - for(i = 0; i < passNum; i++) - strideO *= radixArr[i]; - - int threadsPerXForm = R2; - batchSize = R2 == 1 ? plan->max_work_item_per_workgroup : batchSize; - batchSize = min(batchSize, strideI); - int threadsPerBlock = batchSize * threadsPerXForm; - threadsPerBlock = min(threadsPerBlock, maxThreadsPerBlock); - batchSize = threadsPerBlock / threadsPerXForm; - assert(R2 <= R1); - assert(R1*R2 == radix); - assert(R1 <= maxArrayLen); - assert(threadsPerBlock <= maxThreadsPerBlock); - - int numIter = R1 / R2; - int gInInc = threadsPerBlock / batchSize; - - - int lgStrideO = (int)log2(strideO); - int numBlocksPerXForm = strideI / batchSize; - int numBlocks = numBlocksPerXForm; - if(!vertical) - numBlocks *= BS; - else - numBlocks *= vertBS; - - kernelName = string("fft") + num2str(kCount); - *kInfo = (cl_fft_kernel_info *) malloc(sizeof(cl_fft_kernel_info)); - (*kInfo)->kernel = 0; - if(R2 == 1) - (*kInfo)->lmem_size = 0; - else - { - if(strideO == 1) - (*kInfo)->lmem_size = (radix + 1)*batchSize; - else - (*kInfo)->lmem_size = threadsPerBlock*R1; - } - (*kInfo)->num_workgroups = numBlocks; - (*kInfo)->num_xforms_per_workgroup = 1; - (*kInfo)->num_workitems_per_workgroup = threadsPerBlock; - (*kInfo)->dir = dir; - if( (passNum == (numPasses - 1)) && (numPasses & 1) ) - (*kInfo)->in_place_possible = 1; - else - (*kInfo)->in_place_possible = 0; - (*kInfo)->next = NULL; - (*kInfo)->kernel_name = (char *) malloc(sizeof(char)*(kernelName.size()+1)); - strcpy((*kInfo)->kernel_name, kernelName.c_str()); - - insertVariables(localString, R1); - - if(vertical) - { - localString += string("xNum = groupId >> ") + num2str((int)log2(numBlocksPerXForm)) + string(";\n"); - localString += string("groupId = groupId & ") + num2str(numBlocksPerXForm - 1) + string(";\n"); - localString += string("indexIn = mad24(groupId, ") + num2str(batchSize) + string(", xNum << ") + num2str((int)log2(n*BS)) + string(");\n"); - localString += string("tid = mul24(groupId, ") + num2str(batchSize) + string(");\n"); - localString += string("i = tid >> ") + num2str(lgStrideO) + string(";\n"); - localString += string("j = tid & ") + num2str(strideO - 1) + string(";\n"); - int stride = radix*Rinit; - for(i = 0; i < passNum; i++) - stride *= radixArr[i]; - localString += string("indexOut = mad24(i, ") + num2str(stride) + string(", j + ") + string("(xNum << ") + num2str((int) log2(n*BS)) + string("));\n"); - localString += string("bNum = groupId;\n"); - } - else - { - int lgNumBlocksPerXForm = (int)log2(numBlocksPerXForm); - localString += string("bNum = groupId & ") + num2str(numBlocksPerXForm - 1) + string(";\n"); - localString += string("xNum = groupId >> ") + num2str(lgNumBlocksPerXForm) + string(";\n"); - localString += string("indexIn = mul24(bNum, ") + num2str(batchSize) + string(");\n"); - localString += string("tid = indexIn;\n"); - localString += string("i = tid >> ") + num2str(lgStrideO) + string(";\n"); - localString += string("j = tid & ") + num2str(strideO - 1) + string(";\n"); - int stride = radix*Rinit; - for(i = 0; i < passNum; i++) - stride *= radixArr[i]; - localString += string("indexOut = mad24(i, ") + num2str(stride) + string(", j);\n"); - localString += string("indexIn += (xNum << ") + num2str(m) + string(");\n"); - localString += string("indexOut += (xNum << ") + num2str(m) + string(");\n"); - } - - // Load Data - int lgBatchSize = (int)log2(batchSize); - localString += string("tid = lId;\n"); - localString += string("i = tid & ") + num2str(batchSize - 1) + string(";\n"); - localString += string("j = tid >> ") + num2str(lgBatchSize) + string(";\n"); - localString += string("indexIn += mad24(j, ") + num2str(strideI) + string(", i);\n"); - - if(dataFormat == clFFT_SplitComplexFormat) - { - localString += string("in_real += indexIn;\n"); - localString += string("in_imag += indexIn;\n"); - for(j = 0; j < R1; j++) - localString += string("a[") + num2str(j) + string("].x = in_real[") + num2str(j*gInInc*strideI) + string("];\n"); - for(j = 0; j < R1; j++) - localString += string("a[") + num2str(j) + string("].y = in_imag[") + num2str(j*gInInc*strideI) + string("];\n"); - } - else - { - localString += string("in += indexIn;\n"); - for(j = 0; j < R1; j++) - localString += string("a[") + num2str(j) + string("] = in[") + num2str(j*gInInc*strideI) + string("];\n"); - } - - localString += string("fftKernel") + num2str(R1) + string("(a, dir);\n"); - - if(R2 > 1) - { - // twiddle - for(k = 1; k < R1; k++) - { - localString += string("ang = dir*(2.0f*M_PI*") + num2str(k) + string("/") + num2str(radix) + string(")*j;\n"); - localString += string("w = (float2)(native_cos(ang), native_sin(ang));\n"); - localString += string("a[") + num2str(k) + string("] = complexMul(a[") + num2str(k) + string("], w);\n"); - } - - // shuffle - numIter = R1 / R2; - localString += string("indexIn = mad24(j, ") + num2str(threadsPerBlock*numIter) + string(", i);\n"); - localString += string("lMemStore = sMem + tid;\n"); - localString += string("lMemLoad = sMem + indexIn;\n"); - for(k = 0; k < R1; k++) - localString += string("lMemStore[") + num2str(k*threadsPerBlock) + string("] = a[") + num2str(k) + string("].x;\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - for(k = 0; k < numIter; k++) - for(t = 0; t < R2; t++) - localString += string("a[") + num2str(k*R2+t) + string("].x = lMemLoad[") + num2str(t*batchSize + k*threadsPerBlock) + string("];\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - for(k = 0; k < R1; k++) - localString += string("lMemStore[") + num2str(k*threadsPerBlock) + string("] = a[") + num2str(k) + string("].y;\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - for(k = 0; k < numIter; k++) - for(t = 0; t < R2; t++) - localString += string("a[") + num2str(k*R2+t) + string("].y = lMemLoad[") + num2str(t*batchSize + k*threadsPerBlock) + string("];\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - - for(j = 0; j < numIter; j++) - localString += string("fftKernel") + num2str(R2) + string("(a + ") + num2str(j*R2) + string(", dir);\n"); - } - - // twiddle - if(passNum < (numPasses - 1)) - { - localString += string("l = ((bNum << ") + num2str(lgBatchSize) + string(") + i) >> ") + num2str(lgStrideO) + string(";\n"); - localString += string("k = j << ") + num2str((int)log2(R1/R2)) + string(";\n"); - localString += string("ang1 = dir*(2.0f*M_PI/") + num2str(N) + string(")*l;\n"); - for(t = 0; t < R1; t++) - { - localString += string("ang = ang1*(k + ") + num2str((t%R2)*R1 + (t/R2)) + string(");\n"); - localString += string("w = (float2)(native_cos(ang), native_sin(ang));\n"); - localString += string("a[") + num2str(t) + string("] = complexMul(a[") + num2str(t) + string("], w);\n"); - } - } - - // Store Data - if(strideO == 1) - { - - localString += string("lMemStore = sMem + mad24(i, ") + num2str(radix + 1) + string(", j << ") + num2str((int)log2(R1/R2)) + string(");\n"); - localString += string("lMemLoad = sMem + mad24(tid >> ") + num2str((int)log2(radix)) + string(", ") + num2str(radix+1) + string(", tid & ") + num2str(radix-1) + string(");\n"); - - for(i = 0; i < R1/R2; i++) - for(j = 0; j < R2; j++) - localString += string("lMemStore[ ") + num2str(i + j*R1) + string("] = a[") + num2str(i*R2+j) + string("].x;\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - if(threadsPerBlock >= radix) - { - for(i = 0; i < R1; i++) - localString += string("a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i*(radix+1)*(threadsPerBlock/radix)) + string("];\n"); - } - else - { - int innerIter = radix/threadsPerBlock; - int outerIter = R1/innerIter; - for(i = 0; i < outerIter; i++) - for(j = 0; j < innerIter; j++) - localString += string("a[") + num2str(i*innerIter+j) + string("].x = lMemLoad[") + num2str(j*threadsPerBlock + i*(radix+1)) + string("];\n"); - } - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - - for(i = 0; i < R1/R2; i++) - for(j = 0; j < R2; j++) - localString += string("lMemStore[ ") + num2str(i + j*R1) + string("] = a[") + num2str(i*R2+j) + string("].y;\n"); - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - if(threadsPerBlock >= radix) - { - for(i = 0; i < R1; i++) - localString += string("a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i*(radix+1)*(threadsPerBlock/radix)) + string("];\n"); - } - else - { - int innerIter = radix/threadsPerBlock; - int outerIter = R1/innerIter; - for(i = 0; i < outerIter; i++) - for(j = 0; j < innerIter; j++) - localString += string("a[") + num2str(i*innerIter+j) + string("].y = lMemLoad[") + num2str(j*threadsPerBlock + i*(radix+1)) + string("];\n"); - } - localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); - - localString += string("indexOut += tid;\n"); - if(dataFormat == clFFT_SplitComplexFormat) { - localString += string("out_real += indexOut;\n"); - localString += string("out_imag += indexOut;\n"); - for(k = 0; k < R1; k++) - localString += string("out_real[") + num2str(k*threadsPerBlock) + string("] = a[") + num2str(k) + string("].x;\n"); - for(k = 0; k < R1; k++) - localString += string("out_imag[") + num2str(k*threadsPerBlock) + string("] = a[") + num2str(k) + string("].y;\n"); - } - else { - localString += string("out += indexOut;\n"); - for(k = 0; k < R1; k++) - localString += string("out[") + num2str(k*threadsPerBlock) + string("] = a[") + num2str(k) + string("];\n"); - } - - } - else - { - localString += string("indexOut += mad24(j, ") + num2str(numIter*strideO) + string(", i);\n"); - if(dataFormat == clFFT_SplitComplexFormat) { - localString += string("out_real += indexOut;\n"); - localString += string("out_imag += indexOut;\n"); - for(k = 0; k < R1; k++) - localString += string("out_real[") + num2str(((k%R2)*R1 + (k/R2))*strideO) + string("] = a[") + num2str(k) + string("].x;\n"); - for(k = 0; k < R1; k++) - localString += string("out_imag[") + num2str(((k%R2)*R1 + (k/R2))*strideO) + string("] = a[") + num2str(k) + string("].y;\n"); - } - else { - localString += string("out += indexOut;\n"); - for(k = 0; k < R1; k++) - localString += string("out[") + num2str(((k%R2)*R1 + (k/R2))*strideO) + string("] = a[") + num2str(k) + string("];\n"); - } - } - - insertHeader(*kernelString, kernelName, dataFormat); - *kernelString += string("{\n"); - if((*kInfo)->lmem_size) - *kernelString += string(" __local float sMem[") + num2str((*kInfo)->lmem_size) + string("];\n"); - *kernelString += localString; - *kernelString += string("}\n"); - - N /= radix; - kInfo = &(*kInfo)->next; - kCount++; - } -} - -void FFT1D(cl_fft_plan *plan, cl_fft_kernel_dir dir) -{ - unsigned int radixArray[10]; - unsigned int numRadix; - - switch(dir) - { - case cl_fft_kernel_x: - if(plan->n.x > plan->max_localmem_fft_size) - { - createGlobalFFTKernelString(plan, plan->n.x, 1, cl_fft_kernel_x, 1); - } - else if(plan->n.x > 1) - { - getRadixArray(plan->n.x, radixArray, &numRadix, 0); - if(plan->n.x / radixArray[0] <= plan->max_work_item_per_workgroup) - { - createLocalMemfftKernelString(plan); - } - else - { - getRadixArray(plan->n.x, radixArray, &numRadix, plan->max_radix); - if(plan->n.x / radixArray[0] <= plan->max_work_item_per_workgroup) - createLocalMemfftKernelString(plan); - else - createGlobalFFTKernelString(plan, plan->n.x, 1, cl_fft_kernel_x, 1); - } - } - break; - - case cl_fft_kernel_y: - if(plan->n.y > 1) - createGlobalFFTKernelString(plan, plan->n.y, plan->n.x, cl_fft_kernel_y, 1); - break; - - case cl_fft_kernel_z: - if(plan->n.z > 1) - createGlobalFFTKernelString(plan, plan->n.z, plan->n.x*plan->n.y, cl_fft_kernel_z, 1); - default: - return; - } -} - diff --git a/src/algorithms/libs/fft_setup.cc b/src/algorithms/libs/fft_setup.cc deleted file mode 100644 index 6d2025d66..000000000 --- a/src/algorithms/libs/fft_setup.cc +++ /dev/null @@ -1,402 +0,0 @@ - -// -// File: fft_setup.cpp -// -// Version: <1.0> -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") -// in consideration of your agreement to the following terms, and your use, -// installation, modification or redistribution of this Apple software -// constitutes acceptance of these terms. If you do not agree with these -// terms, please do not use, install, modify or redistribute this Apple -// software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non - exclusive -// license, under Apple's copyrights in this original Apple software ( the -// "Apple Software" ), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and / or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following text -// and disclaimers in all such redistributions of the Apple Software. Neither -// the name, trademarks, service marks or logos of Apple Inc. may be used to -// endorse or promote products derived from the Apple Software without specific -// prior written permission from Apple. Except as expressly stated in this -// notice, no other rights or licenses, express or implied, are granted by -// Apple herein, including but not limited to any patent rights that may be -// infringed by your derivative works or by other works in which the Apple -// Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION -// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION -// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER -// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR -// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -#include "fft_internal.h" -#include "fft_base_kernels.h" -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -extern void getKernelWorkDimensions(cl_fft_plan *plan, cl_fft_kernel_info *kernelInfo, cl_int *batchSize, size_t *gWorkItems, size_t *lWorkItems); - -static void -getBlockConfigAndKernelString(cl_fft_plan *plan) -{ - plan->temp_buffer_needed = 0; - *plan->kernel_string += baseKernels; - - if(plan->format == clFFT_SplitComplexFormat) - *plan->kernel_string += twistKernelPlannar; - else - *plan->kernel_string += twistKernelInterleaved; - - switch(plan->dim) - { - case clFFT_1D: - FFT1D(plan, cl_fft_kernel_x); - break; - - case clFFT_2D: - FFT1D(plan, cl_fft_kernel_x); - FFT1D(plan, cl_fft_kernel_y); - break; - - case clFFT_3D: - FFT1D(plan, cl_fft_kernel_x); - FFT1D(plan, cl_fft_kernel_y); - FFT1D(plan, cl_fft_kernel_z); - break; - - default: - return; - } - - plan->temp_buffer_needed = 0; - cl_fft_kernel_info *kInfo = plan->kernel_info; - while(kInfo) - { - plan->temp_buffer_needed |= !kInfo->in_place_possible; - kInfo = kInfo->next; - } -} - - -static void -deleteKernelInfo(cl_fft_kernel_info *kInfo) -{ - if(kInfo) - { - if(kInfo->kernel_name) - free(kInfo->kernel_name); - if(kInfo->kernel) - clReleaseKernel(kInfo->kernel); - free(kInfo); - } -} - -static void -destroy_plan(cl_fft_plan *Plan) -{ - cl_fft_kernel_info *kernel_info = Plan->kernel_info; - - while(kernel_info) - { - cl_fft_kernel_info *tmp = kernel_info->next; - deleteKernelInfo(kernel_info); - kernel_info = tmp; - } - - Plan->kernel_info = NULL; - - if(Plan->kernel_string) - { - delete Plan->kernel_string; - Plan->kernel_string = NULL; - } - if(Plan->twist_kernel) - { - clReleaseKernel(Plan->twist_kernel); - Plan->twist_kernel = NULL; - } - if(Plan->program) - { - clReleaseProgram(Plan->program); - Plan->program = NULL; - } - if(Plan->tempmemobj) - { - clReleaseMemObject(Plan->tempmemobj); - Plan->tempmemobj = NULL; - } - if(Plan->tempmemobj_real) - { - clReleaseMemObject(Plan->tempmemobj_real); - Plan->tempmemobj_real = NULL; - } - if(Plan->tempmemobj_imag) - { - clReleaseMemObject(Plan->tempmemobj_imag); - Plan->tempmemobj_imag = NULL; - } -} - -static int -createKernelList(cl_fft_plan *plan) -{ - cl_program program = plan->program; - cl_fft_kernel_info *kernel_info = plan->kernel_info; - - cl_int err; - while(kernel_info) - { - kernel_info->kernel = clCreateKernel(program, kernel_info->kernel_name, &err); - if(!kernel_info->kernel || err != CL_SUCCESS) - return err; - kernel_info = kernel_info->next; - } - - if(plan->format == clFFT_SplitComplexFormat) - plan->twist_kernel = clCreateKernel(program, "clFFT_1DTwistSplit", &err); - else - plan->twist_kernel = clCreateKernel(program, "clFFT_1DTwistInterleaved", &err); - - if(!plan->twist_kernel || err) - return err; - - return CL_SUCCESS; -} - -int getMaxKernelWorkGroupSize(cl_fft_plan *plan, unsigned int *max_wg_size, unsigned int num_devices, cl_device_id *devices) -{ - int reg_needed = 0; - *max_wg_size = std::numeric_limits::max(); - int err; - unsigned wg_size; - - unsigned int i; - for(i = 0; i < num_devices; i++) - { - cl_fft_kernel_info *kInfo = plan->kernel_info; - while(kInfo) - { - err = clGetKernelWorkGroupInfo(kInfo->kernel, devices[i], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &wg_size, NULL); - if(err != CL_SUCCESS) - return -1; - - if(wg_size < kInfo->num_workitems_per_workgroup) - reg_needed |= 1; - - if(*max_wg_size > wg_size) - *max_wg_size = wg_size; - - kInfo = kInfo->next; - } - } - - return reg_needed; -} - -#define ERR_MACRO(err) { \ - if( err != CL_SUCCESS) \ - { \ - if(error_code) \ - *error_code = err; \ - clFFT_DestroyPlan((clFFT_Plan) plan); \ - return (clFFT_Plan) NULL; \ - } \ - } - -clFFT_Plan -clFFT_CreatePlan(cl_context context, clFFT_Dim3 n, clFFT_Dimension dim, clFFT_DataFormat dataFormat, cl_int *error_code ) -{ - int i; - cl_int err; - int isPow2 = 1; - cl_fft_plan *plan = NULL; - ostringstream kString; - int num_devices; - int gpu_found = 0; - cl_device_id devices[16]; - size_t ret_size; - cl_device_type device_type; - - if(!context) - ERR_MACRO(CL_INVALID_VALUE); - - isPow2 |= n.x && !( (n.x - 1) & n.x ); - isPow2 |= n.y && !( (n.y - 1) & n.y ); - isPow2 |= n.z && !( (n.z - 1) & n.z ); - - if(!isPow2) - ERR_MACRO(CL_INVALID_VALUE); - - if( (dim == clFFT_1D && (n.y != 1 || n.z != 1)) || (dim == clFFT_2D && n.z != 1) ) - ERR_MACRO(CL_INVALID_VALUE); - - plan = (cl_fft_plan *) malloc(sizeof(cl_fft_plan)); - if(!plan) - ERR_MACRO(CL_OUT_OF_RESOURCES); - - plan->context = context; - clRetainContext(context); - plan->n = n; - plan->dim = dim; - plan->format = dataFormat; - plan->kernel_info = 0; - plan->num_kernels = 0; - plan->twist_kernel = 0; - plan->program = 0; - plan->temp_buffer_needed = 0; - plan->last_batch_size = 0; - plan->tempmemobj = 0; - plan->tempmemobj_real = 0; - plan->tempmemobj_imag = 0; - plan->max_localmem_fft_size = 2048; - plan->max_work_item_per_workgroup = 256; - plan->max_radix = 16; - plan->min_mem_coalesce_width = 16; - plan->num_local_mem_banks = 16; - -patch_kernel_source: - - plan->kernel_string = new string(""); - if(!plan->kernel_string) - ERR_MACRO(CL_OUT_OF_RESOURCES); - - getBlockConfigAndKernelString(plan); - - const char *source_str = plan->kernel_string->c_str(); - plan->program = clCreateProgramWithSource(context, 1, (const char**) &source_str, NULL, &err); - ERR_MACRO(err); - - err = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices), devices, &ret_size); - ERR_MACRO(err); - - num_devices = (int)(ret_size / sizeof(cl_device_id)); - - for(i = 0; i < num_devices; i++) - { - err = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(device_type), &device_type, NULL); - ERR_MACRO(err); - - if(device_type == CL_DEVICE_TYPE_GPU) - { - gpu_found = 1; - err = clBuildProgram(plan->program, 1, &devices[i], "-cl-mad-enable", NULL, NULL); - if (err != CL_SUCCESS) - { - char *build_log; - char devicename[200]; - size_t log_size; - - err = clGetProgramBuildInfo(plan->program, devices[i], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); - ERR_MACRO(err); - - build_log = (char *) malloc(log_size + 1); - - err = clGetProgramBuildInfo(plan->program, devices[i], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL); - ERR_MACRO(err); - - err = clGetDeviceInfo(devices[i], CL_DEVICE_NAME, sizeof(devicename), devicename, NULL); - ERR_MACRO(err); - - fprintf(stdout, "FFT program build log on device %s\n", devicename); - fprintf(stdout, "%s\n", build_log); - free(build_log); - - ERR_MACRO(err); - } - } - } - - if(!gpu_found) - ERR_MACRO(CL_INVALID_CONTEXT); - - err = createKernelList(plan); - ERR_MACRO(err); - - // we created program and kernels based on "some max work group size (default 256)" ... this work group size - // may be larger than what kernel may execute with ... if thats the case we need to regenerate the kernel source - // setting this as limit i.e max group size and rebuild. - unsigned int max_kernel_wg_size; - int patching_req = getMaxKernelWorkGroupSize(plan, &max_kernel_wg_size, num_devices, devices); - if(patching_req == -1) - { - ERR_MACRO(err); - } - - if(patching_req) - { - destroy_plan(plan); - plan->max_work_item_per_workgroup = max_kernel_wg_size; - goto patch_kernel_source; - } - - cl_fft_kernel_info *kInfo = plan->kernel_info; - while(kInfo) - { - plan->num_kernels++; - kInfo = kInfo->next; - } - - if(error_code) - *error_code = CL_SUCCESS; - - return (clFFT_Plan) plan; -} - -void -clFFT_DestroyPlan(clFFT_Plan plan) -{ - cl_fft_plan *Plan = (cl_fft_plan *) plan; - if(Plan) - { - destroy_plan(Plan); - clReleaseContext(Plan->context); - free(Plan); - } -} - -void clFFT_DumpPlan( clFFT_Plan Plan, FILE *file) -{ - size_t gDim, lDim; - FILE *out; - if(!file) - out = stdout; - else - out = file; - - cl_fft_plan *plan = (cl_fft_plan *) Plan; - cl_fft_kernel_info *kInfo = plan->kernel_info; - - while(kInfo) - { - cl_int s = 1; - getKernelWorkDimensions(plan, kInfo, &s, &gDim, &lDim); - fprintf(out, "Run kernel %s with global dim = {%zd*BatchSize}, local dim={%zd}\n", kInfo->kernel_name, gDim, lDim); - kInfo = kInfo->next; - } - fprintf(out, "%s\n", plan->kernel_string->c_str()); -} diff --git a/src/algorithms/libs/galileo_e1_signal_processing.cc b/src/algorithms/libs/galileo_e1_signal_processing.cc index 93fef2f50..23a8d9a94 100644 --- a/src/algorithms/libs/galileo_e1_signal_processing.cc +++ b/src/algorithms/libs/galileo_e1_signal_processing.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,24 +25,25 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_signal_processing.h" -#include #include "Galileo_E1.h" #include "gnss_signal_processing.h" +#include +#include -void galileo_e1_code_gen_int(int* _dest, char _Signal[3], signed int _prn) +void galileo_e1_code_gen_int(int* _dest, char _Signal[3], int32_t _prn) { std::string _galileo_signal = _Signal; - signed int prn = _prn - 1; - int index = 0; + int32_t prn = _prn - 1; + int32_t index = 0; - /* A simple error check */ + // A simple error check if ((_prn < 1) || (_prn > 50)) { return; @@ -50,179 +51,219 @@ void galileo_e1_code_gen_int(int* _dest, char _Signal[3], signed int _prn) if (_galileo_signal.rfind("1B") != std::string::npos && _galileo_signal.length() >= 2) { - for (size_t i = 0; i < Galileo_E1_B_PRIMARY_CODE[prn].length(); i++) + for (char i : Galileo_E1_B_PRIMARY_CODE[prn]) { - hex_to_binary_converter(&_dest[index], Galileo_E1_B_PRIMARY_CODE[prn].at(i)); - index = index + 4; + hex_to_binary_converter(&_dest[index], i); + index += 4; } - } else if (_galileo_signal.rfind("1C") != std::string::npos && _galileo_signal.length() >= 2) { - for (size_t i = 0; i < Galileo_E1_C_PRIMARY_CODE[prn].length(); i++) + for (char i : Galileo_E1_C_PRIMARY_CODE[prn]) { - hex_to_binary_converter(&_dest[index], Galileo_E1_C_PRIMARY_CODE[prn].at(i)); - index = index + 4; + hex_to_binary_converter(&_dest[index], i); + index += 4; } } - else - { - return; - } } - -void galileo_e1_sinboc_11_gen(std::complex* _dest, int* _prn, unsigned int _length_out) +void galileo_e1_sinboc_11_gen_int(int* _dest, const int* _prn, uint32_t _length_out) { - const unsigned int _length_in = Galileo_E1_B_CODE_LENGTH_CHIPS; - unsigned int _period = static_cast( _length_out / _length_in ); - for (unsigned int i = 0; i < _length_in; i++) + const uint32_t _length_in = Galileo_E1_B_CODE_LENGTH_CHIPS; + auto _period = static_cast(_length_out / _length_in); + for (uint32_t i = 0; i < _length_in; i++) { - for (unsigned int j = 0; j < (_period / 2); j++) + for (uint32_t j = 0; j < (_period / 2); j++) { - _dest[i * _period + j] = std::complex(static_cast(_prn[i]), 0.0); + _dest[i * _period + j] = _prn[i]; } - for (unsigned int j = (_period / 2); j < _period; j++) + for (uint32_t j = (_period / 2); j < _period; j++) { - _dest[i * _period + j] = std::complex(static_cast(- _prn[i]), 0.0); + _dest[i * _period + j] = -_prn[i]; } } } - -void galileo_e1_sinboc_61_gen(std::complex* _dest, int* _prn, unsigned int _length_out) +void galileo_e1_sinboc_61_gen_int(int* _dest, const int* _prn, uint32_t _length_out) { - const unsigned int _length_in = Galileo_E1_B_CODE_LENGTH_CHIPS; - unsigned int _period = static_cast(_length_out / _length_in); + const uint32_t _length_in = Galileo_E1_B_CODE_LENGTH_CHIPS; + auto _period = static_cast(_length_out / _length_in); - for (unsigned int i = 0; i < _length_in; i++) + for (uint32_t i = 0; i < _length_in; i++) { - for (unsigned int j = 0; j < _period; j += 2) + for (uint32_t j = 0; j < _period; j += 2) { - _dest[i * _period + j] = std::complex(static_cast(_prn[i]), 0.0); + _dest[i * _period + j] = _prn[i]; } - for (unsigned int j = 1; j < _period; j += 2) + for (uint32_t j = 1; j < _period; j += 2) { - _dest[i * _period + j] = std::complex(static_cast(- _prn[i]), 0.0); + _dest[i * _period + j] = -_prn[i]; } } } - -void galileo_e1_gen(std::complex* _dest, int* _prn, char _Signal[3]) +void galileo_e1_code_gen_sinboc11_float(float* _dest, char _Signal[3], uint32_t _prn) { std::string _galileo_signal = _Signal; - const unsigned int _codeLength = 12 * Galileo_E1_B_CODE_LENGTH_CHIPS; + const auto _codeLength = static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS); + int32_t primary_code_E1_chips[4092]; // _codeLength not accepted by Clang + galileo_e1_code_gen_int(primary_code_E1_chips, _Signal, _prn); //generate Galileo E1 code, 1 sample per chip + for (uint32_t i = 0; i < _codeLength; i++) + { + _dest[2 * i] = static_cast(primary_code_E1_chips[i]); + _dest[2 * i + 1] = -_dest[2 * i]; + } +} + + +void galileo_e1_gen_float(float* _dest, int* _prn, char _Signal[3]) +{ + std::string _galileo_signal = _Signal; + const uint32_t _codeLength = 12 * Galileo_E1_B_CODE_LENGTH_CHIPS; const float alpha = sqrt(10.0 / 11.0); const float beta = sqrt(1.0 / 11.0); - std::complex sinboc_11[12 * 4092]; // _codeLength not accepted by Clang - std::complex sinboc_61[12 * 4092]; + int32_t sinboc_11[12 * 4092] = {0}; // _codeLength not accepted by Clang + int32_t sinboc_61[12 * 4092] = {0}; - galileo_e1_sinboc_11_gen(sinboc_11, _prn, _codeLength); //generate sinboc(1,1) 12 samples per chip - galileo_e1_sinboc_61_gen(sinboc_61, _prn, _codeLength); //generate sinboc(6,1) 12 samples per chip + galileo_e1_sinboc_11_gen_int(sinboc_11, _prn, _codeLength); //generate sinboc(1,1) 12 samples per chip + galileo_e1_sinboc_61_gen_int(sinboc_61, _prn, _codeLength); //generate sinboc(6,1) 12 samples per chip if (_galileo_signal.rfind("1B") != std::string::npos && _galileo_signal.length() >= 2) { - for (unsigned int i = 0; i < _codeLength; i++) + for (uint32_t i = 0; i < _codeLength; i++) { - _dest[i] = alpha * sinboc_11[i] + beta * sinboc_61[i]; + _dest[i] = alpha * static_cast(sinboc_11[i]) + + beta * static_cast(sinboc_61[i]); } } else if (_galileo_signal.rfind("1C") != std::string::npos && _galileo_signal.length() >= 2) { - for (unsigned int i = 0; i < _codeLength; i++) + for (uint32_t i = 0; i < _codeLength; i++) { - _dest[i] = alpha * sinboc_11[i] - beta * sinboc_61[i]; + _dest[i] = alpha * static_cast(sinboc_11[i]) - + beta * static_cast(sinboc_61[i]); } } - else - return; } - -void galileo_e1_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], - bool _cboc, unsigned int _prn, signed int _fs, unsigned int _chip_shift, - bool _secondary_flag) +void galileo_e1_code_gen_float_sampled(float* _dest, char _Signal[3], + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift, + bool _secondary_flag) { // This function is based on the GNU software GPS for MATLAB in Kay Borre's book std::string _galileo_signal = _Signal; - unsigned int _samplesPerCode; - const int _codeFreqBasis = Galileo_E1_CODE_CHIP_RATE_HZ; //Hz - unsigned int _codeLength = Galileo_E1_B_CODE_LENGTH_CHIPS; - int primary_code_E1_chips[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)]; - _samplesPerCode = static_cast( static_cast(_fs) / (static_cast(_codeFreqBasis ) / static_cast(_codeLength))); - const int _samplesPerChip = (_cboc == true) ? 12 : 2; + uint32_t _samplesPerCode; + const int32_t _codeFreqBasis = Galileo_E1_CODE_CHIP_RATE_HZ; // Hz + auto _codeLength = static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS); + auto* primary_code_E1_chips = static_cast(volk_gnsssdr_malloc(static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * sizeof(int32_t), volk_gnsssdr_get_alignment())); - const unsigned int delay = ((static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - _chip_shift) - % static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) - * _samplesPerCode / Galileo_E1_B_CODE_LENGTH_CHIPS; + _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(_codeFreqBasis) / static_cast(_codeLength))); + const int32_t _samplesPerChip = (_cboc == true) ? 12 : 2; - galileo_e1_code_gen_int(primary_code_E1_chips, _Signal, _prn); //generate Galileo E1 code, 1 sample per chip + const uint32_t delay = ((static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - _chip_shift) % static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) * _samplesPerCode / Galileo_E1_B_CODE_LENGTH_CHIPS; - std::complex* _signal_E1; + galileo_e1_code_gen_int(primary_code_E1_chips, _Signal, _prn); // generate Galileo E1 code, 1 sample per chip + + float* _signal_E1; _codeLength = _samplesPerChip * Galileo_E1_B_CODE_LENGTH_CHIPS; - _signal_E1 = new std::complex[_codeLength]; + _signal_E1 = new float[_codeLength]; if (_cboc == true) { - galileo_e1_gen(_signal_E1, primary_code_E1_chips, _Signal); //generate cboc 12 samples per chip + galileo_e1_gen_float(_signal_E1, primary_code_E1_chips, _Signal); // generate cboc 12 samples per chip } else { - galileo_e1_sinboc_11_gen(_signal_E1, primary_code_E1_chips, _codeLength); //generate sinboc(1,1) 2 samples per chip + auto* _signal_E1_int = static_cast(volk_gnsssdr_malloc(_codeLength * sizeof(int32_t), volk_gnsssdr_get_alignment())); + galileo_e1_sinboc_11_gen_int(_signal_E1_int, primary_code_E1_chips, _codeLength); // generate sinboc(1,1) 2 samples per chip + + for (uint32_t ii = 0; ii < _codeLength; ++ii) + { + _signal_E1[ii] = static_cast(_signal_E1_int[ii]); + } + volk_gnsssdr_free(_signal_E1_int); } if (_fs != _samplesPerChip * _codeFreqBasis) { - std::complex* _resampled_signal = new std::complex[_samplesPerCode]; + auto* _resampled_signal = new float[_samplesPerCode]; + resampler(_signal_E1, _resampled_signal, _samplesPerChip * _codeFreqBasis, _fs, - _codeLength, _samplesPerCode); //resamples code to fs + _codeLength, _samplesPerCode); // resamples code to fs delete[] _signal_E1; _signal_E1 = _resampled_signal; } - if (_galileo_signal.rfind("1C") != std::string::npos && _galileo_signal.length() >= 2 && _secondary_flag) - { + { + auto* _signal_E1C_secondary = new float[static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH) * _samplesPerCode]; - std::complex* _signal_E1C_secondary = new std::complex - [static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH) - * _samplesPerCode]; + for (uint32_t i = 0; i < static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); i++) + { + for (unsigned k = 0; k < _samplesPerCode; k++) + { + _signal_E1C_secondary[i * _samplesPerCode + k] = _signal_E1[k] * (Galileo_E1_C_SECONDARY_CODE.at(i) == '0' ? 1.0f : -1.0f); + } + } - for (unsigned int i = 0; i < static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); i++) - { - for (unsigned k = 0; k < _samplesPerCode; k++) - { - _signal_E1C_secondary[i*_samplesPerCode + k] = _signal_E1[k] - * (Galileo_E1_C_SECONDARY_CODE.at(i) == '0' - ? std::complex(1,0) : std::complex(-1,0)); - } - } + _samplesPerCode *= static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); - _samplesPerCode *= static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); + delete[] _signal_E1; + _signal_E1 = _signal_E1C_secondary; + } - delete[] _signal_E1; - _signal_E1 = _signal_E1C_secondary; - } - - for (unsigned int i = 0; i < _samplesPerCode; i++) + for (uint32_t i = 0; i < _samplesPerCode; i++) { _dest[(i + delay) % _samplesPerCode] = _signal_E1[i]; } delete[] _signal_E1; + volk_gnsssdr_free(primary_code_E1_chips); } void galileo_e1_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], - bool _cboc, unsigned int _prn, signed int _fs, unsigned int _chip_shift) + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift, + bool _secondary_flag) +{ + std::string _galileo_signal = _Signal; + const int32_t _codeFreqBasis = Galileo_E1_CODE_CHIP_RATE_HZ; // Hz + auto _samplesPerCode = static_cast(static_cast(_fs) / + (static_cast(_codeFreqBasis) / static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS))); + + if (_galileo_signal.rfind("1C") != std::string::npos && _galileo_signal.length() >= 2 && _secondary_flag) + { + _samplesPerCode *= static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); + } + + auto* real_code = static_cast(volk_gnsssdr_malloc(_samplesPerCode * sizeof(float), volk_gnsssdr_get_alignment())); + + galileo_e1_code_gen_float_sampled(real_code, _Signal, _cboc, _prn, _fs, _chip_shift, _secondary_flag); + + for (uint32_t ii = 0; ii < _samplesPerCode; ++ii) + { + _dest[ii] = std::complex(real_code[ii], 0.0f); + } + volk_gnsssdr_free(real_code); +} + + +void galileo_e1_code_gen_float_sampled(float* _dest, char _Signal[3], + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift) +{ + galileo_e1_code_gen_float_sampled(_dest, _Signal, _cboc, _prn, _fs, _chip_shift, false); +} + + +void galileo_e1_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift) { galileo_e1_code_gen_complex_sampled(_dest, _Signal, _cboc, _prn, _fs, _chip_shift, false); } diff --git a/src/algorithms/libs/galileo_e1_signal_processing.h b/src/algorithms/libs/galileo_e1_signal_processing.h index d7518ab04..6784e6f22 100644 --- a/src/algorithms/libs/galileo_e1_signal_processing.h +++ b/src/algorithms/libs/galileo_e1_signal_processing.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,46 +33,44 @@ #define GNSS_SDR_GALILEO_E1_SIGNAL_PROCESSING_H_ #include - +#include /*! - * \brief This function generates Galileo E1 code (one sample per chip). + * \brief This function generates Galileo E1 code (can select E1B or E1C sinboc). * */ -void galileo_e1_code_gen_int(int* _dest, char _Signal[3], signed int _prn); +void galileo_e1_code_gen_sinboc11_float(float* _dest, char _Signal[3], uint32_t _prn); /*! - * \brief This function generates Galileo E1 sinboc(1,1) code (minimum 2 samples per chip), - * the _codeLength variable must be a multiple of 2*4092. + * \brief This function generates Galileo E1 code (can select E1B or E1C, cboc or sinboc + * and the sample frequency _fs). * */ -void galileo_e1_sinboc_11_gen(std::complex* _dest, int* _prn, - unsigned int _codeLength); +void galileo_e1_code_gen_float_sampled(float* _dest, char _Signal[3], + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift, + bool _secondary_flag); + /*! - * \brief This function generates Galileo E1 sinboc(6,1) code (minimum 12 samples per chip), - * the _codeLength variable must be a multiple of 12*4092. + * \brief This function generates Galileo E1 code (can select E1B or E1C, cboc or sinboc + * and the sample frequency _fs). * */ -void galileo_e1_sinboc_61_gen(std::complex* _dest, int* _prn, - unsigned int _codeLength); -/*! - * \brief This function generates Galileo E1 cboc code (12 samples per chip). - * - */ -void galileo_e1_cboc_gen(std::complex* _dest, int* _prn, char _Signal[3]); +void galileo_e1_code_gen_float_sampled(float* _dest, char _Signal[3], + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift); + /*! * \brief This function generates Galileo E1 code (can select E1B or E1C, cboc or sinboc * and the sample frequency _fs). * */ void galileo_e1_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], - bool _cboc, unsigned int _prn, signed int _fs, unsigned int _chip_shift, - bool _secondary_flag); + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift, + bool _secondary_flag); /*! * \brief galileo_e1_code_gen_complex_sampled without _secondary_flag for backward compatibility. */ void galileo_e1_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], - bool _cboc, unsigned int _prn, signed int _fs, unsigned int _chip_shift); + bool _cboc, uint32_t _prn, int32_t _fs, uint32_t _chip_shift); #endif /* GNSS_SDR_GALILEO_E1_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/galileo_e5_signal_processing.cc b/src/algorithms/libs/galileo_e5_signal_processing.cc index ba2677aae..baa91706f 100644 --- a/src/algorithms/libs/galileo_e5_signal_processing.cc +++ b/src/algorithms/libs/galileo_e5_signal_processing.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,23 +26,22 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e5_signal_processing.h" -#include #include "Galileo_E5a.h" #include "gnss_signal_processing.h" +#include - -void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, signed int _prn, char _Signal[3]) +void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, int32_t _prn, const char _Signal[3]) { - unsigned int prn = _prn - 1; - unsigned int index = 0; - int a[4]; + uint32_t prn = _prn - 1; + uint32_t index = 0; + int32_t a[4]; if ((_prn < 1) || (_prn > 50)) { return; @@ -81,15 +80,15 @@ void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, signed in } else if (_Signal[0] == '5' && _Signal[1] == 'X') { - int b[4]; + int32_t b[4]; for (size_t i = 0; i < Galileo_E5a_I_PRIMARY_CODE[prn].length() - 1; i++) { hex_to_binary_converter(a, Galileo_E5a_I_PRIMARY_CODE[prn].at(i)); hex_to_binary_converter(b, Galileo_E5a_Q_PRIMARY_CODE[prn].at(i)); - _dest[index] = std::complex(float(a[0]),float(b[0])); - _dest[index + 1] = std::complex(float(a[1]),float(b[1])); - _dest[index + 2] = std::complex(float(a[2]),float(b[2])); - _dest[index + 3] = std::complex(float(a[3]),float(b[3])); + _dest[index] = std::complex(float(a[0]), float(b[0])); + _dest[index + 1] = std::complex(float(a[1]), float(b[1])); + _dest[index + 2] = std::complex(float(a[2]), float(b[2])); + _dest[index + 3] = std::complex(float(a[3]), float(b[3])); index = index + 4; } // last 2 bits are filled up zeros @@ -100,41 +99,38 @@ void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, signed in } } + void galileo_e5_a_code_gen_complex_sampled(std::complex* _dest, char _Signal[3], - unsigned int _prn, signed int _fs, unsigned int _chip_shift) + uint32_t _prn, int32_t _fs, uint32_t _chip_shift) { - unsigned int _samplesPerCode; - unsigned int delay; - const unsigned int _codeLength = Galileo_E5a_CODE_LENGTH_CHIPS; - const int _codeFreqBasis = Galileo_E5a_CODE_CHIP_RATE_HZ; + uint32_t _samplesPerCode; + uint32_t delay; + const uint32_t _codeLength = Galileo_E5a_CODE_LENGTH_CHIPS; + const int32_t _codeFreqBasis = Galileo_E5a_CODE_CHIP_RATE_HZ; - std::complex* _code = new std::complex[_codeLength](); + auto* _code = new std::complex[_codeLength](); - galileo_e5_a_code_gen_complex_primary(_code , _prn , _Signal); + galileo_e5_a_code_gen_complex_primary(_code, _prn, _Signal); - _samplesPerCode = static_cast(static_cast(_fs) / ( static_cast(_codeFreqBasis) / static_cast(_codeLength))); + _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(_codeFreqBasis) / static_cast(_codeLength))); delay = ((_codeLength - _chip_shift) % _codeLength) * _samplesPerCode / _codeLength; if (_fs != _codeFreqBasis) { std::complex* _resampled_signal; - if (posix_memalign((void**)&_resampled_signal, 16, _samplesPerCode * sizeof(gr_complex)) == 0){}; - resampler(_code, _resampled_signal, _codeFreqBasis, _fs, _codeLength, _samplesPerCode); //resamples code to fs + if (posix_memalign(reinterpret_cast(&_resampled_signal), 16, _samplesPerCode * sizeof(gr_complex)) == 0) + { + }; + resampler(_code, _resampled_signal, _codeFreqBasis, _fs, _codeLength, _samplesPerCode); // resamples code to fs delete[] _code; _code = _resampled_signal; } - for (unsigned int i = 0; i < _samplesPerCode; i++) + for (uint32_t i = 0; i < _samplesPerCode; i++) { _dest[(i + delay) % _samplesPerCode] = _code[i]; } - if (_fs != _codeFreqBasis) - { - free(_code); - } - else - { - delete[] _code; - } + + delete[] _code; } diff --git a/src/algorithms/libs/galileo_e5_signal_processing.h b/src/algorithms/libs/galileo_e5_signal_processing.h index 41dde566f..7a7dfc8cc 100644 --- a/src/algorithms/libs/galileo_e5_signal_processing.h +++ b/src/algorithms/libs/galileo_e5_signal_processing.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,23 +35,23 @@ #define GNSS_SDR_GALILEO_E5_SIGNAL_PROCESSING_H_ #include +#include /*! * \brief Generates Galileo E5a code at 1 sample/chip * bool _pilot generates E5aQ code if true and E5aI (data signal) if false. */ -void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, signed int _prn, char _Signal[3]); +void galileo_e5_a_code_gen_complex_primary(std::complex* _dest, int32_t _prn, const char _Signal[3]); - -void galileo_e5_a_code_gen_tiered(std::complex* _dest,std::complex* _primary ,unsigned int _prn, char _Signal[3]); +void galileo_e5_a_code_gen_tiered(std::complex* _dest, std::complex* _primary, uint32_t _prn, char _Signal[3]); /*! * \brief Generates Galileo E5a complex code, shifted to the desired chip and sampled at a frequency fs * bool _pilot generates E5aQ code if true and E5aI (data signal) if false. */ void galileo_e5_a_code_gen_complex_sampled(std::complex* _dest, - char _Signal[3], unsigned int _prn, signed int _fs, unsigned int _chip_shift); + char _Signal[3], uint32_t _prn, int32_t _fs, uint32_t _chip_shift); #endif /* GNSS_SDR_GALILEO_E5_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/geofunctions.cc b/src/algorithms/libs/geofunctions.cc new file mode 100644 index 000000000..bf67e07f8 --- /dev/null +++ b/src/algorithms/libs/geofunctions.cc @@ -0,0 +1,775 @@ +/*! + * \file geofunctions.cc + * \brief A set of coordinate transformations functions and helpers, + * some of them migrated from MATLAB, for geographic information systems. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "geofunctions.h" + +const double STRP_PI = 3.1415926535898; // Pi as defined in IS-GPS-200E + +arma::mat Skew_symmetric(const arma::vec &a) +{ + arma::mat A = arma::zeros(3, 3); + + A << 0.0 << -a(2) << a(1) << arma::endr + << a(2) << 0.0 << -a(0) << arma::endr + << -a(1) << a(0) << 0 << arma::endr; + + // {{0, -a(2), a(1)}, + // {a(2), 0, -a(0)}, + // {-a(1), a(0), 0}}; + return A; +} + + +double WGS84_g0(double Lat_rad) +{ + const double k = 0.001931853; // normal gravity constant + const double e2 = 0.00669438002290; // the square of the first numerical eccentricity + const double nge = 9.7803253359; // normal gravity value on the equator (m/sec^2) + double b = sin(Lat_rad); // Lat in degrees + b = b * b; + double g0 = nge * (1 + k * b) / (sqrt(1 - e2 * b)); + return g0; +} + + +double WGS84_geocentric_radius(double Lat_geodetic_rad) +{ + // WGS84 earth model Geocentric radius (Eq. 2.88) + const double WGS84_A = 6378137.0; // Semi-major axis of the Earth, a [m] + const double WGS84_IF = 298.257223563; // Inverse flattening of the Earth + const double WGS84_F = (1.0 / WGS84_IF); // The flattening of the Earth + // double WGS84_B=(WGS84_A*(1-WGS84_F)); // Semi-minor axis of the Earth [m] + double WGS84_E = (sqrt(2 * WGS84_F - WGS84_F * WGS84_F)); // Eccentricity of the Earth + + // transverse radius of curvature + double R_E = WGS84_A / sqrt(1 - WGS84_E * WGS84_E * sin(Lat_geodetic_rad) * sin(Lat_geodetic_rad)); // (Eq. 2.66) + + // geocentric radius at the Earth surface + double r_eS = R_E * sqrt(cos(Lat_geodetic_rad) * cos(Lat_geodetic_rad) + + (1 - WGS84_E * WGS84_E) * (1 - WGS84_E * WGS84_E) * sin(Lat_geodetic_rad) * sin(Lat_geodetic_rad)); // (Eq. 2.88) + return r_eS; +} + + +int topocent(double *Az, double *El, double *D, const arma::vec &x, const arma::vec &dx) +{ + double lambda; + double phi; + double h; + const double dtr = STRP_PI / 180.0; + const double a = 6378137.0; // semi-major axis of the reference ellipsoid WGS-84 + const double finv = 298.257223563; // inverse of flattening of the reference ellipsoid WGS-84 + + // Transform x into geodetic coordinates + togeod(&phi, &lambda, &h, a, finv, x(0), x(1), x(2)); + + double cl = cos(lambda * dtr); + double sl = sin(lambda * dtr); + double cb = cos(phi * dtr); + double sb = sin(phi * dtr); + + arma::mat F = {{-sl, -sb * cl, cb * cl}, + {cl, -sb * sl, cb * sl}, + {0.0, cb, sb}}; + + arma::vec local_vector; + + local_vector = arma::htrans(F) * dx; + + double E = local_vector(0); + double N = local_vector(1); + double U = local_vector(2); + + double hor_dis; + hor_dis = sqrt(E * E + N * N); + + if (hor_dis < 1.0E-20) + { + *Az = 0.0; + *El = 90.0; + } + else + { + *Az = atan2(E, N) / dtr; + *El = atan2(U, hor_dis) / dtr; + } + + if (*Az < 0) + { + *Az = *Az + 360.0; + } + + *D = sqrt(dx(0) * dx(0) + dx(1) * dx(1) + dx(2) * dx(2)); + return 0; +} + + +int togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z) +{ + *h = 0.0; + const double tolsq = 1.e-10; // tolerance to accept convergence + const int maxit = 10; // max number of iterations + const double rtd = 180.0 / STRP_PI; + + // compute square of eccentricity + double esq; + if (finv < 1.0E-20) + { + esq = 0.0; + } + else + { + esq = (2.0 - 1.0 / finv) / finv; + } + + // first guess + double P = sqrt(X * X + Y * Y); // P is distance from spin axis + + // direct calculation of longitude + if (P > 1.0E-20) + { + *dlambda = atan2(Y, X) * rtd; + } + else + { + *dlambda = 0.0; + } + + // correct longitude bound + if (*dlambda < 0) + { + *dlambda = *dlambda + 360.0; + } + + double r = sqrt(P * P + Z * Z); // r is distance from origin (0,0,0) + + double sinphi; + if (r > 1.0E-20) + { + sinphi = Z / r; + } + else + { + sinphi = 0.0; + } + *dphi = asin(sinphi); + + // initial value of height = distance from origin minus + // approximate distance from origin to surface of ellipsoid + if (r < 1.0E-20) + { + *h = 0.0; + return 1; + } + + *h = r - a * (1 - sinphi * sinphi / finv); + + // iterate + double cosphi; + double N_phi; + double dP; + double dZ; + double oneesq = 1.0 - esq; + + for (int i = 0; i < maxit; i++) + { + sinphi = sin(*dphi); + cosphi = cos(*dphi); + + // compute radius of curvature in prime vertical direction + N_phi = a / sqrt(1.0 - esq * sinphi * sinphi); + + // compute residuals in P and Z + dP = P - (N_phi + (*h)) * cosphi; + dZ = Z - (N_phi * oneesq + (*h)) * sinphi; + + // update height and latitude + *h = *h + (sinphi * dZ + cosphi * dP); + *dphi = *dphi + (cosphi * dZ - sinphi * dP) / (N_phi + (*h)); + + // test for convergence + if ((dP * dP + dZ * dZ) < tolsq) + { + break; + } + if (i == (maxit - 1)) + { + // LOG(WARNING) << "The computation of geodetic coordinates did not converge"; + } + } + *dphi = (*dphi) * rtd; + return 0; +} + + +arma::mat Gravity_ECEF(const arma::vec &r_eb_e) +{ + // Parameters + const double R_0 = 6378137.0; // WGS84 Equatorial radius in meters + const double mu = 3.986004418E14; // WGS84 Earth gravitational constant (m^3 s^-2) + const double J_2 = 1.082627E-3; // WGS84 Earth's second gravitational constant + const double omega_ie = 7.292115E-5; // Earth rotation rate (rad/s) + // Calculate distance from center of the Earth + double mag_r = sqrt(arma::as_scalar(r_eb_e.t() * r_eb_e)); + // If the input position is 0,0,0, produce a dummy output + arma::vec g = arma::zeros(3, 1); + if (mag_r != 0) + { + // Calculate gravitational acceleration using (2.142) + double z_scale = 5 * pow((r_eb_e(2) / mag_r), 2); + arma::vec tmp_vec = {(1 - z_scale) * r_eb_e(0), + (1 - z_scale) * r_eb_e(1), + (3 - z_scale) * r_eb_e(2)}; + arma::vec gamma_ = (-mu / pow(mag_r, 3)) * (r_eb_e + 1.5 * J_2 * pow(R_0 / mag_r, 2) * tmp_vec); + + // Add centripetal acceleration using (2.133) + g(0) = gamma_(0) + pow(omega_ie, 2) * r_eb_e(0); + g(1) = gamma_(1) + pow(omega_ie, 2) * r_eb_e(1); + g(2) = gamma_(2); + } + return g; +} + + +arma::vec LLH_to_deg(const arma::vec &LLH) +{ + const double rtd = 180.0 / STRP_PI; + arma::vec deg = arma::zeros(3, 1); + deg(0) = LLH(0) * rtd; + deg(1) = LLH(1) * rtd; + deg(2) = LLH(2); + return deg; +} + + +double degtorad(double angleInDegrees) +{ + double angleInRadians = (STRP_PI / 180.0) * angleInDegrees; + return angleInRadians; +} + + +double radtodeg(double angleInRadians) +{ + double angleInDegrees = (180.0 / STRP_PI) * angleInRadians; + return angleInDegrees; +} + + +double mstoknotsh(double MetersPerSeconds) +{ + double knots = mstokph(MetersPerSeconds) * 0.539957; + return knots; +} + + +double mstokph(double MetersPerSeconds) +{ + double kph = 3600.0 * MetersPerSeconds / 1e3; + return kph; +} + + +arma::vec CTM_to_Euler(const arma::mat &C) +{ + // Calculate Euler angles using (2.23) + arma::mat CTM(C); + arma::vec eul = arma::zeros(3, 1); + eul(0) = atan2(CTM(1, 2), CTM(2, 2)); // roll + if (CTM(0, 2) < -1.0) CTM(0, 2) = -1.0; + if (CTM(0, 2) > 1.0) CTM(0, 2) = 1.0; + eul(1) = -asin(CTM(0, 2)); // pitch + eul(2) = atan2(CTM(0, 1), CTM(0, 0)); // yaw + return eul; +} + + +arma::mat Euler_to_CTM(const arma::vec &eul) +{ + // Eq.2.15 + // Euler angles to Attitude matrix is equivalent to rotate the body + // in the three axes: + // arma::mat Ax= {{1,0,0}, {0,cos(Att_phi),sin(Att_phi)} ,{0,-sin(Att_phi),cos(Att_phi)}}; + // arma::mat Ay= {{cos(Att_theta), 0, -sin(Att_theta)}, {0,1,0} , {sin(Att_theta), 0, cos(Att_theta)}}; + // arma::mat Az= {{cos(Att_psi), sin(Att_psi), 0}, {-sin(Att_psi), cos(Att_psi), 0},{0,0,1}}; + // arma::mat C_b_n=Ax*Ay*Az; // Attitude expressed in the LOCAL FRAME (NED) + // C_b_n=C_b_n.t(); + + // Precalculate sines and cosines of the Euler angles + double sin_phi = sin(eul(0)); + double cos_phi = cos(eul(0)); + double sin_theta = sin(eul(1)); + double cos_theta = cos(eul(1)); + double sin_psi = sin(eul(2)); + double cos_psi = cos(eul(2)); + + // Calculate coordinate transformation matrix using (2.22) + arma::mat C = {{cos_theta * cos_psi, cos_theta * sin_psi, -sin_theta}, + {-cos_phi * sin_psi + sin_phi * sin_theta * cos_psi, cos_phi * cos_psi + sin_phi * sin_theta * sin_psi, sin_phi * cos_theta}, + {sin_phi * sin_psi + cos_phi * sin_theta * cos_psi, -sin_phi * cos_psi + cos_phi * sin_theta * sin_psi, cos_phi * cos_theta}}; + return C; +} + + +arma::vec cart2geo(const arma::vec &XYZ, int elipsoid_selection) +{ + const double a[5] = {6378388.0, 6378160.0, 6378135.0, 6378137.0, 6378137.0}; + const double f[5] = {1.0 / 297.0, 1.0 / 298.247, 1.0 / 298.26, 1.0 / 298.257222101, 1.0 / 298.257223563}; + + double lambda = atan2(XYZ[1], XYZ[0]); + double ex2 = (2.0 - f[elipsoid_selection]) * f[elipsoid_selection] / ((1.0 - f[elipsoid_selection]) * (1.0 - f[elipsoid_selection])); + double c = a[elipsoid_selection] * sqrt(1.0 + ex2); + double phi = atan(XYZ[2] / ((sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1]) * (1.0 - (2.0 - f[elipsoid_selection])) * f[elipsoid_selection]))); + + double h = 0.1; + double oldh = 0.0; + double N; + int iterations = 0; + do + { + oldh = h; + N = c / sqrt(1.0 + ex2 * (cos(phi) * cos(phi))); + phi = atan(XYZ[2] / ((sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1]) * (1.0 - (2.0 - f[elipsoid_selection]) * f[elipsoid_selection] * N / (N + h))))); + h = sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1]) / cos(phi) - N; + iterations = iterations + 1; + if (iterations > 100) + { + // std::cout << "Failed to approximate h with desired precision. h-oldh= " << h - oldh; + break; + } + } + while (std::fabs(h - oldh) > 1.0e-12); + + arma::vec LLH = {{phi, lambda, h}}; // radians + return LLH; +} + + +void ECEF_to_Geo(const arma::vec &r_eb_e, const arma::vec &v_eb_e, const arma::mat &C_b_e, arma::vec &LLH, arma::vec &v_eb_n, arma::mat &C_b_n) +{ + // Compute the Latitude of the ECEF position + LLH = cart2geo(r_eb_e, 4); // ECEF -> WGS84 geographical + + // Calculate ECEF to Geographical coordinate transformation matrix using (2.150) + double cos_lat = cos(LLH(0)); + double sin_lat = sin(LLH(0)); + double cos_long = cos(LLH(1)); + double sin_long = sin(LLH(1)); + // C++11 and arma >= 5.2 + // arma::mat C_e_n = {{-sin_lat * cos_long, -sin_lat * sin_long, cos_lat}, + // {-sin_long, cos_long, 0}, + // {-cos_lat * cos_long, -cos_lat * sin_long, -sin_lat}}; //ECEF to Geo + arma::mat C_e_n = arma::zeros(3, 3); + C_e_n << -sin_lat * cos_long << -sin_lat * sin_long << cos_lat << arma::endr + << -sin_long << cos_long << 0 << arma::endr + << -cos_lat * cos_long << -cos_lat * sin_long << -sin_lat << arma::endr; // ECEF to Geo + // Transform velocity using (2.73) + v_eb_n = C_e_n * v_eb_e; + + C_b_n = C_e_n * C_b_e; // Attitude conversion from ECEF to NED +} + + +void Geo_to_ECEF(const arma::vec &LLH, const arma::vec &v_eb_n, const arma::mat &C_b_n, arma::vec &r_eb_e, arma::vec &v_eb_e, arma::mat &C_b_e) +{ + // Parameters + double R_0 = 6378137.0; // WGS84 Equatorial radius in meters + double e = 0.0818191908425; // WGS84 eccentricity + + // Calculate transverse radius of curvature using (2.105) + double R_E = R_0 / sqrt(1.0 - (e * sin(LLH(0))) * (e * sin(LLH(0)))); + + // Convert position using (2.112) + double cos_lat = cos(LLH(0)); + double sin_lat = sin(LLH(0)); + double cos_long = cos(LLH(1)); + double sin_long = sin(LLH(1)); + r_eb_e = {(R_E + LLH(2)) * cos_lat * cos_long, + (R_E + LLH(2)) * cos_lat * sin_long, + ((1 - e * e) * R_E + LLH(2)) * sin_lat}; + + // Calculate ECEF to Geo coordinate transformation matrix using (2.150) + // C++11 and arma>=5.2 + // arma::mat C_e_n = {{-sin_lat * cos_long, -sin_lat * sin_long, cos_lat}, + // {-sin_long, cos_long, 0}, + // {-cos_lat * cos_long, -cos_lat * sin_long, -sin_lat}}; + arma::mat C_e_n = arma::zeros(3, 3); + C_e_n << -sin_lat * cos_long << -sin_lat * sin_long << cos_lat << arma::endr + << -sin_long << cos_long << 0 << arma::endr + << -cos_lat * cos_long << -cos_lat * sin_long << -sin_lat << arma::endr; + + // Transform velocity using (2.73) + v_eb_e = C_e_n.t() * v_eb_n; + + // Transform attitude using (2.15) + C_b_e = C_e_n.t() * C_b_n; +} + + +void pv_Geo_to_ECEF(double L_b, double lambda_b, double h_b, const arma::vec &v_eb_n, arma::vec &r_eb_e, arma::vec &v_eb_e) +{ + // Parameters + const double R_0 = 6378137.0; // WGS84 Equatorial radius in meters + const double e = 0.0818191908425; // WGS84 eccentricity + + // Calculate transverse radius of curvature using (2.105) + double R_E = R_0 / sqrt(1 - pow(e * sin(L_b), 2)); + + // Convert position using (2.112) + double cos_lat = cos(L_b); + double sin_lat = sin(L_b); + double cos_long = cos(lambda_b); + double sin_long = sin(lambda_b); + r_eb_e = {(R_E + h_b) * cos_lat * cos_long, + (R_E + h_b) * cos_lat * sin_long, + ((1 - pow(e, 2)) * R_E + h_b) * sin_lat}; + + // Calculate ECEF to Geo coordinate transformation matrix using (2.150) + arma::mat C_e_n = arma::zeros(3, 3); + C_e_n << -sin_lat * cos_long << -sin_lat * sin_long << cos_lat << arma::endr + << -sin_long << cos_long << 0 << arma::endr + << -cos_lat * cos_long << -cos_lat * sin_long << -sin_lat << arma::endr; + + // Transform velocity using (2.73) + v_eb_e = C_e_n.t() * v_eb_n; +} + + +double great_circle_distance(double lat1, double lon1, double lat2, double lon2) +{ + // The Haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes. + // generally used geo measurement function + double R = 6378.137; // Radius of earth in KM + double dLat = lat2 * STRP_PI / 180.0 - lat1 * STRP_PI / 180.0; + double dLon = lon2 * STRP_PI / 180.0 - lon1 * STRP_PI / 180.0; + double a = sin(dLat / 2.0) * sin(dLat / 2.0) + + cos(lat1 * STRP_PI / 180.0) * cos(lat2 * STRP_PI / 180.0) * + sin(dLon / 2) * sin(dLon / 2.0); + double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a)); + double d = R * c; + return d * 1000.0; // meters +} + + +void cart2utm(const arma::vec &r_eb_e, int zone, arma::vec &r_enu) +{ + // Transformation of (X,Y,Z) to (E,N,U) in UTM, zone 'zone' + // + // Inputs: + // r_eb_e - Cartesian coordinates. Coordinates are referenced + // with respect to the International Terrestrial Reference + // Frame 1996 (ITRF96) + // zone - UTM zone of the given position + // + // Outputs: + // r_enu - UTM coordinates (Easting, Northing, Uping) + // + // Originally written in Matlab by Kai Borre, Nov. 1994 + // Implemented in C++ by J.Arribas + // + // This implementation is based upon + // O. Andersson & K. Poder (1981) Koordinattransformationer + // ved Geod\ae{}tisk Institut. Landinspekt\oe{}ren + // Vol. 30: 552--571 and Vol. 31: 76 + // + // An excellent, general reference (KW) is + // R. Koenig & K.H. Weise (1951) Mathematische Grundlagen der + // h\"oheren Geod\"asie und Kartographie. + // Erster Band, Springer Verlag + // + // Explanation of variables used: + // f flattening of ellipsoid + // a semi major axis in m + // m0 1 - scale at central meridian; for UTM 0.0004 + // Q_n normalized meridian quadrant + // E0 Easting of central meridian + // L0 Longitude of central meridian + // bg constants for ellipsoidal geogr. to spherical geogr. + // gb constants for spherical geogr. to ellipsoidal geogr. + // gtu constants for ellipsoidal N, E to spherical N, E + // utg constants for spherical N, E to ellipoidal N, E + // tolutm tolerance for utm, 1.2E-10*meridian quadrant + // tolgeo tolerance for geographical, 0.00040 second of arc + // + // B, L refer to latitude and longitude. Southern latitude is negative + // International ellipsoid of 1924, valid for ED50 + + double a = 6378388.0; + double f = 1.0 / 297.0; + double ex2 = (2.0 - f) * f / ((1.0 - f) * (1.0 - f)); + double c = a * sqrt(1.0 + ex2); + arma::vec vec = r_eb_e; + vec(2) = vec(2) - 4.5; + double alpha = 0.756e-6; + arma::mat R = {{1.0, -alpha, 0.0}, {alpha, 1.0, 0.0}, {0.0, 0.0, 1.0}}; + arma::vec trans = {89.5, 93.8, 127.6}; + double scale = 0.9999988; + arma::vec v = scale * R * vec + trans; // coordinate vector in ED50 + double L = atan2(v(1), v(0)); + double N1 = 6395000.0; // preliminary value + double B = atan2(v(2) / ((1.0 - f) * (1.0 - f) * N1), arma::norm(v.subvec(0, 1)) / N1); // preliminary value + double U = 0.1; + double oldU = 0.0; + int iterations = 0; + while (fabs(U - oldU) > 1.0E-4) + { + oldU = U; + N1 = c / sqrt(1.0 + ex2 * (cos(B) * cos(B))); + B = atan2(v(2) / ((1.0 - f) * (1.0 - f) * N1 + U), arma::norm(v.subvec(0, 1)) / (N1 + U)); + U = arma::norm(v.subvec(0, 1)) / cos(B) - N1; + iterations = iterations + 1; + if (iterations > 100) + { + std::cout << "Failed to approximate U with desired precision. U-oldU:" << U - oldU << std::endl; + break; + } + } + // Normalized meridian quadrant, KW p. 50 (96), p. 19 (38b), p. 5 (21) + double m0 = 0.0004; + double n = f / (2.0 - f); + double m = n * n * (1.0 / 4.0 + n * n / 64.0); + double w = (a * (-n - m0 + m * (1.0 - m0))) / (1.0 + n); + double Q_n = a + w; + + // Easting and longitude of central meridian + double E0 = 500000.0; + double L0 = (zone - 30) * 6.0 - 3.0; + + // Check tolerance for reverse transformation + // double tolutm = STRP_PI / 2.0 * 1.2e-10 * Q_n; + // double tolgeo = 0.000040; + // Coefficients of trigonometric series + // + // ellipsoidal to spherical geographical, KW p .186 --187, (51) - (52) + // bg[1] = n * (-2 + n * (2 / 3 + n * (4 / 3 + n * (-82 / 45)))); + // bg[2] = n ^ 2 * (5 / 3 + n * (-16 / 15 + n * (-13 / 9))); + // bg[3] = n ^ 3 * (-26 / 15 + n * 34 / 21); + // bg[4] = n ^ 4 * 1237 / 630; + // + // spherical to ellipsoidal geographical, KW p.190 --191, (61) - (62) % gb[1] = n * (2 + n * (-2 / 3 + n * (-2 + n * 116 / 45))); + // gb[2] = n ^ 2 * (7 / 3 + n * (-8 / 5 + n * (-227 / 45))); + // gb[3] = n ^ 3 * (56 / 15 + n * (-136 / 35)); + // gb[4] = n ^ 4 * 4279 / 630; + // + // spherical to ellipsoidal N, E, KW p.196, (69) % gtu[1] = n * (1 / 2 + n * (-2 / 3 + n * (5 / 16 + n * 41 / 180))); + // gtu[2] = n ^ 2 * (13 / 48 + n * (-3 / 5 + n * 557 / 1440)); + // gtu[3] = n ^ 3 * (61 / 240 + n * (-103 / 140)); + // gtu[4] = n ^ 4 * 49561 / 161280; + // + // ellipsoidal to spherical N, E, KW p.194, (65) % utg[1] = n * (-1 / 2 + n * (2 / 3 + n * (-37 / 96 + n * 1 / 360))); + // utg[2] = n ^ 2 * (-1 / 48 + n * (-1 / 15 + n * 437 / 1440)); + // utg[3] = n ^ 3 * (-17 / 480 + n * 37 / 840); + // utg[4] = n ^ 4 * (-4397 / 161280); + // + // With f = 1 / 297 we get + + arma::colvec bg = {-3.37077907e-3, + 4.73444769e-6, + -8.29914570e-9, + 1.58785330e-11}; + + arma::colvec gb = {3.37077588e-3, + 6.62769080e-6, + 1.78718601e-8, + 5.49266312e-11}; + + arma::colvec gtu = {8.41275991e-4, + 7.67306686e-7, + 1.21291230e-9, + 2.48508228e-12}; + + arma::colvec utg = {-8.41276339e-4, + -5.95619298e-8, + -1.69485209e-10, + -2.20473896e-13}; + + // Ellipsoidal latitude, longitude to spherical latitude, longitude + bool neg_geo = false; + + if (B < 0.0) neg_geo = true; + + double Bg_r = fabs(B); + double res_clensin = clsin(bg, 4, 2.0 * Bg_r); + Bg_r = Bg_r + res_clensin; + L0 = L0 * STRP_PI / 180.0; + double Lg_r = L - L0; + + // Spherical latitude, longitude to complementary spherical latitude % i.e.spherical N, E + double cos_BN = cos(Bg_r); + double Np = atan2(sin(Bg_r), cos(Lg_r) * cos_BN); + double Ep = atanh(sin(Lg_r) * cos_BN); + + // Spherical normalized N, E to ellipsoidal N, E + Np = 2.0 * Np; + Ep = 2.0 * Ep; + + double dN; + double dE; + clksin(gtu, 4, Np, Ep, &dN, &dE); + Np = Np / 2.0; + Ep = Ep / 2.0; + Np = Np + dN; + Ep = Ep + dE; + double N = Q_n * Np; + double E = Q_n * Ep + E0; + if (neg_geo) + { + N = -N + 20000000.0; + } + r_enu(0) = E; + r_enu(1) = N; + r_enu(2) = U; +} + + +double clsin(const arma::colvec &ar, int degree, double argument) +{ + // Clenshaw summation of sinus of argument. + // + // result = clsin(ar, degree, argument); + // + // Originally written in Matlab by Kai Borre + // Implemented in C++ by J.Arribas + + double cos_arg = 2.0 * cos(argument); + double hr1 = 0.0; + double hr = 0.0; + double hr2; + for (int t = degree; t > 0; t--) + { + hr2 = hr1; + hr1 = hr; + hr = ar(t - 1) + cos_arg * hr1 - hr2; + } + + return (hr * sin(argument)); +} + + +void clksin(const arma::colvec &ar, int degree, double arg_real, double arg_imag, double *re, double *im) +{ + // Clenshaw summation of sinus with complex argument + // [re, im] = clksin(ar, degree, arg_real, arg_imag); + // + // Originally written in Matlab by Kai Borre + // Implemented in C++ by J.Arribas + + double sin_arg_r = sin(arg_real); + double cos_arg_r = cos(arg_real); + double sinh_arg_i = sinh(arg_imag); + double cosh_arg_i = cosh(arg_imag); + + double r = 2.0 * cos_arg_r * cosh_arg_i; + double i = -2.0 * sin_arg_r * sinh_arg_i; + + double hr1 = 0.0; + double hr = 0.0; + double hi1 = 0.0; + double hi = 0.0; + double hi2; + double hr2; + for (int t = degree; t > 0; t--) + { + hr2 = hr1; + hr1 = hr; + hi2 = hi1; + hi1 = hi; + double z = ar(t - 1) + r * hr1 - i * hi - hr2; + hi = i * hr1 + r * hi1 - hi2; + hr = z; + } + + r = sin_arg_r * cosh_arg_i; + i = cos_arg_r * sinh_arg_i; + + *re = r * hr - i * hi; + *im = r * hi + i * hr; +} + + +int findUtmZone(double latitude_deg, double longitude_deg) +{ + // Function finds the UTM zone number for given longitude and latitude. + // The longitude value must be between -180 (180 degree West) and 180 (180 + // degree East) degree. The latitude must be within -80 (80 degree South) and + // 84 (84 degree North). + // + // utmZone = findUtmZone(latitude, longitude); + // + // Latitude and longitude must be in decimal degrees (e.g. 15.5 degrees not + // 15 deg 30 min). + // + // Originally written in Matlab by Darius Plausinaitis + // Implemented in C++ by J.Arribas + + // Check value bounds + if ((longitude_deg > 180.0) || (longitude_deg < -180.0)) + std::cout << "Longitude value exceeds limits (-180:180).\n"; + + if ((latitude_deg > 84.0) || (latitude_deg < -80.0)) + std::cout << "Latitude value exceeds limits (-80:84).\n"; + + // + // Find zone + // + + // Start at 180 deg west = -180 deg + int utmZone = floor((180 + longitude_deg) / 6) + 1; + + // Correct zone numbers for particular areas + if (latitude_deg > 72.0) + { + // Corrections for zones 31 33 35 37 + if ((longitude_deg >= 0.0) && (longitude_deg < 9.0)) + { + utmZone = 31; + } + else if ((longitude_deg >= 9.0) && (longitude_deg < 21.0)) + { + utmZone = 33; + } + else if ((longitude_deg >= 21.0) && (longitude_deg < 33.0)) + { + utmZone = 35; + } + else if ((longitude_deg >= 33.0) && (longitude_deg < 42.0)) + { + utmZone = 37; + } + } + else if ((latitude_deg >= 56.0) && (latitude_deg < 64.0)) + { + // Correction for zone 32 + if ((longitude_deg >= 3.0) && (longitude_deg < 12.0)) + utmZone = 32; + } + return utmZone; +} diff --git a/src/algorithms/libs/geofunctions.h b/src/algorithms/libs/geofunctions.h new file mode 100644 index 000000000..677dc4a1d --- /dev/null +++ b/src/algorithms/libs/geofunctions.h @@ -0,0 +1,184 @@ +/*! + * \file geofunctions.h + * \brief A set of coordinate transformations functions and helpers, + * some of them migrated from MATLAB, for geographic information systems. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GEOFUNCTIONS_H +#define GNSS_SDR_GEOFUNCTIONS_H + +#include + +arma::mat Skew_symmetric(const arma::vec &a); //!< Calculates skew-symmetric matrix + +double WGS84_g0(double Lat_rad); + +double WGS84_geocentric_radius(double Lat_geodetic_rad); + +/*! + * \brief Transformation of vector dx into topocentric coordinate + * system with origin at x + * Inputs: + * x - vector origin coordinates (in ECEF system [X; Y; Z;]) + * dx - vector ([dX; dY; dZ;]). + * + * Outputs: + * D - vector length. Units like the input + * Az - azimuth from north positive clockwise, degrees + * El - elevation angle, degrees + * + * Based on a Matlab function by Kai Borre + */ +int topocent(double *Az, double *El, double *D, const arma::vec &x, const arma::vec &dx); + +/*! + * \brief Subroutine to calculate geodetic coordinates latitude, longitude, + * height given Cartesian coordinates X,Y,Z, and reference ellipsoid + * values semi-major axis (a) and the inverse of flattening (finv). + * + * The output units of angular quantities will be in decimal degrees + * (15.5 degrees not 15 deg 30 min). The output units of h will be the + * same as the units of X,Y,Z,a. + * + * Inputs: + * a - semi-major axis of the reference ellipsoid + * finv - inverse of flattening of the reference ellipsoid + * X,Y,Z - Cartesian coordinates + * + * Outputs: + * dphi - latitude + * dlambda - longitude + * h - height above reference ellipsoid + * + * Based in a Matlab function by Kai Borre + */ +int togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z); + +arma::mat Gravity_ECEF(const arma::vec &r_eb_e); //!< Calculates acceleration due to gravity resolved about ECEF-frame + +/*! + * \brief Conversion of Cartesian coordinates (X,Y,Z) to geographical + * coordinates (latitude, longitude, h) on a selected reference ellipsoid. + * + * Choices of Reference Ellipsoid for Geographical Coordinates + * 0. International Ellipsoid 1924 + * 1. International Ellipsoid 1967 + * 2. World Geodetic System 1972 + * 3. Geodetic Reference System 1980 + * 4. World Geodetic System 1984 + */ +arma::vec cart2geo(const arma::vec &XYZ, int elipsoid_selection); + +arma::vec LLH_to_deg(const arma::vec &LLH); + +double degtorad(double angleInDegrees); + +double radtodeg(double angleInRadians); + +double mstoknotsh(double MetersPerSeconds); + +double mstokph(double Kph); + +arma::vec CTM_to_Euler(const arma::mat &C); + +arma::mat Euler_to_CTM(const arma::vec &eul); + +void ECEF_to_Geo(const arma::vec &r_eb_e, const arma::vec &v_eb_e, const arma::mat &C_b_e, arma::vec &LLH, arma::vec &v_eb_n, arma::mat &C_b_n); + + +/*! + * \brief From Geographic to ECEF coordinates + * + * Inputs: + * LLH latitude (rad), longitude (rad), height (m) + * v_eb_n velocity of body frame w.r.t. ECEF frame, resolved along + * north, east, and down (m/s) + * C_b_n body-to-NED coordinate transformation matrix + * + * Outputs: + * r_eb_e Cartesian position of body frame w.r.t. ECEF frame, resolved + * along ECEF-frame axes (m) + * v_eb_e velocity of body frame w.r.t. ECEF frame, resolved along + * ECEF-frame axes (m/s) + * C_b_e body-to-ECEF-frame coordinate transformation matrix + * + */ +void Geo_to_ECEF(const arma::vec &LLH, const arma::vec &v_eb_n, const arma::mat &C_b_n, arma::vec &r_eb_e, arma::vec &v_eb_e, arma::mat &C_b_e); + + +/*! + * \brief Converts curvilinear to Cartesian position and velocity + * resolving axes from NED to ECEF + * This function created 11/4/2012 by Paul Groves + * + * Inputs: + * L_b latitude (rad) + * lambda_b longitude (rad) + * h_b height (m) + * v_eb_n velocity of body frame w.r.t. ECEF frame, resolved along + * north, east, and down (m/s) + * + * Outputs: + * r_eb_e Cartesian position of body frame w.r.t. ECEF frame, resolved + * along ECEF-frame axes (m) + * v_eb_e velocity of body frame w.r.t. ECEF frame, resolved along + * ECEF-frame axes (m/s) + */ +void pv_Geo_to_ECEF(double L_b, double lambda_b, double h_b, const arma::vec &v_eb_n, arma::vec &r_eb_e, arma::vec &v_eb_e); + + +/*! + * \brief The Haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes. + */ +double great_circle_distance(double lat1, double lon1, double lat2, double lon2); + + +/*! + * \brief Transformation of ECEF (X,Y,Z) to (E,N,U) in UTM, zone 'zone'. + */ +void cart2utm(const arma::vec &r_eb_e, int zone, arma::vec &r_enu); + + +/*! + * \brief Function finds the UTM zone number for given longitude and latitude. + */ +int findUtmZone(double latitude_deg, double longitude_deg); + + +/*! + * \brief Clenshaw summation of sinus of argument. + */ +double clsin(const arma::colvec &ar, int degree, double argument); + + +/*! + * \brief Clenshaw summation of sinus with complex argument. + */ +void clksin(const arma::colvec &ar, int degree, double arg_real, double arg_imag, double *re, double *im); + +#endif diff --git a/src/algorithms/libs/glonass_l1_signal_processing.cc b/src/algorithms/libs/glonass_l1_signal_processing.cc new file mode 100644 index 000000000..8707985b4 --- /dev/null +++ b/src/algorithms/libs/glonass_l1_signal_processing.cc @@ -0,0 +1,152 @@ +/*! + * \file glonass_l1_signal_processing.cc + * \brief This class implements various functions for GLONASS L1 CA signals + * \author Javier Arribas, 2011. jarribas(at)cttc.es + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_signal_processing.h" + +auto auxCeil = [](float x) { return static_cast(static_cast((x) + 1)); }; + +void glonass_l1_ca_code_gen_complex(std::complex* _dest, /* int32_t _prn,*/ uint32_t _chip_shift) +{ + const uint32_t _code_length = 511; + bool G1[_code_length]; + bool G1_register[9]; + bool feedback1; + bool aux; + uint32_t delay; + uint32_t lcv, lcv2; + + for (lcv = 0; lcv < 9; lcv++) + { + G1_register[lcv] = true; + } + + /* Generate G1 Register */ + for (lcv = 0; lcv < _code_length; lcv++) + { + G1[lcv] = G1_register[2]; + + feedback1 = G1_register[4] ^ G1_register[0]; + + for (lcv2 = 0; lcv2 < 8; lcv2++) + { + G1_register[lcv2] = G1_register[lcv2 + 1]; + } + + G1_register[8] = feedback1; + } + + /* Generate PRN from G1 Register */ + for (lcv = 0; lcv < _code_length; lcv++) + { + aux = G1[lcv]; + if (aux == true) + { + _dest[lcv] = std::complex(1, 0); + } + else + { + _dest[lcv] = std::complex(-1, 0); + } + } + + /* Set the delay */ + delay = _code_length; + delay += _chip_shift; + delay %= _code_length; + + /* Generate PRN from G1 and G2 Registers */ + for (lcv = 0; lcv < _code_length; lcv++) + { + aux = G1[(lcv + _chip_shift) % _code_length]; + if (aux == true) + { + _dest[lcv] = std::complex(1, 0); + } + else + { + _dest[lcv] = std::complex(-1, 0); + } + delay++; + delay %= _code_length; + } +} + + +/* + * Generates complex GLONASS L1 C/A code for the desired SV ID and sampled to specific sampling frequency + */ +void glonass_l1_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift) +{ + // This function is based on the GNU software GPS for MATLAB in the Kay Borre book + std::complex _code[511]; + int32_t _samplesPerCode, _codeValueIndex; + float _ts; + float _tc; + float aux; + const int32_t _codeFreqBasis = 511000; //Hz + const int32_t _codeLength = 511; + + //--- Find number of samples per spreading code ---------------------------- + _samplesPerCode = static_cast(static_cast(_fs) / static_cast(_codeFreqBasis / _codeLength)); + + //--- Find time constants -------------------------------------------------- + _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _tc = 1.0 / static_cast(_codeFreqBasis); // C/A chip period in sec + glonass_l1_ca_code_gen_complex(_code, _chip_shift); //generate C/A code 1 sample per chip + + for (int32_t i = 0; i < _samplesPerCode; i++) + { + //=== Digitizing ======================================================= + + //--- Make index array to read C/A code values ------------------------- + // The length of the index array depends on the sampling frequency - + // number of samples per millisecond (because one C/A code period is one + // millisecond). + + // _codeValueIndex = ceil((_ts * ((float)i + 1)) / _tc) - 1; + aux = (_ts * (i + 1)) / _tc; + _codeValueIndex = auxCeil(aux) - 1; + + //--- Make the digitized version of the C/A code ----------------------- + // The "upsampled" code is made by selecting values form the CA code + // chip array (caCode) for the time instances of each sample. + if (i == _samplesPerCode - 1) + { + //--- Correct the last index (due to number rounding issues) ----------- + _dest[i] = _code[_codeLength - 1]; + } + else + { + _dest[i] = _code[_codeValueIndex]; //repeat the chip -> upsample + } + } +} diff --git a/src/algorithms/libs/glonass_l1_signal_processing.h b/src/algorithms/libs/glonass_l1_signal_processing.h new file mode 100644 index 000000000..0b1a26cfc --- /dev/null +++ b/src/algorithms/libs/glonass_l1_signal_processing.h @@ -0,0 +1,48 @@ +/*! + * \file glonass_l1_signal_processing.h + * \brief This class implements various functions for GLONASS L1 CA signals + * \author Gabriel Araujo, 2017. gabriel.araujo(at)ieee.org + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_SDR_SIGNAL_PROCESSING_H_ +#define GNSS_SDR_GLONASS_SDR_SIGNAL_PROCESSING_H_ + +#include +#include + +//!Generates complex GLONASS L1 C/A code for the desired SV ID and code shift, and sampled to specific sampling frequency +void glonass_l1_ca_code_gen_complex(std::complex* _dest, /*int32_t _prn,*/ uint32_t _chip_shift); + +//! Generates N complex GLONASS L1 C/A codes for the desired SV ID and code shift +void glonass_l1_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift, uint32_t _ncodes); + +//! Generates complex GLONASS L1 C/A code for the desired SV ID and code shift +void glonass_l1_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift); + +#endif /* GNSS_SDR_GLONASS_SDR_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/glonass_l2_signal_processing.cc b/src/algorithms/libs/glonass_l2_signal_processing.cc new file mode 100644 index 000000000..491b0e735 --- /dev/null +++ b/src/algorithms/libs/glonass_l2_signal_processing.cc @@ -0,0 +1,152 @@ +/*! + * \file glonass_l2_signal_processing.cc + * \brief This class implements various functions for GLONASS L2 CA signals + * \author Damian Miralles, 2018, dmiralles2009(at)gmail.com + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_signal_processing.h" + +auto auxCeil = [](float x) { return static_cast(static_cast((x) + 1)); }; + +void glonass_l2_ca_code_gen_complex(std::complex* _dest, /* int32_t _prn,*/ uint32_t _chip_shift) +{ + const uint32_t _code_length = 511; + bool G1[_code_length]; + bool G1_register[9]; + bool feedback1; + bool aux; + uint32_t delay; + uint32_t lcv, lcv2; + + for (lcv = 0; lcv < 9; lcv++) + { + G1_register[lcv] = true; + } + + /* Generate G1 Register */ + for (lcv = 0; lcv < _code_length; lcv++) + { + G1[lcv] = G1_register[2]; + + feedback1 = G1_register[4] ^ G1_register[0]; + + for (lcv2 = 0; lcv2 < 8; lcv2++) + { + G1_register[lcv2] = G1_register[lcv2 + 1]; + } + + G1_register[8] = feedback1; + } + + /* Generate PRN from G1 Register */ + for (lcv = 0; lcv < _code_length; lcv++) + { + aux = G1[lcv]; + if (aux == true) + { + _dest[lcv] = std::complex(1, 0); + } + else + { + _dest[lcv] = std::complex(-1, 0); + } + } + + /* Set the delay */ + delay = _code_length; + delay += _chip_shift; + delay %= _code_length; + + /* Generate PRN from G1 and G2 Registers */ + for (lcv = 0; lcv < _code_length; lcv++) + { + aux = G1[(lcv + _chip_shift) % _code_length]; + if (aux == true) + { + _dest[lcv] = std::complex(1, 0); + } + else + { + _dest[lcv] = std::complex(-1, 0); + } + delay++; + delay %= _code_length; + } +} + + +/* + * Generates complex GLONASS L2 C/A code for the desired SV ID and sampled to specific sampling frequency + */ +void glonass_l2_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift) +{ + // This function is based on the GNU software GPS for MATLAB in the Kay Borre book + std::complex _code[511]; + int32_t _samplesPerCode, _codeValueIndex; + float _ts; + float _tc; + float aux; + const int32_t _codeFreqBasis = 511000; //Hz + const int32_t _codeLength = 511; + + //--- Find number of samples per spreading code ---------------------------- + _samplesPerCode = static_cast(static_cast(_fs) / static_cast(_codeFreqBasis / _codeLength)); + + //--- Find time constants -------------------------------------------------- + _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _tc = 1.0 / static_cast(_codeFreqBasis); // C/A chip period in sec + glonass_l2_ca_code_gen_complex(_code, _chip_shift); //generate C/A code 1 sample per chip + + for (int32_t i = 0; i < _samplesPerCode; i++) + { + //=== Digitizing ======================================================= + + //--- Make index array to read C/A code values ------------------------- + // The length of the index array depends on the sampling frequency - + // number of samples per millisecond (because one C/A code period is one + // millisecond). + + // _codeValueIndex = ceil((_ts * ((float)i + 1)) / _tc) - 1; + aux = (_ts * (i + 1)) / _tc; + _codeValueIndex = auxCeil(aux) - 1; + + //--- Make the digitized version of the C/A code ----------------------- + // The "upsampled" code is made by selecting values form the CA code + // chip array (caCode) for the time instances of each sample. + if (i == _samplesPerCode - 1) + { + //--- Correct the last index (due to number rounding issues) ----------- + _dest[i] = _code[_codeLength - 1]; + } + else + { + _dest[i] = _code[_codeValueIndex]; //repeat the chip -> upsample + } + } +} diff --git a/src/algorithms/libs/glonass_l2_signal_processing.h b/src/algorithms/libs/glonass_l2_signal_processing.h new file mode 100644 index 000000000..7c798f45a --- /dev/null +++ b/src/algorithms/libs/glonass_l2_signal_processing.h @@ -0,0 +1,48 @@ +/*! + * \file glonass_l2_signal_processing.h + * \brief This class implements various functions for GLONASS L2 CA signals + * \author Damian Miralles, 2018, dmiralles2009(at)gmail.com + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_SIGNAL_PROCESSING_H_ +#define GNSS_SDR_GLONASS_L2_SIGNAL_PROCESSING_H_ + +#include +#include + +//!Generates complex GLONASS L2 C/A code for the desired SV ID and code shift, and sampled to specific sampling frequency +void glonass_l2_ca_code_gen_complex(std::complex* _dest, /*int32_t _prn,*/ uint32_t _chip_shift); + +//! Generates N complex GLONASS L2 C/A codes for the desired SV ID and code shift +void glonass_l2_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift, uint32_t _ncodes); + +//! Generates complex GLONASS L2 C/A code for the desired SV ID and code shift +void glonass_l2_ca_code_gen_complex_sampled(std::complex* _dest, /* uint32_t _prn,*/ int32_t _fs, uint32_t _chip_shift); + +#endif /* GNSS_SDR_GLONASS_L2_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/gnss_circular_deque.h b/src/algorithms/libs/gnss_circular_deque.h new file mode 100644 index 000000000..23d89752b --- /dev/null +++ b/src/algorithms/libs/gnss_circular_deque.h @@ -0,0 +1,136 @@ +/*! + * \file gnss_circular_deque.h + * \brief This class implements a circular deque for Gnss_Synchro + * + * \author Antonio Ramos, 2018. antonio.ramosdet(at)gmail.com + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CIRCULAR_DEQUE_H_ +#define GNSS_SDR_CIRCULAR_DEQUE_H_ + +#include +#include + +template +class Gnss_circular_deque +{ +public: + Gnss_circular_deque(); // Default constructor + Gnss_circular_deque(const unsigned int max_size, const unsigned int nchann); // nchann = number of channels; max_size = channel capacity + unsigned int size(const unsigned int ch); // Returns the number of available elements in a channel + T& at(const unsigned int ch, const unsigned int pos); // Returns a reference to an element + T& front(const unsigned int ch); // Returns a reference to the first element in the deque + T& back(const unsigned int ch); // Returns a reference to the last element in the deque + void push_back(const unsigned int ch, const T& new_data); // Inserts an element at the end of the deque + void pop_front(const unsigned int ch); // Removes the first element of the deque + void clear(const unsigned int ch); // Removes all the elements of the deque (Sets size to 0). Capacity is not modified + void reset(const unsigned int max_size, const unsigned int nchann); // Removes all the elements in all the channels. Re-sets the number of channels and their capacity + void reset(); // Removes all the channels (Sets nchann to 0) + +private: + std::vector> d_data; +}; + + +template +Gnss_circular_deque::Gnss_circular_deque() +{ + reset(); +} + +template +Gnss_circular_deque::Gnss_circular_deque(const unsigned int max_size, const unsigned int nchann) +{ + reset(max_size, nchann); +} + +template +unsigned int Gnss_circular_deque::size(const unsigned int ch) +{ + return d_data.at(ch).size(); +} + +template +T& Gnss_circular_deque::back(const unsigned int ch) +{ + return d_data.at(ch).back(); +} + + +template +T& Gnss_circular_deque::front(const unsigned int ch) +{ + return d_data.at(ch).front(); +} + + +template +T& Gnss_circular_deque::at(const unsigned int ch, const unsigned int pos) +{ + return d_data.at(ch).at(pos); +} + +template +void Gnss_circular_deque::clear(const unsigned int ch) +{ + d_data.at(ch).clear(); +} + +template +void Gnss_circular_deque::reset(const unsigned int max_size, const unsigned int nchann) +{ + d_data.clear(); + if (max_size > 0 and nchann > 0) + { + for (unsigned int i = 0; i < nchann; i++) + { + d_data.push_back(boost::circular_buffer(max_size)); + } + } +} + +template +void Gnss_circular_deque::reset() +{ + d_data.clear(); +} + +template +void Gnss_circular_deque::pop_front(const unsigned int ch) +{ + d_data.at(ch).pop_front(); +} + +template +void Gnss_circular_deque::push_back(const unsigned int ch, const T& new_data) +{ + d_data.at(ch).push_back(new_data); +} + +#endif /* GNSS_SDR_CIRCULAR_DEQUE_H_ */ diff --git a/src/algorithms/libs/gnss_sdr_create_directory.cc b/src/algorithms/libs/gnss_sdr_create_directory.cc new file mode 100644 index 000000000..d0af41952 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_create_directory.cc @@ -0,0 +1,85 @@ +/*! + * \file gnss_sdr_create_directory.cc + * \brief Create a directory + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gnss_sdr_create_directory.h" +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem +#include + + +bool gnss_sdr_create_directory(const std::string& foldername) +{ + std::string new_folder; + for (auto& folder : boost::filesystem::path(foldername)) + { + new_folder += folder.string(); + boost::system::error_code ec; + if (!boost::filesystem::exists(new_folder)) + { + try + { + if (!boost::filesystem::create_directory(new_folder, ec)) + { + return false; + } + } + catch (std::exception& e) + { + return false; + } + } + new_folder += boost::filesystem::path::preferred_separator; + } + + // Check if we have writing permissions + std::string test_file = foldername + "/test_file.txt"; + std::ofstream os_test_file; + os_test_file.open(test_file.c_str(), std::ios::out | std::ios::binary); + + if (os_test_file.is_open()) + { + boost::system::error_code ec; + os_test_file.close(); + try + { + boost::filesystem::remove(test_file, ec); + } + catch (std::exception& e) + { + return false; + } + return true; + } + + os_test_file.close(); + return false; +} diff --git a/src/algorithms/libs/gnss_sdr_create_directory.h b/src/algorithms/libs/gnss_sdr_create_directory.h new file mode 100644 index 000000000..23de7ec14 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_create_directory.h @@ -0,0 +1,38 @@ +/*! + * \file gnss_sdr_create_directory.h + * \brief Create a directory + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GNSS_SDR_CREATE_DIRECTORY_H_ +#define GNSS_SDR_GNSS_SDR_CREATE_DIRECTORY_H_ + +#include + +bool gnss_sdr_create_directory(const std::string& foldername); + +#endif diff --git a/src/algorithms/libs/gnss_sdr_flags.cc b/src/algorithms/libs/gnss_sdr_flags.cc new file mode 100644 index 000000000..3eba67822 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_flags.cc @@ -0,0 +1,200 @@ +/*! + * \file gnss_sdr_flags.cc + * \brief Helper file for gnss-sdr commandline flags + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gnss_sdr_flags.h" +#include // for exists +#include +#include +#include + +DEFINE_string(c, "-", "Path to the configuration file (if set, overrides --config_file)."); + +DEFINE_string(config_file, std::string(GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/default.conf"), + "Path to the configuration file."); + +DEFINE_string(s, "-", + "If defined, path to the file containing the signal samples (overrides the configuration file and --signal_source)."); + +DEFINE_string(signal_source, "-", + "If defined, path to the file containing the signal samples (overrides the configuration file)."); + +DEFINE_int32(doppler_max, 0, "If defined, sets the maximum Doppler value in the search grid, in Hz (overrides the configuration file)."); + +DEFINE_int32(doppler_step, 0, "If defined, sets the frequency step in the search grid, in Hz (overrides the configuration file)."); + +DEFINE_int32(cn0_samples, 20, "Number of correlator outputs used for CN0 estimation."); + +DEFINE_int32(cn0_min, 25, "Minimum valid CN0 (in dB-Hz)."); + +DEFINE_int32(max_lock_fail, 50, "Maximum number of lock failures before dropping a satellite."); + +DEFINE_double(carrier_lock_th, 0.85, "Carrier lock threshold (in rad)."); + +DEFINE_string(RINEX_version, "-", "If defined, specifies the RINEX version (2.11 or 3.02). Overrides the configuration file."); + +DEFINE_double(dll_bw_hz, 0.0, "If defined, bandwidth of the DLL low pass filter, in Hz (overrides the configuration file)."); + +DEFINE_double(pll_bw_hz, 0.0, "If defined, bandwidth of the PLL low pass filter, in Hz (overrides the configuration file)."); + + +#if GFLAGS_GREATER_2_0 + +static bool ValidateC(const char* flagname, const std::string& value) +{ + if (boost::filesystem::exists(value) or value == "-") // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ". The file '" << value << "' does not exist." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateConfigFile(const char* flagname, const std::string& value) +{ + if (boost::filesystem::exists(value) or value == std::string(GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/default.conf")) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ". The file '" << value << "' does not exist." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateS(const char* flagname, const std::string& value) +{ + if (boost::filesystem::exists(value) or value == "-") // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ". The file '" << value << "' does not exist." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateSignalSource(const char* flagname, const std::string& value) +{ + if (boost::filesystem::exists(value) or value == "-") // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ". The file '" << value << "' does not exist." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateDopplerMax(const char* flagname, int32_t value) +{ + const int32_t max_value = 1000000; + if (value >= 0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " Hz." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateDopplerStep(const char* flagname, int32_t value) +{ + const int32_t max_value = 10000; + if (value >= 0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " Hz." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateCn0Samples(const char* flagname, int32_t value) +{ + const int32_t max_value = 10000; + if (value > 0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " samples." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateCn0Min(const char* flagname, int32_t value) +{ + const int32_t max_value = 100; + if (value > 0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " dB-Hz." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateMaxLockFail(const char* flagname, int32_t value) +{ + const int32_t max_value = 10000; + if (value > 0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " fails." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateCarrierLockTh(const char* flagname, double value) +{ + const double max_value = 1.508; + if (value > 0.0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " rad." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidateDllBw(const char* flagname, double value) +{ + const double max_value = 10000.0; + if (value >= 0.0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " Hz." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +static bool ValidatePllBw(const char* flagname, double value) +{ + const double max_value = 10000.0; + if (value >= 0.0 && value < max_value) // value is ok + return true; + std::cout << "Invalid value for flag -" << flagname << ": " << value << ". Allowed range is 0 < " << flagname << " < " << max_value << " Hz." << std::endl; + std::cout << "GNSS-SDR program ended." << std::endl; + return false; +} + +DEFINE_validator(c, &ValidateC); +DEFINE_validator(config_file, &ValidateConfigFile); +DEFINE_validator(s, &ValidateS); +DEFINE_validator(signal_source, &ValidateSignalSource); +DEFINE_validator(doppler_max, &ValidateDopplerMax); +DEFINE_validator(doppler_step, &ValidateDopplerStep); +DEFINE_validator(cn0_samples, &ValidateCn0Samples); +DEFINE_validator(cn0_min, &ValidateCn0Min); +DEFINE_validator(max_lock_fail, &ValidateMaxLockFail); +DEFINE_validator(carrier_lock_th, &ValidateCarrierLockTh); +DEFINE_validator(dll_bw_hz, &ValidateDllBw); +DEFINE_validator(pll_bw_hz, &ValidatePllBw); + + +#endif diff --git a/src/algorithms/libs/gnss_sdr_flags.h b/src/algorithms/libs/gnss_sdr_flags.h new file mode 100644 index 000000000..bb97ca2dd --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_flags.h @@ -0,0 +1,62 @@ +/*! + * \file gnss_sdr_flags.h + * \brief Helper file for gnss-sdr commandline flags + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FLAGS_H_ +#define GNSS_SDR_FLAGS_H_ + + +#include + +DECLARE_string(c); //. + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_sdr_fpga_sample_counter.h" +#include "gnss_synchro.h" +#include +#include +#include +#include +#include // libraries used by the GIPO +#include +#include +#include // libraries used by the GIPO + +#define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map +#define TEST_REG_SANITY_CHECK 0x55AA // value to check the presence of the test register (to detect the hw) + +gnss_sdr_fpga_sample_counter::gnss_sdr_fpga_sample_counter( + double _fs, + int32_t _interval_ms) : gr::block("fpga_fpga_sample_counter", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + message_port_register_out(pmt::mp("fpga_sample_counter")); + set_max_noutput_items(1); + interval_ms = _interval_ms; + fs = _fs; + //printf("CREATOR fs = %f\n", fs); + //printf("CREATOR interval_ms = %" PRIu32 "\n", interval_ms); + samples_per_output = std::round(fs * static_cast(interval_ms) / 1e3); + //printf("CREATOR samples_per_output = %" PRIu32 "\n", samples_per_output); + //todo: Load here the hardware counter register with this amount of samples. It should produce an + //interrupt every samples_per_output count. + //The hardware timer must keep always interrupting the PS. It must not wait for the interrupt to + //be served. + open_device(); + + sample_counter = 0ULL; + current_T_rx_ms = 0; + current_s = 0; + current_m = 0; + current_h = 0; + current_days = 0; + report_interval_ms = 1000; // default reporting 1 second + flag_enable_send_msg = false; // enable it for reporting time with asynchronous message + flag_m = false; + flag_h = false; + flag_days = false; +} + + +gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms) +{ + gnss_sdr_fpga_sample_counter_sptr fpga_sample_counter_(new gnss_sdr_fpga_sample_counter(_fs, _interval_ms)); + return fpga_sample_counter_; +} + + +// Called by gnuradio to enable drivers, etc for i/o devices. +bool gnss_sdr_fpga_sample_counter::start() +{ + //todo: place here the RE-INITIALIZATION routines. This function will be called by GNURadio at every start of the flowgraph. + + // configure the number of samples per output in the FPGA and enable the interrupts + configure_samples_per_output(samples_per_output); + + // return true if everything is ok. + return true; +} + + +// Called by GNURadio to disable drivers, etc for i/o devices. +bool gnss_sdr_fpga_sample_counter::stop() +{ + //todo: place here the routines to stop the associated hardware (if needed).This function will be called by GNURadio at every stop of the flowgraph. + // return true if everything is ok. + close_device(); + + return true; +} + + +int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__((unused)), + __attribute__((unused)) gr_vector_int &ninput_items, + __attribute__((unused)) gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + //todo: Call here a function that waits for an interrupt. Do not open a thread, + //it must be a simple call to a BLOCKING function. + // The function will return the actual absolute sample count of the internal counter of the timmer. + // store the sample count in class member sample_counter + // Possible problem: what happen if the PS is overloaded and gnuradio does not call this function + // with the sufficient rate to catch all the interrupts in the counter. To be evaluated later. + + uint32_t counter = wait_for_interrupt_and_read_counter(); + uint64_t samples_passed = 2 * static_cast(samples_per_output) - static_cast(counter); // ellapsed samples + //printf("============================================ interrupter : samples_passed = %" PRIu64 "\n", samples_passed); + // Note: at this moment the sample counter is implemented as a sample counter that decreases to zero and then it is automatically + // reloaded again and keeps counter. It is done in this way to minimize the logic in the FPGA and maximize the FPGA clock performance + // (it takes less resources and latency in the FPGA to compare a number against a fixed value like zero than to compare it to a programmable + // variable number). + + sample_counter = sample_counter + samples_passed; //samples_per_output; + auto *out = reinterpret_cast(output_items[0]); + out[0] = Gnss_Synchro(); + out[0].Flag_valid_symbol_output = false; + out[0].Flag_valid_word = false; + out[0].Channel_ID = -1; + out[0].fs = fs; + if ((current_T_rx_ms % report_interval_ms) == 0) + { + //printf("time to print sample_counter = %" PRIu64 "\n", sample_counter); + //printf("time to print current Tx ms : %" PRIu64 "\n", current_T_rx_ms); + //printf("time to print report_interval_ms : %" PRIu32 "\n", report_interval_ms); + //printf("time to print %f\n", (current_T_rx_ms % report_interval_ms)); + current_s++; + if ((current_s % 60) == 0) + { + current_s = 0; + current_m++; + flag_m = true; + if ((current_m % 60) == 0) + { + current_m = 0; + current_h++; + flag_h = true; + if ((current_h % 24) == 0) + { + current_h = 0; + current_days++; + flag_days = true; + } + } + } + + if (flag_days) + { + std::string day; + if (current_days == 1) + { + day = " day "; + } + else + { + day = " days "; + } + std::cout << "Current receiver time: " << current_days << day << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_h) + { + std::cout << "Current receiver time: " << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_m) + { + std::cout << "Current receiver time: " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + std::cout << "Current receiver time: " << current_s << " s" << std::endl; + } + } + } + if (flag_enable_send_msg) + { + message_port_pub(pmt::mp("receiver_time"), pmt::from_double(static_cast(current_T_rx_ms) / 1000.0)); + } + } + out[0].Tracking_sample_counter = sample_counter; + //current_T_rx_ms = (sample_counter * 1000) / samples_per_output; + current_T_rx_ms = interval_ms * (sample_counter) / samples_per_output; + return 1; +} + +uint32_t gnss_sdr_fpga_sample_counter::test_register(uint32_t writeval) +{ + uint32_t readval; + // write value to test register + map_base[3] = writeval; + // read value from test register + readval = map_base[3]; + // return read value + return readval; +} + +void gnss_sdr_fpga_sample_counter::configure_samples_per_output(uint32_t interval) +{ + // note : the counter is a 48-bit value in the HW. + //printf("============================================ total counter - interrupted interval : %" PRIu32 "\n", interval); + //uint64_t temp_interval; + //temp_interval = (interval & static_cast(0xFFFFFFFF)); + //printf("LSW counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); + //map_base[0] = static_cast(temp_interval); + map_base[0] = interval - 1; + //temp_interval = (interval >> 32) & static_cast(0xFFFFFFFF); + //printf("MSbits counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); + //map_base[1] = static_cast(temp_interval); // writing the most significant bits also enables the interrupts +} + +void gnss_sdr_fpga_sample_counter::open_device() +{ + // open communication with HW accelerator + if ((fd = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_name; + std::cout << "Counter-Intr: cannot open deviceio" << device_name << std::endl; + } + map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + if (map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; + std::cout << "Counter-Intr: cannot map deviceio" << device_name << std::endl; + } + + // sanity check : check test register + uint32_t writeval = TEST_REG_SANITY_CHECK; + uint32_t readval; + readval = gnss_sdr_fpga_sample_counter::test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Acquisition test register sanity check failed"; + } + else + { + LOG(INFO) << "Acquisition test register sanity check success!"; + //std::cout << "Acquisition test register sanity check success!" << std::endl; + } +} + +void gnss_sdr_fpga_sample_counter::close_device() +{ + //printf("=========================================== NOW closing device ...\n"); + map_base[2] = 0; // disable the generation of the interrupt in the device + + auto *aux = const_cast(map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + close(fd); +} + +uint32_t gnss_sdr_fpga_sample_counter::wait_for_interrupt_and_read_counter() +{ + int32_t irq_count; + ssize_t nb; + int32_t counter; + + // enable interrupts + int32_t reenable = 1; + write(fd, reinterpret_cast(&reenable), sizeof(int32_t)); + + // wait for interrupt + //printf("============================================ interrupter : going to wait for interupt\n"); + nb = read(fd, &irq_count, sizeof(irq_count)); + //printf("============================================ interrupter : interrupt received\n"); + //printf("interrupt received\n"); + if (nb != sizeof(irq_count)) + { + printf("acquisition module Read failed to retrieve 4 bytes!\n"); + printf("acquisition module Interrupt number %d\n", irq_count); + } + + // acknowledge the interrupt + map_base[1] = 0; // writing anything to reg 1 acknowledges the interrupt + + // add number of passed samples or read the current counter value for more accuracy + counter = samples_per_output; //map_base[0]; + return counter; +} diff --git a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h new file mode 100644 index 000000000..75b924e72 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h @@ -0,0 +1,81 @@ +/*! + * \file gnss_sdr_fpga_sample_counter.h + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#ifndef GNSS_SDR_FPGA_sample_counter_H_ +#define GNSS_SDR_FPGA_sample_counter_H_ + +#include +#include +#include + +class gnss_sdr_fpga_sample_counter; + +typedef boost::shared_ptr gnss_sdr_fpga_sample_counter_sptr; + +gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms); + +class gnss_sdr_fpga_sample_counter : public gr::block +{ +private: + gnss_sdr_fpga_sample_counter(double _fs, int32_t _interval_ms); + uint32_t test_register(uint32_t writeval); + void configure_samples_per_output(uint32_t interval); + void close_device(void); + void open_device(void); + bool start(); + bool stop(); + uint32_t wait_for_interrupt_and_read_counter(void); + uint32_t samples_per_output; + double fs; + uint64_t sample_counter; + uint32_t interval_ms; + uint64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run + uint32_t current_s; // Receiver time in seconds, modulo 60 + bool flag_m; // True if the receiver has been running for at least 1 minute + uint32_t current_m; // Receiver time in minutes, modulo 60 + bool flag_h; // True if the receiver has been running for at least 1 hour + uint32_t current_h; // Receiver time in hours, modulo 24 + bool flag_days; // True if the receiver has been running for at least 1 day + uint32_t current_days; // Receiver time in days since the beginning of the run + int32_t report_interval_ms; + bool flag_enable_send_msg; + int32_t fd; // driver descriptor + volatile uint32_t *map_base; // driver memory map + std::string device_name = "/dev/uio26"; // HW device name + +public: + friend gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /*GNSS_SDR_FPGA_sample_counter_H_*/ diff --git a/src/algorithms/libs/gnss_sdr_sample_counter.cc b/src/algorithms/libs/gnss_sdr_sample_counter.cc new file mode 100644 index 000000000..e7d939582 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_sample_counter.cc @@ -0,0 +1,145 @@ +/*! + * \file gnss_sdr_sample_counter.cc + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_sdr_sample_counter.h" +#include "gnss_synchro.h" +#include +#include +#include +#include + +gnss_sdr_sample_counter::gnss_sdr_sample_counter( + double _fs, + int32_t _interval_ms, + size_t _size) : gr::sync_decimator("sample_counter", + gr::io_signature::make(1, 1, _size), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + static_cast(std::round(_fs * static_cast(_interval_ms) / 1e3))) +{ + message_port_register_out(pmt::mp("sample_counter")); + set_max_noutput_items(1); + interval_ms = _interval_ms; + fs = _fs; + samples_per_output = std::round(fs * static_cast(interval_ms) / 1e3); + sample_counter = 0; + current_T_rx_ms = 0; + current_s = 0; + current_m = 0; + current_h = 0; + current_days = 0; + report_interval_ms = 1000; // default reporting 1 second + flag_enable_send_msg = false; // enable it for reporting time with asynchronous message + flag_m = false; + flag_h = false; + flag_days = false; +} + + +gnss_sdr_sample_counter_sptr gnss_sdr_make_sample_counter(double _fs, int32_t _interval_ms, size_t _size) +{ + gnss_sdr_sample_counter_sptr sample_counter_(new gnss_sdr_sample_counter(_fs, _interval_ms, _size)); + return sample_counter_; +} + + +int gnss_sdr_sample_counter::work(int noutput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), + gr_vector_void_star &output_items) +{ + auto *out = reinterpret_cast(output_items[0]); + out[0] = Gnss_Synchro(); + out[0].Flag_valid_symbol_output = false; + out[0].Flag_valid_word = false; + out[0].Channel_ID = -1; + out[0].fs = fs; + if ((current_T_rx_ms % report_interval_ms) == 0) + { + current_s++; + if ((current_s % 60) == 0) + { + current_s = 0; + current_m++; + flag_m = true; + if ((current_m % 60) == 0) + { + current_m = 0; + current_h++; + flag_h = true; + if ((current_h % 24) == 0) + { + current_h = 0; + current_days++; + flag_days = true; + } + } + } + + if (flag_days) + { + std::string day; + if (current_days == 1) + { + day = " day "; + } + else + { + day = " days "; + } + std::cout << "Current receiver time: " << current_days << day << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_h) + { + std::cout << "Current receiver time: " << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_m) + { + std::cout << "Current receiver time: " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + std::cout << "Current receiver time: " << current_s << " s" << std::endl; + } + } + } + if (flag_enable_send_msg) + { + message_port_pub(pmt::mp("receiver_time"), pmt::from_double(static_cast(current_T_rx_ms) / 1000.0)); + } + } + sample_counter += samples_per_output; + out[0].Tracking_sample_counter = sample_counter; + current_T_rx_ms += interval_ms; + return 1; +} diff --git a/src/algorithms/libs/gnss_sdr_sample_counter.h b/src/algorithms/libs/gnss_sdr_sample_counter.h new file mode 100644 index 000000000..8a645d9f3 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_sample_counter.h @@ -0,0 +1,74 @@ +/*! + * \file gnss_sdr_sample_counter.h + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#ifndef GNSS_SDR_SAMPLE_COUNTER_H_ +#define GNSS_SDR_SAMPLE_COUNTER_H_ + +#include +#include +#include + + +class gnss_sdr_sample_counter; + +typedef boost::shared_ptr gnss_sdr_sample_counter_sptr; + +gnss_sdr_sample_counter_sptr gnss_sdr_make_sample_counter( + double _fs, + int32_t _interval_ms, + size_t _size); + +class gnss_sdr_sample_counter : public gr::sync_decimator +{ +private: + gnss_sdr_sample_counter(double _fs, int32_t _interval_ms, size_t _size); + uint32_t samples_per_output; + double fs; + uint64_t sample_counter; + int32_t interval_ms; + int64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run + uint32_t current_s; // Receiver time in seconds, modulo 60 + bool flag_m; // True if the receiver has been running for at least 1 minute + uint32_t current_m; // Receiver time in minutes, modulo 60 + bool flag_h; // True if the receiver has been running for at least 1 hour + uint32_t current_h; // Receiver time in hours, modulo 24 + bool flag_days; // True if the receiver has been running for at least 1 day + uint32_t current_days; // Receiver time in days since the beginning of the run + int32_t report_interval_ms; + bool flag_enable_send_msg; + +public: + friend gnss_sdr_sample_counter_sptr gnss_sdr_make_sample_counter(double _fs, int32_t _interval_ms, size_t _size); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /*GNSS_SDR_SAMPLE_COUNTER_H_*/ diff --git a/src/algorithms/libs/gnss_sdr_time_counter.cc b/src/algorithms/libs/gnss_sdr_time_counter.cc new file mode 100644 index 000000000..0cd06517b --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_time_counter.cc @@ -0,0 +1,126 @@ +/*! + * \file gnss_sdr_time_counter.cc + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Antonio Ramos 2018. antonio.ramos(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_sdr_time_counter.h" +#include "gnss_synchro.h" +#include +#include +#include +#include + +gnss_sdr_time_counter::gnss_sdr_time_counter() : gr::block("time_counter", + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + set_max_noutput_items(1); + current_T_rx_ms = 0; + current_s = 0; + current_m = 0; + current_h = 0; + current_days = 0; + report_interval_ms = 1000; // default reporting 1 second + flag_m = false; + flag_h = false; + flag_days = false; +} + + +gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter() +{ + gnss_sdr_time_counter_sptr counter_(new gnss_sdr_time_counter()); + return counter_; +} + + +int gnss_sdr_time_counter::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), gr_vector_void_star &output_items) +{ + auto *out = reinterpret_cast(output_items[0]); + const auto *in = reinterpret_cast(input_items[0]); + out[0] = in[0]; + if ((current_T_rx_ms % report_interval_ms) == 0) + { + current_s++; + if ((current_s % 60) == 0) + { + current_s = 0; + current_m++; + flag_m = true; + if ((current_m % 60) == 0) + { + current_m = 0; + current_h++; + flag_h = true; + if ((current_h % 24) == 0) + { + current_h = 0; + current_days++; + flag_days = true; + } + } + } + + if (flag_days) + { + std::string day; + if (current_days == 1) + { + day = " day "; + } + else + { + day = " days "; + } + std::cout << "Current receiver time: " << current_days << day << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_h) + { + std::cout << "Current receiver time: " << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_m) + { + std::cout << "Current receiver time: " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + std::cout << "Current receiver time: " << current_s << " s" << std::endl; + } + } + } + } + current_T_rx_ms++; + consume_each(1); + return 1; +} diff --git a/src/algorithms/libs/gnss_sdr_time_counter.h b/src/algorithms/libs/gnss_sdr_time_counter.h new file mode 100644 index 000000000..870f6717c --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_time_counter.h @@ -0,0 +1,64 @@ +/*! + * \file gnss_sdr_time_counter.h + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Antonio Ramos 2018. antonio.ramosdet(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#ifndef GNSS_SDR_TIME_COUNTER_H_ +#define GNSS_SDR_TIME_COUNTER_H_ + +#include +#include +#include + +class gnss_sdr_time_counter; + +typedef boost::shared_ptr gnss_sdr_time_counter_sptr; + +gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter(); + +class gnss_sdr_time_counter : public gr::block +{ +private: + gnss_sdr_time_counter(); + int64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run + uint32_t current_s; // Receiver time in seconds, modulo 60 + bool flag_m; // True if the receiver has been running for at least 1 minute + uint32_t current_m; // Receiver time in minutes, modulo 60 + bool flag_h; // True if the receiver has been running for at least 1 hour + uint32_t current_h; // Receiver time in hours, modulo 24 + bool flag_days; // True if the receiver has been running for at least 1 day + uint32_t current_days; // Receiver time in days since the beginning of the run + int32_t report_interval_ms; + +public: + friend gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter(); + int general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), gr_vector_void_star &output_items); +}; + +#endif /*GNSS_SDR_SAMPLE_COUNTER_H_*/ diff --git a/src/algorithms/libs/gnss_sdr_valve.cc b/src/algorithms/libs/gnss_sdr_valve.cc index 981e8072c..b613f3e2b 100644 --- a/src/algorithms/libs/gnss_sdr_valve.cc +++ b/src/algorithms/libs/gnss_sdr_valve.cc @@ -2,12 +2,13 @@ * \file gnss_sdr_valve.cc * \brief Implementation of a GNU Radio block that sends a STOP message to the * control queue right after a specific number of samples have passed through it. + * \author Javier Arribas, 2018. jarribas(at)cttc.es * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,47 +26,80 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gnss_sdr_valve.h" -#include // for min -#include #include "control_message_factory.h" +#include +#include +#include // for min +#include // for memcpy +#include -gnss_sdr_valve::gnss_sdr_valve (size_t sizeof_stream_item, - unsigned long long nitems, - gr::msg_queue::sptr queue) : gr::sync_block("valve", - gr::io_signature::make(1, 1, sizeof_stream_item), - gr::io_signature::make(1, 1, sizeof_stream_item) ), - d_nitems(nitems), d_ncopied_items(0), d_queue(queue) -{} - - -boost::shared_ptr gnss_sdr_make_valve (size_t sizeof_stream_item, unsigned long long nitems, gr::msg_queue::sptr queue) +gnss_sdr_valve::gnss_sdr_valve(size_t sizeof_stream_item, + uint64_t nitems, + gr::msg_queue::sptr queue, + bool stop_flowgraph) : gr::sync_block("valve", + gr::io_signature::make(1, 1, sizeof_stream_item), + gr::io_signature::make(1, 1, sizeof_stream_item)), + d_nitems(nitems), + d_ncopied_items(0), + d_queue(std::move(queue)), + d_stop_flowgraph(stop_flowgraph) { - boost::shared_ptr valve_(new gnss_sdr_valve(sizeof_stream_item, nitems, queue)); + d_open_valve = false; +} + + +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue, bool stop_flowgraph) +{ + boost::shared_ptr valve_(new gnss_sdr_valve(sizeof_stream_item, nitems, std::move(queue), stop_flowgraph)); return valve_; } - -int gnss_sdr_valve::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue) { - if (d_ncopied_items >= d_nitems) - { - ControlMessageFactory* cmf = new ControlMessageFactory(); - d_queue->handle(cmf->GetQueueMessage(200,0)); - delete cmf; - return -1; // Done! - } - unsigned long long n = std::min(d_nitems - d_ncopied_items, (long long unsigned int)noutput_items); - if (n == 0) return 0; - memcpy (output_items[0], input_items[0], n * input_signature()->sizeof_stream_item(0)); - d_ncopied_items += n; - return n; + boost::shared_ptr valve_(new gnss_sdr_valve(sizeof_stream_item, nitems, std::move(queue), true)); + return valve_; +} + + +void gnss_sdr_valve::open_valve() +{ + d_open_valve = true; +} + + +int gnss_sdr_valve::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + if (d_open_valve == false) + { + if (d_ncopied_items >= d_nitems) + { + auto *cmf = new ControlMessageFactory(); + d_queue->handle(cmf->GetQueueMessage(200, 0)); + LOG(INFO) << "Stopping receiver, " << d_ncopied_items << " samples processed"; + delete cmf; + if (d_stop_flowgraph) + { + return -1; // Done! + } + usleep(1000000); + return 0; // do not produce or consume + } + uint64_t n = std::min(d_nitems - d_ncopied_items, static_cast(noutput_items)); + if (n == 0) return 0; + memcpy(output_items[0], input_items[0], n * input_signature()->sizeof_stream_item(0)); + d_ncopied_items += n; + return n; + } + + memcpy(output_items[0], input_items[0], noutput_items * input_signature()->sizeof_stream_item(0)); + return noutput_items; } diff --git a/src/algorithms/libs/gnss_sdr_valve.h b/src/algorithms/libs/gnss_sdr_valve.h index 7ea1d7961..19c104b99 100644 --- a/src/algorithms/libs/gnss_sdr_valve.h +++ b/src/algorithms/libs/gnss_sdr_valve.h @@ -2,11 +2,12 @@ * \file gnss_sdr_valve.h * \brief Interface of a GNU Radio block that sends a STOP message to the * control queue right after a specific number of samples have passed through it. + * \author Javier Arribas, 2018. jarribas(at)cttc.es * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,15 +34,20 @@ #ifndef GNSS_SDR_GNSS_SDR_VALVE_H_ #define GNSS_SDR_GNSS_SDR_VALVE_H_ -#include -#include -#include #include +#include +#include +#include +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, + uint64_t nitems, + gr::msg_queue::sptr queue); + +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, + uint64_t nitems, + gr::msg_queue::sptr queue, + bool stop_flowgraph); -boost::shared_ptr gnss_sdr_make_valve (size_t sizeof_stream_item, - unsigned long long nitems, - gr::msg_queue::sptr queue); /*! * \brief Implementation of a GNU Radio block that sends a STOP message to the * control queue right after a specific number of samples have passed through it. @@ -49,19 +55,28 @@ boost::shared_ptr gnss_sdr_make_valve (size_t sizeof_stream_item, class gnss_sdr_valve : public gr::sync_block { friend boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, - unsigned long long nitems, - gr::msg_queue::sptr queue); - gnss_sdr_valve (size_t sizeof_stream_item, - unsigned long long nitems, - gr::msg_queue::sptr queue); - unsigned long long d_nitems; - unsigned long long d_ncopied_items; + uint64_t nitems, + gr::msg_queue::sptr queue); + friend boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, + uint64_t nitems, + gr::msg_queue::sptr queue, + bool stop_flowgraph); + + uint64_t d_nitems; + uint64_t d_ncopied_items; gr::msg_queue::sptr d_queue; + bool d_stop_flowgraph; + bool d_open_valve; public: + gnss_sdr_valve(size_t sizeof_stream_item, + uint64_t nitems, + gr::msg_queue::sptr queue, bool stop_flowgraph); + void open_valve(); + int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif /*GNSS_SDR_GNSS_SDR_VALVE_H_*/ diff --git a/src/algorithms/libs/gnss_signal_processing.cc b/src/algorithms/libs/gnss_signal_processing.cc index 86738f062..0dea461e7 100644 --- a/src/algorithms/libs/gnss_signal_processing.cc +++ b/src/algorithms/libs/gnss_signal_processing.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,146 +26,171 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gnss_signal_processing.h" -#include #include "GPS_L1_CA.h" +#include -auto auxCeil2 = [](float x){ return static_cast(static_cast((x)+1)); }; +auto auxCeil2 = [](float x) { return static_cast(static_cast((x) + 1)); }; -void complex_exp_gen(std::complex* _dest, double _f, double _fs, unsigned int _samps) +void complex_exp_gen(std::complex* _dest, double _f, double _fs, uint32_t _samps) { gr::fxpt_nco d_nco; d_nco.set_freq((GPS_TWO_PI * _f) / _fs); - d_nco.sincos(_dest, _samps, 1); + d_nco.sincos(_dest, _samps, 1); } -void complex_exp_gen_conj(std::complex* _dest, double _f, double _fs, unsigned int _samps) +void complex_exp_gen_conj(std::complex* _dest, double _f, double _fs, uint32_t _samps) { gr::fxpt_nco d_nco; d_nco.set_freq(-(GPS_TWO_PI * _f) / _fs); - d_nco.sincos(_dest, _samps, 1); -} - -void hex_to_binary_converter(int * _dest, char _from) -{ - switch(_from) - { - case '0': - *(_dest) = 1; - *(_dest+1) = 1; - *(_dest+2) = 1; - *(_dest+3) = 1; - break; - case '1': - *(_dest) = 1; - *(_dest+1) = 1; - *(_dest+2) = 1; - *(_dest+3) = -1; - break; - case '2': - *(_dest) = 1; - *(_dest+1) = 1; - *(_dest+2) = -1; - *(_dest+3) = 1; - break; - case '3': - *(_dest) = 1; - *(_dest+1) = 1; - *(_dest+2) = -1; - *(_dest+3) = -1; - break; - case '4': - *(_dest) = 1; - *(_dest+1) = -1; - *(_dest+2) = 1; - *(_dest+3) = 1; - break; - case '5': - *(_dest) = 1; - *(_dest+1) = -1; - *(_dest+2) = 1; - *(_dest+3) = -1; - break; - case '6': - *(_dest) = 1; - *(_dest+1) = -1; - *(_dest+2) = -1; - *(_dest+3) = 1; - break; - case '7': - *(_dest) = 1; - *(_dest+1) = -1; - *(_dest+2) = -1; - *(_dest+3) = -1; - break; - case '8': - *(_dest) = -1; - *(_dest+1) = 1; - *(_dest+2) = 1; - *(_dest+3) = 1; - break; - case '9': - *(_dest) = -1; - *(_dest+1) = 1; - *(_dest+2) = 1; - *(_dest+3) = -1; - break; - case 'A': - *(_dest) = -1; - *(_dest+1) = 1; - *(_dest+2) = -1; - *(_dest+3) = 1; - break; - case 'B': - *(_dest) = -1; - *(_dest+1) = 1; - *(_dest+2) = -1; - *(_dest+3) = -1; - break; - case 'C': - *(_dest) = -1; - *(_dest+1) = -1; - *(_dest+2) = 1; - *(_dest+3) = 1; - break; - case 'D': - *(_dest) = -1; - *(_dest+1) = -1; - *(_dest+2) = 1; - *(_dest+3) = -1; - break; - case 'E': - *(_dest) = -1; - *(_dest+1) = -1; - *(_dest+2) = -1; - *(_dest+3) = 1; - break; - case 'F': - *(_dest) = -1; - *(_dest+1) = -1; - *(_dest+2) = -1; - *(_dest+3) = -1; - break; - } + d_nco.sincos(_dest, _samps, 1); } -void resampler(std::complex* _from, std::complex* _dest, float _fs_in, - float _fs_out, unsigned int _length_in, unsigned int _length_out) +void hex_to_binary_converter(int32_t* _dest, char _from) { - unsigned int _codeValueIndex; + switch (_from) + { + case '0': + *(_dest) = 1; + *(_dest + 1) = 1; + *(_dest + 2) = 1; + *(_dest + 3) = 1; + break; + case '1': + *(_dest) = 1; + *(_dest + 1) = 1; + *(_dest + 2) = 1; + *(_dest + 3) = -1; + break; + case '2': + *(_dest) = 1; + *(_dest + 1) = 1; + *(_dest + 2) = -1; + *(_dest + 3) = 1; + break; + case '3': + *(_dest) = 1; + *(_dest + 1) = 1; + *(_dest + 2) = -1; + *(_dest + 3) = -1; + break; + case '4': + *(_dest) = 1; + *(_dest + 1) = -1; + *(_dest + 2) = 1; + *(_dest + 3) = 1; + break; + case '5': + *(_dest) = 1; + *(_dest + 1) = -1; + *(_dest + 2) = 1; + *(_dest + 3) = -1; + break; + case '6': + *(_dest) = 1; + *(_dest + 1) = -1; + *(_dest + 2) = -1; + *(_dest + 3) = 1; + break; + case '7': + *(_dest) = 1; + *(_dest + 1) = -1; + *(_dest + 2) = -1; + *(_dest + 3) = -1; + break; + case '8': + *(_dest) = -1; + *(_dest + 1) = 1; + *(_dest + 2) = 1; + *(_dest + 3) = 1; + break; + case '9': + *(_dest) = -1; + *(_dest + 1) = 1; + *(_dest + 2) = 1; + *(_dest + 3) = -1; + break; + case 'A': + *(_dest) = -1; + *(_dest + 1) = 1; + *(_dest + 2) = -1; + *(_dest + 3) = 1; + break; + case 'B': + *(_dest) = -1; + *(_dest + 1) = 1; + *(_dest + 2) = -1; + *(_dest + 3) = -1; + break; + case 'C': + *(_dest) = -1; + *(_dest + 1) = -1; + *(_dest + 2) = 1; + *(_dest + 3) = 1; + break; + case 'D': + *(_dest) = -1; + *(_dest + 1) = -1; + *(_dest + 2) = 1; + *(_dest + 3) = -1; + break; + case 'E': + *(_dest) = -1; + *(_dest + 1) = -1; + *(_dest + 2) = -1; + *(_dest + 3) = 1; + break; + case 'F': + *(_dest) = -1; + *(_dest + 1) = -1; + *(_dest + 2) = -1; + *(_dest + 3) = -1; + break; + } +} + + +void resampler(const float* _from, float* _dest, float _fs_in, + float _fs_out, uint32_t _length_in, uint32_t _length_out) +{ + uint32_t _codeValueIndex; float aux; //--- Find time constants -------------------------------------------------- - const float _t_in = 1 / _fs_in; // Incoming sampling period in sec - const float _t_out = 1 / _fs_out; // Out sampling period in sec - for (unsigned int i = 0; i < _length_out - 1; i++) + const float _t_in = 1 / _fs_in; // Incoming sampling period in sec + const float _t_out = 1 / _fs_out; // Out sampling period in sec + for (uint32_t i = 0; i < _length_out - 1; i++) + { + //=== Digitizing ======================================================= + //--- compute index array to read sampled values ------------------------- + //_codeValueIndex = ceil((_t_out * ((float)i + 1)) / _t_in) - 1; + aux = (_t_out * (i + 1)) / _t_in; + _codeValueIndex = auxCeil2(aux) - 1; + + //if repeat the chip -> upsample by nearest neighborhood interpolation + _dest[i] = _from[_codeValueIndex]; + } + //--- Correct the last index (due to number rounding issues) ----------- + _dest[_length_out - 1] = _from[_length_in - 1]; +} + + +void resampler(const std::complex* _from, std::complex* _dest, float _fs_in, + float _fs_out, uint32_t _length_in, uint32_t _length_out) +{ + uint32_t _codeValueIndex; + float aux; + //--- Find time constants -------------------------------------------------- + const float _t_in = 1 / _fs_in; // Incoming sampling period in sec + const float _t_out = 1 / _fs_out; // Out sampling period in sec + for (uint32_t i = 0; i < _length_out - 1; i++) { //=== Digitizing ======================================================= //--- compute index array to read sampled values ------------------------- diff --git a/src/algorithms/libs/gnss_signal_processing.h b/src/algorithms/libs/gnss_signal_processing.h index 2449dfaea..3ed363e3e 100644 --- a/src/algorithms/libs/gnss_signal_processing.h +++ b/src/algorithms/libs/gnss_signal_processing.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,6 +36,7 @@ #define GNSS_SDR_GNSS_SIGNAL_PROCESSING_H_ #include +#include /*! @@ -43,14 +44,14 @@ * */ void complex_exp_gen(std::complex* _dest, double _f, double _fs, - unsigned int _samps); + uint32_t _samps); /*! * \brief This function generates a conjugate complex exponential in _dest. * */ void complex_exp_gen_conj(std::complex* _dest, double _f, double _fs, - unsigned int _samps); + uint32_t _samps); /*! @@ -58,14 +59,21 @@ void complex_exp_gen_conj(std::complex* _dest, double _f, double _fs, * to binary (the output are 4 ints with +1 or -1 values). * */ -void hex_to_binary_converter(int * _dest, char _from); +void hex_to_binary_converter(int32_t* _dest, char _from); +/*! + * \brief This function resamples a sequence of float values. + * + */ +void resampler(const float* _from, float* _dest, + float _fs_in, float _fs_out, uint32_t _length_in, + uint32_t _length_out); /*! * \brief This function resamples a sequence of complex values. * */ -void resampler(std::complex* _from, std::complex* _dest, - float _fs_in, float _fs_out, unsigned int _length_in, - unsigned int _length_out); +void resampler(const std::complex* _from, std::complex* _dest, + float _fs_in, float _fs_out, uint32_t _length_in, + uint32_t _length_out); #endif /* GNSS_SDR_GNSS_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/gps_l2c_signal.cc b/src/algorithms/libs/gps_l2c_signal.cc index d4e9cd22e..b3b20be20 100644 --- a/src/algorithms/libs/gps_l2c_signal.cc +++ b/src/algorithms/libs/gps_l2c_signal.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,45 +25,44 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include +#include "gps_l2c_signal.h" #include "GPS_L2C.h" +#include int32_t gps_l2c_m_shift(int32_t x) { - return static_cast((x >> 1)^((x & 1) * 0445112474)); + return static_cast((x >> 1) ^ ((x & 1) * 0445112474)); } -void gps_l2c_m_code(int32_t * _dest, unsigned int _prn) +void gps_l2c_m_code(int32_t* _dest, uint32_t _prn) { int32_t x; - x = GPS_L2C_M_INIT_REG[ _prn - 1]; - for (int n = 0; n < GPS_L2_M_CODE_LENGTH_CHIPS; n++) + x = GPS_L2C_M_INIT_REG[_prn - 1]; + for (int32_t n = 0; n < GPS_L2_M_CODE_LENGTH_CHIPS; n++) { - _dest[n] = (int8_t)(x&1); + _dest[n] = static_cast(x & 1); x = gps_l2c_m_shift(x); } } -void gps_l2c_m_code_gen_complex(std::complex* _dest, unsigned int _prn) +void gps_l2c_m_code_gen_complex(std::complex* _dest, uint32_t _prn) { - int32_t* _code = new int32_t[GPS_L2_M_CODE_LENGTH_CHIPS]; + auto* _code = new int32_t[GPS_L2_M_CODE_LENGTH_CHIPS]; if (_prn > 0 and _prn < 51) { gps_l2c_m_code(_code, _prn); } - for (signed int i = 0; i < GPS_L2_M_CODE_LENGTH_CHIPS; i++) + for (int32_t i = 0; i < GPS_L2_M_CODE_LENGTH_CHIPS; i++) { _dest[i] = std::complex(1.0 - 2.0 * _code[i], 0.0); } @@ -72,39 +71,57 @@ void gps_l2c_m_code_gen_complex(std::complex* _dest, unsigned int _prn) } +void gps_l2c_m_code_gen_float(float* _dest, uint32_t _prn) +{ + auto* _code = new int32_t[GPS_L2_M_CODE_LENGTH_CHIPS]; + + if (_prn > 0 and _prn < 51) + { + gps_l2c_m_code(_code, _prn); + } + + for (int32_t i = 0; i < GPS_L2_M_CODE_LENGTH_CHIPS; i++) + { + _dest[i] = 1.0 - 2.0 * static_cast(_code[i]); + } + + delete[] _code; +} + + /* * Generates complex GPS L2C M code for the desired SV ID and sampled to specific sampling frequency */ -void gps_l2c_m_code_gen_complex_sampled(std::complex* _dest, unsigned int _prn, signed int _fs) +void gps_l2c_m_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs) { - int32_t* _code = new int32_t[GPS_L2_M_CODE_LENGTH_CHIPS]; + auto* _code = new int32_t[GPS_L2_M_CODE_LENGTH_CHIPS]; if (_prn > 0 and _prn < 51) { gps_l2c_m_code(_code, _prn); } - signed int _samplesPerCode, _codeValueIndex; + int32_t _samplesPerCode, _codeValueIndex; float _ts; float _tc; - const signed int _codeLength = GPS_L2_M_CODE_LENGTH_CHIPS; + const int32_t _codeLength = GPS_L2_M_CODE_LENGTH_CHIPS; //--- Find number of samples per spreading code ---------------------------- - _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(GPS_L2_M_CODE_RATE_HZ) / static_cast(_codeLength))); + _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(GPS_L2_M_CODE_RATE_HZ) / static_cast(_codeLength))); //--- Find time constants -------------------------------------------------- - _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _ts = 1.0 / static_cast(_fs); // Sampling period in sec _tc = 1.0 / static_cast(GPS_L2_M_CODE_RATE_HZ); // C/A chip period in sec //float aux; - for (signed int i = 0; i < _samplesPerCode; i++) + for (int32_t i = 0; i < _samplesPerCode; i++) { //=== Digitizing ======================================================= //--- Make index array to read L2C code values ------------------------- //TODO: Check this formula! Seems to start with an extra sample - _codeValueIndex = ceil((_ts * ((float)i + 1)) / _tc) - 1; + _codeValueIndex = ceil((_ts * (static_cast(i) + 1)) / _tc) - 1; //aux = (_ts * (i + 1)) / _tc; - //_codeValueIndex = static_cast(static_cast(aux)) - 1; + //_codeValueIndex = static_cast(static_cast(aux)) - 1; //--- Make the digitized version of the L2C code ----------------------- if (i == _samplesPerCode - 1) @@ -114,12 +131,8 @@ void gps_l2c_m_code_gen_complex_sampled(std::complex* _dest, unsigned int } else { - _dest[i] = std::complex(1.0 - 2.0 * _code[_codeValueIndex], 0); //repeat the chip -> upsample + _dest[i] = std::complex(1.0 - 2.0 * _code[_codeValueIndex], 0); //repeat the chip -> upsample } } delete[] _code; } - - - - diff --git a/src/algorithms/libs/gps_l2c_signal.h b/src/algorithms/libs/gps_l2c_signal.h index 8179ec5b9..84d51e485 100644 --- a/src/algorithms/libs/gps_l2c_signal.h +++ b/src/algorithms/libs/gps_l2c_signal.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,22 +25,23 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_GPS_L2C_SIGNAL_H_ -#define GNSS_GPS_L2C_SIGNAL_H_ +#ifndef GNSS_SDR_GPS_L2C_SIGNAL_H_ +#define GNSS_SDR_GPS_L2C_SIGNAL_H_ #include +#include -//!Generates complex GPS L2C M code for the desired SV ID -void gps_l2c_m_code_gen_complex(std::complex* _dest, unsigned int _prn); - +//! Generates complex GPS L2C M code for the desired SV ID +void gps_l2c_m_code_gen_complex(std::complex* _dest, uint32_t _prn); +void gps_l2c_m_code_gen_float(float* _dest, uint32_t _prn); //! Generates complex GPS L2C M code for the desired SV ID, and sampled to specific sampling frequency -void gps_l2c_m_code_gen_complex_sampled(std::complex* _dest, unsigned int _prn, signed int _fs); +void gps_l2c_m_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs); #endif /* GNSS_GPS_L2C_SIGNAL_H_ */ diff --git a/src/algorithms/libs/gps_l5_signal.cc b/src/algorithms/libs/gps_l5_signal.cc new file mode 100644 index 000000000..198aa27af --- /dev/null +++ b/src/algorithms/libs/gps_l5_signal.cc @@ -0,0 +1,344 @@ +/*! + * \file gps_l5_signal.cc + * \brief This class implements signal generators for the GPS L5 signals + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l5_signal.h" +#include "GPS_L5.h" +#include +#include +#include +#include + + +std::deque l5i_xa_shift(std::deque xa) +{ + if (xa == std::deque{true, true, true, true, true, true, true, true, true, true, true, false, true}) + { + return std::deque{true, true, true, true, true, true, true, true, true, true, true, true, true}; + } + std::deque out(xa.begin(), xa.end() - 1); + out.push_front(xa[12] xor xa[11] xor xa[9] xor xa[8]); + return out; +} + + +std::deque l5q_xa_shift(std::deque xa) +{ + if (xa == std::deque{true, true, true, true, true, true, true, true, true, true, true, false, true}) + { + return std::deque{true, true, true, true, true, true, true, true, true, true, true, true, true}; + } + std::deque out(xa.begin(), xa.end() - 1); + out.push_front(xa[12] xor xa[11] xor xa[9] xor xa[8]); + return out; +} + + +std::deque l5i_xb_shift(std::deque xb) +{ + std::deque out(xb.begin(), xb.end() - 1); + out.push_front(xb[12] xor xb[11] xor xb[7] xor xb[6] xor xb[5] xor xb[3] xor xb[2] xor xb[0]); + return out; +} + + +std::deque l5q_xb_shift(std::deque xb) +{ + std::deque out(xb.begin(), xb.end() - 1); + out.push_front(xb[12] xor xb[11] xor xb[7] xor xb[6] xor xb[5] xor xb[3] xor xb[2] xor xb[0]); + return out; +} + + +std::deque make_l5i_xa() +{ + std::deque xa = {true, true, true, true, true, true, true, true, true, true, true, true, true}; + std::deque y(GPS_L5i_CODE_LENGTH_CHIPS, false); + + for (int32_t i = 0; i < GPS_L5i_CODE_LENGTH_CHIPS; i++) + { + y[i] = xa[12]; + xa = l5i_xa_shift(xa); + } + return y; +} + + +std::deque make_l5i_xb() +{ + std::deque xb = {true, true, true, true, true, true, true, true, true, true, true, true, true}; + std::deque y(GPS_L5i_CODE_LENGTH_CHIPS, false); + + for (int32_t i = 0; i < GPS_L5i_CODE_LENGTH_CHIPS; i++) + { + y[i] = xb[12]; + xb = l5i_xb_shift(xb); + } + return y; +} + + +std::deque make_l5q_xa() +{ + std::deque xa = {true, true, true, true, true, true, true, true, true, true, true, true, true}; + std::deque y(GPS_L5q_CODE_LENGTH_CHIPS, false); + + for (int32_t i = 0; i < GPS_L5q_CODE_LENGTH_CHIPS; i++) + { + y[i] = xa[12]; + xa = l5q_xa_shift(xa); + } + return y; +} + + +std::deque make_l5q_xb() +{ + std::deque xb = {true, true, true, true, true, true, true, true, true, true, true, true, true}; + std::deque y(GPS_L5q_CODE_LENGTH_CHIPS, false); + + for (int32_t i = 0; i < GPS_L5q_CODE_LENGTH_CHIPS; i++) + { + y[i] = xb[12]; + xb = l5q_xb_shift(xb); + } + return y; +} + + +void make_l5i(int32_t* _dest, int32_t prn) +{ + int32_t xb_offset = GPS_L5i_INIT_REG[prn]; + + std::deque xb = make_l5i_xb(); + std::deque xa = make_l5i_xa(); + std::deque xb_shift(GPS_L5i_CODE_LENGTH_CHIPS, false); + + for (int32_t n = 0; n < GPS_L5i_CODE_LENGTH_CHIPS; n++) + { + xb_shift[n] = xb[(xb_offset + n) % GPS_L5i_CODE_LENGTH_CHIPS]; + } + std::deque out_code(GPS_L5i_CODE_LENGTH_CHIPS, false); + for (int32_t n = 0; n < GPS_L5i_CODE_LENGTH_CHIPS; n++) + { + _dest[n] = xa[n] xor xb_shift[n]; + } +} + + +void make_l5q(int32_t* _dest, int32_t prn) +{ + int32_t xb_offset = GPS_L5q_INIT_REG[prn]; + + std::deque xb = make_l5q_xb(); + std::deque xa = make_l5q_xa(); + std::deque xb_shift(GPS_L5q_CODE_LENGTH_CHIPS, false); + + for (int32_t n = 0; n < GPS_L5q_CODE_LENGTH_CHIPS; n++) + { + xb_shift[n] = xb[(xb_offset + n) % GPS_L5q_CODE_LENGTH_CHIPS]; + } + std::deque out_code(GPS_L5q_CODE_LENGTH_CHIPS, false); + for (int32_t n = 0; n < GPS_L5q_CODE_LENGTH_CHIPS; n++) + { + _dest[n] = xa[n] xor xb_shift[n]; + } +} + + +void gps_l5i_code_gen_complex(std::complex* _dest, uint32_t _prn) +{ + auto* _code = new int32_t[GPS_L5i_CODE_LENGTH_CHIPS]; + + if (_prn > 0 and _prn < 51) + { + make_l5i(_code, _prn - 1); + } + + for (int32_t i = 0; i < GPS_L5i_CODE_LENGTH_CHIPS; i++) + { + _dest[i] = std::complex(1.0 - 2.0 * _code[i], 0.0); + } + + delete[] _code; +} + + +void gps_l5i_code_gen_float(float* _dest, uint32_t _prn) +{ + auto* _code = new int32_t[GPS_L5i_CODE_LENGTH_CHIPS]; + + if (_prn > 0 and _prn < 51) + { + make_l5i(_code, _prn - 1); + } + + for (int32_t i = 0; i < GPS_L5i_CODE_LENGTH_CHIPS; i++) + { + _dest[i] = 1.0 - 2.0 * static_cast(_code[i]); + } + + delete[] _code; +} + + +/* + * Generates complex GPS L5i code for the desired SV ID and sampled to specific sampling frequency + */ +void gps_l5i_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs) +{ + auto* _code = new int32_t[GPS_L5i_CODE_LENGTH_CHIPS]; + if (_prn > 0 and _prn < 51) + { + make_l5i(_code, _prn - 1); + } + + int32_t _samplesPerCode, _codeValueIndex; + float _ts; + float _tc; + const int32_t _codeLength = GPS_L5i_CODE_LENGTH_CHIPS; + + //--- Find number of samples per spreading code ---------------------------- + _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(GPS_L5i_CODE_RATE_HZ) / static_cast(_codeLength))); + + //--- Find time constants -------------------------------------------------- + _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _tc = 1.0 / static_cast(GPS_L5i_CODE_RATE_HZ); // C/A chip period in sec + + //float aux; + for (int32_t i = 0; i < _samplesPerCode; i++) + { + //=== Digitizing ======================================================= + + //--- Make index array to read L5 code values ------------------------- + //TODO: Check this formula! Seems to start with an extra sample + _codeValueIndex = ceil((_ts * (static_cast(i) + 1)) / _tc) - 1; + //aux = (_ts * (i + 1)) / _tc; + //_codeValueIndex = static_cast (static_cast(aux)) - 1; + + //--- Make the digitized version of the L2C code ----------------------- + if (i == _samplesPerCode - 1) + { + //--- Correct the last index (due to number rounding issues) ----------- + _dest[i] = std::complex(1.0 - 2.0 * _code[_codeLength - 1], 0); + } + else + { + _dest[i] = std::complex(1.0 - 2.0 * _code[_codeValueIndex], 0); //repeat the chip -> upsample + } + } + delete[] _code; +} + + +void gps_l5q_code_gen_complex(std::complex* _dest, uint32_t _prn) +{ + auto* _code = new int32_t[GPS_L5q_CODE_LENGTH_CHIPS]; + + if (_prn > 0 and _prn < 51) + { + make_l5q(_code, _prn - 1); + } + + for (int32_t i = 0; i < GPS_L5q_CODE_LENGTH_CHIPS; i++) + { + _dest[i] = std::complex(1.0 - 2.0 * _code[i], 0.0); + } + + delete[] _code; +} + + +void gps_l5q_code_gen_float(float* _dest, uint32_t _prn) +{ + auto* _code = new int32_t[GPS_L5q_CODE_LENGTH_CHIPS]; + + if (_prn > 0 and _prn < 51) + { + make_l5q(_code, _prn - 1); + } + + for (int32_t i = 0; i < GPS_L5q_CODE_LENGTH_CHIPS; i++) + { + _dest[i] = 1.0 - 2.0 * static_cast(_code[i]); + } + + delete[] _code; +} + + +/* + * Generates complex GPS L5i code for the desired SV ID and sampled to specific sampling frequency + */ +void gps_l5q_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs) +{ + auto* _code = new int32_t[GPS_L5q_CODE_LENGTH_CHIPS]; + if (_prn > 0 and _prn < 51) + { + make_l5q(_code, _prn - 1); + } + + int32_t _samplesPerCode, _codeValueIndex; + float _ts; + float _tc; + const int32_t _codeLength = GPS_L5q_CODE_LENGTH_CHIPS; + + //--- Find number of samples per spreading code ---------------------------- + _samplesPerCode = static_cast(static_cast(_fs) / (static_cast(GPS_L5q_CODE_RATE_HZ) / static_cast(_codeLength))); + + //--- Find time constants -------------------------------------------------- + _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _tc = 1.0 / static_cast(GPS_L5q_CODE_RATE_HZ); // C/A chip period in sec + + //float aux; + for (int32_t i = 0; i < _samplesPerCode; i++) + { + //=== Digitizing ======================================================= + + //--- Make index array to read L5 code values ------------------------- + //TODO: Check this formula! Seems to start with an extra sample + _codeValueIndex = ceil((_ts * (static_cast(i) + 1)) / _tc) - 1; + //aux = (_ts * (i + 1)) / _tc; + //_codeValueIndex = static_cast (static_cast(aux)) - 1; + + //--- Make the digitized version of the L2C code ----------------------- + if (i == _samplesPerCode - 1) + { + //--- Correct the last index (due to number rounding issues) ----------- + _dest[i] = std::complex(1.0 - 2.0 * _code[_codeLength - 1], 0); + } + else + { + _dest[i] = std::complex(1.0 - 2.0 * _code[_codeValueIndex], 0); //repeat the chip -> upsample + } + } + delete[] _code; +} diff --git a/src/algorithms/libs/gps_l5_signal.h b/src/algorithms/libs/gps_l5_signal.h new file mode 100644 index 000000000..b0b24d2a5 --- /dev/null +++ b/src/algorithms/libs/gps_l5_signal.h @@ -0,0 +1,54 @@ +/*! + * \file gps_l5_signal.h + * \brief This class implements signal generators for the GPS L5 signals + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Detailed description of the file here if needed. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5_SIGNAL_H_ +#define GNSS_SDR_GPS_L5_SIGNAL_H_ + +#include +#include + +//!Generates complex GPS L5i M code for the desired SV ID +void gps_l5i_code_gen_complex(std::complex* _dest, uint32_t _prn); +void gps_l5i_code_gen_float(float* _dest, uint32_t _prn); + +//!Generates complex GPS L5q M code for the desired SV ID +void gps_l5q_code_gen_complex(std::complex* _dest, uint32_t _prn); +void gps_l5q_code_gen_float(float* _dest, uint32_t _prn); + +//! Generates complex GPS L5i M code for the desired SV ID, and sampled to specific sampling frequency +void gps_l5i_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs); + +//! Generates complex GPS L5q M code for the desired SV ID, and sampled to specific sampling frequency +void gps_l5q_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs); + + +#endif /* GNSS_SDR_GPS_L5_SIGNAL_H_ */ diff --git a/src/algorithms/libs/gps_sdr_signal_processing.cc b/src/algorithms/libs/gps_sdr_signal_processing.cc index a88ea5119..e87593f6e 100644 --- a/src/algorithms/libs/gps_sdr_signal_processing.cc +++ b/src/algorithms/libs/gps_sdr_signal_processing.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,37 +25,37 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_sdr_signal_processing.h" -auto auxCeil = [](float x){ return static_cast(static_cast((x)+1)); }; +auto auxCeil = [](float x) { return static_cast(static_cast((x) + 1)); }; -void gps_l1_ca_code_gen_complex(std::complex* _dest, signed int _prn, unsigned int _chip_shift) +void gps_l1_ca_code_gen_int(int32_t* _dest, int32_t _prn, uint32_t _chip_shift) { - const unsigned int _code_length = 1023; + const uint32_t _code_length = 1023; bool G1[_code_length]; bool G2[_code_length]; bool G1_register[10], G2_register[10]; bool feedback1, feedback2; bool aux; - unsigned int lcv, lcv2; - unsigned int delay; - signed int prn_idx; + uint32_t lcv, lcv2; + uint32_t delay; + int32_t prn_idx; /* G2 Delays as defined in GPS-ISD-200D */ - const signed int delays[51] = {5 /*PRN1*/, 6, 7, 8, 17, 18, 139, 140, 141, 251, 252, 254 ,255, 256, 257, 258, 469, 470, 471, 472, - 473, 474, 509, 512, 513, 514, 515, 516, 859, 860, 861, 862 /*PRN32*/, - 145 /*PRN120*/, 175, 52, 21, 237, 235, 886, 657, 634, 762, - 355, 1012, 176, 603, 130, 359, 595, 68, 386 /*PRN138*/}; + const int32_t delays[51] = {5 /*PRN1*/, 6, 7, 8, 17, 18, 139, 140, 141, 251, 252, 254, 255, 256, 257, 258, 469, 470, 471, 472, + 473, 474, 509, 512, 513, 514, 515, 516, 859, 860, 861, 862 /*PRN32*/, + 145 /*PRN120*/, 175, 52, 21, 237, 235, 886, 657, 634, 762, + 355, 1012, 176, 603, 130, 359, 595, 68, 386 /*PRN138*/}; // compute delay array index for given PRN number - if(120 <= _prn && _prn <= 138) + if (120 <= _prn && _prn <= 138) { - prn_idx = _prn - 88; // SBAS PRNs are at array indices 31 to 50 (offset: -120+33-1 =-88) + prn_idx = _prn - 88; // SBAS PRNs are at array indices 31 to 50 (offset: -120+33-1 =-88) } else { @@ -63,25 +63,25 @@ void gps_l1_ca_code_gen_complex(std::complex* _dest, signed int _prn, uns } /* A simple error check */ - if((prn_idx < 0) || (prn_idx > 51)) + if ((prn_idx < 0) || (prn_idx > 51)) return; - for(lcv = 0; lcv < 10; lcv++) + for (lcv = 0; lcv < 10; lcv++) { - G1_register[lcv] = 1; - G2_register[lcv] = 1; + G1_register[lcv] = true; + G2_register[lcv] = true; } /* Generate G1 & G2 Register */ - for(lcv = 0; lcv < _code_length; lcv++) + for (lcv = 0; lcv < _code_length; lcv++) { G1[lcv] = G1_register[0]; G2[lcv] = G2_register[0]; - feedback1 = G1_register[7]^G1_register[0]; + feedback1 = G1_register[7] ^ G1_register[0]; feedback2 = (G2_register[8] + G2_register[7] + G2_register[4] + G2_register[2] + G2_register[1] + G2_register[0]) & 0x1; - for(lcv2 = 0; lcv2 < 9; lcv2++) + for (lcv2 = 0; lcv2 < 9; lcv2++) { G1_register[lcv2] = G1_register[lcv2 + 1]; G2_register[lcv2] = G2_register[lcv2 + 1]; @@ -97,16 +97,16 @@ void gps_l1_ca_code_gen_complex(std::complex* _dest, signed int _prn, uns delay %= _code_length; /* Generate PRN from G1 and G2 Registers */ - for(lcv = 0; lcv < _code_length; lcv++) + for (lcv = 0; lcv < _code_length; lcv++) { - aux = G1[(lcv + _chip_shift) % _code_length]^G2[delay]; - if(aux == true) + aux = G1[(lcv + _chip_shift) % _code_length] ^ G2[delay]; + if (aux == true) { - _dest[lcv] = std::complex(1, 0); + _dest[lcv] = 1; } else { - _dest[lcv] = std::complex(-1, 0); + _dest[lcv] = -1; } delay++; delay %= _code_length; @@ -114,30 +114,58 @@ void gps_l1_ca_code_gen_complex(std::complex* _dest, signed int _prn, uns } +void gps_l1_ca_code_gen_float(float* _dest, int32_t _prn, uint32_t _chip_shift) +{ + const uint32_t _code_length = 1023; + int32_t ca_code_int[_code_length]; + + gps_l1_ca_code_gen_int(ca_code_int, _prn, _chip_shift); + + for (uint32_t ii = 0; ii < _code_length; ++ii) + { + _dest[ii] = static_cast(ca_code_int[ii]); + } +} + + +void gps_l1_ca_code_gen_complex(std::complex* _dest, int32_t _prn, uint32_t _chip_shift) +{ + const uint32_t _code_length = 1023; + int32_t ca_code_int[_code_length] = {0}; + + gps_l1_ca_code_gen_int(ca_code_int, _prn, _chip_shift); + + for (uint32_t ii = 0; ii < _code_length; ++ii) + { + _dest[ii] = std::complex(static_cast(ca_code_int[ii]), 0.0f); + } +} + /* * Generates complex GPS L1 C/A code for the desired SV ID and sampled to specific sampling frequency + * NOTICE: the number of samples is rounded towards zero (integer truncation) */ -void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, unsigned int _prn, signed int _fs, unsigned int _chip_shift) +void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs, uint32_t _chip_shift) { // This function is based on the GNU software GPS for MATLAB in the Kay Borre book std::complex _code[1023]; - signed int _samplesPerCode, _codeValueIndex; + int32_t _samplesPerCode, _codeValueIndex; float _ts; float _tc; float aux; - const signed int _codeFreqBasis = 1023000; //Hz - const signed int _codeLength = 1023; + const int32_t _codeFreqBasis = 1023000; //Hz + const int32_t _codeLength = 1023; //--- Find number of samples per spreading code ---------------------------- - _samplesPerCode = static_cast(static_cast(_fs) / static_cast(_codeFreqBasis / _codeLength)); + _samplesPerCode = static_cast(static_cast(_fs) / static_cast(_codeFreqBasis / _codeLength)); //--- Find time constants -------------------------------------------------- - _ts = 1.0 / static_cast(_fs); // Sampling period in sec - _tc = 1.0 / static_cast(_codeFreqBasis); // C/A chip period in sec - gps_l1_ca_code_gen_complex(_code, _prn, _chip_shift); //generate C/A code 1 sample per chip + _ts = 1.0 / static_cast(_fs); // Sampling period in sec + _tc = 1.0 / static_cast(_codeFreqBasis); // C/A chip period in sec + gps_l1_ca_code_gen_complex(_code, _prn, _chip_shift); //generate C/A code 1 sample per chip - for (signed int i = 0; i < _samplesPerCode; i++) + for (int32_t i = 0; i < _samplesPerCode; i++) { //=== Digitizing ======================================================= @@ -147,8 +175,8 @@ void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, unsigned int // millisecond). // _codeValueIndex = ceil((_ts * ((float)i + 1)) / _tc) - 1; - aux = (_ts * (i + 1)) / _tc; - _codeValueIndex = auxCeil( aux ) - 1; + aux = (_ts * (i + 1)) / _tc; + _codeValueIndex = auxCeil(aux) - 1; //--- Make the digitized version of the C/A code ----------------------- // The "upsampled" code is made by selecting values form the CA code @@ -157,12 +185,10 @@ void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, unsigned int { //--- Correct the last index (due to number rounding issues) ----------- _dest[i] = _code[_codeLength - 1]; - } else { - _dest[i] = _code[_codeValueIndex]; //repeat the chip -> upsample + _dest[i] = _code[_codeValueIndex]; //repeat the chip -> upsample } } } - diff --git a/src/algorithms/libs/gps_sdr_signal_processing.h b/src/algorithms/libs/gps_sdr_signal_processing.h index 2f01b5647..44bb815dd 100644 --- a/src/algorithms/libs/gps_sdr_signal_processing.h +++ b/src/algorithms/libs/gps_sdr_signal_processing.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,14 +34,21 @@ #define GNSS_SDR_GPS_SDR_SIGNAL_PROCESSING_H_ #include +#include -//!Generates complex GPS L1 C/A code for the desired SV ID and code shift, and sampled to specific sampling frequency -void gps_l1_ca_code_gen_complex(std::complex* _dest, signed int _prn, unsigned int _chip_shift); +//! Generates int GPS L1 C/A code for the desired SV ID and code shift +void gps_l1_ca_code_gen_int(int32_t* _dest, int32_t _prn, uint32_t _chip_shift); + +//! Generates float GPS L1 C/A code for the desired SV ID and code shift +void gps_l1_ca_code_gen_float(float* _dest, int32_t _prn, uint32_t _chip_shift); + +//! Generates complex GPS L1 C/A code for the desired SV ID and code shift, and sampled to specific sampling frequency +void gps_l1_ca_code_gen_complex(std::complex* _dest, int32_t _prn, uint32_t _chip_shift); //! Generates N complex GPS L1 C/A codes for the desired SV ID and code shift -void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, unsigned int _prn, signed int _fs, unsigned int _chip_shift, unsigned int _ncodes); +void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs, uint32_t _chip_shift, uint32_t _ncodes); //! Generates complex GPS L1 C/A code for the desired SV ID and code shift -void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, unsigned int _prn, signed int _fs, unsigned int _chip_shift); +void gps_l1_ca_code_gen_complex_sampled(std::complex* _dest, uint32_t _prn, int32_t _fs, uint32_t _chip_shift); #endif /* GNSS_SDR_GPS_SDR_SIGNAL_PROCESSING_H_ */ diff --git a/src/algorithms/libs/opencl/cl.hpp b/src/algorithms/libs/opencl/cl.hpp new file mode 100644 index 000000000..b10828523 --- /dev/null +++ b/src/algorithms/libs/opencl/cl.hpp @@ -0,0 +1,12413 @@ +/******************************************************************************* + * Copyright (c) 2008-2013 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and + * OpenCL 1.2 (rev 15) + * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes + * + * Additions and fixes from: + * Brian Cole, March 3rd 2010 and April 2012 + * Matt Gruenke, April 2012. + * Bruce Merry, February 2013. + * + * \version 1.2.5 + * \date June 2013 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * For many large applications C++ is the language of choice and so it seems + * reasonable to define C++ bindings for OpenCL. + * + * + * The interface is contained with a single C++ header file \em cl.hpp and all + * definitions are contained within the namespace \em cl. There is no additional + * requirement to include \em cl.h and to use either the C++ or original C + * bindings it is enough to simply include \em cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.2 (revision 09) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * descriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 + +#include +#include +#include +#include + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +#endif // #if defined(__CL_ENABLE_EXCEPTIONS) + +#pragma push_macro("max") +#undef max +#if defined(USE_DX_INTEROP) +#include +#include +#endif +#endif // _WIN32 + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#include +#include +#else +#include +#include +#endif // !__APPLE__ + +// To avoid accidentally taking ownership of core OpenCL types +// such as cl_kernel constructors are made explicit +// under OpenCL 1.2 +#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS explicit +#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS +#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +// Define deprecated prefixes and suffixes to ensure compilation +// in case they are not pre-defined +#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) + +#if !defined(CL_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include +#include + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(linux) || defined(__APPLE__) || defined(__MACOSX) +#include +#include +#include +#endif // linux + +#include + + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl +{ +class Memory; + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __INIT_CL_EXT_FCN_PTR(name) \ + if (!pfn_##name) \ + { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if (!pfn_##name) \ + { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +#if defined(CL_VERSION_1_2) +#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ + if (!pfn_##name) \ + { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddressForPlatform(platform, #name); \ + if (!pfn_##name) \ + { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; +class Buffer; + +#if defined(__CL_ENABLE_EXCEPTIONS) +/*! \brief Exception class + * + * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. + */ +class Error : public std::exception +{ +private: + cl_int err_; + const char* errStr_; + +public: + /*! \brief Create a new CL error exception for a given error code + * and corresponding message. + * + * \param err error code value. + * + * \param errStr a descriptive string that must remain in scope until + * handling of the exception has concluded. If set, it + * will be returned by what(). + */ + Error(cl_int err, const char* errStr = NULL) : err_(err), errStr_(errStr) + { + } + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char* what() const throw() + { + if (errStr_ == NULL) + { + return "empty"; + } + else + { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + + +namespace detail +{ +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler( + cl_int err, + const char* errStr = NULL) +{ + if (err != CL_SUCCESS) + { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler(cl_int err, const char* errStr = NULL) +{ + (void)errStr; // suppress unused variable warning + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS +} // namespace detail + + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#if defined(CL_VERSION_1_2) +#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) +#endif // #if defined(CL_VERSION_1_2) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __COPY_ERR __ERR_STR(cl::copy) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#if defined(CL_VERSION_1_2) +#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) +#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) +#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#if defined(CL_VERSION_1_2) +#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) +#endif // #if defined(CL_VERSION_1_2) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#if defined(CL_VERSION_1_2) +#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) + +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) +#endif // #if defined(CL_VERSION_1_2) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + + +#define __RETAIN_ERR __ERR_STR(Retain Object) +#define __RELEASE_ERR __ERR_STR(Release Object) +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) +#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) + +/** + * CL 1.2 version that uses device fission. + */ +#if defined(CL_VERSION_1_2) +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) +#else +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // #if defined(CL_VERSION_1_2) + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) +#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) +#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#endif // #if defined(CL_VERSION_1_1) + +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/** + * CL 1.2 marker and barrier commands + */ +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) +#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) +#endif // #if defined(CL_VERSION_1_2) + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + + * \note Deprecated. Please use std::string as default or + * re-define the string class to match the std::string + * interface by defining STRING_CLASS + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +{ +private: + ::size_t size_; + char* str_; + +public: + //! \brief Constructs an empty string, allocating no memory. + string(void) : size_(0), str_(NULL) + { + } + + /*! \brief Constructs a string populated from an arbitrary value of + * specified size. + * + * An extra '\0' is added, in case none was contained in str. + * + * \param str the initial value of the string instance. Note that '\0' + * characters receive no special treatment. If NULL, + * the string is left empty, with a size of 0. + * + * \param size the number of characters to copy from str. + */ + string(const char* str, ::size_t size) : size_(size), + str_(NULL) + { + if (size > 0) + { + str_ = new char[size_ + 1]; + if (str_ != NULL) + { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else + { + size_ = 0; + } + } + } + + /*! \brief Constructs a string populated from a null-terminated value. + * + * \param str the null-terminated initial value of the string instance. + * If NULL, the string is left empty, with a size of 0. + */ + string(const char* str) : size_(0), + str_(NULL) + { + if (str) + { + size_ = ::strlen(str); + } + if (size_ > 0) + { + str_ = new char[size_ + 1]; + if (str_ != NULL) + { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + } + } + + void resize(::size_t n) + { + if (size_ == n) + { + return; + } + if (n == 0) + { + if (str_) + { + delete[] str_; + } + str_ = NULL; + size_ = 0; + } + else + { + char* newString = new char[n + 1]; + int copySize = n; + if (size_ < n) + { + copySize = size_; + } + size_ = n; + + if (str_) + { + memcpy(newString, str_, (copySize + 1) * sizeof(char)); + } + if (copySize < size_) + { + memset(newString + copySize, 0, size_ - copySize); + } + newString[size_] = '\0'; + + delete[] str_; + str_ = newString; + } + } + + const char& operator[](::size_t pos) const + { + return str_[pos]; + } + + char& operator[](::size_t pos) + { + return str_[pos]; + } + + /*! \brief Copies the value of another string to this one. + * + * \param rhs the string to copy. + * + * \returns a reference to the modified instance. + */ + string& operator=(const string& rhs) + { + if (this == &rhs) + { + return *this; + } + + if (str_ != NULL) + { + delete[] str_; + str_ = NULL; + size_ = 0; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) + { + str_ = NULL; + size_ = 0; + } + else + { + str_ = new char[rhs.size_ + 1]; + size_ = rhs.size_; + + if (str_ != NULL) + { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else + { + size_ = 0; + } + } + + return *this; + } + + /*! \brief Constructs a string by copying the value of another instance. + * + * \param rhs the string to copy. + */ + string(const string& rhs) : size_(0), + str_(NULL) + { + *this = rhs; + } + + //! \brief Destructor - frees memory used to hold the current value. + ~string() + { + delete[] str_; + str_ = NULL; + } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t size(void) const { return size_; } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t length(void) const { return size(); } + + /*! \brief Returns a pointer to the private copy held by this instance, + * or "" if empty/unset. + */ + const char* c_str(void) const { return (str_) ? str_ : ""; } +}; +typedef cl::string STRING_CLASS; +#endif // #elif !defined(__USE_DEV_STRING) + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * + * \note Deprecated. Please use std::vector as default or + * re-define the vector class to match the std::vector + * interface by defining VECTOR_CLASS + + * \note Not recommended for use with custom objects as + * current implementation will construct N elements + * + * std::vector functionality. + * \brief Fixed sized vector compatible with std::vector. + * + * \note + * This differs from std::vector<> not just in memory allocation, + * but also in terms of when members are constructed, destroyed, + * and assigned instead of being copy constructed. + * + * \param T type of element contained in the vector. + * + * \param N maximum size of the vector. + */ +template +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +{ +private: + T data_[N]; + unsigned int size_; + +public: + //! \brief Constructs an empty vector with no memory allocated. + vector() : size_(static_cast(0)) + { + } + + //! \brief Deallocates the vector's memory and destroys all of its elements. + ~vector() + { + clear(); + } + + //! \brief Returns the number of elements currently contained. + unsigned int size(void) const + { + return size_; + } + + /*! \brief Empties the vector of all elements. + * \note + * This does not deallocate memory but will invoke destructors + * on contained elements. + */ + void clear() + { + while (!empty()) + { + pop_back(); + } + } + + /*! \brief Appends an element after the last valid element. + * Calling this on a vector that has reached capacity will throw an + * exception if exceptions are enabled. + */ + void push_back(const T& x) + { + if (size() < N) + { + new (&data_[size_]) T(x); + size_++; + } + else + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Removes the last valid element from the vector. + * Calling this on an empty vector will throw an exception + * if exceptions are enabled. + */ + void pop_back(void) + { + if (size_ != 0) + { + --size_; + data_[size_].~T(); + } + else + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Constructs with a value copied from another. + * + * \param vec the vector to copy. + */ + vector(const vector& vec) : size_(vec.size_) + { + if (size_ != 0) + { + assign(vec.begin(), vec.end()); + } + } + + /*! \brief Constructs with a specified number of initial elements. + * + * \param size number of initial elements. + * + * \param val value of initial elements. + */ + vector(unsigned int size, const T& val = T()) : size_(0) + { + for (unsigned int i = 0; i < size; i++) + { + push_back(val); + } + } + + /*! \brief Overwrites the current content with that copied from another + * instance. + * + * \param rhs vector to copy. + * + * \returns a reference to this. + */ + vector& operator=(const vector& rhs) + { + if (this == &rhs) + { + return *this; + } + + if (rhs.size_ != 0) + { + assign(rhs.begin(), rhs.end()); + } + else + { + clear(); + } + + return *this; + } + + /*! \brief Tests equality against another instance. + * + * \param vec the vector against which to compare. + */ + bool operator==(vector& vec) + { + if (size() != vec.size()) + { + return false; + } + + for (unsigned int i = 0; i < size(); ++i) + { + if (operator[](i) != vec[i]) + { + return false; + } + } + return true; + } + + //! \brief Conversion operator to T*. + operator T*() { return data_; } + + //! \brief Conversion operator to const T*. + operator const T*() const { return data_; } + + //! \brief Tests whether this instance has any elements. + bool empty(void) const + { + return size_ == 0; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int max_size(void) const + { + return N; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int capacity() const + { + return N; + } + + /*! \brief Returns a reference to a given element. + * + * \param index which element to access. * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + T& operator[](int index) + { + return data_[index]; + } + + /*! \brief Returns a const reference to a given element. + * + * \param index which element to access. + * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + const T& operator[](int index) const + { + return data_[index]; + } + + /*! \brief Assigns elements of the vector based on a source iterator range. + * + * \param start Beginning iterator of source range + * \param end Enditerator of source range + * + * \note + * Will throw an exception if exceptions are enabled and size exceeded. + */ + template + void assign(I start, I end) + { + clear(); + while (start != end) + { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Const iterator class for vectors + */ + class iterator + { + private: + const vector* vec_; + int index_; + + /** + * Internal iterator constructor to capture reference + * to the vector it iterates over rather than taking + * the vector by copy. + */ + iterator(const vector& vec, int index) : vec_(&vec) + { + if (!vec.empty()) + { + index_ = index; + } + else + { + index_ = -1; + } + } + + public: + iterator(void) : index_(-1), + vec_(NULL) + { + } + + iterator(const iterator& rhs) : vec_(rhs.vec_), + index_(rhs.index_) + { + } + + ~iterator(void) {} + + static iterator begin(const cl::vector& vec) + { + iterator i(vec, 0); + + return i; + } + + static iterator end(const cl::vector& vec) + { + iterator i(vec, vec.size()); + + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_)); + } + + bool operator!=(iterator i) + { + return (!(*this == i)); + } + + iterator& operator++() + { + ++index_; + return *this; + } + + iterator operator++(int) + { + iterator retVal(*this); + ++index_; + return retVal; + } + + iterator& operator--() + { + --index_; + return *this; + } + + iterator operator--(int) + { + iterator retVal(*this); + --index_; + return retVal; + } + + const T& operator*() const + { + return (*vec_)[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator begin(void) const + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + iterator end(void) const + { + return iterator::end(*this); + } + + T& front(void) + { + return data_[0]; + } + + T& back(void) + { + return data_[size_]; + } + + const T& front(void) const + { + return data_[0]; + } + + const T& back(void) const + { + return data_[size_ - 1]; + } +}; +#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) + + +namespace detail +{ +#define __DEFAULT_NOT_INITIALIZED 1 +#define __DEFAULT_BEING_INITIALIZED 2 +#define __DEFAULT_INITIALIZED 4 + +/* + * Compare and exchange primitives are needed for handling of defaults + */ +inline int compare_exchange(volatile int* dest, int exchange, int comparand) +{ +#ifdef _WIN32 + return (int)(InterlockedCompareExchange( + (volatile long*)dest, + (long)exchange, + (long)comparand)); +#elif defined(__APPLE__) || defined(__MACOSX) + return OSAtomicOr32Orig((uint32_t)exchange, (volatile uint32_t*)dest); +#else // !_WIN32 || defined(__APPLE__) || defined(__MACOSX) + return (__sync_val_compare_and_swap( + dest, + comparand, + exchange)); +#endif // !_WIN32 +} + +inline void fence() { _mm_mfence(); } +}; // namespace detail + + +/*! \brief class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, whose + * size is known statically. + */ +template +class size_t +{ +private: + ::size_t data_[N]; + +public: + //! \brief Initialize size_t to all 0s + size_t() + { + for (int i = 0; i < N; ++i) + { + data_[i] = 0; + } + } + + ::size_t& operator[](int index) + { + return data_[index]; + } + + const ::size_t& operator[](int index) const + { + return data_[index]; + } + + //! \brief Conversion operator to T*. + operator ::size_t*() { return data_; } + + //! \brief Conversion operator to const T*. + operator const ::size_t*() const { return data_; } +}; + +namespace detail +{ +// Generic getInfoHelper. The final parameter is used to guide overload +// resolution: the actual parameter passed is an int, which makes this +// a worse conversion sequence than a specialization that declares the +// parameter as an int. +template +inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) +{ + return f(name, sizeof(T), param, NULL); +} + +// Specialized getInfoHelper for VECTOR_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + T* value = (T*)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + param->assign(&value[0], &value[required / sizeof(T)]); + return CL_SUCCESS; +} + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + typename T::cl_type* value = (typename T::cl_type*)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + ::size_t elements = required / sizeof(typename T::cl_type); + param->assign(&value[0], &value[elements]); + for (::size_t i = 0; i < elements; i++) + { + if (value[i] != NULL) + { + err = (*param)[i].retain(); + if (err != CL_SUCCESS) + { + return err; + } + } + } + return CL_SUCCESS; +} + +// Specialized for getInfo +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) +{ + cl_int err = f(name, param->size() * sizeof(char*), &(*param)[0], NULL); + + if (err != CL_SUCCESS) + { + return err; + } + + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for STRING_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + char* value = (char*)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + *param = value; + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for cl::size_t params +template +inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + ::size_t* value = (::size_t*)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + for (int i = 0; i < N; ++i) + { + (*param)[i] = value[i]; + } + + return CL_SUCCESS; +} + +template +struct ReferenceHandler; + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) +{ + typename T::cl_type value; + cl_int err = f(name, sizeof(value), &value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + *param = value; + if (value != NULL) + { + err = param->retain(); + if (err != CL_SUCCESS) + { + return err; + } + } + return CL_SUCCESS; +} + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_uint) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + + +#if defined(CL_VERSION_1_2) +#define __PARAM_NAME_INFO_1_2(F) \ + F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ + \ + F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ + F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ + \ + F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ + \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ + F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ + F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) +#endif // #if defined(CL_VERSION_1_2) + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits +{ +}; + +#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ + struct token; \ + template <> \ + struct param_traits \ + { \ + enum \ + { \ + value = param_name \ + }; \ + typedef T param_type; \ + }; + +__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 +#if defined(CL_VERSION_1_2) +__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#ifdef CL_PLATFORM_ICD_SUFFIX_KHR +__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) +#endif + +#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) +#endif + +#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) +#endif +#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) +#endif + +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) +#endif +#ifdef CL_DEVICE_WARP_SIZE_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) +#endif +#ifdef CL_DEVICE_GPU_OVERLAP_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) +#endif +#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) +#endif +#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) +#endif + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T* param) +{ + return getInfoHelper(f, name, param, 0); +} + +template +struct GetInfoFunctor0 +{ + Func f_; + const Arg0& arg0_; + cl_int operator()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { + return f_(arg0_, param, size, value, size_ret); + } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; + const Arg0& arg0_; + const Arg1& arg1_; + cl_int operator()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { + return f_(arg0_, arg1_, param, size, value, size_ret); + } +}; + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) +{ + GetInfoFunctor0 f0 = {f, arg0}; + return getInfoHelper(f0, name, param, 0); +} + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) +{ + GetInfoFunctor1 f0 = {f, arg0, arg1}; + return getInfoHelper(f0, name, param, 0); +} + +template +struct ReferenceHandler +{ +}; + +#if defined(CL_VERSION_1_2) +/** + * OpenCL 1.2 devices do have retain/release. + */ +template <> +struct ReferenceHandler +{ + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int retain(cl_device_id device) + { + return ::clRetainDevice(device); + } + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int release(cl_device_id device) + { + return ::clReleaseDevice(device); + } +}; +#else // #if defined(CL_VERSION_1_2) +/** + * OpenCL 1.1 devices do not have retain/release. + */ +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { + return CL_SUCCESS; + } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { + return CL_SUCCESS; + } +}; +#endif // #if defined(CL_VERSION_1_2) + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { + return CL_SUCCESS; + } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { + return CL_SUCCESS; + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { + return ::clRetainContext(context); + } + static cl_int release(cl_context context) + { + return ::clReleaseContext(context); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { + return ::clRetainCommandQueue(queue); + } + static cl_int release(cl_command_queue queue) + { + return ::clReleaseCommandQueue(queue); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { + return ::clRetainMemObject(memory); + } + static cl_int release(cl_mem memory) + { + return ::clReleaseMemObject(memory); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { + return ::clRetainSampler(sampler); + } + static cl_int release(cl_sampler sampler) + { + return ::clReleaseSampler(sampler); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { + return ::clRetainProgram(program); + } + static cl_int release(cl_program program) + { + return ::clReleaseProgram(program); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { + return ::clRetainKernel(kernel); + } + static cl_int release(cl_kernel kernel) + { + return ::clReleaseKernel(kernel); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { + return ::clRetainEvent(event); + } + static cl_int release(cl_event event) + { + return ::clReleaseEvent(event); + } +}; + + +// Extracts version number with major in the upper 16 bits, minor in the lower 16 +static cl_uint getVersion(const char* versionInfo) +{ + int highVersion = 0; + int lowVersion = 0; + int index = 7; + while (versionInfo[index] != '.') + { + highVersion *= 10; + highVersion += versionInfo[index] - '0'; + ++index; + } + ++index; + while (versionInfo[index] != ' ') + { + lowVersion *= 10; + lowVersion += versionInfo[index] - '0'; + ++index; + } + return (highVersion << 16) | lowVersion; +} + +static cl_uint getPlatformVersion(cl_platform_id platform) +{ + ::size_t size = 0; + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); + char* versionInfo = (char*)alloca(size); + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); + return getVersion(versionInfo); +} + +static cl_uint getDevicePlatformVersion(cl_device_id device) +{ + cl_platform_id platform; + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); + return getPlatformVersion(platform); +} + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +static cl_uint getContextPlatformVersion(cl_context context) +{ + // The platform cannot be queried directly, so we first have to grab a + // device and obtain its context + ::size_t size = 0; + clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); + if (size == 0) + return 0; + cl_device_id* devices = (cl_device_id*)alloca(size); + clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); + return getDevicePlatformVersion(devices[0]); +} +#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +template +class Wrapper +{ +public: + typedef T cl_type; + +protected: + cl_type object_; + +public: + Wrapper() : object_(NULL) {} + + Wrapper(const cl_type& obj) : object_(obj) {} + + ~Wrapper() + { + if (object_ != NULL) + { + release(); + } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + + Wrapper& operator=(const Wrapper& rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + return *this; + } + + Wrapper& operator=(const cl_type& rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs; + return *this; + } + + cl_type operator()() const { return object_; } + + cl_type& operator()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +template <> +class Wrapper +{ +public: + typedef cl_device_id cl_type; + +protected: + cl_type object_; + bool referenceCountable_; + + static bool isReferenceCountable(cl_device_id device) + { + bool retVal = false; + if (device != NULL) + { + int version = getDevicePlatformVersion(device); + if (version > ((1 << 16) + 1)) + { + retVal = true; + } + } + return retVal; + } + +public: + Wrapper() : object_(NULL), referenceCountable_(false) + { + } + + Wrapper(const cl_type& obj) : object_(obj), referenceCountable_(false) + { + referenceCountable_ = isReferenceCountable(obj); + } + + ~Wrapper() + { + if (object_ != NULL) + { + release(); + } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + referenceCountable_ = isReferenceCountable(object_); + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + + Wrapper& operator=(const Wrapper& rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + return *this; + } + + Wrapper& operator=(const cl_type& rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs; + referenceCountable_ = isReferenceCountable(object_); + return *this; + } + + cl_type operator()() const { return object_; } + + cl_type& operator()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + template + friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); + + cl_int retain() const + { + if (referenceCountable_) + { + return ReferenceHandler::retain(object_); + } + else + { + return CL_SUCCESS; + } + } + + cl_int release() const + { + if (referenceCountable_) + { + return ReferenceHandler::release(object_); + } + else + { + return CL_SUCCESS; + } + } +}; + +} // namespace detail +//! \endcond + +/*! \struct ImageFormat + * \brief Adds constructors and member functions for cl_image_format. + * + * \see cl_image_format + */ +struct ImageFormat : public cl_image_format +{ + //! \brief Default constructor - performs no initialization. + ImageFormat() {} + + //! \brief Initializing constructor. + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + //! \brief Assignment operator. + ImageFormat& operator=(const ImageFormat& rhs) + { + if (this != &rhs) + { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \brief Class interface for cl_device_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_device_id + */ +class Device : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Device() : detail::Wrapper() {} + + /*! \brief Copy constructor. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device(const Device& device) : detail::Wrapper(device) {} + + /*! \brief Constructor from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device(const cl_device_id& device) : detail::Wrapper(device) {} + + /*! \brief Returns the first device on the default context. + * + * \see Context::getDefault() + */ + static Device getDefault(cl_int* err = NULL); + + /*! \brief Assignment operator from Device. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device& operator=(const Device& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device& operator=(const cl_device_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetDeviceInfo(). + template + cl_int getInfo(cl_device_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + //! \brief Wrapper for clGetDeviceInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /** + * CL 1.2 version + */ +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clCreateSubDevicesEXT(). + cl_int createSubDevices( + const cl_device_partition_property* properties, + VECTOR_CLASS* devices) + { + cl_uint n = 0; + cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); + err = clCreateSubDevices(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(CL_VERSION_1_2) + +/** + * CL 1.1 version that uses device fission. + */ +#if defined(CL_VERSION_1_1) +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext* properties, + VECTOR_CLASS* devices) + { + typedef CL_API_ENTRY cl_int(CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + const cl_device_partition_property_ext* /* properties */, + cl_uint /*num_entries*/, + cl_device_id* /*out_devices*/, + cl_uint* /*num_devices*/) CL_EXT_SUFFIX__VERSION_1_1; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(USE_CL_DEVICE_FISSION) +#endif // #if defined(CL_VERSION_1_1) +}; + +/*! \brief Class interface for cl_platform_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_platform_id + */ +class Platform : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Platform() : detail::Wrapper() {} + + /*! \brief Copy constructor. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform(const Platform& platform) : detail::Wrapper(platform) {} + + /*! \brief Constructor from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform(const cl_platform_id& platform) : detail::Wrapper(platform) {} + + /*! \brief Assignment operator from Platform. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform& operator=(const Platform& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform& operator=(const cl_platform_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetPlatformInfo(). + cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + //! \brief Wrapper for clGetPlatformInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Gets a list of devices for this platform. + * + * Wraps clGetDeviceIDs(). + */ + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS* devices) const + { + cl_uint n = 0; + if (devices == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void* d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS* devices) const + { + typedef CL_API_ENTRY cl_int(CL_API_CALL * PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void* d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id* devices, + cl_uint* num_devices); + + if (devices == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + /*! \brief Gets a list of available platforms. + * + * Wraps clGetPlatformIDs(). + */ + static cl_int get( + VECTOR_CLASS* platforms) + { + cl_uint n = 0; + + if (platforms == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static cl_int get( + Platform* platform) + { + cl_uint n = 0; + + if (platform == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + *platform = ids[0]; + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform, returning it by value. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static Platform get( + cl_int* errResult = NULL) + { + Platform platform; + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) + { + *errResult = err; + } + } + + cl_platform_id* ids = (cl_platform_id*)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + + if (err != CL_SUCCESS) + { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + if (errResult != NULL) + { + *errResult = err; + } + + return ids[0]; + } + + static Platform getDefault( + cl_int* errResult = NULL) + { + return get(errResult); + } + + +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clUnloadCompiler(). + cl_int + unloadCompiler() + { + return ::clUnloadPlatformCompiler(object_); + } +#endif // #if defined(CL_VERSION_1_2) +}; // class Platform + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +/** + * Unload the OpenCL compiler. + * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int +UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline cl_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} +#endif // #if defined(CL_VERSION_1_1) + +/*! \brief Class interface for cl_context. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_context as the original. For details, see + * clRetainContext() and clReleaseContext(). + * + * \see cl_context + */ +class Context + : public detail::Wrapper +{ +private: + static volatile int default_initialized_; + static Context default_; + static volatile cl_int default_error_; + +public: + /*! \brief Destructor. + * + * This calls clReleaseContext() on the value held by this instance. + */ + ~Context() {} + + /*! \brief Constructs a context including a list of specified devices. + * + * Wraps clCreateContext(). + */ + Context( + const VECTOR_CLASS& devices, + cl_context_properties* properties = NULL, + void(CL_CALLBACK* notifyFptr)( + const char*, + const void*, + ::size_t, + void*) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateContext( + properties, (cl_uint)numDevices, + deviceIDs, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) + { + *err = error; + } + } + + Context( + const Device& device, + cl_context_properties* properties = NULL, + void(CL_CALLBACK* notifyFptr)( + const char*, + const void*, + ::size_t, + void*) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + cl_device_id deviceID = device(); + + object_ = ::clCreateContext( + properties, 1, + &deviceID, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Constructs a context including all devices of a specified type. + * + * Wraps clCreateContextFromType(). + */ + Context( + cl_device_type type, + cl_context_properties* properties = NULL, + void(CL_CALLBACK* notifyFptr)( + const char*, + const void*, + ::size_t, + void*) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + +#if !defined(__APPLE__) || !defined(__MACOS) + cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0}; + if (properties == NULL) + { + prop[1] = (cl_context_properties)Platform::get(&error)(); + if (error != CL_SUCCESS) + { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = error; + return; + } + } + + properties = &prop[0]; + } +#endif + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. + * + * \note All calls to this function return the same cl_context as the first. + */ + static Context getDefault(cl_int* err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) + { + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) + { + // Assume writes will propagate eventually... + while (default_initialized_ != __DEFAULT_INITIALIZED) + { + detail::fence(); + } + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + cl_int error; + default_ = Context( + CL_DEVICE_TYPE_DEFAULT, + NULL, + NULL, + NULL, + &error); + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + //! \brief Default constructor - initializes to NULL. + Context() : detail::Wrapper() {} + + /*! \brief Copy constructor. + * + * This calls clRetainContext() on the parameter's cl_context. + */ + Context(const Context& context) : detail::Wrapper(context) {} + + /*! \brief Constructor from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_context + * into the new Context object. + */ + __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) {} + + /*! \brief Assignment operator from Context. + * + * This calls clRetainContext() on the parameter and clReleaseContext() on + * the previous value held by this instance. + */ + Context& operator=(const Context& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseContext() on the value previously held by this instance. + */ + Context& operator=(const cl_context& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetContextInfo(). + template + cl_int getInfo(cl_context_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + //! \brief Wrapper for clGetContextInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Gets a list of supported image formats. + * + * Wraps clGetSupportedImageFormats(). + */ + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS* formats) const + { + cl_uint numEntries; + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + ImageFormat* value = (ImageFormat*) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format*)value, + NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + return CL_SUCCESS; + } +}; + +inline Device Device::getDefault(cl_int* err) +{ + cl_int error; + Device device; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + device = context.getInfo()[0]; + if (err != NULL) + { + *err = CL_SUCCESS; + } + } + + return device; +} + + +#ifdef _WIN32 +__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +__declspec(selectany) Context Context::default_; +__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; +#else +__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +__attribute__((weak)) Context Context::default_; +__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; +#endif + +/*! \brief Class interface for cl_event. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_event as the original. For details, see + * clRetainEvent() and clReleaseEvent(). + * + * \see cl_event + */ +class Event : public detail::Wrapper +{ +public: + /*! \brief Destructor. + * + * This calls clReleaseEvent() on the value held by this instance. + */ + ~Event() {} + + //! \brief Default constructor - initializes to NULL. + Event() : detail::Wrapper() {} + + /*! \brief Copy constructor. + * + * This calls clRetainEvent() on the parameter's cl_event. + */ + Event(const Event& event) : detail::Wrapper(event) {} + + /*! \brief Constructor from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_event + * into the new Event object. + */ + Event(const cl_event& event) : detail::Wrapper(event) {} + + /*! \brief Assignment operator from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseEvent() on the value previously held by this instance. + */ + Event& operator=(const Event& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_event. + * + * This calls clRetainEvent() on the parameter and clReleaseEvent() on + * the previous value held by this instance. + */ + Event& operator=(const cl_event& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetEventInfo(). + template + cl_int getInfo(cl_event_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + //! \brief Wrapper for clGetEventInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + //! \brief Wrapper for clGetEventProfilingInfo(). + template + cl_int getProfilingInfo(cl_profiling_info name, T* param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. + template + typename detail::param_traits::param_type + getProfilingInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Blocks the calling thread until this event completes. + * + * Wraps clWaitForEvents(). + */ + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a user callback function for a specific command execution status. + * + * Wraps clSetEventCallback(). + */ + cl_int setCallback( + cl_int type, + void(CL_CALLBACK* pfn_notify)(cl_event, cl_int, void*), + void* user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + /*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ + static cl_int + waitForEvents(const VECTOR_CLASS& events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint)events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); + } +}; + +#if defined(CL_VERSION_1_1) +/*! \brief Class interface for user events (a subset of cl_event's). + * + * See Event for details about copy semantics, etc. + */ +class UserEvent : public Event +{ +public: + /*! \brief Constructs a user event on a given context. + * + * Wraps clCreateUserEvent(). + */ + UserEvent( + const Context& context, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + UserEvent() : Event() {} + + //! \brief Copy constructor - performs shallow copy. + UserEvent(const UserEvent& event) : Event(event) {} + + //! \brief Assignment Operator - performs shallow copy. + UserEvent& operator=(const UserEvent& rhs) + { + if (this != &rhs) + { + Event::operator=(rhs); + } + return *this; + } + + /*! \brief Sets the execution status of a user event object. + * + * Wraps clSetUserEventStatus(). + */ + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_, status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +/*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ +inline static cl_int +WaitForEvents(const VECTOR_CLASS& events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint)events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \brief Class interface for cl_mem. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_mem as the original. For details, see + * clRetainMemObject() and clReleaseMemObject(). + * + * \see cl_mem + */ +class Memory : public detail::Wrapper +{ +public: + /*! \brief Destructor. + * + * This calls clReleaseMemObject() on the value held by this instance. + */ + ~Memory() {} + + //! \brief Default constructor - initializes to NULL. + Memory() : detail::Wrapper() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * This calls clRetainMemObject() on the parameter's cl_mem. + */ + Memory(const Memory& memory) : detail::Wrapper(memory) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_mem + * into the new Memory object. + */ + __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) {} + + /*! \brief Assignment operator from Memory. + * + * This calls clRetainMemObject() on the parameter and clReleaseMemObject() + * on the previous value held by this instance. + */ + Memory& operator=(const Memory& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseMemObject() on the value previously held by this instance. + */ + Memory& operator=(const cl_mem& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetMemObjectInfo(). + template + cl_int getInfo(cl_mem_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + //! \brief Wrapper for clGetMemObjectInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a callback function to be called when the memory object + * is no longer needed. + * + * Wraps clSetMemObjectDestructorCallback(). + * + * Repeated calls to this function, for a given cl_mem value, will append + * to the list of functions called (in reverse order) when memory object's + * resources are freed and the memory object is deleted. + * + * \note + * The registered callbacks are associated with the underlying cl_mem + * value - not the Memory class instance. + */ + cl_int setDestructorCallback( + void(CL_CALLBACK* pfn_notify)(cl_mem, void*), + void* user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif +}; + +// Pre-declare copy functions +class Buffer; +template +cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer& buffer); +template +cl_int copy(const cl::Buffer& buffer, IteratorType startIterator, IteratorType endIterator); + +/*! \brief Class interface for Buffer Memory Objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Buffer : public Memory +{ +public: + /*! \brief Constructs a Buffer in a specified context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + */ + Buffer( + const Context& context, + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Constructs a Buffer in the default context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + * + * \see Context::getDefault() + */ + Buffer( + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(err); + + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators. + * If useHostPtr is specified iterators must be random access. + */ + template + Buffer( + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr = false, + cl_int* err = NULL) + { + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) + { + flags |= CL_MEM_READ_ONLY; + } + else + { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) + { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType) * (endIterator - startIterator); + + Context context = Context::getDefault(err); + + if (useHostPtr) + { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else + { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + if (!useHostPtr) + { + error = cl::copy(startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + } + + //! \brief Default constructor - initializes to NULL. + Buffer() : Memory() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Buffer(const Buffer& buffer) : Memory(buffer) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) {} + + /*! \brief Assignment from Buffer - performs shallow copy. + * + * See Memory for further details. + */ + Buffer& operator=(const Buffer& rhs) + { + if (this != &rhs) + { + Memory::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Buffer& operator=(const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + +#if defined(CL_VERSION_1_1) + /*! \brief Creates a new buffer object from this. + * + * Wraps clCreateSubBuffer(). + */ + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void* buffer_create_info, + cl_int* err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + return result; + } +#endif +}; + +#if defined(USE_DX_INTEROP) +/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. + * + * This is provided to facilitate interoperability with Direct3D. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferD3D10 : public Buffer +{ +public: + typedef CL_API_ENTRY cl_mem(CL_API_CALL* PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, + cl_int* errcode_ret); + + /*! \brief Constructs a BufferD3D10, in a specified context, from a + * given ID3D10Buffer. + * + * Wraps clCreateFromD3D10BufferKHR(). + */ + BufferD3D10( + const Context& context, + cl_mem_flags flags, + ID3D10Buffer* bufobj, + cl_int* err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + +#if defined(CL_VERSION_1_2) + vector props = context.getInfo(); + cl_platform platform = -1; + for (int i = 0; i < props.size(); ++i) + { + if (props[i] == CL_CONTEXT_PLATFORM) + { + platform = props[i + 1]; + } + } + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); +#endif + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferD3D10() : Buffer() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10(const BufferD3D10& buffer) : Buffer(buffer) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) {} + + /*! \brief Assignment from BufferD3D10 - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10& operator=(const BufferD3D10& rhs) + { + if (this != &rhs) + { + Buffer::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10& operator=(const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } +}; +#endif + +/*! \brief Class interface for GL Buffer Memory Objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferGL : public Buffer +{ +public: + /*! \brief Constructs a BufferGL in a specified context, from a given + * GL buffer. + * + * Wraps clCreateFromGLBuffer(). + */ + BufferGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferGL() : Buffer() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL(const BufferGL& buffer) : Buffer(buffer) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) {} + + /*! \brief Assignment from BufferGL - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL& operator=(const BufferGL& rhs) + { + if (this != &rhs) + { + Buffer::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL& operator=(const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type* type, + GLuint* gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief Class interface for GL Render Buffer Memory Objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferRenderGL : public Buffer +{ +public: + /*! \brief Constructs a BufferRenderGL in a specified context, from a given + * GL Renderbuffer. + * + * Wraps clCreateFromGLRenderbuffer(). + */ + BufferRenderGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferRenderGL() : Buffer() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL(const BufferGL& buffer) : Buffer(buffer) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Buffer(buffer) {} + + /*! \brief Assignment from BufferGL - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL& operator=(const BufferRenderGL& rhs) + { + if (this != &rhs) + { + Buffer::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL& operator=(const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type* type, + GLuint* gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief C++ base class for Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image : public Memory +{ +protected: + //! \brief Default constructor - initializes to NULL. + Image() : Memory() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image(const Image& image) : Memory(image) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) {} + + /*! \brief Assignment from Image - performs shallow copy. + * + * See Memory for further details. + */ + Image& operator=(const Image& rhs) + { + if (this != &rhs) + { + Memory::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image& operator=(const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + +public: + //! \brief Wrapper for clGetImageInfo(). + template + cl_int getImageInfo(cl_image_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + //! \brief Wrapper for clGetImageInfo() that returns by value. + template + typename detail::param_traits::param_type + getImageInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +}; + +#if defined(CL_VERSION_1_2) +/*! \brief Class interface for 1D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image1D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image1D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE1D; + desc.image_width = width; + desc.image_row_pitch = 0; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = 0; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image1D() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image1D(const Image1D& image1D) : Image(image1D) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) {} + + /*! \brief Assignment from Image1D - performs shallow copy. + * + * See Memory for further details. + */ + Image1D& operator=(const Image1D& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image1D& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; + +/*! \class Image1DBuffer + * \brief Image interface for 1D buffer images. + */ +class Image1DBuffer : public Image +{ +public: + Image1DBuffer( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + const Buffer& buffer, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER; + desc.image_width = width; + desc.image_row_pitch = 0; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = buffer(); + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + NULL, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image1DBuffer() {} + + Image1DBuffer(const Image1DBuffer& image1D) : Image(image1D) {} + + __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) {} + + Image1DBuffer& operator=(const Image1DBuffer& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + Image1DBuffer& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; + +/*! \class Image1DArray + * \brief Image interface for arrays of 1D images. + */ +class Image1DArray : public Image +{ +public: + Image1DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t rowPitch, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY; + desc.image_array_size = arraySize; + desc.image_width = width; + desc.image_row_pitch = rowPitch; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = 0; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image1DArray() {} + + Image1DArray(const Image1DArray& imageArray) : Image(imageArray) {} + + __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) {} + + Image1DArray& operator=(const Image1DArray& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + Image1DArray& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; +#endif // #if defined(CL_VERSION_1_2) + + +/*! \brief Class interface for 2D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image2D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image2D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_width = width; + desc.image_height = height; + desc.image_row_pitch = row_pitch; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = 0; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage2D( + context(), flags, &format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image2D() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image2D(const Image2D& image2D) : Image(image2D) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) {} + + /*! \brief Assignment from Image2D - performs shallow copy. + * + * See Memory for further details. + */ + Image2D& operator=(const Image2D& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2D& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; + + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 2D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D +{ +public: + /*! \brief Constructs an Image2DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture2D(). + */ + Image2DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image2DGL() : Image2D() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL(const Image2DGL& image) : Image2D(image) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) {} + + /*! \brief Assignment from Image2DGL - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL& operator=(const Image2DGL& rhs) + { + if (this != &rhs) + { + Image2D::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL& operator=(const cl_mem& rhs) + { + Image2D::operator=(rhs); + return *this; + } +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class Image2DArray + * \brief Image interface for arrays of 2D images. + */ +class Image2DArray : public Image +{ +public: + Image2DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t height, + ::size_t rowPitch, + ::size_t slicePitch, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; + desc.image_array_size = arraySize; + desc.image_width = width; + desc.image_height = height; + desc.image_row_pitch = rowPitch; + desc.image_slice_pitch = slicePitch; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = 0; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image2DArray() {} + + Image2DArray(const Image2DArray& imageArray) : Image(imageArray) {} + + __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) {} + + Image2DArray& operator=(const Image2DArray& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + Image2DArray& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for 3D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3D : public Image +{ +public: + /*! \brief Constructs a 3D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image3D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE3D; + desc.image_width = width; + desc.image_height = height; + desc.image_depth = depth; + desc.image_row_pitch = row_pitch; + desc.image_slice_pitch = slice_pitch; + desc.num_mip_levels = 0; + desc.num_samples = 0; + desc.buffer = 0; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image3D() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image3D(const Image3D& image3D) : Image(image3D) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) {} + + /*! \brief Assignment from Image3D - performs shallow copy. + * + * See Memory for further details. + */ + Image3D& operator=(const Image3D& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3D& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 3D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3DGL : public Image3D +{ +public: + /*! \brief Constructs an Image3DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture3D(). + */ + Image3DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image3DGL() : Image3D() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL(const Image3DGL& image) : Image3D(image) {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) {} + + /*! \brief Assignment from Image3DGL - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL& operator=(const Image3DGL& rhs) + { + if (this != &rhs) + { + Image3D::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL& operator=(const cl_mem& rhs) + { + Image3D::operator=(rhs); + return *this; + } +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class ImageGL + * \brief general image interface for GL interop. + * We abstract the 2D and 3D GL images into a single instance here + * that wraps all GL sourced images on the grounds that setup information + * was performed by OpenCL anyway. + */ +class ImageGL : public Image +{ +public: + ImageGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); + if (err != NULL) + { + *err = error; + } + } + + ImageGL() : Image() {} + + ImageGL(const ImageGL& image) : Image(image) {} + + __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) {} + + ImageGL& operator=(const ImageGL& rhs) + { + if (this != &rhs) + { + Image::operator=(rhs); + } + return *this; + } + + ImageGL& operator=(const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for cl_sampler. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_sampler as the original. For details, see + * clRetainSampler() and clReleaseSampler(). + * + * \see cl_sampler + */ +class Sampler : public detail::Wrapper +{ +public: + /*! \brief Destructor. + * + * This calls clReleaseSampler() on the value held by this instance. + */ + ~Sampler() {} + + //! \brief Default constructor - initializes to NULL. + Sampler() {} + + /*! \brief Constructs a Sampler in a specified context. + * + * Wraps clCreateSampler(). + */ + Sampler( + const Context& context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Copy constructor - performs shallow copy. + * + * This calls clRetainSampler() on the parameter's cl_sampler. + */ + Sampler(const Sampler& sampler) : detail::Wrapper(sampler) {} + + /*! \brief Constructor from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_sampler + * into the new Sampler object. + */ + Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) {} + + /*! \brief Assignment operator from Sampler. + * + * This calls clRetainSampler() on the parameter and clReleaseSampler() + * on the previous value held by this instance. + */ + Sampler& operator=(const Sampler& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseSampler() on the value previously held by this instance. + */ + Sampler& operator=(const cl_sampler& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetSamplerInfo(). + template + cl_int getInfo(cl_sampler_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + //! \brief Wrapper for clGetSamplerInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +}; + +class Program; +class CommandQueue; +class Kernel; + +//! \brief Class interface for specifying NDRange values. +class NDRange +{ +private: + size_t<3> sizes_; + cl_uint dimensions_; + +public: + //! \brief Default constructor - resulting range has zero dimensions. + NDRange() + : dimensions_(0) + { + } + + //! \brief Constructs one-dimensional range. + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_[0] = size0; + } + + //! \brief Constructs two-dimensional range. + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_[0] = size0; + sizes_[1] = size1; + } + + //! \brief Constructs three-dimensional range. + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_[0] = size0; + sizes_[1] = size1; + sizes_[2] = size2; + } + + /*! \brief Conversion operator to const ::size_t *. + * + * \returns a pointer to the size of the first dimension. + */ + operator const ::size_t*() const + { + return (const ::size_t*)sizes_; + } + + //! \brief Queries the number of dimensions in the range. + ::size_t dimensions() const { return dimensions_; } +}; + +//! \brief A zero-dimensional range. +static const NDRange NullRange; + +//! \brief Local address wrapper for use with Kernel::setArg +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail +{ +template +struct KernelArgumentHandler +{ + static ::size_t size(const T&) { return sizeof(T); } + static T* ptr(T& value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg& value) { return value.size_; } + static void* ptr(LocalSpaceArg&) { return NULL; } +}; + +} // namespace detail +//! \endcond + +/*! __local + * \brief Helper function for generating LocalSpaceArg objects. + * Deprecated. Replaced with Local. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg +__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = {size}; + return ret; +} + +/*! Local + * \brief Helper function for generating LocalSpaceArg objects. + */ +inline LocalSpaceArg +Local(::size_t size) +{ + LocalSpaceArg ret = {size}; + return ret; +} + +//class KernelFunctor; + +/*! \brief Class interface for cl_kernel. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_kernel as the original. For details, see + * clRetainKernel() and clReleaseKernel(). + * + * \see cl_kernel + */ +class Kernel : public detail::Wrapper +{ +public: + inline Kernel(const Program& program, const char* name, cl_int* err = NULL); + + /*! \brief Destructor. + * + * This calls clReleaseKernel() on the value held by this instance. + */ + ~Kernel() {} + + //! \brief Default constructor - initializes to NULL. + Kernel() {} + + /*! \brief Copy constructor - performs shallow copy. + * + * This calls clRetainKernel() on the parameter's cl_kernel. + */ + Kernel(const Kernel& kernel) : detail::Wrapper(kernel) {} + + /*! \brief Constructor from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_kernel + * into the new Kernel object. + */ + __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) {} + + /*! \brief Assignment operator from Kernel. + * + * This calls clRetainKernel() on the parameter and clReleaseKernel() + * on the previous value held by this instance. + */ + Kernel& operator=(const Kernel& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + /*! \brief Assignment operator from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseKernel() on the value previously held by this instance. + */ + Kernel& operator=(const cl_kernel& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + template + cl_int getInfo(cl_kernel_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_2) + template + cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), + __GET_KERNEL_ARG_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getArgInfo(cl_uint argIndex, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_arg_info, name>::param_type param; + cl_int result = getArgInfo(argIndex, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +#endif // #if defined(CL_VERSION_1_2) + + template + cl_int getWorkGroupInfo( + const Device& device, cl_kernel_work_group_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getWorkGroupInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, T value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, void* argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } +}; + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ +public: + typedef VECTOR_CLASS > Binaries; + typedef VECTOR_CLASS > Sources; + + Program( + const STRING_CLASS& source, + cl_int* err = NULL) + { + cl_int error; + + const char* strings = source.c_str(); + const ::size_t length = source.size(); + + Context context = Context::getDefault(err); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS) + { + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) + { + *err = error; + } + } + + Program( + const STRING_CLASS& source, + bool build, + cl_int* err = NULL) + { + cl_int error; + + const char* strings = source.c_str(); + const ::size_t length = source.size(); + + Context context = Context::getDefault(err); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) + { + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) + { + *err = error; + } + } + + Program( + const Context& context, + const STRING_CLASS& source, + bool build = false, + cl_int* err = NULL) + { + cl_int error; + + const char* strings = source.c_str(); + const ::size_t length = source.size(); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) + { + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) + { + *err = error; + } + } + + Program( + const Context& context, + const Sources& sources, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t* lengths = (::size_t*)alloca(n * sizeof(::size_t)); + const char** strings = (const char**)alloca(n * sizeof(const char*)); + + for (::size_t i = 0; i < n; ++i) + { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) + { + *err = error; + } + } + + /** + * Construct a program object from a list of devices and a per-device list of binaries. + * \param context A valid OpenCL context in which to construct the program. + * \param devices A vector of OpenCL device objects for which the program will be created. + * \param binaries A vector of pairs of a pointer to a binary object and its length. + * \param binaryStatus An optional vector that on completion will be resized to + * match the size of binaries and filled with values to specify if each binary + * was successfully loaded. + * Set to CL_SUCCESS if the binary was successfully loaded. + * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. + * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. + * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: + * CL_INVALID_CONTEXT if context is not a valid context. + * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; + * or if any entry in binaries is NULL or has length 0. + * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. + * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. + * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const Binaries& binaries, + VECTOR_CLASS* binaryStatus = NULL, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t numDevices = devices.size(); + + // Catch size mismatch early and return + if (binaries.size() != numDevices) + { + error = CL_INVALID_VALUE; + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) + { + *err = error; + } + return; + } + + ::size_t* lengths = (::size_t*)alloca(numDevices * sizeof(::size_t)); + const unsigned char** images = (const unsigned char**)alloca(numDevices * sizeof(const unsigned char**)); + + for (::size_t i = 0; i < numDevices; ++i) + { + images[i] = (const unsigned char*)binaries[i].first; + lengths[i] = binaries[(int)i].second; + } + + cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + if (binaryStatus) + { + binaryStatus->resize(numDevices); + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint)devices.size(), + deviceIDs, + lengths, images, binaryStatus != NULL ? &binaryStatus->front() : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) + { + *err = error; + } + } + + +#if defined(CL_VERSION_1_2) + /** + * Create program using builtin kernels. + * \param kernelNames Semi-colon separated list of builtin kernel names + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const STRING_CLASS& kernelNames, + cl_int* err = NULL) + { + cl_int error; + + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateProgramWithBuiltInKernels( + context(), + (cl_uint)devices.size(), + deviceIDs, + kernelNames.c_str(), + &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) + + Program() + { + } + + Program(const Program& program) : detail::Wrapper(program) {} + + __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) {} + + Program& operator=(const Program& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + Program& operator=(const cl_program& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + cl_int build( + const VECTOR_CLASS& devices, + const char* options = NULL, + void(CL_CALLBACK* notifyFptr)(cl_program, void*) = NULL, + void* data = NULL) const + { + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + deviceIDs, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + cl_int build( + const char* options = NULL, + void(CL_CALLBACK* notifyFptr)(cl_program, void*) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + 0, + NULL, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + +#if defined(CL_VERSION_1_2) + cl_int compile( + const char* options = NULL, + void(CL_CALLBACK* notifyFptr)(cl_program, void*) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clCompileProgram( + object_, + 0, + NULL, + options, + 0, + NULL, + NULL, + notifyFptr, + data), + __COMPILE_PROGRAM_ERR); + } +#endif + + template + cl_int getInfo(cl_program_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device& device, cl_program_build_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getBuildInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS* kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel* value = (Kernel*)alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel*)value, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +#if defined(CL_VERSION_1_2) +inline Program linkProgram( + Program input1, + Program input2, + const char* options = NULL, + void(CL_CALLBACK* notifyFptr)(cl_program, void*) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int err_local = CL_SUCCESS; + + cl_program programs[2] = {input1(), input2()}; + + Context ctx = input1.getInfo(); + + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + 2, + programs, + notifyFptr, + data, + &err_local); + + detail::errHandler(err_local, __COMPILE_PROGRAM_ERR); + if (err != NULL) + { + *err = err_local; + } + + return Program(prog); +} + +inline Program linkProgram( + VECTOR_CLASS inputPrograms, + const char* options = NULL, + void(CL_CALLBACK* notifyFptr)(cl_program, void*) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int err_local = CL_SUCCESS; + + cl_program* programs = (cl_program*)alloca(inputPrograms.size() * sizeof(cl_program)); + + if (programs != NULL) + { + for (unsigned int i = 0; i < inputPrograms.size(); i++) + { + programs[i] = inputPrograms[i](); + } + } + + cl_program prog = ::clLinkProgram( + Context::getDefault()(), + 0, + NULL, + options, + (cl_uint)inputPrograms.size(), + programs, + notifyFptr, + data, + &err_local); + + detail::errHandler(err_local, __COMPILE_PROGRAM_ERR); + if (err != NULL) + { + *err = err_local; + } + + return Program(prog); +} +#endif + +template <> +inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const +{ + VECTOR_CLASS< ::size_t> sizes = getInfo(); + VECTOR_CLASS binaries; + for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) + { + char* ptr = NULL; + if (*s != 0) + ptr = new char[*s]; + binaries.push_back(ptr); + } + + cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); + if (err != NULL) + { + *err = result; + } + return binaries; +} + +inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) + { + *err = error; + } +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ +private: + static volatile int default_initialized_; + static CommandQueue default_; + static volatile cl_int default_error_; + +public: + CommandQueue( + cl_command_queue_properties properties, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + Device device = context.getInfo()[0]; + + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + } + + CommandQueue( + const Context& context, + const Device& device, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + + static CommandQueue getDefault(cl_int* err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) + { + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) + { + // Assume writes will propagate eventually... + while (default_initialized_ != __DEFAULT_INITIALIZED) + { + detail::fence(); + } + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + Device device = context.getInfo()[0]; + + default_ = CommandQueue(context, device, 0, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + CommandQueue() {} + + CommandQueue(const CommandQueue& commandQueue) : detail::Wrapper(commandQueue) {} + + CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) {} + + CommandQueue& operator=(const CommandQueue& rhs) + { + if (this != &rhs) + { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + CommandQueue& operator=(const cl_command_queue& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t*)buffer_offset, + (const ::size_t*)host_offset, + (const ::size_t*)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t*)buffer_offset, + (const ::size_t*)host_offset, + (const ::size_t*)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t*)src_origin, + (const ::size_t*)dst_origin, + (const ::size_t*)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill a buffer object with a pattern + * of a given size. The pattern is specified a as vector. + * \tparam PatternType The datatype of the pattern field. + * The pattern type must be an accepted OpenCL data type. + */ + template + cl_int enqueueFillBuffer( + const Buffer& buffer, + PatternType pattern, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillBuffer( + object_, + buffer(), + static_cast(&pattern), + sizeof(PatternType), + offset, + size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t*)origin, + (const ::size_t*)region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t*)origin, + (const ::size_t*)region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t*)src_origin, + (const ::size_t*)dst_origin, (const ::size_t*)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA floating-point color value if + * the image channel data type is not an unnormalized signed or + * unsigned data type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_float4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t*)origin, + (const ::size_t*)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA signed integer color value if + * the image channel data type is an unnormalized signed integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_int4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t*)origin, + (const ::size_t*)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA unsigned integer color value if + * the image channel data type is an unnormalized unsigned integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_uint4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t*)origin, + (const ::size_t*)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t*)src_origin, + (const ::size_t*)region, dst_offset, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t*)dst_origin, (const ::size_t*)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void* result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (cl_event*)event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + return result; + } + + void* enqueueMapImage( + const Image& buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t* row_pitch, + ::size_t* slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void* result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t*)origin, (const ::size_t*)region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (cl_event*)event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueues a marker command which waits for either a list of events to complete, + * or all previously enqueued commands to complete. + * + * Enqueues a marker command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command returns an event which can be waited on, + * i.e. this event can be waited on to insure that all events either in the event_wait_list + * or all previously enqueued commands, queued before this command to command_queue, + * have completed. + */ + cl_int enqueueMarkerWithWaitList( + const VECTOR_CLASS* events = 0, + Event* event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarkerWithWaitList( + object_, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * A synchronization point that enqueues a barrier operation. + * + * Enqueues a barrier command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command blocks command execution, that is, any + * following commands enqueued after it do not execute until it completes. This command + * returns an event which can be waited on, i.e. this event can be waited on to insure that + * all events either in the event_wait_list or all previously enqueued commands, queued + * before this command to command_queue, have completed. + */ + cl_int enqueueBarrierWithWaitList( + const VECTOR_CLASS* events = 0, + Event* event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueBarrierWithWaitList( + object_, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_BARRIER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueues a command to indicate with which device a set of memory objects + * should be associated. + */ + cl_int enqueueMigrateMemObjects( + const VECTOR_CLASS& memObjects, + cl_mem_migration_flags flags, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) + { + cl_event tmp; + + cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); + for (int i = 0; i < (int)memObjects.size(); ++i) + { + localMemObjects[i] = memObjects[i](); + } + + + cl_int err = detail::errHandler( + ::clEnqueueMigrateMemObjects( + object_, + (cl_uint)memObjects.size(), + static_cast(localMemObjects), + flags, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueNDRangeKernel( + const Kernel& kernel, + const NDRange& offset, + const NDRange& global, + const NDRange& local = NullRange, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint)global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t*)offset : NULL, + (const ::size_t*)global, + local.dimensions() != 0 ? (const ::size_t*)local : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NDRANGE_KERNEL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueTask( + const Kernel& kernel, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_TASK_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueNativeKernel( + void(CL_CALLBACK* userFptr)(void*), + std::pair args, + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* mem_locs = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_mem* mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem*)alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) + { + for (unsigned int i = 0; i < mem_objects->size(); i++) + { + mems[i] = ((*mem_objects)[i])(); + } + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + mems, + (mem_locs != NULL) ? (const void**)&mem_locs->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NATIVE_KERNEL); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueMarker(object_, (cl_event*)event), + __ENQUEUE_MARKER_ERR); + } + + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint)events.size(), + (const cl_event*)&events.front()), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem*)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem*)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(USE_DX_INTEROP) + typedef CL_API_ENTRY cl_int(CL_API_CALL* PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + typedef CL_API_ENTRY cl_int(CL_API_CALL* PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); +#endif + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem*)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_2) +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_1) + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem*)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +#ifdef _WIN32 +__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +__declspec(selectany) CommandQueue CommandQueue::default_; +__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#else +__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +__attribute__((weak)) CommandQueue CommandQueue::default_; +__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#endif + +inline cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + void* result = ::clEnqueueMapBuffer( + queue(), buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (cl_event*)event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + return result; +} + +inline cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (error != CL_SUCCESS) + { + return error; + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + queue(), memory(), mapped_ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; +} + +inline cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); +} + +/** + * Blocking copy operation between iterators and a buffer. + */ +template +inline cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer& buffer) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator - startIterator; + ::size_t byteLength = length * sizeof(DataType); + + DataType* pointer = + static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if (error != CL_SUCCESS) + { + return error; + } +#if defined(_MSC_VER) + std::copy( + startIterator, + endIterator, + stdext::checked_array_iterator( + pointer, length)); +#else + std::copy(startIterator, endIterator, pointer); +#endif + Event endEvent; + error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if (error != CL_SUCCESS) + { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +/** + * Blocking copy operation between iterators and a buffer. + */ +template +inline cl_int copy(const cl::Buffer& buffer, IteratorType startIterator, IteratorType endIterator) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator - startIterator; + ::size_t byteLength = length * sizeof(DataType); + + DataType* pointer = + static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if (error != CL_SUCCESS) + { + return error; + } + std::copy(pointer, pointer + length, startIterator); + Event endEvent; + error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if (error != CL_SUCCESS) + { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +#if defined(CL_VERSION_1_1) +inline cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBufferRect( + src, + dst, + src_origin, + dst_origin, + region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + events, + event); +} +#endif + +inline cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyImage( + src, + dst, + src_origin, + dst_origin, + region, + events, + event); +} + +inline cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyImageToBuffer( + src, + dst, + src_origin, + region, + dst_offset, + events, + event); +} + +inline cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBufferToImage( + src, + dst, + src_offset, + dst_origin, + region, + events, + event); +} + + +inline cl_int flush(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.flush(); +} + +inline cl_int finish(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + + return queue.finish(); +} + +// Kernel Functor support +// New interface as of September 2011 +// Requires the C++11 std::tr1::function (note do not support TR1) +// Visual Studio 2010 and GCC 4.2 + +struct EnqueueArgs +{ + CommandQueue queue_; + const NDRange offset_; + const NDRange global_; + const NDRange local_; + VECTOR_CLASS events_; + + EnqueueArgs(NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + } + + EnqueueArgs(NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + } + + EnqueueArgs(NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + } + + EnqueueArgs(Event e, NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(const VECTOR_CLASS& events, NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + } + + EnqueueArgs(const VECTOR_CLASS& events, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(const VECTOR_CLASS& events, NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(CommandQueue& queue, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + } + + EnqueueArgs(CommandQueue& queue, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + } + + EnqueueArgs(CommandQueue& queue, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + } + + EnqueueArgs(CommandQueue& queue, Event e, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue& queue, Event e, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue& queue, Event e, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue& queue, const VECTOR_CLASS& events, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + } + + EnqueueArgs(CommandQueue& queue, const VECTOR_CLASS& events, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(CommandQueue& queue, const VECTOR_CLASS& events, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + } +}; + +namespace detail +{ +class NullType +{ +}; + +template +struct SetArg +{ + static void set(Kernel kernel, T0 arg) + { + kernel.setArg(index, arg); + } +}; + +template +struct SetArg +{ + static void set(Kernel, NullType) + { + } +}; + +template < + typename T0, typename T1, typename T2, typename T3, + typename T4, typename T5, typename T6, typename T7, + typename T8, typename T9, typename T10, typename T11, + typename T12, typename T13, typename T14, typename T15, + typename T16, typename T17, typename T18, typename T19, + typename T20, typename T21, typename T22, typename T23, + typename T24, typename T25, typename T26, typename T27, + typename T28, typename T29, typename T30, typename T31> +class KernelFunctorGlobal +{ +private: + Kernel kernel_; + +public: + KernelFunctorGlobal( + Kernel kernel) : kernel_(kernel) + { + } + + KernelFunctorGlobal( + const Program& program, + const STRING_CLASS name, + cl_int* err = NULL) : kernel_(program, name.c_str(), err) + { + } + + Event operator()( + const EnqueueArgs& args, + T0 t0, + T1 t1 = NullType(), + T2 t2 = NullType(), + T3 t3 = NullType(), + T4 t4 = NullType(), + T5 t5 = NullType(), + T6 t6 = NullType(), + T7 t7 = NullType(), + T8 t8 = NullType(), + T9 t9 = NullType(), + T10 t10 = NullType(), + T11 t11 = NullType(), + T12 t12 = NullType(), + T13 t13 = NullType(), + T14 t14 = NullType(), + T15 t15 = NullType(), + T16 t16 = NullType(), + T17 t17 = NullType(), + T18 t18 = NullType(), + T19 t19 = NullType(), + T20 t20 = NullType(), + T21 t21 = NullType(), + T22 t22 = NullType(), + T23 t23 = NullType(), + T24 t24 = NullType(), + T25 t25 = NullType(), + T26 t26 = NullType(), + T27 t27 = NullType(), + T28 t28 = NullType(), + T29 t29 = NullType(), + T30 t30 = NullType(), + T31 t31 = NullType()) + { + Event event; + SetArg<0, T0>::set(kernel_, t0); + SetArg<1, T1>::set(kernel_, t1); + SetArg<2, T2>::set(kernel_, t2); + SetArg<3, T3>::set(kernel_, t3); + SetArg<4, T4>::set(kernel_, t4); + SetArg<5, T5>::set(kernel_, t5); + SetArg<6, T6>::set(kernel_, t6); + SetArg<7, T7>::set(kernel_, t7); + SetArg<8, T8>::set(kernel_, t8); + SetArg<9, T9>::set(kernel_, t9); + SetArg<10, T10>::set(kernel_, t10); + SetArg<11, T11>::set(kernel_, t11); + SetArg<12, T12>::set(kernel_, t12); + SetArg<13, T13>::set(kernel_, t13); + SetArg<14, T14>::set(kernel_, t14); + SetArg<15, T15>::set(kernel_, t15); + SetArg<16, T16>::set(kernel_, t16); + SetArg<17, T17>::set(kernel_, t17); + SetArg<18, T18>::set(kernel_, t18); + SetArg<19, T19>::set(kernel_, t19); + SetArg<20, T20>::set(kernel_, t20); + SetArg<21, T21>::set(kernel_, t21); + SetArg<22, T22>::set(kernel_, t22); + SetArg<23, T23>::set(kernel_, t23); + SetArg<24, T24>::set(kernel_, t24); + SetArg<25, T25>::set(kernel_, t25); + SetArg<26, T26>::set(kernel_, t26); + SetArg<27, T27>::set(kernel_, t27); + SetArg<28, T28>::set(kernel_, t28); + SetArg<29, T29>::set(kernel_, t29); + SetArg<30, T30>::set(kernel_, t30); + SetArg<31, T31>::set(kernel_, t31); + + args.queue_.enqueueNDRangeKernel( + kernel_, + args.offset_, + args.global_, + args.local_, + &args.events_, + &event); + + return event; + } +}; + +//------------------------------------------------------------------------------------------------------ + + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30, + typename T31> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30, + T31 arg31) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30, + arg31); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3); + } +}; + +template < + typename T0, + typename T1, + typename T2> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2); + } +}; + +template < + typename T0, + typename T1> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1) + { + return functor_( + enqueueArgs, + arg0, + arg1); + } +}; + +template < + typename T0> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType& functor) : functor_(functor) + { +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0) + { + return functor_( + enqueueArgs, + arg0); + } +}; + + +} // namespace detail + +//---------------------------------------------------------------------------------------------- + +template < + typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, + typename T3 = detail::NullType, typename T4 = detail::NullType, + typename T5 = detail::NullType, typename T6 = detail::NullType, + typename T7 = detail::NullType, typename T8 = detail::NullType, + typename T9 = detail::NullType, typename T10 = detail::NullType, + typename T11 = detail::NullType, typename T12 = detail::NullType, + typename T13 = detail::NullType, typename T14 = detail::NullType, + typename T15 = detail::NullType, typename T16 = detail::NullType, + typename T17 = detail::NullType, typename T18 = detail::NullType, + typename T19 = detail::NullType, typename T20 = detail::NullType, + typename T21 = detail::NullType, typename T22 = detail::NullType, + typename T23 = detail::NullType, typename T24 = detail::NullType, + typename T25 = detail::NullType, typename T26 = detail::NullType, + typename T27 = detail::NullType, typename T28 = detail::NullType, + typename T29 = detail::NullType, typename T30 = detail::NullType, + typename T31 = detail::NullType> +struct make_kernel : public detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31> +{ +public: + typedef detail::KernelFunctorGlobal< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31> + FunctorType; + + make_kernel( + const Program& program, + const STRING_CLASS name, + cl_int* err = NULL) : detail::functionImplementation_( + FunctorType(program, name, err)) + { + } + + make_kernel( + const Kernel kernel) : detail::functionImplementation_( + FunctorType(kernel)) + { + } +}; + + +//---------------------------------------------------------------------------------------------------------------------- + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_ARG_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_ERR +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR +#undef __SET_PRINTF_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __CL_EXPLICIT_CONSTRUCTORS + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __CL_FUNCTION_TYPE + +// Extensions +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_VERSION_1_1) +#undef __INIT_CL_EXT_FCN_PTR +#endif // #if defined(CL_VERSION_1_1) +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +#undef __DEFAULT_NOT_INITIALIZED +#undef __DEFAULT_BEING_INITIALIZED +#undef __DEFAULT_INITIALIZED + +} // namespace cl + +#ifdef _WIN32 +#pragma pop_macro("max") +#endif // _WIN32 + +#endif // CL_HPP_ diff --git a/src/algorithms/libs/clFFT.h b/src/algorithms/libs/opencl/clFFT.h similarity index 62% rename from src/algorithms/libs/clFFT.h rename to src/algorithms/libs/opencl/clFFT.h index d1e3a8fc4..9f9c8c1d3 100644 --- a/src/algorithms/libs/clFFT.h +++ b/src/algorithms/libs/opencl/clFFT.h @@ -50,85 +50,86 @@ #define __CLFFT_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include #ifdef __APPLE__ - #include +#include #else - #include +#include #endif -// XForm type -typedef enum -{ - clFFT_Forward = -1, - clFFT_Inverse = 1 - -}clFFT_Direction; + // XForm type + typedef enum + { + clFFT_Forward = -1, + clFFT_Inverse = 1 -// XForm dimension -typedef enum -{ - clFFT_1D = 0, - clFFT_2D = 1, - clFFT_3D = 3 - -}clFFT_Dimension; + } clFFT_Direction; -// XForm Data type -typedef enum -{ - clFFT_SplitComplexFormat = 0, - clFFT_InterleavedComplexFormat = 1 -}clFFT_DataFormat; + // XForm dimension + typedef enum + { + clFFT_1D = 0, + clFFT_2D = 1, + clFFT_3D = 3 -typedef struct -{ - unsigned int x; - unsigned int y; - unsigned int z; -}clFFT_Dim3; - -typedef struct -{ - float *real; - float *imag; -} clFFT_SplitComplex; + } clFFT_Dimension; -typedef struct -{ - float real; - float imag; -}clFFT_Complex; + // XForm Data type + typedef enum + { + clFFT_SplitComplexFormat = 0, + clFFT_InterleavedComplexFormat = 1 + } clFFT_DataFormat; -typedef void* clFFT_Plan; + typedef struct + { + unsigned int x; + unsigned int y; + unsigned int z; + } clFFT_Dim3; -clFFT_Plan clFFT_CreatePlan( cl_context context, clFFT_Dim3 n, clFFT_Dimension dim, clFFT_DataFormat dataFormat, cl_int *error_code ); + typedef struct + { + float *real; + float *imag; + } clFFT_SplitComplex; -void clFFT_DestroyPlan( clFFT_Plan plan ); + typedef struct + { + float real; + float imag; + } clFFT_Complex; -cl_int clFFT_ExecuteInterleaved( cl_command_queue queue, clFFT_Plan plan, cl_int batchSize, clFFT_Direction dir, - cl_mem data_in, cl_mem data_out, - cl_int num_events, cl_event *event_list, cl_event *event ); + typedef void *clFFT_Plan; -cl_int clFFT_ExecutePlannar( cl_command_queue queue, clFFT_Plan plan, cl_int batchSize, clFFT_Direction dir, - cl_mem data_in_real, cl_mem data_in_imag, cl_mem data_out_real, cl_mem data_out_imag, - cl_int num_events, cl_event *event_list, cl_event *event ); + clFFT_Plan clFFT_CreatePlan(cl_context context, clFFT_Dim3 n, clFFT_Dimension dim, clFFT_DataFormat dataFormat, cl_int *error_code); -cl_int clFFT_1DTwistInterleaved(clFFT_Plan Plan, cl_command_queue queue, cl_mem array, - size_t numRows, size_t numCols, size_t startRow, size_t rowsToProcess, clFFT_Direction dir); - + void clFFT_DestroyPlan(clFFT_Plan plan); -cl_int clFFT_1DTwistPlannar(clFFT_Plan Plan, cl_command_queue queue, cl_mem array_real, cl_mem array_imag, - size_t numRows, size_t numCols, size_t startRow, size_t rowsToProcess, clFFT_Direction dir); - -void clFFT_DumpPlan( clFFT_Plan plan, FILE *file); + cl_int clFFT_ExecuteInterleaved(cl_command_queue queue, clFFT_Plan plan, cl_int batchSize, clFFT_Direction dir, + cl_mem data_in, cl_mem data_out, + cl_int num_events, cl_event *event_list, cl_event *event); + + cl_int clFFT_ExecutePlannar(cl_command_queue queue, clFFT_Plan plan, cl_int batchSize, clFFT_Direction dir, + cl_mem data_in_real, cl_mem data_in_imag, cl_mem data_out_real, cl_mem data_out_imag, + cl_int num_events, cl_event *event_list, cl_event *event); + + cl_int clFFT_1DTwistInterleaved(clFFT_Plan Plan, cl_command_queue queue, cl_mem array, + size_t numRows, size_t numCols, size_t startRow, size_t rowsToProcess, clFFT_Direction dir); + + + cl_int clFFT_1DTwistPlannar(clFFT_Plan Plan, cl_command_queue queue, cl_mem array_real, cl_mem array_imag, + size_t numRows, size_t numCols, size_t startRow, size_t rowsToProcess, clFFT_Direction dir); + + void clFFT_DumpPlan(clFFT_Plan plan, FILE *file); #ifdef __cplusplus } #endif -#endif +#endif diff --git a/src/algorithms/libs/opencl/fft_base_kernels.h b/src/algorithms/libs/opencl/fft_base_kernels.h new file mode 100644 index 000000000..42c7d5816 --- /dev/null +++ b/src/algorithms/libs/opencl/fft_base_kernels.h @@ -0,0 +1,273 @@ + +// +// File: fft_base_kernels.h +// +// Version: <1.0> +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") +// in consideration of your agreement to the following terms, and your use, +// installation, modification or redistribution of this Apple software +// constitutes acceptance of these terms. If you do not agree with these +// terms, please do not use, install, modify or redistribute this Apple +// software. +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non - exclusive +// license, under Apple's copyrights in this original Apple software ( the +// "Apple Software" ), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and / or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following text +// and disclaimers in all such redistributions of the Apple Software. Neither +// the name, trademarks, service marks or logos of Apple Inc. may be used to +// endorse or promote products derived from the Apple Software without specific +// prior written permission from Apple. Except as expressly stated in this +// notice, no other rights or licenses, express or implied, are granted by +// Apple herein, including but not limited to any patent rights that may be +// infringed by your derivative works or by other works in which the Apple +// Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION +// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION +// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER +// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR +// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef __CL_FFT_BASE_KERNELS_ +#define __CL_FFT_BASE_KERNELS_ + +#include + +using namespace std; + +static string baseKernels = string( + "#ifndef M_PI\n" + "#define M_PI 0x1.921fb54442d18p+1\n" + "#endif\n" + "#define complexMul(a,b) ((float2)(mad(-(a).y, (b).y, (a).x * (b).x), mad((a).y, (b).x, (a).x * (b).y)))\n" + "#define conj(a) ((float2)((a).x, -(a).y))\n" + "#define conjTransp(a) ((float2)(-(a).y, (a).x))\n" + "\n" + "#define fftKernel2(a,dir) \\\n" + "{ \\\n" + " float2 c = (a)[0]; \\\n" + " (a)[0] = c + (a)[1]; \\\n" + " (a)[1] = c - (a)[1]; \\\n" + "}\n" + "\n" + "#define fftKernel2S(d1,d2,dir) \\\n" + "{ \\\n" + " float2 c = (d1); \\\n" + " (d1) = c + (d2); \\\n" + " (d2) = c - (d2); \\\n" + "}\n" + "\n" + "#define fftKernel4(a,dir) \\\n" + "{ \\\n" + " fftKernel2S((a)[0], (a)[2], dir); \\\n" + " fftKernel2S((a)[1], (a)[3], dir); \\\n" + " fftKernel2S((a)[0], (a)[1], dir); \\\n" + " (a)[3] = (float2)(dir)*(conjTransp((a)[3])); \\\n" + " fftKernel2S((a)[2], (a)[3], dir); \\\n" + " float2 c = (a)[1]; \\\n" + " (a)[1] = (a)[2]; \\\n" + " (a)[2] = c; \\\n" + "}\n" + "\n" + "#define fftKernel4s(a0,a1,a2,a3,dir) \\\n" + "{ \\\n" + " fftKernel2S((a0), (a2), dir); \\\n" + " fftKernel2S((a1), (a3), dir); \\\n" + " fftKernel2S((a0), (a1), dir); \\\n" + " (a3) = (float2)(dir)*(conjTransp((a3))); \\\n" + " fftKernel2S((a2), (a3), dir); \\\n" + " float2 c = (a1); \\\n" + " (a1) = (a2); \\\n" + " (a2) = c; \\\n" + "}\n" + "\n" + "#define bitreverse8(a) \\\n" + "{ \\\n" + " float2 c; \\\n" + " c = (a)[1]; \\\n" + " (a)[1] = (a)[4]; \\\n" + " (a)[4] = c; \\\n" + " c = (a)[3]; \\\n" + " (a)[3] = (a)[6]; \\\n" + " (a)[6] = c; \\\n" + "}\n" + "\n" + "#define fftKernel8(a,dir) \\\n" + "{ \\\n" + " const float2 w1 = (float2)(0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f); \\\n" + " const float2 w3 = (float2)(-0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f); \\\n" + " float2 c; \\\n" + " fftKernel2S((a)[0], (a)[4], dir); \\\n" + " fftKernel2S((a)[1], (a)[5], dir); \\\n" + " fftKernel2S((a)[2], (a)[6], dir); \\\n" + " fftKernel2S((a)[3], (a)[7], dir); \\\n" + " (a)[5] = complexMul(w1, (a)[5]); \\\n" + " (a)[6] = (float2)(dir)*(conjTransp((a)[6])); \\\n" + " (a)[7] = complexMul(w3, (a)[7]); \\\n" + " fftKernel2S((a)[0], (a)[2], dir); \\\n" + " fftKernel2S((a)[1], (a)[3], dir); \\\n" + " fftKernel2S((a)[4], (a)[6], dir); \\\n" + " fftKernel2S((a)[5], (a)[7], dir); \\\n" + " (a)[3] = (float2)(dir)*(conjTransp((a)[3])); \\\n" + " (a)[7] = (float2)(dir)*(conjTransp((a)[7])); \\\n" + " fftKernel2S((a)[0], (a)[1], dir); \\\n" + " fftKernel2S((a)[2], (a)[3], dir); \\\n" + " fftKernel2S((a)[4], (a)[5], dir); \\\n" + " fftKernel2S((a)[6], (a)[7], dir); \\\n" + " bitreverse8((a)); \\\n" + "}\n" + "\n" + "#define bitreverse4x4(a) \\\n" + "{ \\\n" + " float2 c; \\\n" + " c = (a)[1]; (a)[1] = (a)[4]; (a)[4] = c; \\\n" + " c = (a)[2]; (a)[2] = (a)[8]; (a)[8] = c; \\\n" + " c = (a)[3]; (a)[3] = (a)[12]; (a)[12] = c; \\\n" + " c = (a)[6]; (a)[6] = (a)[9]; (a)[9] = c; \\\n" + " c = (a)[7]; (a)[7] = (a)[13]; (a)[13] = c; \\\n" + " c = (a)[11]; (a)[11] = (a)[14]; (a)[14] = c; \\\n" + "}\n" + "\n" + "#define fftKernel16(a,dir) \\\n" + "{ \\\n" + " const float w0 = 0x1.d906bcp-1f; \\\n" + " const float w1 = 0x1.87de2ap-2f; \\\n" + " const float w2 = 0x1.6a09e6p-1f; \\\n" + " fftKernel4s((a)[0], (a)[4], (a)[8], (a)[12], dir); \\\n" + " fftKernel4s((a)[1], (a)[5], (a)[9], (a)[13], dir); \\\n" + " fftKernel4s((a)[2], (a)[6], (a)[10], (a)[14], dir); \\\n" + " fftKernel4s((a)[3], (a)[7], (a)[11], (a)[15], dir); \\\n" + " (a)[5] = complexMul((a)[5], (float2)(w0, dir*w1)); \\\n" + " (a)[6] = complexMul((a)[6], (float2)(w2, dir*w2)); \\\n" + " (a)[7] = complexMul((a)[7], (float2)(w1, dir*w0)); \\\n" + " (a)[9] = complexMul((a)[9], (float2)(w2, dir*w2)); \\\n" + " (a)[10] = (float2)(dir)*(conjTransp((a)[10])); \\\n" + " (a)[11] = complexMul((a)[11], (float2)(-w2, dir*w2)); \\\n" + " (a)[13] = complexMul((a)[13], (float2)(w1, dir*w0)); \\\n" + " (a)[14] = complexMul((a)[14], (float2)(-w2, dir*w2)); \\\n" + " (a)[15] = complexMul((a)[15], (float2)(-w0, dir*-w1)); \\\n" + " fftKernel4((a), dir); \\\n" + " fftKernel4((a) + 4, dir); \\\n" + " fftKernel4((a) + 8, dir); \\\n" + " fftKernel4((a) + 12, dir); \\\n" + " bitreverse4x4((a)); \\\n" + "}\n" + "\n" + "#define bitreverse32(a) \\\n" + "{ \\\n" + " float2 c1, c2; \\\n" + " c1 = (a)[2]; (a)[2] = (a)[1]; c2 = (a)[4]; (a)[4] = c1; c1 = (a)[8]; (a)[8] = c2; c2 = (a)[16]; (a)[16] = c1; (a)[1] = c2; \\\n" + " c1 = (a)[6]; (a)[6] = (a)[3]; c2 = (a)[12]; (a)[12] = c1; c1 = (a)[24]; (a)[24] = c2; c2 = (a)[17]; (a)[17] = c1; (a)[3] = c2; \\\n" + " c1 = (a)[10]; (a)[10] = (a)[5]; c2 = (a)[20]; (a)[20] = c1; c1 = (a)[9]; (a)[9] = c2; c2 = (a)[18]; (a)[18] = c1; (a)[5] = c2; \\\n" + " c1 = (a)[14]; (a)[14] = (a)[7]; c2 = (a)[28]; (a)[28] = c1; c1 = (a)[25]; (a)[25] = c2; c2 = (a)[19]; (a)[19] = c1; (a)[7] = c2; \\\n" + " c1 = (a)[22]; (a)[22] = (a)[11]; c2 = (a)[13]; (a)[13] = c1; c1 = (a)[26]; (a)[26] = c2; c2 = (a)[21]; (a)[21] = c1; (a)[11] = c2; \\\n" + " c1 = (a)[30]; (a)[30] = (a)[15]; c2 = (a)[29]; (a)[29] = c1; c1 = (a)[27]; (a)[27] = c2; c2 = (a)[23]; (a)[23] = c1; (a)[15] = c2; \\\n" + "}\n" + "\n" + "#define fftKernel32(a,dir) \\\n" + "{ \\\n" + " fftKernel2S((a)[0], (a)[16], dir); \\\n" + " fftKernel2S((a)[1], (a)[17], dir); \\\n" + " fftKernel2S((a)[2], (a)[18], dir); \\\n" + " fftKernel2S((a)[3], (a)[19], dir); \\\n" + " fftKernel2S((a)[4], (a)[20], dir); \\\n" + " fftKernel2S((a)[5], (a)[21], dir); \\\n" + " fftKernel2S((a)[6], (a)[22], dir); \\\n" + " fftKernel2S((a)[7], (a)[23], dir); \\\n" + " fftKernel2S((a)[8], (a)[24], dir); \\\n" + " fftKernel2S((a)[9], (a)[25], dir); \\\n" + " fftKernel2S((a)[10], (a)[26], dir); \\\n" + " fftKernel2S((a)[11], (a)[27], dir); \\\n" + " fftKernel2S((a)[12], (a)[28], dir); \\\n" + " fftKernel2S((a)[13], (a)[29], dir); \\\n" + " fftKernel2S((a)[14], (a)[30], dir); \\\n" + " fftKernel2S((a)[15], (a)[31], dir); \\\n" + " (a)[17] = complexMul((a)[17], (float2)(0x1.f6297cp-1f, dir*0x1.8f8b84p-3f)); \\\n" + " (a)[18] = complexMul((a)[18], (float2)(0x1.d906bcp-1f, dir*0x1.87de2ap-2f)); \\\n" + " (a)[19] = complexMul((a)[19], (float2)(0x1.a9b662p-1f, dir*0x1.1c73b4p-1f)); \\\n" + " (a)[20] = complexMul((a)[20], (float2)(0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f)); \\\n" + " (a)[21] = complexMul((a)[21], (float2)(0x1.1c73b4p-1f, dir*0x1.a9b662p-1f)); \\\n" + " (a)[22] = complexMul((a)[22], (float2)(0x1.87de2ap-2f, dir*0x1.d906bcp-1f)); \\\n" + " (a)[23] = complexMul((a)[23], (float2)(0x1.8f8b84p-3f, dir*0x1.f6297cp-1f)); \\\n" + " (a)[24] = complexMul((a)[24], (float2)(0x0p+0f, dir*0x1p+0f)); \\\n" + " (a)[25] = complexMul((a)[25], (float2)(-0x1.8f8b84p-3f, dir*0x1.f6297cp-1f)); \\\n" + " (a)[26] = complexMul((a)[26], (float2)(-0x1.87de2ap-2f, dir*0x1.d906bcp-1f)); \\\n" + " (a)[27] = complexMul((a)[27], (float2)(-0x1.1c73b4p-1f, dir*0x1.a9b662p-1f)); \\\n" + " (a)[28] = complexMul((a)[28], (float2)(-0x1.6a09e6p-1f, dir*0x1.6a09e6p-1f)); \\\n" + " (a)[29] = complexMul((a)[29], (float2)(-0x1.a9b662p-1f, dir*0x1.1c73b4p-1f)); \\\n" + " (a)[30] = complexMul((a)[30], (float2)(-0x1.d906bcp-1f, dir*0x1.87de2ap-2f)); \\\n" + " (a)[31] = complexMul((a)[31], (float2)(-0x1.f6297cp-1f, dir*0x1.8f8b84p-3f)); \\\n" + " fftKernel16((a), dir); \\\n" + " fftKernel16((a) + 16, dir); \\\n" + " bitreverse32((a)); \\\n" + "}\n\n"); + +static string twistKernelInterleaved = string( + "__kernel void \\\n" + "clFFT_1DTwistInterleaved(__global float2 *in, unsigned int startRow, unsigned int numCols, unsigned int N, unsigned int numRowsToProcess, int dir) \\\n" + "{ \\\n" + " float2 a, w; \\\n" + " float ang; \\\n" + " unsigned int j; \\\n" + " unsigned int i = get_global_id(0); \\\n" + " unsigned int startIndex = i; \\\n" + " \\\n" + " if(i < numCols) \\\n" + " { \\\n" + " for(j = 0; j < numRowsToProcess; j++) \\\n" + " { \\\n" + " a = in[startIndex]; \\\n" + " ang = 2.0f * M_PI * dir * i * (startRow + j) / N; \\\n" + " w = (float2)(native_cos(ang), native_sin(ang)); \\\n" + " a = complexMul(a, w); \\\n" + " in[startIndex] = a; \\\n" + " startIndex += numCols; \\\n" + " } \\\n" + " } \\\n" + "} \\\n"); + +static string twistKernelPlannar = string( + "__kernel void \\\n" + "clFFT_1DTwistSplit(__global float *in_real, __global float *in_imag , unsigned int startRow, unsigned int numCols, unsigned int N, unsigned int numRowsToProcess, int dir) \\\n" + "{ \\\n" + " float2 a, w; \\\n" + " float ang; \\\n" + " unsigned int j; \\\n" + " unsigned int i = get_global_id(0); \\\n" + " unsigned int startIndex = i; \\\n" + " \\\n" + " if(i < numCols) \\\n" + " { \\\n" + " for(j = 0; j < numRowsToProcess; j++) \\\n" + " { \\\n" + " a = (float2)(in_real[startIndex], in_imag[startIndex]); \\\n" + " ang = 2.0f * M_PI * dir * i * (startRow + j) / N; \\\n" + " w = (float2)(native_cos(ang), native_sin(ang)); \\\n" + " a = complexMul(a, w); \\\n" + " in_real[startIndex] = a.x; \\\n" + " in_imag[startIndex] = a.y; \\\n" + " startIndex += numCols; \\\n" + " } \\\n" + " } \\\n" + "} \\\n"); + + +#endif diff --git a/src/algorithms/libs/opencl/fft_execute.cc b/src/algorithms/libs/opencl/fft_execute.cc new file mode 100644 index 000000000..23b2d1c83 --- /dev/null +++ b/src/algorithms/libs/opencl/fft_execute.cc @@ -0,0 +1,403 @@ + +// +// File: fft_execute.cpp +// +// Version: <1.0> +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") +// in consideration of your agreement to the following terms, and your use, +// installation, modification or redistribution of this Apple software +// constitutes acceptance of these terms. If you do not agree with these +// terms, please do not use, install, modify or redistribute this Apple +// software.¬ +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non - exclusive +// license, under Apple's copyrights in this original Apple software ( the +// "Apple Software" ), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and / or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following text +// and disclaimers in all such redistributions of the Apple Software. Neither +// the name, trademarks, service marks or logos of Apple Inc. may be used to +// endorse or promote products derived from the Apple Software without specific +// prior written permission from Apple. Except as expressly stated in this +// notice, no other rights or licenses, express or implied, are granted by +// Apple herein, including but not limited to any patent rights that may be +// infringed by your derivative works or by other works in which the Apple +// Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION +// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION +// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER +// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR +// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include "clFFT.h" +#include "fft_internal.h" +#include +#include +#include + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static cl_int +allocateTemporaryBufferInterleaved(cl_fft_plan *plan, cl_uint batchSize) +{ + cl_int err = CL_SUCCESS; + if (plan->temp_buffer_needed && plan->last_batch_size != batchSize) + { + plan->last_batch_size = batchSize; + size_t tmpLength = plan->n.x * plan->n.y * plan->n.z * batchSize * 2 * sizeof(cl_float); + + if (plan->tempmemobj) + clReleaseMemObject(plan->tempmemobj); + + plan->tempmemobj = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, nullptr, &err); + } + return err; +} + +static cl_int +allocateTemporaryBufferPlannar(cl_fft_plan *plan, cl_uint batchSize) +{ + cl_int err = CL_SUCCESS; + cl_int terr; + if (plan->temp_buffer_needed && plan->last_batch_size != batchSize) + { + plan->last_batch_size = batchSize; + size_t tmpLength = plan->n.x * plan->n.y * plan->n.z * batchSize * sizeof(cl_float); + + if (plan->tempmemobj_real) + clReleaseMemObject(plan->tempmemobj_real); + + if (plan->tempmemobj_imag) + clReleaseMemObject(plan->tempmemobj_imag); + + plan->tempmemobj_real = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, nullptr, &err); + plan->tempmemobj_imag = clCreateBuffer(plan->context, CL_MEM_READ_WRITE, tmpLength, nullptr, &terr); + err |= terr; + } + return err; +} + +void getKernelWorkDimensions(cl_fft_plan *plan, cl_fft_kernel_info *kernelInfo, cl_int *batchSize, size_t *gWorkItems, size_t *lWorkItems) +{ + *lWorkItems = kernelInfo->num_workitems_per_workgroup; + int numWorkGroups = kernelInfo->num_workgroups; + int numXFormsPerWG = kernelInfo->num_xforms_per_workgroup; + + switch (kernelInfo->dir) + { + case cl_fft_kernel_x: + *batchSize *= (plan->n.y * plan->n.z); + numWorkGroups = (*batchSize % numXFormsPerWG) ? (*batchSize / numXFormsPerWG + 1) : (*batchSize / numXFormsPerWG); + numWorkGroups *= kernelInfo->num_workgroups; + break; + case cl_fft_kernel_y: + *batchSize *= plan->n.z; + numWorkGroups *= *batchSize; + break; + case cl_fft_kernel_z: + numWorkGroups *= *batchSize; + break; + } + + *gWorkItems = numWorkGroups * *lWorkItems; +} + +cl_int +clFFT_ExecuteInterleaved(cl_command_queue queue, clFFT_Plan Plan, cl_int batchSize, clFFT_Direction dir, + cl_mem data_in, cl_mem data_out, + cl_int num_events, cl_event *event_list, cl_event *event) +{ + int s; + auto *plan = (cl_fft_plan *)Plan; + if (plan->format != clFFT_InterleavedComplexFormat) + return CL_INVALID_VALUE; + + cl_int err; + size_t gWorkItems, lWorkItems; + int inPlaceDone; + + cl_int isInPlace = data_in == data_out ? 1 : 0; + + if ((err = allocateTemporaryBufferInterleaved(plan, batchSize)) != CL_SUCCESS) + return err; + + cl_mem memObj[3]; + memObj[0] = data_in; + memObj[1] = data_out; + memObj[2] = plan->tempmemobj; + cl_fft_kernel_info *kernelInfo = plan->kernel_info; + int numKernels = plan->num_kernels; + + int numKernelsOdd = numKernels & 1; + int currRead = 0; + int currWrite = 1; + + // at least one external dram shuffle (transpose) required + if (plan->temp_buffer_needed) + { + // in-place transform + if (isInPlace) + { + inPlaceDone = 0; + currRead = 1; + currWrite = 2; + } + else + { + currWrite = (numKernels & 1) ? 1 : 2; + } + + while (kernelInfo) + { + if (isInPlace && numKernelsOdd && !inPlaceDone && kernelInfo->in_place_possible) + { + currWrite = currRead; + inPlaceDone = 1; + } + + s = batchSize; + getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); + err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_int), &dir); + err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_int), &s); + + err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, nullptr, &gWorkItems, &lWorkItems, 0, nullptr, nullptr); + if (err) + return err; + + currRead = (currWrite == 1) ? 1 : 2; + currWrite = (currWrite == 1) ? 2 : 1; + + kernelInfo = kernelInfo->next; + } + } + // no dram shuffle (transpose required) transform + // all kernels can execute in-place. + else + { + while (kernelInfo) + { + s = batchSize; + getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); + err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_int), &dir); + err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_int), &s); + + err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, nullptr, &gWorkItems, &lWorkItems, 0, nullptr, nullptr); + if (err) + return err; + + currRead = 1; + currWrite = 1; + + kernelInfo = kernelInfo->next; + } + } + + return err; +} + +cl_int +clFFT_ExecutePlannar(cl_command_queue queue, clFFT_Plan Plan, cl_int batchSize, clFFT_Direction dir, + cl_mem data_in_real, cl_mem data_in_imag, cl_mem data_out_real, cl_mem data_out_imag, + cl_int num_events, cl_event *event_list, cl_event *event) +{ + int s; + auto *plan = (cl_fft_plan *)Plan; + + if (plan->format != clFFT_SplitComplexFormat) + return CL_INVALID_VALUE; + + cl_int err; + size_t gWorkItems, lWorkItems; + int inPlaceDone; + + cl_int isInPlace = ((data_in_real == data_out_real) && (data_in_imag == data_out_imag)) ? 1 : 0; + + if ((err = allocateTemporaryBufferPlannar(plan, batchSize)) != CL_SUCCESS) + return err; + + cl_mem memObj_real[3]; + cl_mem memObj_imag[3]; + memObj_real[0] = data_in_real; + memObj_real[1] = data_out_real; + memObj_real[2] = plan->tempmemobj_real; + memObj_imag[0] = data_in_imag; + memObj_imag[1] = data_out_imag; + memObj_imag[2] = plan->tempmemobj_imag; + + cl_fft_kernel_info *kernelInfo = plan->kernel_info; + int numKernels = plan->num_kernels; + + int numKernelsOdd = numKernels & 1; + int currRead = 0; + int currWrite = 1; + + // at least one external dram shuffle (transpose) required + if (plan->temp_buffer_needed) + { + // in-place transform + if (isInPlace) + { + inPlaceDone = 0; + currRead = 1; + currWrite = 2; + } + else + { + currWrite = (numKernels & 1) ? 1 : 2; + } + + while (kernelInfo) + { + if (isInPlace && numKernelsOdd && !inPlaceDone && kernelInfo->in_place_possible) + { + currWrite = currRead; + inPlaceDone = 1; + } + + s = batchSize; + getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); + err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj_real[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj_imag[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_mem), &memObj_real[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_mem), &memObj_imag[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 4, sizeof(cl_int), &dir); + err |= clSetKernelArg(kernelInfo->kernel, 5, sizeof(cl_int), &s); + + err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, nullptr, &gWorkItems, &lWorkItems, 0, nullptr, nullptr); + if (err) + return err; + + currRead = (currWrite == 1) ? 1 : 2; + currWrite = (currWrite == 1) ? 2 : 1; + + kernelInfo = kernelInfo->next; + } + } + // no dram shuffle (transpose required) transform + else + { + while (kernelInfo) + { + s = batchSize; + getKernelWorkDimensions(plan, kernelInfo, &s, &gWorkItems, &lWorkItems); + err |= clSetKernelArg(kernelInfo->kernel, 0, sizeof(cl_mem), &memObj_real[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 1, sizeof(cl_mem), &memObj_imag[currRead]); + err |= clSetKernelArg(kernelInfo->kernel, 2, sizeof(cl_mem), &memObj_real[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 3, sizeof(cl_mem), &memObj_imag[currWrite]); + err |= clSetKernelArg(kernelInfo->kernel, 4, sizeof(cl_int), &dir); + err |= clSetKernelArg(kernelInfo->kernel, 5, sizeof(cl_int), &s); + + err |= clEnqueueNDRangeKernel(queue, kernelInfo->kernel, 1, nullptr, &gWorkItems, &lWorkItems, 0, nullptr, nullptr); + if (err) + return err; + + currRead = 1; + currWrite = 1; + + kernelInfo = kernelInfo->next; + } + } + + return err; +} + +cl_int +clFFT_1DTwistInterleaved(clFFT_Plan Plan, cl_command_queue queue, cl_mem array, + unsigned numRows, unsigned numCols, unsigned startRow, unsigned rowsToProcess, clFFT_Direction dir) +{ + auto *plan = (cl_fft_plan *)Plan; + + unsigned int N = numRows * numCols; + unsigned int nCols = numCols; + unsigned int sRow = startRow; + unsigned int rToProcess = rowsToProcess; + int d = dir; + int err = 0; + + cl_device_id device_id; + err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, sizeof(cl_device_id), &device_id, nullptr); + if (err) + return err; + + size_t gSize; + err = clGetKernelWorkGroupInfo(plan->twist_kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &gSize, nullptr); + if (err) + return err; + + gSize = min(128, gSize); + size_t numGlobalThreads[1] = {max(numCols / gSize, 1) * gSize}; + size_t numLocalThreads[1] = {gSize}; + + err |= clSetKernelArg(plan->twist_kernel, 0, sizeof(cl_mem), &array); + err |= clSetKernelArg(plan->twist_kernel, 1, sizeof(unsigned int), &sRow); + err |= clSetKernelArg(plan->twist_kernel, 2, sizeof(unsigned int), &nCols); + err |= clSetKernelArg(plan->twist_kernel, 3, sizeof(unsigned int), &N); + err |= clSetKernelArg(plan->twist_kernel, 4, sizeof(unsigned int), &rToProcess); + err |= clSetKernelArg(plan->twist_kernel, 5, sizeof(int), &d); + + err |= clEnqueueNDRangeKernel(queue, plan->twist_kernel, 1, nullptr, numGlobalThreads, numLocalThreads, 0, nullptr, nullptr); + + return err; +} + +cl_int +clFFT_1DTwistPlannar(clFFT_Plan Plan, cl_command_queue queue, cl_mem array_real, cl_mem array_imag, + unsigned numRows, unsigned numCols, unsigned startRow, unsigned rowsToProcess, clFFT_Direction dir) +{ + auto *plan = (cl_fft_plan *)Plan; + + unsigned int N = numRows * numCols; + unsigned int nCols = numCols; + unsigned int sRow = startRow; + unsigned int rToProcess = rowsToProcess; + int d = dir; + int err = 0; + + cl_device_id device_id; + err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, sizeof(cl_device_id), &device_id, nullptr); + if (err) + return err; + + size_t gSize; + err = clGetKernelWorkGroupInfo(plan->twist_kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &gSize, nullptr); + if (err) + return err; + + gSize = min(128, gSize); + size_t numGlobalThreads[1] = {max(numCols / gSize, 1) * gSize}; + size_t numLocalThreads[1] = {gSize}; + + err |= clSetKernelArg(plan->twist_kernel, 0, sizeof(cl_mem), &array_real); + err |= clSetKernelArg(plan->twist_kernel, 1, sizeof(cl_mem), &array_imag); + err |= clSetKernelArg(plan->twist_kernel, 2, sizeof(unsigned int), &sRow); + err |= clSetKernelArg(plan->twist_kernel, 3, sizeof(unsigned int), &nCols); + err |= clSetKernelArg(plan->twist_kernel, 4, sizeof(unsigned int), &N); + err |= clSetKernelArg(plan->twist_kernel, 5, sizeof(unsigned int), &rToProcess); + err |= clSetKernelArg(plan->twist_kernel, 6, sizeof(int), &d); + + err |= clEnqueueNDRangeKernel(queue, plan->twist_kernel, 1, nullptr, numGlobalThreads, numLocalThreads, 0, nullptr, nullptr); + + return err; +} diff --git a/src/algorithms/libs/opencl/fft_internal.h b/src/algorithms/libs/opencl/fft_internal.h new file mode 100644 index 000000000..96a41c6de --- /dev/null +++ b/src/algorithms/libs/opencl/fft_internal.h @@ -0,0 +1,163 @@ + +// +// File: fft_internal.h +// +// Version: <1.0> +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") +// in consideration of your agreement to the following terms, and your use, +// installation, modification or redistribution of this Apple software +// constitutes acceptance of these terms. If you do not agree with these +// terms, please do not use, install, modify or redistribute this Apple +// software. +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non - exclusive +// license, under Apple's copyrights in this original Apple software ( the +// "Apple Software" ), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and / or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following text +// and disclaimers in all such redistributions of the Apple Software. Neither +// the name, trademarks, service marks or logos of Apple Inc. may be used to +// endorse or promote products derived from the Apple Software without specific +// prior written permission from Apple. Except as expressly stated in this +// notice, no other rights or licenses, express or implied, are granted by +// Apple herein, including but not limited to any patent rights that may be +// infringed by your derivative works or by other works in which the Apple +// Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION +// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION +// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER +// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR +// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef __CLFFT_INTERNAL_H +#define __CLFFT_INTERNAL_H + +#include "clFFT.h" +#include +#include +#include + +using namespace std; + +typedef enum kernel_dir_t +{ + cl_fft_kernel_x, + cl_fft_kernel_y, + cl_fft_kernel_z +} cl_fft_kernel_dir; + +typedef struct kernel_info_t +{ + cl_kernel kernel; + char *kernel_name; + unsigned lmem_size; + unsigned num_workgroups; + unsigned num_xforms_per_workgroup; + unsigned num_workitems_per_workgroup; + cl_fft_kernel_dir dir; + int in_place_possible; + kernel_info_t *next; +} cl_fft_kernel_info; + +typedef struct +{ + // context in which fft resources are created and kernels are executed + cl_context context; + + // size of signal + clFFT_Dim3 n; + + // dimension of transform ... must be either 1D, 2D or 3D + clFFT_Dimension dim; + + // data format ... must be either interleaved or plannar + clFFT_DataFormat format; + + // string containing kernel source. Generated at runtime based on + // n, dim, format and other parameters + string *kernel_string; + + // CL program containing source and kernel this particular + // n, dim, data format + cl_program program; + + // linked list of kernels which needs to be executed for this fft + cl_fft_kernel_info *kernel_info; + + // number of kernels + int num_kernels; + + // twist kernel for virtualizing fft of very large sizes that do not + // fit in GPU global memory + cl_kernel twist_kernel; + + // flag indicating if temporary intermediate buffer is needed or not. + // this depends on fft kernels being executed and if transform is + // in-place or out-of-place. e.g. Local memory fft (say 1D 1024 ... + // one that does not require global transpose do not need temporary buffer) + // 2D 1024x1024 out-of-place fft however do require intermediate buffer. + // If temp buffer is needed, its allocation is lazy i.e. its not allocated + // until its needed + cl_int temp_buffer_needed; + + // Batch size is runtime parameter and size of temporary buffer (if needed) + // depends on batch size. Allocation of temporary buffer is lazy i.e. its + // only created when needed. Once its created at first call of clFFT_Executexxx + // it is not allocated next time if next time clFFT_Executexxx is called with + // batch size different than the first call. last_batch_size caches the last + // batch size with which this plan is used so that we dont keep allocating/deallocating + // temp buffer if same batch size is used again and again. + unsigned last_batch_size; + + // temporary buffer for interleaved plan + cl_mem tempmemobj; + + // temporary buffer for planner plan. Only one of tempmemobj or + // (tempmemobj_real, tempmemobj_imag) pair is valid (allocated) depending + // data format of plan (plannar or interleaved) + cl_mem tempmemobj_real, tempmemobj_imag; + + // Maximum size of signal for which local memory transposed based + // fft is sufficient i.e. no global mem transpose (communication) + // is needed + unsigned max_localmem_fft_size; + + // Maximum work items per work group allowed. This, along with max_radix below controls + // maximum local memory being used by fft kernels of this plan. Set to 256 by default + unsigned max_work_item_per_workgroup; + + // Maximum base radix for local memory fft ... this controls the maximum register + // space used by work items. Currently defaults to 16 + unsigned max_radix; + + // Device depended parameter that tells how many work-items need to be read consecutive + // values to make sure global memory access by work-items of a work-group result in + // coalesced memory access to utilize full bandwidth e.g. on NVidia tesla, this is 16 + unsigned min_mem_coalesce_width; + + // Number of local memory banks. This is used to geneate kernel with local memory + // transposes with appropriate padding to avoid bank conflicts to local memory + // e.g. on NVidia it is 16. + unsigned num_local_mem_banks; +} cl_fft_plan; + +void FFT1D(cl_fft_plan *plan, cl_fft_kernel_dir dir); + +#endif diff --git a/src/algorithms/libs/opencl/fft_kernelstring.cc b/src/algorithms/libs/opencl/fft_kernelstring.cc new file mode 100644 index 000000000..33b3109e8 --- /dev/null +++ b/src/algorithms/libs/opencl/fft_kernelstring.cc @@ -0,0 +1,1281 @@ + +// +// File: fft_kernelstring.cpp +// +// Version: <1.0> +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") +// in consideration of your agreement to the following terms, and your use, +// installation, modification or redistribution of this Apple software +// constitutes acceptance of these terms. If you do not agree with these +// terms, please do not use, install, modify or redistribute this Apple +// software. +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non - exclusive +// license, under Apple's copyrights in this original Apple software ( the +// "Apple Software" ), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and / or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following text +// and disclaimers in all such redistributions of the Apple Software. Neither +// the name, trademarks, service marks or logos of Apple Inc. may be used to +// endorse or promote products derived from the Apple Software without specific +// prior written permission from Apple. Except as expressly stated in this +// notice, no other rights or licenses, express or implied, are granted by +// Apple herein, including but not limited to any patent rights that may be +// infringed by your derivative works or by other works in which the Apple +// Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION +// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION +// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER +// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR +// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include "clFFT.h" +#include "fft_internal.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define max(A, B) ((A) > (B) ? (A) : (B)) +#define min(A, B) ((A) < (B) ? (A) : (B)) + +static string +num2str(int num) +{ + char temp[200]; + sprintf(temp, "%d", num); + return string(temp); +} + +// For any n, this function decomposes n into factors for loacal memory tranpose +// based fft. Factors (radices) are sorted such that the first one (radixArray[0]) +// is the largest. This base radix determines the number of registers used by each +// work item and product of remaining radices determine the size of work group needed. +// To make things concrete with and example, suppose n = 1024. It is decomposed into +// 1024 = 16 x 16 x 4. Hence kernel uses float2 a[16], for local in-register fft and +// needs 16 x 4 = 64 work items per work group. So kernel first performance 64 length +// 16 ffts (64 work items working in parallel) following by transpose using local +// memory followed by again 64 length 16 ffts followed by transpose using local memory +// followed by 256 length 4 ffts. For the last step since with size of work group is +// 64 and each work item can array for 16 values, 64 work items can compute 256 length +// 4 ffts by each work item computing 4 length 4 ffts. +// Similarly for n = 2048 = 8 x 8 x 8 x 4, each work group has 8 x 8 x 4 = 256 work +// iterms which each computes 256 (in-parallel) length 8 ffts in-register, followed +// by transpose using local memory, followed by 256 length 8 in-register ffts, followed +// by transpose using local memory, followed by 256 length 8 in-register ffts, followed +// by transpose using local memory, followed by 512 length 4 in-register ffts. Again, +// for the last step, each work item computes two length 4 in-register ffts and thus +// 256 work items are needed to compute all 512 ffts. +// For n = 32 = 8 x 4, 4 work items first compute 4 in-register +// lenth 8 ffts, followed by transpose using local memory followed by 8 in-register +// length 4 ffts, where each work item computes two length 4 ffts thus 4 work items +// can compute 8 length 4 ffts. However if work group size of say 64 is choosen, +// each work group can compute 64/ 4 = 16 size 32 ffts (batched transform). +// Users can play with these parameters to figure what gives best performance on +// their particular device i.e. some device have less register space thus using +// smaller base radix can avoid spilling ... some has small local memory thus +// using smaller work group size may be required etc + +static void +getRadixArray(unsigned int n, unsigned int *radixArray, unsigned int *numRadices, unsigned int maxRadix) +{ + if (maxRadix > 1) + { + maxRadix = min(n, maxRadix); + unsigned int cnt = 0; + while (n > maxRadix) + { + radixArray[cnt++] = maxRadix; + n /= maxRadix; + } + radixArray[cnt++] = n; + *numRadices = cnt; + return; + } + + switch (n) + { + case 2: + *numRadices = 1; + radixArray[0] = 2; + break; + + case 4: + *numRadices = 1; + radixArray[0] = 4; + break; + + case 8: + *numRadices = 1; + radixArray[0] = 8; + break; + + case 16: + *numRadices = 2; + radixArray[0] = 8; + radixArray[1] = 2; + break; + + case 32: + *numRadices = 2; + radixArray[0] = 8; + radixArray[1] = 4; + break; + + case 64: + *numRadices = 2; + radixArray[0] = 8; + radixArray[1] = 8; + break; + + case 128: + *numRadices = 3; + radixArray[0] = 8; + radixArray[1] = 4; + radixArray[2] = 4; + break; + + case 256: + *numRadices = 4; + radixArray[0] = 4; + radixArray[1] = 4; + radixArray[2] = 4; + radixArray[3] = 4; + break; + + case 512: + *numRadices = 3; + radixArray[0] = 8; + radixArray[1] = 8; + radixArray[2] = 8; + break; + + case 1024: + *numRadices = 3; + radixArray[0] = 16; + radixArray[1] = 16; + radixArray[2] = 4; + break; + case 2048: + *numRadices = 4; + radixArray[0] = 8; + radixArray[1] = 8; + radixArray[2] = 8; + radixArray[3] = 4; + break; + default: + *numRadices = 0; + return; + } +} + +static void +insertHeader(string &kernelString, string &kernelName, clFFT_DataFormat dataFormat) +{ + if (dataFormat == clFFT_SplitComplexFormat) + kernelString += string("__kernel void ") + kernelName + string("(__global float *in_real, __global float *in_imag, __global float *out_real, __global float *out_imag, int dir, int S)\n"); + else + kernelString += string("__kernel void ") + kernelName + string("(__global float2 *in, __global float2 *out, int dir, int S)\n"); +} + +static void +insertVariables(string &kStream, int maxRadix) +{ + kStream += string(" int i, j, r, indexIn, indexOut, index, tid, bNum, xNum, k, l;\n"); + kStream += string(" int s, ii, jj, offset;\n"); + kStream += string(" float2 w;\n"); + kStream += string(" float ang, angf, ang1;\n"); + kStream += string(" __local float *lMemStore, *lMemLoad;\n"); + kStream += string(" float2 a[") + num2str(maxRadix) + string("];\n"); + kStream += string(" int lId = get_local_id( 0 );\n"); + kStream += string(" int groupId = get_group_id( 0 );\n"); +} + +static void +formattedLoad(string &kernelString, int aIndex, int gIndex, clFFT_DataFormat dataFormat) +{ + if (dataFormat == clFFT_InterleavedComplexFormat) + kernelString += string(" a[") + num2str(aIndex) + string("] = in[") + num2str(gIndex) + string("];\n"); + else + { + kernelString += string(" a[") + num2str(aIndex) + string("].x = in_real[") + num2str(gIndex) + string("];\n"); + kernelString += string(" a[") + num2str(aIndex) + string("].y = in_imag[") + num2str(gIndex) + string("];\n"); + } +} + +static void +formattedStore(string &kernelString, int aIndex, int gIndex, clFFT_DataFormat dataFormat) +{ + if (dataFormat == clFFT_InterleavedComplexFormat) + kernelString += string(" out[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("];\n"); + else + { + kernelString += string(" out_real[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("].x;\n"); + kernelString += string(" out_imag[") + num2str(gIndex) + string("] = a[") + num2str(aIndex) + string("].y;\n"); + } +} + +static int +insertGlobalLoadsAndTranspose(string &kernelString, int N, int numWorkItemsPerXForm, int numXFormsPerWG, int R0, int mem_coalesce_width, clFFT_DataFormat dataFormat) +{ + int log2NumWorkItemsPerXForm = (int)log2(numWorkItemsPerXForm); + int groupSize = numWorkItemsPerXForm * numXFormsPerWG; + int i, j; + int lMemSize = 0; + + if (numXFormsPerWG > 1) + kernelString += string(" s = S & ") + num2str(numXFormsPerWG - 1) + string(";\n"); + + if (numWorkItemsPerXForm >= mem_coalesce_width) + { + if (numXFormsPerWG > 1) + { + kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); + kernelString += string(" if( !s || (groupId < get_num_groups(0)-1) || (jj < s) ) {\n"); + kernelString += string(" offset = mad24( mad24(groupId, ") + num2str(numXFormsPerWG) + string(", jj), ") + num2str(N) + string(", ii );\n"); + if (dataFormat == clFFT_InterleavedComplexFormat) + { + kernelString += string(" in += offset;\n"); + kernelString += string(" out += offset;\n"); + } + else + { + kernelString += string(" in_real += offset;\n"); + kernelString += string(" in_imag += offset;\n"); + kernelString += string(" out_real += offset;\n"); + kernelString += string(" out_imag += offset;\n"); + } + for (i = 0; i < R0; i++) + formattedLoad(kernelString, i, i * numWorkItemsPerXForm, dataFormat); + kernelString += string(" }\n"); + } + else + { + kernelString += string(" ii = lId;\n"); + kernelString += string(" jj = 0;\n"); + kernelString += string(" offset = mad24(groupId, ") + num2str(N) + string(", ii);\n"); + if (dataFormat == clFFT_InterleavedComplexFormat) + { + kernelString += string(" in += offset;\n"); + kernelString += string(" out += offset;\n"); + } + else + { + kernelString += string(" in_real += offset;\n"); + kernelString += string(" in_imag += offset;\n"); + kernelString += string(" out_real += offset;\n"); + kernelString += string(" out_imag += offset;\n"); + } + for (i = 0; i < R0; i++) + formattedLoad(kernelString, i, i * numWorkItemsPerXForm, dataFormat); + } + } + else if (N >= mem_coalesce_width) + { + int numInnerIter = N / mem_coalesce_width; + int numOuterIter = numXFormsPerWG / (groupSize / mem_coalesce_width); + + kernelString += string(" ii = lId & ") + num2str(mem_coalesce_width - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str((int)log2(mem_coalesce_width)) + string(";\n"); + kernelString += string(" lMemStore = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + kernelString += string(" offset = mad24( groupId, ") + num2str(numXFormsPerWG) + string(", jj);\n"); + kernelString += string(" offset = mad24( offset, ") + num2str(N) + string(", ii );\n"); + if (dataFormat == clFFT_InterleavedComplexFormat) + { + kernelString += string(" in += offset;\n"); + kernelString += string(" out += offset;\n"); + } + else + { + kernelString += string(" in_real += offset;\n"); + kernelString += string(" in_imag += offset;\n"); + kernelString += string(" out_real += offset;\n"); + kernelString += string(" out_imag += offset;\n"); + } + + kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); + for (i = 0; i < numOuterIter; i++) + { + kernelString += string(" if( jj < s ) {\n"); + for (j = 0; j < numInnerIter; j++) + formattedLoad(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * N, dataFormat); + kernelString += string(" }\n"); + if (i != numOuterIter - 1) + kernelString += string(" jj += ") + num2str(groupSize / mem_coalesce_width) + string(";\n"); + } + kernelString += string("}\n "); + kernelString += string("else {\n"); + for (i = 0; i < numOuterIter; i++) + { + for (j = 0; j < numInnerIter; j++) + formattedLoad(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * N, dataFormat); + } + kernelString += string("}\n"); + + kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); + kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii);\n"); + + for (i = 0; i < numOuterIter; i++) + { + for (j = 0; j < numInnerIter; j++) + { + kernelString += string(" lMemStore[") + num2str(j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * (N + numWorkItemsPerXForm)) + string("] = a[") + + num2str(i * numInnerIter + j) + string("].x;\n"); + } + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < R0; i++) + kernelString += string(" a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < numOuterIter; i++) + { + for (j = 0; j < numInnerIter; j++) + { + kernelString += string(" lMemStore[") + num2str(j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * (N + numWorkItemsPerXForm)) + string("] = a[") + + num2str(i * numInnerIter + j) + string("].y;\n"); + } + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < R0; i++) + kernelString += string(" a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; + } + else + { + kernelString += string(" offset = mad24( groupId, ") + num2str(N * numXFormsPerWG) + string(", lId );\n"); + if (dataFormat == clFFT_InterleavedComplexFormat) + { + kernelString += string(" in += offset;\n"); + kernelString += string(" out += offset;\n"); + } + else + { + kernelString += string(" in_real += offset;\n"); + kernelString += string(" in_imag += offset;\n"); + kernelString += string(" out_real += offset;\n"); + kernelString += string(" out_imag += offset;\n"); + } + + kernelString += string(" ii = lId & ") + num2str(N - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str((int)log2(N)) + string(";\n"); + kernelString += string(" lMemStore = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + + kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); + for (i = 0; i < R0; i++) + { + kernelString += string(" if(jj < s )\n"); + formattedLoad(kernelString, i, i * groupSize, dataFormat); + if (i != R0 - 1) + kernelString += string(" jj += ") + num2str(groupSize / N) + string(";\n"); + } + kernelString += string("}\n"); + kernelString += string("else {\n"); + for (i = 0; i < R0; i++) + { + formattedLoad(kernelString, i, i * groupSize, dataFormat); + } + kernelString += string("}\n"); + + if (numWorkItemsPerXForm > 1) + { + kernelString += string(" ii = lId & ") + num2str(numWorkItemsPerXForm - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str(log2NumWorkItemsPerXForm) + string(";\n"); + kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + } + else + { + kernelString += string(" ii = 0;\n"); + kernelString += string(" jj = lId;\n"); + kernelString += string(" lMemLoad = sMem + mul24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(");\n"); + } + + + for (i = 0; i < R0; i++) + kernelString += string(" lMemStore[") + num2str(i * (groupSize / N) * (N + numWorkItemsPerXForm)) + string("] = a[") + num2str(i) + string("].x;\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < R0; i++) + kernelString += string(" a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < R0; i++) + kernelString += string(" lMemStore[") + num2str(i * (groupSize / N) * (N + numWorkItemsPerXForm)) + string("] = a[") + num2str(i) + string("].y;\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < R0; i++) + kernelString += string(" a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; + } + + return lMemSize; +} + +static int +insertGlobalStoresAndTranspose(string &kernelString, int N, int maxRadix, int Nr, int numWorkItemsPerXForm, int numXFormsPerWG, int mem_coalesce_width, clFFT_DataFormat dataFormat) +{ + int groupSize = numWorkItemsPerXForm * numXFormsPerWG; + int i, j, k, ind; + int lMemSize = 0; + int numIter = maxRadix / Nr; + string indent = string(""); + + if (numWorkItemsPerXForm >= mem_coalesce_width) + { + if (numXFormsPerWG > 1) + { + kernelString += string(" if( !s || (groupId < get_num_groups(0)-1) || (jj < s) ) {\n"); + indent = string(" "); + } + for (i = 0; i < maxRadix; i++) + { + j = i % numIter; + k = i / numIter; + ind = j * Nr + k; + formattedStore(kernelString, ind, i * numWorkItemsPerXForm, dataFormat); + } + if (numXFormsPerWG > 1) + kernelString += string(" }\n"); + } + else if (N >= mem_coalesce_width) + { + int numInnerIter = N / mem_coalesce_width; + int numOuterIter = numXFormsPerWG / (groupSize / mem_coalesce_width); + + kernelString += string(" lMemLoad = sMem + mad24( jj, ") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + kernelString += string(" ii = lId & ") + num2str(mem_coalesce_width - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str((int)log2(mem_coalesce_width)) + string(";\n"); + kernelString += string(" lMemStore = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + + for (i = 0; i < maxRadix; i++) + { + j = i % numIter; + k = i / numIter; + ind = j * Nr + k; + kernelString += string(" lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].x;\n"); + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < numOuterIter; i++) + for (j = 0; j < numInnerIter; j++) + kernelString += string(" a[") + num2str(i * numInnerIter + j) + string("].x = lMemStore[") + num2str(j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * (N + numWorkItemsPerXForm)) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < maxRadix; i++) + { + j = i % numIter; + k = i / numIter; + ind = j * Nr + k; + kernelString += string(" lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].y;\n"); + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < numOuterIter; i++) + for (j = 0; j < numInnerIter; j++) + kernelString += string(" a[") + num2str(i * numInnerIter + j) + string("].y = lMemStore[") + num2str(j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * (N + numWorkItemsPerXForm)) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); + for (i = 0; i < numOuterIter; i++) + { + kernelString += string(" if( jj < s ) {\n"); + for (j = 0; j < numInnerIter; j++) + formattedStore(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * N, dataFormat); + kernelString += string(" }\n"); + if (i != numOuterIter - 1) + kernelString += string(" jj += ") + num2str(groupSize / mem_coalesce_width) + string(";\n"); + } + kernelString += string("}\n"); + kernelString += string("else {\n"); + for (i = 0; i < numOuterIter; i++) + { + for (j = 0; j < numInnerIter; j++) + formattedStore(kernelString, i * numInnerIter + j, j * mem_coalesce_width + i * (groupSize / mem_coalesce_width) * N, dataFormat); + } + kernelString += string("}\n"); + + lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; + } + else + { + kernelString += string(" lMemLoad = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + + kernelString += string(" ii = lId & ") + num2str(N - 1) + string(";\n"); + kernelString += string(" jj = lId >> ") + num2str((int)log2(N)) + string(";\n"); + kernelString += string(" lMemStore = sMem + mad24( jj,") + num2str(N + numWorkItemsPerXForm) + string(", ii );\n"); + + for (i = 0; i < maxRadix; i++) + { + j = i % numIter; + k = i / numIter; + ind = j * Nr + k; + kernelString += string(" lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].x;\n"); + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < maxRadix; i++) + kernelString += string(" a[") + num2str(i) + string("].x = lMemStore[") + num2str(i * (groupSize / N) * (N + numWorkItemsPerXForm)) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < maxRadix; i++) + { + j = i % numIter; + k = i / numIter; + ind = j * Nr + k; + kernelString += string(" lMemLoad[") + num2str(i * numWorkItemsPerXForm) + string("] = a[") + num2str(ind) + string("].y;\n"); + } + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + for (i = 0; i < maxRadix; i++) + kernelString += string(" a[") + num2str(i) + string("].y = lMemStore[") + num2str(i * (groupSize / N) * (N + numWorkItemsPerXForm)) + string("];\n"); + kernelString += string(" barrier( CLK_LOCAL_MEM_FENCE );\n"); + + kernelString += string("if((groupId == get_num_groups(0)-1) && s) {\n"); + for (i = 0; i < maxRadix; i++) + { + kernelString += string(" if(jj < s ) {\n"); + formattedStore(kernelString, i, i * groupSize, dataFormat); + kernelString += string(" }\n"); + if (i != maxRadix - 1) + kernelString += string(" jj +=") + num2str(groupSize / N) + string(";\n"); + } + kernelString += string("}\n"); + kernelString += string("else {\n"); + for (i = 0; i < maxRadix; i++) + { + formattedStore(kernelString, i, i * groupSize, dataFormat); + } + kernelString += string("}\n"); + + lMemSize = (N + numWorkItemsPerXForm) * numXFormsPerWG; + } + + return lMemSize; +} + +static void +insertfftKernel(string &kernelString, int Nr, int numIter) +{ + int i; + for (i = 0; i < numIter; i++) + { + kernelString += string(" fftKernel") + num2str(Nr) + string("(a+") + num2str(i * Nr) + string(", dir);\n"); + } +} + +static void +insertTwiddleKernel(string &kernelString, int Nr, int numIter, int Nprev, int len, int numWorkItemsPerXForm) +{ + int z, k; + int logNPrev = (int)log2(Nprev); + + for (z = 0; z < numIter; z++) + { + if (z == 0) + { + if (Nprev > 1) + kernelString += string(" angf = (float) (ii >> ") + num2str(logNPrev) + string(");\n"); + else + kernelString += string(" angf = (float) ii;\n"); + } + else + { + if (Nprev > 1) + kernelString += string(" angf = (float) ((") + num2str(z * numWorkItemsPerXForm) + string(" + ii) >>") + num2str(logNPrev) + string(");\n"); + else + kernelString += string(" angf = (float) (") + num2str(z * numWorkItemsPerXForm) + string(" + ii);\n"); + } + + for (k = 1; k < Nr; k++) + { + int ind = z * Nr + k; + //float fac = (float) (2.0 * M_PI * (double) k / (double) len); + kernelString += string(" ang = dir * ( 2.0f * M_PI * ") + num2str(k) + string(".0f / ") + num2str(len) + string(".0f )") + string(" * angf;\n"); + kernelString += string(" w = (float2)(native_cos(ang), native_sin(ang));\n"); + kernelString += string(" a[") + num2str(ind) + string("] = complexMul(a[") + num2str(ind) + string("], w);\n"); + } + } +} + +static int +getPadding(int numWorkItemsPerXForm, int Nprev, int numWorkItemsReq, int numXFormsPerWG, int Nr, int numBanks, int *offset, int *midPad) +{ + if ((numWorkItemsPerXForm <= Nprev) || (Nprev >= numBanks)) + *offset = 0; + else + { + int numRowsReq = ((numWorkItemsPerXForm < numBanks) ? numWorkItemsPerXForm : numBanks) / Nprev; + int numColsReq = 1; + if (numRowsReq > Nr) + numColsReq = numRowsReq / Nr; + numColsReq = Nprev * numColsReq; + *offset = numColsReq; + } + + if (numWorkItemsPerXForm >= numBanks || numXFormsPerWG == 1) + *midPad = 0; + else + { + int bankNum = ((numWorkItemsReq + *offset) * Nr) & (numBanks - 1); + if (bankNum >= numWorkItemsPerXForm) + *midPad = 0; + else + *midPad = numWorkItemsPerXForm - bankNum; + } + + int lMemSize = (numWorkItemsReq + *offset) * Nr * numXFormsPerWG + *midPad * (numXFormsPerWG - 1); + return lMemSize; +} + + +static void +insertLocalStores(string &kernelString, int numIter, int Nr, int numWorkItemsPerXForm, int numWorkItemsReq, int offset, string &comp) +{ + int z, k; + + for (z = 0; z < numIter; z++) + { + for (k = 0; k < Nr; k++) + { + int index = k * (numWorkItemsReq + offset) + z * numWorkItemsPerXForm; + kernelString += string(" lMemStore[") + num2str(index) + string("] = a[") + num2str(z * Nr + k) + string("].") + comp + string(";\n"); + } + } + kernelString += string(" barrier(CLK_LOCAL_MEM_FENCE);\n"); +} + +static void +insertLocalLoads(string &kernelString, int n, int Nr, int Nrn, int Nprev, int Ncurr, int numWorkItemsPerXForm, int numWorkItemsReq, int offset, string &comp) +{ + int numWorkItemsReqN = n / Nrn; + int interBlockHNum = max(Nprev / numWorkItemsPerXForm, 1); + int interBlockHStride = numWorkItemsPerXForm; + int vertWidth = max(numWorkItemsPerXForm / Nprev, 1); + vertWidth = min(vertWidth, Nr); + int vertNum = Nr / vertWidth; + int vertStride = (n / Nr + offset) * vertWidth; + int iter = max(numWorkItemsReqN / numWorkItemsPerXForm, 1); + int intraBlockHStride = (numWorkItemsPerXForm / (Nprev * Nr)) > 1 ? (numWorkItemsPerXForm / (Nprev * Nr)) : 1; + intraBlockHStride *= Nprev; + + int stride = numWorkItemsReq / Nrn; + int i; + for (i = 0; i < iter; i++) + { + int ii = i / (interBlockHNum * vertNum); + int zz = i % (interBlockHNum * vertNum); + int jj = zz % interBlockHNum; + int kk = zz / interBlockHNum; + int z; + for (z = 0; z < Nrn; z++) + { + int st = kk * vertStride + jj * interBlockHStride + ii * intraBlockHStride + z * stride; + kernelString += string(" a[") + num2str(i * Nrn + z) + string("].") + comp + string(" = lMemLoad[") + num2str(st) + string("];\n"); + } + } + kernelString += string(" barrier(CLK_LOCAL_MEM_FENCE);\n"); +} + +static void +insertLocalLoadIndexArithmatic(string &kernelString, int Nprev, int Nr, int numWorkItemsReq, int numWorkItemsPerXForm, int numXFormsPerWG, int offset, int midPad) +{ + int Ncurr = Nprev * Nr; + int logNcurr = (int)log2(Ncurr); + int logNprev = (int)log2(Nprev); + int incr = (numWorkItemsReq + offset) * Nr + midPad; + + if (Ncurr < numWorkItemsPerXForm) + { + if (Nprev == 1) + kernelString += string(" j = ii & ") + num2str(Ncurr - 1) + string(";\n"); + else + kernelString += string(" j = (ii & ") + num2str(Ncurr - 1) + string(") >> ") + num2str(logNprev) + string(";\n"); + + if (Nprev == 1) + kernelString += string(" i = ii >> ") + num2str(logNcurr) + string(";\n"); + else + kernelString += string(" i = mad24(ii >> ") + num2str(logNcurr) + string(", ") + num2str(Nprev) + string(", ii & ") + num2str(Nprev - 1) + string(");\n"); + } + else + { + if (Nprev == 1) + kernelString += string(" j = ii;\n"); + else + kernelString += string(" j = ii >> ") + num2str(logNprev) + string(";\n"); + if (Nprev == 1) + kernelString += string(" i = 0;\n"); + else + kernelString += string(" i = ii & ") + num2str(Nprev - 1) + string(";\n"); + } + + if (numXFormsPerWG > 1) + kernelString += string(" i = mad24(jj, ") + num2str(incr) + string(", i);\n"); + + kernelString += string(" lMemLoad = sMem + mad24(j, ") + num2str(numWorkItemsReq + offset) + string(", i);\n"); +} + +static void +insertLocalStoreIndexArithmatic(string &kernelString, int numWorkItemsReq, int numXFormsPerWG, int Nr, int offset, int midPad) +{ + if (numXFormsPerWG == 1) + { + kernelString += string(" lMemStore = sMem + ii;\n"); + } + else + { + kernelString += string(" lMemStore = sMem + mad24(jj, ") + num2str((numWorkItemsReq + offset) * Nr + midPad) + string(", ii);\n"); + } +} + + +static void +createLocalMemfftKernelString(cl_fft_plan *plan) +{ + unsigned int radixArray[10]; + unsigned int numRadix; + + unsigned int n = plan->n.x; + + assert(n <= plan->max_work_item_per_workgroup * plan->max_radix && "signal lenght too big for local mem fft\n"); + + getRadixArray(n, radixArray, &numRadix, 0); + assert(numRadix > 0 && "no radix array supplied\n"); + + if (n / radixArray[0] > plan->max_work_item_per_workgroup) + getRadixArray(n, radixArray, &numRadix, plan->max_radix); + + assert(radixArray[0] <= plan->max_radix && "max radix choosen is greater than allowed\n"); + assert(n / radixArray[0] <= plan->max_work_item_per_workgroup && "required work items per xform greater than maximum work items allowed per work group for local mem fft\n"); + + unsigned int tmpLen = 1; + unsigned int i; + for (i = 0; i < numRadix; i++) + { + assert(radixArray[i] && !((radixArray[i] - 1) & radixArray[i])); + tmpLen *= radixArray[i]; + } + assert(tmpLen == n && "product of radices choosen doesnt match the length of signal\n"); + + int offset, midPad; + string localString(""), kernelName(""); + + clFFT_DataFormat dataFormat = plan->format; + string *kernelString = plan->kernel_string; + + + cl_fft_kernel_info **kInfo = &plan->kernel_info; + int kCount = 0; + + while (*kInfo) + { + kInfo = &(*kInfo)->next; + kCount++; + } + + kernelName = string("fft") + num2str(kCount); + + *kInfo = (cl_fft_kernel_info *)malloc(sizeof(cl_fft_kernel_info)); + (*kInfo)->kernel = nullptr; + (*kInfo)->lmem_size = 0; + (*kInfo)->num_workgroups = 0; + (*kInfo)->num_workitems_per_workgroup = 0; + (*kInfo)->dir = cl_fft_kernel_x; + (*kInfo)->in_place_possible = 1; + (*kInfo)->next = nullptr; + (*kInfo)->kernel_name = (char *)malloc(sizeof(char) * (kernelName.size() + 1)); + strcpy((*kInfo)->kernel_name, kernelName.c_str()); + + unsigned int numWorkItemsPerXForm = n / radixArray[0]; + unsigned int numWorkItemsPerWG = numWorkItemsPerXForm <= 64 ? 64 : numWorkItemsPerXForm; + assert(numWorkItemsPerWG <= plan->max_work_item_per_workgroup); + int numXFormsPerWG = numWorkItemsPerWG / numWorkItemsPerXForm; + (*kInfo)->num_workgroups = 1; + (*kInfo)->num_xforms_per_workgroup = numXFormsPerWG; + (*kInfo)->num_workitems_per_workgroup = numWorkItemsPerWG; + + unsigned int *N = radixArray; + unsigned int maxRadix = N[0]; + unsigned int lMemSize = 0; + + insertVariables(localString, maxRadix); + + lMemSize = insertGlobalLoadsAndTranspose(localString, n, numWorkItemsPerXForm, numXFormsPerWG, maxRadix, plan->min_mem_coalesce_width, dataFormat); + (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; + + string xcomp = string("x"); + string ycomp = string("y"); + + unsigned int Nprev = 1; + unsigned int len = n; + unsigned int r; + for (r = 0; r < numRadix; r++) + { + int numIter = N[0] / N[r]; + int numWorkItemsReq = n / N[r]; + int Ncurr = Nprev * N[r]; + insertfftKernel(localString, N[r], numIter); + + if (r < (numRadix - 1)) + { + insertTwiddleKernel(localString, N[r], numIter, Nprev, len, numWorkItemsPerXForm); + lMemSize = getPadding(numWorkItemsPerXForm, Nprev, numWorkItemsReq, numXFormsPerWG, N[r], plan->num_local_mem_banks, &offset, &midPad); + (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; + insertLocalStoreIndexArithmatic(localString, numWorkItemsReq, numXFormsPerWG, N[r], offset, midPad); + insertLocalLoadIndexArithmatic(localString, Nprev, N[r], numWorkItemsReq, numWorkItemsPerXForm, numXFormsPerWG, offset, midPad); + insertLocalStores(localString, numIter, N[r], numWorkItemsPerXForm, numWorkItemsReq, offset, xcomp); + insertLocalLoads(localString, n, N[r], N[r + 1], Nprev, Ncurr, numWorkItemsPerXForm, numWorkItemsReq, offset, xcomp); + insertLocalStores(localString, numIter, N[r], numWorkItemsPerXForm, numWorkItemsReq, offset, ycomp); + insertLocalLoads(localString, n, N[r], N[r + 1], Nprev, Ncurr, numWorkItemsPerXForm, numWorkItemsReq, offset, ycomp); + Nprev = Ncurr; + len = len / N[r]; + } + } + + lMemSize = insertGlobalStoresAndTranspose(localString, n, maxRadix, N[numRadix - 1], numWorkItemsPerXForm, numXFormsPerWG, plan->min_mem_coalesce_width, dataFormat); + (*kInfo)->lmem_size = (lMemSize > (*kInfo)->lmem_size) ? lMemSize : (*kInfo)->lmem_size; + + insertHeader(*kernelString, kernelName, dataFormat); + *kernelString += string("{\n"); + if ((*kInfo)->lmem_size) + *kernelString += string(" __local float sMem[") + num2str((*kInfo)->lmem_size) + string("];\n"); + *kernelString += localString; + *kernelString += string("}\n"); +} + +// For n larger than what can be computed using local memory fft, global transposes +// multiple kernel launces is needed. For these sizes, n can be decomposed using +// much larger base radices i.e. say n = 262144 = 128 x 64 x 32. Thus three kernel +// launches will be needed, first computing 64 x 32, length 128 ffts, second computing +// 128 x 32 length 64 ffts, and finally a kernel computing 128 x 64 length 32 ffts. +// Each of these base radices can futher be divided into factors so that each of these +// base ffts can be computed within one kernel launch using in-register ffts and local +// memory transposes i.e for the first kernel above which computes 64 x 32 ffts on length +// 128, 128 can be decomposed into 128 = 16 x 8 i.e. 8 work items can compute 8 length +// 16 ffts followed by transpose using local memory followed by each of these eight +// work items computing 2 length 8 ffts thus computing 16 length 8 ffts in total. This +// means only 8 work items are needed for computing one length 128 fft. If we choose +// work group size of say 64, we can compute 64/8 = 8 length 128 ffts within one +// work group. Since we need to compute 64 x 32 length 128 ffts in first kernel, this +// means we need to launch 64 x 32 / 8 = 256 work groups with 64 work items in each +// work group where each work group is computing 8 length 128 ffts where each length +// 128 fft is computed by 8 work items. Same logic can be applied to other two kernels +// in this example. Users can play with difference base radices and difference +// decompositions of base radices to generates different kernels and see which gives +// best performance. Following function is just fixed to use 128 as base radix + +void getGlobalRadixInfo(int n, int *radix, int *R1, int *R2, int *numRadices) +{ + int baseRadix = min(n, 128); + + int numR = 0; + int N = n; + while (N > baseRadix) + { + N /= baseRadix; + numR++; + } + + for (int i = 0; i < numR; i++) + radix[i] = baseRadix; + + radix[numR] = N; + numR++; + *numRadices = numR; + + for (int i = 0; i < numR; i++) + { + int B = radix[i]; + if (B <= 8) + { + R1[i] = B; + R2[i] = 1; + continue; + } + + int r1 = 2; + int r2 = B / r1; + while (r2 > r1) + { + r1 *= 2; + r2 = B / r1; + } + R1[i] = r1; + R2[i] = r2; + } +} + +static void +createGlobalFFTKernelString(cl_fft_plan *plan, int n, int BS, cl_fft_kernel_dir dir, int vertBS) +{ + int i, j, k, t; + int radixArr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int R1Arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int R2Arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int radix, R1, R2; + int numRadices; + + int maxThreadsPerBlock = plan->max_work_item_per_workgroup; + int maxArrayLen = plan->max_radix; + int batchSize = plan->min_mem_coalesce_width; + clFFT_DataFormat dataFormat = plan->format; + int vertical = (dir == cl_fft_kernel_x) ? 0 : 1; + + getGlobalRadixInfo(n, radixArr, R1Arr, R2Arr, &numRadices); + + int numPasses = numRadices; + + string localString(""), kernelName(""); + string *kernelString = plan->kernel_string; + cl_fft_kernel_info **kInfo = &plan->kernel_info; + int kCount = 0; + + while (*kInfo) + { + kInfo = &(*kInfo)->next; + kCount++; + } + + int N = n; + int m = (int)log2(n); + int Rinit = vertical ? BS : 1; + batchSize = vertical ? min(BS, batchSize) : batchSize; + int passNum; + + for (passNum = 0; passNum < numPasses; passNum++) + { + localString.clear(); + kernelName.clear(); + + radix = radixArr[passNum]; + R1 = R1Arr[passNum]; + R2 = R2Arr[passNum]; + + int strideI = Rinit; + for (i = 0; i < numPasses; i++) + if (i != passNum) + strideI *= radixArr[i]; + + int strideO = Rinit; + for (i = 0; i < passNum; i++) + strideO *= radixArr[i]; + + int threadsPerXForm = R2; + batchSize = R2 == 1 ? plan->max_work_item_per_workgroup : batchSize; + batchSize = min(batchSize, strideI); + int threadsPerBlock = batchSize * threadsPerXForm; + threadsPerBlock = min(threadsPerBlock, maxThreadsPerBlock); + batchSize = threadsPerBlock / threadsPerXForm; + assert(R2 <= R1); + assert(R1 * R2 == radix); + assert(R1 <= maxArrayLen); + assert(threadsPerBlock <= maxThreadsPerBlock); + + int numIter = R1 / R2; + int gInInc = threadsPerBlock / batchSize; + + + int lgStrideO = (int)log2(strideO); + int numBlocksPerXForm = strideI / batchSize; + int numBlocks = numBlocksPerXForm; + if (!vertical) + numBlocks *= BS; + else + numBlocks *= vertBS; + + kernelName = string("fft") + num2str(kCount); + *kInfo = (cl_fft_kernel_info *)malloc(sizeof(cl_fft_kernel_info)); + (*kInfo)->kernel = nullptr; + if (R2 == 1) + (*kInfo)->lmem_size = 0; + else + { + if (strideO == 1) + (*kInfo)->lmem_size = (radix + 1) * batchSize; + else + (*kInfo)->lmem_size = threadsPerBlock * R1; + } + (*kInfo)->num_workgroups = numBlocks; + (*kInfo)->num_xforms_per_workgroup = 1; + (*kInfo)->num_workitems_per_workgroup = threadsPerBlock; + (*kInfo)->dir = dir; + if ((passNum == (numPasses - 1)) && (numPasses & 1)) + (*kInfo)->in_place_possible = 1; + else + (*kInfo)->in_place_possible = 0; + (*kInfo)->next = nullptr; + (*kInfo)->kernel_name = (char *)malloc(sizeof(char) * (kernelName.size() + 1)); + strcpy((*kInfo)->kernel_name, kernelName.c_str()); + + insertVariables(localString, R1); + + if (vertical) + { + localString += string("xNum = groupId >> ") + num2str((int)log2(numBlocksPerXForm)) + string(";\n"); + localString += string("groupId = groupId & ") + num2str(numBlocksPerXForm - 1) + string(";\n"); + localString += string("indexIn = mad24(groupId, ") + num2str(batchSize) + string(", xNum << ") + num2str((int)log2(n * BS)) + string(");\n"); + localString += string("tid = mul24(groupId, ") + num2str(batchSize) + string(");\n"); + localString += string("i = tid >> ") + num2str(lgStrideO) + string(";\n"); + localString += string("j = tid & ") + num2str(strideO - 1) + string(";\n"); + int stride = radix * Rinit; + for (i = 0; i < passNum; i++) + stride *= radixArr[i]; + localString += string("indexOut = mad24(i, ") + num2str(stride) + string(", j + ") + string("(xNum << ") + num2str((int)log2(n * BS)) + string("));\n"); + localString += string("bNum = groupId;\n"); + } + else + { + int lgNumBlocksPerXForm = (int)log2(numBlocksPerXForm); + localString += string("bNum = groupId & ") + num2str(numBlocksPerXForm - 1) + string(";\n"); + localString += string("xNum = groupId >> ") + num2str(lgNumBlocksPerXForm) + string(";\n"); + localString += string("indexIn = mul24(bNum, ") + num2str(batchSize) + string(");\n"); + localString += string("tid = indexIn;\n"); + localString += string("i = tid >> ") + num2str(lgStrideO) + string(";\n"); + localString += string("j = tid & ") + num2str(strideO - 1) + string(";\n"); + int stride = radix * Rinit; + for (i = 0; i < passNum; i++) + stride *= radixArr[i]; + localString += string("indexOut = mad24(i, ") + num2str(stride) + string(", j);\n"); + localString += string("indexIn += (xNum << ") + num2str(m) + string(");\n"); + localString += string("indexOut += (xNum << ") + num2str(m) + string(");\n"); + } + + // Load Data + int lgBatchSize = (int)log2(batchSize); + localString += string("tid = lId;\n"); + localString += string("i = tid & ") + num2str(batchSize - 1) + string(";\n"); + localString += string("j = tid >> ") + num2str(lgBatchSize) + string(";\n"); + localString += string("indexIn += mad24(j, ") + num2str(strideI) + string(", i);\n"); + + if (dataFormat == clFFT_SplitComplexFormat) + { + localString += string("in_real += indexIn;\n"); + localString += string("in_imag += indexIn;\n"); + for (j = 0; j < R1; j++) + localString += string("a[") + num2str(j) + string("].x = in_real[") + num2str(j * gInInc * strideI) + string("];\n"); + for (j = 0; j < R1; j++) + localString += string("a[") + num2str(j) + string("].y = in_imag[") + num2str(j * gInInc * strideI) + string("];\n"); + } + else + { + localString += string("in += indexIn;\n"); + for (j = 0; j < R1; j++) + localString += string("a[") + num2str(j) + string("] = in[") + num2str(j * gInInc * strideI) + string("];\n"); + } + + localString += string("fftKernel") + num2str(R1) + string("(a, dir);\n"); + + if (R2 > 1) + { + // twiddle + for (k = 1; k < R1; k++) + { + localString += string("ang = dir*(2.0f*M_PI*") + num2str(k) + string("/") + num2str(radix) + string(")*j;\n"); + localString += string("w = (float2)(native_cos(ang), native_sin(ang));\n"); + localString += string("a[") + num2str(k) + string("] = complexMul(a[") + num2str(k) + string("], w);\n"); + } + + // shuffle + numIter = R1 / R2; + localString += string("indexIn = mad24(j, ") + num2str(threadsPerBlock * numIter) + string(", i);\n"); + localString += string("lMemStore = sMem + tid;\n"); + localString += string("lMemLoad = sMem + indexIn;\n"); + for (k = 0; k < R1; k++) + localString += string("lMemStore[") + num2str(k * threadsPerBlock) + string("] = a[") + num2str(k) + string("].x;\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + for (k = 0; k < numIter; k++) + for (t = 0; t < R2; t++) + localString += string("a[") + num2str(k * R2 + t) + string("].x = lMemLoad[") + num2str(t * batchSize + k * threadsPerBlock) + string("];\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + for (k = 0; k < R1; k++) + localString += string("lMemStore[") + num2str(k * threadsPerBlock) + string("] = a[") + num2str(k) + string("].y;\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + for (k = 0; k < numIter; k++) + for (t = 0; t < R2; t++) + localString += string("a[") + num2str(k * R2 + t) + string("].y = lMemLoad[") + num2str(t * batchSize + k * threadsPerBlock) + string("];\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + + for (j = 0; j < numIter; j++) + localString += string("fftKernel") + num2str(R2) + string("(a + ") + num2str(j * R2) + string(", dir);\n"); + } + + // twiddle + if (passNum < (numPasses - 1)) + { + localString += string("l = ((bNum << ") + num2str(lgBatchSize) + string(") + i) >> ") + num2str(lgStrideO) + string(";\n"); + localString += string("k = j << ") + num2str((int)log2(R1 / R2)) + string(";\n"); + localString += string("ang1 = dir*(2.0f*M_PI/") + num2str(N) + string(")*l;\n"); + for (t = 0; t < R1; t++) + { + localString += string("ang = ang1*(k + ") + num2str((t % R2) * R1 + (t / R2)) + string(");\n"); + localString += string("w = (float2)(native_cos(ang), native_sin(ang));\n"); + localString += string("a[") + num2str(t) + string("] = complexMul(a[") + num2str(t) + string("], w);\n"); + } + } + + // Store Data + if (strideO == 1) + { + localString += string("lMemStore = sMem + mad24(i, ") + num2str(radix + 1) + string(", j << ") + num2str((int)log2(R1 / R2)) + string(");\n"); + localString += string("lMemLoad = sMem + mad24(tid >> ") + num2str((int)log2(radix)) + string(", ") + num2str(radix + 1) + string(", tid & ") + num2str(radix - 1) + string(");\n"); + + for (i = 0; i < R1 / R2; i++) + for (j = 0; j < R2; j++) + localString += string("lMemStore[ ") + num2str(i + j * R1) + string("] = a[") + num2str(i * R2 + j) + string("].x;\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + if (threadsPerBlock >= radix) + { + for (i = 0; i < R1; i++) + localString += string("a[") + num2str(i) + string("].x = lMemLoad[") + num2str(i * (radix + 1) * (threadsPerBlock / radix)) + string("];\n"); + } + else + { + int innerIter = radix / threadsPerBlock; + int outerIter = R1 / innerIter; + for (i = 0; i < outerIter; i++) + for (j = 0; j < innerIter; j++) + localString += string("a[") + num2str(i * innerIter + j) + string("].x = lMemLoad[") + num2str(j * threadsPerBlock + i * (radix + 1)) + string("];\n"); + } + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + + for (i = 0; i < R1 / R2; i++) + for (j = 0; j < R2; j++) + localString += string("lMemStore[ ") + num2str(i + j * R1) + string("] = a[") + num2str(i * R2 + j) + string("].y;\n"); + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + if (threadsPerBlock >= radix) + { + for (i = 0; i < R1; i++) + localString += string("a[") + num2str(i) + string("].y = lMemLoad[") + num2str(i * (radix + 1) * (threadsPerBlock / radix)) + string("];\n"); + } + else + { + int innerIter = radix / threadsPerBlock; + int outerIter = R1 / innerIter; + for (i = 0; i < outerIter; i++) + for (j = 0; j < innerIter; j++) + localString += string("a[") + num2str(i * innerIter + j) + string("].y = lMemLoad[") + num2str(j * threadsPerBlock + i * (radix + 1)) + string("];\n"); + } + localString += string("barrier(CLK_LOCAL_MEM_FENCE);\n"); + + localString += string("indexOut += tid;\n"); + if (dataFormat == clFFT_SplitComplexFormat) + { + localString += string("out_real += indexOut;\n"); + localString += string("out_imag += indexOut;\n"); + for (k = 0; k < R1; k++) + localString += string("out_real[") + num2str(k * threadsPerBlock) + string("] = a[") + num2str(k) + string("].x;\n"); + for (k = 0; k < R1; k++) + localString += string("out_imag[") + num2str(k * threadsPerBlock) + string("] = a[") + num2str(k) + string("].y;\n"); + } + else + { + localString += string("out += indexOut;\n"); + for (k = 0; k < R1; k++) + localString += string("out[") + num2str(k * threadsPerBlock) + string("] = a[") + num2str(k) + string("];\n"); + } + } + else + { + localString += string("indexOut += mad24(j, ") + num2str(numIter * strideO) + string(", i);\n"); + if (dataFormat == clFFT_SplitComplexFormat) + { + localString += string("out_real += indexOut;\n"); + localString += string("out_imag += indexOut;\n"); + for (k = 0; k < R1; k++) + localString += string("out_real[") + num2str(((k % R2) * R1 + (k / R2)) * strideO) + string("] = a[") + num2str(k) + string("].x;\n"); + for (k = 0; k < R1; k++) + localString += string("out_imag[") + num2str(((k % R2) * R1 + (k / R2)) * strideO) + string("] = a[") + num2str(k) + string("].y;\n"); + } + else + { + localString += string("out += indexOut;\n"); + for (k = 0; k < R1; k++) + localString += string("out[") + num2str(((k % R2) * R1 + (k / R2)) * strideO) + string("] = a[") + num2str(k) + string("];\n"); + } + } + + insertHeader(*kernelString, kernelName, dataFormat); + *kernelString += string("{\n"); + if ((*kInfo)->lmem_size) + *kernelString += string(" __local float sMem[") + num2str((*kInfo)->lmem_size) + string("];\n"); + *kernelString += localString; + *kernelString += string("}\n"); + + N /= radix; + kInfo = &(*kInfo)->next; + kCount++; + } +} + +void FFT1D(cl_fft_plan *plan, cl_fft_kernel_dir dir) +{ + unsigned int radixArray[10]; + unsigned int numRadix; + + switch (dir) + { + case cl_fft_kernel_x: + if (plan->n.x > plan->max_localmem_fft_size) + { + createGlobalFFTKernelString(plan, plan->n.x, 1, cl_fft_kernel_x, 1); + } + else if (plan->n.x > 1) + { + getRadixArray(plan->n.x, radixArray, &numRadix, 0); + if (plan->n.x / radixArray[0] <= plan->max_work_item_per_workgroup) + { + createLocalMemfftKernelString(plan); + } + else + { + getRadixArray(plan->n.x, radixArray, &numRadix, plan->max_radix); + if (plan->n.x / radixArray[0] <= plan->max_work_item_per_workgroup) + createLocalMemfftKernelString(plan); + else + createGlobalFFTKernelString(plan, plan->n.x, 1, cl_fft_kernel_x, 1); + } + } + break; + + case cl_fft_kernel_y: + if (plan->n.y > 1) + createGlobalFFTKernelString(plan, plan->n.y, plan->n.x, cl_fft_kernel_y, 1); + break; + + case cl_fft_kernel_z: + if (plan->n.z > 1) + createGlobalFFTKernelString(plan, plan->n.z, plan->n.x * plan->n.y, cl_fft_kernel_z, 1); + default: + return; + } +} diff --git a/src/algorithms/libs/opencl/fft_setup.cc b/src/algorithms/libs/opencl/fft_setup.cc new file mode 100644 index 000000000..a56c05328 --- /dev/null +++ b/src/algorithms/libs/opencl/fft_setup.cc @@ -0,0 +1,402 @@ + +// +// File: fft_setup.cpp +// +// Version: <1.0> +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") +// in consideration of your agreement to the following terms, and your use, +// installation, modification or redistribution of this Apple software +// constitutes acceptance of these terms. If you do not agree with these +// terms, please do not use, install, modify or redistribute this Apple +// software. +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non - exclusive +// license, under Apple's copyrights in this original Apple software ( the +// "Apple Software" ), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and / or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following text +// and disclaimers in all such redistributions of the Apple Software. Neither +// the name, trademarks, service marks or logos of Apple Inc. may be used to +// endorse or promote products derived from the Apple Software without specific +// prior written permission from Apple. Except as expressly stated in this +// notice, no other rights or licenses, express or implied, are granted by +// Apple herein, including but not limited to any patent rights that may be +// infringed by your derivative works or by other works in which the Apple +// Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION +// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION +// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER +// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR +// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include "fft_base_kernels.h" +#include "fft_internal.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +extern void getKernelWorkDimensions(cl_fft_plan *plan, cl_fft_kernel_info *kernelInfo, cl_int *batchSize, size_t *gWorkItems, size_t *lWorkItems); + +static void +getBlockConfigAndKernelString(cl_fft_plan *plan) +{ + plan->temp_buffer_needed = 0; + *plan->kernel_string += baseKernels; + + if (plan->format == clFFT_SplitComplexFormat) + *plan->kernel_string += twistKernelPlannar; + else + *plan->kernel_string += twistKernelInterleaved; + + switch (plan->dim) + { + case clFFT_1D: + FFT1D(plan, cl_fft_kernel_x); + break; + + case clFFT_2D: + FFT1D(plan, cl_fft_kernel_x); + FFT1D(plan, cl_fft_kernel_y); + break; + + case clFFT_3D: + FFT1D(plan, cl_fft_kernel_x); + FFT1D(plan, cl_fft_kernel_y); + FFT1D(plan, cl_fft_kernel_z); + break; + + default: + return; + } + + plan->temp_buffer_needed = 0; + cl_fft_kernel_info *kInfo = plan->kernel_info; + while (kInfo) + { + plan->temp_buffer_needed |= !kInfo->in_place_possible; + kInfo = kInfo->next; + } +} + + +static void +deleteKernelInfo(cl_fft_kernel_info *kInfo) +{ + if (kInfo) + { + if (kInfo->kernel_name) + free(kInfo->kernel_name); + if (kInfo->kernel) + clReleaseKernel(kInfo->kernel); + free(kInfo); + } +} + +static void +destroy_plan(cl_fft_plan *Plan) +{ + cl_fft_kernel_info *kernel_info = Plan->kernel_info; + + while (kernel_info) + { + cl_fft_kernel_info *tmp = kernel_info->next; + deleteKernelInfo(kernel_info); + kernel_info = tmp; + } + + Plan->kernel_info = nullptr; + + if (Plan->kernel_string) + { + delete Plan->kernel_string; + Plan->kernel_string = nullptr; + } + if (Plan->twist_kernel) + { + clReleaseKernel(Plan->twist_kernel); + Plan->twist_kernel = nullptr; + } + if (Plan->program) + { + clReleaseProgram(Plan->program); + Plan->program = nullptr; + } + if (Plan->tempmemobj) + { + clReleaseMemObject(Plan->tempmemobj); + Plan->tempmemobj = nullptr; + } + if (Plan->tempmemobj_real) + { + clReleaseMemObject(Plan->tempmemobj_real); + Plan->tempmemobj_real = nullptr; + } + if (Plan->tempmemobj_imag) + { + clReleaseMemObject(Plan->tempmemobj_imag); + Plan->tempmemobj_imag = nullptr; + } +} + +static int +createKernelList(cl_fft_plan *plan) +{ + cl_program program = plan->program; + cl_fft_kernel_info *kernel_info = plan->kernel_info; + + cl_int err; + while (kernel_info) + { + kernel_info->kernel = clCreateKernel(program, kernel_info->kernel_name, &err); + if (!kernel_info->kernel || err != CL_SUCCESS) + return err; + kernel_info = kernel_info->next; + } + + if (plan->format == clFFT_SplitComplexFormat) + plan->twist_kernel = clCreateKernel(program, "clFFT_1DTwistSplit", &err); + else + plan->twist_kernel = clCreateKernel(program, "clFFT_1DTwistInterleaved", &err); + + if (!plan->twist_kernel || err) + return err; + + return CL_SUCCESS; +} + +int getMaxKernelWorkGroupSize(cl_fft_plan *plan, unsigned int *max_wg_size, unsigned int num_devices, cl_device_id *devices) +{ + int reg_needed = 0; + *max_wg_size = std::numeric_limits::max(); + int err; + unsigned wg_size; + + unsigned int i; + for (i = 0; i < num_devices; i++) + { + cl_fft_kernel_info *kInfo = plan->kernel_info; + while (kInfo) + { + err = clGetKernelWorkGroupInfo(kInfo->kernel, devices[i], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &wg_size, nullptr); + if (err != CL_SUCCESS) + return -1; + + if (wg_size < kInfo->num_workitems_per_workgroup) + reg_needed |= 1; + + if (*max_wg_size > wg_size) + *max_wg_size = wg_size; + + kInfo = kInfo->next; + } + } + + return reg_needed; +} + +#define ERR_MACRO(err) \ + { \ + if (err != CL_SUCCESS) \ + { \ + if (error_code) \ + *error_code = err; \ + clFFT_DestroyPlan((clFFT_Plan)plan); \ + return (clFFT_Plan)NULL; \ + } \ + } + +clFFT_Plan +clFFT_CreatePlan(cl_context context, clFFT_Dim3 n, clFFT_Dimension dim, clFFT_DataFormat dataFormat, cl_int *error_code) +{ + int i; + cl_int err; + int isPow2 = 1; + cl_fft_plan *plan = nullptr; + ostringstream kString; + int num_devices; + int gpu_found = 0; + cl_device_id devices[16]; + size_t ret_size; + cl_device_type device_type; + + if (!context) + ERR_MACRO(CL_INVALID_VALUE); + + isPow2 |= n.x && !((n.x - 1) & n.x); + isPow2 |= n.y && !((n.y - 1) & n.y); + isPow2 |= n.z && !((n.z - 1) & n.z); + + if (!isPow2) + ERR_MACRO(CL_INVALID_VALUE); + + if ((dim == clFFT_1D && (n.y != 1 || n.z != 1)) || (dim == clFFT_2D && n.z != 1)) + ERR_MACRO(CL_INVALID_VALUE); + + plan = (cl_fft_plan *)malloc(sizeof(cl_fft_plan)); + if (!plan) + ERR_MACRO(CL_OUT_OF_RESOURCES); + + plan->context = context; + clRetainContext(context); + plan->n = n; + plan->dim = dim; + plan->format = dataFormat; + plan->kernel_info = nullptr; + plan->num_kernels = 0; + plan->twist_kernel = nullptr; + plan->program = nullptr; + plan->temp_buffer_needed = 0; + plan->last_batch_size = 0; + plan->tempmemobj = nullptr; + plan->tempmemobj_real = nullptr; + plan->tempmemobj_imag = nullptr; + plan->max_localmem_fft_size = 2048; + plan->max_work_item_per_workgroup = 256; + plan->max_radix = 16; + plan->min_mem_coalesce_width = 16; + plan->num_local_mem_banks = 16; + +patch_kernel_source: + + plan->kernel_string = new string(""); + if (!plan->kernel_string) + ERR_MACRO(CL_OUT_OF_RESOURCES); + + getBlockConfigAndKernelString(plan); + + const char *source_str = plan->kernel_string->c_str(); + plan->program = clCreateProgramWithSource(context, 1, (const char **)&source_str, nullptr, &err); + ERR_MACRO(err); + + err = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices), devices, &ret_size); + ERR_MACRO(err); + + num_devices = (int)(ret_size / sizeof(cl_device_id)); + + for (i = 0; i < num_devices; i++) + { + err = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(device_type), &device_type, nullptr); + ERR_MACRO(err); + + if (device_type == CL_DEVICE_TYPE_GPU) + { + gpu_found = 1; + err = clBuildProgram(plan->program, 1, &devices[i], "-cl-mad-enable", nullptr, nullptr); + if (err != CL_SUCCESS) + { + char *build_log; + char devicename[200]; + size_t log_size; + + err = clGetProgramBuildInfo(plan->program, devices[i], CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); + ERR_MACRO(err); + + build_log = (char *)malloc(log_size + 1); + + err = clGetProgramBuildInfo(plan->program, devices[i], CL_PROGRAM_BUILD_LOG, log_size, build_log, nullptr); + ERR_MACRO(err); + + err = clGetDeviceInfo(devices[i], CL_DEVICE_NAME, sizeof(devicename), devicename, nullptr); + ERR_MACRO(err); + + fprintf(stdout, "FFT program build log on device %s\n", devicename); + fprintf(stdout, "%s\n", build_log); + free(build_log); + + ERR_MACRO(err); + } + } + } + + if (!gpu_found) + ERR_MACRO(CL_INVALID_CONTEXT); + + err = createKernelList(plan); + ERR_MACRO(err); + + // we created program and kernels based on "some max work group size (default 256)" ... this work group size + // may be larger than what kernel may execute with ... if thats the case we need to regenerate the kernel source + // setting this as limit i.e max group size and rebuild. + unsigned int max_kernel_wg_size; + int patching_req = getMaxKernelWorkGroupSize(plan, &max_kernel_wg_size, num_devices, devices); + if (patching_req == -1) + { + ERR_MACRO(err); + } + + if (patching_req) + { + destroy_plan(plan); + plan->max_work_item_per_workgroup = max_kernel_wg_size; + goto patch_kernel_source; + } + + cl_fft_kernel_info *kInfo = plan->kernel_info; + while (kInfo) + { + plan->num_kernels++; + kInfo = kInfo->next; + } + + if (error_code) + *error_code = CL_SUCCESS; + + return (clFFT_Plan)plan; +} + +void clFFT_DestroyPlan(clFFT_Plan plan) +{ + auto *Plan = (cl_fft_plan *)plan; + if (Plan) + { + destroy_plan(Plan); + clReleaseContext(Plan->context); + free(Plan); + } +} + +void clFFT_DumpPlan(clFFT_Plan Plan, FILE *file) +{ + size_t gDim, lDim; + FILE *out; + if (!file) + out = stdout; + else + out = file; + + auto *plan = (cl_fft_plan *)Plan; + cl_fft_kernel_info *kInfo = plan->kernel_info; + + while (kInfo) + { + cl_int s = 1; + getKernelWorkDimensions(plan, kInfo, &s, &gDim, &lDim); + fprintf(out, "Run kernel %s with global dim = {%zd*BatchSize}, local dim={%zd}\n", kInfo->kernel_name, gDim, lDim); + kInfo = kInfo->next; + } + fprintf(out, "%s\n", plan->kernel_string->c_str()); +} diff --git a/src/algorithms/libs/pass_through.cc b/src/algorithms/libs/pass_through.cc index 94394866e..32b8b65c8 100644 --- a/src/algorithms/libs/pass_through.cc +++ b/src/algorithms/libs/pass_through.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,31 +25,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "pass_through.h" -#include -#include +#include "configuration_interface.h" #include #include -#include "configuration_interface.h" +#include using google::LogMessage; -Pass_Through::Pass_Through(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) +Pass_Through::Pass_Through(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_item_type = "gr_complex"; std::string input_type = configuration->property(role + ".input_item_type", default_item_type); std::string output_type = configuration->property(role + ".output_item_type", default_item_type); - if(input_type.compare(output_type) != 0) + if (input_type != output_type) { LOG(WARNING) << "input_item_type and output_item_type are different in a Pass_Through implementation! Taking " << input_type @@ -57,80 +55,135 @@ Pass_Through::Pass_Through(ConfigurationInterface* configuration, std::string ro } item_type_ = configuration->property(role + ".item_type", input_type); - vector_size_ = configuration->property(role + ".vector_size", 1); + inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); - if(item_type_.compare("float") == 0) + if (item_type_ == "float") { item_size_ = sizeof(float); } - else if(item_type_.compare("gr_complex") == 0) + else if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); + if (inverted_spectrum) + { + conjugate_cc_ = make_conjugate_cc(); + } } - else if(item_type_.compare("short") == 0) + else if (item_type_ == "short") { item_size_ = sizeof(int16_t); } - else if(item_type_.compare("ishort") == 0) + else if (item_type_ == "ishort") { item_size_ = sizeof(int16_t); } - else if(item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); + if (inverted_spectrum) + { + conjugate_sc_ = make_conjugate_sc(); + } } - else if(item_type_.compare("byte") == 0) + else if (item_type_ == "byte") { item_size_ = sizeof(int8_t); } - else if(item_type_.compare("ibyte") == 0) + else if (item_type_ == "ibyte") { item_size_ = sizeof(int8_t); } - else if(item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { item_size_ = sizeof(lv_8sc_t); + if (inverted_spectrum) + { + conjugate_ic_ = make_conjugate_ic(); + } } else { LOG(WARNING) << item_type_ << " unrecognized item type. Using float"; item_size_ = sizeof(float); } + kludge_copy_ = gr::blocks::copy::make(item_size_); DLOG(INFO) << "kludge_copy(" << kludge_copy_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - -Pass_Through::~Pass_Through() -{} - +Pass_Through::~Pass_Through() = default; void Pass_Through::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; DLOG(INFO) << "nothing to connect internally"; } - void Pass_Through::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } - gr::basic_block_sptr Pass_Through::get_left_block() { + if (inverted_spectrum) + { + if (item_type_ == "gr_complex") + { + return conjugate_cc_; + } + if (item_type_ == "cshort") + { + return conjugate_sc_; + } + if (item_type_ == "cbyte") + { + return conjugate_ic_; + } + LOG(WARNING) << "Setting inverted_spectrum to true with item_type " + << item_type_ << " is not defined and has no effect."; + } + return kludge_copy_; } - gr::basic_block_sptr Pass_Through::get_right_block() { + if (inverted_spectrum) + { + if (item_type_ == "gr_complex") + { + return conjugate_cc_; + } + if (item_type_ == "cshort") + { + return conjugate_sc_; + } + if (item_type_ == "cbyte") + { + return conjugate_ic_; + } + DLOG(WARNING) << "Setting inverted_spectrum to true with item_type " + << item_type_ << " is not defined and has no effect."; + } + return kludge_copy_; } diff --git a/src/algorithms/libs/pass_through.h b/src/algorithms/libs/pass_through.h index b8f394ee2..7ef1838bf 100644 --- a/src/algorithms/libs/pass_through.h +++ b/src/algorithms/libs/pass_through.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,14 @@ #ifndef GNSS_SDR_PASS_THROUGH_H_ #define GNSS_SDR_PASS_THROUGH_H_ -#include -#include -#include +#include "conjugate_cc.h" +#include "conjugate_ic.h" +#include "conjugate_sc.h" #include "gnss_block_interface.h" +#include +#include +#include + class ConfigurationInterface; @@ -47,46 +51,49 @@ class Pass_Through : public GNSSBlockInterface { public: Pass_Through(ConfigurationInterface* configuration, - std::string role, - unsigned int in_stream, - unsigned int out_stream); + const std::string& role, + unsigned int in_stream, + unsigned int out_stream); virtual ~Pass_Through(); - std::string role() + + inline std::string role() override { return role_; } + //! returns "Pass_Through" - std::string implementation() + inline std::string implementation() override { return "Pass_Through"; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - size_t vector_size() - { - return vector_size_; - } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string item_type_; - size_t vector_size_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; - //gr_kludge_copy_sptr kludge_copy_; gr::blocks::copy::sptr kludge_copy_; size_t item_size_; + conjugate_cc_sptr conjugate_cc_; + conjugate_sc_sptr conjugate_sc_; + conjugate_ic_sptr conjugate_ic_; + bool inverted_spectrum; }; #endif /*GNSS_SDR_PASS_THROUGH_H_*/ diff --git a/src/algorithms/libs/rtklib/CMakeLists.txt b/src/algorithms/libs/rtklib/CMakeLists.txt new file mode 100644 index 000000000..882cd4a81 --- /dev/null +++ b/src/algorithms/libs/rtklib/CMakeLists.txt @@ -0,0 +1,91 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + +add_definitions(-DGNSS_SDR_VERSION="${VERSION}") + +set(RTKLIB_LIB_SOURCES + rtklib_rtkcmn.cc + rtklib_ephemeris.cc + rtklib_preceph.cc + rtklib_sbas.cc + rtklib_ionex.cc + rtklib_pntpos.cc + rtklib_ppp.cc + rtklib_tides.cc + rtklib_lambda.cc + rtklib_rtkpos.cc + rtklib_conversions.cc + rtklib_stream.cc + rtklib_rtksvr.cc + rtklib_solution.cc + rtklib_rtcm.cc + rtklib_rtcm2.cc + rtklib_rtcm3.cc +) + +set(RTKLIB_LIB_HEADERS + rtklib_rtkcmn.h + rtklib_ephemeris.h + rtklib_preceph.h + rtklib_sbas.h + rtklib_ionex.h + rtklib_pntpos.h + rtklib_ppp.h + rtklib_tides.h + rtklib_lambda.h + rtklib_rtkpos.h + rtklib_conversions.h + rtklib_stream.h + rtklib_rtksvr.h + rtklib_solution.h + rtklib_rtcm.h + rtklib_rtcm2.h + rtklib_rtcm3.h + rtklib.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${Boost_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} +) + +list(SORT RTKLIB_LIB_HEADERS) +list(SORT RTKLIB_LIB_SOURCES) + +add_library(rtklib_lib ${RTKLIB_LIB_SOURCES} ${RTKLIB_LIB_HEADERS}) +source_group(Headers FILES ${RTKLIB_LIB_HEADERS}) +add_dependencies(rtklib_lib glog-${glog_RELEASE}) + +if(OS_IS_MACOSX) + set(MAC_LIBRARIES "-framework Accelerate") +endif() + +target_link_libraries( + rtklib_lib + ${Boost_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${BLAS} + ${LAPACK} + ${MAC_LIBRARIES} +) diff --git a/src/algorithms/libs/rtklib/rtklib.h b/src/algorithms/libs/rtklib/rtklib.h new file mode 100644 index 000000000..24c1dd1e8 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib.h @@ -0,0 +1,1336 @@ +/*! + * \file rtklib.h + * \brief main header file for the rtklib library + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_H_ +#define GNSS_SDR_RTKLIB_H_ + +#include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include "gnss_obs_codes.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +/* macros --------------------------------------------------------------------*/ + +#define dev_t int +#define socket_t int +#define closesocket close +#define lock_t pthread_mutex_t +#define initlock(f) pthread_mutex_init(f, NULL) +#define rtk_lock(f) pthread_mutex_lock(f) +#define rtk_unlock(f) pthread_mutex_unlock(f) + +#define VER_RTKLIB "2.4.2" +#define NTRIP_AGENT "RTKLIB/" VER_RTKLIB +#define NTRIP_CLI_PORT 2101 /* default ntrip-client connection port */ +#define NTRIP_SVR_PORT 80 /* default ntrip-server connection port */ +#define NTRIP_MAXRSP 32768 /* max size of ntrip response */ +#define NTRIP_MAXSTR 256 /* max length of mountpoint string */ +#define NTRIP_RSP_OK_CLI "ICY 200 OK\r\n" /* ntrip response: client */ +#define NTRIP_RSP_OK_SVR "OK\r\n" /* ntrip response: server */ +#define NTRIP_RSP_SRCTBL "SOURCETABLE 200 OK\r\n" /* ntrip response: source table */ +#define NTRIP_RSP_TBLEND "ENDSOURCETABLE" +#define NTRIP_RSP_HTTP "HTTP/" /* ntrip response: http */ +#define NTRIP_RSP_ERROR "ERROR" /* ntrip response: error */ + +#define FTP_CMD "wget" /* ftp/http command */ + +const int TINTACT = 200; //!< period for stream active (ms) +const int SERIBUFFSIZE = 4096; //!< serial buffer size (bytes) +const int TIMETAGH_LEN = 64; //!< time tag file header length +const int MAXCLI = 32; //!< max client connection for tcp svr +const int MAXSTATMSG = 32; //!< max length of status message + +const int FTP_TIMEOUT = 30; //!< ftp/http timeout (s) +const int MAXRAWLEN = 4096; //!< max length of receiver raw message +const int MAXSOLBUF = 256; //!< max number of solution buffer +const int MAXSBSMSG = 32; //!< max number of SBAS msg in RTK server +const int MAXOBSBUF = 128; //!< max number of observation data buffer + +const int FILEPATHSEP = '/'; +const double RE_WGS84 = 6378137.0; //!< earth semimajor axis (WGS84) (m) +const double FE_WGS84 = (1.0 / 298.257223563); //!< earth flattening (WGS84) + +const double HION = 350000.0; //!< ionosphere height (m) +const double PRN_HWBIAS = 1e-6; //!< process noise of h/w bias (m/MHz/sqrt(s)) + +const double INT_SWAP_STAT = 86400.0; //!< swap interval of solution status file (s) +const double INT_SWAP_TRAC = 86400.0; //!< swap interval of trace file (s) + +const unsigned int POLYCRC32 = 0xEDB88320u; //!< CRC32 polynomial +const unsigned int POLYCRC24Q = 0x1864CFBu; //!< CRC24Q polynomial + +const int PMODE_SINGLE = 0; //!< positioning mode: single +const int PMODE_DGPS = 1; //!< positioning mode: DGPS/DGNSS +const int PMODE_KINEMA = 2; //!< positioning mode: kinematic +const int PMODE_STATIC = 3; //!< positioning mode: static +const int PMODE_MOVEB = 4; //!< positioning mode: moving-base +const int PMODE_FIXED = 5; //!< positioning mode: fixed +const int PMODE_PPP_KINEMA = 6; //!< positioning mode: PPP-kinemaric +const int PMODE_PPP_STATIC = 7; //!< positioning mode: PPP-static +const int PMODE_PPP_FIXED = 8; //!< positioning mode: PPP-fixed + +const int SOLF_LLH = 0; //!< solution format: lat/lon/height +const int SOLF_XYZ = 1; //!< solution format: x/y/z-ecef +const int SOLF_ENU = 2; //!< solution format: e/n/u-baseline +const int SOLF_NMEA = 3; //!< solution format: NMEA-183 +const int SOLF_STAT = 4; //!< solution format: solution status +const int SOLF_GSIF = 5; //!< solution format: GSI F1/F2 + +const int SOLQ_NONE = 0; //!< solution status: no solution +const int SOLQ_FIX = 1; //!< solution status: fix +const int SOLQ_FLOAT = 2; //!< solution status: float +const int SOLQ_SBAS = 3; //!< solution status: SBAS +const int SOLQ_DGPS = 4; //!< solution status: DGPS/DGNSS +const int SOLQ_SINGLE = 5; //!< solution status: single +const int SOLQ_PPP = 6; //!< solution status: PPP +const int SOLQ_DR = 7; //!< solution status: dead reckoning +const int MAXSOLQ = 7; //!< max number of solution status + +const int TIMES_GPST = 0; //!< time system: gps time +const int TIMES_UTC = 1; //!< time system: utc +const int TIMES_JST = 2; //!< time system: jst + + +const double ERR_SAAS = 0.3; //!< saastamoinen model error std (m) +const double ERR_BRDCI = 0.5; //!< broadcast iono model error factor +const double ERR_CBIAS = 0.3; //!< code bias error std (m) +const double REL_HUMI = 0.7; //!< relative humidity for saastamoinen model +const double GAP_RESION = 120; //!< default gap to reset ionos parameters (ep) + +const int MAXFREQ = 7; //!< max NFREQ + +const int MAXLEAPS = 64; //!< max number of leap seconds table +const double DTTOL = 0.005; //!< tolerance of time difference (s) + +const int NFREQ = 3; //!< number of carrier frequencies +const int NFREQGLO = 2; //!< number of carrier frequencies of GLONASS +const int NEXOBS = 0; //!< number of extended obs codes +const int MAXANT = 64; //!< max length of station name/antenna type + +const int MINPRNGPS = 1; //!< min satellite PRN number of GPS +const int MAXPRNGPS = 32; //!< max satellite PRN number of GPS +const int NSATGPS = (MAXPRNGPS - MINPRNGPS + 1); //!< number of GPS satellites +const int NSYSGPS = 1; + +const int SYS_NONE = 0x00; //!< navigation system: none +const int SYS_GPS = 0x01; //!< navigation system: GPS +const int SYS_SBS = 0x02; //!< navigation system: SBAS +const int SYS_GLO = 0x04; //!< navigation system: GLONASS +const int SYS_GAL = 0x08; //!< navigation system: Galileo +const int SYS_QZS = 0x10; //!< navigation system: QZSS +const int SYS_BDS = 0x20; //!< navigation system: BeiDou +const int SYS_IRN = 0x40; //!< navigation system: IRNS +const int SYS_LEO = 0x80; //!< navigation system: LEO +const int SYS_ALL = 0xFF; //!< navigation system: all + + +#define ENAGLO +#ifdef ENAGLO +const int MINPRNGLO = 1; //!< min satellite slot number of GLONASS +const int MAXPRNGLO = 27; //!< max satellite slot number of GLONASS +const int NSATGLO = (MAXPRNGLO - MINPRNGLO + 1); //!< number of GLONASS satellites +const int NSYSGLO = 1; +#else +const int MINPRNGLO = 0; +const int MAXPRNGLO = 0; +const int NSATGLO = 0; +const int NSYSGLO = 0; +#endif + +/* +const int MINPRNGLO = 1; //!< min satellite slot number of GLONASS +const int MAXPRNGLO = 27; //!< max satellite slot number of GLONASS +const int NSATGLO = (MAXPRNGLO - MINPRNGLO + 1); //!< number of GLONASS satellites +const int NSYSGLO = 1; +*/ +const int MINPRNGAL = 1; //!< min satellite PRN number of Galileo +const int MAXPRNGAL = 36; //!< max satellite PRN number of Galileo +const int NSATGAL = (MAXPRNGAL - MINPRNGAL + 1); //!< number of Galileo satellites +const int NSYSGAL = 1; + +#ifdef ENAQZS +const int MINPRNQZS = 193; //!< min satellite PRN number of QZSS +const int MAXPRNQZS = 199; //!< max satellite PRN number of QZSS +const int MINPRNQZS_S = 183; //!< min satellite PRN number of QZSS SAIF +const int MAXPRNQZS_S = 189; //!< max satellite PRN number of QZSS SAIF +const int NSATQZS = (MAXPRNQZS - MINPRNQZS + 1); //!< number of QZSS satellites +const int NSYSQZS = 1; +#else +const int MINPRNQZS = 0; +const int MAXPRNQZS = 0; +const int MINPRNQZS_S = 0; +const int MAXPRNQZS_S = 0; +const int NSATQZS = 0; +const int NSYSQZS = 0; +#endif + +#ifdef ENABDS +const int MINPRNBDS = 1; //!< min satellite sat number of BeiDou +const int MAXPRNBDS = 35; //!< max satellite sat number of BeiDou +const int NSATBDS = (MAXPRNBDS - MINPRNCM + 1); //!< number of BeiDou satellites +const int NSYSBDS = 1; +#else +const int MINPRNBDS = 0; +const int MAXPRNBDS = 0; +const int NSATBDS = 0; +const int NSYSBDS = 0; +#endif + +#ifdef ENAIRN +const int MINPRNIRN = 1; //!< min satellite sat number of IRNSS +const int MAXPRNIRN = 7; //!< max satellite sat number of IRNSS +const int NSATIRN = (MAXPRNIRN - MINPRNIRN + 1); //!< number of IRNSS satellites +const int NSYSIRN = 1; +#else +const int MINPRNIRN = 0; +const int MAXPRNIRN = 0; +const int NSATIRN = 0; +const int NSYSIRN = 0; +#endif + +#ifdef ENALEO +const int MINPRNLEO = 1; //!< min satellite sat number of LEO +const int NSATLEO = 10; //!< max satellite sat number of LEO +const int NSATLEO = (MAXPRNLEO - MINPRNLEO + 1); //!< number of LEO satellites +const int NSYSLEO = 1; +#else +const int MINPRNLEO = 0; +const int MAXPRNLEO = 0; +const int NSATLEO = 0; +const int NSYSLEO = 0; +#endif + +const int NSYS = (NSYSGPS + NSYSGLO + NSYSGAL + NSYSQZS + NSYSBDS + NSYSIRN + NSYSLEO); //!< number of systems + +const int MINPRNSBS = 120; //!< min satellite PRN number of SBAS +const int MAXPRNSBS = 142; //!< max satellite PRN number of SBAS +const int NSATSBS = (MAXPRNSBS - MINPRNSBS + 1); //!< number of SBAS satellites + +const int MAXSAT = (NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATBDS + NSATIRN + NSATSBS + NSATLEO); + +const int MAXSTA = 255; + +#ifndef MAXOBS +const int MAXOBS = 64; //!< max number of obs in an epoch +#endif + +const int MAXRCV = 64; //!< max receiver number (1 to MAXRCV) +const int MAXOBSTYPE = 64; //!< max number of obs type in RINEX +const double MAXDTOE = 7200.0; //!< max time difference to GPS Toe (s) +const double MAXDTOE_QZS = 7200.0; //!< max time difference to QZSS Toe (s) +const double MAXDTOE_GAL = 10800.0; //!< max time difference to Galileo Toe (s) +const double MAXDTOE_BDS = 21600.0; //!< max time difference to BeiDou Toe (s) +const double MAXDTOE_GLO = 1800.0; //!< max time difference to GLONASS Toe (s) +const double MAXDTOE_SBS = 360.0; //!< max time difference to SBAS Toe (s) +const double MAXDTOE_S = 86400.0; //!< max time difference to ephem toe (s) for other +const double MAXGDOP = 300.0; //!< max GDOP + +const int MAXSBSURA = 8; //!< max URA of SBAS satellite +const int MAXBAND = 10; //!< max SBAS band of IGP +const int MAXNIGP = 201; //!< max number of IGP in SBAS band +const int MAXNGEO = 4; //!< max number of GEO satellites + +const int MAXSOLMSG = 8191; //!< max length of solution message +const int MAXERRMSG = 4096; //!< max length of error/warning message + +const int IONOOPT_OFF = 0; //!< ionosphere option: correction off +const int IONOOPT_BRDC = 1; //!< ionosphere option: broadcast model +const int IONOOPT_SBAS = 2; //!< ionosphere option: SBAS model +const int IONOOPT_IFLC = 3; //!< ionosphere option: L1/L2 or L1/L5 iono-free LC +const int IONOOPT_EST = 4; //!< ionosphere option: estimation +const int IONOOPT_TEC = 5; //!< ionosphere option: IONEX TEC model +const int IONOOPT_QZS = 6; //!< ionosphere option: QZSS broadcast model +const int IONOOPT_LEX = 7; //!< ionosphere option: QZSS LEX ionospehre +const int IONOOPT_STEC = 8; //!< ionosphere option: SLANT TEC model + +const int TROPOPT_OFF = 0; //!< troposphere option: correction off +const int TROPOPT_SAAS = 1; //!< troposphere option: Saastamoinen model +const int TROPOPT_SBAS = 2; //!< troposphere option: SBAS model +const int TROPOPT_EST = 3; //!< troposphere option: ZTD estimation +const int TROPOPT_ESTG = 4; //!< troposphere option: ZTD+grad estimation +const int TROPOPT_COR = 5; //!< troposphere option: ZTD correction +const int TROPOPT_CORG = 6; //!< troposphere option: ZTD+grad correction + + +const int EPHOPT_BRDC = 0; //!< ephemeris option: broadcast ephemeris +const int EPHOPT_PREC = 1; //!< ephemeris option: precise ephemeris +const int EPHOPT_SBAS = 2; //!< ephemeris option: broadcast + SBAS +const int EPHOPT_SSRAPC = 3; //!< ephemeris option: broadcast + SSR_APC +const int EPHOPT_SSRCOM = 4; //!< ephemeris option: broadcast + SSR_COM +const int EPHOPT_LEX = 5; //!< ephemeris option: QZSS LEX ephemeris + +const double EFACT_GPS = 1.0; //!< error factor: GPS +const double EFACT_GLO = 1.5; //!< error factor: GLONASS +const double EFACT_GAL = 1.0; //!< error factor: Galileo +const double EFACT_QZS = 1.0; //!< error factor: QZSS +const double EFACT_BDS = 1.0; //!< error factor: BeiDou +const double EFACT_IRN = 1.5; //!< error factor: IRNSS +const double EFACT_SBS = 3.0; //!< error factor: SBAS + +const int MAXEXFILE = 1024; //!< max number of expanded files +const double MAXSBSAGEF = 30.0; //!< max age of SBAS fast correction (s) +const double MAXSBSAGEL = 1800.0; //!< max age of SBAS long term corr (s) + +const int ARMODE_OFF = 0; //!< AR mode: off +const int ARMODE_CONT = 1; //!< AR mode: continuous +const int ARMODE_INST = 2; //!< AR mode: instantaneous +const int ARMODE_FIXHOLD = 3; //!< AR mode: fix and hold +const int ARMODE_PPPAR = 4; //!< AR mode: PPP-AR +const int ARMODE_PPPAR_ILS = 5; //!< AR mode: AR mode: PPP-AR ILS +const int ARMODE_WLNL = 6; +const int ARMODE_TCAR = 7; + + +const int POSOPT_RINEX = 3; //!< pos option: rinex header pos +const int MAXSTRPATH = 1024; //!< max length of stream path +const int MAXSTRMSG = 1024; //!< max length of stream message + +typedef void fatalfunc_t(const char *); //!< fatal callback function type + +#define STR_MODE_R 0x1 /* stream mode: read */ +#define STR_MODE_W 0x2 /* stream mode: write */ +#define STR_MODE_RW 0x3 /* stream mode: read/write */ + +#define STR_NONE 0 /* stream type: none */ +#define STR_SERIAL 1 /* stream type: serial */ +#define STR_FILE 2 /* stream type: file */ +#define STR_TCPSVR 3 /* stream type: TCP server */ +#define STR_TCPCLI 4 /* stream type: TCP client */ +#define STR_UDP 5 /* stream type: UDP stream */ +#define STR_NTRIPSVR 6 /* stream type: NTRIP server */ +#define STR_NTRIPCLI 7 /* stream type: NTRIP client */ +#define STR_FTP 8 /* stream type: ftp */ +#define STR_HTTP 9 /* stream type: http */ + +#define NP_PPP(opt) ((opt)->dynamics ? 9 : 3) /* number of pos solution */ +#define IC_PPP(s, opt) (NP_PPP(opt) + (s)) /* state index of clocks (s=0:gps,1:glo) */ +#define IT_PPP(opt) (IC_PPP(0, opt) + NSYS) /* state index of tropos */ +#define NR_PPP(opt) (IT_PPP(opt) + ((opt)->tropopt < TROPOPT_EST ? 0 : ((opt)->tropopt == TROPOPT_EST ? 1 : 3))) /* number of solutions */ +#define IB_PPP(s, opt) (NR_PPP(opt) + (s)-1) /* state index of phase bias */ +#define NX_PPP(opt) (IB_PPP(MAXSAT, opt) + 1) /* number of estimated states */ + +#define NF_RTK(opt) ((opt)->ionoopt == IONOOPT_IFLC ? 1 : (opt)->nf) +#define NP_RTK(opt) ((opt)->dynamics == 0 ? 3 : 9) +#define NI_RTK(opt) ((opt)->ionoopt != IONOOPT_EST ? 0 : MAXSAT) +#define NT_RTK(opt) ((opt)->tropopt < TROPOPT_EST ? 0 : ((opt)->tropopt < TROPOPT_ESTG ? 2 : 6)) +#define NL_RTK(opt) ((opt)->glomodear != 2 ? 0 : NFREQGLO) +#define NB_RTK(opt) ((opt)->mode <= PMODE_DGPS ? 0 : MAXSAT * NF_RTK(opt)) +#define NR_RTK(opt) (NP_RTK(opt) + NI_RTK(opt) + NT_RTK(opt) + NL_RTK(opt)) +#define NX_RTK(opt) (NR_RTK(opt) + NB_RTK(opt)) + +typedef struct +{ /* time struct */ + time_t time; /* time (s) expressed by standard time_t */ + double sec; /* fraction of second under 1 s */ +} gtime_t; + + +typedef struct +{ /* observation data record */ + gtime_t time; /* receiver sampling time (GPST) */ + unsigned char sat, rcv; /* satellite/receiver number */ + unsigned char SNR[NFREQ + NEXOBS]; /* signal strength (0.25 dBHz) */ + unsigned char LLI[NFREQ + NEXOBS]; /* loss of lock indicator */ + unsigned char code[NFREQ + NEXOBS]; /* code indicator (CODE_???) */ + double L[NFREQ + NEXOBS]; /* observation data carrier-phase (cycle) */ + double P[NFREQ + NEXOBS]; /* observation data pseudorange (m) */ + float D[NFREQ + NEXOBS]; /* observation data doppler frequency (Hz) */ +} obsd_t; + + +typedef struct +{ /* observation data */ + int n, nmax; /* number of obervation data/allocated */ + obsd_t *data; /* observation data records */ +} obs_t; + + +typedef struct +{ /* earth rotation parameter data type */ + double mjd; /* mjd (days) */ + double xp, yp; /* pole offset (rad) */ + double xpr, ypr; /* pole offset rate (rad/day) */ + double ut1_utc; /* ut1-utc (s) */ + double lod; /* length of day (s/day) */ +} erpd_t; + + +typedef struct +{ /* earth rotation parameter type */ + int n, nmax; /* number and max number of data */ + erpd_t *data; /* earth rotation parameter data */ +} erp_t; + + +typedef struct +{ /* antenna parameter type */ + int sat; /* satellite number (0:receiver) */ + char type[MAXANT]; /* antenna type */ + char code[MAXANT]; /* serial number or satellite code */ + gtime_t ts, te; /* valid time start and end */ + double off[NFREQ][3]; /* phase center offset e/n/u or x/y/z (m) */ + double var[NFREQ][19]; /* phase center variation (m) */ + /* el=90,85,...,0 or nadir=0,1,2,3,... (deg) */ +} pcv_t; + + +typedef struct +{ /* antenna parameters type */ + int n, nmax; /* number of data/allocated */ + pcv_t *pcv; /* antenna parameters data */ +} pcvs_t; + + +typedef struct +{ /* almanac type */ + int sat; /* satellite number */ + int svh; /* sv health (0:ok) */ + int svconf; /* as and sv config */ + int week; /* GPS/QZS: gps week, GAL: galileo week */ + gtime_t toa; /* Toa */ + /* SV orbit parameters */ + double A, e, i0, OMG0, omg, M0, OMGd; + double toas; /* Toa (s) in week */ + double f0, f1; /* SV clock parameters (af0,af1) */ +} alm_t; + + +typedef struct +{ /* GPS/QZS/GAL broadcast ephemeris type */ + int sat; /* satellite number */ + int iode, iodc; /* IODE,IODC */ + int sva; /* SV accuracy (URA index) */ + int svh; /* SV health (0:ok) */ + int week; /* GPS/QZS: gps week, GAL: galileo week */ + int code; /* GPS/QZS: code on L2, GAL/BDS: data sources */ + int flag; /* GPS/QZS: L2 P data flag, BDS: nav type */ + gtime_t toe, toc, ttr; /* Toe,Toc,T_trans */ + /* SV orbit parameters */ + double A, e, i0, OMG0, omg, M0, deln, OMGd, idot; + double crc, crs, cuc, cus, cic, cis; + double toes; /* Toe (s) in week */ + double fit; /* fit interval (h) */ + double f0, f1, f2; /* SV clock parameters (af0,af1,af2) */ + double tgd[4]; /* group delay parameters */ + /* GPS/QZS:tgd[0]=TGD */ + /* GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 */ + /* BDS :tgd[0]=BGD1,tgd[1]=BGD2 */ + double isc[4]; /* GPS :isc[0]=ISCL1, isc[1]=ISCL2, isc[2]=ISCL5I, isc[3]=ISCL5Q */ + double Adot, ndot; /* Adot,ndot for CNAV */ +} eph_t; + + +typedef struct +{ /* GLONASS broadcast ephemeris type */ + int sat; /* satellite number */ + int iode; /* IODE (0-6 bit of tb field) */ + int frq; /* satellite frequency number */ + int svh, sva, age; /* satellite health, accuracy, age of operation */ + gtime_t toe; /* epoch of epherides (gpst) */ + gtime_t tof; /* message frame time (gpst) */ + double pos[3]; /* satellite position (ecef) (m) */ + double vel[3]; /* satellite velocity (ecef) (m/s) */ + double acc[3]; /* satellite acceleration (ecef) (m/s^2) */ + double taun, gamn; /* SV clock bias (s)/relative freq bias */ + double dtaun; /* delay between L1 and L2 (s) */ +} geph_t; + + +typedef struct +{ /* precise ephemeris type */ + gtime_t time; /* time (GPST) */ + int index; /* ephemeris index for multiple files */ + double pos[MAXSAT][4]; /* satellite position/clock (ecef) (m|s) */ + float std[MAXSAT][4]; /* satellite position/clock std (m|s) */ + double vel[MAXSAT][4]; /* satellite velocity/clk-rate (m/s|s/s) */ + float vst[MAXSAT][4]; /* satellite velocity/clk-rate std (m/s|s/s) */ + float cov[MAXSAT][3]; /* satellite position covariance (m^2) */ + float vco[MAXSAT][3]; /* satellite velocity covariance (m^2) */ +} peph_t; + + +typedef struct +{ /* precise clock type */ + gtime_t time; /* time (GPST) */ + int index; /* clock index for multiple files */ + double clk[MAXSAT][1]; /* satellite clock (s) */ + float std[MAXSAT][1]; /* satellite clock std (s) */ +} pclk_t; + + +typedef struct +{ /* SBAS ephemeris type */ + int sat; /* satellite number */ + gtime_t t0; /* reference epoch time (GPST) */ + gtime_t tof; /* time of message frame (GPST) */ + int sva; /* SV accuracy (URA index) */ + int svh; /* SV health (0:ok) */ + double pos[3]; /* satellite position (m) (ecef) */ + double vel[3]; /* satellite velocity (m/s) (ecef) */ + double acc[3]; /* satellite acceleration (m/s^2) (ecef) */ + double af0, af1; /* satellite clock-offset/drift (s,s/s) */ +} seph_t; + + +typedef struct +{ /* norad two line element data type */ + char name[32]; /* common name */ + char alias[32]; /* alias name */ + char satno[16]; /* satellite catalog number */ + char satclass; /* classification */ + char desig[16]; /* international designator */ + gtime_t epoch; /* element set epoch (UTC) */ + double ndot; /* 1st derivative of mean motion */ + double nddot; /* 2st derivative of mean motion */ + double bstar; /* B* drag term */ + int etype; /* element set type */ + int eleno; /* element number */ + double inc; /* orbit inclination (deg) */ + double OMG; /* right ascension of ascending node (deg) */ + double ecc; /* eccentricity */ + double omg; /* argument of perigee (deg) */ + double M; /* mean anomaly (deg) */ + double n; /* mean motion (rev/day) */ + int rev; /* revolution number at epoch */ +} tled_t; + + +typedef struct +{ /* norad two line element type */ + int n, nmax; /* number/max number of two line element data */ + tled_t *data; /* norad two line element data */ +} tle_t; + + +typedef struct +{ /* TEC grid type */ + gtime_t time; /* epoch time (GPST) */ + int ndata[3]; /* TEC grid data size {nlat,nlon,nhgt} */ + double rb; /* earth radius (km) */ + double lats[3]; /* latitude start/interval (deg) */ + double lons[3]; /* longitude start/interval (deg) */ + double hgts[3]; /* heights start/interval (km) */ + double *data; /* TEC grid data (tecu) */ + float *rms; /* RMS values (tecu) */ +} tec_t; + + +typedef struct +{ /* satellite fcb data type */ + gtime_t ts, te; /* start/end time (GPST) */ + double bias[MAXSAT][3]; /* fcb value (cyc) */ + double std[MAXSAT][3]; /* fcb std-dev (cyc) */ +} fcbd_t; + + +typedef struct +{ /* SBAS message type */ + int week, tow; /* receiption time */ + int prn; /* SBAS satellite PRN number */ + unsigned char msg[29]; /* SBAS message (226bit) padded by 0 */ +} sbsmsg_t; + + +typedef struct +{ /* SBAS messages type */ + int n, nmax; /* number of SBAS messages/allocated */ + sbsmsg_t *msgs; /* SBAS messages */ +} sbs_t; + + +typedef struct +{ /* SBAS fast correction type */ + gtime_t t0; /* time of applicability (TOF) */ + double prc; /* pseudorange correction (PRC) (m) */ + double rrc; /* range-rate correction (RRC) (m/s) */ + double dt; /* range-rate correction delta-time (s) */ + int iodf; /* IODF (issue of date fast corr) */ + short udre; /* UDRE+1 */ + short ai; /* degradation factor indicator */ +} sbsfcorr_t; + + +typedef struct +{ /* SBAS long term satellite error correction type */ + gtime_t t0; /* correction time */ + int iode; /* IODE (issue of date ephemeris) */ + double dpos[3]; /* delta position (m) (ecef) */ + double dvel[3]; /* delta velocity (m/s) (ecef) */ + double daf0, daf1; /* delta clock-offset/drift (s,s/s) */ +} sbslcorr_t; + + +typedef struct +{ /* SBAS satellite correction type */ + int sat; /* satellite number */ + sbsfcorr_t fcorr; /* fast correction */ + sbslcorr_t lcorr; /* long term correction */ +} sbssatp_t; + + +typedef struct +{ /* SBAS satellite corrections type */ + int iodp; /* IODP (issue of date mask) */ + int nsat; /* number of satellites */ + int tlat; /* system latency (s) */ + sbssatp_t sat[MAXSAT]; /* satellite correction */ +} sbssat_t; + + +typedef struct +{ /* SBAS ionospheric correction type */ + gtime_t t0; /* correction time */ + short lat, lon; /* latitude/longitude (deg) */ + short give; /* GIVI+1 */ + float delay; /* vertical delay estimate (m) */ +} sbsigp_t; + + +typedef struct +{ /* IGP band type */ + short x; /* longitude/latitude (deg) */ + const short *y; /* latitudes/longitudes (deg) */ + unsigned char bits; /* IGP mask start bit */ + unsigned char bite; /* IGP mask end bit */ +} sbsigpband_t; + + +typedef struct +{ /* SBAS ionospheric corrections type */ + int iodi; /* IODI (issue of date ionos corr) */ + int nigp; /* number of igps */ + sbsigp_t igp[MAXNIGP]; /* ionospheric correction */ +} sbsion_t; + + +typedef struct +{ /* DGPS/GNSS correction type */ + gtime_t t0; /* correction time */ + double prc; /* pseudorange correction (PRC) (m) */ + double rrc; /* range rate correction (RRC) (m/s) */ + int iod; /* issue of data (IOD) */ + double udre; /* UDRE */ +} dgps_t; + + +typedef struct +{ /* SSR correction type */ + gtime_t t0[6]; /* epoch time (GPST) {eph,clk,hrclk,ura,bias,pbias} */ + double udi[6]; /* SSR update interval (s) */ + int iod[6]; /* iod ssr {eph,clk,hrclk,ura,bias,pbias} */ + int iode; /* issue of data */ + int iodcrc; /* issue of data crc for beidou/sbas */ + int ura; /* URA indicator */ + int refd; /* sat ref datum (0:ITRF,1:regional) */ + double deph[3]; /* delta orbit {radial,along,cross} (m) */ + double ddeph[3]; /* dot delta orbit {radial,along,cross} (m/s) */ + double dclk[3]; /* delta clock {c0,c1,c2} (m,m/s,m/s^2) */ + double hrclk; /* high-rate clock corection (m) */ + float cbias[MAXCODE]; /* code biases (m) */ + double pbias[MAXCODE]; /* phase biases (m) */ + float stdpb[MAXCODE]; /* std-dev of phase biases (m) */ + double yaw_ang, yaw_rate; /* yaw angle and yaw rate (deg,deg/s) */ + unsigned char update; /* update flag (0:no update,1:update) */ +} ssr_t; + + +typedef struct +{ /* QZSS LEX message type */ + int prn; /* satellite PRN number */ + int type; /* message type */ + int alert; /* alert flag */ + unsigned char stat; /* signal tracking status */ + unsigned char snr; /* signal C/N0 (0.25 dBHz) */ + unsigned int ttt; /* tracking time (ms) */ + unsigned char msg[212]; /* LEX message data part 1695 bits */ +} lexmsg_t; + + +typedef struct +{ /* QZSS LEX messages type */ + int n, nmax; /* number of LEX messages and allocated */ + lexmsg_t *msgs; /* LEX messages */ +} lex_t; + + +typedef struct +{ /* QZSS LEX ephemeris type */ + gtime_t toe; /* epoch time (GPST) */ + gtime_t tof; /* message frame time (GPST) */ + int sat; /* satellite number */ + unsigned char health; /* signal health (L1,L2,L1C,L5,LEX) */ + unsigned char ura; /* URA index */ + double pos[3]; /* satellite position (m) */ + double vel[3]; /* satellite velocity (m/s) */ + double acc[3]; /* satellite acceleration (m/s2) */ + double jerk[3]; /* satellite jerk (m/s3) */ + double af0, af1; /* satellite clock bias and drift (s,s/s) */ + double tgd; /* TGD */ + double isc[8]; /* ISC */ +} lexeph_t; + + +typedef struct +{ /* QZSS LEX ionosphere correction type */ + gtime_t t0; /* epoch time (GPST) */ + double tspan; /* valid time span (s) */ + double pos0[2]; /* reference position {lat,lon} (rad) */ + double coef[3][2]; /* coefficients lat x lon (3 x 2) */ +} lexion_t; + + +typedef struct +{ /* stec data type */ + gtime_t time; /* time (GPST) */ + unsigned char sat; /* satellite number */ + double ion; /* slant ionos delay (m) */ + float std; /* std-dev (m) */ + float azel[2]; /* azimuth/elevation (rad) */ + unsigned char flag; /* fix flag */ +} stec_t; + + +typedef struct +{ /* trop data type */ + gtime_t time; /* time (GPST) */ + double trp[3]; /* zenith tropos delay/gradient (m) */ + float std[3]; /* std-dev (m) */ +} trop_t; + + +typedef struct +{ /* ppp corrections type */ + int nsta; /* number of stations */ + char stas[MAXSTA][8]; /* station names */ + double rr[MAXSTA][3]; /* station ecef positions (m) */ + int ns[MAXSTA], nsmax[MAXSTA]; /* number of stec data */ + int nt[MAXSTA], ntmax[MAXSTA]; /* number of trop data */ + stec_t *stec[MAXSTA]; /* stec data */ + trop_t *trop[MAXSTA]; /* trop data */ +} pppcorr_t; + + +typedef struct +{ /* navigation data type */ + int n, nmax; /* number of broadcast ephemeris */ + int ng, ngmax; /* number of glonass ephemeris */ + int ns, nsmax; /* number of sbas ephemeris */ + int ne, nemax; /* number of precise ephemeris */ + int nc, ncmax; /* number of precise clock */ + int na, namax; /* number of almanac data */ + int nt, ntmax; /* number of tec grid data */ + int nf, nfmax; /* number of satellite fcb data */ + eph_t *eph; /* GPS/QZS/GAL ephemeris */ + geph_t *geph; /* GLONASS ephemeris */ + seph_t *seph; /* SBAS ephemeris */ + peph_t *peph; /* precise ephemeris */ + pclk_t *pclk; /* precise clock */ + alm_t *alm; /* almanac data */ + tec_t *tec; /* tec grid data */ + fcbd_t *fcb; /* satellite fcb data */ + erp_t erp; /* earth rotation parameters */ + double utc_gps[4]; /* GPS delta-UTC parameters {A0,A1,T,W} */ + double utc_glo[4]; /* GLONASS UTC GPS time parameters */ + double utc_gal[4]; /* Galileo UTC GPS time parameters */ + double utc_qzs[4]; /* QZS UTC GPS time parameters */ + double utc_cmp[4]; /* BeiDou UTC parameters */ + double utc_irn[4]; /* IRNSS UTC parameters */ + double utc_sbs[4]; /* SBAS UTC parameters */ + double ion_gps[8]; /* GPS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + double ion_gal[4]; /* Galileo iono model parameters {ai0,ai1,ai2,0} */ + double ion_qzs[8]; /* QZSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + double ion_cmp[8]; /* BeiDou iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + double ion_irn[8]; /* IRNSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + int leaps; /* leap seconds (s) */ + double lam[MAXSAT][NFREQ]; /* carrier wave lengths (m) */ + double cbias[MAXSAT][3]; /* satellite dcb (0:p1-p2,1:p1-c1,2:p2-c2) (m) */ + double rbias[MAXRCV][2][3]; /* receiver dcb (0:p1-p2,1:p1-c1,2:p2-c2) (m) */ + double wlbias[MAXSAT]; /* wide-lane bias (cycle) */ + double glo_cpbias[4]; /* glonass code-phase bias {1C,1P,2C,2P} (m) */ + char glo_fcn[MAXPRNGLO + 1]; /* glonass frequency channel number + 8 */ + pcv_t pcvs[MAXSAT]; /* satellite antenna pcv */ + sbssat_t sbssat; /* SBAS satellite corrections */ + sbsion_t sbsion[MAXBAND + 1]; /* SBAS ionosphere corrections */ + dgps_t dgps[MAXSAT]; /* DGPS corrections */ + ssr_t ssr[MAXSAT]; /* SSR corrections */ + lexeph_t lexeph[MAXSAT]; /* LEX ephemeris */ + lexion_t lexion; /* LEX ionosphere correction */ + pppcorr_t pppcorr; /* ppp corrections */ +} nav_t; + + +typedef struct +{ /* station parameter type */ + char name[MAXANT]; /* marker name */ + char marker[MAXANT]; /* marker number */ + char antdes[MAXANT]; /* antenna descriptor */ + char antsno[MAXANT]; /* antenna serial number */ + char rectype[MAXANT]; /* receiver type descriptor */ + char recver[MAXANT]; /* receiver firmware version */ + char recsno[MAXANT]; /* receiver serial number */ + int antsetup; /* antenna setup id */ + int itrf; /* ITRF realization year */ + int deltype; /* antenna delta type (0:enu,1:xyz) */ + double pos[3]; /* station position (ecef) (m) */ + double del[3]; /* antenna position delta (e/n/u or x/y/z) (m) */ + double hgt; /* antenna height (m) */ +} sta_t; + + +typedef struct +{ /* solution type */ + gtime_t time; /* time (GPST) */ + double rr[6]; /* position/velocity (m|m/s) */ + /* {x,y,z,vx,vy,vz} or {e,n,u,ve,vn,vu} */ + float qr[6]; /* position variance/covariance (m^2) */ + /* {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} or */ + /* {c_ee,c_nn,c_uu,c_en,c_nu,c_ue} */ + double dtr[6]; /* receiver clock bias to time systems (s) */ + unsigned char type; /* type (0:xyz-ecef,1:enu-baseline) */ + unsigned char stat; /* solution status (SOLQ_???) */ + unsigned char ns; /* number of valid satellites */ + float age; /* age of differential (s) */ + float ratio; /* AR ratio factor for validation */ + float thres; /* AR ratio threshold for validation */ +} sol_t; + + +typedef struct +{ /* solution buffer type */ + int n, nmax; /* number of solution/max number of buffer */ + int cyclic; /* cyclic buffer flag */ + int start, end; /* start/end index */ + gtime_t time; /* current solution time */ + sol_t *data; /* solution data */ + double rb[3]; /* reference position {x,y,z} (ecef) (m) */ + unsigned char buff[MAXSOLMSG + 1]; /* message buffer */ + int nb; /* number of byte in message buffer */ +} solbuf_t; + + +typedef struct +{ /* solution status type */ + gtime_t time; /* time (GPST) */ + unsigned char sat; /* satellite number */ + unsigned char frq; /* frequency (1:L1,2:L2,...) */ + float az, el; /* azimuth/elevation angle (rad) */ + float resp; /* pseudorange residual (m) */ + float resc; /* carrier-phase residual (m) */ + unsigned char flag; /* flags: (vsat<<5)+(slip<<3)+fix */ + unsigned char snr; /* signal strength (0.25 dBHz) */ + unsigned short lock; /* lock counter */ + unsigned short outc; /* outage counter */ + unsigned short slipc; /* slip counter */ + unsigned short rejc; /* reject counter */ +} solstat_t; + + +typedef struct +{ /* solution status buffer type */ + int n, nmax; /* number of solution/max number of buffer */ + solstat_t *data; /* solution status data */ +} solstatbuf_t; + + +typedef struct +{ /* RTCM control struct type */ + int staid; /* station id */ + int stah; /* station health */ + int seqno; /* sequence number for rtcm 2 or iods msm */ + int outtype; /* output message type */ + gtime_t time; /* message time */ + gtime_t time_s; /* message start time */ + obs_t obs; /* observation data (uncorrected) */ + nav_t nav; /* satellite ephemerides */ + sta_t sta; /* station parameters */ + dgps_t *dgps; /* output of dgps corrections */ + ssr_t ssr[MAXSAT]; /* output of ssr corrections */ + char msg[128]; /* special message */ + char msgtype[256]; /* last message type */ + char msmtype[6][128]; /* msm signal types */ + int obsflag; /* obs data complete flag (1:ok,0:not complete) */ + int ephsat; /* update satellite of ephemeris */ + double cp[MAXSAT][NFREQ + NEXOBS]; /* carrier-phase measurement */ + unsigned short lock[MAXSAT][NFREQ + NEXOBS]; /* lock time */ + unsigned short loss[MAXSAT][NFREQ + NEXOBS]; /* loss of lock count */ + gtime_t lltime[MAXSAT][NFREQ + NEXOBS]; /* last lock time */ + int nbyte; /* number of bytes in message buffer */ + int nbit; /* number of bits in word buffer */ + int len; /* message length (bytes) */ + unsigned char buff[1200]; /* message buffer */ + unsigned int word; /* word buffer for rtcm 2 */ + unsigned int nmsg2[100]; /* message count of RTCM 2 (1-99:1-99,0:other) */ + unsigned int nmsg3[400]; /* message count of RTCM 3 (1-299:1001-1299,300-399:2000-2099,0:ohter) */ + char opt[256]; /* RTCM dependent options */ +} rtcm_t; + + +typedef struct +{ /* download url type */ + char type[32]; /* data type */ + char path[1024]; /* url path */ + char dir[1024]; /* local directory */ + double tint; /* time interval (s) */ +} url_t; + + +typedef struct +{ /* option type */ + const char *name; /* option name */ + int format; /* option format (0:int,1:double,2:string,3:enum) */ + void *var; /* pointer to option variable */ + const char *comment; /* option comment/enum labels/unit */ +} opt_t; + + +typedef struct +{ /* extended receiver error model */ + int ena[4]; /* model enabled */ + double cerr[4][NFREQ * 2]; /* code errors (m) */ + double perr[4][NFREQ * 2]; /* carrier-phase errors (m) */ + double gpsglob[NFREQ]; /* gps-glonass h/w bias (m) */ + double gloicb[NFREQ]; /* glonass interchannel bias (m/fn) */ +} exterr_t; + + +typedef struct +{ /* SNR mask type */ + int ena[2]; /* enable flag {rover,base} */ + double mask[NFREQ][9]; /* mask (dBHz) at 5,10,...85 deg */ +} snrmask_t; + + +typedef struct +{ /* processing options type */ + int mode; /* positioning mode (PMODE_???) */ + int soltype; /* solution type (0:forward,1:backward,2:combined) */ + int nf; /* number of frequencies (1:L1,2:L1+L2,3:L1+L2+L5) */ + int navsys; /* navigation system */ + double elmin; /* elevation mask angle (rad) */ + snrmask_t snrmask; /* SNR mask */ + int sateph; /* satellite ephemeris/clock (EPHOPT_???) */ + int modear; /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + int glomodear; /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */ + int bdsmodear; /* BeiDou AR mode (0:off,1:on) */ + int maxout; /* obs outage count to reset bias */ + int minlock; /* min lock count to fix ambiguity */ + int minfix; /* min fix count to hold ambiguity */ + int armaxiter; /* max iteration to resolve ambiguity */ + int ionoopt; /* ionosphere option (IONOOPT_???) */ + int tropopt; /* troposphere option (TROPOPT_???) */ + int dynamics; /* dynamics model (0:none,1:velociy,2:accel) */ + int tidecorr; /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */ + int niter; /* number of filter iteration */ + int codesmooth; /* code smoothing window size (0:none) */ + int intpref; /* interpolate reference obs (for post mission) */ + int sbascorr; /* SBAS correction options */ + int sbassatsel; /* SBAS satellite selection (0:all) */ + int rovpos; /* rover position for fixed mode */ + int refpos; /* base position for relative mode */ + /* (0:pos in prcopt, 1:average of single pos, */ + /* 2:read from file, 3:rinex header, 4:rtcm pos) */ + double eratio[NFREQ]; /* code/phase error ratio */ + double err[5]; /* measurement error factor */ + /* [0]:reserved */ + /* [1-3]:error factor a/b/c of phase (m) */ + /* [4]:doppler frequency (hz) */ + double std[3]; /* initial-state std [0]bias,[1]iono [2]trop */ + double prn[6]; /* process-noise std [0]bias,[1]iono [2]trop [3]acch [4]accv [5] pos */ + double sclkstab; /* satellite clock stability (sec/sec) */ + double thresar[8]; /* AR validation threshold */ + double elmaskar; /* elevation mask of AR for rising satellite (deg) */ + double elmaskhold; /* elevation mask to hold ambiguity (deg) */ + double thresslip; /* slip threshold of geometry-free phase (m) */ + double maxtdiff; /* max difference of time (sec) */ + double maxinno; /* reject threshold of innovation (m) */ + double maxgdop; /* reject threshold of gdop */ + double baseline[2]; /* baseline length constraint {const,sigma} (m) */ + double ru[3]; /* rover position for fixed mode {x,y,z} (ecef) (m) */ + double rb[3]; /* base position for relative mode {x,y,z} (ecef) (m) */ + char anttype[2][MAXANT]; /* antenna types {rover,base} */ + double antdel[2][3]; /* antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */ + pcv_t pcvr[2]; /* receiver antenna parameters {rov,base} */ + unsigned char exsats[MAXSAT]; /* excluded satellites (1:excluded,2:included) */ + int maxaveep; /* max averaging epoches */ + int initrst; /* initialize by restart */ + int outsingle; /* output single by dgps/float/fix/ppp outage */ + char rnxopt[2][256]; /* rinex options {rover,base} */ + int posopt[6]; /* positioning options */ + int syncsol; /* solution sync mode (0:off,1:on) */ + double odisp[2][6 * 11]; /* ocean tide loading parameters {rov,base} */ + exterr_t exterr; /* extended receiver error model */ + int freqopt; /* disable L2-AR */ + char pppopt[256]; /* ppp option */ +} prcopt_t; + + +typedef struct +{ /* solution options type */ + int posf; /* solution format (SOLF_???) */ + int times; /* time system (TIMES_???) */ + int timef; /* time format (0:sssss.s,1:yyyy/mm/dd hh:mm:ss.s) */ + int timeu; /* time digits under decimal point */ + int degf; /* latitude/longitude format (0:ddd.ddd,1:ddd mm ss) */ + int outhead; /* output header (0:no,1:yes) */ + int outopt; /* output processing options (0:no,1:yes) */ + int datum; /* datum (0:WGS84,1:Tokyo) */ + int height; /* height (0:ellipsoidal,1:geodetic) */ + int geoid; /* geoid model (0:EGM96,1:JGD2000) */ + int solstatic; /* solution of static mode (0:all,1:single) */ + int sstat; /* solution statistics level (0:off,1:states,2:residuals) */ + int trace; /* debug trace level (0:off,1-5:debug) */ + double nmeaintv[2]; /* nmea output interval (s) (<0:no,0:all) */ + /* nmeaintv[0]:gprmc,gpgga,nmeaintv[1]:gpgsv */ + char sep[64]; /* field separator */ + char prog[64]; /* program name */ + double maxsolstd; /* max std-dev for solution output (m) (0:all) */ +} solopt_t; + + +typedef struct +{ /* satellite status type */ + unsigned char sys; /* navigation system */ + unsigned char vs; /* valid satellite flag single */ + double azel[2]; /* azimuth/elevation angles {az,el} (rad) */ + double resp[NFREQ]; /* residuals of pseudorange (m) */ + double resc[NFREQ]; /* residuals of carrier-phase (m) */ + unsigned char vsat[NFREQ]; /* valid satellite flag */ + unsigned char snr[NFREQ]; /* signal strength (0.25 dBHz) */ + unsigned char fix[NFREQ]; /* ambiguity fix flag (1:fix,2:float,3:hold) */ + unsigned char slip[NFREQ]; /* cycle-slip flag */ + unsigned char half[NFREQ]; /* half-cycle valid flag */ + int lock[NFREQ]; /* lock counter of phase */ + unsigned int outc[NFREQ]; /* obs outage counter of phase */ + unsigned int slipc[NFREQ]; /* cycle-slip counter */ + unsigned int rejc[NFREQ]; /* reject counter */ + double gf; /* geometry-free phase L1-L2 (m) */ + double gf2; /* geometry-free phase L1-L5 (m) */ + double mw; /* MW-LC (m) */ + double phw; /* phase windup (cycle) */ + gtime_t pt[2][NFREQ]; /* previous carrier-phase time */ + double ph[2][NFREQ]; /* previous carrier-phase observable (cycle) */ +} ssat_t; + + +typedef struct +{ /* ambiguity control type */ + gtime_t epoch[4]; /* last epoch */ + int n[4]; /* number of epochs */ + double LC[4]; /* linear combination average */ + double LCv[4]; /* linear combination variance */ + int fixcnt; /* fix count */ + char flags[MAXSAT]; /* fix flags */ +} ambc_t; + + +typedef struct +{ /* RTK control/result type */ + sol_t sol; /* RTK solution */ + double rb[6]; /* base position/velocity (ecef) (m|m/s) */ + int nx, na; /* number of float states/fixed states */ + double tt; /* time difference between current and previous (s) */ + double *x, *P; /* float states and their covariance */ + double *xa, *Pa; /* fixed states and their covariance */ + int nfix; /* number of continuous fixes of ambiguity */ + ambc_t ambc[MAXSAT]; /* ambiguity control */ + ssat_t ssat[MAXSAT]; /* satellite status */ + int neb; /* bytes in error message buffer */ + char errbuf[MAXERRMSG]; /* error message buffer */ + prcopt_t opt; /* processing options */ +} rtk_t; + + +typedef struct half_cyc_tag +{ /* half-cycle correction list type */ + unsigned char sat; /* satellite number */ + unsigned char freq; /* frequency number (0:L1,1:L2,2:L5) */ + unsigned char valid; /* half-cycle valid flag */ + char corr; /* half-cycle corrected (x 0.5 cyc) */ + gtime_t ts, te; /* time start, time end */ + struct half_cyc_tag *next; /* pointer to next correction */ +} half_cyc_t; + + +typedef struct +{ /* stream type */ + int type; /* type (STR_???) */ + int mode; /* mode (STR_MODE_?) */ + int state; /* state (-1:error,0:close,1:open) */ + unsigned int inb, inr; /* input bytes/rate */ + unsigned int outb, outr; /* output bytes/rate */ + unsigned int tick, tact; /* tick/active tick */ + unsigned int inbt, outbt; /* input/output bytes at tick */ + lock_t lock; /* lock flag */ + void *port; /* type dependent port control struct */ + char path[MAXSTRPATH]; /* stream path */ + char msg[MAXSTRMSG]; /* stream message */ +} stream_t; + + +typedef struct +{ /* serial control type */ + dev_t dev; /* serial device */ + int error; /* error state */ +} serial_t; + + +typedef struct +{ /* file control type */ + FILE *fp; /* file pointer */ + FILE *fp_tag; /* file pointer of tag file */ + FILE *fp_tmp; /* temporary file pointer for swap */ + FILE *fp_tag_tmp; /* temporary file pointer of tag file for swap */ + char path[MAXSTRPATH]; /* file path */ + char openpath[MAXSTRPATH]; /* open file path */ + int mode; /* file mode */ + int timetag; /* time tag flag (0:off,1:on) */ + int repmode; /* replay mode (0:master,1:slave) */ + int offset; /* time offset (ms) for slave */ + gtime_t time; /* start time */ + gtime_t wtime; /* write time */ + unsigned int tick; /* start tick */ + unsigned int tick_f; /* start tick in file */ + unsigned int fpos; /* current file position */ + double start; /* start offset (s) */ + double speed; /* replay speed (time factor) */ + double swapintv; /* swap interval (hr) (0: no swap) */ + lock_t lock; /* lock flag */ +} file_t; + + +typedef struct +{ /* tcp control type */ + int state; /* state (0:close,1:wait,2:connect) */ + char saddr[256]; /* address string */ + int port; /* port */ + struct sockaddr_in addr; /* address resolved */ + socket_t sock; /* socket descriptor */ + int tcon; /* reconnect time (ms) (-1:never,0:now) */ + unsigned int tact; /* data active tick */ + unsigned int tdis; /* disconnect tick */ +} tcp_t; + + +typedef struct +{ /* tcp server type */ + tcp_t svr; /* tcp server control */ + tcp_t cli[MAXCLI]; /* tcp client controls */ +} tcpsvr_t; + + +typedef struct +{ /* tcp cilent type */ + tcp_t svr; /* tcp server control */ + int toinact; /* inactive timeout (ms) (0:no timeout) */ + int tirecon; /* reconnect interval (ms) (0:no reconnect) */ +} tcpcli_t; + + +typedef struct +{ /* ntrip control type */ + int state; /* state (0:close,1:wait,2:connect) */ + int type; /* type (0:server,1:client) */ + int nb; /* response buffer size */ + char url[256]; /* url for proxy */ + char mntpnt[256]; /* mountpoint */ + char user[256]; /* user */ + char passwd[256]; /* password */ + char str[NTRIP_MAXSTR]; /* mountpoint string for server */ + unsigned char buff[NTRIP_MAXRSP]; /* response buffer */ + tcpcli_t *tcp; /* tcp client */ +} ntrip_t; + + +typedef struct +{ /* ftp download control type */ + int state; /* state (0:close,1:download,2:complete,3:error) */ + int proto; /* protocol (0:ftp,1:http) */ + int error; /* error code (0:no error,1-10:wget error, */ + /* 11:no temp dir,12:uncompact error) */ + char addr[1024]; /* download address */ + char file[1024]; /* download file path */ + char user[256]; /* user for ftp */ + char passwd[256]; /* password for ftp */ + char local[1024]; /* local file path */ + int topts[4]; /* time options {poff,tint,toff,tretry} (s) */ + gtime_t tnext; /* next retry time (gpst) */ + pthread_t thread; /* download thread */ +} ftp_t; + + +typedef struct +{ /* receiver raw data control type */ + gtime_t time; /* message time */ + gtime_t tobs; /* observation data time */ + obs_t obs; /* observation data */ + obs_t obuf; /* observation data buffer */ + nav_t nav; /* satellite ephemerides */ + sta_t sta; /* station parameters */ + int ephsat; /* sat number of update ephemeris (0:no satellite) */ + sbsmsg_t sbsmsg; /* SBAS message */ + char msgtype[256]; /* last message type */ + unsigned char subfrm[MAXSAT][380]; /* subframe buffer */ + lexmsg_t lexmsg; /* LEX message */ + double lockt[MAXSAT][NFREQ + NEXOBS]; /* lock time (s) */ + double icpp[MAXSAT], off[MAXSAT], icpc; /* carrier params for ss2 */ + double prCA[MAXSAT], dpCA[MAXSAT]; /* L1/CA pseudrange/doppler for javad */ + unsigned char halfc[MAXSAT][NFREQ + NEXOBS]; /* half-cycle add flag */ + char freqn[MAXOBS]; /* frequency number for javad */ + int nbyte; /* number of bytes in message buffer */ + int len; /* message length (bytes) */ + int iod; /* issue of data */ + int tod; /* time of day (ms) */ + int tbase; /* time base (0:gpst,1:utc(usno),2:glonass,3:utc(su) */ + int flag; /* general purpose flag */ + int outtype; /* output message type */ + unsigned char buff[MAXRAWLEN]; /* message buffer */ + char opt[256]; /* receiver dependent options */ + double receive_time; /* RT17: Reiceve time of week for week rollover detection */ + unsigned int plen; /* RT17: Total size of packet to be read */ + unsigned int pbyte; /* RT17: How many packet bytes have been read so far */ + unsigned int page; /* RT17: Last page number */ + unsigned int reply; /* RT17: Current reply number */ + int week; /* RT17: week number */ + unsigned char pbuff[255 + 4 + 2]; /* RT17: Packet buffer */ +} raw_t; + + +typedef struct +{ /* RTK server type */ + int state; /* server state (0:stop,1:running) */ + int cycle; /* processing cycle (ms) */ + int nmeacycle; /* NMEA request cycle (ms) (0:no req) */ + int nmeareq; /* NMEA request (0:no,1:nmeapos,2:single sol) */ + double nmeapos[3]; /* NMEA request position (ecef) (m) */ + int buffsize; /* input buffer size (bytes) */ + int format[3]; /* input format {rov,base,corr} */ + solopt_t solopt[2]; /* output solution options {sol1,sol2} */ + int navsel; /* ephemeris select (0:all,1:rover,2:base,3:corr) */ + int nsbs; /* number of sbas message */ + int nsol; /* number of solution buffer */ + rtk_t rtk; /* RTK control/result struct */ + int nb[3]; /* bytes in input buffers {rov,base} */ + int nsb[2]; /* bytes in soulution buffers */ + int npb[3]; /* bytes in input peek buffers */ + unsigned char *buff[3]; /* input buffers {rov,base,corr} */ + unsigned char *sbuf[2]; /* output buffers {sol1,sol2} */ + unsigned char *pbuf[3]; /* peek buffers {rov,base,corr} */ + sol_t solbuf[MAXSOLBUF]; /* solution buffer */ + unsigned int nmsg[3][10]; /* input message counts */ + raw_t raw[3]; /* receiver raw control {rov,base,corr} */ + rtcm_t rtcm[3]; /* RTCM control {rov,base,corr} */ + gtime_t ftime[3]; /* download time {rov,base,corr} */ + char files[3][MAXSTRPATH]; /* download paths {rov,base,corr} */ + obs_t obs[3][MAXOBSBUF]; /* observation data {rov,base,corr} */ + nav_t nav; /* navigation data */ + sbsmsg_t sbsmsg[MAXSBSMSG]; /* SBAS message buffer */ + stream_t stream[8]; /* streams {rov,base,corr,sol1,sol2,logr,logb,logc} */ + stream_t *moni; /* monitor stream */ + unsigned int tick; /* start tick */ + pthread_t thread; /* server thread */ + int cputime; /* CPU time (ms) for a processing cycle */ + int prcout; /* missing observation data count */ + lock_t lock; /* lock flag */ +} rtksvr_t; + +typedef struct +{ /* multi-signal-message header type */ + unsigned char iod; /* issue of data station */ + unsigned char time_s; /* cumulative session transmitting time */ + unsigned char clk_str; /* clock steering indicator */ + unsigned char clk_ext; /* external clock indicator */ + unsigned char smooth; /* divergence free smoothing indicator */ + unsigned char tint_s; /* soothing interval */ + unsigned char nsat, nsig; /* number of satellites/signals */ + unsigned char sats[64]; /* satellites */ + unsigned char sigs[32]; /* signals */ + unsigned char cellmask[64]; /* cell mask */ +} msm_h_t; + + +const double chisqr[100] = {/* chi-sqr(n) (alpha=0.001) */ + 10.8, 13.8, 16.3, 18.5, 20.5, 22.5, 24.3, 26.1, 27.9, 29.6, + 31.3, 32.9, 34.5, 36.1, 37.7, 39.3, 40.8, 42.3, 43.8, 45.3, + 46.8, 48.3, 49.7, 51.2, 52.6, 54.1, 55.5, 56.9, 58.3, 59.7, + 61.1, 62.5, 63.9, 65.2, 66.6, 68.0, 69.3, 70.7, 72.1, 73.4, + 74.7, 76.0, 77.3, 78.6, 80.0, 81.3, 82.6, 84.0, 85.4, 86.7, + 88.0, 89.3, 90.6, 91.9, 93.3, 94.7, 96.0, 97.4, 98.7, 100, + 101, 102, 103, 104, 105, 107, 108, 109, 110, 112, + 113, 114, 115, 116, 118, 119, 120, 122, 123, 125, + 126, 127, 128, 129, 131, 132, 133, 134, 135, 137, + 138, 139, 140, 142, 143, 144, 145, 147, 148, 149}; + + +const double lam_carr[MAXFREQ] = {/* carrier wave length (m) */ + SPEED_OF_LIGHT / FREQ1, SPEED_OF_LIGHT / FREQ2, SPEED_OF_LIGHT / FREQ5, SPEED_OF_LIGHT / FREQ6, SPEED_OF_LIGHT / FREQ7, + SPEED_OF_LIGHT / FREQ8, SPEED_OF_LIGHT / FREQ9}; + +const int STRFMT_RTCM2 = 0; /* stream format: RTCM 2 */ +const int STRFMT_RTCM3 = 1; /* stream format: RTCM 3 */ +const int STRFMT_SP3 = 16; /* stream format: SP3 */ +const int STRFMT_RNXCLK = 17; /* stream format: RINEX CLK */ +const int STRFMT_SBAS = 18; /* stream format: SBAS messages */ +const int STRFMT_NMEA = 19; /* stream format: NMEA 0183 */ +//const solopt_t solopt_default; /* default solution output options */ + +const int MAXSTRRTK = 8; /* max number of stream in RTK server */ + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.cc b/src/algorithms/libs/rtklib/rtklib_conversions.cc new file mode 100644 index 000000000..937beee41 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_conversions.cc @@ -0,0 +1,349 @@ +/*! + * \file rtklib_conversions.cc + * \brief GNSS-SDR to RTKLIB data structures conversion functions + * \author 2017, Javier Arribas + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "rtklib_conversions.h" +#include "rtklib_rtkcmn.h" + +obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro, int week, int band) +{ + rtklib_obs.D[band] = gnss_synchro.Carrier_Doppler_hz; + rtklib_obs.P[band] = gnss_synchro.Pseudorange_m; + rtklib_obs.L[band] = gnss_synchro.Carrier_phase_rads / PI_2; + switch (band) + { + case 0: + rtklib_obs.code[band] = static_cast(CODE_L1C); + break; + case 1: + rtklib_obs.code[band] = static_cast(CODE_L2S); + break; + case 2: + rtklib_obs.code[band] = static_cast(CODE_L5X); + break; + } + double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; + if (CN0_dB_Hz_est > 63.75) CN0_dB_Hz_est = 63.75; + if (CN0_dB_Hz_est < 0.0) CN0_dB_Hz_est = 0.0; + auto CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25)); + rtklib_obs.SNR[band] = CN0_dB_Hz; + //Galileo is the third satellite system for RTKLIB, so, add the required offset to discriminate Galileo ephemeris + switch (gnss_synchro.System) + { + case 'G': + rtklib_obs.sat = gnss_synchro.PRN; + break; + case 'E': + rtklib_obs.sat = gnss_synchro.PRN + NSATGPS + NSATGLO; + break; + case 'R': + rtklib_obs.sat = gnss_synchro.PRN + NSATGPS; + break; + + default: + rtklib_obs.sat = gnss_synchro.PRN; + } + rtklib_obs.time = gpst2time(adjgpsweek(week), gnss_synchro.RX_time); + rtklib_obs.rcv = 1; + return rtklib_obs; +} + +geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& gnav_clock_model) +{ + double week, sec; + int adj_week; + geph_t rtklib_sat = {0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, 0.0, 0.0, 0.0}; + + rtklib_sat.sat = glonass_gnav_eph.i_satellite_slot_number + NSATGPS; /* satellite number */ + rtklib_sat.iode = static_cast(glonass_gnav_eph.d_t_b); /* IODE (0-6 bit of tb field) */ + rtklib_sat.frq = glonass_gnav_eph.i_satellite_freq_channel; /* satellite frequency number */ + rtklib_sat.svh = glonass_gnav_eph.d_l3rd_n; /* satellite health*/ + rtklib_sat.sva = static_cast(glonass_gnav_eph.d_F_T); /* satellite accuracy*/ + rtklib_sat.age = static_cast(glonass_gnav_eph.d_E_n); /* satellite age*/ + rtklib_sat.pos[0] = glonass_gnav_eph.d_Xn * 1000; /* satellite position (ecef) (m) */ + rtklib_sat.pos[1] = glonass_gnav_eph.d_Yn * 1000; /* satellite position (ecef) (m) */ + rtklib_sat.pos[2] = glonass_gnav_eph.d_Zn * 1000; /* satellite position (ecef) (m) */ + rtklib_sat.vel[0] = glonass_gnav_eph.d_VXn * 1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.vel[1] = glonass_gnav_eph.d_VYn * 1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.vel[2] = glonass_gnav_eph.d_VZn * 1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.acc[0] = glonass_gnav_eph.d_AXn * 1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.acc[1] = glonass_gnav_eph.d_AYn * 1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.acc[2] = glonass_gnav_eph.d_AZn * 1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.taun = glonass_gnav_eph.d_tau_n; /* SV clock bias (s) */ + rtklib_sat.gamn = glonass_gnav_eph.d_gamma_n; /* SV relative freq bias */ + rtklib_sat.age = static_cast(glonass_gnav_eph.d_Delta_tau_n); /* delay between L1 and L2 (s) */ + + // Time expressed in GPS Time but using RTKLib format + glonass_gnav_eph.glot_to_gpst(glonass_gnav_eph.d_t_b, gnav_clock_model.d_tau_c, gnav_clock_model.d_tau_gps, &week, &sec); + adj_week = adjgpsweek(static_cast(week)); + rtklib_sat.toe = gpst2time(adj_week, sec); + + // Time expressed in GPS Time but using RTKLib format + glonass_gnav_eph.glot_to_gpst(glonass_gnav_eph.d_t_k, gnav_clock_model.d_tau_c, gnav_clock_model.d_tau_gps, &week, &sec); + adj_week = adjgpsweek(static_cast(week)); + rtklib_sat.tof = gpst2time(adj_week, sec); + + return rtklib_sat; +} + + +eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph) +{ + eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + //Galileo is the third satellite system for RTKLIB, so, add the required offset to discriminate Galileo ephemeris + rtklib_sat.sat = gal_eph.i_satellite_PRN + NSATGPS + NSATGLO; + rtklib_sat.A = gal_eph.A_1 * gal_eph.A_1; + rtklib_sat.M0 = gal_eph.M0_1; + rtklib_sat.deln = gal_eph.delta_n_3; + rtklib_sat.OMG0 = gal_eph.OMEGA_0_2; + rtklib_sat.OMGd = gal_eph.OMEGA_dot_3; + rtklib_sat.omg = gal_eph.omega_2; + rtklib_sat.i0 = gal_eph.i_0_2; + rtklib_sat.idot = gal_eph.iDot_2; + rtklib_sat.e = gal_eph.e_1; + rtklib_sat.Adot = 0; //only in CNAV; + rtklib_sat.ndot = 0; //only in CNAV; + + rtklib_sat.week = adjgpsweek(gal_eph.WN_5); /* week of tow */ + rtklib_sat.cic = gal_eph.C_ic_4; + rtklib_sat.cis = gal_eph.C_is_4; + rtklib_sat.cuc = gal_eph.C_uc_3; + rtklib_sat.cus = gal_eph.C_us_3; + rtklib_sat.crc = gal_eph.C_rc_3; + rtklib_sat.crs = gal_eph.C_rs_3; + rtklib_sat.f0 = gal_eph.af0_4; + rtklib_sat.f1 = gal_eph.af1_4; + rtklib_sat.f2 = gal_eph.af2_4; + rtklib_sat.tgd[0] = gal_eph.BGD_E1E5a_5; + rtklib_sat.tgd[1] = gal_eph.BGD_E1E5b_5; + rtklib_sat.tgd[2] = 0; + rtklib_sat.tgd[3] = 0; + rtklib_sat.toes = gal_eph.t0e_1; + rtklib_sat.toc = gpst2time(rtklib_sat.week, gal_eph.t0c_4); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, gal_eph.TOW_5); + + /* adjustment for week handover */ + double tow, toc; + tow = time2gpst(rtklib_sat.ttr, &rtklib_sat.week); + toc = time2gpst(rtklib_sat.toc, nullptr); + if (rtklib_sat.toes < tow - 302400.0) + { + rtklib_sat.week++; + tow -= 604800.0; + } + else if (rtklib_sat.toes > tow + 302400.0) + { + rtklib_sat.week--; + tow += 604800.0; + } + rtklib_sat.toe = gpst2time(rtklib_sat.week, rtklib_sat.toes); + rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + + return rtklib_sat; +} + + +eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph) +{ + eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + rtklib_sat.sat = gps_eph.i_satellite_PRN; + rtklib_sat.A = gps_eph.d_sqrt_A * gps_eph.d_sqrt_A; + rtklib_sat.M0 = gps_eph.d_M_0; + rtklib_sat.deln = gps_eph.d_Delta_n; + rtklib_sat.OMG0 = gps_eph.d_OMEGA0; + rtklib_sat.OMGd = gps_eph.d_OMEGA_DOT; + rtklib_sat.omg = gps_eph.d_OMEGA; + rtklib_sat.i0 = gps_eph.d_i_0; + rtklib_sat.idot = gps_eph.d_IDOT; + rtklib_sat.e = gps_eph.d_e_eccentricity; + rtklib_sat.Adot = 0; //only in CNAV; + rtklib_sat.ndot = 0; //only in CNAV; + + rtklib_sat.week = adjgpsweek(gps_eph.i_GPS_week); /* week of tow */ + rtklib_sat.cic = gps_eph.d_Cic; + rtklib_sat.cis = gps_eph.d_Cis; + rtklib_sat.cuc = gps_eph.d_Cuc; + rtklib_sat.cus = gps_eph.d_Cus; + rtklib_sat.crc = gps_eph.d_Crc; + rtklib_sat.crs = gps_eph.d_Crs; + rtklib_sat.f0 = gps_eph.d_A_f0; + rtklib_sat.f1 = gps_eph.d_A_f1; + rtklib_sat.f2 = gps_eph.d_A_f2; + rtklib_sat.tgd[0] = gps_eph.d_TGD; + rtklib_sat.tgd[1] = 0.0; + rtklib_sat.tgd[2] = 0.0; + rtklib_sat.tgd[3] = 0.0; + rtklib_sat.toes = gps_eph.d_Toe; + rtklib_sat.toc = gpst2time(rtklib_sat.week, gps_eph.d_Toc); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, gps_eph.d_TOW); + + /* adjustment for week handover */ + double tow, toc; + tow = time2gpst(rtklib_sat.ttr, &rtklib_sat.week); + toc = time2gpst(rtklib_sat.toc, nullptr); + if (rtklib_sat.toes < tow - 302400.0) + { + rtklib_sat.week++; + tow -= 604800.0; + } + else if (rtklib_sat.toes > tow + 302400.0) + { + rtklib_sat.week--; + tow += 604800.0; + } + rtklib_sat.toe = gpst2time(rtklib_sat.week, rtklib_sat.toes); + rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + + return rtklib_sat; +} + + +eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris& gps_cnav_eph) +{ + eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + rtklib_sat.sat = gps_cnav_eph.i_satellite_PRN; + const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 170 + rtklib_sat.A = A_REF + gps_cnav_eph.d_DELTA_A; + rtklib_sat.M0 = gps_cnav_eph.d_M_0; + rtklib_sat.deln = gps_cnav_eph.d_Delta_n; + rtklib_sat.OMG0 = gps_cnav_eph.d_OMEGA0; + // Compute the angle between the ascending node and the Greenwich meridian + const double OMEGA_DOT_REF = -2.6e-9; // semicircles / s, see IS-GPS-200H pp. 164 + double d_OMEGA_DOT = OMEGA_DOT_REF * PI + gps_cnav_eph.d_DELTA_OMEGA_DOT; + rtklib_sat.OMGd = d_OMEGA_DOT; + rtklib_sat.omg = gps_cnav_eph.d_OMEGA; + rtklib_sat.i0 = gps_cnav_eph.d_i_0; + rtklib_sat.idot = gps_cnav_eph.d_IDOT; + rtklib_sat.e = gps_cnav_eph.d_e_eccentricity; + rtklib_sat.Adot = gps_cnav_eph.d_A_DOT; //only in CNAV; + rtklib_sat.ndot = gps_cnav_eph.d_DELTA_DOT_N; //only in CNAV; + + rtklib_sat.week = adjgpsweek(gps_cnav_eph.i_GPS_week); /* week of tow */ + rtklib_sat.cic = gps_cnav_eph.d_Cic; + rtklib_sat.cis = gps_cnav_eph.d_Cis; + rtklib_sat.cuc = gps_cnav_eph.d_Cuc; + rtklib_sat.cus = gps_cnav_eph.d_Cus; + rtklib_sat.crc = gps_cnav_eph.d_Crc; + rtklib_sat.crs = gps_cnav_eph.d_Crs; + rtklib_sat.f0 = gps_cnav_eph.d_A_f0; + rtklib_sat.f1 = gps_cnav_eph.d_A_f1; + rtklib_sat.f2 = gps_cnav_eph.d_A_f2; + rtklib_sat.tgd[0] = gps_cnav_eph.d_TGD; + rtklib_sat.tgd[1] = 0.0; + rtklib_sat.tgd[2] = 0.0; + rtklib_sat.tgd[3] = 0.0; + rtklib_sat.isc[0] = gps_cnav_eph.d_ISCL1; + rtklib_sat.isc[1] = gps_cnav_eph.d_ISCL2; + rtklib_sat.isc[2] = gps_cnav_eph.d_ISCL5I; + rtklib_sat.isc[3] = gps_cnav_eph.d_ISCL5Q; + rtklib_sat.toes = gps_cnav_eph.d_Toe1; + rtklib_sat.toc = gpst2time(rtklib_sat.week, gps_cnav_eph.d_Toc); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, gps_cnav_eph.d_TOW); + + /* adjustment for week handover */ + double tow, toc; + tow = time2gpst(rtklib_sat.ttr, &rtklib_sat.week); + toc = time2gpst(rtklib_sat.toc, nullptr); + if (rtklib_sat.toes < tow - 302400.0) + { + rtklib_sat.week++; + tow -= 604800.0; + } + else if (rtklib_sat.toes > tow + 302400.0) + { + rtklib_sat.week--; + tow += 604800.0; + } + rtklib_sat.toe = gpst2time(rtklib_sat.week, rtklib_sat.toes); + rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); + rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + + return rtklib_sat; +} + +alm_t alm_to_rtklib(const Gps_Almanac& gps_alm) +{ + alm_t rtklib_alm; + + rtklib_alm = {0, 0, 0, 0, {0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + rtklib_alm.sat = gps_alm.i_satellite_PRN; + rtklib_alm.svh = gps_alm.i_SV_health; + rtklib_alm.svconf = gps_alm.i_AS_status; + rtklib_alm.week = gps_alm.i_WNa; + gtime_t toa; + toa.time = gps_alm.i_Toa; + rtklib_alm.toa = toa; + rtklib_alm.A = gps_alm.d_sqrt_A * gps_alm.d_sqrt_A; + rtklib_alm.e = gps_alm.d_e_eccentricity; + rtklib_alm.i0 = (gps_alm.d_Delta_i + 0.3) * PI; + rtklib_alm.OMG0 = gps_alm.d_OMEGA0 * PI; + rtklib_alm.OMGd = gps_alm.d_OMEGA_DOT * PI; + rtklib_alm.omg = gps_alm.d_OMEGA * PI; + rtklib_alm.M0 = gps_alm.d_M_0 * PI; + rtklib_alm.f0 = gps_alm.d_A_f0; + rtklib_alm.f1 = gps_alm.d_A_f1; + rtklib_alm.toas = gps_alm.i_Toa; + + return rtklib_alm; +} + + +alm_t alm_to_rtklib(const Galileo_Almanac& gal_alm) +{ + alm_t rtklib_alm; + + rtklib_alm = {0, 0, 0, 0, {0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + rtklib_alm.sat = gal_alm.i_satellite_PRN + NSATGPS + NSATGLO; + rtklib_alm.svh = gal_alm.E1B_HS; + rtklib_alm.svconf = gal_alm.E1B_HS; + rtklib_alm.week = gal_alm.i_WNa; + gtime_t toa; + toa.time = gal_alm.i_Toa; + rtklib_alm.toa = toa; + rtklib_alm.A = 5440.588203494 + gal_alm.d_Delta_sqrt_A; + rtklib_alm.A = rtklib_alm.A * rtklib_alm.A; + rtklib_alm.e = gal_alm.d_e_eccentricity; + rtklib_alm.i0 = (gal_alm.d_Delta_i + 56.0 / 180.0) * PI; + rtklib_alm.OMG0 = gal_alm.d_OMEGA0 * PI; + rtklib_alm.OMGd = gal_alm.d_OMEGA_DOT * PI; + rtklib_alm.omg = gal_alm.d_OMEGA * PI; + rtklib_alm.M0 = gal_alm.d_M_0 * PI; + rtklib_alm.f0 = gal_alm.d_A_f0; + rtklib_alm.f1 = gal_alm.d_A_f1; + rtklib_alm.toas = gal_alm.i_Toa; + + return rtklib_alm; +} diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.h b/src/algorithms/libs/rtklib/rtklib_conversions.h new file mode 100644 index 000000000..0264ad9e8 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_conversions.h @@ -0,0 +1,60 @@ +/*! + * \file rtklib_conversions.h + * \brief GNSS-SDR to RTKLIB data structures conversion functions + * \author 2017, Javier Arribas + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_RTKLIB_CONVERSIONS_H_ +#define GNSS_SDR_RTKLIB_CONVERSIONS_H_ + +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include "gnss_synchro.h" +#include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" +#include "gps_ephemeris.h" +#include "rtklib.h" + +eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph); +eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph); +eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris& gps_cnav_eph); + +alm_t alm_to_rtklib(const Gps_Almanac& gps_alm); +alm_t alm_to_rtklib(const Galileo_Almanac& gal_alm); + +/*! + * \brief Transforms a Glonass_Gnav_Ephemeris to its RTKLIB counterpart + * \param glonass_gnav_eph GLONASS GNAV Ephemeris structure + * \return Ephemeris structure for RTKLIB parsing + */ +geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& gnav_clock_model); + +obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro, int week, int band); + +#endif /* GNSS_SDR_RTKLIB_CONVERSIONS_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_ephemeris.cc b/src/algorithms/libs/rtklib/rtklib_ephemeris.cc new file mode 100644 index 000000000..c942c0d2c --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ephemeris.cc @@ -0,0 +1,915 @@ +/*! + * \file rtklib_ephemeris.cc + * \brief satellite ephemeris and clock functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_ephemeris.h" +#include "rtklib_preceph.h" +#include "rtklib_rtkcmn.h" +#include "rtklib_sbas.h" + +/* constants ------------------------------------------------------*/ + +const double RE_GLO = 6378136.0; /* radius of earth (m) ref [2] */ +const double MU_GPS = 3.9860050e14; /* gravitational constant ref [1] */ +const double MU_GLO = 3.9860044e14; /* gravitational constant ref [2] */ +const double MU_GAL = 3.986004418e14; /* earth gravitational constant ref [7] */ +const double MU_BDS = 3.986004418e14; /* earth gravitational constant ref [9] */ +const double J2_GLO = 1.0826257e-3; /* 2nd zonal harmonic of geopot ref [2] */ + +const double OMGE_GLO = 7.292115e-5; /* earth angular velocity (rad/s) ref [2] */ +const double OMGE_GAL = 7.2921151467e-5; /* earth angular velocity (rad/s) ref [7] */ +const double OMGE_BDS = 7.292115e-5; /* earth angular velocity (rad/s) ref [9] */ + +const double SIN_5 = -0.0871557427476582; /* sin(-5.0 deg) */ +const double COS_5 = 0.9961946980917456; /* cos(-5.0 deg) */ + +const double ERREPH_GLO = 5.0; /* error of glonass ephemeris (m) */ +const double TSTEP = 60.0; /* integration step glonass ephemeris (s) */ +const double RTOL_KEPLER = 1e-13; /* relative tolerance for Kepler equation */ + +const double DEFURASSR = 0.15; /* default accurary of ssr corr (m) */ +const double MAXECORSSR = 10.0; /* max orbit correction of ssr (m) */ +const double MAXCCORSSR = 1e-6 * SPEED_OF_LIGHT; /* max clock correction of ssr (m) */ +const double MAXAGESSR = 90.0; /* max age of ssr orbit and clock (s) */ +const double MAXAGESSR_HRCLK = 10.0; /* max age of ssr high-rate clock (s) */ +const double STD_BRDCCLK = 30.0; /* error of broadcast clock (m) */ + +const int MAX_ITER_KEPLER = 30; /* max number of iteration of Kelpler */ + + +/* variance by ura ephemeris (ref [1] 20.3.3.3.1.1) --------------------------*/ +double var_uraeph(int ura) +{ + const double ura_value[] = { + 2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24.0, 48.0, 96.0, 192.0, 384.0, 768.0, 1536.0, + 3072.0, 6144.0}; + return ura < 0 || 14 < ura ? std::pow(6144.0, 2.0) : std::pow(ura_value[ura], 2.0); +} + + +/* variance by ura ssr (ref [4]) ---------------------------------------------*/ +double var_urassr(int ura) +{ + double std_; + if (ura <= 0) return std::pow(DEFURASSR, 2.0); + if (ura >= 63) return std::pow(5.4665, 2.0); + std_ = (std::pow((ura >> 3) & 7, 2.0) * (1.0 + (ura & 7) / 4.0) - 1.0) * 1e-3; + return std::pow(std_, 2.0); +} + + +/* almanac to satellite position and clock bias -------------------------------- + * compute satellite position and clock bias with almanac (gps, galileo, qzss) + * args : gtime_t time I time (gpst) + * alm_t *alm I almanac + * double *rs O satellite position (ecef) {x,y,z} (m) + * double *dts O satellite clock bias (s) + * return : none + * notes : see ref [1],[7],[8] + *-----------------------------------------------------------------------------*/ +void alm2pos(gtime_t time, const alm_t *alm, double *rs, double *dts) +{ + double tk, M, E, Ek, sinE, cosE, u, r, i, O, x, y, sinO, cosO, cosi, mu; + int n; + + trace(4, "alm2pos : time=%s sat=%2d\n", time_str(time, 3), alm->sat); + + tk = timediff(time, alm->toa); + + if (alm->A <= 0.0) + { + rs[0] = rs[1] = rs[2] = *dts = 0.0; + return; + } + mu = satsys(alm->sat, nullptr) == SYS_GAL ? MU_GAL : MU_GPS; + + M = alm->M0 + sqrt(mu / (alm->A * alm->A * alm->A)) * tk; + for (n = 0, E = M, Ek = 0.0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++) + { + Ek = E; + E -= (E - alm->e * sin(E) - M) / (1.0 - alm->e * cos(E)); + } + if (n >= MAX_ITER_KEPLER) + { + trace(2, "alm2pos: kepler iteration overflow sat=%2d\n", alm->sat); + return; + } + sinE = sin(E); + cosE = cos(E); + u = atan2(sqrt(1.0 - alm->e * alm->e) * sinE, cosE - alm->e) + alm->omg; + r = alm->A * (1.0 - alm->e * cosE); + i = alm->i0; + O = alm->OMG0 + (alm->OMGd - DEFAULT_OMEGA_EARTH_DOT) * tk - DEFAULT_OMEGA_EARTH_DOT * alm->toas; + x = r * cos(u); + y = r * sin(u); + sinO = sin(O); + cosO = cos(O); + cosi = cos(i); + rs[0] = x * cosO - y * cosi * sinO; + rs[1] = x * sinO + y * cosi * cosO; + rs[2] = y * sin(i); + *dts = alm->f0 + alm->f1 * tk; +} + + +/* broadcast ephemeris to satellite clock bias --------------------------------- + * compute satellite clock bias with broadcast ephemeris (gps, galileo, qzss) + * args : gtime_t time I time by satellite clock (gpst) + * eph_t *eph I broadcast ephemeris + * return : satellite clock bias (s) without relativeity correction + * notes : see ref [1],[7],[8] + * satellite clock does not include relativity correction and tdg + *-----------------------------------------------------------------------------*/ +double eph2clk(gtime_t time, const eph_t *eph) +{ + double t; + int i; + + trace(4, "eph2clk : time=%s sat=%2d\n", time_str(time, 3), eph->sat); + + t = timediff(time, eph->toc); + + for (i = 0; i < 2; i++) + { + t -= eph->f0 + eph->f1 * t + eph->f2 * t * t; + } + return eph->f0 + eph->f1 * t + eph->f2 * t * t; +} + + +/* broadcast ephemeris to satellite position and clock bias -------------------- + * compute satellite position and clock bias with broadcast ephemeris (gps, + * galileo, qzss) + * args : gtime_t time I time (gpst) + * eph_t *eph I broadcast ephemeris + * double *rs O satellite position (ecef) {x,y,z} (m) + * double *dts O satellite clock bias (s) + * double *var O satellite position and clock variance (m^2) + * return : none + * notes : see ref [1],[7],[8] + * satellite clock includes relativity correction without code bias + * (tgd or bgd) + *-----------------------------------------------------------------------------*/ +void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, + double *var) +{ + double tk, M, E, Ek, sinE, cosE, u, r, i, O, sin2u, cos2u, x, y, sinO, cosO, cosi, mu, omge; + double xg, yg, zg, sino, coso; + int n, sys, prn; + + trace(4, "eph2pos : time=%s sat=%2d\n", time_str(time, 3), eph->sat); + + if (eph->A <= 0.0) + { + rs[0] = rs[1] = rs[2] = *dts = *var = 0.0; + return; + } + tk = timediff(time, eph->toe); + + switch ((sys = satsys(eph->sat, &prn))) + { + case SYS_GAL: + mu = MU_GAL; + omge = OMGE_GAL; + break; + case SYS_BDS: + mu = MU_BDS; + omge = OMGE_BDS; + break; + default: + mu = MU_GPS; + omge = DEFAULT_OMEGA_EARTH_DOT; + break; + } + M = eph->M0 + (sqrt(mu / (eph->A * eph->A * eph->A)) + eph->deln) * tk; + + for (n = 0, E = M, Ek = 0.0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++) + { + Ek = E; + E -= (E - eph->e * sin(E) - M) / (1.0 - eph->e * cos(E)); + } + if (n >= MAX_ITER_KEPLER) + { + trace(2, "eph2pos: kepler iteration overflow sat=%2d\n", eph->sat); + return; + } + sinE = sin(E); + cosE = cos(E); + + trace(4, "kepler: sat=%2d e=%8.5f n=%2d del=%10.3e\n", eph->sat, eph->e, n, E - Ek); + + u = atan2(sqrt(1.0 - eph->e * eph->e) * sinE, cosE - eph->e) + eph->omg; + r = eph->A * (1.0 - eph->e * cosE); + i = eph->i0 + eph->idot * tk; + sin2u = sin(2.0 * u); + cos2u = cos(2.0 * u); + u += eph->cus * sin2u + eph->cuc * cos2u; + r += eph->crs * sin2u + eph->crc * cos2u; + i += eph->cis * sin2u + eph->cic * cos2u; + x = r * cos(u); + y = r * sin(u); + cosi = cos(i); + + /* beidou geo satellite (ref [9]) */ + if (sys == SYS_BDS && prn <= 5) + { + O = eph->OMG0 + eph->OMGd * tk - omge * eph->toes; + sinO = sin(O); + cosO = cos(O); + xg = x * cosO - y * cosi * sinO; + yg = x * sinO + y * cosi * cosO; + zg = y * sin(i); + sino = sin(omge * tk); + coso = cos(omge * tk); + rs[0] = xg * coso + yg * sino * COS_5 + zg * sino * SIN_5; + rs[1] = -xg * sino + yg * coso * COS_5 + zg * coso * SIN_5; + rs[2] = -yg * SIN_5 + zg * COS_5; + } + else + { + O = eph->OMG0 + (eph->OMGd - omge) * tk - omge * eph->toes; + sinO = sin(O); + cosO = cos(O); + rs[0] = x * cosO - y * cosi * sinO; + rs[1] = x * sinO + y * cosi * cosO; + rs[2] = y * sin(i); + } + tk = timediff(time, eph->toc); + *dts = eph->f0 + eph->f1 * tk + eph->f2 * tk * tk; + + /* relativity correction */ + *dts -= 2.0 * sqrt(mu * eph->A) * eph->e * sinE / std::pow(SPEED_OF_LIGHT, 2.0); + + /* position and clock error variance */ + *var = var_uraeph(eph->sva); +} + + +/* glonass orbit differential equations --------------------------------------*/ +void deq(const double *x, double *xdot, const double *acc) +{ + double a, b, c, r2 = dot(x, x, 3), r3 = r2 * sqrt(r2), omg2 = std::pow(OMGE_GLO, 2.0); + + if (r2 <= 0.0) + { + xdot[0] = xdot[1] = xdot[2] = xdot[3] = xdot[4] = xdot[5] = 0.0; + return; + } + /* ref [2] A.3.1.2 with bug fix for xdot[4],xdot[5] */ + a = 1.5 * J2_GLO * MU_GLO * std::pow(RE_GLO, 2.0) / r2 / r3; /* 3/2*J2*mu*Ae^2/r^5 */ + b = 5.0 * x[2] * x[2] / r2; /* 5*z^2/r^2 */ + c = -MU_GLO / r3 - a * (1.0 - b); /* -mu/r^3-a(1-b) */ + xdot[0] = x[3]; + xdot[1] = x[4]; + xdot[2] = x[5]; + xdot[3] = (c + omg2) * x[0] + 2.0 * OMGE_GLO * x[4] + acc[0]; + xdot[4] = (c + omg2) * x[1] - 2.0 * OMGE_GLO * x[3] + acc[1]; + xdot[5] = (c - 2.0 * a) * x[2] + acc[2]; +} + + +/* glonass position and velocity by numerical integration --------------------*/ +void glorbit(double t, double *x, const double *acc) +{ + double k1[6], k2[6], k3[6], k4[6], w[6]; + int i; + + deq(x, k1, acc); + for (i = 0; i < 6; i++) w[i] = x[i] + k1[i] * t / 2.0; + deq(w, k2, acc); + for (i = 0; i < 6; i++) w[i] = x[i] + k2[i] * t / 2.0; + deq(w, k3, acc); + for (i = 0; i < 6; i++) w[i] = x[i] + k3[i] * t; + deq(w, k4, acc); + for (i = 0; i < 6; i++) x[i] += (k1[i] + 2.0 * k2[i] + 2.0 * k3[i] + k4[i]) * t / 6.0; +} + + +/* glonass ephemeris to satellite clock bias ----------------------------------- + * compute satellite clock bias with glonass ephemeris + * args : gtime_t time I time by satellite clock (gpst) + * geph_t *geph I glonass ephemeris + * return : satellite clock bias (s) + * notes : see ref [2] + *-----------------------------------------------------------------------------*/ +double geph2clk(gtime_t time, const geph_t *geph) +{ + double t; + int i; + + trace(4, "geph2clk: time=%s sat=%2d\n", time_str(time, 3), geph->sat); + + t = timediff(time, geph->toe); + + for (i = 0; i < 2; i++) + { + t -= -geph->taun + geph->gamn * t; + } + return -geph->taun + geph->gamn * t; +} + + +/* glonass ephemeris to satellite position and clock bias ---------------------- + * compute satellite position and clock bias with glonass ephemeris + * args : gtime_t time I time (gpst) + * geph_t *geph I glonass ephemeris + * double *rs O satellite position {x,y,z} (ecef) (m) + * double *dts O satellite clock bias (s) + * double *var O satellite position and clock variance (m^2) + * return : none + * notes : see ref [2] + *-----------------------------------------------------------------------------*/ +void geph2pos(gtime_t time, const geph_t *geph, double *rs, double *dts, + double *var) +{ + double t, tt, x[6]; + int i; + + trace(4, "geph2pos: time=%s sat=%2d\n", time_str(time, 3), geph->sat); + + t = timediff(time, geph->toe); + + *dts = -geph->taun + geph->gamn * t; + + for (i = 0; i < 3; i++) + { + x[i] = geph->pos[i]; + x[i + 3] = geph->vel[i]; + } + for (tt = t < 0.0 ? -TSTEP : TSTEP; fabs(t) > 1e-9; t -= tt) + { + if (fabs(t) < TSTEP) tt = t; + glorbit(tt, x, geph->acc); + } + for (i = 0; i < 3; i++) rs[i] = x[i]; + + *var = std::pow(ERREPH_GLO, 2.0); +} + + +/* sbas ephemeris to satellite clock bias -------------------------------------- + * compute satellite clock bias with sbas ephemeris + * args : gtime_t time I time by satellite clock (gpst) + * seph_t *seph I sbas ephemeris + * return : satellite clock bias (s) + * notes : see ref [3] + *-----------------------------------------------------------------------------*/ +double seph2clk(gtime_t time, const seph_t *seph) +{ + double t; + int i; + + trace(4, "seph2clk: time=%s sat=%2d\n", time_str(time, 3), seph->sat); + + t = timediff(time, seph->t0); + + for (i = 0; i < 2; i++) + { + t -= seph->af0 + seph->af1 * t; + } + return seph->af0 + seph->af1 * t; +} + + +/* sbas ephemeris to satellite position and clock bias ------------------------- + * compute satellite position and clock bias with sbas ephemeris + * args : gtime_t time I time (gpst) + * seph_t *seph I sbas ephemeris + * double *rs O satellite position {x,y,z} (ecef) (m) + * double *dts O satellite clock bias (s) + * double *var O satellite position and clock variance (m^2) + * return : none + * notes : see ref [3] + *-----------------------------------------------------------------------------*/ +void seph2pos(gtime_t time, const seph_t *seph, double *rs, double *dts, + double *var) +{ + double t; + int i; + + trace(4, "seph2pos: time=%s sat=%2d\n", time_str(time, 3), seph->sat); + + t = timediff(time, seph->t0); + + for (i = 0; i < 3; i++) + { + rs[i] = seph->pos[i] + seph->vel[i] * t + seph->acc[i] * t * t / 2.0; + } + *dts = seph->af0 + seph->af1 * t; + + *var = var_uraeph(seph->sva); +} + + +/* select ephememeris --------------------------------------------------------*/ +eph_t *seleph(gtime_t time, int sat, int iode, const nav_t *nav) +{ + double t, tmax, tmin; + int i, j = -1; + + trace(4, "seleph : time=%s sat=%2d iode=%d\n", time_str(time, 3), sat, iode); + + switch (satsys(sat, nullptr)) + { + case SYS_QZS: + tmax = MAXDTOE_QZS + 1.0; + break; + case SYS_GAL: + tmax = MAXDTOE_GAL + 1.0; + break; + case SYS_BDS: + tmax = MAXDTOE_BDS + 1.0; + break; + default: + tmax = MAXDTOE + 1.0; + break; + } + tmin = tmax + 1.0; + + for (i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + if (iode >= 0 && nav->eph[i].iode != iode) continue; + if ((t = fabs(timediff(nav->eph[i].toe, time))) > tmax) continue; + if (iode >= 0) return nav->eph + i; + if (t <= tmin) + { + j = i; + tmin = t; + } /* toe closest to time */ + } + if (iode >= 0 || j < 0) + { + trace(3, "no broadcast ephemeris: %s sat=%2d iode=%3d\n", time_str(time, 0), + sat, iode); + return nullptr; + } + return nav->eph + j; +} + + +/* select glonass ephememeris ------------------------------------------------*/ +geph_t *selgeph(gtime_t time, int sat, int iode, const nav_t *nav) +{ + double t, tmax = MAXDTOE_GLO, tmin = tmax + 1.0; + int i, j = -1; + + trace(4, "selgeph : time=%s sat=%2d iode=%2d\n", time_str(time, 3), sat, iode); + + for (i = 0; i < nav->ng; i++) + { + if (nav->geph[i].sat != sat) continue; + if (iode >= 0 && nav->geph[i].iode != iode) continue; + if ((t = fabs(timediff(nav->geph[i].toe, time))) > tmax) continue; + if (iode >= 0) return nav->geph + i; + if (t <= tmin) + { + j = i; + tmin = t; + } /* toe closest to time */ + } + if (iode >= 0 || j < 0) + { + trace(3, "no glonass ephemeris : %s sat=%2d iode=%2d\n", time_str(time, 0), + sat, iode); + return nullptr; + } + return nav->geph + j; +} + + +/* select sbas ephememeris ---------------------------------------------------*/ +seph_t *selseph(gtime_t time, int sat, const nav_t *nav) +{ + double t, tmax = MAXDTOE_SBS, tmin = tmax + 1.0; + int i, j = -1; + + trace(4, "selseph : time=%s sat=%2d\n", time_str(time, 3), sat); + + for (i = 0; i < nav->ns; i++) + { + if (nav->seph[i].sat != sat) continue; + if ((t = fabs(timediff(nav->seph[i].t0, time))) > tmax) continue; + if (t <= tmin) + { + j = i; + tmin = t; + } /* toe closest to time */ + } + if (j < 0) + { + trace(3, "no sbas ephemeris : %s sat=%2d\n", time_str(time, 0), sat); + return nullptr; + } + return nav->seph + j; +} + + +/* satellite clock with broadcast ephemeris ----------------------------------*/ +int ephclk(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + double *dts) +{ + eph_t *eph; + geph_t *geph; + seph_t *seph; + int sys; + + trace(4, "ephclk : time=%s sat=%2d\n", time_str(time, 3), sat); + + sys = satsys(sat, nullptr); + + if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS) + { + if (!(eph = seleph(teph, sat, -1, nav))) return 0; + *dts = eph2clk(time, eph); + } + else if (sys == SYS_GLO) + { + if (!(geph = selgeph(teph, sat, -1, nav))) return 0; + *dts = geph2clk(time, geph); + } + else if (sys == SYS_SBS) + { + if (!(seph = selseph(teph, sat, nav))) return 0; + *dts = seph2clk(time, seph); + } + else + return 0; + + return 1; +} + + +/* satellite position and clock by broadcast ephemeris -----------------------*/ +int ephpos(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + int iode, double *rs, double *dts, double *var, int *svh) +{ + eph_t *eph; + geph_t *geph; + seph_t *seph; + double rst[3], dtst[1], tt = 1e-3; + int i, sys; + + trace(4, "ephpos : time=%s sat=%2d iode=%d\n", time_str(time, 3), sat, iode); + + sys = satsys(sat, nullptr); + + *svh = -1; + + if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS) + { + if (!(eph = seleph(teph, sat, iode, nav))) return 0; + + eph2pos(time, eph, rs, dts, var); + time = timeadd(time, tt); + eph2pos(time, eph, rst, dtst, var); + *svh = eph->svh; + } + else if (sys == SYS_GLO) + { + if (!(geph = selgeph(teph, sat, iode, nav))) return 0; + geph2pos(time, geph, rs, dts, var); + time = timeadd(time, tt); + geph2pos(time, geph, rst, dtst, var); + *svh = geph->svh; + } + else if (sys == SYS_SBS) + { + if (!(seph = selseph(teph, sat, nav))) return 0; + + seph2pos(time, seph, rs, dts, var); + time = timeadd(time, tt); + seph2pos(time, seph, rst, dtst, var); + *svh = seph->svh; + } + else + return 0; + + /* satellite velocity and clock drift by differential approx */ + for (i = 0; i < 3; i++) rs[i + 3] = (rst[i] - rs[i]) / tt; + dts[1] = (dtst[0] - dts[0]) / tt; + + return 1; +} + + +/* satellite position and clock with sbas correction -------------------------*/ +int satpos_sbas(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + double *rs, double *dts, double *var, int *svh) +{ + const sbssatp_t *sbs; + int i; + + trace(4, "satpos_sbas: time=%s sat=%2d\n", time_str(time, 3), sat); + + /* search sbas satellite correciton */ + for (i = 0; i < nav->sbssat.nsat; i++) + { + sbs = nav->sbssat.sat + i; + if (sbs->sat == sat) break; + } + if (i >= nav->sbssat.nsat) + { + trace(2, "no sbas correction for orbit: %s sat=%2d\n", time_str(time, 0), sat); + ephpos(time, teph, sat, nav, -1, rs, dts, var, svh); + *svh = -1; + return 0; + } + /* satellite position and clock by broadcast ephemeris */ + if (!ephpos(time, teph, sat, nav, sbs->lcorr.iode, rs, dts, var, svh)) return 0; + + /* sbas satellite correction (long term and fast) */ + if (sbssatcorr(time, sat, nav, rs, dts, var)) return 1; + *svh = -1; + return 0; +} + + +/* satellite position and clock with ssr correction --------------------------*/ +int satpos_ssr(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + int opt, double *rs, double *dts, double *var, int *svh) +{ + const ssr_t *ssr; + eph_t *eph; + double t1, t2, t3, er[3], ea[3], ec[3], rc[3], deph[3], dclk, dant[3] = {0}, tk; + int i, sys; + + trace(4, "satpos_ssr: time=%s sat=%2d\n", time_str(time, 3), sat); + + ssr = nav->ssr + sat - 1; + + if (!ssr->t0[0].time) + { + trace(2, "no ssr orbit correction: %s sat=%2d\n", time_str(time, 0), sat); + return 0; + } + if (!ssr->t0[1].time) + { + trace(2, "no ssr clock correction: %s sat=%2d\n", time_str(time, 0), sat); + return 0; + } + /* inconsistency between orbit and clock correction */ + if (ssr->iod[0] != ssr->iod[1]) + { + trace(2, "inconsist ssr correction: %s sat=%2d iod=%d %d\n", + time_str(time, 0), sat, ssr->iod[0], ssr->iod[1]); + *svh = -1; + return 0; + } + t1 = timediff(time, ssr->t0[0]); + t2 = timediff(time, ssr->t0[1]); + t3 = timediff(time, ssr->t0[2]); + + /* ssr orbit and clock correction (ref [4]) */ + if (fabs(t1) > MAXAGESSR || fabs(t2) > MAXAGESSR) + { + trace(2, "age of ssr error: %s sat=%2d t=%.0f %.0f\n", time_str(time, 0), + sat, t1, t2); + *svh = -1; + return 0; + } + if (ssr->udi[0] >= 1.0) t1 -= ssr->udi[0] / 2.0; + if (ssr->udi[1] >= 1.0) t2 -= ssr->udi[0] / 2.0; + + for (i = 0; i < 3; i++) deph[i] = ssr->deph[i] + ssr->ddeph[i] * t1; + dclk = ssr->dclk[0] + ssr->dclk[1] * t2 + ssr->dclk[2] * t2 * t2; + + /* ssr highrate clock correction (ref [4]) */ + if (ssr->iod[0] == ssr->iod[2] && ssr->t0[2].time && fabs(t3) < MAXAGESSR_HRCLK) + { + dclk += ssr->hrclk; + } + if (norm_rtk(deph, 3) > MAXECORSSR || fabs(dclk) > MAXCCORSSR) + { + trace(3, "invalid ssr correction: %s deph=%.1f dclk=%.1f\n", + time_str(time, 0), norm_rtk(deph, 3), dclk); + *svh = -1; + return 0; + } + /* satellite position and clock by broadcast ephemeris */ + if (!ephpos(time, teph, sat, nav, ssr->iode, rs, dts, var, svh)) return 0; + + /* satellite clock for gps, galileo and qzss */ + sys = satsys(sat, nullptr); + if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS) + { + if (!(eph = seleph(teph, sat, ssr->iode, nav))) return 0; + + /* satellite clock by clock parameters */ + tk = timediff(time, eph->toc); + dts[0] = eph->f0 + eph->f1 * tk + eph->f2 * tk * tk; + dts[1] = eph->f1 + 2.0 * eph->f2 * tk; + + /* relativity correction */ + dts[0] -= 2.0 * dot(rs, rs + 3, 3) / SPEED_OF_LIGHT / SPEED_OF_LIGHT; + } + /* radial-along-cross directions in ecef */ + if (!normv3(rs + 3, ea)) return 0; + cross3(rs, rs + 3, rc); + if (!normv3(rc, ec)) + { + *svh = -1; + return 0; + } + cross3(ea, ec, er); + + /* satellite antenna offset correction */ + if (opt) + { + satantoff(time, rs, sat, nav, dant); + } + for (i = 0; i < 3; i++) + { + rs[i] += -(er[i] * deph[0] + ea[i] * deph[1] + ec[i] * deph[2]) + dant[i]; + } + /* t_corr = t_sv - (dts(brdc) + dclk(ssr) / SPEED_OF_LIGHT) (ref [10] eq.3.12-7) */ + dts[0] += dclk / SPEED_OF_LIGHT; + + /* variance by ssr ura */ + *var = var_urassr(ssr->ura); + + trace(5, "satpos_ssr: %s sat=%2d deph=%6.3f %6.3f %6.3f er=%6.3f %6.3f %6.3f dclk=%6.3f var=%6.3f\n", + time_str(time, 2), sat, deph[0], deph[1], deph[2], er[0], er[1], er[2], dclk, *var); + + return 1; +} + + +/* satellite position and clock ------------------------------------------------ + * compute satellite position, velocity and clock + * args : gtime_t time I time (gpst) + * gtime_t teph I time to select ephemeris (gpst) + * int sat I satellite number + * nav_t *nav I navigation data + * int ephopt I ephemeris option (EPHOPT_???) + * double *rs O sat position and velocity (ecef) + * {x,y,z,vx,vy,vz} (m|m/s) + * double *dts O sat clock {bias,drift} (s|s/s) + * double *var O sat position and clock error variance (m^2) + * int *svh O sat health flag (-1:correction not available) + * return : status (1:ok,0:error) + * notes : satellite position is referenced to antenna phase center + * satellite clock does not include code bias correction (tgd or bgd) + *-----------------------------------------------------------------------------*/ +int satpos(gtime_t time, gtime_t teph, int sat, int ephopt, + const nav_t *nav, double *rs, double *dts, double *var, + int *svh) +{ + trace(4, "satpos : time=%s sat=%2d ephopt=%d\n", time_str(time, 3), sat, ephopt); + + *svh = 0; + + switch (ephopt) + { + case EPHOPT_BRDC: + return ephpos(time, teph, sat, nav, -1, rs, dts, var, svh); + case EPHOPT_SBAS: + return satpos_sbas(time, teph, sat, nav, rs, dts, var, svh); + case EPHOPT_SSRAPC: + return satpos_ssr(time, teph, sat, nav, 0, rs, dts, var, svh); + case EPHOPT_SSRCOM: + return satpos_ssr(time, teph, sat, nav, 1, rs, dts, var, svh); + case EPHOPT_PREC: + if (!peph2pos(time, sat, nav, 1, rs, dts, var)) + break; + else + return 1; + //TODO: enable lex + //case EPHOPT_LEX : + // if (!lexeph2pos(time, sat, nav, rs, dts, var)) break; else return 1; + } + *svh = -1; + return 0; +} + + +/* satellite positions and clocks ---------------------------------------------- + * compute satellite positions, velocities and clocks + * args : gtime_t teph I time to select ephemeris (gpst) + * obsd_t *obs I observation data + * int n I number of observation data + * nav_t *nav I navigation data + * int ephopt I ephemeris option (EPHOPT_???) + * double *rs O satellite positions and velocities (ecef) + * double *dts O satellite clocks + * double *var O sat position and clock error variances (m^2) + * int *svh O sat health flag (-1:correction not available) + * return : none + * notes : rs [(0:2)+i*6]= obs[i] sat position {x,y,z} (m) + * rs [(3:5)+i*6]= obs[i] sat velocity {vx,vy,vz} (m/s) + * dts[(0:1)+i*2]= obs[i] sat clock {bias,drift} (s|s/s) + * var[i] = obs[i] sat position and clock error variance (m^2) + * svh[i] = obs[i] sat health flag + * if no navigation data, set 0 to rs[], dts[], var[] and svh[] + * satellite position and clock are values at signal transmission time + * satellite position is referenced to antenna phase center + * satellite clock does not include code bias correction (tgd or bgd) + * any pseudorange and broadcast ephemeris are always needed to get + * signal transmission time + *-----------------------------------------------------------------------------*/ +void satposs(gtime_t teph, const obsd_t *obs, int n, const nav_t *nav, + int ephopt, double *rs, double *dts, double *var, int *svh) +{ + gtime_t time[MAXOBS] = {}; + double dt, pr; + int i, j; + + trace(3, "satposs : teph=%s n=%d ephopt=%d\n", time_str(teph, 3), n, ephopt); + + for (i = 0; i < n && i < MAXOBS; i++) + { + for (j = 0; j < 6; j++) rs[j + i * 6] = 0.0; + for (j = 0; j < 2; j++) dts[j + i * 2] = 0.0; + var[i] = 0.0; + svh[i] = 0; + + /* search any pseudorange */ + for (j = 0, pr = 0.0; j < NFREQ; j++) + if ((pr = obs[i].P[j]) != 0.0) break; + + if (j >= NFREQ) + { + trace(2, "no pseudorange %s sat=%2d\n", time_str(obs[i].time, 3), obs[i].sat); + continue; + } + /* transmission time by satellite clock */ + time[i] = timeadd(obs[i].time, -pr / SPEED_OF_LIGHT); + + /* satellite clock bias by broadcast ephemeris */ + if (!ephclk(time[i], teph, obs[i].sat, nav, &dt)) + { + trace(3, "no broadcast clock %s sat=%2d\n", time_str(time[i], 3), obs[i].sat); + continue; + } + time[i] = timeadd(time[i], -dt); + + /* satellite position and clock at transmission time */ + if (!satpos(time[i], teph, obs[i].sat, ephopt, nav, rs + i * 6, dts + i * 2, var + i, + svh + i)) + { + trace(3, "no ephemeris %s sat=%2d\n", time_str(time[i], 3), obs[i].sat); + continue; + } + /* if no precise clock available, use broadcast clock instead */ + if (dts[i * 2] == 0.0) + { + if (!ephclk(time[i], teph, obs[i].sat, nav, dts + i * 2)) continue; + dts[1 + i * 2] = 0.0; + *var = std::pow(STD_BRDCCLK, 2.0); + } + } + for (i = 0; i < n && i < MAXOBS; i++) + { + trace(4, "%s sat=%2d rs=%13.3f %13.3f %13.3f dts=%12.3f var=%7.3f svh=%02X\n", + time_str(time[i], 6), obs[i].sat, rs[i * 6], rs[1 + i * 6], rs[2 + i * 6], + dts[i * 2] * 1e9, var[i], svh[i]); + } +} diff --git a/src/algorithms/libs/rtklib/rtklib_ephemeris.h b/src/algorithms/libs/rtklib/rtklib_ephemeris.h new file mode 100644 index 000000000..b6eaf6b78 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ephemeris.h @@ -0,0 +1,95 @@ +/*! + * \file rtklib_ephemeris.h + * \brief satellite ephemeris and clock functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + + +#ifndef GNSS_SDR_RTKLIB_EPHEMERIS_H_ +#define GNSS_SDR_RTKLIB_EPHEMERIS_H_ + +#include "rtklib.h" + + +double var_uraeph(int ura); +double var_urassr(int ura); +void alm2pos(gtime_t time, const alm_t *alm, double *rs, double *dts); +double eph2clk(gtime_t time, const eph_t *eph); +void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, + double *var); +void deq(const double *x, double *xdot, const double *acc); +void glorbit(double t, double *x, const double *acc); +double geph2clk(gtime_t time, const geph_t *geph); + +void geph2pos(gtime_t time, const geph_t *geph, double *rs, double *dts, + double *var); +double seph2clk(gtime_t time, const seph_t *seph); +void seph2pos(gtime_t time, const seph_t *seph, double *rs, double *dts, + double *var); +eph_t *seleph(gtime_t time, int sat, int iode, const nav_t *nav); +geph_t *selgeph(gtime_t time, int sat, int iode, const nav_t *nav); +seph_t *selseph(gtime_t time, int sat, const nav_t *nav); +int ephclk(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + double *dts); +//satellite position and clock by broadcast ephemeris +int ephpos(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + int iode, double *rs, double *dts, double *var, int *svh); +int satpos_sbas(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + double *rs, double *dts, double *var, int *svh); +int satpos_ssr(gtime_t time, gtime_t teph, int sat, const nav_t *nav, + int opt, double *rs, double *dts, double *var, int *svh); + +int satpos(gtime_t time, gtime_t teph, int sat, int ephopt, + const nav_t *nav, double *rs, double *dts, double *var, + int *svh); +void satposs(gtime_t teph, const obsd_t *obs, int n, const nav_t *nav, + int ephopt, double *rs, double *dts, double *var, int *svh); + + +#endif /* GNSS_SDR_RTKLIB_EPHEMERIS_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_ionex.cc b/src/algorithms/libs/rtklib/rtklib_ionex.cc new file mode 100644 index 000000000..162778f9a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ionex.cc @@ -0,0 +1,622 @@ +/*! + * \file rtklib_ionex.h + * \brief ionex functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * References: + * [1] S.Schear, W.Gurtner and J.Feltens, IONEX: The IONosphere Map EXchange + * Format Version 1, February 25, 1998 + * [2] S.Schaer, R.Markus, B.Gerhard and A.S.Timon, Daily Global Ionosphere + * Maps based on GPS Carrier Phase Data Routinely producted by CODE + * Analysis Center, Proceeding of the IGS Analysis Center Workshop, 1996 + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_ionex.h" +#include "rtklib_rtkcmn.h" + +/* get index -----------------------------------------------------------------*/ +int getindex(double value, const double *range) +{ + if (range[2] == 0.0) return 0; + if (range[1] > 0.0 && (value < range[0] || range[1] < value)) return -1; + if (range[1] < 0.0 && (value < range[1] || range[0] < value)) return -1; + return static_cast(floor((value - range[0]) / range[2] + 0.5)); +} + + +/* get number of items -------------------------------------------------------*/ +int nitem(const double *range) +{ + return getindex(range[1], range) + 1; +} + + +/* data index (i:lat,j:lon,k:hgt) --------------------------------------------*/ +int dataindex(int i, int j, int k, const int *ndata) +{ + if (i < 0 || ndata[0] <= i || j < 0 || ndata[1] <= j || k < 0 || ndata[2] <= k) return -1; + return i + ndata[0] * (j + ndata[1] * k); +} + + +/* add tec data to navigation data -------------------------------------------*/ +tec_t *addtec(const double *lats, const double *lons, const double *hgts, + double rb, nav_t *nav) +{ + tec_t *p, *nav_tec; + gtime_t time0 = {0, 0}; + int i, n, ndata[3]; + + trace(3, "addtec :\n"); + + ndata[0] = nitem(lats); + ndata[1] = nitem(lons); + ndata[2] = nitem(hgts); + if (ndata[0] <= 1 || ndata[1] <= 1 || ndata[2] <= 0) return nullptr; + + if (nav->nt >= nav->ntmax) + { + nav->ntmax += 256; + if (!(nav_tec = static_cast(realloc(nav->tec, sizeof(tec_t) * nav->ntmax)))) + { + trace(1, "readionex malloc error ntmax=%d\n", nav->ntmax); + free(nav->tec); + nav->tec = nullptr; + nav->nt = nav->ntmax = 0; + return nullptr; + } + nav->tec = nav_tec; + } + p = nav->tec + nav->nt; + p->time = time0; + p->rb = rb; + for (i = 0; i < 3; i++) + { + p->ndata[i] = ndata[i]; + p->lats[i] = lats[i]; + p->lons[i] = lons[i]; + p->hgts[i] = hgts[i]; + } + n = ndata[0] * ndata[1] * ndata[2]; + + if (!(p->data = static_cast(malloc(sizeof(double) * n))) || + !(p->rms = static_cast(malloc(sizeof(float) * n)))) + { + return nullptr; + } + for (i = 0; i < n; i++) + { + p->data[i] = 0.0; + p->rms[i] = 0.0f; + } + nav->nt++; + return p; +} + + +/* read ionex dcb aux data ----------------------------------------------------*/ +void readionexdcb(FILE *fp, double *dcb, double *rms) +{ + int i, sat; + char buff[1024], id[32], *label; + + trace(3, "readionexdcb:\n"); + + for (i = 0; i < MAXSAT; i++) dcb[i] = rms[i] = 0.0; + + while (fgets(buff, sizeof(buff), fp)) + { + if (strlen(buff) < 60) continue; + label = buff + 60; + + if (strstr(label, "PRN / BIAS / RMS") == label) + { + strncpy(id, buff + 3, 3); + id[3] = '\0'; + + if (!(sat = satid2no(id))) + { + trace(2, "ionex invalid satellite: %s\n", id); + continue; + } + dcb[sat - 1] = str2num(buff, 6, 10); + rms[sat - 1] = str2num(buff, 16, 10); + } + else if (strstr(label, "END OF AUX DATA") == label) + break; + } +} + + +/* read ionex header ---------------------------------------------------------*/ +double readionexh(FILE *fp, double *lats, double *lons, double *hgts, + double *rb, double *nexp, double *dcb, double *rms) +{ + double ver = 0.0; + char buff[1024], *label; + + trace(3, "readionexh:\n"); + + while (fgets(buff, sizeof(buff), fp)) + { + if (strlen(buff) < 60) continue; + label = buff + 60; + + if (strstr(label, "IONEX VERSION / TYPE") == label) + { + if (buff[20] == 'I') ver = str2num(buff, 0, 8); + } + else if (strstr(label, "BASE RADIUS") == label) + { + *rb = str2num(buff, 0, 8); + } + else if (strstr(label, "HGT1 / HGT2 / DHGT") == label) + { + hgts[0] = str2num(buff, 2, 6); + hgts[1] = str2num(buff, 8, 6); + hgts[2] = str2num(buff, 14, 6); + } + else if (strstr(label, "LAT1 / LAT2 / DLAT") == label) + { + lats[0] = str2num(buff, 2, 6); + lats[1] = str2num(buff, 8, 6); + lats[2] = str2num(buff, 14, 6); + } + else if (strstr(label, "LON1 / LON2 / DLON") == label) + { + lons[0] = str2num(buff, 2, 6); + lons[1] = str2num(buff, 8, 6); + lons[2] = str2num(buff, 14, 6); + } + else if (strstr(label, "EXPONENT") == label) + { + *nexp = str2num(buff, 0, 6); + } + else if (strstr(label, "START OF AUX DATA") == label && + strstr(buff, "DIFFERENTIAL CODE BIASES")) + { + readionexdcb(fp, dcb, rms); + } + else if (strstr(label, "END OF HEADER") == label) + { + return ver; + } + } + return 0.0; +} + + +/* read ionex body -----------------------------------------------------------*/ +int readionexb(FILE *fp, const double *lats, const double *lons, + const double *hgts, double rb, double nexp, nav_t *nav) +{ + tec_t *p = nullptr; + gtime_t time = {0, 0}; + double lat, lon[3], hgt, x; + int i, j, k, n, m, index, type = 0; + char buff[1024], *label = buff + 60; + + trace(3, "readionexb:\n"); + + while (fgets(buff, sizeof(buff), fp)) + { + if (strlen(buff) < 60) continue; + + if (strstr(label, "START OF TEC MAP") == label) + { + if ((p = addtec(lats, lons, hgts, rb, nav))) type = 1; + } + else if (strstr(label, "END OF TEC MAP") == label) + { + type = 0; + p = nullptr; + } + else if (strstr(label, "START OF RMS MAP") == label) + { + type = 2; + p = nullptr; + } + else if (strstr(label, "END OF RMS MAP") == label) + { + type = 0; + p = nullptr; + } + else if (strstr(label, "EPOCH OF CURRENT MAP") == label) + { + if (str2time(buff, 0, 36, &time)) + { + trace(2, "ionex epoch invalid: %-36.36s\n", buff); + continue; + } + if (type == 2) + { + for (i = nav->nt - 1; i >= 0; i--) + { + if (fabs(timediff(time, nav->tec[i].time)) >= 1.0) continue; + p = nav->tec + i; + break; + } + } + else if (p) + p->time = time; + } + else if (strstr(label, "LAT/LON1/LON2/DLON/H") == label && p) + { + lat = str2num(buff, 2, 6); + lon[0] = str2num(buff, 8, 6); + lon[1] = str2num(buff, 14, 6); + lon[2] = str2num(buff, 20, 6); + hgt = str2num(buff, 26, 6); + + i = getindex(lat, p->lats); + k = getindex(hgt, p->hgts); + n = nitem(lon); + + for (m = 0; m < n; m++) + { + if (m % 16 == 0 && !fgets(buff, sizeof(buff), fp)) break; + + j = getindex(lon[0] + lon[2] * m, p->lons); + if ((index = dataindex(i, j, k, p->ndata)) < 0) continue; + + if ((x = str2num(buff, m % 16 * 5, 5)) == 9999.0) continue; + + if (type == 1) + p->data[index] = x * std::pow(10.0, nexp); + else + p->rms[index] = static_cast(x * std::pow(10.0, nexp)); + } + } + } + return 1; +} + + +/* combine tec grid data -----------------------------------------------------*/ +void combtec(nav_t *nav) +{ + tec_t tmp; + int i, j, n = 0; + + trace(3, "combtec : nav->nt=%d\n", nav->nt); + + for (i = 0; i < nav->nt - 1; i++) + { + for (j = i + 1; j < nav->nt; j++) + { + if (timediff(nav->tec[j].time, nav->tec[i].time) < 0.0) + { + tmp = nav->tec[i]; + nav->tec[i] = nav->tec[j]; + nav->tec[j] = tmp; + } + } + } + for (i = 0; i < nav->nt; i++) + { + if (i > 0 && timediff(nav->tec[i].time, nav->tec[n - 1].time) == 0.0) + { + free(nav->tec[n - 1].data); + free(nav->tec[n - 1].rms); + nav->tec[n - 1] = nav->tec[i]; + continue; + } + nav->tec[n++] = nav->tec[i]; + } + nav->nt = n; + + trace(4, "combtec : nav->nt=%d\n", nav->nt); +} + + +/* read ionex tec grid file ---------------------------------------------------- + * read ionex ionospheric tec grid file + * args : char *file I ionex tec grid file + * (wind-card * is expanded) + * nav_t *nav IO navigation data + * nav->nt, nav->ntmax and nav->tec are modified + * int opt I read option (1: no clear of tec data,0:clear) + * return : none + * notes : see ref [1] + *-----------------------------------------------------------------------------*/ +void readtec(const char *file, nav_t *nav, int opt) +{ + FILE *fp; + double lats[3] = {0}, lons[3] = {0}, hgts[3] = {0}, rb = 0.0, nexp = -1.0; + double dcb[MAXSAT] = {0}, rms[MAXSAT] = {0}; + int i, n; + char *efiles[MAXEXFILE]; + + trace(3, "readtec : file=%s\n", file); + + /* clear of tec grid data option */ + if (!opt) + { + free(nav->tec); + nav->tec = nullptr; + nav->nt = nav->ntmax = 0; + } + for (i = 0; i < MAXEXFILE; i++) + { + if (!(efiles[i] = static_cast(malloc(1024)))) + { + for (i--; i >= 0; i--) free(efiles[i]); + return; + } + } + /* expand wild card in file path */ + n = expath(file, efiles, MAXEXFILE); + + for (i = 0; i < n; i++) + { + if (!(fp = fopen(efiles[i], "re"))) + { + trace(2, "ionex file open error %s\n", efiles[i]); + continue; + } + + /* read ionex header */ + if (readionexh(fp, lats, lons, hgts, &rb, &nexp, dcb, rms) <= 0.0) + { + trace(2, "ionex file format error %s\n", efiles[i]); + fclose(fp); + continue; + } + + /* read ionex body */ + readionexb(fp, lats, lons, hgts, rb, nexp, nav); + fclose(fp); + } + for (i = 0; i < MAXEXFILE; i++) free(efiles[i]); + + /* combine tec grid data */ + if (nav->nt > 0) combtec(nav); + + /* P1-P2 dcb */ + for (i = 0; i < MAXSAT; i++) + { + nav->cbias[i][0] = SPEED_OF_LIGHT * dcb[i] * 1e-9; /* ns->m */ + } +} + + +/* interpolate tec grid data -------------------------------------------------*/ +int interptec(const tec_t *tec, int k, const double *posp, double *value, + double *rms) +{ + double dlat, dlon, a, b, d[4] = {0}, r[4] = {0}; + int i, j, n, index; + + trace(3, "interptec: k=%d posp=%.2f %.2f\n", k, posp[0] * R2D, posp[1] * R2D); + *value = *rms = 0.0; + + if (tec->lats[2] == 0.0 || tec->lons[2] == 0.0) return 0; + + dlat = posp[0] * R2D - tec->lats[0]; + dlon = posp[1] * R2D - tec->lons[0]; + if (tec->lons[2] > 0.0) + dlon -= floor(dlon / 360) * 360.0; /* 0 <= dlon<360 */ + else + dlon += floor(-dlon / 360) * 360.0; /* -360lats[2]; + b = dlon / tec->lons[2]; + i = static_cast(floor(a)); + a -= i; + j = static_cast(floor(b)); + b -= j; + + /* get gridded tec data */ + for (n = 0; n < 4; n++) + { + if ((index = dataindex(i + (n % 2), j + (n < 2 ? 0 : 1), k, tec->ndata)) < 0) continue; + d[n] = tec->data[index]; + r[n] = tec->rms[index]; + } + if (d[0] > 0.0 && d[1] > 0.0 && d[2] > 0.0 && d[3] > 0.0) + { + /* bilinear interpolation (inside of grid) */ + *value = (1.0 - a) * (1.0 - b) * d[0] + a * (1.0 - b) * d[1] + (1.0 - a) * b * d[2] + a * b * d[3]; + *rms = (1.0 - a) * (1.0 - b) * r[0] + a * (1.0 - b) * r[1] + (1.0 - a) * b * r[2] + a * b * r[3]; + } + /* nearest-neighbour extrapolation (outside of grid) */ + else if (a <= 0.5 && b <= 0.5 && d[0] > 0.0) + { + *value = d[0]; + *rms = r[0]; + } + else if (a > 0.5 && b <= 0.5 && d[1] > 0.0) + { + *value = d[1]; + *rms = r[1]; + } + else if (a <= 0.5 && b > 0.5 && d[2] > 0.0) + { + *value = d[2]; + *rms = r[2]; + } + else if (a > 0.5 && b > 0.5 && d[3] > 0.0) + { + *value = d[3]; + *rms = r[3]; + } + else + { + i = 0; + for (n = 0; n < 4; n++) + if (d[n] > 0.0) + { + i++; + *value += d[n]; + *rms += r[n]; + } + if (i == 0) return 0; + *value /= i; + *rms /= i; + } + return 1; +} + + +/* ionosphere delay by tec grid data -----------------------------------------*/ +int iondelay(gtime_t time, const tec_t *tec, const double *pos, + const double *azel, int opt, double *delay, double *var) +{ + const double fact = 40.30E16 / FREQ1 / FREQ1; /* tecu->L1 iono (m) */ + double fs, posp[3] = {0}, vtec, rms, hion, rp; + int i; + + trace(3, "iondelay: time=%s pos=%.1f %.1f azel=%.1f %.1f\n", time_str(time, 0), + pos[0] * R2D, pos[1] * R2D, azel[0] * R2D, azel[1] * R2D); + + *delay = *var = 0.0; + + for (i = 0; i < tec->ndata[2]; i++) + { /* for a layer */ + hion = tec->hgts[0] + tec->hgts[2] * i; + + /* ionospheric pierce point position */ + fs = ionppp(pos, azel, tec->rb, hion, posp); + + if (opt & 2) + { + /* modified single layer mapping function (M-SLM) ref [2] */ + rp = tec->rb / (tec->rb + hion) * sin(0.9782 * (PI / 2.0 - azel[1])); + fs = 1.0 / sqrt(1.0 - rp * rp); + } + if (opt & 1) + { + /* earth rotation correction (sun-fixed coordinate) */ + posp[1] += 2.0 * PI * timediff(time, tec->time) / 86400.0; + } + /* interpolate tec grid data */ + if (!interptec(tec, i, posp, &vtec, &rms)) return 0; + + *delay += fact * fs * vtec; + *var += fact * fact * fs * fs * rms * rms; + } + trace(4, "iondelay: delay=%7.2f std=%6.2f\n", *delay, sqrt(*var)); + + return 1; +} + + +/* ionosphere model by tec grid data ------------------------------------------- + * compute ionospheric delay by tec grid data + * args : gtime_t time I time (gpst) + * nav_t *nav I navigation data + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * int opt I model option + * bit0: 0:earth-fixed,1:sun-fixed + * bit1: 0:single-layer,1:modified single-layer + * double *delay O ionospheric delay (L1) (m) + * double *var O ionospheric dealy (L1) variance (m^2) + * return : status (1:ok,0:error) + * notes : before calling the function, read tec grid data by calling readtec() + * return ok with delay=0 and var=VAR_NOTEC if elnt; i++) + { + if (timediff(nav->tec[i].time, time) > 0.0) break; + } + if (i == 0 || i >= nav->nt) + { + trace(2, "%s: tec grid out of period\n", time_str(time, 0)); + return 0; + } + if ((tt = timediff(nav->tec[i].time, nav->tec[i - 1].time)) == 0.0) + { + trace(2, "tec grid time interval error\n"); + return 0; + } + /* ionospheric delay by tec grid data */ + stat[0] = iondelay(time, nav->tec + i - 1, pos, azel, opt, dels, vars); + stat[1] = iondelay(time, nav->tec + i, pos, azel, opt, dels + 1, vars + 1); + + if (!stat[0] && !stat[1]) + { + trace(2, "%s: tec grid out of area pos=%6.2f %7.2f azel=%6.1f %5.1f\n", + time_str(time, 0), pos[0] * R2D, pos[1] * R2D, azel[0] * R2D, azel[1] * R2D); + return 0; + } + if (stat[0] && stat[1]) + { /* linear interpolation by time */ + a = timediff(time, nav->tec[i - 1].time) / tt; + *delay = dels[0] * (1.0 - a) + dels[1] * a; + *var = vars[0] * (1.0 - a) + vars[1] * a; + } + else if (stat[0]) + { /* nearest-neighbour extrapolation by time */ + *delay = dels[0]; + *var = vars[0]; + } + else + { + *delay = dels[1]; + *var = vars[1]; + } + trace(3, "iontec : delay=%5.2f std=%5.2f\n", *delay, sqrt(*var)); + return 1; +} diff --git a/src/algorithms/libs/rtklib/rtklib_ionex.h b/src/algorithms/libs/rtklib/rtklib_ionex.h new file mode 100644 index 000000000..6ffeb2c7a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ionex.h @@ -0,0 +1,90 @@ +/*! + * \file rtklib_ionex.h + * \brief ionex functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * References: + * [1] S.Schear, W.Gurtner and J.Feltens, IONEX: The IONosphere Map EXchange + * Format Version 1, February 25, 1998 + * [2] S.Schaer, R.Markus, B.Gerhard and A.S.Timon, Daily Global Ionosphere + * Maps based on GPS Carrier Phase Data Routinely producted by CODE + * Analysis Center, Proceeding of the IGS Analysis Center Workshop, 1996 + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_IONEX_H_ +#define GNSS_SDR_RTKLIB_IONEX_H_ + +#include "rtklib.h" + +const double VAR_NOTEC = 30.0 * 30.0; /* variance of no tec */ +const double MIN_EL = 0.0; /* min elevation angle (rad) */ +const double MIN_HGT = -1000.0; /* min user height (m) */ + +int getindex(double value, const double *range); + +int nitem(const double *range); +int dataindex(int i, int j, int k, const int *ndata); +tec_t *addtec(const double *lats, const double *lons, const double *hgts, + double rb, nav_t *nav); +void readionexdcb(FILE *fp, double *dcb, double *rms); +double readionexh(FILE *fp, double *lats, double *lons, double *hgts, + double *rb, double *nexp, double *dcb, double *rms); +int readionexb(FILE *fp, const double *lats, const double *lons, + const double *hgts, double rb, double nexp, nav_t *nav); +void combtec(nav_t *nav); +void readtec(const char *file, nav_t *nav, int opt); +int interptec(const tec_t *tec, int k, const double *posp, double *value, + double *rms); + +int iondelay(gtime_t time, const tec_t *tec, const double *pos, + const double *azel, int opt, double *delay, double *var); +int iontec(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, int opt, double *delay, double *var); + +#endif /* GNSS_SDR_RTKLIB_IONEX_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_lambda.cc b/src/algorithms/libs/rtklib/rtklib_lambda.cc new file mode 100644 index 000000000..e96efb39a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_lambda.cc @@ -0,0 +1,350 @@ +/*! + * \file rtklib_lambda.cc + * \brief Integer ambiguity resolution + * \authors
          + *
        • 2007-2008, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2008, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_lambda.h" +#include "rtklib_rtkcmn.h" + +/* LD factorization (Q=L'*diag(D)*L) -----------------------------------------*/ +int LD(int n, const double *Q, double *L, double *D) +{ + int i, j, k, info = 0; + double a, *A = mat(n, n); + + memcpy(A, Q, sizeof(double) * n * n); + for (i = n - 1; i >= 0; i--) + { + if ((D[i] = A[i + i * n]) <= 0.0) + { + info = -1; + break; + } + a = sqrt(D[i]); + for (j = 0; j <= i; j++) L[i + j * n] = A[i + j * n] / a; + for (j = 0; j <= i - 1; j++) + for (k = 0; k <= j; k++) A[j + k * n] -= L[i + k * n] * L[i + j * n]; + for (j = 0; j <= i; j++) L[i + j * n] /= L[i + i * n]; + } + free(A); + if (info) fprintf(stderr, "%s : LD factorization error\n", __FILE__); + return info; +} + + +/* integer gauss transformation ----------------------------------------------*/ +void gauss(int n, double *L, double *Z, int i, int j) +{ + int k, mu; + + if ((mu = static_cast ROUND_LAMBDA(L[i + j * n])) != 0) + { + for (k = i; k < n; k++) L[k + n * j] -= static_cast(mu) * L[k + i * n]; + for (k = 0; k < n; k++) Z[k + n * j] -= static_cast(mu) * Z[k + i * n]; + } +} + + +/* permutations --------------------------------------------------------------*/ +void perm(int n, double *L, double *D, int j, double del, double *Z) +{ + int k; + double eta, lam, a0, a1; + + eta = D[j] / del; + lam = D[j + 1] * L[j + 1 + j * n] / del; + D[j] = eta * D[j + 1]; + D[j + 1] = del; + for (k = 0; k <= j - 1; k++) + { + a0 = L[j + k * n]; + a1 = L[j + 1 + k * n]; + L[j + k * n] = -L[j + 1 + j * n] * a0 + a1; + L[j + 1 + k * n] = eta * a0 + lam * a1; + } + L[j + 1 + j * n] = lam; + for (k = j + 2; k < n; k++) SWAP_LAMBDA(L[k + j * n], L[k + (j + 1) * n]); + for (k = 0; k < n; k++) SWAP_LAMBDA(Z[k + j * n], Z[k + (j + 1) * n]); +} + + +/* lambda reduction (z=Z'*a, Qz=Z'*Q*Z=L'*diag(D)*L) (ref.[1]) ---------------*/ +void reduction(int n, double *L, double *D, double *Z) +{ + int i, j, k; + double del; + + j = n - 2; + k = n - 2; + while (j >= 0) + { + if (j <= k) + for (i = j + 1; i < n; i++) gauss(n, L, Z, i, j); + del = D[j] + L[j + 1 + j * n] * L[j + 1 + j * n] * D[j + 1]; + if (del + 1E-6 < D[j + 1]) + { /* compared considering numerical error */ + perm(n, L, D, j, del, Z); + k = j; + j = n - 2; + } + else + j--; + } +} + + +/* modified lambda (mlambda) search (ref. [2]) -------------------------------*/ +int search(int n, int m, const double *L, const double *D, + const double *zs, double *zn, double *s) +{ + int i, j, k, c, nn = 0, imax = 0; + double newdist, maxdist = 1E99, y; + double *S = zeros(n, n), *dist = mat(n, 1), *zb = mat(n, 1), *z = mat(n, 1), *step = mat(n, 1); + + k = n - 1; + dist[k] = 0.0; + zb[k] = zs[k]; + z[k] = ROUND_LAMBDA(zb[k]); + y = zb[k] - z[k]; + step[k] = SGN_LAMBDA(y); + for (c = 0; c < LOOPMAX; c++) + { + newdist = dist[k] + y * y / D[k]; + if (newdist < maxdist) + { + if (k != 0) + { + dist[--k] = newdist; + for (i = 0; i <= k; i++) + S[k + i * n] = S[k + 1 + i * n] + (z[k + 1] - zb[k + 1]) * L[k + 1 + i * n]; + zb[k] = zs[k] + S[k + k * n]; + z[k] = ROUND_LAMBDA(zb[k]); + y = zb[k] - z[k]; + step[k] = SGN_LAMBDA(y); + } + else + { + if (nn < m) + { + if (nn == 0 || newdist > s[imax]) imax = nn; + for (i = 0; i < n; i++) zn[i + nn * n] = z[i]; + s[nn++] = newdist; + } + else + { + if (newdist < s[imax]) + { + for (i = 0; i < n; i++) zn[i + imax * n] = z[i]; + s[imax] = newdist; + for (i = imax = 0; i < m; i++) + if (s[imax] < s[i]) imax = i; + } + maxdist = s[imax]; + } + z[0] += step[0]; + y = zb[0] - z[0]; + step[0] = -step[0] - SGN_LAMBDA(step[0]); + } + } + else + { + if (k == n - 1) + break; + + k++; + z[k] += step[k]; + y = zb[k] - z[k]; + step[k] = -step[k] - SGN_LAMBDA(step[k]); + } + } + for (i = 0; i < m - 1; i++) + { /* sort by s */ + for (j = i + 1; j < m; j++) + { + if (s[i] < s[j]) continue; + SWAP_LAMBDA(s[i], s[j]); + for (k = 0; k < n; k++) SWAP_LAMBDA(zn[k + i * n], zn[k + j * n]); + } + } + free(S); + free(dist); + free(zb); + free(z); + free(step); + + if (c >= LOOPMAX) + { + fprintf(stderr, "%s : search loop count overflow\n", __FILE__); + return -1; + } + return 0; +} + + +/* lambda/mlambda integer least-square estimation ------------------------------ + * integer least-square estimation. reduction is performed by lambda (ref.[1]), + * and search by mlambda (ref.[2]). + * args : int n I number of float parameters + * int m I number of fixed solutions + * double *a I float parameters (n x 1) + * double *Q I covariance matrix of float parameters (n x n) + * double *F O fixed solutions (n x m) + * double *s O sum of squared residulas of fixed solutions (1 x m) + * return : status (0:ok,other:error) + * notes : matrix stored by column-major order (fortran convension) + *-----------------------------------------------------------------------------*/ +int lambda(int n, int m, const double *a, const double *Q, double *F, + double *s) +{ + int info; + double *L, *D, *Z, *z, *E; + + if (n <= 0 || m <= 0) return -1; + L = zeros(n, n); + D = mat(n, 1); + Z = eye(n); + z = mat(n, 1); + E = mat(n, m); + + /* LD factorization */ + if (!(info = LD(n, Q, L, D))) + { + /* lambda reduction */ + reduction(n, L, D, Z); + matmul("TN", n, 1, n, 1.0, Z, a, 0.0, z); /* z=Z'*a */ + + /* mlambda search */ + if (!(info = search(n, m, L, D, z, E, s))) + { + info = solve("T", Z, E, n, m, F); /* F=Z'\E */ + } + } + free(L); + free(D); + free(Z); + free(z); + free(E); + return info; +} + + +/* lambda reduction ------------------------------------------------------------ + * reduction by lambda (ref [1]) for integer least square + * args : int n I number of float parameters + * double *Q I covariance matrix of float parameters (n x n) + * double *Z O lambda reduction matrix (n x n) + * return : status (0:ok,other:error) + *-----------------------------------------------------------------------------*/ +int lambda_reduction(int n, const double *Q, double *Z) +{ + double *L, *D; + int i, j, info; + + if (n <= 0) return -1; + + L = zeros(n, n); + D = mat(n, 1); + + for (i = 0; i < n; i++) + for (j = 0; j < n; j++) + { + Z[i + j * n] = i == j ? 1.0 : 0.0; + } + /* LD factorization */ + if ((info = LD(n, Q, L, D))) + { + free(L); + free(D); + return info; + } + /* lambda reduction */ + reduction(n, L, D, Z); + + free(L); + free(D); + return 0; +} + + +/* mlambda search -------------------------------------------------------------- + * search by mlambda (ref [2]) for integer least square + * args : int n I number of float parameters + * int m I number of fixed solutions + * double *a I float parameters (n x 1) + * double *Q I covariance matrix of float parameters (n x n) + * double *F O fixed solutions (n x m) + * double *s O sum of squared residulas of fixed solutions (1 x m) + * return : status (0:ok,other:error) + *-----------------------------------------------------------------------------*/ +int lambda_search(int n, int m, const double *a, const double *Q, + double *F, double *s) +{ + double *L, *D; + int info; + + if (n <= 0 || m <= 0) return -1; + + L = zeros(n, n); + D = mat(n, 1); + + /* LD factorization */ + if ((info = LD(n, Q, L, D))) + { + free(L); + free(D); + return info; + } + /* mlambda search */ + info = search(n, m, L, D, a, F, s); + + free(L); + free(D); + return info; +} diff --git a/src/algorithms/libs/rtklib/rtklib_lambda.h b/src/algorithms/libs/rtklib/rtklib_lambda.h new file mode 100644 index 000000000..7c9fa18bf --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_lambda.h @@ -0,0 +1,95 @@ +/*! + * \file rtklib_lambda.h + * \brief Integer ambiguity resolution + * \authors
          + *
        • 2007-2008, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2008, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * References: + * [1] P.J.G.Teunissen, The least-square ambiguity decorrelation adjustment: + * a method for fast GPS ambiguity estimation, J.Geodesy, Vol.70, 65-82, + * 1995 + * [2] X.-W.Chang, X.Yang, T.Zhou, MLAMBDA: A modified LAMBDA method for + * integer least-squares estimation, J.Geodesy, Vol.79, 552-565, 2005 + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_LAMBDA_H_ +#define GNSS_SDR_RTKLIB_LAMBDA_H_ + + +#include "rtklib.h" + +/* constants/macros ----------------------------------------------------------*/ +const int LOOPMAX = 10000; /* maximum count of search loop */ +#define SGN_LAMBDA(x) ((x) <= 0.0 ? -1.0 : 1.0) +#define ROUND_LAMBDA(x) (floor((x) + 0.5)) +#define SWAP_LAMBDA(x, y) \ + do \ + { \ + double tmp_; \ + tmp_ = x; \ + x = y; \ + y = tmp_; \ + } \ + while (0) + +int LD(int n, const double *Q, double *L, double *D); +void gauss(int n, double *L, double *Z, int i, int j); +void perm(int n, double *L, double *D, int j, double del, double *Z); +void reduction(int n, double *L, double *D, double *Z); +int search(int n, int m, const double *L, const double *D, + const double *zs, double *zn, double *s); + +int lambda(int n, int m, const double *a, const double *Q, double *F, double *s); + +int lambda_reduction(int n, const double *Q, double *Z); + +int lambda_search(int n, int m, const double *a, const double *Q, + double *F, double *s); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_pntpos.cc b/src/algorithms/libs/rtklib/rtklib_pntpos.cc new file mode 100644 index 000000000..016037f77 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_pntpos.cc @@ -0,0 +1,915 @@ +/*! + * \file rtklib_pntpos.cc + * \brief standard code-based positioning + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_pntpos.h" +#include "rtklib_ephemeris.h" +#include "rtklib_ionex.h" +#include "rtklib_sbas.h" + +/* pseudorange measurement error variance ------------------------------------*/ +double varerr(const prcopt_t *opt, double el, int sys) +{ + double fact, varr; + fact = sys == SYS_GLO ? EFACT_GLO : (sys == SYS_SBS ? EFACT_SBS : EFACT_GPS); + varr = std::pow(opt->err[0], 2.0) * (std::pow(opt->err[1], 2.0) + std::pow(opt->err[2], 2.0) / sin(el)); + if (opt->ionoopt == IONOOPT_IFLC) varr *= std::pow(2, 3.0); /* iono-free */ + return std::pow(fact, 2.0) * varr; +} + + +/* get tgd parameter (m) -----------------------------------------------------*/ +double gettgd(int sat, const nav_t *nav) +{ + int i; + for (i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].tgd[0]; + } + return 0.0; +} + +/* get isc parameter (m) -----------------------------------------------------*/ +double getiscl1(int sat, const nav_t *nav) +{ + for (int i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].isc[0]; + } + return 0.0; +} + +double getiscl2(int sat, const nav_t *nav) +{ + for (int i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].isc[1]; + } + return 0.0; +} + +double getiscl5i(int sat, const nav_t *nav) +{ + for (int i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].isc[2]; + } + return 0.0; +} + +double getiscl5q(int sat, const nav_t *nav) +{ + for (int i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].isc[3]; + } + return 0.0; +} + +/* psendorange with code bias correction -------------------------------------*/ +double prange(const obsd_t *obs, const nav_t *nav, const double *azel, + int iter, const prcopt_t *opt, double *var) +{ + const double *lam = nav->lam[obs->sat - 1]; + double PC = 0.0; + double P1 = 0.0; + double P2 = 0.0; + double P1_P2 = 0.0; + double P1_C1 = 0.0; + double P2_C2 = 0.0; + // Intersignal corrections (m). See GPS IS-200 CNAV message + //double ISCl1 = 0.0; + double ISCl2 = 0.0; + double ISCl5i = 0.0; + //double ISCl5q = 0.0; + double gamma_ = 0.0; + int i = 0; + int j = 1; + int sys = satsys(obs->sat, nullptr); + *var = 0.0; + + if (sys == SYS_NONE) + { + trace(4, "prange: satsys NULL\n"); + return 0.0; + } + + + /* L1-L2 for GPS/GLO/QZS, L1-L5 for GAL/SBS */ + if (sys == SYS_GAL or sys == SYS_SBS) + { + j = 2; + } + else if (sys == SYS_GPS or sys == SYS_GLO) + { + if (obs->code[1] != CODE_NONE) + { + j = 1; + } + else if (obs->code[2] != CODE_NONE) + { + j = 2; + } + } + + if (lam[i] == 0.0 or lam[j] == 0.0) + { + trace(4, "prange: NFREQ<2||lam[i]==0.0||lam[j]==0.0\n"); + printf("i: %d j:%d, lam[i]: %f lam[j] %f\n", i, j, lam[i], lam[j]); + return 0.0; + } + + /* test snr mask */ + if (iter > 0) + { + if (testsnr(0, i, azel[1], obs->SNR[i] * 0.25, &opt->snrmask)) + { + trace(4, "snr mask: %s sat=%2d el=%.1f snr=%.1f\n", + time_str(obs->time, 0), obs->sat, azel[1] * R2D, obs->SNR[i] * 0.25); + return 0.0; + } + if (opt->ionoopt == IONOOPT_IFLC) + { + if (testsnr(0, j, azel[1], obs->SNR[j] * 0.25, &opt->snrmask)) + { + trace(4, "prange: testsnr error\n"); + return 0.0; + } + } + } + /* fL1^2 / fL2(orL5)^2 . See IS-GPS-200, p. 103 and Galileo ICD p. 48 */ + if (sys == SYS_GPS or sys == SYS_GAL or sys == SYS_GLO) + { + gamma_ = std::pow(lam[j], 2.0) / std::pow(lam[i], 2.0); + } + P1 = obs->P[i]; + P2 = obs->P[j]; + P1_P2 = nav->cbias[obs->sat - 1][0]; + P1_C1 = nav->cbias[obs->sat - 1][1]; + P2_C2 = nav->cbias[obs->sat - 1][2]; + + /* if no P1-P2 DCB, use TGD instead */ + if (P1_P2 == 0.0) + { + P1_P2 = gettgd(obs->sat, nav); + } + + if (sys == SYS_GPS) + { + // ISCl1 = getiscl1(obs->sat, nav); + ISCl2 = getiscl2(obs->sat, nav); + ISCl5i = getiscl5i(obs->sat, nav); + // ISCl5q = getiscl5q(obs->sat, nav); + } + + //CHECK IF IT IS STILL NEEDED + if (opt->ionoopt == IONOOPT_IFLC) + { /* dual-frequency */ + + if (P1 == 0.0 || P2 == 0.0) + { + return 0.0; + } + if (obs->code[i] == CODE_L1C) + { + P1 += P1_C1; + } /* C1->P1 */ + if (obs->code[j] == CODE_L2C) + { + P2 += P2_C2; + } /* C2->P2 */ + + /* iono-free combination */ + PC = (gamma_ * P1 - P2) / (gamma_ - 1.0); + } + //////////////////////////////////////////// + else + { /* single-frequency */ + if (obs->code[i] == CODE_NONE and obs->code[j] == CODE_NONE) + { + return 0.0; + } + + if (obs->code[i] != CODE_NONE and obs->code[j] == CODE_NONE) + { + P1 += P1_C1; /* C1->P1 */ + PC = P1 - P1_P2; + } + else if (obs->code[i] == CODE_NONE and obs->code[j] != CODE_NONE) + { + if (sys == SYS_GPS) + { + P2 += P2_C2; /* C2->P2 */ + //PC = P2 - gamma_ * P1_P2 / (1.0 - gamma_); + if (obs->code[j] == CODE_L2S) //L2 single freq. + { + PC = P2 + P1_P2 - ISCl2; + } + else if (obs->code[j] == CODE_L5X) //L5 single freq. + { + PC = P2 + P1_P2 - ISCl5i; + } + } + else if (sys == SYS_GAL or sys == SYS_GLO) // Gal. E5a single freq. + { + P2 += P2_C2; /* C2->P2 */ + PC = P2 - gamma_ * P1_P2 / (1.0 - gamma_); + } + } + /* dual-frequency */ + else if (sys == SYS_GPS) + { + if (obs->code[j] == CODE_L2S) /* L1 + L2 */ + { + //By the moment, GPS L2 pseudoranges are not used + //PC = (P2 + ISCl2 - gamma_ * (P1 + ISCl1)) / (1.0 - gamma_) - P1_P2; + P1 += P1_C1; /* C1->P1 */ + PC = P1 + P1_P2; + } + else if (obs->code[j] == CODE_L5X) /* L1 + L5 */ + { + //By the moment, GPS L5 pseudoranges are not used + //PC = (P2 + ISCl5i - gamma_ * (P1 + ISCl5i)) / (1.0 - gamma_) - P1_P2; + P1 += P1_C1; /* C1->P1 */ + PC = P1 + P1_P2; + } + } + else if (sys == SYS_GAL or sys == SYS_GLO) /* E1 + E5a */ + { + P1 += P1_C1; + P2 += P2_C2; + PC = (gamma_ * P1 - P2) / (gamma_ - 1.0); + } + } + if (opt->sateph == EPHOPT_SBAS) + { + PC -= P1_C1; + } /* sbas clock based C1 */ + *var = std::pow(ERR_CBIAS, 2.0); + return PC; +} + + +/* ionospheric correction ------------------------------------------------------ + * compute ionospheric correction + * args : gtime_t time I time + * nav_t *nav I navigation data + * int sat I satellite number + * double *pos I receiver position {lat,lon,h} (rad|m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * int ionoopt I ionospheric correction option (IONOOPT_???) + * double *ion O ionospheric delay (L1) (m) + * double *var O ionospheric delay (L1) variance (m^2) + * return : status(1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, + const double *azel, int ionoopt, double *ion, double *var) +{ + trace(4, "ionocorr: time=%s opt=%d sat=%2d pos=%.3f %.3f azel=%.3f %.3f\n", + time_str(time, 3), ionoopt, sat, pos[0] * R2D, pos[1] * R2D, azel[0] * R2D, + azel[1] * R2D); + + /* broadcast model */ + if (ionoopt == IONOOPT_BRDC) + { + *ion = ionmodel(time, nav->ion_gps, pos, azel); + *var = std::pow(*ion * ERR_BRDCI, 2.0); + return 1; + } + /* sbas ionosphere model */ + if (ionoopt == IONOOPT_SBAS) + { + return sbsioncorr(time, nav, pos, azel, ion, var); + } + /* ionex tec model */ + if (ionoopt == IONOOPT_TEC) + { + return iontec(time, nav, pos, azel, 1, ion, var); + } + /* qzss broadcast model */ + if (ionoopt == IONOOPT_QZS && norm_rtk(nav->ion_qzs, 8) > 0.0) + { + *ion = ionmodel(time, nav->ion_qzs, pos, azel); + *var = std::pow(*ion * ERR_BRDCI, 2.0); + return 1; + } + /* lex ionosphere model */ + //if (ionoopt == IONOOPT_LEX) { + // return lexioncorr(time, nav, pos, azel, ion, var); + //} + *ion = 0.0; + *var = ionoopt == IONOOPT_OFF ? std::pow(ERR_ION, 2.0) : 0.0; + return 1; +} + + +/* tropospheric correction ----------------------------------------------------- + * compute tropospheric correction + * args : gtime_t time I time + * nav_t *nav I navigation data + * double *pos I receiver position {lat,lon,h} (rad|m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * int tropopt I tropospheric correction option (TROPOPT_???) + * double *trp O tropospheric delay (m) + * double *var O tropospheric delay variance (m^2) + * return : status(1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int tropcorr(gtime_t time, const nav_t *nav __attribute__((unused)), const double *pos, + const double *azel, int tropopt, double *trp, double *var) +{ + trace(4, "tropcorr: time=%s opt=%d pos=%.3f %.3f azel=%.3f %.3f\n", + time_str(time, 3), tropopt, pos[0] * R2D, pos[1] * R2D, azel[0] * R2D, + azel[1] * R2D); + + /* saastamoinen model */ + if (tropopt == TROPOPT_SAAS || tropopt == TROPOPT_EST || tropopt == TROPOPT_ESTG) + { + *trp = tropmodel(time, pos, azel, REL_HUMI); + *var = std::pow(ERR_SAAS / (sin(azel[1]) + 0.1), 2.0); + return 1; + } + /* sbas troposphere model */ + if (tropopt == TROPOPT_SBAS) + { + *trp = sbstropcorr(time, pos, azel, var); + return 1; + } + /* no correction */ + *trp = 0.0; + *var = tropopt == TROPOPT_OFF ? std::pow(ERR_TROP, 2.0) : 0.0; + return 1; +} + + +/* pseudorange residuals -----------------------------------------------------*/ +int rescode(int iter, const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const double *x, const prcopt_t *opt, + double *v, double *H, double *var, double *azel, int *vsat, + double *resp, int *ns) +{ + double r, dion, dtrp, vmeas, vion, vtrp, rr[3], pos[3], dtr, e[3], P, lam_L1; + int i, j, nv = 0, sys, mask[4] = {0}; + + trace(3, "resprng : n=%d\n", n); + + for (i = 0; i < 3; i++) rr[i] = x[i]; + dtr = x[3]; + + ecef2pos(rr, pos); + + for (i = *ns = 0; i < n && i < MAXOBS; i++) + { + vsat[i] = 0; + azel[i * 2] = azel[1 + i * 2] = resp[i] = 0.0; + + if (!(sys = satsys(obs[i].sat, nullptr))) continue; + + /* reject duplicated observation data */ + if (i < n - 1 && i < MAXOBS - 1 && obs[i].sat == obs[i + 1].sat) + { + trace(2, "duplicated observation data %s sat=%2d\n", + time_str(obs[i].time, 3), obs[i].sat); + i++; + continue; + } + /* geometric distance/azimuth/elevation angle */ + if ((r = geodist(rs + i * 6, rr, e)) <= 0.0) + { + trace(4, "geodist error\n"); + continue; + } + double elaux = satazel(pos, e, azel + i * 2); + if (elaux < opt->elmin) + { + trace(4, "satazel error. el = %lf , elmin = %lf\n", elaux, opt->elmin); + continue; + } + /* psudorange with code bias correction */ + if ((P = prange(obs + i, nav, azel + i * 2, iter, opt, &vmeas)) == 0.0) + { + trace(4, "prange error\n"); + continue; + } + + /* excluded satellite? */ + if (satexclude(obs[i].sat, svh[i], opt)) + { + trace(4, "satexclude error\n"); + continue; + } + + /* ionospheric corrections */ + if (!ionocorr(obs[i].time, nav, obs[i].sat, pos, azel + i * 2, + iter > 0 ? opt->ionoopt : IONOOPT_BRDC, &dion, &vion)) + { + trace(4, "ionocorr error\n"); + continue; + } + + /* GPS-L1 -> L1/B1 */ + if ((lam_L1 = nav->lam[obs[i].sat - 1][0]) > 0.0) + { + dion *= std::pow(lam_L1 / lam_carr[0], 2.0); + } + /* tropospheric corrections */ + if (!tropcorr(obs[i].time, nav, pos, azel + i * 2, + iter > 0 ? opt->tropopt : TROPOPT_SAAS, &dtrp, &vtrp)) + { + trace(4, "tropocorr error\n"); + continue; + } + /* pseudorange residual */ + v[nv] = P - (r + dtr - SPEED_OF_LIGHT * dts[i * 2] + dion + dtrp); + + /* design matrix */ + for (j = 0; j < NX; j++) H[j + nv * NX] = j < 3 ? -e[j] : (j == 3 ? 1.0 : 0.0); + + /* time system and receiver bias offset correction */ + if (sys == SYS_GLO) + { + v[nv] -= x[4]; + H[4 + nv * NX] = 1.0; + mask[1] = 1; + } + else if (sys == SYS_GAL) + { + v[nv] -= x[5]; + H[5 + nv * NX] = 1.0; + mask[2] = 1; + } + else if (sys == SYS_BDS) + { + v[nv] -= x[6]; + H[6 + nv * NX] = 1.0; + mask[3] = 1; + } + else + mask[0] = 1; + + vsat[i] = 1; + resp[i] = v[nv]; + (*ns)++; + + /* error variance */ + var[nv++] = varerr(opt, azel[1 + i * 2], sys) + vare[i] + vmeas + vion + vtrp; + + trace(4, "sat=%2d azel=%5.1f %4.1f res=%7.3f sig=%5.3f\n", obs[i].sat, + azel[i * 2] * R2D, azel[1 + i * 2] * R2D, resp[i], sqrt(var[nv - 1])); + } + /* constraint to avoid rank-deficient */ + for (i = 0; i < 4; i++) + { + if (mask[i]) continue; + v[nv] = 0.0; + for (j = 0; j < NX; j++) H[j + nv * NX] = j == i + 3 ? 1.0 : 0.0; + var[nv++] = 0.01; + } + return nv; +} + + +/* validate solution ---------------------------------------------------------*/ +int valsol(const double *azel, const int *vsat, int n, + const prcopt_t *opt, const double *v, int nv, int nx, + char *msg) +{ + double azels[MAXOBS * 2] = {0}; + double dop[4], vv; + int i, ns; + + trace(3, "valsol : n=%d nv=%d\n", n, nv); + + /* chi-square validation of residuals */ + vv = dot(v, v, nv); + if (nv > nx && vv > chisqr[nv - nx - 1]) + { + sprintf(msg, "chi-square error nv=%d vv=%.1f cs=%.1f", nv, vv, chisqr[nv - nx - 1]); + return 0; + } + /* large gdop check */ + for (i = ns = 0; i < n; i++) + { + if (!vsat[i]) continue; + azels[ns * 2] = azel[i * 2]; + azels[1 + ns * 2] = azel[1 + i * 2]; + ns++; + } + dops(ns, azels, opt->elmin, dop); + if (dop[0] <= 0.0 || dop[0] > opt->maxgdop) + { + sprintf(msg, "gdop error nv=%d gdop=%.1f", nv, dop[0]); + return 0; + } + return 1; +} + + +/* estimate receiver position ------------------------------------------------*/ +int estpos(const obsd_t *obs, int n, const double *rs, const double *dts, + const double *vare, const int *svh, const nav_t *nav, + const prcopt_t *opt, sol_t *sol, double *azel, int *vsat, + double *resp, char *msg) +{ + double x[NX] = {0}, dx[NX], Q[NX * NX], *v, *H, *var, sig; + int i, j, k, info, stat, nv, ns; + + trace(3, "estpos : n=%d\n", n); + + v = mat(n + 4, 1); + H = mat(NX, n + 4); + var = mat(n + 4, 1); + + for (i = 0; i < 3; i++) x[i] = sol->rr[i]; + + for (i = 0; i < MAXITR; i++) + { + /* pseudorange residuals */ + nv = rescode(i, obs, n, rs, dts, vare, svh, nav, x, opt, v, H, var, azel, vsat, resp, &ns); + + if (nv < NX) + { + sprintf(msg, "lack of valid sats ns=%d", nv); + break; + } + /* weight by variance */ + for (j = 0; j < nv; j++) + { + sig = sqrt(var[j]); + v[j] /= sig; + for (k = 0; k < NX; k++) H[k + j * NX] /= sig; + } + /* least square estimation */ + if ((info = lsq(H, v, NX, nv, dx, Q))) + { + sprintf(msg, "lsq error info=%d", info); + break; + } + for (j = 0; j < NX; j++) x[j] += dx[j]; + + if (norm_rtk(dx, NX) < 1e-4) + { + sol->type = 0; + sol->time = timeadd(obs[0].time, -x[3] / SPEED_OF_LIGHT); + sol->dtr[0] = x[3] / SPEED_OF_LIGHT; /* receiver clock bias (s) */ + sol->dtr[1] = x[4] / SPEED_OF_LIGHT; /* glo-gps time offset (s) */ + sol->dtr[2] = x[5] / SPEED_OF_LIGHT; /* gal-gps time offset (s) */ + sol->dtr[3] = x[6] / SPEED_OF_LIGHT; /* bds-gps time offset (s) */ + for (j = 0; j < 6; j++) sol->rr[j] = j < 3 ? x[j] : 0.0; + for (j = 0; j < 3; j++) sol->qr[j] = static_cast(Q[j + j * NX]); + sol->qr[3] = static_cast(Q[1]); /* cov xy */ + sol->qr[4] = static_cast(Q[2 + NX]); /* cov yz */ + sol->qr[5] = static_cast(Q[2]); /* cov zx */ + sol->ns = static_cast(ns); + sol->age = sol->ratio = 0.0; + + /* validate solution */ + if ((stat = valsol(azel, vsat, n, opt, v, nv, NX, msg))) + { + sol->stat = opt->sateph == EPHOPT_SBAS ? SOLQ_SBAS : SOLQ_SINGLE; + } + free(v); + free(H); + free(var); + + return stat; + } + } + if (i >= MAXITR) sprintf(msg, "iteration divergent i=%d", i); + + free(v); + free(H); + free(var); + + return 0; +} + + +/* raim fde (failure detection and exclution) -------------------------------*/ +int raim_fde(const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const prcopt_t *opt, sol_t *sol, + double *azel, int *vsat, double *resp, char *msg) +{ + obsd_t *obs_e; + sol_t sol_e = {{0, 0}, {}, {}, {}, '0', '0', '0', 0.0, 0.0, 0.0}; + char tstr[32], name[16], msg_e[128]; + double *rs_e, *dts_e, *vare_e, *azel_e, *resp_e, rms_e, rms = 100.0; + int i, j, k, nvsat, stat = 0, *svh_e, *vsat_e, sat = 0; + + trace(3, "raim_fde: %s n=%2d\n", time_str(obs[0].time, 0), n); + + if (!(obs_e = static_cast(malloc(sizeof(obsd_t) * n)))) return 0; + rs_e = mat(6, n); + dts_e = mat(2, n); + vare_e = mat(1, n); + azel_e = zeros(2, n); + svh_e = imat(1, n); + vsat_e = imat(1, n); + resp_e = mat(1, n); + + for (i = 0; i < n; i++) + { + /* satellite exclution */ + for (j = k = 0; j < n; j++) + { + if (j == i) continue; + obs_e[k] = obs[j]; + matcpy(rs_e + 6 * k, rs + 6 * j, 6, 1); + matcpy(dts_e + 2 * k, dts + 2 * j, 2, 1); + vare_e[k] = vare[j]; + svh_e[k++] = svh[j]; + } + /* estimate receiver position without a satellite */ + if (!estpos(obs_e, n - 1, rs_e, dts_e, vare_e, svh_e, nav, opt, &sol_e, azel_e, + vsat_e, resp_e, msg_e)) + { + trace(3, "raim_fde: exsat=%2d (%s)\n", obs[i].sat, msg); + continue; + } + for (j = nvsat = 0, rms_e = 0.0; j < n - 1; j++) + { + if (!vsat_e[j]) continue; + rms_e += std::pow(resp_e[j], 2.0); + nvsat++; + } + if (nvsat < 5) + { + trace(3, "raim_fde: exsat=%2d lack of satellites nvsat=%2d\n", + obs[i].sat, nvsat); + continue; + } + rms_e = sqrt(rms_e / nvsat); + + trace(3, "raim_fde: exsat=%2d rms=%8.3f\n", obs[i].sat, rms_e); + + if (rms_e > rms) continue; + + /* save result */ + for (j = k = 0; j < n; j++) + { + if (j == i) continue; + matcpy(azel + 2 * j, azel_e + 2 * k, 2, 1); + vsat[j] = vsat_e[k]; + resp[j] = resp_e[k++]; + } + stat = 1; + *sol = sol_e; + sat = obs[i].sat; + rms = rms_e; + vsat[i] = 0; + strcpy(msg, msg_e); + } + if (stat) + { + time2str(obs[0].time, tstr, 2); + satno2id(sat, name); + trace(2, "%s: %s excluded by raim\n", tstr + 11, name); + } + free(obs_e); + free(rs_e); + free(dts_e); + free(vare_e); + free(azel_e); + free(svh_e); + free(vsat_e); + free(resp_e); + + return stat; +} + + +/* doppler residuals ---------------------------------------------------------*/ +int resdop(const obsd_t *obs, int n, const double *rs, const double *dts, + const nav_t *nav, const double *rr, const double *x, + const double *azel, const int *vsat, double *v, double *H) +{ + double lam, rate, pos[3], E[9], a[3], e[3], vs[3], cosel; + int i, j, nv = 0; + int band = 0; + + trace(3, "resdop : n=%d\n", n); + + ecef2pos(rr, pos); + xyz2enu(pos, E); + + for (i = 0; i < n && i < MAXOBS; i++) + { + if (obs[i].code[0] != CODE_NONE) band = 0; + if (obs[i].code[1] != CODE_NONE) band = 1; + if (obs[i].code[2] != CODE_NONE) band = 2; + lam = nav->lam[obs[i].sat - 1][band]; + + if (obs[i].D[band] == 0.0 || lam == 0.0 || !vsat[i] || norm_rtk(rs + 3 + i * 6, 3) <= 0.0) + { + continue; + } + /* line-of-sight vector in ecef */ + cosel = cos(azel[1 + i * 2]); + a[0] = sin(azel[i * 2]) * cosel; + a[1] = cos(azel[i * 2]) * cosel; + a[2] = sin(azel[1 + i * 2]); + matmul("TN", 3, 1, 3, 1.0, E, a, 0.0, e); + + /* satellite velocity relative to receiver in ecef */ + for (j = 0; j < 3; j++) vs[j] = rs[j + 3 + i * 6] - x[j]; + + /* range rate with earth rotation correction */ + rate = dot(vs, e, 3) + DEFAULT_OMEGA_EARTH_DOT / SPEED_OF_LIGHT * (rs[4 + i * 6] * rr[0] + rs[1 + i * 6] * x[0] - rs[3 + i * 6] * rr[1] - rs[i * 6] * x[1]); + + /* doppler residual */ + v[nv] = -lam * obs[i].D[band] - (rate + x[3] - SPEED_OF_LIGHT * dts[1 + i * 2]); + + /* design matrix */ + for (j = 0; j < 4; j++) H[j + nv * 4] = j < 3 ? -e[j] : 1.0; + + nv++; + } + return nv; +} + + +/* estimate receiver velocity ------------------------------------------------*/ +void estvel(const obsd_t *obs, int n, const double *rs, const double *dts, + const nav_t *nav, const prcopt_t *opt __attribute__((unused)), sol_t *sol, + const double *azel, const int *vsat) +{ + double x[4] = {0}, dx[4], Q[16], *v, *H; + int i, j, nv; + + trace(3, "estvel : n=%d\n", n); + + v = mat(n, 1); + H = mat(4, n); + + for (i = 0; i < MAXITR; i++) + { + /* doppler residuals */ + if ((nv = resdop(obs, n, rs, dts, nav, sol->rr, x, azel, vsat, v, H)) < 4) + { + break; + } + /* least square estimation */ + if (lsq(H, v, 4, nv, dx, Q)) break; + + for (j = 0; j < 4; j++) x[j] += dx[j]; + + if (norm_rtk(dx, 4) < 1e-6) + { + for (i = 0; i < 3; i++) sol->rr[i + 3] = x[i]; + break; + } + } + free(v); + free(H); +} + + +/* single-point positioning ---------------------------------------------------- + * compute receiver position, velocity, clock bias by single-point positioning + * with pseudorange and doppler observables + * args : obsd_t *obs I observation data + * int n I number of observation data + * nav_t *nav I navigation data + * prcopt_t *opt I processing options + * sol_t *sol IO solution + * double *azel IO azimuth/elevation angle (rad) (NULL: no output) + * ssat_t *ssat IO satellite status (NULL: no output) + * char *msg O error message for error exit + * return : status(1:ok,0:error) + * notes : assuming sbas-gps, galileo-gps, qzss-gps, compass-gps time offset and + * receiver bias are negligible (only involving glonass-gps time offset + * and receiver bias) + *-----------------------------------------------------------------------------*/ +int pntpos(const obsd_t *obs, int n, const nav_t *nav, + const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat, + char *msg) +{ + prcopt_t opt_ = *opt; + double *rs, *dts, *var, *azel_, *resp; + int i, stat, vsat[MAXOBS] = {0}, svh[MAXOBS]; + + sol->stat = SOLQ_NONE; + + if (n <= 0) + { + strcpy(msg, "no observation data"); + return 0; + } + + trace(3, "pntpos : tobs=%s n=%d\n", time_str(obs[0].time, 3), n); + + sol->time = obs[0].time; + msg[0] = '\0'; + + rs = mat(6, n); + dts = mat(2, n); + var = mat(1, n); + azel_ = zeros(2, n); + resp = mat(1, n); + + if (opt_.mode != PMODE_SINGLE) + { /* for precise positioning */ +#if 0 + opt_.sateph = EPHOPT_BRDC; +#endif + opt_.ionoopt = IONOOPT_BRDC; + opt_.tropopt = TROPOPT_SAAS; + } + /* satellite positions, velocities and clocks */ + satposs(sol->time, obs, n, nav, opt_.sateph, rs, dts, var, svh); + + /* estimate receiver position with pseudorange */ + stat = estpos(obs, n, rs, dts, var, svh, nav, &opt_, sol, azel_, vsat, resp, msg); + + /* raim fde */ + if (!stat && n >= 6 && opt->posopt[4]) + { + stat = raim_fde(obs, n, rs, dts, var, svh, nav, &opt_, sol, azel_, vsat, resp, msg); + } + /* estimate receiver velocity with doppler */ + if (stat) estvel(obs, n, rs, dts, nav, &opt_, sol, azel_, vsat); + + if (azel) + { + for (i = 0; i < n * 2; i++) azel[i] = azel_[i]; + } + if (ssat) + { + for (i = 0; i < MAXSAT; i++) + { + ssat[i].vs = 0; + ssat[i].azel[0] = ssat[i].azel[1] = 0.0; + ssat[i].resp[0] = ssat[i].resc[0] = 0.0; + ssat[i].snr[0] = 0; + } + for (i = 0; i < n; i++) + { + ssat[obs[i].sat - 1].azel[0] = azel_[i * 2]; + ssat[obs[i].sat - 1].azel[1] = azel_[1 + i * 2]; + ssat[obs[i].sat - 1].snr[0] = obs[i].SNR[0]; + if (!vsat[i]) continue; + ssat[obs[i].sat - 1].vs = 1; + ssat[obs[i].sat - 1].resp[0] = resp[i]; + } + } + free(rs); + free(dts); + free(var); + free(azel_); + free(resp); + return stat; +} diff --git a/src/algorithms/libs/rtklib/rtklib_pntpos.h b/src/algorithms/libs/rtklib/rtklib_pntpos.h new file mode 100644 index 000000000..13becebef --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_pntpos.h @@ -0,0 +1,165 @@ +/*! + * \file rtklib_pntpos.h + * \brief standard code-based positioning + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_PNTPOS_H_ +#define GNSS_SDR_RTKLIB_PNTPOS_H_ + +#include "rtklib.h" +#include "rtklib_rtkcmn.h" + +/* constants -----------------------------------------------------------------*/ +const int NX = 4 + 3; //!< # of estimated parameters +const int MAXITR = 10; //!< max number of iteration for point pos +const double ERR_ION = 5.0; //!< ionospheric delay std (m) +const double ERR_TROP = 3.0; //!< tropspheric delay std (m) + + +/* pseudorange measurement error variance ------------------------------------*/ +double varerr(const prcopt_t *opt, double el, int sys); + +/* get tgd parameter (m) -----------------------------------------------------*/ +double gettgd(int sat, const nav_t *nav); + +/* get isc parameter (m) -----------------------------------------------------*/ +double getiscl1(int sat, const nav_t *nav); +double getiscl2(int sat, const nav_t *nav); +double getiscl5i(int sat, const nav_t *nav); +double getiscl5q(int sat, const nav_t *nav); + +/* psendorange with code bias correction -------------------------------------*/ +double prange(const obsd_t *obs, const nav_t *nav, const double *azel, + int iter, const prcopt_t *opt, double *var); + +/* ionospheric correction ------------------------------------------------------ +* compute ionospheric correction +* args : gtime_t time I time +* nav_t *nav I navigation data +* int sat I satellite number +* double *pos I receiver position {lat,lon,h} (rad|m) +* double *azel I azimuth/elevation angle {az,el} (rad) +* int ionoopt I ionospheric correction option (IONOOPT_???) +* double *ion O ionospheric delay (L1) (m) +* double *var O ionospheric delay (L1) variance (m^2) +* return : status(1:ok,0:error) +*-----------------------------------------------------------------------------*/ +int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, + const double *azel, int ionoopt, double *ion, double *var); +/* tropospheric correction ----------------------------------------------------- +* compute tropospheric correction +* args : gtime_t time I time +* nav_t *nav I navigation data +* double *pos I receiver position {lat,lon,h} (rad|m) +* double *azel I azimuth/elevation angle {az,el} (rad) +* int tropopt I tropospheric correction option (TROPOPT_???) +* double *trp O tropospheric delay (m) +* double *var O tropospheric delay variance (m^2) +* return : status(1:ok,0:error) +*-----------------------------------------------------------------------------*/ +int tropcorr(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, int tropopt, double *trp, double *var); + +/* pseudorange residuals -----------------------------------------------------*/ +int rescode(int iter, const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const double *x, const prcopt_t *opt, + double *v, double *H, double *var, double *azel, int *vsat, + double *resp, int *ns); + +/* validate solution ---------------------------------------------------------*/ +int valsol(const double *azel, const int *vsat, int n, + const prcopt_t *opt, const double *v, int nv, int nx, + char *msg); + +/* estimate receiver position ------------------------------------------------*/ +int estpos(const obsd_t *obs, int n, const double *rs, const double *dts, + const double *vare, const int *svh, const nav_t *nav, + const prcopt_t *opt, sol_t *sol, double *azel, int *vsat, + double *resp, char *msg); + +/* raim fde (failure detection and exclution) -------------------------------*/ +int raim_fde(const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const prcopt_t *opt, sol_t *sol, + double *azel, int *vsat, double *resp, char *msg); + +/* doppler residuals ---------------------------------------------------------*/ +int resdop(const obsd_t *obs, int n, const double *rs, const double *dts, + const nav_t *nav, const double *rr, const double *x, + const double *azel, const int *vsat, double *v, double *H); + +/* estimate receiver velocity ------------------------------------------------*/ +void estvel(const obsd_t *obs, int n, const double *rs, const double *dts, + const nav_t *nav, const prcopt_t *opt, sol_t *sol, + const double *azel, const int *vsat); + +/*! +* \brief single-point positioning +* compute receiver position, velocity, clock bias by single-point positioning +* with pseudorange and doppler observables +* args : obsd_t *obs I observation data +* int n I number of observation data +* nav_t *nav I navigation data +* prcopt_t *opt I processing options +* sol_t *sol IO solution +* double *azel IO azimuth/elevation angle (rad) (NULL: no output) +* ssat_t *ssat IO satellite status (NULL: no output) +* char *msg O error message for error exit +* return : status(1:ok,0:error) +* notes : assuming sbas-gps, galileo-gps, qzss-gps, compass-gps time offset and +* receiver bias are negligible (only involving glonass-gps time offset +* and receiver bias) +*/ +int pntpos(const obsd_t *obs, int n, const nav_t *nav, + const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat, + char *msg); + +#endif /* GNSS_SDR_RTKLIB_PNTPOS_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_ppp.cc b/src/algorithms/libs/rtklib/rtklib_ppp.cc new file mode 100644 index 000000000..3589ab522 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ppp.cc @@ -0,0 +1,1520 @@ +/*! + * \file rtklib_ppp.cc + * \brief Precise Point Positioning + * \authors
          + *
        • 2007-2008, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2008, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_ppp.h" +#include "rtklib_ephemeris.h" +#include "rtklib_ionex.h" +#include "rtklib_lambda.h" +#include "rtklib_rtkcmn.h" +#include "rtklib_sbas.h" +#include "rtklib_tides.h" + +/* wave length of LC (m) -----------------------------------------------------*/ +double lam_LC(int i, int j, int k) +{ + const double f1 = FREQ1, f2 = FREQ2, f5 = FREQ5; + + return SPEED_OF_LIGHT / (i * f1 + j * f2 + k * f5); +} + + +/* carrier-phase LC (m) ------------------------------------------------------*/ +double L_LC(int i, int j, int k, const double *L) +{ + const double f1 = FREQ1, f2 = FREQ2, f5 = FREQ5; + double L1, L2, L5; + + if ((i && !L[0]) || (j && !L[1]) || (k && !L[2])) + { + return 0.0; + } + L1 = SPEED_OF_LIGHT / f1 * L[0]; + L2 = SPEED_OF_LIGHT / f2 * L[1]; + L5 = SPEED_OF_LIGHT / f5 * L[2]; + return (i * f1 * L1 + j * f2 * L2 + k * f5 * L5) / (i * f1 + j * f2 + k * f5); +} + + +/* pseudorange LC (m) --------------------------------------------------------*/ +double P_LC(int i, int j, int k, const double *P) +{ + const double f1 = FREQ1, f2 = FREQ2, f5 = FREQ5; + double P1, P2, P5; + + if ((i && !P[0]) || (j && !P[1]) || (k && !P[2])) + { + return 0.0; + } + P1 = P[0]; + P2 = P[1]; + P5 = P[2]; + return (i * f1 * P1 + j * f2 * P2 + k * f5 * P5) / (i * f1 + j * f2 + k * f5); +} + + +/* noise variance of LC (m) --------------------------------------------------*/ +double var_LC(int i, int j, int k, double sig) +{ + const double f1 = FREQ1, f2 = FREQ2, f5 = FREQ5; + + return (std::pow(i * f1, 2.0) + std::pow(j * f2, 2.0) + std::pow(k * f5, 2.0)) / std::pow(i * f1 + j * f2 + k * f5, 2.0) * std::pow(sig, 2.0); +} + + +/* complementaty error function (ref [1] p.227-229) --------------------------*/ +double p_gamma(double a, double x, double log_gamma_a) +{ + double y, w; + int i; + + if (x == 0.0) return 0.0; + if (x >= a + 1.0) return 1.0 - q_gamma(a, x, log_gamma_a); + + y = w = exp(a * log(x) - x - log_gamma_a) / a; + + for (i = 1; i < 100; i++) + { + w *= x / (a + i); + y += w; + if (fabs(w) < 1E-15) break; + } + return y; +} + + +double q_gamma(double a, double x, double log_gamma_a) +{ + double y, w, la = 1.0, lb = x + 1.0 - a, lc; + int i; + + if (x < a + 1.0) return 1.0 - p_gamma(a, x, log_gamma_a); + w = exp(-x + a * log(x) - log_gamma_a); + y = w / lb; + for (i = 2; i < 100; i++) + { + lc = ((i - 1 - a) * (lb - la) + (i + x) * lb) / i; + la = lb; + lb = lc; + w *= (i - 1 - a) / i; + y += w / la / lb; + if (fabs(w / la / lb) < 1E-15) break; + } + return y; +} + + +double f_erfc(double x) +{ + return x >= 0.0 ? q_gamma(0.5, x * x, LOG_PI / 2.0) : 1.0 + p_gamma(0.5, x * x, LOG_PI / 2.0); +} + + +/* confidence function of integer ambiguity ----------------------------------*/ +double conffunc(int N, double B, double sig) +{ + double x, p = 1.0; + int i; + + x = fabs(B - N); + for (i = 1; i < 8; i++) + { + p -= f_erfc((i - x) / (SQRT2 * sig)) - f_erfc((i + x) / (SQRT2 * sig)); + } + return p; +} + + +/* average LC ----------------------------------------------------------------*/ +void average_LC(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav __attribute__((unused)), + const double *azel) +{ + ambc_t *amb; + double LC1, LC2, LC3, var1, var2, var3, sig; + int i, j, sat; + + for (i = 0; i < n; i++) + { + sat = obs[i].sat; + + if (azel[1 + 2 * i] < rtk->opt.elmin) continue; + + if (satsys(sat, nullptr) != SYS_GPS) continue; + + /* triple-freq carrier and code LC (m) */ + LC1 = L_LC(1, -1, 0, obs[i].L) - P_LC(1, 1, 0, obs[i].P); + LC2 = L_LC(0, 1, -1, obs[i].L) - P_LC(0, 1, 1, obs[i].P); + LC3 = L_LC(1, -6, 5, obs[i].L) - P_LC(1, 1, 0, obs[i].P); + + sig = std::sqrt(std::pow(rtk->opt.err[1], 2.0) + std::pow(rtk->opt.err[2] / sin(azel[1 + 2 * i]), 2.0)); + + /* measurement noise variance (m) */ + var1 = var_LC(1, 1, 0, sig * rtk->opt.eratio[0]); + var2 = var_LC(0, 1, 1, sig * rtk->opt.eratio[0]); + var3 = var_LC(1, 1, 0, sig * rtk->opt.eratio[0]); + + amb = rtk->ambc + sat - 1; + + if (rtk->ssat[sat - 1].slip[0] || rtk->ssat[sat - 1].slip[1] || + rtk->ssat[sat - 1].slip[2] || amb->n[0] == 0.0 || + fabs(timediff(amb->epoch[0], obs[0].time)) > MIN_ARC_GAP) + { + amb->n[0] = amb->n[1] = amb->n[2] = 0.0; + amb->LC[0] = amb->LC[1] = amb->LC[2] = 0.0; + amb->LCv[0] = amb->LCv[1] = amb->LCv[2] = 0.0; + amb->fixcnt = 0; + for (j = 0; j < MAXSAT; j++) amb->flags[j] = 0; + } + /* averaging */ + if (LC1) + { + amb->n[0] += 1.0; + amb->LC[0] += (LC1 - amb->LC[0]) / amb->n[0]; + amb->LCv[0] += (var1 - amb->LCv[0]) / amb->n[0]; + } + if (LC2) + { + amb->n[1] += 1.0; + amb->LC[1] += (LC2 - amb->LC[1]) / amb->n[1]; + amb->LCv[1] += (var2 - amb->LCv[1]) / amb->n[1]; + } + if (LC3) + { + amb->n[2] += 1.0; + amb->LC[2] += (LC3 - amb->LC[2]) / amb->n[2]; + amb->LCv[2] += (var3 - amb->LCv[2]) / amb->n[2]; + } + amb->epoch[0] = obs[0].time; + } +} + + +/* fix wide-lane ambiguity ---------------------------------------------------*/ +int fix_amb_WL(rtk_t *rtk, const nav_t *nav, int sat1, int sat2, int *NW) +{ + ambc_t *amb1, *amb2; + double BW, vW, lam_WL = lam_LC(1, -1, 0); + + amb1 = rtk->ambc + sat1 - 1; + amb2 = rtk->ambc + sat2 - 1; + if (!amb1->n[0] || !amb2->n[0]) return 0; + + /* wide-lane ambiguity */ +#ifndef REV_WL_FCB + BW = (amb1->LC[0] - amb2->LC[0]) / lam_WL + nav->wlbias[sat1 - 1] - nav->wlbias[sat2 - 1]; +#else + BW = (amb1->LC[0] - amb2->LC[0]) / lam_WL - nav->wlbias[sat1 - 1] + nav->wlbias[sat2 - 1]; +#endif + *NW = ROUND_PPP(BW); + + /* variance of wide-lane ambiguity */ + vW = (amb1->LCv[0] / amb1->n[0] + amb2->LCv[0] / amb2->n[0]) / std::pow(lam_WL, 2.0); + + /* validation of integer wide-lane ambigyity */ + return fabs(*NW - BW) <= rtk->opt.thresar[2] && + conffunc(*NW, BW, sqrt(vW)) >= rtk->opt.thresar[1]; +} + + +/* linear dependency check ---------------------------------------------------*/ +int is_depend(int sat1, int sat2, int *flgs, int *max_flg) +{ + int i; + + if (flgs[sat1 - 1] == 0 && flgs[sat2 - 1] == 0) + { + flgs[sat1 - 1] = flgs[sat2 - 1] = ++(*max_flg); + } + else if (flgs[sat1 - 1] == 0 && flgs[sat2 - 1] != 0) + { + flgs[sat1 - 1] = flgs[sat2 - 1]; + } + else if (flgs[sat1 - 1] != 0 && flgs[sat2 - 1] == 0) + { + flgs[sat2 - 1] = flgs[sat1 - 1]; + } + else if (flgs[sat1 - 1] > flgs[sat2 - 1]) + { + for (i = 0; i < MAXSAT; i++) + if (flgs[i] == flgs[sat2 - 1]) flgs[i] = flgs[sat1 - 1]; + } + else if (flgs[sat1 - 1] < flgs[sat2 - 1]) + { + for (i = 0; i < MAXSAT; i++) + if (flgs[i] == flgs[sat1 - 1]) flgs[i] = flgs[sat2 - 1]; + } + else + return 0; /* linear depenent */ + return 1; +} + + +/* select fixed ambiguities --------------------------------------------------*/ +int sel_amb(int *sat1, int *sat2, double *N, double *var, int n) +{ + int i, j, flgs[MAXSAT] = {0}, max_flg = 0; + + /* sort by variance */ + for (i = 0; i < n; i++) + for (j = 1; j < n - i; j++) + { + if (var[j] >= var[j - 1]) continue; + SWAP_I(sat1[j], sat1[j - 1]); + SWAP_I(sat2[j], sat2[j - 1]); + SWAP_D(N[j], N[j - 1]); + SWAP_D(var[j], var[j - 1]); + } + /* select linearly independent satellite pair */ + for (i = j = 0; i < n; i++) + { + if (!is_depend(sat1[i], sat2[i], flgs, &max_flg)) continue; + sat1[j] = sat1[i]; + sat2[j] = sat2[i]; + N[j] = N[i]; + var[j++] = var[i]; + } + return j; +} + + +/* fixed solution ------------------------------------------------------------*/ +int fix_sol(rtk_t *rtk, const int *sat1, const int *sat2, + const double *NC, int n) +{ + double *v, *H, *R; + int i, j, k, info; + + if (n <= 0) return 0; + + v = zeros(n, 1); + H = zeros(rtk->nx, n); + R = zeros(n, n); + + /* constraints to fixed ambiguities */ + for (i = 0; i < n; i++) + { + j = IB_PPP(sat1[i], &rtk->opt); + k = IB_PPP(sat2[i], &rtk->opt); + v[i] = NC[i] - (rtk->x[j] - rtk->x[k]); + H[j + i * rtk->nx] = 1.0; + H[k + i * rtk->nx] = -1.0; + R[i + i * n] = std::pow(CONST_AMB, 2.0); + } + /* update states with constraints */ + if ((info = filter(rtk->x, rtk->P, H, v, R, rtk->nx, n))) + { + trace(1, "filter error (info=%d)\n", info); + free(v); + free(H); + free(R); + return 0; + } + /* set solution */ + for (i = 0; i < rtk->na; i++) + { + rtk->xa[i] = rtk->x[i]; + for (j = 0; j < rtk->na; j++) + { + rtk->Pa[i + j * rtk->na] = rtk->Pa[j + i * rtk->na] = rtk->P[i + j * rtk->nx]; + } + } + /* set flags */ + for (i = 0; i < n; i++) + { + rtk->ambc[sat1[i] - 1].flags[sat2[i] - 1] = 1; + rtk->ambc[sat2[i] - 1].flags[sat1[i] - 1] = 1; + } + free(v); + free(H); + free(R); + return 1; +} + + +/* fix narrow-lane ambiguity by rounding -------------------------------------*/ +int fix_amb_ROUND(rtk_t *rtk, int *sat1, int *sat2, const int *NW, int n) +{ + double C1, C2, B1, v1, BC, v, vc, *NC, *var, lam_NL = lam_LC(1, 1, 0), lam1, lam2; + int i, j, k, m = 0, N1, stat; + + lam1 = lam_carr[0]; + lam2 = lam_carr[1]; + + C1 = std::pow(lam2, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + C2 = -std::pow(lam1, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + + NC = zeros(n, 1); + var = zeros(n, 1); + + for (i = 0; i < n; i++) + { + j = IB_PPP(sat1[i], &rtk->opt); + k = IB_PPP(sat2[i], &rtk->opt); + + /* narrow-lane ambiguity */ + B1 = (rtk->x[j] - rtk->x[k] + C2 * lam2 * NW[i]) / lam_NL; + N1 = ROUND_PPP(B1); + + /* variance of narrow-lane ambiguity */ + var[m] = rtk->P[j + j * rtk->nx] + rtk->P[k + k * rtk->nx] - 2.0 * rtk->P[j + k * rtk->nx]; + v1 = var[m] / std::pow(lam_NL, 2.0); + + /* validation of narrow-lane ambiguity */ + if (fabs(N1 - B1) > rtk->opt.thresar[2] || + conffunc(N1, B1, sqrt(v1)) < rtk->opt.thresar[1]) + { + continue; + } + /* iono-free ambiguity (m) */ + BC = C1 * lam1 * N1 + C2 * lam2 * (N1 - NW[i]); + + /* check residuals */ + v = rtk->ssat[sat1[i] - 1].resc[0] - rtk->ssat[sat2[i] - 1].resc[0]; + vc = v + (BC - (rtk->x[j] - rtk->x[k])); + if (fabs(vc) > THRES_RES) continue; + + sat1[m] = sat1[i]; + sat2[m] = sat2[i]; + NC[m++] = BC; + } + /* select fixed ambiguities by dependency check */ + m = sel_amb(sat1, sat2, NC, var, m); + + /* fixed solution */ + stat = fix_sol(rtk, sat1, sat2, NC, m); + + free(NC); + free(var); + + return stat && m >= 3; +} + + +/* fix narrow-lane ambiguity by ILS ------------------------------------------*/ +int fix_amb_ILS(rtk_t *rtk, int *sat1, int *sat2, int *NW, int n) +{ + double C1, C2, *B1, *N1, *NC, *D, *E, *Q, s[2], lam_NL = lam_LC(1, 1, 0), lam1, lam2; + int i, j, k, m = 0, info, stat, flgs[MAXSAT] = {0}, max_flg = 0; + + lam1 = lam_carr[0]; + lam2 = lam_carr[1]; + + C1 = std::pow(lam2, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + C2 = -std::pow(lam1, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + + B1 = zeros(n, 1); + N1 = zeros(n, 2); + D = zeros(rtk->nx, n); + E = mat(n, rtk->nx); + Q = mat(n, n); + NC = mat(n, 1); + + for (i = 0; i < n; i++) + { + /* check linear independency */ + if (!is_depend(sat1[i], sat2[i], flgs, &max_flg)) continue; + + j = IB_PPP(sat1[i], &rtk->opt); + k = IB_PPP(sat2[i], &rtk->opt); + + /* float narrow-lane ambiguity (cycle) */ + B1[m] = (rtk->x[j] - rtk->x[k] + C2 * lam2 * NW[i]) / lam_NL; + N1[m] = ROUND_PPP(B1[m]); + + /* validation of narrow-lane ambiguity */ + if (fabs(N1[m] - B1[m]) > rtk->opt.thresar[2]) continue; + + /* narrow-lane ambiguity transformation matrix */ + D[j + m * rtk->nx] = 1.0 / lam_NL; + D[k + m * rtk->nx] = -1.0 / lam_NL; + + sat1[m] = sat1[i]; + sat2[m] = sat2[i]; + NW[m++] = NW[i]; + } + if (m < 3) + { + free(B1); + free(N1); + free(D); + free(E); + free(Q); + free(NC); + return 0; + } + + /* covariance of narrow-lane ambiguities */ + matmul("TN", m, rtk->nx, rtk->nx, 1.0, D, rtk->P, 0.0, E); + matmul("NN", m, m, rtk->nx, 1.0, E, D, 0.0, Q); + + /* integer least square */ + if ((info = lambda(m, 2, B1, Q, N1, s))) + { + trace(2, "lambda error: info=%d\n", info); + free(B1); + free(N1); + free(D); + free(E); + free(Q); + free(NC); + return 0; + } + if (s[0] <= 0.0) + { + free(B1); + free(N1); + free(D); + free(E); + free(Q); + free(NC); + return 0; + } + + rtk->sol.ratio = static_cast(MIN_PPP(s[1] / s[0], 999.9)); + + /* varidation by ratio-test */ + if (rtk->opt.thresar[0] > 0.0 && rtk->sol.ratio < rtk->opt.thresar[0]) + { + trace(2, "varidation error: n=%2d ratio=%8.3f\n", m, rtk->sol.ratio); + free(B1); + free(N1); + free(D); + free(E); + free(Q); + free(NC); + return 0; + } + trace(2, "varidation ok: %s n=%2d ratio=%8.3f\n", time_str(rtk->sol.time, 0), m, + rtk->sol.ratio); + + /* narrow-lane to iono-free ambiguity */ + for (i = 0; i < m; i++) + { + NC[i] = C1 * lam1 * N1[i] + C2 * lam2 * (N1[i] - NW[i]); + } + /* fixed solution */ + stat = fix_sol(rtk, sat1, sat2, NC, m); + + free(B1); + free(N1); + free(D); + free(E); + free(Q); + free(NC); + + return stat; +} + + +/* resolve integer ambiguity for ppp -----------------------------------------*/ +int pppamb(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav, + const double *azel) +{ + double elmask; + int i, j, m = 0, stat = 0, *NW, *sat1, *sat2; + + if (n <= 0 || rtk->opt.ionoopt != IONOOPT_IFLC || rtk->opt.nf < 2) return 0; + + trace(3, "pppamb: time=%s n=%d\n", time_str(obs[0].time, 0), n); + + elmask = rtk->opt.elmaskar > 0.0 ? rtk->opt.elmaskar : rtk->opt.elmin; + + sat1 = imat(n * n, 1); + sat2 = imat(n * n, 1); + NW = imat(n * n, 1); + + /* average LC */ + average_LC(rtk, obs, n, nav, azel); + + /* fix wide-lane ambiguity */ + for (i = 0; i < n - 1; i++) + for (j = i + 1; j < n; j++) + { + if (!rtk->ssat[obs[i].sat - 1].vsat[0] || + !rtk->ssat[obs[j].sat - 1].vsat[0] || + azel[1 + i * 2] < elmask || azel[1 + j * 2] < elmask) continue; +#if 0 + /* test already fixed */ + if (rtk->ambc[obs[i].sat-1].flags[obs[j].sat-1] && + rtk->ambc[obs[j].sat-1].flags[obs[i].sat-1]) continue; +#endif + sat1[m] = obs[i].sat; + sat2[m] = obs[j].sat; + if (fix_amb_WL(rtk, nav, sat1[m], sat2[m], NW + m)) m++; + } + /* fix narrow-lane ambiguity */ + if (rtk->opt.modear == ARMODE_PPPAR) + { + stat = fix_amb_ROUND(rtk, sat1, sat2, NW, m); + } + else if (rtk->opt.modear == ARMODE_PPPAR_ILS) + { + stat = fix_amb_ILS(rtk, sat1, sat2, NW, m); + } + free(sat1); + free(sat2); + free(NW); + + return stat; +} + + +void pppoutsolstat(rtk_t *rtk, int level, FILE *fp) +{ + ssat_t *ssat; + double tow, pos[3], vel[3], acc[3]; + int i, j, week, nfreq = 1; + char id[32]; + + if (level <= 0 || !fp) return; + + trace(3, "pppoutsolstat:\n"); + + tow = time2gpst(rtk->sol.time, &week); + + /* receiver position */ + fprintf(fp, "$POS,%d,%.3f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f\n", week, tow, + rtk->sol.stat, rtk->x[0], rtk->x[1], rtk->x[2], 0.0, 0.0, 0.0); + + /* receiver velocity and acceleration */ + if (rtk->opt.dynamics) + { + ecef2pos(rtk->sol.rr, pos); + ecef2enu(pos, rtk->x + 3, vel); + ecef2enu(pos, rtk->x + 6, acc); + fprintf(fp, "$VELACC,%d,%.3f,%d,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f\n", + week, tow, rtk->sol.stat, vel[0], vel[1], vel[2], acc[0], acc[1], acc[2], + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + /* receiver clocks */ + i = IC_PPP(0, &rtk->opt); + fprintf(fp, "$CLK,%d,%.3f,%d,%d,%.3f,%.3f,%.3f,%.3f\n", + week, tow, rtk->sol.stat, 1, rtk->x[i] * 1E9 / SPEED_OF_LIGHT, rtk->x[i + 1] * 1E9 / SPEED_OF_LIGHT, + 0.0, 0.0); + + /* tropospheric parameters */ + if (rtk->opt.tropopt == TROPOPT_EST || rtk->opt.tropopt == TROPOPT_ESTG) + { + i = IT_PPP(&rtk->opt); + fprintf(fp, "$TROP,%d,%.3f,%d,%d,%.4f,%.4f\n", week, tow, rtk->sol.stat, + 1, rtk->x[i], 0.0); + } + if (rtk->opt.tropopt == TROPOPT_ESTG) + { + i = IT_PPP(&rtk->opt); + fprintf(fp, "$TRPG,%d,%.3f,%d,%d,%.5f,%.5f,%.5f,%.5f\n", week, tow, + rtk->sol.stat, 1, rtk->x[i + 1], rtk->x[i + 2], 0.0, 0.0); + } + if (rtk->sol.stat == SOLQ_NONE || level <= 1) return; + + /* residuals and status */ + for (i = 0; i < MAXSAT; i++) + { + ssat = rtk->ssat + i; + if (!ssat->vs) continue; + satno2id(i + 1, id); + for (j = 0; j < nfreq; j++) + { + fprintf(fp, "$SAT,%d,%.3f,%s,%d,%.1f,%.1f,%.4f,%.4f,%d,%.0f,%d,%d,%d,%d,%d,%d\n", + week, tow, id, j + 1, ssat->azel[0] * R2D, ssat->azel[1] * R2D, + ssat->resp[j], ssat->resc[j], ssat->vsat[j], ssat->snr[j] * 0.25, + ssat->fix[j], ssat->slip[j] & 3, ssat->lock[j], ssat->outc[j], + ssat->slipc[j], ssat->rejc[j]); + } + } +} + + +/* exclude meas of eclipsing satellite (block IIA) ---------------------------*/ +void testeclipse(const obsd_t *obs, int n, const nav_t *nav, double *rs) +{ + double rsun[3], esun[3], r, ang, erpv[5] = {0}, cosa; + int i, j; + const char *type; + + trace(3, "testeclipse:\n"); + + /* unit vector of sun direction (ecef) */ + sunmoonpos(gpst2utc(obs[0].time), erpv, rsun, nullptr, nullptr); + if (normv3(rsun, esun) == 0) trace(1, "Error computing the norm"); + + for (i = 0; i < n; i++) + { + type = nav->pcvs[obs[i].sat - 1].type; + + if ((r = norm_rtk(rs + i * 6, 3)) <= 0.0) continue; +#if 1 + /* only block IIA */ + if (*type && !strstr(type, "BLOCK IIA")) continue; +#endif + /* sun-earth-satellite angle */ + cosa = dot(rs + i * 6, esun, 3) / r; + cosa = cosa < -1.0 ? -1.0 : (cosa > 1.0 ? 1.0 : cosa); + ang = acos(cosa); + + /* test eclipse */ + if (ang < PI / 2.0 || r * sin(ang) > RE_WGS84) continue; + + trace(2, "eclipsing sat excluded %s sat=%2d\n", time_str(obs[0].time, 0), + obs[i].sat); + + for (j = 0; j < 3; j++) rs[j + i * 6] = 0.0; + } +} + + +/* measurement error variance ------------------------------------------------*/ +double varerr(int sat __attribute__((unused)), int sys, double el, int type, const prcopt_t *opt) +{ + double a, b, a2, b2, fact = 1.0; + double sinel = sin(el); + int i = sys == SYS_GLO ? 1 : (sys == SYS_GAL ? 2 : 0); + + /* extended error model */ + if (type == 1 && opt->exterr.ena[0]) + { /* code */ + a = opt->exterr.cerr[i][0]; + b = opt->exterr.cerr[i][1]; + if (opt->ionoopt == IONOOPT_IFLC) + { + a2 = opt->exterr.cerr[i][2]; + b2 = opt->exterr.cerr[i][3]; + a = std::sqrt(std::pow(2.55, 2.0) * a * a + std::pow(1.55, 2.0) * a2 * a2); + b = std::sqrt(std::pow(2.55, 2.0) * b * b + std::pow(1.55, 2.0) * b2 * b2); + } + } + else if (type == 0 && opt->exterr.ena[1]) + { /* phase */ + a = opt->exterr.perr[i][0]; + b = opt->exterr.perr[i][1]; + if (opt->ionoopt == IONOOPT_IFLC) + { + a2 = opt->exterr.perr[i][2]; + b2 = opt->exterr.perr[i][3]; + a = std::sqrt(std::pow(2.55, 2.0) * a * a + std::pow(1.55, 2.0) * a2 * a2); + b = std::sqrt(std::pow(2.55, 2.0) * b * b + std::pow(1.55, 2.0) * b2 * b2); + } + } + else + { /* normal error model */ + if (type == 1) fact *= opt->eratio[0]; + fact *= sys == SYS_GLO ? EFACT_GLO : (sys == SYS_SBS ? EFACT_SBS : EFACT_GPS); + if (opt->ionoopt == IONOOPT_IFLC) fact *= 3.0; + a = fact * opt->err[1]; + b = fact * opt->err[2]; + } + return a * a + b * b / sinel / sinel; +} + + +/* initialize state and covariance -------------------------------------------*/ +void initx(rtk_t *rtk, double xi, double var, int i) +{ + int j; + rtk->x[i] = xi; + for (j = 0; j < rtk->nx; j++) + { + rtk->P[i + j * rtk->nx] = rtk->P[j + i * rtk->nx] = i == j ? var : 0.0; + } +} + + +/* dual-frequency iono-free measurements -------------------------------------*/ +int ifmeas(const obsd_t *obs, const nav_t *nav, const double *azel, + const prcopt_t *opt, const double *dantr, const double *dants, + double phw, double *meas, double *var) +{ + const double *lam = nav->lam[obs->sat - 1]; + double c1, c2, L1, L2, P1, P2, P1_C1, P2_C2, gamma; + int i = 0, j = 1, k; + + trace(4, "ifmeas :\n"); + + /* L1-L2 for GPS/GLO/QZS, L1-L5 for GAL/SBS */ + if (NFREQ >= 3 && (satsys(obs->sat, nullptr) & (SYS_GAL | SYS_SBS))) j = 2; + + if (NFREQ < 2 || lam[i] == 0.0 || lam[j] == 0.0) return 0; + + /* test snr mask */ + if (testsnr(0, i, azel[1], obs->SNR[i] * 0.25, &opt->snrmask) || + testsnr(0, j, azel[1], obs->SNR[j] * 0.25, &opt->snrmask)) + { + return 0; + } + gamma = std::pow(lam[j], 2.0) / std::pow(lam[i], 2.0); /* f1^2/f2^2 */ + c1 = gamma / (gamma - 1.0); /* f1^2/(f1^2-f2^2) */ + c2 = -1.0 / (gamma - 1.0); /* -f2^2/(f1^2-f2^2) */ + + L1 = obs->L[i] * lam[i]; /* cycle -> m */ + L2 = obs->L[j] * lam[j]; + P1 = obs->P[i]; + P2 = obs->P[j]; + P1_C1 = nav->cbias[obs->sat - 1][1]; + P2_C2 = nav->cbias[obs->sat - 1][2]; + if (opt->sateph == EPHOPT_LEX) + { + P1_C1 = nav->lexeph[obs->sat - 1].isc[0] * SPEED_OF_LIGHT; /* ISC_L1C/A */ + } + if (L1 == 0.0 || L2 == 0.0 || P1 == 0.0 || P2 == 0.0) return 0; + + /* iono-free phase with windup correction */ + meas[0] = c1 * L1 + c2 * L2 - (c1 * lam[i] + c2 * lam[j]) * phw; + + /* iono-free code with dcb correction */ + if (obs->code[i] == CODE_L1C) P1 += P1_C1; /* C1->P1 */ + if (obs->code[j] == CODE_L2C) P2 += P2_C2; /* C2->P2 */ + meas[1] = c1 * P1 + c2 * P2; + var[1] = std::pow(ERR_CBIAS, 2.0); + + if (opt->sateph == EPHOPT_SBAS) meas[1] -= P1_C1; /* sbas clock based C1 */ + + /* gps-glonass h/w bias correction for code */ + if (opt->exterr.ena[3] && satsys(obs->sat, nullptr) == SYS_GLO) + { + meas[1] += c1 * opt->exterr.gpsglob[0] + c2 * opt->exterr.gpsglob[1]; + } + /* antenna phase center variation correction */ + for (k = 0; k < 2; k++) + { + if (dants) meas[k] -= c1 * dants[i] + c2 * dants[j]; + if (dantr) meas[k] -= c1 * dantr[i] + c2 * dantr[j]; + } + return 1; +} + + +/* get tgd parameter (m) -----------------------------------------------------*/ +double gettgd_ppp(int sat, const nav_t *nav) +{ + int i; + for (i = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != sat) continue; + return SPEED_OF_LIGHT * nav->eph[i].tgd[0]; + } + return 0.0; +} + + +/* slant ionospheric delay ---------------------------------------------------*/ +int corr_ion(gtime_t time, const nav_t *nav, int sat __attribute__((unused)), const double *pos, + const double *azel, int ionoopt, double *ion, double *var, + int *brk __attribute__((unused))) +{ +#ifdef EXTSTEC + double rate; +#endif + /* sbas ionosphere model */ + if (ionoopt == IONOOPT_SBAS) + { + return sbsioncorr(time, nav, pos, azel, ion, var); + } + /* ionex tec model */ + if (ionoopt == IONOOPT_TEC) + { + return iontec(time, nav, pos, azel, 1, ion, var); + } +#ifdef EXTSTEC + /* slant tec model */ + if (ionoopt == IONOOPT_STEC) + { + return stec_ion(time, nav, sat, pos, azel, ion, &rate, var, brk); + } +#endif + /* broadcast model */ + if (ionoopt == IONOOPT_BRDC) + { + *ion = ionmodel(time, nav->ion_gps, pos, azel); + *var = std::pow(*ion * ERR_BRDCI, 2.0); + return 1; + } + /* ionosphere model off */ + *ion = 0.0; + *var = VAR_IONO_OFF; + return 1; +} + + +/* ionosphere and antenna corrected measurements -----------------------------*/ +int corrmeas(const obsd_t *obs, const nav_t *nav, const double *pos, + const double *azel, const prcopt_t *opt, + const double *dantr, const double *dants, double phw, + double *meas, double *var, int *brk) +{ + const double *lam = nav->lam[obs->sat - 1]; + double ion = 0.0, L1, P1, PC, P1_P2, P1_C1, vari, gamma; + int i; + + trace(4, "corrmeas:\n"); + + meas[0] = meas[1] = var[0] = var[1] = 0.0; + + /* iono-free LC */ + if (opt->ionoopt == IONOOPT_IFLC) + { + return ifmeas(obs, nav, azel, opt, dantr, dants, phw, meas, var); + } + if (lam[0] == 0.0 || obs->L[0] == 0.0 || obs->P[0] == 0.0) return 0; + + if (testsnr(0, 0, azel[1], obs->SNR[0] * 0.25, &opt->snrmask)) return 0; + + L1 = obs->L[0] * lam[0]; + P1 = obs->P[0]; + + /* dcb correction */ + gamma = std::pow(lam[1] / lam[0], 2.0); /* f1^2/f2^2 */ + P1_P2 = nav->cbias[obs->sat - 1][0]; + P1_C1 = nav->cbias[obs->sat - 1][1]; + if (P1_P2 == 0.0 && (satsys(obs->sat, nullptr) & (SYS_GPS | SYS_GAL | SYS_QZS))) + { + P1_P2 = (1.0 - gamma) * gettgd_ppp(obs->sat, nav); + } + if (obs->code[0] == CODE_L1C) P1 += P1_C1; /* C1->P1 */ + PC = P1 - P1_P2 / (1.0 - gamma); /* P1->PC */ + + /* slant ionospheric delay L1 (m) */ + if (!corr_ion(obs->time, nav, obs->sat, pos, azel, opt->ionoopt, &ion, &vari, brk)) + { + trace(2, "iono correction error: time=%s sat=%2d ionoopt=%d\n", + time_str(obs->time, 2), obs->sat, opt->ionoopt); + return 0; + } + /* ionosphere and windup corrected phase and code */ + meas[0] = L1 + ion - lam[0] * phw; + meas[1] = PC - ion; + + var[0] += vari; + var[1] += vari + std::pow(ERR_CBIAS, 2.0); + + /* antenna phase center variation correction */ + for (i = 0; i < 2; i++) + { + if (dants) meas[i] -= dants[0]; + if (dantr) meas[i] -= dantr[0]; + } + return 1; +} + + +/* L1/L2 geometry-free phase measurement -------------------------------------*/ +double gfmeas(const obsd_t *obs, const nav_t *nav) +{ + const double *lam = nav->lam[obs->sat - 1]; + + if (lam[0] == 0.0 || lam[1] == 0.0 || obs->L[0] == 0.0 || obs->L[1] == 0.0) return 0.0; + + return lam[0] * obs->L[0] - lam[1] * obs->L[1]; +} + + +/* temporal update of position -----------------------------------------------*/ +void udpos_ppp(rtk_t *rtk) +{ + int i; + + trace(3, "udpos_ppp:\n"); + + /* fixed mode */ + if (rtk->opt.mode == PMODE_PPP_FIXED) + { + for (i = 0; i < 3; i++) initx(rtk, rtk->opt.ru[i], 1E-8, i); + return; + } + /* initialize position for first epoch */ + if (norm_rtk(rtk->x, 3) <= 0.0) + { + for (i = 0; i < 3; i++) initx(rtk, rtk->sol.rr[i], VAR_POS_PPP, i); + } + /* static ppp mode */ + if (rtk->opt.mode == PMODE_PPP_STATIC) return; + + /* kinmatic mode without dynamics */ + for (i = 0; i < 3; i++) + { + initx(rtk, rtk->sol.rr[i], VAR_POS_PPP, i); + } +} + + +/* temporal update of clock --------------------------------------------------*/ +void udclk_ppp(rtk_t *rtk) +{ + double dtr; + int i; + + trace(3, "udclk_ppp:\n"); + + /* initialize every epoch for clock (white noise) */ + for (i = 0; i < NSYS; i++) + { + if (rtk->opt.sateph == EPHOPT_PREC) + { + /* time of prec ephemeris is based gpst */ + /* negelect receiver inter-system bias */ + dtr = rtk->sol.dtr[0]; + } + else + { + dtr = i == 0 ? rtk->sol.dtr[0] : rtk->sol.dtr[0] + rtk->sol.dtr[i]; + } + initx(rtk, SPEED_OF_LIGHT * dtr, VAR_CLK, IC_PPP(i, &rtk->opt)); + } +} + + +/* temporal update of tropospheric parameters --------------------------------*/ +void udtrop_ppp(rtk_t *rtk) +{ + double pos[3], azel[] = {0.0, PI / 2.0}, ztd, var; + int i = IT_PPP(&rtk->opt), j; + + trace(3, "udtrop_ppp:\n"); + + if (rtk->x[i] == 0.0) + { + ecef2pos(rtk->sol.rr, pos); + ztd = sbstropcorr(rtk->sol.time, pos, azel, &var); + initx(rtk, ztd, var, i); + + if (rtk->opt.tropopt >= TROPOPT_ESTG) + { + for (j = 0; j < 2; j++) initx(rtk, 1E-6, VAR_GRA_PPP, ++i); + } + } + else + { + rtk->P[i * (1 + rtk->nx)] += std::pow(rtk->opt.prn[2], 2.0) * fabs(rtk->tt); + + if (rtk->opt.tropopt >= TROPOPT_ESTG) + { + for (j = 0; j < 2; j++) + { + rtk->P[++i * (1 + rtk->nx)] += std::pow(rtk->opt.prn[2] * 0.1, 2.0) * fabs(rtk->tt); + } + } + } +} + + +/* detect cycle slip by LLI --------------------------------------------------*/ +void detslp_ll(rtk_t *rtk, const obsd_t *obs, int n) +{ + int i, j; + + trace(3, "detslp_ll: n=%d\n", n); + + for (i = 0; i < n && i < MAXOBS; i++) + for (j = 0; j < rtk->opt.nf; j++) + { + if (obs[i].L[j] == 0.0 || !(obs[i].LLI[j] & 3)) continue; + + trace(3, "detslp_ll: slip detected sat=%2d f=%d\n", obs[i].sat, j + 1); + + rtk->ssat[obs[i].sat - 1].slip[j] = 1; + } +} + + +/* detect cycle slip by geometry free phase jump -----------------------------*/ +void detslp_gf(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) +{ + double g0, g1; + int i, j; + + trace(3, "detslp_gf: n=%d\n", n); + + for (i = 0; i < n && i < MAXOBS; i++) + { + if ((g1 = gfmeas(obs + i, nav)) == 0.0) continue; + + g0 = rtk->ssat[obs[i].sat - 1].gf; + rtk->ssat[obs[i].sat - 1].gf = g1; + + trace(4, "detslip_gf: sat=%2d gf0=%8.3f gf1=%8.3f\n", obs[i].sat, g0, g1); + + if (g0 != 0.0 && fabs(g1 - g0) > rtk->opt.thresslip) + { + trace(3, "detslip_gf: slip detected sat=%2d gf=%8.3f->%8.3f\n", + obs[i].sat, g0, g1); + + for (j = 0; j < rtk->opt.nf; j++) rtk->ssat[obs[i].sat - 1].slip[j] |= 1; + } + } +} + + +/* temporal update of phase biases -------------------------------------------*/ +void udbias_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) +{ + double meas[2], var[2], bias[MAXOBS] = {0}, offset = 0.0, pos[3] = {0}; + int i, j, k, sat, brk = 0; + + trace(3, "udbias : n=%d\n", n); + + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < rtk->opt.nf; j++) + { + rtk->ssat[i].slip[j] = 0; + } + /* detect cycle slip by LLI */ + detslp_ll(rtk, obs, n); + + /* detect cycle slip by geometry-free phase jump */ + detslp_gf(rtk, obs, n, nav); + + /* reset phase-bias if expire obs outage counter */ + for (i = 0; i < MAXSAT; i++) + { + if (++rtk->ssat[i].outc[0] > static_cast(rtk->opt.maxout)) + { + initx(rtk, 0.0, 0.0, IB_PPP(i + 1, &rtk->opt)); + } + } + ecef2pos(rtk->sol.rr, pos); + + for (i = k = 0; i < n && i < MAXOBS; i++) + { + sat = obs[i].sat; + j = IB_PPP(sat, &rtk->opt); + if (!corrmeas(obs + i, nav, pos, rtk->ssat[sat - 1].azel, &rtk->opt, nullptr, nullptr, + 0.0, meas, var, &brk)) continue; + + if (brk) + { + rtk->ssat[sat - 1].slip[0] = 1; + trace(2, "%s: sat=%2d correction break\n", time_str(obs[i].time, 0), sat); + } + bias[i] = meas[0] - meas[1]; + if (rtk->x[j] == 0.0 || + rtk->ssat[sat - 1].slip[0] || rtk->ssat[sat - 1].slip[1]) continue; + offset += bias[i] - rtk->x[j]; + k++; + } + /* correct phase-code jump to enssure phase-code coherency */ + if (k >= 2 && fabs(offset / k) > 0.0005 * SPEED_OF_LIGHT) + { + for (i = 0; i < MAXSAT; i++) + { + j = IB_PPP(i + 1, &rtk->opt); + if (rtk->x[j] != 0.0) rtk->x[j] += offset / k; + } + trace(2, "phase-code jump corrected: %s n=%2d dt=%12.9fs\n", + time_str(rtk->sol.time, 0), k, offset / k / SPEED_OF_LIGHT); + } + for (i = 0; i < n && i < MAXOBS; i++) + { + sat = obs[i].sat; + j = IB_PPP(sat, &rtk->opt); + + rtk->P[j + j * rtk->nx] += std::pow(rtk->opt.prn[0], 2.0) * fabs(rtk->tt); + + if (rtk->x[j] != 0.0 && + !rtk->ssat[sat - 1].slip[0] && !rtk->ssat[sat - 1].slip[1]) continue; + + if (bias[i] == 0.0) continue; + + /* reinitialize phase-bias if detecting cycle slip */ + initx(rtk, bias[i], VAR_BIAS, IB_PPP(sat, &rtk->opt)); + + trace(5, "udbias_ppp: sat=%2d bias=%.3f\n", sat, meas[0] - meas[1]); + } +} + + +/* temporal update of states --------------------------------------------------*/ +void udstate_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) +{ + trace(3, "udstate_ppp: n=%d\n", n); + + /* temporal update of position */ + udpos_ppp(rtk); + + /* temporal update of clock */ + udclk_ppp(rtk); + + /* temporal update of tropospheric parameters */ + if (rtk->opt.tropopt >= TROPOPT_EST) + { + udtrop_ppp(rtk); + } + /* temporal update of phase-bias */ + udbias_ppp(rtk, obs, n, nav); +} + + +/* satellite antenna phase center variation ----------------------------------*/ +void satantpcv(const double *rs, const double *rr, const pcv_t *pcv, + double *dant) +{ + double ru[3], rz[3], eu[3], ez[3], nadir, cosa; + int i; + + for (i = 0; i < 3; i++) + { + ru[i] = rr[i] - rs[i]; + rz[i] = -rs[i]; + } + if (!normv3(ru, eu) || !normv3(rz, ez)) return; + + cosa = dot(eu, ez, 3); + cosa = cosa < -1.0 ? -1.0 : (cosa > 1.0 ? 1.0 : cosa); + nadir = acos(cosa); + + antmodel_s(pcv, nadir, dant); +} + + +/* precise tropospheric model ------------------------------------------------*/ +double prectrop(gtime_t time, const double *pos, const double *azel, + const prcopt_t *opt, const double *x, double *dtdx, + double *var) +{ + const double zazel[] = {0.0, PI / 2.0}; + double zhd, m_h, m_w, cotz, grad_n, grad_e; + + /* zenith hydrostatic delay */ + zhd = tropmodel(time, pos, zazel, 0.0); + + /* mapping function */ + m_h = tropmapf(time, pos, azel, &m_w); + + if ((opt->tropopt == TROPOPT_ESTG || opt->tropopt == TROPOPT_CORG) && azel[1] > 0.0) + { + /* m_w=m_0+m_0*cot(el)*(Gn*cos(az)+Ge*sin(az)): ref [6] */ + cotz = 1.0 / tan(azel[1]); + grad_n = m_w * cotz * cos(azel[0]); + grad_e = m_w * cotz * sin(azel[0]); + m_w += grad_n * x[1] + grad_e * x[2]; + dtdx[1] = grad_n * (x[0] - zhd); + dtdx[2] = grad_e * (x[0] - zhd); + } + dtdx[0] = m_w; + *var = std::pow(0.01, 2.0); + return m_h * zhd + m_w * (x[0] - zhd); +} + + +/* phase and code residuals --------------------------------------------------*/ +int res_ppp(int iter __attribute__((unused)), const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const double *x, rtk_t *rtk, double *v, + double *H, double *R, double *azel) +{ + prcopt_t *opt = &rtk->opt; + double r, rr[3], disp[3], pos[3], e[3], meas[2], dtdx[3], dantr[NFREQ] = {0}; + double dants[NFREQ] = {0}, var[MAXOBS * 2], dtrp = 0.0, vart = 0.0, varm[2] = {0}; + int i, j, k, sat, sys, nv = 0, nx = rtk->nx, brk, tideopt; + + trace(3, "res_ppp : n=%d nx=%d\n", n, nx); + + for (i = 0; i < MAXSAT; i++) rtk->ssat[i].vsat[0] = 0; + + for (i = 0; i < 3; i++) rr[i] = x[i]; + + /* earth tides correction */ + if (opt->tidecorr) + { + tideopt = opt->tidecorr == 1 ? 1 : 7; /* 1:solid, 2:solid+otl+pole */ + + tidedisp(gpst2utc(obs[0].time), rr, tideopt, &nav->erp, opt->odisp[0], + disp); + for (i = 0; i < 3; i++) rr[i] += disp[i]; + } + ecef2pos(rr, pos); + + for (i = 0; i < n && i < MAXOBS; i++) + { + sat = obs[i].sat; + if (!(sys = satsys(sat, nullptr)) || !rtk->ssat[sat - 1].vs) continue; + + /* geometric distance/azimuth/elevation angle */ + if ((r = geodist(rs + i * 6, rr, e)) <= 0.0 || + satazel(pos, e, azel + i * 2) < opt->elmin) continue; + + /* excluded satellite? */ + if (satexclude(obs[i].sat, svh[i], opt)) continue; + + /* tropospheric delay correction */ + if (opt->tropopt == TROPOPT_SAAS) + { + dtrp = tropmodel(obs[i].time, pos, azel + i * 2, REL_HUMI); + vart = std::pow(ERR_SAAS, 2.0); + } + else if (opt->tropopt == TROPOPT_SBAS) + { + dtrp = sbstropcorr(obs[i].time, pos, azel + i * 2, &vart); + } + else if (opt->tropopt == TROPOPT_EST || opt->tropopt == TROPOPT_ESTG) + { + dtrp = prectrop(obs[i].time, pos, azel + i * 2, opt, x + IT_PPP(opt), dtdx, &vart); + } + else if (opt->tropopt == TROPOPT_COR || opt->tropopt == TROPOPT_CORG) + { + dtrp = prectrop(obs[i].time, pos, azel + i * 2, opt, x, dtdx, &vart); + } + /* satellite antenna model */ + if (opt->posopt[0]) + { + satantpcv(rs + i * 6, rr, nav->pcvs + sat - 1, dants); + } + /* receiver antenna model */ + antmodel(opt->pcvr, opt->antdel[0], azel + i * 2, opt->posopt[1], dantr); + + /* phase windup correction */ + if (opt->posopt[2]) + { + windupcorr(rtk->sol.time, rs + i * 6, rr, &rtk->ssat[sat - 1].phw); + } + /* ionosphere and antenna phase corrected measurements */ + if (!corrmeas(obs + i, nav, pos, azel + i * 2, &rtk->opt, dantr, dants, + rtk->ssat[sat - 1].phw, meas, varm, &brk)) + { + continue; + } + /* satellite clock and tropospheric delay */ + r += -SPEED_OF_LIGHT * dts[i * 2] + dtrp; + + trace(5, "sat=%2d azel=%6.1f %5.1f dtrp=%.3f dantr=%6.3f %6.3f dants=%6.3f %6.3f phw=%6.3f\n", + sat, azel[i * 2] * R2D, azel[1 + i * 2] * R2D, dtrp, dantr[0], dantr[1], dants[0], + dants[1], rtk->ssat[sat - 1].phw); + + for (j = 0; j < 2; j++) + { /* for phase and code */ + + if (meas[j] == 0.0) continue; + + for (k = 0; k < nx; k++) H[k + nx * nv] = 0.0; + + v[nv] = meas[j] - r; + + for (k = 0; k < 3; k++) H[k + nx * nv] = -e[k]; + + if (sys != SYS_GLO) + { + v[nv] -= x[IC_PPP(0, opt)]; + H[IC_PPP(0, opt) + nx * nv] = 1.0; + } + else + { + v[nv] -= x[IC_PPP(1, opt)]; + H[IC_PPP(1, opt) + nx * nv] = 1.0; + } + if (opt->tropopt >= TROPOPT_EST) + { + for (k = 0; k < (opt->tropopt >= TROPOPT_ESTG ? 3 : 1); k++) + { + H[IT_PPP(opt) + k + nx * nv] = dtdx[k]; + } + } + if (j == 0) + { + v[nv] -= x[IB_PPP(obs[i].sat, opt)]; + H[IB_PPP(obs[i].sat, opt) + nx * nv] = 1.0; + } + var[nv] = varerr(obs[i].sat, sys, azel[1 + i * 2], j, opt) + varm[j] + vare[i] + vart; + + if (j == 0) + rtk->ssat[sat - 1].resc[0] = v[nv]; + else + rtk->ssat[sat - 1].resp[0] = v[nv]; + + /* test innovation */ +#if 0 + if (opt->maxinno>0.0 && fabs(v[nv])>opt->maxinno) + { +#else + if (opt->maxinno > 0.0 && fabs(v[nv]) > opt->maxinno && sys != SYS_GLO) + { +#endif + trace(2, "ppp outlier rejected %s sat=%2d type=%d v=%.3f\n", + time_str(obs[i].time, 0), sat, j, v[nv]); + rtk->ssat[sat - 1].rejc[0]++; + continue; + } + if (j == 0) rtk->ssat[sat - 1].vsat[0] = 1; + nv++; + } +} +for (i = 0; i < nv; i++) + for (j = 0; j < nv; j++) + { + R[i + j * nv] = i == j ? var[i] : 0.0; + } +trace(5, "x=\n"); +tracemat(5, x, 1, nx, 8, 3); +trace(5, "v=\n"); +tracemat(5, v, 1, nv, 8, 3); +trace(5, "H=\n"); +tracemat(5, H, nx, nv, 8, 3); +trace(5, "R=\n"); +tracemat(5, R, nv, nv, 8, 5); +return nv; +} + + +/* number of estimated states ------------------------------------------------*/ +int pppnx(const prcopt_t *opt) +{ + return NX_PPP(opt); +} + + +/* precise point positioning -------------------------------------------------*/ +void pppos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) +{ + const prcopt_t *opt = &rtk->opt; + double *rs, *dts, *var, *v, *H, *R, *azel, *xp, *Pp; + int i, nv, info, svh[MAXOBS], stat = SOLQ_SINGLE; + + trace(3, "pppos : nx=%d n=%d\n", rtk->nx, n); + + rs = mat(6, n); + dts = mat(2, n); + var = mat(1, n); + azel = zeros(2, n); + + for (i = 0; i < MAXSAT; i++) rtk->ssat[i].fix[0] = 0; + + /* temporal update of states */ + udstate_ppp(rtk, obs, n, nav); + + trace(4, "x(0)="); + tracemat(4, rtk->x, 1, NR_PPP(opt), 13, 4); + + /* satellite positions and clocks */ + satposs(obs[0].time, obs, n, nav, rtk->opt.sateph, rs, dts, var, svh); + + /* exclude measurements of eclipsing satellite */ + if (rtk->opt.posopt[3]) + { + testeclipse(obs, n, nav, rs); + } + xp = mat(rtk->nx, 1); + Pp = zeros(rtk->nx, rtk->nx); + matcpy(xp, rtk->x, rtk->nx, 1); + nv = n * rtk->opt.nf * 2; + v = mat(nv, 1); + H = mat(rtk->nx, nv); + R = mat(nv, nv); + + for (i = 0; i < rtk->opt.niter; i++) + { + /* phase and code residuals */ + if ((nv = res_ppp(i, obs, n, rs, dts, var, svh, nav, xp, rtk, v, H, R, azel)) <= 0) break; + + /* measurement update */ + matcpy(Pp, rtk->P, rtk->nx, rtk->nx); + + if ((info = filter(xp, Pp, H, v, R, rtk->nx, nv))) + { + trace(2, "ppp filter error %s info=%d\n", time_str(rtk->sol.time, 0), info); + break; + } + trace(4, "x(%d)=", i + 1); + tracemat(4, xp, 1, NR_PPP(opt), 13, 4); + + stat = SOLQ_PPP; + } + if (stat == SOLQ_PPP) + { + /* postfit residuals */ + res_ppp(1, obs, n, rs, dts, var, svh, nav, xp, rtk, v, H, R, azel); + + /* update state and covariance matrix */ + matcpy(rtk->x, xp, rtk->nx, 1); + matcpy(rtk->P, Pp, rtk->nx, rtk->nx); + + /* ambiguity resolution in ppp */ + if (opt->modear == ARMODE_PPPAR || opt->modear == ARMODE_PPPAR_ILS) + { + if (pppamb(rtk, obs, n, nav, azel)) stat = SOLQ_FIX; + } + /* update solution status */ + rtk->sol.ns = 0; + for (i = 0; i < n && i < MAXOBS; i++) + { + if (!rtk->ssat[obs[i].sat - 1].vsat[0]) continue; + rtk->ssat[obs[i].sat - 1].lock[0]++; + rtk->ssat[obs[i].sat - 1].outc[0] = 0; + rtk->ssat[obs[i].sat - 1].fix[0] = 4; + rtk->sol.ns++; + } + rtk->sol.stat = stat; + + for (i = 0; i < 3; i++) + { + rtk->sol.rr[i] = rtk->x[i]; + rtk->sol.qr[i] = static_cast(rtk->P[i + i * rtk->nx]); + } + rtk->sol.qr[3] = static_cast(rtk->P[1]); + rtk->sol.qr[4] = static_cast(rtk->P[2 + rtk->nx]); + rtk->sol.qr[5] = static_cast(rtk->P[2]); + rtk->sol.dtr[0] = rtk->x[IC_PPP(0, opt)]; + rtk->sol.dtr[1] = rtk->x[IC_PPP(1, opt)] - rtk->x[IC_PPP(0, opt)]; + for (i = 0; i < n && i < MAXOBS; i++) + { + rtk->ssat[obs[i].sat - 1].snr[0] = MIN_PPP(obs[i].SNR[0], obs[i].SNR[1]); + } + for (i = 0; i < MAXSAT; i++) + { + if (rtk->ssat[i].slip[0] & 3) rtk->ssat[i].slipc[0]++; + } + } + free(rs); + free(dts); + free(var); + free(azel); + free(xp); + free(Pp); + free(v); + free(H); + free(R); +} diff --git a/src/algorithms/libs/rtklib/rtklib_ppp.h b/src/algorithms/libs/rtklib/rtklib_ppp.h new file mode 100644 index 000000000..cd8449e1a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_ppp.h @@ -0,0 +1,184 @@ +/*! + * \file rtklib_ppp.h + * \brief Precise Point Positioning + * \authors
          + *
        • 2007-2008, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2008, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + + +#ifndef GNSS_SDR_RTKLIB_PPP_H_ +#define GNSS_SDR_RTKLIB_PPP_H_ + +#include "rtklib.h" + + +#define MIN_PPP(x, y) ((x) <= (y) ? (x) : (y)) +#define ROUND_PPP(x) (int)floor((x) + 0.5) + +#define SWAP_I(x, y) \ + do \ + { \ + int _z = x; \ + x = y; \ + y = _z; \ + } \ + while (0) +#define SWAP_D(x, y) \ + do \ + { \ + double _z = x; \ + x = y; \ + y = _z; \ + } \ + while (0) + +const double MIN_ARC_GAP = 300.0; /* min arc gap (s) */ +const double CONST_AMB = 0.001; /* constraint to fixed ambiguity */ +const double THRES_RES = 0.3; /* threshold of residuals test (m) */ +const double LOG_PI = 1.14472988584940017; /* log(pi) */ +const double SQRT2 = 1.41421356237309510; /* sqrt(2) */ + +const double VAR_POS_PPP = std::pow(100.0, 2.0); /* init variance receiver position (m^2) */ +const double VAR_CLK = std::pow(100.0, 2.0); /* init variance receiver clock (m^2) */ +const double VAR_ZTD = std::pow(0.3, 2.0); /* init variance ztd (m^2) */ +const double VAR_GRA_PPP = std::pow(0.001, 2.0); /* init variance gradient (m^2) */ +const double VAR_BIAS = std::pow(100.0, 2.0); /* init variance phase-bias (m^2) */ + +const double VAR_IONO_OFF = std::pow(10.0, 2.0); /* variance of iono-model-off */ + + +/* functions originally included in RTKLIB/src/ppp_ar.c v2.4.2*/ +double lam_LC(int i, int j, int k); + +double L_LC(int i, int j, int k, const double *L); + +double P_LC(int i, int j, int k, const double *P); + +double var_LC(int i, int j, int k, double sig); + +double q_gamma(double a, double x, double log_gamma_a); + +double p_gamma(double a, double x, double log_gamma_a); + +double f_erfc(double x); + +double conffunc(int N, double B, double sig); + +void average_LC(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav, const double *azel); + +int fix_amb_WL(rtk_t *rtk, const nav_t *nav, int sat1, int sat2, int *NW); + +int is_depend(int sat1, int sat2, int *flgs, int *max_flg); + +int sel_amb(int *sat1, int *sat2, double *N, double *var, int n); + +int fix_sol(rtk_t *rtk, const int *sat1, const int *sat2, const double *NC, int n); + +int fix_amb_ROUND(rtk_t *rtk, int *sat1, int *sat2, const int *NW, int n); + +int fix_amb_ILS(rtk_t *rtk, int *sat1, int *sat2, int *NW, int n); + +int pppamb(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav, const double *azel); + + +/* functions originally included in RTKLIB/src/ppp.c v2.4.2 */ +void pppoutsolstat(rtk_t *rtk, int level, FILE *fp); + +void testeclipse(const obsd_t *obs, int n, const nav_t *nav, double *rs); + +double varerr(int sat, int sys, double el, int type, const prcopt_t *opt); + +void initx(rtk_t *rtk, double xi, double var, int i); + +int ifmeas(const obsd_t *obs, const nav_t *nav, const double *azel, + const prcopt_t *opt, const double *dantr, const double *dants, + double phw, double *meas, double *var); + +double gettgd_ppp(int sat, const nav_t *nav); + +int corr_ion(gtime_t time, const nav_t *nav, int sat, const double *pos, + const double *azel, int ionoopt, double *ion, double *var, + int *brk); + +int corrmeas(const obsd_t *obs, const nav_t *nav, const double *pos, + const double *azel, const prcopt_t *opt, + const double *dantr, const double *dants, double phw, + double *meas, double *var, int *brk); + +double gfmeas(const obsd_t *obs, const nav_t *nav); + +void udpos_ppp(rtk_t *rtk); + +void udclk_ppp(rtk_t *rtk); + +void udtrop_ppp(rtk_t *rtk); + +void detslp_ll(rtk_t *rtk, const obsd_t *obs, int n); + +void detslp_gf(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); + +void udbias_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); + +void udstate_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); + +void satantpcv(const double *rs, const double *rr, const pcv_t *pcv, double *dant); + +double prectrop(gtime_t time, const double *pos, const double *azel, + const prcopt_t *opt, const double *x, double *dtdx, + double *var); + +int res_ppp(int iter, const obsd_t *obs, int n, const double *rs, + const double *dts, const double *vare, const int *svh, + const nav_t *nav, const double *x, rtk_t *rtk, double *v, + double *H, double *R, double *azel); + +int pppnx(const prcopt_t *opt); + +void pppos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_preceph.cc b/src/algorithms/libs/rtklib/rtklib_preceph.cc new file mode 100644 index 000000000..72c62fbf1 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_preceph.cc @@ -0,0 +1,900 @@ +/*! + * \file rtklib_preceph.cc + * \brief precise ephemeris and clock functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * References : + * [1] S.Hilla, The Extended Standard Product 3 Orbit Format (SP3-c), + * 12 February, 2007 + * [2] J.Ray, W.Gurtner, RINEX Extensions to Handle Clock Information, + * 27 August, 1998 + * [3] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 + * [4] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, + * Space Technology Library, 2004 + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_preceph.h" +#include "rtklib_rtkcmn.h" + +/* satellite code to satellite system ----------------------------------------*/ +int code2sys(char code) +{ + if (code == 'G' || code == ' ') return SYS_GPS; + if (code == 'R') return SYS_GLO; + if (code == 'E') return SYS_GAL; /* extension to sp3-c */ + if (code == 'J') return SYS_QZS; /* extension to sp3-c */ + if (code == 'C') return SYS_BDS; /* extension to sp3-c */ + if (code == 'L') return SYS_LEO; /* extension to sp3-c */ + return SYS_NONE; +} + + +/* read sp3 header -----------------------------------------------------------*/ +int readsp3h(FILE *fp, gtime_t *time, char *type, int *sats, + double *bfact, char *tsys) +{ + int i, j, k = 0, ns = 0, sys, prn; + char buff[1024]; + + trace(3, "readsp3h:\n"); + + for (i = 0; i < 22; i++) + { + if (!fgets(buff, sizeof(buff), fp)) break; + + if (i == 0) + { + *type = buff[2]; + if (str2time(buff, 3, 28, time)) return 0; + } + else if (2 <= i && i <= 6) + { + if (i == 2) + { + ns = static_cast(str2num(buff, 4, 2)); + } + for (j = 0; j < 17 && k < ns; j++) + { + sys = code2sys(buff[9 + 3 * j]); + prn = static_cast(str2num(buff, 10 + 3 * j, 2)); + if (k < MAXSAT) sats[k++] = satno(sys, prn); + } + } + else if (i == 12) + { + strncpy(tsys, buff + 9, 3); + tsys[3] = '\0'; + } + else if (i == 14) + { + bfact[0] = str2num(buff, 3, 10); + bfact[1] = str2num(buff, 14, 12); + } + } + return ns; +} + + +/* add precise ephemeris -----------------------------------------------------*/ +int addpeph(nav_t *nav, peph_t *peph) +{ + peph_t *nav_peph; + + if (nav->ne >= nav->nemax) + { + nav->nemax += 256; + if (!(nav_peph = static_cast(realloc(nav->peph, sizeof(peph_t) * nav->nemax)))) + { + trace(1, "readsp3b malloc error n=%d\n", nav->nemax); + free(nav->peph); + nav->peph = nullptr; + nav->ne = nav->nemax = 0; + return 0; + } + nav->peph = nav_peph; + } + nav->peph[nav->ne++] = *peph; + return 1; +} + + +/* read sp3 body -------------------------------------------------------------*/ +void readsp3b(FILE *fp, char type, int *sats __attribute__((unused)), int ns, const double *bfact, + char *tsys, int index, int opt, nav_t *nav) +{ + peph_t peph; + gtime_t time; + double val, std, base; + int i, j, sat, sys, prn, n = ns * (type == 'P' ? 1 : 2), pred_o, pred_c, v; + char buff[1024]; + + trace(3, "readsp3b: type=%c ns=%d index=%d opt=%d\n", type, ns, index, opt); + + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "EOF", 3)) break; + + if (buff[0] != '*' || str2time(buff, 3, 28, &time)) + { + trace(2, "sp3 invalid epoch %31.31s\n", buff); + continue; + } + if (!strcmp(tsys, "UTC")) time = utc2gpst(time); /* utc->gpst */ + peph.time = time; + peph.index = index; + + for (i = 0; i < MAXSAT; i++) + { + for (j = 0; j < 4; j++) + { + peph.pos[i][j] = 0.0; + peph.std[i][j] = 0.0f; + peph.vel[i][j] = 0.0; + peph.vst[i][j] = 0.0f; + } + for (j = 0; j < 3; j++) + { + peph.cov[i][j] = 0.0f; + peph.vco[i][j] = 0.0f; + } + } + for (i = pred_o = pred_c = v = 0; i < n && fgets(buff, sizeof(buff), fp); i++) + { + if (strlen(buff) < 4 || (buff[0] != 'P' && buff[0] != 'V')) continue; + + sys = buff[1] == ' ' ? SYS_GPS : code2sys(buff[1]); + prn = static_cast(str2num(buff, 2, 2)); + if (sys == SYS_SBS) + prn += 100; + else if (sys == SYS_QZS) + prn += 192; /* extension to sp3-c */ + + if (!(sat = satno(sys, prn))) continue; + + if (buff[0] == 'P') + { + pred_c = strlen(buff) >= 76 && buff[75] == 'P'; + pred_o = strlen(buff) >= 80 && buff[79] == 'P'; + } + for (j = 0; j < 4; j++) + { + /* read option for predicted value */ + if (j < 3 && (opt & 1) && pred_o) continue; + if (j < 3 && (opt & 2) && !pred_o) continue; + if (j == 3 && (opt & 1) && pred_c) continue; + if (j == 3 && (opt & 2) && !pred_c) continue; + + val = str2num(buff, 4 + j * 14, 14); + std = str2num(buff, 61 + j * 3, j < 3 ? 2 : 3); + + if (buff[0] == 'P') + { /* position */ + if (val != 0.0 && fabs(val - 999999.999999) >= 1e-6) + { + peph.pos[sat - 1][j] = val * (j < 3 ? 1000.0 : 1e-6); + v = 1; /* valid epoch */ + } + if ((base = bfact[j < 3 ? 0 : 1]) > 0.0 && std > 0.0) + { + peph.std[sat - 1][j] = static_cast(std::pow(base, std) * (j < 3 ? 1e-3 : 1e-12)); + } + } + else if (v) + { /* velocity */ + if (val != 0.0 && fabs(val - 999999.999999) >= 1e-6) + { + peph.vel[sat - 1][j] = val * (j < 3 ? 0.1 : 1e-10); + } + if ((base = bfact[j < 3 ? 0 : 1]) > 0.0 && std > 0.0) + { + peph.vst[sat - 1][j] = static_cast(std::pow(base, std) * (j < 3 ? 1e-7 : 1e-16)); + } + } + } + } + if (v) + { + if (!addpeph(nav, &peph)) return; + } + } +} + + +/* compare precise ephemeris -------------------------------------------------*/ +int cmppeph(const void *p1, const void *p2) +{ + auto *q1 = (peph_t *)p1, *q2 = (peph_t *)p2; + double tt = timediff(q1->time, q2->time); + return tt < -1e-9 ? -1 : (tt > 1e-9 ? 1 : q1->index - q2->index); +} + + +/* combine precise ephemeris -------------------------------------------------*/ +void combpeph(nav_t *nav, int opt) +{ + int i, j, k, m; + + trace(3, "combpeph: ne=%d\n", nav->ne); + + qsort(nav->peph, nav->ne, sizeof(peph_t), cmppeph); + + if (opt & 4) return; + + for (i = 0, j = 1; j < nav->ne; j++) + { + if (fabs(timediff(nav->peph[i].time, nav->peph[j].time)) < 1e-9) + { + for (k = 0; k < MAXSAT; k++) + { + if (norm_rtk(nav->peph[j].pos[k], 4) <= 0.0) continue; + for (m = 0; m < 4; m++) nav->peph[i].pos[k][m] = nav->peph[j].pos[k][m]; + for (m = 0; m < 4; m++) nav->peph[i].std[k][m] = nav->peph[j].std[k][m]; + for (m = 0; m < 4; m++) nav->peph[i].vel[k][m] = nav->peph[j].vel[k][m]; + for (m = 0; m < 4; m++) nav->peph[i].vst[k][m] = nav->peph[j].vst[k][m]; + } + } + else if (++i < j) + nav->peph[i] = nav->peph[j]; + } + nav->ne = i + 1; + + trace(4, "combpeph: ne=%d\n", nav->ne); +} + + +/* read sp3 precise ephemeris file --------------------------------------------- + * read sp3 precise ephemeris/clock files and set them to navigation data + * args : char *file I sp3-c precise ephemeris file + * (wind-card * is expanded) + * nav_t *nav IO navigation data + * int opt I options (1: only observed + 2: only predicted + + * 4: not combined) + * return : none + * notes : see ref [1] + * precise ephemeris is appended and combined + * nav->peph and nav->ne must by properly initialized before calling the + * function + * only files with extensions of .sp3, .SP3, .eph* and .EPH* are read + *-----------------------------------------------------------------------------*/ +void readsp3(const char *file, nav_t *nav, int opt) +{ + FILE *fp; + gtime_t time = {0, 0}; + double bfact[2] = {}; + int i, j, n, ns, sats[MAXSAT] = {}; + char *efiles[MAXEXFILE], *ext, type = ' ', tsys[4] = ""; + + trace(3, "readpephs: file=%s\n", file); + + for (i = 0; i < MAXEXFILE; i++) + { + if (!(efiles[i] = static_cast(malloc(1024)))) + { + for (i--; i >= 0; i--) free(efiles[i]); + return; + } + } + /* expand wild card in file path */ + n = expath(file, efiles, MAXEXFILE); + + for (i = j = 0; i < n; i++) + { + if (!(ext = strrchr(efiles[i], '.'))) continue; + + if (!strstr(ext + 1, "sp3") && !strstr(ext + 1, ".SP3") && + !strstr(ext + 1, "eph") && !strstr(ext + 1, ".EPH")) continue; + + if (!(fp = fopen(efiles[i], "re"))) + { + trace(2, "sp3 file open error %s\n", efiles[i]); + continue; + } + /* read sp3 header */ + ns = readsp3h(fp, &time, &type, sats, bfact, tsys); + + /* read sp3 body */ + readsp3b(fp, type, sats, ns, bfact, tsys, j++, opt, nav); + + fclose(fp); + } + for (i = 0; i < MAXEXFILE; i++) free(efiles[i]); + + /* combine precise ephemeris */ + if (nav->ne > 0) combpeph(nav, opt); +} + + +/* read satellite antenna parameters ------------------------------------------- + * read satellite antenna parameters + * args : char *file I antenna parameter file + * gtime_t time I time + * nav_t *nav IO navigation data + * return : status (1:ok,0:error) + * notes : only support antex format for the antenna parameter file + *-----------------------------------------------------------------------------*/ +int readsap(const char *file, gtime_t time, nav_t *nav) +{ + pcvs_t pcvs = {0, 0, (pcv_t *){nullptr}}; + pcv_t pcv0 = {0, {}, {}, {0, 0}, {0, 0}, {{}, {}}, {{}, {}}}, *pcv; + int i; + + trace(3, "readsap : file=%s time=%s\n", file, time_str(time, 0)); + + if (!readpcv(file, &pcvs)) return 0; + + for (i = 0; i < MAXSAT; i++) + { + pcv = searchpcv(i + 1, "", time, &pcvs); + nav->pcvs[i] = pcv ? *pcv : pcv0; + } + free(pcv); + return 1; +} + + +/* read dcb parameters file --------------------------------------------------*/ +int readdcbf(const char *file, nav_t *nav, const sta_t *sta) +{ + FILE *fp; + double cbias; + char buff[256], str1[32], str2[32] = ""; + int i, j, sat, type = 0; + + trace(3, "readdcbf: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) + { + trace(2, "dcb parameters file open error: %s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (strstr(buff, "DIFFERENTIAL (P1-P2) CODE BIASES")) + type = 1; + else if (strstr(buff, "DIFFERENTIAL (P1-C1) CODE BIASES")) + type = 2; + else if (strstr(buff, "DIFFERENTIAL (P2-C2) CODE BIASES")) + type = 3; + + if (!type || sscanf(buff, "%s %s", str1, str2) < 1) continue; + + if ((cbias = str2num(buff, 26, 9)) == 0.0) continue; + + if (sta && (!strcmp(str1, "G") || !strcmp(str1, "R"))) + { /* receiver dcb */ + for (i = 0; i < MAXRCV; i++) + { + if (!strcmp(sta[i].name, str2)) break; + } + if (i < MAXRCV) + { + j = !strcmp(str1, "G") ? 0 : 1; + nav->rbias[i][j][type - 1] = cbias * 1e-9 * SPEED_OF_LIGHT; /* ns -> m */ + } + } + else if ((sat = satid2no(str1))) + { /* satellite dcb */ + nav->cbias[sat - 1][type - 1] = cbias * 1e-9 * SPEED_OF_LIGHT; /* ns -> m */ + } + } + fclose(fp); + + return 1; +} + + +/* read dcb parameters --------------------------------------------------------- + * read differential code bias (dcb) parameters + * args : char *file I dcb parameters file (wild-card * expanded) + * nav_t *nav IO navigation data + * sta_t *sta I station info data to inport receiver dcb + * (NULL: no use) + * return : status (1:ok,0:error) + * notes : currently only p1-c1 bias of code *.dcb file + *-----------------------------------------------------------------------------*/ +int readdcb(const char *file, nav_t *nav, const sta_t *sta) +{ + int i, j, n; + char *efiles[MAXEXFILE] = {}; + + trace(3, "readdcb : file=%s\n", file); + + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < 3; j++) + { + nav->cbias[i][j] = 0.0; + } + for (i = 0; i < MAXEXFILE; i++) + { + if (!(efiles[i] = static_cast(malloc(1024)))) + { + for (i--; i >= 0; i--) free(efiles[i]); + return 0; + } + } + n = expath(file, efiles, MAXEXFILE); + + for (i = 0; i < n; i++) + { + readdcbf(efiles[i], nav, sta); + } + for (i = 0; i < MAXEXFILE; i++) free(efiles[i]); + + return 1; +} + + +/* add satellite fcb ---------------------------------------------------------*/ +int addfcb(nav_t *nav, gtime_t ts, gtime_t te, int sat, + const double *bias, const double *std) +{ + fcbd_t *nav_fcb; + int i, j; + + if (nav->nf > 0 && fabs(timediff(ts, nav->fcb[nav->nf - 1].ts)) <= 1e-3) + { + for (i = 0; i < 3; i++) + { + nav->fcb[nav->nf - 1].bias[sat - 1][i] = bias[i]; + nav->fcb[nav->nf - 1].std[sat - 1][i] = std[i]; + } + return 1; + } + if (nav->nf >= nav->nfmax) + { + nav->nfmax = nav->nfmax <= 0 ? 2048 : nav->nfmax * 2; + if (!(nav_fcb = static_cast(realloc(nav->fcb, sizeof(fcbd_t) * nav->nfmax)))) + { + free(nav->fcb); + nav->nf = nav->nfmax = 0; + return 0; + } + nav->fcb = nav_fcb; + } + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < 3; j++) + { + nav->fcb[nav->nf].bias[i][j] = nav->fcb[nav->nf].std[i][j] = 0.0; + } + for (i = 0; i < 3; i++) + { + nav->fcb[nav->nf].bias[sat - 1][i] = bias[i]; + nav->fcb[nav->nf].std[sat - 1][i] = std[i]; + } + nav->fcb[nav->nf].ts = ts; + nav->fcb[nav->nf++].te = te; + return 1; +} + + +/* read satellite fcb file ---------------------------------------------------*/ +int readfcbf(const char *file, nav_t *nav) +{ + FILE *fp; + gtime_t ts, te; + double ep1[6], ep2[6], bias[3] = {}, std[3] = {}; + char buff[1024], str[32], *p; + int sat; + + trace(3, "readfcbf: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) + { + trace(2, "fcb parameters file open error: %s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if ((p = strchr(buff, '#'))) *p = '\0'; + if (sscanf(buff, + "%lf/%lf/%lf %lf:%lf:%lf %lf/%lf/%lf %lf:%lf:%lf %s" + "%lf %lf %lf %lf %lf %lf", + ep1, ep1 + 1, ep1 + 2, ep1 + 3, ep1 + 4, ep1 + 5, + ep2, ep2 + 1, ep2 + 2, ep2 + 3, ep2 + 4, ep2 + 5, str, bias, std, bias + 1, std + 1, + bias + 2, std + 2) < 17) continue; + if (!(sat = satid2no(str))) continue; + ts = epoch2time(ep1); + te = epoch2time(ep2); + if (!addfcb(nav, ts, te, sat, bias, std)) + { + fclose(fp); + return 0; + } + } + fclose(fp); + return 1; +} + + +/* compare satellite fcb -----------------------------------------------------*/ +int cmpfcb(const void *p1, const void *p2) +{ + auto *q1 = (fcbd_t *)p1, *q2 = (fcbd_t *)p2; + double tt = timediff(q1->ts, q2->ts); + return tt < -1e-3 ? -1 : (tt > 1e-3 ? 1 : 0); +} + + +/* read satellite fcb data ----------------------------------------------------- + * read satellite fractional cycle bias (dcb) parameters + * args : char *file I fcb parameters file (wild-card * expanded) + * nav_t *nav IO navigation data + * return : status (1:ok,0:error) + * notes : fcb data appended to navigation data + *-----------------------------------------------------------------------------*/ +int readfcb(const char *file, nav_t *nav) +{ + char *efiles[MAXEXFILE] = {}; + int i, n; + + trace(3, "readfcb : file=%s\n", file); + + for (i = 0; i < MAXEXFILE; i++) + { + if (!(efiles[i] = static_cast(malloc(1024)))) + { + for (i--; i >= 0; i--) free(efiles[i]); + return 0; + } + } + n = expath(file, efiles, MAXEXFILE); + + for (i = 0; i < n; i++) + { + readfcbf(efiles[i], nav); + } + for (i = 0; i < MAXEXFILE; i++) free(efiles[i]); + + if (nav->nf > 1) + { + qsort(nav->fcb, nav->nf, sizeof(fcbd_t), cmpfcb); + } + return 1; +} + + +/* polynomial interpolation by Neville's algorithm ---------------------------*/ +double interppol(const double *x, double *y, int n) +{ + int i, j; + + for (j = 1; j < n; j++) + { + for (i = 0; i < n - j; i++) + { + y[i] = (x[i + j] * y[i] - x[i] * y[i + 1]) / (x[i + j] - x[i]); + } + } + return y[0]; +} + + +/* satellite position by precise ephemeris -----------------------------------*/ +int pephpos(gtime_t time, int sat, const nav_t *nav, double *rs, + double *dts, double *vare, double *varc) +{ + double t[NMAX + 1], p[3][NMAX + 1], c[2], *pos, std = 0.0, s[3], sinl, cosl; + int i, j, k, index; + + trace(4, "pephpos : time=%s sat=%2d\n", time_str(time, 3), sat); + + rs[0] = rs[1] = rs[2] = dts[0] = 0.0; + + if (nav->ne < NMAX + 1 || + timediff(time, nav->peph[0].time) < -MAXDTE || + timediff(time, nav->peph[nav->ne - 1].time) > MAXDTE) + { + trace(3, "no prec ephem %s sat=%2d\n", time_str(time, 0), sat); + return 0; + } + /* binary search */ + for (i = 0, j = nav->ne - 1; i < j;) + { + k = (i + j) / 2; + if (timediff(nav->peph[k].time, time) < 0.0) + i = k + 1; + else + j = k; + } + index = i <= 0 ? 0 : i - 1; + + /* polynomial interpolation for orbit */ + i = index - (NMAX + 1) / 2; + if (i < 0) + i = 0; + else if (i + NMAX >= nav->ne) + i = nav->ne - NMAX - 1; + + for (j = 0; j <= NMAX; j++) + { + t[j] = timediff(nav->peph[i + j].time, time); + if (norm_rtk(nav->peph[i + j].pos[sat - 1], 3) <= 0.0) + { + trace(3, "prec ephem outage %s sat=%2d\n", time_str(time, 0), sat); + return 0; + } + } + for (j = 0; j <= NMAX; j++) + { + pos = nav->peph[i + j].pos[sat - 1]; +#if 0 + p[0][j] = pos[0]; + p[1][j] = pos[1]; +#else + /* correciton for earh rotation ver.2.4.0 */ + sinl = sin(DEFAULT_OMEGA_EARTH_DOT * t[j]); + cosl = cos(DEFAULT_OMEGA_EARTH_DOT * t[j]); + p[0][j] = cosl * pos[0] - sinl * pos[1]; + p[1][j] = sinl * pos[0] + cosl * pos[1]; +#endif + p[2][j] = pos[2]; + } + for (i = 0; i < 3; i++) + { + rs[i] = interppol(t, p[i], NMAX + 1); + } + if (vare) + { + for (i = 0; i < 3; i++) s[i] = nav->peph[index].std[sat - 1][i]; + std = norm_rtk(s, 3); + + /* extrapolation error for orbit */ + if (t[0] > 0.0) + std += EXTERR_EPH * std::pow(t[0], 2.0) / 2.0; + else if (t[NMAX] < 0.0) + std += EXTERR_EPH * std::pow(t[NMAX], 2.0) / 2.0; + *vare = std::pow(std, 2.0); + } + /* linear interpolation for clock */ + t[0] = timediff(time, nav->peph[index].time); + t[1] = timediff(time, nav->peph[index + 1].time); + c[0] = nav->peph[index].pos[sat - 1][3]; + c[1] = nav->peph[index + 1].pos[sat - 1][3]; + + if (t[0] <= 0.0) + { + if ((dts[0] = c[0]) != 0.0) + { + std = nav->peph[index].std[sat - 1][3] * SPEED_OF_LIGHT - EXTERR_CLK * t[0]; + } + } + else if (t[1] >= 0.0) + { + if ((dts[0] = c[1]) != 0.0) + { + std = nav->peph[index + 1].std[sat - 1][3] * SPEED_OF_LIGHT + EXTERR_CLK * t[1]; + } + } + else if (c[0] != 0.0 && c[1] != 0.0) + { + dts[0] = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]); + i = t[0] < -t[1] ? 0 : 1; + std = nav->peph[index + i].std[sat - 1][3] + EXTERR_CLK * fabs(t[i]); + } + else + { + dts[0] = 0.0; + } + if (varc) *varc = std::pow(std, 2.0); + return 1; +} + + +/* satellite clock by precise clock ------------------------------------------*/ +int pephclk(gtime_t time, int sat, const nav_t *nav, double *dts, + double *varc) +{ + double t[2], c[2], std; + int i, j, k, index; + + trace(4, "pephclk : time=%s sat=%2d\n", time_str(time, 3), sat); + + if (nav->nc < 2 || + timediff(time, nav->pclk[0].time) < -MAXDTE || + timediff(time, nav->pclk[nav->nc - 1].time) > MAXDTE) + { + trace(3, "no prec clock %s sat=%2d\n", time_str(time, 0), sat); + return 1; + } + /* binary search */ + for (i = 0, j = nav->nc - 1; i < j;) + { + k = (i + j) / 2; + if (timediff(nav->pclk[k].time, time) < 0.0) + i = k + 1; + else + j = k; + } + index = i <= 0 ? 0 : i - 1; + + /* linear interpolation for clock */ + t[0] = timediff(time, nav->pclk[index].time); + t[1] = timediff(time, nav->pclk[index + 1].time); + c[0] = nav->pclk[index].clk[sat - 1][0]; + c[1] = nav->pclk[index + 1].clk[sat - 1][0]; + + if (t[0] <= 0.0) + { + if ((dts[0] = c[0]) == 0.0) return 0; + std = nav->pclk[index].std[sat - 1][0] * SPEED_OF_LIGHT - EXTERR_CLK * t[0]; + } + else if (t[1] >= 0.0) + { + if ((dts[0] = c[1]) == 0.0) return 0; + std = nav->pclk[index + 1].std[sat - 1][0] * SPEED_OF_LIGHT + EXTERR_CLK * t[1]; + } + else if (c[0] != 0.0 && c[1] != 0.0) + { + dts[0] = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]); + i = t[0] < -t[1] ? 0 : 1; + std = nav->pclk[index + i].std[sat - 1][0] * SPEED_OF_LIGHT + EXTERR_CLK * fabs(t[i]); + } + else + { + trace(3, "prec clock outage %s sat=%2d\n", time_str(time, 0), sat); + return 0; + } + if (varc) *varc = std::pow(std, 2.0); + return 1; +} + + +/* satellite antenna phase center offset --------------------------------------- + * compute satellite antenna phase center offset in ecef + * args : gtime_t time I time (gpst) + * double *rs I satellite position and velocity (ecef) + * {x,y,z,vx,vy,vz} (m|m/s) + * int sat I satellite number + * nav_t *nav I navigation data + * double *dant I satellite antenna phase center offset (ecef) + * {dx,dy,dz} (m) (iono-free LC value) + * return : none + *-----------------------------------------------------------------------------*/ +void satantoff(gtime_t time, const double *rs, int sat, const nav_t *nav, + double *dant) +{ + const double *lam = nav->lam[sat - 1]; + const pcv_t *pcv = nav->pcvs + sat - 1; + double ex[3], ey[3], ez[3], es[3], r[3], rsun[3], gmst, erpv[5] = {}; + double gamma, C1, C2, dant1, dant2; + int i, j = 0, k = 1; + + trace(4, "satantoff: time=%s sat=%2d\n", time_str(time, 3), sat); + + /* sun position in ecef */ + sunmoonpos(gpst2utc(time), erpv, rsun, nullptr, &gmst); + + /* unit vectors of satellite fixed coordinates */ + for (i = 0; i < 3; i++) r[i] = -rs[i]; + if (!normv3(r, ez)) return; + for (i = 0; i < 3; i++) r[i] = rsun[i] - rs[i]; + if (!normv3(r, es)) return; + cross3(ez, es, r); + if (!normv3(r, ey)) return; + cross3(ey, ez, ex); + + if (NFREQ >= 3 && (satsys(sat, nullptr) & (SYS_GAL | SYS_SBS))) k = 2; + + if (NFREQ < 2 || lam[j] == 0.0 || lam[k] == 0.0) return; + + gamma = std::pow(lam[k], 2.0) / std::pow(lam[j], 2.0); + C1 = gamma / (gamma - 1.0); + C2 = -1.0 / (gamma - 1.0); + + /* iono-free LC */ + for (i = 0; i < 3; i++) + { + dant1 = pcv->off[j][0] * ex[i] + pcv->off[j][1] * ey[i] + pcv->off[j][2] * ez[i]; + dant2 = pcv->off[k][0] * ex[i] + pcv->off[k][1] * ey[i] + pcv->off[k][2] * ez[i]; + dant[i] = C1 * dant1 + C2 * dant2; + } +} + + +/* satellite position/clock by precise ephemeris/clock ------------------------- + * compute satellite position/clock with precise ephemeris/clock + * args : gtime_t time I time (gpst) + * int sat I satellite number + * nav_t *nav I navigation data + * int opt I sat position option + * (0: center of mass, 1: antenna phase center) + * double *rs O sat position and velocity (ecef) + * {x,y,z,vx,vy,vz} (m|m/s) + * double *dts O sat clock {bias,drift} (s|s/s) + * double *var IO sat position and clock error variance (m) + * (NULL: no output) + * return : status (1:ok,0:error or data outage) + * notes : clock includes relativistic correction but does not contain code bias + * before calling the function, nav->peph, nav->ne, nav->pclk and + * nav->nc must be set by calling readsp3(), readrnx() or readrnxt() + * if precise clocks are not set, clocks in sp3 are used instead + *-----------------------------------------------------------------------------*/ +int peph2pos(gtime_t time, int sat, const nav_t *nav, int opt, + double *rs, double *dts, double *var) +{ + double rss[3], rst[3], dtss[1], dtst[1], dant[3] = {}, vare = 0.0, varc = 0.0, tt = 1e-3; + int i; + + trace(4, "peph2pos: time=%s sat=%2d opt=%d\n", time_str(time, 3), sat, opt); + + if (sat <= 0 || MAXSAT < sat) return 0; + + /* satellite position and clock bias */ + if (!pephpos(time, sat, nav, rss, dtss, &vare, &varc) || + !pephclk(time, sat, nav, dtss, &varc)) return 0; + + time = timeadd(time, tt); + if (!pephpos(time, sat, nav, rst, dtst, nullptr, nullptr) || + !pephclk(time, sat, nav, dtst, nullptr)) return 0; + + /* satellite antenna offset correction */ + if (opt) + { + satantoff(time, rss, sat, nav, dant); + } + for (i = 0; i < 3; i++) + { + rs[i] = rss[i] + dant[i]; + rs[i + 3] = (rst[i] - rss[i]) / tt; + } + /* relativistic effect correction */ + if (dtss[0] != 0.0) + { + dts[0] = dtss[0] - 2.0 * dot(rs, rs + 3, 3) / SPEED_OF_LIGHT / SPEED_OF_LIGHT; + dts[1] = (dtst[0] - dtss[0]) / tt; + } + else + { /* no precise clock */ + dts[0] = dts[1] = 0.0; + } + if (var) *var = vare + varc; + + return 1; +} diff --git a/src/algorithms/libs/rtklib/rtklib_preceph.h b/src/algorithms/libs/rtklib/rtklib_preceph.h new file mode 100644 index 000000000..1186b6a88 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_preceph.h @@ -0,0 +1,107 @@ +/*! + * \file rtklib_preceph.h + * \brief precise ephemeris and clock functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * References : + * [1] S.Hilla, The Extended Standard Product 3 Orbit Format (SP3-c), + * 12 February, 2007 + * [2] J.Ray, W.Gurtner, RINEX Extensions to Handle Clock Information, + * 27 August, 1998 + * [3] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 + * [4] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, + * Space Technology Library, 2004 + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_PRECEPH_H_ +#define GNSS_SDR_RTKLIB_PRECEPH_H_ + +#include "rtklib.h" + + +const int NMAX = 10; /* order of polynomial interpolation */ +const double MAXDTE = 900.0; /* max time difference to ephem time (s) */ +const double EXTERR_CLK = 1e-3; /* extrapolation error for clock (m/s) */ +const double EXTERR_EPH = 5e-7; /* extrapolation error for ephem (m/s^2) */ + +int code2sys(char code); +int readsp3h(FILE *fp, gtime_t *time, char *type, int *sats, + double *bfact, char *tsys); +int addpeph(nav_t *nav, peph_t *peph); +void readsp3b(FILE *fp, char type, int *sats, int ns, const double *bfact, + char *tsys, int index, int opt, nav_t *nav); +int cmppeph(const void *p1, const void *p2); +void combpeph(nav_t *nav, int opt); +void readsp3(const char *file, nav_t *nav, int opt); +int readsap(const char *file, gtime_t time, nav_t *nav); +int readdcbf(const char *file, nav_t *nav, const sta_t *sta); +int readdcb(const char *file, nav_t *nav, const sta_t *sta); +int addfcb(nav_t *nav, gtime_t ts, gtime_t te, int sat, + const double *bias, const double *std); +int readfcbf(const char *file, nav_t *nav); +int readdcb(const char *file, nav_t *nav, const sta_t *sta); +int addfcb(nav_t *nav, gtime_t ts, gtime_t te, int sat, + const double *bias, const double *std); +int readfcbf(const char *file, nav_t *nav); +int cmpfcb(const void *p1, const void *p2); +int readfcb(const char *file, nav_t *nav); +double interppol(const double *x, double *y, int n); +int pephpos(gtime_t time, int sat, const nav_t *nav, double *rs, + double *dts, double *vare, double *varc); + +int pephclk(gtime_t time, int sat, const nav_t *nav, double *dts, + double *varc); + +void satantoff(gtime_t time, const double *rs, int sat, const nav_t *nav, + double *dant); +int peph2pos(gtime_t time, int sat, const nav_t *nav, int opt, + double *rs, double *dts, double *var); + +#endif // GNSS_SDR_RTKLIB_PRECEPH_H_ diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm.cc b/src/algorithms/libs/rtklib/rtklib_rtcm.cc new file mode 100644 index 000000000..c82065d2c --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm.cc @@ -0,0 +1,427 @@ +/*! + * \file rtklib_rtcm.cc + * \brief RTCM functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_rtcm.h" +#include "rtklib_rtkcmn.h" + +//extern int encode_rtcm3(rtcm_t *rtcm, int type, int sync); + + +/* initialize rtcm control ----------------------------------------------------- + * initialize rtcm control struct and reallocate memory for observation and + * ephemeris buffer in rtcm control struct + * args : rtcm_t *raw IO rtcm control struct + * return : status (1:ok,0:memory allocation error) + *-----------------------------------------------------------------------------*/ +int init_rtcm(rtcm_t *rtcm) +{ + gtime_t time0 = {0, 0.0}; + obsd_t data0 = {{0, 0.0}, 0, 0, {0}, {0}, {0}, {0.0}, {0.0}, {0.0}}; + eph_t eph0 = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + geph_t geph0 = {0, -1, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0.0}, {0.0}, {0.0}, + 0.0, 0.0, 0.0}; + ssr_t ssr0 = {{{0, 0.0}}, {0.0}, {0}, 0, 0, 0, 0, {0.0}, {0.0}, {0.0}, 0.0, {0.0}, {0.0}, {0.0}, 0.0, 0.0, '0'}; + int i, j; + + trace(3, "init_rtcm:\n"); + + rtcm->staid = rtcm->stah = rtcm->seqno = rtcm->outtype = 0; + rtcm->time = rtcm->time_s = time0; + rtcm->sta.name[0] = rtcm->sta.marker[0] = '\0'; + rtcm->sta.antdes[0] = rtcm->sta.antsno[0] = '\0'; + rtcm->sta.rectype[0] = rtcm->sta.recver[0] = rtcm->sta.recsno[0] = '\0'; + rtcm->sta.antsetup = rtcm->sta.itrf = rtcm->sta.deltype = 0; + for (i = 0; i < 3; i++) + { + rtcm->sta.pos[i] = rtcm->sta.del[i] = 0.0; + } + rtcm->sta.hgt = 0.0; + rtcm->dgps = nullptr; + for (i = 0; i < MAXSAT; i++) + { + rtcm->ssr[i] = ssr0; + } + rtcm->msg[0] = rtcm->msgtype[0] = rtcm->opt[0] = '\0'; + for (i = 0; i < 6; i++) rtcm->msmtype[i][0] = '\0'; + rtcm->obsflag = rtcm->ephsat = 0; + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ + NEXOBS; j++) + { + rtcm->cp[i][j] = 0.0; + rtcm->lock[i][j] = rtcm->loss[i][j] = 0; + rtcm->lltime[i][j] = time0; + } + rtcm->nbyte = rtcm->nbit = rtcm->len = 0; + rtcm->word = 0; + for (i = 0; i < 100; i++) rtcm->nmsg2[i] = 0; + for (i = 0; i < 300; i++) rtcm->nmsg3[i] = 0; + + rtcm->obs.data = nullptr; + rtcm->nav.eph = nullptr; + rtcm->nav.geph = nullptr; + + /* reallocate memory for observation and ephemris buffer */ + if (!(rtcm->obs.data = static_cast(malloc(sizeof(obsd_t) * MAXOBS))) || + !(rtcm->nav.eph = static_cast(malloc(sizeof(eph_t) * MAXSAT))) || + !(rtcm->nav.geph = static_cast(malloc(sizeof(geph_t) * MAXPRNGLO)))) + { + free_rtcm(rtcm); + return 0; + } + rtcm->obs.n = 0; + rtcm->nav.n = MAXSAT; + rtcm->nav.ng = MAXPRNGLO; + for (i = 0; i < MAXOBS; i++) rtcm->obs.data[i] = data0; + for (i = 0; i < MAXSAT; i++) rtcm->nav.eph[i] = eph0; + for (i = 0; i < MAXPRNGLO; i++) rtcm->nav.geph[i] = geph0; + return 1; +} + + +/* free rtcm control ---------------------------------------------------------- + * free observation and ephemris buffer in rtcm control struct + * args : rtcm_t *raw IO rtcm control struct + * return : none + *-----------------------------------------------------------------------------*/ +void free_rtcm(rtcm_t *rtcm) +{ + trace(3, "free_rtcm:\n"); + + /* free memory for observation and ephemeris buffer */ + free(rtcm->obs.data); + rtcm->obs.data = nullptr; + rtcm->obs.n = 0; + free(rtcm->nav.eph); + rtcm->nav.eph = nullptr; + rtcm->nav.n = 0; + free(rtcm->nav.geph); + rtcm->nav.geph = nullptr; + rtcm->nav.ng = 0; +} + + +/* input rtcm 2 message from stream -------------------------------------------- + * fetch next rtcm 2 message and input a message from byte stream + * args : rtcm_t *rtcm IO rtcm control struct + * unsigned char data I stream data (1 byte) + * return : status (-1: error message, 0: no message, 1: input observation data, + * 2: input ephemeris, 5: input station pos/ant parameters, + * 6: input time parameter, 7: input dgps corrections, + * 9: input special message) + * notes : before firstly calling the function, time in rtcm control struct has + * to be set to the approximate time within 1/2 hour in order to resolve + * ambiguity of time in rtcm messages. + * supported msgs RTCM ver.2: 1,3,9,14,16,17,18,19,22 + * refer [1] for RTCM ver.2 + *-----------------------------------------------------------------------------*/ +int input_rtcm2(rtcm_t *rtcm, unsigned char data) +{ + unsigned char preamb; + int i; + + trace(5, "input_rtcm2: data=%02x\n", data); + + if ((data & 0xC0) != 0x40) return 0; /* ignore if upper 2bit != 01 */ + + for (i = 0; i < 6; i++, data >>= 1) + { /* decode 6-of-8 form */ + rtcm->word = (rtcm->word << 1) + (data & 1); + + /* synchronize frame */ + if (rtcm->nbyte == 0) + { + preamb = static_cast(rtcm->word >> 22); + if (rtcm->word & 0x40000000) preamb ^= 0xFF; /* decode preamble */ + if (preamb != RTCM2PREAMB) continue; + + /* check parity */ + if (!decode_word(rtcm->word, rtcm->buff)) continue; + rtcm->nbyte = 3; + rtcm->nbit = 0; + continue; + } + if (++rtcm->nbit < 30) + continue; + + rtcm->nbit = 0; + + /* check parity */ + if (!decode_word(rtcm->word, rtcm->buff + rtcm->nbyte)) + { + trace(2, "rtcm2 partity error: i=%d word=%08x\n", i, rtcm->word); + rtcm->nbyte = 0; + rtcm->word &= 0x3; + continue; + } + rtcm->nbyte += 3; + if (rtcm->nbyte == 6) rtcm->len = (rtcm->buff[5] >> 3) * 3 + 6; + if (rtcm->nbyte < rtcm->len) continue; + rtcm->nbyte = 0; + rtcm->word &= 0x3; + + /* decode rtcm2 message */ + return decode_rtcm2(rtcm); + } + return 0; +} + + +/* input rtcm 3 message from stream -------------------------------------------- + * fetch next rtcm 3 message and input a message from byte stream + * args : rtcm_t *rtcm IO rtcm control struct + * unsigned char data I stream data (1 byte) + * return : status (-1: error message, 0: no message, 1: input observation data, + * 2: input ephemeris, 5: input station pos/ant parameters, + * 10: input ssr messages) + * notes : before firstly calling the function, time in rtcm control struct has + * to be set to the approximate time within 1/2 week in order to resolve + * ambiguity of time in rtcm messages. + * + * to specify input options, set rtcm->opt to the following option + * strings separated by spaces. + * + * -EPHALL : input all ephemerides + * -STA=nnn : input only message with STAID=nnn + * -GLss : select signal ss for GPS MSM (ss=1C,1P,...) + * -RLss : select signal ss for GLO MSM (ss=1C,1P,...) + * -ELss : select signal ss for GAL MSM (ss=1C,1B,...) + * -JLss : select signal ss for QZS MSM (ss=1C,2C,...) + * -CLss : select signal ss for BDS MSM (ss=2I,7I,...) + * + * supported RTCM 3 messages + * (ref [2][3][4][5][6][7][8][9][10][11][12][13][14][15]) + * + * TYPE GPS GLOASS GALILEO QZSS BEIDOU SBAS + * ---------------------------------------------------------------------- + * OBS C-L1 : 1001~ 1009~ - - - - + * F-L1 : 1002 1010 - - - - + * C-L12 : 1003~ 1011~ - - - - + * F-L12 : 1004 1012 - - - - + * + * NAV : 1019 1020 1045* 1044* 1047* - + * - - 1046* - - - + * + * MSM 1 : 1071~ 1081~ 1091~ 1111*~ 1121*~ 1101*~ + * 2 : 1072~ 1082~ 1092~ 1112*~ 1122*~ 1102*~ + * 3 : 1073~ 1083~ 1093~ 1113*~ 1123*~ 1103*~ + * 4 : 1074 1084 1094 1114* 1124* 1104* + * 5 : 1075 1085 1095 1115* 1125* 1105* + * 6 : 1076 1086 1096 1116* 1126* 1106* + * 7 : 1077 1087 1097 1117* 1127* 1107* + * + * SSR OBT : 1057 1063 1240* 1246* 1258* - + * CLK : 1058 1064 1241* 1247* 1259* - + * BIAS : 1059 1065 1242* 1248* 1260* - + * OBTCLK: 1060 1066 1243* 1249* 1261* - + * URA : 1061 1067 1244* 1250* 1262* - + * HRCLK : 1062 1068 1245* 1251* 1263* - + * + * ANT INFO : 1005 1006 1007 1008 1033 + * ---------------------------------------------------------------------- + * (* draft, ~ only encode) + * + * for MSM observation data with multiple signals for a frequency, + * a signal is selected according to internal priority. to select + * a specified signal, use the input options. + * + * rtcm3 message format: + * +----------+--------+-----------+--------------------+----------+ + * | preamble | 000000 | length | data message | parity | + * +----------+--------+-----------+--------------------+----------+ + * |<-- 8 --->|<- 6 -->|<-- 10 --->|<--- length x 8 --->|<-- 24 -->| + * + *-----------------------------------------------------------------------------*/ +int input_rtcm3(rtcm_t *rtcm, unsigned char data) +{ + trace(5, "input_rtcm3: data=%02x\n", data); + + /* synchronize frame */ + if (rtcm->nbyte == 0) + { + if (data != RTCM3PREAMB) return 0; + rtcm->buff[rtcm->nbyte++] = data; + return 0; + } + rtcm->buff[rtcm->nbyte++] = data; + + if (rtcm->nbyte == 3) + { + rtcm->len = getbitu(rtcm->buff, 14, 10) + 3; /* length without parity */ + } + if (rtcm->nbyte < 3 || rtcm->nbyte < rtcm->len + 3) return 0; + rtcm->nbyte = 0; + + /* check parity */ + if (rtk_crc24q(rtcm->buff, rtcm->len) != getbitu(rtcm->buff, rtcm->len * 8, 24)) + { + trace(2, "rtcm3 parity error: len=%d\n", rtcm->len); + return 0; + } + /* decode rtcm3 message */ + return decode_rtcm3(rtcm); +} + + +/* input rtcm 2 message from file ---------------------------------------------- + * fetch next rtcm 2 message and input a message from file + * args : rtcm_t *rtcm IO rtcm control struct + * FILE *fp I file pointer + * return : status (-2: end of file, -1...10: same as above) + * notes : same as above + *-----------------------------------------------------------------------------*/ +int input_rtcm2f(rtcm_t *rtcm, FILE *fp) +{ + int i, data = 0, ret; + + trace(4, "input_rtcm2f: data=%02x\n", data); + + for (i = 0; i < 4096; i++) + { + if ((data = fgetc(fp)) == EOF) return -2; + if ((ret = input_rtcm2(rtcm, static_cast(data)))) return ret; + } + return 0; /* return at every 4k bytes */ +} + + +/* input rtcm 3 message from file ---------------------------------------------- + * fetch next rtcm 3 message and input a message from file + * args : rtcm_t *rtcm IO rtcm control struct + * FILE *fp I file pointer + * return : status (-2: end of file, -1...10: same as above) + * notes : same as above + *-----------------------------------------------------------------------------*/ +int input_rtcm3f(rtcm_t *rtcm, FILE *fp) +{ + int i, data = 0, ret; + + trace(4, "input_rtcm3f: data=%02x\n", data); + + for (i = 0; i < 4096; i++) + { + if ((data = fgetc(fp)) == EOF) return -2; + if ((ret = input_rtcm3(rtcm, static_cast(data)))) return ret; + } + return 0; /* return at every 4k bytes */ +} + + +/* generate rtcm 2 message ----------------------------------------------------- + * generate rtcm 2 message + * args : rtcm_t *rtcm IO rtcm control struct + * int type I message type + * int sync I sync flag (1:another message follows) + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int gen_rtcm2(rtcm_t *rtcm, int type, int sync) +{ + trace(4, "gen_rtcm2: type=%d sync=%d\n", type, sync); + + rtcm->nbit = rtcm->len = rtcm->nbyte = 0; + + /* not yet implemented */ + + return 0; +} + + +///* generate rtcm 3 message ----------------------------------------------------- +// * generate rtcm 3 message +// * args : rtcm_t *rtcm IO rtcm control struct +// * int type I message type +// * int sync I sync flag (1:another message follows) +// * return : status (1:ok,0:error) +// *-----------------------------------------------------------------------------*/ +//int gen_rtcm3(rtcm_t *rtcm, int type, int sync) +//{ +// unsigned int crc; +// int i = 0; +// +// trace(4, "gen_rtcm3: type=%d sync=%d\n", type, sync); +// +// rtcm->nbit = rtcm->len = rtcm->nbyte = 0; +// +// /* set preamble and reserved */ +// setbitu(rtcm->buff, i, 8, RTCM3PREAMB); i += 8; +// setbitu(rtcm->buff, i, 6, 0 ); i += 6; +// setbitu(rtcm->buff, i, 10, 0 ); i += 10; +// +// /* encode rtcm 3 message body */ +// if (!encode_rtcm3(rtcm, type, sync)) return 0; +// +// /* padding to align 8 bit boundary */ +// for (i = rtcm->nbit;i%8;i++) +// { +// setbitu(rtcm->buff, i, 1, 0); +// } +// /* message length (header+data) (bytes) */ +// if ((rtcm->len = i/8) >= 3+1024) +// { +// trace(2, "generate rtcm 3 message length error len=%d\n", rtcm->len-3); +// rtcm->nbit = rtcm->len = 0; +// return 0; +// } +// /* message length without header and parity */ +// setbitu(rtcm->buff, 14, 10, rtcm->len-3); +// +// /* crc-24q */ +// crc = rtk_crc24q(rtcm->buff, rtcm->len); +// setbitu(rtcm->buff, i, 24, crc); +// +// /* length total (bytes) */ +// rtcm->nbyte = rtcm->len+3; +// +// return 1; +//} diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm.h b/src/algorithms/libs/rtklib/rtklib_rtcm.h new file mode 100644 index 000000000..c2efbb378 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm.h @@ -0,0 +1,76 @@ +/*! + * \file rtklib_rtcm.h + * \brief RTCM functions headers + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + + +#ifndef GNSS_SDR_RTKLIB_RTCM_H_ +#define GNSS_SDR_RTKLIB_RTCM_H_ + +#include "rtklib.h" +#include "rtklib_rtcm2.h" +#include "rtklib_rtcm3.h" + +#define RTCM2PREAMB 0x66 /* rtcm ver.2 frame preamble */ +#define RTCM3PREAMB 0xD3 /* rtcm ver.3 frame preamble */ + + +int init_rtcm(rtcm_t *rtcm); +void free_rtcm(rtcm_t *rtcm); +int input_rtcm2(rtcm_t *rtcm, unsigned char data); +int input_rtcm3(rtcm_t *rtcm, unsigned char data); +int input_rtcm2f(rtcm_t *rtcm, FILE *fp); +int input_rtcm3f(rtcm_t *rtcm, FILE *fp); +int gen_rtcm2(rtcm_t *rtcm, int type, int sync); +//int gen_rtcm3(rtcm_t *rtcm, int type, int sync); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm2.cc b/src/algorithms/libs/rtklib/rtklib_rtcm2.cc new file mode 100644 index 000000000..c7af88ccd --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm2.cc @@ -0,0 +1,648 @@ +/*! + * \file rtklib_rtcm2.cc + * \brief RTCM functions for v2 + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + + +#include "rtklib_rtcm2.h" +#include "rtklib_rtkcmn.h" + + +/* adjust hourly rollover of rtcm 2 time -------------------------------------*/ +void adjhour(rtcm_t *rtcm, double zcnt) +{ + double tow, hour, sec; + int week; + + /* if no time, get cpu time */ + if (rtcm->time.time == 0) rtcm->time = utc2gpst(timeget()); + tow = time2gpst(rtcm->time, &week); + hour = floor(tow / 3600.0); + sec = tow - hour * 3600.0; + if (zcnt < sec - 1800.0) + zcnt += 3600.0; + else if (zcnt > sec + 1800.0) + zcnt -= 3600.0; + rtcm->time = gpst2time(week, hour * 3600 + zcnt); +} + + +/* get observation data index ------------------------------------------------*/ +int obsindex(obs_t *obs, gtime_t time, int sat) +{ + int i, j; + + for (i = 0; i < obs->n; i++) + { + if (obs->data[i].sat == sat) return i; /* field already exists */ + } + if (i >= MAXOBS) return -1; /* overflow */ + + /* add new field */ + obs->data[i].time = time; + obs->data[i].sat = sat; + for (j = 0; j < NFREQ; j++) + { + obs->data[i].L[j] = obs->data[i].P[j] = 0.0; + obs->data[i].D[j] = 0.0; + obs->data[i].SNR[j] = obs->data[i].LLI[j] = obs->data[i].code[j] = 0; + } + obs->n++; + return i; +} + + +/* decode type 1/9: differential gps correction/partial correction set -------*/ +int decode_type1(rtcm_t *rtcm) +{ + int i = 48, fact, udre, prn, sat, iod; + double prc, rrc; + + trace(4, "decode_type1: len=%d\n", rtcm->len); + + while (i + 40 <= rtcm->len * 8) + { + fact = getbitu(rtcm->buff, i, 1); + i += 1; + udre = getbitu(rtcm->buff, i, 2); + i += 2; + prn = getbitu(rtcm->buff, i, 5); + i += 5; + prc = getbits(rtcm->buff, i, 16); + i += 16; + rrc = getbits(rtcm->buff, i, 8); + i += 8; + iod = getbits(rtcm->buff, i, 8); + i += 8; + if (prn == 0) prn = 32; + if (prc == 0x80000000 || rrc == 0xFFFF8000) + { + trace(2, "rtcm2 1 prc/rrc indicates satellite problem: prn=%d\n", prn); + continue; + } + if (rtcm->dgps) + { + sat = satno(SYS_GPS, prn); + rtcm->dgps[sat - 1].t0 = rtcm->time; + rtcm->dgps[sat - 1].prc = prc * (fact ? 0.32 : 0.02); + rtcm->dgps[sat - 1].rrc = rrc * (fact ? 0.032 : 0.002); + rtcm->dgps[sat - 1].iod = iod; + rtcm->dgps[sat - 1].udre = udre; + } + } + return 7; +} + + +/* decode type 3: reference station parameter --------------------------------*/ +int decode_type3(rtcm_t *rtcm) +{ + int i = 48; + + trace(4, "decode_type3: len=%d\n", rtcm->len); + + if (i + 96 <= rtcm->len * 8) + { + rtcm->sta.pos[0] = getbits(rtcm->buff, i, 32) * 0.01; + i += 32; + rtcm->sta.pos[1] = getbits(rtcm->buff, i, 32) * 0.01; + i += 32; + rtcm->sta.pos[2] = getbits(rtcm->buff, i, 32) * 0.01; + } + else + { + trace(2, "rtcm2 3 length error: len=%d\n", rtcm->len); + return -1; + } + return 5; +} + + +/* decode type 14: gps time of week ------------------------------------------*/ +int decode_type14(rtcm_t *rtcm) +{ + double zcnt; + int i = 48, week, hour, leaps; + + trace(4, "decode_type14: len=%d\n", rtcm->len); + + zcnt = getbitu(rtcm->buff, 24, 13); + if (i + 24 <= rtcm->len * 8) + { + week = getbitu(rtcm->buff, i, 10); + i += 10; + hour = getbitu(rtcm->buff, i, 8); + i += 8; + leaps = getbitu(rtcm->buff, i, 6); + } + else + { + trace(2, "rtcm2 14 length error: len=%d\n", rtcm->len); + return -1; + } + week = adjgpsweek(week); + rtcm->time = gpst2time(week, hour * 3600.0 + zcnt * 0.6); + rtcm->nav.leaps = leaps; + return 6; +} + + +/* decode type 16: gps special message ---------------------------------------*/ +int decode_type16(rtcm_t *rtcm) +{ + int i = 48, n = 0; + + trace(4, "decode_type16: len=%d\n", rtcm->len); + + while (i + 8 <= rtcm->len * 8 && n < 90) + { + rtcm->msg[n++] = getbitu(rtcm->buff, i, 8); + i += 8; + } + rtcm->msg[n] = '\0'; + + trace(3, "rtcm2 16 message: %s\n", rtcm->msg); + return 9; +} + + +/* decode type 17: gps ephemerides -------------------------------------------*/ +int decode_type17(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + int i = 48, week, prn, sat; + + trace(4, "decode_type17: len=%d\n", rtcm->len); + + if (i + 480 <= rtcm->len * 8) + { + week = getbitu(rtcm->buff, i, 10); + i += 10; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + eph.iode = getbitu(rtcm->buff, i, 8); + i += 8; + toc = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.f1 = getbits(rtcm->buff, i, 16) * TWO_N43; + i += 16; + eph.f2 = getbits(rtcm->buff, i, 8) * TWO_N55; + i += 8; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16); + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 16); + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.iodc = getbitu(rtcm->buff, i, 10); + i += 10; + eph.f0 = getbits(rtcm->buff, i, 22) * TWO_N31; + i += 22; + prn = getbitu(rtcm->buff, i, 5); + i += 5 + 3; + eph.tgd[0] = getbits(rtcm->buff, i, 8) * TWO_N31; + i += 8; + eph.code = getbitu(rtcm->buff, i, 2); + i += 2; + eph.sva = getbitu(rtcm->buff, i, 4); + i += 4; + eph.svh = getbitu(rtcm->buff, i, 6); + i += 6; + eph.flag = getbitu(rtcm->buff, i, 1); + } + else + { + trace(2, "rtcm2 17 length error: len=%d\n", rtcm->len); + return -1; + } + if (prn == 0) prn = 32; + sat = satno(SYS_GPS, prn); + eph.sat = sat; + eph.week = adjgpsweek(week); + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 18: rtk uncorrected carrier-phase -----------------------------*/ +int decode_type18(rtcm_t *rtcm) +{ + gtime_t time; + double usec, cp, tt; + int i = 48, index, freq, sync = 1, code, sys, prn, sat, loss; + + trace(4, "decode_type18: len=%d\n", rtcm->len); + + if (i + 24 <= rtcm->len * 8) + { + freq = getbitu(rtcm->buff, i, 2); + i += 2 + 2; + usec = getbitu(rtcm->buff, i, 20); + i += 20; + } + else + { + trace(2, "rtcm2 18 length error: len=%d\n", rtcm->len); + return -1; + } + if (freq & 0x1) + { + trace(2, "rtcm2 18 not supported frequency: freq=%d\n", freq); + return -1; + } + freq >>= 1; + + while (i + 48 <= rtcm->len * 8 && rtcm->obs.n < MAXOBS) + { + sync = getbitu(rtcm->buff, i, 1); + i += 1; + code = getbitu(rtcm->buff, i, 1); + i += 1; + sys = getbitu(rtcm->buff, i, 1); + i += 1; + prn = getbitu(rtcm->buff, i, 5); + i += 5 + 3; + loss = getbitu(rtcm->buff, i, 5); + i += 5; + cp = getbits(rtcm->buff, i, 32); + i += 32; + if (prn == 0) prn = 32; + if (!(sat = satno(sys ? SYS_GLO : SYS_GPS, prn))) + { + trace(2, "rtcm2 18 satellite number error: sys=%d prn=%d\n", sys, prn); + continue; + } + time = timeadd(rtcm->time, usec * 1E-6); + if (sys) time = utc2gpst(time); /* convert glonass time to gpst */ + + tt = timediff(rtcm->obs.data[0].time, time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex(&rtcm->obs, time, sat)) >= 0) + { + rtcm->obs.data[index].L[freq] = -cp / 256.0; + rtcm->obs.data[index].LLI[freq] = rtcm->loss[sat - 1][freq] != loss; + rtcm->obs.data[index].code[freq] = + !freq ? (code ? CODE_L1P : CODE_L1C) : (code ? CODE_L2P : CODE_L2C); + rtcm->loss[sat - 1][freq] = loss; + } + } + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 19: rtk uncorrected pseudorange -------------------------------*/ +int decode_type19(rtcm_t *rtcm) +{ + gtime_t time; + double usec, pr, tt; + int i = 48, index, freq, sync = 1, code, sys, prn, sat; + + trace(4, "decode_type19: len=%d\n", rtcm->len); + + if (i + 24 <= rtcm->len * 8) + { + freq = getbitu(rtcm->buff, i, 2); + i += 2 + 2; + usec = getbitu(rtcm->buff, i, 20); + i += 20; + } + else + { + trace(2, "rtcm2 19 length error: len=%d\n", rtcm->len); + return -1; + } + if (freq & 0x1) + { + trace(2, "rtcm2 19 not supported frequency: freq=%d\n", freq); + return -1; + } + freq >>= 1; + + while (i + 48 <= rtcm->len * 8 && rtcm->obs.n < MAXOBS) + { + sync = getbitu(rtcm->buff, i, 1); + i += 1; + code = getbitu(rtcm->buff, i, 1); + i += 1; + sys = getbitu(rtcm->buff, i, 1); + i += 1; + prn = getbitu(rtcm->buff, i, 5); + i += 5 + 8; + pr = getbitu(rtcm->buff, i, 32); + i += 32; + if (prn == 0) prn = 32; + if (!(sat = satno(sys ? SYS_GLO : SYS_GPS, prn))) + { + trace(2, "rtcm2 19 satellite number error: sys=%d prn=%d\n", sys, prn); + continue; + } + time = timeadd(rtcm->time, usec * 1E-6); + if (sys) time = utc2gpst(time); /* convert glonass time to gpst */ + + tt = timediff(rtcm->obs.data[0].time, time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex(&rtcm->obs, time, sat)) >= 0) + { + rtcm->obs.data[index].P[freq] = pr * 0.02; + rtcm->obs.data[index].code[freq] = + !freq ? (code ? CODE_L1P : CODE_L1C) : (code ? CODE_L2P : CODE_L2C); + } + } + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 22: extended reference station parameter ----------------------*/ +int decode_type22(rtcm_t *rtcm) +{ + double del[2][3] = {{0}}, hgt = 0.0; + int i = 48, j, noh; + + trace(4, "decode_type22: len=%d\n", rtcm->len); + + if (i + 24 <= rtcm->len * 8) + { + del[0][0] = getbits(rtcm->buff, i, 8) / 25600.0; + i += 8; + del[0][1] = getbits(rtcm->buff, i, 8) / 25600.0; + i += 8; + del[0][2] = getbits(rtcm->buff, i, 8) / 25600.0; + i += 8; + } + else + { + trace(2, "rtcm2 22 length error: len=%d\n", rtcm->len); + return -1; + } + if (i + 24 <= rtcm->len * 8) + { + i += 5; + noh = getbits(rtcm->buff, i, 1); + i += 1; + hgt = noh ? 0.0 : getbitu(rtcm->buff, i, 18) / 25600.0; + i += 18; + } + if (i + 24 <= rtcm->len * 8) + { + del[1][0] = getbits(rtcm->buff, i, 8) / 1600.0; + i += 8; + del[1][1] = getbits(rtcm->buff, i, 8) / 1600.0; + i += 8; + del[1][2] = getbits(rtcm->buff, i, 8) / 1600.0; + } + rtcm->sta.deltype = 1; /* xyz */ + for (j = 0; j < 3; j++) rtcm->sta.del[j] = del[0][j]; + rtcm->sta.hgt = hgt; + return 5; +} + + +/* decode type 23: antenna type definition record ----------------------------*/ +int decode_type23(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 24: antenna reference point (arp) -----------------------------*/ +int decode_type24(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 31: differential glonass correction ---------------------------*/ +int decode_type31(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 32: differential glonass reference station parameters ---------*/ +int decode_type32(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 34: glonass partial differential correction set ---------------*/ +int decode_type34(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 36: glonass special message -----------------------------------*/ +int decode_type36(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 37: gnss system time offset -----------------------------------*/ +int decode_type37(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode type 59: proprietary message ---------------------------------------*/ +int decode_type59(rtcm_t *rtcm __attribute((unused))) +{ + return 0; +} + + +/* decode rtcm ver.2 message -------------------------------------------------*/ +int decode_rtcm2(rtcm_t *rtcm) +{ + double zcnt; + int staid, seqno, stah, ret = 0, type = getbitu(rtcm->buff, 8, 6); + + trace(3, "decode_rtcm2: type=%2d len=%3d\n", type, rtcm->len); + + if ((zcnt = getbitu(rtcm->buff, 24, 13) * 0.6) >= 3600.0) + { + trace(2, "rtcm2 modified z-count error: zcnt=%.1f\n", zcnt); + return -1; + } + adjhour(rtcm, zcnt); + staid = getbitu(rtcm->buff, 14, 10); + seqno = getbitu(rtcm->buff, 37, 3); + stah = getbitu(rtcm->buff, 45, 3); + if (seqno - rtcm->seqno != 1 && seqno - rtcm->seqno != -7) + { + trace(2, "rtcm2 message outage: seqno=%d->%d\n", rtcm->seqno, seqno); + } + rtcm->seqno = seqno; + rtcm->stah = stah; + + if (rtcm->outtype) + { + sprintf(rtcm->msgtype, "RTCM %2d (%4d) zcnt=%7.1f staid=%3d seqno=%d", + type, rtcm->len, zcnt, staid, seqno); + } + if (type == 3 || type == 22 || type == 23 || type == 24) + { + if (rtcm->staid != 0 && staid != rtcm->staid) + { + trace(2, "rtcm2 station id changed: %d->%d\n", rtcm->staid, staid); + } + rtcm->staid = staid; + } + if (rtcm->staid != 0 && staid != rtcm->staid) + { + trace(2, "rtcm2 station id invalid: %d %d\n", staid, rtcm->staid); + return -1; + } + switch (type) + { + case 1: + ret = decode_type1(rtcm); + break; + case 3: + ret = decode_type3(rtcm); + break; + case 9: + ret = decode_type1(rtcm); + break; + case 14: + ret = decode_type14(rtcm); + break; + case 16: + ret = decode_type16(rtcm); + break; + case 17: + ret = decode_type17(rtcm); + break; + case 18: + ret = decode_type18(rtcm); + break; + case 19: + ret = decode_type19(rtcm); + break; + case 22: + ret = decode_type22(rtcm); + break; + case 23: + ret = decode_type23(rtcm); + break; /* not supported */ + case 24: + ret = decode_type24(rtcm); + break; /* not supported */ + case 31: + ret = decode_type31(rtcm); + break; /* not supported */ + case 32: + ret = decode_type32(rtcm); + break; /* not supported */ + case 34: + ret = decode_type34(rtcm); + break; /* not supported */ + case 36: + ret = decode_type36(rtcm); + break; /* not supported */ + case 37: + ret = decode_type37(rtcm); + break; /* not supported */ + case 59: + ret = decode_type59(rtcm); + break; /* not supported */ + } + if (ret >= 0) + { + if (1 <= type && type <= 99) + rtcm->nmsg2[type]++; + else + rtcm->nmsg2[0]++; + } + return ret; +} diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm2.h b/src/algorithms/libs/rtklib/rtklib_rtcm2.h new file mode 100644 index 000000000..56fbe948f --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm2.h @@ -0,0 +1,80 @@ +/*! + * \file rtklib_rtcm2.h + * \brief RTCM v2 functions headers + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_RTCM2_H_ +#define GNSS_SDR_RTKLIB_RTCM2_H_ + +#include "rtklib.h" + + +void adjhour(rtcm_t *rtcm, double zcnt); +int obsindex(obs_t *obs, gtime_t time, int sat); +int decode_type1(rtcm_t *rtcm); +int decode_type3(rtcm_t *rtcm); +int decode_type14(rtcm_t *rtcm); +int decode_type16(rtcm_t *rtcm); +int decode_type17(rtcm_t *rtcm); +int decode_type18(rtcm_t *rtcm); +int decode_type19(rtcm_t *rtcm); +int decode_type22(rtcm_t *rtcm); +int decode_type23(rtcm_t *rtcm); +int decode_type24(rtcm_t *rtcm); +int decode_type31(rtcm_t *rtcm); +int decode_type32(rtcm_t *rtcm); +int decode_type34(rtcm_t *rtcm); +int decode_type36(rtcm_t *rtcm); +int decode_type37(rtcm_t *rtcm); +int decode_type59(rtcm_t *rtcm); +int decode_rtcm2(rtcm_t *rtcm); + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm3.cc b/src/algorithms/libs/rtklib/rtklib_rtcm3.cc new file mode 100644 index 000000000..ef11206a5 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm3.cc @@ -0,0 +1,3633 @@ +/*! + * \file rtklib_rtcm3.cc + * \brief RTCM functions for v3 + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + + +#include "rtklib_rtcm3.h" +#include "rtklib_rtkcmn.h" + + +/* msm signal id table -------------------------------------------------------*/ +const char *msm_sig_gps[32] = { + /* GPS: ref [13] table 3.5-87, ref [14][15] table 3.5-91 */ + "", "1C", "1P", "1W", "1Y", "1M", "", "2C", "2P", "2W", "2Y", "2M", /* 1-12 */ + "", "", "2S", "2L", "2X", "", "", "", "", "5I", "5Q", "5X", /* 13-24 */ + "", "", "", "", "", "1S", "1L", "1X" /* 25-32 */ +}; + + +const char *msm_sig_glo[32] = { + /* GLONASS: ref [13] table 3.5-93, ref [14][15] table 3.5-97 */ + "", "1C", "1P", "", "", "", "", "2C", "2P", "", "3I", "3Q", + "3X", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""}; + + +const char *msm_sig_gal[32] = { + /* Galileo: ref [15] table 3.5-100 */ + "", "1C", "1A", "1B", "1X", "1Z", "", "6C", "6A", "6B", "6X", "6Z", + "", "7I", "7Q", "7X", "", "8I", "8Q", "8X", "", "5I", "5Q", "5X", + "", "", "", "", "", "", "", ""}; + + +const char *msm_sig_qzs[32] = { + /* QZSS: ref [15] table 3.5-103 */ + "", "1C", "", "", "", "", "", "", "6S", "6L", "6X", "", + "", "", "2S", "2L", "2X", "", "", "", "", "5I", "5Q", "5X", + "", "", "", "", "", "1S", "1L", "1X"}; + + +const char *msm_sig_sbs[32] = { + /* SBAS: ref [13] table 3.5-T+005 */ + "", "1C", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "5I", "5Q", "5X", + "", "", "", "", "", "", "", ""}; + + +const char *msm_sig_cmp[32] = { + /* BeiDou: ref [15] table 3.5-106 */ + "", "1I", "1Q", "1X", "", "", "", "6I", "6Q", "6X", "", "", + "", "7I", "7Q", "7X", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""}; + +/* get sign-magnitude bits ---------------------------------------------------*/ +double getbitg(const unsigned char *buff, int pos, int len) +{ + double value = getbitu(buff, pos + 1, len - 1); + return getbitu(buff, pos, 1) ? -value : value; +} + + +/* adjust weekly rollover of gps time ----------------------------------------*/ +void adjweek(rtcm_t *rtcm, double tow) +{ + double tow_p; + int week; + + /* if no time, get cpu time */ + if (rtcm->time.time == 0) rtcm->time = utc2gpst(timeget()); + tow_p = time2gpst(rtcm->time, &week); + if (tow < tow_p - 302400.0) + tow += 604800.0; + else if (tow > tow_p + 302400.0) + tow -= 604800.0; + rtcm->time = gpst2time(week, tow); +} + + +/* adjust weekly rollover of bdt time ----------------------------------------*/ +int adjbdtweek(int week) +{ + int w; + (void)time2bdt(gpst2bdt(utc2gpst(timeget())), &w); + if (w < 1) w = 1; /* use 2006/1/1 if time is earlier than 2006/1/1 */ + return week + (w - week + 512) / 1024 * 1024; +} + + +/* adjust daily rollover of glonass time -------------------------------------*/ +void adjday_glot(rtcm_t *rtcm, double tod) +{ + gtime_t time; + double tow, tod_p; + int week; + + if (rtcm->time.time == 0) rtcm->time = utc2gpst(timeget()); + time = timeadd(gpst2utc(rtcm->time), 10800.0); /* glonass time */ + tow = time2gpst(time, &week); + tod_p = fmod(tow, 86400.0); + tow -= tod_p; + if (tod < tod_p - 43200.0) + tod += 86400.0; + else if (tod > tod_p + 43200.0) + tod -= 86400.0; + time = gpst2time(week, tow + tod); + rtcm->time = utc2gpst(timeadd(time, -10800.0)); +} + + +/* adjust carrier-phase rollover ---------------------------------------------*/ +double adjcp(rtcm_t *rtcm, int sat, int freq, double cp) +{ + if (rtcm->cp[sat - 1][freq] == 0.0) + ; + else if (cp < rtcm->cp[sat - 1][freq] - 750.0) + cp += 1500.0; + else if (cp > rtcm->cp[sat - 1][freq] + 750.0) + cp -= 1500.0; + rtcm->cp[sat - 1][freq] = cp; + return cp; +} + + +/* loss-of-lock indicator ----------------------------------------------------*/ +int lossoflock(rtcm_t *rtcm, int sat, int freq, int lock) +{ + int lli = (!lock && !rtcm->lock[sat - 1][freq]) || lock < rtcm->lock[sat - 1][freq]; + rtcm->lock[sat - 1][freq] = static_cast(lock); + return lli; +} + + +/* s/n ratio -----------------------------------------------------------------*/ +unsigned char snratio(double snr) +{ + return static_cast(snr <= 0.0 || 255.5 <= snr ? 0.0 : snr * 4.0 + 0.5); +} + + +/* get observation data index ------------------------------------------------*/ +int obsindex3(obs_t *obs, gtime_t time, int sat) +{ + int i, j; + + for (i = 0; i < obs->n; i++) + { + if (obs->data[i].sat == sat) return i; /* field already exists */ + } + if (i >= MAXOBS) return -1; /* overflow */ + + /* add new field */ + obs->data[i].time = time; + obs->data[i].sat = sat; + for (j = 0; j < NFREQ + NEXOBS; j++) + { + obs->data[i].L[j] = obs->data[i].P[j] = 0.0; + obs->data[i].D[j] = 0.0; + obs->data[i].SNR[j] = obs->data[i].LLI[j] = obs->data[i].code[j] = 0; + } + obs->n++; + return i; +} + + +/* test station id consistency -----------------------------------------------*/ +int test_staid(rtcm_t *rtcm, int staid) +{ + char *p; + int type, id; + + /* test station id option */ + if ((p = strstr(rtcm->opt, "-STA=")) && sscanf(p, "-STA=%d", &id) == 1) + { + if (staid != id) return 0; + } + /* save station id */ + if (rtcm->staid == 0 || rtcm->obsflag) + { + rtcm->staid = staid; + } + else if (staid != rtcm->staid) + { + type = getbitu(rtcm->buff, 24, 12); + trace(2, "rtcm3 %d staid invalid id=%d %d\n", type, staid, rtcm->staid); + + /* reset station id if station id error */ + rtcm->staid = 0; + return 0; + } + return 1; +} + + +/* decode type 1001-1004 message header --------------------------------------*/ +int decode_head1001(rtcm_t *rtcm, int *sync) +{ + double tow; + char *msg; + int i = 24, staid, nsat, type; + + type = getbitu(rtcm->buff, i, 12); + i += 12; + + if (i + 52 <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + tow = getbitu(rtcm->buff, i, 30) * 0.001; + i += 30; + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + nsat = getbitu(rtcm->buff, i, 5); + } + else + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + adjweek(rtcm, tow); + + trace(4, "decode_head1001: time=%s nsat=%d sync=%d\n", time_str(rtcm->time, 2), + nsat, *sync); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d %s nsat=%2d sync=%d", staid, + time_str(rtcm->time, 2), nsat, *sync); + } + return nsat; +} + + +/* decode type 1001: L1-only gps rtk observation -----------------------------*/ +int decode_type1001(rtcm_t *rtcm) +{ + int sync; + if (decode_head1001(rtcm, &sync) < 0) return -1; + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1002: extended L1-only gps rtk observables --------------------*/ +int decode_type1002(rtcm_t *rtcm) +{ + double pr1, cnr1, tt, cp1; + int i = 24 + 64, j, index, nsat, sync, prn, code, sat, ppr1, lock1, amb, sys; + + if ((nsat = decode_head1001(rtcm, &sync)) < 0) return -1; + + for (j = 0; j < nsat && rtcm->obs.n < MAXOBS && i + 74 <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + code = getbitu(rtcm->buff, i, 1); + i += 1; + pr1 = getbitu(rtcm->buff, i, 24); + i += 24; + ppr1 = getbits(rtcm->buff, i, 20); + i += 20; + lock1 = getbitu(rtcm->buff, i, 7); + i += 7; + amb = getbitu(rtcm->buff, i, 8); + i += 8; + cnr1 = getbitu(rtcm->buff, i, 8); + i += 8; + if (prn < 40) + { + sys = SYS_GPS; + } + else + { + sys = SYS_SBS; + prn += 80; + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1002 satellite number error: prn=%d\n", prn); + continue; + } + tt = timediff(rtcm->obs.data[0].time, rtcm->time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex3(&rtcm->obs, rtcm->time, sat)) < 0) continue; + pr1 = pr1 * 0.02 + amb * PRUNIT_GPS; + if (ppr1 != static_cast(0xFFF80000)) + { + rtcm->obs.data[index].P[0] = pr1; + cp1 = adjcp(rtcm, sat, 0, ppr1 * 0.0005 / lam_carr[0]); + rtcm->obs.data[index].L[0] = pr1 / lam_carr[0] + cp1; + } + rtcm->obs.data[index].LLI[0] = lossoflock(rtcm, sat, 0, lock1); + rtcm->obs.data[index].SNR[0] = snratio(cnr1 * 0.25); + rtcm->obs.data[index].code[0] = code ? CODE_L1P : CODE_L1C; + } + return sync ? 0 : 1; +} + + +/* decode type 1003: L1&L2 gps rtk observables -------------------------------*/ +int decode_type1003(rtcm_t *rtcm) +{ + int sync; + if (decode_head1001(rtcm, &sync) < 0) return -1; + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1004: extended L1&L2 gps rtk observables ----------------------*/ +int decode_type1004(rtcm_t *rtcm) +{ + const int L2codes[] = {CODE_L2X, CODE_L2P, CODE_L2D, CODE_L2W}; + double pr1, cnr1, cnr2, tt, cp1, cp2; + int i = 24 + 64, j, index, nsat, sync, prn, sat, code1, code2, pr21, ppr1, ppr2; + int lock1, lock2, amb, sys; + + if ((nsat = decode_head1001(rtcm, &sync)) < 0) return -1; + + for (j = 0; j < nsat && rtcm->obs.n < MAXOBS && i + 125 <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + code1 = getbitu(rtcm->buff, i, 1); + i += 1; + pr1 = getbitu(rtcm->buff, i, 24); + i += 24; + ppr1 = getbits(rtcm->buff, i, 20); + i += 20; + lock1 = getbitu(rtcm->buff, i, 7); + i += 7; + amb = getbitu(rtcm->buff, i, 8); + i += 8; + cnr1 = getbitu(rtcm->buff, i, 8); + i += 8; + code2 = getbitu(rtcm->buff, i, 2); + i += 2; + pr21 = getbits(rtcm->buff, i, 14); + i += 14; + ppr2 = getbits(rtcm->buff, i, 20); + i += 20; + lock2 = getbitu(rtcm->buff, i, 7); + i += 7; + cnr2 = getbitu(rtcm->buff, i, 8); + i += 8; + if (prn < 40) + { + sys = SYS_GPS; + } + else + { + sys = SYS_SBS; + prn += 80; + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1004 satellite number error: sys=%d prn=%d\n", sys, prn); + continue; + } + tt = timediff(rtcm->obs.data[0].time, rtcm->time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex3(&rtcm->obs, rtcm->time, sat)) < 0) continue; + pr1 = pr1 * 0.02 + amb * PRUNIT_GPS; + if (ppr1 != static_cast(0xFFF80000)) + { + rtcm->obs.data[index].P[0] = pr1; + cp1 = adjcp(rtcm, sat, 0, ppr1 * 0.0005 / lam_carr[0]); + rtcm->obs.data[index].L[0] = pr1 / lam_carr[0] + cp1; + } + rtcm->obs.data[index].LLI[0] = lossoflock(rtcm, sat, 0, lock1); + rtcm->obs.data[index].SNR[0] = snratio(cnr1 * 0.25); + rtcm->obs.data[index].code[0] = code1 ? CODE_L1P : CODE_L1C; + + if (pr21 != static_cast(0xFFFFE000)) + { + rtcm->obs.data[index].P[1] = pr1 + pr21 * 0.02; + } + if (ppr2 != static_cast(0xFFF80000)) + { + cp2 = adjcp(rtcm, sat, 1, ppr2 * 0.0005 / lam_carr[1]); + rtcm->obs.data[index].L[1] = pr1 / lam_carr[1] + cp2; + } + rtcm->obs.data[index].LLI[1] = lossoflock(rtcm, sat, 1, lock2); + rtcm->obs.data[index].SNR[1] = snratio(cnr2 * 0.25); + rtcm->obs.data[index].code[1] = L2codes[code2]; + } + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* get signed 38bit field ----------------------------------------------------*/ +double getbits_38(const unsigned char *buff, int pos) +{ + return static_cast(getbits(buff, pos, 32)) * 64.0 + getbitu(buff, pos + 32, 6); +} + + +/* decode type 1005: stationary rtk reference station arp --------------------*/ +int decode_type1005(rtcm_t *rtcm) +{ + double rr[3], re[3], pos[3]; + char *msg; + int i = 24 + 12, j, staid, itrf; + + if (i + 140 == rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + itrf = getbitu(rtcm->buff, i, 6); + i += 6 + 4; + rr[0] = getbits_38(rtcm->buff, i); + i += 38 + 2; + rr[1] = getbits_38(rtcm->buff, i); + i += 38 + 2; + rr[2] = getbits_38(rtcm->buff, i); + } + else + { + trace(2, "rtcm3 1005 length error: len=%d\n", rtcm->len); + return -1; + } + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + for (j = 0; j < 3; j++) re[j] = rr[j] * 0.0001; + ecef2pos(re, pos); + sprintf(msg, " staid=%4d pos=%.8f %.8f %.3f", staid, pos[0] * R2D, pos[1] * R2D, + pos[2]); + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + rtcm->sta.deltype = 0; /* xyz */ + for (j = 0; j < 3; j++) + { + rtcm->sta.pos[j] = rr[j] * 0.0001; + rtcm->sta.del[j] = 0.0; + } + rtcm->sta.hgt = 0.0; + rtcm->sta.itrf = itrf; + return 5; +} + + +/* decode type 1006: stationary rtk reference station arp with height --------*/ +int decode_type1006(rtcm_t *rtcm) +{ + double rr[3], re[3], pos[3], anth; + char *msg; + int i = 24 + 12, j, staid, itrf; + + if (i + 156 <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + itrf = getbitu(rtcm->buff, i, 6); + i += 6 + 4; + rr[0] = getbits_38(rtcm->buff, i); + i += 38 + 2; + rr[1] = getbits_38(rtcm->buff, i); + i += 38 + 2; + rr[2] = getbits_38(rtcm->buff, i); + i += 38; + anth = getbitu(rtcm->buff, i, 16); + } + else + { + trace(2, "rtcm3 1006 length error: len=%d\n", rtcm->len); + return -1; + } + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + for (j = 0; j < 3; j++) re[j] = rr[j] * 0.0001; + ecef2pos(re, pos); + sprintf(msg, " staid=%4d pos=%.8f %.8f %.3f anth=%.3f", staid, pos[0] * R2D, + pos[1] * R2D, pos[2], anth); + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + rtcm->sta.deltype = 1; /* xyz */ + for (j = 0; j < 3; j++) + { + rtcm->sta.pos[j] = rr[j] * 0.0001; + rtcm->sta.del[j] = 0.0; + } + rtcm->sta.hgt = anth * 0.0001; + rtcm->sta.itrf = itrf; + return 5; +} + + +/* decode type 1007: antenna descriptor --------------------------------------*/ +int decode_type1007(rtcm_t *rtcm) +{ + char des[32] = ""; + char *msg; + int i = 24 + 12, j, staid, n, setup; + + n = getbitu(rtcm->buff, i + 12, 8); + + if (i + 28 + 8 * n <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12 + 8; + for (j = 0; j < n && j < 31; j++) + { + des[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + setup = getbitu(rtcm->buff, i, 8); + } + else + { + trace(2, "rtcm3 1007 length error: len=%d\n", rtcm->len); + return -1; + } + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d", staid); + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + strncpy(rtcm->sta.antdes, des, n); + rtcm->sta.antdes[n] = '\0'; + rtcm->sta.antsetup = setup; + rtcm->sta.antsno[0] = '\0'; + return 5; +} + + +/* decode type 1008: antenna descriptor & serial number ----------------------*/ +int decode_type1008(rtcm_t *rtcm) +{ + char des[32] = "", sno[32] = ""; + char *msg; + int i = 24 + 12, j, staid, n, m, setup; + + n = getbitu(rtcm->buff, i + 12, 8); + m = getbitu(rtcm->buff, i + 28 + 8 * n, 8); + + if (i + 36 + 8 * (n + m) <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12 + 8; + for (j = 0; j < n && j < 31; j++) + { + des[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + setup = getbitu(rtcm->buff, i, 8); + i += 8 + 8; + for (j = 0; j < m && j < 31; j++) + { + sno[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + } + else + { + trace(2, "rtcm3 1008 length error: len=%d\n", rtcm->len); + return -1; + } + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d", staid); + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + strncpy(rtcm->sta.antdes, des, n); + rtcm->sta.antdes[n] = '\0'; + rtcm->sta.antsetup = setup; + strncpy(rtcm->sta.antsno, sno, m); + rtcm->sta.antsno[m] = '\0'; + return 5; +} + + +/* decode type 1009-1012 message header --------------------------------------*/ +int decode_head1009(rtcm_t *rtcm, int *sync) +{ + double tod; + char *msg; + int i = 24, staid, nsat, type; + + type = getbitu(rtcm->buff, i, 12); + i += 12; + + if (i + 49 <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + tod = getbitu(rtcm->buff, i, 27) * 0.001; + i += 27; /* sec in a day */ + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + nsat = getbitu(rtcm->buff, i, 5); + } + else + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + adjday_glot(rtcm, tod); + + trace(4, "decode_head1009: time=%s nsat=%d sync=%d\n", time_str(rtcm->time, 2), + nsat, *sync); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d %s nsat=%2d sync=%d", staid, + time_str(rtcm->time, 2), nsat, *sync); + } + return nsat; +} + + +/* decode type 1009: L1-only glonass rtk observables -------------------------*/ +int decode_type1009(rtcm_t *rtcm) +{ + int sync; + if (decode_head1009(rtcm, &sync) < 0) return -1; + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1010: extended L1-only glonass rtk observables ----------------*/ +int decode_type1010(rtcm_t *rtcm) +{ + double pr1, cnr1, tt, cp1, lam1; + int i = 24 + 61, j, index, nsat, sync, prn, sat, code, freq, ppr1, lock1, amb, sys = SYS_GLO; + + if ((nsat = decode_head1009(rtcm, &sync)) < 0) return -1; + + for (j = 0; j < nsat && rtcm->obs.n < MAXOBS && i + 79 <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + code = getbitu(rtcm->buff, i, 1); + i += 1; + freq = getbitu(rtcm->buff, i, 5); + i += 5; + pr1 = getbitu(rtcm->buff, i, 25); + i += 25; + ppr1 = getbits(rtcm->buff, i, 20); + i += 20; + lock1 = getbitu(rtcm->buff, i, 7); + i += 7; + amb = getbitu(rtcm->buff, i, 7); + i += 7; + cnr1 = getbitu(rtcm->buff, i, 8); + i += 8; + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1010 satellite number error: prn=%d\n", prn); + continue; + } + tt = timediff(rtcm->obs.data[0].time, rtcm->time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex3(&rtcm->obs, rtcm->time, sat)) < 0) continue; + pr1 = pr1 * 0.02 + amb * PRUNIT_GLO; + if (ppr1 != static_cast(0xFFF80000)) + { + rtcm->obs.data[index].P[0] = pr1; + lam1 = SPEED_OF_LIGHT / (FREQ1_GLO + DFRQ1_GLO * (freq - 7)); + cp1 = adjcp(rtcm, sat, 0, ppr1 * 0.0005 / lam1); + rtcm->obs.data[index].L[0] = pr1 / lam1 + cp1; + } + rtcm->obs.data[index].LLI[0] = lossoflock(rtcm, sat, 0, lock1); + rtcm->obs.data[index].SNR[0] = snratio(cnr1 * 0.25); + rtcm->obs.data[index].code[0] = code ? CODE_L1P : CODE_L1C; + } + return sync ? 0 : 1; +} + + +/* decode type 1011: L1&L2 glonass rtk observables ---------------------------*/ +int decode_type1011(rtcm_t *rtcm) +{ + int sync; + if (decode_head1009(rtcm, &sync) < 0) return -1; + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1012: extended L1&L2 glonass rtk observables ------------------*/ +int decode_type1012(rtcm_t *rtcm) +{ + double pr1, cnr1, cnr2, tt, cp1, cp2, lam1, lam2; + int i = 24 + 61, j, index, nsat, sync, prn, sat, freq, code1, code2, pr21, ppr1, ppr2; + int lock1, lock2, amb, sys = SYS_GLO; + + if ((nsat = decode_head1009(rtcm, &sync)) < 0) return -1; + + for (j = 0; j < nsat && rtcm->obs.n < MAXOBS && i + 130 <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + code1 = getbitu(rtcm->buff, i, 1); + i += 1; + freq = getbitu(rtcm->buff, i, 5); + i += 5; + pr1 = getbitu(rtcm->buff, i, 25); + i += 25; + ppr1 = getbits(rtcm->buff, i, 20); + i += 20; + lock1 = getbitu(rtcm->buff, i, 7); + i += 7; + amb = getbitu(rtcm->buff, i, 7); + i += 7; + cnr1 = getbitu(rtcm->buff, i, 8); + i += 8; + code2 = getbitu(rtcm->buff, i, 2); + i += 2; + pr21 = getbits(rtcm->buff, i, 14); + i += 14; + ppr2 = getbits(rtcm->buff, i, 20); + i += 20; + lock2 = getbitu(rtcm->buff, i, 7); + i += 7; + cnr2 = getbitu(rtcm->buff, i, 8); + i += 8; + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1012 satellite number error: sys=%d prn=%d\n", sys, prn); + continue; + } + tt = timediff(rtcm->obs.data[0].time, rtcm->time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + if ((index = obsindex3(&rtcm->obs, rtcm->time, sat)) < 0) continue; + pr1 = pr1 * 0.02 + amb * PRUNIT_GLO; + if (ppr1 != static_cast(0xFFF80000)) + { + lam1 = SPEED_OF_LIGHT / (FREQ1_GLO + DFRQ1_GLO * (freq - 7)); + rtcm->obs.data[index].P[0] = pr1; + cp1 = adjcp(rtcm, sat, 0, ppr1 * 0.0005 / lam1); + rtcm->obs.data[index].L[0] = pr1 / lam1 + cp1; + } + rtcm->obs.data[index].LLI[0] = lossoflock(rtcm, sat, 0, lock1); + rtcm->obs.data[index].SNR[0] = snratio(cnr1 * 0.25); + rtcm->obs.data[index].code[0] = code1 ? CODE_L1P : CODE_L1C; + + if (pr21 != static_cast(0xFFFFE000)) + { + rtcm->obs.data[index].P[1] = pr1 + pr21 * 0.02; + } + if (ppr2 != static_cast(0xFFF80000)) + { + lam2 = SPEED_OF_LIGHT / (FREQ2_GLO + DFRQ2_GLO * (freq - 7)); + cp2 = adjcp(rtcm, sat, 1, ppr2 * 0.0005 / lam2); + rtcm->obs.data[index].L[1] = pr1 / lam2 + cp2; + } + rtcm->obs.data[index].LLI[1] = lossoflock(rtcm, sat, 1, lock2); + rtcm->obs.data[index].SNR[1] = snratio(cnr2 * 0.25); + rtcm->obs.data[index].code[1] = code2 ? CODE_L2P : CODE_L2C; + } + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1013: system parameters ---------------------------------------*/ +int decode_type1013(rtcm_t *rtcm __attribute__((unused))) +{ + return 0; +} + + +/* decode type 1019: gps ephemerides -----------------------------------------*/ +int decode_type1019(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, sys = SYS_GPS; + + if (i + 476 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + week = getbitu(rtcm->buff, i, 10); + i += 10; + eph.sva = getbitu(rtcm->buff, i, 4); + i += 4; + eph.code = getbitu(rtcm->buff, i, 2); + i += 2; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + eph.iode = getbitu(rtcm->buff, i, 8); + i += 8; + toc = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.f2 = getbits(rtcm->buff, i, 8) * TWO_N55; + i += 8; + eph.f1 = getbits(rtcm->buff, i, 16) * TWO_N43; + i += 16; + eph.f0 = getbits(rtcm->buff, i, 22) * TWO_N31; + i += 22; + eph.iodc = getbitu(rtcm->buff, i, 10); + i += 10; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.tgd[0] = getbits(rtcm->buff, i, 8) * TWO_N31; + i += 8; + eph.svh = getbitu(rtcm->buff, i, 6); + i += 6; + eph.flag = getbitu(rtcm->buff, i, 1); + i += 1; + eph.fit = getbitu(rtcm->buff, i, 1) ? 0.0 : 4.0; /* 0:4hr, 1:>4hr */ + } + else + { + trace(2, "rtcm3 1019 length error: len=%d\n", rtcm->len); + return -1; + } + if (prn >= 40) + { + sys = SYS_SBS; + prn += 80; + } + trace(4, "decode_type1019: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + prn, eph.iode, eph.iodc, week, eph.toes, toc, eph.svh); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1019 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = adjgpsweek(week); + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (eph.iode == rtcm->nav.eph[sat - 1].iode) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 1020: glonass ephemerides -------------------------------------*/ +int decode_type1020(rtcm_t *rtcm) +{ + geph_t geph = {0, -1, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0.0}, {0.0}, {0.0}, + 0.0, 0.0, 0.0}; + double tk_h, tk_m, tk_s, toe, tow, tod, tof; + char *msg; + int i = 24 + 12, prn, sat, week, tb, bn, sys = SYS_GLO; + + if (i + 348 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + geph.frq = getbitu(rtcm->buff, i, 5) - 7; + i += 5 + 2 + 2; + tk_h = getbitu(rtcm->buff, i, 5); + i += 5; + tk_m = getbitu(rtcm->buff, i, 6); + i += 6; + tk_s = getbitu(rtcm->buff, i, 1) * 30.0; + i += 1; + bn = getbitu(rtcm->buff, i, 1); + i += 1 + 1; + tb = getbitu(rtcm->buff, i, 7); + i += 7; + geph.vel[0] = getbitg(rtcm->buff, i, 24) * TWO_N20 * 1E3; + i += 24; + geph.pos[0] = getbitg(rtcm->buff, i, 27) * TWO_N11 * 1E3; + i += 27; + geph.acc[0] = getbitg(rtcm->buff, i, 5) * TWO_N30 * 1E3; + i += 5; + geph.vel[1] = getbitg(rtcm->buff, i, 24) * TWO_N20 * 1E3; + i += 24; + geph.pos[1] = getbitg(rtcm->buff, i, 27) * TWO_N11 * 1E3; + i += 27; + geph.acc[1] = getbitg(rtcm->buff, i, 5) * TWO_N30 * 1E3; + i += 5; + geph.vel[2] = getbitg(rtcm->buff, i, 24) * TWO_N20 * 1E3; + i += 24; + geph.pos[2] = getbitg(rtcm->buff, i, 27) * TWO_N11 * 1E3; + i += 27; + geph.acc[2] = getbitg(rtcm->buff, i, 5) * TWO_N30 * 1E3; + i += 5 + 1; + geph.gamn = getbitg(rtcm->buff, i, 11) * TWO_N40; + i += 11 + 3; + geph.taun = getbitg(rtcm->buff, i, 22) * TWO_N30; + } + else + { + trace(2, "rtcm3 1020 length error: len=%d\n", rtcm->len); + return -1; + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1020 satellite number error: prn=%d\n", prn); + return -1; + } + trace(4, "decode_type1020: prn=%d tk=%02.0f:%02.0f:%02.0f\n", prn, tk_h, tk_m, tk_s); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d tk=%02.0f:%02.0f:%02.0f frq=%2d bn=%d tb=%d", + prn, tk_h, tk_m, tk_s, geph.frq, bn, tb); + } + geph.sat = sat; + geph.svh = bn; + geph.iode = tb & 0x7F; + if (rtcm->time.time == 0) rtcm->time = utc2gpst(timeget()); + tow = time2gpst(gpst2utc(rtcm->time), &week); + tod = fmod(tow, 86400.0); + tow -= tod; + tof = tk_h * 3600.0 + tk_m * 60.0 + tk_s - 10800.0; /* lt->utc */ + if (tof < tod - 43200.0) + tof += 86400.0; + else if (tof > tod + 43200.0) + tof -= 86400.0; + geph.tof = utc2gpst(gpst2time(week, tow + tof)); + toe = tb * 900.0 - 10800.0; /* lt->utc */ + if (toe < tod - 43200.0) + toe += 86400.0; + else if (toe > tod + 43200.0) + toe -= 86400.0; + geph.toe = utc2gpst(gpst2time(week, tow + toe)); /* utc->gpst */ + + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (fabs(timediff(geph.toe, rtcm->nav.geph[prn - 1].toe)) < 1.0 && + geph.svh == rtcm->nav.geph[prn - 1].svh) return 0; /* unchanged */ + } + rtcm->nav.geph[prn - 1] = geph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 1021: helmert/abridged molodenski -----------------------------*/ +int decode_type1021(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1021: not supported message\n"); + return 0; +} + + +/* decode type 1022: moledenski-badekas transformation -----------------------*/ +int decode_type1022(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1022: not supported message\n"); + return 0; +} + + +/* decode type 1023: residual, ellipoidal grid representation ----------------*/ +int decode_type1023(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1023: not supported message\n"); + return 0; +} + + +/* decode type 1024: residual, plane grid representation ---------------------*/ +int decode_type1024(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1024: not supported message\n"); + return 0; +} + + +/* decode type 1025: projection (types except LCC2SP, OM) ---------------------*/ +int decode_type1025(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1025: not supported message\n"); + return 0; +} + + +/* decode type 1026: projection (LCC2SP - lambert conic conformal (2sp)) -----*/ +int decode_type1026(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1026: not supported message\n"); + return 0; +} + + +/* decode type 1027: projection (type OM - oblique mercator) -----------------*/ +int decode_type1027(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1027: not supported message\n"); + return 0; +} + + +/* decode type 1029: unicode text string -------------------------------------*/ +int decode_type1029(rtcm_t *rtcm) +{ + char *msg; + int i = 24 + 12, j, staid, nchar; // mjd, tod, nchar, cunit; + + if (i + 60 <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + /* mjd = getbitu(rtcm->buff, i, 16); */ i += 16; + /* tod = getbitu(rtcm->buff, i, 17); */ i += 17; + nchar = getbitu(rtcm->buff, i, 7); + i += 7; + /* cunit = getbitu(rtcm->buff, i, 8); */ i += 8; + } + else + { + trace(2, "rtcm3 1029 length error: len=%d\n", rtcm->len); + return -1; + } + if (i + nchar * 8 > rtcm->len * 8) + { + trace(2, "rtcm3 1029 length error: len=%d nchar=%d\n", rtcm->len, nchar); + return -1; + } + for (j = 0; j < nchar && j < 126; j++) + { + rtcm->msg[j] = getbitu(rtcm->buff, i, 8); + i += 8; + } + rtcm->msg[j] = '\0'; + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d text=%s", staid, rtcm->msg); + } + return 0; +} + + +/* decode type 1030: network rtk residual ------------------------------------*/ +int decode_type1030(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1030: not supported message\n"); + return 0; +} + + +/* decode type 1031: glonass network rtk residual ----------------------------*/ +int decode_type1031(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1031: not supported message\n"); + return 0; +} + + +/* decode type 1032: physical reference station position information ---------*/ +int decode_type1032(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1032: not supported message\n"); + return 0; +} + + +/* decode type 1033: receiver and antenna descriptor -------------------------*/ +int decode_type1033(rtcm_t *rtcm) +{ + char des[32] = "", sno[32] = "", rec[32] = "", ver[32] = "", rsn[32] = ""; + char *msg; + int i = 24 + 12, j, staid, n, m, n1, n2, n3, setup; + + n = getbitu(rtcm->buff, i + 12, 8); + m = getbitu(rtcm->buff, i + 28 + 8 * n, 8); + n1 = getbitu(rtcm->buff, i + 36 + 8 * (n + m), 8); + n2 = getbitu(rtcm->buff, i + 44 + 8 * (n + m + n1), 8); + n3 = getbitu(rtcm->buff, i + 52 + 8 * (n + m + n1 + n2), 8); + + if (i + 60 + 8 * (n + m + n1 + n2 + n3) <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12 + 8; + for (j = 0; j < n && j < 31; j++) + { + des[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + setup = getbitu(rtcm->buff, i, 8); + i += 8 + 8; + for (j = 0; j < m && j < 31; j++) + { + sno[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + i += 8; + for (j = 0; j < n1 && j < 31; j++) + { + rec[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + i += 8; + for (j = 0; j < n2 && j < 31; j++) + { + ver[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + i += 8; + for (j = 0; j < n3 && j < 31; j++) + { + rsn[j] = static_cast(getbitu(rtcm->buff, i, 8)); + i += 8; + } + } + else + { + trace(2, "rtcm3 1033 length error: len=%d\n", rtcm->len); + return -1; + } + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d", staid); + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + strncpy(rtcm->sta.antdes, des, n); + rtcm->sta.antdes[n] = '\0'; + rtcm->sta.antsetup = setup; + strncpy(rtcm->sta.antsno, sno, m); + rtcm->sta.antsno[m] = '\0'; + strncpy(rtcm->sta.rectype, rec, n1); + rtcm->sta.rectype[n1] = '\0'; + strncpy(rtcm->sta.recver, ver, n2); + rtcm->sta.recver[n2] = '\0'; + strncpy(rtcm->sta.recsno, rsn, n3); + rtcm->sta.recsno[n3] = '\0'; + + trace(3, "rtcm3 1033: ant=%s:%s rec=%s:%s:%s\n", des, sno, rec, ver, rsn); + return 5; +} + + +/* decode type 1034: gps network fkp gradient --------------------------------*/ +int decode_type1034(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1034: not supported message\n"); + return 0; +} + + +/* decode type 1035: glonass network fkp gradient ----------------------------*/ +int decode_type1035(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1035: not supported message\n"); + return 0; +} + + +/* decode type 1037: glonass network rtk ionospheric correction difference ---*/ +int decode_type1037(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1037: not supported message\n"); + return 0; +} + + +/* decode type 1038: glonass network rtk geometic correction difference ------*/ +int decode_type1038(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1038: not supported message\n"); + return 0; +} + + +/* decode type 1039: glonass network rtk combined correction difference ------*/ +int decode_type1039(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1039: not supported message\n"); + return 0; +} + + +/* decode type 1044: qzss ephemerides (ref [15]) -----------------------------*/ +int decode_type1044(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, sys = SYS_QZS; + + if (i + 473 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 4) + 192; + i += 4; + toc = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.f2 = getbits(rtcm->buff, i, 8) * TWO_N55; + i += 8; + eph.f1 = getbits(rtcm->buff, i, 16) * TWO_N43; + i += 16; + eph.f0 = getbits(rtcm->buff, i, 22) * TWO_N31; + i += 22; + eph.iode = getbitu(rtcm->buff, i, 8); + i += 8; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + eph.code = getbitu(rtcm->buff, i, 2); + i += 2; + week = getbitu(rtcm->buff, i, 10); + i += 10; + eph.sva = getbitu(rtcm->buff, i, 4); + i += 4; + eph.svh = getbitu(rtcm->buff, i, 6); + i += 6; + eph.tgd[0] = getbits(rtcm->buff, i, 8) * TWO_N31; + i += 8; + eph.iodc = getbitu(rtcm->buff, i, 10); + i += 10; + eph.fit = getbitu(rtcm->buff, i, 1) ? 0.0 : 2.0; /* 0:2hr, 1:>2hr */ + } + else + { + trace(2, "rtcm3 1044 length error: len=%d\n", rtcm->len); + return -1; + } + trace(4, "decode_type1044: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%3d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + prn, eph.iode, eph.iodc, week, eph.toes, toc, eph.svh); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1044 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = adjgpsweek(week); + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (eph.iode == rtcm->nav.eph[sat - 1].iode && + eph.iodc == rtcm->nav.eph[sat - 1].iodc) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 1045: galileo satellite ephemerides (ref [15]) ----------------*/ +int decode_type1045(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, e5a_hs, e5a_dvs, sys = SYS_GAL; + + if (i + 484 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + week = getbitu(rtcm->buff, i, 12); + i += 12; /* gst-week */ + eph.iode = getbitu(rtcm->buff, i, 10); + i += 10; + eph.sva = getbitu(rtcm->buff, i, 8); + i += 8; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + toc = getbitu(rtcm->buff, i, 14) * 60.0; + i += 14; + eph.f2 = getbits(rtcm->buff, i, 6) * TWO_N59; + i += 6; + eph.f1 = getbits(rtcm->buff, i, 21) * TWO_N46; + i += 21; + eph.f0 = getbits(rtcm->buff, i, 31) * TWO_N34; + i += 31; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 14) * 60.0; + i += 14; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.tgd[0] = getbits(rtcm->buff, i, 10) * TWO_N32; + i += 10; /* E5a/E1 */ + e5a_hs = getbitu(rtcm->buff, i, 2); + i += 2; /* OSHS */ + e5a_dvs = getbitu(rtcm->buff, i, 1); + i += 1; /* OSDVS */ + //rsv = getbitu(rtcm->buff, i, 7); + } + else + { + trace(2, "rtcm3 1045 length error: len=%d\n", rtcm->len); + return -1; + } + trace(4, "decode_type1045: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d iode=%3d week=%d toe=%6.0f toc=%6.0f hs=%d dvs=%d", + prn, eph.iode, week, eph.toes, toc, e5a_hs, e5a_dvs); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1045 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = week + 1024; /* gal-week = gst-week + 1024 */ + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + eph.svh = (e5a_hs << 4) + (e5a_dvs << 3); + eph.code = 2; /* data source = f/nav e5a */ + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (eph.iode == rtcm->nav.eph[sat - 1].iode) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 1046: galileo satellite ephemerides (extension for IGS MGEX) --*/ +int decode_type1046(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, e5a_hs, e5a_dvs, sys = SYS_GAL; + + if (i + 484 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + week = getbitu(rtcm->buff, i, 12); + i += 12; /* gst-week */ + eph.iode = getbitu(rtcm->buff, i, 10); + i += 10; + eph.sva = getbitu(rtcm->buff, i, 8); + i += 8; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + toc = getbitu(rtcm->buff, i, 14) * 60.0; + i += 14; + eph.f2 = getbits(rtcm->buff, i, 6) * TWO_N59; + i += 6; + eph.f1 = getbits(rtcm->buff, i, 21) * TWO_N46; + i += 21; + eph.f0 = getbits(rtcm->buff, i, 31) * TWO_N34; + i += 31; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 14) * 60.0; + i += 14; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.tgd[0] = getbits(rtcm->buff, i, 10) * TWO_N32; + i += 10; /* E5a/E1 */ + e5a_hs = getbitu(rtcm->buff, i, 2); + i += 2; /* OSHS */ + e5a_dvs = getbitu(rtcm->buff, i, 1); + i += 1; /* OSDVS */ + //rsv = getbitu(rtcm->buff, i, 7); + } + else + { + trace(2, "rtcm3 1046 length error: len=%d\n", rtcm->len); + return -1; + } + trace(4, "decode_type1046: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d iode=%3d week=%d toe=%6.0f toc=%6.0f hs=%d dvs=%d", + prn, eph.iode, week, eph.toes, toc, e5a_hs, e5a_dvs); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1046 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = week + 1024; /* gal-week = gst-week + 1024 */ + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + eph.svh = (e5a_hs << 4) + (e5a_dvs << 3); + eph.code = 2; /* data source = f/nav e5a */ + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (eph.iode == rtcm->nav.eph[sat - 1].iode) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 1047: beidou ephemerides (tentative mt and format) ------------*/ +int decode_type1047(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + ; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, sys = SYS_BDS; + + if (i + 476 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + week = getbitu(rtcm->buff, i, 10); + i += 10; + eph.sva = getbitu(rtcm->buff, i, 4); + i += 4; + eph.code = getbitu(rtcm->buff, i, 2); + i += 2; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + eph.iode = getbitu(rtcm->buff, i, 8); + i += 8; + toc = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.f2 = getbits(rtcm->buff, i, 8) * TWO_N55; + i += 8; + eph.f1 = getbits(rtcm->buff, i, 16) * TWO_N43; + i += 16; + eph.f0 = getbits(rtcm->buff, i, 22) * TWO_N31; + i += 22; + eph.iodc = getbitu(rtcm->buff, i, 10); + i += 10; + eph.crs = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 16) * 16.0; + i += 16; + eph.cic = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 16) * TWO_N29; + i += 16; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 16) * TWO_N5; + i += 16; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.tgd[0] = getbits(rtcm->buff, i, 8) * TWO_N31; + i += 8; + eph.svh = getbitu(rtcm->buff, i, 6); + i += 6; + eph.flag = getbitu(rtcm->buff, i, 1); + i += 1; + eph.fit = getbitu(rtcm->buff, i, 1) ? 0.0 : 4.0; /* 0:4hr, 1:>4hr */ + } + else + { + trace(2, "rtcm3 1047 length error: len=%d\n", rtcm->len); + return -1; + } + trace(4, "decode_type1047: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + prn, eph.iode, eph.iodc, week, eph.toes, toc, eph.svh); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 1047 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = adjbdtweek(week); + eph.toe = bdt2gpst(bdt2time(eph.week, eph.toes)); /* bdt -> gpst */ + eph.toc = bdt2gpst(bdt2time(eph.week, toc)); /* bdt -> gpst */ + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + if (!strstr(rtcm->opt, "-EPHALL")) + + { + if (timediff(eph.toe, rtcm->nav.eph[sat - 1].toe) == 0.0 && + eph.iode == rtcm->nav.eph[sat - 1].iode && + eph.iodc == rtcm->nav.eph[sat - 1].iodc) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode type 63: beidou ephemerides (rtcm draft) ---------------------------*/ +int decode_type63(rtcm_t *rtcm) +{ + eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + double toc, sqrtA; + char *msg; + int i = 24 + 12, prn, sat, week, sys = SYS_BDS; + + if (i + 499 <= rtcm->len * 8) + { + prn = getbitu(rtcm->buff, i, 6); + i += 6; + week = getbitu(rtcm->buff, i, 13); + i += 13; + eph.sva = getbitu(rtcm->buff, i, 4); + i += 4; + eph.idot = getbits(rtcm->buff, i, 14) * TWO_N43 * SC2RAD; + i += 14; + eph.iode = getbitu(rtcm->buff, i, 5); + i += 5; /* AODE */ + toc = getbitu(rtcm->buff, i, 17) * 8.0; + i += 17; + eph.f2 = getbits(rtcm->buff, i, 11) * TWO_N55; + i += 11; + eph.f1 = getbits(rtcm->buff, i, 22) * TWO_N50; + i += 22; + eph.f0 = getbits(rtcm->buff, i, 24) * TWO_N33; + i += 24; + eph.iodc = getbitu(rtcm->buff, i, 5); + i += 5; /* AODC */ + eph.crs = getbits(rtcm->buff, i, 18) * TWO_N6; + i += 18; + eph.deln = getbits(rtcm->buff, i, 16) * TWO_N43 * SC2RAD; + i += 16; + eph.M0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cuc = getbits(rtcm->buff, i, 18) * TWO_N31; + i += 18; + eph.e = getbitu(rtcm->buff, i, 32) * TWO_N33; + i += 32; + eph.cus = getbits(rtcm->buff, i, 18) * TWO_N31; + i += 18; + sqrtA = getbitu(rtcm->buff, i, 32) * TWO_N19; + i += 32; + eph.toes = getbitu(rtcm->buff, i, 17) * 8.0; + i += 17; + eph.cic = getbits(rtcm->buff, i, 18) * TWO_N31; + i += 18; + eph.OMG0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.cis = getbits(rtcm->buff, i, 18) * TWO_N31; + i += 18; + eph.i0 = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.crc = getbits(rtcm->buff, i, 18) * TWO_N6; + i += 18; + eph.omg = getbits(rtcm->buff, i, 32) * TWO_N31 * SC2RAD; + i += 32; + eph.OMGd = getbits(rtcm->buff, i, 24) * TWO_N43 * SC2RAD; + i += 24; + eph.tgd[0] = getbits(rtcm->buff, i, 10) * 1E-10; + i += 10; + eph.tgd[1] = getbits(rtcm->buff, i, 10) * 1E-10; + i += 10; + eph.svh = getbitu(rtcm->buff, i, 1); + i += 1; + } + else + { + trace(2, "rtcm3 63 length error: len=%d\n", rtcm->len); + return -1; + } + trace(4, "decode_type63: prn=%d iode=%d toe=%.0f\n", prn, eph.iode, eph.toes); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " prn=%2d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + prn, eph.iode, eph.iodc, week, eph.toes, toc, eph.svh); + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 63 satellite number error: prn=%d\n", prn); + return -1; + } + eph.sat = sat; + eph.week = adjbdtweek(week); + eph.toe = bdt2gpst(bdt2time(eph.week, eph.toes)); /* bdt -> gpst */ + eph.toc = bdt2gpst(bdt2time(eph.week, toc)); /* bdt -> gpst */ + eph.ttr = rtcm->time; + eph.A = sqrtA * sqrtA; + if (!strstr(rtcm->opt, "-EPHALL")) + { + if (timediff(eph.toe, rtcm->nav.eph[sat - 1].toe) == 0.0 && + eph.iode == rtcm->nav.eph[sat - 1].iode && + eph.iodc == rtcm->nav.eph[sat - 1].iodc) return 0; /* unchanged */ + } + rtcm->nav.eph[sat - 1] = eph; + rtcm->ephsat = sat; + return 2; +} + + +/* decode ssr 1, 4 message header ---------------------------------------------*/ +int decode_ssr1_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *refd, int *hsize) +{ + double tod, tow; + char *msg; + int i = 24 + 12, nsat, udi, provid = 0, solid = 0, ns = 6; + +#ifndef SSR_QZSS_DRAFT_V05 + ns = sys == SYS_QZS ? 4 : 6; +#endif + if (i + (sys == SYS_GLO ? 53 : 50 + ns) > rtcm->len * 8) return -1; + + if (sys == SYS_GLO) + { + tod = getbitu(rtcm->buff, i, 17); + i += 17; + adjday_glot(rtcm, tod); + } + else + { + tow = getbitu(rtcm->buff, i, 20); + i += 20; + adjweek(rtcm, tow); + } + udi = getbitu(rtcm->buff, i, 4); + i += 4; + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + *refd = getbitu(rtcm->buff, i, 1); + i += 1; /* satellite ref datum */ + *iod = getbitu(rtcm->buff, i, 4); + i += 4; /* iod */ + provid = getbitu(rtcm->buff, i, 16); + i += 16; /* provider id */ + solid = getbitu(rtcm->buff, i, 4); + i += 4; /* solution id */ + nsat = getbitu(rtcm->buff, i, ns); + i += ns; + *udint = ssrudint[udi]; + + trace(4, "decode_ssr1_head: time=%s sys=%d nsat=%d sync=%d iod=%d provid=%d solid=%d\n", + time_str(rtcm->time, 2), sys, nsat, *sync, *iod, provid, solid); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " %s nsat=%2d iod=%2d udi=%2d sync=%d", + time_str(rtcm->time, 2), nsat, *iod, udi, *sync); + } + *hsize = i; + return nsat; +} + + +/* decode ssr 2, 3, 5, 6 message header -----------------------------------------*/ +int decode_ssr2_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *hsize) +{ + double tod, tow; + char *msg; + int i = 24 + 12, nsat, udi, provid = 0, solid = 0, ns = 6; + +#ifndef SSR_QZSS_DRAFT_V05 + ns = sys == SYS_QZS ? 4 : 6; +#endif + if (i + (sys == SYS_GLO ? 52 : 49 + ns) > rtcm->len * 8) return -1; + + if (sys == SYS_GLO) + { + tod = getbitu(rtcm->buff, i, 17); + i += 17; + adjday_glot(rtcm, tod); + } + else + { + tow = getbitu(rtcm->buff, i, 20); + i += 20; + adjweek(rtcm, tow); + } + udi = getbitu(rtcm->buff, i, 4); + i += 4; + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + *iod = getbitu(rtcm->buff, i, 4); + i += 4; + provid = getbitu(rtcm->buff, i, 16); + i += 16; /* provider id */ + solid = getbitu(rtcm->buff, i, 4); + i += 4; /* solution id */ + nsat = getbitu(rtcm->buff, i, ns); + i += ns; + *udint = ssrudint[udi]; + + trace(4, "decode_ssr2_head: time=%s sys=%d nsat=%d sync=%d iod=%d provid=%d solid=%d\n", + time_str(rtcm->time, 2), sys, nsat, *sync, *iod, provid, solid); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " %s nsat=%2d iod=%2d udi=%2d sync=%d", + time_str(rtcm->time, 2), nsat, *iod, udi, *sync); + } + *hsize = i; + return nsat; +} + + +/* decode ssr 7 message header -----------------------------------------------*/ +int decode_ssr7_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *dispe, int *mw, int *hsize) +{ + double tod, tow; + char *msg; + int i = 24 + 12, nsat, udi, provid = 0, solid = 0, ns = 6; + +#ifndef SSR_QZSS_DRAFT_V05 + ns = sys == SYS_QZS ? 4 : 6; +#endif + if (i + (sys == SYS_GLO ? 54 : 51 + ns) > rtcm->len * 8) return -1; + + if (sys == SYS_GLO) + { + tod = getbitu(rtcm->buff, i, 17); + i += 17; + adjday_glot(rtcm, tod); + } + else + { + tow = getbitu(rtcm->buff, i, 20); + i += 20; + adjweek(rtcm, tow); + } + udi = getbitu(rtcm->buff, i, 4); + i += 4; + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + *iod = getbitu(rtcm->buff, i, 4); + i += 4; + provid = getbitu(rtcm->buff, i, 16); + i += 16; /* provider id */ + solid = getbitu(rtcm->buff, i, 4); + i += 4; /* solution id */ + *dispe = getbitu(rtcm->buff, i, 1); + i += 1; /* dispersive bias consistency ind */ + *mw = getbitu(rtcm->buff, i, 1); + i += 1; /* MW consistency indicator */ + nsat = getbitu(rtcm->buff, i, ns); + i += ns; + *udint = ssrudint[udi]; + + trace(4, "decode_ssr7_head: time=%s sys=%d nsat=%d sync=%d iod=%d provid=%d solid=%d\n", + time_str(rtcm->time, 2), sys, nsat, *sync, *iod, provid, solid); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " %s nsat=%2d iod=%2d udi=%2d sync=%d", + time_str(rtcm->time, 2), nsat, *iod, udi, *sync); + } + *hsize = i; + return nsat; +} + + +/* decode ssr 1: orbit corrections -------------------------------------------*/ +int decode_ssr1(rtcm_t *rtcm, int sys) +{ + double udint, deph[3], ddeph[3]; + int i, j, k, type, sync, iod, nsat, prn, sat, iode, iodcrc, refd = 0, np, ni, nj, offp; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr1_head(rtcm, sys, &sync, &iod, &udint, &refd, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + ni = 8; + nj = 0; + offp = 0; + break; + case SYS_GLO: + np = 5; + ni = 8; + nj = 0; + offp = 0; + break; + case SYS_GAL: + np = 6; + ni = 10; + nj = 0; + offp = 0; + break; + case SYS_QZS: + np = 4; + ni = 8; + nj = 0; + offp = 192; + break; + case SYS_BDS: + np = 6; + ni = 10; + nj = 24; + offp = 1; + break; + case SYS_SBS: + np = 6; + ni = 9; + nj = 24; + offp = 120; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 121 + np + ni + nj <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + iode = getbitu(rtcm->buff, i, ni); + i += ni; + iodcrc = getbitu(rtcm->buff, i, nj); + i += nj; + deph[0] = getbits(rtcm->buff, i, 22) * 1E-4; + i += 22; + deph[1] = getbits(rtcm->buff, i, 20) * 4E-4; + i += 20; + deph[2] = getbits(rtcm->buff, i, 20) * 4E-4; + i += 20; + ddeph[0] = getbits(rtcm->buff, i, 21) * 1E-6; + i += 21; + ddeph[1] = getbits(rtcm->buff, i, 19) * 4E-6; + i += 19; + ddeph[2] = getbits(rtcm->buff, i, 19) * 4E-6; + i += 19; + + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[0] = rtcm->time; + rtcm->ssr[sat - 1].udi[0] = udint; + rtcm->ssr[sat - 1].iod[0] = iod; + rtcm->ssr[sat - 1].iode = iode; /* sbas/bds: toe/t0 modulo */ + rtcm->ssr[sat - 1].iodcrc = iodcrc; /* sbas/bds: iod crc */ + rtcm->ssr[sat - 1].refd = refd; + + for (k = 0; k < 3; k++) + { + rtcm->ssr[sat - 1].deph[k] = deph[k]; + rtcm->ssr[sat - 1].ddeph[k] = ddeph[k]; + } + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 2: clock corrections -------------------------------------------*/ +int decode_ssr2(rtcm_t *rtcm, int sys) +{ + double udint, dclk[3]; + int i, j, k, type, sync, iod, nsat, prn, sat, np, offp; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr2_head(rtcm, sys, &sync, &iod, &udint, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + offp = 0; + break; + case SYS_GLO: + np = 5; + offp = 0; + break; + case SYS_GAL: + np = 6; + offp = 0; + break; + case SYS_QZS: + np = 4; + offp = 192; + break; + case SYS_BDS: + np = 6; + offp = 1; + break; + case SYS_SBS: + np = 6; + offp = 120; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 70 + np <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + dclk[0] = getbits(rtcm->buff, i, 22) * 1E-4; + i += 22; + dclk[1] = getbits(rtcm->buff, i, 21) * 1E-6; + i += 21; + dclk[2] = getbits(rtcm->buff, i, 27) * 2E-8; + i += 27; + + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[1] = rtcm->time; + rtcm->ssr[sat - 1].udi[1] = udint; + rtcm->ssr[sat - 1].iod[1] = iod; + + for (k = 0; k < 3; k++) + { + rtcm->ssr[sat - 1].dclk[k] = dclk[k]; + } + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 3: satellite code biases ---------------------------------------*/ +int decode_ssr3(rtcm_t *rtcm, int sys) +{ + const int *codes; + double udint, bias, cbias[MAXCODE]; + int i, j, k, type, mode, sync, iod, nsat, prn, sat, nbias, np, offp, ncode; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr2_head(rtcm, sys, &sync, &iod, &udint, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + offp = 0; + codes = codes_gps; + ncode = 17; + break; + case SYS_GLO: + np = 5; + offp = 0; + codes = codes_glo; + ncode = 4; + break; + case SYS_GAL: + np = 6; + offp = 0; + codes = codes_gal; + ncode = 19; + break; + case SYS_QZS: + np = 4; + offp = 192; + codes = codes_qzs; + ncode = 13; + break; + case SYS_BDS: + np = 6; + offp = 1; + codes = codes_bds; + ncode = 9; + break; + case SYS_SBS: + np = 6; + offp = 120; + codes = codes_sbs; + ncode = 4; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 5 + np <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + nbias = getbitu(rtcm->buff, i, 5); + i += 5; + + for (k = 0; k < MAXCODE; k++) cbias[k] = 0.0; + for (k = 0; k < nbias && i + 19 <= rtcm->len * 8; k++) + { + mode = getbitu(rtcm->buff, i, 5); + i += 5; + bias = getbits(rtcm->buff, i, 14) * 0.01; + i += 14; + if (mode <= ncode) + { + cbias[codes[mode] - 1] = static_cast(bias); + } + else + { + trace(2, "rtcm3 %d not supported mode: mode=%d\n", type, mode); + } + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[4] = rtcm->time; + rtcm->ssr[sat - 1].udi[4] = udint; + rtcm->ssr[sat - 1].iod[4] = iod; + + for (k = 0; k < MAXCODE; k++) + { + rtcm->ssr[sat - 1].cbias[k] = static_cast(cbias[k]); + } + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 4: combined orbit and clock corrections ------------------------*/ +int decode_ssr4(rtcm_t *rtcm, int sys) +{ + double udint, deph[3], ddeph[3], dclk[3]; + int i, j, k, type, nsat, sync, iod, prn, sat, iode, iodcrc, refd = 0, np, ni, nj, offp; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr1_head(rtcm, sys, &sync, &iod, &udint, &refd, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + ni = 8; + nj = 0; + offp = 0; + break; + case SYS_GLO: + np = 5; + ni = 8; + nj = 0; + offp = 0; + break; + case SYS_GAL: + np = 6; + ni = 10; + nj = 0; + offp = 0; + break; + case SYS_QZS: + np = 4; + ni = 8; + nj = 0; + offp = 192; + break; + case SYS_BDS: + np = 6; + ni = 10; + nj = 24; + offp = 1; + break; + case SYS_SBS: + np = 6; + ni = 9; + nj = 24; + offp = 120; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 191 + np + ni + nj <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + iode = getbitu(rtcm->buff, i, ni); + i += ni; + iodcrc = getbitu(rtcm->buff, i, nj); + i += nj; + deph[0] = getbits(rtcm->buff, i, 22) * 1E-4; + i += 22; + deph[1] = getbits(rtcm->buff, i, 20) * 4E-4; + i += 20; + deph[2] = getbits(rtcm->buff, i, 20) * 4E-4; + i += 20; + ddeph[0] = getbits(rtcm->buff, i, 21) * 1E-6; + i += 21; + ddeph[1] = getbits(rtcm->buff, i, 19) * 4E-6; + i += 19; + ddeph[2] = getbits(rtcm->buff, i, 19) * 4E-6; + i += 19; + + dclk[0] = getbits(rtcm->buff, i, 22) * 1E-4; + i += 22; + dclk[1] = getbits(rtcm->buff, i, 21) * 1E-6; + i += 21; + dclk[2] = getbits(rtcm->buff, i, 27) * 2E-8; + i += 27; + + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[0] = rtcm->ssr[sat - 1].t0[1] = rtcm->time; + rtcm->ssr[sat - 1].udi[0] = rtcm->ssr[sat - 1].udi[1] = udint; + rtcm->ssr[sat - 1].iod[0] = rtcm->ssr[sat - 1].iod[1] = iod; + rtcm->ssr[sat - 1].iode = iode; + rtcm->ssr[sat - 1].iodcrc = iodcrc; + rtcm->ssr[sat - 1].refd = refd; + + for (k = 0; k < 3; k++) + { + rtcm->ssr[sat - 1].deph[k] = deph[k]; + rtcm->ssr[sat - 1].ddeph[k] = ddeph[k]; + rtcm->ssr[sat - 1].dclk[k] = dclk[k]; + } + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 5: ura ---------------------------------------------------------*/ +int decode_ssr5(rtcm_t *rtcm, int sys) +{ + double udint; + int i, j, type, nsat, sync, iod, prn, sat, ura, np, offp; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr2_head(rtcm, sys, &sync, &iod, &udint, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + offp = 0; + break; + case SYS_GLO: + np = 5; + offp = 0; + break; + case SYS_GAL: + np = 6; + offp = 0; + break; + case SYS_QZS: + np = 4; + offp = 192; + break; + case SYS_BDS: + np = 6; + offp = 1; + break; + case SYS_SBS: + np = 6; + offp = 120; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 6 + np <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + ura = getbitu(rtcm->buff, i, 6); + i += 6; + + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[3] = rtcm->time; + rtcm->ssr[sat - 1].udi[3] = udint; + rtcm->ssr[sat - 1].iod[3] = iod; + rtcm->ssr[sat - 1].ura = ura; + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 6: high rate clock correction ----------------------------------*/ +int decode_ssr6(rtcm_t *rtcm, int sys) +{ + double udint, hrclk; + int i, j, type, nsat, sync, iod, prn, sat, np, offp; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr2_head(rtcm, sys, &sync, &iod, &udint, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + offp = 0; + break; + case SYS_GLO: + np = 5; + offp = 0; + break; + case SYS_GAL: + np = 6; + offp = 0; + break; + case SYS_QZS: + np = 4; + offp = 192; + break; + case SYS_BDS: + np = 6; + offp = 1; + break; + case SYS_SBS: + np = 6; + offp = 120; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 22 + np <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + hrclk = getbits(rtcm->buff, i, 22) * 1E-4; + i += 22; + + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[2] = rtcm->time; + rtcm->ssr[sat - 1].udi[2] = udint; + rtcm->ssr[sat - 1].iod[2] = iod; + rtcm->ssr[sat - 1].hrclk = hrclk; + rtcm->ssr[sat - 1].update = 1; + } + return sync ? 0 : 10; +} + + +/* decode ssr 7: phase bias --------------------------------------------------*/ +int decode_ssr7(rtcm_t *rtcm, int sys) +{ + const int *codes; + double udint, bias, std, pbias[MAXCODE], stdpb[MAXCODE]; + int i, j, k, type, mode, sync, iod, nsat, prn, sat, nbias, ncode, np, mw, offp; + int dispe, yaw_ang, yaw_rate; + + type = getbitu(rtcm->buff, 24, 12); + + if ((nsat = decode_ssr7_head(rtcm, sys, &sync, &iod, &udint, &dispe, &mw, &i)) < 0) + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + switch (sys) + { + case SYS_GPS: + np = 6; + offp = 0; + codes = codes_gps; + ncode = 17; + break; + case SYS_GLO: + np = 5; + offp = 0; + codes = codes_glo; + ncode = 4; + break; + case SYS_GAL: + np = 6; + offp = 0; + codes = codes_gal; + ncode = 19; + break; + case SYS_QZS: + np = 4; + offp = 192; + codes = codes_qzs; + ncode = 13; + break; + case SYS_BDS: + np = 6; + offp = 1; + codes = codes_bds; + ncode = 9; + break; + default: + return sync ? 0 : 10; + } + for (j = 0; j < nsat && i + 5 + 17 + np <= rtcm->len * 8; j++) + { + prn = getbitu(rtcm->buff, i, np) + offp; + i += np; + nbias = getbitu(rtcm->buff, i, 5); + i += 5; + yaw_ang = getbitu(rtcm->buff, i, 9); + i += 9; + yaw_rate = getbits(rtcm->buff, i, 8); + i += 8; + + for (k = 0; k < MAXCODE; k++) pbias[k] = stdpb[k] = 0.0; + for (k = 0; k < nbias && i + 49 <= rtcm->len * 8; k++) + { + mode = getbitu(rtcm->buff, i, 5); + i += 5; + /* sii = getbitu(rtcm->buff, i, 1); */ i += 1; /* integer-indicator */ + /* swl = getbitu(rtcm->buff, i, 2); */ i += 2; /* WL integer-indicator */ + /* sdc = getbitu(rtcm->buff, i, 4); */ i += 4; /* discontinuity counter */ + bias = getbits(rtcm->buff, i, 20); + i += 20; /* phase bias (m) */ + std = getbitu(rtcm->buff, i, 17); + i += 17; /* phase bias std-dev (m) */ + if (mode <= ncode) + { + pbias[codes[mode] - 1] = bias * 0.0001; /* (m) */ + stdpb[codes[mode] - 1] = std * 0.0001; /* (m) */ + } + else + { + trace(2, "rtcm3 %d not supported mode: mode=%d\n", type, mode); + } + } + if (!(sat = satno(sys, prn))) + { + trace(2, "rtcm3 %d satellite number error: prn=%d\n", type, prn); + continue; + } + rtcm->ssr[sat - 1].t0[5] = rtcm->time; + rtcm->ssr[sat - 1].udi[5] = udint; + rtcm->ssr[sat - 1].iod[5] = iod; + rtcm->ssr[sat - 1].yaw_ang = yaw_ang / 256.0 * 180.0; /* (deg) */ + rtcm->ssr[sat - 1].yaw_rate = yaw_rate / 8192.0 * 180.0; /* (deg/s) */ + + for (k = 0; k < MAXCODE; k++) + { + rtcm->ssr[sat - 1].pbias[k] = pbias[k]; + rtcm->ssr[sat - 1].stdpb[k] = static_cast(stdpb[k]); + } + } + return 20; +} + + +/* get signal index ----------------------------------------------------------*/ +void sigindex(int sys, const unsigned char *code, const int *freq, int n, + const char *opt, int *ind) +{ + int i, nex, pri, pri_h[8] = {0}, index[8] = {0}, ex[32] = {0}; + + /* test code priority */ + for (i = 0; i < n; i++) + { + if (!code[i]) continue; + + if (freq[i] > NFREQ) + { /* save as extended signal if freq > NFREQ */ + ex[i] = 1; + continue; + } + /* code priority */ + pri = getcodepri(sys, code[i], opt); + + /* select highest priority signal */ + if (pri > pri_h[freq[i] - 1]) + { + if (index[freq[i] - 1]) ex[index[freq[i] - 1] - 1] = 1; + pri_h[freq[i] - 1] = pri; + index[freq[i] - 1] = i + 1; + } + else + ex[i] = 1; + } + /* signal index in obs data */ + for (i = nex = 0; i < n; i++) + { + if (ex[i] == 0) + ind[i] = freq[i] - 1; + else if (nex < NEXOBS) + ind[i] = NFREQ + nex++; + else + { /* no space in obs data */ + trace(2, "rtcm msm: no space in obs data sys=%d code=%d\n", sys, code[i]); + ind[i] = -1; + } +#if 0 + trace(2, "sig pos: sys=%d code=%d ex=%d ind=%d\n", sys, code[i], ex[i], ind[i]); +#endif + } +} + + +/* save obs data in msm message ----------------------------------------------*/ +void save_msm_obs(rtcm_t *rtcm, int sys, msm_h_t *h, const double *r, + const double *pr, const double *cp, const double *rr, + const double *rrf, const double *cnr, const int *lock, + const int *ex, const int *half) +{ + const char *sig[32]; + double tt, wl; + unsigned char code[32]; + char *msm_type = (char *)"", *q = nullptr; + int i, j, k, type, prn, sat, fn, index = 0, freq[32], ind[32]; + + type = getbitu(rtcm->buff, 24, 12); + + switch (sys) + { + case SYS_GPS: + msm_type = q = rtcm->msmtype[0]; + break; + case SYS_GLO: + msm_type = q = rtcm->msmtype[1]; + break; + case SYS_GAL: + msm_type = q = rtcm->msmtype[2]; + break; + case SYS_QZS: + msm_type = q = rtcm->msmtype[3]; + break; + case SYS_SBS: + msm_type = q = rtcm->msmtype[4]; + break; + case SYS_BDS: + msm_type = q = rtcm->msmtype[5]; + break; + } + /* id to signal */ + for (i = 0; i < h->nsig; i++) + { + switch (sys) + { + case SYS_GPS: + sig[i] = msm_sig_gps[h->sigs[i] - 1]; + break; + case SYS_GLO: + sig[i] = msm_sig_glo[h->sigs[i] - 1]; + break; + case SYS_GAL: + sig[i] = msm_sig_gal[h->sigs[i] - 1]; + break; + case SYS_QZS: + sig[i] = msm_sig_qzs[h->sigs[i] - 1]; + break; + case SYS_SBS: + sig[i] = msm_sig_sbs[h->sigs[i] - 1]; + break; + case SYS_BDS: + sig[i] = msm_sig_cmp[h->sigs[i] - 1]; + break; + default: + sig[i] = ""; + break; + } + /* signal to rinex obs type */ + code[i] = obs2code(sig[i], freq + i); + + /* frequency index for beidou */ + if (sys == SYS_BDS) + { + if (freq[i] == 5) + freq[i] = 2; /* B2 */ + else if (freq[i] == 4) + freq[i] = 3; /* B3 */ + } + if (code[i] != CODE_NONE) + { + if (q) q += sprintf(q, "L%s%s", sig[i], i < h->nsig - 1 ? ", " : ""); + } + else + { + if (q) q += sprintf(q, "(%d)%s", h->sigs[i], i < h->nsig - 1 ? ", " : ""); + + trace(2, "rtcm3 %d: unknown signal id=%2d\n", type, h->sigs[i]); + } + } + trace(3, "rtcm3 %d: signals=%s\n", type, msm_type); + + /* get signal index */ + sigindex(sys, code, freq, h->nsig, rtcm->opt, ind); + + for (i = j = 0; i < h->nsat; i++) + { + prn = h->sats[i]; + if (sys == SYS_QZS) + prn += MINPRNQZS - 1; + else if (sys == SYS_SBS) + prn += MINPRNSBS - 1; + + if ((sat = satno(sys, prn))) + { + tt = timediff(rtcm->obs.data[0].time, rtcm->time); + if (rtcm->obsflag || fabs(tt) > 1E-9) + { + rtcm->obs.n = rtcm->obsflag = 0; + } + index = obsindex3(&rtcm->obs, rtcm->time, sat); + } + else + { + trace(2, "rtcm3 %d satellite error: prn=%d\n", type, prn); + } + for (k = 0; k < h->nsig; k++) + { + if (!h->cellmask[k + i * h->nsig]) continue; + + if (sat && index >= 0 && ind[k] >= 0) + { + /* satellite carrier wave length */ + wl = satwavelen(sat, freq[k] - 1, &rtcm->nav); + + /* glonass wave length by extended info */ + if (sys == SYS_GLO && ex && ex[i] <= 13) + { + fn = ex[i] - 7; + wl = SPEED_OF_LIGHT / ((freq[k] == 2 ? FREQ2_GLO : FREQ1_GLO) + + (freq[k] == 2 ? DFRQ2_GLO : DFRQ1_GLO) * fn); + } + /* pseudorange (m) */ + if (r[i] != 0.0 && pr[j] > -1E12) + { + rtcm->obs.data[index].P[ind[k]] = r[i] + pr[j]; + } + /* carrier-phase (cycle) */ + if (r[i] != 0.0 && cp[j] > -1E12 && wl > 0.0) + { + rtcm->obs.data[index].L[ind[k]] = (r[i] + cp[j]) / wl; + } + /* doppler (hz) */ + if (rr && rrf && rrf[j] > -1E12 && wl > 0.0) + { + rtcm->obs.data[index].D[ind[k]] = static_cast(-(rr[i] + rrf[j]) / wl); + } + rtcm->obs.data[index].LLI[ind[k]] = + lossoflock(rtcm, sat, ind[k], lock[j]) + (half[j] ? 3 : 0); + rtcm->obs.data[index].SNR[ind[k]] = static_cast(cnr[j] * 4.0); + rtcm->obs.data[index].code[ind[k]] = code[k]; + } + j++; + } + } +} + + +/* decode type msm message header --------------------------------------------*/ +int decode_msm_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + msm_h_t *h, int *hsize) +{ + msm_h_t h0 = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + double tow, tod; + char *msg; + int i = 24, j, mask, staid, type, ncell = 0; + + type = getbitu(rtcm->buff, i, 12); + i += 12; + + *h = h0; + if (i + 157 <= rtcm->len * 8) + { + staid = getbitu(rtcm->buff, i, 12); + i += 12; + + if (sys == SYS_GLO) + { + /* dow = getbitu(rtcm->buff, i, 3); */ i += 3; + tod = getbitu(rtcm->buff, i, 27) * 0.001; + i += 27; + adjday_glot(rtcm, tod); + } + else if (sys == SYS_BDS) + { + tow = getbitu(rtcm->buff, i, 30) * 0.001; + i += 30; + tow += 14.0; /* BDT -> GPST */ + adjweek(rtcm, tow); + } + else + { + tow = getbitu(rtcm->buff, i, 30) * 0.001; + i += 30; + adjweek(rtcm, tow); + } + *sync = getbitu(rtcm->buff, i, 1); + i += 1; + *iod = getbitu(rtcm->buff, i, 3); + i += 3; + h->time_s = getbitu(rtcm->buff, i, 7); + i += 7; + h->clk_str = getbitu(rtcm->buff, i, 2); + i += 2; + h->clk_ext = getbitu(rtcm->buff, i, 2); + i += 2; + h->smooth = getbitu(rtcm->buff, i, 1); + i += 1; + h->tint_s = getbitu(rtcm->buff, i, 3); + i += 3; + for (j = 1; j <= 64; j++) + { + mask = getbitu(rtcm->buff, i, 1); + i += 1; + if (mask) h->sats[h->nsat++] = j; + } + for (j = 1; j <= 32; j++) + { + mask = getbitu(rtcm->buff, i, 1); + i += 1; + if (mask) h->sigs[h->nsig++] = j; + } + } + else + { + trace(2, "rtcm3 %d length error: len=%d\n", type, rtcm->len); + return -1; + } + /* test station id */ + if (!test_staid(rtcm, staid)) return -1; + + if (h->nsat * h->nsig > 64) + { + trace(2, "rtcm3 %d number of sats and sigs error: nsat=%d nsig=%d\n", + type, h->nsat, h->nsig); + return -1; + } + if (i + h->nsat * h->nsig > rtcm->len * 8) + { + trace(2, "rtcm3 %d length error: len=%d nsat=%d nsig=%d\n", type, + rtcm->len, h->nsat, h->nsig); + return -1; + } + for (j = 0; j < h->nsat * h->nsig; j++) + { + h->cellmask[j] = getbitu(rtcm->buff, i, 1); + i += 1; + if (h->cellmask[j]) ncell++; + } + *hsize = i; + + trace(4, "decode_head_msm: time=%s sys=%d staid=%d nsat=%d nsig=%d sync=%d iod=%d ncell=%d\n", + time_str(rtcm->time, 2), sys, staid, h->nsat, h->nsig, *sync, *iod, ncell); + + if (rtcm->outtype) + { + msg = rtcm->msgtype + strlen(rtcm->msgtype); + sprintf(msg, " staid=%4d %s nsat=%2d nsig=%2d iod=%2d ncell=%2d sync=%d", + staid, time_str(rtcm->time, 2), h->nsat, h->nsig, *iod, ncell, *sync); + } + return ncell; +} + + +/* decode unsupported msm message --------------------------------------------*/ +int decode_msm0(rtcm_t *rtcm, int sys) +{ + msm_h_t h = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + int i, sync, iod; + if (decode_msm_head(rtcm, sys, &sync, &iod, &h, &i) < 0) return -1; + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode msm 4: full pseudorange and phaserange plus cnr --------------------*/ +int decode_msm4(rtcm_t *rtcm, int sys) +{ + msm_h_t h = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + double r[64], pr[64], cp[64], cnr[64]; + int i, j, type, sync, iod, ncell, rng, rng_m, prv, cpv, lock[64], half[64]; + + type = getbitu(rtcm->buff, 24, 12); + + /* decode msm header */ + if ((ncell = decode_msm_head(rtcm, sys, &sync, &iod, &h, &i)) < 0) return -1; + + if (i + h.nsat * 18 + ncell * 48 > rtcm->len * 8) + { + trace(2, "rtcm3 %d length error: nsat=%d ncell=%d len=%d\n", type, h.nsat, + ncell, rtcm->len); + return -1; + } + for (j = 0; j < h.nsat; j++) r[j] = 0.0; + for (j = 0; j < ncell; j++) pr[j] = cp[j] = -1E16; + + /* decode satellite data */ + for (j = 0; j < h.nsat; j++) + { /* range */ + rng = getbitu(rtcm->buff, i, 8); + i += 8; + if (rng != 255) r[j] = rng * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { + rng_m = getbitu(rtcm->buff, i, 10); + i += 10; + if (r[j] != 0.0) r[j] += rng_m * TWO_N10 * RANGE_MS; + } + /* decode signal data */ + for (j = 0; j < ncell; j++) + { /* pseudorange */ + prv = getbits(rtcm->buff, i, 15); + i += 15; + if (prv != -16384) pr[j] = prv * TWO_N24 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* phaserange */ + cpv = getbits(rtcm->buff, i, 22); + i += 22; + if (cpv != -2097152) cp[j] = cpv * TWO_N29 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* lock time */ + lock[j] = getbitu(rtcm->buff, i, 4); + i += 4; + } + for (j = 0; j < ncell; j++) + { /* half-cycle ambiguity */ + half[j] = getbitu(rtcm->buff, i, 1); + i += 1; + } + for (j = 0; j < ncell; j++) + { /* cnr */ + cnr[j] = getbitu(rtcm->buff, i, 6) * 1.0; + i += 6; + } + /* save obs data in msm message */ + save_msm_obs(rtcm, sys, &h, r, pr, cp, nullptr, nullptr, cnr, lock, nullptr, half); + + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode msm 5: full pseudorange, phaserange, phaserangerate and cnr --------*/ +int decode_msm5(rtcm_t *rtcm, int sys) +{ + msm_h_t h = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + double r[64], rr[64], pr[64], cp[64], rrf[64], cnr[64]; + int i, j, type, sync, iod, ncell, rng, rng_m, rate, prv, cpv, rrv, lock[64]; + int ex[64], half[64]; + + type = getbitu(rtcm->buff, 24, 12); + + /* decode msm header */ + if ((ncell = decode_msm_head(rtcm, sys, &sync, &iod, &h, &i)) < 0) return -1; + + if (i + h.nsat * 36 + ncell * 63 > rtcm->len * 8) + { + trace(2, "rtcm3 %d length error: nsat=%d ncell=%d len=%d\n", type, h.nsat, + ncell, rtcm->len); + return -1; + } + for (j = 0; j < h.nsat; j++) + { + r[j] = rr[j] = 0.0; + ex[j] = 15; + } + for (j = 0; j < ncell; j++) pr[j] = cp[j] = rrf[j] = -1E16; + + /* decode satellite data */ + for (j = 0; j < h.nsat; j++) + { /* range */ + rng = getbitu(rtcm->buff, i, 8); + i += 8; + if (rng != 255) r[j] = rng * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { /* extended info */ + ex[j] = getbitu(rtcm->buff, i, 4); + i += 4; + } + for (j = 0; j < h.nsat; j++) + { + rng_m = getbitu(rtcm->buff, i, 10); + i += 10; + if (r[j] != 0.0) r[j] += rng_m * TWO_N10 * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { /* phaserangerate */ + rate = getbits(rtcm->buff, i, 14); + i += 14; + if (rate != -8192) rr[j] = rate * 1.0; + } + /* decode signal data */ + for (j = 0; j < ncell; j++) + { /* pseudorange */ + prv = getbits(rtcm->buff, i, 15); + i += 15; + if (prv != -16384) pr[j] = prv * TWO_N24 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* phaserange */ + cpv = getbits(rtcm->buff, i, 22); + i += 22; + if (cpv != -2097152) cp[j] = cpv * TWO_N29 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* lock time */ + lock[j] = getbitu(rtcm->buff, i, 4); + i += 4; + } + for (j = 0; j < ncell; j++) + { /* half-cycle ambiguity */ + half[j] = getbitu(rtcm->buff, i, 1); + i += 1; + } + for (j = 0; j < ncell; j++) + { /* cnr */ + cnr[j] = getbitu(rtcm->buff, i, 6) * 1.0; + i += 6; + } + for (j = 0; j < ncell; j++) + { /* phaserangerate */ + rrv = getbits(rtcm->buff, i, 15); + i += 15; + if (rrv != -16384) rrf[j] = rrv * 0.0001; + } + /* save obs data in msm message */ + save_msm_obs(rtcm, sys, &h, r, pr, cp, rr, rrf, cnr, lock, ex, half); + + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode msm 6: full pseudorange and phaserange plus cnr (high-res) ---------*/ +int decode_msm6(rtcm_t *rtcm, int sys) +{ + msm_h_t h = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + double r[64], pr[64], cp[64], cnr[64]; + int i, j, type, sync, iod, ncell, rng, rng_m, prv, cpv, lock[64], half[64]; + + type = getbitu(rtcm->buff, 24, 12); + + /* decode msm header */ + if ((ncell = decode_msm_head(rtcm, sys, &sync, &iod, &h, &i)) < 0) return -1; + + if (i + h.nsat * 18 + ncell * 65 > rtcm->len * 8) + { + trace(2, "rtcm3 %d length error: nsat=%d ncell=%d len=%d\n", type, h.nsat, + ncell, rtcm->len); + return -1; + } + for (j = 0; j < h.nsat; j++) r[j] = 0.0; + for (j = 0; j < ncell; j++) pr[j] = cp[j] = -1E16; + + /* decode satellite data */ + for (j = 0; j < h.nsat; j++) + { /* range */ + rng = getbitu(rtcm->buff, i, 8); + i += 8; + if (rng != 255) r[j] = rng * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { + rng_m = getbitu(rtcm->buff, i, 10); + i += 10; + if (r[j] != 0.0) r[j] += rng_m * TWO_N10 * RANGE_MS; + } + /* decode signal data */ + for (j = 0; j < ncell; j++) + { /* pseudorange */ + prv = getbits(rtcm->buff, i, 20); + i += 20; + if (prv != -524288) pr[j] = prv * TWO_N29 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* phaserange */ + cpv = getbits(rtcm->buff, i, 24); + i += 24; + if (cpv != -8388608) cp[j] = cpv * TWO_N31 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* lock time */ + lock[j] = getbitu(rtcm->buff, i, 10); + i += 10; + } + for (j = 0; j < ncell; j++) + { /* half-cycle ambiguity */ + half[j] = getbitu(rtcm->buff, i, 1); + i += 1; + } + for (j = 0; j < ncell; j++) + { /* cnr */ + cnr[j] = getbitu(rtcm->buff, i, 10) * 0.0625; + i += 10; + } + /* save obs data in msm message */ + save_msm_obs(rtcm, sys, &h, r, pr, cp, nullptr, nullptr, cnr, lock, nullptr, half); + + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode msm 7: full pseudorange, phaserange, phaserangerate and cnr (h-res) */ +int decode_msm7(rtcm_t *rtcm, int sys) +{ + msm_h_t h = {0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}; + double r[64], rr[64], pr[64], cp[64], rrf[64], cnr[64]; + int i, j, type, sync, iod, ncell, rng, rng_m, rate, prv, cpv, rrv, lock[64]; + int ex[64], half[64]; + + type = getbitu(rtcm->buff, 24, 12); + + /* decode msm header */ + if ((ncell = decode_msm_head(rtcm, sys, &sync, &iod, &h, &i)) < 0) return -1; + + if (i + h.nsat * 36 + ncell * 80 > rtcm->len * 8) + { + trace(2, "rtcm3 %d length error: nsat=%d ncell=%d len=%d\n", type, h.nsat, + ncell, rtcm->len); + return -1; + } + for (j = 0; j < h.nsat; j++) + { + r[j] = rr[j] = 0.0; + ex[j] = 15; + } + for (j = 0; j < ncell; j++) pr[j] = cp[j] = rrf[j] = -1E16; + + /* decode satellite data */ + for (j = 0; j < h.nsat; j++) + { /* range */ + rng = getbitu(rtcm->buff, i, 8); + i += 8; + if (rng != 255) r[j] = rng * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { /* extended info */ + ex[j] = getbitu(rtcm->buff, i, 4); + i += 4; + } + for (j = 0; j < h.nsat; j++) + { + rng_m = getbitu(rtcm->buff, i, 10); + i += 10; + if (r[j] != 0.0) r[j] += rng_m * TWO_N10 * RANGE_MS; + } + for (j = 0; j < h.nsat; j++) + { /* phaserangerate */ + rate = getbits(rtcm->buff, i, 14); + i += 14; + if (rate != -8192) rr[j] = rate * 1.0; + } + /* decode signal data */ + for (j = 0; j < ncell; j++) + { /* pseudorange */ + prv = getbits(rtcm->buff, i, 20); + i += 20; + if (prv != -524288) pr[j] = prv * TWO_N29 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* phaserange */ + cpv = getbits(rtcm->buff, i, 24); + i += 24; + if (cpv != -8388608) cp[j] = cpv * TWO_N31 * RANGE_MS; + } + for (j = 0; j < ncell; j++) + { /* lock time */ + lock[j] = getbitu(rtcm->buff, i, 10); + i += 10; + } + for (j = 0; j < ncell; j++) + { /* half-cycle amiguity */ + half[j] = getbitu(rtcm->buff, i, 1); + i += 1; + } + for (j = 0; j < ncell; j++) + { /* cnr */ + cnr[j] = getbitu(rtcm->buff, i, 10) * 0.0625; + i += 10; + } + for (j = 0; j < ncell; j++) + { /* phaserangerate */ + rrv = getbits(rtcm->buff, i, 15); + i += 15; + if (rrv != -16384) rrf[j] = rrv * 0.0001; + } + /* save obs data in msm message */ + save_msm_obs(rtcm, sys, &h, r, pr, cp, rr, rrf, cnr, lock, ex, half); + + rtcm->obsflag = !sync; + return sync ? 0 : 1; +} + + +/* decode type 1230: glonass L1 and L2 code-phase biases ---------------------*/ +int decode_type1230(rtcm_t *rtcm __attribute__((unused))) +{ + trace(2, "rtcm3 1230: not supported message\n"); + return 0; +} + + +/* decode rtcm ver.3 message -------------------------------------------------*/ +int decode_rtcm3(rtcm_t *rtcm) +{ + double tow; + int ret = 0, type = getbitu(rtcm->buff, 24, 12), week; + + trace(3, "decode_rtcm3: len=%3d type=%d\n", rtcm->len, type); + + if (rtcm->outtype) + { + sprintf(rtcm->msgtype, "RTCM %4d (%4d):", type, rtcm->len); + } + /* real-time input option */ + if (strstr(rtcm->opt, "-RT_INP")) + { + tow = time2gpst(utc2gpst(timeget()), &week); + rtcm->time = gpst2time(week, floor(tow)); + } + switch (type) + { + case 1001: + ret = decode_type1001(rtcm); + break; /* not supported */ + case 1002: + ret = decode_type1002(rtcm); + break; + case 1003: + ret = decode_type1003(rtcm); + break; /* not supported */ + case 1004: + ret = decode_type1004(rtcm); + break; + case 1005: + ret = decode_type1005(rtcm); + break; + case 1006: + ret = decode_type1006(rtcm); + break; + case 1007: + ret = decode_type1007(rtcm); + break; + case 1008: + ret = decode_type1008(rtcm); + break; + case 1009: + ret = decode_type1009(rtcm); + break; /* not supported */ + case 1010: + ret = decode_type1010(rtcm); + break; + case 1011: + ret = decode_type1011(rtcm); + break; /* not supported */ + case 1012: + ret = decode_type1012(rtcm); + break; + case 1013: + ret = decode_type1013(rtcm); + break; /* not supported */ + case 1019: + ret = decode_type1019(rtcm); + break; + case 1020: + ret = decode_type1020(rtcm); + break; + case 1021: + ret = decode_type1021(rtcm); + break; /* not supported */ + case 1022: + ret = decode_type1022(rtcm); + break; /* not supported */ + case 1023: + ret = decode_type1023(rtcm); + break; /* not supported */ + case 1024: + ret = decode_type1024(rtcm); + break; /* not supported */ + case 1025: + ret = decode_type1025(rtcm); + break; /* not supported */ + case 1026: + ret = decode_type1026(rtcm); + break; /* not supported */ + case 1027: + ret = decode_type1027(rtcm); + break; /* not supported */ + case 1029: + ret = decode_type1029(rtcm); + break; + case 1030: + ret = decode_type1030(rtcm); + break; /* not supported */ + case 1031: + ret = decode_type1031(rtcm); + break; /* not supported */ + case 1032: + ret = decode_type1032(rtcm); + break; /* not supported */ + case 1033: + ret = decode_type1033(rtcm); + break; + case 1034: + ret = decode_type1034(rtcm); + break; /* not supported */ + case 1035: + ret = decode_type1035(rtcm); + break; /* not supported */ + case 1037: + ret = decode_type1037(rtcm); + break; /* not supported */ + case 1038: + ret = decode_type1038(rtcm); + break; /* not supported */ + case 1039: + ret = decode_type1039(rtcm); + break; /* not supported */ + case 1044: + ret = decode_type1044(rtcm); + break; + case 1045: + ret = decode_type1045(rtcm); + break; + case 1046: + ret = decode_type1046(rtcm); + break; /* extension for IGS MGEX */ + case 1047: + ret = decode_type1047(rtcm); + break; /* beidou ephemeris (tentative mt) */ + case 63: + ret = decode_type63(rtcm); + break; /* beidou ephemeris (rtcm draft) */ + case 1057: + ret = decode_ssr1(rtcm, SYS_GPS); + break; + case 1058: + ret = decode_ssr2(rtcm, SYS_GPS); + break; + case 1059: + ret = decode_ssr3(rtcm, SYS_GPS); + break; + case 1060: + ret = decode_ssr4(rtcm, SYS_GPS); + break; + case 1061: + ret = decode_ssr5(rtcm, SYS_GPS); + break; + case 1062: + ret = decode_ssr6(rtcm, SYS_GPS); + break; + case 1063: + ret = decode_ssr1(rtcm, SYS_GLO); + break; + case 1064: + ret = decode_ssr2(rtcm, SYS_GLO); + break; + case 1065: + ret = decode_ssr3(rtcm, SYS_GLO); + break; + case 1066: + ret = decode_ssr4(rtcm, SYS_GLO); + break; + case 1067: + ret = decode_ssr5(rtcm, SYS_GLO); + break; + case 1068: + ret = decode_ssr6(rtcm, SYS_GLO); + break; + case 1071: + ret = decode_msm0(rtcm, SYS_GPS); + break; /* not supported */ + case 1072: + ret = decode_msm0(rtcm, SYS_GPS); + break; /* not supported */ + case 1073: + ret = decode_msm0(rtcm, SYS_GPS); + break; /* not supported */ + case 1074: + ret = decode_msm4(rtcm, SYS_GPS); + break; + case 1075: + ret = decode_msm5(rtcm, SYS_GPS); + break; + case 1076: + ret = decode_msm6(rtcm, SYS_GPS); + break; + case 1077: + ret = decode_msm7(rtcm, SYS_GPS); + break; + case 1081: + ret = decode_msm0(rtcm, SYS_GLO); + break; /* not supported */ + case 1082: + ret = decode_msm0(rtcm, SYS_GLO); + break; /* not supported */ + case 1083: + ret = decode_msm0(rtcm, SYS_GLO); + break; /* not supported */ + case 1084: + ret = decode_msm4(rtcm, SYS_GLO); + break; + case 1085: + ret = decode_msm5(rtcm, SYS_GLO); + break; + case 1086: + ret = decode_msm6(rtcm, SYS_GLO); + break; + case 1087: + ret = decode_msm7(rtcm, SYS_GLO); + break; + case 1091: + ret = decode_msm0(rtcm, SYS_GAL); + break; /* not supported */ + case 1092: + ret = decode_msm0(rtcm, SYS_GAL); + break; /* not supported */ + case 1093: + ret = decode_msm0(rtcm, SYS_GAL); + break; /* not supported */ + case 1094: + ret = decode_msm4(rtcm, SYS_GAL); + break; + case 1095: + ret = decode_msm5(rtcm, SYS_GAL); + break; + case 1096: + ret = decode_msm6(rtcm, SYS_GAL); + break; + case 1097: + ret = decode_msm7(rtcm, SYS_GAL); + break; + case 1101: + ret = decode_msm0(rtcm, SYS_SBS); + break; /* not supported */ + case 1102: + ret = decode_msm0(rtcm, SYS_SBS); + break; /* not supported */ + case 1103: + ret = decode_msm0(rtcm, SYS_SBS); + break; /* not supported */ + case 1104: + ret = decode_msm4(rtcm, SYS_SBS); + break; + case 1105: + ret = decode_msm5(rtcm, SYS_SBS); + break; + case 1106: + ret = decode_msm6(rtcm, SYS_SBS); + break; + case 1107: + ret = decode_msm7(rtcm, SYS_SBS); + break; + case 1111: + ret = decode_msm0(rtcm, SYS_QZS); + break; /* not supported */ + case 1112: + ret = decode_msm0(rtcm, SYS_QZS); + break; /* not supported */ + case 1113: + ret = decode_msm0(rtcm, SYS_QZS); + break; /* not supported */ + case 1114: + ret = decode_msm4(rtcm, SYS_QZS); + break; + case 1115: + ret = decode_msm5(rtcm, SYS_QZS); + break; + case 1116: + ret = decode_msm6(rtcm, SYS_QZS); + break; + case 1117: + ret = decode_msm7(rtcm, SYS_QZS); + break; + case 1121: + ret = decode_msm0(rtcm, SYS_BDS); + break; /* not supported */ + case 1122: + ret = decode_msm0(rtcm, SYS_BDS); + break; /* not supported */ + case 1123: + ret = decode_msm0(rtcm, SYS_BDS); + break; /* not supported */ + case 1124: + ret = decode_msm4(rtcm, SYS_BDS); + break; + case 1125: + ret = decode_msm5(rtcm, SYS_BDS); + break; + case 1126: + ret = decode_msm6(rtcm, SYS_BDS); + break; + case 1127: + ret = decode_msm7(rtcm, SYS_BDS); + break; + case 1230: + ret = decode_type1230(rtcm); + break; /* not supported */ + case 1240: + ret = decode_ssr1(rtcm, SYS_GAL); + break; + case 1241: + ret = decode_ssr2(rtcm, SYS_GAL); + break; + case 1242: + ret = decode_ssr3(rtcm, SYS_GAL); + break; + case 1243: + ret = decode_ssr4(rtcm, SYS_GAL); + break; + case 1244: + ret = decode_ssr5(rtcm, SYS_GAL); + break; + case 1245: + ret = decode_ssr6(rtcm, SYS_GAL); + break; + case 1246: + ret = decode_ssr1(rtcm, SYS_QZS); + break; + case 1247: + ret = decode_ssr2(rtcm, SYS_QZS); + break; + case 1248: + ret = decode_ssr3(rtcm, SYS_QZS); + break; + case 1249: + ret = decode_ssr4(rtcm, SYS_QZS); + break; + case 1250: + ret = decode_ssr5(rtcm, SYS_QZS); + break; + case 1251: + ret = decode_ssr6(rtcm, SYS_QZS); + break; + case 1252: + ret = decode_ssr1(rtcm, SYS_SBS); + break; + case 1253: + ret = decode_ssr2(rtcm, SYS_SBS); + break; + case 1254: + ret = decode_ssr3(rtcm, SYS_SBS); + break; + case 1255: + ret = decode_ssr4(rtcm, SYS_SBS); + break; + case 1256: + ret = decode_ssr5(rtcm, SYS_SBS); + break; + case 1257: + ret = decode_ssr6(rtcm, SYS_SBS); + break; + case 1258: + ret = decode_ssr1(rtcm, SYS_BDS); + break; + case 1259: + ret = decode_ssr2(rtcm, SYS_BDS); + break; + case 1260: + ret = decode_ssr3(rtcm, SYS_BDS); + break; + case 1261: + ret = decode_ssr4(rtcm, SYS_BDS); + break; + case 1262: + ret = decode_ssr5(rtcm, SYS_BDS); + break; + case 1263: + ret = decode_ssr6(rtcm, SYS_BDS); + break; + case 2065: + ret = decode_ssr7(rtcm, SYS_GPS); + break; /* tentative */ + case 2066: + ret = decode_ssr7(rtcm, SYS_GLO); + break; /* tentative */ + case 2067: + ret = decode_ssr7(rtcm, SYS_GAL); + break; /* tentative */ + case 2068: + ret = decode_ssr7(rtcm, SYS_QZS); + break; /* tentative */ + case 2070: + ret = decode_ssr7(rtcm, SYS_BDS); + break; /* tentative */ + } + if (ret >= 0) + { + type -= 1000; + if (1 <= type && type <= 299) + rtcm->nmsg3[type]++; /* 1001-1299 */ + else if (1000 <= type && type <= 1099) + rtcm->nmsg3[type - 700]++; /* 2000-2099 */ + else + rtcm->nmsg3[0]++; + } + return ret; +} diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm3.h b/src/algorithms/libs/rtklib/rtklib_rtcm3.h new file mode 100644 index 000000000..b907f223d --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtcm3.h @@ -0,0 +1,249 @@ +/*! + * \file rtklib_rtcm3.h + * \brief RTCM v3 functions headers + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_RTCM3_H_ +#define GNSS_SDR_RTKLIB_RTCM3_H_ + +#include "rtklib.h" + +/* constants -----------------------------------------------------------------*/ + +const double PRUNIT_GPS = 299792.458; /* rtcm ver.3 unit of gps pseudorange (m) */ +const double PRUNIT_GLO = 599584.916; /* rtcm ver.3 unit of glonass pseudorange (m) */ +const double RANGE_MS = SPEED_OF_LIGHT * 0.001; /* range in 1 ms */ + + +/* ssr update intervals ------------------------------------------------------*/ +const double ssrudint[16] = { + 1, 2, 5, 10, 15, 30, 60, 120, 240, 300, 600, 900, 1800, 3600, 7200, 10800}; + + +/* ssr 3 and 7 signal and tracking mode ids ----------------------------------*/ +const int codes_gps[] = { + CODE_L1C, CODE_L1P, CODE_L1W, CODE_L1Y, CODE_L1M, CODE_L2C, CODE_L2D, CODE_L2S, + CODE_L2L, CODE_L2X, CODE_L2P, CODE_L2W, CODE_L2Y, CODE_L2M, CODE_L5I, CODE_L5Q, + CODE_L5X}; + + +const int codes_glo[] = { + CODE_L1C, CODE_L1P, CODE_L2C, CODE_L2P}; + + +const int codes_gal[] = { + CODE_L1A, CODE_L1B, CODE_L1C, CODE_L1X, CODE_L1Z, CODE_L5I, CODE_L5Q, CODE_L5X, + CODE_L7I, CODE_L7Q, CODE_L7X, CODE_L8I, CODE_L8Q, CODE_L8X, CODE_L6A, CODE_L6B, + CODE_L6C, CODE_L6X, CODE_L6Z}; + + +const int codes_qzs[] = { + CODE_L1C, CODE_L1S, CODE_L1L, CODE_L2S, CODE_L2L, CODE_L2X, CODE_L5I, CODE_L5Q, + CODE_L5X, CODE_L6S, CODE_L6L, CODE_L6X, CODE_L1X}; + + +const int codes_bds[] = { + CODE_L1I, CODE_L1Q, CODE_L1X, CODE_L7I, CODE_L7Q, CODE_L7X, CODE_L6I, CODE_L6Q, + CODE_L6X}; + + +const int codes_sbs[] = { + CODE_L1C, CODE_L5I, CODE_L5Q, CODE_L5X}; + + +double getbitg(const unsigned char *buff, int pos, int len); + +void adjweek(rtcm_t *rtcm, double tow); + +int adjbdtweek(int week); + +void adjday_glot(rtcm_t *rtcm, double tod); + +double adjcp(rtcm_t *rtcm, int sat, int freq, double cp); + +int lossoflock(rtcm_t *rtcm, int sat, int freq, int lock); + +unsigned char snratio(double snr); + +int obsindex3(obs_t *obs, gtime_t time, int sat); + +int test_staid(rtcm_t *rtcm, int staid); + +int decode_head1001(rtcm_t *rtcm, int *sync); + +int decode_type1001(rtcm_t *rtcm); + +int decode_type1002(rtcm_t *rtcm); + +int decode_type1003(rtcm_t *rtcm); + +int decode_type1004(rtcm_t *rtcm); + +double getbits_38(const unsigned char *buff, int pos); + +int decode_type1005(rtcm_t *rtcm); + +int decode_type1006(rtcm_t *rtcm); + +int decode_type1007(rtcm_t *rtcm); + +int decode_type1008(rtcm_t *rtcm); + +int decode_head1009(rtcm_t *rtcm, int *sync); + +int decode_type1009(rtcm_t *rtcm); + +int decode_type1010(rtcm_t *rtcm); + +int decode_type1011(rtcm_t *rtcm); + +int decode_type1012(rtcm_t *rtcm); + +int decode_type1013(rtcm_t *rtcm); + +int decode_type1019(rtcm_t *rtcm); + +int decode_type1020(rtcm_t *rtcm); + +int decode_type1021(rtcm_t *rtcm); + +int decode_type1022(rtcm_t *rtcm); + +int decode_type1023(rtcm_t *rtcm); + +int decode_type1024(rtcm_t *rtcm); + +int decode_type1025(rtcm_t *rtcm); + +int decode_type1026(rtcm_t *rtcm); + +int decode_type1027(rtcm_t *rtcm); + +int decode_type1029(rtcm_t *rtcm); + +int decode_type1030(rtcm_t *rtcm); + +int decode_type1031(rtcm_t *rtcm); + +int decode_type1032(rtcm_t *rtcm); + +int decode_type1033(rtcm_t *rtcm); + +int decode_type1034(rtcm_t *rtcm); + +int decode_type1035(rtcm_t *rtcm); + +int decode_type1037(rtcm_t *rtcm); + +int decode_type1038(rtcm_t *rtcm); + +int decode_type1039(rtcm_t *rtcm); + +int decode_type1044(rtcm_t *rtcm); + +int decode_type1045(rtcm_t *rtcm); + +int decode_type1046(rtcm_t *rtcm); + +int decode_type1047(rtcm_t *rtcm); + +int decode_type1063(rtcm_t *rtcm); + +int decode_ssr1_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *refd, int *hsize); + +int decode_ssr2_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *hsize); + +int decode_ssr7_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + double *udint, int *dispe, int *mw, int *hsize); + +int decode_ssr1(rtcm_t *rtcm, int sys); + +int decode_ssr2(rtcm_t *rtcm, int sys); + +int decode_ssr3(rtcm_t *rtcm, int sys); + +int decode_ssr4(rtcm_t *rtcm, int sys); + +int decode_ssr5(rtcm_t *rtcm, int sys); + +int decode_ssr6(rtcm_t *rtcm, int sys); + +int decode_ssr7(rtcm_t *rtcm, int sys); + +void sigindex(int sys, const unsigned char *code, const int *freq, int n, + const char *opt, int *ind); + +void save_msm_obs(rtcm_t *rtcm, int sys, msm_h_t *h, const double *r, + const double *pr, const double *cp, const double *rr, + const double *rrf, const double *cnr, const int *lock, + const int *ex, const int *half); + +int decode_msm_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + msm_h_t *h, int *hsize); + +int decode_msm0(rtcm_t *rtcm, int sys); + +int decode_msm4(rtcm_t *rtcm, int sys); + +int decode_msm5(rtcm_t *rtcm, int sys); + +int decode_msm6(rtcm_t *rtcm, int sys); + +int decode_msm7(rtcm_t *rtcm, int sys); + +int decode_type1230(rtcm_t *rtcm); + +int decode_rtcm3(rtcm_t *rtcm); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc b/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc new file mode 100644 index 000000000..9eea3a0b2 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc @@ -0,0 +1,4401 @@ +/*! + * \file rtklib_rtkcmn.cc + * \brief rtklib common functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_rtkcmn.h" +//#include +#include +#include +#include +#include +#include +#include +#include + + +const double gpst0[] = {1980, 1, 6, 0, 0, 0}; /* gps time reference */ +const double gst0[] = {1999, 8, 22, 0, 0, 0}; /* galileo system time reference */ +const double bdt0[] = {2006, 1, 1, 0, 0, 0}; /* beidou time reference */ + +static double timeoffset_ = 0.0; + +double leaps[MAXLEAPS + 1][7] = {/* leap seconds (y,m,d,h,m,s,utc-gpst) */ + {2017, 1, 1, 0, 0, 0, -18}, + {2015, 7, 1, 0, 0, 0, -17}, + {2012, 7, 1, 0, 0, 0, -16}, + {2009, 1, 1, 0, 0, 0, -15}, + {2006, 1, 1, 0, 0, 0, -14}, + {1999, 1, 1, 0, 0, 0, -13}, + {1997, 7, 1, 0, 0, 0, -12}, + {1996, 1, 1, 0, 0, 0, -11}, + {1994, 7, 1, 0, 0, 0, -10}, + {1993, 7, 1, 0, 0, 0, -9}, + {1992, 7, 1, 0, 0, 0, -8}, + {1991, 1, 1, 0, 0, 0, -7}, + {1990, 1, 1, 0, 0, 0, -6}, + {1988, 1, 1, 0, 0, 0, -5}, + {1985, 7, 1, 0, 0, 0, -4}, + {1983, 7, 1, 0, 0, 0, -3}, + {1982, 7, 1, 0, 0, 0, -2}, + {1981, 7, 1, 0, 0, 0, -1}, + {}}; + + +const char *formatstrs[32] = {/* stream format strings */ + "RTCM 2", /* 0 */ + "RTCM 3", /* 1 */ + "NovAtel OEM6", /* 2 */ + "NovAtel OEM3", /* 3 */ + "u-blox", /* 4 */ + "Superstar II", /* 5 */ + "Hemisphere", /* 6 */ + "SkyTraq", /* 7 */ + "GW10", /* 8 */ + "Javad", /* 9 */ + "NVS BINR", /* 10 */ + "BINEX", /* 11 */ + "Trimble RT17", /* 12 */ + "Septentrio", /* 13 */ + "CMR/CMR+", /* 14 */ + "LEX Receiver", /* 15 */ + "RINEX", /* 16 */ + "SP3", /* 17 */ + "RINEX CLK", /* 18 */ + "SBAS", /* 19 */ + "NMEA 0183", /* 20 */ + nullptr}; + + +char obscodes[][3] = { + /* observation code strings */ + "", "1C", "1P", "1W", "1Y", "1M", "1N", "1S", "1L", "1E", /* 0- 9 */ + "1A", "1B", "1X", "1Z", "2C", "2D", "2S", "2L", "2X", "2P", /* 10-19 */ + "2W", "2Y", "2M", "2N", "5I", "5Q", "5X", "7I", "7Q", "7X", /* 20-29 */ + "6A", "6B", "6C", "6X", "6Z", "6S", "6L", "8L", "8Q", "8X", /* 30-39 */ + "2I", "2Q", "6I", "6Q", "3I", "3Q", "3X", "1I", "1Q", "5A", /* 40-49 */ + "5B", "5C", "9A", "9B", "9C", "9X", "", "", "", "" /* 50-59 */ +}; + + +unsigned char obsfreqs[] = { + /* 1:L1/E1, 2:L2/B1, 3:L5/E5a/L3, 4:L6/LEX/B3, 5:E5b/B2, 6:E5(a+b), 7:S */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0- 9 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, /* 10-19 */ + 2, 2, 2, 2, 3, 3, 3, 5, 5, 5, /* 20-29 */ + 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, /* 30-39 */ + 2, 2, 4, 4, 3, 3, 3, 1, 1, 3, /* 40-49 */ + 3, 3, 7, 7, 7, 7, 0, 0, 0, 0 /* 50-59 */ +}; + + +char codepris[7][MAXFREQ][16] = { + /* code priority table */ + + /* L1/E1 L2/B1 L5/E5a/L3 L6/LEX/B3 E5b/B2 E5(a+b) S */ + {"CPYWMNSL", "PYWCMNDSLX", "IQX", "", "", "", ""}, /* GPS */ + {"PC", "PC", "IQX", "", "", "", ""}, /* GLO */ + {"CABXZ", "", "IQX", "ABCXZ", "IQX", "IQX", ""}, /* GAL */ + {"CSLXZ", "SLX", "IQX", "SLX", "", "", ""}, /* QZS */ + {"C", "", "IQX", "", "", "", ""}, /* SBS */ + {"IQX", "IQX", "IQX", "IQX", "IQX", "", ""}, /* BDS */ + {"", "", "ABCX", "", "", "", "ABCX"} /* IRN */ +}; + + +fatalfunc_t *fatalfunc = nullptr; /* fatal callback function */ + +/* crc tables generated by util/gencrc ---------------------------------------*/ +const uint16_t tbl_CRC16[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; + + +const unsigned int tbl_CRC24Q[] = { + 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC, 0x9F7F17, + 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5, 0x3EFE2E, + 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65, 0x5A319E, + 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C, 0xFBB0A7, + 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, 0x93AEFE, + 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, 0x322FC7, + 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, 0x56E077, + 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5, 0xF7614E, + 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E, 0x86DCC5, + 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107, 0x275DFC, + 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7, 0x43924C, + 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, 0xE21375, + 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, 0x8A0D2C, + 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, 0x2B8C15, + 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E, 0x4F43A5, + 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67, 0xEEC29C, + 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448, 0xAC38B3, + 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571, 0x0DB98A, + 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, 0x69763A, + 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, 0xC8F703, + 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, 0xA0E95A, + 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498, 0x016863, + 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28, 0x65A7D3, + 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11, 0xC426EA, + 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A, 0xB59B61, + 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, 0x141A58, + 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, 0x70D5E8, + 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, 0xD154D1, + 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673, 0xB94A88, + 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A, 0x18CBB1, + 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA, 0x7C0401, + 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3, 0xDD8538}; + + +extern "C" +{ + void dgemm_(char *, char *, int *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *); + extern void dgetrf_(int *, int *, double *, int *, int *, int *); + extern void dgetri_(int *, double *, int *, int *, double *, int *, int *); + extern void dgetrs_(char *, int *, int *, double *, int *, int *, double *, int *, int *); +} + + +/* function prototypes -------------------------------------------------------*/ + + +#ifdef IERS_MODEL +extern int gmf_(double *mjd, double *lat, double *lon, double *hgt, double *zd, + double *gmfh, double *gmfw); +#endif + + +/* fatal error ---------------------------------------------------------------*/ +void fatalerr(const char *format, ...) +{ + char msg[1024]; + va_list ap; + va_start(ap, format); + vsprintf(msg, format, ap); + va_end(ap); + fprintf(stderr, "%s", msg); + exit(-9); +} + + +/* satellite system+prn/slot number to satellite number ------------------------ + * convert satellite system+prn/slot number to satellite number + * args : int sys I satellite system (SYS_GPS,SYS_GLO,...) + * int prn I satellite prn/slot number + * return : satellite number (0:error) + *-----------------------------------------------------------------------------*/ +int satno(int sys, int prn) +{ + if (prn <= 0) return 0; + switch (sys) + { + case SYS_GPS: + if (prn < MINPRNGPS || MAXPRNGPS < prn) return 0; + return prn - MINPRNGPS + 1; + case SYS_GLO: + if (prn < MINPRNGLO || MAXPRNGLO < prn) return 0; + return NSATGPS + prn - MINPRNGLO + 1; + case SYS_GAL: + if (prn < MINPRNGAL || MAXPRNGAL < prn) return 0; + return NSATGPS + NSATGLO + prn - MINPRNGAL + 1; + case SYS_QZS: + if (prn < MINPRNQZS || MAXPRNQZS < prn) return 0; + return NSATGPS + NSATGLO + NSATGAL + prn - MINPRNQZS + 1; + case SYS_BDS: + if (prn < MINPRNBDS || MAXPRNBDS < prn) return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + prn - MINPRNBDS + 1; + case SYS_IRN: + if (prn < MINPRNIRN || MAXPRNIRN < prn) return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATBDS + prn - MINPRNIRN + 1; + case SYS_LEO: + if (prn < MINPRNLEO || MAXPRNLEO < prn) return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATBDS + NSATIRN + + prn - MINPRNLEO + 1; + case SYS_SBS: + if (prn < MINPRNSBS || MAXPRNSBS < prn) return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATBDS + NSATIRN + NSATLEO + + prn - MINPRNSBS + 1; + } + return 0; +} + + +/* satellite number to satellite system ---------------------------------------- + * convert satellite number to satellite system + * args : int sat I satellite number (1-MAXSAT) + * int *prn IO satellite prn/slot number (NULL: no output) + * return : satellite system (SYS_GPS,SYS_GLO,...) + *-----------------------------------------------------------------------------*/ +int satsys(int sat, int *prn) +{ + int sys = SYS_NONE; + if (sat <= 0 || MAXSAT < sat) + sat = 0; + else if (sat <= NSATGPS) + { + sys = SYS_GPS; + sat += MINPRNGPS - 1; + } + else if ((sat -= NSATGPS) <= NSATGLO) + { + sys = SYS_GLO; + sat += MINPRNGLO - 1; + } + else if ((sat -= NSATGLO) <= NSATGAL) + { + sys = SYS_GAL; + sat += MINPRNGAL - 1; + } + else if ((sat -= NSATGAL) <= NSATQZS) + { + sys = SYS_QZS; + sat += MINPRNQZS - 1; + } + else if ((sat -= NSATQZS) <= NSATBDS) + { + sys = SYS_BDS; + sat += MINPRNBDS - 1; + } + else if ((sat -= NSATBDS) <= NSATIRN) + { + sys = SYS_IRN; + sat += MINPRNIRN - 1; + } + else if ((sat -= NSATIRN) <= NSATLEO) + { + sys = SYS_LEO; + sat += MINPRNLEO - 1; + } + else if ((sat -= NSATLEO) <= NSATSBS) + { + sys = SYS_SBS; + sat += MINPRNSBS - 1; + } + else + sat = 0; + if (prn) *prn = sat; + return sys; +} + + +/* satellite id to satellite number -------------------------------------------- + * convert satellite id to satellite number + * args : char *id I satellite id (nn,Gnn,Rnn,Enn,Jnn,Cnn,Inn or Snn) + * return : satellite number (0: error) + * notes : 120-142 and 193-199 are also recognized as sbas and qzss + *-----------------------------------------------------------------------------*/ +int satid2no(const char *id) +{ + int sys, prn; + char code; + + if (sscanf(id, "%d", &prn) == 1) + { + if (MINPRNGPS <= prn && prn <= MAXPRNGPS) + sys = SYS_GPS; + else if (MINPRNSBS <= prn && prn <= MAXPRNSBS) + sys = SYS_SBS; + else if (MINPRNQZS <= prn && prn <= MAXPRNQZS) + sys = SYS_QZS; + else + return 0; + return satno(sys, prn); + } + if (sscanf(id, "%c%d", &code, &prn) < 2) return 0; + + switch (code) + { + case 'G': + sys = SYS_GPS; + prn += MINPRNGPS - 1; + break; + case 'R': + sys = SYS_GLO; + prn += MINPRNGLO - 1; + break; + case 'E': + sys = SYS_GAL; + prn += MINPRNGAL - 1; + break; + case 'J': + sys = SYS_QZS; + prn += MINPRNQZS - 1; + break; + case 'C': + sys = SYS_BDS; + prn += MINPRNBDS - 1; + break; + case 'I': + sys = SYS_IRN; + prn += MINPRNIRN - 1; + break; + case 'L': + sys = SYS_LEO; + prn += MINPRNLEO - 1; + break; + case 'S': + sys = SYS_SBS; + prn += 100; + break; + default: + return 0; + } + return satno(sys, prn); +} + + +/* satellite number to satellite id -------------------------------------------- + * convert satellite number to satellite id + * args : int sat I satellite number + * char *id O satellite id (Gnn,Rnn,Enn,Jnn,Cnn,Inn or nnn) + * return : none + *-----------------------------------------------------------------------------*/ +void satno2id(int sat, char *id) +{ + int prn; + switch (satsys(sat, &prn)) + { + case SYS_GPS: + sprintf(id, "G%02d", prn - MINPRNGPS + 1); + return; + case SYS_GLO: + sprintf(id, "R%02d", prn - MINPRNGLO + 1); + return; + case SYS_GAL: + sprintf(id, "E%02d", prn - MINPRNGAL + 1); + return; + case SYS_QZS: + sprintf(id, "J%02d", prn - MINPRNQZS + 1); + return; + case SYS_BDS: + sprintf(id, "C%02d", prn - MINPRNBDS + 1); + return; + case SYS_IRN: + sprintf(id, "I%02d", prn - MINPRNIRN + 1); + return; + case SYS_LEO: + sprintf(id, "L%02d", prn - MINPRNLEO + 1); + return; + case SYS_SBS: + sprintf(id, "%03d", prn); + return; + } + strcpy(id, ""); +} + + +/* test excluded satellite ----------------------------------------------------- + * test excluded satellite + * args : int sat I satellite number + * int svh I sv health flag + * prcopt_t *opt I processing options (NULL: not used) + * return : status (1:excluded,0:not excluded) + *-----------------------------------------------------------------------------*/ +int satexclude(int sat, int svh, const prcopt_t *opt) +{ + int sys = satsys(sat, nullptr); + + if (svh < 0) + { + trace(3, "ephemeris unavailable: sat=%3d svh=%02X\n", sat, svh); + return 1; /* ephemeris unavailable */ + } + + if (opt) + { + if (opt->exsats[sat - 1] == 1) + { + trace(3, "excluded satellite: sat=%3d svh=%02X\n", sat, svh); + return 1; /* excluded satellite */ + } + if (opt->exsats[sat - 1] == 2) return 0; /* included satellite */ + if (!(sys & opt->navsys)) + { + trace(3, "unselected sat sys: sat=%3d svh=%02X\n", sat, svh); + return 1; /* unselected sat sys */ + } + } + if (sys == SYS_QZS) svh &= 0xFE; /* mask QZSS LEX health */ + if (svh) + { + trace(3, "unhealthy satellite: sat=%3d svh=%02X\n", sat, svh); + return 1; + } + return 0; +} + + +/* test SNR mask --------------------------------------------------------------- + * test SNR mask + * args : int base I rover or base-station (0:rover,1:base station) + * int freq I frequency (0:L1,1:L2,2:L3,...) + * double el I elevation angle (rad) + * double snr I C/N0 (dBHz) + * snrmask_t *mask I SNR mask + * return : status (1:masked,0:unmasked) + *-----------------------------------------------------------------------------*/ +int testsnr(int base, int freq, double el, double snr, + const snrmask_t *mask) +{ + double minsnr, a; + int i; + + if (!mask->ena[base] || freq < 0 || freq >= NFREQ) return 0; + + a = (el * R2D + 5.0) / 10.0; + i = static_cast(floor(a)); + a -= i; + if (i < 1) + minsnr = mask->mask[freq][0]; + else if (i > 8) + minsnr = mask->mask[freq][8]; + else + minsnr = (1.0 - a) * mask->mask[freq][i - 1] + a * mask->mask[freq][i]; + + return snr < minsnr; +} + + +/* obs type string to obs code ------------------------------------------------- + * convert obs code type string to obs code + * args : char *str I obs code string ("1C","1P","1Y",...) + * int *freq IO frequency (1:L1,2:L2,3:L5,4:L6,5:L7,6:L8,0:err) + * (NULL: no output) + * return : obs code (CODE_???) + * notes : obs codes are based on reference [6] and qzss extension + *-----------------------------------------------------------------------------*/ +unsigned char obs2code(const char *obs, int *freq) +{ + int i; + if (freq) *freq = 0; + for (i = 1; *obscodes[i]; i++) + { + if (strcmp(obscodes[i], obs) != 0) continue; + if (freq) *freq = obsfreqs[i]; + return static_cast(i); + } + return CODE_NONE; +} + + +/* obs code to obs code string ------------------------------------------------- + * convert obs code to obs code string + * args : unsigned char code I obs code (CODE_???) + * int *freq IO frequency (NULL: no output) + * (1:L1/E1, 2:L2/B1, 3:L5/E5a/L3, 4:L6/LEX/B3, + 5:E5b/B2, 6:E5(a+b), 7:S) + * return : obs code string ("1C","1P","1P",...) + * notes : obs codes are based on reference [6] and qzss extension + *-----------------------------------------------------------------------------*/ +char *code2obs(unsigned char code, int *freq) +{ + if (freq) *freq = 0; + if (code <= CODE_NONE || MAXCODE < code) return (char *)""; + if (freq) *freq = obsfreqs[code]; + return obscodes[code]; +} + + +/* set code priority ----------------------------------------------------------- + * set code priority for multiple codes in a frequency + * args : int sys I system (or of SYS_???) + * int freq I frequency (1:L1,2:L2,3:L5,4:L6,5:L7,6:L8,7:L9) + * char *pri I priority of codes (series of code characters) + * (higher priority precedes lower) + * return : none + *-----------------------------------------------------------------------------*/ +void setcodepri(int sys, int freq, const char *pri) +{ + trace(3, "setcodepri : sys=%d freq=%d pri=%s\n", sys, freq, pri); + + if (freq <= 0 || MAXFREQ < freq) return; + if (strlen(pri) < 17) + { + if (sys & SYS_GPS) strcpy(codepris[0][freq - 1], pri); + if (sys & SYS_GLO) strcpy(codepris[1][freq - 1], pri); + if (sys & SYS_GAL) strcpy(codepris[2][freq - 1], pri); + if (sys & SYS_QZS) strcpy(codepris[3][freq - 1], pri); + if (sys & SYS_SBS) strcpy(codepris[4][freq - 1], pri); + if (sys & SYS_BDS) strcpy(codepris[5][freq - 1], pri); + if (sys & SYS_IRN) strcpy(codepris[6][freq - 1], pri); + } + else + { + trace(1, "pri array is too long"); + } +} + + +/* get code priority ----------------------------------------------------------- + * get code priority for multiple codes in a frequency + * args : int sys I system (SYS_???) + * unsigned char code I obs code (CODE_???) + * char *opt I code options (NULL:no option) + * return : priority (15:highest-1:lowest,0:error) + *-----------------------------------------------------------------------------*/ +int getcodepri(int sys, unsigned char code, const char *opt) +{ + const char *p, *optstr; + char *obs, str[8] = ""; + int i, j; + + switch (sys) + { + case SYS_GPS: + i = 0; + optstr = "-GL%2s"; + break; + case SYS_GLO: + i = 1; + optstr = "-RL%2s"; + break; + case SYS_GAL: + i = 2; + optstr = "-EL%2s"; + break; + case SYS_QZS: + i = 3; + optstr = "-JL%2s"; + break; + case SYS_SBS: + i = 4; + optstr = "-SL%2s"; + break; + case SYS_BDS: + i = 5; + optstr = "-CL%2s"; + break; + case SYS_IRN: + i = 6; + optstr = "-IL%2s"; + break; + default: + return 0; + } + obs = code2obs(code, &j); + + /* parse code options */ + for (p = opt; p && (p = strchr(p, '-')); p++) + { + if (sscanf(p, optstr, str) < 1 || str[0] != obs[0]) continue; + return str[1] == obs[1] ? 15 : 0; + } + /* search code priority */ + return (p = strchr(codepris[i][j - 1], obs[1])) ? 14 - static_cast(p - codepris[i][j - 1]) : 0; +} + + +/* extract unsigned/signed bits ------------------------------------------------ + * extract unsigned/signed bits from byte data + * args : unsigned char *buff I byte data + * int pos I bit position from start of data (bits) + * int len I bit length (bits) (len <= 32) + * return : extracted unsigned/signed bits + *-----------------------------------------------------------------------------*/ +unsigned int getbitu(const unsigned char *buff, int pos, int len) +{ + unsigned int bits = 0; + int i; + for (i = pos; i < pos + len; i++) bits = (bits << 1) + ((buff[i / 8] >> (7 - i % 8)) & 1u); + return bits; +} + + +int getbits(const unsigned char *buff, int pos, int len) +{ + unsigned int bits = getbitu(buff, pos, len); + if (len <= 0 || 32 <= len || !(bits & (1u << (len - 1)))) return static_cast(bits); + return static_cast(bits | (~0u << len)); /* extend sign */ +} + + +/* set unsigned/signed bits ---------------------------------------------------- + * set unsigned/signed bits to byte data + * args : unsigned char *buff IO byte data + * int pos I bit position from start of data (bits) + * int len I bit length (bits) (len <= 32) + * (unsigned) int I unsigned/signed data + * return : none + *-----------------------------------------------------------------------------*/ +void setbitu(unsigned char *buff, int pos, int len, unsigned int data) +{ + unsigned int mask = 1u << (len - 1); + int i; + if (len <= 0 || 32 < len) return; + for (i = pos; i < pos + len; i++, mask >>= 1) + { + if (data & mask) + buff[i / 8] |= 1u << (7 - i % 8); + else + buff[i / 8] &= ~(1u << (7 - i % 8)); + } +} + + +void setbits(unsigned char *buff, int pos, int len, int data) +{ + if (data < 0) + data |= 1 << (len - 1); + else + data &= ~(1 << (len - 1)); /* set sign bit */ + setbitu(buff, pos, len, static_cast(data)); +} + + +/* crc-32 parity --------------------------------------------------------------- + * compute crc-32 parity for novatel raw + * args : unsigned char *buff I data + * int len I data length (bytes) + * return : crc-32 parity + * notes : see NovAtel OEMV firmware manual 1.7 32-bit CRC + *-----------------------------------------------------------------------------*/ +unsigned int rtk_crc32(const unsigned char *buff, int len) +{ + unsigned int crc = 0; + int i, j; + + trace(4, "rtk_crc32: len=%d\n", len); + + for (i = 0; i < len; i++) + { + crc ^= buff[i]; + for (j = 0; j < 8; j++) + { + if (crc & 1) + crc = (crc >> 1) ^ POLYCRC32; + else + crc >>= 1; + } + } + return crc; +} + + +/* crc-24q parity -------------------------------------------------------------- + * compute crc-24q parity for sbas, rtcm3 + * args : unsigned char *buff I data + * int len I data length (bytes) + * return : crc-24Q parity + * notes : see reference [2] A.4.3.3 Parity + *-----------------------------------------------------------------------------*/ +unsigned int rtk_crc24q(const unsigned char *buff, int len) +{ + unsigned int crc = 0; + int i; + + trace(4, "rtk_crc24q: len=%d\n", len); + + for (i = 0; i < len; i++) crc = ((crc << 8) & 0xFFFFFF) ^ tbl_CRC24Q[(crc >> 16) ^ buff[i]]; + return crc; +} + + +/* crc-16 parity --------------------------------------------------------------- + * compute crc-16 parity for binex, nvs + * args : unsigned char *buff I data + * int len I data length (bytes) + * return : crc-16 parity + * notes : see reference [10] A.3. + *-----------------------------------------------------------------------------*/ +uint16_t rtk_crc16(const unsigned char *buff, int len) +{ + uint16_t crc = 0; + int i; + + trace(4, "rtk_crc16: len=%d\n", len); + + for (i = 0; i < len; i++) + { + crc = (crc << 8) ^ tbl_CRC16[((crc >> 8) ^ buff[i]) & 0xFF]; + } + return crc; +} + + +/* decode navigation data word ------------------------------------------------- + * check party and decode navigation data word + * args : unsigned int word I navigation data word (2+30bit) + * (previous word D29*-30* + current word D1-30) + * unsigned char *data O decoded navigation data without parity + * (8bitx3) + * return : status (1:ok,0:parity error) + * notes : see reference [1] 20.3.5.2 user parity algorithm + *-----------------------------------------------------------------------------*/ +int decode_word(unsigned int word, unsigned char *data) +{ + const unsigned int hamming[] = { + 0xBB1F3480, 0x5D8F9A40, 0xAEC7CD00, 0x5763E680, 0x6BB1F340, 0x8B7A89C0}; + unsigned int parity = 0, w; + int i; + + trace(5, "decodeword: word=%08x\n", word); + + if (word & 0x40000000) word ^= 0x3FFFFFC0; + + for (i = 0; i < 6; i++) + { + parity <<= 1; + for (w = (word & hamming[i]) >> 6; w; w >>= 1) parity ^= w & 1; + } + if (parity != (word & 0x3F)) return 0; + + for (i = 0; i < 3; i++) data[i] = static_cast(word >> (22 - i * 8)); + return 1; +} + + +/* new matrix ------------------------------------------------------------------ + * allocate memory of matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n<=0 or m<=0, return NULL) + *-----------------------------------------------------------------------------*/ +double *mat(int n, int m) +{ + double *p; + + if (n <= 0 || m <= 0) return nullptr; + if (!(p = static_cast(malloc(sizeof(double) * n * m)))) + { + fatalerr("matrix memory allocation error: n=%d,m=%d\n", n, m); + } + return p; +} + + +/* new integer matrix ---------------------------------------------------------- + * allocate memory of integer matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n <= 0 or m <= 0, return NULL) + *-----------------------------------------------------------------------------*/ +int *imat(int n, int m) +{ + int *p; + + if (n <= 0 || m <= 0) return nullptr; + if (!(p = static_cast(malloc(sizeof(int) * n * m)))) + { + fatalerr("integer matrix memory allocation error: n=%d,m=%d\n", n, m); + } + return p; +} + + +/* zero matrix ----------------------------------------------------------------- + * generate new zero matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n <= 0 or m <= 0, return NULL) + *-----------------------------------------------------------------------------*/ +double *zeros(int n, int m) +{ + double *p; + +#if NOCALLOC + if ((p = mat(n, m))) + for (n = n * m - 1; n >= 0; n--) p[n] = 0.0; +#else + if (n <= 0 || m <= 0) return nullptr; + if (!(p = static_cast(calloc(sizeof(double), n * m)))) + { + fatalerr("matrix memory allocation error: n=%d,m=%d\n", n, m); + } +#endif + return p; +} + + +/* identity matrix ------------------------------------------------------------- + * generate new identity matrix + * args : int n I number of rows and columns of matrix + * return : matrix pointer (if n <= 0, return NULL) + *-----------------------------------------------------------------------------*/ +double *eye(int n) +{ + double *p; + int i; + + if ((p = zeros(n, n))) + for (i = 0; i < n; i++) p[i + i * n] = 1.0; + return p; +} + + +/* inner product --------------------------------------------------------------- + * inner product of vectors + * args : double *a,*b I vector a,b (n x 1) + * int n I size of vector a,b + * return : a'*b + *-----------------------------------------------------------------------------*/ +double dot(const double *a, const double *b, int n) +{ + double c = 0.0; + + while (--n >= 0) c += a[n] * b[n]; + return c; +} + + +/* euclid norm ----------------------------------------------------------------- + * euclid norm of vector + * args : double *a I vector a (n x 1) + * int n I size of vector a + * return : || a || + *-----------------------------------------------------------------------------*/ +double norm_rtk(const double *a, int n) +{ + return std::sqrt(dot(a, a, n)); +} + + +/* outer product of 3d vectors ------------------------------------------------- + * outer product of 3d vectors + * args : double *a,*b I vector a,b (3 x 1) + * double *c O outer product (a x b) (3 x 1) + * return : none + *-----------------------------------------------------------------------------*/ +void cross3(const double *a, const double *b, double *c) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} + + +/* normalize 3d vector --------------------------------------------------------- + * normalize 3d vector + * args : double *a I vector a (3 x 1) + * double *b O normlized vector (3 x 1) || b || = 1 + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int normv3(const double *a, double *b) +{ + double r; + if ((r = norm_rtk(a, 3)) <= 0.0) return 0; + b[0] = a[0] / r; + b[1] = a[1] / r; + b[2] = a[2] / r; + return 1; +} + + +/* copy matrix ----------------------------------------------------------------- + * copy matrix + * args : double *A O destination matrix A (n x m) + * double *B I source matrix B (n x m) + * int n,m I number of rows and columns of matrix + * return : none + *-----------------------------------------------------------------------------*/ +void matcpy(double *A, const double *B, int n, int m) +{ + memcpy(A, B, sizeof(double) * n * m); +} + +/* matrix routines -----------------------------------------------------------*/ + + +/* multiply matrix (wrapper of blas dgemm) ------------------------------------- + * multiply matrix by matrix (C=alpha*A*B+beta*C) + * args : char *tr I transpose flags ("N":normal,"T":transpose) + * int n,k,m I size of (transposed) matrix A,B + * double alpha I alpha + * double *A,*B I (transposed) matrix A (n x m), B (m x k) + * double beta I beta + * double *C IO matrix C (n x k) + * return : none + *-----------------------------------------------------------------------------*/ +void matmul(const char *tr, int n, int k, int m, double alpha, + const double *A, const double *B, double beta, double *C) +{ + int lda = tr[0] == 'T' ? m : n, ldb = tr[1] == 'T' ? k : m; + + dgemm_(const_cast(tr), const_cast(tr) + 1, &n, &k, &m, &alpha, const_cast(A), &lda, const_cast(B), + &ldb, &beta, C, &n); +} + + +/* inverse of matrix ----------------------------------------------------------- + * inverse of matrix (A=A^-1) + * args : double *A IO matrix (n x n) + * int n I size of matrix A + * return : status (0:ok,0>:error) + *-----------------------------------------------------------------------------*/ +int matinv(double *A, int n) +{ + double *work; + int info, lwork = n * 16, *ipiv = imat(n, 1); + + work = mat(lwork, 1); + dgetrf_(&n, &n, A, &n, ipiv, &info); + if (!info) dgetri_(&n, A, &n, ipiv, work, &lwork, &info); + free(ipiv); + free(work); + return info; +} + + +/* solve linear equation ------------------------------------------------------- + * solve linear equation (X=A\Y or X=A'\Y) + * args : char *tr I transpose flag ("N":normal,"T":transpose) + * double *A I input matrix A (n x n) + * double *Y I input matrix Y (n x m) + * int n,m I size of matrix A,Y + * double *X O X=A\Y or X=A'\Y (n x m) + * return : status (0:ok,0>:error) + * notes : matirix stored by column-major order (fortran convention) + * X can be same as Y + *-----------------------------------------------------------------------------*/ +int solve(const char *tr, const double *A, const double *Y, int n, + int m, double *X) +{ + double *B = mat(n, n); + int info, *ipiv = imat(n, 1); + + matcpy(B, A, n, n); + matcpy(X, Y, n, m); + dgetrf_(&n, &n, B, &n, ipiv, &info); + if (!info) dgetrs_(const_cast(tr), &n, &m, B, &n, ipiv, X, &n, &info); + free(ipiv); + free(B); + return info; +} + + +/* end of matrix routines ----------------------------------------------------*/ + +/* least square estimation ----------------------------------------------------- + * least square estimation by solving normal equation (x=(A*A')^-1*A*y) + * args : double *A I transpose of (weighted) design matrix (n x m) + * double *y I (weighted) measurements (m x 1) + * int n,m I number of parameters and measurements (n <= m) + * double *x O estmated parameters (n x 1) + * double *Q O esimated parameters covariance matrix (n x n) + * return : status (0:ok,0>:error) + * notes : for weighted least square, replace A and y by A*w and w*y (w=W^(1/2)) + * matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +int lsq(const double *A, const double *y, int n, int m, double *x, + double *Q) +{ + double *Ay; + int info; + + if (m < n) return -1; + Ay = mat(n, 1); + matmul("NN", n, 1, m, 1.0, A, y, 0.0, Ay); /* Ay=A*y */ + matmul("NT", n, n, m, 1.0, A, A, 0.0, Q); /* Q=A*A' */ + if (!(info = matinv(Q, n))) matmul("NN", n, 1, n, 1.0, Q, Ay, 0.0, x); /* x=Q^-1*Ay */ + free(Ay); + return info; +} + + +/* kalman filter --------------------------------------------------------------- + * kalman filter state update as follows: + * + * K=P*H*(H'*P*H+R)^-1, xp=x+K*v, Pp=(I-K*H')*P + * + * args : double *x I states vector (n x 1) + * double *P I covariance matrix of states (n x n) + * double *H I transpose of design matrix (n x m) + * double *v I innovation (measurement - model) (m x 1) + * double *R I covariance matrix of measurement error (m x m) + * int n,m I number of states and measurements + * double *xp O states vector after update (n x 1) + * double *Pp O covariance matrix of states after update (n x n) + * return : status (0:ok,<0:error) + * notes : matirix stored by column-major order (fortran convention) + * if state x[i]==0.0, not updates state x[i]/P[i+i*n] + *-----------------------------------------------------------------------------*/ +int filter_(const double *x, const double *P, const double *H, + const double *v, const double *R, int n, int m, + double *xp, double *Pp) +{ + double *F = mat(n, m), *Q = mat(m, m), *K = mat(n, m), *I = eye(n); + int info; + + matcpy(Q, R, m, m); + matcpy(xp, x, n, 1); + matmul("NN", n, m, n, 1.0, P, H, 0.0, F); /* Q=H'*P*H+R */ + matmul("TN", m, m, n, 1.0, H, F, 1.0, Q); + if (!(info = matinv(Q, m))) + { + matmul("NN", n, m, m, 1.0, F, Q, 0.0, K); /* K=P*H*Q^-1 */ + matmul("NN", n, 1, m, 1.0, K, v, 1.0, xp); /* xp=x+K*v */ + matmul("NT", n, n, m, -1.0, K, H, 1.0, I); /* Pp=(I-K*H')*P */ + matmul("NN", n, n, n, 1.0, I, P, 0.0, Pp); + } + free(F); + free(Q); + free(K); + free(I); + return info; +} + + +int filter(double *x, double *P, const double *H, const double *v, + const double *R, int n, int m) +{ + double *x_, *xp_, *P_, *Pp_, *H_; + int i, j, k, info, *ix; + + ix = imat(n, 1); + for (i = k = 0; i < n; i++) + if (x[i] != 0.0 && P[i + i * n] > 0.0) ix[k++] = i; + x_ = mat(k, 1); + xp_ = mat(k, 1); + P_ = mat(k, k); + Pp_ = mat(k, k); + H_ = mat(k, m); + for (i = 0; i < k; i++) + { + x_[i] = x[ix[i]]; + for (j = 0; j < k; j++) P_[i + j * k] = P[ix[i] + ix[j] * n]; + for (j = 0; j < m; j++) H_[i + j * k] = H[ix[i] + j * n]; + } + info = filter_(x_, P_, H_, v, R, k, m, xp_, Pp_); + for (i = 0; i < k; i++) + { + x[ix[i]] = xp_[i]; + for (j = 0; j < k; j++) P[ix[i] + ix[j] * n] = Pp_[i + j * k]; + } + free(ix); + free(x_); + free(xp_); + free(P_); + free(Pp_); + free(H_); + return info; +} + + +/* smoother -------------------------------------------------------------------- + * combine forward and backward filters by fixed-interval smoother as follows: + * + * xs=Qs*(Qf^-1*xf+Qb^-1*xb), Qs=(Qf^-1+Qb^-1)^-1) + * + * args : double *xf I forward solutions (n x 1) + * args : double *Qf I forward solutions covariance matrix (n x n) + * double *xb I backward solutions (n x 1) + * double *Qb I backward solutions covariance matrix (n x n) + * int n I number of solutions + * double *xs O smoothed solutions (n x 1) + * double *Qs O smoothed solutions covariance matrix (n x n) + * return : status (0:ok,0>:error) + * notes : see reference [4] 5.2 + * matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +int smoother(const double *xf, const double *Qf, const double *xb, + const double *Qb, int n, double *xs, double *Qs) +{ + double *invQf = mat(n, n), *invQb = mat(n, n), *xx = mat(n, 1); + int i, info = -1; + + matcpy(invQf, Qf, n, n); + matcpy(invQb, Qb, n, n); + if (!matinv(invQf, n) && !matinv(invQb, n)) + { + for (i = 0; i < n * n; i++) Qs[i] = invQf[i] + invQb[i]; + if (!(info = matinv(Qs, n))) + { + matmul("NN", n, 1, n, 1.0, invQf, xf, 0.0, xx); + matmul("NN", n, 1, n, 1.0, invQb, xb, 1.0, xx); + matmul("NN", n, 1, n, 1.0, Qs, xx, 0.0, xs); + } + } + free(invQf); + free(invQb); + free(xx); + return info; +} + + +/* print matrix ---------------------------------------------------------------- + * print matrix to stdout + * args : double *A I matrix A (n x m) + * int n,m I number of rows and columns of A + * int p,q I total columns, columns under decimal point + * (FILE *fp I output file pointer) + * return : none + * notes : matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +void matfprint(const double A[], int n, int m, int p, int q, FILE *fp) +{ + int i, j; + + for (i = 0; i < n; i++) + { + for (j = 0; j < m; j++) fprintf(fp, " %*.*f", p, q, A[i + j * n]); + fprintf(fp, "\n"); + } +} + +void matsprint(const double A[], int n, int m, int p, int q, std::string &buffer) +{ + int i, j; + buffer += '\n'; + for (i = 0; i < n; i++) + { + for (j = 0; j < m; j++) + { + char buf_[256]; + sprintf(buf_, " %*.*f", p, q, A[i + j * n]); + std::string s(buf_); + buffer = buffer + s; + } + buffer += '\n'; + } +} + + +void matprint(const double A[], int n, int m, int p, int q) +{ + matfprint(A, n, m, p, q, stdout); +} + + +/* string to number ------------------------------------------------------------ + * convert substring in string to number + * args : char *s I string ("... nnn.nnn ...") + * int i,n I substring position and width + * return : converted number (0.0:error) + *-----------------------------------------------------------------------------*/ +double str2num(const char *s, int i, int n) +{ + double value; + char str[256], *p = str; + + if (i < 0 || static_cast(strlen(s)) < i || static_cast(sizeof(str)) - 1 < n) return 0.0; + for (s += i; *s && --n >= 0; s++) + { + *p++ = *s == 'd' || *s == 'D' ? 'E' : *s; + } + *p = '\0'; + return sscanf(str, "%lf", &value) == 1 ? value : 0.0; +} + + +/* string to time -------------------------------------------------------------- + * convert substring in string to gtime_t struct + * args : char *s I string ("... yyyy mm dd hh mm ss ...") + * int i,n I substring position and width + * gtime_t *t O gtime_t struct + * return : status (0:ok,0>:error) + *-----------------------------------------------------------------------------*/ +int str2time(const char *s, int i, int n, gtime_t *t) +{ + double ep[6]; + char str[256], *p = str; + + if (i < 0 || static_cast(strlen(s)) < i || static_cast(sizeof(str)) - 1 < i) return -1; + for (s += i; *s && --n >= 0;) + { + *p++ = *s++; + } + *p = '\0'; + if (sscanf(str, "%lf %lf %lf %lf %lf %lf", ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5) < 6) + return -1; + if (ep[0] < 100.0) ep[0] += ep[0] < 80.0 ? 2000.0 : 1900.0; + *t = epoch2time(ep); + return 0; +} + + +/* convert calendar day/time to time ------------------------------------------- + * convert calendar day/time to gtime_t struct + * args : double *ep I day/time {year,month,day,hour,min,sec} + * return : gtime_t struct + * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) + *-----------------------------------------------------------------------------*/ +gtime_t epoch2time(const double *ep) +{ + const int doy[] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; + gtime_t time = {0, 0}; + int days, sec, year = static_cast(ep[0]), mon = static_cast(ep[1]), day = static_cast(ep[2]); + + if (year < 1970 || 2099 < year || mon < 1 || 12 < mon) return time; + + /* leap year if year%4==0 in 1901-2099 */ + days = (year - 1970) * 365 + (year - 1969) / 4 + doy[mon - 1] + day - 2 + (year % 4 == 0 && mon >= 3 ? 1 : 0); + sec = static_cast(floor(ep[5])); + time.time = static_cast(days) * 86400 + static_cast(ep[3]) * 3600 + static_cast(ep[4]) * 60 + sec; + time.sec = ep[5] - sec; + return time; +} + + +/* time to calendar day/time --------------------------------------------------- + * convert gtime_t struct to calendar day/time + * args : gtime_t t I gtime_t struct + * double *ep O day/time {year,month,day,hour,min,sec} + * return : none + * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) + *-----------------------------------------------------------------------------*/ +void time2epoch(gtime_t t, double *ep) +{ + const int mday[] = {/* # of days in a month */ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int days, sec, mon, day; + + /* leap year if year%4==0 in 1901-2099 */ + days = static_cast(t.time / 86400); + sec = static_cast(t.time - static_cast(days) * 86400); + for (day = days % 1461, mon = 0; mon < 48; mon++) + { + if (day >= mday[mon]) + day -= mday[mon]; + else + break; + } + ep[0] = 1970 + days / 1461 * 4 + mon / 12; + ep[1] = mon % 12 + 1; + ep[2] = day + 1; + ep[3] = sec / 3600; + ep[4] = sec % 3600 / 60; + ep[5] = sec % 60 + t.sec; +} + + +/* gps time to time ------------------------------------------------------------ + * convert week and tow in gps time to gtime_t struct + * args : int week I week number in gps time + * double sec I time of week in gps time (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +gtime_t gpst2time(int week, double sec) +{ + gtime_t t = epoch2time(gpst0); + + if (sec < -1e9 || 1e9 < sec) sec = 0.0; + t.time += static_cast(86400) * 7 * week + static_cast(sec); + t.sec = sec - static_cast(sec); + return t; +} + + +/* time to gps time ------------------------------------------------------------ + * convert gtime_t struct to week and tow in gps time + * args : gtime_t t I gtime_t struct + * int *week IO week number in gps time (NULL: no output) + * return : time of week in gps time (s) + *-----------------------------------------------------------------------------*/ +double time2gpst(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(gpst0); + time_t sec = t.time - t0.time; + int w = static_cast(sec / 604800); + + if (week) *week = w; + return (static_cast(sec - static_cast(w * 604800)) + t.sec); +} + + +/* galileo system time to time ------------------------------------------------- + * convert week and tow in galileo system time (gst) to gtime_t struct + * args : int week I week number in gst + * double sec I time of week in gst (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +gtime_t gst2time(int week, double sec) +{ + gtime_t t = epoch2time(gst0); + + if (sec < -1e9 || 1e9 < sec) sec = 0.0; + t.time += static_cast(86400) * 7 * week + static_cast(sec); + t.sec = sec - static_cast(sec); + return t; +} + + +/* time to galileo system time ------------------------------------------------- + * convert gtime_t struct to week and tow in galileo system time (gst) + * args : gtime_t t I gtime_t struct + * int *week IO week number in gst (NULL: no output) + * return : time of week in gst (s) + *-----------------------------------------------------------------------------*/ +double time2gst(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(gst0); + time_t sec = t.time - t0.time; + int w = static_cast(sec / (86400 * 7)); + + if (week) *week = w; + return (sec - static_cast(w) * 86400 * 7) + t.sec; +} + + +/* beidou time (bdt) to time --------------------------------------------------- + * convert week and tow in beidou time (bdt) to gtime_t struct + * args : int week I week number in bdt + * double sec I time of week in bdt (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +gtime_t bdt2time(int week, double sec) +{ + gtime_t t = epoch2time(bdt0); + + if (sec < -1e9 || 1e9 < sec) sec = 0.0; + t.time += static_cast(86400) * 7 * week + static_cast(sec); + t.sec = sec - static_cast(sec); + return t; +} + + +/* time to beidouo time (bdt) -------------------------------------------------- + * convert gtime_t struct to week and tow in beidou time (bdt) + * args : gtime_t t I gtime_t struct + * int *week IO week number in bdt (NULL: no output) + * return : time of week in bdt (s) + *-----------------------------------------------------------------------------*/ +double time2bdt(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(bdt0); + time_t sec = t.time - t0.time; + int w = static_cast(sec / (86400 * 7)); + + if (week) *week = w; + return (sec - static_cast(w) * 86400 * 7) + t.sec; +} + + +/* add time -------------------------------------------------------------------- + * add time to gtime_t struct + * args : gtime_t t I gtime_t struct + * double sec I time to add (s) + * return : gtime_t struct (t+sec) + *-----------------------------------------------------------------------------*/ +gtime_t timeadd(gtime_t t, double sec) +{ + double tt; + + t.sec += sec; + tt = floor(t.sec); + t.time += static_cast(tt); + t.sec -= tt; + return t; +} + + +/* time difference ------------------------------------------------------------- + * difference between gtime_t structs + * args : gtime_t t1,t2 I gtime_t structs + * return : time difference (t1-t2) (s) + *-----------------------------------------------------------------------------*/ +double timediff(gtime_t t1, gtime_t t2) +{ + return difftime(t1.time, t2.time) + t1.sec - t2.sec; +} + + +/* get current time in utc ----------------------------------------------------- + * get current time in utc + * args : none + * return : current time in utc + *-----------------------------------------------------------------------------*/ +gtime_t timeget(void) +{ + gtime_t time; + double ep[6] = {}; + struct timeval tv + { + }; + struct tm *tt; + + if (!gettimeofday(&tv, nullptr) && (tt = gmtime(&tv.tv_sec))) + { + ep[0] = tt->tm_year + 1900; + ep[1] = tt->tm_mon + 1; + ep[2] = tt->tm_mday; + ep[3] = tt->tm_hour; + ep[4] = tt->tm_min; + ep[5] = tt->tm_sec + tv.tv_usec * 1e-6; + } + time = epoch2time(ep); + +#ifdef CPUTIME_IN_GPST /* cputime operated in gpst */ + time = gpst2utc(time); +#endif + return time; +} + + +/* set current time in utc ----------------------------------------------------- + * set current time in utc + * args : gtime_t I current time in utc + * return : none + * notes : just set time offset between cpu time and current time + * the time offset is reflected to only timeget() + * not reentrant + *-----------------------------------------------------------------------------*/ +void timeset(gtime_t t) +{ + timeoffset_ += timediff(t, timeget()); +} + +/* read leap seconds table by text -------------------------------------------*/ +int read_leaps_text(FILE *fp) +{ + char buff[256], *p; + int i, n = 0, ep[6], ls; + + rewind(fp); + + while (fgets(buff, sizeof(buff), fp) && n < MAXLEAPS) + { + if ((p = strchr(buff, '#'))) *p = '\0'; + if (sscanf(buff, "%d %d %d %d %d %d %d", ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5, + &ls) < 7) continue; + for (i = 0; i < 6; i++) leaps[n][i] = ep[i]; + leaps[n++][6] = ls; + } + return n; +} + + +/* read leap seconds table by usno -------------------------------------------*/ +int read_leaps_usno(FILE *fp) +{ + static const char *months[] = { + "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + double jd, tai_utc; + char buff[256], month[32], ls[MAXLEAPS][7] = {}; + int i, j, y, m, d, n = 0; + + rewind(fp); + + while (fgets(buff, sizeof(buff), fp) && n < MAXLEAPS) + { + if (sscanf(buff, "%d %s %d =JD %lf TAI-UTC= %lf", &y, month, &d, &jd, + &tai_utc) < 5) continue; + if (y < 1980) continue; + for (m = 1; m <= 12; m++) + if (!strcmp(months[m - 1], month)) break; + if (m >= 13) continue; + ls[n][0] = y; + ls[n][1] = m; + ls[n][2] = d; + ls[n++][6] = static_cast(19.0 - tai_utc); + } + for (i = 0; i < n; i++) + for (j = 0; j < 7; j++) + { + leaps[i][j] = ls[n - i - 1][j]; + } + return n; +} + + +/* read leap seconds table ----------------------------------------------------- + * read leap seconds table + * args : char *file I leap seconds table file + * return : status (1:ok,0:error) + * notes : The leap second table should be as follows or leapsec.dat provided + * by USNO. + * (1) The records in the table file cosist of the following fields: + * year month day hour min sec UTC-GPST(s) + * (2) The date and time indicate the start UTC time for the UTC-GPST + * (3) The date and time should be descending order. + *-----------------------------------------------------------------------------*/ +int read_leaps(const char *file) +{ + FILE *fp; + int i, n; + + if (!(fp = fopen(file, "re"))) return 0; + + /* read leap seconds table by text or usno */ + if (!(n = read_leaps_text(fp)) && !(n = read_leaps_usno(fp))) + { + fclose(fp); + return 0; + } + for (i = 0; i < 7; i++) leaps[n][i] = 0.0; + fclose(fp); + return 1; +} + + +/* gpstime to utc -------------------------------------------------------------- + * convert gpstime to utc considering leap seconds + * args : gtime_t t I time expressed in gpstime + * return : time expressed in utc + * notes : ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +gtime_t gpst2utc(gtime_t t) +{ + gtime_t tu; + int i; + + for (i = 0; leaps[i][0] > 0; i++) + { + tu = timeadd(t, leaps[i][6]); + if (timediff(tu, epoch2time(leaps[i])) >= 0.0) return tu; + } + return t; +} + + +/* utc to gpstime -------------------------------------------------------------- + * convert utc to gpstime considering leap seconds + * args : gtime_t t I time expressed in utc + * return : time expressed in gpstime + * notes : ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +gtime_t utc2gpst(gtime_t t) +{ + int i; + + for (i = 0; leaps[i][0] > 0; i++) + { + if (timediff(t, epoch2time(leaps[i])) >= 0.0) return timeadd(t, -leaps[i][6]); + } + return t; +} + + +/* gpstime to bdt -------------------------------------------------------------- + * convert gpstime to bdt (beidou navigation satellite system time) + * args : gtime_t t I time expressed in gpstime + * return : time expressed in bdt + * notes : ref [8] 3.3, 2006/1/1 00:00 BDT = 2006/1/1 00:00 UTC + * no leap seconds in BDT + * ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +gtime_t gpst2bdt(gtime_t t) +{ + return timeadd(t, -14.0); +} + + +/* bdt to gpstime -------------------------------------------------------------- + * convert bdt (beidou navigation satellite system time) to gpstime + * args : gtime_t t I time expressed in bdt + * return : time expressed in gpstime + * notes : see gpst2bdt() + *-----------------------------------------------------------------------------*/ +gtime_t bdt2gpst(gtime_t t) +{ + return timeadd(t, 14.0); +} + + +/* time to day and sec -------------------------------------------------------*/ +double time2sec(gtime_t time, gtime_t *day) +{ + double ep[6], sec; + time2epoch(time, ep); + sec = ep[3] * 3600.0 + ep[4] * 60.0 + ep[5]; + ep[3] = ep[4] = ep[5] = 0.0; + *day = epoch2time(ep); + return sec; +} + + +/* utc to gmst ----------------------------------------------------------------- + * convert utc to gmst (Greenwich mean sidereal time) + * args : gtime_t t I time expressed in utc + * double ut1_utc I UT1-UTC (s) + * return : gmst (rad) + *-----------------------------------------------------------------------------*/ +double utc2gmst(gtime_t t, double ut1_utc) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + gtime_t tut, tut0; + double ut, t1, t2, t3, gmst0, gmst; + + tut = timeadd(t, ut1_utc); + ut = time2sec(tut, &tut0); + t1 = timediff(tut0, epoch2time(ep2000)) / 86400.0 / 36525.0; + t2 = t1 * t1; + t3 = t2 * t1; + gmst0 = 24110.54841 + 8640184.812866 * t1 + 0.093104 * t2 - 6.2E-6 * t3; + gmst = gmst0 + 1.002737909350795 * ut; + + return fmod(gmst, 86400.0) * PI / 43200.0; /* 0 <= gmst <= 2*PI */ +} + + +/* time to string -------------------------------------------------------------- + * convert gtime_t struct to string + * args : gtime_t t I gtime_t struct + * char *s O string ("yyyy/mm/dd hh:mm:ss.ssss") + * int n I number of decimals + * return : none + *-----------------------------------------------------------------------------*/ +void time2str(gtime_t t, char *s, int n) +{ + double ep[6]; + + if (n < 0) + n = 0; + else if (n > 12) + n = 12; + if (1.0 - t.sec < 0.5 / pow(10.0, n)) + { + t.time++; + t.sec = 0.0; + }; + time2epoch(t, ep); + sprintf(s, "%04.0f/%02.0f/%02.0f %02.0f:%02.0f:%0*.*f", ep[0], ep[1], ep[2], + ep[3], ep[4], n <= 0 ? 2 : n + 3, n <= 0 ? 0 : n, ep[5]); +} + + +/* get time string ------------------------------------------------------------- + * get time string + * args : gtime_t t I gtime_t struct + * int n I number of decimals + * return : time string + * notes : not reentrant, do not use multiple in a function + *-----------------------------------------------------------------------------*/ +char *time_str(gtime_t t, int n) +{ + static char buff[64]; + time2str(t, buff, n); + return buff; +} + + +/* time to day of year --------------------------------------------------------- + * convert time to day of year + * args : gtime_t t I gtime_t struct + * return : day of year (days) + *-----------------------------------------------------------------------------*/ +double time2doy(gtime_t t) +{ + double ep[6]; + + time2epoch(t, ep); + ep[1] = ep[2] = 1.0; + ep[3] = ep[4] = ep[5] = 0.0; + return timediff(t, epoch2time(ep)) / 86400.0 + 1.0; +} + + +/* adjust gps week number ------------------------------------------------------ + * adjust gps week number using cpu time + * args : int week I not-adjusted gps week number + * return : adjusted gps week number + *-----------------------------------------------------------------------------*/ +int adjgpsweek(int week) +{ + int w; + (void)time2gpst(utc2gpst(timeget()), &w); + if (w < 1560) w = 1560; /* use 2009/12/1 if time is earlier than 2009/12/1 */ + return week + (w - week + 512) / 1024 * 1024; +} + + +/* get tick time --------------------------------------------------------------- + * get current tick in ms + * args : none + * return : current tick in ms + *-----------------------------------------------------------------------------*/ +unsigned int tickget(void) +{ + struct timespec tp = {0, 0}; + struct timeval tv = {0, 0}; + +#ifdef CLOCK_MONOTONIC_RAW + /* linux kernel > 2.6.28 */ + if (!clock_gettime(CLOCK_MONOTONIC_RAW, &tp)) + { + return tp.tv_sec * 1000u + tp.tv_nsec / 1000000u; + } + gettimeofday(&tv, nullptr); + return tv.tv_sec * 1000u + tv.tv_usec / 1000u; + +#else + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000u + tv.tv_usec / 1000u; +#endif +} + + +/* sleep ms -------------------------------------------------------------------- + * sleep ms + * args : int ms I milliseconds to sleep (<0:no sleep) + * return : none + *-----------------------------------------------------------------------------*/ +void sleepms(int ms) +{ + struct timespec ts = {0, 0}; + if (ms <= 0) return; + ts.tv_sec = static_cast(ms / 1000); + ts.tv_nsec = static_cast(ms % 1000 * 1000000); + nanosleep(&ts, nullptr); +} + + +/* convert degree to deg-min-sec ----------------------------------------------- + * convert degree to degree-minute-second + * args : double deg I degree + * double *dms O degree-minute-second {deg, min, sec} + * int ndec I number of decimals of second + * return : none + *-----------------------------------------------------------------------------*/ +void deg2dms(double deg, double *dms, int ndec) +{ + double sign = deg < 0.0 ? -1.0 : 1.0, a = fabs(deg); + double unit = pow(0.1, ndec); + dms[0] = floor(a); + a = (a - dms[0]) * 60.0; + dms[1] = floor(a); + a = (a - dms[1]) * 60.0; + dms[2] = floor(a / unit + 0.5) * unit; + if (dms[2] >= 60.0) + { + dms[2] = 0.0; + dms[1] += 1.0; + if (dms[1] >= 60.0) + { + dms[1] = 0.0; + dms[0] += 1.0; + } + } + dms[0] *= sign; +} + +void deg2dms(double deg, double *dms) +{ + double sign = deg < 0.0 ? -1.0 : 1.0, a = fabs(deg); + dms[0] = floor(a); + a = (a - dms[0]) * 60.0; + dms[1] = floor(a); + a = (a - dms[1]) * 60.0; + dms[2] = a; + dms[0] *= sign; +} + +/* convert deg-min-sec to degree ----------------------------------------------- + * convert degree-minute-second to degree + * args : double *dms I degree-minute-second {deg,min,sec} + * return : degree + *-----------------------------------------------------------------------------*/ +double dms2deg(const double *dms) +{ + double sign = dms[0] < 0.0 ? -1.0 : 1.0; + return sign * (fabs(dms[0]) + dms[1] / 60.0 + dms[2] / 3600.0); +} + + +/* transform ecef to geodetic position ------------------------------------------ + * transform ecef position to geodetic position + * args : double *r I ecef position {x,y,z} (m) + * double *pos O geodetic position {lat,lon,h} (rad,m) + * return : none + * notes : WGS84, ellipsoidal height + *-----------------------------------------------------------------------------*/ +void ecef2pos(const double *r, double *pos) +{ + double e2 = FE_WGS84 * (2.0 - FE_WGS84), r2 = dot(r, r, 2), z, zk, v = RE_WGS84, sinp; + + for (z = r[2], zk = 0.0; fabs(z - zk) >= 1e-4;) + { + zk = z; + sinp = z / sqrt(r2 + z * z); + v = RE_WGS84 / sqrt(1.0 - e2 * sinp * sinp); + z = r[2] + v * e2 * sinp; + } + pos[0] = r2 > 1e-12 ? atan(z / sqrt(r2)) : (r[2] > 0.0 ? PI / 2.0 : -PI / 2.0); + pos[1] = r2 > 1e-12 ? atan2(r[1], r[0]) : 0.0; + pos[2] = sqrt(r2 + z * z) - v; +} + + +/* transform geodetic to ecef position ----------------------------------------- + * transform geodetic position to ecef position + * args : double *pos I geodetic position {lat, lon,h} (rad,m) + * double *r O ecef position {x,y,z} (m) + * return : none + * notes : WGS84, ellipsoidal height + *-----------------------------------------------------------------------------*/ +void pos2ecef(const double *pos, double *r) +{ + double sinp = sin(pos[0]), cosp = cos(pos[0]), sinl = sin(pos[1]), cosl = cos(pos[1]); + double e2 = FE_WGS84 * (2.0 - FE_WGS84), v = RE_WGS84 / sqrt(1.0 - e2 * sinp * sinp); + + r[0] = (v + pos[2]) * cosp * cosl; + r[1] = (v + pos[2]) * cosp * sinl; + r[2] = (v * (1.0 - e2) + pos[2]) * sinp; +} + + +/* ecef to local coordinate transformation matrix ------------------------------ + * compute ecef to local coordinate transformation matrix + * args : double *pos I geodetic position {lat,lon} (rad) + * double *E O ecef to local coord transformation matrix (3x3) + * return : none + * notes : matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +void xyz2enu(const double *pos, double *E) +{ + double sinp = sin(pos[0]), cosp = cos(pos[0]), sinl = sin(pos[1]), cosl = cos(pos[1]); + + E[0] = -sinl; + E[3] = cosl; + E[6] = 0.0; + E[1] = -sinp * cosl; + E[4] = -sinp * sinl; + E[7] = cosp; + E[2] = cosp * cosl; + E[5] = cosp * sinl; + E[8] = sinp; +} + + +/* transform ecef vector to local tangental coordinate ------------------------- + * transform ecef vector to local tangental coordinate + * args : double *pos I geodetic position {lat,lon} (rad) + * double *r I vector in ecef coordinate {x,y,z} + * double *e O vector in local tangental coordinate {e,n,u} + * return : none + *-----------------------------------------------------------------------------*/ +void ecef2enu(const double *pos, const double *r, double *e) +{ + double E[9]; + + xyz2enu(pos, E); + matmul("NN", 3, 1, 3, 1.0, E, r, 0.0, e); +} + + +/* transform local vector to ecef coordinate ----------------------------------- + * transform local tangental coordinate vector to ecef + * args : double *pos I geodetic position {lat,lon} (rad) + * double *e I vector in local tangental coordinate {e,n,u} + * double *r O vector in ecef coordinate {x,y,z} + * return : none + *-----------------------------------------------------------------------------*/ +void enu2ecef(const double *pos, const double *e, double *r) +{ + double E[9]; + + xyz2enu(pos, E); + matmul("TN", 3, 1, 3, 1.0, E, e, 0.0, r); +} + + +/* transform covariance to local tangental coordinate -------------------------- + * transform ecef covariance to local tangental coordinate + * args : double *pos I geodetic position {lat, lon} (rad) + * double *P I covariance in ecef coordinate + * double *Q O covariance in local tangental coordinate + * return : none + *-----------------------------------------------------------------------------*/ +void covenu(const double *pos, const double *P, double *Q) +{ + double E[9], EP[9]; + + xyz2enu(pos, E); + matmul("NN", 3, 3, 3, 1.0, E, P, 0.0, EP); + matmul("NT", 3, 3, 3, 1.0, EP, E, 0.0, Q); +} + + +/* transform local enu coordinate covariance to xyz-ecef ----------------------- + * transform local enu covariance to xyz-ecef coordinate + * args : double *pos I geodetic position {lat,lon} (rad) + * double *Q I covariance in local enu coordinate + * double *P O covariance in xyz-ecef coordinate + * return : none + *-----------------------------------------------------------------------------*/ +void covecef(const double *pos, const double *Q, double *P) +{ + double E[9], EQ[9]; + + xyz2enu(pos, E); + matmul("TN", 3, 3, 3, 1.0, E, Q, 0.0, EQ); + matmul("NN", 3, 3, 3, 1.0, EQ, E, 0.0, P); +} + + +/* astronomical arguments: f={l,l',F,D,OMG} (rad) ----------------------------*/ +void ast_args(double t, double *f) +{ + static const double fc[][5] = {/* coefficients for iau 1980 nutation */ + {134.96340251, 1717915923.2178, 31.8792, 0.051635, -0.00024470}, + {357.52910918, 129596581.0481, -0.5532, 0.000136, -0.00001149}, + {93.27209062, 1739527262.8478, -12.7512, -0.001037, 0.00000417}, + {297.85019547, 1602961601.2090, -6.3706, 0.006593, -0.00003169}, + {125.04455501, -6962890.2665, 7.4722, 0.007702, -0.00005939}}; + double tt[4]; + int i, j; + + for (tt[0] = t, i = 1; i < 4; i++) tt[i] = tt[i - 1] * t; + for (i = 0; i < 5; i++) + { + f[i] = fc[i][0] * 3600.0; + for (j = 0; j < 4; j++) f[i] += fc[i][j + 1] * tt[j]; + f[i] = fmod(f[i] * AS2R, 2.0 * PI); + } +} + + +/* iau 1980 nutation ---------------------------------------------------------*/ +void nut_iau1980(double t, const double *f, double *dpsi, double *deps) +{ + static const double nut[106][10] = { + {0, 0, 0, 0, 1, -6798.4, -171996, -174.2, 92025, 8.9}, + {0, 0, 2, -2, 2, 182.6, -13187, -1.6, 5736, -3.1}, + {0, 0, 2, 0, 2, 13.7, -2274, -0.2, 977, -0.5}, + {0, 0, 0, 0, 2, -3399.2, 2062, 0.2, -895, 0.5}, + {0, -1, 0, 0, 0, -365.3, -1426, 3.4, 54, -0.1}, + {1, 0, 0, 0, 0, 27.6, 712, 0.1, -7, 0.0}, + {0, 1, 2, -2, 2, 121.7, -517, 1.2, 224, -0.6}, + {0, 0, 2, 0, 1, 13.6, -386, -0.4, 200, 0.0}, + {1, 0, 2, 0, 2, 9.1, -301, 0.0, 129, -0.1}, + {0, -1, 2, -2, 2, 365.2, 217, -0.5, -95, 0.3}, + {-1, 0, 0, 2, 0, 31.8, 158, 0.0, -1, 0.0}, + {0, 0, 2, -2, 1, 177.8, 129, 0.1, -70, 0.0}, + {-1, 0, 2, 0, 2, 27.1, 123, 0.0, -53, 0.0}, + {1, 0, 0, 0, 1, 27.7, 63, 0.1, -33, 0.0}, + {0, 0, 0, 2, 0, 14.8, 63, 0.0, -2, 0.0}, + {-1, 0, 2, 2, 2, 9.6, -59, 0.0, 26, 0.0}, + {-1, 0, 0, 0, 1, -27.4, -58, -0.1, 32, 0.0}, + {1, 0, 2, 0, 1, 9.1, -51, 0.0, 27, 0.0}, + {-2, 0, 0, 2, 0, -205.9, -48, 0.0, 1, 0.0}, + {-2, 0, 2, 0, 1, 1305.5, 46, 0.0, -24, 0.0}, + {0, 0, 2, 2, 2, 7.1, -38, 0.0, 16, 0.0}, + {2, 0, 2, 0, 2, 6.9, -31, 0.0, 13, 0.0}, + {2, 0, 0, 0, 0, 13.8, 29, 0.0, -1, 0.0}, + {1, 0, 2, -2, 2, 23.9, 29, 0.0, -12, 0.0}, + {0, 0, 2, 0, 0, 13.6, 26, 0.0, -1, 0.0}, + {0, 0, 2, -2, 0, 173.3, -22, 0.0, 0, 0.0}, + {-1, 0, 2, 0, 1, 27.0, 21, 0.0, -10, 0.0}, + {0, 2, 0, 0, 0, 182.6, 17, -0.1, 0, 0.0}, + {0, 2, 2, -2, 2, 91.3, -16, 0.1, 7, 0.0}, + {-1, 0, 0, 2, 1, 32.0, 16, 0.0, -8, 0.0}, + {0, 1, 0, 0, 1, 386.0, -15, 0.0, 9, 0.0}, + {1, 0, 0, -2, 1, -31.7, -13, 0.0, 7, 0.0}, + {0, -1, 0, 0, 1, -346.6, -12, 0.0, 6, 0.0}, + {2, 0, -2, 0, 0, -1095.2, 11, 0.0, 0, 0.0}, + {-1, 0, 2, 2, 1, 9.5, -10, 0.0, 5, 0.0}, + {1, 0, 2, 2, 2, 5.6, -8, 0.0, 3, 0.0}, + {0, -1, 2, 0, 2, 14.2, -7, 0.0, 3, 0.0}, + {0, 0, 2, 2, 1, 7.1, -7, 0.0, 3, 0.0}, + {1, 1, 0, -2, 0, -34.8, -7, 0.0, 0, 0.0}, + {0, 1, 2, 0, 2, 13.2, 7, 0.0, -3, 0.0}, + {-2, 0, 0, 2, 1, -199.8, -6, 0.0, 3, 0.0}, + {0, 0, 0, 2, 1, 14.8, -6, 0.0, 3, 0.0}, + {2, 0, 2, -2, 2, 12.8, 6, 0.0, -3, 0.0}, + {1, 0, 0, 2, 0, 9.6, 6, 0.0, 0, 0.0}, + {1, 0, 2, -2, 1, 23.9, 6, 0.0, -3, 0.0}, + {0, 0, 0, -2, 1, -14.7, -5, 0.0, 3, 0.0}, + {0, -1, 2, -2, 1, 346.6, -5, 0.0, 3, 0.0}, + {2, 0, 2, 0, 1, 6.9, -5, 0.0, 3, 0.0}, + {1, -1, 0, 0, 0, 29.8, 5, 0.0, 0, 0.0}, + {1, 0, 0, -1, 0, 411.8, -4, 0.0, 0, 0.0}, + {0, 0, 0, 1, 0, 29.5, -4, 0.0, 0, 0.0}, + {0, 1, 0, -2, 0, -15.4, -4, 0.0, 0, 0.0}, + {1, 0, -2, 0, 0, -26.9, 4, 0.0, 0, 0.0}, + {2, 0, 0, -2, 1, 212.3, 4, 0.0, -2, 0.0}, + {0, 1, 2, -2, 1, 119.6, 4, 0.0, -2, 0.0}, + {1, 1, 0, 0, 0, 25.6, -3, 0.0, 0, 0.0}, + {1, -1, 0, -1, 0, -3232.9, -3, 0.0, 0, 0.0}, + {-1, -1, 2, 2, 2, 9.8, -3, 0.0, 1, 0.0}, + {0, -1, 2, 2, 2, 7.2, -3, 0.0, 1, 0.0}, + {1, -1, 2, 0, 2, 9.4, -3, 0.0, 1, 0.0}, + {3, 0, 2, 0, 2, 5.5, -3, 0.0, 1, 0.0}, + {-2, 0, 2, 0, 2, 1615.7, -3, 0.0, 1, 0.0}, + {1, 0, 2, 0, 0, 9.1, 3, 0.0, 0, 0.0}, + {-1, 0, 2, 4, 2, 5.8, -2, 0.0, 1, 0.0}, + {1, 0, 0, 0, 2, 27.8, -2, 0.0, 1, 0.0}, + {-1, 0, 2, -2, 1, -32.6, -2, 0.0, 1, 0.0}, + {0, -2, 2, -2, 1, 6786.3, -2, 0.0, 1, 0.0}, + {-2, 0, 0, 0, 1, -13.7, -2, 0.0, 1, 0.0}, + {2, 0, 0, 0, 1, 13.8, 2, 0.0, -1, 0.0}, + {3, 0, 0, 0, 0, 9.2, 2, 0.0, 0, 0.0}, + {1, 1, 2, 0, 2, 8.9, 2, 0.0, -1, 0.0}, + {0, 0, 2, 1, 2, 9.3, 2, 0.0, -1, 0.0}, + {1, 0, 0, 2, 1, 9.6, -1, 0.0, 0, 0.0}, + {1, 0, 2, 2, 1, 5.6, -1, 0.0, 1, 0.0}, + {1, 1, 0, -2, 1, -34.7, -1, 0.0, 0, 0.0}, + {0, 1, 0, 2, 0, 14.2, -1, 0.0, 0, 0.0}, + {0, 1, 2, -2, 0, 117.5, -1, 0.0, 0, 0.0}, + {0, 1, -2, 2, 0, -329.8, -1, 0.0, 0, 0.0}, + {1, 0, -2, 2, 0, 23.8, -1, 0.0, 0, 0.0}, + {1, 0, -2, -2, 0, -9.5, -1, 0.0, 0, 0.0}, + {1, 0, 2, -2, 0, 32.8, -1, 0.0, 0, 0.0}, + {1, 0, 0, -4, 0, -10.1, -1, 0.0, 0, 0.0}, + {2, 0, 0, -4, 0, -15.9, -1, 0.0, 0, 0.0}, + {0, 0, 2, 4, 2, 4.8, -1, 0.0, 0, 0.0}, + {0, 0, 2, -1, 2, 25.4, -1, 0.0, 0, 0.0}, + {-2, 0, 2, 4, 2, 7.3, -1, 0.0, 1, 0.0}, + {2, 0, 2, 2, 2, 4.7, -1, 0.0, 0, 0.0}, + {0, -1, 2, 0, 1, 14.2, -1, 0.0, 0, 0.0}, + {0, 0, -2, 0, 1, -13.6, -1, 0.0, 0, 0.0}, + {0, 0, 4, -2, 2, 12.7, 1, 0.0, 0, 0.0}, + {0, 1, 0, 0, 2, 409.2, 1, 0.0, 0, 0.0}, + {1, 1, 2, -2, 2, 22.5, 1, 0.0, -1, 0.0}, + {3, 0, 2, -2, 2, 8.7, 1, 0.0, 0, 0.0}, + {-2, 0, 2, 2, 2, 14.6, 1, 0.0, -1, 0.0}, + {-1, 0, 0, 0, 2, -27.3, 1, 0.0, -1, 0.0}, + {0, 0, -2, 2, 1, -169.0, 1, 0.0, 0, 0.0}, + {0, 1, 2, 0, 1, 13.1, 1, 0.0, 0, 0.0}, + {-1, 0, 4, 0, 2, 9.1, 1, 0.0, 0, 0.0}, + {2, 1, 0, -2, 0, 131.7, 1, 0.0, 0, 0.0}, + {2, 0, 0, 2, 0, 7.1, 1, 0.0, 0, 0.0}, + {2, 0, 2, -2, 1, 12.8, 1, 0.0, -1, 0.0}, + {2, 0, -2, 0, 1, -943.2, 1, 0.0, 0, 0.0}, + {1, -1, 0, -2, 0, -29.3, 1, 0.0, 0, 0.0}, + {-1, 0, 0, 1, 1, -388.3, 1, 0.0, 0, 0.0}, + {-1, -1, 0, 2, 1, 35.0, 1, 0.0, 0, 0.0}, + {0, 1, 0, 1, 0, 27.3, 1, 0.0, 0, 0.0}}; + double ang; + int i, j; + + *dpsi = *deps = 0.0; + + for (i = 0; i < 106; i++) + { + ang = 0.0; + for (j = 0; j < 5; j++) ang += nut[i][j] * f[j]; + *dpsi += (nut[i][6] + nut[i][7] * t) * sin(ang); + *deps += (nut[i][8] + nut[i][9] * t) * cos(ang); + } + *dpsi *= 1e-4 * AS2R; /* 0.1 mas -> rad */ + *deps *= 1e-4 * AS2R; +} + + +/* eci to ecef transformation matrix ------------------------------------------- + * compute eci to ecef transformation matrix + * args : gtime_t tutc I time in utc + * double *erpv I erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) + * double *U O eci to ecef transformation matrix (3 x 3) + * double *gmst IO greenwich mean sidereal time (rad) + * (NULL: no output) + * return : none + * note : see ref [3] chap 5 + * not thread-safe + *-----------------------------------------------------------------------------*/ +void eci2ecef(gtime_t tutc, const double *erpv, double *U, double *gmst) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + static gtime_t tutc_; + static double U_[9], gmst_; + gtime_t tgps; + double eps, ze, th, z, t, t2, t3, dpsi, deps, gast, f[5]; + double R1[9], R2[9], R3[9], R[9], W[9], N[9], P[9], NP[9]; + int i; + + trace(4, "eci2ecef: tutc=%s\n", time_str(tutc, 3)); + + if (fabs(timediff(tutc, tutc_)) < 0.01) + { /* read cache */ + for (i = 0; i < 9; i++) U[i] = U_[i]; + if (gmst) *gmst = gmst_; + return; + } + tutc_ = tutc; + + /* terrestrial time */ + tgps = utc2gpst(tutc_); + t = (timediff(tgps, epoch2time(ep2000)) + 19.0 + 32.184) / 86400.0 / 36525.0; + t2 = t * t; + t3 = t2 * t; + + /* astronomical arguments */ + ast_args(t, f); + + /* iau 1976 precession */ + ze = (2306.2181 * t + 0.30188 * t2 + 0.017998 * t3) * AS2R; + th = (2004.3109 * t - 0.42665 * t2 - 0.041833 * t3) * AS2R; + z = (2306.2181 * t + 1.09468 * t2 + 0.018203 * t3) * AS2R; + eps = (84381.448 - 46.8150 * t - 0.00059 * t2 + 0.001813 * t3) * AS2R; + Rz(-z, R1); + Ry(th, R2); + Rz(-ze, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, R); + matmul("NN", 3, 3, 3, 1.0, R, R3, 0.0, P); /* P=Rz(-z)*Ry(th)*Rz(-ze) */ + + /* iau 1980 nutation */ + nut_iau1980(t, f, &dpsi, &deps); + Rx(-eps - deps, R1); + Rz(-dpsi, R2); + Rx(eps, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, R); + matmul("NN", 3, 3, 3, 1.0, R, R3, 0.0, N); /* N=Rx(-eps)*Rz(-dspi)*Rx(eps) */ + + /* greenwich apparent sidereal time (rad) */ + gmst_ = utc2gmst(tutc_, erpv[2]); + gast = gmst_ + dpsi * cos(eps); + gast += (0.00264 * sin(f[4]) + 0.000063 * sin(2.0 * f[4])) * AS2R; + + /* eci to ecef transformation matrix */ + Ry(-erpv[0], R1); + Rx(-erpv[1], R2); + Rz(gast, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, W); + matmul("NN", 3, 3, 3, 1.0, W, R3, 0.0, R); /* W=Ry(-xp)*Rx(-yp) */ + matmul("NN", 3, 3, 3, 1.0, N, P, 0.0, NP); + matmul("NN", 3, 3, 3, 1.0, R, NP, 0.0, U_); /* U=W*Rz(gast)*N*P */ + + for (i = 0; i < 9; i++) U[i] = U_[i]; + if (gmst) *gmst = gmst_; + + trace(5, "gmst=%.12f gast=%.12f\n", gmst_, gast); + trace(5, "P=\n"); + tracemat(5, P, 3, 3, 15, 12); + trace(5, "N=\n"); + tracemat(5, N, 3, 3, 15, 12); + trace(5, "W=\n"); + tracemat(5, W, 3, 3, 15, 12); + trace(5, "U=\n"); + tracemat(5, U, 3, 3, 15, 12); +} + + +/* decode antenna parameter field --------------------------------------------*/ +int decodef(char *p, int n, double *v) +{ + int i; + + for (i = 0; i < n; i++) v[i] = 0.0; + for (i = 0, p = strtok(p, " "); p && i < n; p = strtok(nullptr, " ")) + { + v[i++] = atof(p) * 1e-3; + } + return i; +} + + +/* add antenna parameter -----------------------------------------------------*/ +void addpcv(const pcv_t *pcv, pcvs_t *pcvs) +{ + pcv_t *pcvs_pcv; + + if (pcvs->nmax <= pcvs->n) + { + pcvs->nmax += 256; + if (!(pcvs_pcv = static_cast(realloc(pcvs->pcv, sizeof(pcv_t) * pcvs->nmax)))) + { + trace(1, "addpcv: memory allocation error\n"); + free(pcvs->pcv); + pcvs->pcv = nullptr; + pcvs->n = pcvs->nmax = 0; + return; + } + pcvs->pcv = pcvs_pcv; + } + pcvs->pcv[pcvs->n++] = *pcv; +} + + +/* read ngs antenna parameter file -------------------------------------------*/ +int readngspcv(const char *file, pcvs_t *pcvs) +{ + FILE *fp; + static const pcv_t pcv0 = {0, {}, {}, {0, 0}, {0, 0}, {{}, {}}, {{}, {}}}; + pcv_t pcv = {0, {}, {}, {0, 0}, {0, 0}, {{}, {}}, {{}, {}}}; + double neu[3]; + int n = 0; + char buff[256]; + + if (!(fp = fopen(file, "re"))) + { + trace(2, "ngs pcv file open error: %s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (strlen(buff) >= 62 && buff[61] == '|') continue; + + if (buff[0] != ' ') n = 0; /* start line */ + if (++n == 1) + { + pcv = pcv0; + strncpy(pcv.type, buff, 61); + pcv.type[61] = '\0'; + } + else if (n == 2) + { + if (decodef(buff, 3, neu) < 3) continue; + pcv.off[0][0] = neu[1]; + pcv.off[0][1] = neu[0]; + pcv.off[0][2] = neu[2]; + } + else if (n == 3) + decodef(buff, 10, pcv.var[0]); + else if (n == 4) + decodef(buff, 9, pcv.var[0] + 10); + else if (n == 5) + { + if (decodef(buff, 3, neu) < 3) continue; + ; + pcv.off[1][0] = neu[1]; + pcv.off[1][1] = neu[0]; + pcv.off[1][2] = neu[2]; + } + else if (n == 6) + decodef(buff, 10, pcv.var[1]); + else if (n == 7) + { + decodef(buff, 9, pcv.var[1] + 10); + addpcv(&pcv, pcvs); + } + } + fclose(fp); + + return 1; +} + + +/* read antex file ----------------------------------------------------------*/ +int readantex(const char *file, pcvs_t *pcvs) +{ + FILE *fp; + static const pcv_t pcv0 = {0, {}, {}, {0, 0}, {0, 0}, {{}, {}}, {{}, {}}}; + pcv_t pcv = {0, {}, {}, {0, 0}, {0, 0}, {{}, {}}, {{}, {}}}; + double neu[3]; + int i, f, freq = 0, state = 0, freqs[] = {1, 2, 5, 6, 7, 8, 0}; + char buff[256]; + + trace(3, "readantex: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) + { + trace(2, "antex pcv file open error: %s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (strlen(buff) < 60 || strstr(buff + 60, "COMMENT")) continue; + + if (strstr(buff + 60, "START OF ANTENNA")) + { + pcv = pcv0; + state = 1; + } + if (strstr(buff + 60, "END OF ANTENNA")) + { + addpcv(&pcv, pcvs); + state = 0; + } + if (!state) continue; + + if (strstr(buff + 60, "TYPE / SERIAL NO")) + { + strncpy(pcv.type, buff, 20); + pcv.type[20] = '\0'; + strncpy(pcv.code, buff + 20, 20); + pcv.code[20] = '\0'; + if (!strncmp(pcv.code + 3, " ", 8)) + { + pcv.sat = satid2no(pcv.code); + } + } + else if (strstr(buff + 60, "VALID FROM")) + { + if (!str2time(buff, 0, 43, &pcv.ts)) continue; + } + else if (strstr(buff + 60, "VALID UNTIL")) + { + if (!str2time(buff, 0, 43, &pcv.te)) continue; + } + else if (strstr(buff + 60, "START OF FREQUENCY")) + { + if (sscanf(buff + 4, "%d", &f) < 1) continue; + for (i = 0; i < NFREQ; i++) + if (freqs[i] == f) break; + if (i < NFREQ) freq = i + 1; + } + else if (strstr(buff + 60, "END OF FREQUENCY")) + { + freq = 0; + } + else if (strstr(buff + 60, "NORTH / EAST / UP")) + { + if (freq < 1 || NFREQ < freq) continue; + if (decodef(buff, 3, neu) < 3) continue; + pcv.off[freq - 1][0] = neu[pcv.sat ? 0 : 1]; /* x or e */ + pcv.off[freq - 1][1] = neu[pcv.sat ? 1 : 0]; /* y or n */ + pcv.off[freq - 1][2] = neu[2]; /* z or u */ + } + else if (strstr(buff, "NOAZI")) + { + if (freq < 1 || NFREQ < freq) continue; + if ((i = decodef(buff + 8, 19, pcv.var[freq - 1])) <= 0) continue; + for (; i < 19; i++) pcv.var[freq - 1][i] = pcv.var[freq - 1][i - 1]; + } + } + fclose(fp); + + return 1; +} + + +/* read antenna parameters ------------------------------------------------------ + * read antenna parameters + * args : char *file I antenna parameter file (antex) + * pcvs_t *pcvs IO antenna parameters + * return : status (1:ok,0:file open error) + * notes : file with the externsion .atx or .ATX is recognized as antex + * file except for antex is recognized ngs antenna parameters + * see reference [3] + * only support non-azimuth-depedent parameters + *-----------------------------------------------------------------------------*/ +int readpcv(const char *file, pcvs_t *pcvs) +{ + pcv_t *pcv; + const char *ext; + int i, stat; + + trace(3, "readpcv: file=%s\n", file); + + if (!(ext = strrchr(file, '.'))) + { + ext = ""; + } + + if (!strcmp(ext, ".atx") || !strcmp(ext, ".ATX")) + { + stat = readantex(file, pcvs); + } + else + { + stat = readngspcv(file, pcvs); + } + for (i = 0; i < pcvs->n; i++) + { + pcv = pcvs->pcv + i; + trace(4, "sat=%2d type=%20s code=%s off=%8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", + pcv->sat, pcv->type, pcv->code, pcv->off[0][0], pcv->off[0][1], + pcv->off[0][2], pcv->off[1][0], pcv->off[1][1], pcv->off[1][2]); + } + return stat; +} + + +/* search antenna parameter ---------------------------------------------------- + * read satellite antenna phase center position + * args : int sat I satellite number (0: receiver antenna) + * char *type I antenna type for receiver antenna + * gtime_t time I time to search parameters + * pcvs_t *pcvs IO antenna parameters + * return : antenna parameter (NULL: no antenna) + *-----------------------------------------------------------------------------*/ +pcv_t *searchpcv(int sat, const char *type, gtime_t time, + const pcvs_t *pcvs) +{ + pcv_t *pcv; + char buff[MAXANT] = "", *types[2], *p; + int i, j, n = 0; + + trace(3, "searchpcv: sat=%2d type=%s\n", sat, type); + + if (sat) + { /* search satellite antenna */ + for (i = 0; i < pcvs->n; i++) + { + pcv = pcvs->pcv + i; + if (pcv->sat != sat) continue; + if (pcv->ts.time != 0 && timediff(pcv->ts, time) > 0.0) continue; + if (pcv->te.time != 0 && timediff(pcv->te, time) < 0.0) continue; + return pcv; + } + } + else + { + if (strlen(type) < MAXANT + 1) + strcpy(buff, type); + else + { + trace(1, "type array is too long"); + } + for (p = strtok(buff, " "); p && n < 2; p = strtok(nullptr, " ")) types[n++] = p; + if (n <= 0) return nullptr; + + /* search receiver antenna with radome at first */ + for (i = 0; i < pcvs->n; i++) + { + pcv = pcvs->pcv + i; + for (j = 0; j < n; j++) + if (!strstr(pcv->type, types[j])) break; + if (j >= n) return pcv; + } + /* search receiver antenna without radome */ + for (i = 0; i < pcvs->n; i++) + { + pcv = pcvs->pcv + i; + if (strstr(pcv->type, types[0]) != pcv->type) continue; + + trace(2, "pcv without radome is used type=%s\n", type); + return pcv; + } + } + return nullptr; +} + + +/* read station positions ------------------------------------------------------ + * read positions from station position file + * args : char *file I station position file containing + * lat(deg) lon(deg) height(m) name in a line + * char *rcvs I station name + * double *pos O station position {lat,lon,h} (rad/m) + * (all 0 if search error) + * return : none + *-----------------------------------------------------------------------------*/ +void readpos(const char *file, const char *rcv, double *pos) +{ + static double poss[2048][3]; + static char stas[2048][16]; + FILE *fp; + int i, j, len, np = 0; + char buff[256], str[256]; + + trace(3, "readpos: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) + { + fprintf(stderr, "reference position file open error : %s\n", file); + return; + } + while (np < 2048 && fgets(buff, sizeof(buff), fp)) + { + if (buff[0] == '%' || buff[0] == '#') continue; + if (sscanf(buff, "%lf %lf %lf %s", &poss[np][0], &poss[np][1], &poss[np][2], + str) < 4) continue; + // strncpy(stas[np], str, 15); This line triggers a warning. Replaced by: + memcpy(stas[np], str, 15 * sizeof(stas[np][0])); + stas[np++][15] = '\0'; + } + fclose(fp); + len = static_cast(strlen(rcv)); + for (i = 0; i < np; i++) + { + if (strncmp(stas[i], rcv, len) != 0) continue; + for (j = 0; j < 3; j++) pos[j] = poss[i][j]; + pos[0] *= D2R; + pos[1] *= D2R; + return; + } + pos[0] = pos[1] = pos[2] = 0.0; +} + + +/* read blq record -----------------------------------------------------------*/ +int readblqrecord(FILE *fp, double *odisp) +{ + double v[11]; + char buff[256]; + int i, n = 0; + + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "$$", 2)) continue; + if (sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + v, v + 1, v + 2, v + 3, v + 4, v + 5, v + 6, v + 7, v + 8, v + 9, v + 10) < 11) continue; + for (i = 0; i < 11; i++) odisp[n + i * 6] = v[i]; + if (++n == 6) return 1; + } + return 0; +} + + +/* read blq ocean tide loading parameters -------------------------------------- + * read blq ocean tide loading parameters + * args : char *file I BLQ ocean tide loading parameter file + * char *sta I station name + * double *odisp O ocean tide loading parameters + * return : status (1:ok, 0:file open error) + *-----------------------------------------------------------------------------*/ +int readblq(const char *file, const char *sta, double *odisp) +{ + FILE *fp; + char buff[256], staname[32] = "", name[32], *p; + + /* station name to upper case */ + sscanf(sta, "%16s", staname); + for (p = staname; (*p = static_cast(toupper(static_cast(*p)))); p++) + ; + + if (!(fp = fopen(file, "re"))) + { + trace(2, "blq file open error: file=%s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "$$", 2) || strlen(buff) < 2) continue; + + if (sscanf(buff + 2, "%16s", name) < 1) continue; + for (p = name; (*p = static_cast(toupper(static_cast(*p)))); p++) + ; + if (strcmp(name, staname) != 0) continue; + + /* read blq record */ + if (readblqrecord(fp, odisp)) + { + fclose(fp); + return 1; + } + } + fclose(fp); + trace(2, "no otl parameters: sta=%s file=%s\n", sta, file); + return 0; +} + + +/* read earth rotation parameters ---------------------------------------------- + * read earth rotation parameters + * args : char *file I IGS ERP file (IGS ERP ver.2) + * erp_t *erp O earth rotation parameters + * return : status (1:ok,0:file open error) + *-----------------------------------------------------------------------------*/ +int readerp(const char *file, erp_t *erp) +{ + FILE *fp; + erpd_t *erp_data; + double v[14] = {}; + char buff[256]; + + trace(3, "readerp: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) + { + trace(2, "erp file open error: file=%s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + v, v + 1, v + 2, v + 3, v + 4, v + 5, v + 6, v + 7, v + 8, v + 9, v + 10, v + 11, v + 12, v + 13) < 5) + { + continue; + } + if (erp->n >= erp->nmax) + { + erp->nmax = erp->nmax <= 0 ? 128 : erp->nmax * 2; + erp_data = static_cast(realloc(erp->data, sizeof(erpd_t) * erp->nmax)); + if (!erp_data) + { + free(erp->data); + erp->data = nullptr; + erp->n = erp->nmax = 0; + fclose(fp); + return 0; + } + erp->data = erp_data; + } + erp->data[erp->n].mjd = v[0]; + erp->data[erp->n].xp = v[1] * 1e-6 * AS2R; + erp->data[erp->n].yp = v[2] * 1e-6 * AS2R; + erp->data[erp->n].ut1_utc = v[3] * 1e-7; + erp->data[erp->n].lod = v[4] * 1e-7; + erp->data[erp->n].xpr = v[12] * 1e-6 * AS2R; + erp->data[erp->n++].ypr = v[13] * 1e-6 * AS2R; + } + fclose(fp); + return 1; +} + + +/* get earth rotation parameter values ----------------------------------------- + * get earth rotation parameter values + * args : erp_t *erp I earth rotation parameters + * gtime_t time I time (gpst) + * double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int geterp(const erp_t *erp, gtime_t time, double *erpv) +{ + const double ep[] = {2000, 1, 1, 12, 0, 0}; + double mjd, day, a; + int i, j, k; + + trace(4, "geterp:\n"); + + if (erp->n <= 0) return 0; + + mjd = 51544.5 + (timediff(gpst2utc(time), epoch2time(ep))) / 86400.0; + + if (mjd <= erp->data[0].mjd) + { + day = mjd - erp->data[0].mjd; + erpv[0] = erp->data[0].xp + erp->data[0].xpr * day; + erpv[1] = erp->data[0].yp + erp->data[0].ypr * day; + erpv[2] = erp->data[0].ut1_utc - erp->data[0].lod * day; + erpv[3] = erp->data[0].lod; + return 1; + } + if (mjd >= erp->data[erp->n - 1].mjd) + { + day = mjd - erp->data[erp->n - 1].mjd; + erpv[0] = erp->data[erp->n - 1].xp + erp->data[erp->n - 1].xpr * day; + erpv[1] = erp->data[erp->n - 1].yp + erp->data[erp->n - 1].ypr * day; + erpv[2] = erp->data[erp->n - 1].ut1_utc - erp->data[erp->n - 1].lod * day; + erpv[3] = erp->data[erp->n - 1].lod; + return 1; + } + for (j = 0, k = erp->n - 1; j < k - 1;) + { + i = (j + k) / 2; + if (mjd < erp->data[i].mjd) + k = i; + else + j = i; + } + if (erp->data[j].mjd == erp->data[j + 1].mjd) + { + a = 0.5; + } + else + { + a = (mjd - erp->data[j].mjd) / (erp->data[j + 1].mjd - erp->data[j].mjd); + } + erpv[0] = (1.0 - a) * erp->data[j].xp + a * erp->data[j + 1].xp; + erpv[1] = (1.0 - a) * erp->data[j].yp + a * erp->data[j + 1].yp; + erpv[2] = (1.0 - a) * erp->data[j].ut1_utc + a * erp->data[j + 1].ut1_utc; + erpv[3] = (1.0 - a) * erp->data[j].lod + a * erp->data[j + 1].lod; + return 1; +} + +/* compare ephemeris ---------------------------------------------------------*/ +int cmpeph(const void *p1, const void *p2) +{ + auto *q1 = (eph_t *)p1, *q2 = (eph_t *)p2; + return q1->ttr.time != q2->ttr.time ? static_cast(q1->ttr.time - q2->ttr.time) : (q1->toe.time != q2->toe.time ? static_cast(q1->toe.time - q2->toe.time) : q1->sat - q2->sat); +} + + +/* sort and unique ephemeris -------------------------------------------------*/ +void uniqeph(nav_t *nav) +{ + eph_t *nav_eph; + int i, j; + + trace(3, "uniqeph: n=%d\n", nav->n); + + if (nav->n <= 0) return; + + qsort(nav->eph, nav->n, sizeof(eph_t), cmpeph); + + for (i = 1, j = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != nav->eph[j].sat || + nav->eph[i].iode != nav->eph[j].iode) + { + nav->eph[++j] = nav->eph[i]; + } + } + nav->n = j + 1; + + if (!(nav_eph = static_cast(realloc(nav->eph, sizeof(eph_t) * nav->n)))) + { + trace(1, "uniqeph malloc error n=%d\n", nav->n); + free(nav->eph); + nav->eph = nullptr; + nav->n = nav->nmax = 0; + return; + } + nav->eph = nav_eph; + nav->nmax = nav->n; + + trace(4, "uniqeph: n=%d\n", nav->n); +} + + +/* compare glonass ephemeris -------------------------------------------------*/ +int cmpgeph(const void *p1, const void *p2) +{ + auto *q1 = (geph_t *)p1, *q2 = (geph_t *)p2; + return q1->tof.time != q2->tof.time ? static_cast(q1->tof.time - q2->tof.time) : (q1->toe.time != q2->toe.time ? static_cast(q1->toe.time - q2->toe.time) : q1->sat - q2->sat); +} + + +/* sort and unique glonass ephemeris -----------------------------------------*/ +void uniqgeph(nav_t *nav) +{ + geph_t *nav_geph; + int i, j; + + trace(3, "uniqgeph: ng=%d\n", nav->ng); + + if (nav->ng <= 0) return; + + qsort(nav->geph, nav->ng, sizeof(geph_t), cmpgeph); + + for (i = j = 0; i < nav->ng; i++) + { + if (nav->geph[i].sat != nav->geph[j].sat || + nav->geph[i].toe.time != nav->geph[j].toe.time || + nav->geph[i].svh != nav->geph[j].svh) + { + nav->geph[++j] = nav->geph[i]; + } + } + nav->ng = j + 1; + + if (!(nav_geph = static_cast(realloc(nav->geph, sizeof(geph_t) * nav->ng)))) + { + trace(1, "uniqgeph malloc error ng=%d\n", nav->ng); + free(nav->geph); + nav->geph = nullptr; + nav->ng = nav->ngmax = 0; + return; + } + nav->geph = nav_geph; + nav->ngmax = nav->ng; + + trace(4, "uniqgeph: ng=%d\n", nav->ng); +} + + +/* compare sbas ephemeris ----------------------------------------------------*/ +int cmpseph(const void *p1, const void *p2) +{ + auto *q1 = (seph_t *)p1, *q2 = (seph_t *)p2; + return q1->tof.time != q2->tof.time ? static_cast(q1->tof.time - q2->tof.time) : (q1->t0.time != q2->t0.time ? static_cast(q1->t0.time - q2->t0.time) : q1->sat - q2->sat); +} + + +/* sort and unique sbas ephemeris --------------------------------------------*/ +void uniqseph(nav_t *nav) +{ + seph_t *nav_seph; + int i, j; + + trace(3, "uniqseph: ns=%d\n", nav->ns); + + if (nav->ns <= 0) return; + + qsort(nav->seph, nav->ns, sizeof(seph_t), cmpseph); + + for (i = j = 0; i < nav->ns; i++) + { + if (nav->seph[i].sat != nav->seph[j].sat || + nav->seph[i].t0.time != nav->seph[j].t0.time) + { + nav->seph[++j] = nav->seph[i]; + } + } + nav->ns = j + 1; + + if (!(nav_seph = static_cast(realloc(nav->seph, sizeof(seph_t) * nav->ns)))) + { + trace(1, "uniqseph malloc error ns=%d\n", nav->ns); + free(nav->seph); + nav->seph = nullptr; + nav->ns = nav->nsmax = 0; + return; + } + nav->seph = nav_seph; + nav->nsmax = nav->ns; + + trace(4, "uniqseph: ns=%d\n", nav->ns); +} + + +/* unique ephemerides ---------------------------------------------------------- + * unique ephemerides in navigation data and update carrier wave length + * args : nav_t *nav IO navigation data + * return : number of epochs + *-----------------------------------------------------------------------------*/ +void uniqnav(nav_t *nav) +{ + int i, j; + + trace(3, "uniqnav: neph=%d ngeph=%d nseph=%d\n", nav->n, nav->ng, nav->ns); + + /* unique ephemeris */ + uniqeph(nav); + uniqgeph(nav); + uniqseph(nav); + + /* update carrier wave length */ + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ; j++) + { + nav->lam[i][j] = satwavelen(i + 1, j, nav); + } +} + + +/* compare observation data -------------------------------------------------*/ +int cmpobs(const void *p1, const void *p2) +{ + auto *q1 = (obsd_t *)p1, *q2 = (obsd_t *)p2; + double tt = timediff(q1->time, q2->time); + if (fabs(tt) > DTTOL) return tt < 0 ? -1 : 1; + if (q1->rcv != q2->rcv) return static_cast(q1->rcv) - static_cast(q2->rcv); + return static_cast(q1->sat) - static_cast(q2->sat); +} + + +/* sort and unique observation data -------------------------------------------- + * sort and unique observation data by time, rcv, sat + * args : obs_t *obs IO observation data + * return : number of epochs + *-----------------------------------------------------------------------------*/ +int sortobs(obs_t *obs) +{ + int i, j, n; + + trace(3, "sortobs: nobs=%d\n", obs->n); + + if (obs->n <= 0) return 0; + + qsort(obs->data, obs->n, sizeof(obsd_t), cmpobs); + + /* delete duplicated data */ + for (i = j = 0; i < obs->n; i++) + { + if (obs->data[i].sat != obs->data[j].sat || + obs->data[i].rcv != obs->data[j].rcv || + timediff(obs->data[i].time, obs->data[j].time) != 0.0) + { + obs->data[++j] = obs->data[i]; + } + } + obs->n = j + 1; + + for (i = n = 0; i < obs->n; i = j, n++) + { + for (j = i + 1; j < obs->n; j++) + { + if (timediff(obs->data[j].time, obs->data[i].time) > DTTOL) break; + } + } + return n; +} + + +/* screen by time -------------------------------------------------------------- + * screening by time start, time end, and time interval + * args : gtime_t time I time + * gtime_t ts I time start (ts.time==0:no screening by ts) + * gtime_t te I time end (te.time==0:no screening by te) + * double tint I time interval (s) (0.0:no screen by tint) + * return : 1:on condition, 0:not on condition + *-----------------------------------------------------------------------------*/ +int screent(gtime_t time, gtime_t ts, gtime_t te, double tint) +{ + return (tint <= 0.0 || fmod(time2gpst(time, nullptr) + DTTOL, tint) <= DTTOL * 2.0) && + (ts.time == 0 || timediff(time, ts) >= -DTTOL) && + (te.time == 0 || timediff(time, te) < DTTOL); +} + + +/* read/save navigation data --------------------------------------------------- + * save or load navigation data + * args : char file I file path + * nav_t nav O/I navigation data + * return : status (1:ok,0:no file) + *-----------------------------------------------------------------------------*/ +int readnav(const char *file, nav_t *nav) +{ + FILE *fp; + eph_t eph0 = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + geph_t geph0 = {0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {}, {}, {}, 0.0, 0.0, 0.0}; + char buff[4096], *p; + int32_t toe_time, tof_time, toc_time, ttr_time; + int i, sat, prn; + + trace(3, "loadnav: file=%s\n", file); + + if (!(fp = fopen(file, "re"))) return 0; + + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "IONUTC", 6)) + { + for (i = 0; i < 8; i++) nav->ion_gps[i] = 0.0; + for (i = 0; i < 4; i++) nav->utc_gps[i] = 0.0; + nav->leaps = 0; + sscanf(buff, "IONUTC,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d", + &nav->ion_gps[0], &nav->ion_gps[1], &nav->ion_gps[2], &nav->ion_gps[3], + &nav->ion_gps[4], &nav->ion_gps[5], &nav->ion_gps[6], &nav->ion_gps[7], + &nav->utc_gps[0], &nav->utc_gps[1], &nav->utc_gps[2], &nav->utc_gps[3], + &nav->leaps); + continue; + } + if ((p = strchr(buff, ','))) + *p = '\0'; + else + continue; + if (!(sat = satid2no(buff))) continue; + if (satsys(sat, &prn) == SYS_GLO) + { + nav->geph[prn - 1] = geph0; + nav->geph[prn - 1].sat = sat; + toe_time = tof_time = 0; + sscanf(p + 1, + "%d,%d,%d,%d,%d,%d,%d,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf," + "%lf,%lf,%lf,%lf", + &nav->geph[prn - 1].iode, &nav->geph[prn - 1].frq, &nav->geph[prn - 1].svh, + &nav->geph[prn - 1].sva, &nav->geph[prn - 1].age, + &toe_time, &tof_time, + &nav->geph[prn - 1].pos[0], &nav->geph[prn - 1].pos[1], &nav->geph[prn - 1].pos[2], + &nav->geph[prn - 1].vel[0], &nav->geph[prn - 1].vel[1], &nav->geph[prn - 1].vel[2], + &nav->geph[prn - 1].acc[0], &nav->geph[prn - 1].acc[1], &nav->geph[prn - 1].acc[2], + &nav->geph[prn - 1].taun, &nav->geph[prn - 1].gamn, &nav->geph[prn - 1].dtaun); + nav->geph[prn - 1].toe.time = toe_time; + nav->geph[prn - 1].tof.time = tof_time; + } + else + { + nav->eph[sat - 1] = eph0; + nav->eph[sat - 1].sat = sat; + toe_time = toc_time = ttr_time = 0; + sscanf(p + 1, + "%d,%d,%d,%d,%d,%d,%d,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf," + "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d", + &nav->eph[sat - 1].iode, &nav->eph[sat - 1].iodc, &nav->eph[sat - 1].sva, + &nav->eph[sat - 1].svh, + &toe_time, &toc_time, &ttr_time, + &nav->eph[sat - 1].A, &nav->eph[sat - 1].e, &nav->eph[sat - 1].i0, + &nav->eph[sat - 1].OMG0, &nav->eph[sat - 1].omg, &nav->eph[sat - 1].M0, + &nav->eph[sat - 1].deln, &nav->eph[sat - 1].OMGd, &nav->eph[sat - 1].idot, + &nav->eph[sat - 1].crc, &nav->eph[sat - 1].crs, &nav->eph[sat - 1].cuc, + &nav->eph[sat - 1].cus, &nav->eph[sat - 1].cic, &nav->eph[sat - 1].cis, + &nav->eph[sat - 1].toes, &nav->eph[sat - 1].fit, &nav->eph[sat - 1].f0, + &nav->eph[sat - 1].f1, &nav->eph[sat - 1].f2, &nav->eph[sat - 1].tgd[0], + &nav->eph[sat - 1].code, &nav->eph[sat - 1].flag); + nav->eph[sat - 1].toe.time = toe_time; + nav->eph[sat - 1].toc.time = toc_time; + nav->eph[sat - 1].ttr.time = ttr_time; + } + } + fclose(fp); + return 1; +} + + +int savenav(const char *file, const nav_t *nav) +{ + FILE *fp; + int i; + char id[32]; + + trace(3, "savenav: file=%s\n", file); + + if (!(fp = fopen(file, "we"))) return 0; + + for (i = 0; i < MAXSAT; i++) + { + if (nav->eph[i].ttr.time == 0) continue; + satno2id(nav->eph[i].sat, id); + fprintf(fp, + "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%d,%d\n", + id, nav->eph[i].iode, nav->eph[i].iodc, nav->eph[i].sva, + nav->eph[i].svh, static_cast(nav->eph[i].toe.time), + static_cast(nav->eph[i].toc.time), static_cast(nav->eph[i].ttr.time), + nav->eph[i].A, nav->eph[i].e, nav->eph[i].i0, nav->eph[i].OMG0, + nav->eph[i].omg, nav->eph[i].M0, nav->eph[i].deln, nav->eph[i].OMGd, + nav->eph[i].idot, nav->eph[i].crc, nav->eph[i].crs, nav->eph[i].cuc, + nav->eph[i].cus, nav->eph[i].cic, nav->eph[i].cis, nav->eph[i].toes, + nav->eph[i].fit, nav->eph[i].f0, nav->eph[i].f1, nav->eph[i].f2, + nav->eph[i].tgd[0], nav->eph[i].code, nav->eph[i].flag); + } + for (i = 0; i < MAXPRNGLO; i++) + { + if (nav->geph[i].tof.time == 0) continue; + satno2id(nav->geph[i].sat, id); + fprintf(fp, + "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E\n", + id, nav->geph[i].iode, nav->geph[i].frq, nav->geph[i].svh, + nav->geph[i].sva, nav->geph[i].age, static_cast(nav->geph[i].toe.time), + static_cast(nav->geph[i].tof.time), + nav->geph[i].pos[0], nav->geph[i].pos[1], nav->geph[i].pos[2], + nav->geph[i].vel[0], nav->geph[i].vel[1], nav->geph[i].vel[2], + nav->geph[i].acc[0], nav->geph[i].acc[1], nav->geph[i].acc[2], + nav->geph[i].taun, nav->geph[i].gamn, nav->geph[i].dtaun); + } + fprintf(fp, + "IONUTC,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%d", + nav->ion_gps[0], nav->ion_gps[1], nav->ion_gps[2], nav->ion_gps[3], + nav->ion_gps[4], nav->ion_gps[5], nav->ion_gps[6], nav->ion_gps[7], + nav->utc_gps[0], nav->utc_gps[1], nav->utc_gps[2], nav->utc_gps[3], + nav->leaps); + + fclose(fp); + return 1; +} + + +/* free observation data ------------------------------------------------------- + * free memory for observation data + * args : obs_t *obs IO observation data + * return : none + *-----------------------------------------------------------------------------*/ +void freeobs(obs_t *obs) +{ + free(obs->data); + obs->data = nullptr; + obs->n = obs->nmax = 0; +} + + +/* free navigation data --------------------------------------------------------- + * free memory for navigation data + * args : nav_t *nav IO navigation data + * int opt I option (or of followings) + * (0x01: gps/qzs ephmeris, 0x02: glonass ephemeris, + * 0x04: sbas ephemeris, 0x08: precise ephemeris, + * 0x10: precise clock 0x20: almanac, + * 0x40: tec data) + * return : none + *-----------------------------------------------------------------------------*/ +void freenav(nav_t *nav, int opt) +{ + if (opt & 0x01) + { + free(nav->eph); + nav->eph = nullptr; + nav->n = nav->nmax = 0; + } + if (opt & 0x02) + { + free(nav->geph); + nav->geph = nullptr; + nav->ng = nav->ngmax = 0; + } + if (opt & 0x04) + { + free(nav->seph); + nav->seph = nullptr; + nav->ns = nav->nsmax = 0; + } + if (opt & 0x08) + { + free(nav->peph); + nav->peph = nullptr; + nav->ne = nav->nemax = 0; + } + if (opt & 0x10) + { + free(nav->pclk); + nav->pclk = nullptr; + nav->nc = nav->ncmax = 0; + } + if (opt & 0x20) + { + free(nav->alm); + nav->alm = nullptr; + nav->na = nav->namax = 0; + } + if (opt & 0x40) + { + free(nav->tec); + nav->tec = nullptr; + nav->nt = nav->ntmax = 0; + } + if (opt & 0x80) + { + free(nav->fcb); + nav->fcb = nullptr; + nav->nf = nav->nfmax = 0; + } +} + + +/* debug trace functions -----------------------------------------------------*/ +//#ifdef TRACE +// +FILE *fp_trace = nullptr; /* file pointer of trace */ +char file_trace[1024]; /* trace file */ +static int level_trace = 0; /* level of trace */ +unsigned int tick_trace = 0; /* tick time at traceopen (ms) */ +gtime_t time_trace = {0, 0.0}; /* time at traceopen */ +pthread_mutex_t lock_trace; /* lock for trace */ + +void traceswap(void) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + rtk_lock(&lock_trace); + + if (static_cast(time2gpst(time, nullptr) / INT_SWAP_TRAC) == + static_cast(time2gpst(time_trace, nullptr) / INT_SWAP_TRAC)) + { + rtk_unlock(&lock_trace); + return; + } + time_trace = time; + + if (!reppath(file_trace, path, time, "", "")) + { + rtk_unlock(&lock_trace); + return; + } + if (fp_trace) fclose(fp_trace); + + if (!(fp_trace = fopen(path, "we"))) + { + fp_trace = stderr; + } + rtk_unlock(&lock_trace); +} + + +void traceopen(const char *file) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + reppath(file, path, time, "", ""); + if (!*path || !(fp_trace = fopen(path, "we"))) fp_trace = stderr; + if (strlen(file) < 1025) + strcpy(file_trace, file); + else + trace(1, "file array is too long"); + tick_trace = tickget(); + time_trace = time; + initlock(&lock_trace); +} + + +void traceclose(void) +{ + if (fp_trace && fp_trace != stderr) fclose(fp_trace); + fp_trace = nullptr; + file_trace[0] = '\0'; +} + + +void tracelevel(int level) +{ + level_trace = level; +} +//extern void trace(int level, const char *format, ...) +//{ +// va_list ap; +// +// /* print error message to stderr */ +// if (level <= 1) { +// va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap); +// } +// if (!fp_trace||level>level_trace) return; +// traceswap(); +// fprintf(fp_trace,"%d ",level); +// va_start(ap,format); vfprintf(fp_trace,format,ap); va_end(ap); +// fflush(fp_trace); +//} + +void tracet(int level, const char *format, ...) +{ + va_list ap; + if (!fp_trace || level > level_trace) return; + traceswap(); + fprintf(fp_trace, "%d %9.3f: ", level, (tickget() - tick_trace) / 1000.0); + va_start(ap, format); + vfprintf(fp_trace, format, ap); + va_end(ap); + fflush(fp_trace); +} + +void tracemat(int level, const double *A, int n, int m, int p, int q) +{ + std::string buffer_; + matsprint(A, n, m, p, q, buffer_); + VLOG(level) << buffer_; +} + + +void traceobs(int level __attribute__((unused)), const obsd_t *obs __attribute__((unused)), int n __attribute__((unused))) +{ + // char str[64],id[16]; + // int i; + // + // if (!fp_trace||level>level_trace) return; + // for (i=0;ilevel_trace) return; +// for (i=0;in;i++) { +// time2str(nav->eph[i].toe,s1,0); +// time2str(nav->eph[i].ttr,s2,0); +// satno2id(nav->eph[i].sat,id); +// fprintf(fp_trace,"(%3d) %-3s : %s %s %3d %3d %02x\n",i+1, +// id,s1,s2,nav->eph[i].iode,nav->eph[i].iodc,nav->eph[i].svh); +// } +// fprintf(fp_trace,"(ion) %9.4e %9.4e %9.4e %9.4e\n",nav->ion_gps[0], +// nav->ion_gps[1],nav->ion_gps[2],nav->ion_gps[3]); +// fprintf(fp_trace,"(ion) %9.4e %9.4e %9.4e %9.4e\n",nav->ion_gps[4], +// nav->ion_gps[5],nav->ion_gps[6],nav->ion_gps[7]); +// fprintf(fp_trace,"(ion) %9.4e %9.4e %9.4e %9.4e\n",nav->ion_gal[0], +// nav->ion_gal[1],nav->ion_gal[2],nav->ion_gal[3]); +//} +//extern void tracegnav(int level, const nav_t *nav) +//{ +// char s1[64],s2[64],id[16]; +// int i; +// +// if (!fp_trace||level>level_trace) return; +// for (i=0;ing;i++) { +// time2str(nav->geph[i].toe,s1,0); +// time2str(nav->geph[i].tof,s2,0); +// satno2id(nav->geph[i].sat,id); +// fprintf(fp_trace,"(%3d) %-3s : %s %s %2d %2d %8.3f\n",i+1, +// id,s1,s2,nav->geph[i].frq,nav->geph[i].svh,nav->geph[i].taun*1e6); +// } +//} +//extern void tracehnav(int level, const nav_t *nav) +//{ +// char s1[64],s2[64],id[16]; +// int i; +// +// if (!fp_trace||level>level_trace) return; +// for (i=0;ins;i++) { +// time2str(nav->seph[i].t0,s1,0); +// time2str(nav->seph[i].tof,s2,0); +// satno2id(nav->seph[i].sat,id); +// fprintf(fp_trace,"(%3d) %-3s : %s %s %2d %2d\n",i+1, +// id,s1,s2,nav->seph[i].svh,nav->seph[i].sva); +// } +//} +//extern void tracepeph(int level, const nav_t *nav) +//{ +// char s[64],id[16]; +// int i,j; +// +// if (!fp_trace||level>level_trace) return; +// +// for (i=0;ine;i++) { +// time2str(nav->peph[i].time,s,0); +// for (j=0;jpeph[i].index,id, +// nav->peph[i].pos[j][0],nav->peph[i].pos[j][1], +// nav->peph[i].pos[j][2],nav->peph[i].pos[j][3]*1e9, +// nav->peph[i].std[j][0],nav->peph[i].std[j][1], +// nav->peph[i].std[j][2],nav->peph[i].std[j][3]*1e9); +// } +// } +//} +//extern void tracepclk(int level, const nav_t *nav) +//{ +// char s[64],id[16]; +// int i,j; +// +// if (!fp_trace||level>level_trace) return; +// +// for (i=0;inc;i++) { +// time2str(nav->pclk[i].time,s,0); +// for (j=0;jpclk[i].index,id, +// nav->pclk[i].clk[j][0]*1e9,nav->pclk[i].std[j][0]*1e9); +// } +// } +//} +//extern void traceb(int level, const unsigned char *p, int n) +//{ +// int i; +// if (!fp_trace||level>level_trace) return; +// for (i=0;i:error) + *-----------------------------------------------------------------------------*/ +int execcmd(const char *cmd) +{ + trace(3, "execcmd: cmd=%s\n", cmd); + return system(cmd); +} + + +/* create directory ------------------------------------------------------------ + * create directory if not exist + * args : char *path I file path to be saved + * return : none + * notes : not recursive. only one level + *-----------------------------------------------------------------------------*/ +void createdir(const char *path) +{ + char buff[1024], *p; + //tracet(3, "createdir: path=%s\n", path); + + if (strlen(path) < 1025) + strcpy(buff, path); + else + trace(1, "path is too long"); + if (!(p = strrchr(buff, FILEPATHSEP))) return; + *p = '\0'; + + if (mkdir(buff, 0777) != 0) trace(1, "Error creating folder"); +} + + +/* replace string ------------------------------------------------------------*/ +int repstr(char *str, const char *pat, const char *rep) +{ + int len = static_cast(strlen(pat)); + char buff[1024], *p, *q, *r; + + for (p = str, r = buff; *p; p = q + len) + { + if (!(q = strstr(p, pat))) break; + strncpy(r, p, q - p); + r += q - p; + r += sprintf(r, "%s", rep); + } + if (p <= str) return 0; + + if (strlen(p) < 1025) + strcpy(r, p); + else + trace(1, "pat array is too long"); + strcpy(str, buff); + return 1; +} + + +/* replace keywords in file path ----------------------------------------------- + * replace keywords in file path with date, time, rover and base station id + * args : char *path I file path (see below) + * char *rpath O file path in which keywords replaced (see below) + * gtime_t time I time (gpst) (time.time==0: not replaced) + * char *rov I rover id string ("": not replaced) + * char *base I base station id string ("": not replaced) + * return : status (1:keywords replaced, 0:no valid keyword in the path, + * -1:no valid time) + * notes : the following keywords in path are replaced by date, time and name + * %Y -> yyyy : year (4 digits) (1900-2099) + * %y -> yy : year (2 digits) (00-99) + * %m -> mm : month (01-12) + * %d -> dd : day of month (01-31) + * %h -> hh : hours (00-23) + * %M -> mm : minutes (00-59) + * %S -> ss : seconds (00-59) + * %n -> ddd : day of year (001-366) + * %W -> wwww : gps week (0001-9999) + * %D -> d : day of gps week (0-6) + * %H -> h : hour code (a=0,b=1,c=2,...,x=23) + * %ha-> hh : 3 hours (00,03,06,...,21) + * %hb-> hh : 6 hours (00,06,12,18) + * %hc-> hh : 12 hours (00,12) + * %t -> mm : 15 minutes (00,15,30,45) + * %r -> rrrr : rover id + * %b -> bbbb : base station id + *-----------------------------------------------------------------------------*/ +int reppath(const char *path, char *rpath, gtime_t time, const char *rov, + const char *base) +{ + double ep[6], ep0[6] = {2000, 1, 1, 0, 0, 0}; + int week, dow, doy, stat = 0; + char rep[64]; + + strcpy(rpath, path); + + if (!strstr(rpath, "%")) return 0; + if (*rov) stat |= repstr(rpath, "%r", rov); + if (*base) stat |= repstr(rpath, "%b", base); + if (time.time != 0) + { + time2epoch(time, ep); + ep0[0] = ep[0]; + dow = static_cast(floor(time2gpst(time, &week) / 86400.0)); + doy = static_cast(floor(timediff(time, epoch2time(ep0)) / 86400.0)) + 1; + sprintf(rep, "%02d", (static_cast(ep[3]) / 3) * 3); + stat |= repstr(rpath, "%ha", rep); + sprintf(rep, "%02d", (static_cast(ep[3]) / 6) * 6); + stat |= repstr(rpath, "%hb", rep); + sprintf(rep, "%02d", (static_cast(ep[3]) / 12) * 12); + stat |= repstr(rpath, "%hc", rep); + sprintf(rep, "%04.0f", ep[0]); + stat |= repstr(rpath, "%Y", rep); + sprintf(rep, "%02.0f", fmod(ep[0], 100.0)); + stat |= repstr(rpath, "%y", rep); + sprintf(rep, "%02.0f", ep[1]); + stat |= repstr(rpath, "%m", rep); + sprintf(rep, "%02.0f", ep[2]); + stat |= repstr(rpath, "%d", rep); + sprintf(rep, "%02.0f", ep[3]); + stat |= repstr(rpath, "%h", rep); + sprintf(rep, "%02.0f", ep[4]); + stat |= repstr(rpath, "%M", rep); + sprintf(rep, "%02.0f", floor(ep[5])); + stat |= repstr(rpath, "%S", rep); + sprintf(rep, "%03d", doy); + stat |= repstr(rpath, "%n", rep); + sprintf(rep, "%04d", week); + stat |= repstr(rpath, "%W", rep); + sprintf(rep, "%d", dow); + stat |= repstr(rpath, "%D", rep); + sprintf(rep, "%c", 'a' + static_cast(ep[3])); + stat |= repstr(rpath, "%H", rep); + sprintf(rep, "%02d", (static_cast(ep[4]) / 15) * 15); + stat |= repstr(rpath, "%t", rep); + } + else if (strstr(rpath, "%ha") || strstr(rpath, "%hb") || strstr(rpath, "%hc") || + strstr(rpath, "%Y") || strstr(rpath, "%y") || strstr(rpath, "%m") || + strstr(rpath, "%d") || strstr(rpath, "%h") || strstr(rpath, "%M") || + strstr(rpath, "%S") || strstr(rpath, "%n") || strstr(rpath, "%W") || + strstr(rpath, "%D") || strstr(rpath, "%H") || strstr(rpath, "%t")) + { + return -1; /* no valid time */ + } + return stat; +} + + +/* replace keywords in file path and generate multiple paths ------------------- + * replace keywords in file path with date, time, rover and base station id + * generate multiple keywords-replaced paths + * args : char *path I file path (see below) + * char *rpath[] O file paths in which keywords replaced + * int nmax I max number of output file paths + * gtime_t ts I time start (gpst) + * gtime_t te I time end (gpst) + * char *rov I rover id string ("": not replaced) + * char *base I base station id string ("": not replaced) + * return : number of replaced file paths + * notes : see reppath() for replacements of keywords. + * minimum interval of time replaced is 900s. + *-----------------------------------------------------------------------------*/ +int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts, + gtime_t te, const char *rov, const char *base) +{ + gtime_t time; + double tow, tint = 86400.0; + int i, n = 0, week; + + trace(3, "reppaths: path =%s nmax=%d rov=%s base=%s\n", path, nmax, rov, base); + + if (ts.time == 0 || te.time == 0 || timediff(ts, te) > 0.0) return 0; + + if (strstr(path, "%S") || strstr(path, "%M") || strstr(path, "%t")) + tint = 900.0; + else if (strstr(path, "%h") || strstr(path, "%H")) + tint = 3600.0; + + tow = time2gpst(ts, &week); + time = gpst2time(week, floor(tow / tint) * tint); + + while (timediff(time, te) <= 0.0 && n < nmax) + { + reppath(path, rpath[n], time, rov, base); + if (n == 0 || strcmp(rpath[n], rpath[n - 1]) != 0) n++; + time = timeadd(time, tint); + } + for (i = 0; i < n; i++) trace(3, "reppaths: rpath=%s\n", rpath[i]); + return n; +} + + +/* satellite carrier wave length ----------------------------------------------- + * get satellite carrier wave lengths + * args : int sat I satellite number + * int frq I frequency index (0:L1,1:L2,2:L5/3,...) + * nav_t *nav I navigation messages + * return : carrier wave length (m) (0.0: error) + *-----------------------------------------------------------------------------*/ +double satwavelen(int sat, int frq, const nav_t *nav) +{ + const double freq_glo[] = {FREQ1_GLO, FREQ2_GLO}; + const double dfrq_glo[] = {DFRQ1_GLO, DFRQ2_GLO}; + int i, sys = satsys(sat, nullptr); + + if (sys == SYS_GLO) + { + if (0 <= frq && frq <= 1) + { + for (i = 0; i < nav->ng; i++) + { + if (nav->geph[i].sat != sat) continue; + return SPEED_OF_LIGHT / (freq_glo[frq] + dfrq_glo[frq] * nav->geph[i].frq); + } + } + else if (frq == 2) + { /* L3 */ + return SPEED_OF_LIGHT / FREQ3_GLO; + } + } + else if (sys == SYS_BDS) + { + if (frq == 0) + return SPEED_OF_LIGHT / FREQ1_BDS; /* B1 */ + if (frq == 1) + return SPEED_OF_LIGHT / FREQ2_BDS; /* B2 */ + if (frq == 2) + return SPEED_OF_LIGHT / FREQ3_BDS; /* B3 */ + } + else + { + if (frq == 0) + return SPEED_OF_LIGHT / FREQ1; /* L1/E1 */ + if (frq == 1) + return SPEED_OF_LIGHT / FREQ2; /* L2 */ + if (frq == 2) + return SPEED_OF_LIGHT / FREQ5; /* L5/E5a */ + if (frq == 3) + return SPEED_OF_LIGHT / FREQ6; /* L6/LEX */ + if (frq == 4) + return SPEED_OF_LIGHT / FREQ7; /* E5b */ + else if (frq == 5) + return SPEED_OF_LIGHT / FREQ8; /* E5a+b */ + else if (frq == 6) + return SPEED_OF_LIGHT / FREQ9; /* S */ + } + return 0.0; +} + + +/* geometric distance ---------------------------------------------------------- + * compute geometric distance and receiver-to-satellite unit vector + * args : double *rs I satellilte position (ecef at transmission) (m) + * double *rr I receiver position (ecef at reception) (m) + * double *e O line-of-sight vector (ecef) + * return : geometric distance (m) (0>:error/no satellite position) + * notes : distance includes sagnac effect correction + *-----------------------------------------------------------------------------*/ +double geodist(const double *rs, const double *rr, double *e) +{ + double r; + int i; + + if (norm_rtk(rs, 3) < RE_WGS84) return -1.0; + for (i = 0; i < 3; i++) e[i] = rs[i] - rr[i]; + r = norm_rtk(e, 3); + for (i = 0; i < 3; i++) e[i] /= r; + return r + DEFAULT_OMEGA_EARTH_DOT * (rs[0] * rr[1] - rs[1] * rr[0]) / SPEED_OF_LIGHT; +} + + +/* satellite azimuth/elevation angle ------------------------------------------- + * compute satellite azimuth/elevation angle + * args : double *pos I geodetic position {lat,lon,h} (rad,m) + * double *e I receiver-to-satellilte unit vector (ecef) + * double *azel IO azimuth/elevation {az,el} (rad) (NULL: no output) + * (0.0<=azel[0]<2*pi,-pi/2<=azel[1]<=pi/2) + * return : elevation angle (rad) + *-----------------------------------------------------------------------------*/ +double satazel(const double *pos, const double *e, double *azel) +{ + double az = 0.0, el = PI / 2.0, enu[3]; + + if (pos[2] > -RE_WGS84) + { + ecef2enu(pos, e, enu); + az = dot(enu, enu, 2) < 1e-12 ? 0.0 : atan2(enu[0], enu[1]); + if (az < 0.0) az += 2 * PI; + el = asin(enu[2]); + } + if (azel) + { + azel[0] = az; + azel[1] = el; + } + return el; +} + + +/* compute dops ---------------------------------------------------------------- + * compute DOP (dilution of precision) + * args : int ns I number of satellites + * double *azel I satellite azimuth/elevation angle (rad) + * double elmin I elevation cutoff angle (rad) + * double *dop O DOPs {GDOP,PDOP,HDOP,VDOP} + * return : none + * notes : dop[0]-[3] return 0 in case of dop computation error + *-----------------------------------------------------------------------------*/ +void dops(int ns, const double *azel, double elmin, double *dop) +{ + double H[4 * MAXSAT], Q[16], cosel, sinel; + int i, n; + + for (i = 0; i < 4; i++) dop[i] = 0.0; + for (i = n = 0; i < ns && i < MAXSAT; i++) + { + if (azel[1 + i * 2] < elmin || azel[1 + i * 2] <= 0.0) continue; + cosel = cos(azel[1 + i * 2]); + sinel = sin(azel[1 + i * 2]); + H[4 * n] = cosel * sin(azel[i * 2]); + H[1 + 4 * n] = cosel * cos(azel[i * 2]); + H[2 + 4 * n] = sinel; + H[3 + 4 * n++] = 1.0; + } + if (n < 4) return; + + matmul("NT", 4, 4, n, 1.0, H, H, 0.0, Q); + if (!matinv(Q, 4)) + { + dop[0] = std::sqrt(Q[0] + Q[5] + Q[10] + Q[15]); /* GDOP */ + dop[1] = std::sqrt(Q[0] + Q[5] + Q[10]); /* PDOP */ + dop[2] = std::sqrt(Q[0] + Q[5]); /* HDOP */ + dop[3] = std::sqrt(Q[10]); /* VDOP */ + } +} + + +/* ionosphere model ------------------------------------------------------------ + * compute ionospheric delay by broadcast ionosphere model (klobuchar model) + * args : gtime_t t I time (gpst) + * double *ion I iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * return : ionospheric delay (L1) (m) + *-----------------------------------------------------------------------------*/ +double ionmodel(gtime_t t, const double *ion, const double *pos, + const double *azel) +{ + const double ion_default[] = {/* 2004/1/1 */ + 0.1118E-07, -0.7451e-08, -0.5961e-07, 0.1192E-06, + 0.1167E+06, -0.2294E+06, -0.1311e+06, 0.1049E+07}; + double tt, f, psi, phi, lam, amp, per, x; + int week; + + if (pos[2] < -1e3 || azel[1] <= 0) return 0.0; + if (norm_rtk(ion, 8) <= 0.0) ion = ion_default; + + /* earth centered angle (semi-circle) */ + psi = 0.0137 / (azel[1] / PI + 0.11) - 0.022; + + /* subionospheric latitude/longitude (semi-circle) */ + phi = pos[0] / PI + psi * cos(azel[0]); + if (phi > 0.416) + phi = 0.416; + else if (phi < -0.416) + phi = -0.416; + lam = pos[1] / PI + psi * sin(azel[0]) / cos(phi * PI); + + /* geomagnetic latitude (semi-circle) */ + phi += 0.064 * cos((lam - 1.617) * PI); + + /* local time (s) */ + tt = 43200.0 * lam + time2gpst(t, &week); + tt -= floor(tt / 86400.0) * 86400.0; /* 0 <= tt<86400 */ + + /* slant factor */ + f = 1.0 + 16.0 * pow(0.53 - azel[1] / PI, 3.0); + + /* ionospheric delay */ + amp = ion[0] + phi * (ion[1] + phi * (ion[2] + phi * ion[3])); + per = ion[4] + phi * (ion[5] + phi * (ion[6] + phi * ion[7])); + amp = amp < 0.0 ? 0.0 : amp; + per = per < 72000.0 ? 72000.0 : per; + x = 2.0 * PI * (tt - 50400.0) / per; + + return SPEED_OF_LIGHT * f * (fabs(x) < 1.57 ? 5E-9 + amp * (1.0 + x * x * (-0.5 + x * x / 24.0)) : 5E-9); +} + + +/* ionosphere mapping function ------------------------------------------------- + * compute ionospheric delay mapping function by single layer model + * args : double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * return : ionospheric mapping function + *-----------------------------------------------------------------------------*/ +double ionmapf(const double *pos, const double *azel) +{ + if (pos[2] >= HION) return 1.0; + return 1.0 / cos(asin((RE_WGS84 + pos[2]) / (RE_WGS84 + HION) * sin(PI / 2.0 - azel[1]))); +} + + +/* ionospheric pierce point position ------------------------------------------- + * compute ionospheric pierce point (ipp) position and slant factor + * args : double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double re I earth radius (km) + * double hion I altitude of ionosphere (km) + * double *posp O pierce point position {lat,lon,h} (rad,m) + * return : slant factor + * notes : see ref [2], only valid on the earth surface + * fixing bug on ref [2] A.4.4.10.1 A-22,23 + *-----------------------------------------------------------------------------*/ +double ionppp(const double *pos, const double *azel, double re, + double hion, double *posp) +{ + double cosaz, rp, ap, sinap, tanap; + + rp = re / (re + hion) * cos(azel[1]); + ap = PI / 2.0 - azel[1] - asin(rp); + sinap = sin(ap); + tanap = tan(ap); + cosaz = cos(azel[0]); + posp[0] = asin(sin(pos[0]) * cos(ap) + cos(pos[0]) * sinap * cosaz); + + if ((pos[0] > 70.0 * D2R && tanap * cosaz > tan(PI / 2.0 - pos[0])) || + (pos[0] < -70.0 * D2R && -tanap * cosaz > tan(PI / 2.0 + pos[0]))) + { + posp[1] = pos[1] + PI - asin(sinap * sin(azel[0]) / cos(posp[0])); + } + else + { + posp[1] = pos[1] + asin(sinap * sin(azel[0]) / cos(posp[0])); + } + return 1.0 / sqrt(1.0 - rp * rp); +} + + +/* troposphere model ----------------------------------------------------------- + * compute tropospheric delay by standard atmosphere and saastamoinen model + * args : gtime_t time I time + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double humi I relative humidity + * return : tropospheric delay (m) + *-----------------------------------------------------------------------------*/ +double tropmodel(gtime_t time __attribute__((unused)), const double *pos, const double *azel, + double humi) +{ + const double temp0 = 15.0; /* temparature at sea level */ + double hgt, pres, temp, e, z, trph, trpw; + + if (pos[2] < -100.0 || 1e4 < pos[2] || azel[1] <= 0) return 0.0; + + /* standard atmosphere */ + hgt = pos[2] < 0.0 ? 0.0 : pos[2]; + + pres = 1013.25 * pow(1.0 - 2.2557E-5 * hgt, 5.2568); + temp = temp0 - 6.5E-3 * hgt + 273.16; + e = 6.108 * humi * exp((17.15 * temp - 4684.0) / (temp - 38.45)); + + /* saastamoninen model */ + z = PI / 2.0 - azel[1]; + trph = 0.0022768 * pres / (1.0 - 0.00266 * cos(2.0 * pos[0]) - 0.00028 * hgt / 1e3) / cos(z); + trpw = 0.002277 * (1255.0 / temp + 0.05) * e / cos(z); + return trph + trpw; +} +#ifndef IERS_MODEL + + +double interpc(const double coef[], double lat) +{ + int i = static_cast(lat / 15.0); + if (i < 1) + return coef[0]; + if (i > 4) + return coef[4]; + return coef[i - 1] * (1.0 - lat / 15.0 + i) + coef[i] * (lat / 15.0 - i); +} + + +double mapf(double el, double a, double b, double c) +{ + double sinel = sin(el); + return (1.0 + a / (1.0 + b / (1.0 + c))) / (sinel + (a / (sinel + b / (sinel + c)))); +} + + +double nmf(gtime_t time, const double pos[], const double azel[], + double *mapfw) +{ + /* ref [5] table 3 */ + /* hydro-ave-a,b,c, hydro-amp-a,b,c, wet-a,b,c at latitude 15,30,45,60,75 */ + const double coef[][5] = { + {1.2769934E-3, 1.2683230E-3, 1.2465397E-3, 1.2196049E-3, 1.2045996E-3}, + {2.9153695E-3, 2.9152299E-3, 2.9288445E-3, 2.9022565E-3, 2.9024912E-3}, + {62.610505E-3, 62.837393E-3, 63.721774E-3, 63.824265E-3, 64.258455E-3}, + + {0.0000000E-0, 1.2709626E-5, 2.6523662E-5, 3.4000452E-5, 4.1202191e-5}, + {0.0000000E-0, 2.1414979E-5, 3.0160779E-5, 7.2562722E-5, 11.723375E-5}, + {0.0000000E-0, 9.0128400E-5, 4.3497037E-5, 84.795348E-5, 170.37206E-5}, + + {5.8021897E-4, 5.6794847E-4, 5.8118019E-4, 5.9727542E-4, 6.1641693E-4}, + {1.4275268E-3, 1.5138625E-3, 1.4572752E-3, 1.5007428E-3, 1.7599082E-3}, + {4.3472961e-2, 4.6729510E-2, 4.3908931e-2, 4.4626982E-2, 5.4736038E-2}}; + const double aht[] = {2.53E-5, 5.49E-3, 1.14E-3}; /* height correction */ + + double y, cosy, ah[3], aw[3], dm, el = azel[1], lat = pos[0] * R2D, hgt = pos[2]; + int i; + + if (el <= 0.0) + { + if (mapfw) *mapfw = 0.0; + return 0.0; + } + /* year from doy 28, added half a year for southern latitudes */ + y = (time2doy(time) - 28.0) / 365.25 + (lat < 0.0 ? 0.5 : 0.0); + + cosy = cos(2.0 * PI * y); + lat = fabs(lat); + + for (i = 0; i < 3; i++) + { + ah[i] = interpc(coef[i], lat) - interpc(coef[i + 3], lat) * cosy; + aw[i] = interpc(coef[i + 6], lat); + } + /* ellipsoidal height is used instead of height above sea level */ + dm = (1.0 / sin(el) - mapf(el, aht[0], aht[1], aht[2])) * hgt / 1e3; + + if (mapfw) *mapfw = mapf(el, aw[0], aw[1], aw[2]); + + return mapf(el, ah[0], ah[1], ah[2]) + dm; +} +#endif /* !IERS_MODEL */ + + +/* troposphere mapping function ------------------------------------------------ + * compute tropospheric mapping function by NMF + * args : gtime_t t I time + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double *mapfw IO wet mapping function (NULL: not output) + * return : dry mapping function + * note : see ref [5] (NMF) and [9] (GMF) + * original JGR paper of [5] has bugs in eq.(4) and (5). the corrected + * paper is obtained from: + * ftp://web.haystack.edu/pub/aen/nmf/NMF_JGR.pdf + *-----------------------------------------------------------------------------*/ +double tropmapf(gtime_t time, const double pos[], const double azel[], + double *mapfw) +{ +#ifdef IERS_MODEL + const double ep[] = {2000, 1, 1, 12, 0, 0}; + double mjd, lat, lon, hgt, zd, gmfh, gmfw; +#endif + trace(4, "tropmapf: pos=%10.6f %11.6f %6.1f azel=%5.1f %4.1f\n", + pos[0] * R2D, pos[1] * R2D, pos[2], azel[0] * R2D, azel[1] * R2D); + + if (pos[2] < -1000.0 || pos[2] > 20000.0) + { + if (mapfw) *mapfw = 0.0; + return 0.0; + } +#ifdef IERS_MODEL + mjd = 51544.5 + (timediff(time, epoch2time(ep))) / 86400.0; + lat = pos[0]; + lon = pos[1]; + hgt = pos[2] - geoidh(pos); /* height in m (mean sea level) */ + zd = PI / 2.0 - azel[1]; + + /* call GMF */ + gmf_(&mjd, &lat, &lon, &hgt, &zd, &gmfh, &gmfw); + + if (mapfw) *mapfw = gmfw; + return gmfh; +#else + return nmf(time, pos, azel, mapfw); /* NMF */ +#endif +} + + +/* interpolate antenna phase center variation --------------------------------*/ +double interpvar(double ang, const double *var) +{ + double a = ang / 5.0; /* ang=0-90 */ + int i = static_cast(a); + if (i < 0) + return var[0]; + if (i >= 18) + return var[18]; + return var[i] * (1.0 - a + i) + var[i + 1] * (a - i); +} + + +/* receiver antenna model ------------------------------------------------------ + * compute antenna offset by antenna phase center parameters + * args : pcv_t *pcv I antenna phase center parameters + * double *azel I azimuth/elevation for receiver {az,el} (rad) + * int opt I option (0:only offset,1:offset+pcv) + * double *dant O range offsets for each frequency (m) + * return : none + * notes : current version does not support azimuth dependent terms + *-----------------------------------------------------------------------------*/ +void antmodel(const pcv_t *pcv, const double *del, const double *azel, + int opt, double *dant) +{ + double e[3], off[3], cosel = cos(azel[1]); + int i, j; + + trace(4, "antmodel: azel=%6.1f %4.1f opt=%d\n", azel[0] * R2D, azel[1] * R2D, opt); + + e[0] = sin(azel[0]) * cosel; + e[1] = cos(azel[0]) * cosel; + e[2] = sin(azel[1]); + + for (i = 0; i < NFREQ; i++) + { + for (j = 0; j < 3; j++) off[j] = pcv->off[i][j] + del[j]; + + dant[i] = -dot(off, e, 3) + (opt ? interpvar(90.0 - azel[1] * R2D, pcv->var[i]) : 0.0); + } + trace(5, "antmodel: dant=%6.3f %6.3f\n", dant[0], dant[1]); +} + + +/* satellite antenna model ------------------------------------------------------ + * compute satellite antenna phase center parameters + * args : pcv_t *pcv I antenna phase center parameters + * double nadir I nadir angle for satellite (rad) + * double *dant O range offsets for each frequency (m) + * return : none + *-----------------------------------------------------------------------------*/ +void antmodel_s(const pcv_t *pcv, double nadir, double *dant) +{ + int i; + + trace(4, "antmodel_s: nadir=%6.1f\n", nadir * R2D); + + for (i = 0; i < NFREQ; i++) + { + dant[i] = interpvar(nadir * R2D * 5.0, pcv->var[i]); + } + trace(5, "antmodel_s: dant=%6.3f %6.3f\n", dant[0], dant[1]); +} + + +/* sun and moon position in eci (ref [4] 5.1.1, 5.2.1) -----------------------*/ +void sunmoonpos_eci(gtime_t tut, double *rsun, double *rmoon) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + double t, f[5], eps, Ms, ls, rs, lm, pm, rm, sine, cose, sinp, cosp, sinl, cosl; + + trace(4, "sunmoonpos_eci: tut=%s\n", time_str(tut, 3)); + + t = timediff(tut, epoch2time(ep2000)) / 86400.0 / 36525.0; + + /* astronomical arguments */ + ast_args(t, f); + + /* obliquity of the ecliptic */ + eps = 23.439291 - 0.0130042 * t; + sine = sin(eps * D2R); + cose = cos(eps * D2R); + + /* sun position in eci */ + if (rsun) + { + Ms = 357.5277233 + 35999.05034 * t; + ls = 280.460 + 36000.770 * t + 1.914666471 * sin(Ms * D2R) + 0.019994643 * sin(2.0 * Ms * D2R); + rs = AU * (1.000140612 - 0.016708617 * cos(Ms * D2R) - 0.000139589 * cos(2.0 * Ms * D2R)); + sinl = sin(ls * D2R); + cosl = cos(ls * D2R); + rsun[0] = rs * cosl; + rsun[1] = rs * cose * sinl; + rsun[2] = rs * sine * sinl; + + trace(5, "rsun =%.3f %.3f %.3f\n", rsun[0], rsun[1], rsun[2]); + } + /* moon position in eci */ + if (rmoon) + { + lm = 218.32 + 481267.883 * t + 6.29 * sin(f[0]) - 1.27 * sin(f[0] - 2.0 * f[3]) + + 0.66 * sin(2.0 * f[3]) + 0.21 * sin(2.0 * f[0]) - 0.19 * sin(f[1]) - 0.11 * sin(2.0 * f[2]); + pm = 5.13 * sin(f[2]) + 0.28 * sin(f[0] + f[2]) - 0.28 * sin(f[2] - f[0]) - + 0.17 * sin(f[2] - 2.0 * f[3]); + rm = RE_WGS84 / sin((0.9508 + 0.0518 * cos(f[0]) + 0.0095 * cos(f[0] - 2.0 * f[3]) + + 0.0078 * cos(2.0 * f[3]) + 0.0028 * cos(2.0 * f[0])) * + D2R); + sinl = sin(lm * D2R); + cosl = cos(lm * D2R); + sinp = sin(pm * D2R); + cosp = cos(pm * D2R); + rmoon[0] = rm * cosp * cosl; + rmoon[1] = rm * (cose * cosp * sinl - sine * sinp); + rmoon[2] = rm * (sine * cosp * sinl + cose * sinp); + + trace(5, "rmoon=%.3f %.3f %.3f\n", rmoon[0], rmoon[1], rmoon[2]); + } +} + + +/* sun and moon position ------------------------------------------------------- + * get sun and moon position in ecef + * args : gtime_t tut I time in ut1 + * double *erpv I erp value {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) + * double *rsun IO sun position in ecef (m) (NULL: not output) + * double *rmoon IO moon position in ecef (m) (NULL: not output) + * double *gmst O gmst (rad) + * return : none + *-----------------------------------------------------------------------------*/ +void sunmoonpos(gtime_t tutc, const double *erpv, double *rsun, + double *rmoon, double *gmst) +{ + gtime_t tut; + double rs[3], rm[3], U[9], gmst_; + + trace(4, "sunmoonpos: tutc=%s\n", time_str(tutc, 3)); + + tut = timeadd(tutc, erpv[2]); /* utc -> ut1 */ + + /* sun and moon position in eci */ + sunmoonpos_eci(tut, rsun ? rs : nullptr, rmoon ? rm : nullptr); + + /* eci to ecef transformation matrix */ + eci2ecef(tutc, erpv, U, &gmst_); + + /* sun and moon position in ecef */ + if (rsun) matmul("NN", 3, 1, 3, 1.0, U, rs, 0.0, rsun); + if (rmoon) matmul("NN", 3, 1, 3, 1.0, U, rm, 0.0, rmoon); + if (gmst) *gmst = gmst_; +} + + +/* carrier smoothing ----------------------------------------------------------- + * carrier smoothing by Hatch filter + * args : obs_t *obs IO raw observation data/smoothed observation data + * int ns I smoothing window size (epochs) + * return : none + *-----------------------------------------------------------------------------*/ +void csmooth(obs_t *obs, int ns) +{ + double Ps[2][MAXSAT][NFREQ] = {}, Lp[2][MAXSAT][NFREQ] = {}, dcp; + int i, j, s, r, n[2][MAXSAT][NFREQ] = {}; + obsd_t *p; + + trace(3, "csmooth: nobs=%d,ns=%d\n", obs->n, ns); + + for (i = 0; i < obs->n; i++) + { + p = &obs->data[i]; + s = p->sat; + r = p->rcv; + for (j = 0; j < NFREQ; j++) + { + if (s <= 0 || MAXSAT < s || r <= 0 || 2 < r) continue; + if (p->P[j] == 0.0 || p->L[j] == 0.0) continue; + if (p->LLI[j]) n[r - 1][s - 1][j] = 0; + if (n[r - 1][s - 1][j] == 0) + Ps[r - 1][s - 1][j] = p->P[j]; + else + { + dcp = lam_carr[j] * (p->L[j] - Lp[r - 1][s - 1][j]); + Ps[r - 1][s - 1][j] = p->P[j] / ns + (Ps[r - 1][s - 1][j] + dcp) * (ns - 1) / ns; + } + if (++n[r - 1][s - 1][j] < ns) + p->P[j] = 0.0; + else + p->P[j] = Ps[r - 1][s - 1][j]; + Lp[r - 1][s - 1][j] = p->L[j]; + } + } +} + + +/* uncompress file ------------------------------------------------------------- + * uncompress (uncompress/unzip/uncompact hatanaka-compression/tar) file + * args : char *file I input file + * char *uncfile O uncompressed file + * return : status (-1:error,0:not compressed file,1:uncompress completed) + * note : creates uncompressed file in tempolary directory + * gzip and crx2rnx commands have to be installed in commands path + *-----------------------------------------------------------------------------*/ +int rtk_uncompress(const char *file, char *uncfile) +{ + int stat = 0; + char *p, cmd[2048] = "", tmpfile[1024] = "", buff[1024], *fname, *dir = (char *)""; + + trace(3, "rtk_uncompress: file=%s\n", file); + + if (strlen(file) < 1025) + strcpy(tmpfile, file); + else + trace(1, "file array is too long"); + if (!(p = strrchr(tmpfile, '.'))) return 0; + + /* uncompress by gzip */ + if (!strcmp(p, ".z") || !strcmp(p, ".Z") || + !strcmp(p, ".gz") || !strcmp(p, ".GZ") || + !strcmp(p, ".zip") || !strcmp(p, ".ZIP")) + { + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile] = '\0'; + sprintf(cmd, R"(gzip -f -d -c "%s" > "%s")", tmpfile, uncfile); + + if (execcmd(cmd)) + { + if (remove(uncfile) != 0) trace(1, "Error removing file"); + return -1; + } + if (strlen(uncfile) < 1025) strcpy(tmpfile, uncfile); + stat = 1; + } + /* extract tar file */ + if ((p = strrchr(tmpfile, '.')) && !strcmp(p, ".tar")) + { + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile] = '\0'; + strcpy(buff, tmpfile); + fname = buff; + if ((p = strrchr(buff, '/'))) + { + *p = '\0'; + dir = fname; + fname = p + 1; + } + // sprintf(cmd, "tar -C \"%s\" -xf \"%s\"", dir, tmpfile); + // NOTE: This sprintf triggers a format overflow warning. Replaced by: + std::ostringstream temp; + std::string s_aux1(dir); + std::string s_aux2(tmpfile); + temp << "tar -C " << s_aux1 << " -xf " << s_aux2; + std::string s_aux = temp.str(); + int n = s_aux.length(); + if (n < 2048) + for (int i = 0; i < n; i++) cmd[i] = s_aux[i]; + + if (execcmd(cmd)) + { + if (stat) + if (remove(tmpfile) != 0) trace(1, "Error removing file"); + return -1; + } + if (stat) + if (remove(tmpfile) != 0) trace(1, "Error removing file"); + stat = 1; + } + /* extract hatanaka-compressed file by cnx2rnx */ + else if ((p = strrchr(tmpfile, '.')) && strlen(p) > 3 && (*(p + 3) == 'd' || *(p + 3) == 'D')) + { + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile + 3] = *(p + 3) == 'D' ? 'O' : 'o'; + sprintf(cmd, R"(crx2rnx < "%s" > "%s")", tmpfile, uncfile); + + if (execcmd(cmd)) + { + if (remove(uncfile) != 0) trace(1, "Error removing file"); + if (stat) + if (remove(tmpfile) != 0) trace(1, "Error removing file"); + return -1; + } + if (stat) + if (remove(tmpfile) != 0) trace(1, "Error removing file"); + stat = 1; + } + trace(3, "rtk_uncompress: stat=%d\n", stat); + return stat; +} + + +/* expand file path ------------------------------------------------------------ + * expand file path with wild-card (*) in file + * args : char *path I file path to expand (captal insensitive) + * char *paths O expanded file paths + * int nmax I max number of expanded file paths + * return : number of expanded file paths + * notes : the order of expanded files is alphabetical order + *-----------------------------------------------------------------------------*/ +int expath(const char *path, char *paths[], int nmax) +{ + int i, j, n = 0; + char tmp[1024] = ""; + struct dirent *d; + DIR *dp; + const char *file = path; + char dir[1024] = "", s1[1024], s2[1024], *p, *q, *r; + + trace(3, "expath : path=%s nmax=%d\n", path, nmax); + + //TODO: Fix invalid conversion from ‘const char*’ to ‘char*’ + //if ((p=strrchr(path,'/')) || (p=strrchr(path,'\\'))) { + // file=p+1; strncpy(dir,path,p-path+1); dir[p-path+1]='\0'; + //} + if (!(dp = opendir(*dir ? dir : "."))) return 0; + while ((d = readdir(dp))) + { + if (*(d->d_name) == '.') continue; + sprintf(s1, "^%s$", d->d_name); + sprintf(s2, "^%s$", file); + for (p = s1; *p; p++) *p = static_cast(tolower(static_cast(*p))); + for (p = s2; *p; p++) *p = static_cast(tolower(static_cast(*p))); + + for (p = s1, q = strtok_r(s2, "*", &r); q; q = strtok_r(nullptr, "*", &r)) + { + if ((p = strstr(p, q))) + p += strlen(q); + else + break; + } + if (p && n < nmax) sprintf(paths[n++], "%s%s", dir, d->d_name); + } + closedir(dp); + /* sort paths in alphabetical order */ + for (i = 0; i < n - 1; i++) + { + for (j = i + 1; j < n; j++) + { + if (strcmp(paths[i], paths[j]) > 0) + { + if (strlen(paths[i]) < 1025) + strcpy(tmp, paths[i]); + else + { + trace(1, "Path is too long"); + } + strcpy(paths[i], paths[j]); + strcpy(paths[j], tmp); + } + } + } + for (i = 0; i < n; i++) trace(3, "expath : file=%s\n", paths[i]); + + return n; +} + +/* From RTKLIB 2.4.2 */ +void windupcorr(gtime_t time, const double *rs, const double *rr, double *phw) +{ + double ek[3], exs[3], eys[3], ezs[3], ess[3], exr[3], eyr[3], eks[3], ekr[3], E[9]; + double dr[3], ds[3], drs[3], r[3], pos[3], rsun[3], cosp, ph, erpv[5] = {0}; + int i; + + trace(4, "windupcorr: time=%s\n", time_str(time, 0)); + + /* sun position in ecef */ + sunmoonpos(gpst2utc(time), erpv, rsun, nullptr, nullptr); + + /* unit vector satellite to receiver */ + for (i = 0; i < 3; i++) r[i] = rr[i] - rs[i]; + if (!normv3(r, ek)) return; + + /* unit vectors of satellite antenna */ + for (i = 0; i < 3; i++) r[i] = -rs[i]; + if (!normv3(r, ezs)) return; + for (i = 0; i < 3; i++) r[i] = rsun[i] - rs[i]; + if (!normv3(r, ess)) return; + cross3(ezs, ess, r); + if (!normv3(r, eys)) return; + cross3(eys, ezs, exs); + + /* unit vectors of receiver antenna */ + ecef2pos(rr, pos); + xyz2enu(pos, E); + exr[0] = E[1]; + exr[1] = E[4]; + exr[2] = E[7]; /* x = north */ + eyr[0] = -E[0]; + eyr[1] = -E[3]; + eyr[2] = -E[6]; /* y = west */ + + /* phase windup effect */ + cross3(ek, eys, eks); + cross3(ek, eyr, ekr); + for (i = 0; i < 3; i++) + { + ds[i] = exs[i] - ek[i] * dot(ek, exs, 3) - eks[i]; + dr[i] = exr[i] - ek[i] * dot(ek, exr, 3) + ekr[i]; + } + cosp = dot(ds, dr, 3) / norm_rtk(ds, 3) / norm_rtk(dr, 3); + if (cosp < -1.0) + cosp = -1.0; + else if (cosp > 1.0) + cosp = 1.0; + ph = acos(cosp) / 2.0 / PI; + cross3(ds, dr, drs); + if (dot(ek, drs, 3) < 0.0) ph = -ph; + + *phw = ph + floor(*phw - ph + 0.5); /* in cycle */ +} diff --git a/src/algorithms/libs/rtklib/rtklib_rtkcmn.h b/src/algorithms/libs/rtklib/rtklib_rtkcmn.h new file mode 100644 index 000000000..f58e95193 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtkcmn.h @@ -0,0 +1,288 @@ +/*! + * \file rtklib_rtkcmn.h + * \brief rtklib common functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * References : + * [1] IS-GPS-200D, Navstar GPS Space Segment/Navigation User Interfaces, + * 7 March, 2006 + * [2] RTCA/DO-229C, Minimum operational performanc standards for global + * positioning system/wide area augmentation system airborne equipment, + * RTCA inc, November 28, 2001 + * [3] M.Rothacher, R.Schmid, ANTEX: The Antenna Exchange Format Version 1.4, + * 15 September, 2010 + * [4] A.Gelb ed., Applied Optimal Estimation, The M.I.T Press, 1974 + * [5] A.E.Niell, Global mapping functions for the atmosphere delay at radio + * wavelengths, Jounal of geophysical research, 1996 + * [6] W.Gurtner and L.Estey, RINEX The Receiver Independent Exchange Format + * Version 3.00, November 28, 2007 + * [7] J.Kouba, A Guide to using International GNSS Service (IGS) products, + * May 2009 + * [8] China Satellite Navigation Office, BeiDou navigation satellite system + * signal in space interface control document, open service signal B1I + * (version 1.0), Dec 2012 + * [9] J.Boehm, A.Niell, P.Tregoning and H.Shuh, Global Mapping Function + * (GMF): A new empirical mapping function base on numerical weather + * model data, Geophysical Research Letters, 33, L07304, 2006 + * [10] GLONASS/GPS/Galileo/Compass/SBAS NV08C receiver series BINR interface + * protocol specification ver.1.3, August, 2012 + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_RTKCMN_H_ +#define GNSS_SDR_RTKLIB_RTKCMN_H_ + +#include "rtklib.h" +#include + +/* coordinate rotation matrix ------------------------------------------------*/ +#define Rx(t, X) \ + do \ + { \ + (X)[0] = 1.0; \ + (X)[1] = (X)[2] = (X)[3] = (X)[6] = 0.0; \ + (X)[4] = (X)[8] = cos(t); \ + (X)[7] = sin(t); \ + (X)[5] = -(X)[7]; \ + } \ + while (0) + +#define Ry(t, X) \ + do \ + { \ + (X)[4] = 1.0; \ + (X)[1] = (X)[3] = (X)[5] = (X)[7] = 0.0; \ + (X)[0] = (X)[8] = cos(t); \ + (X)[2] = sin(t); \ + (X)[6] = -(X)[2]; \ + } \ + while (0) + +#define Rz(t, X) \ + do \ + { \ + (X)[8] = 1.0; \ + (X)[2] = (X)[5] = (X)[6] = (X)[7] = 0.0; \ + (X)[0] = (X)[4] = cos(t); \ + (X)[3] = sin(t); \ + (X)[1] = -(X)[3]; \ + } \ + while (0) + + +void fatalerr(const char *format, ...); +int satno(int sys, int prn); +int satsys(int sat, int *prn); +int satid2no(const char *id); +void satno2id(int sat, char *id); +int satexclude(int sat, int svh, const prcopt_t *opt); +int testsnr(int base, int freq, double el, double snr, const snrmask_t *mask); +unsigned char obs2code(const char *obs, int *freq); +char *code2obs(unsigned char code, int *freq); +void setcodepri(int sys, int freq, const char *pri); +int getcodepri(int sys, unsigned char code, const char *opt); +unsigned int getbitu(const unsigned char *buff, int pos, int len); +int getbits(const unsigned char *buff, int pos, int len); +void setbitu(unsigned char *buff, int pos, int len, unsigned int data); +void setbits(unsigned char *buff, int pos, int len, int data); +unsigned int rtk_crc32(const unsigned char *buff, int len); +unsigned int rtk_crc24q(const unsigned char *buff, int len); +unsigned short rtk_crc16(const unsigned char *buff, int len); +int decode_word(unsigned int word, unsigned char *data); +double *mat(int n, int m); +int *imat(int n, int m); +double *zeros(int n, int m); +double *eye(int n); +double dot(const double *a, const double *b, int n); +double norm_rtk(const double *a, int n); +void cross3(const double *a, const double *b, double *c); +int normv3(const double *a, double *b); +void matcpy(double *A, const double *B, int n, int m); +void matmul(const char *tr, int n, int k, int m, double alpha, + const double *A, const double *B, double beta, double *C); +int matinv(double *A, int n); +int solve(const char *tr, const double *A, const double *Y, int n, + int m, double *X); +int lsq(const double *A, const double *y, int n, int m, double *x, + double *Q); +int filter_(const double *x, const double *P, const double *H, + const double *v, const double *R, int n, int m, + double *xp, double *Pp); +int filter(double *x, double *P, const double *H, const double *v, + const double *R, int n, int m); +int smoother(const double *xf, const double *Qf, const double *xb, + const double *Qb, int n, double *xs, double *Qs); +void matfprint(const double A[], int n, int m, int p, int q, FILE *fp); +void matsprint(const double A[], int n, int m, int p, int q, std::string &buffer); +void matprint(const double A[], int n, int m, int p, int q); +double str2num(const char *s, int i, int n); +int str2time(const char *s, int i, int n, gtime_t *t); +gtime_t epoch2time(const double *ep); +void time2epoch(gtime_t t, double *ep); +gtime_t gpst2time(int week, double sec); +double time2gpst(gtime_t t, int *week); +gtime_t gst2time(int week, double sec); +double time2gst(gtime_t t, int *week); +gtime_t bdt2time(int week, double sec); +double time2bdt(gtime_t t, int *week); +gtime_t timeadd(gtime_t t, double sec); +double timediff(gtime_t t1, gtime_t t2); +gtime_t timeget(void); +void timeset(gtime_t t); +int read_leaps_text(FILE *fp); +int read_leaps_usno(FILE *fp); +int read_leaps(const char *file); +gtime_t gpst2utc(gtime_t t); +gtime_t utc2gpst(gtime_t t); +gtime_t gpst2bdt(gtime_t t); +gtime_t bdt2gpst(gtime_t t); +double time2sec(gtime_t time, gtime_t *day); +double utc2gmst(gtime_t t, double ut1_utc); +void time2str(gtime_t t, char *s, int n); +char *time_str(gtime_t t, int n); +double time2doy(gtime_t t); +int adjgpsweek(int week); +unsigned int tickget(void); +void sleepms(int ms); +void deg2dms(double deg, double *dms, int ndec); +void deg2dms(double deg, double *dms); +double dms2deg(const double *dms); +void ecef2pos(const double *r, double *pos); +void pos2ecef(const double *pos, double *r); +void xyz2enu(const double *pos, double *E); +void ecef2enu(const double *pos, const double *r, double *e); +void enu2ecef(const double *pos, const double *e, double *r); +void covenu(const double *pos, const double *P, double *Q); +void covecef(const double *pos, const double *Q, double *P); +void ast_args(double t, double *f); +void nut_iau1980(double t, const double *f, double *dpsi, double *deps); +void eci2ecef(gtime_t tutc, const double *erpv, double *U, double *gmst); +int decodef(char *p, int n, double *v); +void addpcv(const pcv_t *pcv, pcvs_t *pcvs); +int readngspcv(const char *file, pcvs_t *pcvs); +int readantex(const char *file, pcvs_t *pcvs); +int readpcv(const char *file, pcvs_t *pcvs); +pcv_t *searchpcv(int sat, const char *type, gtime_t time, + const pcvs_t *pcvs); +void readpos(const char *file, const char *rcv, double *pos); +int readblqrecord(FILE *fp, double *odisp); +int readblq(const char *file, const char *sta, double *odisp); +int readerp(const char *file, erp_t *erp); +int geterp(const erp_t *erp, gtime_t time, double *erpv); +int cmpeph(const void *p1, const void *p2); +void uniqeph(nav_t *nav); +int cmpgeph(const void *p1, const void *p2); +void uniqgeph(nav_t *nav); +int cmpseph(const void *p1, const void *p2); +void uniqseph(nav_t *nav); +void uniqnav(nav_t *nav); +int cmpobs(const void *p1, const void *p2); +int sortobs(obs_t *obs); +int screent(gtime_t time, gtime_t ts, gtime_t te, double tint); +int readnav(const char *file, nav_t *nav); +int savenav(const char *file, const nav_t *nav); +void freeobs(obs_t *obs); +void freenav(nav_t *nav, int opt); + +void traceopen(const char *file); +void traceclose(void); +void tracelevel(int level); +void traceswap(void); +void trace(int level, const char *format, ...); +void tracet(int level, const char *format, ...); +void tracemat(int level, const double *A, int n, int m, int p, int q); +void traceobs(int level, const obsd_t *obs, int n); +//void tracenav(int level, const nav_t *nav); +//void tracegnav(int level, const nav_t *nav); +//void tracehnav(int level, const nav_t *nav); +//void tracepeph(int level, const nav_t *nav); +//void tracepclk(int level, const nav_t *nav); +//void traceb (int level, const unsigned char *p, int n); + +int execcmd(const char *cmd); +void createdir(const char *path); +int repstr(char *str, const char *pat, const char *rep); +int reppath(const char *path, char *rpath, gtime_t time, const char *rov, + const char *base); +int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts, + gtime_t te, const char *rov, const char *base); +double satwavelen(int sat, int frq, const nav_t *nav); +double geodist(const double *rs, const double *rr, double *e); +double satazel(const double *pos, const double *e, double *azel); + +//#define SQRT(x) ((x)<0.0?0.0:sqrt(x)) +void dops(int ns, const double *azel, double elmin, double *dop); +double ionmodel(gtime_t t, const double *ion, const double *pos, + const double *azel); +double ionmapf(const double *pos, const double *azel); +double ionppp(const double *pos, const double *azel, double re, + double hion, double *posp); +double tropmodel(gtime_t time, const double *pos, const double *azel, + double humi); +double interpc(const double coef[], double lat); +double mapf(double el, double a, double b, double c); +double nmf(gtime_t time, const double pos[], const double azel[], + double *mapfw); +double tropmapf(gtime_t time, const double pos[], const double azel[], + double *mapfw); +double interpvar(double ang, const double *var); + +void antmodel(const pcv_t *pcv, const double *del, const double *azel, + int opt, double *dant); + +void antmodel_s(const pcv_t *pcv, double nadir, double *dant); +void sunmoonpos_eci(gtime_t tut, double *rsun, double *rmoon); +void sunmoonpos(gtime_t tutc, const double *erpv, double *rsun, + double *rmoon, double *gmst); +void csmooth(obs_t *obs, int ns); +int rtk_uncompress(const char *file, char *uncfile); +int expath(const char *path, char *paths[], int nmax); +void windupcorr(gtime_t time, const double *rs, const double *rr, double *phw); + +#endif /* GNSS_SDR_RTKLIB_RTKCMN_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_rtkpos.cc b/src/algorithms/libs/rtklib/rtklib_rtkpos.cc new file mode 100644 index 000000000..1634b8fcb --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtkpos.cc @@ -0,0 +1,2352 @@ +/*! + * \file rtklib_rtkpos.cc + * \brief rtklib ppp-related functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_rtkpos.h" +#include "rtklib_ephemeris.h" +#include "rtklib_lambda.h" +#include "rtklib_pntpos.h" +#include "rtklib_ppp.h" +#include "rtklib_tides.h" + +static int resamb_WLNL(rtk_t *rtk __attribute((unused)), const obsd_t *obs __attribute((unused)), const int *sat __attribute((unused)), + const int *iu __attribute((unused)), const int *ir __attribute((unused)), int ns __attribute__((unused)), const nav_t *nav __attribute((unused)), + const double *azel __attribute((unused))) { return 0; } +static int resamb_TCAR(rtk_t *rtk __attribute((unused)), const obsd_t *obs __attribute((unused)), const int *sat __attribute((unused)), + const int *iu __attribute((unused)), const int *ir __attribute((unused)), int ns __attribute((unused)), const nav_t *nav __attribute((unused)), + const double *azel __attribute((unused))) { return 0; } + +/* global variables ----------------------------------------------------------*/ +static int statlevel = 0; /* rtk status output level (0:off) */ +static FILE *fp_stat = nullptr; /* rtk status file pointer */ +static char file_stat[1024] = ""; /* rtk status file original path */ +static gtime_t time_stat = {0, 0}; /* rtk status file time */ + +/* open solution status file --------------------------------------------------- + * open solution status file and set output level + * args : char *file I rtk status file + * int level I rtk status level (0: off) + * return : status (1:ok,0:error) + * notes : file can constain time keywords (%Y,%y,%m...) defined in reppath(). + * The time to replace keywords is based on UTC of CPU time. + * output : solution status file record format + * + * $POS,week,tow,stat,posx,posy,posz,posxf,posyf,poszf + * week/tow : gps week no/time of week (s) + * stat : solution status + * posx/posy/posz : position x/y/z ecef (m) float + * posxf/posyf/poszf : position x/y/z ecef (m) fixed + * + * $VELACC,week,tow,stat,vele,veln,velu,acce,accn,accu,velef,velnf,veluf,accef,accnf,accuf + * week/tow : gps week no/time of week (s) + * stat : solution status + * vele/veln/velu : velocity e/n/u (m/s) float + * acce/accn/accu : acceleration e/n/u (m/s^2) float + * velef/velnf/veluf : velocity e/n/u (m/s) fixed + * accef/accnf/accuf : acceleration e/n/u (m/s^2) fixed + * + * $CLK,week,tow,stat,clk1,clk2,clk3,clk4 + * week/tow : gps week no/time of week (s) + * stat : solution status + * clk1 : receiver clock bias GPS (ns) + * clk2 : receiver clock bias GLO-GPS (ns) + * clk3 : receiver clock bias GAL-GPS (ns) + * clk4 : receiver clock bias BDS-GPS (ns) + * + * $ION,week,tow,stat,sat,az,el,ion,ion-fixed + * week/tow : gps week no/time of week (s) + * stat : solution status + * sat : satellite id + * az/el : azimuth/elevation angle(deg) + * ion : vertical ionospheric delay L1 (m) float + * ion-fixed: vertical ionospheric delay L1 (m) fixed + * + * $TROP,week,tow,stat,rcv,ztd,ztdf + * week/tow : gps week no/time of week (s) + * stat : solution status + * rcv : receiver (1:rover,2:base station) + * ztd : zenith total delay (m) float + * ztdf : zenith total delay (m) fixed + * + * $HWBIAS,week,tow,stat,frq,bias,biasf + * week/tow : gps week no/time of week (s) + * stat : solution status + * frq : frequency (1:L1,2:L2,...) + * bias : h/w bias coefficient (m/MHz) float + * biasf : h/w bias coefficient (m/MHz) fixed + * + * $SAT,week,tow,sat,frq,az,el,resp,resc,vsat,snr,fix,slip,lock,outc,slipc,rejc + * week/tow : gps week no/time of week (s) + * sat/frq : satellite id/frequency (1:L1,2:L2,...) + * az/el : azimuth/elevation angle (deg) + * resp : pseudorange residual (m) + * resc : carrier-phase residual (m) + * vsat : valid data flag (0:invalid,1:valid) + * snr : signal strength (dbHz) + * fix : ambiguity flag (0:no data,1:float,2:fixed,3:hold,4:ppp) + * slip : cycle-slip flag (bit1:slip,bit2:parity unknown) + * lock : carrier-lock count + * outc : data outage count + * slipc : cycle-slip count + * rejc : data reject (outlier) count + * + *-----------------------------------------------------------------------------*/ +int rtkopenstat(const char *file, int level) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + trace(3, "rtkopenstat: file=%s level=%d\n", file, level); + + if (level <= 0) return 0; + + reppath(file, path, time, "", ""); + + if (!(fp_stat = fopen(path, "we"))) + { + trace(1, "rtkopenstat: file open error path=%s\n", path); + return 0; + } + if (strlen(file) < 1025) + strcpy(file_stat, file); + else + trace(1, "File name is too long"); + time_stat = time; + statlevel = level; + return 1; +} + + +/* close solution status file -------------------------------------------------- + * close solution status file + * args : none + * return : none + *-----------------------------------------------------------------------------*/ +void rtkclosestat(void) +{ + trace(3, "rtkclosestat:\n"); + + if (fp_stat) fclose(fp_stat); + fp_stat = nullptr; + file_stat[0] = '\0'; + statlevel = 0; +} + + +/* write solution status to buffer -------------------------------------------*/ +void rtkoutstat(rtk_t *rtk, char *buff __attribute__((unused))) +{ + ssat_t *ssat; + double tow, pos[3], vel[3], acc[3], vela[3] = {0}, acca[3] = {0}, xa[3]; + int i, j, week, est, nfreq, nf = NF_RTK(&rtk->opt); + char id[32]; + + if (statlevel <= 0 || !fp_stat) return; + + trace(3, "outsolstat:\n"); + + /* swap solution status file */ + swapsolstat(); + + est = rtk->opt.mode >= PMODE_DGPS; + nfreq = est ? nf : 1; + tow = time2gpst(rtk->sol.time, &week); + + /* receiver position */ + if (est) + { + for (i = 0; i < 3; i++) xa[i] = i < rtk->na ? rtk->xa[i] : 0.0; + fprintf(fp_stat, "$POS,%d,%.3f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f\n", week, tow, + rtk->sol.stat, rtk->x[0], rtk->x[1], rtk->x[2], xa[0], xa[1], xa[2]); + } + else + { + fprintf(fp_stat, "$POS,%d,%.3f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f\n", week, tow, + rtk->sol.stat, rtk->sol.rr[0], rtk->sol.rr[1], rtk->sol.rr[2], + 0.0, 0.0, 0.0); + } + /* receiver velocity and acceleration */ + if (est && rtk->opt.dynamics) + { + ecef2pos(rtk->sol.rr, pos); + ecef2enu(pos, rtk->x + 3, vel); + ecef2enu(pos, rtk->x + 6, acc); + if (rtk->na >= 6) ecef2enu(pos, rtk->xa + 3, vela); + if (rtk->na >= 9) ecef2enu(pos, rtk->xa + 6, acca); + fprintf(fp_stat, "$VELACC,%d,%.3f,%d,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f\n", + week, tow, rtk->sol.stat, vel[0], vel[1], vel[2], acc[0], acc[1], acc[2], + vela[0], vela[1], vela[2], acca[0], acca[1], acca[2]); + } + else + { + ecef2pos(rtk->sol.rr, pos); + ecef2enu(pos, rtk->sol.rr + 3, vel); + fprintf(fp_stat, "$VELACC,%d,%.3f,%d,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f\n", + week, tow, rtk->sol.stat, vel[0], vel[1], vel[2], + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + /* receiver clocks */ + fprintf(fp_stat, "$CLK,%d,%.3f,%d,%d,%.3f,%.3f,%.3f,%.3f\n", + week, tow, rtk->sol.stat, 1, rtk->sol.dtr[0] * 1E9, rtk->sol.dtr[1] * 1E9, + rtk->sol.dtr[2] * 1E9, rtk->sol.dtr[3] * 1E9); + + /* ionospheric parameters */ + if (est && rtk->opt.ionoopt == IONOOPT_EST) + { + for (i = 0; i < MAXSAT; i++) + { + ssat = rtk->ssat + i; + if (!ssat->vs) continue; + satno2id(i + 1, id); + j = II_RTK(i + 1, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$ION,%d,%.3f,%d,%s,%.1f,%.1f,%.4f,%.4f\n", week, tow, rtk->sol.stat, + id, ssat->azel[0] * R2D, ssat->azel[1] * R2D, rtk->x[j], xa[0]); + } + } + /* tropospheric parameters */ + if (est && (rtk->opt.tropopt == TROPOPT_EST || rtk->opt.tropopt == TROPOPT_ESTG)) + { + for (i = 0; i < 2; i++) + { + j = IT_RTK(i, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$TROP,%d,%.3f,%d,%d,%.4f,%.4f\n", week, tow, rtk->sol.stat, + i + 1, rtk->x[j], xa[0]); + } + } + /* receiver h/w bias */ + if (est && rtk->opt.glomodear == 2) + { + for (i = 0; i < nfreq; i++) + { + j = IL_RTK(i, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$HWBIAS,%d,%.3f,%d,%d,%.4f,%.4f\n", week, tow, rtk->sol.stat, + i + 1, rtk->x[j], xa[0]); + } + } + if (rtk->sol.stat == SOLQ_NONE || statlevel <= 1) return; + + /* residuals and status */ + for (i = 0; i < MAXSAT; i++) + { + ssat = rtk->ssat + i; + if (!ssat->vs) continue; + satno2id(i + 1, id); + for (j = 0; j < nfreq; j++) + { + fprintf(fp_stat, "$SAT,%d,%.3f,%s,%d,%.1f,%.1f,%.4f,%.4f,%d,%.0f,%d,%d,%d,%d,%d,%d\n", + week, tow, id, j + 1, ssat->azel[0] * R2D, ssat->azel[1] * R2D, + ssat->resp[j], ssat->resc[j], ssat->vsat[j], ssat->snr[j] * 0.25, + ssat->fix[j], ssat->slip[j] & 3, ssat->lock[j], ssat->outc[j], + ssat->slipc[j], ssat->rejc[j]); + } + } +} + + +/* swap solution status file -------------------------------------------------*/ +void swapsolstat(void) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + if (static_cast(time2gpst(time, nullptr) / INT_SWAP_STAT) == + static_cast(time2gpst(time_stat, nullptr) / INT_SWAP_STAT)) + { + return; + } + time_stat = time; + + if (!reppath(file_stat, path, time, "", "")) + { + return; + } + if (fp_stat) fclose(fp_stat); + + if (!(fp_stat = fopen(path, "we"))) + { + trace(2, "swapsolstat: file open error path=%s\n", path); + return; + } + trace(3, "swapsolstat: path=%s\n", path); +} + + +/* output solution status ----------------------------------------------------*/ +void outsolstat(rtk_t *rtk) +{ + ssat_t *ssat; + double tow, pos[3], vel[3], acc[3], vela[3] = {0}, acca[3] = {0}, xa[3]; + int i, j, week, est, nfreq, nf = NF_RTK(&rtk->opt); + char id[32]; + + if (statlevel <= 0 || !fp_stat) return; + + trace(3, "outsolstat:\n"); + + /* swap solution status file */ + swapsolstat(); + + est = rtk->opt.mode >= PMODE_DGPS; + nfreq = est ? nf : 1; + tow = time2gpst(rtk->sol.time, &week); + + /* receiver position */ + if (est) + { + for (i = 0; i < 3; i++) xa[i] = i < rtk->na ? rtk->xa[i] : 0.0; + fprintf(fp_stat, "$POS,%d,%.3f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f\n", week, tow, + rtk->sol.stat, rtk->x[0], rtk->x[1], rtk->x[2], xa[0], xa[1], xa[2]); + } + else + { + fprintf(fp_stat, "$POS,%d,%.3f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f\n", week, tow, + rtk->sol.stat, rtk->sol.rr[0], rtk->sol.rr[1], rtk->sol.rr[2], + 0.0, 0.0, 0.0); + } + /* receiver velocity and acceleration */ + if (est && rtk->opt.dynamics) + { + ecef2pos(rtk->sol.rr, pos); + ecef2enu(pos, rtk->x + 3, vel); + ecef2enu(pos, rtk->x + 6, acc); + if (rtk->na >= 6) ecef2enu(pos, rtk->xa + 3, vela); + if (rtk->na >= 9) ecef2enu(pos, rtk->xa + 6, acca); + fprintf(fp_stat, "$VELACC,%d,%.3f,%d,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f\n", + week, tow, rtk->sol.stat, vel[0], vel[1], vel[2], acc[0], acc[1], acc[2], + vela[0], vela[1], vela[2], acca[0], acca[1], acca[2]); + } + else + { + ecef2pos(rtk->sol.rr, pos); + ecef2enu(pos, rtk->sol.rr + 3, vel); + fprintf(fp_stat, "$VELACC,%d,%.3f,%d,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f,%.4f,%.4f,%.4f,%.5f,%.5f,%.5f\n", + week, tow, rtk->sol.stat, vel[0], vel[1], vel[2], + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + /* receiver clocks */ + fprintf(fp_stat, "$CLK,%d,%.3f,%d,%d,%.3f,%.3f,%.3f,%.3f\n", + week, tow, rtk->sol.stat, 1, rtk->sol.dtr[0] * 1E9, rtk->sol.dtr[1] * 1E9, + rtk->sol.dtr[2] * 1E9, rtk->sol.dtr[3] * 1E9); + + /* ionospheric parameters */ + if (est && rtk->opt.ionoopt == IONOOPT_EST) + { + for (i = 0; i < MAXSAT; i++) + { + ssat = rtk->ssat + i; + if (!ssat->vs) continue; + satno2id(i + 1, id); + j = II_RTK(i + 1, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$ION,%d,%.3f,%d,%s,%.1f,%.1f,%.4f,%.4f\n", week, tow, rtk->sol.stat, + id, ssat->azel[0] * R2D, ssat->azel[1] * R2D, rtk->x[j], xa[0]); + } + } + /* tropospheric parameters */ + if (est && (rtk->opt.tropopt == TROPOPT_EST || rtk->opt.tropopt == TROPOPT_ESTG)) + { + for (i = 0; i < 2; i++) + { + j = IT_RTK(i, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$TROP,%d,%.3f,%d,%d,%.4f,%.4f\n", week, tow, rtk->sol.stat, + i + 1, rtk->x[j], xa[0]); + } + } + /* receiver h/w bias */ + if (est && rtk->opt.glomodear == 2) + { + for (i = 0; i < nfreq; i++) + { + j = IL_RTK(i, &rtk->opt); + xa[0] = j < rtk->na ? rtk->xa[j] : 0.0; + fprintf(fp_stat, "$HWBIAS,%d,%.3f,%d,%d,%.4f,%.4f\n", week, tow, rtk->sol.stat, + i + 1, rtk->x[j], xa[0]); + } + } + if (rtk->sol.stat == SOLQ_NONE || statlevel <= 1) return; + + /* residuals and status */ + for (i = 0; i < MAXSAT; i++) + { + ssat = rtk->ssat + i; + if (!ssat->vs) continue; + satno2id(i + 1, id); + for (j = 0; j < nfreq; j++) + { + fprintf(fp_stat, "$SAT,%d,%.3f,%s,%d,%.1f,%.1f,%.4f,%.4f,%d,%.0f,%d,%d,%d,%d,%d,%d\n", + week, tow, id, j + 1, ssat->azel[0] * R2D, ssat->azel[1] * R2D, + ssat->resp[j], ssat->resc[j], ssat->vsat[j], ssat->snr[j] * 0.25, + ssat->fix[j], ssat->slip[j] & 3, ssat->lock[j], ssat->outc[j], + ssat->slipc[j], ssat->rejc[j]); + } + } +} + + +/* save error message --------------------------------------------------------*/ +void errmsg(rtk_t *rtk, const char *format, ...) +{ + char buff[256], tstr[32]; + int n; + va_list ap; + time2str(rtk->sol.time, tstr, 2); + n = sprintf(buff, "%s: ", tstr + 11); + va_start(ap, format); + n += vsprintf(buff + n, format, ap); + va_end(ap); + n = n < MAXERRMSG - rtk->neb ? n : MAXERRMSG - rtk->neb; + memcpy(rtk->errbuf + rtk->neb, buff, n); + rtk->neb += n; + trace(2, "%s", buff); +} + + +/* single-differenced observable ---------------------------------------------*/ +double sdobs(const obsd_t *obs, int i, int j, int f) +{ + double pi = f < NFREQ ? obs[i].L[f] : obs[i].P[f - NFREQ]; + double pj = f < NFREQ ? obs[j].L[f] : obs[j].P[f - NFREQ]; + return pi == 0.0 || pj == 0.0 ? 0.0 : pi - pj; +} + + +/* single-differenced geometry-free linear combination of phase --------------*/ +double gfobs_L1L2(const obsd_t *obs, int i, int j, const double *lam) +{ + double pi = sdobs(obs, i, j, 0) * lam[0], pj = sdobs(obs, i, j, 1) * lam[1]; + return pi == 0.0 || pj == 0.0 ? 0.0 : pi - pj; +} + + +double gfobs_L1L5(const obsd_t *obs, int i, int j, const double *lam) +{ + double pi = sdobs(obs, i, j, 0) * lam[0], pj = sdobs(obs, i, j, 2) * lam[2]; + return pi == 0.0 || pj == 0.0 ? 0.0 : pi - pj; +} + + +/* single-differenced measurement error variance -----------------------------*/ +double varerr(int sat __attribute((unused)), int sys, double el, double bl, double dt, int f, + const prcopt_t *opt) +{ + double a, b, c = opt->err[3] * bl / 1e4, d = SPEED_OF_LIGHT * opt->sclkstab * dt, fact = 1.0; + double sinel = sin(el); + int i = sys == SYS_GLO ? 1 : (sys == SYS_GAL ? 2 : 0), nf = NF_RTK(opt); + + /* extended error model */ + if (f >= nf && opt->exterr.ena[0]) + { /* code */ + a = opt->exterr.cerr[i][(f - nf) * 2]; + b = opt->exterr.cerr[i][1 + (f - nf) * 2]; + if (sys == SYS_SBS) + { + a *= EFACT_SBS; + b *= EFACT_SBS; + } + } + else if (f < nf && opt->exterr.ena[1]) + { /* phase */ + a = opt->exterr.perr[i][f * 2]; + b = opt->exterr.perr[i][1 + f * 2]; + if (sys == SYS_SBS) + { + a *= EFACT_SBS; + b *= EFACT_SBS; + } + } + else + { /* normal error model */ + if (f >= nf) fact = opt->eratio[f - nf]; + if (fact <= 0.0) fact = opt->eratio[0]; + fact *= sys == SYS_GLO ? EFACT_GLO : (sys == SYS_SBS ? EFACT_SBS : EFACT_GPS); + a = fact * opt->err[1]; + b = fact * opt->err[2]; + } + return 2.0 * (opt->ionoopt == IONOOPT_IFLC ? 3.0 : 1.0) * (a * a + b * b / sinel / sinel + c * c) + d * d; +} + + +/* baseline length -----------------------------------------------------------*/ +double baseline(const double *ru, const double *rb, double *dr) +{ + int i; + for (i = 0; i < 3; i++) dr[i] = ru[i] - rb[i]; + return norm_rtk(dr, 3); +} + + +/* initialize state and covariance -------------------------------------------*/ +void initx_rtk(rtk_t *rtk, double xi, double var, int i) +{ + int j; + rtk->x[i] = xi; + for (j = 0; j < rtk->nx; j++) + { + rtk->P[i + j * rtk->nx] = rtk->P[j + i * rtk->nx] = i == j ? var : 0.0; + } +} + + +/* select common satellites between rover and reference station --------------*/ +int selsat(const obsd_t *obs, const double *azel, int nu, int nr, + const prcopt_t *opt, int *sat, int *iu, int *ir) +{ + int i, j, k = 0; + + trace(3, "selsat : nu=%d nr=%d\n", nu, nr); + + for (i = 0, j = nu; i < nu && j < nu + nr; i++, j++) + { + if (obs[i].sat < obs[j].sat) + j--; + else if (obs[i].sat > obs[j].sat) + i--; + else if (azel[1 + j * 2] >= opt->elmin) + { /* elevation at base station */ + sat[k] = obs[i].sat; + iu[k] = i; + ir[k++] = j; + trace(4, "(%2d) sat=%3d iu=%2d ir=%2d\n", k - 1, obs[i].sat, i, j); + } + } + return k; +} + + +/* temporal update of position/velocity/acceleration -------------------------*/ +void udpos(rtk_t *rtk, double tt) +{ + double *F, *FP, *xp, pos[3], Q[9] = {0}, Qv[9], var = 0.0; + int i, j; + + trace(3, "udpos : tt=%.3f\n", tt); + + /* fixed mode */ + if (rtk->opt.mode == PMODE_FIXED) + { + for (i = 0; i < 3; i++) initx_rtk(rtk, rtk->opt.ru[i], 1E-8, i); + return; + } + /* initialize position for first epoch */ + if (norm_rtk(rtk->x, 3) <= 0.0) + { + for (i = 0; i < 3; i++) initx_rtk(rtk, rtk->sol.rr[i], VAR_POS, i); + if (rtk->opt.dynamics) + { + for (i = 3; i < 6; i++) initx_rtk(rtk, rtk->sol.rr[i], VAR_VEL, i); + for (i = 6; i < 9; i++) initx_rtk(rtk, 1E-6, VAR_ACC, i); + } + } + /* static mode */ + if (rtk->opt.mode == PMODE_STATIC) return; + + /* kinmatic mode without dynamics */ + if (!rtk->opt.dynamics) + { + for (i = 0; i < 3; i++) initx_rtk(rtk, rtk->sol.rr[i], VAR_POS, i); + return; + } + /* check variance of estimated position */ + for (i = 0; i < 3; i++) + { + var += rtk->P[i + i * rtk->nx]; + } + var /= 3.0; + + if (var > VAR_POS) + { + /* reset position with large variance */ + for (i = 0; i < 3; i++) initx_rtk(rtk, rtk->sol.rr[i], VAR_POS, i); + for (i = 3; i < 6; i++) initx_rtk(rtk, rtk->sol.rr[i], VAR_VEL, i); + for (i = 6; i < 9; i++) initx_rtk(rtk, 1E-6, VAR_ACC, i); + trace(2, "reset rtk position due to large variance: var=%.3f\n", var); + return; + } + /* state transition of position/velocity/acceleration */ + F = eye(rtk->nx); + FP = mat(rtk->nx, rtk->nx); + xp = mat(rtk->nx, 1); + + for (i = 0; i < 6; i++) + { + F[i + (i + 3) * rtk->nx] = tt; + } + /* x=F*x, P=F*P*F+Q */ + matmul("NN", rtk->nx, 1, rtk->nx, 1.0, F, rtk->x, 0.0, xp); + matcpy(rtk->x, xp, rtk->nx, 1); + matmul("NN", rtk->nx, rtk->nx, rtk->nx, 1.0, F, rtk->P, 0.0, FP); + matmul("NT", rtk->nx, rtk->nx, rtk->nx, 1.0, FP, F, 0.0, rtk->P); + + /* process noise added to only acceleration */ + Q[0] = Q[4] = std::pow(rtk->opt.prn[3], 2.0); + Q[8] = std::pow(rtk->opt.prn[4], 2.0); + ecef2pos(rtk->x, pos); + covecef(pos, Q, Qv); + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + { + rtk->P[i + 6 + (j + 6) * rtk->nx] += Qv[i + j * 3]; + } + free(F); + free(FP); + free(xp); +} + + +/* temporal update of ionospheric parameters ---------------------------------*/ +void udion(rtk_t *rtk, double tt, double bl, const int *sat, int ns) +{ + double el, fact; + int i, j; + + trace(3, "udion : tt=%.1f bl=%.0f ns=%d\n", tt, bl, ns); + + for (i = 1; i <= MAXSAT; i++) + { + j = II_RTK(i, &rtk->opt); + if (rtk->x[j] != 0.0 && + rtk->ssat[i - 1].outc[0] > GAP_RESION && rtk->ssat[i - 1].outc[1] > GAP_RESION) + rtk->x[j] = 0.0; + } + for (i = 0; i < ns; i++) + { + j = II_RTK(sat[i], &rtk->opt); + + if (rtk->x[j] == 0.0) + { + initx_rtk(rtk, 1E-6, std::pow(rtk->opt.std[1] * bl / 1e4, 2.0), j); + } + else + { + /* elevation dependent factor of process noise */ + el = rtk->ssat[sat[i] - 1].azel[1]; + fact = cos(el); + rtk->P[j + j * rtk->nx] += std::pow(rtk->opt.prn[1] * bl / 1e4 * fact, 2.0) * tt; + } + } +} + + +/* temporal update of tropospheric parameters --------------------------------*/ +void udtrop(rtk_t *rtk, double tt, double bl __attribute((unused))) +{ + int i, j, k; + + trace(3, "udtrop : tt=%.1f\n", tt); + + for (i = 0; i < 2; i++) + { + j = IT_RTK(i, &rtk->opt); + + if (rtk->x[j] == 0.0) + { + initx_rtk(rtk, INIT_ZWD, std::pow(rtk->opt.std[2], 2.0), j); /* initial zwd */ + + if (rtk->opt.tropopt >= TROPOPT_ESTG) + { + for (k = 0; k < 2; k++) initx_rtk(rtk, 1e-6, VAR_GRA, ++j); + } + } + else + { + rtk->P[j + j * rtk->nx] += std::pow(rtk->opt.prn[2], 2.0) * tt; + + if (rtk->opt.tropopt >= TROPOPT_ESTG) + { + for (k = 0; k < 2; k++) + { + rtk->P[++j * (1 + rtk->nx)] += std::pow(rtk->opt.prn[2] * 0.3, 2.0) * fabs(rtk->tt); + } + } + } + } +} + + +/* temporal update of receiver h/w biases ------------------------------------*/ +void udrcvbias(rtk_t *rtk, double tt) +{ + int i, j; + + trace(3, "udrcvbias: tt=%.1f\n", tt); + + for (i = 0; i < NFREQGLO; i++) + { + j = IL_RTK(i, &rtk->opt); + + if (rtk->x[j] == 0.0) + { + initx_rtk(rtk, 1E-6, VAR_HWBIAS, j); + } + /* hold to fixed solution */ + else if (rtk->nfix >= rtk->opt.minfix && rtk->sol.ratio > rtk->opt.thresar[0]) + { + initx_rtk(rtk, rtk->xa[j], rtk->Pa[j + j * rtk->na], j); + } + else + { + rtk->P[j + j * rtk->nx] += std::pow(PRN_HWBIAS, 2.0) * tt; + } + } +} + + +/* detect cycle slip by LLI --------------------------------------------------*/ +void detslp_ll(rtk_t *rtk, const obsd_t *obs, int i, int rcv) +{ + unsigned int slip, LLI; + int f, sat = obs[i].sat; + + trace(3, "detslp_ll: i=%d rcv=%d\n", i, rcv); + + for (f = 0; f < rtk->opt.nf; f++) + { + if (obs[i].L[f] == 0.0) continue; + + /* restore previous LLI */ + if (rcv == 1) + LLI = getbitu(&rtk->ssat[sat - 1].slip[f], 0, 2); /* rover */ + else + LLI = getbitu(&rtk->ssat[sat - 1].slip[f], 2, 2); /* base */ + + /* detect slip by cycle slip flag in LLI */ + if (rtk->tt >= 0.0) + { /* forward */ + if (obs[i].LLI[f] & 1) + { + errmsg(rtk, "slip detected forward (sat=%2d rcv=%d F=%d LLI=%x)\n", + sat, rcv, f + 1, obs[i].LLI[f]); + } + slip = obs[i].LLI[f]; + } + else + { /* backward */ + if (LLI & 1) + { + errmsg(rtk, "slip detected backward (sat=%2d rcv=%d F=%d LLI=%x)\n", + sat, rcv, f + 1, LLI); + } + slip = LLI; + } + /* detect slip by parity unknown flag transition in LLI */ + if (((LLI & 2) && !(obs[i].LLI[f] & 2)) || (!(LLI & 2) && (obs[i].LLI[f] & 2))) + { + errmsg(rtk, "slip detected half-cyc (sat=%2d rcv=%d F=%d LLI=%x->%x)\n", + sat, rcv, f + 1, LLI, obs[i].LLI[f]); + slip |= 1; + } + /* save current LLI */ + if (rcv == 1) + setbitu(&rtk->ssat[sat - 1].slip[f], 0, 2, obs[i].LLI[f]); + else + setbitu(&rtk->ssat[sat - 1].slip[f], 2, 2, obs[i].LLI[f]); + + /* save slip and half-cycle valid flag */ + rtk->ssat[sat - 1].slip[f] |= static_cast(slip); + rtk->ssat[sat - 1].half[f] = (obs[i].LLI[f] & 2) ? 0 : 1; + } +} + + +/* detect cycle slip by L1-L2 geometry free phase jump -----------------------*/ +void detslp_gf_L1L2(rtk_t *rtk, const obsd_t *obs, int i, int j, + const nav_t *nav) +{ + int sat = obs[i].sat; + double g0, g1; + + trace(3, "detslp_gf_L1L2: i=%d j=%d\n", i, j); + + if (rtk->opt.nf <= 1 || (g1 = gfobs_L1L2(obs, i, j, nav->lam[sat - 1])) == 0.0) return; + + g0 = rtk->ssat[sat - 1].gf; + rtk->ssat[sat - 1].gf = g1; + + if (g0 != 0.0 && fabs(g1 - g0) > rtk->opt.thresslip) + { + rtk->ssat[sat - 1].slip[0] |= 1; + rtk->ssat[sat - 1].slip[1] |= 1; + + errmsg(rtk, "slip detected (sat=%2d GF_L1_L2=%.3f %.3f)\n", sat, g0, g1); + } +} + + +/* detect cycle slip by L1-L5 geometry free phase jump -----------------------*/ +void detslp_gf_L1L5(rtk_t *rtk, const obsd_t *obs, int i, int j, + const nav_t *nav) +{ + int sat = obs[i].sat; + double g0, g1; + + trace(3, "detslp_gf_L1L5: i=%d j=%d\n", i, j); + + if (rtk->opt.nf <= 2 || (g1 = gfobs_L1L5(obs, i, j, nav->lam[sat - 1])) == 0.0) return; + + g0 = rtk->ssat[sat - 1].gf2; + rtk->ssat[sat - 1].gf2 = g1; + + if (g0 != 0.0 && fabs(g1 - g0) > rtk->opt.thresslip) + { + rtk->ssat[sat - 1].slip[0] |= 1; + rtk->ssat[sat - 1].slip[2] |= 1; + + errmsg(rtk, "slip detected (sat=%2d GF_L1_L5=%.3f %.3f)\n", sat, g0, g1); + } +} + + +/* detect cycle slip by doppler and phase difference -------------------------*/ +void detslp_dop(rtk_t *rtk __attribute__((unused)), const obsd_t *obs __attribute__((unused)), int i __attribute__((unused)), int rcv __attribute__((unused)), + const nav_t *nav __attribute__((unused))) +{ +/* detection with doppler disabled because of clock-jump issue (v.2.3.0) */ +#if 0 + int f,sat = obs[i].sat; + double tt,dph,dpt,lam,thres; + + trace(3,"detslp_dop: i=%d rcv=%d\n",i,rcv); + + for (f = 0;fopt.nf;f++) + { + if (obs[i].L[f] == 0.0 || obs[i].D[f] == 0.0 || rtk->ph[rcv-1][sat-1][f] == 0.0) + { + continue; + } + if (fabs(tt = timediff(obs[i].time,rtk->pt[rcv-1][sat-1][f]))lam[sat-1][f])<=0.0) continue; + + /* cycle slip threshold (cycle) */ + thres = MAXACC*tt*tt/2.0/lam+rtk->opt.err[4]*fabs(tt)*4.0; + + /* phase difference and doppler x time (cycle) */ + dph = obs[i].L[f]-rtk->ph[rcv-1][sat-1][f]; + dpt = -obs[i].D[f]*tt; + + if (fabs(dph-dpt)<=thres) continue; + + rtk->slip[sat-1][f]| = 1; + + errmsg(rtk,"slip detected (sat=%2d rcv=%d L%d=%.3f %.3f thres=%.3f)\n", + sat,rcv,f+1,dph,dpt,thres); + } +#endif +} + + +/* temporal update of phase biases -------------------------------------------*/ +void udbias(rtk_t *rtk, double tt, const obsd_t *obs, const int *sat, + const int *iu, const int *ir, int ns, const nav_t *nav) +{ + double cp, pr, cp1, cp2, pr1, pr2, *bias, offset, lami, lam1, lam2, C1, C2; + int i, j, f, slip, reset, nf = NF_RTK(&rtk->opt); + + trace(3, "udbias : tt=%.1f ns=%d\n", tt, ns); + + for (i = 0; i < ns; i++) + { + /* detect cycle slip by LLI */ + for (f = 0; f < rtk->opt.nf; f++) rtk->ssat[sat[i] - 1].slip[f] &= 0xFC; + detslp_ll(rtk, obs, iu[i], 1); + detslp_ll(rtk, obs, ir[i], 2); + + /* detect cycle slip by geometry-free phase jump */ + detslp_gf_L1L2(rtk, obs, iu[i], ir[i], nav); + detslp_gf_L1L5(rtk, obs, iu[i], ir[i], nav); + + /* detect cycle slip by doppler and phase difference */ + detslp_dop(rtk, obs, iu[i], 1, nav); + detslp_dop(rtk, obs, ir[i], 2, nav); + + /* update half-cycle valid flag */ + for (f = 0; f < nf; f++) + { + rtk->ssat[sat[i] - 1].half[f] = + !((obs[iu[i]].LLI[f] & 2) || (obs[ir[i]].LLI[f] & 2)); + } + } + for (f = 0; f < nf; f++) + { + /* reset phase-bias if instantaneous AR or expire obs outage counter */ + for (i = 1; i <= MAXSAT; i++) + { + reset = ++rtk->ssat[i - 1].outc[f] > static_cast(rtk->opt.maxout); + + if (rtk->opt.modear == ARMODE_INST && rtk->x[IB_RTK(i, f, &rtk->opt)] != 0.0) + { + initx_rtk(rtk, 0.0, 0.0, IB_RTK(i, f, &rtk->opt)); + } + else if (reset && rtk->x[IB_RTK(i, f, &rtk->opt)] != 0.0) + { + initx_rtk(rtk, 0.0, 0.0, IB_RTK(i, f, &rtk->opt)); + trace(3, "udbias : obs outage counter overflow (sat=%3d L%d n=%d)\n", + i, f + 1, rtk->ssat[i - 1].outc[f]); + } + if (rtk->opt.modear != ARMODE_INST && reset) + { + rtk->ssat[i - 1].lock[f] = -rtk->opt.minlock; + } + } + /* reset phase-bias if detecting cycle slip */ + for (i = 0; i < ns; i++) + { + j = IB_RTK(sat[i], f, &rtk->opt); + rtk->P[j + j * rtk->nx] += rtk->opt.prn[0] * rtk->opt.prn[0] * tt; + slip = rtk->ssat[sat[i] - 1].slip[f]; + if (rtk->opt.ionoopt == IONOOPT_IFLC) slip |= rtk->ssat[sat[i] - 1].slip[1]; + if (rtk->opt.modear == ARMODE_INST || !(slip & 1)) continue; + rtk->x[j] = 0.0; + rtk->ssat[sat[i] - 1].lock[f] = -rtk->opt.minlock; + } + bias = zeros(ns, 1); + + /* estimate approximate phase-bias by phase - code */ + for (i = j = 0, offset = 0.0; i < ns; i++) + { + if (rtk->opt.ionoopt != IONOOPT_IFLC) + { + cp = sdobs(obs, iu[i], ir[i], f); /* cycle */ + pr = sdobs(obs, iu[i], ir[i], f + NFREQ); + lami = nav->lam[sat[i] - 1][f]; + if (cp == 0.0 || pr == 0.0 || lami <= 0.0) continue; + + bias[i] = cp - pr / lami; + } + else + { + cp1 = sdobs(obs, iu[i], ir[i], 0); + cp2 = sdobs(obs, iu[i], ir[i], 1); + pr1 = sdobs(obs, iu[i], ir[i], NFREQ); + pr2 = sdobs(obs, iu[i], ir[i], NFREQ + 1); + lam1 = nav->lam[sat[i] - 1][0]; + lam2 = nav->lam[sat[i] - 1][1]; + if (cp1 == 0.0 || cp2 == 0.0 || pr1 == 0.0 || pr2 == 0.0 || lam1 <= 0.0 || lam2 <= 0.0) continue; + + C1 = std::pow(lam2, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + C2 = -std::pow(lam1, 2.0) / (std::pow(lam2, 2.0) - std::pow(lam1, 2.0)); + bias[i] = (C1 * lam1 * cp1 + C2 * lam2 * cp2) - (C1 * pr1 + C2 * pr2); + } + if (rtk->x[IB_RTK(sat[i], f, &rtk->opt)] != 0.0) + { + offset += bias[i] - rtk->x[IB_RTK(sat[i], f, &rtk->opt)]; + j++; + } + } + /* correct phase-bias offset to enssure phase-code coherency */ + if (j > 0) + { + for (i = 1; i <= MAXSAT; i++) + { + if (rtk->x[IB_RTK(i, f, &rtk->opt)] != 0.0) rtk->x[IB_RTK(i, f, &rtk->opt)] += offset / j; + } + } + /* set initial states of phase-bias */ + for (i = 0; i < ns; i++) + { + if (bias[i] == 0.0 || rtk->x[IB_RTK(sat[i], f, &rtk->opt)] != 0.0) continue; + initx_rtk(rtk, bias[i], std::pow(rtk->opt.std[0], 2.0), IB_RTK(sat[i], f, &rtk->opt)); + } + free(bias); + } +} + + +/* temporal update of states --------------------------------------------------*/ +void udstate(rtk_t *rtk, const obsd_t *obs, const int *sat, + const int *iu, const int *ir, int ns, const nav_t *nav) +{ + double tt = fabs(rtk->tt), bl = 0.0, dr[3]; + + trace(3, "udstate : ns=%d\n", ns); + + /* temporal update of position/velocity/acceleration */ + udpos(rtk, tt); + + /* temporal update of ionospheric parameters */ + if (rtk->opt.ionoopt >= IONOOPT_EST) + { + bl = baseline(rtk->x, rtk->rb, dr); + udion(rtk, tt, bl, sat, ns); + } + /* temporal update of tropospheric parameters */ + if (rtk->opt.tropopt >= TROPOPT_EST) + { + udtrop(rtk, tt, bl); + } + /* temporal update of eceiver h/w bias */ + if (rtk->opt.glomodear == 2 && (rtk->opt.navsys & SYS_GLO)) + { + udrcvbias(rtk, tt); + } + /* temporal update of phase-bias */ + if (rtk->opt.mode > PMODE_DGPS) + { + udbias(rtk, tt, obs, sat, iu, ir, ns, nav); + } +} + + +/* undifferenced phase/code residual for satellite ---------------------------*/ +void zdres_sat(int base, double r, const obsd_t *obs, const nav_t *nav, + const double *azel, const double *dant, + const prcopt_t *opt, double *y) +{ + const double *lam = nav->lam[obs->sat - 1]; + double f1, f2, C1, C2, dant_if; + int i, nf = NF_RTK(opt); + + if (opt->ionoopt == IONOOPT_IFLC) + { /* iono-free linear combination */ + if (lam[0] == 0.0 || lam[1] == 0.0) return; + + if (testsnr(base, 0, azel[1], obs->SNR[0] * 0.25, &opt->snrmask) || + testsnr(base, 1, azel[1], obs->SNR[1] * 0.25, &opt->snrmask)) return; + + f1 = SPEED_OF_LIGHT / lam[0]; + f2 = SPEED_OF_LIGHT / lam[1]; + C1 = std::pow(f1, 2.0) / (std::pow(f1, 2.0) - std::pow(f2, 2.0)); + C2 = -std::pow(f2, 2.0) / (std::pow(f1, 2.0) - std::pow(f2, 2.0)); + dant_if = C1 * dant[0] + C2 * dant[1]; + + if (obs->L[0] != 0.0 && obs->L[1] != 0.0) + { + y[0] = C1 * obs->L[0] * lam[0] + C2 * obs->L[1] * lam[1] - r - dant_if; + } + if (obs->P[0] != 0.0 && obs->P[1] != 0.0) + { + y[1] = C1 * obs->P[0] + C2 * obs->P[1] - r - dant_if; + } + } + else + { + for (i = 0; i < nf; i++) + { + if (lam[i] == 0.0) continue; + + /* check snr mask */ + if (testsnr(base, i, azel[1], obs->SNR[i] * 0.25, &opt->snrmask)) + { + continue; + } + /* residuals = observable - pseudorange */ + if (obs->L[i] != 0.0) y[i] = obs->L[i] * lam[i] - r - dant[i]; + if (obs->P[i] != 0.0) y[i + nf] = obs->P[i] - r - dant[i]; + } + } +} + + +/* undifferenced phase/code residuals ----------------------------------------*/ +int zdres(int base, const obsd_t *obs, int n, const double *rs, + const double *dts, const int *svh, const nav_t *nav, + const double *rr, const prcopt_t *opt, int index, double *y, + double *e, double *azel) +{ + double r, rr_[3], pos[3], dant[NFREQ] = {0}, disp[3]; + double zhd, zazel[] = {0.0, 90.0 * D2R}; + int i, nf = NF_RTK(opt); + + trace(3, "zdres : n=%d\n", n); + + for (i = 0; i < n * nf * 2; i++) y[i] = 0.0; + + if (norm_rtk(rr, 3) <= 0.0) return 0; /* no receiver position */ + + for (i = 0; i < 3; i++) rr_[i] = rr[i]; + + /* earth tide correction */ + if (opt->tidecorr) + { + tidedisp(gpst2utc(obs[0].time), rr_, opt->tidecorr, &nav->erp, + opt->odisp[base], disp); + for (i = 0; i < 3; i++) rr_[i] += disp[i]; + } + ecef2pos(rr_, pos); + + for (i = 0; i < n; i++) + { + /* compute geometric-range and azimuth/elevation angle */ + if ((r = geodist(rs + i * 6, rr_, e + i * 3)) <= 0.0) continue; + if (satazel(pos, e + i * 3, azel + i * 2) < opt->elmin) continue; + + /* excluded satellite? */ + if (satexclude(obs[i].sat, svh[i], opt)) continue; + + /* satellite clock-bias */ + r += -SPEED_OF_LIGHT * dts[i * 2]; + + /* troposphere delay model (hydrostatic) */ + zhd = tropmodel(obs[0].time, pos, zazel, 0.0); + r += tropmapf(obs[i].time, pos, azel + i * 2, nullptr) * zhd; + + /* receiver antenna phase center correction */ + antmodel(opt->pcvr + index, opt->antdel[index], azel + i * 2, opt->posopt[1], + dant); + + /* undifferenced phase/code residual for satellite */ + zdres_sat(base, r, obs + i, nav, azel + i * 2, dant, opt, y + i * nf * 2); + } + trace(4, "rr_=%.3f %.3f %.3f\n", rr_[0], rr_[1], rr_[2]); + trace(4, "pos=%.9f %.9f %.3f\n", pos[0] * R2D, pos[1] * R2D, pos[2]); + for (i = 0; i < n; i++) + { + trace(4, "sat=%2d %13.3f %13.3f %13.3f %13.10f %6.1f %5.1f\n", + obs[i].sat, rs[i * 6], rs[1 + i * 6], rs[2 + i * 6], dts[i * 2], azel[i * 2] * R2D, + azel[1 + i * 2] * R2D); + } + trace(4, "y=\n"); + tracemat(4, y, nf * 2, n, 13, 3); + + return 1; +} + + +/* test valid observation data -----------------------------------------------*/ +int validobs(int i, int j, int f, int nf, const double *y) +{ + /* if no phase observable, psudorange is also unusable */ + return y[f + i * nf * 2] != 0.0 && y[f + j * nf * 2] != 0.0 && + (f < nf || (y[f - nf + i * nf * 2] != 0.0 && y[f - nf + j * nf * 2] != 0.0)); +} + + +/* double-differenced measurement error covariance ---------------------------*/ +void ddcov(const int *nb, int n, const double *Ri, const double *Rj, + int nv, double *R) +{ + int i, j, k = 0, b; + + trace(3, "ddcov : n=%d\n", n); + + for (i = 0; i < nv * nv; i++) R[i] = 0.0; + for (b = 0; b < n; k += nb[b++]) + { + for (i = 0; i < nb[b]; i++) + for (j = 0; j < nb[b]; j++) + { + R[k + i + (k + j) * nv] = Ri[k + i] + (i == j ? Rj[k + i] : 0.0); + } + } + trace(5, "R=\n"); + tracemat(5, R, nv, nv, 8, 6); +} + + +/* baseline length constraint ------------------------------------------------*/ +int constbl(rtk_t *rtk, const double *x, const double *P, double *v, + double *H, double *Ri, double *Rj, int index) +{ + const double thres = 0.1; /* threshold for nonliearity (v.2.3.0) */ + double xb[3], b[3], bb, var = 0.0; + int i; + + trace(3, "constbl : \n"); + + /* no constraint */ + if (rtk->opt.baseline[0] <= 0.0) return 0; + + /* time-adjusted baseline vector and length */ + for (i = 0; i < 3; i++) + { + xb[i] = rtk->rb[i] + rtk->rb[i + 3] * rtk->sol.age; + b[i] = x[i] - xb[i]; + } + bb = norm_rtk(b, 3); + + /* approximate variance of solution */ + if (P) + { + for (i = 0; i < 3; i++) + { + var += P[i + i * rtk->nx]; + } + var /= 3.0; + } + /* check nonlinearity */ + if (var > thres * thres * bb * bb) + { + trace(3, "constbl : equation nonlinear (bb=%.3f var=%.3f)\n", bb, var); + return 0; + } + /* constraint to baseline length */ + v[index] = rtk->opt.baseline[0] - bb; + if (H) + { + for (i = 0; i < 3; i++) H[i + index * rtk->nx] = b[i] / bb; + } + Ri[index] = 0.0; + Rj[index] = std::pow(rtk->opt.baseline[1], 2.0); + + trace(4, "baseline len v=%13.3f R=%8.6f %8.6f\n", v[index], Ri[index], Rj[index]); + + return 1; +} + + +/* precise tropspheric model -------------------------------------------------*/ +double prectrop(gtime_t time, const double *pos, int r, + const double *azel, const prcopt_t *opt, const double *x, + double *dtdx) +{ + double m_w = 0.0, cotz, grad_n, grad_e; + int i = IT_RTK(r, opt); + + /* wet mapping function */ + tropmapf(time, pos, azel, &m_w); + + if (opt->tropopt >= TROPOPT_ESTG && azel[1] > 0.0) + { + /* m_w=m_0+m_0*cot(el)*(Gn*cos(az)+Ge*sin(az)): ref [6] */ + cotz = 1.0 / tan(azel[1]); + grad_n = m_w * cotz * cos(azel[0]); + grad_e = m_w * cotz * sin(azel[0]); + m_w += grad_n * x[i + 1] + grad_e * x[i + 2]; + dtdx[1] = grad_n * x[i]; + dtdx[2] = grad_e * x[i]; + } + else + dtdx[1] = dtdx[2] = 0.0; + dtdx[0] = m_w; + return m_w * x[i]; +} + + +/* glonass inter-channel bias correction -------------------------------------*/ +double gloicbcorr(int sat1 __attribute((unused)), int sat2 __attribute((unused)), const prcopt_t *opt, double lam1, + double lam2, int f) +{ + double dfreq; + + if (f >= NFREQGLO || f >= opt->nf || !opt->exterr.ena[2]) return 0.0; + + dfreq = (SPEED_OF_LIGHT / lam1 - SPEED_OF_LIGHT / lam2) / (f == 0 ? DFRQ1_GLO : DFRQ2_GLO); + + return opt->exterr.gloicb[f] * 0.01 * dfreq; /* (m) */ +} + + +/* test navi system (m=0:gps/qzs/sbs,1:glo,2:gal,3:bds) ----------------------*/ +int test_sys(int sys, int m) +{ + switch (sys) + { + case SYS_GPS: + return m == 0; + case SYS_QZS: + return m == 0; + case SYS_SBS: + return m == 0; + case SYS_GLO: + return m == 1; + case SYS_GAL: + return m == 2; + case SYS_BDS: + return m == 3; + } + return 0; +} + + +/* double-differenced phase/code residuals -----------------------------------*/ +int ddres(rtk_t *rtk, const nav_t *nav, double dt, const double *x, + const double *P, const int *sat, double *y, const double *e, + double *azel, const int *iu, const int *ir, int ns, double *v, + double *H, double *R, int *vflg) +{ + prcopt_t *opt = &rtk->opt; + double bl, dr[3], posu[3], posr[3], didxi = 0.0, didxj = 0.0, *im; + double *tropr, *tropu, *dtdxr, *dtdxu, *Ri, *Rj, lami, lamj, fi, fj, df, *Hi = nullptr; + int i, j, k, m, f, ff, nv = 0, nb[NFREQ * 4 * 2 + 2] = {0}, b = 0, sysi, sysj, nf = NF_RTK(opt); + + trace(3, "ddres : dt=%.1f nx=%d ns=%d\n", dt, rtk->nx, ns); + + bl = baseline(x, rtk->rb, dr); + ecef2pos(x, posu); + ecef2pos(rtk->rb, posr); + + Ri = mat(ns * nf * 2 + 2, 1); + Rj = mat(ns * nf * 2 + 2, 1); + im = mat(ns, 1); + tropu = mat(ns, 1); + tropr = mat(ns, 1); + dtdxu = mat(ns, 3); + dtdxr = mat(ns, 3); + + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ; j++) + { + rtk->ssat[i].resp[j] = rtk->ssat[i].resc[j] = 0.0; + } + /* compute factors of ionospheric and tropospheric delay */ + for (i = 0; i < ns; i++) + { + if (opt->ionoopt >= IONOOPT_EST) + { + im[i] = (ionmapf(posu, azel + iu[i] * 2) + ionmapf(posr, azel + ir[i] * 2)) / 2.0; + } + if (opt->tropopt >= TROPOPT_EST) + { + tropu[i] = prectrop(rtk->sol.time, posu, 0, azel + iu[i] * 2, opt, x, dtdxu + i * 3); + tropr[i] = prectrop(rtk->sol.time, posr, 1, azel + ir[i] * 2, opt, x, dtdxr + i * 3); + } + } + for (m = 0; m < 4; m++) /* m=0:gps/qzs/sbs, 1:glo, 2:gal, 3:bds */ + + for (f = opt->mode > PMODE_DGPS ? 0 : nf; f < nf * 2; f++) + { + /* search reference satellite with highest elevation */ + for (i = -1, j = 0; j < ns; j++) + { + sysi = rtk->ssat[sat[j] - 1].sys; + if (!test_sys(sysi, m)) continue; + if (!validobs(iu[j], ir[j], f, nf, y)) continue; + if (i < 0 || azel[1 + iu[j] * 2] >= azel[1 + iu[i] * 2]) i = j; + } + if (i < 0) continue; + + /* make double difference */ + for (j = 0; j < ns; j++) + { + if (i == j) continue; + sysi = rtk->ssat[sat[i] - 1].sys; + sysj = rtk->ssat[sat[j] - 1].sys; + if (!test_sys(sysj, m)) continue; + if (!validobs(iu[j], ir[j], f, nf, y)) continue; + + ff = f % nf; + lami = nav->lam[sat[i] - 1][ff]; + lamj = nav->lam[sat[j] - 1][ff]; + if (lami <= 0.0 || lamj <= 0.0) continue; + if (H) + { + Hi = H + nv * rtk->nx; + for (k = 0; k < rtk->nx; k++) Hi[k] = 0.0; + } + /* double-differenced residual */ + v[nv] = (y[f + iu[i] * nf * 2] - y[f + ir[i] * nf * 2]) - + (y[f + iu[j] * nf * 2] - y[f + ir[j] * nf * 2]); + + /* partial derivatives by rover position */ + if (H) + { + for (k = 0; k < 3; k++) + { + Hi[k] = -e[k + iu[i] * 3] + e[k + iu[j] * 3]; + } + } + /* double-differenced ionospheric delay term */ + if (opt->ionoopt == IONOOPT_EST) + { + fi = lami / lam_carr[0]; + fj = lamj / lam_carr[0]; + didxi = (f < nf ? -1.0 : 1.0) * fi * fi * im[i]; + didxj = (f < nf ? -1.0 : 1.0) * fj * fj * im[j]; + v[nv] -= didxi * x[II_RTK(sat[i], opt)] - didxj * x[II_RTK(sat[j], opt)]; + if (H) + { + Hi[II_RTK(sat[i], opt)] = didxi; + Hi[II_RTK(sat[j], opt)] = -didxj; + } + } + /* double-differenced tropospheric delay term */ + if (opt->tropopt == TROPOPT_EST || opt->tropopt == TROPOPT_ESTG) + { + v[nv] -= (tropu[i] - tropu[j]) - (tropr[i] - tropr[j]); + for (k = 0; k < (opt->tropopt < TROPOPT_ESTG ? 1 : 3); k++) + { + if (!H) continue; + Hi[IT_RTK(0, opt) + k] = (dtdxu[k + i * 3] - dtdxu[k + j * 3]); + Hi[IT_RTK(1, opt) + k] = -(dtdxr[k + i * 3] - dtdxr[k + j * 3]); + } + } + /* double-differenced phase-bias term */ + if (f < nf) + { + if (opt->ionoopt != IONOOPT_IFLC) + { + v[nv] -= lami * x[IB_RTK(sat[i], f, opt)] - lamj * x[IB_RTK(sat[j], f, opt)]; + if (H) + { + Hi[IB_RTK(sat[i], f, opt)] = lami; + Hi[IB_RTK(sat[j], f, opt)] = -lamj; + } + } + else + { + v[nv] -= x[IB_RTK(sat[i], f, opt)] - x[IB_RTK(sat[j], f, opt)]; + if (H) + { + Hi[IB_RTK(sat[i], f, opt)] = 1.0; + Hi[IB_RTK(sat[j], f, opt)] = -1.0; + } + } + } + /* glonass receiver h/w bias term */ + if (rtk->opt.glomodear == 2 && sysi == SYS_GLO && sysj == SYS_GLO && ff < NFREQGLO) + { + df = (SPEED_OF_LIGHT / lami - SPEED_OF_LIGHT / lamj) / 1E6; /* freq-difference (MHz) */ + v[nv] -= df * x[IL_RTK(ff, opt)]; + if (H) Hi[IL_RTK(ff, opt)] = df; + } + /* glonass interchannel bias correction */ + else if (sysi == SYS_GLO && sysj == SYS_GLO) + { + v[nv] -= gloicbcorr(sat[i], sat[j], &rtk->opt, lami, lamj, f); + } + if (f < nf) + rtk->ssat[sat[j] - 1].resc[f] = v[nv]; + else + rtk->ssat[sat[j] - 1].resp[f - nf] = v[nv]; + + /* test innovation */ + if (opt->maxinno > 0.0 && fabs(v[nv]) > opt->maxinno) + { + if (f < nf) + { + rtk->ssat[sat[i] - 1].rejc[f]++; + rtk->ssat[sat[j] - 1].rejc[f]++; + } + errmsg(rtk, "outlier rejected (sat=%3d-%3d %s%d v=%.3f)\n", + sat[i], sat[j], f < nf ? "L" : "P", f % nf + 1, v[nv]); + continue; + } + /* single-differenced measurement error variances */ + Ri[nv] = varerr(sat[i], sysi, azel[1 + iu[i] * 2], bl, dt, f, opt); + Rj[nv] = varerr(sat[j], sysj, azel[1 + iu[j] * 2], bl, dt, f, opt); + + /* set valid data flags */ + if (opt->mode > PMODE_DGPS) + { + if (f < nf) rtk->ssat[sat[i] - 1].vsat[f] = rtk->ssat[sat[j] - 1].vsat[f] = 1; + } + else + { + rtk->ssat[sat[i] - 1].vsat[f - nf] = rtk->ssat[sat[j] - 1].vsat[f - nf] = 1; + } + trace(4, "sat=%3d-%3d %s%d v=%13.3f R=%8.6f %8.6f\n", sat[i], + sat[j], f < nf ? "L" : "P", f % nf + 1, v[nv], Ri[nv], Rj[nv]); + + vflg[nv++] = (sat[i] << 16) | (sat[j] << 8) | ((f < nf ? 0 : 1) << 4) | (f % nf); + nb[b]++; + } +#if 0 /* residuals referenced to reference satellite (2.4.2 p11) */ + /* restore single-differenced residuals assuming sum equal zero */ + if (fssat[j].resc[f]; + s/=nb[b]+1; + for (j=0;jssat[j].resc[f]!=0.0) rtk->ssat[j].resc[f]-=s; + } + } + else + { + for (j=0,s=0.0;jssat[j].resp[f-nf]; + s/=nb[b]+1; + for (j=0;jssat[j].resp[f-nf]!=0.0) + rtk->ssat[j].resp[f-nf]-=s; + } + } +#endif + b++; + } + /* end of system loop */ + + /* baseline length constraint for moving baseline */ + if (opt->mode == PMODE_MOVEB && constbl(rtk, x, P, v, H, Ri, Rj, nv)) + { + vflg[nv++] = 3 << 4; + nb[b++]++; + } + if (H) + { + trace(5, "H=\n"); + tracemat(5, H, rtk->nx, nv, 7, 4); + } + + /* double-differenced measurement error covariance */ + ddcov(nb, b, Ri, Rj, nv, R); + + free(Ri); + free(Rj); + free(im); + free(tropu); + free(tropr); + free(dtdxu); + free(dtdxr); + + return nv; +} + + +/* time-interpolation of residuals (for post-mission) ------------------------*/ +double intpres(gtime_t time, const obsd_t *obs, int n, const nav_t *nav, + rtk_t *rtk, double *y) +{ + static obsd_t obsb[MAXOBS]; + static double yb[MAXOBS * NFREQ * 2], rs[MAXOBS * 6], dts[MAXOBS * 2], var[MAXOBS]; + static double e[MAXOBS * 3], azel[MAXOBS * 2]; + static int nb = 0, svh[MAXOBS * 2]; + prcopt_t *opt = &rtk->opt; + double tt = timediff(time, obs[0].time), ttb, *p, *q; + int i, j, k, nf = NF_RTK(opt); + + trace(3, "intpres : n=%d tt=%.1f\n", n, tt); + + if (nb == 0 || fabs(tt) < DTTOL) + { + nb = n; + for (i = 0; i < n; i++) obsb[i] = obs[i]; + return tt; + } + ttb = timediff(time, obsb[0].time); + if (fabs(ttb) > opt->maxtdiff * 2.0 || ttb == tt) return tt; + + satposs(time, obsb, nb, nav, opt->sateph, rs, dts, var, svh); + + if (!zdres(1, obsb, nb, rs, dts, svh, nav, rtk->rb, opt, 1, yb, e, azel)) + { + return tt; + } + for (i = 0; i < n; i++) + { + for (j = 0; j < nb; j++) + if (obsb[j].sat == obs[i].sat) break; + if (j >= nb) continue; + for (k = 0, p = y + i * nf * 2, q = yb + j * nf * 2; k < nf * 2; k++, p++, q++) + { + if (*p == 0.0 || *q == 0.0) + *p = 0.0; + else + *p = (ttb * (*p) - tt * (*q)) / (ttb - tt); + } + } + return fabs(ttb) > fabs(tt) ? ttb : tt; +} + + +/* single to double-difference transformation matrix (D') --------------------*/ +int ddmat(rtk_t *rtk, double *D) +{ + int i, j, k, m, f, nb = 0, nx = rtk->nx, na = rtk->na, nf = NF_RTK(&rtk->opt), nofix; + + trace(3, "ddmat :\n"); + + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ; j++) + { + rtk->ssat[i].fix[j] = 0; + } + for (i = 0; i < na; i++) D[i + i * nx] = 1.0; + + for (m = 0; m < 4; m++) + { /* m=0:gps/qzs/sbs, 1:glo, 2:gal, 3:bds */ + nofix = (m == 1 && rtk->opt.glomodear == 0) || (m == 3 && rtk->opt.bdsmodear == 0); + + for (f = 0, k = na; f < nf; f++, k += MAXSAT) + { + if (i < k + MAXSAT) + { + for (i = k; i < k + MAXSAT; i++) + { + if (rtk->x[i] == 0.0 || !test_sys(rtk->ssat[i - k].sys, m) || + !rtk->ssat[i - k].vsat[f] || !rtk->ssat[i - k].half[f]) + { + continue; + } + if (rtk->ssat[i - k].lock[f] > 0 && !(rtk->ssat[i - k].slip[f] & 2) && + rtk->ssat[i - k].azel[1] >= rtk->opt.elmaskar && !nofix) + { + rtk->ssat[i - k].fix[f] = 2; /* fix */ + break; + } + rtk->ssat[i - k].fix[f] = 1; + } + for (j = k; j < k + MAXSAT; j++) + { + if (i == j || rtk->x[j] == 0.0 || !test_sys(rtk->ssat[j - k].sys, m) || + !rtk->ssat[j - k].vsat[f]) + { + continue; + } + if (rtk->ssat[j - k].lock[f] > 0 && !(rtk->ssat[j - k].slip[f] & 2) && + rtk->ssat[i - k].vsat[f] && + rtk->ssat[j - k].azel[1] >= rtk->opt.elmaskar && !nofix) + { + D[i + (na + nb) * nx] = 1.0; + D[j + (na + nb) * nx] = -1.0; + nb++; + rtk->ssat[j - k].fix[f] = 2; /* fix */ + } + else + rtk->ssat[j - k].fix[f] = 1; + } + } + } + } + trace(5, "D=\n"); + tracemat(5, D, nx, na + nb, 2, 0); + return nb; +} + + +/* restore single-differenced ambiguity --------------------------------------*/ +void restamb(rtk_t *rtk, const double *bias, int nb __attribute((unused)), double *xa) +{ + int i, n, m, f, index[MAXSAT], nv = 0, nf = NF_RTK(&rtk->opt); + + trace(3, "restamb :\n"); + + for (i = 0; i < rtk->nx; i++) xa[i] = rtk->x[i]; + for (i = 0; i < rtk->na; i++) xa[i] = rtk->xa[i]; + + for (m = 0; m < 4; m++) + for (f = 0; f < nf; f++) + { + for (n = i = 0; i < MAXSAT; i++) + { + if (!test_sys(rtk->ssat[i].sys, m) || rtk->ssat[i].fix[f] != 2) + { + continue; + } + index[n++] = IB_RTK(i + 1, f, &rtk->opt); + } + if (n < 2) continue; + + xa[index[0]] = rtk->x[index[0]]; + + for (i = 1; i < n; i++) + { + xa[index[i]] = xa[index[0]] - bias[nv++]; + } + } +} + + +/* hold integer ambiguity ----------------------------------------------------*/ +void holdamb(rtk_t *rtk, const double *xa) +{ + double *v, *H, *R; + int i, n, m, f, info, index[MAXSAT], nb = rtk->nx - rtk->na, nv = 0, nf = NF_RTK(&rtk->opt); + + trace(3, "holdamb :\n"); + + v = mat(nb, 1); + H = zeros(nb, rtk->nx); + + for (m = 0; m < 4; m++) + for (f = 0; f < nf; f++) + { + for (n = i = 0; i < MAXSAT; i++) + { + if (!test_sys(rtk->ssat[i].sys, m) || rtk->ssat[i].fix[f] != 2 || + rtk->ssat[i].azel[1] < rtk->opt.elmaskhold) + { + continue; + } + index[n++] = IB_RTK(i + 1, f, &rtk->opt); + rtk->ssat[i].fix[f] = 3; /* hold */ + } + /* constraint to fixed ambiguity */ + for (i = 1; i < n; i++) + { + v[nv] = (xa[index[0]] - xa[index[i]]) - (rtk->x[index[0]] - rtk->x[index[i]]); + + H[index[0] + nv * rtk->nx] = 1.0; + H[index[i] + nv * rtk->nx] = -1.0; + nv++; + } + } + if (nv > 0) + { + R = zeros(nv, nv); + for (i = 0; i < nv; i++) R[i + i * nv] = VAR_HOLDAMB; + + /* update states with constraints */ + if ((info = filter(rtk->x, rtk->P, H, v, R, rtk->nx, nv))) + { + errmsg(rtk, "filter error (info=%d)\n", info); + } + free(R); + } + free(v); + free(H); +} + + +/* resolve integer ambiguity by LAMBDA ---------------------------------------*/ +int resamb_LAMBDA(rtk_t *rtk, double *bias, double *xa) +{ + prcopt_t *opt = &rtk->opt; + int i, j, ny, nb, info, nx = rtk->nx, na = rtk->na; + double *D, *DP, *y, *Qy, *b, *db, *Qb, *Qab, *QQ, s[2]; + + trace(3, "resamb_LAMBDA : nx=%d\n", nx); + + rtk->sol.ratio = 0.0; + + if (rtk->opt.mode <= PMODE_DGPS || rtk->opt.modear == ARMODE_OFF || + rtk->opt.thresar[0] < 1.0) + { + return 0; + } + /* single to double-difference transformation matrix (D') */ + D = zeros(nx, nx); + if ((nb = ddmat(rtk, D)) <= 0) + { + errmsg(rtk, "no valid double-difference\n"); + free(D); + return 0; + } + ny = na + nb; + y = mat(ny, 1); + Qy = mat(ny, ny); + DP = mat(ny, nx); + b = mat(nb, 2); + db = mat(nb, 1); + Qb = mat(nb, nb); + Qab = mat(na, nb); + QQ = mat(na, nb); + + /* transform single to double-differenced phase-bias (y=D'*x, Qy=D'*P*D) */ + matmul("TN", ny, 1, nx, 1.0, D, rtk->x, 0.0, y); + matmul("TN", ny, nx, nx, 1.0, D, rtk->P, 0.0, DP); + matmul("NN", ny, ny, nx, 1.0, DP, D, 0.0, Qy); + + /* phase-bias covariance (Qb) and real-parameters to bias covariance (Qab) */ + for (i = 0; i < nb; i++) + for (j = 0; j < nb; j++) Qb[i + j * nb] = Qy[na + i + (na + j) * ny]; + for (i = 0; i < na; i++) + for (j = 0; j < nb; j++) Qab[i + j * na] = Qy[i + (na + j) * ny]; + + trace(4, "N(0)="); + tracemat(4, y + na, 1, nb, 10, 3); + + /* lambda/mlambda integer least-square estimation */ + if (!(info = lambda(nb, 2, y + na, Qb, b, s))) + { + trace(4, "N(1)="); + tracemat(4, b, 1, nb, 10, 3); + trace(4, "N(2)="); + tracemat(4, b + nb, 1, nb, 10, 3); + + rtk->sol.ratio = s[0] > 0 ? static_cast(s[1] / s[0]) : 0.0f; + if (rtk->sol.ratio > 999.9) rtk->sol.ratio = 999.9f; + + /* validation by popular ratio-test */ + if (s[0] <= 0.0 || s[1] / s[0] >= opt->thresar[0]) + { + /* transform float to fixed solution (xa=xa-Qab*Qb\(b0-b)) */ + for (i = 0; i < na; i++) + { + rtk->xa[i] = rtk->x[i]; + for (j = 0; j < na; j++) rtk->Pa[i + j * na] = rtk->P[i + j * nx]; + } + for (i = 0; i < nb; i++) + { + bias[i] = b[i]; + y[na + i] -= b[i]; + } + if (!matinv(Qb, nb)) + { + matmul("NN", nb, 1, nb, 1.0, Qb, y + na, 0.0, db); + matmul("NN", na, 1, nb, -1.0, Qab, db, 1.0, rtk->xa); + + /* covariance of fixed solution (Qa=Qa-Qab*Qb^-1*Qab') */ + matmul("NN", na, nb, nb, 1.0, Qab, Qb, 0.0, QQ); + matmul("NT", na, na, nb, -1.0, QQ, Qab, 1.0, rtk->Pa); + + trace(3, "resamb : validation ok (nb=%d ratio=%.2f s=%.2f/%.2f)\n", + nb, s[0] == 0.0 ? 0.0 : s[1] / s[0], s[0], s[1]); + + /* restore single-differenced ambiguity */ + restamb(rtk, bias, nb, xa); + } + else + nb = 0; + } + else + { /* validation failed */ + errmsg(rtk, "ambiguity validation failed (nb=%d ratio=%.2f s=%.2f/%.2f)\n", + nb, s[1] / s[0], s[0], s[1]); + nb = 0; + } + } + else + { + errmsg(rtk, "lambda error (info=%d)\n", info); + } + free(D); + free(y); + free(Qy); + free(DP); + free(b); + free(db); + free(Qb); + free(Qab); + free(QQ); + + return nb; /* number of ambiguities */ +} + + +/* validation of solution ----------------------------------------------------*/ +int valpos(rtk_t *rtk, const double *v, const double *R, const int *vflg, + int nv, double thres) +{ +#if 0 + prcopt_t *opt = &rtk->opt; + double vv = 0.0; +#endif + double fact = thres * thres; + int i, stat = 1, sat1, sat2, type, freq; + char stype; + + trace(3, "valpos : nv=%d thres=%.1f\n", nv, thres); + + /* post-fit residual test */ + for (i = 0; i < nv; i++) + { + if (v[i] * v[i] <= fact * R[i + i * nv]) continue; + sat1 = (vflg[i] >> 16) & 0xFF; + sat2 = (vflg[i] >> 8) & 0xFF; + type = (vflg[i] >> 4) & 0xF; + freq = vflg[i] & 0xF; + stype = type == 0 ? 'L' : (type == 1 ? 'L' : 'C'); + errmsg(rtk, "large residual (sat=%2d-%2d %s%d v=%6.3f sig=%.3f)\n", + sat1, sat2, stype, freq + 1, v[i], std::sqrt(R[i + i * nv])); + } +#if 0 /* omitted v.2.4.0 */ + if (stat&&nv>NP(opt)) + { + /* chi-square validation */ + for (i = 0; i chisqr[nv-NP(opt)-1]) + { + errmsg(rtk,"residuals validation failed (nv=%d np=%d vv=%.2f cs=%.2f)\n", + nv, NP(opt), vv, chisqr[nv-NP(opt)-1]); + stat = 0; + } + else + { + trace(3,"valpos : validation ok (%s nv=%d np=%d vv=%.2f cs=%.2f)\n", + rtk->tstr, nv, NP(opt), vv, chisqr[nv-NP(opt)-1]); + } + } +#endif + return stat; +} + + +/* relative positioning ------------------------------------------------------*/ +int relpos(rtk_t *rtk, const obsd_t *obs, int nu, int nr, + const nav_t *nav) +{ + prcopt_t *opt = &rtk->opt; + gtime_t time = obs[0].time; + double *rs, *dts, *var, *y, *e, *azel, *v, *H, *R, *xp, *Pp, *xa, *bias, dt; + int i, j, f, n = nu + nr, ns, ny, nv, sat[MAXSAT], iu[MAXSAT], ir[MAXSAT], niter; + int info, vflg[MAXOBS * NFREQ * 2 + 1], svh[MAXOBS * 2]; + int stat = rtk->opt.mode <= PMODE_DGPS ? SOLQ_DGPS : SOLQ_FLOAT; + int nf = opt->ionoopt == IONOOPT_IFLC ? 1 : opt->nf; + + trace(3, "relpos : nx=%d nu=%d nr=%d\n", rtk->nx, nu, nr); + + dt = timediff(time, obs[nu].time); + + rs = mat(6, n); + dts = mat(2, n); + var = mat(1, n); + y = mat(nf * 2, n); + e = mat(3, n); + azel = zeros(2, n); + + for (i = 0; i < MAXSAT; i++) + { + rtk->ssat[i].sys = satsys(i + 1, nullptr); + for (j = 0; j < NFREQ; j++) rtk->ssat[i].vsat[j] = rtk->ssat[i].snr[j] = 0; + } + /* satellite positions/clocks */ + satposs(time, obs, n, nav, opt->sateph, rs, dts, var, svh); + + /* undifferenced residuals for base station */ + if (!zdres(1, obs + nu, nr, rs + nu * 6, dts + nu * 2, svh + nu, nav, rtk->rb, opt, 1, + y + nu * nf * 2, e + nu * 3, azel + nu * 2)) + { + errmsg(rtk, "initial base station position error\n"); + + free(rs); + free(dts); + free(var); + free(y); + free(e); + free(azel); + return 0; + } + /* time-interpolation of residuals (for post-processing) */ + if (opt->intpref) + { + dt = intpres(time, obs + nu, nr, nav, rtk, y + nu * nf * 2); + } + /* select common satellites between rover and base-station */ + if ((ns = selsat(obs, azel, nu, nr, opt, sat, iu, ir)) <= 0) + { + errmsg(rtk, "no common satellite\n"); + + free(rs); + free(dts); + free(var); + free(y); + free(e); + free(azel); + return 0; + } + /* temporal update of states */ + udstate(rtk, obs, sat, iu, ir, ns, nav); + + trace(4, "x(0)="); + tracemat(4, rtk->x, 1, NR_RTK(opt), 13, 4); + + xp = mat(rtk->nx, 1); + Pp = zeros(rtk->nx, rtk->nx); + xa = mat(rtk->nx, 1); + matcpy(xp, rtk->x, rtk->nx, 1); + + ny = ns * nf * 2 + 2; + v = mat(ny, 1); + H = zeros(rtk->nx, ny); + R = mat(ny, ny); + bias = mat(rtk->nx, 1); + + /* add 2 iterations for baseline-constraint moving-base */ + niter = opt->niter + (opt->mode == PMODE_MOVEB && opt->baseline[0] > 0.0 ? 2 : 0); + + for (i = 0; i < niter; i++) + { + /* undifferenced residuals for rover */ + if (!zdres(0, obs, nu, rs, dts, svh, nav, xp, opt, 0, y, e, azel)) + { + errmsg(rtk, "rover initial position error\n"); + stat = SOLQ_NONE; + break; + } + /* double-differenced residuals and partial derivatives */ + if ((nv = ddres(rtk, nav, dt, xp, Pp, sat, y, e, azel, iu, ir, ns, v, H, R, vflg)) < 1) + { + errmsg(rtk, "no double-differenced residual\n"); + stat = SOLQ_NONE; + break; + } + /* kalman filter measurement update */ + matcpy(Pp, rtk->P, rtk->nx, rtk->nx); + if ((info = filter(xp, Pp, H, v, R, rtk->nx, nv))) + { + errmsg(rtk, "filter error (info=%d)\n", info); + stat = SOLQ_NONE; + break; + } + trace(4, "x(%d)=", i + 1); + tracemat(4, xp, 1, NR_RTK(opt), 13, 4); + } + if (stat != SOLQ_NONE && zdres(0, obs, nu, rs, dts, svh, nav, xp, opt, 0, y, e, azel)) + { + /* post-fit residuals for float solution */ + nv = ddres(rtk, nav, dt, xp, Pp, sat, y, e, azel, iu, ir, ns, v, nullptr, R, vflg); + + /* validation of float solution */ + if (valpos(rtk, v, R, vflg, nv, 4.0)) + { + /* update state and covariance matrix */ + matcpy(rtk->x, xp, rtk->nx, 1); + matcpy(rtk->P, Pp, rtk->nx, rtk->nx); + + /* update ambiguity control struct */ + rtk->sol.ns = 0; + for (i = 0; i < ns; i++) + for (f = 0; f < nf; f++) + { + if (!rtk->ssat[sat[i] - 1].vsat[f]) continue; + rtk->ssat[sat[i] - 1].lock[f]++; + rtk->ssat[sat[i] - 1].outc[f] = 0; + if (f == 0) rtk->sol.ns++; /* valid satellite count by L1 */ + } + /* lack of valid satellites */ + if (rtk->sol.ns < 4) stat = SOLQ_NONE; + } + else + stat = SOLQ_NONE; + } + /* resolve integer ambiguity by WL-NL */ + if (stat != SOLQ_NONE && rtk->opt.modear == ARMODE_WLNL) + { + if (resamb_WLNL(rtk, obs, sat, iu, ir, ns, nav, azel)) + { + stat = SOLQ_FIX; + } + } + /* resolve integer ambiguity by TCAR */ + else if (stat != SOLQ_NONE && rtk->opt.modear == ARMODE_TCAR) + { + if (resamb_TCAR(rtk, obs, sat, iu, ir, ns, nav, azel)) + { + stat = SOLQ_FIX; + } + } + /* resolve integer ambiguity by LAMBDA */ + else if (stat != SOLQ_NONE && resamb_LAMBDA(rtk, bias, xa) > 1) + { + if (zdres(0, obs, nu, rs, dts, svh, nav, xa, opt, 0, y, e, azel)) + { + /* post-fit reisiduals for fixed solution */ + nv = ddres(rtk, nav, dt, xa, nullptr, sat, y, e, azel, iu, ir, ns, v, nullptr, R, vflg); + + /* validation of fixed solution */ + if (valpos(rtk, v, R, vflg, nv, 4.0)) + { + /* hold integer ambiguity */ + if (++rtk->nfix >= rtk->opt.minfix && + rtk->opt.modear == ARMODE_FIXHOLD) + { + holdamb(rtk, xa); + } + stat = SOLQ_FIX; + } + } + } + + /* save solution status */ + if (stat == SOLQ_FIX) + { + for (i = 0; i < 3; i++) + { + rtk->sol.rr[i] = rtk->xa[i]; + rtk->sol.qr[i] = static_cast(rtk->Pa[i + i * rtk->na]); + } + rtk->sol.qr[3] = static_cast(rtk->Pa[1]); + rtk->sol.qr[4] = static_cast(rtk->Pa[1 + 2 * rtk->na]); + rtk->sol.qr[5] = static_cast(rtk->Pa[2]); + } + else + { + for (i = 0; i < 3; i++) + { + rtk->sol.rr[i] = rtk->x[i]; + rtk->sol.qr[i] = static_cast(rtk->P[i + i * rtk->nx]); + } + rtk->sol.qr[3] = static_cast(rtk->P[1]); + rtk->sol.qr[4] = static_cast(rtk->P[1 + 2 * rtk->nx]); + rtk->sol.qr[5] = static_cast(rtk->P[2]); + rtk->nfix = 0; + } + for (i = 0; i < n; i++) + for (j = 0; j < nf; j++) + { + if (obs[i].L[j] == 0.0) continue; + rtk->ssat[obs[i].sat - 1].pt[obs[i].rcv - 1][j] = obs[i].time; + rtk->ssat[obs[i].sat - 1].ph[obs[i].rcv - 1][j] = obs[i].L[j]; + } + for (i = 0; i < ns; i++) + for (j = 0; j < nf; j++) + { + /* output snr of rover receiver */ + rtk->ssat[sat[i] - 1].snr[j] = obs[iu[i]].SNR[j]; + } + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < nf; j++) + { + if (rtk->ssat[i].fix[j] == 2 && stat != SOLQ_FIX) rtk->ssat[i].fix[j] = 1; + if (rtk->ssat[i].slip[j] & 1) rtk->ssat[i].slipc[j]++; + } + free(rs); + free(dts); + free(var); + free(y); + free(e); + free(azel); + free(xp); + free(Pp); + free(xa); + free(v); + free(H); + free(R); + free(bias); + + if (stat != SOLQ_NONE) rtk->sol.stat = stat; + + return stat != SOLQ_NONE; +} + + +/* initialize rtk control ------------------------------------------------------ + * initialize rtk control struct + * args : rtk_t *rtk IO rtk control/result struct + * prcopt_t *opt I positioning options (see rtklib.h) + * return : none + *-----------------------------------------------------------------------------*/ +void rtkinit(rtk_t *rtk, const prcopt_t *opt) +{ + sol_t sol0 = {{0, 0}, {}, {}, {}, '0', '0', '0', 0.0, 0.0, 0.0}; + ambc_t ambc0 = {{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {}, {}, {}, 0, {}}; + ssat_t ssat0 = {0, 0, {0.0}, {0.0}, {0.0}, {'0'}, {'0'}, {'0'}, {'0'}, {'0'}, {}, {}, {}, {}, 0.0, 0.0, 0.0, 0.0, {{{0, 0}}, {{0, 0}}}, {{}, {}}}; + int i; + + trace(3, "rtkinit :\n"); + + rtk->sol = sol0; + for (i = 0; i < 6; i++) rtk->rb[i] = 0.0; + rtk->nx = opt->mode <= PMODE_FIXED ? NX_RTK(opt) : pppnx(opt); + rtk->na = opt->mode <= PMODE_FIXED ? NR_RTK(opt) : pppnx(opt); + rtk->tt = 0.0; + rtk->x = zeros(rtk->nx, 1); + rtk->P = zeros(rtk->nx, rtk->nx); + rtk->xa = zeros(rtk->na, 1); + rtk->Pa = zeros(rtk->na, rtk->na); + rtk->nfix = rtk->neb = 0; + for (i = 0; i < MAXSAT; i++) + { + rtk->ambc[i] = ambc0; + rtk->ssat[i] = ssat0; + } + for (i = 0; i < MAXERRMSG; i++) rtk->errbuf[i] = 0; + rtk->opt = *opt; +} + + +/* free rtk control ------------------------------------------------------------ + * free memory for rtk control struct + * args : rtk_t *rtk IO rtk control/result struct + * return : none + *-----------------------------------------------------------------------------*/ +void rtkfree(rtk_t *rtk) +{ + trace(3, "rtkfree :\n"); + + rtk->nx = rtk->na = 0; + free(rtk->x); + rtk->x = nullptr; + free(rtk->P); + rtk->P = nullptr; + free(rtk->xa); + rtk->xa = nullptr; + free(rtk->Pa); + rtk->Pa = nullptr; +} + + +/* precise positioning --------------------------------------------------------- + * input observation data and navigation message, compute rover position by + * precise positioning + * args : rtk_t *rtk IO rtk control/result struct + * rtk->sol IO solution + * .time O solution time + * .rr[] IO rover position/velocity + * (I:fixed mode,O:single mode) + * .dtr[0] O receiver clock bias (s) + * .dtr[1] O receiver glonass-gps time offset (s) + * .Qr[] O rover position covarinace + * .stat O solution status (SOLQ_???) + * .ns O number of valid satellites + * .age O age of differential (s) + * .ratio O ratio factor for ambiguity validation + * rtk->rb[] IO base station position/velocity + * (I:relative mode,O:moving-base mode) + * rtk->nx I number of all states + * rtk->na I number of integer states + * rtk->ns O number of valid satellite + * rtk->tt O time difference between current and previous (s) + * rtk->x[] IO float states pre-filter and post-filter + * rtk->P[] IO float covariance pre-filter and post-filter + * rtk->xa[] O fixed states after AR + * rtk->Pa[] O fixed covariance after AR + * rtk->ssat[s] IO sat(s+1) status + * .sys O system (SYS_???) + * .az [r] O azimuth angle (rad) (r=0:rover,1:base) + * .el [r] O elevation angle (rad) (r=0:rover,1:base) + * .vs [r] O data valid single (r=0:rover,1:base) + * .resp [f] O freq(f+1) pseudorange residual (m) + * .resc [f] O freq(f+1) carrier-phase residual (m) + * .vsat [f] O freq(f+1) data valid (0:invalid,1:valid) + * .fix [f] O freq(f+1) ambiguity flag + * (0:nodata,1:float,2:fix,3:hold) + * .slip [f] O freq(f+1) slip flag + * (bit8-7:rcv1 LLI, bit6-5:rcv2 LLI, + * bit2:parity unknown, bit1:slip) + * .lock [f] IO freq(f+1) carrier lock count + * .outc [f] IO freq(f+1) carrier outage count + * .slipc[f] IO freq(f+1) cycle slip count + * .rejc [f] IO freq(f+1) data reject count + * .gf IO geometry-free phase (L1-L2) (m) + * .gf2 IO geometry-free phase (L1-L5) (m) + * rtk->nfix IO number of continuous fixes of ambiguity + * rtk->neb IO bytes of error message buffer + * rtk->errbuf IO error message buffer + * rtk->tstr O time string for debug + * rtk->opt I processing options + * obsd_t *obs I observation data for an epoch + * obs[i].rcv=1:rover,2:reference + * sorted by receiver and satellte + * int n I number of observation data + * nav_t *nav I navigation messages + * return : status (0:no solution,1:valid solution) + * notes : before calling function, base station position rtk->sol.rb[] should + * be properly set for relative mode except for moving-baseline + *-----------------------------------------------------------------------------*/ +int rtkpos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) +{ + prcopt_t *opt = &rtk->opt; + sol_t solb = {{0, 0}, {}, {}, {}, '0', '0', '0', 0.0, 0.0, 0.0}; + gtime_t time; + int i, nu, nr; + char msg[128] = ""; + + trace(3, "rtkpos : time=%s n=%d\n", time_str(obs[0].time, 3), n); + trace(4, "obs=\n"); + traceobs(4, obs, n); + /*trace(5,"nav=\n"); tracenav(5,nav);*/ + + /* set base station position */ + if (opt->refpos <= POSOPT_RINEX && opt->mode != PMODE_SINGLE && + opt->mode != PMODE_MOVEB) + { + for (i = 0; i < 6; i++) rtk->rb[i] = i < 3 ? opt->rb[i] : 0.0; + } + /* count rover/base station observations */ + for (nu = 0; nu < n && obs[nu].rcv == 1; nu++) + ; + for (nr = 0; nu + nr < n && obs[nu + nr].rcv == 2; nr++) + ; + + time = rtk->sol.time; /* previous epoch */ + + /* rover position by single point positioning */ + if (!pntpos(obs, nu, nav, &rtk->opt, &rtk->sol, nullptr, rtk->ssat, msg)) + { + errmsg(rtk, "point pos error (%s)\n", msg); + if (!rtk->opt.dynamics) + { + outsolstat(rtk); + return 0; + } + } + if (time.time != 0) rtk->tt = timediff(rtk->sol.time, time); + + /* single point positioning */ + if (opt->mode == PMODE_SINGLE) + { + outsolstat(rtk); + return 1; + } + /* suppress output of single solution */ + if (!opt->outsingle) + { + rtk->sol.stat = SOLQ_NONE; + } + /* precise point positioning */ + if (opt->mode >= PMODE_PPP_KINEMA) + { + pppos(rtk, obs, nu, nav); + outsolstat(rtk); + return 1; + } + /* check number of data of base station and age of differential */ + if (nr == 0) + { + errmsg(rtk, "no base station observation data for rtk\n"); + outsolstat(rtk); + return 1; + } + if (opt->mode == PMODE_MOVEB) + { /* moving baseline */ + + /* estimate position/velocity of base station */ + if (!pntpos(obs + nu, nr, nav, &rtk->opt, &solb, nullptr, nullptr, msg)) + { + errmsg(rtk, "base station position error (%s)\n", msg); + return 0; + } + rtk->sol.age = static_cast(timediff(rtk->sol.time, solb.time)); + + if (fabs(rtk->sol.age) > TTOL_MOVEB) + { + errmsg(rtk, "time sync error for moving-base (age=%.1f)\n", rtk->sol.age); + return 0; + } + for (i = 0; i < 6; i++) rtk->rb[i] = solb.rr[i]; + + /* time-synchronized position of base station */ + for (i = 0; i < 3; i++) rtk->rb[i] += rtk->rb[i + 3] * rtk->sol.age; + } + else + { + rtk->sol.age = static_cast(timediff(obs[0].time, obs[nu].time)); + + if (fabs(rtk->sol.age) > opt->maxtdiff) + { + errmsg(rtk, "age of differential error (age=%.1f)\n", rtk->sol.age); + outsolstat(rtk); + return 1; + } + } + /* relative potitioning */ + relpos(rtk, obs, nu, nr, nav); + outsolstat(rtk); + + return 1; +} diff --git a/src/algorithms/libs/rtklib/rtklib_rtkpos.h b/src/algorithms/libs/rtklib/rtklib_rtkpos.h new file mode 100644 index 000000000..3cac6b4d0 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtkpos.h @@ -0,0 +1,194 @@ +/*! + * \file rtklib_rtkpos.h + * \brief rtklib ppp-related functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_RKTPOS_H_ +#define GNSS_SDR_RTKLIB_RKTPOS_H_ + +#include "rtklib.h" +#include "rtklib_rtkcmn.h" + +/* constants/macros ----------------------------------------------------------*/ +const double VAR_POS = std::pow(30.0, 2.0); /* initial variance of receiver pos (m^2) */ +const double VAR_VEL = std::pow(10.0, 2.0); /* initial variance of receiver vel ((m/s)^2) */ +const double VAR_ACC = std::pow(10.0, 2.0); /* initial variance of receiver acc ((m/ss)^2) */ +const double VAR_HWBIAS = std::pow(1.0, 2.0); /* initial variance of h/w bias ((m/MHz)^2) */ +const double VAR_GRA = std::pow(0.001, 2.0); /* initial variance of gradient (m^2) */ +const double INIT_ZWD = 0.15; /* initial zwd (m) */ + +const double PRN_HWBIA = 1E-6; /* process noise of h/w bias (m/MHz/sqrt(s)) */ +const double MAXAC = 30.0; /* max accel for doppler slip detection (m/s^2) */ + +const double VAR_HOLDAMB = 0.001; /* constraint to hold ambiguity (cycle^2) */ + +const double TTOL_MOVEB = (1.0 + 2 * DTTOL); +/* time sync tolerance for moving-baseline (s) */ + +/* number of parameters (pos,ionos,tropos,hw-bias,phase-bias,real,estimated) */ + + +/* state variable index */ +#define II_RTK(s, opt) (NP_RTK(opt) + (s)-1) /* ionos (s:satellite no) */ +#define IT_RTK(r, opt) (NP_RTK(opt) + NI_RTK(opt) + NT_RTK(opt) / 2 * (r)) /* tropos (r:0=rov,1:ref) */ +#define IL_RTK(f, opt) (NP_RTK(opt) + NI_RTK(opt) + NT_RTK(opt) + (f)) /* receiver h/w bias */ +#define IB_RTK(s, f, opt) (NR_RTK(opt) + MAXSAT * (f) + (s)-1) /* phase bias (s:satno,f:freq) */ + +int rtkopenstat(const char *file, int level); + +void rtkclosestat(void); + +void rtkoutstat(rtk_t *rtk); + +void swapsolstat(void); + +void outsolstat(rtk_t *rtk); + +void errmsg(rtk_t *rtk, const char *format, ...); + +double sdobs(const obsd_t *obs, int i, int j, int f); + +double gfobs_L1L2(const obsd_t *obs, int i, int j, const double *lam); + +double gfobs_L1L5(const obsd_t *obs, int i, int j, const double *lam); + +double varerr(int sat, int sys, double el, double bl, double dt, int f, + const prcopt_t *opt); + + +double baseline(const double *ru, const double *rb, double *dr); + +void initx_rtk(rtk_t *rtk, double xi, double var, int i); + +int selsat(const obsd_t *obs, const double *azel, int nu, int nr, + const prcopt_t *opt, int *sat, int *iu, int *ir); + +void udpos(rtk_t *rtk, double tt); + +void udion(rtk_t *rtk, double tt, double bl, const int *sat, int ns); + +void udtrop(rtk_t *rtk, double tt, double bl); + +void udrcvbias(rtk_t *rtk, double tt); + +void detslp_ll(rtk_t *rtk, const obsd_t *obs, int i, int rcv); +void detslp_gf_L1L2(rtk_t *rtk, const obsd_t *obs, int i, int j, + const nav_t *nav); + +void detslp_gf_L1L5(rtk_t *rtk, const obsd_t *obs, int i, int j, + const nav_t *nav); + +void detslp_dop(rtk_t *rtk, const obsd_t *obs, int i, int rcv, + const nav_t *nav); + +void udbias(rtk_t *rtk, double tt, const obsd_t *obs, const int *sat, + const int *iu, const int *ir, int ns, const nav_t *nav); + +void udstate(rtk_t *rtk, const obsd_t *obs, const int *sat, + const int *iu, const int *ir, int ns, const nav_t *nav); + +void zdres_sat(int base, double r, const obsd_t *obs, const nav_t *nav, + const double *azel, const double *dant, + const prcopt_t *opt, double *y); + +int zdres(int base, const obsd_t *obs, int n, const double *rs, + const double *dts, const int *svh, const nav_t *nav, + const double *rr, const prcopt_t *opt, int index, double *y, + double *e, double *azel); + +int validobs(int i, int j, int f, int nf, const double *y); + +void ddcov(const int *nb, int n, const double *Ri, const double *Rj, + int nv, double *R); + +int constbl(rtk_t *rtk, const double *x, const double *P, double *v, + double *H, double *Ri, double *Rj, int index); + +double prectrop(gtime_t time, const double *pos, int r, + const double *azel, const prcopt_t *opt, const double *x, + double *dtdx); + +double gloicbcorr(int sat1, int sat2, const prcopt_t *opt, double lam1, + double lam2, int f); + +int test_sys(int sys, int m); + +int ddres(rtk_t *rtk, const nav_t *nav, double dt, const double *x, + const double *P, const int *sat, double *y, const double *e, + double *azel, const int *iu, const int *ir, int ns, double *v, + double *H, double *R, int *vflg); + +double intpres(gtime_t time, const obsd_t *obs, int n, const nav_t *nav, + rtk_t *rtk, double *y); + + +int ddmat(rtk_t *rtk, double *D); + +void restamb(rtk_t *rtk, const double *bias, int nb, double *xa); + +void holdamb(rtk_t *rtk, const double *xa); + +int resamb_LAMBDA(rtk_t *rtk, double *bias, double *xa); + +int valpos(rtk_t *rtk, const double *v, const double *R, const int *vflg, + int nv, double thres); + +int relpos(rtk_t *rtk, const obsd_t *obs, int nu, int nr, + const nav_t *nav); + +void rtkinit(rtk_t *rtk, const prcopt_t *opt); + +void rtkfree(rtk_t *rtk); + +int rtkpos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_rtksvr.cc b/src/algorithms/libs/rtklib/rtklib_rtksvr.cc new file mode 100644 index 000000000..ac047012a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtksvr.cc @@ -0,0 +1,1019 @@ + +#include "rtklib_rtksvr.h" +#include "rtklib_preceph.h" +#include "rtklib_rtcm.h" +#include "rtklib_rtkcmn.h" +#include "rtklib_rtkpos.h" +#include "rtklib_sbas.h" +#include "rtklib_solution.h" +#include "rtklib_stream.h" + +/* write solution header to output stream ------------------------------------*/ +void writesolhead(stream_t *stream, const solopt_t *solopt) +{ + unsigned char buff[1024]; + int n; + n = outsolheads(buff, solopt); + strwrite(stream, buff, n); +} + + +/* save output buffer --------------------------------------------------------*/ +void saveoutbuf(rtksvr_t *svr, unsigned char *buff, int n, int index) +{ + rtksvrlock(svr); + + n = n < svr->buffsize - svr->nsb[index] ? n : svr->buffsize - svr->nsb[index]; + memcpy(svr->sbuf[index] + svr->nsb[index], buff, n); + svr->nsb[index] += n; + + rtksvrunlock(svr); +} + + +/* write solution to output stream -------------------------------------------*/ +void writesol(rtksvr_t *svr, int index) +{ + solopt_t solopt = solopt_default; + unsigned char buff[1024]; + int i, n; + + tracet(4, "writesol: index=%d\n", index); + + for (i = 0; i < 2; i++) + { + /* output solution */ + n = outsols(buff, &svr->rtk.sol, svr->rtk.rb, svr->solopt + i); + strwrite(svr->stream + i + 3, buff, n); + + /* save output buffer */ + saveoutbuf(svr, buff, n, i); + + /* output extended solution */ + n = outsolexs(buff, &svr->rtk.sol, svr->rtk.ssat, svr->solopt + i); + strwrite(svr->stream + i + 3, buff, n); + + /* save output buffer */ + saveoutbuf(svr, buff, n, i); + } + /* output solution to monitor port */ + if (svr->moni) + { + n = outsols(buff, &svr->rtk.sol, svr->rtk.rb, &solopt); + strwrite(svr->moni, buff, n); + } + /* save solution buffer */ + if (svr->nsol < MAXSOLBUF) + { + rtksvrlock(svr); + svr->solbuf[svr->nsol++] = svr->rtk.sol; + rtksvrunlock(svr); + } +} + + +/* update navigation data ----------------------------------------------------*/ +void updatenav(nav_t *nav) +{ + int i, j; + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ; j++) + { + nav->lam[i][j] = satwavelen(i + 1, j, nav); + } +} + + +/* update glonass frequency channel number in raw data struct ----------------*/ +void updatefcn(rtksvr_t *svr) +{ + int i, j, sat, frq; + + for (i = 0; i < MAXPRNGLO; i++) + { + sat = satno(SYS_GLO, i + 1); + + for (j = 0, frq = -999; j < 3; j++) + { + if (svr->raw[j].nav.geph[i].sat != sat) continue; + frq = svr->raw[j].nav.geph[i].frq; + } + if (frq < -7 || frq > 6) continue; + + for (j = 0; j < 3; j++) + { + if (svr->raw[j].nav.geph[i].sat == sat) continue; + svr->raw[j].nav.geph[i].sat = sat; + svr->raw[j].nav.geph[i].frq = frq; + } + } +} + + +/* update rtk server struct --------------------------------------------------*/ +void updatesvr(rtksvr_t *svr, int ret, obs_t *obs, nav_t *nav, int sat, + sbsmsg_t *sbsmsg, int index, int iobs) +{ + eph_t *eph1, *eph2, *eph3; + geph_t *geph1, *geph2, *geph3; + // gtime_t tof; + double pos[3], del[3] = {0}, dr[3]; + int i, n = 0, prn, sbssat = svr->rtk.opt.sbassatsel, sys, iode; + + tracet(4, "updatesvr: ret=%d sat=%2d index=%d\n", ret, sat, index); + + if (ret == 1) + { /* observation data */ + if (iobs < MAXOBSBUF) + { + for (i = 0; i < obs->n; i++) + { + if (svr->rtk.opt.exsats[obs->data[i].sat - 1] == 1 || + !(satsys(obs->data[i].sat, nullptr) & svr->rtk.opt.navsys)) continue; + svr->obs[index][iobs].data[n] = obs->data[i]; + svr->obs[index][iobs].data[n++].rcv = index + 1; + } + svr->obs[index][iobs].n = n; + sortobs(&svr->obs[index][iobs]); + } + svr->nmsg[index][0]++; + } + else if (ret == 2) + { /* ephemeris */ + if (satsys(sat, &prn) != SYS_GLO) + { + if (!svr->navsel || svr->navsel == index + 1) + { + eph1 = nav->eph + sat - 1; + eph2 = svr->nav.eph + sat - 1; + eph3 = svr->nav.eph + sat - 1 + MAXSAT; + if (eph2->ttr.time == 0 || + (eph1->iode != eph3->iode && eph1->iode != eph2->iode) || + (timediff(eph1->toe, eph3->toe) != 0.0 && + timediff(eph1->toe, eph2->toe) != 0.0)) + { + *eph3 = *eph2; + *eph2 = *eph1; + updatenav(&svr->nav); + } + } + svr->nmsg[index][1]++; + } + else + { + if (!svr->navsel || svr->navsel == index + 1) + { + geph1 = nav->geph + prn - 1; + geph2 = svr->nav.geph + prn - 1; + geph3 = svr->nav.geph + prn - 1 + MAXPRNGLO; + if (geph2->tof.time == 0 || + (geph1->iode != geph3->iode && geph1->iode != geph2->iode)) + { + *geph3 = *geph2; + *geph2 = *geph1; + updatenav(&svr->nav); + updatefcn(svr); + } + } + svr->nmsg[index][6]++; + } + } + else if (ret == 3) + { /* sbas message */ + if (sbsmsg && (sbssat == sbsmsg->prn || sbssat == 0)) + { + if (svr->nsbs < MAXSBSMSG) + { + svr->sbsmsg[svr->nsbs++] = *sbsmsg; + } + else + { + for (i = 0; i < MAXSBSMSG - 1; i++) svr->sbsmsg[i] = svr->sbsmsg[i + 1]; + svr->sbsmsg[i] = *sbsmsg; + } + sbsupdatecorr(sbsmsg, &svr->nav); + } + svr->nmsg[index][3]++; + } + else if (ret == 9) + { /* ion/utc parameters */ + if (svr->navsel == index || svr->navsel >= 3) + { + for (i = 0; i < 8; i++) svr->nav.ion_gps[i] = nav->ion_gps[i]; + for (i = 0; i < 4; i++) svr->nav.utc_gps[i] = nav->utc_gps[i]; + for (i = 0; i < 4; i++) svr->nav.ion_gal[i] = nav->ion_gal[i]; + for (i = 0; i < 4; i++) svr->nav.utc_gal[i] = nav->utc_gal[i]; + for (i = 0; i < 8; i++) svr->nav.ion_qzs[i] = nav->ion_qzs[i]; + for (i = 0; i < 4; i++) svr->nav.utc_qzs[i] = nav->utc_qzs[i]; + svr->nav.leaps = nav->leaps; + } + svr->nmsg[index][2]++; + } + else if (ret == 5) + { /* antenna position parameters */ + if (svr->rtk.opt.refpos == 4 && index == 1) + { + for (i = 0; i < 3; i++) + { + svr->rtk.rb[i] = svr->rtcm[1].sta.pos[i]; + } + /* antenna delta */ + ecef2pos(svr->rtk.rb, pos); + if (svr->rtcm[1].sta.deltype) + { /* xyz */ + del[2] = svr->rtcm[1].sta.hgt; + enu2ecef(pos, del, dr); + for (i = 0; i < 3; i++) + { + svr->rtk.rb[i] += svr->rtcm[1].sta.del[i] + dr[i]; + } + } + else + { /* enu */ + enu2ecef(pos, svr->rtcm[1].sta.del, dr); + for (i = 0; i < 3; i++) + { + svr->rtk.rb[i] += dr[i]; + } + } + } + svr->nmsg[index][4]++; + } + else if (ret == 7) + { /* dgps correction */ + svr->nmsg[index][5]++; + } + else if (ret == 10) + { /* ssr message */ + for (i = 0; i < MAXSAT; i++) + { + if (!svr->rtcm[index].ssr[i].update) continue; + svr->rtcm[index].ssr[i].update = 0; + + iode = svr->rtcm[index].ssr[i].iode; + sys = satsys(i + 1, &prn); + + /* check corresponding ephemeris exists */ + if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS) + { + if (svr->nav.eph[i].iode != iode && + svr->nav.eph[i + MAXSAT].iode != iode) + { + continue; + } + } + else if (sys == SYS_GLO) + { + if (svr->nav.geph[prn - 1].iode != iode && + svr->nav.geph[prn - 1 + MAXPRNGLO].iode != iode) + { + continue; + } + } + svr->nav.ssr[i] = svr->rtcm[index].ssr[i]; + } + svr->nmsg[index][7]++; + } + else if (ret == 31) + { /* lex message */ + // lexupdatecorr(&svr->raw[index].lexmsg, &svr->nav, &tof); + svr->nmsg[index][8]++; + } + else if (ret == -1) + { /* error */ + svr->nmsg[index][9]++; + } +} + + +/* decode receiver raw/rtcm data ---------------------------------------------*/ +int decoderaw(rtksvr_t *svr, int index) +{ + obs_t *obs; + nav_t *nav; + sbsmsg_t *sbsmsg = nullptr; + int i, ret = 0, sat, fobs = 0; + + tracet(4, "decoderaw: index=%d\n", index); + + rtksvrlock(svr); + + for (i = 0; i < svr->nb[index]; i++) + { + /* input rtcm/receiver raw data from stream */ + if (svr->format[index] == STRFMT_RTCM2) + { + ret = input_rtcm2(svr->rtcm + index, svr->buff[index][i]); + obs = &svr->rtcm[index].obs; + nav = &svr->rtcm[index].nav; + sat = svr->rtcm[index].ephsat; + } + else if (svr->format[index] == STRFMT_RTCM3) + { + ret = input_rtcm3(svr->rtcm + index, svr->buff[index][i]); + obs = &svr->rtcm[index].obs; + nav = &svr->rtcm[index].nav; + sat = svr->rtcm[index].ephsat; + } + else + { + // Disabled !! + //ret = input_raw(svr->raw+index, svr->format[index], svr->buff[index][i]); + obs = &svr->raw[index].obs; + nav = &svr->raw[index].nav; + sat = svr->raw[index].ephsat; + sbsmsg = &svr->raw[index].sbsmsg; + } +#if 0 /* record for receiving tick */ + if (ret == 1) + { + trace(0, "%d %10d T=%s NS=%2d\n", index, tickget(), + time_str(obs->data[0].time, 0), obs->n); + } +#endif + /* update rtk server */ + if (ret > 0) updatesvr(svr, ret, obs, nav, sat, sbsmsg, index, fobs); + + /* observation data received */ + if (ret == 1) + { + if (fobs < MAXOBSBUF) + fobs++; + else + svr->prcout++; + } + } + svr->nb[index] = 0; + + rtksvrunlock(svr); + + return fobs; +} + + +/* decode download file ------------------------------------------------------*/ +void decodefile(rtksvr_t *svr, int index) +{ + int i = 0; + char glo_fcn[MAXPRNGLO + 1]; + + // Allocate space for GLONASS frequency channels depending on availability + for (i = 0; i < MAXPRNGLO + 1; i++) + glo_fcn[i] = '0'; + pcv_t pcvt0[MAXSAT] = {{0, {'0'}, {'0'}, {0, 0.0}, {0, 0.0}, {{0.0}, {0.0}}, {{0.0}, {0.0}}}}; + sbsfcorr_t sbsfcorr0 = {{0, 0.0}, 0.0, 0.0, 0.0, 0, 0, 0}; + sbslcorr_t sbslcorr0 = {{0, 0.0}, 0, {0.0}, {0.0}, 0.0, 0.0}; + sbssat_t sbssat0 = {0, 0, 0, {{0, sbsfcorr0, sbslcorr0}}}; + sbsigp_t sbsigp0[MAXNIGP] = {{{0, 0.0}, 0, 0, 0, 0.0}}; + sbsion_t sbsion0[MAXBAND + 1] = {{0, 0, {*sbsigp0}}}; + dgps_t dgps0[MAXSAT] = {{{0, 0.0}, 0.0, 0.0, 0, 0.0}}; + ssr_t ssr0[MAXSAT] = {{{{0, 0.0}}, {0.0}, {0}, 0, 0, 0, 0, {0.0}, {0.0}, {0.0}, 0.0, {0.0}, {0.0}, {0.0}, 0.0, 0.0, '0'}}; + lexeph_t lexeph0[MAXSAT] = {{{0, 0.0}, {0, 0.0}, 0, 0, 0, {0.0}, {0.0}, {0.0}, {0.0}, 0.0, 0.0, 0.0, {0.0}}}; + stec_t stec0[MAXSTA] = {{{0, 0.0}, 0, 0.0, 0.0, {0.0}, 0}}; + trop_t trop0[MAXSTA] = {{{0, 0.0}, {0.0}, {0.0}}}; + pppcorr_t pppcorr0 = {0, {{0}, {0}}, {{0.0}, {0.0}}, {0}, {0}, {0}, {0}, {stec0}, {trop0}}; + + nav_t nav = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + {0, 0, (erpd_t *){nullptr}}, {0.0}, {0.0}, {0.0}, {0.0}, {0.0}, {0.0}, {0.0}, {0.0}, + {0.0}, {0.0}, {0.0}, {0.0}, 0, {{0.0}, {0.0}}, {{0.0}, {0.0}}, {{{0.0}}, {{0.0}}, {{0.0}}}, + {0.0}, {0.0}, {*glo_fcn}, {*pcvt0}, sbssat0, {*sbsion0}, {*dgps0}, {*ssr0}, {*lexeph0}, + {{0, 0.0}, 0.0, {0.0}, {{0.0}, {0.0}}}, pppcorr0}; + + char file[1024]; + int nb; + + tracet(4, "decodefile: index=%d\n", index); + + rtksvrlock(svr); + + /* check file path completed */ + if ((nb = svr->nb[index]) <= 2 || + svr->buff[index][nb - 2] != '\r' || svr->buff[index][nb - 1] != '\n') + { + rtksvrunlock(svr); + return; + } + strncpy(file, reinterpret_cast(svr->buff[index]), nb - 2); + file[nb - 2] = '\0'; + svr->nb[index] = 0; + + rtksvrunlock(svr); + + if (svr->format[index] == STRFMT_SP3) + { /* precise ephemeris */ + + /* read sp3 precise ephemeris */ + readsp3(file, &nav, 0); + if (nav.ne <= 0) + { + tracet(1, "sp3 file read error: %s\n", file); + return; + } + /* update precise ephemeris */ + rtksvrlock(svr); + + if (svr->nav.peph) free(svr->nav.peph); + svr->nav.ne = svr->nav.nemax = nav.ne; + svr->nav.peph = nav.peph; + svr->ftime[index] = utc2gpst(timeget()); + strcpy(svr->files[index], file); + + rtksvrunlock(svr); + } + else if (svr->format[index] == STRFMT_RNXCLK) + { /* precise clock */ + + /* read rinex clock */ // Disabled!! + if (true /*readrnxc(file, &nav)<=0 */) + { + tracet(1, "rinex clock file read error: %s\n", file); + return; + } + /* update precise clock */ + rtksvrlock(svr); + + if (svr->nav.pclk) free(svr->nav.pclk); + svr->nav.nc = svr->nav.ncmax = nav.nc; + svr->nav.pclk = nav.pclk; + svr->ftime[index] = utc2gpst(timeget()); + strcpy(svr->files[index], file); + + rtksvrunlock(svr); + } +} + + +/* rtk server thread ---------------------------------------------------------*/ +void *rtksvrthread(void *arg) +{ + auto *svr = static_cast(arg); + obs_t obs; + obsd_t data[MAXOBS * 2]; + double tt; + unsigned int tick, ticknmea; + unsigned char *p, *q; + int i, j, n, fobs[3] = {0}, cycle, cputime; + + tracet(3, "rtksvrthread:\n"); + + svr->state = 1; + obs.data = data; + svr->tick = tickget(); + ticknmea = svr->tick - 1000; + + for (cycle = 0; svr->state; cycle++) + { + tick = tickget(); + + for (i = 0; i < 3; i++) + { + p = svr->buff[i] + svr->nb[i]; + q = svr->buff[i] + svr->buffsize; + + /* read receiver raw/rtcm data from input stream */ + if ((n = strread(svr->stream + i, p, static_cast(q[0]) - static_cast(p[0]))) <= 0) + { + continue; + } + /* write receiver raw/rtcm data to log stream */ + strwrite(svr->stream + i + 5, p, n); + svr->nb[i] += n; + + /* save peek buffer */ + rtksvrlock(svr); + n = n < svr->buffsize - svr->npb[i] ? n : svr->buffsize - svr->npb[i]; + memcpy(svr->pbuf[i] + svr->npb[i], p, n); + svr->npb[i] += n; + rtksvrunlock(svr); + } + for (i = 0; i < 3; i++) + { + if (svr->format[i] == STRFMT_SP3 || svr->format[i] == STRFMT_RNXCLK) + { + /* decode download file */ + decodefile(svr, i); + } + else + { + /* decode receiver raw/rtcm data */ + fobs[i] = decoderaw(svr, i); + } + } + for (i = 0; i < fobs[0]; i++) + { /* for each rover observation data */ + obs.n = 0; + for (j = 0; j < svr->obs[0][i].n && obs.n < MAXOBS * 2; j++) + { + obs.data[obs.n++] = svr->obs[0][i].data[j]; + } + for (j = 0; j < svr->obs[1][0].n && obs.n < MAXOBS * 2; j++) + { + obs.data[obs.n++] = svr->obs[1][0].data[j]; + } + /* rtk positioning */ + rtksvrlock(svr); + rtkpos(&svr->rtk, obs.data, obs.n, &svr->nav); + rtksvrunlock(svr); + + if (svr->rtk.sol.stat != SOLQ_NONE) + { + /* adjust current time */ + tt = static_cast(tickget() - tick) / 1000.0 + DTTOL; + timeset(gpst2utc(timeadd(svr->rtk.sol.time, tt))); + + /* write solution */ + writesol(svr, i); + } + /* if cpu overload, inclement obs outage counter and break */ + if (static_cast(tickget() - tick) >= svr->cycle) + { + svr->prcout += fobs[0] - i - 1; +#if 0 /* omitted v.2.4.1 */ + break; +#endif + } + } + /* send null solution if no solution (1hz) */ + if (svr->rtk.sol.stat == SOLQ_NONE && cycle % (1000 / svr->cycle) == 0) + { + writesol(svr, 0); + } + /* send nmea request to base/nrtk input stream */ + if (svr->nmeacycle > 0 && static_cast(tick - ticknmea) >= svr->nmeacycle) + { + if (svr->stream[1].state == 1) + { + if (svr->nmeareq == 1) + { + strsendnmea(svr->stream + 1, svr->nmeapos); + } + else if (svr->nmeareq == 2 && norm_rtk(svr->rtk.sol.rr, 3) > 0.0) + { + strsendnmea(svr->stream + 1, svr->rtk.sol.rr); + } + } + ticknmea = tick; + } + if ((cputime = static_cast(tickget() - tick)) > 0) svr->cputime = cputime; + + /* sleep until next cycle */ + sleepms(svr->cycle - cputime); + } + for (i = 0; i < MAXSTRRTK; i++) strclose(svr->stream + i); + for (i = 0; i < 3; i++) + { + svr->nb[i] = svr->npb[i] = 0; + free(svr->buff[i]); + svr->buff[i] = nullptr; + free(svr->pbuf[i]); + svr->pbuf[i] = nullptr; + //free_raw (svr->raw +i); + free_rtcm(svr->rtcm + i); + } + for (i = 0; i < 2; i++) + { + svr->nsb[i] = 0; + free(svr->sbuf[i]); + svr->sbuf[i] = nullptr; + } + return nullptr; +} + + +/* initialize rtk server ------------------------------------------------------- + * initialize rtk server + * args : rtksvr_t *svr IO rtk server + * return : status (0:error, 1:ok) + *-----------------------------------------------------------------------------*/ +int rtksvrinit(rtksvr_t *svr) +{ + gtime_t time0 = {0, 0.0}; + sol_t sol0 = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + '0', '0', '0', 0, 0, 0}; + eph_t eph0 = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + geph_t geph0 = {0, -1, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0.0}, {0.0}, {0.0}, + 0.0, 0.0, 0.0}; + seph_t seph0 = {0, {0, 0.0}, {0, 0.0}, 0, 0, {0.0}, {0.0}, {0.0}, 0.0, 0.0}; + int i, j; + + tracet(3, "rtksvrinit:\n"); + + svr->state = svr->cycle = svr->nmeacycle = svr->nmeareq = 0; + for (i = 0; i < 3; i++) svr->nmeapos[i] = 0.0; + svr->buffsize = 0; + for (i = 0; i < 3; i++) svr->format[i] = 0; + for (i = 0; i < 2; i++) svr->solopt[i] = solopt_default; + svr->navsel = svr->nsbs = svr->nsol = 0; + rtkinit(&svr->rtk, &prcopt_default); + for (i = 0; i < 3; i++) svr->nb[i] = 0; + for (i = 0; i < 2; i++) svr->nsb[i] = 0; + for (i = 0; i < 3; i++) svr->npb[i] = 0; + for (i = 0; i < 3; i++) svr->buff[i] = nullptr; + for (i = 0; i < 2; i++) svr->sbuf[i] = nullptr; + for (i = 0; i < 3; i++) svr->pbuf[i] = nullptr; + for (i = 0; i < MAXSOLBUF; i++) svr->solbuf[i] = sol0; + for (i = 0; i < 3; i++) + for (j = 0; j < 10; j++) svr->nmsg[i][j] = 0; + for (i = 0; i < 3; i++) svr->ftime[i] = time0; + for (i = 0; i < 3; i++) svr->files[i][0] = '\0'; + svr->moni = nullptr; + svr->tick = 0; + svr->thread = 0; // NOLINT + svr->cputime = svr->prcout = 0; + + if (!(svr->nav.eph = static_cast(malloc(sizeof(eph_t) * MAXSAT * 2))) || + !(svr->nav.geph = static_cast(malloc(sizeof(geph_t) * NSATGLO * 2))) || + !(svr->nav.seph = static_cast(malloc(sizeof(seph_t) * NSATSBS * 2)))) + { + tracet(1, "rtksvrinit: malloc error\n"); + return 0; + } + for (i = 0; i < MAXSAT * 2; i++) svr->nav.eph[i] = eph0; + for (i = 0; i < NSATGLO * 2; i++) svr->nav.geph[i] = geph0; + for (i = 0; i < NSATSBS * 2; i++) svr->nav.seph[i] = seph0; + svr->nav.n = MAXSAT * 2; + svr->nav.ng = NSATGLO * 2; + svr->nav.ns = NSATSBS * 2; + + for (i = 0; i < 3; i++) + for (j = 0; j < MAXOBSBUF; j++) + { + if (!(svr->obs[i][j].data = static_cast(malloc(sizeof(obsd_t) * MAXOBS)))) + { + tracet(1, "rtksvrinit: malloc error\n"); + return 0; + } + } + for (i = 0; i < 3; i++) + { + memset(svr->raw + i, 0, sizeof(raw_t)); + memset(svr->rtcm + i, 0, sizeof(rtcm_t)); + } + for (i = 0; i < MAXSTRRTK; i++) strinit(svr->stream + i); + + initlock(&svr->lock); + + return 1; +} + + +/* free rtk server ------------------------------------------------------------- + * free rtk server + * args : rtksvr_t *svr IO rtk server + * return : none + *-----------------------------------------------------------------------------*/ +void rtksvrfree(rtksvr_t *svr) +{ + int i, j; + + free(svr->nav.eph); + free(svr->nav.geph); + free(svr->nav.seph); + for (i = 0; i < 3; i++) + for (j = 0; j < MAXOBSBUF; j++) + { + free(svr->obs[i][j].data); + } +} + + +/* lock/unlock rtk server ------------------------------------------------------ + * lock/unlock rtk server + * args : rtksvr_t *svr IO rtk server + * return : status (1:ok 0:error) + *-----------------------------------------------------------------------------*/ +void rtksvrlock(rtksvr_t *svr) { rtk_lock(&svr->lock); } + + +void rtksvrunlock(rtksvr_t *svr) { rtk_unlock(&svr->lock); } + + +/* start rtk server ------------------------------------------------------------ + * start rtk server thread + * args : rtksvr_t *svr IO rtk server + * int cycle I server cycle (ms) + * int buffsize I input buffer size (bytes) + * int *strs I stream types (STR_???) + * types[0]=input stream rover + * types[1]=input stream base station + * types[2]=input stream correction + * types[3]=output stream solution 1 + * types[4]=output stream solution 2 + * types[5]=log stream rover + * types[6]=log stream base station + * types[7]=log stream correction + * char *paths I input stream paths + * int *format I input stream formats (STRFMT_???) + * format[0]=input stream rover + * format[1]=input stream base station + * format[2]=input stream correction + * int navsel I navigation message select + * (0:rover, 1:base, 2:ephem, 3:all) + * char **cmds I input stream start commands + * cmds[0]=input stream rover (NULL: no command) + * cmds[1]=input stream base (NULL: no command) + * cmds[2]=input stream corr (NULL: no command) + * char **rcvopts I receiver options + * rcvopt[0]=receiver option rover + * rcvopt[1]=receiver option base + * rcvopt[2]=receiver option corr + * int nmeacycle I nmea request cycle (ms) (0:no request) + * int nmeareq I nmea request type (0:no, 1:base pos, 2:single sol) + * double *nmeapos I transmitted nmea position (ecef) (m) + * prcopt_t *prcopt I rtk processing options + * solopt_t *solopt I solution options + * solopt[0]=solution 1 options + * solopt[1]=solution 2 options + * stream_t *moni I monitor stream (NULL: not used) + * return : status (1:ok 0:error) + *-----------------------------------------------------------------------------*/ +int rtksvrstart(rtksvr_t *svr, int cycle, int buffsize, int *strs, + char **paths, const int *formats, int navsel, char **cmds, + char **rcvopts, int nmeacycle, int nmeareq, + const double *nmeapos, prcopt_t *prcopt, + solopt_t *solopt, stream_t *moni) +{ + gtime_t time, time0 = {0, 0.0}; + int i, j, rw; + + tracet(3, "rtksvrstart: cycle=%d buffsize=%d navsel=%d nmeacycle=%d nmeareq=%d\n", + cycle, buffsize, navsel, nmeacycle, nmeareq); + + if (svr->state) return 0; + + strinitcom(); + svr->cycle = cycle > 1 ? cycle : 1; + svr->nmeacycle = nmeacycle > 1000 ? nmeacycle : 1000; + svr->nmeareq = nmeareq; + for (i = 0; i < 3; i++) svr->nmeapos[i] = nmeapos[i]; + svr->buffsize = buffsize > 4096 ? buffsize : 4096; + for (i = 0; i < 3; i++) svr->format[i] = formats[i]; + svr->navsel = navsel; + svr->nsbs = 0; + svr->nsol = 0; + svr->prcout = 0; + rtkfree(&svr->rtk); + rtkinit(&svr->rtk, prcopt); + + for (i = 0; i < 3; i++) + { /* input/log streams */ + svr->nb[i] = svr->npb[i] = 0; + if (!(svr->buff[i] = static_cast(malloc(buffsize))) || + !(svr->pbuf[i] = static_cast(malloc(buffsize)))) + { + tracet(1, "rtksvrstart: malloc error\n"); + return 0; + } + for (j = 0; j < 10; j++) svr->nmsg[i][j] = 0; + for (j = 0; j < MAXOBSBUF; j++) svr->obs[i][j].n = 0; + + /* initialize receiver raw and rtcm control */ + //init_raw (svr->raw +i); + init_rtcm(svr->rtcm + i); + + /* set receiver and rtcm option */ + if (strlen(rcvopts[i]) < 256) strcpy(svr->raw[i].opt, rcvopts[i]); + if (strlen(rcvopts[i]) < 256) strcpy(svr->rtcm[i].opt, rcvopts[i]); + + /* connect dgps corrections */ + svr->rtcm[i].dgps = svr->nav.dgps; + } + for (i = 0; i < 2; i++) + { /* output peek buffer */ + if (!(svr->sbuf[i] = static_cast(malloc(buffsize)))) + { + tracet(1, "rtksvrstart: malloc error\n"); + return 0; + } + } + /* set solution options */ + for (i = 0; i < 2; i++) + { + svr->solopt[i] = solopt[i]; + } + /* set base station position */ + for (i = 0; i < 6; i++) + { + svr->rtk.rb[i] = i < 3 ? prcopt->rb[i] : 0.0; + } + /* update navigation data */ + for (i = 0; i < MAXSAT * 2; i++) svr->nav.eph[i].ttr = time0; + for (i = 0; i < NSATGLO * 2; i++) svr->nav.geph[i].tof = time0; + for (i = 0; i < NSATSBS * 2; i++) svr->nav.seph[i].tof = time0; + updatenav(&svr->nav); + + /* set monitor stream */ + svr->moni = moni; + + /* open input streams */ + for (i = 0; i < 8; i++) + { + rw = i < 3 ? STR_MODE_R : STR_MODE_W; + if (strs[i] != STR_FILE) rw |= STR_MODE_W; + if (!stropen(svr->stream + i, strs[i], rw, paths[i])) + { + for (i--; i >= 0; i--) strclose(svr->stream + i); + return 0; + } + /* set initial time for rtcm and raw */ + if (i < 3) + { + time = utc2gpst(timeget()); + svr->raw[i].time = strs[i] == STR_FILE ? strgettime(svr->stream + i) : time; + svr->rtcm[i].time = strs[i] == STR_FILE ? strgettime(svr->stream + i) : time; + } + } + /* sync input streams */ + strsync(svr->stream, svr->stream + 1); + strsync(svr->stream, svr->stream + 2); + + /* write start commands to input streams */ + for (i = 0; i < 3; i++) + { + if (cmds[i]) strsendcmd(svr->stream + i, cmds[i]); + } + /* write solution header to solution streams */ + for (i = 3; i < 5; i++) + { + writesolhead(svr->stream + i, svr->solopt + i - 3); + } + /* create rtk server thread */ + if (pthread_create(&svr->thread, nullptr, rtksvrthread, svr)) + { + for (i = 0; i < MAXSTRRTK; i++) strclose(svr->stream + i); + return 0; + } + return 1; +} + + +/* stop rtk server ------------------------------------------------------------- + * start rtk server thread + * args : rtksvr_t *svr IO rtk server + * char **cmds I input stream stop commands + * cmds[0]=input stream rover (NULL: no command) + * cmds[1]=input stream base (NULL: no command) + * cmds[2]=input stream ephem (NULL: no command) + * return : none + *-----------------------------------------------------------------------------*/ +void rtksvrstop(rtksvr_t *svr, char **cmds) +{ + int i; + + tracet(3, "rtksvrstop:\n"); + + /* write stop commands to input streams */ + rtksvrlock(svr); + for (i = 0; i < 3; i++) + { + if (cmds[i]) strsendcmd(svr->stream + i, cmds[i]); + } + rtksvrunlock(svr); + + /* stop rtk server */ + svr->state = 0; + + /* free rtk server thread */ + pthread_join(svr->thread, nullptr); +} + + +/* open output/log stream ------------------------------------------------------ + * open output/log stream + * args : rtksvr_t *svr IO rtk server + * int index I output/log stream index + * (3:solution 1, 4:solution 2, 5:log rover, + * 6:log base station, 7:log correction) + * int str I output/log stream types (STR_???) + * char *path I output/log stream path + * solopt_t *solopt I solution options + * return : status (1:ok 0:error) + *-----------------------------------------------------------------------------*/ +int rtksvropenstr(rtksvr_t *svr, int index, int str, const char *path, + const solopt_t *solopt) +{ + tracet(3, "rtksvropenstr: index=%d str=%d path=%s\n", index, str, path); + + if (index < 3 || index > 7 || !svr->state) return 0; + + rtksvrlock(svr); + + if (svr->stream[index].state > 0) + { + rtksvrunlock(svr); + return 0; + } + if (!stropen(svr->stream + index, str, STR_MODE_W, path)) + { + tracet(2, "stream open error: index=%d\n", index); + rtksvrunlock(svr); + return 0; + } + if (index <= 4) + { + svr->solopt[index - 3] = *solopt; + + /* write solution header to solution stream */ + writesolhead(svr->stream + index, svr->solopt + index - 3); + } + rtksvrunlock(svr); + return 1; +} + + +/* close output/log stream ----------------------------------------------------- + * close output/log stream + * args : rtksvr_t *svr IO rtk server + * int index I output/log stream index + * (3:solution 1, 4:solution 2, 5:log rover, + * 6:log base station, 7:log correction) + * return : none + *-----------------------------------------------------------------------------*/ +void rtksvrclosestr(rtksvr_t *svr, int index) +{ + tracet(3, "rtksvrclosestr: index=%d\n", index); + + if (index < 3 || index > 7 || !svr->state) return; + + rtksvrlock(svr); + + strclose(svr->stream + index); + + rtksvrunlock(svr); +} + + +/* get observation data status ------------------------------------------------- + * get current observation data status + * args : rtksvr_t *svr I rtk server + * int rcv I receiver (0:rover, 1:base, 2:ephem) + * gtime_t *time O time of observation data + * int *sat O satellite prn numbers + * double *az O satellite azimuth angles (rad) + * double *el O satellite elevation angles (rad) + * int **snr O satellite snr for each freq (dBHz) + * snr[i][j] = sat i freq j snr + * int *vsat O valid satellite flag + * return : number of satellites + *-----------------------------------------------------------------------------*/ +int rtksvrostat(rtksvr_t *svr, int rcv, gtime_t *time, int *sat, + double *az, double *el, int **snr, int *vsat) +{ + int i, j, ns; + + tracet(4, "rtksvrostat: rcv=%d\n", rcv); + + if (!svr->state) return 0; + rtksvrlock(svr); + ns = svr->obs[rcv][0].n; + if (ns > 0) + { + *time = svr->obs[rcv][0].data[0].time; + } + for (i = 0; i < ns; i++) + { + sat[i] = svr->obs[rcv][0].data[i].sat; + az[i] = svr->rtk.ssat[sat[i] - 1].azel[0]; + el[i] = svr->rtk.ssat[sat[i] - 1].azel[1]; + for (j = 0; j < NFREQ; j++) + { + snr[i][j] = static_cast(svr->obs[rcv][0].data[i].SNR[j] * 0.25); + } + if (svr->rtk.sol.stat == SOLQ_NONE || svr->rtk.sol.stat == SOLQ_SINGLE) + { + vsat[i] = svr->rtk.ssat[sat[i] - 1].vs; + } + else + { + vsat[i] = svr->rtk.ssat[sat[i] - 1].vsat[0]; + } + } + rtksvrunlock(svr); + return ns; +} + + +/* get stream status ----------------------------------------------------------- + * get current stream status + * args : rtksvr_t *svr I rtk server + * int *sstat O status of streams + * char *msg O status messages + * return : none + *-----------------------------------------------------------------------------*/ +void rtksvrsstat(rtksvr_t *svr, int *sstat, char *msg) +{ + int i; + char s[MAXSTRMSG], *p = msg; + + tracet(4, "rtksvrsstat:\n"); + + rtksvrlock(svr); + for (i = 0; i < MAXSTRRTK; i++) + { + sstat[i] = strstat(svr->stream + i, s); + if (*s) p += sprintf(p, "(%d) %s ", i + 1, s); + } + rtksvrunlock(svr); +} diff --git a/src/algorithms/libs/rtklib/rtklib_rtksvr.h b/src/algorithms/libs/rtklib/rtklib_rtksvr.h new file mode 100644 index 000000000..d5edbd252 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_rtksvr.h @@ -0,0 +1,137 @@ +/*! + * \file rtklib_rtksvr.h + * \brief rtk server functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_RKTSVR_H_ +#define GNSS_SDR_RTKLIB_RKTSVR_H_ + +#include "rtklib.h" + + +const solopt_t solopt_default = { + /* defaults solution output options */ + SOLF_LLH, TIMES_GPST, 1, 3, /* posf, times, timef, timeu */ + 0, 1, 0, 0, 0, 0, /* degf, outhead, outopt, datum, height, geoid */ + 0, 0, 0, /* solstatic, sstat, trace */ + {0.0, 0.0}, /* nmeaintv */ + " ", "", 0 /* separator/program name */ +}; + +const prcopt_t prcopt_default = { /* defaults processing options */ + PMODE_SINGLE, 0, 2, SYS_GPS, /* mode, soltype, nf, navsys */ + 15.0 * D2R, {{}, {{}, {}}}, /* elmin, snrmask */ + 0, 1, 1, 1, /* sateph, modear, glomodear, bdsmodear */ + 5, 0, 10, 1, /* maxout, minlock, minfix, armaxiter */ + 0, 0, 0, 0, /* estion, esttrop, dynamics, tidecorr */ + 1, 0, 0, 0, 0, /* niter, codesmooth, intpref, sbascorr, sbassatsel */ + 0, 0, /* rovpos, refpos */ + {100.0, 100.0, 100.0}, /* eratio[] */ + {100.0, 0.003, 0.003, 0.0, 1.0}, /* err[] */ + {30.0, 0.03, 0.3}, /* std[] */ + {1e-4, 1e-3, 1e-4, 1e-1, 1e-2, 0.0}, /* prn[] */ + 5E-12, /* sclkstab */ + {3.0, 0.9999, 0.25, 0.1, 0.05, 0, 0, 0}, /* thresar */ + 0.0, 0.0, 0.05, /* elmaskar, almaskhold, thresslip */ + 30.0, 30.0, 30.0, /* maxtdif, maxinno, maxgdop */ + {}, {}, {}, /* baseline, ru, rb */ + {"", ""}, /* anttype */ + {}, {}, {}, /* antdel, pcv, exsats */ + 0, 0, 0, {"", ""}, {}, 0, {{}, {}}, {{}, {{}, {}}, {{}, {}}, {}, {}}, 0, {}}; + + +void writesolhead(stream_t *stream, const solopt_t *solopt); + +void saveoutbuf(rtksvr_t *svr, unsigned char *buff, int n, int index); + +void writesol(rtksvr_t *svr, int index); + +void updatenav(nav_t *nav); + +void updatefcn(rtksvr_t *svr); + +void updatesvr(rtksvr_t *svr, int ret, obs_t *obs, nav_t *nav, int sat, + sbsmsg_t *sbsmsg, int index, int iobs); + +int decoderaw(rtksvr_t *svr, int index); + +void decodefile(rtksvr_t *svr, int index); + +void *rtksvrthread(void *arg); + +int rtksvrinit(rtksvr_t *svr); + +void rtksvrfree(rtksvr_t *svr); + +void rtksvrlock(rtksvr_t *svr); + +void rtksvrunlock(rtksvr_t *svr); + +int rtksvrstart(rtksvr_t *svr, int cycle, int buffsize, int *strs, + char **paths, const int *formats, int navsel, char **cmds, + char **rcvopts, int nmeacycle, int nmeareq, + const double *nmeapos, prcopt_t *prcopt, + solopt_t *solopt, stream_t *moni); + +void rtksvrstop(rtksvr_t *svr, char **cmds); + +int rtksvropenstr(rtksvr_t *svr, int index, int str, const char *path, + const solopt_t *solopt); + +void rtksvrclosestr(rtksvr_t *svr, int index); + +int rtksvrostat(rtksvr_t *svr, int rcv, gtime_t *time, int *sat, + double *az, double *el, int **snr, int *vsat); + +void rtksvrsstat(rtksvr_t *svr, int *sstat, char *msg); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_sbas.cc b/src/algorithms/libs/rtklib/rtklib_sbas.cc new file mode 100644 index 000000000..d4c45aad8 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_sbas.cc @@ -0,0 +1,1064 @@ +/*! + * \file rtklib_sbas.cc + * \brief sbas functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * References : + * [1] RTCA/DO-229C, Minimum operational performanc standards for global + * positioning system/wide area augmentation system airborne equipment, + * RTCA inc, November 28, 2001 + * [2] IS-QZSS v.1.1, Quasi-Zenith Satellite System Navigation Service + * Interface Specification for QZSS, Japan Aerospace Exploration Agency, + * July 31, 2009 + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_sbas.h" +#include "rtklib_rtkcmn.h" + +/* extract field from line ---------------------------------------------------*/ +char *getfield(char *p, int pos) +{ + for (pos--; pos > 0; pos--, p++) + if (!(p = strchr(p, ','))) return nullptr; + return p; +} + + +/* variance of fast correction (udre=UDRE+1) ---------------------------------*/ +double varfcorr(int udre) +{ + const double var[14] = { + 0.052, 0.0924, 0.1444, 0.283, 0.4678, 0.8315, 1.2992, 1.8709, 2.5465, 3.326, + 5.1968, 20.7870, 230.9661, 2078.695}; + return 0 < udre && udre <= 14 ? var[udre - 1] : 0.0; +} + + +/* variance of ionosphere correction (give=GIVEI+1) --------------------------*/ +double varicorr(int give) +{ + const double var[15] = { + 0.0084, 0.0333, 0.0749, 0.1331, 0.2079, 0.2994, 0.4075, 0.5322, 0.6735, 0.8315, + 1.1974, 1.8709, 3.326, 20.787, 187.0826}; + return 0 < give && give <= 15 ? var[give - 1] : 0.0; +} + + +/* fast correction degradation -----------------------------------------------*/ +double degfcorr(int ai) +{ + const double degf[16] = { + 0.00000, 0.00005, 0.00009, 0.00012, 0.00015, 0.00020, 0.00030, 0.00045, + 0.00060, 0.00090, 0.00150, 0.00210, 0.00270, 0.00330, 0.00460, 0.00580}; + return 0 < ai && ai <= 15 ? degf[ai] : 0.0058; +} + + +/* decode type 1: prn masks --------------------------------------------------*/ +int decode_sbstype1(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + int i, n, sat; + + trace(4, "decode_sbstype1:\n"); + + for (i = 1, n = 0; i <= 210 && n < MAXSAT; i++) + { + if (getbitu(msg->msg, 13 + i, 1)) + { + if (i <= 37) + sat = satno(SYS_GPS, i); /* 0- 37: gps */ + else if (i <= 61) + sat = satno(SYS_GLO, i - 37); /* 38- 61: glonass */ + else if (i <= 119) + sat = 0; /* 62-119: future gnss */ + else if (i <= 138) + sat = satno(SYS_SBS, i); /* 120-138: geo/waas */ + else if (i <= 182) + sat = 0; /* 139-182: reserved */ + else if (i <= 192) + sat = satno(SYS_SBS, i + 10); /* 183-192: qzss ref [2] */ + else if (i <= 202) + sat = satno(SYS_QZS, i); /* 193-202: qzss ref [2] */ + else + sat = 0; /* 203- : reserved */ + sbssat->sat[n++].sat = sat; + } + } + sbssat->iodp = getbitu(msg->msg, 224, 2); + sbssat->nsat = n; + + trace(5, "decode_sbstype1: nprn=%d iodp=%d\n", n, sbssat->iodp); + return 1; +} + + +/* decode type 2-5,0: fast corrections ---------------------------------------*/ +int decode_sbstype2(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + int i, j, iodf, type, udre; + double prc, dt; + gtime_t t0; + + trace(4, "decode_sbstype2:\n"); + + if (sbssat->iodp != static_cast(getbitu(msg->msg, 16, 2))) return 0; + + type = getbitu(msg->msg, 8, 6); + iodf = getbitu(msg->msg, 14, 2); + + for (i = 0; i < 13; i++) + { + if ((j = 13 * ((type == 0 ? 2 : type) - 2) + i) >= sbssat->nsat) break; + udre = getbitu(msg->msg, 174 + 4 * i, 4); + t0 = sbssat->sat[j].fcorr.t0; + prc = sbssat->sat[j].fcorr.prc; + sbssat->sat[j].fcorr.t0 = gpst2time(msg->week, msg->tow); + sbssat->sat[j].fcorr.prc = getbits(msg->msg, 18 + i * 12, 12) * 0.125f; + sbssat->sat[j].fcorr.udre = udre + 1; + dt = timediff(sbssat->sat[j].fcorr.t0, t0); + if (t0.time == 0 || dt <= 0.0 || 18.0 < dt || sbssat->sat[j].fcorr.ai == 0) + { + sbssat->sat[j].fcorr.rrc = 0.0; + sbssat->sat[j].fcorr.dt = 0.0; + } + else + { + sbssat->sat[j].fcorr.rrc = (sbssat->sat[j].fcorr.prc - prc) / dt; + sbssat->sat[j].fcorr.dt = dt; + } + sbssat->sat[j].fcorr.iodf = iodf; + } + trace(5, "decode_sbstype2: type=%d iodf=%d\n", type, iodf); + return 1; +} + + +/* decode type 6: integrity info ---------------------------------------------*/ +int decode_sbstype6(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + int i, iodf[4], udre; + + trace(4, "decode_sbstype6:\n"); + + for (i = 0; i < 4; i++) + { + iodf[i] = getbitu(msg->msg, 14 + i * 2, 2); + } + for (i = 0; i < sbssat->nsat && i < MAXSAT; i++) + { + if (sbssat->sat[i].fcorr.iodf != iodf[i / 28]) continue; + udre = getbitu(msg->msg, 22 + i * 4, 4); + sbssat->sat[i].fcorr.udre = udre + 1; + } + trace(5, "decode_sbstype6: iodf=%d %d %d %d\n", iodf[0], iodf[1], iodf[2], iodf[3]); + return 1; +} + + +/* decode type 7: fast correction degradation factor -------------------------*/ +int decode_sbstype7(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + int i; + + trace(4, "decode_sbstype7\n"); + + if (sbssat->iodp != static_cast(getbitu(msg->msg, 18, 2))) return 0; + + sbssat->tlat = getbitu(msg->msg, 14, 4); + + for (i = 0; i < sbssat->nsat && i < MAXSAT; i++) + { + sbssat->sat[i].fcorr.ai = getbitu(msg->msg, 22 + i * 4, 4); + } + return 1; +} + + +/* decode type 9: geo navigation message -------------------------------------*/ +int decode_sbstype9(const sbsmsg_t *msg, nav_t *nav) +{ + seph_t seph = {0, {0, 0}, {0, 0}, 0, 0, {}, {}, {}, 0.0, 0.0}; + int i, sat, t; + + trace(4, "decode_sbstype9:\n"); + + if (!(sat = satno(SYS_SBS, msg->prn))) + { + trace(2, "invalid prn in sbas type 9: prn=%3d\n", msg->prn); + return 0; + } + t = static_cast(getbitu(msg->msg, 22, 13)) * 16 - msg->tow % 86400; + if (t <= -43200) + t += 86400; + else if (t > 43200) + t -= 86400; + seph.sat = sat; + seph.t0 = gpst2time(msg->week, msg->tow + t); + seph.tof = gpst2time(msg->week, msg->tow); + seph.sva = getbitu(msg->msg, 35, 4); + seph.svh = seph.sva == 15 ? 1 : 0; /* unhealthy if ura==15 */ + + seph.pos[0] = getbits(msg->msg, 39, 30) * 0.08; + seph.pos[1] = getbits(msg->msg, 69, 30) * 0.08; + seph.pos[2] = getbits(msg->msg, 99, 25) * 0.4; + seph.vel[0] = getbits(msg->msg, 124, 17) * 0.000625; + seph.vel[1] = getbits(msg->msg, 141, 17) * 0.000625; + seph.vel[2] = getbits(msg->msg, 158, 18) * 0.004; + seph.acc[0] = getbits(msg->msg, 176, 10) * 0.0000125; + seph.acc[1] = getbits(msg->msg, 186, 10) * 0.0000125; + seph.acc[2] = getbits(msg->msg, 196, 10) * 0.0000625; + + seph.af0 = getbits(msg->msg, 206, 12) * TWO_N31; + seph.af1 = getbits(msg->msg, 218, 8) * TWO_N39 / 2.0; + + i = msg->prn - MINPRNSBS; + if (!nav->seph || fabs(timediff(nav->seph[i].t0, seph.t0)) < 1e-3) + { /* not change */ + return 0; + } + nav->seph[NSATSBS + i] = nav->seph[i]; /* previous */ + nav->seph[i] = seph; /* current */ + + trace(5, "decode_sbstype9: prn=%d\n", msg->prn); + return 1; +} + + +/* decode type 18: ionospheric grid point masks ------------------------------*/ +int decode_sbstype18(const sbsmsg_t *msg, sbsion_t *sbsion) +{ + const sbsigpband_t *p; + int i, j, n, m, band = getbitu(msg->msg, 18, 4); + + trace(4, "decode_sbstype18:\n"); + + if (0 <= band && band <= 8) + { + p = igpband1[band]; + m = 8; + } + else if (9 <= band && band <= 10) + { + p = igpband2[band - 9]; + m = 5; + } + else + return 0; + + sbsion[band].iodi = static_cast(getbitu(msg->msg, 22, 2)); + + for (i = 1, n = 0; i <= 201; i++) + { + if (!getbitu(msg->msg, 23 + i, 1)) continue; + for (j = 0; j < m; j++) + { + if (i < p[j].bits || p[j].bite < i) continue; + sbsion[band].igp[n].lat = band <= 8 ? p[j].y[i - p[j].bits] : p[j].x; + sbsion[band].igp[n++].lon = band <= 8 ? p[j].x : p[j].y[i - p[j].bits]; + break; + } + } + sbsion[band].nigp = n; + + trace(5, "decode_sbstype18: band=%d nigp=%d\n", band, n); + return 1; +} + + +/* decode half long term correction (vel code=0) -----------------------------*/ +int decode_longcorr0(const sbsmsg_t *msg, int p, sbssat_t *sbssat) +{ + int i, n = getbitu(msg->msg, p, 6); + + trace(4, "decode_longcorr0:\n"); + + if (n == 0 || n > MAXSAT) return 0; + + sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8); + + for (i = 0; i < 3; i++) + { + sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + 9 * i, 9) * 0.125; + sbssat->sat[n - 1].lcorr.dvel[i] = 0.0; + } + sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 41, 10) * TWO_N31; + sbssat->sat[n - 1].lcorr.daf1 = 0.0; + sbssat->sat[n - 1].lcorr.t0 = gpst2time(msg->week, msg->tow); + + trace(5, "decode_longcorr0:sat=%2d\n", sbssat->sat[n - 1].sat); + return 1; +} + + +/* decode half long term correction (vel code=1) -----------------------------*/ +int decode_longcorr1(const sbsmsg_t *msg, int p, sbssat_t *sbssat) +{ + int i, n = getbitu(msg->msg, p, 6), t; + + trace(4, "decode_longcorr1:\n"); + + if (n == 0 || n > MAXSAT) return 0; + + sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8); + + for (i = 0; i < 3; i++) + { + sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + i * 11, 11) * 0.125; + sbssat->sat[n - 1].lcorr.dvel[i] = getbits(msg->msg, p + 58 + i * 8, 8) * TWO_N11; + } + sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 47, 11) * TWO_N31; + sbssat->sat[n - 1].lcorr.daf1 = getbits(msg->msg, p + 82, 8) * TWO_N39; + t = static_cast(getbitu(msg->msg, p + 90, 13)) * 16 - msg->tow % 86400; + if (t <= -43200) + t += 86400; + else if (t > 43200) + t -= 86400; + sbssat->sat[n - 1].lcorr.t0 = gpst2time(msg->week, msg->tow + t); + + trace(5, "decode_longcorr1: sat=%2d\n", sbssat->sat[n - 1].sat); + return 1; +} + + +/* decode half long term correction ------------------------------------------*/ +int decode_longcorrh(const sbsmsg_t *msg, int p, sbssat_t *sbssat) +{ + trace(4, "decode_longcorrh:\n"); + + if (getbitu(msg->msg, p, 1) == 0) + { /* vel code=0 */ + if (sbssat->iodp == static_cast(getbitu(msg->msg, p + 103, 2))) + { + return decode_longcorr0(msg, p + 1, sbssat) && + decode_longcorr0(msg, p + 52, sbssat); + } + } + else if (sbssat->iodp == static_cast(getbitu(msg->msg, p + 104, 2))) + { + return decode_longcorr1(msg, p + 1, sbssat); + } + return 0; +} + + +/* decode type 24: mixed fast/long term correction ---------------------------*/ +int decode_sbstype24(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + int i, j, iodf, blk, udre; + + trace(4, "decode_sbstype24:\n"); + + if (sbssat->iodp != static_cast(getbitu(msg->msg, 110, 2))) return 0; /* check IODP */ + + blk = getbitu(msg->msg, 112, 2); + iodf = getbitu(msg->msg, 114, 2); + + for (i = 0; i < 6; i++) + { + if ((j = 13 * blk + i) >= sbssat->nsat) break; + udre = getbitu(msg->msg, 86 + 4 * i, 4); + + sbssat->sat[j].fcorr.t0 = gpst2time(msg->week, msg->tow); + sbssat->sat[j].fcorr.prc = getbits(msg->msg, 14 + i * 12, 12) * 0.125f; + sbssat->sat[j].fcorr.udre = udre + 1; + sbssat->sat[j].fcorr.iodf = iodf; + } + return decode_longcorrh(msg, 120, sbssat); +} + + +/* decode type 25: long term satellite error correction ----------------------*/ +int decode_sbstype25(const sbsmsg_t *msg, sbssat_t *sbssat) +{ + trace(4, "decode_sbstype25:\n"); + + return decode_longcorrh(msg, 14, sbssat) && decode_longcorrh(msg, 120, sbssat); +} + + +/* decode type 26: ionospheric deley corrections -----------------------------*/ +int decode_sbstype26(const sbsmsg_t *msg, sbsion_t *sbsion) +{ + int i, j, block, delay, give, band = getbitu(msg->msg, 14, 4); + + trace(4, "decode_sbstype26:\n"); + + if (band > MAXBAND || sbsion[band].iodi != static_cast(getbitu(msg->msg, 217, 2))) return 0; + + block = getbitu(msg->msg, 18, 4); + + for (i = 0; i < 15; i++) + { + if ((j = block * 15 + i) >= sbsion[band].nigp) continue; + give = getbitu(msg->msg, 22 + i * 13 + 9, 4); + + delay = getbitu(msg->msg, 22 + i * 13, 9); + sbsion[band].igp[j].t0 = gpst2time(msg->week, msg->tow); + sbsion[band].igp[j].delay = delay == 0x1FF ? 0.0f : delay * 0.125f; + sbsion[band].igp[j].give = give + 1; + + if (sbsion[band].igp[j].give >= 16) + { + sbsion[band].igp[j].give = 0; + } + } + trace(5, "decode_sbstype26: band=%d block=%d\n", band, block); + return 1; +} + + +/* update sbas corrections ----------------------------------------------------- + * update sbas correction parameters in navigation data with a sbas message + * args : sbsmg_t *msg I sbas message + * nav_t *nav IO navigation data + * return : message type (-1: error or not supported type) + * notes : nav->seph must point to seph[NSATSBS*2] (array of seph_t) + * seph[prn-MINPRNSBS+1] : sat prn current epehmeris + * seph[prn-MINPRNSBS+1+MAXPRNSBS]: sat prn previous epehmeris + *-----------------------------------------------------------------------------*/ +int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav) +{ + int type = getbitu(msg->msg, 8, 6), stat = -1; + + trace(3, "sbsupdatecorr: type=%d\n", type); + + if (msg->week == 0) return -1; + + switch (type) + { + case 0: + stat = decode_sbstype2(msg, &nav->sbssat); + break; + case 1: + stat = decode_sbstype1(msg, &nav->sbssat); + break; + case 2: + case 3: + case 4: + case 5: + stat = decode_sbstype2(msg, &nav->sbssat); + break; + case 6: + stat = decode_sbstype6(msg, &nav->sbssat); + break; + case 7: + stat = decode_sbstype7(msg, &nav->sbssat); + break; + case 9: + stat = decode_sbstype9(msg, nav); + break; + case 18: + stat = decode_sbstype18(msg, nav->sbsion); + break; + case 24: + stat = decode_sbstype24(msg, &nav->sbssat); + break; + case 25: + stat = decode_sbstype25(msg, &nav->sbssat); + break; + case 26: + stat = decode_sbstype26(msg, nav->sbsion); + break; + case 63: + break; /* null message */ + + /*default: trace(2, "unsupported sbas message: type=%d\n", type); break;*/ + } + return stat ? type : -1; +} + + +/* read sbas log file --------------------------------------------------------*/ +void readmsgs(const char *file, int sel, gtime_t ts, gtime_t te, + sbs_t *sbs) +{ + sbsmsg_t *sbs_msgs; + int i, week, prn, ch, msg; + unsigned int b; + double tow, ep[6] = {}; + char buff[256], *p; + gtime_t time; + FILE *fp; + + trace(3, "readmsgs: file=%s sel=%d\n", file, sel); + + if (!(fp = fopen(file, "re"))) + { + trace(2, "sbas message file open error: %s\n", file); + return; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (sscanf(buff, "%d %lf %d", &week, &tow, &prn) == 3 && (p = strstr(buff, ": "))) + { + p += 2; /* rtklib form */ + } + else if (sscanf(buff, "%d %lf %lf %lf %lf %lf %lf %d", + &prn, ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5, &msg) == 8) + { + /* ems (EGNOS Message Service) form */ + ep[0] += ep[0] < 70.0 ? 2000.0 : 1900.0; + tow = time2gpst(epoch2time(ep), &week); + p = buff + (msg >= 10 ? 25 : 24); + } + else if (!strncmp(buff, "#RAWWAASFRAMEA", 14)) + { /* NovAtel OEM4/V */ + if (!(p = getfield(buff, 6))) continue; + if (sscanf(p, "%d,%lf", &week, &tow) < 2) continue; + if (!(p = strchr(++p, ';'))) continue; + if (sscanf(++p, "%d,%d", &ch, &prn) < 2) continue; + if (!(p = getfield(p, 4))) continue; + } + else if (!strncmp(buff, "$FRMA", 5)) + { /* NovAtel OEM3 */ + if (!(p = getfield(buff, 2))) continue; + if (sscanf(p, "%d,%lf,%d", &week, &tow, &prn) < 3) continue; + if (!(p = getfield(p, 6))) continue; + if (week < WEEKOFFSET) week += WEEKOFFSET; + } + else + continue; + + if (sel != 0 && sel != prn) continue; + + time = gpst2time(week, tow); + + if (!screent(time, ts, te, 0.0)) continue; + + if (sbs->n >= sbs->nmax) + { + sbs->nmax = sbs->nmax == 0 ? 1024 : sbs->nmax * 2; + if (!(sbs_msgs = static_cast(realloc(sbs->msgs, sbs->nmax * sizeof(sbsmsg_t))))) + { + trace(1, "readsbsmsg malloc error: nmax=%d\n", sbs->nmax); + free(sbs->msgs); + sbs->msgs = nullptr; + sbs->n = sbs->nmax = 0; + fclose(fp); + return; + } + sbs->msgs = sbs_msgs; + } + sbs->msgs[sbs->n].week = week; + sbs->msgs[sbs->n].tow = static_cast(tow + 0.5); + sbs->msgs[sbs->n].prn = prn; + for (i = 0; i < 29; i++) sbs->msgs[sbs->n].msg[i] = 0; + for (i = 0; *(p - 1) && *p && i < 29; p += 2, i++) + { + if (sscanf(p, "%2X", &b) == 1) sbs->msgs[sbs->n].msg[i] = static_cast(b); + } + sbs->msgs[sbs->n++].msg[28] &= 0xC0; + } + fclose(fp); +} + + +/* compare sbas messages -----------------------------------------------------*/ +int cmpmsgs(const void *p1, const void *p2) +{ + auto *q1 = (sbsmsg_t *)p1, *q2 = (sbsmsg_t *)p2; + return q1->week != q2->week ? q1->week - q2->week : (q1->tow < q2->tow ? -1 : (q1->tow > q2->tow ? 1 : q1->prn - q2->prn)); +} + + +/* read sbas message file ------------------------------------------------------ + * read sbas message file + * args : char *file I sbas message file (wind-card * is expanded) + * int sel I sbas satellite prn number selection (0:all) + * (gtime_t ts I start time) + * (gtime_t te I end time ) + * sbs_t *sbs IO sbas messages + * return : number of sbas messages + * notes : sbas message are appended and sorted. before calling the function, + * sbs->n, sbs->nmax and sbs->msgs must be set properly. (initially + * sbs->n=sbs->nmax=0, sbs->msgs=NULL) + * only the following file extensions after wild card expanded are valid + * to read. others are skipped + * .sbs, .SBS, .ems, .EMS + *-----------------------------------------------------------------------------*/ +int sbsreadmsgt(const char *file, int sel, gtime_t ts, gtime_t te, + sbs_t *sbs) +{ + char *efiles[MAXEXFILE] = {}, *ext; + int i, n; + + trace(3, "sbsreadmsgt: file=%s sel=%d\n", file, sel); + + for (i = 0; i < MAXEXFILE; i++) + { + if (!(efiles[i] = static_cast(malloc(1024)))) + { + for (i--; i >= 0; i--) free(efiles[i]); + return 0; + } + } + /* expand wild card in file path */ + n = expath(file, efiles, MAXEXFILE); + + for (i = 0; i < n; i++) + { + if (!(ext = strrchr(efiles[i], '.'))) continue; + if (strcmp(ext, ".sbs") != 0 && strcmp(ext, ".SBS") != 0 && + strcmp(ext, ".ems") != 0 && strcmp(ext, ".EMS") != 0) continue; + + readmsgs(efiles[i], sel, ts, te, sbs); + } + for (i = 0; i < MAXEXFILE; i++) free(efiles[i]); + + /* sort messages */ + if (sbs->n > 0) + { + qsort(sbs->msgs, sbs->n, sizeof(sbsmsg_t), cmpmsgs); + } + return sbs->n; +} + + +int sbsreadmsg(const char *file, int sel, sbs_t *sbs) +{ + gtime_t ts = {0, 0}, te = {0, 0}; + + trace(3, "sbsreadmsg: file=%s sel=%d\n", file, sel); + + return sbsreadmsgt(file, sel, ts, te, sbs); +} + + +/* output sbas messages -------------------------------------------------------- + * output sbas message record to output file in rtklib sbas log format + * args : FILE *fp I output file pointer + * sbsmsg_t *sbsmsg I sbas messages + * return : none + *-----------------------------------------------------------------------------*/ +void sbsoutmsg(FILE *fp, sbsmsg_t *sbsmsg) +{ + int i, type = sbsmsg->msg[1] >> 2; + + trace(4, "sbsoutmsg:\n"); + + fprintf(fp, "%4d %6d %3d %2d : ", sbsmsg->week, sbsmsg->tow, sbsmsg->prn, type); + for (i = 0; i < 29; i++) fprintf(fp, "%02X", sbsmsg->msg[i]); + fprintf(fp, "\n"); +} + + +/* search igps ---------------------------------------------------------------*/ +void searchigp(gtime_t time __attribute__((unused)), const double *pos, const sbsion_t *ion, + const sbsigp_t **igp, double *x, double *y) +{ + int i, latp[2], lonp[4]; + double lat = pos[0] * R2D, lon = pos[1] * R2D; + const sbsigp_t *p; + + trace(4, "searchigp: pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D); + + if (lon >= 180.0) lon -= 360.0; + if (-55.0 <= lat && lat < 55.0) + { + latp[0] = static_cast(floor(lat / 5.0)) * 5; + latp[1] = latp[0] + 5; + lonp[0] = lonp[1] = static_cast(floor(lon / 5.0)) * 5; + lonp[2] = lonp[3] = lonp[0] + 5; + *x = (lon - lonp[0]) / 5.0; + *y = (lat - latp[0]) / 5.0; + } + else + { + latp[0] = static_cast(floor((lat - 5.0) / 10.0)) * 10 + 5; + latp[1] = latp[0] + 10; + lonp[0] = lonp[1] = static_cast(floor(lon / 10.0)) * 10; + lonp[2] = lonp[3] = lonp[0] + 10; + *x = (lon - lonp[0]) / 10.0; + *y = (lat - latp[0]) / 10.0; + if (75.0 <= lat && lat < 85.0) + { + lonp[1] = static_cast(floor(lon / 90.0)) * 90; + lonp[3] = lonp[1] + 90; + } + else if (-85.0 <= lat && lat < -75.0) + { + lonp[0] = static_cast(floor((lon - 50.0) / 90.0)) * 90 + 40; + lonp[2] = lonp[0] + 90; + } + else if (lat >= 85.0) + { + for (i = 0; i < 4; i++) lonp[i] = static_cast(floor(lon / 90.0)) * 90; + } + else if (lat < -85.0) + { + for (i = 0; i < 4; i++) lonp[i] = static_cast(floor((lon - 50.0) / 90.0)) * 90 + 40; + } + } + for (i = 0; i < 4; i++) + if (lonp[i] == 180) lonp[i] = -180; + for (i = 0; i <= MAXBAND; i++) + { + for (p = ion[i].igp; p < ion[i].igp + ion[i].nigp; p++) + { + if (p->t0.time == 0) continue; + if (p->lat == latp[0] && p->lon == lonp[0] && p->give > 0) + igp[0] = p; + else if (p->lat == latp[1] && p->lon == lonp[1] && p->give > 0) + igp[1] = p; + else if (p->lat == latp[0] && p->lon == lonp[2] && p->give > 0) + igp[2] = p; + else if (p->lat == latp[1] && p->lon == lonp[3] && p->give > 0) + igp[3] = p; + if (igp[0] && igp[1] && igp[2] && igp[3]) return; + } + } +} + + +/* sbas ionospheric delay correction ------------------------------------------- + * compute sbas ionosphric delay correction + * args : gtime_t time I time + * nav_t *nav I navigation data + * double *pos I receiver position {lat,lon,height} (rad/m) + * double *azel I satellite azimuth/elavation angle (rad) + * double *delay O slant ionospheric delay (L1) (m) + * double *var O variance of ionospheric delay (m^2) + * return : status (1:ok, 0:no correction) + * notes : before calling the function, sbas ionosphere correction parameters + * in navigation data (nav->sbsion) must be set by callig + * sbsupdatecorr() + *-----------------------------------------------------------------------------*/ +int sbsioncorr(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, double *delay, double *var) +{ + const double re = 6378.1363, hion = 350.0; + int i, err = 0; + double fp, posp[2], x = 0.0, y = 0.0, t, w[4] = {}; + const sbsigp_t *igp[4] = {}; /* {ws,wn,es,en} */ + + trace(4, "sbsioncorr: pos=%.3f %.3f azel=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D, + azel[0] * R2D, azel[1] * R2D); + + *delay = *var = 0.0; + if (pos[2] < -100.0 || azel[1] <= 0) return 1; + + /* ipp (ionospheric pierce point) position */ + fp = ionppp(pos, azel, re, hion, posp); + + /* search igps around ipp */ + searchigp(time, posp, nav->sbsion, igp, &x, &y); + + /* weight of igps */ + if (igp[0] && igp[1] && igp[2] && igp[3]) + { + w[0] = (1.0 - x) * (1.0 - y); + w[1] = (1.0 - x) * y; + w[2] = x * (1.0 - y); + w[3] = x * y; + } + else if (igp[0] && igp[1] && igp[2]) + { + w[1] = y; + w[2] = x; + if ((w[0] = 1.0 - w[1] - w[2]) < 0.0) err = 1; + } + else if (igp[0] && igp[2] && igp[3]) + { + w[0] = 1.0 - x; + w[3] = y; + if ((w[2] = 1.0 - w[0] - w[3]) < 0.0) err = 1; + } + else if (igp[0] && igp[1] && igp[3]) + { + w[0] = 1.0 - y; + w[3] = x; + if ((w[1] = 1.0 - w[0] - w[3]) < 0.0) err = 1; + } + else if (igp[1] && igp[2] && igp[3]) + { + w[1] = 1.0 - x; + w[2] = 1.0 - y; + if ((w[3] = 1.0 - w[1] - w[2]) < 0.0) err = 1; + } + else + err = 1; + + if (err) + { + trace(2, "no sbas iono correction: lat=%3.0f lon=%4.0f\n", posp[0] * R2D, + posp[1] * R2D); + return 0; + } + for (i = 0; i < 4; i++) + { + if (!igp[i]) continue; + t = timediff(time, igp[i]->t0); + *delay += w[i] * igp[i]->delay; + *var += w[i] * varicorr(igp[i]->give) * 9e-8 * fabs(t); + } + *delay *= fp; + *var *= fp * fp; + + trace(5, "sbsioncorr: dion=%7.2f sig=%7.2f\n", *delay, sqrt(*var)); + return 1; +} + + +/* get meterological parameters ----------------------------------------------*/ +void getmet(double lat, double *met) +{ + static const double metprm[][10] = {/* lat=15,30,45,60,75 */ + {1013.25, 299.65, 26.31, 6.30E-3, 2.77, 0.00, 0.00, 0.00, 0.00E-3, 0.00}, + {1017.25, 294.15, 21.79, 6.05E-3, 3.15, -3.75, 7.00, 8.85, 0.25E-3, 0.33}, + {1015.75, 283.15, 11.66, 5.58E-3, 2.57, -2.25, 11.00, 7.24, 0.32E-3, 0.46}, + {1011.75, 272.15, 6.78, 5.39E-3, 1.81, -1.75, 15.00, 5.36, 0.81E-3, 0.74}, + {1013.00, 263.65, 4.11, 4.53E-3, 1.55, -0.50, 14.50, 3.39, 0.62E-3, 0.30}}; + int i, j; + double a; + lat = fabs(lat); + if (lat <= 15.0) + for (i = 0; i < 10; i++) met[i] = metprm[0][i]; + else if (lat >= 75.0) + for (i = 0; i < 10; i++) met[i] = metprm[4][i]; + else + { + j = static_cast(lat / 15.0); + a = (lat - j * 15.0) / 15.0; + for (i = 0; i < 10; i++) met[i] = (1.0 - a) * metprm[j - 1][i] + a * metprm[j][i]; + } +} + + +/* tropospheric delay correction ----------------------------------------------- + * compute sbas tropospheric delay correction (mops model) + * args : gtime_t time I time + * double *pos I receiver position {lat,lon,height} (rad/m) + * double *azel I satellite azimuth/elavation (rad) + * double *var O variance of troposphric error (m^2) + * return : slant tropospheric delay (m) + *-----------------------------------------------------------------------------*/ +double sbstropcorr(gtime_t time, const double *pos, const double *azel, + double *var) +{ + const double k1 = 77.604, k2 = 382000.0, rd = 287.054, gm = 9.784, g = 9.80665; + static double pos_[3] = {}, zh = 0.0, zw = 0.0; + int i; + double c, met[10], sinel = sin(azel[1]), h = pos[2], m; + + trace(4, "sbstropcorr: pos=%.3f %.3f azel=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D, + azel[0] * R2D, azel[1] * R2D); + + if (pos[2] < -100.0 || 10000.0 < pos[2] || azel[1] <= 0) + { + *var = 0.0; + return 0.0; + } + if (zh == 0.0 || fabs(pos[0] - pos_[0]) > 1e-7 || fabs(pos[1] - pos_[1]) > 1e-7 || + fabs(pos[2] - pos_[2]) > 1.0) + { + getmet(pos[0] * R2D, met); + c = cos(2.0 * PI * (time2doy(time) - (pos[0] >= 0.0 ? 28.0 : 211.0)) / 365.25); + for (i = 0; i < 5; i++) met[i] -= met[i + 5] * c; + zh = 1e-6 * k1 * rd * met[0] / gm; + zw = 1e-6 * k2 * rd / (gm * (met[4] + 1.0) - met[3] * rd) * met[2] / met[1]; + zh *= pow(1.0 - met[3] * h / met[1], g / (rd * met[3])); + zw *= pow(1.0 - met[3] * h / met[1], (met[4] + 1.0) * g / (rd * met[3]) - 1.0); + for (i = 0; i < 3; i++) pos_[i] = pos[i]; + } + m = 1.001 / sqrt(0.002001 + sinel * sinel); + *var = 0.12 * 0.12 * m * m; + return (zh + zw) * m; +} + + +/* long term correction ------------------------------------------------------*/ +int sbslongcorr(gtime_t time, int sat, const sbssat_t *sbssat, + double *drs, double *ddts) +{ + const sbssatp_t *p; + double t; + int i; + + trace(3, "sbslongcorr: sat=%2d\n", sat); + + for (p = sbssat->sat; p < sbssat->sat + sbssat->nsat; p++) + { + if (p->sat != sat || p->lcorr.t0.time == 0) continue; + t = timediff(time, p->lcorr.t0); + if (fabs(t) > MAXSBSAGEL) + { + trace(2, "sbas long-term correction expired: %s sat=%2d t=%5.0f\n", + time_str(time, 0), sat, t); + return 0; + } + for (i = 0; i < 3; i++) drs[i] = p->lcorr.dpos[i] + p->lcorr.dvel[i] * t; + *ddts = p->lcorr.daf0 + p->lcorr.daf1 * t; + + trace(5, "sbslongcorr: sat=%2d drs=%7.2f%7.2f%7.2f ddts=%7.2f\n", + sat, drs[0], drs[1], drs[2], *ddts * SPEED_OF_LIGHT); + + return 1; + } + /* if sbas satellite without correction, no correction applied */ + if (satsys(sat, nullptr) == SYS_SBS) return 1; + + trace(2, "no sbas long-term correction: %s sat=%2d\n", time_str(time, 0), sat); + return 0; +} + + +/* fast correction -----------------------------------------------------------*/ +int sbsfastcorr(gtime_t time, int sat, const sbssat_t *sbssat, + double *prc, double *var) +{ + const sbssatp_t *p; + double t; + + trace(3, "sbsfastcorr: sat=%2d\n", sat); + + for (p = sbssat->sat; p < sbssat->sat + sbssat->nsat; p++) + { + if (p->sat != sat) continue; + if (p->fcorr.t0.time == 0) break; + t = timediff(time, p->fcorr.t0) + sbssat->tlat; + + /* expire age of correction or UDRE==14 (not monitored) */ + if (fabs(t) > MAXSBSAGEF || p->fcorr.udre >= 15) continue; + *prc = p->fcorr.prc; +#ifdef RRCENA + if (p->fcorr.ai > 0 && fabs(t) <= 8.0 * p->fcorr.dt) + { + *prc += p->fcorr.rrc * t; + } +#endif + *var = varfcorr(p->fcorr.udre) + degfcorr(p->fcorr.ai) * t * t / 2.0; + + trace(5, "sbsfastcorr: sat=%3d prc=%7.2f sig=%7.2f t=%5.0f\n", sat, + *prc, sqrt(*var), t); + return 1; + } + trace(2, "no sbas fast correction: %s sat=%2d\n", time_str(time, 0), sat); + return 0; +} + + +/* sbas satellite ephemeris and clock correction ------------------------------- + * correct satellite position and clock bias with sbas satellite corrections + * args : gtime_t time I reception time + * int sat I satellite + * nav_t *nav I navigation data + * double *rs IO sat position and corrected {x,y,z} (ecef) (m) + * double *dts IO sat clock bias and corrected (s) + * double *var O sat position and clock variance (m^2) + * return : status (1:ok,0:no correction) + * notes : before calling the function, sbas satellite correction parameters + * in navigation data (nav->sbssat) must be set by callig + * sbsupdatecorr(). + * satellite clock correction include long-term correction and fast + * correction. + * sbas clock correction is usually based on L1C/A code. TGD or DCB has + * to be considered for other codes + *-----------------------------------------------------------------------------*/ +int sbssatcorr(gtime_t time, int sat, const nav_t *nav, double *rs, + double *dts, double *var) +{ + double drs[3] = {}, dclk = 0.0, prc = 0.0; + int i; + + trace(3, "sbssatcorr : sat=%2d\n", sat); + + /* sbas long term corrections */ + if (!sbslongcorr(time, sat, &nav->sbssat, drs, &dclk)) + { + return 0; + } + /* sbas fast corrections */ + if (!sbsfastcorr(time, sat, &nav->sbssat, &prc, var)) + { + return 0; + } + for (i = 0; i < 3; i++) rs[i] += drs[i]; + + dts[0] += dclk + prc / SPEED_OF_LIGHT; + + trace(5, "sbssatcorr: sat=%2d drs=%6.3f %6.3f %6.3f dclk=%.3f %.3f var=%.3f\n", + sat, drs[0], drs[1], drs[2], dclk, prc / SPEED_OF_LIGHT, *var); + + return 1; +} + + +/* decode sbas message --------------------------------------------------------- + * decode sbas message frame words and check crc + * args : gtime_t time I reception time + * int prn I sbas satellite prn number + * unsigned int *word I message frame words (24bit x 10) + * sbsmsg_t *sbsmsg O sbas message + * return : status (1:ok,0:crc error) + *-----------------------------------------------------------------------------*/ +int sbsdecodemsg(gtime_t time, int prn, const unsigned int *words, + sbsmsg_t *sbsmsg) +{ + int i, j; + unsigned char f[29]; + double tow; + + trace(5, "sbsdecodemsg: prn=%d\n", prn); + + if (time.time == 0) return 0; + tow = time2gpst(time, &sbsmsg->week); + sbsmsg->tow = static_cast(tow + DTTOL); + sbsmsg->prn = prn; + for (i = 0; i < 7; i++) + for (j = 0; j < 4; j++) + { + sbsmsg->msg[i * 4 + j] = static_cast(words[i] >> ((3 - j) * 8)); + } + sbsmsg->msg[28] = static_cast(words[7] >> 18) & 0xC0; + for (i = 28; i > 0; i--) f[i] = (sbsmsg->msg[i] >> 6) + (sbsmsg->msg[i - 1] << 2); + f[0] = sbsmsg->msg[0] >> 6; + + return rtk_crc24q(f, 29) == (words[7] & 0xFFFFFF); /* check crc */ +} diff --git a/src/algorithms/libs/rtklib/rtklib_sbas.h b/src/algorithms/libs/rtklib/rtklib_sbas.h new file mode 100644 index 000000000..1ff7bf6ad --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_sbas.h @@ -0,0 +1,163 @@ +/*! + * \file rtklib_sbas.h + * \brief sbas functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * References : + * [1] RTCA/DO-229C, Minimum operational performanc standards for global + * positioning system/wide area augmentation system airborne equipment, + * RTCA inc, November 28, 2001 + * [2] IS-QZSS v.1.1, Quasi-Zenith Satellite System Navigation Service + * Interface Specification for QZSS, Japan Aerospace Exploration Agency, + * July 31, 2009 + * + *----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_SBAS_H_ +#define GNSS_SDR_RTKLIB_SBAS_H_ + +#include "rtklib.h" + +/* constants -----------------------------------------------------------------*/ + +const int WEEKOFFSET = 1024; /* gps week offset for NovAtel OEM-3 */ + +/* sbas igp definition -------------------------------------------------------*/ +static const short + x1[] = {-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, + 25, 30, 35, 40, 45, 50, 55, 65, 75, 85}, + x2[] = {-55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, + 35, 40, 45, 50, 55}, + x3[] = {-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, + 25, 30, 35, 40, 45, 50, 55, 65, 75}, + x4[] = {-85, -75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, + 20, 25, 30, 35, 40, 45, 50, 55, 65, 75}, + x5[] = {-180, -175, -170, -165, -160, -155, -150, -145, -140, -135, -130, -125, -120, -115, + -110, -105, -100, -95, -90, -85, -80, -75, -70, -65, -60, -55, -50, -45, + -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, + 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, + 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, + 170, 175}, + x6[] = {-180, -170, -160, -150, -140, -130, -120, -110, -100, -90, -80, -70, -60, -50, + -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, + 100, 110, 120, 130, 140, 150, 160, 170}, + x7[] = {-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150}, + x8[] = {-170, -140, -110, -80, -50, -20, 10, 40, 70, 100, 130, 160}; + +const sbsigpband_t igpband1[9][8] = {/* band 0-8 */ + {{-180, x1, 1, 28}, {-175, x2, 29, 51}, {-170, x3, 52, 78}, {-165, x2, 79, 101}, + {-160, x3, 102, 128}, {-155, x2, 129, 151}, {-150, x3, 152, 178}, {-145, x2, 179, 201}}, + {{-140, x4, 1, 28}, {-135, x2, 29, 51}, {-130, x3, 52, 78}, {-125, x2, 79, 101}, + {-120, x3, 102, 128}, {-115, x2, 129, 151}, {-110, x3, 152, 178}, {-105, x2, 179, 201}}, + {{-100, x3, 1, 27}, {-95, x2, 28, 50}, {-90, x1, 51, 78}, {-85, x2, 79, 101}, + {-80, x3, 102, 128}, {-75, x2, 129, 151}, {-70, x3, 152, 178}, {-65, x2, 179, 201}}, + {{-60, x3, 1, 27}, {-55, x2, 28, 50}, {-50, x4, 51, 78}, {-45, x2, 79, 101}, + {-40, x3, 102, 128}, {-35, x2, 129, 151}, {-30, x3, 152, 178}, {-25, x2, 179, 201}}, + {{-20, x3, 1, 27}, {-15, x2, 28, 50}, {-10, x3, 51, 77}, {-5, x2, 78, 100}, + {0, x1, 101, 128}, {5, x2, 129, 151}, {10, x3, 152, 178}, {15, x2, 179, 201}}, + {{20, x3, 1, 27}, {25, x2, 28, 50}, {30, x3, 51, 77}, {35, x2, 78, 100}, + {40, x4, 101, 128}, {45, x2, 129, 151}, {50, x3, 152, 178}, {55, x2, 179, 201}}, + {{60, x3, 1, 27}, {65, x2, 28, 50}, {70, x3, 51, 77}, {75, x2, 78, 100}, + {80, x3, 101, 127}, {85, x2, 128, 150}, {90, x1, 151, 178}, {95, x2, 179, 201}}, + {{100, x3, 1, 27}, {105, x2, 28, 50}, {110, x3, 51, 77}, {115, x2, 78, 100}, + {120, x3, 101, 127}, {125, x2, 128, 150}, {130, x4, 151, 178}, {135, x2, 179, 201}}, + {{140, x3, 1, 27}, {145, x2, 28, 50}, {150, x3, 51, 77}, {155, x2, 78, 100}, + {160, x3, 101, 127}, {165, x2, 128, 150}, {170, x3, 151, 177}, {175, x2, 178, 200}}}; +const sbsigpband_t igpband2[2][5] = {/* band 9-10 */ + {{60, x5, 1, 72}, {65, x6, 73, 108}, {70, x6, 109, 144}, {75, x6, 145, 180}, + {85, x7, 181, 192}}, + {{-60, x5, 1, 72}, {-65, x6, 73, 108}, {-70, x6, 109, 144}, {-75, x6, 145, 180}, + {-85, x8, 181, 192}}}; + + +char *getfield(char *p, int pos); +double varfcorr(int udre); +double varicorr(int give); +double degfcorr(int ai); + +int decode_sbstype1(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype2(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype6(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype7(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype9(const sbsmsg_t *msg, nav_t *nav); +int decode_sbstype18(const sbsmsg_t *msg, sbsion_t *sbsion); +int decode_longcorr0(const sbsmsg_t *msg, int p, sbssat_t *sbssat); +int decode_longcorr1(const sbsmsg_t *msg, int p, sbssat_t *sbssat); +int decode_longcorrh(const sbsmsg_t *msg, int p, sbssat_t *sbssat); +int decode_sbstype24(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype25(const sbsmsg_t *msg, sbssat_t *sbssat); +int decode_sbstype26(const sbsmsg_t *msg, sbsion_t *sbsion); + +int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav); +void readmsgs(const char *file, int sel, gtime_t ts, gtime_t te, sbs_t *sbs); +int cmpmsgs(const void *p1, const void *p2); +int sbsreadmsgt(const char *file, int sel, gtime_t ts, gtime_t te, + sbs_t *sbs); +int sbsreadmsg(const char *file, int sel, sbs_t *sbs); +void sbsoutmsg(FILE *fp, sbsmsg_t *sbsmsg); +void searchigp(gtime_t time, const double *pos, const sbsion_t *ion, + const sbsigp_t **igp, double *x, double *y); +int sbsioncorr(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, double *delay, double *var); + +void getmet(double lat, double *met); +double sbstropcorr(gtime_t time, const double *pos, const double *azel, + double *var); +int sbslongcorr(gtime_t time, int sat, const sbssat_t *sbssat, + double *drs, double *ddts); +int sbsfastcorr(gtime_t time, int sat, const sbssat_t *sbssat, + double *prc, double *var); + +int sbssatcorr(gtime_t time, int sat, const nav_t *nav, double *rs, + double *dts, double *var); +int sbsdecodemsg(gtime_t time, int prn, const unsigned int *words, + sbsmsg_t *sbsmsg); + + +#endif /* GNSS_SDR_RTKLIB_SBAS_H_ */ diff --git a/src/algorithms/libs/rtklib/rtklib_solution.cc b/src/algorithms/libs/rtklib/rtklib_solution.cc new file mode 100644 index 000000000..e2c19cecd --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_solution.cc @@ -0,0 +1,1914 @@ +/*! + * \file rtklib_solution.cc + * \brief solution functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_solution.h" +#include "rtklib_rtkcmn.h" +#include "rtklib_rtksvr.h" +#include + + +/* constants and macros ------------------------------------------------------*/ + +#define SQR_SOL(x) ((x) < 0.0 ? -(x) * (x) : (x) * (x)) +#define SQRT_SOL(x) ((x) < 0.0 ? 0.0 : sqrt(x)) + +const int MAXFIELD = 64; /* max number of fields in a record */ + +const double KNOT2M = 0.514444444; /* m/knot */ + +static const int solq_nmea[] = {/* nmea quality flags to rtklib sol quality */ + /* nmea 0183 v.2.3 quality flags: */ + /* 0=invalid, 1=gps fix (sps), 2=dgps fix, 3=pps fix, 4=rtk, 5=float rtk */ + /* 6=estimated (dead reckoning), 7=manual input, 8=simulation */ + SOLQ_NONE, SOLQ_SINGLE, SOLQ_DGPS, SOLQ_PPP, SOLQ_FIX, + SOLQ_FLOAT, SOLQ_DR, SOLQ_NONE, SOLQ_NONE, SOLQ_NONE}; + + +/* solution option to field separator ----------------------------------------*/ +const char *opt2sep(const solopt_t *opt) +{ + if (!*opt->sep) + return " "; + if (!strcmp(opt->sep, "\\t")) + return "\t"; + return opt->sep; +} + + +/* separate fields -----------------------------------------------------------*/ +int tonum(char *buff, const char *sep, double *v) +{ + int n, len = static_cast(strlen(sep)); + char *p, *q; + + for (p = buff, n = 0; n < MAXFIELD; p = q + len) + { + if ((q = strstr(p, sep))) *q = '\0'; + if (*p) v[n++] = atof(p); + if (!q) break; + } + return n; +} + + +/* sqrt of covariance --------------------------------------------------------*/ +double sqvar(double covar) +{ + return covar < 0.0 ? -sqrt(-covar) : sqrt(covar); +} + + +/* convert ddmm.mm in nmea format to deg -------------------------------------*/ +double dmm2deg(double dmm) +{ + return floor(dmm / 100.0) + fmod(dmm, 100.0) / 60.0; +} + + +/* convert time in nmea format to time ---------------------------------------*/ +void septime(double t, double *t1, double *t2, double *t3) +{ + *t1 = floor(t / 10000.0); + t -= *t1 * 10000.0; + *t2 = floor(t / 100.0); + *t3 = t - *t2 * 100.0; +} + + +/* solution to covariance ----------------------------------------------------*/ +void soltocov(const sol_t *sol, double *P) +{ + P[0] = sol->qr[0]; /* xx or ee */ + P[4] = sol->qr[1]; /* yy or nn */ + P[8] = sol->qr[2]; /* zz or uu */ + P[1] = P[3] = sol->qr[3]; /* xy or en */ + P[5] = P[7] = sol->qr[4]; /* yz or nu */ + P[2] = P[6] = sol->qr[5]; /* zx or ue */ +} + + +/* covariance to solution ----------------------------------------------------*/ +void covtosol(const double *P, sol_t *sol) +{ + sol->qr[0] = static_cast(P[0]); /* xx or ee */ + sol->qr[1] = static_cast(P[4]); /* yy or nn */ + sol->qr[2] = static_cast(P[8]); /* zz or uu */ + sol->qr[3] = static_cast(P[1]); /* xy or en */ + sol->qr[4] = static_cast(P[5]); /* yz or nu */ + sol->qr[5] = static_cast(P[2]); /* zx or ue */ +} + + +/* decode nmea gprmc: recommended minimum data for gps -----------------------*/ +int decode_nmearmc(char **val, int n, sol_t *sol) +{ + double tod = 0.0, lat = 0.0, lon = 0.0, vel = 0.0, dir = 0.0, date = 0.0, ang = 0.0, ep[6]; + double pos[3] = {0}; + char act = ' ', ns = 'N', ew = 'E', mew = 'E', mode = 'A'; + int i; + + trace(4, "decode_nmearmc: n=%d\n", n); + + for (i = 0; i < n; i++) + { + switch (i) + { + case 0: + tod = atof(val[i]); + break; /* time in utc (hhmmss) */ + case 1: + act = *val[i]; + break; /* A=active,V=void */ + case 2: + lat = atof(val[i]); + break; /* latitude (ddmm.mmm) */ + case 3: + ns = *val[i]; + break; /* N=north,S=south */ + case 4: + lon = atof(val[i]); + break; /* longitude (dddmm.mmm) */ + case 5: + ew = *val[i]; + break; /* E=east,W=west */ + case 6: + vel = atof(val[i]); + break; /* speed (knots) */ + case 7: + dir = atof(val[i]); + break; /* track angle (deg) */ + case 8: + date = atof(val[i]); + break; /* date (ddmmyy) */ + case 9: + ang = atof(val[i]); + break; /* magnetic variation */ + case 10: + mew = *val[i]; + break; /* E=east,W=west */ + case 11: + mode = *val[i]; + break; /* mode indicator (>nmea 2) */ + /* A=autonomous,D=differential */ + /* E=estimated,N=not valid,S=simulator */ + } + } + if ((act != 'A' && act != 'V') || (ns != 'N' && ns != 'S') || (ew != 'E' && ew != 'W')) + { + trace(2, "invalid nmea gprmc format\n"); + return 0; + } + pos[0] = (ns == 'S' ? -1.0 : 1.0) * dmm2deg(lat) * D2R; + pos[1] = (ew == 'W' ? -1.0 : 1.0) * dmm2deg(lon) * D2R; + septime(date, ep + 2, ep + 1, ep); + septime(tod, ep + 3, ep + 4, ep + 5); + ep[0] += ep[0] < 80.0 ? 2000.0 : 1900.0; + sol->time = utc2gpst(epoch2time(ep)); + pos2ecef(pos, sol->rr); + sol->stat = mode == 'D' ? SOLQ_DGPS : SOLQ_SINGLE; + sol->ns = 0; + + sol->type = 0; /* position type = xyz */ + + trace(5, "decode_nmearmc: %s rr=%.3f %.3f %.3f stat=%d ns=%d vel=%.2f dir=%.0f ang=%.0f mew=%c mode=%c\n", + time_str(sol->time, 0), sol->rr[0], sol->rr[1], sol->rr[2], sol->stat, sol->ns, + vel, dir, ang, mew, mode); + + return 1; +} + + +/* decode nmea gpgga: fix information ----------------------------------------*/ +int decode_nmeagga(char **val, int n, sol_t *sol) +{ + gtime_t time; + double tod = 0.0, lat = 0.0, lon = 0.0, hdop = 0.0, alt = 0.0, msl = 0.0, ep[6], tt; + double pos[3] = {0}; + char ns = 'N', ew = 'E', ua = ' ', um = ' '; + int i, solq = 0, nrcv = 0; + + trace(4, "decode_nmeagga: n=%d\n", n); + + for (i = 0; i < n; i++) + { + switch (i) + { + case 0: + tod = atof(val[i]); + break; /* time in utc (hhmmss) */ + case 1: + lat = atof(val[i]); + break; /* latitude (ddmm.mmm) */ + case 2: + ns = *val[i]; + break; /* N=north,S=south */ + case 3: + lon = atof(val[i]); + break; /* longitude (dddmm.mmm) */ + case 4: + ew = *val[i]; + break; /* E=east,W=west */ + case 5: + solq = atoi(val[i]); + break; /* fix quality */ + case 6: + nrcv = atoi(val[i]); + break; /* # of satellite tracked */ + case 7: + hdop = atof(val[i]); + break; /* hdop */ + case 8: + alt = atof(val[i]); + break; /* altitude in msl */ + case 9: + ua = *val[i]; + break; /* unit (M) */ + case 10: + msl = atof(val[i]); + break; /* height of geoid */ + case 11: + um = *val[i]; + break; /* unit (M) */ + } + } + if ((ns != 'N' && ns != 'S') || (ew != 'E' && ew != 'W')) + { + trace(2, "invalid nmea gpgga format\n"); + return 0; + } + if (sol->time.time == 0.0) + { + trace(2, "no date info for nmea gpgga\n"); + return 0; + } + pos[0] = (ns == 'N' ? 1.0 : -1.0) * dmm2deg(lat) * D2R; + pos[1] = (ew == 'E' ? 1.0 : -1.0) * dmm2deg(lon) * D2R; + pos[2] = alt + msl; + + time2epoch(sol->time, ep); + septime(tod, ep + 3, ep + 4, ep + 5); + time = utc2gpst(epoch2time(ep)); + tt = timediff(time, sol->time); + if (tt < -43200.0) + sol->time = timeadd(time, 86400.0); + else if (tt > 43200.0) + sol->time = timeadd(time, -86400.0); + else + sol->time = time; + pos2ecef(pos, sol->rr); + sol->stat = 0 <= solq && solq <= 8 ? solq_nmea[solq] : SOLQ_NONE; + sol->ns = nrcv; + + sol->type = 0; /* position type = xyz */ + + trace(5, "decode_nmeagga: %s rr=%.3f %.3f %.3f stat=%d ns=%d hdop=%.1f ua=%c um=%c\n", + time_str(sol->time, 0), sol->rr[0], sol->rr[1], sol->rr[2], sol->stat, sol->ns, + hdop, ua, um); + + return 1; +} + + +/* decode nmea ---------------------------------------------------------------*/ +int decode_nmea(char *buff, sol_t *sol) +{ + char *p, *q, *val[MAXFIELD] = {nullptr}; + int n = 0; + + trace(4, "decode_nmea: buff=%s\n", buff); + + /* parse fields */ + for (p = buff; *p && n < MAXFIELD; p = q + 1) + { + if ((q = strchr(p, ',')) || (q = strchr(p, '*'))) + { + val[n++] = p; + *q = '\0'; + } + else + break; + } + /* decode nmea sentence */ + if (!strcmp(val[0], "$GPRMC")) + { + return decode_nmearmc(val + 1, n - 1, sol); + } + if (!strcmp(val[0], "$GPGGA")) + { + return decode_nmeagga(val + 1, n - 1, sol); + } + return 0; +} + + +/* decode solution time ------------------------------------------------------*/ +char *decode_soltime(char *buff, const solopt_t *opt, gtime_t *time) +{ + double v[MAXFIELD]; + char *p, *q, s[64] = " "; + int n, len; + + trace(4, "decode_soltime:\n"); + + if (!strcmp(opt->sep, "\\t")) + strcpy(s, "\t"); + else if (*opt->sep) + strcpy(s, opt->sep); + len = static_cast(strlen(s)); + + /* yyyy/mm/dd hh:mm:ss or yyyy mm dd hh:mm:ss */ + if (sscanf(buff, "%lf/%lf/%lf %lf:%lf:%lf", v, v + 1, v + 2, v + 3, v + 4, v + 5) >= 6) + { + if (v[0] < 100.0) + { + v[0] += v[0] < 80.0 ? 2000.0 : 1900.0; + } + *time = epoch2time(v); + if (opt->times == TIMES_UTC) + { + *time = utc2gpst(*time); + } + else if (opt->times == TIMES_JST) + { + *time = utc2gpst(timeadd(*time, -9 * 3600.0)); + } + if (!(p = strchr(buff, ':')) || !(p = strchr(p + 1, ':'))) return nullptr; + for (p++; isdigit(static_cast(*p)) || *p == '.';) p++; + return p + len; + } + if (opt->posf == SOLF_GSIF) + { + if (sscanf(buff, "%lf %lf %lf %lf:%lf:%lf", v, v + 1, v + 2, v + 3, v + 4, v + 5) < 6) + { + return nullptr; + } + *time = timeadd(epoch2time(v), -12.0 * 3600.0); + if (!(p = strchr(buff, ':')) || !(p = strchr(p + 1, ':'))) return nullptr; + for (p++; isdigit(static_cast(*p)) || *p == '.';) p++; + return p + len; + } + /* wwww ssss */ + for (p = buff, n = 0; n < 2; p = q + len) + { + if ((q = strstr(p, s))) *q = '\0'; + if (*p) v[n++] = atof(p); + if (!q) break; + } + if (n >= 2 && 0.0 <= v[0] && v[0] <= 3000.0 && 0.0 <= v[1] && v[1] < 604800.0) + { + *time = gpst2time(static_cast(v[0]), v[1]); + return p; + } + return nullptr; +} + + +/* decode x/y/z-ecef ---------------------------------------------------------*/ +int decode_solxyz(char *buff, const solopt_t *opt, sol_t *sol) +{ + double val[MAXFIELD], P[9] = {0}; + int i = 0, j, n; + const char *sep = opt2sep(opt); + + trace(4, "decode_solxyz:\n"); + + if ((n = tonum(buff, sep, val)) < 3) return 0; + + for (j = 0; j < 3; j++) + { + sol->rr[j] = val[i++]; /* xyz */ + } + if (i < n) sol->stat = static_cast(val[i++]); + if (i < n) sol->ns = static_cast(val[i++]); + if (i + 3 < n) + { + P[0] = val[i] * val[i]; + i++; /* sdx */ + P[4] = val[i] * val[i]; + i++; /* sdy */ + P[8] = val[i] * val[i]; + i++; /* sdz */ + if (i + 3 < n) + { + P[1] = P[3] = SQR_SOL(val[i]); + i++; /* sdxy */ + P[5] = P[7] = SQR_SOL(val[i]); + i++; /* sdyz */ + P[2] = P[6] = SQR_SOL(val[i]); + i++; /* sdzx */ + } + covtosol(P, sol); + } + if (i < n) sol->age = static_cast(val[i++]); + if (i < n) sol->ratio = static_cast(val[i]); + + sol->type = 0; /* position type = xyz */ + + if (MAXSOLQ < sol->stat) sol->stat = SOLQ_NONE; + return 1; +} + + +/* decode lat/lon/height -----------------------------------------------------*/ +int decode_solllh(char *buff, const solopt_t *opt, sol_t *sol) +{ + double val[MAXFIELD], pos[3], Q[9] = {0}, P[9]; + int i = 0, n; + const char *sep = opt2sep(opt); + + trace(4, "decode_solllh:\n"); + + n = tonum(buff, sep, val); + + if (!opt->degf) + { + if (n < 3) return 0; + pos[0] = val[i++] * D2R; /* lat/lon/hgt (ddd.ddd) */ + pos[1] = val[i++] * D2R; + pos[2] = val[i++]; + } + else + { + if (n < 7) return 0; + pos[0] = dms2deg(val) * D2R; /* lat/lon/hgt (ddd mm ss) */ + pos[1] = dms2deg(val + 3) * D2R; + pos[2] = val[6]; + i += 7; + } + pos2ecef(pos, sol->rr); + if (i < n) sol->stat = static_cast(val[i++]); + if (i < n) sol->ns = static_cast(val[i++]); + if (i + 3 < n) + { + Q[4] = val[i] * val[i]; + i++; /* sdn */ + Q[0] = val[i] * val[i]; + i++; /* sde */ + Q[8] = val[i] * val[i]; + i++; /* sdu */ + if (i + 3 < n) + { + Q[1] = Q[3] = SQR_SOL(val[i]); + i++; /* sdne */ + Q[2] = Q[6] = SQR_SOL(val[i]); + i++; /* sdeu */ + Q[5] = Q[7] = SQR_SOL(val[i]); + i++; /* sdun */ + } + covecef(pos, Q, P); + covtosol(P, sol); + } + if (i < n) sol->age = static_cast(val[i++]); + if (i < n) sol->ratio = static_cast(val[i]); + + sol->type = 0; /* position type = xyz */ + + if (MAXSOLQ < sol->stat) sol->stat = SOLQ_NONE; + return 1; +} + + +/* decode e/n/u-baseline -----------------------------------------------------*/ +int decode_solenu(char *buff, const solopt_t *opt, sol_t *sol) +{ + double val[MAXFIELD], Q[9] = {0}; + int i = 0, j, n; + const char *sep = opt2sep(opt); + + trace(4, "decode_solenu:\n"); + + if ((n = tonum(buff, sep, val)) < 3) return 0; + + for (j = 0; j < 3; j++) + { + sol->rr[j] = val[i++]; /* enu */ + } + if (i < n) sol->stat = static_cast(val[i++]); + if (i < n) sol->ns = static_cast(val[i++]); + if (i + 3 < n) + { + Q[0] = val[i] * val[i]; + i++; /* sde */ + Q[4] = val[i] * val[i]; + i++; /* sdn */ + Q[8] = val[i] * val[i]; + i++; /* sdu */ + if (i + 3 < n) + { + Q[1] = Q[3] = SQR_SOL(val[i]); + i++; /* sden */ + Q[5] = Q[7] = SQR_SOL(val[i]); + i++; /* sdnu */ + Q[2] = Q[6] = SQR_SOL(val[i]); + i++; /* sdue */ + } + covtosol(Q, sol); + } + if (i < n) sol->age = static_cast(val[i++]); + if (i < n) sol->ratio = static_cast(val[i]); + + sol->type = 1; /* position type = enu */ + + if (MAXSOLQ < sol->stat) sol->stat = SOLQ_NONE; + return 1; +} + + +/* decode gsi f solution -----------------------------------------------------*/ +int decode_solgsi(char *buff, const solopt_t *opt __attribute((unused)), sol_t *sol) +{ + double val[MAXFIELD]; + int i = 0, j; + + trace(4, "decode_solgsi:\n"); + + if (tonum(buff, " ", val) < 3) return 0; + + for (j = 0; j < 3; j++) + { + sol->rr[j] = val[i++]; /* xyz */ + } + sol->stat = SOLQ_FIX; + return 1; +} + + +/* decode solution position --------------------------------------------------*/ +int decode_solpos(char *buff, const solopt_t *opt, sol_t *sol) +{ + sol_t sol0 = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, '0', '0', '0', 0, 0, 0}; + char *p = buff; + + trace(4, "decode_solpos: buff=%s\n", buff); + + *sol = sol0; + + /* decode solution time */ + if (!(p = decode_soltime(p, opt, &sol->time))) + { + return 0; + } + /* decode solution position */ + switch (opt->posf) + { + case SOLF_XYZ: + return decode_solxyz(p, opt, sol); + case SOLF_LLH: + return decode_solllh(p, opt, sol); + case SOLF_ENU: + return decode_solenu(p, opt, sol); + case SOLF_GSIF: + return decode_solgsi(p, opt, sol); + } + return 0; +} + + +/* decode reference position -------------------------------------------------*/ +void decode_refpos(char *buff, const solopt_t *opt, double *rb) +{ + double val[MAXFIELD], pos[3]; + int i, n; + const char *sep = opt2sep(opt); + + trace(3, "decode_refpos: buff=%s\n", buff); + + if ((n = tonum(buff, sep, val)) < 3) return; + + if (opt->posf == SOLF_XYZ) + { /* xyz */ + for (i = 0; i < 3; i++) rb[i] = val[i]; + } + else if (opt->degf == 0) + { /* lat/lon/hgt (ddd.ddd) */ + pos[0] = val[0] * D2R; + pos[1] = val[1] * D2R; + pos[2] = val[2]; + pos2ecef(pos, rb); + } + else if (opt->degf == 1 && n >= 7) + { /* lat/lon/hgt (ddd mm ss) */ + pos[0] = dms2deg(val) * D2R; + pos[1] = dms2deg(val + 3) * D2R; + pos[2] = val[6]; + pos2ecef(pos, rb); + } +} + + +/* decode solution -----------------------------------------------------------*/ +int decode_sol(char *buff, const solopt_t *opt, sol_t *sol, double *rb) +{ + char *p; + + trace(4, "decode_sol: buff=%s\n", buff); + + if (!strncmp(buff, COMMENTH, 1)) + { /* reference position */ + if (!strstr(buff, "ref pos") && !strstr(buff, "slave pos")) return 0; + if (!(p = strchr(buff, ':'))) return 0; + decode_refpos(p + 1, opt, rb); + return 0; + } + if (!strncmp(buff, "$GP", 3)) + { /* decode nmea */ + if (!decode_nmea(buff, sol)) return 0; + + /* for time update only */ + if (opt->posf != SOLF_NMEA && !strncmp(buff, "$GPRMC", 6)) return 2; + } + else + { /* decode position record */ + if (!decode_solpos(buff, opt, sol)) return 0; + } + return 1; +} + + +/* decode solution options ---------------------------------------------------*/ +void decode_solopt(char *buff, solopt_t *opt) +{ + char *p; + + trace(4, "decode_solhead: buff=%s\n", buff); + + if (strncmp(buff, COMMENTH, 1) != 0 && strncmp(buff, "+", 1) != 0) return; + + if (strstr(buff, "GPST")) + opt->times = TIMES_GPST; + else if (strstr(buff, "UTC")) + opt->times = TIMES_UTC; + else if (strstr(buff, "JST")) + opt->times = TIMES_JST; + + if ((p = strstr(buff, "x-ecef(m)"))) + { + opt->posf = SOLF_XYZ; + opt->degf = 0; + strncpy(opt->sep, p + 9, 1); + opt->sep[1] = '\0'; + } + else if ((p = strstr(buff, "latitude(d'\")"))) + { + opt->posf = SOLF_LLH; + opt->degf = 1; + strncpy(opt->sep, p + 14, 1); + opt->sep[1] = '\0'; + } + else if ((p = strstr(buff, "latitude(deg)"))) + { + opt->posf = SOLF_LLH; + opt->degf = 0; + strncpy(opt->sep, p + 13, 1); + opt->sep[1] = '\0'; + } + else if ((p = strstr(buff, "e-baseline(m)"))) + { + opt->posf = SOLF_ENU; + opt->degf = 0; + strncpy(opt->sep, p + 13, 1); + opt->sep[1] = '\0'; + } + else if ((p = strstr(buff, "+SITE/INF"))) + { /* gsi f2/f3 solution */ + opt->times = TIMES_GPST; + opt->posf = SOLF_GSIF; + opt->degf = 0; + strcpy(opt->sep, " "); + } +} + + +/* read solution option ------------------------------------------------------*/ +void readsolopt(FILE *fp, solopt_t *opt) +{ + char buff[MAXSOLMSG + 1]; + int i; + + trace(3, "readsolopt:\n"); + + for (i = 0; fgets(buff, sizeof(buff), fp) && i < 100; i++) + { /* only 100 lines */ + /* decode solution options */ + decode_solopt(buff, opt); + } +} + + +/* input solution data from stream --------------------------------------------- + * input solution data from stream + * args : unsigned char data I stream data + * gtime_t ts I start time (ts.time == 0: from start) + * gtime_t te I end time (te.time == 0: to end) + * double tint I time interval (0: all) + * int qflag I quality flag (0: all) + * solbuf_t *solbuf IO solution buffer + * return : status (1:solution received,0:no solution,-1:disconnect received) + *-----------------------------------------------------------------------------*/ +int inputsol(unsigned char data, gtime_t ts, gtime_t te, double tint, + int qflag, const solopt_t *opt, solbuf_t *solbuf) +{ + sol_t sol = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, '0', '0', '0', 0, 0, 0}; + int stat; + + trace(4, "inputsol: data=0x%02x\n", data); + + sol.time = solbuf->time; + + if (data == '$' || (!isprint(data) && data != '\r' && data != '\n')) + { /* sync header */ + solbuf->nb = 0; + } + solbuf->buff[solbuf->nb++] = data; + if (data != '\n' && solbuf->nb < MAXSOLMSG) return 0; /* sync trailer */ + + solbuf->buff[solbuf->nb] = '\0'; + solbuf->nb = 0; + + /* check disconnect message */ + if (!strcmp(reinterpret_cast(solbuf->buff), MSG_DISCONN)) + { + trace(3, "disconnect received\n"); + return -1; + } + /* decode solution */ + if ((stat = decode_sol(reinterpret_cast(solbuf->buff), opt, &sol, solbuf->rb)) > 0) + { + solbuf->time = sol.time; /* update current time */ + } + if (stat != 1 || !screent(sol.time, ts, te, tint) || (qflag && sol.stat != qflag)) + { + return 0; + } + /* add solution to solution buffer */ + return addsol(solbuf, &sol); +} + + +/* read solution data --------------------------------------------------------*/ +int readsoldata(FILE *fp, gtime_t ts, gtime_t te, double tint, int qflag, + const solopt_t *opt, solbuf_t *solbuf) +{ + int c; + + trace(3, "readsoldata:\n"); + + while ((c = fgetc(fp)) != EOF) + { + /* input solution */ + inputsol(static_cast(c), ts, te, tint, qflag, opt, solbuf); + } + return solbuf->n > 0; +} + + +/* compare solution data -----------------------------------------------------*/ +int cmpsol(const void *p1, const void *p2) +{ + auto *q1 = (sol_t *)p1, *q2 = (sol_t *)p2; + double tt = timediff(q1->time, q2->time); + return tt < -0.0 ? -1 : (tt > 0.0 ? 1 : 0); +} + + +/* sort solution data --------------------------------------------------------*/ +int sort_solbuf(solbuf_t *solbuf) +{ + sol_t *solbuf_data; + + trace(4, "sort_solbuf: n=%d\n", solbuf->n); + + if (solbuf->n <= 0) return 0; + + if (!(solbuf_data = static_cast(realloc(solbuf->data, sizeof(sol_t) * solbuf->n)))) + { + trace(1, "sort_solbuf: memory allocation error\n"); + free(solbuf->data); + solbuf->data = nullptr; + solbuf->n = solbuf->nmax = 0; + return 0; + } + solbuf->data = solbuf_data; + qsort(solbuf->data, solbuf->n, sizeof(sol_t), cmpsol); + solbuf->nmax = solbuf->n; + solbuf->start = 0; + solbuf->end = solbuf->n - 1; + return 1; +} + + +/* read solutions data from solution files ------------------------------------- + * read solution data from soluiton files + * args : char *files[] I solution files + * int nfile I number of files + * (gtime_t ts) I start time (ts.time == 0: from start) + * (gtime_t te) I end time (te.time == 0: to end) + * (double tint) I time interval (0: all) + * (int qflag) I quality flag (0: all) + * solbuf_t *solbuf O solution buffer + * return : status (1:ok,0:no data or error) + *-----------------------------------------------------------------------------*/ +int readsolt(char *files[], int nfile, gtime_t ts, gtime_t te, + double tint, int qflag, solbuf_t *solbuf) +{ + FILE *fp; + solopt_t opt = solopt_default; + int i; + + trace(3, "readsolt: nfile=%d\n", nfile); + + initsolbuf(solbuf, 0, 0); + + for (i = 0; i < nfile; i++) + { + if (!(fp = fopen(files[i], "rbe"))) + { + trace(1, "readsolt: file open error %s\n", files[i]); + continue; + } + /* read solution options in header */ + readsolopt(fp, &opt); + rewind(fp); + + /* read solution data */ + if (!readsoldata(fp, ts, te, tint, qflag, &opt, solbuf)) + { + trace(1, "readsolt: no solution in %s\n", files[i]); + } + fclose(fp); + } + return sort_solbuf(solbuf); +} + + +int readsol(char *files[], int nfile, solbuf_t *sol) +{ + gtime_t time = {0, 0.0}; + + trace(3, "readsol: nfile=%d\n", nfile); + + return readsolt(files, nfile, time, time, 0.0, 0, sol); +} + + +/* add solution data to solution buffer ---------------------------------------- + * add solution data to solution buffer + * args : solbuf_t *solbuf IO solution buffer + * sol_t *sol I solution data + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +int addsol(solbuf_t *solbuf, const sol_t *sol) +{ + sol_t *solbuf_data; + + trace(4, "addsol:\n"); + + if (solbuf->cyclic) + { /* ring buffer */ + if (solbuf->nmax <= 1) return 0; + solbuf->data[solbuf->end] = *sol; + if (++solbuf->end >= solbuf->nmax) solbuf->end = 0; + if (solbuf->start == solbuf->end) + { + if (++solbuf->start >= solbuf->nmax) solbuf->start = 0; + } + else + solbuf->n++; + + return 1; + } + + if (solbuf->n >= solbuf->nmax) + { + solbuf->nmax = solbuf->nmax == 0 ? 8192 : solbuf->nmax * 2; + if (!(solbuf_data = static_cast(realloc(solbuf->data, sizeof(sol_t) * solbuf->nmax)))) + { + trace(1, "addsol: memory allocation error\n"); + free(solbuf->data); + solbuf->data = nullptr; + solbuf->n = solbuf->nmax = 0; + return 0; + } + solbuf->data = solbuf_data; + } + solbuf->data[solbuf->n++] = *sol; + return 1; +} + + +/* get solution data from solution buffer -------------------------------------- + * get solution data by index from solution buffer + * args : solbuf_t *solbuf I solution buffer + * int index I index of solution (0...) + * return : solution data pointer (NULL: no solution, out of range) + *-----------------------------------------------------------------------------*/ +sol_t *getsol(solbuf_t *solbuf, int index) +{ + trace(4, "getsol: index=%d\n", index); + + if (index < 0 || solbuf->n <= index) return nullptr; + if ((index = solbuf->start + index) >= solbuf->nmax) + { + index -= solbuf->nmax; + } + return solbuf->data + index; +} + + +/* initialize solution buffer -------------------------------------------------- + * initialize position solutions + * args : solbuf_t *solbuf I solution buffer + * int cyclic I solution data buffer type (0:linear,1:cyclic) + * int nmax I initial number of solution data + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +void initsolbuf(solbuf_t *solbuf, int cyclic, int nmax) +{ + gtime_t time0 = {0, 0.0}; + + trace(3, "initsolbuf: cyclic=%d nmax=%d\n", cyclic, nmax); + + solbuf->n = solbuf->nmax = solbuf->start = solbuf->end = 0; + solbuf->cyclic = cyclic; + solbuf->time = time0; + solbuf->data = nullptr; + if (cyclic) + { + if (nmax <= 2) nmax = 2; + if (!(solbuf->data = static_cast(malloc(sizeof(sol_t) * nmax)))) + { + trace(1, "initsolbuf: memory allocation error\n"); + return; + } + solbuf->nmax = nmax; + } +} + + +/* free solution --------------------------------------------------------------- + * free memory for solution buffer + * args : solbuf_t *solbuf I solution buffer + * return : none + *-----------------------------------------------------------------------------*/ +void freesolbuf(solbuf_t *solbuf) +{ + trace(3, "freesolbuf: n=%d\n", solbuf->n); + + free(solbuf->data); + solbuf->n = solbuf->nmax = solbuf->start = solbuf->end = 0; + solbuf->data = nullptr; +} + + +void freesolstatbuf(solstatbuf_t *solstatbuf) +{ + trace(3, "freesolstatbuf: n=%d\n", solstatbuf->n); + + solstatbuf->n = solstatbuf->nmax = 0; + free(solstatbuf->data); + solstatbuf->data = nullptr; +} + + +/* compare solution status ---------------------------------------------------*/ +int cmpsolstat(const void *p1, const void *p2) +{ + auto *q1 = (solstat_t *)p1, *q2 = (solstat_t *)p2; + double tt = timediff(q1->time, q2->time); + return tt < -0.0 ? -1 : (tt > 0.0 ? 1 : 0); +} + + +/* sort solution data --------------------------------------------------------*/ +int sort_solstat(solstatbuf_t *statbuf) +{ + solstat_t *statbuf_data; + + trace(4, "sort_solstat: n=%d\n", statbuf->n); + + if (statbuf->n <= 0) return 0; + + if (!(statbuf_data = static_cast(realloc(statbuf->data, sizeof(solstat_t) * statbuf->n)))) + { + trace(1, "sort_solstat: memory allocation error\n"); + free(statbuf->data); + statbuf->data = nullptr; + statbuf->n = statbuf->nmax = 0; + return 0; + } + statbuf->data = statbuf_data; + qsort(statbuf->data, statbuf->n, sizeof(solstat_t), cmpsolstat); + statbuf->nmax = statbuf->n; + return 1; +} + + +/* decode solution status ----------------------------------------------------*/ +int decode_solstat(char *buff, solstat_t *stat) +{ + static const solstat_t stat0 = {{0, 0.0}, '0', '0', 0, 0, 0, 0, '0', '0', 0, 0, 0, 0}; + double tow, az, el, resp, resc; + int n, week, sat, frq, vsat, snr, fix, slip, lock, outc, slipc, rejc; + char id[32] = "", *p; + + trace(4, "decode_solstat: buff=%s\n", buff); + + if (strstr(buff, "$SAT") != buff) return 0; + + for (p = buff; *p; p++) + if (*p == ',') *p = ' '; + + n = sscanf(buff, "$SAT%d%lf%s%d%lf%lf%lf%lf%d%d%d%d%d%d%d%d", + &week, &tow, id, &frq, &az, &el, &resp, &resc, &vsat, &snr, &fix, &slip, + &lock, &outc, &slipc, &rejc); + + if (n < 15) + { + trace(2, "invalid format of solution status: %s\n", buff); + return 0; + } + if ((sat = satid2no(id)) <= 0) + { + trace(2, "invalid satellite in solution status: %s\n", id); + return 0; + } + *stat = stat0; + stat->time = gpst2time(week, tow); + stat->sat = static_cast(sat); + stat->frq = static_cast(frq); + stat->az = static_cast(az * D2R); + stat->el = static_cast(el * D2R); + stat->resp = static_cast(resp); + stat->resc = static_cast(resc); + stat->flag = static_cast((vsat << 5) + (slip << 3) + fix); + stat->snr = static_cast(snr * 4.0 + 0.5); + stat->lock = static_cast(lock); + stat->outc = static_cast(outc); + stat->slipc = static_cast(slipc); + stat->rejc = static_cast(rejc); + return 1; +} + + +/* add solution status data --------------------------------------------------*/ +void addsolstat(solstatbuf_t *statbuf, const solstat_t *stat) +{ + solstat_t *statbuf_data; + + trace(4, "addsolstat:\n"); + + if (statbuf->n >= statbuf->nmax) + { + statbuf->nmax = statbuf->nmax == 0 ? 8192 : statbuf->nmax * 2; + if (!(statbuf_data = static_cast(realloc(statbuf->data, sizeof(solstat_t) * + statbuf->nmax)))) + { + trace(1, "addsolstat: memory allocation error\n"); + free(statbuf->data); + statbuf->data = nullptr; + statbuf->n = statbuf->nmax = 0; + return; + } + statbuf->data = statbuf_data; + } + statbuf->data[statbuf->n++] = *stat; +} + + +/* read solution status data -------------------------------------------------*/ +int readsolstatdata(FILE *fp, gtime_t ts, gtime_t te, double tint, + solstatbuf_t *statbuf) +{ + solstat_t stat = {{0, 0.0}, '0', '0', 0, 0, 0, 0, '0', '0', 0, 0, 0, 0}; + char buff[MAXSOLMSG + 1]; + + trace(3, "readsolstatdata:\n"); + + while (fgets(buff, sizeof(buff), fp)) + { + /* decode solution status */ + if (!decode_solstat(buff, &stat)) continue; + + /* add solution to solution buffer */ + if (screent(stat.time, ts, te, tint)) + { + addsolstat(statbuf, &stat); + } + } + return statbuf->n > 0; +} + + +/* read solution status -------------------------------------------------------- + * read solution status from solution status files + * args : char *files[] I solution status files + * int nfile I number of files + * (gtime_t ts) I start time (ts.time == 0: from start) + * (gtime_t te) I end time (te.time == 0: to end) + * (double tint) I time interval (0: all) + * solstatbuf_t *statbuf O solution status buffer + * return : status (1:ok,0:no data or error) + *-----------------------------------------------------------------------------*/ +int readsolstatt(char *files[], int nfile, gtime_t ts, gtime_t te, + double tint, solstatbuf_t *statbuf) +{ + FILE *fp; + char path[1024]; + int i; + + trace(3, "readsolstatt: nfile=%d\n", nfile); + + statbuf->n = statbuf->nmax = 0; + statbuf->data = nullptr; + + for (i = 0; i < nfile; i++) + { + sprintf(path, "%s.stat", files[i]); + if (!(fp = fopen(path, "re"))) + { + trace(1, "readsolstatt: file open error %s\n", path); + continue; + } + /* read solution status data */ + if (!readsolstatdata(fp, ts, te, tint, statbuf)) + { + trace(1, "readsolt: no solution in %s\n", path); + } + fclose(fp); + } + return sort_solstat(statbuf); +} + + +int readsolstat(char *files[], int nfile, solstatbuf_t *statbuf) +{ + gtime_t time = {0, 0.0}; + + trace(3, "readsolstat: nfile=%d\n", nfile); + + return readsolstatt(files, nfile, time, time, 0.0, statbuf); +} + + +/* output solution as the form of x/y/z-ecef ---------------------------------*/ +int outecef(unsigned char *buff, const char *s, const sol_t *sol, + const solopt_t *opt) +{ + const char *sep = opt2sep(opt); + char *p = reinterpret_cast(buff); + + trace(3, "outecef:\n"); + + p += snprintf(p, 255, "%s%s%14.4f%s%14.4f%s%14.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%6.2f%s%6.1f\n", + s, sep, sol->rr[0], sep, sol->rr[1], sep, sol->rr[2], sep, sol->stat, sep, + sol->ns, sep, SQRT_SOL(sol->qr[0]), sep, SQRT_SOL(sol->qr[1]), sep, SQRT_SOL(sol->qr[2]), + sep, sqvar(sol->qr[3]), sep, sqvar(sol->qr[4]), sep, sqvar(sol->qr[5]), + sep, sol->age, sep, sol->ratio); + return p - reinterpret_cast(buff); +} + + +/* output solution as the form of lat/lon/height -----------------------------*/ +int outpos(unsigned char *buff, const char *s, const sol_t *sol, + const solopt_t *opt) +{ + double pos[3], dms1[3], dms2[3], P[9], Q[9]; + const char *sep = opt2sep(opt); + char *p = reinterpret_cast(buff); + + trace(3, "outpos :\n"); + + ecef2pos(sol->rr, pos); + soltocov(sol, P); + covenu(pos, P, Q); + if (opt->height == 1) + { /* geodetic height */ + // pos[2] -= geoidh(pos); + } + if (opt->degf) + { + deg2dms(pos[0] * R2D, dms1); + deg2dms(pos[1] * R2D, dms2); + p += sprintf(p, "%s%s%4.0f%s%02.0f%s%08.5f%s%4.0f%s%02.0f%s%08.5f", s, sep, + dms1[0], sep, dms1[1], sep, dms1[2], sep, dms2[0], sep, dms2[1], sep, + dms2[2]); + } + else + p += sprintf(p, "%s%s%14.9f%s%14.9f", s, sep, pos[0] * R2D, sep, pos[1] * R2D); + p += sprintf(p, "%s%10.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%6.2f%s%6.1f\n", + sep, pos[2], sep, sol->stat, sep, sol->ns, sep, SQRT_SOL(Q[4]), sep, + SQRT_SOL(Q[0]), sep, SQRT_SOL(Q[8]), sep, sqvar(Q[1]), sep, sqvar(Q[2]), + sep, sqvar(Q[5]), sep, sol->age, sep, sol->ratio); + return p - reinterpret_cast(buff); +} + + +/* output solution as the form of e/n/u-baseline -----------------------------*/ +int outenu(unsigned char *buff, const char *s, const sol_t *sol, + const double *rb, const solopt_t *opt) +{ + double pos[3], rr[3], enu[3], P[9], Q[9]; + int i; + const char *sep = opt2sep(opt); + char *p = reinterpret_cast(buff); + + trace(3, "outenu :\n"); + + for (i = 0; i < 3; i++) rr[i] = sol->rr[i] - rb[i]; + ecef2pos(rb, pos); + soltocov(sol, P); + covenu(pos, P, Q); + ecef2enu(pos, rr, enu); + p += sprintf(p, "%s%s%14.4f%s%14.4f%s%14.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%6.2f%s%6.1f\n", + s, sep, enu[0], sep, enu[1], sep, enu[2], sep, sol->stat, sep, sol->ns, sep, + SQRT_SOL(Q[0]), sep, SQRT_SOL(Q[4]), sep, SQRT_SOL(Q[8]), sep, sqvar(Q[1]), + sep, sqvar(Q[5]), sep, sqvar(Q[2]), sep, sol->age, sep, sol->ratio); + return p - reinterpret_cast(buff); +} + + +/* output solution in the form of nmea RMC sentence --------------------------*/ +int outnmea_rmc(unsigned char *buff, const sol_t *sol) +{ + static double dirp = 0.0; + gtime_t time; + double ep[6], pos[3], enuv[3], dms1[3], dms2[3], vel, dir, amag = 0.0; + char *p = reinterpret_cast(buff), *q, sum, *emag = (char *)"E"; + + trace(3, "outnmea_rmc:\n"); + + if (sol->stat <= SOLQ_NONE) + { + p += sprintf(p, "$GPRMC,,,,,,,,,,,,"); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); + } + time = gpst2utc(sol->time); + if (time.sec >= 0.995) + { + time.time++; + time.sec = 0.0; + } + time2epoch(time, ep); + ecef2pos(sol->rr, pos); + ecef2enu(pos, sol->rr + 3, enuv); + vel = norm_rtk(enuv, 3); + if (vel >= 1.0) + { + dir = atan2(enuv[0], enuv[1]) * R2D; + if (dir < 0.0) dir += 360.0; + dirp = dir; + } + else + dir = dirp; + deg2dms(fabs(pos[0]) * R2D, dms1); + deg2dms(fabs(pos[1]) * R2D, dms2); + p += sprintf(p, "$GPRMC,%02.0f%02.0f%05.2f,A,%02.0f%010.7f,%s,%03.0f%010.7f,%s,%4.2f,%4.2f,%02.0f%02.0f%02d,%.1f,%s,%s", + ep[3], ep[4], ep[5], dms1[0], dms1[1] + dms1[2] / 60.0, pos[0] >= 0 ? "N" : "S", + dms2[0], dms2[1] + dms2[2] / 60.0, pos[1] >= 0 ? "E" : "W", vel / KNOT2M, dir, + ep[2], ep[1], static_cast(ep[0]) % 100, amag, emag, + sol->stat == SOLQ_DGPS || sol->stat == SOLQ_FLOAT || sol->stat == SOLQ_FIX ? "D" : "A"); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); +} + + +/* output solution in the form of nmea GGA sentence --------------------------*/ +int outnmea_gga(unsigned char *buff, const sol_t *sol) +{ + gtime_t time; + double h, ep[6], pos[3], dms1[3], dms2[3], dop = 1.0; + int solq; + char *p = reinterpret_cast(buff), *q, sum; + + trace(3, "outnmea_gga:\n"); + + if (sol->stat <= SOLQ_NONE) + { + p += sprintf(p, "$GPGGA,,,,,,,,,,,,,,"); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); + } + for (solq = 0; solq < 8; solq++) + if (solq_nmea[solq] == sol->stat) break; + if (solq >= 8) solq = 0; + time = gpst2utc(sol->time); + if (time.sec >= 0.995) + { + time.time++; + time.sec = 0.0; + } + time2epoch(time, ep); + ecef2pos(sol->rr, pos); + h = 0; //geoidh(pos); + deg2dms(fabs(pos[0]) * R2D, dms1); + deg2dms(fabs(pos[1]) * R2D, dms2); + p += sprintf(p, "$GPGGA,%02.0f%02.0f%05.2f,%02.0f%010.7f,%s,%03.0f%010.7f,%s,%d,%02d,%.1f,%.3f,M,%.3f,M,%.1f,", + ep[3], ep[4], ep[5], dms1[0], dms1[1] + dms1[2] / 60.0, pos[0] >= 0 ? "N" : "S", + dms2[0], dms2[1] + dms2[2] / 60.0, pos[1] >= 0 ? "E" : "W", solq, + sol->ns, dop, pos[2] - h, h, sol->age); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); +} + + +/* output solution in the form of nmea GSA sentences -------------------------*/ +int outnmea_gsa(unsigned char *buff, const sol_t *sol, + const ssat_t *ssat) +{ + double azel[MAXSAT * 2], dop[4]; + int i, sat, sys, nsat, prn[MAXSAT]; + char *p = reinterpret_cast(buff), *q, *s, sum; + + trace(3, "outnmea_gsa:\n"); + + if (sol->stat <= SOLQ_NONE) + { + p += sprintf(p, "$GPGSA,A,1,,,,,,,,,,,,,,,"); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); + } + + /* GPGSA: gps/sbas */ + for (sat = 1, nsat = 0; sat <= MAXSAT && nsat < 12; sat++) + { + if (!ssat[sat - 1].vs || ssat[sat - 1].azel[1] <= 0.0) continue; + sys = satsys(sat, prn + nsat); + if (sys != SYS_GPS && sys != SYS_SBS) continue; + if (sys == SYS_SBS) prn[nsat] += 33 - MINPRNSBS; + for (i = 0; i < 2; i++) azel[i + nsat * 2] = ssat[sat - 1].azel[i]; + nsat++; + } + if (nsat > 0) + { + s = p; + p += sprintf(p, "$GPGSA,A,%d", sol->stat <= 0 ? 1 : 3); + for (i = 0; i < 12; i++) + { + if (i < nsat) + p += sprintf(p, ",%02d", prn[i]); + else + p += sprintf(p, ","); + } + dops(nsat, azel, 0.0, dop); + p += sprintf(p, ",%3.1f,%3.1f,%3.1f,1", dop[1], dop[2], dop[3]); + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + /* GLGSA: glonass */ + for (sat = 1, nsat = 0; sat <= MAXSAT && nsat < 12; sat++) + { + if (!ssat[sat - 1].vs || ssat[sat - 1].azel[1] <= 0.0) continue; + if (satsys(sat, prn + nsat) != SYS_GLO) continue; + for (i = 0; i < 2; i++) azel[i + nsat * 2] = ssat[sat - 1].azel[i]; + nsat++; + } + if (nsat > 0) + { + s = p; + p += sprintf(p, "$GLGSA,A,%d", sol->stat <= 0 ? 1 : 3); + for (i = 0; i < 12; i++) + { + if (i < nsat) + p += sprintf(p, ",%02d", prn[i] + 64); + else + p += sprintf(p, ","); + } + dops(nsat, azel, 0.0, dop); + p += sprintf(p, ",%3.1f,%3.1f,%3.1f,2", dop[1], dop[2], dop[3]); + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + /* GAGSA: galileo */ + for (sat = 1, nsat = 0; sat <= MAXSAT && nsat < 12; sat++) + { + if (!ssat[sat - 1].vs || ssat[sat - 1].azel[1] <= 0.0) continue; + if (satsys(sat, prn + nsat) != SYS_GAL) continue; + for (i = 0; i < 2; i++) azel[i + nsat * 2] = ssat[sat - 1].azel[i]; + nsat++; + } + if (nsat > 0) + { + s = p; + p += sprintf(p, "$GAGSA,A,%d", sol->stat <= 0 ? 1 : 3); + for (i = 0; i < 12; i++) + { + if (i < nsat) + p += sprintf(p, ",%02d", prn[i]); + else + p += sprintf(p, ","); + } + dops(nsat, azel, 0.0, dop); + p += sprintf(p, ",%3.1f,%3.1f,%3.1f,3", dop[1], dop[2], dop[3]); + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + return p - reinterpret_cast(buff); +} + + +/* output solution in the form of nmea GSV sentence --------------------------*/ +int outnmea_gsv(unsigned char *buff, const sol_t *sol, + const ssat_t *ssat) +{ + double az, el, snr; + int i, j, k, n, sat, prn, sys, nmsg, sats[MAXSAT]; + char *p = reinterpret_cast(buff), *q, *s, sum; + + trace(3, "outnmea_gsv:\n"); + + if (sol->stat <= SOLQ_NONE) + { + p += sprintf(p, "$GPGSV,1,1,0,,,,,,,,,,,,,,,,"); + for (q = reinterpret_cast(buff) + 1, sum = 0; *q; q++) sum ^= *q; + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + return p - reinterpret_cast(buff); + } + /* GPGSV: gps/sbas */ + for (sat = 1, n = 0; sat < MAXSAT && n < 12; sat++) + { + sys = satsys(sat, &prn); + if (sys != SYS_GPS && sys != SYS_SBS) continue; + if (ssat[sat - 1].vs && ssat[sat - 1].azel[1] > 0.0) sats[n++] = sat; + } + nmsg = n <= 0 ? 0 : (n - 1) / 4 + 1; + + for (i = k = 0; i < nmsg; i++) + { + s = p; + p += sprintf(p, "$GPGSV,%d,%d,%02d", nmsg, i + 1, n); + + for (j = 0; j < 4; j++, k++) + { + if (k < n) + { + if (satsys(sats[k], &prn) == SYS_SBS) prn += 33 - MINPRNSBS; + az = ssat[sats[k] - 1].azel[0] * R2D; + if (az < 0.0) az += 360.0; + el = ssat[sats[k] - 1].azel[1] * R2D; + snr = ssat[sats[k] - 1].snr[0] * 0.25; + p += sprintf(p, ",%02d,%02.0f,%03.0f,%02.0f", prn, el, az, snr); + } + else + p += sprintf(p, ",,,,"); + } + p += sprintf(p, ",1"); /* L1C/A */ + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + /* GLGSV: glonass */ + for (sat = 1, n = 0; sat < MAXSAT && n < 12; sat++) + { + if (satsys(sat, &prn) != SYS_GLO) continue; + if (ssat[sat - 1].vs && ssat[sat - 1].azel[1] > 0.0) sats[n++] = sat; + } + nmsg = n <= 0 ? 0 : (n - 1) / 4 + 1; + + for (i = k = 0; i < nmsg; i++) + { + s = p; + p += sprintf(p, "$GLGSV,%d,%d,%02d", nmsg, i + 1, n); + + for (j = 0; j < 4; j++, k++) + { + if (k < n) + { + satsys(sats[k], &prn); + prn += 64; /* 65-99 */ + az = ssat[sats[k] - 1].azel[0] * R2D; + if (az < 0.0) az += 360.0; + el = ssat[sats[k] - 1].azel[1] * R2D; + snr = ssat[sats[k] - 1].snr[0] * 0.25; + p += sprintf(p, ",%02d,%02.0f,%03.0f,%02.0f", prn, el, az, snr); + } + else + p += sprintf(p, ",,,,"); + } + p += sprintf(p, ",1"); /* L1C/A */ + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + /* GAGSV: galileo */ + for (sat = 1, n = 0; sat < MAXSAT && n < 12; sat++) + { + if (satsys(sat, &prn) != SYS_GAL) continue; + if (ssat[sat - 1].vs && ssat[sat - 1].azel[1] > 0.0) sats[n++] = sat; + } + nmsg = n <= 0 ? 0 : (n - 1) / 4 + 1; + + for (i = k = 0; i < nmsg; i++) + { + s = p; + p += sprintf(p, "$GAGSV,%d,%d,%02d", nmsg, i + 1, n); + + for (j = 0; j < 4; j++, k++) + { + if (k < n) + { + satsys(sats[k], &prn); /* 1-36 */ + az = ssat[sats[k] - 1].azel[0] * R2D; + if (az < 0.0) az += 360.0; + el = ssat[sats[k] - 1].azel[1] * R2D; + snr = ssat[sats[k] - 1].snr[0] * 0.25; + p += sprintf(p, ",%02d,%02.0f,%03.0f,%02.0f", prn, el, az, snr); + } + else + p += sprintf(p, ",,,,"); + } + p += sprintf(p, ",7"); /* L1BC */ + for (q = s + 1, sum = 0; *q; q++) sum ^= *q; /* check-sum */ + p += sprintf(p, "*%02X%c%c", sum, 0x0D, 0x0A); + } + return p - reinterpret_cast(buff); +} + + +/* output processing options --------------------------------------------------- + * output processing options to buffer + * args : unsigned char *buff IO output buffer + * prcopt_t *opt I processign options + * return : number of output bytes + *-----------------------------------------------------------------------------*/ +int outprcopts(unsigned char *buff, const prcopt_t *opt) +{ + const int sys[] = {SYS_GPS, SYS_GLO, SYS_GAL, SYS_QZS, SYS_SBS, 0}; + const char *s1[] = {"single", "dgps", "kinematic", "static", "moving-base", "fixed", + "ppp-kinematic", "ppp-static", "ppp-fixed", ""}; + const char *s2[] = {"L1", "L1+L2", "L1+L2+L5", "L1+L2+L5+L6", "L1+L2+L5+L6+L7", + "L1+L2+L5+L6+L7+L8", ""}; + const char *s3[] = {"forward", "backward", "combined"}; + const char *s4[] = {"off", "broadcast", "sbas", "iono-free", "estimation", + "ionex tec", "qzs", "lex", "vtec_sf", "vtec_ef", "gtec", ""}; + const char *s5[] = {"off", "saastamoinen", "sbas", "est ztd", "est ztd+grad", ""}; + const char *s6[] = {"broadcast", "precise", "broadcast+sbas", "broadcast+ssr apc", + "broadcast+ssr com", "qzss lex", ""}; + const char *s7[] = {"gps", "glonass", "galileo", "qzss", "sbas", ""}; + const char *s8[] = {"off", "continuous", "instantaneous", "fix and hold", ""}; + const char *s9[] = {"off", "on", "auto calib", "external calib", ""}; + int i; + char *p = reinterpret_cast(buff); + + trace(3, "outprcopts:\n"); + + p += sprintf(p, "%s pos mode : %s\n", COMMENTH, s1[opt->mode]); + + if (PMODE_DGPS <= opt->mode && opt->mode <= PMODE_FIXED) + { + p += sprintf(p, "%s freqs : %s\n", COMMENTH, s2[opt->nf - 1]); + } + if (opt->mode > PMODE_SINGLE) + { + p += sprintf(p, "%s solution : %s\n", COMMENTH, s3[opt->soltype]); + } + p += sprintf(p, "%s elev mask : %.1f deg\n", COMMENTH, opt->elmin * R2D); + if (opt->mode > PMODE_SINGLE) + { + p += sprintf(p, "%s dynamics : %s\n", COMMENTH, opt->dynamics ? "on" : "off"); + p += sprintf(p, "%s tidecorr : %s\n", COMMENTH, opt->tidecorr ? "on" : "off"); + } + if (opt->mode <= PMODE_FIXED) + { + p += sprintf(p, "%s ionos opt : %s\n", COMMENTH, s4[opt->ionoopt]); + } + p += sprintf(p, "%s tropo opt : %s\n", COMMENTH, s5[opt->tropopt]); + p += sprintf(p, "%s ephemeris : %s\n", COMMENTH, s6[opt->sateph]); + if (opt->navsys != SYS_GPS) + { + p += sprintf(p, "%s navi sys :", COMMENTH); + for (i = 0; sys[i]; i++) + { + if (opt->navsys & sys[i]) p += sprintf(p, " %s", s7[i]); + } + p += sprintf(p, "\n"); + } + if (PMODE_KINEMA <= opt->mode && opt->mode <= PMODE_FIXED) + { + p += sprintf(p, "%s amb res : %s\n", COMMENTH, s8[opt->modear]); + if (opt->navsys & SYS_GLO) + { + p += sprintf(p, "%s amb glo : %s\n", COMMENTH, s9[opt->glomodear]); + } + if (opt->thresar[0] > 0.0) + { + p += sprintf(p, "%s val thres : %.1f\n", COMMENTH, opt->thresar[0]); + } + } + if (opt->mode == PMODE_MOVEB && opt->baseline[0] > 0.0) + { + p += sprintf(p, "%s baseline : %.4f %.4f m\n", COMMENTH, + opt->baseline[0], opt->baseline[1]); + } + for (i = 0; i < 2; i++) + { + if (opt->mode == PMODE_SINGLE || (i >= 1 && opt->mode > PMODE_FIXED)) continue; + p += sprintf(p, "%s antenna%d : %-21s (%7.4f %7.4f %7.4f)\n", COMMENTH, + i + 1, opt->anttype[i], opt->antdel[i][0], opt->antdel[i][1], + opt->antdel[i][2]); + } + return p - reinterpret_cast(buff); +} + + +/* output solution header ------------------------------------------------------ + * output solution header to buffer + * args : unsigned char *buff IO output buffer + * solopt_t *opt I solution options + * return : number of output bytes + *-----------------------------------------------------------------------------*/ +int outsolheads(unsigned char *buff, const solopt_t *opt) +{ + const char *s1[] = {"WGS84", "Tokyo"}, *s2[] = {"ellipsoidal", "geodetic"}; + const char *s3[] = {"GPST", "UTC ", "JST "}, *sep = opt2sep(opt); + char *p = reinterpret_cast(buff); + int timeu = opt->timeu < 0 ? 0 : (opt->timeu > 20 ? 20 : opt->timeu); + + trace(3, "outsolheads:\n"); + + if (opt->posf == SOLF_NMEA) return 0; + + if (opt->outhead) + { + p += sprintf(p, "%s (", COMMENTH); + if (opt->posf == SOLF_XYZ) + p += sprintf(p, "x/y/z-ecef=WGS84"); + else if (opt->posf == SOLF_ENU) + p += sprintf(p, "e/n/u-baseline=WGS84"); + else + p += sprintf(p, "lat/lon/height=%s/%s", s1[opt->datum], s2[opt->height]); + p += sprintf(p, ",Q=1:fix,2:float,3:sbas,4:dgps,5:single,6:ppp,ns=# of satellites)\n"); + } + p += sprintf(p, "%s %-*s%s", COMMENTH, (opt->timef ? 16 : 8) + timeu + 1, s3[opt->times], sep); + + if (opt->posf == SOLF_LLH) + { /* lat/lon/hgt */ + if (opt->degf) + { + p += sprintf(p, "%16s%s%16s%s%10s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s%s%6s%s%6s\n", + "latitude(d'\")", sep, "longitude(d'\")", sep, "height(m)", sep, + "Q", sep, "ns", sep, "sdn(m)", sep, "sde(m)", sep, "sdu(m)", sep, + "sdne(m)", sep, "sdeu(m)", sep, "sdue(m)", sep, "age(s)", sep, "ratio"); + } + else + { + p += sprintf(p, "%14s%s%14s%s%10s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s%s%6s%s%6s\n", + "latitude(deg)", sep, "longitude(deg)", sep, "height(m)", sep, + "Q", sep, "ns", sep, "sdn(m)", sep, "sde(m)", sep, "sdu(m)", sep, + "sdne(m)", sep, "sdeu(m)", sep, "sdun(m)", sep, "age(s)", sep, "ratio"); + } + } + else if (opt->posf == SOLF_XYZ) + { /* x/y/z-ecef */ + p += sprintf(p, "%14s%s%14s%s%14s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s%s%6s%s%6s\n", + "x-ecef(m)", sep, "y-ecef(m)", sep, "z-ecef(m)", sep, "Q", sep, "ns", sep, + "sdx(m)", sep, "sdy(m)", sep, "sdz(m)", sep, "sdxy(m)", sep, + "sdyz(m)", sep, "sdzx(m)", sep, "age(s)", sep, "ratio"); + } + else if (opt->posf == SOLF_ENU) + { /* e/n/u-baseline */ + p += sprintf(p, "%14s%s%14s%s%14s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s%s%6s%s%6s\n", + "e-baseline(m)", sep, "n-baseline(m)", sep, "u-baseline(m)", sep, + "Q", sep, "ns", sep, "sde(m)", sep, "sdn(m)", sep, "sdu(m)", sep, + "sden(m)", sep, "sdnu(m)", sep, "sdue(m)", sep, "age(s)", sep, "ratio"); + } + return p - reinterpret_cast(buff); +} + + +/* output solution body -------------------------------------------------------- + * output solution body to buffer + * args : unsigned char *buff IO output buffer + * sol_t *sol I solution + * double *rb I base station position {x,y,z} (ecef) (m) + * solopt_t *opt I solution options + * return : number of output bytes + *-----------------------------------------------------------------------------*/ +int outsols(unsigned char *buff, const sol_t *sol, const double *rb, + const solopt_t *opt) +{ + gtime_t time, ts = {0, 0.0}; + double gpst; + int week, timeu; + const char *sep = opt2sep(opt); + char s[255]; + unsigned char *p = buff; + + trace(3, "outsols :\n"); + + if (opt->posf == SOLF_NMEA) + { + if (opt->nmeaintv[0] < 0.0) return 0; + if (!screent(sol->time, ts, ts, opt->nmeaintv[0])) return 0; + } + if (sol->stat <= SOLQ_NONE || (opt->posf == SOLF_ENU && norm_rtk(rb, 3) <= 0.0)) + { + return 0; + } + timeu = opt->timeu < 0 ? 0 : (opt->timeu > 20 ? 20 : opt->timeu); + + time = sol->time; + if (opt->times >= TIMES_UTC) time = gpst2utc(time); + if (opt->times == TIMES_JST) time = timeadd(time, 9 * 3600.0); + + if (opt->timef) + time2str(time, s, timeu); + else + { + gpst = time2gpst(time, &week); + if (86400 * 7 - gpst < 0.5 / pow(10.0, timeu)) + { + week++; + gpst = 0.0; + } + snprintf(s, 255, "%4d%s%*.*f", week, sep, 6 + (timeu <= 0 ? 0 : timeu + 1), timeu, gpst); + } + switch (opt->posf) + { + case SOLF_LLH: + p += outpos(p, s, sol, opt); + break; + case SOLF_XYZ: + p += outecef(p, s, sol, opt); + break; + case SOLF_ENU: + p += outenu(p, s, sol, rb, opt); + break; + case SOLF_NMEA: + p += outnmea_rmc(p, sol); + p += outnmea_gga(p, sol); + break; + } + return p - buff; +} + + +/* output solution extended ---------------------------------------------------- + * output solution exteneded information + * args : unsigned char *buff IO output buffer + * sol_t *sol I solution + * ssat_t *ssat I satellite status + * solopt_t *opt I solution options + * return : number of output bytes + * notes : only support nmea + *-----------------------------------------------------------------------------*/ +int outsolexs(unsigned char *buff, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt) +{ + gtime_t ts = {0, 0.0}; + unsigned char *p = buff; + + trace(3, "outsolexs:\n"); + + if (opt->posf == SOLF_NMEA) + { + if (opt->nmeaintv[1] < 0.0) return 0; + if (!screent(sol->time, ts, ts, opt->nmeaintv[1])) return 0; + } + if (opt->posf == SOLF_NMEA) + { + p += outnmea_gsa(p, sol, ssat); + p += outnmea_gsv(p, sol, ssat); + } + return p - buff; +} + + +/* output processing option ---------------------------------------------------- + * output processing option to file + * args : FILE *fp I output file pointer + * prcopt_t *opt I processing options + * return : none + *-----------------------------------------------------------------------------*/ +void outprcopt(FILE *fp, const prcopt_t *opt) +{ + unsigned char buff[MAXSOLMSG + 1]; + int n; + + trace(3, "outprcopt:\n"); + + if ((n = outprcopts(buff, opt)) > 0) + { + fwrite(buff, n, 1, fp); + } +} + + +/* output solution header ------------------------------------------------------ + * output solution heade to file + * args : FILE *fp I output file pointer + * solopt_t *opt I solution options + * return : none + *-----------------------------------------------------------------------------*/ +void outsolhead(FILE *fp, const solopt_t *opt) +{ + unsigned char buff[MAXSOLMSG + 1]; + int n; + + trace(3, "outsolhead:\n"); + + if ((n = outsolheads(buff, opt)) > 0) + { + fwrite(buff, n, 1, fp); + } +} + + +/* output solution body -------------------------------------------------------- + * output solution body to file + * args : FILE *fp I output file pointer + * sol_t *sol I solution + * double *rb I base station position {x,y,z} (ecef) (m) + * solopt_t *opt I solution options + * return : none + *-----------------------------------------------------------------------------*/ +void outsol(FILE *fp, const sol_t *sol, const double *rb, + const solopt_t *opt) +{ + unsigned char buff[MAXSOLMSG + 1]; + int n; + + trace(3, "outsol :\n"); + + if ((n = outsols(buff, sol, rb, opt)) > 0) + { + fwrite(buff, n, 1, fp); + } +} + + +/* output solution extended ---------------------------------------------------- + * output solution exteneded information to file + * args : FILE *fp I output file pointer + * sol_t *sol I solution + * ssat_t *ssat I satellite status + * solopt_t *opt I solution options + * return : output size (bytes) + * notes : only support nmea + *-----------------------------------------------------------------------------*/ +void outsolex(FILE *fp, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt) +{ + unsigned char buff[MAXSOLMSG + 1]; + int n; + + trace(3, "outsolex:\n"); + + if ((n = outsolexs(buff, sol, ssat, opt)) > 0) + { + fwrite(buff, n, 1, fp); + } +} diff --git a/src/algorithms/libs/rtklib/rtklib_solution.h b/src/algorithms/libs/rtklib/rtklib_solution.h new file mode 100644 index 000000000..10906c01a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_solution.h @@ -0,0 +1,181 @@ +/*! + * \file rtklib_solution.h + * \brief solution functions headers + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *-----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_SOLUTION_H_ +#define GNSS_SDR_RTKLIB_SOLUTION_H_ + +#include "rtklib.h" + +#define COMMENTH "%" /* comment line indicator for solution */ +#define MSG_DISCONN "$_DISCONNECT\r\n" /* disconnect message */ + +const char *opt2sep(const solopt_t *opt); + +int tonum(char *buff, const char *sep, double *v); + +double sqvar(double covar); + +double dmm2deg(double dmm); + +void septime(double t, double *t1, double *t2, double *t3); + +void soltocov(const sol_t *sol, double *P); + +void covtosol(const double *P, sol_t *sol); + +int decode_nmearmc(char **val, int n, sol_t *sol); + +int decode_nmeagga(char **val, int n, sol_t *sol); + +int decode_nmea(char *buff, sol_t *sol); + +char *decode_soltime(char *buff, const solopt_t *opt, gtime_t *time); + +int decode_solxyz(char *buff, const solopt_t *opt, sol_t *sol); + +int decode_solllh(char *buff, const solopt_t *opt, sol_t *sol); + +int decode_solenu(char *buff, const solopt_t *opt, sol_t *sol); + +int decode_solgsi(char *buff, const solopt_t *opt, sol_t *sol); + +int decode_solpos(char *buff, const solopt_t *opt, sol_t *sol); + +void decode_refpos(char *buff, const solopt_t *opt, double *rb); + +int decode_sol(char *buff, const solopt_t *opt, sol_t *sol, double *rb); + +void decode_solopt(char *buff, solopt_t *opt); + +void readsolopt(FILE *fp, solopt_t *opt); + +int inputsol(unsigned char data, gtime_t ts, gtime_t te, double tint, + int qflag, const solopt_t *opt, solbuf_t *solbuf); + +int readsoldata(FILE *fp, gtime_t ts, gtime_t te, double tint, int qflag, + const solopt_t *opt, solbuf_t *solbuf); + +int cmpsol(const void *p1, const void *p2); + +int sort_solbuf(solbuf_t *solbuf); + +int readsolt(char *files[], int nfile, gtime_t ts, gtime_t te, + double tint, int qflag, solbuf_t *solbuf); + +int readsol(char *files[], int nfile, solbuf_t *sol); + +int addsol(solbuf_t *solbuf, const sol_t *sol); + +sol_t *getsol(solbuf_t *solbuf, int index); + +void initsolbuf(solbuf_t *solbuf, int cyclic, int nmax); + +void freesolbuf(solbuf_t *solbuf); + +void freesolstatbuf(solstatbuf_t *solstatbuf); + +int cmpsolstat(const void *p1, const void *p2); + +int sort_solstat(solstatbuf_t *statbuf); + +int decode_solstat(char *buff, solstat_t *stat); + +void addsolstat(solstatbuf_t *statbuf, const solstat_t *stat); + +int readsolstatdata(FILE *fp, gtime_t ts, gtime_t te, double tint, + solstatbuf_t *statbuf); + +int readsolstatt(char *files[], int nfile, gtime_t ts, gtime_t te, + double tint, solstatbuf_t *statbuf); + +int readsolstat(char *files[], int nfile, solstatbuf_t *statbuf); + +int outecef(unsigned char *buff, const char *s, const sol_t *sol, + const solopt_t *opt); + +int outpos(unsigned char *buff, const char *s, const sol_t *sol, const solopt_t *opt); + +int outenu(unsigned char *buff, const char *s, const sol_t *sol, + const double *rb, const solopt_t *opt); + +int outnmea_rmc(unsigned char *buff, const sol_t *sol); + +int outnmea_gga(unsigned char *buff, const sol_t *sol); + +int outnmea_gsa(unsigned char *buff, const sol_t *sol, + const ssat_t *ssat); + +int outnmea_gsv(unsigned char *buff, const sol_t *sol, + const ssat_t *ssat); + +int outprcopts(unsigned char *buff, const prcopt_t *opt); + +int outsolheads(unsigned char *buff, const solopt_t *opt); + +int outsols(unsigned char *buff, const sol_t *sol, const double *rb, + const solopt_t *opt); + +int outsolexs(unsigned char *buff, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt); + +void outprcopt(FILE *fp, const prcopt_t *opt); + +void outsolhead(FILE *fp, const solopt_t *opt); + +void outsol(FILE *fp, const sol_t *sol, const double *rb, + const solopt_t *opt); + +void outsolex(FILE *fp, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_stream.cc b/src/algorithms/libs/rtklib/rtklib_stream.cc new file mode 100644 index 000000000..9b2a0d3e2 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_stream.cc @@ -0,0 +1,2372 @@ +/*! + * \file rtklib_stream.cc + * \brief streaming functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* global options ------------------------------------------------------------*/ + +static int toinact = 10000; /* inactive timeout (ms) */ +static int ticonnect = 10000; /* interval to re-connect (ms) */ +static int tirate = 1000; /* avraging time for data rate (ms) */ +static int buffsize = 32768; /* receive/send buffer size (bytes) */ +static char localdir[1024] = ""; /* local directory for ftp/http */ +static char proxyaddr[256] = ""; /* http/ntrip/ftp proxy address */ +static unsigned int tick_master = 0; /* time tick master for replay */ +static int fswapmargin = 30; /* file swap margin (s) */ + + +/* open serial ---------------------------------------------------------------*/ +serial_t *openserial(const char *path, int mode, char *msg) +{ + const int br[] = { + 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}; + serial_t *serial; + int i, brate = 9600, bsize = 8, stopb = 1; + char *p, parity = 'N', dev[128], port[128], fctr[64] = ""; + + const speed_t bs[] = { + B300, B600, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400}; + struct termios ios + { + }; + int rw = 0; + tracet(3, "openserial: path=%s mode=%d\n", path, mode); + + if (!(serial = static_cast(malloc(sizeof(serial_t))))) return nullptr; + + if ((p = strchr(const_cast(path), ':'))) + { + strncpy(port, path, p - path); + port[p - path] = '\0'; + sscanf(p, ":%d:%d:%c:%d:%s", &brate, &bsize, &parity, &stopb, fctr); + } + else if (strlen(path) < 128) + strcpy(port, path); + + for (i = 0; i < 10; i++) + if (br[i] == brate) break; + if (i >= 11) + { + sprintf(msg, "bitrate error (%d)", brate); + tracet(1, "openserial: %s path=%s\n", msg, path); + free(serial); + return nullptr; + } + parity = static_cast(toupper(static_cast(parity))); + + // sprintf(dev, "/dev/%s", port); This line triggers a warning. Replaced by: + std::string s_aux = "/dev/" + std::string(port); + s_aux.resize(128, '\0'); + int n = s_aux.length(); + for (int i = 0; i < n; i++) dev[i] = s_aux[i]; + if (n == 0) dev[0] = '\0'; + + if ((mode & STR_MODE_R) && (mode & STR_MODE_W)) + rw = O_RDWR; + else if (mode & STR_MODE_R) + rw = O_RDONLY; + else if (mode & STR_MODE_W) + rw = O_WRONLY; + + if ((serial->dev = open(dev, rw | O_NOCTTY | O_NONBLOCK)) < 0) + { + sprintf(msg, "device open error (%d)", errno); + tracet(1, "openserial: %s dev=%s\n", msg, dev); + free(serial); + return nullptr; + } + tcgetattr(serial->dev, &ios); + ios.c_iflag = 0; + ios.c_oflag = 0; + ios.c_lflag = 0; /* non-canonical */ + ios.c_cc[VMIN] = 0; /* non-block-mode */ + ios.c_cc[VTIME] = 0; + cfsetospeed(&ios, bs[i]); + cfsetispeed(&ios, bs[i]); + ios.c_cflag |= bsize == 7 ? CS7 : CS8; + ios.c_cflag |= parity == 'O' ? (PARENB | PARODD) : (parity == 'E' ? PARENB : 0); + ios.c_cflag |= stopb == 2 ? CSTOPB : 0; + ios.c_cflag |= !strcmp(fctr, "rts") ? CRTSCTS : 0; + tcsetattr(serial->dev, TCSANOW, &ios); + tcflush(serial->dev, TCIOFLUSH); + return serial; +} + + +/* close serial --------------------------------------------------------------*/ +void closeserial(serial_t *serial) +{ + if (!serial) return; + tracet(3, "closeserial: dev=%d\n", serial->dev); + close(serial->dev); + free(serial); +} + + +/* read serial ---------------------------------------------------------------*/ +int readserial(serial_t *serial, unsigned char *buff, int n, char *msg __attribute__((unused))) +{ + int nr; + if (!serial) return 0; + tracet(4, "readserial: dev=%d n=%d\n", serial->dev, n); + if ((nr = read(serial->dev, buff, n)) < 0) return 0; + tracet(5, "readserial: exit dev=%d nr=%d\n", serial->dev, nr); + return nr; +} + + +/* write serial --------------------------------------------------------------*/ +int writeserial(serial_t *serial, unsigned char *buff, int n, char *msg __attribute__((unused))) +{ + int ns; + if (!serial) return 0; + tracet(3, "writeserial: dev=%d n=%d\n", serial->dev, n); + if ((ns = write(serial->dev, buff, n)) < 0) return 0; + tracet(5, "writeserial: exit dev=%d ns=%d\n", serial->dev, ns); + return ns; +} + + +/* get state serial ----------------------------------------------------------*/ +int stateserial(serial_t *serial) +{ + return !serial ? 0 : (serial->error ? -1 : 2); +} + + +/* open file -----------------------------------------------------------------*/ +int openfile_(file_t *file, gtime_t time, char *msg) +{ + FILE *fp; + char *rw, tagpath[MAXSTRPATH + 4] = ""; + char tagh[TIMETAGH_LEN + 1] = ""; + + tracet(3, "openfile_: path=%s time=%s\n", file->path, time_str(time, 0)); + + file->time = utc2gpst(timeget()); + file->tick = file->tick_f = tickget(); + file->fpos = 0; + + /* use stdin or stdout if file path is null */ + if (!*file->path) + { + file->fp = file->mode & STR_MODE_R ? stdin : stdout; + return 1; + } + /* replace keywords */ + reppath(file->path, file->openpath, time, "", ""); + + /* create directory */ + if ((file->mode & STR_MODE_W) && !(file->mode & STR_MODE_R)) + { + createdir(file->openpath); + } + if (file->mode & STR_MODE_R) + rw = (char *)"rb"; + else + rw = (char *)"wb"; + + if (!(file->fp = fopen(file->openpath, rw))) + { + sprintf(msg, "file open error: %s", file->openpath); + tracet(1, "openfile: %s\n", msg); + return 0; + } + tracet(4, "openfile_: open file %s (%s)\n", file->openpath, rw); + + sprintf(tagpath, "%s.tag", file->openpath); + + if (file->timetag) + { /* output/sync time-tag */ + if (!(file->fp_tag = fopen(tagpath, rw))) + { + sprintf(msg, "tag open error: %s", tagpath); + tracet(1, "openfile: %s\n", msg); + fclose(file->fp); + return 0; + } + tracet(4, "openfile_: open tag file %s (%s)\n", tagpath, rw); + + if (file->mode & STR_MODE_R) + { + if (fread(&tagh, TIMETAGH_LEN, 1, file->fp_tag) == 1 && + fread(&file->time, sizeof(file->time), 1, file->fp_tag) == 1) + { + memcpy(&file->tick_f, tagh + TIMETAGH_LEN - 4, sizeof(file->tick_f)); + } + else + { + file->tick_f = 0; + } + /* adust time to read playback file */ + timeset(file->time); + } + else + { + sprintf(tagh, "TIMETAG RTKLIB %s", VER_RTKLIB); + memcpy(tagh + TIMETAGH_LEN - 4, &file->tick_f, sizeof(file->tick_f)); + fwrite(&tagh, 1, TIMETAGH_LEN, file->fp_tag); + fwrite(&file->time, 1, sizeof(file->time), file->fp_tag); + /* time tag file structure */ + /* HEADER(60)+TICK(4)+TIME(12)+ */ + /* TICK0(4)+FPOS0(4/8)+ */ + /* TICK1(4)+FPOS1(4/8)+... */ + } + } + else if (file->mode & STR_MODE_W) + { /* remove time-tag */ + if ((fp = fopen(tagpath, "rbe"))) + { + fclose(fp); + if (remove(tagpath) != 0) trace(1, "Error removing file"); + } + } + return 1; +} + + +/* close file ----------------------------------------------------------------*/ +void closefile_(file_t *file) +{ + tracet(3, "closefile_: path=%s\n", file->path); + if (file->fp) fclose(file->fp); + if (file->fp_tag) fclose(file->fp_tag); + if (file->fp_tmp) fclose(file->fp_tmp); + if (file->fp_tag_tmp) fclose(file->fp_tag_tmp); + file->fp = file->fp_tag = file->fp_tmp = file->fp_tag_tmp = nullptr; +} + + +/* open file (path=filepath[::T[::+][::x]][::S=swapintv]) --------*/ +file_t *openfile(const char *path, int mode, char *msg) +{ + file_t *file; + gtime_t time, time0 = {0, 0.0}; + double speed = 0.0, start = 0.0, swapintv = 0.0; + char *p; + int timetag = 0; + + tracet(3, "openfile: path=%s mode=%d\n", path, mode); + + if (!(mode & (STR_MODE_R | STR_MODE_W))) return nullptr; + + /* file options */ + for (p = const_cast(path); (p = strstr(p, "::")); p += 2) + { /* file options */ + if (*(p + 2) == 'T') + timetag = 1; + else if (*(p + 2) == '+') + sscanf(p + 2, "+%lf", &start); + else if (*(p + 2) == 'x') + sscanf(p + 2, "x%lf", &speed); + else if (*(p + 2) == 'S') + sscanf(p + 2, "S=%lf", &swapintv); + } + if (start <= 0.0) start = 0.0; + if (swapintv <= 0.0) swapintv = 0.0; + + if (!(file = static_cast(malloc(sizeof(file_t))))) return nullptr; + + file->fp = file->fp_tag = file->fp_tmp = file->fp_tag_tmp = nullptr; + if (strlen(path) < MAXSTRPATH) strcpy(file->path, path); + if ((p = strstr(file->path, "::"))) *p = '\0'; + file->openpath[0] = '\0'; + file->mode = mode; + file->timetag = timetag; + file->repmode = 0; + file->offset = 0; + file->time = file->wtime = time0; + file->tick = file->tick_f = file->fpos = 0; + file->start = start; + file->speed = speed; + file->swapintv = swapintv; + initlock(&file->lock); + + time = utc2gpst(timeget()); + + /* open new file */ + if (!openfile_(file, time, msg)) + { + free(file); + return nullptr; + } + return file; +} + + +/* close file ----------------------------------------------------------------*/ +void closefile(file_t *file) +{ + if (!file) return; + tracet(3, "closefile: fp=%d\n", file->fp); + closefile_(file); + free(file); +} + + +/* open new swap file --------------------------------------------------------*/ +void swapfile(file_t *file, gtime_t time, char *msg) +{ + char openpath[MAXSTRPATH]; + + tracet(3, "swapfile: fp=%d time=%s\n", file->fp, time_str(time, 0)); + + /* return if old swap file open */ + if (file->fp_tmp || file->fp_tag_tmp) return; + + /* check path of new swap file */ + reppath(file->path, openpath, time, "", ""); + + if (!strcmp(openpath, file->openpath)) + { + tracet(2, "swapfile: no need to swap %s\n", openpath); + return; + } + /* save file pointer to temporary pointer */ + file->fp_tmp = file->fp; + file->fp_tag_tmp = file->fp_tag; + + /* open new swap file */ + openfile_(file, time, msg); +} + + +/* close old swap file -------------------------------------------------------*/ +void swapclose(file_t *file) +{ + tracet(3, "swapclose: fp_tmp=%d\n", file->fp_tmp); + if (file->fp_tmp) fclose(file->fp_tmp); + if (file->fp_tag_tmp) fclose(file->fp_tag_tmp); + file->fp_tmp = file->fp_tag_tmp = nullptr; +} + + +/* get state file ------------------------------------------------------------*/ +int statefile(file_t *file) +{ + return file ? 2 : 0; +} + + +/* read file -----------------------------------------------------------------*/ +int readfile(file_t *file, unsigned char *buff, int nmax, char *msg) +{ + struct timeval tv = {0, 0}; + fd_set rs; + unsigned int t, tick; + int nr = 0; + size_t fpos; + + if (!file) return 0; + tracet(4, "readfile: fp=%d nmax=%d\n", file->fp, nmax); + + if (file->fp == stdin) + { + /* input from stdin */ + FD_ZERO(&rs); + FD_SET(0, &rs); + if (!select(1, &rs, nullptr, nullptr, &tv)) return 0; + if ((nr = read(0, buff, nmax)) < 0) return 0; + return nr; + } + if (file->fp_tag) + { + if (file->repmode) + { /* slave */ + t = (tick_master + file->offset); + } + else + { /* master */ + t = static_cast((tickget() - file->tick) * file->speed + file->start * 1000.0); + } + for (;;) + { /* seek file position */ + if (fread(&tick, sizeof(tick), 1, file->fp_tag) < 1 || + fread(&fpos, sizeof(fpos), 1, file->fp_tag) < 1) + { + if (fseek(file->fp, 0, SEEK_END) != 0) trace(1, "fseek error"); + sprintf(msg, "end"); + break; + } + if (file->repmode || file->speed > 0.0) + { + if (static_cast(tick - t) < 1) continue; + } + if (!file->repmode) tick_master = tick; + + sprintf(msg, "T%+.1fs", static_cast(tick) < 0 ? 0.0 : static_cast(tick) / 1000.0); + + if (static_cast(fpos - file->fpos) >= nmax) + { + if (fseek(file->fp, fpos, SEEK_SET) != 0) trace(1, "Error fseek"); + file->fpos = fpos; + return 0; + } + nmax = static_cast(fpos - file->fpos); + + if (file->repmode || file->speed > 0.0) + { + if (fseek(file->fp_tag, -static_cast(sizeof(tick) + sizeof(fpos)), SEEK_CUR) != 0) trace(1, "Error fseek"); + } + break; + } + } + if (nmax > 0) + { + nr = fread(buff, 1, nmax, file->fp); + file->fpos += nr; + if (nr <= 0) sprintf(msg, "end"); + } + tracet(5, "readfile: fp=%d nr=%d fpos=%d\n", file->fp, nr, file->fpos); + return nr; +} + + +/* write file ----------------------------------------------------------------*/ +int writefile(file_t *file, unsigned char *buff, int n, char *msg) +{ + gtime_t wtime; + unsigned int ns, tick = tickget(); + int week1, week2; + double tow1, tow2, intv; + size_t fpos, fpos_tmp; + + if (!file) return 0; + tracet(3, "writefile: fp=%d n=%d\n", file->fp, n); + + wtime = utc2gpst(timeget()); /* write time in gpst */ + + /* swap writing file */ + if (file->swapintv > 0.0 && file->wtime.time != 0) + { + intv = file->swapintv * 3600.0; + tow1 = time2gpst(file->wtime, &week1); + tow2 = time2gpst(wtime, &week2); + tow2 += 604800.0 * (week2 - week1); + + /* open new swap file */ + if (floor((tow1 + fswapmargin) / intv) < floor((tow2 + fswapmargin) / intv)) + { + swapfile(file, timeadd(wtime, fswapmargin), msg); + } + /* close old swap file */ + if (floor((tow1 - fswapmargin) / intv) < floor((tow2 - fswapmargin) / intv)) + { + swapclose(file); + } + } + if (!file->fp) return 0; + + ns = fwrite(buff, 1, n, file->fp); + fpos = ftell(file->fp); + fflush(file->fp); + file->wtime = wtime; + + if (file->fp_tmp) + { + fwrite(buff, 1, n, file->fp_tmp); + fpos_tmp = ftell(file->fp_tmp); + fflush(file->fp_tmp); + } + if (file->fp_tag) + { + tick -= file->tick; + fwrite(&tick, 1, sizeof(tick), file->fp_tag); + fwrite(&fpos, 1, sizeof(fpos), file->fp_tag); + fflush(file->fp_tag); + + if (file->fp_tag_tmp) + { + fwrite(&tick, 1, sizeof(tick), file->fp_tag_tmp); + fwrite(&fpos_tmp, 1, sizeof(fpos_tmp), file->fp_tag_tmp); + fflush(file->fp_tag_tmp); + } + } + tracet(5, "writefile: fp=%d ns=%d tick=%5d fpos=%d\n", file->fp, ns, tick, fpos); + + return static_cast(ns); +} + + +/* sync files by time-tag ----------------------------------------------------*/ +void syncfile(file_t *file1, file_t *file2) +{ + if (!file1->fp_tag || !file2->fp_tag) return; + file1->repmode = 0; + file2->repmode = 1; + file2->offset = static_cast(file1->tick_f - file2->tick_f); +} + + +/* decode tcp/ntrip path (path=[user[:passwd]@]addr[:port][/mntpnt[:str]]) ---*/ +void decodetcppath(const char *path, char *addr, char *port, char *user, + char *passwd, char *mntpnt, char *str) +{ + char buff[MAXSTRPATH], *p, *q; + + tracet(4, "decodetcpepath: path=%s\n", path); + + if (port) *port = '\0'; + if (user) *user = '\0'; + if (passwd) *passwd = '\0'; + if (mntpnt) *mntpnt = '\0'; + if (str) *str = '\0'; + + if (strlen(path) < MAXSTRPATH) strcpy(buff, path); + + if (!(p = strrchr(buff, '@'))) p = buff; + + if ((p = strchr(p, '/'))) + { + if ((q = strchr(p + 1, ':'))) + { + *q = '\0'; + if (str) strcpy(str, q + 1); + } + *p = '\0'; + if (mntpnt) strcpy(mntpnt, p + 1); + } + if ((p = strrchr(buff, '@'))) + { + *p++ = '\0'; + if ((q = strchr(buff, ':'))) + { + *q = '\0'; + if (passwd) strcpy(passwd, q + 1); + } + if (user) strcpy(user, buff); + } + else + p = buff; + + if ((q = strchr(p, ':'))) + { + *q = '\0'; + if (port) strcpy(port, q + 1); + } + if (addr) strcpy(addr, p); +} + + +/* get socket error ----------------------------------------------------------*/ +int errsock(void) { return errno; } + + +/* set socket option ---------------------------------------------------------*/ +int setsock(socket_t sock, char *msg) +{ + int bs = buffsize, mode = 1; + struct timeval tv = {0, 0}; + + tracet(3, "setsock: sock=%d\n", sock); + + if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&tv), sizeof(tv)) == -1 || + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast(&tv), sizeof(tv)) == -1) + { + sprintf(msg, "sockopt error: notimeo"); + tracet(1, "setsock: setsockopt error 1 sock=%d err=%d\n", sock, errsock()); + closesocket(sock); + return 0; + } + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&bs), sizeof(bs)) == -1 || + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&bs), sizeof(bs)) == -1) + { + tracet(1, "setsock: setsockopt error 2 sock=%d err=%d bs=%d\n", sock, errsock(), bs); + sprintf(msg, "sockopt error: bufsiz"); + } + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&mode), sizeof(mode)) == -1) + { + tracet(1, "setsock: setsockopt error 3 sock=%d err=%d\n", sock, errsock()); + sprintf(msg, "sockopt error: nodelay"); + } + return 1; +} + + +/* non-block accept ----------------------------------------------------------*/ +socket_t accept_nb(socket_t sock, struct sockaddr *addr, socklen_t *len) +{ + struct timeval tv = {0, 0}; + fd_set rs; + FD_ZERO(&rs); + FD_SET(sock, &rs); + if (!select(sock + 1, &rs, nullptr, nullptr, &tv)) return 0; + return accept(sock, addr, len); +} + + +/* non-block connect ---------------------------------------------------------*/ +int connect_nb(socket_t sock, struct sockaddr *addr, socklen_t len) +{ + struct timeval tv = {0, 0}; + fd_set rs, ws; + int err, flag; + + flag = fcntl(sock, F_GETFL, 0); + if (fcntl(sock, F_SETFL, flag | O_NONBLOCK) == -1) trace(1, "fcntl error"); + if (connect(sock, addr, len) == -1) + { + err = errsock(); + if (err != EISCONN && err != EINPROGRESS && err != EALREADY) return -1; + FD_ZERO(&rs); + FD_SET(sock, &rs); + ws = rs; + if (select(sock + 1, &rs, &ws, nullptr, &tv) == 0) return 0; + } + return 1; +} + + +/* non-block receive ---------------------------------------------------------*/ +int recv_nb(socket_t sock, unsigned char *buff, int n) +{ + struct timeval tv = {0, 0}; + fd_set rs; + FD_ZERO(&rs); + FD_SET(sock, &rs); + if (!select(sock + 1, &rs, nullptr, nullptr, &tv)) return 0; + return recv(sock, reinterpret_cast(buff), n, 0); +} + + +/* non-block send ------------------------------------------------------------*/ +int send_nb(socket_t sock, unsigned char *buff, int n) +{ + struct timeval tv = {0, 0}; + fd_set ws; + FD_ZERO(&ws); + FD_SET(sock, &ws); + if (!select(sock + 1, nullptr, &ws, nullptr, &tv)) return 0; + return send(sock, reinterpret_cast(buff), n, 0); +} + + +/* generate tcp socket -------------------------------------------------------*/ +int gentcp(tcp_t *tcp, int type, char *msg) +{ + struct hostent *hp; +#ifdef SVR_REUSEADDR + int opt = 1; +#endif + + tracet(3, "gentcp: type=%d\n", type); + + /* generate socket */ + if ((tcp->sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + sprintf(msg, "socket error (%d)", errsock()); + tracet(1, "gentcp: socket error err=%d\n", errsock()); + tcp->state = -1; + return 0; + } + if (!setsock(tcp->sock, msg)) + { + tcp->state = -1; + return 0; + } + memset(&tcp->addr, 0, sizeof(tcp->addr)); + tcp->addr.sin_family = AF_INET; + tcp->addr.sin_port = htons(tcp->port); + + if (type == 0) + { /* server socket */ + +#ifdef SVR_REUSEADDR + /* multiple-use of server socket */ + setsockopt(tcp->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, + sizeof(opt)); +#endif + if (bind(tcp->sock, reinterpret_cast(&tcp->addr), sizeof(tcp->addr)) == -1) + { + sprintf(msg, "bind error (%d) : %d", errsock(), tcp->port); + tracet(1, "gentcp: bind error port=%d err=%d\n", tcp->port, errsock()); + closesocket(tcp->sock); + tcp->state = -1; + return 0; + } + listen(tcp->sock, 5); + } + else + { /* client socket */ + if (!(hp = gethostbyname(tcp->saddr))) + { + sprintf(msg, "address error (%s)", tcp->saddr); + tracet(1, "gentcp: gethostbyname error addr=%s err=%d\n", tcp->saddr, errsock()); + closesocket(tcp->sock); + tcp->state = 0; + tcp->tcon = ticonnect; + tcp->tdis = tickget(); + return 0; + } + memcpy(&tcp->addr.sin_addr, hp->h_addr, hp->h_length); + } + tcp->state = 1; + tcp->tact = tickget(); + tracet(5, "gentcp: exit sock=%d\n", tcp->sock); + return 1; +} + + +/* disconnect tcp ------------------------------------------------------------*/ +void discontcp(tcp_t *tcp, int tcon) +{ + tracet(3, "discontcp: sock=%d tcon=%d\n", tcp->sock, tcon); + closesocket(tcp->sock); + tcp->state = 0; + tcp->tcon = tcon; + tcp->tdis = tickget(); +} + + +/* open tcp server -----------------------------------------------------------*/ +tcpsvr_t *opentcpsvr(const char *path, char *msg) +{ + tcpsvr_t *tcpsvr, tcpsvr0; // = {{0}}; + char port[256] = ""; + tcpsvr0 = {{0, {0}, 0, {0, 0, 0, {0}}, 0, 0, 0, 0}, {{0, {0}, 0, {0, 0, 0, {0}}, 0, 0, 0, 0}}}; + tracet(3, "opentcpsvr: path=%s\n", path); + + if (!(tcpsvr = static_cast(malloc(sizeof(tcpsvr_t))))) return nullptr; + *tcpsvr = tcpsvr0; + decodetcppath(path, tcpsvr->svr.saddr, port, nullptr, nullptr, nullptr, nullptr); + if (sscanf(port, "%d", &tcpsvr->svr.port) < 1) + { + sprintf(msg, "port error: %s", port); + tracet(1, "opentcpsvr: port error port=%s\n", port); + free(tcpsvr); + return nullptr; + } + if (!gentcp(&tcpsvr->svr, 0, msg)) + { + free(tcpsvr); + return nullptr; + } + tcpsvr->svr.tcon = 0; + return tcpsvr; +} + + +/* close tcp server ----------------------------------------------------------*/ +void closetcpsvr(tcpsvr_t *tcpsvr) +{ + int i; + tracet(3, "closetcpsvr:\n"); + for (i = 0; i < MAXCLI; i++) + { + if (tcpsvr->cli[i].state) closesocket(tcpsvr->cli[i].sock); + } + closesocket(tcpsvr->svr.sock); + free(tcpsvr); +} + + +/* update tcp server ---------------------------------------------------------*/ +void updatetcpsvr(tcpsvr_t *tcpsvr, char *msg) +{ + char saddr[256] = ""; + int i, j, n = 0; + + tracet(3, "updatetcpsvr: state=%d\n", tcpsvr->svr.state); + + if (tcpsvr->svr.state == 0) return; + + for (i = 0; i < MAXCLI; i++) + { + if (tcpsvr->cli[i].state) continue; + for (j = i + 1; j < MAXCLI; j++) + { + if (!tcpsvr->cli[j].state) continue; + tcpsvr->cli[i] = tcpsvr->cli[j]; + tcpsvr->cli[j].state = 0; + break; + } + } + for (i = 0; i < MAXCLI; i++) + { + if (!tcpsvr->cli[i].state) continue; + strcpy(saddr, tcpsvr->cli[i].saddr); + n++; + } + if (n == 0) + { + tcpsvr->svr.state = 1; + sprintf(msg, "waiting..."); + return; + } + tcpsvr->svr.state = 2; + if (n == 1) + sprintf(msg, "%s", saddr); + else + sprintf(msg, "%d clients", n); +} + + +/* accept client connection --------------------------------------------------*/ +int accsock(tcpsvr_t *tcpsvr, char *msg) +{ + struct sockaddr_in addr + { + }; + socket_t sock; + socklen_t len = sizeof(addr); + int i, err; + + tracet(3, "accsock: sock=%d\n", tcpsvr->svr.sock); + + for (i = 0; i < MAXCLI; i++) + if (tcpsvr->cli[i].state == 0) break; + if (i >= MAXCLI) return 0; /* too many client */ + + if ((sock = accept_nb(tcpsvr->svr.sock, reinterpret_cast(&addr), &len)) == -1) + { + err = errsock(); + sprintf(msg, "accept error (%d)", err); + tracet(1, "accsock: accept error sock=%d err=%d\n", tcpsvr->svr.sock, err); + closesocket(tcpsvr->svr.sock); + tcpsvr->svr.state = 0; + return 0; + } + if (sock == 0) return 0; + + tcpsvr->cli[i].sock = sock; + if (!setsock(tcpsvr->cli[i].sock, msg)) return 0; + memcpy(&tcpsvr->cli[i].addr, &addr, sizeof(addr)); + if (strlen(inet_ntoa(addr.sin_addr)) < 256) strcpy(tcpsvr->cli[i].saddr, inet_ntoa(addr.sin_addr)); + sprintf(msg, "%s", tcpsvr->cli[i].saddr); + tracet(2, "accsock: connected sock=%d addr=%s\n", tcpsvr->cli[i].sock, tcpsvr->cli[i].saddr); + tcpsvr->cli[i].state = 2; + tcpsvr->cli[i].tact = tickget(); + return 1; +} + + +/* wait socket accept --------------------------------------------------------*/ +int waittcpsvr(tcpsvr_t *tcpsvr, char *msg) +{ + tracet(4, "waittcpsvr: sock=%d state=%d\n", tcpsvr->svr.sock, tcpsvr->svr.state); + if (tcpsvr->svr.state <= 0) return 0; + while (accsock(tcpsvr, msg)) + ; + updatetcpsvr(tcpsvr, msg); + return tcpsvr->svr.state == 2; +} + + +/* read tcp server -----------------------------------------------------------*/ +int readtcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg) +{ + int nr, err; + + tracet(4, "readtcpsvr: state=%d n=%d\n", tcpsvr->svr.state, n); + + if (!waittcpsvr(tcpsvr, msg) || tcpsvr->cli[0].state != 2) return 0; + + if ((nr = recv_nb(tcpsvr->cli[0].sock, buff, n)) == -1) + { + err = errsock(); + tracet(1, "readtcpsvr: recv error sock=%d err=%d\n", tcpsvr->cli[0].sock, err); + sprintf(msg, "recv error (%d)", err); + discontcp(&tcpsvr->cli[0], ticonnect); + updatetcpsvr(tcpsvr, msg); + return 0; + } + if (nr > 0) tcpsvr->cli[0].tact = tickget(); + tracet(5, "readtcpsvr: exit sock=%d nr=%d\n", tcpsvr->cli[0].sock, nr); + return nr; +} + + +/* write tcp server ----------------------------------------------------------*/ +int writetcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg) +{ + int i, ns = 0, err; + + tracet(3, "writetcpsvr: state=%d n=%d\n", tcpsvr->svr.state, n); + + if (!waittcpsvr(tcpsvr, msg)) return 0; + + for (i = 0; i < MAXCLI; i++) + { + if (tcpsvr->cli[i].state != 2) continue; + + if ((ns = send_nb(tcpsvr->cli[i].sock, buff, n)) == -1) + { + err = errsock(); + tracet(1, "writetcpsvr: send error i=%d sock=%d err=%d\n", i, tcpsvr->cli[i].sock, err); + sprintf(msg, "send error (%d)", err); + discontcp(&tcpsvr->cli[i], ticonnect); + updatetcpsvr(tcpsvr, msg); + return 0; + } + if (ns > 0) tcpsvr->cli[i].tact = tickget(); + tracet(5, "writetcpsvr: send i=%d ns=%d\n", i, ns); + } + return ns; +} + + +/* get state tcp server ------------------------------------------------------*/ +int statetcpsvr(tcpsvr_t *tcpsvr) +{ + return tcpsvr ? tcpsvr->svr.state : 0; +} + + +/* connect server ------------------------------------------------------------*/ +int consock(tcpcli_t *tcpcli, char *msg) +{ + int stat, err; + + tracet(3, "consock: sock=%d\n", tcpcli->svr.sock); + + /* wait re-connect */ + if (tcpcli->svr.tcon < 0 || (tcpcli->svr.tcon > 0 && + static_cast(tickget() - tcpcli->svr.tdis) < tcpcli->svr.tcon)) + { + return 0; + } + /* non-block connect */ + if ((stat = connect_nb(tcpcli->svr.sock, reinterpret_cast(&tcpcli->svr.addr), + sizeof(tcpcli->svr.addr))) == -1) + { + err = errsock(); + sprintf(msg, "connect error (%d)", err); + tracet(1, "consock: connect error sock=%d err=%d\n", tcpcli->svr.sock, err); + closesocket(tcpcli->svr.sock); + tcpcli->svr.state = 0; + return 0; + } + if (!stat) + { /* not connect */ + sprintf(msg, "connecting..."); + return 0; + } + sprintf(msg, "%s", tcpcli->svr.saddr); + tracet(2, "consock: connected sock=%d addr=%s\n", tcpcli->svr.sock, tcpcli->svr.saddr); + tcpcli->svr.state = 2; + tcpcli->svr.tact = tickget(); + return 1; +} + + +/* open tcp client -----------------------------------------------------------*/ +tcpcli_t *opentcpcli(const char *path, char *msg) +{ + tcpcli_t *tcpcli, tcpcli0; // = {{0}}; + char port[256] = ""; + tcpcli0 = {{0, {0}, 0, {0, 0, 0, {0}}, 0, 0, 0, 0}, 0, 0}; + + tracet(3, "opentcpcli: path=%s\n", path); + + if (!(tcpcli = static_cast(malloc(sizeof(tcpcli_t))))) return nullptr; + *tcpcli = tcpcli0; + decodetcppath(path, tcpcli->svr.saddr, port, nullptr, nullptr, nullptr, nullptr); + if (sscanf(port, "%d", &tcpcli->svr.port) < 1) + { + sprintf(msg, "port error: %s", port); + tracet(1, "opentcp: port error port=%s\n", port); + free(tcpcli); + return nullptr; + } + tcpcli->svr.tcon = 0; + tcpcli->toinact = toinact; + tcpcli->tirecon = ticonnect; + return tcpcli; +} + + +/* close tcp client ----------------------------------------------------------*/ +void closetcpcli(tcpcli_t *tcpcli) +{ + tracet(3, "closetcpcli: sock=%d\n", tcpcli->svr.sock); + closesocket(tcpcli->svr.sock); + free(tcpcli); +} + + +/* wait socket connect -------------------------------------------------------*/ +int waittcpcli(tcpcli_t *tcpcli, char *msg) +{ + tracet(4, "waittcpcli: sock=%d state=%d\n", tcpcli->svr.sock, tcpcli->svr.state); + + if (tcpcli->svr.state < 0) return 0; + + if (tcpcli->svr.state == 0) + { /* close */ + if (!gentcp(&tcpcli->svr, 1, msg)) return 0; + } + if (tcpcli->svr.state == 1) + { /* wait */ + if (!consock(tcpcli, msg)) return 0; + } + if (tcpcli->svr.state == 2) + { /* connect */ + if (tcpcli->toinact > 0 && + static_cast(tickget() - tcpcli->svr.tact) > tcpcli->toinact) + { + sprintf(msg, "timeout"); + tracet(2, "waittcpcli: inactive timeout sock=%d\n", tcpcli->svr.sock); + discontcp(&tcpcli->svr, tcpcli->tirecon); + return 0; + } + } + return 1; +} + + +/* read tcp client -----------------------------------------------------------*/ +int readtcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg) +{ + int nr, err; + + tracet(4, "readtcpcli: sock=%d state=%d n=%d\n", tcpcli->svr.sock, tcpcli->svr.state, n); + + if (!waittcpcli(tcpcli, msg)) return 0; + + if ((nr = recv_nb(tcpcli->svr.sock, buff, n)) == -1) + { + err = errsock(); + tracet(1, "readtcpcli: recv error sock=%d err=%d\n", tcpcli->svr.sock, err); + sprintf(msg, "recv error (%d)", err); + discontcp(&tcpcli->svr, tcpcli->tirecon); + return 0; + } + if (nr > 0) tcpcli->svr.tact = tickget(); + tracet(5, "readtcpcli: exit sock=%d nr=%d\n", tcpcli->svr.sock, nr); + return nr; +} + + +/* write tcp client ----------------------------------------------------------*/ +int writetcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg) +{ + int ns, err; + + tracet(3, "writetcpcli: sock=%d state=%d n=%d\n", tcpcli->svr.sock, tcpcli->svr.state, n); + + if (!waittcpcli(tcpcli, msg)) return 0; + + if ((ns = send_nb(tcpcli->svr.sock, buff, n)) == -1) + { + err = errsock(); + tracet(1, "writetcp: send error sock=%d err=%d\n", tcpcli->svr.sock, err); + sprintf(msg, "send error (%d)", err); + discontcp(&tcpcli->svr, tcpcli->tirecon); + return 0; + } + if (ns > 0) tcpcli->svr.tact = tickget(); + tracet(5, "writetcpcli: exit sock=%d ns=%d\n", tcpcli->svr.sock, ns); + return ns; +} + + +/* get state tcp client ------------------------------------------------------*/ +int statetcpcli(tcpcli_t *tcpcli) +{ + return tcpcli ? tcpcli->svr.state : 0; +} + + +/* base64 encoder ------------------------------------------------------------*/ +int encbase64(char *str, const unsigned char *byte, int n) +{ + const char table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int i, j, k, b; + + tracet(4, "encbase64: n=%d\n", n); + + for (i = j = 0; i / 8 < n;) + { + for (k = b = 0; k < 6; k++, i++) + { + b <<= 1; + if (i / 8 < n) b |= (byte[i / 8] >> (7 - i % 8)) & 0x1; + } + str[j++] = table[b]; + } + while (j & 0x3) str[j++] = '='; + str[j] = '\0'; + tracet(5, "encbase64: str=%s\n", str); + return j; +} + + +/* send ntrip server request -------------------------------------------------*/ +int reqntrip_s(ntrip_t *ntrip, char *msg) +{ + char buff[256 + NTRIP_MAXSTR], *p = buff; + + tracet(3, "reqntrip_s: state=%d\n", ntrip->state); + + p += snprintf(p, 256 + NTRIP_MAXSTR, "SOURCE %s %s\r\n", ntrip->passwd, ntrip->mntpnt); + p += sprintf(p, "Source-Agent: NTRIP %s\r\n", NTRIP_AGENT); + p += sprintf(p, "STR: %s\r\n", ntrip->str); + p += sprintf(p, "\r\n"); + + if (writetcpcli(ntrip->tcp, reinterpret_cast(buff), p - buff, msg) != p - buff) return 0; + + tracet(2, "reqntrip_s: send request state=%d ns=%d\n", ntrip->state, p - buff); + tracet(5, "reqntrip_s: n=%d buff=\n%s\n", p - buff, buff); + ntrip->state = 1; + return 1; +} + + +/* send ntrip client request -------------------------------------------------*/ +int reqntrip_c(ntrip_t *ntrip, char *msg) +{ + char buff[1024], user[512], *p = buff; + + tracet(3, "reqntrip_c: state=%d\n", ntrip->state); + + p += sprintf(p, "GET %s/%s HTTP/1.0\r\n", ntrip->url, ntrip->mntpnt); + p += sprintf(p, "User-Agent: NTRIP %s\r\n", NTRIP_AGENT); + + if (!*ntrip->user) + { + p += sprintf(p, "Accept: */*\r\n"); + p += sprintf(p, "Connection: close\r\n"); + } + else + { + sprintf(user, "%s:%s", ntrip->user, ntrip->passwd); + p += sprintf(p, "Authorization: Basic "); + p += encbase64(p, reinterpret_cast(user), strlen(user)); + p += sprintf(p, "\r\n"); + } + p += sprintf(p, "\r\n"); + + if (writetcpcli(ntrip->tcp, reinterpret_cast(buff), p - buff, msg) != p - buff) return 0; + + tracet(2, "reqntrip_c: send request state=%d ns=%d\n", ntrip->state, p - buff); + tracet(5, "reqntrip_c: n=%d buff=\n%s\n", p - buff, buff); + ntrip->state = 1; + return 1; +} + + +/* test ntrip server response ------------------------------------------------*/ +int rspntrip_s(ntrip_t *ntrip, char *msg) +{ + int i, nb; + char *p, *q; + + tracet(3, "rspntrip_s: state=%d nb=%d\n", ntrip->state, ntrip->nb); + ntrip->buff[ntrip->nb] = '0'; + tracet(5, "rspntrip_s: n=%d buff=\n%s\n", ntrip->nb, ntrip->buff); + + if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_OK_SVR))) + { /* ok */ + q = reinterpret_cast(ntrip->buff); + p += strlen(NTRIP_RSP_OK_SVR); + ntrip->nb -= p - q; + for (i = 0; i < ntrip->nb; i++) *q++ = *p++; + ntrip->state = 2; + sprintf(msg, "%s/%s", ntrip->tcp->svr.saddr, ntrip->mntpnt); + tracet(2, "rspntrip_s: response ok nb=%d\n", ntrip->nb); + return 1; + } + if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_ERROR))) + { /* error */ + nb = ntrip->nb < MAXSTATMSG ? ntrip->nb : MAXSTATMSG; + // strncpy(msg, (char *)ntrip->buff, nb); This line triggers a warning. Replaced by; + std::string s_aux(reinterpret_cast(ntrip->buff)); + s_aux.resize(nb, '\0'); + for (int i = 0; i < nb; i++) msg[i] = s_aux[i]; + + msg[nb] = 0; + tracet(1, "rspntrip_s: %s nb=%d\n", msg, ntrip->nb); + ntrip->nb = 0; + ntrip->buff[0] = '\0'; + ntrip->state = 0; + discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); + } + else if (ntrip->nb >= NTRIP_MAXRSP) + { /* buffer overflow */ + sprintf(msg, "response overflow"); + tracet(1, "rspntrip_s: response overflow nb=%d\n", ntrip->nb); + ntrip->nb = 0; + ntrip->buff[0] = '\0'; + ntrip->state = 0; + discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); + } + tracet(5, "rspntrip_s: exit state=%d nb=%d\n", ntrip->state, ntrip->nb); + return 0; +} + + +/* test ntrip client response ------------------------------------------------*/ +int rspntrip_c(ntrip_t *ntrip, char *msg) +{ + int i; + char *p, *q; + + tracet(3, "rspntrip_c: state=%d nb=%d\n", ntrip->state, ntrip->nb); + ntrip->buff[ntrip->nb] = '0'; + tracet(5, "rspntrip_c: n=%d buff=\n%s\n", ntrip->nb, ntrip->buff); + + if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_OK_CLI))) + { /* ok */ + q = reinterpret_cast(ntrip->buff); + p += strlen(NTRIP_RSP_OK_CLI); + ntrip->nb -= p - q; + for (i = 0; i < ntrip->nb; i++) *q++ = *p++; + ntrip->state = 2; + sprintf(msg, "%s/%s", ntrip->tcp->svr.saddr, ntrip->mntpnt); + tracet(2, "rspntrip_c: response ok nb=%d\n", ntrip->nb); + return 1; + } + if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_SRCTBL))) + { /* source table */ + if (!*ntrip->mntpnt) + { /* source table request */ + ntrip->state = 2; + sprintf(msg, "source table received"); + tracet(2, "rspntrip_c: receive source table nb=%d\n", ntrip->nb); + return 1; + } + sprintf(msg, "no mountp. reconnect..."); + tracet(2, "rspntrip_c: no mount point nb=%d\n", ntrip->nb); + ntrip->nb = 0; + ntrip->buff[0] = '\0'; + ntrip->state = 0; + discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); + } + else if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_HTTP))) + { /* http response */ + if ((q = strchr(p, '\r'))) + *q = '\0'; + else + ntrip->buff[128] = '\0'; + strcpy(msg, p); + tracet(1, "rspntrip_s: %s nb=%d\n", msg, ntrip->nb); + ntrip->nb = 0; + ntrip->buff[0] = '\0'; + ntrip->state = 0; + discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); + } + else if (ntrip->nb >= NTRIP_MAXRSP) + { /* buffer overflow */ + sprintf(msg, "response overflow"); + tracet(1, "rspntrip_s: response overflow nb=%d\n", ntrip->nb); + ntrip->nb = 0; + ntrip->buff[0] = '\0'; + ntrip->state = 0; + discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); + } + tracet(5, "rspntrip_c: exit state=%d nb=%d\n", ntrip->state, ntrip->nb); + return 0; +} + + +/* wait ntrip request/response -----------------------------------------------*/ +int waitntrip(ntrip_t *ntrip, char *msg) +{ + int n; + char *p; + + tracet(4, "waitntrip: state=%d nb=%d\n", ntrip->state, ntrip->nb); + + if (ntrip->state < 0) return 0; /* error */ + + if (ntrip->tcp->svr.state < 2) ntrip->state = 0; /* tcp disconnected */ + + if (ntrip->state == 0) + { /* send request */ + if (!(ntrip->type == 0 ? reqntrip_s(ntrip, msg) : reqntrip_c(ntrip, msg))) + { + return 0; + } + tracet(2, "waitntrip: state=%d nb=%d\n", ntrip->state, ntrip->nb); + } + if (ntrip->state == 1) + { /* read response */ + p = reinterpret_cast(ntrip->buff) + ntrip->nb; + if ((n = readtcpcli(ntrip->tcp, reinterpret_cast(p), NTRIP_MAXRSP - ntrip->nb - 1, msg)) == 0) + { + tracet(5, "waitntrip: readtcp n=%d\n", n); + return 0; + } + ntrip->nb += n; + ntrip->buff[ntrip->nb] = '\0'; + + /* wait response */ + return ntrip->type == 0 ? rspntrip_s(ntrip, msg) : rspntrip_c(ntrip, msg); + } + return 1; +} + + +/* open ntrip ----------------------------------------------------------------*/ +ntrip_t *openntrip(const char *path, int type, char *msg) +{ + ntrip_t *ntrip; + int i; + char addr[256] = "", port[256] = "", tpath[MAXSTRPATH]; + + tracet(3, "openntrip: path=%s type=%d\n", path, type); + + if (!(ntrip = static_cast(malloc(sizeof(ntrip_t))))) return nullptr; + + ntrip->state = 0; + ntrip->type = type; /* 0:server, 1:client */ + ntrip->nb = 0; + ntrip->url[0] = '\0'; + ntrip->mntpnt[0] = ntrip->user[0] = ntrip->passwd[0] = ntrip->str[0] = '\0'; + for (i = 0; i < NTRIP_MAXRSP; i++) ntrip->buff[i] = 0; + + /* decode tcp/ntrip path */ + decodetcppath(path, addr, port, ntrip->user, ntrip->passwd, ntrip->mntpnt, + ntrip->str); + + /* use default port if no port specified */ + if (!*port) + { + sprintf(port, "%d", type ? NTRIP_CLI_PORT : NTRIP_SVR_PORT); + } + sprintf(tpath, "%s:%s", addr, port); + + /* ntrip access via proxy server */ + if (*proxyaddr) + { + // sprintf(ntrip->url, "http://%s", tpath); This line triggers a warning. Replaced by: + std::string s_aux = "http://" + std::string(tpath); + int n = s_aux.length(); + if (n < 256) + for (int k = 0; k < n; k++) ntrip->url[k] = s_aux[k]; + strcpy(tpath, proxyaddr); + } + /* open tcp client stream */ + if (!(ntrip->tcp = opentcpcli(tpath, msg))) + { + tracet(1, "openntrip: opentcp error\n"); + free(ntrip); + return nullptr; + } + return ntrip; +} + + +/* close ntrip ---------------------------------------------------------------*/ +void closentrip(ntrip_t *ntrip) +{ + tracet(3, "closentrip: state=%d\n", ntrip->state); + closetcpcli(ntrip->tcp); + free(ntrip); +} + + +/* read ntrip ----------------------------------------------------------------*/ +int readntrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg) +{ + int nb; + + tracet(4, "readntrip: n=%d\n", n); + + if (!waitntrip(ntrip, msg)) return 0; + if (ntrip->nb > 0) + { /* read response buffer first */ + nb = ntrip->nb <= n ? ntrip->nb : n; + memcpy(buff, ntrip->buff + ntrip->nb - nb, nb); + ntrip->nb = 0; + return nb; + } + return readtcpcli(ntrip->tcp, buff, n, msg); +} + + +/* write ntrip ---------------------------------------------------------------*/ +int writentrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg) +{ + tracet(3, "writentrip: n=%d\n", n); + + if (!waitntrip(ntrip, msg)) return 0; + return writetcpcli(ntrip->tcp, buff, n, msg); +} + + +/* get state ntrip -----------------------------------------------------------*/ +int statentrip(ntrip_t *ntrip) +{ + return !ntrip ? 0 : (ntrip->state == 0 ? ntrip->tcp->svr.state : ntrip->state); +} + + +/* decode ftp path ----------------------------------------------------------*/ +void decodeftppath(const char *path, char *addr, char *file, char *user, + char *passwd, int *topts) +{ + char buff[MAXSTRPATH], *p, *q; + + tracet(4, "decodeftpath: path=%s\n", path); + + if (user) *user = '\0'; + if (passwd) *passwd = '\0'; + if (topts) + { + topts[0] = 0; /* time offset in path (s) */ + topts[1] = 3600; /* download interval (s) */ + topts[2] = 0; /* download time offset (s) */ + topts[3] = 0; /* retry interval (s) (0: no retry) */ + } + if (strlen(path) < MAXSTRPATH) strcpy(buff, path); + + if ((p = strchr(buff, '/'))) + { + if ((q = strstr(p + 1, "::"))) + { + *q = '\0'; + if (topts) sscanf(q + 2, "T=%d, %d, %d, %d", topts, topts + 1, topts + 2, topts + 3); + } + strcpy(file, p + 1); + *p = '\0'; + } + else + file[0] = '\0'; + + if ((p = strrchr(buff, '@'))) + { + *p++ = '\0'; + if ((q = strchr(buff, ':'))) + { + *q = '\0'; + if (passwd) strcpy(passwd, q + 1); + } + if (user) strcpy(user, buff); + } + else + p = buff; + + strcpy(addr, p); +} + + +/* next download time --------------------------------------------------------*/ +gtime_t nextdltime(const int *topts, int stat) +{ + gtime_t time; + double tow; + int week, tint; + + tracet(3, "nextdltime: topts=%d %d %d %d stat=%d\n", topts[0], topts[1], + topts[2], topts[3], stat); + + /* current time (gpst) */ + time = utc2gpst(timeget()); + tow = time2gpst(time, &week); + + /* next retry time */ + if (stat == 0 && topts[3] > 0) + { + tow = (floor((tow - topts[2]) / topts[3]) + 1.0) * topts[3] + topts[2]; + return gpst2time(week, tow); + } + /* next interval time */ + tint = topts[1] <= 0 ? 3600 : topts[1]; + tow = (floor((tow - topts[2]) / tint) + 1.0) * tint + topts[2]; + time = gpst2time(week, tow); + + return time; +} + + +/* ftp thread ----------------------------------------------------------------*/ +void *ftpthread(void *arg) +{ + auto *ftp = static_cast(arg); + FILE *fp; + gtime_t time; + char remote[1024], local[1024], tmpfile[1024], errfile[1024], *p; + char cmd[2048], env[1024] = "", opt[1024], *proxyopt = (char *)"", *proto; + int ret; + + tracet(3, "ftpthread:\n"); + + if (!*localdir) + { + tracet(1, "no local directory\n"); + ftp->error = 11; + ftp->state = 3; + return nullptr; + } + /* replace keyword in file path and local path */ + time = timeadd(utc2gpst(timeget()), ftp->topts[0]); + reppath(ftp->file, remote, time, "", ""); + + if ((p = strrchr(remote, '/'))) + p++; + else + p = remote; + // sprintf(local, "%s%c%s", localdir, FILEPATHSEP, p); This line triggers a warning. Replaced by: + std::string s_aux = std::string(localdir) + std::to_string(FILEPATHSEP) + std::string(p); + int n = s_aux.length(); + if (n < 1024) + for (int i = 0; i < n; i++) local[i] = s_aux[i]; + + // sprintf(errfile, "%s.err", local); This line triggers a warning. Replaced by: + std::string s_aux2 = std::string(local) + ".err"; + n = s_aux2.length(); + if (n < 1024) + for (int i = 0; i < n; i++) errfile[i] = s_aux2[i]; + + /* if local file exist, skip download */ + strcpy(tmpfile, local); + if ((p = strrchr(tmpfile, '.')) && + (!strcmp(p, ".z") || !strcmp(p, ".gz") || !strcmp(p, ".zip") || + !strcmp(p, ".Z") || !strcmp(p, ".GZ") || !strcmp(p, ".ZIP"))) + { + *p = '\0'; + } + if ((fp = fopen(tmpfile, "rbe"))) + { + fclose(fp); + strcpy(ftp->local, tmpfile); + tracet(3, "ftpthread: file exists %s\n", ftp->local); + ftp->state = 2; + return nullptr; + } + /* proxy settings for wget (ref [2]) */ + if (*proxyaddr) + { + proto = ftp->proto ? (char *)"http" : (char *)"ftp"; + sprintf(env, "set %s_proxy=http://%s & ", proto, proxyaddr); + proxyopt = (char *)"--proxy=on "; + } + /* download command (ref [2]) */ + if (ftp->proto == 0) + { /* ftp */ + // sprintf(opt, "--ftp-user=%s --ftp-password=%s --glob=off --passive-ftp %s-t 1 -T %d -O \"%s\"", + // ftp->user, ftp->passwd, proxyopt, FTP_TIMEOUT, local); This line triggers a warning. Replaced by: + std::string s_aux = "--ftp-user=" + std::string(ftp->user) + " --ftp-password=" + std::string(ftp->passwd) + + " --glob=off --passive-ftp " + std::string(proxyopt) + "s-t 1 -T " + std::to_string(FTP_TIMEOUT) + + " -O \"" + std::string(local) + "\""; + int k = s_aux.length(); + if (k < 1024) + for (int i = 0; i < k; i++) opt[i] = s_aux[i]; + + // sprintf(cmd, "%s%s %s \"ftp://%s/%s\" 2> \"%s\"\n", env, FTP_CMD, opt, ftp->addr, + // remote, errfile); This line triggers a warning. Replaced by: + std::string s_aux2 = std::string(env) + std::string(FTP_CMD) + " " + std::string(opt) + " " + + "\"ftp://" + std::string(ftp->addr) + "/" + std::string(remote) + "\" 2> \"" + std::string(errfile) + "\"\n"; + k = s_aux2.length(); + for (int i = 0; (i < k) && (i < 1024); i++) cmd[i] = s_aux2[i]; + } + else + { /* http */ + // sprintf(opt, "%s-t 1 -T %d -O \"%s\"", proxyopt, FTP_TIMEOUT, local); This line triggers a warning. Replaced by: + std::string s_aux = std::string(proxyopt) + " -t 1 -T " + std::to_string(FTP_TIMEOUT) + " -O \"" + std::string(local) + "\""; + int l = s_aux.length(); + for (int i = 0; (i < l) && (i < 1024); i++) opt[i] = s_aux[i]; + + // sprintf(cmd, "%s%s %s \"http://%s/%s\" 2> \"%s\"\n", env, FTP_CMD, opt, ftp->addr, + // remote, errfile); This line triggers a warning. Replaced by: + std::string s_aux2 = std::string(env) + std::string(FTP_CMD) + " " + std::string(opt) + " " + + "\"http://" + std::string(ftp->addr) + "/" + std::string(remote) + "\" 2> \"" + std::string(errfile) + "\"\n"; + l = s_aux2.length(); + for (int i = 0; (i < l) && (i < 1024); i++) cmd[i] = s_aux2[i]; + } + /* execute download command */ + if ((ret = execcmd(cmd))) + { + if (remove(local) != 0) trace(1, "Error removing file"); + tracet(1, "execcmd error: cmd=%s ret=%d\n", cmd, ret); + ftp->error = ret; + ftp->state = 3; + return nullptr; + } + if (remove(errfile) != 0) trace(1, "Error removing file"); + + /* uncompress downloaded file */ + if ((p = strrchr(local, '.')) && + (!strcmp(p, ".z") || !strcmp(p, ".gz") || !strcmp(p, ".zip") || + !strcmp(p, ".Z") || !strcmp(p, ".GZ") || !strcmp(p, ".ZIP"))) + { + if (rtk_uncompress(local, tmpfile)) + { + if (remove(local) != 0) trace(1, "Error removing file"); + if (strlen(tmpfile) < 1024) strcpy(local, tmpfile); + } + else + { + tracet(1, "file uncompact error: %s\n", local); + ftp->error = 12; + ftp->state = 3; + return nullptr; + } + } + if (strlen(local) < 1024) strcpy(ftp->local, local); + ftp->state = 2; /* ftp completed */ + + tracet(3, "ftpthread: complete cmd=%s\n", cmd); + return nullptr; +} + + +/* open ftp ------------------------------------------------------------------*/ +ftp_t *openftp(const char *path, int type, char *msg) +{ + ftp_t *ftp; + + tracet(3, "openftp: path=%s type=%d\n", path, type); + + msg[0] = '\0'; + + if (!(ftp = static_cast(malloc(sizeof(ftp_t))))) return nullptr; + + ftp->state = 0; + ftp->proto = type; + ftp->error = 0; + ftp->thread = 0; // NOLINT + ftp->local[0] = '\0'; + + /* decode ftp path */ + decodeftppath(path, ftp->addr, ftp->file, ftp->user, ftp->passwd, ftp->topts); + + /* set first download time */ + ftp->tnext = timeadd(timeget(), 10.0); + + return ftp; +} + + +/* close ftp -----------------------------------------------------------------*/ +void closeftp(ftp_t *ftp) +{ + tracet(3, "closeftp: state=%d\n", ftp->state); + + if (ftp->state != 1) free(ftp); +} + + +/* read ftp ------------------------------------------------------------------*/ +int readftp(ftp_t *ftp, unsigned char *buff, int n, char *msg) +{ + gtime_t time; + unsigned char *p, *q; + + tracet(4, "readftp: n=%d\n", n); + + time = utc2gpst(timeget()); + + if (timediff(time, ftp->tnext) < 0.0) + { /* until download time? */ + return 0; + } + if (ftp->state <= 0) + { /* ftp/http not executed? */ + ftp->state = 1; + sprintf(msg, "%s://%s", ftp->proto ? "http" : "ftp", ftp->addr); + + if (pthread_create(&ftp->thread, nullptr, ftpthread, ftp)) + { + tracet(1, "readftp: ftp thread create error\n"); + ftp->state = 3; + strcpy(msg, "ftp thread error"); + return 0; + } + } + if (ftp->state <= 1) return 0; /* ftp/http on going? */ + + if (ftp->state == 3) + { /* ftp error */ + sprintf(msg, "%s error (%d)", ftp->proto ? "http" : "ftp", ftp->error); + + /* set next retry time */ + ftp->tnext = nextdltime(ftp->topts, 0); + ftp->state = 0; + return 0; + } + /* return local file path if ftp completed */ + p = buff; + q = reinterpret_cast(ftp->local); + while (*q && static_cast(p - buff) < n) *p++ = *q++; + p += sprintf(reinterpret_cast(p), "\r\n"); + + /* set next download time */ + ftp->tnext = nextdltime(ftp->topts, 1); + ftp->state = 0; + + strcpy(msg, ""); + + return static_cast(p - buff); +} + + +/* get state ftp -------------------------------------------------------------*/ +int stateftp(ftp_t *ftp) +{ + return !ftp ? 0 : (ftp->state == 0 ? 2 : (ftp->state <= 2 ? 3 : -1)); +} + + +/* initialize stream environment ----------------------------------------------- + * initialize stream environment + * args : none + * return : none + *-----------------------------------------------------------------------------*/ +void strinitcom(void) +{ + tracet(3, "strinitcom:\n"); +} + + +/* initialize stream ----------------------------------------------------------- + * initialize stream struct + * args : stream_t *stream IO stream + * return : none + *-----------------------------------------------------------------------------*/ +void strinit(stream_t *stream) +{ + tracet(3, "strinit:\n"); + + stream->type = 0; + stream->mode = 0; + stream->state = 0; + stream->inb = stream->inr = stream->outb = stream->outr = 0; + stream->tick = stream->tact = stream->inbt = stream->outbt = 0; + initlock(&stream->lock); + stream->port = nullptr; + stream->path[0] = '\0'; + stream->msg[0] = '\0'; +} + + +/* open stream ----------------------------------------------------------------- + * open stream for read or write + * args : stream_t *stream IO stream + * int type I stream type (STR_SERIAL, STR_FILE, STR_TCPSVR, ...) + * int mode I stream mode (STR_MODE_???) + * char *path I stream path (see below) + * return : status (0:error, 1:ok) + * notes : see reference [1] for NTRIP + * STR_FTP/HTTP needs "wget" in command search paths + * + * stream path ([] options): + * + * STR_SERIAL port[:brate[:bsize[:parity[:stopb[:fctr]]]]] + * port = COM?? (windows), tty??? (linuex, omit /dev/) + * brate = bit rate (bps) + * bsize = bit size (7|8) + * parity= parity (n|o|e) + * stopb = stop bits (1|2) + * fctr = flow control (off|rts) + * STR_FILE file_path[::T][::+start][::xseppd][::S=swap] + * ::T = enable time tag + * start = replay start offset (s) + * speed = replay speed factor + * swap = output swap interval (hr) (0: no swap) + * STR_TCPSVR :port + * STR_TCPCLI address:port + * STR_NTRIPSVR user[:passwd]@address[:port]/moutpoint[:string] + * STR_NTRIPCLI [user[:passwd]]@address[:port][/mountpoint] + * STR_FTP [user[:passwd]]@address/file_path[::T=poff[, tint[, toff, tret]]]] + * STR_HTTP address/file_path[::T=poff[, tint[, toff, tret]]]] + * poff = time offset for path extension (s) + * tint = download interval (s) + * toff = download time offset (s) + * tret = download retry interval (s) (0:no retry) + *-----------------------------------------------------------------------------*/ +int stropen(stream_t *stream, int type, int mode, const char *path) +{ + tracet(3, "stropen: type=%d mode=%d path=%s\n", type, mode, path); + + stream->type = type; + stream->mode = mode; + if (strlen(path) < MAXSTRPATH) strcpy(stream->path, path); + stream->inb = stream->inr = stream->outb = stream->outr = 0; + stream->tick = tickget(); + stream->inbt = stream->outbt = 0; + stream->msg[0] = '\0'; + stream->port = nullptr; + switch (type) + { + case STR_SERIAL: + stream->port = openserial(path, mode, stream->msg); + break; + case STR_FILE: + stream->port = openfile(path, mode, stream->msg); + break; + case STR_TCPSVR: + stream->port = opentcpsvr(path, stream->msg); + break; + case STR_TCPCLI: + stream->port = opentcpcli(path, stream->msg); + break; + case STR_NTRIPSVR: + stream->port = openntrip(path, 0, stream->msg); + break; + case STR_NTRIPCLI: + stream->port = openntrip(path, 1, stream->msg); + break; + case STR_FTP: + stream->port = openftp(path, 0, stream->msg); + break; + case STR_HTTP: + stream->port = openftp(path, 1, stream->msg); + break; + default: + stream->state = 0; + return 1; + } + stream->state = !stream->port ? -1 : 1; + return stream->port != nullptr; +} + + +/* close stream ---------------------------------------------------------------- + * close stream + * args : stream_t *stream IO stream + * return : none + *-----------------------------------------------------------------------------*/ +void strclose(stream_t *stream) +{ + tracet(3, "strclose: type=%d mode=%d\n", stream->type, stream->mode); + + if (stream->port) + { + switch (stream->type) + { + case STR_SERIAL: + closeserial(static_cast(stream->port)); + break; + case STR_FILE: + closefile(static_cast(stream->port)); + break; + case STR_TCPSVR: + closetcpsvr(static_cast(stream->port)); + break; + case STR_TCPCLI: + closetcpcli(static_cast(stream->port)); + break; + case STR_NTRIPSVR: + closentrip(static_cast(stream->port)); + break; + case STR_NTRIPCLI: + closentrip(static_cast(stream->port)); + break; + case STR_FTP: + closeftp(static_cast(stream->port)); + break; + case STR_HTTP: + closeftp(static_cast(stream->port)); + break; + } + } + else + { + trace(2, "no port to close stream: type=%d\n", stream->type); + } + stream->type = 0; + stream->mode = 0; + stream->state = 0; + stream->inr = stream->outr = 0; + stream->path[0] = '\0'; + stream->msg[0] = '\0'; + stream->port = nullptr; +} + + +/* sync streams ---------------------------------------------------------------- + * sync time for streams + * args : stream_t *stream1 IO stream 1 + * stream_t *stream2 IO stream 2 + * return : none + * notes : for replay files with time tags + *-----------------------------------------------------------------------------*/ +void strsync(stream_t *stream1, stream_t *stream2) +{ + file_t *file1, *file2; + if (stream1->type != STR_FILE || stream2->type != STR_FILE) return; + file1 = static_cast(stream1->port); + file2 = static_cast(stream2->port); + if (file1 && file2) syncfile(file1, file2); +} + + +/* lock/unlock stream ---------------------------------------------------------- + * lock/unlock stream + * args : stream_t *stream I stream + * return : none + *-----------------------------------------------------------------------------*/ +void strlock(stream_t *stream) { rtk_lock(&stream->lock); } + +void strunlock(stream_t *stream) { rtk_unlock(&stream->lock); } + + +/* read stream ----------------------------------------------------------------- + * read data from stream (unblocked) + * args : stream_t *stream I stream + * unsigned char *buff O data buffer + * int n I maximum data length + * return : read data length + * notes : if no data, return immediately with no data + *-----------------------------------------------------------------------------*/ +int strread(stream_t *stream, unsigned char *buff, int n) +{ + unsigned int tick; + char *msg = stream->msg; + int nr; + + tracet(4, "strread: n=%d\n", n); + + if (!(stream->mode & STR_MODE_R) || !stream->port) return 0; + + strlock(stream); + + switch (stream->type) + { + case STR_SERIAL: + nr = readserial(static_cast(stream->port), buff, n, msg); + break; + case STR_FILE: + nr = readfile(static_cast(stream->port), buff, n, msg); + break; + case STR_TCPSVR: + nr = readtcpsvr(static_cast(stream->port), buff, n, msg); + break; + case STR_TCPCLI: + nr = readtcpcli(static_cast(stream->port), buff, n, msg); + break; + case STR_NTRIPCLI: + nr = readntrip(static_cast(stream->port), buff, n, msg); + break; + case STR_FTP: + nr = readftp(static_cast(stream->port), buff, n, msg); + break; + case STR_HTTP: + nr = readftp(static_cast(stream->port), buff, n, msg); + break; + default: + strunlock(stream); + return 0; + } + stream->inb += nr; + tick = tickget(); + if (nr > 0) stream->tact = tick; + + if (static_cast(tick - stream->tick) >= tirate) + { + stream->inr = (stream->inb - stream->inbt) * 8000 / (tick - stream->tick); + stream->tick = tick; + stream->inbt = stream->inb; + } + strunlock(stream); + return nr; +} + + +/* write stream ---------------------------------------------------------------- + * write data to stream (unblocked) + * args : stream_t *stream I stream + * unsigned char *buff I data buffer + * int n I data length + * return : status (0:error, 1:ok) + * notes : write data to buffer and return immediately + *-----------------------------------------------------------------------------*/ +int strwrite(stream_t *stream, unsigned char *buff, int n) +{ + unsigned int tick; + char *msg = stream->msg; + int ns; + + tracet(3, "strwrite: n=%d\n", n); + + if (!(stream->mode & STR_MODE_W) || !stream->port) return 0; + + strlock(stream); + + switch (stream->type) + { + case STR_SERIAL: + ns = writeserial(static_cast(stream->port), buff, n, msg); + break; + case STR_FILE: + ns = writefile(static_cast(stream->port), buff, n, msg); + break; + case STR_TCPSVR: + ns = writetcpsvr(static_cast(stream->port), buff, n, msg); + break; + case STR_TCPCLI: + ns = writetcpcli(static_cast(stream->port), buff, n, msg); + break; + case STR_NTRIPCLI: + case STR_NTRIPSVR: + ns = writentrip(static_cast(stream->port), buff, n, msg); + break; + case STR_FTP: + case STR_HTTP: + default: + strunlock(stream); + return 0; + } + stream->outb += ns; + tick = tickget(); + if (ns > 0) stream->tact = tick; + + if (static_cast(tick - stream->tick) > tirate) + { + stream->outr = (stream->outb - stream->outbt) * 8000 / (tick - stream->tick); + stream->tick = tick; + stream->outbt = stream->outb; + } + strunlock(stream); + return ns; +} + + +/* get stream status ----------------------------------------------------------- + * get stream status + * args : stream_t *stream I stream + * char *msg IO status message (NULL: no output) + * return : status (-1:error, 0:close, 1:wait, 2:connect, 3:active) + *-----------------------------------------------------------------------------*/ +int strstat(stream_t *stream, char *msg) +{ + int state; + + tracet(4, "strstat:\n"); + + strlock(stream); + if (msg) + { + // strncpy(msg, stream->msg, MAXSTRMSG - 1); This line triggers a warning. Replaced by: + std::string aux_s(stream->msg); + aux_s.resize(MAXSTRMSG - 1, '0'); + for (int i = 0; i < MAXSTRMSG - 1; i++) msg[i] = aux_s[i]; + msg[MAXSTRMSG - 1] = '\0'; + } + if (!stream->port) + { + strunlock(stream); + return stream->state; + } + switch (stream->type) + { + case STR_SERIAL: + state = stateserial(static_cast(stream->port)); + break; + case STR_FILE: + state = statefile(static_cast(stream->port)); + break; + case STR_TCPSVR: + state = statetcpsvr(static_cast(stream->port)); + break; + case STR_TCPCLI: + state = statetcpcli(static_cast(stream->port)); + break; + case STR_NTRIPSVR: + case STR_NTRIPCLI: + state = statentrip(static_cast(stream->port)); + break; + case STR_FTP: + state = stateftp(static_cast(stream->port)); + break; + case STR_HTTP: + state = stateftp(static_cast(stream->port)); + break; + default: + strunlock(stream); + return 0; + } + if (state == 2 && static_cast(tickget() - stream->tact) <= TINTACT) state = 3; + strunlock(stream); + return state; +} + + +/* get stream statistics summary ----------------------------------------------- + * get stream statistics summary + * args : stream_t *stream I stream + * int *inb IO bytes of input (NULL: no output) + * int *inr IO bps of input (NULL: no output) + * int *outb IO bytes of output (NULL: no output) + * int *outr IO bps of output (NULL: no output) + * return : none + *-----------------------------------------------------------------------------*/ +void strsum(stream_t *stream, int *inb, int *inr, int *outb, int *outr) +{ + tracet(4, "strsum:\n"); + + strlock(stream); + if (inb) *inb = stream->inb; + if (inr) *inr = stream->inr; + if (outb) *outb = stream->outb; + if (outr) *outr = stream->outr; + strunlock(stream); +} + + +/* set global stream options --------------------------------------------------- + * set global stream options + * args : int *opt I options + * opt[0]= inactive timeout (ms) (0: no timeout) + * opt[1]= interval to reconnect (ms) + * opt[2]= averaging time of data rate (ms) + * opt[3]= receive/send buffer size (bytes); + * opt[4]= file swap margin (s) + * opt[5]= reserved + * opt[6]= reserved + * opt[7]= reserved + * return : none + *-----------------------------------------------------------------------------*/ +void strsetopt(const int *opt) +{ + tracet(3, "strsetopt: opt=%d %d %d %d %d %d %d %d\n", opt[0], opt[1], opt[2], + opt[3], opt[4], opt[5], opt[6], opt[7]); + + toinact = 0 < opt[0] && opt[0] < 1000 ? 1000 : opt[0]; /* >=1s */ + ticonnect = opt[1] < 1000 ? 1000 : opt[1]; /* >=1s */ + tirate = opt[2] < 100 ? 100 : opt[2]; /* >=0.1s */ + buffsize = opt[3] < 4096 ? 4096 : opt[3]; /* >=4096byte */ + fswapmargin = opt[4] < 0 ? 0 : opt[4]; +} + + +/* set timeout time ------------------------------------------------------------ + * set timeout time + * args : stream_t *stream I stream (STR_TCPCLI, STR_NTRIPCLI, STR_NTRIPSVR) + * int toinact I inactive timeout (ms) (0: no timeout) + * int tirecon I reconnect interval (ms) (0: no reconnect) + * return : none + *-----------------------------------------------------------------------------*/ +void strsettimeout(stream_t *stream, int toinact, int tirecon) +{ + tcpcli_t *tcpcli; + + tracet(3, "strsettimeout: toinact=%d tirecon=%d\n", toinact, tirecon); + + if (stream->type == STR_TCPCLI) + { + tcpcli = static_cast(stream->port); + } + else if (stream->type == STR_NTRIPCLI || stream->type == STR_NTRIPSVR) + { + tcpcli = (static_cast(stream->port))->tcp; + } + else + return; + + tcpcli->toinact = toinact; + tcpcli->tirecon = tirecon; +} + + +/* set local directory --------------------------------------------------------- + * set local directory path for ftp/http download + * args : char *dir I directory for download files + * return : none + *-----------------------------------------------------------------------------*/ +void strsetdir(const char *dir) +{ + tracet(3, "strsetdir: dir=%s\n", dir); + if (strlen(dir) < 1024) strcpy(localdir, dir); +} + + +/* set http/ntrip proxy address ------------------------------------------------ + * set http/ntrip proxy address + * args : char *addr I http/ntrip proxy address
        : + * return : none + *-----------------------------------------------------------------------------*/ +void strsetproxy(const char *addr) +{ + tracet(3, "strsetproxy: addr=%s\n", addr); + if (strlen(addr) < 256) strcpy(proxyaddr, addr); +} + + +/* get stream time ------------------------------------------------------------- + * get stream time + * args : stream_t *stream I stream + * return : current time or replay time for playback file + *-----------------------------------------------------------------------------*/ +gtime_t strgettime(stream_t *stream) +{ + file_t *file; + if (stream->type == STR_FILE && (stream->mode & STR_MODE_R) && + (file = static_cast(stream->port))) + { + return timeadd(file->time, file->start); /* replay start time */ + } + return utc2gpst(timeget()); +} + + +/* send nmea request ----------------------------------------------------------- + * send nmea gpgga message to stream + * args : stream_t *stream I stream + * double *pos I position {x, y, z} (ecef) (m) + * return : none + *-----------------------------------------------------------------------------*/ +void strsendnmea(stream_t *stream, const double *pos) +{ + sol_t sol = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, '0', '0', '0', 0, 0, 0}; + unsigned char buff[1024]; + int i, n; + + tracet(3, "strsendnmea: pos=%.3f %.3f %.3f\n", pos[0], pos[1], pos[2]); + + sol.stat = SOLQ_SINGLE; + sol.time = utc2gpst(timeget()); + for (i = 0; i < 3; i++) sol.rr[i] = pos[i]; + n = outnmea_gga(buff, &sol); + strwrite(stream, buff, n); +} + + +/* generate general hex message ----------------------------------------------*/ +int gen_hex(const char *msg, unsigned char *buff) +{ + unsigned char *q = buff; + char mbuff[1024] = "", *args[256], *p; + unsigned int byte; + int i, narg = 0; + + trace(4, "gen_hex: msg=%s\n", msg); + + strncpy(mbuff, msg, 1023); + for (p = strtok(mbuff, " "); p && narg < 256; p = strtok(nullptr, " ")) + { + args[narg++] = p; + } + for (i = 0; i < narg; i++) + { + if (sscanf(args[i], "%x", &byte)) *q++ = static_cast(byte); + } + return static_cast(q - buff); +} + + +/* send receiver command ------------------------------------------------------- + * send receiver commands to stream + * args : stream_t *stream I stream + * char *cmd I receiver command strings + * return : none + *-----------------------------------------------------------------------------*/ +void strsendcmd(stream_t *str, const char *cmd) +{ + unsigned char buff[1024]; + const char *p = cmd, *q; + char msg[1024], cmdend[] = "\r\n"; + int n, m, ms; + + tracet(3, "strsendcmd: cmd=%s\n", cmd); + + for (;;) + { + for (q = p;; q++) + if (*q == '\r' || *q == '\n' || *q == '\0') break; + n = static_cast(q - p); + strncpy(msg, p, n); + msg[n] = '\0'; + + if (!*msg || *msg == '#') + { /* null or comment */ + ; + } + else if (*msg == '!') + { /* binary escape */ + if (!strncmp(msg + 1, "WAIT", 4)) + { /* wait */ + if (sscanf(msg + 5, "%d", &ms) < 1) ms = 100; + if (ms > 3000) ms = 3000; /* max 3 s */ + sleepms(ms); + } + + //else if (!strncmp(msg+1, "UBX", 3)) + //{ /* ublox */ + // if ((m=gen_ubx(msg+4, buff))>0) strwrite(str, buff, m); + //} + //else if (!strncmp(msg+1, "STQ", 3)) + //{ /* skytraq */ + // if ((m=gen_stq(msg+4, buff))>0) strwrite(str, buff, m); + //} + //else if (!strncmp(msg+1, "NVS", 3)) + //{ /* nvs */ + // if ((m=gen_nvs(msg+4, buff))>0) strwrite(str, buff, m); + //} + //else if (!strncmp(msg+1, "LEXR", 4)) + //{ /* lex receiver */ + // if ((m=gen_lexr(msg+5, buff))>0) strwrite(str, buff, m); + //} + else if (!strncmp(msg + 1, "HEX", 3)) + { /* general hex message */ + if ((m = gen_hex(msg + 4, buff)) > 0) strwrite(str, buff, m); + } + } + else + { + strwrite(str, reinterpret_cast(msg), n); + strwrite(str, reinterpret_cast(cmdend), 2); + } + if (*q == '\0') + break; + + p = q + 1; + } +} diff --git a/src/algorithms/libs/rtklib/rtklib_stream.h b/src/algorithms/libs/rtklib/rtklib_stream.h new file mode 100644 index 000000000..175c5b063 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_stream.h @@ -0,0 +1,238 @@ +/*! + * \file rtklib_sbas.h + * \brief sbas functions + * \authors
          + *
        • 2007-2013, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2013, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *-----------------------------------------------------------------------------*/ + +#ifndef GNSS_SDR_RTKLIB_STREAM_H_ +#define GNSS_SDR_RTKLIB_STREAM_H_ + +#include "rtklib.h" + +/* constants -----------------------------------------------------------------*/ + +#define TINTACT 200 /* period for stream active (ms) */ +#define SERIBUFFSIZE 4096 /* serial buffer size (bytes) */ +#define TIMETAGH_LEN 64 /* time tag file header length */ +#define MAXCLI 32 /* max client connection for tcp svr */ +#define MAXSTATMSG 32 /* max length of status message */ + +#define VER_RTKLIB "2.4.2" +#define NTRIP_AGENT "RTKLIB/" VER_RTKLIB +#define NTRIP_CLI_PORT 2101 /* default ntrip-client connection port */ +#define NTRIP_SVR_PORT 80 /* default ntrip-server connection port */ +#define NTRIP_MAXRSP 32768 /* max size of ntrip response */ +#define NTRIP_MAXSTR 256 /* max length of mountpoint string */ +#define NTRIP_RSP_OK_CLI "ICY 200 OK\r\n" /* ntrip response: client */ +#define NTRIP_RSP_OK_SVR "OK\r\n" /* ntrip response: server */ +#define NTRIP_RSP_SRCTBL "SOURCETABLE 200 OK\r\n" /* ntrip response: source table */ +#define NTRIP_RSP_TBLEND "ENDSOURCETABLE" +#define NTRIP_RSP_HTTP "HTTP/" /* ntrip response: http */ +#define NTRIP_RSP_ERROR "ERROR" /* ntrip response: error */ + +#define FTP_CMD "wget" /* ftp/http command */ +#define FTP_TIMEOUT 30 /* ftp/http timeout (s) */ + + +serial_t *openserial(const char *path, int mode, char *msg); + +void closeserial(serial_t *serial); + +int readserial(serial_t *serial, unsigned char *buff, int n, char *msg); + +int writeserial(serial_t *serial, unsigned char *buff, int n, char *msg); + +int stateserial(serial_t *serial); + +int openfile_(file_t *file, gtime_t time, char *msg); + +void closefile_(file_t *file); + +file_t *openfile(const char *path, int mode, char *msg); + +void closefile(file_t *file); + +void swapfile(file_t *file, gtime_t time, char *msg); + +void swapclose(file_t *file); + +int statefile(file_t *file); + +int readfile(file_t *file, unsigned char *buff, int nmax, char *msg); + +int writefile(file_t *file, unsigned char *buff, int n, char *msg); + +void syncfile(file_t *file1, file_t *file2); + +void decodetcppath(const char *path, char *addr, char *port, char *user, + char *passwd, char *mntpnt, char *str); + +int errsock(void); + +int setsock(socket_t sock, char *msg); + +socket_t accept_nb(socket_t sock, struct sockaddr *addr, socklen_t *len); + +int connect_nb(socket_t sock, struct sockaddr *addr, socklen_t len); + +int recv_nb(socket_t sock, unsigned char *buff, int n); + +int send_nb(socket_t sock, unsigned char *buff, int n); + +int gentcp(tcp_t *tcp, int type, char *msg); + +void discontcp(tcp_t *tcp, int tcon); + +tcpsvr_t *opentcpsvr(const char *path, char *msg); + +void closetcpsvr(tcpsvr_t *tcpsvr); + +void updatetcpsvr(tcpsvr_t *tcpsvr, char *msg); + +int accsock(tcpsvr_t *tcpsvr, char *msg); + +int waittcpsvr(tcpsvr_t *tcpsvr, char *msg); + +int readtcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg); + +int writetcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg); + +int statetcpsvr(tcpsvr_t *tcpsvr); + +int consock(tcpcli_t *tcpcli, char *msg); + +tcpcli_t *opentcpcli(const char *path, char *msg); + +void closetcpcli(tcpcli_t *tcpcli); + +int waittcpcli(tcpcli_t *tcpcli, char *msg); + +int readtcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg); + +int writetcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg); + +int statetcpcli(tcpcli_t *tcpcli); + +int encbase64(char *str, const unsigned char *byte, int n); + +int reqntrip_s(ntrip_t *ntrip, char *msg); + +int reqntrip_c(ntrip_t *ntrip, char *msg); + +int rspntrip_s(ntrip_t *ntrip, char *msg); + +int rspntrip_c(ntrip_t *ntrip, char *msg); + +int waitntrip(ntrip_t *ntrip, char *msg); + +ntrip_t *openntrip(const char *path, int type, char *msg); + +void closentrip(ntrip_t *ntrip); + +int readntrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg); + +int writentrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg); + +int statentrip(ntrip_t *ntrip); + +void decodeftppath(const char *path, char *addr, char *file, char *user, + char *passwd, int *topts); + +gtime_t nextdltime(const int *topts, int stat); + +void *ftpthread(void *arg); + +ftp_t *openftp(const char *path, int type, char *msg); + +void closeftp(ftp_t *ftp); + +int readftp(ftp_t *ftp, unsigned char *buff, int n, char *msg); + +int stateftp(ftp_t *ftp); + +void strinitcom(void); + +void strinit(stream_t *stream); + +int stropen(stream_t *stream, int type, int mode, const char *path); + +void strclose(stream_t *stream); + +void strsync(stream_t *stream1, stream_t *stream2); + +void strlock(stream_t *stream); + +void strunlock(stream_t *stream); + +int strread(stream_t *stream, unsigned char *buff, int n); + +int strwrite(stream_t *stream, unsigned char *buff, int n); + +int strstat(stream_t *stream, char *msg); + +void strsum(stream_t *stream, int *inb, int *inr, int *outb, int *outr); + +void strsetopt(const int *opt); + +void strsettimeout(stream_t *stream, int toinact, int tirecon); + +void strsetdir(const char *dir); + +void strsetproxy(const char *addr); + +gtime_t strgettime(stream_t *stream); + +void strsendnmea(stream_t *stream, const double *pos); + +int gen_hex(const char *msg, unsigned char *buff); + +void strsendcmd(stream_t *str, const char *cmd); + + +#endif diff --git a/src/algorithms/libs/rtklib/rtklib_tides.cc b/src/algorithms/libs/rtklib/rtklib_tides.cc new file mode 100644 index 000000000..c53d5cd98 --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_tides.cc @@ -0,0 +1,327 @@ +/*! + * \file rtklib_tides.cc + * \brief Tidal displacement corrections + * \authors
          + *
        • 2007-2008, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2007-2008, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *----------------------------------------------------------------------------*/ + +#include "rtklib_tides.h" +#include "rtklib_rtkcmn.h" + + +/* solar/lunar tides (ref [2] 7) ---------------------------------------------*/ +//#ifndef IERS_MODEL +void tide_pl(const double *eu, const double *rp, double GMp, + const double *pos, double *dr) +{ + const double H3 = 0.292, L3 = 0.015; + double r, ep[3], latp, lonp, p, K2, K3, a, H2, L2, dp, du, cosp, sinl, cosl; + int i; + + trace(4, "tide_pl : pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D); + + if ((r = norm_rtk(rp, 3)) <= 0.0) return; + + for (i = 0; i < 3; i++) ep[i] = rp[i] / r; + + K2 = GMp / GME * std::pow(RE_WGS84, 2.04) * std::pow(RE_WGS84, 2.0) / (r * r * r); + K3 = K2 * RE_WGS84 / r; + latp = asin(ep[2]); + lonp = atan2(ep[1], ep[0]); + cosp = cos(latp); + sinl = sin(pos[0]); + cosl = cos(pos[0]); + + /* step1 in phase (degree 2) */ + p = (3.0 * sinl * sinl - 1.0) / 2.0; + H2 = 0.6078 - 0.0006 * p; + L2 = 0.0847 + 0.0002 * p; + a = dot(ep, eu, 3); + dp = K2 * 3.0 * L2 * a; + du = K2 * (H2 * (1.5 * a * a - 0.5) - 3.0 * L2 * a * a); + + /* step1 in phase (degree 3) */ + dp += K3 * L3 * (7.5 * a * a - 1.5); + du += K3 * (H3 * (2.5 * a * a * a - 1.5 * a) - L3 * (7.5 * a * a - 1.5) * a); + + /* step1 out-of-phase (only radial) */ + du += 3.0 / 4.0 * 0.0025 * K2 * sin(2.0 * latp) * sin(2.0 * pos[0]) * sin(pos[1] - lonp); + du += 3.0 / 4.0 * 0.0022 * K2 * cosp * cosp * cosl * cosl * sin(2.0 * (pos[1] - lonp)); + + dr[0] = dp * ep[0] + du * eu[0]; + dr[1] = dp * ep[1] + du * eu[1]; + dr[2] = dp * ep[2] + du * eu[2]; + + trace(5, "tide_pl : dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]); +} + + +/* displacement by solid earth tide (ref [2] 7) ------------------------------*/ +void tide_solid(const double *rsun, const double *rmoon, + const double *pos, const double *E, double gmst, int opt, + double *dr) +{ + double dr1[3], dr2[3], eu[3], du, dn, sinl, sin2l; + + trace(3, "tide_solid: pos=%.3f %.3f opt=%d\n", pos[0] * R2D, pos[1] * R2D, opt); + + /* step1: time domain */ + eu[0] = E[2]; + eu[1] = E[5]; + eu[2] = E[8]; + tide_pl(eu, rsun, GMS, pos, dr1); + tide_pl(eu, rmoon, GMM, pos, dr2); + + /* step2: frequency domain, only K1 radial */ + sin2l = sin(2.0 * pos[0]); + du = -0.012 * sin2l * sin(gmst + pos[1]); + + dr[0] = dr1[0] + dr2[0] + du * E[2]; + dr[1] = dr1[1] + dr2[1] + du * E[5]; + dr[2] = dr1[2] + dr2[2] + du * E[8]; + + /* eliminate permanent deformation */ + if (opt & 8) + { + sinl = sin(pos[0]); + du = 0.1196 * (1.5 * sinl * sinl - 0.5); + dn = 0.0247 * sin2l; + dr[0] += du * E[2] + dn * E[1]; + dr[1] += du * E[5] + dn * E[4]; + dr[2] += du * E[8] + dn * E[7]; + } + trace(5, "tide_solid: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]); +} +//#endif /* !IERS_MODEL */ + + +/* displacement by ocean tide loading (ref [2] 7) ----------------------------*/ +void tide_oload(gtime_t tut, const double *odisp, double *denu) +{ + const double args[][5] = { + {1.40519E-4, 2.0, -2.0, 0.0, 0.00}, /* M2 */ + {1.45444E-4, 0.0, 0.0, 0.0, 0.00}, /* S2 */ + {1.37880E-4, 2.0, -3.0, 1.0, 0.00}, /* N2 */ + {1.45842E-4, 2.0, 0.0, 0.0, 0.00}, /* K2 */ + {0.72921E-4, 1.0, 0.0, 0.0, 0.25}, /* K1 */ + {0.67598E-4, 1.0, -2.0, 0.0, -0.25}, /* O1 */ + {0.72523E-4, -1.0, 0.0, 0.0, -0.25}, /* P1 */ + {0.64959E-4, 1.0, -3.0, 1.0, -0.25}, /* Q1 */ + {0.53234E-5, 0.0, 2.0, 0.0, 0.00}, /* Mf */ + {0.26392E-5, 0.0, 1.0, -1.0, 0.00}, /* Mm */ + {0.03982E-5, 2.0, 0.0, 0.0, 0.00} /* Ssa */ + }; + const double ep1975[] = {1975, 1, 1, 0, 0, 0}; + double ep[6], fday, days, t, t2, t3, a[5], ang, dp[3] = {0}; + int i, j; + + trace(3, "tide_oload:\n"); + + /* angular argument: see subroutine arg.f for reference [1] */ + time2epoch(tut, ep); + fday = ep[3] * 3600.0 + ep[4] * 60.0 + ep[5]; + ep[3] = ep[4] = ep[5] = 0.0; + days = timediff(epoch2time(ep), epoch2time(ep1975)) / 86400.0 + 1.0; + t = (27392.500528 + 1.000000035 * days) / 36525.0; + t2 = t * t; + t3 = t2 * t; + + a[0] = fday; + a[1] = (279.69668 + 36000.768930485 * t + 3.03E-4 * t2) * D2R; /* H0 */ + a[2] = (270.434358 + 481267.88314137 * t - 0.001133 * t2 + 1.9E-6 * t3) * D2R; /* S0 */ + a[3] = (334.329653 + 4069.0340329577 * t - 0.010325 * t2 - 1.2E-5 * t3) * D2R; /* P0 */ + a[4] = 2.0 * PI; + + /* displacements by 11 constituents */ + for (i = 0; i < 11; i++) + { + ang = 0.0; + for (j = 0; j < 5; j++) ang += a[j] * args[i][j]; + for (j = 0; j < 3; j++) dp[j] += odisp[j + i * 6] * cos(ang - odisp[j + 3 + i * 6] * D2R); + } + denu[0] = -dp[1]; + denu[1] = -dp[2]; + denu[2] = dp[0]; + + trace(5, "tide_oload: denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]); +} + + +/* iers mean pole (ref [7] eq.7.25) ------------------------------------------*/ +void iers_mean_pole(gtime_t tut, double *xp_bar, double *yp_bar) +{ + const double ep2000[] = {2000, 1, 1, 0, 0, 0}; + double y, y2, y3; + + y = timediff(tut, epoch2time(ep2000)) / 86400.0 / 365.25; + + if (y < 3653.0 / 365.25) + { /* until 2010.0 */ + y2 = y * y; + y3 = y2 * y; + *xp_bar = 55.974 + 1.8243 * y + 0.18413 * y2 + 0.007024 * y3; /* (mas) */ + *yp_bar = 346.346 + 1.7896 * y - 0.10729 * y2 - 0.000908 * y3; + } + else + { /* after 2010.0 */ + *xp_bar = 23.513 + 7.6141 * y; /* (mas) */ + *yp_bar = 358.891 - 0.6287 * y; + } +} + + +/* displacement by pole tide (ref [7] eq.7.26) --------------------------------*/ +void tide_pole(gtime_t tut, const double *pos, const double *erpv, + double *denu) +{ + double xp_bar, yp_bar, m1, m2, cosl, sinl; + + trace(3, "tide_pole: pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D); + + /* iers mean pole (mas) */ + iers_mean_pole(tut, &xp_bar, &yp_bar); + + /* ref [7] eq.7.24 */ + m1 = erpv[0] / AS2R - xp_bar * 1E-3; /* (as) */ + m2 = -erpv[1] / AS2R + yp_bar * 1E-3; + + /* sin(2*theta) = sin(2*phi), cos(2*theta)=-cos(2*phi) */ + cosl = cos(pos[1]); + sinl = sin(pos[1]); + denu[0] = 9E-3 * sin(pos[0]) * (m1 * sinl - m2 * cosl); /* de= Slambda (m) */ + denu[1] = -9E-3 * cos(2.0 * pos[0]) * (m1 * cosl + m2 * sinl); /* dn=-Stheta (m) */ + denu[2] = -33E-3 * sin(2.0 * pos[0]) * (m1 * cosl + m2 * sinl); /* du= Sr (m) */ + + trace(5, "tide_pole : denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]); +} + + +/* tidal displacement ---------------------------------------------------------- + * displacements by earth tides + * args : gtime_t tutc I time in utc + * double *rr I site position (ecef) (m) + * int opt I options (or of the followings) + * 1: solid earth tide + * 2: ocean tide loading + * 4: pole tide + * 8: elimate permanent deformation + * double *erp I earth rotation parameters (NULL: not used) + * double *odisp I ocean loading parameters (NULL: not used) + * odisp[0+i*6]: consituent i amplitude radial(m) + * odisp[1+i*6]: consituent i amplitude west (m) + * odisp[2+i*6]: consituent i amplitude south (m) + * odisp[3+i*6]: consituent i phase radial (deg) + * odisp[4+i*6]: consituent i phase west (deg) + * odisp[5+i*6]: consituent i phase south (deg) + * (i=0:M2,1:S2,2:N2,3:K2,4:K1,5:O1,6:P1,7:Q1, + * 8:Mf,9:Mm,10:Ssa) + * double *dr O displacement by earth tides (ecef) (m) + * return : none + * notes : see ref [1], [2] chap 7 + * see ref [4] 5.2.1, 5.2.2, 5.2.3 + * ver.2.4.0 does not use ocean loading and pole tide corrections + *-----------------------------------------------------------------------------*/ +void tidedisp(gtime_t tutc, const double *rr, int opt, const erp_t *erp, + const double *odisp, double *dr) +{ + gtime_t tut; + double pos[2], E[9], drt[3], denu[3], rs[3], rm[3], gmst, erpv[5] = {0}; + int i; +#ifdef IERS_MODEL + double ep[6], fhr; + int year, mon, day; +#endif + + trace(3, "tidedisp: tutc=%s\n", time_str(tutc, 0)); + + if (erp) geterp(erp, tutc, erpv); + + tut = timeadd(tutc, erpv[2]); + + dr[0] = dr[1] = dr[2] = 0.0; + + if (norm_rtk(rr, 3) <= 0.0) return; + + pos[0] = asin(rr[2] / norm_rtk(rr, 3)); + pos[1] = atan2(rr[1], rr[0]); + xyz2enu(pos, E); + + if (opt & 1) + { /* solid earth tides */ + + /* sun and moon position in ecef */ + sunmoonpos(tutc, erpv, rs, rm, &gmst); + +#ifdef IERS_MODEL + time2epoch(tutc, ep); + year = (int)ep[0]; + mon = (int)ep[1]; + day = (int)ep[2]; + fhr = ep[3] + ep[4] / 60.0 + ep[5] / 3600.0; + + /* call DEHANTTIDEINEL */ + // dehanttideinel_((double *)rr,&year,&mon,&day,&fhr,rs,rm,drt); +#else + tide_solid(rs, rm, pos, E, gmst, opt, drt); +#endif + for (i = 0; i < 3; i++) dr[i] += drt[i]; + } + if ((opt & 2) && odisp) + { /* ocean tide loading */ + tide_oload(tut, odisp, denu); + matmul("TN", 3, 1, 3, 1.0, E, denu, 0.0, drt); + for (i = 0; i < 3; i++) dr[i] += drt[i]; + } + if ((opt & 4) && erp) + { /* pole tide */ + tide_pole(tut, pos, erpv, denu); + matmul("TN", 3, 1, 3, 1.0, E, denu, 0.0, drt); + for (i = 0; i < 3; i++) dr[i] += drt[i]; + } + trace(5, "tidedisp: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]); +} diff --git a/src/algorithms/libs/rtklib/rtklib_tides.h b/src/algorithms/libs/rtklib/rtklib_tides.h new file mode 100644 index 000000000..cb21f495a --- /dev/null +++ b/src/algorithms/libs/rtklib/rtklib_tides.h @@ -0,0 +1,92 @@ +/*! + * \file rtklib_tides.h + * \brief Tidal displacement corrections + * \authors
          + *
        • 2015, T. Takasu + *
        • 2017, Javier Arribas + *
        • 2017, Carles Fernandez + *
        + * + * This is a derived work from RTKLIB http://www.rtklib.com/ + * The original source code at https://github.com/tomojitakasu/RTKLIB is + * released under the BSD 2-clause license with an additional exclusive clause + * that does not apply here. This additional clause is reproduced below: + * + * " The software package includes some companion executive binaries or shared + * libraries necessary to execute APs on Windows. These licenses succeed to the + * original ones of these software. " + * + * Neither the executive binaries nor the shared libraries are required by, used + * or included in GNSS-SDR. + * + * ------------------------------------------------------------------------- + * Copyright (C) 2015, T. Takasu + * Copyright (C) 2017, Javier Arribas + * Copyright (C) 2017, Carles Fernandez + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * References: + * [1] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 + * [2] D.D.McCarthy and G.Petit, IERS Technical Note 32, IERS Conventions + * 2003, November 2003 + * [3] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, + * Space Technology Library, 2004 + * [4] J.Kouba, A Guide to using International GNSS Service (IGS) products, + * May 2009 + * [5] G.Petit and B.Luzum (eds), IERS Technical Note No. 36, IERS + * Conventions (2010), 2010 + *----------------------------------------------------------------------------*/ + + +#ifndef GNSS_SDR_RTKLIB_TIDES_H_ +#define GNSS_SDR_RTKLIB_TIDES_H_ + + +#include "rtklib.h" + + +const double GME = 3.986004415E+14; /* earth gravitational constant */ +const double GMS = 1.327124E+20; /* sun gravitational constant */ +const double GMM = 4.902801E+12; /* moon gravitational constant */ + +void tide_pl(const double *eu, const double *rp, double GMp, + const double *pos, double *dr); + +void tide_solid(const double *rsun, const double *rmoon, + const double *pos, const double *E, double gmst, int opt, + double *dr); + +void tide_oload(gtime_t tut, const double *odisp, double *denu); + +void iers_mean_pole(gtime_t tut, double *xp_bar, double *yp_bar); + + +void tide_pole(gtime_t tut, const double *pos, const double *erpv, + double *denu); + +void tidedisp(gtime_t tutc, const double *rr, int opt, const erp_t *erp, + const double *odisp, double *dr); +#endif diff --git a/src/algorithms/libs/short_x2_to_cshort.cc b/src/algorithms/libs/short_x2_to_cshort.cc index e55b1ac27..90ce99a7e 100644 --- a/src/algorithms/libs/short_x2_to_cshort.cc +++ b/src/algorithms/libs/short_x2_to_cshort.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,10 +40,9 @@ short_x2_to_cshort_sptr make_short_x2_to_cshort() } - short_x2_to_cshort::short_x2_to_cshort() : sync_block("short_x2_to_cshort", - gr::io_signature::make (2, 2, sizeof(short)), - gr::io_signature::make (1, 1, sizeof(lv_16sc_t))) // lv_8sc_t is a Volk's typedef for std::complex + gr::io_signature::make(2, 2, sizeof(int16_t)), + gr::io_signature::make(1, 1, sizeof(lv_16sc_t))) { const int alignment_multiple = volk_get_alignment() / sizeof(lv_16sc_t); set_alignment(std::max(1, alignment_multiple)); @@ -51,16 +50,16 @@ short_x2_to_cshort::short_x2_to_cshort() : sync_block("short_x2_to_cshort", int short_x2_to_cshort::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const short *in0 = (const short *) input_items[0]; - const short *in1 = (const short *) input_items[1]; - lv_16sc_t *out = (lv_16sc_t *) output_items[0]; + const auto *in0 = reinterpret_cast(input_items[0]); + const auto *in1 = reinterpret_cast(input_items[1]); + auto *out = reinterpret_cast(output_items[0]); // This could be put into a volk kernel - short real_part; - short imag_part; - for(int number = 0; number < noutput_items; number++) + int16_t real_part; + int16_t imag_part; + for (int number = 0; number < noutput_items; number++) { // lv_cmake(r, i) defined at volk/volk_complex.h real_part = *in0++; diff --git a/src/algorithms/libs/short_x2_to_cshort.h b/src/algorithms/libs/short_x2_to_cshort.h index 6bd44fddf..a95ae1214 100644 --- a/src/algorithms/libs/short_x2_to_cshort.h +++ b/src/algorithms/libs/short_x2_to_cshort.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,12 +48,13 @@ class short_x2_to_cshort : public gr::sync_block { private: friend short_x2_to_cshort_sptr make_short_x2_to_cshort(); + public: short_x2_to_cshort(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt index fe9bf972d..59a8d1ff7 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -14,7 +14,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # ######################################################################## @@ -27,9 +27,95 @@ enable_language(CXX) enable_language(C) enable_testing() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +# Set compiler flags +set(GNSSSDR_CLANG_MIN_VERSION "3.4.0") +set(GNSSSDR_APPLECLANG_MIN_VERSION "500") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + execute_process(COMMAND + ${CMAKE_CXX_COMPILER} -v + RESULT_VARIABLE _res ERROR_VARIABLE _err + ERROR_STRIP_TRAILING_WHITESPACE) + if(${_res} STREQUAL "0") + # output is in error stream + string(REGEX MATCH "^Apple.*" IS_APPLE ${_err}) + if("${IS_APPLE}" STREQUAL "") + set(MIN_VERSION ${GNSSSDR_CLANG_MIN_VERSION}) + set(APPLE_STR "") + # retrieve the compiler's version from it + string(REGEX MATCH "clang version [0-9.]+" CLANG_OTHER_VERSION ${_err}) + string(REGEX MATCH "[0-9.]+" CLANG_VERSION ${CLANG_OTHER_VERSION}) + else() + set(MIN_VERSION ${GNSSSDR_APPLECLANG_MIN_VERSION}) + set(APPLE_STR "Apple ") + # retrieve the compiler's version from it + string(REGEX MATCH "(clang-[0-9.]+)" CLANG_APPLE_VERSION ${_err}) + string(REGEX MATCH "[0-9.]+" CLANG_VERSION ${CLANG_APPLE_VERSION}) + endif() + if(${CLANG_VERSION} VERSION_LESS "${MIN_VERSION}") + message(WARNING "\nThe compiler selected to build VOLK-GNSSSDR (${APPLE_STR}Clang version ${CLANG_VERSION} : ${CMAKE_CXX_COMPILER}) is older than that officially supported (${MIN_VERSION} minimum). This build may or not work. We highly recommend using Apple Clang version ${APPLECLANG_MIN_VERSION} or more recent, or Clang version ${CLANG_MIN_VERSION} or more recent.") + endif() + else() + message(WARNING "\nCannot determine the version of the compiler selected to build VOLK-GNSSSDR (${APPLE_STR}Clang : ${CMAKE_CXX_COMPILER}). This build may or not work. We highly recommend using Apple Clang version ${APPLECLANG_MIN_VERSION} or more recent, or Clang version ${CLANG_MIN_VERSION} or more recent.") + endif() +endif() + +# Enable C++17 support in GCC >= 8.0.0 +# Enable C++14 support in 8.0.0 > GCC >= 6.1.1 +# Fallback to C++11 when using GCC < 6.1.1 + +if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.1.1") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + else() + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++17") + endif() + endif() + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -Wall -Wextra") #Add warning flags: For "-Wall" see http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html +endif() + +# Enable C++17 support in Clang >= 6.0.0 +# Enable C++14 support in 6.0.0 > Clang >= 3.5.0 or AppleClang >= 600 +# Fallback to C++11 if older version +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + # See https://trac.macports.org/wiki/XcodeVersionInfo for Apple Clang version equivalences + if(CLANG_VERSION VERSION_LESS "600") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + endif() + else() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++11") + else() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0.0") + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++14") + else() + set(MY_CXX_FLAGS "${MY_CXX_FLAGS} -std=c++17") + endif() + endif() + endif() +endif() + +if(NOT ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + if(NOT (CMAKE_VERSION VERSION_LESS "3.1")) + set(CMAKE_C_STANDARD 11) + set(CMAKE_CXX_STANDARD 11) + endif() +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_FLAGS} -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) + +if(CMAKE_VERSION VERSION_GREATER "3.0") + cmake_policy(SET CMP0042 NEW) + if(CMAKE_VERSION VERSION_GREATER "3.9") + cmake_policy(SET CMP0068 NEW) + endif() +endif() option(ENABLE_STRIP "Create a stripped volk_gnsssdr_profile binary (without shared libraries)" OFF) @@ -43,13 +129,13 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") message(STATUS "Build type not specified: defaulting to release.") endif() -VOLK_CHECK_BUILD_TYPE(${CMAKE_BUILD_TYPE}) +volk_check_build_type(${CMAKE_BUILD_TYPE}) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.") set(VERSION_INFO_MAJOR_VERSION 0) set(VERSION_INFO_MINOR_VERSION 0) -set(VERSION_INFO_MAINT_VERSION 9) +set(VERSION_INFO_MAINT_VERSION 10) include(VolkVersion) #setup version info @@ -58,14 +144,14 @@ include(VolkVersion) #setup version info ######################################################################## # Environment setup ######################################################################## -IF(NOT DEFINED BOOST_ROOT AND NOT DEFINED ENV{BOOST_ROOT}) - SET(BOOST_ROOT ${CMAKE_INSTALL_PREFIX}) -ENDIF() +if(NOT DEFINED BOOST_ROOT AND NOT DEFINED ENV{BOOST_ROOT}) + set(BOOST_ROOT ${CMAKE_INSTALL_PREFIX}) +endif() -IF(NOT DEFINED CROSSCOMPILE_MULTILIB) - SET(CROSSCOMPILE_MULTILIB "") -ENDIF() -SET(CROSSCOMPILE_MULTILIB ${CROSSCOMPILE_MULTILIB} CACHE STRING "Define \"true\" if you have and want to use multiple C development libs installed for cross compile") +if(NOT DEFINED CROSSCOMPILE_MULTILIB) + set(CROSSCOMPILE_MULTILIB "") +endif() +set(CROSSCOMPILE_MULTILIB ${CROSSCOMPILE_MULTILIB} CACHE STRING "Define \"true\" if you have and want to use multiple C development libs installed for cross compile") if(MSVC) add_definitions(-D_USE_MATH_DEFINES) #enables math constants on all supported versions of MSVC @@ -74,7 +160,17 @@ if(MSVC) add_compile_options(/wd4752) add_compile_options(/wo4273) add_compile_options(/wo4838) -endif(MSVC) +endif() + +# allow 'large' files in 32 bit builds +if(UNIX) + add_definitions(-D_LARGEFILE_SOURCE + -D_FILE_OFFSET_BITS=64 + -D_LARGE_FILES + -D_FORTIFY_SOURCE=2 + ) +endif() + ######################################################################## # Dependencies setup @@ -82,9 +178,9 @@ endif(MSVC) # Python include(VolkPython) #sets PYTHON_EXECUTABLE and PYTHON_DASH_B -VOLK_PYTHON_CHECK_MODULE("python >= 2.7" sys "sys.version.split()[0] >= '2.7'" PYTHON_MIN_VER_FOUND) -VOLK_PYTHON_CHECK_MODULE("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) -VOLK_PYTHON_CHECK_MODULE("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) +volk_python_check_module("python >= 2.7" sys "sys.version.split()[0] >= '2.7'" PYTHON_MIN_VER_FOUND) +volk_python_check_module("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) +volk_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) if(NOT PYTHON_MIN_VER_FOUND) @@ -103,16 +199,16 @@ endif() # Boost if(MSVC) - if (NOT DEFINED BOOST_ALL_DYN_LINK) + if(NOT DEFINED BOOST_ALL_DYN_LINK) set(BOOST_ALL_DYN_LINK TRUE) endif() set(BOOST_ALL_DYN_LINK "${BOOST_ALL_DYN_LINK}" CACHE BOOL "boost enable dynamic linking") if(BOOST_ALL_DYN_LINK) add_definitions(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc - else(BOOST_ALL_DYN_LINK) + else() unset(BOOST_REQUIRED_COMPONENTS) #empty components list for static link - endif(BOOST_ALL_DYN_LINK) -endif(MSVC) + endif() +endif() include(VolkBoost) @@ -124,9 +220,9 @@ endif() option(ENABLE_ORC "Enable Orc" True) if(ENABLE_ORC) find_package(ORC) -else(ENABLE_ORC) +else() message(STATUS "Disabling use of ORC") -endif(ENABLE_ORC) +endif() ######################################################################## @@ -144,7 +240,7 @@ if(DOXYGEN_FOUND) WORKING_DIRECTORY ${PROJECT_BINARY_DIR} COMMENT "Generating documentation with Doxygen" VERBATIM ) -endif(DOXYGEN_FOUND) +endif() ######################################################################## @@ -159,7 +255,8 @@ set(includedir "\${prefix}/include") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/volk_gnsssdr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr.pc -@ONLY) + @ONLY +) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/volk_gnsssdr.pc @@ -184,7 +281,9 @@ install(FILES ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_prefs.h ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_complex.h ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_common.h + ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/saturation_arithmetic.h ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_avx_intrinsics.h + ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_sse_intrinsics.h ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_sse3_intrinsics.h ${PROJECT_SOURCE_DIR}/include/volk_gnsssdr/volk_gnsssdr_neon_intrinsics.h ${PROJECT_BINARY_DIR}/include/volk_gnsssdr/volk_gnsssdr.h @@ -206,17 +305,17 @@ if(APPLE) set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/${VOLK_LIBRARY_DIR} CACHE PATH "Library Install Name Destination Directory" FORCE) - endif(NOT CMAKE_INSTALL_NAME_DIR) + endif() if(NOT CMAKE_INSTALL_RPATH) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${VOLK_LIBRARY_DIR} CACHE PATH "Library Install RPath" FORCE) - endif(NOT CMAKE_INSTALL_RPATH) + endif() if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "Do Build Using Library Install RPath" FORCE) - endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) -endif(APPLE) + endif() +endif() ######################################################################## @@ -260,7 +359,7 @@ configure_file( if(NOT CMAKE_MODULES_DIR) set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) -endif(NOT CMAKE_MODULES_DIR) +endif() install( FILES @@ -273,7 +372,7 @@ install( ######################################################################## # Option to enable QA testing, on by default ######################################################################## -OPTION(ENABLE_TESTING "Enable QA testing" ON) +option(ENABLE_TESTING "Enable QA testing" ON) if(ENABLE_TESTING) message(STATUS "QA Testing is enabled.") else() @@ -285,10 +384,10 @@ message(STATUS " Modify using: -DENABLE_TESTING=ON/OFF") ######################################################################## # Option to enable post-build profiling using volk_profile, off by default ######################################################################## -OPTION(ENABLE_PROFILING "Launch system profiler after build" OFF) +option(ENABLE_PROFILING "Launch system profiler after build" OFF) if(ENABLE_PROFILING) set(ENABLE_STATIC_LIBS ON) - if(DEFINED VOLK_CONFIGPATH) + if(DEFINED VOLK_CONFIGPATH) get_filename_component(VOLK_CONFIGPATH ${VOLK_CONFIGPATH} ABSOLUTE) set(VOLK_CONFIGPATH "${VOLK_CONFIGPATH}/volk_gnsssdr") message(STATUS "System profiling is enabled, using path: ${VOLK_CONFIGPATH}") @@ -308,7 +407,7 @@ else() endif() message(STATUS " Modify using: -DENABLE_PROFILING=ON/OFF") ######################################################################## - + ######################################################################## # Setup the library ######################################################################## diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/COPYING b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/COPYING index 818433ecc..8859f3d09 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/COPYING +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/COPYING @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found. 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 . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/Doxyfile.in b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/Doxyfile.in index bf566c57b..4d9e579a3 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/Doxyfile.in +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/Doxyfile.in @@ -20,7 +20,7 @@ # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# built into libc) for the transcoding. See https://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. @@ -145,7 +145,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -287,7 +287,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -320,7 +320,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -679,7 +679,7 @@ LAYOUT_FILE = @PROJECT_SOURCE_DIR@/DoxygenLayout.xml # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See @@ -761,7 +761,7 @@ INPUT = @PROJECT_SOURCE_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. @@ -994,7 +994,7 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: @@ -1117,7 +1117,7 @@ HTML_STYLESHEET = # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1137,7 +1137,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1195,13 +1195,12 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# environment (see: https://developer.apple.com/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1240,7 +1239,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1453,7 +1452,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1465,7 +1464,7 @@ USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# https://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1480,11 +1479,11 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.com/libraries/mathjax/. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdnjs.com/libraries/mathjax/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1495,7 +1494,7 @@ MATHJAX_EXTENSIONS = # 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. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1542,7 +1541,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1555,7 +1554,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1726,7 +1725,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2008,7 +2007,7 @@ PREDEFINED = LV_HAVE_GENERIC \ EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an +# remove all references to function-like macros that are alone on a line, have an # all uppercase name, and do not end with a semicolon. Such function macros are # typically used for boiler-plate code, and will confuse the parser if not # removed. diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/README.md b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/README.md index 8c9c2254c..f37cc5b35 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/README.md +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/README.md @@ -1,46 +1,81 @@ # Welcome to VOLK_GNSSSDR, the Vector-Optimized Library of Kernels for GNSS-SDR -VOLK_GNSSSDR is a sub-project of GNSS-SDR. This library provides a set of extra kernels that can be used stand-alone or in combination with VOLK's. Please see http://libvolk.org for documentation, source code, and contact information about the original VOLK library. +VOLK_GNSSSDR is a sub-project of GNSS-SDR. This library provides a set +of extra kernels that can be used stand-alone or in combination with +VOLK's. Please see http://libvolk.org for documentation, source code, +and contact information about the original VOLK library. -The boilerplate of this code was initially generated with ```volk_modtool```, an application provided by VOLK that creates the skeleton than can then be filled with custom kernels. Some modifications were added to accomodate the specificities of Global Navigation Satellite Systems (GNSS) signal processing. Those changes are clearly indicated in the source code, and do not break compatibility. +The boilerplate of this code was initially generated with +```volk_modtool```, an application provided by VOLK that creates the +skeleton that can then be filled with custom kernels. Some modifications +were added to accommodate the specificities of Global Navigation +Satellite Systems (GNSS) signal processing. Those changes are clearly +indicated in the source code, and do not break compatibility. -This library contains kernels of hand-written SIMD code for different mathematical operations, mainly with 8-bit and 16-bit real and complex data types, offering a platform/architecture agnostic version that will run in all machines, plus other versions for different SIMD instruction sets. Then, the application ```volk_gnsssdr_profile``` runs some iterations of all versions that your machine can execute and annotates which is the fastest, which will then be selected at runtime when executing GNSS-SDR. In this way, we can address at the same time portability (by creating executables that will run in nearly all processor architectures) and efficiency (by providing custom implementations specially designed to take advantage of the specific processor that is running the code). +This library contains kernels of hand-written SIMD code for different +mathematical operations, mainly with 8-bit and 16-bit real and complex +data types, offering a platform/architecture agnostic version that will +run in all machines, plus other versions for different SIMD instruction +sets. Then, the application ```volk_gnsssdr_profile``` runs some +iterations of all versions that your machine can execute and annotates +which is the fastest, which will then be selected at runtime when +executing GNSS-SDR. In this way, we can address at the same time +[portability](https://gnss-sdr.org/design-forces/portability/) (by +creating executables that will run in nearly all processor +architectures) and +[efficiency](https://gnss-sdr.org/design-forces/efficiency/) (by +providing custom implementations specially designed to take advantage of +the specific processor that is running the code). -These kernels have some specific features (e.g. saturation arithmetics) that are aimed to GNSS signal processing, but could make them not suitable for its general use in other applications. Check out the documentation generated by Doxygen and the *generic* (that is, plain C) implementation to see what each kernel is actually doing. +These kernels have some specific features (e.g. saturation arithmetics) +that are aimed to GNSS signal processing, but could make them not +suitable for its general use in other applications. Check out the +documentation generated by Doxygen and the *generic* (that is, plain C) +implementation to see what each kernel is actually doing. ## How to use VOLK_GNSSSDR: -This library is automatically built and installed along with GNSS-SDR if it is not found by CMake on your system at configure time. +This library is automatically built and installed along with GNSS-SDR if +it is not found by CMake on your system at configure time. -However, you can install and use VOLK_GNSSSDR kernels as you use VOLK's, independently from GNSS-SDR. +However, you can install and use VOLK_GNSSSDR kernels as you use VOLK's, +independently of GNSS-SDR. -First, make sure that the required dependencies are installed in you machine: +First, make sure that the required dependencies are installed in your +machine: -~~~~~~ -$ sudo apt-get install git cmake python-mako python-six libboost-dev libbbost-filesystem -~~~~~~ +~~~~~~ +$ sudo apt-get install cmake python-mako python-six libboost-dev \ + libboost-filesystem-dev libboost-system-dev +~~~~~~ -In order to build and install the library, go to the base folder of the source code and do: +In order to build and install the library, go to the base folder of the +source code and do: -~~~~~~ +~~~~~~ $ mkdir build $ cd build $ cmake .. $ make $ sudo make install -~~~~~~ +~~~~~~ That's it! -Before its first use, please execute ```volk_gnsssdr_profile``` to let your system know which is the fastest available implementation. This only has to be done once: +Before its first use, please execute ```volk_gnsssdr_profile``` to let +your system know which is the fastest available implementation. This +only has to be done once: -~~~~~~ +~~~~~~ $ volk_gnsssdr_profile ~~~~~~ -From now on, GNSS-SDR (and any other program of your own that makes use of VOLK_GNSSSDR) will benefit from the acceleration provided by SIMD instructions available in your processor. +From now on, GNSS-SDR (and any other program of your own that makes use +of VOLK_GNSSSDR) will benefit from the acceleration provided by SIMD +instructions available in your processor. -The execution of ```volk_gnsssdr_profile``` can be set automatically after building, leaving your system ready to use: +The execution of ```volk_gnsssdr_profile``` can be set automatically +after building, leaving your system ready to use: ~~~~~~ $ cmake -DENABLE_PROFILING=ON ../ @@ -49,22 +84,35 @@ $ sudo make install ~~~~~~ -This figure shows the role of some VOLK_GNSSSDR kernels in the context of a GNSS baseband processor: +This figure shows the role of some VOLK_GNSSSDR kernels in the context +of a GNSS baseband processor: -![Example of VOLK_GNSSSDR usage.](./docs/images/VOLK_GNSSSDR_Usage_Example.png) +![Example of VOLK_GNSSSDR +usage.](./docs/images/VOLK_GNSSSDR_Usage_Example.png) -If you use VOLK_GNSSSDR in your research and/or software, please cite the following paper: +If you use VOLK_GNSSSDR in your research and/or software, please cite +the following paper: - * C. Fernández-Prades, J. Arribas, P. Closas, [*Accelerating GNSS Software Receivers*](https://zenodo.org/record/266493#.WJR8j7bhB89), in Proc. of the ION GNSS+ 2016 Conference, pp. 44-61, Portland, Oregon, Sept. 12-16, 2016. + * C. Fernández-Prades, J. Arribas, P. Closas, [*Accelerating +GNSS Software Receivers*](https://zenodo.org/record/266493), in Proc. of +the ION GNSS+ 2016 Conference, pp. 44-61, Portland, Oregon, Sept. 12-16, 2016. -Citations are useful for the continued development and maintenance of the library. +Citations are useful for the continued development and maintenance of +the library. ___ -VOLK_GNSSSDR was originally created by Andres Cecilia Luque in the framework of the [Summer Of Code In Space (SOCIS 2014)](http://sophia.estec.esa.int/socis2014/?q=about "SOCIS 2014 webpage") program organized by the European Space Agency, and then evolved and maintained by Carles Fernández-Prades and Javier Arribas. This software is released under the GNU General Public License version 3, see the file COPYING. +VOLK_GNSSSDR was originally created by Andres Cecilia Luque in the +framework of the [Summer Of Code In Space (SOCIS +2014)](http://sophia.estec.esa.int/socis2014/?q=about "SOCIS 2014 +webpage") program organized by the European Space Agency, and then +evolved and maintained by Carles Fernández-Prades and Javier +Arribas. This software is released under the GNU General Public License +version 3, see the file COPYING. -This project is managed by [Centre Tecnologic de Telecomunicacions de Catalunya](http://www.cttc.es "CTTC webpage"). +This project is managed by [Centre Tecnologic de Telecomunicacions de +Catalunya](http://www.cttc.es "CTTC webpage"). diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/CMakeLists.txt index 40d38a9a1..b1afa4ed0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -14,7 +14,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # ######################################################################## @@ -22,7 +22,7 @@ ######################################################################## if(MSVC) include_directories(${PROJECT_SOURCE_DIR}/cmake/msvc) -endif(MSVC) +endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR} @@ -34,39 +34,52 @@ include_directories( ${Boost_INCLUDE_DIRS} ) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(Clang_required_link "c++") -elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(Clang_required_link "") -endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + +set(Clang_required_link "") +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(Clang_required_link "c++") + endif() +endif() + if(ORC_FOUND) set(orc_lib ${ORC_LIBRARIES}) -elseif(ORC_FOUND) +else() set(orc_lib "") -endif(ORC_FOUND) +endif() + + +# allow 'large' files in 32 bit builds +if(UNIX) + add_definitions(-D_LARGEFILE_SOURCE + -D_FILE_OFFSET_BITS=64 + -D_LARGE_FILES + ) +endif() # MAKE volk_gnsssdr_profile add_executable(volk_gnsssdr_profile ${CMAKE_CURRENT_SOURCE_DIR}/volk_gnsssdr_profile.cc ${PROJECT_SOURCE_DIR}/lib/qa_utils.cc + ${CMAKE_CURRENT_SOURCE_DIR}/volk_gnsssdr_option_helpers.cc ) if(ENABLE_STATIC_LIBS) target_link_libraries(volk_gnsssdr_profile volk_gnsssdr_static ${Boost_LIBRARIES} ${Clang_required_link} ${orc_lib}) -else(ENABLE_STATIC_LIBS) +else() target_link_libraries(volk_gnsssdr_profile volk_gnsssdr ${Boost_LIBRARIES} ${Clang_required_link} ${orc_lib}) add_dependencies(volk_gnsssdr_profile volk_gnsssdr) -endif(ENABLE_STATIC_LIBS) +endif() if(ENABLE_STRIP) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) set_target_properties(volk_gnsssdr_profile - PROPERTIES LINK_FLAGS "-s") - endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) -endif(ENABLE_STRIP) + PROPERTIES LINK_FLAGS "-s") + endif() +endif() install( @@ -75,35 +88,22 @@ install( COMPONENT "volk_gnsssdr" ) -# Launch volk_gnsssdr_profile if requested to do so -if(ENABLE_PROFILING) - if(DEFINED VOLK_CONFIGPATH) - set( VOLK_CONFIG_ARG "-p${VOLK_CONFIGPATH}" ) - set( VOLK_CONFIG "${VOLK_CONFIGPATH}/volk_gnsssdr_config" ) - endif() - add_custom_command(OUTPUT ${VOLK_CONFIG} - COMMAND volk_gnsssdr_profile "${VOLK_CONFIG_ARG}" - DEPENDS volk_gnsssdr_profile - COMMENT "Launching profiler, this may take a few minutes..." - ) - add_custom_target(volk-gnsssdr-profile-run ALL DEPENDS ${VOLK_CONFIG}) -endif() # MAKE volk_gnsssdr-config-info -add_executable(volk_gnsssdr-config-info volk_gnsssdr-config-info.cc) +add_executable(volk_gnsssdr-config-info volk_gnsssdr-config-info.cc ${CMAKE_CURRENT_SOURCE_DIR}/volk_gnsssdr_option_helpers.cc) if(ENABLE_STATIC_LIBS) - target_link_libraries(volk_gnsssdr-config-info volk_gnsssdr_static ${Boost_LIBRARIES} ${Clang_required_link} ${orc_lib}) -else(ENABLE_STATIC_LIBS) - target_link_libraries(volk_gnsssdr-config-info volk_gnsssdr ${Boost_LIBRARIES} ${Clang_required_link} ${orc_lib}) - add_dependencies(volk_gnsssdr-config-info volk_gnsssdr) -endif(ENABLE_STATIC_LIBS) + target_link_libraries(volk_gnsssdr-config-info volk_gnsssdr_static ${Clang_required_link} ${orc_lib}) +else() + target_link_libraries(volk_gnsssdr-config-info volk_gnsssdr ${Clang_required_link} ${orc_lib}) + add_dependencies(volk_gnsssdr-config-info volk_gnsssdr) +endif() if(ENABLE_STRIP) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) set_target_properties(volk_gnsssdr-config-info - PROPERTIES LINK_FLAGS "-s") - endif(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) -endif(ENABLE_STRIP) + PROPERTIES LINK_FLAGS "-s") + endif() +endif() install( TARGETS volk_gnsssdr-config-info @@ -111,3 +111,17 @@ install( COMPONENT "volk_gnsssdr" ) + +# Launch volk_gnsssdr_profile if requested to do so +if(ENABLE_PROFILING) + if(DEFINED VOLK_CONFIGPATH) + set( VOLK_CONFIG_ARG "-p${VOLK_CONFIGPATH}" ) + set( VOLK_CONFIG "${VOLK_CONFIGPATH}/volk_gnsssdr_config" ) + endif() + add_custom_command(OUTPUT ${VOLK_CONFIG} + COMMAND volk_gnsssdr_profile "${VOLK_CONFIG_ARG}" + DEPENDS volk_gnsssdr_profile + COMMENT "Launching profiler, this may take a few minutes..." + ) + add_custom_target(volk-gnsssdr-profile-run ALL DEPENDS ${VOLK_CONFIG}) +endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr-config-info.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr-config-info.cc index 084855ed6..ffc551ac1 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr-config-info.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr-config-info.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,95 +13,65 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #if HAVE_CONFIG_H #include #endif -#include -#include "volk_gnsssdr/volk_gnsssdr.h" -#include -#include +#include "volk_gnsssdr/volk_gnsssdr.h" // for volk_gnsssdr_get_alignment, volk_gnsssdr_get_machine +#include "volk_gnsssdr_option_helpers.h" // for option_list, option_t +#include // for volk_gnsssdr_available_machines, volk_gnsssdr_c_compiler ... +#include // for operator<<, endl, cout, ostream +#include // for string -namespace po = boost::program_options; - -int -main(int argc, char **argv) +void print_alignment() { - po::options_description desc("Program options: volk_gnsssdr-config-info [options]"); - po::variables_map vm; - - desc.add_options() - ("help,h", "print help message") - ("prefix", "print VOLK_GNSSSDR installation prefix") - ("cc", "print VOLK_GNSSSDR C compiler version") - ("cflags", "print VOLK_GNSSSDR CFLAGS") - ("all-machines", "print VOLK_GNSSSDR machines built into library") - ("avail-machines", "print VOLK_GNSSSDR machines the current platform can use") - ("machine", "print the VOLK_GNSSSDR machine that will be used") - ("alignment", "print the alignment that will be used") - ("malloc", "print malloc implementation that will be used") - ("version,v", "print VOLK_GNSSSDR version") - ; - - try { - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - } - catch (po::error& error){ - std::cerr << "Error: " << error.what() << std::endl << std::endl; - std::cerr << desc << std::endl; - return 1; - } - - if(vm.size() == 0 || vm.count("help")) { - std::cout << desc << std::endl; - return 1; - } - - if(vm.count("prefix")) - std::cout << volk_gnsssdr_prefix() << std::endl; - - if(vm.count("version")) - std::cout << volk_gnsssdr_version() << std::endl; - - if(vm.count("cc")) - std::cout << volk_gnsssdr_c_compiler() << std::endl; - - if(vm.count("cflags")) - std::cout << volk_gnsssdr_compiler_flags() << std::endl; - - // stick an extra ';' to make output of this and avail-machines the - // same structure for easier parsing - if(vm.count("all-machines")) - std::cout << volk_gnsssdr_available_machines() << ";" << std::endl; - - if(vm.count("avail-machines")) { - volk_gnsssdr_list_machines(); - } - - if(vm.count("machine")) { - std::cout << volk_gnsssdr_get_machine() << std::endl; - } - - if(vm.count("alignment")) { - std::cout << "Alignment in bytes: " << volk_gnsssdr_get_alignment() << std::endl; - } - - // You don't want to change the volk_malloc code, so just copy the if/else - // structure from there and give an explanation for the implementations - if(vm.count("malloc")) { - std::cout << "Used malloc implementation: "; - #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN - std::cout << "posix_memalign" << std::endl; - #elif _MSC_VER >= 1400 - std::cout << "aligned_malloc" << std::endl; - #else - std::cout << "No standard handler available, using own implementation." << std::endl; - #endif - } - - return 0; + std::cout << "Alignment in bytes: " << volk_gnsssdr_get_alignment() << std::endl; +} + + +void print_malloc() +{ + // You don't want to change the volk_malloc code, so just copy the if/else + // structure from there and give an explanation for the implementations + std::cout << "Used malloc implementation: "; +#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN + std::cout << "posix_memalign" << std::endl; +#elif _MSC_VER >= 1400 + std::cout << "aligned_malloc" << std::endl; +#else + std::cout << "No standard handler available, using own implementation." << std::endl; +#endif +} + + +int main(int argc, char **argv) +{ + option_list our_options("volk_gnsssdr-config-info"); + our_options.add(option_t("prefix", "", "print the VOLK_GNSSSDR installation prefix", volk_gnsssdr_prefix())); + our_options.add(option_t("cc", "", "print the VOLK_GNSSDR C compiler version", volk_gnsssdr_c_compiler())); + our_options.add(option_t("cflags", "", "print the VOLK_GNSSSDR CFLAGS", volk_gnsssdr_compiler_flags())); + our_options.add(option_t("all-machines", "", "print VOLK_GNSSSDR machines built", volk_gnsssdr_available_machines())); + our_options.add(option_t("avail-machines", "", + "print VOLK_GNSSSDR machines on the current " + "platform", + volk_gnsssdr_list_machines)); + our_options.add(option_t("machine", "", "print the current VOLK_GNSSSDR machine that will be used", + volk_gnsssdr_get_machine())); + our_options.add(option_t("alignment", "", "print the memory alignment", print_alignment)); + our_options.add(option_t("malloc", "", "print the malloc implementation used in volk_gnsssdr_malloc", + print_malloc)); + our_options.add(option_t("version", "v", "print the VOLK_GNSSSDR version", volk_gnsssdr_version())); + + try + { + our_options.parse(argc, argv); + } + catch (...) + { + return 1; + } + return 0; } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.cc new file mode 100644 index 000000000..3c1853d05 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.cc @@ -0,0 +1,198 @@ +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + */ + +#include "volk_gnsssdr_option_helpers.h" +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include // for exception +#include // for operator<<, endl, basic_ostream, cout, ostream +#include // for pair + + +/* + * Option type + */ +option_t::option_t(std::string longform, std::string shortform, std::string msg, void (*callback)()) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + callback(callback) { option_type = VOID_CALLBACK; } + +option_t::option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(int)) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + callback((void (*)())callback) { option_type = INT_CALLBACK; } + +option_t::option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(float)) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + callback((void (*)())callback) { option_type = FLOAT_CALLBACK; } + +option_t::option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(bool)) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + callback((void (*)())callback) { option_type = BOOL_CALLBACK; } + +option_t::option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(std::string)) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + callback((void (*)())callback) { option_type = STRING_CALLBACK; } + +option_t::option_t(std::string longform, std::string shortform, std::string msg, std::string printval) + : longform("--" + longform), + shortform("-" + shortform), + msg(msg), + printval(printval) { option_type = STRING; } + + +/* + * Option List + */ + +option_list::option_list(std::string program_name) : program_name(program_name) +{ + { + internal_list = std::vector(); + } +} + +void option_list::add(const option_t &opt) { internal_list.push_back(opt); } + +void option_list::parse(int argc, char **argv) +{ + for (int arg_number = 0; arg_number < argc; ++arg_number) + { + for (std::vector::iterator this_option = internal_list.begin(); + this_option != internal_list.end(); + this_option++) + { + if (this_option->longform == std::string(argv[arg_number]) || + this_option->shortform == std::string(argv[arg_number])) + { + switch (this_option->option_type) + { + case VOID_CALLBACK: + this_option->callback(); + break; + case INT_CALLBACK: + try + { + int int_val = std::stoi(argv[++arg_number]); + ((void (*)(int))this_option->callback)(int_val); + } + catch (std::exception &exc) + { + std::cout << "An int option can only receive a number" << std::endl; + throw std::exception(); + }; + break; + case FLOAT_CALLBACK: + try + { + int int_val = std::stof(argv[++arg_number]); + ((void (*)(float))this_option->callback)(int_val); + } + catch (std::exception &exc) + { + std::cout << "A float option can only receive a number" << std::endl; + throw std::exception(); + }; + break; + case BOOL_CALLBACK: + try + { + bool int_val = (bool)std::stoi(argv[++arg_number]); + ((void (*)(bool))this_option->callback)(int_val); + } + catch (std::exception &exc) + { + std::cout << "A bool option can only receive 0 or 1" << std::endl; + throw std::exception(); + }; + break; + case STRING_CALLBACK: + try + { + ((void (*)(std::string))this_option->callback)(argv[++arg_number]); + } + catch (std::exception &exc) + { + throw std::exception(); + }; + break; + case STRING: + std::cout << this_option->printval << std::endl; + break; + default: + this_option->callback(); + break; + } + } + } + if (std::string("--help") == std::string(argv[arg_number]) || + std::string("-h") == std::string(argv[arg_number])) + { + help(); + } + } +} + +void option_list::help() +{ + std::cout << program_name << std::endl; + std::cout << " -h [ --help ] \t\tDisplay this help message" << std::endl; + for (std::vector::iterator this_option = internal_list.begin(); + this_option != internal_list.end(); + this_option++) + { + std::string help_line(" "); + if (this_option->shortform == "-") + { + help_line += this_option->longform + " "; + } + else + { + help_line += this_option->shortform + " [ " + this_option->longform + " ]"; + } + + switch (help_line.size() / 8) + { + case 0: + help_line += "\t\t\t\t"; + break; + case 1: + help_line += "\t\t\t"; + break; + case 2: + help_line += "\t\t"; + break; + case 3: + help_line += "\t"; + break; + default: + break; + } + help_line += this_option->msg; + std::cout << help_line << std::endl; + } +} diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.h new file mode 100644 index 000000000..cd8a6258c --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_option_helpers.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + */ + +#ifndef VOLK_GNSSSDR_OPTION_HELPERS_H +#define VOLK_GNSSSDR_OPTION_HELPERS_H + +#include +#include +#include +#include +#include + + +typedef enum +{ + VOID_CALLBACK, + INT_CALLBACK, + BOOL_CALLBACK, + STRING_CALLBACK, + FLOAT_CALLBACK, + STRING, +} VOLK_OPTYPE; + +class option_t +{ +public: + option_t(std::string longform, std::string shortform, std::string msg, void (*callback)()); + option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(int)); + option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(float)); + option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(bool)); + option_t(std::string longform, std::string shortform, std::string msg, void (*callback)(std::string)); + option_t(std::string longform, std::string shortform, std::string msg, std::string printval); + + std::string longform; + std::string shortform; + std::string msg; + VOLK_OPTYPE option_type; + std::string printval; + void (*callback)(); +}; + +class option_list +{ +public: + option_list(std::string program_name); + + void add(const option_t &opt); + + void parse(int argc, char **argv); + + void help(); + +private: + std::string program_name; + std::vector internal_list; +}; + + +#endif //VOLK_GNSSSDR_OPTION_HELPERS_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.cc index c1b764210..c211ed710 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,215 +13,168 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ -#include "qa_utils.h" -#include "kernel_tests.h" #include "volk_gnsssdr_profile.h" +#include "kernel_tests.h" // for init_test_list +#include "qa_utils.h" // for volk_gnsssdr_test_results_t +#include "volk_gnsssdr/volk_gnsssdr_complex.h" // for lv_32fc_t +#include "volk_gnsssdr/volk_gnsssdr_prefs.h" // for volk_gnsssdr_get_config_path +#include "volk_gnsssdr_option_helpers.h" // for option_list, option_t +#include // for create_directories, exists +#include // for path, operator<< +#include // for filesystem +#include // for size_t +#include // IWYU pragma: keep +#include // for operator<<, basic_ostream +#include // for map, map<>::iterator +#include // for stat +#include // for pair +#include // for vector, vector<>::const_.. -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include namespace fs = boost::filesystem; -int main(int argc, char *argv[]) { - // Adding program options - boost::program_options::options_description desc("Options"); - desc.add_options() - ("help,h", "Print help messages") - ("benchmark,b", - boost::program_options::value()->default_value( false ) - ->implicit_value( true ), - "Run all kernels (benchmark mode)") - ("tol,t", - boost::program_options::value()->default_value( 1e-6 ), - "Set the default error tolerance for tests") - ("vlen,v", - boost::program_options::value()->default_value( 8111 ), //it is also prime - "Set the default vector length for tests") // default is a mersenne prime - ("iter,i", - boost::program_options::value()->default_value( 1987 ), - "Set the default number of test iterations per kernel") - ("tests-regex,R", - boost::program_options::value(), - "Run tests matching regular expression.") - ("update,u", - boost::program_options::value()->default_value( false ) - ->implicit_value( true ), - "Run only kernels missing from config; use -R to further restrict the candidates") - ("dry-run,n", - boost::program_options::value()->default_value( false ) - ->implicit_value( true ), - "Dry run. Respect other options, but don't write to file") - ("json,j", - boost::program_options::value(), - "JSON output file") - ("path,p", - boost::program_options::value(), - "Specify volk_config path.") - ; +volk_gnsssdr_test_params_t test_params(1e-6f, 327.f, 8111, 1987, false, ""); - // Handle the options that were given - boost::program_options::variables_map vm; - bool benchmark_mode; - std::string kernel_regex; - std::ofstream json_file; - float def_tol; - lv_32fc_t def_scalar; - int def_iter; - int def_vlen; - bool def_benchmark_mode; - std::string def_kernel_regex; - bool update_mode = false; - bool dry_run = false; - std::string config_file; +void set_benchmark(bool val) { test_params.set_benchmark(val); } +void set_tolerance(float val) { test_params.set_tol(val); } +void set_vlen(int val) { test_params.set_vlen((unsigned int)val); } +void set_iter(int val) { test_params.set_iter((unsigned int)val); } +void set_substr(std::string val) { test_params.set_regex(val); } +bool update_mode = false; +void set_update(bool val) { update_mode = val; } +bool dry_run = false; +void set_dryrun(bool val) { dry_run = val; } +std::string json_filename(""); +void set_json(std::string val) { json_filename = val; } +std::string volk_config_path(""); +void set_volk_config(std::string val) { volk_config_path = val; } - // Handle the provided options - try { - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); - boost::program_options::notify(vm); - benchmark_mode = vm.count("benchmark")?vm["benchmark"].as():false; - if ( vm.count("tests-regex" ) ) { - kernel_regex = vm["tests-regex"].as(); +int main(int argc, char *argv[]) +{ + option_list profile_options("volk_gnsssdr_profile"); + profile_options.add(option_t("benchmark", "b", "Run all kernels (benchmark mode)", set_benchmark)); + profile_options.add(option_t("tol", "t", "Set the default tolerance for all tests", set_tolerance)); + profile_options.add(option_t("vlen", "v", "Set the default vector length for tests", set_vlen)); + profile_options.add((option_t("iter", "i", "Set the default number of test iterations per kernel", set_iter))); + profile_options.add((option_t("tests-substr", "R", "Run tests matching substring", set_substr))); + profile_options.add((option_t("update", "u", "Run only kernels missing from config", set_update))); + profile_options.add((option_t("dry-run", "n", "Dry run. Respect other options, but don't write to file", set_dryrun))); + profile_options.add((option_t("json", "j", "Write results to JSON file named as argument value", set_json))); + profile_options.add((option_t("path", "p", "Specify the volk_config path", set_volk_config))); + + try + { + profile_options.parse(argc, argv); } - else { - kernel_regex = ".*"; - } - - def_tol = vm["tol"].as(); - def_scalar = 327.0; - def_vlen = vm["vlen"].as(); - def_iter = vm["iter"].as(); - def_benchmark_mode = benchmark_mode; - def_kernel_regex = kernel_regex; - update_mode = vm["update"].as(); - dry_run = vm["dry-run"].as(); - } - catch (boost::program_options::error& error) { - std::cerr << "Error: " << error.what() << std::endl << std::endl; - std::cerr << desc << std::endl; - return 1; - } - - /** --help option */ - if ( vm.count("help") ) { - std::cout << "The VOLK_GNSSSDR profiler." << std::endl - << desc << std::endl; - return 0; - } - - if ( vm.count("json") ) { - std::string filename; - try { - filename = vm["json"].as(); - } - catch (boost::bad_any_cast& error) { - std::cerr << error.what() << std::endl; + catch (...) + { return 1; } - json_file.open( filename.c_str() ); - } - if ( vm.count("path") ) { - try { - config_file = vm["path"].as() + "/volk_config"; + for (int arg_number = 0; arg_number < argc; ++arg_number) + { + if (std::string("--help") == std::string(argv[arg_number]) || + std::string("-h") == std::string(argv[arg_number])) + { + return 0; } - catch (boost::bad_any_cast& error) { - std::cerr << error.what() << std::endl; - return 1; - } - } + } + // Adding program options + std::ofstream json_file; + std::string config_file; - volk_gnsssdr_test_params_t test_params(def_tol, def_scalar, def_vlen, def_iter, - def_benchmark_mode, def_kernel_regex); + if (json_filename != "") + { + json_file.open(json_filename.c_str()); + } + + if (volk_config_path != "") + { + config_file = volk_config_path + "/volk_config"; + } // Run tests std::vector results; - if(update_mode) { - read_results(&results); - if( vm.count("path") ) read_results(&results, config_file); - else read_results(&results); - } - + if (update_mode) + { + if (config_file != "") + read_results(&results, config_file); + else + read_results(&results); + } // Initialize the list of tests - // the default test parameters come from options std::vector test_cases = init_test_list(test_params); - boost::xpressive::sregex kernel_expression; - try { - kernel_expression = boost::xpressive::sregex::compile(kernel_regex); - } - catch (boost::xpressive::regex_error& error) { - std::cerr << "Error occurred while compiling regex" << std::endl << std::endl; - return 1; - } - // Iteratate through list of tests running each one - for(unsigned int ii = 0; ii < test_cases.size(); ++ii) { - bool regex_match = true; + // Iterate through list of tests running each one + std::string substr_to_match(test_params.kernel_regex()); + for (unsigned int ii = 0; ii < test_cases.size(); ++ii) + { + bool regex_match = true; - volk_gnsssdr_test_case_t test_case = test_cases[ii]; - // if the kernel name matches regex then do the test - if(boost::xpressive::regex_search(test_case.name(), kernel_expression)) { - regex_match = true; - } - else { - regex_match = false; - } - - // if we are in update mode check if we've already got results - // if we have any, then no need to test that kernel - bool update = true; - if(update_mode) { - for(unsigned int jj=0; jj < results.size(); ++jj) { - if(results[jj].name == test_case.name() || - results[jj].name == test_case.puppet_master_name()) { - update = false; - break; + volk_gnsssdr_test_case_t test_case = test_cases[ii]; + // if the kernel name matches regex then do the test + std::string test_case_name = test_case.name(); + if (test_case_name.find(substr_to_match) == std::string::npos) + { + regex_match = false; } - } - } - if( regex_match && update ) { - try { - run_volk_gnsssdr_tests(test_case.desc(), test_case.kernel_ptr(), test_case.name(), - test_case.test_parameters(), &results, test_case.puppet_master_name()); - } - catch (std::string error) { - std::cerr << "Caught Exception in 'run_volk_gnsssdr_tests': " << error << std::endl; - } + // if we are in update mode check if we've already got results + // if we have any, then no need to test that kernel + bool update = true; + if (update_mode) + { + for (unsigned int jj = 0; jj < results.size(); ++jj) + { + if (results[jj].name == test_case.name() || + results[jj].name == test_case.puppet_master_name()) + { + update = false; + break; + } + } + } + if (regex_match && update) + { + try + { + run_volk_gnsssdr_tests(test_case.desc(), test_case.kernel_ptr(), test_case.name(), + test_case.test_parameters(), &results, test_case.puppet_master_name()); + } + catch (std::string &error) + { + std::cerr << "Caught Exception in 'run_volk_gnsssdr_tests': " << error << std::endl; + } + } } - } // Output results according to provided options - if(vm.count("json")) { - write_json(json_file, results); - json_file.close(); - } + if (json_filename != "") + { + write_json(json_file, results); + json_file.close(); + } - if(!dry_run) { - write_results(&results, false); - if(vm.count("path")) write_results(&results, false, config_file); - else write_results(&results, false); - } - else { - std::cout << "Warning: this was a dry-run. Config not generated" << std::endl; - } + if (!dry_run) + { + if (config_file != "") + write_results(&results, false, config_file); + else + write_results(&results, false); + } + else + { + std::cout << "Warning: this was a dry-run. Config not generated" << std::endl; + } } + void read_results(std::vector *results) { char path[1024]; @@ -232,51 +185,56 @@ void read_results(std::vector *results) void read_results(std::vector *results, std::string path) { - const fs::path config_path(path); + struct stat buffer; + bool config_status = (stat(path.c_str(), &buffer) == 0); - if(fs::exists(config_path)) { - // a config exists and we are reading results from it - std::ifstream config(config_path.string().c_str()); - char config_line[256]; - while(config.getline(config_line, 255)) { - // tokenize the input line by kernel_name unaligned aligned - // then push back in the results vector with fields filled in + if (config_status) + { + // a config exists and we are reading results from it + std::ifstream config(path.c_str()); + char config_line[256]; + while (config.getline(config_line, 255)) + { + // tokenize the input line by kernel_name unaligned aligned + // then push back in the results vector with fields filled in - std::vector single_kernel_result; - std::string config_str(config_line); - std::size_t str_size = config_str.size(); - std::size_t found = 1; + std::vector single_kernel_result; + std::string config_str(config_line); + std::size_t str_size = config_str.size(); + std::size_t found = 1; - found = config_str.find(" "); - // Split line by spaces - while(found && found < str_size) { - found = config_str.find(" "); - // kernel names MUST be less than 128 chars, which is - // a length restricted by volk_gnsssdr/volk_gnsssdr_prefs.c - // on the last token in the parsed string we won't find a space - // so make sure we copy at most 128 chars. - if(found > 127) { - found = 127; + found = config_str.find(' '); + // Split line by spaces + while (found && found < str_size) + { + found = config_str.find(' '); + // kernel names MUST be less than 128 chars, which is + // a length restricted by volk/volk_prefs.c + // on the last token in the parsed string we won't find a space + // so make sure we copy at most 128 chars. + if (found > 127) + { + found = 127; + } + str_size = config_str.size(); + char buffer[128] = {'\0'}; + config_str.copy(buffer, found + 1, 0); + buffer[found] = '\0'; + single_kernel_result.push_back(std::string(buffer)); + config_str.erase(0, found + 1); + } + + if (single_kernel_result.size() == 3) + { + volk_gnsssdr_test_results_t kernel_result; + kernel_result.name = std::string(single_kernel_result[0]); + kernel_result.config_name = std::string(single_kernel_result[0]); + kernel_result.best_arch_u = std::string(single_kernel_result[1]); + kernel_result.best_arch_a = std::string(single_kernel_result[2]); + results->push_back(kernel_result); + } } - str_size = config_str.size(); - char buffer[128] = {'\0'}; - config_str.copy(buffer, found + 1, 0); - buffer[found] = '\0'; - single_kernel_result.push_back(std::string(buffer)); - config_str.erase(0, found+1); - } - - if(single_kernel_result.size() == 3) { - volk_gnsssdr_test_results_t kernel_result; - kernel_result.name = std::string(single_kernel_result[0]); - kernel_result.config_name = std::string(single_kernel_result[0]); - kernel_result.best_arch_u = std::string(single_kernel_result[1]); - kernel_result.best_arch_a = std::string(single_kernel_result[2]); - results->push_back(kernel_result); - } } - } - } void write_results(const std::vector *results, bool update_result) @@ -284,7 +242,7 @@ void write_results(const std::vector *results, bool char path[1024]; volk_gnsssdr_get_config_path(path); - write_results( results, update_result, std::string(path)); + write_results(results, update_result, std::string(path)); } void write_results(const std::vector *results, bool update_result, const std::string path) @@ -292,39 +250,44 @@ void write_results(const std::vector *results, bool const fs::path config_path(path); // Until we can update the config on a kernel by kernel basis // do not overwrite volk_gnsssdr_config when using a regex. - if (not fs::exists(config_path.branch_path())) - { - std::cout << "Creating " << config_path.branch_path() << "..." << std::endl; - fs::create_directories(config_path.branch_path()); - } + if (!fs::exists(config_path.branch_path())) + { + std::cout << "Creating " << config_path.branch_path() << " ..." << std::endl; + fs::create_directories(config_path.branch_path()); + } std::ofstream config; - if(update_result) { - std::cout << "Updating " << config_path << "..." << std::endl; - config.open(config_path.string().c_str(), std::ofstream::app); - if (!config.is_open()) { //either we don't have write access or we don't have the dir yet - std::cout << "Error opening file " << config_path << std::endl; - } - } - else { - std::cout << "Writing " << config_path << "..." << std::endl; - config.open(config_path.string().c_str()); - if (!config.is_open()) { //either we don't have write access or we don't have the dir yet - std::cout << "Error opening file " << config_path << std::endl; + if (update_result) + { + std::cout << "Updating " << path << " ..." << std::endl; + config.open(path.c_str(), std::ofstream::app); + if (!config.is_open()) + { //either we don't have write access or we don't have the dir yet + std::cout << "Error opening file " << path << std::endl; + } } + else + { + std::cout << "Writing " << path << " ..." << std::endl; + config.open(path.c_str()); + if (!config.is_open()) + { //either we don't have write access or we don't have the dir yet + std::cout << "Error opening file " << path << std::endl; + } - config << "\ + config << "\ #this file is generated by volk_gnsssdr_profile.\n\ #the function name is followed by the preferred architecture.\n\ "; - } + } std::vector::const_iterator profile_results; - for(profile_results = results->begin(); profile_results != results->end(); ++profile_results) { - config << profile_results->config_name << " " - << profile_results->best_arch_a << " " - << profile_results->best_arch_u << std::endl; - } + for (profile_results = results->begin(); profile_results != results->end(); ++profile_results) + { + config << profile_results->config_name << " " + << profile_results->best_arch_a << " " + << profile_results->best_arch_u << std::endl; + } config.close(); } @@ -335,43 +298,45 @@ void write_json(std::ofstream &json_file, std::vector::iterator result; - for(result = results.begin(); result != results.end(); ++result) { - json_file << " {" << std::endl; - json_file << " \"name\": \"" << result->name << "\"," << std::endl; - json_file << " \"vlen\": " << (int)(result->vlen) << "," << std::endl; - json_file << " \"iter\": " << result->iter << "," << std::endl; - json_file << " \"best_arch_a\": \"" << result->best_arch_a - << "\"," << std::endl; - json_file << " \"best_arch_u\": \"" << result->best_arch_u - << "\"," << std::endl; - json_file << " \"results\": {" << std::endl; - size_t results_len = result->results.size(); - size_t ri = 0; + for (result = results.begin(); result != results.end(); ++result) + { + json_file << " {" << std::endl; + json_file << " \"name\": \"" << result->name << "\"," << std::endl; + json_file << " \"vlen\": " << (int)(result->vlen) << "," << std::endl; + json_file << " \"iter\": " << result->iter << "," << std::endl; + json_file << " \"best_arch_a\": \"" << result->best_arch_a + << "\"," << std::endl; + json_file << " \"best_arch_u\": \"" << result->best_arch_u + << "\"," << std::endl; + json_file << " \"results\": {" << std::endl; + size_t results_len = result->results.size(); + size_t ri = 0; - std::map::iterator kernel_time_pair; - for(kernel_time_pair = result->results.begin(); kernel_time_pair != result->results.end(); ++kernel_time_pair) { - volk_gnsssdr_test_time_t time = kernel_time_pair->second; - json_file << " \"" << time.name << "\": {" << std::endl; - json_file << " \"name\": \"" << time.name << "\"," << std::endl; - json_file << " \"time\": " << time.time << "," << std::endl; - json_file << " \"units\": \"" << time.units << "\"" << std::endl; - json_file << " }" ; - if(ri+1 != results_len) { - json_file << ","; - } + std::map::iterator kernel_time_pair; + for (kernel_time_pair = result->results.begin(); kernel_time_pair != result->results.end(); ++kernel_time_pair) + { + volk_gnsssdr_test_time_t time = kernel_time_pair->second; + json_file << " \"" << time.name << "\": {" << std::endl; + json_file << " \"name\": \"" << time.name << "\"," << std::endl; + json_file << " \"time\": " << time.time << "," << std::endl; + json_file << " \"units\": \"" << time.units << "\"" << std::endl; + json_file << " }"; + if (ri + 1 != results_len) + { + json_file << ","; + } + json_file << std::endl; + ri++; + } + json_file << " }" << std::endl; + json_file << " }"; + if (i + 1 != len) + { + json_file << ","; + } json_file << std::endl; - ri++; + i++; } - json_file << " }" << std::endl; - json_file << " }"; - if(i+1 != len) { - json_file << ","; - } - json_file << std::endl; - i++; - } json_file << " ]" << std::endl; json_file << "}" << std::endl; } - - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.h index 4530c6be7..33187a87d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/apps/volk_gnsssdr_profile.h @@ -4,7 +4,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -22,11 +22,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#include // for bool +#include // for ofstream +#include // for string +#include // for vector + +class volk_gnsssdr_test_results_t; void read_results(std::vector *results); diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/CMakeParseArgumentsCopy.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/CMakeParseArgumentsCopy.cmake index 7ce4c49ae..66016cb2f 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/CMakeParseArgumentsCopy.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/CMakeParseArgumentsCopy.cmake @@ -58,7 +58,7 @@ # the new option. # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would -# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore. #============================================================================= # Copyright 2010 Alexander Neundorf diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/FindORC.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/FindORC.cmake index 8e8e4f292..1154d2e7a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/FindORC.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/FindORC.cmake @@ -1,52 +1,71 @@ -FIND_PACKAGE(PkgConfig) -PKG_CHECK_MODULES(PC_ORC "orc-0.4 > 0.4.22") +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +find_package(PkgConfig) +pkg_check_modules(PC_ORC "orc-0.4 > 0.4.22") +find_program(ORCC_EXECUTABLE orcc + HINTS ${PC_ORC_TOOLSDIR} + PATHS ${ORC_ROOT}/bin ${CMAKE_INSTALL_PREFIX}/bin +) -FIND_PROGRAM(ORCC_EXECUTABLE orcc - HINTS ${PC_ORC_TOOLSDIR} - PATHS ${ORC_ROOT}/bin ${CMAKE_INSTALL_PREFIX}/bin) - -FIND_PATH(ORC_INCLUDE_DIR NAMES orc/orc.h - HINTS ${PC_ORC_INCLUDEDIR} - PATHS ${ORC_ROOT}/include/orc-0.4 ${CMAKE_INSTALL_PREFIX}/include/orc-0.4) - - -FIND_PATH(ORC_LIBRARY_DIR NAMES ${CMAKE_SHARED_LIBRARY_PREFIX}orc-0.4${CMAKE_SHARED_LIBRARY_SUFFIX} - HINTS ${PC_ORC_LIBDIR} - /usr/local/lib - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib64 - /usr/lib - PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - -FIND_LIBRARY(ORC_LIB orc-0.4 - HINTS ${PC_ORC_LIBRARY_DIRS} - PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - -LIST(APPEND ORC_LIBRARY - ${ORC_LIB} +find_path(ORC_INCLUDE_DIR NAMES orc/orc.h + HINTS ${PC_ORC_INCLUDEDIR} + PATHS ${ORC_ROOT}/include/orc-0.4 ${CMAKE_INSTALL_PREFIX}/include/orc-0.4 ) -SET(ORC_INCLUDE_DIRS ${ORC_INCLUDE_DIR}) -SET(ORC_LIBRARIES ${ORC_LIBRARY}) -SET(ORC_LIBRARY_DIRS ${ORC_LIBRARY_DIR}) +find_path(ORC_LIBRARY_DIR + NAMES ${CMAKE_SHARED_LIBRARY_PREFIX}orc-0.4${CMAKE_SHARED_LIBRARY_SUFFIX} + HINTS ${PC_ORC_LIBDIR} + /usr/local/lib + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib64 + /usr/lib + PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} +) -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(ORC "orc files" ORC_LIBRARY ORC_INCLUDE_DIR ORCC_EXECUTABLE) +find_library(ORC_LIB orc-0.4 + HINTS ${PC_ORC_LIBRARY_DIRS} + PATHS ${ORC_ROOT}/lib${LIB_SUFFIX} ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) + +list(APPEND ORC_LIBRARY + ${ORC_LIB} +) + + +set(ORC_INCLUDE_DIRS ${ORC_INCLUDE_DIR}) +set(ORC_LIBRARIES ${ORC_LIBRARY}) +set(ORC_LIBRARY_DIRS ${ORC_LIBRARY_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ORC "orc files" ORC_LIBRARY ORC_INCLUDE_DIR ORCC_EXECUTABLE) mark_as_advanced(ORC_INCLUDE_DIR ORC_LIBRARY ORCC_EXECUTABLE) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkAddTest.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkAddTest.cmake index 4106678e8..a2097046e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkAddTest.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkAddTest.cmake @@ -1,45 +1,59 @@ -# Copyright 2015 Free Software Foundation, Inc. +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) # -# This file is part of Volk +# This file is part of GNSS-SDR. # -# Volk 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. +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# Volk 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. +# GNSS-SDR 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 Volk; see the file COPYING. If not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Boston, MA -# 02110-1301, USA. +# along with GNSS-SDR. If not, see . if(DEFINED __INCLUDED_VOLK_ADD_TEST) return() endif() set(__INCLUDED_VOLK_ADD_TEST TRUE) +######################################################################## +# Generate a test executable which can be used in ADD_TEST to call +# various subtests. +# +# SOURCES - sources for the test +# TARGET_DEPS - build target dependencies (e.g., libraries) +######################################################################## + +function(VOLK_GEN_TEST executable_name) + include(CMakeParseArgumentsCopy) + cmake_parse_arguments(VOLK_TEST "" "" "SOURCES;TARGET_DEPS;EXTRA_LIB_DIRS;ENVIRONS;ARGS" ${ARGN}) + add_executable(${executable_name} ${VOLK_TEST_SOURCES}) + target_link_libraries(${executable_name} ${VOLK_TEST_TARGET_DEPS}) +endfunction() + ######################################################################## # Add a unit test and setup the environment for it. # Encloses ADD_TEST, with additional functionality to create a shell # script that sets the environment to gain access to in-build binaries # properly. The following variables are used to pass in settings: +# A test executable has to be generated with VOLK_GEN_TEST beforehand. +# The executable name has to be passed as argument. # # NAME - the test name -# SOURCES - sources for the test # TARGET_DEPS - build target dependencies (e.g., libraries) # EXTRA_LIB_DIRS - other directories for the library path # ENVIRONS - other environment key/value pairs # ARGS - arguments for the test ######################################################################## -function(VOLK_ADD_TEST test_name) +function(VOLK_ADD_TEST test_name executable_name) #parse the arguments for component names include(CMakeParseArgumentsCopy) - CMAKE_PARSE_ARGUMENTS(VOLK_TEST "" "" "SOURCES;TARGET_DEPS;EXTRA_LIB_DIRS;ENVIRONS;ARGS" ${ARGN}) + cmake_parse_arguments(VOLK_TEST "" "" "TARGET_DEPS;EXTRA_LIB_DIRS;ENVIRONS;ARGS" ${ARGN}) #set the initial environs to use set(environs ${VOLK_TEST_ENVIRONS}) @@ -65,7 +79,7 @@ function(VOLK_ADD_TEST test_name) #"add_test" command, via the $ operator; make sure the #test's directory is first, since it ($1) is prepended to PATH. unset(TARGET_DIR_LIST) - foreach(target ${test_name} ${VOLK_TEST_TARGET_DEPS}) + foreach(target ${executable_name} ${VOLK_TEST_TARGET_DEPS}) list(APPEND TARGET_DIR_LIST "\$") endforeach() @@ -132,20 +146,19 @@ function(VOLK_ADD_TEST test_name) #each line sets an environment variable foreach(environ ${environs}) file(APPEND ${sh_file} "export ${environ}\n") - endforeach(environ) + endforeach() + + set(VOLK_TEST_ARGS "${test_name}") #redo the test args to have a space between each string(REPLACE ";" " " VOLK_TEST_ARGS "${VOLK_TEST_ARGS}") #finally: append the test name to execute - file(APPEND ${sh_file} ${test_name} " " ${VOLK_TEST_ARGS} "\n") + file(APPEND ${sh_file} "${CMAKE_CROSSCOMPILING_EMULATOR} ${executable_name} ${VOLK_TEST_ARGS}\n") #make the shell file executable execute_process(COMMAND chmod +x ${sh_file}) - add_executable(${test_name} ${VOLK_TEST_SOURCES}) - target_link_libraries(${test_name} ${VOLK_TEST_TARGET_DEPS}) - #add the shell file as the test to execute; #use the form that allows for $ substitutions, #then combine the script arguments inside the script. @@ -153,7 +166,7 @@ function(VOLK_ADD_TEST test_name) COMMAND ${SHELL} ${sh_file} ${TARGET_DIR_LIST} ) - endif(UNIX) + endif() if(WIN32) #In the land of windows, all libraries must be in the PATH. Since @@ -161,20 +174,19 @@ function(VOLK_ADD_TEST test_name) #set them in the PATH to run tests. The following appends the #path of a target dependency. # - #NOTE: get_target_property LOCATION is being deprecated as of - #CMake 3.2.0, which just prints a warning & notes that this - #functionality will be removed in the future. Leave it here for - #now until someone can figure out how to do this in Windows. - foreach(target ${test_name} ${VOLK_TEST_TARGET_DEPS}) - get_target_property(location "${target}" LOCATION) - if(location) - get_filename_component(path ${location} PATH) - string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path}) - list(APPEND libpath ${path}) - endif(location) - endforeach(target) + #create a list of target directories to be determined by the + #"add_test" command, via the $ operator; make sure the + #test's directory is first, since it ($1) is prepended to PATH. + unset(TARGET_DIR_LIST) + foreach(target ${executable_name} ${VOLK_TEST_TARGET_DEPS}) + list(APPEND TARGET_DIR_LIST "$") + endforeach() + #replace list separator with the path separator (escaped) + string(REPLACE ";" "\\\\;" TARGET_DIR_LIST "${TARGET_DIR_LIST}") - list(APPEND libpath ${DLL_PATHS} "%PATH%") + #add command line argument (TARGET_DIR_LIST) to path and append current path + list(INSERT libpath 0 "%1") + list(APPEND libpath "%PATH%") #replace list separator with the path separator (escaped) string(REPLACE ";" "\\;" libpath "${libpath}") @@ -187,19 +199,21 @@ function(VOLK_ADD_TEST test_name) #each line sets an environment variable foreach(environ ${environs}) file(APPEND ${bat_file} "SET ${environ}\n") - endforeach(environ) + endforeach() + + set(VOLK_TEST_ARGS "${test_name}") #redo the test args to have a space between each string(REPLACE ";" " " VOLK_TEST_ARGS "${VOLK_TEST_ARGS}") #finally: append the test name to execute - file(APPEND ${bat_file} ${test_name} " " ${VOLK_TEST_ARGS} "\n") + file(APPEND ${bat_file} "${executable_name} ${VOLK_TEST_ARGS}\n") file(APPEND ${bat_file} "\n") - add_executable(${test_name} ${VOLK_TEST_SOURCES}) - target_link_libraries(${test_name} ${VOLK_TEST_TARGET_DEPS}) + add_test(NAME qa_${test_name} + COMMAND ${bat_file} ${TARGET_DIR_LIST} + ) + endif() - add_test(${test_name} ${bat_file}) - endif(WIN32) +endfunction() -endfunction(VOLK_ADD_TEST) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBoost.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBoost.cmake index 9afa9f8b5..2aea96b2a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBoost.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBoost.cmake @@ -1,21 +1,19 @@ -# Copyright 2010-2011 Free Software Foundation, Inc. +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) # -# This file is part of GNU Radio +# This file is part of GNSS-SDR. # -# GNU Radio is free software; you can redistribute it and/or modify +# GNSS-SDR 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. +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# GNU Radio is distributed in the hope that it will be useful, +# GNSS-SDR 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. +# along with GNSS-SDR. If not, see . if(DEFINED __INCLUDED_VOLK_BOOST_CMAKE) return() @@ -29,27 +27,25 @@ set(__INCLUDED_VOLK_BOOST_CMAKE TRUE) set(BOOST_REQUIRED_COMPONENTS filesystem system - unit_test_framework - program_options ) if(UNIX AND NOT BOOST_ROOT AND EXISTS "/usr/lib64") list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix -endif(UNIX AND NOT BOOST_ROOT AND EXISTS "/usr/lib64") +endif() if(MSVC) set(BOOST_REQUIRED_COMPONENTS ${BOOST_REQUIRED_COMPONENTS} chrono) - if (NOT DEFINED BOOST_ALL_DYN_LINK) + if(NOT DEFINED BOOST_ALL_DYN_LINK) set(BOOST_ALL_DYN_LINK TRUE) endif() set(BOOST_ALL_DYN_LINK "${BOOST_ALL_DYN_LINK}" CACHE BOOL "boost enable dynamic linking") if(BOOST_ALL_DYN_LINK) add_definitions(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc - else(BOOST_ALL_DYN_LINK) + else() unset(BOOST_REQUIRED_COMPONENTS) #empty components list for static link - endif(BOOST_ALL_DYN_LINK) -endif(MSVC) + endif() +endif() find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) @@ -65,15 +61,17 @@ set(Boost_ADDITIONAL_VERSIONS "1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59" "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" + "1.70.0" "1.70" "1.71.0" "1.71" "1.72.0" "1.72" "1.73.0" "1.73" "1.74.0" "1.74" + "1.75.0" "1.75" "1.76.0" "1.76" "1.77.0" "1.77" "1.78.0" "1.78" "1.79.0" "1.79" ) # Boost 1.52 disabled, see https://svn.boost.org/trac/boost/ticket/7669 # Similar problems with Boost 1.46 and 1.47. -OPTION(ENABLE_BAD_BOOST "Enable known bad versions of Boost" OFF) +option(ENABLE_BAD_BOOST "Enable known bad versions of Boost" OFF) if(ENABLE_BAD_BOOST) - MESSAGE(STATUS "Enabling use of known bad versions of Boost.") -endif(ENABLE_BAD_BOOST) + message(STATUS "Enabling use of known bad versions of Boost.") +endif() # For any unsuitable Boost version, add the version number below in # the following format: XXYYZZ @@ -82,17 +80,17 @@ endif(ENABLE_BAD_BOOST) # YY is the minor version number ('46' for 1.46) # ZZ is the patcher version number (typically just '00') set(Boost_NOGO_VERSIONS - 104600 104601 104700 105200 - ) + 104600 104601 104700 105200 +) foreach(ver ${Boost_NOGO_VERSIONS}) - if("${Boost_VERSION}" STREQUAL "${ver}") - if(NOT ENABLE_BAD_BOOST) - MESSAGE(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Disabling.") - set(Boost_FOUND FALSE) - else(NOT ENABLE_BAD_BOOST) - MESSAGE(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Continuing anyway.") - set(Boost_FOUND TRUE) - endif(NOT ENABLE_BAD_BOOST) - endif("${Boost_VERSION}" STREQUAL "${ver}") -endforeach(ver) + if("${Boost_VERSION}" STREQUAL "${ver}") + if(NOT ENABLE_BAD_BOOST) + message(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Disabling.") + set(Boost_FOUND FALSE) + else() + message(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Continuing anyway.") + set(Boost_FOUND TRUE) + endif() + endif() +endforeach() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBuildTypes.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBuildTypes.cmake index 345415e8f..6f45f1683 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBuildTypes.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkBuildTypes.cmake @@ -1,21 +1,19 @@ -# Copyright 2014 Free Software Foundation, Inc. +# Copyright (C) 2014-2018 (see AUTHORS file for a list of contributors) # -# This file is part of VOLK +# This file is part of GNSS-SDR. # -# VOLK is free software; you can redistribute it and/or modify +# GNSS-SDR 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. +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# VOLK is distributed in the hope that it will be useful, +# GNSS-SDR 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. +# along with GNSS-SDR. If not, see . if(DEFINED __INCLUDED_VOLK_BUILD_TYPES_CMAKE) return() @@ -29,7 +27,7 @@ set(__INCLUDED_VOLK_BUILD_TYPES_CMAKE TRUE) # - RelWithDebInfo: -O3 -g # - MinSizeRel: -Os -# Addtional Build Types, defined below: +# Additional Build Types, defined below: # - NoOptWithASM: -O0 -g -save-temps # - O2WithASM: -O2 -g -save-temps # - O3WithASM: -O3 -g -save-temps @@ -40,6 +38,7 @@ set(__INCLUDED_VOLK_BUILD_TYPES_CMAKE TRUE) list(APPEND AVAIL_BUILDTYPES None Debug Release RelWithDebInfo MinSizeRel DebugParanoid NoOptWithASM O2WithASM O3WithASM + ASAN ) ######################################################################## @@ -54,16 +53,16 @@ list(APPEND AVAIL_BUILDTYPES # the avialable build types. ######################################################################## function(VOLK_CHECK_BUILD_TYPE settype) - STRING(TOUPPER ${settype} _settype) + string(TOUPPER ${settype} _settype) foreach(btype ${AVAIL_BUILDTYPES}) - STRING(TOUPPER ${btype} _btype) + string(TOUPPER ${btype} _btype) if(${_settype} STREQUAL ${_btype}) return() # found it; exit cleanly - endif(${_settype} STREQUAL ${_btype}) - endforeach(btype) + endif() + endforeach() # Build type not found; error out message(FATAL_ERROR "Build type '${settype}' not valid, must be one of: ${AVAIL_BUILDTYPES}") -endfunction(VOLK_CHECK_BUILD_TYPE) +endfunction() ######################################################################## # For GCC and Clang, we can set a build type: @@ -75,23 +74,23 @@ endfunction(VOLK_CHECK_BUILD_TYPE) # NOTE: This is not defined on Windows systems. ######################################################################## if(NOT WIN32) - SET(CMAKE_CXX_FLAGS_DEBUGPARANOID "-Wall -Wextra -g -O0" CACHE STRING + set(CMAKE_CXX_FLAGS_DEBUGPARANOID "-Wall -Wextra -g -O0" CACHE STRING "Flags used by the C++ compiler during DebugParanoid builds." FORCE) - SET(CMAKE_C_FLAGS_DEBUGPARANOID "-Wall -Wextra -g -O0" CACHE STRING + set(CMAKE_C_FLAGS_DEBUGPARANOID "-Wall -Wextra -g -O0" CACHE STRING "Flags used by the C compiler during DebugParanoid builds." FORCE) - SET(CMAKE_EXE_LINKER_FLAGS_DEBUGPARANOID + set(CMAKE_EXE_LINKER_FLAGS_DEBUGPARANOID "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used for linking binaries during NoOptWithASM builds." FORCE) - SET(CMAKE_SHARED_LINKER_FLAGS_DEBUGPARANOID + set(CMAKE_SHARED_LINKER_FLAGS_DEBUGPARANOID "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used by the shared lib linker during NoOptWithASM builds." FORCE) - MARK_AS_ADVANCED( + mark_as_advanced( CMAKE_CXX_FLAGS_DEBUGPARANOID CMAKE_C_FLAGS_DEBUGPARANOID CMAKE_EXE_LINKER_FLAGS_DEBUGPARANOID CMAKE_SHARED_LINKER_DEBUGPARANOID) -endif(NOT WIN32) +endif() ######################################################################## @@ -106,23 +105,23 @@ endif(NOT WIN32) # NOTE: This is not defined on Windows systems. ######################################################################## if(NOT WIN32) - SET(CMAKE_CXX_FLAGS_NOOPTWITHASM "-save-temps -g -O0" CACHE STRING + set(CMAKE_CXX_FLAGS_NOOPTWITHASM "-save-temps -g -O0" CACHE STRING "Flags used by the C++ compiler during NoOptWithASM builds." FORCE) - SET(CMAKE_C_FLAGS_NOOPTWITHASM "-save-temps -g -O0" CACHE STRING + set(CMAKE_C_FLAGS_NOOPTWITHASM "-save-temps -g -O0" CACHE STRING "Flags used by the C compiler during NoOptWithASM builds." FORCE) - SET(CMAKE_EXE_LINKER_FLAGS_NOOPTWITHASM + set(CMAKE_EXE_LINKER_FLAGS_NOOPTWITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used for linking binaries during NoOptWithASM builds." FORCE) - SET(CMAKE_SHARED_LINKER_FLAGS_NOOPTWITHASM + set(CMAKE_SHARED_LINKER_FLAGS_NOOPTWITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used by the shared lib linker during NoOptWithASM builds." FORCE) - MARK_AS_ADVANCED( + mark_as_advanced( CMAKE_CXX_FLAGS_NOOPTWITHASM CMAKE_C_FLAGS_NOOPTWITHASM CMAKE_EXE_LINKER_FLAGS_NOOPTWITHASM CMAKE_SHARED_LINKER_FLAGS_NOOPTWITHASM) -endif(NOT WIN32) +endif() ######################################################################## @@ -138,23 +137,23 @@ endif(NOT WIN32) ######################################################################## if(NOT WIN32) - SET(CMAKE_CXX_FLAGS_O2WITHASM "-save-temps -g -O2" CACHE STRING + set(CMAKE_CXX_FLAGS_O2WITHASM "-save-temps -g -O2" CACHE STRING "Flags used by the C++ compiler during O2WithASM builds." FORCE) - SET(CMAKE_C_FLAGS_O2WITHASM "-save-temps -g -O2" CACHE STRING + set(CMAKE_C_FLAGS_O2WITHASM "-save-temps -g -O2" CACHE STRING "Flags used by the C compiler during O2WithASM builds." FORCE) - SET(CMAKE_EXE_LINKER_FLAGS_O2WITHASM + set(CMAKE_EXE_LINKER_FLAGS_O2WITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used for linking binaries during O2WithASM builds." FORCE) - SET(CMAKE_SHARED_LINKER_FLAGS_O2WITHASM + set(CMAKE_SHARED_LINKER_FLAGS_O2WITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used by the shared lib linker during O2WithASM builds." FORCE) - MARK_AS_ADVANCED( + mark_as_advanced( CMAKE_CXX_FLAGS_O2WITHASM CMAKE_C_FLAGS_O2WITHASM CMAKE_EXE_LINKER_FLAGS_O2WITHASM CMAKE_SHARED_LINKER_FLAGS_O2WITHASM) -endif(NOT WIN32) +endif() ######################################################################## @@ -170,20 +169,42 @@ endif(NOT WIN32) ######################################################################## if(NOT WIN32) - SET(CMAKE_CXX_FLAGS_O3WITHASM "-save-temps -g -O3" CACHE STRING + set(CMAKE_CXX_FLAGS_O3WITHASM "-save-temps -g -O3" CACHE STRING "Flags used by the C++ compiler during O3WithASM builds." FORCE) - SET(CMAKE_C_FLAGS_O3WITHASM "-save-temps -g -O3" CACHE STRING + set(CMAKE_C_FLAGS_O3WITHASM "-save-temps -g -O3" CACHE STRING "Flags used by the C compiler during O3WithASM builds." FORCE) - SET(CMAKE_EXE_LINKER_FLAGS_O3WITHASM + set(CMAKE_EXE_LINKER_FLAGS_O3WITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used for linking binaries during O3WithASM builds." FORCE) - SET(CMAKE_SHARED_LINKER_FLAGS_O3WITHASM + set(CMAKE_SHARED_LINKER_FLAGS_O3WITHASM "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING "Flags used by the shared lib linker during O3WithASM builds." FORCE) - MARK_AS_ADVANCED( + mark_as_advanced( CMAKE_CXX_FLAGS_O3WITHASM CMAKE_C_FLAGS_O3WITHASM CMAKE_EXE_LINKER_FLAGS_O3WITHASM CMAKE_SHARED_LINKER_FLAGS_O3WITHASM) -endif(NOT WIN32) +endif() + +######################################################################## +# For GCC and Clang, we can set a build type: +# +# -DCMAKE_BUILD_TYPE=ASAN +# +# This type creates an address sanitized build (-fsanitize=address) +# and defaults to the DebugParanoid linker flags. +# NOTE: This is not defined on Windows systems. +######################################################################## +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_ASAN "-Wall -Wextra -g -O2 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING + "Flags used by the C++ compiler during Address Sanitized builds." FORCE) + set(CMAKE_C_FLAGS_ASAN "-Wall -Wextra -g -O2 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING + "Flags used by the C compiler during Address Sanitized builds." FORCE) + mark_as_advanced( + CMAKE_CXX_FLAGS_ASAN + CMAKE_C_FLAGS_ASAN + CMAKE_EXE_LINKER_FLAGS_DEBUGPARANOID + CMAKE_SHARED_LINKER_DEBUGPARANOID) +endif() + diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfig.cmake.in b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfig.cmake.in index f07b02d50..af9e75169 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfig.cmake.in +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfig.cmake.in @@ -1,30 +1,47 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_VOLK_GNSSSDR volk_gnsssdr) +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . -FIND_PATH( +include(FindPkgConfig) +pkg_check_modules(PC_VOLK_GNSSSDR volk_gnsssdr) + +find_path( VOLK_GNSSSDR_INCLUDE_DIRS NAMES volk_gnsssdr/volk_gnsssdr.h HINTS $ENV{VOLK_DIR}/include ${PC_VOLK_INCLUDEDIR} PATHS /usr/local/include - /usr/include - /opt/local/include - "@CMAKE_INSTALL_PREFIX@/include" + /usr/include + /opt/local/include + "@CMAKE_INSTALL_PREFIX@/include" ) -FIND_LIBRARY( +find_library( VOLK_GNSSSDR_LIBRARIES NAMES volk_gnsssdr HINTS $ENV{VOLK_DIR}/lib ${PC_VOLK_LIBDIR} PATHS /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 - /opt/local/lib - "@CMAKE_INSTALL_PREFIX@/lib" + /usr/local/lib64 + /usr/lib + /usr/lib64 + /opt/local/lib + "@CMAKE_INSTALL_PREFIX@/lib" ) -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK_GNSSSDR DEFAULT_MSG VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) -MARK_AS_ADVANCED(VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VOLKGNSSSDR DEFAULT_MSG VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) +mark_as_advanced(VOLK_GNSSSDR_LIBRARIES VOLK_GNSSSDR_INCLUDE_DIRS) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfigVersion.cmake.in b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfigVersion.cmake.in index 265daeb8e..7808c7dbe 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfigVersion.cmake.in +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkGnsssdrConfigVersion.cmake.in @@ -1,21 +1,19 @@ -# Copyright 2014 Free Software Foundation, Inc. +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) # -# This file is part of VOLK. +# This file is part of GNSS-SDR. # -# VOLK is free software; you can redistribute it and/or modify +# GNSS-SDR 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. +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# VOLK is distributed in the hope that it will be useful, +# GNSS-SDR 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 VOLK; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. +# along with GNSS-SDR. If not, see . set(MAJOR_VERSION @VERSION_INFO_MAJOR_VERSION@) set(MINOR_VERSION @VERSION_INFO_MINOR_VERSION@) @@ -29,6 +27,6 @@ if(${PACKAGE_FIND_VERSION_MAJOR} EQUAL ${MAJOR_VERSION}) if(NOT ${PACKAGE_FIND_VERSION_PATCH} GREATER ${MAINT_VERSION}) set(PACKAGE_VERSION_EXACT 1) # exact match for API version set(PACKAGE_VERSION_COMPATIBLE 1) # compat for minor/patch version - endif(NOT ${PACKAGE_FIND_VERSION_PATCH} GREATER ${MINOR_VERSION}) - endif(${PACKAGE_FIND_VERSION_MINOR} EQUAL ${API_COMPAT}) -endif(${PACKAGE_FIND_VERSION_MAJOR} EQUAL ${MAJOR_VERSION}) + endif() + endif() +endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake index dc6571e93..06c51883c 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake @@ -1,21 +1,19 @@ -# Copyright 2010-2011,2013 Free Software Foundation, Inc. +# Copyright (C) 2015-2018 (see AUTHORS file for a list of contributors) # -# This file is part of GNU Radio +# This file is part of GNSS-SDR. # -# GNU Radio is free software; you can redistribute it and/or modify +# GNSS-SDR 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. +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# GNU Radio is distributed in the hope that it will be useful, +# GNSS-SDR 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. +# along with GNSS-SDR. If not, see . if(DEFINED __INCLUDED_VOLK_PYTHON_CMAKE) return() @@ -27,42 +25,39 @@ set(__INCLUDED_VOLK_PYTHON_CMAKE TRUE) # This allows the user to specify a specific interpreter, # or finds the interpreter via the built-in cmake module. ######################################################################## -#this allows the user to override PYTHON_EXECUTABLE -if(PYTHON_EXECUTABLE) +set(VOLK_PYTHON_MIN_VERSION "2.7") +set(VOLK_PYTHON3_MIN_VERSION "3.4") - set(PYTHONINTERP_FOUND TRUE) - -#otherwise if not set, try to automatically find it -else(PYTHON_EXECUTABLE) - - #use the built-in find script - set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6) - find_package(PythonInterp 2) - - #and if that fails use the find program routine - if(NOT PYTHONINTERP_FOUND) - find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python3) - if(PYTHON_EXECUTABLE) - set(PYTHONINTERP_FOUND TRUE) - endif(PYTHON_EXECUTABLE) - endif(NOT PYTHONINTERP_FOUND) - -endif(PYTHON_EXECUTABLE) - -#make the path to the executable appear in the cmake gui -set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") - -#make sure we can use -B with python (introduced in 2.6) -if(PYTHON_EXECUTABLE) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -B -c "" - OUTPUT_QUIET ERROR_QUIET - RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT - ) - if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) - set(PYTHON_DASH_B "-B") +if(CMAKE_VERSION VERSION_LESS 3.12) + if(PYTHON_EXECUTABLE) + message(STATUS "User set python executable ${PYTHON_EXECUTABLE}") + find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION} REQUIRED) + else() + message(STATUS "PYTHON_EXECUTABLE not set - using default python2") + message(STATUS "Use -DPYTHON_EXECUTABLE=/path/to/python3 to build for python3.") + find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION}) + if(NOT PYTHONINTERP_FOUND) + message(STATUS "python2 not found - using python3") + find_package(PythonInterp ${VOLK_PYTHON3_MIN_VERSION} REQUIRED) + endif() endif() -endif(PYTHON_EXECUTABLE) + find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT) +else() + if(PYTHON_EXECUTABLE) + message(STATUS "User set python executable ${PYTHON_EXECUTABLE}") + find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION} REQUIRED) + else() + find_package(Python COMPONENTS Interpreter) + set(PYTHON_VERSION_MAJOR ${Python_VERSION_MAJOR}) + set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) + endif() +endif() + +if(${PYTHON_VERSION_MAJOR} VERSION_EQUAL 3) + set(PYTHON3 TRUE) +endif() + + ######################################################################## # Check for the existence of a python module: @@ -71,37 +66,45 @@ endif(PYTHON_EXECUTABLE) # - cmd an additional command to run # - have the result variable to set ######################################################################## -macro(VOLK_PYTHON_CHECK_MODULE desc mod cmd have) - message(STATUS "") - message(STATUS "Python checking for ${desc}") +macro(VOLK_PYTHON_CHECK_MODULE_RAW desc python_code have) execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c " -######################################### -try: import ${mod} -except: - try: ${mod} - except: exit(-1) -try: assert ${cmd} -except: exit(-1) -#########################################" - RESULT_VARIABLE ${have} + COMMAND ${PYTHON_EXECUTABLE} -c "${python_code}" + OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE return_code ) - if(${have} EQUAL 0) + if(return_code EQUAL 0) message(STATUS "Python checking for ${desc} - found") set(${have} TRUE) - else(${have} EQUAL 0) + else() message(STATUS "Python checking for ${desc} - not found") set(${have} FALSE) - endif(${have} EQUAL 0) -endmacro(VOLK_PYTHON_CHECK_MODULE) + endif() +endmacro() + +macro(VOLK_PYTHON_CHECK_MODULE desc mod cmd have) + VOLK_PYTHON_CHECK_MODULE_RAW( + "${desc}" " +######################################### +try: + import ${mod} + assert ${cmd} +except (ImportError, AssertionError): exit(-1) +except: pass +#########################################" + "${have}") +endmacro() ######################################################################## # Sets the python installation directory VOLK_PYTHON_DIR ######################################################################## if(NOT DEFINED VOLK_PYTHON_DIR) execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " -from distutils import sysconfig -print(sysconfig.get_python_lib(plat_specific=True, prefix='')) +import os +import sys +if os.name == 'posix': + print(os.path.join('lib', 'python' + sys.version[:3], 'dist-packages')) +if os.name == 'nt': + print(os.path.join('Lib', 'site-packages')) " OUTPUT_VARIABLE VOLK_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() @@ -118,14 +121,14 @@ unique = hashlib.md5(b'${reldir}${ARGN}').hexdigest()[:5] print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))" OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE) add_custom_target(${_target} ALL DEPENDS ${ARGN}) -endfunction(VOLK_UNIQUE_TARGET) +endfunction() ######################################################################## # Install python sources (also builds and installs byte-compiled python) ######################################################################## function(VOLK_PYTHON_INSTALL) include(CMakeParseArgumentsCopy) - CMAKE_PARSE_ARGUMENTS(VOLK_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) + cmake_parse_arguments(VOLK_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) #################################################################### if(VOLK_PYTHON_INSTALL_FILES) @@ -159,7 +162,7 @@ function(VOLK_PYTHON_INSTALL) get_filename_component(pygen_path ${pygenfile} PATH) file(MAKE_DIRECTORY ${pygen_path}) - endforeach(pyfile) + endforeach() #the command to generate the pyc files add_custom_command( @@ -186,8 +189,8 @@ function(VOLK_PYTHON_INSTALL) #################################################################### file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native) - if (CMAKE_CROSSCOMPILING) - set(pyexe_native "/usr/bin/env python") + if(CMAKE_CROSSCOMPILING) + set(pyexe_native "/usr/bin/env python") endif() foreach(pyfile ${VOLK_PYTHON_INSTALL_PROGRAMS}) @@ -202,7 +205,7 @@ function(VOLK_PYTHON_INSTALL) add_custom_command( OUTPUT ${pyexefile} DEPENDS ${pyfile} COMMAND ${PYTHON_EXECUTABLE} -c - "open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())" + "open('${pyexefile}','w').write(r'\#!${pyexe_native}'+'\\n'+open('${pyfile}').read())" COMMENT "Shebangin ${pyfile_name}" VERBATIM ) @@ -217,13 +220,13 @@ function(VOLK_PYTHON_INSTALL) DESTINATION ${VOLK_PYTHON_INSTALL_DESTINATION} COMPONENT ${VOLK_PYTHON_INSTALL_COMPONENT} ) - endforeach(pyfile) + endforeach() endif() - VOLK_UNIQUE_TARGET("pygen" ${python_install_gen_targets}) + volk_unique_target("pygen" ${python_install_gen_targets}) -endfunction(VOLK_PYTHON_INSTALL) +endfunction() ######################################################################## # Write the python helper script that generates byte code files diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkVersion.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkVersion.cmake index 4ed349aac..33d5f21db 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkVersion.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkVersion.cmake @@ -1,21 +1,19 @@ -# Copyright 2014 Free Software Foundation, Inc. +# Copyright (C) 2014-2018 (see AUTHORS file for a list of contributors) # -# This file is part of VOLK. +# This file is part of GNSS-SDR. # -# VOLK is free software; you can redistribute it and/or modify +# GNSS-SDR 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. +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# VOLK is distributed in the hope that it will be useful, +# GNSS-SDR 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 VOLK; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. +# along with GNSS-SDR. If not, see . if(DEFINED __INCLUDED_VOLK_VERSION_CMAKE) return() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage index be69e4aba..6f273a82b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage @@ -1,14 +1,14 @@ -.\" Manpage for volk_gnsssdr-config-info +.\" Manpage for volk_gnsssdr\-config\-info .\" Contact carles.fernandez@cttc.es to correct errors or typos. -.TH volk_gnsssdr_profile 1 "06 Feb 2017" "0.0.9" "volk_gnsssdr-config-info man page" +.TH volk_gnsssdr\-config\-info 1 "12 Dec 2018" "0.0.10" "volk_gnsssdr\-config\-info man page" .SH NAME -\fBvolk_gnsssdr-config-info\fR \- Prints configuration information of libvolk_gnsssdr functions. +\fBvolk_gnsssdr\-config\-info\fR \- Prints configuration information of libvolk_gnsssdr functions. .SH SYNOPSIS -\fBvolk_gnsssdr-config-info\fR [OPTION] +\fBvolk_gnsssdr\-config\-info\fR [OPTION] .SH DESCRIPTION -This program prints configuration information for the Vector-Optimized Library of Kernels of GNSS-SDR (VOLK_GNSSSDR). +This program prints configuration information for the Vector\-Optimized Library of Kernels of GNSS\-SDR (VOLK_GNSSSDR). .SH OPTIONS -\fBvolk_gnsssdr-config-info\fR takes the following options: +\fBvolk_gnsssdr\-config\-info\fR takes the following options: .TP \fB-h\fR [ \fB--help\fR ] Print help message. .TP @@ -33,8 +33,8 @@ This program prints configuration information for the Vector-Optimized Library o .BR volk_gnsssdr_profile (1) .BR gnss-sdr (1) \.TP -Check http://gnss-sdr.org for more information. +Check https://gnss\-sdr.org for more information. .SH BUGS No known bugs. .SH AUTHOR -Carles Fernandez-Prades (carles.fernandez@cttc.es) \ No newline at end of file +Carles Fernandez-Prades (carles.fernandez@cttc.es) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage index 159bbfee1..99a9ae316 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage @@ -1,6 +1,6 @@ .\" Manpage for volk_gnsssdr_profile .\" Contact carles.fernandez@cttc.es to correct errors or typos. -.TH volk_gnsssdr_profile 1 "06 Feb 2017" "0.0.9" "volk_gnsssdr_profile man page" +.TH volk_gnsssdr_profile 1 "12 Dec 2018" "0.0.10" "volk_gnsssdr_profile man page" .SH NAME \fBvolk_gnsssdr_profile\fR \- Profiler application for libvolk_gnsssdr functions. .SH SYNOPSIS @@ -10,7 +10,7 @@ The Vector-Optimized Library of Kernels of GNSS-SDR (VOLK_GNSSSDR) is a software .TP Processors providing SIMD instruction sets compute with multiple processing elements that perform the same operation on multiple data points simultaneously, thus exploiting data-level parallelism, an can be found in most modern desktop and laptop personal computers. In a nutshell, VOLK_GNSSSDR implements in assembly language optimized versions of computationally-intensive operations for different processor architectures that are commonly found in modern computers. In order to use the most optimized version for the specific processor(s) of the host machine running the software receiver (that is, the implementation than runs the fastest). .TP -\fBvolk_gnsssdr_profile\fR is a program that tests all known VOLK_GNSSSDR kernels (that is, basic processing components like adders, multipliers, correlators, and much more) for each architecture supported by the host machine, measuring their performance. When finished, the profiler writes to $HOME/.volk_gnsssdr/volk_gnsssdr_config the best architecture for each VOLK_GSSSDR function. This file is read when using a function to know the best version to execute. +\fBvolk_gnsssdr_profile\fR is a program that tests all known VOLK_GNSSSDR kernels (that is, basic processing components like adders, multipliers, correlators, and much more) for each architecture supported by the host machine, measuring their performance. When finished, the profiler writes to $HOME/.volk_gnsssdr/volk_gnsssdr_config the best architecture for each VOLK_GSSSDR function. This file is read when using a function to know the best version to execute. .SH OPTIONS \fBvolk_gnsssdr_profile\fR takes the following options: .TP @@ -34,7 +34,7 @@ Processors providing SIMD instruction sets compute with multiple processing elem .SH SEE ALSO .BR gnss-sdr (1) \.TP -Check http://gnss-sdr.org for more information. +Check https://gnss\-sdr.org for more information. .SH HISTORY This library was originally developed by Andres Cecilia Luque in the framework of the Summer of Code in Space program (SOCIS 2014) by the European Space Agency (ESA), and then integrated into \fBgnss-sdr\fR. This software is based on the VOLK library http://libvolk.org/ .SH BUGS @@ -42,4 +42,4 @@ No known bugs. .SH AUTHOR Andres Cecilia Luque (a.cecilia.luque@gmail.com) \.TP -Carles Fernandez-Prades (carles.fernandez@cttc.es) \ No newline at end of file +Carles Fernandez-Prades (carles.fernandez@cttc.es) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a15_hardfp_native.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a15_hardfp_native.cmake new file mode 100644 index 000000000..bbe2f262e --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a15_hardfp_native.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +######################################################################## +# Toolchain file for building native on a ARM Cortex A8 w/ NEON +# Usage: cmake -DCMAKE_TOOLCHAIN_FILE= +######################################################################## +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_FLAGS "-march=armv7-a -mtune=cortex-a15 -mfpu=neon -mfloat-abi=hard" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE) #same flags for C sources diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a9_hardfp_native.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a9_hardfp_native.cmake new file mode 100644 index 000000000..87bfae005 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Toolchains/arm_cortex_a9_hardfp_native.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + +######################################################################## +# Toolchain file for building native on a ARM Cortex A8 w/ NEON +# Usage: cmake -DCMAKE_TOOLCHAIN_FILE= +######################################################################## +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_FLAGS "-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=hard" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE) #same flags for C sources diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/cmake_uninstall.cmake.in b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/cmake_uninstall.cmake.in index 2c34c8199..d026a667a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/cmake_uninstall.cmake.in +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/cmake_uninstall.cmake.in @@ -1,3 +1,21 @@ +# Copyright (C) 2011-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . + + if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") @@ -7,10 +25,10 @@ string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - exec_program( - "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove \"$ENV{DESTDIR}${file}\" OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval + RESULT_VARIABLE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/config.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/config.h index 8b12c2a47..cc76ff9b2 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/config.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/config.h @@ -1,15 +1,34 @@ -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] +/* + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + */ -#ifndef _MSC_CONFIG_H_ // [ +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_CONFIG_H_ // [ #define _MSC_CONFIG_H_ //////////////////////////////////////////////////////////////////////// // enable inline functions for C code //////////////////////////////////////////////////////////////////////// #ifndef __cplusplus -# define inline __inline +#define inline __inline #endif //////////////////////////////////////////////////////////////////////// @@ -23,12 +42,15 @@ typedef ptrdiff_t ssize_t; //////////////////////////////////////////////////////////////////////// #if _MSC_VER < 1800 #include -static inline long lrint(double x){return (long)(x > 0.0 ? x + 0.5 : x - 0.5);} -static inline long lrintf(float x){return (long)(x > 0.0f ? x + 0.5f : x - 0.5f);} -static inline long long llrint(double x){return (long long)(x > 0.0 ? x + 0.5 : x - 0.5);} -static inline long long llrintf(float x){return (long long)(x > 0.0f ? x + 0.5f : x - 0.5f);} -static inline double rint(double x){return (x > 0.0)? floor(x + 0.5) : ceil(x - 0.5);} -static inline float rintf(float x){return (x > 0.0f)? floorf(x + 0.5f) : ceilf(x - 0.5f);} +static inline long lrint(double x) +{ + return (long)(x > 0.0 ? x + 0.5 : x - 0.5); +} +static inline long lrintf(float x) { return (long)(x > 0.0f ? x + 0.5f : x - 0.5f); } +static inline long long llrint(double x) { return (long long)(x > 0.0 ? x + 0.5 : x - 0.5); } +static inline long long llrintf(float x) { return (long long)(x > 0.0f ? x + 0.5f : x - 0.5f); } +static inline double rint(double x) { return (x > 0.0) ? floor(x + 0.5) : ceil(x - 0.5); } +static inline float rintf(float x) { return (x > 0.0f) ? floorf(x + 0.5f) : ceilf(x - 0.5f); } #endif //////////////////////////////////////////////////////////////////////// @@ -43,7 +65,10 @@ static inline float rintf(float x){return (x > 0.0f)? floorf(x + 0.5f) : ceilf(x // random and srandom //////////////////////////////////////////////////////////////////////// #include -static inline long int random (void) { return rand(); } -static inline void srandom (unsigned int seed) { srand(seed); } +static inline long int random(void) +{ + return rand(); +} +static inline void srandom(unsigned int seed) { srand(seed); } -#endif // _MSC_CONFIG_H_ ] +#endif // _MSC_CONFIG_H_ ] diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/sys/time.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/sys/time.h new file mode 100644 index 000000000..fc62a7041 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/msvc/sys/time.h @@ -0,0 +1,72 @@ +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_SYS_TIME_H_ +#define _MSC_SYS_TIME_H_ + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +//http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/430449b3-f6dd-4e18-84de-eebd26a8d668 +#include < time.h > +#include //I've omitted this line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +#if _MSC_VER < 1900 +struct timespec +{ + time_t tv_sec; /* Seconds since 00:00:00 GMT, */ + + /* 1 January 1970 */ + + long tv_nsec; /* Additional nanoseconds since */ + + /* tv_sec */ +}; +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +static inline int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/archs.xml b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/archs.xml index ff1de1e15..1f741ac02 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/archs.xml +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/archs.xml @@ -13,12 +13,24 @@ - -mfpu=neon -funsafe-math-optimizations 16 + + -mfpu=neon + -funsafe-math-optimizations + 16 + + + + + -funsafe-math-optimizations + 16 + + + -m32 @@ -226,4 +238,48 @@ 32 + + + + 7 + 0 + 1 + 16 + + + + 2 + 0x00000001 + 27 + + + + -mavx512f + -mavx512f + /arch:AVX512F + 64 + + + + + + 7 + 0 + 1 + 28 + + + + 2 + 0x00000001 + 27 + + + + -mavx512cd + -mavx512cd + /arch:AVX512CD + 64 + + diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/machines.xml b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/machines.xml index b60f336cd..d787a6b14 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/machines.xml +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/machines.xml @@ -5,7 +5,15 @@ -generic neon softfp|hardfp orc| +generic neon orc| + + + +generic neon neonv7 softfp|hardfp orc| + + + +generic neon neonv8 @@ -43,4 +51,14 @@ generic 32|64| mmx| sse sse2 sse3 ssse3 sse4_1 sse4_2 popcount avx fma avx2 orc| + + +generic 32|64| mmx| sse sse2 sse3 ssse3 sse4_1 sse4_2 popcount avx fma avx2 avx512f orc| + + + + +generic 32|64| mmx| sse sse2 sse3 ssse3 sse4_1 sse4_2 popcount avx fma avx2 avx512f avx512cd orc| + + diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_arch_defs.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_arch_defs.py index d1e656d70..f639ae767 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_arch_defs.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_arch_defs.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,7 +15,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # from __future__ import print_function @@ -25,7 +25,7 @@ import six archs = list() arch_dict = dict() -class arch_class: +class arch_class(object): def __init__(self, flags, checks, **kwargs): for key, cast, failval in ( ('name', str, None), @@ -82,7 +82,7 @@ for arch_xml in archs_xml: flags = dict() for flag_xml in arch_xml.getElementsByTagName("flag"): name = flag_xml.attributes["compiler"].value - if not flags.has_key(name): flags[name] = list() + if name not in flags: flags[name] = list() flags[name].append(flag_xml.firstChild.data) #force kwargs keys to be of type str, not unicode for py25 kwargs = dict((str(k), v) for k, v in six.iteritems(kwargs)) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_compile_utils.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_compile_utils.py index 3ddc204d3..5ef4e1c8c 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_compile_utils.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_compile_utils.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,7 +15,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # from __future__ import print_function diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_kernel_defs.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_kernel_defs.py index 90ba0693c..fb1ae58f9 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_kernel_defs.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_kernel_defs.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,7 +15,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # @@ -118,10 +118,10 @@ def flatten_section_text(sections): ######################################################################## # Extract kernel info from section, represent as an implementation ######################################################################## -class impl_class: +class impl_class(object): def __init__(self, kern_name, header, body): #extract LV_HAVE_* - self.deps = set(map(str.lower, re.findall('LV_HAVE_(\w+)', header))) + self.deps = set(res.lower() for res in re.findall('LV_HAVE_(\w+)', header)) #extract function suffix and args body = flatten_section_text(body) try: @@ -138,7 +138,7 @@ class impl_class: arg_type, arg_name = m.groups() self.args.append((arg_type, arg_name)) except Exception as ex: - raise Exception('I cant parse the function prototype from: %s in %s\n%s'%(kern_name, body, ex)) + raise Exception('I can\'t parse the function prototype from: %s in %s\n%s'%(kern_name, body, ex)) assert self.name self.is_aligned = self.name.startswith('a_') @@ -153,18 +153,18 @@ def extract_lv_haves(code): haves = list() for line in code.splitlines(): if not line.strip().startswith('#'): continue - have_set = set(map(str.lower, re.findall('LV_HAVE_(\w+)', line))) + have_set = set(res.lower() for res in re.findall('LV_HAVE_(\w+)', line)) if have_set: haves.append(have_set) return haves ######################################################################## # Represent a processing kernel, parse from file ######################################################################## -class kernel_class: +class kernel_class(object): def __init__(self, kernel_file): self.name = os.path.splitext(os.path.basename(kernel_file))[0] self.pname = self.name.replace('volk_gnsssdr_', 'p_') - code = open(kernel_file, 'r').read() + code = open(kernel_file, 'rb').read().decode("utf-8") code = comment_remover(code) sections = split_into_nested_ifdef_sections(code) self._impls = list() @@ -204,7 +204,7 @@ class kernel_class: ######################################################################## __file__ = os.path.abspath(__file__) srcdir = os.path.dirname(os.path.dirname(__file__)) -kernel_files = glob.glob(os.path.join(srcdir, "kernels", "volk_gnsssdr", "*.h")) +kernel_files = sorted(glob.glob(os.path.join(srcdir, "kernels", "volk_gnsssdr", "*.h"))) kernels = list(map(kernel_class, kernel_files)) if __name__ == '__main__': diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_machine_defs.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_machine_defs.py index bd68c2326..8eb7e5472 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_machine_defs.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_machine_defs.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,7 +15,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # from __future__ import print_function @@ -26,7 +26,7 @@ from volk_gnsssdr_arch_defs import arch_dict machines = list() machine_dict = dict() -class machine_class: +class machine_class(object): def __init__(self, name, archs): self.name = name self.archs = list() @@ -36,7 +36,7 @@ class machine_class: arch = arch_dict[arch_name] self.archs.append(arch) self.arch_names.append(arch_name) - self.alignment = max(map(lambda a: a.alignment, self.archs)) + self.alignment = max([a.alignment for a in self.archs]) def __repr__(self): return self.name diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_tmpl_utils.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_tmpl_utils.py index 200283947..55e466788 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_tmpl_utils.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/gen/volk_gnsssdr_tmpl_utils.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,7 +15,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # from __future__ import print_function diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/constants.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/constants.h index 066f8d6b6..3bcfbe645 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/constants.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/constants.h @@ -3,7 +3,7 @@ * \brief Definition of VOLK_GNSSSDR-related constants * \author Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_CONSTANTS_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/saturation_arithmetic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/saturation_arithmetic.h index 194bb46e3..856c62cb2 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/saturation_arithmetic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/saturation_arithmetic.h @@ -3,7 +3,7 @@ * \brief Defines addition of 16-bit integers with saturation * \author Javier Arribas, 2015. javier.arribas(at)cttc.es * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ @@ -29,7 +29,7 @@ static inline int16_t sat_adds16i(int16_t x, int16_t y) { - int32_t res = (int32_t) x + (int32_t) y; + int32_t res = (int32_t)x + (int32_t)y; if (res < SHRT_MIN) res = SHRT_MIN; if (res > SHRT_MAX) res = SHRT_MAX; @@ -39,7 +39,7 @@ static inline int16_t sat_adds16i(int16_t x, int16_t y) static inline int16_t sat_muls16i(int16_t x, int16_t y) { - int32_t res = (int32_t) x * (int32_t) y; + int32_t res = (int32_t)x * (int32_t)y; if (res < SHRT_MIN) res = SHRT_MIN; if (res > SHRT_MAX) res = SHRT_MAX; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_avx_intrinsics.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_avx_intrinsics.h index b737ea164..e98b24e27 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_avx_intrinsics.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_avx_intrinsics.h @@ -4,7 +4,7 @@ * \brief This file is intended to hold AVX intrinsics of intrinsics. * They should be used in VOLK kernels to avoid copy-paste. * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ @@ -30,40 +30,53 @@ static inline __m256 _mm256_complexmul_ps(__m256 x, __m256 y) { - __m256 yl, yh, tmp1, tmp2; - yl = _mm256_moveldup_ps(y); // Load yl with cr,cr,dr,dr ... - yh = _mm256_movehdup_ps(y); // Load yh with ci,ci,di,di ... - tmp1 = _mm256_mul_ps(x, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr ... - x = _mm256_shuffle_ps(x, x, 0xB1); // Re-arrange x to be ai,ar,bi,br ... - tmp2 = _mm256_mul_ps(x, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - return _mm256_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + __m256 yl, yh, tmp1, tmp2; + yl = _mm256_moveldup_ps(y); // Load yl with cr,cr,dr,dr ... + yh = _mm256_movehdup_ps(y); // Load yh with ci,ci,di,di ... + tmp1 = _mm256_mul_ps(x, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr ... + x = _mm256_shuffle_ps(x, x, 0xB1); // Re-arrange x to be ai,ar,bi,br ... + tmp2 = _mm256_mul_ps(x, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + return _mm256_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di } static inline __m256 -_mm256_conjugate_ps(__m256 x){ - const __m256 conjugator = _mm256_setr_ps(0, -0.f, 0, -0.f, 0, -0.f, 0, -0.f); - return _mm256_xor_ps(x, conjugator); // conjugate y +_mm256_conjugate_ps(__m256 x) +{ + const __m256 conjugator = _mm256_setr_ps(0, -0.f, 0, -0.f, 0, -0.f, 0, -0.f); + return _mm256_xor_ps(x, conjugator); // conjugate y } static inline __m256 -_mm256_complexconjugatemul_ps(__m256 x, __m256 y){ - y = _mm256_conjugate_ps(y); - return _mm256_complexmul_ps(x, y); +_mm256_complexconjugatemul_ps(__m256 x, __m256 y) +{ + y = _mm256_conjugate_ps(y); + return _mm256_complexmul_ps(x, y); } static inline __m256 -_mm256_magnitudesquared_ps(__m256 cplxValue1, __m256 cplxValue2){ - __m256 complex1, complex2; - cplxValue1 = _mm256_mul_ps(cplxValue1, cplxValue1); // Square the values - cplxValue2 = _mm256_mul_ps(cplxValue2, cplxValue2); // Square the Values - complex1 = _mm256_permute2f128_ps(cplxValue1, cplxValue2, 0x20); - complex2 = _mm256_permute2f128_ps(cplxValue1, cplxValue2, 0x31); - return _mm256_hadd_ps(complex1, complex2); // Add the I2 and Q2 values +_mm256_magnitudesquared_ps(__m256 cplxValue1, __m256 cplxValue2) +{ + __m256 complex1, complex2; + cplxValue1 = _mm256_mul_ps(cplxValue1, cplxValue1); // Square the values + cplxValue2 = _mm256_mul_ps(cplxValue2, cplxValue2); // Square the Values + complex1 = _mm256_permute2f128_ps(cplxValue1, cplxValue2, 0x20); + complex2 = _mm256_permute2f128_ps(cplxValue1, cplxValue2, 0x31); + return _mm256_hadd_ps(complex1, complex2); // Add the I2 and Q2 values +} + +static inline __m256 _mm256_complexnormalise_ps(__m256 z) +{ + __m256 tmp1 = _mm256_mul_ps(z, z); + __m256 tmp2 = _mm256_hadd_ps(tmp1, tmp1); + tmp1 = _mm256_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm256_sqrt_ps(tmp1); + return _mm256_div_ps(z, tmp2); } static inline __m256 -_mm256_magnitude_ps(__m256 cplxValue1, __m256 cplxValue2){ - return _mm256_sqrt_ps(_mm256_magnitudesquared_ps(cplxValue1, cplxValue2)); +_mm256_magnitude_ps(__m256 cplxValue1, __m256 cplxValue2) +{ + return _mm256_sqrt_ps(_mm256_magnitudesquared_ps(cplxValue1, cplxValue2)); } #endif /* INCLUDE_VOLK_VOLK_AVX_INTRINSICS_H_ */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_common.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_common.h index 87841616d..b8d3d444d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_common.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_common.h @@ -3,7 +3,7 @@ * \brief Cross-platform attribute macros * \author Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_LIBVOLK_GNSSSDR_COMMON_H @@ -28,14 +28,14 @@ // Cross-platform attribute macros not included in VOLK //////////////////////////////////////////////////////////////////////// #if defined __GNUC__ -# define __VOLK_GNSSSDR_PREFETCH(addr) __builtin_prefetch(addr) -# define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) __builtin_prefetch(addr, rw, locality) +#define __VOLK_GNSSSDR_PREFETCH(addr) __builtin_prefetch(addr) +#define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) __builtin_prefetch(addr, rw, locality) #elif _MSC_VER -# define __VOLK_GNSSSDR_PREFETCH(addr) -# define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) +#define __VOLK_GNSSSDR_PREFETCH(addr) +#define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) #else -# define __VOLK_GNSSSDR_PREFETCH(addr) -# define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) +#define __VOLK_GNSSSDR_PREFETCH(addr) +#define __VOLK_GNSSSDR_PREFETCH_LOCALITY(addr, rw, locality) #endif #ifndef INCLUDED_LIBVOLK_COMMON_H @@ -45,39 +45,45 @@ // Cross-platform attribute macros //////////////////////////////////////////////////////////////////////// #if defined __GNUC__ -# define __VOLK_ATTR_ALIGNED(x) __attribute__((aligned(x))) -# define __VOLK_ATTR_UNUSED __attribute__((unused)) -# define __VOLK_ATTR_INLINE __attribute__((always_inline)) -# define __VOLK_ATTR_DEPRECATED __attribute__((deprecated)) -# if __GNUC__ >= 4 -# define __VOLK_ATTR_EXPORT __attribute__((visibility("default"))) -# define __VOLK_ATTR_IMPORT __attribute__((visibility("default"))) -# else -# define __VOLK_ATTR_EXPORT -# define __VOLK_ATTR_IMPORT -# endif -#elif _MSC_VER -# define __VOLK_ATTR_ALIGNED(x) __declspec(align(x)) -# define __VOLK_ATTR_UNUSED -# define __VOLK_ATTR_INLINE __forceinline -# define __VOLK_ATTR_DEPRECATED __declspec(deprecated) -# define __VOLK_ATTR_EXPORT __declspec(dllexport) -# define __VOLK_ATTR_IMPORT __declspec(dllimport) +#define __VOLK_ATTR_ALIGNED(x) __attribute__((aligned(x))) +#define __VOLK_ATTR_UNUSED __attribute__((unused)) +#define __VOLK_ATTR_INLINE __attribute__((always_inline)) +#define __VOLK_ATTR_DEPRECATED __attribute__((deprecated)) +#define __VOLK_ASM __asm__ +#define __VOLK_VOLATILE __volatile__ +#if __GNUC__ >= 4 +#define __VOLK_ATTR_EXPORT __attribute__((visibility("default"))) +#define __VOLK_ATTR_IMPORT __attribute__((visibility("default"))) #else -# define __VOLK_ATTR_ALIGNED(x) -# define __VOLK_ATTR_UNUSED -# define __VOLK_ATTR_INLINE -# define __VOLK_ATTR_DEPRECATED -# define __VOLK_ATTR_EXPORT -# define __VOLK_ATTR_IMPORT +#define __VOLK_ATTR_EXPORT +#define __VOLK_ATTR_IMPORT +#endif +#elif _MSC_VER +#define __VOLK_ATTR_ALIGNED(x) __declspec(align(x)) +#define __VOLK_ATTR_UNUSED +#define __VOLK_ATTR_INLINE __forceinline +#define __VOLK_ATTR_DEPRECATED __declspec(deprecated) +#define __VOLK_ATTR_EXPORT __declspec(dllexport) +#define __VOLK_ATTR_IMPORT __declspec(dllimport) +#define __VOLK_ASM __asm +#define __VOLK_VOLATILE +#else +#define __VOLK_ATTR_ALIGNED(x) +#define __VOLK_ATTR_UNUSED +#define __VOLK_ATTR_INLINE +#define __VOLK_ATTR_DEPRECATED +#define __VOLK_ATTR_EXPORT +#define __VOLK_ATTR_IMPORT +#define __VOLK_ASM __asm__ +#define __VOLK_VOLATILE __volatile__ #endif //////////////////////////////////////////////////////////////////////// // Ignore annoying warnings in MSVC //////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) -# pragma warning(disable: 4244) //'conversion' conversion from 'type1' to 'type2', possible loss of data -# pragma warning(disable: 4305) //'identifier' : truncation from 'type1' to 'type2' +#pragma warning(disable : 4244) //'conversion' conversion from 'type1' to 'type2', possible loss of data +#pragma warning(disable : 4305) //'identifier' : truncation from 'type1' to 'type2' #endif //////////////////////////////////////////////////////////////////////// @@ -85,11 +91,13 @@ // FIXME: due to the usage of complex.h, require gcc for c-linkage //////////////////////////////////////////////////////////////////////// #if defined(__cplusplus) && (__GNUC__) -# define __VOLK_DECL_BEGIN extern "C" { -# define __VOLK_DECL_END } +#define __VOLK_DECL_BEGIN \ + extern "C" \ + { +#define __VOLK_DECL_END } #else -# define __VOLK_DECL_BEGIN -# define __VOLK_DECL_END +#define __VOLK_DECL_BEGIN +#define __VOLK_DECL_END #endif //////////////////////////////////////////////////////////////////////// @@ -97,9 +105,9 @@ // http://gcc.gnu.org/wiki/Visibility //////////////////////////////////////////////////////////////////////// #ifdef volk_gnsssdr_EXPORTS -# define VOLK_API __VOLK_ATTR_EXPORT +#define VOLK_API __VOLK_ATTR_EXPORT #else -# define VOLK_API __VOLK_ATTR_IMPORT +#define VOLK_API __VOLK_ATTR_IMPORT #endif //////////////////////////////////////////////////////////////////////// @@ -115,35 +123,37 @@ #endif #endif -union bit128{ - uint8_t i8[16]; - uint16_t i16[8]; - uint32_t i[4]; - float f[4]; - double d[2]; +union bit128 +{ + uint8_t i8[16]; + uint16_t i16[8]; + uint32_t i[4]; + float f[4]; + double d[2]; - #ifdef LV_HAVE_SSE - __m128 float_vec; - #endif +#ifdef LV_HAVE_SSE + __m128 float_vec; +#endif - #ifdef LV_HAVE_SSE2 - __m128i int_vec; - __m128d double_vec; - #endif +#ifdef LV_HAVE_SSE2 + __m128i int_vec; + __m128d double_vec; +#endif }; -union bit256{ - uint8_t i8[32]; - uint16_t i16[16]; - uint32_t i[8]; - float f[8]; - double d[4]; +union bit256 +{ + uint8_t i8[32]; + uint16_t i16[16]; + uint32_t i[8]; + float f[8]; + double d[4]; - #ifdef LV_HAVE_AVX - __m256 float_vec; - __m256i int_vec; - __m256d double_vec; - #endif +#ifdef LV_HAVE_AVX + __m256 float_vec; + __m256i int_vec; + __m256d double_vec; +#endif }; #define bit128_p(x) ((union bit128 *)(x)) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_complex.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_complex.h index ea97a38c9..1382d48ce 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_complex.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_complex.h @@ -3,7 +3,7 @@ * \brief Provide typedefs and operators for all complex types in C and C++. * \author Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDE_VOLK_COMPLEX_H @@ -48,41 +48,54 @@ #include #include -typedef std::complex lv_8sc_t; +typedef std::complex lv_8sc_t; typedef std::complex lv_16sc_t; typedef std::complex lv_32sc_t; typedef std::complex lv_64sc_t; -typedef std::complex lv_32fc_t; -typedef std::complex lv_64fc_t; +typedef std::complex lv_32fc_t; +typedef std::complex lv_64fc_t; -template inline std::complex lv_cmake(const T &r, const T &i){ +template +inline std::complex lv_cmake(const T &r, const T &i) +{ return std::complex(r, i); } -template inline typename T::value_type lv_creal(const T &x){ +template +inline typename T::value_type lv_creal(const T &x) +{ return x.real(); } -template inline typename T::value_type lv_cimag(const T &x){ +template +inline typename T::value_type lv_cimag(const T &x) +{ return x.imag(); } -template inline T lv_conj(const T &x){ +template +inline T lv_conj(const T &x) +{ return std::conj(x); } #else /* __cplusplus */ +#if __STDC_VERSION__ >= 199901L /* C99 check */ +/* this allows us to conj in lv_conj without the double detour for single-precision floats */ +#include +#endif /* C99 check */ + #include -typedef char complex lv_8sc_t; -typedef short complex lv_16sc_t; -typedef long complex lv_32sc_t; -typedef long long complex lv_64sc_t; -typedef float complex lv_32fc_t; -typedef double complex lv_64fc_t; +typedef char complex lv_8sc_t; +typedef short complex lv_16sc_t; +typedef long complex lv_32sc_t; +typedef long long complex lv_64sc_t; +typedef float complex lv_32fc_t; +typedef double complex lv_64fc_t; -#define lv_cmake(r, i) ((r) + _Complex_I*(i)) +#define lv_cmake(r, i) ((r) + _Complex_I * (i)) // When GNUC is available, use the complex extensions. // The extensions always return the correct value type. @@ -96,7 +109,9 @@ typedef double complex lv_64fc_t; #define lv_conj(x) (~(x)) // When not available, use the c99 complex function family, -// which always returns double regardless of the input type. +// which always returns double regardless of the input type, +// unless we have C99 and thus tgmath.h overriding functions +// with type-generic versions. #else /* __GNUC__ */ #define lv_creal(x) (creal(x)) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_malloc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_malloc.h index fbe0d76a1..eefc87339 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_malloc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_malloc.h @@ -4,7 +4,7 @@ * returns a pointer to the allocated memory. * \author Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_MALLOC_H @@ -38,7 +38,7 @@ __VOLK_DECL_BEGIN * memory that are guaranteed to be on an alignment, VOLK handles this * itself. The volk_gnsssdr_malloc function behaves like malloc in that it * returns a pointer to the allocated memory. However, it also takes - * in an alignment specfication, which is usually something like 16 or + * in an alignment specification, which is usually something like 16 or * 32 to ensure that the aligned memory is located on a particular * byte boundary for use with SIMD. * diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_neon_intrinsics.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_neon_intrinsics.h index 49aa561d1..d7b5d376e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_neon_intrinsics.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_neon_intrinsics.h @@ -4,7 +4,7 @@ * \brief Holds NEON intrinsics of intrinsics. * They can be used in VOLK_GNSSSDR kernels to avoid copy-paste * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_NEON_INTRINSICS_H_ @@ -27,30 +27,30 @@ #include -static inline float32x4_t vdivq_f32( float32x4_t num, float32x4_t den ) +static inline float32x4_t vdivq_f32(float32x4_t num, float32x4_t den) { - const float32x4_t q_inv0 = vrecpeq_f32( den ); - const float32x4_t q_step0 = vrecpsq_f32( q_inv0, den ); + const float32x4_t q_inv0 = vrecpeq_f32(den); + const float32x4_t q_step0 = vrecpsq_f32(q_inv0, den); - const float32x4_t q_inv1 = vmulq_f32( q_step0, q_inv0 ); - return vmulq_f32( num, q_inv1 ); + const float32x4_t q_inv1 = vmulq_f32(q_step0, q_inv0); + return vmulq_f32(num, q_inv1); } -static inline float32x4_t vsqrtq_f32( float32x4_t q_x ) +static inline float32x4_t vsqrtq_f32(float32x4_t q_x) { - const float32x4_t q_step_0 = vrsqrteq_f32( q_x ); + const float32x4_t q_step_0 = vrsqrteq_f32(q_x); // step - const float32x4_t q_step_parm0 = vmulq_f32( q_x, q_step_0 ); - const float32x4_t q_step_result0 = vrsqrtsq_f32( q_step_parm0, q_step_0 ); + const float32x4_t q_step_parm0 = vmulq_f32(q_x, q_step_0); + const float32x4_t q_step_result0 = vrsqrtsq_f32(q_step_parm0, q_step_0); // step - const float32x4_t q_step_1 = vmulq_f32( q_step_0, q_step_result0 ); - const float32x4_t q_step_parm1 = vmulq_f32( q_x, q_step_1 ); - const float32x4_t q_step_result1 = vrsqrtsq_f32( q_step_parm1, q_step_1 ); + const float32x4_t q_step_1 = vmulq_f32(q_step_0, q_step_result0); + const float32x4_t q_step_parm1 = vmulq_f32(q_x, q_step_1); + const float32x4_t q_step_result1 = vrsqrtsq_f32(q_step_parm1, q_step_1); // take the res - const float32x4_t q_step_2 = vmulq_f32( q_step_1, q_step_result1 ); + const float32x4_t q_step_2 = vmulq_f32(q_step_1, q_step_result1); // mul by x to get sqrt, not rsqrt - return vmulq_f32( q_x, q_step_2 ); + return vmulq_f32(q_x, q_step_2); } #endif /* INCLUDED_VOLK_GNSSSDR_NEON_INTRINSICS_H_ */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_prefs.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_prefs.h index bb03e4407..199c9256f 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_prefs.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_prefs.h @@ -4,7 +4,7 @@ * prefs into global prefs struct * \author Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_PREFS_H @@ -32,9 +32,9 @@ __VOLK_DECL_BEGIN typedef struct volk_gnsssdr_arch_pref { - char name[128]; //name of the kernel - char impl_a[128]; //best aligned impl - char impl_u[128]; //best unaligned impl + char name[128]; //name of the kernel + char impl_a[128]; //best aligned impl + char impl_u[128]; //best unaligned impl } volk_gnsssdr_arch_pref_t; //////////////////////////////////////////////////////////////////////// diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sine_table.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sine_table.h index 90bd78569..4f2727c4b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sine_table.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sine_table.h @@ -3,7 +3,7 @@ * \brief Sine table * \author Carles Fernandez-Prades, 2015 cfernandez(at)cttc.es * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ @@ -29,1030 +29,1030 @@ * max_error = 2.353084136763606e-06 */ static const float sine_table_10bits[1 << 10][2] = { -{ 2.925817799165007e-09, 7.219194364267018e-09 }, - { 2.925707643778599e-09, 2.526699001579799e-07 }, - { 2.925487337153070e-09, 1.191140162167675e-06 }, - { 2.925156887582842e-09, 3.284585035595589e-06 }, - { 2.924716307509151e-09, 6.994872605695784e-06 }, - { 2.924165613519592e-09, 1.278374920658798e-05 }, - { 2.923504826347475e-09, 2.111280464718590e-05 }, - { 2.922733970871080e-09, 3.244343744537165e-05 }, - { 2.921853076112655e-09, 4.723682007436170e-05 }, - { 2.920862175237416e-09, 6.595386421935634e-05 }, - { 2.919761305552202e-09, 8.905518605213658e-05 }, - { 2.918550508504146e-09, 1.170010715193098e-04 }, - { 2.917229829679050e-09, 1.502514416517192e-04 }, - { 2.915799318799769e-09, 1.892658178912071e-04 }, - { 2.914259029724184e-09, 2.345032874456615e-04 }, - { 2.912609020443340e-09, 2.864224686607020e-04 }, - { 2.910849353079123e-09, 3.454814764261432e-04 }, - { 2.908980093882049e-09, 4.121378876027343e-04 }, - { 2.907001313228646e-09, 4.868487064877691e-04 }, - { 2.904913085618902e-09, 5.700703303049837e-04 }, - { 2.902715489673383e-09, 6.622585147355725e-04 }, - { 2.900408608130373e-09, 7.638683394782519e-04 }, - { 2.897992527842612e-09, 8.753541738578119e-04 }, - { 2.895467339774186e-09, 9.971696424604937e-04 }, - { 2.892833138996999e-09, 1.129767590823255e-03 }, - { 2.890090024687216e-09, 1.273600051161478e-03 }, - { 2.887238100121550e-09, 1.429118208142094e-03 }, - { 2.884277472673313e-09, 1.596772364709564e-03 }, - { 2.881208253808507e-09, 1.777011907950626e-03 }, - { 2.878030559081432e-09, 1.970285275029487e-03 }, - { 2.874744508130554e-09, 2.177039919152579e-03 }, - { 2.871350224673798e-09, 2.397722275614272e-03 }, - { 2.867847836504030e-09, 2.632777727878843e-03 }, - { 2.864237475484149e-09, 2.882650573737405e-03 }, - { 2.860519277542297e-09, 3.147783991507308e-03 }, - { 2.856693382666432e-09, 3.428620006328931e-03 }, - { 2.852759934899389e-09, 3.725599456482154e-03 }, - { 2.848719082333207e-09, 4.039161959812243e-03 }, - { 2.844570977103752e-09, 4.369745880190706e-03 }, - { 2.840315775384800e-09, 4.717788294077374e-03 }, - { 2.835953637382310e-09, 5.083724957128360e-03 }, - { 2.831484727328322e-09, 5.467990270896617e-03 }, - { 2.826909213474759e-09, 5.871017249604038e-03 }, - { 2.822227268087134e-09, 6.293237486988512e-03 }, - { 2.817439067438018e-09, 6.735081123237729e-03 }, - { 2.812544791800534e-09, 7.196976811989608e-03 }, - { 2.807544625441273e-09, 7.679351687456759e-03 }, - { 2.802438756613836e-09, 8.182631331563162e-03 }, - { 2.797227377551135e-09, 8.707239741274575e-03 }, - { 2.791910684458716e-09, 9.253599295902304e-03 }, - { 2.786488877507140e-09, 9.822130724578715e-03 }, - { 2.780962160824228e-09, 1.041325307382490e-02 }, - { 2.775330742487884e-09, 1.102738367513773e-02 }, - { 2.769594834517682e-09, 1.166493811278924e-02 }, - { 2.763754652867477e-09, 1.232633019159818e-02 }, - { 2.757810417416620e-09, 1.301197190494069e-02 }, - { 2.751762351962413e-09, 1.372227340270610e-02 }, - { 2.745610684210923e-09, 1.445764295952962e-02 }, - { 2.739355645769094e-09, 1.521848694296229e-02 }, - { 2.732997472135539e-09, 1.600520978188769e-02 }, - { 2.726536402691907e-09, 1.681821393496225e-02 }, - { 2.719972680693777e-09, 1.765789985920713e-02 }, - { 2.713306553261610e-09, 1.852466597868779e-02 }, - { 2.706538271371373e-09, 1.941890865333146e-02 }, - { 2.699668089844909e-09, 2.034102214787814e-02 }, - { 2.692696267340880e-09, 2.129139860085272e-02 }, - { 2.685623066344263e-09, 2.227042799383416e-02 }, - { 2.678448753157212e-09, 2.327849812064098e-02 }, - { 2.671173597888530e-09, 2.431599455681316e-02 }, - { 2.663797874443630e-09, 2.538330062913108e-02 }, - { 2.656321860514457e-09, 2.648079738524795e-02 }, - { 2.648745837568575e-09, 2.760886356354952e-02 }, - { 2.641070090839117e-09, 2.876787556300114e-02 }, - { 2.633294909313421e-09, 2.995820741329835e-02 }, - { 2.625420585722845e-09, 3.118023074495535e-02 }, - { 2.617447416531143e-09, 3.243431475972608e-02 }, - { 2.609375701923643e-09, 3.372082620101990e-02 }, - { 2.601205745795833e-09, 3.504012932452527e-02 }, - { 2.592937855741933e-09, 3.639258586895711e-02 }, - { 2.584572343043400e-09, 3.777855502693250e-02 }, - { 2.576109522656942e-09, 3.919839341605197e-02 }, - { 2.567549713203028e-09, 4.065245505002102e-02 }, - { 2.558893236953688e-09, 4.214109131001403e-02 }, - { 2.550140419820252e-09, 4.366465091617666e-02 }, - { 2.541291591341445e-09, 4.522347989919473e-02 }, - { 2.532347084670572e-09, 4.681792157215026e-02 }, - { 2.523307236563343e-09, 4.844831650239501e-02 }, - { 2.514172387364900e-09, 5.011500248369893e-02 }, - { 2.504942880997064e-09, 5.181831450849345e-02 }, - { 2.495619064945627e-09, 5.355858474024022e-02 }, - { 2.486201290246928e-09, 5.533614248606705e-02 }, - { 2.476689911475047e-09, 5.715131416942842e-02 }, - { 2.467085286727668e-09, 5.900442330315692e-02 }, - { 2.457387777613798e-09, 6.089579046229943e-02 }, - { 2.447597749239101e-09, 6.282573325755320e-02 }, - { 2.437715570192557e-09, 6.479456630859221e-02 }, - { 2.427741612532542e-09, 6.680260121764925e-02 }, - { 2.417676251773166e-09, 6.885014654319160e-02 }, - { 2.407519866869294e-09, 7.093750777401114e-02 }, - { 2.397272840203310e-09, 7.306498730310884e-02 }, - { 2.386935557569868e-09, 7.523288440214027e-02 }, - { 2.376508408161815e-09, 7.744149519577415e-02 }, - { 2.365991784555363e-09, 7.969111263635709e-02 }, - { 2.355386082695641e-09, 8.198202647865405e-02 }, - { 2.344691701881232e-09, 8.431452325495814e-02 }, - { 2.333909044749407e-09, 8.668888625021409e-02 }, - { 2.323038517261246e-09, 8.910539547731611e-02 }, - { 2.312080528685971e-09, 9.156432765274414e-02 }, - { 2.301035491585642e-09, 9.406595617227698e-02 }, - { 2.289903821799651e-09, 9.661055108691619e-02 }, - { 2.278685938428940e-09, 9.919837907903295e-02 }, - { 2.267382263820762e-09, 1.018297034385580e-01 }, - { 2.255993223551837e-09, 1.045047840397028e-01 }, - { 2.244519246413220e-09, 1.072238773174577e-01 }, - { 2.232960764393620e-09, 1.099872362446146e-01 }, - { 2.221318212663309e-09, 1.127951103088245e-01 }, - { 2.209592029557811e-09, 1.156477454898748e-01 }, - { 2.197782656561395e-09, 1.185453842371912e-01 }, - { 2.185890538290176e-09, 1.214882654476019e-01 }, - { 2.173916122475606e-09, 1.244766244431883e-01 }, - { 2.161859859947797e-09, 1.275106929493488e-01 }, - { 2.149722204618256e-09, 1.305906990731841e-01 }, - { 2.137503613462743e-09, 1.337168672820376e-01 }, - { 2.125204546504321e-09, 1.368894183821595e-01 }, - { 2.112825466795944e-09, 1.401085694976751e-01 }, - { 2.100366840402933e-09, 1.433745340497602e-01 }, - { 2.087829136385612e-09, 1.466875217359607e-01 }, - { 2.075212826781308e-09, 1.500477385098620e-01 }, - { 2.062518386587093e-09, 1.534553865607503e-01 }, - { 2.049746293741359e-09, 1.569106642937665e-01 }, - { 2.036897029106193e-09, 1.604137663100403e-01 }, - { 2.023971076449323e-09, 1.639648833871233e-01 }, - { 2.010968922425217e-09, 1.675642024598467e-01 }, - { 1.997891056557933e-09, 1.712119066008896e-01 }, - { 1.984737971221581e-09, 1.749081750021970e-01 }, - { 1.971510161622434e-09, 1.786531829561379e-01 }, - { 1.958208125780130e-09, 1.824471018371070e-01 }, - { 1.944832364508511e-09, 1.862900990834311e-01 }, - { 1.931383381397782e-09, 1.901823381790926e-01 }, - { 1.917861682794392e-09, 1.941239786363039e-01 }, - { 1.904267777782611e-09, 1.981151759777950e-01 }, - { 1.890602178165317e-09, 2.021560817195309e-01 }, - { 1.876865398444616e-09, 2.062468433536743e-01 }, - { 1.863057955802572e-09, 2.103876043317229e-01 }, - { 1.849180370081465e-09, 2.145785040479915e-01 }, - { 1.835233163764673e-09, 2.188196778231083e-01 }, - { 1.821216861956509e-09, 2.231112568880342e-01 }, - { 1.807131992362945e-09, 2.274533683680190e-01 }, - { 1.792979085271234e-09, 2.318461352671018e-01 }, - { 1.778758673530482e-09, 2.362896764525300e-01 }, - { 1.764471292530943e-09, 2.407841066397789e-01 }, - { 1.750117480184598e-09, 2.453295363773890e-01 }, - { 1.735697776904342e-09, 2.499260720324433e-01 }, - { 1.721212725583874e-09, 2.545738157760434e-01 }, - { 1.706662871577097e-09, 2.592728655691494e-01 }, - { 1.692048762677849e-09, 2.640233151485341e-01 }, - { 1.677370949099090e-09, 2.688252540131204e-01 }, - { 1.662629983452104e-09, 2.736787674105404e-01 }, - { 1.647826420726167e-09, 2.785839363237506e-01 }, - { 1.632960818266680e-09, 2.835408374583758e-01 }, - { 1.618033735755429e-09, 2.885495432295704e-01 }, - { 1.603045735188609e-09, 2.936101217498361e-01 }, - { 1.587997380855918e-09, 2.987226368167127e-01 }, - { 1.572889239319430e-09, 3.038871479007593e-01 }, - { 1.557721879392051e-09, 3.091037101339017e-01 }, - { 1.542495872116447e-09, 3.143723742978435e-01 }, - { 1.527211790743024e-09, 3.196931868130269e-01 }, - { 1.511870210708909e-09, 3.250661897274744e-01 }, - { 1.496471709615926e-09, 3.304914207062036e-01 }, - { 1.481016867208896e-09, 3.359689130207621e-01 }, - { 1.465506265353924e-09, 3.414986955389885e-01 }, - { 1.449940488016384e-09, 3.470807927151147e-01 }, - { 1.434320121238994e-09, 3.527152245800635e-01 }, - { 1.418645753119802e-09, 3.584020067320109e-01 }, - { 1.402917973789838e-09, 3.641411503272979e-01 }, - { 1.387137375391042e-09, 3.699326620714776e-01 }, - { 1.371304552054134e-09, 3.757765442106153e-01 }, - { 1.355420099875958e-09, 3.816727945230153e-01 }, - { 1.339484616897137e-09, 3.876214063110671e-01 }, - { 1.323498703079580e-09, 3.936223683933865e-01 }, - { 1.307462960283922e-09, 3.996756650972121e-01 }, - { 1.291377992246768e-09, 4.057812762511174e-01 }, - { 1.275244404558188e-09, 4.119391771778626e-01 }, - { 1.259062804638585e-09, 4.181493386877248e-01 }, - { 1.242833801715929e-09, 4.244117270719281e-01 }, - { 1.226558006803155e-09, 4.307263040962509e-01 }, - { 1.210236032674760e-09, 4.370930269951803e-01 }, - { 1.193868493843725e-09, 4.435118484661861e-01 }, - { 1.177456006538695e-09, 4.499827166641340e-01 }, - { 1.160999188680582e-09, 4.565055751961679e-01 }, - { 1.144498659859216e-09, 4.630803631168164e-01 }, - { 1.127955041310214e-09, 4.697070149232604e-01 }, - { 1.111368955891417e-09, 4.763854605510119e-01 }, - { 1.094741028059551e-09, 4.831156253697562e-01 }, - { 1.078071883846871e-09, 4.898974301794375e-01 }, - { 1.061362150836978e-09, 4.967307912069362e-01 }, - { 1.044612458142151e-09, 5.036156201023686e-01 }, - { 1.027823436378632e-09, 5.105518239364775e-01 }, - { 1.010995717643647e-09, 5.175393051975563e-01 }, - { 9.941299354913699e-10, 5.245779617890562e-01 }, - { 9.772267249089968e-10, 5.316676870274011e-01 }, - { 9.602867222926046e-10, 5.388083696401416e-01 }, - { 9.433105654240147e-10, 5.459998937639375e-01 }, - { 9.262988934458084e-10, 5.532421389435711e-01 }, - { 9.092523468378193e-10, 5.605349801305876e-01 }, - { 8.921715673928355e-10, 5.678782876825250e-01 }, - { 8.750571981926701e-10, 5.752719273622372e-01 }, - { 8.579098835836508e-10, 5.827157603377209e-01 }, - { 8.407302691522673e-10, 5.902096431821322e-01 }, - { 8.235190017016133e-10, 5.977534278737073e-01 }, - { 8.062767292259225e-10, 6.053469617967722e-01 }, - { 7.890041008871165e-10, 6.129900877421282e-01 }, - { 7.717017669898175e-10, 6.206826439083659e-01 }, - { 7.543703789572603e-10, 6.284244639030392e-01 }, - { 7.370105893063053e-10, 6.362153767444958e-01 }, - { 7.196230516231919e-10, 6.440552068636356e-01 }, - { 7.022084205389746e-10, 6.519437741060674e-01 }, - { 6.847673517046416e-10, 6.598808937346672e-01 }, - { 6.673005017664976e-10, 6.678663764322770e-01 }, - { 6.498085283416530e-10, 6.759000283046127e-01 }, - { 6.322920899929834e-10, 6.839816508836737e-01 }, - { 6.147518462045659e-10, 6.921110411311926e-01 }, - { 5.971884573565851e-10, 7.002879914425926e-01 }, - { 5.796025847007168e-10, 7.085122896509806e-01 }, - { 5.619948903351406e-10, 7.167837190315758e-01 }, - { 5.443660371796048e-10, 7.251020583063744e-01 }, - { 5.267166889504394e-10, 7.334670816491009e-01 }, - { 5.090475101356742e-10, 7.418785586903696e-01 }, - { 4.913591659698399e-10, 7.503362545232619e-01 }, - { 4.736523224091392e-10, 7.588399297089872e-01 }, - { 4.559276461062478e-10, 7.673893402829834e-01 }, - { 4.381858043851147e-10, 7.759842377612828e-01 }, - { 4.204274652161870e-10, 7.846243691469355e-01 }, - { 4.026532971908398e-10, 7.933094769370790e-01 }, - { 3.848639694963359e-10, 8.020392991300200e-01 }, - { 3.670601518910503e-10, 8.108135692324444e-01 }, - { 3.492425146784233e-10, 8.196320162675177e-01 }, - { 3.314117286825031e-10, 8.284943647824689e-01 }, - { 3.135684652223755e-10, 8.374003348569865e-01 }, - { 2.957133960867535e-10, 8.463496421118015e-01 }, - { 2.778471935089361e-10, 8.553419977173513e-01 }, - { 2.599705301412391e-10, 8.643771084029740e-01 }, - { 2.420840790301135e-10, 8.734546764660205e-01 }, - { 2.241885135902046e-10, 8.825743997817682e-01 }, - { 2.062845075795238e-10, 8.917359718130367e-01 }, - { 1.883727350736140e-10, 9.009390816205823e-01 }, - { 1.704538704408269e-10, 9.101834138731877e-01 }, - { 1.525285883160648e-10, 9.194686488588080e-01 }, - { 1.345975635762696e-10, 9.287944624950824e-01 }, - { 1.166614713141648e-10, 9.381605263410157e-01 }, - { 9.872098681369190e-11, 9.475665076080466e-01 }, - { 8.077678552380464e-11, 9.570120691722380e-01 }, - { 6.282954303364090e-11, 9.664968695860140e-01 }, - { 4.487993504668797e-11, 9.760205630906909e-01 }, - { 2.692863735553042e-11, 9.855827996289697e-01 }, - { 8.976325816439114e-12, 9.951832248577780e-01 }, - { -8.976323676304494e-12, 1.004821480161519e+00 }, - { -2.692863521550168e-11, 1.014497202665280e+00 }, - { -4.487993290681805e-11, 1.024210025248670e+00 }, - { -6.282954089398273e-11, 1.033959576559617e+00 }, - { -8.077678338451706e-11, 1.043745481028715e+00 }, - { -9.872098467477489e-11, 1.053567358883467e+00 }, - { -1.166614691757772e-10, 1.063424826163223e+00 }, - { -1.345975614383584e-10, 1.073317494734013e+00 }, - { -1.525285861788948e-10, 1.083244972303963e+00 }, - { -1.704538683042922e-10, 1.093206862438572e+00 }, - { -1.883727329379793e-10, 1.103202764576806e+00 }, - { -2.062845054446831e-10, 1.113232274046796e+00 }, - { -2.241885114563697e-10, 1.123294982082432e+00 }, - { -2.420840768973375e-10, 1.133390475839767e+00 }, - { -2.599705280096278e-10, 1.143518338413855e+00 }, - { -2.778471913784365e-10, 1.153678148855860e+00 }, - { -2.957133939575774e-10, 1.163869482190458e+00 }, - { -3.135684630945758e-10, 1.174091909433296e+00 }, - { -3.314117265561857e-10, 1.184344997608959e+00 }, - { -3.492425125535882e-10, 1.194628309769018e+00 }, - { -3.670601497678034e-10, 1.204941405010466e+00 }, - { -3.848639673748360e-10, 1.215283838494269e+00 }, - { -4.026532950710339e-10, 1.225655161464298e+00 }, - { -4.204274630982869e-10, 1.236054921266445e+00 }, - { -4.381858022691734e-10, 1.246482661367958e+00 }, - { -4.559276439922654e-10, 1.256937921377146e+00 }, - { -4.736523202972214e-10, 1.267420237063216e+00 }, - { -4.913591638600925e-10, 1.277929140376502e+00 }, - { -5.090475080282032e-10, 1.288464159468706e+00 }, - { -5.267166868452449e-10, 1.299024818713528e+00 }, - { -5.443660350768455e-10, 1.309610638727845e+00 }, - { -5.619948882348695e-10, 1.320221136392390e+00 }, - { -5.796025826029868e-10, 1.330855824873457e+00 }, - { -5.971884552615020e-10, 1.341514213644420e+00 }, - { -6.147518441122357e-10, 1.352195808507556e+00 }, - { -6.322920879034590e-10, 1.362900111616144e+00 }, - { -6.498085262549874e-10, 1.373626621496939e+00 }, - { -6.673004996827436e-10, 1.384374833072571e+00 }, - { -6.847673496239581e-10, 1.395144237684605e+00 }, - { -7.022084184613616e-10, 1.405934323116231e+00 }, - { -7.196230495488082e-10, 1.416744573616104e+00 }, - { -7.370105872352039e-10, 1.427574469921397e+00 }, - { -7.543703768894941e-10, 1.438423489281758e+00 }, - { -7.717017649255453e-10, 1.449291105483472e+00 }, - { -7.890040988262324e-10, 1.460176788873383e+00 }, - { -8.062767271686383e-10, 1.471080006383765e+00 }, - { -8.235189996479819e-10, 1.482000221556656e+00 }, - { -8.407302671024475e-10, 1.492936894569018e+00 }, - { -8.579098815375368e-10, 1.503889482257845e+00 }, - { -8.750571961505266e-10, 1.514857438145604e+00 }, - { -8.921715653546624e-10, 1.525840212465756e+00 }, - { -9.092523448036167e-10, 1.536837252188703e+00 }, - { -9.262988914157881e-10, 1.547848001047890e+00 }, - { -9.433105633981766e-10, 1.558871899565883e+00 }, - { -9.602867202711075e-10, 1.569908385081254e+00 }, - { -9.772267228916820e-10, 1.580956891774897e+00 }, - { -9.941299334786078e-10, 1.592016850697478e+00 }, - { -1.010995715635332e-09, 1.603087689796053e+00 }, - { -1.027823434374870e-09, 1.614168833942028e+00 }, - { -1.044612456143047e-09, 1.625259704958335e+00 }, - { -1.061362148842745e-09, 1.636359721647526e+00 }, - { -1.078071881857297e-09, 1.647468299819543e+00 }, - { -1.094741026074900e-09, 1.658584852320419e+00 }, - { -1.111368953911690e-09, 1.669708789060341e+00 }, - { -1.127955039335462e-09, 1.680839517042381e+00 }, - { -1.144498657889600e-09, 1.691976440391624e+00 }, - { -1.160999186716154e-09, 1.703118960383971e+00 }, - { -1.177456004579561e-09, 1.714266475475616e+00 }, - { -1.193868491889832e-09, 1.725418381332405e+00 }, - { -1.210236030726319e-09, 1.736574070859850e+00 }, - { -1.226558004860220e-09, 1.747732934232508e+00 }, - { -1.242833799778447e-09, 1.758894358924547e+00 }, - { -1.259062802706714e-09, 1.770057729740021e+00 }, - { -1.275244402631982e-09, 1.781222428842935e+00 }, - { -1.291377990326492e-09, 1.792387835788660e+00 }, - { -1.307462958369363e-09, 1.803553327553897e+00 }, - { -1.323498701170897e-09, 1.814718278568759e+00 }, - { -1.339484614994490e-09, 1.825882060747428e+00 }, - { -1.355420097979292e-09, 1.837044043519582e+00 }, - { -1.371304550163662e-09, 1.848203593862598e+00 }, - { -1.387137373506711e-09, 1.859360076332671e+00 }, - { -1.402917971911754e-09, 1.870512853097495e+00 }, - { -1.418645751248018e-09, 1.881661283967967e+00 }, - { -1.434320119373722e-09, 1.892804726431080e+00 }, - { -1.449940486157623e-09, 1.903942535681972e+00 }, - { -1.465506263501516e-09, 1.915074064656886e+00 }, - { -1.481016865363264e-09, 1.926198664066737e+00 }, - { -1.496471707776859e-09, 1.937315682428795e+00 }, - { -1.511870208876724e-09, 1.948424466101625e+00 }, - { -1.527211788917509e-09, 1.959524359317042e+00 }, - { -1.542495870297867e-09, 1.970614704215133e+00 }, - { -1.557721877580406e-09, 1.981694840876775e+00 }, - { -1.572889237514880e-09, 1.992764107358707e+00 }, - { -1.587997379058514e-09, 2.003821839726753e+00 }, - { -1.603045733398246e-09, 2.014867372090665e+00 }, - { -1.618033733972424e-09, 2.025900036638798e+00 }, - { -1.632960816490822e-09, 2.036919163671778e+00 }, - { -1.647826418957721e-09, 2.047924081638631e+00 }, - { -1.662629981691070e-09, 2.058914117170269e+00 }, - { -1.677370947345626e-09, 2.069888595116115e+00 }, - { -1.692048760931849e-09, 2.080846838577820e+00 }, - { -1.706662869838827e-09, 2.091788168946183e+00 }, - { -1.721212723853279e-09, 2.102711905935372e+00 }, - { -1.735697775181424e-09, 2.113617367619504e+00 }, - { -1.750117478469621e-09, 2.124503870468520e+00 }, - { -1.764471290823748e-09, 2.135370729383332e+00 }, - { -1.778758671831281e-09, 2.146217257733207e+00 }, - { -1.792979083579974e-09, 2.157042767390815e+00 }, - { -1.807131990679890e-09, 2.167846568770014e+00 }, - { -1.821216860281448e-09, 2.178627970860822e+00 }, - { -1.835233162097977e-09, 2.189386281268046e+00 }, - { -1.849180368423027e-09, 2.200120806246095e+00 }, - { -1.863057954152340e-09, 2.210830850737588e+00 }, - { -1.876865396802907e-09, 2.221515718409926e+00 }, - { -1.890602176531920e-09, 2.232174711691990e+00 }, - { -1.904267776157843e-09, 2.242807131812679e+00 }, - { -1.917861681178094e-09, 2.253412278837029e+00 }, - { -1.931383379790273e-09, 2.263989451705295e+00 }, - { -1.944832362909578e-09, 2.274537948269257e+00 }, - { -1.958208124189984e-09, 2.285057065331676e+00 }, - { -1.971510160041235e-09, 2.295546098682665e+00 }, - { -1.984737969649064e-09, 2.306004343138794e+00 }, - { -1.997891054994522e-09, 2.316431092581699e+00 }, - { -2.010968920870647e-09, 2.326825639994779e+00 }, - { -2.023971074903858e-09, 2.337187277503834e+00 }, - { -2.036897027569834e-09, 2.347515296413520e+00 }, - { -2.049746292214264e-09, 2.357808987247877e+00 }, - { -2.062518385069210e-09, 2.368067639787542e+00 }, - { -2.075212825272584e-09, 2.378290543109652e+00 }, - { -2.087829134886364e-09, 2.388476985626922e+00 }, - { -2.100366838912949e-09, 2.398626255125417e+00 }, - { -2.112825465315542e-09, 2.408737638805759e+00 }, - { -2.125204545033289e-09, 2.418810423320288e+00 }, - { -2.137503612001452e-09, 2.428843894814472e+00 }, - { -2.149722203166389e-09, 2.438837338964302e+00 }, - { -2.161859858505829e-09, 2.448790041018174e+00 }, - { -2.173916121043380e-09, 2.458701285834241e+00 }, - { -2.185890536867478e-09, 2.468570357921585e+00 }, - { -2.197782655148702e-09, 2.478396541480230e+00 }, - { -2.209592028154913e-09, 2.488179120439544e+00 }, - { -2.221318211270522e-09, 2.497917378500214e+00 }, - { -2.232960763010574e-09, 2.507610599172123e+00 }, - { -2.244519245040444e-09, 2.517258065817044e+00 }, - { -2.255993222189014e-09, 2.526859061686102e+00 }, - { -2.267382262468209e-09, 2.536412869962689e+00 }, - { -2.278685937086658e-09, 2.545918773800664e+00 }, - { -2.289903820467374e-09, 2.555376056366064e+00 }, - { -2.301035490263848e-09, 2.564784000877677e+00 }, - { -2.312080527374447e-09, 2.574141890646339e+00 }, - { -2.323038515960257e-09, 2.583449009117307e+00 }, - { -2.333909043458635e-09, 2.592704639909166e+00 }, - { -2.344691700601153e-09, 2.601908066856634e+00 }, - { -2.355386081425938e-09, 2.611058574048749e+00 }, - { -2.365991783296513e-09, 2.620155445872768e+00 }, - { -2.376508406913500e-09, 2.629197967052127e+00 }, - { -2.386935556332088e-09, 2.638185422689490e+00 }, - { -2.397272838976436e-09, 2.647117098307332e+00 }, - { -2.407519865653114e-09, 2.655992279887846e+00 }, - { -2.417676250567891e-09, 2.664810253915885e+00 }, - { -2.427741611338014e-09, 2.673570307418169e+00 }, - { -2.437715569009093e-09, 2.682271728006635e+00 }, - { -2.447597748066437e-09, 2.690913803917100e+00 }, - { -2.457387776452357e-09, 2.699495824053297e+00 }, - { -2.467085285577292e-09, 2.708017078025636e+00 }, - { -2.476689910335470e-09, 2.716476856194105e+00 }, - { -2.486201289118733e-09, 2.724874449709689e+00 }, - { -2.495619063828443e-09, 2.733209150554255e+00 }, - { -2.504942879891263e-09, 2.741480251583985e+00 }, - { -2.514172386270163e-09, 2.749687046568741e+00 }, - { -2.523307235480146e-09, 2.757828830235740e+00 }, - { -2.532347083598520e-09, 2.765904898308531e+00 }, - { -2.541291590280960e-09, 2.773914547551261e+00 }, - { -2.550140418771202e-09, 2.781857075807392e+00 }, - { -2.558893235915887e-09, 2.789731782043156e+00 }, - { -2.567549712176927e-09, 2.797537966388929e+00 }, - { -2.576109521642196e-09, 2.805274930179221e+00 }, - { -2.584572342040407e-09, 2.812941975996573e+00 }, - { -2.592937854750428e-09, 2.820538407710556e+00 }, - { -2.601205744816134e-09, 2.828063530521908e+00 }, - { -2.609375700955458e-09, 2.835516651001539e+00 }, - { -2.617447415574869e-09, 2.842897077134583e+00 }, - { -2.625420584778350e-09, 2.850204118359573e+00 }, - { -2.633294908380520e-09, 2.857437085611509e+00 }, - { -2.641070089918234e-09, 2.864595291363663e+00 }, - { -2.648745836659391e-09, 2.871678049666939e+00 }, - { -2.656321859617343e-09, 2.878684676194483e+00 }, - { -2.663797873558322e-09, 2.885614488280000e+00 }, - { -2.671173597015318e-09, 2.892466804962122e+00 }, - { -2.678448752295859e-09, 2.899240947023252e+00 }, - { -2.685623065495139e-09, 2.905936237033475e+00 }, - { -2.692696266503800e-09, 2.912551999389617e+00 }, - { -2.699668089019767e-09, 2.919087560358171e+00 }, - { -2.706538270558513e-09, 2.925542248116882e+00 }, - { -2.713306552460767e-09, 2.931915392794031e+00 }, - { -2.719972679905295e-09, 2.938206326512581e+00 }, - { -2.726536401915442e-09, 2.944414383428562e+00 }, - { -2.732997471371516e-09, 2.950538899775061e+00 }, - { -2.739355645017194e-09, 2.956579213900666e+00 }, - { -2.745610683471516e-09, 2.962534666313284e+00 }, - { -2.751762351235315e-09, 2.968404599718795e+00 }, - { -2.757810416701751e-09, 2.974188359063684e+00 }, - { -2.763754652165128e-09, 2.979885291576143e+00 }, - { -2.769594833827588e-09, 2.985494746805227e+00 }, - { -2.775330741810390e-09, 2.991016076664491e+00 }, - { -2.780962160159068e-09, 2.996448635469842e+00 }, - { -2.786488876854607e-09, 3.001791779983262e+00 }, - { -2.791910683818570e-09, 3.007044869450794e+00 }, - { -2.797227376923695e-09, 3.012207265645876e+00 }, - { -2.802438755998943e-09, 3.017278332907412e+00 }, - { -2.807544624838820e-09, 3.022257438182037e+00 }, - { -2.812544791210840e-09, 3.027143951064684e+00 }, - { -2.817439066860792e-09, 3.031937243837070e+00 }, - { -2.822227267522746e-09, 3.036636691510884e+00 }, - { -2.826909212922864e-09, 3.041241671864994e+00 }, - { -2.831484726789317e-09, 3.045751565488710e+00 }, - { -2.835953636855826e-09, 3.050165755818853e+00 }, - { -2.840315774871260e-09, 3.054483629182857e+00 }, - { -2.844570976602957e-09, 3.058704574835744e+00 }, - { -2.848719081844986e-09, 3.062827985002047e+00 }, - { -2.852759934424164e-09, 3.066853254915581e+00 }, - { -2.856693382203833e-09, 3.070779782857041e+00 }, - { -2.860519277092708e-09, 3.074606970196721e+00 }, - { -2.864237475047239e-09, 3.078334221430809e+00 }, - { -2.867847836080156e-09, 3.081960944223928e+00 }, - { -2.871350224262603e-09, 3.085486549445314e+00 }, - { -2.874744507732462e-09, 3.088910451211251e+00 }, - { -2.878030558696270e-09, 3.092232066921130e+00 }, - { -2.881208253436038e-09, 3.095450817298478e+00 }, - { -2.884277472313999e-09, 3.098566126429974e+00 }, - { -2.887238099774968e-09, 3.101577421802070e+00 }, - { -2.890090024353816e-09, 3.104484134342861e+00 }, - { -2.892833138676371e-09, 3.107285698457308e+00 }, - { -2.895467339466766e-09, 3.109981552069083e+00 }, - { -2.897992527547963e-09, 3.112571136655481e+00 }, - { -2.900408607848946e-09, 3.115053897289195e+00 }, - { -2.902715489404992e-09, 3.117429282673042e+00 }, - { -2.904913085363323e-09, 3.119696745180238e+00 }, - { -2.907001312986328e-09, 3.121855740892224e+00 }, - { -2.908980093652563e-09, 3.123905729634218e+00 }, - { -2.910849352862924e-09, 3.125846175016163e+00 }, - { -2.912609020239985e-09, 3.127676544466606e+00 }, - { -2.914259029534118e-09, 3.129396309273659e+00 }, - { -2.915799318622574e-09, 3.131004944618667e+00 }, - { -2.917229829515169e-09, 3.132501929616775e+00 }, - { -2.918550508353347e-09, 3.133886747350606e+00 }, - { -2.919761305414294e-09, 3.135158884909254e+00 }, - { -2.920862175112829e-09, 3.136317833424958e+00 }, - { -2.921853076000972e-09, 3.137363088107359e+00 }, - { -2.922733970772719e-09, 3.138294148283254e+00 }, - { -2.923504826262027e-09, 3.139110517429204e+00 }, - { -2.924165613447473e-09, 3.139811703211207e+00 }, - { -2.924716307449950e-09, 3.140397217517018e+00 }, - { -2.925156887536978e-09, 3.140866576495489e+00 }, - { -2.925487337120335e-09, 3.141219300588825e+00 }, - { -2.925707643758784e-09, 3.141454914570261e+00 }, - { -2.925817799158535e-09, 3.141572947579352e+00 }, - { -2.925817799171455e-09, 3.141572933154836e+00 }, - { -2.925707643798390e-09, 3.141454409272987e+00 }, - { -2.925487337185779e-09, 3.141216918378770e+00 }, - { -2.925156887628892e-09, 3.140860007424112e+00 }, - { -2.924716307568119e-09, 3.140383227898687e+00 }, - { -2.924165613591896e-09, 3.139786135867868e+00 }, - { -2.923504826432903e-09, 3.139068292003385e+00 }, - { -2.922733970969412e-09, 3.138229261619561e+00 }, - { -2.921853076224321e-09, 3.137268614707029e+00 }, - { -2.920862175361976e-09, 3.136185925964038e+00 }, - { -2.919761305690083e-09, 3.134980774833275e+00 }, - { -2.918550508654911e-09, 3.133652745531368e+00 }, - { -2.917229829843137e-09, 3.132201427085629e+00 }, - { -2.915799318976726e-09, 3.130626413363146e+00 }, - { -2.914259029914435e-09, 3.128927303107136e+00 }, - { -2.912609020646661e-09, 3.127103699965947e+00 }, - { -2.910849353295315e-09, 3.125155212527586e+00 }, - { -2.908980094111509e-09, 3.123081454351802e+00 }, - { -2.907001313470937e-09, 3.120882043999591e+00 }, - { -2.904913085874448e-09, 3.118556605068443e+00 }, - { -2.902715489941767e-09, 3.116104766219928e+00 }, - { -2.900408608411958e-09, 3.113526161214776e+00 }, - { -2.897992528137022e-09, 3.110820428940251e+00 }, - { -2.895467340081818e-09, 3.107987213444579e+00 }, - { -2.892833139317615e-09, 3.105026163964191e+00 }, - { -2.890090025020589e-09, 3.101936934956479e+00 }, - { -2.887238100468092e-09, 3.098719186130021e+00 }, - { -2.884277473032614e-09, 3.095372582472161e+00 }, - { -2.881208254180937e-09, 3.091896794282404e+00 }, - { -2.878030559466594e-09, 3.088291497198199e+00 }, - { -2.874744508528832e-09, 3.084556372228054e+00 }, - { -2.871350225084755e-09, 3.080691105776848e+00 }, - { -2.867847836928063e-09, 3.076695389678615e+00 }, - { -2.864237475921086e-09, 3.072568921221621e+00 }, - { -2.860519277991847e-09, 3.068311403179147e+00 }, - { -2.856693383129018e-09, 3.063922543837792e+00 }, - { -2.852759935374575e-09, 3.059402057023109e+00 }, - { -2.848719082821403e-09, 3.054749662130841e+00 }, - { -2.844570977604520e-09, 3.049965084150782e+00 }, - { -2.840315775898525e-09, 3.045048053697736e+00 }, - { -2.835953637908582e-09, 3.039998307034967e+00 }, - { -2.831484727867511e-09, 3.034815586104635e+00 }, - { -2.826909214026628e-09, 3.029499638550941e+00 }, - { -2.822227268651470e-09, 3.024050217748861e+00 }, - { -2.817439068015245e-09, 3.018467082830179e+00 }, - { -2.812544792390175e-09, 3.012749998707001e+00 }, - { -2.807544626043751e-09, 3.006898736100911e+00 }, - { -2.802438757228650e-09, 3.000913071564665e+00 }, - { -2.797227378178760e-09, 2.994792787510961e+00 }, - { -2.791910685098702e-09, 2.988537672233504e+00 }, - { -2.786488878159805e-09, 2.982147519935565e+00 }, - { -2.780962161489413e-09, 2.975622130750641e+00 }, - { -2.775330743165298e-09, 2.968961310769028e+00 }, - { -2.769594835207775e-09, 2.962164872061613e+00 }, - { -2.763754653569747e-09, 2.955232632701135e+00 }, - { -2.757810418131543e-09, 2.948164416789036e+00 }, - { -2.751762352689432e-09, 2.940960054474719e+00 }, - { -2.745610684950541e-09, 2.933619381982341e+00 }, - { -2.739355646520809e-09, 2.926142241629213e+00 }, - { -2.732997472899722e-09, 2.918528481852205e+00 }, - { -2.726536403468318e-09, 2.910777957226018e+00 }, - { -2.719972681482232e-09, 2.902890528487386e+00 }, - { -2.713306554062453e-09, 2.894866062556452e+00 }, - { -2.706538272184154e-09, 2.886704432555728e+00 }, - { -2.699668090670078e-09, 2.878405517834426e+00 }, - { -2.692696268177908e-09, 2.869969203985464e+00 }, - { -2.685623067193599e-09, 2.861395382869544e+00 }, - { -2.678448754018380e-09, 2.852683952631486e+00 }, - { -2.671173598761847e-09, 2.843834817723832e+00 }, - { -2.663797875328991e-09, 2.834847888922988e+00 }, - { -2.656321861411517e-09, 2.825723083350459e+00 }, - { -2.648745838477759e-09, 2.816460324492298e+00 }, - { -2.641070091759922e-09, 2.807059542215146e+00 }, - { -2.633294910246296e-09, 2.797520672788269e+00 }, - { -2.625420586667340e-09, 2.787843658897949e+00 }, - { -2.617447417487602e-09, 2.778028449668942e+00 }, - { -2.609375702891616e-09, 2.768075000678399e+00 }, - { -2.601205746775692e-09, 2.757983273976943e+00 }, - { -2.592937856733464e-09, 2.747753238101915e+00 }, - { -2.584572344046340e-09, 2.737384868096553e+00 }, - { -2.576109523671634e-09, 2.726878145526201e+00 }, - { -2.567549714229129e-09, 2.716233058492422e+00 }, - { -2.558893237991435e-09, 2.705449601651722e+00 }, - { -2.550140420869302e-09, 2.694527776227857e+00 }, - { -2.541291592402089e-09, 2.683467590030445e+00 }, - { -2.532347085742440e-09, 2.672269057466213e+00 }, - { -2.523307237646751e-09, 2.660932199557362e+00 }, - { -2.514172388459584e-09, 2.649457043952206e+00 }, - { -2.504942882102813e-09, 2.637843624941622e+00 }, - { -2.495619066062810e-09, 2.626091983472908e+00 }, - { -2.486201291375123e-09, 2.614202167160335e+00 }, - { -2.476689912614465e-09, 2.602174230302269e+00 }, - { -2.467085287878098e-09, 2.590008233889805e+00 }, - { -2.457387778775451e-09, 2.577704245623143e+00 }, - { -2.447597750411553e-09, 2.565262339920002e+00 }, - { -2.437715571376127e-09, 2.552682597931055e+00 }, - { -2.427741613727123e-09, 2.539965107548168e+00 }, - { -2.417676252978335e-09, 2.527109963417675e+00 }, - { -2.407519868085581e-09, 2.514117266951687e+00 }, - { -2.397272841430131e-09, 2.500987126335739e+00 }, - { -2.386935558807595e-09, 2.487719656543254e+00 }, - { -2.376508409410024e-09, 2.474314979341178e+00 }, - { -2.365991785814531e-09, 2.460773223303822e+00 }, - { -2.355386083965131e-09, 2.447094523817833e+00 }, - { -2.344691703161363e-09, 2.433279023095734e+00 }, - { -2.333909046040126e-09, 2.419326870180582e+00 }, - { -2.323038518562289e-09, 2.405238220956597e+00 }, - { -2.312080529997549e-09, 2.391013238157397e+00 }, - { -2.301035492907384e-09, 2.376652091371587e+00 }, - { -2.289903823131822e-09, 2.362154957053137e+00 }, - { -2.278685939771276e-09, 2.347522018525197e+00 }, - { -2.267382265173420e-09, 2.332753465990296e+00 }, - { -2.255993224914501e-09, 2.317849496533128e+00 }, - { -2.244519247786155e-09, 2.302810314130351e+00 }, - { -2.232960765776561e-09, 2.287636129652823e+00 }, - { -2.221318214056095e-09, 2.272327160873552e+00 }, - { -2.209592030960763e-09, 2.256883632472565e+00 }, - { -2.197782657974034e-09, 2.241305776039511e+00 }, - { -2.185890539712767e-09, 2.225593830081461e+00 }, - { -2.173916123907886e-09, 2.209748040023618e+00 }, - { -2.161859861389976e-09, 2.193768658216360e+00 }, - { -2.149722206070124e-09, 2.177655943935795e+00 }, - { -2.137503614923981e-09, 2.161410163388424e+00 }, - { -2.125204547975352e-09, 2.145031589714984e+00 }, - { -2.112825468276292e-09, 2.128520502989477e+00 }, - { -2.100366841892917e-09, 2.111877190225612e+00 }, - { -2.087829137884807e-09, 2.095101945374541e+00 }, - { -2.075212828290086e-09, 2.078195069329960e+00 }, - { -2.062518388104923e-09, 2.061156869925600e+00 }, - { -2.049746295268559e-09, 2.043987661939897e+00 }, - { -2.036897030642658e-09, 2.026687767092888e+00 }, - { -2.023971077994576e-09, 2.009257514048162e+00 }, - { -2.010968923979840e-09, 1.991697238413571e+00 }, - { -1.997891058121344e-09, 1.974007282737320e+00 }, - { -1.984737972794098e-09, 1.956187996511354e+00 }, - { -1.971510163203686e-09, 1.938239736166060e+00 }, - { -1.958208127370276e-09, 1.920162865072273e+00 }, - { -1.944832366107339e-09, 1.901957753535934e+00 }, - { -1.931383383005451e-09, 1.883624778799427e+00 }, - { -1.917861684410531e-09, 1.865164325035177e+00 }, - { -1.904267779407432e-09, 1.846576783346324e+00 }, - { -1.890602179798714e-09, 1.827862551760622e+00 }, - { -1.876865400086483e-09, 1.809022035228338e+00 }, - { -1.863057957452539e-09, 1.790055645617624e+00 }, - { -1.849180371740008e-09, 1.770963801711725e+00 }, - { -1.835233165431475e-09, 1.751746929201178e+00 }, - { -1.821216863631569e-09, 1.732405460681919e+00 }, - { -1.807131994045840e-09, 1.712939835648088e+00 }, - { -1.792979086962494e-09, 1.693350500488565e+00 }, - { -1.778758675229683e-09, 1.673637908477153e+00 }, - { -1.764471294238191e-09, 1.653802519770021e+00 }, - { -1.750117481899733e-09, 1.633844801396848e+00 }, - { -1.735697778626995e-09, 1.613765227254186e+00 }, - { -1.721212727314574e-09, 1.593564278099856e+00 }, - { -1.706662873315474e-09, 1.573242441540939e+00 }, - { -1.692048764423848e-09, 1.552800212030258e+00 }, - { -1.677370950852395e-09, 1.532238090855187e+00 }, - { -1.662629985213192e-09, 1.511556586131055e+00 }, - { -1.647826422494560e-09, 1.490756212788764e+00 }, - { -1.632960820042537e-09, 1.469837492568651e+00 }, - { -1.618033737538645e-09, 1.448800954008929e+00 }, - { -1.603045736978760e-09, 1.427647132435469e+00 }, - { -1.587997382653428e-09, 1.406376569953373e+00 }, - { -1.572889241124034e-09, 1.384989815432507e+00 }, - { -1.557721881203696e-09, 1.363487424499449e+00 }, - { -1.542495873934815e-09, 1.341869959524515e+00 }, - { -1.527211792568486e-09, 1.320137989611176e+00 }, - { -1.511870212541253e-09, 1.298292090581491e+00 }, - { -1.496471711454994e-09, 1.276332844965754e+00 }, - { -1.481016869054634e-09, 1.254260841988828e+00 }, - { -1.465506267206068e-09, 1.232076677556547e+00 }, - { -1.449940489875303e-09, 1.209780954243628e+00 }, - { -1.434320123104372e-09, 1.187374281276747e+00 }, - { -1.418645754991533e-09, 1.164857274523495e+00 }, - { -1.402917975667710e-09, 1.142230556475749e+00 }, - { -1.387137377275425e-09, 1.119494756236361e+00 }, - { -1.371304553944712e-09, 1.096650509501278e+00 }, - { -1.355420101772623e-09, 1.073698458546610e+00 }, - { -1.339484618799891e-09, 1.050639252211352e+00 }, - { -1.323498704988051e-09, 1.027473545880543e+00 }, - { -1.307462962198534e-09, 1.004202001471034e+00 }, - { -1.291377994167204e-09, 9.808252874104182e-01 }, - { -1.275244406484394e-09, 9.573440786237052e-01 }, - { -1.259062806570190e-09, 9.337590565128454e-01 }, - { -1.242833803653464e-09, 9.100709089414796e-01 }, - { -1.226558008746195e-09, 8.862803302125812e-01 }, - { -1.210236034623253e-09, 8.623880210538113e-01 }, - { -1.193868495797618e-09, 8.383946885959868e-01 }, - { -1.177456008497777e-09, 8.143010463544786e-01 }, - { -1.160999190645010e-09, 7.901078142102129e-01 }, - { -1.144498661828833e-09, 7.658157183877095e-01 }, - { -1.127955043284965e-09, 7.414254914366063e-01 }, - { -1.111368957870986e-09, 7.169378722095157e-01 }, - { -1.094741030044308e-09, 6.923536058430697e-01 }, - { -1.078071885836393e-09, 6.676734437331688e-01 }, - { -1.061362152831423e-09, 6.428981435165511e-01 }, - { -1.044612460141255e-09, 6.180284690466404e-01 }, - { -1.027823438382183e-09, 5.930651903718045e-01 }, - { -1.010995719652015e-09, 5.680090837138436e-01 }, - { -9.941299375042378e-10, 5.428609314418970e-01 }, - { -9.772267269262058e-10, 5.176215220520872e-01 }, - { -9.602867243141016e-10, 4.922916501421032e-01 }, - { -9.433105674499058e-10, 4.668721163885412e-01 }, - { -9.262988954758817e-10, 4.413637275202624e-01 }, - { -9.092523488719689e-10, 4.157672962958654e-01 }, - { -8.921715694311144e-10, 3.900836414778084e-01 }, - { -8.750572002347607e-10, 3.643135878065193e-01 }, - { -8.579098856296589e-10, 3.384579659762392e-01 }, - { -8.407302712022458e-10, 3.125176126069478e-01 }, - { -8.235190037551917e-10, 2.864933702193017e-01 }, - { -8.062767312831008e-10, 2.603860872080448e-01 }, - { -7.890041029479477e-10, 2.341966178147619e-01 }, - { -7.717017690542486e-10, 2.079258220999725e-01 }, - { -7.543703810250266e-10, 1.815745659161734e-01 }, - { -7.370105913774597e-10, 1.551437208801425e-01 }, - { -7.196230536974697e-10, 1.286341643433767e-01 }, - { -7.022084226165876e-10, 1.020467793657360e-01 }, - { -6.847673537853251e-10, 7.538245468350446e-02 }, - { -6.673005038502516e-10, 4.864208468284503e-02 }, - { -6.498085304282128e-10, 2.182656936863137e-02 }, - { -6.322920920826137e-10, -5.063185663820913e-03 }, - { -6.147518482969490e-10, -3.202626926150343e-02 }, - { -5.971884594516681e-10, -5.906176474160862e-02 }, - { -5.796025867984469e-10, -8.616874992366363e-02 }, - { -5.619948924353588e-10, -1.133462971605448e-01 }, - { -5.443660392823640e-10, -1.405934733692621e-01 }, - { -5.267166910556339e-10, -1.679093400638023e-01 }, - { -5.090475122431451e-10, -1.952929533862739e-01 }, - { -4.913591680795342e-10, -2.227433641394564e-01 }, - { -4.736523245210571e-10, -2.502596178194491e-01 }, - { -4.559276482202303e-10, -2.778407546490776e-01 }, - { -4.381858065011618e-10, -3.054858096104932e-01 }, - { -4.204274673340870e-10, -3.331938124792702e-01 }, - { -4.026532993105397e-10, -3.609637878577768e-01 }, - { -3.848639716178888e-10, -3.887947552098022e-01 }, - { -3.670601540142443e-10, -4.166857288948674e-01 }, - { -3.492425168032583e-10, -4.446357182029681e-01 }, - { -3.314117308088734e-10, -4.726437273896633e-01 }, - { -3.135684673501752e-10, -5.007087557112619e-01 }, - { -2.957133982159296e-10, -5.288297974607742e-01 }, - { -2.778471956393828e-10, -5.570058420037128e-01 }, - { -2.599705322729564e-10, -5.852358738143247e-01 }, - { -2.420840811628366e-10, -6.135188725122560e-01 }, - { -2.241885157240923e-10, -6.418538128986450e-01 }, - { -2.062845097142585e-10, -6.702396649949099e-01 }, - { -1.883727372093546e-10, -6.986753940779493e-01 }, - { -1.704538725773087e-10, -7.271599607197149e-01 }, - { -1.525285904532877e-10, -7.556923208240308e-01 }, - { -1.345975657140748e-10, -7.842714256651911e-01 }, - { -1.166614734526054e-10, -8.128962219265712e-01 }, - { -9.872098895260891e-11, -8.415656517393372e-01 }, - { -8.077678766314517e-11, -8.702786527215916e-01 }, - { -6.282954517324612e-11, -8.990341580176152e-01 }, - { -4.487993718655790e-11, -9.278310963373758e-01 }, - { -2.692863949561210e-11, -9.566683919968972e-01 }, - { -8.976327956520795e-12, -9.855449649582175e-01 }, - { 8.976321536169872e-12, -1.014459730869357e+00 }, - { 2.692863307547294e-11, -1.043411601105914e+00 }, - { 4.487993076694813e-11, -1.072399482811314e+00 }, - { 6.282953875437751e-11, -1.101422278938424e+00 }, - { 8.077678124517653e-11, -1.130478888291020e+00 }, - { 9.872098253591082e-11, -1.159568205565684e+00 }, - { 1.166614670373367e-10, -1.188689121393192e+00 }, - { 1.345975593005002e-10, -1.217840522381901e+00 }, - { 1.525285840416718e-10, -1.247021291159495e+00 }, - { 1.704538661678104e-10, -1.276230306415868e+00 }, - { 1.883727308022916e-10, -1.305466442946703e+00 }, - { 2.062845033098954e-10, -1.334728571696106e+00 }, - { 2.241885093225349e-10, -1.364015559800721e+00 }, - { 2.420840747645085e-10, -1.393326270633325e+00 }, - { 2.599705258779635e-10, -1.422659563847049e+00 }, - { 2.778471892479898e-10, -1.452014295419243e+00 }, - { 2.957133918284542e-10, -1.481389317696831e+00 }, - { 3.135684609667761e-10, -1.510783479440191e+00 }, - { 3.314117244297624e-10, -1.540195625869043e+00 }, - { 3.492425104288060e-10, -1.569624598707558e+00 }, - { 3.670601476445565e-10, -1.599069236228850e+00 }, - { 3.848639652533361e-10, -1.628528373302631e+00 }, - { 4.026532929512281e-10, -1.658000841439269e+00 }, - { 4.204274609803869e-10, -1.687485468837799e+00 }, - { 4.381858001531792e-10, -1.716981080430596e+00 }, - { 4.559276418782829e-10, -1.746486497931567e+00 }, - { 4.736523181853565e-10, -1.776000539882225e+00 }, - { 4.913591617503452e-10, -1.805522021699094e+00 }, - { 5.090475059206794e-10, -1.835049755721194e+00 }, - { 5.267166847401562e-10, -1.864582551257262e+00 }, - { 5.443660329740862e-10, -1.894119214633676e+00 }, - { 5.619948861345454e-10, -1.923658549242818e+00 }, - { 5.796025805053097e-10, -1.953199355591180e+00 }, - { 5.971884531664190e-10, -1.982740431347091e+00 }, - { 6.147518420199055e-10, -2.012280571390674e+00 }, - { 6.322920858139346e-10, -2.041818567861395e+00 }, - { 6.498085241682158e-10, -2.071353210208005e+00 }, - { 6.673004975990425e-10, -2.100883285238127e+00 }, - { 6.847673475432746e-10, -2.130407577166309e+00 }, - { 7.022084163838545e-10, -2.159924867664933e+00 }, - { 7.196230474743716e-10, -2.189433935913779e+00 }, - { 7.370105851640495e-10, -2.218933558650552e+00 }, - { 7.543703748217808e-10, -2.248422510220072e+00 }, - { 7.717017628611672e-10, -2.277899562625407e+00 }, - { 7.890040967654542e-10, -2.307363485579104e+00 }, - { 8.062767251113011e-10, -2.336813046552684e+00 }, - { 8.235189975944034e-10, -2.366247010829556e+00 }, - { 8.407302650525749e-10, -2.395664141553858e+00 }, - { 8.579098794915287e-10, -2.425063199784153e+00 }, - { 8.750571941082773e-10, -2.454442944543319e+00 }, - { 8.921715633164894e-10, -2.483802132872044e+00 }, - { 9.092523427695200e-10, -2.513139519878584e+00 }, - { 9.262988893857148e-10, -2.542453858792682e+00 }, - { 9.433105613723914e-10, -2.571743901017465e+00 }, - { 9.602867182493987e-10, -2.601008396180870e+00 }, - { 9.772267208744730e-10, -2.630246092190425e+00 }, - { 9.941299314658458e-10, -2.659455735283526e+00 }, - { 1.010995713627070e-09, -2.688636070081818e+00 }, - { 1.027823432371055e-09, -2.717785839644439e+00 }, - { 1.044612454143997e-09, -2.746903785521352e+00 }, - { 1.061362146848353e-09, -2.775988647805256e+00 }, - { 1.078071879867828e-09, -2.805039165187255e+00 }, - { 1.094741024090249e-09, -2.834054075009077e+00 }, - { 1.111368951931856e-09, -2.863032113318052e+00 }, - { 1.127955037360817e-09, -2.891972014920939e+00 }, - { 1.144498655920037e-09, -2.920872513436805e+00 }, - { 1.160999184751779e-09, -2.949732341353290e+00 }, - { 1.177456002620215e-09, -2.978550230079517e+00 }, - { 1.193868489936097e-09, -3.007324910002949e+00 }, - { 1.210236028777826e-09, -3.036055110540183e+00 }, - { 1.226558002917232e-09, -3.064739560196251e+00 }, - { 1.242833797841123e-09, -3.093376986616735e+00 }, - { 1.259062800774685e-09, -3.121966116643377e+00 }, - { 1.275244400705935e-09, -3.150505676371791e+00 }, - { 1.291377988406056e-09, -3.178994391202159e+00 }, - { 1.307462956454857e-09, -3.207430985899192e+00 }, - { 1.323498699262108e-09, -3.235814184645077e+00 }, - { 1.339484613091842e-09, -3.264142711097884e+00 }, - { 1.355420096082785e-09, -3.292415288443373e+00 }, - { 1.371304548273191e-09, -3.320630639454825e+00 }, - { 1.387137371622433e-09, -3.348787486547389e+00 }, - { 1.402917970033511e-09, -3.376884551834256e+00 }, - { 1.418645749376393e-09, -3.404920557184582e+00 }, - { 1.434320117508396e-09, -3.432894224276359e+00 }, - { 1.449940484298756e-09, -3.460804274656981e+00 }, - { 1.465506261649108e-09, -3.488649429796768e+00 }, - { 1.481016863517580e-09, -3.516428411149154e+00 }, - { 1.496471705937951e-09, -3.544139940202303e+00 }, - { 1.511870207044433e-09, -3.571782738540999e+00 }, - { 1.527211787092206e-09, -3.599355527901174e+00 }, - { 1.542495868479076e-09, -3.626857030226671e+00 }, - { 1.557721875768920e-09, -3.654285967729458e+00 }, - { 1.572889235710329e-09, -3.681641062941412e+00 }, - { 1.587997377261005e-09, -3.708921038776707e+00 }, - { 1.603045731607830e-09, -3.736124618586623e+00 }, - { 1.618033732189314e-09, -3.763250526218862e+00 }, - { 1.632960814715177e-09, -3.790297486071938e+00 }, - { 1.647826417189275e-09, -3.817264223155802e+00 }, - { 1.662629979930247e-09, -3.844149463148589e+00 }, - { 1.677370945591844e-09, -3.870951932452996e+00 }, - { 1.692048759186008e-09, -3.897670358257890e+00 }, - { 1.706662868100504e-09, -3.924303468590212e+00 }, - { 1.721212722122685e-09, -3.950849992378278e+00 }, - { 1.735697773458400e-09, -3.977308659506432e+00 }, - { 1.750117476754591e-09, -4.003678200876669e+00 }, - { 1.764471289116712e-09, -4.029957348461003e+00 }, - { 1.778758670132079e-09, -4.056144835364877e+00 }, - { 1.792979081888926e-09, -4.082239395882965e+00 }, - { 1.807131988996465e-09, -4.108239765556996e+00 }, - { 1.821216858606652e-09, -4.134144681236933e+00 }, - { 1.835233160431175e-09, -4.159952881133585e+00 }, - { 1.849180366764537e-09, -4.185663104882633e+00 }, - { 1.863057952502055e-09, -4.211274093599509e+00 }, - { 1.876865395161145e-09, -4.236784589940537e+00 }, - { 1.890602174898734e-09, -4.262193338157148e+00 }, - { 1.904267774533022e-09, -4.287499084158302e+00 }, - { 1.917861679562008e-09, -4.312700575567174e+00 }, - { 1.931383378182392e-09, -4.337796561778708e+00 }, - { 1.944832361310856e-09, -4.362785794021793e+00 }, - { 1.958208122599839e-09, -4.387667025411434e+00 }, - { 1.971510158459931e-09, -4.412439011013396e+00 }, - { 1.984737968076495e-09, -4.437100507898339e+00 }, - { 1.997891053431005e-09, -4.461650275204912e+00 }, - { 2.010968919316289e-09, -4.486087074191693e+00 }, - { 2.023971073358447e-09, -4.510409668301784e+00 }, - { 2.036897026033634e-09, -4.534616823217992e+00 }, - { 2.049746290686799e-09, -4.558707306921882e+00 }, - { 2.062518383551274e-09, -4.582679889754607e+00 }, - { 2.075212823764071e-09, -4.606533344469879e+00 }, - { 2.087829133387063e-09, -4.630266446298172e+00 }, - { 2.100366837422912e-09, -4.653877973001258e+00 }, - { 2.112825463835087e-09, -4.677366704934605e+00 }, - { 2.125204543562522e-09, -4.700731425099899e+00 }, - { 2.137503610540056e-09, -4.723970919208608e+00 }, - { 2.149722201714786e-09, -4.747083975738060e+00 }, - { 2.161859857063438e-09, -4.770069385989595e+00 }, - { 2.173916119610994e-09, -4.792925944149308e+00 }, - { 2.185890535445098e-09, -4.815652447340950e+00 }, - { 2.197782653735957e-09, -4.838247695689436e+00 }, - { 2.209592026751962e-09, -4.860710492376411e+00 }, - { 2.221318209877576e-09, -4.883039643700314e+00 }, - { 2.232960761627846e-09, -4.905233959130168e+00 }, - { 2.244519243667616e-09, -4.927292251368517e+00 }, - { 2.255993220826402e-09, -4.949213336406265e+00 }, - { 2.267382261115285e-09, -4.970996033581527e+00 }, - { 2.278685935744269e-09, -4.992639165639563e+00 }, - { 2.289903819135414e-09, -5.014141558784778e+00 }, - { 2.301035488942000e-09, -5.035502042744443e+00 }, - { 2.312080526062763e-09, -5.056719450823151e+00 }, - { 2.323038514659161e-09, -5.077792619963239e+00 }, - { 2.333909042168180e-09, -5.098720390796817e+00 }, - { 2.344691699320969e-09, -5.119501607709159e+00 }, - { 2.355386080156553e-09, -5.140135118892792e+00 }, - { 2.365991782037187e-09, -5.160619776404897e+00 }, - { 2.376508405665132e-09, -5.180954436227641e+00 }, - { 2.386935555094626e-09, -5.201137958319343e+00 }, - { 2.397272837749508e-09, -5.221169206676762e+00 }, - { 2.407519864436774e-09, -5.241047049389645e+00 }, - { 2.417676249362563e-09, -5.260770358700167e+00 }, - { 2.427741610143750e-09, -5.280338011053974e+00 }, - { 2.437715567825576e-09, -5.299748887163106e+00 }, - { 2.447597746894037e-09, -5.319001872058887e+00 }, - { 2.457387775290440e-09, -5.338095855149190e+00 }, - { 2.467085284426756e-09, -5.357029730277389e+00 }, - { 2.476689909196263e-09, -5.375802395772283e+00 }, - { 2.486201287990485e-09, -5.394412754510426e+00 }, - { 2.495619062711154e-09, -5.412859713968929e+00 }, - { 2.504942878785408e-09, -5.431142186284682e+00 }, - { 2.514172385175743e-09, -5.449259088303476e+00 }, - { 2.523307234396791e-09, -5.467209341642627e+00 }, - { 2.532347082526785e-09, -5.484991872743321e+00 }, - { 2.541291589219998e-09, -5.502605612925014e+00 }, - { 2.550140417722072e-09, -5.520049498445633e+00 }, - { 2.558893234878378e-09, -5.537322470548212e+00 }, - { 2.567549711150773e-09, -5.554423475524196e+00 }, - { 2.576109520627371e-09, -5.571351464763084e+00 }, - { 2.584572341037361e-09, -5.588105394812198e+00 }, - { 2.592937853759161e-09, -5.604684227423386e+00 }, - { 2.601205743836355e-09, -5.621086929615246e+00 }, - { 2.609375699987564e-09, -5.637312473723475e+00 }, - { 2.617447414618146e-09, -5.653359837454964e+00 }, - { 2.625420583833750e-09, -5.669228003945694e+00 }, - { 2.633294907447937e-09, -5.684915961806963e+00 }, - { 2.641070088997271e-09, -5.700422705186584e+00 }, - { 2.648745835750128e-09, -5.715747233817712e+00 }, - { 2.656321858720176e-09, -5.730888553077074e+00 }, - { 2.663797872673252e-09, -5.745845674030161e+00 }, - { 2.671173596142054e-09, -5.760617613492118e+00 }, - { 2.678448751434797e-09, -5.775203394076705e+00 }, - { 2.685623064645538e-09, -5.789602044248679e+00 }, - { 2.692696265666640e-09, -5.803812598380606e+00 }, - { 2.699668088194915e-09, -5.817834096797069e+00 }, - { 2.706538269745573e-09, -5.831665585834668e+00 }, - { 2.713306551659817e-09, -5.845306117889361e+00 }, - { 2.719972679116734e-09, -5.858754751472542e+00 }, - { 2.726536401139295e-09, -5.872010551255358e+00 }, - { 2.732997470607439e-09, -5.885072588127400e+00 }, - { 2.739355644265558e-09, -5.897939939244211e+00 }, - { 2.745610682731633e-09, -5.910611688078208e+00 }, - { 2.751762350508137e-09, -5.923086924473290e+00 }, - { 2.757810415987146e-09, -5.935364744687794e+00 }, - { 2.763754651462700e-09, -5.947444251452243e+00 }, - { 2.769594833137415e-09, -5.959324554015538e+00 }, - { 2.775330741132843e-09, -5.971004768198829e+00 }, - { 2.780962159494174e-09, -5.982484016437981e+00 }, - { 2.786488876202047e-09, -5.993761427840588e+00 }, - { 2.791910683178690e-09, -6.004836138231525e+00 }, - { 2.797227376295779e-09, -6.015707290202086e+00 }, - { 2.802438755383971e-09, -6.026374033162623e+00 }, - { 2.807544624236659e-09, -6.036835523383457e+00 }, - { 2.812544790621093e-09, -6.047090924050914e+00 }, - { 2.817439066283459e-09, -6.057139405311101e+00 }, - { 2.822227266958278e-09, -6.066980144322601e+00 }, - { 2.826909212371261e-09, -6.076612325295799e+00 }, - { 2.831484726250221e-09, -6.086035139548830e+00 }, - { 2.835953636329660e-09, -6.095247785550617e+00 }, - { 2.840315774357203e-09, -6.104249468967751e+00 }, - { 2.844570976102082e-09, -6.113039402715685e+00 }, - { 2.848719081357095e-09, -6.121616806996519e+00 }, - { 2.852759933948860e-09, -6.129980909353977e+00 }, - { 2.856693381741114e-09, -6.138130944714082e+00 }, - { 2.860519276643053e-09, -6.146066155436312e+00 }, - { 2.864237474610633e-09, -6.153785791350256e+00 }, - { 2.867847835656203e-09, -6.161289109809551e+00 }, - { 2.871350223851726e-09, -6.168575375732642e+00 }, - { 2.874744507333867e-09, -6.175643861647406e+00 }, - { 2.878030558310989e-09, -6.182493847739853e+00 }, - { 2.881208253063899e-09, -6.189124621889823e+00 }, - { 2.884277471954592e-09, -6.195535479723423e+00 }, - { 2.887238099428306e-09, -6.201725724651554e+00 }, - { 2.890090024020323e-09, -6.207694667918394e+00 }, - { 2.892833138356060e-09, -6.213441628635915e+00 }, - { 2.895467339159240e-09, -6.218965933835304e+00 }, - { 2.897992527253659e-09, -6.224266918505075e+00 }, - { 2.900408607567016e-09, -6.229343925633495e+00 }, - { 2.902715489136496e-09, -6.234196306254763e+00 }, - { 2.904913085108075e-09, -6.238823419482017e+00 }, - { 2.907001312743911e-09, -6.243224632557377e+00 }, - { 2.908980093422997e-09, -6.247399320887848e+00 }, - { 2.910849352646620e-09, -6.251346868091392e+00 }, - { 2.912609020036956e-09, -6.255066666028537e+00 }, - { 2.914259029343965e-09, -6.258558114851525e+00 }, - { 2.915799318445710e-09, -6.261820623039620e+00 }, - { 2.917229829350759e-09, -6.264853607438842e+00 }, - { 2.918550508202463e-09, -6.267656493305673e+00 }, - { 2.919761305276718e-09, -6.270228714337005e+00 }, - { 2.920862174988150e-09, -6.272569712717951e+00 }, - { 2.921853075889193e-09, -6.274678939154603e+00 }, - { 2.922733970674264e-09, -6.276555852917634e+00 }, - { 2.923504826176907e-09, -6.278199921870962e+00 }, - { 2.924165613375264e-09, -6.279610622518139e+00 }, - { 2.924716307391075e-09, -6.280787440034993e+00 }, - { 2.925156887490598e-09, -6.281729868306345e+00 }, - { 2.925487337087508e-09, -6.282437409966992e+00 }, - { 2.925707643739298e-09, -6.282909576428774e+00 }, - { 2.925817799151970e-09, -6.283145887925411e+00 }, + {2.925817799165007e-09, 7.219194364267018e-09}, + {2.925707643778599e-09, 2.526699001579799e-07}, + {2.925487337153070e-09, 1.191140162167675e-06}, + {2.925156887582842e-09, 3.284585035595589e-06}, + {2.924716307509151e-09, 6.994872605695784e-06}, + {2.924165613519592e-09, 1.278374920658798e-05}, + {2.923504826347475e-09, 2.111280464718590e-05}, + {2.922733970871080e-09, 3.244343744537165e-05}, + {2.921853076112655e-09, 4.723682007436170e-05}, + {2.920862175237416e-09, 6.595386421935634e-05}, + {2.919761305552202e-09, 8.905518605213658e-05}, + {2.918550508504146e-09, 1.170010715193098e-04}, + {2.917229829679050e-09, 1.502514416517192e-04}, + {2.915799318799769e-09, 1.892658178912071e-04}, + {2.914259029724184e-09, 2.345032874456615e-04}, + {2.912609020443340e-09, 2.864224686607020e-04}, + {2.910849353079123e-09, 3.454814764261432e-04}, + {2.908980093882049e-09, 4.121378876027343e-04}, + {2.907001313228646e-09, 4.868487064877691e-04}, + {2.904913085618902e-09, 5.700703303049837e-04}, + {2.902715489673383e-09, 6.622585147355725e-04}, + {2.900408608130373e-09, 7.638683394782519e-04}, + {2.897992527842612e-09, 8.753541738578119e-04}, + {2.895467339774186e-09, 9.971696424604937e-04}, + {2.892833138996999e-09, 1.129767590823255e-03}, + {2.890090024687216e-09, 1.273600051161478e-03}, + {2.887238100121550e-09, 1.429118208142094e-03}, + {2.884277472673313e-09, 1.596772364709564e-03}, + {2.881208253808507e-09, 1.777011907950626e-03}, + {2.878030559081432e-09, 1.970285275029487e-03}, + {2.874744508130554e-09, 2.177039919152579e-03}, + {2.871350224673798e-09, 2.397722275614272e-03}, + {2.867847836504030e-09, 2.632777727878843e-03}, + {2.864237475484149e-09, 2.882650573737405e-03}, + {2.860519277542297e-09, 3.147783991507308e-03}, + {2.856693382666432e-09, 3.428620006328931e-03}, + {2.852759934899389e-09, 3.725599456482154e-03}, + {2.848719082333207e-09, 4.039161959812243e-03}, + {2.844570977103752e-09, 4.369745880190706e-03}, + {2.840315775384800e-09, 4.717788294077374e-03}, + {2.835953637382310e-09, 5.083724957128360e-03}, + {2.831484727328322e-09, 5.467990270896617e-03}, + {2.826909213474759e-09, 5.871017249604038e-03}, + {2.822227268087134e-09, 6.293237486988512e-03}, + {2.817439067438018e-09, 6.735081123237729e-03}, + {2.812544791800534e-09, 7.196976811989608e-03}, + {2.807544625441273e-09, 7.679351687456759e-03}, + {2.802438756613836e-09, 8.182631331563162e-03}, + {2.797227377551135e-09, 8.707239741274575e-03}, + {2.791910684458716e-09, 9.253599295902304e-03}, + {2.786488877507140e-09, 9.822130724578715e-03}, + {2.780962160824228e-09, 1.041325307382490e-02}, + {2.775330742487884e-09, 1.102738367513773e-02}, + {2.769594834517682e-09, 1.166493811278924e-02}, + {2.763754652867477e-09, 1.232633019159818e-02}, + {2.757810417416620e-09, 1.301197190494069e-02}, + {2.751762351962413e-09, 1.372227340270610e-02}, + {2.745610684210923e-09, 1.445764295952962e-02}, + {2.739355645769094e-09, 1.521848694296229e-02}, + {2.732997472135539e-09, 1.600520978188769e-02}, + {2.726536402691907e-09, 1.681821393496225e-02}, + {2.719972680693777e-09, 1.765789985920713e-02}, + {2.713306553261610e-09, 1.852466597868779e-02}, + {2.706538271371373e-09, 1.941890865333146e-02}, + {2.699668089844909e-09, 2.034102214787814e-02}, + {2.692696267340880e-09, 2.129139860085272e-02}, + {2.685623066344263e-09, 2.227042799383416e-02}, + {2.678448753157212e-09, 2.327849812064098e-02}, + {2.671173597888530e-09, 2.431599455681316e-02}, + {2.663797874443630e-09, 2.538330062913108e-02}, + {2.656321860514457e-09, 2.648079738524795e-02}, + {2.648745837568575e-09, 2.760886356354952e-02}, + {2.641070090839117e-09, 2.876787556300114e-02}, + {2.633294909313421e-09, 2.995820741329835e-02}, + {2.625420585722845e-09, 3.118023074495535e-02}, + {2.617447416531143e-09, 3.243431475972608e-02}, + {2.609375701923643e-09, 3.372082620101990e-02}, + {2.601205745795833e-09, 3.504012932452527e-02}, + {2.592937855741933e-09, 3.639258586895711e-02}, + {2.584572343043400e-09, 3.777855502693250e-02}, + {2.576109522656942e-09, 3.919839341605197e-02}, + {2.567549713203028e-09, 4.065245505002102e-02}, + {2.558893236953688e-09, 4.214109131001403e-02}, + {2.550140419820252e-09, 4.366465091617666e-02}, + {2.541291591341445e-09, 4.522347989919473e-02}, + {2.532347084670572e-09, 4.681792157215026e-02}, + {2.523307236563343e-09, 4.844831650239501e-02}, + {2.514172387364900e-09, 5.011500248369893e-02}, + {2.504942880997064e-09, 5.181831450849345e-02}, + {2.495619064945627e-09, 5.355858474024022e-02}, + {2.486201290246928e-09, 5.533614248606705e-02}, + {2.476689911475047e-09, 5.715131416942842e-02}, + {2.467085286727668e-09, 5.900442330315692e-02}, + {2.457387777613798e-09, 6.089579046229943e-02}, + {2.447597749239101e-09, 6.282573325755320e-02}, + {2.437715570192557e-09, 6.479456630859221e-02}, + {2.427741612532542e-09, 6.680260121764925e-02}, + {2.417676251773166e-09, 6.885014654319160e-02}, + {2.407519866869294e-09, 7.093750777401114e-02}, + {2.397272840203310e-09, 7.306498730310884e-02}, + {2.386935557569868e-09, 7.523288440214027e-02}, + {2.376508408161815e-09, 7.744149519577415e-02}, + {2.365991784555363e-09, 7.969111263635709e-02}, + {2.355386082695641e-09, 8.198202647865405e-02}, + {2.344691701881232e-09, 8.431452325495814e-02}, + {2.333909044749407e-09, 8.668888625021409e-02}, + {2.323038517261246e-09, 8.910539547731611e-02}, + {2.312080528685971e-09, 9.156432765274414e-02}, + {2.301035491585642e-09, 9.406595617227698e-02}, + {2.289903821799651e-09, 9.661055108691619e-02}, + {2.278685938428940e-09, 9.919837907903295e-02}, + {2.267382263820762e-09, 1.018297034385580e-01}, + {2.255993223551837e-09, 1.045047840397028e-01}, + {2.244519246413220e-09, 1.072238773174577e-01}, + {2.232960764393620e-09, 1.099872362446146e-01}, + {2.221318212663309e-09, 1.127951103088245e-01}, + {2.209592029557811e-09, 1.156477454898748e-01}, + {2.197782656561395e-09, 1.185453842371912e-01}, + {2.185890538290176e-09, 1.214882654476019e-01}, + {2.173916122475606e-09, 1.244766244431883e-01}, + {2.161859859947797e-09, 1.275106929493488e-01}, + {2.149722204618256e-09, 1.305906990731841e-01}, + {2.137503613462743e-09, 1.337168672820376e-01}, + {2.125204546504321e-09, 1.368894183821595e-01}, + {2.112825466795944e-09, 1.401085694976751e-01}, + {2.100366840402933e-09, 1.433745340497602e-01}, + {2.087829136385612e-09, 1.466875217359607e-01}, + {2.075212826781308e-09, 1.500477385098620e-01}, + {2.062518386587093e-09, 1.534553865607503e-01}, + {2.049746293741359e-09, 1.569106642937665e-01}, + {2.036897029106193e-09, 1.604137663100403e-01}, + {2.023971076449323e-09, 1.639648833871233e-01}, + {2.010968922425217e-09, 1.675642024598467e-01}, + {1.997891056557933e-09, 1.712119066008896e-01}, + {1.984737971221581e-09, 1.749081750021970e-01}, + {1.971510161622434e-09, 1.786531829561379e-01}, + {1.958208125780130e-09, 1.824471018371070e-01}, + {1.944832364508511e-09, 1.862900990834311e-01}, + {1.931383381397782e-09, 1.901823381790926e-01}, + {1.917861682794392e-09, 1.941239786363039e-01}, + {1.904267777782611e-09, 1.981151759777950e-01}, + {1.890602178165317e-09, 2.021560817195309e-01}, + {1.876865398444616e-09, 2.062468433536743e-01}, + {1.863057955802572e-09, 2.103876043317229e-01}, + {1.849180370081465e-09, 2.145785040479915e-01}, + {1.835233163764673e-09, 2.188196778231083e-01}, + {1.821216861956509e-09, 2.231112568880342e-01}, + {1.807131992362945e-09, 2.274533683680190e-01}, + {1.792979085271234e-09, 2.318461352671018e-01}, + {1.778758673530482e-09, 2.362896764525300e-01}, + {1.764471292530943e-09, 2.407841066397789e-01}, + {1.750117480184598e-09, 2.453295363773890e-01}, + {1.735697776904342e-09, 2.499260720324433e-01}, + {1.721212725583874e-09, 2.545738157760434e-01}, + {1.706662871577097e-09, 2.592728655691494e-01}, + {1.692048762677849e-09, 2.640233151485341e-01}, + {1.677370949099090e-09, 2.688252540131204e-01}, + {1.662629983452104e-09, 2.736787674105404e-01}, + {1.647826420726167e-09, 2.785839363237506e-01}, + {1.632960818266680e-09, 2.835408374583758e-01}, + {1.618033735755429e-09, 2.885495432295704e-01}, + {1.603045735188609e-09, 2.936101217498361e-01}, + {1.587997380855918e-09, 2.987226368167127e-01}, + {1.572889239319430e-09, 3.038871479007593e-01}, + {1.557721879392051e-09, 3.091037101339017e-01}, + {1.542495872116447e-09, 3.143723742978435e-01}, + {1.527211790743024e-09, 3.196931868130269e-01}, + {1.511870210708909e-09, 3.250661897274744e-01}, + {1.496471709615926e-09, 3.304914207062036e-01}, + {1.481016867208896e-09, 3.359689130207621e-01}, + {1.465506265353924e-09, 3.414986955389885e-01}, + {1.449940488016384e-09, 3.470807927151147e-01}, + {1.434320121238994e-09, 3.527152245800635e-01}, + {1.418645753119802e-09, 3.584020067320109e-01}, + {1.402917973789838e-09, 3.641411503272979e-01}, + {1.387137375391042e-09, 3.699326620714776e-01}, + {1.371304552054134e-09, 3.757765442106153e-01}, + {1.355420099875958e-09, 3.816727945230153e-01}, + {1.339484616897137e-09, 3.876214063110671e-01}, + {1.323498703079580e-09, 3.936223683933865e-01}, + {1.307462960283922e-09, 3.996756650972121e-01}, + {1.291377992246768e-09, 4.057812762511174e-01}, + {1.275244404558188e-09, 4.119391771778626e-01}, + {1.259062804638585e-09, 4.181493386877248e-01}, + {1.242833801715929e-09, 4.244117270719281e-01}, + {1.226558006803155e-09, 4.307263040962509e-01}, + {1.210236032674760e-09, 4.370930269951803e-01}, + {1.193868493843725e-09, 4.435118484661861e-01}, + {1.177456006538695e-09, 4.499827166641340e-01}, + {1.160999188680582e-09, 4.565055751961679e-01}, + {1.144498659859216e-09, 4.630803631168164e-01}, + {1.127955041310214e-09, 4.697070149232604e-01}, + {1.111368955891417e-09, 4.763854605510119e-01}, + {1.094741028059551e-09, 4.831156253697562e-01}, + {1.078071883846871e-09, 4.898974301794375e-01}, + {1.061362150836978e-09, 4.967307912069362e-01}, + {1.044612458142151e-09, 5.036156201023686e-01}, + {1.027823436378632e-09, 5.105518239364775e-01}, + {1.010995717643647e-09, 5.175393051975563e-01}, + {9.941299354913699e-10, 5.245779617890562e-01}, + {9.772267249089968e-10, 5.316676870274011e-01}, + {9.602867222926046e-10, 5.388083696401416e-01}, + {9.433105654240147e-10, 5.459998937639375e-01}, + {9.262988934458084e-10, 5.532421389435711e-01}, + {9.092523468378193e-10, 5.605349801305876e-01}, + {8.921715673928355e-10, 5.678782876825250e-01}, + {8.750571981926701e-10, 5.752719273622372e-01}, + {8.579098835836508e-10, 5.827157603377209e-01}, + {8.407302691522673e-10, 5.902096431821322e-01}, + {8.235190017016133e-10, 5.977534278737073e-01}, + {8.062767292259225e-10, 6.053469617967722e-01}, + {7.890041008871165e-10, 6.129900877421282e-01}, + {7.717017669898175e-10, 6.206826439083659e-01}, + {7.543703789572603e-10, 6.284244639030392e-01}, + {7.370105893063053e-10, 6.362153767444958e-01}, + {7.196230516231919e-10, 6.440552068636356e-01}, + {7.022084205389746e-10, 6.519437741060674e-01}, + {6.847673517046416e-10, 6.598808937346672e-01}, + {6.673005017664976e-10, 6.678663764322770e-01}, + {6.498085283416530e-10, 6.759000283046127e-01}, + {6.322920899929834e-10, 6.839816508836737e-01}, + {6.147518462045659e-10, 6.921110411311926e-01}, + {5.971884573565851e-10, 7.002879914425926e-01}, + {5.796025847007168e-10, 7.085122896509806e-01}, + {5.619948903351406e-10, 7.167837190315758e-01}, + {5.443660371796048e-10, 7.251020583063744e-01}, + {5.267166889504394e-10, 7.334670816491009e-01}, + {5.090475101356742e-10, 7.418785586903696e-01}, + {4.913591659698399e-10, 7.503362545232619e-01}, + {4.736523224091392e-10, 7.588399297089872e-01}, + {4.559276461062478e-10, 7.673893402829834e-01}, + {4.381858043851147e-10, 7.759842377612828e-01}, + {4.204274652161870e-10, 7.846243691469355e-01}, + {4.026532971908398e-10, 7.933094769370790e-01}, + {3.848639694963359e-10, 8.020392991300200e-01}, + {3.670601518910503e-10, 8.108135692324444e-01}, + {3.492425146784233e-10, 8.196320162675177e-01}, + {3.314117286825031e-10, 8.284943647824689e-01}, + {3.135684652223755e-10, 8.374003348569865e-01}, + {2.957133960867535e-10, 8.463496421118015e-01}, + {2.778471935089361e-10, 8.553419977173513e-01}, + {2.599705301412391e-10, 8.643771084029740e-01}, + {2.420840790301135e-10, 8.734546764660205e-01}, + {2.241885135902046e-10, 8.825743997817682e-01}, + {2.062845075795238e-10, 8.917359718130367e-01}, + {1.883727350736140e-10, 9.009390816205823e-01}, + {1.704538704408269e-10, 9.101834138731877e-01}, + {1.525285883160648e-10, 9.194686488588080e-01}, + {1.345975635762696e-10, 9.287944624950824e-01}, + {1.166614713141648e-10, 9.381605263410157e-01}, + {9.872098681369190e-11, 9.475665076080466e-01}, + {8.077678552380464e-11, 9.570120691722380e-01}, + {6.282954303364090e-11, 9.664968695860140e-01}, + {4.487993504668797e-11, 9.760205630906909e-01}, + {2.692863735553042e-11, 9.855827996289697e-01}, + {8.976325816439114e-12, 9.951832248577780e-01}, + {-8.976323676304494e-12, 1.004821480161519e+00}, + {-2.692863521550168e-11, 1.014497202665280e+00}, + {-4.487993290681805e-11, 1.024210025248670e+00}, + {-6.282954089398273e-11, 1.033959576559617e+00}, + {-8.077678338451706e-11, 1.043745481028715e+00}, + {-9.872098467477489e-11, 1.053567358883467e+00}, + {-1.166614691757772e-10, 1.063424826163223e+00}, + {-1.345975614383584e-10, 1.073317494734013e+00}, + {-1.525285861788948e-10, 1.083244972303963e+00}, + {-1.704538683042922e-10, 1.093206862438572e+00}, + {-1.883727329379793e-10, 1.103202764576806e+00}, + {-2.062845054446831e-10, 1.113232274046796e+00}, + {-2.241885114563697e-10, 1.123294982082432e+00}, + {-2.420840768973375e-10, 1.133390475839767e+00}, + {-2.599705280096278e-10, 1.143518338413855e+00}, + {-2.778471913784365e-10, 1.153678148855860e+00}, + {-2.957133939575774e-10, 1.163869482190458e+00}, + {-3.135684630945758e-10, 1.174091909433296e+00}, + {-3.314117265561857e-10, 1.184344997608959e+00}, + {-3.492425125535882e-10, 1.194628309769018e+00}, + {-3.670601497678034e-10, 1.204941405010466e+00}, + {-3.848639673748360e-10, 1.215283838494269e+00}, + {-4.026532950710339e-10, 1.225655161464298e+00}, + {-4.204274630982869e-10, 1.236054921266445e+00}, + {-4.381858022691734e-10, 1.246482661367958e+00}, + {-4.559276439922654e-10, 1.256937921377146e+00}, + {-4.736523202972214e-10, 1.267420237063216e+00}, + {-4.913591638600925e-10, 1.277929140376502e+00}, + {-5.090475080282032e-10, 1.288464159468706e+00}, + {-5.267166868452449e-10, 1.299024818713528e+00}, + {-5.443660350768455e-10, 1.309610638727845e+00}, + {-5.619948882348695e-10, 1.320221136392390e+00}, + {-5.796025826029868e-10, 1.330855824873457e+00}, + {-5.971884552615020e-10, 1.341514213644420e+00}, + {-6.147518441122357e-10, 1.352195808507556e+00}, + {-6.322920879034590e-10, 1.362900111616144e+00}, + {-6.498085262549874e-10, 1.373626621496939e+00}, + {-6.673004996827436e-10, 1.384374833072571e+00}, + {-6.847673496239581e-10, 1.395144237684605e+00}, + {-7.022084184613616e-10, 1.405934323116231e+00}, + {-7.196230495488082e-10, 1.416744573616104e+00}, + {-7.370105872352039e-10, 1.427574469921397e+00}, + {-7.543703768894941e-10, 1.438423489281758e+00}, + {-7.717017649255453e-10, 1.449291105483472e+00}, + {-7.890040988262324e-10, 1.460176788873383e+00}, + {-8.062767271686383e-10, 1.471080006383765e+00}, + {-8.235189996479819e-10, 1.482000221556656e+00}, + {-8.407302671024475e-10, 1.492936894569018e+00}, + {-8.579098815375368e-10, 1.503889482257845e+00}, + {-8.750571961505266e-10, 1.514857438145604e+00}, + {-8.921715653546624e-10, 1.525840212465756e+00}, + {-9.092523448036167e-10, 1.536837252188703e+00}, + {-9.262988914157881e-10, 1.547848001047890e+00}, + {-9.433105633981766e-10, 1.558871899565883e+00}, + {-9.602867202711075e-10, 1.569908385081254e+00}, + {-9.772267228916820e-10, 1.580956891774897e+00}, + {-9.941299334786078e-10, 1.592016850697478e+00}, + {-1.010995715635332e-09, 1.603087689796053e+00}, + {-1.027823434374870e-09, 1.614168833942028e+00}, + {-1.044612456143047e-09, 1.625259704958335e+00}, + {-1.061362148842745e-09, 1.636359721647526e+00}, + {-1.078071881857297e-09, 1.647468299819543e+00}, + {-1.094741026074900e-09, 1.658584852320419e+00}, + {-1.111368953911690e-09, 1.669708789060341e+00}, + {-1.127955039335462e-09, 1.680839517042381e+00}, + {-1.144498657889600e-09, 1.691976440391624e+00}, + {-1.160999186716154e-09, 1.703118960383971e+00}, + {-1.177456004579561e-09, 1.714266475475616e+00}, + {-1.193868491889832e-09, 1.725418381332405e+00}, + {-1.210236030726319e-09, 1.736574070859850e+00}, + {-1.226558004860220e-09, 1.747732934232508e+00}, + {-1.242833799778447e-09, 1.758894358924547e+00}, + {-1.259062802706714e-09, 1.770057729740021e+00}, + {-1.275244402631982e-09, 1.781222428842935e+00}, + {-1.291377990326492e-09, 1.792387835788660e+00}, + {-1.307462958369363e-09, 1.803553327553897e+00}, + {-1.323498701170897e-09, 1.814718278568759e+00}, + {-1.339484614994490e-09, 1.825882060747428e+00}, + {-1.355420097979292e-09, 1.837044043519582e+00}, + {-1.371304550163662e-09, 1.848203593862598e+00}, + {-1.387137373506711e-09, 1.859360076332671e+00}, + {-1.402917971911754e-09, 1.870512853097495e+00}, + {-1.418645751248018e-09, 1.881661283967967e+00}, + {-1.434320119373722e-09, 1.892804726431080e+00}, + {-1.449940486157623e-09, 1.903942535681972e+00}, + {-1.465506263501516e-09, 1.915074064656886e+00}, + {-1.481016865363264e-09, 1.926198664066737e+00}, + {-1.496471707776859e-09, 1.937315682428795e+00}, + {-1.511870208876724e-09, 1.948424466101625e+00}, + {-1.527211788917509e-09, 1.959524359317042e+00}, + {-1.542495870297867e-09, 1.970614704215133e+00}, + {-1.557721877580406e-09, 1.981694840876775e+00}, + {-1.572889237514880e-09, 1.992764107358707e+00}, + {-1.587997379058514e-09, 2.003821839726753e+00}, + {-1.603045733398246e-09, 2.014867372090665e+00}, + {-1.618033733972424e-09, 2.025900036638798e+00}, + {-1.632960816490822e-09, 2.036919163671778e+00}, + {-1.647826418957721e-09, 2.047924081638631e+00}, + {-1.662629981691070e-09, 2.058914117170269e+00}, + {-1.677370947345626e-09, 2.069888595116115e+00}, + {-1.692048760931849e-09, 2.080846838577820e+00}, + {-1.706662869838827e-09, 2.091788168946183e+00}, + {-1.721212723853279e-09, 2.102711905935372e+00}, + {-1.735697775181424e-09, 2.113617367619504e+00}, + {-1.750117478469621e-09, 2.124503870468520e+00}, + {-1.764471290823748e-09, 2.135370729383332e+00}, + {-1.778758671831281e-09, 2.146217257733207e+00}, + {-1.792979083579974e-09, 2.157042767390815e+00}, + {-1.807131990679890e-09, 2.167846568770014e+00}, + {-1.821216860281448e-09, 2.178627970860822e+00}, + {-1.835233162097977e-09, 2.189386281268046e+00}, + {-1.849180368423027e-09, 2.200120806246095e+00}, + {-1.863057954152340e-09, 2.210830850737588e+00}, + {-1.876865396802907e-09, 2.221515718409926e+00}, + {-1.890602176531920e-09, 2.232174711691990e+00}, + {-1.904267776157843e-09, 2.242807131812679e+00}, + {-1.917861681178094e-09, 2.253412278837029e+00}, + {-1.931383379790273e-09, 2.263989451705295e+00}, + {-1.944832362909578e-09, 2.274537948269257e+00}, + {-1.958208124189984e-09, 2.285057065331676e+00}, + {-1.971510160041235e-09, 2.295546098682665e+00}, + {-1.984737969649064e-09, 2.306004343138794e+00}, + {-1.997891054994522e-09, 2.316431092581699e+00}, + {-2.010968920870647e-09, 2.326825639994779e+00}, + {-2.023971074903858e-09, 2.337187277503834e+00}, + {-2.036897027569834e-09, 2.347515296413520e+00}, + {-2.049746292214264e-09, 2.357808987247877e+00}, + {-2.062518385069210e-09, 2.368067639787542e+00}, + {-2.075212825272584e-09, 2.378290543109652e+00}, + {-2.087829134886364e-09, 2.388476985626922e+00}, + {-2.100366838912949e-09, 2.398626255125417e+00}, + {-2.112825465315542e-09, 2.408737638805759e+00}, + {-2.125204545033289e-09, 2.418810423320288e+00}, + {-2.137503612001452e-09, 2.428843894814472e+00}, + {-2.149722203166389e-09, 2.438837338964302e+00}, + {-2.161859858505829e-09, 2.448790041018174e+00}, + {-2.173916121043380e-09, 2.458701285834241e+00}, + {-2.185890536867478e-09, 2.468570357921585e+00}, + {-2.197782655148702e-09, 2.478396541480230e+00}, + {-2.209592028154913e-09, 2.488179120439544e+00}, + {-2.221318211270522e-09, 2.497917378500214e+00}, + {-2.232960763010574e-09, 2.507610599172123e+00}, + {-2.244519245040444e-09, 2.517258065817044e+00}, + {-2.255993222189014e-09, 2.526859061686102e+00}, + {-2.267382262468209e-09, 2.536412869962689e+00}, + {-2.278685937086658e-09, 2.545918773800664e+00}, + {-2.289903820467374e-09, 2.555376056366064e+00}, + {-2.301035490263848e-09, 2.564784000877677e+00}, + {-2.312080527374447e-09, 2.574141890646339e+00}, + {-2.323038515960257e-09, 2.583449009117307e+00}, + {-2.333909043458635e-09, 2.592704639909166e+00}, + {-2.344691700601153e-09, 2.601908066856634e+00}, + {-2.355386081425938e-09, 2.611058574048749e+00}, + {-2.365991783296513e-09, 2.620155445872768e+00}, + {-2.376508406913500e-09, 2.629197967052127e+00}, + {-2.386935556332088e-09, 2.638185422689490e+00}, + {-2.397272838976436e-09, 2.647117098307332e+00}, + {-2.407519865653114e-09, 2.655992279887846e+00}, + {-2.417676250567891e-09, 2.664810253915885e+00}, + {-2.427741611338014e-09, 2.673570307418169e+00}, + {-2.437715569009093e-09, 2.682271728006635e+00}, + {-2.447597748066437e-09, 2.690913803917100e+00}, + {-2.457387776452357e-09, 2.699495824053297e+00}, + {-2.467085285577292e-09, 2.708017078025636e+00}, + {-2.476689910335470e-09, 2.716476856194105e+00}, + {-2.486201289118733e-09, 2.724874449709689e+00}, + {-2.495619063828443e-09, 2.733209150554255e+00}, + {-2.504942879891263e-09, 2.741480251583985e+00}, + {-2.514172386270163e-09, 2.749687046568741e+00}, + {-2.523307235480146e-09, 2.757828830235740e+00}, + {-2.532347083598520e-09, 2.765904898308531e+00}, + {-2.541291590280960e-09, 2.773914547551261e+00}, + {-2.550140418771202e-09, 2.781857075807392e+00}, + {-2.558893235915887e-09, 2.789731782043156e+00}, + {-2.567549712176927e-09, 2.797537966388929e+00}, + {-2.576109521642196e-09, 2.805274930179221e+00}, + {-2.584572342040407e-09, 2.812941975996573e+00}, + {-2.592937854750428e-09, 2.820538407710556e+00}, + {-2.601205744816134e-09, 2.828063530521908e+00}, + {-2.609375700955458e-09, 2.835516651001539e+00}, + {-2.617447415574869e-09, 2.842897077134583e+00}, + {-2.625420584778350e-09, 2.850204118359573e+00}, + {-2.633294908380520e-09, 2.857437085611509e+00}, + {-2.641070089918234e-09, 2.864595291363663e+00}, + {-2.648745836659391e-09, 2.871678049666939e+00}, + {-2.656321859617343e-09, 2.878684676194483e+00}, + {-2.663797873558322e-09, 2.885614488280000e+00}, + {-2.671173597015318e-09, 2.892466804962122e+00}, + {-2.678448752295859e-09, 2.899240947023252e+00}, + {-2.685623065495139e-09, 2.905936237033475e+00}, + {-2.692696266503800e-09, 2.912551999389617e+00}, + {-2.699668089019767e-09, 2.919087560358171e+00}, + {-2.706538270558513e-09, 2.925542248116882e+00}, + {-2.713306552460767e-09, 2.931915392794031e+00}, + {-2.719972679905295e-09, 2.938206326512581e+00}, + {-2.726536401915442e-09, 2.944414383428562e+00}, + {-2.732997471371516e-09, 2.950538899775061e+00}, + {-2.739355645017194e-09, 2.956579213900666e+00}, + {-2.745610683471516e-09, 2.962534666313284e+00}, + {-2.751762351235315e-09, 2.968404599718795e+00}, + {-2.757810416701751e-09, 2.974188359063684e+00}, + {-2.763754652165128e-09, 2.979885291576143e+00}, + {-2.769594833827588e-09, 2.985494746805227e+00}, + {-2.775330741810390e-09, 2.991016076664491e+00}, + {-2.780962160159068e-09, 2.996448635469842e+00}, + {-2.786488876854607e-09, 3.001791779983262e+00}, + {-2.791910683818570e-09, 3.007044869450794e+00}, + {-2.797227376923695e-09, 3.012207265645876e+00}, + {-2.802438755998943e-09, 3.017278332907412e+00}, + {-2.807544624838820e-09, 3.022257438182037e+00}, + {-2.812544791210840e-09, 3.027143951064684e+00}, + {-2.817439066860792e-09, 3.031937243837070e+00}, + {-2.822227267522746e-09, 3.036636691510884e+00}, + {-2.826909212922864e-09, 3.041241671864994e+00}, + {-2.831484726789317e-09, 3.045751565488710e+00}, + {-2.835953636855826e-09, 3.050165755818853e+00}, + {-2.840315774871260e-09, 3.054483629182857e+00}, + {-2.844570976602957e-09, 3.058704574835744e+00}, + {-2.848719081844986e-09, 3.062827985002047e+00}, + {-2.852759934424164e-09, 3.066853254915581e+00}, + {-2.856693382203833e-09, 3.070779782857041e+00}, + {-2.860519277092708e-09, 3.074606970196721e+00}, + {-2.864237475047239e-09, 3.078334221430809e+00}, + {-2.867847836080156e-09, 3.081960944223928e+00}, + {-2.871350224262603e-09, 3.085486549445314e+00}, + {-2.874744507732462e-09, 3.088910451211251e+00}, + {-2.878030558696270e-09, 3.092232066921130e+00}, + {-2.881208253436038e-09, 3.095450817298478e+00}, + {-2.884277472313999e-09, 3.098566126429974e+00}, + {-2.887238099774968e-09, 3.101577421802070e+00}, + {-2.890090024353816e-09, 3.104484134342861e+00}, + {-2.892833138676371e-09, 3.107285698457308e+00}, + {-2.895467339466766e-09, 3.109981552069083e+00}, + {-2.897992527547963e-09, 3.112571136655481e+00}, + {-2.900408607848946e-09, 3.115053897289195e+00}, + {-2.902715489404992e-09, 3.117429282673042e+00}, + {-2.904913085363323e-09, 3.119696745180238e+00}, + {-2.907001312986328e-09, 3.121855740892224e+00}, + {-2.908980093652563e-09, 3.123905729634218e+00}, + {-2.910849352862924e-09, 3.125846175016163e+00}, + {-2.912609020239985e-09, 3.127676544466606e+00}, + {-2.914259029534118e-09, 3.129396309273659e+00}, + {-2.915799318622574e-09, 3.131004944618667e+00}, + {-2.917229829515169e-09, 3.132501929616775e+00}, + {-2.918550508353347e-09, 3.133886747350606e+00}, + {-2.919761305414294e-09, 3.135158884909254e+00}, + {-2.920862175112829e-09, 3.136317833424958e+00}, + {-2.921853076000972e-09, 3.137363088107359e+00}, + {-2.922733970772719e-09, 3.138294148283254e+00}, + {-2.923504826262027e-09, 3.139110517429204e+00}, + {-2.924165613447473e-09, 3.139811703211207e+00}, + {-2.924716307449950e-09, 3.140397217517018e+00}, + {-2.925156887536978e-09, 3.140866576495489e+00}, + {-2.925487337120335e-09, 3.141219300588825e+00}, + {-2.925707643758784e-09, 3.141454914570261e+00}, + {-2.925817799158535e-09, 3.141572947579352e+00}, + {-2.925817799171455e-09, 3.141572933154836e+00}, + {-2.925707643798390e-09, 3.141454409272987e+00}, + {-2.925487337185779e-09, 3.141216918378770e+00}, + {-2.925156887628892e-09, 3.140860007424112e+00}, + {-2.924716307568119e-09, 3.140383227898687e+00}, + {-2.924165613591896e-09, 3.139786135867868e+00}, + {-2.923504826432903e-09, 3.139068292003385e+00}, + {-2.922733970969412e-09, 3.138229261619561e+00}, + {-2.921853076224321e-09, 3.137268614707029e+00}, + {-2.920862175361976e-09, 3.136185925964038e+00}, + {-2.919761305690083e-09, 3.134980774833275e+00}, + {-2.918550508654911e-09, 3.133652745531368e+00}, + {-2.917229829843137e-09, 3.132201427085629e+00}, + {-2.915799318976726e-09, 3.130626413363146e+00}, + {-2.914259029914435e-09, 3.128927303107136e+00}, + {-2.912609020646661e-09, 3.127103699965947e+00}, + {-2.910849353295315e-09, 3.125155212527586e+00}, + {-2.908980094111509e-09, 3.123081454351802e+00}, + {-2.907001313470937e-09, 3.120882043999591e+00}, + {-2.904913085874448e-09, 3.118556605068443e+00}, + {-2.902715489941767e-09, 3.116104766219928e+00}, + {-2.900408608411958e-09, 3.113526161214776e+00}, + {-2.897992528137022e-09, 3.110820428940251e+00}, + {-2.895467340081818e-09, 3.107987213444579e+00}, + {-2.892833139317615e-09, 3.105026163964191e+00}, + {-2.890090025020589e-09, 3.101936934956479e+00}, + {-2.887238100468092e-09, 3.098719186130021e+00}, + {-2.884277473032614e-09, 3.095372582472161e+00}, + {-2.881208254180937e-09, 3.091896794282404e+00}, + {-2.878030559466594e-09, 3.088291497198199e+00}, + {-2.874744508528832e-09, 3.084556372228054e+00}, + {-2.871350225084755e-09, 3.080691105776848e+00}, + {-2.867847836928063e-09, 3.076695389678615e+00}, + {-2.864237475921086e-09, 3.072568921221621e+00}, + {-2.860519277991847e-09, 3.068311403179147e+00}, + {-2.856693383129018e-09, 3.063922543837792e+00}, + {-2.852759935374575e-09, 3.059402057023109e+00}, + {-2.848719082821403e-09, 3.054749662130841e+00}, + {-2.844570977604520e-09, 3.049965084150782e+00}, + {-2.840315775898525e-09, 3.045048053697736e+00}, + {-2.835953637908582e-09, 3.039998307034967e+00}, + {-2.831484727867511e-09, 3.034815586104635e+00}, + {-2.826909214026628e-09, 3.029499638550941e+00}, + {-2.822227268651470e-09, 3.024050217748861e+00}, + {-2.817439068015245e-09, 3.018467082830179e+00}, + {-2.812544792390175e-09, 3.012749998707001e+00}, + {-2.807544626043751e-09, 3.006898736100911e+00}, + {-2.802438757228650e-09, 3.000913071564665e+00}, + {-2.797227378178760e-09, 2.994792787510961e+00}, + {-2.791910685098702e-09, 2.988537672233504e+00}, + {-2.786488878159805e-09, 2.982147519935565e+00}, + {-2.780962161489413e-09, 2.975622130750641e+00}, + {-2.775330743165298e-09, 2.968961310769028e+00}, + {-2.769594835207775e-09, 2.962164872061613e+00}, + {-2.763754653569747e-09, 2.955232632701135e+00}, + {-2.757810418131543e-09, 2.948164416789036e+00}, + {-2.751762352689432e-09, 2.940960054474719e+00}, + {-2.745610684950541e-09, 2.933619381982341e+00}, + {-2.739355646520809e-09, 2.926142241629213e+00}, + {-2.732997472899722e-09, 2.918528481852205e+00}, + {-2.726536403468318e-09, 2.910777957226018e+00}, + {-2.719972681482232e-09, 2.902890528487386e+00}, + {-2.713306554062453e-09, 2.894866062556452e+00}, + {-2.706538272184154e-09, 2.886704432555728e+00}, + {-2.699668090670078e-09, 2.878405517834426e+00}, + {-2.692696268177908e-09, 2.869969203985464e+00}, + {-2.685623067193599e-09, 2.861395382869544e+00}, + {-2.678448754018380e-09, 2.852683952631486e+00}, + {-2.671173598761847e-09, 2.843834817723832e+00}, + {-2.663797875328991e-09, 2.834847888922988e+00}, + {-2.656321861411517e-09, 2.825723083350459e+00}, + {-2.648745838477759e-09, 2.816460324492298e+00}, + {-2.641070091759922e-09, 2.807059542215146e+00}, + {-2.633294910246296e-09, 2.797520672788269e+00}, + {-2.625420586667340e-09, 2.787843658897949e+00}, + {-2.617447417487602e-09, 2.778028449668942e+00}, + {-2.609375702891616e-09, 2.768075000678399e+00}, + {-2.601205746775692e-09, 2.757983273976943e+00}, + {-2.592937856733464e-09, 2.747753238101915e+00}, + {-2.584572344046340e-09, 2.737384868096553e+00}, + {-2.576109523671634e-09, 2.726878145526201e+00}, + {-2.567549714229129e-09, 2.716233058492422e+00}, + {-2.558893237991435e-09, 2.705449601651722e+00}, + {-2.550140420869302e-09, 2.694527776227857e+00}, + {-2.541291592402089e-09, 2.683467590030445e+00}, + {-2.532347085742440e-09, 2.672269057466213e+00}, + {-2.523307237646751e-09, 2.660932199557362e+00}, + {-2.514172388459584e-09, 2.649457043952206e+00}, + {-2.504942882102813e-09, 2.637843624941622e+00}, + {-2.495619066062810e-09, 2.626091983472908e+00}, + {-2.486201291375123e-09, 2.614202167160335e+00}, + {-2.476689912614465e-09, 2.602174230302269e+00}, + {-2.467085287878098e-09, 2.590008233889805e+00}, + {-2.457387778775451e-09, 2.577704245623143e+00}, + {-2.447597750411553e-09, 2.565262339920002e+00}, + {-2.437715571376127e-09, 2.552682597931055e+00}, + {-2.427741613727123e-09, 2.539965107548168e+00}, + {-2.417676252978335e-09, 2.527109963417675e+00}, + {-2.407519868085581e-09, 2.514117266951687e+00}, + {-2.397272841430131e-09, 2.500987126335739e+00}, + {-2.386935558807595e-09, 2.487719656543254e+00}, + {-2.376508409410024e-09, 2.474314979341178e+00}, + {-2.365991785814531e-09, 2.460773223303822e+00}, + {-2.355386083965131e-09, 2.447094523817833e+00}, + {-2.344691703161363e-09, 2.433279023095734e+00}, + {-2.333909046040126e-09, 2.419326870180582e+00}, + {-2.323038518562289e-09, 2.405238220956597e+00}, + {-2.312080529997549e-09, 2.391013238157397e+00}, + {-2.301035492907384e-09, 2.376652091371587e+00}, + {-2.289903823131822e-09, 2.362154957053137e+00}, + {-2.278685939771276e-09, 2.347522018525197e+00}, + {-2.267382265173420e-09, 2.332753465990296e+00}, + {-2.255993224914501e-09, 2.317849496533128e+00}, + {-2.244519247786155e-09, 2.302810314130351e+00}, + {-2.232960765776561e-09, 2.287636129652823e+00}, + {-2.221318214056095e-09, 2.272327160873552e+00}, + {-2.209592030960763e-09, 2.256883632472565e+00}, + {-2.197782657974034e-09, 2.241305776039511e+00}, + {-2.185890539712767e-09, 2.225593830081461e+00}, + {-2.173916123907886e-09, 2.209748040023618e+00}, + {-2.161859861389976e-09, 2.193768658216360e+00}, + {-2.149722206070124e-09, 2.177655943935795e+00}, + {-2.137503614923981e-09, 2.161410163388424e+00}, + {-2.125204547975352e-09, 2.145031589714984e+00}, + {-2.112825468276292e-09, 2.128520502989477e+00}, + {-2.100366841892917e-09, 2.111877190225612e+00}, + {-2.087829137884807e-09, 2.095101945374541e+00}, + {-2.075212828290086e-09, 2.078195069329960e+00}, + {-2.062518388104923e-09, 2.061156869925600e+00}, + {-2.049746295268559e-09, 2.043987661939897e+00}, + {-2.036897030642658e-09, 2.026687767092888e+00}, + {-2.023971077994576e-09, 2.009257514048162e+00}, + {-2.010968923979840e-09, 1.991697238413571e+00}, + {-1.997891058121344e-09, 1.974007282737320e+00}, + {-1.984737972794098e-09, 1.956187996511354e+00}, + {-1.971510163203686e-09, 1.938239736166060e+00}, + {-1.958208127370276e-09, 1.920162865072273e+00}, + {-1.944832366107339e-09, 1.901957753535934e+00}, + {-1.931383383005451e-09, 1.883624778799427e+00}, + {-1.917861684410531e-09, 1.865164325035177e+00}, + {-1.904267779407432e-09, 1.846576783346324e+00}, + {-1.890602179798714e-09, 1.827862551760622e+00}, + {-1.876865400086483e-09, 1.809022035228338e+00}, + {-1.863057957452539e-09, 1.790055645617624e+00}, + {-1.849180371740008e-09, 1.770963801711725e+00}, + {-1.835233165431475e-09, 1.751746929201178e+00}, + {-1.821216863631569e-09, 1.732405460681919e+00}, + {-1.807131994045840e-09, 1.712939835648088e+00}, + {-1.792979086962494e-09, 1.693350500488565e+00}, + {-1.778758675229683e-09, 1.673637908477153e+00}, + {-1.764471294238191e-09, 1.653802519770021e+00}, + {-1.750117481899733e-09, 1.633844801396848e+00}, + {-1.735697778626995e-09, 1.613765227254186e+00}, + {-1.721212727314574e-09, 1.593564278099856e+00}, + {-1.706662873315474e-09, 1.573242441540939e+00}, + {-1.692048764423848e-09, 1.552800212030258e+00}, + {-1.677370950852395e-09, 1.532238090855187e+00}, + {-1.662629985213192e-09, 1.511556586131055e+00}, + {-1.647826422494560e-09, 1.490756212788764e+00}, + {-1.632960820042537e-09, 1.469837492568651e+00}, + {-1.618033737538645e-09, 1.448800954008929e+00}, + {-1.603045736978760e-09, 1.427647132435469e+00}, + {-1.587997382653428e-09, 1.406376569953373e+00}, + {-1.572889241124034e-09, 1.384989815432507e+00}, + {-1.557721881203696e-09, 1.363487424499449e+00}, + {-1.542495873934815e-09, 1.341869959524515e+00}, + {-1.527211792568486e-09, 1.320137989611176e+00}, + {-1.511870212541253e-09, 1.298292090581491e+00}, + {-1.496471711454994e-09, 1.276332844965754e+00}, + {-1.481016869054634e-09, 1.254260841988828e+00}, + {-1.465506267206068e-09, 1.232076677556547e+00}, + {-1.449940489875303e-09, 1.209780954243628e+00}, + {-1.434320123104372e-09, 1.187374281276747e+00}, + {-1.418645754991533e-09, 1.164857274523495e+00}, + {-1.402917975667710e-09, 1.142230556475749e+00}, + {-1.387137377275425e-09, 1.119494756236361e+00}, + {-1.371304553944712e-09, 1.096650509501278e+00}, + {-1.355420101772623e-09, 1.073698458546610e+00}, + {-1.339484618799891e-09, 1.050639252211352e+00}, + {-1.323498704988051e-09, 1.027473545880543e+00}, + {-1.307462962198534e-09, 1.004202001471034e+00}, + {-1.291377994167204e-09, 9.808252874104182e-01}, + {-1.275244406484394e-09, 9.573440786237052e-01}, + {-1.259062806570190e-09, 9.337590565128454e-01}, + {-1.242833803653464e-09, 9.100709089414796e-01}, + {-1.226558008746195e-09, 8.862803302125812e-01}, + {-1.210236034623253e-09, 8.623880210538113e-01}, + {-1.193868495797618e-09, 8.383946885959868e-01}, + {-1.177456008497777e-09, 8.143010463544786e-01}, + {-1.160999190645010e-09, 7.901078142102129e-01}, + {-1.144498661828833e-09, 7.658157183877095e-01}, + {-1.127955043284965e-09, 7.414254914366063e-01}, + {-1.111368957870986e-09, 7.169378722095157e-01}, + {-1.094741030044308e-09, 6.923536058430697e-01}, + {-1.078071885836393e-09, 6.676734437331688e-01}, + {-1.061362152831423e-09, 6.428981435165511e-01}, + {-1.044612460141255e-09, 6.180284690466404e-01}, + {-1.027823438382183e-09, 5.930651903718045e-01}, + {-1.010995719652015e-09, 5.680090837138436e-01}, + {-9.941299375042378e-10, 5.428609314418970e-01}, + {-9.772267269262058e-10, 5.176215220520872e-01}, + {-9.602867243141016e-10, 4.922916501421032e-01}, + {-9.433105674499058e-10, 4.668721163885412e-01}, + {-9.262988954758817e-10, 4.413637275202624e-01}, + {-9.092523488719689e-10, 4.157672962958654e-01}, + {-8.921715694311144e-10, 3.900836414778084e-01}, + {-8.750572002347607e-10, 3.643135878065193e-01}, + {-8.579098856296589e-10, 3.384579659762392e-01}, + {-8.407302712022458e-10, 3.125176126069478e-01}, + {-8.235190037551917e-10, 2.864933702193017e-01}, + {-8.062767312831008e-10, 2.603860872080448e-01}, + {-7.890041029479477e-10, 2.341966178147619e-01}, + {-7.717017690542486e-10, 2.079258220999725e-01}, + {-7.543703810250266e-10, 1.815745659161734e-01}, + {-7.370105913774597e-10, 1.551437208801425e-01}, + {-7.196230536974697e-10, 1.286341643433767e-01}, + {-7.022084226165876e-10, 1.020467793657360e-01}, + {-6.847673537853251e-10, 7.538245468350446e-02}, + {-6.673005038502516e-10, 4.864208468284503e-02}, + {-6.498085304282128e-10, 2.182656936863137e-02}, + {-6.322920920826137e-10, -5.063185663820913e-03}, + {-6.147518482969490e-10, -3.202626926150343e-02}, + {-5.971884594516681e-10, -5.906176474160862e-02}, + {-5.796025867984469e-10, -8.616874992366363e-02}, + {-5.619948924353588e-10, -1.133462971605448e-01}, + {-5.443660392823640e-10, -1.405934733692621e-01}, + {-5.267166910556339e-10, -1.679093400638023e-01}, + {-5.090475122431451e-10, -1.952929533862739e-01}, + {-4.913591680795342e-10, -2.227433641394564e-01}, + {-4.736523245210571e-10, -2.502596178194491e-01}, + {-4.559276482202303e-10, -2.778407546490776e-01}, + {-4.381858065011618e-10, -3.054858096104932e-01}, + {-4.204274673340870e-10, -3.331938124792702e-01}, + {-4.026532993105397e-10, -3.609637878577768e-01}, + {-3.848639716178888e-10, -3.887947552098022e-01}, + {-3.670601540142443e-10, -4.166857288948674e-01}, + {-3.492425168032583e-10, -4.446357182029681e-01}, + {-3.314117308088734e-10, -4.726437273896633e-01}, + {-3.135684673501752e-10, -5.007087557112619e-01}, + {-2.957133982159296e-10, -5.288297974607742e-01}, + {-2.778471956393828e-10, -5.570058420037128e-01}, + {-2.599705322729564e-10, -5.852358738143247e-01}, + {-2.420840811628366e-10, -6.135188725122560e-01}, + {-2.241885157240923e-10, -6.418538128986450e-01}, + {-2.062845097142585e-10, -6.702396649949099e-01}, + {-1.883727372093546e-10, -6.986753940779493e-01}, + {-1.704538725773087e-10, -7.271599607197149e-01}, + {-1.525285904532877e-10, -7.556923208240308e-01}, + {-1.345975657140748e-10, -7.842714256651911e-01}, + {-1.166614734526054e-10, -8.128962219265712e-01}, + {-9.872098895260891e-11, -8.415656517393372e-01}, + {-8.077678766314517e-11, -8.702786527215916e-01}, + {-6.282954517324612e-11, -8.990341580176152e-01}, + {-4.487993718655790e-11, -9.278310963373758e-01}, + {-2.692863949561210e-11, -9.566683919968972e-01}, + {-8.976327956520795e-12, -9.855449649582175e-01}, + {8.976321536169872e-12, -1.014459730869357e+00}, + {2.692863307547294e-11, -1.043411601105914e+00}, + {4.487993076694813e-11, -1.072399482811314e+00}, + {6.282953875437751e-11, -1.101422278938424e+00}, + {8.077678124517653e-11, -1.130478888291020e+00}, + {9.872098253591082e-11, -1.159568205565684e+00}, + {1.166614670373367e-10, -1.188689121393192e+00}, + {1.345975593005002e-10, -1.217840522381901e+00}, + {1.525285840416718e-10, -1.247021291159495e+00}, + {1.704538661678104e-10, -1.276230306415868e+00}, + {1.883727308022916e-10, -1.305466442946703e+00}, + {2.062845033098954e-10, -1.334728571696106e+00}, + {2.241885093225349e-10, -1.364015559800721e+00}, + {2.420840747645085e-10, -1.393326270633325e+00}, + {2.599705258779635e-10, -1.422659563847049e+00}, + {2.778471892479898e-10, -1.452014295419243e+00}, + {2.957133918284542e-10, -1.481389317696831e+00}, + {3.135684609667761e-10, -1.510783479440191e+00}, + {3.314117244297624e-10, -1.540195625869043e+00}, + {3.492425104288060e-10, -1.569624598707558e+00}, + {3.670601476445565e-10, -1.599069236228850e+00}, + {3.848639652533361e-10, -1.628528373302631e+00}, + {4.026532929512281e-10, -1.658000841439269e+00}, + {4.204274609803869e-10, -1.687485468837799e+00}, + {4.381858001531792e-10, -1.716981080430596e+00}, + {4.559276418782829e-10, -1.746486497931567e+00}, + {4.736523181853565e-10, -1.776000539882225e+00}, + {4.913591617503452e-10, -1.805522021699094e+00}, + {5.090475059206794e-10, -1.835049755721194e+00}, + {5.267166847401562e-10, -1.864582551257262e+00}, + {5.443660329740862e-10, -1.894119214633676e+00}, + {5.619948861345454e-10, -1.923658549242818e+00}, + {5.796025805053097e-10, -1.953199355591180e+00}, + {5.971884531664190e-10, -1.982740431347091e+00}, + {6.147518420199055e-10, -2.012280571390674e+00}, + {6.322920858139346e-10, -2.041818567861395e+00}, + {6.498085241682158e-10, -2.071353210208005e+00}, + {6.673004975990425e-10, -2.100883285238127e+00}, + {6.847673475432746e-10, -2.130407577166309e+00}, + {7.022084163838545e-10, -2.159924867664933e+00}, + {7.196230474743716e-10, -2.189433935913779e+00}, + {7.370105851640495e-10, -2.218933558650552e+00}, + {7.543703748217808e-10, -2.248422510220072e+00}, + {7.717017628611672e-10, -2.277899562625407e+00}, + {7.890040967654542e-10, -2.307363485579104e+00}, + {8.062767251113011e-10, -2.336813046552684e+00}, + {8.235189975944034e-10, -2.366247010829556e+00}, + {8.407302650525749e-10, -2.395664141553858e+00}, + {8.579098794915287e-10, -2.425063199784153e+00}, + {8.750571941082773e-10, -2.454442944543319e+00}, + {8.921715633164894e-10, -2.483802132872044e+00}, + {9.092523427695200e-10, -2.513139519878584e+00}, + {9.262988893857148e-10, -2.542453858792682e+00}, + {9.433105613723914e-10, -2.571743901017465e+00}, + {9.602867182493987e-10, -2.601008396180870e+00}, + {9.772267208744730e-10, -2.630246092190425e+00}, + {9.941299314658458e-10, -2.659455735283526e+00}, + {1.010995713627070e-09, -2.688636070081818e+00}, + {1.027823432371055e-09, -2.717785839644439e+00}, + {1.044612454143997e-09, -2.746903785521352e+00}, + {1.061362146848353e-09, -2.775988647805256e+00}, + {1.078071879867828e-09, -2.805039165187255e+00}, + {1.094741024090249e-09, -2.834054075009077e+00}, + {1.111368951931856e-09, -2.863032113318052e+00}, + {1.127955037360817e-09, -2.891972014920939e+00}, + {1.144498655920037e-09, -2.920872513436805e+00}, + {1.160999184751779e-09, -2.949732341353290e+00}, + {1.177456002620215e-09, -2.978550230079517e+00}, + {1.193868489936097e-09, -3.007324910002949e+00}, + {1.210236028777826e-09, -3.036055110540183e+00}, + {1.226558002917232e-09, -3.064739560196251e+00}, + {1.242833797841123e-09, -3.093376986616735e+00}, + {1.259062800774685e-09, -3.121966116643377e+00}, + {1.275244400705935e-09, -3.150505676371791e+00}, + {1.291377988406056e-09, -3.178994391202159e+00}, + {1.307462956454857e-09, -3.207430985899192e+00}, + {1.323498699262108e-09, -3.235814184645077e+00}, + {1.339484613091842e-09, -3.264142711097884e+00}, + {1.355420096082785e-09, -3.292415288443373e+00}, + {1.371304548273191e-09, -3.320630639454825e+00}, + {1.387137371622433e-09, -3.348787486547389e+00}, + {1.402917970033511e-09, -3.376884551834256e+00}, + {1.418645749376393e-09, -3.404920557184582e+00}, + {1.434320117508396e-09, -3.432894224276359e+00}, + {1.449940484298756e-09, -3.460804274656981e+00}, + {1.465506261649108e-09, -3.488649429796768e+00}, + {1.481016863517580e-09, -3.516428411149154e+00}, + {1.496471705937951e-09, -3.544139940202303e+00}, + {1.511870207044433e-09, -3.571782738540999e+00}, + {1.527211787092206e-09, -3.599355527901174e+00}, + {1.542495868479076e-09, -3.626857030226671e+00}, + {1.557721875768920e-09, -3.654285967729458e+00}, + {1.572889235710329e-09, -3.681641062941412e+00}, + {1.587997377261005e-09, -3.708921038776707e+00}, + {1.603045731607830e-09, -3.736124618586623e+00}, + {1.618033732189314e-09, -3.763250526218862e+00}, + {1.632960814715177e-09, -3.790297486071938e+00}, + {1.647826417189275e-09, -3.817264223155802e+00}, + {1.662629979930247e-09, -3.844149463148589e+00}, + {1.677370945591844e-09, -3.870951932452996e+00}, + {1.692048759186008e-09, -3.897670358257890e+00}, + {1.706662868100504e-09, -3.924303468590212e+00}, + {1.721212722122685e-09, -3.950849992378278e+00}, + {1.735697773458400e-09, -3.977308659506432e+00}, + {1.750117476754591e-09, -4.003678200876669e+00}, + {1.764471289116712e-09, -4.029957348461003e+00}, + {1.778758670132079e-09, -4.056144835364877e+00}, + {1.792979081888926e-09, -4.082239395882965e+00}, + {1.807131988996465e-09, -4.108239765556996e+00}, + {1.821216858606652e-09, -4.134144681236933e+00}, + {1.835233160431175e-09, -4.159952881133585e+00}, + {1.849180366764537e-09, -4.185663104882633e+00}, + {1.863057952502055e-09, -4.211274093599509e+00}, + {1.876865395161145e-09, -4.236784589940537e+00}, + {1.890602174898734e-09, -4.262193338157148e+00}, + {1.904267774533022e-09, -4.287499084158302e+00}, + {1.917861679562008e-09, -4.312700575567174e+00}, + {1.931383378182392e-09, -4.337796561778708e+00}, + {1.944832361310856e-09, -4.362785794021793e+00}, + {1.958208122599839e-09, -4.387667025411434e+00}, + {1.971510158459931e-09, -4.412439011013396e+00}, + {1.984737968076495e-09, -4.437100507898339e+00}, + {1.997891053431005e-09, -4.461650275204912e+00}, + {2.010968919316289e-09, -4.486087074191693e+00}, + {2.023971073358447e-09, -4.510409668301784e+00}, + {2.036897026033634e-09, -4.534616823217992e+00}, + {2.049746290686799e-09, -4.558707306921882e+00}, + {2.062518383551274e-09, -4.582679889754607e+00}, + {2.075212823764071e-09, -4.606533344469879e+00}, + {2.087829133387063e-09, -4.630266446298172e+00}, + {2.100366837422912e-09, -4.653877973001258e+00}, + {2.112825463835087e-09, -4.677366704934605e+00}, + {2.125204543562522e-09, -4.700731425099899e+00}, + {2.137503610540056e-09, -4.723970919208608e+00}, + {2.149722201714786e-09, -4.747083975738060e+00}, + {2.161859857063438e-09, -4.770069385989595e+00}, + {2.173916119610994e-09, -4.792925944149308e+00}, + {2.185890535445098e-09, -4.815652447340950e+00}, + {2.197782653735957e-09, -4.838247695689436e+00}, + {2.209592026751962e-09, -4.860710492376411e+00}, + {2.221318209877576e-09, -4.883039643700314e+00}, + {2.232960761627846e-09, -4.905233959130168e+00}, + {2.244519243667616e-09, -4.927292251368517e+00}, + {2.255993220826402e-09, -4.949213336406265e+00}, + {2.267382261115285e-09, -4.970996033581527e+00}, + {2.278685935744269e-09, -4.992639165639563e+00}, + {2.289903819135414e-09, -5.014141558784778e+00}, + {2.301035488942000e-09, -5.035502042744443e+00}, + {2.312080526062763e-09, -5.056719450823151e+00}, + {2.323038514659161e-09, -5.077792619963239e+00}, + {2.333909042168180e-09, -5.098720390796817e+00}, + {2.344691699320969e-09, -5.119501607709159e+00}, + {2.355386080156553e-09, -5.140135118892792e+00}, + {2.365991782037187e-09, -5.160619776404897e+00}, + {2.376508405665132e-09, -5.180954436227641e+00}, + {2.386935555094626e-09, -5.201137958319343e+00}, + {2.397272837749508e-09, -5.221169206676762e+00}, + {2.407519864436774e-09, -5.241047049389645e+00}, + {2.417676249362563e-09, -5.260770358700167e+00}, + {2.427741610143750e-09, -5.280338011053974e+00}, + {2.437715567825576e-09, -5.299748887163106e+00}, + {2.447597746894037e-09, -5.319001872058887e+00}, + {2.457387775290440e-09, -5.338095855149190e+00}, + {2.467085284426756e-09, -5.357029730277389e+00}, + {2.476689909196263e-09, -5.375802395772283e+00}, + {2.486201287990485e-09, -5.394412754510426e+00}, + {2.495619062711154e-09, -5.412859713968929e+00}, + {2.504942878785408e-09, -5.431142186284682e+00}, + {2.514172385175743e-09, -5.449259088303476e+00}, + {2.523307234396791e-09, -5.467209341642627e+00}, + {2.532347082526785e-09, -5.484991872743321e+00}, + {2.541291589219998e-09, -5.502605612925014e+00}, + {2.550140417722072e-09, -5.520049498445633e+00}, + {2.558893234878378e-09, -5.537322470548212e+00}, + {2.567549711150773e-09, -5.554423475524196e+00}, + {2.576109520627371e-09, -5.571351464763084e+00}, + {2.584572341037361e-09, -5.588105394812198e+00}, + {2.592937853759161e-09, -5.604684227423386e+00}, + {2.601205743836355e-09, -5.621086929615246e+00}, + {2.609375699987564e-09, -5.637312473723475e+00}, + {2.617447414618146e-09, -5.653359837454964e+00}, + {2.625420583833750e-09, -5.669228003945694e+00}, + {2.633294907447937e-09, -5.684915961806963e+00}, + {2.641070088997271e-09, -5.700422705186584e+00}, + {2.648745835750128e-09, -5.715747233817712e+00}, + {2.656321858720176e-09, -5.730888553077074e+00}, + {2.663797872673252e-09, -5.745845674030161e+00}, + {2.671173596142054e-09, -5.760617613492118e+00}, + {2.678448751434797e-09, -5.775203394076705e+00}, + {2.685623064645538e-09, -5.789602044248679e+00}, + {2.692696265666640e-09, -5.803812598380606e+00}, + {2.699668088194915e-09, -5.817834096797069e+00}, + {2.706538269745573e-09, -5.831665585834668e+00}, + {2.713306551659817e-09, -5.845306117889361e+00}, + {2.719972679116734e-09, -5.858754751472542e+00}, + {2.726536401139295e-09, -5.872010551255358e+00}, + {2.732997470607439e-09, -5.885072588127400e+00}, + {2.739355644265558e-09, -5.897939939244211e+00}, + {2.745610682731633e-09, -5.910611688078208e+00}, + {2.751762350508137e-09, -5.923086924473290e+00}, + {2.757810415987146e-09, -5.935364744687794e+00}, + {2.763754651462700e-09, -5.947444251452243e+00}, + {2.769594833137415e-09, -5.959324554015538e+00}, + {2.775330741132843e-09, -5.971004768198829e+00}, + {2.780962159494174e-09, -5.982484016437981e+00}, + {2.786488876202047e-09, -5.993761427840588e+00}, + {2.791910683178690e-09, -6.004836138231525e+00}, + {2.797227376295779e-09, -6.015707290202086e+00}, + {2.802438755383971e-09, -6.026374033162623e+00}, + {2.807544624236659e-09, -6.036835523383457e+00}, + {2.812544790621093e-09, -6.047090924050914e+00}, + {2.817439066283459e-09, -6.057139405311101e+00}, + {2.822227266958278e-09, -6.066980144322601e+00}, + {2.826909212371261e-09, -6.076612325295799e+00}, + {2.831484726250221e-09, -6.086035139548830e+00}, + {2.835953636329660e-09, -6.095247785550617e+00}, + {2.840315774357203e-09, -6.104249468967751e+00}, + {2.844570976102082e-09, -6.113039402715685e+00}, + {2.848719081357095e-09, -6.121616806996519e+00}, + {2.852759933948860e-09, -6.129980909353977e+00}, + {2.856693381741114e-09, -6.138130944714082e+00}, + {2.860519276643053e-09, -6.146066155436312e+00}, + {2.864237474610633e-09, -6.153785791350256e+00}, + {2.867847835656203e-09, -6.161289109809551e+00}, + {2.871350223851726e-09, -6.168575375732642e+00}, + {2.874744507333867e-09, -6.175643861647406e+00}, + {2.878030558310989e-09, -6.182493847739853e+00}, + {2.881208253063899e-09, -6.189124621889823e+00}, + {2.884277471954592e-09, -6.195535479723423e+00}, + {2.887238099428306e-09, -6.201725724651554e+00}, + {2.890090024020323e-09, -6.207694667918394e+00}, + {2.892833138356060e-09, -6.213441628635915e+00}, + {2.895467339159240e-09, -6.218965933835304e+00}, + {2.897992527253659e-09, -6.224266918505075e+00}, + {2.900408607567016e-09, -6.229343925633495e+00}, + {2.902715489136496e-09, -6.234196306254763e+00}, + {2.904913085108075e-09, -6.238823419482017e+00}, + {2.907001312743911e-09, -6.243224632557377e+00}, + {2.908980093422997e-09, -6.247399320887848e+00}, + {2.910849352646620e-09, -6.251346868091392e+00}, + {2.912609020036956e-09, -6.255066666028537e+00}, + {2.914259029343965e-09, -6.258558114851525e+00}, + {2.915799318445710e-09, -6.261820623039620e+00}, + {2.917229829350759e-09, -6.264853607438842e+00}, + {2.918550508202463e-09, -6.267656493305673e+00}, + {2.919761305276718e-09, -6.270228714337005e+00}, + {2.920862174988150e-09, -6.272569712717951e+00}, + {2.921853075889193e-09, -6.274678939154603e+00}, + {2.922733970674264e-09, -6.276555852917634e+00}, + {2.923504826176907e-09, -6.278199921870962e+00}, + {2.924165613375264e-09, -6.279610622518139e+00}, + {2.924716307391075e-09, -6.280787440034993e+00}, + {2.925156887490598e-09, -6.281729868306345e+00}, + {2.925487337087508e-09, -6.282437409966992e+00}, + {2.925707643739298e-09, -6.282909576428774e+00}, + {2.925817799151970e-09, -6.283145887925411e+00}, }; #endif diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse3_intrinsics.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse3_intrinsics.h index f48e84aa1..bc25483e0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse3_intrinsics.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse3_intrinsics.h @@ -4,7 +4,7 @@ * \brief Holds SSE3 intrinsics of intrinsics. * They should be used in VOLK kernels to avoid copy-paste. * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ @@ -30,33 +30,35 @@ static inline __m128 _mm_complexmul_ps(__m128 x, __m128 y) { - __m128 yl, yh, tmp1, tmp2; - yl = _mm_moveldup_ps(y); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(y); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(x, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - x = _mm_shuffle_ps(x, x, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(x, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - return _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + __m128 yl, yh, tmp1, tmp2; + yl = _mm_moveldup_ps(y); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(y); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(x, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + x = _mm_shuffle_ps(x, x, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(x, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + return _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di } static inline __m128 _mm_complexconjugatemul_ps(__m128 x, __m128 y) { - const __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); - y = _mm_xor_ps(y, conjugator); // conjugate y - return _mm_complexmul_ps(x, y); + const __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); + y = _mm_xor_ps(y, conjugator); // conjugate y + return _mm_complexmul_ps(x, y); } static inline __m128 -_mm_magnitudesquared_ps_sse3(__m128 cplxValue1, __m128 cplxValue2){ - cplxValue1 = _mm_mul_ps(cplxValue1, cplxValue1); // Square the values - cplxValue2 = _mm_mul_ps(cplxValue2, cplxValue2); // Square the Values - return _mm_hadd_ps(cplxValue1, cplxValue2); // Add the I2 and Q2 values +_mm_magnitudesquared_ps_sse3(__m128 cplxValue1, __m128 cplxValue2) +{ + cplxValue1 = _mm_mul_ps(cplxValue1, cplxValue1); // Square the values + cplxValue2 = _mm_mul_ps(cplxValue2, cplxValue2); // Square the Values + return _mm_hadd_ps(cplxValue1, cplxValue2); // Add the I2 and Q2 values } static inline __m128 -_mm_magnitude_ps_sse3(__m128 cplxValue1, __m128 cplxValue2){ - return _mm_sqrt_ps(_mm_magnitudesquared_ps_sse3(cplxValue1, cplxValue2)); +_mm_magnitude_ps_sse3(__m128 cplxValue1, __m128 cplxValue2) +{ + return _mm_sqrt_ps(_mm_magnitudesquared_ps_sse3(cplxValue1, cplxValue2)); } #endif /* INCLUDE_VOLK_VOLK_SSE3_INTRINSICS_H_ */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse_intrinsics.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse_intrinsics.h index 6136efba3..9366775ec 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse_intrinsics.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/include/volk_gnsssdr/volk_gnsssdr_sse_intrinsics.h @@ -4,7 +4,7 @@ * \brief Holds SSE intrinsics of intrinsics. * They should be used in VOLK kernels to avoid copy-paste * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_VOLK_SSE_INTRINSICS_H_ @@ -27,20 +27,22 @@ #include static inline __m128 -_mm_magnitudesquared_ps(__m128 cplxValue1, __m128 cplxValue2){ - __m128 iValue, qValue; - // Arrange in i1i2i3i4 format - iValue = _mm_shuffle_ps(cplxValue1, cplxValue2, _MM_SHUFFLE(2,0,2,0)); - // Arrange in q1q2q3q4 format - qValue = _mm_shuffle_ps(cplxValue1, cplxValue2, _MM_SHUFFLE(3,1,3,1)); - iValue = _mm_mul_ps(iValue, iValue); // Square the I values - qValue = _mm_mul_ps(qValue, qValue); // Square the Q Values - return _mm_add_ps(iValue, qValue); // Add the I2 and Q2 values +_mm_magnitudesquared_ps(__m128 cplxValue1, __m128 cplxValue2) +{ + __m128 iValue, qValue; + // Arrange in i1i2i3i4 format + iValue = _mm_shuffle_ps(cplxValue1, cplxValue2, _MM_SHUFFLE(2, 0, 2, 0)); + // Arrange in q1q2q3q4 format + qValue = _mm_shuffle_ps(cplxValue1, cplxValue2, _MM_SHUFFLE(3, 1, 3, 1)); + iValue = _mm_mul_ps(iValue, iValue); // Square the I values + qValue = _mm_mul_ps(qValue, qValue); // Square the Q Values + return _mm_add_ps(iValue, qValue); // Add the I2 and Q2 values } static inline __m128 -_mm_magnitude_ps(__m128 cplxValue1, __m128 cplxValue2){ - return _mm_sqrt_ps(_mm_magnitudesquared_ps(cplxValue1, cplxValue2)); +_mm_magnitude_ps(__m128 cplxValue1, __m128 cplxValue2) +{ + return _mm_sqrt_ps(_mm_magnitudesquared_ps(cplxValue1, cplxValue2)); } #endif /* INCLUDED_VOLK_VOLK_SSE_INTRINSICS_H_ */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_16sc_magnitude_32f_aligned16_orc_impl.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_16sc_magnitude_32f_aligned16_orc_impl.orc index deef65904..c51514cd7 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_16sc_magnitude_32f_aligned16_orc_impl.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_16sc_magnitude_32f_aligned16_orc_impl.orc @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # .function volk_gnsssdr_16ic_magnitude_32f_a_orc_impl diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32f_x2_add_32f.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32f_x2_add_32f.orc index 887b8d6d9..3fcf5ef12 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32f_x2_add_32f.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32f_x2_add_32f.orc @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # .function volk_gnsssdr_32f_x2_add_32f_a_orc_impl diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_s32fc_multiply_32fc.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_s32fc_multiply_32fc.orc index 7ac882022..3a887137b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_s32fc_multiply_32fc.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_s32fc_multiply_32fc.orc @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # .function volk_gnsssdr_32fc_s32fc_multiply_32fc_a_orc_impl diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_x2_multiply_32fc.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_x2_multiply_32fc.orc index d1909f916..e9a6a0c60 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_x2_multiply_32fc.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_32fc_x2_multiply_32fc.orc @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # .function volk_gnsssdr_32fc_x2_multiply_32fc_a_orc_impl diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_accumulator_s8i.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_accumulator_s8i.orc index 0bf013391..0a172e80e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_accumulator_s8i.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_accumulator_s8i.orc @@ -7,7 +7,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -25,7 +25,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_x2_add_8i.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_x2_add_8i.orc index 30c3d354b..a5ff92e14 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_x2_add_8i.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8i_x2_add_8i.orc @@ -6,7 +6,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -24,7 +24,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc index b006f75d5..c6c2a1f6a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc @@ -10,7 +10,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -28,7 +28,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_magnitude_squared_8i.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_magnitude_squared_8i.orc index 3d271dfb6..e28bc323d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_magnitude_squared_8i.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_magnitude_squared_8i.orc @@ -10,7 +10,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -28,7 +28,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc index 0033a0bf7..038f8cc59 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc @@ -9,7 +9,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -27,7 +27,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_dot_prod_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_dot_prod_8ic.orc index d16fb3975..3af6dab5b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_dot_prod_8ic.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_dot_prod_8ic.orc @@ -10,7 +10,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -28,7 +28,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_multiply_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_multiply_8ic.orc index 1198b9da5..2d7e8e025 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_multiply_8ic.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x2_multiply_8ic.orc @@ -10,7 +10,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -28,7 +28,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x5_cw_epl_corr_8ic_x3.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x5_cw_epl_corr_8ic_x3.orc index 5fcf360d6..7b202294f 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x5_cw_epl_corr_8ic_x3.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_x5_cw_epl_corr_8ic_x3.orc @@ -19,7 +19,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -37,7 +37,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8u_x2_multiply_8u.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8u_x2_multiply_8u.orc index 64ba8f4fc..c638fc5d5 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8u_x2_multiply_8u.orc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8u_x2_multiply_8u.orc @@ -8,7 +8,7 @@ # # ------------------------------------------------------------------------- # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # GNSS-SDR is a software defined Global Navigation # Satellite Systems receiver @@ -26,7 +26,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # ------------------------------------------------------------------------- # diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_resamplerxnpuppet_16i.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_resamplerxnpuppet_16i.h new file mode 100644 index 000000000..1be4896b2 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_resamplerxnpuppet_16i.h @@ -0,0 +1,281 @@ +/*! + * \file volk_gnsssdr_16i_resamplerxnpuppet_16i.h + * \brief VOLK_GNSSSDR puppet for the multiple 16-bit vector resampler kernel. + * \authors
          + *
        • Cillian O'Driscoll 2017 cillian.odriscoll at gmail dot com + *
        + * + * VOLK_GNSSSDR puppet for integrating the multiple resampler into the test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_16i_resamplerxnpuppet_16i_H +#define INCLUDED_volk_gnsssdr_16i_resamplerxnpuppet_16i_H + +#include "volk_gnsssdr/volk_gnsssdr_16i_xn_resampler_16i_xn.h" +#include +#include +#include +#include + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_generic(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + int n; + float rem_code_phase_chips = -0.234; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif /* LV_HAVE_GENERIC */ + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_a_sse3(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_a_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_u_sse3(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_u_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_u_sse4_1(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_u_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_a_sse4_1(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_a_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_u_avx(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_u_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_a_avx(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_a_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_NEONV7 +static inline void volk_gnsssdr_16i_resamplerxnpuppet_16i_neon(int16_t* result, const int16_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + int16_t** result_aux = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_16i_xn_resampler_16i_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((int16_t*)result, (int16_t*)result_aux[0], sizeof(int16_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + +#endif // INCLUDED_volk_gnsssdr_16i_resamplerpuppet_16i_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_xn_resampler_16i_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_xn_resampler_16i_xn.h new file mode 100644 index 000000000..2491813bb --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16i_xn_resampler_16i_xn.h @@ -0,0 +1,615 @@ +/*! + * \file volk_gnsssdr_16i_xn_resampler_16i_xn.h + * \brief VOLK_GNSSSDR kernel: Resamples N 16 bits integer short vectors using zero hold resample algorithm. + * \authors
          + *
        • Cillian O'Driscoll, 2017. cillian.odriscoll(at)gmail.com + *
        + * + * VOLK_GNSSSDR kernel that resamples N 16 bits integer short complex vectors using zero hold resample algorithm. + * It resamples a single GNSS local code signal replica into N vectors fractional-resampled and fractional-delayed + * (i.e. it creates the Early, Prompt, and Late code replicas) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_16i_xn_resampler_16i_xn + * + * \b Overview + * + * Resamples a complex vector (16-bit integer each component), providing \p num_out_vectors outputs. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_16i_xn_resampler_16i_xn(int16_t** result, const int16_t* local_code, float* rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) + * \endcode + * + * \b Inputs + * \li local_code: Vector to be resampled. + * \li rem_code_phase_chips: Remnant code phase [chips]. + * \li code_phase_step_chips: Phase increment per sample [chips/sample]. + * \li shifts_chips: Vector of floats that defines the spacing (in chips) between the replicas of \p local_code + * \li code_length_chips: Code length in chips. + * \li num_out_vectors: Number of output vectors. + * \li num_points: The number of data values to be in the resampled vector. + * + * \b Outputs + * \li result: Pointer to a vector of pointers where the results will be stored. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_16i_xn_resampler_16i_xn_H +#define INCLUDED_volk_gnsssdr_16i_xn_resampler_16i_xn_H + +#include +#include +#include +#include +#include +#include + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_generic(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int local_code_chip_index; + int current_correlator_tap; + unsigned int n; + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = 0; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index < 0) local_code_chip_index += (int)code_length_chips * (abs(local_code_chip_index) / code_length_chips + 1); + local_code_chip_index = local_code_chip_index % code_length_chips; + result[current_correlator_tap][n] = local_code[local_code_chip_index]; + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_a_sse4_1(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_u_sse4_1(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_a_sse3(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_u_sse3(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_a_avx(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_u_avx(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_NEONV7 +#include +static inline void volk_gnsssdr_16i_xn_resampler_16i_xn_neon(int16_t** result, const int16_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int16_t** _result = result; + const unsigned int neon_iters = num_points / 4; + const int32x4_t ones = vdupq_n_s32(1); + const float32x4_t fours = vdupq_n_f32(4.0f); + const float32x4_t rem_code_phase_chips_reg = vdupq_n_f32(rem_code_phase_chips); + const float32x4_t code_phase_step_chips_reg = vdupq_n_f32(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int32_t local_code_chip_index[4]; + int32_t local_code_chip_index_; + + const int32x4_t zeros = vdupq_n_s32(0); + const float32x4_t code_length_chips_reg_f = vdupq_n_f32((float)code_length_chips); + const int32x4_t code_length_chips_reg_i = vdupq_n_s32((int32_t)code_length_chips); + int32x4_t local_code_chip_index_reg, aux_i, negatives, i; + float32x4_t aux, aux2, shifts_chips_reg, fi, c, j, cTrunc, base, indexn, reciprocal; + __VOLK_ATTR_ALIGNED(16) + const float vec[4] = {0.0f, 1.0f, 2.0f, 3.0f}; + uint32x4_t igx; + reciprocal = vrecpeq_f32(code_length_chips_reg_f); + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! + float32x4_t n0 = vld1q_f32((float*)vec); + int current_correlator_tap; + unsigned int n; + unsigned int k; + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = vdupq_n_f32((float)shifts_chips[current_correlator_tap]); + aux2 = vsubq_f32(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < neon_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][4 * n + 3], 1, 0); + __VOLK_GNSSSDR_PREFETCH(&local_code_chip_index[4]); + aux = vmulq_f32(code_phase_step_chips_reg, indexn); + aux = vaddq_f32(aux, aux2); + + //floor + i = vcvtq_s32_f32(aux); + fi = vcvtq_f32_s32(i); + igx = vcgtq_f32(fi, aux); + j = vcvtq_f32_s32(vandq_s32(vreinterpretq_s32_u32(igx), ones)); + aux = vsubq_f32(fi, j); + + // fmod + c = vmulq_f32(aux, reciprocal); + i = vcvtq_s32_f32(c); + cTrunc = vcvtq_f32_s32(i); + base = vmulq_f32(cTrunc, code_length_chips_reg_f); + aux = vsubq_f32(aux, base); + local_code_chip_index_reg = vcvtq_s32_f32(aux); + + negatives = vreinterpretq_s32_u32(vcltq_s32(local_code_chip_index_reg, zeros)); + aux_i = vandq_s32(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = vaddq_s32(local_code_chip_index_reg, aux_i); + + vst1q_s32((int32_t*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = vaddq_f32(indexn, fours); + } + for (n = neon_iters * 4; n < num_points; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][n], 1, 0); + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + + +#endif + + +#endif /*INCLUDED_volk_gnsssdr_16i_xn_resampler_16i_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h new file mode 100644 index 000000000..c16812e00 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h @@ -0,0 +1,1606 @@ +/*! + * \file volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h + * \brief VOLK_GNSSSDR kernel: multiplies N 16 bits vectors by a common vector + * phase rotated and accumulates the results in N 16 bits short complex outputs. + * \authors
          + *
        • Javier Arribas, 2015. jarribas(at)cttc.es + *
        + * + * VOLK_GNSSSDR kernel that multiplies N 16 bits vectors by a common vector, which is + * phase-rotated by phase offset and phase increment, and accumulates the results + * in N 16 bits short complex outputs. + * It is optimized to perform the N tap correlation process in GNSS receivers. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn + * + * \b Overview + * + * Rotates and multiplies the reference complex vector with an arbitrary number of other complex vectors, + * accumulates the results and stores them in the output vector. + * The rotation is done at a fixed rate per sample, from an initial \p phase offset. + * This function can be used for Doppler wipe-off and multiple correlator. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn((lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points); + * \endcode + * + * \b Inputs + * \li in_common: Pointer to one of the vectors to be rotated, multiplied and accumulated (reference vector). + * \li phase_inc: Phase increment = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)) + * \li phase: Initial phase = lv_cmake(cos(initial_phase_rad), sin(initial_phase_rad)) + * \li in_a: Pointer to an array of pointers to multiple vectors to be multiplied and accumulated. + * \li num_a_vectors: Number of vectors to be multiplied by the reference vector and accumulated. + * \li num_points: Number of complex values to be multiplied together, accumulated and stored into \p result. + * + * \b Outputs + * \li phase: Final phase. + * \li result: Vector of \p num_a_vectors components with the multiple vectors of \p in_a rotated, multiplied by \p in_common and accumulated. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_H +#define INCLUDED_volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_H + + +#include +#include +#include +#include +#include +//#include + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_generic(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_16sc_t tmp16; + lv_32fc_t tmp32; + int n_vec; + unsigned int n; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] = lv_cmake(0, 0); + } + for (n = 0; n < num_points; n++) + { + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + + // Regenerate phase + if (n % 256 == 0) + { + //printf("Phase before regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); +#ifdef __cplusplus + (*phase) /= std::abs((*phase)); +#else + (*phase) /= hypotf(lv_creal(*phase), lv_cimag(*phase)); +#endif + //printf("Phase after regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); + } + + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; + //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); + result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_generic_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_16sc_t tmp16; + lv_32fc_t tmp32; + int n_vec; + unsigned int n; + unsigned int j; + const unsigned int ROTATOR_RELOAD = 256; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] = lv_cmake(0, 0); + } + + for (n = 0; n < num_points / ROTATOR_RELOAD; n++) + { + for (j = 0; j < ROTATOR_RELOAD; j++) + { + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n * ROTATOR_RELOAD + j]; + //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); + result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); + } + } + /* Regenerate phase */ +#ifdef __cplusplus + (*phase) /= std::abs((*phase)); +#else + //(*phase) /= cabsf((*phase)); + (*phase) /= hypotf(lv_creal(*phase), lv_cimag(*phase)); +#endif + } + + for (j = 0; j < num_points % ROTATOR_RELOAD; j++) + { + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][(num_points / ROTATOR_RELOAD) * ROTATOR_RELOAD + j]; + //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); + result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + + +#ifdef LV_HAVE_SSE3 +#include + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_16sc_t dotProduct = lv_cmake(0, 0); + + const unsigned int sse_iters = num_points / 4; + int n_vec; + int i; + unsigned int number; + unsigned int n; + const int16_t** _in_a = in_a; + const lv_16sc_t* _in_common = in_common; + lv_16sc_t* _out = result; + + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; + + __m128i* cacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + cacc[n_vec] = _mm_setzero_si128(); + } + + __m128i a, b, c; + + // phase rotation registers + __m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; + __m128i pc1, pc2; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; + two_phase_inc[0] = phase_inc * phase_inc; + two_phase_inc[1] = phase_inc * phase_inc; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; + two_phase_acc[0] = (*phase); + two_phase_acc[1] = (*phase) * phase_inc; + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); + __m128 yl, yh, tmp1, tmp2, tmp3; + lv_16sc_t tmp16; + lv_32fc_t tmp32; + + for (number = 0; number < sse_iters; number++) + { + // Phase rotation on operand in_common starts here: + //printf("generic phase %i: %f,%f\n", n*4,lv_creal(*phase),lv_cimag(*phase)); + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + + //next two samples + _in_common += 2; + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + __VOLK_GNSSSDR_PREFETCH(_in_common + 8); + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + + // store four rotated in_common samples in the register b + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic + + //next two samples + _in_common += 2; + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a = _mm_loadl_epi64((__m128i*)&(_in_a[n_vec][number * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + + a = _mm_unpacklo_epi16(a, a); + + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + + cacc[n_vec] = _mm_adds_epi16(cacc[n_vec], c); + } + // Regenerate phase + if ((number % 128) == 0) + { + tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); + tmp2 = _mm_hadd_ps(tmp1, tmp1); + tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm_sqrt_ps(tmp1); + two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + } + } + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a = cacc[n_vec]; + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); + for (i = 0; i < 4; ++i) + { + dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + } + _out[n_vec] = dotProduct; + } + volk_gnsssdr_free(cacc); + + tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); + tmp2 = _mm_hadd_ps(tmp1, tmp1); + tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm_sqrt_ps(tmp1); + two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + + _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); + //(*phase) = lv_cmake((float*)two_phase_acc[0], (float*)two_phase_acc[1]); + (*phase) = two_phase_acc[0]; + + for (n = sse_iters * 4; n < num_points; n++) + { + tmp16 = in_common[n]; //printf("a_sse phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; + //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); + _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + } + } +} +#endif /* LV_HAVE_SSE3 */ + + +//#ifdef LV_HAVE_SSE3 +//#include + +//static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_sse3_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +//{ +//lv_16sc_t dotProduct = lv_cmake(0,0); + +//const unsigned int sse_iters = num_points / 4; +//const unsigned int ROTATOR_RELOAD = 128; +//int n_vec; +//int i; +//unsigned int number; +//unsigned int j; +//unsigned int n; + +//const int16_t** _in_a = in_a; +//const lv_16sc_t* _in_common = in_common; +//lv_16sc_t* _out = result; + +//__VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + +//__m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); +//__m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//realcacc[n_vec] = _mm_setzero_si128(); +//imagcacc[n_vec] = _mm_setzero_si128(); +//} + +//__m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl; + +//mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); +//mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + +//// phase rotation registers +//__m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; +//__m128i pc1, pc2; +//__VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; +//two_phase_inc[0] = phase_inc * phase_inc; +//two_phase_inc[1] = phase_inc * phase_inc; +//two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); +//__VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; +//two_phase_acc[0] = (*phase); +//two_phase_acc[1] = (*phase) * phase_inc; +//two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); +//__m128 yl, yh, tmp1, tmp2, tmp3; +//lv_16sc_t tmp16; +//lv_32fc_t tmp32; + +//for (number = 0; number < sse_iters / ROTATOR_RELOAD; ++number) +//{ +//for (j = 0; j < ROTATOR_RELOAD; j++) +//{ +//// Phase rotation on operand in_common starts here: +////printf("generic phase %i: %f,%f\n", n*4,lv_creal(*phase),lv_cimag(*phase)); +//pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg +////complex 32fc multiplication b=a*two_phase_acc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di +//pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + +////complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + +////next two samples +//_in_common += 2; +//pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg +//__VOLK_GNSSSDR_PREFETCH(_in_common + 8); +////complex 32fc multiplication b=a*two_phase_acc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di +//pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + +////complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + +//// store four rotated in_common samples in the register b +//b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + +////next two samples +//_in_common += 2; + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//a = _mm_load_si128((__m128i*)&(_in_a[n_vec][(number * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + +//c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + +//c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. +//real = _mm_subs_epi16(c, c_sr); + +//b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... +//a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + +//imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... +//imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + +//imag = _mm_adds_epi16(imag1, imag2); + +//realcacc[n_vec] = _mm_adds_epi16(realcacc[n_vec], real); +//imagcacc[n_vec] = _mm_adds_epi16(imagcacc[n_vec], imag); +//} +//} +//// regenerate phase +//tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); +//tmp2 = _mm_hadd_ps(tmp1, tmp1); +//tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); +//tmp2 = _mm_sqrt_ps(tmp1); +//two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); +//} + +//for (j = 0; j < sse_iters % ROTATOR_RELOAD; j++) +//{ +//pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg +////complex 32fc multiplication b=a*two_phase_acc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di +//pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + +////complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + +////next two samples +//_in_common += 2; +//pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg +//__VOLK_GNSSSDR_PREFETCH(_in_common + 8); +////complex 32fc multiplication b=a*two_phase_acc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di +//pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + +////complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg +//yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr +//yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di +//tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr +//tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br +//tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di +//two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + +//// store four rotated in_common samples in the register b +//b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + +////next two samples +//_in_common += 2; + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//a = _mm_load_si128((__m128i*)&(_in_a[n_vec][((sse_iters / ROTATOR_RELOAD) * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + +//c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + +//c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. +//real = _mm_subs_epi16(c, c_sr); + +//b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... +//a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + +//imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... +//imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + +//imag = _mm_adds_epi16(imag1, imag2); + +//realcacc[n_vec] = _mm_adds_epi16(realcacc[n_vec], real); +//imagcacc[n_vec] = _mm_adds_epi16(imagcacc[n_vec], imag); +//} +//} + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//realcacc[n_vec] = _mm_and_si128(realcacc[n_vec], mask_real); +//imagcacc[n_vec] = _mm_and_si128(imagcacc[n_vec], mask_imag); + +//a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); + +//_mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector +//dotProduct = lv_cmake(0,0); +//for (i = 0; i < 4; ++i) +//{ +//dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), +//sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); +//} +//_out[n_vec] = dotProduct; +//} + +//volk_gnsssdr_free(realcacc); +//volk_gnsssdr_free(imagcacc); + +//tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); +//tmp2 = _mm_hadd_ps(tmp1, tmp1); +//tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); +//tmp2 = _mm_sqrt_ps(tmp1); +//two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + +//_mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); +////(*phase) = lv_cmake((float*)two_phase_acc[0], (float*)two_phase_acc[1]); +//(*phase) = two_phase_acc[0]; + +//for(n = sse_iters * 4; n < num_points; n++) +//{ +//tmp16 = in_common[n]; //printf("a_sse phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); +//tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); +//tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); +//(*phase) *= phase_inc; + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; +////lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); +//_out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), +//sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); +//} +//} + +//} +//#endif [> LV_HAVE_SSE3 <] + + +#ifdef LV_HAVE_SSE3 +#include + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_16sc_t dotProduct = lv_cmake(0, 0); + + const unsigned int sse_iters = num_points / 4; + int n_vec; + int i; + unsigned int number; + unsigned int n; + const int16_t** _in_a = in_a; + const lv_16sc_t* _in_common = in_common; + lv_16sc_t* _out = result; + + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; + + __m128i* cacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + cacc[n_vec] = _mm_setzero_si128(); + } + + __m128i a, b, c; + + // phase rotation registers + __m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; + __m128i pc1, pc2; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; + two_phase_inc[0] = phase_inc * phase_inc; + two_phase_inc[1] = phase_inc * phase_inc; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; + two_phase_acc[0] = (*phase); + two_phase_acc[1] = (*phase) * phase_inc; + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); + __m128 yl, yh, tmp1, tmp2, tmp3; + lv_16sc_t tmp16; + lv_32fc_t tmp32; + + for (number = 0; number < sse_iters; number++) + { + // Phase rotation on operand in_common starts here: + //printf("generic phase %i: %f,%f\n", n*4,lv_creal(*phase),lv_cimag(*phase)); + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + + //next two samples + _in_common += 2; + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + __VOLK_GNSSSDR_PREFETCH(_in_common + 8); + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + + // store four rotated in_common samples in the register b + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic + + //next two samples + _in_common += 2; + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a = _mm_loadl_epi64((__m128i*)&(_in_a[n_vec][number * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + + a = _mm_unpacklo_epi16(a, a); + + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + + cacc[n_vec] = _mm_adds_epi16(cacc[n_vec], c); + } + // Regenerate phase + if ((number % 128) == 0) + { + tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); + tmp2 = _mm_hadd_ps(tmp1, tmp1); + tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm_sqrt_ps(tmp1); + two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + } + } + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a = cacc[n_vec]; + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); + for (i = 0; i < 4; ++i) + { + dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + } + _out[n_vec] = dotProduct; + } + volk_gnsssdr_free(cacc); + + tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); + tmp2 = _mm_hadd_ps(tmp1, tmp1); + tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm_sqrt_ps(tmp1); + two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + + _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); + //(*phase) = lv_cmake((float*)two_phase_acc[0], (float*)two_phase_acc[1]); + (*phase) = two_phase_acc[0]; + + for (n = sse_iters * 4; n < num_points; n++) + { + tmp16 = in_common[n]; //printf("a_sse phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; + //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); + _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + } + } +} +#endif /* LV_HAVE_SSE3 */ + + +#ifdef LV_HAVE_AVX2 +#include +#include +#include + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + const int16_t** _in_a = in_a; + const lv_16sc_t* _in_common = in_common; + lv_16sc_t* _out = result; + int n_vec; + unsigned int number; + unsigned int n; + + lv_16sc_t tmp16; + lv_32fc_t tmp32; + + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; + lv_16sc_t dotProduct = lv_cmake(0, 0); + + __m256i* cacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + cacc[n_vec] = _mm256_setzero_si256(); + } + + __m128i a128, ain_128, ain_128_lo, ain_128_hi; + __m256i ai; + __m256 a, b; + + __m256 four_phase_acc_reg, four_phase_inc_reg; + + lv_32fc_t _phase_inc = phase_inc * phase_inc * phase_inc * phase_inc; + + // Normalise the 4*phase increment +#ifdef __cplusplus + _phase_inc /= std::abs(_phase_inc); +#else + _phase_inc /= hypotf(lv_creal(_phase_inc), lv_cimag(_phase_inc)); +#endif + + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_inc[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_acc[4]; + for (n = 0; n < 4; ++n) + { + four_phase_inc[n] = _phase_inc; + four_phase_acc[n] = *phase; + *phase *= phase_inc; + } + four_phase_acc_reg = _mm256_load_ps((float*)four_phase_acc); + four_phase_inc_reg = _mm256_load_ps((float*)four_phase_inc); + + __m256i a2, b2, c, c1, c2, perm_idx; + + perm_idx = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + //perm_idx = _mm256_set_epi32( 0, 1, 4, 5, 2, 3, 6, 7); + + for (number = 0; number < avx2_iters; number++) + { + a128 = _mm_load_si128((__m128i*)_in_common); + ai = _mm256_cvtepi16_epi32(a128); + a = _mm256_cvtepi32_ps(ai); + + //complex 32fc multiplication b=a*two_phase_acc_reg + b = _mm256_complexmul_ps(a, four_phase_acc_reg); + c1 = _mm256_cvtps_epi32(b); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + four_phase_acc_reg = _mm256_complexmul_ps(four_phase_inc_reg, four_phase_acc_reg); + + //next four samples + _in_common += 4; + a128 = _mm_load_si128((__m128i*)_in_common); + ai = _mm256_cvtepi16_epi32(a128); + a = _mm256_cvtepi32_ps(ai); + + //complex 32fc multiplication b=a*two_phase_acc_reg + b = _mm256_complexmul_ps(a, four_phase_acc_reg); + c2 = _mm256_cvtps_epi32(b); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + four_phase_acc_reg = _mm256_complexmul_ps(four_phase_inc_reg, four_phase_acc_reg); + + __VOLK_GNSSSDR_PREFETCH(_in_common + 16); + + + // Store and convert 32ic to 16ic: + b2 = _mm256_packs_epi32(c1, c2); + + b2 = _mm256_permutevar8x32_epi32(b2, perm_idx); + + + _in_common += 4; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + ain_128 = _mm_load_si128((__m128i*)&(_in_a[n_vec][number * 8])); + + ain_128_lo = _mm_unpacklo_epi16(ain_128, ain_128); + ain_128_hi = _mm_unpackhi_epi16(ain_128, ain_128); + + a2 = _mm256_insertf128_si256(_mm256_castsi128_si256(ain_128_lo), ain_128_hi, 1); + + c = _mm256_mullo_epi16(a2, b2); + + cacc[n_vec] = _mm256_adds_epi16(cacc[n_vec], c); + } + // Regenerate phase + if ((number % 128) == 0) + { + four_phase_acc_reg = _mm256_complexnormalise_ps(four_phase_acc_reg); + } + } + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a2 = cacc[n_vec]; + + _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); + for (number = 0; number < 8; ++number) + { + dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[number])), + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[number]))); + } + _out[n_vec] = dotProduct; + } + + volk_gnsssdr_free(cacc); + _mm256_zeroupper(); + + _mm256_store_ps((float*)four_phase_acc, four_phase_acc_reg); + (*phase) = four_phase_acc[0]; + + for (n = avx2_iters * 8; n < num_points; n++) + { + tmp16 = in_common[n]; + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; + _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + } + } +} +#endif /* LV_HAVE_AVX2 */ + +#ifdef LV_HAVE_AVX2 +#include +#include +#include + +static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_u_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + const int16_t** _in_a = in_a; + const lv_16sc_t* _in_common = in_common; + lv_16sc_t* _out = result; + int n_vec; + unsigned int number; + unsigned int n; + + lv_16sc_t tmp16; + lv_32fc_t tmp32; + + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; + lv_16sc_t dotProduct = lv_cmake(0, 0); + + __m256i* cacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + cacc[n_vec] = _mm256_setzero_si256(); + } + + __m128i a128, ain_128, ain_128_lo, ain_128_hi; + __m256i ai; + __m256 a, b; + + __m256 four_phase_acc_reg, four_phase_inc_reg; + + lv_32fc_t _phase_inc = phase_inc * phase_inc * phase_inc * phase_inc; + + // Normalise the 4*phase increment +#ifdef __cplusplus + _phase_inc /= std::abs(_phase_inc); +#else + _phase_inc /= hypotf(lv_creal(_phase_inc), lv_cimag(_phase_inc)); +#endif + + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_inc[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_acc[4]; + for (n = 0; n < 4; ++n) + { + four_phase_inc[n] = _phase_inc; + four_phase_acc[n] = *phase; + *phase *= phase_inc; + } + four_phase_acc_reg = _mm256_load_ps((float*)four_phase_acc); + four_phase_inc_reg = _mm256_load_ps((float*)four_phase_inc); + + __m256i a2, b2, c, c1, c2, perm_idx; + + perm_idx = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + //perm_idx = _mm256_set_epi32( 0, 1, 4, 5, 2, 3, 6, 7); + + for (number = 0; number < avx2_iters; number++) + { + a128 = _mm_loadu_si128((__m128i*)_in_common); + ai = _mm256_cvtepi16_epi32(a128); + a = _mm256_cvtepi32_ps(ai); + + //complex 32fc multiplication b=a*two_phase_acc_reg + b = _mm256_complexmul_ps(a, four_phase_acc_reg); + c1 = _mm256_cvtps_epi32(b); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + four_phase_acc_reg = _mm256_complexmul_ps(four_phase_inc_reg, four_phase_acc_reg); + + //next four samples + _in_common += 4; + a128 = _mm_loadu_si128((__m128i*)_in_common); + ai = _mm256_cvtepi16_epi32(a128); + a = _mm256_cvtepi32_ps(ai); + + //complex 32fc multiplication b=a*two_phase_acc_reg + b = _mm256_complexmul_ps(a, four_phase_acc_reg); + c2 = _mm256_cvtps_epi32(b); // convert from 32fc to 32ic + + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + four_phase_acc_reg = _mm256_complexmul_ps(four_phase_inc_reg, four_phase_acc_reg); + + __VOLK_GNSSSDR_PREFETCH(_in_common + 16); + + + // Store and convert 32ic to 16ic: + b2 = _mm256_packs_epi32(c1, c2); + + b2 = _mm256_permutevar8x32_epi32(b2, perm_idx); + + + _in_common += 4; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + ain_128 = _mm_loadu_si128((__m128i*)&(_in_a[n_vec][number * 8])); + + ain_128_lo = _mm_unpacklo_epi16(ain_128, ain_128); + ain_128_hi = _mm_unpackhi_epi16(ain_128, ain_128); + + a2 = _mm256_insertf128_si256(_mm256_castsi128_si256(ain_128_lo), ain_128_hi, 1); + + c = _mm256_mullo_epi16(a2, b2); + + cacc[n_vec] = _mm256_adds_epi16(cacc[n_vec], c); + } + // Regenerate phase + if ((number % 128) == 0) + { + four_phase_acc_reg = _mm256_complexnormalise_ps(four_phase_acc_reg); + } + } + + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + a2 = cacc[n_vec]; + + _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); + for (number = 0; number < 8; ++number) + { + dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[number])), + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[number]))); + } + _out[n_vec] = dotProduct; + } + + volk_gnsssdr_free(cacc); + _mm256_zeroupper(); + + _mm256_store_ps((float*)four_phase_acc, four_phase_acc_reg); + (*phase) = four_phase_acc[0]; + + for (n = avx2_iters * 8; n < num_points; n++) + { + tmp16 = in_common[n]; + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; + _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + } + } +} +#endif /* LV_HAVE_AVX2 */ + +//#ifdef LV_HAVE_NEONV7 +//#include + +//static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +//{ +//const unsigned int neon_iters = num_points / 4; + +//const int16_t** _in_a = in_a; +//const lv_16sc_t* _in_common = in_common; +//lv_16sc_t* _out = result; +//int n_vec; +//int i; +//unsigned int number; +//unsigned int n; +//lv_16sc_t tmp16_, tmp; +//lv_32fc_t tmp32_; + +//if (neon_iters > 0) +//{ +//lv_16sc_t dotProduct = lv_cmake(0,0); +//float arg_phase0 = cargf(*phase); +//float arg_phase_inc = cargf(phase_inc); +//float phase_est; + +//lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + +//float32x4_t _phase4_real = vld1q_f32(__phase4_real); +//float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); + +//lv_32fc_t phase2 = (lv_32fc_t)(*phase) * phase_inc; +//lv_32fc_t phase3 = phase2 * phase_inc; +//lv_32fc_t phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//float32x4_t _phase_real = vld1q_f32(__phase_real); +//float32x4_t _phase_imag = vld1q_f32(__phase_imag); + +//int16x4x2_t a_val, b_val, c_val; +//__VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; +//float32x4_t half = vdupq_n_f32(0.5f); +//int16x4x2_t tmp16; +//int32x4x2_t tmp32i; + +//float32x4x2_t tmp32f, tmp32_real, tmp32_imag; +//float32x4_t sign, PlusHalf, Round; + +//int16x4x2_t* accumulator = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); + +//for(n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//accumulator[n_vec].val[0] = vdup_n_s16(0); +//accumulator[n_vec].val[1] = vdup_n_s16(0); +//} + +//for(number = 0; number < neon_iters; number++) +//{ +//[> load 4 complex numbers (int 16 bits each component) <] +//tmp16 = vld2_s16((int16_t*)_in_common); +//__VOLK_GNSSSDR_PREFETCH(_in_common + 8); +//_in_common += 4; + +//[> promote them to int 32 bits <] +//tmp32i.val[0] = vmovl_s16(tmp16.val[0]); +//tmp32i.val[1] = vmovl_s16(tmp16.val[1]); + +//[> promote them to float 32 bits <] +//tmp32f.val[0] = vcvtq_f32_s32(tmp32i.val[0]); +//tmp32f.val[1] = vcvtq_f32_s32(tmp32i.val[1]); + +//[> complex multiplication of four complex samples (float 32 bits each component) <] +//tmp32_real.val[0] = vmulq_f32(tmp32f.val[0], _phase_real); +//tmp32_real.val[1] = vmulq_f32(tmp32f.val[1], _phase_imag); +//tmp32_imag.val[0] = vmulq_f32(tmp32f.val[0], _phase_imag); +//tmp32_imag.val[1] = vmulq_f32(tmp32f.val[1], _phase_real); + +//tmp32f.val[0] = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//tmp32f.val[1] = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//[> downcast results to int32 <] +//[> in __aarch64__ we can do that with vcvtaq_s32_f32(ret1); vcvtaq_s32_f32(ret2); <] +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[0]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[0], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[0] = vcvtq_s32_f32(Round); + +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[1]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[1], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[1] = vcvtq_s32_f32(Round); + +//[> downcast results to int16 <] +//tmp16.val[0] = vqmovn_s32(tmp32i.val[0]); +//tmp16.val[1] = vqmovn_s32(tmp32i.val[1]); + +//[> compute next four phases <] +//tmp32_real.val[0] = vmulq_f32(_phase_real, _phase4_real); +//tmp32_real.val[1] = vmulq_f32(_phase_imag, _phase4_imag); +//tmp32_imag.val[0] = vmulq_f32(_phase_real, _phase4_imag); +//tmp32_imag.val[1] = vmulq_f32(_phase_imag, _phase4_real); + +//_phase_real = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//_phase_imag = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg +////__VOLK_GNSSSDR_PREFETCH(&_in_a[n_vec][number*4] + 8); + +//// multiply the real*real and imag*imag to get real result +//// a0r*b0r|a1r*b1r|a2r*b2r|a3r*b3r +//b_val.val[0] = vmul_s16(a_val.val[0], tmp16.val[0]); +//// a0i*b0i|a1i*b1i|a2i*b2i|a3i*b3i +//b_val.val[1] = vmul_s16(a_val.val[1], tmp16.val[1]); +//c_val.val[0] = vqsub_s16(b_val.val[0], b_val.val[1]); + +//// Multiply cross terms to get the imaginary result +//// a0r*b0i|a1r*b1i|a2r*b2i|a3r*b3i +//b_val.val[0] = vmul_s16(a_val.val[0], tmp16.val[1]); +//// a0i*b0r|a1i*b1r|a2i*b2r|a3i*b3r +//b_val.val[1] = vmul_s16(a_val.val[1], tmp16.val[0]); +//c_val.val[1] = vqadd_s16(b_val.val[0], b_val.val[1]); + +//accumulator[n_vec].val[0] = vqadd_s16(accumulator[n_vec].val[0], c_val.val[0]); +//accumulator[n_vec].val[1] = vqadd_s16(accumulator[n_vec].val[1], c_val.val[1]); +//} +//// Regenerate phase +//if ((number % 256) == 0) +//{ +//phase_est = arg_phase0 + (number + 1) * 4 * arg_phase_inc; + +//*phase = lv_cmake(cos(phase_est), sin(phase_est)); +//phase2 = (lv_32fc_t)(*phase) * phase_inc; +//phase3 = phase2 * phase_inc; +//phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//_phase_real = vld1q_f32(____phase_real); +//_phase_imag = vld1q_f32(____phase_imag); +//} +//} + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector +//dotProduct = lv_cmake(0,0); +//for (i = 0; i < 4; ++i) +//{ +//dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), +//sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); +//} +//_out[n_vec] = dotProduct; +//} +//volk_gnsssdr_free(accumulator); +//vst1q_f32((float32_t*)__phase_real, _phase_real); +//vst1q_f32((float32_t*)__phase_imag, _phase_imag); + +//(*phase) = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); +//} + +//for (n = neon_iters * 4; n < num_points; n++) +//{ +//tmp16_ = in_common[n]; //printf("neon phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); +//tmp32_ = lv_cmake((float32_t)lv_creal(tmp16_), (float32_t)lv_cimag(tmp16_)) * (*phase); +//tmp16_ = lv_cmake((int16_t)rintf(lv_creal(tmp32_)), (int16_t)rintf(lv_cimag(tmp32_))); +//(*phase) *= phase_inc; +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//tmp = tmp16_ * in_a[n_vec][n]; +//_out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); +//} +//} +//} + +//#endif [> LV_HAVE_NEONV7 <] + + +//#ifdef LV_HAVE_NEONV7 +//#include +//#include + +//static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_neon_vma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +//{ +//const unsigned int neon_iters = num_points / 4; + +//const int16_t** _in_a = in_a; +//const lv_16sc_t* _in_common = in_common; +//lv_16sc_t* _out = result; +//int n_vec; +//int i; +//unsigned int number; +//unsigned int n; +//lv_16sc_t tmp16_, tmp; +//lv_32fc_t tmp32_; + +//if (neon_iters > 0) +//{ +//lv_16sc_t dotProduct = lv_cmake(0,0); +//float arg_phase0 = cargf(*phase); +//float arg_phase_inc = cargf(phase_inc); +//float phase_est; +////printf("arg phase0: %f", arg_phase0); +//lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + +//float32x4_t _phase4_real = vld1q_f32(__phase4_real); +//float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); + +//lv_32fc_t phase2 = (lv_32fc_t)(*phase) * phase_inc; +//lv_32fc_t phase3 = phase2 * phase_inc; +//lv_32fc_t phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//float32x4_t _phase_real = vld1q_f32(__phase_real); +//float32x4_t _phase_imag = vld1q_f32(__phase_imag); + +//int16x4x2_t a_val, b_val; +//__VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; +//float32x4_t half = vdupq_n_f32(0.5f); +//int16x4x2_t tmp16; +//int32x4x2_t tmp32i; + +//float32x4x2_t tmp32f, tmp32_real, tmp32_imag; +//float32x4_t sign, PlusHalf, Round; + +//int16x4x2_t* accumulator = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); + +//for(n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//accumulator[n_vec].val[0] = vdup_n_s16(0); +//accumulator[n_vec].val[1] = vdup_n_s16(0); +//} + +//for(number = 0; number < neon_iters; number++) +//{ +//[> load 4 complex numbers (int 16 bits each component) <] +//tmp16 = vld2_s16((int16_t*)_in_common); +//__VOLK_GNSSSDR_PREFETCH(_in_common + 8); +//_in_common += 4; + +//[> promote them to int 32 bits <] +//tmp32i.val[0] = vmovl_s16(tmp16.val[0]); +//tmp32i.val[1] = vmovl_s16(tmp16.val[1]); + +//[> promote them to float 32 bits <] +//tmp32f.val[0] = vcvtq_f32_s32(tmp32i.val[0]); +//tmp32f.val[1] = vcvtq_f32_s32(tmp32i.val[1]); + +//[> complex multiplication of four complex samples (float 32 bits each component) <] +//tmp32_real.val[0] = vmulq_f32(tmp32f.val[0], _phase_real); +//tmp32_real.val[1] = vmulq_f32(tmp32f.val[1], _phase_imag); +//tmp32_imag.val[0] = vmulq_f32(tmp32f.val[0], _phase_imag); +//tmp32_imag.val[1] = vmulq_f32(tmp32f.val[1], _phase_real); + +//tmp32f.val[0] = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//tmp32f.val[1] = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//[> downcast results to int32 <] +//[> in __aarch64__ we can do that with vcvtaq_s32_f32(ret1); vcvtaq_s32_f32(ret2); <] +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[0]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[0], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[0] = vcvtq_s32_f32(Round); + +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[1]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[1], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[1] = vcvtq_s32_f32(Round); + +//[> downcast results to int16 <] +//tmp16.val[0] = vqmovn_s32(tmp32i.val[0]); +//tmp16.val[1] = vqmovn_s32(tmp32i.val[1]); + +//[> compute next four phases <] +//tmp32_real.val[0] = vmulq_f32(_phase_real, _phase4_real); +//tmp32_real.val[1] = vmulq_f32(_phase_imag, _phase4_imag); +//tmp32_imag.val[0] = vmulq_f32(_phase_real, _phase4_imag); +//tmp32_imag.val[1] = vmulq_f32(_phase_imag, _phase4_real); + +//_phase_real = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//_phase_imag = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//// Regenerate phase +//if ((number % 256) == 0) +//{ +////printf("computed phase: %f\n", cos(cargf(lv_cmake(_phase_real[0],_phase_imag[0])))); +//phase_est = arg_phase0 + (number + 1) * 4 * arg_phase_inc; +////printf("Estimated phase: %f\n\n", cos(phase_est)); + +//*phase = lv_cmake(cos(phase_est), sin(phase_est)); +//phase2 = (lv_32fc_t)(*phase) * phase_inc; +//phase3 = phase2 * phase_inc; +//phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//_phase_real = vld1q_f32(____phase_real); +//_phase_imag = vld1q_f32(____phase_imag); + +//// Round = vmulq_f32(_phase_real, _phase_real); +//// Round = vmlaq_f32(Round, _phase_imag, _phase_imag); +//// Round = vsqrtq_f32(Round);//printf("sqrt: %f \n", Round[0]); +////Round = vrsqrteq_f32(Round);printf("1/sqtr: %f \n",Round[0]); +////Round = vrecpeq_f32((Round); +//// _phase_real = vdivq_f32(_phase_real, Round); +//// _phase_imag = vdivq_f32(_phase_imag, Round); +////_phase_real = vmulq_f32(_phase_real, Round); +////_phase_imag = vmulq_f32(_phase_imag, Round); +////printf("After %i: %f,%f, %f\n\n", number, _phase_real[0], _phase_imag[0], sqrt(_phase_real[0]*_phase_real[0]+_phase_imag[0]*_phase_imag[0])); + +//} + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); + +//b_val.val[0] = vmul_s16(a_val.val[0], tmp16.val[0]); +//b_val.val[1] = vmul_s16(a_val.val[1], tmp16.val[0]); + +//// use multiply accumulate/subtract to get result +//b_val.val[0] = vmls_s16(b_val.val[0], a_val.val[1], tmp16.val[1]); +//b_val.val[1] = vmla_s16(b_val.val[1], a_val.val[0], tmp16.val[1]); + +//accumulator[n_vec].val[0] = vqadd_s16(accumulator[n_vec].val[0], b_val.val[0]); +//accumulator[n_vec].val[1] = vqadd_s16(accumulator[n_vec].val[1], b_val.val[1]); +//} +//} + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector +//dotProduct = lv_cmake(0,0); +//for (i = 0; i < 4; ++i) +//{ +//dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), +//sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); +//} +//_out[n_vec] = dotProduct; +//} +//volk_gnsssdr_free(accumulator); + +//vst1q_f32((float32_t*)__phase_real, _phase_real); +//vst1q_f32((float32_t*)__phase_imag, _phase_imag); + +//(*phase) = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); +//} + +//for (n = neon_iters * 4; n < num_points; n++) +//{ +//tmp16_ = in_common[n]; //printf("neon phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); +//tmp32_ = lv_cmake((float32_t)lv_creal(tmp16_), (float32_t)lv_cimag(tmp16_)) * (*phase); +//tmp16_ = lv_cmake((int16_t)rintf(lv_creal(tmp32_)), (int16_t)rintf(lv_cimag(tmp32_))); +//(*phase) *= phase_inc; +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//tmp = tmp16_ * in_a[n_vec][n]; +//_out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); +//} +//} +//} + +//#endif [> LV_HAVE_NEONV7 <] + + +//#ifdef LV_HAVE_NEONV7 +//#include +//#include + +//static inline void volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const int16_t** in_a, int num_a_vectors, unsigned int num_points) +//{ +//const unsigned int neon_iters = num_points / 4; + +//const int16_t** _in_a = in_a; +//const lv_16sc_t* _in_common = in_common; +//lv_16sc_t* _out = result; +//int n_vec; +//int i; +//unsigned int number; +//unsigned int n; +//lv_16sc_t tmp16_, tmp; +//lv_32fc_t tmp32_; + +//if (neon_iters > 0) +//{ +//lv_16sc_t dotProduct = lv_cmake(0,0); +//float arg_phase0 = cargf(*phase); +//float arg_phase_inc = cargf(phase_inc); +//float phase_est; + +//lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + +//float32x4_t _phase4_real = vld1q_f32(__phase4_real); +//float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); + +//lv_32fc_t phase2 = (lv_32fc_t)(*phase) * phase_inc; +//lv_32fc_t phase3 = phase2 * phase_inc; +//lv_32fc_t phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//float32x4_t _phase_real = vld1q_f32(__phase_real); +//float32x4_t _phase_imag = vld1q_f32(__phase_imag); + +//int16x4x2_t a_val, b_val; +//__VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; +//float32x4_t half = vdupq_n_f32(0.5f); +//int32x4x2_t tmp32i; + +//float32x4x2_t tmp32f, tmp32_real, tmp32_imag; +//float32x4_t sign, PlusHalf, Round; + +//int16x4x2_t* accumulator1 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); +//int16x4x2_t* accumulator2 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); + +//for(n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//accumulator1[n_vec].val[0] = vdup_n_s16(0); +//accumulator1[n_vec].val[1] = vdup_n_s16(0); +//accumulator2[n_vec].val[0] = vdup_n_s16(0); +//accumulator2[n_vec].val[1] = vdup_n_s16(0); +//} + +//for(number = 0; number < neon_iters; number++) +//{ +//[> load 4 complex numbers (int 16 bits each component) <] +//b_val = vld2_s16((int16_t*)_in_common); +//__VOLK_GNSSSDR_PREFETCH(_in_common + 8); +//_in_common += 4; + +//[> promote them to int 32 bits <] +//tmp32i.val[0] = vmovl_s16(b_val.val[0]); +//tmp32i.val[1] = vmovl_s16(b_val.val[1]); + +//[> promote them to float 32 bits <] +//tmp32f.val[0] = vcvtq_f32_s32(tmp32i.val[0]); +//tmp32f.val[1] = vcvtq_f32_s32(tmp32i.val[1]); + +//[> complex multiplication of four complex samples (float 32 bits each component) <] +//tmp32_real.val[0] = vmulq_f32(tmp32f.val[0], _phase_real); +//tmp32_real.val[1] = vmulq_f32(tmp32f.val[1], _phase_imag); +//tmp32_imag.val[0] = vmulq_f32(tmp32f.val[0], _phase_imag); +//tmp32_imag.val[1] = vmulq_f32(tmp32f.val[1], _phase_real); + +//tmp32f.val[0] = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//tmp32f.val[1] = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//[> downcast results to int32 <] +//[> in __aarch64__ we can do that with vcvtaq_s32_f32(ret1); vcvtaq_s32_f32(ret2); <] +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[0]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[0], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[0] = vcvtq_s32_f32(Round); + +//sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(tmp32f.val[1]), 31))); +//PlusHalf = vaddq_f32(tmp32f.val[1], half); +//Round = vsubq_f32(PlusHalf, sign); +//tmp32i.val[1] = vcvtq_s32_f32(Round); + +//[> downcast results to int16 <] +//b_val.val[0] = vqmovn_s32(tmp32i.val[0]); +//b_val.val[1] = vqmovn_s32(tmp32i.val[1]); + +//[> compute next four phases <] +//tmp32_real.val[0] = vmulq_f32(_phase_real, _phase4_real); +//tmp32_real.val[1] = vmulq_f32(_phase_imag, _phase4_imag); +//tmp32_imag.val[0] = vmulq_f32(_phase_real, _phase4_imag); +//tmp32_imag.val[1] = vmulq_f32(_phase_imag, _phase4_real); + +//_phase_real = vsubq_f32(tmp32_real.val[0], tmp32_real.val[1]); +//_phase_imag = vaddq_f32(tmp32_imag.val[0], tmp32_imag.val[1]); + +//// Regenerate phase +//if ((number % 256) == 0) +//{ +////printf("computed phase: %f\n", cos(cargf(lv_cmake(_phase_real[0],_phase_imag[0])))); +//phase_est = arg_phase0 + (number + 1) * 4 * arg_phase_inc; +////printf("Estimated phase: %f\n\n", cos(phase_est)); + +//*phase = lv_cmake(cos(phase_est), sin(phase_est)); +//phase2 = (lv_32fc_t)(*phase) * phase_inc; +//phase3 = phase2 * phase_inc; +//phase4 = phase3 * phase_inc; + +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; +//__VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + +//_phase_real = vld1q_f32(____phase_real); +//_phase_imag = vld1q_f32(____phase_imag); +//} + +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); + +//// use 2 accumulators to remove inter-instruction data dependencies +//accumulator1[n_vec].val[0] = vmla_s16(accumulator1[n_vec].val[0], a_val.val[0], b_val.val[0]); +//accumulator1[n_vec].val[1] = vmla_s16(accumulator1[n_vec].val[1], a_val.val[0], b_val.val[1]); +//accumulator2[n_vec].val[0] = vmls_s16(accumulator2[n_vec].val[0], a_val.val[1], b_val.val[1]); +//accumulator2[n_vec].val[1] = vmla_s16(accumulator2[n_vec].val[1], a_val.val[1], b_val.val[0]); +//} +//} +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//accumulator1[n_vec].val[0] = vqadd_s16(accumulator1[n_vec].val[0], accumulator2[n_vec].val[0]); +//accumulator1[n_vec].val[1] = vqadd_s16(accumulator1[n_vec].val[1], accumulator2[n_vec].val[1]); +//} +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//vst2_s16((int16_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector +//dotProduct = lv_cmake(0,0); +//for (i = 0; i < 4; ++i) +//{ +//dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), +//sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); +//} +//_out[n_vec] = dotProduct; +//} +//volk_gnsssdr_free(accumulator1); +//volk_gnsssdr_free(accumulator2); + +//vst1q_f32((float32_t*)__phase_real, _phase_real); +//vst1q_f32((float32_t*)__phase_imag, _phase_imag); + +//(*phase) = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); +//} + +//for (n = neon_iters * 4; n < num_points; n++) +//{ +//tmp16_ = in_common[n]; //printf("neon phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); +//tmp32_ = lv_cmake((float32_t)lv_creal(tmp16_), (float32_t)lv_cimag(tmp16_)) * (*phase); +//tmp16_ = lv_cmake((int16_t)rintf(lv_creal(tmp32_)), (int16_t)rintf(lv_cimag(tmp32_))); +//(*phase) *= phase_inc; +//for (n_vec = 0; n_vec < num_a_vectors; n_vec++) +//{ +//tmp = tmp16_ * in_a[n_vec][n]; +//_out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); +//} +//} +//} + +//#endif [> LV_HAVE_NEONV7 <] + +#endif /*INCLUDED_volk_gnsssdr_16ic_16i_dot_prod_16ic_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic.h new file mode 100644 index 000000000..e28e01225 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic.h @@ -0,0 +1,381 @@ +/*! + * \file volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic.h + * \brief Volk puppet for the multiple 16-bit complex dot product kernel. + * \authors
          + *
        • Carles Fernandez Prades 2016 cfernandez at cttc dot cat + *
        + * + * Volk puppet for integrating the resampler into volk's test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_H +#define INCLUDED_volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_H + +#include "volk_gnsssdr/volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn.h" +#include +#include +#include + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_generic(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_generic(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // Generic + + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_generic_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_generic_reload(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // Generic + + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_a_sse3(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_sse3(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // SSE3 + + +//#ifdef LV_HAVE_SSE3 +//static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_a_sse3_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +//{ +//// phases must be normalized. Phase rotator expects a complex exponential input! +//float rem_carrier_phase_in_rad = 0.345; +//float phase_step_rad = 0.1; +//lv_32fc_t phase[1]; +//phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +//lv_32fc_t phase_inc[1]; +//phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +//int n; +//int num_a_vectors = 3; +//int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); +//for(n = 0; n < num_a_vectors; n++) +//{ +//in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); +//memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); +//} + +//volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_sse3_reload(result, local_code, phase_inc[0], phase, (const int16_t**) in_a, num_a_vectors, num_points); + +//for(n = 0; n < num_a_vectors; n++) +//{ +//volk_gnsssdr_free(in_a[n]); +//} +//volk_gnsssdr_free(in_a); +//} + +//#endif // SSE3 + + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_u_sse3(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_u_sse3(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // SSE3 + + +#ifdef LV_HAVE_AVX2 +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_a_avx2(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_avx2(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // AVX2 + + +//#ifdef LV_HAVE_AVX2 +//static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_a_avx2_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +//{ +//// phases must be normalized. Phase rotator expects a complex exponential input! +//float rem_carrier_phase_in_rad = 0.345; +//float phase_step_rad = 0.1; +//lv_32fc_t phase[1]; +//phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +//lv_32fc_t phase_inc[1]; +//phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +//int n; +//int num_a_vectors = 3; +//int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); +//for(n = 0; n < num_a_vectors; n++) +//{ +//in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); +//memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); +//} + +//volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const int16_t**) in_a, num_a_vectors, num_points); + +//for(n = 0; n < num_a_vectors; n++) +//{ +//volk_gnsssdr_free(in_a[n]); +//} +//volk_gnsssdr_free(in_a); +//} + +//#endif // AVX2 + + +#ifdef LV_HAVE_AVX2 +static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_u_avx2(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.345; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); + } + + volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_u_avx2(result, local_code, phase_inc[0], phase, (const int16_t**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // AVX2 + + +//#ifdef LV_HAVE_AVX2 +//static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_u_avx2_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +//{ +//// phases must be normalized. Phase rotator expects a complex exponential input! +//float rem_carrier_phase_in_rad = 0.345; +//float phase_step_rad = 0.1; +//lv_32fc_t phase[1]; +//phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +//lv_32fc_t phase_inc[1]; +//phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +//int n; +//int num_a_vectors = 3; +//int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); +//for(n = 0; n < num_a_vectors; n++) +//{ +//in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); +//memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); +//} + +//volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const int16_t**) in_a, num_a_vectors, num_points); + +//for(n = 0; n < num_a_vectors; n++) +//{ +//volk_gnsssdr_free(in_a[n]); +//} +//volk_gnsssdr_free(in_a); +//} + +//#endif // AVX2 + + +//#ifdef LV_HAVE_NEONV7 +//static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +//{ +//// phases must be normalized. Phase rotator expects a complex exponential input! +//float rem_carrier_phase_in_rad = 0.345; +//float phase_step_rad = 0.1; +//lv_32fc_t phase[1]; +//phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +//lv_32fc_t phase_inc[1]; +//phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +//int n; +//int num_a_vectors = 3; +//int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); +//for(n = 0; n < num_a_vectors; n++) +//{ +//in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); +//memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); +//} + +//volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_neon(result, local_code, phase_inc[0], phase, (const int16_t**) in_a, num_a_vectors, num_points); + +//for(n = 0; n < num_a_vectors; n++) +//{ +//volk_gnsssdr_free(in_a[n]); +//} +//volk_gnsssdr_free(in_a); +//} + +//#endif // NEON + + +//#ifdef LV_HAVE_NEONV7 +//static inline void volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_neon_vma(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +//{ +//// phases must be normalized. Phase rotator expects a complex exponential input! +//float rem_carrier_phase_in_rad = 0.345; +//float phase_step_rad = 0.1; +//lv_32fc_t phase[1]; +//phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +//lv_32fc_t phase_inc[1]; +//phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +//int n; +//int num_a_vectors = 3; +//int16_t** in_a = (int16_t**)volk_gnsssdr_malloc(sizeof(int16_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); +//for(n = 0; n < num_a_vectors; n++) +//{ +//in_a[n] = (int16_t*)volk_gnsssdr_malloc(sizeof(int16_t) * num_points, volk_gnsssdr_get_alignment()); +//memcpy((int16_t*)in_a[n], (int16_t*)in, sizeof(int16_t) * num_points); +//} + +//volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn_neon_vma(result, local_code, phase_inc[0], phase, (const int16_t**) in_a, num_a_vectors, num_points); + +//for(n = 0; n < num_a_vectors; n++) +//{ +//volk_gnsssdr_free(in_a[n]); +//} +//volk_gnsssdr_free(in_a); +//} + +//#endif // NEON + +#endif // INCLUDED_volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_conjugate_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_conjugate_16ic.h new file mode 100644 index 000000000..035ae676b --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_conjugate_16ic.h @@ -0,0 +1,233 @@ +/*! + * \file volk_gnsssdr_16ic_conjugate_16ic.h + * \brief VOLK_GNSSSDR kernel: returns the conjugate of a 16 bits complex vector. + * \authors
          + *
        • Carles Fernandez Prades 2017 cfernandez at cttc dot cat + *
        + * + * VOLK_GNSSSDR kernel that calculates the conjugate of a + * 16 bits complex vector (16 bits the real part and 16 bits the imaginary part) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_16ic_conjugate_16ic + * + * \b Overview + * + * Takes the conjugate of a complex signed 16-bit integer vector. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_16ic_conjugate_16ic(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points); + * \endcode + * + * \b Inputs + * \li aVector: Vector of complex items to be conjugated + * \li num_points: The number of complex data points. + * + * \b Outputs + * \li cVector: The vector where the result will be stored + * + */ + +#ifndef INCLUDED_volk_gnsssdr_16ic_conjugate_16ic_H +#define INCLUDED_volk_gnsssdr_16ic_conjugate_16ic_H + +#include + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_16ic_conjugate_16ic_generic(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +{ + lv_16sc_t* cPtr = cVector; + const lv_16sc_t* aPtr = aVector; + unsigned int number; + + for (number = 0; number < num_points; number++) + { + *cPtr++ = lv_conj(*aPtr++); + } +} + +#endif /* LV_HAVE_GENERIC */ + + +#ifdef LV_HAVE_SSSE3 +#include + +static inline void volk_gnsssdr_16ic_conjugate_16ic_u_ssse3(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +{ + const unsigned int sse_iters = num_points / 4; + unsigned int i; + lv_16sc_t* c = cVector; + const lv_16sc_t* a = aVector; + __m128i tmp; + + __m128i conjugator = _mm_setr_epi16(1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < sse_iters; ++i) + { + tmp = _mm_lddqu_si128((__m128i*)a); + tmp = _mm_sign_epi16(tmp, conjugator); + _mm_storeu_si128((__m128i*)c, tmp); + a += 4; + c += 4; + } + + for (i = sse_iters * 4; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} + +#endif /* LV_HAVE_SSSE3 */ + + +#ifdef LV_HAVE_SSSE3 +#include + +static inline void volk_gnsssdr_16ic_conjugate_16ic_a_ssse3(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +{ + const unsigned int sse_iters = num_points / 4; + unsigned int i; + lv_16sc_t* c = cVector; + const lv_16sc_t* a = aVector; + __m128i tmp; + __m128i conjugator = _mm_setr_epi16(1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < sse_iters; ++i) + { + tmp = _mm_load_si128((__m128i*)a); + tmp = _mm_sign_epi16(tmp, conjugator); + _mm_store_si128((__m128i*)c, tmp); + a += 4; + c += 4; + } + + for (i = sse_iters * 4; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} + +#endif /* LV_HAVE_SSSE3 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_16ic_conjugate_16ic_a_avx2(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + unsigned int i; + lv_16sc_t* c = cVector; + const lv_16sc_t* a = aVector; + + __m256i tmp; + __m256i conjugator = _mm256_setr_epi16(1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < avx2_iters; ++i) + { + tmp = _mm256_load_si256((__m256i*)a); + tmp = _mm256_sign_epi16(tmp, conjugator); + _mm256_store_si256((__m256i*)c, tmp); + + a += 8; + c += 8; + } + + for (i = avx2_iters * 8; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} + +#endif /* LV_HAVE_AVX2 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_16ic_conjugate_16ic_u_avx2(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + unsigned int i; + lv_16sc_t* c = cVector; + const lv_16sc_t* a = aVector; + + __m256i tmp; + __m256i conjugator = _mm256_setr_epi16(1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < avx2_iters; ++i) + { + tmp = _mm256_loadu_si256((__m256i*)a); + tmp = _mm256_sign_epi16(tmp, conjugator); + _mm256_storeu_si256((__m256i*)c, tmp); + + a += 8; + c += 8; + } + + for (i = avx2_iters * 8; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} +#endif /* LV_HAVE_AVX2 */ + +// +// +//#ifdef LV_HAVE_NEONV7 +//#include +// +//static inline void volk_gnsssdr_16ic_conjugate_16ic_neon(lv_16sc_t* cVector, const lv_16sc_t* aVector, unsigned int num_points) +//{ +// const unsigned int sse_iters = num_points / 4; +// unsigned int i; +// lv_16sc_t* c = cVector; +// const lv_16sc_t* a = aVector; +// int16x4x2_t a_val; +// +// for (i = 0; i < sse_iters; ++i) +// { +// a_val = vld2_s16((const int16_t*)a); +// __VOLK_GNSSSDR_PREFETCH(a + 4); +// a_val.val[1] = vneg_s16(a_val.val[1]); +// vst2_s16((int16_t*)c, a_val); +// a += 4; +// c += 4; +// } +// +// for (i = sse_iters * 4; i < num_points; ++i) +// { +// *c++ = lv_conj(*a++); +// } +//} +//#endif /* LV_HAVE_NEONV7 */ + +#endif /* INCLUDED_volk_gnsssdr_16ic_conjugate_16ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_convert_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_convert_32fc.h index fa9517b76..57d76874c 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_convert_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_convert_32fc.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -63,7 +63,7 @@ static inline void volk_gnsssdr_16ic_convert_32fc_generic(lv_32fc_t* outputVector, const lv_16sc_t* inputVector, unsigned int num_points) { unsigned int i; - for(i = 0; i < num_points; i++) + for (i = 0; i < num_points; i++) { outputVector[i] = lv_cmake((float)lv_creal(inputVector[i]), (float)lv_cimag(inputVector[i])); } @@ -82,9 +82,9 @@ static inline void volk_gnsssdr_16ic_convert_32fc_a_sse2(lv_32fc_t* outputVector lv_32fc_t* _out = outputVector; __m128 a; - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // load (2 byte imag, 2 byte real) x 2 into 128 bits reg _mm_store_ps((float*)_out, a); _in += 2; _out += 2; @@ -109,9 +109,9 @@ static inline void volk_gnsssdr_16ic_convert_32fc_u_sse2(lv_32fc_t* outputVector lv_32fc_t* _out = outputVector; __m128 a; - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg _mm_storeu_ps((float*)_out, a); _in += 2; _out += 2; @@ -136,15 +136,15 @@ static inline void volk_gnsssdr_16ic_convert_32fc_u_axv(lv_32fc_t* outputVector, lv_32fc_t* _out = outputVector; __m256 a; - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - a = _mm256_set_ps((float)(lv_cimag(_in[3])), (float)(lv_creal(_in[3])), (float)(lv_cimag(_in[2])), (float)(lv_creal(_in[2])), (float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm256_set_ps((float)(lv_cimag(_in[3])), (float)(lv_creal(_in[3])), (float)(lv_cimag(_in[2])), (float)(lv_creal(_in[2])), (float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg _mm256_storeu_ps((float*)_out, a); _in += 4; _out += 4; } _mm256_zeroupper(); - for(i = 0; i < (num_points % 4); ++i) + for (i = 0; i < (num_points % 4); ++i) { *_out++ = lv_cmake((float)lv_creal(*_in), (float)lv_cimag(*_in)); _in++; @@ -163,15 +163,15 @@ static inline void volk_gnsssdr_16ic_convert_32fc_a_axv(lv_32fc_t* outputVector, lv_32fc_t* _out = outputVector; __m256 a; - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - a = _mm256_set_ps((float)(lv_cimag(_in[3])), (float)(lv_creal(_in[3])), (float)(lv_cimag(_in[2])), (float)(lv_creal(_in[2])), (float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm256_set_ps((float)(lv_cimag(_in[3])), (float)(lv_creal(_in[3])), (float)(lv_cimag(_in[2])), (float)(lv_creal(_in[2])), (float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg _mm256_store_ps((float*)_out, a); _in += 4; _out += 4; } _mm256_zeroupper(); - for(i = 0; i < (num_points % 4); ++i) + for (i = 0; i < (num_points % 4); ++i) { *_out++ = lv_cmake((float)lv_creal(*_in), (float)lv_cimag(*_in)); _in++; @@ -179,8 +179,75 @@ static inline void volk_gnsssdr_16ic_convert_32fc_a_axv(lv_32fc_t* outputVector, } #endif /* LV_HAVE_AVX */ +#ifdef LV_HAVE_AVX2 +#include -#ifdef LV_HAVE_NEON +static inline void volk_gnsssdr_16ic_convert_32fc_a_avx2(lv_32fc_t* outputVector, const lv_16sc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx_iters = num_points / 8; + unsigned int number = 0; + const int16_t* complexVectorPtr = (int16_t*)inputVector; + float* outputVectorPtr = (float*)outputVector; + __m256 outVal; + __m256i outValInt; + __m128i cplxValue; + + for (number = 0; number < avx_iters; number++) + { + cplxValue = _mm_load_si128((__m128i*)complexVectorPtr); + complexVectorPtr += 8; + + outValInt = _mm256_cvtepi16_epi32(cplxValue); + outVal = _mm256_cvtepi32_ps(outValInt); + _mm256_store_ps((float*)outputVectorPtr, outVal); + + outputVectorPtr += 8; + } + + number = avx_iters * 8; + for (; number < num_points * 2; number++) + { + *outputVectorPtr++ = (float)*complexVectorPtr++; + } +} + +#endif /* LV_HAVE_AVX2 */ + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_16ic_convert_32fc_u_avx2(lv_32fc_t* outputVector, const lv_16sc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx_iters = num_points / 8; + unsigned int number = 0; + const int16_t* complexVectorPtr = (int16_t*)inputVector; + float* outputVectorPtr = (float*)outputVector; + __m256 outVal; + __m256i outValInt; + __m128i cplxValue; + + for (number = 0; number < avx_iters; number++) + { + cplxValue = _mm_loadu_si128((__m128i*)complexVectorPtr); + complexVectorPtr += 8; + + outValInt = _mm256_cvtepi16_epi32(cplxValue); + outVal = _mm256_cvtepi32_ps(outValInt); + _mm256_storeu_ps((float*)outputVectorPtr, outVal); + + outputVectorPtr += 8; + } + + number = avx_iters * 8; + for (; number < num_points * 2; number++) + { + *outputVectorPtr++ = (float)*complexVectorPtr++; + } +} + +#endif /* LV_HAVE_AVX2 */ + +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_convert_32fc_neon(lv_32fc_t* outputVector, const lv_16sc_t* inputVector, unsigned int num_points) @@ -194,7 +261,7 @@ static inline void volk_gnsssdr_16ic_convert_32fc_neon(lv_32fc_t* outputVector, int32x4_t a32x4; float32x4_t f32x4; - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { a16x4 = vld1_s16((const int16_t*)_in); __VOLK_GNSSSDR_PREFETCH(_in + 4); @@ -210,6 +277,6 @@ static inline void volk_gnsssdr_16ic_convert_32fc_neon(lv_32fc_t* outputVector, _in++; } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_32fc_convert_16ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resampler_fast_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resampler_fast_16ic.h index 8f35d59b8..634f4f8c3 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resampler_fast_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resampler_fast_16ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -61,9 +61,9 @@ #ifndef INCLUDED_volk_gnsssdr_16ic_resampler_fast_16ic_H #define INCLUDED_volk_gnsssdr_16ic_resampler_fast_16ic_H -#include #include #include +#include #ifdef LV_HAVE_GENERIC @@ -78,7 +78,7 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_generic(lv_16sc_t* resu // resample code for current tap local_code_chip_index = round(code_phase_step_chips * (float)n + rem_code_phase_chips - 0.5f); if (local_code_chip_index < 0.0) local_code_chip_index += code_length_chips; - if (local_code_chip_index > (code_length_chips-1)) local_code_chip_index -= code_length_chips; + if (local_code_chip_index > (code_length_chips - 1)) local_code_chip_index -= code_length_chips; result[n] = local_code[local_code_chip_index]; } } @@ -89,61 +89,66 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_generic(lv_16sc_t* resu #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples)//, int* scratch_buffer, float* scratch_buffer_float) +static inline void volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples) //, int* scratch_buffer, float* scratch_buffer_float) { - _MM_SET_ROUNDING_MODE (_MM_ROUND_NEAREST);//_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); //_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; lv_16sc_t* _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; __m128 _rem_code_phase, _code_phase_step_chips; __m128i _code_length_chips, _code_length_chips_minus1; __m128 _code_phase_out, _code_phase_out_with_offset; rem_code_phase_chips = rem_code_phase_chips - 0.5f; - _rem_code_phase = _mm_load1_ps(&rem_code_phase_chips); //load float to all four float values in m128 register - _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; - four_times_code_length_chips_minus1[0] = code_length_chips-1; - four_times_code_length_chips_minus1[1] = code_length_chips-1; - four_times_code_length_chips_minus1[2] = code_length_chips-1; - four_times_code_length_chips_minus1[3] = code_length_chips-1; + _rem_code_phase = _mm_load1_ps(&rem_code_phase_chips); //load float to all four float values in m128 register + _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; + four_times_code_length_chips_minus1[0] = code_length_chips - 1; + four_times_code_length_chips_minus1[1] = code_length_chips - 1; + four_times_code_length_chips_minus1[2] = code_length_chips - 1; + four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = _mm_load_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register - _code_length_chips_minus1 = _mm_load_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register + _code_length_chips = _mm_load_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register + _code_length_chips_minus1 = _mm_load_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register __m128i negative_indexes, overflow_indexes, _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; __m128i zero = _mm_setzero_si128(); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; __m128 _4output_index = _mm_load_ps(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; __m128 _4constant_float = _mm_load_ps(init_4constant_float); - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { - _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset - _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer + _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer - negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128( negative_indexes, _mm_xor_si128( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128(negative_indexes, _mm_xor_si128(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128( overflow_indexes, _mm_xor_si128( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128(overflow_indexes, _mm_xor_si128(_code_phase_out_int_over, _code_phase_out_int_neg))); - _mm_store_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + _mm_store_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible *_result++ = local_code[local_code_chip_index[0]]; @@ -154,7 +159,7 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(lv_16sc_t* resul _4output_index = _mm_add_ps(_4output_index, _4constant_float); } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)number + rem_code_phase_chips + 0.5f); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; @@ -169,61 +174,66 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(lv_16sc_t* resul #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples)//, int* scratch_buffer, float* scratch_buffer_float) +static inline void volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples) //, int* scratch_buffer, float* scratch_buffer_float) { - _MM_SET_ROUNDING_MODE (_MM_ROUND_NEAREST);//_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); //_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; lv_16sc_t* _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; __m128 _rem_code_phase, _code_phase_step_chips; __m128i _code_length_chips, _code_length_chips_minus1; __m128 _code_phase_out, _code_phase_out_with_offset; rem_code_phase_chips = rem_code_phase_chips - 0.5f; - _rem_code_phase = _mm_load1_ps(&rem_code_phase_chips); //load float to all four float values in m128 register - _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; - four_times_code_length_chips_minus1[0] = code_length_chips-1; - four_times_code_length_chips_minus1[1] = code_length_chips-1; - four_times_code_length_chips_minus1[2] = code_length_chips-1; - four_times_code_length_chips_minus1[3] = code_length_chips-1; + _rem_code_phase = _mm_load1_ps(&rem_code_phase_chips); //load float to all four float values in m128 register + _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; + four_times_code_length_chips_minus1[0] = code_length_chips - 1; + four_times_code_length_chips_minus1[1] = code_length_chips - 1; + four_times_code_length_chips_minus1[2] = code_length_chips - 1; + four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = _mm_loadu_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register - _code_length_chips_minus1 = _mm_loadu_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register + _code_length_chips = _mm_loadu_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register + _code_length_chips_minus1 = _mm_loadu_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register __m128i negative_indexes, overflow_indexes, _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; __m128i zero = _mm_setzero_si128(); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; __m128 _4output_index = _mm_loadu_ps(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; __m128 _4constant_float = _mm_loadu_ps(init_4constant_float); - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { - _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset - _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer + _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer - negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128( negative_indexes, _mm_xor_si128( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128(negative_indexes, _mm_xor_si128(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128( overflow_indexes, _mm_xor_si128( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128(overflow_indexes, _mm_xor_si128(_code_phase_out_int_over, _code_phase_out_int_neg))); - _mm_storeu_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + _mm_storeu_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible *_result++ = local_code[local_code_chip_index[0]]; @@ -234,7 +244,7 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(lv_16sc_t* resul _4output_index = _mm_add_ps(_4output_index, _4constant_float); } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)number + rem_code_phase_chips + 0.5f); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; @@ -246,10 +256,10 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(lv_16sc_t* resul #endif /* LV_HAVE_SSE2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_resampler_fast_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples)//, int* scratch_buffer, float* scratch_buffer_float) +static inline void volk_gnsssdr_16ic_resampler_fast_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, int code_length_chips, unsigned int num_output_samples) //, int* scratch_buffer, float* scratch_buffer_float) { unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; @@ -257,57 +267,62 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_neon(lv_16sc_t* result, lv_16sc_t* _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; float32x4_t _rem_code_phase, _code_phase_step_chips; int32x4_t _code_length_chips, _code_length_chips_minus1; float32x4_t _code_phase_out, _code_phase_out_with_offset; rem_code_phase_chips = rem_code_phase_chips - 0.5f; float32x4_t sign, PlusHalf, Round; - _rem_code_phase = vld1q_dup_f32(&rem_code_phase_chips); //load float to all four float values in m128 register - _code_phase_step_chips = vld1q_dup_f32(&code_phase_step_chips); //load float to all four float values in m128 register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; + _rem_code_phase = vld1q_dup_f32(&rem_code_phase_chips); //load float to all four float values in m128 register + _code_phase_step_chips = vld1q_dup_f32(&code_phase_step_chips); //load float to all four float values in m128 register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; four_times_code_length_chips_minus1[0] = code_length_chips - 1; four_times_code_length_chips_minus1[1] = code_length_chips - 1; four_times_code_length_chips_minus1[2] = code_length_chips - 1; four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = vld1q_s32((int32_t*)&four_times_code_length_chips); //load float to all four float values in m128 register - _code_length_chips_minus1 = vld1q_s32((int32_t*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register + _code_length_chips = vld1q_s32((int32_t*)&four_times_code_length_chips); //load float to all four float values in m128 register + _code_length_chips_minus1 = vld1q_s32((int32_t*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register - int32x4_t _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; + int32x4_t _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; uint32x4_t negative_indexes, overflow_indexes; int32x4_t zero = vmovq_n_s32(0); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; float32x4_t _4output_index = vld1q_f32(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; float32x4_t _4constant_float = vld1q_f32(init_4constant_float); - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { - _code_phase_out = vmulq_f32(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - _code_phase_out_with_offset = vaddq_f32(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out = vmulq_f32(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out_with_offset = vaddq_f32(_code_phase_out, _rem_code_phase); //add the phase offset sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(_code_phase_out_with_offset), 31))); PlusHalf = vaddq_f32(_code_phase_out_with_offset, half); Round = vsubq_f32(PlusHalf, sign); _code_phase_out_int = vcvtq_s32_f32(Round); - negative_indexes = vcltq_s32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = vaddq_s32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = veorq_s32(_code_phase_out_int, vandq_s32( (int32x4_t)negative_indexes, veorq_s32( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = vcltq_s32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = vaddq_s32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = veorq_s32(_code_phase_out_int, vandq_s32((int32x4_t)negative_indexes, veorq_s32(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = vcgtq_s32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = vsubq_s32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = veorq_s32(_code_phase_out_int_neg, vandq_s32( (int32x4_t)overflow_indexes, veorq_s32( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = vcgtq_s32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = vsubq_s32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = veorq_s32(_code_phase_out_int_neg, vandq_s32((int32x4_t)overflow_indexes, veorq_s32(_code_phase_out_int_over, _code_phase_out_int_neg))); - vst1q_s32((int32_t*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + vst1q_s32((int32_t*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible *_result++ = local_code[local_code_chip_index[0]]; @@ -318,7 +333,7 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_neon(lv_16sc_t* result, _4output_index = vaddq_f32(_4output_index, _4constant_float); } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)number + rem_code_phase_chips + 0.5f); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; @@ -327,6 +342,6 @@ static inline void volk_gnsssdr_16ic_resampler_fast_16ic_neon(lv_16sc_t* result, } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_16ic_resampler_fast_16ic_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastpuppet_16ic.h index 0b67ce73c..697bb3b34 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -44,7 +44,7 @@ static inline void volk_gnsssdr_16ic_resamplerfastpuppet_16ic_generic(lv_16sc_t* float rem_code_phase_chips = -0.123; float code_phase_step_chips = 0.1; int code_length_chips = 1023; - volk_gnsssdr_16ic_resampler_fast_16ic_generic(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points); + volk_gnsssdr_16ic_resampler_fast_16ic_generic(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points); } #endif /* LV_HAVE_GENERIC */ @@ -55,7 +55,7 @@ static inline void volk_gnsssdr_16ic_resamplerfastpuppet_16ic_a_sse2(lv_16sc_t* float rem_code_phase_chips = -0.123; float code_phase_step_chips = 0.1; int code_length_chips = 1023; - volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points ); + volk_gnsssdr_16ic_resampler_fast_16ic_a_sse2(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points); } #endif /* LV_HAVE_SSE2 */ @@ -67,21 +67,21 @@ static inline void volk_gnsssdr_16ic_resamplerfastpuppet_16ic_u_sse2(lv_16sc_t* float rem_code_phase_chips = -0.123; float code_phase_step_chips = 0.1; int code_length_chips = 1023; - volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points ); + volk_gnsssdr_16ic_resampler_fast_16ic_u_sse2(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points); } #endif /* LV_HAVE_SSE2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_resamplerfastpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { float rem_code_phase_chips = -0.123; float code_phase_step_chips = 0.1; int code_length_chips = 1023; - volk_gnsssdr_16ic_resampler_fast_16ic_neon(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points ); + volk_gnsssdr_16ic_resampler_fast_16ic_neon(result, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_points); } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#endif // INCLUDED_volk_gnsssdr_16ic_resamplerfastpuppet_16ic_H +#endif // INCLUDED_volk_gnsssdr_16ic_resamplerfastpuppet_16ic_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic.h index bc4c2faa8..c6e535a42 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,9 +36,9 @@ #define INCLUDED_volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic_H #include "volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn.h" -#include -#include #include +#include +#include #include #ifdef LV_HAVE_GENERIC @@ -47,23 +47,23 @@ static inline void volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic_generic(lv_16sc_ float code_phase_step_chips = 0.1; int code_length_chips = 2046; int num_out_vectors = 3; - unsigned int n; + int n; float* rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - rem_code_phase_chips[n] = -0.234; - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + rem_code_phase_chips[n] = -0.234; + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); volk_gnsssdr_free(rem_code_phase_chips); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -76,23 +76,23 @@ static inline void volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic_a_sse2(lv_16sc_t float code_phase_step_chips = 0.1; int code_length_chips = 2046; int num_out_vectors = 3; - unsigned int n; - float * rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float* rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - rem_code_phase_chips[n] = -0.234; - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + rem_code_phase_chips[n] = -0.234; + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_a_sse2(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_out_vectors, num_points); memcpy(result, result_aux[0], sizeof(lv_16sc_t) * num_points); volk_gnsssdr_free(rem_code_phase_chips); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -105,56 +105,56 @@ static inline void volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic_u_sse2(lv_16sc_t float code_phase_step_chips = 0.1; int code_length_chips = 2046; int num_out_vectors = 3; - unsigned int n; - float * rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float* rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - rem_code_phase_chips[n] = -0.234; - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + rem_code_phase_chips[n] = -0.234; + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_u_sse2(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_out_vectors, num_points); memcpy(result, result_aux[0], sizeof(lv_16sc_t) * num_points); volk_gnsssdr_free(rem_code_phase_chips); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { float code_phase_step_chips = 0.1; int code_length_chips = 2046; int num_out_vectors = 3; - unsigned int n; - float * rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float* rem_code_phase_chips = (float*)volk_gnsssdr_malloc(sizeof(float) * num_out_vectors, volk_gnsssdr_get_alignment()); + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - rem_code_phase_chips[n] = -0.234; - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + rem_code_phase_chips[n] = -0.234; + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_length_chips, num_out_vectors, num_points); memcpy(result, result_aux[0], sizeof(lv_16sc_t) * num_points); volk_gnsssdr_free(rem_code_phase_chips); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#endif // INCLUDED_volk_gnsssdr_16ic_resamplerpuppet_16ic_H +#endif // INCLUDED_volk_gnsssdr_16ic_resamplerpuppet_16ic_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerxnpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerxnpuppet_16ic.h index 106ad85b7..ffac7fece 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerxnpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_resamplerxnpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,65 +36,65 @@ #define INCLUDED_volk_gnsssdr_16ic_resamplerxnpuppet_16ic_H #include "volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_16ic_xn.h" -#include -#include #include +#include +#include #include #ifdef LV_HAVE_GENERIC static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_generic(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; - unsigned int n; + int n; float rem_code_phase_chips = -0.234; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif /* LV_HAVE_GENERIC */ - + #ifdef LV_HAVE_SSE3 static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_a_sse3(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -103,27 +103,27 @@ static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_a_sse3(lv_16sc_t* re #ifdef LV_HAVE_SSE3 static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_sse3(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -133,27 +133,27 @@ static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_sse3(lv_16sc_t* re #ifdef LV_HAVE_SSE4_1 static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_sse4_1(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -163,27 +163,27 @@ static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_sse4_1(lv_16sc_t* #ifdef LV_HAVE_SSE4_1 static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_a_sse4_1(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -193,27 +193,27 @@ static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_a_sse4_1(lv_16sc_t* #ifdef LV_HAVE_AVX static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_avx(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -223,60 +223,60 @@ static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_u_avx(lv_16sc_t* res #ifdef LV_HAVE_AVX static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_a_avx(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_resamplerxnpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; - lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + lv_16sc_t** result_aux = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - } + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_16sc_t*)result, (lv_16sc_t*)result_aux[0], sizeof(lv_16sc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#endif // INCLUDED_volk_gnsssdr_16ic_resamplerpuppet_16ic_H +#endif // INCLUDED_volk_gnsssdr_16ic_resamplerpuppet_16ic_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_rotatorpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_rotatorpuppet_16ic.h index 245eed773..757e213d2 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_rotatorpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_rotatorpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,8 +36,8 @@ #define INCLUDED_volk_gnsssdr_16ic_rotatorpuppet_16ic_H -#include #include "volk_gnsssdr/volk_gnsssdr_16ic_s32fc_x2_rotator_16ic.h" +#include #include @@ -137,7 +137,7 @@ static inline void volk_gnsssdr_16ic_rotatorpuppet_16ic_u_sse3_reload(lv_16sc_t* #endif /* LV_HAVE_SSE3 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_rotatorpuppet_16ic_neon(lv_16sc_t* outVector, const lv_16sc_t* inVector, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! @@ -150,10 +150,10 @@ static inline void volk_gnsssdr_16ic_rotatorpuppet_16ic_neon(lv_16sc_t* outVecto volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(outVector, inVector, phase_inc[0], phase, num_points); } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_rotatorpuppet_16ic_neon_reload(lv_16sc_t* outVector, const lv_16sc_t* inVector, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! @@ -166,7 +166,7 @@ static inline void volk_gnsssdr_16ic_rotatorpuppet_16ic_neon_reload(lv_16sc_t* o volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(outVector, inVector, phase_inc[0], phase, num_points); } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_16ic_rotatorpuppet_16ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_s32fc_x2_rotator_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_s32fc_x2_rotator_16ic.h index d971fa04e..0caba5e9b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_s32fc_x2_rotator_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_s32fc_x2_rotator_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -61,7 +61,6 @@ #include #include -//#include #ifdef LV_HAVE_GENERIC @@ -71,7 +70,7 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_generic(lv_16sc_t* ou unsigned int i = 0; lv_16sc_t tmp16; lv_32fc_t tmp32; - for(i = 0; i < (unsigned int)(num_points); ++i) + for (i = 0; i < (unsigned int)(num_points); ++i) { tmp16 = *inVector++; tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -112,8 +111,8 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_generic_reload(lv_16s *outVector++ = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); (*phase) *= phase_inc; } - // Regenerate phase - //printf("Phase before regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); + // Regenerate phase + //printf("Phase before regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); #ifdef __cplusplus (*phase) /= std::abs((*phase)); #else @@ -142,11 +141,13 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3(lv_16sc_t* out unsigned int number; __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; __m128i c1, c2, result; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -158,49 +159,49 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3(lv_16sc_t* out lv_16sc_t tmp16; lv_32fc_t tmp32; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _mm_store_si128((__m128i*)_out, result); // Regenerate phase @@ -233,7 +234,6 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3(lv_16sc_t* out #endif /* LV_HAVE_SSE3 */ - #ifdef LV_HAVE_SSE3 #include @@ -245,11 +245,13 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3_reload(lv_16sc unsigned int j; __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; __m128i c1, c2, result; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -266,47 +268,47 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3_reload(lv_16sc { for (j = 0; j < ROTATOR_RELOAD; j++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _mm_store_si128((__m128i*)_out, result); //next two samples @@ -323,47 +325,47 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3_reload(lv_16sc for (j = 0; j < sse_iters % ROTATOR_RELOAD; j++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _mm_store_si128((__m128i*)_out, result); //next two samples @@ -386,7 +388,6 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_a_sse3_reload(lv_16sc #endif /* LV_HAVE_SSE3 */ - #ifdef LV_HAVE_SSE3 #include @@ -396,14 +397,16 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_u_sse3(lv_16sc_t* out unsigned int number; __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; __m128i c1, c2, result; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; - two_phase_acc_reg = _mm_load_ps((float*) two_phase_acc); + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); const lv_16sc_t* _in = inVector; @@ -413,49 +416,49 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_u_sse3(lv_16sc_t* out lv_16sc_t tmp16; lv_32fc_t tmp32; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _mm_storeu_si128((__m128i*)_out, result); // Regenerate phase @@ -494,153 +497,155 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_u_sse3(lv_16sc_t* out static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_u_sse3_reload(lv_16sc_t* outVector, const lv_16sc_t* inVector, const lv_32fc_t phase_inc, lv_32fc_t* phase, unsigned int num_points) { const unsigned int sse_iters = num_points / 4; - unsigned int ROTATOR_RELOAD = 512; - unsigned int n; - unsigned int j; - __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; - __m128i c1, c2, result; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; - two_phase_inc[0] = phase_inc * phase_inc; - two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; - two_phase_acc[0] = (*phase); - two_phase_acc[1] = (*phase) * phase_inc; - two_phase_acc_reg = _mm_load_ps((float*) two_phase_acc); + unsigned int ROTATOR_RELOAD = 512; + unsigned int n; + unsigned int j; + __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; + __m128i c1, c2, result; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; + two_phase_inc[0] = phase_inc * phase_inc; + two_phase_inc[1] = phase_inc * phase_inc; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; + two_phase_acc[0] = (*phase); + two_phase_acc[1] = (*phase) * phase_inc; + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); - const lv_16sc_t* _in = inVector; + const lv_16sc_t* _in = inVector; - lv_16sc_t* _out = outVector; + lv_16sc_t* _out = outVector; - __m128 yl, yh, tmp1, tmp2, tmp3; - lv_16sc_t tmp16; - lv_32fc_t tmp32; + __m128 yl, yh, tmp1, tmp2, tmp3; + lv_16sc_t tmp16; + lv_32fc_t tmp32; - for (n = 0; n < sse_iters / ROTATOR_RELOAD; n++) - { - for (j = 0; j < ROTATOR_RELOAD; j++) - { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg - //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + for (n = 0; n < sse_iters / ROTATOR_RELOAD; n++) + { + for (j = 0; j < ROTATOR_RELOAD; j++) + { + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic - //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - //next two samples - _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg - __VOLK_GNSSSDR_PREFETCH(_in + 8); - //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + //next two samples + _in += 2; + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + __VOLK_GNSSSDR_PREFETCH(_in + 8); + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic - //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic - _mm_storeu_si128((__m128i*)_out, result); + // store four output samples + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic + _mm_storeu_si128((__m128i*)_out, result); - //next two samples - _in += 2; - _out += 4; - } - // Regenerate phase - tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); - tmp2 = _mm_hadd_ps(tmp1, tmp1); - tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); - tmp2 = _mm_sqrt_ps(tmp1); - two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); - } + //next two samples + _in += 2; + _out += 4; + } + // Regenerate phase + tmp1 = _mm_mul_ps(two_phase_acc_reg, two_phase_acc_reg); + tmp2 = _mm_hadd_ps(tmp1, tmp1); + tmp1 = _mm_shuffle_ps(tmp2, tmp2, 0xD8); + tmp2 = _mm_sqrt_ps(tmp1); + two_phase_acc_reg = _mm_div_ps(two_phase_acc_reg, tmp2); + } - for (j = 0; j < sse_iters % ROTATOR_RELOAD; j++) - { - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg - //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + for (j = 0; j < sse_iters % ROTATOR_RELOAD; j++) + { + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic - //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - //next two samples - _in += 2; - a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg - __VOLK_GNSSSDR_PREFETCH(_in + 8); - //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + //next two samples + _in += 2; + a = _mm_set_ps((float)(lv_cimag(_in[1])), (float)(lv_creal(_in[1])), (float)(lv_cimag(_in[0])), (float)(lv_creal(_in[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + __VOLK_GNSSSDR_PREFETCH(_in + 8); + //complex 32fc multiplication b=a*two_phase_acc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic - //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - // store four output samples - result = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic - _mm_storeu_si128((__m128i*)_out, result); + // store four output samples + result = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic + _mm_storeu_si128((__m128i*)_out, result); - //next two samples - _in += 2; - _out += 4; - } + //next two samples + _in += 2; + _out += 4; + } - _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); - (*phase) = two_phase_acc[0]; + _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); + (*phase) = two_phase_acc[0]; - for (n = sse_iters * 4; n < num_points; ++n) - { - tmp16 = *_in++; - tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); - *_out++ = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); - (*phase) *= phase_inc; - } + for (n = sse_iters * 4; n < num_points; ++n) + { + tmp16 = *_in++; + tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); + *_out++ = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); + (*phase) *= phase_inc; + } } #endif /* LV_HAVE_SSE3 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVector, const lv_16sc_t* inVector, const lv_32fc_t phase_inc, lv_32fc_t* phase, unsigned int num_points) @@ -658,8 +663,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe lv_16sc_t* _out = outVector; lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); @@ -668,8 +675,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); @@ -682,7 +691,7 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe if (neon_iters > 0) { - for(; i < neon_iters; ++i) + for (; i < neon_iters; ++i) { /* load 4 complex numbers (int 16 bits each component) */ tmp16 = vld2_s16((int16_t*)_in); @@ -746,8 +755,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -758,7 +769,7 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe (*phase) = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); } - for(i = 0; i < neon_iters % 4; ++i) + for (i = 0; i < neon_iters % 4; ++i) { tmp16_ = *_in++; tmp32_ = lv_cmake((float32_t)lv_creal(tmp16_), (float32_t)lv_cimag(tmp16_)) * (*phase); @@ -767,10 +778,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon(lv_16sc_t* outVe } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t* outVector, const lv_16sc_t* inVector, const lv_32fc_t phase_inc, lv_32fc_t* phase, unsigned int num_points) @@ -792,8 +803,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t lv_16sc_t* _out = outVector; lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); @@ -802,8 +815,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); @@ -880,8 +895,10 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -946,7 +963,7 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t (*phase) = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); } - for(i = 0; i < neon_iters % 4; ++i) + for (i = 0; i < neon_iters % 4; ++i) { tmp16_ = *_in++; tmp32_ = lv_cmake((float32_t)lv_creal(tmp16_), (float32_t)lv_cimag(tmp16_)) * (*phase); @@ -955,6 +972,6 @@ static inline void volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_neon_reload(lv_16sc_t } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_16ic_s32fc_x2_rotator_16ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic.h index fa19ee50e..6d65f80f3 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -59,9 +59,9 @@ #ifndef INCLUDED_volk_gnsssdr_16ic_x2_dot_prod_16ic_H #define INCLUDED_volk_gnsssdr_16ic_x2_dot_prod_16ic_H +#include #include #include -#include #ifdef LV_HAVE_GENERIC @@ -73,7 +73,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_generic(lv_16sc_t* result, for (n = 0; n < num_points; n++) { lv_16sc_t tmp = in_a[n] * in_b[n]; - result[0] = lv_cmake(sat_adds16i(lv_creal(result[0]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[0]), lv_cimag(tmp) )); + result[0] = lv_cmake(sat_adds16i(lv_creal(result[0]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[0]), lv_cimag(tmp))); } } @@ -96,33 +96,34 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_sse2(lv_16sc_t* out, con if (sse_iters > 0) { __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, realcacc, imagcacc; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { // a[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - a = _mm_load_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_a + 8); b = _mm_load_si128((__m128i*)_in_b); __VOLK_GNSSSDR_PREFETCH(_in_b + 8); - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... - imag = _mm_adds_epi16(imag1, imag2); //with saturation arithmetic! + imag = _mm_adds_epi16(imag1, imag2); //with saturation arithmetic! realcacc = _mm_adds_epi16(realcacc, real); imagcacc = _mm_adds_epi16(imagcacc, imag); @@ -136,7 +137,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_sse2(lv_16sc_t* out, con a = _mm_or_si128(realcacc, imagcacc); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector for (number = 0; number < 4; ++number) { @@ -174,35 +175,36 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_sse2(lv_16sc_t* out, con if (sse_iters > 0) { __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, realcacc, imagcacc, result; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { //std::complex memory structure: real part -> reinterpret_cast(a)[2*i] - //imaginery part -> reinterpret_cast(a)[2*i + 1] + //imaginary part -> reinterpret_cast(a)[2*i + 1] // a[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - a = _mm_loadu_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_loadu_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_a + 8); b = _mm_loadu_si128((__m128i*)_in_b); __VOLK_GNSSSDR_PREFETCH(_in_b + 8); - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... - imag = _mm_adds_epi16(imag1, imag2); //with saturation arithmetic! + imag = _mm_adds_epi16(imag1, imag2); //with saturation arithmetic! realcacc = _mm_adds_epi16(realcacc, real); imagcacc = _mm_adds_epi16(imagcacc, imag); @@ -216,7 +218,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_sse2(lv_16sc_t* out, con result = _mm_or_si128(realcacc, imagcacc); - _mm_storeu_si128((__m128i*)dotProductVector, result); // Store the results back into the dot product vector + _mm_storeu_si128((__m128i*)dotProductVector, result); // Store the results back into the dot product vector for (i = 0; i < 4; ++i) { @@ -253,15 +255,16 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_axv2(lv_16sc_t* out, con if (avx_iters > 0) { __m256i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, realcacc, imagcacc, result; - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; realcacc = _mm256_setzero_si256(); imagcacc = _mm256_setzero_si256(); - mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(number = 0; number < avx_iters; number++) + for (number = 0; number < avx_iters; number++) { a = _mm256_loadu_si256((__m256i*)_in_a); __VOLK_GNSSSDR_PREFETCH(_in_a + 16); @@ -269,7 +272,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_axv2(lv_16sc_t* out, con __VOLK_GNSSSDR_PREFETCH(_in_b + 16); c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); b_sl = _mm256_slli_si256(b, 2); @@ -278,7 +281,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_axv2(lv_16sc_t* out, con imag1 = _mm256_mullo_epi16(a, b_sl); imag2 = _mm256_mullo_epi16(b, a_sl); - imag = _mm256_adds_epi16(imag1, imag2); //with saturation arithmetic! + imag = _mm256_adds_epi16(imag1, imag2); //with saturation arithmetic! realcacc = _mm256_adds_epi16(realcacc, real); imagcacc = _mm256_adds_epi16(imagcacc, imag); @@ -292,7 +295,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_u_axv2(lv_16sc_t* out, con result = _mm256_or_si256(realcacc, imagcacc); - _mm256_storeu_si256((__m256i*)dotProductVector, result); // Store the results back into the dot product vector + _mm256_storeu_si256((__m256i*)dotProductVector, result); // Store the results back into the dot product vector _mm256_zeroupper(); for (i = 0; i < 8; ++i) @@ -330,15 +333,16 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_axv2(lv_16sc_t* out, con if (avx_iters > 0) { __m256i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, realcacc, imagcacc, result; - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; realcacc = _mm256_setzero_si256(); imagcacc = _mm256_setzero_si256(); - mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(number = 0; number < avx_iters; number++) + for (number = 0; number < avx_iters; number++) { a = _mm256_load_si256((__m256i*)_in_a); __VOLK_GNSSSDR_PREFETCH(_in_a + 16); @@ -346,7 +350,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_axv2(lv_16sc_t* out, con __VOLK_GNSSSDR_PREFETCH(_in_b + 16); c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); b_sl = _mm256_slli_si256(b, 2); @@ -355,7 +359,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_axv2(lv_16sc_t* out, con imag1 = _mm256_mullo_epi16(a, b_sl); imag2 = _mm256_mullo_epi16(b, a_sl); - imag = _mm256_adds_epi16(imag1, imag2); //with saturation arithmetic! + imag = _mm256_adds_epi16(imag1, imag2); //with saturation arithmetic! realcacc = _mm256_adds_epi16(realcacc, real); imagcacc = _mm256_adds_epi16(imagcacc, imag); @@ -369,7 +373,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_axv2(lv_16sc_t* out, con result = _mm256_or_si256(realcacc, imagcacc); - _mm256_store_si256((__m256i*)dotProductVector, result); // Store the results back into the dot product vector + _mm256_store_si256((__m256i*)dotProductVector, result); // Store the results back into the dot product vector _mm256_zeroupper(); for (i = 0; i < 8; ++i) @@ -389,7 +393,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_a_axv2(lv_16sc_t* out, con #endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon(lv_16sc_t* out, const lv_16sc_t* in_a, const lv_16sc_t* in_b, unsigned int num_points) @@ -397,8 +401,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon(lv_16sc_t* out, const unsigned int quarter_points = num_points / 4; unsigned int number; - lv_16sc_t* a_ptr = (lv_16sc_t*) in_a; - lv_16sc_t* b_ptr = (lv_16sc_t*) in_b; + lv_16sc_t* a_ptr = (lv_16sc_t*)in_a; + lv_16sc_t* b_ptr = (lv_16sc_t*)in_b; *out = lv_cmake((int16_t)0, (int16_t)0); if (quarter_points > 0) @@ -407,15 +411,16 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon(lv_16sc_t* out, const // 2nd lane holds the imaginary part int16x4x2_t a_val, b_val, c_val, accumulator; int16x4x2_t tmp_real, tmp_imag; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t accum_result[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t accum_result[4]; accumulator.val[0] = vdup_n_s16(0); accumulator.val[1] = vdup_n_s16(0); lv_16sc_t dotProduct = lv_cmake((int16_t)0, (int16_t)0); - for(number = 0; number < quarter_points; ++number) + for (number = 0; number < quarter_points; ++number) { - a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i - b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i + a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i + b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i __VOLK_GNSSSDR_PREFETCH(a_ptr + 8); __VOLK_GNSSSDR_PREFETCH(b_ptr + 8); @@ -451,16 +456,16 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon(lv_16sc_t* out, const } // tail case - for(number = quarter_points * 4; number < num_points; ++number) + for (number = quarter_points * 4; number < num_points; ++number) { *out += (*a_ptr++) * (*b_ptr++); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_vma(lv_16sc_t* out, const lv_16sc_t* in_a, const lv_16sc_t* in_b, unsigned int num_points) @@ -468,20 +473,21 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_vma(lv_16sc_t* out, c unsigned int quarter_points = num_points / 4; unsigned int number; - lv_16sc_t* a_ptr = (lv_16sc_t*) in_a; - lv_16sc_t* b_ptr = (lv_16sc_t*) in_b; + lv_16sc_t* a_ptr = (lv_16sc_t*)in_a; + lv_16sc_t* b_ptr = (lv_16sc_t*)in_b; // for 2-lane vectors, 1st lane holds the real part, // 2nd lane holds the imaginary part int16x4x2_t a_val, b_val, accumulator; int16x4x2_t tmp; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t accum_result[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t accum_result[4]; accumulator.val[0] = vdup_n_s16(0); accumulator.val[1] = vdup_n_s16(0); - for(number = 0; number < quarter_points; ++number) + for (number = 0; number < quarter_points; ++number) { - a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i - b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i + a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i + b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i __VOLK_GNSSSDR_PREFETCH(a_ptr + 8); __VOLK_GNSSSDR_PREFETCH(b_ptr + 8); @@ -503,16 +509,16 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_vma(lv_16sc_t* out, c *out = accum_result[0] + accum_result[1] + accum_result[2] + accum_result[3]; // tail case - for(number = quarter_points * 4; number < num_points; ++number) + for (number = quarter_points * 4; number < num_points; ++number) { *out += (*a_ptr++) * (*b_ptr++); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_optvma(lv_16sc_t* out, const lv_16sc_t* in_a, const lv_16sc_t* in_b, unsigned int num_points) @@ -520,22 +526,23 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_optvma(lv_16sc_t* out unsigned int quarter_points = num_points / 4; unsigned int number; - lv_16sc_t* a_ptr = (lv_16sc_t*) in_a; - lv_16sc_t* b_ptr = (lv_16sc_t*) in_b; + lv_16sc_t* a_ptr = (lv_16sc_t*)in_a; + lv_16sc_t* b_ptr = (lv_16sc_t*)in_b; // for 2-lane vectors, 1st lane holds the real part, // 2nd lane holds the imaginary part int16x4x2_t a_val, b_val, accumulator1, accumulator2; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t accum_result[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t accum_result[4]; accumulator1.val[0] = vdup_n_s16(0); accumulator1.val[1] = vdup_n_s16(0); accumulator2.val[0] = vdup_n_s16(0); accumulator2.val[1] = vdup_n_s16(0); - for(number = 0; number < quarter_points; ++number) + for (number = 0; number < quarter_points; ++number) { - a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i - b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i + a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i + b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i __VOLK_GNSSSDR_PREFETCH(a_ptr + 8); __VOLK_GNSSSDR_PREFETCH(b_ptr + 8); @@ -556,12 +563,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_neon_optvma(lv_16sc_t* out *out = accum_result[0] + accum_result[1] + accum_result[2] + accum_result[3]; // tail case - for(number = quarter_points * 4; number < num_points; ++number) + for (number = quarter_points * 4; number < num_points; ++number) { *out += (*a_ptr++) * (*b_ptr++); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_16ic_x2_dot_prod_16ic_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic_xn.h index 4f53594a8..9d370fb19 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic_xn.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -61,10 +61,10 @@ #define INCLUDED_volk_gnsssdr_16ic_xn_dot_prod_16ic_xn_H +#include +#include #include #include -#include -#include #ifdef LV_HAVE_GENERIC @@ -74,7 +74,7 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic(lv_16sc_t* resu unsigned int n; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); for (n = 0; n < num_points; n++) { //r*a.r - i*a.i, i*a.r + r*a.i @@ -96,11 +96,11 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic_sat(lv_16sc_t* unsigned int n; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); for (n = 0; n < num_points; n++) { - lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(in_common[n]), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(in_common[n]), lv_cimag(in_a[n_vec][n]))), - sat_adds16i(sat_muls16i(lv_creal(in_common[n]), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(in_common[n]), lv_creal(in_a[n_vec][n])))); + lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(in_common[n]), lv_creal(in_a[n_vec][n])), -sat_muls16i(lv_cimag(in_common[n]), lv_cimag(in_a[n_vec][n]))), + sat_adds16i(sat_muls16i(lv_creal(in_common[n]), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(in_common[n]), lv_creal(in_a[n_vec][n])))); result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); } } @@ -112,9 +112,9 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic_sat(lv_16sc_t* #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); int n_vec; unsigned int index; const unsigned int sse_iters = num_points / 4; @@ -125,7 +125,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* resul if (sse_iters > 0) { - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; __m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); __m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); @@ -138,28 +139,28 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* resul __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(index = 0; index < sse_iters; index++) + for (index = 0; index < sse_iters; index++) { // b[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - b = _mm_load_si128((__m128i*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + b = _mm_load_si128((__m128i*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_load_si128((__m128i*)&(_in_a[n_vec][index*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)&(_in_a[n_vec][index * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - c_sr = _mm_slli_si128(b, 2); // b3.r, b2.i .... - c = _mm_mullo_epi16(a, c_sr); // a3.i*b3.r, .... + c_sr = _mm_slli_si128(b, 2); // b3.r, b2.i .... + c = _mm_mullo_epi16(a, c_sr); // a3.i*b3.r, .... - c_sr = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag = _mm_mullo_epi16(b, c_sr); // b3.i*a3.r, .... + c_sr = _mm_slli_si128(a, 2); // a3.r, a2.i .... + imag = _mm_mullo_epi16(b, c_sr); // b3.i*a3.r, .... imag = _mm_adds_epi16(c, imag); @@ -176,12 +177,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* resul a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 4; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -191,12 +192,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* resul for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = sse_iters * 4; index < num_points; index++) + for (index = sse_iters * 4; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -206,9 +207,9 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(lv_16sc_t* resul #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); int n_vec; unsigned int index; const unsigned int sse_iters = num_points / 4; @@ -219,7 +220,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* resul if (sse_iters > 0) { - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; __m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); __m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); @@ -232,28 +234,28 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* resul __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(index = 0; index < sse_iters; index++) + for (index = 0; index < sse_iters; index++) { // b[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - b = _mm_loadu_si128((__m128i*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + b = _mm_loadu_si128((__m128i*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_loadu_si128((__m128i*)&(_in_a[n_vec][index*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_loadu_si128((__m128i*)&(_in_a[n_vec][index * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - c_sr = _mm_slli_si128(b, 2); // b3.r, b2.i .... - c = _mm_mullo_epi16(a, c_sr); // a3.i*b3.r, .... + c_sr = _mm_slli_si128(b, 2); // b3.r, b2.i .... + c = _mm_mullo_epi16(a, c_sr); // a3.i*b3.r, .... - c_sr = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag = _mm_mullo_epi16(b, c_sr); // b3.i*a3.r, .... + c_sr = _mm_slli_si128(a, 2); // a3.r, a2.i .... + imag = _mm_mullo_epi16(b, c_sr); // b3.i*a3.r, .... imag = _mm_adds_epi16(c, imag); @@ -270,12 +272,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* resul a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 4; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -285,12 +287,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* resul for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = sse_iters * 4; index < num_points; index++) + for (index = sse_iters * 4; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -300,9 +302,9 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(lv_16sc_t* resul #ifdef LV_HAVE_AVX2 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); int n_vec; unsigned int index; const unsigned int sse_iters = num_points / 8; @@ -313,7 +315,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* resul if (sse_iters > 0) { - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; __m256i* realcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); __m256i* imagcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); @@ -326,27 +329,27 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* resul __m256i a, b, c, c_sr, mask_imag, mask_real, real, imag; - mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(index = 0; index < sse_iters; index++) + for (index = 0; index < sse_iters; index++) { b = _mm256_load_si256((__m256i*)_in_common); __VOLK_GNSSSDR_PREFETCH(_in_common + 16); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm256_load_si256((__m256i*)&(_in_a[n_vec][index*8])); + a = _mm256_load_si256((__m256i*)&(_in_a[n_vec][index * 8])); c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); - c_sr = _mm256_slli_si256(b, 2); // b3.r, b2.i .... - c = _mm256_mullo_epi16(a, c_sr); // a3.i*b3.r, .... + c_sr = _mm256_slli_si256(b, 2); // b3.r, b2.i .... + c = _mm256_mullo_epi16(a, c_sr); // a3.i*b3.r, .... - c_sr = _mm256_slli_si256(a, 2); // a3.r, a2.i .... - imag = _mm256_mullo_epi16(b, c_sr); // b3.i*a3.r, .... + c_sr = _mm256_slli_si256(a, 2); // a3.r, a2.i .... + imag = _mm256_mullo_epi16(b, c_sr); // b3.i*a3.r, .... imag = _mm256_adds_epi16(c, imag); @@ -363,12 +366,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* resul a = _mm256_or_si256(realcacc[n_vec], imagcacc[n_vec]); - _mm256_store_si256((__m256i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_si256((__m256i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 8; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -379,12 +382,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* resul for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = sse_iters * 8; index < num_points; index++) + for (index = sse_iters * 8; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -394,9 +397,9 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(lv_16sc_t* resul #ifdef LV_HAVE_AVX2 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int sse_iters = num_points / 8; int n_vec; @@ -407,7 +410,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* resul if (sse_iters > 0) { - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; __m256i* realcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); __m256i* imagcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); @@ -420,27 +424,27 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* resul __m256i a, b, c, c_sr, mask_imag, mask_real, real, imag; - mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(index = 0; index < sse_iters; index++) + for (index = 0; index < sse_iters; index++) { b = _mm256_loadu_si256((__m256i*)_in_common); __VOLK_GNSSSDR_PREFETCH(_in_common + 16); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm256_loadu_si256((__m256i*)&(_in_a[n_vec][index*8])); + a = _mm256_loadu_si256((__m256i*)&(_in_a[n_vec][index * 8])); c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); - c_sr = _mm256_slli_si256(b, 2); // b3.r, b2.i .... - c = _mm256_mullo_epi16(a, c_sr); // a3.i*b3.r, .... + c_sr = _mm256_slli_si256(b, 2); // b3.r, b2.i .... + c = _mm256_mullo_epi16(a, c_sr); // a3.i*b3.r, .... - c_sr = _mm256_slli_si256(a, 2); // a3.r, a2.i .... - imag = _mm256_mullo_epi16(b, c_sr); // b3.i*a3.r, .... + c_sr = _mm256_slli_si256(a, 2); // a3.r, a2.i .... + imag = _mm256_mullo_epi16(b, c_sr); // b3.i*a3.r, .... imag = _mm256_adds_epi16(c, imag); @@ -457,12 +461,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* resul a = _mm256_or_si256(realcacc[n_vec], imagcacc[n_vec]); - _mm256_store_si256((__m256i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_si256((__m256i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 8; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -473,24 +477,24 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(lv_16sc_t* resul for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = sse_iters * 8; index < num_points; index++) + for (index = sse_iters * 8; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } #endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); int n_vec; unsigned int index; const unsigned int neon_iters = num_points / 4; @@ -501,7 +505,8 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, if (neon_iters > 0) { - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; int16x4x2_t a_val, b_val, c_val; @@ -509,19 +514,19 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, int16x4x2_t tmp_real, tmp_imag; - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator[n_vec].val[0] = vdup_n_s16(0); accumulator[n_vec].val[1] = vdup_n_s16(0); } - for(index = 0; index < neon_iters; index++) + for (index = 0; index < neon_iters; index++) { - b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg //__VOLK_GNSSSDR_PREFETCH(&_in_a[n_vec][index*4] + 8); // multiply the real*real and imag*imag to get real result @@ -547,12 +552,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 4; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -561,24 +566,24 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(lv_16sc_t* result, for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = neon_iters * 4; index < num_points; index++) + for (index = neon_iters * 4; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int neon_iters = num_points / 4; int n_vec; @@ -589,25 +594,26 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(lv_16sc_t* res if (neon_iters > 0) { - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; int16x4x2_t a_val, b_val, tmp; int16x4x2_t* accumulator = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator[n_vec].val[0] = vdup_n_s16(0); accumulator[n_vec].val[1] = vdup_n_s16(0); } - for(index = 0; index < neon_iters; index++) + for (index = 0; index < neon_iters; index++) { - b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index*4])); + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index * 4])); tmp.val[0] = vmul_s16(a_val.val[0], b_val.val[0]); tmp.val[1] = vmul_s16(a_val.val[1], b_val.val[0]); @@ -624,12 +630,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(lv_16sc_t* res for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 4; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -638,24 +644,24 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(lv_16sc_t* res for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = neon_iters * 4; index < num_points; index++) + for (index = neon_iters * 4; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int neon_iters = num_points / 4; int n_vec; @@ -666,14 +672,15 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* if (neon_iters > 0) { - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; int16x4x2_t a_val, b_val; int16x4x2_t* accumulator1 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); int16x4x2_t* accumulator2 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator1[n_vec].val[0] = vdup_n_s16(0); accumulator1[n_vec].val[1] = vdup_n_s16(0); @@ -681,13 +688,13 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* accumulator2[n_vec].val[1] = vdup_n_s16(0); } - for(index = 0; index < neon_iters; index++) + for (index = 0; index < neon_iters; index++) { - b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + b_val = vld2_s16((int16_t*)_in_common); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index*4])); + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][index * 4])); accumulator1[n_vec].val[0] = vmla_s16(accumulator1[n_vec].val[0], a_val.val[0], b_val.val[0]); accumulator1[n_vec].val[1] = vmla_s16(accumulator1[n_vec].val[1], a_val.val[0], b_val.val[1]); @@ -705,12 +712,12 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (index = 0; index < 4; ++index) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[index])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[index]))); } _out[n_vec] = dotProduct; } @@ -720,15 +727,15 @@ static inline void volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - for(index = neon_iters * 4; index < num_points; index++) + for (index = neon_iters * 4; index < num_points; index++) { lv_16sc_t tmp = in_common[index] * in_a[n_vec][index]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_16ic_xn_dot_prod_16ic_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic.h index 549fff25d..67bfb1a0b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,9 +36,9 @@ #define INCLUDED_volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_H #include "volk_gnsssdr/volk_gnsssdr_16ic_x2_dot_prod_16ic_xn.h" -#include -#include #include +#include +#include #include #ifdef LV_HAVE_GENERIC @@ -46,23 +46,23 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_generic(lv_16sc_t* { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } -#endif /* Generic */ +#endif /* Generic */ #ifdef LV_HAVE_GENERIC @@ -70,23 +70,23 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_generic_sat(lv_16sc { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic_sat(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_generic_sat(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } -#endif /* Generic */ +#endif /* Generic */ #ifdef LV_HAVE_SSE2 @@ -94,19 +94,19 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_a_sse2(lv_16sc_t* r { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_sse2(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } @@ -119,19 +119,19 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_u_sse2(lv_16sc_t* r { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_sse2(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } @@ -144,19 +144,19 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_a_avx2(lv_16sc_t* r { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_a_avx2(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } @@ -169,98 +169,96 @@ static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_u_avx2(lv_16sc_t* r { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_u_avx2(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } #endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } -#endif // NEON +#endif // NEON -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_neon_vma(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_vma(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } -#endif // NEON +#endif // NEON -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_neon_optvma(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - unsigned int n; - for(n = 0; n < num_a_vectors; n++) - { - in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t)*num_points, volk_gnsssdr_get_alignment()); - memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t)*num_points); - } + int n; + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); + memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); + } - volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(result, local_code, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_neon_optvma(result, local_code, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) - { - volk_gnsssdr_free(in_a[n]); - } + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } volk_gnsssdr_free(in_a); } -#endif // NEON +#endif // NEON #endif // INCLUDED_volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic_H - - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_multiply_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_multiply_16ic.h index 9dbc9bd31..4838c3559 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_multiply_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_multiply_16ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -85,35 +85,35 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_a_sse2(lv_16sc_t* out, con unsigned int number; __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, result; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); const lv_16sc_t* _in_a = in_a; const lv_16sc_t* _in_b = in_b; lv_16sc_t* _out = out; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { //std::complex memory structure: real part -> reinterpret_cast(a)[2*i] - //imaginery part -> reinterpret_cast(a)[2*i + 1] + //imaginary part -> reinterpret_cast(a)[2*i + 1] // a[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - a = _mm_load_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg b = _mm_load_si128((__m128i*)_in_b); - c = _mm_mullo_epi16 (a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128 (c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. - real = _mm_subs_epi16 (c, c_sr); - real = _mm_and_si128 (real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + real = _mm_subs_epi16(c, c_sr); + real = _mm_and_si128(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); - imag = _mm_and_si128 (imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... + imag = _mm_and_si128(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... - result = _mm_or_si128 (real, imag); + result = _mm_or_si128(real, imag); _mm_store_si128((__m128i*)_out, result); @@ -137,37 +137,37 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_u_sse2(lv_16sc_t* out, con { const unsigned int sse_iters = num_points / 4; unsigned int number; - __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1,imag2, b_sl, a_sl, result; + __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl, result; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); const lv_16sc_t* _in_a = in_a; const lv_16sc_t* _in_b = in_b; lv_16sc_t* _out = out; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { //std::complex memory structure: real part -> reinterpret_cast(a)[2*i] - //imaginery part -> reinterpret_cast(a)[2*i + 1] + //imaginary part -> reinterpret_cast(a)[2*i + 1] // a[127:0]=[a3.i,a3.r,a2.i,a2.r,a1.i,a1.r,a0.i,a0.r] - a = _mm_loadu_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_loadu_si128((__m128i*)_in_a); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg b = _mm_loadu_si128((__m128i*)_in_b); - c = _mm_mullo_epi16 (a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128 (c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. - real = _mm_subs_epi16 (c, c_sr); - real = _mm_and_si128 (real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + real = _mm_subs_epi16(c, c_sr); + real = _mm_and_si128(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); - imag = _mm_and_si128 (imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... + imag = _mm_and_si128(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... - result = _mm_or_si128 (real, imag); + result = _mm_or_si128(real, imag); _mm_storeu_si128((__m128i*)_out, result); @@ -196,29 +196,29 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_u_avx2(lv_16sc_t* out, con const lv_16sc_t* _in_b = in_b; lv_16sc_t* _out = out; - __m256i a, b, c, c_sr, real, imag, imag1, imag2, b_sl, a_sl, result; + __m256i a, b, c, c_sr, real, imag, imag1, imag2, b_sl, a_sl, result; - const __m256i mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - const __m256i mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + const __m256i mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + const __m256i mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(;number < avx2_points; number++) + for (; number < avx2_points; number++) { - a = _mm256_loadu_si256((__m256i*)_in_a); // Load the ar + ai, br + bi as ar,ai,br,bi - b = _mm256_loadu_si256((__m256i*)_in_b); // Load the cr + ci, dr + di as cr,ci,dr,di + a = _mm256_loadu_si256((__m256i*)_in_a); // Load the ar + ai, br + bi as ar,ai,br,bi + b = _mm256_loadu_si256((__m256i*)_in_b); // Load the cr + ci, dr + di as cr,ci,dr,di c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); - real = _mm256_and_si256(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i + real = _mm256_and_si256(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i - b_sl = _mm256_slli_si256(b, 2); // b3.r, b2.i .... - a_sl = _mm256_slli_si256(a, 2); // a3.r, a2.i .... + b_sl = _mm256_slli_si256(b, 2); // b3.r, b2.i .... + a_sl = _mm256_slli_si256(a, 2); // a3.r, a2.i .... - imag1 = _mm256_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm256_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm256_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm256_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm256_adds_epi16(imag1, imag2); - imag = _mm256_and_si256(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... + imag = _mm256_and_si256(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... result = _mm256_or_si256(real, imag); @@ -230,7 +230,7 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_u_avx2(lv_16sc_t* out, con } _mm256_zeroupper(); number = avx2_points * 8; - for(;number < num_points; number++) + for (; number < num_points; number++) { *_out++ = (*_in_a++) * (*_in_b++); } @@ -250,29 +250,29 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_a_avx2(lv_16sc_t* out, con const lv_16sc_t* _in_b = in_b; lv_16sc_t* _out = out; - __m256i a, b, c, c_sr, real, imag, imag1, imag2, b_sl, a_sl, result; + __m256i a, b, c, c_sr, real, imag, imag1, imag2, b_sl, a_sl, result; - const __m256i mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - const __m256i mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + const __m256i mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + const __m256i mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); - for(;number < avx2_points; number++) + for (; number < avx2_points; number++) { - a = _mm256_load_si256((__m256i*)_in_a); // Load the ar + ai, br + bi as ar,ai,br,bi - b = _mm256_load_si256((__m256i*)_in_b); // Load the cr + ci, dr + di as cr,ci,dr,di + a = _mm256_load_si256((__m256i*)_in_a); // Load the ar + ai, br + bi as ar,ai,br,bi + b = _mm256_load_si256((__m256i*)_in_b); // Load the cr + ci, dr + di as cr,ci,dr,di c = _mm256_mullo_epi16(a, b); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); - real = _mm256_and_si256(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i + real = _mm256_and_si256(real, mask_real); // a3.r*b3.r-a3.i*b3.i , 0, a3.r*b3.r- a3.i*b3.i - b_sl = _mm256_slli_si256(b, 2); // b3.r, b2.i .... - a_sl = _mm256_slli_si256(a, 2); // a3.r, a2.i .... + b_sl = _mm256_slli_si256(b, 2); // b3.r, b2.i .... + a_sl = _mm256_slli_si256(a, 2); // a3.r, a2.i .... - imag1 = _mm256_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm256_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm256_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm256_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm256_adds_epi16(imag1, imag2); - imag = _mm256_and_si256(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... + imag = _mm256_and_si256(imag, mask_imag); // a3.i*b3.r+b3.i*a3.r, 0, ... result = _mm256_or_si256(real, imag); @@ -284,7 +284,7 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_a_avx2(lv_16sc_t* out, con } _mm256_zeroupper(); number = avx2_points * 8; - for(;number < num_points; number++) + for (; number < num_points; number++) { *_out++ = (*_in_a++) * (*_in_b++); } @@ -292,23 +292,22 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_a_avx2(lv_16sc_t* out, con #endif /* LV_HAVE_AVX2 */ - -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_x2_multiply_16ic_neon(lv_16sc_t* out, const lv_16sc_t* in_a, const lv_16sc_t* in_b, unsigned int num_points) { - lv_16sc_t *a_ptr = (lv_16sc_t*) in_a; - lv_16sc_t *b_ptr = (lv_16sc_t*) in_b; + lv_16sc_t* a_ptr = (lv_16sc_t*)in_a; + lv_16sc_t* b_ptr = (lv_16sc_t*)in_b; unsigned int quarter_points = num_points / 4; int16x4x2_t a_val, b_val, c_val; int16x4x2_t tmp_real, tmp_imag; unsigned int number = 0; - for(number = 0; number < quarter_points; ++number) + for (number = 0; number < quarter_points; ++number) { - a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i - b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i + a_val = vld2_s16((int16_t*)a_ptr); // a0r|a1r|a2r|a3r || a0i|a1i|a2i|a3i + b_val = vld2_s16((int16_t*)b_ptr); // b0r|b1r|b2r|b3r || b0i|b1i|b2i|b3i __VOLK_GNSSSDR_PREFETCH(a_ptr + 4); __VOLK_GNSSSDR_PREFETCH(b_ptr + 4); @@ -334,11 +333,11 @@ static inline void volk_gnsssdr_16ic_x2_multiply_16ic_neon(lv_16sc_t* out, const out += 4; } - for(number = quarter_points * 4; number < num_points; number++) + for (number = quarter_points * 4; number < num_points; number++) { *out++ = (*a_ptr++) * (*b_ptr++); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7*/ #endif /*INCLUDED_volk_gnsssdr_16ic_x2_multiply_16ic_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn.h index f6e3a05c5..efc0feb70 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -69,12 +69,11 @@ #define INCLUDED_volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_H -#include -#include -#include #include +#include +#include +#include #include -//#include #ifdef LV_HAVE_GENERIC @@ -86,11 +85,11 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic(lv_16sc unsigned int n; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); } for (n = 0; n < num_points; n++) { - tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); @@ -131,14 +130,14 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload( const unsigned int ROTATOR_RELOAD = 256; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); } for (n = 0; n < num_points / ROTATOR_RELOAD; n++) { for (j = 0; j < ROTATOR_RELOAD; j++) { - tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); (*phase) *= phase_inc; @@ -149,7 +148,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload( result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); } } - /* Regenerate phase */ + /* Regenerate phase */ #ifdef __cplusplus (*phase) /= std::abs((*phase)); #else @@ -160,13 +159,13 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload( for (j = 0; j < num_points % ROTATOR_RELOAD; j++) { - tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp16 = *in_common++; //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); tmp16 = lv_cmake((int16_t)rintf(lv_creal(tmp32)), (int16_t)rintf(lv_cimag(tmp32))); (*phase) *= phase_inc; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - lv_16sc_t tmp = tmp16 * in_a[n_vec][ (num_points / ROTATOR_RELOAD) * ROTATOR_RELOAD + j ]; + lv_16sc_t tmp = tmp16 * in_a[n_vec][(num_points / ROTATOR_RELOAD) * ROTATOR_RELOAD + j]; //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); result[n_vec] = lv_cmake(sat_adds16i(lv_creal(result[n_vec]), lv_creal(tmp)), sat_adds16i(lv_cimag(result[n_vec]), lv_cimag(tmp))); } @@ -179,9 +178,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload( #ifdef LV_HAVE_SSE3 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int sse_iters = num_points / 4; int n_vec; @@ -192,7 +191,8 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ const lv_16sc_t* _in_common = in_common; lv_16sc_t* _out = result; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; __m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); __m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); @@ -205,17 +205,19 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); // phase rotation registers __m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; __m128i pc1, pc2; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -223,69 +225,69 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ lv_16sc_t tmp16; lv_32fc_t tmp32; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { // Phase rotation on operand in_common starts here: //printf("generic phase %i: %f,%f\n", n*4,lv_creal(*phase),lv_cimag(*phase)); - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four rotated in_common samples in the register b - b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic //next two samples _in_common += 2; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_load_si128((__m128i*)&(_in_a[n_vec][number*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)&(_in_a[n_vec][number * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); @@ -310,12 +312,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); } _out[n_vec] = dotProduct; } @@ -332,7 +334,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ //(*phase) = lv_cmake((float*)two_phase_acc[0], (float*)two_phase_acc[1]); (*phase) = two_phase_acc[0]; - for(n = sse_iters * 4; n < num_points; n++) + for (n = sse_iters * 4; n < num_points; n++) { tmp16 = in_common[n]; //printf("a_sse phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -344,7 +346,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -354,9 +356,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(lv_16sc_ #ifdef LV_HAVE_SSE3 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int sse_iters = num_points / 4; const unsigned int ROTATOR_RELOAD = 128; @@ -370,7 +372,8 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l const lv_16sc_t* _in_common = in_common; lv_16sc_t* _out = result; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; __m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); __m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); @@ -383,17 +386,19 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); // phase rotation registers __m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; __m128i pc1, pc2; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -401,71 +406,71 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l lv_16sc_t tmp16; lv_32fc_t tmp32; - for (number = 0; number < sse_iters / ROTATOR_RELOAD; ++number) + for (number = 0; number < sse_iters / ROTATOR_RELOAD; ++number) { for (j = 0; j < ROTATOR_RELOAD; j++) { // Phase rotation on operand in_common starts here: //printf("generic phase %i: %f,%f\n", n*4,lv_creal(*phase),lv_cimag(*phase)); - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four rotated in_common samples in the register b - b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic //next two samples _in_common += 2; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_load_si128((__m128i*)&(_in_a[n_vec][(number * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)&(_in_a[n_vec][(number * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); @@ -483,65 +488,65 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l for (j = 0; j < sse_iters % ROTATOR_RELOAD; j++) { - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four rotated in_common samples in the register b - b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic //next two samples _in_common += 2; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_load_si128((__m128i*)&(_in_a[n_vec][((sse_iters / ROTATOR_RELOAD) * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_load_si128((__m128i*)&(_in_a[n_vec][((sse_iters / ROTATOR_RELOAD) * ROTATOR_RELOAD + j) * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); @@ -557,12 +562,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); } _out[n_vec] = dotProduct; } @@ -580,7 +585,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l //(*phase) = lv_cmake((float*)two_phase_acc[0], (float*)two_phase_acc[1]); (*phase) = two_phase_acc[0]; - for(n = sse_iters * 4; n < num_points; n++) + for (n = sse_iters * 4; n < num_points; n++) { tmp16 = in_common[n]; //printf("a_sse phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -592,10 +597,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; //lv_16sc_t tmp = lv_cmake(sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_creal(in_a[n_vec][n])), - sat_muls16i(lv_cimag(tmp16), lv_cimag(in_a[n_vec][n]))) , sat_adds16i(sat_muls16i(lv_creal(tmp16), lv_cimag(in_a[n_vec][n])), sat_muls16i(lv_cimag(tmp16), lv_creal(in_a[n_vec][n])))); _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } - } #endif /* LV_HAVE_SSE3 */ @@ -603,9 +607,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(l #ifdef LV_HAVE_SSE3 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); const unsigned int sse_iters = num_points / 4; int n_vec; @@ -616,7 +620,8 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ const lv_16sc_t* _in_common = in_common; lv_16sc_t* _out = result; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; __m128i* realcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); __m128i* imagcacc = (__m128i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128i), volk_gnsssdr_get_alignment()); @@ -629,17 +634,19 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ __m128i a, b, c, c_sr, mask_imag, mask_real, real, imag, imag1, imag2, b_sl, a_sl; - mask_imag = _mm_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - mask_real = _mm_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + mask_imag = _mm_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + mask_real = _mm_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); // phase rotation registers __m128 pa, pb, two_phase_acc_reg, two_phase_inc_reg; __m128i pc1, pc2; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_loadu_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_loadu_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_loadu_ps((float*)two_phase_acc); @@ -647,69 +654,69 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ lv_16sc_t tmp16; lv_32fc_t tmp32; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { // Phase rotation on operand in_common starts here: - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc1 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + pa = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 8); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(pa, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + pa = _mm_shuffle_ps(pa, pa, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(pa, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + pb = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + pc2 = _mm_cvtps_epi32(pb); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four rotated in_common samples in the register b - b = _mm_packs_epi32(pc1, pc2);// convert from 32ic to 16ic + b = _mm_packs_epi32(pc1, pc2); // convert from 32ic to 16ic //next two samples _in_common += 2; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_loadu_si128((__m128i*)&(_in_a[n_vec][number*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a = _mm_loadu_si128((__m128i*)&(_in_a[n_vec][number * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg - c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... + c = _mm_mullo_epi16(a, b); // a3.i*b3.i, a3.r*b3.r, .... - c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm_srli_si128(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm_subs_epi16(c, c_sr); - b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... - a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... + b_sl = _mm_slli_si128(b, 2); // b3.r, b2.i .... + a_sl = _mm_slli_si128(a, 2); // a3.r, a2.i .... - imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... - imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... + imag1 = _mm_mullo_epi16(a, b_sl); // a3.i*b3.r, .... + imag2 = _mm_mullo_epi16(b, a_sl); // b3.i*a3.r, .... imag = _mm_adds_epi16(imag1, imag2); @@ -734,12 +741,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ a = _mm_or_si128(realcacc[n_vec], imagcacc[n_vec]); - _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_si128((__m128i*)dotProductVector, a); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (j = 0; j < 4; ++j) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[j])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[j]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[j]))); } _out[n_vec] = dotProduct; } @@ -749,7 +756,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); (*phase) = two_phase_acc[0]; - for(n = sse_iters * 4; n < num_points; n++) + for (n = sse_iters * 4; n < num_points; n++) { tmp16 = in_common[n]; tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -759,7 +766,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ { lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -769,7 +776,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(lv_16sc_ #ifdef LV_HAVE_AVX2 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { const unsigned int avx2_iters = num_points / 8; const lv_16sc_t** _in_a = in_a; @@ -782,8 +789,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ lv_16sc_t tmp16; lv_32fc_t tmp32; - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; - lv_16sc_t dotProduct = lv_cmake(0,0); + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; + lv_16sc_t dotProduct = lv_cmake(0, 0); __m256i* realcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); __m256i* imagcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); @@ -794,109 +802,111 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ imagcacc[n_vec] = _mm256_setzero_si256(); } - const __m256i mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - const __m256i mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + const __m256i mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + const __m256i mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; __m128i c1, c2, result1, result2; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; - two_phase_acc_reg = _mm_load_ps((float*) two_phase_acc); + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); __m256i a2, b2, c, c_sr, real, imag; __m128 yl, yh, tmp1, tmp2, tmp3; - for(number = 0; number < avx2_iters; number++) + for (number = 0; number < avx2_iters; number++) { - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result1 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result1 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 16); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result2 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result2 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; b2 = _mm256_insertf128_si256(_mm256_castsi128_si256(result1), (result2), 1); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) @@ -905,7 +915,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ c = _mm256_mullo_epi16(a2, b2); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); c_sr = _mm256_slli_si256(b2, 2); @@ -937,12 +947,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ a2 = _mm256_or_si256(realcacc[n_vec], imagcacc[n_vec]); - _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (number = 0; number < 8; ++number) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[number])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[number]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[number]))); } _out[n_vec] = dotProduct; } @@ -954,7 +964,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); (*phase) = two_phase_acc[0]; - for(n = avx2_iters * 8; n < num_points; n++) + for (n = avx2_iters * 8; n < num_points; n++) { tmp16 = in_common[n]; tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -964,10 +974,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ { lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } - } #endif /* LV_HAVE_AVX2 */ @@ -975,7 +984,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(lv_16sc_ #ifdef LV_HAVE_AVX2 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { const unsigned int avx2_iters = num_points / 8; const unsigned int ROTATOR_RELOAD = 128; @@ -990,8 +999,9 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l lv_16sc_t tmp16; lv_32fc_t tmp32; - __VOLK_ATTR_ALIGNED(32) lv_16sc_t dotProductVector[8]; - lv_16sc_t dotProduct = lv_cmake(0,0); + __VOLK_ATTR_ALIGNED(32) + lv_16sc_t dotProductVector[8]; + lv_16sc_t dotProduct = lv_cmake(0, 0); __m256i* realcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); __m256i* imagcacc = (__m256i*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256i), volk_gnsssdr_get_alignment()); @@ -1002,111 +1012,113 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l imagcacc[n_vec] = _mm256_setzero_si256(); } - const __m256i mask_imag = _mm256_set_epi8(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0); - const __m256i mask_real = _mm256_set_epi8(0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255); + const __m256i mask_imag = _mm256_set_epi8(0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0); + const __m256i mask_real = _mm256_set_epi8(0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF, 0, 0, 0xFF, 0xFF); __m128 a, b, two_phase_acc_reg, two_phase_inc_reg; __m128i c1, c2, result1, result2; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; - two_phase_acc_reg = _mm_load_ps((float*) two_phase_acc); + two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); __m256i a2, b2, c, c_sr, real, imag; __m128 yl, yh, tmp1, tmp2, tmp3; - for (number = 0; number < avx2_iters / ROTATOR_RELOAD; ++number) + for (number = 0; number < avx2_iters / ROTATOR_RELOAD; ++number) { for (j = 0; j < ROTATOR_RELOAD; j++) { - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result1 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result1 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 16); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result2 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result2 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; b2 = _mm256_insertf128_si256(_mm256_castsi128_si256(result1), (result2), 1); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) @@ -1115,7 +1127,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l c = _mm256_mullo_epi16(a2, b2); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); c_sr = _mm256_slli_si256(b2, 2); @@ -1140,98 +1152,98 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l for (j = 0; j < avx2_iters % ROTATOR_RELOAD; j++) { - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result1 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result1 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c1 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di //next two samples _in_common += 2; - a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg + a = _mm_set_ps((float)(lv_cimag(_in_common[1])), (float)(lv_creal(_in_common[1])), (float)(lv_cimag(_in_common[0])), (float)(lv_creal(_in_common[0]))); // //load (2 byte imag, 2 byte real) x 2 into 128 bits reg __VOLK_GNSSSDR_PREFETCH(_in_common + 16); //complex 32fc multiplication b=a*two_phase_acc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di - c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(a, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + a = _mm_shuffle_ps(a, a, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(a, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + b = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + c2 = _mm_cvtps_epi32(b); // convert from 32fc to 32ic //complex 32fc multiplication two_phase_acc_reg=two_phase_acc_reg*two_phase_inc_reg - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr - yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di - tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr - tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br - tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di - two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + yh = _mm_movehdup_ps(two_phase_acc_reg); // Load yh with ci,ci,di,di + tmp1 = _mm_mul_ps(two_phase_inc_reg, yl); // tmp1 = ar*cr,ai*cr,br*dr,bi*dr + tmp3 = _mm_shuffle_ps(two_phase_inc_reg, two_phase_inc_reg, 0xB1); // Re-arrange x to be ai,ar,bi,br + tmp2 = _mm_mul_ps(tmp3, yh); // tmp2 = ai*ci,ar*ci,bi*di,br*di + two_phase_acc_reg = _mm_addsub_ps(tmp1, tmp2); // ar*cr-ai*ci, ai*cr+ar*ci, br*dr-bi*di, bi*dr+br*di // store four output samples - result2 = _mm_packs_epi32(c1, c2);// convert from 32ic to 16ic + result2 = _mm_packs_epi32(c1, c2); // convert from 32ic to 16ic _in_common += 2; b2 = _mm256_insertf128_si256(_mm256_castsi128_si256(result1), (result2), 1); for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a2 = _mm256_load_si256((__m256i*)&(_in_a[n_vec][((avx2_iters / ROTATOR_RELOAD) * ROTATOR_RELOAD + j) * 8])); + a2 = _mm256_load_si256((__m256i*)&(_in_a[n_vec][((avx2_iters / ROTATOR_RELOAD) * ROTATOR_RELOAD + j) * 8])); c = _mm256_mullo_epi16(a2, b2); - c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. + c_sr = _mm256_srli_si256(c, 2); // Shift a right by imm8 bytes while shifting in zeros, and store the results in dst. real = _mm256_subs_epi16(c, c_sr); c_sr = _mm256_slli_si256(b2, 2); @@ -1254,12 +1266,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l a2 = _mm256_or_si256(realcacc[n_vec], imagcacc[n_vec]); - _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_si256((__m256i*)dotProductVector, a2); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (j = 0; j < 8; ++j) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[j])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[j]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[j]))); } _out[n_vec] = dotProduct; } @@ -1270,7 +1282,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); (*phase) = two_phase_acc[0]; - for(n = avx2_iters * 8; n < num_points; n++) + for (n = avx2_iters * 8; n < num_points; n++) { tmp16 = in_common[n]; tmp32 = lv_cmake((float)lv_creal(tmp16), (float)lv_cimag(tmp16)) * (*phase); @@ -1280,7 +1292,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l { lv_16sc_t tmp = tmp16 * in_a[n_vec][n]; _out[n_vec] = lv_cmake(sat_adds16i(lv_creal(_out[n_vec]), lv_creal(tmp)), - sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); + sat_adds16i(lv_cimag(_out[n_vec]), lv_cimag(tmp))); } } } @@ -1288,10 +1300,10 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(l #endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { const unsigned int neon_iters = num_points / 4; @@ -1307,14 +1319,16 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* if (neon_iters > 0) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); float arg_phase0 = cargf(*phase); float arg_phase_inc = cargf(phase_inc); float phase_est; lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); @@ -1323,14 +1337,17 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); int16x4x2_t a_val, b_val, c_val; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; float32x4_t half = vdupq_n_f32(0.5f); int16x4x2_t tmp16; int32x4x2_t tmp32i; @@ -1340,13 +1357,13 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* int16x4x2_t* accumulator = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator[n_vec].val[0] = vdup_n_s16(0); accumulator[n_vec].val[1] = vdup_n_s16(0); } - for(number = 0; number < neon_iters; number++) + for (number = 0; number < neon_iters; number++) { /* load 4 complex numbers (int 16 bits each component) */ tmp16 = vld2_s16((int16_t*)_in_common); @@ -1397,7 +1414,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number * 4])); //load (2 byte imag, 2 byte real) x 4 into 128 bits reg //__VOLK_GNSSSDR_PREFETCH(&_in_a[n_vec][number*4] + 8); // multiply the real*real and imag*imag to get real result @@ -1427,8 +1444,10 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -1437,12 +1456,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); } _out[n_vec] = dotProduct; } @@ -1467,14 +1486,14 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(lv_16sc_t* } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON -#include +#ifdef LV_HAVE_NEONV7 #include +#include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { const unsigned int neon_iters = num_points / 4; @@ -1490,14 +1509,16 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s if (neon_iters > 0) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); float arg_phase0 = cargf(*phase); float arg_phase_inc = cargf(phase_inc); float phase_est; //printf("arg phase0: %f", arg_phase0); lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); @@ -1506,14 +1527,17 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); int16x4x2_t a_val, b_val; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; float32x4_t half = vdupq_n_f32(0.5f); int16x4x2_t tmp16; int32x4x2_t tmp32i; @@ -1523,13 +1547,13 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s int16x4x2_t* accumulator = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator[n_vec].val[0] = vdup_n_s16(0); accumulator[n_vec].val[1] = vdup_n_s16(0); } - for(number = 0; number < neon_iters; number++) + for (number = 0; number < neon_iters; number++) { /* load 4 complex numbers (int 16 bits each component) */ tmp16 = vld2_s16((int16_t*)_in_common); @@ -1590,8 +1614,10 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -1599,19 +1625,18 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s // Round = vmulq_f32(_phase_real, _phase_real); // Round = vmlaq_f32(Round, _phase_imag, _phase_imag); // Round = vsqrtq_f32(Round);//printf("sqrt: %f \n", Round[0]); - //Round = vrsqrteq_f32(Round);printf("1/sqtr: %f \n",Round[0]); + //Round = vrsqrteq_f32(Round);printf("1/sqtr: %f \n",Round[0]); //Round = vrecpeq_f32((Round); // _phase_real = vdivq_f32(_phase_real, Round); // _phase_imag = vdivq_f32(_phase_imag, Round); //_phase_real = vmulq_f32(_phase_real, Round); //_phase_imag = vmulq_f32(_phase_imag, Round); //printf("After %i: %f,%f, %f\n\n", number, _phase_real[0], _phase_imag[0], sqrt(_phase_real[0]*_phase_real[0]+_phase_imag[0]*_phase_imag[0])); - } for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number * 4])); b_val.val[0] = vmul_s16(a_val.val[0], tmp16.val[0]); b_val.val[1] = vmul_s16(a_val.val[1], tmp16.val[0]); @@ -1627,12 +1652,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); } _out[n_vec] = dotProduct; } @@ -1658,14 +1683,14 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(lv_16s } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#ifdef LV_HAVE_NEON -#include +#ifdef LV_HAVE_NEONV7 #include +#include -static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_16sc_t* result, const lv_16sc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_16sc_t** in_a, int num_a_vectors, unsigned int num_points) { const unsigned int neon_iters = num_points / 4; @@ -1681,14 +1706,16 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ if (neon_iters > 0) { - lv_16sc_t dotProduct = lv_cmake(0,0); + lv_16sc_t dotProduct = lv_cmake(0, 0); float arg_phase0 = cargf(*phase); float arg_phase_inc = cargf(phase_inc); float phase_est; lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); @@ -1697,14 +1724,17 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); int16x4x2_t a_val, b_val; - __VOLK_ATTR_ALIGNED(16) lv_16sc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(16) + lv_16sc_t dotProductVector[4]; float32x4_t half = vdupq_n_f32(0.5f); int32x4x2_t tmp32i; @@ -1714,7 +1744,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ int16x4x2_t* accumulator1 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); int16x4x2_t* accumulator2 = (int16x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(int16x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator1[n_vec].val[0] = vdup_n_s16(0); accumulator1[n_vec].val[1] = vdup_n_s16(0); @@ -1722,7 +1752,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ accumulator2[n_vec].val[1] = vdup_n_s16(0); } - for(number = 0; number < neon_iters; number++) + for (number = 0; number < neon_iters; number++) { /* load 4 complex numbers (int 16 bits each component) */ b_val = vld2_s16((int16_t*)_in_common); @@ -1783,8 +1813,10 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((*phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((*phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -1792,7 +1824,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number*4])); + a_val = vld2_s16((int16_t*)&(_in_a[n_vec][number * 4])); // use 2 accumulators to remove inter-instruction data dependencies accumulator1[n_vec].val[0] = vmla_s16(accumulator1[n_vec].val[0], a_val.val[0], b_val.val[0]); @@ -1808,12 +1840,12 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ } for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2_s16((int16_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2_s16((int16_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = lv_cmake(sat_adds16i(lv_creal(dotProduct), lv_creal(dotProductVector[i])), - sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); + sat_adds16i(lv_cimag(dotProduct), lv_cimag(dotProductVector[i]))); } _out[n_vec] = dotProduct; } @@ -1840,7 +1872,6 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_optvma(lv_ } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_16ic_x2_dot_prod_16ic_xn_H*/ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic.h index cf002bf6c..51536530e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,12 +36,12 @@ #define INCLUDED_volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_H #include "volk_gnsssdr/volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn.h" -#include #include +#include #include #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.345; @@ -50,17 +50,17 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic(lv_ phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic(result, local_code, phase_inc[0], phase,(const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -71,7 +71,7 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic(lv_ #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic_reload(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.345; @@ -80,17 +80,17 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_generic_rel phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload(result, local_code, phase_inc[0], phase,(const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_generic_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -110,25 +110,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_a_sse3(lv_1 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // SSE3 +#endif // SSE3 #ifdef LV_HAVE_SSE3 @@ -141,25 +141,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_a_sse3_relo phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_sse3_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // SSE3 +#endif // SSE3 #ifdef LV_HAVE_SSE3 @@ -172,25 +172,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_u_sse3(lv_1 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_u_sse3(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // SSE3 +#endif // SSE3 #ifdef LV_HAVE_AVX2 @@ -203,25 +203,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_a_avx2(lv_1 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // AVX2 +#endif // AVX2 #ifdef LV_HAVE_AVX2 @@ -234,25 +234,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_a_avx2_relo phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // AVX2 +#endif // AVX2 #ifdef LV_HAVE_AVX2 @@ -265,25 +265,25 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_u_avx2(lv_1 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // AVX2 +#endif // AVX2 #ifdef LV_HAVE_AVX2 @@ -296,28 +296,28 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_u_avx2_relo phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_a_avx2_reload(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // AVX2 +#endif // AVX2 -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_neon(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! @@ -327,28 +327,28 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_neon(lv_16s phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // NEON +#endif // NEON -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_neon_vma(lv_16sc_t* result, const lv_16sc_t* local_code, const lv_16sc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! @@ -358,26 +358,24 @@ static inline void volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_neon_vma(lv phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_16sc_t** in_a = (lv_16sc_t**)volk_gnsssdr_malloc(sizeof(lv_16sc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_16sc_t*)volk_gnsssdr_malloc(sizeof(lv_16sc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_16sc_t*)in_a[n], (lv_16sc_t*)in, sizeof(lv_16sc_t) * num_points); } - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(result, local_code, phase_inc[0], phase, (const lv_16sc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn_neon_vma(result, local_code, phase_inc[0], phase, (const lv_16sc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } volk_gnsssdr_free(in_a); } -#endif // NEON +#endif // NEON #endif // INCLUDED_volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic_H - - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_16ic_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_16ic_xn.h index 843fa8ed2..8bf573ea1 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_16ic_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_16ic_xn.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -63,10 +63,10 @@ #ifndef INCLUDED_volk_gnsssdr_16ic_xn_resampler_16ic_xn_H #define INCLUDED_volk_gnsssdr_16ic_xn_resampler_16ic_xn_H -#include -#include #include #include +#include +#include #ifdef LV_HAVE_GENERIC @@ -75,8 +75,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_generic(lv_16sc_t** re { int local_code_chip_index; int current_correlator_tap; - int n; - for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + unsigned int n; + for (current_correlator_tap = 0U; current_correlator_tap < num_out_vectors; current_correlator_tap++) { for (n = 0; n < num_points; n++) { @@ -106,7 +106,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse4_1(lv_16sc_t** r const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -120,7 +121,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse4_1(lv_16sc_t** r shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -138,13 +139,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse4_1(lv_16sc_t** r aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -156,7 +157,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse4_1(lv_16sc_t** r } } -#endif +#endif #ifdef LV_HAVE_SSE4_1 @@ -172,7 +173,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse4_1(lv_16sc_t** r const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -186,7 +188,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse4_1(lv_16sc_t** r shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -204,13 +206,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse4_1(lv_16sc_t** r aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -239,7 +241,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse3(lv_16sc_t** res const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -253,7 +256,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse3(lv_16sc_t** res shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -274,13 +277,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_sse3(lv_16sc_t** res aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -309,7 +312,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse3(lv_16sc_t** res const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -323,7 +327,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse3(lv_16sc_t** res shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -344,13 +348,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_sse3(lv_16sc_t** res aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -378,7 +382,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_avx(lv_16sc_t** resu const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(32) int local_code_chip_index[8]; + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; int local_code_chip_index_; const __m256 zeros = _mm256_setzero_ps(); @@ -393,7 +398,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_avx(lv_16sc_t** resu shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < avx_iters; n++) + for (n = 0; n < avx_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); @@ -411,13 +416,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_avx(lv_16sc_t** resu // no negatives c = _mm256_cvtepi32_ps(local_code_chip_index_reg); - negatives = _mm256_cmp_ps(c, zeros, 0x01 ); + negatives = _mm256_cmp_ps(c, zeros, 0x01); aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); aux = _mm256_add_ps(c, aux3); local_code_chip_index_reg = _mm256_cvttps_epi32(aux); _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 8; ++k) + for (k = 0; k < 8; ++k) { _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; } @@ -427,7 +432,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_a_avx(lv_16sc_t** resu _mm256_zeroupper(); for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) { - for(n = avx_iters * 8; n < num_points; n++) + for (n = avx_iters * 8; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -455,7 +460,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(lv_16sc_t** resu const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(32) int local_code_chip_index[8]; + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; int local_code_chip_index_; const __m256 zeros = _mm256_setzero_ps(); @@ -470,7 +476,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(lv_16sc_t** resu shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < avx_iters; n++) + for (n = 0; n < avx_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); @@ -488,13 +494,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(lv_16sc_t** resu // no negatives c = _mm256_cvtepi32_ps(local_code_chip_index_reg); - negatives = _mm256_cmp_ps(c, zeros, 0x01 ); + negatives = _mm256_cmp_ps(c, zeros, 0x01); aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); aux = _mm256_add_ps(c, aux3); local_code_chip_index_reg = _mm256_cvttps_epi32(aux); _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 8; ++k) + for (k = 0; k < 8; ++k) { _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; } @@ -504,7 +510,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(lv_16sc_t** resu _mm256_zeroupper(); for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) { - for(n = avx_iters * 8; n < num_points; n++) + for (n = avx_iters * 8; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); @@ -519,7 +525,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_u_avx(lv_16sc_t** resu #endif -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** result, const lv_16sc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) { @@ -530,7 +536,8 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul const float32x4_t rem_code_phase_chips_reg = vdupq_n_f32(rem_code_phase_chips); const float32x4_t code_phase_step_chips_reg = vdupq_n_f32(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int32_t local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int32_t local_code_chip_index[4]; int32_t local_code_chip_index_; const int32x4_t zeros = vdupq_n_s32(0); @@ -538,11 +545,12 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul const int32x4_t code_length_chips_reg_i = vdupq_n_s32((int32_t)code_length_chips); int32x4_t local_code_chip_index_reg, aux_i, negatives, i; float32x4_t aux, aux2, shifts_chips_reg, fi, c, j, cTrunc, base, indexn, reciprocal; - __VOLK_ATTR_ALIGNED(16) const float vec[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + const float vec[4] = {0.0f, 1.0f, 2.0f, 3.0f}; uint32x4_t igx; reciprocal = vrecpeq_f32(code_length_chips_reg_f); reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); - reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! float32x4_t n0 = vld1q_f32((float*)vec); int current_correlator_tap; unsigned int n; @@ -552,7 +560,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul shifts_chips_reg = vdupq_n_f32((float)shifts_chips[current_correlator_tap]); aux2 = vsubq_f32(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < neon_iters; n++) + for (n = 0; n < neon_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][4 * n + 3], 1, 0); __VOLK_GNSSSDR_PREFETCH(&local_code_chip_index[4]); @@ -568,7 +576,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul // fmod c = vmulq_f32(aux, reciprocal); - i = vcvtq_s32_f32(c); + i = vcvtq_s32_f32(c); cTrunc = vcvtq_f32_s32(i); base = vmulq_f32(cTrunc, code_length_chips_reg_f); aux = vsubq_f32(aux, base); @@ -580,13 +588,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul vst1q_s32((int32_t*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = vaddq_f32(indexn, fours); } - for(n = neon_iters * 4; n < num_points; n++) + for (n = neon_iters * 4; n < num_points; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][n], 1, 0); // resample code for current tap @@ -604,4 +612,3 @@ static inline void volk_gnsssdr_16ic_xn_resampler_16ic_xn_neon(lv_16sc_t** resul #endif /*INCLUDED_volk_gnsssdr_16ic_xn_resampler_16ic_xn_H*/ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn.h index a31cba3a5..4d3cc61c1 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn.h @@ -6,12 +6,12 @@ *
      * * VOLK_GNSSSDR kernel that esamples N 16 bits integer short complex vectors using zero hold resample algorithm. - * It is optimized to resample a sigle GNSS local code signal replica into N vectors fractional-resampled and fractional-delayed + * It is optimized to resample a single GNSS local code signal replica into N vectors fractional-resampled and fractional-delayed * (i.e. it creates the Early, Prompt, and Late code replicas) * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -63,9 +63,9 @@ #ifndef INCLUDED_volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_H #define INCLUDED_volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_H -#include #include #include +#include #ifdef LV_HAVE_GENERIC @@ -83,7 +83,7 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_generic(lv_16sc_t // resample code for current tap local_code_chip_index = round(code_phase_step_chips * (float)(n) + rem_code_phase_chips[current_vector] - 0.5f); if (local_code_chip_index < 0.0) local_code_chip_index += code_length_chips; - if (local_code_chip_index > (code_length_chips - 1)) local_code_chip_index -= code_length_chips; + if (local_code_chip_index > ((int)code_length_chips - 1)) local_code_chip_index -= code_length_chips; result[current_vector][n] = local_code[local_code_chip_index]; } } @@ -95,69 +95,74 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_generic(lv_16sc_t #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_a_sse2(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips ,float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) +static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_a_sse2(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips, float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) { - _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);//_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); //_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; lv_16sc_t** _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; float tmp_rem_code_phase_chips; - __m128 _rem_code_phase,_code_phase_step_chips; - __m128i _code_length_chips,_code_length_chips_minus1; - __m128 _code_phase_out,_code_phase_out_with_offset; + __m128 _rem_code_phase, _code_phase_step_chips; + __m128i _code_length_chips, _code_length_chips_minus1; + __m128 _code_phase_out, _code_phase_out_with_offset; - _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; + _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; four_times_code_length_chips_minus1[0] = code_length_chips - 1; four_times_code_length_chips_minus1[1] = code_length_chips - 1; four_times_code_length_chips_minus1[2] = code_length_chips - 1; four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = _mm_load_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register - _code_length_chips_minus1 = _mm_load_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register + _code_length_chips = _mm_load_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register + _code_length_chips_minus1 = _mm_load_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register - __m128i negative_indexes, overflow_indexes,_code_phase_out_int, _code_phase_out_int_neg,_code_phase_out_int_over; + __m128i negative_indexes, overflow_indexes, _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; __m128i zero = _mm_setzero_si128(); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; __m128 _4output_index = _mm_load_ps(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; __m128 _4constant_float = _mm_load_ps(init_4constant_float); int current_vector = 0; int sample_idx = 0; - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { //common to all outputs - _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - //output vector dependant (different code phase offset) - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + //output vector dependent (different code phase offset) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { - tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) - _rem_code_phase = _mm_load1_ps(&tmp_rem_code_phase_chips); //load float to all four float values in m128 register + tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) + _rem_code_phase = _mm_load1_ps(&tmp_rem_code_phase_chips); //load float to all four float values in m128 register - _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset - _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer + _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer - negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128( negative_indexes, _mm_xor_si128( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128(negative_indexes, _mm_xor_si128(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128( overflow_indexes, _mm_xor_si128( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128(overflow_indexes, _mm_xor_si128(_code_phase_out_int_over, _code_phase_out_int_neg))); - _mm_store_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + _mm_store_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible _result[current_vector][sample_idx] = local_code[local_code_chip_index[0]]; @@ -169,13 +174,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_a_sse2(lv_16sc_t* sample_idx += 4; } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)(number) + rem_code_phase_chips[current_vector]); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; - if (local_code_chip_index[0] > (code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; + if (local_code_chip_index[0] > ((int)code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; _result[current_vector][number] = local_code[local_code_chip_index[0]]; } } @@ -186,69 +191,74 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_a_sse2(lv_16sc_t* #ifdef LV_HAVE_SSE2 #include -static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_u_sse2(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips ,float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) +static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_u_sse2(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips, float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) { - _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);//_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); //_MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; lv_16sc_t** _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; float tmp_rem_code_phase_chips; - __m128 _rem_code_phase,_code_phase_step_chips; - __m128i _code_length_chips,_code_length_chips_minus1; - __m128 _code_phase_out,_code_phase_out_with_offset; + __m128 _rem_code_phase, _code_phase_step_chips; + __m128i _code_length_chips, _code_length_chips_minus1; + __m128 _code_phase_out, _code_phase_out_with_offset; - _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; + _code_phase_step_chips = _mm_load1_ps(&code_phase_step_chips); //load float to all four float values in m128 register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; four_times_code_length_chips_minus1[0] = code_length_chips - 1; four_times_code_length_chips_minus1[1] = code_length_chips - 1; four_times_code_length_chips_minus1[2] = code_length_chips - 1; four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = _mm_loadu_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register - _code_length_chips_minus1 = _mm_loadu_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register + _code_length_chips = _mm_loadu_si128((__m128i*)&four_times_code_length_chips); //load float to all four float values in m128 register + _code_length_chips_minus1 = _mm_loadu_si128((__m128i*)&four_times_code_length_chips_minus1); //load float to all four float values in m128 register - __m128i negative_indexes, overflow_indexes,_code_phase_out_int, _code_phase_out_int_neg,_code_phase_out_int_over; + __m128i negative_indexes, overflow_indexes, _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; __m128i zero = _mm_setzero_si128(); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; __m128 _4output_index = _mm_loadu_ps(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; __m128 _4constant_float = _mm_loadu_ps(init_4constant_float); int current_vector = 0; int sample_idx = 0; - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { //common to all outputs - _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out = _mm_mul_ps(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - //output vector dependant (different code phase offset) - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + //output vector dependent (different code phase offset) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { - tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) - _rem_code_phase = _mm_load1_ps(&tmp_rem_code_phase_chips); //load float to all four float values in m128 register + tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) + _rem_code_phase = _mm_load1_ps(&tmp_rem_code_phase_chips); //load float to all four float values in m128 register - _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset - _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer + _code_phase_out_with_offset = _mm_add_ps(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer - negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128( negative_indexes, _mm_xor_si128( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = _mm_cmplt_epi32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = _mm_add_epi32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = _mm_xor_si128(_code_phase_out_int, _mm_and_si128(negative_indexes, _mm_xor_si128(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128( overflow_indexes, _mm_xor_si128( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = _mm_cmpgt_epi32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = _mm_sub_epi32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = _mm_xor_si128(_code_phase_out_int_neg, _mm_and_si128(overflow_indexes, _mm_xor_si128(_code_phase_out_int_over, _code_phase_out_int_neg))); - _mm_storeu_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + _mm_storeu_si128((__m128i*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible _result[current_vector][sample_idx] = local_code[local_code_chip_index[0]]; @@ -260,13 +270,13 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_u_sse2(lv_16sc_t* sample_idx += 4; } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)(number) + rem_code_phase_chips[current_vector]); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; - if (local_code_chip_index[0] > (code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; + if (local_code_chip_index[0] > ((int)code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; _result[current_vector][number] = local_code[local_code_chip_index[0]]; } } @@ -275,77 +285,82 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_u_sse2(lv_16sc_t* #endif /* LV_HAVE_SSE2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include -static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_neon(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips ,float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) +static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_neon(lv_16sc_t** result, const lv_16sc_t* local_code, float* rem_code_phase_chips, float code_phase_step_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_output_samples) { unsigned int number; const unsigned int quarterPoints = num_output_samples / 4; float32x4_t half = vdupq_n_f32(0.5f); lv_16sc_t** _result = result; - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; float tmp_rem_code_phase_chips; float32x4_t _rem_code_phase, _code_phase_step_chips; int32x4_t _code_length_chips, _code_length_chips_minus1; float32x4_t _code_phase_out, _code_phase_out_with_offset; float32x4_t sign, PlusHalf, Round; - _code_phase_step_chips = vld1q_dup_f32(&code_phase_step_chips); //load float to all four float values in float32x4_t register - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips_minus1[4]; + _code_phase_step_chips = vld1q_dup_f32(&code_phase_step_chips); //load float to all four float values in float32x4_t register + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips_minus1[4]; four_times_code_length_chips_minus1[0] = code_length_chips - 1; four_times_code_length_chips_minus1[1] = code_length_chips - 1; four_times_code_length_chips_minus1[2] = code_length_chips - 1; four_times_code_length_chips_minus1[3] = code_length_chips - 1; - __VOLK_ATTR_ALIGNED(16) int four_times_code_length_chips[4]; + __VOLK_ATTR_ALIGNED(16) + int four_times_code_length_chips[4]; four_times_code_length_chips[0] = code_length_chips; four_times_code_length_chips[1] = code_length_chips; four_times_code_length_chips[2] = code_length_chips; four_times_code_length_chips[3] = code_length_chips; - _code_length_chips = vld1q_s32((int32_t*)&four_times_code_length_chips); //load float to all four float values in float32x4_t register - _code_length_chips_minus1 = vld1q_s32((int32_t*)&four_times_code_length_chips_minus1); //load float to all four float values in float32x4_t register + _code_length_chips = vld1q_s32((int32_t*)&four_times_code_length_chips); //load float to all four float values in float32x4_t register + _code_length_chips_minus1 = vld1q_s32((int32_t*)&four_times_code_length_chips_minus1); //load float to all four float values in float32x4_t register - int32x4_t _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; + int32x4_t _code_phase_out_int, _code_phase_out_int_neg, _code_phase_out_int_over; uint32x4_t negative_indexes, overflow_indexes; int32x4_t zero = vmovq_n_s32(0); - __VOLK_ATTR_ALIGNED(16) float init_idx_float[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_idx_float[4] = {0.0f, 1.0f, 2.0f, 3.0f}; float32x4_t _4output_index = vld1q_f32(init_idx_float); - __VOLK_ATTR_ALIGNED(16) float init_4constant_float[4] = { 4.0f, 4.0f, 4.0f, 4.0f }; + __VOLK_ATTR_ALIGNED(16) + float init_4constant_float[4] = {4.0f, 4.0f, 4.0f, 4.0f}; float32x4_t _4constant_float = vld1q_f32(init_4constant_float); int current_vector = 0; int sample_idx = 0; - for(number = 0; number < quarterPoints; number++) + for (number = 0; number < quarterPoints; number++) { //common to all outputs - _code_phase_out = vmulq_f32(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step + _code_phase_out = vmulq_f32(_code_phase_step_chips, _4output_index); //compute the code phase point with the phase step - //output vector dependant (different code phase offset) - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + //output vector dependent (different code phase offset) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { - tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) - _rem_code_phase = vld1q_dup_f32(&tmp_rem_code_phase_chips); //load float to all four float values in float32x4_t register + tmp_rem_code_phase_chips = rem_code_phase_chips[current_vector] - 0.5f; // adjust offset to perform correct rounding (chip transition at 0) + _rem_code_phase = vld1q_dup_f32(&tmp_rem_code_phase_chips); //load float to all four float values in float32x4_t register - _code_phase_out_with_offset = vaddq_f32(_code_phase_out, _rem_code_phase); //add the phase offset + _code_phase_out_with_offset = vaddq_f32(_code_phase_out, _rem_code_phase); //add the phase offset //_code_phase_out_int = _mm_cvtps_epi32(_code_phase_out_with_offset); //convert to integer sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(_code_phase_out_with_offset), 31))); PlusHalf = vaddq_f32(_code_phase_out_with_offset, half); Round = vsubq_f32(PlusHalf, sign); _code_phase_out_int = vcvtq_s32_f32(Round); - negative_indexes = vcltq_s32(_code_phase_out_int, zero); //test for negative values - _code_phase_out_int_neg = vaddq_s32(_code_phase_out_int, _code_length_chips); //the negative values branch - _code_phase_out_int_neg = veorq_s32(_code_phase_out_int, vandq_s32( (int32x4_t)negative_indexes, veorq_s32( _code_phase_out_int_neg, _code_phase_out_int ))); + negative_indexes = vcltq_s32(_code_phase_out_int, zero); //test for negative values + _code_phase_out_int_neg = vaddq_s32(_code_phase_out_int, _code_length_chips); //the negative values branch + _code_phase_out_int_neg = veorq_s32(_code_phase_out_int, vandq_s32((int32x4_t)negative_indexes, veorq_s32(_code_phase_out_int_neg, _code_phase_out_int))); - overflow_indexes = vcgtq_s32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values - _code_phase_out_int_over = vsubq_s32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch - _code_phase_out_int_over = veorq_s32(_code_phase_out_int_neg, vandq_s32( (int32x4_t)overflow_indexes, veorq_s32( _code_phase_out_int_over, _code_phase_out_int_neg ))); + overflow_indexes = vcgtq_s32(_code_phase_out_int_neg, _code_length_chips_minus1); //test for overflow values + _code_phase_out_int_over = vsubq_s32(_code_phase_out_int_neg, _code_length_chips); //the negative values branch + _code_phase_out_int_over = veorq_s32(_code_phase_out_int_neg, vandq_s32((int32x4_t)overflow_indexes, veorq_s32(_code_phase_out_int_over, _code_phase_out_int_neg))); - vst1q_s32((int32_t*)local_code_chip_index, _code_phase_out_int_over); // Store the results back + vst1q_s32((int32_t*)local_code_chip_index, _code_phase_out_int_over); // Store the results back //todo: optimize the local code lookup table with intrinsics, if possible _result[current_vector][sample_idx] = local_code[local_code_chip_index[0]]; @@ -357,18 +372,18 @@ static inline void volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_neon(lv_16sc_t** sample_idx += 4; } - for(number = quarterPoints * 4; number < num_output_samples; number++) + for (number = quarterPoints * 4; number < num_output_samples; number++) { - for(current_vector = 0; current_vector < num_out_vectors; current_vector++) + for (current_vector = 0; current_vector < num_out_vectors; current_vector++) { local_code_chip_index[0] = (int)(code_phase_step_chips * (float)(number) + rem_code_phase_chips[current_vector]); if (local_code_chip_index[0] < 0.0) local_code_chip_index[0] += code_length_chips - 1; - if (local_code_chip_index[0] > (code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; + if (local_code_chip_index[0] > ((int)code_length_chips - 1)) local_code_chip_index[0] -= code_length_chips; _result[current_vector][number] = local_code[local_code_chip_index[0]]; } } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f.h new file mode 100644 index 000000000..d6fbcf756 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f.h @@ -0,0 +1,288 @@ +/*! + * \file volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f.h + * \brief VOLK_GNSSSDR puppet for the multiple 32-bit float vector high dynamics resampler kernel. + * \authors
        + *
      • Cillian O'Driscoll 2017 cillian.odriscoll at gmail dot com + *
      • Javier Arribas, 2018. javiarribas(at)gmail.com + *
      + * + * VOLK_GNSSSDR puppet for integrating the multiple resampler into the test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_H +#define INCLUDED_volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_H + +#include "volk_gnsssdr/volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn.h" +#include +#include +#include +#include + + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_generic(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif /* LV_HAVE_GENERIC */ + + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_a_sse3(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_u_sse3(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_u_sse4_1(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_a_sse4_1(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_a_avx(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f_u_avx(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.8234; + float code_phase_rate_step_chips = 1.0 / powf(2.0, 33.0); + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif +// +//#ifdef LV_HAVE_NEONV7 +//static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_neon(float* result, const float* local_code, unsigned int num_points) +//{ +// int code_length_chips = 2046; +// float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); +// int num_out_vectors = 3; +// float rem_code_phase_chips = -0.234; +// int n; +// float shifts_chips[3] = {-0.1, 0.0, 0.1}; +// +// float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); +// for (n = 0; n < num_out_vectors; n++) +// { +// result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); +// } +// +// volk_gnsssdr_32f_xn_resampler_32f_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); +// +// memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); +// +// for (n = 0; n < num_out_vectors; n++) +// { +// volk_gnsssdr_free(result_aux[n]); +// } +// volk_gnsssdr_free(result_aux); +//} +//#endif + +#endif // INCLUDED_volk_gnsssdr_32f_high_dynamics_resamplerpuppet_32f_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_index_max_32u.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_index_max_32u.h index 3948a96a6..26b41aadd 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_index_max_32u.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_index_max_32u.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,13 +23,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - /*! * \page volk_gnsssdr_32f_index_max_32u.h * @@ -57,14 +56,13 @@ #include #include -#include #ifdef LV_HAVE_AVX #include static inline void volk_gnsssdr_32f_index_max_32u_a_avx(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 8; @@ -72,7 +70,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_avx(uint32_t* target, const float* inputPtr = (float*)src0; __m256 indexIncrementValues = _mm256_set1_ps(8); - __m256 currentIndexes = _mm256_set_ps(-1,-2,-3,-4,-5,-6,-7,-8); + __m256 currentIndexes = _mm256_set_ps(-1, -2, -3, -4, -5, -6, -7, -8); float max = src0[0]; float index = 0; @@ -81,25 +79,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_avx(uint32_t* target, const __m256 compareResults; __m256 currentValues; - __VOLK_ATTR_ALIGNED(32) float maxValuesBuffer[8]; - __VOLK_ATTR_ALIGNED(32) float maxIndexesBuffer[8]; + __VOLK_ATTR_ALIGNED(32) + float maxValuesBuffer[8]; + __VOLK_ATTR_ALIGNED(32) + float maxIndexesBuffer[8]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = _mm256_load_ps(inputPtr); inputPtr += 8; + currentValues = _mm256_load_ps(inputPtr); + inputPtr += 8; currentIndexes = _mm256_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm256_cmp_ps(maxValues, currentValues, 0x1e); maxValuesIndex = _mm256_blendv_ps(currentIndexes, maxValuesIndex, compareResults); - maxValues = _mm256_blendv_ps(currentValues, maxValues, compareResults); + maxValues = _mm256_blendv_ps(currentValues, maxValues, compareResults); } // Calculate the largest value from the remaining 8 points _mm256_store_ps(maxValuesBuffer, maxValues); _mm256_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 8; number++) + for (number = 0; number < 8; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -107,9 +108,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_avx(uint32_t* target, const } number = quarterPoints * 8; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -127,7 +128,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_avx(uint32_t* target, const static inline void volk_gnsssdr_32f_index_max_32u_u_avx(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 8; @@ -135,7 +136,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_avx(uint32_t* target, const float* inputPtr = (float*)src0; __m256 indexIncrementValues = _mm256_set1_ps(8); - __m256 currentIndexes = _mm256_set_ps(-1,-2,-3,-4,-5,-6,-7,-8); + __m256 currentIndexes = _mm256_set_ps(-1, -2, -3, -4, -5, -6, -7, -8); float max = src0[0]; float index = 0; @@ -144,25 +145,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_avx(uint32_t* target, const __m256 compareResults; __m256 currentValues; - __VOLK_ATTR_ALIGNED(32) float maxValuesBuffer[8]; - __VOLK_ATTR_ALIGNED(32) float maxIndexesBuffer[8]; + __VOLK_ATTR_ALIGNED(32) + float maxValuesBuffer[8]; + __VOLK_ATTR_ALIGNED(32) + float maxIndexesBuffer[8]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = _mm256_loadu_ps(inputPtr); inputPtr += 8; + currentValues = _mm256_loadu_ps(inputPtr); + inputPtr += 8; currentIndexes = _mm256_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm256_cmp_ps(maxValues, currentValues, 0x1e); maxValuesIndex = _mm256_blendv_ps(currentIndexes, maxValuesIndex, compareResults); - maxValues = _mm256_blendv_ps(currentValues, maxValues, compareResults); + maxValues = _mm256_blendv_ps(currentValues, maxValues, compareResults); } // Calculate the largest value from the remaining 8 points _mm256_store_ps(maxValuesBuffer, maxValues); _mm256_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 8; number++) + for (number = 0; number < 8; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -170,9 +174,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_avx(uint32_t* target, const } number = quarterPoints * 8; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -186,11 +190,11 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_avx(uint32_t* target, const #ifdef LV_HAVE_SSE4_1 -#include +#include static inline void volk_gnsssdr_32f_index_max_32u_a_sse4_1(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 4; @@ -198,7 +202,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse4_1(uint32_t* target, con float* inputPtr = (float*)src0; __m128 indexIncrementValues = _mm_set1_ps(4); - __m128 currentIndexes = _mm_set_ps(-1,-2,-3,-4); + __m128 currentIndexes = _mm_set_ps(-1, -2, -3, -4); float max = src0[0]; float index = 0; @@ -207,26 +211,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse4_1(uint32_t* target, con __m128 compareResults; __m128 currentValues; - __VOLK_ATTR_ALIGNED(16) float maxValuesBuffer[4]; - __VOLK_ATTR_ALIGNED(16) float maxIndexesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxValuesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxIndexesBuffer[4]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - - currentValues = _mm_load_ps(inputPtr); inputPtr += 4; + currentValues = _mm_load_ps(inputPtr); + inputPtr += 4; currentIndexes = _mm_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm_cmpgt_ps(maxValues, currentValues); maxValuesIndex = _mm_blendv_ps(currentIndexes, maxValuesIndex, compareResults); - maxValues = _mm_blendv_ps(currentValues, maxValues, compareResults); + maxValues = _mm_blendv_ps(currentValues, maxValues, compareResults); } // Calculate the largest value from the remaining 4 points _mm_store_ps(maxValuesBuffer, maxValues); _mm_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 4; number++) + for (number = 0; number < 4; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -234,9 +240,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse4_1(uint32_t* target, con } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -250,11 +256,11 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse4_1(uint32_t* target, con #ifdef LV_HAVE_SSE4_1 -#include +#include static inline void volk_gnsssdr_32f_index_max_32u_u_sse4_1(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 4; @@ -262,7 +268,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse4_1(uint32_t* target, con float* inputPtr = (float*)src0; __m128 indexIncrementValues = _mm_set1_ps(4); - __m128 currentIndexes = _mm_set_ps(-1,-2,-3,-4); + __m128 currentIndexes = _mm_set_ps(-1, -2, -3, -4); float max = src0[0]; float index = 0; @@ -271,25 +277,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse4_1(uint32_t* target, con __m128 compareResults; __m128 currentValues; - __VOLK_ATTR_ALIGNED(16) float maxValuesBuffer[4]; - __VOLK_ATTR_ALIGNED(16) float maxIndexesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxValuesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxIndexesBuffer[4]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = _mm_loadu_ps(inputPtr); inputPtr += 4; + currentValues = _mm_loadu_ps(inputPtr); + inputPtr += 4; currentIndexes = _mm_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm_cmpgt_ps(maxValues, currentValues); maxValuesIndex = _mm_blendv_ps(currentIndexes, maxValuesIndex, compareResults); - maxValues = _mm_blendv_ps(currentValues, maxValues, compareResults); + maxValues = _mm_blendv_ps(currentValues, maxValues, compareResults); } // Calculate the largest value from the remaining 4 points _mm_store_ps(maxValuesBuffer, maxValues); _mm_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 4; number++) + for (number = 0; number < 4; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -297,9 +306,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse4_1(uint32_t* target, con } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -314,11 +323,11 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse4_1(uint32_t* target, con #ifdef LV_HAVE_SSE -#include +#include static inline void volk_gnsssdr_32f_index_max_32u_a_sse(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 4; @@ -326,7 +335,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse(uint32_t* target, const float* inputPtr = (float*)src0; __m128 indexIncrementValues = _mm_set1_ps(4); - __m128 currentIndexes = _mm_set_ps(-1,-2,-3,-4); + __m128 currentIndexes = _mm_set_ps(-1, -2, -3, -4); float max = src0[0]; float index = 0; @@ -335,25 +344,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse(uint32_t* target, const __m128 compareResults; __m128 currentValues; - __VOLK_ATTR_ALIGNED(16) float maxValuesBuffer[4]; - __VOLK_ATTR_ALIGNED(16) float maxIndexesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxValuesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxIndexesBuffer[4]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = _mm_load_ps(inputPtr); inputPtr += 4; + currentValues = _mm_load_ps(inputPtr); + inputPtr += 4; currentIndexes = _mm_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm_cmpgt_ps(maxValues, currentValues); - maxValuesIndex = _mm_or_ps(_mm_and_ps(compareResults, maxValuesIndex) , _mm_andnot_ps(compareResults, currentIndexes)); - maxValues = _mm_or_ps(_mm_and_ps(compareResults, maxValues) , _mm_andnot_ps(compareResults, currentValues)); + maxValuesIndex = _mm_or_ps(_mm_and_ps(compareResults, maxValuesIndex), _mm_andnot_ps(compareResults, currentIndexes)); + maxValues = _mm_or_ps(_mm_and_ps(compareResults, maxValues), _mm_andnot_ps(compareResults, currentValues)); } // Calculate the largest value from the remaining 4 points _mm_store_ps(maxValuesBuffer, maxValues); _mm_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 4; number++) + for (number = 0; number < 4; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -361,9 +373,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse(uint32_t* target, const } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -378,11 +390,11 @@ static inline void volk_gnsssdr_32f_index_max_32u_a_sse(uint32_t* target, const #ifdef LV_HAVE_SSE -#include +#include static inline void volk_gnsssdr_32f_index_max_32u_u_sse(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 4; @@ -390,7 +402,7 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse(uint32_t* target, const float* inputPtr = (float*)src0; __m128 indexIncrementValues = _mm_set1_ps(4); - __m128 currentIndexes = _mm_set_ps(-1,-2,-3,-4); + __m128 currentIndexes = _mm_set_ps(-1, -2, -3, -4); float max = src0[0]; float index = 0; @@ -399,25 +411,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse(uint32_t* target, const __m128 compareResults; __m128 currentValues; - __VOLK_ATTR_ALIGNED(16) float maxValuesBuffer[4]; - __VOLK_ATTR_ALIGNED(16) float maxIndexesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxValuesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxIndexesBuffer[4]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = _mm_loadu_ps(inputPtr); inputPtr += 4; + currentValues = _mm_loadu_ps(inputPtr); + inputPtr += 4; currentIndexes = _mm_add_ps(currentIndexes, indexIncrementValues); compareResults = _mm_cmpgt_ps(maxValues, currentValues); - maxValuesIndex = _mm_or_ps(_mm_and_ps(compareResults, maxValuesIndex) , _mm_andnot_ps(compareResults, currentIndexes)); - maxValues = _mm_or_ps(_mm_and_ps(compareResults, maxValues) , _mm_andnot_ps(compareResults, currentValues)); + maxValuesIndex = _mm_or_ps(_mm_and_ps(compareResults, maxValuesIndex), _mm_andnot_ps(compareResults, currentIndexes)); + maxValues = _mm_or_ps(_mm_and_ps(compareResults, maxValues), _mm_andnot_ps(compareResults, currentValues)); } // Calculate the largest value from the remaining 4 points _mm_store_ps(maxValuesBuffer, maxValues); _mm_store_ps(maxIndexesBuffer, maxValuesIndex); - for(number = 0; number < 4; number++) + for (number = 0; number < 4; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -425,9 +440,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse(uint32_t* target, const } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -444,16 +459,16 @@ static inline void volk_gnsssdr_32f_index_max_32u_u_sse(uint32_t* target, const static inline void volk_gnsssdr_32f_index_max_32u_generic(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { float max = src0[0]; uint32_t index = 0; uint32_t i = 1; - for(; i < num_points; ++i) + for (; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -466,19 +481,20 @@ static inline void volk_gnsssdr_32f_index_max_32u_generic(uint32_t* target, cons #endif /*LV_HAVE_GENERIC*/ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_32f_index_max_32u_neon(uint32_t* target, const float* src0, uint32_t num_points) { - if(num_points > 0) + if (num_points > 0) { uint32_t number = 0; const uint32_t quarterPoints = num_points / 4; float* inputPtr = (float*)src0; float32x4_t indexIncrementValues = vdupq_n_f32(4); - __VOLK_ATTR_ALIGNED(16) float currentIndexes_float[4] = { -4.0f, -3.0f, -2.0f, -1.0f }; + __VOLK_ATTR_ALIGNED(16) + float currentIndexes_float[4] = {-4.0f, -3.0f, -2.0f, -1.0f}; float32x4_t currentIndexes = vld1q_f32(currentIndexes_float); float max = src0[0]; @@ -489,25 +505,28 @@ static inline void volk_gnsssdr_32f_index_max_32u_neon(uint32_t* target, const f uint32x4_t currentIndexes_u; float32x4_t currentValues; - __VOLK_ATTR_ALIGNED(16) float maxValuesBuffer[4]; - __VOLK_ATTR_ALIGNED(16) float maxIndexesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxValuesBuffer[4]; + __VOLK_ATTR_ALIGNED(16) + float maxIndexesBuffer[4]; - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { - currentValues = vld1q_f32(inputPtr); inputPtr += 4; - currentIndexes = vaddq_f32(currentIndexes, indexIncrementValues); + currentValues = vld1q_f32(inputPtr); + inputPtr += 4; + currentIndexes = vaddq_f32(currentIndexes, indexIncrementValues); currentIndexes_u = vcvtq_u32_f32(currentIndexes); - compareResults = vcgtq_f32( maxValues, currentValues); - maxValuesIndex = vorrq_u32( vandq_u32( compareResults, maxValuesIndex ), vbicq_u32(currentIndexes_u, compareResults) ); - maxValues = vmaxq_f32(currentValues, maxValues); + compareResults = vcgtq_f32(maxValues, currentValues); + maxValuesIndex = vorrq_u32(vandq_u32(compareResults, maxValuesIndex), vbicq_u32(currentIndexes_u, compareResults)); + maxValues = vmaxq_f32(currentValues, maxValues); } // Calculate the largest value from the remaining 4 points vst1q_f32(maxValuesBuffer, maxValues); vst1q_f32(maxIndexesBuffer, vcvtq_f32_u32(maxValuesIndex)); - for(number = 0; number < 4; number++) + for (number = 0; number < 4; number++) { - if(maxValuesBuffer[number] > max) + if (maxValuesBuffer[number] > max) { index = maxIndexesBuffer[number]; max = maxValuesBuffer[number]; @@ -515,9 +534,9 @@ static inline void volk_gnsssdr_32f_index_max_32u_neon(uint32_t* target, const f } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { - if(src0[number] > max) + if (src0[number] > max) { index = number; max = src0[number]; @@ -527,7 +546,6 @@ static inline void volk_gnsssdr_32f_index_max_32u_neon(uint32_t* target, const f } } -#endif /*LV_HAVE_NEON*/ +#endif /*LV_HAVE_NEONV7*/ #endif /*INCLUDED_volk_gnsssdr_32f_index_max_32u_H*/ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_resamplerxnpuppet_32f.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_resamplerxnpuppet_32f.h new file mode 100644 index 000000000..5f979c69e --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_resamplerxnpuppet_32f.h @@ -0,0 +1,277 @@ +/*! + * \file volk_gnsssdr_32f_resamplerxnpuppet_32f.h + * \brief VOLK_GNSSSDR puppet for the multiple 32-bit float vector resampler kernel. + * \authors
        + *
      • Cillian O'Driscoll 2017 cillian.odriscoll at gmail dot com + *
      + * + * VOLK_GNSSSDR puppet for integrating the multiple resampler into the test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_32f_resamplerxnpuppet_32f_H +#define INCLUDED_volk_gnsssdr_32f_resamplerxnpuppet_32f_H + +#include "volk_gnsssdr/volk_gnsssdr_32f_xn_resampler_32f_xn.h" +#include +#include +#include +#include + + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_generic(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + + +#endif /* LV_HAVE_GENERIC */ + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_a_sse3(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_a_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + +#ifdef LV_HAVE_SSE3 +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_u_sse3(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_u_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_u_sse4_1(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_u_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + +#ifdef LV_HAVE_SSE4_1 +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_a_sse4_1(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_a_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} + +#endif + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_a_avx(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_a_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_u_avx(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_u_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + +#ifdef LV_HAVE_NEONV7 +static inline void volk_gnsssdr_32f_resamplerxnpuppet_32f_neon(float* result, const float* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + float** result_aux = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32f_xn_resampler_32f_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((float*)result, (float*)result_aux[0], sizeof(float) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + +#endif // INCLUDED_volk_gnsssdr_32f_resamplerpuppet_32f_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_sincos_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_sincos_32fc.h index 6f18fb9d2..9c7f01227 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_sincos_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_sincos_32fc.h @@ -57,9 +57,9 @@ #ifndef INCLUDED_volk_gnsssdr_32f_sincos_32fc_H #define INCLUDED_volk_gnsssdr_32f_sincos_32fc_H -#include #include #include +#include #ifdef LV_HAVE_SSE4_1 #include @@ -97,7 +97,7 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse4_1(lv_32fc_t* out, const f cp4 = _mm_set1_ps(0.49603e-4); cp5 = _mm_set1_ps(0.551e-6); - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { aVal = _mm_loadu_ps(aPtr); __VOLK_GNSSSDR_PREFETCH(aPtr + 8); @@ -108,12 +108,12 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse4_1(lv_32fc_t* out, const f s = _mm_sub_ps(s, _mm_mul_ps(_mm_cvtepi32_ps(r), pio4A)); s = _mm_sub_ps(s, _mm_mul_ps(_mm_cvtepi32_ps(r), pio4B)); - s = _mm_div_ps(s, _mm_set1_ps(8.0)); // The constant is 2^N, for 3 times argument reduction + s = _mm_div_ps(s, _mm_set1_ps(8.0)); // The constant is 2^N, for 3 times argument reduction s = _mm_mul_ps(s, s); // Evaluate Taylor series s = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_sub_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_sub_ps(_mm_mul_ps(s, cp5), cp4), s), cp3), s), cp2), s), cp1), s); - for(i = 0; i < 3; i++) + for (i = 0; i < 3; i++) { s = _mm_mul_ps(s, _mm_sub_ps(ffours, s)); } @@ -145,10 +145,10 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse4_1(lv_32fc_t* out, const f } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { float _in = *aPtr++; - *bPtr++ = lv_cmake(cos(_in), sin(_in)); + *bPtr++ = lv_cmake(cosf(_in), sinf(_in)); } } @@ -191,7 +191,7 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse4_1(lv_32fc_t* out, const f cp4 = _mm_set1_ps(0.49603e-4); cp5 = _mm_set1_ps(0.551e-6); - for(;number < quarterPoints; number++) + for (; number < quarterPoints; number++) { aVal = _mm_load_ps(aPtr); __VOLK_GNSSSDR_PREFETCH(aPtr + 8); @@ -202,12 +202,12 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse4_1(lv_32fc_t* out, const f s = _mm_sub_ps(s, _mm_mul_ps(_mm_cvtepi32_ps(r), pio4A)); s = _mm_sub_ps(s, _mm_mul_ps(_mm_cvtepi32_ps(r), pio4B)); - s = _mm_div_ps(s, _mm_set1_ps(8.0)); // The constant is 2^N, for 3 times argument reduction + s = _mm_div_ps(s, _mm_set1_ps(8.0)); // The constant is 2^N, for 3 times argument reduction s = _mm_mul_ps(s, s); // Evaluate Taylor series s = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_sub_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_sub_ps(_mm_mul_ps(s, cp5), cp4), s), cp3), s), cp2), s), cp1), s); - for(i = 0; i < 3; i++) + for (i = 0; i < 3; i++) { s = _mm_mul_ps(s, _mm_sub_ps(ffours, s)); } @@ -239,10 +239,10 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse4_1(lv_32fc_t* out, const f } number = quarterPoints * 4; - for(;number < num_points; number++) + for (; number < num_points; number++) { float _in = *aPtr++; - *bPtr++ = lv_cmake(cos(_in), sin(_in)); + *bPtr++ = lv_cmake(cosf(_in), sinf(_in)); } } @@ -265,31 +265,49 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse2(lv_32fc_t* out, const flo __m128 sine, cosine, aux, x; __m128 xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y; - __m128i emm0, emm2, emm4; + __m128i emm0, emm2, emm4; /* declare some SSE constants */ - __VOLK_ATTR_ALIGNED(16) static const int _ps_inv_sign_mask[4] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - __VOLK_ATTR_ALIGNED(16) static const int _ps_sign_mask[4] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_inv_sign_mask[4] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_sign_mask[4] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_cephes_FOPI[4] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_1[4] = { 1, 1, 1, 1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_inv1[4] = { ~1, ~1, ~1, ~1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_2[4] = { 2, 2, 2, 2}; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_4[4] = { 4, 4, 4, 4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_cephes_FOPI[4] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_1[4] = {1, 1, 1, 1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_inv1[4] = {~1, ~1, ~1, ~1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_2[4] = {2, 2, 2, 2}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_4[4] = {4, 4, 4, 4}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP1[4] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP2[4] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP3[4] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p0[4] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p1[4] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p2[4] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p0[4] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p1[4] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p2[4] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_0p5[4] = { 0.5f, 0.5f, 0.5f, 0.5f }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_1[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP1[4] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP2[4] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP3[4] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p0[4] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p1[4] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p2[4] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p0[4] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p1[4] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p2[4] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_0p5[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_1[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - for(;number < sse_iters; number++) + for (; number < sse_iters; number++) { x = _mm_load_ps(aPtr); __VOLK_GNSSSDR_PREFETCH(aPtr + 8); @@ -307,19 +325,19 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse2(lv_32fc_t* out, const flo emm2 = _mm_cvttps_epi32(y); /* j=(j+1) & (~1) (see the cephes sources) */ - emm2 = _mm_add_epi32(emm2, *(__m128i *)_pi32_1); - emm2 = _mm_and_si128(emm2, *(__m128i *)_pi32_inv1); + emm2 = _mm_add_epi32(emm2, *(__m128i*)_pi32_1); + emm2 = _mm_and_si128(emm2, *(__m128i*)_pi32_inv1); y = _mm_cvtepi32_ps(emm2); emm4 = emm2; /* get the swap sign flag for the sine */ - emm0 = _mm_and_si128(emm2, *(__m128i *)_pi32_4); + emm0 = _mm_and_si128(emm2, *(__m128i*)_pi32_4); emm0 = _mm_slli_epi32(emm0, 29); __m128 swap_sign_bit_sin = _mm_castsi128_ps(emm0); /* get the polynom selection mask for the sine*/ - emm2 = _mm_and_si128(emm2, *(__m128i *)_pi32_2); + emm2 = _mm_and_si128(emm2, *(__m128i*)_pi32_2); emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128()); __m128 poly_mask = _mm_castsi128_ps(emm2); @@ -335,15 +353,15 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse2(lv_32fc_t* out, const flo x = _mm_add_ps(x, xmm2); x = _mm_add_ps(x, xmm3); - emm4 = _mm_sub_epi32(emm4, *(__m128i *)_pi32_2); - emm4 = _mm_andnot_si128(emm4, *(__m128i *)_pi32_4); + emm4 = _mm_sub_epi32(emm4, *(__m128i*)_pi32_2); + emm4 = _mm_andnot_si128(emm4, *(__m128i*)_pi32_4); emm4 = _mm_slli_epi32(emm4, 29); __m128 sign_bit_cos = _mm_castsi128_ps(emm4); sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); /* Evaluate the first polynom (0 <= x <= Pi/4) */ - __m128 z = _mm_mul_ps(x,x); + __m128 z = _mm_mul_ps(x, x); y = *(__m128*)_ps_coscof_p0; y = _mm_mul_ps(y, z); @@ -371,11 +389,11 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse2(lv_32fc_t* out, const flo xmm3 = poly_mask; __m128 ysin2 = _mm_and_ps(xmm3, y2); __m128 ysin1 = _mm_andnot_ps(xmm3, y); - y2 = _mm_sub_ps(y2,ysin2); + y2 = _mm_sub_ps(y2, ysin2); y = _mm_sub_ps(y, ysin1); - xmm1 = _mm_add_ps(ysin1,ysin2); - xmm2 = _mm_add_ps(y,y2); + xmm1 = _mm_add_ps(ysin1, ysin2); + xmm2 = _mm_add_ps(y, y2); /* update the sign */ sine = _mm_xor_ps(xmm1, sign_bit_sin); @@ -392,12 +410,11 @@ static inline void volk_gnsssdr_32f_sincos_32fc_a_sse2(lv_32fc_t* out, const flo aPtr += 4; } - for(number = sse_iters * 4; number < num_points; number++) + for (number = sse_iters * 4; number < num_points; number++) { _in = *aPtr++; - *bPtr++ = lv_cmake((float)cos(_in), (float)sin(_in) ); + *bPtr++ = lv_cmake((float)cosf(_in), (float)sinf(_in)); } - } #endif /* LV_HAVE_SSE2 */ @@ -418,31 +435,49 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse2(lv_32fc_t* out, const flo __m128 sine, cosine, aux, x; __m128 xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y; - __m128i emm0, emm2, emm4; + __m128i emm0, emm2, emm4; /* declare some SSE constants */ - __VOLK_ATTR_ALIGNED(16) static const int _ps_inv_sign_mask[4] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - __VOLK_ATTR_ALIGNED(16) static const int _ps_sign_mask[4] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_inv_sign_mask[4] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_sign_mask[4] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_cephes_FOPI[4] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_1[4] = { 1, 1, 1, 1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_inv1[4] = { ~1, ~1, ~1, ~1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_2[4] = { 2, 2, 2, 2}; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_4[4] = { 4, 4, 4, 4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_cephes_FOPI[4] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_1[4] = {1, 1, 1, 1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_inv1[4] = {~1, ~1, ~1, ~1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_2[4] = {2, 2, 2, 2}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_4[4] = {4, 4, 4, 4}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP1[4] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP2[4] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP3[4] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p0[4] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p1[4] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p2[4] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p0[4] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p1[4] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p2[4] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_0p5[4] = { 0.5f, 0.5f, 0.5f, 0.5f }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_1[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP1[4] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP2[4] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP3[4] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p0[4] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p1[4] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p2[4] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p0[4] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p1[4] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p2[4] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_0p5[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_1[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - for(;number < sse_iters; number++) + for (; number < sse_iters; number++) { x = _mm_loadu_ps(aPtr); __VOLK_GNSSSDR_PREFETCH(aPtr + 8); @@ -460,19 +495,19 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse2(lv_32fc_t* out, const flo emm2 = _mm_cvttps_epi32(y); /* j=(j+1) & (~1) (see the cephes sources) */ - emm2 = _mm_add_epi32(emm2, *(__m128i *)_pi32_1); - emm2 = _mm_and_si128(emm2, *(__m128i *)_pi32_inv1); + emm2 = _mm_add_epi32(emm2, *(__m128i*)_pi32_1); + emm2 = _mm_and_si128(emm2, *(__m128i*)_pi32_inv1); y = _mm_cvtepi32_ps(emm2); emm4 = emm2; /* get the swap sign flag for the sine */ - emm0 = _mm_and_si128(emm2, *(__m128i *)_pi32_4); + emm0 = _mm_and_si128(emm2, *(__m128i*)_pi32_4); emm0 = _mm_slli_epi32(emm0, 29); __m128 swap_sign_bit_sin = _mm_castsi128_ps(emm0); /* get the polynom selection mask for the sine*/ - emm2 = _mm_and_si128(emm2, *(__m128i *)_pi32_2); + emm2 = _mm_and_si128(emm2, *(__m128i*)_pi32_2); emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128()); __m128 poly_mask = _mm_castsi128_ps(emm2); @@ -488,15 +523,15 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse2(lv_32fc_t* out, const flo x = _mm_add_ps(x, xmm2); x = _mm_add_ps(x, xmm3); - emm4 = _mm_sub_epi32(emm4, *(__m128i *)_pi32_2); - emm4 = _mm_andnot_si128(emm4, *(__m128i *)_pi32_4); + emm4 = _mm_sub_epi32(emm4, *(__m128i*)_pi32_2); + emm4 = _mm_andnot_si128(emm4, *(__m128i*)_pi32_4); emm4 = _mm_slli_epi32(emm4, 29); __m128 sign_bit_cos = _mm_castsi128_ps(emm4); sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); /* Evaluate the first polynom (0 <= x <= Pi/4) */ - __m128 z = _mm_mul_ps(x,x); + __m128 z = _mm_mul_ps(x, x); y = *(__m128*)_ps_coscof_p0; y = _mm_mul_ps(y, z); @@ -524,11 +559,11 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse2(lv_32fc_t* out, const flo xmm3 = poly_mask; __m128 ysin2 = _mm_and_ps(xmm3, y2); __m128 ysin1 = _mm_andnot_ps(xmm3, y); - y2 = _mm_sub_ps(y2,ysin2); + y2 = _mm_sub_ps(y2, ysin2); y = _mm_sub_ps(y, ysin1); - xmm1 = _mm_add_ps(ysin1,ysin2); - xmm2 = _mm_add_ps(y,y2); + xmm1 = _mm_add_ps(ysin1, ysin2); + xmm2 = _mm_add_ps(y, y2); /* update the sign */ sine = _mm_xor_ps(xmm1, sign_bit_sin); @@ -545,12 +580,11 @@ static inline void volk_gnsssdr_32f_sincos_32fc_u_sse2(lv_32fc_t* out, const flo aPtr += 4; } - for(number = sse_iters * 4; number < num_points; number++) + for (number = sse_iters * 4; number < num_points; number++) { _in = *aPtr++; - *bPtr++ = lv_cmake((float)cos(_in), (float)sin(_in) ); + *bPtr++ = lv_cmake((float)cosf(_in), (float)sinf(_in)); } - } #endif /* LV_HAVE_SSE2 */ @@ -561,10 +595,10 @@ static inline void volk_gnsssdr_32f_sincos_32fc_generic(lv_32fc_t* out, const fl { float _in; unsigned int i; - for(i = 0; i < num_points; i++) + for (i = 0; i < num_points; i++) { _in = *in++; - *out++ = lv_cmake((float)cos(_in), (float)sin(_in) ); + *out++ = lv_cmake((float)cosf(_in), (float)sinf(_in)); } } @@ -586,12 +620,12 @@ static inline void volk_gnsssdr_32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, con const int32_t diffbits = bitlength - Nbits; uint32_t ux; unsigned int i; - for(i = 0; i < num_points; i++) + for (i = 0; i < num_points; i++) { _in = *in++; d = (int32_t)floor(_in / TWO_PI + 0.5); _in -= d * TWO_PI; - x = (int32_t) ((float)_in * TWO_TO_THE_31_DIV_PI); + x = (int32_t)((float)_in * TWO_TO_THE_31_DIV_PI); ux = x; sin_index = ux >> diffbits; @@ -601,14 +635,14 @@ static inline void volk_gnsssdr_32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, con cos_index = ux >> diffbits; c = sine_table_10bits[cos_index][0] * (ux >> 1) + sine_table_10bits[cos_index][1]; - *out++ = lv_cmake((float)c, (float)s ); + *out++ = lv_cmake((float)c, (float)s); } } #endif /* LV_HAVE_GENERIC */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include /* Adapted from http://gruntthepeon.free.fr/ssemath/neon_mathfun.h, original code from Julien Pommier */ /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ */ @@ -637,7 +671,7 @@ static inline void volk_gnsssdr_32f_sincos_32fc_neon(lv_32fc_t* out, const float uint32x4_t emm2, poly_mask, sign_mask_sin, sign_mask_cos; - for(;number < neon_iters; number++) + for (; number < neon_iters; number++) { x = vld1q_f32(aPtr); __VOLK_GNSSSDR_PREFETCH(aPtr + 8); @@ -677,7 +711,7 @@ static inline void volk_gnsssdr_32f_sincos_32fc_neon(lv_32fc_t* out, const float /* Evaluate the first polynom (0 <= x <= Pi/4) in y1, and the second polynom (Pi/4 <= x <= 0) in y2 */ - z = vmulq_f32(x,x); + z = vmulq_f32(x, x); y1 = vmulq_n_f32(z, c_coscof_p0); y2 = vmulq_n_f32(z, c_sincof_p0); @@ -706,14 +740,14 @@ static inline void volk_gnsssdr_32f_sincos_32fc_neon(lv_32fc_t* out, const float aPtr += 4; } - for(number = neon_iters * 4; number < num_points; number++) + for (number = neon_iters * 4; number < num_points; number++) { _in = *aPtr++; - *bPtr++ = lv_cmake((float)cos(_in), (float)sin(_in) ); + *bPtr++ = lv_cmake((float)cosf(_in), (float)sinf(_in)); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_32f_sincos_32fc_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn.h new file mode 100644 index 000000000..db878c584 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn.h @@ -0,0 +1,707 @@ +/*! + * \file volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn.h + * \brief VOLK_GNSSSDR kernel: Resamples 1 complex 32-bit float vectors using zero hold resample algorithm + * and produces the delayed replicas by copying and rotating the resulting resampled signal. + * \authors
        + *
      • Cillian O'Driscoll, 2017. cillian.odirscoll(at)gmail.com + *
      • Javier Arribas, 2018. javiarribas(at)gmail.com + *
      + * + * VOLK_GNSSSDR kernel that resamples N 32-bit float vectors using zero hold resample algorithm. + * It is optimized to resample a single GNSS local code signal replica into 1 vector fractional-resampled and fractional-delayed + * and produces the delayed replicas by copying and rotating the resulting resampled signal. + * (i.e. it creates the Early, Prompt, and Late code replicas) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn + * + * \b Overview + * + * Resamples a 32-bit floating point vector , providing \p num_out_vectors outputs. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) + * \endcode + * + * \b Inputs + * \li local_code: Vector to be resampled. + * \li rem_code_phase_chips: Remnant code phase [chips]. + * \li code_phase_step_chips: Phase increment per sample [chips/sample]. + * \li code_phase_rate_step_chips: Phase rate increment per sample [chips/sample^2]. + * \li shifts_chips: Vector of floats that defines the spacing (in chips) between the replicas of \p local_code + * \li code_length_chips: Code length in chips. + * \li num_out_vectors Number of output vectors. + * \li num_points: The number of data values to be in the resampled vector. + * + * \b Outputs + * \li result: Pointer to a vector of pointers where the results will be stored. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_H +#define INCLUDED_volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_H + +#include +#include +#include +#include +#include /* int64_t */ +#include +#include /* abs */ + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_generic(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int local_code_chip_index; + int current_correlator_tap; + unsigned int n; + //first correlator + for (n = 0; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index < 0) local_code_chip_index += (int)code_length_chips * (abs(local_code_chip_index) / code_length_chips + 1); + local_code_chip_index = local_code_chip_index % code_length_chips; + result[0][n] = local_code[local_code_chip_index]; + } + + //adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&result[current_correlator_tap][0], &result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&result[current_correlator_tap][num_points - shift_samples], &result[0][0], shift_samples * sizeof(float)); + } +} + +#endif /*LV_HAVE_GENERIC*/ + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_sse3(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + // int current_correlator_tap; + unsigned int n; + unsigned int k; + int current_correlator_tap; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + const __m128 code_phase_rate_step_chips_reg = _mm_set_ps1(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, aux3, indexnn, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[0]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm_mul_ps(indexn, indexn); + aux3 = _mm_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm_add_ps(aux, aux3); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + + // Correct negative shift + c = _mm_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm_add_ps(c, ones); + i = _mm_cvttps_epi32(aux3); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[0][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} +#endif + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_sse3(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + // int current_correlator_tap; + unsigned int n; + unsigned int k; + int current_correlator_tap; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + const __m128 code_phase_rate_step_chips_reg = _mm_set_ps1(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, aux3, indexnn, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[0]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm_mul_ps(indexn, indexn); + aux3 = _mm_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm_add_ps(aux, aux3); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + + // Correct negative shift + c = _mm_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm_add_ps(c, ones); + i = _mm_cvttps_epi32(aux3); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[0][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_sse4_1(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + // int current_correlator_tap; + unsigned int n; + unsigned int k; + int current_correlator_tap; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + const __m128 code_phase_rate_step_chips_reg = _mm_set_ps1(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, aux3, indexnn, shifts_chips_reg, c, cTrunc, base; + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[0]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm_mul_ps(indexn, indexn); + aux3 = _mm_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm_add_ps(aux, aux3); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // Correct negative shift + c = _mm_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm_add_ps(c, ones); + i = _mm_cvttps_epi32(aux3); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[0][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_sse4_1(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + // int current_correlator_tap; + unsigned int n; + unsigned int k; + int current_correlator_tap; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + const __m128 code_phase_rate_step_chips_reg = _mm_set_ps1(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, aux3, indexnn, shifts_chips_reg, c, cTrunc, base; + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[0]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm_mul_ps(indexn, indexn); + aux3 = _mm_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm_add_ps(aux, aux3); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // Correct negative shift + c = _mm_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm_add_ps(c, ones); + i = _mm_cvttps_epi32(aux3); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[0][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_a_avx(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 ones = _mm256_set1_ps(1.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + const __m256 code_phase_rate_step_chips_reg = _mm256_set1_ps(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn, indexnn; + + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[0]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[0][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm256_mul_ps(indexn, indexn); + aux3 = _mm256_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm256_add_ps(aux, aux3); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // Correct negative shift + c = _mm256_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm256_add_ps(c, ones); + i = _mm256_cvttps_epi32(aux3); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[0][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + + _mm256_zeroupper(); + + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_u_avx(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 ones = _mm256_set1_ps(1.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + const __m256 code_phase_rate_step_chips_reg = _mm256_set1_ps(code_phase_rate_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn, indexnn; + + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[0]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[0][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + indexnn = _mm256_mul_ps(indexn, indexn); + aux3 = _mm256_mul_ps(code_phase_rate_step_chips_reg, indexnn); + aux = _mm256_add_ps(aux, aux3); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // Correct negative shift + c = _mm256_div_ps(aux, code_length_chips_reg_f); + aux3 = _mm256_add_ps(c, ones); + i = _mm256_cvttps_epi32(aux3); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[0][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + + _mm256_zeroupper(); + + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for first tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + code_phase_rate_step_chips * (float)(n * n) + shifts_chips[0] - rem_code_phase_chips); + // Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[0][n] = local_code[local_code_chip_index_]; + } + + // adjacent correlators + unsigned int shift_samples = 0; + for (current_correlator_tap = 1; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shift_samples += (int)round((shifts_chips[current_correlator_tap] - shifts_chips[current_correlator_tap - 1]) / code_phase_step_chips); + memcpy(&_result[current_correlator_tap][0], &_result[0][shift_samples], (num_points - shift_samples) * sizeof(float)); + memcpy(&_result[current_correlator_tap][num_points - shift_samples], &_result[0][0], shift_samples * sizeof(float)); + } +} + +#endif +// +// +//#ifdef LV_HAVE_NEONV7 +//#include +// +//static inline void volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_neon(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +//{ +// float** _result = result; +// const unsigned int neon_iters = num_points / 4; +// int current_correlator_tap; +// unsigned int n; +// unsigned int k; +// const int32x4_t ones = vdupq_n_s32(1); +// const float32x4_t fours = vdupq_n_f32(4.0f); +// const float32x4_t rem_code_phase_chips_reg = vdupq_n_f32(rem_code_phase_chips); +// const float32x4_t code_phase_step_chips_reg = vdupq_n_f32(code_phase_step_chips); +// +// __VOLK_ATTR_ALIGNED(16) +// int32_t local_code_chip_index[4]; +// int32_t local_code_chip_index_; +// +// const int32x4_t zeros = vdupq_n_s32(0); +// const float32x4_t code_length_chips_reg_f = vdupq_n_f32((float)code_length_chips); +// const int32x4_t code_length_chips_reg_i = vdupq_n_s32((int32_t)code_length_chips); +// int32x4_t local_code_chip_index_reg, aux_i, negatives, i; +// float32x4_t aux, aux2, shifts_chips_reg, fi, c, j, cTrunc, base, indexn, reciprocal; +// __VOLK_ATTR_ALIGNED(16) +// const float vec[4] = {0.0f, 1.0f, 2.0f, 3.0f}; +// uint32x4_t igx; +// reciprocal = vrecpeq_f32(code_length_chips_reg_f); +// reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); +// reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! +// float32x4_t n0 = vld1q_f32((float*)vec); +// +// for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) +// { +// shifts_chips_reg = vdupq_n_f32((float)shifts_chips[current_correlator_tap]); +// aux2 = vsubq_f32(shifts_chips_reg, rem_code_phase_chips_reg); +// indexn = n0; +// for (n = 0; n < neon_iters; n++) +// { +// __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][4 * n + 3], 1, 0); +// __VOLK_GNSSSDR_PREFETCH(&local_code_chip_index[4]); +// aux = vmulq_f32(code_phase_step_chips_reg, indexn); +// aux = vaddq_f32(aux, aux2); +// +// //floor +// i = vcvtq_s32_f32(aux); +// fi = vcvtq_f32_s32(i); +// igx = vcgtq_f32(fi, aux); +// j = vcvtq_f32_s32(vandq_s32(vreinterpretq_s32_u32(igx), ones)); +// aux = vsubq_f32(fi, j); +// +// // fmod +// c = vmulq_f32(aux, reciprocal); +// i = vcvtq_s32_f32(c); +// cTrunc = vcvtq_f32_s32(i); +// base = vmulq_f32(cTrunc, code_length_chips_reg_f); +// aux = vsubq_f32(aux, base); +// local_code_chip_index_reg = vcvtq_s32_f32(aux); +// +// negatives = vreinterpretq_s32_u32(vcltq_s32(local_code_chip_index_reg, zeros)); +// aux_i = vandq_s32(code_length_chips_reg_i, negatives); +// local_code_chip_index_reg = vaddq_s32(local_code_chip_index_reg, aux_i); +// +// vst1q_s32((int32_t*)local_code_chip_index, local_code_chip_index_reg); +// +// for (k = 0; k < 4; ++k) +// { +// _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; +// } +// indexn = vaddq_f32(indexn, fours); +// } +// for (n = neon_iters * 4; n < num_points; n++) +// { +// __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][n], 1, 0); +// // resample code for current tap +// local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); +// //Take into account that in multitap correlators, the shifts can be negative! +// if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); +// local_code_chip_index_ = local_code_chip_index_ % code_length_chips; +// _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; +// } +// } +//} +// +//#endif + +#endif /*INCLUDED_volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_resampler_32f_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_resampler_32f_xn.h new file mode 100644 index 000000000..50bdd732c --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32f_xn_resampler_32f_xn.h @@ -0,0 +1,616 @@ +/*! + * \file volk_gnsssdr_32f_xn_resampler_32f_xn.h + * \brief VOLK_GNSSSDR kernel: Resamples N complex 32-bit float vectors using zero hold resample algorithm. + * \authors
        + *
      • Cillian O'Driscoll, 2017. cillian.odirscoll(at)gmail.com + *
      + * + * VOLK_GNSSSDR kernel that resamples N 32-bit float vectors using zero hold resample algorithm. + * It is optimized to resample a single GNSS local code signal replica into N vectors fractional-resampled and fractional-delayed + * (i.e. it creates the Early, Prompt, and Late code replicas) + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_32f_xn_resampler_32f_xn + * + * \b Overview + * + * Resamples a 32-bit floating point vector , providing \p num_out_vectors outputs. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_32f_xn_resampler_32f_xn(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) + * \endcode + * + * \b Inputs + * \li local_code: Vector to be resampled. + * \li rem_code_phase_chips: Remnant code phase [chips]. + * \li code_phase_step_chips: Phase increment per sample [chips/sample]. + * \li shifts_chips: Vector of floats that defines the spacing (in chips) between the replicas of \p local_code + * \li code_length_chips: Code length in chips. + * \li num_out_vectors Number of output vectors. + * \li num_points: The number of data values to be in the resampled vector. + * + * \b Outputs + * \li result: Pointer to a vector of pointers where the results will be stored. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_32f_xn_resampler_32f_xn_H +#define INCLUDED_volk_gnsssdr_32f_xn_resampler_32f_xn_H + +#include +#include +#include +#include +#include /* int64_t */ +#include +#include /* abs */ + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_generic(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + int local_code_chip_index; + int current_correlator_tap; + unsigned int n; + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = 0; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index < 0) local_code_chip_index += (int)code_length_chips * (abs(local_code_chip_index) / code_length_chips + 1); + local_code_chip_index = local_code_chip_index % code_length_chips; + result[current_correlator_tap][n] = local_code[local_code_chip_index]; + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_a_sse3(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_SSE3 +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_u_sse3(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 ones = _mm_set1_ps(1.0f); + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, fi, igx, j, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + i = _mm_cvttps_epi32(aux); + fi = _mm_cvtepi32_ps(i); + igx = _mm_cmpgt_ps(fi, aux); + j = _mm_and_ps(igx, ones); + aux = _mm_sub_ps(fi, j); + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} +#endif + + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_a_sse4_1(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_SSE4_1 +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_u_sse4_1(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int quarterPoints = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m128 fours = _mm_set1_ps(4.0f); + const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); + const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; + int local_code_chip_index_; + + const __m128i zeros = _mm_setzero_si128(); + const __m128 code_length_chips_reg_f = _mm_set_ps1((float)code_length_chips); + const __m128i code_length_chips_reg_i = _mm_set1_epi32((int)code_length_chips); + __m128i local_code_chip_index_reg, aux_i, negatives, i; + __m128 aux, aux2, shifts_chips_reg, c, cTrunc, base; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); + aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); + for (n = 0; n < quarterPoints; n++) + { + aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm_add_ps(aux, aux2); + // floor + aux = _mm_floor_ps(aux); + + // fmod + c = _mm_div_ps(aux, code_length_chips_reg_f); + i = _mm_cvttps_epi32(c); + cTrunc = _mm_cvtepi32_ps(i); + base = _mm_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm_cvtps_epi32(_mm_sub_ps(aux, base)); + + negatives = _mm_cmplt_epi32(local_code_chip_index_reg, zeros); + aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); + _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm_add_ps(indexn, fours); + } + for (n = quarterPoints * 4; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_a_avx(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_AVX +#include +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_u_avx(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_mul_ps(cTrunc, code_length_chips_reg_f); + local_code_chip_index_reg = _mm256_cvttps_epi32(_mm256_sub_ps(aux, base)); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_NEONV7 +#include + +static inline void volk_gnsssdr_32f_xn_resampler_32f_xn_neon(float** result, const float* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + float** _result = result; + const unsigned int neon_iters = num_points / 4; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const int32x4_t ones = vdupq_n_s32(1); + const float32x4_t fours = vdupq_n_f32(4.0f); + const float32x4_t rem_code_phase_chips_reg = vdupq_n_f32(rem_code_phase_chips); + const float32x4_t code_phase_step_chips_reg = vdupq_n_f32(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(16) + int32_t local_code_chip_index[4]; + int32_t local_code_chip_index_; + + const int32x4_t zeros = vdupq_n_s32(0); + const float32x4_t code_length_chips_reg_f = vdupq_n_f32((float)code_length_chips); + const int32x4_t code_length_chips_reg_i = vdupq_n_s32((int32_t)code_length_chips); + int32x4_t local_code_chip_index_reg, aux_i, negatives, i; + float32x4_t aux, aux2, shifts_chips_reg, fi, c, j, cTrunc, base, indexn, reciprocal; + __VOLK_ATTR_ALIGNED(16) + const float vec[4] = {0.0f, 1.0f, 2.0f, 3.0f}; + uint32x4_t igx; + reciprocal = vrecpeq_f32(code_length_chips_reg_f); + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! + float32x4_t n0 = vld1q_f32((float*)vec); + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = vdupq_n_f32((float)shifts_chips[current_correlator_tap]); + aux2 = vsubq_f32(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < neon_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][4 * n + 3], 1, 0); + __VOLK_GNSSSDR_PREFETCH(&local_code_chip_index[4]); + aux = vmulq_f32(code_phase_step_chips_reg, indexn); + aux = vaddq_f32(aux, aux2); + + //floor + i = vcvtq_s32_f32(aux); + fi = vcvtq_f32_s32(i); + igx = vcgtq_f32(fi, aux); + j = vcvtq_f32_s32(vandq_s32(vreinterpretq_s32_u32(igx), ones)); + aux = vsubq_f32(fi, j); + + // fmod + c = vmulq_f32(aux, reciprocal); + i = vcvtq_s32_f32(c); + cTrunc = vcvtq_f32_s32(i); + base = vmulq_f32(cTrunc, code_length_chips_reg_f); + aux = vsubq_f32(aux, base); + local_code_chip_index_reg = vcvtq_s32_f32(aux); + + negatives = vreinterpretq_s32_u32(vcltq_s32(local_code_chip_index_reg, zeros)); + aux_i = vandq_s32(code_length_chips_reg_i, negatives); + local_code_chip_index_reg = vaddq_s32(local_code_chip_index_reg, aux_i); + + vst1q_s32((int32_t*)local_code_chip_index, local_code_chip_index_reg); + + for (k = 0; k < 4; ++k) + { + _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; + } + indexn = vaddq_f32(indexn, fours); + } + for (n = neon_iters * 4; n < num_points; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][n], 1, 0); + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + +#endif /*INCLUDED_volk_gnsssdr_32f_xn_resampler_32f_xn_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn.h new file mode 100644 index 000000000..822742daf --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn.h @@ -0,0 +1,122 @@ +/*! + * \file volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn.h + * \brief VOLK_GNSSSDR kernel: multiplies N complex (32-bit float per component) vectors + * by a common vector, phase rotated and accumulates the results in N float complex outputs. + * \authors
        + *
      • Antonio Ramos 2018. antonio.ramosdet(at)gmail.com + *
      + * + * VOLK_GNSSSDR kernel that multiplies N 32 bits complex vectors by a common vector, which is + * phase-rotated by phase offset and phase increment, and accumulates the results + * in N 32 bits float complex outputs. + * It is optimized to perform the N tap correlation process in GNSS receivers. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn + * + * \b Overview + * + * Rotates and multiplies the reference complex vector with an arbitrary number of other real vectors, + * accumulates the results and stores them in the output vector. + * The rotation is done at a fixed rate per sample, from an initial \p phase offset. + * This function can be used for Doppler wipe-off and multiple correlator. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, const lv_32fc_t phase_inc_rate, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points); + * \endcode + * + * \b Inputs + * \li in_common: Pointer to one of the vectors to be rotated, multiplied and accumulated (reference vector). + * \li phase_inc: Phase increment = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)) + * \li phase_inc_rate: Phase increment rate = lv_cmake(cos(phase_step_rate_rad), sin(phase_step_rate_rad)) + * \li phase: Initial phase = lv_cmake(cos(initial_phase_rad), sin(initial_phase_rad)) + * \li in_a: Pointer to an array of pointers to multiple vectors to be multiplied and accumulated. + * \li num_a_vectors: Number of vectors to be multiplied by the reference vector and accumulated. + * \li num_points: Number of complex values to be multiplied together, accumulated and stored into \p result. + * + * \b Outputs + * \li phase: Final phase. + * \li result: Vector of \p num_a_vectors components with the multiple vectors of \p in_a rotated, multiplied by \p in_common and accumulated. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn_H +#define INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn_H + + +#include +#include +#include +#include +#include + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn_generic(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, const lv_32fc_t phase_inc_rate, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_32fc_t tmp32_1; +#ifdef __cplusplus + lv_32fc_t half_phase_inc_rate = std::sqrt(phase_inc_rate); +#else + lv_32fc_t half_phase_inc_rate = csqrtf(phase_inc_rate); +#endif + lv_32fc_t constant_rotation = phase_inc * half_phase_inc_rate; + lv_32fc_t delta_phase_rate = lv_cmake(1.0f, 0.0f); + int n_vec; + unsigned int n; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] = lv_cmake(0.0f, 0.0f); + } + for (n = 0; n < num_points; n++) + { + tmp32_1 = *in_common++ * (*phase); + // Regenerate phase + if (n % 256 == 0) + { +#ifdef __cplusplus + (*phase) /= std::abs((*phase)); + delta_phase_rate /= std::abs(delta_phase_rate); +#else + (*phase) /= hypotf(lv_creal(*phase), lv_cimag(*phase)); + delta_phase_rate /= hypotf(lv_creal(delta_phase_rate), lv_cimag(delta_phase_rate)); +#endif + } + (*phase) *= (constant_rotation * delta_phase_rate); + delta_phase_rate *= phase_inc_rate; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] += (tmp32_1 * in_a[n_vec][n]); + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + +#endif /* INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc.h new file mode 100644 index 000000000..ac71ab47a --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc.h @@ -0,0 +1,163 @@ +/*! + * \file volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc.h + * \brief Volk puppet for the multiple 16-bit complex dot product kernel. + * \authors
        + *
      • Carles Fernandez Prades 2016 cfernandez at cttc dot cat + *
      + * + * Volk puppet for integrating the resampler into volk's test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc_H +#define INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc_H + +#include "volk_gnsssdr/volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn.h" +#include +#include +#include + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc_generic(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.25; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + lv_32fc_t phase_inc_rate[1]; + phase_inc_rate[0] = lv_cmake(cos(phase_step_rad * 0.001), sin(phase_step_rad * 0.001)); + int n; + int num_a_vectors = 3; + float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); + } + volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn_generic(result, local_code, phase_inc[0], phase_inc_rate[0], phase, (const float**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} +#endif // Generic + +// +//#ifdef LV_HAVE_GENERIC +//static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_generic_reload(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +//{ +// // phases must be normalized. Phase rotator expects a complex exponential input! +// float rem_carrier_phase_in_rad = 0.25; +// float phase_step_rad = 0.1; +// lv_32fc_t phase[1]; +// phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +// lv_32fc_t phase_inc[1]; +// phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +// int n; +// int num_a_vectors = 3; +// float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); +// for (n = 0; n < num_a_vectors; n++) +// { +// in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); +// memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); +// } +// volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); +// +// for (n = 0; n < num_a_vectors; n++) +// { +// volk_gnsssdr_free(in_a[n]); +// } +// volk_gnsssdr_free(in_a); +//} +// +//#endif // Generic +// +//#ifdef LV_HAVE_AVX +//static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_u_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +//{ +// // phases must be normalized. Phase rotator expects a complex exponential input! +// float rem_carrier_phase_in_rad = 0.25; +// float phase_step_rad = 0.1; +// lv_32fc_t phase[1]; +// phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +// lv_32fc_t phase_inc[1]; +// phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +// int n; +// int num_a_vectors = 3; +// float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); +// for (n = 0; n < num_a_vectors; n++) +// { +// in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); +// memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); +// } +// volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_u_avx(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); +// +// for (n = 0; n < num_a_vectors; n++) +// { +// volk_gnsssdr_free(in_a[n]); +// } +// volk_gnsssdr_free(in_a); +//} +// +//#endif // AVX +// +// +//#ifdef LV_HAVE_AVX +//static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_a_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +//{ +// // phases must be normalized. Phase rotator expects a complex exponential input! +// float rem_carrier_phase_in_rad = 0.25; +// float phase_step_rad = 0.1; +// lv_32fc_t phase[1]; +// phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); +// lv_32fc_t phase_inc[1]; +// phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); +// int n; +// int num_a_vectors = 3; +// float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); +// for (n = 0; n < num_a_vectors; n++) +// { +// in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); +// memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); +// } +// volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_a_avx(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); +// +// for (n = 0; n < num_a_vectors; n++) +// { +// volk_gnsssdr_free(in_a[n]); +// } +// volk_gnsssdr_free(in_a); +//} +// +//#endif // AVX + +#endif // INCLUDED_volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h new file mode 100644 index 000000000..c08591deb --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h @@ -0,0 +1,495 @@ +/*! + * \file volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h + * \brief VOLK_GNSSSDR kernel: multiplies N complex (32-bit float per component) vectors + * by a common vector, phase rotated and accumulates the results in N float complex outputs. + * \authors
        + *
      • Cillian O'Driscoll 2016. cillian.odriscoll(at)gmail.com + *
      + * + * VOLK_GNSSSDR kernel that multiplies N 32 bits complex vectors by a common vector, which is + * phase-rotated by phase offset and phase increment, and accumulates the results + * in N 32 bits float complex outputs. + * It is optimized to perform the N tap correlation process in GNSS receivers. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +/*! + * \page volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn + * + * \b Overview + * + * Rotates and multiplies the reference complex vector with an arbitrary number of other real vectors, + * accumulates the results and stores them in the output vector. + * The rotation is done at a fixed rate per sample, from an initial \p phase offset. + * This function can be used for Doppler wipe-off and multiple correlator. + * + * Dispatcher Prototype + * \code + * void volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points); + * \endcode + * + * \b Inputs + * \li in_common: Pointer to one of the vectors to be rotated, multiplied and accumulated (reference vector). + * \li phase_inc: Phase increment = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)) + * \li phase: Initial phase = lv_cmake(cos(initial_phase_rad), sin(initial_phase_rad)) + * \li in_a: Pointer to an array of pointers to multiple vectors to be multiplied and accumulated. + * \li num_a_vectors: Number of vectors to be multiplied by the reference vector and accumulated. + * \li num_points: Number of complex values to be multiplied together, accumulated and stored into \p result. + * + * \b Outputs + * \li phase: Final phase. + * \li result: Vector of \p num_a_vectors components with the multiple vectors of \p in_a rotated, multiplied by \p in_common and accumulated. + * + */ + +#ifndef INCLUDED_volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_H +#define INCLUDED_volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_H + + +#include +#include +#include +#include +#include +//#include + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_generic(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_32fc_t tmp32_1, tmp32_2; + int n_vec; + unsigned int n; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] = lv_cmake(0, 0); + } + for (n = 0; n < num_points; n++) + { + tmp32_1 = *in_common++ * (*phase); //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + + // Regenerate phase + if (n % 256 == 0) + { + //printf("Phase before regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); +#ifdef __cplusplus + (*phase) /= std::abs((*phase)); +#else + (*phase) /= hypotf(lv_creal(*phase), lv_cimag(*phase)); +#endif + //printf("Phase after regeneration %i: %f,%f Modulus: %f\n", n,lv_creal(*phase),lv_cimag(*phase), cabsf(*phase)); + } + + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + tmp32_2 = tmp32_1 * in_a[n_vec][n]; + result[n_vec] += tmp32_2; + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_generic_reload(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points) +{ + lv_32fc_t tmp32_1, tmp32_2; + const unsigned int ROTATOR_RELOAD = 256; + int n_vec; + unsigned int n; + unsigned int j; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + result[n_vec] = lv_cmake(0, 0); + } + + for (n = 0; n < num_points / ROTATOR_RELOAD; n++) + { + for (j = 0; j < ROTATOR_RELOAD; j++) + { + tmp32_1 = *in_common++ * (*phase); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + tmp32_2 = tmp32_1 * in_a[n_vec][n * ROTATOR_RELOAD + j]; + result[n_vec] += tmp32_2; + } + } + /* Regenerate phase */ +#ifdef __cplusplus + (*phase) /= std::abs((*phase)); +#else + //(*phase) /= cabsf((*phase)); + (*phase) /= hypotf(lv_creal(*phase), lv_cimag(*phase)); +#endif + } + + for (j = 0; j < num_points % ROTATOR_RELOAD; j++) + { + tmp32_1 = *in_common++ * (*phase); + (*phase) *= phase_inc; + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) + { + tmp32_2 = tmp32_1 * in_a[n_vec][(num_points / ROTATOR_RELOAD) * ROTATOR_RELOAD + j]; + result[n_vec] += tmp32_2; + } + } +} + +#endif /*LV_HAVE_GENERIC*/ + +#ifdef LV_HAVE_AVX +#include +#include +static inline void volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points) +{ + unsigned int number = 0; + int vec_ind = 0; + unsigned int i = 0; + const unsigned int sixteenthPoints = num_points / 16; + + const float* aPtr = (float*)in_common; + const float* bPtr[num_a_vectors]; + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + bPtr[vec_ind] = in_a[vec_ind]; + } + + lv_32fc_t _phase = (*phase); + lv_32fc_t wo; + + __m256 a0Val, a1Val, a2Val, a3Val; + __m256 b0Val[num_a_vectors], b1Val[num_a_vectors], b2Val[num_a_vectors], b3Val[num_a_vectors]; + __m256 x0Val[num_a_vectors], x1Val[num_a_vectors], x0loVal[num_a_vectors], x0hiVal[num_a_vectors], x1loVal[num_a_vectors], x1hiVal[num_a_vectors]; + __m256 c0Val[num_a_vectors], c1Val[num_a_vectors], c2Val[num_a_vectors], c3Val[num_a_vectors]; + + __m256 dotProdVal0[num_a_vectors]; + __m256 dotProdVal1[num_a_vectors]; + __m256 dotProdVal2[num_a_vectors]; + __m256 dotProdVal3[num_a_vectors]; + + for (vec_ind = 0; vec_ind < num_a_vectors; vec_ind++) + { + dotProdVal0[vec_ind] = _mm256_setzero_ps(); + dotProdVal1[vec_ind] = _mm256_setzero_ps(); + dotProdVal2[vec_ind] = _mm256_setzero_ps(); + dotProdVal3[vec_ind] = _mm256_setzero_ps(); + } + + // Set up the complex rotator + __m256 z0, z1, z2, z3; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t phase_vec[16]; + for (vec_ind = 0; vec_ind < 16; ++vec_ind) + { + phase_vec[vec_ind] = _phase; + _phase *= phase_inc; + } + + z0 = _mm256_load_ps((float*)phase_vec); + z1 = _mm256_load_ps((float*)(phase_vec + 4)); + z2 = _mm256_load_ps((float*)(phase_vec + 8)); + z3 = _mm256_load_ps((float*)(phase_vec + 12)); + + lv_32fc_t dz = phase_inc; + dz *= dz; + dz *= dz; + dz *= dz; + dz *= dz; // dz = phase_inc^16; + + for (vec_ind = 0; vec_ind < 4; ++vec_ind) + { + phase_vec[vec_ind] = dz; + } + + __m256 dz_reg = _mm256_load_ps((float*)phase_vec); + dz_reg = _mm256_complexnormalise_ps(dz_reg); + + for (; number < sixteenthPoints; number++) + { + a0Val = _mm256_loadu_ps(aPtr); + a1Val = _mm256_loadu_ps(aPtr + 8); + a2Val = _mm256_loadu_ps(aPtr + 16); + a3Val = _mm256_loadu_ps(aPtr + 24); + + a0Val = _mm256_complexmul_ps(a0Val, z0); + a1Val = _mm256_complexmul_ps(a1Val, z1); + a2Val = _mm256_complexmul_ps(a2Val, z2); + a3Val = _mm256_complexmul_ps(a3Val, z3); + + z0 = _mm256_complexmul_ps(z0, dz_reg); + z1 = _mm256_complexmul_ps(z1, dz_reg); + z2 = _mm256_complexmul_ps(z2, dz_reg); + z3 = _mm256_complexmul_ps(z3, dz_reg); + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + x0Val[vec_ind] = _mm256_loadu_ps(bPtr[vec_ind]); // t0|t1|t2|t3|t4|t5|t6|t7 + x1Val[vec_ind] = _mm256_loadu_ps(bPtr[vec_ind] + 8); + x0loVal[vec_ind] = _mm256_unpacklo_ps(x0Val[vec_ind], x0Val[vec_ind]); // t0|t0|t1|t1|t4|t4|t5|t5 + x0hiVal[vec_ind] = _mm256_unpackhi_ps(x0Val[vec_ind], x0Val[vec_ind]); // t2|t2|t3|t3|t6|t6|t7|t7 + x1loVal[vec_ind] = _mm256_unpacklo_ps(x1Val[vec_ind], x1Val[vec_ind]); + x1hiVal[vec_ind] = _mm256_unpackhi_ps(x1Val[vec_ind], x1Val[vec_ind]); + + // TODO: it may be possible to rearrange swizzling to better pipeline data + b0Val[vec_ind] = _mm256_permute2f128_ps(x0loVal[vec_ind], x0hiVal[vec_ind], 0x20); // t0|t0|t1|t1|t2|t2|t3|t3 + b1Val[vec_ind] = _mm256_permute2f128_ps(x0loVal[vec_ind], x0hiVal[vec_ind], 0x31); // t4|t4|t5|t5|t6|t6|t7|t7 + b2Val[vec_ind] = _mm256_permute2f128_ps(x1loVal[vec_ind], x1hiVal[vec_ind], 0x20); + b3Val[vec_ind] = _mm256_permute2f128_ps(x1loVal[vec_ind], x1hiVal[vec_ind], 0x31); + + c0Val[vec_ind] = _mm256_mul_ps(a0Val, b0Val[vec_ind]); + c1Val[vec_ind] = _mm256_mul_ps(a1Val, b1Val[vec_ind]); + c2Val[vec_ind] = _mm256_mul_ps(a2Val, b2Val[vec_ind]); + c3Val[vec_ind] = _mm256_mul_ps(a3Val, b3Val[vec_ind]); + + dotProdVal0[vec_ind] = _mm256_add_ps(c0Val[vec_ind], dotProdVal0[vec_ind]); + dotProdVal1[vec_ind] = _mm256_add_ps(c1Val[vec_ind], dotProdVal1[vec_ind]); + dotProdVal2[vec_ind] = _mm256_add_ps(c2Val[vec_ind], dotProdVal2[vec_ind]); + dotProdVal3[vec_ind] = _mm256_add_ps(c3Val[vec_ind], dotProdVal3[vec_ind]); + + bPtr[vec_ind] += 16; + } + + // Force the rotators back onto the unit circle + if ((number % 64) == 0) + { + z0 = _mm256_complexnormalise_ps(z0); + z1 = _mm256_complexnormalise_ps(z1); + z2 = _mm256_complexnormalise_ps(z2); + z3 = _mm256_complexnormalise_ps(z3); + } + + aPtr += 32; + } + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t dotProductVector[4]; + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal1[vec_ind]); + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal2[vec_ind]); + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal3[vec_ind]); + + _mm256_store_ps((float*)dotProductVector, dotProdVal0[vec_ind]); // Store the results back into the dot product vector + + result[vec_ind] = lv_cmake(0, 0); + for (i = 0; i < 4; ++i) + { + result[vec_ind] += dotProductVector[i]; + } + } + + z0 = _mm256_complexnormalise_ps(z0); + _mm256_store_ps((float*)phase_vec, z0); + _phase = phase_vec[0]; + _mm256_zeroupper(); + + number = sixteenthPoints * 16; + for (; number < num_points; number++) + { + wo = (*aPtr++) * _phase; + _phase *= phase_inc; + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + result[vec_ind] += wo * in_a[vec_ind][number]; + } + } + + *phase = _phase; +} + +#endif /* LV_HAVE_AVX */ + + +#ifdef LV_HAVE_AVX +#include +#include +static inline void volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const float** in_a, int num_a_vectors, unsigned int num_points) +{ + unsigned int number = 0; + int vec_ind = 0; + unsigned int i = 0; + const unsigned int sixteenthPoints = num_points / 16; + + const float* aPtr = (float*)in_common; + const float* bPtr[num_a_vectors]; + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + bPtr[vec_ind] = in_a[vec_ind]; + } + + lv_32fc_t _phase = (*phase); + lv_32fc_t wo; + + __m256 a0Val, a1Val, a2Val, a3Val; + __m256 b0Val[num_a_vectors], b1Val[num_a_vectors], b2Val[num_a_vectors], b3Val[num_a_vectors]; + __m256 x0Val[num_a_vectors], x1Val[num_a_vectors], x0loVal[num_a_vectors], x0hiVal[num_a_vectors], x1loVal[num_a_vectors], x1hiVal[num_a_vectors]; + __m256 c0Val[num_a_vectors], c1Val[num_a_vectors], c2Val[num_a_vectors], c3Val[num_a_vectors]; + + __m256 dotProdVal0[num_a_vectors]; + __m256 dotProdVal1[num_a_vectors]; + __m256 dotProdVal2[num_a_vectors]; + __m256 dotProdVal3[num_a_vectors]; + + for (vec_ind = 0; vec_ind < num_a_vectors; vec_ind++) + { + dotProdVal0[vec_ind] = _mm256_setzero_ps(); + dotProdVal1[vec_ind] = _mm256_setzero_ps(); + dotProdVal2[vec_ind] = _mm256_setzero_ps(); + dotProdVal3[vec_ind] = _mm256_setzero_ps(); + } + + // Set up the complex rotator + __m256 z0, z1, z2, z3; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t phase_vec[16]; + for (vec_ind = 0; vec_ind < 16; ++vec_ind) + { + phase_vec[vec_ind] = _phase; + _phase *= phase_inc; + } + + z0 = _mm256_load_ps((float*)phase_vec); + z1 = _mm256_load_ps((float*)(phase_vec + 4)); + z2 = _mm256_load_ps((float*)(phase_vec + 8)); + z3 = _mm256_load_ps((float*)(phase_vec + 12)); + + lv_32fc_t dz = phase_inc; + dz *= dz; + dz *= dz; + dz *= dz; + dz *= dz; // dz = phase_inc^16; + + for (vec_ind = 0; vec_ind < 4; ++vec_ind) + { + phase_vec[vec_ind] = dz; + } + + __m256 dz_reg = _mm256_load_ps((float*)phase_vec); + dz_reg = _mm256_complexnormalise_ps(dz_reg); + + for (; number < sixteenthPoints; number++) + { + a0Val = _mm256_load_ps(aPtr); + a1Val = _mm256_load_ps(aPtr + 8); + a2Val = _mm256_load_ps(aPtr + 16); + a3Val = _mm256_load_ps(aPtr + 24); + + a0Val = _mm256_complexmul_ps(a0Val, z0); + a1Val = _mm256_complexmul_ps(a1Val, z1); + a2Val = _mm256_complexmul_ps(a2Val, z2); + a3Val = _mm256_complexmul_ps(a3Val, z3); + + z0 = _mm256_complexmul_ps(z0, dz_reg); + z1 = _mm256_complexmul_ps(z1, dz_reg); + z2 = _mm256_complexmul_ps(z2, dz_reg); + z3 = _mm256_complexmul_ps(z3, dz_reg); + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + x0Val[vec_ind] = _mm256_loadu_ps(bPtr[vec_ind]); // t0|t1|t2|t3|t4|t5|t6|t7 + x1Val[vec_ind] = _mm256_loadu_ps(bPtr[vec_ind] + 8); + x0loVal[vec_ind] = _mm256_unpacklo_ps(x0Val[vec_ind], x0Val[vec_ind]); // t0|t0|t1|t1|t4|t4|t5|t5 + x0hiVal[vec_ind] = _mm256_unpackhi_ps(x0Val[vec_ind], x0Val[vec_ind]); // t2|t2|t3|t3|t6|t6|t7|t7 + x1loVal[vec_ind] = _mm256_unpacklo_ps(x1Val[vec_ind], x1Val[vec_ind]); + x1hiVal[vec_ind] = _mm256_unpackhi_ps(x1Val[vec_ind], x1Val[vec_ind]); + + // TODO: it may be possible to rearrange swizzling to better pipeline data + b0Val[vec_ind] = _mm256_permute2f128_ps(x0loVal[vec_ind], x0hiVal[vec_ind], 0x20); // t0|t0|t1|t1|t2|t2|t3|t3 + b1Val[vec_ind] = _mm256_permute2f128_ps(x0loVal[vec_ind], x0hiVal[vec_ind], 0x31); // t4|t4|t5|t5|t6|t6|t7|t7 + b2Val[vec_ind] = _mm256_permute2f128_ps(x1loVal[vec_ind], x1hiVal[vec_ind], 0x20); + b3Val[vec_ind] = _mm256_permute2f128_ps(x1loVal[vec_ind], x1hiVal[vec_ind], 0x31); + + c0Val[vec_ind] = _mm256_mul_ps(a0Val, b0Val[vec_ind]); + c1Val[vec_ind] = _mm256_mul_ps(a1Val, b1Val[vec_ind]); + c2Val[vec_ind] = _mm256_mul_ps(a2Val, b2Val[vec_ind]); + c3Val[vec_ind] = _mm256_mul_ps(a3Val, b3Val[vec_ind]); + + dotProdVal0[vec_ind] = _mm256_add_ps(c0Val[vec_ind], dotProdVal0[vec_ind]); + dotProdVal1[vec_ind] = _mm256_add_ps(c1Val[vec_ind], dotProdVal1[vec_ind]); + dotProdVal2[vec_ind] = _mm256_add_ps(c2Val[vec_ind], dotProdVal2[vec_ind]); + dotProdVal3[vec_ind] = _mm256_add_ps(c3Val[vec_ind], dotProdVal3[vec_ind]); + + bPtr[vec_ind] += 16; + } + + // Force the rotators back onto the unit circle + if ((number % 64) == 0) + { + z0 = _mm256_complexnormalise_ps(z0); + z1 = _mm256_complexnormalise_ps(z1); + z2 = _mm256_complexnormalise_ps(z2); + z3 = _mm256_complexnormalise_ps(z3); + } + + aPtr += 32; + } + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t dotProductVector[4]; + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal1[vec_ind]); + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal2[vec_ind]); + dotProdVal0[vec_ind] = _mm256_add_ps(dotProdVal0[vec_ind], dotProdVal3[vec_ind]); + + _mm256_store_ps((float*)dotProductVector, dotProdVal0[vec_ind]); // Store the results back into the dot product vector + + result[vec_ind] = lv_cmake(0, 0); + for (i = 0; i < 4; ++i) + { + result[vec_ind] += dotProductVector[i]; + } + } + + z0 = _mm256_complexnormalise_ps(z0); + _mm256_store_ps((float*)phase_vec, z0); + _phase = phase_vec[0]; + _mm256_zeroupper(); + + number = sixteenthPoints * 16; + for (; number < num_points; number++) + { + wo = (*aPtr++) * _phase; + _phase *= phase_inc; + + for (vec_ind = 0; vec_ind < num_a_vectors; ++vec_ind) + { + result[vec_ind] += wo * in_a[vec_ind][number]; + } + } + + *phase = _phase; +} + + +#endif /* LV_HAVE_AVX */ + +#endif /* INCLUDED_volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc.h new file mode 100644 index 000000000..0a166d97f --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc.h @@ -0,0 +1,161 @@ +/*! + * \file volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc.h + * \brief Volk puppet for the multiple 16-bit complex dot product kernel. + * \authors
        + *
      • Carles Fernandez Prades 2016 cfernandez at cttc dot cat + *
      + * + * Volk puppet for integrating the resampler into volk's test system + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef INCLUDED_volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_H +#define INCLUDED_volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_H + +#include "volk_gnsssdr/volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn.h" +#include +#include +#include + +#ifdef LV_HAVE_GENERIC + +static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_generic(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.25; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); + } + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_generic(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} +#endif // Generic + + +#ifdef LV_HAVE_GENERIC +static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_generic_reload(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.25; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); + } + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // Generic + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_u_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.25; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); + } + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_u_avx(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // AVX + + +#ifdef LV_HAVE_AVX +static inline void volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_a_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const float* in, unsigned int num_points) +{ + // phases must be normalized. Phase rotator expects a complex exponential input! + float rem_carrier_phase_in_rad = 0.25; + float phase_step_rad = 0.1; + lv_32fc_t phase[1]; + phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); + lv_32fc_t phase_inc[1]; + phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); + int n; + int num_a_vectors = 3; + float** in_a = (float**)volk_gnsssdr_malloc(sizeof(float*) * num_a_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_a_vectors; n++) + { + in_a[n] = (float*)volk_gnsssdr_malloc(sizeof(float) * num_points, volk_gnsssdr_get_alignment()); + memcpy((float*)in_a[n], (float*)in, sizeof(float) * num_points); + } + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn_a_avx(result, local_code, phase_inc[0], phase, (const float**)in_a, num_a_vectors, num_points); + + for (n = 0; n < num_a_vectors; n++) + { + volk_gnsssdr_free(in_a[n]); + } + volk_gnsssdr_free(in_a); +} + +#endif // AVX + +#endif // INCLUDED_volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_16ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_16ic.h index c4aeea1a2..ecfe1fb2e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_16ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_16ic.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -56,9 +56,9 @@ #ifndef INCLUDED_volk_gnsssdr_32fc_convert_16ic_H #define INCLUDED_volk_gnsssdr_32fc_convert_16ic_H +#include "volk_gnsssdr/volk_gnsssdr_complex.h" #include #include -#include "volk_gnsssdr/volk_gnsssdr_complex.h" #ifdef LV_HAVE_SSE2 #include @@ -80,10 +80,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_u_sse2(lv_16sc_t* outputVector const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 8); // Clip @@ -99,12 +101,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_u_sse2(lv_16sc_t* outputVector outputVectorPtr += 8; } - for(i = sse_iters * 8; i < num_points * 2; i++) + for (i = sse_iters * 8; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int16_t)rintf(aux); } @@ -128,15 +130,17 @@ static inline void volk_gnsssdr_32fc_convert_16ic_u_sse(lv_16sc_t* outputVector, const float max_val = (float)SHRT_MAX; __m128 inputVal1, inputVal2; - __m128i intInputVal1, intInputVal2; // is __m128i defined in xmmintrin.h? + __m128i intInputVal1, intInputVal2; // is __m128i defined in xmmintrin.h? __m128 ret1, ret2; const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0;i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 8); // Clip @@ -152,18 +156,72 @@ static inline void volk_gnsssdr_32fc_convert_16ic_u_sse(lv_16sc_t* outputVector, outputVectorPtr += 8; } - for(i = sse_iters * 8; i < num_points*2; i++) + for (i = sse_iters * 8; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int16_t)rintf(aux); } } #endif /* LV_HAVE_SSE */ +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_32fc_convert_16ic_u_avx2(lv_16sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + + float* inputVectorPtr = (float*)inputVector; + int16_t* outputVectorPtr = (int16_t*)outputVector; + float aux; + unsigned int i; + const float min_val = (float)SHRT_MIN; ///todo Something off here, compiler does not perform right cast + const float max_val = (float)SHRT_MAX; + + __m256 inputVal1, inputVal2; + __m256i intInputVal1, intInputVal2; + __m256 ret1, ret2; + const __m256 vmin_val = _mm256_set1_ps(min_val); + const __m256 vmax_val = _mm256_set1_ps(max_val); + + for (i = 0; i < avx2_iters; i++) + { + inputVal1 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal2 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 16); + + // Clip + ret1 = _mm256_max_ps(_mm256_min_ps(inputVal1, vmax_val), vmin_val); + ret2 = _mm256_max_ps(_mm256_min_ps(inputVal2, vmax_val), vmin_val); + + intInputVal1 = _mm256_cvtps_epi32(ret1); + intInputVal2 = _mm256_cvtps_epi32(ret2); + + intInputVal1 = _mm256_packs_epi32(intInputVal1, intInputVal2); + intInputVal1 = _mm256_permute4x64_epi64(intInputVal1, 0b11011000); + + _mm256_storeu_si256((__m256i*)outputVectorPtr, intInputVal1); + outputVectorPtr += 16; + } + + for (i = avx2_iters * 16; i < num_points * 2; i++) + { + aux = *inputVectorPtr++; + if (aux > max_val) + aux = max_val; + else if (aux < min_val) + aux = min_val; + *outputVectorPtr++ = (int16_t)rintf(aux); + } +} +#endif /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE2 #include @@ -186,10 +244,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_a_sse2(lv_16sc_t* outputVector const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 8); // Clip @@ -205,12 +265,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_a_sse2(lv_16sc_t* outputVector outputVectorPtr += 8; } - for(i = sse_iters * 8; i < num_points * 2; i++) + for (i = sse_iters * 8; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int16_t)rintf(aux); } @@ -237,10 +297,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_a_sse(lv_16sc_t* outputVector, const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 8); // Clip @@ -256,12 +318,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_a_sse(lv_16sc_t* outputVector, outputVectorPtr += 8; } - for(i = sse_iters * 8; i < num_points * 2; i++) + for (i = sse_iters * 8; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int16_t)rintf(aux); } @@ -269,7 +331,62 @@ static inline void volk_gnsssdr_32fc_convert_16ic_a_sse(lv_16sc_t* outputVector, #endif /* LV_HAVE_SSE */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_32fc_convert_16ic_a_avx2(lv_16sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 8; + + float* inputVectorPtr = (float*)inputVector; + int16_t* outputVectorPtr = (int16_t*)outputVector; + float aux; + unsigned int i; + const float min_val = (float)SHRT_MIN; ///todo Something off here, compiler does not perform right cast + const float max_val = (float)SHRT_MAX; + + __m256 inputVal1, inputVal2; + __m256i intInputVal1, intInputVal2; + __m256 ret1, ret2; + const __m256 vmin_val = _mm256_set1_ps(min_val); + const __m256 vmax_val = _mm256_set1_ps(max_val); + + for (i = 0; i < avx2_iters; i++) + { + inputVal1 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal2 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 16); + + // Clip + ret1 = _mm256_max_ps(_mm256_min_ps(inputVal1, vmax_val), vmin_val); + ret2 = _mm256_max_ps(_mm256_min_ps(inputVal2, vmax_val), vmin_val); + + intInputVal1 = _mm256_cvtps_epi32(ret1); + intInputVal2 = _mm256_cvtps_epi32(ret2); + + intInputVal1 = _mm256_packs_epi32(intInputVal1, intInputVal2); + intInputVal1 = _mm256_permute4x64_epi64(intInputVal1, 0b11011000); + + _mm256_store_si256((__m256i*)outputVectorPtr, intInputVal1); + outputVectorPtr += 16; + } + + for (i = avx2_iters * 16; i < num_points * 2; i++) + { + aux = *inputVectorPtr++; + if (aux > max_val) + aux = max_val; + else if (aux < min_val) + aux = min_val; + *outputVectorPtr++ = (int16_t)rintf(aux); + } +} +#endif /* LV_HAVE_AVX2 */ + + +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_32fc_convert_16ic_neon(lv_16sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) @@ -292,10 +409,12 @@ static inline void volk_gnsssdr_32fc_convert_16ic_neon(lv_16sc_t* outputVector, int16x4_t intInputVal1, intInputVal2; int16x8_t res; - for(i = 0; i < neon_iters; i++) + for (i = 0; i < neon_iters; i++) { - a = vld1q_f32((const float32_t*)(inputVectorPtr)); inputVectorPtr += 4; - b = vld1q_f32((const float32_t*)(inputVectorPtr)); inputVectorPtr += 4; + a = vld1q_f32((const float32_t*)(inputVectorPtr)); + inputVectorPtr += 4; + b = vld1q_f32((const float32_t*)(inputVectorPtr)); + inputVectorPtr += 4; __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 8); ret1 = vmaxq_f32(vminq_f32(a, max_val), min_val); @@ -320,18 +439,18 @@ static inline void volk_gnsssdr_32fc_convert_16ic_neon(lv_16sc_t* outputVector, outputVectorPtr += 8; } - for(i = neon_iters * 8; i < num_points * 2; i++) + for (i = neon_iters * 8; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val_f) + if (aux > max_val_f) aux = max_val_f; - else if(aux < min_val_f) + else if (aux < min_val_f) aux = min_val_f; *outputVectorPtr++ = (int16_t)rintf(aux); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #ifdef LV_HAVE_GENERIC @@ -344,14 +463,14 @@ static inline void volk_gnsssdr_32fc_convert_16ic_generic(lv_16sc_t* outputVecto const float max_val = (float)SHRT_MAX; float aux; unsigned int i; - for(i = 0; i < num_points * 2; i++) + for (i = 0; i < num_points * 2; i++) { aux = *inputVectorPtr++; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; - *outputVectorPtr++ = (int16_t)rintf(aux); + *outputVectorPtr++ = (int16_t)rintf(aux); } } #endif /* LV_HAVE_GENERIC */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_8ic.h old mode 100755 new mode 100644 index b04b1072f..634fdd60e --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_convert_8ic.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -56,10 +56,10 @@ #ifndef INCLUDED_volk_gnsssdr_32fc_convert_8ic_H #define INCLUDED_volk_gnsssdr_32fc_convert_8ic_H -#include -#include -#include #include "volk_gnsssdr/volk_gnsssdr_complex.h" +#include +#include +#include #ifdef LV_HAVE_GENERIC @@ -72,12 +72,12 @@ static inline void volk_gnsssdr_32fc_convert_8ic_generic(lv_8sc_t* outputVector, const float max_val = (float)SCHAR_MAX; float aux; unsigned int i; - for(i = 0; i < num_points * 2; i++) + for (i = 0; i < num_points * 2; i++) { aux = *inputVectorPtr++ * max_val; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int8_t)rintf(aux); } @@ -85,6 +85,154 @@ static inline void volk_gnsssdr_32fc_convert_8ic_generic(lv_8sc_t* outputVector, #endif /* LV_HAVE_GENERIC */ +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_32fc_convert_8ic_u_avx2(lv_8sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 16; + + float* inputVectorPtr = (float*)inputVector; + int8_t* outputVectorPtr = (int8_t*)outputVector; + + const float min_val = (float)SCHAR_MIN; + const float max_val = (float)SCHAR_MAX; + float aux; + unsigned int i; + + __m256 inputVal1, inputVal2, inputVal3, inputVal4; + __m256i intInputVal1, intInputVal2, intInputVal3, intInputVal4; + __m256i int8InputVal; + __m256 ret1, ret2, ret3, ret4; + const __m256 vmin_val = _mm256_set1_ps(min_val); + const __m256 vmax_val = _mm256_set1_ps(max_val); + + for (i = 0; i < avx2_iters; i++) + { + inputVal1 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal2 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal3 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal4 = _mm256_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 32); + + inputVal1 = _mm256_mul_ps(inputVal1, vmax_val); + inputVal2 = _mm256_mul_ps(inputVal2, vmax_val); + inputVal3 = _mm256_mul_ps(inputVal3, vmax_val); + inputVal4 = _mm256_mul_ps(inputVal4, vmax_val); + + // Clip + ret1 = _mm256_max_ps(_mm256_min_ps(inputVal1, vmax_val), vmin_val); + ret2 = _mm256_max_ps(_mm256_min_ps(inputVal2, vmax_val), vmin_val); + ret3 = _mm256_max_ps(_mm256_min_ps(inputVal3, vmax_val), vmin_val); + ret4 = _mm256_max_ps(_mm256_min_ps(inputVal4, vmax_val), vmin_val); + + intInputVal1 = _mm256_cvtps_epi32(ret1); + intInputVal2 = _mm256_cvtps_epi32(ret2); + intInputVal3 = _mm256_cvtps_epi32(ret3); + intInputVal4 = _mm256_cvtps_epi32(ret4); + + intInputVal1 = _mm256_packs_epi32(intInputVal1, intInputVal2); + intInputVal1 = _mm256_permute4x64_epi64(intInputVal1, 0b11011000); + intInputVal2 = _mm256_packs_epi32(intInputVal3, intInputVal4); + intInputVal2 = _mm256_permute4x64_epi64(intInputVal2, 0b11011000); + int8InputVal = _mm256_packs_epi16(intInputVal1, intInputVal2); + int8InputVal = _mm256_permute4x64_epi64(int8InputVal, 0b11011000); + + _mm256_storeu_si256((__m256i*)outputVectorPtr, int8InputVal); + outputVectorPtr += 32; + } + + for (i = avx2_iters * 32; i < num_points * 2; i++) + { + aux = *inputVectorPtr++ * max_val; + if (aux > max_val) + aux = max_val; + else if (aux < min_val) + aux = min_val; + *outputVectorPtr++ = (int8_t)rintf(aux); + } +} +#endif /* LV_HAVE_AVX2 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_32fc_convert_8ic_a_avx2(lv_8sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 16; + + float* inputVectorPtr = (float*)inputVector; + int8_t* outputVectorPtr = (int8_t*)outputVector; + + const float min_val = (float)SCHAR_MIN; + const float max_val = (float)SCHAR_MAX; + float aux; + unsigned int i; + + __m256 inputVal1, inputVal2, inputVal3, inputVal4; + __m256i intInputVal1, intInputVal2, intInputVal3, intInputVal4; + __m256i int8InputVal; + __m256 ret1, ret2, ret3, ret4; + const __m256 vmin_val = _mm256_set1_ps(min_val); + const __m256 vmax_val = _mm256_set1_ps(max_val); + + for (i = 0; i < avx2_iters; i++) + { + inputVal1 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal2 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal3 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + inputVal4 = _mm256_load_ps((float*)inputVectorPtr); + inputVectorPtr += 8; + __VOLK_GNSSSDR_PREFETCH(inputVectorPtr + 32); + + inputVal1 = _mm256_mul_ps(inputVal1, vmax_val); + inputVal2 = _mm256_mul_ps(inputVal2, vmax_val); + inputVal3 = _mm256_mul_ps(inputVal3, vmax_val); + inputVal4 = _mm256_mul_ps(inputVal4, vmax_val); + + // Clip + ret1 = _mm256_max_ps(_mm256_min_ps(inputVal1, vmax_val), vmin_val); + ret2 = _mm256_max_ps(_mm256_min_ps(inputVal2, vmax_val), vmin_val); + ret3 = _mm256_max_ps(_mm256_min_ps(inputVal3, vmax_val), vmin_val); + ret4 = _mm256_max_ps(_mm256_min_ps(inputVal4, vmax_val), vmin_val); + + intInputVal1 = _mm256_cvtps_epi32(ret1); + intInputVal2 = _mm256_cvtps_epi32(ret2); + intInputVal3 = _mm256_cvtps_epi32(ret3); + intInputVal4 = _mm256_cvtps_epi32(ret4); + + intInputVal1 = _mm256_packs_epi32(intInputVal1, intInputVal2); + intInputVal1 = _mm256_permute4x64_epi64(intInputVal1, 0b11011000); + intInputVal2 = _mm256_packs_epi32(intInputVal3, intInputVal4); + intInputVal2 = _mm256_permute4x64_epi64(intInputVal2, 0b11011000); + int8InputVal = _mm256_packs_epi16(intInputVal1, intInputVal2); + int8InputVal = _mm256_permute4x64_epi64(int8InputVal, 0b11011000); + + _mm256_store_si256((__m256i*)outputVectorPtr, int8InputVal); + outputVectorPtr += 32; + } + + for (i = avx2_iters * 32; i < num_points * 2; i++) + { + aux = *inputVectorPtr++ * max_val; + if (aux > max_val) + aux = max_val; + else if (aux < min_val) + aux = min_val; + *outputVectorPtr++ = (int8_t)rintf(aux); + } +} +#endif /* LV_HAVE_AVX2 */ + + #ifdef LV_HAVE_SSE2 #include @@ -107,12 +255,16 @@ static inline void volk_gnsssdr_32fc_convert_8ic_u_sse2(lv_8sc_t* outputVector, const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal3 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal4 = _mm_loadu_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal3 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal4 = _mm_loadu_ps((float*)inputVectorPtr); + inputVectorPtr += 4; inputVal1 = _mm_mul_ps(inputVal1, vmax_val); inputVal2 = _mm_mul_ps(inputVal2, vmax_val); @@ -138,12 +290,12 @@ static inline void volk_gnsssdr_32fc_convert_8ic_u_sse2(lv_8sc_t* outputVector, outputVectorPtr += 16; } - for(i = sse_iters * 16; i < num_points * 2; i++) + for (i = sse_iters * 16; i < num_points * 2; i++) { aux = *inputVectorPtr++ * max_val; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int8_t)rintf(aux); } @@ -173,12 +325,16 @@ static inline void volk_gnsssdr_32fc_convert_8ic_a_sse2(lv_8sc_t* outputVector, const __m128 vmin_val = _mm_set_ps1(min_val); const __m128 vmax_val = _mm_set_ps1(max_val); - for(i = 0; i < sse_iters; i++) + for (i = 0; i < sse_iters; i++) { - inputVal1 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal2 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal3 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; - inputVal4 = _mm_load_ps((float*)inputVectorPtr); inputVectorPtr += 4; + inputVal1 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal2 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal3 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; + inputVal4 = _mm_load_ps((float*)inputVectorPtr); + inputVectorPtr += 4; inputVal1 = _mm_mul_ps(inputVal1, vmax_val); inputVal2 = _mm_mul_ps(inputVal2, vmax_val); @@ -204,12 +360,12 @@ static inline void volk_gnsssdr_32fc_convert_8ic_a_sse2(lv_8sc_t* outputVector, outputVectorPtr += 16; } - for(i = sse_iters * 16; i < num_points * 2; i++) + for (i = sse_iters * 16; i < num_points * 2; i++) { aux = *inputVectorPtr++ * max_val; - if(aux > max_val) + if (aux > max_val) aux = max_val; - else if(aux < min_val) + else if (aux < min_val) aux = min_val; *outputVectorPtr++ = (int8_t)rintf(aux); } @@ -217,7 +373,7 @@ static inline void volk_gnsssdr_32fc_convert_8ic_a_sse2(lv_8sc_t* outputVector, #endif /* LV_HAVE_SSE2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points) @@ -243,9 +399,10 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co int8x8_t res8_1, res8_2; int8x16_t outputVal; - for(i = 0; i < neon_iters; i++) + for (i = 0; i < neon_iters; i++) { - a = vld1q_f32((const float32_t*)inputVectorPtr); inputVectorPtr += 4; + a = vld1q_f32((const float32_t*)inputVectorPtr); + inputVectorPtr += 4; a = vmulq_f32(a, max_val); ret1 = vmaxq_f32(vminq_f32(a, max_val), min_val); sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(ret1), 31))); @@ -254,7 +411,8 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co toint_a = vcvtq_s32_f32(Round); intInputVal1 = vqmovn_s32(toint_a); - a = vld1q_f32((const float32_t*)inputVectorPtr); inputVectorPtr += 4; + a = vld1q_f32((const float32_t*)inputVectorPtr); + inputVectorPtr += 4; a = vmulq_f32(a, max_val); ret1 = vmaxq_f32(vminq_f32(a, max_val), min_val); sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(ret1), 31))); @@ -266,7 +424,8 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co pack16_8_1 = vcombine_s16(intInputVal1, intInputVal2); res8_1 = vqmovn_s16(pack16_8_1); - a = vld1q_f32((const float32_t*)inputVectorPtr); inputVectorPtr += 4; + a = vld1q_f32((const float32_t*)inputVectorPtr); + inputVectorPtr += 4; a = vmulq_f32(a, max_val); ret1 = vmaxq_f32(vminq_f32(a, max_val), min_val); sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(ret1), 31))); @@ -275,7 +434,8 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co toint_a = vcvtq_s32_f32(Round); intInputVal1 = vqmovn_s32(toint_a); - a = vld1q_f32((const float32_t*)inputVectorPtr); inputVectorPtr += 4; + a = vld1q_f32((const float32_t*)inputVectorPtr); + inputVectorPtr += 4; a = vmulq_f32(a, max_val); ret1 = vmaxq_f32(vminq_f32(a, max_val), min_val); sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(ret1), 31))); @@ -293,17 +453,17 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co outputVectorPtr += 16; } - for(i = neon_iters * 16; i < num_points * 2; i++) + for (i = neon_iters * 16; i < num_points * 2; i++) { aux = *inputVectorPtr++ * max_val_f; - if(aux > max_val_f) + if (aux > max_val_f) aux = max_val_f; - else if(aux < min_val_f) + else if (aux < min_val_f) aux = min_val_f; *outputVectorPtr++ = (int8_t)rintf(aux); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_32fc_convert_8ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_resamplerxnpuppet_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_resamplerxnpuppet_32fc.h index c109a1be3..c95091ac0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_resamplerxnpuppet_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_resamplerxnpuppet_32fc.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,67 +36,67 @@ #define INCLUDED_volk_gnsssdr_32fc_resamplerxnpuppet_32fc_H #include "volk_gnsssdr/volk_gnsssdr_32fc_xn_resampler_32fc_xn.h" -#include -#include #include +#include +#include #include - #ifdef LV_HAVE_GENERIC static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_generic(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_generic(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } + #endif /* LV_HAVE_GENERIC */ - + #ifdef LV_HAVE_SSE3 static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -105,27 +105,27 @@ static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_sse3(lv_32fc_t* re #ifdef LV_HAVE_SSE3 static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse3(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -135,27 +135,27 @@ static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_sse3(lv_32fc_t* re #ifdef LV_HAVE_SSE4_1 static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_sse4_1(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -164,27 +164,27 @@ static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_sse4_1(lv_32fc_t* #ifdef LV_HAVE_SSE4_1 static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_sse4_1(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse4_1(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } @@ -193,27 +193,27 @@ static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_sse4_1(lv_32fc_t* #ifdef LV_HAVE_AVX static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_avx(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif @@ -222,58 +222,116 @@ static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_avx(lv_32fc_t* res #ifdef LV_HAVE_AVX static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_avx(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#ifdef LV_HAVE_NEON -static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_neon(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) +#ifdef LV_HAVE_AVX2 +static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_a_avx2(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) { - float code_phase_step_chips = -0.6; - int code_length_chips = 1023; + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); int num_out_vectors = 3; float rem_code_phase_chips = -0.234; - unsigned int n; - float shifts_chips[3] = { -0.1, 0.0, 0.1 }; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; - lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_out_vectors; n++) - { - result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); - } + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx2(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + + +#ifdef LV_HAVE_AVX2 +static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_u_avx2(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } + + volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx2(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); + + memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); + + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } + volk_gnsssdr_free(result_aux); +} +#endif + + +#ifdef LV_HAVE_NEONV7 +static inline void volk_gnsssdr_32fc_resamplerxnpuppet_32fc_neon(lv_32fc_t* result, const lv_32fc_t* local_code, unsigned int num_points) +{ + int code_length_chips = 2046; + float code_phase_step_chips = ((float)(code_length_chips) + 0.1) / ((float)num_points); + int num_out_vectors = 3; + float rem_code_phase_chips = -0.234; + int n; + float shifts_chips[3] = {-0.1, 0.0, 0.1}; + + lv_32fc_t** result_aux = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_out_vectors, volk_gnsssdr_get_alignment()); + for (n = 0; n < num_out_vectors; n++) + { + result_aux[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); + } volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(result_aux, local_code, rem_code_phase_chips, code_phase_step_chips, shifts_chips, code_length_chips, num_out_vectors, num_points); memcpy((lv_32fc_t*)result, (lv_32fc_t*)result_aux[0], sizeof(lv_32fc_t) * num_points); - for(n = 0; n < num_out_vectors; n++) - { - volk_gnsssdr_free(result_aux[n]); - } + for (n = 0; n < num_out_vectors; n++) + { + volk_gnsssdr_free(result_aux[n]); + } volk_gnsssdr_free(result_aux); } #endif -#endif // INCLUDED_volk_gnsssdr_32fc_resamplerpuppet_32fc_H +#endif // INCLUDED_volk_gnsssdr_32fc_resamplerpuppet_32fc_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn.h index 13c9d1986..5701ae041 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -69,12 +69,12 @@ #define INCLUDED_volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_H -#include -#include -#include #include +#include +#include +#include #include -#include + #ifdef LV_HAVE_GENERIC @@ -85,11 +85,11 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic(lv_32fc unsigned int n; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); } for (n = 0; n < num_points; n++) { - tmp32_1 = *in_common++ * (*phase);//if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); + tmp32_1 = *in_common++ * (*phase); //if(n<10 || n >= 8108) printf("generic phase %i: %f,%f\n", n,lv_creal(*phase),lv_cimag(*phase)); // Regenerate phase if (n % 256 == 0) @@ -126,7 +126,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload( unsigned int j; for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - result[n_vec] = lv_cmake(0,0); + result[n_vec] = lv_cmake(0, 0); } for (n = 0; n < num_points / ROTATOR_RELOAD; n++) @@ -141,7 +141,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload( result[n_vec] += tmp32_2; } } - /* Regenerate phase */ + /* Regenerate phase */ #ifdef __cplusplus (*phase) /= std::abs((*phase)); #else @@ -169,7 +169,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload( #include static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_32fc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_32fc_t dotProduct = lv_cmake(0,0); + lv_32fc_t dotProduct = lv_cmake(0, 0); lv_32fc_t tmp32_1, tmp32_2; const unsigned int sse_iters = num_points / 2; int n_vec; @@ -179,7 +179,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ const lv_32fc_t** _in_a = in_a; const lv_32fc_t* _in_common = in_common; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t dotProductVector[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t dotProductVector[2]; __m128* acc = (__m128*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128), volk_gnsssdr_get_alignment()); @@ -191,11 +192,13 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ // phase rotation registers __m128 a, two_phase_acc_reg, two_phase_inc_reg, yl, yh, tmp1, tmp1p, tmp2, tmp2p, z1; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -203,12 +206,12 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ const __m128 ylp = _mm_moveldup_ps(two_phase_inc_reg); const __m128 yhp = _mm_movehdup_ps(two_phase_inc_reg); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { // Phase rotation on operand in_common starts here: a = _mm_loadu_ps((float*)_in_common); - // __VOLK_GNSSSDR_PREFETCH(_in_common + 4); - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + // __VOLK_GNSSSDR_PREFETCH(_in_common + 4); + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr yh = _mm_movehdup_ps(two_phase_acc_reg); tmp1 = _mm_mul_ps(a, yl); tmp1p = _mm_mul_ps(two_phase_acc_reg, ylp); @@ -219,7 +222,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ z1 = _mm_addsub_ps(tmp1, tmp2); two_phase_acc_reg = _mm_addsub_ps(tmp1p, tmp2p); - yl = _mm_moveldup_ps(z1); // Load yl with cr,cr,dr,dr + yl = _mm_moveldup_ps(z1); // Load yl with cr,cr,dr,dr yh = _mm_movehdup_ps(z1); //next two samples @@ -227,7 +230,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_loadu_ps((float*)&(_in_a[n_vec][number*2])); + a = _mm_loadu_ps((float*)&(_in_a[n_vec][number * 2])); tmp1 = _mm_mul_ps(a, yl); a = _mm_shuffle_ps(a, a, 0xB1); tmp2 = _mm_mul_ps(a, yh); @@ -247,8 +250,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - _mm_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 2; ++i) { dotProduct = dotProduct + dotProductVector[i]; @@ -260,7 +263,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); (*phase) = two_phase_acc[0]; - for(n = sse_iters * 2; n < num_points; n++) + for (n = sse_iters * 2; n < num_points; n++) { tmp32_1 = in_common[n] * (*phase); (*phase) *= phase_inc; @@ -278,7 +281,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(lv_32fc_ #include static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_32fc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_32fc_t dotProduct = lv_cmake(0,0); + lv_32fc_t dotProduct = lv_cmake(0, 0); lv_32fc_t tmp32_1, tmp32_2; const unsigned int sse_iters = num_points / 2; int n_vec; @@ -288,7 +291,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ const lv_32fc_t** _in_a = in_a; const lv_32fc_t* _in_common = in_common; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t dotProductVector[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t dotProductVector[2]; __m128* acc = (__m128*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m128), volk_gnsssdr_get_alignment()); @@ -300,11 +304,13 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ // phase rotation registers __m128 a, two_phase_acc_reg, two_phase_inc_reg, yl, yh, tmp1, tmp1p, tmp2, tmp2p, z1; - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_inc[2]; + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_inc[2]; two_phase_inc[0] = phase_inc * phase_inc; two_phase_inc[1] = phase_inc * phase_inc; - two_phase_inc_reg = _mm_load_ps((float*) two_phase_inc); - __VOLK_ATTR_ALIGNED(16) lv_32fc_t two_phase_acc[2]; + two_phase_inc_reg = _mm_load_ps((float*)two_phase_inc); + __VOLK_ATTR_ALIGNED(16) + lv_32fc_t two_phase_acc[2]; two_phase_acc[0] = (*phase); two_phase_acc[1] = (*phase) * phase_inc; two_phase_acc_reg = _mm_load_ps((float*)two_phase_acc); @@ -312,12 +318,12 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ const __m128 ylp = _mm_moveldup_ps(two_phase_inc_reg); const __m128 yhp = _mm_movehdup_ps(two_phase_inc_reg); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { // Phase rotation on operand in_common starts here: a = _mm_load_ps((float*)_in_common); - // __VOLK_GNSSSDR_PREFETCH(_in_common + 4); - yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr + // __VOLK_GNSSSDR_PREFETCH(_in_common + 4); + yl = _mm_moveldup_ps(two_phase_acc_reg); // Load yl with cr,cr,dr,dr yh = _mm_movehdup_ps(two_phase_acc_reg); tmp1 = _mm_mul_ps(a, yl); tmp1p = _mm_mul_ps(two_phase_acc_reg, ylp); @@ -328,7 +334,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ z1 = _mm_addsub_ps(tmp1, tmp2); two_phase_acc_reg = _mm_addsub_ps(tmp1p, tmp2p); - yl = _mm_moveldup_ps(z1); // Load yl with cr,cr,dr,dr + yl = _mm_moveldup_ps(z1); // Load yl with cr,cr,dr,dr yh = _mm_movehdup_ps(z1); //next two samples @@ -336,7 +342,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - a = _mm_load_ps((float*)&(_in_a[n_vec][number*2])); + a = _mm_load_ps((float*)&(_in_a[n_vec][number * 2])); tmp1 = _mm_mul_ps(a, yl); a = _mm_shuffle_ps(a, a, 0xB1); tmp2 = _mm_mul_ps(a, yh); @@ -356,8 +362,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - _mm_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 2; ++i) { dotProduct = dotProduct + dotProductVector[i]; @@ -369,7 +375,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ _mm_store_ps((float*)two_phase_acc, two_phase_acc_reg); (*phase) = two_phase_acc[0]; - for(n = sse_iters * 2; n < num_points; n++) + for (n = sse_iters * 2; n < num_points; n++) { tmp32_1 = in_common[n] * (*phase); (*phase) *= phase_inc; @@ -387,7 +393,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(lv_32fc_ #include static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_32fc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_32fc_t dotProduct = lv_cmake(0,0); + lv_32fc_t dotProduct = lv_cmake(0, 0); lv_32fc_t tmp32_1, tmp32_2; const unsigned int avx_iters = num_points / 4; int n_vec; @@ -398,7 +404,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t const lv_32fc_t* _in_common = in_common; lv_32fc_t _phase = (*phase); - __VOLK_ATTR_ALIGNED(32) lv_32fc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t dotProductVector[4]; __m256* acc = (__m256*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256), volk_gnsssdr_get_alignment()); @@ -431,12 +438,12 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t const __m256 ylp = _mm256_moveldup_ps(four_phase_inc_reg); const __m256 yhp = _mm256_movehdup_ps(four_phase_inc_reg); - for(number = 0; number < avx_iters; number++) + for (number = 0; number < avx_iters; number++) { // Phase rotation on operand in_common starts here: a = _mm256_loadu_ps((float*)_in_common); __VOLK_GNSSSDR_PREFETCH(_in_common + 16); - yl = _mm256_moveldup_ps(four_phase_acc_reg); // Load yl with cr,cr,dr,dr + yl = _mm256_moveldup_ps(four_phase_acc_reg); // Load yl with cr,cr,dr,dr yh = _mm256_movehdup_ps(four_phase_acc_reg); tmp1 = _mm256_mul_ps(a, yl); tmp1p = _mm256_mul_ps(four_phase_acc_reg, ylp); @@ -447,7 +454,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t z = _mm256_addsub_ps(tmp1, tmp2); four_phase_acc_reg = _mm256_addsub_ps(tmp1p, tmp2p); - yl = _mm256_moveldup_ps(z); // Load yl with cr,cr,dr,dr + yl = _mm256_moveldup_ps(z); // Load yl with cr,cr,dr,dr yh = _mm256_movehdup_ps(z); //next two samples @@ -475,8 +482,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - _mm256_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = dotProduct + dotProductVector[i]; @@ -492,10 +499,10 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t four_phase_acc_reg = _mm256_div_ps(four_phase_acc_reg, tmp2); _mm256_store_ps((float*)four_phase_acc, four_phase_acc_reg); - _phase = four_phase_acc[0]; + _phase = four_phase_acc[0]; _mm256_zeroupper(); - for(n = avx_iters * 4; n < num_points; n++) + for (n = avx_iters * 4; n < num_points; n++) { tmp32_1 = *_in_common++ * _phase; _phase *= phase_inc; @@ -514,7 +521,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(lv_32fc_t #include static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_32fc_t** in_a, int num_a_vectors, unsigned int num_points) { - lv_32fc_t dotProduct = lv_cmake(0,0); + lv_32fc_t dotProduct = lv_cmake(0, 0); lv_32fc_t tmp32_1, tmp32_2; const unsigned int avx_iters = num_points / 4; int n_vec; @@ -525,7 +532,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t const lv_32fc_t* _in_common = in_common; lv_32fc_t _phase = (*phase); - __VOLK_ATTR_ALIGNED(32) lv_32fc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t dotProductVector[4]; __m256* acc = (__m256*)volk_gnsssdr_malloc(num_a_vectors * sizeof(__m256), volk_gnsssdr_get_alignment()); @@ -538,7 +546,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t // phase rotation registers __m256 a, four_phase_acc_reg, yl, yh, tmp1, tmp1p, tmp2, tmp2p, z; - __VOLK_ATTR_ALIGNED(32) lv_32fc_t four_phase_inc[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_inc[4]; const lv_32fc_t phase_inc2 = phase_inc * phase_inc; const lv_32fc_t phase_inc3 = phase_inc2 * phase_inc; const lv_32fc_t phase_inc4 = phase_inc3 * phase_inc; @@ -548,7 +557,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t four_phase_inc[3] = phase_inc4; const __m256 four_phase_inc_reg = _mm256_load_ps((float*)four_phase_inc); - __VOLK_ATTR_ALIGNED(32) lv_32fc_t four_phase_acc[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t four_phase_acc[4]; four_phase_acc[0] = _phase; four_phase_acc[1] = _phase * phase_inc; four_phase_acc[2] = _phase * phase_inc2; @@ -558,12 +568,12 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t const __m256 ylp = _mm256_moveldup_ps(four_phase_inc_reg); const __m256 yhp = _mm256_movehdup_ps(four_phase_inc_reg); - for(number = 0; number < avx_iters; number++) + for (number = 0; number < avx_iters; number++) { // Phase rotation on operand in_common starts here: a = _mm256_load_ps((float*)_in_common); __VOLK_GNSSSDR_PREFETCH(_in_common + 16); - yl = _mm256_moveldup_ps(four_phase_acc_reg); // Load yl with cr,cr,dr,dr + yl = _mm256_moveldup_ps(four_phase_acc_reg); // Load yl with cr,cr,dr,dr yh = _mm256_movehdup_ps(four_phase_acc_reg); tmp1 = _mm256_mul_ps(a, yl); tmp1p = _mm256_mul_ps(four_phase_acc_reg, ylp); @@ -574,7 +584,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t z = _mm256_addsub_ps(tmp1, tmp2); four_phase_acc_reg = _mm256_addsub_ps(tmp1p, tmp2p); - yl = _mm256_moveldup_ps(z); // Load yl with cr,cr,dr,dr + yl = _mm256_moveldup_ps(z); // Load yl with cr,cr,dr,dr yh = _mm256_movehdup_ps(z); //next two samples @@ -602,8 +612,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - _mm256_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + _mm256_store_ps((float*)dotProductVector, acc[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = dotProduct + dotProductVector[i]; @@ -619,10 +629,10 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t four_phase_acc_reg = _mm256_div_ps(four_phase_acc_reg, tmp2); _mm256_store_ps((float*)four_phase_acc, four_phase_acc_reg); - _phase = four_phase_acc[0]; + _phase = four_phase_acc[0]; _mm256_zeroupper(); - for(n = avx_iters * 4; n < num_points; n++) + for (n = avx_iters * 4; n < num_points; n++) { tmp32_1 = *_in_common++ * _phase; _phase *= phase_inc; @@ -637,7 +647,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(lv_32fc_t #endif /* LV_HAVE_AVX */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* result, const lv_32fc_t* in_common, const lv_32fc_t phase_inc, lv_32fc_t* phase, const lv_32fc_t** in_a, int num_a_vectors, unsigned int num_points) @@ -646,7 +656,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* int n_vec; int i; unsigned int number; - unsigned int n ; + unsigned int n; const lv_32fc_t** _in_a = in_a; const lv_32fc_t* _in_common = in_common; lv_32fc_t* _out = result; @@ -656,36 +666,41 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* if (neon_iters > 0) { - lv_32fc_t dotProduct = lv_cmake(0,0); + lv_32fc_t dotProduct = lv_cmake(0, 0); float32_t arg_phase0 = cargf(_phase); float32_t arg_phase_inc = cargf(phase_inc); float32_t phase_est; lv_32fc_t ___phase4 = phase_inc * phase_inc * phase_inc * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_real[4] = { lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase4_imag[4] = { lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_real[4] = {lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4), lv_creal(___phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase4_imag[4] = {lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4), lv_cimag(___phase4)}; float32x4_t _phase4_real = vld1q_f32(__phase4_real); float32x4_t _phase4_imag = vld1q_f32(__phase4_imag); - lv_32fc_t phase2 = (lv_32fc_t)(_phase) * phase_inc; + lv_32fc_t phase2 = (lv_32fc_t)(_phase)*phase_inc; lv_32fc_t phase3 = phase2 * phase_inc; lv_32fc_t phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_real[4] = { lv_creal((_phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t __phase_imag[4] = { lv_cimag((_phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_real[4] = {lv_creal((_phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t __phase_imag[4] = {lv_cimag((_phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; float32x4_t _phase_real = vld1q_f32(__phase_real); float32x4_t _phase_imag = vld1q_f32(__phase_imag); - __VOLK_ATTR_ALIGNED(32) lv_32fc_t dotProductVector[4]; + __VOLK_ATTR_ALIGNED(32) + lv_32fc_t dotProductVector[4]; float32x4x2_t a_val, b_val, tmp32_real, tmp32_imag; float32x4x2_t* accumulator1 = (float32x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(float32x4x2_t), volk_gnsssdr_get_alignment()); float32x4x2_t* accumulator2 = (float32x4x2_t*)volk_gnsssdr_malloc(num_a_vectors * sizeof(float32x4x2_t), volk_gnsssdr_get_alignment()); - for(n_vec = 0; n_vec < num_a_vectors; n_vec++) + for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { accumulator1[n_vec].val[0] = vdupq_n_f32(0.0f); accumulator1[n_vec].val[1] = vdupq_n_f32(0.0f); @@ -693,7 +708,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* accumulator2[n_vec].val[1] = vdupq_n_f32(0.0f); } - for(number = 0; number < neon_iters; number++) + for (number = 0; number < neon_iters; number++) { /* load 4 complex numbers (float 32 bits each component) */ b_val = vld2q_f32((float32_t*)_in_common); @@ -728,8 +743,10 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* phase3 = phase2 * phase_inc; phase4 = phase3 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_real[4] = { lv_creal((_phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4) }; - __VOLK_ATTR_ALIGNED(16) float32_t ____phase_imag[4] = { lv_cimag((_phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4) }; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_real[4] = {lv_creal((_phase)), lv_creal(phase2), lv_creal(phase3), lv_creal(phase4)}; + __VOLK_ATTR_ALIGNED(16) + float32_t ____phase_imag[4] = {lv_cimag((_phase)), lv_cimag(phase2), lv_cimag(phase3), lv_cimag(phase4)}; _phase_real = vld1q_f32(____phase_real); _phase_imag = vld1q_f32(____phase_imag); @@ -753,8 +770,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* } for (n_vec = 0; n_vec < num_a_vectors; n_vec++) { - vst2q_f32((float32_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector - dotProduct = lv_cmake(0,0); + vst2q_f32((float32_t*)dotProductVector, accumulator1[n_vec]); // Store the results back into the dot product vector + dotProduct = lv_cmake(0, 0); for (i = 0; i < 4; ++i) { dotProduct = dotProduct + dotProductVector[i]; @@ -770,7 +787,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* _phase = lv_cmake((float32_t)__phase_real[0], (float32_t)__phase_imag[0]); } - for(n = neon_iters * 4; n < num_points; n++) + for (n = neon_iters * 4; n < num_points; n++) { tmp32_1 = in_common[n] * _phase; _phase *= phase_inc; @@ -783,7 +800,6 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(lv_32fc_t* (*phase) = _phase; } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_H */ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc.h index 3072542cf..4d5efcefe 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,12 +36,12 @@ #define INCLUDED_volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_H #include "volk_gnsssdr/volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn.h" -#include #include +#include #include #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -50,17 +50,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic(lv_ phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -71,7 +71,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic(lv_ #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic_reload(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic_reload(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -80,17 +80,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic_rel phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_generic_reload(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -101,7 +101,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_generic_rel #ifdef LV_HAVE_SSE3 -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -110,17 +110,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_sse3(lv_3 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_sse3(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -131,7 +131,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_sse3(lv_3 #ifdef LV_HAVE_SSE3 -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_sse3(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -140,17 +140,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_sse3(lv_3 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_sse3(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -161,7 +161,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_sse3(lv_3 #ifdef LV_HAVE_AVX -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -170,17 +170,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_avx(lv_32 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_u_avx(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -191,7 +191,7 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_u_avx(lv_32 #ifdef LV_HAVE_AVX -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_avx(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -200,17 +200,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_avx(lv_32 phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_a_avx(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } @@ -220,8 +220,8 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_a_avx(lv_32 #endif // AVX -#ifdef LV_HAVE_NEON -static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_neon(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) +#ifdef LV_HAVE_NEONV7 +static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_neon(lv_32fc_t* result, const lv_32fc_t* local_code, const lv_32fc_t* in, unsigned int num_points) { // phases must be normalized. Phase rotator expects a complex exponential input! float rem_carrier_phase_in_rad = 0.25; @@ -230,17 +230,17 @@ static inline void volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc_neon(lv_32f phase[0] = lv_cmake(cos(rem_carrier_phase_in_rad), sin(rem_carrier_phase_in_rad)); lv_32fc_t phase_inc[1]; phase_inc[0] = lv_cmake(cos(phase_step_rad), sin(phase_step_rad)); - unsigned int n; + int n; int num_a_vectors = 3; lv_32fc_t** in_a = (lv_32fc_t**)volk_gnsssdr_malloc(sizeof(lv_32fc_t*) * num_a_vectors, volk_gnsssdr_get_alignment()); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { in_a[n] = (lv_32fc_t*)volk_gnsssdr_malloc(sizeof(lv_32fc_t) * num_points, volk_gnsssdr_get_alignment()); memcpy((lv_32fc_t*)in_a[n], (lv_32fc_t*)in, sizeof(lv_32fc_t) * num_points); } - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(result, local_code, phase_inc[0], phase, (const lv_32fc_t**) in_a, num_a_vectors, num_points); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn_neon(result, local_code, phase_inc[0], phase, (const lv_32fc_t**)in_a, num_a_vectors, num_points); - for(n = 0; n < num_a_vectors; n++) + for (n = 0; n < num_a_vectors; n++) { volk_gnsssdr_free(in_a[n]); } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_xn_resampler_32fc_xn.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_xn_resampler_32fc_xn.h index 9149a0bb9..4335e0722 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_xn_resampler_32fc_xn.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_32fc_xn_resampler_32fc_xn.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -63,10 +63,10 @@ #ifndef INCLUDED_volk_gnsssdr_32fc_xn_resampler_32fc_xn_H #define INCLUDED_volk_gnsssdr_32fc_xn_resampler_32fc_xn_H -#include -#include /* abs */ #include #include +#include +#include /* abs */ #ifdef LV_HAVE_GENERIC @@ -75,7 +75,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_generic(lv_32fc_t** re { int local_code_chip_index; int current_correlator_tap; - int n; + unsigned int n; for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) { for (n = 0; n < num_points; n++) @@ -107,7 +107,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse3(lv_32fc_t** res const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -121,7 +122,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse3(lv_32fc_t** res shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -142,25 +143,25 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse3(lv_32fc_t** res aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } } } -#endif +#endif #ifdef LV_HAVE_SSE3 @@ -177,7 +178,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse3(lv_32fc_t** res const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -191,7 +193,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse3(lv_32fc_t** res shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -212,18 +214,18 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse3(lv_32fc_t** res aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } @@ -245,7 +247,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse4_1(lv_32fc_t** r const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -259,7 +262,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse4_1(lv_32fc_t** r shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -277,25 +280,25 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_sse4_1(lv_32fc_t** r aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } } } -#endif +#endif #ifdef LV_HAVE_SSE4_1 @@ -311,7 +314,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse4_1(lv_32fc_t** r const __m128 rem_code_phase_chips_reg = _mm_set_ps1(rem_code_phase_chips); const __m128 code_phase_step_chips_reg = _mm_set_ps1(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int local_code_chip_index[4]; int local_code_chip_index_; const __m128i zeros = _mm_setzero_si128(); @@ -325,7 +329,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse4_1(lv_32fc_t** r shifts_chips_reg = _mm_set_ps1((float)shifts_chips[current_correlator_tap]); aux2 = _mm_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); __m128 indexn = _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f); - for(n = 0; n < quarterPoints; n++) + for (n = 0; n < quarterPoints; n++) { aux = _mm_mul_ps(code_phase_step_chips_reg, indexn); aux = _mm_add_ps(aux, aux2); @@ -343,18 +347,18 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_sse4_1(lv_32fc_t** r aux_i = _mm_and_si128(code_length_chips_reg_i, negatives); local_code_chip_index_reg = _mm_add_epi32(local_code_chip_index_reg, aux_i); _mm_store_si128((__m128i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = _mm_add_ps(indexn, fours); } - for(n = quarterPoints * 4; n < num_points; n++) + for (n = quarterPoints * 4; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } @@ -377,7 +381,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx(lv_32fc_t** resu const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(32) int local_code_chip_index[8]; + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; int local_code_chip_index_; const __m256 zeros = _mm256_setzero_ps(); @@ -392,7 +397,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx(lv_32fc_t** resu shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < avx_iters; n++) + for (n = 0; n < avx_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); @@ -410,13 +415,13 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx(lv_32fc_t** resu // no negatives c = _mm256_cvtepi32_ps(local_code_chip_index_reg); - negatives = _mm256_cmp_ps(c, zeros, 0x01 ); + negatives = _mm256_cmp_ps(c, zeros, 0x01); aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); aux = _mm256_add_ps(c, aux3); local_code_chip_index_reg = _mm256_cvttps_epi32(aux); _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 8; ++k) + for (k = 0; k < 8; ++k) { _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; } @@ -426,12 +431,12 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx(lv_32fc_t** resu _mm256_zeroupper(); for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) { - for(n = avx_iters * 8; n < num_points; n++) + for (n = avx_iters * 8; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } @@ -454,7 +459,8 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(lv_32fc_t** resu const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(32) int local_code_chip_index[8]; + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; int local_code_chip_index_; const __m256 zeros = _mm256_setzero_ps(); @@ -469,7 +475,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(lv_32fc_t** resu shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < avx_iters; n++) + for (n = 0; n < avx_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); @@ -487,13 +493,13 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(lv_32fc_t** resu // no negatives c = _mm256_cvtepi32_ps(local_code_chip_index_reg); - negatives = _mm256_cmp_ps(c, zeros, 0x01 ); + negatives = _mm256_cmp_ps(c, zeros, 0x01); aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); aux = _mm256_add_ps(c, aux3); local_code_chip_index_reg = _mm256_cvttps_epi32(aux); _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 8; ++k) + for (k = 0; k < 8; ++k) { _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; } @@ -503,12 +509,12 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(lv_32fc_t** resu _mm256_zeroupper(); for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) { - for(n = avx_iters * 8; n < num_points; n++) + for (n = avx_iters * 8; n < num_points; n++) { // resample code for current tap local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); //Take into account that in multitap correlators, the shifts can be negative! - if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1) ; + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); local_code_chip_index_ = local_code_chip_index_ % code_length_chips; _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; } @@ -518,7 +524,165 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx(lv_32fc_t** resu #endif -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_AVX2 +#include +static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_u_avx2(lv_32fc_t** result, const lv_32fc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + lv_32fc_t** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_fmadd_ps(code_phase_step_chips_reg, indexn, aux2); + //aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + //_mm_fmsub_ps(c, code_length_chips_reg_f, aux) + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_fnmadd_ps(cTrunc, code_length_chips_reg_f, aux); + local_code_chip_index_reg = _mm256_cvttps_epi32(base); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_AVX2 +#include +static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_a_avx2(lv_32fc_t** result, const lv_32fc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) +{ + lv_32fc_t** _result = result; + const unsigned int avx_iters = num_points / 8; + int current_correlator_tap; + unsigned int n; + unsigned int k; + const __m256 eights = _mm256_set1_ps(8.0f); + const __m256 rem_code_phase_chips_reg = _mm256_set1_ps(rem_code_phase_chips); + const __m256 code_phase_step_chips_reg = _mm256_set1_ps(code_phase_step_chips); + + __VOLK_ATTR_ALIGNED(32) + int local_code_chip_index[8]; + int local_code_chip_index_; + + const __m256 zeros = _mm256_setzero_ps(); + const __m256 code_length_chips_reg_f = _mm256_set1_ps((float)code_length_chips); + const __m256 n0 = _mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f); + + __m256i local_code_chip_index_reg, i; + __m256 aux, aux2, aux3, shifts_chips_reg, c, cTrunc, base, negatives, indexn; + + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + shifts_chips_reg = _mm256_set1_ps((float)shifts_chips[current_correlator_tap]); + aux2 = _mm256_sub_ps(shifts_chips_reg, rem_code_phase_chips_reg); + indexn = n0; + for (n = 0; n < avx_iters; n++) + { + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][8 * n + 7], 1, 0); + __VOLK_GNSSSDR_PREFETCH_LOCALITY(&local_code_chip_index[8], 1, 3); + aux = _mm256_fmadd_ps(code_phase_step_chips_reg, indexn, aux2); + //aux = _mm256_mul_ps(code_phase_step_chips_reg, indexn); + //aux = _mm256_add_ps(aux, aux2); + // floor + aux = _mm256_floor_ps(aux); + + // fmod + c = _mm256_div_ps(aux, code_length_chips_reg_f); + i = _mm256_cvttps_epi32(c); + cTrunc = _mm256_cvtepi32_ps(i); + base = _mm256_fnmadd_ps(cTrunc, code_length_chips_reg_f, aux); + local_code_chip_index_reg = _mm256_cvttps_epi32(base); + + // no negatives + c = _mm256_cvtepi32_ps(local_code_chip_index_reg); + negatives = _mm256_cmp_ps(c, zeros, 0x01); + aux3 = _mm256_and_ps(code_length_chips_reg_f, negatives); + aux = _mm256_add_ps(c, aux3); + local_code_chip_index_reg = _mm256_cvttps_epi32(aux); + + _mm256_store_si256((__m256i*)local_code_chip_index, local_code_chip_index_reg); + for (k = 0; k < 8; ++k) + { + _result[current_correlator_tap][n * 8 + k] = local_code[local_code_chip_index[k]]; + } + indexn = _mm256_add_ps(indexn, eights); + } + } + _mm256_zeroupper(); + for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) + { + for (n = avx_iters * 8; n < num_points; n++) + { + // resample code for current tap + local_code_chip_index_ = (int)floor(code_phase_step_chips * (float)n + shifts_chips[current_correlator_tap] - rem_code_phase_chips); + //Take into account that in multitap correlators, the shifts can be negative! + if (local_code_chip_index_ < 0) local_code_chip_index_ += (int)code_length_chips * (abs(local_code_chip_index_) / code_length_chips + 1); + local_code_chip_index_ = local_code_chip_index_ % code_length_chips; + _result[current_correlator_tap][n] = local_code[local_code_chip_index_]; + } + } +} + +#endif + + +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** result, const lv_32fc_t* local_code, float rem_code_phase_chips, float code_phase_step_chips, float* shifts_chips, unsigned int code_length_chips, int num_out_vectors, unsigned int num_points) @@ -533,19 +697,21 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** resul const float32x4_t rem_code_phase_chips_reg = vdupq_n_f32(rem_code_phase_chips); const float32x4_t code_phase_step_chips_reg = vdupq_n_f32(code_phase_step_chips); - __VOLK_ATTR_ALIGNED(16) int32_t local_code_chip_index[4]; + __VOLK_ATTR_ALIGNED(16) + int32_t local_code_chip_index[4]; int32_t local_code_chip_index_; const int32x4_t zeros = vdupq_n_s32(0); const float32x4_t code_length_chips_reg_f = vdupq_n_f32((float)code_length_chips); const int32x4_t code_length_chips_reg_i = vdupq_n_s32((int32_t)code_length_chips); - int32x4_t local_code_chip_index_reg, aux_i, negatives, i; + int32x4_t local_code_chip_index_reg, aux_i, negatives, i; float32x4_t aux, aux2, shifts_chips_reg, fi, c, j, cTrunc, base, indexn, reciprocal; - __VOLK_ATTR_ALIGNED(16) const float vec[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + __VOLK_ATTR_ALIGNED(16) + const float vec[4] = {0.0f, 1.0f, 2.0f, 3.0f}; uint32x4_t igx; reciprocal = vrecpeq_f32(code_length_chips_reg_f); reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); - reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! + reciprocal = vmulq_f32(vrecpsq_f32(code_length_chips_reg_f, reciprocal), reciprocal); // this refinement is required! float32x4_t n0 = vld1q_f32((float*)vec); for (current_correlator_tap = 0; current_correlator_tap < num_out_vectors; current_correlator_tap++) @@ -553,7 +719,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** resul shifts_chips_reg = vdupq_n_f32((float)shifts_chips[current_correlator_tap]); aux2 = vsubq_f32(shifts_chips_reg, rem_code_phase_chips_reg); indexn = n0; - for(n = 0; n < neon_iters; n++) + for (n = 0; n < neon_iters; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][4 * n + 3], 1, 0); __VOLK_GNSSSDR_PREFETCH(&local_code_chip_index[4]); @@ -569,7 +735,7 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** resul // fmod c = vmulq_f32(aux, reciprocal); - i = vcvtq_s32_f32(c); + i = vcvtq_s32_f32(c); cTrunc = vcvtq_f32_s32(i); base = vmulq_f32(cTrunc, code_length_chips_reg_f); aux = vsubq_f32(aux, base); @@ -581,13 +747,13 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** resul vst1q_s32((int32_t*)local_code_chip_index, local_code_chip_index_reg); - for(k = 0; k < 4; ++k) + for (k = 0; k < 4; ++k) { _result[current_correlator_tap][n * 4 + k] = local_code[local_code_chip_index[k]]; } indexn = vaddq_f32(indexn, fours); } - for(n = neon_iters * 4; n < num_points; n++) + for (n = neon_iters * 4; n < num_points; n++) { __VOLK_GNSSSDR_PREFETCH_LOCALITY(&_result[current_correlator_tap][n], 1, 0); // resample code for current tap @@ -604,4 +770,3 @@ static inline void volk_gnsssdr_32fc_xn_resampler_32fc_xn_neon(lv_32fc_t** resul #endif /*INCLUDED_volk_gnsssdr_32fc_xn_resampler_32fc_xn_H*/ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_64f_accumulator_64f.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_64f_accumulator_64f.h index e1d577c1e..0af6fff1b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_64f_accumulator_64f.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_64f_accumulator_64f.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -69,11 +69,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_avx(double* result, const unsigned int i; const double* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(32) double tempBuffer[4]; + __VOLK_ATTR_ALIGNED(32) + double tempBuffer[4]; __m256d accumulator = _mm256_setzero_pd(); __m256d aVal = _mm256_setzero_pd(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm256_loadu_pd(aPtr); accumulator = _mm256_add_pd(accumulator, aVal); @@ -82,12 +83,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_avx(double* result, const _mm256_storeu_pd((double*)tempBuffer, accumulator); - for(i = 0; i < 4; ++i) + for (i = 0; i < 4; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 4); ++i) + for (i = 0; i < (num_points % 4); ++i) { returnValue += (*aPtr++); } @@ -100,7 +101,7 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_avx(double* result, const #ifdef LV_HAVE_SSE3 #include -static inline void volk_gnsssdr_64f_accumulator_64f_u_sse3(double* result,const double* inputBuffer, unsigned int num_points) +static inline void volk_gnsssdr_64f_accumulator_64f_u_sse3(double* result, const double* inputBuffer, unsigned int num_points) { double returnValue = 0; const unsigned int sse_iters = num_points / 2; @@ -108,11 +109,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_sse3(double* result,const unsigned int i; const double* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(16) double tempBuffer[2]; + __VOLK_ATTR_ALIGNED(16) + double tempBuffer[2]; __m128d accumulator = _mm_setzero_pd(); __m128d aVal = _mm_setzero_pd(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_loadu_pd(aPtr); accumulator = _mm_add_pd(accumulator, aVal); @@ -121,12 +123,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_sse3(double* result,const _mm_storeu_pd((double*)tempBuffer, accumulator); - for(i = 0; i < 2; ++i) + for (i = 0; i < 2; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 2); ++i) + for (i = 0; i < (num_points % 2); ++i) { returnValue += (*aPtr++); } @@ -138,13 +140,13 @@ static inline void volk_gnsssdr_64f_accumulator_64f_u_sse3(double* result,const #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_64f_accumulator_64f_generic(double* result,const double* inputBuffer, unsigned int num_points) +static inline void volk_gnsssdr_64f_accumulator_64f_generic(double* result, const double* inputBuffer, unsigned int num_points) { const double* aPtr = inputBuffer; double returnValue = 0; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { returnValue += (*aPtr++); } @@ -156,7 +158,7 @@ static inline void volk_gnsssdr_64f_accumulator_64f_generic(double* result,const #ifdef LV_HAVE_AVX #include -static inline void volk_gnsssdr_64f_accumulator_64f_a_avx(double* result,const double* inputBuffer, unsigned int num_points) +static inline void volk_gnsssdr_64f_accumulator_64f_a_avx(double* result, const double* inputBuffer, unsigned int num_points) { double returnValue = 0; const unsigned int sse_iters = num_points / 4; @@ -164,11 +166,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_a_avx(double* result,const d unsigned int i; const double* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(32) double tempBuffer[4]; + __VOLK_ATTR_ALIGNED(32) + double tempBuffer[4]; __m256d accumulator = _mm256_setzero_pd(); __m256d aVal = _mm256_setzero_pd(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm256_load_pd(aPtr); accumulator = _mm256_add_pd(accumulator, aVal); @@ -177,12 +180,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_a_avx(double* result,const d _mm256_store_pd((double*)tempBuffer, accumulator); - for(i = 0; i < 4; ++i) + for (i = 0; i < 4; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 4); ++i) + for (i = 0; i < (num_points % 4); ++i) { returnValue += (*aPtr++); } @@ -195,7 +198,7 @@ static inline void volk_gnsssdr_64f_accumulator_64f_a_avx(double* result,const d #ifdef LV_HAVE_SSE3 #include -static inline void volk_gnsssdr_64f_accumulator_64f_a_sse3(double* result,const double* inputBuffer, unsigned int num_points) +static inline void volk_gnsssdr_64f_accumulator_64f_a_sse3(double* result, const double* inputBuffer, unsigned int num_points) { double returnValue = 0; const unsigned int sse_iters = num_points / 2; @@ -203,11 +206,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_a_sse3(double* result,const unsigned int i; const double* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(16) double tempBuffer[2]; + __VOLK_ATTR_ALIGNED(16) + double tempBuffer[2]; __m128d accumulator = _mm_setzero_pd(); __m128d aVal = _mm_setzero_pd(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_load_pd(aPtr); accumulator = _mm_add_pd(accumulator, aVal); @@ -216,12 +220,12 @@ static inline void volk_gnsssdr_64f_accumulator_64f_a_sse3(double* result,const _mm_store_pd((double*)tempBuffer, accumulator); - for(i = 0; i < 2; ++i) + for (i = 0; i < 2; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 2); ++i) + for (i = 0; i < (num_points % 2); ++i) { returnValue += (*aPtr++); } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_accumulator_s8i.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_accumulator_s8i.h index 99588fca5..8753a7a32 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_accumulator_s8i.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_accumulator_s8i.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -70,11 +70,12 @@ static inline void volk_gnsssdr_8i_accumulator_s8i_u_sse3(char* result, const ch unsigned int i; const char* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(16) char tempBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char tempBuffer[16]; __m128i accumulator = _mm_setzero_si128(); __m128i aVal = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_lddqu_si128((__m128i*)aPtr); accumulator = _mm_add_epi8(accumulator, aVal); @@ -82,12 +83,12 @@ static inline void volk_gnsssdr_8i_accumulator_s8i_u_sse3(char* result, const ch } _mm_storeu_si128((__m128i*)tempBuffer, accumulator); - for(i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) { returnValue += (*aPtr++); } @@ -104,7 +105,7 @@ static inline void volk_gnsssdr_8i_accumulator_s8i_generic(char* result, const c const char* aPtr = inputBuffer; char returnValue = 0; unsigned int number; - for(number = 0;number < num_points; number++) + for (number = 0; number < num_points; number++) { returnValue += (*aPtr++); } @@ -125,24 +126,104 @@ static inline void volk_gnsssdr_8i_accumulator_s8i_a_sse3(char* result, const ch const char* aPtr = inputBuffer; - __VOLK_ATTR_ALIGNED(16) char tempBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char tempBuffer[16]; __m128i accumulator = _mm_setzero_si128(); __m128i aVal = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_load_si128((__m128i*)aPtr); accumulator = _mm_add_epi8(accumulator, aVal); aPtr += 16; } - _mm_store_si128((__m128i*)tempBuffer,accumulator); + _mm_store_si128((__m128i*)tempBuffer, accumulator); - for(i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) { returnValue += tempBuffer[i]; } - for(i = 0; i < (num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) + { + returnValue += (*aPtr++); + } + + *result = returnValue; +} +#endif /* LV_HAVE_SSE3 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_accumulator_s8i_a_avx2(char* result, const char* inputBuffer, unsigned int num_points) +{ + char returnValue = 0; + const unsigned int sse_iters = num_points / 32; + unsigned int number; + unsigned int i; + + const char* aPtr = inputBuffer; + + __VOLK_ATTR_ALIGNED(32) + char tempBuffer[32]; + __m256i accumulator = _mm256_setzero_si256(); + __m256i aVal = _mm256_setzero_si256(); + + for (number = 0; number < sse_iters; number++) + { + aVal = _mm256_load_si256((__m256i*)aPtr); + accumulator = _mm256_add_epi8(accumulator, aVal); + aPtr += 32; + } + _mm256_store_si256((__m256i*)tempBuffer, accumulator); + + for (i = 0; i < 32; ++i) + { + returnValue += tempBuffer[i]; + } + + for (i = 0; i < (num_points % 32); ++i) + { + returnValue += (*aPtr++); + } + + *result = returnValue; +} +#endif /* LV_HAVE_SSE3 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_accumulator_s8i_u_avx2(char* result, const char* inputBuffer, unsigned int num_points) +{ + char returnValue = 0; + const unsigned int sse_iters = num_points / 32; + unsigned int number; + unsigned int i; + const char* aPtr = inputBuffer; + + __VOLK_ATTR_ALIGNED(32) + char tempBuffer[32]; + __m256i accumulator = _mm256_setzero_si256(); + __m256i aVal = _mm256_setzero_si256(); + + for (number = 0; number < sse_iters; number++) + { + aVal = _mm256_lddqu_si256((__m256i*)aPtr); + accumulator = _mm256_add_epi8(accumulator, aVal); + aPtr += 32; + } + _mm256_storeu_si256((__m256i*)tempBuffer, accumulator); + + for (i = 0; i < 32; ++i) + { + returnValue += tempBuffer[i]; + } + + for (i = 0; i < (num_points % 32); ++i) { returnValue += (*aPtr++); } @@ -169,4 +250,3 @@ static inline void volk_gnsssdr_8i_accumulator_s8i_u_orc(char* result, const cha #endif /* LV_HAVE_ORC */ #endif /* INCLUDED_volk_gnsssdr_8i_accumulator_s8i_H */ - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_index_max_16u.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_index_max_16u.h index 75ad588d2..08fdcff80 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_index_max_16u.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_index_max_16u.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -58,12 +58,78 @@ #include + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_index_max_16u_u_avx2(unsigned int* target, const char* src0, unsigned int num_points) +{ + if (num_points > 0) + { + const unsigned int avx2_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* basePtr = (char*)src0; + char* inputPtr = (char*)src0; + char max = src0[0]; + unsigned int index = 0; + unsigned int mask; + __VOLK_ATTR_ALIGNED(32) + char currentValuesBuffer[32]; + __m256i maxValues, compareResults, currentValues; + + maxValues = _mm256_set1_epi8(max); + + for (number = 0; number < avx2_iters; number++) + { + currentValues = _mm256_loadu_si256((__m256i*)inputPtr); + compareResults = _mm256_cmpgt_epi8(maxValues, currentValues); + mask = _mm256_movemask_epi8(compareResults); + + if (mask != 0xFFFFFFFF) + { + _mm256_storeu_si256((__m256i*)¤tValuesBuffer, currentValues); + mask = ~mask; + i = 0; + while (mask > 0) + { + if ((mask & 1) == 1) + { + if (currentValuesBuffer[i] > max) + { + index = inputPtr - basePtr + i; + max = currentValuesBuffer[i]; + } + } + i++; + mask >>= 1; + } + maxValues = _mm256_set1_epi8(max); + } + inputPtr += 32; + } + + for (i = 0; i < (num_points % 32); ++i) + { + if (src0[i] > max) + { + index = i; + max = src0[i]; + } + } + target[0] = index; + } +} + +#endif /*LV_HAVE_AVX2*/ + + #ifdef LV_HAVE_AVX #include static inline void volk_gnsssdr_8i_index_max_16u_u_avx(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 32; unsigned int number; @@ -72,33 +138,34 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_avx(unsigned int* target, con char* inputPtr = (char*)src0; char max = src0[0]; unsigned int index = 0; - __VOLK_ATTR_ALIGNED(32) char currentValuesBuffer[32]; + __VOLK_ATTR_ALIGNED(32) + char currentValuesBuffer[32]; __m256i ones, compareResults, currentValues; __m128i compareResultslo, compareResultshi, maxValues, lo, hi; ones = _mm256_set1_epi8(0xFF); maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm256_lddqu_si256((__m256i*)inputPtr); + currentValues = _mm256_lddqu_si256((__m256i*)inputPtr); lo = _mm256_castsi256_si128(currentValues); - hi = _mm256_extractf128_si256(currentValues,1); + hi = _mm256_extractf128_si256(currentValues, 1); compareResultslo = _mm_cmpgt_epi8(maxValues, lo); compareResultshi = _mm_cmpgt_epi8(maxValues, hi); //compareResults = _mm256_set_m128i(compareResultshi , compareResultslo); //not defined in some versions of immintrin.h - compareResults = _mm256_insertf128_si256(_mm256_castsi128_si256(compareResultslo),(compareResultshi),1); + compareResults = _mm256_insertf128_si256(_mm256_castsi128_si256(compareResultslo), (compareResultshi), 1); if (!_mm256_testc_si256(compareResults, ones)) { _mm256_storeu_si256((__m256i*)¤tValuesBuffer, currentValues); - for(i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -110,9 +177,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_avx(unsigned int* target, con inputPtr += 32; } - for(i = 0; i<(num_points % 32); ++i) + for (i = 0; i < (num_points % 32); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -130,7 +197,7 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_avx(unsigned int* target, con static inline void volk_gnsssdr_8i_index_max_16u_u_sse4_1(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -139,14 +206,15 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse4_1(unsigned int* target, char* inputPtr = (char*)src0; char max = src0[0]; unsigned int index = 0; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_lddqu_si128((__m128i*)inputPtr); + currentValues = _mm_lddqu_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); @@ -154,9 +222,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse4_1(unsigned int* target, { _mm_storeu_si128((__m128i*)¤tValuesBuffer, currentValues); - for(i = 0; i < 16; i++) + for (i = 0; i < 16; i++) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -168,9 +236,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse4_1(unsigned int* target, inputPtr += 16; } - for(i = 0; i<(num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -184,11 +252,11 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse4_1(unsigned int* target, #ifdef LV_HAVE_SSE2 -#include +#include static inline void volk_gnsssdr_8i_index_max_16u_u_sse2(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -198,14 +266,15 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse2(unsigned int* target, co char max = src0[0]; unsigned int index = 0; unsigned short mask; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_loadu_si128((__m128i*)inputPtr); + currentValues = _mm_loadu_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); mask = _mm_movemask_epi8(compareResults); @@ -218,7 +287,7 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse2(unsigned int* target, co { if ((mask & 1) == 1) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -232,9 +301,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse2(unsigned int* target, co inputPtr += 16; } - for(i = 0; i<(num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -251,14 +320,14 @@ static inline void volk_gnsssdr_8i_index_max_16u_u_sse2(unsigned int* target, co static inline void volk_gnsssdr_8i_index_max_16u_generic(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { char max = src0[0]; unsigned int index = 0; unsigned int i; - for(i = 1; i < num_points; ++i) + for (i = 1; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -271,12 +340,77 @@ static inline void volk_gnsssdr_8i_index_max_16u_generic(unsigned int* target, c #endif /*LV_HAVE_GENERIC*/ +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_index_max_16u_a_avx2(unsigned int* target, const char* src0, unsigned int num_points) +{ + if (num_points > 0) + { + const unsigned int avx2_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* basePtr = (char*)src0; + char* inputPtr = (char*)src0; + char max = src0[0]; + unsigned int index = 0; + unsigned int mask; + __VOLK_ATTR_ALIGNED(32) + char currentValuesBuffer[32]; + __m256i maxValues, compareResults, currentValues; + + maxValues = _mm256_set1_epi8(max); + + for (number = 0; number < avx2_iters; number++) + { + currentValues = _mm256_load_si256((__m256i*)inputPtr); + compareResults = _mm256_cmpgt_epi8(maxValues, currentValues); + mask = _mm256_movemask_epi8(compareResults); + + if (mask != 0xFFFFFFFF) + { + _mm256_store_si256((__m256i*)¤tValuesBuffer, currentValues); + mask = ~mask; + i = 0; + while (mask > 0) + { + if ((mask & 1) == 1) + { + if (currentValuesBuffer[i] > max) + { + index = inputPtr - basePtr + i; + max = currentValuesBuffer[i]; + } + } + i++; + mask >>= 1; + } + maxValues = _mm256_set1_epi8(max); + } + inputPtr += 32; + } + + for (i = 0; i < (num_points % 32); ++i) + { + if (src0[i] > max) + { + index = i; + max = src0[i]; + } + } + target[0] = index; + } +} + +#endif /*LV_HAVE_AVX2*/ + + #ifdef LV_HAVE_AVX #include static inline void volk_gnsssdr_8i_index_max_16u_a_avx(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 32; unsigned int number; @@ -285,19 +419,20 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_avx(unsigned int* target, con char* inputPtr = (char*)src0; char max = src0[0]; unsigned int index = 0; - __VOLK_ATTR_ALIGNED(32) char currentValuesBuffer[32]; + __VOLK_ATTR_ALIGNED(32) + char currentValuesBuffer[32]; __m256i ones, compareResults, currentValues; __m128i compareResultslo, compareResultshi, maxValues, lo, hi; ones = _mm256_set1_epi8(0xFF); maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm256_load_si256((__m256i*)inputPtr); + currentValues = _mm256_load_si256((__m256i*)inputPtr); lo = _mm256_castsi256_si128(currentValues); - hi = _mm256_extractf128_si256(currentValues,1); + hi = _mm256_extractf128_si256(currentValues, 1); compareResultslo = _mm_cmpgt_epi8(maxValues, lo); compareResultshi = _mm_cmpgt_epi8(maxValues, hi); @@ -309,9 +444,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_avx(unsigned int* target, con { _mm256_store_si256((__m256i*)¤tValuesBuffer, currentValues); - for(i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -323,9 +458,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_avx(unsigned int* target, con inputPtr += 32; } - for(i = 0; i<(num_points % 32); ++i) + for (i = 0; i < (num_points % 32); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -343,7 +478,7 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_avx(unsigned int* target, con static inline void volk_gnsssdr_8i_index_max_16u_a_sse4_1(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -352,14 +487,15 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse4_1(unsigned int* target, char* inputPtr = (char*)src0; char max = src0[0]; unsigned int index = 0; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_load_si128((__m128i*)inputPtr); + currentValues = _mm_load_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); @@ -367,9 +503,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse4_1(unsigned int* target, { _mm_store_si128((__m128i*)¤tValuesBuffer, currentValues); - for(i = 0; i < 16; i++) + for (i = 0; i < 16; i++) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -381,9 +517,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse4_1(unsigned int* target, inputPtr += 16; } - for(i = 0; i<(num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; @@ -401,7 +537,7 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse4_1(unsigned int* target, static inline void volk_gnsssdr_8i_index_max_16u_a_sse2(unsigned int* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -411,14 +547,15 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse2(unsigned int* target, co char max = src0[0]; unsigned int index = 0; unsigned short mask; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_load_si128((__m128i*)inputPtr); + currentValues = _mm_load_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); mask = _mm_movemask_epi8(compareResults); @@ -431,7 +568,7 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse2(unsigned int* target, co { if ((mask & 1) == 1) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { index = inputPtr - basePtr + i; max = currentValuesBuffer[i]; @@ -445,9 +582,9 @@ static inline void volk_gnsssdr_8i_index_max_16u_a_sse2(unsigned int* target, co inputPtr += 16; } - for(i = 0; i<(num_points % 16); ++i) + for (i = 0; i < (num_points % 16); ++i) { - if(src0[i] > max) + if (src0[i] > max) { index = i; max = src0[i]; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_max_s8i.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_max_s8i.h index 2e3bad400..dffe14c12 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_max_s8i.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_max_s8i.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -58,26 +58,77 @@ #include +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_max_s8i_u_avx2(char* target, const char* src0, unsigned int num_points) +{ + if (num_points > 0) + { + const unsigned int avx_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* inputPtr = (char*)src0; + char max = src0[0]; + __VOLK_ATTR_ALIGNED(32) + char maxValuesBuffer[32]; + __m256i maxValues, compareResults, currentValues; + + maxValues = _mm256_set1_epi8(max); + + for (number = 0; number < avx_iters; number++) + { + currentValues = _mm256_loadu_si256((__m256i*)inputPtr); + compareResults = _mm256_max_epi8(maxValues, currentValues); + maxValues = compareResults; + inputPtr += 32; + } + + _mm256_storeu_si256((__m256i*)maxValuesBuffer, maxValues); + + for (i = 0; i < 32; ++i) + { + if (maxValuesBuffer[i] > max) + { + max = maxValuesBuffer[i]; + } + } + + for (i = avx_iters * 32; i < num_points; ++i) + { + if (src0[i] > max) + { + max = src0[i]; + } + } + target[0] = max; + } +} + +#endif /*LV_HAVE_SSE4_1*/ + + #ifdef LV_HAVE_SSE4_1 #include static inline void volk_gnsssdr_8i_max_s8i_u_sse4_1(char* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; unsigned int i; char* inputPtr = (char*)src0; char max = src0[0]; - __VOLK_ATTR_ALIGNED(16) char maxValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char maxValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_loadu_si128((__m128i*)inputPtr); + currentValues = _mm_loadu_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); maxValues = _mm_blendv_epi8(currentValues, maxValues, compareResults); inputPtr += 16; @@ -85,17 +136,17 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse4_1(char* target, const char* sr _mm_storeu_si128((__m128i*)maxValuesBuffer, maxValues); - for(i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) { - if(maxValuesBuffer[i] > max) + if (maxValuesBuffer[i] > max) { max = maxValuesBuffer[i]; } } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { max = src0[i]; } @@ -108,11 +159,11 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse4_1(char* target, const char* sr #ifdef LV_HAVE_SSE2 -#include +#include static inline void volk_gnsssdr_8i_max_s8i_u_sse2(char* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -120,14 +171,15 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse2(char* target, const char* src0 char* inputPtr = (char*)src0; char max = src0[0]; unsigned short mask; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_loadu_si128((__m128i*)inputPtr); + currentValues = _mm_loadu_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); mask = _mm_movemask_epi8(compareResults); @@ -140,7 +192,7 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse2(char* target, const char* src0 { if ((mask & 1) == 1) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { max = currentValuesBuffer[i]; } @@ -153,9 +205,9 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse2(char* target, const char* src0 inputPtr += 16; } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { max = src0[i]; } @@ -171,13 +223,13 @@ static inline void volk_gnsssdr_8i_max_s8i_u_sse2(char* target, const char* src0 static inline void volk_gnsssdr_8i_max_s8i_generic(char* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { char max = src0[0]; unsigned int i; - for(i = 1; i < num_points; ++i) + for (i = 1; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { max = src0[i]; } @@ -194,21 +246,22 @@ static inline void volk_gnsssdr_8i_max_s8i_generic(char* target, const char* src static inline void volk_gnsssdr_8i_max_s8i_a_sse4_1(char* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; unsigned int i; char* inputPtr = (char*)src0; char max = src0[0]; - __VOLK_ATTR_ALIGNED(16) char maxValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char maxValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_load_si128((__m128i*)inputPtr); + currentValues = _mm_load_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); maxValues = _mm_blendv_epi8(currentValues, maxValues, compareResults); inputPtr += 16; @@ -216,17 +269,67 @@ static inline void volk_gnsssdr_8i_max_s8i_a_sse4_1(char* target, const char* sr _mm_store_si128((__m128i*)maxValuesBuffer, maxValues); - for(i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) { - if(maxValuesBuffer[i] > max) + if (maxValuesBuffer[i] > max) { max = maxValuesBuffer[i]; } } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) + { + max = src0[i]; + } + } + target[0] = max; + } +} + +#endif /*LV_HAVE_SSE4_1*/ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_max_s8i_a_avx2(char* target, const char* src0, unsigned int num_points) +{ + if (num_points > 0) + { + const unsigned int avx_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* inputPtr = (char*)src0; + char max = src0[0]; + __VOLK_ATTR_ALIGNED(32) + char maxValuesBuffer[32]; + __m256i maxValues, compareResults, currentValues; + + maxValues = _mm256_set1_epi8(max); + + for (number = 0; number < avx_iters; number++) + { + currentValues = _mm256_load_si256((__m256i*)inputPtr); + compareResults = _mm256_max_epi8(maxValues, currentValues); + maxValues = compareResults; //_mm256_blendv_epi8(currentValues, maxValues, compareResults); + inputPtr += 32; + } + + _mm256_store_si256((__m256i*)maxValuesBuffer, maxValues); + + for (i = 0; i < 32; ++i) + { + if (maxValuesBuffer[i] > max) + { + max = maxValuesBuffer[i]; + } + } + + for (i = avx_iters * 32; i < num_points; ++i) + { + if (src0[i] > max) { max = src0[i]; } @@ -243,7 +346,7 @@ static inline void volk_gnsssdr_8i_max_s8i_a_sse4_1(char* target, const char* sr static inline void volk_gnsssdr_8i_max_s8i_a_sse2(char* target, const char* src0, unsigned int num_points) { - if(num_points > 0) + if (num_points > 0) { const unsigned int sse_iters = num_points / 16; unsigned int number; @@ -251,14 +354,15 @@ static inline void volk_gnsssdr_8i_max_s8i_a_sse2(char* target, const char* src0 char* inputPtr = (char*)src0; char max = src0[0]; unsigned short mask; - __VOLK_ATTR_ALIGNED(16) char currentValuesBuffer[16]; + __VOLK_ATTR_ALIGNED(16) + char currentValuesBuffer[16]; __m128i maxValues, compareResults, currentValues; maxValues = _mm_set1_epi8(max); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { - currentValues = _mm_load_si128((__m128i*)inputPtr); + currentValues = _mm_load_si128((__m128i*)inputPtr); compareResults = _mm_cmpgt_epi8(maxValues, currentValues); mask = _mm_movemask_epi8(compareResults); @@ -271,7 +375,7 @@ static inline void volk_gnsssdr_8i_max_s8i_a_sse2(char* target, const char* src0 { if ((mask & 1) == 1) { - if(currentValuesBuffer[i] > max) + if (currentValuesBuffer[i] > max) { max = currentValuesBuffer[i]; } @@ -284,9 +388,9 @@ static inline void volk_gnsssdr_8i_max_s8i_a_sse2(char* target, const char* src0 inputPtr += 16; } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) { - if(src0[i] > max) + if (src0[i] > max) { max = src0[i]; } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_x2_add_8i.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_x2_add_8i.h index 54460a3a2..d1d3e0ed5 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_x2_add_8i.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8i_x2_add_8i.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -72,21 +72,57 @@ static inline void volk_gnsssdr_8i_x2_add_8i_u_sse2(char* cVector, const char* a __m128i aVal, bVal, cVal; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_loadu_si128((__m128i*)aPtr); bVal = _mm_loadu_si128((__m128i*)bPtr); cVal = _mm_add_epi8(aVal, bVal); - _mm_storeu_si128((__m128i*)cPtr, cVal); // Store the results back into the C container + _mm_storeu_si128((__m128i*)cPtr, cVal); // Store the results back into the C container aPtr += 16; bPtr += 16; cPtr += 16; } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) + { + *cPtr++ = (*aPtr++) + (*bPtr++); + } +} +#endif /* LV_HAVE_SSE2 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_x2_add_8i_u_avx2(char* cVector, const char* aVector, const char* bVector, unsigned int num_points) +{ + const unsigned int avx_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* cPtr = cVector; + const char* aPtr = aVector; + const char* bPtr = bVector; + + __m256i aVal, bVal, cVal; + + for (number = 0; number < avx_iters; number++) + { + aVal = _mm256_loadu_si256((__m256i*)aPtr); + bVal = _mm256_loadu_si256((__m256i*)bPtr); + + cVal = _mm256_add_epi8(aVal, bVal); + + _mm256_storeu_si256((__m256i*)cPtr, cVal); // Store the results back into the C container + + aPtr += 32; + bPtr += 32; + cPtr += 32; + } + + for (i = avx_iters * 32; i < num_points; ++i) { *cPtr++ = (*aPtr++) + (*bPtr++); } @@ -103,7 +139,7 @@ static inline void volk_gnsssdr_8i_x2_add_8i_generic(char* cVector, const char* const char* bPtr = bVector; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { *cPtr++ = (*aPtr++) + (*bPtr++); } @@ -125,21 +161,57 @@ static inline void volk_gnsssdr_8i_x2_add_8i_a_sse2(char* cVector, const char* a __m128i aVal, bVal, cVal; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { aVal = _mm_load_si128((__m128i*)aPtr); bVal = _mm_load_si128((__m128i*)bPtr); cVal = _mm_add_epi8(aVal, bVal); - _mm_store_si128((__m128i*)cPtr, cVal); // Store the results back into the C container + _mm_store_si128((__m128i*)cPtr, cVal); // Store the results back into the C container aPtr += 16; bPtr += 16; cPtr += 16; } - for(i = sse_iters * 16; i < num_points; ++i) + for (i = sse_iters * 16; i < num_points; ++i) + { + *cPtr++ = (*aPtr++) + (*bPtr++); + } +} +#endif /* LV_HAVE_SSE2 */ + + +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8i_x2_add_8i_a_avx2(char* cVector, const char* aVector, const char* bVector, unsigned int num_points) +{ + const unsigned int avx_iters = num_points / 32; + unsigned int number; + unsigned int i; + char* cPtr = cVector; + const char* aPtr = aVector; + const char* bPtr = bVector; + + __m256i aVal, bVal, cVal; + + for (number = 0; number < avx_iters; number++) + { + aVal = _mm256_load_si256((__m256i*)aPtr); + bVal = _mm256_load_si256((__m256i*)bPtr); + + cVal = _mm256_add_epi8(aVal, bVal); + + _mm256_store_si256((__m256i*)cPtr, cVal); // Store the results back into the C container + + aPtr += 32; + bPtr += 32; + cPtr += 32; + } + + for (i = avx_iters * 32; i < num_points; ++i) { *cPtr++ = (*aPtr++) + (*bPtr++); } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h index 0ccbd7aba..3217c7986 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -59,6 +59,37 @@ #include +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8ic_conjugate_8ic_u_avx2(lv_8sc_t* cVector, const lv_8sc_t* aVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 16; + unsigned int i; + lv_8sc_t* c = cVector; + const lv_8sc_t* a = aVector; + + __m256i tmp; + __m256i conjugator = _mm256_setr_epi8(1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < avx2_iters; ++i) + { + tmp = _mm256_loadu_si256((__m256i*)a); + tmp = _mm256_sign_epi8(tmp, conjugator); + _mm256_storeu_si256((__m256i*)c, tmp); + + a += 16; + c += 16; + } + + for (i = avx2_iters * 16; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} +#endif /* LV_HAVE_AVX2 */ + + #ifdef LV_HAVE_AVX #include @@ -71,7 +102,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_avx(lv_8sc_t* cVector, const __m256 tmp; __m128i tmp128lo, tmp128hi; - __m256 conjugator1 = _mm256_castsi256_ps(_mm256_setr_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255)); + __m256 conjugator1 = _mm256_castsi256_ps(_mm256_setr_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF)); __m128i conjugator2 = _mm_setr_epi8(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1); for (i = 0; i < sse_iters; ++i) @@ -80,10 +111,10 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_avx(lv_8sc_t* cVector, const tmp = _mm256_xor_ps(tmp, conjugator1); tmp128lo = _mm256_castsi256_si128(_mm256_castps_si256(tmp)); tmp128lo = _mm_add_epi8(tmp128lo, conjugator2); - tmp128hi = _mm256_extractf128_si256(_mm256_castps_si256(tmp),1); + tmp128hi = _mm256_extractf128_si256(_mm256_castps_si256(tmp), 1); tmp128hi = _mm_add_epi8(tmp128hi, conjugator2); //tmp = _mm256_set_m128i(tmp128hi , tmp128lo); //not defined in some versions of immintrin.h - tmp = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(tmp128lo),(tmp128hi),1)); + tmp = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(tmp128lo), (tmp128hi), 1)); _mm256_storeu_ps((float*)c, tmp); a += 16; @@ -124,7 +155,6 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_ssse3(lv_8sc_t* cVector, con { *c++ = lv_conj(*a++); } - } #endif /* LV_HAVE_SSSE3 */ @@ -140,7 +170,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_sse3(lv_8sc_t* cVector, cons const lv_8sc_t* a = aVector; __m128i tmp; - __m128i conjugator1 = _mm_setr_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + __m128i conjugator1 = _mm_setr_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); __m128i conjugator2 = _mm_setr_epi8(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1); for (i = 0; i < sse_iters; ++i) @@ -157,7 +187,6 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_sse3(lv_8sc_t* cVector, cons { *c++ = lv_conj(*a++); } - } #endif /* LV_HAVE_SSE3 */ @@ -170,7 +199,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_generic(lv_8sc_t* cVector, con const lv_8sc_t* aPtr = aVector; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { *cPtr++ = lv_conj(*aPtr++); } @@ -190,7 +219,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_avx(lv_8sc_t* cVector, const __m256 tmp; __m128i tmp128lo, tmp128hi; - __m256 conjugator1 = _mm256_castsi256_ps(_mm256_setr_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255)); + __m256 conjugator1 = _mm256_castsi256_ps(_mm256_setr_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF)); __m128i conjugator2 = _mm_setr_epi8(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1); for (i = 0; i < sse_iters; ++i) @@ -199,10 +228,10 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_avx(lv_8sc_t* cVector, const tmp = _mm256_xor_ps(tmp, conjugator1); tmp128lo = _mm256_castsi256_si128(_mm256_castps_si256(tmp)); tmp128lo = _mm_add_epi8(tmp128lo, conjugator2); - tmp128hi = _mm256_extractf128_si256(_mm256_castps_si256(tmp),1); + tmp128hi = _mm256_extractf128_si256(_mm256_castps_si256(tmp), 1); tmp128hi = _mm_add_epi8(tmp128hi, conjugator2); //tmp = _mm256_set_m128i(tmp128hi , tmp128lo); //not defined in some versions of immintrin.h - tmp = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(tmp128lo),(tmp128hi),1)); + tmp = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(tmp128lo), (tmp128hi), 1)); _mm256_store_ps((float*)c, tmp); a += 16; @@ -217,6 +246,37 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_avx(lv_8sc_t* cVector, const #endif /* LV_HAVE_AVX */ +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8ic_conjugate_8ic_a_avx2(lv_8sc_t* cVector, const lv_8sc_t* aVector, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 16; + unsigned int i; + lv_8sc_t* c = cVector; + const lv_8sc_t* a = aVector; + + __m256i tmp; + __m256i conjugator = _mm256_setr_epi8(1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1); + + for (i = 0; i < avx2_iters; ++i) + { + tmp = _mm256_load_si256((__m256i*)a); + tmp = _mm256_sign_epi8(tmp, conjugator); + _mm256_store_si256((__m256i*)c, tmp); + + a += 16; + c += 16; + } + + for (i = avx2_iters * 16; i < num_points; ++i) + { + *c++ = lv_conj(*a++); + } +} +#endif /* LV_HAVE_AVX2 */ + + #ifdef LV_HAVE_SSSE3 #include @@ -257,7 +317,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_sse3(lv_8sc_t* cVector, cons const lv_8sc_t* a = aVector; __m128i tmp; - __m128i conjugator1 = _mm_setr_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + __m128i conjugator1 = _mm_setr_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); __m128i conjugator2 = _mm_setr_epi8(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1); for (i = 0; i < sse_iters; ++i) @@ -274,7 +334,6 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_sse3(lv_8sc_t* cVector, cons { *c++ = lv_conj(*a++); } - } #endif /* LV_HAVE_SSE3 */ @@ -289,7 +348,7 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_u_orc(lv_8sc_t* cVector, const #endif /* LV_HAVE_ORC */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_8ic_conjugate_8ic_neon(lv_8sc_t* cVector, const lv_8sc_t* aVector, unsigned int num_points) @@ -315,6 +374,6 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_neon(lv_8sc_t* cVector, const *c++ = lv_conj(*a++); } } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_8ic_conjugate_8ic_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_magnitude_squared_8i.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_magnitude_squared_8i.h index 7152b0f29..3f58617f0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_magnitude_squared_8i.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_magnitude_squared_8i.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -78,23 +78,23 @@ static inline void volk_gnsssdr_8ic_magnitude_squared_8i_u_sse3(char* magnitudeV maska = _mm_set_epi8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 14, 12, 10, 8, 6, 4, 2, 0); maskb = _mm_set_epi8(14, 12, 10, 8, 6, 4, 2, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { avector = _mm_lddqu_si128((__m128i*)complexVectorPtr); - avectorlo = _mm_unpacklo_epi8 (avector, zero); - avectorhi = _mm_unpackhi_epi8 (avector, zero); - avectorlomult = _mm_mullo_epi16 (avectorlo, avectorlo); - avectorhimult = _mm_mullo_epi16 (avectorhi, avectorhi); - aadded = _mm_hadd_epi16 (avectorlomult, avectorhimult); + avectorlo = _mm_unpacklo_epi8(avector, zero); + avectorhi = _mm_unpackhi_epi8(avector, zero); + avectorlomult = _mm_mullo_epi16(avectorlo, avectorlo); + avectorhimult = _mm_mullo_epi16(avectorhi, avectorhi); + aadded = _mm_hadd_epi16(avectorlomult, avectorhimult); complexVectorPtr += 16; bvector = _mm_lddqu_si128((__m128i*)complexVectorPtr); - bvectorlo = _mm_unpacklo_epi8 (bvector, zero); - bvectorhi = _mm_unpackhi_epi8 (bvector, zero); - bvectorlomult = _mm_mullo_epi16 (bvectorlo, bvectorlo); - bvectorhimult = _mm_mullo_epi16 (bvectorhi, bvectorhi); - badded = _mm_hadd_epi16 (bvectorlomult, bvectorhimult); + bvectorlo = _mm_unpacklo_epi8(bvector, zero); + bvectorhi = _mm_unpackhi_epi8(bvector, zero); + bvectorlomult = _mm_mullo_epi16(bvectorlo, bvectorlo); + bvectorhimult = _mm_mullo_epi16(bvectorhi, bvectorhi); + badded = _mm_hadd_epi16(bvectorlomult, bvectorhimult); complexVectorPtr += 16; @@ -162,11 +162,11 @@ static inline void volk_gnsssdr_8ic_magnitude_squared_8i_generic(char* magnitude const char* complexVectorPtr = (char*)complexVector; char* magnitudeVectorPtr = magnitudeVector; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { const char real = *complexVectorPtr++; const char imag = *complexVectorPtr++; - *magnitudeVectorPtr++ = (real*real) + (imag*imag); + *magnitudeVectorPtr++ = (real * real) + (imag * imag); } } #endif /* LV_HAVE_GENERIC */ @@ -192,23 +192,23 @@ static inline void volk_gnsssdr_8ic_magnitude_squared_8i_a_sse3(char* magnitudeV maska = _mm_set_epi8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 14, 12, 10, 8, 6, 4, 2, 0); maskb = _mm_set_epi8(14, 12, 10, 8, 6, 4, 2, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { avector = _mm_load_si128((__m128i*)complexVectorPtr); - avectorlo = _mm_unpacklo_epi8 (avector, zero); - avectorhi = _mm_unpackhi_epi8 (avector, zero); - avectorlomult = _mm_mullo_epi16 (avectorlo, avectorlo); - avectorhimult = _mm_mullo_epi16 (avectorhi, avectorhi); - aadded = _mm_hadd_epi16 (avectorlomult, avectorhimult); + avectorlo = _mm_unpacklo_epi8(avector, zero); + avectorhi = _mm_unpackhi_epi8(avector, zero); + avectorlomult = _mm_mullo_epi16(avectorlo, avectorlo); + avectorhimult = _mm_mullo_epi16(avectorhi, avectorhi); + aadded = _mm_hadd_epi16(avectorlomult, avectorhimult); complexVectorPtr += 16; bvector = _mm_load_si128((__m128i*)complexVectorPtr); - bvectorlo = _mm_unpacklo_epi8 (bvector, zero); - bvectorhi = _mm_unpackhi_epi8 (bvector, zero); - bvectorlomult = _mm_mullo_epi16 (bvectorlo, bvectorlo); - bvectorhimult = _mm_mullo_epi16 (bvectorhi, bvectorhi); - badded = _mm_hadd_epi16 (bvectorlomult, bvectorhimult); + bvectorlo = _mm_unpacklo_epi8(bvector, zero); + bvectorhi = _mm_unpackhi_epi8(bvector, zero); + bvectorlomult = _mm_mullo_epi16(bvectorlo, bvectorlo); + bvectorhimult = _mm_mullo_epi16(bvectorhi, bvectorhi); + badded = _mm_hadd_epi16(bvectorlomult, bvectorhimult); complexVectorPtr += 16; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h index eae5363c2..f43ab659b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -73,14 +73,14 @@ static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_u_sse3(lv_8sc_t* cVector, lv_8sc_t* c = cVector; const lv_8sc_t* a = aVector; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); y = _mm_set1_epi16(*(short*)&scalar); imagy = _mm_srli_si128(y, 1); imagy = _mm_and_si128(imagy, mult1); realy = _mm_and_si128(y, mult1); - for(; number < sse_iters; number++) + for (; number < sse_iters; number++) { x = _mm_lddqu_si128((__m128i*)a); @@ -111,7 +111,6 @@ static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_u_sse3(lv_8sc_t* cVector, { *c++ = (*a++) * scalar; } - } #endif /* LV_HAVE_SSE3 */ @@ -166,14 +165,14 @@ static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_a_sse3(lv_8sc_t* cVector, lv_8sc_t* c = cVector; const lv_8sc_t* a = aVector; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); y = _mm_set1_epi16(*(short*)&scalar); imagy = _mm_srli_si128(y, 1); imagy = _mm_and_si128(imagy, mult1); realy = _mm_and_si128(y, mult1); - for(; number < sse_iters; number++) + for (; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); @@ -204,7 +203,6 @@ static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_a_sse3(lv_8sc_t* cVector, { *c++ = (*a++) * scalar; } - } #endif /* LV_HAVE_SSE3 */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_dot_prod_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_dot_prod_8ic.h index 7e381a9c4..d123f6225 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_dot_prod_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_dot_prod_8ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -59,9 +59,9 @@ #ifndef INCLUDED_volk_gnsssdr_8ic_x2_dot_prod_8ic_H #define INCLUDED_volk_gnsssdr_8ic_x2_dot_prod_8ic_H -#include #include #include +#include #ifdef LV_HAVE_GENERIC @@ -75,17 +75,17 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_generic(lv_8sc_t* result, co *cPtr += (*aPtr++) * (*bPtr++); }*/ - char * res = (char*) result; - char * in = (char*) in_a; - char * tp = (char*) in_b; - unsigned int n_2_ccomplex_blocks = num_points/2; + char* res = (char*)result; + char* in = (char*)in_a; + char* tp = (char*)in_b; + unsigned int n_2_ccomplex_blocks = num_points / 2; unsigned int isodd = num_points & 1; - char sum0[2] = {0,0}; - char sum1[2] = {0,0}; + char sum0[2] = {0, 0}; + char sum1[2] = {0, 0}; unsigned int i = 0; - for(i = 0; i < n_2_ccomplex_blocks; ++i) + for (i = 0; i < n_2_ccomplex_blocks; ++i) { sum0[0] += in[0] * tp[0] - in[1] * tp[1]; sum0[1] += in[0] * tp[1] + in[1] * tp[0]; @@ -100,7 +100,7 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_generic(lv_8sc_t* result, co res[1] = sum0[1] + sum1[1]; // Cleanup if we had an odd number of points - for(i = 0; i < isodd; ++i) + for (i = 0; i < isodd; ++i) { *result += in_a[num_points - 1] * in_b[num_points - 1]; } @@ -115,23 +115,23 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_generic(lv_8sc_t* result, co static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse2(lv_8sc_t* result, const lv_8sc_t* in_a, const lv_8sc_t* in_b, unsigned int num_points) { lv_8sc_t dotProduct; - memset(&dotProduct, 0x0, 2*sizeof(char)); + memset(&dotProduct, 0x0, 2 * sizeof(char)); unsigned int number; unsigned int i; const lv_8sc_t* a = in_a; const lv_8sc_t* b = in_b; - const unsigned int sse_iters = num_points/8; + const unsigned int sse_iters = num_points / 8; if (sse_iters > 0) { __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc, realcacc, imagcacc; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_loadu_si128((__m128i*)a); y = _mm_loadu_si128((__m128i*)b); @@ -165,9 +165,10 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse2(lv_8sc_t* result, con totalc = _mm_or_si128(realcacc, imagcacc); - __VOLK_ATTR_ALIGNED(16) lv_8sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(16) + lv_8sc_t dotProductVector[8]; - _mm_storeu_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector + _mm_storeu_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector for (i = 0; i < 8; ++i) { @@ -192,23 +193,23 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse2(lv_8sc_t* result, con static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse4_1(lv_8sc_t* result, const lv_8sc_t* in_a, const lv_8sc_t* in_b, unsigned int num_points) { lv_8sc_t dotProduct; - memset(&dotProduct, 0x0, 2*sizeof(char)); + memset(&dotProduct, 0x0, 2 * sizeof(char)); unsigned int number; unsigned int i; const lv_8sc_t* a = in_a; const lv_8sc_t* b = in_b; - const unsigned int sse_iters = num_points/8; + const unsigned int sse_iters = num_points / 8; if (sse_iters > 0) { __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc, realcacc, imagcacc; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_lddqu_si128((__m128i*)a); y = _mm_lddqu_si128((__m128i*)b); @@ -236,13 +237,14 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse4_1(lv_8sc_t* result, c b += 8; } - imagcacc = _mm_slli_si128 (imagcacc, 1); + imagcacc = _mm_slli_si128(imagcacc, 1); - totalc = _mm_blendv_epi8 (imagcacc, realcacc, mult1); + totalc = _mm_blendv_epi8(imagcacc, realcacc, mult1); - __VOLK_ATTR_ALIGNED(16) lv_8sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(16) + lv_8sc_t dotProductVector[8]; - _mm_storeu_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector + _mm_storeu_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector for (i = 0; i < 8; ++i) { @@ -267,23 +269,23 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_sse4_1(lv_8sc_t* result, c static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse2(lv_8sc_t* result, const lv_8sc_t* in_a, const lv_8sc_t* in_b, unsigned int num_points) { lv_8sc_t dotProduct; - memset(&dotProduct, 0x0, 2*sizeof(char)); + memset(&dotProduct, 0x0, 2 * sizeof(char)); unsigned int number; unsigned int i; const lv_8sc_t* a = in_a; const lv_8sc_t* b = in_b; - const unsigned int sse_iters = num_points/8; + const unsigned int sse_iters = num_points / 8; if (sse_iters > 0) { __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc, realcacc, imagcacc; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); y = _mm_load_si128((__m128i*)b); @@ -317,9 +319,10 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse2(lv_8sc_t* result, con totalc = _mm_or_si128(realcacc, imagcacc); - __VOLK_ATTR_ALIGNED(16) lv_8sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(16) + lv_8sc_t dotProductVector[8]; - _mm_store_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector + _mm_store_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector for (i = 0; i < 8; ++i) { @@ -343,7 +346,7 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse2(lv_8sc_t* result, con static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse4_1(lv_8sc_t* result, const lv_8sc_t* in_a, const lv_8sc_t* in_b, unsigned int num_points) { lv_8sc_t dotProduct; - memset(&dotProduct, 0x0, 2*sizeof(char)); + memset(&dotProduct, 0x0, 2 * sizeof(char)); unsigned int number; unsigned int i; const lv_8sc_t* a = in_a; @@ -355,11 +358,11 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse4_1(lv_8sc_t* result, c { __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc, realcacc, imagcacc; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); realcacc = _mm_setzero_si128(); imagcacc = _mm_setzero_si128(); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); y = _mm_load_si128((__m128i*)b); @@ -387,13 +390,14 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_a_sse4_1(lv_8sc_t* result, c b += 8; } - imagcacc = _mm_slli_si128 (imagcacc, 1); + imagcacc = _mm_slli_si128(imagcacc, 1); - totalc = _mm_blendv_epi8 (imagcacc, realcacc, mult1); + totalc = _mm_blendv_epi8(imagcacc, realcacc, mult1); - __VOLK_ATTR_ALIGNED(16) lv_8sc_t dotProductVector[8]; + __VOLK_ATTR_ALIGNED(16) + lv_8sc_t dotProductVector[8]; - _mm_store_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector + _mm_store_si128((__m128i*)dotProductVector, totalc); // Store the results back into the dot product vector for (i = 0; i < 8; ++i) { @@ -432,28 +436,29 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_u_orc(lv_8sc_t* result, cons #endif /* LV_HAVE_ORC */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_neon(lv_8sc_t* result, const lv_8sc_t* in_a, const lv_8sc_t* in_b, unsigned int num_points) { lv_8sc_t dotProduct; - dotProduct = lv_cmake(0,0); - *result = lv_cmake(0,0); + dotProduct = lv_cmake(0, 0); + *result = lv_cmake(0, 0); const lv_8sc_t* a = in_a; const lv_8sc_t* b = in_b; // for 2-lane vectors, 1st lane holds the real part, // 2nd lane holds the imaginary part int8x8x2_t a_val, b_val, c_val, accumulator, tmp_real, tmp_imag; - __VOLK_ATTR_ALIGNED(16) lv_8sc_t accum_result[8] = { lv_cmake(0,0) }; + __VOLK_ATTR_ALIGNED(16) + lv_8sc_t accum_result[8] = {lv_cmake(0, 0)}; accumulator.val[0] = vdup_n_s8(0); accumulator.val[1] = vdup_n_s8(0); unsigned int number; const unsigned int neon_iters = num_points / 8; - for(number = 0; number < neon_iters; ++number) + for (number = 0; number < neon_iters; ++number) { a_val = vld2_s8((const int8_t*)a); b_val = vld2_s8((const int8_t*)b); @@ -478,7 +483,7 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_neon(lv_8sc_t* result, const b += 8; } vst2_s8((int8_t*)accum_result, accumulator); - for(number = 0; number < 8; ++number) + for (number = 0; number < 8; ++number) { *result += accum_result[number]; } @@ -490,6 +495,6 @@ static inline void volk_gnsssdr_8ic_x2_dot_prod_8ic_neon(lv_8sc_t* result, const *result += dotProduct; } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /*INCLUDED_volk_gnsssdr_8ic_x2_dot_prod_8ic_H*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_multiply_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_multiply_8ic.h index 185ffa39f..1f566eabd 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_multiply_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_x2_multiply_8ic.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -73,9 +73,9 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_u_sse2(lv_8sc_t* cVector, co const lv_8sc_t* a = aVector; const lv_8sc_t* b = bVector; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_loadu_si128((__m128i*)a); y = _mm_loadu_si128((__m128i*)b); @@ -131,9 +131,9 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_u_sse4_1(lv_8sc_t* cVector, const lv_8sc_t* b = bVector; _mm_setzero_si128(); - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_lddqu_si128((__m128i*)a); y = _mm_lddqu_si128((__m128i*)b); @@ -181,7 +181,7 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_generic(lv_8sc_t* cVector, c const lv_8sc_t* bPtr = bVector; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { *cPtr++ = (*aPtr++) * (*bPtr++); } @@ -202,9 +202,9 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_a_sse2(lv_8sc_t* cVector, co const lv_8sc_t* a = aVector; const lv_8sc_t* b = bVector; - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); y = _mm_load_si128((__m128i*)b); @@ -228,7 +228,7 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_a_sse2(lv_8sc_t* cVector, co imagc = _mm_and_si128(imagc, mult1); imagc = _mm_slli_si128(imagc, 1); - totalc = _mm_or_si128 (realc, imagc); + totalc = _mm_or_si128(realc, imagc); _mm_store_si128((__m128i*)c, totalc); @@ -260,9 +260,9 @@ static inline void volk_gnsssdr_8ic_x2_multiply_8ic_a_sse4_1(lv_8sc_t* cVector, const lv_8sc_t* b = bVector; _mm_setzero_si128(); - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); y = _mm_load_si128((__m128i*)b); diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8u_x2_multiply_8u.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8u_x2_multiply_8u.h index 156f83a48..32785fe43 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8u_x2_multiply_8u.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8u_x2_multiply_8u.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -58,6 +58,56 @@ #ifndef INCLUDED_volk_gnsssdr_8u_x2_multiply_8u_H #define INCLUDED_volk_gnsssdr_8u_x2_multiply_8u_H +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8u_x2_multiply_8u_u_avx2(unsigned char* cChar, const unsigned char* aChar, const unsigned char* bChar, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 32; + unsigned int number; + unsigned int i; + + __m256i x, y, x1, x2, y1, y2, mult1, x1_mult_y1, x2_mult_y2, tmp, tmp1, tmp2, totalc; + unsigned char* c = cChar; + const unsigned char* a = aChar; + const unsigned char* b = bChar; + + for (number = 0; number < avx2_iters; number++) + { + x = _mm256_loadu_si256((__m256i*)a); + y = _mm256_loadu_si256((__m256i*)b); + + mult1 = _mm256_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); + x1 = _mm256_srli_si256(x, 1); + x1 = _mm256_and_si256(x1, mult1); + x2 = _mm256_and_si256(x, mult1); + + y1 = _mm256_srli_si256(y, 1); + y1 = _mm256_and_si256(y1, mult1); + y2 = _mm256_and_si256(y, mult1); + + x1_mult_y1 = _mm256_mullo_epi16(x1, y1); + x2_mult_y2 = _mm256_mullo_epi16(x2, y2); + + tmp = _mm256_and_si256(x1_mult_y1, mult1); + tmp1 = _mm256_slli_si256(tmp, 1); + tmp2 = _mm256_and_si256(x2_mult_y2, mult1); + totalc = _mm256_or_si256(tmp1, tmp2); + + _mm256_storeu_si256((__m256i*)c, totalc); + + a += 32; + b += 32; + c += 32; + } + + for (i = avx2_iters * 32; i < num_points; ++i) + { + *c++ = (*a++) * (*b++); + } +} +#endif /* LV_HAVE_SSE3 */ + #ifdef LV_HAVE_SSE3 #include @@ -73,12 +123,12 @@ static inline void volk_gnsssdr_8u_x2_multiply_8u_u_sse3(unsigned char* cChar, c const unsigned char* a = aChar; const unsigned char* b = bChar; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_lddqu_si128((__m128i*)a); y = _mm_lddqu_si128((__m128i*)b); - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); x1 = _mm_srli_si128(x, 1); x1 = _mm_and_si128(x1, mult1); x2 = _mm_and_si128(x, mult1); @@ -102,7 +152,7 @@ static inline void volk_gnsssdr_8u_x2_multiply_8u_u_sse3(unsigned char* cChar, c c += 16; } - for (i = sse_iters * 16; i < num_points ; ++i) + for (i = sse_iters * 16; i < num_points; ++i) { *c++ = (*a++) * (*b++); } @@ -118,7 +168,7 @@ static inline void volk_gnsssdr_8u_x2_multiply_8u_generic(unsigned char* cChar, const unsigned char* bPtr = bChar; unsigned int number; - for(number = 0; number < num_points; number++) + for (number = 0; number < num_points; number++) { *cPtr++ = (*aPtr++) * (*bPtr++); } @@ -139,12 +189,12 @@ static inline void volk_gnsssdr_8u_x2_multiply_8u_a_sse3(unsigned char* cChar, c const unsigned char* a = aChar; const unsigned char* b = bChar; - for(number = 0; number < sse_iters; number++) + for (number = 0; number < sse_iters; number++) { x = _mm_load_si128((__m128i*)a); y = _mm_load_si128((__m128i*)b); - mult1 = _mm_set_epi8(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255); + mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); x1 = _mm_srli_si128(x, 1); x1 = _mm_and_si128(x1, mult1); x2 = _mm_and_si128(x, mult1); @@ -176,6 +226,57 @@ static inline void volk_gnsssdr_8u_x2_multiply_8u_a_sse3(unsigned char* cChar, c #endif /* LV_HAVE_SSE */ +#ifdef LV_HAVE_AVX2 +#include + +static inline void volk_gnsssdr_8u_x2_multiply_8u_a_avx2(unsigned char* cChar, const unsigned char* aChar, const unsigned char* bChar, unsigned int num_points) +{ + const unsigned int avx2_iters = num_points / 32; + unsigned int number; + unsigned int i; + + __m256i x, y, x1, x2, y1, y2, mult1, x1_mult_y1, x2_mult_y2, tmp, tmp1, tmp2, totalc; + unsigned char* c = cChar; + const unsigned char* a = aChar; + const unsigned char* b = bChar; + + for (number = 0; number < avx2_iters; number++) + { + x = _mm256_load_si256((__m256i*)a); + y = _mm256_load_si256((__m256i*)b); + + mult1 = _mm256_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); + x1 = _mm256_srli_si256(x, 1); + x1 = _mm256_and_si256(x1, mult1); + x2 = _mm256_and_si256(x, mult1); + + y1 = _mm256_srli_si256(y, 1); + y1 = _mm256_and_si256(y1, mult1); + y2 = _mm256_and_si256(y, mult1); + + x1_mult_y1 = _mm256_mullo_epi16(x1, y1); + x2_mult_y2 = _mm256_mullo_epi16(x2, y2); + + tmp = _mm256_and_si256(x1_mult_y1, mult1); + tmp1 = _mm256_slli_si256(tmp, 1); + tmp2 = _mm256_and_si256(x2_mult_y2, mult1); + totalc = _mm256_or_si256(tmp1, tmp2); + + _mm256_store_si256((__m256i*)c, totalc); + + a += 32; + b += 32; + c += 32; + } + + for (i = avx2_iters * 32; i < num_points; ++i) + { + *c++ = (*a++) * (*b++); + } +} +#endif /* LV_HAVE_SSE3 */ + + #ifdef LV_HAVE_ORC extern void volk_gnsssdr_8u_x2_multiply_8u_a_orc_impl(unsigned char* cVector, const unsigned char* aVector, const unsigned char* bVector, unsigned int num_points); diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincos_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincos_32fc.h index 0b60682ce..41e59e525 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincos_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincos_32fc.h @@ -62,18 +62,18 @@ #ifndef INCLUDED_volk_gnsssdr_s32f_sincos_32fc_H #define INCLUDED_volk_gnsssdr_s32f_sincos_32fc_H -#include #include #include +#include #ifdef LV_HAVE_SSE2 #include /* Adapted from http://gruntthepeon.free.fr/ssemath/sse_mathfun.h, original code from Julien Pommier */ /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ */ -static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { - lv_32fc_t* bPtr = out; + lv_32fc_t *bPtr = out; const unsigned int sse_iters = num_points / 4; unsigned int number = 0; @@ -84,44 +84,44 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl __m128i emm0, emm2, emm4; /* declare some SSE constants */ - static const int _ps_inv_sign_mask[4] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - static const int _ps_sign_mask[4] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + static const int _ps_inv_sign_mask[4] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + static const int _ps_sign_mask[4] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - static const float _ps_cephes_FOPI[4] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - static const int _pi32_1[4] = { 1, 1, 1, 1 }; - static const int _pi32_inv1[4] = { ~1, ~1, ~1, ~1 }; - static const int _pi32_2[4] = { 2, 2, 2, 2}; - static const int _pi32_4[4] = { 4, 4, 4, 4}; + static const float _ps_cephes_FOPI[4] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + static const int _pi32_1[4] = {1, 1, 1, 1}; + static const int _pi32_inv1[4] = {~1, ~1, ~1, ~1}; + static const int _pi32_2[4] = {2, 2, 2, 2}; + static const int _pi32_4[4] = {4, 4, 4, 4}; - static const float _ps_minus_cephes_DP1[4] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - static const float _ps_minus_cephes_DP2[4] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - static const float _ps_minus_cephes_DP3[4] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - static const float _ps_coscof_p0[4] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - static const float _ps_coscof_p1[4] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - static const float _ps_coscof_p2[4] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - static const float _ps_sincof_p0[4] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - static const float _ps_sincof_p1[4] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - static const float _ps_sincof_p2[4] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - static const float _ps_0p5[4] = { 0.5f, 0.5f, 0.5f, 0.5f }; - static const float _ps_1[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static const float _ps_minus_cephes_DP1[4] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625}; + static const float _ps_minus_cephes_DP2[4] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + static const float _ps_minus_cephes_DP3[4] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + static const float _ps_coscof_p0[4] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + static const float _ps_coscof_p1[4] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + static const float _ps_coscof_p2[4] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + static const float _ps_sincof_p0[4] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + static const float _ps_sincof_p1[4] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + static const float _ps_sincof_p2[4] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + static const float _ps_0p5[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + static const float _ps_1[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - float four_phases[4] = { _phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc }; - float four_phases_inc[4] = { 4 * phase_inc, 4 * phase_inc, 4 * phase_inc, 4 * phase_inc }; + float four_phases[4] = {_phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc}; + float four_phases_inc[4] = {4 * phase_inc, 4 * phase_inc, 4 * phase_inc, 4 * phase_inc}; four_phases_reg = _mm_load_ps(four_phases); const __m128 four_phases_inc_reg = _mm_load_ps(four_phases_inc); - for(;number < sse_iters; number++) + for (; number < sse_iters; number++) { x = four_phases_reg; sign_bit_sin = x; /* take the absolute value */ - x = _mm_and_ps(x, *(__m128*)_ps_inv_sign_mask); + x = _mm_and_ps(x, *(__m128 *)_ps_inv_sign_mask); /* extract the sign bit (upper one) */ - sign_bit_sin = _mm_and_ps(sign_bit_sin, *(__m128*)_ps_sign_mask); + sign_bit_sin = _mm_and_ps(sign_bit_sin, *(__m128 *)_ps_sign_mask); /* scale by 4/Pi */ - y = _mm_mul_ps(x, *(__m128*)_ps_cephes_FOPI); + y = _mm_mul_ps(x, *(__m128 *)_ps_cephes_FOPI); /* store the integer part of y in emm2 */ emm2 = _mm_cvttps_epi32(y); @@ -145,9 +145,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl /* The magic pass: "Extended precision modular arithmetic” x = ((x - y * DP1) - y * DP2) - y * DP3; */ - xmm1 = *(__m128*)_ps_minus_cephes_DP1; - xmm2 = *(__m128*)_ps_minus_cephes_DP2; - xmm3 = *(__m128*)_ps_minus_cephes_DP3; + xmm1 = *(__m128 *)_ps_minus_cephes_DP1; + xmm2 = *(__m128 *)_ps_minus_cephes_DP2; + xmm3 = *(__m128 *)_ps_minus_cephes_DP3; xmm1 = _mm_mul_ps(y, xmm1); xmm2 = _mm_mul_ps(y, xmm2); xmm3 = _mm_mul_ps(y, xmm3); @@ -163,25 +163,25 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); /* Evaluate the first polynom (0 <= x <= Pi/4) */ - __m128 z = _mm_mul_ps(x,x); - y = *(__m128*)_ps_coscof_p0; + __m128 z = _mm_mul_ps(x, x); + y = *(__m128 *)_ps_coscof_p0; y = _mm_mul_ps(y, z); - y = _mm_add_ps(y, *(__m128*)_ps_coscof_p1); + y = _mm_add_ps(y, *(__m128 *)_ps_coscof_p1); y = _mm_mul_ps(y, z); - y = _mm_add_ps(y, *(__m128*)_ps_coscof_p2); + y = _mm_add_ps(y, *(__m128 *)_ps_coscof_p2); y = _mm_mul_ps(y, z); y = _mm_mul_ps(y, z); - __m128 tmp = _mm_mul_ps(z, *(__m128*)_ps_0p5); + __m128 tmp = _mm_mul_ps(z, *(__m128 *)_ps_0p5); y = _mm_sub_ps(y, tmp); - y = _mm_add_ps(y, *(__m128*)_ps_1); + y = _mm_add_ps(y, *(__m128 *)_ps_1); /* Evaluate the second polynom (Pi/4 <= x <= 0) */ - __m128 y2 = *(__m128*)_ps_sincof_p0; + __m128 y2 = *(__m128 *)_ps_sincof_p0; y2 = _mm_mul_ps(y2, z); - y2 = _mm_add_ps(y2, *(__m128*)_ps_sincof_p1); + y2 = _mm_add_ps(y2, *(__m128 *)_ps_sincof_p1); y2 = _mm_mul_ps(y2, z); - y2 = _mm_add_ps(y2, *(__m128*)_ps_sincof_p2); + y2 = _mm_add_ps(y2, *(__m128 *)_ps_sincof_p2); y2 = _mm_mul_ps(y2, z); y2 = _mm_mul_ps(y2, x); y2 = _mm_add_ps(y2, x); @@ -190,11 +190,11 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl xmm3 = poly_mask; __m128 ysin2 = _mm_and_ps(xmm3, y2); __m128 ysin1 = _mm_andnot_ps(xmm3, y); - y2 = _mm_sub_ps(y2,ysin2); + y2 = _mm_sub_ps(y2, ysin2); y = _mm_sub_ps(y, ysin1); - xmm1 = _mm_add_ps(ysin1,ysin2); - xmm2 = _mm_add_ps(y,y2); + xmm1 = _mm_add_ps(ysin1, ysin2); + xmm2 = _mm_add_ps(y, y2); /* update the sign */ sine = _mm_xor_ps(xmm1, sign_bit_sin); @@ -202,19 +202,19 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl /* write the output */ aux = _mm_unpacklo_ps(cosine, sine); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(cosine, sine); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; four_phases_reg = _mm_add_ps(four_phases_reg, four_phases_inc_reg); } _phase = _phase + phase_inc * (sse_iters * 4); - for(number = sse_iters * 4; number < num_points; number++) + for (number = sse_iters * 4; number < num_points; number++) { - *bPtr++ = lv_cmake((float)cos((_phase)), (float)sin((_phase)) ); + *bPtr++ = lv_cmake((float)cosf((_phase)), (float)sinf((_phase))); _phase += phase_inc; } (*phase) = _phase; @@ -227,9 +227,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_sse2(lv_32fc_t* out, const fl #include /* Adapted from http://gruntthepeon.free.fr/ssemath/sse_mathfun.h, original code from Julien Pommier */ /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ */ -static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { - lv_32fc_t* bPtr = out; + lv_32fc_t *bPtr = out; const unsigned int sse_iters = num_points / 4; unsigned int number = 0; @@ -241,44 +241,64 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl __m128i emm0, emm2, emm4; /* declare some SSE constants */ - __VOLK_ATTR_ALIGNED(16) static const int _ps_inv_sign_mask[4] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - __VOLK_ATTR_ALIGNED(16) static const int _ps_sign_mask[4] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_inv_sign_mask[4] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + __VOLK_ATTR_ALIGNED(16) + static const int _ps_sign_mask[4] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_cephes_FOPI[4] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_1[4] = { 1, 1, 1, 1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_inv1[4] = { ~1, ~1, ~1, ~1 }; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_2[4] = { 2, 2, 2, 2}; - __VOLK_ATTR_ALIGNED(16) static const int _pi32_4[4] = { 4, 4, 4, 4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_cephes_FOPI[4] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_1[4] = {1, 1, 1, 1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_inv1[4] = {~1, ~1, ~1, ~1}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_2[4] = {2, 2, 2, 2}; + __VOLK_ATTR_ALIGNED(16) + static const int _pi32_4[4] = {4, 4, 4, 4}; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP1[4] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP2[4] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_minus_cephes_DP3[4] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p0[4] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p1[4] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_coscof_p2[4] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p0[4] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p1[4] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_sincof_p2[4] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_0p5[4] = { 0.5f, 0.5f, 0.5f, 0.5f }; - __VOLK_ATTR_ALIGNED(16) static const float _ps_1[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP1[4] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP2[4] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_minus_cephes_DP3[4] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p0[4] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p1[4] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_coscof_p2[4] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p0[4] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p1[4] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_sincof_p2[4] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_0p5[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + __VOLK_ATTR_ALIGNED(16) + static const float _ps_1[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - __VOLK_ATTR_ALIGNED(16) float four_phases[4] = { _phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc }; - __VOLK_ATTR_ALIGNED(16) float four_phases_inc[4] = { 4 * phase_inc, 4 * phase_inc, 4 * phase_inc, 4 * phase_inc }; + __VOLK_ATTR_ALIGNED(16) + float four_phases[4] = {_phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc}; + __VOLK_ATTR_ALIGNED(16) + float four_phases_inc[4] = {4 * phase_inc, 4 * phase_inc, 4 * phase_inc, 4 * phase_inc}; four_phases_reg = _mm_load_ps(four_phases); const __m128 four_phases_inc_reg = _mm_load_ps(four_phases_inc); - for(;number < sse_iters; number++) + for (; number < sse_iters; number++) { x = four_phases_reg; sign_bit_sin = x; /* take the absolute value */ - x = _mm_and_ps(x, *(__m128*)_ps_inv_sign_mask); + x = _mm_and_ps(x, *(__m128 *)_ps_inv_sign_mask); /* extract the sign bit (upper one) */ - sign_bit_sin = _mm_and_ps(sign_bit_sin, *(__m128*)_ps_sign_mask); + sign_bit_sin = _mm_and_ps(sign_bit_sin, *(__m128 *)_ps_sign_mask); /* scale by 4/Pi */ - y = _mm_mul_ps(x, *(__m128*)_ps_cephes_FOPI); + y = _mm_mul_ps(x, *(__m128 *)_ps_cephes_FOPI); /* store the integer part of y in emm2 */ emm2 = _mm_cvttps_epi32(y); @@ -302,9 +322,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl /* The magic pass: "Extended precision modular arithmetic” x = ((x - y * DP1) - y * DP2) - y * DP3; */ - xmm1 = *(__m128*)_ps_minus_cephes_DP1; - xmm2 = *(__m128*)_ps_minus_cephes_DP2; - xmm3 = *(__m128*)_ps_minus_cephes_DP3; + xmm1 = *(__m128 *)_ps_minus_cephes_DP1; + xmm2 = *(__m128 *)_ps_minus_cephes_DP2; + xmm3 = *(__m128 *)_ps_minus_cephes_DP3; xmm1 = _mm_mul_ps(y, xmm1); xmm2 = _mm_mul_ps(y, xmm2); xmm3 = _mm_mul_ps(y, xmm3); @@ -320,25 +340,25 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); /* Evaluate the first polynom (0 <= x <= Pi/4) */ - __m128 z = _mm_mul_ps(x,x); - y = *(__m128*)_ps_coscof_p0; + __m128 z = _mm_mul_ps(x, x); + y = *(__m128 *)_ps_coscof_p0; y = _mm_mul_ps(y, z); - y = _mm_add_ps(y, *(__m128*)_ps_coscof_p1); + y = _mm_add_ps(y, *(__m128 *)_ps_coscof_p1); y = _mm_mul_ps(y, z); - y = _mm_add_ps(y, *(__m128*)_ps_coscof_p2); + y = _mm_add_ps(y, *(__m128 *)_ps_coscof_p2); y = _mm_mul_ps(y, z); y = _mm_mul_ps(y, z); - __m128 tmp = _mm_mul_ps(z, *(__m128*)_ps_0p5); + __m128 tmp = _mm_mul_ps(z, *(__m128 *)_ps_0p5); y = _mm_sub_ps(y, tmp); - y = _mm_add_ps(y, *(__m128*)_ps_1); + y = _mm_add_ps(y, *(__m128 *)_ps_1); /* Evaluate the second polynom (Pi/4 <= x <= 0) */ - __m128 y2 = *(__m128*)_ps_sincof_p0; + __m128 y2 = *(__m128 *)_ps_sincof_p0; y2 = _mm_mul_ps(y2, z); - y2 = _mm_add_ps(y2, *(__m128*)_ps_sincof_p1); + y2 = _mm_add_ps(y2, *(__m128 *)_ps_sincof_p1); y2 = _mm_mul_ps(y2, z); - y2 = _mm_add_ps(y2, *(__m128*)_ps_sincof_p2); + y2 = _mm_add_ps(y2, *(__m128 *)_ps_sincof_p2); y2 = _mm_mul_ps(y2, z); y2 = _mm_mul_ps(y2, x); y2 = _mm_add_ps(y2, x); @@ -347,11 +367,11 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl xmm3 = poly_mask; __m128 ysin2 = _mm_and_ps(xmm3, y2); __m128 ysin1 = _mm_andnot_ps(xmm3, y); - y2 = _mm_sub_ps(y2,ysin2); + y2 = _mm_sub_ps(y2, ysin2); y = _mm_sub_ps(y, ysin1); - xmm1 = _mm_add_ps(ysin1,ysin2); - xmm2 = _mm_add_ps(y,y2); + xmm1 = _mm_add_ps(ysin1, ysin2); + xmm2 = _mm_add_ps(y, y2); /* update the sign */ sine = _mm_xor_ps(xmm1, sign_bit_sin); @@ -359,19 +379,19 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl /* write the output */ aux = _mm_unpacklo_ps(cosine, sine); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(cosine, sine); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; four_phases_reg = _mm_add_ps(four_phases_reg, four_phases_inc_reg); } _phase = _phase + phase_inc * (sse_iters * 4); - for(number = sse_iters * 4; number < num_points; number++) + for (number = sse_iters * 4; number < num_points; number++) { - *bPtr++ = lv_cmake((float)cos(_phase), (float)sin(_phase) ); + *bPtr++ = lv_cmake((float)cosf(_phase), (float)sinf(_phase)); _phase += phase_inc; } (*phase) = _phase; @@ -382,13 +402,13 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_sse2(lv_32fc_t* out, const fl #ifdef LV_HAVE_GENERIC -static inline void volk_gnsssdr_s32f_sincos_32fc_generic(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_generic(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { float _phase = (*phase); unsigned int i; - for(i = 0; i < num_points; i++) + for (i = 0; i < num_points; i++) { - *out++ = lv_cmake((float)cos(_phase), (float)sin(_phase) ); + *out++ = lv_cmake((float)cosf(_phase), (float)sinf(_phase)); _phase += phase_inc; } (*phase) = _phase; @@ -400,7 +420,7 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_generic(lv_32fc_t* out, const f #ifdef LV_HAVE_GENERIC #include #include -static inline void volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { float _in, s, c; unsigned int i; @@ -413,12 +433,12 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, co const int32_t diffbits = bitlength - Nbits; uint32_t ux; float _phase = (*phase); - for(i = 0; i < num_points; i++) + for (i = 0; i < num_points; i++) { _in = _phase; d = (int32_t)floor(_in / TWO_PI + 0.5); _in -= d * TWO_PI; - x = (int32_t) ((float)_in * TWO_TO_THE_31_DIV_PI); + x = (int32_t)((float)_in * TWO_TO_THE_31_DIV_PI); ux = x; sin_index = ux >> diffbits; @@ -428,7 +448,7 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, co cos_index = ux >> diffbits; c = sine_table_10bits[cos_index][0] * (ux >> 1) + sine_table_10bits[cos_index][1]; - *out++ = lv_cmake((float)c, (float)s ); + *out++ = lv_cmake((float)c, (float)s); _phase += phase_inc; } (*phase) = _phase; @@ -441,9 +461,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(lv_32fc_t* out, co #include /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ * Adapted to AVX2 by Carles Fernandez, based on original SSE2 code by Julien Pommier*/ -static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { - lv_32fc_t* bPtr = out; + lv_32fc_t *bPtr = out; const unsigned int avx_iters = num_points / 8; unsigned int number = 0; @@ -456,44 +476,64 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const fl __m128 aux, c1, s1; /* declare some AXX2 constants */ - __VOLK_ATTR_ALIGNED(32) static const int _ps_inv_sign_mask[8] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - __VOLK_ATTR_ALIGNED(32) static const int _ps_sign_mask[8] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + __VOLK_ATTR_ALIGNED(32) + static const int _ps_inv_sign_mask[8] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + __VOLK_ATTR_ALIGNED(32) + static const int _ps_sign_mask[8] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - __VOLK_ATTR_ALIGNED(32) static const float _ps_cephes_FOPI[8] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_1[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_inv1[8] = { ~1, ~1, ~1, ~1, ~1, ~1, ~1, ~1 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_2[8] = { 2, 2, 2, 2, 2, 2, 2, 2 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_4[8] = { 4, 4, 4, 4, 4, 4, 4, 4 }; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_cephes_FOPI[8] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_1[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_inv1[8] = {~1, ~1, ~1, ~1, ~1, ~1, ~1, ~1}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_2[8] = {2, 2, 2, 2, 2, 2, 2, 2}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_4[8] = {4, 4, 4, 4, 4, 4, 4, 4}; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP1[8] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP2[8] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP3[8] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p0[8] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p1[8] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p2[8] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p0[8] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p1[8] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p2[8] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_0p5[8] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_1[8] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP1[8] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP2[8] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP3[8] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p0[8] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p1[8] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p2[8] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p0[8] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p1[8] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p2[8] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_0p5[8] = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_1[8] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; - __VOLK_ATTR_ALIGNED(32) float eight_phases[8] = { _phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc, _phase + 4 * phase_inc, _phase + 5 * phase_inc, _phase + 6 * phase_inc, _phase + 7 * phase_inc }; - __VOLK_ATTR_ALIGNED(32) float eight_phases_inc[8] = { 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc }; + __VOLK_ATTR_ALIGNED(32) + float eight_phases[8] = {_phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc, _phase + 4 * phase_inc, _phase + 5 * phase_inc, _phase + 6 * phase_inc, _phase + 7 * phase_inc}; + __VOLK_ATTR_ALIGNED(32) + float eight_phases_inc[8] = {8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc}; eight_phases_reg = _mm256_load_ps(eight_phases); const __m256 eight_phases_inc_reg = _mm256_load_ps(eight_phases_inc); - for(;number < avx_iters; number++) + for (; number < avx_iters; number++) { x = eight_phases_reg; sign_bit_sin = x; /* take the absolute value */ - x = _mm256_and_ps(x, *(__m256*)_ps_inv_sign_mask); + x = _mm256_and_ps(x, *(__m256 *)_ps_inv_sign_mask); /* extract the sign bit (upper one) */ - sign_bit_sin = _mm256_and_ps(sign_bit_sin, *(__m256*)_ps_sign_mask); + sign_bit_sin = _mm256_and_ps(sign_bit_sin, *(__m256 *)_ps_sign_mask); /* scale by 4/Pi */ - y = _mm256_mul_ps(x, *(__m256*)_ps_cephes_FOPI); + y = _mm256_mul_ps(x, *(__m256 *)_ps_cephes_FOPI); /* store the integer part of y in emm2 */ emm2 = _mm256_cvttps_epi32(y); @@ -517,9 +557,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const fl /* The magic pass: "Extended precision modular arithmetic” x = ((x - y * DP1) - y * DP2) - y * DP3; */ - xmm1 = *(__m256*)_ps_minus_cephes_DP1; - xmm2 = *(__m256*)_ps_minus_cephes_DP2; - xmm3 = *(__m256*)_ps_minus_cephes_DP3; + xmm1 = *(__m256 *)_ps_minus_cephes_DP1; + xmm2 = *(__m256 *)_ps_minus_cephes_DP2; + xmm3 = *(__m256 *)_ps_minus_cephes_DP3; xmm1 = _mm256_mul_ps(y, xmm1); xmm2 = _mm256_mul_ps(y, xmm2); xmm3 = _mm256_mul_ps(y, xmm3); @@ -536,24 +576,24 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const fl /* Evaluate the first polynom (0 <= x <= Pi/4) */ __m256 z = _mm256_mul_ps(x, x); - y = *(__m256*)_ps_coscof_p0; + y = *(__m256 *)_ps_coscof_p0; y = _mm256_mul_ps(y, z); - y = _mm256_add_ps(y, *(__m256*)_ps_coscof_p1); + y = _mm256_add_ps(y, *(__m256 *)_ps_coscof_p1); y = _mm256_mul_ps(y, z); - y = _mm256_add_ps(y, *(__m256*)_ps_coscof_p2); + y = _mm256_add_ps(y, *(__m256 *)_ps_coscof_p2); y = _mm256_mul_ps(y, z); y = _mm256_mul_ps(y, z); - __m256 tmp = _mm256_mul_ps(z, *(__m256*)_ps_0p5); + __m256 tmp = _mm256_mul_ps(z, *(__m256 *)_ps_0p5); y = _mm256_sub_ps(y, tmp); - y = _mm256_add_ps(y, *(__m256*)_ps_1); + y = _mm256_add_ps(y, *(__m256 *)_ps_1); /* Evaluate the second polynom (Pi/4 <= x <= 0) */ - __m256 y2 = *(__m256*)_ps_sincof_p0; + __m256 y2 = *(__m256 *)_ps_sincof_p0; y2 = _mm256_mul_ps(y2, z); - y2 = _mm256_add_ps(y2, *(__m256*)_ps_sincof_p1); + y2 = _mm256_add_ps(y2, *(__m256 *)_ps_sincof_p1); y2 = _mm256_mul_ps(y2, z); - y2 = _mm256_add_ps(y2, *(__m256*)_ps_sincof_p2); + y2 = _mm256_add_ps(y2, *(__m256 *)_ps_sincof_p2); y2 = _mm256_mul_ps(y2, z); y2 = _mm256_mul_ps(y2, x); y2 = _mm256_add_ps(y2, x); @@ -576,27 +616,27 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const fl s1 = _mm256_extractf128_ps(sine, 0); c1 = _mm256_extractf128_ps(cosine, 0); aux = _mm_unpacklo_ps(c1, s1); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(c1, s1); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; s1 = _mm256_extractf128_ps(sine, 1); c1 = _mm256_extractf128_ps(cosine, 1); aux = _mm_unpacklo_ps(c1, s1); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(c1, s1); - _mm_store_ps((float*)bPtr, aux); + _mm_store_ps((float *)bPtr, aux); bPtr += 2; eight_phases_reg = _mm256_add_ps(eight_phases_reg, eight_phases_inc_reg); } _mm256_zeroupper(); _phase = _phase + phase_inc * (avx_iters * 8); - for(number = avx_iters * 8; number < num_points; number++) + for (number = avx_iters * 8; number < num_points; number++) { - out[number] = lv_cmake((float)cos(_phase), (float)sin(_phase) ); + out[number] = lv_cmake((float)cosf(_phase), (float)sinf(_phase)); _phase += phase_inc; } (*phase) = _phase; @@ -609,9 +649,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_a_avx2(lv_32fc_t* out, const fl #include /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ * Adapted to AVX2 by Carles Fernandez, based on original SSE2 code by Julien Pommier*/ -static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { - lv_32fc_t* bPtr = out; + lv_32fc_t *bPtr = out; const unsigned int avx_iters = num_points / 8; unsigned int number = 0; @@ -624,44 +664,64 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const fl __m128 aux, c1, s1; /* declare some AXX2 constants */ - __VOLK_ATTR_ALIGNED(32) static const int _ps_inv_sign_mask[8] = { ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000 }; - __VOLK_ATTR_ALIGNED(32) static const int _ps_sign_mask[8] = { (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000 }; + __VOLK_ATTR_ALIGNED(32) + static const int _ps_inv_sign_mask[8] = {~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000, ~0x80000000}; + __VOLK_ATTR_ALIGNED(32) + static const int _ps_sign_mask[8] = {(int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000, (int)0x80000000}; - __VOLK_ATTR_ALIGNED(32) static const float _ps_cephes_FOPI[8] = { 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_1[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_inv1[8] = { ~1, ~1, ~1, ~1, ~1, ~1, ~1, ~1 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_2[8] = { 2, 2, 2, 2, 2, 2, 2, 2 }; - __VOLK_ATTR_ALIGNED(32) static const int _pi32_4[8] = { 4, 4, 4, 4, 4, 4, 4, 4 }; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_cephes_FOPI[8] = {1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516, 1.27323954473516}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_1[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_inv1[8] = {~1, ~1, ~1, ~1, ~1, ~1, ~1, ~1}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_2[8] = {2, 2, 2, 2, 2, 2, 2, 2}; + __VOLK_ATTR_ALIGNED(32) + static const int _pi32_4[8] = {4, 4, 4, 4, 4, 4, 4, 4}; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP1[8] = { -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP2[8] = { -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_minus_cephes_DP3[8] = { -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p0[8] = { 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p1[8] = { -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_coscof_p2[8] = { 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p0[8] = { -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p1[8] = { 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_sincof_p2[8] = { -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1 }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_0p5[8] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; - __VOLK_ATTR_ALIGNED(32) static const float _ps_1[8] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP1[8] = {-0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625, -0.78515625}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP2[8] = {-2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4, -2.4187564849853515625e-4}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_minus_cephes_DP3[8] = {-3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8, -3.77489497744594108e-8}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p0[8] = {2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005, 2.443315711809948E-005}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p1[8] = {-1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003, -1.388731625493765E-003}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_coscof_p2[8] = {4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002, 4.166664568298827E-002}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p0[8] = {-1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4, -1.9515295891E-4}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p1[8] = {8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3, 8.3321608736E-3}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_sincof_p2[8] = {-1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1, -1.6666654611E-1}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_0p5[8] = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f}; + __VOLK_ATTR_ALIGNED(32) + static const float _ps_1[8] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; - __VOLK_ATTR_ALIGNED(32) float eight_phases[8] = { _phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc, _phase + 4 * phase_inc, _phase + 5 * phase_inc, _phase + 6 * phase_inc, _phase + 7 * phase_inc }; - __VOLK_ATTR_ALIGNED(32) float eight_phases_inc[8] = { 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc }; + __VOLK_ATTR_ALIGNED(32) + float eight_phases[8] = {_phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc, _phase + 4 * phase_inc, _phase + 5 * phase_inc, _phase + 6 * phase_inc, _phase + 7 * phase_inc}; + __VOLK_ATTR_ALIGNED(32) + float eight_phases_inc[8] = {8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc, 8 * phase_inc}; eight_phases_reg = _mm256_load_ps(eight_phases); const __m256 eight_phases_inc_reg = _mm256_load_ps(eight_phases_inc); - for(;number < avx_iters; number++) + for (; number < avx_iters; number++) { x = eight_phases_reg; sign_bit_sin = x; /* take the absolute value */ - x = _mm256_and_ps(x, *(__m256*)_ps_inv_sign_mask); + x = _mm256_and_ps(x, *(__m256 *)_ps_inv_sign_mask); /* extract the sign bit (upper one) */ - sign_bit_sin = _mm256_and_ps(sign_bit_sin, *(__m256*)_ps_sign_mask); + sign_bit_sin = _mm256_and_ps(sign_bit_sin, *(__m256 *)_ps_sign_mask); /* scale by 4/Pi */ - y = _mm256_mul_ps(x, *(__m256*)_ps_cephes_FOPI); + y = _mm256_mul_ps(x, *(__m256 *)_ps_cephes_FOPI); /* store the integer part of y in emm2 */ emm2 = _mm256_cvttps_epi32(y); @@ -685,9 +745,9 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const fl /* The magic pass: "Extended precision modular arithmetic” x = ((x - y * DP1) - y * DP2) - y * DP3; */ - xmm1 = *(__m256*)_ps_minus_cephes_DP1; - xmm2 = *(__m256*)_ps_minus_cephes_DP2; - xmm3 = *(__m256*)_ps_minus_cephes_DP3; + xmm1 = *(__m256 *)_ps_minus_cephes_DP1; + xmm2 = *(__m256 *)_ps_minus_cephes_DP2; + xmm3 = *(__m256 *)_ps_minus_cephes_DP3; xmm1 = _mm256_mul_ps(y, xmm1); xmm2 = _mm256_mul_ps(y, xmm2); xmm3 = _mm256_mul_ps(y, xmm3); @@ -704,24 +764,24 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const fl /* Evaluate the first polynom (0 <= x <= Pi/4) */ __m256 z = _mm256_mul_ps(x, x); - y = *(__m256*)_ps_coscof_p0; + y = *(__m256 *)_ps_coscof_p0; y = _mm256_mul_ps(y, z); - y = _mm256_add_ps(y, *(__m256*)_ps_coscof_p1); + y = _mm256_add_ps(y, *(__m256 *)_ps_coscof_p1); y = _mm256_mul_ps(y, z); - y = _mm256_add_ps(y, *(__m256*)_ps_coscof_p2); + y = _mm256_add_ps(y, *(__m256 *)_ps_coscof_p2); y = _mm256_mul_ps(y, z); y = _mm256_mul_ps(y, z); - __m256 tmp = _mm256_mul_ps(z, *(__m256*)_ps_0p5); + __m256 tmp = _mm256_mul_ps(z, *(__m256 *)_ps_0p5); y = _mm256_sub_ps(y, tmp); - y = _mm256_add_ps(y, *(__m256*)_ps_1); + y = _mm256_add_ps(y, *(__m256 *)_ps_1); /* Evaluate the second polynom (Pi/4 <= x <= 0) */ - __m256 y2 = *(__m256*)_ps_sincof_p0; + __m256 y2 = *(__m256 *)_ps_sincof_p0; y2 = _mm256_mul_ps(y2, z); - y2 = _mm256_add_ps(y2, *(__m256*)_ps_sincof_p1); + y2 = _mm256_add_ps(y2, *(__m256 *)_ps_sincof_p1); y2 = _mm256_mul_ps(y2, z); - y2 = _mm256_add_ps(y2, *(__m256*)_ps_sincof_p2); + y2 = _mm256_add_ps(y2, *(__m256 *)_ps_sincof_p2); y2 = _mm256_mul_ps(y2, z); y2 = _mm256_mul_ps(y2, x); y2 = _mm256_add_ps(y2, x); @@ -744,27 +804,27 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const fl s1 = _mm256_extractf128_ps(sine, 0); c1 = _mm256_extractf128_ps(cosine, 0); aux = _mm_unpacklo_ps(c1, s1); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(c1, s1); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; s1 = _mm256_extractf128_ps(sine, 1); c1 = _mm256_extractf128_ps(cosine, 1); aux = _mm_unpacklo_ps(c1, s1); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; aux = _mm_unpackhi_ps(c1, s1); - _mm_storeu_ps((float*)bPtr, aux); + _mm_storeu_ps((float *)bPtr, aux); bPtr += 2; eight_phases_reg = _mm256_add_ps(eight_phases_reg, eight_phases_inc_reg); } _mm256_zeroupper(); _phase = _phase + phase_inc * (avx_iters * 8); - for(number = avx_iters * 8; number < num_points; number++) + for (number = avx_iters * 8; number < num_points; number++) { - out[number] = lv_cmake((float)cos(_phase), (float)sin(_phase) ); + out[number] = lv_cmake((float)cosf(_phase), (float)sinf(_phase)); _phase += phase_inc; } (*phase) = _phase; @@ -773,19 +833,21 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_u_avx2(lv_32fc_t* out, const fl #endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 #include /* Adapted from http://gruntthepeon.free.fr/ssemath/neon_mathfun.h, original code from Julien Pommier */ /* Based on algorithms from the cephes library http://www.netlib.org/cephes/ */ -static inline void volk_gnsssdr_s32f_sincos_32fc_neon(lv_32fc_t* out, const float phase_inc, float* phase, unsigned int num_points) +static inline void volk_gnsssdr_s32f_sincos_32fc_neon(lv_32fc_t *out, const float phase_inc, float *phase, unsigned int num_points) { - lv_32fc_t* bPtr = out; + lv_32fc_t *bPtr = out; const unsigned int neon_iters = num_points / 4; float _phase = (*phase); - __VOLK_ATTR_ALIGNED(16) float32_t four_phases[4] = { _phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc }; + __VOLK_ATTR_ALIGNED(16) + float32_t four_phases[4] = {_phase, _phase + phase_inc, _phase + 2 * phase_inc, _phase + 3 * phase_inc}; float four_inc = 4 * phase_inc; - __VOLK_ATTR_ALIGNED(16) float32_t four_phases_inc[4] = { four_inc, four_inc, four_inc, four_inc }; + __VOLK_ATTR_ALIGNED(16) + float32_t four_phases_inc[4] = {four_inc, four_inc, four_inc, four_inc}; float32x4_t four_phases_reg = vld1q_f32(four_phases); float32x4_t four_phases_inc_reg = vld1q_f32(four_phases_inc); @@ -808,7 +870,7 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_neon(lv_32fc_t* out, const floa uint32x4_t emm2, poly_mask, sign_mask_sin, sign_mask_cos; - for(;number < neon_iters; number++) + for (; number < neon_iters; number++) { x = four_phases_reg; @@ -847,7 +909,7 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_neon(lv_32fc_t* out, const floa /* Evaluate the first polynom (0 <= x <= Pi/4) in y1, and the second polynom (Pi/4 <= x <= 0) in y2 */ - z = vmulq_f32(x,x); + z = vmulq_f32(x, x); y1 = vmulq_n_f32(z, c_coscof_p0); y2 = vmulq_n_f32(z, c_sincof_p0); @@ -871,21 +933,21 @@ static inline void volk_gnsssdr_s32f_sincos_32fc_neon(lv_32fc_t* out, const floa result.val[1] = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys); result.val[0] = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc)); - vst2q_f32((float32_t*)bPtr, result); + vst2q_f32((float32_t *)bPtr, result); bPtr += 4; four_phases_reg = vaddq_f32(four_phases_reg, four_phases_inc_reg); } _phase = _phase + phase_inc * (neon_iters * 4); - for(number = neon_iters * 4; number < num_points; number++) + for (number = neon_iters * 4; number < num_points; number++) { - *bPtr++ = lv_cmake((float)cos(_phase), (float)sin(_phase) ); + *bPtr++ = lv_cmake((float)cosf(_phase), (float)sinf(_phase)); _phase += phase_inc; } (*phase) = _phase; } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ #endif /* INCLUDED_volk_gnsssdr_s32f_sincos_32fc_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincospuppet_32fc.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincospuppet_32fc.h index 07d3bf5d2..6146d443a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincospuppet_32fc.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_s32f_sincospuppet_32fc.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,8 +36,8 @@ #define INCLUDED_volk_gnsssdr_s32f_sincospuppet_32fc_H -#include #include "volk_gnsssdr/volk_gnsssdr_s32f_sincos_32fc.h" +#include #include @@ -49,7 +49,7 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_generic(lv_32fc_t* out, c volk_gnsssdr_s32f_sincos_32fc_generic(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_GENERIC */ +#endif /* LV_HAVE_GENERIC */ #ifdef LV_HAVE_GENERIC @@ -60,7 +60,7 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_generic_fxpt(lv_32fc_t* o volk_gnsssdr_s32f_sincos_32fc_generic_fxpt(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_GENERIC */ +#endif /* LV_HAVE_GENERIC */ #ifdef LV_HAVE_SSE2 @@ -70,7 +70,7 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_a_sse2(lv_32fc_t* out, co phase[0] = 3; volk_gnsssdr_s32f_sincos_32fc_a_sse2(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_SSE2 */ +#endif /* LV_HAVE_SSE2 */ #ifdef LV_HAVE_SSE2 @@ -80,7 +80,7 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_u_sse2(lv_32fc_t* out, co phase[0] = 3; volk_gnsssdr_s32f_sincos_32fc_u_sse2(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_SSE2 */ +#endif /* LV_HAVE_SSE2 */ #ifdef LV_HAVE_AVX2 @@ -90,7 +90,7 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_a_avx2(lv_32fc_t* out, co phase[0] = 3; volk_gnsssdr_s32f_sincos_32fc_a_avx2(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX2 */ #ifdef LV_HAVE_AVX2 @@ -100,16 +100,16 @@ static inline void volk_gnsssdr_s32f_sincospuppet_32fc_u_avx2(lv_32fc_t* out, co phase[0] = 3; volk_gnsssdr_s32f_sincos_32fc_u_avx2(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX2 */ -#ifdef LV_HAVE_NEON +#ifdef LV_HAVE_NEONV7 static inline void volk_gnsssdr_s32f_sincospuppet_32fc_neon(lv_32fc_t* out, const float phase_inc, unsigned int num_points) { float phase[1]; phase[0] = 3; volk_gnsssdr_s32f_sincos_32fc_neon(out, phase_inc, phase, num_points); } -#endif /* LV_HAVE_NEON */ +#endif /* LV_HAVE_NEONV7 */ -#endif /* INCLUDED_volk_gnsssdr_s32f_sincospuppet_32fc_H */ +#endif /* INCLUDED_volk_gnsssdr_s32f_sincospuppet_32fc_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/CMakeLists.txt index 97847d51c..48c012c09 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -14,7 +14,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # @@ -22,22 +22,22 @@ # header file detection ######################################################################## include(CheckIncludeFile) -CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) +check_include_file(cpuid.h HAVE_CPUID_H) if(HAVE_CPUID_H) add_definitions(-DHAVE_CPUID_H) endif() -CHECK_INCLUDE_FILE(intrin.h HAVE_INTRIN_H) +check_include_file(intrin.h HAVE_INTRIN_H) if(HAVE_INTRIN_H) add_definitions(-DHAVE_INTRIN_H) endif() -CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H) +check_include_file(fenv.h HAVE_FENV_H) if(HAVE_FENV_H) add_definitions(-DHAVE_FENV_H) endif() -CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) +check_include_file(dlfcn.h HAVE_DLFCN_H) if(HAVE_DLFCN_H) add_definitions(-DHAVE_DLFCN_H) list(APPEND volk_gnsssdr_libraries ${CMAKE_DL_LIBS}) @@ -62,7 +62,7 @@ endif() ######################################################################## if(COMPILER_NAME MATCHES "GNU") include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-Werror=unused-command-line-argument" HAVE_WERROR_UNUSED_CMD_LINE_ARG) + check_cxx_compiler_flag("-Werror=unused-command-line-argument" HAVE_WERROR_UNUSED_CMD_LINE_ARG) if(HAVE_WERROR_UNUSED_CMD_LINE_ARG) set(VOLK_FLAG_CHECK_FLAGS "-Werror=unused-command-line-argument") endif() @@ -74,20 +74,20 @@ endif() ######################################################################## include(CheckSymbolExists) -CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) - +check_symbol_exists(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) + if(HAVE_POSIX_MEMALIGN) add_definitions(-DHAVE_POSIX_MEMALIGN) -endif(HAVE_POSIX_MEMALIGN) +endif() if(NOT DEFINED _XOPEN_SOURCE) add_definitions(-D_XOPEN_SOURCE=700) -endif(NOT DEFINED _XOPEN_SOURCE) +endif() ######################################################################## # detect x86 flavor of CPU ######################################################################## -if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(i.86|x86|x86_64|amd64|AMD64)$") +if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(i.86|x86|x86_64|amd64|AMD64)$") message(STATUS "x86* CPU detected") set(CPU_IS_x86 TRUE) endif() @@ -106,7 +106,7 @@ macro(check_arch arch_name) set(flags ${ARGN}) set(have_${arch_name} TRUE) foreach(flag ${flags}) - if (MSVC AND (${flag} STREQUAL "/arch:SSE2" OR ${flag} STREQUAL "/arch:SSE" )) + if(MSVC AND (${flag} STREQUAL "/arch:SSE2" OR ${flag} STREQUAL "/arch:SSE")) # SSE/SSE2 is supported in MSVC since VS 2005 but flag not available when compiling 64-bit so do not check else() include(CheckCXXCompilerFlag) @@ -119,27 +119,27 @@ macro(check_arch arch_name) if(VOLK_FLAG_CHECK_FLAGS) set(CMAKE_REQUIRED_FLAGS ${VOLK_FLAG_CHECK_FLAGS}) endif() - CHECK_CXX_COMPILER_FLAG(${flag} ${have_flag}) + check_cxx_compiler_flag(${flag} ${have_flag}) unset(CMAKE_REQUIRED_FLAGS) - if (NOT ${have_flag}) + if(NOT ${have_flag}) set(have_${arch_name} FALSE) endif() endif() endforeach() - if (have_${arch_name}) + if(have_${arch_name}) list(APPEND available_archs ${arch_name}) endif() -endmacro(check_arch) +endmacro() foreach(line ${arch_flag_lines}) string(REGEX REPLACE "," ";" arch_flags ${line}) check_arch(${arch_flags}) -endforeach(line) +endforeach() macro(OVERRULE_ARCH arch reason) message(STATUS "${reason}, Overruled arch ${arch}") list(REMOVE_ITEM available_archs ${arch}) -endmacro(OVERRULE_ARCH) +endmacro() ######################################################################## # eliminate AVX on if not on x86, or if the compiler does not accept @@ -150,25 +150,25 @@ set(HAVE_XGETBV 0) set(HAVE_AVX_CVTPI32_PS 0) if(CPU_IS_x86) # check to see if the compiler/linker works with xgetb instruction - if (NOT MSVC) + if(NOT MSVC) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c "unsigned long long _xgetbv(unsigned int index) { unsigned int eax, edx; __asm__ __volatile__(\"xgetbv\" : \"=a\"(eax), \"=d\"(edx) : \"c\"(index)); return ((unsigned long long)edx << 32) | eax; } int main (void) { (void) _xgetbv(0); return (0); }") - else (NOT MSVC) + else() #MSVC defines an intrinsic file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c "#include \n #include \n int main() { int avxSupported = 0; \n#if (_MSC_FULL_VER >= 160040219) \nint cpuInfo[4]; __cpuid(cpuInfo, 1);\nif ((cpuInfo[2] & (1 << 27) || 0) && (cpuInfo[2] & (1 << 28) || 0)) \n{\nunsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);\n avxSupported = (xcrFeatureMask & 0x6) == 6;}\n#endif \n return 1- avxSupported; }") - endif(NOT MSVC) + endif() execute_process(COMMAND ${CMAKE_C_COMPILER} -o ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE avx_compile_result) if(NOT ${avx_compile_result} EQUAL 0) - OVERRULE_ARCH(avx "Compiler or linker missing xgetbv instruction") + overrule_arch(avx "Compiler or linker missing xgetbv instruction") elseif(NOT CROSSCOMPILE_MULTILIB) execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE avx_exe_result) if(NOT ${avx_exe_result} EQUAL 0) - OVERRULE_ARCH(avx "CPU missing xgetbv") + overrule_arch(avx "CPU missing xgetbv") else() set(HAVE_XGETBV 1) endif() @@ -184,7 +184,7 @@ if(CPU_IS_x86) ######################################################################### # check to see if the compiler/linker works with cvtpi32_ps instrinsic when using AVX - if (CMAKE_SIZEOF_VOID_P EQUAL 4) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_cvtpi32_ps.c "#include \nint main (void) {__m128 __a; __m64 __b; __m128 foo = _mm_cvtpi32_ps(__a, __b); return (0); }") execute_process(COMMAND ${CMAKE_C_COMPILER} -mavx -o ${CMAKE_CURRENT_BINARY_DIR}/test_cvtpi32_ps @@ -192,13 +192,13 @@ if(CPU_IS_x86) OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE avx_compile_result) if(NOT ${avx_compile_result} EQUAL 0) - OVERRULE_ARCH(avx "Compiler missing cvtpi32_ps instrinsic") + overrule_arch(avx "Compiler missing cvtpi32_ps instrinsic") elseif(NOT CROSSCOMPILE_MULTILIB) execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_cvtpi32_ps OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE avx_exe_result) if(NOT ${avx_exe_result} EQUAL 0) - OVERRULE_ARCH(avx "CPU missing cvtpi32_ps") + overrule_arch(avx "CPU missing cvtpi32_ps") else() set(HAVE_AVX_CVTPI32_PS 1) endif() @@ -207,13 +207,13 @@ if(CPU_IS_x86) endif() file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/test_cvtpi32_ps ${CMAKE_CURRENT_BINARY_DIR}/test_cvtpi32_ps.c) - else(CMAKE_SIZEOF_VOID_P EQUAL 4) - # 64-bit compilations won't need this command so don't overrule AVX - set(HAVE_AVX_CVTPI32_PS 0) - endif(CMAKE_SIZEOF_VOID_P EQUAL 4) + else() + # 64-bit compilations won't need this command so don't overrule AVX + set(HAVE_AVX_CVTPI32_PS 0) + endif() # Disable SSE4a if Clang is less than version 3.2 - if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") + if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") # Figure out the version of Clang if(CMAKE_VERSION VERSION_LESS "2.8.10") # Exctract the Clang version from the --version string. @@ -222,14 +222,14 @@ if(CPU_IS_x86) execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE clang_version) string(REGEX MATCH "[0-9].[0-9]" CMAKE_C_COMPILER_VERSION ${clang_version}) - endif(CMAKE_VERSION VERSION_LESS "2.8.10") + endif() if(CMAKE_C_COMPILER_VERSION VERSION_LESS "3.2") - OVERRULE_ARCH(sse4_a "Clang >= 3.2 required for SSE4a") - endif(CMAKE_C_COMPILER_VERSION VERSION_LESS "3.2") - endif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") + overrule_arch(sse4_a "Clang >= 3.2 required for SSE4a") + endif() + endif() -endif(CPU_IS_x86) +endif() if(${HAVE_XGETBV}) add_definitions(-DHAVE_XGETBV) @@ -244,24 +244,54 @@ endif() ######################################################################## if(NOT CPU_IS_x86) - OVERRULE_ARCH(3dnow "Architecture is not x86 or x86_64") - OVERRULE_ARCH(mmx "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse2 "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse3 "Architecture is not x86 or x86_64") - OVERRULE_ARCH(ssse3 "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse4_a "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse4_1 "Architecture is not x86 or x86_64") - OVERRULE_ARCH(sse4_2 "Architecture is not x86 or x86_64") - OVERRULE_ARCH(avx "Architecture is not x86 or x86_64") -endif(NOT CPU_IS_x86) + overrule_arch(3dnow "Architecture is not x86 or x86_64") + overrule_arch(mmx "Architecture is not x86 or x86_64") + overrule_arch(sse "Architecture is not x86 or x86_64") + overrule_arch(sse2 "Architecture is not x86 or x86_64") + overrule_arch(sse3 "Architecture is not x86 or x86_64") + overrule_arch(ssse3 "Architecture is not x86 or x86_64") + overrule_arch(sse4_a "Architecture is not x86 or x86_64") + overrule_arch(sse4_1 "Architecture is not x86 or x86_64") + overrule_arch(sse4_2 "Architecture is not x86 or x86_64") + overrule_arch(avx "Architecture is not x86 or x86_64") +endif() + +######################################################################## +# Select neon based on ARM ISA version +######################################################################## + +# First, compile a test program to see if compiler supports neon. + +include(CheckCSourceCompiles) + +check_c_source_compiles("#include \nint main(){ uint8_t *dest; uint8x8_t res; vst1_u8(dest, res); }" + neon_compile_result) + +if(neon_compile_result) + check_c_source_compiles("int main(){asm volatile(\"vrev32.8 q0, q0\");}" + have_neonv7_result) + check_c_source_compiles("int main(){asm volatile(\"sub v1.4s,v1.4s,v1.4s\");}" + have_neonv8_result) + + if(have_neonv7_result) + overrule_arch(neonv8 "CPU is armv7") + endif() + + if(have_neonv8_result) + overrule_arch(neonv7 "CPU is armv8") + endif() +else() + overrule_arch(neon "Compiler doesn't support NEON") + overrule_arch(neonv7 "Compiler doesn't support NEON") + overrule_arch(neonv8 "Compiler doesn't support NEON") +endif() ######################################################################## # implement overruling in the ORC case, # since ORC always passes flag detection ######################################################################## if(NOT ORC_FOUND) - OVERRULE_ARCH(orc "ORC support not found") + overrule_arch(orc "ORC support not found") endif() ######################################################################## @@ -271,16 +301,16 @@ endif() if(NOT CROSSCOMPILE_MULTILIB AND CPU_IS_x86) include(CheckTypeSize) check_type_size("void*[8]" SIZEOF_CPU BUILTIN_TYPES_ONLY) - if (${SIZEOF_CPU} EQUAL 64) - OVERRULE_ARCH(32 "CPU width is 64 bits") + if(${SIZEOF_CPU} EQUAL 64) + overrule_arch(32 "CPU width is 64 bits") endif() - if (${SIZEOF_CPU} EQUAL 32) - OVERRULE_ARCH(64 "CPU width is 32 bits") + if(${SIZEOF_CPU} EQUAL 32) + overrule_arch(64 "CPU width is 32 bits") endif() #MSVC 64 bit does not have MMX, overrule it - if (${SIZEOF_CPU} EQUAL 64 AND MSVC) - OVERRULE_ARCH(mmx "No MMX for Win64") + if(${SIZEOF_CPU} EQUAL 64 AND MSVC) + overrule_arch(mmx "No MMX for Win64") endif() endif() @@ -310,12 +340,12 @@ execute_process( foreach(arch mmx orc 64 32) foreach(machine_name ${available_machines}) string(REPLACE "_${arch}" "" machine_name_no_arch ${machine_name}) - if (${machine_name} STREQUAL ${machine_name_no_arch}) + if(${machine_name} STREQUAL ${machine_name_no_arch}) else() list(REMOVE_ITEM available_machines ${machine_name_no_arch}) endif() - endforeach(machine_name) -endforeach(arch) + endforeach() +endforeach() ######################################################################## # done overrules! print the result @@ -343,9 +373,9 @@ macro(gen_template tmpl output) ${PROJECT_SOURCE_DIR}/gen/volk_gnsssdr_tmpl_utils.py --input ${tmpl} --output ${output} ${ARGN} ) -endmacro(gen_template) +endmacro() -make_directory(${PROJECT_BINARY_DIR}/include/volk_gnsssdr) +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/volk_gnsssdr) gen_template(${PROJECT_SOURCE_DIR}/tmpl/volk_gnsssdr.tmpl.h ${PROJECT_BINARY_DIR}/include/volk_gnsssdr/volk_gnsssdr.h) gen_template(${PROJECT_SOURCE_DIR}/tmpl/volk_gnsssdr.tmpl.c ${PROJECT_BINARY_DIR}/lib/volk_gnsssdr.c) @@ -369,13 +399,13 @@ if(MSVC) elseif(MSVC11) #Visual Studio 11 set(cmake_c_compiler_version "Microsoft Visual Studio 11.0") elseif(MSVC12) #Visual Studio 12 - SET(cmake_c_compiler_version "Microsoft Visual Studio 12.0") + set(cmake_c_compiler_version "Microsoft Visual Studio 12.0") endif() else() execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE cmake_c_compiler_version) -endif(MSVC) -set(COMPILER_INFO "${CMAKE_C_COMPILER}:::${CMAKE_C_FLAGS_${GRCBTU}} ${CMAKE_C_FLAGS}\n${CMAKE_CXX_COMPILER}:::${CMAKE_CXX_FLAGS_${GRCBTU}} ${CMAKE_CXX_FLAGS}\n" ) +endif() +set(COMPILER_INFO "${CMAKE_C_COMPILER}:::${CMAKE_C_FLAGS_${GRCBTU}} ${CMAKE_C_FLAGS}\n${CMAKE_CXX_COMPILER}:::${CMAKE_CXX_FLAGS_${GRCBTU}} ${CMAKE_CXX_FLAGS}\n") foreach(machine_name ${available_machines}) #generate machine source @@ -389,8 +419,8 @@ foreach(machine_name ${available_machines}) --mode "machine_flags" --machine "${machine_name}" --compiler "${COMPILER_NAME}" OUTPUT_VARIABLE ${machine_name}_flags OUTPUT_STRIP_TRAILING_WHITESPACE ) - MESSAGE(STATUS "BUILD INFO ::: ${machine_name} ::: ${COMPILER_NAME} ::: ${CMAKE_C_FLAGS_${CBTU}} ${CMAKE_C_FLAGS} ${${machine_name}_flags}") - set(COMPILER_INFO "${COMPILER_INFO}${machine_name}:::${COMPILER_NAME}:::${CMAKE_C_FLAGS_${CBTU}} ${CMAKE_C_FLAGS} ${${machine_name}_flags}\n" ) + message(STATUS "BUILD INFO ::: ${machine_name} ::: ${COMPILER_NAME} ::: ${CMAKE_C_FLAGS_${CBTU}} ${CMAKE_C_FLAGS} ${${machine_name}_flags}") + set(COMPILER_INFO "${COMPILER_INFO}${machine_name}:::${COMPILER_NAME}:::${CMAKE_C_FLAGS_${CBTU}} ${CMAKE_C_FLAGS} ${${machine_name}_flags}\n") if(${machine_name}_flags AND NOT MSVC) set_source_files_properties(${machine_source} PROPERTIES COMPILE_FLAGS "${${machine_name}_flags}") endif() @@ -398,12 +428,12 @@ foreach(machine_name ${available_machines}) #add to available machine defs string(TOUPPER LV_MACHINE_${machine_name} machine_def) list(APPEND machine_defs ${machine_def}) -endforeach(machine_name) +endforeach() # Convert to a C string to compile and display properly string(STRIP "${cmake_c_compiler_version}" cmake_c_compiler_version) string(STRIP ${COMPILER_INFO} COMPILER_INFO) -MESSAGE(STATUS "Compiler Version: ${cmake_c_compiler_version}") +message(STATUS "Compiler Version: ${cmake_c_compiler_version}") string(REPLACE "\n" " \\n" cmake_c_compiler_version ${cmake_c_compiler_version}) string(REPLACE "\n" " \\n" COMPILER_INFO ${COMPILER_INFO}) @@ -423,7 +453,7 @@ include_directories( # on by default, but let users turn it off ######################################################################## if(${CMAKE_VERSION} VERSION_GREATER "2.8.9") - set(ASM_ARCHS_AVAILABLE "neon") + set(ASM_ARCHS_AVAILABLE "neonv7" "neonv8") set(FULL_C_FLAGS "${CMAKE_C_FLAGS}" "${CMAKE_CXX_COMPILER_ARG1}") @@ -432,7 +462,7 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.9") # set up the assembler flags and include the source files foreach(ARCH ${ASM_ARCHS_AVAILABLE}) string(REGEX MATCH "${ARCH}" ASM_ARCH "${available_archs}") - if( ASM_ARCH STREQUAL "neon" ) + if(ASM_ARCH STREQUAL "neonv7") message(STATUS "---- Adding ASM files") # we always use ATT syntax message(STATUS "-- Detected neon architecture; enabling ASM") # setup architecture specific assembler flags @@ -444,23 +474,23 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.9") foreach(asm_file ${asm_files}) list(APPEND volk_gnsssdr_sources ${asm_file}) message(STATUS "Adding source file: ${asm_file}") - endforeach(asm_file) + endforeach() endif() enable_language(ASM) set(CMAKE_ASM_FLAGS ${ARCH_ASM_FLAGS}) message(STATUS "c flags: ${FULL_C_FLAGS}") message(STATUS "asm flags: ${CMAKE_ASM_FLAGS}") - endforeach(ARCH) + endforeach() -else(${CMAKE_VERSION} VERSION_GREATER "2.8.9") +else() message(STATUS "Not enabling ASM support. CMake >= 2.8.10 required.") foreach(machine_name ${available_machines}) string(REGEX MATCH "neon" NEON_MACHINE ${machine_name}) - if( NEON_MACHINE STREQUAL "neon") + if(NEON_MACHINE STREQUAL "neon") message(FATAL_ERROR "CMake >= 2.8.10 is required for ARM NEON support") endif() endforeach() -endif(${CMAKE_VERSION} VERSION_GREATER "2.8.9") +endif() ######################################################################## # Handle orc support @@ -487,7 +517,7 @@ if(ORC_FOUND) ) list(APPEND volk_gnsssdr_sources ${orcc_gen}) - endforeach(orc_file) + endforeach() else() message(STATUS "Did not find liborc and orcc, disabling orc support...") endif() @@ -541,7 +571,7 @@ endif() if(CMAKE_VERSION VERSION_GREATER "2.8.7") #Create a volk_gnsssdr object library (requires cmake >= 2.8.8) add_library(volk_gnsssdr_obj OBJECT ${volk_gnsssdr_sources}) - + #Add dynamic library add_library(volk_gnsssdr SHARED $) target_link_libraries(volk_gnsssdr ${volk_gnsssdr_libraries} ${Boost_LIBRARIES}) @@ -567,7 +597,7 @@ if(CMAKE_VERSION VERSION_GREATER "2.8.7") install(TARGETS volk_gnsssdr_static ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT "volk_gnsssdr_devel" ) - endif(ENABLE_STATIC_LIBS) + endif() #Older cmake versions (slower to build when building dynamic/static libs) else() @@ -589,14 +619,14 @@ else() if(NOT WIN32) set_target_properties(volk_gnsssdr_static PROPERTIES OUTPUT_NAME volk_gnsssdr) - endif(NOT WIN32) + endif() install(TARGETS volk_gnsssdr_static ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT "volk_gnsssdr_devel" # .lib file ) - endif(ENABLE_STATIC_LIBS) + endif() +endif() -endif(CMAKE_VERSION VERSION_GREATER "2.8.7") ######################################################################## # Build the QA test application ######################################################################## @@ -604,18 +634,22 @@ if(ENABLE_TESTING) #include Boost headers include_directories(${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) - make_directory(${CMAKE_CURRENT_BINARY_DIR}/.unittest) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.unittest) set_source_files_properties( ${CMAKE_CURRENT_SOURCE_DIR}/testqa.cc PROPERTIES COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MAIN" ) include(VolkAddTest) - VOLK_ADD_TEST(test_all + volk_gen_test("volk_gnsssdr_test_all" SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/testqa.cc - ${CMAKE_CURRENT_SOURCE_DIR}/qa_utils.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_utils.cc TARGET_DEPS volk_gnsssdr - ) + ) + foreach(kernel ${h_files}) + get_filename_component(kernel ${kernel} NAME) + string(REPLACE ".h" "" kernel ${kernel}) + volk_add_test(${kernel} "volk_gnsssdr_test_all") + endforeach() -endif(ENABLE_TESTING) +endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/constants.c.in b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/constants.c.in index a28fdc39f..7277d37a2 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/constants.c.in +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/constants.c.in @@ -1,5 +1,5 @@ /* -*- c++ -*- */ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #if HAVE_CONFIG_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h index de3284a06..86b20b5e0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h @@ -4,7 +4,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -22,16 +22,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "qa_utils.h" -#include -#include #include +#include // macros for initializing volk_gnsssdr_test_case_t. Macros are needed to generate @@ -39,61 +38,68 @@ // for puppets we need to get all the func_variants for the puppet and just // keep track of the actual function name to write to results -#define VOLK_INIT_PUPP(func, puppet_master_func, test_params)\ - volk_gnsssdr_test_case_t(func##_get_func_desc(), (void(*)())func##_manual, std::string(#func),\ - std::string(#puppet_master_func), test_params) +#define VOLK_INIT_PUPP(func, puppet_master_func, test_params) \ + volk_gnsssdr_test_case_t(func##_get_func_desc(), (void (*)())func##_manual, std::string(#func), \ + std::string(#puppet_master_func), test_params) -#define VOLK_INIT_TEST(func, test_params)\ - volk_gnsssdr_test_case_t(func##_get_func_desc(), (void(*)())func##_manual, std::string(#func),\ - test_params) +#define VOLK_INIT_TEST(func, test_params) \ + volk_gnsssdr_test_case_t(func##_get_func_desc(), (void (*)())func##_manual, std::string(#func), \ + test_params) + +#define QA(test) test_cases.push_back(test); std::vector init_test_list(volk_gnsssdr_test_params_t test_params) { - // Some kernels need a lower tolerance volk_gnsssdr_test_params_t test_params_inacc = volk_gnsssdr_test_params_t(1e-3, test_params.scalar(), - test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); + test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); volk_gnsssdr_test_params_t test_params_int1 = volk_gnsssdr_test_params_t(1, test_params.scalar(), - test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); + test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); // some others need more iterations ***** ADDED BY GNSS-SDR volk_gnsssdr_test_params_t test_params_more_iters = volk_gnsssdr_test_params_t(test_params.tol(), test_params.scalar(), - test_params.vlen(), 100000, test_params.benchmark_mode(), test_params.kernel_regex()); + test_params.vlen(), 100000, test_params.benchmark_mode(), test_params.kernel_regex()); // ... or more tolerance ***** ADDED BY GNSS-SDR volk_gnsssdr_test_params_t test_params_int16 = volk_gnsssdr_test_params_t(16, test_params.scalar(), - test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); + test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); volk_gnsssdr_test_params_t test_params_inacc2 = volk_gnsssdr_test_params_t(2e-1, test_params.scalar(), - test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); + test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); - std::vector test_cases = boost::assign::list_of + std::vector test_cases; - (VOLK_INIT_TEST(volk_gnsssdr_8i_accumulator_s8i, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8i_index_max_16u, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8i_max_s8i, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8i_x2_add_8i, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8ic_conjugate_8ic, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8ic_magnitude_squared_8i, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_dot_prod_8ic, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_multiply_8ic, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_8ic_s8ic_multiply_8ic, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_8u_x2_multiply_8u, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_64f_accumulator_64f, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_32f_sincos_32fc, test_params_inacc)) - (VOLK_INIT_TEST(volk_gnsssdr_32f_index_max_32u, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_32fc_convert_8ic, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_32fc_convert_16ic, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_16ic_x2_dot_prod_16ic, test_params)) - (VOLK_INIT_TEST(volk_gnsssdr_16ic_x2_multiply_16ic, test_params_more_iters)) - (VOLK_INIT_TEST(volk_gnsssdr_16ic_convert_32fc, test_params_more_iters)) - (VOLK_INIT_PUPP(volk_gnsssdr_s32f_sincospuppet_32fc, volk_gnsssdr_s32f_sincos_32fc, test_params_inacc2)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_rotatorpuppet_16ic, volk_gnsssdr_16ic_s32fc_x2_rotator_16ic, test_params_int1)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerfastpuppet_16ic, volk_gnsssdr_16ic_resampler_fast_16ic, test_params)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic, volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn, test_params)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerxnpuppet_16ic, volk_gnsssdr_16ic_xn_resampler_16ic_xn, test_params)) - (VOLK_INIT_PUPP(volk_gnsssdr_32fc_resamplerxnpuppet_32fc, volk_gnsssdr_32fc_xn_resampler_32fc_xn, test_params)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic, volk_gnsssdr_16ic_x2_dot_prod_16ic_xn, test_params)) - (VOLK_INIT_PUPP(volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic, volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn, test_params_int16)) - (VOLK_INIT_PUPP(volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc, volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn, test_params_int1)) - ; + QA(VOLK_INIT_TEST(volk_gnsssdr_8i_accumulator_s8i, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8i_index_max_16u, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8i_max_s8i, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8i_x2_add_8i, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_conjugate_8ic, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_magnitude_squared_8i, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_dot_prod_8ic, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_multiply_8ic, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_s8ic_multiply_8ic, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_8u_x2_multiply_8u, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_64f_accumulator_64f, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_32f_sincos_32fc, test_params_inacc)) + QA(VOLK_INIT_TEST(volk_gnsssdr_32f_index_max_32u, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_32fc_convert_8ic, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_32fc_convert_16ic, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_16ic_x2_dot_prod_16ic, test_params)) + QA(VOLK_INIT_TEST(volk_gnsssdr_16ic_x2_multiply_16ic, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_16ic_convert_32fc, test_params_more_iters)) + QA(VOLK_INIT_TEST(volk_gnsssdr_16ic_conjugate_16ic, test_params_more_iters)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_s32f_sincospuppet_32fc, volk_gnsssdr_s32f_sincos_32fc, test_params_inacc2)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_rotatorpuppet_16ic, volk_gnsssdr_16ic_s32fc_x2_rotator_16ic, test_params_int1)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerfastpuppet_16ic, volk_gnsssdr_16ic_resampler_fast_16ic, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerfastxnpuppet_16ic, volk_gnsssdr_16ic_xn_resampler_fast_16ic_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_resamplerxnpuppet_16ic, volk_gnsssdr_16ic_xn_resampler_16ic_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16i_resamplerxnpuppet_16i, volk_gnsssdr_16i_xn_resampler_16i_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_32fc_resamplerxnpuppet_32fc, volk_gnsssdr_32fc_xn_resampler_32fc_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_32f_resamplerxnpuppet_32f, volk_gnsssdr_32f_xn_resampler_32f_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_32f_high_dynamics_resamplerxnpuppet_32f, volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_x2_dotprodxnpuppet_16ic, volk_gnsssdr_16ic_x2_dot_prod_16ic_xn, test_params)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_x2_rotator_dotprodxnpuppet_16ic, volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn, test_params_int16)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_16ic_16i_rotator_dotprodxnpuppet_16ic, volk_gnsssdr_16ic_16i_rotator_dot_prod_16ic_xn, test_params_int16)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_32fc_x2_rotator_dotprodxnpuppet_32fc, volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn, test_params_int1)) + QA(VOLK_INIT_PUPP(volk_gnsssdr_32fc_32f_rotator_dotprodxnpuppet_32fc, volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn, test_params_int1)); + QA(VOLK_INIT_PUPP(volk_gnsssdr_32fc_32f_high_dynamic_rotator_dotprodxnpuppet_32fc, volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn, test_params_int1)); return test_cases; } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.cc index c5b3f5262..906028e6d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,96 +13,130 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include "qa_utils.h" -#include -#include -#include -#include -#include +#include "volk_gnsssdr/volk_gnsssdr.h" // for volk_gnsssdr_func_desc_t +#include // for volk_gnsssdr_free, volk_gnsssdr_malloc +#include // for assert +#include // for system_clock, duration,... +#include // for sqrt, fabs, abs +#include // for uint16_t, uint64_t,int16_t, int32_t +#include // for memcpy, memset +#include // for operator<< +#include // for cout, cerr +#include // for numeric_limits +#include // for map +#include // for random_device, default_random_engine, uniform_real_distribution +#include // for vector -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -float uniform() { - return 2.0f * ((float) rand() / RAND_MAX - 0.5f); // uniformly (-1, 1) +float uniform() +{ + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_real_distribution uniform_dist(-1, 1); + return uniform_dist(e1); // uniformly (-1, 1) } template -void random_floats (t *buf, unsigned n) +void random_floats(t *buf, unsigned n) { - for (unsigned i = 0; i < n; i++) - buf[i] = uniform (); + for (unsigned i = 0; i < n; i++) + buf[i] = uniform(); } void load_random_data(void *data, volk_gnsssdr_type_t type, unsigned int n) { - if(type.is_complex) n *= 2; - if(type.is_float) + std::random_device r; + std::default_random_engine e2(r()); + + if (type.is_complex) n *= 2; + + if (type.is_float) { - if(type.size == 8) random_floats((double *)data, n); - else random_floats((float *)data, n); + if (type.size == 8) + random_floats((double *)data, n); + else + random_floats((float *)data, n); } else { - float int_max = float(uint64_t(2) << (type.size*8)); - if(type.is_signed) int_max /= 2.0; - for(unsigned int i = 0; i < n; i++) + float int_max = float(uint64_t(2) << (type.size * 8)); + if (type.is_signed) int_max /= 2.0; + std::uniform_real_distribution uniform_dist(-int_max, int_max); + for (unsigned int i = 0; i < n; i++) { - float scaled_rand = (((float) (rand() - (RAND_MAX/2))) / static_cast((RAND_MAX/2))) * int_max; - //man i really don't know how to do this in a more clever way, you have to cast down at some point - switch(type.size) - { - case 8: - if(type.is_signed) ((int64_t *)data)[i] = (int64_t) scaled_rand; - else ((uint64_t *)data)[i] = (uint64_t) scaled_rand; - break; - case 4: - if(type.is_signed) ((int32_t *)data)[i] = (int32_t) scaled_rand; - else ((uint32_t *)data)[i] = (uint32_t) scaled_rand; - break; - case 2: - // 16 bit multiplication saturates very fast - // we produce here only 3 bits input range - if(type.is_signed) ((int16_t *)data)[i] = (int16_t)((int16_t) scaled_rand % 8); - else ((uint16_t *)data)[i] = (uint16_t) (int16_t)((int16_t) scaled_rand % 8); - break; - case 1: - if(type.is_signed) ((int8_t *)data)[i] = (int8_t) scaled_rand; - else ((uint8_t *)data)[i] = (uint8_t) scaled_rand; - break; - default: - throw "load_random_data: no support for data size > 8 or < 1"; //no shenanigans here - } + float scaled_rand = uniform_dist(e2); + + switch (type.size) + { + case 8: + if (type.is_signed) + ((int64_t *)data)[i] = (int64_t)scaled_rand; + else + ((uint64_t *)data)[i] = (uint64_t)scaled_rand; + break; + case 4: + if (type.is_signed) + ((int32_t *)data)[i] = (int32_t)scaled_rand; + else + ((uint32_t *)data)[i] = (uint32_t)scaled_rand; + break; + case 2: + // 16 bit multiplication saturates very fast + // we produce here only 3 bits input range + if (type.is_signed) + ((int16_t *)data)[i] = (int16_t)((int16_t)scaled_rand % 8); + else + ((uint16_t *)data)[i] = (uint16_t)(int16_t)((int16_t)scaled_rand % 8); + break; + case 1: + if (type.is_signed) + ((int8_t *)data)[i] = (int8_t)scaled_rand; + else + ((uint8_t *)data)[i] = (uint8_t)scaled_rand; + break; + default: + throw "load_random_data: no support for data size > 8 or < 1"; //no shenanigans here + } } } } -static std::vector get_arch_list(volk_gnsssdr_func_desc_t desc) { +static std::vector get_arch_list(volk_gnsssdr_func_desc_t desc) +{ std::vector archlist; - for(size_t i = 0; i < desc.n_impls; i++) { - archlist.push_back(std::string(desc.impl_names[i])); - } + for (size_t i = 0; i < desc.n_impls; i++) + { + archlist.push_back(std::string(desc.impl_names[i])); + } return archlist; } -volk_gnsssdr_type_t volk_gnsssdr_type_from_string(std::string name) { +template +T volk_lexical_cast(const std::string &str) +{ + for (unsigned int c_index = 0; c_index < str.size(); ++c_index) + { + if (str.at(c_index) < '0' || str.at(c_index) > '9') + { + throw "not all numbers!"; + } + } + T var; + std::istringstream iss; + iss.str(str); + iss >> var; + // deal with any error bits that may have been set on the stream + return var; +} + +volk_gnsssdr_type_t volk_gnsssdr_type_from_string(std::string name) +{ volk_gnsssdr_type_t type; type.is_float = false; type.is_scalar = false; @@ -111,291 +145,368 @@ volk_gnsssdr_type_t volk_gnsssdr_type_from_string(std::string name) { type.size = 0; type.str = name; - if(name.size() < 2) { - throw std::string("name too short to be a datatype"); - } + if (name.size() < 2) + { + throw std::string("name too short to be a datatype"); + } //is it a scalar? - if(name[0] == 's') { - type.is_scalar = true; - name = name.substr(1, name.size()-1); - } + if (name[0] == 's') + { + type.is_scalar = true; + name = name.substr(1, name.size() - 1); + } //get the data size size_t last_size_pos = name.find_last_of("0123456789"); - if(last_size_pos == std::string::npos) { - throw std::string("no size spec in type ").append(name); - } + if (last_size_pos == std::string::npos) + { + throw std::string("no size spec in type ").append(name); + } //will throw if malformed - int size = boost::lexical_cast(name.substr(0, last_size_pos+1)); + int size = volk_lexical_cast(name.substr(0, last_size_pos + 1)); assert(((size % 8) == 0) && (size <= 64) && (size != 0)); - type.size = size/8; //in bytes + type.size = size / 8; //in bytes - for(size_t i=last_size_pos+1; i < name.size(); i++) { - switch (name[i]) { - case 'f': - type.is_float = true; - break; - case 'i': - type.is_signed = true; - break; - case 'c': - type.is_complex = true; - break; - case 'u': - type.is_signed = false; - break; - default: - throw; + for (size_t i = last_size_pos + 1; i < name.size(); i++) + { + switch (name[i]) + { + case 'f': + type.is_float = true; + break; + case 'i': + type.is_signed = true; + break; + case 'c': + type.is_complex = true; + break; + case 'u': + type.is_signed = false; + break; + default: + throw; + } } - } return type; } +std::vector split_signature(const std::string &protokernel_signature) +{ + std::vector signature_tokens; + std::string token; + for (unsigned int loc = 0; loc < protokernel_signature.size(); ++loc) + { + if (protokernel_signature.at(loc) == '_') + { + if (protokernel_signature.substr(loc + 1, 7).compare("gnsssdr") == 0) // jump the "gnsssdr" part of "volk_gnsssdr" + { + loc += 7; + } + else + { + // this is a break + signature_tokens.push_back(token); + token = ""; + } + } + else + { + token.push_back(protokernel_signature.at(loc)); + } + } + // Get the last one to the end of the string + signature_tokens.push_back(token); + return signature_tokens; +} + static void get_signatures_from_name(std::vector &inputsig, - std::vector &outputsig, - std::string name) { - boost::char_separator sep("_"); - boost::tokenizer > tok(name, sep); - std::vector toked; - tok.assign(name); - toked.assign(tok.begin(), tok.end()); + std::vector &outputsig, + std::string name) +{ + std::vector toked = split_signature(name); assert(toked[0] == "volk"); toked.erase(toked.begin()); - toked.erase(toked.begin()); - //ok. we're assuming a string in the form - //(sig)_(multiplier-opt)_..._(name)_(sig)_(multiplier-opt)_..._(alignment) - - enum { SIDE_INPUT, SIDE_NAME, SIDE_OUTPUT } side = SIDE_INPUT; + enum + { + SIDE_INPUT, + SIDE_NAME, + SIDE_OUTPUT + } side = SIDE_INPUT; std::string fn_name; volk_gnsssdr_type_t type; - BOOST_FOREACH(std::string token, toked) { - try { - type = volk_gnsssdr_type_from_string(token); - if(side == SIDE_NAME) side = SIDE_OUTPUT; //if this is the first one after the name... + for (unsigned int token_index = 0; token_index < toked.size(); ++token_index) + { + std::string token = toked[token_index]; + try + { + type = volk_gnsssdr_type_from_string(token); + if (side == SIDE_NAME) side = SIDE_OUTPUT; //if this is the first one after the name... - if(side == SIDE_INPUT) inputsig.push_back(type); - else outputsig.push_back(type); - } catch (...){ - if(token[0] == 'x' && (token.size() > 1) && (token[1] > '0' || token[1] < '9')) { - if(side == SIDE_INPUT) assert(inputsig.size() > 0); - else assert(outputsig.size() > 0); - int multiplier = boost::lexical_cast(token.substr(1, token.size()-1)); //will throw if invalid /////////// - for(int i=1; i 1) && (token[1] > '0' || token[1] < '9')) + { + if (side == SIDE_INPUT) + assert(inputsig.size() > 0); + else + assert(outputsig.size() > 0); + int multiplier = volk_lexical_cast(token.substr(1, token.size() - 1)); // will throw if invalid + for (int i = 1; i < multiplier; i++) + { + if (side == SIDE_INPUT) + inputsig.push_back(inputsig.back()); + else + outputsig.push_back(outputsig.back()); + } + } - else if(side == SIDE_INPUT) { //it's the function name, at least it better be - side = SIDE_NAME; - fn_name.append("_"); - fn_name.append(token); - } - else if(side == SIDE_OUTPUT) { - if(token != toked.back()) throw; //the last token in the name is the alignment - } + else if (side == SIDE_INPUT) + { //it's the function name, at least it better be + side = SIDE_NAME; + fn_name.append("_"); + fn_name.append(token); + } + else if (side == SIDE_OUTPUT) + { + if (token != toked.back()) throw; //the last token in the name is the alignment + } + } } - } //we don't need an output signature (some fn's operate on the input data, "in place"), but we do need at least one input! assert(inputsig.size() != 0); - } -inline void run_cast_test1(volk_gnsssdr_fn_1arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], vlen, arch.c_str()); +inline void run_cast_test1(volk_gnsssdr_fn_1arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], vlen, arch.c_str()); } -inline void run_cast_test2(volk_gnsssdr_fn_2arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], vlen, arch.c_str()); +inline void run_cast_test2(volk_gnsssdr_fn_2arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], vlen, arch.c_str()); } -inline void run_cast_test3(volk_gnsssdr_fn_3arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], vlen, arch.c_str()); +inline void run_cast_test3(volk_gnsssdr_fn_3arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], buffs[2], vlen, arch.c_str()); } -inline void run_cast_test4(volk_gnsssdr_fn_4arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], buffs[3], vlen, arch.c_str()); +inline void run_cast_test4(volk_gnsssdr_fn_4arg func, std::vector &buffs, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], buffs[2], buffs[3], vlen, arch.c_str()); } -inline void run_cast_test1_s32f(volk_gnsssdr_fn_1arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], scalar, vlen, arch.c_str()); +inline void run_cast_test1_s32f(volk_gnsssdr_fn_1arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], scalar, vlen, arch.c_str()); } -inline void run_cast_test2_s32f(volk_gnsssdr_fn_2arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); +inline void run_cast_test2_s32f(volk_gnsssdr_fn_2arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); } -inline void run_cast_test3_s32f(volk_gnsssdr_fn_3arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); +inline void run_cast_test3_s32f(volk_gnsssdr_fn_3arg_s32f func, std::vector &buffs, float scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); } -inline void run_cast_test1_s32fc(volk_gnsssdr_fn_1arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], scalar, vlen, arch.c_str()); +inline void run_cast_test1_s32fc(volk_gnsssdr_fn_1arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], scalar, vlen, arch.c_str()); } -inline void run_cast_test2_s32fc(volk_gnsssdr_fn_2arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); +inline void run_cast_test2_s32fc(volk_gnsssdr_fn_2arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); } -inline void run_cast_test3_s32fc(volk_gnsssdr_fn_3arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); +inline void run_cast_test3_s32fc(volk_gnsssdr_fn_3arg_s32fc func, std::vector &buffs, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) +{ + while (iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); } // *************** ADDED BY GNSS-SDR. START inline void run_cast_test1_s8i(volk_gnsssdr_fn_1arg_s8i func, std::vector &buffs, char scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], scalar, vlen, arch.c_str()); } inline void run_cast_test2_s8i(volk_gnsssdr_fn_2arg_s8i func, std::vector &buffs, char scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); } inline void run_cast_test3_s8i(volk_gnsssdr_fn_3arg_s8i func, std::vector &buffs, char scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); } inline void run_cast_test1_s8ic(volk_gnsssdr_fn_1arg_s8ic func, std::vector &buffs, lv_8sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], scalar, vlen, arch.c_str()); } inline void run_cast_test2_s8ic(volk_gnsssdr_fn_2arg_s8ic func, std::vector &buffs, lv_8sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); } inline void run_cast_test3_s8ic(volk_gnsssdr_fn_3arg_s8ic func, std::vector &buffs, lv_8sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); } inline void run_cast_test1_s16ic(volk_gnsssdr_fn_1arg_s16ic func, std::vector &buffs, lv_16sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], scalar, vlen, arch.c_str()); } inline void run_cast_test2_s16ic(volk_gnsssdr_fn_2arg_s16ic func, std::vector &buffs, lv_16sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], scalar, vlen, arch.c_str()); } inline void run_cast_test3_s16ic(volk_gnsssdr_fn_3arg_s16ic func, std::vector &buffs, lv_16sc_t scalar, unsigned int vlen, unsigned int iter, std::string arch) { - while(iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); + while (iter--) func(buffs[0], buffs[1], buffs[2], scalar, vlen, arch.c_str()); } // *************** ADDED BY GNSS-SDR. END template -bool fcompare(t *in1, t *in2, unsigned int vlen, float tol) { +bool fcompare(t *in1, t *in2, unsigned int vlen, float tol) +{ bool fail = false; int print_max_errs = 10; - for(unsigned int i=0; i tol ) - { - fail=true; - if(print_max_errs-- > 0) { - std::cout << "offset " << i << " in1: " << t(((t *)(in1))[i]) << " in2: " << t(((t *)(in2))[i]); - std::cout << " tolerance was: " << tol << std::endl; + for (unsigned int i = 0; i < vlen; i++) + { + // for very small numbers we'll see round off errors due to limited + // precision. So a special test case... + if (fabs(((t *)(in1))[i]) < 1e-30) + { + if (fabs(((t *)(in2))[i]) > tol) + { + fail = true; + if (print_max_errs-- > 0) + { + std::cout << "offset " << i << " in1: " << t(((t *)(in1))[i]) << " in2: " << t(((t *)(in2))[i]); + std::cout << " tolerance was: " << tol << std::endl; + } + } + } + // the primary test is the percent different greater than given tol + else if (fabs(((t *)(in1))[i] - ((t *)(in2))[i]) / fabs(((t *)in1)[i]) > tol) + { + fail = true; + if (print_max_errs-- > 0) + { + std::cout << "offset " << i << " in1: " << t(((t *)(in1))[i]) << " in2: " << t(((t *)(in2))[i]); + std::cout << " tolerance was: " << tol << std::endl; + } } - } } - // the primary test is the percent different greater than given tol - else if(fabs(((t *)(in1))[i] - ((t *)(in2))[i])/fabs(((t *)in1)[i]) > tol) { - fail=true; - if(print_max_errs-- > 0) { - std::cout << "offset " << i << " in1: " << t(((t *)(in1))[i]) << " in2: " << t(((t *)(in2))[i]); - std::cout << " tolerance was: " << tol << std::endl; - } - } - } return fail; } template -bool ccompare(t *in1, t *in2, unsigned int vlen, float tol) { +bool ccompare(t *in1, t *in2, unsigned int vlen, float tol) +{ bool fail = false; int print_max_errs = 10; - for(unsigned int i=0; i<2*vlen; i+=2) { - t diff[2] = { in1[i] - in2[i], in1[i+1] - in2[i+1] }; - t err = std::sqrt(diff[0] * diff[0] + diff[1] * diff[1]); - t norm = std::sqrt(in1[i] * in1[i] + in1[i+1] * in1[i+1]); + for (unsigned int i = 0; i < 2 * vlen; i += 2) + { + t diff[2] = {in1[i] - in2[i], in1[i + 1] - in2[i + 1]}; + t err = std::sqrt(diff[0] * diff[0] + diff[1] * diff[1]); + t norm = std::sqrt(in1[i] * in1[i] + in1[i + 1] * in1[i + 1]); - // for very small numbers we'll see round off errors due to limited - // precision. So a special test case... - if (norm < 1e-30) { - if (err > tol) - { - fail=true; - if(print_max_errs-- > 0) { - std::cout << "offset " << i/2 << " in1: " << in1[i] << " + " << in1[i+1] << "j in2: " << in2[i] << " + " << in2[i+1] << "j"; - std::cout << " tolerance was: " << tol << std::endl; + // for very small numbers we'll see round off errors due to limited + // precision. So a special test case... + if (norm < 1e-30) + { + if (err > tol) + { + fail = true; + if (print_max_errs-- > 0) + { + std::cout << "offset " << i / 2 << " in1: " << in1[i] << " + " << in1[i + 1] << "j in2: " << in2[i] << " + " << in2[i + 1] << "j"; + std::cout << " tolerance was: " << tol << std::endl; + } + } + } + // the primary test is the percent different greater than given tol + else if ((err / norm) > tol) + { + fail = true; + if (print_max_errs-- > 0) + { + std::cout << "offset " << i / 2 << " in1: " << in1[i] << " + " << in1[i + 1] << "j in2: " << in2[i] << " + " << in2[i + 1] << "j"; + std::cout << " tolerance was: " << tol << std::endl; + } } - } } - // the primary test is the percent different greater than given tol - else if((err / norm) > tol) { - fail=true; - if(print_max_errs-- > 0) { - std::cout << "offset " << i/2 << " in1: " << in1[i] << " + " << in1[i+1] << "j in2: " << in2[i] << " + " << in2[i+1] << "j"; - std::cout << " tolerance was: " << tol << std::endl; - } - } - } return fail; } template -bool icompare(t *in1, t *in2, unsigned int vlen, unsigned int tol) { +bool icompare(t *in1, t *in2, unsigned int vlen, unsigned int tol) +{ bool fail = false; int print_max_errs = 10; - for(unsigned int i=0; i tol) { - fail=true; - if(print_max_errs-- > 0) { - std::cout << "offset " << i << " in1: " << static_cast(t(((t *)(in1))[i])) << " in2: " << static_cast(t(((t *)(in2))[i])); - std::cout << " tolerance was: " << tol << std::endl; - } + for (unsigned int i = 0; i < vlen; i++) + { + if (((unsigned int)abs(int(((t *)(in1))[i]) - int(((t *)(in2))[i]))) > tol) + { + fail = true; + if (print_max_errs-- > 0) + { + std::cout << "offset " << i << " in1: " << static_cast(t(((t *)(in1))[i])) << " in2: " << static_cast(t(((t *)(in2))[i])); + std::cout << " tolerance was: " << tol << std::endl; + } + } } - } return fail; } -class volk_gnsssdr_qa_aligned_mem_pool{ +class volk_gnsssdr_qa_aligned_mem_pool +{ public: - void *get_new(size_t size){ + void *get_new(size_t size) + { size_t alignment = volk_gnsssdr_get_alignment(); - void* ptr = volk_gnsssdr_malloc(size, alignment); + void *ptr = volk_gnsssdr_malloc(size, alignment); memset(ptr, 0x00, size); _mems.push_back(ptr); return ptr; } - ~volk_gnsssdr_qa_aligned_mem_pool() { - for(unsigned int ii = 0; ii < _mems.size(); ++ii) { - volk_gnsssdr_free(_mems[ii]); - } + ~volk_gnsssdr_qa_aligned_mem_pool() + { + for (unsigned int ii = 0; ii < _mems.size(); ++ii) + { + volk_gnsssdr_free(_mems[ii]); + } } -private: std::vector _mems; + +private: + std::vector _mems; }; bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, - void (*manual_func)(), - std::string name, - volk_gnsssdr_test_params_t test_params, - std::vector *results, - std::string puppet_master_name -) + void (*manual_func)(), + std::string name, + volk_gnsssdr_test_params_t test_params, + std::vector *results, + std::string puppet_master_name) { return run_volk_gnsssdr_tests(desc, manual_func, name, test_params.tol(), test_params.scalar(), test_params.vlen(), test_params.iter(), results, puppet_master_name, @@ -403,15 +514,15 @@ bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, } bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, - void (*manual_func)(), - std::string name, - float tol, - lv_32fc_t scalar, - unsigned int vlen, - unsigned int iter, - std::vector *results, - std::string puppet_master_name, - bool benchmark_mode) + void (*manual_func)(), + std::string name, + float tol, + lv_32fc_t scalar, + unsigned int vlen, + unsigned int iter, + std::vector *results, + std::string puppet_master_name, + bool benchmark_mode) { // Initialize this entry in results vector results->push_back(volk_gnsssdr_test_results_t()); @@ -427,62 +538,78 @@ bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, vlen = vlen + vlen_twiddle; const float tol_f = tol; - const unsigned int tol_i = static_cast(tol); + const unsigned int tol_i = static_cast(tol); //first let's get a list of available architectures for the test std::vector arch_list = get_arch_list(desc); - if((!benchmark_mode) && (arch_list.size() < 2)) { - std::cout << "no architectures to test" << std::endl; - return false; - } + if ((!benchmark_mode) && (arch_list.size() < 2)) + { + std::cout << "no architectures to test" << std::endl; + return false; + } //something that can hang onto memory and cleanup when this function exits volk_gnsssdr_qa_aligned_mem_pool mem_pool; //now we have to get a function signature by parsing the name std::vector inputsig, outputsig; - try { - get_signatures_from_name(inputsig, outputsig, name); - } - catch (boost::bad_lexical_cast& error) { - std::cerr << "Error: unable to get function signature from kernel name" << std::endl; - std::cerr << " - " << name << std::endl; - return false; - } + try + { + get_signatures_from_name(inputsig, outputsig, name); + } + catch (std::exception &error) + { + std::cerr << "Error: unable to get function signature from kernel name" << std::endl; + std::cerr << " - " << name << std::endl; + return false; + } + catch (std::string s) + { + std::cerr << "Error: " << s << std::endl; + return false; + } //pull the input scalars into their own vector std::vector inputsc; - for(size_t i=0; i inbuffs; - BOOST_FOREACH(volk_gnsssdr_type_t sig, inputsig) { - if(!sig.is_scalar) //we don't make buffers for scalars - inbuffs.push_back(mem_pool.get_new(vlen*sig.size*(sig.is_complex ? 2 : 1))); - } - for(size_t i=0; i > test_data; - for(size_t i=0; i arch_buffs; - for(size_t j=0; j arch_buffs; + for (size_t j = 0; j < outputsig.size(); j++) + { + arch_buffs.push_back(mem_pool.get_new(vlen * outputsig[j].size * (outputsig[j].is_complex ? 2 : 1))); + } + for (size_t j = 0; j < inputsig.size(); j++) + { + void *arch_inbuff = mem_pool.get_new(vlen * inputsig[j].size * (inputsig[j].is_complex ? 2 : 1)); + memcpy(arch_inbuff, inbuffs[j], vlen * inputsig[j].size * (inputsig[j].is_complex ? 2 : 1)); + arch_buffs.push_back(arch_inbuff); + } + test_data.push_back(arch_buffs); } - for(size_t j=0; j both_sigs; both_sigs.insert(both_sigs.end(), outputsig.begin(), outputsig.end()); @@ -490,271 +617,281 @@ bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, //now run the test vlen = vlen - vlen_twiddle; - clock_t start, end; + std::chrono::time_point start, end; std::vector profile_times; - for(size_t i = 0; i < arch_list.size(); i++) { - start = clock(); - - switch(both_sigs.size()) + for (size_t i = 0; i < arch_list.size(); i++) { - case 1: - if(inputsc.size() == 0) + start = std::chrono::system_clock::now(); + + switch (both_sigs.size()) { - run_cast_test1((volk_gnsssdr_fn_1arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); - } - else if(inputsc.size() == 1 && inputsc[0].is_float) - { - if(inputsc[0].is_complex) + case 1: + if (inputsc.size() == 0) { - run_cast_test1_s32fc((volk_gnsssdr_fn_1arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + run_cast_test1((volk_gnsssdr_fn_1arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); } - else + else if (inputsc.size() == 1 && inputsc[0].is_float) { - run_cast_test1_s32f((volk_gnsssdr_fn_1arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); - } - } - //ADDED BY GNSS-SDR. START - else if(inputsc.size() == 1 && !inputsc[0].is_float) - { - if(inputsc[0].is_complex) - { - if(inputsc[0].size == 2) + if (inputsc[0].is_complex) { - run_cast_test1_s16ic((volk_gnsssdr_fn_1arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + run_cast_test1_s32fc((volk_gnsssdr_fn_1arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); } else { - run_cast_test1_s8ic((volk_gnsssdr_fn_1arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + run_cast_test1_s32f((volk_gnsssdr_fn_1arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); } } - else + //ADDED BY GNSS-SDR. START + else if (inputsc.size() == 1 && !inputsc[0].is_float) { - run_cast_test1_s8i((volk_gnsssdr_fn_1arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + if (inputsc[0].is_complex) + { + if (inputsc[0].size == 2) + { + run_cast_test1_s16ic((volk_gnsssdr_fn_1arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + else + { + run_cast_test1_s8ic((volk_gnsssdr_fn_1arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + } + else + { + run_cast_test1_s8i((volk_gnsssdr_fn_1arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + } } - } - //ADDED BY GNSS-SDR. END - else throw "unsupported 1 arg function >1 scalars"; - break; - case 2: - if(inputsc.size() == 0) - { + //ADDED BY GNSS-SDR. END + else + throw "unsupported 1 arg function >1 scalars"; + break; + case 2: + if (inputsc.size() == 0) + { run_cast_test2((volk_gnsssdr_fn_2arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); - } - else if(inputsc.size() == 1 && inputsc[0].is_float) - { - if(inputsc[0].is_complex) - { - run_cast_test2_s32fc((volk_gnsssdr_fn_2arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); } - else + else if (inputsc.size() == 1 && inputsc[0].is_float) { - run_cast_test2_s32f((volk_gnsssdr_fn_2arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); - } - } - //ADDED BY GNSS-SDR. START - else if(inputsc.size() == 1 && !inputsc[0].is_float) - { - if(inputsc[0].is_complex) - { - if(inputsc[0].size == 2) + if (inputsc[0].is_complex) { - run_cast_test2_s16ic((volk_gnsssdr_fn_2arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + run_cast_test2_s32fc((volk_gnsssdr_fn_2arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); } else { - run_cast_test2_s8ic((volk_gnsssdr_fn_2arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + run_cast_test2_s32f((volk_gnsssdr_fn_2arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); } } + //ADDED BY GNSS-SDR. START + else if (inputsc.size() == 1 && !inputsc[0].is_float) + { + if (inputsc[0].is_complex) + { + if (inputsc[0].size == 2) + { + run_cast_test2_s16ic((volk_gnsssdr_fn_2arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + else + { + run_cast_test2_s8ic((volk_gnsssdr_fn_2arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + } + else + { + run_cast_test2_s8i((volk_gnsssdr_fn_2arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + } + } + //ADDED BY GNSS-SDR. END else + throw "unsupported 2 arg function >1 scalars"; + break; + case 3: + if (inputsc.size() == 0) { - run_cast_test2_s8i((volk_gnsssdr_fn_2arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + run_cast_test3((volk_gnsssdr_fn_3arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); } - } - //ADDED BY GNSS-SDR. END - else throw "unsupported 2 arg function >1 scalars"; - break; - case 3: - if(inputsc.size() == 0) - { - run_cast_test3((volk_gnsssdr_fn_3arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); - } - else if(inputsc.size() == 1 && inputsc[0].is_float) - { - if(inputsc[0].is_complex) + else if (inputsc.size() == 1 && inputsc[0].is_float) { - run_cast_test3_s32fc((volk_gnsssdr_fn_3arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + if (inputsc[0].is_complex) + { + run_cast_test3_s32fc((volk_gnsssdr_fn_3arg_s32fc)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + else + { + run_cast_test3_s32f((volk_gnsssdr_fn_3arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + } } + //ADDED BY GNSS-SDR. START + else if (inputsc.size() == 1 && !inputsc[0].is_float) + { + if (inputsc[0].is_complex) + { + { + if (inputsc[0].size == 4) + { + run_cast_test3_s16ic((volk_gnsssdr_fn_3arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + else + { + run_cast_test3_s8ic((volk_gnsssdr_fn_3arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); + } + } + } + else + { + run_cast_test3_s8i((volk_gnsssdr_fn_3arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); + } + } + //ADDED BY GNSS-SDR. END else - { - run_cast_test3_s32f((volk_gnsssdr_fn_3arg_s32f)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); - } + throw "unsupported 3 arg function >1 scalars"; + break; + case 4: + run_cast_test4((volk_gnsssdr_fn_4arg)(manual_func), test_data[i], vlen, iter, arch_list[i]); + break; + default: + throw "no function handler for this signature"; + break; } - //ADDED BY GNSS-SDR. START - else if(inputsc.size() == 1 && !inputsc[0].is_float) - { - if(inputsc[0].is_complex) - { - { - if(inputsc[0].size == 4) - { - run_cast_test3_s16ic((volk_gnsssdr_fn_3arg_s16ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); - } - else - { - run_cast_test3_s8ic((volk_gnsssdr_fn_3arg_s8ic)(manual_func), test_data[i], scalar, vlen, iter, arch_list[i]); - } - } - } - else - { - run_cast_test3_s8i((volk_gnsssdr_fn_3arg_s8i)(manual_func), test_data[i], scalar.real(), vlen, iter, arch_list[i]); - } - } - //ADDED BY GNSS-SDR. END - else throw "unsupported 3 arg function >1 scalars"; - break; - default: - throw "no function handler for this signature"; - break; + + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + double arch_time = 1000.0 * elapsed_seconds.count(); + std::cout << arch_list[i] << " completed in " << arch_time << " ms" << std::endl; + volk_gnsssdr_test_time_t result; + result.name = arch_list[i]; + result.time = arch_time; + result.units = "ms"; + result.pass = true; + results->back().results[result.name] = result; + + profile_times.push_back(arch_time); } - end = clock(); - double arch_time = 1000.0 * (double)(end-start)/(double)CLOCKS_PER_SEC; - std::cout << arch_list[i] << " completed in " << arch_time << "ms" << std::endl; - volk_gnsssdr_test_time_t result; - result.name = arch_list[i]; - result.time = arch_time; - result.units = "ms"; - result.pass = true; - results->back().results[result.name] = result; - - profile_times.push_back(arch_time); - } - //and now compare each output to the generic output //first we have to know which output is the generic one, they aren't in order... - size_t generic_offset=0; - for(size_t i=0; i arch_results; - for(size_t i = 0; i < arch_list.size(); i++) + for (size_t i = 0; i < arch_list.size(); i++) { fail = false; - if(i != generic_offset) + if (i != generic_offset) { - for(size_t j=0; jback().results[arch_list[i]]; result->pass = !fail; @@ -770,14 +907,14 @@ bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, double best_time_u = std::numeric_limits::max(); std::string best_arch_a = "generic"; std::string best_arch_u = "generic"; - for(size_t i=0; i < arch_list.size(); i++) + for (size_t i = 0; i < arch_list.size(); i++) { - if((profile_times[i] < best_time_u) && arch_results[i] && desc.impl_alignment[i] == 0) + if ((profile_times[i] < best_time_u) && arch_results[i] && desc.impl_alignment[i] == 0) { best_time_u = profile_times[i]; best_arch_u = arch_list[i]; } - if((profile_times[i] < best_time_a) && arch_results[i]) + if ((profile_times[i] < best_time_a) && arch_results[i]) { best_time_a = profile_times[i]; best_arch_a = arch_list[i]; @@ -787,11 +924,14 @@ bool run_volk_gnsssdr_tests(volk_gnsssdr_func_desc_t desc, std::cout << "Best aligned arch: " << best_arch_a << std::endl; std::cout << "Best unaligned arch: " << best_arch_u << std::endl; - if(puppet_master_name == "NULL") { - results->back().config_name = name; - } else { - results->back().config_name = puppet_master_name; - } + if (puppet_master_name == "NULL") + { + results->back().config_name = name; + } + else + { + results->back().config_name = puppet_master_name; + } results->back().best_arch_a = best_arch_a; results->back().best_arch_u = best_arch_u; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.h index a50fe8fc8..2a69e5947 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/qa_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,25 +13,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef GNSS_SDR_VOLK_QA_UTILS_H #define GNSS_SDR_VOLK_QA_UTILS_H -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#endif + +#include "volk_gnsssdr/volk_gnsssdr.h" // for volk_gnsssdr_func_desc_t +#include "volk_gnsssdr/volk_gnsssdr_complex.h" // for lv_32fc_t +#include // for bool, false +#include // for NULL +#include // for map +#include // for string, basic_string +#include // for vector + /************************************************ * VOLK QA type definitions * ************************************************/ -struct volk_gnsssdr_type_t { +struct volk_gnsssdr_type_t +{ bool is_float; bool is_scalar; bool is_signed; @@ -40,73 +45,78 @@ struct volk_gnsssdr_type_t { std::string str; }; -class volk_gnsssdr_test_time_t { - public: - std::string name; - double time; - std::string units; - bool pass; +class volk_gnsssdr_test_time_t +{ +public: + std::string name; + double time; + std::string units; + bool pass; }; -class volk_gnsssdr_test_results_t { - public: - std::string name; - std::string config_name; - unsigned int vlen; - unsigned int iter; - std::map results; - std::string best_arch_a; - std::string best_arch_u; +class volk_gnsssdr_test_results_t +{ +public: + std::string name; + std::string config_name; + unsigned int vlen; + unsigned int iter; + std::map results; + std::string best_arch_a; + std::string best_arch_u; }; -class volk_gnsssdr_test_params_t { - private: - float _tol; - lv_32fc_t _scalar; - unsigned int _vlen; - unsigned int _iter; - bool _benchmark_mode; - std::string _kernel_regex; - public: - // ctor - volk_gnsssdr_test_params_t(float tol, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, - bool benchmark_mode, std::string kernel_regex) : - _tol(tol), _scalar(scalar), _vlen(vlen), _iter(iter), - _benchmark_mode(benchmark_mode), _kernel_regex(kernel_regex) {}; - // getters - float tol() {return _tol;}; - lv_32fc_t scalar() {return _scalar;}; - unsigned int vlen() {return _vlen;}; - unsigned int iter() {return _iter;}; - bool benchmark_mode() {return _benchmark_mode;}; - std::string kernel_regex() {return _kernel_regex;}; +class volk_gnsssdr_test_params_t +{ +private: + float _tol; + lv_32fc_t _scalar; + unsigned int _vlen; + unsigned int _iter; + bool _benchmark_mode; + std::string _kernel_regex; + +public: + // ctor + volk_gnsssdr_test_params_t(float tol, lv_32fc_t scalar, unsigned int vlen, unsigned int iter, + bool benchmark_mode, std::string kernel_regex) : _tol(tol), _scalar(scalar), _vlen(vlen), _iter(iter), _benchmark_mode(benchmark_mode), _kernel_regex(kernel_regex){}; + // setters + void set_tol(float tol) { _tol = tol; }; + void set_scalar(lv_32fc_t scalar) { _scalar = scalar; }; + void set_vlen(unsigned int vlen) { _vlen = vlen; }; + void set_iter(unsigned int iter) { _iter = iter; }; + void set_benchmark(bool benchmark) { _benchmark_mode = benchmark; }; + void set_regex(std::string regex) { _kernel_regex = regex; }; + // getters + float tol() { return _tol; }; + lv_32fc_t scalar() { return _scalar; }; + unsigned int vlen() { return _vlen; }; + unsigned int iter() { return _iter; }; + bool benchmark_mode() { return _benchmark_mode; }; + std::string kernel_regex() { return _kernel_regex; }; }; -class volk_gnsssdr_test_case_t { - private: - volk_gnsssdr_func_desc_t _desc; - void(*_kernel_ptr)(); - std::string _name; - volk_gnsssdr_test_params_t _test_parameters; - std::string _puppet_master_name; - public: - volk_gnsssdr_func_desc_t desc() {return _desc;}; - void (*kernel_ptr()) () {return _kernel_ptr;}; - std::string name() {return _name;}; - std::string puppet_master_name() {return _puppet_master_name;}; - volk_gnsssdr_test_params_t test_parameters() {return _test_parameters;}; - // normal ctor - volk_gnsssdr_test_case_t(volk_gnsssdr_func_desc_t desc, void(*kernel_ptr)(), std::string name, - volk_gnsssdr_test_params_t test_parameters) : - _desc(desc), _kernel_ptr(kernel_ptr), _name(name), _test_parameters(test_parameters), - _puppet_master_name("NULL") - {}; - // ctor for puppets - volk_gnsssdr_test_case_t(volk_gnsssdr_func_desc_t desc, void(*kernel_ptr)(), std::string name, - std::string puppet_master_name, volk_gnsssdr_test_params_t test_parameters) : - _desc(desc), _kernel_ptr(kernel_ptr), _name(name), _test_parameters(test_parameters), - _puppet_master_name(puppet_master_name) - {}; +class volk_gnsssdr_test_case_t +{ +private: + volk_gnsssdr_func_desc_t _desc; + void (*_kernel_ptr)(); + std::string _name; + volk_gnsssdr_test_params_t _test_parameters; + std::string _puppet_master_name; + +public: + volk_gnsssdr_func_desc_t desc() { return _desc; }; + void (*kernel_ptr())() { return _kernel_ptr; }; + std::string name() { return _name; }; + std::string puppet_master_name() { return _puppet_master_name; }; + volk_gnsssdr_test_params_t test_parameters() { return _test_parameters; }; + // normal ctor + volk_gnsssdr_test_case_t(volk_gnsssdr_func_desc_t desc, void (*kernel_ptr)(), std::string name, + volk_gnsssdr_test_params_t test_parameters) : _desc(desc), _kernel_ptr(kernel_ptr), _name(name), _test_parameters(test_parameters), _puppet_master_name("NULL"){}; + // ctor for puppets + volk_gnsssdr_test_case_t(volk_gnsssdr_func_desc_t desc, void (*kernel_ptr)(), std::string name, + std::string puppet_master_name, volk_gnsssdr_test_params_t test_parameters) : _desc(desc), _kernel_ptr(kernel_ptr), _name(name), _test_parameters(test_parameters), _puppet_master_name(puppet_master_name){}; }; /************************************************ @@ -119,58 +129,57 @@ void random_floats(float *buf, unsigned n); bool run_volk_gnsssdr_tests( volk_gnsssdr_func_desc_t, - void(*)(), + void (*)(), std::string, volk_gnsssdr_test_params_t, std::vector *results = NULL, - std::string puppet_master_name = "NULL" - ); + std::string puppet_master_name = "NULL"); bool run_volk_gnsssdr_tests( - volk_gnsssdr_func_desc_t, - void(*)(), - std::string, - float, - lv_32fc_t, - unsigned int, - unsigned int, - std::vector *results = NULL, - std::string puppet_master_name = "NULL", - bool benchmark_mode = false -); + volk_gnsssdr_func_desc_t, + void (*)(), + std::string, + float, + lv_32fc_t, + unsigned int, + unsigned int, + std::vector *results = NULL, + std::string puppet_master_name = "NULL", + bool benchmark_mode = false); -#define VOLK_RUN_TESTS(func, tol, scalar, len, iter) \ - BOOST_AUTO_TEST_CASE(func##_test) { \ - BOOST_CHECK_EQUAL(run_volk_gnsssdr_tests( \ - func##_get_func_desc(), (void (*)())func##_manual, \ - std::string(#func), tol, scalar, len, iter, 0, "NULL"), \ - 0); \ +#define VOLK_RUN_TESTS(func, tol, scalar, len, iter) \ + BOOST_AUTO_TEST_CASE(func##_test) \ + { \ + BOOST_CHECK_EQUAL(run_volk_gnsssdr_tests( \ + func##_get_func_desc(), (void (*)())func##_manual, \ + std::string(#func), tol, scalar, len, iter, 0, "NULL"), \ + 0); \ } #define VOLK_PROFILE(func, test_params, results) run_volk_gnsssdr_tests(func##_get_func_desc(), (void (*)())func##_manual, std::string(#func), test_params, results, "NULL") #define VOLK_PUPPET_PROFILE(func, puppet_master_func, test_params, results) run_volk_gnsssdr_tests(func##_get_func_desc(), (void (*)())func##_manual, std::string(#func), test_params, results, std::string(#puppet_master_func)) -typedef void (*volk_gnsssdr_fn_1arg)(void *, unsigned int, const char*); //one input, operate in place -typedef void (*volk_gnsssdr_fn_2arg)(void *, void *, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg)(void *, void *, void *, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_4arg)(void *, void *, void *, void *, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_1arg_s32f)(void *, float, unsigned int, const char*); //one input vector, one scalar float input -typedef void (*volk_gnsssdr_fn_2arg_s32f)(void *, void *, float, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg_s32f)(void *, void *, void *, float, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_1arg_s32fc)(void *, lv_32fc_t, unsigned int, const char*); //one input vector, one scalar float input -typedef void (*volk_gnsssdr_fn_2arg_s32fc)(void *, void *, lv_32fc_t, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg_s32fc)(void *, void *, void *, lv_32fc_t, unsigned int, const char*); +typedef void (*volk_gnsssdr_fn_1arg)(void *, unsigned int, const char *); //one input, operate in place +typedef void (*volk_gnsssdr_fn_2arg)(void *, void *, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg)(void *, void *, void *, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_4arg)(void *, void *, void *, void *, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_1arg_s32f)(void *, float, unsigned int, const char *); //one input vector, one scalar float input +typedef void (*volk_gnsssdr_fn_2arg_s32f)(void *, void *, float, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg_s32f)(void *, void *, void *, float, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_1arg_s32fc)(void *, lv_32fc_t, unsigned int, const char *); //one input vector, one scalar float input +typedef void (*volk_gnsssdr_fn_2arg_s32fc)(void *, void *, lv_32fc_t, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg_s32fc)(void *, void *, void *, lv_32fc_t, unsigned int, const char *); //ADDED BY GNSS-SDR. START -typedef void (*volk_gnsssdr_fn_1arg_s8i)(void *, char, unsigned int, const char*); //one input vector, one scalar char input -typedef void (*volk_gnsssdr_fn_2arg_s8i)(void *, void *, char, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg_s8i)(void *, void *, void *, char, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_1arg_s8ic)(void *, lv_8sc_t, unsigned int, const char*); //one input vector, one scalar lv_8sc_t vector input -typedef void (*volk_gnsssdr_fn_2arg_s8ic)(void *, void *, lv_8sc_t, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg_s8ic)(void *, void *, void *, lv_8sc_t, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_1arg_s16ic)(void *, lv_16sc_t, unsigned int, const char*); //one input vector, one scalar lv_16sc_t vector input -typedef void (*volk_gnsssdr_fn_2arg_s16ic)(void *, void *, lv_16sc_t, unsigned int, const char*); -typedef void (*volk_gnsssdr_fn_3arg_s16ic)(void *, void *, void *, lv_16sc_t, unsigned int, const char*); +typedef void (*volk_gnsssdr_fn_1arg_s8i)(void *, char, unsigned int, const char *); //one input vector, one scalar char input +typedef void (*volk_gnsssdr_fn_2arg_s8i)(void *, void *, char, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg_s8i)(void *, void *, void *, char, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_1arg_s8ic)(void *, lv_8sc_t, unsigned int, const char *); //one input vector, one scalar lv_8sc_t vector input +typedef void (*volk_gnsssdr_fn_2arg_s8ic)(void *, void *, lv_8sc_t, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg_s8ic)(void *, void *, void *, lv_8sc_t, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_1arg_s16ic)(void *, lv_16sc_t, unsigned int, const char *); //one input vector, one scalar lv_16sc_t vector input +typedef void (*volk_gnsssdr_fn_2arg_s16ic)(void *, void *, lv_16sc_t, unsigned int, const char *); +typedef void (*volk_gnsssdr_fn_3arg_s16ic)(void *, void *, void *, lv_16sc_t, unsigned int, const char *); //ADDED BY GNSS-SDR. END -#endif // GNSS_SDR_VOLK_QA_UTILS_H +#endif // GNSS_SDR_VOLK_QA_UTILS_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/testqa.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/testqa.cc index 659b111c4..6c23220d1 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/testqa.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/testqa.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -14,72 +14,112 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ -#include "qa_utils.h" -#include "kernel_tests.h" - -#include - -#include -#include -#include -#include +#include "kernel_tests.h" // for init_test_list +#include "qa_utils.h" // for volk_gnsssdr_test_case_t, volk_gnsssdr_test_results_t +#include "volk_gnsssdr/volk_gnsssdr_complex.h" // for lv_32fc_t +#include // for bool, false, true +#include // IWYU pragma: keep +#include // for operator<<, basic_ostream, endl, char... +#include // for map, map<>::iterator, _Rb_tree_iterator +#include // for stringstream +#include // for string, operator<< +#include // for pair +#include // for vector void print_qa_xml(std::vector results, unsigned int nfails); -int main() +int main(int argc, char* argv[]) { bool qa_ret_val = 0; float def_tol = 1e-6; lv_32fc_t def_scalar = 327.0; int def_iter = 1; - int def_vlen = 131071; + int def_vlen = 8111; bool def_benchmark_mode = true; std::string def_kernel_regex = ""; volk_gnsssdr_test_params_t test_params(def_tol, def_scalar, def_vlen, def_iter, def_benchmark_mode, def_kernel_regex); std::vector test_cases = init_test_list(test_params); - - std::vector qa_failures; std::vector results; - // Test every kernel reporting failures when they occur - for(unsigned int ii = 0; ii < test_cases.size(); ++ii) { - bool qa_result = false; - volk_gnsssdr_test_case_t test_case = test_cases[ii]; - try { - qa_result = run_volk_gnsssdr_tests(test_case.desc(), test_case.kernel_ptr(), test_case.name(), - test_case.test_parameters(), &results, test_case.puppet_master_name()); - } - catch(...) { - // TODO: what exceptions might we need to catch and how do we handle them? - std::cerr << "Exception found on kernel: " << test_case.name() << std::endl; - qa_result = false; + if (argc > 1) + { + std::stringstream ss; + ss << argv[1]; + if (ss.fail()) + { + std::cerr << "Test name not correctly set." << std::endl; + return 0; + } + for (unsigned int ii = 0; ii < test_cases.size(); ++ii) + { + if (ss.str() == test_cases[ii].name()) + { + volk_gnsssdr_test_case_t test_case = test_cases[ii]; + if (run_volk_gnsssdr_tests(test_case.desc(), test_case.kernel_ptr(), + test_case.name(), + test_case.test_parameters(), &results, + test_case.puppet_master_name())) + { + return 1; + } + else + { + return 0; + } + } + } + std::cerr << "Did not run a test for kernel: " << std::string(argv[1]) << " !" << std::endl; + return 0; } + else + { + std::vector qa_failures; + // Test every kernel reporting failures when they occur + for (unsigned int ii = 0; ii < test_cases.size(); ++ii) + { + bool qa_result = false; + volk_gnsssdr_test_case_t test_case = test_cases[ii]; + try + { + qa_result = run_volk_gnsssdr_tests(test_case.desc(), test_case.kernel_ptr(), test_case.name(), + test_case.test_parameters(), &results, test_case.puppet_master_name()); + } + catch (...) + { + // TODO: what exceptions might we need to catch and how do we handle them? + std::cerr << "Exception found on kernel: " << test_case.name() << std::endl; + qa_result = false; + } - if(qa_result) { - std::cerr << "Failure on " << test_case.name() << std::endl; - qa_failures.push_back(test_case.name()); - } - } + if (qa_result) + { + std::cerr << "Failure on " << test_case.name() << std::endl; + qa_failures.push_back(test_case.name()); + } + } - // Generate XML results - print_qa_xml(results, qa_failures.size()); + // Generate XML results + print_qa_xml(results, qa_failures.size()); - // Summarize QA results - std::cerr << "Kernel QA finished: " << qa_failures.size() << " failures out of " - << test_cases.size() << " tests." << std::endl; - if(qa_failures.size() > 0) { - std::cerr << "The following kernels failed QA:" << std::endl; - for(unsigned int ii = 0; ii < qa_failures.size(); ++ii) { - std::cerr << " " << qa_failures[ii] << std::endl; + // Summarize QA results + std::cerr << "Kernel QA finished: " << qa_failures.size() << " failures out of " + << test_cases.size() << " tests." << std::endl; + if (qa_failures.size() > 0) + { + std::cerr << "The following kernels failed QA:" << std::endl; + for (unsigned int ii = 0; ii < qa_failures.size(); ++ii) + { + std::cerr << " " << qa_failures[ii] << std::endl; + } + qa_ret_val = 1; + } } - qa_ret_val = 1; - } return qa_ret_val; } @@ -94,34 +134,33 @@ void print_qa_xml(std::vector results, unsigned int qa_file.open(".unittest/kernels.xml"); qa_file << "" << std::endl; - qa_file << "" << std::endl; + qa_file << "" << std::endl; // Results are in a vector by kernel. Each element has a result // map containing time and arch name with test result - for(unsigned int ii=0; ii < results.size(); ++ii) { - volk_gnsssdr_test_results_t result = results[ii]; - qa_file << " " << std::endl; + for (unsigned int ii = 0; ii < results.size(); ++ii) + { + volk_gnsssdr_test_results_t result = results[ii]; + qa_file << " " << std::endl; - std::map::iterator kernel_time_pair; - for(kernel_time_pair = result.results.begin(); kernel_time_pair != result.results.end(); ++kernel_time_pair) { - volk_gnsssdr_test_time_t test_time = kernel_time_pair->second; - qa_file << " " << std::endl; - if(!test_time.pass) - qa_file << " " << - "" << std::endl; - qa_file << " " << std::endl; + std::map::iterator kernel_time_pair; + for (kernel_time_pair = result.results.begin(); kernel_time_pair != result.results.end(); ++kernel_time_pair) + { + volk_gnsssdr_test_time_t test_time = kernel_time_pair->second; + qa_file << " " << std::endl; + if (!test_time.pass) + qa_file << " " + << "" << std::endl; + qa_file << " " << std::endl; + } + qa_file << " " << std::endl; } - qa_file << " " << std::endl; - } - qa_file << "" << std::endl; qa_file.close(); - } - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_malloc.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_malloc.c index 6e48815b3..bdeaaf7c3 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_malloc.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_malloc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include "volk_gnsssdr/volk_gnsssdr_malloc.h" @@ -43,15 +43,16 @@ void *volk_gnsssdr_malloc(size_t size, size_t alignment) return malloc(size); int err = posix_memalign(&ptr, alignment, size); - if(err == 0) + if (err == 0) { return ptr; } else { fprintf(stderr, - "VOLK: Error allocating memory " - "(posix_memalign: error %d: %s)\n", err, strerror(err)); + "VOLK_GNSSSDR: Error allocating memory " + "(posix_memalign: error %d: %s)\n", + err, strerror(err)); return NULL; } } @@ -68,9 +69,9 @@ void volk_gnsssdr_free(void *ptr) void *volk_gnsssdr_malloc(size_t size, size_t alignment) { void *ptr = _aligned_malloc(size, alignment); - if(ptr == NULL) + if (ptr == NULL) { - fprintf(stderr, "VOLK: Error allocating memory (_aligned_malloc)\n"); + fprintf(stderr, "VOLK_GNSSSDR: Error allocating memory (_aligned_malloc)\n"); } return ptr; } @@ -81,7 +82,7 @@ void volk_gnsssdr_free(void *ptr) } // No standard handlers; we'll do it ourselves. -#else // _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN +#else // _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN struct block_info { @@ -102,7 +103,7 @@ volk_gnsssdr_malloc(size_t size, size_t alignment) real = malloc(size + (2 * alignment - 1)); /* Get pointer to the various zones */ - user = (void *)((((uintptr_t) real) + sizeof(struct block_info) + alignment - 1) & ~(alignment - 1)); + user = (void *)((((uintptr_t)real) + sizeof(struct block_info) + alignment - 1) & ~(alignment - 1)); info = (struct block_info *)(((uintptr_t)user) - sizeof(struct block_info)); /* Store the info for the free */ @@ -112,8 +113,7 @@ volk_gnsssdr_malloc(size_t size, size_t alignment) return user; } -void -volk_gnsssdr_free(void *ptr) +void volk_gnsssdr_free(void *ptr) { struct block_info *info; @@ -124,6 +124,6 @@ volk_gnsssdr_free(void *ptr) free(info->real); } -#endif // _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN +#endif // _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || HAVE_POSIX_MEMALIGN //#endif // _ISOC11_SOURCE diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_prefs.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_prefs.c index b77aed467..87a51732d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_prefs.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_prefs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,7 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include @@ -26,16 +26,17 @@ void volk_gnsssdr_get_config_path(char *path) { if (!path) return; const char *suffix = "/.volk_gnsssdr/volk_gnsssdr_config"; - const char *suffix2 = "/volk_gnsssdr/volk_gnsssdr_config"; //non-hidden + const char *suffix2 = "/volk_gnsssdr/volk_gnsssdr_config"; // non-hidden char *home = NULL; //allows config redirection via env variable home = getenv("VOLK_CONFIGPATH"); - if(home!=NULL){ - strncpy(path,home,512); - strcat(path,suffix2); - return; - } + if (home != NULL) + { + strncpy(path, home, 512); + strcat(path, suffix2); + return; + } if (home == NULL) home = getenv("HOME"); if (home == NULL) home = getenv("APPDATA"); @@ -57,16 +58,16 @@ size_t volk_gnsssdr_load_preferences(volk_gnsssdr_arch_pref_t **prefs_res) //get the config path volk_gnsssdr_get_config_path(path); - if (!path[0]) return n_arch_prefs; //no prefs found + if (!path[0]) return n_arch_prefs; //no prefs found config_file = fopen(path, "r"); - if(!config_file) return n_arch_prefs; //no prefs found + if (!config_file) return n_arch_prefs; //no prefs found //reset the file pointer and write the prefs into volk_gnsssdr_arch_prefs - while(fgets(line, sizeof(line), config_file) != NULL) + while (fgets(line, sizeof(line), config_file) != NULL) { - prefs = (volk_gnsssdr_arch_pref_t *) realloc(prefs, (n_arch_prefs+1) * sizeof(*prefs)); + prefs = (volk_gnsssdr_arch_pref_t *)realloc(prefs, (n_arch_prefs + 1) * sizeof(*prefs)); volk_gnsssdr_arch_pref_t *p = prefs + n_arch_prefs; - if(sscanf(line, "%s %s %s", p->name, p->impl_a, p->impl_u) == 3 && !strncmp(p->name, "volk_gnsssdr_", 5)) + if (sscanf(line, "%s %s %s", p->name, p->impl_a, p->impl_u) == 3 && !strncmp(p->name, "volk_gnsssdr_", 5)) { n_arch_prefs++; } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.c index d1871426d..d231e9e96 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,7 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ @@ -29,7 +29,7 @@ inline unsigned __popcnt(unsigned num) { unsigned pop = 0; - while(num) + while (num) { if (num & 0x1) pop++; num >>= 1; @@ -39,15 +39,15 @@ inline unsigned __popcnt(unsigned num) #endif int volk_gnsssdr_get_index( - const char *impl_names[], //list of implementations by name - const size_t n_impls, //number of implementations available - const char *impl_name //the implementation name to find - ) + const char *impl_names[], //list of implementations by name + const size_t n_impls, //number of implementations available + const char *impl_name //the implementation name to find +) { unsigned int i; for (i = 0; i < n_impls; i++) { - if(!strncmp(impl_names[i], impl_name, 20)) + if (!strncmp(impl_names[i], impl_name, 20)) { return i; } @@ -55,24 +55,24 @@ int volk_gnsssdr_get_index( //TODO return -1; //something terrible should happen here fprintf(stderr, "VOLK_GNSSSDR warning: no arch found, returning generic impl\n"); - return volk_gnsssdr_get_index(impl_names, n_impls, "generic"); //but we'll fake it for now + return volk_gnsssdr_get_index(impl_names, n_impls, "generic"); //but we'll fake it for now } int volk_gnsssdr_rank_archs( - const char *kern_name, //name of the kernel to rank - const char *impl_names[], //list of implementations by name - const int* impl_deps, //requirement mask per implementation - const bool* alignment, //alignment status of each implementation - size_t n_impls, //number of implementations available - const bool align //if false, filter aligned implementations + const char *kern_name, //name of the kernel to rank + const char *impl_names[], //list of implementations by name + const int *impl_deps, //requirement mask per implementation + const bool *alignment, //alignment status of each implementation + size_t n_impls, //number of implementations available + const bool align //if false, filter aligned implementations ) { size_t i; static volk_gnsssdr_arch_pref_t *volk_gnsssdr_arch_prefs; static size_t n_arch_prefs = 0; static int prefs_loaded = 0; - if(!prefs_loaded) + if (!prefs_loaded) { n_arch_prefs = volk_gnsssdr_load_preferences(&volk_gnsssdr_arch_prefs); prefs_loaded = 1; @@ -81,17 +81,17 @@ int volk_gnsssdr_rank_archs( // If we've defined VOLK_GENERIC to be anything, always return the // 'generic' kernel. Used in GR's QA code. char *gen_env = getenv("VOLK_GENERIC"); - if(gen_env) + if (gen_env) { return volk_gnsssdr_get_index(impl_names, n_impls, "generic"); } //now look for the function name in the prefs list - for(i = 0; i < n_arch_prefs; i++) + for (i = 0; i < n_arch_prefs; i++) { - if(!strncmp(kern_name, volk_gnsssdr_arch_prefs[i].name, sizeof(volk_gnsssdr_arch_prefs[i].name))) //found it + if (!strncmp(kern_name, volk_gnsssdr_arch_prefs[i].name, sizeof(volk_gnsssdr_arch_prefs[i].name))) //found it { - const char *impl_name = align? volk_gnsssdr_arch_prefs[i].impl_a : volk_gnsssdr_arch_prefs[i].impl_u; + const char *impl_name = align ? volk_gnsssdr_arch_prefs[i].impl_a : volk_gnsssdr_arch_prefs[i].impl_u; return volk_gnsssdr_get_index(impl_names, n_impls, impl_name); } } @@ -101,7 +101,7 @@ int volk_gnsssdr_rank_archs( size_t best_index_u = 0; int best_value_a = -1; int best_value_u = -1; - for(i = 0; i < n_impls; i++) + for (i = 0; i < n_impls; i++) { const signed val = __popcnt(impl_deps[i]); if (alignment[i] && val > best_value_a) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.h index 312fb9f47..06c2cd41e 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/volk_gnsssdr_rank_archs.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,33 +13,34 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef GNSS_SDR_VOLK_GNSSSDR_RANK_ARCHS_H #define GNSS_SDR_VOLK_GNSSSDR_RANK_ARCHS_H -#include #include +#include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -int volk_gnsssdr_get_index( - const char *impl_names[], //list of implementations by name - const size_t n_impls, //number of implementations available - const char *impl_name //the implementation name to find -); + int volk_gnsssdr_get_index( + const char *impl_names[], //list of implementations by name + const size_t n_impls, //number of implementations available + const char *impl_name //the implementation name to find + ); -int volk_gnsssdr_rank_archs( - const char *kern_name, //name of the kernel to rank - const char *impl_names[], //list of implementations by name - const int* impl_deps, //requirement mask per implementation - const bool* alignment, //alignment status of each implementation - size_t n_impls, //number of implementations available - const bool align //if false, filter aligned implementations -); + int volk_gnsssdr_rank_archs( + const char *kern_name, //name of the kernel to rank + const char *impl_names[], //list of implementations by name + const int *impl_deps, //requirement mask per implementation + const bool *alignment, //alignment status of each implementation + size_t n_impls, //number of implementations available + const bool align //if false, filter aligned implementations + ); #ifdef __cplusplus } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/CMakeLists.txt index 1a3a8c8ef..3309080ba 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # ######################################################################## diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/README b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/README index 3820201c2..f0da0f59d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/README +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/README @@ -76,8 +76,7 @@ This will put the code for the new kernel into Other kernels must be added by hand. See the following webpages for more information about creating VOLK kernels: - http://gnuradio.org/doc/doxygen/volk_gnsssdr_guide.html - http://gnuradio.org/redmine/projects/gnuradio/wiki/Volk + https://www.gnuradio.org/doc/doxygen/volk_guide.html ====================================================================== diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/__init__.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/__init__.py index 486360958..04e726c70 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/__init__.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,9 +15,9 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # -from cfg import volk_gnsssdr_modtool_config -from volk_gnsssdr_modtool_generate import volk_gnsssdr_modtool +from .cfg import volk_gnsssdr_modtool_config +from .volk_gnsssdr_modtool_generate import volk_gnsssdr_modtool diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/cfg.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/cfg.py index 899950354..e4f12a62c 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/cfg.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/cfg.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,20 +15,19 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # # from __future__ import print_function -import ConfigParser import sys import os -import exceptions import re +from six.moves import configparser, input -class volk_gnsssdr_modtool_config: +class volk_gnsssdr_modtool_config(object): def key_val_sub(self, num, stuff, section): return re.sub('\$' + 'k' + str(num), stuff[num][0], (re.sub('\$' + str(num), stuff[num][1], section[1][num]))); @@ -46,11 +45,11 @@ class volk_gnsssdr_modtool_config: try: val = eval(self.key_val_sub(i, stuff, section)) if val == False: - raise exceptions.ValueError + raise ValueError except ValueError: - raise exceptions.ValueError('Verification function returns False... key:%s, val:%s'%(stuff[i][0], stuff[i][1])) + raise ValueError('Verification function returns False... key:%s, val:%s'%(stuff[i][0], stuff[i][1])) except: - raise exceptions.IOError('bad configuration... key:%s, val:%s'%(stuff[i][0], stuff[i][1])) + raise IOError('bad configuration... key:%s, val:%s'%(stuff[i][0], stuff[i][1])) def __init__(self, cfg=None): @@ -66,7 +65,7 @@ class volk_gnsssdr_modtool_config: self.remapification = [(self.config_name, self.config_defaults_remap)] self.verification = [(self.config_name, self.config_defaults_verify)] default = os.path.join(os.getcwd(), 'volk_gnsssdr_modtool.cfg') - icfg = ConfigParser.RawConfigParser() + icfg = configparser.RawConfigParser() if cfg: icfg.read(cfg) elif os.path.exists(default): @@ -75,7 +74,7 @@ class volk_gnsssdr_modtool_config: print("Initializing config file...") icfg.add_section(self.config_name) for kn in self.config_defaults: - rv = raw_input("%s: "%(kn)) + rv = input("%s: "%(kn)) icfg.set(self.config_name, kn, rv) self.cfg = icfg self.remap() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool index 375558dd8..ded907fbe 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -15,13 +15,13 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # +from __future__ import print_function from volk_gnsssdr_modtool import volk_gnsssdr_modtool, volk_gnsssdr_modtool_config from optparse import OptionParser, OptionGroup -import exceptions import os import sys @@ -57,12 +57,12 @@ if __name__ == '__main__': parser.print_help() elif options.moo: - print " (__) " - print " (oo) " - print " /------\/ " - print " / | || " - print " * /\---/\ " - print " ~~ ~~ " + print(" (__) ") + print(" (oo) ") + print(" /------\/ ") + print(" / | || ") + print(" * /\---/\ ") + print(" ~~ ~~ ") else: my_cfg = volk_gnsssdr_modtool_config(options.config_file); @@ -77,7 +77,7 @@ if __name__ == '__main__': if options.add_kernel: if not options.kernel_name: - raise exceptions.IOError("This action requires the -n option."); + raise IOError("This action requires the -n option."); else: name = options.kernel_name; if options.base_path: @@ -88,7 +88,7 @@ if __name__ == '__main__': if options.remove_kernel: if not options.kernel_name: - raise exceptions.IOError("This action requires the -n option."); + raise IOError("This action requires the -n option."); else: name = options.kernel_name; my_modtool.remove_kernel(name); @@ -105,17 +105,17 @@ if __name__ == '__main__': if options.remote_list: if not options.base_path: - raise exceptions.IOError("This action requires the -b option. Try -l or -k for listing kernels in the base or the module.") + raise IOError("This action requires the -b option. Try -l or -k for listing kernels in the base or the module.") else: base = options.base_path; kernelset = my_modtool.get_current_kernels(base); for i in kernelset: - print i; + print(i); if options.list: kernelset = my_modtool.get_current_kernels(); for i in kernelset: - print i; + print(i); if options.kernels: dest = my_cfg.cfg.get(my_cfg.config_name, 'destination'); @@ -123,4 +123,4 @@ if __name__ == '__main__': base = os.path.join(dest, 'volk_gnsssdr_' + name); kernelset = my_modtool.get_current_kernels(base); for i in kernelset: - print i; + print(i); diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool_generate.py b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool_generate.py index 31a48e500..df613a938 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool_generate.py +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/python/volk_gnsssdr_modtool/volk_gnsssdr_modtool_generate.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -21,15 +21,10 @@ from __future__ import print_function import os -import glob -import sys import re import glob -import shutil -import exceptions -from sets import Set -class volk_gnsssdr_modtool: +class volk_gnsssdr_modtool(object): def __init__(self, cfg): self.volk_gnsssdr = re.compile('volk_gnsssdr'); self.remove_after_underscore = re.compile("_.*"); @@ -58,10 +53,10 @@ class volk_gnsssdr_modtool: else: name = self.get_basename(base); if name == '': - hdr_files = glob.glob(os.path.join(base, "kernels/volk_gnsssdr/*.h")); + hdr_files = sorted(glob.glob(os.path.join(base, "kernels/volk_gnsssdr/*.h"))); begins = re.compile("(?<=volk_gnsssdr_).*") else: - hdr_files = glob.glob(os.path.join(base, "kernels/volk_gnsssdr_" + name + "/*.h")); + hdr_files = sorted(glob.glob(os.path.join(base, "kernels/volk_gnsssdr_" + name + "/*.h"))); begins = re.compile("(?<=volk_gnsssdr_" + name + "_).*") datatypes = []; @@ -96,23 +91,32 @@ class volk_gnsssdr_modtool: dest = os.path.join(self.my_dict['destination'], 'volk_gnsssdr_' + self.my_dict['name']) if os.path.exists(dest): - raise exceptions.IOError("Destination %s already exits!"%(dest)); + raise IOError("Destination %s already exits!" % (dest)); if not os.path.exists(os.path.join(self.my_dict['destination'], 'volk_gnsssdr_' + self.my_dict['name'], 'kernels/volk_gnsssdr_' + self.my_dict['name'])): os.makedirs(os.path.join(self.my_dict['destination'], 'volk_gnsssdr_' + self.my_dict['name'], 'kernels/volk_gnsssdr_' + self.my_dict['name'])) current_kernel_names = self.get_current_kernels(); + need_ifdef_updates = ["constant.h", "volk_complex.h", "volk_malloc.h", "volk_prefs.h", + "volk_common.h", "volk_cpu.tmpl.h", "volk_config_fixed.tmpl.h", + "volk_typedefs.h", "volk.tmpl.h"] for root, dirnames, filenames in os.walk(self.my_dict['base']): for name in filenames: - t_table = map(lambda a: re.search(a, name), current_kernel_names); + t_table = [re.search(a, name) for a in current_kernel_names] t_table = set(t_table); if t_table == set([None]): infile = os.path.join(root, name); instring = open(infile, 'r').read(); outstring = re.sub(self.volk_gnsssdr, 'volk_gnsssdr_' + self.my_dict['name'], instring); + if name in need_ifdef_updates: + outstring = re.sub(self.volk_included, 'INCLUDED_VOLK_' + self.my_dict['name'].upper(), outstring) newname = re.sub(self.volk_gnsssdr, 'volk_gnsssdr_' + self.my_dict['name'], name); relpath = os.path.relpath(infile, self.my_dict['base']); + if name == 'VolkConfig.cmake.in': + outstring = re.sub("VOLK", 'VOLK_' + self.my_dict['name'].upper(), outstring) + newname = "Volk%sConfig.cmake.in" % self.my_dict['name'] + newrelpath = re.sub(self.volk_gnsssdr, 'volk_gnsssdr_' + self.my_dict['name'], relpath); dest = os.path.join(self.my_dict['destination'], 'volk_gnsssdr_' + self.my_dict['name'], os.path.dirname(newrelpath), newname); @@ -157,7 +161,7 @@ class volk_gnsssdr_modtool: open(dest, 'w+').write(outstring); # copy orc proto-kernels if they exist - for orcfile in glob.glob(inpath + '/orc/' + top + name + '*.orc'): + for orcfile in sorted(glob.glob(inpath + '/kernels/volk_gnsssdr/asm/orc/' + top + name + '*.orc')): if os.path.isfile(orcfile): instring = open(orcfile, 'r').read(); outstring = re.sub(oldvolk_gnsssdr, 'volk_gnsssdr_' + self.my_dict['name'], instring); @@ -179,16 +183,11 @@ class volk_gnsssdr_modtool: base = os.path.join(self.my_dict['destination'], top[:-1]) ; if not name in self.get_current_kernels(): - - raise exceptions.IOError("Requested kernel %s is not in module %s"%(name,base)); - - + raise IOError("Requested kernel %s is not in module %s" % (name,base)); inpath = os.path.abspath(base); - - kernel = re.compile(name) - search_kernels = Set([kernel]) + search_kernels = set([kernel]) profile = re.compile('^\s*VOLK_PROFILE') puppet = re.compile('^\s*VOLK_PUPPET') src_dest = os.path.join(inpath, 'apps/', top[:-1] + '_profile.cc'); @@ -244,7 +243,7 @@ class volk_gnsssdr_modtool: else: basename = self.get_basename(base); if not name in self.get_current_kernels(base): - raise exceptions.IOError("Requested kernel %s is not in module %s"%(name,base)); + raise IOError("Requested kernel %s is not in module %s" % (name, base)); inpath = os.path.abspath(base); if len(basename) > 0: @@ -256,7 +255,7 @@ class volk_gnsssdr_modtool: self.convert_kernel(oldvolk_gnsssdr, name, base, inpath, top); kernel = re.compile(name) - search_kernels = Set([kernel]) + search_kernels = set([kernel]) profile = re.compile('^\s*VOLK_PROFILE') puppet = re.compile('^\s*VOLK_PUPPET') @@ -324,8 +323,3 @@ class volk_gnsssdr_modtool: write_okay = False if write_okay: open(dest, 'a').write(otherline); - - - - - diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.c index 95f5f057c..260f1fe77 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,7 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include @@ -31,85 +31,97 @@ static intptr_t __alignment_mask = 0; struct volk_gnsssdr_machine *get_machine(void) { - extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; - extern unsigned int n_volk_gnsssdr_machines; - static struct volk_gnsssdr_machine *machine = NULL; + extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; + extern unsigned int n_volk_gnsssdr_machines; + static struct volk_gnsssdr_machine *machine = NULL; - if(machine != NULL) - return machine; - else { - unsigned int max_score = 0; - unsigned int i; - struct volk_gnsssdr_machine *max_machine = NULL; - for(i=0; icaps & (~volk_gnsssdr_get_lvarch()))) { - if(volk_gnsssdr_machines[i]->caps > max_score) { - max_score = volk_gnsssdr_machines[i]->caps; - max_machine = volk_gnsssdr_machines[i]; + if (machine != NULL) + return machine; + else + { + unsigned int max_score = 0; + unsigned int i; + struct volk_gnsssdr_machine *max_machine = NULL; + for (i = 0; i < n_volk_gnsssdr_machines; i++) + { + if (!(volk_gnsssdr_machines[i]->caps & (~volk_gnsssdr_get_lvarch()))) + { + if (volk_gnsssdr_machines[i]->caps > max_score) + { + max_score = volk_gnsssdr_machines[i]->caps; + max_machine = volk_gnsssdr_machines[i]; + } + } + } + machine = max_machine; + //printf("Using Volk machine: %s\n", machine->name); + __alignment = machine->alignment; + __alignment_mask = (intptr_t)(__alignment - 1); + return machine; } - } - } - machine = max_machine; - //printf("Using Volk machine: %s\n", machine->name); - __alignment = machine->alignment; - __alignment_mask = (intptr_t)(__alignment-1); - return machine; - } } void volk_gnsssdr_list_machines(void) { - extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; - extern unsigned int n_volk_gnsssdr_machines; + extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; + extern unsigned int n_volk_gnsssdr_machines; - unsigned int i; - for(i=0; icaps & (~volk_gnsssdr_get_lvarch()))) { - printf("%s;", volk_gnsssdr_machines[i]->name); - } - } - printf("\n"); + unsigned int i; + for (i = 0; i < n_volk_gnsssdr_machines; i++) + { + if (!(volk_gnsssdr_machines[i]->caps & (~volk_gnsssdr_get_lvarch()))) + { + printf("%s;", volk_gnsssdr_machines[i]->name); + } + } + printf("\n"); } -const char* volk_gnsssdr_get_machine(void) +const char *volk_gnsssdr_get_machine(void) { - extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; - extern unsigned int n_volk_gnsssdr_machines; - static struct volk_gnsssdr_machine *machine = NULL; + extern struct volk_gnsssdr_machine *volk_gnsssdr_machines[]; + extern unsigned int n_volk_gnsssdr_machines; + static struct volk_gnsssdr_machine *machine = NULL; - if(machine != NULL) - return machine->name; - else { - unsigned int max_score = 0; - unsigned int i; - struct volk_gnsssdr_machine *max_machine = NULL; - for(i=0; icaps & (~volk_gnsssdr_get_lvarch()))) { - if(volk_gnsssdr_machines[i]->caps > max_score) { - max_score = volk_gnsssdr_machines[i]->caps; - max_machine = volk_gnsssdr_machines[i]; + if (machine != NULL) + return machine->name; + else + { + unsigned int max_score = 0; + unsigned int i; + struct volk_gnsssdr_machine *max_machine = NULL; + for (i = 0; i < n_volk_gnsssdr_machines; i++) + { + if (!(volk_gnsssdr_machines[i]->caps & (~volk_gnsssdr_get_lvarch()))) + { + if (volk_gnsssdr_machines[i]->caps > max_score) + { + max_score = volk_gnsssdr_machines[i]->caps; + max_machine = volk_gnsssdr_machines[i]; + } + } + } + machine = max_machine; + return machine->name; } - } - } - machine = max_machine; - return machine->name; - } } size_t volk_gnsssdr_get_alignment(void) { - get_machine(); //ensures alignment is set + get_machine(); //ensures alignment is set return __alignment; } bool volk_gnsssdr_is_aligned(const void *ptr) { - return ((intptr_t)(ptr) & __alignment_mask) == 0; + return ((intptr_t)(ptr)&__alignment_mask) == 0; } #define LV_HAVE_GENERIC #define LV_HAVE_DISPATCHER +// clang-format off + %for kern in kernels: %if kern.has_dispatcher: @@ -190,6 +202,8 @@ void ${kern.name}_manual(${kern.arglist_full}, const char* impl_name) ); } + + volk_gnsssdr_func_desc_t ${kern.name}_get_func_desc(void) { const char **impl_names = get_machine()->${kern.name}_impl_names; const int *impl_deps = get_machine()->${kern.name}_impl_deps; @@ -205,3 +219,5 @@ volk_gnsssdr_func_desc_t ${kern.name}_get_func_desc(void) { } %endfor + + // clang-format on diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.h index 0586dd640..51f8026fc 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr.tmpl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,20 +13,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_RUNTIME #define INCLUDED_VOLK_GNSSSDR_RUNTIME -#include -#include #include #include +#include #include - -#include +#include #include +#include __VOLK_DECL_BEGIN @@ -35,14 +34,14 @@ typedef struct volk_gnsssdr_func_desc const char **impl_names; const int *impl_deps; const bool *impl_alignment; - const size_t n_impls; + size_t n_impls; } volk_gnsssdr_func_desc_t; //! Prints a list of machines available VOLK_API void volk_gnsssdr_list_machines(void); //! Returns the name of the machine this instance will use -VOLK_API const char* volk_gnsssdr_get_machine(void); +VOLK_API const char *volk_gnsssdr_get_machine(void); //! Get the machine alignment in bytes VOLK_API size_t volk_gnsssdr_get_alignment(void); @@ -68,6 +67,7 @@ VOLK_API size_t volk_gnsssdr_get_alignment(void); */ VOLK_API bool volk_gnsssdr_is_aligned(const void *ptr); +// clang-format off %for kern in kernels: //! A function pointer to the dispatcher implementation @@ -82,11 +82,10 @@ extern VOLK_API ${kern.pname} ${kern.name}_u; //! Call into a specific implementation given by name extern VOLK_API void ${kern.name}_manual(${kern.arglist_full}, const char* impl_name); -//! Get description paramaters for this kernel +//! Get description parameters for this kernel extern VOLK_API volk_gnsssdr_func_desc_t ${kern.name}_get_func_desc(void); %endfor - __VOLK_DECL_END - +// clang-format on #endif /*INCLUDED_VOLK_GNSSSDR_RUNTIME*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_config_fixed.tmpl.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_config_fixed.tmpl.h index ed55d0b58..29c936d7b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_config_fixed.tmpl.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_config_fixed.tmpl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,16 +13,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_CONFIG_FIXED_H #define INCLUDED_VOLK_GNSSSDR_CONFIG_FIXED_H +// clang-format off %for i, arch in enumerate(archs): -//#ifndef LV_${arch.name.upper()} +#ifndef LV_${arch.name.upper()} #define LV_${arch.name.upper()} ${i} -//#endif +#endif %endfor - +// clang-format on #endif /*INCLUDED_VOLK_GNSSSDR_CONFIG_FIXED*/ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c index d77bf49ad..420b5c91d 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,7 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include @@ -24,50 +24,54 @@ struct VOLK_CPU volk_gnsssdr_cpu; #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) - #define VOLK_CPU_x86 +#define VOLK_CPU_x86 #endif #if defined(VOLK_CPU_x86) //implement get cpuid for gcc compilers using a system or local copy of cpuid.h #if defined(__GNUC__) - #include - #define cpuid_x86(op, r) __get_cpuid(op, (unsigned int *)r+0, (unsigned int *)r+1, (unsigned int *)r+2, (unsigned int *)r+3) - #define cpuid_x86_count(op, count, regs) __cpuid_count(op, count, *((unsigned int*)regs), *((unsigned int*)regs+1), *((unsigned int*)regs+2), *((unsigned int*)regs+3)) +#include +#define cpuid_x86(op, r) __get_cpuid(op, (unsigned int *)r + 0, (unsigned int *)r + 1, (unsigned int *)r + 2, (unsigned int *)r + 3) +#define cpuid_x86_count(op, count, regs) __cpuid_count(op, count, *((unsigned int *)regs), *((unsigned int *)regs + 1), *((unsigned int *)regs + 2), *((unsigned int *)regs + 3)) - /* Return Intel AVX extended CPU capabilities register. +/* Return Intel AVX extended CPU capabilities register. * This function will bomb on non-AVX-capable machines, so * check for AVX capability before executing. */ - #if ((__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 2) || (__clang_major__ >= 3)) && defined(HAVE_XGETBV) - static inline unsigned long long _xgetbv(unsigned int index){ - unsigned int eax, edx; - __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); - return ((unsigned long long)edx << 32) | eax; - } - #define __xgetbv() _xgetbv(0) - #else - #define __xgetbv() 0 - #endif +#if ((__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 2) || (__clang_major__ >= 3)) && defined(HAVE_XGETBV) +static inline unsigned long long _xgetbv(unsigned int index) +{ + unsigned int eax, edx; + __VOLK_ASM __VOLK_VOLATILE("xgetbv" + : "=a"(eax), "=d"(edx) + : "c"(index)); + return ((unsigned long long)edx << 32) | eax; +} +#define __xgetbv() _xgetbv(0) +#else +#define __xgetbv() 0 +#endif //implement get cpuid for MSVC compilers using __cpuid intrinsic #elif defined(_MSC_VER) && defined(HAVE_INTRIN_H) - #include - #define cpuid_x86(op, r) __cpuid(((int*)r), op) +#include +#define cpuid_x86(op, r) __cpuid(((int *)r), op) - #if defined(_XCR_XFEATURE_ENABLED_MASK) - #define __xgetbv() _xgetbv(_XCR_XFEATURE_ENABLED_MASK) - #else - #define __xgetbv() 0 - #endif +#if defined(_XCR_XFEATURE_ENABLED_MASK) +#define __xgetbv() _xgetbv(_XCR_XFEATURE_ENABLED_MASK) +#else +#define __xgetbv() 0 +#endif #else - #error "A get cpuid for volk_gnsssdr is not available on this compiler..." -#endif //defined(__GNUC__) +#error "A get cpuid for volk_gnsssdr is not available on this compiler..." +#endif //defined(__GNUC__) -#endif //defined(VOLK_CPU_x86) +#endif //defined(VOLK_CPU_x86) -static inline unsigned int cpuid_count_x86_bit(unsigned int level, unsigned int count, unsigned int reg, unsigned int bit) { +static inline unsigned int cpuid_count_x86_bit(unsigned int level, unsigned int count, unsigned int reg, unsigned int bit) +{ #if defined(VOLK_CPU_x86) unsigned int regs[4] = {0}; cpuid_x86_count(level, count, regs); @@ -77,10 +81,11 @@ static inline unsigned int cpuid_count_x86_bit(unsigned int level, unsigned int #endif } -static inline unsigned int cpuid_x86_bit(unsigned int reg, unsigned int op, unsigned int bit) { +static inline unsigned int cpuid_x86_bit(unsigned int reg, unsigned int op, unsigned int bit) +{ #if defined(VOLK_CPU_x86) unsigned int regs[4]; - memset(regs, 0, sizeof(unsigned int)*4); + memset(regs, 0, sizeof(unsigned int) * 4); cpuid_x86(op, regs); return regs[reg] >> bit & 0x01; #else @@ -88,10 +93,11 @@ static inline unsigned int cpuid_x86_bit(unsigned int reg, unsigned int op, unsi #endif } -static inline unsigned int check_extended_cpuid(unsigned int val) { +static inline unsigned int check_extended_cpuid(unsigned int val) +{ #if defined(VOLK_CPU_x86) unsigned int regs[4]; - memset(regs, 0, sizeof(unsigned int)*4); + memset(regs, 0, sizeof(unsigned int) * 4); cpuid_x86(0x80000000, regs); return regs[0] >= val; #else @@ -99,7 +105,8 @@ static inline unsigned int check_extended_cpuid(unsigned int val) { #endif } -static inline unsigned int get_avx_enabled(void) { +static inline unsigned int get_avx_enabled(void) +{ #if defined(VOLK_CPU_x86) return __xgetbv() & 0x6; #else @@ -107,7 +114,8 @@ static inline unsigned int get_avx_enabled(void) { #endif } -static inline unsigned int get_avx2_enabled(void) { +static inline unsigned int get_avx2_enabled(void) +{ #if defined(VOLK_CPU_x86) return __xgetbv() & 0x6; #else @@ -115,30 +123,41 @@ static inline unsigned int get_avx2_enabled(void) { #endif } +static inline unsigned int get_avx512_enabled(void) +{ +#if defined(VOLK_CPU_x86) + return __xgetbv() & 0xE6; //check for zmm, xmm and ymm regs +#else + return 0; +#endif +} + //neon detection is linux specific #if defined(__arm__) && defined(__linux__) - #include - #include - #include - #define VOLK_CPU_ARM +#include +#include +#include +#define VOLK_CPU_ARMV7 #endif -static int has_neon(void){ -#if defined(VOLK_CPU_ARM) +static int has_neonv7(void) +{ +#if defined(VOLK_CPU_ARMV7) FILE *auxvec_f; unsigned long auxvec[2]; unsigned int found_neon = 0; auxvec_f = fopen("/proc/self/auxv", "rb"); - if(!auxvec_f) return 0; + if (!auxvec_f) return 0; size_t r = 1; //so auxv is basically 32b of ID and 32b of value //so it goes like this - while(!found_neon && r) { - r = fread(auxvec, sizeof(unsigned long), 2, auxvec_f); - if((auxvec[0] == AT_HWCAP) && (auxvec[1] & HWCAP_NEON)) - found_neon = 1; - } + while (!found_neon && r) + { + r = fread(auxvec, sizeof(unsigned long), 2, auxvec_f); + if ((auxvec[0] == AT_HWCAP) && (auxvec[1] & HWCAP_NEON)) + found_neon = 1; + } fclose(auxvec_f); return found_neon; @@ -147,6 +166,54 @@ static int has_neon(void){ #endif } +//\todo: Fix this to really check for neon on aarch64 +//neon detection is linux specific +#if defined(__aarch64__) && defined(__linux__) +#include +#include +#include +#define VOLK_CPU_ARMV8 +#endif + +static int has_neonv8(void) +{ +#if defined(VOLK_CPU_ARMV8) + FILE *auxvec_f; + unsigned long auxvec[2]; + unsigned int found_neon = 0; + auxvec_f = fopen("/proc/self/auxv", "rb"); + if (!auxvec_f) return 0; + + size_t r = 1; + //so auxv is basically 32b of ID and 32b of value + //so it goes like this + while (!found_neon && r) + { + r = fread(auxvec, sizeof(unsigned long), 2, auxvec_f); + if ((auxvec[0] == AT_HWCAP) && (auxvec[1] & HWCAP_ASIMD)) + found_neon = 1; + } + + fclose(auxvec_f); + return found_neon; +#else + return 0; +#endif +} + +static int has_neon(void) +{ +#if defined(VOLK_CPU_ARMV8) || defined(VOLK_CPU_ARMV7) + if (has_neonv7() || has_neonv8()) + return 1; + else + return 0; +#else + return 0; +#endif +} +// clang-format off + %for arch in archs: static int i_can_has_${arch.name} (void) { %for check, params in arch.checks: @@ -195,3 +262,4 @@ unsigned int volk_gnsssdr_get_lvarch() { %endfor return retval; } +// clang-format on diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.h index 20dbac2cc..940c2e30a 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,7 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_CPU_H @@ -23,16 +23,18 @@ __VOLK_DECL_BEGIN +// clang-format off struct VOLK_CPU { %for arch in archs: int (*has_${arch.name}) (); %endfor }; +// clang-format on extern struct VOLK_CPU volk_gnsssdr_cpu; -void volk_gnsssdr_cpu_init (); -unsigned int volk_gnsssdr_get_lvarch (); +void volk_gnsssdr_cpu_init(); +unsigned int volk_gnsssdr_get_lvarch(); __VOLK_DECL_END diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machine_xxx.tmpl.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machine_xxx.tmpl.c index c6182cb50..30bdb47d5 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machine_xxx.tmpl.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machine_xxx.tmpl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,9 +13,11 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ +// clang-format off + <% this_machine = machine_dict[args[0]] %> <% arch_names = this_machine.arch_names %> @@ -31,6 +33,7 @@ #include "config.h" #endif + %for kern in kernels: #include %endfor @@ -56,3 +59,4 @@ struct volk_gnsssdr_machine volk_gnsssdr_machine_${this_machine.name} = { <% len_impls = len(impls) %> ${len_impls}, %endfor }; +// clang-format on diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.c index 1485a34e0..91d9748a0 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,13 +13,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #include #include #include "volk_gnsssdr_machines.h" +// clang-format off struct volk_gnsssdr_machine *volk_gnsssdr_machines[] = { %for machine in machines: #ifdef LV_MACHINE_${machine.name.upper()} @@ -27,5 +28,5 @@ struct volk_gnsssdr_machine *volk_gnsssdr_machines[] = { #endif %endfor }; - -unsigned int n_volk_gnsssdr_machines = sizeof(volk_gnsssdr_machines)/sizeof(*volk_gnsssdr_machines); +// clang-format on +unsigned int n_volk_gnsssdr_machines = sizeof(volk_gnsssdr_machines) / sizeof(*volk_gnsssdr_machines); diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.h index 10e955e25..70ee588ca 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_machines.tmpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_LIBVOLK_GNSSSDR_MACHINES_H @@ -27,6 +27,7 @@ __VOLK_DECL_BEGIN +// clang-format off struct volk_gnsssdr_machine { const unsigned int caps; //capabilities (i.e., archs compiled into this machine, in the volk_gnsssdr_get_lvarch format) const char *name; @@ -48,5 +49,6 @@ extern struct volk_gnsssdr_machine volk_gnsssdr_machine_${machine.name}; %endfor __VOLK_DECL_END +// clang-format on -#endif //INCLUDED_LIBVOLK_GNSSSDR_MACHINES_H +#endif //INCLUDED_LIBVOLK_GNSSSDR_MACHINES_H diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_typedefs.tmpl.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_typedefs.tmpl.h index def7e24c3..d55149147 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_typedefs.tmpl.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_typedefs.tmpl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +/* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * This file is part of GNSS-SDR. * @@ -13,17 +13,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . */ #ifndef INCLUDED_VOLK_GNSSSDR_TYPEDEFS #define INCLUDED_VOLK_GNSSSDR_TYPEDEFS -#include #include +#include +// clang-format off %for kern in kernels: typedef void (*${kern.pname})(${kern.arglist_types}); %endfor +// clang-format on #endif /*INCLUDED_VOLK_GNSSSDR_TYPEDEFS*/ diff --git a/src/algorithms/observables/CMakeLists.txt b/src/algorithms/observables/CMakeLists.txt index 20a0f5449..1841d3dfc 100644 --- a/src/algorithms/observables/CMakeLists.txt +++ b/src/algorithms/observables/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,8 +13,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) -add_subdirectory(gnuradio_blocks) \ No newline at end of file +add_subdirectory(gnuradio_blocks) diff --git a/src/algorithms/observables/adapters/CMakeLists.txt b/src/algorithms/observables/adapters/CMakeLists.txt index dcb40e527..ef0df1d7d 100644 --- a/src/algorithms/observables/adapters/CMakeLists.txt +++ b/src/algorithms/observables/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,31 +13,30 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(OBS_ADAPTER_SOURCES - gps_l1_ca_observables.cc - gps_l2c_observables.cc - galileo_e1_observables.cc - galileo_e5a_observables.cc - hybrid_observables.cc + hybrid_observables.cc +) + +set(OBS_ADAPTER_HEADERS + hybrid_observables.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/observables/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/observables/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB OBS_ADAPTER_HEADERS "*.h") -list(SORT OBS_ADAPTER_HEADERS) add_library(obs_adapters ${OBS_ADAPTER_SOURCES} ${OBS_ADAPTER_HEADERS}) source_group(Headers FILES ${OBS_ADAPTER_HEADERS}) target_link_libraries(obs_adapters obs_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES}) diff --git a/src/algorithms/observables/adapters/galileo_e1_observables.cc b/src/algorithms/observables/adapters/galileo_e1_observables.cc deleted file mode 100644 index 28edee2d5..000000000 --- a/src/algorithms/observables/adapters/galileo_e1_observables.cc +++ /dev/null @@ -1,95 +0,0 @@ -/*! - * \file galileo_e1_observables.cc - * \brief Implementation of an adapter of a Galileo E1 observables block - * to a ObservablesInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "galileo_e1_observables.h" -#include -#include "configuration_interface.h" -#include "Galileo_E1.h" - -using google::LogMessage; - -GalileoE1Observables::GalileoE1Observables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - std::string default_dump_filename = "./observables.dat"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - unsigned int history_deep = configuration->property(role + ".averaging_depth", GALILEO_E1_HISTORY_DEEP); - observables_ = galileo_e1_make_observables_cc(in_streams_, dump_, dump_filename_, history_deep); - DLOG(INFO) << "pseudorange(" << observables_->unique_id() << ")"; -} - - - - -GalileoE1Observables::~GalileoE1Observables() -{} - - - - -void GalileoE1Observables::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - - -void GalileoE1Observables::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - - - - -gr::basic_block_sptr GalileoE1Observables::get_left_block() -{ - return observables_; -} - - - - -gr::basic_block_sptr GalileoE1Observables::get_right_block() -{ - return observables_; -} diff --git a/src/algorithms/observables/adapters/galileo_e1_observables.h b/src/algorithms/observables/adapters/galileo_e1_observables.h deleted file mode 100644 index 8aad5b142..000000000 --- a/src/algorithms/observables/adapters/galileo_e1_observables.h +++ /dev/null @@ -1,89 +0,0 @@ -/*! - * \file galileo_e1_observables.h - * \brief Implementation of an adapter of a Galileo E1 observables block - * to a ObservablesInterface - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GALILEO_E1_OBSERVABLES_H_ -#define GNSS_SDR_GALILEO_E1_OBSERVABLES_H_ - -#include -#include "observables_interface.h" -#include "galileo_e1_observables_cc.h" - - -class ConfigurationInterface; - -/*! - * \brief This class implements an ObservablesInterface for Galileo E1B - */ -class GalileoE1Observables : public ObservablesInterface -{ -public: - GalileoE1Observables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - virtual ~GalileoE1Observables(); - std::string role() - { - return role_; - } - - //! Returns "Galileo_E1B_Observables" - std::string implementation() - { - return "Galileo_E1B_Observables"; - } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation - size_t item_size() - { - return sizeof(gr_complex); - } - -private: - galileo_e1_observables_cc_sptr observables_; - bool dump_; - std::string dump_filename_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; -}; - -#endif diff --git a/src/algorithms/observables/adapters/galileo_e5a_observables.cc b/src/algorithms/observables/adapters/galileo_e5a_observables.cc deleted file mode 100644 index 239b4b17d..000000000 --- a/src/algorithms/observables/adapters/galileo_e5a_observables.cc +++ /dev/null @@ -1,96 +0,0 @@ -/*! - * \file galileo_e5a_observables.cc - * \brief Implementation of an adapter of a Galileo E5a observables block - * to a ObservablesInterface - * \author Carles Fernandez 2016. carles.fernandez(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - - #include "galileo_e5a_observables.h" - #include "configuration_interface.h" - #include - #include "Galileo_E5a.h" - - using google::LogMessage; - - GalileoE5aObservables::GalileoE5aObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) - { - std::string default_dump_filename = "./observables.dat"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - unsigned int default_depth = GALILEO_E5A_HISTORY_DEEP; - unsigned int history_deep = configuration->property(role + ".averaging_depth", default_depth); - observables_ = hybrid_make_observables_cc(in_streams_, dump_, dump_filename_, history_deep); - DLOG(INFO) << "pseudorange(" << observables_->unique_id() << ")"; - } - - - - - GalileoE5aObservables::~GalileoE5aObservables() - {} - - - - - void GalileoE5aObservables::connect(gr::top_block_sptr top_block) - { - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; - } - - - - void GalileoE5aObservables::disconnect(gr::top_block_sptr top_block) - { - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect - } - - - - - gr::basic_block_sptr GalileoE5aObservables::get_left_block() - { - return observables_; - } - - - - - gr::basic_block_sptr GalileoE5aObservables::get_right_block() - { - return observables_; - } diff --git a/src/algorithms/observables/adapters/galileo_e5a_observables.h b/src/algorithms/observables/adapters/galileo_e5a_observables.h deleted file mode 100644 index 89898c99a..000000000 --- a/src/algorithms/observables/adapters/galileo_e5a_observables.h +++ /dev/null @@ -1,88 +0,0 @@ -/*! - * \file galileo_e5a_observables.h - * \brief Implementation of an adapter of a Galileo E5a observables block - * to a ObservablesInterface - * \author Carles Fernandez 2016. carles.fernandez(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GALILEO_E5A_OBSERVABLES_H_ -#define GNSS_SDR_GALILEO_E5A_OBSERVABLES_H_ - -#include -#include "observables_interface.h" -#include "hybrid_observables_cc.h" - - -class ConfigurationInterface; - -/*! - * \brief This class implements an ObservablesInterface for Galileo E5A - */ -class GalileoE5aObservables : public ObservablesInterface -{ -public: - GalileoE5aObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - virtual ~GalileoE5aObservables(); - std::string role() - { - return role_; - } - - //! Returns "Galileo_E5A_Observables" - std::string implementation() - { - return "Galileo_E5A_Observables"; - } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation - size_t item_size() - { - return sizeof(gr_complex); - } - -private: - hybrid_observables_cc_sptr observables_; - bool dump_; - std::string dump_filename_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; -}; - -#endif diff --git a/src/algorithms/observables/adapters/gps_l1_ca_observables.cc b/src/algorithms/observables/adapters/gps_l1_ca_observables.cc deleted file mode 100644 index b75f1c3ef..000000000 --- a/src/algorithms/observables/adapters/gps_l1_ca_observables.cc +++ /dev/null @@ -1,95 +0,0 @@ -/*! - * \file gps_l1_ca_observables.cc - * \brief Implementation of an adapter of a GPS L1 C/A observables block - * to a ObservablesInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "gps_l1_ca_observables.h" -#include "configuration_interface.h" -#include -#include "GPS_L1_CA.h" - -using google::LogMessage; - -GpsL1CaObservables::GpsL1CaObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - std::string default_dump_filename = "./observables.dat"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - unsigned int history_deep = configuration->property(role + ".averaging_depth", GPS_L1_CA_HISTORY_DEEP); - observables_ = gps_l1_ca_make_observables_cc(in_streams_, dump_, dump_filename_, history_deep); - DLOG(INFO) << "pseudorange(" << observables_->unique_id() << ")"; -} - - - - -GpsL1CaObservables::~GpsL1CaObservables() -{} - - - - -void GpsL1CaObservables::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - - -void GpsL1CaObservables::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - - - - -gr::basic_block_sptr GpsL1CaObservables::get_left_block() -{ - return observables_; -} - - - - -gr::basic_block_sptr GpsL1CaObservables::get_right_block() -{ - return observables_; -} diff --git a/src/algorithms/observables/adapters/gps_l1_ca_observables.h b/src/algorithms/observables/adapters/gps_l1_ca_observables.h deleted file mode 100644 index cf83be10d..000000000 --- a/src/algorithms/observables/adapters/gps_l1_ca_observables.h +++ /dev/null @@ -1,89 +0,0 @@ -/*! - * \file gps_l1_ca_observables.h - * \brief Interface of an adapter of a GPS L1 C/A observables block - * to a ObservablesInterface - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GPS_L1_CA_OBSERVABLES_H_ -#define GNSS_SDR_GPS_L1_CA_OBSERVABLES_H_ - -#include -#include "observables_interface.h" -#include "gps_l1_ca_observables_cc.h" - - -class ConfigurationInterface; - -/*! - * \brief This class implements an ObservablesInterface for GPS L1 C/A - */ -class GpsL1CaObservables : public ObservablesInterface -{ -public: - GpsL1CaObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - virtual ~GpsL1CaObservables(); - std::string role() - { - return role_; - } - - //! Returns "GPS_L1_CA_Observables" - std::string implementation() - { - return "GPS_L1_CA_Observables"; - } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation - size_t item_size() - { - return sizeof(gr_complex); - } - -private: - gps_l1_ca_observables_cc_sptr observables_; - bool dump_; - //unsigned int fs_in_; - std::string dump_filename_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; -}; - -#endif diff --git a/src/algorithms/observables/adapters/gps_l2c_observables.cc b/src/algorithms/observables/adapters/gps_l2c_observables.cc deleted file mode 100644 index 4ceffd1a1..000000000 --- a/src/algorithms/observables/adapters/gps_l2c_observables.cc +++ /dev/null @@ -1,87 +0,0 @@ -/*! - * \file gps_l2c_observables.cc - * \brief Implementation of an adapter of a GPS L2 C(M) observables block - * to a ObservablesInterface - * \author Carles Fernandez 2016. carles.fernandez(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "gps_l2c_observables.h" -#include "configuration_interface.h" -#include -#include "GPS_L2C.h" - -using google::LogMessage; - -GpsL2CObservables::GpsL2CObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) -{ - std::string default_dump_filename = "./observables.dat"; - DLOG(INFO) << "role " << role; - dump_ = configuration->property(role + ".dump", false); - dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - unsigned int default_depth = GPS_L2C_HISTORY_DEEP; - unsigned int history_deep = configuration->property(role + ".averaging_depth", default_depth); - observables_ = hybrid_make_observables_cc(in_streams_, dump_, dump_filename_, history_deep); - DLOG(INFO) << "pseudorange(" << observables_->unique_id() << ")"; -} - - -GpsL2CObservables::~GpsL2CObservables() -{} - - -void GpsL2CObservables::connect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to connect internally - DLOG(INFO) << "nothing to connect internally"; -} - - -void GpsL2CObservables::disconnect(gr::top_block_sptr top_block) -{ - if(top_block) { /* top_block is not null */}; - // Nothing to disconnect -} - - -gr::basic_block_sptr GpsL2CObservables::get_left_block() -{ - return observables_; -} - - -gr::basic_block_sptr GpsL2CObservables::get_right_block() -{ - return observables_; -} diff --git a/src/algorithms/observables/adapters/gps_l2c_observables.h b/src/algorithms/observables/adapters/gps_l2c_observables.h deleted file mode 100644 index aee598f73..000000000 --- a/src/algorithms/observables/adapters/gps_l2c_observables.h +++ /dev/null @@ -1,88 +0,0 @@ -/*! - * \file gps_l2c_observables.h - * \brief Implementation of an adapter of a GPS L2C(M) observables block - * to a ObservablesInterface - * \author Carles Fernandez 2016. carles.fernandez(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GPS_L2C_OBSERVABLES_H_ -#define GNSS_SDR_GPS_L2C_OBSERVABLES_H_ - -#include -#include "observables_interface.h" -#include "hybrid_observables_cc.h" - - -class ConfigurationInterface; - -/*! - * \brief This class implements an ObservablesInterface for GPS L2C - */ -class GpsL2CObservables : public ObservablesInterface -{ -public: - GpsL2CObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); - virtual ~GpsL2CObservables(); - std::string role() - { - return role_; - } - - //! Returns "GPS_L2C_Observables" - std::string implementation() - { - return "GPS_L2C_Observables"; - } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void reset() - { - return; - } - - //! All blocks must have an item_size() function implementation - size_t item_size() - { - return sizeof(gr_complex); - } - -private: - hybrid_observables_cc_sptr observables_; - bool dump_; - std::string dump_filename_; - std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; -}; - -#endif diff --git a/src/algorithms/observables/adapters/hybrid_observables.cc b/src/algorithms/observables/adapters/hybrid_observables.cc index e1d539d74..f92c02b48 100644 --- a/src/algorithms/observables/adapters/hybrid_observables.cc +++ b/src/algorithms/observables/adapters/hybrid_observables.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,72 +33,52 @@ #include "hybrid_observables.h" #include "configuration_interface.h" #include -#include "GPS_L1_CA.h" -#include "Galileo_E1.h" + using google::LogMessage; HybridObservables::HybridObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { std::string default_dump_filename = "./observables.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); + dump_mat_ = configuration->property(role + ".dump_mat", true); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); - unsigned int default_depth = 0; - if (GPS_L1_CA_HISTORY_DEEP == GALILEO_E1_HISTORY_DEEP) - { - default_depth = GPS_L1_CA_HISTORY_DEEP; - } - else - { - default_depth = 100; - } - unsigned int history_deep = configuration->property(role + ".averaging_depth", default_depth); - observables_ = hybrid_make_observables_cc(in_streams_, dump_, dump_filename_, history_deep); - DLOG(INFO) << "pseudorange(" << observables_->unique_id() << ")"; + + observables_ = hybrid_make_observables_cc(in_streams_, out_streams_, dump_, dump_mat_, dump_filename_); + DLOG(INFO) << "Observables block ID (" << observables_->unique_id() << ")"; } - - -HybridObservables::~HybridObservables() -{} - - +HybridObservables::~HybridObservables() = default; void HybridObservables::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } - void HybridObservables::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } - - gr::basic_block_sptr HybridObservables::get_left_block() { return observables_; } - - gr::basic_block_sptr HybridObservables::get_right_block() { return observables_; diff --git a/src/algorithms/observables/adapters/hybrid_observables.h b/src/algorithms/observables/adapters/hybrid_observables.h index 98bc9216f..35015b837 100644 --- a/src/algorithms/observables/adapters/hybrid_observables.h +++ b/src/algorithms/observables/adapters/hybrid_observables.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,10 +34,9 @@ #ifndef GNSS_SDR_HYBRID_OBSERVABLES_H_ #define GNSS_SDR_HYBRID_OBSERVABLES_H_ -#include -#include "observables_interface.h" #include "hybrid_observables_cc.h" - +#include "observables_interface.h" +#include class ConfigurationInterface; @@ -48,31 +47,35 @@ class HybridObservables : public ObservablesInterface { public: HybridObservables(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + virtual ~HybridObservables(); - std::string role() + + inline std::string role() override { return role_; } //! Returns "Hybrid_Observables" - std::string implementation() + inline std::string implementation() override { return "Hybrid_Observables"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline void reset() override { return; } //! All blocks must have an item_size() function implementation - size_t item_size() + inline size_t item_size() override { return sizeof(gr_complex); } @@ -80,6 +83,7 @@ public: private: hybrid_observables_cc_sptr observables_; bool dump_; + bool dump_mat_; std::string dump_filename_; std::string role_; unsigned int in_streams_; diff --git a/src/algorithms/observables/gnuradio_blocks/CMakeLists.txt b/src/algorithms/observables/gnuradio_blocks/CMakeLists.txt index aad359d18..e829c474d 100644 --- a/src/algorithms/observables/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/observables/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,31 +13,53 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(OBS_GR_BLOCKS_SOURCES - gps_l1_ca_observables_cc.cc - galileo_e1_observables_cc.cc - hybrid_observables_cc.cc +set(OBS_GR_BLOCKS_SOURCES + hybrid_observables_cc.cc +) + +set(OBS_GR_BLOCKS_HEADERS + hybrid_observables_cc.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${ARMADILLO_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} ) -file(GLOB OBS_GR_BLOCKS_HEADERS "*.h") -list(SORT OBS_GR_BLOCKS_HEADERS) add_library(obs_gr_blocks ${OBS_GR_BLOCKS_SOURCES} ${OBS_GR_BLOCKS_HEADERS}) + source_group(Headers FILES ${OBS_GR_BLOCKS_HEADERS}) -add_dependencies(obs_gr_blocks glog-${glog_RELEASE} armadillo-${armadillo_RELEASE}) -target_link_libraries(obs_gr_blocks ${GNURADIO_RUNTIME_LIBRARIES} ${ARMADILLO_LIBRARIES}) + +if(MATIO_FOUND) + add_dependencies(obs_gr_blocks + gnss_sp_libs + glog-${glog_RELEASE} + armadillo-${armadillo_RELEASE} + ) +else() + add_dependencies(obs_gr_blocks + gnss_sp_libs + glog-${glog_RELEASE} + armadillo-${armadillo_RELEASE} + matio-${GNSSSDR_MATIO_LOCAL_VERSION} + ) +endif() + +target_link_libraries(obs_gr_blocks + gnss_sp_libs + ${GNURADIO_RUNTIME_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${MATIO_LIBRARIES} +) diff --git a/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.cc b/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.cc deleted file mode 100644 index ed75b4c46..000000000 --- a/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.cc +++ /dev/null @@ -1,281 +0,0 @@ -/*! - * \file galileo_e1_observables_cc.cc - * \brief Implementation of the pseudorange computation block for Galileo E1 - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "galileo_e1_observables_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "Galileo_E1.h" -#include "galileo_navigation_message.h" - - - -using google::LogMessage; - - -galileo_e1_observables_cc_sptr -galileo_e1_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) -{ - return galileo_e1_observables_cc_sptr(new galileo_e1_observables_cc(nchannels, dump, dump_filename, deep_history)); -} - - -galileo_e1_observables_cc::galileo_e1_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) : - gr::block("galileo_e1_observables_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), - gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro))) -{ - // initialize internal vars - d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - history_deep = deep_history; - - for (unsigned int i = 0; i < d_nchannels; i++) - { - d_acc_carrier_phase_queue_rads.push_back(std::deque(d_nchannels)); - d_carrier_doppler_queue_hz.push_back(std::deque(d_nchannels)); - d_symbol_TOW_queue_s.push_back(std::deque(d_nchannels)); - } - - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Observables dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception opening observables dump file " << e.what(); - } - } - } -} - - - -galileo_e1_observables_cc::~galileo_e1_observables_cc() -{ - d_dump_file.close(); -} - - - -bool Galileo_pairCompare_gnss_synchro_Prn_delay_ms(const std::pair& a, const std::pair& b) -{ - return (a.second.Prn_timestamp_ms) < (b.second.Prn_timestamp_ms); -} - - - -bool Galileo_pairCompare_gnss_synchro_d_TOW_at_current_symbol(const std::pair& a, const std::pair& b) -{ - return (a.second.d_TOW_at_current_symbol) < (b.second.d_TOW_at_current_symbol); -} - - - -int galileo_e1_observables_cc::general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; // Get the input pointer - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; // Get the output pointer - - Gnss_Synchro current_gnss_synchro[d_nchannels]; - std::map current_gnss_synchro_map; - std::map::iterator gnss_synchro_iter; - if (d_nchannels != ninput_items.size()) - { - LOG(WARNING) << "The Observables block is not well connected"; - } - - /* - * 1. Read the GNSS SYNCHRO objects from available channels - */ - for (unsigned int i = 0; i < d_nchannels; i++) - { - //Copy the telemetry decoder data to local copy - current_gnss_synchro[i] = in[i][0]; - /* - * 1.2 Assume no valid pseudoranges - */ - current_gnss_synchro[i].Flag_valid_pseudorange = false; - current_gnss_synchro[i].Pseudorange_m = 0.0; - - if (current_gnss_synchro[i].Flag_valid_word) //if this channel have valid word - { - //record the word structure in a map for pseudorange computation - current_gnss_synchro_map.insert(std::pair(current_gnss_synchro[i].Channel_ID, current_gnss_synchro[i])); - - //################### SAVE DOPPLER AND ACC CARRIER PHASE HISTORIC DATA FOR INTERPOLATION IN OBSERVABLE MODULE ####### - d_carrier_doppler_queue_hz[i].push_back(current_gnss_synchro[i].Carrier_Doppler_hz); - d_acc_carrier_phase_queue_rads[i].push_back(current_gnss_synchro[i].Carrier_phase_rads); - // save TOW history - d_symbol_TOW_queue_s[i].push_back(current_gnss_synchro[i].d_TOW_at_current_symbol); - - if (d_carrier_doppler_queue_hz[i].size() > history_deep) - { - d_carrier_doppler_queue_hz[i].pop_front(); - } - if (d_acc_carrier_phase_queue_rads[i].size() > history_deep) - { - d_acc_carrier_phase_queue_rads[i].pop_front(); - } - if (d_symbol_TOW_queue_s[i].size() > history_deep) - { - d_symbol_TOW_queue_s[i].pop_front(); - } - } - else - { - // Clear the observables history for this channel - if (d_symbol_TOW_queue_s[i].size() > 0) - { - d_symbol_TOW_queue_s[i].clear(); - d_carrier_doppler_queue_hz[i].clear(); - d_acc_carrier_phase_queue_rads[i].clear(); - } - } - } - - /* - * 2. Compute RAW pseudoranges using COMMON RECEPTION TIME algorithm. Use only the valid channels (channels that are tracking a satellite) - */ - if(current_gnss_synchro_map.size() > 0) - { - /* - * 2.1 Use CURRENT set of measurements and find the nearest satellite - * common RX time algorithm - */ - // what is the most recent symbol TOW in the current set? -> this will be the reference symbol - gnss_synchro_iter = max_element(current_gnss_synchro_map.begin(), current_gnss_synchro_map.end(), Galileo_pairCompare_gnss_synchro_d_TOW_at_current_symbol); - double d_TOW_reference = gnss_synchro_iter->second.d_TOW_at_current_symbol; - double d_ref_PRN_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms; - //int reference_channel= gnss_synchro_iter->second.Channel_ID; - - // Now compute RX time differences due to the PRN alignment in the correlators - double traveltime_ms; - double pseudorange_m; - double delta_rx_time_ms; - arma::vec symbol_TOW_vec_s; - arma::vec dopper_vec_hz; - arma::vec dopper_vec_interp_hz; - arma::vec acc_phase_vec_rads; - arma::vec acc_phase_vec_interp_rads; - arma::vec desired_symbol_TOW(1); - for(gnss_synchro_iter = current_gnss_synchro_map.begin(); gnss_synchro_iter != current_gnss_synchro_map.end(); gnss_synchro_iter++) - { - // compute the required symbol history shift in order to match the reference symbol - delta_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms - d_ref_PRN_rx_time_ms; - //compute the pseudorange - traveltime_ms = (d_TOW_reference-gnss_synchro_iter->second.d_TOW_at_current_symbol) * 1000.0 + delta_rx_time_ms + GALILEO_STARTOFFSET_ms; - pseudorange_m = traveltime_ms * GALILEO_C_m_ms; // [m] - // update the pseudorange object - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID] = gnss_synchro_iter->second; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Pseudorange_m = pseudorange_m; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Flag_valid_pseudorange = true; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].d_TOW_at_current_symbol = round(d_TOW_reference * 1000.0) / 1000.0 + GALILEO_STARTOFFSET_ms / 1000.0; - - if (d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].size() >= history_deep) - { - // compute interpolated observation values for Doppler and Accumulate carrier phase - symbol_TOW_vec_s = arma::vec(std::vector(d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].begin(), d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].end())); - acc_phase_vec_rads = arma::vec(std::vector(d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].begin(), d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].end())); - dopper_vec_hz = arma::vec(std::vector(d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].begin(), d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].end())); - desired_symbol_TOW[0] = symbol_TOW_vec_s[history_deep - 1] + delta_rx_time_ms / 1000.0; - // Curve fitting to cuadratic function - arma::mat A = arma::ones(history_deep, 2); - A.col(1) = symbol_TOW_vec_s; - //A.col(2)=symbol_TOW_vec_s % symbol_TOW_vec_s; - arma::mat coef_acc_phase(1,3); - arma::mat pinv_A = arma::pinv(A.t() * A) * A.t(); - coef_acc_phase = pinv_A * acc_phase_vec_rads; - arma::mat coef_doppler(1,3); - coef_doppler = pinv_A * dopper_vec_hz; - arma::vec acc_phase_lin; - arma::vec carrier_doppler_lin; - acc_phase_lin = coef_acc_phase[0] + coef_acc_phase[1] * desired_symbol_TOW[0];//+coef_acc_phase[2]*desired_symbol_TOW[0]*desired_symbol_TOW[0]; - carrier_doppler_lin = coef_doppler[0] + coef_doppler[1] * desired_symbol_TOW[0];//+coef_doppler[2]*desired_symbol_TOW[0]*desired_symbol_TOW[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_phase_rads = acc_phase_lin[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_Doppler_hz = carrier_doppler_lin[0]; - } - } - } - - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels ; i++) - { - tmp_double = current_gnss_synchro[i].d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Prn_timestamp_ms; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = (double)(current_gnss_synchro[i].Flag_valid_pseudorange==true); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].PRN; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - - consume_each(1); //one by one - for (unsigned int i = 0; i < d_nchannels ; i++) - { - *out[i] = current_gnss_synchro[i]; - } - if (noutput_items == 0) - { - LOG(WARNING) << "noutput_items = 0"; - } - return 1; -} diff --git a/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.h b/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.h deleted file mode 100644 index 1cb3ef4c4..000000000 --- a/src/algorithms/observables/gnuradio_blocks/galileo_e1_observables_cc.h +++ /dev/null @@ -1,78 +0,0 @@ -/*! - * \file galileo_e1_observables_cc.h - * \brief Interface of the observables computation block for Galileo E1 - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GALILEO_E1_OBSERVABLES_CC_H -#define GNSS_SDR_GALILEO_E1_OBSERVABLES_CC_H - - -#include -#include -#include - - -class galileo_e1_observables_cc; - -typedef boost::shared_ptr galileo_e1_observables_cc_sptr; - -galileo_e1_observables_cc_sptr -galileo_e1_make_observables_cc(unsigned int n_channels, bool dump, std::string dump_filename, unsigned int deep_history); - -/*! - * \brief This class implements a block that computes Galileo observables - */ -class galileo_e1_observables_cc : public gr::block -{ -public: - ~galileo_e1_observables_cc (); - - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - -private: - friend galileo_e1_observables_cc_sptr - galileo_e1_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); - galileo_e1_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); - - //Tracking observable history - std::vector> d_acc_carrier_phase_queue_rads; - std::vector> d_carrier_doppler_queue_hz; - std::vector> d_symbol_TOW_queue_s; - - // class private vars - bool d_dump; - unsigned int d_nchannels; - unsigned int history_deep; - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif diff --git a/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.cc b/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.cc deleted file mode 100644 index 2c7a64170..000000000 --- a/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.cc +++ /dev/null @@ -1,279 +0,0 @@ -/*! - * \file gps_l1_ca_observables_cc.cc - * \brief Implementation of the pseudorange computation block for GPS L1 C/A - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_observables_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "gnss_synchro.h" -#include "GPS_L1_CA.h" - - - -using google::LogMessage; - - -gps_l1_ca_observables_cc_sptr -gps_l1_ca_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) -{ - return gps_l1_ca_observables_cc_sptr(new gps_l1_ca_observables_cc(nchannels, dump, dump_filename, deep_history)); -} - - -gps_l1_ca_observables_cc::gps_l1_ca_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) : - gr::block("gps_l1_ca_observables_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), - gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro))) -{ - - // initialize internal vars - d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - history_deep = deep_history; - - for (unsigned int i = 0; i < d_nchannels; i++) - { - d_acc_carrier_phase_queue_rads.push_back(std::deque(d_nchannels)); - d_carrier_doppler_queue_hz.push_back(std::deque(d_nchannels)); - d_symbol_TOW_queue_s.push_back(std::deque(d_nchannels)); - } - - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Observables dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception opening observables dump file " << e.what(); - } - } - } -} - - - -gps_l1_ca_observables_cc::~gps_l1_ca_observables_cc() -{ - d_dump_file.close(); -} - -bool pairCompare_gnss_synchro_Prn_delay_ms(const std::pair& a, const std::pair& b) -{ - return (a.second.Prn_timestamp_ms) < (b.second.Prn_timestamp_ms); -} - - -bool pairCompare_gnss_synchro_d_TOW_at_current_symbol(const std::pair& a, const std::pair& b) -{ - return (a.second.d_TOW_at_current_symbol) < (b.second.d_TOW_at_current_symbol); -} - - -int gps_l1_ca_observables_cc::general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; // Get the input pointer - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; // Get the output pointer - - Gnss_Synchro current_gnss_synchro[d_nchannels]; - std::map current_gnss_synchro_map; - std::map::iterator gnss_synchro_iter; - - if (d_nchannels != ninput_items.size()) - { - LOG(WARNING) << "The Observables block is not well connected"; - } - - /* - * 1. Read the GNSS SYNCHRO objects from available channels - */ - for (unsigned int i = 0; i < d_nchannels; i++) - { - //Copy the telemetry decoder data to local copy - current_gnss_synchro[i] = in[i][0]; - /* - * 1.2 Assume no valid pseudoranges - */ - current_gnss_synchro[i].Flag_valid_pseudorange = false; - current_gnss_synchro[i].Pseudorange_m = 0.0; - if (current_gnss_synchro[i].Flag_valid_word) //if this channel have valid word - { - //record the word structure in a map for pseudorange computation - current_gnss_synchro_map.insert(std::pair(current_gnss_synchro[i].Channel_ID, current_gnss_synchro[i])); - - //################### SAVE DOPPLER AND ACC CARRIER PHASE HISTORIC DATA FOR INTERPOLATION IN OBSERVABLE MODULE ####### - d_carrier_doppler_queue_hz[i].push_back(current_gnss_synchro[i].Carrier_Doppler_hz); - d_acc_carrier_phase_queue_rads[i].push_back(current_gnss_synchro[i].Carrier_phase_rads); - // save TOW history - d_symbol_TOW_queue_s[i].push_back(current_gnss_synchro[i].d_TOW_at_current_symbol); - - if (d_carrier_doppler_queue_hz[i].size() > history_deep) - { - d_carrier_doppler_queue_hz[i].pop_front(); - } - if (d_acc_carrier_phase_queue_rads[i].size() > history_deep) - { - d_acc_carrier_phase_queue_rads[i].pop_front(); - } - if (d_symbol_TOW_queue_s[i].size() > history_deep) - { - d_symbol_TOW_queue_s[i].pop_front(); - } - } - else - { - // Clear the observables history for this channel - if (d_symbol_TOW_queue_s[i].size() > 0) - { - d_symbol_TOW_queue_s[i].clear(); - d_carrier_doppler_queue_hz[i].clear(); - d_acc_carrier_phase_queue_rads[i].clear(); - } - } - } - - /* - * 2. Compute RAW pseudoranges using COMMON RECEPTION TIME algorithm. Use only the valid channels (channels that are tracking a satellite) - */ - if(current_gnss_synchro_map.size() > 0) - { - /* - * 2.1 Use CURRENT set of measurements and find the nearest satellite - * common RX time algorithm - */ - // what is the most recent symbol TOW in the current set? -> this will be the reference symbol - gnss_synchro_iter = max_element(current_gnss_synchro_map.begin(), current_gnss_synchro_map.end(), pairCompare_gnss_synchro_d_TOW_at_current_symbol); - double d_TOW_reference = gnss_synchro_iter->second.d_TOW_at_current_symbol; - double d_ref_PRN_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms; - - // Now compute RX time differences due to the PRN alignment in the correlators - double traveltime_ms; - double pseudorange_m; - double delta_rx_time_ms; - arma::vec symbol_TOW_vec_s; - arma::vec dopper_vec_hz; - arma::vec dopper_vec_interp_hz; - arma::vec acc_phase_vec_rads; - arma::vec acc_phase_vec_interp_rads; - arma::vec desired_symbol_TOW(1); - for(gnss_synchro_iter = current_gnss_synchro_map.begin(); gnss_synchro_iter != current_gnss_synchro_map.end(); gnss_synchro_iter++) - { - // compute the required symbol history shift in order to match the reference symbol - delta_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms - d_ref_PRN_rx_time_ms; - //compute the pseudorange - traveltime_ms = (d_TOW_reference - gnss_synchro_iter->second.d_TOW_at_current_symbol) * 1000.0 + delta_rx_time_ms + GPS_STARTOFFSET_ms; - //convert to meters and remove the receiver time offset in meters - pseudorange_m = traveltime_ms * GPS_C_m_ms; // [m] - // update the pseudorange object - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID] = gnss_synchro_iter->second; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Pseudorange_m = pseudorange_m; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Flag_valid_pseudorange = true; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].d_TOW_at_current_symbol = round(d_TOW_reference * 1000.0) / 1000.0 + GPS_STARTOFFSET_ms / 1000.0; - - if (d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].size() >= history_deep) - { - // compute interpolated observation values for Doppler and Accumulate carrier phase - symbol_TOW_vec_s = arma::vec(std::vector(d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].begin(), d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].end())); - acc_phase_vec_rads = arma::vec(std::vector(d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].begin(), d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].end())); - dopper_vec_hz = arma::vec(std::vector(d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].begin(), d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].end())); - - desired_symbol_TOW[0] = symbol_TOW_vec_s[history_deep - 1] + delta_rx_time_ms / 1000.0; - // arma::interp1(symbol_TOW_vec_s,dopper_vec_hz,desired_symbol_TOW,dopper_vec_interp_hz); - // arma::interp1(symbol_TOW_vec_s,acc_phase_vec_rads,desired_symbol_TOW,acc_phase_vec_interp_rads); - // Curve fitting to quadratic function - arma::mat A = arma::ones (history_deep, 2); - A.col(1) = symbol_TOW_vec_s; - - arma::mat coef_acc_phase(1,3); - arma::mat pinv_A = arma::pinv(A.t() * A) * A.t(); - coef_acc_phase = pinv_A * acc_phase_vec_rads; - arma::mat coef_doppler(1,3); - coef_doppler = pinv_A * dopper_vec_hz; - arma::vec acc_phase_lin; - arma::vec carrier_doppler_lin; - acc_phase_lin = coef_acc_phase[0] + coef_acc_phase[1] * desired_symbol_TOW[0]; - carrier_doppler_lin = coef_doppler[0] + coef_doppler[1] * desired_symbol_TOW[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_phase_rads = acc_phase_lin[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_Doppler_hz = carrier_doppler_lin[0]; - } - } - } - - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels; i++) - { - tmp_double = current_gnss_synchro[i].d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - //tmp_double = current_gnss_synchro[i].Prn_timestamp_ms; - tmp_double = current_gnss_synchro[i].Carrier_Doppler_hz; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Carrier_phase_rads/GPS_TWO_PI; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].PRN; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - - consume_each(1); //one by one - for (unsigned int i = 0; i < d_nchannels; i++) - { - *out[i] = current_gnss_synchro[i]; - } - if (noutput_items == 0) - { - LOG(WARNING) << "noutput_items = 0"; - } - return 1; -} diff --git a/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.h b/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.h deleted file mode 100644 index 38a1e7f4d..000000000 --- a/src/algorithms/observables/gnuradio_blocks/gps_l1_ca_observables_cc.h +++ /dev/null @@ -1,79 +0,0 @@ -/*! - * \file gps_l1_ca_observables_cc.h - * \brief Interface of the pseudorange computation block for GPS L1 C/A - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GPS_L1_CA_OBSERVABLES_CC_H -#define GNSS_SDR_GPS_L1_CA_OBSERVABLES_CC_H - -#include -#include -#include -#include -#include -#include - - -class gps_l1_ca_observables_cc; - -typedef boost::shared_ptr gps_l1_ca_observables_cc_sptr; - -gps_l1_ca_observables_cc_sptr -gps_l1_ca_make_observables_cc(unsigned int n_channels, bool dump, std::string dump_filename, unsigned int deep_history); - -/*! - * \brief This class implements a block that computes GPS L1 C/A observables - */ -class gps_l1_ca_observables_cc : public gr::block -{ -public: - ~gps_l1_ca_observables_cc (); - //void set_fs_in(unsigned long int fs_in) {d_fs_in = fs_in;}; - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - -private: - friend gps_l1_ca_observables_cc_sptr - gps_l1_ca_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); - gps_l1_ca_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); - - - //Tracking observable history - std::vector> d_acc_carrier_phase_queue_rads; - std::vector> d_carrier_doppler_queue_hz; - std::vector> d_symbol_TOW_queue_s; - - // class private vars - bool d_dump; - unsigned int d_nchannels; - unsigned int history_deep; - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc index 90fd8c6be..cf9807ece 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc @@ -1,12 +1,12 @@ /*! * \file hybrid_observables_cc.cc - * \brief Implementation of the pseudorange computation block for Galileo E1 - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es + * \brief Implementation of the observables computation block + * \author Javier Arribas 2017. jarribas(at)cttc.es + * \author Antonio Ramos 2018. antonio.ramos(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,274 +24,587 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "hybrid_observables_cc.h" +#include "GPS_L1_CA.h" +#include "display.h" +#include "gnss_sdr_create_directory.h" +#include +#include +#include +#include #include #include +#include #include -#include +#include #include -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "Galileo_E1.h" -#include "GPS_L1_CA.h" - using google::LogMessage; -hybrid_observables_cc_sptr -hybrid_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) +hybrid_observables_cc_sptr hybrid_make_observables_cc(unsigned int nchannels_in, unsigned int nchannels_out, bool dump, bool dump_mat, std::string dump_filename) { - return hybrid_observables_cc_sptr(new hybrid_observables_cc(nchannels, dump, dump_filename, deep_history)); + return hybrid_observables_cc_sptr(new hybrid_observables_cc(nchannels_in, nchannels_out, dump, dump_mat, std::move(dump_filename))); } -hybrid_observables_cc::hybrid_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history) : - gr::block("hybrid_observables_cc", gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)), - gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro))) +hybrid_observables_cc::hybrid_observables_cc(uint32_t nchannels_in, + uint32_t nchannels_out, + bool dump, + bool dump_mat, + std::string dump_filename) : gr::block("hybrid_observables_cc", + gr::io_signature::make(nchannels_in, nchannels_in, sizeof(Gnss_Synchro)), + gr::io_signature::make(nchannels_out, nchannels_out, sizeof(Gnss_Synchro))) { - // initialize internal vars d_dump = dump; - d_nchannels = nchannels; - d_dump_filename = dump_filename; - history_deep = deep_history; - - for (unsigned int i = 0; i < d_nchannels; i++) - { - d_acc_carrier_phase_queue_rads.push_back(std::deque(d_nchannels)); - d_carrier_doppler_queue_hz.push_back(std::deque(d_nchannels)); - d_symbol_TOW_queue_s.push_back(std::deque(d_nchannels)); - } + d_dump_mat = dump_mat and d_dump; + d_dump_filename = std::move(dump_filename); + d_nchannels_out = nchannels_out; + d_nchannels_in = nchannels_in; + T_rx_clock_step_samples = 0U; + d_gnss_synchro_history = new Gnss_circular_deque(500, d_nchannels_out); // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) + if (d_dump) { - if (d_dump_file.is_open() == false) + std::string dump_path; + // Get path + if (d_dump_filename.find_last_of('/') != std::string::npos) { - try - { - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Observables dump enabled Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception opening observables dump file " << e.what(); - } + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/')); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "observables.dat"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.')); + } + d_dump_filename.append(".dat"); + d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump file for the Observables block. Wrong permissions?" << std::endl; + d_dump = false; + } + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Observables dump enabled Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception opening observables dump file " << e.what(); + d_dump = false; } } + T_rx_TOW_ms = 0U; + T_rx_TOW_offset_ms = 0U; + T_rx_TOW_set = false; + + // rework + d_Rx_clock_buffer.resize(10); // 10*20 ms = 200 ms of data in buffer + d_Rx_clock_buffer.clear(); // Clear all the elements in the buffer } hybrid_observables_cc::~hybrid_observables_cc() { - d_dump_file.close(); + delete d_gnss_synchro_history; + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } + if (d_dump_mat) + { + save_matfile(); + } } -bool Hybrid_pairCompare_gnss_synchro_d_TOW_hybrid_at_current_symbol(const std::pair& a, const std::pair& b) +int32_t hybrid_observables_cc::save_matfile() { - return (a.second.d_TOW_hybrid_at_current_symbol) < (b.second.d_TOW_hybrid_at_current_symbol); + // READ DUMP FILE + std::string dump_filename = d_dump_filename; + std::ifstream::pos_type size; + int32_t number_of_double_vars = 7; + int32_t epoch_size_bytes = sizeof(double) * number_of_double_vars * d_nchannels_out; + std::ifstream dump_file; + std::cout << "Generating .mat file for " << dump_filename << std::endl; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0LL; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto **RX_time = new double *[d_nchannels_out]; + auto **TOW_at_current_symbol_s = new double *[d_nchannels_out]; + auto **Carrier_Doppler_hz = new double *[d_nchannels_out]; + auto **Carrier_phase_cycles = new double *[d_nchannels_out]; + auto **Pseudorange_m = new double *[d_nchannels_out]; + auto **PRN = new double *[d_nchannels_out]; + auto **Flag_valid_pseudorange = new double *[d_nchannels_out]; + + for (uint32_t i = 0; i < d_nchannels_out; i++) + { + RX_time[i] = new double[num_epoch]; + TOW_at_current_symbol_s[i] = new double[num_epoch]; + Carrier_Doppler_hz[i] = new double[num_epoch]; + Carrier_phase_cycles[i] = new double[num_epoch]; + Pseudorange_m[i] = new double[num_epoch]; + PRN[i] = new double[num_epoch]; + Flag_valid_pseudorange[i] = new double[num_epoch]; + } + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + for (uint32_t chan = 0; chan < d_nchannels_out; chan++) + { + dump_file.read(reinterpret_cast(&RX_time[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&TOW_at_current_symbol_s[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&Carrier_Doppler_hz[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&Carrier_phase_cycles[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&Pseudorange_m[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&Flag_valid_pseudorange[chan][i]), sizeof(double)); + } + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + for (uint32_t i = 0; i < d_nchannels_out; i++) + { + delete[] RX_time[i]; + delete[] TOW_at_current_symbol_s[i]; + delete[] Carrier_Doppler_hz[i]; + delete[] Carrier_phase_cycles[i]; + delete[] Pseudorange_m[i]; + delete[] PRN[i]; + delete[] Flag_valid_pseudorange[i]; + } + delete[] RX_time; + delete[] TOW_at_current_symbol_s; + delete[] Carrier_Doppler_hz; + delete[] Carrier_phase_cycles; + delete[] Pseudorange_m; + delete[] PRN; + delete[] Flag_valid_pseudorange; + + return 1; + } + + auto *RX_time_aux = new double[d_nchannels_out * num_epoch]; + auto *TOW_at_current_symbol_s_aux = new double[d_nchannels_out * num_epoch]; + auto *Carrier_Doppler_hz_aux = new double[d_nchannels_out * num_epoch]; + auto *Carrier_phase_cycles_aux = new double[d_nchannels_out * num_epoch]; + auto *Pseudorange_m_aux = new double[d_nchannels_out * num_epoch]; + auto *PRN_aux = new double[d_nchannels_out * num_epoch]; + auto *Flag_valid_pseudorange_aux = new double[d_nchannels_out * num_epoch]; + uint32_t k = 0U; + for (int64_t j = 0; j < num_epoch; j++) + { + for (uint32_t i = 0; i < d_nchannels_out; i++) + { + RX_time_aux[k] = RX_time[i][j]; + TOW_at_current_symbol_s_aux[k] = TOW_at_current_symbol_s[i][j]; + Carrier_Doppler_hz_aux[k] = Carrier_Doppler_hz[i][j]; + Carrier_phase_cycles_aux[k] = Carrier_phase_cycles[i][j]; + Pseudorange_m_aux[k] = Pseudorange_m[i][j]; + PRN_aux[k] = PRN[i][j]; + Flag_valid_pseudorange_aux[k] = Flag_valid_pseudorange[i][j]; + k++; + } + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + if (filename.size() > 4) + { + filename.erase(filename.end() - 4, filename.end()); + } + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {static_cast(d_nchannels_out), static_cast(num_epoch)}; + matvar = Mat_VarCreate("RX_time", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, RX_time_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("TOW_at_current_symbol_s", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, TOW_at_current_symbol_s_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Carrier_Doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, Carrier_Doppler_hz_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Carrier_phase_cycles", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, Carrier_phase_cycles_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Pseudorange_m", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, Pseudorange_m_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, PRN_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Flag_valid_pseudorange", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, Flag_valid_pseudorange_aux, MAT_F_DONT_COPY_DATA); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + + for (uint32_t i = 0; i < d_nchannels_out; i++) + { + delete[] RX_time[i]; + delete[] TOW_at_current_symbol_s[i]; + delete[] Carrier_Doppler_hz[i]; + delete[] Carrier_phase_cycles[i]; + delete[] Pseudorange_m[i]; + delete[] PRN[i]; + delete[] Flag_valid_pseudorange[i]; + } + delete[] RX_time; + delete[] TOW_at_current_symbol_s; + delete[] Carrier_Doppler_hz; + delete[] Carrier_phase_cycles; + delete[] Pseudorange_m; + delete[] PRN; + delete[] Flag_valid_pseudorange; + + delete[] RX_time_aux; + delete[] TOW_at_current_symbol_s_aux; + delete[] Carrier_Doppler_hz_aux; + delete[] Carrier_phase_cycles_aux; + delete[] Pseudorange_m_aux; + delete[] PRN_aux; + delete[] Flag_valid_pseudorange_aux; + return 0; } -int hybrid_observables_cc::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, +double hybrid_observables_cc::compute_T_rx_s(const Gnss_Synchro &a) +{ + return ((static_cast(a.Tracking_sample_counter) + a.Code_phase_samples) / static_cast(a.fs)); +} + + +bool hybrid_observables_cc::interp_trk_obs(Gnss_Synchro &interpolated_obs, const uint32_t &ch, const uint64_t &rx_clock) +{ + int32_t nearest_element = -1; + int64_t abs_diff; + int64_t old_abs_diff = std::numeric_limits::max(); + for (uint32_t i = 0; i < d_gnss_synchro_history->size(ch); i++) + { + abs_diff = llabs(static_cast(rx_clock) - static_cast(d_gnss_synchro_history->at(ch, i).Tracking_sample_counter)); + if (old_abs_diff > abs_diff) + { + old_abs_diff = abs_diff; + nearest_element = static_cast(i); + } + } + + if (nearest_element != -1 and nearest_element != static_cast(d_gnss_synchro_history->size(ch))) + { + if ((static_cast(old_abs_diff) / static_cast(d_gnss_synchro_history->at(ch, nearest_element).fs)) < 0.02) + { + int32_t neighbor_element; + if (rx_clock > d_gnss_synchro_history->at(ch, nearest_element).Tracking_sample_counter) + { + neighbor_element = nearest_element + 1; + } + else + { + neighbor_element = nearest_element - 1; + } + if (neighbor_element < static_cast(d_gnss_synchro_history->size(ch)) and neighbor_element >= 0) + { + int32_t t1_idx; + int32_t t2_idx; + if (rx_clock > d_gnss_synchro_history->at(ch, nearest_element).Tracking_sample_counter) + { + //std::cout << "S1= " << d_gnss_synchro_history->at(ch, nearest_element).Tracking_sample_counter + // << " Si=" << rx_clock << " S2=" << d_gnss_synchro_history->at(ch, neighbor_element).Tracking_sample_counter << std::endl; + t1_idx = nearest_element; + t2_idx = neighbor_element; + } + else + { + //std::cout << "inv S1= " << d_gnss_synchro_history->at(ch, neighbor_element).Tracking_sample_counter + // << " Si=" << rx_clock << " S2=" << d_gnss_synchro_history->at(ch, nearest_element).Tracking_sample_counter << std::endl; + t1_idx = neighbor_element; + t2_idx = nearest_element; + } + + // 1st: copy the nearest gnss_synchro data for that channel + interpolated_obs = d_gnss_synchro_history->at(ch, nearest_element); + + // 2nd: Linear interpolation: y(t) = y(t1) + (y(t2) - y(t1)) * (t - t1) / (t2 - t1) + + double T_rx_s = static_cast(rx_clock) / static_cast(interpolated_obs.fs); + + double time_factor = (T_rx_s - d_gnss_synchro_history->at(ch, t1_idx).RX_time) / + (d_gnss_synchro_history->at(ch, t2_idx).RX_time - + d_gnss_synchro_history->at(ch, t1_idx).RX_time); + + // CARRIER PHASE INTERPOLATION + interpolated_obs.Carrier_phase_rads = d_gnss_synchro_history->at(ch, t1_idx).Carrier_phase_rads + (d_gnss_synchro_history->at(ch, t2_idx).Carrier_phase_rads - d_gnss_synchro_history->at(ch, t1_idx).Carrier_phase_rads) * time_factor; + // CARRIER DOPPLER INTERPOLATION + interpolated_obs.Carrier_Doppler_hz = d_gnss_synchro_history->at(ch, t1_idx).Carrier_Doppler_hz + (d_gnss_synchro_history->at(ch, t2_idx).Carrier_Doppler_hz - d_gnss_synchro_history->at(ch, t1_idx).Carrier_Doppler_hz) * time_factor; + // TOW INTERPOLATION + interpolated_obs.interp_TOW_ms = static_cast(d_gnss_synchro_history->at(ch, t1_idx).TOW_at_current_symbol_ms) + (static_cast(d_gnss_synchro_history->at(ch, t2_idx).TOW_at_current_symbol_ms) - static_cast(d_gnss_synchro_history->at(ch, t1_idx).TOW_at_current_symbol_ms)) * time_factor; + // + // std::cout << "Rx samplestamp: " << T_rx_s << " Channel " << ch << " interp buff idx " << nearest_element + // << " ,diff: " << old_abs_diff << " samples (" << static_cast(old_abs_diff) / static_cast(d_gnss_synchro_history->at(ch, nearest_element).fs) << " s)\n"; + return true; + } + return false; + } + // std::cout << "ALERT: Channel " << ch << " interp buff idx " << nearest_element + // << " ,diff: " << old_abs_diff << " samples (" << static_cast(old_abs_diff) / static_cast(d_gnss_synchro_history->at(ch, nearest_element).fs) << " s)\n"; + // usleep(1000); + } + return false; +} + + +void hybrid_observables_cc::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for (int32_t n = 0; n < static_cast(d_nchannels_in) - 1; n++) + { + ninput_items_required[n] = 0; + } + // last input channel is the sample counter, triggered each ms + ninput_items_required[d_nchannels_in - 1] = 1; +} + + +void hybrid_observables_cc::update_TOW(std::vector &data) +{ + //1. Set the TOW using the minimum TOW in the observables. + // this will be the receiver time. + //2. If the TOW is set, it must be incremented by the desired receiver time step. + // the time step must match the observables timer block (connected to the las input channel) + std::vector::iterator it; + // if (!T_rx_TOW_set) + // { + //uint32_t TOW_ref = std::numeric_limits::max(); + uint32_t TOW_ref = 0U; + for (it = data.begin(); it != data.end(); it++) + { + if (it->Flag_valid_word) + { + if (it->TOW_at_current_symbol_ms > TOW_ref) + { + TOW_ref = it->TOW_at_current_symbol_ms; + T_rx_TOW_set = true; + } + } + } + T_rx_TOW_ms = TOW_ref; + //} + // else + // { + // T_rx_TOW_ms += T_rx_step_ms; + // //todo: check what happens during the week rollover + // if (T_rx_TOW_ms >= 604800000) + // { + // T_rx_TOW_ms = T_rx_TOW_ms % 604800000; + // } + // } + // std::cout << "T_rx_TOW_ms: " << T_rx_TOW_ms << std::endl; +} + + +void hybrid_observables_cc::compute_pranges(std::vector &data) +{ + std::vector::iterator it; + for (it = data.begin(); it != data.end(); it++) + { + if (it->Flag_valid_word) + { + double traveltime_s = (static_cast(T_rx_TOW_ms) - it->interp_TOW_ms + GPS_STARTOFFSET_ms) / 1000.0; + //todo: check what happens during the week rollover (TOW rollover at 604800000s) + it->RX_time = (static_cast(T_rx_TOW_ms) + GPS_STARTOFFSET_ms) / 1000.0; + it->Pseudorange_m = traveltime_s * SPEED_OF_LIGHT; + it->Flag_valid_pseudorange = true; + // debug code + // std::cout.precision(17); + // std::cout << "[" << it->Channel_ID << "] interp_TOW_ms: " << it->interp_TOW_ms << std::endl; + // std::cout << "[" << it->Channel_ID << "] Diff T_rx_TOW_ms - interp_TOW_ms: " << static_cast(T_rx_TOW_ms) - it->interp_TOW_ms << std::endl; + // std::cout << "[" << it->Channel_ID << "] Pseudorange_m: " << it->Pseudorange_m << std::endl; + } + } + // usleep(1000); +} + + +int hybrid_observables_cc::general_work(int noutput_items __attribute__((unused)), + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - Gnss_Synchro **in = (Gnss_Synchro **) &input_items[0]; // Get the input pointer - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; // Get the output pointer + const auto **in = reinterpret_cast(&input_items[0]); + auto **out = reinterpret_cast(&output_items[0]); - Gnss_Synchro current_gnss_synchro[d_nchannels]; - std::map current_gnss_synchro_map; - std::map::iterator gnss_synchro_iter; - - if (d_nchannels != ninput_items.size()) + // Push receiver clock into history buffer (connected to the last of the input channels) + // The clock buffer gives time to the channels to compute the tracking observables + if (ninput_items[d_nchannels_in - 1] > 0) { - LOG(WARNING) << "The Observables block is not well connected"; + d_Rx_clock_buffer.push_back(in[d_nchannels_in - 1][0].Tracking_sample_counter); + if (T_rx_clock_step_samples == 0) + { + T_rx_clock_step_samples = std::round(static_cast(in[d_nchannels_in - 1][0].fs) * 1e-3); // 1 ms + LOG(INFO) << "Observables clock step samples set to " << T_rx_clock_step_samples; + usleep(1000000); + } + + // Consume one item from the clock channel (last of the input channels) + consume(d_nchannels_in - 1, 1); } - /* - * 1. Read the GNSS SYNCHRO objects from available channels - */ - for (unsigned int i = 0; i < d_nchannels; i++) + // Push the tracking observables into buffers to allow the observable interpolation at the desired Rx clock + for (uint32_t n = 0; n < d_nchannels_out; n++) { - //Copy the telemetry decoder data to local copy - current_gnss_synchro[i] = in[i][0]; - /* - * 1.2 Assume no valid pseudoranges - */ - current_gnss_synchro[i].Flag_valid_pseudorange = false; - current_gnss_synchro[i].Pseudorange_m = 0.0; - if (current_gnss_synchro[i].Flag_valid_word) + // Push the valid tracking Gnss_Synchros to their corresponding deque + for (int32_t m = 0; m < ninput_items[n]; m++) { - //record the word structure in a map for pseudorange computation - current_gnss_synchro_map.insert(std::pair(current_gnss_synchro[i].Channel_ID, current_gnss_synchro[i])); - //################### SAVE DOPPLER AND ACC CARRIER PHASE HISTORIC DATA FOR INTERPOLATION IN OBSERVABLE MODULE ####### - d_carrier_doppler_queue_hz[i].push_back(current_gnss_synchro[i].Carrier_Doppler_hz); - d_acc_carrier_phase_queue_rads[i].push_back(current_gnss_synchro[i].Carrier_phase_rads); - // save TOW history - d_symbol_TOW_queue_s[i].push_back(current_gnss_synchro[i].d_TOW_at_current_symbol); - if (d_carrier_doppler_queue_hz[i].size() > history_deep) + if (in[n][m].Flag_valid_word) { - d_carrier_doppler_queue_hz[i].pop_front(); - } - if (d_acc_carrier_phase_queue_rads[i].size() > history_deep) - { - d_acc_carrier_phase_queue_rads[i].pop_front(); - } - if (d_symbol_TOW_queue_s[i].size() > history_deep) - { - d_symbol_TOW_queue_s[i].pop_front(); + if (d_gnss_synchro_history->size(n) > 0) + { + // Check if the last Gnss_Synchro comes from the same satellite as the previous ones + if (d_gnss_synchro_history->front(n).PRN != in[n][m].PRN) + { + d_gnss_synchro_history->clear(n); + } + } + d_gnss_synchro_history->push_back(n, in[n][m]); + d_gnss_synchro_history->back(n).RX_time = compute_T_rx_s(in[n][m]); } } - else + consume(n, ninput_items[n]); + } + + if (d_Rx_clock_buffer.size() == d_Rx_clock_buffer.capacity()) + { + std::vector epoch_data; + int32_t n_valid = 0; + for (uint32_t n = 0; n < d_nchannels_out; n++) { - // Clear the observables history for this channel - if (d_symbol_TOW_queue_s[i].size() > 0) + Gnss_Synchro interpolated_gnss_synchro{}; + if (!interp_trk_obs(interpolated_gnss_synchro, n, d_Rx_clock_buffer.front() + T_rx_TOW_offset_ms * T_rx_clock_step_samples)) { - d_symbol_TOW_queue_s[i].clear(); - d_carrier_doppler_queue_hz[i].clear(); - d_acc_carrier_phase_queue_rads[i].clear(); + // Produce an empty observation + interpolated_gnss_synchro = Gnss_Synchro(); + interpolated_gnss_synchro.Flag_valid_pseudorange = false; + interpolated_gnss_synchro.Flag_valid_word = false; + interpolated_gnss_synchro.Flag_valid_acquisition = false; + interpolated_gnss_synchro.fs = 0; + interpolated_gnss_synchro.Channel_ID = n; + } + else + { + n_valid++; + } + epoch_data.push_back(interpolated_gnss_synchro); + } + if (n_valid > 0) + { + update_TOW(epoch_data); + if (T_rx_TOW_ms % 20 != 0) + { + T_rx_TOW_offset_ms = T_rx_TOW_ms % 20; } } - } - /* - * 2. Compute RAW pseudoranges using COMMON RECEPTION TIME algorithm. Use only the valid channels (channels that are tracking a satellite) - */ - DLOG(INFO) << "gnss_synchro set size=" << current_gnss_synchro_map.size(); - double traveltime_ms; - double pseudorange_m; - double delta_rx_time_ms; - double delta_TOW_ms; - arma::vec symbol_TOW_vec_s; - arma::vec dopper_vec_hz; - arma::vec dopper_vec_interp_hz; - arma::vec acc_phase_vec_rads; - arma::vec acc_phase_vec_interp_rads; - arma::vec desired_symbol_TOW(1); - double start_offset_ms = 0.0; + if (n_valid > 0) compute_pranges(epoch_data); - if(current_gnss_synchro_map.size() > 0) - { - /* - * 2.1 Use CURRENT set of measurements and find the nearest satellite - * common RX time algorithm - */ - // what is the most recent symbol TOW in the current set? -> this will be the reference symbol - gnss_synchro_iter = max_element(current_gnss_synchro_map.begin(), current_gnss_synchro_map.end(), Hybrid_pairCompare_gnss_synchro_d_TOW_hybrid_at_current_symbol); - //gnss_synchro_iter = max_element(current_gnss_synchro_map_gps_only.begin(), current_gnss_synchro_map_gps_only.end(), Hybrid_pairCompare_gnss_synchro_d_TOW_hybrid_at_current_symbol); - double d_TOW_reference = gnss_synchro_iter->second.d_TOW_hybrid_at_current_symbol; - DLOG(INFO) << "d_TOW_hybrid_reference [ms] = " << d_TOW_reference * 1000; - double d_ref_PRN_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms; - DLOG(INFO) << "ref_PRN_rx_time_ms [ms] = " << d_ref_PRN_rx_time_ms; - - // Now compute RX time differences due to the PRN alignment in the correlators - for(gnss_synchro_iter = current_gnss_synchro_map.begin(); gnss_synchro_iter != current_gnss_synchro_map.end(); gnss_synchro_iter++) + for (uint32_t n = 0; n < d_nchannels_out; n++) { - // check and correct synchronization in cross-system pseudoranges! - delta_rx_time_ms = gnss_synchro_iter->second.Prn_timestamp_ms - d_ref_PRN_rx_time_ms; - delta_TOW_ms = (d_TOW_reference - gnss_synchro_iter->second.d_TOW_hybrid_at_current_symbol) * 1000.0; - if(gnss_synchro_iter->second.System == 'E') + out[n][0] = epoch_data.at(n); + } + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try { - start_offset_ms = GALILEO_STARTOFFSET_ms; + double tmp_double; + for (uint32_t i = 0; i < d_nchannels_out; i++) + { + tmp_double = out[i][0].RX_time; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = out[i][0].interp_TOW_ms / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = out[i][0].Carrier_Doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = out[i][0].Carrier_phase_rads / GPS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = out[i][0].Pseudorange_m; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = static_cast(out[i][0].PRN); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = static_cast(out[i][0].Flag_valid_pseudorange); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } } - if(gnss_synchro_iter->second.System == 'G') + catch (const std::ifstream::failure &e) { - start_offset_ms = GPS_STARTOFFSET_ms; - } - //compute the pseudorange - traveltime_ms = delta_TOW_ms + delta_rx_time_ms + start_offset_ms; - pseudorange_m = traveltime_ms * GALILEO_C_m_ms; // [m] - DLOG(INFO) << "CH " << gnss_synchro_iter->second.Channel_ID << " tracking GNSS System " - << gnss_synchro_iter->second.System << " has PRN start at= " << gnss_synchro_iter->second.Prn_timestamp_ms - << " [ms], d_TOW_at_current_symbol = " << (gnss_synchro_iter->second.d_TOW_at_current_symbol) * 1000 - << " [ms], d_TOW_hybrid_at_current_symbol = "<< (gnss_synchro_iter->second.d_TOW_hybrid_at_current_symbol) * 1000 - << "[ms], delta_rx_time_ms = " << delta_rx_time_ms << "[ms], travel_time = " << traveltime_ms - << ", pseudorange[m] = "<< pseudorange_m; - - // update the pseudorange object - //current_gnss_synchro[gnss_synchro_iter->second.Channel_ID] = gnss_synchro_iter->second; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Pseudorange_m = pseudorange_m; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Flag_valid_pseudorange = true; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].d_TOW_hybrid_at_current_symbol = round(d_TOW_reference * 1000) / 1000 + start_offset_ms / 1000.0; - if (d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].size() >= history_deep) - { - // compute interpolated observation values for Doppler and Accumulate carrier phase - symbol_TOW_vec_s = arma::vec(std::vector(d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].begin(), d_symbol_TOW_queue_s[gnss_synchro_iter->second.Channel_ID].end())); - acc_phase_vec_rads = arma::vec(std::vector(d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].begin(), d_acc_carrier_phase_queue_rads[gnss_synchro_iter->second.Channel_ID].end())); - dopper_vec_hz = arma::vec(std::vector(d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].begin(), d_carrier_doppler_queue_hz[gnss_synchro_iter->second.Channel_ID].end())); - - desired_symbol_TOW[0] = symbol_TOW_vec_s[history_deep - 1] + delta_rx_time_ms / 1000.0; - - // Curve fitting to cuadratic function - arma::mat A = arma::ones (history_deep, 2); - A.col(1) = symbol_TOW_vec_s; - - arma::mat coef_acc_phase(1,3); - arma::mat pinv_A = arma::pinv(A.t() * A) * A.t(); - coef_acc_phase = pinv_A * acc_phase_vec_rads; - arma::mat coef_doppler(1,3); - coef_doppler = pinv_A * dopper_vec_hz; - arma::vec acc_phase_lin; - arma::vec carrier_doppler_lin; - acc_phase_lin = coef_acc_phase[0] + coef_acc_phase[1] * desired_symbol_TOW[0]; - carrier_doppler_lin = coef_doppler[0] + coef_doppler[1] * desired_symbol_TOW[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_phase_rads = acc_phase_lin[0]; - current_gnss_synchro[gnss_synchro_iter->second.Channel_ID].Carrier_Doppler_hz = carrier_doppler_lin[0]; + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + d_dump = false; } } + return 1; } - - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - for (unsigned int i = 0; i < d_nchannels ; i++) - { - tmp_double = current_gnss_synchro[i].d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].d_TOW_hybrid_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Prn_timestamp_ms; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].Pseudorange_m; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = (double)(current_gnss_synchro[i].Flag_valid_pseudorange==true); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_gnss_synchro[i].PRN; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - - consume_each(1); //consume one by one - - for (unsigned int i = 0; i < d_nchannels ; i++) - { - *out[i] = current_gnss_synchro[i]; - } - - if (noutput_items == 0) - { - LOG(WARNING) << "noutput_items = 0"; - } - return 1; + return 0; } diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.h b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.h index 20154c78a..9f6d31e47 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.h +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.h @@ -1,12 +1,13 @@ /*! * \file hybrid_observables_cc.h - * \brief Interface of the observables computation block for Galileo E1 + * \brief Interface of the observables computation block * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com * \author Javier Arribas 2013. jarribas(at)cttc.es + * \author Antonio Ramos 2018. antonio.ramos(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,9 +34,13 @@ #ifndef GNSS_SDR_HYBRID_OBSERVABLES_CC_H #define GNSS_SDR_HYBRID_OBSERVABLES_CC_H +#include "gnss_circular_deque.h" +#include "gnss_synchro.h" +#include +#include #include #include -#include +#include class hybrid_observables_cc; @@ -43,32 +48,43 @@ class hybrid_observables_cc; typedef boost::shared_ptr hybrid_observables_cc_sptr; hybrid_observables_cc_sptr -hybrid_make_observables_cc(unsigned int n_channels, bool dump, std::string dump_filename, unsigned int deep_history); +hybrid_make_observables_cc(unsigned int nchannels_in, unsigned int nchannels_out, bool dump, bool dump_mat, std::string dump_filename); /*! - * \brief This class implements a block that computes Galileo observables + * \brief This class implements a block that computes observables */ class hybrid_observables_cc : public gr::block { public: - ~hybrid_observables_cc (); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + ~hybrid_observables_cc(); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); private: friend hybrid_observables_cc_sptr - hybrid_make_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); - hybrid_observables_cc(unsigned int nchannels, bool dump, std::string dump_filename, unsigned int deep_history); + hybrid_make_observables_cc(uint32_t nchannels_in, uint32_t nchannels_out, bool dump, bool dump_mat, std::string dump_filename); + hybrid_observables_cc(uint32_t nchannels_in, uint32_t nchannels_out, bool dump, bool dump_mat, std::string dump_filename); + bool interpolate_data(Gnss_Synchro& out, const uint32_t& ch, const double& ti); + bool interp_trk_obs(Gnss_Synchro& interpolated_obs, const uint32_t& ch, const uint64_t& rx_clock); + double compute_T_rx_s(const Gnss_Synchro& a); + void compute_pranges(std::vector& data); + void update_TOW(std::vector& data); + int32_t save_matfile(); + //time history + boost::circular_buffer d_Rx_clock_buffer; //Tracking observable history - std::vector> d_acc_carrier_phase_queue_rads; - std::vector> d_carrier_doppler_queue_hz; - std::vector> d_symbol_TOW_queue_s; - - // class private vars + Gnss_circular_deque* d_gnss_synchro_history; + uint32_t T_rx_clock_step_samples; + //rx time follow GPST + bool T_rx_TOW_set; + uint32_t T_rx_TOW_ms; + uint32_t T_rx_TOW_offset_ms; bool d_dump; - unsigned int d_nchannels; - unsigned int history_deep; + bool d_dump_mat; + uint32_t d_nchannels_in; + uint32_t d_nchannels_out; std::string d_dump_filename; std::ofstream d_dump_file; }; diff --git a/src/algorithms/resampler/CMakeLists.txt b/src/algorithms/resampler/CMakeLists.txt index 20a0f5449..1841d3dfc 100644 --- a/src/algorithms/resampler/CMakeLists.txt +++ b/src/algorithms/resampler/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,8 +13,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) -add_subdirectory(gnuradio_blocks) \ No newline at end of file +add_subdirectory(gnuradio_blocks) diff --git a/src/algorithms/resampler/adapters/CMakeLists.txt b/src/algorithms/resampler/adapters/CMakeLists.txt index de168eec5..07e8ddc74 100644 --- a/src/algorithms/resampler/adapters/CMakeLists.txt +++ b/src/algorithms/resampler/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,23 +13,42 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(RESAMPLER_ADAPTER_SOURCES direct_resampler_conditioner.cc ) -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/gnuradio_blocks - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} +set(RESAMPLER_ADAPTER_SOURCES + direct_resampler_conditioner.cc + mmse_resampler_conditioner.cc ) -file(GLOB RESAMPLER_ADAPTER_HEADERS "*.h") +set(RESAMPLER_ADAPTER_HEADERS + direct_resampler_conditioner.h + mmse_resampler_conditioner.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/gnuradio_blocks + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} +) + +if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.13.4") + add_definitions(-DGR_GREATER_38=1) +endif() + list(SORT RESAMPLER_ADAPTER_HEADERS) -add_library(resampler_adapters ${RESAMPLER_ADAPTER_SOURCES} ${RESAMPLER_ADAPTER_HEADERS}) +list(SORT RESAMPLER_ADAPTER_SOURCES) + +add_library(resampler_adapters + ${RESAMPLER_ADAPTER_SOURCES} + ${RESAMPLER_ADAPTER_HEADERS} +) + source_group(Headers FILES ${RESAMPLER_ADAPTER_HEADERS}) + target_link_libraries(resampler_adapters resampler_gr_blocks) diff --git a/src/algorithms/resampler/adapters/direct_resampler_conditioner.cc b/src/algorithms/resampler/adapters/direct_resampler_conditioner.cc index 1e08d02e4..a1e6e2e1b 100644 --- a/src/algorithms/resampler/adapters/direct_resampler_conditioner.cc +++ b/src/algorithms/resampler/adapters/direct_resampler_conditioner.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,39 +24,39 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "direct_resampler_conditioner.h" -#include -#include +#include "configuration_interface.h" +#include "direct_resampler_conditioner_cb.h" +#include "direct_resampler_conditioner_cc.h" +#include "direct_resampler_conditioner_cs.h" #include #include #include -#include "direct_resampler_conditioner_cc.h" -#include "direct_resampler_conditioner_cs.h" -#include "direct_resampler_conditioner_cb.h" -#include "configuration_interface.h" +#include +#include +#include using google::LogMessage; DirectResamplerConditioner::DirectResamplerConditioner( - ConfigurationInterface* configuration, std::string role, - unsigned int in_stream, unsigned int out_stream) : - role_(role), in_stream_(in_stream), out_stream_(out_stream) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_stream, unsigned int out_stream) : role_(role), in_stream_(in_stream), out_stream_(out_stream) { std::string default_item_type = "short"; std::string default_dump_file = "./data/signal_conditioner.dat"; - double fs_in; - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000.0); - sample_freq_in_ = configuration->property(role_ + ".sample_freq_in", (double)4000000.0); + double fs_in_deprecated, fs_in; + fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000.0); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + sample_freq_in_ = configuration->property(role_ + ".sample_freq_in", 4000000.0); sample_freq_out_ = configuration->property(role_ + ".sample_freq_out", fs_in); - if(std::fabs(fs_in - sample_freq_out_) > std::numeric_limits::epsilon()) + if (std::fabs(fs_in - sample_freq_out_) > std::numeric_limits::epsilon()) { - std::string aux_warn = "CONFIGURATION WARNING: Parameters GNSS-SDR.internal_fs_hz and " - + role_ + ".sample_freq_out are not set to the same value!" ; + std::string aux_warn = "CONFIGURATION WARNING: Parameters GNSS-SDR.internal_fs_sps and " + role_ + ".sample_freq_out are not set to the same value!"; LOG(WARNING) << aux_warn; std::cout << aux_warn << std::endl; } @@ -65,7 +65,7 @@ DirectResamplerConditioner::DirectResamplerConditioner( DLOG(INFO) << "dump_ is " << dump_; dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); resampler_ = direct_resampler_make_conditioner_cc(sample_freq_in_, sample_freq_out_); @@ -74,7 +74,7 @@ DirectResamplerConditioner::DirectResamplerConditioner( DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "resampler(" << resampler_->unique_id() << ")"; } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); resampler_ = direct_resampler_make_conditioner_cs(sample_freq_in_, sample_freq_out_); @@ -83,7 +83,7 @@ DirectResamplerConditioner::DirectResamplerConditioner( DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "resampler(" << resampler_->unique_id() << ")"; } - else if (item_type_.compare("cbyte") == 0) + else if (item_type_ == "cbyte") { item_size_ = sizeof(lv_8sc_t); resampler_ = direct_resampler_make_conditioner_cb(sample_freq_in_, sample_freq_out_); @@ -95,7 +95,7 @@ DirectResamplerConditioner::DirectResamplerConditioner( else { LOG(WARNING) << item_type_ << " unrecognized item type for resampler"; - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } if (dump_) { @@ -103,11 +103,18 @@ DirectResamplerConditioner::DirectResamplerConditioner( file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; } + if (in_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -DirectResamplerConditioner::~DirectResamplerConditioner() {} - +DirectResamplerConditioner::~DirectResamplerConditioner() = default; void DirectResamplerConditioner::connect(gr::top_block_sptr top_block) diff --git a/src/algorithms/resampler/adapters/direct_resampler_conditioner.h b/src/algorithms/resampler/adapters/direct_resampler_conditioner.h index 246ec58b8..300ce297f 100644 --- a/src/algorithms/resampler/adapters/direct_resampler_conditioner.h +++ b/src/algorithms/resampler/adapters/direct_resampler_conditioner.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,9 +33,9 @@ #ifndef GNSS_SDR_DIRECT_RESAMPLER_CONDITIONER_H_ #define GNSS_SDR_DIRECT_RESAMPLER_CONDITIONER_H_ -#include -#include #include "gnss_block_interface.h" +#include +#include class ConfigurationInterface; @@ -43,31 +43,35 @@ class ConfigurationInterface; * \brief Interface of an adapter of a direct resampler conditioner block * to a SignalConditionerInterface */ -class DirectResamplerConditioner: public GNSSBlockInterface +class DirectResamplerConditioner : public GNSSBlockInterface { public: DirectResamplerConditioner(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream); + const std::string& role, unsigned int in_stream, + unsigned int out_stream); virtual ~DirectResamplerConditioner(); - std::string role() + + inline std::string role() override { return role_; } - //! returns "Direct_Resampler" - std::string implementation() + + //! Returns "Direct_Resampler" + inline std::string implementation() override { return "Direct_Resampler"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string role_; diff --git a/src/algorithms/resampler/adapters/mmse_resampler_conditioner.cc b/src/algorithms/resampler/adapters/mmse_resampler_conditioner.cc new file mode 100644 index 000000000..bc18beba5 --- /dev/null +++ b/src/algorithms/resampler/adapters/mmse_resampler_conditioner.cc @@ -0,0 +1,150 @@ +/*! + * \file mmse_resampler_conditioner.cc + * \brief Implementation of an adapter of a MMSE resampler conditioner block + * to a SignalConditionerInterface + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "mmse_resampler_conditioner.h" +#include "configuration_interface.h" +#include +#include +#include +#include + +using google::LogMessage; + +MmseResamplerConditioner::MmseResamplerConditioner( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_stream, unsigned int out_stream) : role_(role), in_stream_(in_stream), out_stream_(out_stream) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/signal_conditioner.dat"; + double fs_in_deprecated, fs_in; + fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000.0); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + sample_freq_in_ = configuration->property(role_ + ".sample_freq_in", 4000000.0); + sample_freq_out_ = configuration->property(role_ + ".sample_freq_out", fs_in); + if (std::fabs(fs_in - sample_freq_out_) > std::numeric_limits::epsilon()) + { + std::string aux_warn = "CONFIGURATION WARNING: Parameters GNSS-SDR.internal_fs_sps and " + role_ + ".sample_freq_out are not set to the same value!"; + LOG(WARNING) << aux_warn; + std::cout << aux_warn << std::endl; + } + item_type_ = configuration->property(role + ".item_type", default_item_type); + dump_ = configuration->property(role + ".dump", false); + DLOG(INFO) << "dump_ is " << dump_; + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + + + //create a FIR low pass filter + std::vector taps = gr::filter::firdes::low_pass(1.0, + sample_freq_in_, + sample_freq_out_ / 2.1, + sample_freq_out_ / 5, + gr::filter::firdes::win_type::WIN_HAMMING); + std::cout << "Enabled fractional resampler low pass filter with " << taps.size() << " taps" << std::endl; + fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(1, taps); + +#ifdef GR_GREATER_38 + resampler_ = gr::filter::mmse_resampler_cc::make(0.0, sample_freq_in_ / sample_freq_out_); +#else + resampler_ = gr::filter::fractional_resampler_cc::make(0.0, sample_freq_in_ / sample_freq_out_); +#endif + DLOG(INFO) << "sample_freq_in " << sample_freq_in_; + DLOG(INFO) << "sample_freq_out" << sample_freq_out_; + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "resampler(" << resampler_->unique_id() << ")"; + } + else + { + LOG(WARNING) << item_type_ << " unrecognized item type for resampler"; + item_size_ = sizeof(gr_complex); + } + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +MmseResamplerConditioner::~MmseResamplerConditioner() = default; + + +void MmseResamplerConditioner::connect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->connect(fir_filter_ccf_, 0, resampler_, 0); + top_block->connect(resampler_, 0, file_sink_, 0); + DLOG(INFO) << "connected resampler to file sink"; + } + else + { + top_block->connect(fir_filter_ccf_, 0, resampler_, 0); + } +} + + +void MmseResamplerConditioner::disconnect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->disconnect(fir_filter_ccf_, 0, resampler_, 0); + top_block->disconnect(resampler_, 0, file_sink_, 0); + } + else + { + top_block->disconnect(fir_filter_ccf_, 0, resampler_, 0); + } +} + + +gr::basic_block_sptr MmseResamplerConditioner::get_left_block() +{ + return fir_filter_ccf_; +} + + +gr::basic_block_sptr MmseResamplerConditioner::get_right_block() +{ + return resampler_; +} diff --git a/src/algorithms/resampler/adapters/mmse_resampler_conditioner.h b/src/algorithms/resampler/adapters/mmse_resampler_conditioner.h new file mode 100644 index 000000000..641975e83 --- /dev/null +++ b/src/algorithms/resampler/adapters/mmse_resampler_conditioner.h @@ -0,0 +1,102 @@ +/*! + * \file mmse_resampler_conditioner.h + * \brief Interface of an adapter of a mmse resampler conditioner block + * to a SignalConditionerInterface + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_MMSE_RESAMPLER_CONDITIONER_H_ +#define GNSS_SDR_MMSE_RESAMPLER_CONDITIONER_H_ + +#include "gnss_block_interface.h" +#ifdef GR_GREATER_38 +#include +#include +#else +#include +#include +#endif + +#include +#include + +class ConfigurationInterface; + +/*! + * \brief Interface of a MMSE resampler block adapter + * to a SignalConditionerInterface + */ +class MmseResamplerConditioner : public GNSSBlockInterface +{ +public: + MmseResamplerConditioner(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream); + + virtual ~MmseResamplerConditioner(); + + inline std::string role() override + { + return role_; + } + + inline std::string implementation() override + { + return "Mmse_Resampler"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + unsigned int in_stream_; + unsigned int out_stream_; + std::string item_type_; + size_t item_size_; + bool dump_; + std::string dump_filename_; + double sample_freq_in_; + double sample_freq_out_; +#ifdef GR_GREATER_38 + gr::filter::mmse_resampler_cc::sptr resampler_; +#else + gr::filter::fractional_resampler_cc::sptr resampler_; +#endif + gr::filter::fir_filter_ccf::sptr fir_filter_ccf_; + gr::block_sptr file_sink_; +}; + +#endif /*GNSS_SDR_FRACTIONAL_RESAMPLER_CONDITIONER_H_*/ diff --git a/src/algorithms/resampler/gnuradio_blocks/CMakeLists.txt b/src/algorithms/resampler/gnuradio_blocks/CMakeLists.txt index 13d8427fe..ae570d644 100644 --- a/src/algorithms/resampler/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/resampler/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,26 +13,38 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(RESAMPLER_GR_BLOCKS_SOURCES - direct_resampler_conditioner_cc.cc - direct_resampler_conditioner_cs.cc - direct_resampler_conditioner_cb.cc +set(RESAMPLER_GR_BLOCKS_SOURCES + direct_resampler_conditioner_cc.cc + direct_resampler_conditioner_cs.cc + direct_resampler_conditioner_cb.cc +) + +set(RESAMPLER_GR_BLOCKS_HEADERS + direct_resampler_conditioner_cc.h + direct_resampler_conditioner_cs.h + direct_resampler_conditioner_cb.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) -file(GLOB RESAMPLER_GR_BLOCKS_HEADERS "*.h") list(SORT RESAMPLER_GR_BLOCKS_HEADERS) -add_library(resampler_gr_blocks ${RESAMPLER_GR_BLOCKS_SOURCES} ${RESAMPLER_GR_BLOCKS_HEADERS}) +list(SORT RESAMPLER_GR_BLOCKS_SOURCES) + +add_library(resampler_gr_blocks + ${RESAMPLER_GR_BLOCKS_SOURCES} + ${RESAMPLER_GR_BLOCKS_HEADERS} +) + source_group(Headers FILES ${RESAMPLER_GR_BLOCKS_HEADERS}) -add_dependencies(resampler_gr_blocks glog-${glog_RELEASE}) \ No newline at end of file + +add_dependencies(resampler_gr_blocks glog-${glog_RELEASE}) diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.cc b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.cc index a3e3687c6..39bf2883a 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.cc +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,113 +26,110 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "direct_resampler_conditioner_cb.h" -#include -#include -#include #include +#include using google::LogMessage; direct_resampler_conditioner_cb_sptr direct_resampler_make_conditioner_cb( - double sample_freq_in, double sample_freq_out) + double sample_freq_in, double sample_freq_out) { - return direct_resampler_conditioner_cb_sptr( - new direct_resampler_conditioner_cb(sample_freq_in, - sample_freq_out)); + new direct_resampler_conditioner_cb(sample_freq_in, + sample_freq_out)); } + direct_resampler_conditioner_cb::direct_resampler_conditioner_cb( - double sample_freq_in, double sample_freq_out) : - gr::block("direct_resampler_make_conditioner_cb", gr::io_signature::make(1, - 1, sizeof(lv_8sc_t)), gr::io_signature::make(1, 1, sizeof(lv_8sc_t))), - d_sample_freq_in(sample_freq_in), d_sample_freq_out( - sample_freq_out), d_phase(0), d_lphase(0), d_history(1) + double sample_freq_in, + double sample_freq_out) : gr::block("direct_resampler_make_conditioner_cb", gr::io_signature::make(1, 1, sizeof(lv_8sc_t)), gr::io_signature::make(1, 1, sizeof(lv_8sc_t))), + d_sample_freq_in(sample_freq_in), + d_sample_freq_out( + sample_freq_out), + d_phase(0), + d_lphase(0) { const double two_32 = 4294967296.0; // Computes the phase step multiplying the resampling ratio by 2^32 = 4294967296 if (d_sample_freq_in >= d_sample_freq_out) - { - d_phase_step = static_cast(floor(two_32 * sample_freq_out / sample_freq_in)); - } + { + d_phase_step = static_cast(floor(two_32 * sample_freq_out / sample_freq_in)); + } else - { - d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); - } + { + d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); + } set_relative_rate(1.0 * sample_freq_out / sample_freq_in); set_output_multiple(1); } -direct_resampler_conditioner_cb::~direct_resampler_conditioner_cb() -{ -} +direct_resampler_conditioner_cb::~direct_resampler_conditioner_cb() = default; + void direct_resampler_conditioner_cb::forecast(int noutput_items, - gr_vector_int &ninput_items_required) + gr_vector_int &ninput_items_required) { - - int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) - * sample_freq_in() / sample_freq_out()) + history() - 1); + int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) * sample_freq_in() / sample_freq_out()) + history() - 1); unsigned ninputs = ninput_items_required.size(); for (unsigned i = 0; i < ninputs; i++) - { - ninput_items_required[i] = nreqd; - } + { + ninput_items_required[i] = nreqd; + } } -int direct_resampler_conditioner_cb::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const lv_8sc_t *in = (const lv_8sc_t *)input_items[0]; - lv_8sc_t *out = (lv_8sc_t *)output_items[0]; +int direct_resampler_conditioner_cb::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 = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); int lcv = 0; int count = 0; if (d_sample_freq_in >= d_sample_freq_out) - { - while ((lcv < noutput_items)) { - if (d_phase <= d_lphase) - { - out[lcv] = *in; - lcv++; - } + while ((lcv < noutput_items)) + { + if (d_phase <= d_lphase) + { + out[lcv] = *in; + lcv++; + } - d_lphase = d_phase; - d_phase += d_phase_step; - in++; - count++; + d_lphase = d_phase; + d_phase += d_phase_step; + in++; + count++; + } } - } else - { - while ((lcv < noutput_items)) { - d_lphase = d_phase; - d_phase += d_phase_step; - if (d_phase <= d_lphase) - { - in++; - count++; - } - out[lcv] = *in; - lcv++; + while ((lcv < noutput_items)) + { + d_lphase = d_phase; + d_phase += d_phase_step; + if (d_phase <= d_lphase) + { + in++; + count++; + } + out[lcv] = *in; + lcv++; + } } - } consume_each(std::min(count, ninput_items[0])); return lcv; diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.h b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.h index 8565d9473..1db7f374d 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.h +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cb.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,51 +37,50 @@ class direct_resampler_conditioner_cb; typedef boost::shared_ptr - direct_resampler_conditioner_cb_sptr; + direct_resampler_conditioner_cb_sptr; direct_resampler_conditioner_cb_sptr direct_resampler_make_conditioner_cb(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); /*! * \brief This class implements a direct resampler conditioner for std::complex * * Direct resampling without interpolation */ -class direct_resampler_conditioner_cb: public gr::block +class direct_resampler_conditioner_cb : public gr::block { - private: - friend direct_resampler_conditioner_cb_sptr direct_resampler_make_conditioner_cb(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); double d_sample_freq_in; double d_sample_freq_out; uint32_t d_phase; uint32_t d_lphase; uint32_t d_phase_step; - unsigned int d_history; direct_resampler_conditioner_cb(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); public: - ~direct_resampler_conditioner_cb(); - unsigned int sample_freq_in() const + inline unsigned int sample_freq_in() const { return d_sample_freq_in; } - unsigned int sample_freq_out() const + + inline unsigned int sample_freq_out() const { return d_sample_freq_out; } + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif /* GNSS_SDR_DIRECT_RESAMPLER_CONDITIONER_CS_H */ diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.cc b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.cc index 828a11a58..a288cd4da 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.cc +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,38 +26,35 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "direct_resampler_conditioner_cc.h" -#include -#include -#include #include +#include + using google::LogMessage; direct_resampler_conditioner_cc_sptr direct_resampler_make_conditioner_cc( - double sample_freq_in, double sample_freq_out) + double sample_freq_in, double sample_freq_out) { - return direct_resampler_conditioner_cc_sptr( - new direct_resampler_conditioner_cc(sample_freq_in, - sample_freq_out)); + new direct_resampler_conditioner_cc(sample_freq_in, + sample_freq_out)); } - direct_resampler_conditioner_cc::direct_resampler_conditioner_cc( - double sample_freq_in, double sample_freq_out) : - gr::block("direct_resampler_conditioner_cc", gr::io_signature::make(1, 1, - sizeof(gr_complex)), gr::io_signature::make(1, 1, - sizeof(gr_complex))), d_sample_freq_in(sample_freq_in), - d_sample_freq_out(sample_freq_out), d_phase(0), d_lphase(0), - d_history(1) + double sample_freq_in, + double sample_freq_out) : gr::block("direct_resampler_conditioner_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_sample_freq_in(sample_freq_in), + d_sample_freq_out(sample_freq_out), + d_phase(0), + d_lphase(0) { // Computes the phase step multiplying the resampling ratio by 2^32 = 4294967296 const double two_32 = 4294967296.0; @@ -67,42 +64,34 @@ direct_resampler_conditioner_cc::direct_resampler_conditioner_cc( } else { - d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); + d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); } set_relative_rate(1.0 * sample_freq_out / sample_freq_in); set_output_multiple(1); } - - -direct_resampler_conditioner_cc::~direct_resampler_conditioner_cc() -{ - -} - +direct_resampler_conditioner_cc::~direct_resampler_conditioner_cc() = default; void direct_resampler_conditioner_cc::forecast(int noutput_items, - gr_vector_int &ninput_items_required) + gr_vector_int &ninput_items_required) { - int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) - * sample_freq_in() / sample_freq_out()) + history() - 1); + int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) * sample_freq_in() / sample_freq_out()) + history() - 1); unsigned ninputs = ninput_items_required.size(); for (unsigned i = 0; i < ninputs; i++) - { - ninput_items_required[i] = nreqd; - } + { + ninput_items_required[i] = nreqd; + } } - int direct_resampler_conditioner_cc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const gr_complex *in = (const gr_complex *)input_items[0]; - gr_complex *out = (gr_complex *)output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); int lcv = 0; int count = 0; diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.h b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.h index c53b0cf9d..0c477c571 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.h +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cc.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -46,42 +46,44 @@ class direct_resampler_conditioner_cc; typedef boost::shared_ptr direct_resampler_conditioner_cc_sptr; direct_resampler_conditioner_cc_sptr direct_resampler_make_conditioner_cc(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); /*! * \brief This class implements a direct resampler conditioner for complex data * * Direct resampling without interpolation */ -class direct_resampler_conditioner_cc: public gr::block +class direct_resampler_conditioner_cc : public gr::block { private: friend direct_resampler_conditioner_cc_sptr direct_resampler_make_conditioner_cc(double sample_freq_in, - double sample_freq_out); - double d_sample_freq_in; //! Specifies the sampling frequency of the input signal - double d_sample_freq_out; //! Specifies the sampling frequency of the output signal + double sample_freq_out); + double d_sample_freq_in; //! Specifies the sampling frequency of the input signal + double d_sample_freq_out; //! Specifies the sampling frequency of the output signal uint32_t d_phase; uint32_t d_lphase; uint32_t d_phase_step; - unsigned int d_history; direct_resampler_conditioner_cc(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); public: ~direct_resampler_conditioner_cc(); - unsigned int sample_freq_in() const + inline unsigned int sample_freq_in() const { return d_sample_freq_in; } - unsigned int sample_freq_out() const + + inline unsigned int sample_freq_out() const { return d_sample_freq_out; } + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif /* GNSS_SDR_DIRECT_RESAMPLER_CONDITIONER_CC_H */ diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.cc b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.cc index 1ed0872ba..3506879b6 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.cc +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,112 +26,108 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "direct_resampler_conditioner_cs.h" -#include -#include -#include #include +#include using google::LogMessage; direct_resampler_conditioner_cs_sptr direct_resampler_make_conditioner_cs( - double sample_freq_in, double sample_freq_out) + double sample_freq_in, double sample_freq_out) { - return direct_resampler_conditioner_cs_sptr( - new direct_resampler_conditioner_cs(sample_freq_in, - sample_freq_out)); + new direct_resampler_conditioner_cs(sample_freq_in, + sample_freq_out)); } + direct_resampler_conditioner_cs::direct_resampler_conditioner_cs( - double sample_freq_in, double sample_freq_out) : - gr::block("direct_resampler_make_conditioner_cs", gr::io_signature::make(1, - 1, sizeof(lv_16sc_t)), gr::io_signature::make(1, 1, sizeof(lv_16sc_t))), - d_sample_freq_in(sample_freq_in), d_sample_freq_out( - sample_freq_out), d_phase(0), d_lphase(0), d_history(1) + double sample_freq_in, + double sample_freq_out) : gr::block("direct_resampler_make_conditioner_cs", gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), gr::io_signature::make(1, 1, sizeof(lv_16sc_t))), + d_sample_freq_in(sample_freq_in), + d_sample_freq_out(sample_freq_out), + d_phase(0), + d_lphase(0) { const double two_32 = 4294967296.0; // Computes the phase step multiplying the resampling ratio by 2^32 = 4294967296 if (d_sample_freq_in >= d_sample_freq_out) - { - d_phase_step = static_cast(floor(two_32 * sample_freq_out / sample_freq_in)); - } + { + d_phase_step = static_cast(floor(two_32 * sample_freq_out / sample_freq_in)); + } else - { - d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); - } + { + d_phase_step = static_cast(floor(two_32 * sample_freq_in / sample_freq_out)); + } set_relative_rate(1.0 * sample_freq_out / sample_freq_in); set_output_multiple(1); } -direct_resampler_conditioner_cs::~direct_resampler_conditioner_cs() -{ -} +direct_resampler_conditioner_cs::~direct_resampler_conditioner_cs() = default; + void direct_resampler_conditioner_cs::forecast(int noutput_items, - gr_vector_int &ninput_items_required) + gr_vector_int &ninput_items_required) { - - int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) - * sample_freq_in() / sample_freq_out()) + history() - 1); + int nreqd = std::max(static_cast(1), static_cast(static_cast(noutput_items + 1) * sample_freq_in() / sample_freq_out()) + history() - 1); unsigned ninputs = ninput_items_required.size(); for (unsigned i = 0; i < ninputs; i++) - { - ninput_items_required[i] = nreqd; - } + { + ninput_items_required[i] = nreqd; + } } -int direct_resampler_conditioner_cs::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const lv_16sc_t *in = (const lv_16sc_t *)input_items[0]; - lv_16sc_t *out = (lv_16sc_t *)output_items[0]; +int direct_resampler_conditioner_cs::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 = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); int lcv = 0; int count = 0; if (d_sample_freq_in >= d_sample_freq_out) - { - while ((lcv < noutput_items)) { - if (d_phase <= d_lphase) - { - out[lcv] = *in; - lcv++; - } + while ((lcv < noutput_items)) + { + if (d_phase <= d_lphase) + { + out[lcv] = *in; + lcv++; + } - d_lphase = d_phase; - d_phase += d_phase_step; - in++; - count++; + d_lphase = d_phase; + d_phase += d_phase_step; + in++; + count++; + } } - } else - { - while ((lcv < noutput_items)) { - d_lphase = d_phase; - d_phase += d_phase_step; - if (d_phase <= d_lphase) - { - in++; - count++; - } - out[lcv] = *in; - lcv++; + while ((lcv < noutput_items)) + { + d_lphase = d_phase; + d_phase += d_phase_step; + if (d_phase <= d_lphase) + { + in++; + count++; + } + out[lcv] = *in; + lcv++; + } } - } consume_each(std::min(count, ninput_items[0])); return lcv; diff --git a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.h b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.h index 3e648b427..40602a68d 100644 --- a/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.h +++ b/src/algorithms/resampler/gnuradio_blocks/direct_resampler_conditioner_cs.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,51 +37,50 @@ class direct_resampler_conditioner_cs; typedef boost::shared_ptr - direct_resampler_conditioner_cs_sptr; + direct_resampler_conditioner_cs_sptr; direct_resampler_conditioner_cs_sptr direct_resampler_make_conditioner_cs(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); /*! * \brief This class implements a direct resampler conditioner for std::complex * * Direct resampling without interpolation */ -class direct_resampler_conditioner_cs: public gr::block +class direct_resampler_conditioner_cs : public gr::block { - private: - friend direct_resampler_conditioner_cs_sptr direct_resampler_make_conditioner_cs(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); double d_sample_freq_in; double d_sample_freq_out; uint32_t d_phase; uint32_t d_lphase; uint32_t d_phase_step; - unsigned int d_history; direct_resampler_conditioner_cs(double sample_freq_in, - double sample_freq_out); + double sample_freq_out); public: - ~direct_resampler_conditioner_cs(); - unsigned int sample_freq_in() const + inline unsigned int sample_freq_in() const { return d_sample_freq_in; } - unsigned int sample_freq_out() const + + inline unsigned int sample_freq_out() const { return d_sample_freq_out; } + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif /* GNSS_SDR_DIRECT_RESAMPLER_CONDITIONER_CS_H */ diff --git a/src/algorithms/signal_generator/CMakeLists.txt b/src/algorithms/signal_generator/CMakeLists.txt index c82608385..1841d3dfc 100644 --- a/src/algorithms/signal_generator/CMakeLists.txt +++ b/src/algorithms/signal_generator/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) diff --git a/src/algorithms/signal_generator/adapters/CMakeLists.txt b/src/algorithms/signal_generator/adapters/CMakeLists.txt index c55031d1a..fe793203b 100644 --- a/src/algorithms/signal_generator/adapters/CMakeLists.txt +++ b/src/algorithms/signal_generator/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,30 +13,35 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(SIGNAL_GENERATOR_ADAPTER_SOURCES signal_generator.cc) +set(SIGNAL_GENERATOR_ADAPTER_HEADERS signal_generator.h) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB SIGNAL_GENERATOR_ADAPTER_HEADERS "*.h") -list(SORT SIGNAL_GENERATOR_ADAPTER_HEADERS) -add_library(signal_generator_adapters ${SIGNAL_GENERATOR_ADAPTER_SOURCES} ${SIGNAL_GENERATOR_ADAPTER_HEADERS}) -source_group(Headers FILES ${SIGNAL_GENERATOR_ADAPTER_HEADERS}) -target_link_libraries(signal_generator_adapters gnss_sp_libs - signal_generator_blocks - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} +add_library(signal_generator_adapters + ${SIGNAL_GENERATOR_ADAPTER_SOURCES} + ${SIGNAL_GENERATOR_ADAPTER_HEADERS} +) + +source_group(Headers FILES ${SIGNAL_GENERATOR_ADAPTER_HEADERS}) + +target_link_libraries(signal_generator_adapters + gnss_sp_libs + signal_generator_blocks + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} ) diff --git a/src/algorithms/signal_generator/adapters/signal_generator.cc b/src/algorithms/signal_generator/adapters/signal_generator.cc index affa75705..a5e3d3923 100644 --- a/src/algorithms/signal_generator/adapters/signal_generator.cc +++ b/src/algorithms/signal_generator/adapters/signal_generator.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,26 +24,28 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "signal_generator.h" -#include -#include "configuration_interface.h" -#include "Galileo_E1.h" +#include "GLONASS_L1_L2_CA.h" #include "GPS_L1_CA.h" +#include "Galileo_E1.h" #include "Galileo_E5a.h" +#include "configuration_interface.h" +#include +#include +#include using google::LogMessage; SignalGenerator::SignalGenerator(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/gen_source.dat"; @@ -85,30 +87,37 @@ SignalGenerator::SignalGenerator(ConfigurationInterface* configuration, unsigned int vector_length = 0; if (std::find(system.begin(), system.end(), "E") != system.end()) { - if (signal1[0].at(0)=='5') + if (signal1[0].at(0) == '5') { - vector_length = round((float) fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ - / Galileo_E5a_CODE_LENGTH_CHIPS)); + vector_length = round(static_cast(fs_in) / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS)); } else { - vector_length = round((float)fs_in / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS)) - * Galileo_E1_C_SECONDARY_CODE_LENGTH; + vector_length = round(static_cast(fs_in) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)) * Galileo_E1_C_SECONDARY_CODE_LENGTH; } } else if (std::find(system.begin(), system.end(), "G") != system.end()) { - vector_length = round((float)fs_in - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + vector_length = round(static_cast(fs_in) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + } + else if (std::find(system.begin(), system.end(), "R") != system.end()) + { + if (signal1[0].at(0) == '1') + { + vector_length = round(static_cast(fs_in) / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS)); + } + else + { + vector_length = round(static_cast(fs_in) / (GLONASS_L2_CA_CODE_RATE_HZ / GLONASS_L2_CA_CODE_LENGTH_CHIPS)); + } } - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); DLOG(INFO) << "Item size " << item_size_; gen_source_ = signal_make_generator_c(signal1, system, PRN, CN0_dB, doppler_Hz, delay_chips, delay_sec, - data_flag, noise_flag, fs_in, vector_length, BW_BB); + data_flag, noise_flag, fs_in, vector_length, BW_BB); vector_to_stream_ = gr::blocks::vector_to_stream::make(item_size_, vector_length); @@ -119,7 +128,7 @@ SignalGenerator::SignalGenerator(ConfigurationInterface* configuration, else { LOG(WARNING) << item_type_ << " unrecognized item type for resampler"; - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } if (dump_) @@ -131,16 +140,23 @@ SignalGenerator::SignalGenerator(ConfigurationInterface* configuration, { DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -SignalGenerator::~SignalGenerator() -{} +SignalGenerator::~SignalGenerator() = default; void SignalGenerator::connect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->connect(gen_source_, 0, vector_to_stream_, 0); DLOG(INFO) << "connected gen_source to vector_to_stream"; @@ -150,14 +166,13 @@ void SignalGenerator::connect(gr::top_block_sptr top_block) top_block->connect(vector_to_stream_, 0, file_sink_, 0); DLOG(INFO) << "connected vector_to_stream_ to file sink"; } - } } void SignalGenerator::disconnect(gr::top_block_sptr top_block) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { top_block->disconnect(gen_source_, 0, vector_to_stream_, 0); if (dump_) diff --git a/src/algorithms/signal_generator/adapters/signal_generator.h b/src/algorithms/signal_generator/adapters/signal_generator.h index 623a28180..e32c431b8 100644 --- a/src/algorithms/signal_generator/adapters/signal_generator.h +++ b/src/algorithms/signal_generator/adapters/signal_generator.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,15 +33,14 @@ #ifndef GNSS_SDR_SIGNAL_GENERATOR_H_ #define GNSS_SDR_SIGNAL_GENERATOR_H_ - -#include -#include -#include -#include -#include -#include #include "gnss_block_interface.h" #include "signal_generator_c.h" +#include +#include +#include +#include +#include +#include class ConfigurationInterface; @@ -49,35 +48,37 @@ class ConfigurationInterface; * \brief This class generates synthesized GNSS signal. * */ -class SignalGenerator: public GNSSBlockInterface +class SignalGenerator : public GNSSBlockInterface { public: SignalGenerator(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); virtual ~SignalGenerator(); - std::string role() + + inline std::string role() override { return role_; } /*! -* \brief Returns "GNSSSignalGenerator". -*/ - std::string implementation() + * \brief Returns "GNSSSignalGenerator". + */ + inline std::string implementation() override { return "GNSSSignalGenerator"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string role_; diff --git a/src/algorithms/signal_generator/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_generator/gnuradio_blocks/CMakeLists.txt index 8086e3672..30ab655e1 100644 --- a/src/algorithms/signal_generator/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_generator/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,35 +13,42 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(SIGNAL_GENERATOR_BLOCK_SOURCES signal_generator_c.cc) +set(SIGNAL_GENERATOR_BLOCK_HEADERS signal_generator_c.h) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} +) + +add_library(signal_generator_blocks + ${SIGNAL_GENERATOR_BLOCK_SOURCES} + ${SIGNAL_GENERATOR_BLOCK_HEADERS} ) -file(GLOB SIGNAL_GENERATOR_BLOCK_HEADERS "*.h") -list(SORT SIGNAL_GENERATOR_BLOCK_HEADERS) -add_library(signal_generator_blocks ${SIGNAL_GENERATOR_BLOCK_SOURCES} ${SIGNAL_GENERATOR_BLOCK_HEADERS}) source_group(Headers FILES ${SIGNAL_GENERATOR_BLOCK_HEADERS}) -target_link_libraries(signal_generator_blocks gnss_system_parameters gnss_sp_libs - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + +target_link_libraries(signal_generator_blocks + gnss_system_parameters + gnss_sp_libs + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${ORC_LIBRARIES} ) -if(VOLK_GNSSSDR_FOUND) +if(VOLKGNSSSDR_FOUND) # add_dependencies(signal_generator_blocks glog-${glog_RELEASE}) -else(VOLK_GNSSSDR_FOUND) +else() add_dependencies(signal_generator_blocks volk_gnsssdr_module) -endif() \ No newline at end of file +endif() diff --git a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc index 74a1cf9f2..84a90d555 100644 --- a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc +++ b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * -* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -15,7 +15,7 @@ * GNSS-SDR is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. +* (at your option) any later version. * * GNSS-SDR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,71 +23,80 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License -* along with GNSS-SDR. If not, see . +* along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "signal_generator_c.h" -#include -#include -#include -#include -//#include -#include -#include "gps_sdr_signal_processing.h" -#include "galileo_e1_signal_processing.h" -#include "galileo_e5_signal_processing.h" +#include "GLONASS_L1_L2_CA.h" +#include "GPS_L1_CA.h" #include "Galileo_E1.h" #include "Galileo_E5a.h" -#include "GPS_L1_CA.h" +#include "galileo_e1_signal_processing.h" +#include "galileo_e5_signal_processing.h" +#include "glonass_l1_signal_processing.h" +#include "gps_sdr_signal_processing.h" +#include +#include +#include +#include + /* * Create a new instance of signal_generator_c and return * a boost shared_ptr. This is effectively the public constructor. */ signal_generator_c_sptr -signal_make_generator_c (std::vector signal1, std::vector system, const std::vector &PRN, - const std::vector &CN0_dB, const std::vector &doppler_Hz, - const std::vector &delay_chips, const std::vector &delay_sec,bool data_flag, bool noise_flag, - unsigned int fs_in, unsigned int vector_length, float BW_BB) +signal_make_generator_c(std::vector signal1, std::vector system, const std::vector &PRN, + const std::vector &CN0_dB, const std::vector &doppler_Hz, + const std::vector &delay_chips, const std::vector &delay_sec, bool data_flag, bool noise_flag, + unsigned int fs_in, unsigned int vector_length, float BW_BB) { - return gnuradio::get_initial_sptr(new signal_generator_c(signal1, system, PRN, CN0_dB, doppler_Hz, delay_chips,delay_sec, - data_flag, noise_flag, fs_in, vector_length, BW_BB)); + return gnuradio::get_initial_sptr(new signal_generator_c(std::move(signal1), std::move(system), PRN, CN0_dB, doppler_Hz, delay_chips, delay_sec, + data_flag, noise_flag, fs_in, vector_length, BW_BB)); } + /* * The private constructor */ -signal_generator_c::signal_generator_c (std::vector signal1, std::vector system, const std::vector &PRN, - const std::vector &CN0_dB, const std::vector &doppler_Hz, - const std::vector &delay_chips,const std::vector &delay_sec ,bool data_flag, bool noise_flag, - unsigned int fs_in, unsigned int vector_length, float BW_BB) : - gr::block ("signal_gen_cc", gr::io_signature::make(0, 0, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(gr_complex) * vector_length)), - signal_(signal1), - system_(system), - PRN_(PRN), - CN0_dB_(CN0_dB), - doppler_Hz_(doppler_Hz), - delay_chips_(delay_chips), - delay_sec_(delay_sec), - data_flag_(data_flag), - noise_flag_(noise_flag), - fs_in_(fs_in), - num_sats_(PRN.size()), - vector_length_(vector_length), - BW_BB_(BW_BB * static_cast(fs_in) / 2.0) +signal_generator_c::signal_generator_c(std::vector signal1, + std::vector system, + const std::vector &PRN, + std::vector CN0_dB, + std::vector doppler_Hz, + std::vector delay_chips, + std::vector delay_sec, + bool data_flag, + bool noise_flag, + unsigned int fs_in, + unsigned int vector_length, + float BW_BB) : gr::block("signal_gen_cc", gr::io_signature::make(0, 0, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex) * vector_length)), + signal_(std::move(signal1)), + system_(std::move(system)), + PRN_(PRN), + CN0_dB_(std::move(CN0_dB)), + doppler_Hz_(std::move(doppler_Hz)), + delay_chips_(std::move(delay_chips)), + delay_sec_(std::move(delay_sec)), + data_flag_(data_flag), + noise_flag_(noise_flag), + fs_in_(fs_in), + num_sats_(PRN.size()), + vector_length_(vector_length), + BW_BB_(BW_BB * static_cast(fs_in) / 2.0) { init(); generate_codes(); } + void signal_generator_c::init() { work_counter_ = 0; - complex_phase_ = static_cast(volk_gnsssdr_malloc(vector_length_ * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + complex_phase_ = static_cast(volk_gnsssdr_malloc(vector_length_ * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // True if Galileo satellites are present bool galileo_signal = std::find(system_.begin(), system_.end(), "E") != system_.end(); @@ -96,67 +105,73 @@ void signal_generator_c::init() { start_phase_rad_.push_back(0); current_data_bit_int_.push_back(1); - current_data_bits_.push_back(gr_complex(1, 0)); + current_data_bits_.emplace_back(1, 0); ms_counter_.push_back(0); data_modulation_.push_back((Galileo_E5a_I_SECONDARY_CODE.at(0) == '0' ? 1 : -1)); pilot_modulation_.push_back((Galileo_E5a_Q_SECONDARY_CODE[PRN_[sat]].at(0) == '0' ? 1 : -1)); if (system_[sat] == "G") { - samples_per_code_.push_back(round(static_cast(fs_in_) - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + samples_per_code_.push_back(round(static_cast(fs_in_) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); num_of_codes_per_vector_.push_back(galileo_signal ? 4 * static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH) : 1); data_bit_duration_ms_.push_back(1e3 / GPS_CA_TELEMETRY_RATE_BITS_SECOND); } + else if (system_[sat] == "R") + { + samples_per_code_.push_back(round(static_cast(fs_in_) / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS))); + + num_of_codes_per_vector_.push_back(galileo_signal ? 4 * static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH) : 1); + data_bit_duration_ms_.push_back(1e3 / GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND); + } else if (system_[sat] == "E") { if (signal_[sat].at(0) == '5') { int codelen = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); - samples_per_code_.push_back(round(static_cast(fs_in_) / (Galileo_E5a_CODE_CHIP_RATE_HZ - / codelen))); + samples_per_code_.push_back(round(static_cast(fs_in_) / (Galileo_E5a_CODE_CHIP_RATE_HZ / codelen))); num_of_codes_per_vector_.push_back(1); - data_bit_duration_ms_.push_back(1e3/Galileo_E5a_SYMBOL_RATE_BPS); + data_bit_duration_ms_.push_back(1e3 / Galileo_E5a_SYMBOL_RATE_BPS); } else { - samples_per_code_.push_back(round(static_cast(fs_in_) / (Galileo_E1_CODE_CHIP_RATE_HZ - / Galileo_E1_B_CODE_LENGTH_CHIPS))); + samples_per_code_.push_back(round(static_cast(fs_in_) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS))); num_of_codes_per_vector_.push_back(static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH)); data_bit_duration_ms_.push_back(1e3 / Galileo_E1_B_SYMBOL_RATE_BPS); } } } - random_ = new gr::random(); + std::default_random_engine e1(r()); + std::default_random_engine e2(r()); + std::uniform_int_distribution uniform_dist(0, RAND_MAX); } void signal_generator_c::generate_codes() { - sampled_code_data_.reset(new gr_complex*[num_sats_]); - sampled_code_pilot_.reset(new gr_complex*[num_sats_]); + sampled_code_data_.reset(new gr_complex *[num_sats_]); + sampled_code_pilot_.reset(new gr_complex *[num_sats_]); for (unsigned int sat = 0; sat < num_sats_; sat++) { - sampled_code_data_[sat] = static_cast(std::malloc(vector_length_ * sizeof(gr_complex))); + sampled_code_data_[sat] = static_cast(std::malloc(vector_length_ * sizeof(gr_complex))); - gr_complex code[64000]; //[samples_per_code_[sat]]; + gr_complex code[64000]; //[samples_per_code_[sat]]; if (system_[sat] == "G") { // Generate one code-period of 1C signal gps_l1_ca_code_gen_complex_sampled(code, PRN_[sat], fs_in_, - static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) - delay_chips_[sat]); + static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) - delay_chips_[sat]); // Obtain the desired CN0 assuming that Pn = 1. if (noise_flag_) { for (unsigned int i = 0; i < samples_per_code_[sat]; i++) { - code[i] *= sqrt(pow(10,CN0_dB_[sat] / 10) / BW_BB_); + code[i] *= sqrt(pow(10, CN0_dB_[sat] / 10) / BW_BB_); } } @@ -164,18 +179,40 @@ void signal_generator_c::generate_codes() for (unsigned int i = 0; i < num_of_codes_per_vector_[sat]; i++) { memcpy(&(sampled_code_data_[sat][i * samples_per_code_[sat]]), - code, sizeof(gr_complex) * samples_per_code_[sat]); + code, sizeof(gr_complex) * samples_per_code_[sat]); + } + } + else if (system_[sat] == "R") + { + // Generate one code-period of 1G signal + glonass_l1_ca_code_gen_complex_sampled(code, /*PRN_[sat],*/ fs_in_, + static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS) - delay_chips_[sat]); + + // Obtain the desired CN0 assuming that Pn = 1. + if (noise_flag_) + { + for (unsigned int i = 0; i < samples_per_code_[sat]; i++) + { + code[i] *= sqrt(pow(10, CN0_dB_[sat] / 10) / BW_BB_); + } + } + + // Concatenate "num_of_codes_per_vector_" codes + for (unsigned int i = 0; i < num_of_codes_per_vector_[sat]; i++) + { + memcpy(&(sampled_code_data_[sat][i * samples_per_code_[sat]]), + code, sizeof(gr_complex) * samples_per_code_[sat]); } } else if (system_[sat] == "E") { - if(signal_[sat].at(0) == '5') + if (signal_[sat].at(0) == '5') { char signal[3]; strcpy(signal, "5X"); - galileo_e5_a_code_gen_complex_sampled(sampled_code_data_[sat] , signal, PRN_[sat], fs_in_, - static_cast(Galileo_E5a_CODE_LENGTH_CHIPS) - delay_chips_[sat]); + galileo_e5_a_code_gen_complex_sampled(sampled_code_data_[sat], signal, PRN_[sat], fs_in_, + static_cast(Galileo_E5a_CODE_LENGTH_CHIPS) - delay_chips_[sat]); //noise if (noise_flag_) { @@ -193,7 +230,7 @@ void signal_generator_c::generate_codes() strcpy(signal, "1B"); galileo_e1_code_gen_complex_sampled(code, signal, cboc, PRN_[sat], fs_in_, - static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - delay_chips_[sat]); + static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - delay_chips_[sat]); // Obtain the desired CN0 assuming that Pn = 1. if (noise_flag_) @@ -208,16 +245,16 @@ void signal_generator_c::generate_codes() for (unsigned int i = 0; i < num_of_codes_per_vector_[sat]; i++) { memcpy(&(sampled_code_data_[sat][i * samples_per_code_[sat]]), - code, sizeof(gr_complex) * samples_per_code_[sat]); + code, sizeof(gr_complex) * samples_per_code_[sat]); } // Generate E1C signal (25 code-periods, with secondary code) - sampled_code_pilot_[sat] = static_cast(std::malloc(vector_length_ * sizeof(gr_complex))); + sampled_code_pilot_[sat] = static_cast(std::malloc(vector_length_ * sizeof(gr_complex))); strcpy(signal, "1C"); galileo_e1_code_gen_complex_sampled(sampled_code_pilot_[sat], signal, cboc, PRN_[sat], fs_in_, - static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - delay_chips_[sat], true); + static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) - delay_chips_[sat], true); // Obtain the desired CN0 assuming that Pn = 1. if (noise_flag_) @@ -233,7 +270,6 @@ void signal_generator_c::generate_codes() } - signal_generator_c::~signal_generator_c() { /* for (unsigned int sat = 0; sat < num_sats_; sat++) @@ -245,26 +281,27 @@ signal_generator_c::~signal_generator_c() } } */ volk_gnsssdr_free(complex_phase_); - delete random_; } -int signal_generator_c::general_work (int noutput_items __attribute__((unused)), - gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items __attribute__((unused)), - gr_vector_void_star &output_items) +int signal_generator_c::general_work(int noutput_items __attribute__((unused)), + gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), + gr_vector_void_star &output_items) { - gr_complex *out = (gr_complex *) output_items[0]; + auto *out = reinterpret_cast(output_items[0]); work_counter_++; unsigned int out_idx = 0; unsigned int i = 0; unsigned int k = 0; + // the intermediate frequency must be set by the user + unsigned int freq = 4e6; for (out_idx = 0; out_idx < vector_length_; out_idx++) { - out[out_idx] = gr_complex(0.0,0.0); + out[out_idx] = gr_complex(0.0, 0.0); } for (unsigned int sat = 0; sat < num_sats_; sat++) @@ -279,97 +316,119 @@ int signal_generator_c::general_work (int noutput_items __attribute__((unused)), if (system_[sat] == "G") { - unsigned int delay_samples = (delay_chips_[sat] % static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)) - * samples_per_code_[sat] / GPS_L1_CA_CODE_LENGTH_CHIPS; + unsigned int delay_samples = (delay_chips_[sat] % static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)) * samples_per_code_[sat] / GPS_L1_CA_CODE_LENGTH_CHIPS; for (i = 0; i < num_of_codes_per_vector_[sat]; i++) { for (k = 0; k < delay_samples; k++) { - out[out_idx] += sampled_code_data_[sat][out_idx] - * current_data_bits_[sat] - * complex_phase_[out_idx]; + out[out_idx] += sampled_code_data_[sat][out_idx] * current_data_bits_[sat] * complex_phase_[out_idx]; out_idx++; } if (ms_counter_[sat] == 0 && data_flag_) { // New random data bit - current_data_bits_[sat] = gr_complex((rand() % 2) == 0 ? 1 : -1, 0); + current_data_bits_[sat] = gr_complex((uniform_dist(e1) % 2) == 0 ? 1 : -1, 0); } for (k = delay_samples; k < samples_per_code_[sat]; k++) { - out[out_idx] += sampled_code_data_[sat][out_idx] - * current_data_bits_[sat] - * complex_phase_[out_idx]; + out[out_idx] += sampled_code_data_[sat][out_idx] * current_data_bits_[sat] * complex_phase_[out_idx]; out_idx++; } - ms_counter_[sat] = (ms_counter_[sat] + static_cast(round(1e3*GPS_L1_CA_CODE_PERIOD))) - % data_bit_duration_ms_[sat]; + ms_counter_[sat] = (ms_counter_[sat] + static_cast(round(1e3 * GPS_L1_CA_CODE_PERIOD))) % data_bit_duration_ms_[sat]; + } + } + + else if (system_[sat] == "R") + { + phase_step_rad = -static_cast(GPS_TWO_PI) * (freq + (DFRQ1_GLO * GLONASS_PRN.at(PRN_[sat])) + doppler_Hz_[sat]) / static_cast(fs_in_); + // std::cout << "sat " << PRN_[sat] << " SG - Freq = " << (freq + (DFRQ1_GLO * GLONASS_PRN.at(PRN_[sat]))) << " Doppler = " << doppler_Hz_[sat] << std::endl; + _phase[0] = -start_phase_rad_[sat]; + volk_gnsssdr_s32f_sincos_32fc(complex_phase_, -phase_step_rad, _phase, vector_length_); + + unsigned int delay_samples = (delay_chips_[sat] % static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS)) * samples_per_code_[sat] / GLONASS_L1_CA_CODE_LENGTH_CHIPS; + + for (i = 0; i < num_of_codes_per_vector_[sat]; i++) + { + for (k = 0; k < delay_samples; k++) + { + out[out_idx] += sampled_code_data_[sat][out_idx] * current_data_bits_[sat] * complex_phase_[out_idx]; + out_idx++; + } + + if (ms_counter_[sat] == 0 && data_flag_) + { + // New random data bit + current_data_bits_[sat] = gr_complex((uniform_dist(e1) % 2) == 0 ? 1 : -1, 0); + } + + for (k = delay_samples; k < samples_per_code_[sat]; k++) + { + out[out_idx] += sampled_code_data_[sat][out_idx] * current_data_bits_[sat] * complex_phase_[out_idx]; + out_idx++; + } + + ms_counter_[sat] = (ms_counter_[sat] + static_cast(round(1e3 * GLONASS_L1_CA_CODE_PERIOD))) % data_bit_duration_ms_[sat]; } } else if (system_[sat] == "E") { - if(signal_[sat].at(0)=='5') + if (signal_[sat].at(0) == '5') { // EACH WORK outputs 1 modulated primary code int codelen = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); - unsigned int delay_samples = (delay_chips_[sat] % codelen) - * samples_per_code_[sat] / codelen; + unsigned int delay_samples = (delay_chips_[sat] % codelen) * samples_per_code_[sat] / codelen; for (k = 0; k < delay_samples; k++) { - out[out_idx] += (gr_complex(sampled_code_data_[sat][out_idx].real()*data_modulation_[sat], - sampled_code_data_[sat][out_idx].imag()*pilot_modulation_[sat]) ) - * complex_phase_[out_idx]; + out[out_idx] += (gr_complex(sampled_code_data_[sat][out_idx].real() * data_modulation_[sat], + sampled_code_data_[sat][out_idx].imag() * pilot_modulation_[sat])) * + complex_phase_[out_idx]; out_idx++; } - if (ms_counter_[sat]%data_bit_duration_ms_[sat] == 0 && data_flag_) + if (ms_counter_[sat] % data_bit_duration_ms_[sat] == 0 && data_flag_) { // New random data bit - current_data_bit_int_[sat] = (rand()%2) == 0 ? 1 : -1; + current_data_bit_int_[sat] = (uniform_dist(e1) % 2) == 0 ? 1 : -1; } - data_modulation_[sat] = current_data_bit_int_[sat] * (Galileo_E5a_I_SECONDARY_CODE.at((ms_counter_[sat]+delay_sec_[sat]) % 20) == '0' ? 1 : -1); + data_modulation_[sat] = current_data_bit_int_[sat] * (Galileo_E5a_I_SECONDARY_CODE.at((ms_counter_[sat] + delay_sec_[sat]) % 20) == '0' ? 1 : -1); pilot_modulation_[sat] = (Galileo_E5a_Q_SECONDARY_CODE[PRN_[sat] - 1].at((ms_counter_[sat] + delay_sec_[sat]) % 100) == '0' ? 1 : -1); - ms_counter_[sat] = ms_counter_[sat] + static_cast(round(1e3*GALILEO_E5a_CODE_PERIOD)); + ms_counter_[sat] = ms_counter_[sat] + static_cast(round(1e3 * GALILEO_E5a_CODE_PERIOD)); for (k = delay_samples; k < samples_per_code_[sat]; k++) { - out[out_idx] += (gr_complex(sampled_code_data_[sat][out_idx].real() * data_modulation_[sat] , - sampled_code_data_[sat][out_idx].imag() * pilot_modulation_[sat]) ) - * complex_phase_[out_idx]; + out[out_idx] += (gr_complex(sampled_code_data_[sat][out_idx].real() * data_modulation_[sat], + sampled_code_data_[sat][out_idx].imag() * pilot_modulation_[sat])) * + complex_phase_[out_idx]; out_idx++; } } else { - unsigned int delay_samples = (delay_chips_[sat] % static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) - * samples_per_code_[sat] / Galileo_E1_B_CODE_LENGTH_CHIPS; + unsigned int delay_samples = (delay_chips_[sat] % static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) * samples_per_code_[sat] / Galileo_E1_B_CODE_LENGTH_CHIPS; for (i = 0; i < num_of_codes_per_vector_[sat]; i++) { for (k = 0; k < delay_samples; k++) { - out[out_idx] += (sampled_code_data_[sat][out_idx] * current_data_bits_[sat] - - sampled_code_pilot_[sat][out_idx]) * complex_phase_[out_idx]; + out[out_idx] += (sampled_code_data_[sat][out_idx] * current_data_bits_[sat] - sampled_code_pilot_[sat][out_idx]) * complex_phase_[out_idx]; out_idx++; } if (ms_counter_[sat] == 0 && data_flag_) { // New random data bit - current_data_bits_[sat] = gr_complex((rand() % 2) == 0 ? 1 : -1, 0); + current_data_bits_[sat] = gr_complex((uniform_dist(e1) % 2) == 0 ? 1 : -1, 0); } for (k = delay_samples; k < samples_per_code_[sat]; k++) { - out[out_idx] += (sampled_code_data_[sat][out_idx] * current_data_bits_[sat] - - sampled_code_pilot_[sat][out_idx]) - * complex_phase_[out_idx]; + out[out_idx] += (sampled_code_data_[sat][out_idx] * current_data_bits_[sat] - sampled_code_pilot_[sat][out_idx]) * complex_phase_[out_idx]; out_idx++; } @@ -383,7 +442,7 @@ int signal_generator_c::general_work (int noutput_items __attribute__((unused)), { for (out_idx = 0; out_idx < vector_length_; out_idx++) { - out[out_idx] += gr_complex(random_->gasdev(),random_->gasdev()); + out[out_idx] += gr_complex(normal_dist(e1), normal_dist(e2)); } } diff --git a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.h b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.h index e35dd0229..d47fc558b 100644 --- a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.h +++ b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,12 +31,14 @@ #ifndef GNSS_SDR_SIGNAL_GENERATOR_C_H #define GNSS_SDR_SIGNAL_GENERATOR_C_H +#include "gnss_signal.h" +#include +//#include +#include +#include #include #include -#include -#include -#include -#include "gnss_signal.h" + class signal_generator_c; @@ -60,10 +62,10 @@ typedef boost::shared_ptr signal_generator_c_sptr; * interface for creating new instances. */ signal_generator_c_sptr -signal_make_generator_c (std::vector signal1, std::vector system, const std::vector &PRN, - const std::vector &CN0_dB, const std::vector &doppler_Hz, - const std::vector &delay_chips,const std::vector &delay_sec, bool data_flag, bool noise_flag, - unsigned int fs_in, unsigned int vector_length, float BW_BB); +signal_make_generator_c(std::vector signal1, std::vector system, const std::vector &PRN, + const std::vector &CN0_dB, const std::vector &doppler_Hz, + const std::vector &delay_chips, const std::vector &delay_sec, bool data_flag, bool noise_flag, + unsigned int fs_in, unsigned int vector_length, float BW_BB); /*! * \brief This class generates synthesized GNSS signal. @@ -79,15 +81,15 @@ private: /* Create the signal_generator_c object*/ friend signal_generator_c_sptr - signal_make_generator_c (std::vector signal1, std::vector system, const std::vector &PRN, - const std::vector &CN0_dB, const std::vector &doppler_Hz, - const std::vector &delay_chips,const std::vector &delay_sec, bool data_flag, bool noise_flag, - unsigned int fs_in, unsigned int vector_length, float BW_BB); + signal_make_generator_c(std::vector signal1, std::vector system, const std::vector &PRN, + const std::vector &CN0_dB, const std::vector &doppler_Hz, + const std::vector &delay_chips, const std::vector &delay_sec, bool data_flag, bool noise_flag, + unsigned int fs_in, unsigned int vector_length, float BW_BB); - signal_generator_c (std::vector signal1, std::vector system, const std::vector &PRN, - const std::vector &CN0_dB, const std::vector &doppler_Hz, - const std::vector &delay_chips,const std::vector &delay_sec, bool data_flag, bool noise_flag, - unsigned int fs_in, unsigned int vector_length, float BW_BB); + signal_generator_c(std::vector signal1, std::vector system, const std::vector &PRN, + std::vector CN0_dB, std::vector doppler_Hz, + std::vector delay_chips, std::vector delay_sec, bool data_flag, bool noise_flag, + unsigned int fs_in, unsigned int vector_length, float BW_BB); void init(); void generate_codes(); @@ -116,23 +118,27 @@ private: std::vector data_modulation_; std::vector pilot_modulation_; - boost::scoped_array sampled_code_data_; - boost::scoped_array sampled_code_pilot_; - gr::random* random_; - gr_complex* complex_phase_; + boost::scoped_array sampled_code_data_; + boost::scoped_array sampled_code_pilot_; + //gr::random *random_; + gr_complex *complex_phase_; unsigned int work_counter_; + std::random_device r; + std::default_random_engine e1; + std::default_random_engine e2; + std::uniform_int_distribution uniform_dist; + std::normal_distribution normal_dist; public: - ~signal_generator_c(); // public destructor + ~signal_generator_c(); // public destructor // Where all the action really happens - int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif /* GNSS_SDR_SIGNAL_GENERATOR_C_H */ - diff --git a/src/algorithms/signal_source/CMakeLists.txt b/src/algorithms/signal_source/CMakeLists.txt index 5cd1218c0..9a158daa9 100644 --- a/src/algorithms/signal_source/CMakeLists.txt +++ b/src/algorithms/signal_source/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(libs) diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index ad00956da..6674cd853 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,131 +13,230 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # + # Optional drivers +if(ENABLE_RAW_UDP) + find_package(PCAP) + if(NOT PCAP_FOUND) + message(FATAL_ERROR "PCAP required to compile custom UDP packet sample source (ENABLE_RAW_UDP)") + endif() + get_filename_component(PCAP_LIBRARY_DIRS ${PCAP_LIBRARY} DIRECTORY CACHE) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${PCAP_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${PCAP_INCLUDE_DIRS}) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} custom_udp_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} custom_udp_signal_source.h) +endif() + +if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) + find_package(GRIIO REQUIRED) + if(NOT GRIIO_FOUND) + message(STATUS "gnuradio-iio not found, its installation is required.") + message(STATUS "Please build and install the following projects:") + message(STATUS " * libiio from https://github.com/analogdevicesinc/libiio") + message(STATUS " * libad9361-iio from https://github.com/analogdevicesinc/libad9361-iio") + message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") + message(FATAL_ERROR "gnuradio-iio is required for building gnss-sdr with this option enabled.") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${IIO_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) +endif() + +if(ENABLE_AD9361) + find_package(LIBIIO REQUIRED) + if(NOT LIBIIO_FOUND) + message(STATUS "libiio not found, its installation is required.") + message(STATUS "Please build and install the following projects:") + message(STATUS " * libiio from https://github.com/analogdevicesinc/libiio") + message(STATUS " * libad9361-iio from https://github.com/analogdevicesinc/libad9361-iio") + message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") + message(FATAL_ERROR "libiio is required for building gnss-sdr with this option enabled.") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${LIBIIO_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${LIBIIO_INCLUDE_DIRS}) +endif() + + +if(ENABLE_PLUTOSDR) + ############################################## + # ADALM-PLUTO (Analog Devices Inc.) + ############################################## + if(GRIIO_FOUND) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} plutosdr_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} plutosdr_signal_source.h) + endif() +endif() + + +if(ENABLE_FMCOMMS2) + ############################################### + # FMCOMMS2 based SDR Hardware + ############################################### + if(GRIIO_FOUND) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} fmcomms2_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} fmcomms2_signal_source.h) + endif() +endif() + + +if(ENABLE_AD9361) + ############################################### + # AD9361 DIRECT TO FPGA Hardware + ############################################### + if(LIBIIO_FOUND) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad9361_fpga_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad9361_fpga_signal_source.h) + endif() +endif() + + if(ENABLE_GN3S) - ############################################## - # GN3S (USB dongle) - ############################################## - find_package(GrGN3S REQUIRED) - if(NOT GR_GN3S_FOUND) - message(" gr-gn3s not found, install it from https://github.com/gnss-sdr/gr-gn3s ") - message(FATAL_ERROR "gr-gn3s required for building gnss-sdr with this option enabled") - endif(NOT GR_GN3S_FOUND) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GR_GN3S_LIBRARIES}) - set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${GR_GN3S_INCLUDE_DIRS}) - set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gn3s_signal_source.cc) -endif(ENABLE_GN3S) + ############################################## + # GN3S (USB dongle) + ############################################## + find_package(GRGN3S REQUIRED) + if(NOT GRGN3S_FOUND) + message(" gr-gn3s not found, install it from https://github.com/gnss-sdr/gr-gn3s ") + message(FATAL_ERROR "gr-gn3s required for building gnss-sdr with this option enabled") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GR_GN3S_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${GR_GN3S_INCLUDE_DIRS}) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gn3s_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gn3s_signal_source.h) +endif() if(ENABLE_FLEXIBAND) - ############################################## - # TELEORBIT FLEXIBAND FRONTEND ADAPTER - ############################################## - find_package(Teleorbit REQUIRED) - if(NOT TELEORBIT_FOUND) - message(FATAL_ERROR "Teleorbit Flexiband GNU Radio driver required to build gnss-sdr with the optional FLEXIBAND adapter") - endif(NOT TELEORBIT_FOUND) - - # Set up variables - set(FLEXIBAND_DRIVER_INCLUDE_DIRS - ${OPT_DRIVER_INCLUDE_DIRS} - ${TELEORBIT_INCLUDE_DIR}/teleorbit - ) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${TELEORBIT_LIBRARIES}) - set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${FLEXIBAND_DRIVER_INCLUDE_DIRS}) - set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} flexiband_signal_source.cc) -endif(ENABLE_FLEXIBAND) + ############################################## + # TELEORBIT FLEXIBAND FRONTEND ADAPTER + ############################################## + find_package(TELEORBIT REQUIRED) + if(NOT TELEORBIT_FOUND) + message(FATAL_ERROR "Teleorbit Flexiband GNU Radio driver required to build gnss-sdr with the optional FLEXIBAND adapter") + endif() + # Set up variables + set(FLEXIBAND_DRIVER_INCLUDE_DIRS + ${OPT_DRIVER_INCLUDE_DIRS} + ${TELEORBIT_INCLUDE_DIR}/teleorbit + ) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${TELEORBIT_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${FLEXIBAND_DRIVER_INCLUDE_DIRS}) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} flexiband_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} flexiband_signal_source.h) +endif() if(ENABLE_ARRAY) - ############################################## - # DBFCTTC GNSS EXPERIMENTAL ARRAY PROTOTYPE - ############################################## - find_package(GrDbfcttc REQUIRED) - if(NOT GR_DBFCTTC_FOUND) - message(" gr-dbfcttc not found, install it from https://github.com/gnss-sdr/gr-dbfcttc ") - message(FATAL_ERROR "gr-dbfcttc required for building gnss-sdr with this option enabled") - endif(NOT GR_DBFCTTC_FOUND) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GR_DBFCTTC_LIBRARIES}) - set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${GR_DBFCTTC_INCLUDE_DIRS}) - set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} raw_array_signal_source.cc) -endif(ENABLE_ARRAY) + ############################################## + # DBFCTTC GNSS EXPERIMENTAL ARRAY PROTOTYPE + ############################################## + find_package(GRDBFCTTC REQUIRED) + if(NOT GRDBFCTTC_FOUND) + message(" gr-dbfcttc not found, install it from https://github.com/gnss-sdr/gr-dbfcttc ") + message(FATAL_ERROR "gr-dbfcttc required for building gnss-sdr with this option enabled") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GR_DBFCTTC_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${GR_DBFCTTC_INCLUDE_DIRS}) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} raw_array_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} raw_array_signal_source.h) +endif() if(ENABLE_OSMOSDR) ################################################################################ # OsmoSDR - http://sdr.osmocom.org/trac/ ################################################################################ - find_package(GrOsmoSDR REQUIRED) if(NOT GROSMOSDR_FOUND) - message(FATAL_ERROR "gr-osmosdr required to build gnss-sdr with the optional OSMOSDR driver") - endif(NOT GROSMOSDR_FOUND) + if(ENABLE_PACKAGING) + list(REMOVE_ITEM SIGNAL_SOURCE_ADAPTER_HEADERS ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters/osmosdr_signal_source.h) + endif() + else() + # set OSMO include dirs + set(OSMO_DRIVER_INCLUDE_DIRS + ${OPT_DRIVER_INCLUDE_DIRS} + ${GROSMOSDR_INCLUDE_DIR}/osmosdr + ) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} osmosdr_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} osmosdr_signal_source.h) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GROSMOSDR_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${OSMO_DRIVER_INCLUDE_DIRS}) + endif() +endif() - # set OSMO include dirs - set(OSMO_DRIVER_INCLUDE_DIRS - ${OPT_DRIVER_INCLUDE_DIRS} - ${GROSMOSDR_INCLUDE_DIR}/osmosdr - ) - set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} osmosdr_signal_source.cc) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${GROSMOSDR_LIBRARIES}) - set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${OSMO_DRIVER_INCLUDE_DIRS}) -endif(ENABLE_OSMOSDR) -if(ENABLE_UHD) +if(ENABLE_UHD AND GNURADIO_UHD_LIBRARIES_gnuradio-uhd) set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} uhd_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} uhd_signal_source.h) set(OPT_LIBRARIES ${OPT_LIBRARIES} ${UHD_LIBRARIES} ${GNURADIO_UHD_LIBRARIES}) set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${UHD_INCLUDE_DIRS}) -endif(ENABLE_UHD) +endif() -set(SIGNAL_SOURCE_ADAPTER_SOURCES file_signal_source.cc - gen_signal_source.cc - nsr_file_signal_source.cc - spir_file_signal_source.cc - rtl_tcp_signal_source.cc - ${OPT_DRIVER_SOURCES} +set(SIGNAL_SOURCE_ADAPTER_SOURCES + file_signal_source.cc + gen_signal_source.cc + nsr_file_signal_source.cc + spir_file_signal_source.cc + spir_gss6450_file_signal_source.cc + rtl_tcp_signal_source.cc + labsat_signal_source.cc + ${OPT_DRIVER_SOURCES} ) +set(SIGNAL_SOURCE_ADAPTER_HEADERS + file_signal_source.h + gen_signal_source.h + nsr_file_signal_source.h + spir_file_signal_source.h + spir_gss6450_file_signal_source.h + rtl_tcp_signal_source.h + labsat_signal_source.h + ${OPT_DRIVER_HEADERS} +) + + if(PC_GNURADIO_RUNTIME_VERSION VERSION_GREATER 3.7.3) - set(SIGNAL_SOURCE_ADAPTER_SOURCES ${SIGNAL_SOURCE_ADAPTER_SOURCES} - two_bit_cpx_file_signal_source.cc - two_bit_packed_file_signal_source.cc ) -endif(PC_GNURADIO_RUNTIME_VERSION VERSION_GREATER 3.7.3) + set(SIGNAL_SOURCE_ADAPTER_SOURCES ${SIGNAL_SOURCE_ADAPTER_SOURCES} + two_bit_cpx_file_signal_source.cc + two_bit_packed_file_signal_source.cc) + set(SIGNAL_SOURCE_ADAPTER_HEADERS ${SIGNAL_SOURCE_ADAPTER_HEADERS} + two_bit_cpx_file_signal_source.h + two_bit_packed_file_signal_source.h) +endif() include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${OPT_DRIVER_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${OPT_DRIVER_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) if(ARCH_64BITS) add_definitions(-DARCH_64BITS=1) -endif(ARCH_64BITS) +endif() add_definitions(-DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}") -file(GLOB SIGNAL_SOURCE_ADAPTER_HEADERS "*.h") list(SORT SIGNAL_SOURCE_ADAPTER_HEADERS) +list(SORT SIGNAL_SOURCE_ADAPTER_SOURCES) + add_library(signal_source_adapters ${SIGNAL_SOURCE_ADAPTER_SOURCES} ${SIGNAL_SOURCE_ADAPTER_HEADERS}) source_group(Headers FILES ${SIGNAL_SOURCE_ADAPTER_HEADERS}) target_link_libraries(signal_source_adapters signal_source_gr_blocks - ${Boost_LIBRARIES} - ${GNURADIO_PMT_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${OPT_LIBRARIES} - gnss_sp_libs + ${Boost_LIBRARIES} + ${GNURADIO_PMT_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${OPT_LIBRARIES} + gnss_sp_libs ) - diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc new file mode 100644 index 000000000..a9cade7c5 --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -0,0 +1,179 @@ +/*! + * \file ad9361_fpga_signal_source.cc + * \brief signal source for Analog Devices front-end AD9361 connected directly to FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking is selected in the configuration file. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "ad9361_fpga_signal_source.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "ad9361_manager.h" +#include "configuration_interface.h" +#include +#include +#include // for cout, endl +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/signal_source.dat"; + freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2600000); + bandwidth_ = configuration->property(role + ".bandwidth", 2000000); + rx1_en_ = configuration->property(role + ".rx1_enable", true); + rx2_en_ = configuration->property(role + ".rx2_enable", false); + buffer_size_ = configuration->property(role + ".buffer_size", 0xA0000); + quadrature_ = configuration->property(role + ".quadrature", true); + rf_dc_ = configuration->property(role + ".rf_dc", true); + bb_dc_ = configuration->property(role + ".bb_dc", true); + gain_mode_rx1_ = configuration->property(role + ".gain_mode_rx1", std::string("manual")); + gain_mode_rx2_ = configuration->property(role + ".gain_mode_rx2", std::string("manual")); + rf_gain_rx1_ = configuration->property(role + ".gain_rx1", 64.0); + rf_gain_rx2_ = configuration->property(role + ".gain_rx2", 64.0); + rf_port_select_ = configuration->property(role + ".rf_port_select", std::string("A_BALANCED")); + filter_file_ = configuration->property(role + ".filter_file", std::string("")); + filter_auto_ = configuration->property(role + ".filter_auto", true); + item_type_ = configuration->property(role + ".item_type", default_item_type); + samples_ = configuration->property(role + ".samples", 0); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + enable_dds_lo_ = configuration->property(role + ".enable_dds_lo", false); + freq_rf_tx_hz_ = configuration->property(role + ".freq_rf_tx_hz", GPS_L1_FREQ_HZ - GPS_L2_FREQ_HZ - 1000); + freq_dds_tx_hz_ = configuration->property(role + ".freq_dds_tx_hz", 1000); + scale_dds_dbfs_ = configuration->property(role + ".scale_dds_dbfs", -3.0); + phase_dds_deg_ = configuration->property(role + ".phase_dds_deg", 0.0); + tx_attenuation_db_ = configuration->property(role + ".tx_attenuation_db", 0.0); + + item_size_ = sizeof(gr_complex); + + std::cout << "device address: " << uri_ << std::endl; + std::cout << "LO frequency : " << freq_ << " Hz" << std::endl; + std::cout << "sample rate: " << sample_rate_ << " Hz" << std::endl; + + config_ad9361_rx_local(bandwidth_, + sample_rate_, + freq_, + rf_port_select_, + gain_mode_rx1_, + gain_mode_rx2_, + rf_gain_rx1_, + rf_gain_rx2_); + + //LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION + if (enable_dds_lo_ == true) + { + config_ad9361_lo_local(bandwidth_, + sample_rate_, + freq_rf_tx_hz_, + tx_attenuation_db_, + freq_dds_tx_hz_, + scale_dds_dbfs_); + } + + // turn switch to A/D position + std::string default_device_name = "/dev/uio13"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + int switch_position = configuration->property(role + ".switch_position", 0); + switch_fpga = std::make_shared(device_name); + switch_fpga->set_switch_position(switch_position); + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() +{ + /* cleanup and exit */ + //std::cout<<"* AD9361 Disabling streaming channels\n"; + //if (rx0_i) { iio_channel_disable(rx0_i); } + //if (rx0_q) { iio_channel_disable(rx0_q); } + + if (enable_dds_lo_) + { + try + { + ad9361_disable_lo_local(); + } + catch (const std::exception& e) + { + LOG(WARNING) << "Problem closing the Ad9361FpgaSignalSource: " << e.what(); + } + } + + // std::cout<<"* AD9361 Destroying context\n"; + //if (ctx) { iio_context_destroy(ctx); } +} + + +void Ad9361FpgaSignalSource::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void Ad9361FpgaSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr Ad9361FpgaSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return gr::basic_block_sptr(); +} + + +gr::basic_block_sptr Ad9361FpgaSignalSource::get_right_block() +{ + LOG(WARNING) << "Trying to get AD9361 FPGA signal source right block."; + return gr::basic_block_sptr(); +} diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h new file mode 100644 index 000000000..79ebeff3e --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h @@ -0,0 +1,120 @@ +/*! + * \file ad9361_fpga_signal_source.h + * \brief signal source for Analog Devices front-end AD9361 connected directly to FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking is selected in the configuration file. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ +#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ + +#include "fpga_switch.h" +#include "gnss_block_interface.h" +#include +#include +#include +#include + +class ConfigurationInterface; + +class Ad9361FpgaSignalSource : public GNSSBlockInterface +{ +public: + Ad9361FpgaSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + ~Ad9361FpgaSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Ad9361_Fpga_Signal_Source" + */ + inline std::string implementation() override + { + return "Ad9361_Fpga_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + + // Front-end settings + std::string uri_; // device direction + uint64_t freq_; // frequency of local oscillator + uint64_t sample_rate_; + uint64_t bandwidth_; + uint64_t buffer_size_; // reception buffer + bool rx1_en_; + bool rx2_en_; + bool quadrature_; + bool rf_dc_; + bool bb_dc_; + std::string gain_mode_rx1_; + std::string gain_mode_rx2_; + double rf_gain_rx1_; + double rf_gain_rx2_; + std::string rf_port_select_; + std::string filter_file_; + bool filter_auto_; + + // DDS configuration for LO generation for external mixer + bool enable_dds_lo_; + uint64_t freq_rf_tx_hz_; + uint64_t freq_dds_tx_hz_; + double scale_dds_dbfs_; + double phase_dds_deg_; + double tx_attenuation_db_; + + uint32_t in_stream_; + uint32_t out_stream_; + + std::string item_type_; + size_t item_size_; + long samples_; + bool dump_; + std::string dump_filename_; + + boost::shared_ptr queue_; + + std::shared_ptr switch_fpga; +}; + +#endif /*GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc b/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc new file mode 100644 index 000000000..2f2e76ef3 --- /dev/null +++ b/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc @@ -0,0 +1,174 @@ +/*! + * \file udp_signal_source.cc + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "custom_udp_signal_source.h" +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include +#include +#include +#include + + +using google::LogMessage; + + +CustomUDPSignalSource::CustomUDPSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) +{ + // DUMP PARAMETERS + std::string empty = ""; + std::string default_dump_file = "./data/signal_source.dat"; + std::string default_item_type = "gr_complex"; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + // network PARAMETERS + std::string default_capture_device = "eth0"; + std::string default_address = "127.0.0.1"; + int default_port = 1234; + std::string address = configuration->property(role + ".origin_address", default_address); + std::string capture_device = configuration->property(role + ".capture_device", default_capture_device); + int port = configuration->property(role + ".port", default_port); + int payload_bytes = configuration->property(role + ".payload_bytes", 1024); + + RF_channels_ = configuration->property(role + ".RF_channels", 1); + channels_in_udp_ = configuration->property(role + ".channels_in_udp", 1); + IQ_swap_ = configuration->property(role + ".IQ_swap", false); + + std::string default_sample_type = "cbyte"; + std::string sample_type = configuration->property(role + ".sample_type", default_sample_type); + item_type_ = configuration->property(role + ".item_type", default_item_type); + // output item size is always gr_complex + item_size_ = sizeof(gr_complex); + + udp_gnss_rx_source_ = gr_complex_ip_packet_source::make(capture_device, + address, + port, + payload_bytes, + channels_in_udp_, + sample_type, + item_size_, + IQ_swap_); + + if (channels_in_udp_ >= RF_channels_) + { + for (int n = 0; n < channels_in_udp_; n++) + { + null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); + } + } + else + { + std::cout << "Configuration error: RF_channels 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +CustomUDPSignalSource::~CustomUDPSignalSource() = default; + + +void CustomUDPSignalSource::connect(gr::top_block_sptr top_block) +{ + // connect null sinks to unused streams + for (int n = 0; n < channels_in_udp_; n++) + { + top_block->connect(udp_gnss_rx_source_, n, null_sinks_.at(n), 0); + } + DLOG(INFO) << "connected udp_source to null_sinks to enable the use of spare channels" << std::endl; + + if (dump_) + { + for (int n = 0; n < channels_in_udp_; n++) + { + top_block->connect(udp_gnss_rx_source_, n, file_sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } +} + + +void CustomUDPSignalSource::disconnect(gr::top_block_sptr top_block) +{ + // disconnect null sinks to unused streams + for (int n = 0; n < channels_in_udp_; n++) + { + top_block->disconnect(udp_gnss_rx_source_, n, null_sinks_.at(n), 0); + } + if (dump_) + { + for (int n = 0; n < channels_in_udp_; n++) + { + top_block->disconnect(udp_gnss_rx_source_, n, file_sink_.at(n), 0); + DLOG(INFO) << "disconnected source to file sink"; + } + } + DLOG(INFO) << "disconnected udp_source" << std::endl; +} + + +gr::basic_block_sptr CustomUDPSignalSource::get_left_block() +{ + LOG(WARNING) << "Left block of a signal source should not be retrieved"; + return gr::block_sptr(); +} + + +gr::basic_block_sptr CustomUDPSignalSource::get_right_block() +{ + return udp_gnss_rx_source_; +} + + +gr::basic_block_sptr CustomUDPSignalSource::get_right_block(__attribute__((unused)) int RF_channel) +{ + return udp_gnss_rx_source_; +} diff --git a/src/algorithms/signal_source/adapters/custom_udp_signal_source.h b/src/algorithms/signal_source/adapters/custom_udp_signal_source.h new file mode 100644 index 000000000..bec7c3d73 --- /dev/null +++ b/src/algorithms/signal_source/adapters/custom_udp_signal_source.h @@ -0,0 +1,105 @@ +/*! + * \file udp_signal_source.h + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H +#define GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H + +#include "gnss_block_interface.h" +#include "gr_complex_ip_packet_source.h" +#include +#include +#include +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class reads from UDP packets, which streams interleaved + * I/Q samples over a network. + */ +class CustomUDPSignalSource : public GNSSBlockInterface +{ +public: + CustomUDPSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + virtual ~CustomUDPSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "UDP_Signal_Source" + */ + inline std::string implementation() override + { + return "Custom_UDP_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; + +private: + std::string role_; + + bool IQ_swap_; + int RF_channels_; + int channels_in_udp_; + unsigned int in_stream_; + unsigned int out_stream_; + + std::string item_type_; + size_t item_size_; + bool dump_; + std::string dump_filename_; + std::vector> null_sinks_; + gr_complex_ip_packet_source::sptr udp_gnss_rx_source_; + std::vector> file_sink_; + boost::shared_ptr queue_; +}; + +#endif /*GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H */ diff --git a/src/algorithms/signal_source/adapters/file_signal_source.cc b/src/algorithms/signal_source/adapters/file_signal_source.cc index e4d16190a..bc4fb6329 100644 --- a/src/algorithms/signal_source/adapters/file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/file_signal_source.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,34 +25,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "file_signal_source.h" -#include -#include +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include +#include #include #include -#include -#include -#include -#include -#include "gnss_sdr_valve.h" -#include "configuration_interface.h" +#include // for std::cerr +#include + using google::LogMessage; -DEFINE_string(signal_source, "-", - "If defined, path to the file containing the signal samples (overrides the configuration file)"); - - FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : - role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) + const std::string& role, unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "./example_capture.dat"; std::string default_item_type = "short"; @@ -65,43 +60,43 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, filename_ = configuration->property(role + ".filename", default_filename); // override value with commandline flag, if present - if (FLAGS_signal_source.compare("-") != 0) filename_= FLAGS_signal_source; + if (FLAGS_signal_source != "-") filename_ = FLAGS_signal_source; + if (FLAGS_s != "-") filename_ = FLAGS_s; item_type_ = configuration->property(role + ".item_type", default_item_type); repeat_ = configuration->property(role + ".repeat", false); dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); - std::string s = "InputFilter"; - //double IF = configuration->property(s + ".IF", 0.0); - double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip ); - header_size = configuration->property( role + ".header_size", 0 ); - long samples_to_skip = 0; + + double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); + header_size = configuration->property(role + ".header_size", 0); + int64_t samples_to_skip = 0; bool is_complex = false; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); } - else if (item_type_.compare("float") == 0) + else if (item_type_ == "float") { item_size_ = sizeof(float); } - else if (item_type_.compare("short") == 0) + else if (item_type_ == "short") { item_size_ = sizeof(int16_t); } - else if (item_type_.compare("ishort") == 0) + else if (item_type_ == "ishort") { item_size_ = sizeof(int16_t); is_complex = true; } - else if (item_type_.compare("byte") == 0) + else if (item_type_ == "byte") { item_size_ = sizeof(int8_t); } - else if (item_type_.compare("ibyte") == 0) + else if (item_type_ == "ibyte") { item_size_ = sizeof(int8_t); is_complex = true; @@ -109,87 +104,84 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, else { LOG(WARNING) << item_type_ - << " unrecognized item type. Using gr_complex."; + << " unrecognized item type. Using gr_complex."; item_size_ = sizeof(gr_complex); } try - { + { file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); - if( seconds_to_skip > 0 ) - { - samples_to_skip = static_cast< long >( - seconds_to_skip * sampling_frequency_ ); - - if( is_complex ) + if (seconds_to_skip > 0) { - samples_to_skip *= 2; - } - } - if( header_size > 0 ) - { - samples_to_skip += header_size; - } + samples_to_skip = static_cast(seconds_to_skip * sampling_frequency_); - if( samples_to_skip > 0 ) - { - LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file"; - if( not file_source_->seek( samples_to_skip, SEEK_SET ) ) + if (is_complex) + { + samples_to_skip *= 2; + } + } + if (header_size > 0) { - LOG(INFO) << "Error skipping bytes!"; + samples_to_skip += header_size; } - } - } - catch (const std::exception &e) - { - if (filename_.compare(default_filename) == 0) + if (samples_to_skip > 0) + { + LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file"; + if (not file_source_->seek(samples_to_skip, SEEK_SET)) + { + LOG(INFO) << "Error skipping bytes!"; + } + } + } + catch (const std::exception& e) + { + if (filename_ == default_filename) { std::cerr - << "The configuration file has not been found." - << std::endl - << "Please create a configuration file based on the examples at the 'conf/' folder " - << std::endl - << "and then generate your own GNSS Software Defined Receiver by doing:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl; + << "The configuration file has not been found." + << std::endl + << "Please create a configuration file based on the examples at the 'conf/' folder " + << std::endl + << "and then generate your own GNSS Software Defined Receiver by doing:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl; } else { std::cerr - << "The receiver was configured to work with a file signal source " - << std::endl - << "but the specified file is unreachable by GNSS-SDR." - << std::endl - << "Please modify your configuration file" - << std::endl - << "and point SignalSource.filename to a valid raw data file. Then:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl - << "Examples of configuration files available at:" - << std::endl - << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" - << std::endl; - + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; } LOG(INFO) << "file_signal_source: Unable to open the samples file " << filename_.c_str() << ", exiting the program."; throw(e); - } + } DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; - if (samples_ == 0) // read all file + if (samples_ == 0) // read all file { /*! * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the * valve block */ - std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream::pos_type size; if (file.is_open()) @@ -205,21 +197,21 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(16); std::cout << "Processing file " << filename_ << ", which contains " << static_cast(size) << " [bytes]" << std::endl; - std::cout.precision (ss); + std::cout.precision(ss); if (size > 0) { - long bytes_to_skip = samples_to_skip*item_size_; - long bytes_to_process = static_cast(size) - bytes_to_skip; - samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size()) - ceil(0.002 * static_cast(sampling_frequency_))); //process all the samples available in the file excluding at least the last 1 ms + int64_t bytes_to_skip = samples_to_skip * item_size_; + int64_t bytes_to_process = static_cast(size) - bytes_to_skip; + samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size()) - ceil(0.002 * static_cast(sampling_frequency_))); //process all the samples available in the file excluding at least the last 1 ms } } CHECK(samples_ > 0) << "File does not contain enough samples to process."; double signal_duration_s; - signal_duration_s = static_cast(samples_) * ( 1 / static_cast(sampling_frequency_)); + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); - if( is_complex ) + if (is_complex) { signal_duration_s /= 2.0; } @@ -239,8 +231,8 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, if (enable_throttle_control_) { throttle_ = gr::blocks::throttle::make(item_size_, sampling_frequency_); - } + DLOG(INFO) << "File source filename " << filename_; DLOG(INFO) << "Samples " << samples_; DLOG(INFO) << "Sampling frequency " << sampling_frequency_; @@ -249,15 +241,18 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, DLOG(INFO) << "Repeat " << repeat_; DLOG(INFO) << "Dump " << dump_; DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - - -FileSignalSource::~FileSignalSource() -{} - - +FileSignalSource::~FileSignalSource() = default; void FileSignalSource::connect(gr::top_block_sptr top_block) @@ -311,10 +306,6 @@ void FileSignalSource::connect(gr::top_block_sptr top_block) } - - - - void FileSignalSource::disconnect(gr::top_block_sptr top_block) { if (samples_ > 0) @@ -366,9 +357,6 @@ void FileSignalSource::disconnect(gr::top_block_sptr top_block) } - - - gr::basic_block_sptr FileSignalSource::get_left_block() { LOG(WARNING) << "Left block of a signal source should not be retrieved"; @@ -376,24 +364,15 @@ gr::basic_block_sptr FileSignalSource::get_left_block() } - - - gr::basic_block_sptr FileSignalSource::get_right_block() { if (samples_ > 0) { return valve_; } - else + if (enable_throttle_control_ == true) { - if (enable_throttle_control_ == true) - { - return throttle_; - } - else - { - return file_source_; - } + return throttle_; } + return file_source_; } diff --git a/src/algorithms/signal_source/adapters/file_signal_source.h b/src/algorithms/signal_source/adapters/file_signal_source.h index 434db7f92..0d4658304 100644 --- a/src/algorithms/signal_source/adapters/file_signal_source.h +++ b/src/algorithms/signal_source/adapters/file_signal_source.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,14 +35,14 @@ #ifndef GNSS_SDR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_FILE_SIGNAL_SOURCE_H_ -#include -#include +#include "gnss_block_interface.h" #include +#include #include #include #include -#include "gnss_block_interface.h" - +#include +#include class ConfigurationInterface; @@ -50,15 +50,16 @@ class ConfigurationInterface; * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class FileSignalSource: public GNSSBlockInterface +class FileSignalSource : public GNSSBlockInterface { public: - FileSignalSource(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + FileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); virtual ~FileSignalSource(); - std::string role() + + inline std::string role() override { return role_; } @@ -66,41 +67,48 @@ public: /*! * \brief Returns "File_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "File_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string filename() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const { return filename_; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - bool repeat() + + inline bool repeat() const { return repeat_; } - long sampling_frequency() + + inline long sampling_frequency() const { return sampling_frequency_; } - long samples() + + inline long samples() const { return samples_; } private: - unsigned long long samples_; + uint64_t samples_; long sampling_frequency_; std::string filename_; std::string item_type_; @@ -108,12 +116,12 @@ private: bool dump_; std::string dump_filename_; std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; + uint32_t in_streams_; + uint32_t out_streams_; gr::blocks::file_source::sptr file_source_; boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; - gr::blocks::throttle::sptr throttle_; + gr::blocks::throttle::sptr throttle_; boost::shared_ptr queue_; size_t item_size_; // Throttle control diff --git a/src/algorithms/signal_source/adapters/flexiband_signal_source.cc b/src/algorithms/signal_source/adapters/flexiband_signal_source.cc index e21126506..95b3c56cd 100644 --- a/src/algorithms/signal_source/adapters/flexiband_signal_source.cc +++ b/src/algorithms/signal_source/adapters/flexiband_signal_source.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,24 +23,23 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "flexiband_signal_source.h" +#include "configuration_interface.h" +#include #include #include -#include #include -#include "configuration_interface.h" using google::LogMessage; FlexibandSignalSource::FlexibandSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { std::string default_item_type = "byte"; item_type_ = configuration->property(role + ".item_type", default_item_type); @@ -48,12 +47,12 @@ FlexibandSignalSource::FlexibandSignalSource(ConfigurationInterface* configurati std::string default_firmware_file = "flexiband_I-1b.bit"; firmware_filename_ = configuration->property(role + ".firmware_file", default_firmware_file); - gain1_ = configuration->property(role + ".gain1", 0); // check gain DAC values for Flexiband frontend! - gain2_ = configuration->property(role + ".gain2", 0); // check gain DAC values for Flexiband frontend! - gain3_ = configuration->property(role + ".gain3", 0); // check gain DAC values for Flexiband frontend! + gain1_ = configuration->property(role + ".gain1", 0); // check gain DAC values for Flexiband frontend! + gain2_ = configuration->property(role + ".gain2", 0); // check gain DAC values for Flexiband frontend! + gain3_ = configuration->property(role + ".gain3", 0); // check gain DAC values for Flexiband frontend! - AGC_ = configuration->property(role + ".AGC", true); // enabled AGC by default - flag_read_file = configuration->property(role + ".flag_read_file", false); //disable read samples from file by default + AGC_ = configuration->property(role + ".AGC", true); // enabled AGC by default + flag_read_file = configuration->property(role + ".flag_read_file", false); //disable read samples from file by default std::string default_signal_file = "flexiband_frame_samples.bin"; signal_file = configuration->property(role + ".signal_file", default_signal_file); @@ -86,13 +85,20 @@ FlexibandSignalSource::FlexibandSignalSource(ConfigurationInterface* configurati LOG(WARNING) << item_type_ << " unrecognized item type for flexiband_source_"; item_size_ = sizeof(gr_complex); } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - FlexibandSignalSource::~FlexibandSignalSource() -{} - +{ +} void FlexibandSignalSource::connect(gr::top_block_sptr top_block) @@ -111,7 +117,6 @@ void FlexibandSignalSource::connect(gr::top_block_sptr top_block) } - void FlexibandSignalSource::disconnect(gr::top_block_sptr top_block) { for (int n = 0; n < (RF_channels_ * 2); n++) @@ -144,4 +149,3 @@ gr::basic_block_sptr FlexibandSignalSource::get_right_block(int RF_channel) { return float_to_complex_.at(RF_channel); } - diff --git a/src/algorithms/signal_source/adapters/flexiband_signal_source.h b/src/algorithms/signal_source/adapters/flexiband_signal_source.h index a621d8ea3..54e7eeff4 100644 --- a/src/algorithms/signal_source/adapters/flexiband_signal_source.h +++ b/src/algorithms/signal_source/adapters/flexiband_signal_source.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,14 +33,14 @@ #ifndef FLEXIBAND_SIGNAL_SOURCE_H_ #define FLEXIBAND_SIGNAL_SOURCE_H_ -#include +#include "gnss_block_interface.h" +#include +#include +#include #include #include -#include -#include -#include +#include #include -#include "gnss_block_interface.h" class ConfigurationInterface; @@ -49,15 +49,16 @@ class ConfigurationInterface; * \brief This class configures and reads samples from Teleorbit Flexiband front-end. * This software requires a Flexiband GNU Radio driver installed (not included with GNSS-SDR). */ -class FlexibandSignalSource: public GNSSBlockInterface +class FlexibandSignalSource : public GNSSBlockInterface { public: FlexibandSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + std::string role, unsigned int in_stream, + unsigned int out_stream, gr::msg_queue::sptr queue); virtual ~FlexibandSignalSource(); - std::string role() + + inline std::string role() override { return role_; } @@ -65,19 +66,21 @@ public: /*! * \brief Returns "Flexiband_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "Flexiband_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - gr::basic_block_sptr get_right_block(int RF_channel); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; private: std::string role_; diff --git a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc new file mode 100644 index 000000000..8f3f5fa82 --- /dev/null +++ b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc @@ -0,0 +1,256 @@ +/*! + * \file fmcomms2_signal_source.cc + * \brief Signal source for SDR hardware from Analog Devices based on + * fmcomms2 evaluation board. + * \author Rodrigo Muñoz, 2017, rmunozl(at)inacap.cl + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fmcomms2_signal_source.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "ad9361_manager.h" +#include "configuration_interface.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include + + +using google::LogMessage; + +Fmcomms2SignalSource::Fmcomms2SignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/signal_source.dat"; + uri_ = configuration->property(role + ".device_address", std::string("192.168.2.1")); + freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2600000); + bandwidth_ = configuration->property(role + ".bandwidth", 2000000); + rx1_en_ = configuration->property(role + ".rx1_enable", true); + rx2_en_ = configuration->property(role + ".rx2_enable", false); + buffer_size_ = configuration->property(role + ".buffer_size", 0xA0000); + quadrature_ = configuration->property(role + ".quadrature", true); + rf_dc_ = configuration->property(role + ".rf_dc", true); + bb_dc_ = configuration->property(role + ".bb_dc", true); + RF_channels_ = configuration->property(role + ".RF_channels", 1); + gain_mode_rx1_ = configuration->property(role + ".gain_mode_rx1", std::string("manual")); + gain_mode_rx2_ = configuration->property(role + ".gain_mode_rx2", std::string("manual")); + rf_gain_rx1_ = configuration->property(role + ".gain_rx1", 64.0); + rf_gain_rx2_ = configuration->property(role + ".gain_rx2", 64.0); + rf_port_select_ = configuration->property(role + ".rf_port_select", std::string("A_BALANCED")); + filter_file_ = configuration->property(role + ".filter_file", std::string("")); + filter_auto_ = configuration->property(role + ".filter_auto", true); + item_type_ = configuration->property(role + ".item_type", default_item_type); + samples_ = configuration->property(role + ".samples", 0); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + // AD9361 Local Oscillator generation for dual band operation + enable_dds_lo_ = configuration->property(role + ".enable_dds_lo", false); + freq_rf_tx_hz_ = configuration->property(role + ".freq_rf_tx_hz", GPS_L1_FREQ_HZ - GPS_L2_FREQ_HZ - 1000); + freq_dds_tx_hz_ = configuration->property(role + ".freq_dds_tx_hz", 1000); + scale_dds_dbfs_ = configuration->property(role + ".scale_dds_dbfs", 0.0); + phase_dds_deg_ = configuration->property(role + ".phase_dds_deg", 0.0); + tx_attenuation_db_ = configuration->property(role + ".tx_attenuation_db", 0.0); + + item_size_ = sizeof(gr_complex); + + std::cout << "device address: " << uri_ << std::endl; + std::cout << "LO frequency : " << freq_ << " Hz" << std::endl; + std::cout << "sample rate: " << sample_rate_ << " Hz" << std::endl; + + if (item_type_ == "gr_complex") + { + if (RF_channels_ == 1) + { + if (rx1_en_ and rx2_en_) + { + LOG(FATAL) << "Configuration error: both rx1 and rx2 are enabled but RF_channels=1 !"; + } + else + { + fmcomms2_source_f32c_ = gr::iio::fmcomms2_source_f32c::make( + uri_.c_str(), freq_, sample_rate_, + bandwidth_, + rx1_en_, rx2_en_, + buffer_size_, quadrature_, rf_dc_, + bb_dc_, gain_mode_rx1_.c_str(), rf_gain_rx1_, + gain_mode_rx2_.c_str(), rf_gain_rx2_, + rf_port_select_.c_str(), filter_file_.c_str(), + filter_auto_); + + // configure LO + if (enable_dds_lo_ == true) + { + std::cout << "Enabling Local Oscillator generator in FMCOMMS2\n"; + config_ad9361_lo_remote(uri_, + bandwidth_, + sample_rate_, + freq_rf_tx_hz_, + tx_attenuation_db_, + freq_dds_tx_hz_, + scale_dds_dbfs_); + } + } + } + else if (RF_channels_ == 2) + { + if (!(rx1_en_ and rx2_en_)) + { + LOG(FATAL) << "Configuration error: RF_channels=2 but are not enabled both receivers in FMCOMMS2 !"; + } + else + { + fmcomms2_source_f32c_ = gr::iio::fmcomms2_source_f32c::make( + uri_.c_str(), freq_, sample_rate_, + bandwidth_, + rx1_en_, rx2_en_, + buffer_size_, quadrature_, rf_dc_, + bb_dc_, gain_mode_rx1_.c_str(), rf_gain_rx1_, + gain_mode_rx2_.c_str(), rf_gain_rx2_, + rf_port_select_.c_str(), filter_file_.c_str(), + filter_auto_); + // configure LO + if (enable_dds_lo_ == true) + { + std::cout << "Enabling Local Oscillator generator in FMCOMMS2\n"; + config_ad9361_lo_remote(uri_, + bandwidth_, + sample_rate_, + freq_rf_tx_hz_, + tx_attenuation_db_, + freq_dds_tx_hz_, + scale_dds_dbfs_); + } + } + } + else + { + LOG(FATAL) << "Configuration error: Unsupported number of RF_channels !"; + } + } + else + { + LOG(FATAL) << "Configuration error: item type " << item_type_ << " not supported!"; + } + + if (samples_ != 0) + { + DLOG(INFO) << "Send STOP signal after " << samples_ << " samples"; + valve_ = gnss_sdr_make_valve(item_size_, samples_, queue_); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + } + + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } +} + + +Fmcomms2SignalSource::~Fmcomms2SignalSource() +{ + if (enable_dds_lo_ == true) + { + try + { + ad9361_disable_lo_remote(uri_); + } + catch (const std::exception& e) + { + LOG(WARNING) << "Exception thrown in Fmcomms2SignalSource destructor: " << e.what(); + } + } +} + + +void Fmcomms2SignalSource::connect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->connect(fmcomms2_source_f32c_, 0, valve_, 0); + DLOG(INFO) << "connected fmcomms2 source to valve"; + if (dump_) + { + top_block->connect(valve_, 0, file_sink_, 0); + DLOG(INFO) << "connected valve to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(fmcomms2_source_f32c_, 0, file_sink_, 0); + DLOG(INFO) << "connected fmcomms2 source to file sink"; + } + } +} + + +void Fmcomms2SignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->disconnect(fmcomms2_source_f32c_, 0, valve_, 0); + if (dump_) + { + top_block->disconnect(valve_, 0, file_sink_, 0); + } + } + else + { + if (dump_) + { + top_block->disconnect(fmcomms2_source_f32c_, 0, file_sink_, 0); + } + } +} + + +gr::basic_block_sptr Fmcomms2SignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return gr::basic_block_sptr(); +} + + +gr::basic_block_sptr Fmcomms2SignalSource::get_right_block() +{ + if (samples_ != 0) + { + return valve_; + } + else + { + return (fmcomms2_source_f32c_); + } +} diff --git a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h new file mode 100644 index 000000000..820ce1a14 --- /dev/null +++ b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h @@ -0,0 +1,124 @@ +/*! + * \file fmcomms2_signal_source.h + * \brief Interface to use SDR hardware based in FMCOMMS2 driver from analog + * devices, for example FMCOMMS4 and ADALM-PLUTO (PlutoSdr) + * \author Rodrigo Muñoz, 2017. rmunozl(at)inacap.cl + * + * This class represent a fmcomms2 signal source. It use the gr_iio block + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H_ +#define GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include + +class ConfigurationInterface; + +class Fmcomms2SignalSource : public GNSSBlockInterface +{ +public: + Fmcomms2SignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + virtual ~Fmcomms2SignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Fmcomms2_Signal_Source" + */ + inline std::string implementation() override + { + return "Fmcomms2_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + + // Front-end settings + std::string uri_; //device direction + unsigned long freq_; //frequency of local oscilator + unsigned long sample_rate_; + unsigned long bandwidth_; + unsigned long buffer_size_; //reception buffer + bool rx1_en_; + bool rx2_en_; + bool quadrature_; + bool rf_dc_; + bool bb_dc_; + int RF_channels_; + std::string gain_mode_rx1_; + std::string gain_mode_rx2_; + double rf_gain_rx1_; + double rf_gain_rx2_; + std::string rf_port_select_; + std::string filter_file_; + bool filter_auto_; + + //DDS configuration for LO generation for external mixer + bool enable_dds_lo_; + unsigned long freq_rf_tx_hz_; + unsigned long freq_dds_tx_hz_; + double scale_dds_dbfs_; + double phase_dds_deg_; + double tx_attenuation_db_; + + unsigned int in_stream_; + unsigned int out_stream_; + + std::string item_type_; + size_t item_size_; + long samples_; + bool dump_; + std::string dump_filename_; + + gr::iio::fmcomms2_source_f32c::sptr fmcomms2_source_f32c_; + + boost::shared_ptr valve_; + gr::blocks::file_sink::sptr file_sink_; + boost::shared_ptr queue_; +}; + +#endif /*GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/gen_signal_source.cc b/src/algorithms/signal_source/adapters/gen_signal_source.cc index bede41061..69c1151c1 100644 --- a/src/algorithms/signal_source/adapters/gen_signal_source.cc +++ b/src/algorithms/signal_source/adapters/gen_signal_source.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,29 +25,28 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gen_signal_source.h" -#include -#include #include #include +#include #include #include -#include +#include +#include using google::LogMessage; // Constructor GenSignalSource::GenSignalSource(GNSSBlockInterface *signal_generator, GNSSBlockInterface *filter, - std::string role, boost::shared_ptr queue) : - signal_generator_(signal_generator), - filter_(filter), - role_(role), - queue_(queue) + std::string role, boost::shared_ptr queue) : signal_generator_(signal_generator), + filter_(filter), + role_(std::move(role)), + queue_(std::move(queue)) { connected_ = false; } @@ -73,7 +72,7 @@ void GenSignalSource::connect(gr::top_block_sptr top_block) filter_->connect(top_block); top_block->connect(signal_generator_->get_right_block(), 0, - filter_->get_left_block(), 0); + filter_->get_left_block(), 0); DLOG(INFO) << "signal_generator -> filter"; @@ -90,7 +89,7 @@ void GenSignalSource::disconnect(gr::top_block_sptr top_block) } top_block->disconnect(signal_generator_->get_right_block(), 0, - filter_->get_left_block(), 0); + filter_->get_left_block(), 0); signal_generator_->disconnect(top_block); filter_->disconnect(top_block); @@ -109,4 +108,3 @@ gr::basic_block_sptr GenSignalSource::get_right_block() { return filter_->get_right_block(); } - diff --git a/src/algorithms/signal_source/adapters/gen_signal_source.h b/src/algorithms/signal_source/adapters/gen_signal_source.h index b607f0320..49fb25293 100644 --- a/src/algorithms/signal_source/adapters/gen_signal_source.h +++ b/src/algorithms/signal_source/adapters/gen_signal_source.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,37 +33,37 @@ #ifndef GNSS_SDR_GEN_SIGNAL_SOURCE_H_ #define GNSS_SDR_GEN_SIGNAL_SOURCE_H_ -#include -#include -#include "gnss_block_interface.h" +#include "gnss_block_interface.h" +#include +#include /*! * \brief This class wraps blocks that generates synthesized GNSS signal and * filters the signal. */ -class GenSignalSource: public GNSSBlockInterface +class GenSignalSource : public GNSSBlockInterface { public: //! Constructor GenSignalSource(GNSSBlockInterface *signal_generator, GNSSBlockInterface *filter, - std::string role, boost::shared_ptr queue); + std::string role, boost::shared_ptr queue); //! Virtual destructor virtual ~GenSignalSource(); - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; - std::string role(){ return role_; } + inline std::string role() override { return role_; } //! Returns "Signal Source" - std::string implementation(){ return "Signal Source"; } - size_t item_size(){ return 0; } + inline std::string implementation() override { return "Signal Source"; } + inline size_t item_size() override { return 0; } - GNSSBlockInterface *signal_generator(){ return signal_generator_; } + inline GNSSBlockInterface *signal_generator() const { return signal_generator_; } private: GNSSBlockInterface *signal_generator_; diff --git a/src/algorithms/signal_source/adapters/gn3s_signal_source.cc b/src/algorithms/signal_source/adapters/gn3s_signal_source.cc index f3f7aa8cb..ebf984c18 100644 --- a/src/algorithms/signal_source/adapters/gn3s_signal_source.cc +++ b/src/algorithms/signal_source/adapters/gn3s_signal_source.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,25 +23,23 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gn3s_signal_source.h" +#include "configuration_interface.h" +#include #include #include -#include -#include #include -#include "configuration_interface.h" using google::LogMessage; Gn3sSignalSource::Gn3sSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { std::string default_item_type = "short"; std::string default_dump_file = "./data/gn3s_source.dat"; @@ -55,7 +53,6 @@ Gn3sSignalSource::Gn3sSignalSource(ConfigurationInterface* configuration, gn3s_source_ = gn3s_make_source_cc(); DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "gn3s_source(" << gn3s_source_->unique_id() << ")"; - } // else if (item_type_.compare("short") == 0) // { @@ -66,7 +63,7 @@ Gn3sSignalSource::Gn3sSignalSource(ConfigurationInterface* configuration, else { LOG(WARNING) << item_type_ - << " unrecognized item type for resampler"; + << " unrecognized item type for resampler"; item_size_ = sizeof(short); } if (dump_) @@ -81,10 +78,9 @@ Gn3sSignalSource::Gn3sSignalSource(ConfigurationInterface* configuration, } - Gn3sSignalSource::~Gn3sSignalSource() -{} - +{ +} void Gn3sSignalSource::connect(gr::top_block_sptr top_block) @@ -101,7 +97,6 @@ void Gn3sSignalSource::connect(gr::top_block_sptr top_block) } - void Gn3sSignalSource::disconnect(gr::top_block_sptr top_block) { if (dump_) diff --git a/src/algorithms/signal_source/adapters/gn3s_signal_source.h b/src/algorithms/signal_source/adapters/gn3s_signal_source.h index c8a566e7b..8fb7637f5 100644 --- a/src/algorithms/signal_source/adapters/gn3s_signal_source.h +++ b/src/algorithms/signal_source/adapters/gn3s_signal_source.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,20 +23,20 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GN3S_SIGNAL_SOURCE_H_ -#define GN3S_SIGNAL_SOURCE_H_ +#ifndef GNSS_SDR_GN3S_SIGNAL_SOURCE_H_ +#define GNSS_SDR_GN3S_SIGNAL_SOURCE_H_ -#include +#include "gnss_block_interface.h" +#include #include #include -#include -#include "gnss_block_interface.h" +#include class ConfigurationInterface; @@ -44,15 +44,16 @@ class ConfigurationInterface; /*! * \brief This class reads samples from a GN3S USB dongle, a RF front-end signal sampler */ -class Gn3sSignalSource: public GNSSBlockInterface +class Gn3sSignalSource : public GNSSBlockInterface { public: Gn3sSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + std::string role, unsigned int in_stream, + unsigned int out_stream, gr::msg_queue::sptr queue); virtual ~Gn3sSignalSource(); - std::string role() + + inline std::string role() override { return role_; } @@ -60,18 +61,20 @@ public: /*! * \brief Returns "Gn3sSignalSource". */ - std::string implementation() + inline std::string implementation() override { return "Gn3sSignalSource"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string role_; @@ -87,4 +90,4 @@ private: boost::shared_ptr queue_; }; -#endif /*GN3S_SIGNAL_SOURCE_H_*/ +#endif /*GNSS_SDR_GN3S_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/labsat_signal_source.cc b/src/algorithms/signal_source/adapters/labsat_signal_source.cc new file mode 100644 index 000000000..cf1278d9d --- /dev/null +++ b/src/algorithms/signal_source/adapters/labsat_signal_source.cc @@ -0,0 +1,124 @@ +/*! + * \file labsat_signal_source.cc + * \brief Labsat 2 and 3 front-end signal sampler driver + * \author Javier Arribas, jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "labsat_signal_source.h" +#include "configuration_interface.h" +#include "labsat23_source.h" +#include +#include +#include + + +using google::LogMessage; + +LabsatSignalSource::LabsatSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/source.bin"; + item_type_ = configuration->property(role + ".item_type", default_item_type); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + int channel_selector = configuration->property(role + ".selected_channel", 1); + std::string default_filename = "./example_capture.LS3"; + + samples_ = configuration->property(role + ".samples", 0); + filename_ = configuration->property(role + ".filename", default_filename); + + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + labsat23_source_ = labsat23_make_source(filename_.c_str(), channel_selector); + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "labsat23_source_(" << labsat23_source_->unique_id() << ")"; + } + else + { + LOG(WARNING) << item_type_ << " unrecognized item type for LabSat source"; + item_size_ = sizeof(int16_t); + } + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + } + if (dump_) + { + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +LabsatSignalSource::~LabsatSignalSource() = default; + + +void LabsatSignalSource::connect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->connect(labsat23_source_, 0, file_sink_, 0); + DLOG(INFO) << "connected labsat23_source_ to file sink"; + } + else + { + DLOG(INFO) << "nothing to connect internally"; + } +} + + +void LabsatSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (dump_) + { + top_block->disconnect(labsat23_source_, 0, file_sink_, 0); + } +} + + +gr::basic_block_sptr LabsatSignalSource::get_left_block() +{ + LOG(WARNING) << "Left block of a signal source should not be retrieved"; + return gr::block_sptr(); +} + + +gr::basic_block_sptr LabsatSignalSource::get_right_block() +{ + return labsat23_source_; +} diff --git a/src/algorithms/signal_source/adapters/labsat_signal_source.h b/src/algorithms/signal_source/adapters/labsat_signal_source.h new file mode 100644 index 000000000..8a36f8ad5 --- /dev/null +++ b/src/algorithms/signal_source/adapters/labsat_signal_source.h @@ -0,0 +1,93 @@ +/*! + * \file labsat_signal_source.h + * \brief Labsat 2 and 3 front-end signal sampler driver + * \author Javier Arribas, jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_ +#define GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include +#include +#include +#include + +class ConfigurationInterface; + +/*! + * \brief This class reads samples stored by a LabSat 2 or LabSat 3 device + */ +class LabsatSignalSource : public GNSSBlockInterface +{ +public: + LabsatSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, gr::msg_queue::sptr queue); + + virtual ~LabsatSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Labsat_Signal_Source". + */ + inline std::string implementation() override + { + return "Labsat_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + unsigned int in_stream_; + unsigned int out_stream_; + std::string item_type_; + size_t item_size_; + long samples_; + std::string filename_; + bool dump_; + std::string dump_filename_; + gr::block_sptr labsat23_source_; + gr::blocks::file_sink::sptr file_sink_; + boost::shared_ptr queue_; +}; + +#endif /*GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc b/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc index 86b81b65a..60566ed5e 100644 --- a/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,33 +25,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "nsr_file_signal_source.h" -#include +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include #include #include #include #include -#include -#include -#include "gnss_sdr_valve.h" -#include "configuration_interface.h" +#include using google::LogMessage; -DEFINE_string(nsr_signal_source, "-", - "If defined, path to the file containing the NSR (byte to 2-bit packed) signal samples (overrides the configuration file)"); - NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : - role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) + const std::string& role, unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "byte"; @@ -62,7 +58,8 @@ NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, filename_ = configuration->property(role + ".filename", default_filename); // override value with commandline flag, if present - if (FLAGS_nsr_signal_source.compare("-") != 0) filename_= FLAGS_nsr_signal_source; + if (FLAGS_signal_source != "-") filename_ = FLAGS_signal_source; + if (FLAGS_s != "-") filename_ = FLAGS_s; item_type_ = configuration->property(role + ".item_type", default_item_type); repeat_ = configuration->property(role + ".repeat", false); @@ -70,60 +67,59 @@ NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); - if (item_type_.compare("byte") == 0) + if (item_type_ == "byte") { item_size_ = sizeof(char); } else { - LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; + LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; item_size_ = sizeof(char); } try - { + { file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); unpack_byte_ = make_unpack_byte_2bit_samples(); - - } - catch (const std::exception &e) - { + } + catch (const std::exception& e) + { std::cerr - << "The receiver was configured to work with a file signal source " - << std::endl - << "but the specified file is unreachable by GNSS-SDR." - << std::endl - << "Please modify your configuration file" - << std::endl - << "and point SignalSource.filename to a valid raw data file. Then:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl - << "Examples of configuration files available at:" - << std::endl - << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" - << std::endl; + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; LOG(WARNING) << "file_signal_source: Unable to open the samples file " << filename_.c_str() << ", exiting the program."; throw(e); - } + } DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; - if (samples_ == 0) // read all file + if (samples_ == 0) // read all file { /*! * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. * A possible solution is to compute the file length in samples using file size, excluding the last 2 milliseconds, and enable always the * valve block */ - std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream::pos_type size; if (file.is_open()) { size = file.tellg(); - LOG(INFO) << "Total samples in the file= " << floor((double)size / (double)item_size()); + LOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size())); } else { @@ -132,20 +128,20 @@ NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, } std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(16); - std::cout << "Processing file " << filename_ << ", which contains " << (double)size << " [bytes]" << std::endl; - std::cout.precision (ss); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision(ss); if (size > 0) { - int sample_packet_factor = 4; // 1 byte -> 4 samples - samples_ = floor((double)size / (double)item_size())*sample_packet_factor; - samples_ = samples_- ceil(0.002 * (double)sampling_frequency_); //process all the samples available in the file excluding the last 2 ms + int sample_packet_factor = 4; // 1 byte -> 4 samples + samples_ = floor(static_cast(size) / static_cast(item_size())) * sample_packet_factor; + samples_ = samples_ - ceil(0.002 * static_cast(sampling_frequency_)); //process all the samples available in the file excluding the last 2 ms } } CHECK(samples_ > 0) << "File does not contain enough samples to process."; double signal_duration_s; - signal_duration_s = (double)samples_ * ( 1 /(double)sampling_frequency_); + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; @@ -171,15 +167,18 @@ NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, DLOG(INFO) << "Repeat " << repeat_; DLOG(INFO) << "Dump " << dump_; DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - - -NsrFileSignalSource::~NsrFileSignalSource() -{} - - +NsrFileSignalSource::~NsrFileSignalSource() = default; void NsrFileSignalSource::connect(gr::top_block_sptr top_block) @@ -189,7 +188,7 @@ void NsrFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; top_block->connect(throttle_, 0, valve_, 0); DLOG(INFO) << "connected throttle to valve"; @@ -202,7 +201,7 @@ void NsrFileSignalSource::connect(gr::top_block_sptr top_block) else { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,valve_,0); + top_block->connect(unpack_byte_, 0, valve_, 0); DLOG(INFO) << "connected file source to valve"; if (dump_) { @@ -216,7 +215,7 @@ void NsrFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; if (dump_) { @@ -237,10 +236,6 @@ void NsrFileSignalSource::connect(gr::top_block_sptr top_block) } - - - - void NsrFileSignalSource::disconnect(gr::top_block_sptr top_block) { if (samples_ > 0) @@ -249,7 +244,7 @@ void NsrFileSignalSource::disconnect(gr::top_block_sptr top_block) { top_block->disconnect(file_source_, 0, unpack_byte_, 0); DLOG(INFO) << "disconnected file source to unpack_byte_"; - top_block->connect(unpack_byte_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, throttle_, 0); DLOG(INFO) << "disconnected unpack_byte_ to throttle_"; top_block->disconnect(throttle_, 0, valve_, 0); DLOG(INFO) << "disconnected throttle to valve"; @@ -300,9 +295,6 @@ void NsrFileSignalSource::disconnect(gr::top_block_sptr top_block) } - - - gr::basic_block_sptr NsrFileSignalSource::get_left_block() { LOG(WARNING) << "Left block of a signal source should not be retrieved"; @@ -311,24 +303,15 @@ gr::basic_block_sptr NsrFileSignalSource::get_left_block() } - - - gr::basic_block_sptr NsrFileSignalSource::get_right_block() { if (samples_ > 0) { return valve_; } - else + if (enable_throttle_control_ == true) { - if (enable_throttle_control_ == true) - { - return throttle_; - } - else - { - return unpack_byte_; - } + return throttle_; } + return unpack_byte_; } diff --git a/src/algorithms/signal_source/adapters/nsr_file_signal_source.h b/src/algorithms/signal_source/adapters/nsr_file_signal_source.h index fabaa10f4..89bc32ac0 100644 --- a/src/algorithms/signal_source/adapters/nsr_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/nsr_file_signal_source.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,15 +35,14 @@ #ifndef GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H_ -#include -#include +#include "gnss_block_interface.h" +#include "unpack_byte_2bit_samples.h" #include +#include #include #include #include -#include "gnss_block_interface.h" -#include "unpack_byte_2bit_samples.h" - +#include class ConfigurationInterface; @@ -51,15 +50,15 @@ class ConfigurationInterface; * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class NsrFileSignalSource: public GNSSBlockInterface +class NsrFileSignalSource : public GNSSBlockInterface { public: - NsrFileSignalSource(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + NsrFileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); virtual ~NsrFileSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -67,35 +66,42 @@ public: /*! * \brief Returns "Nsr_File_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "Nsr_File_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string filename() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const { return filename_; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - bool repeat() + + inline bool repeat() const { return repeat_; } - long sampling_frequency() + + inline long sampling_frequency() const { return sampling_frequency_; } - long samples() + + inline long samples() const { return samples_; } @@ -115,7 +121,7 @@ private: unpack_byte_2bit_samples_sptr unpack_byte_; boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; - gr::blocks::throttle::sptr throttle_; + gr::blocks::throttle::sptr throttle_; boost::shared_ptr queue_; size_t item_size_; // Throttle control diff --git a/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc b/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc index 4365b1bbc..80f52a290 100644 --- a/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc +++ b/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,29 +24,28 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "osmosdr_signal_source.h" -#include +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_valve.h" #include #include #include -#include "configuration_interface.h" -#include "gnss_sdr_valve.h" -#include "GPS_L1_CA.h" +#include +#include using google::LogMessage; OsmosdrSignalSource::OsmosdrSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), - queue_(queue) + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { // DUMP PARAMETERS std::string empty = ""; @@ -55,53 +54,50 @@ OsmosdrSignalSource::OsmosdrSignalSource(ConfigurationInterface* configuration, samples_ = configuration->property(role + ".samples", 0); dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", - default_dump_file); + default_dump_file); // OSMOSDR Driver parameters AGC_enabled_ = configuration->property(role + ".AGC_enabled", true); freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); - gain_ = configuration->property(role + ".gain", (double)40.0); - rf_gain_ = configuration->property(role + ".rf_gain", (double)40.0); - if_gain_ = configuration->property(role + ".if_gain", (double)40.0); - sample_rate_ = configuration->property(role + ".sampling_frequency", (double)2.0e6); + gain_ = configuration->property(role + ".gain", 40.0); + rf_gain_ = configuration->property(role + ".rf_gain", 40.0); + if_gain_ = configuration->property(role + ".if_gain", 40.0); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2.0e6); item_type_ = configuration->property(role + ".item_type", default_item_type); - osmosdr_args_ = configuration->property(role + ".osmosdr_args", std::string( )); + osmosdr_args_ = configuration->property(role + ".osmosdr_args", std::string()); + antenna_ = configuration->property(role + ".antenna", empty); - if (item_type_.compare("short") == 0) + if (item_type_ == "short") { - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } - else if (item_type_.compare("gr_complex") == 0) + else if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); // 1. Make the driver instance - try - { - if (!osmosdr_args_.empty()) - { - std::cout << "OsmoSdr arguments: " << osmosdr_args_ << std::endl; - LOG(INFO) << "OsmoSdr arguments: " << osmosdr_args_; - } - osmosdr_source_ = osmosdr::source::make(osmosdr_args_); - } - catch( boost::exception & e ) - { - DLOG(FATAL) << "Boost exception: " << boost::diagnostic_information(e); - } + OsmosdrSignalSource::driver_instance(); + + // For LimeSDR: Set RX antenna + if (!antenna_.empty()) + { + osmosdr_source_->set_antenna(antenna_, 0); + std::cout << boost::format("Set RX Antenna : %s") % (osmosdr_source_->get_antenna(0)) << std::endl; + LOG(INFO) << boost::format("Set RX Antenna : %s") % (osmosdr_source_->get_antenna(0)); + } // 2 set sampling rate osmosdr_source_->set_sample_rate(sample_rate_); - std::cout << boost::format("Actual RX Rate: %f [SPS]...") % (osmosdr_source_->get_sample_rate()) << std::endl ; + std::cout << boost::format("Actual RX Rate: %f [SPS]...") % (osmosdr_source_->get_sample_rate()) << std::endl; LOG(INFO) << boost::format("Actual RX Rate: %f [SPS]...") % (osmosdr_source_->get_sample_rate()); // 3. set rx frequency osmosdr_source_->set_center_freq(freq_); - std::cout << boost::format("Actual RX Freq: %f [Hz]...") % (osmosdr_source_->get_center_freq()) << std::endl ; + std::cout << boost::format("Actual RX Freq: %f [Hz]...") % (osmosdr_source_->get_center_freq()) << std::endl; LOG(INFO) << boost::format("Actual RX Freq: %f [Hz]...") % (osmosdr_source_->get_center_freq()); // TODO: Assign the remnant IF from the PLL tune error - std::cout << boost::format("PLL Frequency tune error %f [Hz]...") % (osmosdr_source_->get_center_freq() - freq_) ; - LOG(INFO) << boost::format("PLL Frequency tune error %f [Hz]...") % (osmosdr_source_->get_center_freq() - freq_) ; + std::cout << boost::format("PLL Frequency tune error %f [Hz]...") % (osmosdr_source_->get_center_freq() - freq_) << std::endl; + LOG(INFO) << boost::format("PLL Frequency tune error %f [Hz]...") % (osmosdr_source_->get_center_freq() - freq_); // 4. set rx gain if (this->AGC_enabled_ == true) @@ -116,14 +112,26 @@ OsmosdrSignalSource::OsmosdrSignalSource(ConfigurationInterface* configuration, osmosdr_source_->set_gain(gain_, 0); osmosdr_source_->set_if_gain(rf_gain_, 0); osmosdr_source_->set_bb_gain(if_gain_, 0); - std::cout << boost::format("Actual RX Gain: %f dB...") % osmosdr_source_->get_gain() << std::endl; - LOG(INFO) << boost::format("Actual RX Gain: %f dB...") % osmosdr_source_->get_gain(); + if (!osmosdr_args_.empty() && (osmosdr_args_.find("bladerf") != std::string::npos)) + { + std::cout << boost::format("Actual LNA Gain: %f dB...") % osmosdr_source_->get_gain("LNA", 0) << std::endl; + std::cout << boost::format("Actual VGA1 Gain: %f dB...") % osmosdr_source_->get_gain("VGA1", 0) << std::endl; + std::cout << boost::format("Actual VGA2 Gain: %f dB...") % osmosdr_source_->get_gain("VGA2", 0) << std::endl; + } + else + { + std::cout << boost::format("Actual RX Gain: %f dB...") % osmosdr_source_->get_gain() << std::endl; + LOG(INFO) << boost::format("Actual RX Gain: %f dB...") % osmosdr_source_->get_gain(); + } } + + // Get actual bandwidth + std::cout << boost::format("Actual Bandwidth: %f [Hz]...") % osmosdr_source_->get_bandwidth(0) << std::endl; } else { LOG(WARNING) << item_type_ << " unrecognized item type. Using short."; - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } if (samples_ != 0) @@ -139,13 +147,37 @@ OsmosdrSignalSource::OsmosdrSignalSource(ConfigurationInterface* configuration, file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } +OsmosdrSignalSource::~OsmosdrSignalSource() = default; -OsmosdrSignalSource::~OsmosdrSignalSource() -{} +void OsmosdrSignalSource::driver_instance() +{ + try + { + if (!osmosdr_args_.empty()) + { + std::cout << "OsmoSdr arguments: " << osmosdr_args_ << std::endl; + LOG(INFO) << "OsmoSdr arguments: " << osmosdr_args_; + } + osmosdr_source_ = osmosdr::source::make(osmosdr_args_); + } + catch (const boost::exception& e) + { + LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); + throw std::invalid_argument("Wrong OsmoSdr arguments"); + } +} void OsmosdrSignalSource::connect(gr::top_block_sptr top_block) @@ -171,7 +203,6 @@ void OsmosdrSignalSource::connect(gr::top_block_sptr top_block) } - void OsmosdrSignalSource::disconnect(gr::top_block_sptr top_block) { if (samples_ != 0) @@ -192,7 +223,6 @@ void OsmosdrSignalSource::disconnect(gr::top_block_sptr top_block) } - gr::basic_block_sptr OsmosdrSignalSource::get_left_block() { LOG(WARNING) << "Trying to get signal source left block."; @@ -200,7 +230,6 @@ gr::basic_block_sptr OsmosdrSignalSource::get_left_block() } - gr::basic_block_sptr OsmosdrSignalSource::get_right_block() { if (samples_ != 0) diff --git a/src/algorithms/signal_source/adapters/osmosdr_signal_source.h b/src/algorithms/signal_source/adapters/osmosdr_signal_source.h index 886d713d7..15f38b2a3 100644 --- a/src/algorithms/signal_source/adapters/osmosdr_signal_source.h +++ b/src/algorithms/signal_source/adapters/osmosdr_signal_source.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,12 +33,14 @@ #ifndef GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H_ #define GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H_ -#include -#include -#include -#include -#include #include "gnss_block_interface.h" +#include +#include +#include +#include +#include +#include +#include class ConfigurationInterface; @@ -47,16 +49,16 @@ class ConfigurationInterface; * HackRF or Realtek's RTL2832U-based USB dongle DVB-T receivers * (see http://sdr.osmocom.org/trac/wiki/rtl-sdr) */ -class OsmosdrSignalSource: public GNSSBlockInterface +class OsmosdrSignalSource : public GNSSBlockInterface { public: OsmosdrSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); virtual ~OsmosdrSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -64,21 +66,23 @@ public: /*! * \brief Returns "Osmosdr_Signal_Source" */ - std::string implementation() + inline std::string implementation() override { return "Osmosdr_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: + void driver_instance(); std::string role_; // Front-end settings @@ -95,13 +99,15 @@ private: std::string item_type_; size_t item_size_; - long samples_; + int64_t samples_; bool dump_; std::string dump_filename_; osmosdr::source::sptr osmosdr_source_; std::string osmosdr_args_; + std::string antenna_; + boost::shared_ptr valve_; gr::blocks::file_sink::sptr file_sink_; boost::shared_ptr queue_; diff --git a/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc b/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc new file mode 100644 index 000000000..5c4c71dd9 --- /dev/null +++ b/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc @@ -0,0 +1,172 @@ +/*! + * \file plutosdr_signal_source.cc + * \brief Signal source for PlutoSDR + * \author Rodrigo Muñoz, 2017, rmunozl(at)inacap.cl + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "plutosdr_signal_source.h" +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_valve.h" +#include +#include +#include + + +using google::LogMessage; + + +PlutosdrSignalSource::PlutosdrSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/signal_source.dat"; + uri_ = configuration->property(role + ".device_address", std::string("192.168.2.1")); + freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); + sample_rate_ = configuration->property(role + ".sampling_frequency", 3000000); + bandwidth_ = configuration->property(role + ".bandwidth", 2000000); + buffer_size_ = configuration->property(role + ".buffer_size", 0xA0000); + quadrature_ = configuration->property(role + ".quadrature", true); + rf_dc_ = configuration->property(role + ".rf_dc", true); + bb_dc_ = configuration->property(role + ".bb_dc", true); + gain_mode_ = configuration->property(role + ".gain_mode", std::string("manual")); + rf_gain_ = configuration->property(role + ".gain", 50.0); + filter_file_ = configuration->property(role + ".filter_file", std::string("")); + filter_auto_ = configuration->property(role + ".filter_auto", true); + + item_type_ = configuration->property(role + ".item_type", default_item_type); + samples_ = configuration->property(role + ".samples", 0); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + if (item_type_ != "gr_complex") + { + std::cout << "Configuration error: item_type must be gr_complex" << std::endl; + LOG(FATAL) << "Configuration error: item_type must be gr_complex!"; + } + + item_size_ = sizeof(gr_complex); + + std::cout << "device address: " << uri_ << std::endl; + std::cout << "frequency : " << freq_ << " Hz" << std::endl; + std::cout << "sample rate: " << sample_rate_ << " Hz" << std::endl; + std::cout << "gain mode: " << gain_mode_ << std::endl; + std::cout << "item type: " << item_type_ << std::endl; + + plutosdr_source_ = gr::iio::pluto_source::make(uri_, freq_, sample_rate_, + bandwidth_, buffer_size_, quadrature_, rf_dc_, bb_dc_, + gain_mode_.c_str(), rf_gain_, filter_file_.c_str(), filter_auto_); + + if (samples_ != 0) + { + DLOG(INFO) << "Send STOP signal after " << samples_ << " samples"; + valve_ = gnss_sdr_make_valve(item_size_, samples_, queue_); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + } + + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +PlutosdrSignalSource::~PlutosdrSignalSource() = default; + + +void PlutosdrSignalSource::connect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->connect(plutosdr_source_, 0, valve_, 0); + DLOG(INFO) << "connected plutosdr source to valve"; + if (dump_) + { + top_block->connect(valve_, 0, file_sink_, 0); + DLOG(INFO) << "connected valve to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(plutosdr_source_, 0, file_sink_, 0); + DLOG(INFO) << "connected plutosdr source to file sink"; + } + } +} + + +void PlutosdrSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->disconnect(plutosdr_source_, 0, valve_, 0); + if (dump_) + { + top_block->disconnect(valve_, 0, file_sink_, 0); + } + } + else + { + if (dump_) + { + top_block->disconnect(plutosdr_source_, 0, file_sink_, 0); + } + } +} + + +gr::basic_block_sptr PlutosdrSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return gr::basic_block_sptr(); +} + + +gr::basic_block_sptr PlutosdrSignalSource::get_right_block() +{ + if (samples_ != 0) + { + return valve_; + } + else + { + return plutosdr_source_; + } +} diff --git a/src/algorithms/signal_source/adapters/plutosdr_signal_source.h b/src/algorithms/signal_source/adapters/plutosdr_signal_source.h new file mode 100644 index 000000000..4cedb3787 --- /dev/null +++ b/src/algorithms/signal_source/adapters/plutosdr_signal_source.h @@ -0,0 +1,111 @@ +/*! + * \file plutosdr_signal_source.h + * \brief Signal source for PlutoSDR + * \author Rodrigo Muñoz, 2017, rmunozl(at)inacap.cl + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H_ +#define GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + */ +class PlutosdrSignalSource : public GNSSBlockInterface +{ +public: + PlutosdrSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + virtual ~PlutosdrSignalSource(); + + std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Plutosdr_Signal_Source" + */ + std::string implementation() override + { + return "Plutosdr_Signal_Source"; + } + size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + + // Front-end settings + std::string uri_; // device direction + unsigned long freq_; // frequency of local oscilator + unsigned long sample_rate_; + unsigned long bandwidth_; + unsigned long buffer_size_; // reception buffer + bool quadrature_; + bool rf_dc_; + bool bb_dc_; + std::string gain_mode_; + double rf_gain_; + std::string filter_file_; + bool filter_auto_; + + unsigned int in_stream_; + unsigned int out_stream_; + + std::string item_type_; + size_t item_size_; + long samples_; + bool dump_; + std::string dump_filename_; + + gr::iio::pluto_source::sptr plutosdr_source_; + + boost::shared_ptr valve_; + gr::blocks::file_sink::sptr file_sink_; + boost::shared_ptr queue_; +}; + +#endif /*GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/raw_array_signal_source.cc b/src/algorithms/signal_source/adapters/raw_array_signal_source.cc index d203901e8..b7f29a012 100644 --- a/src/algorithms/signal_source/adapters/raw_array_signal_source.cc +++ b/src/algorithms/signal_source/adapters/raw_array_signal_source.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,24 +23,23 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "raw_array_signal_source.h" +#include "configuration_interface.h" +#include #include #include -#include #include -#include "configuration_interface.h" using google::LogMessage; RawArraySignalSource::RawArraySignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/raw_array_source.dat"; @@ -70,10 +69,9 @@ RawArraySignalSource::RawArraySignalSource(ConfigurationInterface* configuration if (item_type_.compare("gr_complex") == 0) { item_size_ = sizeof(gr_complex); - raw_array_source_ = gr::dbfcttc::raw_array::make(eth_device_.c_str(),channels_,snapshots_per_frame_,inter_frame_delay_,sampling_freq_); + raw_array_source_ = gr::dbfcttc::raw_array::make(eth_device_.c_str(), channels_, snapshots_per_frame_, inter_frame_delay_, sampling_freq_); DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "raw_array_source(" << raw_array_source_->unique_id() << ")"; - } // else if (item_type_.compare("short") == 0) // { @@ -99,10 +97,9 @@ RawArraySignalSource::RawArraySignalSource(ConfigurationInterface* configuration } - RawArraySignalSource::~RawArraySignalSource() -{} - +{ +} void RawArraySignalSource::connect(gr::top_block_sptr top_block) @@ -120,7 +117,6 @@ void RawArraySignalSource::connect(gr::top_block_sptr top_block) } - void RawArraySignalSource::disconnect(gr::top_block_sptr top_block) { if (dump_) diff --git a/src/algorithms/signal_source/adapters/raw_array_signal_source.h b/src/algorithms/signal_source/adapters/raw_array_signal_source.h index 93501273f..9af4df30f 100644 --- a/src/algorithms/signal_source/adapters/raw_array_signal_source.h +++ b/src/algorithms/signal_source/adapters/raw_array_signal_source.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,27 +32,27 @@ #ifndef RAW_ARRAY_SIGNAL_SOURCE_H_ #define RAW_ARRAY_SIGNAL_SOURCE_H_ -#include +#include "gnss_block_interface.h" +#include #include #include -#include -#include "gnss_block_interface.h" - +#include class ConfigurationInterface; /*! * \brief This class reads samples from a GN3S USB dongle, a RF front-end signal sampler */ -class RawArraySignalSource: public GNSSBlockInterface +class RawArraySignalSource : public GNSSBlockInterface { public: RawArraySignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + std::string role, unsigned int in_stream, + unsigned int out_stream, gr::msg_queue::sptr queue); virtual ~RawArraySignalSource(); - std::string role() + + inline std::string role() override { return role_; } @@ -60,18 +60,20 @@ public: /*! * \brief Returns "RawArraySignalSource". */ - std::string implementation() + inline std::string implementation() override { return "Raw_Array_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: std::string role_; diff --git a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc index bfa5da504..5166840f5 100644 --- a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,27 +25,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "rtl_tcp_signal_source.h" -#include -#include -#include +#include "GPS_L1_CA.h" #include "configuration_interface.h" #include "gnss_sdr_valve.h" -#include "GPS_L1_CA.h" +#include +#include +#include +#include +#include + using google::LogMessage; RtlTcpSignalSource::RtlTcpSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), - queue_(queue) + const std::string& role, + unsigned int in_stream, + unsigned int out_stream, + boost::shared_ptr queue) : role_(std::move(role)), + in_stream_(in_stream), + out_stream_(out_stream), + queue_(queue) { // DUMP PARAMETERS std::string empty = ""; @@ -54,40 +60,31 @@ RtlTcpSignalSource::RtlTcpSignalSource(ConfigurationInterface* configuration, samples_ = configuration->property(role + ".samples", 0); dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", - default_dump_file); + default_dump_file); - // rtl_tcp PARAMTERS + // rtl_tcp PARAMETERS std::string default_address = "127.0.0.1"; - short default_port = 1234; + int16_t default_port = 1234; AGC_enabled_ = configuration->property(role + ".AGC_enabled", true); freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); - gain_ = configuration->property(role + ".gain", (double)40.0); - rf_gain_ = configuration->property(role + ".rf_gain", (double)40.0); - if_gain_ = configuration->property(role + ".if_gain", (double)40.0); - sample_rate_ = configuration->property(role + ".sampling_frequency", (double)2.0e6); + gain_ = configuration->property(role + ".gain", 40.0); + rf_gain_ = configuration->property(role + ".rf_gain", 40.0); + if_gain_ = configuration->property(role + ".if_gain", 40.0); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2.0e6); item_type_ = configuration->property(role + ".item_type", default_item_type); address_ = configuration->property(role + ".address", default_address); port_ = configuration->property(role + ".port", default_port); flip_iq_ = configuration->property(role + ".flip_iq", false); - if (item_type_.compare("short") == 0) + if (item_type_ == "short") { - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } - else if (item_type_.compare("gr_complex") == 0) + else if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); // 1. Make the gr block - try - { - std::cout << "Connecting to " << address_ << ":" << port_ << std::endl; - LOG (INFO) << "Connecting to " << address_ << ":" << port_; - signal_source_ = rtl_tcp_make_signal_source_c (address_, port_, flip_iq_); - } - catch( boost::exception & e ) - { - DLOG(FATAL) << "Boost exception: " << boost::diagnostic_information(e); - } + MakeBlock(); // 2 set sampling rate signal_source_->set_sample_rate(sample_rate_); @@ -122,7 +119,7 @@ RtlTcpSignalSource::RtlTcpSignalSource(ConfigurationInterface* configuration, else { LOG(WARNING) << item_type_ << " unrecognized item type. Using short."; - item_size_ = sizeof(short); + item_size_ = sizeof(int16_t); } if (samples_ != 0) @@ -138,26 +135,49 @@ RtlTcpSignalSource::RtlTcpSignalSource(ConfigurationInterface* configuration, file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -RtlTcpSignalSource::~RtlTcpSignalSource() -{} +RtlTcpSignalSource::~RtlTcpSignalSource() = default; + + +void RtlTcpSignalSource::MakeBlock() +{ + try + { + std::cout << "Connecting to " << address_ << ":" << port_ << std::endl; + LOG(INFO) << "Connecting to " << address_ << ":" << port_; + signal_source_ = rtl_tcp_make_signal_source_c(address_, port_, flip_iq_); + } + catch (const boost::exception& e) + { + LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); + throw std::runtime_error("Failure connecting to the device"); + } +} void RtlTcpSignalSource::connect(gr::top_block_sptr top_block) { - if ( samples_ ) + if (samples_) { - top_block->connect (signal_source_, 0, valve_, 0); + top_block->connect(signal_source_, 0, valve_, 0); DLOG(INFO) << "connected rtl tcp source to valve"; - if ( dump_ ) + if (dump_) { top_block->connect(valve_, 0, file_sink_, 0); DLOG(INFO) << "connected valve to file sink"; } } - else if ( dump_ ) + else if (dump_) { top_block->connect(signal_source_, 0, file_sink_, 0); DLOG(INFO) << "connected rtl tcp source to file sink"; @@ -167,15 +187,15 @@ void RtlTcpSignalSource::connect(gr::top_block_sptr top_block) void RtlTcpSignalSource::disconnect(gr::top_block_sptr top_block) { - if ( samples_ ) + if (samples_) { - top_block->disconnect (signal_source_, 0, valve_, 0); - if ( dump_ ) + top_block->disconnect(signal_source_, 0, valve_, 0); + if (dump_) { top_block->disconnect(valve_, 0, file_sink_, 0); } } - else if ( dump_ ) + else if (dump_) { top_block->disconnect(signal_source_, 0, file_sink_, 0); } diff --git a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h index 8635d0b0b..3a89bb088 100644 --- a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h +++ b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,14 +32,16 @@ #ifndef GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H #define GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H -#include -#include -#include -#include -#include -#include -#include "rtl_tcp_signal_source_c.h" #include "gnss_block_interface.h" +#include "rtl_tcp_signal_source_c.h" +#include +#include +#include +#include +#include +#include +#include + class ConfigurationInterface; @@ -48,16 +50,18 @@ class ConfigurationInterface; * I/Q samples over TCP. * (see http://sdr.osmocom.org/trac/wiki/rtl-sdr) */ -class RtlTcpSignalSource: public GNSSBlockInterface +class RtlTcpSignalSource : public GNSSBlockInterface { public: RtlTcpSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + const std::string& role, + unsigned int in_stream, + unsigned int out_stream, + boost::shared_ptr queue); virtual ~RtlTcpSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -65,21 +69,23 @@ public: /*! * \brief Returns "RtlTcp_Signal_Source" */ - std::string implementation() + inline std::string implementation() override { return "RtlTcp_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; private: + void MakeBlock(); std::string role_; // rtl_tcp settings diff --git a/src/algorithms/signal_source/adapters/spir_file_signal_source.cc b/src/algorithms/signal_source/adapters/spir_file_signal_source.cc index c8bb32ff8..d5692e434 100644 --- a/src/algorithms/signal_source/adapters/spir_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/spir_file_signal_source.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,33 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "spir_file_signal_source.h" -#include +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include #include #include #include #include -#include -#include -#include "gnss_sdr_valve.h" -#include "configuration_interface.h" +#include using google::LogMessage; -DEFINE_string(spir_signal_source, "-", - "If defined, path to the file containing the NSR (byte to 2-bit packed) signal samples (overrides the configuration file)"); - SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : - role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) + const std::string& role, unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "int"; @@ -61,7 +57,8 @@ SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration filename_ = configuration->property(role + ".filename", default_filename); // override value with commandline flag, if present - if (FLAGS_spir_signal_source.compare("-") != 0) filename_= FLAGS_spir_signal_source; + if (FLAGS_signal_source != "-") filename_ = FLAGS_signal_source; + if (FLAGS_s != "-") filename_ = FLAGS_s; item_type_ = configuration->property(role + ".item_type", default_item_type); repeat_ = configuration->property(role + ".repeat", false); @@ -69,60 +66,59 @@ SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); - if (item_type_.compare("int") == 0) + if (item_type_ == "int") { item_size_ = sizeof(int); } else { - LOG(WARNING) << item_type_ << " unrecognized item type. Using int."; + LOG(WARNING) << item_type_ << " unrecognized item type. Using int."; item_size_ = sizeof(int); } try - { + { file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); unpack_intspir_ = make_unpack_intspir_1bit_samples(); - - } - catch (const std::exception &e) - { + } + catch (const std::exception& e) + { std::cerr - << "The receiver was configured to work with a file signal source " - << std::endl - << "but the specified file is unreachable by GNSS-SDR." - << std::endl - << "Please modify your configuration file" - << std::endl - << "and point SignalSource.filename to a valid raw data file. Then:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl - << "Examples of configuration files available at:" - << std::endl - << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" - << std::endl; + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; LOG(WARNING) << "file_signal_source: Unable to open the samples file " - << filename_.c_str() << ", exiting the program."; + << filename_.c_str() << ", exiting the program."; throw(e); - } + } DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; - if (samples_ == 0) // read all file + if (samples_ == 0) // read all file { /*! * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the * valve block */ - std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream::pos_type size; if (file.is_open()) { size = file.tellg(); - LOG(INFO) << "Total samples in the file= " << floor((double)size / (double)item_size()); + LOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size())); } else { @@ -131,20 +127,20 @@ SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration } std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(16); - std::cout << "Processing file " << filename_ << ", which contains " << (double)size << " [bytes]" << std::endl; - std::cout.precision (ss); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision(ss); if (size > 0) { - int sample_packet_factor = 1; // 1 int -> 1 complex sample (I&Q from 1 channel) - samples_ = floor((double)size / (double)item_size())*sample_packet_factor; - samples_ = samples_- ceil(0.002 * (double)sampling_frequency_); //process all the samples available in the file excluding the last 2 ms + int sample_packet_factor = 1; // 1 int -> 1 complex sample (I&Q from 1 channel) + samples_ = floor(static_cast(size) / static_cast(item_size())) * sample_packet_factor; + samples_ = samples_ - ceil(0.002 * static_cast(sampling_frequency_)); //process all the samples available in the file excluding the last 2 ms } } CHECK(samples_ > 0) << "File does not contain enough samples to process."; double signal_duration_s; - signal_duration_s = (double)samples_ * ( 1 /(double)sampling_frequency_); + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; @@ -170,15 +166,18 @@ SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration DLOG(INFO) << "Repeat " << repeat_; DLOG(INFO) << "Dump " << dump_; DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - - -SpirFileSignalSource::~SpirFileSignalSource() -{} - - +SpirFileSignalSource::~SpirFileSignalSource() = default; void SpirFileSignalSource::connect(gr::top_block_sptr top_block) @@ -188,7 +187,7 @@ void SpirFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_intspir_, 0); - top_block->connect(unpack_intspir_, 0,throttle_,0); + top_block->connect(unpack_intspir_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; top_block->connect(throttle_, 0, valve_, 0); DLOG(INFO) << "connected throttle to valve"; @@ -201,7 +200,7 @@ void SpirFileSignalSource::connect(gr::top_block_sptr top_block) else { top_block->connect(file_source_, 0, unpack_intspir_, 0); - top_block->connect(unpack_intspir_, 0,valve_,0); + top_block->connect(unpack_intspir_, 0, valve_, 0); DLOG(INFO) << "connected file source to valve"; if (dump_) { @@ -215,7 +214,7 @@ void SpirFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_intspir_, 0); - top_block->connect(unpack_intspir_, 0,throttle_,0); + top_block->connect(unpack_intspir_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; if (dump_) { @@ -236,10 +235,6 @@ void SpirFileSignalSource::connect(gr::top_block_sptr top_block) } - - - - void SpirFileSignalSource::disconnect(gr::top_block_sptr top_block) { if (samples_ > 0) @@ -248,7 +243,7 @@ void SpirFileSignalSource::disconnect(gr::top_block_sptr top_block) { top_block->disconnect(file_source_, 0, unpack_intspir_, 0); DLOG(INFO) << "disconnected file source to unpack_intspir_"; - top_block->connect(unpack_intspir_, 0,throttle_,0); + top_block->connect(unpack_intspir_, 0, throttle_, 0); DLOG(INFO) << "disconnected unpack_intspir_ to throttle_"; top_block->disconnect(throttle_, 0, valve_, 0); DLOG(INFO) << "disconnected throttle to valve"; @@ -299,9 +294,6 @@ void SpirFileSignalSource::disconnect(gr::top_block_sptr top_block) } - - - gr::basic_block_sptr SpirFileSignalSource::get_left_block() { LOG(WARNING) << "Left block of a signal source should not be retrieved"; @@ -310,24 +302,15 @@ gr::basic_block_sptr SpirFileSignalSource::get_left_block() } - - - gr::basic_block_sptr SpirFileSignalSource::get_right_block() { if (samples_ > 0) { return valve_; } - else + if (enable_throttle_control_ == true) { - if (enable_throttle_control_ == true) - { - return throttle_; - } - else - { - return unpack_intspir_; - } + return throttle_; } + return unpack_intspir_; } diff --git a/src/algorithms/signal_source/adapters/spir_file_signal_source.h b/src/algorithms/signal_source/adapters/spir_file_signal_source.h index 5cc88d24b..659f5b19a 100644 --- a/src/algorithms/signal_source/adapters/spir_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/spir_file_signal_source.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,15 +32,14 @@ #ifndef GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H_ -#include -#include +#include "gnss_block_interface.h" +#include "unpack_intspir_1bit_samples.h" #include +#include #include #include #include -#include "gnss_block_interface.h" -#include "unpack_intspir_1bit_samples.h" - +#include class ConfigurationInterface; @@ -48,15 +47,15 @@ class ConfigurationInterface; * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class SpirFileSignalSource: public GNSSBlockInterface +class SpirFileSignalSource : public GNSSBlockInterface { public: - SpirFileSignalSource(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + SpirFileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); virtual ~SpirFileSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -64,35 +63,42 @@ public: /*! * \brief Returns "Spir_File_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "Spir_File_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string filename() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const { return filename_; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - bool repeat() + + inline bool repeat() const { return repeat_; } - long sampling_frequency() + + inline long sampling_frequency() const { return sampling_frequency_; } - long samples() + + inline long samples() const { return samples_; } @@ -112,7 +118,7 @@ private: unpack_intspir_1bit_samples_sptr unpack_intspir_; boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; - gr::blocks::throttle::sptr throttle_; + gr::blocks::throttle::sptr throttle_; boost::shared_ptr queue_; size_t item_size_; // Throttle control diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc new file mode 100644 index 000000000..ff8f45411 --- /dev/null +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc @@ -0,0 +1,327 @@ +/*! + * \file spir_gss6450_file_signal_source.cc + * \brief Implementation of a class that reads signals samples from a SPIR file + * and adapts it to a SignalSourceInterface. + * \author Antonio Ramos, 2017 antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "spir_gss6450_file_signal_source.h" +#include "configuration_interface.h" +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + + +SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, + const std::string& role, uint32_t in_streams, uint32_t out_streams, gr::msg_queue::sptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) +{ + std::string default_filename = "../data/my_capture.dat"; + std::string default_dump_filename = "../data/my_capture_dump.dat"; + item_type_ = "int"; + + samples_ = configuration->property(role + ".samples", 0); + sampling_frequency_ = configuration->property(role + ".sampling_frequency", 0.0); + filename_ = configuration->property(role + ".filename", default_filename); + repeat_ = configuration->property(role + ".repeat", false); + dump_ = configuration->property(role + ".dump", false); + endian_swap_ = configuration->property(role + ".endian", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); + adc_bits_ = configuration->property(role + ".adc_bits", 4); + n_channels_ = configuration->property(role + ".total_channels", 1); + sel_ch_ = configuration->property(role + ".sel_ch", 1); + item_size_ = sizeof(int32_t); + int64_t bytes_seek = configuration->property(role + ".bytes_to_skip", 65536); + double sample_size_byte = static_cast(adc_bits_) / 4.0; + + if (sel_ch_ > n_channels_) + { + LOG(WARNING) << "Invalid RF channel selection"; + } + if (n_channels_ > 1) + { + for (uint32_t i = 0; i < n_channels_; i++) + { + null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); + unpack_spir_vec_.push_back(make_unpack_spir_gss6450_samples(adc_bits_)); + if (endian_swap_) + { + endian_vec_.push_back(gr::blocks::endian_swap::make(item_size_)); + } + } + } + try + { + file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); + file_source_->seek(bytes_seek / item_size_, SEEK_SET); + + + deint_ = gr::blocks::deinterleave::make(item_size_); + } + catch (const std::exception& e) + { + std::cerr + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; + + LOG(WARNING) << "file_signal_source: Unable to open the samples file " + << filename_.c_str() << ", exiting the program."; + throw(e); + } + DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; + + if (samples_ == 0) // read all file + { + /*! + * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. + * A possible solution is to compute the file length in samples using file size, excluding the last 2 milliseconds, and enable always the + * valve block + */ + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + LOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); + } + else + { + std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << std::endl; + LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision(ss); + + if (size > 0) + { + samples_ = static_cast(floor(static_cast(static_cast(size) - static_cast(bytes_seek)) / (sample_size_byte * static_cast(n_channels_)))); + samples_ = samples_ - static_cast(ceil(0.002 * sampling_frequency_)); //process all the samples available in the file excluding the last 2 ms + } + } + + CHECK(samples_ > 0) << "File does not contain enough samples to process."; + double signal_duration_s = static_cast(samples_) / sampling_frequency_; + LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; + std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; + + for (uint32_t i = 0; i < (n_channels_); i++) + { + valve_vec_.push_back(gnss_sdr_make_valve(sizeof(gr_complex), samples_, queue_)); + if (dump_) + { + std::string tmp_str = dump_filename_ + "_ch" + std::to_string(i); + sink_vec_.push_back(gr::blocks::file_sink::make(sizeof(gr_complex), tmp_str.c_str())); + } + if (enable_throttle_control_) + { + throttle_vec_.push_back(gr::blocks::throttle::make(sizeof(gr_complex), sampling_frequency_)); + } + } + + DLOG(INFO) << "File source filename " << filename_; + DLOG(INFO) << "Samples " << samples_; + DLOG(INFO) << "Sampling frequency " << sampling_frequency_; + DLOG(INFO) << "Item type " << item_type_; + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "Repeat " << repeat_; + DLOG(INFO) << "Dump " << dump_; + DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +SpirGSS6450FileSignalSource::~SpirGSS6450FileSignalSource() = default; + + +void SpirGSS6450FileSignalSource::connect(gr::top_block_sptr top_block) +{ + if (samples_ > 0) + { + top_block->connect(file_source_, 0, deint_, 0); + + if (endian_swap_) + { + top_block->connect(deint_, sel_ch_ - 1, endian_vec_.at(sel_ch_ - 1), 0); + top_block->connect(endian_vec_.at(sel_ch_ - 1), 0, unpack_spir_vec_.at(sel_ch_ - 1), 0); + } + else + { + top_block->connect(deint_, sel_ch_ - 1, unpack_spir_vec_.at(sel_ch_ - 1), 0); + } + + if (n_channels_ > 1) + { + uint32_t aux = 0; + for (uint32_t i = 0; i < n_channels_; i++) + { + if (i != (sel_ch_ - 1)) + { + if (endian_swap_) + { + top_block->connect(deint_, i, endian_vec_.at(i), 0); + top_block->connect(endian_vec_.at(i), 0, unpack_spir_vec_.at(i), 0); + } + else + { + top_block->connect(deint_, i, unpack_spir_vec_.at(i), 0); + } + + aux++; + } + } + } + for (uint32_t i = 0; i < n_channels_; i++) + { + if (enable_throttle_control_) + { + top_block->connect(unpack_spir_vec_.at(i), 0, throttle_vec_.at(i), 0); + top_block->connect(throttle_vec_.at(i), 0, valve_vec_.at(i), 0); + } + else + { + top_block->connect(unpack_spir_vec_.at(i), 0, valve_vec_.at(i), 0); + } + if (dump_) + { + top_block->connect(valve_vec_.at(i), 0, sink_vec_.at(i), 0); + } + + top_block->connect(valve_vec_.at(i), 0, null_sinks_.at(i), 0); + } + } + else + { + LOG(WARNING) << "0 samples to read"; + } +} + + +void SpirGSS6450FileSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (samples_ > 0) + { + top_block->disconnect(file_source_, 0, deint_, 0); + if (endian_swap_) + { + top_block->disconnect(deint_, sel_ch_ - 1, endian_vec_.at(sel_ch_ - 1), 0); + top_block->disconnect(endian_vec_.at(sel_ch_ - 1), 0, unpack_spir_vec_.at(sel_ch_ - 1), 0); + } + else + { + top_block->disconnect(deint_, sel_ch_ - 1, unpack_spir_vec_.at(sel_ch_ - 1), 0); + } + if (n_channels_ > 1) + { + uint32_t aux = 0; + for (uint32_t i = 0; i < n_channels_; i++) + { + if (i != (sel_ch_ - 1)) + { + if (endian_swap_) + { + top_block->disconnect(deint_, i, endian_vec_.at(i), 0); + top_block->disconnect(endian_vec_.at(i), 0, unpack_spir_vec_.at(i), 0); + } + else + { + top_block->disconnect(deint_, i, unpack_spir_vec_.at(i), 0); + } + + aux++; + } + } + } + + for (uint32_t i = 0; i < (n_channels_); i++) + { + if (enable_throttle_control_) + { + top_block->disconnect(unpack_spir_vec_.at(i), 0, throttle_vec_.at(i), 0); + top_block->disconnect(throttle_vec_.at(i), 0, valve_vec_.at(i), 0); + } + else + { + top_block->disconnect(unpack_spir_vec_.at(i), 0, valve_vec_.at(i), 0); + } + if (dump_) + { + top_block->disconnect(valve_vec_.at(i), 0, sink_vec_.at(i), 0); + } + + top_block->disconnect(valve_vec_.at(i), 0, null_sinks_.at(i), 0); + } + } + else + { + LOG(WARNING) << "Nothing to disconnect"; + } +} + + +gr::basic_block_sptr SpirGSS6450FileSignalSource::get_left_block() +{ + LOG(WARNING) << "Left block of a signal source should not be retrieved"; + return gr::blocks::file_source::sptr(); +} + +gr::basic_block_sptr SpirGSS6450FileSignalSource::get_right_block(int RF_channel) +{ + return valve_vec_.at(RF_channel); +} + +gr::basic_block_sptr SpirGSS6450FileSignalSource::get_right_block() +{ + return valve_vec_.at(0); +} diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h new file mode 100644 index 000000000..71eb9c9df --- /dev/null +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h @@ -0,0 +1,138 @@ +/*! + * \file spir_gss6450_file_signal_source.h + * \brief Implementation of a class that reads signals samples from a SPIR file + * and adapts it to a SignalSourceInterface. + * \author Antonio Ramos, 2017 antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ +#define GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "unpack_spir_gss6450_samples.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief Class that reads signals samples from a file + * and adapts it to a SignalSourceInterface + */ +class SpirGSS6450FileSignalSource : public GNSSBlockInterface +{ +public: + SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, const std::string& role, + uint32_t in_streams, uint32_t out_streams, gr::msg_queue::sptr queue); + + virtual ~SpirGSS6450FileSignalSource(); + inline std::string role() override + { + return role_; + } + + inline std::string implementation() override + { + return "Spir_GSS6450_File_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const + { + return filename_; + } + + inline std::string item_type() const + { + return item_type_; + } + + inline bool repeat() const + { + return repeat_; + } + + inline long sampling_frequency() const + { + return sampling_frequency_; + } + + inline long samples() const + { + return samples_; + } + +private: + uint64_t samples_; + double sampling_frequency_; + std::string filename_; + bool repeat_; + bool dump_; //Enables dumping the gr_complex sample output + bool enable_throttle_control_; + bool endian_swap_; + std::string dump_filename_; + std::string role_; + std::string item_type_; + uint32_t in_streams_; + uint32_t out_streams_; + uint32_t adc_bits_; + uint32_t n_channels_; + uint32_t sel_ch_; + gr::blocks::file_source::sptr file_source_; + gr::blocks::deinterleave::sptr deint_; + std::vector endian_vec_; + std::vector null_sinks_; + std::vector unpack_spir_vec_; + std::vector> valve_vec_; + std::vector sink_vec_; + std::vector throttle_vec_; + gr::msg_queue::sptr queue_; + size_t item_size_; +}; + +#endif /*GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc index 97e320e9b..7115771e9 100644 --- a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,33 +24,34 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "two_bit_cpx_file_signal_source.h" -#include +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include #include #include #include #include -#include -#include -#include "gnss_sdr_valve.h" -#include "configuration_interface.h" +#include using google::LogMessage; -//DEFINE_string(two_bit_cpx_signal_source, "-", -// "If defined, path to the file containing the NSR (byte to 2-bit packed) signal samples (overrides the configuration file)"); - TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : - role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, + boost::shared_ptr queue) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams), + queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "byte"; @@ -61,7 +62,8 @@ TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* con filename_ = configuration->property(role + ".filename", default_filename); // override value with commandline flag, if present - //if (FLAGS_nsr_signal_source.compare("-") != 0) filename_= FLAGS_nsr_signal_source; + if (FLAGS_signal_source != "-") filename_ = FLAGS_signal_source; + if (FLAGS_s != "-") filename_ = FLAGS_s; item_type_ = configuration->property(role + ".item_type", default_item_type); repeat_ = configuration->property(role + ".repeat", false); @@ -69,61 +71,60 @@ TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* con dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); - if (item_type_.compare("byte") == 0) + if (item_type_ == "byte") { item_size_ = sizeof(char); } else { - LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; + LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; item_size_ = sizeof(char); } try - { + { file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); unpack_byte_ = make_unpack_byte_2bit_cpx_samples(); - inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false,true); //I/Q swap enabled - - } - catch (const std::exception &e) - { + inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, true); //I/Q swap enabled + } + catch (const std::exception& e) + { std::cerr - << "The receiver was configured to work with a file signal source " - << std::endl - << "but the specified file is unreachable by GNSS-SDR." - << std::endl - << "Please modify your configuration file" - << std::endl - << "and point SignalSource.filename to a valid raw data file. Then:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl - << "Examples of configuration files available at:" - << std::endl - << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" - << std::endl; + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; LOG(WARNING) << "file_signal_source: Unable to open the samples file " - << filename_.c_str() << ", exiting the program."; + << filename_.c_str() << ", exiting the program."; throw(e); - } + } DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; - if (samples_ == 0) // read all file + if (samples_ == 0) // read all file { /*! * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. * A possible solution is to compute the file length in samples using file size, excluding the last 2 milliseconds, and enable always the * valve block */ - std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream::pos_type size; if (file.is_open()) { size = file.tellg(); - LOG(INFO) << "Total samples in the file= " << floor((double)size / (double)item_size()); + LOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size())); } else { @@ -132,20 +133,20 @@ TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* con } std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(16); - std::cout << "Processing file " << filename_ << ", which contains " << (double)size << " [bytes]" << std::endl; - std::cout.precision (ss); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision(ss); if (size > 0) { - int sample_packet_factor = 2; // 1 byte -> 2 samples - samples_ = floor((double)size / (double)item_size())*sample_packet_factor; - samples_ = samples_- ceil(0.002 * (double)sampling_frequency_); //process all the samples available in the file excluding the last 2 ms + int sample_packet_factor = 2; // 1 byte -> 2 samples + samples_ = floor(static_cast(size) / static_cast(item_size())) * sample_packet_factor; + samples_ = samples_ - ceil(0.002 * static_cast(sampling_frequency_)); //process all the samples available in the file excluding the last 2 ms } } CHECK(samples_ > 0) << "File does not contain enough samples to process."; double signal_duration_s; - signal_duration_s = (double)samples_ * ( 1 /(double)sampling_frequency_); + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; @@ -171,11 +172,18 @@ TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* con DLOG(INFO) << "Repeat " << repeat_; DLOG(INFO) << "Dump " << dump_; DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -TwoBitCpxFileSignalSource::~TwoBitCpxFileSignalSource() -{} +TwoBitCpxFileSignalSource::~TwoBitCpxFileSignalSource() = default; void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) @@ -185,8 +193,8 @@ void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,inter_shorts_to_cpx_,0); - top_block->connect(inter_shorts_to_cpx_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); + top_block->connect(inter_shorts_to_cpx_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; top_block->connect(throttle_, 0, valve_, 0); DLOG(INFO) << "connected throttle to valve"; @@ -199,8 +207,8 @@ void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) else { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,inter_shorts_to_cpx_,0); - top_block->connect(inter_shorts_to_cpx_, 0,valve_,0); + top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); + top_block->connect(inter_shorts_to_cpx_, 0, valve_, 0); DLOG(INFO) << "connected file source to valve"; if (dump_) { @@ -214,8 +222,8 @@ void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) if (enable_throttle_control_ == true) { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,inter_shorts_to_cpx_,0); - top_block->connect(inter_shorts_to_cpx_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); + top_block->connect(inter_shorts_to_cpx_, 0, throttle_, 0); DLOG(INFO) << "connected file source to throttle"; if (dump_) { @@ -228,7 +236,7 @@ void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) if (dump_) { top_block->connect(file_source_, 0, unpack_byte_, 0); - top_block->connect(unpack_byte_, 0,inter_shorts_to_cpx_,0); + top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); top_block->connect(inter_shorts_to_cpx_, 0, sink_, 0); DLOG(INFO) << "connected file source to sink"; } @@ -237,10 +245,6 @@ void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) } - - - - void TwoBitCpxFileSignalSource::disconnect(gr::top_block_sptr top_block) { if (samples_ > 0) @@ -249,7 +253,7 @@ void TwoBitCpxFileSignalSource::disconnect(gr::top_block_sptr top_block) { top_block->disconnect(file_source_, 0, unpack_byte_, 0); DLOG(INFO) << "disconnected file source to unpack_byte_"; - top_block->connect(unpack_byte_, 0,throttle_,0); + top_block->connect(unpack_byte_, 0, throttle_, 0); DLOG(INFO) << "disconnected unpack_byte_ to throttle_"; top_block->disconnect(throttle_, 0, valve_, 0); DLOG(INFO) << "disconnected throttle to valve"; @@ -314,15 +318,9 @@ gr::basic_block_sptr TwoBitCpxFileSignalSource::get_right_block() { return valve_; } - else + if (enable_throttle_control_ == true) { - if (enable_throttle_control_ == true) - { - return throttle_; - } - else - { - return unpack_byte_; - } + return throttle_; } + return unpack_byte_; } diff --git a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h index a7f8d1adc..a66a87965 100644 --- a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,16 +34,16 @@ #ifndef GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H_ -#include -#include +#include "gnss_block_interface.h" +#include "unpack_byte_2bit_cpx_samples.h" #include +#include +#include #include #include #include -#include -#include "gnss_block_interface.h" -#include "unpack_byte_2bit_cpx_samples.h" - +#include +#include class ConfigurationInterface; @@ -52,15 +52,17 @@ class ConfigurationInterface; * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class TwoBitCpxFileSignalSource: public GNSSBlockInterface +class TwoBitCpxFileSignalSource : public GNSSBlockInterface { public: - TwoBitCpxFileSignalSource(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + TwoBitCpxFileSignalSource(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, + boost::shared_ptr queue); virtual ~TwoBitCpxFileSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -68,42 +70,49 @@ public: /*! * \brief Returns "Two_Bit_Cpx_File_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "Two_Bit_Cpx_File_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string filename() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const { return filename_; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - bool repeat() + + inline bool repeat() const { return repeat_; } - long sampling_frequency() + + inline int64_t sampling_frequency() const { return sampling_frequency_; } - long samples() + + inline uint64_t samples() const { return samples_; } private: - unsigned long long samples_; - long sampling_frequency_; + uint64_t samples_; + int64_t sampling_frequency_; std::string filename_; std::string item_type_; bool repeat_; @@ -117,7 +126,7 @@ private: gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_; boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; - gr::blocks::throttle::sptr throttle_; + gr::blocks::throttle::sptr throttle_; boost::shared_ptr queue_; size_t item_size_; // Throttle control diff --git a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc index 9fa6361f9..9355537ce 100644 --- a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,34 +25,35 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "two_bit_packed_file_signal_source.h" -#include +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include +#include #include #include #include #include -#include -#include -#include "gnss_sdr_valve.h" -#include "configuration_interface.h" -#include +#include using google::LogMessage; -//DEFINE_string(two_bit_packed_signal_source, "-", -// "If defined, path to the file containing the NSR (byte to 2-bit packed) signal samples (overrides the configuration file)"); - TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : - role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, + boost::shared_ptr queue) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams), + queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "byte"; @@ -60,139 +61,141 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(ConfigurationInterfac std::string default_sample_type = "real"; double default_seconds_to_skip = 0.0; - samples_ = configuration->property(role + ".samples", 0L); + samples_ = configuration->property(role + ".samples", 0); sampling_frequency_ = configuration->property(role + ".sampling_frequency", 0); filename_ = configuration->property(role + ".filename", default_filename); // override value with commandline flag, if present - //if (FLAGS_nsr_signal_source.compare("-") != 0) filename_= FLAGS_nsr_signal_source; + if (FLAGS_signal_source != "-") filename_ = FLAGS_signal_source; + if (FLAGS_s != "-") filename_ = FLAGS_s; item_type_ = configuration->property(role + ".item_type", default_item_type); big_endian_items_ = configuration->property(role + ".big_endian_items", true); big_endian_bytes_ = configuration->property(role + ".big_endian_bytes", false); - sample_type_ = configuration->property(role + ".sample_type", default_sample_type ); // options: "real", "iq", "qi" + sample_type_ = configuration->property(role + ".sample_type", default_sample_type); // options: "real", "iq", "qi" repeat_ = configuration->property(role + ".repeat", false); dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); - double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip ); - long bytes_to_skip = 0; + double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); + int64_t bytes_to_skip = 0; - if (item_type_.compare("byte") == 0) + if (item_type_ == "byte") { item_size_ = sizeof(char); } - else if( item_type_.compare("short") == 0) + else if (item_type_ == "short") { // If we have shorts stored in little endian format, might as // well read them in as bytes. - if( big_endian_items_ ) - { - item_size_ = sizeof(short); - } + if (big_endian_items_) + { + item_size_ = sizeof(int16_t); + } else - { - item_size_ = sizeof(char); - } + { + item_size_ = sizeof(char); + } } else { - LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; + LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; item_size_ = sizeof(char); } - if( sample_type_.compare("real") == 0 ) - { - is_complex_ = false; - } - else if( sample_type_.compare("iq" ) == 0 ) - { - is_complex_ = true; - reverse_interleaving_ = false; - } - else if( sample_type_.compare("qi") == 0 ) - { - is_complex_ = true; - reverse_interleaving_ = true; - } + if (sample_type_ == "real") + { + is_complex_ = false; + } + else if (sample_type_ == "iq") + { + is_complex_ = true; + reverse_interleaving_ = false; + } + else if (sample_type_ == "qi") + { + is_complex_ = true; + reverse_interleaving_ = true; + } else - { - LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: " - << ( is_complex_ ? ( reverse_interleaving_ ? "qi" : "iq" ) : "real" ); - } + { + LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: " + << (is_complex_ ? (reverse_interleaving_ ? "qi" : "iq") : "real"); + } try - { + { file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); - if( seconds_to_skip > 0 ) - { - bytes_to_skip = static_cast< long >( - seconds_to_skip * sampling_frequency_ / 4 ); - if( is_complex_ ) + if (seconds_to_skip > 0) { - bytes_to_skip <<= 1; + bytes_to_skip = static_cast( + seconds_to_skip * sampling_frequency_ / 4); + if (is_complex_) + { + bytes_to_skip <<= 1; + } + file_source_->seek(bytes_to_skip, SEEK_SET); } - file_source_->seek( bytes_to_skip, SEEK_SET ); - } - unpack_samples_ = make_unpack_2bit_samples( big_endian_bytes_, - item_size_, big_endian_items_, reverse_interleaving_); - if( is_complex_ ) - { - char_to_float_ = - gr::blocks::interleaved_char_to_complex::make(false); - } + unpack_samples_ = make_unpack_2bit_samples(big_endian_bytes_, + item_size_, big_endian_items_, reverse_interleaving_); + if (is_complex_) + { + char_to_float_ = + gr::blocks::interleaved_char_to_complex::make(false); + } else - { - char_to_float_ = - gr::blocks::char_to_float::make(); - } - - } - catch (const std::exception &e) - { + { + char_to_float_ = + gr::blocks::char_to_float::make(); + } + } + catch (const std::exception& e) + { std::cerr - << "The receiver was configured to work with a file signal source " - << std::endl - << "but the specified file is unreachable by GNSS-SDR." - << std::endl - << "Please modify your configuration file" - << std::endl - << "and point SignalSource.filename to a valid raw data file. Then:" - << std::endl - << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" - << std::endl - << "Examples of configuration files available at:" - << std::endl - << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" - << std::endl; + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; LOG(WARNING) << "file_signal_source: Unable to open the samples file " << filename_.c_str() << ", exiting the program."; throw(e); - } + } DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; - if (samples_ == 0) // read all file + size_t output_item_size = (is_complex_ ? sizeof(gr_complex) : sizeof(float)); + + if (samples_ == 0) // read all file { /*! * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. * A possible solution is to compute the file length in samples using file size, excluding the last 2 milliseconds, and enable always the * valve block */ - std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream::pos_type size; if (file.is_open()) { size = file.tellg(); - samples_ = floor((double)size * ( is_complex_ ? 2.0 : 4.0 ) ); - LOG(INFO) << "Total samples in the file= " << samples_; // 4 samples per byte + samples_ = floor(static_cast(size) * (is_complex_ ? 2.0 : 4.0)); + LOG(INFO) << "Total samples in the file= " << samples_; // 4 samples per byte samples_ -= bytes_to_skip; //Also skip the last two milliseconds: - samples_ -= ceil( 0.002 * sampling_frequency_ / (is_complex_ ? 2.0 : 4.0 ) ); + samples_ -= ceil(0.002 * sampling_frequency_ / (is_complex_ ? 2.0 : 4.0)); } else { @@ -201,29 +204,29 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(ConfigurationInterfac } std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(16); - std::cout << "Processing file " << filename_ << ", which contains " << (double)size << " [bytes]" << std::endl; - std::cout.precision (ss); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision(ss); } CHECK(samples_ > 0) << "File does not contain enough samples to process."; double signal_duration_s; - signal_duration_s = (double)samples_ * ( 1 /(double)sampling_frequency_); + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; - valve_ = gnss_sdr_make_valve(sizeof(gr_complex), samples_, queue_); + valve_ = gnss_sdr_make_valve(output_item_size, samples_, queue_); DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; if (dump_) { //sink_ = gr_make_file_sink(item_size_, dump_filename_.c_str()); - sink_ = gr::blocks::file_sink::make(sizeof(gr_complex), dump_filename_.c_str()); + sink_ = gr::blocks::file_sink::make(output_item_size, dump_filename_.c_str()); DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; } if (enable_throttle_control_) { - throttle_ = gr::blocks::throttle::make(sizeof(gr_complex), sampling_frequency_); + throttle_ = gr::blocks::throttle::make(output_item_size, sampling_frequency_); } DLOG(INFO) << "File source filename " << filename_; DLOG(INFO) << "Samples " << samples_; @@ -233,11 +236,18 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(ConfigurationInterfac DLOG(INFO) << "Repeat " << repeat_; DLOG(INFO) << "Dump " << dump_; DLOG(INFO) << "Dump filename " << dump_filename_; + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -TwoBitPackedFileSignalSource::~TwoBitPackedFileSignalSource() -{} +TwoBitPackedFileSignalSource::~TwoBitPackedFileSignalSource() = default; void TwoBitPackedFileSignalSource::connect(gr::top_block_sptr top_block) @@ -250,25 +260,25 @@ void TwoBitPackedFileSignalSource::connect(gr::top_block_sptr top_block) DLOG(INFO) << "connected file source to unpack samples"; right_block = char_to_float_; - top_block->connect( left_block, 0, right_block, 0 ); + top_block->connect(left_block, 0, right_block, 0); left_block = right_block; DLOG(INFO) << "connected unpack samples to char to float"; - if( enable_throttle_control_ ) - { - right_block = throttle_; - top_block->connect( left_block, 0, right_block, 0 ); - left_block = right_block; - DLOG(INFO) << " connected to throttle"; - } + if (enable_throttle_control_) + { + right_block = throttle_; + top_block->connect(left_block, 0, right_block, 0); + left_block = right_block; + DLOG(INFO) << " connected to throttle"; + } top_block->connect(left_block, 0, valve_, 0); DLOG(INFO) << "connected to valve"; if (dump_) - { - top_block->connect(valve_, 0, sink_, 0); - DLOG(INFO) << "connected valve to file sink"; - } + { + top_block->connect(valve_, 0, sink_, 0); + DLOG(INFO) << "connected valve to file sink"; + } } @@ -283,25 +293,25 @@ void TwoBitPackedFileSignalSource::disconnect(gr::top_block_sptr top_block) DLOG(INFO) << "disconnected file source to unpack samples"; right_block = char_to_float_; - top_block->disconnect( left_block, 0, right_block, 0 ); + top_block->disconnect(left_block, 0, right_block, 0); left_block = right_block; DLOG(INFO) << "disconnected unpack samples to char to float"; - if( enable_throttle_control_ ) - { - right_block = throttle_; - top_block->disconnect( left_block, 0, right_block, 0 ); - left_block = right_block; - DLOG(INFO) << " disconnected to throttle"; - } + if (enable_throttle_control_) + { + right_block = throttle_; + top_block->disconnect(left_block, 0, right_block, 0); + left_block = right_block; + DLOG(INFO) << " disconnected to throttle"; + } top_block->disconnect(left_block, 0, valve_, 0); DLOG(INFO) << "disconnected to valve"; if (dump_) - { - top_block->disconnect(valve_, 0, sink_, 0); - DLOG(INFO) << "disconnected valve to file sink"; - } + { + top_block->disconnect(valve_, 0, sink_, 0); + DLOG(INFO) << "disconnected valve to file sink"; + } } @@ -317,4 +327,3 @@ gr::basic_block_sptr TwoBitPackedFileSignalSource::get_right_block() { return valve_; } - diff --git a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h index 48a365c61..1e98d737b 100644 --- a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,16 +35,16 @@ #ifndef GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H_ -#include -#include +#include "gnss_block_interface.h" +#include "unpack_2bit_samples.h" #include +#include +#include #include #include #include -#include -#include "gnss_block_interface.h" -#include "unpack_2bit_samples.h" - +#include +#include class ConfigurationInterface; @@ -53,15 +53,15 @@ class ConfigurationInterface; * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class TwoBitPackedFileSignalSource: public GNSSBlockInterface +class TwoBitPackedFileSignalSource : public GNSSBlockInterface { public: - TwoBitPackedFileSignalSource(ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + TwoBitPackedFileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); virtual ~TwoBitPackedFileSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -69,58 +69,69 @@ public: /*! * \brief Returns "Two_Bit_Packed_File_Signal_Source". */ - std::string implementation() + inline std::string implementation() override { return "Two_Bit_Packed_File_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - std::string filename() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + inline std::string filename() const { return filename_; } - std::string item_type() + + inline std::string item_type() const { return item_type_; } - bool repeat() + + inline bool repeat() const { return repeat_; } - long sampling_frequency() + + inline int64_t sampling_frequency() const { return sampling_frequency_; } - long samples() + + inline uint64_t samples() const { return samples_; } - bool big_endian_items() + + inline bool big_endian_items() const { return big_endian_items_; } - bool big_endian_bytes() + + inline bool big_endian_bytes() const { return big_endian_bytes_; } - bool is_complex() + + inline bool is_complex() const { return is_complex_; } - bool reverse_interleaving() + + inline bool reverse_interleaving() const { return reverse_interleaving_; } private: - unsigned long long samples_; - long sampling_frequency_; + uint64_t samples_; + int64_t sampling_frequency_; std::string filename_; std::string item_type_; bool repeat_; @@ -134,7 +145,7 @@ private: gr::basic_block_sptr char_to_float_; boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; - gr::blocks::throttle::sptr throttle_; + gr::blocks::throttle::sptr throttle_; boost::shared_ptr queue_; size_t item_size_; bool big_endian_items_; @@ -147,4 +158,3 @@ private: }; #endif /*GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H_*/ - diff --git a/src/algorithms/signal_source/adapters/uhd_signal_source.cc b/src/algorithms/signal_source/adapters/uhd_signal_source.cc index 4728543d3..54a353837 100644 --- a/src/algorithms/signal_source/adapters/uhd_signal_source.cc +++ b/src/algorithms/signal_source/adapters/uhd_signal_source.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,28 +23,28 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "uhd_signal_source.h" -#include -#include -#include -#include -#include +#include "GPS_L1_CA.h" #include "configuration_interface.h" #include "gnss_sdr_valve.h" -#include "GPS_L1_CA.h" +#include +#include +#include +#include +#include +#include + using google::LogMessage; UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : - role_(role), in_stream_(in_stream), out_stream_(out_stream), - queue_(queue) + const std::string& role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { // DUMP PARAMETERS std::string empty = ""; @@ -58,15 +58,20 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, // available transports on the system (ethernet, usb...). // To narrow down the discovery process to a particular device, // specify a transport key/value pair specific to your device. - if (empty.compare(device_address_) != 0) // if not empty + if (empty != device_address_) // if not empty { dev_addr["addr"] = device_address_; } - + //filter the device by serial number if required (useful for USB devices) + std::string device_serial = configuration->property(role + ".device_serial", empty); + if (empty != device_serial) // if not empty + { + dev_addr["serial"] = device_serial; + } subdevice_ = configuration->property(role + ".subdevice", empty); clock_source_ = configuration->property(role + ".clock_source", std::string("internal")); RF_channels_ = configuration->property(role + ".RF_channels", 1); - sample_rate_ = configuration->property(role + ".sampling_frequency", (double)4.0e6); + sample_rate_ = configuration->property(role + ".sampling_frequency", 4.0e6); item_type_ = configuration->property(role + ".item_type", default_item_type); if (RF_channels_ == 1) @@ -77,10 +82,9 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, dump_filename_.push_back(configuration->property(role + ".dump_filename", default_dump_file)); freq_.push_back(configuration->property(role + ".freq", GPS_L1_FREQ_HZ)); - gain_.push_back(configuration->property(role + ".gain", (double)50.0)); - - IF_bandwidth_hz_.push_back(configuration->property(role + ".IF_bandwidth_hz", sample_rate_/2)); + gain_.push_back(configuration->property(role + ".gain", 50.0)); + IF_bandwidth_hz_.push_back(configuration->property(role + ".IF_bandwidth_hz", sample_rate_ / 2)); } else { @@ -88,14 +92,14 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, for (int i = 0; i < RF_channels_; i++) { // Single RF channel UHD operation (backward compatible config file format) - samples_.push_back(configuration->property(role + ".samples" + boost::lexical_cast(i), 0)); - dump_.push_back(configuration->property(role + ".dump" + boost::lexical_cast(i), false)); - dump_filename_.push_back(configuration->property(role + ".dump_filename" + boost::lexical_cast(i), default_dump_file)); + samples_.push_back(configuration->property(role + ".samples" + std::to_string(i), 0)); + dump_.push_back(configuration->property(role + ".dump" + std::to_string(i), false)); + dump_filename_.push_back(configuration->property(role + ".dump_filename" + std::to_string(i), default_dump_file)); - freq_.push_back(configuration->property(role + ".freq" + boost::lexical_cast(i), GPS_L1_FREQ_HZ)); - gain_.push_back(configuration->property(role + ".gain" + boost::lexical_cast(i), (double)50.0)); + freq_.push_back(configuration->property(role + ".freq" + std::to_string(i), GPS_L1_FREQ_HZ)); + gain_.push_back(configuration->property(role + ".gain" + std::to_string(i), 50.0)); - IF_bandwidth_hz_.push_back(configuration->property(role + ".IF_bandwidth_hz" + boost::lexical_cast(i), sample_rate_/2)); + IF_bandwidth_hz_.push_back(configuration->property(role + ".IF_bandwidth_hz" + std::to_string(i), sample_rate_ / 2)); } } // 1. Make the uhd driver instance @@ -108,17 +112,17 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, // fc32: Complex floating point (32-bit floats) range [-1.0, +1.0]. // sc16: Complex signed integer (16-bit integers) range [-32768, +32767]. // sc8: Complex signed integer (8-bit integers) range [-128, 127]. - if (item_type_.compare("cbyte") == 0) + if (item_type_ == "cbyte") { item_size_ = sizeof(lv_8sc_t); uhd_stream_args_ = uhd::stream_args_t("sc8"); } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); uhd_stream_args_ = uhd::stream_args_t("sc16"); } - else if (item_type_.compare("gr_complex") == 0) + else if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); uhd_stream_args_ = uhd::stream_args_t("fc32"); @@ -213,24 +217,30 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, { if (samples_.at(i) != 0) { - LOG(INFO) << "RF_channel "<< i << " Send STOP signal after " << samples_.at(i) << " samples"; + LOG(INFO) << "RF_channel " << i << " Send STOP signal after " << samples_.at(i) << " samples"; valve_.push_back(gnss_sdr_make_valve(item_size_, samples_.at(i), queue_)); DLOG(INFO) << "valve(" << valve_.at(i)->unique_id() << ")"; } if (dump_.at(i)) { - LOG(INFO) << "RF_channel "<< i << "Dumping output into file " << dump_filename_.at(i); + LOG(INFO) << "RF_channel " << i << "Dumping output into file " << dump_filename_.at(i); file_sink_.push_back(gr::blocks::file_sink::make(item_size_, dump_filename_.at(i).c_str())); DLOG(INFO) << "file_sink(" << file_sink_.at(i)->unique_id() << ")"; } } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } - -UhdSignalSource::~UhdSignalSource() -{} +UhdSignalSource::~UhdSignalSource() = default; void UhdSignalSource::connect(gr::top_block_sptr top_block) @@ -259,7 +269,6 @@ void UhdSignalSource::connect(gr::top_block_sptr top_block) } - void UhdSignalSource::disconnect(gr::top_block_sptr top_block) { for (int i = 0; i < RF_channels_; i++) @@ -284,7 +293,6 @@ void UhdSignalSource::disconnect(gr::top_block_sptr top_block) } - gr::basic_block_sptr UhdSignalSource::get_left_block() { LOG(WARNING) << "Trying to get signal source left block."; @@ -306,8 +314,5 @@ gr::basic_block_sptr UhdSignalSource::get_right_block(int RF_channel) { return valve_.at(RF_channel); } - else - { - return uhd_source_; - } + return uhd_source_; } diff --git a/src/algorithms/signal_source/adapters/uhd_signal_source.h b/src/algorithms/signal_source/adapters/uhd_signal_source.h index cda8c0270..68d6e6b76 100644 --- a/src/algorithms/signal_source/adapters/uhd_signal_source.h +++ b/src/algorithms/signal_source/adapters/uhd_signal_source.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,31 +31,31 @@ #ifndef GNSS_SDR_UHD_SIGNAL_SOURCE_H_ #define GNSS_SDR_UHD_SIGNAL_SOURCE_H_ +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include "gnss_block_interface.h" + class ConfigurationInterface; /*! * \brief This class reads samples from a UHD device (see http://code.ettus.com/redmine/ettus/projects/uhd/wiki) */ -class UhdSignalSource: public GNSSBlockInterface +class UhdSignalSource : public GNSSBlockInterface { - public: UhdSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + const std::string& role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); virtual ~UhdSignalSource(); - std::string role() + inline std::string role() override { return role_; } @@ -63,23 +63,23 @@ public: /*! * \brief Returns "UHD_Signal_Source" */ - std::string implementation() + inline std::string implementation() override { return "UHD_Signal_Source"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - gr::basic_block_sptr get_right_block(int RF_channel); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; private: - std::string role_; unsigned int in_stream_; unsigned int out_stream_; diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index 417f08d17..fb94ec51c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,30 +13,74 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # +if(ENABLE_RAW_UDP) + find_package(PCAP) + if(NOT PCAP_FOUND) + message(FATAL_ERROR "PCAP required to compile custom UDP packet sample source") + endif() + get_filename_component(PCAP_LIBRARY_DIRS ${PCAP_LIBRARY} DIRECTORY CACHE) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${PCAP_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${PCAP_INCLUDE_DIRS}) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gr_complex_ip_packet_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h) +endif() + + set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES - unpack_byte_2bit_samples.cc - unpack_byte_2bit_cpx_samples.cc - unpack_intspir_1bit_samples.cc - rtl_tcp_signal_source_c.cc - unpack_2bit_samples.cc + unpack_byte_2bit_samples.cc + unpack_byte_2bit_cpx_samples.cc + unpack_byte_4bit_samples.cc + unpack_intspir_1bit_samples.cc + rtl_tcp_signal_source_c.cc + unpack_2bit_samples.cc + unpack_spir_gss6450_samples.cc + labsat23_source.cc + ${OPT_DRIVER_SOURCES} ) + +set(SIGNAL_SOURCE_GR_BLOCKS_HEADERS + unpack_byte_2bit_samples.h + unpack_byte_2bit_cpx_samples.h + unpack_byte_4bit_samples.h + unpack_intspir_1bit_samples.h + rtl_tcp_signal_source_c.h + unpack_2bit_samples.h + unpack_spir_gss6450_samples.h + labsat23_source.h + ${OPT_DRIVER_HEADERS} +) + + include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${OPT_DRIVER_INCLUDE_DIRS} ) -file(GLOB SIGNAL_SOURCE_GR_BLOCKS_HEADERS "*.h") list(SORT SIGNAL_SOURCE_GR_BLOCKS_HEADERS) -add_library(signal_source_gr_blocks ${SIGNAL_SOURCE_GR_BLOCKS_SOURCES} ${SIGNAL_SOURCE_GR_BLOCKS_HEADERS}) +list(SORT SIGNAL_SOURCE_GR_BLOCKS_SOURCES) + +add_library(signal_source_gr_blocks + ${SIGNAL_SOURCE_GR_BLOCKS_SOURCES} + ${SIGNAL_SOURCE_GR_BLOCKS_HEADERS} +) + source_group(Headers FILES ${SIGNAL_SOURCE_GR_BLOCKS_HEADERS}) -target_link_libraries(signal_source_gr_blocks signal_source_lib ${GNURADIO_RUNTIME_LIBRARIES} ${Boost_LIBRARIES}) + +target_link_libraries(signal_source_gr_blocks + signal_source_lib + ${GNURADIO_RUNTIME_LIBRARIES} + ${Boost_LIBRARIES} + ${OPT_LIBRARIES} +) + add_dependencies(signal_source_gr_blocks glog-${glog_RELEASE}) diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc new file mode 100644 index 000000000..ba6a8ec3e --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -0,0 +1,448 @@ +/*! + * \file gr_complex_ip_packet_source.cc + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gr_complex_ip_packet_source.h" +#include +#include +#include + +const int FIFO_SIZE = 1472000; + + +/* 4 bytes IP address */ +typedef struct gr_ip_address +{ + u_char byte1; + u_char byte2; + u_char byte3; + u_char byte4; +} gr_ip_address; + + +/* IPv4 header */ +typedef struct gr_ip_header +{ + u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits) + u_char tos; // Type of service + u_short tlen; // Total length + u_short identification; // Identification + u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) + u_char ttl; // Time to live + u_char proto; // Protocol + u_short crc; // Header checksum + gr_ip_address saddr; // Source address + gr_ip_address daddr; // Destination address + u_int op_pad; // Option + Padding +} gr_ip_header; + + +/* UDP header*/ +typedef struct gr_udp_header +{ + u_short sport; // Source port + u_short dport; // Destination port + u_short len; // Datagram length + u_short crc; // Checksum +} gr_udp_header; + + +gr_complex_ip_packet_source::sptr +gr_complex_ip_packet_source::make(std::string src_device, + const std::string &origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + const std::string &wire_sample_type, + size_t item_size, + bool IQ_swap_) +{ + return gnuradio::get_initial_sptr(new gr_complex_ip_packet_source(std::move(src_device), + origin_address, + udp_port, + udp_packet_size, + n_baseband_channels, + wire_sample_type, + item_size, + IQ_swap_)); +} + + +/* + * The private constructor + */ +gr_complex_ip_packet_source::gr_complex_ip_packet_source(std::string src_device, + __attribute__((unused)) const std::string &origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + const std::string &wire_sample_type, + size_t item_size, + bool IQ_swap_) + : gr::sync_block("gr_complex_ip_packet_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 4, item_size)) // 1 to 4 baseband complex channels +{ + std::cout << "Start Ethernet packet capture\n"; + + d_n_baseband_channels = n_baseband_channels; + if (wire_sample_type == "cbyte") + { + d_wire_sample_type = 1; + d_bytes_per_sample = d_n_baseband_channels * 2; + } + else if (wire_sample_type == "c4bits") + { + d_wire_sample_type = 2; + d_bytes_per_sample = d_n_baseband_channels; + } + else + { + std::cout << "Unknown wire sample type\n"; + exit(0); + } + std::cout << "d_wire_sample_type:" << d_wire_sample_type << std::endl; + d_src_device = std::move(src_device); + d_udp_port = udp_port; + d_udp_payload_size = udp_packet_size; + d_fifo_full = false; + + // allocate signal samples buffer + fifo_buff = new char[FIFO_SIZE]; + fifo_read_ptr = 0; + fifo_write_ptr = 0; + fifo_items = 0; + d_item_size = item_size; + d_IQ_swap = IQ_swap_; + d_sock_raw = 0; + d_pcap_thread = nullptr; + descr = nullptr; + + memset(reinterpret_cast(&si_me), 0, sizeof(si_me)); +} + + +// Called by gnuradio to enable drivers, etc for i/o devices. +bool gr_complex_ip_packet_source::start() +{ + std::cout << "gr_complex_ip_packet_source START\n"; + // open the ethernet device + if (open() == true) + { + // start pcap capture thread + d_pcap_thread = new boost::thread(boost::bind(&gr_complex_ip_packet_source::my_pcap_loop_thread, this, descr)); + return true; + } + else + { + return false; + } +} + + +// Called by gnuradio to disable drivers, etc for i/o devices. +bool gr_complex_ip_packet_source::stop() +{ + std::cout << "gr_complex_ip_packet_source STOP\n"; + if (descr != nullptr) + { + pcap_breakloop(descr); + d_pcap_thread->join(); + pcap_close(descr); + } + return true; +} + + +bool gr_complex_ip_packet_source::open() +{ + char errbuf[PCAP_ERRBUF_SIZE]; + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + // open device for reading + descr = pcap_open_live(d_src_device.c_str(), 1500, 1, 1000, errbuf); + if (descr == nullptr) + { + std::cout << "Error opening Ethernet device " << d_src_device << std::endl; + std::cout << "Fatal Error in pcap_open_live(): " << std::string(errbuf) << std::endl; + return false; + } + // bind UDP port to avoid automatic reply with ICMP port unreachable packets from kernel + d_sock_raw = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (d_sock_raw == -1) + { + std::cout << "Error opening UDP socket" << std::endl; + return false; + } + + // zero out the structure + memset(reinterpret_cast(&si_me), 0, sizeof(si_me)); + + si_me.sin_family = AF_INET; + si_me.sin_port = htons(d_udp_port); + si_me.sin_addr.s_addr = htonl(INADDR_ANY); + + // bind socket to port + if (bind(d_sock_raw, reinterpret_cast(&si_me), sizeof(si_me)) == -1) + { + std::cout << "Error opening UDP socket" << std::endl; + return false; + } + return true; +} + + +gr_complex_ip_packet_source::~gr_complex_ip_packet_source() +{ + if (d_pcap_thread != nullptr) + { + delete d_pcap_thread; + } + delete fifo_buff; + std::cout << "Stop Ethernet packet capture\n"; +} + + +void gr_complex_ip_packet_source::static_pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, + const u_char *packet) +{ + auto *bridge = reinterpret_cast(args); + bridge->pcap_callback(args, pkthdr, packet); +} + + +void gr_complex_ip_packet_source::pcap_callback(__attribute__((unused)) u_char *args, __attribute__((unused)) const struct pcap_pkthdr *pkthdr, + const u_char *packet) +{ + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + + const gr_ip_header *ih; + const gr_udp_header *uh; + + // eth frame parameters + // **** UDP RAW PACKET DECODER **** + if ((packet[12] == 0x08) & (packet[13] == 0x00)) // IP FRAME + { + // retrieve the position of the ip header + ih = reinterpret_cast(packet + 14); // length of ethernet header + + // retrieve the position of the udp header + u_int ip_len; + ip_len = (ih->ver_ihl & 0xf) * 4; + uh = reinterpret_cast(reinterpret_cast(ih) + ip_len); + + // convert from network byte order to host byte order + //u_short sport; + u_short dport; + dport = ntohs(uh->dport); + //sport = ntohs(uh->sport); + if (dport == d_udp_port) + { + // print ip addresses and udp ports + // printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n", + // ih->saddr.byte1, + // ih->saddr.byte2, + // ih->saddr.byte3, + // ih->saddr.byte4, + // sport, + // ih->daddr.byte1, + // ih->daddr.byte2, + // ih->daddr.byte3, + // ih->daddr.byte4, + // dport); + // std::cout<<"uh->len:"<len)<len) - 8; // total udp packet length minus the header length + // read the payload bytes and insert them into the shared circular buffer + const u_char *udp_payload = (reinterpret_cast(uh) + sizeof(gr_udp_header)); + if (fifo_items <= (FIFO_SIZE - payload_length_bytes)) + { + int aligned_write_items = FIFO_SIZE - fifo_write_ptr; + if (aligned_write_items >= payload_length_bytes) + { + // write all in a single memcpy + memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], payload_length_bytes); // size in bytes + fifo_write_ptr += payload_length_bytes; + if (fifo_write_ptr == FIFO_SIZE) fifo_write_ptr = 0; + fifo_items += payload_length_bytes; + } + else + { + // two step wrap write + memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], aligned_write_items); // size in bytes + fifo_write_ptr = payload_length_bytes - aligned_write_items; + memcpy(&fifo_buff[0], &udp_payload[aligned_write_items], fifo_write_ptr); // size in bytes + fifo_items += payload_length_bytes; + } + } + else + { + // notify overflow + std::cout << "O" << std::flush; + } + } + } +} + + +void gr_complex_ip_packet_source::my_pcap_loop_thread(pcap_t *pcap_handle) +{ + pcap_loop(pcap_handle, -1, gr_complex_ip_packet_source::static_pcap_callback, reinterpret_cast(this)); +} + + +void gr_complex_ip_packet_source::demux_samples(gr_vector_void_star output_items, int num_samples_readed) +{ + int8_t real; + int8_t imag; + uint8_t tmp_char2; + for (int n = 0; n < num_samples_readed; n++) + { + switch (d_wire_sample_type) + { + case 1: // interleaved byte samples + for (auto &output_item : output_items) + { + real = fifo_buff[fifo_read_ptr++]; + imag = fifo_buff[fifo_read_ptr++]; + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + else + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + } + break; + case 2: // 4-bit samples + for (auto &output_item : output_items) + { + tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F; + if (tmp_char2 >= 8) + { + real = 2 * (tmp_char2 - 16) + 1; + } + else + { + real = 2 * tmp_char2 + 1; + } + tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4; + tmp_char2 = tmp_char2 & 0x0F; + if (tmp_char2 >= 8) + { + imag = 2 * (tmp_char2 - 16) + 1; + } + else + { + imag = 2 * tmp_char2 + 1; + } + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + else + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + } + break; + default: + std::cout << "Unknown wire sample type\n"; + exit(0); + } + if (fifo_read_ptr == FIFO_SIZE) fifo_read_ptr = 0; + } +} + + +int gr_complex_ip_packet_source::work(int noutput_items, + __attribute__((unused)) gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + // send samples to next GNU Radio block + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + if (fifo_items == 0) return 0; + + if (output_items.size() > static_cast(d_n_baseband_channels)) + { + std::cout << "Configuration error: more baseband channels connected than the available in the UDP source\n"; + exit(0); + } + int num_samples_readed; + int bytes_requested; + switch (d_wire_sample_type) + { + case 1: // complex byte samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; // read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; // read what we have + } + break; + case 2: // complex 4 bits samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; // read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; // read what we have + } + break; + default: // complex byte samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; // read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; // read what we have + } + } + + bytes_requested = num_samples_readed * d_bytes_per_sample; + // read all in a single loop + demux_samples(output_items, num_samples_readed); // it also increases the fifo read pointer + // update fifo items + fifo_items = fifo_items - bytes_requested; + + for (uint64_t n = 0; n < output_items.size(); n++) + { + produce(static_cast(n), num_samples_readed); + } + return this->WORK_CALLED_PRODUCE; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h new file mode 100644 index 000000000..d008e1314 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h @@ -0,0 +1,115 @@ +/*! + * \file gr_complex_ip_packet_source.h + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H +#define INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class gr_complex_ip_packet_source : virtual public gr::sync_block +{ +private: + boost::mutex d_mutex; + pcap_t *descr; //ethernet pcap device descriptor + + char *fifo_buff; + + int fifo_read_ptr; + int fifo_write_ptr; + int fifo_items; + int d_sock_raw; + int d_udp_port; + struct sockaddr_in si_me; + std::string d_src_device; + std::string d_origin_address; + int d_udp_payload_size; + bool d_fifo_full; + + int d_n_baseband_channels; + int d_wire_sample_type; + int d_bytes_per_sample; + size_t d_item_size; + bool d_IQ_swap; + + boost::thread *d_pcap_thread; + /*! + * \brief + * Opens the ethernet device using libpcap raw capture mode + * If any of these fail, the fuction retuns the error and exits. + */ + bool open(); + + void demux_samples(gr_vector_void_star output_items, int num_samples_readed); + void my_pcap_loop_thread(pcap_t *pcap_handle); + void pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet); + static void static_pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet); + +public: + typedef boost::shared_ptr sptr; + static sptr make(std::string src_device, + const std::string &origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + const std::string &wire_sample_type, + size_t item_size, + bool IQ_swap_); + gr_complex_ip_packet_source(std::string src_device, + const std::string &origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + const std::string &wire_sample_type, + size_t item_size, + bool IQ_swap_); + ~gr_complex_ip_packet_source(); + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + // Called by gnuradio to enable drivers, etc for i/o devices. + bool start(); + // Called by gnuradio to disable drivers, etc for i/o devices. + bool stop(); +}; + +#endif /* INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H */ diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc new file mode 100644 index 000000000..2ae97cd1d --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc @@ -0,0 +1,486 @@ +/*! + * \file labsat23_source.cc + * + * \brief Unpacks the Labsat 2 (ls2) and (ls3) capture files + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "labsat23_source.h" +#include +#include +#include + + +labsat23_source_sptr labsat23_make_source(const char *signal_file_basename, int channel_selector) +{ + return labsat23_source_sptr(new labsat23_source(signal_file_basename, channel_selector)); +} + + +std::string labsat23_source::generate_filename() +{ + std::ostringstream ss; + ss << std::setw(4) << std::setfill('0') << d_current_file_number; + return d_signal_file_basename + "_" + ss.str() + ".LS3"; +} + + +labsat23_source::labsat23_source(const char *signal_file_basename, + int channel_selector) : gr::block("labsat23_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + if (channel_selector < 1 or channel_selector > 2) + { + std::cout << "Labsat source config error: channel selection out of bounds, check gnss-sdr config file" << std::endl; + exit(1); + } + d_channel_selector_config = channel_selector; + d_header_parsed = false; + d_bits_per_sample = 0; + d_current_file_number = 0; + d_labsat_version = 0; + d_ref_clock = 0; + d_channel_selector = 0; + d_signal_file_basename = std::string(signal_file_basename); + + std::string signal_file; + this->set_output_multiple(8); + signal_file = generate_filename(); + binary_input_file = new std::ifstream(signal_file.c_str(), std::ios::in | std::ios::binary); + + if (binary_input_file->is_open()) + { + std::cout << "Labsat file source is reading samples from " << signal_file << std::endl; + } + else + { + std::cout << "Labsat file " << signal_file << " could not be opened!" << std::endl; + delete binary_input_file; + exit(1); + } +} + + +labsat23_source::~labsat23_source() +{ + if (binary_input_file->is_open()) + { + binary_input_file->close(); + } + delete binary_input_file; +} + + +int labsat23_source::getBit(uint8_t byte, int position) +{ + return (byte >> position) & 0x01; +} + + +void labsat23_source::decode_samples_one_channel(int16_t input_short, gr_complex *out, int type) +{ + std::bitset<16> bs(input_short); + switch (type) + { + case 2: + //two bits per sample, 8 samples per int16 + for (int i = 0; i < 8; i++) + { + out[i] = gr_complex(static_cast(bs[15 - (2 * i)]), + static_cast(bs[14 - (2 * i)])); + out[i] = out[i] * gr_complex(2, 0) - gr_complex(1, 1); + } + break; + case 4: + //four bits per sample, 4 samples per int16 + for (int i = 0; i < 4; i++) + { + out[i] = gr_complex(0.0, 0.0); + //In-Phase + if (bs[15 - 4 * i]) + { + if (bs[13 - 4 * i]) //11 + { + out[i] += gr_complex(-1, 0); + } + else //10 + { + out[i] += gr_complex(-2, 0); + } + } + else + { + if (bs[13 - 4 * i]) //01 + { + out[i] += gr_complex(1, 0); + } + } + + //Quadrature + if (bs[14 - 4 * i]) + { + if (bs[12 - 4 * i]) //11 + { + out[i] += gr_complex(0, -1); + } + else //10 + { + out[i] += gr_complex(0, -2); + } + } + else + { + if (bs[12 - 4 * i]) //01 + { + out[i] += gr_complex(0, 1); + } + } + out[i] += gr_complex(0.5, 0.5); + } + break; + } +} + + +int labsat23_source::general_work(int noutput_items, + __attribute__((unused)) gr_vector_int &ninput_items, + __attribute__((unused)) gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + auto *out = reinterpret_cast(output_items[0]); + + if (d_header_parsed == false) + { + if (binary_input_file->eof() == false) + { + char memblock[1024]; + binary_input_file->read(memblock, 1024); + //parse Labsat header + //check preamble + int byte_counter = 0; + bool preamble_ok = true; + for (int i = 0; i < 8; i++) + { + if (memblock[byte_counter] != 0x00) preamble_ok = false; + //std::cout << "H[" << i << "]:" << (int)memblock[byte_counter] << std::endl; + byte_counter++; + } + + if (preamble_ok == false) + { + std::cout << "Labsat source do not detect the preamble in the selected file" << std::endl; + return -1; + } + + // check Labsat version + if (memblock[byte_counter] == 0x4C and memblock[byte_counter + 1] == 0x53 and memblock[byte_counter + 2] == 0x32) + { + d_labsat_version = 2; + std::cout << "Labsat file version 2 detected" << std::endl; + } + + if (memblock[byte_counter] == 0x4C and memblock[byte_counter + 1] == 0x53 and memblock[byte_counter + 2] == 0x33) + { + d_labsat_version = 3; + std::cout << "Labsat file version 3 detected" << std::endl; + } + + if (d_labsat_version == 0) + { + std::cout << "Labsat source do not detect the labsat version in file header" << std::endl; + return -1; + } + + byte_counter += 3; + + int sub_version = static_cast(memblock[byte_counter]); + + std::cout << "Labsat file sub version " << sub_version << std::endl; + + byte_counter++; + + int header_bytes = 0; + header_bytes += memblock[byte_counter] | (memblock[byte_counter + 1] << 8) | (memblock[byte_counter + 2] << 16) | (memblock[byte_counter + 3] << 24); + + byte_counter += 4; + //std::cout << "header_bytes=" << header_bytes << std::endl; + + // read first section + // section ID (little-endian) + uint8_t section_id = static_cast(memblock[byte_counter]) + static_cast(memblock[byte_counter + 1]) * 256; + //std::cout << "Section ID: " << (int)section_id << std::endl; + byte_counter += 2; + + //uint8_t section_lenght_bytes = 0; + //section_lenght_bytes += memblock[byte_counter] | (memblock[byte_counter + 1] << 8) | (memblock[byte_counter + 2] << 16) | (memblock[byte_counter + 3] << 24); + //std::cout << "section_lenght_bytes=" << (int)section_lenght_bytes << std::endl; + + byte_counter += 4; + if (section_id == 2) + { + d_ref_clock = static_cast(memblock[byte_counter]); + switch (d_ref_clock) + { + case 0: + std::cout << "Labsat reference clock: internal OXCO" << std::endl; + break; + case 1: + std::cout << "Labsat reference clock: internal TXCO" << std::endl; + break; + case 2: + std::cout << "Labsat reference clock: external 10 MHz" << std::endl; + break; + case 3: + std::cout << "Labsat reference clock: external 16.386 MHz" << std::endl; + break; + default: + std::cout << "Labsat Unknown reference clock ID " << static_cast(d_ref_clock) << std::endl; + } + byte_counter++; + d_bits_per_sample = static_cast(memblock[byte_counter]); + switch (d_bits_per_sample) + { + case 2: + std::cout << "Labsat is using 2 bits per sample" << std::endl; + break; + case 4: + std::cout << "Labsat is using 4 bits per sample" << std::endl; + break; + default: + std::cout << "Labsat Unknown bits per sample ID " << static_cast(d_bits_per_sample) << std::endl; + return -1; + } + + byte_counter++; + d_channel_selector = static_cast(memblock[byte_counter]); + switch (d_channel_selector) + { + case 0: + std::cout << "Available channels: Channel A + B, 1 bit quantisation" << std::endl; + break; + case 1: + std::cout << "Available channels: Channel A, 1 bit quantisation" << std::endl; + break; + case 2: + std::cout << "Available channels: Channel B, 1 bit quantisation" << std::endl; + break; + case 3: + std::cout << "Available channels: Channel A, 2 bit quantisation" << std::endl; + break; + case 4: + std::cout << "Available channels: Channel B, 2 bit quantisation" << std::endl; + break; + default: + std::cout << "Unknown channel selection ID " << static_cast(d_channel_selector) << std::endl; + return -1; + } + + // check if the selected channel in config file match the file encoding + if (d_channel_selector_config == 2 and d_channel_selector != 0) + { + std::cout << "Labsat source channel config inconsistency: channel 2 is selected but the file has only one channel" << std::endl; + return -1; + } + + //todo: Add support for dual channel files + if (d_channel_selector == 0) + { + std::cout << "ERROR: Labsat file contains more than one channel and it is not currently supported by Labsat signal source." << std::endl; + return -1; + } + byte_counter++; + auto quantization = static_cast(memblock[byte_counter]); + switch (quantization) + { + case 1: + std::cout << "1 bit per sample" << std::endl; + break; + case 2: + std::cout << "2 bit per sample" << std::endl; + break; + default: + std::cout << "Unknown quantization ID " << static_cast(quantization) << std::endl; + } + byte_counter++; + auto channel_a_constellation = static_cast(memblock[byte_counter]); + switch (channel_a_constellation) + { + case 0: + std::cout << "Labsat Channel A is GPS" << std::endl; + break; + case 1: + std::cout << "Labsat Channel A is GLONASS" << std::endl; + break; + case 2: + std::cout << "Labsat Channel A is BDS" << std::endl; + break; + default: + std::cout << "Unknown channel A constellation ID " << static_cast(channel_a_constellation) << std::endl; + } + byte_counter++; + auto channel_b_constellation = static_cast(memblock[byte_counter]); + switch (channel_b_constellation) + { + case 0: + std::cout << "Labsat Channel B is GPS" << std::endl; + break; + case 1: + std::cout << "Labsat Channel B is GLONASS" << std::endl; + break; + case 2: + std::cout << "Labsat Channel B is BDS" << std::endl; + break; + default: + std::cout << "Unknown channel B constellation ID " << static_cast(channel_b_constellation) << std::endl; + } + + // end of header + d_header_parsed = true; + // seek file to the first signal sample + binary_input_file->clear(); + binary_input_file->seekg(header_bytes, binary_input_file->beg); + return 0; + } + std::cout << "Labsat file header error: section 2 is not available." << std::endl; + return -1; + } + std::cout << "Labsat file read error: file is empty." << std::endl; + return -1; + } + + + // ready to start reading samples + switch (d_bits_per_sample) + { + case 2: + { + switch (d_channel_selector) + { + case 0: + // dual channel 2 bits per complex sample + break; + default: + // single channel 2 bits per complex sample (1 bit I + 1 bit Q, 8 samples per int16) + int n_int16_to_read = noutput_items / 8; + if (n_int16_to_read > 0) + { + int16_t memblock[n_int16_to_read]; + binary_input_file->read(reinterpret_cast(memblock), n_int16_to_read * 2); + n_int16_to_read = binary_input_file->gcount() / 2; //from bytes to int16 + if (n_int16_to_read > 0) + { + int output_pointer = 0; + for (int i = 0; i < n_int16_to_read; i++) + { + decode_samples_one_channel(memblock[i], &out[output_pointer], d_bits_per_sample); + output_pointer += 8; + } + return output_pointer; + } + + // trigger the read of the next file in the sequence + std::cout << "End of current file, reading the next Labsat file in sequence: " << generate_filename() << std::endl; + + d_current_file_number++; + binary_input_file->close(); + binary_input_file->open(generate_filename().c_str(), std::ios::in | std::ios::binary); + if (binary_input_file->is_open()) + { + std::cout << "Labsat file source is reading samples from " << generate_filename() << std::endl; + } + else + { + std::cout << "Last file reached, LabSat source stop" << std::endl; + return -1; + } + } + else + { + return 0; + } + }; + break; + } + case 4: + { + switch (d_channel_selector) + { + case 0: + // dual channel + break; + default: + // single channel 4 bits per complex sample (2 bit I + 2 bit Q, 4 samples per int16) + int n_int16_to_read = noutput_items / 4; + if (n_int16_to_read > 0) + { + int16_t memblock[n_int16_to_read]; + binary_input_file->read(reinterpret_cast(memblock), n_int16_to_read * 2); + n_int16_to_read = binary_input_file->gcount() / 2; //from bytes to int16 + if (n_int16_to_read > 0) + { + int output_pointer = 0; + for (int i = 0; i < n_int16_to_read; i++) + { + decode_samples_one_channel(memblock[i], &out[output_pointer], d_bits_per_sample); + output_pointer += 4; + } + return output_pointer; + } + + // trigger the read of the next file in the sequence + std::cout << "End of current file, reading the next Labsat file in sequence: " << generate_filename() << std::endl; + + d_current_file_number++; + binary_input_file->close(); + binary_input_file->open(generate_filename().c_str(), std::ios::in | std::ios::binary); + if (binary_input_file->is_open()) + { + std::cout << "Labsat file source is reading samples from " << generate_filename() << std::endl; + } + else + { + std::cout << "Last file reached, LabSat source stop" << std::endl; + return -1; + } + } + else + { + return 0; + } + } + break; + } + default: + { + return -1; + } + } + + std::cout << "Warning!!" << std::endl; + return 0; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h new file mode 100644 index 000000000..e7776efd9 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h @@ -0,0 +1,75 @@ +/*! + * \file labsat23_source.h + * + * \brief Unpacks the Labsat 2 (ls2) and (ls3) capture files + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_LABSAT23_SOURCE_H +#define GNSS_SDR_LABSAT23_SOURCE_H + +#include +#include +#include +#include + + +class labsat23_source; + +typedef boost::shared_ptr labsat23_source_sptr; + +labsat23_source_sptr labsat23_make_source(const char *signal_file_basename, int channel_selector); + +/*! + * \brief This class implements conversion between Labsat2 and 3 format byte packet samples to gr_complex + */ +class labsat23_source : public gr::block +{ +private: + friend labsat23_source_sptr labsat23_make_source_sptr(const char *signal_file_basename, int channel_selector); + std::string generate_filename(); + void decode_samples_one_channel(int16_t input_short, gr_complex *out, int type); + int getBit(uint8_t byte, int position); + bool d_header_parsed; + uint8_t d_channel_selector; + int d_channel_selector_config; + int d_current_file_number; + uint8_t d_labsat_version; + std::string d_signal_file_basename; + std::ifstream *binary_input_file; + uint8_t d_ref_clock; + uint8_t d_bits_per_sample; + +public: + labsat23_source(const char *signal_file_basename, int channel_selector); + ~labsat23_source(); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.cc b/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.cc index 52e565a28..f43f3e90c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,15 +25,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "rtl_tcp_signal_source_c.h" #include "rtl_tcp_commands.h" -#include #include +#include #include using google::LogMessage; @@ -43,69 +43,70 @@ using boost::asio::ip::tcp; // Buffer constants // TODO: Make these configurable -enum { - RTL_TCP_BUFFER_SIZE = 1024 * 16, // 16 KB - RTL_TCP_PAYLOAD_SIZE = 1024 * 4 // 4 KB +enum +{ + RTL_TCP_BUFFER_SIZE = 1024 * 16, // 16 KB + RTL_TCP_PAYLOAD_SIZE = 1024 * 4 // 4 KB }; rtl_tcp_signal_source_c_sptr rtl_tcp_make_signal_source_c(const std::string &address, - short port, - bool flip_iq) + int16_t port, + bool flip_iq) { - return gnuradio::get_initial_sptr (new rtl_tcp_signal_source_c (address, - port, - flip_iq)); + return gnuradio::get_initial_sptr(new rtl_tcp_signal_source_c(address, + port, + flip_iq)); } rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address, - short port, - bool flip_iq) -: gr::sync_block ("rtl_tcp_signal_source_c", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(1, 1, sizeof(gr_complex))), - socket_ (io_service_), - data_ (RTL_TCP_PAYLOAD_SIZE), - flip_iq_(flip_iq), - buffer_ (RTL_TCP_BUFFER_SIZE), - unread_ (0) + int16_t port, + bool flip_iq) + : gr::sync_block("rtl_tcp_signal_source_c", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, sizeof(gr_complex))), + socket_(io_service_), + data_(RTL_TCP_PAYLOAD_SIZE), + flip_iq_(flip_iq), + buffer_(RTL_TCP_BUFFER_SIZE), + unread_(0) { boost::system::error_code ec; // 1. Setup lookup table for (unsigned i = 0; i < 0xff; i++) { - lookup_[i] = ((float)(i & 0xff) - 127.4f) * (1.0f / 128.0f); + lookup_[i] = (static_cast(i & 0xff) - 127.4f) * (1.0f / 128.0f); } // 2. Set socket options - ip::address addr = ip::address::from_string (address, ec); + ip::address addr = ip::address::from_string(address, ec); if (ec) { std::cout << address << " is not an IP address" << std::endl; - LOG (ERROR) << address << " is not an IP address"; + LOG(ERROR) << address << " is not an IP address"; return; } - ip::tcp::endpoint ep (addr, port); - socket_.open (ep.protocol( ), ec); + ip::tcp::endpoint ep(addr, port); + socket_.open(ep.protocol(), ec); if (ec) { std::cout << "Failed to open socket." << std::endl; - LOG (ERROR) << "Failed to open socket."; + LOG(ERROR) << "Failed to open socket."; } - socket_.set_option (boost::asio::socket_base::reuse_address (true), ec); + socket_.set_option(boost::asio::socket_base::reuse_address(true), ec); if (ec) { std::cout << "Failed to set reuse address option: " << ec << std::endl; - LOG (WARNING) << "Failed to set reuse address option"; + LOG(WARNING) << "Failed to set reuse address option"; } - socket_.set_option (boost::asio::socket_base::linger (true, 0), ec); + socket_.set_option(boost::asio::socket_base::linger(true, 0), ec); if (ec) { std::cout << "Failed to set linger option: " << ec << std::endl; - LOG (WARNING) << "Failed to set linger option"; + LOG(WARNING) << "Failed to set linger option"; } // 3. Connect socket @@ -114,162 +115,130 @@ rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address, if (ec) { std::cout << "Failed to connect to " << addr << ":" << port - << "(" << ec << ")" << std::endl; - LOG (ERROR) << "Failed to connect to " << addr << ":" << port - << "(" << ec << ")"; + << "(" << ec << ")" << std::endl; + LOG(ERROR) << "Failed to connect to " << addr << ":" << port + << "(" << ec << ")"; return; } std::cout << "Connected to " << addr << ":" << port << std::endl; - LOG (INFO) << "Connected to " << addr << ":" << port; + LOG(INFO) << "Connected to " << addr << ":" << port; // 4. Set nodelay - socket_.set_option (tcp::no_delay (true), ec); + socket_.set_option(tcp::no_delay(true), ec); if (ec) { std::cout << "Failed to set no delay option." << std::endl; - LOG (WARNING) << "Failed to set no delay option"; + LOG(WARNING) << "Failed to set no delay option"; } // 5. Receive dongle info - ec = info_.read (socket_); + ec = info_.read(socket_); if (ec) { std::cout << "Failed to read dongle info." << std::endl; - LOG (WARNING) << "Failed to read dongle info"; + LOG(WARNING) << "Failed to read dongle info"; } - else if (info_.is_valid ()) + else if (info_.is_valid()) { - std::cout << "Found " << info_.get_type_name() << " tuner." << std::endl; - LOG (INFO) << "Found " << info_.get_type_name() << " tuner."; + std::cout << "Found " << info_.get_type_name() << " tuner." << std::endl; + LOG(INFO) << "Found " << info_.get_type_name() << " tuner."; } // 6. Start reading - boost::asio::async_read (socket_, boost::asio::buffer (data_), - boost::bind (&rtl_tcp_signal_source_c::handle_read, - this, _1, _2)); - boost::thread (boost::bind (&boost::asio::io_service::run, &io_service_)); + boost::asio::async_read(socket_, boost::asio::buffer(data_), + boost::bind(&rtl_tcp_signal_source_c::handle_read, + this, _1, _2)); + boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_)); } -rtl_tcp_signal_source_c::~rtl_tcp_signal_source_c() +rtl_tcp_signal_source_c::~rtl_tcp_signal_source_c() // NOLINT(modernize-use-equals-default) { - io_service_.stop (); + mutex_.unlock(); + io_service_.stop(); + not_empty_.notify_one(); + not_full_.notify_one(); } -int rtl_tcp_signal_source_c::work (int noutput_items, - gr_vector_const_void_star &/*input_items*/, - gr_vector_void_star &output_items) -{ - gr_complex *out = reinterpret_cast ( output_items[0] ); - int i = 0; - if (io_service_.stopped ()) - { - return -1; - } - - { - boost::mutex::scoped_lock lock (mutex_); - not_empty_.wait (lock, boost::bind (&rtl_tcp_signal_source_c::not_empty, - this)); - - for ( ; i < noutput_items && unread_ > 1; i++ ) - { - float re = buffer_[--unread_]; - float im = buffer_[--unread_]; - if (flip_iq_) - { - out[i] = gr_complex (im, re); - } - else - { - out[i] = gr_complex (re, im); - } - } - } - not_full_.notify_one (); - return i == 0 ? -1 : i; -} - - -void rtl_tcp_signal_source_c::set_frequency (int frequency) +void rtl_tcp_signal_source_c::set_frequency(int frequency) { boost::system::error_code ec = - rtl_tcp_command (RTL_TCP_SET_FREQUENCY, frequency, socket_); + rtl_tcp_command(RTL_TCP_SET_FREQUENCY, frequency, socket_); if (ec) { std::cout << "Failed to set frequency" << std::endl; - LOG (WARNING) << "Failed to set frequency"; + LOG(WARNING) << "Failed to set frequency"; } } -void rtl_tcp_signal_source_c::set_sample_rate (int sample_rate) +void rtl_tcp_signal_source_c::set_sample_rate(int sample_rate) { boost::system::error_code ec = - rtl_tcp_command (RTL_TCP_SET_SAMPLE_RATE, sample_rate, socket_); + rtl_tcp_command(RTL_TCP_SET_SAMPLE_RATE, sample_rate, socket_); if (ec) { std::cout << "Failed to set sample rate" << std::endl; - LOG (WARNING) << "Failed to set sample rate"; + LOG(WARNING) << "Failed to set sample rate"; } } -void rtl_tcp_signal_source_c::set_agc_mode (bool agc) +void rtl_tcp_signal_source_c::set_agc_mode(bool agc) { boost::system::error_code ec = - rtl_tcp_command (RTL_TCP_SET_GAIN_MODE, !agc, socket_); + rtl_tcp_command(RTL_TCP_SET_GAIN_MODE, !agc, socket_); if (ec) { std::cout << "Failed to set gain mode" << std::endl; - LOG (WARNING) << "Failed to set gain mode"; + LOG(WARNING) << "Failed to set gain mode"; } - ec = rtl_tcp_command (RTL_TCP_SET_AGC_MODE, agc, socket_); + ec = rtl_tcp_command(RTL_TCP_SET_AGC_MODE, agc, socket_); if (ec) { std::cout << "Failed to set gain mode" << std::endl; - LOG (WARNING) << "Failed to set gain mode"; + LOG(WARNING) << "Failed to set gain mode"; } } -void rtl_tcp_signal_source_c::set_gain (int gain) +void rtl_tcp_signal_source_c::set_gain(int gain) { - unsigned clipped = static_cast (info_.clip_gain (gain) * 10.0); - boost::system::error_code ec = rtl_tcp_command (RTL_TCP_SET_GAIN, clipped, socket_); + auto clipped = static_cast(info_.clip_gain(gain) * 10.0); + boost::system::error_code ec = rtl_tcp_command(RTL_TCP_SET_GAIN, clipped, socket_); if (ec) { std::cout << "Failed to set gain" << std::endl; - LOG (WARNING) << "Failed to set gain"; + LOG(WARNING) << "Failed to set gain"; } } -void rtl_tcp_signal_source_c::set_if_gain (int gain) +void rtl_tcp_signal_source_c::set_if_gain(int gain) { // from gr-osmosdr - struct range { + struct range + { double start, stop, step; }; - if (info_.get_tuner_type () != rtl_tcp_dongle_info::TUNER_E4000) + if (info_.get_tuner_type() != rtl_tcp_dongle_info::TUNER_E4000) { return; } std::vector ranges = { - { -3, 6, 9 }, - { 0, 9, 3 }, - { 0, 9, 3 }, - { 0, 2, 1 }, - { 3, 15, 3}, - { 3, 15, 3} - }; + {-3, 6, 9}, + {0, 9, 3}, + {0, 9, 3}, + {0, 2, 1}, + {3, 15, 3}, + {3, 15, 3}}; - std::map gains; - for (int i = 0; i < static_cast(ranges.size ()); i++) + std::map gains; + for (int i = 0; i < static_cast(ranges.size()); i++) { - gains[i+1] = ranges[i].start; + gains[i + 1] = ranges[i].start; } for (int i = ranges.size() - 1; i >= 0; i--) @@ -280,7 +249,7 @@ void rtl_tcp_signal_source_c::set_if_gain (int gain) for (double g = r.start; g < r.stop; g += r.step) { double sum = 0; - for (int j = 0; j < static_cast ( gains.size() ); j++) + for (int j = 0; j < static_cast(gains.size()); j++) { if (i == j) { @@ -291,71 +260,105 @@ void rtl_tcp_signal_source_c::set_if_gain (int gain) sum += gains[j + 1]; } } - double err = std::abs (gain - sum); + double err = std::abs(gain - sum); if (err < error) { error = err; - gains[i+1] = g; + gains[i + 1] = g; } } } for (unsigned stage = 1; stage <= gains.size(); stage++) { - int stage_gain = static_cast( gains[stage] * 10 ); + int stage_gain = static_cast(gains[stage] * 10); unsigned param = (stage << 16) | (stage_gain & 0xffff); - boost::system::error_code ec = rtl_tcp_command (RTL_TCP_SET_IF_GAIN, param, socket_); + boost::system::error_code ec = rtl_tcp_command(RTL_TCP_SET_IF_GAIN, param, socket_); if (ec) { std::cout << "Failed to set if gain" << std::endl; - LOG (WARNING) << "Failed to set if gain"; + LOG(WARNING) << "Failed to set if gain"; } } } - -void rtl_tcp_signal_source_c::handle_read (const boost::system::error_code &ec, - size_t bytes_transferred) +void rtl_tcp_signal_source_c::handle_read(const boost::system::error_code &ec, + size_t bytes_transferred) { if (ec) { std::cout << "Error during read: " << ec << std::endl; - LOG (WARNING) << "Error during read: " << ec; - boost::mutex::scoped_lock lock (mutex_); - io_service_.stop (); - not_empty_.notify_one (); + LOG(WARNING) << "Error during read: " << ec; + boost::mutex::scoped_lock lock(mutex_); + io_service_.stop(); + not_empty_.notify_one(); } else { { // Unpack read data - boost::mutex::scoped_lock lock (mutex_); - not_full_.wait (lock, - boost::bind (&rtl_tcp_signal_source_c::not_full, - this)); + boost::mutex::scoped_lock lock(mutex_); + not_full_.wait(lock, + boost::bind(&rtl_tcp_signal_source_c::not_full, + this)); for (size_t i = 0; i < bytes_transferred; i++) { - while (!not_full( )) + while (!not_full()) { // uh-oh, buffer overflow // wait until there's space for more - not_empty_.notify_one (); // needed? - not_full_.wait (lock, - boost::bind (&rtl_tcp_signal_source_c::not_full, - this)); + not_empty_.notify_one(); // needed? + not_full_.wait(lock, + boost::bind(&rtl_tcp_signal_source_c::not_full, + this)); } - buffer_.push_front (lookup_[data_[i]]); + buffer_.push_front(lookup_[data_[i]]); unread_++; } } // let woker know that more data is available - not_empty_.notify_one (); + not_empty_.notify_one(); // Read some more - boost::asio::async_read (socket_, - boost::asio::buffer (data_), - boost::bind (&rtl_tcp_signal_source_c::handle_read, - this, _1, _2)); + boost::asio::async_read(socket_, + boost::asio::buffer(data_), + boost::bind(&rtl_tcp_signal_source_c::handle_read, + this, _1, _2)); } } + + +int rtl_tcp_signal_source_c::work(int noutput_items, + gr_vector_const_void_star & /*input_items*/, + gr_vector_void_star &output_items) +{ + gr_complex *out = reinterpret_cast(output_items[0]); + int i = 0; + if (io_service_.stopped()) + { + return -1; + } + + { + boost::mutex::scoped_lock lock(mutex_); + not_empty_.wait(lock, boost::bind(&rtl_tcp_signal_source_c::not_empty, + this)); + + for (; i < noutput_items && unread_ > 1; i++) + { + float re = buffer_[--unread_]; + float im = buffer_[--unread_]; + if (flip_iq_) + { + out[i] = gr_complex(im, re); + } + else + { + out[i] = gr_complex(re, im); + } + } + } + not_full_.notify_one(); + return i == 0 ? -1 : i; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.h b/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.h index 7ce11eeb3..62e7f2c07 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.h +++ b/src/algorithms/signal_source/gnuradio_blocks/rtl_tcp_signal_source_c.h @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,32 +30,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #ifndef GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_C_H -#define GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_C_H +#define GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_C_H #include "rtl_tcp_dongle_info.h" -#include -#include -#include -#include -#include #include +#include #include +#include +#include +#include +#include +#include class rtl_tcp_signal_source_c; typedef boost::shared_ptr - rtl_tcp_signal_source_c_sptr; + rtl_tcp_signal_source_c_sptr; rtl_tcp_signal_source_c_sptr rtl_tcp_make_signal_source_c(const std::string &address, - short port, - bool flip_iq = false); + int16_t port, + bool flip_iq = false); /*! * \brief This class reads interleaved I/Q samples @@ -66,27 +67,27 @@ class rtl_tcp_signal_source_c : public gr::sync_block public: ~rtl_tcp_signal_source_c(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); - void set_frequency (int frequency); - void set_sample_rate (int sample_rate); - void set_agc_mode (bool agc); - void set_gain (int gain); - void set_if_gain (int gain); + void set_frequency(int frequency); + void set_sample_rate(int sample_rate); + void set_agc_mode(bool agc); + void set_gain(int gain); + void set_if_gain(int gain); private: typedef boost::circular_buffer_space_optimized buffer_type; friend rtl_tcp_signal_source_c_sptr rtl_tcp_make_signal_source_c(const std::string &address, - short port, - bool flip_iq); + int16_t port, + bool flip_iq); rtl_tcp_signal_source_c(const std::string &address, - short port, - bool flip_iq); + int16_t port, + bool flip_iq); rtl_tcp_dongle_info info_; @@ -107,16 +108,18 @@ private: boost::array lookup_; // async read callback - void handle_read (const boost::system::error_code &ec, - size_t bytes_transferred); + void handle_read(const boost::system::error_code &ec, + size_t bytes_transferred); - inline bool not_full ( ) const { - return unread_ < buffer_.capacity( ); + inline bool not_full() const + { + return unread_ < buffer_.capacity(); } - inline bool not_empty ( ) const { - return unread_ > 0 || io_service_.stopped (); + inline bool not_empty() const + { + return unread_ > 0 || io_service_.stopped(); } }; -#endif //GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_C_H +#endif // GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_C_H diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.cc index df79dc8a3..1fd5c2032 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.cc @@ -5,7 +5,7 @@ * \author Cillian O'Driscoll cillian.odriscoll (at) gmail.com * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,18 +34,20 @@ struct byte_2bit_struct { - signed sample_0:2; // <- 2 bits wide only - signed sample_1:2; // <- 2 bits wide only - signed sample_2:2; // <- 2 bits wide only - signed sample_3:2; // <- 2 bits wide only + signed sample_0 : 2; // <- 2 bits wide only + signed sample_1 : 2; // <- 2 bits wide only + signed sample_2 : 2; // <- 2 bits wide only + signed sample_3 : 2; // <- 2 bits wide only }; + union byte_and_samples { int8_t byte; byte_2bit_struct samples; }; + bool systemIsBigEndian() { union @@ -54,18 +56,22 @@ bool systemIsBigEndian() char c[4]; } test_int = {0x01020304}; - return test_int.c[0] == 1; + return test_int.c[0] == 1; } + bool systemBytesAreBigEndian() { - byte_and_samples b; + byte_and_samples b{}; b.byte = static_cast(0x01); - if(*(char *)&b.byte == 1) return false; - else return true; + if (*reinterpret_cast(&b.byte) == 1) + return false; + + return true; } -void swapEndianness( int8_t const *in, std::vector< int8_t > &out, size_t item_size, unsigned int ninput_items ) + +void swapEndianness(int8_t const *in, std::vector &out, size_t item_size, unsigned int ninput_items) { unsigned int i; unsigned int j = 0; @@ -73,152 +79,146 @@ void swapEndianness( int8_t const *in, std::vector< int8_t > &out, size_t item_s int l = 0; size_t skip = item_size - 1; - for( i = 0; i < ninput_items; ++i ) - { - k = j + skip; - l = j; - while( k >= l ) + for (i = 0; i < ninput_items; ++i) { - out[j++] = in[k--]; + k = j + skip; + l = j; + while (k >= l) + { + out[j++] = in[k--]; + } } - } } -unpack_2bit_samples_sptr make_unpack_2bit_samples( bool big_endian_bytes, - size_t item_size, - bool big_endian_items, - bool reverse_interleaving ) + +unpack_2bit_samples_sptr make_unpack_2bit_samples(bool big_endian_bytes, + size_t item_size, + bool big_endian_items, + bool reverse_interleaving) { return unpack_2bit_samples_sptr( - new unpack_2bit_samples( big_endian_bytes, - item_size, - big_endian_items, - reverse_interleaving ) - ); + new unpack_2bit_samples(big_endian_bytes, + item_size, + big_endian_items, + reverse_interleaving)); } -unpack_2bit_samples::unpack_2bit_samples( bool big_endian_bytes, - size_t item_size, - bool big_endian_items, - bool reverse_interleaving ) + +unpack_2bit_samples::unpack_2bit_samples(bool big_endian_bytes, + size_t item_size, + bool big_endian_items, + bool reverse_interleaving) : sync_interpolator("unpack_2bit_samples", - gr::io_signature::make(1, 1, item_size), - gr::io_signature::make(1, 1, sizeof(char)), - 4*item_size ), // we make 4 bytes out for every byte in + gr::io_signature::make(1, 1, item_size), + gr::io_signature::make(1, 1, sizeof(char)), + 4 * item_size), // we make 4 bytes out for every byte in big_endian_bytes_(big_endian_bytes), item_size_(item_size), big_endian_items_(big_endian_items), swap_endian_items_(false), reverse_interleaving_(reverse_interleaving) { - bool big_endian_system = systemIsBigEndian(); - // Only swap the item bytes if the item size > 1 byte and the system - // endianess is not the same as the item endianness: - swap_endian_items_ = ( item_size_ > 1 ) && - ( big_endian_system != big_endian_items); + // Only swap the item bytes if the item size > 1 byte and the system + // endianness is not the same as the item endianness: + swap_endian_items_ = (item_size_ > 1) && + (big_endian_system != big_endian_items); bool big_endian_bytes_system = systemBytesAreBigEndian(); - swap_endian_bytes_ = ( big_endian_bytes_system != big_endian_bytes_ ); - + swap_endian_bytes_ = (big_endian_bytes_system != big_endian_bytes_); } -unpack_2bit_samples::~unpack_2bit_samples() -{} + +unpack_2bit_samples::~unpack_2bit_samples() = default; + int unpack_2bit_samples::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - signed char const *in = (signed char const *)input_items[0]; - int8_t *out = (int8_t*)output_items[0]; + auto const *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + + size_t ninput_bytes = noutput_items / 4; + size_t ninput_items = ninput_bytes / item_size_; - size_t ninput_bytes = noutput_items/4; - size_t ninput_items = ninput_bytes/item_size_; - // Handle endian swap if needed - if( swap_endian_items_ ) - { - work_buffer_.reserve( ninput_bytes ); - swapEndianness( in, work_buffer_, item_size_, ninput_items ); + if (swap_endian_items_) + { + work_buffer_.reserve(ninput_bytes); + swapEndianness(in, work_buffer_, item_size_, ninput_items); - in = const_cast< signed char const *> ( &work_buffer_[0] ); - } + in = const_cast(&work_buffer_[0]); + } // Here the in pointer can be interpreted as a stream of bytes to be // converted. But we now have two possibilities: // 1) The samples in a byte are in big endian order // 2) The samples in a byte are in little endian order - byte_and_samples raw_byte; + byte_and_samples raw_byte{}; int n = 0; - if( !reverse_interleaving_ ) - { - if( swap_endian_bytes_ ) + if (!reverse_interleaving_) { - for(unsigned int i = 0; i < ninput_bytes; ++i) - { - // Read packed input sample (1 byte = 4 samples) - raw_byte.byte = in[i]; + if (swap_endian_bytes_) + { + for (unsigned int i = 0; i < ninput_bytes; ++i) + { + // Read packed input sample (1 byte = 4 samples) + raw_byte.byte = in[i]; - out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 ); + out[n++] = static_cast(2 * raw_byte.samples.sample_3 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_2 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_1 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_0 + 1); + } + } + else + { + for (unsigned int i = 0; i < ninput_bytes; ++i) + { + // Read packed input sample (1 byte = 4 samples) + raw_byte.byte = in[i]; - } + out[n++] = static_cast(2 * raw_byte.samples.sample_0 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_1 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_2 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_3 + 1); + } + } } - else - { - for(unsigned int i = 0; i < ninput_bytes; ++i ) - { - - // Read packed input sample (1 byte = 4 samples) - raw_byte.byte = in[i]; - - out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 ); - } - } - } else - { - - if( swap_endian_bytes_ ) { - for(unsigned int i = 0; i < ninput_bytes; ++i) - { - // Read packed input sample (1 byte = 4 samples) - raw_byte.byte = in[i]; + if (swap_endian_bytes_) + { + for (unsigned int i = 0; i < ninput_bytes; ++i) + { + // Read packed input sample (1 byte = 4 samples) + raw_byte.byte = in[i]; - out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 ); + out[n++] = static_cast(2 * raw_byte.samples.sample_2 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_3 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_0 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_1 + 1); + } + } + else + { + for (unsigned int i = 0; i < ninput_bytes; ++i) + { + // Read packed input sample (1 byte = 4 samples) + raw_byte.byte = in[i]; - } + out[n++] = static_cast(2 * raw_byte.samples.sample_1 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_0 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_3 + 1); + out[n++] = static_cast(2 * raw_byte.samples.sample_2 + 1); + } + } } - else - { - for(unsigned int i = 0; i < ninput_bytes; ++i ) - { - - // Read packed input sample (1 byte = 4 samples) - raw_byte.byte = in[i]; - - out[n++] = (int8_t)( 2*raw_byte.samples.sample_1 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_0 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_3 + 1 ); - out[n++] = (int8_t)( 2*raw_byte.samples.sample_2 + 1 ); - } - } - } return noutput_items; } - diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.h index 0e8a73da3..b2148b23b 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.h +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_2bit_samples.h @@ -42,7 +42,7 @@ * \author Cillian O'Driscoll cillian.odriscoll (at) gmail . com * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -60,7 +60,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -68,51 +68,50 @@ #ifndef GNSS_SDR_UNPACK_2BIT_SAMPLES_H #define GNSS_SDR_UNPACK_2BIT_SAMPLES_H -#include #include - +#include class unpack_2bit_samples; typedef boost::shared_ptr unpack_2bit_samples_sptr; -unpack_2bit_samples_sptr make_unpack_2bit_samples( bool big_endian_bytes, - size_t item_size, - bool big_endian_items, - bool reverse_interleaving = false ); +unpack_2bit_samples_sptr make_unpack_2bit_samples(bool big_endian_bytes, + size_t item_size, + bool big_endian_items, + bool reverse_interleaving = false); /*! * \brief This class takes 2 bit samples that have been packed into bytes or * shorts as input and generates a byte for each sample. It generates eight * times as much data as is input (every two bits become 16 bits) */ -class unpack_2bit_samples: public gr::sync_interpolator +class unpack_2bit_samples : public gr::sync_interpolator { private: friend unpack_2bit_samples_sptr - make_unpack_2bit_samples_sptr( bool big_endian_bytes, - size_t item_size, - bool big_endian_items, - bool reverse_interleaving); + make_unpack_2bit_samples_sptr(bool big_endian_bytes, + size_t item_size, + bool big_endian_items, + bool reverse_interleaving); bool big_endian_bytes_; size_t item_size_; bool big_endian_items_; bool swap_endian_items_; bool swap_endian_bytes_; bool reverse_interleaving_; - std::vector< int8_t > work_buffer_; + std::vector work_buffer_; public: - unpack_2bit_samples( bool big_endianBytes, - size_t item_size, - bool big_endian_items, - bool reverse_interleaving ); + unpack_2bit_samples(bool big_endianBytes, + size_t item_size, + bool big_endian_items, + bool reverse_interleaving); ~unpack_2bit_samples(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.cc index 64a21da35..692bc22d7 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.cc @@ -9,7 +9,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,10 +35,11 @@ #include "unpack_byte_2bit_cpx_samples.h" #include +#include struct byte_2bit_struct { - signed two_bit_sample:2; // <- 2 bits wide only + signed two_bit_sample : 2; // <- 2 bits wide only }; @@ -47,25 +48,28 @@ unpack_byte_2bit_cpx_samples_sptr make_unpack_byte_2bit_cpx_samples() return unpack_byte_2bit_cpx_samples_sptr(new unpack_byte_2bit_cpx_samples()); } -unpack_byte_2bit_cpx_samples::unpack_byte_2bit_cpx_samples() : sync_interpolator("unpack_byte_2bit_cpx_samples", - gr::io_signature::make(1, 1, sizeof(signed char)), - gr::io_signature::make(1, 1, sizeof(short)), - 4) -{} -unpack_byte_2bit_cpx_samples::~unpack_byte_2bit_cpx_samples() -{} +unpack_byte_2bit_cpx_samples::unpack_byte_2bit_cpx_samples() : sync_interpolator("unpack_byte_2bit_cpx_samples", + gr::io_signature::make(1, 1, sizeof(int8_t)), + gr::io_signature::make(1, 1, sizeof(int16_t)), + 4) +{ +} + + +unpack_byte_2bit_cpx_samples::~unpack_byte_2bit_cpx_samples() = default; + int unpack_byte_2bit_cpx_samples::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const signed char *in = (const signed char *)input_items[0]; - short *out = (short*)output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); - byte_2bit_struct sample; + byte_2bit_struct sample{}; int n = 0; - for(int i = 0; i < noutput_items/4; i++) + for (int i = 0; i < noutput_items / 4; i++) { // Read packed input sample (1 byte = 2 complex samples) //* Packing Order @@ -73,34 +77,34 @@ int unpack_byte_2bit_cpx_samples::work(int noutput_items, //* Least Significant Nibble - Sample n+1 //* Packing order in Nibble Q1 Q0 I1 I0 //normal - // signed char c = in[i]; + // int8_t c = in[i]; // //Q[n] // sample.two_bit_sample = (c>>6) & 3; - // out[n++] = (2*(short)sample.two_bit_sample+1); + // out[n++] = (2*(int16_t)sample.two_bit_sample+1); // //I[n] // sample.two_bit_sample = (c>>4) & 3; - // out[n++] = (2*(short)sample.two_bit_sample+1); + // out[n++] = (2*(int16_t)sample.two_bit_sample+1); // //Q[n+1] // sample.two_bit_sample = (c>>2) & 3; - // out[n++] = (2*(short)sample.two_bit_sample+1); + // out[n++] = (2*(int16_t)sample.two_bit_sample+1); // //I[n+1] // sample.two_bit_sample = c & 3; - // out[n++] = (2*(short)sample.two_bit_sample+1); + // out[n++] = (2*(int16_t)sample.two_bit_sample+1); //I/Q swap - signed char c = in[i]; + int8_t c = in[i]; //I[n] sample.two_bit_sample = (c >> 4) & 3; - out[n++] = (2*(short)sample.two_bit_sample + 1); + out[n++] = (2 * static_cast(sample.two_bit_sample) + 1); //Q[n] sample.two_bit_sample = (c >> 6) & 3; - out[n++] = (2*(short)sample.two_bit_sample + 1); + out[n++] = (2 * static_cast(sample.two_bit_sample) + 1); //I[n+1] sample.two_bit_sample = c & 3; - out[n++] = (2*(short)sample.two_bit_sample + 1); + out[n++] = (2 * static_cast(sample.two_bit_sample) + 1); //Q[n+1] sample.two_bit_sample = (c >> 2) & 3; - out[n++] = (2*(short)sample.two_bit_sample + 1); + out[n++] = (2 * static_cast(sample.two_bit_sample) + 1); } return noutput_items; } diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.h index f0b03283e..090568aa7 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.h +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_cpx_samples.h @@ -9,7 +9,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -47,7 +47,7 @@ unpack_byte_2bit_cpx_samples_sptr make_unpack_byte_2bit_cpx_samples(); * \brief This class implements conversion between byte packet samples to 2bit_cpx samples * 1 byte = 2 x complex 2bit I, + 2bit Q samples */ -class unpack_byte_2bit_cpx_samples: public gr::sync_interpolator +class unpack_byte_2bit_cpx_samples : public gr::sync_interpolator { private: friend unpack_byte_2bit_cpx_samples_sptr make_unpack_byte_2bit_cpx_samples_sptr(); @@ -55,9 +55,9 @@ private: public: unpack_byte_2bit_cpx_samples(); ~unpack_byte_2bit_cpx_samples(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.cc index 8a2d5344c..28637016b 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.cc @@ -5,7 +5,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,7 +34,7 @@ struct byte_2bit_struct { - signed two_bit_sample:2; // <- 2 bits wide only + signed two_bit_sample : 2; // <- 2 bits wide only }; @@ -45,40 +45,40 @@ unpack_byte_2bit_samples_sptr make_unpack_byte_2bit_samples() unpack_byte_2bit_samples::unpack_byte_2bit_samples() : sync_interpolator("unpack_byte_2bit_samples", - gr::io_signature::make(1, 1, sizeof(signed char)), - gr::io_signature::make(1, 1, sizeof(float)), - 4) -{} + gr::io_signature::make(1, 1, sizeof(signed char)), + gr::io_signature::make(1, 1, sizeof(float)), + 4) +{ +} -unpack_byte_2bit_samples::~unpack_byte_2bit_samples() -{} +unpack_byte_2bit_samples::~unpack_byte_2bit_samples() = default; int unpack_byte_2bit_samples::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const signed char *in = (const signed char *)input_items[0]; - float *out = (float*)output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); - byte_2bit_struct sample; + byte_2bit_struct sample{}; int n = 0; - for(int i = 0; i < noutput_items/4; i++) + for (int i = 0; i < noutput_items / 4; i++) { // Read packed input sample (1 byte = 4 samples) signed char c = in[i]; sample.two_bit_sample = c & 3; - out[n++] = (float)sample.two_bit_sample; + out[n++] = static_cast(sample.two_bit_sample); - sample.two_bit_sample = (c>>2) & 3; - out[n++] = (float)sample.two_bit_sample; + sample.two_bit_sample = (c >> 2) & 3; + out[n++] = static_cast(sample.two_bit_sample); - sample.two_bit_sample = (c>>4) & 3; - out[n++] = (float)sample.two_bit_sample; + sample.two_bit_sample = (c >> 4) & 3; + out[n++] = static_cast(sample.two_bit_sample); - sample.two_bit_sample = (c>>6) & 3; - out[n++] = (float)sample.two_bit_sample; + sample.two_bit_sample = (c >> 6) & 3; + out[n++] = static_cast(sample.two_bit_sample); } return noutput_items; } diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.h index 7d96d5d4f..90ed74e60 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.h +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_2bit_samples.h @@ -5,7 +5,7 @@ * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -43,7 +43,7 @@ unpack_byte_2bit_samples_sptr make_unpack_byte_2bit_samples(); * \brief This class implements conversion between byte packet samples to 2bit samples * 1 byte = 4 2bit samples */ -class unpack_byte_2bit_samples: public gr::sync_interpolator +class unpack_byte_2bit_samples : public gr::sync_interpolator { private: friend unpack_byte_2bit_samples_sptr @@ -52,9 +52,9 @@ private: public: unpack_byte_2bit_samples(); ~unpack_byte_2bit_samples(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc new file mode 100644 index 000000000..b20ccf21f --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc @@ -0,0 +1,84 @@ +/*! + * \file unpack_byte_4bit_samples.cc + * + * \brief Unpacks byte samples to 4 bits samples. + * Packing Order + * Packing order in Nibble I0 I1 I2 I3 I0 I1 I2 I3 + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "unpack_byte_4bit_samples.h" +#include + +unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples() +{ + return unpack_byte_4bit_samples_sptr(new unpack_byte_4bit_samples()); +} + + +unpack_byte_4bit_samples::unpack_byte_4bit_samples() : sync_interpolator("unpack_byte_4bit_samples", + gr::io_signature::make(1, 1, sizeof(signed char)), + gr::io_signature::make(1, 1, sizeof(signed char)), + 2) +{ +} + + +unpack_byte_4bit_samples::~unpack_byte_4bit_samples() = default; + + +int unpack_byte_4bit_samples::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); + int n = 0; + unsigned char tmp_char2; + for (int i = 0; i < noutput_items / 2; i++) + { + tmp_char2 = in[i] & 0x0F; + if (tmp_char2 >= 8) + { + out[n++] = 2 * (tmp_char2 - 16) + 1; + } + else + { + out[n++] = 2 * tmp_char2 + 1; + } + tmp_char2 = in[i] >> 4; + tmp_char2 = tmp_char2 & 0x0F; + if (tmp_char2 >= 8) + { + out[n++] = 2 * (tmp_char2 - 16) + 1; + } + else + { + out[n++] = 2 * tmp_char2 + 1; + } + } + return noutput_items; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h new file mode 100644 index 000000000..0a48bcb5f --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h @@ -0,0 +1,61 @@ +/*! + * \file unpack_byte_4bit_samples.h + * + * \brief Unpacks byte samples to 4 bits samples. + * Packing Order + * Packing order in Nibble I0 I1 I2 I3 I0 I1 I2 I3 + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_unpack_byte_4bit_samples_H +#define GNSS_SDR_unpack_byte_4bit_samples_H + +#include + +class unpack_byte_4bit_samples; + +typedef boost::shared_ptr unpack_byte_4bit_samples_sptr; + +unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples(); + +/*! + * \brief This class implements conversion between byte packet samples to 4bit_cpx samples + * 1 byte = 1 x complex 4bit I, + 4bit Q samples + */ +class unpack_byte_4bit_samples : public gr::sync_interpolator +{ +private: + friend unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples_sptr(); + +public: + unpack_byte_4bit_samples(); + ~unpack_byte_4bit_samples(); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.cc index 20afb3c41..f2a805f17 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.cc @@ -5,7 +5,7 @@ * \author Fran Fabra fabra (at) ice.csic.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,7 +33,6 @@ #include - unpack_intspir_1bit_samples_sptr make_unpack_intspir_1bit_samples() { return unpack_intspir_1bit_samples_sptr(new unpack_intspir_1bit_samples()); @@ -41,31 +40,31 @@ unpack_intspir_1bit_samples_sptr make_unpack_intspir_1bit_samples() unpack_intspir_1bit_samples::unpack_intspir_1bit_samples() : sync_interpolator("unpack_intspir_1bit_samples", - gr::io_signature::make(1, 1, sizeof(int)), - gr::io_signature::make(1, 1, sizeof(float)), - 2) -{} + gr::io_signature::make(1, 1, sizeof(int)), + gr::io_signature::make(1, 1, sizeof(float)), + 2) +{ +} -unpack_intspir_1bit_samples::~unpack_intspir_1bit_samples() -{} +unpack_intspir_1bit_samples::~unpack_intspir_1bit_samples() = default; int unpack_intspir_1bit_samples::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { - const signed int *in = (const signed int *)input_items[0]; - float *out = (float*)output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); int n = 0; int channel = 1; - for(int i = 0; i < noutput_items/2; i++) + for (int i = 0; i < noutput_items / 2; i++) { // Read packed input sample (1 byte = 1 complex sample) // For historical reasons, values are float versions of short int limits (32767) signed int val = in[i]; - if(((val >> ((channel - 1)*2)) & 1) == 1) + if (((val >> ((channel - 1) * 2)) & 1) == 1) { out[n++] = static_cast(32767.0); } @@ -73,7 +72,7 @@ int unpack_intspir_1bit_samples::work(int noutput_items, { out[n++] = static_cast(-32767.0); } - if(((val >> (2*channel - 1)) & 1) == 1) + if (((val >> (2 * channel - 1)) & 1) == 1) { out[n++] = static_cast(32767.0); } diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.h index 387c3039f..536816f0c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.h +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_intspir_1bit_samples.h @@ -5,7 +5,7 @@ * \author Fran Fabra fabra (at) ice.csic.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -43,7 +43,7 @@ unpack_intspir_1bit_samples_sptr make_unpack_intspir_1bit_samples(); * \brief This class implements conversion between byte packet samples to 2bit samples * 1 byte = 4 2bit samples */ -class unpack_intspir_1bit_samples: public gr::sync_interpolator +class unpack_intspir_1bit_samples : public gr::sync_interpolator { private: friend unpack_intspir_1bit_samples_sptr @@ -52,9 +52,9 @@ private: public: unpack_intspir_1bit_samples(); ~unpack_intspir_1bit_samples(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc new file mode 100644 index 000000000..02b9e3d30 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc @@ -0,0 +1,138 @@ +/*! + * \file unpack_spir_gss6450_samples.cc + * + * \brief Unpacks SPIR int samples + * \author Antonio Ramos, antonio(at)cttc.es + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "unpack_spir_gss6450_samples.h" +#include +#include + +unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples(unsigned int adc_nbit) +{ + return unpack_spir_gss6450_samples_sptr(new unpack_spir_gss6450_samples(adc_nbit)); +} + + +unpack_spir_gss6450_samples::unpack_spir_gss6450_samples(unsigned int adc_nbit) : gr::sync_interpolator("unpack_spir_gss6450_samples", + gr::io_signature::make(1, 1, sizeof(int32_t)), + gr::io_signature::make(1, 1, sizeof(gr_complex)), 16 / adc_nbit) +{ + adc_bits = adc_nbit; + samples_per_int = 16 / adc_bits; +} + + +unpack_spir_gss6450_samples::~unpack_spir_gss6450_samples() = default; + + +void unpack_spir_gss6450_samples::decode_4bits_word(uint32_t input_uint32, gr_complex* out, int adc_bits) +{ + int8_t tmp_char; + float Q; + float I; + switch (adc_bits) + { + case 2: + //four bits per complex sample (2 I + 2 Q), 8 samples per int32[s0,s1,s2,s3,s4,s5,s6,s7] + for (int i = 0; i < 8; i++) + { + tmp_char = input_uint32 & 3; + + if (tmp_char >= 2) + { + I = (tmp_char - 4); + } + else + { + I = tmp_char; + } + input_uint32 = input_uint32 >> 2; + tmp_char = input_uint32 & 3; + if (tmp_char >= 2) + { + Q = (tmp_char - 4); + } + else + { + Q = tmp_char; + } + input_uint32 = input_uint32 >> 2; + + out[7 - i] = gr_complex(I, Q); + } + break; + case 4: + //eight bits per complex sample (4 I + 4 Q), 4 samples per int32= [s0,s1,s2,s3] + for (int i = 0; i < 4; i++) + { + tmp_char = input_uint32 & 0x0F; + + if (tmp_char >= 8) + { + I = (tmp_char - 16); + } + else + { + I = tmp_char; + } + input_uint32 = input_uint32 >> 4; + tmp_char = input_uint32 & 0x0F; + if (tmp_char >= 8) + { + Q = (tmp_char - 16); + } + else + { + Q = tmp_char; + } + input_uint32 = input_uint32 >> 4; + + out[3 - i] = gr_complex(I, Q); + } + break; + } +} + +int unpack_spir_gss6450_samples::work(int noutput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) +{ + const auto* in = reinterpret_cast(input_items[0]); + auto* out = reinterpret_cast(output_items[0]); + int n_sample = 0; + int in_counter = 0; + do + { + decode_4bits_word(in[in_counter++], &out[n_sample], adc_bits); + n_sample += samples_per_int; + } + while (n_sample < noutput_items); + + return noutput_items; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h new file mode 100644 index 000000000..a8f4b47f9 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h @@ -0,0 +1,59 @@ +/*! + * \file unpack_spir_gss6450_samples.h + * + * \brief Unpacks SPIR int samples + * \author Antonio Ramos, antonio.ramos(at)cttc.es + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_UNPACK_SPIR_GSS6450_SAMPLES_H +#define GNSS_SDR_UNPACK_SPIR_GSS6450_SAMPLES_H + +#include + +class unpack_spir_gss6450_samples; + +typedef boost::shared_ptr unpack_spir_gss6450_samples_sptr; + +unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples(unsigned int adc_nbit); + + +class unpack_spir_gss6450_samples : public gr::sync_interpolator +{ +public: + int work(int noutput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + friend unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples_sptr(unsigned int adc_nbit); + void decode_4bits_word(uint32_t input_int32, gr_complex *out, int adc_bits); + unpack_spir_gss6450_samples(unsigned int adc_nbit); + ~unpack_spir_gss6450_samples(); + +private: + unsigned int adc_bits; + unsigned int samples_per_int; +}; + +#endif diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 7d6c9b4ef..3f2a6bbe5 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,19 +13,74 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set (SIGNAL_SOURCE_LIB_SOURCES - rtl_tcp_commands.cc - rtl_tcp_dongle_info.cc) +if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) + find_package(GRIIO REQUIRED) + if(NOT GRIIO_FOUND) + message(STATUS "gnuradio-iio not found, its installation is required.") + message(STATUS "Please build and install the following projects:") + message(STATUS " * libiio from https://github.com/analogdevicesinc/libiio") + message(STATUS " * libad9361-iio from https://github.com/analogdevicesinc/libad9361-iio") + message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") + message(FATAL_ERROR "gnuradio-iio is required for building gnss-sdr with this option enabled") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${IIO_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) +endif() + +if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) + find_package(LIBIIO REQUIRED) + if(NOT LIBIIO_FOUND) + message(STATUS "libiio not found, its installation is required.") + message(STATUS "Please build and install the following projects:") + message(STATUS " * libiio from https://github.com/analogdevicesinc/libiio") + message(STATUS " * libad9361-iio from https://github.com/analogdevicesinc/libad9361-iio") + message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") + message(FATAL_ERROR "libiio is required for building gnss-sdr with this option enabled") + endif() + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${LIBIIO_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${LIBIIO_INCLUDE_DIRS}) + + ############################################### + # FMCOMMS2 based SDR Hardware + ############################################### + if(LIBIIO_FOUND) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ad9361_manager.h) + endif() +endif() + +if(ENABLE_FPGA OR ENABLE_AD9361) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h) +endif() include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${Boost_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${OPT_DRIVER_INCLUDE_DIRS} +) + +set(SIGNAL_SOURCE_LIB_SOURCES + rtl_tcp_commands.cc + rtl_tcp_dongle_info.cc + ${OPT_SIGNAL_SOURCE_LIB_SOURCES} +) + +set(SIGNAL_SOURCE_LIB_HEADERS + rtl_tcp_commands.h + rtl_tcp_dongle_info.h + ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ) -file(GLOB SIGNAL_SOURCE_LIB_HEADERS "*.h") list(SORT SIGNAL_SOURCE_LIB_HEADERS) +list(SORT SIGNAL_SOURCE_LIB_SOURCES) + add_library(signal_source_lib ${SIGNAL_SOURCE_LIB_SOURCES} ${SIGNAL_SOURCE_LIB_HEADERS}) -source_group(Headers FILES ${SIGNAL_SOURCE_LIB_HEADERS}) \ No newline at end of file +source_group(Headers FILES ${SIGNAL_SOURCE_LIB_HEADERS}) +target_link_libraries(signal_source_lib ${OPT_LIBRARIES}) +add_dependencies(signal_source_lib glog-${glog_RELEASE}) diff --git a/src/algorithms/signal_source/libs/ad9361_manager.cc b/src/algorithms/signal_source/libs/ad9361_manager.cc new file mode 100644 index 000000000..c1786ec08 --- /dev/null +++ b/src/algorithms/signal_source/libs/ad9361_manager.cc @@ -0,0 +1,764 @@ +/*! + * \file ad9361_manager.cc + * \brief An Analog Devices AD9361 front-end configuration library wrapper for configure some functions via iiod link. + * \author Javier Arribas, jarribas(at)cttc.es + * + * This file contains information taken from librtlsdr: + * http://git.osmocom.org/rtl-sdr/ + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#include "ad9361_manager.h" +#include +#include +#include +#include + + +/* check return value of attr_write function */ +void errchk(int v, const char *what) +{ + if (v < 0) + { + LOG(WARNING) << "Error " << v << " writing to channel " << what << " value may not be supported. "; + } +} + + +/* write attribute: int64_t int */ +void wr_ch_lli(struct iio_channel *chn, const char *what, int64_t val) +{ + errchk(iio_channel_attr_write_longlong(chn, what, val), what); +} + + +/* write attribute: string */ +void wr_ch_str(struct iio_channel *chn, const char *what, const char *str) +{ + errchk(iio_channel_attr_write(chn, what, str), what); +} + + +/* returns ad9361 phy device */ +struct iio_device *get_ad9361_phy(struct iio_context *ctx) +{ + struct iio_device *dev = iio_context_find_device(ctx, "ad9361-phy"); + return dev; +} + + +/* finds AD9361 streaming IIO devices */ +bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev) +{ + switch (d) + { + case TX: + *dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); + return *dev != nullptr; + case RX: + *dev = iio_context_find_device(ctx, "cf-ad9361-lpc"); + return *dev != nullptr; + default: + return false; + } +} + + +/* finds AD9361 streaming IIO channels */ +bool get_ad9361_stream_ch(struct iio_context *ctx __attribute__((unused)), enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn) +{ + std::stringstream name; + name.str(""); + name << "voltage"; + name << chid; + *chn = iio_device_find_channel(dev, name.str().c_str(), d == TX); + if (!*chn) + { + name.str(""); + name << "altvoltage"; + name << chid; + *chn = iio_device_find_channel(dev, name.str().c_str(), d == TX); + } + return *chn != nullptr; +} + + +/* finds AD9361 phy IIO configuration channel with id chid */ +bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn) +{ + std::stringstream name; + switch (d) + { + case RX: + name.str(""); + name << "voltage"; + name << chid; + *chn = iio_device_find_channel(get_ad9361_phy(ctx), name.str().c_str(), false); + return *chn != nullptr; + break; + case TX: + name.str(""); + name << "voltage"; + name << chid; + *chn = iio_device_find_channel(get_ad9361_phy(ctx), name.str().c_str(), true); + return *chn != nullptr; + break; + default: + return false; + } +} + + +/* finds AD9361 local oscillator IIO configuration channels */ +bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn) +{ + switch (d) + { + // LO chan is always output, i.e. true + case RX: + *chn = iio_device_find_channel(get_ad9361_phy(ctx), "altvoltage0", true); + return *chn != nullptr; + case TX: + *chn = iio_device_find_channel(get_ad9361_phy(ctx), "altvoltage1", true); + return *chn != nullptr; + default: + return false; + } +} + + +/* applies streaming configuration through IIO */ +bool cfg_ad9361_streaming_ch(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid) +{ + struct iio_channel *chn = nullptr; + + // Configure phy and lo channels + //LOG(INFO)<<"* Acquiring AD9361 phy channel"<rfport); + wr_ch_lli(chn, "rf_bandwidth", cfg->bw_hz); + wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz); + + // Configure LO channel + //LOG(INFO)<<"* Acquiring AD9361 "<lo_hz); + return true; +} + + +bool config_ad9361_rx_local(uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_, + const std::string &rf_port_select_, + const std::string &gain_mode_rx1_, + const std::string &gain_mode_rx2_, + double rf_gain_rx1_, + double rf_gain_rx2_) + +{ + // RX stream config + // Stream configurations + struct stream_cfg rxcfg; + rxcfg.bw_hz = bandwidth_; // 2 MHz rf bandwidth + rxcfg.fs_hz = sample_rate_; // 2.5 MS/s rx sample rate + rxcfg.lo_hz = freq_; // 2.5 GHz rf frequency + rxcfg.rfport = rf_port_select_.c_str(); // port A (select for rf freq.) + + std::cout << "AD9361 Acquiring IIO LOCAL context\n"; + struct iio_context *ctx; + // Streaming devices + struct iio_device *rx; + struct iio_channel *rx0_i; + struct iio_channel *rx0_q; + + ctx = iio_create_default_context(); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + + if (iio_context_get_devices_count(ctx) <= 0) + { + std::cout << "No devices\n"; + throw std::runtime_error("AD9361 IIO No devices"); + } + + std::cout << "* Acquiring AD9361 streaming devices\n"; + + if (!get_ad9361_stream_dev(ctx, RX, &rx)) + { + std::cout << "No rx dev found\n"; + throw std::runtime_error("AD9361 IIO No rx dev found"); + }; + + std::cout << "* Configuring AD9361 for streaming\n"; + if (!cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0)) + { + std::cout << "RX port 0 not found\n"; + throw std::runtime_error("AD9361 IIO RX port 0 not found"); + } + + std::cout << "* Initializing AD9361 IIO streaming channels\n"; + if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i)) + { + std::cout << "RX chan i not found\n"; + throw std::runtime_error("RX chan i not found"); + } + + if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q)) + { + std::cout << "RX chan q not found\n"; + throw std::runtime_error("RX chan q not found"); + } + + std::cout << "* Enabling IIO streaming channels\n"; + iio_channel_enable(rx0_i); + iio_channel_enable(rx0_q); + + struct iio_device *ad9361_phy; + ad9361_phy = iio_context_find_device(ctx, "ad9361-phy"); + int ret; + ret = iio_device_attr_write(ad9361_phy, "trx_rate_governor", "nominal"); + if (ret < 0) + { + std::cout << "Failed to set trx_rate_governor: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "ensm_mode", "fdd"); + if (ret < 0) + { + std::cout << "Failed to set ensm_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "calib_mode", "auto"); + if (ret < 0) + { + std::cout << "Failed to set calib_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "in_voltage0_gain_control_mode", gain_mode_rx1_.c_str()); + if (ret < 0) + { + std::cout << "Failed to set in_voltage0_gain_control_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "in_voltage1_gain_control_mode", gain_mode_rx2_.c_str()); + if (ret < 0) + { + std::cout << "Failed to set in_voltage1_gain_control_mode: " << ret << std::endl; + } + ret = iio_device_attr_write_double(ad9361_phy, "in_voltage0_hardwaregain", rf_gain_rx1_); + if (ret < 0) + { + std::cout << "Failed to set in_voltage0_hardwaregain: " << ret << std::endl; + } + ret = iio_device_attr_write_double(ad9361_phy, "in_voltage1_hardwaregain", rf_gain_rx2_); + if (ret < 0) + { + std::cout << "Failed to set in_voltage1_hardwaregain: " << ret << std::endl; + } + + std::cout << "End of AD9361 RX configuration.\n"; + iio_context_destroy(ctx); + return true; +} + + +bool config_ad9361_rx_remote(const std::string &remote_host, + uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_, + const std::string &rf_port_select_, + const std::string &gain_mode_rx1_, + const std::string &gain_mode_rx2_, + double rf_gain_rx1_, + double rf_gain_rx2_) +{ + // RX stream config + // Stream configurations + struct stream_cfg rxcfg; + rxcfg.bw_hz = bandwidth_; // 2 MHz rf bandwidth + rxcfg.fs_hz = sample_rate_; // 2.5 MS/s rx sample rate + rxcfg.lo_hz = freq_; // 2.5 GHz rf frequency + rxcfg.rfport = rf_port_select_.c_str(); // port A (select for rf freq.) + + std::cout << "AD9361 Acquiring IIO REMOTE context in host " << remote_host << std::endl; + struct iio_context *ctx; + // Streaming devices + struct iio_device *rx; + struct iio_channel *rx0_i; + struct iio_channel *rx0_q; + + ctx = iio_create_network_context(remote_host.c_str()); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + + if (iio_context_get_devices_count(ctx) <= 0) + { + std::cout << "No devices\n"; + throw std::runtime_error("AD9361 IIO No devices"); + } + + std::cout << "* Acquiring AD9361 streaming devices\n"; + + if (!get_ad9361_stream_dev(ctx, RX, &rx)) + { + std::cout << "No rx dev found\n"; + throw std::runtime_error("AD9361 IIO No rx dev found"); + }; + + std::cout << "* Configuring AD9361 for streaming\n"; + if (!cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0)) + { + std::cout << "RX port 0 not found\n"; + throw std::runtime_error("AD9361 IIO RX port 0 not found"); + } + + std::cout << "* Initializing AD9361 IIO streaming channels\n"; + if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i)) + { + std::cout << "RX chan i not found\n"; + throw std::runtime_error("RX chan i not found"); + } + + if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q)) + { + std::cout << "RX chan q not found\n"; + throw std::runtime_error("RX chan q not found"); + } + + std::cout << "* Enabling IIO streaming channels\n"; + iio_channel_enable(rx0_i); + iio_channel_enable(rx0_q); + + struct iio_device *ad9361_phy; + ad9361_phy = iio_context_find_device(ctx, "ad9361-phy"); + int ret; + ret = iio_device_attr_write(ad9361_phy, "trx_rate_governor", "nominal"); + if (ret < 0) + { + std::cout << "Failed to set trx_rate_governor: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "ensm_mode", "fdd"); + if (ret < 0) + { + std::cout << "Failed to set ensm_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "calib_mode", "auto"); + if (ret < 0) + { + std::cout << "Failed to set calib_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "in_voltage0_gain_control_mode", gain_mode_rx1_.c_str()); + if (ret < 0) + { + std::cout << "Failed to set in_voltage0_gain_control_mode: " << ret << std::endl; + } + ret = iio_device_attr_write(ad9361_phy, "in_voltage1_gain_control_mode", gain_mode_rx2_.c_str()); + if (ret < 0) + { + std::cout << "Failed to set in_voltage1_gain_control_mode: " << ret << std::endl; + } + ret = iio_device_attr_write_double(ad9361_phy, "in_voltage0_hardwaregain", rf_gain_rx1_); + if (ret < 0) + { + std::cout << "Failed to set in_voltage0_hardwaregain: " << ret << std::endl; + } + ret = iio_device_attr_write_double(ad9361_phy, "in_voltage1_hardwaregain", rf_gain_rx2_); + if (ret < 0) + { + std::cout << "Failed to set in_voltage1_hardwaregain: " << ret << std::endl; + } + + std::cout << "End of AD9361 RX configuration.\n"; + + iio_context_destroy(ctx); + return true; +} + + +bool config_ad9361_lo_local(uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_dbfs_) +{ + // TX stream config + std::cout << "Start of AD9361 TX Local Oscillator DDS configuration\n"; + struct stream_cfg txcfg; + txcfg.bw_hz = bandwidth_; + txcfg.fs_hz = sample_rate_; + txcfg.lo_hz = freq_rf_tx_hz_; + txcfg.rfport = "A"; + + std::cout << "AD9361 Acquiring IIO LOCAL context\n"; + struct iio_context *ctx; + ctx = iio_create_default_context(); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + + //find tx device + struct iio_device *tx; + + std::cout << "* Acquiring AD9361 TX streaming devices\n"; + + if (!get_ad9361_stream_dev(ctx, TX, &tx)) + { + std::cout << "No tx dev found\n"; + throw std::runtime_error("AD9361 IIO No tx dev found"); + }; + + std::cout << "* Configuring AD9361 for streaming TX\n"; + if (!cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0)) + { + std::cout << "TX port 0 not found\n"; + throw std::runtime_error("AD9361 IIO TX port 0 not found"); + } + + //ENABLE DDS on TX1 + struct iio_device *ad9361_phy; + ad9361_phy = iio_context_find_device(ctx, "ad9361-phy"); + int ret; + //set output amplifier attenuation + ret = iio_device_attr_write_double(ad9361_phy, "out_voltage0_hardwaregain", -tx_attenuation_db_); + if (ret < 0) + { + std::cout << "Failed to set out_voltage0_hardwaregain value " << -tx_attenuation_db_ << " error " << ret << std::endl; + } + + struct iio_device *dds; + dds = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); + struct iio_channel *dds_channel0_I; + dds_channel0_I = iio_device_find_channel(dds, "TX1_I_F1", true); + + struct iio_channel *dds_channel0_Q; + dds_channel0_Q = iio_device_find_channel(dds, "TX1_Q_F1", true); + + ret = iio_channel_attr_write_bool(dds_channel0_I, "raw", true); + if (ret < 0) + { + std::cout << "Failed to toggle DDS: " << ret << std::endl; + } + + //set frequency, scale and phase + + ret = iio_channel_attr_write_longlong(dds_channel0_I, "frequency", static_cast(freq_dds_tx_hz_)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS frequency I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_longlong(dds_channel0_Q, "frequency", static_cast(freq_dds_tx_hz_)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS frequency Q: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "phase", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS phase I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "phase", 270000.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS phase Q: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "scale", pow(10, scale_dds_dbfs_ / 20.0)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "scale", pow(10, scale_dds_dbfs_ / 20.0)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale Q: " << ret << std::endl; + } + + //disable TX2 + + ret = iio_device_attr_write_double(ad9361_phy, "out_voltage1_hardwaregain", -89.0); + if (ret < 0) + { + std::cout << "Failed to set out_voltage1_hardwaregain value " << -89.0 << " error " << ret << std::endl; + } + + struct iio_channel *dds_channel1_I; + dds_channel1_I = iio_device_find_channel(dds, "TX2_I_F1", true); + + struct iio_channel *dds_channel1_Q; + dds_channel1_Q = iio_device_find_channel(dds, "TX2_Q_F1", true); + + ret = iio_channel_attr_write_double(dds_channel1_I, "scale", 0); + if (ret < 0) + { + std::cout << "Failed to set TX2 DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel1_Q, "scale", 0); + if (ret < 0) + { + std::cout << "Failed to set TX2 DDS scale Q: " << ret << std::endl; + } + + iio_context_destroy(ctx); + return true; +} + + +bool config_ad9361_lo_remote(const std::string &remote_host, + uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_dbfs_) +{ + // TX stream config + std::cout << "Start of AD9361 TX Local Oscillator DDS configuration\n"; + struct stream_cfg txcfg; + txcfg.bw_hz = bandwidth_; + txcfg.fs_hz = sample_rate_; + txcfg.lo_hz = freq_rf_tx_hz_; + txcfg.rfport = "A"; + + std::cout << "AD9361 Acquiring IIO REMOTE context in host " << remote_host << std::endl; + struct iio_context *ctx; + ctx = iio_create_network_context(remote_host.c_str()); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + + //find tx device + struct iio_device *tx; + + std::cout << "* Acquiring AD9361 TX streaming devices\n"; + + if (!get_ad9361_stream_dev(ctx, TX, &tx)) + { + std::cout << "No tx dev found\n"; + throw std::runtime_error("AD9361 IIO No tx dev found"); + }; + + std::cout << "* Configuring AD9361 for streaming TX\n"; + if (!cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0)) + { + std::cout << "TX port 0 not found\n"; + throw std::runtime_error("AD9361 IIO TX port 0 not found"); + } + + //ENABLE DDS on TX1 + struct iio_device *ad9361_phy; + ad9361_phy = iio_context_find_device(ctx, "ad9361-phy"); + int ret; + //set output amplifier attenuation + ret = iio_device_attr_write_double(ad9361_phy, "out_voltage0_hardwaregain", -tx_attenuation_db_); + if (ret < 0) + { + std::cout << "Failed to set out_voltage0_hardwaregain value " << -tx_attenuation_db_ << " error " << ret << std::endl; + } + + struct iio_device *dds; + dds = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); + struct iio_channel *dds_channel0_I; + dds_channel0_I = iio_device_find_channel(dds, "TX1_I_F1", true); + + struct iio_channel *dds_channel0_Q; + dds_channel0_Q = iio_device_find_channel(dds, "TX1_Q_F1", true); + + ret = iio_channel_attr_write_bool(dds_channel0_I, "raw", true); + if (ret < 0) + { + std::cout << "Failed to toggle DDS: " << ret << std::endl; + } + + //set frequency, scale and phase + + ret = iio_channel_attr_write_longlong(dds_channel0_I, "frequency", static_cast(freq_dds_tx_hz_)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS frequency I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_longlong(dds_channel0_Q, "frequency", static_cast(freq_dds_tx_hz_)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS frequency Q: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "phase", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS phase I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "phase", 270000.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS phase Q: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "scale", pow(10, scale_dds_dbfs_ / 20.0)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "scale", pow(10, scale_dds_dbfs_ / 20.0)); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale Q: " << ret << std::endl; + } + + //disable TX2 + + ret = iio_device_attr_write_double(ad9361_phy, "out_voltage1_hardwaregain", -89.0); + if (ret < 0) + { + std::cout << "Failed to set out_voltage1_hardwaregain value " << -89.0 << " error " << ret << std::endl; + } + + struct iio_channel *dds_channel1_I; + dds_channel1_I = iio_device_find_channel(dds, "TX2_I_F1", true); + + struct iio_channel *dds_channel1_Q; + dds_channel1_Q = iio_device_find_channel(dds, "TX2_Q_F1", true); + + ret = iio_channel_attr_write_double(dds_channel1_I, "scale", 0); + if (ret < 0) + { + std::cout << "Failed to set TX2 DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel1_Q, "scale", 0); + if (ret < 0) + { + std::cout << "Failed to set TX2 DDS scale Q: " << ret << std::endl; + } + + iio_context_destroy(ctx); + return true; +} + + +bool ad9361_disable_lo_remote(const std::string &remote_host) +{ + std::cout << "AD9361 Acquiring IIO REMOTE context in host " << remote_host << std::endl; + struct iio_context *ctx; + ctx = iio_create_network_context(remote_host.c_str()); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + struct iio_device *dds; + dds = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); + struct iio_channel *dds_channel0_I; + dds_channel0_I = iio_device_find_channel(dds, "TX1_I_F1", true); + + struct iio_channel *dds_channel0_Q; + dds_channel0_Q = iio_device_find_channel(dds, "TX1_Q_F1", true); + int ret; + ret = iio_channel_attr_write_bool(dds_channel0_I, "raw", false); + if (ret < 0) + { + std::cout << "Failed to toggle DDS: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "scale", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "scale", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale Q: " << ret << std::endl; + } + + iio_context_destroy(ctx); + + return true; +} + + +bool ad9361_disable_lo_local() +{ + std::cout << "AD9361 Acquiring IIO LOCAL context" << std::endl; + struct iio_context *ctx; + ctx = iio_create_default_context(); + if (!ctx) + { + std::cout << "No context\n"; + throw std::runtime_error("AD9361 IIO No context"); + } + struct iio_device *dds; + dds = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); + struct iio_channel *dds_channel0_I; + dds_channel0_I = iio_device_find_channel(dds, "TX1_I_F1", true); + + struct iio_channel *dds_channel0_Q; + dds_channel0_Q = iio_device_find_channel(dds, "TX1_Q_F1", true); + int ret; + ret = iio_channel_attr_write_bool(dds_channel0_I, "raw", false); + if (ret < 0) + { + std::cout << "Failed to toggle DDS: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_I, "scale", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale I: " << ret << std::endl; + } + + ret = iio_channel_attr_write_double(dds_channel0_Q, "scale", 0.0); + if (ret < 0) + { + std::cout << "Failed to set TX DDS scale Q: " << ret << std::endl; + } + + iio_context_destroy(ctx); + + return true; +} diff --git a/src/algorithms/signal_source/libs/ad9361_manager.h b/src/algorithms/signal_source/libs/ad9361_manager.h new file mode 100644 index 000000000..af4390ddb --- /dev/null +++ b/src/algorithms/signal_source/libs/ad9361_manager.h @@ -0,0 +1,131 @@ +/*! + * \file ad9361_manager.h + * \brief An Analog Devices AD9361 front-end configuration library wrapper for configure some functions via iiod link. + * \author Javier Arribas, jarribas(at)cttc.es + * + * This file contains information taken from librtlsdr: + * http://git.osmocom.org/rtl-sdr/ + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_AD9361_MANAGER_H +#define GNSS_SDR_AD9361_MANAGER_H + +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +/* RX is input, TX is output */ +enum iodev +{ + RX, + TX +}; + +/* common RX and TX streaming params */ +struct stream_cfg +{ + int64_t bw_hz; // Analog banwidth in Hz + int64_t fs_hz; // Baseband sample rate in Hz + int64_t lo_hz; // Local oscillator frequency in Hz + const char *rfport; // Port name +}; + + +/* check return value of attr_write function */ +void errchk(int v, const char *what); + +/* write attribute: int64_t int */ +void wr_ch_lli(struct iio_channel *chn, const char *what, int64_t val); + +/* write attribute: string */ +void wr_ch_str(struct iio_channel *chn, const char *what, const char *str); + +/* helper function generating channel names */ +char *get_ch_name(const char *type, int id, char *tmpstr); + +/* returns ad9361 phy device */ +struct iio_device *get_ad9361_phy(struct iio_context *ctx); + +/* finds AD9361 streaming IIO devices */ +bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev); + +/* finds AD9361 streaming IIO channels */ +bool get_ad9361_stream_ch(struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn); + +/* finds AD9361 phy IIO configuration channel with id chid */ +bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn); + +/* finds AD9361 local oscillator IIO configuration channels */ +bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn); + +/* applies streaming configuration through IIO */ +bool cfg_ad9361_streaming_ch(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid); + +bool config_ad9361_rx_local(uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_, + const std::string &rf_port_select_, + const std::string &gain_mode_rx1_, + const std::string &gain_mode_rx2_, + double rf_gain_rx1_, + double rf_gain_rx2_); + +bool config_ad9361_rx_remote(const std::string &remote_host, + uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_, + const std::string &rf_port_select_, + const std::string &gain_mode_rx1_, + const std::string &gain_mode_rx2_, + double rf_gain_rx1_, + double rf_gain_rx2_); + +bool config_ad9361_lo_local(uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_dbfs_); + +bool config_ad9361_lo_remote(const std::string &remote_host, + uint64_t bandwidth_, + uint64_t sample_rate_, + uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_dbfs_); + + +bool ad9361_disable_lo_remote(const std::string &remote_host); + +bool ad9361_disable_lo_local(); + +#endif diff --git a/src/algorithms/signal_source/libs/fpga_switch.cc b/src/algorithms/signal_source/libs/fpga_switch.cc new file mode 100644 index 000000000..71fd26eba --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_switch.cc @@ -0,0 +1,118 @@ +/*! + * \file fpga_switch.cc + * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2015. jarribas(at)cttc.es + *
      + * + * Class that controls a switch in the FPGA + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fpga_switch.h" +#include +#include // for open, O_RDWR, O_SYNC +#include // for cout, endl +#include // for mmap + + +// constants +const size_t PAGE_SIZE = 0x10000; +const unsigned int TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; + +fpga_switch::fpga_switch(const std::string &device_name) +{ + if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_name; + } + d_map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); + + if (d_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA switch module into tracking memory"; + std::cout << "Could not map switch memory." << std::endl; + } + else + { + std::cout << "Switch memory successfully mapped." << std::endl; + } + + // sanity check : check test register + unsigned writeval = TEST_REGISTER_TRACK_WRITEVAL; + unsigned readval; + readval = fpga_switch::fpga_switch_test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Test register sanity check failed"; + } + else + { + LOG(INFO) << "Test register sanity check success !"; + } + + DLOG(INFO) << "Switch FPGA class created"; +} + + +fpga_switch::~fpga_switch() +{ + close_device(); +} + + +void fpga_switch::set_switch_position(int switch_position) +{ + d_map_base[0] = switch_position; +} + + +unsigned fpga_switch::fpga_switch_test_register( + unsigned writeval) +{ + unsigned readval; + // write value to test register + d_map_base[3] = writeval; + // read value from test register + readval = d_map_base[3]; + // return read value + return readval; +} + + +void fpga_switch::close_device() +{ + auto *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + std::cout << "Failed to unmap memory uio" << std::endl; + } + + close(d_device_descriptor); +} diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h new file mode 100644 index 000000000..2ab67dbef --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_switch.h @@ -0,0 +1,60 @@ +/*! + * \file fpga_switch.h + * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2016. jarribas(at)cttc.es + *
      + * + * Class that controls a switch in the FPGA + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FPGA_SWITCH_H_ +#define GNSS_SDR_FPGA_SWITCH_H_ + +#include + +#define MAX_LENGTH_DEVICEIO_NAME 50 + +class fpga_switch +{ +public: + fpga_switch(const std::string& device_name); + ~fpga_switch(); + void set_switch_position(int switch_position); + +private: + int d_device_descriptor; // driver descriptor + volatile unsigned* d_map_base; // driver memory map + + // private functions + unsigned fpga_switch_test_register(unsigned writeval); + void close_device(void); +}; + +#endif /* GNSS_SDR_FPGA_SWITCH_H_ */ diff --git a/src/algorithms/signal_source/libs/rtl_tcp_commands.cc b/src/algorithms/signal_source/libs/rtl_tcp_commands.cc index 7cf21eafd..45bb25a9f 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_commands.cc +++ b/src/algorithms/signal_source/libs/rtl_tcp_commands.cc @@ -7,7 +7,7 @@ * http://git.osmocom.org/rtl-sdr/ * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,29 +25,25 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #include "rtl_tcp_commands.h" -#include +#include -using boost::asio::ip::tcp; - - -boost::system::error_code -rtl_tcp_command (RTL_TCP_COMMAND id, unsigned param, tcp::socket &socket) { +boost::system::error_code rtl_tcp_command(RTL_TCP_COMMAND id, unsigned param, boost::asio::ip::tcp::socket &socket) +{ // Data payload - unsigned char data[sizeof (unsigned char) + sizeof (unsigned)]; + unsigned char data[sizeof(unsigned char) + sizeof(unsigned)]; - data[0] = static_cast (id); + data[0] = static_cast(id); - - unsigned nparam = - boost::asio::detail::socket_ops::host_to_network_long (param); - ::memcpy (&data[1], &nparam, sizeof (nparam)); + unsigned nparam = boost::asio::detail::socket_ops::host_to_network_long(param); + std::memcpy(&data[1], &nparam, sizeof(nparam)); boost::system::error_code ec; - socket.send (boost::asio::buffer (data), 0, ec); + socket.send(boost::asio::buffer(data), 0, ec); return ec; } diff --git a/src/algorithms/signal_source/libs/rtl_tcp_commands.h b/src/algorithms/signal_source/libs/rtl_tcp_commands.h index 361dc10a4..8dab2a0c8 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_commands.h +++ b/src/algorithms/signal_source/libs/rtl_tcp_commands.h @@ -7,7 +7,7 @@ * http://git.osmocom.org/rtl-sdr/ * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,7 +35,8 @@ #include /// Command IDs for configuration rtl_tcp -enum RTL_TCP_COMMAND { +enum RTL_TCP_COMMAND +{ RTL_TCP_SET_FREQUENCY = 1, RTL_TCP_SET_SAMPLE_RATE = 2, RTL_TCP_SET_GAIN_MODE = 3, @@ -48,8 +49,7 @@ enum RTL_TCP_COMMAND { /*! * \brief Send a command to rtl_tcp over the given socket. */ -boost::system::error_code -rtl_tcp_command (RTL_TCP_COMMAND id, unsigned param, - boost::asio::ip::tcp::socket &socket); +boost::system::error_code rtl_tcp_command(RTL_TCP_COMMAND id, unsigned param, + boost::asio::ip::tcp::socket &socket); -#endif // GNSS_SDR_RTL_TCP_COMMANDS_H +#endif // GNSS_SDR_RTL_TCP_COMMANDS_H diff --git a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc index e7e7b15ef..fab664d28 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc +++ b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc @@ -8,7 +8,7 @@ * http://git.osmocom.org/rtl-sdr/ * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,119 +26,130 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #include "rtl_tcp_dongle_info.h" -#include #include +#include using boost::asio::ip::tcp; -rtl_tcp_dongle_info::rtl_tcp_dongle_info () - : tuner_type_ (0), tuner_gain_count_ (0) +rtl_tcp_dongle_info::rtl_tcp_dongle_info() : tuner_type_(0), tuner_gain_count_(0) { - ::memset (magic_, 0, sizeof (magic_)); + std::memset(magic_, 0, sizeof(magic_)); } -boost::system::error_code rtl_tcp_dongle_info::read (tcp::socket &socket) { + +boost::system::error_code rtl_tcp_dongle_info::read(boost::asio::ip::tcp::socket &socket) +{ boost::system::error_code ec; - unsigned char data[sizeof (char) * 4 + sizeof (uint32_t) * 2]; - socket.receive (boost::asio::buffer (data), 0, ec); - if (!ec) { - ::memcpy (magic_, data, 4); + unsigned char data[sizeof(char) * 4 + sizeof(uint32_t) * 2]; + socket.receive(boost::asio::buffer(data), 0, ec); + if (!ec) + { + std::memcpy(magic_, data, 4); - uint32_t type; - ::memcpy (&type, &data[4], 4); + uint32_t type; + std::memcpy(&type, &data[4], 4); - tuner_type_ = - boost::asio::detail::socket_ops::network_to_host_long (type); + tuner_type_ = boost::asio::detail::socket_ops::network_to_host_long(type); + uint32_t count; + std ::memcpy(&count, &data[8], 4); - uint32_t count; - ::memcpy (&count, &data[8], 4); - - tuner_gain_count_ = - boost::asio::detail::socket_ops::network_to_host_long (count); - } + tuner_gain_count_ = boost::asio::detail::socket_ops::network_to_host_long(count); + } return ec; } -const char *rtl_tcp_dongle_info::get_type_name () const { - switch (get_tuner_type()) { - default: - return "UNKNOWN"; - case TUNER_E4000: - return "E4000"; - case TUNER_FC0012: - return "FC0012"; - case TUNER_FC0013: - return "FC0013"; - case TUNER_FC2580: - return "FC2580"; - case TUNER_R820T: - return "R820T"; - case TUNER_R828D: - return "R828D"; - } +const char *rtl_tcp_dongle_info::get_type_name() const +{ + switch (get_tuner_type()) + { + default: + return "UNKNOWN"; + case TUNER_E4000: + return "E4000"; + case TUNER_FC0012: + return "FC0012"; + case TUNER_FC0013: + return "FC0013"; + case TUNER_FC2580: + return "FC2580"; + case TUNER_R820T: + return "R820T"; + case TUNER_R828D: + return "R828D"; + } } -double rtl_tcp_dongle_info::clip_gain (int gain) const { + +double rtl_tcp_dongle_info::clip_gain(int gain) const +{ // the following gain values have been copied from librtlsdr // all gain values are expressed in tenths of a dB std::vector gains; - switch (get_tuner_type()) { - case TUNER_E4000: - gains = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, - 240, 290, 340, 420 }; - break; - case TUNER_FC0012: - gains = { -99, -40, 71, 179, 192 }; - break; - case TUNER_FC0013: - gains = { -99, -73, -65, -63, -60, -58, -54, 58, 61, - 63, 65, 67, 68, 70, 71, 179, 181, 182, - 184, 186, 188, 191, 197 }; - break; - case TUNER_R820T: - gains = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, - 166, 197, 207, 229, 254, 280, 297, 328, - 338, 364, 372, 386, 402, 421, 434, 439, - 445, 480, 496 }; - break; - default: - // no gains - break; - } + switch (get_tuner_type()) + { + case TUNER_E4000: + gains = {-10, 15, 40, 65, 90, 115, 140, 165, 190, 215, + 240, 290, 340, 420}; + break; + case TUNER_FC0012: + gains = {-99, -40, 71, 179, 192}; + break; + case TUNER_FC0013: + gains = {-99, -73, -65, -63, -60, -58, -54, 58, 61, + 63, 65, 67, 68, 70, 71, 179, 181, 182, + 184, 186, 188, 191, 197}; + break; + case TUNER_R820T: + gains = {0, 9, 14, 27, 37, 77, 87, 125, 144, 157, + 166, 197, 207, 229, 254, 280, 297, 328, + 338, 364, 372, 386, 402, 421, 434, 439, + 445, 480, 496}; + break; + default: + // no gains + break; + } // clip - if (gains.size() == 0) { - // no defined gains to clip to - return gain; - } - else { - double last_stop = gains.front (); - BOOST_FOREACH (double g, gains) { + if (gains.size() == 0) + { + // no defined gains to clip to + return gain; + } + + double last_stop = gains.front(); + BOOST_FOREACH (double g, gains) + { g /= 10.0; - if (gain < g) { - if (std::abs (gain - g) < std::abs (gain - last_stop)) { - return g; + if (gain < g) + { + if (std::abs(gain - g) < std::abs(gain - last_stop)) + { + return g; + } + else + { + return last_stop; + } } - else { - return last_stop; - } - } last_stop = g; } - return last_stop; - } + return last_stop; } -bool rtl_tcp_dongle_info::is_valid () const { - return ::memcmp (magic_, "RTL0", 4) == 0; + +bool rtl_tcp_dongle_info::is_valid() const +{ + return std::memcmp(magic_, "RTL0", 4) == 0; } diff --git a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.h b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.h index 78e0ff646..983b94a29 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.h +++ b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.h @@ -7,7 +7,7 @@ * http://git.osmocom.org/rtl-sdr/ * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,10 +25,11 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #ifndef GNSS_SDR_RTL_TCP_DONGLE_INFO_H #define GNSS_SDR_RTL_TCP_DONGLE_INFO_H @@ -38,9 +39,16 @@ * \brief This class represents the dongle information * which is sent by rtl_tcp. */ -class rtl_tcp_dongle_info { - public: - enum { +class rtl_tcp_dongle_info +{ +private: + char magic_[4]{}; + uint32_t tuner_type_; + uint32_t tuner_gain_count_; + +public: + enum + { TUNER_UNKNOWN = 0, TUNER_E4000, TUNER_FC0012, @@ -50,31 +58,26 @@ class rtl_tcp_dongle_info { TUNER_R828D }; - private: - char magic_[4]; - uint32_t tuner_type_; - uint32_t tuner_gain_count_; + rtl_tcp_dongle_info(); - public: - rtl_tcp_dongle_info (); + boost::system::error_code read(boost::asio::ip::tcp::socket &socket); - boost::system::error_code read ( - boost::asio::ip::tcp::socket &socket); + bool is_valid() const; - bool is_valid () const; + const char *get_type_name() const; - const char *get_type_name () const; + double clip_gain(int gain) const; - double clip_gain (int gain) const; - - inline uint32_t get_tuner_type () const { + inline uint32_t get_tuner_type() const + { return tuner_type_; } - inline uint32_t get_tuner_gain_count () const { + inline uint32_t get_tuner_gain_count() const + { return tuner_gain_count_; } }; -#endif // GNSS_SDR_RTL_TCP_DONGLE_INFO_H +#endif // GNSS_SDR_RTL_TCP_DONGLE_INFO_H diff --git a/src/algorithms/telemetry_decoder/CMakeLists.txt b/src/algorithms/telemetry_decoder/CMakeLists.txt index ec514fac4..96259341c 100644 --- a/src/algorithms/telemetry_decoder/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,9 +13,9 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) add_subdirectory(gnuradio_blocks) -add_subdirectory(libs) \ No newline at end of file +add_subdirectory(libs) diff --git a/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt b/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt index 20095b8fe..01836e5ae 100644 --- a/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,32 +13,58 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(TELEMETRY_DECODER_ADAPTER_SOURCES - gps_l1_ca_telemetry_decoder.cc - gps_l2c_telemetry_decoder.cc + +set(TELEMETRY_DECODER_ADAPTER_SOURCES + gps_l1_ca_telemetry_decoder.cc + gps_l2c_telemetry_decoder.cc + gps_l5_telemetry_decoder.cc galileo_e1b_telemetry_decoder.cc sbas_l1_telemetry_decoder.cc galileo_e5a_telemetry_decoder.cc + glonass_l1_ca_telemetry_decoder.cc + glonass_l2_ca_telemetry_decoder.cc +) + +set(TELEMETRY_DECODER_ADAPTER_HEADERS + gps_l1_ca_telemetry_decoder.h + gps_l2c_telemetry_decoder.h + gps_l5_telemetry_decoder.h + galileo_e1b_telemetry_decoder.h + sbas_l1_telemetry_decoder.h + galileo_e5a_telemetry_decoder.h + glonass_l1_ca_telemetry_decoder.h + glonass_l2_ca_telemetry_decoder.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs/libswiftcnav + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) -file(GLOB TELEMETRY_DECODER_ADAPTER_HEADERS "*.h") list(SORT TELEMETRY_DECODER_ADAPTER_HEADERS) -add_library(telemetry_decoder_adapters ${TELEMETRY_DECODER_ADAPTER_SOURCES} ${TELEMETRY_DECODER_ADAPTER_HEADERS}) +list(SORT TELEMETRY_DECODER_ADAPTER_SOURCES) + +add_library(telemetry_decoder_adapters + ${TELEMETRY_DECODER_ADAPTER_SOURCES} + ${TELEMETRY_DECODER_ADAPTER_HEADERS} +) + source_group(Headers FILES ${TELEMETRY_DECODER_ADAPTER_HEADERS}) -target_link_libraries(telemetry_decoder_adapters telemetry_decoder_gr_blocks gnss_system_parameters ${GNURADIO_RUNTIME_LIBRARIES}) + +target_link_libraries(telemetry_decoder_adapters + telemetry_decoder_gr_blocks + gnss_system_parameters + ${GNURADIO_RUNTIME_LIBRARIES} +) diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc index 508127cfa..be7dd59ce 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,53 +25,54 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1b_telemetry_decoder.h" -#include -#include #include "configuration_interface.h" -#include "concurrent_queue.h" -#include "galileo_ephemeris.h" #include "galileo_almanac.h" +#include "galileo_ephemeris.h" #include "galileo_iono.h" #include "galileo_utc_model.h" +#include +#include + using google::LogMessage; GalileoE1BTelemetryDecoder::GalileoE1BTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_dump_filename = "./navigation.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = galileo_e1b_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = galileo_make_telemetry_decoder_cc(satellite_, 1, dump_); //unified galileo decoder set to INAV (frame_type=1) DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; - - //decimation factor - int decimation_factor = configuration->property(role + ".decimation_factor", 1); - telemetry_decoder_->set_decimation(decimation_factor); - channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GalileoE1BTelemetryDecoder::~GalileoE1BTelemetryDecoder() -{} +GalileoE1BTelemetryDecoder::~GalileoE1BTelemetryDecoder() = default; -void GalileoE1BTelemetryDecoder::set_satellite(Gnss_Satellite satellite) +void GalileoE1BTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) { satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); telemetry_decoder_->set_satellite(satellite_); @@ -81,7 +82,9 @@ void GalileoE1BTelemetryDecoder::set_satellite(Gnss_Satellite satellite) void GalileoE1BTelemetryDecoder::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } @@ -89,7 +92,9 @@ void GalileoE1BTelemetryDecoder::connect(gr::top_block_sptr top_block) void GalileoE1BTelemetryDecoder::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } @@ -104,4 +109,3 @@ gr::basic_block_sptr GalileoE1BTelemetryDecoder::get_right_block() { return telemetry_decoder_; } - diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h index deb2035d5..c277725ce 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,11 +34,11 @@ #ifndef GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_H_ #define GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_H_ -#include -#include "telemetry_decoder_interface.h" -#include "galileo_e1b_telemetry_decoder_cc.h" -#include "gnss_satellite.h" +#include "galileo_telemetry_decoder_cc.h" +#include "gnss_satellite.h" +#include "telemetry_decoder_interface.h" +#include class ConfigurationInterface; @@ -50,12 +50,13 @@ class GalileoE1BTelemetryDecoder : public TelemetryDecoderInterface { public: GalileoE1BTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1BTelemetryDecoder(); - std::string role() + + inline std::string role() override { return role_; } @@ -63,27 +64,30 @@ public: /*! * \brief Returns "Galileo_E1B_Telemetry_Decoder" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E1B_Telemetry_Decoder"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void set_satellite(Gnss_Satellite satellite); - void set_channel(int channel){telemetry_decoder_->set_channel(channel);} - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + inline void reset() override { return; } - size_t item_size() + + inline size_t item_size() override { return 0; } private: - galileo_e1b_telemetry_decoder_cc_sptr telemetry_decoder_; + galileo_telemetry_decoder_cc_sptr telemetry_decoder_; Gnss_Satellite satellite_; int channel_; bool dump_; diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc index 9049079d4..715e5c1cb 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,49 +29,53 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e5a_telemetry_decoder.h" -#include -#include -#include "concurrent_queue.h" -#include "galileo_ephemeris.h" +#include "configuration_interface.h" #include "galileo_almanac.h" +#include "galileo_ephemeris.h" #include "galileo_iono.h" #include "galileo_utc_model.h" -#include "configuration_interface.h" +#include +#include using google::LogMessage; GalileoE5aTelemetryDecoder::GalileoE5aTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_dump_filename = "./navigation.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = galileo_e5a_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = galileo_make_telemetry_decoder_cc(satellite_, 2, dump_); //unified galileo decoder set to FNAV (frame_type=2) DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; - DLOG(INFO) << "global navigation message queue assigned to telemetry_decoder ("<< telemetry_decoder_->unique_id() << ")"; channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GalileoE5aTelemetryDecoder::~GalileoE5aTelemetryDecoder() -{} +GalileoE5aTelemetryDecoder::~GalileoE5aTelemetryDecoder() = default; -void GalileoE5aTelemetryDecoder::set_satellite(Gnss_Satellite satellite) +void GalileoE5aTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) { satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); telemetry_decoder_->set_satellite(satellite_); @@ -81,7 +85,9 @@ void GalileoE5aTelemetryDecoder::set_satellite(Gnss_Satellite satellite) void GalileoE5aTelemetryDecoder::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } @@ -89,7 +95,9 @@ void GalileoE5aTelemetryDecoder::connect(gr::top_block_sptr top_block) void GalileoE5aTelemetryDecoder::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h index 9ea653e7b..cdb21af2d 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,26 +37,26 @@ #ifndef GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_H_ #define GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_H_ -#include +#include "galileo_telemetry_decoder_cc.h" #include "telemetry_decoder_interface.h" -#include "galileo_e5a_telemetry_decoder_cc.h" - +#include class ConfigurationInterface; /*! * \brief This class implements a NAV data decoder for Galileo INAV frames in E1B radio link */ -class GalileoE5aTelemetryDecoder: public TelemetryDecoderInterface +class GalileoE5aTelemetryDecoder : public TelemetryDecoderInterface { public: GalileoE5aTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE5aTelemetryDecoder(); - std::string role() + + inline std::string role() override { return role_; } @@ -64,27 +64,30 @@ public: /*! * \brief Returns "Galileo_E5a_Telemetry_Decoder" */ - std::string implementation() + inline std::string implementation() override { return "Galileo_E5A_Telemetry_Decoder"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void set_satellite(Gnss_Satellite satellite); - void set_channel(int channel){telemetry_decoder_->set_channel(channel);} - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + inline void reset() override { return; } - size_t item_size() + + inline size_t item_size() override { return 0; } private: - galileo_e5a_telemetry_decoder_cc_sptr telemetry_decoder_; + galileo_telemetry_decoder_cc_sptr telemetry_decoder_; Gnss_Satellite satellite_; int channel_; bool dump_; diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc new file mode 100644 index 000000000..c0d88314f --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc @@ -0,0 +1,110 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder.cc + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_telemetry_decoder.h" +#include "configuration_interface.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include +#include + + +using google::LogMessage; + +GlonassL1CaTelemetryDecoder::GlonassL1CaTelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + std::string default_dump_filename = "./navigation.dat"; + DLOG(INFO) << "role " << role; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + // make telemetry decoder object + telemetry_decoder_ = glonass_l1_ca_make_telemetry_decoder_cc(satellite_, dump_); + DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; + channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL1CaTelemetryDecoder::~GlonassL1CaTelemetryDecoder() = default; + + +void GlonassL1CaTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) +{ + satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + telemetry_decoder_->set_satellite(satellite_); + DLOG(INFO) << "TELEMETRY DECODER: satellite set to " << satellite_; +} + + +void GlonassL1CaTelemetryDecoder::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect internally + DLOG(INFO) << "nothing to connect internally"; +} + + +void GlonassL1CaTelemetryDecoder::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect +} + + +gr::basic_block_sptr GlonassL1CaTelemetryDecoder::get_left_block() +{ + return telemetry_decoder_; +} + + +gr::basic_block_sptr GlonassL1CaTelemetryDecoder::get_right_block() +{ + return telemetry_decoder_; +} diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h new file mode 100644 index 000000000..33bc3ecbd --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h @@ -0,0 +1,91 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder.h + * \brief Interface of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_H_ +#define GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_H_ + +#include "glonass_l1_ca_telemetry_decoder_cc.h" +#include "telemetry_decoder_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a NAV data decoder for GLONASS L1 C/A + */ +class GlonassL1CaTelemetryDecoder : public TelemetryDecoderInterface +{ +public: + GlonassL1CaTelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL1CaTelemetryDecoder(); + std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L1_CA_Telemetry_Decoder" + std::string implementation() override + { + return "GLONASS_L1_CA_Telemetry_Decoder"; + } + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + void set_satellite(const Gnss_Satellite& satellite) override; + void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + void reset() override + { + return; + } + size_t item_size() override + { + return 0; + } + +private: + glonass_l1_ca_telemetry_decoder_cc_sptr telemetry_decoder_; + Gnss_Satellite satellite_; + int channel_; + bool dump_; + std::string dump_filename_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.cc new file mode 100644 index 000000000..c96851552 --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.cc @@ -0,0 +1,109 @@ +/*! + * \file glonass_l2_ca_telemetry_decoder.cc + * \brief Implementation of an adapter of a GLONASS L2 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l2_ca_telemetry_decoder.h" +#include "configuration_interface.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include +#include + + +using google::LogMessage; + +GlonassL2CaTelemetryDecoder::GlonassL2CaTelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + std::string default_dump_filename = "./navigation.dat"; + DLOG(INFO) << "role " << role; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + // make telemetry decoder object + telemetry_decoder_ = glonass_l2_ca_make_telemetry_decoder_cc(satellite_, dump_); + DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; + channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL2CaTelemetryDecoder::~GlonassL2CaTelemetryDecoder() = default; + + +void GlonassL2CaTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) +{ + satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + telemetry_decoder_->set_satellite(satellite_); + DLOG(INFO) << "TELEMETRY DECODER: satellite set to " << satellite_; +} + + +void GlonassL2CaTelemetryDecoder::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect internally + DLOG(INFO) << "nothing to connect internally"; +} + + +void GlonassL2CaTelemetryDecoder::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect +} + + +gr::basic_block_sptr GlonassL2CaTelemetryDecoder::get_left_block() +{ + return telemetry_decoder_; +} + + +gr::basic_block_sptr GlonassL2CaTelemetryDecoder::get_right_block() +{ + return telemetry_decoder_; +} diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.h new file mode 100644 index 000000000..83c7c8c4e --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l2_ca_telemetry_decoder.h @@ -0,0 +1,90 @@ +/*! + * \file glonass_l2_ca_telemetry_decoder.h + * \brief Interface of an adapter of a GLONASS L2 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_L2_CA_TELEMETRY_DECODER_H_ +#define GNSS_SDR_GLONASS_L2_CA_TELEMETRY_DECODER_H_ + +#include "glonass_l2_ca_telemetry_decoder_cc.h" +#include "telemetry_decoder_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a NAV data decoder for GLONASS L2 C/A + */ +class GlonassL2CaTelemetryDecoder : public TelemetryDecoderInterface +{ +public: + GlonassL2CaTelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL2CaTelemetryDecoder(); + std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L2_CA_Telemetry_Decoder" + std::string implementation() override + { + return "GLONASS_L2_CA_Telemetry_Decoder"; + } + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + void set_satellite(const Gnss_Satellite& satellite) override; + void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + void reset() override + { + return; + } + size_t item_size() override + { + return 0; + } + +private: + glonass_l2_ca_telemetry_decoder_cc_sptr telemetry_decoder_; + Gnss_Satellite satellite_; + int channel_; + bool dump_; + std::string dump_filename_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.cc index fe22b7a66..b7a4530b3 100644 --- a/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,53 +24,54 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_telemetry_decoder.h" -#include -#include -#include "concurrent_queue.h" -#include "gps_ephemeris.h" +#include "configuration_interface.h" #include "gps_almanac.h" +#include "gps_ephemeris.h" #include "gps_iono.h" #include "gps_utc_model.h" -#include "configuration_interface.h" +#include +#include + using google::LogMessage; GpsL1CaTelemetryDecoder::GpsL1CaTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_dump_filename = "./navigation.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = gps_l1_ca_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = gps_l1_ca_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; - - //decimation factor - int decimation_factor = configuration->property(role + ".decimation_factor", 1); - telemetry_decoder_->set_decimation(decimation_factor); - DLOG(INFO) << "global navigation message queue assigned to telemetry_decoder ("<< telemetry_decoder_->unique_id() << ")"; channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL1CaTelemetryDecoder::~GpsL1CaTelemetryDecoder() -{} +GpsL1CaTelemetryDecoder::~GpsL1CaTelemetryDecoder() = default; -void GpsL1CaTelemetryDecoder::set_satellite(Gnss_Satellite satellite) +void GpsL1CaTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) { satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); telemetry_decoder_->set_satellite(satellite_); @@ -80,7 +81,9 @@ void GpsL1CaTelemetryDecoder::set_satellite(Gnss_Satellite satellite) void GpsL1CaTelemetryDecoder::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } @@ -88,7 +91,9 @@ void GpsL1CaTelemetryDecoder::connect(gr::top_block_sptr top_block) void GpsL1CaTelemetryDecoder::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } @@ -103,4 +108,3 @@ gr::basic_block_sptr GpsL1CaTelemetryDecoder::get_right_block() { return telemetry_decoder_; } - diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.h index fd5f8dc1b..9436e8ae5 100644 --- a/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/gps_l1_ca_telemetry_decoder.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,9 @@ #ifndef GNSS_SDR_GPS_L1_CA_TELEMETRY_DECODER_H_ #define GNSS_SDR_GPS_L1_CA_TELEMETRY_DECODER_H_ -#include -#include "telemetry_decoder_interface.h" #include "gps_l1_ca_telemetry_decoder_cc.h" - +#include "telemetry_decoder_interface.h" +#include class ConfigurationInterface; @@ -47,32 +46,37 @@ class GpsL1CaTelemetryDecoder : public TelemetryDecoderInterface { public: GpsL1CaTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaTelemetryDecoder(); - std::string role() + + inline std::string role() override { return role_; } //! Returns "GPS_L1_CA_Telemetry_Decoder" - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_Telemetry_Decoder"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void set_satellite(Gnss_Satellite satellite); - void set_channel(int channel){telemetry_decoder_->set_channel(channel);} - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + + inline void reset() override { return; } - size_t item_size() + + inline size_t item_size() override { return 0; } diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.cc index 2d352b24e..db451a045 100644 --- a/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,54 +24,54 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l2c_telemetry_decoder.h" -#include -#include -#include "concurrent_queue.h" -#include "gps_cnav_ephemeris.h" +#include "configuration_interface.h" #include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" #include "gps_cnav_iono.h" #include "gps_cnav_utc_model.h" -#include "configuration_interface.h" +#include +#include using google::LogMessage; GpsL2CTelemetryDecoder::GpsL2CTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_dump_filename = "./navigation.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = gps_l2c_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = gps_l2c_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; - - //decimation factor - int decimation_factor = configuration->property(role + ".decimation_factor", 1); - telemetry_decoder_->set_decimation(decimation_factor); - LOG(INFO) << "global navigation message queue assigned to telemetry_decoder (" << telemetry_decoder_->unique_id() << ")" << "role " << role; channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL2CTelemetryDecoder::~GpsL2CTelemetryDecoder() -{} +GpsL2CTelemetryDecoder::~GpsL2CTelemetryDecoder() = default; -void GpsL2CTelemetryDecoder::set_satellite(Gnss_Satellite satellite) +void GpsL2CTelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) { satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); telemetry_decoder_->set_satellite(satellite_); @@ -81,7 +81,9 @@ void GpsL2CTelemetryDecoder::set_satellite(Gnss_Satellite satellite) void GpsL2CTelemetryDecoder::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } @@ -89,7 +91,9 @@ void GpsL2CTelemetryDecoder::connect(gr::top_block_sptr top_block) void GpsL2CTelemetryDecoder::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } @@ -104,4 +108,3 @@ gr::basic_block_sptr GpsL2CTelemetryDecoder::get_right_block() { return telemetry_decoder_; } - diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.h index 08ccc12f0..f7e9fb76b 100644 --- a/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/gps_l2c_telemetry_decoder.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,9 @@ #ifndef GNSS_SDR_GPS_L2C_TELEMETRY_DECODER_H_ #define GNSS_SDR_GPS_L2C_TELEMETRY_DECODER_H_ -#include -#include "telemetry_decoder_interface.h" #include "gps_l2c_telemetry_decoder_cc.h" - +#include "telemetry_decoder_interface.h" +#include class ConfigurationInterface; @@ -47,32 +46,36 @@ class GpsL2CTelemetryDecoder : public TelemetryDecoderInterface { public: GpsL2CTelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL2CTelemetryDecoder(); - std::string role() + + inline std::string role() override { return role_; } //! Returns "GPS_L2C_Telemetry_Decoder" - std::string implementation() + inline std::string implementation() override { return "GPS_L2C_Telemetry_Decoder"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void set_satellite(Gnss_Satellite satellite); - void set_channel(int channel){telemetry_decoder_->set_channel(channel);} - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + + inline void reset() override { return; } - size_t item_size() + inline size_t item_size() override { return 0; } diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.cc new file mode 100644 index 000000000..68fa96d26 --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.cc @@ -0,0 +1,106 @@ +/*! + * \file gps_l5_telemetry_decoder.cc + * \brief Implementation of an adapter of a GPS L5 NAV data decoder block + * to a TelemetryDecoderInterface + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l5_telemetry_decoder.h" +#include "configuration_interface.h" +#include +#include + + +using google::LogMessage; + +GpsL5TelemetryDecoder::GpsL5TelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + std::string default_dump_filename = "./navigation.dat"; + DLOG(INFO) << "role " << role; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + // make telemetry decoder object + telemetry_decoder_ = gps_l5_make_telemetry_decoder_cc(satellite_, dump_); + DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; + channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GpsL5TelemetryDecoder::~GpsL5TelemetryDecoder() = default; + + +void GpsL5TelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) +{ + satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + telemetry_decoder_->set_satellite(satellite_); + DLOG(INFO) << "TELEMETRY DECODER: satellite set to " << satellite_; +} + + +void GpsL5TelemetryDecoder::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect internally + DLOG(INFO) << "nothing to connect internally"; +} + + +void GpsL5TelemetryDecoder::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect +} + + +gr::basic_block_sptr GpsL5TelemetryDecoder::get_left_block() +{ + return telemetry_decoder_; +} + + +gr::basic_block_sptr GpsL5TelemetryDecoder::get_right_block() +{ + return telemetry_decoder_; +} diff --git a/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.h new file mode 100644 index 000000000..c895b3b48 --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/gps_l5_telemetry_decoder.h @@ -0,0 +1,97 @@ +/*! + * \file gps_l5_telemetry_decoder.h + * \brief Interface of an adapter of a GPS L5 (CNAV) data decoder block + * to a TelemetryDecoderInterface + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GPS_L5_TELEMETRY_DECODER_H_ +#define GNSS_SDR_GPS_L5_TELEMETRY_DECODER_H_ + + +#include "gnss_satellite.h" +#include "gps_l5_telemetry_decoder_cc.h" +#include "telemetry_decoder_interface.h" +#include + + +class ConfigurationInterface; + +/*! + * \brief This class implements a NAV data decoder for GPS L5 + */ +class GpsL5TelemetryDecoder : public TelemetryDecoderInterface +{ +public: + GpsL5TelemetryDecoder(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL5TelemetryDecoder(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L5_Telemetry_Decoder" + inline std::string implementation() override + { + return "GPS_L5_Telemetry_Decoder"; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + + inline void reset() override + { + return; + } + inline size_t item_size() override + { + return 0; + } + +private: + gps_l5_telemetry_decoder_cc_sptr telemetry_decoder_; + Gnss_Satellite satellite_; + int channel_; + bool dump_; + std::string dump_filename_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.cc index 0264acdba..2083509e1 100644 --- a/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,49 +24,52 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "sbas_l1_telemetry_decoder.h" -#include -#include -#include "concurrent_queue.h" -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_satellite_correction.h" -#include "sbas_ephemeris.h" #include "configuration_interface.h" +#include "sbas_ephemeris.h" #include "sbas_l1_telemetry_decoder_cc.h" +#include +#include + using google::LogMessage; SbasL1TelemetryDecoder::SbasL1TelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams) : - role_(role), - in_streams_(in_streams), - out_streams_(out_streams) + const std::string& role, + unsigned int in_streams, + unsigned int out_streams) : role_(role), + in_streams_(in_streams), + out_streams_(out_streams) { std::string default_dump_filename = "./navigation.dat"; DLOG(INFO) << "role " << role; dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = sbas_l1_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = sbas_l1_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me channel_ = 0; DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -SbasL1TelemetryDecoder::~SbasL1TelemetryDecoder() -{} +SbasL1TelemetryDecoder::~SbasL1TelemetryDecoder() = default; -void SbasL1TelemetryDecoder::set_satellite(Gnss_Satellite satellite) +void SbasL1TelemetryDecoder::set_satellite(const Gnss_Satellite& satellite) { satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); telemetry_decoder_->set_satellite(satellite_); @@ -76,7 +79,9 @@ void SbasL1TelemetryDecoder::set_satellite(Gnss_Satellite satellite) void SbasL1TelemetryDecoder::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to connect internally DLOG(INFO) << "nothing to connect internally"; } @@ -84,7 +89,9 @@ void SbasL1TelemetryDecoder::connect(gr::top_block_sptr top_block) void SbasL1TelemetryDecoder::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; // Nothing to disconnect } @@ -99,4 +106,3 @@ gr::basic_block_sptr SbasL1TelemetryDecoder::get_right_block() { return telemetry_decoder_; } - diff --git a/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.h index 58c59861e..c7ab0043b 100644 --- a/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/sbas_l1_telemetry_decoder.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,10 @@ #ifndef GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_H_ #define GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_H_ -#include -#include "telemetry_decoder_interface.h" -#include "sbas_l1_telemetry_decoder_cc.h" +#include "sbas_l1_telemetry_decoder_cc.h" +#include "telemetry_decoder_interface.h" +#include class ConfigurationInterface; @@ -48,12 +48,13 @@ class SbasL1TelemetryDecoder : public TelemetryDecoderInterface { public: SbasL1TelemetryDecoder(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~SbasL1TelemetryDecoder(); - std::string role() + + inline std::string role() override { return role_; } @@ -61,21 +62,25 @@ public: /*! * \brief Returns "SBAS_L1_Telemetry_Decoder" */ - std::string implementation() + inline std::string implementation() override { return "SBAS_L1_Telemetry_Decoder"; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - void set_satellite(Gnss_Satellite satellite); - void set_channel(int channel){ telemetry_decoder_->set_channel(channel); } - void reset() + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + void set_satellite(const Gnss_Satellite& satellite) override; + inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } + + inline void reset() override { return; } - size_t item_size() + + inline size_t item_size() override { return 0; } diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt index 29aafa1b8..83fe5d36f 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,30 +13,60 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES - gps_l1_ca_telemetry_decoder_cc.cc - gps_l2c_telemetry_decoder_cc.cc - galileo_e1b_telemetry_decoder_cc.cc - sbas_l1_telemetry_decoder_cc.cc - galileo_e5a_telemetry_decoder_cc.cc -) - -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} +set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES + gps_l1_ca_telemetry_decoder_cc.cc + gps_l2c_telemetry_decoder_cc.cc + gps_l5_telemetry_decoder_cc.cc + sbas_l1_telemetry_decoder_cc.cc + glonass_l1_ca_telemetry_decoder_cc.cc + glonass_l2_ca_telemetry_decoder_cc.cc + galileo_telemetry_decoder_cc.cc +) + +set(TELEMETRY_DECODER_GR_BLOCKS_HEADERS + gps_l1_ca_telemetry_decoder_cc.h + gps_l2c_telemetry_decoder_cc.h + gps_l5_telemetry_decoder_cc.h + sbas_l1_telemetry_decoder_cc.h + glonass_l1_ca_telemetry_decoder_cc.h + glonass_l2_ca_telemetry_decoder_cc.h + galileo_telemetry_decoder_cc.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs/libswiftcnav + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} ) -file(GLOB TELEMETRY_DECODER_GR_BLOCKS_HEADERS "*.h") list(SORT TELEMETRY_DECODER_GR_BLOCKS_HEADERS) -add_library(telemetry_decoder_gr_blocks ${TELEMETRY_DECODER_GR_BLOCKS_SOURCES} ${TELEMETRY_DECODER_GR_BLOCKS_HEADERS}) +list(SORT TELEMETRY_DECODER_GR_BLOCKS_SOURCES) + +add_library(telemetry_decoder_gr_blocks + ${TELEMETRY_DECODER_GR_BLOCKS_SOURCES} + ${TELEMETRY_DECODER_GR_BLOCKS_HEADERS} +) + source_group(Headers FILES ${TELEMETRY_DECODER_GR_BLOCKS_HEADERS}) -target_link_libraries(telemetry_decoder_gr_blocks telemetry_decoder_lib gnss_system_parameters ${GNURADIO_RUNTIME_LIBRARIES}) + +target_link_libraries(telemetry_decoder_gr_blocks + telemetry_decoder_libswiftcnav + telemetry_decoder_lib + gnss_system_parameters + ${GNURADIO_RUNTIME_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} +) + +if(NOT VOLKGNSSSDR_FOUND) + add_dependencies(telemetry_decoder_gr_blocks volk_gnsssdr_module) +endif() diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc deleted file mode 100644 index 93e02e3fa..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc +++ /dev/null @@ -1,546 +0,0 @@ -/*! - * \file galileo_e1b_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo INAV message demodulator block - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "galileo_e1b_telemetry_decoder_cc.h" -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "gnss_synchro.h" -#include "convolutional.h" - - -#define CRC_ERROR_LIMIT 6 - -using google::LogMessage; - - -galileo_e1b_telemetry_decoder_cc_sptr -galileo_e1b_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) -{ - return galileo_e1b_telemetry_decoder_cc_sptr(new galileo_e1b_telemetry_decoder_cc(satellite, dump)); -} - - - -void galileo_e1b_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - if(noutput_items != 0) - { - ninput_items_required[0] = GALILEO_INAV_PAGE_SYMBOLS; // set the required sample history - } -} - - -void galileo_e1b_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int *page_part_bits) -{ - int CodeLength = 240; - int DataLength; - int nn, KK, mm, max_states; - int g_encoder[2]; - - nn = 2; // Coding rate 1/n - KK = 7; // Constraint Length - g_encoder[0] = 121; // Polynomial G1 - g_encoder[1] = 91; // Polynomial G2 - - mm = KK - 1; - max_states = 1 << mm; /* 2^mm */ - DataLength = (CodeLength/nn) - mm; - - /* create appropriate transition matrices */ - int *out0, *out1, *state0, *state1; - out0 = (int*)calloc( max_states, sizeof(int) ); - out1 = (int*)calloc( max_states, sizeof(int) ); - state0 = (int*)calloc( max_states, sizeof(int) ); - state1 = (int*)calloc( max_states, sizeof(int) ); - - nsc_transit( out0, state0, 0, g_encoder, KK, nn ); - nsc_transit( out1, state1, 1, g_encoder, KK, nn ); - - Viterbi(page_part_bits, out0, state0, out1, state1, - page_part_symbols, KK, nn, DataLength ); - - /* Clean up memory */ - free( out0 ); - free( out1 ); - free( state0 ); - free( state1 ); -} - - -void galileo_e1b_telemetry_decoder_cc::deinterleaver(int rows, int cols, double *in, double *out) -{ - for (int r = 0; r < rows; r++) - { - for(int c = 0; c < cols; c++) - { - out[c*rows + r] = in[r*cols + c]; - } - } -} - - -galileo_e1b_telemetry_decoder_cc::galileo_e1b_telemetry_decoder_cc( - Gnss_Satellite satellite, - bool dump) : - gr::block("galileo_e1b_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry Bit transition synchronization port out - this->message_port_register_out(pmt::mp("preamble_timestamp_s")); - // Ephemeris data port out - this->message_port_register_out(pmt::mp("telemetry")); - // initialize internal vars - d_dump = dump; - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - LOG(INFO) << "Initializing GALILEO E1B TELEMETRY PROCESSING"; - d_samples_per_symbol = ( Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS ) / Galileo_E1_B_SYMBOL_RATE_BPS; - - // set the preamble - unsigned short int preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS] = GALILEO_INAV_PREAMBLE; - - d_symbols_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; - - memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GALILEO_INAV_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int)); - - // preamble bits to sampled symbols - d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * d_symbols_per_preamble); - int n = 0; - for (int i = 0; i < GALILEO_INAV_PREAMBLE_LENGTH_BITS; i++) - { - for (unsigned int j = 0; j < d_samples_per_symbol; j++) - { - if (d_preambles_bits[i] == 1) - { - d_preambles_symbols[n] = 1; - } - else - { - d_preambles_symbols[n] = -1; - } - n++; - } - } - d_sample_counter = 0; - d_stat = 0; - d_preamble_index = 0; - - d_preamble_time_seconds = 0; - d_flag_frame_sync = false; - - d_flag_parity = false; - d_TOW_at_Preamble = 0; - d_TOW_at_current_symbol = 0; - delta_t = 0; - d_CRC_error_counter = 0; - flag_even_word_arrived = 0; - d_flag_preamble = false; - d_channel = 0; - Prn_timestamp_at_preamble_ms = 0.0; - flag_TOW_set = false; - d_average_count = 0; - d_decimation_output_factor = 1; -} - - -galileo_e1b_telemetry_decoder_cc::~galileo_e1b_telemetry_decoder_cc() -{ - delete d_preambles_symbols; - d_dump_file.close(); -} - - -void galileo_e1b_telemetry_decoder_cc::decode_word(double *page_part_symbols,int frame_length) -{ - double page_part_symbols_deint[frame_length]; - // 1. De-interleave - deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_deint); - - // 2. Viterbi decoder - // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) - // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180� - for (int i = 0; i < frame_length; i++) - { - if ((i + 1) % 2 == 0) - { - page_part_symbols_deint[i] = -page_part_symbols_deint[i]; - } - } - - int page_part_bits[frame_length/2]; - viterbi_decoder(page_part_symbols_deint, page_part_bits); - - // 3. Call the Galileo page decoder - std::string page_String; - for(int i = 0; i < (frame_length/2); i++) - { - if (page_part_bits[i] > 0) - { - page_String.push_back('1'); - } - else - { - page_String.push_back('0'); - } - } - - if (page_part_bits[0] == 1) - { - // DECODE COMPLETE WORD (even + odd) and TEST CRC - d_nav.split_page(page_String, flag_even_word_arrived); - if(d_nav.flag_CRC_test == true) - { - LOG(INFO) << "Galileo CRC correct on channel " << d_channel << " from satellite " << d_satellite; - std::cout << "Galileo CRC correct on channel " << d_channel << " from satellite " << d_satellite << std::endl; - } - else - { - std::cout << "Galileo CRC error on channel " << d_channel << " from satellite " << d_satellite << std::endl; - LOG(INFO) << "Galileo CRC error on channel " << d_channel << " from satellite " << d_satellite; - } - flag_even_word_arrived = 0; - } - else - { - // STORE HALF WORD (even page) - d_nav.split_page(page_String.c_str(), flag_even_word_arrived); - flag_even_word_arrived = 1; - } - - // 4. Push the new navigation data to the queues - if (d_nav.have_new_ephemeris() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); - - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - - } - if (d_nav.have_new_iono_and_GST() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_iono()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_utc_model() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_almanac() == true) - { - std::shared_ptr tmp_obj= std::make_shared(d_nav.get_almanac()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - //debug - std::cout << "Galileo almanac received!" << std::endl; - LOG(INFO) << "GPS_to_Galileo time conversion:"; - LOG(INFO) << "A0G=" << tmp_obj->A_0G_10; - LOG(INFO) << "A1G=" << tmp_obj->A_1G_10; - LOG(INFO) << "T0G=" << tmp_obj->t_0G_10; - LOG(INFO) << "WN_0G_10=" << tmp_obj->WN_0G_10; - LOG(INFO) << "Current parameters:"; - LOG(INFO) << "d_TOW_at_current_symbol=" << d_TOW_at_current_symbol; - LOG(INFO) << "d_nav.WN_0=" << d_nav.WN_0; - delta_t = tmp_obj->A_0G_10 + tmp_obj->A_1G_10 * (d_TOW_at_current_symbol - tmp_obj->t_0G_10 + 604800 * (fmod((d_nav.WN_0 - tmp_obj->WN_0G_10), 64))); - LOG(INFO) << "delta_t=" << delta_t << "[s]"; - } -} - - - - -int galileo_e1b_telemetry_decoder_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - int corr_value = 0; - int preamble_diff = 0; - - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - d_sample_counter++; //count for the processed samples - - // ########### Output the tracking data to navigation and PVT ########## - const Gnss_Synchro **in = (const Gnss_Synchro **) &input_items[0]; //Get the input samples pointer - - // TODO Optimize me! - //******* preamble correlation ******** - for (int i = 0; i < d_symbols_per_preamble; i++) - { - if (in[0][i].Prompt_I < 0) // symbols clipping - { - corr_value -= d_preambles_symbols[i]; - } - else - { - corr_value += d_preambles_symbols[i]; - } - } - d_flag_preamble = false; - - //******* frame sync ****************** - if (d_stat == 0) //no preamble information - { - if (abs(corr_value) >= d_symbols_per_preamble) - { - d_preamble_index = d_sample_counter;//record the preamble sample stamp - LOG(INFO) << "Preamble detection for Galileo SAT " << this->d_satellite; - d_stat = 1; // enter into frame pre-detection status - } - } - else if (d_stat == 1) // posible preamble lock - { - if (abs(corr_value) >= d_symbols_per_preamble) - { - //check preamble separation - preamble_diff = d_sample_counter - d_preamble_index; - if (abs(preamble_diff - GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) == 0) - { - //try to decode frame - LOG(INFO) << "Starting page decoder for Galileo SAT " << this->d_satellite; - d_preamble_index = d_sample_counter; //record the preamble sample stamp - d_stat = 2; - } - else - { - if (preamble_diff > GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) - { - d_stat = 0; // start again - } - } - } - } - else if (d_stat == 2) - { - if (d_sample_counter == d_preamble_index + GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) - { - // NEW Galileo page part is received - // 0. fetch the symbols into an array - int frame_length = GALILEO_INAV_PAGE_PART_SYMBOLS - d_symbols_per_preamble; - double page_part_symbols[frame_length]; - - for (int i = 0; i < frame_length; i++) - { - if (corr_value > 0) - { - page_part_symbols[i] = in[0][i + d_symbols_per_preamble].Prompt_I; // because last symbol of the preamble is just received now! - - } - else - { - page_part_symbols[i] = -in[0][i + d_symbols_per_preamble].Prompt_I; // because last symbol of the preamble is just received now! - } - } - - //call the decoder - decode_word(page_part_symbols, frame_length); - if (d_nav.flag_CRC_test == true) - { - d_CRC_error_counter = 0; - d_flag_preamble = true; //valid preamble indicator (initialized to false every work()) - d_preamble_index = d_sample_counter; //record the preamble sample stamp (t_P) - d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs; // - d_preamble_duration_seconds; //record the PRN start sample index associated to the preamble - if (!d_flag_frame_sync) - { - d_flag_frame_sync = true; - LOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " << d_preamble_time_seconds << " [s]"; - } - } - else - { - d_CRC_error_counter++; - d_preamble_index = d_sample_counter; //record the preamble sample stamp - if (d_CRC_error_counter > CRC_ERROR_LIMIT) - { - LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; - d_flag_frame_sync = false; - d_stat = 0; - } - } - } - } - - consume_each(1); //one by one - - // UPDATE GNSS SYNCHRO DATA - Gnss_Synchro current_synchro_data; //structure to save the synchronization information and send the output object to the next block - //1. Copy the current tracking output - current_synchro_data = in[0][0]; - //2. Add the telemetry decoder information - if (this->d_flag_preamble == true and d_nav.flag_TOW_set == true) - //update TOW at the preamble instant - // JAVI: 30/06/2014 - // TOW, in Galileo, is referred to the START of the PAGE PART, that is, THE FIRST SYMBOL OF THAT PAGE, NOT THE PREAMBLE. - // thus, no correction should be done. d_TOW_at_Preamble should be renamed to d_TOW_at_page_start. - // Since we detected the preamble, then, we are in the last symbol of that preamble, or just at the start of the first page symbol. - //flag preamble is true after the all page (even and odd) is received. I/NAV page period is 2 SECONDS - { - Prn_timestamp_at_preamble_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - if(d_nav.flag_TOW_5 == true) //page 5 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) - { - //std::cout<< "Using TOW_5 for timestamping" << std::endl; - d_TOW_at_Preamble = d_nav.TOW_5 + GALILEO_INAV_PAGE_PART_SECONDS; //TOW_5 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later - /* 1 sec (GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD) is added because - * if we have a TOW value it means that we are at the beginning of the last page part - * (GNU Radio history keeps in a buffer the rest of the incoming frame part)*/ - d_TOW_at_current_symbol = d_TOW_at_Preamble;//-GALILEO_E1_CODE_PERIOD;//+ (double)GALILEO_INAV_PREAMBLE_LENGTH_BITS/(double)GALILEO_TELEMETRY_RATE_BITS_SECOND; - d_nav.flag_TOW_5 = false; - } - - else if(d_nav.flag_TOW_6 == true) //page 6 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) - { - //std::cout<< "Using TOW_6 for timestamping" << std::endl; - d_TOW_at_Preamble = d_nav.TOW_6 + GALILEO_INAV_PAGE_PART_SECONDS; - //TOW_6 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later - /* 1 sec (GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD) is added because - * if we have a TOW value it means that we are at the beginning of the last page part - * (GNU Radio history keeps in a buffer the rest of the incoming frame part)*/ - d_TOW_at_current_symbol = d_TOW_at_Preamble;//-GALILEO_E1_CODE_PERIOD;//+ (double)GALILEO_INAV_PREAMBLE_LENGTH_BITS/(double)GALILEO_TELEMETRY_RATE_BITS_SECOND; - d_nav.flag_TOW_6 = false; - } - else - { - //this page has no timing information - d_TOW_at_Preamble = d_TOW_at_Preamble + GALILEO_INAV_PAGE_SECONDS; - d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E1_CODE_PERIOD;// + GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD; - } - } - else //if there is not a new preamble, we define the TOW of the current symbol - { - d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E1_CODE_PERIOD; - } - - //if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true) - - if(d_nav.flag_GGTO_1 == true and d_nav.flag_GGTO_2 == true and d_nav.flag_GGTO_3 == true and d_nav.flag_GGTO_4 == true) //all GGTO parameters arrived - { - delta_t = d_nav.A_0G_10 + d_nav.A_1G_10 * (d_TOW_at_current_symbol - d_nav.t_0G_10 + 604800.0 * (fmod((d_nav.WN_0 - d_nav.WN_0G_10), 64))); - } - - if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true) - { - current_synchro_data.Flag_valid_word = true; - } - else - { - current_synchro_data.Flag_valid_word = false; - } - - current_synchro_data.d_TOW = d_TOW_at_Preamble; - current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol; - current_synchro_data.d_TOW_hybrid_at_current_symbol = current_synchro_data.d_TOW_at_current_symbol - delta_t; //delta_t = t_gal - t_gps ----> t_gps = t_gal -delta_t - current_synchro_data.Flag_preamble = d_flag_preamble; - current_synchro_data.Prn_timestamp_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms; - - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - tmp_double = d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_synchro_data.Prn_timestamp_ms; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = d_TOW_at_Preamble; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - //todo: implement averaging - d_average_count++; - - if (d_average_count == d_decimation_output_factor) - { - d_average_count = 0; - //3. Make the output (copy the object contents to the GNURadio reserved memory) - *out[0] = current_synchro_data; - //std::cout<<"GPS L1 TLM output on CH="<d_channel << " SAMPLE STAMP="<(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} - - - diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h deleted file mode 100644 index 774ae2f72..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h +++ /dev/null @@ -1,133 +0,0 @@ -/*! - * \file galileo_e1b_telemetry_decoder_cc.h - * \brief Interface of a Galileo INAV message demodulator block - * \author Javier Arribas 2013 jarribas(at)cttc.es, - * Mara Branzanti 2013 mara.branzanti(at)gmail.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_CC_H -#define GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_CC_H - -#include -#include -#include -#include "Galileo_E1.h" -#include "concurrent_queue.h" -#include "gnss_satellite.h" -#include "galileo_navigation_message.h" -#include "galileo_ephemeris.h" -#include "galileo_almanac.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" - - - -class galileo_e1b_telemetry_decoder_cc; - -typedef boost::shared_ptr galileo_e1b_telemetry_decoder_cc_sptr; - -galileo_e1b_telemetry_decoder_cc_sptr galileo_e1b_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - -/*! - * \brief This class implements a block that decodes the INAV data defined in Galileo ICD - * - */ -class galileo_e1b_telemetry_decoder_cc : public gr::block -{ -public: - ~galileo_e1b_telemetry_decoder_cc(); - void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN - void set_channel(int channel); //!< Set receiver's channel - int flag_even_word_arrived; - /*! - * \brief Set decimation factor to average the GPS synchronization estimation output from the tracking module. - */ - void set_decimation(int decimation); - - /*! - * \brief This is where all signal processing takes place - */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /*! - * \brief Function which tells the scheduler how many input items - * are required to produce noutput_items output items. - */ - void forecast (int noutput_items, gr_vector_int &ninput_items_required); - -private: - friend galileo_e1b_telemetry_decoder_cc_sptr - galileo_e1b_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - galileo_e1b_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - - void viterbi_decoder(double *page_part_symbols, int *page_part_bits); - - void deinterleaver(int rows, int cols, double *in, double *out); - - void decode_word(double *symbols,int frame_length); - - unsigned short int d_preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS]; - - int *d_preambles_symbols; - unsigned int d_samples_per_symbol; - int d_symbols_per_preamble; - - long unsigned int d_sample_counter; - long unsigned int d_preamble_index; - unsigned int d_stat; - bool d_flag_frame_sync; - - bool d_flag_parity; - bool d_flag_preamble; - int d_CRC_error_counter; - - // navigation message vars - Galileo_Navigation_Message d_nav; - - bool d_dump; - Gnss_Satellite d_satellite; - int d_channel; - - // output averaging and decimation - int d_average_count; - int d_decimation_output_factor; - - double d_preamble_time_seconds; - - double d_TOW_at_Preamble; - double d_TOW_at_current_symbol; - - double Prn_timestamp_at_preamble_ms; - bool flag_TOW_set; - double delta_t; //GPS-GALILEO time offset - - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc deleted file mode 100644 index ed37a2a35..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc +++ /dev/null @@ -1,604 +0,0 @@ -/*! - * \file galileo_e5a_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo FNAV message demodulator block - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * \based on work from: - *
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e5a_telemetry_decoder_cc.h" -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "gnss_synchro.h" -#include "convolutional.h" - - -#define CRC_ERROR_LIMIT 6 - -using google::LogMessage; - - -galileo_e5a_telemetry_decoder_cc_sptr -galileo_e5a_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) -{ - return galileo_e5a_telemetry_decoder_cc_sptr(new galileo_e5a_telemetry_decoder_cc(satellite, dump)); -} - - -void galileo_e5a_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - //ninput_items_required[0] = GALILEO_FNAV_SAMPLES_PER_PAGE; // set the required sample history - if (noutput_items != 0) - { - ninput_items_required[0] = GALILEO_FNAV_CODES_PER_PREAMBLE; - } -} - - -void galileo_e5a_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int *page_part_bits) -{ - // int CodeLength = 240; - int CodeLength = 488; - int DataLength; - int nn, KK, mm, max_states; - int g_encoder[2]; - - nn = 2; // Coding rate 1/n - KK = 7; // Constraint Length - g_encoder[0] = 121; // Polynomial G1 - g_encoder[1] = 91; // Polynomial G2 - // g_encoder[0] = 171; // Polynomial G1 - // g_encoder[1] = 133; // Polynomial G2 - - mm = KK - 1; - max_states = 1 << mm; // 2^mm - DataLength = (CodeLength/nn) - mm; - - //create appropriate transition matrices - - int *out0, *out1, *state0, *state1; - out0 = (int*)calloc( max_states, sizeof(int) ); - out1 = (int*)calloc( max_states, sizeof(int) ); - state0 = (int*)calloc( max_states, sizeof(int) ); - state1 = (int*)calloc( max_states, sizeof(int) ); - - nsc_transit( out0, state0, 0, g_encoder, KK, nn ); - nsc_transit( out1, state1, 1, g_encoder, KK, nn ); - - Viterbi(page_part_bits, out0, state0, out1, state1, - page_part_symbols, KK, nn, DataLength ); - - //Clean up memory - free( out0 ); - free( out1 ); - free( state0 ); - free( state1 ); -} - - -void galileo_e5a_telemetry_decoder_cc::deinterleaver(int rows, int cols, double *in, double *out) -{ - for (int r = 0; r < rows; r++) - { - for(int c = 0; c < cols; c++) - { - out[c*rows + r] = in[r*cols + c]; - } - } -} - - -void galileo_e5a_telemetry_decoder_cc::decode_word(double *page_symbols,int frame_length) -{ - double page_symbols_deint[frame_length]; - // 1. De-interleave - - galileo_e5a_telemetry_decoder_cc::deinterleaver(GALILEO_FNAV_INTERLEAVER_ROWS, GALILEO_FNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint); - - // 2. Viterbi decoder - // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) - // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180� - for (int i = 0; i < frame_length; i++) - { - if ((i + 1) % 2 == 0) - { - page_symbols_deint[i] = -page_symbols_deint[i]; - } - } - int page_bits[frame_length/2]; - galileo_e5a_telemetry_decoder_cc::viterbi_decoder(page_symbols_deint, page_bits); - - // 3. Call the Galileo page decoder - std::string page_String; - for(int i = 0; i < frame_length; i++) - { - if (page_bits[i] > 0) - { - page_String.push_back('1'); - } - else - { - page_String.push_back('0'); - } - } - - // DECODE COMPLETE WORD (even + odd) and TEST CRC - d_nav.split_page(page_String); - if(d_nav.flag_CRC_test == true) - { - LOG(INFO) << "Galileo CRC correct on channel " << d_channel << " from satellite " << d_satellite; - std::cout << "Galileo CRC correct on channel " << d_channel << " from satellite " << d_satellite << std::endl; - } - else - { - std::cout << "Galileo CRC error on channel " << d_channel << " from satellite " << d_satellite << std::endl; - LOG(INFO)<< "Galileo CRC error on channel " << d_channel << " from satellite " << d_satellite; - } - - // 4. Push the new navigation data to the queues - if (d_nav.have_new_ephemeris() == true) - { - std::shared_ptr tmp_obj= std::make_shared(d_nav.get_ephemeris()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_iono_and_GST() == true) - { - std::shared_ptr tmp_obj= std::make_shared(d_nav.get_iono()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_utc_model() == true) - { - std::shared_ptr tmp_obj= std::make_shared(d_nav.get_utc_model()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - -} - -galileo_e5a_telemetry_decoder_cc::galileo_e5a_telemetry_decoder_cc( - Gnss_Satellite satellite, - bool dump) : - gr::block("galileo_e5a_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry Bit transition synchronization port out - this->message_port_register_out(pmt::mp("preamble_timestamp_s")); - // Ephemeris data port out - this->message_port_register_out(pmt::mp("telemetry")); - // initialize internal vars - d_dump = dump; - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - LOG(INFO) << "GALILEO E5A TELEMETRY PROCESSING: satellite " << d_satellite; - //d_samples_per_symbol = ( Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS ) / Galileo_E1_B_SYMBOL_RATE_BPS; - - // set the preamble - //unsigned short int preambles_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS] = GALILEO_FNAV_PREAMBLE; - for (int i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - if (GALILEO_FNAV_PREAMBLE.at(i) == '0') - { - d_preamble_bits[i] = 1; - } - else - { - d_preamble_bits[i] = -1; - } - } - - // memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GALILEO_FNAV_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int)); - - // // preamble bits to sampled symbols - // d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * GALILEO_FNAV_SAMPLES_PER_PREAMBLE); - // int n = 0; - // for (int i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - // { - // for (unsigned int j = 0; j < GALILEO_FNAV_SAMPLES_PER_SYMBOL; j++) - // { - // if (d_preambles_bits[i] == 1) - // { - // d_preambles_symbols[n] = 1; - // } - // else - // { - // d_preambles_symbols[n] = -1; - // } - // n++; - // } - // } - // - d_sample_counter = 0; - d_state = 0; - d_preamble_lock = false; - d_preamble_index = 0; - d_preamble_time_seconds = 0; - d_flag_frame_sync = false; - d_current_symbol = 0; - d_prompt_counter = 0; - d_symbol_counter = 0; - - d_TOW_at_Preamble = 0; - d_TOW_at_current_symbol = 0; - - d_CRC_error_counter = 0; - d_sign_init = 0; - - d_flag_preamble = false; - d_channel = 0; - Prn_timestamp_at_preamble_ms = 0; - flag_TOW_set = false; -} - - -galileo_e5a_telemetry_decoder_cc::~galileo_e5a_telemetry_decoder_cc() -{ - d_dump_file.close(); -} - - -int galileo_e5a_telemetry_decoder_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // - const Gnss_Synchro **in = (const Gnss_Synchro **) &input_items[0]; //Get the input samples pointer - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - - /* Terminology: Prompt: output from tracking Prompt correlator (Prompt samples) - * Symbol: encoded navigation bits. 1 symbol = 20 samples in E5a - * Bit: decoded navigation bits forming words as described in Galileo ICD - * States: 0 Receiving dummy samples. - * 1 Preamble not locked - * 3 Preamble lock - */ - switch (d_state) - { - case 0: - { - if (in[0][0].Prompt_I != 0) - { - d_current_symbol += in[0][0].Prompt_I; - if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1) - { - if (d_current_symbol > 0) - { - d_page_symbols[d_symbol_counter] = 1; - } - else - { - d_page_symbols[d_symbol_counter] = -1; - } - d_current_symbol = 0; - d_symbol_counter++; - d_prompt_counter = 0; - if (d_symbol_counter == GALILEO_FNAV_PREAMBLE_LENGTH_BITS - 1) - { - d_state = 1; - } - } - else - { - d_prompt_counter++; - } - } - break; - } - case 1: - { - d_current_symbol += in[0][0].Prompt_I; - if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1) - { - if (d_current_symbol > 0) - { - d_page_symbols[d_symbol_counter] = 1; - } - else - { - d_page_symbols[d_symbol_counter] = -1; - } - // d_page_symbols[d_symbol_counter] = d_current_symbol_float/(float)GALILEO_FNAV_CODES_PER_SYMBOL; - d_current_symbol = 0; - d_symbol_counter++; - d_prompt_counter = 0; - // **** Attempt Preamble correlation **** - bool corr_flag=true; - int corr_sign = 0; // sequence can be found inverted - // check if the preamble starts positive correlated or negative correlated - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS] < 0) // symbols clipping - { - corr_sign=-d_preamble_bits[0]; - } - else - { - corr_sign=d_preamble_bits[0]; - } - // the preamble is fully correlated only if maintains corr_sign along the whole sequence - for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] < 0 && d_preamble_bits[i]+corr_sign != 0) - { - //exit for - corr_flag=false; - break; - } - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] > 0 && d_preamble_bits[i]+corr_sign == 0) - { - //exit for - corr_flag=false; - break; - } - } - // - if (corr_flag==true) // preamble fully correlates - { - d_preamble_index = d_sample_counter - GALILEO_FNAV_CODES_PER_PREAMBLE;//record the preamble sample stamp. Remember correlation appears at the end of the preamble in this design - LOG(INFO) << "Preamble detection for Galileo SAT " << this->d_satellite << std::endl; - d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble. - d_state = 2; // preamble lock - } - if (d_symbol_counter >= GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS) - { - d_symbol_counter = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; // prevents overflow - } - } - else - { - d_prompt_counter++; - } - break; - } - case 2: - { - d_current_symbol += in[0][0].Prompt_I; - if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1) - { - if (d_current_symbol > 0) - { - d_page_symbols[d_symbol_counter] = 1; - } - else - { - d_page_symbols[d_symbol_counter] = -1; - } - // d_page_symbols[d_symbol_counter] = d_current_symbol_float/(float)GALILEO_FNAV_CODES_PER_SYMBOL; - d_current_symbol = 0; - d_symbol_counter++; - d_prompt_counter = 0; - // At the right sample stamp, check preamble synchro - if (d_sample_counter == d_preamble_index + GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) - { - // **** Attempt Preamble correlation **** - bool corr_flag = true; - int corr_sign = 0; // sequence can be found inverted - // corr_sign = d_preamble_bits[0] * d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - // for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - // { - // if ((d_preamble_bits[i] * d_page_symbols[i + d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS]) != corr_sign) - // { - // //exit for if one bit doesn't correlate - // corr_flag = false; - // break; - // } - // } - // check if the preamble starts positive correlated or negative correlated - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS] < 0) // symbols clipping - { - corr_sign=-d_preamble_bits[0]; - } - else - { - corr_sign=d_preamble_bits[0]; - } - // the preamble is fully correlated only if maintains corr_sign along the whole sequence - for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] < 0 && d_preamble_bits[i]+corr_sign != 0) - { - //exit for - corr_flag=false; - break; - } - if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] > 0 && d_preamble_bits[i]+corr_sign == 0) - { - //exit for - corr_flag=false; - break; - } - } - - if (corr_flag==true) // NEW PREAMBLE RECEIVED. DECODE PAGE - { - d_preamble_index = d_sample_counter - GALILEO_FNAV_CODES_PER_PREAMBLE;//record the preamble sample stamp - // DECODE WORD - decode_word(d_page_symbols, GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS); - // CHECK CRC - if (d_nav.flag_CRC_test == true) - { - d_CRC_error_counter = 0; - d_flag_preamble = true; //valid preamble indicator (initialized to false every work()) - d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs - (static_cast(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); //record the PRN start sample index associated to the preamble start. - if (!d_flag_frame_sync) - { - d_flag_frame_sync = true; - LOG(INFO) <<" Frame sync SAT " << this->d_satellite << " with preamble start at " << d_preamble_time_seconds << " [s]"; - } - d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble. - } - else - { - d_CRC_error_counter++; - if (d_CRC_error_counter > CRC_ERROR_LIMIT) - { - LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; - d_state = 1; - d_symbol_counter = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; // prevents overflow - d_flag_frame_sync = false; - } - else - { - d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble. - } - } - } - } - } - else - { - d_prompt_counter++; - } - break; - } - } - consume_each(1); - - // UPDATE GNSS SYNCHRO DATA - Gnss_Synchro current_synchro_data; //structure to save the synchronization information and send the output object to the next block - //1. Copy the current tracking output - current_synchro_data = in[0][0]; - //2. Add the telemetry decoder information - if (this->d_flag_preamble == true and d_nav.flag_TOW_set == true) - //update TOW at the preamble instant - //We expect a preamble each 10 seconds (FNAV page period) - { - Prn_timestamp_at_preamble_ms = d_preamble_time_seconds * 1000; - //Prn_timestamp_at_preamble_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - if (d_nav.flag_TOW_1 == true) - { - d_TOW_at_Preamble = d_nav.FNAV_TOW_1; - d_TOW_at_current_symbol = d_TOW_at_Preamble + (static_cast(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); - d_nav.flag_TOW_1 = false; - } - if (d_nav.flag_TOW_2 == true) - { - d_TOW_at_Preamble = d_nav.FNAV_TOW_2; - d_TOW_at_current_symbol = d_TOW_at_Preamble + (static_cast(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); - d_nav.flag_TOW_2 = false; - } - if (d_nav.flag_TOW_3 == true) - { - d_TOW_at_Preamble = d_nav.FNAV_TOW_3; - d_TOW_at_current_symbol = d_TOW_at_Preamble + (static_cast(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); - d_nav.flag_TOW_3 = false; - } - if (d_nav.flag_TOW_4 == true) - { - d_TOW_at_Preamble = d_nav.FNAV_TOW_4; - d_TOW_at_current_symbol = d_TOW_at_Preamble + (static_cast(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); - d_nav.flag_TOW_4 = false; - } - else - { - //this page has no timming information - d_TOW_at_Preamble = d_TOW_at_Preamble + GALILEO_FNAV_SECONDS_PER_PAGE; - d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD; - } - - } - else //if there is not a new preamble, we define the TOW of the current symbol - { - d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD; - } - - //if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true) - if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true) - { - current_synchro_data.Flag_valid_word = true; - } - else - { - current_synchro_data.Flag_valid_word = false; - } - - current_synchro_data.d_TOW = d_TOW_at_Preamble; - current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol; - current_synchro_data.Flag_preamble = d_flag_preamble; - current_synchro_data.Prn_timestamp_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms; - - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - tmp_double = d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_synchro_data.Prn_timestamp_ms; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = d_TOW_at_Preamble; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - d_sample_counter++; //count for the processed samples - //3. Make the output (copy the object contents to the GNURadio reserved memory) - *out[0] = current_synchro_data; - return 1; -} - - -void galileo_e5a_telemetry_decoder_cc::set_satellite(Gnss_Satellite satellite) -{ - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; - DLOG(INFO) << "Navigation Satellite set to " << d_satellite; -} - - -void galileo_e5a_telemetry_decoder_cc::set_channel(int channel) -{ - d_channel = channel; - LOG(INFO) << "Navigation channel set to " << channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename = "telemetry"; - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure& e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h deleted file mode 100644 index 1168df64b..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h +++ /dev/null @@ -1,130 +0,0 @@ -/*! - * \file galileo_e5a_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo FNAV message demodulator block - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * \based on work from: - *
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ -#define GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ - -#include -#include -#include -#include "Galileo_E5a.h" -#include "concurrent_queue.h" -#include "gnss_satellite.h" -#include "galileo_fnav_message.h" -#include "galileo_ephemeris.h" -#include "galileo_almanac.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" - -//#include "convolutional.h" - -class galileo_e5a_telemetry_decoder_cc; - -typedef boost::shared_ptr galileo_e5a_telemetry_decoder_cc_sptr; - -galileo_e5a_telemetry_decoder_cc_sptr galileo_e5a_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - - -/*! - * \brief This class implements a block that decodes the FNAV data defined in Galileo ICD - * - */ -class galileo_e5a_telemetry_decoder_cc : public gr::block -{ -public: - ~galileo_e5a_telemetry_decoder_cc(); - void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN - void set_channel(int channel); //!< Set receiver's channel - /*! - * \brief This is where all signal processing takes place - */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /*! - * \brief Function which tells the scheduler how many input items - * are required to produce noutput_items output items. - */ - void forecast (int noutput_items, gr_vector_int &ninput_items_required); - -private: - friend galileo_e5a_telemetry_decoder_cc_sptr - galileo_e5a_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - galileo_e5a_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - - void viterbi_decoder(double *page_part_symbols, int *page_part_bits); - - void deinterleaver(int rows, int cols, double *in, double *out); - - void decode_word(double *page_symbols,int frame_length); - - int d_preamble_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - // signed int d_page_symbols[GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - double d_page_symbols[GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - // signed int *d_preamble_symbols; - double d_current_symbol; - long unsigned int d_symbol_counter; - int d_prompt_counter; - int d_sign_init; - - long unsigned int d_sample_counter; - long unsigned int d_preamble_index; - - bool d_preamble_lock; - bool d_flag_frame_sync; - int d_state; - - bool d_flag_preamble; - int d_CRC_error_counter; - - // navigation message vars - Galileo_Fnav_Message d_nav; - - bool d_dump; - Gnss_Satellite d_satellite; - int d_channel; - - double d_preamble_time_seconds; - - double d_TOW_at_Preamble; - double d_TOW_at_current_symbol; - double Prn_timestamp_at_preamble_ms; - bool flag_TOW_set; - - std::string d_dump_filename; - std::ofstream d_dump_file; -}; - -#endif /* GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ */ diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc new file mode 100644 index 000000000..bb5b68a9e --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc @@ -0,0 +1,784 @@ +/*! + * \file galileo_telemetry_decoder_cc.cc + * \brief Implementation of a Galileo unified INAV and FNAV message demodulator block + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "galileo_telemetry_decoder_cc.h" +#include "control_message_factory.h" +#include "convolutional.h" +#include "display.h" +#include "gnss_synchro.h" +#include +#include +#include +#include +#include + + +#define CRC_ERROR_LIMIT 6 + +using google::LogMessage; + + +galileo_telemetry_decoder_cc_sptr +galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump) +{ + return galileo_telemetry_decoder_cc_sptr(new galileo_telemetry_decoder_cc(satellite, frame_type, dump)); +} + + +void galileo_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits) +{ + Viterbi(page_part_bits, out0, state0, out1, state1, + page_part_symbols, KK, nn, DataLength); +} + + +void galileo_telemetry_decoder_cc::deinterleaver(int32_t rows, int32_t cols, const double *in, double *out) +{ + for (int32_t r = 0; r < rows; r++) + { + for (int32_t c = 0; c < cols; c++) + { + out[c * rows + r] = in[r * cols + c]; + } + } +} + + +galileo_telemetry_decoder_cc::galileo_telemetry_decoder_cc( + const Gnss_Satellite &satellite, int frame_type, + bool dump) : gr::block("galileo_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + d_frame_type = frame_type; + LOG(INFO) << "Initializing GALILEO UNIFIED TELEMETRY DECODER"; + + switch (d_frame_type) + { + case 1: // INAV + { + d_PRN_code_period_ms = static_cast(GALILEO_E1_CODE_PERIOD_MS); + d_samples_per_symbol = Galileo_E1_B_SAMPLES_PER_SYMBOL; + d_bits_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS; + // set the preamble + d_samples_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; + d_preamble_period_symbols = GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS; + d_required_symbols = static_cast(GALILEO_INAV_PAGE_SYMBOLS) + d_samples_per_preamble; + // preamble bits to sampled symbols + d_preamble_samples = static_cast(volk_gnsssdr_malloc(d_samples_per_preamble * sizeof(int32_t), volk_gnsssdr_get_alignment())); + d_secondary_code_samples = nullptr; + d_frame_length_symbols = GALILEO_INAV_PAGE_PART_SYMBOLS - GALILEO_INAV_PREAMBLE_LENGTH_BITS; + CodeLength = GALILEO_INAV_PAGE_PART_SYMBOLS - GALILEO_INAV_PREAMBLE_LENGTH_BITS; + DataLength = (CodeLength / nn) - mm; + break; + } + case 2: // FNAV + { + d_PRN_code_period_ms = static_cast(GALILEO_E5a_CODE_PERIOD_MS); + d_samples_per_symbol = GALILEO_FNAV_CODES_PER_SYMBOL; + d_bits_per_preamble = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + // set the preamble + d_samples_per_preamble = GALILEO_FNAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; + d_preamble_period_symbols = GALILEO_FNAV_CODES_PER_PAGE; + d_required_symbols = static_cast(GALILEO_FNAV_SYMBOLS_PER_PAGE) * d_samples_per_symbol + d_samples_per_preamble; + // preamble bits to sampled symbols + d_preamble_samples = static_cast(volk_gnsssdr_malloc(d_samples_per_preamble * sizeof(int32_t), volk_gnsssdr_get_alignment())); + d_secondary_code_samples = static_cast(volk_gnsssdr_malloc(Galileo_E5a_I_SECONDARY_CODE_LENGTH * sizeof(int32_t), volk_gnsssdr_get_alignment())); + d_frame_length_symbols = GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + CodeLength = GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + DataLength = (CodeLength / nn) - mm; + for (int32_t i = 0; i < Galileo_E5a_I_SECONDARY_CODE_LENGTH; i++) + { + if (Galileo_E5a_I_SECONDARY_CODE.at(i) == '1') + { + d_secondary_code_samples[i] = 1; + } + else + { + d_secondary_code_samples[i] = -1; + } + } + break; + } + default: + d_bits_per_preamble = 0; + d_samples_per_preamble = 0; + d_preamble_period_symbols = 0; + d_preamble_samples = nullptr; + d_secondary_code_samples = nullptr; + d_samples_per_symbol = 0U; + d_PRN_code_period_ms = 0U; + d_required_symbols = 0U; + d_frame_length_symbols = 0U; + CodeLength = 0; + DataLength = 0; + std::cout << "Galileo unified telemetry decoder error: Unknown frame type " << std::endl; + } + + d_page_part_symbols = static_cast(volk_gnsssdr_malloc(d_frame_length_symbols * sizeof(double), volk_gnsssdr_get_alignment())); + int32_t n = 0; + for (int32_t i = 0; i < d_bits_per_preamble; i++) + { + switch (d_frame_type) + { + case 1: // INAV + { + if (GALILEO_INAV_PREAMBLE.at(i) == '1') + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = 1; + n++; + } + } + else + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = -1; + n++; + } + } + break; + } + case 2: // FNAV for E5a-I + { + // Galileo E5a data channel (E5a-I) still has a secondary code + int m = 0; + if (GALILEO_FNAV_PREAMBLE.at(i) == '1') + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = d_secondary_code_samples[m]; + n++; + m++; + m = m % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + else + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = -d_secondary_code_samples[m]; + n++; + m++; + m = m % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + break; + } + } + } + d_sample_counter = 0ULL; + d_stat = 0; + d_preamble_index = 0ULL; + + d_flag_frame_sync = false; + + d_flag_parity = false; + d_TOW_at_current_symbol_ms = 0; + d_TOW_at_Preamble_ms = 0; + delta_t = 0; + d_CRC_error_counter = 0; + flag_even_word_arrived = 0; + d_flag_preamble = false; + d_channel = 0; + flag_TOW_set = false; + + // vars for Viterbi decoder + int32_t max_states = 1 << mm; // 2^mm + g_encoder[0] = 121; // Polynomial G1 + g_encoder[1] = 91; // Polynomial G2 + out0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + out1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + // create appropriate transition matrices + nsc_transit(out0, state0, 0, g_encoder, KK, nn); + nsc_transit(out1, state1, 1, g_encoder, KK, nn); +} + + +galileo_telemetry_decoder_cc::~galileo_telemetry_decoder_cc() +{ + volk_gnsssdr_free(d_preamble_samples); + if (d_frame_type == 2) + { + volk_gnsssdr_free(d_secondary_code_samples); + } + volk_gnsssdr_free(d_page_part_symbols); + volk_gnsssdr_free(out0); + volk_gnsssdr_free(out1); + volk_gnsssdr_free(state0); + volk_gnsssdr_free(state1); + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void galileo_telemetry_decoder_cc::decode_INAV_word(double *page_part_symbols, int32_t frame_length) +{ + // 1. De-interleave + auto *page_part_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180º + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_part_symbols_deint[i] = -page_part_symbols_deint[i]; + } + } + + auto *page_part_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + viterbi_decoder(page_part_symbols_deint, page_part_bits); + volk_gnsssdr_free(page_part_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < (frame_length / 2); i++) + { + if (page_part_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + + if (page_part_bits[0] == 1) + { + // DECODE COMPLETE WORD (even + odd) and TEST CRC + d_inav_nav.split_page(page_String, flag_even_word_arrived); + if (d_inav_nav.flag_CRC_test == true) + { + LOG(INFO) << "Galileo E1 CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "Galileo E1 CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + flag_even_word_arrived = 0; + } + else + { + // STORE HALF WORD (even page) + d_inav_nav.split_page(page_String, flag_even_word_arrived); + flag_even_word_arrived = 1; + } + volk_gnsssdr_free(page_part_bits); + + // 4. Push the new navigation data to the queues + if (d_inav_nav.have_new_ephemeris() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_ephemeris()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_inav_nav.have_new_iono_and_GST() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_iono()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_inav_nav.have_new_utc_model() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_utc_model()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + delta_t = tmp_obj->A_0G_10 + tmp_obj->A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G_10 + 604800 * (fmod((d_inav_nav.WN_0 - tmp_obj->WN_0G_10), 64))); + DLOG(INFO) << "delta_t=" << delta_t << "[s]"; + } + if (d_inav_nav.have_new_almanac() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_almanac()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + //debug + std::cout << "Galileo E1 I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << std::endl; + DLOG(INFO) << "Current parameters:"; + DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; + DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.WN_0; + } +} + + +void galileo_telemetry_decoder_cc::decode_FNAV_word(double *page_symbols, int32_t frame_length) +{ + // 1. De-interleave + auto *page_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_FNAV_INTERLEAVER_ROWS, GALILEO_FNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180� + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_symbols_deint[i] = -page_symbols_deint[i]; + } + } + auto *page_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + viterbi_decoder(page_symbols_deint, page_bits); + volk_gnsssdr_free(page_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < frame_length; i++) + { + if (page_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + volk_gnsssdr_free(page_bits); + + // DECODE COMPLETE WORD (even + odd) and TEST CRC + d_fnav_nav.split_page(page_String); + if (d_fnav_nav.flag_CRC_test == true) + { + LOG(INFO) << "Galileo E5a CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "Galileo E5a CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + + // 4. Push the new navigation data to the queues + if (d_fnav_nav.have_new_ephemeris() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_ephemeris()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_fnav_nav.have_new_iono_and_GST() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_iono()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_fnav_nav.have_new_utc_model() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_utc_model()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } +} + + +void galileo_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} + + +void galileo_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +int galileo_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t corr_value = 0; + int32_t preamble_diff = 0; + + auto **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer + const auto **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol{}; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0][0]; + // add new symbol to the symbol queue + d_symbol_history.push_back(current_symbol.Prompt_I); + d_sample_counter++; // count for the processed samples + consume_each(1); + d_flag_preamble = false; + + if (d_symbol_history.size() > d_required_symbols) + { + // TODO Optimize me! + // ******* preamble correlation ******** + for (int32_t i = 0; i < d_samples_per_preamble; i++) + { + if (d_symbol_history.at(i) < 0.0) // symbols clipping + { + corr_value -= d_preamble_samples[i]; + } + else + { + corr_value += d_preamble_samples[i]; + } + } + } + + // ******* frame sync ****************** + switch (d_stat) + { + case 0: // no preamble information + { + if (abs(corr_value) >= d_samples_per_preamble) + { + d_preamble_index = d_sample_counter; // record the preamble sample stamp + LOG(INFO) << "Preamble detection for Galileo satellite " << this->d_satellite; + d_stat = 1; // enter into frame pre-detection status + } + break; + } + case 1: // possible preamble lock + { + if (abs(corr_value) >= d_samples_per_preamble) + { + // check preamble separation + preamble_diff = static_cast(d_sample_counter - d_preamble_index); + if (abs(preamble_diff - d_preamble_period_symbols) == 0) + { + // try to decode frame + LOG(INFO) << "Starting page decoder for Galileo satellite " << this->d_satellite; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + d_stat = 2; + } + else + { + if (preamble_diff > d_preamble_period_symbols) + { + d_stat = 0; // start again + } + } + } + break; + } + case 2: //preamble acquired + { + if (d_sample_counter == d_preamble_index + static_cast(d_preamble_period_symbols)) + { + // call the decoder + switch (d_frame_type) + { + case 1: // INAV + // NEW Galileo page part is received + // 0. fetch the symbols into an array + if (corr_value > 0) //normal PLL lock + { + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = d_symbol_history.at(i + d_samples_per_preamble); // because last symbol of the preamble is just received now! + } + } + else //180 deg. inverted carrier phase PLL lock + { + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = d_symbol_history.at(i + d_samples_per_preamble); // because last symbol of the preamble is just received now! + } + } + decode_INAV_word(d_page_part_symbols, d_frame_length_symbols); + break; + case 2: // FNAV + // NEW Galileo page part is received + // 0. fetch the symbols into an array + if (corr_value > 0) //normal PLL lock + { + int k = 0; + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = 0; + for (uint32_t m = 0; m < d_samples_per_symbol; m++) + { + d_page_part_symbols[i] += static_cast(d_secondary_code_samples[k]) * d_symbol_history.at(i * d_samples_per_symbol + d_samples_per_preamble + m); // because last symbol of the preamble is just received now! + k++; + k = k % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + } + else //180 deg. inverted carrier phase PLL lock + { + int k = 0; + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = 0; + for (uint32_t m = 0; m < d_samples_per_symbol; m++) //integrate samples into symbols + { + d_page_part_symbols[i] -= static_cast(d_secondary_code_samples[k]) * d_symbol_history.at(i * d_samples_per_symbol + d_samples_per_preamble + m); // because last symbol of the preamble is just received now! + k++; + k = k % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + } + decode_FNAV_word(d_page_part_symbols, d_frame_length_symbols); + break; + default: + return -1; + break; + } + + if (d_inav_nav.flag_CRC_test == true or d_fnav_nav.flag_CRC_test == true) + { + d_CRC_error_counter = 0; + d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) + d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) + if (!d_flag_frame_sync) + { + d_flag_frame_sync = true; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite; + } + } + else + { + d_CRC_error_counter++; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + if (d_CRC_error_counter > CRC_ERROR_LIMIT) + { + LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; + d_flag_frame_sync = false; + d_stat = 0; + d_TOW_at_current_symbol_ms = 0; + d_TOW_at_Preamble_ms = 0; + d_fnav_nav.flag_TOW_set = false; + d_inav_nav.flag_TOW_set = false; + } + } + } + break; + } + } + + // UPDATE GNSS SYNCHRO DATA + // 2. Add the telemetry decoder information + if (this->d_flag_preamble == true) + // update TOW at the preamble instant + { + switch (d_frame_type) + { + case 1: // INAV + { + if (d_inav_nav.flag_TOW_set == true) + { + if (d_inav_nav.flag_TOW_5 == true) // page 5 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) + { + // TOW_5 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay + d_TOW_at_Preamble_ms = static_cast(d_inav_nav.TOW_5 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (d_required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); + d_inav_nav.flag_TOW_5 = false; + } + + else if (d_inav_nav.flag_TOW_6 == true) // page 6 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) + { + // TOW_6 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay + d_TOW_at_Preamble_ms = static_cast(d_inav_nav.TOW_6 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (d_required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); + d_inav_nav.flag_TOW_6 = false; + } + else + { + // this page has no timing information + d_TOW_at_current_symbol_ms += static_cast(GALILEO_E1_CODE_PERIOD_MS); // + GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD; + } + } + break; + } + case 2: // FNAV + { + if (d_fnav_nav.flag_TOW_set == true) + { + if (d_fnav_nav.flag_TOW_1 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_1 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_1 = false; + } + else if (d_fnav_nav.flag_TOW_2 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_2 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_2 = false; + } + else if (d_fnav_nav.flag_TOW_3 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_3 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_3 = false; + } + else if (d_fnav_nav.flag_TOW_4 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_4 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_4 = false; + } + else + { + d_TOW_at_current_symbol_ms += static_cast(GALILEO_E5a_CODE_PERIOD_MS); + } + break; + } + } + } + } + else // if there is not a new preamble, we define the TOW of the current symbol + { + switch (d_frame_type) + { + case 1: // INAV + { + if (d_inav_nav.flag_TOW_set == true) + { + d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; + } + break; + } + case 2: // FNAV + { + if (d_fnav_nav.flag_TOW_set == true) + { + d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; + } + break; + } + } + } + + // remove used symbols from history + // todo: Use circular buffer here + if (d_symbol_history.size() > d_required_symbols) + { + d_symbol_history.pop_front(); + } + + switch (d_frame_type) + { + case 1: // INAV + { + if (d_inav_nav.flag_TOW_set) + { + if (d_inav_nav.flag_GGTO_1 == true and d_inav_nav.flag_GGTO_2 == true and d_inav_nav.flag_GGTO_3 == true and d_inav_nav.flag_GGTO_4 == true) // all GGTO parameters arrived + { + delta_t = d_inav_nav.A_0G_10 + d_inav_nav.A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - d_inav_nav.t_0G_10 + 604800.0 * (fmod((d_inav_nav.WN_0 - d_inav_nav.WN_0G_10), 64.0))); + } + + current_symbol.Flag_valid_word = true; + } + break; + } + + case 2: // FNAV + { + if (d_fnav_nav.flag_TOW_set) + { + current_symbol.Flag_valid_word = true; + } + break; + } + } + + if (d_inav_nav.flag_TOW_set or d_fnav_nav.flag_TOW_set) + { + current_symbol.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; + // todo: Galileo to GPS time conversion should be moved to observable block. + // current_symbol.TOW_at_current_symbol_ms -= delta_t; //Galileo to GPS TOW + + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; + return 1; + } + return 0; +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h new file mode 100644 index 000000000..c06df6010 --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h @@ -0,0 +1,136 @@ +/*! + * \file galileo_telemetry_decoder_cc.h + * \brief Implementation of a Galileo unified INAV and FNAV message demodulator block + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GALILEO_TELEMETRY_DECODER_CC_H +#define GNSS_SDR_GALILEO_TELEMETRY_DECODER_CC_H + + +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "galileo_almanac_helper.h" +#include "galileo_ephemeris.h" +#include "galileo_fnav_message.h" +#include "galileo_iono.h" +#include "galileo_navigation_message.h" +#include "galileo_utc_model.h" +#include "gnss_satellite.h" +#include "gnss_synchro.h" +#include +#include +#include + + +class galileo_telemetry_decoder_cc; + +typedef boost::shared_ptr galileo_telemetry_decoder_cc_sptr; + +galileo_telemetry_decoder_cc_sptr galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); + +/*! + * \brief This class implements a block that decodes the INAV and FNAV data defined in Galileo ICD + */ +class galileo_telemetry_decoder_cc : public gr::block +{ +public: + ~galileo_telemetry_decoder_cc(); + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel + int32_t flag_even_word_arrived; + + /*! + * \brief This is where all signal processing takes place + */ + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + +private: + friend galileo_telemetry_decoder_cc_sptr + galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); + galileo_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); + + void viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits); + + void deinterleaver(int32_t rows, int32_t cols, const double *in, double *out); + + void decode_INAV_word(double *symbols, int32_t frame_length); + void decode_FNAV_word(double *page_symbols, int32_t frame_length); + + int d_frame_type; + int32_t d_bits_per_preamble; + int32_t d_samples_per_preamble; + int32_t d_preamble_period_symbols; + int32_t *d_preamble_samples; + int32_t *d_secondary_code_samples; + uint32_t d_samples_per_symbol; + uint32_t d_PRN_code_period_ms; + uint32_t d_required_symbols; + uint32_t d_frame_length_symbols; + double *d_page_part_symbols; + + std::deque d_symbol_history; + + uint64_t d_sample_counter; + uint64_t d_preamble_index; + uint32_t d_stat; + bool d_flag_frame_sync; + + bool d_flag_parity; + bool d_flag_preamble; + int32_t d_CRC_error_counter; + + // navigation message vars + Galileo_Navigation_Message d_inav_nav; + Galileo_Fnav_Message d_fnav_nav; + + bool d_dump; + Gnss_Satellite d_satellite; + int32_t d_channel; + + uint32_t d_TOW_at_Preamble_ms; + uint32_t d_TOW_at_current_symbol_ms; + + bool flag_TOW_set; + double delta_t; //GPS-GALILEO time offset + + std::string d_dump_filename; + std::ofstream d_dump_file; + + // vars for Viterbi decoder + int32_t *out0, *out1, *state0, *state1; + int32_t g_encoder[2]{}; + const int32_t nn = 2; // Coding rate 1/n + const int32_t KK = 7; // Constraint Length + int32_t mm = KK - 1; + int32_t CodeLength; + int32_t DataLength; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc new file mode 100644 index 000000000..7ead9f53b --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc @@ -0,0 +1,449 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder_cc.cc + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_telemetry_decoder_cc.h" +#include +#include +#include + + +#define CRC_ERROR_LIMIT 6 + +using google::LogMessage; + + +glonass_l1_ca_telemetry_decoder_cc_sptr +glonass_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) +{ + return glonass_l1_ca_telemetry_decoder_cc_sptr(new glonass_l1_ca_telemetry_decoder_cc(satellite, dump)); +} + + +glonass_l1_ca_telemetry_decoder_cc::glonass_l1_ca_telemetry_decoder_cc( + const Gnss_Satellite &satellite, + bool dump) : gr::block("glonass_l1_ca_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + LOG(INFO) << "Initializing GLONASS L1 CA TELEMETRY DECODING"; + // Define the number of sampes per symbol. Notice that GLONASS has 2 rates, + // one for the navigation data and the other for the preamble information + d_samples_per_symbol = (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS) / GLONASS_L1_CA_SYMBOL_RATE_BPS; + + // Set the preamble information + uint16_t preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS] = GLONASS_GNAV_PREAMBLE; + // Since preamble rate is different than navigation data rate we use a constant + d_symbols_per_preamble = GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS; + + memcpy(static_cast(this->d_preambles_bits), static_cast(preambles_bits), GLONASS_GNAV_PREAMBLE_LENGTH_BITS * sizeof(uint16_t)); + + // preamble bits to sampled symbols + d_preambles_symbols = static_cast(malloc(sizeof(int32_t) * d_symbols_per_preamble)); + int32_t n = 0; + for (uint16_t d_preambles_bit : d_preambles_bits) + { + for (uint32_t j = 0; j < GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_PREAMBLE_BIT; j++) + { + if (d_preambles_bit == 1) + { + d_preambles_symbols[n] = 1; + } + else + { + d_preambles_symbols[n] = -1; + } + n++; + } + } + d_sample_counter = 0ULL; + d_stat = 0; + d_preamble_index = 0ULL; + + d_flag_frame_sync = false; + + d_flag_parity = false; + d_TOW_at_current_symbol = 0; + Flag_valid_word = false; + delta_t = 0; + d_CRC_error_counter = 0; + d_flag_preamble = false; + d_channel = 0; + flag_TOW_set = false; + d_preamble_time_samples = 0; +} + + +glonass_l1_ca_telemetry_decoder_cc::~glonass_l1_ca_telemetry_decoder_cc() +{ + delete d_preambles_symbols; + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void glonass_l1_ca_telemetry_decoder_cc::decode_string(const double *frame_symbols, int32_t frame_length) +{ + double chip_acc = 0.0; + int32_t chip_acc_counter = 0; + + // 1. Transform from symbols to bits + std::string bi_binary_code; + std::string relative_code; + std::string data_bits; + + // Group samples into bi-binary code + for (int32_t i = 0; i < (frame_length); i++) + { + chip_acc += frame_symbols[i]; + chip_acc_counter += 1; + + if (chip_acc_counter == (GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT)) + { + if (chip_acc > 0) + { + bi_binary_code.push_back('1'); + chip_acc_counter = 0; + chip_acc = 0; + } + else + { + bi_binary_code.push_back('0'); + chip_acc_counter = 0; + chip_acc = 0; + } + } + } + // Convert from bi-binary code to relative code + for (int32_t i = 0; i < (GLONASS_GNAV_STRING_BITS); i++) + { + if (bi_binary_code[2 * i] == '1' && bi_binary_code[2 * i + 1] == '0') + { + relative_code.push_back('1'); + } + else + { + relative_code.push_back('0'); + } + } + // Convert from relative code to data bits + data_bits.push_back('0'); + for (int32_t i = 1; i < (GLONASS_GNAV_STRING_BITS); i++) + { + data_bits.push_back(((relative_code[i - 1] - '0') ^ (relative_code[i] - '0')) + '0'); + } + + // 2. Call the GLONASS GNAV string decoder + d_nav.string_decoder(data_bits); + + // 3. Check operation executed correctly + if (d_nav.flag_CRC_test == true) + { + LOG(INFO) << "GLONASS GNAV CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "GLONASS GNAV CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + // 4. Push the new navigation data to the queues + if (d_nav.have_new_ephemeris() == true) + { + // get object for this SV (mandatory) + d_nav.gnav_ephemeris.i_satellite_freq_channel = d_satellite.get_rf_link(); + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV Ephemeris have been received in channel" << d_channel << " from satellite " << d_satellite; + std::cout << "New GLONASS L1 GNAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << std::endl; + } + if (d_nav.have_new_utc_model() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV UTC Model have been received in channel" << d_channel << " from satellite " << d_satellite; + std::cout << "New GLONASS L1 GNAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << std::endl; + } + if (d_nav.have_new_almanac() == true) + { + uint32_t slot_nbr = d_nav.i_alm_satellite_slot_number; + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_almanac(slot_nbr)); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV Almanac have been received in channel" << d_channel << " in slot number " << slot_nbr; + std::cout << "New GLONASS L1 GNAV almanac received in channel " << d_channel << " from satellite " << d_satellite << std::endl; + } + // 5. Update satellite information on system + if (d_nav.flag_update_slot_number == true) + { + LOG(INFO) << "GLONASS GNAV Slot Number Identified in channel " << d_channel; + d_satellite.update_PRN(d_nav.gnav_ephemeris.d_n); + d_satellite.what_block(d_satellite.get_system(), d_nav.gnav_ephemeris.d_n); + d_nav.flag_update_slot_number = false; + } +} + + +void glonass_l1_ca_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} + + +void glonass_l1_ca_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << ": exception opening Glonass TLM dump file. " << e.what(); + } + } + } +} + + +int glonass_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t corr_value = 0; + int32_t preamble_diff = 0; + + auto **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer + const auto **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol{}; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0][0]; + d_symbol_history.push_back(current_symbol); // add new symbol to the symbol queue + d_sample_counter++; // count for the processed samples + consume_each(1); + + d_flag_preamble = false; + uint32_t required_symbols = GLONASS_GNAV_STRING_SYMBOLS; + + if (d_symbol_history.size() > required_symbols) + { + // ******* preamble correlation ******** + for (int32_t i = 0; i < d_symbols_per_preamble; i++) + { + if (d_symbol_history.at(i).Prompt_I < 0) // symbols clipping + { + corr_value -= d_preambles_symbols[i]; + } + else + { + corr_value += d_preambles_symbols[i]; + } + } + } + + // ******* frame sync ****************** + if (d_stat == 0) // no preamble information + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + // Record the preamble sample stamp + d_preamble_index = d_sample_counter; + LOG(INFO) << "Preamble detection for GLONASS L1 C/A SAT " << this->d_satellite; + // Enter into frame pre-detection status + d_stat = 1; + d_preamble_time_samples = d_symbol_history.at(0).Tracking_sample_counter; // record the preamble sample stamp + } + } + else if (d_stat == 1) // possible preamble lock + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + // check preamble separation + preamble_diff = static_cast(d_sample_counter - d_preamble_index); + // Record the PRN start sample index associated to the preamble + d_preamble_time_samples = static_cast(d_symbol_history.at(0).Tracking_sample_counter); + if (abs(preamble_diff - GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) == 0) + { + // try to decode frame + LOG(INFO) << "Starting string decoder for GLONASS L1 C/A SAT " << this->d_satellite; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + d_stat = 2; + } + else + { + if (preamble_diff > GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) + { + d_stat = 0; // start again + } + DLOG(INFO) << "Failed string decoder for GLONASS L1 C/A SAT " << this->d_satellite; + } + } + } + else if (d_stat == 2) + { + // FIXME: The preamble index marks the first symbol of the string count. Here I just wait for another full string to be received before processing + if (d_sample_counter == d_preamble_index + static_cast(GLONASS_GNAV_STRING_SYMBOLS)) + { + // NEW GLONASS string received + // 0. fetch the symbols into an array + int32_t string_length = GLONASS_GNAV_STRING_SYMBOLS - d_symbols_per_preamble; + double string_symbols[GLONASS_GNAV_DATA_SYMBOLS] = {0}; + + // ******* SYMBOL TO BIT ******* + for (int32_t i = 0; i < string_length; i++) + { + if (corr_value > 0) + { + string_symbols[i] = d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + } + else + { + string_symbols[i] = -d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + } + } + + // call the decoder + decode_string(string_symbols, string_length); + if (d_nav.flag_CRC_test == true) + { + d_CRC_error_counter = 0; + d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) + d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) + if (!d_flag_frame_sync) + { + d_flag_frame_sync = true; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " + << d_symbol_history.at(0).Tracking_sample_counter << " [samples]"; + } + } + else + { + d_CRC_error_counter++; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + if (d_CRC_error_counter > CRC_ERROR_LIMIT) + { + LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; + d_flag_frame_sync = false; + d_stat = 0; + } + } + } + } + + // UPDATE GNSS SYNCHRO DATA + // 2. Add the telemetry decoder information + if (this->d_flag_preamble == true and d_nav.flag_TOW_new == true) + // update TOW at the preamble instant + { + d_TOW_at_current_symbol = floor((d_nav.gnav_ephemeris.d_TOW - GLONASS_GNAV_PREAMBLE_DURATION_S) * 1000) / 1000; + d_nav.flag_TOW_new = false; + } + else // if there is not a new preamble, we define the TOW of the current symbol + { + d_TOW_at_current_symbol = d_TOW_at_current_symbol + GLONASS_L1_CA_CODE_PERIOD; + } + + // if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true) + + // if(d_nav.flag_GGTO_1 == true and d_nav.flag_GGTO_2 == true and d_nav.flag_GGTO_3 == true and d_nav.flag_GGTO_4 == true) // all GGTO parameters arrived + // { + // delta_t = d_nav.A_0G_10 + d_nav.A_1G_10 * (d_TOW_at_current_symbol - d_nav.t_0G_10 + 604800.0 * (fmod((d_nav.WN_0 - d_nav.WN_0G_10), 64))); + // } + + if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true) + { + current_symbol.Flag_valid_word = true; + } + else + { + current_symbol.Flag_valid_word = false; + } + + current_symbol.PRN = this->d_satellite.get_PRN(); + current_symbol.TOW_at_current_symbol_ms = round(d_TOW_at_current_symbol * 1000.0); + // todo: glonass time to gps time should be done in observables block + // current_symbol.TOW_at_current_symbol_ms -= -= static_cast(delta_t) * 1000; // Galileo to GPS TOW + + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = d_TOW_at_current_symbol; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = 0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } + + // remove used symbols from history + if (d_symbol_history.size() > required_symbols) + { + d_symbol_history.pop_front(); + } + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; + + return 1; +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h new file mode 100644 index 000000000..1bdde14da --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h @@ -0,0 +1,119 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder_cc.h + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_CC_H +#define GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_CC_H + + +#include "GLONASS_L1_L2_CA.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_navigation_message.h" +#include "glonass_gnav_utc_model.h" +#include "gnss_satellite.h" +#include "gnss_synchro.h" +#include +#include +#include + + +class glonass_l1_ca_telemetry_decoder_cc; + +typedef boost::shared_ptr glonass_l1_ca_telemetry_decoder_cc_sptr; + +glonass_l1_ca_telemetry_decoder_cc_sptr glonass_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + +/*! + * \brief This class implements a block that decodes the GNAV data defined in GLONASS ICD v5.1 + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + * + */ +class glonass_l1_ca_telemetry_decoder_cc : public gr::block +{ +public: + ~glonass_l1_ca_telemetry_decoder_cc(); //!< Class destructor + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel + + /*! + * \brief This is where all signal processing takes place + */ + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + +private: + friend glonass_l1_ca_telemetry_decoder_cc_sptr + glonass_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + glonass_l1_ca_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + + void decode_string(const double *symbols, int32_t frame_length); + + //!< Help with coherent tracking + double d_preamble_time_samples; + + //!< Preamble decoding + uint16_t d_preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS]{}; + int32_t *d_preambles_symbols; + uint32_t d_samples_per_symbol; + int32_t d_symbols_per_preamble; + + //!< Storage for incoming data + std::deque d_symbol_history; + + //!< Variables for internal functionality + uint64_t d_sample_counter; //!< Sample counter as an index (1,2,3,..etc) indicating number of samples processed + uint64_t d_preamble_index; //!< Index of sample number where preamble was found + uint32_t d_stat; //!< Status of decoder + bool d_flag_frame_sync; //!< Indicate when a frame sync is achieved + bool d_flag_parity; //!< Flag indicating when parity check was achieved (crc check) + bool d_flag_preamble; //!< Flag indicating when preamble was found + int32_t d_CRC_error_counter; //!< Number of failed CRC operations + bool flag_TOW_set; //!< Indicates when time of week is set + double delta_t; //!< GPS-GLONASS time offset + + //!< Navigation Message variable + Glonass_Gnav_Navigation_Message d_nav; + + //!< Values to populate gnss synchronization structure + double d_TOW_at_current_symbol; + bool Flag_valid_word; + + //!< Satellite Information and logging capacity + Gnss_Satellite d_satellite; + int32_t d_channel; + bool d_dump; + std::string d_dump_filename; + std::ofstream d_dump_file; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.cc new file mode 100644 index 000000000..b250fb912 --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.cc @@ -0,0 +1,449 @@ +/*! + * \file glonass_l2_ca_telemetry_decoder_cc.cc + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l2_ca_telemetry_decoder_cc.h" +#include "display.h" +#include +#include +#include + + +#define CRC_ERROR_LIMIT 6 + +using google::LogMessage; + + +glonass_l2_ca_telemetry_decoder_cc_sptr +glonass_l2_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) +{ + return glonass_l2_ca_telemetry_decoder_cc_sptr(new glonass_l2_ca_telemetry_decoder_cc(satellite, dump)); +} + + +glonass_l2_ca_telemetry_decoder_cc::glonass_l2_ca_telemetry_decoder_cc( + const Gnss_Satellite &satellite, + bool dump) : gr::block("glonass_l2_ca_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + LOG(INFO) << "Initializing GLONASS L2 CA TELEMETRY DECODING"; + // Define the number of sampes per symbol. Notice that GLONASS has 2 rates, + // one for the navigation data and the other for the preamble information + d_samples_per_symbol = (GLONASS_L2_CA_CODE_RATE_HZ / GLONASS_L2_CA_CODE_LENGTH_CHIPS) / GLONASS_L2_CA_SYMBOL_RATE_BPS; + + // Set the preamble information + uint16_t preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS] = GLONASS_GNAV_PREAMBLE; + // Since preamble rate is different than navigation data rate we use a constant + d_symbols_per_preamble = GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS; + + memcpy(static_cast(this->d_preambles_bits), static_cast(preambles_bits), GLONASS_GNAV_PREAMBLE_LENGTH_BITS * sizeof(uint16_t)); + + // preamble bits to sampled symbols + d_preambles_symbols = static_cast(malloc(sizeof(int32_t) * d_symbols_per_preamble)); + int32_t n = 0; + for (uint16_t d_preambles_bit : d_preambles_bits) + { + for (uint32_t j = 0; j < GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_PREAMBLE_BIT; j++) + { + if (d_preambles_bit == 1) + { + d_preambles_symbols[n] = 1; + } + else + { + d_preambles_symbols[n] = -1; + } + n++; + } + } + d_sample_counter = 0ULL; + d_stat = 0; + d_preamble_index = 0ULL; + + d_flag_frame_sync = false; + + d_flag_parity = false; + d_TOW_at_current_symbol = 0; + Flag_valid_word = false; + delta_t = 0; + d_CRC_error_counter = 0; + d_flag_preamble = false; + d_channel = 0; + flag_TOW_set = false; + d_preamble_time_samples = 0; +} + + +glonass_l2_ca_telemetry_decoder_cc::~glonass_l2_ca_telemetry_decoder_cc() +{ + delete d_preambles_symbols; + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void glonass_l2_ca_telemetry_decoder_cc::decode_string(const double *frame_symbols, int32_t frame_length) +{ + double chip_acc = 0.0; + int32_t chip_acc_counter = 0; + + // 1. Transform from symbols to bits + std::string bi_binary_code; + std::string relative_code; + std::string data_bits; + + // Group samples into bi-binary code + for (int32_t i = 0; i < (frame_length); i++) + { + chip_acc += frame_symbols[i]; + chip_acc_counter += 1; + + if (chip_acc_counter == (GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT)) + { + if (chip_acc > 0) + { + bi_binary_code.push_back('1'); + chip_acc_counter = 0; + chip_acc = 0; + } + else + { + bi_binary_code.push_back('0'); + chip_acc_counter = 0; + chip_acc = 0; + } + } + } + // Convert from bi-binary code to relative code + for (int32_t i = 0; i < (GLONASS_GNAV_STRING_BITS); i++) + { + if (bi_binary_code[2 * i] == '1' && bi_binary_code[2 * i + 1] == '0') + { + relative_code.push_back('1'); + } + else + { + relative_code.push_back('0'); + } + } + // Convert from relative code to data bits + data_bits.push_back('0'); + for (int32_t i = 1; i < (GLONASS_GNAV_STRING_BITS); i++) + { + data_bits.push_back(((relative_code[i - 1] - '0') ^ (relative_code[i] - '0')) + '0'); + } + + // 2. Call the GLONASS GNAV string decoder + d_nav.string_decoder(data_bits); + + // 3. Check operation executed correctly + if (d_nav.flag_CRC_test == true) + { + LOG(INFO) << "GLONASS GNAV CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "GLONASS GNAV CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + // 4. Push the new navigation data to the queues + if (d_nav.have_new_ephemeris() == true) + { + // get object for this SV (mandatory) + d_nav.gnav_ephemeris.i_satellite_freq_channel = d_satellite.get_rf_link(); + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV Ephemeris have been received in channel" << d_channel << " from satellite " << d_satellite; + std::cout << TEXT_CYAN << "New GLONASS L2 GNAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; + } + if (d_nav.have_new_utc_model() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV UTC Model have been received in channel" << d_channel << " from satellite " << d_satellite; + std::cout << TEXT_CYAN << "New GLONASS L2 GNAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + } + if (d_nav.have_new_almanac() == true) + { + uint32_t slot_nbr = d_nav.i_alm_satellite_slot_number; + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_almanac(slot_nbr)); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + LOG(INFO) << "GLONASS GNAV Almanac have been received in channel" << d_channel << " in slot number " << slot_nbr; + std::cout << TEXT_CYAN << "New GLONASS L2 GNAV almanac received in channel " << d_channel << " from satellite " << d_satellite << TEXT_RESET << std::endl; + } + // 5. Update satellite information on system + if (d_nav.flag_update_slot_number == true) + { + LOG(INFO) << "GLONASS GNAV Slot Number Identified in channel " << d_channel; + d_satellite.update_PRN(d_nav.gnav_ephemeris.d_n); + d_satellite.what_block(d_satellite.get_system(), d_nav.gnav_ephemeris.d_n); + d_nav.flag_update_slot_number = false; + } +} + + +void glonass_l2_ca_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} + + +void glonass_l2_ca_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << ": exception opening Glonass TLM dump file. " << e.what(); + } + } + } +} + + +int glonass_l2_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t corr_value = 0; + int32_t preamble_diff = 0; + + auto **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer + const auto **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol{}; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0][0]; + d_symbol_history.push_back(current_symbol); // add new symbol to the symbol queue + d_sample_counter++; // count for the processed samples + consume_each(1); + + d_flag_preamble = false; + uint32_t required_symbols = GLONASS_GNAV_STRING_SYMBOLS; + + if (d_symbol_history.size() > required_symbols) + { + // ******* preamble correlation ******** + for (int32_t i = 0; i < d_symbols_per_preamble; i++) + { + if (d_symbol_history.at(i).Prompt_I < 0) // symbols clipping + { + corr_value -= d_preambles_symbols[i]; + } + else + { + corr_value += d_preambles_symbols[i]; + } + } + } + + // ******* frame sync ****************** + if (d_stat == 0) // no preamble information + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + // Record the preamble sample stamp + d_preamble_index = d_sample_counter; + LOG(INFO) << "Preamble detection for GLONASS L2 C/A SAT " << this->d_satellite; + // Enter into frame pre-detection status + d_stat = 1; + d_preamble_time_samples = d_symbol_history.at(0).Tracking_sample_counter; // record the preamble sample stamp + } + } + else if (d_stat == 1) // possible preamble lock + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + // check preamble separation + preamble_diff = static_cast(d_sample_counter - d_preamble_index); + // Record the PRN start sample index associated to the preamble + d_preamble_time_samples = static_cast(d_symbol_history.at(0).Tracking_sample_counter); + if (abs(preamble_diff - GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) == 0) + { + // try to decode frame + LOG(INFO) << "Starting string decoder for GLONASS L2 C/A SAT " << this->d_satellite; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + d_stat = 2; + } + else + { + if (preamble_diff > GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) + { + d_stat = 0; // start again + } + DLOG(INFO) << "Failed string decoder for GLONASS L2 C/A SAT " << this->d_satellite; + } + } + } + else if (d_stat == 2) + { + // FIXME: The preamble index marks the first symbol of the string count. Here I just wait for another full string to be received before processing + if (d_sample_counter == d_preamble_index + static_cast(GLONASS_GNAV_STRING_SYMBOLS)) + { + // NEW GLONASS string received + // 0. fetch the symbols into an array + int32_t string_length = GLONASS_GNAV_STRING_SYMBOLS - d_symbols_per_preamble; + double string_symbols[GLONASS_GNAV_DATA_SYMBOLS] = {0}; + + // ******* SYMBOL TO BIT ******* + for (int32_t i = 0; i < string_length; i++) + { + if (corr_value > 0) + { + string_symbols[i] = d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + } + else + { + string_symbols[i] = -d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + } + } + + // call the decoder + decode_string(string_symbols, string_length); + if (d_nav.flag_CRC_test == true) + { + d_CRC_error_counter = 0; + d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) + d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) + if (!d_flag_frame_sync) + { + d_flag_frame_sync = true; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " + << d_symbol_history.at(0).Tracking_sample_counter << " [samples]"; + } + } + else + { + d_CRC_error_counter++; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + if (d_CRC_error_counter > CRC_ERROR_LIMIT) + { + LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; + d_flag_frame_sync = false; + d_stat = 0; + } + } + } + } + + // UPDATE GNSS SYNCHRO DATA + // 2. Add the telemetry decoder information + if (this->d_flag_preamble == true and d_nav.flag_TOW_new == true) + // update TOW at the preamble instant + { + d_TOW_at_current_symbol = floor((d_nav.gnav_ephemeris.d_TOW - GLONASS_GNAV_PREAMBLE_DURATION_S) * 1000) / 1000; + d_nav.flag_TOW_new = false; + } + else // if there is not a new preamble, we define the TOW of the current symbol + { + d_TOW_at_current_symbol = d_TOW_at_current_symbol + GLONASS_L2_CA_CODE_PERIOD; + } + + // if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true) + + // if(d_nav.flag_GGTO_1 == true and d_nav.flag_GGTO_2 == true and d_nav.flag_GGTO_3 == true and d_nav.flag_GGTO_4 == true) // all GGTO parameters arrived + // { + // delta_t = d_nav.A_0G_10 + d_nav.A_1G_10 * (d_TOW_at_current_symbol - d_nav.t_0G_10 + 604800.0 * (fmod((d_nav.WN_0 - d_nav.WN_0G_10), 64))); + // } + + if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true) + { + current_symbol.Flag_valid_word = true; + } + else + { + current_symbol.Flag_valid_word = false; + } + + current_symbol.PRN = this->d_satellite.get_PRN(); + current_symbol.TOW_at_current_symbol_ms = round(d_TOW_at_current_symbol * 1000.0); + // todo: glonass time to gps time should be done in observables block + // current_symbol.TOW_at_current_symbol_ms -= static_cast(delta_t) * 1000; + + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = d_TOW_at_current_symbol; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = 0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } + + // remove used symbols from history + if (d_symbol_history.size() > required_symbols) + { + d_symbol_history.pop_front(); + } + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; + + return 1; +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.h new file mode 100644 index 000000000..8b1a25ee9 --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_cc.h @@ -0,0 +1,117 @@ +/*! + * \file glonass_l2_ca_telemetry_decoder_cc.h + * \brief Implementation of an adapter of a GLONASS L2 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_TELEMETRY_DECODER_CC_H +#define GNSS_SDR_GLONASS_L2_CA_TELEMETRY_DECODER_CC_H + + +#include "GLONASS_L1_L2_CA.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_navigation_message.h" +#include "glonass_gnav_utc_model.h" +#include "gnss_satellite.h" +#include "gnss_synchro.h" +#include +#include +#include + + +class glonass_l2_ca_telemetry_decoder_cc; + +typedef boost::shared_ptr glonass_l2_ca_telemetry_decoder_cc_sptr; + +glonass_l2_ca_telemetry_decoder_cc_sptr glonass_l2_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + +/*! + * \brief This class implements a block that decodes the GNAV data defined in GLONASS ICD v5.1 + * \see GLONASS ICD + * + */ +class glonass_l2_ca_telemetry_decoder_cc : public gr::block +{ +public: + ~glonass_l2_ca_telemetry_decoder_cc(); //!< Class destructor + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel + + /*! + * \brief This is where all signal processing takes place + */ + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + +private: + friend glonass_l2_ca_telemetry_decoder_cc_sptr + glonass_l2_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + glonass_l2_ca_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + + void decode_string(const double *symbols, int32_t frame_length); + + //!< Help with coherent tracking + double d_preamble_time_samples; + + //!< Preamble decoding + uint16_t d_preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS]{}; + int32_t *d_preambles_symbols; + uint32_t d_samples_per_symbol; + int32_t d_symbols_per_preamble; + + //!< Storage for incoming data + std::deque d_symbol_history; + + //!< Variables for internal functionality + uint64_t d_sample_counter; //!< Sample counter as an index (1,2,3,..etc) indicating number of samples processed + uint64_t d_preamble_index; //!< Index of sample number where preamble was found + uint32_t d_stat; //!< Status of decoder + bool d_flag_frame_sync; //!< Indicate when a frame sync is achieved + bool d_flag_parity; //!< Flag indicating when parity check was achieved (crc check) + bool d_flag_preamble; //!< Flag indicating when preamble was found + int32_t d_CRC_error_counter; //!< Number of failed CRC operations + bool flag_TOW_set; //!< Indicates when time of week is set + double delta_t; //!< GPS-GLONASS time offset + + //!< Navigation Message variable + Glonass_Gnav_Navigation_Message d_nav; + + //!< Values to populate gnss synchronization structure + double d_TOW_at_current_symbol; + bool Flag_valid_word; + + //!< Satellite Information and logging capacity + Gnss_Satellite d_satellite; + int32_t d_channel; + bool d_dump; + std::string d_dump_filename; + std::ofstream d_dump_file; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.cc index c90930ce3..ef2988629 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,44 +24,37 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_telemetry_decoder_cc.h" -#include -#include -#include -#include #include "control_message_factory.h" -#include "gnss_synchro.h" +#include +#include +#include +#include + #ifndef _rotl -#define _rotl(X,N) ((X << N) ^ (X >> (32-N))) // Used in the parity check algorithm +#define _rotl(X, N) (((X) << (N)) ^ ((X) >> (32 - (N)))) // Used in the parity check algorithm #endif using google::LogMessage; gps_l1_ca_telemetry_decoder_cc_sptr -gps_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) +gps_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) { return gps_l1_ca_telemetry_decoder_cc_sptr(new gps_l1_ca_telemetry_decoder_cc(satellite, dump)); } -void gps_l1_ca_telemetry_decoder_cc::forecast (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) -{ - ninput_items_required[0] = GPS_CA_PREAMBLE_LENGTH_SYMBOLS; //set the required sample history -} gps_l1_ca_telemetry_decoder_cc::gps_l1_ca_telemetry_decoder_cc( - Gnss_Satellite satellite, - bool dump) : - gr::block("gps_navigation_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + const Gnss_Satellite &satellite, + bool dump) : gr::block("gps_navigation_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { - // Telemetry Bit transition synchronization port out - this->message_port_register_out(pmt::mp("preamble_timestamp_s")); // Ephemeris data port out this->message_port_register_out(pmt::mp("telemetry")); // initialize internal vars @@ -69,18 +62,16 @@ gps_l1_ca_telemetry_decoder_cc::gps_l1_ca_telemetry_decoder_cc( d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); // set the preamble - unsigned short int preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE; - - //memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GPS_CA_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int)); + uint16_t preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE; // preamble bits to sampled symbols - d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * GPS_CA_PREAMBLE_LENGTH_SYMBOLS); - int n = 0; - for (int i = 0; i < GPS_CA_PREAMBLE_LENGTH_BITS; i++) + d_preambles_symbols = static_cast(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int32_t), volk_gnsssdr_get_alignment())); + int32_t n = 0; + for (uint16_t preambles_bit : preambles_bits) { - for (unsigned int j = 0; j < GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; j++) + for (uint32_t j = 0; j < GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; j++) { - if (preambles_bits[i] == 1) + if (preambles_bit == 1) { d_preambles_symbols[n] = 1; } @@ -91,130 +82,326 @@ gps_l1_ca_telemetry_decoder_cc::gps_l1_ca_telemetry_decoder_cc( n++; } } - d_stat = 0; - d_symbol_accumulator = 0; - d_symbol_accumulator_counter = 0; - d_frame_bit_index = 0; - d_preamble_time_seconds = 0; + d_stat = 0U; d_flag_frame_sync = false; - d_GPS_frame_4bytes = 0; d_prev_GPS_frame_4bytes = 0; - d_flag_parity = false; - d_TOW_at_Preamble = 0; - d_TOW_at_current_symbol = 0; + d_TOW_at_Preamble_ms = 0; flag_TOW_set = false; - d_average_count = 0; d_flag_preamble = false; - d_word_number = 0; - d_decimation_output_factor = 1; + d_flag_new_tow_available = false; d_channel = 0; - Prn_timestamp_at_preamble_ms = 0.0; flag_PLL_180_deg_phase_locked = false; + d_preamble_time_samples = 0ULL; + d_TOW_at_current_symbol_ms = 0; + d_symbol_history.set_capacity(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); + d_crc_error_synchronization_counter = 0; + d_current_subframe_symbol = 0; } gps_l1_ca_telemetry_decoder_cc::~gps_l1_ca_telemetry_decoder_cc() { - delete d_preambles_symbols; - d_dump_file.close(); + volk_gnsssdr_free(d_preambles_symbols); + d_symbol_history.clear(); + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } } -bool gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(unsigned int gpsword) + +bool gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(uint32_t gpsword) { - unsigned int d1, d2, d3, d4, d5, d6, d7, t, parity; - /* XOR as many bits in parallel as possible. The magic constants pick - up bits which are to be XOR'ed together to implement the GPS parity - check algorithm described in IS-GPS-200E. This avoids lengthy shift- - and-xor loops. */ + uint32_t d1, d2, d3, d4, d5, d6, d7, t, parity; + // XOR as many bits in parallel as possible. The magic constants pick + // up bits which are to be XOR'ed together to implement the GPS parity + // check algorithm described in IS-GPS-200E. This avoids lengthy shift- + // and-xor loops. d1 = gpsword & 0xFBFFBF00; - d2 = _rotl(gpsword,1) & 0x07FFBF01; - d3 = _rotl(gpsword,2) & 0xFC0F8100; - d4 = _rotl(gpsword,3) & 0xF81FFE02; - d5 = _rotl(gpsword,4) & 0xFC00000E; - d6 = _rotl(gpsword,5) & 0x07F00001; - d7 = _rotl(gpsword,6) & 0x00003000; + d2 = _rotl(gpsword, 1) & 0x07FFBF01; + d3 = _rotl(gpsword, 2) & 0xFC0F8100; + d4 = _rotl(gpsword, 3) & 0xF81FFE02; + d5 = _rotl(gpsword, 4) & 0xFC00000E; + d6 = _rotl(gpsword, 5) & 0x07F00001; + d7 = _rotl(gpsword, 6) & 0x00003000; t = d1 ^ d2 ^ d3 ^ d4 ^ d5 ^ d6 ^ d7; // Now XOR the 5 6-bit fields together to produce the 6-bit final result. - parity = t ^ _rotl(t,6) ^ _rotl(t,12) ^ _rotl(t,18) ^ _rotl(t,24); + parity = t ^ _rotl(t, 6) ^ _rotl(t, 12) ^ _rotl(t, 18) ^ _rotl(t, 24); parity = parity & 0x3F; - if (parity == (gpsword & 0x3F)) return(true); - else return(false); + if (parity == (gpsword & 0x3F)) + { + return (true); + } + + return (false); } -int gps_l1_ca_telemetry_decoder_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +void gps_l1_ca_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) { + d_nav.reset(); + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; + d_nav.i_satellite_PRN = d_satellite.get_PRN(); + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} - int corr_value = 0; - int preamble_diff_ms = 0; - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - - // ########### Output the tracking data to navigation and PVT ########## - const Gnss_Synchro **in = (const Gnss_Synchro **) &input_items[0]; //Get the input samples pointer - - //******* preamble correlation ******** - for (unsigned int i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) +void gps_l1_ca_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + d_nav.i_channel_ID = channel; + DLOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) { - if (in[0][i].Flag_valid_symbol_output == true) + if (d_dump_file.is_open() == false) { - if (in[0][i].Prompt_I < 0) // symbols clipping + try { - corr_value -= d_preambles_symbols[i] * in[0][i].correlation_length_ms; + d_dump_filename = "telemetry"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel + << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +bool gps_l1_ca_telemetry_decoder_cc::decode_subframe() +{ + char subframe[GPS_SUBFRAME_LENGTH]; + + int32_t symbol_accumulator_counter = 0; + int32_t frame_bit_index = 0; + int32_t word_index = 0; + uint32_t GPS_frame_4bytes = 0; + float symbol_accumulator = 0; + bool subframe_synchro_confirmation = false; + bool CRC_ok = true; + + for (float d_subframe_symbol : d_subframe_symbols) + { + // ******* SYMBOL TO BIT ******* + // extended correlation to bit period is enabled in tracking! + symbol_accumulator += d_subframe_symbol; // accumulate the input value in d_symbol_accumulator + symbol_accumulator_counter++; + if (symbol_accumulator_counter == 20) + { + // symbol to bit + if (symbol_accumulator > 0) GPS_frame_4bytes += 1; // insert the telemetry bit in LSB + symbol_accumulator = 0; + symbol_accumulator_counter = 0; + + // ******* bits to words ****** + frame_bit_index++; + if (frame_bit_index == 30) + { + frame_bit_index = 0; + // parity check + // Each word in wordbuff is composed of: + // Bits 0 to 29 = the GPS data word + // Bits 30 to 31 = 2 LSBs of the GPS word ahead. + // prepare the extended frame [-2 -1 0 ... 30] + if (d_prev_GPS_frame_4bytes & 0x00000001) + { + GPS_frame_4bytes = GPS_frame_4bytes | 0x40000000; + } + if (d_prev_GPS_frame_4bytes & 0x00000002) + { + GPS_frame_4bytes = GPS_frame_4bytes | 0x80000000; + } + // Check that the 2 most recently logged words pass parity. Have to first + // invert the data bits according to bit 30 of the previous word. + if (GPS_frame_4bytes & 0x40000000) + { + GPS_frame_4bytes ^= 0x3FFFFFC0; // invert the data bits (using XOR) + } + if (gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(GPS_frame_4bytes)) + { + subframe_synchro_confirmation = true; + } + else + { + // std::cout << "word invalid sat " << this->d_satellite << std::endl; + CRC_ok = false; + } + // add word to subframe + // insert the word in the correct position of the subframe + std::memcpy(&subframe[word_index * GPS_WORD_LENGTH], &GPS_frame_4bytes, sizeof(uint32_t)); + word_index++; + d_prev_GPS_frame_4bytes = GPS_frame_4bytes; // save the actual frame + GPS_frame_4bytes = 0; } else { - corr_value += d_preambles_symbols[i] * in[0][i].correlation_length_ms; + GPS_frame_4bytes <<= 1; // shift 1 bit left the telemetry word } } - if (corr_value >= GPS_CA_PREAMBLE_LENGTH_SYMBOLS) break; } + + // decode subframe + // NEW GPS SUBFRAME HAS ARRIVED! + if (CRC_ok) + { + int32_t subframe_ID = d_nav.subframe_decoder(subframe); //d ecode the subframe + if (subframe_ID > 0 and subframe_ID < 6) + { + std::cout << "New GPS NAV message received in channel " << this->d_channel << ": " + << "subframe " + << subframe_ID << " from satellite " + << Gnss_Satellite(std::string("GPS"), d_nav.i_satellite_PRN) << std::endl; + + switch (subframe_ID) + { + case 3: // we have a new set of ephemeris data for the current SV + if (d_nav.satellite_validation() == true) + { + // get ephemeris object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + break; + case 4: // Possible IONOSPHERE and UTC model update (page 18) + if (d_nav.flag_iono_valid == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_iono()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_nav.flag_utc_model_valid == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + break; + case 5: + // get almanac (if available) + //TODO: implement almanac reader in navigation_message + break; + default: + break; + } + d_flag_new_tow_available = true; + } + else + { + return false; + } + } + + return subframe_synchro_confirmation; +} + + +int gps_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t preamble_diff_ms = 0; + + auto **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer + const auto **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol{}; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0][0]; + + // record the oldest subframe symbol before inserting a new symbol into the circular buffer + if (d_current_subframe_symbol < GPS_SUBFRAME_MS and !d_symbol_history.empty()) + { + d_subframe_symbols[d_current_subframe_symbol] = d_symbol_history[0].Prompt_I; + d_current_subframe_symbol++; + } + + d_symbol_history.push_back(current_symbol); // add new symbol to the symbol queue + consume_each(1); + d_flag_preamble = false; - //******* frame sync ****************** - if (abs(corr_value) == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) + // ******* preamble correlation ******** + int32_t corr_value = 0; + if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync)) + { + // std::cout << "-------\n"; + for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) + { + if (d_symbol_history[i].Flag_valid_symbol_output == true) + { + if (d_symbol_history[i].Prompt_I < 0) // symbols clipping + { + corr_value -= d_preambles_symbols[i]; + } + else + { + corr_value += d_preambles_symbols[i]; + } + } + } + } + + // ******* frame sync ****************** + if (std::abs(corr_value) == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) { //TODO: Rewrite with state machine if (d_stat == 0) { - d_GPS_FSM.Event_gps_word_preamble(); - //record the preamble sample stamp - d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs; // record the preamble sample stamp - DLOG(INFO) << "Preamble detection for SAT " << this->d_satellite << "in[0][0].Tracking_timestamp_secs=" << round(in[0][0].Tracking_timestamp_secs * 1000.0); - //sync the symbol to bits integrator - d_symbol_accumulator = 0; - d_symbol_accumulator_counter = 0; - d_frame_bit_index = 0; - d_stat = 1; // enter into frame pre-detection status + // record the preamble sample stamp + d_preamble_time_samples = d_symbol_history[0].Tracking_sample_counter; // record the preamble sample stamp + DLOG(INFO) << "Preamble detection for SAT " << this->d_satellite << "d_symbol_history[0].Tracking_sample_counter=" << d_symbol_history[0].Tracking_sample_counter; + d_stat = 1; // enter into frame pre-detection status } - else if (d_stat == 1) //check 6 seconds of preamble separation + else if (d_stat == 1) // check 6 seconds of preamble separation { - preamble_diff_ms = round((in[0][0].Tracking_timestamp_secs - d_preamble_time_seconds) * 1000.0); - if (abs(preamble_diff_ms - GPS_SUBFRAME_MS) < 1) + preamble_diff_ms = std::round(((static_cast(d_symbol_history[0].Tracking_sample_counter) - static_cast(d_preamble_time_samples)) / static_cast(d_symbol_history[0].fs)) * 1000.0); + if (std::abs(preamble_diff_ms - GPS_SUBFRAME_MS) % GPS_SUBFRAME_MS == 0) { - DLOG(INFO) << "Preamble confirmation for SAT " << this->d_satellite << "in[0][0].Tracking_timestamp_secs=" << round(in[0][0].Tracking_timestamp_secs * 1000.0); - d_GPS_FSM.Event_gps_word_preamble(); + DLOG(INFO) << "Preamble confirmation for SAT " << this->d_satellite; d_flag_preamble = true; - d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs; // record the PRN start sample index associated to the preamble - + d_preamble_time_samples = d_symbol_history[0].Tracking_sample_counter; // record the PRN start sample index associated to the preamble if (!d_flag_frame_sync) { - // send asynchronous message to tracking to inform of frame sync and extend correlation time - pmt::pmt_t value = pmt::from_double(d_preamble_time_seconds - 0.001); - this->message_port_pub(pmt::mp("preamble_timestamp_s"), value); d_flag_frame_sync = true; if (corr_value < 0) { - flag_PLL_180_deg_phase_locked = true; // PLL is locked to opposite phase! - DLOG(INFO) << " PLL in opposite phase for Sat "<< this->d_satellite.get_PRN(); + flag_PLL_180_deg_phase_locked = true; // PLL is locked to opposite phase! + DLOG(INFO) << " PLL in opposite phase for Sat " << this->d_satellite.get_PRN(); } else { flag_PLL_180_deg_phase_locked = false; } - DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " << d_preamble_time_seconds << " [s]"; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " + << static_cast(d_preamble_time_samples) / static_cast(d_symbol_history[0].fs) << " [s]"; } + + // try to decode the subframe: + if (decode_subframe() == false) + { + d_crc_error_synchronization_counter++; + if (d_crc_error_synchronization_counter > 3) + { + DLOG(INFO) << "TOO MANY CRC ERRORS: Lost of frame sync SAT " << this->d_satellite << std::endl; + d_stat = 0; // lost of frame sync + d_flag_frame_sync = false; + flag_TOW_set = false; + d_crc_error_synchronization_counter = 0; + } + } + d_current_subframe_symbol = 0; } } } @@ -222,226 +409,74 @@ int gps_l1_ca_telemetry_decoder_cc::general_work (int noutput_items __attribute_ { if (d_stat == 1) { - preamble_diff_ms = round((in[0][0].Tracking_timestamp_secs - d_preamble_time_seconds) * 1000.0); - if (preamble_diff_ms > GPS_SUBFRAME_MS+1) + preamble_diff_ms = round(((static_cast(d_symbol_history[0].Tracking_sample_counter) - static_cast(d_preamble_time_samples)) / static_cast(d_symbol_history[0].fs)) * 1000.0); + if (preamble_diff_ms > GPS_SUBFRAME_MS) { DLOG(INFO) << "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff_ms; - d_stat = 0; //lost of frame sync + // std::cout << "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff_ms << std::endl; + d_stat = 0; // lost of frame sync d_flag_frame_sync = false; flag_TOW_set = false; + d_current_subframe_symbol = 0; + d_crc_error_synchronization_counter = 0; + d_TOW_at_current_symbol_ms = 0; } } } - //******* SYMBOL TO BIT ******* - if (in[0][0].Flag_valid_symbol_output == true) + // 2. Add the telemetry decoder information + if (this->d_flag_preamble == true and d_flag_new_tow_available == true) { - // extended correlation to bit period is enabled in tracking! - d_symbol_accumulator += in[0][0].Prompt_I; // accumulate the input value in d_symbol_accumulator - d_symbol_accumulator_counter += in[0][0].correlation_length_ms; - } - if (d_symbol_accumulator_counter >= 20) - { - if (d_symbol_accumulator > 0) - { //symbol to bit - d_GPS_frame_4bytes += 1; //insert the telemetry bit in LSB - } - d_symbol_accumulator = 0; - d_symbol_accumulator_counter = 0; - //******* bits to words ****** - d_frame_bit_index++; - if (d_frame_bit_index == 30) - { - d_frame_bit_index = 0; - // parity check - // Each word in wordbuff is composed of: - // Bits 0 to 29 = the GPS data word - // Bits 30 to 31 = 2 LSBs of the GPS word ahead. - // prepare the extended frame [-2 -1 0 ... 30] - if (d_prev_GPS_frame_4bytes & 0x00000001) - { - d_GPS_frame_4bytes = d_GPS_frame_4bytes | 0x40000000; - } - if (d_prev_GPS_frame_4bytes & 0x00000002) - { - d_GPS_frame_4bytes = d_GPS_frame_4bytes | 0x80000000; - } - /* Check that the 2 most recently logged words pass parity. Have to first - invert the data bits according to bit 30 of the previous word. */ - if(d_GPS_frame_4bytes & 0x40000000) - { - d_GPS_frame_4bytes ^= 0x3FFFFFC0; // invert the data bits (using XOR) - } - if (gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(d_GPS_frame_4bytes)) - { - memcpy(&d_GPS_FSM.d_GPS_frame_4bytes, &d_GPS_frame_4bytes, sizeof(char)*4); - d_GPS_FSM.d_preamble_time_ms = d_preamble_time_seconds * 1000.0; - d_GPS_FSM.Event_gps_word_valid(); - // send TLM data to PVT using asynchronous message queues - if (d_GPS_FSM.d_flag_new_subframe == true) - { - switch (d_GPS_FSM.d_subframe_ID) - { - case 3: //we have a new set of ephemeris data for the current SV - if (d_GPS_FSM.d_nav.satellite_validation() == true) - { - // get ephemeris object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_GPS_FSM.d_nav.get_ephemeris()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - break; - case 4: // Possible IONOSPHERE and UTC model update (page 18) - if (d_GPS_FSM.d_nav.flag_iono_valid == true) - { - std::shared_ptr tmp_obj = std::make_shared( d_GPS_FSM.d_nav.get_iono()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_GPS_FSM.d_nav.flag_utc_model_valid == true) - { - std::shared_ptr tmp_obj = std::make_shared(d_GPS_FSM.d_nav.get_utc_model()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - break; - case 5: - // get almanac (if available) - //TODO: implement almanac reader in navigation_message - break; - default: - break; - } - d_GPS_FSM.clear_flag_new_subframe(); - } - - d_flag_parity = true; - } - else - { - d_GPS_FSM.Event_gps_word_invalid(); - d_flag_parity = false; - } - d_prev_GPS_frame_4bytes = d_GPS_frame_4bytes; // save the actual frame - d_GPS_frame_4bytes = d_GPS_frame_4bytes & 0; - } - else - { - d_GPS_frame_4bytes <<= 1; //shift 1 bit left the telemetry word - } - } - // output the frame - consume_each(1); // one by one - - Gnss_Synchro current_synchro_data; // structure to save the synchronization information and send the output object to the next block - - //1. Copy the current tracking output - current_synchro_data = in[0][0]; - - //2. Add the telemetry decoder information - if (this->d_flag_preamble == true and d_GPS_FSM.d_nav.d_TOW > 0) - { - // update TOW at the preamble instant - d_TOW_at_Preamble = d_GPS_FSM.d_nav.d_TOW + GPS_L1_CA_CODE_PERIOD; - Prn_timestamp_at_preamble_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - d_TOW_at_current_symbol = d_TOW_at_Preamble; - if (flag_TOW_set == false) - { - flag_TOW_set = true; - } + d_TOW_at_current_symbol_ms = static_cast(d_nav.d_TOW * 1000.0) + GPS_CA_PREAMBLE_DURATION_MS; + d_TOW_at_Preamble_ms = static_cast(d_nav.d_TOW * 1000.0); + flag_TOW_set = true; + d_flag_new_tow_available = false; } else { - d_TOW_at_current_symbol = d_TOW_at_current_symbol + GPS_L1_CA_CODE_PERIOD; + if (flag_TOW_set == true) + { + d_TOW_at_current_symbol_ms += GPS_L1_CA_CODE_PERIOD_MS; + } } - current_synchro_data.d_TOW = d_TOW_at_Preamble; - current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol; - current_synchro_data.d_TOW_hybrid_at_current_symbol = current_synchro_data.d_TOW_at_current_symbol; // to be used in the hybrid configuration - current_synchro_data.Flag_valid_word = (d_flag_frame_sync == true and d_flag_parity == true and flag_TOW_set == true); - current_synchro_data.Flag_preamble = d_flag_preamble; - current_synchro_data.Prn_timestamp_ms = in[0][0].Tracking_timestamp_secs * 1000.0; - current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms; + if (flag_TOW_set == true) + { + current_symbol.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; + current_symbol.Flag_valid_word = flag_TOW_set; - if (flag_PLL_180_deg_phase_locked == true) - { - //correct the accumulated phase for the Costas loop phase shift, if required - current_synchro_data.Carrier_phase_rads += GPS_PI; - } + if (flag_PLL_180_deg_phase_locked == true) + { + // correct the accumulated phase for the Costas loop phase shift, if required + current_symbol.Carrier_phase_rads += GPS_PI; + } - if(d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - tmp_double = d_TOW_at_current_symbol; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = current_synchro_data.Prn_timestamp_ms; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - tmp_double = d_TOW_at_Preamble; - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } - //todo: implement averaging + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; - d_average_count++; - if (d_average_count == d_decimation_output_factor) - { - d_average_count = 0; - //3. Make the output (copy the object contents to the GNURadio reserved memory) - *out[0] = current_synchro_data; - //std::cout<<"GPS L1 TLM output on CH="<d_channel << " SAMPLE STAMP="<(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel - << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } - } + return 0; +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.h index 495b5b252..c1b55cd9f 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l1_ca_telemetry_decoder_cc.h @@ -5,7 +5,7 @@ * \author Javier Arribas, 2011. jarribas(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,23 +31,21 @@ #ifndef GNSS_SDR_GPS_L1_CA_TELEMETRY_DECODER_CC_H #define GNSS_SDR_GPS_L1_CA_TELEMETRY_DECODER_CC_H +#include "GPS_L1_CA.h" +#include "gnss_satellite.h" +#include "gnss_synchro.h" +#include "gps_navigation_message.h" +#include +#include #include #include -#include -#include -#include "GPS_L1_CA.h" -#include "gps_l1_ca_subframe_fsm.h" -#include "concurrent_queue.h" -#include "gnss_satellite.h" - - class gps_l1_ca_telemetry_decoder_cc; typedef boost::shared_ptr gps_l1_ca_telemetry_decoder_cc_sptr; gps_l1_ca_telemetry_decoder_cc_sptr -gps_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); +gps_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); /*! * \brief This class implements a block that decodes the NAV data defined in IS-GPS-200E @@ -57,74 +55,53 @@ class gps_l1_ca_telemetry_decoder_cc : public gr::block { public: ~gps_l1_ca_telemetry_decoder_cc(); - void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN - void set_channel(int channel); //!< Set receiver's channel - /*! - * \brief Set decimation factor to average the GPS synchronization estimation output from the tracking module. - */ - void set_decimation(int decimation); + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int channel); //!< Set receiver's channel /*! * \brief This is where all signal processing takes place */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /*! - * \brief Function which tells the scheduler how many input items - * are required to produce noutput_items output items. - */ - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); private: friend gps_l1_ca_telemetry_decoder_cc_sptr - gps_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + gps_l1_ca_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - gps_l1_ca_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + gps_l1_ca_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - bool gps_word_parityCheck(unsigned int gpsword); + bool gps_word_parityCheck(uint32_t gpsword); - // constants - //unsigned short int d_preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS]; - // class private vars + bool decode_subframe(); + bool new_decoder(); + int d_crc_error_synchronization_counter; int *d_preambles_symbols; - unsigned int d_stat; + uint32_t d_stat; bool d_flag_frame_sync; // symbols - std::deque d_symbol_history; - std::deque d_correlation_length_ms_history; - double d_symbol_accumulator; - short int d_symbol_accumulator_counter; + boost::circular_buffer d_symbol_history; + float d_subframe_symbols[GPS_SUBFRAME_MS]{}; // symbols per subframe + int d_current_subframe_symbol; - //bits and frame - unsigned short int d_frame_bit_index; - unsigned int d_GPS_frame_4bytes; - unsigned int d_prev_GPS_frame_4bytes; - bool d_flag_parity; + // bits and frame + uint32_t d_prev_GPS_frame_4bytes; bool d_flag_preamble; - int d_word_number; + bool d_flag_new_tow_available; - // output averaging and decimation - int d_average_count; - int d_decimation_output_factor; - - //double d_preamble_duration_seconds; // navigation message vars Gps_Navigation_Message d_nav; - GpsL1CaSubframeFsm d_GPS_FSM; bool d_dump; Gnss_Satellite d_satellite; int d_channel; - double d_preamble_time_seconds; + uint64_t d_preamble_time_samples; - long double d_TOW_at_Preamble; - long double d_TOW_at_current_symbol; + uint32_t d_TOW_at_Preamble_ms; + uint32_t d_TOW_at_current_symbol_ms; - double Prn_timestamp_at_preamble_ms; bool flag_TOW_set; bool flag_PLL_180_deg_phase_locked; diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.cc index e7fc300af..49e5704d6 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,487 +24,207 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + +#include "gps_l2c_telemetry_decoder_cc.h" +#include "display.h" +#include "gnss_synchro.h" +#include +#include +#include +#include #include #include -#include -#include -#include -#include "gnss_synchro.h" -#include "gps_l2c_telemetry_decoder_cc.h" + using google::LogMessage; -// logging levels -#define EVENT 2 // logs important events which don't occur every block -#define FLOW 3 // logs the function calls of block processing functions -#define SAMP_SYNC 4 // about 1 log entry per sample -> high output -#define LMORE 5 // - - - gps_l2c_telemetry_decoder_cc_sptr -gps_l2c_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) +gps_l2c_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) { return gps_l2c_telemetry_decoder_cc_sptr(new gps_l2c_telemetry_decoder_cc(satellite, dump)); } - gps_l2c_telemetry_decoder_cc::gps_l2c_telemetry_decoder_cc( - Gnss_Satellite satellite, - bool dump) : - gr::block("gps_l2c_telemetry_decoder_cc", - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + const Gnss_Satellite &satellite, bool dump) : gr::block("gps_l2c_telemetry_decoder_cc", + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { - // Telemetry Bit transition synchronization port out - this->message_port_register_out(pmt::mp("preamble_timestamp_s")); // Ephemeris data port out this->message_port_register_out(pmt::mp("telemetry")); // initialize internal vars d_dump = dump; d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - LOG(INFO) << "GPS L2C M TELEMETRY PROCESSING: satellite " << d_satellite; - d_block_size = GPS_L2_SAMPLES_PER_SYMBOL * GPS_L2_SYMBOLS_PER_BIT * GPS_L2_CNAV_DATA_PAGE_BITS * 2; // two CNAV frames - d_decimation_output_factor = 0; - //set_output_multiple (1); - d_average_count = 0; - d_flag_invert_buffer_symbols = false; - d_flag_invert_input_symbols = false; + DLOG(INFO) << "GPS L2C M TELEMETRY PROCESSING: satellite " << d_satellite; + // set_output_multiple (1); d_channel = 0; d_flag_valid_word = false; d_TOW_at_current_symbol = 0; d_TOW_at_Preamble = 0; - //set_history(d_samples_per_bit*8); // At least a history of 8 bits are needed to correlate with the preamble -} + d_state = 0; //initial state + d_crc_error_count = 0; + // initialize the CNAV frame decoder (libswiftcnav) + cnav_msg_decoder_init(&d_cnav_decoder); +} gps_l2c_telemetry_decoder_cc::~gps_l2c_telemetry_decoder_cc() { - d_dump_file.close(); -} - - -void gps_l2c_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - if (noutput_items != 0) + if (d_dump_file.is_open() == true) { - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = noutput_items; - } - //LOG(INFO) << "forecast(): " << "noutput_items=" << noutput_items << "\tninput_items_required ninput_items_required.size()=" << ninput_items_required.size(); -} - - -void gps_l2c_telemetry_decoder_cc::set_decimation(int decimation) -{ - d_decimation_output_factor = decimation; -} - - -int gps_l2c_telemetry_decoder_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // get pointers on in- and output gnss-synchro objects - const Gnss_Synchro *in = (const Gnss_Synchro *) input_items[0]; // input - Gnss_Synchro *out = (Gnss_Synchro *) output_items[0]; // output - - bool flag_new_cnav_frame = false; - int last_frame_preamble_start = 0; - // copy correlation samples into samples vector - d_sample_buf.push_back(in[0].Prompt_I); - - consume_each(1); //one by one - - // decode only if enough samples in buffer - if(d_sample_buf.size() >= d_block_size) - { - if (in[0].Flag_valid_symbol_output == false) // check if the tracking is locked + try { - LOG(INFO) << "Discarting channel " << d_channel << " tracking not ready!" << std::endl; - d_flag_valid_word = false; + d_dump_file.close(); } - else + catch (const std::exception &ex) { - d_flag_invert_buffer_symbols = d_flag_invert_input_symbols; - while (true) - { - if (d_flag_invert_buffer_symbols == true) - { - for (std::vector::iterator symbol_it = d_sample_buf.begin(); symbol_it != d_sample_buf.end(); symbol_it++) - { - *symbol_it = -(*symbol_it); - } - //LOG(INFO)<<"Inverting buffer symbols"; - } - // align symbols in pairs - // and obtain the bits by decoding the symbols (viterbi decoder) - // they can be already aligned or shifted by one position - std::vector bits; - - d_symbol_aligner_and_decoder.get_bits(d_sample_buf, bits); - - //std::stringstream ss; - //for (std::vector::const_iterator bit_it = bits.begin(); bit_it < bits.end(); ++bit_it) - // { - // ss << *bit_it; - // } - //LOG(INFO) << "get_bits=" << ss.str() << std::endl; - - // search for preambles - // and extract the corresponding message candidates - std::vector msg_candidates; - d_frame_detector.get_frame_candidates(bits, msg_candidates); - - // verify checksum - // and return the valid messages - std::vector valid_msgs; - d_crc_verifier.get_valid_frames(msg_candidates, valid_msgs); - if (valid_msgs.size() == 0) - { - if (d_flag_invert_buffer_symbols == d_flag_invert_input_symbols) - { - d_flag_invert_buffer_symbols = not d_flag_invert_buffer_symbols; - } - else - {//already tested the symbol inversion but CRC still fail - LOG(INFO) << "Discarting this buffer, no CNAV frames detected CH " << this->d_channel; - break; - } - } - else - { //at least one frame has good CRC, keep the invert sign for the next frames - d_flag_invert_input_symbols = d_flag_invert_buffer_symbols; - std::vector tmp_msg; - std::string msg; - //todo: now the symbol buffer size is two CNAV frames because the preamble is not detected. - // Use the first valid frame to realign the bufer symbols with the preamble start and not miss a frame - LOG(INFO) << valid_msgs.size() << " GOOD L2C CNAV FRAME DETECTED! CH " <d_channel; - for (unsigned int i = 0;i < valid_msgs.size(); i++) - { - tmp_msg = valid_msgs.at(i).second; - d_CNAV_Message.decode_page(tmp_msg); - std::cout << "Valid CNAV frame with relative preamble start at " << valid_msgs.at(i).first << std::endl; - flag_new_cnav_frame = true; - d_flag_valid_word = true; - last_frame_preamble_start = valid_msgs.at(i).first; - // 4. Push the new navigation data to the queues - if (d_CNAV_Message.have_new_ephemeris() == true) - { - // get ephemeris object for this SV - std::shared_ptr tmp_obj= std::make_shared(d_CNAV_Message.get_ephemeris()); - std::cout << "New GPS CNAV Ephemeris received for SV " << tmp_obj->i_satellite_PRN << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - - } - if (d_CNAV_Message.have_new_iono() == true) - { - std::shared_ptr tmp_obj= std::make_shared(d_CNAV_Message.get_iono()); - std::cout << "New GPS CNAV IONO model received for SV " << d_satellite.get_PRN() << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - } - break; - } - } + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); } - // clear all processed samples in the input buffer - d_sample_buf.clear(); - } - - // UPDATE GNSS SYNCHRO DATA - Gnss_Synchro current_synchro_data; //structure to save the synchronization information and send the output object to the next block - - //1. Copy the current tracking output - current_synchro_data = in[0]; - - if (d_flag_valid_word == true) - { - double Prn_timestamp_at_preamble_ms = 0; - //2. Add the telemetry decoder information - if (flag_new_cnav_frame == true) - { - //update TOW at the preamble instant - Prn_timestamp_at_preamble_ms = (in[0].Tracking_timestamp_secs * 1000.0) - (d_block_size - last_frame_preamble_start) * GPS_L2_M_PERIOD; - d_TOW_at_Preamble = d_CNAV_Message.d_TOW - GPS_L2_CNAV_DATA_PAGE_DURATION_S; - d_TOW_at_current_symbol = d_TOW_at_Preamble + (d_block_size - last_frame_preamble_start) * GPS_L2_M_PERIOD; - current_synchro_data.d_TOW = d_TOW_at_Preamble; - current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol; - current_synchro_data.d_TOW_hybrid_at_current_symbol = current_synchro_data.d_TOW_at_current_symbol; - current_synchro_data.Flag_preamble = false; - current_synchro_data.Prn_timestamp_ms = in[0].Tracking_timestamp_secs * 1000.0; - current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms; - } - else - { - d_TOW_at_current_symbol = d_TOW_at_Preamble + (d_block_size - last_frame_preamble_start) * GPS_L2_M_PERIOD; - current_synchro_data.d_TOW = d_TOW_at_Preamble; - current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol; - current_synchro_data.d_TOW_hybrid_at_current_symbol = current_synchro_data.d_TOW_at_current_symbol; - current_synchro_data.Flag_preamble = false; - current_synchro_data.Prn_timestamp_ms = in[0].Tracking_timestamp_secs * 1000.0; - current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms; - } - current_synchro_data.Flag_valid_word = true; - } - else - { - current_synchro_data.Flag_valid_word = false; - } - - d_average_count++; - if (d_average_count == d_decimation_output_factor) - { - d_average_count = 0; - //3. Make the output (copy the object contents to the GNURadio reserved memory) - out[0] = current_synchro_data; - //std::cout<<"GPS L2 TLM output on CH="<d_channel << " SAMPLE STAMP="<d_channel << " set to satellite " << d_satellite; + DLOG(INFO) << "GPS L2C CNAV telemetry decoder in channel " << this->d_channel << " set to satellite " << d_satellite; } - void gps_l2c_telemetry_decoder_cc::set_channel(int channel) { d_channel = channel; LOG(INFO) << "GPS L2C CNAV channel set to " << channel; -} - - -// ### helper class for symbol alignment and viterbi decoding ### -gps_l2c_telemetry_decoder_cc::symbol_aligner_and_decoder::symbol_aligner_and_decoder() -{ - // convolutional code properties - d_KK = 7; - int nn = 2; - int g_encoder[nn]; - g_encoder[0] = 121; //171o - g_encoder[1] = 91; //133o - - d_vd1 = new Viterbi_Decoder(g_encoder, d_KK, nn); - d_vd2 = new Viterbi_Decoder(g_encoder, d_KK, nn); - d_past_symbol = 0; -} - - -gps_l2c_telemetry_decoder_cc::symbol_aligner_and_decoder::~symbol_aligner_and_decoder() -{ - delete d_vd1; - delete d_vd2; -} - - -void gps_l2c_telemetry_decoder_cc::symbol_aligner_and_decoder::reset() -{ - d_past_symbol = 0; - d_vd1->reset(); - d_vd2->reset(); -} - - -bool gps_l2c_telemetry_decoder_cc::symbol_aligner_and_decoder::get_bits(const std::vector & symbols, std::vector & bits) -{ - const int traceback_depth = 5 * d_KK; - int nbits_requested = symbols.size() / GPS_L2_SYMBOLS_PER_BIT; - int nbits_decoded; - // fill two vectors with the two possible symbol alignments - std::vector symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector - std::vector symbols_vd2; // shifted symbol vector -> add past sample in front of input vector - symbols_vd2.push_back(d_past_symbol); - for (std::vector::const_iterator symbol_it = symbols.begin(); symbol_it != symbols.end() - 1; ++symbol_it) + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) { - symbols_vd2.push_back(*symbol_it); - } - // arrays for decoded bits - int * bits_vd1 = new int[nbits_requested]; - int * bits_vd2 = new int[nbits_requested]; - // decode - float metric_vd1 = d_vd1->decode_continuous(symbols_vd1.data(), traceback_depth, bits_vd1, nbits_requested, nbits_decoded); - float metric_vd2 = d_vd2->decode_continuous(symbols_vd2.data(), traceback_depth, bits_vd2, nbits_requested, nbits_decoded); - //LOG(INFO)<<"metric_vd1="<::const_iterator bit_it = bits.begin(); bit_it < bits.end(); ++bit_it) - { - d_buffer.push_back(*bit_it); - //ss << *bit_it; - count++; - } - //LOG(INFO) << ss.str() << " into working buffer (" << count << " bits)"; - int relative_preamble_start = 0; - while(d_buffer.size() >= cnav_msg_length) - { - // compare with all preambles - for (std::vector>::iterator preample_it = preambles.begin(); preample_it < preambles.end(); ++preample_it) + if (d_dump_file.is_open() == false) { - bool preamble_detected = true; - bool inv_preamble_detected = true; - // compare the buffer bits with the preamble bits - for (std::vector::iterator preample_bit_it = preample_it->begin(); preample_bit_it < preample_it->end(); ++preample_bit_it) + try { - preamble_detected = *preample_bit_it == d_buffer[preample_bit_it - preample_it->begin()] ? preamble_detected : false ; - inv_preamble_detected = *preample_bit_it != d_buffer[preample_bit_it - preample_it->begin()] ? inv_preamble_detected : false ; + d_dump_filename = "telemetry_L2CM_"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel + << " Log file: " << d_dump_filename.c_str(); } - if (preamble_detected || inv_preamble_detected) + catch (const std::ifstream::failure &e) { - // copy candidate - std::vector candidate; - std::copy(d_buffer.begin(), d_buffer.begin() + cnav_msg_length, std::back_inserter(candidate)); - if(inv_preamble_detected) - { - // invert bits - for (std::vector::iterator candidate_bit_it = candidate.begin(); candidate_bit_it != candidate.end(); candidate_bit_it++) - *candidate_bit_it = *candidate_bit_it == 0 ? 1 : 0; - } - msg_candidates.push_back(std::pair>(relative_preamble_start, candidate)); - //ss.str(""); - //ss << "preamble " << preample_it - preambles.begin() << (inv_preamble_detected?" inverted":" normal") << " detected! candidate="; - //for (std::vector::iterator bit_it = candidate.begin(); bit_it < candidate.end(); ++bit_it) - // ss << *bit_it; - //LOG(INFO) << ss.str(); + LOG(WARNING) << "channel " << d_channel << " Exception opening Telemetry GPS L2 dump file " << e.what(); } } - relative_preamble_start++; - // remove bit in front - d_buffer.pop_front(); } } -// ### helper class for checking the CRC of the message candidates ### - -void gps_l2c_telemetry_decoder_cc::crc_verifier::reset() +int gps_l2c_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + // get pointers on in- and output gnss-synchro objects + auto *out = reinterpret_cast(output_items[0]); // Get the output buffer pointer + const auto *in = reinterpret_cast(input_items[0]); // Get the input buffer pointer -} + bool flag_new_cnav_frame = false; + cnav_msg_t msg; + uint32_t delay = 0; -void gps_l2c_telemetry_decoder_cc::crc_verifier::get_valid_frames(const std::vector & msg_candidates, std::vector & valid_msgs) -{ - std::vector tmp_msg; - LOG(INFO) << "get_valid_frames(): " << "msg_candidates.size()=" << msg_candidates.size(); - // for each candidate - for (std::vector::const_iterator candidate_it = msg_candidates.begin(); candidate_it < msg_candidates.end(); ++candidate_it) + // add the symbol to the decoder + uint8_t symbol_clip = static_cast(in[0].Prompt_I > 0) * 255; + flag_new_cnav_frame = cnav_msg_decoder_add_symbol(&d_cnav_decoder, symbol_clip, &msg, &delay); + + consume_each(1); // one by one + + // UPDATE GNSS SYNCHRO DATA + Gnss_Synchro current_synchro_data{}; // structure to save the synchronization information and send the output object to the next block + + // 1. Copy the current tracking output + current_synchro_data = in[0]; + + // 2. Add the telemetry decoder information + // check if new CNAV frame is available + if (flag_new_cnav_frame == true) { - // convert to bytes - std::vector candidate_bytes; - zerropad_back_and_convert_to_bytes(candidate_it->second, candidate_bytes); - // verify CRC - d_checksum_agent.reset(0); - d_checksum_agent.process_bytes(candidate_bytes.data(), candidate_bytes.size()); - unsigned int crc = d_checksum_agent.checksum(); - //LOG(INFO) << "candidate " << ": final crc remainder= " << std::hex << crc - // << std::setfill(' ') << std::resetiosflags(std::ios::hex); - // the final remainder must be zero for a valid message, because the CRC is done over the received CRC value - if (crc == 0) + std::bitset raw_bits; + // Expand packet bits to bitsets. Notice the reverse order of the bits sequence, required by the CNAV message decoder + for (uint32_t i = 0; i < GPS_L2_CNAV_DATA_PAGE_BITS; i++) { - valid_msgs.push_back(msg_candiate_int_t(candidate_it->first, candidate_it->second)); - std::cout << "Valid CNAV message found!"<> (7 - i % 8)) & 1u); + } + + d_CNAV_Message.decode_page(raw_bits); + + // Push the new navigation data to the queues + if (d_CNAV_Message.have_new_ephemeris() == true) + { + // get ephemeris object for this SV + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_ephemeris()); + std::cout << TEXT_BLUE << "New GPS CNAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_CNAV_Message.have_new_iono() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_iono()); + std::cout << TEXT_BLUE << "New GPS CNAV message received in channel " << d_channel << ": iono model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + + if (d_CNAV_Message.have_new_utc_model() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_utc_model()); + std::cout << TEXT_BLUE << "New GPS CNAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + + // update TOW at the preamble instant + d_TOW_at_Preamble = static_cast(msg.tow); + // The time of the last input symbol can be computed from the message ToW and + // delay by the formulae: + // \code + // symbolTime_ms = msg->tow * 6000 + *pdelay * 20 + (12 * 20); 12 symbols of the encoder's transitory + d_TOW_at_current_symbol = static_cast(msg.tow) * 6.0 + static_cast(delay) * GPS_L2_M_PERIOD + 12 * GPS_L2_M_PERIOD; + //d_TOW_at_current_symbol = floor(d_TOW_at_current_symbol * 1000.0) / 1000.0; + d_flag_valid_word = true; + } + else + { + d_TOW_at_current_symbol += GPS_L2_M_PERIOD; + if (current_synchro_data.Flag_valid_symbol_output == false) + { + d_flag_valid_word = false; } } -} + current_synchro_data.TOW_at_current_symbol_ms = round(d_TOW_at_current_symbol * 1000.0); + current_synchro_data.Flag_valid_word = d_flag_valid_word; - -void gps_l2c_telemetry_decoder_cc::crc_verifier::zerropad_back_and_convert_to_bytes(const std::vector & msg_candidate, std::vector & bytes) -{ - //std::stringstream ss; - const size_t bits_per_byte = 8; - unsigned char byte = 0; - //LOG(INFO) << "zerropad_back_and_convert_to_bytes():" << byte; - for (std::vector::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it) + if (d_dump == true) { - int idx_bit = candidate_bit_it - msg_candidate.begin(); - int bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); - byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte; - // ss << *candidate_bit_it; - if (idx_bit % bits_per_byte == bits_per_byte - 1) + // MULTIPLEXED FILE RECORDING - Record results to file + try { - bytes.push_back(byte); - //LOG(INFO) << ss.str() << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte; ss.str(""); - byte = 0; + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = d_TOW_at_current_symbol; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_synchro_data.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = d_TOW_at_Preamble; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing Telemetry GPS L2 dump file " << e.what(); } } - bytes.push_back(byte); // implies: insert 6 zeros at the end to fit the 250bits into a multiple of bytes - //LOG(INFO) << " -> byte=" << std::setw(2) - // << std::setfill('0') << std::hex << (unsigned int)byte - // << std::setfill(' ') << std::resetiosflags(std::ios::hex); -} -void gps_l2c_telemetry_decoder_cc::crc_verifier::zerropad_front_and_convert_to_bytes(const std::vector & msg_candidate, std::vector & bytes) -{ - //std::stringstream ss; - const size_t bits_per_byte = 8; - unsigned char byte = 0; - int idx_bit = 6; // insert 6 zeros at the front to fit the 250bits into a multiple of bytes - //LOG(INFO) << "zerropad_front_and_convert_to_bytes():" << byte; - for (std::vector::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it) - { - int bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); - byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte; - // ss << *candidate_bit_it; - if (idx_bit % bits_per_byte == bits_per_byte - 1) - { - bytes.push_back(byte); - //LOG(INFO) << ss.str() << " -> byte=" << std::setw(2) - // << std::setfill('0') << std::hex << (unsigned int)byte; ss.str(""); - byte = 0; - } - idx_bit++; - } - //LOG(INFO) << " -> byte=" << std::setw(2) - // << std::setfill('0') << std::hex << (unsigned int)byte - // << std::setfill(' ') << std::resetiosflags(std::ios::hex); + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + out[0] = current_synchro_data; + return 1; } - diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.h index 2b0ce1b5b..8b5922575 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l2c_telemetry_decoder_cc.h @@ -5,7 +5,7 @@ * \author Javier Arribas, 2015. jarribas(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,20 +31,28 @@ #ifndef GNSS_SDR_GPS_L2C_TELEMETRY_DECODER_CC_H #define GNSS_SDR_GPS_L2C_TELEMETRY_DECODER_CC_H -#include // for copy + +#include "gnss_satellite.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include "gps_cnav_navigation_message.h" +#include +#include // for copy +#include #include #include #include -#include // for pair +#include // for pair #include -#include -#include -#include "gnss_satellite.h" -#include "viterbi_decoder.h" -#include "gps_cnav_navigation_message.h" -#include "gps_cnav_ephemeris.h" -#include "gps_cnav_iono.h" -#include "concurrent_queue.h" + + +extern "C" +{ +#include "bits.h" +#include "cnav_msg.h" +#include "edc.h" +} + #include "GPS_L2C.h" class gps_l2c_telemetry_decoder_cc; @@ -52,7 +60,7 @@ class gps_l2c_telemetry_decoder_cc; typedef boost::shared_ptr gps_l2c_telemetry_decoder_cc_sptr; gps_l2c_telemetry_decoder_cc_sptr -gps_l2c_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); +gps_l2c_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); /*! * \brief This class implements a block that decodes the SBAS integrity and corrections data defined in RTCA MOPS DO-229 @@ -62,91 +70,36 @@ class gps_l2c_telemetry_decoder_cc : public gr::block { public: ~gps_l2c_telemetry_decoder_cc(); - void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN - void set_channel(int channel); //!< Set receiver's channel - void set_decimation(int decimation); + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel /*! * \brief This is where all signal processing takes place */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /*! - * \brief Function which tells the scheduler how many input items - * are required to produce noutput_items output items. - */ - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); private: friend gps_l2c_telemetry_decoder_cc_sptr - gps_l2c_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - gps_l2c_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - - void viterbi_decoder(double *page_part_symbols, int *page_part_bits); - void align_samples(); + gps_l2c_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + gps_l2c_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); bool d_dump; Gnss_Satellite d_satellite; - int d_channel; + int32_t d_channel; std::string d_dump_filename; std::ofstream d_dump_file; + cnav_msg_decoder_t d_cnav_decoder{}; + + int32_t d_state; + int32_t d_crc_error_count; + double d_TOW_at_current_symbol; double d_TOW_at_Preamble; bool d_flag_valid_word; - bool d_flag_invert_input_symbols; - bool d_flag_invert_buffer_symbols; - int d_decimation_output_factor; - int d_average_count; - size_t d_block_size; //!< number of samples which are processed during one invocation of the algorithms - std::vector d_sample_buf; //!< input buffer holding the samples to be processed in one block - - typedef std::pair> msg_candiate_int_t; - typedef std::pair> msg_candiate_char_t; - - // helper class for symbol alignment and Viterbi decoding - class symbol_aligner_and_decoder - { - public: - symbol_aligner_and_decoder(); - ~symbol_aligner_and_decoder(); - void reset(); - bool get_bits(const std::vector & symbols, std::vector & bits); - private: - int d_KK; - Viterbi_Decoder * d_vd1; - Viterbi_Decoder * d_vd2; - double d_past_symbol; - } d_symbol_aligner_and_decoder; - - - // helper class for detecting the preamble and collect the corresponding message candidates - class frame_detector - { - public: - void reset(); - void get_frame_candidates(const std::vector & bits, std::vector>> & msg_candidates); - private: - std::deque d_buffer; - } d_frame_detector; - - - // helper class for checking the CRC of the message candidates - class crc_verifier - { - public: - void reset(); - void get_valid_frames(const std::vector & msg_candidates, std::vector & valid_msgs); - private: - typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> crc_24_q_type; - crc_24_q_type d_checksum_agent; - void zerropad_front_and_convert_to_bytes(const std::vector & msg_candidate, std::vector & bytes); - void zerropad_back_and_convert_to_bytes(const std::vector & msg_candidate, std::vector & bytes); - } d_crc_verifier; - Gps_CNAV_Navigation_Message d_CNAV_Message; }; diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.cc new file mode 100644 index 000000000..76e64eaaf --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.cc @@ -0,0 +1,286 @@ +/*! + * \file gps_l5_telemetry_decoder_cc.cc + * \brief Implementation of a CNAV message demodulator block + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l5_telemetry_decoder_cc.h" +#include "display.h" +#include "gnss_synchro.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + +gps_l5_telemetry_decoder_cc_sptr +gps_l5_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) +{ + return gps_l5_telemetry_decoder_cc_sptr(new gps_l5_telemetry_decoder_cc(satellite, dump)); +} + + +gps_l5_telemetry_decoder_cc::gps_l5_telemetry_decoder_cc( + const Gnss_Satellite &satellite, bool dump) : gr::block("gps_l5_telemetry_decoder_cc", + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "GPS L5 TELEMETRY PROCESSING: satellite " << d_satellite; + d_channel = 0; + d_flag_valid_word = false; + d_TOW_at_current_symbol_ms = 0U; + d_TOW_at_Preamble_ms = 0U; + // initialize the CNAV frame decoder (libswiftcnav) + cnav_msg_decoder_init(&d_cnav_decoder); + for (int32_t aux = 0; aux < GPS_L5i_NH_CODE_LENGTH; aux++) + { + if (GPS_L5i_NH_CODE[aux] == 0) + { + bits_NH[aux] = -1.0; + } + else + { + bits_NH[aux] = 1.0; + } + } + sync_NH = false; + new_sym = false; +} + + +gps_l5_telemetry_decoder_cc::~gps_l5_telemetry_decoder_cc() +{ + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void gps_l5_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + LOG(INFO) << "GPS L5 CNAV telemetry decoder in channel " << this->d_channel << " set to satellite " << d_satellite; + d_CNAV_Message.reset(); +} + + +void gps_l5_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + d_CNAV_Message.reset(); + LOG(INFO) << "GPS L5 CNAV channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry_L5_"; + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel + << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening Telemetry GPS L5 dump file " << e.what(); + } + } + } +} + + +int gps_l5_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // get pointers on in- and output gnss-synchro objects + auto *out = reinterpret_cast(output_items[0]); // Get the output buffer pointer + const auto *in = reinterpret_cast(input_items[0]); // Get the input buffer pointer + + // UPDATE GNSS SYNCHRO DATA + Gnss_Synchro current_synchro_data{}; //structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_synchro_data = in[0]; + consume_each(1); //one by one + sym_hist.push_back(in[0].Prompt_I); + int32_t corr_NH = 0; + int32_t symbol_value = 0; + + // Search correlation with Neuman-Hofman Code (see IS-GPS-705D) + if (sym_hist.size() == GPS_L5i_NH_CODE_LENGTH) + { + for (int32_t i = 0; i < GPS_L5i_NH_CODE_LENGTH; i++) + { + if ((bits_NH[i] * sym_hist.at(i)) > 0.0) + { + corr_NH += 1; + } + else + { + corr_NH -= 1; + } + } + if (abs(corr_NH) == GPS_L5i_NH_CODE_LENGTH) + { + sync_NH = true; + if (corr_NH > 0) + { + symbol_value = 1; + } + else + { + symbol_value = -1; + } + new_sym = true; + sym_hist.clear(); + } + else + { + sym_hist.pop_front(); + sync_NH = false; + new_sym = false; + } + } + + bool flag_new_cnav_frame = false; + cnav_msg_t msg; + uint32_t delay = 0; + + // add the symbol to the decoder + if (new_sym) + { + uint8_t symbol_clip = static_cast(symbol_value > 0) * 255; + flag_new_cnav_frame = cnav_msg_decoder_add_symbol(&d_cnav_decoder, symbol_clip, &msg, &delay); + new_sym = false; + } + // 2. Add the telemetry decoder information + // check if new CNAV frame is available + if (flag_new_cnav_frame == true) + { + std::bitset raw_bits; + // Expand packet bits to bitsets. Notice the reverse order of the bits sequence, required by the CNAV message decoder + for (uint32_t i = 0; i < GPS_L5_CNAV_DATA_PAGE_BITS; i++) + { + raw_bits[GPS_L5_CNAV_DATA_PAGE_BITS - 1 - i] = ((msg.raw_msg[i / 8] >> (7 - i % 8)) & 1u); + } + + d_CNAV_Message.decode_page(raw_bits); + + // Push the new navigation data to the queues + if (d_CNAV_Message.have_new_ephemeris() == true) + { + // get ephemeris object for this SV + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_ephemeris()); + std::cout << TEXT_MAGENTA << "New GPS L5 CNAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_CNAV_Message.have_new_iono() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_iono()); + std::cout << TEXT_MAGENTA << "New GPS L5 CNAV message received in channel " << d_channel << ": iono model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + + if (d_CNAV_Message.have_new_utc_model() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_CNAV_Message.get_utc_model()); + std::cout << TEXT_MAGENTA << "New GPS L5 CNAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + + // update TOW at the preamble instant + d_TOW_at_Preamble_ms = msg.tow * 6000; + // The time of the last input symbol can be computed from the message ToW and + // delay by the formulae: + // \code + // symbolTime_ms = msg->tow * 6000 + *pdelay * 10 + (12 * 10); 12 symbols of the encoder's transitory + d_TOW_at_current_symbol_ms = msg.tow * 6000 + (delay + 12) * GPS_L5i_SYMBOL_PERIOD_MS; + d_flag_valid_word = true; + } + else + { + d_TOW_at_current_symbol_ms += GPS_L5i_PERIOD_MS; + if (current_synchro_data.Flag_valid_symbol_output == false) + { + d_flag_valid_word = false; + } + } + + if (d_flag_valid_word == true) + { + current_synchro_data.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; + current_synchro_data.Flag_valid_word = d_flag_valid_word; + + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_synchro_data.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing Telemetry GPS L5 dump file " << e.what(); + } + } + + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + out[0] = current_synchro_data; + return 1; + } + return 0; +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.h new file mode 100644 index 000000000..eb57696bc --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/gps_l5_telemetry_decoder_cc.h @@ -0,0 +1,100 @@ +/*! + * \file gps_l5_telemetry_decoder_cc.h + * \brief Interface of a CNAV message demodulator block + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5_TELEMETRY_DECODER_CC_H +#define GNSS_SDR_GPS_L5_TELEMETRY_DECODER_CC_H + + +#include "gnss_satellite.h" +#include "gps_cnav_navigation_message.h" +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" +{ +#include "bits.h" +#include "cnav_msg.h" +#include "edc.h" +} + +#include "GPS_L5.h" + +class gps_l5_telemetry_decoder_cc; + +typedef boost::shared_ptr gps_l5_telemetry_decoder_cc_sptr; + +gps_l5_telemetry_decoder_cc_sptr +gps_l5_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + +/*! + * \brief This class implements a GPS L5 Telemetry decoder + * + */ +class gps_l5_telemetry_decoder_cc : public gr::block +{ +public: + ~gps_l5_telemetry_decoder_cc(); + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + +private: + friend gps_l5_telemetry_decoder_cc_sptr + gps_l5_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + gps_l5_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + + bool d_dump; + Gnss_Satellite d_satellite; + int32_t d_channel; + + std::string d_dump_filename; + std::ofstream d_dump_file; + + cnav_msg_decoder_t d_cnav_decoder{}; + + uint32_t d_TOW_at_current_symbol_ms; + uint32_t d_TOW_at_Preamble_ms; + bool d_flag_valid_word; + + Gps_CNAV_Navigation_Message d_CNAV_Message; + double bits_NH[GPS_L5i_NH_CODE_LENGTH]{}; + std::deque sym_hist; + bool sync_NH; + bool new_sym; +}; + + +#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.cc index c634a994e..705df32a4 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,47 +23,42 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include +#include "sbas_l1_telemetry_decoder_cc.h" #include "control_message_factory.h" #include "gnss_synchro.h" -#include "sbas_l1_telemetry_decoder_cc.h" +#include +#include +#include +#include + using google::LogMessage; // logging levels -#define EVENT 2 // logs important events which don't occur every block -#define FLOW 3 // logs the function calls of block processing functions -#define SAMP_SYNC 4 // about 1 log entry per sample -> high output -#define LMORE 5 // - +#define EVENT 2 // logs important events which don't occur every block +#define FLOW 3 // logs the function calls of block processing functions +#define SAMP_SYNC 4 // about 1 log entry per sample -> high output +#define LMORE 5 // sbas_l1_telemetry_decoder_cc_sptr -sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) +sbas_l1_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) { return sbas_l1_telemetry_decoder_cc_sptr(new sbas_l1_telemetry_decoder_cc(satellite, dump)); } - sbas_l1_telemetry_decoder_cc::sbas_l1_telemetry_decoder_cc( - Gnss_Satellite satellite, - bool dump) : - gr::block("sbas_l1_telemetry_decoder_cc", - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + const Gnss_Satellite &satellite, + bool dump) : gr::block("sbas_l1_telemetry_decoder_cc", + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { - // Telemetry Bit transition synchronization port out - this->message_port_register_out(pmt::mp("preamble_timestamp_s")); // Ephemeris data port out this->message_port_register_out(pmt::mp("telemetry")); // initialize internal vars @@ -72,141 +67,41 @@ sbas_l1_telemetry_decoder_cc::sbas_l1_telemetry_decoder_cc( LOG(INFO) << "SBAS L1 TELEMETRY PROCESSING: satellite " << d_satellite; d_block_size = d_samples_per_symbol * d_symbols_per_bit * d_block_size_in_bits; d_channel = 0; - set_output_multiple (1); + set_output_multiple(1); } - sbas_l1_telemetry_decoder_cc::~sbas_l1_telemetry_decoder_cc() { - d_dump_file.close(); -} - - - -void sbas_l1_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = noutput_items; - VLOG(LMORE) << "forecast(): " << "noutput_items=" << noutput_items << "\tninput_items_required ninput_items_required.size()=" << ninput_items_required.size(); -} - - - -int sbas_l1_telemetry_decoder_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - VLOG(FLOW) << "general_work(): " << "noutput_items=" << noutput_items << "\toutput_items real size=" << output_items.size() << "\tninput_items size=" << ninput_items.size() << "\tinput_items real size=" << input_items.size() << "\tninput_items[0]=" << ninput_items[0]; - // get pointers on in- and output gnss-synchro objects - const Gnss_Synchro *in = (const Gnss_Synchro *) input_items[0]; // input - Gnss_Synchro *out = (Gnss_Synchro *) output_items[0]; // output - - // store the time stamp of the first sample in the processed sample block - double sample_stamp = in[0].Tracking_timestamp_secs; - - // copy correlation samples into samples vector - for (int i = 0; i < noutput_items; i++) + if (d_dump_file.is_open() == true) { - // check if channel is in tracking state - //if(in[i].Prompt_I != in[i].Prompt_Q) // TODO: check for real condition - { - d_sample_buf.push_back(in[i].Prompt_I); - } - } - - // decode only if enough samples in buffer - if(d_sample_buf.size() >= d_block_size) - { - // align correlation samples in pairs - // and obtain the symbols by summing the paired correlation samples - std::vector symbols; - bool sample_alignment = d_sample_aligner.get_symbols(d_sample_buf, symbols); - - // align symbols in pairs - // and obtain the bits by decoding the symbol pairs - std::vector bits; - bool symbol_alignment = d_symbol_aligner_and_decoder.get_bits(symbols, bits); - - // search for preambles - // and extract the corresponding message candidates - std::vector msg_candidates; - d_frame_detector.get_frame_candidates(bits, msg_candidates); - - // verify checksum - // and return the valid messages - std::vector valid_msgs; - d_crc_verifier.get_valid_frames(msg_candidates, valid_msgs); - - // compute message sample stamp - // and fill messages in SBAS raw message objects - std::vector sbas_raw_msgs; - for(std::vector::const_iterator it = valid_msgs.begin(); - it != valid_msgs.end(); ++it) + try { - int message_sample_offset = - (sample_alignment ? 0 : -1) - + d_samples_per_symbol*(symbol_alignment ? -1 : 0) - + d_samples_per_symbol * d_symbols_per_bit * it->first; - double message_sample_stamp = sample_stamp + ((double)message_sample_offset)/1000; - VLOG(EVENT) << "message_sample_stamp=" << message_sample_stamp - << " (sample_stamp=" << sample_stamp - << " sample_alignment=" << sample_alignment - << " symbol_alignment=" << symbol_alignment - << " relative_preamble_start=" << it->first - << " message_sample_offset=" << message_sample_offset - << ")"; - Sbas_Raw_Msg sbas_raw_msg(message_sample_stamp, this->d_satellite.get_PRN(), it->second); - sbas_raw_msgs.push_back(sbas_raw_msg); + d_dump_file.close(); } - - // parse messages - // and send them to the SBAS raw message queue - for(std::vector::iterator it = sbas_raw_msgs.begin(); it != sbas_raw_msgs.end(); it++) + catch (const std::exception &ex) { - std::cout << "SBAS message type " << it->get_msg_type() << " from PRN" << it->get_prn() << " received" << std::endl; - sbas_telemetry_data.update(*it); + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); } - - // clear all processed samples in the input buffer - d_sample_buf.clear(); } - - // UPDATE GNSS SYNCHRO DATA - // actually the SBAS telemetry decoder doesn't support ranging - Gnss_Synchro * current_synchro_data = out; //structure to save the synchronization information and send the output object to the next block - for (int i = 0; i < noutput_items; i++) - { - //1. Copy the current tracking output - current_synchro_data[i] = in[i]; - //2. Add the telemetry decoder information - current_synchro_data[i].Flag_valid_word = false; // indicate to observable block that this synchro object isn't valid for pseudorange computation - } - consume_each(noutput_items); // tell scheduler input items consumed - return noutput_items; // tell scheduler output items produced } - -void sbas_l1_telemetry_decoder_cc::set_satellite(Gnss_Satellite satellite) +void sbas_l1_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) { d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); LOG(INFO) << "SBAS telemetry decoder in channel " << this->d_channel << " set to satellite " << d_satellite; } - -void sbas_l1_telemetry_decoder_cc::set_channel(int channel) +void sbas_l1_telemetry_decoder_cc::set_channel(int32_t channel) { d_channel = channel; LOG(INFO) << "SBAS channel set to " << channel; } - - // ### helper class for sample alignment ### - sbas_l1_telemetry_decoder_cc::sample_aligner::sample_aligner() { d_n_smpls_in_history = 3; @@ -215,8 +110,7 @@ sbas_l1_telemetry_decoder_cc::sample_aligner::sample_aligner() } -sbas_l1_telemetry_decoder_cc::sample_aligner::~sample_aligner() -{} +sbas_l1_telemetry_decoder_cc::sample_aligner::~sample_aligner() = default; void sbas_l1_telemetry_decoder_cc::sample_aligner::reset() @@ -231,54 +125,57 @@ void sbas_l1_telemetry_decoder_cc::sample_aligner::reset() /* * samples length must be a multiple of two */ -bool sbas_l1_telemetry_decoder_cc::sample_aligner::get_symbols(const std::vector samples, std::vector &symbols) +bool sbas_l1_telemetry_decoder_cc::sample_aligner::get_symbols(const std::vector &samples, std::vector &symbols) { - double smpls[3] = { }; + double smpls[3] = {}; double corr_diff; bool stand_by = true; double sym; - VLOG(FLOW) << "get_symbols(): " << "d_past_sample=" << d_past_sample << "\tsamples size=" << samples.size(); + VLOG(FLOW) << "get_symbols(): " + << "d_past_sample=" << d_past_sample << "\tsamples size=" << samples.size(); - for (unsigned int i_sym = 0; i_sym < samples.size()/sbas_l1_telemetry_decoder_cc::d_samples_per_symbol; i_sym++) + for (uint32_t i_sym = 0; i_sym < samples.size() / sbas_l1_telemetry_decoder_cc::d_samples_per_symbol; i_sym++) { // get the next samples - for (int i = 0; i < d_n_smpls_in_history; i++) + for (int32_t i = 0; i < d_n_smpls_in_history; i++) { - smpls[i] = ((int)i_sym)*sbas_l1_telemetry_decoder_cc::d_samples_per_symbol + i - 1 == -1 ? d_past_sample : samples[i_sym*sbas_l1_telemetry_decoder_cc::d_samples_per_symbol + i - 1]; + smpls[i] = static_cast(i_sym) * sbas_l1_telemetry_decoder_cc::d_samples_per_symbol + i - 1 == -1 ? d_past_sample : samples[i_sym * sbas_l1_telemetry_decoder_cc::d_samples_per_symbol + i - 1]; } // update the pseudo correlations (IIR method) of the two possible alignments - d_corr_paired = d_iir_par*smpls[1]*smpls[2] + (1 - d_iir_par)*d_corr_paired; - d_corr_shifted = d_iir_par*smpls[0]*smpls[1] + (1 - d_iir_par)*d_corr_shifted; + d_corr_paired = d_iir_par * smpls[1] * smpls[2] + (1 - d_iir_par) * d_corr_paired; + d_corr_shifted = d_iir_par * smpls[0] * smpls[1] + (1 - d_iir_par) * d_corr_shifted; // decide which alignment is the correct one corr_diff = std::abs(d_corr_paired - d_corr_shifted); - stand_by = d_aligned ? corr_diff < d_corr_paired/2 : corr_diff < d_corr_shifted/2; + stand_by = d_aligned ? corr_diff < d_corr_paired / 2 : corr_diff < d_corr_shifted / 2; if (!stand_by) { d_aligned = d_corr_paired >= d_corr_shifted; } // sum the correct pair of samples to a symbol, depending on the current alignment d_align - sym = smpls[0 + int(d_aligned)*2] + smpls[1]; + sym = smpls[0 + int32_t(d_aligned) * 2] + smpls[1]; symbols.push_back(sym); // sample alignment debug output VLOG(SAMP_SYNC) << std::setprecision(5) - << "smplp: " << std::setw(6) << smpls[0] << " " << "smpl0: " << std::setw(6) - << smpls[1] << " " << "smpl1: " << std::setw(6) << smpls[2] << "\t" - //<< "Flag_valid_tracking: " << std::setw(1) << in[0][0].Flag_valid_tracking << " " << std::setw(1) << in[0][0].Flag_valid_tracking << "\t" - << "d_corr_paired: " << std::setw(10) << d_corr_paired << "\t" - << "d_corr_shifted: " << std::setw(10) << d_corr_shifted << "\t" - << "corr_diff: " << std::setw(10) << corr_diff << "\t" - << "stand_by: " << std::setw(1) << stand_by << "\t" - << "d_aligned: " << std::setw(1) << d_aligned << "\t" - << "sym: " << std::setw(10) << sym << "\t"; + << "smplp: " << std::setw(6) << smpls[0] << " " + << "smpl0: " << std::setw(6) + << smpls[1] << " " + << "smpl1: " << std::setw(6) << smpls[2] << "\t" + //<< "Flag_valid_tracking: " << std::setw(1) << in[0][0].Flag_valid_tracking << " " << std::setw(1) << in[0][0].Flag_valid_tracking << "\t" + << "d_corr_paired: " << std::setw(10) << d_corr_paired << "\t" + << "d_corr_shifted: " << std::setw(10) << d_corr_shifted << "\t" + << "corr_diff: " << std::setw(10) << corr_diff << "\t" + << "stand_by: " << std::setw(1) << stand_by << "\t" + << "d_aligned: " << std::setw(1) << d_aligned << "\t" + << "sym: " << std::setw(10) << sym << "\t"; } // save last sample for next block - double temp; + double temp; temp = samples.back(); d_past_sample = (temp); return d_aligned; @@ -290,8 +187,8 @@ sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::symbol_aligner_and_dec { // convolutional code properties d_KK = 7; - int nn = 2; - int g_encoder[nn]; + const int32_t nn = 2; + int32_t g_encoder[nn]; g_encoder[0] = 121; g_encoder[1] = 91; @@ -316,34 +213,34 @@ void sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::reset() } -bool sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::get_bits(const std::vector symbols, std::vector &bits) +bool sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::get_bits(const std::vector &symbols, std::vector &bits) { - const int traceback_depth = 5*d_KK; - int nbits_requested = symbols.size()/d_symbols_per_bit; - int nbits_decoded; + const int32_t traceback_depth = 5 * d_KK; + int32_t nbits_requested = symbols.size() / d_symbols_per_bit; + int32_t nbits_decoded; // fill two vectors with the two possible symbol alignments - std::vector symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector - std::vector symbols_vd2; // shifted symbol vector -> add past sample in front of input vector + std::vector symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector + std::vector symbols_vd2; // shifted symbol vector -> add past sample in front of input vector symbols_vd2.push_back(d_past_symbol); - for (std::vector::const_iterator symbol_it = symbols.begin(); symbol_it != symbols.end() - 1; ++symbol_it) + for (auto symbol_it = symbols.cbegin(); symbol_it != symbols.cend() - 1; ++symbol_it) { symbols_vd2.push_back(*symbol_it); } // arrays for decoded bits - int * bits_vd1 = new int[nbits_requested]; - int * bits_vd2 = new int[nbits_requested]; + auto *bits_vd1 = new int32_t[nbits_requested]; + auto *bits_vd2 = new int32_t[nbits_requested]; // decode float metric_vd1 = d_vd1->decode_continuous(symbols_vd1.data(), traceback_depth, bits_vd1, nbits_requested, nbits_decoded); float metric_vd2 = d_vd2->decode_continuous(symbols_vd2.data(), traceback_depth, bits_vd2, nbits_requested, nbits_decoded); // choose the bits with the better metric - for (int i = 0; i < nbits_decoded; i++) + for (int32_t i = 0; i < nbits_decoded; i++) { if (metric_vd1 > metric_vd2) - {// symbols aligned + { // symbols aligned bits.push_back(bits_vd1[i]); } else - {// symbols shifted + { // symbols shifted bits.push_back(bits_vd2[i]); } } @@ -361,53 +258,54 @@ void sbas_l1_telemetry_decoder_cc::frame_detector::reset() } -void sbas_l1_telemetry_decoder_cc::frame_detector::get_frame_candidates(const std::vector bits, std::vector>> &msg_candidates) +void sbas_l1_telemetry_decoder_cc::frame_detector::get_frame_candidates(const std::vector &bits, std::vector>> &msg_candidates) { std::stringstream ss; - unsigned int sbas_msg_length = 250; - std::vector> preambles = {{0, 1, 0, 1, 0, 0, 1 ,1}, - {1, 0, 0, 1, 1, 0, 1, 0}, - {1, 1, 0, 0, 0, 1, 1, 0}}; - VLOG(FLOW) << "get_frame_candidates(): " << "d_buffer.size()=" << d_buffer.size() << "\tbits.size()=" << bits.size(); + uint32_t sbas_msg_length = 250; + std::vector> preambles = {{0, 1, 0, 1, 0, 0, 1, 1}, + {1, 0, 0, 1, 1, 0, 1, 0}, + {1, 1, 0, 0, 0, 1, 1, 0}}; + VLOG(FLOW) << "get_frame_candidates(): " + << "d_buffer.size()=" << d_buffer.size() << "\tbits.size()=" << bits.size(); ss << "copy bits "; - int count = 0; + int32_t count = 0; // copy new bits into the working buffer - for (std::vector::const_iterator bit_it = bits.begin(); bit_it < bits.end(); ++bit_it) + for (auto bit_it = bits.cbegin(); bit_it < bits.cend(); ++bit_it) { d_buffer.push_back(*bit_it); ss << *bit_it; count++; } VLOG(SAMP_SYNC) << ss.str() << " into working buffer (" << count << " bits)"; - int relative_preamble_start = 0; - while(d_buffer.size() >= sbas_msg_length) + int32_t relative_preamble_start = 0; + while (d_buffer.size() >= sbas_msg_length) { // compare with all preambles - for (std::vector>::iterator preample_it = preambles.begin(); preample_it < preambles.end(); ++preample_it) + for (auto preample_it = preambles.begin(); preample_it < preambles.end(); ++preample_it) { bool preamble_detected = true; bool inv_preamble_detected = true; // compare the buffer bits with the preamble bits - for (std::vector::iterator preample_bit_it = preample_it->begin(); preample_bit_it < preample_it->end(); ++preample_bit_it) + for (auto preample_bit_it = preample_it->begin(); preample_bit_it < preample_it->end(); ++preample_bit_it) { - preamble_detected = *preample_bit_it == d_buffer[preample_bit_it - preample_it->begin()] ? preamble_detected : false ; - inv_preamble_detected = *preample_bit_it != d_buffer[preample_bit_it - preample_it->begin()] ? inv_preamble_detected : false ; + preamble_detected = *preample_bit_it == d_buffer[preample_bit_it - preample_it->begin()] ? preamble_detected : false; + inv_preamble_detected = *preample_bit_it != d_buffer[preample_bit_it - preample_it->begin()] ? inv_preamble_detected : false; } if (preamble_detected || inv_preamble_detected) { // copy candidate - std::vector candidate; + std::vector candidate; std::copy(d_buffer.begin(), d_buffer.begin() + sbas_msg_length, std::back_inserter(candidate)); - if(inv_preamble_detected) + if (inv_preamble_detected) { // invert bits - for (std::vector::iterator candidate_bit_it = candidate.begin(); candidate_bit_it != candidate.end(); candidate_bit_it++) - *candidate_bit_it = *candidate_bit_it == 0 ? 1 : 0; + for (int &candidate_bit_it : candidate) + candidate_bit_it = candidate_bit_it == 0 ? 1 : 0; } - msg_candidates.push_back(std::pair>(relative_preamble_start, candidate)); + msg_candidates.emplace_back(relative_preamble_start, candidate); ss.str(""); - ss << "preamble " << preample_it - preambles.begin() << (inv_preamble_detected?" inverted":" normal") << " detected! candidate="; - for (std::vector::iterator bit_it = candidate.begin(); bit_it < candidate.end(); ++bit_it) + ss << "preamble " << preample_it - preambles.begin() << (inv_preamble_detected ? " inverted" : " normal") << " detected! candidate="; + for (auto bit_it = candidate.begin(); bit_it < candidate.end(); ++bit_it) ss << *bit_it; VLOG(EVENT) << ss.str(); } @@ -420,34 +318,33 @@ void sbas_l1_telemetry_decoder_cc::frame_detector::get_frame_candidates(const st // ### helper class for checking the CRC of the message candidates ### - - void sbas_l1_telemetry_decoder_cc::crc_verifier::reset() { - } -void sbas_l1_telemetry_decoder_cc::crc_verifier::get_valid_frames(const std::vector msg_candidates, std::vector &valid_msgs) + +void sbas_l1_telemetry_decoder_cc::crc_verifier::get_valid_frames(const std::vector &msg_candidates, std::vector &valid_msgs) { std::stringstream ss; - VLOG(FLOW) << "get_valid_frames(): " << "msg_candidates.size()=" << msg_candidates.size(); + VLOG(FLOW) << "get_valid_frames(): " + << "msg_candidates.size()=" << msg_candidates.size(); // for each candidate - for (std::vector::const_iterator candidate_it = msg_candidates.begin(); candidate_it < msg_candidates.end(); ++candidate_it) + for (auto candidate_it = msg_candidates.cbegin(); candidate_it < msg_candidates.cend(); ++candidate_it) { // convert to bytes - std::vector candidate_bytes; + std::vector candidate_bytes; zerropad_back_and_convert_to_bytes(candidate_it->second, candidate_bytes); // verify CRC d_checksum_agent.reset(0); d_checksum_agent.process_bytes(candidate_bytes.data(), candidate_bytes.size()); - unsigned int crc = d_checksum_agent.checksum(); + uint32_t crc = d_checksum_agent.checksum(); VLOG(SAMP_SYNC) << "candidate " << candidate_it - msg_candidates.begin() << ": final crc remainder= " << std::hex << crc << std::setfill(' ') << std::resetiosflags(std::ios::hex); // the final remainder must be zero for a valid message, because the CRC is done over the received CRC value if (crc == 0) { - valid_msgs.push_back(msg_candiate_char_t(candidate_it->first, candidate_bytes)); + valid_msgs.emplace_back(candidate_it->first, candidate_bytes); ss << "Valid message found!"; } else @@ -455,68 +352,146 @@ void sbas_l1_telemetry_decoder_cc::crc_verifier::get_valid_frames(const std::vec ss << "Not a valid message."; } ss << " Relbitoffset=" << candidate_it->first << " content="; - for (std::vector::iterator byte_it = candidate_bytes.begin(); byte_it < candidate_bytes.end(); ++byte_it) + for (auto byte_it = candidate_bytes.begin(); byte_it < candidate_bytes.end(); ++byte_it) { - ss << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)(*byte_it); + ss << std::setw(2) << std::setfill('0') << std::hex << static_cast((*byte_it)); } VLOG(SAMP_SYNC) << ss.str() << std::setfill(' ') << std::resetiosflags(std::ios::hex) << std::endl; } } - - - -void sbas_l1_telemetry_decoder_cc::crc_verifier::zerropad_back_and_convert_to_bytes(const std::vector msg_candidate, std::vector &bytes) +void sbas_l1_telemetry_decoder_cc::crc_verifier::zerropad_back_and_convert_to_bytes(const std::vector &msg_candidate, std::vector &bytes) { std::stringstream ss; const size_t bits_per_byte = 8; - unsigned char byte = 0; + uint8_t byte = 0; VLOG(LMORE) << "zerropad_back_and_convert_to_bytes():" << byte; - for (std::vector::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it) + for (auto candidate_bit_it = msg_candidate.cbegin(); candidate_bit_it < msg_candidate.cend(); ++candidate_bit_it) { - int idx_bit = candidate_bit_it - msg_candidate.begin(); - int bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); - byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte; + int32_t idx_bit = candidate_bit_it - msg_candidate.begin(); + int32_t bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); + byte |= static_cast(*candidate_bit_it) << bit_pos_in_current_byte; ss << *candidate_bit_it; if (idx_bit % bits_per_byte == bits_per_byte - 1) { bytes.push_back(byte); - VLOG(LMORE) << ss.str() << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte; ss.str(""); + VLOG(LMORE) << ss.str() << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << static_cast(byte); + ss.str(""); byte = 0; } } - bytes.push_back(byte); // implies: insert 6 zeros at the end to fit the 250bits into a multiple of bytes + bytes.push_back(byte); // implies: insert 6 zeros at the end to fit the 250bits into a multiple of bytes VLOG(LMORE) << " -> byte=" << std::setw(2) - << std::setfill('0') << std::hex << (unsigned int)byte + << std::setfill('0') << std::hex << static_cast(byte) << std::setfill(' ') << std::resetiosflags(std::ios::hex); } - -void sbas_l1_telemetry_decoder_cc::crc_verifier::zerropad_front_and_convert_to_bytes(const std::vector msg_candidate, std::vector &bytes) +void sbas_l1_telemetry_decoder_cc::crc_verifier::zerropad_front_and_convert_to_bytes(const std::vector &msg_candidate, std::vector &bytes) { std::stringstream ss; const size_t bits_per_byte = 8; - unsigned char byte = 0; - int idx_bit = 6; // insert 6 zeros at the front to fit the 250bits into a multiple of bytes + uint8_t byte = 0; + int32_t idx_bit = 6; // insert 6 zeros at the front to fit the 250bits into a multiple of bytes VLOG(LMORE) << "zerropad_front_and_convert_to_bytes():" << byte; - for (std::vector::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it) + for (auto candidate_bit_it = msg_candidate.cbegin(); candidate_bit_it < msg_candidate.cend(); ++candidate_bit_it) { - int bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); - byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte; + int32_t bit_pos_in_current_byte = (bits_per_byte - 1) - (idx_bit % bits_per_byte); + byte |= static_cast(*candidate_bit_it) << bit_pos_in_current_byte; ss << *candidate_bit_it; if (idx_bit % bits_per_byte == bits_per_byte - 1) { bytes.push_back(byte); VLOG(LMORE) << ss.str() << " -> byte=" << std::setw(2) - << std::setfill('0') << std::hex << (unsigned int)byte; ss.str(""); + << std::setfill('0') << std::hex << static_cast(byte); + ss.str(""); byte = 0; } idx_bit++; } VLOG(LMORE) << " -> byte=" << std::setw(2) - << std::setfill('0') << std::hex << (unsigned int)byte + << std::setfill('0') << std::hex << static_cast(byte) << std::setfill(' ') << std::resetiosflags(std::ios::hex); } + +int sbas_l1_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + VLOG(FLOW) << "general_work(): " + << "noutput_items=" << noutput_items << "\toutput_items real size=" << output_items.size() << "\tninput_items size=" << ninput_items.size() << "\tinput_items real size=" << input_items.size() << "\tninput_items[0]=" << ninput_items[0]; + // get pointers on in- and output gnss-synchro objects + auto *out = reinterpret_cast(output_items[0]); // Get the output buffer pointer + const auto *in = reinterpret_cast(input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol{}; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0]; + // copy correlation samples into samples vector + d_sample_buf.push_back(current_symbol.Prompt_I); //add new symbol to the symbol queue + + // store the time stamp of the first sample in the processed sample block + double sample_stamp = static_cast(in[0].Tracking_sample_counter) / static_cast(in[0].fs); + + // decode only if enough samples in buffer + if (d_sample_buf.size() >= d_block_size) + { + // align correlation samples in pairs + // and obtain the symbols by summing the paired correlation samples + std::vector symbols; + bool sample_alignment = d_sample_aligner.get_symbols(d_sample_buf, symbols); + + // align symbols in pairs + // and obtain the bits by decoding the symbol pairs + std::vector bits; + bool symbol_alignment = d_symbol_aligner_and_decoder.get_bits(symbols, bits); + + // search for preambles + // and extract the corresponding message candidates + std::vector msg_candidates; + d_frame_detector.get_frame_candidates(bits, msg_candidates); + + // verify checksum + // and return the valid messages + std::vector valid_msgs; + d_crc_verifier.get_valid_frames(msg_candidates, valid_msgs); + + // compute message sample stamp + // and fill messages in SBAS raw message objects + //std::vector sbas_raw_msgs; + for (const auto &valid_msg : valid_msgs) + { + int32_t message_sample_offset = + (sample_alignment ? 0 : -1) + d_samples_per_symbol * (symbol_alignment ? -1 : 0) + d_samples_per_symbol * d_symbols_per_bit * valid_msg.first; + double message_sample_stamp = sample_stamp + static_cast(message_sample_offset) / 1000.0; + VLOG(EVENT) << "message_sample_stamp=" << message_sample_stamp + << " (sample_stamp=" << sample_stamp + << " sample_alignment=" << sample_alignment + << " symbol_alignment=" << symbol_alignment + << " relative_preamble_start=" << valid_msg.first + << " message_sample_offset=" << message_sample_offset + << ")"; + //Sbas_Raw_Msg sbas_raw_msg(message_sample_stamp, this->d_satellite.get_PRN(), it->second); + //sbas_raw_msgs.push_back(sbas_raw_msg); + } + + // parse messages + // and send them to the SBAS raw message queue + //for(std::vector::iterator it = sbas_raw_msgs.begin(); it != sbas_raw_msgs.end(); it++) + // { + //std::cout << "SBAS message type " << it->get_msg_type() << " from PRN" << it->get_prn() << " received" << std::endl; + //sbas_telemetry_data.update(*it); + // } + + // clear all processed samples in the input buffer + d_sample_buf.clear(); + } + + // UPDATE GNSS SYNCHRO DATA + // actually the SBAS telemetry decoder doesn't support ranging + current_symbol.Flag_valid_word = false; // indicate to observable block that this synchro object isn't valid for pseudorange computation + out[0] = current_symbol; + consume_each(1); // tell scheduler input items consumed + return 1; // tell scheduler output items produced +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.h index 6fc2d5699..5dcf4f27b 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/sbas_l1_telemetry_decoder_cc.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,24 +31,25 @@ #ifndef GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_CC_H #define GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_CC_H -#include // for copy +#include "gnss_satellite.h" +#include "viterbi_decoder.h" +#include +#include +#include // for copy +#include #include #include #include -#include // for pair +#include // for pair #include -#include -#include -#include "gnss_satellite.h" -#include "viterbi_decoder.h" -#include "sbas_telemetry_data.h" + class sbas_l1_telemetry_decoder_cc; typedef boost::shared_ptr sbas_l1_telemetry_decoder_cc_sptr; sbas_l1_telemetry_decoder_cc_sptr -sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); +sbas_l1_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); /*! * \brief This class implements a block that decodes the SBAS integrity and corrections data defined in RTCA MOPS DO-229 @@ -58,45 +59,39 @@ class sbas_l1_telemetry_decoder_cc : public gr::block { public: ~sbas_l1_telemetry_decoder_cc(); - void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN - void set_channel(int channel); //!< Set receiver's channel + void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN + void set_channel(int32_t channel); //!< Set receiver's channel /*! * \brief This is where all signal processing takes place */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /*! - * \brief Function which tells the scheduler how many input items - * are required to produce noutput_items output items. - */ - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); private: friend sbas_l1_telemetry_decoder_cc_sptr - sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); - sbas_l1_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + sbas_l1_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + sbas_l1_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - void viterbi_decoder(double *page_part_symbols, int *page_part_bits); + void viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits); void align_samples(); - static const int d_samples_per_symbol = 2; - static const int d_symbols_per_bit = 2; - static const int d_block_size_in_bits = 30; + static const int32_t d_samples_per_symbol = 2; + static const int32_t d_symbols_per_bit = 2; + static const int32_t d_block_size_in_bits = 30; bool d_dump; Gnss_Satellite d_satellite; - int d_channel; + int32_t d_channel; std::string d_dump_filename; std::ofstream d_dump_file; - size_t d_block_size; //!< number of samples which are processed during one invocation of the algorithms - std::vector d_sample_buf; //!< input buffer holding the samples to be processed in one block + size_t d_block_size; //!< number of samples which are processed during one invocation of the algorithms + std::vector d_sample_buf; //!< input buffer holding the samples to be processed in one block - typedef std::pair> msg_candiate_int_t; - typedef std::pair> msg_candiate_char_t; + typedef std::pair> msg_candiate_int_t; + typedef std::pair> msg_candiate_char_t; // helper class for sample alignment class sample_aligner @@ -109,9 +104,10 @@ private: * samples length must be a multiple of two * for block operation */ - bool get_symbols(const std::vector samples, std::vector &symbols); + bool get_symbols(const std::vector &samples, std::vector &symbols); + private: - int d_n_smpls_in_history ; + int32_t d_n_smpls_in_history; double d_iir_par; double d_corr_paired; double d_corr_shifted; @@ -126,11 +122,12 @@ private: symbol_aligner_and_decoder(); ~symbol_aligner_and_decoder(); void reset(); - bool get_bits(const std::vector symbols, std::vector &bits); + bool get_bits(const std::vector &symbols, std::vector &bits); + private: - int d_KK; - Viterbi_Decoder * d_vd1; - Viterbi_Decoder * d_vd2; + int32_t d_KK; + Viterbi_Decoder *d_vd1; + Viterbi_Decoder *d_vd2; double d_past_symbol; } d_symbol_aligner_and_decoder; @@ -140,9 +137,10 @@ private: { public: void reset(); - void get_frame_candidates(const std::vector bits, std::vector>> &msg_candidates); + void get_frame_candidates(const std::vector &bits, std::vector>> &msg_candidates); + private: - std::deque d_buffer; + std::deque d_buffer; } d_frame_detector; @@ -151,16 +149,14 @@ private: { public: void reset(); - void get_valid_frames(const std::vector msg_candidates, std::vector &valid_msgs); + void get_valid_frames(const std::vector &msg_candidates, std::vector &valid_msgs); + private: typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> crc_24_q_type; crc_24_q_type d_checksum_agent; - void zerropad_front_and_convert_to_bytes(const std::vector msg_candidate, std::vector &bytes); - void zerropad_back_and_convert_to_bytes(const std::vector msg_candidate, std::vector &bytes); + void zerropad_front_and_convert_to_bytes(const std::vector &msg_candidate, std::vector &bytes); + void zerropad_back_and_convert_to_bytes(const std::vector &msg_candidate, std::vector &bytes); } d_crc_verifier; - - - Sbas_Telemetry_Data sbas_telemetry_data; }; #endif diff --git a/src/algorithms/telemetry_decoder/libs/CMakeLists.txt b/src/algorithms/telemetry_decoder/libs/CMakeLists.txt index 9b5ab2c74..53a997cc8 100644 --- a/src/algorithms/telemetry_decoder/libs/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,27 +13,39 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # -set(TELEMETRY_DECODER_LIB_SOURCES - gps_l1_ca_subframe_fsm.cc - viterbi_decoder.cc + +add_subdirectory(libswiftcnav) + +set(TELEMETRY_DECODER_LIB_SOURCES + viterbi_decoder.cc +) + +set(TELEMETRY_DECODER_LIB_HEADERS + viterbi_decoder.h + convolutional.h ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} ) -file(GLOB TELEMETRY_DECODER_LIB_HEADERS "*.h") list(SORT TELEMETRY_DECODER_LIB_HEADERS) -add_library(telemetry_decoder_lib ${TELEMETRY_DECODER_LIB_SOURCES} ${TELEMETRY_DECODER_LIB_HEADERS}) +list(SORT TELEMETRY_DECODER_LIB_SOURCES) + +add_library(telemetry_decoder_lib + ${TELEMETRY_DECODER_LIB_SOURCES} + ${TELEMETRY_DECODER_LIB_HEADERS} +) source_group(Headers FILES ${TELEMETRY_DECODER_LIB_HEADERS}) -target_link_libraries(telemetry_decoder_lib gnss_system_parameters) \ No newline at end of file + +target_link_libraries(telemetry_decoder_lib gnss_system_parameters) diff --git a/src/algorithms/telemetry_decoder/libs/convolutional.h b/src/algorithms/telemetry_decoder/libs/convolutional.h index 5f0f1b379..4195154df 100644 --- a/src/algorithms/telemetry_decoder/libs/convolutional.h +++ b/src/algorithms/telemetry_decoder/libs/convolutional.h @@ -1,298 +1,295 @@ -/*! - * \file convolutional.h - * \brief General functions used to implement convolutional encoding. - * \author Matthew C. Valenti - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2006-2008 Matthew C. Valenti - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This file is a derived work of the original file, which had this note: - * - * Last updated on May 22, 2008 - * - * The functions in this file are part of the Iterative Solutions - * Coded Modulation Library. The Iterative Solutions Coded Modulation - * Library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, - * or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef GNSS_SDR_CONVOLUTIONAL_H_ -#define GNSS_SDR_CONVOLUTIONAL_H_ - -#include // for calloc - -/* define constants used throughout the library */ -const float MAXLOG = 1e7; /* Define infinity */ - - -/*! - * \brief Determines if a symbol has odd (1) or even (0) parity - * Output parameters: - * \return (returned int): The symbol's parity = 1 for odd and 0 for even - * - * \param[in] symbol The integer-valued symbol - * \param[in] length The highest bit position in the symbol - * - * This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail() - */ -static int parity_counter(int symbol, int length) -{ - int counter; - int temp_parity = 0; - - for (counter = 0; counter < length; counter++) - { - temp_parity = temp_parity^(symbol & 1); - symbol = symbol >> 1; - } - return(temp_parity); -} - - - -/*! - * \brief Convolutionally encodes a single bit using a rate 1/n encoder. - * Takes in one input bit at a time, and produces a n-bit output. - * - * \param[in] input The input data bit (i.e. a 0 or 1). - * \param[in] state_in The starting state of the encoder (an int from 0 to 2^m-1). - * \param[in] g[] An n-element vector containing the code generators in binary form. - * \param[in] KK The constraint length of the convolutional code. - * \param[out] output_p[] An n-element vector containing the encoded bits. - * \param[out] state_out_p[] An integer containing the final state of the encoder - * (i.e. the state after encoding this bit) - * - * This function is used by nsc_transit() - */ -static int nsc_enc_bit(int state_out_p[], - int input, - int state_in, - int g[], - int KK, - int nn) -{ - /* declare variables */ - int state, i; - int out_ = 0; - - /* create a word made up of state and new input */ - state = (input << (KK - 1))^state_in; - - /* AND the word with the generators */ - for (i = 0; i < nn; i++) - { - /* update output symbol */ - out_ = (out_ << 1) + parity_counter(state & g[i], KK); - } - - /* shift the state to make the new state */ - state_out_p[0] = state >> 1; - return(out_); -} - - - -/*! - * \brief Function that creates the transit and output vectors - */ -static void nsc_transit(int output_p[], - int trans_p[], - int input, - int g[], - int KK, - int nn) -{ - int nextstate[1]; - int state, states; - states = (1 << (KK - 1)); /* The number of states: 2^mm */ - - /* Determine the output and next state for each possible starting state */ - for(state = 0; state < states; state++) - { - output_p[state] = nsc_enc_bit(nextstate, input, state, g, KK, nn); - trans_p[state] = nextstate[0]; - } - return; -} - - - -/*! - * \brief Computes the branch metric used for decoding. - * \return (returned float) The metric between the hypothetical symbol and the received vector - * \param[in] rec_array The received vector, of length nn - * \param[in] symbol The hypothetical symbol - * \param[in] nn The length of the received vector - * - */ -static float Gamma(float rec_array[], - int symbol, - int nn) -{ - float rm = 0; - int i; - int mask = 1; - - for (i = 0; i < nn; i++) - { - if (symbol & mask) - rm += rec_array[nn - i - 1]; - mask = mask << 1; - } - return(rm); -} - - -/*! - * \brief Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code. - * \param[in] out0[] The output bits for each state if input is a 0. - * \param[in] state0[] The next state if input is a 0. - * \param[in] out1[] The output bits for each state if input is a 1. - * \param[in] state1[] The next state if input is a 1. - * \param[in] r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2). - * \param[in] KK The constraint length of the convolutional code. - * \param[in] LL The number of data bits. - * \param[out] output_u_int[] Hard decisions on the data bits - * - */ -static void Viterbi(int output_u_int[], - int out0[], - int state0[], - int out1[], - int state1[], - double input_c[], - int KK, - int nn, - int LL) -{ - int i, t, state, mm, states; - int number_symbols; - float metric; - float *prev_section, *next_section; - int *prev_bit; - int *prev_state; - float *metric_c; /* Set of all possible branch metrics */ - float *rec_array; /* Received values for one trellis section */ - float max_val; - - /* some derived constants */ - mm = KK - 1; - states = 1 << mm; /* 2^mm */ - number_symbols = 1 << nn; /* 2^nn */ - - /* dynamically allocate memory */ - prev_section = static_cast(calloc( states, sizeof(float) )); - next_section = static_cast(calloc( states, sizeof(float) )); - prev_bit = static_cast(calloc( states*(LL + mm), sizeof(int) )); - prev_state = static_cast(calloc( states*(LL + mm), sizeof(int) )); - rec_array = static_cast(calloc( nn, sizeof(float) )); - metric_c = static_cast(calloc( number_symbols, sizeof(float) )); - - /* initialize trellis */ - for (state = 0; state < states; state++) - { - prev_section[state] = -MAXLOG; - next_section[state] = -MAXLOG; - } - prev_section[0] = 0; /* start in all-zeros state */ - - /* go through trellis */ - for (t = 0; t < LL + mm; t++) - { - for (i = 0; i < nn; i++) - rec_array[i] = static_cast(input_c[nn*t + i]); - - /* precompute all possible branch metrics */ - for (i = 0; i < number_symbols; i++) - metric_c[i] = Gamma( rec_array, i, nn ); - - /* step through all states */ - for (state = 0; state < states; state++) - { - /* hypothesis: info bit is a zero */ - metric = prev_section[state] + metric_c[ out0[ state ] ]; - - /* store new metric if more than metric in storage */ - if ( metric > next_section[state0[state]] ) - { - next_section[state0[state]] = metric; - prev_state[t*states + state0[state]] = state; - prev_bit[t*states + state0[state]] = 0; - } - - /* hypothesis: info bit is a one */ - metric = prev_section[state] + metric_c[ out1[ state ] ]; - - /* store new metric if more than metric in storage */ - if ( metric > next_section[state1[state]] ) - { - next_section[state1[state]] = metric; - prev_state[t*states + state1[state]] = state; - prev_bit[t*states + state1[state]] = 1; - } - } - - /* normalize */ - max_val = 0; - for (state = 0; state < states; state++) - { - if (next_section[state] > max_val) - { - max_val = next_section[state]; - } - } - for (state = 0; state < states; state++) - { - prev_section[state] = next_section[state] - max_val; - next_section[state] = -MAXLOG; - } - } - - /* trace-back operation */ - state = 0; - - /* tail, no need to output */ - for (t = LL + mm - 1; t >= LL; t--) - { - state = prev_state[t*states + state]; - } - - for (t = LL - 1; t >= 0; t--) - { - output_u_int[t] = prev_bit[t*states + state]; - state = prev_state[t*states + state]; - } - - /* free the dynamically allocated memory */ - free(prev_section); - free(next_section); - free(prev_bit); - free(prev_state); - free(rec_array); - free(metric_c); -} - - -#endif +/*! + * \file convolutional.h + * \brief General functions used to implement convolutional encoding. + * \author Matthew C. Valenti + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2006-2008 Matthew C. Valenti + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This file is a derived work of the original file, which had this note: + * + * Last updated on May 22, 2008 + * + * The functions in this file are part of the Iterative Solutions + * Coded Modulation Library. The Iterative Solutions Coded Modulation + * Library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GNSS_SDR_CONVOLUTIONAL_H_ +#define GNSS_SDR_CONVOLUTIONAL_H_ + +#include // for calloc + +/* define constants used throughout the library */ +const float MAXLOG = 1e7; /* Define infinity */ + + +/*! + * \brief Determines if a symbol has odd (1) or even (0) parity + * Output parameters: + * \return (returned int): The symbol's parity = 1 for odd and 0 for even + * + * \param[in] symbol The integer-valued symbol + * \param[in] length The highest bit position in the symbol + * + * This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail() + */ +inline static int parity_counter(int symbol, int length) +{ + int counter; + int temp_parity = 0; + + for (counter = 0; counter < length; counter++) + { + temp_parity = temp_parity ^ (symbol & 1); + symbol = symbol >> 1; + } + return (temp_parity); +} + + +/*! + * \brief Convolutionally encodes a single bit using a rate 1/n encoder. + * Takes in one input bit at a time, and produces a n-bit output. + * + * \param[in] input The input data bit (i.e. a 0 or 1). + * \param[in] state_in The starting state of the encoder (an int from 0 to 2^m-1). + * \param[in] g[] An n-element vector containing the code generators in binary form. + * \param[in] KK The constraint length of the convolutional code. + * \param[out] output_p[] An n-element vector containing the encoded bits. + * \param[out] state_out_p[] An integer containing the final state of the encoder + * (i.e. the state after encoding this bit) + * + * This function is used by nsc_transit() + */ +inline static int nsc_enc_bit(int state_out_p[], + int input, + int state_in, + int g[], + int KK, + int nn) +{ + /* declare variables */ + int state, i; + int out_ = 0; + + /* create a word made up of state and new input */ + state = (input << (KK - 1)) ^ state_in; + + /* AND the word with the generators */ + for (i = 0; i < nn; i++) + { + /* update output symbol */ + out_ = (out_ << 1) + parity_counter(state & g[i], KK); + } + + /* shift the state to make the new state */ + state_out_p[0] = state >> 1; + return (out_); +} + + +/*! + * \brief Function that creates the transit and output vectors + */ +inline static void nsc_transit(int output_p[], + int trans_p[], + int input, + int g[], + int KK, + int nn) +{ + int nextstate[1]; + int state, states; + states = (1 << (KK - 1)); /* The number of states: 2^mm */ + + /* Determine the output and next state for each possible starting state */ + for (state = 0; state < states; state++) + { + output_p[state] = nsc_enc_bit(nextstate, input, state, g, KK, nn); + trans_p[state] = nextstate[0]; + } + return; +} + + +/*! + * \brief Computes the branch metric used for decoding. + * \return (returned float) The metric between the hypothetical symbol and the received vector + * \param[in] rec_array The received vector, of length nn + * \param[in] symbol The hypothetical symbol + * \param[in] nn The length of the received vector + * + */ +inline static float Gamma(float rec_array[], + int symbol, + int nn) +{ + float rm = 0; + int i; + int mask = 1; + + for (i = 0; i < nn; i++) + { + if (symbol & mask) + rm += rec_array[nn - i - 1]; + mask = mask << 1; + } + return (rm); +} + + +/*! + * \brief Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code. + * \param[in] out0[] The output bits for each state if input is a 0. + * \param[in] state0[] The next state if input is a 0. + * \param[in] out1[] The output bits for each state if input is a 1. + * \param[in] state1[] The next state if input is a 1. + * \param[in] r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2). + * \param[in] KK The constraint length of the convolutional code. + * \param[in] LL The number of data bits. + * \param[out] output_u_int[] Hard decisions on the data bits + * + */ +inline static void Viterbi(int output_u_int[], + int out0[], + int state0[], + int out1[], + int state1[], + double input_c[], + int KK, + int nn, + int LL) +{ + int i, t, state, mm, states; + int number_symbols; + float metric; + float *prev_section, *next_section; + int *prev_bit; + int *prev_state; + float *metric_c; /* Set of all possible branch metrics */ + float *rec_array; /* Received values for one trellis section */ + float max_val; + + /* some derived constants */ + mm = KK - 1; + states = 1 << mm; /* 2^mm */ + number_symbols = 1 << nn; /* 2^nn */ + + /* dynamically allocate memory */ + prev_section = static_cast(calloc(states, sizeof(float))); + next_section = static_cast(calloc(states, sizeof(float))); + prev_bit = static_cast(calloc(states * (LL + mm), sizeof(int))); + prev_state = static_cast(calloc(states * (LL + mm), sizeof(int))); + rec_array = static_cast(calloc(nn, sizeof(float))); + metric_c = static_cast(calloc(number_symbols, sizeof(float))); + + /* initialize trellis */ + for (state = 0; state < states; state++) + { + prev_section[state] = -MAXLOG; + next_section[state] = -MAXLOG; + } + prev_section[0] = 0; /* start in all-zeros state */ + + /* go through trellis */ + for (t = 0; t < LL + mm; t++) + { + for (i = 0; i < nn; i++) + rec_array[i] = static_cast(input_c[nn * t + i]); + + /* precompute all possible branch metrics */ + for (i = 0; i < number_symbols; i++) + metric_c[i] = Gamma(rec_array, i, nn); + + /* step through all states */ + for (state = 0; state < states; state++) + { + /* hypothesis: info bit is a zero */ + metric = prev_section[state] + metric_c[out0[state]]; + + /* store new metric if more than metric in storage */ + if (metric > next_section[state0[state]]) + { + next_section[state0[state]] = metric; + prev_state[t * states + state0[state]] = state; + prev_bit[t * states + state0[state]] = 0; + } + + /* hypothesis: info bit is a one */ + metric = prev_section[state] + metric_c[out1[state]]; + + /* store new metric if more than metric in storage */ + if (metric > next_section[state1[state]]) + { + next_section[state1[state]] = metric; + prev_state[t * states + state1[state]] = state; + prev_bit[t * states + state1[state]] = 1; + } + } + + /* normalize */ + max_val = 0; + for (state = 0; state < states; state++) + { + if (next_section[state] > max_val) + { + max_val = next_section[state]; + } + } + for (state = 0; state < states; state++) + { + prev_section[state] = next_section[state] - max_val; + next_section[state] = -MAXLOG; + } + } + + /* trace-back operation */ + state = 0; + + /* tail, no need to output */ + for (t = LL + mm - 1; t >= LL; t--) + { + state = prev_state[t * states + state]; + } + + for (t = LL - 1; t >= 0; t--) + { + output_u_int[t] = prev_bit[t * states + state]; + state = prev_state[t * states + state]; + } + + /* free the dynamically allocated memory */ + free(prev_section); + free(next_section); + free(prev_bit); + free(prev_state); + free(rec_array); + free(metric_c); +} + + +#endif diff --git a/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.cc b/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.cc deleted file mode 100644 index f1db84183..000000000 --- a/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.cc +++ /dev/null @@ -1,292 +0,0 @@ -/*! - * \file gps_l1_ca_subframe_fsm.cc - * \brief Implementation of a GPS NAV message word-to-subframe decoder state machine - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_subframe_fsm.h" -#include -#include -#include -#include -#include -#include -#include "gnss_satellite.h" - - -//************ GPS WORD TO SUBFRAME DECODER STATE MACHINE ********** - -struct Ev_gps_word_valid : sc::event {}; -struct Ev_gps_word_invalid : sc::event{}; -struct Ev_gps_word_preamble : sc::event{}; - - -struct gps_subframe_fsm_S0: public sc::state -{ -public: - // sc::transition(event,next_status) - typedef sc::transition< Ev_gps_word_preamble, gps_subframe_fsm_S1 > reactions; - gps_subframe_fsm_S0(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S0 "< -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S2 > > reactions; - - gps_subframe_fsm_S1(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S1 "< -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S3 > > reactions; - - gps_subframe_fsm_S2(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S2 "<().gps_word_to_subframe(0); - } -}; - - - - -struct gps_subframe_fsm_S3: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S4 > > reactions; - - gps_subframe_fsm_S3(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S3 "<().gps_word_to_subframe(1); - } -}; - - - - -struct gps_subframe_fsm_S4: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S5 > > reactions; - - gps_subframe_fsm_S4(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S4 "<().gps_word_to_subframe(2); - } -}; - - - - -struct gps_subframe_fsm_S5: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S6 > > reactions; - - gps_subframe_fsm_S5(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S5 "<().gps_word_to_subframe(3); - } -}; - - - - - -struct gps_subframe_fsm_S6: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S7 > > reactions; - - gps_subframe_fsm_S6(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S6 "<().gps_word_to_subframe(4); - } -}; - - - -struct gps_subframe_fsm_S7: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S8 > > reactions; - - gps_subframe_fsm_S7(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S7 "<().gps_word_to_subframe(5); - } -}; - - - -struct gps_subframe_fsm_S8: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S9 > > reactions; - - gps_subframe_fsm_S8(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S8 "<().gps_word_to_subframe(6); - } -}; - - - - -struct gps_subframe_fsm_S9: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S10 > > reactions; - - gps_subframe_fsm_S9(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S9 "<().gps_word_to_subframe(7); - } -}; - - - -struct gps_subframe_fsm_S10: public sc::state -{ -public: - typedef mpl::list, - sc::transition< Ev_gps_word_valid, gps_subframe_fsm_S11 > > reactions; - - gps_subframe_fsm_S10(my_context ctx): my_base( ctx ) - { - //std::cout<<"Enter S10 "<().gps_word_to_subframe(8); - } -}; - - - -struct gps_subframe_fsm_S11: public sc::state -{ -public: - typedef sc::transition< Ev_gps_word_preamble, gps_subframe_fsm_S1 > reactions; - - gps_subframe_fsm_S11(my_context ctx): my_base( ctx ) - { - //std::cout<<"Completed GPS Subframe!"<().gps_word_to_subframe(9); - context< GpsL1CaSubframeFsm >().gps_subframe_to_nav_msg(); //decode the subframe - // DECODE SUBFRAME - //std::cout<<"Enter S11"<d_subframe); //decode the subframe - std::cout << "NAV Message: received subframe " - << d_subframe_ID << " from satellite " - << Gnss_Satellite(std::string("GPS"), i_satellite_PRN) << std::endl; - d_nav.i_satellite_PRN = i_satellite_PRN; - d_nav.i_channel_ID = i_channel_ID; - d_nav.d_subframe_timestamp_ms = this->d_preamble_time_ms; - - d_flag_new_subframe=true; -} - -void GpsL1CaSubframeFsm::Event_gps_word_valid() -{ - this->process_event(Ev_gps_word_valid()); -} - - - -void GpsL1CaSubframeFsm::Event_gps_word_invalid() -{ - this->process_event(Ev_gps_word_invalid()); -} - - - -void GpsL1CaSubframeFsm::Event_gps_word_preamble() -{ - this->process_event(Ev_gps_word_preamble()); -} - diff --git a/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.h b/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.h deleted file mode 100644 index 0a577502b..000000000 --- a/src/algorithms/telemetry_decoder/libs/gps_l1_ca_subframe_fsm.h +++ /dev/null @@ -1,101 +0,0 @@ -/*! - * \file gps_l1_ca_subframe_fsm.h - * \brief Interface of a GPS NAV message word-to-subframe decoder state machine - * \author Javier Arribas, 2011. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#ifndef GNSS_SDR_GPS_L1_CA_SUBFRAME_FSM_H_ -#define GNSS_SDR_GPS_L1_CA_SUBFRAME_FSM_H_ - -#include -#include "concurrent_queue.h" -#include "GPS_L1_CA.h" -#include "gps_navigation_message.h" -#include "gps_ephemeris.h" -#include "gps_iono.h" -#include "gps_almanac.h" -#include "gps_utc_model.h" - -namespace sc = boost::statechart; -namespace mpl = boost::mpl; - -struct gps_subframe_fsm_S0; -struct gps_subframe_fsm_S1; -struct gps_subframe_fsm_S2; -struct gps_subframe_fsm_S3; -struct gps_subframe_fsm_S4; -struct gps_subframe_fsm_S5; -struct gps_subframe_fsm_S6; -struct gps_subframe_fsm_S7; -struct gps_subframe_fsm_S8; -struct gps_subframe_fsm_S9; -struct gps_subframe_fsm_S10; -struct gps_subframe_fsm_S11; - - -/*! - * \brief This class implements a Finite State Machine that handles the decoding - * of the GPS L1 C/A NAV message - */ -class GpsL1CaSubframeFsm : public sc::state_machine< GpsL1CaSubframeFsm, gps_subframe_fsm_S0 > -{ -public: - GpsL1CaSubframeFsm(); //!< The constructor starts the Finite State Machine - void clear_flag_new_subframe(); - // channel and satellite info - int i_channel_ID; //!< Channel id - unsigned int i_satellite_PRN; //!< Satellite PRN number - - Gps_Navigation_Message d_nav; //!< GPS L1 C/A navigation message object - - // GPS SV and System parameters - Gps_Ephemeris ephemeris; //!< Object that handles GPS ephemeris parameters - Gps_Almanac almanac; //!< Object that handles GPS almanac data - Gps_Utc_Model utc_model; //!< Object that handles UTM model parameters - Gps_Iono iono; //!< Object that handles ionospheric parameters - - char d_subframe[GPS_SUBFRAME_LENGTH]; - int d_subframe_ID; - bool d_flag_new_subframe; - char d_GPS_frame_4bytes[GPS_WORD_LENGTH]; - double d_preamble_time_ms; - - void gps_word_to_subframe(int position); //!< inserts the word in the correct position of the subframe - - /*! - * \brief This function decodes a NAv message subframe and pushes the information to the right queues - */ - void gps_subframe_to_nav_msg(); - - //FSM EVENTS - void Event_gps_word_valid(); //!< FSM event: the received word is valid - void Event_gps_word_invalid(); //!< FSM event: the received word is not valid - void Event_gps_word_preamble(); //!< FSM event: word preamble detected -}; - -#endif diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/CMakeLists.txt b/src/algorithms/telemetry_decoder/libs/libswiftcnav/CMakeLists.txt new file mode 100644 index 000000000..af753c057 --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + +set(TELEMETRY_DECODER_LIBSWIFTCNAV_SOURCES + cnav_msg.c + bits.c + edc.c + viterbi27.c +) + +set(TELEMETRY_DECODER_LIBSWIFTCNAV_HEADERS + cnav_msg.h + bits.h + edc.h + swift_common.h + fec.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} +) + +list(SORT TELEMETRY_DECODER_LIBSWIFTCNAV_HEADERS) +list(SORT TELEMETRY_DECODER_LIBSWIFTCNAV_SOURCES) + +add_library(telemetry_decoder_libswiftcnav STATIC + ${TELEMETRY_DECODER_LIBSWIFTCNAV_SOURCES} + ${TELEMETRY_DECODER_LIBSWIFTCNAV_HEADERS} +) + +source_group(Headers FILES ${TELEMETRY_DECODER_LIBSWIFTCNAV_HEADERS}) + +set_target_properties(telemetry_decoder_libswiftcnav + PROPERTIES LINKER_LANGUAGE C) diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.c b/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.c new file mode 100644 index 000000000..866b822fb --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.c @@ -0,0 +1,301 @@ +/*! + * \file bits.c + * \author Fergus Noble + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2013, 2016 Swift Navigation Inc. + * Contact: Fergus Noble + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "bits.h" + +#include +#include + + +static const u8 bitn[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; + +/** \defgroup bits Bit Utils + * Bit field packing, unpacking and utility functions. + * \{ */ + +/** Computes the parity of a 32-bit word. + * + * References: + * -# https://graphics.stanford.edu/~seander/bithacks.html#ParityParallel + * + * \param x Word for which to compute parity + * \return 1 if there are an odd number of bits set. + * 0 if there are an even number of bits set. + */ +u8 parity(u32 x) +{ + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x &= 0xF; + return (0x6996 >> x) & 1; +} + + +/** Get bit field from buffer as an unsigned integer. + * Unpacks `len` bits at bit position `pos` from the start of the buffer. + * Maximum bit field length is 32 bits, i.e. `len <= 32`. + * + * \param buff + * \param pos Position in buffer of start of bit field in bits. + * \param len Length of bit field in bits. + * \return Bit field as an unsigned value. + */ +u32 getbitu(const u8 *buff, u32 pos, u8 len) +{ + u32 bits = 0; + u32 i=0; + for (i = pos; i < pos + len; i++) + { + bits = (bits << 1) + + ((buff[i/8] >> (7 - i%8)) & 1u); + } + + return bits; +} + +/** Get bit field from buffer as a signed integer. + * Unpacks `len` bits at bit position `pos` from the start of the buffer. + * Maximum bit field length is 32 bits, i.e. `len <= 32`. + * + * This function sign extends the `len` bit field to a signed 32 bit integer. + * + * \param buff + * \param pos Position in buffer of start of bit field in bits. + * \param len Length of bit field in bits. + * \return Bit field as a signed value. + */ +s32 getbits(const u8 *buff, u32 pos, u8 len) +{ + s32 bits = (s32)getbitu(buff, pos, len); + + /* Sign extend, taken from: + * http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend + */ + s32 m = 1u << (len - 1); + return (bits ^ m) - m; +} + +/** Set bit field in buffer from an unsigned integer. + * Packs `len` bits into bit position `pos` from the start of the buffer. + * Maximum bit field length is 32 bits, i.e. `len <= 32`. + * + * \param buff + * \param pos Position in buffer of start of bit field in bits. + * \param len Length of bit field in bits. + * \param data Unsigned integer to be packed into bit field. + */ +void setbitu(u8 *buff, u32 pos, u32 len, u32 data) +{ + u32 mask = 1u << (len - 1); + + if (len <= 0 || 32 < len) + return; + u32 i = 0; + for (i = pos; i < pos + len; i++, mask >>= 1) + { + if (data & mask) + buff[i/8] |= 1u << (7 - i % 8); + else + buff[i/8] &= ~(1u << (7 - i % 8)); + } +} + +/** Set bit field in buffer from a signed integer. + * Packs `len` bits into bit position `pos` from the start of the buffer. + * Maximum bit field length is 32 bits, i.e. `len <= 32`. + * + * \param buff + * \param pos Position in buffer of start of bit field in bits. + * \param len Length of bit field in bits. + * \param data Signed integer to be packed into bit field. + */ +void setbits(u8 *buff, u32 pos, u32 len, s32 data) +{ + setbitu(buff, pos, len, (u32)data); +} + +/** + * Shift MSB bit buffer contents to the left. + * The method performs in-place shift operation. + * + * \param[in,out] buf Pointer to buffer head. + * \param[in] size Number of bytes in the buffer. + * \param[in] shift Number of bits for left shift operation. + * + * \return None + */ +void bitshl(void *buf, u32 size, u32 shift) +{ + if (shift > size * CHAR_BIT) + { + /* Quick check: if the shift is larger, than the buffer, zero the data */ + memset(buf, 0, size); + return; + } + + unsigned char *dst = buf; /* Destination byte. */ + const unsigned char *src = dst + shift / CHAR_BIT; /* First source byte, possibly incomplete. */ + + u32 copy_bits = size * CHAR_BIT - shift; /* Number of bits to move */ + u32 byte_shift = copy_bits % CHAR_BIT; /* Shift of data */ + u32 full_bytes = copy_bits / CHAR_BIT; /* Number of bytes to move */ + + if (0 == byte_shift) + { + /* When moving data in character boundaries, use built-in functions: move + * data, and then zero the tail. */ + memmove(dst, src, full_bytes); + memset(dst + full_bytes, 0, size - full_bytes); + } + else + { + /* Create an accumulator: it will hold a value of two consecutive bytes */ + u32 acc = *src++; + u32 i = 0; + for (i = 0; i < full_bytes; ++i) + { + acc = (acc << CHAR_BIT) | *src++; + *dst++ = acc >> byte_shift; + } + *dst++ = acc << CHAR_BIT >> byte_shift; + if (full_bytes + 1 < size) + { + memset(dst, 0, size - full_bytes - 1); + } + } +} + +/** + * Performs block bit copy operation. + * + * The function copies given number of bits from the source to destination. + * + * \param[in,out] dst Pointer to destination buffer. + * \param[in] dst_index Destination bit index. + * \param[in] src Source buffer. + * \param[in] src_index Source bit index. + * \param[in] count Number of bits to copy. + * + * \return None + * + * \todo This function can be optimized for copying aligned data and using + * proper native type like long. + */ +void bitcopy(void *dst, u32 dst_index, const void *src, u32 src_index, + u32 count) +{ + u32 limit1 = count / 32; + u32 limit2 = count % 32; + u32 idx = 0; + for (idx = 0; idx < limit1; ++idx) + { + u32 tmp = getbitu(src, src_index, 32); + setbitu(dst, dst_index, 32, tmp); + src_index += 32; + dst_index += 32; + } + if (0 != limit2) + { + u32 tmp = getbitu(src, src_index, limit2); + setbitu(dst, dst_index, limit2, tmp); + } +} + +/** + * Count number of bits set to certain value in 64 bits word + * + * \param[in] v input 64 bits word to count bits in + * \param[in] bv 1 or 0 - which value to count + * + * \return Number of bits set to one or zero. + */ +u8 count_bits_u64(u64 v, u8 bv) +{ + u8 r = 0; + int i = 0; + for (i = 0; i < 16; i++) + r += bitn[(v >> (i*4)) & 0xf]; + return bv == 1 ? r : 64 - r; +} + +/** + * Count number of bits set to certain value in 32 bits word + * + * \param[in] v input 32 bits word to count bits in + * \param[in] bv 1 or 0 - which value to count + * + * \return Number of bits set to one or zero. + */ +u8 count_bits_u32(u32 v, u8 bv) +{ + u8 r = 0; + int i = 0; + for (i = 0; i < 8; i++) + r += bitn[(v >> (i*4)) & 0xf]; + return bv == 1 ? r : 32 - r; +} + +/** + * Count number of bits set to certain value in 16 bits word + * + * \param[in] v input 16 bits word to count bits in + * \param[in] bv 1 or 0 - which value to count + * + * \return Number of bits set to one or zero. + */ +u8 count_bits_u16(u16 v, u8 bv) +{ + u8 r = 0; + int i = 0; + for (i= 0; i < 4; i++) + r += bitn[(v >> (i*4)) & 0xf]; + return bv == 1 ? r : 16 - r; +} + +/** + * Count number of bits set to certain value in 8 bits word + * + * \param[in] v input 8 bits word to count bits in + * \param[in] bv 1 or 0 - which value to count + * + * \return Number of bits set to one or zero. + */ +u8 count_bits_u8(u8 v, u8 bv) +{ + u8 r = 0; + int i = 0; + for (i = 0; i < 2; i++) + r += bitn[(v >> (i*4)) & 0xf]; + return bv == 1 ? r : 8 - r; +} + +/** \} */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.h b/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.h new file mode 100644 index 000000000..8e73ccf4a --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/bits.h @@ -0,0 +1,50 @@ +/*! + * \file bits.h + * \author Fergus Noble + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2013, 2016 Swift Navigation Inc. + * Contact: Fergus Noble + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef LIBSWIFTNAV_BITS_H +#define LIBSWIFTNAV_BITS_H + +#include "swift_common.h" + +u8 parity(u32 x); +u32 getbitu(const u8 *buff, u32 pos, u8 len); +s32 getbits(const u8 *buff, u32 pos, u8 len); +void setbitu(u8 *buff, u32 pos, u32 len, u32 data); +void setbits(u8 *buff, u32 pos, u32 len, s32 data); +void bitcopy(void *dst, u32 dst_index, + const void *src, u32 src_index, u32 count); +void bitshl(void *buf, u32 size, u32 shift); +u8 count_bits_u64(u64 v, u8 bv); +u8 count_bits_u32(u32 v, u8 bv); +u8 count_bits_u16(u16 v, u8 bv); +u8 count_bits_u8(u8 v, u8 bv); + +#endif /* LIBSWIFTNAV_BITS_H */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.c b/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.c new file mode 100644 index 000000000..bbb52ac4d --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.c @@ -0,0 +1,491 @@ +/*! + * \file cnav_msg.c + * \author Valeri Atamaniouk + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2016 Swift Navigation Inc. + * Contact: Valeri Atamaniouk + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#include "edc.h" +#include "bits.h" +#include "cnav_msg.h" + +#include +#include + +/** \defgroup GPS_L2 GPS L2 + * GPS L2 operations + * \{ */ +/** \defgroup gps_cnav_decoder Decoder + * GPS L2C CNAV message decoding. + * \{ */ +/* + * Block Viterbi decoding parameters. + */ +/** Viterbi decoder reversed polynomial A */ +#define GPS_L2C_V27_POLY_A (0x4F) /* 0b01001111 - reversed 0171*/ + +/** Viterbi decoder reversed polynomial B */ +#define GPS_L2C_V27_POLY_B (0x6D) /* 0b01101101 - reversed 0133 */ +/* + * GPS L2C message constants. + */ + +/** GPS L2C preamble */ +const u32 GPS_CNAV_PREAMBLE1 = 0x8Bu; /* (0b10001011u) */ +/** Inverted GPS L2C preamble */ +const u32 GPS_CNAV_PREAMBLE2 = 0x74u; /* (0b01110100u) */ +/** GPS L2C preamble length in bits */ +#define GPS_CNAV_PREAMBLE_LENGTH (8) +/** GPS L2C CNAV message length in bits */ +#define GPS_CNAV_MSG_LENGTH (300) +/** GPS LC2 CNAV CRC length in bits */ +#define GPS_CNAV_MSG_CRC_LENGTH (24) +/** GPS L2C CNAV message payload length in bits */ +#define GPS_CNAV_MSG_DATA_LENGTH (GPS_CNAV_MSG_LENGTH - GPS_CNAV_MSG_CRC_LENGTH) +/** GPS L2C CNAV message lock detector threshold */ +#define GPS_CNAV_LOCK_MAX_CRC_FAILS (10) + +/** + * Computes CRC-24Q from a CNAV message buffer. + * CRC-24Q is computed for 274 bits. For a purpose of 8-bit alignment, the + * message is assumed to be prepended with four zero bits. + * + * \param[in] part Decoder component with payload + * + * \return CRC-24Q value. + * + * \private + */ +static u32 _cnav_compute_crc(cnav_v27_part_t *part) +{ + u32 crc = crc24q_bits(0, part->decoded, GPS_CNAV_MSG_DATA_LENGTH, + part->invert); + + return crc; +} + + +/** + * Extracts CRC-24Q from a CNAV message buffer. + * CRC-24Q value is the last 24 bits from 300 bits message buffer. + * + * \param[in] part Decoded component with payload. + * + * \return CRC24-Q value. + * + * \private + */ +static u32 _cnav_extract_crc(const cnav_v27_part_t *part) +{ + u32 crc = getbitu(part->decoded, GPS_CNAV_MSG_DATA_LENGTH, + GPS_CNAV_MSG_CRC_LENGTH); + if (part->invert) + { + crc ^= 0xFFFFFF; + } + return crc; +} + + +/** + * Helper to rescan for preamble in the received buffer. + * Occasionally there could be a false lock on message contents if it the + * preamble sequence is encountered in the message body. For this case, the + * function performs for a scan for a preamble with a different offset: + * - When found, the preamble octet is moved into the head of the buffer. + * - When not found, only 7 bits are left in the buffer. + * + * \param[in,out] part Decoded component. + * + * \return None + * + * \private + */ +static void _cnav_rescan_preamble(cnav_v27_part_t *part) +{ + part->preamble_seen = false; + + if (part->n_decoded > GPS_CNAV_PREAMBLE_LENGTH + 1) + { + size_t i = 0; + size_t j = 0; + for (i = 1, j = part->n_decoded - GPS_CNAV_PREAMBLE_LENGTH; i < j; ++i) + { + u32 c = getbitu(part->decoded, i, GPS_CNAV_PREAMBLE_LENGTH); + if (GPS_CNAV_PREAMBLE1 == c || GPS_CNAV_PREAMBLE2 == c) + { + part->preamble_seen = true; + part->invert = (GPS_CNAV_PREAMBLE2 == c); + /* We shift the accumulated bits to the beginning of the buffer */ + bitshl(part->decoded, sizeof(part->decoded), i); + part->n_decoded -= i; + break; + } + } + } + if (!part->preamble_seen && part->n_decoded >= GPS_CNAV_PREAMBLE_LENGTH) + { + bitshl(part->decoded, sizeof(part->decoded), + part->n_decoded - GPS_CNAV_PREAMBLE_LENGTH + 1); + part->n_decoded = GPS_CNAV_PREAMBLE_LENGTH - 1; + } +} + + +/** + * Feed a symbol into Viterbi decoder instance. + * + * The method uses block Viterbi decoder. It first accumulates initial number of + * symbols, and after that runs decoding every time the buffer is full. Only + * some of the decoded symbols are used. + * + * \param[in,out] part Decoder object + * \param[in] s Symbol (0x00 - Hard 0, 0xFF - Hard 1) + * + * \return None + * + * \private + */ +static void _cnav_add_symbol(cnav_v27_part_t *part, u8 ch) +{ + part->symbols[part->n_symbols++] = ch; + + if (part->init) + { + /* Initial step - load more symbols without decoding. */ + if (part->n_symbols < (GPS_L2C_V27_INIT_BITS + GPS_L2C_V27_DECODE_BITS) * 2) + { + return; + } + part->init = false; + } + else if (part->n_symbols < GPS_L2C_V27_DECODE_BITS * 2) + { + /* Wait until decoding block is accumulated */ + return; + } + + /* Feed accumulated symbols into the buffer, reset the number of accumulated + * symbols. */ + v27_update(&part->dec, part->symbols, part->n_symbols / 2); + part->n_symbols = 0; + + /* Decode N+M bits, where: + * - N - Number of bits to put into decoded buffer + * - M - Number of bits in the tail to ignore. + */ + unsigned char tmp_bits[(GPS_L2C_V27_DECODE_BITS + GPS_L2C_V27_DELAY_BITS + + CHAR_BIT - 1) / + CHAR_BIT]; + + v27_chainback_likely(&part->dec, tmp_bits, + GPS_L2C_V27_DECODE_BITS + GPS_L2C_V27_DELAY_BITS); + + /* Read decoded bits and add them to the decoded buffer */ + bitcopy(part->decoded, part->n_decoded, tmp_bits, 0, GPS_L2C_V27_DECODE_BITS); + part->n_decoded += GPS_L2C_V27_DECODE_BITS; + + /* Depending on the decoder state, one of the following actions are + * possible: + * - If no message lock + * - If no preamble seen - look for preamble + * - If preamble seen - collect 300 bits + * - If 300 bits are collected - verify CRC + * - If CRC is OK - message lock is acquired + * - If CRC fails - rescan for preamble + * - If found - continue collecting 300 bits + * - If not found - continue preamble wait + * - If message lock + * - If 300 bits collected, compute CRC + * - If CRC is OK, message can be decoded + * - If CRC is not OK, discard data + */ + + bool retry = true; + while (retry) + { + retry = false; + + if (!part->preamble_seen) + { + /* Rescan for preamble if possible. The first bit is ignored. */ + _cnav_rescan_preamble(part); + } + if (part->preamble_seen && GPS_CNAV_MSG_LENGTH <= part->n_decoded) + { + /* We have collected 300 bits starting from message preamble. Now try + * to compute CRC-24Q */ + u32 crc = _cnav_compute_crc(part); + u32 crc2 = _cnav_extract_crc(part); + + if (part->message_lock) + { + /* We have message lock */ + part->crc_ok = (crc == crc2); + if (part->crc_ok) + { + /* Reset message lock counter */ + part->n_crc_fail = 0; + } + else + { + /* Increment message lock counter */ + part->n_crc_fail++; + if (part->n_crc_fail > GPS_CNAV_LOCK_MAX_CRC_FAILS) + { + /* CRC has failed too many times - drop the lock. */ + part->n_crc_fail = 0; + part->message_lock = false; + part->preamble_seen = false; + /* Try to find a new preamble, reuse data from buffer. */ + retry = true; + } + } + } + else if (crc == crc2) + { + /* CRC match - message can be decoded */ + part->message_lock = true; + part->crc_ok = true; + part->n_crc_fail = 0; + } + else + { + /* There is no message lock and the CRC check fails. Assume there is + * false positive lock - rescan for preamble. */ + part->crc_ok = false; + part->preamble_seen = false; + + /* CRC mismatch - try to re-scan for preamble */ + retry = true; + } + } + else + { + /* No preamble or preamble and less than 300 bits decoded */ + } + } +} + + +/** + * Invert message bits in the buffer. + * + * The method inverts bits of the decoded data. + * + * \param[in,out] part Decoder component with a message buffer. + * + * \return None + */ +static void _cnav_msg_invert(cnav_v27_part_t *part) +{ + size_t i = 0; + for (i = 0; i < sizeof(part->decoded); i++) + { + part->decoded[i] ^= 0xFFu; + } +} + + +/** + * Performs CNAV message decoding. + * + * This function decoded CNAV message, if the following conditions are met: + * - Buffer contains 300 bits. + * - First 8 bits are matching direct or inverse preamble. + * - Message data CRC matches one in the buffer. + * + * In case the message starts with inverted preamble, the data is inverted + * before parsing. + * + * \param[in,out] part Decoder component. + * \param[out] msg Container for a decoded message. + * \param[out] delay Delay of the message in symbols. + * + * \retval true The message has been decoded, and \a msg container is populated. + * \retval false Not enough data or CRC is not correct. + * + * \private + */ +static bool _cnav_msg_decode(cnav_v27_part_t *part, cnav_msg_t *msg, u32 *delay) +{ + bool res = false; + if (GPS_CNAV_MSG_LENGTH <= part->n_decoded) + { + if (part->crc_ok) + { + /* CRC is OK */ + if (part->invert) + { + _cnav_msg_invert(part); + } + + msg->prn = getbitu(part->decoded, 8, 6); + msg->msg_id = getbitu(part->decoded, 14, 6); + msg->tow = getbitu(part->decoded, 20, 17); + msg->alert = getbitu(part->decoded, 37, 1) ? true : false; + + /* copy RAW message for GNSS-SDR */ + memcpy(msg->raw_msg, part->decoded, GPS_L2C_V27_DECODE_BITS + GPS_L2C_V27_DELAY_BITS); + + *delay = (part->n_decoded - GPS_CNAV_MSG_LENGTH + GPS_L2C_V27_DELAY_BITS) * 2 + part->n_symbols; + + if (part->invert) + { + _cnav_msg_invert(part); + } + res = true; + } + else + { + /* CRC mismatch - no decoding */ + } + bitshl(part->decoded, sizeof(part->decoded), GPS_CNAV_MSG_LENGTH); + part->n_decoded -= GPS_CNAV_MSG_LENGTH; + } + + return res; +} + + +/** + * Initialize CNAV decoder. + * + * CNAV decoder contains two Viterbi decoders that are used to estimate bit and + * message boundary. + * + * \param[out] dec Decoder structure. + * + * \return None + */ +void cnav_msg_decoder_init(cnav_msg_decoder_t *dec) +{ + memset(dec, 0, sizeof(*dec)); + v27_init(&dec->part1.dec, + dec->part1.decisions, + GPS_L2_V27_HISTORY_LENGTH_BITS, + cnav_msg_decoder_get_poly(), + 0); + v27_init(&dec->part2.dec, + dec->part2.decisions, + GPS_L2_V27_HISTORY_LENGTH_BITS, + cnav_msg_decoder_get_poly(), + 0); + dec->part1.init = true; + dec->part2.init = true; + _cnav_add_symbol(&dec->part2, 0x80); +} + +/** + * Adds a received symbol to decoder. + * + * The method feeds the symbol into the decoder. In case there is a sufficient + * information to produce a message, the message is decoded and symbol delay is + * reported. + * The time of the last input symbol can be computed from the message ToW and + * delay by the formulae: + * \code + * symbolTime_ms = msg->tow * 6000 + *pdelay * 20 (L2) + * symbolTime_ms = msg->tow * 6000 + *pdelay * 10 (L5) + * \endcode + * + * \param[in,out] dec Decoder object. + * \param[in] symbol Symbol value probability, where 0x00 - 100% of 0, + * 0xFF - 100% of 1. + * \param[out] msg Buffer for decoded message. The message is available + * only when message lock is acquired and CRC is correct. + * \param[out] pdelay Delay of message generation in symbols. + * + * \retval true The message has been decoded. ToW parameter is available. + * \retval false More data is required. + */ +bool cnav_msg_decoder_add_symbol(cnav_msg_decoder_t *dec, + u8 symbol, + cnav_msg_t *msg, + u32 *pdelay) +{ + _cnav_add_symbol(&dec->part1, symbol); + _cnav_add_symbol(&dec->part2, symbol); + + if (dec->part1.message_lock) + { + /* Flush data in decoder. */ + dec->part2.n_decoded = 0; + dec->part2.n_symbols = 0; + return _cnav_msg_decode(&dec->part1, msg, pdelay); + } + if (dec->part2.message_lock) + { + /* Flush data in decoder. */ + dec->part1.n_decoded = 0; + dec->part1.n_symbols = 0; + return _cnav_msg_decode(&dec->part2, msg, pdelay); + } + + return false; +} + + +/** + * Provides a singleton polynomial object. + * + * The method constructs and returns polynomial object for CNAV message + * decoding. The same polynomial can be used also for other message handling. + * + * The object is initialized on the first call. The method is thread-safe. + * + * @return Pointer to polynomial object for CNAV message decoding. + */ +const v27_poly_t *cnav_msg_decoder_get_poly(void) +{ + static v27_poly_t instance; + static bool initialized = false; + + if (!initialized) + { + /* Coefficients for polynomial object */ + const signed char coeffs[2] = {GPS_L2C_V27_POLY_A, GPS_L2C_V27_POLY_B}; + + /* Racing condition handling: the data can be potential initialized more + * than once in case multiple threads request concurrent access. However, + * nature of the v27_poly_init() function and data alignment ensure that + * the data returned from the earlier finished call is consistent and can + * be used even when re-initialization is happening. + * + * Other possible approaches are: + * - Replace late initialization with an explicit call. + * - Use POSIX synchronization objects like pthread_once_t. + */ + v27_poly_init(&instance, coeffs); + initialized = true; + } + return &instance; +} + +/** \} */ +/** \} */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.h b/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.h new file mode 100644 index 000000000..f402675c5 --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/cnav_msg.h @@ -0,0 +1,120 @@ +/*! + * \file cnav_msg.h + * \author Valeri Atamaniouk + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2016 Swift Navigation Inc. + * Contact: Valeri Atamaniouk + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#ifndef LIBSWIFTNAV_CNAV_MSG_H +#define LIBSWIFTNAV_CNAV_MSG_H + +#include "fec.h" +#include "swift_common.h" +#include +#include +#include +#include + +/** \addtogroup GPS_L2 + * \{ */ +/** \addtogroup gps_cnav_decoder + * \{ */ + +/** Size of the Viterbi decoder history. */ +#define GPS_L2_V27_HISTORY_LENGTH_BITS 64 +/** Bits to accumulate before decoding starts. */ +#define GPS_L2C_V27_INIT_BITS (32) +/** Bits to decode at a time. */ +#define GPS_L2C_V27_DECODE_BITS (32) +/** Bits in decoder tail. We ignore them. */ +#define GPS_L2C_V27_DELAY_BITS (32) +/** + * GPS CNAV message container. + * + * @sa cnav_msg_decoder_add_symbol + */ +typedef struct +{ + u8 prn; /**< SV PRN. 0..31 */ + u8 msg_id; /**< Message id. 0..31 */ + u32 tow; /**< GPS ToW in 6-second units. Multiply to 6 to get seconds. */ + bool alert; /**< CNAV message alert flag */ + u8 raw_msg[GPS_L2C_V27_DECODE_BITS + GPS_L2C_V27_DELAY_BITS]; /**< RAW MSG for GNSS-SDR */ +} cnav_msg_t; + +/** + * GPS CNAV decoder component. + * This component controls symbol decoding string. + * + * @sa cnav_msg_decoder_t + */ +typedef struct +{ + v27_t dec; /**< Viterbi block decoder object */ + v27_decision_t decisions[GPS_L2_V27_HISTORY_LENGTH_BITS]; + /**< Decision graph */ + unsigned char symbols[(GPS_L2C_V27_INIT_BITS + GPS_L2C_V27_DECODE_BITS) * 2]; + /**< Symbol buffer */ + size_t n_symbols; /**< Count of symbols in the symbol buffer */ + unsigned char decoded[GPS_L2C_V27_DECODE_BITS + GPS_L2C_V27_DELAY_BITS]; + /**< Decode buffer */ + size_t n_decoded; /**< Number of bits in the decode buffer */ + bool preamble_seen; /**< When true, the decode buffer is aligned on + * preamble. */ + bool invert; /**< When true, indicates the bits are inverted */ + bool message_lock; /**< When true, indicates the message boundary + * is found. */ + bool crc_ok; /**< Flag that the last message had good CRC */ + size_t n_crc_fail; /**< Counter for CRC failures */ + bool init; /**< Initial state flag. When true, initial bits + * do not produce output. */ +} cnav_v27_part_t; + +/** + * GPS CNAV message lock and decoder object. + * + * Decoder uses two Viterbi decoder objects to ensure the lock is acquired when + * the input symbol phase is not known. + */ +typedef struct +{ + cnav_v27_part_t part1; /**< Decoder for odd symbol pairs */ + cnav_v27_part_t part2; /**< Decoder for even symbol pairs */ +} cnav_msg_decoder_t; + +const v27_poly_t *cnav_msg_decoder_get_poly(void); +void cnav_msg_decoder_init(cnav_msg_decoder_t *dec); +bool cnav_msg_decoder_add_symbol(cnav_msg_decoder_t *dec, + unsigned char symbol, + cnav_msg_t *msg, + u32 *delay); + +/** \} */ +/** \} */ + +#endif /* LIBSWIFTNAV_CNAV_MSG_H */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.c b/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.c new file mode 100644 index 000000000..c89bae64d --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.c @@ -0,0 +1,146 @@ +/*! + * \file edc.c + * \author Fergus Noble + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2010 Swift Navigation Inc. + * Contact: Fergus Noble + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "edc.h" + +/** \defgroup edc Error Detection and Correction + * Error detection and correction functions. + * \{ */ + +/** \defgroup crc CRC + * Cyclic redundancy checks. + * \{ */ + +static const u32 crc24qtab[256] = { + 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC, 0x9F7F17, + 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5, 0x3EFE2E, + 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65, 0x5A319E, + 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C, 0xFBB0A7, + 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, 0x93AEFE, + 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, 0x322FC7, + 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, 0x56E077, + 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5, 0xF7614E, + 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E, 0x86DCC5, + 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107, 0x275DFC, + 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7, 0x43924C, + 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, 0xE21375, + 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, 0x8A0D2C, + 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, 0x2B8C15, + 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E, 0x4F43A5, + 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67, 0xEEC29C, + 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448, 0xAC38B3, + 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571, 0x0DB98A, + 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, 0x69763A, + 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, 0xC8F703, + 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, 0xA0E95A, + 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498, 0x016863, + 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28, 0x65A7D3, + 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11, 0xC426EA, + 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A, 0xB59B61, + 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, 0x141A58, + 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, 0x70D5E8, + 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, 0xD154D1, + 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673, 0xB94A88, + 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A, 0x18CBB1, + 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA, 0x7C0401, + 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3, 0xDD8538 +}; + +/** Calculate Qualcomm 24-bit Cyclical Redundancy Check (CRC-24Q). + * + * The CRC polynomial used is: + * \f[ + * x^{24} + x^{23} + x^{18} + x^{17} + x^{14} + x^{11} + x^{10} + + * x^7 + x^6 + x^5 + x^4 + x^3 + x+1 + * \f] + * Mask 0x1864CFB, not reversed, not XOR'd + * + * \param buf Array of data to calculate CRC for + * \param len Length of data array + * \param crc Initial CRC value + * + * \return CRC-24Q value + */ +u32 crc24q(const u8 *buf, u32 len, u32 crc) +{ + u32 i = 0; + for (i = 0; i < len; i++) + crc = ((crc << 8) & 0xFFFFFF) ^ crc24qtab[((crc >> 16) ^ buf[i]) & 0xff]; + return crc; +} + +/** + * Computes CRC-24Q for left-aligned bit message. + * This function is used for left-aligned bit messages, for example SBAS and + * GPS CNAV. + * GPS message is 300 bits total, but 276 bits without CRC. It takes 34.5 + * 8-bit bytes, and when computing CRC the message has to be padded with zero + * bits. + * + * \param[in] crc Initial CRC value + * \param[in] buf Pointer to MSB-aligned data. + * \param[in] n_bits Number of bits in the data buffer. + * \param[in] invert Flag to compute inverted CRC. + * + * \return CRC-24Q value + */ +u32 crc24q_bits(u32 crc, const u8 *buf, u32 n_bits, bool invert) +{ + u16 acc = 0; + u8 b = 0; + u32 shift = 8 - n_bits % 8; + + u32 i = 0; + for (i = 0; i < n_bits / 8; ++i) + { + acc = (acc << 8) | *buf++; + if (invert) + { + acc ^= 0xFFu; + } + b = (acc >> shift) & 0xFFu; + crc = ((crc << 8) & 0xFFFFFFu) ^ crc24qtab[((crc >> 16) ^ b) & 0xFFu]; + } + acc = (acc << 8) | *buf; + if (invert) + { + acc ^= 0xFFu; + } + b = (acc >> shift) & 0xFFu; + crc = ((crc << 8) & 0xFFFFFFu) ^ crc24qtab[((crc >> 16) ^ b) & 0xFFu]; + + return crc; +} + + +/** \} */ + +/** \} */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.h b/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.h new file mode 100644 index 000000000..58a968a65 --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/edc.h @@ -0,0 +1,41 @@ +/*! + * \file edc.h + * \author Fergus Noble + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2010 Swift Navigation Inc. + * Contact: Fergus Noble + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#ifndef LIBSWIFTNAV_EDC_H +#define LIBSWIFTNAV_EDC_H + +#include "swift_common.h" + +u32 crc24q(const u8 *buf, u32 len, u32 crc); +u32 crc24q_bits(u32 crc, const u8 *buf, u32 n_bits, bool invert); + +#endif /* LIBSWIFTNAV_EDC_H */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/fec.h b/src/algorithms/telemetry_decoder/libs/libswiftcnav/fec.h new file mode 100644 index 000000000..f00e88e68 --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/fec.h @@ -0,0 +1,76 @@ +/*! + * \file fec.h + * \author Phil Karn, KA9Q + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2004, Phil Karn, KA9Q + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#ifndef LIBSWIFTNAV_FEC_H_ +#define LIBSWIFTNAV_FEC_H_ + +/* r=1/2 k=7 convolutional encoder polynomials + * The NASA-DSN convention is to use V27POLYA inverted, then V27POLYB + * The CCSDS/NASA-GSFC convention is to use V27POLYB, then V27POLYA inverted + */ +#define V27POLYA 0x4f +#define V27POLYB 0x6d + +typedef struct +{ + unsigned char c0[32]; + unsigned char c1[32]; +} v27_poly_t; + +typedef struct +{ + unsigned int w[2]; +} v27_decision_t; + +/* State info for instance of r=1/2 k=7 Viterbi decoder + */ +typedef struct +{ + unsigned int metrics1[64]; /* Path metric buffer 1 */ + unsigned int metrics2[64]; /* Path metric buffer 2 */ + /* Pointers to path metrics, swapped on every bit */ + unsigned int *old_metrics, *new_metrics; + const v27_poly_t *poly; /* Polynomial to use */ + v27_decision_t *decisions; /* Beginning of decisions for block */ + unsigned int decisions_index; /* Index of current decision */ + unsigned int decisions_count; /* Number of decisions in history */ +} v27_t; + +void v27_poly_init(v27_poly_t *poly, const signed char polynomial[2]); + +void v27_init(v27_t *v, v27_decision_t *decisions, unsigned int decisions_count, + const v27_poly_t *poly, unsigned char initial_state); +void v27_update(v27_t *v, const unsigned char *syms, int nbits); +void v27_chainback_fixed(v27_t *v, unsigned char *data, unsigned int nbits, + unsigned char final_state); +void v27_chainback_likely(v27_t *v, unsigned char *data, unsigned int nbits); + +#endif diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/swift_common.h b/src/algorithms/telemetry_decoder/libs/libswiftcnav/swift_common.h new file mode 100644 index 000000000..b4a3a6fae --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/swift_common.h @@ -0,0 +1,84 @@ +/*! + * \file swift_common.h + * \author Henry Hallam + * Fergus Noble + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2012 Swift Navigation Inc. + * Contact: Henry Hallam + * Fergus Noble + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#ifndef LIBSWIFTNAV_COMMON_H +#define LIBSWIFTNAV_COMMON_H + +/** \defgroup common Common definitions + * Common definitions used throughout the library. + * \{ */ + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define CLAMP_DIFF(a, b) (MAX((a), (b)) - (b)) + +#include +#include +#include + +#ifndef COMMON_INT_TYPES +#define COMMON_INT_TYPES + +/** \defgroup common_inttypes Integer types + * Specified-width integer type definitions for shorter and nicer code. + * + * These should be used in preference to unspecified width types such as + * `int` which can lead to portability issues between different platforms. + * \{ */ + +/** Signed 8-bit integer. */ +typedef int8_t s8; +/** Signed 16-bit integer. */ +typedef int16_t s16; +/** Signed 32-bit integer. */ +typedef int32_t s32; +/** Signed 64-bit integer. */ +typedef int64_t s64; +/** Unsigned 8-bit integer. */ +typedef uint8_t u8; +/** Unsigned 16-bit integer. */ +typedef uint16_t u16; +/** Unsigned 32-bit integer. */ +typedef uint32_t u32; +/** Unsigned 64-bit integer. */ +typedef uint64_t u64; + +#endif + +/** \} */ + +/** \} */ + +#endif /* LIBSWIFTNAV_COMMON_H */ diff --git a/src/algorithms/telemetry_decoder/libs/libswiftcnav/viterbi27.c b/src/algorithms/telemetry_decoder/libs/libswiftcnav/viterbi27.c new file mode 100644 index 000000000..9739c2ab3 --- /dev/null +++ b/src/algorithms/telemetry_decoder/libs/libswiftcnav/viterbi27.c @@ -0,0 +1,252 @@ +/*! + * \file viterbi27.c + * \author Phil Karn, KA9Q + * \brief K=7 r=1/2 Viterbi decoder in portable C + * + * ------------------------------------------------------------------------- + * This file was originally borrowed from libswiftnav + * , + * a portable C library implementing GNSS related functions and algorithms, + * and then modified by J. Arribas and C. Fernandez + * + * Copyright (C) 2004, Phil Karn, KA9Q + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3. + * + * 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 + * Lesser General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#include +#include "fec.h" + +static inline int parity(int x) +{ + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x &= 0xf; + return (0x6996 >> x) & 1; +} + + +/** Initialize a v27_poly_t struct for use with a v27_t decoder. + * + * \param poly Structure to initialize. + * \param polynomial Byte array representing the desired polynomials. + */ +void v27_poly_init(v27_poly_t *poly, const signed char polynomial[2]) +{ + int state; + + for(state = 0; state < 32; state++) + { + poly->c0[state] = (polynomial[0] < 0) ^ parity((2*state) & abs(polynomial[0])) ? 255 : 0; + poly->c1[state] = (polynomial[1] < 0) ^ parity((2*state) & abs(polynomial[1])) ? 255 : 0; + } +} + + +/** Initialize a v27_t struct for Viterbi decoding. + * + * \param v Structure to initialize + * \param decisions Array of v27_decision_t structs, capacity = decisions_count. + * Must remain valid as long as v is used. + * \param decisions_count Size of decisions array. Equal to the number of bit + * decisions kept in history. + * \param poly Struct describing the polynomials to use. Must remain valid as + * long as v is used. May be shared between multiple decoders. + * \param initial_state Initial state of the decoder shift register. Usually zero. + */ +void v27_init(v27_t *v, v27_decision_t *decisions, unsigned int decisions_count, + const v27_poly_t *poly, unsigned char initial_state) +{ + int i; + + v->old_metrics = v->metrics1; + v->new_metrics = v->metrics2; + v->poly = poly; + v->decisions = decisions; + v->decisions_index = 0; + v->decisions_count = decisions_count; + + for(i = 0; i < 64; i++) + v->old_metrics[i] = 63; + + v->old_metrics[initial_state & 63] = 0; /* Bias known start state */ +} + + +/* C-language butterfly */ +#define BFLY(i) {\ + unsigned int metric,m0,m1,decision;\ + metric = (v->poly->c0[i] ^ sym0) + (v->poly->c1[i] ^ sym1);\ + m0 = v->old_metrics[i] + metric;\ + m1 = v->old_metrics[(i)+32] + (510 - metric);\ + decision = (signed int)(m0-m1) > 0;\ + v->new_metrics[2*(i)] = decision ? m1 : m0;\ + d->w[(i)/16] |= decision << ((2*(i))&31);\ + m0 -= (metric+metric-510);\ + m1 += (metric+metric-510);\ + decision = (signed int)(m0-m1) > 0;\ + v->new_metrics[2*(i)+1] = decision ? m1 : m0;\ + d->w[(i)/16] |= decision << ((2*(i)+1)&31);\ +} + +/** Update a v27_t decoder with a block of symbols. + * + * \param v Structure to update. + * \param syms Array of symbols to use. Must contain two symbols per bit. + * 0xff = strong 1, 0x00 = strong 0. + * \param nbits Number of bits corresponding to the provided symbols. + */ +void v27_update(v27_t *v, const unsigned char *syms, int nbits) +{ + unsigned char sym0, sym1; + unsigned int *tmp; + int normalize = 0; + + while(nbits--) + { + v27_decision_t *d = &v->decisions[v->decisions_index]; + + d->w[0] = d->w[1] = 0; + sym0 = *syms++; + sym1 = *syms++; + + BFLY(0); + BFLY(1); + BFLY(2); + BFLY(3); + BFLY(4); + BFLY(5); + BFLY(6); + BFLY(7); + BFLY(8); + BFLY(9); + BFLY(10); + BFLY(11); + BFLY(12); + BFLY(13); + BFLY(14); + BFLY(15); + BFLY(16); + BFLY(17); + BFLY(18); + BFLY(19); + BFLY(20); + BFLY(21); + BFLY(22); + BFLY(23); + BFLY(24); + BFLY(25); + BFLY(26); + BFLY(27); + BFLY(28); + BFLY(29); + BFLY(30); + BFLY(31); + + /* Normalize metrics if they are nearing overflow */ + if(v->new_metrics[0] > (1 << 30)) + { + int i; + unsigned int minmetric = 1 << 31; + + for(i = 0; i < 64; i++) + { + if(v->new_metrics[i] < minmetric) + minmetric = v->new_metrics[i]; + } + + for(i = 0; i < 64; i++) + v->new_metrics[i] -= minmetric; + + normalize += minmetric; + } + + /* Advance decision index */ + if(++v->decisions_index >= v->decisions_count) + v->decisions_index = 0; + + /* Swap pointers to old and new metrics */ + tmp = v->old_metrics; + v->old_metrics = v->new_metrics; + v->new_metrics = tmp; + } +} + + +/** Retrieve the most likely output bit sequence with known final state from + * a v27_t decoder. + * + * \param v Structure to use. + * \param data Array used to store output bits, capacity = nbits. + * \param nbits Number of bits to retrieve. + * \param final_state Known final state of the decoder shift register. + */ +void v27_chainback_fixed(v27_t *v, unsigned char *data, unsigned int nbits, + unsigned char final_state) +{ + int k; + unsigned int decisions_index = v->decisions_index; + + final_state %= 64; + final_state <<= 2; + + while(nbits-- != 0) + { + + /* Decrement decision index */ + decisions_index = (decisions_index == 0) ? + v->decisions_count-1 : decisions_index-1; + + v27_decision_t *d = &v->decisions[decisions_index]; + k = (d->w[(final_state >> 2) / 32] >> ((final_state >> 2) % 32)) & 1; + /* The store into data[] only needs to be done every 8 bits. + * But this avoids a conditional branch, and the writes will + * combine in the cache anyway + */ + data[nbits >> 3] = final_state = (final_state >> 1) | (k << 7); + } +} + + +/** Retrieve the most likely output bit sequence with unknown final state from + * a v27_t decoder. + * + * \param v Structure to use. + * \param data Array used to store output bits, capacity = nbits. + * \param nbits Number of bits to retrieve. + */ +void v27_chainback_likely(v27_t *v, unsigned char *data, unsigned int nbits) +{ + /* Determine state with minimum metric */ + + int i; + unsigned int best_metric = 0xffffffff; + unsigned char best_state = 0; + for(i = 0; i < 64; i++) + { + if(v->new_metrics[i] < best_metric) + { + best_metric = v->new_metrics[i]; + best_state = i; + } + } + + v27_chainback_fixed(v, data, nbits, best_state); +} diff --git a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc index 1fbcb558b..957efa9a6 100644 --- a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc +++ b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,33 +24,32 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "viterbi_decoder.h" -#include #include // logging -#define EVENT 2 // logs important events which don't occur every block -#define FLOW 3 // logs the function calls of block processing functions -#define BLOCK 4 // once per block -#define SAMPLE 5 // about one log entry per sample -#define LMORE 6 // many entries per sample / very specific stuff +#define EVENT 2 // logs important events which don't occur every block +#define FLOW 3 // logs the function calls of block processing functions +#define BLOCK 4 // once per block +#define SAMPLE 5 // about one log entry per sample +#define LMORE 6 // many entries per sample / very specific stuff -const float MAXLOG = 1e7; /* Define infinity */ +const float MAXLOG = 1e7; /* Define infinity */ Viterbi_Decoder::Viterbi_Decoder(const int g_encoder[], const int KK, const int nn) { - d_nn = nn; // Coding rate 1/n - d_KK = KK; // Constraint Length + d_nn = nn; // Coding rate 1/n + d_KK = KK; // Constraint Length // derived code properties d_mm = d_KK - 1; - d_states = 1 << d_mm; /* 2^mm */ + d_states = 1 << d_mm; /* 2^mm */ d_number_symbols = 1 << d_nn; /* 2^nn */ /* create appropriate transition matrices (trellis) */ @@ -83,15 +82,12 @@ Viterbi_Decoder::~Viterbi_Decoder() } - void Viterbi_Decoder::reset() { init_trellis_state(); } - - /* Function decode_block() Description: Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code. Input parameters: @@ -114,7 +110,7 @@ float Viterbi_Decoder::decode_block(const double input_c[], int output_u_int[], // tail, no need to output -> traceback, but don't decode state = do_traceback(d_mm); // traceback and decode - decoding_length_mismatch = do_tb_and_decode(d_mm, LL, state, output_u_int, d_indicator_metric); + decoding_length_mismatch = do_tb_and_decode(d_mm, LL, state, output_u_int, d_indicator_metric); VLOG(FLOW) << "decoding length mismatch: " << decoding_length_mismatch; @@ -122,12 +118,11 @@ float Viterbi_Decoder::decode_block(const double input_c[], int output_u_int[], } - float Viterbi_Decoder::decode_continuous(const double sym[], - const int traceback_depth, - int bits[], - const int nbits_requested, - int &nbits_decoded) + const int traceback_depth, + int bits[], + const int nbits_requested, + int& nbits_decoded) { int state; int decoding_length_mismatch; @@ -140,7 +135,7 @@ float Viterbi_Decoder::decode_continuous(const double sym[], // since it depends on the future values -> traceback, but don't decode state = do_traceback(traceback_depth); // traceback and decode - decoding_length_mismatch = do_tb_and_decode(traceback_depth, nbits_requested, state, bits, d_indicator_metric); + decoding_length_mismatch = do_tb_and_decode(traceback_depth, nbits_requested, state, bits, d_indicator_metric); nbits_decoded = nbits_requested + decoding_length_mismatch; VLOG(FLOW) << "decoding length mismatch (continuous decoding): " << decoding_length_mismatch; @@ -149,12 +144,11 @@ float Viterbi_Decoder::decode_continuous(const double sym[], } - void Viterbi_Decoder::init_trellis_state() { int state; // if trellis state has been initialised, free old state memory - if(d_trellis_state_is_initialised) + if (d_trellis_state_is_initialised) { // init trellis state delete[] d_pm_t; @@ -181,14 +175,12 @@ void Viterbi_Decoder::init_trellis_state() } - - int Viterbi_Decoder::do_acs(const double sym[], int nbits) { int t, i, state_at_t; float metric; float max_val; - float * pm_t_next = new float[d_states]; + auto* pm_t_next = new float[d_states]; /* t: * - state: state at t @@ -217,7 +209,7 @@ int Viterbi_Decoder::do_acs(const double sym[], int nbits) } // find the survivor branches leading the trellis states at t+1 - Prev next_trellis_states(d_states, t+1); + Prev next_trellis_states(d_states, t + 1); /* step through all states */ for (state_at_t = 0; state_at_t < d_states; state_at_t++) { @@ -226,7 +218,7 @@ int Viterbi_Decoder::do_acs(const double sym[], int nbits) /* hypothesis: info bit is a zero */ int bm_0 = d_metric_c[d_out0[state_at_t]]; - metric = d_pm_t[state_at_t] + bm_0; // path metric + zerobranch metric + metric = d_pm_t[state_at_t] + bm_0; // path metric + zerobranch metric /* store new metric if more than metric in storage */ if (metric > pm_t_next[next_state_if_0]) @@ -239,7 +231,7 @@ int Viterbi_Decoder::do_acs(const double sym[], int nbits) /* hypothesis: info bit is a one */ int bm_1 = d_metric_c[d_out1[state_at_t]]; - metric = d_pm_t[state_at_t] + bm_1; // path metric + onebranch metric + metric = d_pm_t[state_at_t] + bm_1; // path metric + onebranch metric /* store new metric if more than metric in storage */ if (metric > pm_t_next[next_state_if_1]) @@ -277,7 +269,6 @@ int Viterbi_Decoder::do_acs(const double sym[], int nbits) } - int Viterbi_Decoder::do_traceback(size_t traceback_length) { // traceback_length is in bits @@ -291,7 +282,7 @@ int Viterbi_Decoder::do_traceback(size_t traceback_length) traceback_length = d_trellis_paths.size(); } - state = 0; // maybe start not at state 0, but at state with best metric + state = 0; // maybe start not at state 0, but at state with best metric for (it = d_trellis_paths.begin(); it < d_trellis_paths.begin() + traceback_length; ++it) { state = it->get_anchestor_state_of_current_state(state); @@ -300,8 +291,6 @@ int Viterbi_Decoder::do_traceback(size_t traceback_length) } - - int Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decoding_length, int state, int output_u_int[], float& indicator_metric) { int n_of_branches_for_indicator_metric = 500; @@ -319,15 +308,15 @@ int Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decodi VLOG(BLOCK) << "overstep_length=" << overstep_length; for (it = d_trellis_paths.begin() + traceback_length; - it < d_trellis_paths.begin() + traceback_length + overstep_length; ++it) + it < d_trellis_paths.begin() + traceback_length + overstep_length; ++it) { state = it->get_anchestor_state_of_current_state(state); } - t_out = d_trellis_paths.end() - (d_trellis_paths.begin() + traceback_length + overstep_length) - 1;//requested_decoding_length-1; + t_out = d_trellis_paths.end() - (d_trellis_paths.begin() + traceback_length + overstep_length) - 1; //requested_decoding_length-1; indicator_metric = 0; for (it = d_trellis_paths.begin() + traceback_length + overstep_length; it < d_trellis_paths.end(); ++it) { - if(it - (d_trellis_paths.begin() + traceback_length + overstep_length) < n_of_branches_for_indicator_metric) + if (it - (d_trellis_paths.begin() + traceback_length + overstep_length) < n_of_branches_for_indicator_metric) { n_im++; indicator_metric += it->get_metric_of_current_state(state); @@ -337,7 +326,7 @@ int Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decodi state = it->get_anchestor_state_of_current_state(state); t_out--; } - if(n_im > 0) + if (n_im > 0) { indicator_metric /= n_im; } @@ -346,14 +335,12 @@ int Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decodi // remove old states if (d_trellis_paths.begin() + traceback_length + overstep_length <= d_trellis_paths.end()) { - - d_trellis_paths.erase(d_trellis_paths.begin() + traceback_length+overstep_length, d_trellis_paths.end()); + d_trellis_paths.erase(d_trellis_paths.begin() + traceback_length + overstep_length, d_trellis_paths.end()); } return decoding_length_mismatch; } - /* function Gamma() Description: Computes the branch metric used for decoding. @@ -367,8 +354,7 @@ int Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decodi nn The length of the received vector This function is used by siso() */ -float -Viterbi_Decoder::gamma(float rec_array[], int symbol, int nn) +float Viterbi_Decoder::gamma(const float rec_array[], int symbol, int nn) { float rm = 0; int i; @@ -389,9 +375,8 @@ Viterbi_Decoder::gamma(float rec_array[], int symbol, int nn) } /* function that creates the transit and output vectors */ -void -Viterbi_Decoder::nsc_transit(int output_p[], int trans_p[], int input, const int g[], - int KK, int nn) +void Viterbi_Decoder::nsc_transit(int output_p[], int trans_p[], int input, const int g[], + int KK, int nn) { int nextstate[1]; int state, states; @@ -426,7 +411,7 @@ Viterbi_Decoder::nsc_transit(int output_p[], int trans_p[], int input, const int This function is used by rsc_encode(), nsc_transit(), rsc_transit(), and nsc_transit() */ int Viterbi_Decoder::nsc_enc_bit(int state_out_p[], int input, int state_in, - const int g[], int KK, int nn) + const int g[], int KK, int nn) { /* declare variables */ int state, i; @@ -473,7 +458,6 @@ int Viterbi_Decoder::parity_counter(int symbol, int length) } - // prev helper class Viterbi_Decoder::Prev::Prev(int states, int t) { @@ -490,7 +474,6 @@ Viterbi_Decoder::Prev::Prev(int states, int t) } - // copy constructor Viterbi_Decoder::Prev::Prev(const Prev& prev) { @@ -501,30 +484,32 @@ Viterbi_Decoder::Prev::Prev(const Prev& prev) num_states = prev.num_states; bit = prev.bit; metric = prev.metric; - VLOG(LMORE) << "Prev(" << "?" << ", " << t << ")" << " copy, new refcount = " << *refcount; + VLOG(LMORE) << "Prev(" + << "?" + << ", " << t << ")" + << " copy, new refcount = " << *refcount; } - // assignment constructor Viterbi_Decoder::Prev& Viterbi_Decoder::Prev::operator=(const Prev& other) { // check for self-assignment - if(&other == this) + if (&other == this) { return *this; } // handle old resources - if(*refcount == 1) - { // if they are not used anymore -> unallocate them + if (*refcount == 1) + { // if they are not used anymore -> unallocate them delete[] state; delete[] bit; delete[] metric; delete refcount; } else - { // this object is not anymore using them + { // this object is not anymore using them (*refcount)--; } @@ -538,13 +523,14 @@ Viterbi_Decoder::Prev& Viterbi_Decoder::Prev::operator=(const Prev& other) bit = other.bit; metric = other.metric; - VLOG(LMORE) << "Prev(" << "?" << ", " << t << ")" << " assignment, new refcount = " << *refcount; + VLOG(LMORE) << "Prev(" + << "?" + << ", " << t << ")" + << " assignment, new refcount = " << *refcount; return *this; } - - Viterbi_Decoder::Prev::~Prev() { if (*refcount == 1) @@ -558,12 +544,14 @@ Viterbi_Decoder::Prev::~Prev() else { (*refcount)--; - VLOG(LMORE) << "~Prev(" << "?" << ", " << t << ")" << " destructor after copy, new refcount = " << *refcount; + VLOG(LMORE) << "~Prev(" + << "?" + << ", " << t << ")" + << " destructor after copy, new refcount = " << *refcount; } } - int Viterbi_Decoder::Prev::get_anchestor_state_of_current_state(int current_state) { //std::cout << "get prev state: for state " << current_state << " at time " << t << ", the prev state at time " << t-1 << " is " << state[current_state] << std::endl; @@ -571,16 +559,12 @@ int Viterbi_Decoder::Prev::get_anchestor_state_of_current_state(int current_stat { return state[current_state]; } - else - { - //std::cout<<"alarm "<<"num_states="<. + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,8 +32,8 @@ #ifndef GNSS_SDR_VITERBI_DECODER_H_ #define GNSS_SDR_VITERBI_DECODER_H_ +#include // for size_t #include -#include /*! * \brief Class that implements a Viterbi decoder @@ -56,7 +56,7 @@ public: float decode_block(const double input_c[], int* output_u_int, const int LL); float decode_continuous(const double sym[], const int traceback_depth, int output_u_int[], - const int nbits_requested, int &nbits_decoded); + const int nbits_requested, int& nbits_decoded); private: class Prev @@ -78,10 +78,10 @@ private: private: int t; - int * state; - int * bit; - float * metric; - int * refcount; + int* state; + int* bit; + float* metric; + int* refcount; }; // code properties @@ -100,10 +100,10 @@ private: int* d_state1; // trellis state - float *d_pm_t; + float* d_pm_t; std::deque d_trellis_paths; - float *d_metric_c; /* Set of all possible branch metrics */ - float *d_rec_array; /* Received values for one trellis section */ + float* d_metric_c; /* Set of all possible branch metrics */ + float* d_rec_array; /* Received values for one trellis section */ bool d_trellis_state_is_initialised; // measures @@ -112,11 +112,11 @@ private: // operations on the trellis (change decoder state) void init_trellis_state(); int do_acs(const double sym[], int nbits); - int do_traceback(size_t traceback_length); + int do_traceback(std::size_t traceback_length); int do_tb_and_decode(int traceback_length, int requested_decoding_length, int state, int bits[], float& indicator_metric); // branch metric function - float gamma(float rec_array[], int symbol, int nn); + float gamma(const float rec_array[], int symbol, int nn); // trellis generation void nsc_transit(int output_p[], int trans_p[], int input, const int g[], int KK, int nn); diff --git a/src/algorithms/tracking/CMakeLists.txt b/src/algorithms/tracking/CMakeLists.txt index ec514fac4..ea74d8ec3 100644 --- a/src/algorithms/tracking/CMakeLists.txt +++ b/src/algorithms/tracking/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(adapters) diff --git a/src/algorithms/tracking/adapters/CMakeLists.txt b/src/algorithms/tracking/adapters/CMakeLists.txt index 275d5151d..5150aa400 100644 --- a/src/algorithms/tracking/adapters/CMakeLists.txt +++ b/src/algorithms/tracking/adapters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,42 +13,106 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # + if(ENABLE_CUDA) - set(OPT_TRACKING_ADAPTERS ${OPT_TRACKING_ADAPTERS} gps_l1_ca_dll_pll_tracking_gpu.cc) - set(OPT_TRACKING_INCLUDE_DIRS ${OPT_TRACKING_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS}) -endif(ENABLE_CUDA) + set(OPT_TRACKING_ADAPTERS_SOURCES + ${OPT_TRACKING_ADAPTERS_SOURCES} + gps_l1_ca_dll_pll_tracking_gpu.cc + ) + set(OPT_TRACKING_ADAPTERS_HEADERS + ${OPT_TRACKING_ADAPTERS_HEADERS} + gps_l1_ca_dll_pll_tracking_gpu.h + ) + set(OPT_TRACKING_INCLUDE_DIRS + ${OPT_TRACKING_INCLUDE_DIRS} + ${CUDA_INCLUDE_DIRS} + ) +endif() -set(TRACKING_ADAPTER_SOURCES - galileo_e1_dll_pll_veml_tracking.cc - galileo_e1_tcp_connector_tracking.cc - gps_l1_ca_dll_pll_tracking.cc - gps_l1_ca_dll_pll_c_aid_tracking.cc - gps_l1_ca_tcp_connector_tracking.cc - galileo_e5a_dll_pll_tracking.cc - gps_l2_m_dll_pll_tracking.cc - ${OPT_TRACKING_ADAPTERS} +if(ENABLE_FPGA) + set(OPT_TRACKING_ADAPTERS_SOURCES + ${OPT_TRACKING_ADAPTERS_SOURCES} + gps_l1_ca_dll_pll_tracking_fpga.cc + gps_l2_m_dll_pll_tracking_fpga.cc + galileo_e1_dll_pll_veml_tracking_fpga.cc + galileo_e5a_dll_pll_tracking_fpga.cc + gps_l5_dll_pll_tracking_fpga.cc + ) + set(OPT_TRACKING_ADAPTERS_HEADERS + ${OPT_TRACKING_ADAPTERS_HEADERS} + gps_l1_ca_dll_pll_tracking_fpga.h + gps_l2_m_dll_pll_tracking_fpga.h + galileo_e1_dll_pll_veml_tracking_fpga.h + galileo_e5a_dll_pll_tracking_fpga.h + gps_l5_dll_pll_tracking_fpga.h + ) +endif() + +set(TRACKING_ADAPTER_SOURCES + galileo_e1_dll_pll_veml_tracking.cc + galileo_e1_tcp_connector_tracking.cc + gps_l1_ca_dll_pll_tracking.cc + gps_l1_ca_dll_pll_c_aid_tracking.cc + gps_l1_ca_tcp_connector_tracking.cc + galileo_e5a_dll_pll_tracking.cc + gps_l2_m_dll_pll_tracking.cc + glonass_l1_ca_dll_pll_tracking.cc + glonass_l1_ca_dll_pll_c_aid_tracking.cc + gps_l1_ca_kf_tracking.cc + gps_l5_dll_pll_tracking.cc + glonass_l2_ca_dll_pll_tracking.cc + glonass_l2_ca_dll_pll_c_aid_tracking.cc + ${OPT_TRACKING_ADAPTERS_SOURCES} ) - + +set(TRACKING_ADAPTER_HEADERS + galileo_e1_dll_pll_veml_tracking.h + galileo_e1_tcp_connector_tracking.h + gps_l1_ca_dll_pll_tracking.h + gps_l1_ca_dll_pll_c_aid_tracking.h + gps_l1_ca_tcp_connector_tracking.h + galileo_e5a_dll_pll_tracking.h + gps_l2_m_dll_pll_tracking.h + glonass_l1_ca_dll_pll_tracking.h + glonass_l1_ca_dll_pll_c_aid_tracking.h + gps_l1_ca_kf_tracking.h + gps_l5_dll_pll_tracking.h + glonass_l2_ca_dll_pll_tracking.h + glonass_l2_ca_dll_pll_c_aid_tracking.h + ${OPT_TRACKING_ADAPTERS_HEADERS} +) + include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} - ${OPT_TRACKING_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${ARMADILLO_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${OPT_TRACKING_INCLUDE_DIRS} ) -file(GLOB TRACKING_ADAPTER_HEADERS "*.h") list(SORT TRACKING_ADAPTER_HEADERS) -add_library(tracking_adapters ${TRACKING_ADAPTER_SOURCES} ${TRACKING_ADAPTER_HEADERS}) +list(SORT TRACKING_ADAPTER_SOURCES) + +add_library(tracking_adapters + ${TRACKING_ADAPTER_SOURCES} + ${TRACKING_ADAPTER_HEADERS} +) + source_group(Headers FILES ${TRACKING_ADAPTER_HEADERS}) -target_link_libraries(tracking_adapters tracking_gr_blocks gnss_sp_libs) + +target_link_libraries(tracking_adapters + tracking_gr_blocks + gnss_sp_libs + gnss_sdr_flags +) diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc old mode 100755 new mode 100644 index ce9613e24..3bb059dc2 --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,66 +29,111 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_dll_pll_veml_tracking.h" -#include #include "Galileo_E1.h" #include "configuration_interface.h" +#include "display.h" +#include "dll_pll_conf.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; + GalileoE1DllPllVemlTracking::GalileoE1DllPllVemlTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { + Dll_Pll_Conf trk_param = Dll_Pll_Conf(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - int fs_in; - int vector_length; - int f_if; - bool dump; - std::string dump_filename; - std::string item_type; std::string default_item_type = "gr_complex"; - float pll_bw_hz; - float dll_bw_hz; - float early_late_space_chips; - float very_early_late_space_chips; - - item_type = configuration->property(role + ".item_type", default_item_type); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); - dump = configuration->property(role + ".dump", false); - pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); - dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); - early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15); - very_early_late_space_chips = configuration->property(role + ".very_early_late_space_chips", 0.6); - + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param.dump = dump; std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", - default_dump_filename); //unused! - vector_length = std::round(fs_in / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param.dump_mat = dump_mat; + trk_param.high_dyn = configuration->property(role + ".high_dyn", false); + if (configuration->property(role + ".smoother_length", 10) < 1) + { + trk_param.smoother_length = 1; + std::cout << TEXT_RED << "WARNING: Gal. E1. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl; + } + else + { + trk_param.smoother_length = configuration->property(role + ".smoother_length", 10); + } + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 5.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 0.5); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0); + trk_param.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25); + trk_param.dll_bw_narrow_hz = dll_bw_narrow_hz; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15); + trk_param.early_late_space_chips = early_late_space_chips; + float very_early_late_space_chips = configuration->property(role + ".very_early_late_space_chips", 0.6); + trk_param.very_early_late_space_chips = very_early_late_space_chips; + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param.early_late_space_narrow_chips = early_late_space_narrow_chips; + float very_early_late_space_narrow_chips = configuration->property(role + ".very_early_late_space_narrow_chips", 0.6); + trk_param.very_early_late_space_narrow_chips = very_early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E1. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (4 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E1. Extended coherent integration is not allowed when tracking the data component. Coherent integration has been set to 4 ms (1 symbol)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: Galileo E1. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param.track_pilot = track_pilot; + trk_param.extend_correlation_symbols = extend_correlation_symbols; + int vector_length = std::round(fs_in / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); + trk_param.vector_length = vector_length; + trk_param.system = 'E'; + char sig_[3] = "1B"; + std::memcpy(trk_param.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param.carrier_lock_th = carrier_lock_th; //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); - tracking_ = galileo_e1_dll_pll_veml_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips, - very_early_late_space_chips); + tracking_ = dll_pll_veml_make_tracking(trk_param); } else { @@ -97,18 +142,32 @@ GalileoE1DllPllVemlTracking::GalileoE1DllPllVemlTracking( } channel_ = 0; - DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GalileoE1DllPllVemlTracking::~GalileoE1DllPllVemlTracking() = default; + + +void GalileoE1DllPllVemlTracking::stop_tracking() +{ } -GalileoE1DllPllVemlTracking::~GalileoE1DllPllVemlTracking() -{} void GalileoE1DllPllVemlTracking::start_tracking() { tracking_->start_tracking(); } + /* * Set tracking channel unique ID */ @@ -124,25 +183,32 @@ void GalileoE1DllPllVemlTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) tracking_->set_gnss_synchro(p_gnss_synchro); } + void GalileoE1DllPllVemlTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } + void GalileoE1DllPllVemlTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } + gr::basic_block_sptr GalileoE1DllPllVemlTracking::get_left_block() { return tracking_; } + gr::basic_block_sptr GalileoE1DllPllVemlTracking::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.h b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.h old mode 100755 new mode 100644 index 874044b7b..035daf48e --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.h +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.h @@ -7,11 +7,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,10 +37,9 @@ #ifndef GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_H_ #define GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_H_ - -#include +#include "dll_pll_veml_tracking.h" #include "tracking_interface.h" -#include "galileo_e1_dll_pll_veml_tracking_cc.h" +#include class ConfigurationInterface; @@ -53,50 +52,53 @@ class GalileoE1DllPllVemlTracking : public TrackingInterface { public: GalileoE1DllPllVemlTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1DllPllVemlTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "Galileo_E1_DLL_PLL_VEML_Tracking" - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_DLL_PLL_VEML_Tracking"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: - galileo_e1_dll_pll_veml_tracking_cc_sptr tracking_; + dll_pll_veml_tracking_sptr tracking_; size_t item_size_; unsigned int channel_; std::string role_; @@ -104,4 +106,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_H_ +#endif // GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc new file mode 100644 index 000000000..31d2cbfff --- /dev/null +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc @@ -0,0 +1,271 @@ +/*! + * \file galileo_e1_dll_pll_veml_tracking.cc + * \brief Adapts a DLL+PLL VEML (Very Early Minus Late) tracking loop block + * to a TrackingInterface for Galileo E1 signals + * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_e1_dll_pll_veml_tracking_fpga.h" +#include "Galileo_E1.h" +#include "configuration_interface.h" +#include "display.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include + +//#define NUM_PRNs_GALILEO_E1 50 + +using google::LogMessage; + +void GalileoE1DllPllVemlTrackingFpga::stop_tracking() +{ +} + +GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + //dllpllconf_t trk_param; + Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + std::string default_item_type = "gr_complex"; + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param_fpga.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param_fpga.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param_fpga.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param_fpga.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 5.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param_fpga.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 0.5); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param_fpga.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0); + trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25); + trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15); + trk_param_fpga.early_late_space_chips = early_late_space_chips; + float very_early_late_space_chips = configuration->property(role + ".very_early_late_space_chips", 0.6); + trk_param_fpga.very_early_late_space_chips = very_early_late_space_chips; + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; + float very_early_late_space_narrow_chips = configuration->property(role + ".very_early_late_space_narrow_chips", 0.6); + trk_param_fpga.very_early_late_space_narrow_chips = very_early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E1. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (4 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E1. Extended coherent integration is not allowed when tracking the data component. Coherent integration has been set to 4 ms (1 symbol)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: Galileo E1. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param_fpga.track_pilot = track_pilot; + d_track_pilot = track_pilot; + trk_param_fpga.extend_correlation_symbols = extend_correlation_symbols; + int vector_length = std::round(fs_in / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); + trk_param_fpga.vector_length = vector_length; + trk_param_fpga.system = 'E'; + char sig_[3] = "1B"; + std::memcpy(trk_param_fpga.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param_fpga.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param_fpga.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param_fpga.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param_fpga.carrier_lock_th = carrier_lock_th; + + // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + trk_param_fpga.device_name = device_name; + unsigned int device_base = configuration->property(role + ".device_base", 1); + trk_param_fpga.device_base = device_base; + //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 1); + trk_param_fpga.multicorr_type = 1; // 0 -> 3 correlators, 1 -> 5 correlators + + //################# PRE-COMPUTE ALL THE CODES ################# + unsigned int code_samples_per_chip = 2; + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * Galileo_E1_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + float* ca_codes_f; + float* data_codes_f; + + if (trk_param_fpga.track_pilot) + { + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * Galileo_E1_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + } + ca_codes_f = static_cast(volk_gnsssdr_malloc(static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); + + if (trk_param_fpga.track_pilot) + { + data_codes_f = static_cast(volk_gnsssdr_malloc((static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); + } + + //printf("pppppppp trk_param_fpga.track_pilot = %d\n", trk_param_fpga.track_pilot); + + //int kk; + + for (unsigned int PRN = 1; PRN <= Galileo_E1_NUMBER_OF_CODES; PRN++) + { + char data_signal[3] = "1B"; + if (trk_param_fpga.track_pilot) + { + //printf("yes tracking pilot !!!!!!!!!!!!!!!\n"); + char pilot_signal[3] = "1C"; + galileo_e1_code_gen_sinboc11_float(ca_codes_f, pilot_signal, PRN); + galileo_e1_code_gen_sinboc11_float(data_codes_f, data_signal, PRN); + + for (unsigned int s = 0; s < 2 * Galileo_E1_B_CODE_LENGTH_CHIPS; s++) + { + d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); + d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(data_codes_f[s]); + //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + //printf("\n next \n"); + //scanf ("%d",&kk); + } + else + { + //printf("no tracking pilot\n"); + galileo_e1_code_gen_sinboc11_float(ca_codes_f, data_signal, PRN); + + for (unsigned int s = 0; s < 2 * Galileo_E1_B_CODE_LENGTH_CHIPS; s++) + { + d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); + //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + //printf("\n next \n"); + //scanf ("%d",&kk); + } + } + + delete[] ca_codes_f; + if (trk_param_fpga.track_pilot) + { + delete[] data_codes_f; + } + trk_param_fpga.ca_codes = d_ca_codes; + trk_param_fpga.data_codes = d_data_codes; + trk_param_fpga.code_length_chips = Galileo_E1_B_CODE_LENGTH_CHIPS; + trk_param_fpga.code_samples_per_chip = code_samples_per_chip; // 2 sample per chip + //################# MAKE TRACKING GNURadio object ################### + tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + + +GalileoE1DllPllVemlTrackingFpga::~GalileoE1DllPllVemlTrackingFpga() +{ + delete[] d_ca_codes; + if (d_track_pilot) + { + delete[] d_data_codes; + } +} + +void GalileoE1DllPllVemlTrackingFpga::start_tracking() +{ + //tracking_->start_tracking(); + tracking_fpga_sc->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GalileoE1DllPllVemlTrackingFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + //tracking_->set_channel(channel); + tracking_fpga_sc->set_channel(channel); +} + + +void GalileoE1DllPllVemlTrackingFpga::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + //tracking_->set_gnss_synchro(p_gnss_synchro); + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + + +void GalileoE1DllPllVemlTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GalileoE1DllPllVemlTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GalileoE1DllPllVemlTrackingFpga::get_left_block() +{ + //return tracking_; + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GalileoE1DllPllVemlTrackingFpga::get_right_block() +{ + //return tracking_; + return tracking_fpga_sc; +} diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h new file mode 100644 index 000000000..794aa22d4 --- /dev/null +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h @@ -0,0 +1,116 @@ +/*! + * \file galileo_e1_dll_pll_veml_tracking.h + * \brief Adapts a DLL+PLL VEML (Very Early Minus Late) tracking loop block + * to a TrackingInterface for Galileo E1 signals + * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_FPGA_H_ +#define GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_FPGA_H_ + +#include "dll_pll_veml_tracking_fpga.h" +#include "tracking_interface.h" +#include + + +class ConfigurationInterface; + +/*! + * \brief This class Adapts a DLL+PLL VEML (Very Early Minus Late) tracking + * loop block to a TrackingInterface for Galileo E1 signals + */ +class GalileoE1DllPllVemlTrackingFpga : public TrackingInterface +{ +public: + GalileoE1DllPllVemlTrackingFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GalileoE1DllPllVemlTrackingFpga(); + + inline std::string role() override + { + return role_; + } + + //! Returns "Galileo_E1_DLL_PLL_VEML_Tracking" + inline std::string implementation() override + { + return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and + * tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + + +private: + //dll_pll_veml_tracking_sptr tracking_; + dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + int* d_ca_codes; + int* d_data_codes; + bool d_track_pilot; +}; + + +#endif // GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc index 1f8cd2744..70fdd98a2 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,29 +30,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_tcp_connector_tracking.h" -#include #include "Galileo_E1.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include +#include using google::LogMessage; + GalileoE1TcpConnectorTracking::GalileoE1TcpConnectorTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) { DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## int fs_in; int vector_length; - int f_if; bool dump; std::string dump_filename; std::string item_type; @@ -62,34 +63,35 @@ GalileoE1TcpConnectorTracking::GalileoE1TcpConnectorTracking( float early_late_space_chips; float very_early_late_space_chips; size_t port_ch0; - item_type = configuration->property(role + ".item_type",default_item_type); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); + item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump = configuration->property(role + ".dump", false); pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15); very_early_late_space_chips = configuration->property(role + ".very_early_late_space_chips", 0.6); port_ch0 = configuration->property(role + ".port_ch0", 2060); std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); //unused! + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); vector_length = std::round(fs_in / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)); //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); tracking_ = galileo_e1_tcp_connector_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips, - very_early_late_space_chips, - port_ch0); + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + early_late_space_chips, + very_early_late_space_chips, + port_ch0); } else { @@ -98,11 +100,23 @@ GalileoE1TcpConnectorTracking::GalileoE1TcpConnectorTracking( } channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GalileoE1TcpConnectorTracking::~GalileoE1TcpConnectorTracking() -{} +GalileoE1TcpConnectorTracking::~GalileoE1TcpConnectorTracking() = default; + + +void GalileoE1TcpConnectorTracking::stop_tracking() +{ +} void GalileoE1TcpConnectorTracking::start_tracking() @@ -127,13 +141,17 @@ void GalileoE1TcpConnectorTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchr void GalileoE1TcpConnectorTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } void GalileoE1TcpConnectorTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -146,4 +164,3 @@ gr::basic_block_sptr GalileoE1TcpConnectorTracking::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.h b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.h index c4e0c3e6a..ff68056f7 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.h +++ b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -39,9 +39,9 @@ #ifndef GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_H_ #define GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_H_ -#include -#include "tracking_interface.h" #include "galileo_e1_tcp_connector_tracking_cc.h" +#include "tracking_interface.h" +#include class ConfigurationInterface; @@ -53,47 +53,50 @@ class GalileoE1TcpConnectorTracking : public TrackingInterface { public: GalileoE1TcpConnectorTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE1TcpConnectorTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "Galileo_E1_TCP_CONNECTOR_Tracking" - std::string implementation() + inline std::string implementation() override { return "Galileo_E1_TCP_CONNECTOR_Tracking"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and * tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: galileo_e1_tcp_connector_tracking_cc_sptr tracking_; @@ -104,4 +107,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_H_ +#endif // GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc index c90d9814e..b0e0a0730 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,72 +31,107 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #include "galileo_e5a_dll_pll_tracking.h" -#include #include "Galileo_E5a.h" #include "configuration_interface.h" - +#include "display.h" +#include "dll_pll_conf.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; + GalileoE5aDllPllTracking::GalileoE5aDllPllTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { + Dll_Pll_Conf trk_param = Dll_Pll_Conf(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - int fs_in; - int vector_length; - int f_if; - bool dump; - std::string dump_filename; - std::string item_type; std::string default_item_type = "gr_complex"; - float pll_bw_hz; - float dll_bw_hz; - float pll_bw_init_hz; - float dll_bw_init_hz; - int ti_ms; - float early_late_space_chips; - item_type = configuration->property(role + ".item_type", default_item_type); - //vector_length = configuration->property(role + ".vector_length", 2048); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 12000000); - f_if = configuration->property(role + ".if", 0); - dump = configuration->property(role + ".dump", false); - pll_bw_hz = configuration->property(role + ".pll_bw_hz", 5.0); - dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); - pll_bw_init_hz = configuration->property(role + ".pll_bw_init_hz", 20.0); - dll_bw_init_hz = configuration->property(role + ".dll_bw_init_hz", 20.0); - ti_ms = configuration->property(role + ".ti_ms", 3); - - early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12000000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param.dump = dump; std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", - default_dump_filename); //unused! - vector_length = std::round(fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS)); + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param.dump_mat = dump_mat; + trk_param.high_dyn = configuration->property(role + ".high_dyn", false); + if (configuration->property(role + ".smoother_length", 10) < 1) + { + trk_param.smoother_length = 1; + std::cout << TEXT_RED << "WARNING: Gal. E5a. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl; + } + else + { + trk_param.smoother_length = configuration->property(role + ".smoother_length", 10); + } + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 20.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 20.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 5.0); + trk_param.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + trk_param.dll_bw_narrow_hz = dll_bw_narrow_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param.early_late_space_chips = early_late_space_chips; + int vector_length = std::round(fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS)); + trk_param.vector_length = vector_length; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param.early_late_space_narrow_chips = early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E5a. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > Galileo_E5a_I_SECONDARY_CODE_LENGTH) + { + extend_correlation_symbols = Galileo_E5a_I_SECONDARY_CODE_LENGTH; + std::cout << TEXT_RED << "WARNING: Galileo E5a. extend_correlation_symbols must be lower than 21 when tracking the data component. Coherent integration has been set to 20 symbols (20 ms)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: Galileo E5a. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param.extend_correlation_symbols = extend_correlation_symbols; + trk_param.track_pilot = track_pilot; + trk_param.very_early_late_space_chips = 0.0; + trk_param.very_early_late_space_narrow_chips = 0.0; + trk_param.system = 'E'; + char sig_[3] = "5X"; + std::memcpy(trk_param.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param.carrier_lock_th = carrier_lock_th; //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); - tracking_ = galileo_e5a_dll_pll_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - pll_bw_init_hz, - dll_bw_init_hz, - ti_ms, - early_late_space_chips); + tracking_ = dll_pll_veml_make_tracking(trk_param); } else { @@ -105,11 +140,23 @@ GalileoE5aDllPllTracking::GalileoE5aDllPllTracking( } channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GalileoE5aDllPllTracking::~GalileoE5aDllPllTracking() -{} +GalileoE5aDllPllTracking::~GalileoE5aDllPllTracking() = default; + + +void GalileoE5aDllPllTracking::stop_tracking() +{ +} void GalileoE5aDllPllTracking::start_tracking() @@ -117,6 +164,7 @@ void GalileoE5aDllPllTracking::start_tracking() tracking_->start_tracking(); } + /* * Set tracking channel unique ID */ @@ -132,26 +180,32 @@ void GalileoE5aDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) tracking_->set_gnss_synchro(p_gnss_synchro); } + void GalileoE5aDllPllTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } + void GalileoE5aDllPllTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } + gr::basic_block_sptr GalileoE5aDllPllTracking::get_left_block() { return tracking_; } + gr::basic_block_sptr GalileoE5aDllPllTracking::get_right_block() { return tracking_; } - - diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.h b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.h index b9b46780a..1aefcf2cf 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.h +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -39,10 +39,9 @@ #ifndef GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_H_ #define GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_H_ -#include +#include "dll_pll_veml_tracking.h" #include "tracking_interface.h" -#include "galileo_e5a_dll_pll_tracking_cc.h" - +#include class ConfigurationInterface; @@ -53,48 +52,52 @@ class GalileoE5aDllPllTracking : public TrackingInterface { public: GalileoE5aDllPllTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GalileoE5aDllPllTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "Galileo_E5a_DLL_PLL_Tracking" - std::string implementation() + inline std::string implementation() override { return "Galileo_E5a_DLL_PLL_Tracking"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: - galileo_e5a_dll_pll_tracking_cc_sptr tracking_; + dll_pll_veml_tracking_sptr tracking_; size_t item_size_; unsigned int channel_; std::string role_; diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc new file mode 100644 index 000000000..1a5e1cf09 --- /dev/null +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc @@ -0,0 +1,288 @@ +/*! + * \file galileo_e5a_dll_pll_tracking.cc + * \brief Adapts a code DLL + carrier PLL + * tracking block to a TrackingInterface for Galileo E5a signals + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Marc Sales, 2014. marcsales92(at)gmail.com + * \based on work from: + *
        + *
      • Javier Arribas, 2011. jarribas(at)cttc.es + *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
      + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_e5a_dll_pll_tracking_fpga.h" +#include "Galileo_E5a.h" +#include "configuration_interface.h" +#include "display.h" +#include "galileo_e5_signal_processing.h" +#include "gnss_sdr_flags.h" +#include + +using google::LogMessage; + +void GalileoE5aDllPllTrackingFpga::stop_tracking() +{ +} + +GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga( + ConfigurationInterface *configuration, const std::string &role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + //printf("creating the E5A tracking"); + + + Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + std::string default_item_type = "gr_complex"; + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12000000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param_fpga.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param_fpga.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param_fpga.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param_fpga.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 20.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param_fpga.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 20.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param_fpga.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 5.0); + trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param_fpga.early_late_space_chips = early_late_space_chips; + int vector_length = std::round(fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS)); + trk_param_fpga.vector_length = vector_length; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + d_track_pilot = track_pilot; + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: Galileo E5a. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > Galileo_E5a_I_SECONDARY_CODE_LENGTH) + { + extend_correlation_symbols = Galileo_E5a_I_SECONDARY_CODE_LENGTH; + std::cout << TEXT_RED << "WARNING: Galileo E5a. extend_correlation_symbols must be lower than 21 when tracking the data component. Coherent integration has been set to 20 symbols (20 ms)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: Galileo E5a. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param_fpga.extend_correlation_symbols = extend_correlation_symbols; + trk_param_fpga.track_pilot = track_pilot; + trk_param_fpga.very_early_late_space_chips = 0.0; + trk_param_fpga.very_early_late_space_narrow_chips = 0.0; + trk_param_fpga.system = 'E'; + char sig_[3] = "5X"; + std::memcpy(trk_param_fpga.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param_fpga.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param_fpga.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param_fpga.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param_fpga.carrier_lock_th = carrier_lock_th; + + // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + trk_param_fpga.device_name = device_name; + unsigned int device_base = configuration->property(role + ".device_base", 1); + trk_param_fpga.device_base = device_base; + //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 1); + trk_param_fpga.multicorr_type = 1; // 0 -> 3 correlators, 1 -> up to 5+1 correlators + + //################# PRE-COMPUTE ALL THE CODES ################# + unsigned int code_samples_per_chip = 1; + auto code_length_chips = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); + + auto *aux_code = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex) * code_length_chips * code_samples_per_chip, volk_gnsssdr_get_alignment())); + + float *tracking_code; + float *data_code; + + if (trk_param_fpga.track_pilot) + { + data_code = static_cast(volk_gnsssdr_malloc(code_samples_per_chip * code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + } + tracking_code = static_cast(volk_gnsssdr_malloc(code_samples_per_chip * code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips) * code_samples_per_chip * Galileo_E5a_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + + if (trk_param_fpga.track_pilot) + { + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * code_samples_per_chip * Galileo_E5a_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + } + + + for (unsigned int PRN = 1; PRN <= Galileo_E5a_NUMBER_OF_CODES; PRN++) + { + //galileo_e5_a_code_gen_complex_primary(aux_code, PRN, const_cast(trk_param_fpga.signal.c_str())); + galileo_e5_a_code_gen_complex_primary(aux_code, PRN, const_cast(sig_)); + if (trk_param_fpga.track_pilot) + { + //d_secondary_code_string = const_cast(&Galileo_E5a_Q_SECONDARY_CODE[PRN - 1]); + for (unsigned int i = 0; i < code_length_chips; i++) + { + tracking_code[i] = aux_code[i].imag(); + data_code[i] = aux_code[i].real(); + } + for (unsigned int s = 0; s < code_length_chips; s++) + { + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); + d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); + //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + } + else + { + for (unsigned int i = 0; i < code_length_chips; i++) + { + tracking_code[i] = aux_code[i].real(); + } + + for (unsigned int s = 0; s < code_length_chips; s++) + { + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); + //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + } + } + + volk_gnsssdr_free(aux_code); + volk_gnsssdr_free(tracking_code); + if (trk_param_fpga.track_pilot) + { + volk_gnsssdr_free(data_code); + } + trk_param_fpga.ca_codes = d_ca_codes; + trk_param_fpga.data_codes = d_data_codes; + trk_param_fpga.code_length_chips = code_length_chips; + trk_param_fpga.code_samples_per_chip = code_samples_per_chip; // 2 sample per chip + //################# MAKE TRACKING GNURadio object ################### + tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); + // if (item_type.compare("gr_complex") == 0) + // { + // item_size_ = sizeof(gr_complex); + // tracking_ = dll_pll_veml_make_tracking(trk_param_fpga); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // LOG(WARNING) << item_type << " unknown tracking item type."; + // } + channel_ = 0; + + //DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + + +GalileoE5aDllPllTrackingFpga::~GalileoE5aDllPllTrackingFpga() +{ + delete[] d_ca_codes; + if (d_track_pilot) + { + delete[] d_data_codes; + } +} + + +void GalileoE5aDllPllTrackingFpga::start_tracking() +{ + //tracking_->start_tracking(); + tracking_fpga_sc->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GalileoE5aDllPllTrackingFpga::set_channel(unsigned int channel) +{ + //printf("blabla channel = %d\n", channel); + channel_ = channel; + //tracking_->set_channel(channel); + tracking_fpga_sc->set_channel(channel); +} + + +void GalileoE5aDllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + //tracking_->set_gnss_synchro(p_gnss_synchro); + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + + +void GalileoE5aDllPllTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GalileoE5aDllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GalileoE5aDllPllTrackingFpga::get_left_block() +{ + //return tracking_; + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GalileoE5aDllPllTrackingFpga::get_right_block() +{ + //return tracking_; + return tracking_fpga_sc; +} diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h new file mode 100644 index 000000000..49c52de5e --- /dev/null +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h @@ -0,0 +1,113 @@ +/*! + * \file galileo_e5a_dll_pll_tracking.h + * \brief Adapts a code DLL + carrier PLL + * tracking block to a TrackingInterface for Galileo E5a signals + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for + * Galileo E5a data and pilot Signals + * \author Marc Sales, 2014. marcsales92(at)gmail.com + * \based on work from: + *
        + *
      • Javier Arribas, 2011. jarribas(at)cttc.es + *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
      + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_FPGA_H_ +#define GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_FPGA_H_ + +#include "dll_pll_veml_tracking_fpga.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GalileoE5aDllPllTrackingFpga : public TrackingInterface +{ +public: + GalileoE5aDllPllTrackingFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GalileoE5aDllPllTrackingFpga(); + + inline std::string role() override + { + return role_; + } + + //! Returns "Galileo_E5a_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "Galileo_E5a_DLL_PLL_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + + + int* d_ca_codes; + int* d_data_codes; + bool d_track_pilot; +}; + +#endif /* GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_FPGA_H_ */ diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc new file mode 100644 index 000000000..30101a0ff --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc @@ -0,0 +1,246 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L1 C/A to a TrackingInterface + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_dll_pll_c_aid_tracking.h" +#include "GLONASS_L1_L2_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GlonassL1CaDllPllCAidTracking::GlonassL1CaDllPllCAidTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int fs_in; + int vector_length; + bool dump; + std::string dump_filename; + std::string default_item_type = "gr_complex"; + float pll_bw_hz; + float pll_bw_narrow_hz; + float dll_bw_hz; + float dll_bw_narrow_hz; + float early_late_space_chips; + item_type_ = configuration->property(role + ".item_type", default_item_type); + //vector_length = configuration->property(role + ".vector_length", 2048); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + dump = configuration->property(role + ".dump", false); + pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); + dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + int extend_correlation_ms; + extend_correlation_ms = configuration->property(role + ".extend_correlation_ms", 1); + + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + vector_length = std::round(fs_in / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS)); + + //################# MAKE TRACKING GNURadio object ################### + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_cc = glonass_l1_ca_dll_pll_c_aid_make_tracking_cc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); + DLOG(INFO) << "tracking(" << tracking_cc->unique_id() << ")"; + } + else if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + tracking_sc = glonass_l1_ca_dll_pll_c_aid_make_tracking_sc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); + DLOG(INFO) << "tracking(" << tracking_sc->unique_id() << ")"; + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type_ << " unknown tracking item type."; + } + channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL1CaDllPllCAidTracking::~GlonassL1CaDllPllCAidTracking() = default; + + +void GlonassL1CaDllPllCAidTracking::stop_tracking() +{ +} + + +void GlonassL1CaDllPllCAidTracking::start_tracking() +{ + if (item_type_ == "gr_complex") + { + tracking_cc->start_tracking(); + } + else if (item_type_ == "cshort") + { + tracking_sc->start_tracking(); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +/* + * Set tracking channel unique ID + */ +void GlonassL1CaDllPllCAidTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + + if (item_type_ == "gr_complex") + { + tracking_cc->set_channel(channel); + } + else if (item_type_ == "cshort") + { + tracking_sc->set_channel(channel); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +void GlonassL1CaDllPllCAidTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + if (item_type_ == "gr_complex") + { + tracking_cc->set_gnss_synchro(p_gnss_synchro); + } + else if (item_type_ == "cshort") + { + tracking_sc->set_gnss_synchro(p_gnss_synchro); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +void GlonassL1CaDllPllCAidTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GlonassL1CaDllPllCAidTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GlonassL1CaDllPllCAidTracking::get_left_block() +{ + if (item_type_ == "gr_complex") + { + return tracking_cc; + } + if (item_type_ == "cshort") + { + return tracking_sc; + } + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; +} + + +gr::basic_block_sptr GlonassL1CaDllPllCAidTracking::get_right_block() +{ + if (item_type_ == "gr_complex") + { + return tracking_cc; + } + if (item_type_ == "cshort") + { + return tracking_sc; + } + + + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; +} diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.h b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.h new file mode 100644 index 000000000..d50003964 --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.h @@ -0,0 +1,112 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L1 C/A to a TrackingInterface + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ +#define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ + +#include "glonass_l1_ca_dll_pll_c_aid_tracking_cc.h" +#include "glonass_l1_ca_dll_pll_c_aid_tracking_sc.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GlonassL1CaDllPllCAidTracking : public TrackingInterface +{ +public: + GlonassL1CaDllPllCAidTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL1CaDllPllCAidTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking" + inline std::string implementation() override + { + return "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr tracking_cc; + glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr tracking_sc; + size_t item_size_; + std::string item_type_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc new file mode 100644 index 000000000..a96165d47 --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc @@ -0,0 +1,165 @@ +/*! + * \file glonass_l1_ca_dll_pll_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L1 C/A to a TrackingInterface + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_dll_pll_tracking.h" +#include "GLONASS_L1_L2_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GlonassL1CaDllPllTracking::GlonassL1CaDllPllTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int fs_in; + int vector_length; + bool dump; + std::string dump_filename; + std::string item_type; + std::string default_item_type = "gr_complex"; + float pll_bw_hz; + float dll_bw_hz; + float early_late_space_chips; + item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + dump = configuration->property(role + ".dump", false); + pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + vector_length = std::round(fs_in / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS)); + + //################# MAKE TRACKING GNURadio object ################### + if (item_type == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_ = glonass_l1_ca_dll_pll_make_tracking_cc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + early_late_space_chips); + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type << " unknown tracking item type."; + } + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL1CaDllPllTracking::~GlonassL1CaDllPllTracking() = default; + + +void GlonassL1CaDllPllTracking::stop_tracking() +{ +} + + +void GlonassL1CaDllPllTracking::start_tracking() +{ + tracking_->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GlonassL1CaDllPllTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_->set_channel(channel); +} + + +void GlonassL1CaDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_->set_gnss_synchro(p_gnss_synchro); +} + + +void GlonassL1CaDllPllTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GlonassL1CaDllPllTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GlonassL1CaDllPllTracking::get_left_block() +{ + return tracking_; +} + + +gr::basic_block_sptr GlonassL1CaDllPllTracking::get_right_block() +{ + return tracking_; +} diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h new file mode 100644 index 000000000..cd8482113 --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h @@ -0,0 +1,108 @@ +/*! + * \file glonass_l1_ca_dll_pll_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L1 C/A to a TrackingInterface + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H_ +#define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H_ + +#include "glonass_l1_ca_dll_pll_tracking_cc.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GlonassL1CaDllPllTracking : public TrackingInterface +{ +public: + GlonassL1CaDllPllTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL1CaDllPllTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L1_CA_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "GLONASS_L1_CA_DLL_PLL_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + glonass_l1_ca_dll_pll_tracking_cc_sptr tracking_; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc new file mode 100644 index 000000000..4ddff7163 --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc @@ -0,0 +1,242 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L2 C/A to a TrackingInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_dll_pll_c_aid_tracking.h" +#include "GLONASS_L1_L2_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GlonassL2CaDllPllCAidTracking::GlonassL2CaDllPllCAidTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int fs_in; + int vector_length; + bool dump; + std::string dump_filename; + std::string default_item_type = "gr_complex"; + float pll_bw_hz; + float pll_bw_narrow_hz; + float dll_bw_hz; + float dll_bw_narrow_hz; + float early_late_space_chips; + item_type_ = configuration->property(role + ".item_type", default_item_type); + //vector_length = configuration->property(role + ".vector_length", 2048); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + dump = configuration->property(role + ".dump", false); + pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); + dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + int extend_correlation_ms; + extend_correlation_ms = configuration->property(role + ".extend_correlation_ms", 1); + + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + vector_length = std::round(fs_in / (GLONASS_L2_CA_CODE_RATE_HZ / GLONASS_L2_CA_CODE_LENGTH_CHIPS)); + + //################# MAKE TRACKING GNURadio object ################### + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_cc = glonass_l2_ca_dll_pll_c_aid_make_tracking_cc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); + DLOG(INFO) << "tracking(" << tracking_cc->unique_id() << ")"; + } + else if (item_type_ == "cshort") + { + item_size_ = sizeof(lv_16sc_t); + tracking_sc = glonass_l2_ca_dll_pll_c_aid_make_tracking_sc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); + DLOG(INFO) << "tracking(" << tracking_sc->unique_id() << ")"; + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type_ << " unknown tracking item type."; + } + channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL2CaDllPllCAidTracking::~GlonassL2CaDllPllCAidTracking() = default; + + +void GlonassL2CaDllPllCAidTracking::stop_tracking() +{ +} + + +void GlonassL2CaDllPllCAidTracking::start_tracking() +{ + if (item_type_ == "gr_complex") + { + tracking_cc->start_tracking(); + } + else if (item_type_ == "cshort") + { + tracking_sc->start_tracking(); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +/* + * Set tracking channel unique ID + */ +void GlonassL2CaDllPllCAidTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + + if (item_type_ == "gr_complex") + { + tracking_cc->set_channel(channel); + } + else if (item_type_ == "cshort") + { + tracking_sc->set_channel(channel); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +void GlonassL2CaDllPllCAidTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + if (item_type_ == "gr_complex") + { + tracking_cc->set_gnss_synchro(p_gnss_synchro); + } + else if (item_type_ == "cshort") + { + tracking_sc->set_gnss_synchro(p_gnss_synchro); + } + else + { + LOG(WARNING) << item_type_ << " unknown tracking item type"; + } +} + + +void GlonassL2CaDllPllCAidTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GlonassL2CaDllPllCAidTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GlonassL2CaDllPllCAidTracking::get_left_block() +{ + if (item_type_ == "gr_complex") + { + return tracking_cc; + } + if (item_type_ == "cshort") + { + return tracking_sc; + } + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; +} + + +gr::basic_block_sptr GlonassL2CaDllPllCAidTracking::get_right_block() +{ + if (item_type_ == "gr_complex") + { + return tracking_cc; + } + if (item_type_ == "cshort") + { + return tracking_sc; + } + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; +} diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.h b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.h new file mode 100644 index 000000000..b5659c527 --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.h @@ -0,0 +1,110 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L2 C/A to a TrackingInterface + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_H_ +#define GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_H_ + +#include "glonass_l2_ca_dll_pll_c_aid_tracking_cc.h" +#include "glonass_l2_ca_dll_pll_c_aid_tracking_sc.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GlonassL2CaDllPllCAidTracking : public TrackingInterface +{ +public: + GlonassL2CaDllPllCAidTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL2CaDllPllCAidTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L2_CA_DLL_PLL_C_Aid_Tracking" + inline std::string implementation() override + { + return "GLONASS_L2_CA_DLL_PLL_C_Aid_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr tracking_cc; + glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr tracking_sc; + size_t item_size_; + std::string item_type_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc new file mode 100644 index 000000000..3c39300af --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc @@ -0,0 +1,163 @@ +/*! + * \file glonass_l2_ca_dll_pll_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L2 C/A to a TrackingInterface + * \author Damian Miralles, 2018, dmiralles2009(at)gmail.com * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_dll_pll_tracking.h" +#include "GLONASS_L1_L2_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GlonassL2CaDllPllTracking::GlonassL2CaDllPllTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int fs_in; + int vector_length; + bool dump; + std::string dump_filename; + std::string item_type; + std::string default_item_type = "gr_complex"; + float pll_bw_hz; + float dll_bw_hz; + float early_late_space_chips; + item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + dump = configuration->property(role + ".dump", false); + pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + vector_length = std::round(fs_in / (GLONASS_L2_CA_CODE_RATE_HZ / GLONASS_L2_CA_CODE_LENGTH_CHIPS)); + + //################# MAKE TRACKING GNURadio object ################### + if (item_type == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_ = glonass_l2_ca_dll_pll_make_tracking_cc( + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + early_late_space_chips); + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type << " unknown tracking item type."; + } + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GlonassL2CaDllPllTracking::~GlonassL2CaDllPllTracking() = default; + + +void GlonassL2CaDllPllTracking::stop_tracking() +{ +} + + +void GlonassL2CaDllPllTracking::start_tracking() +{ + tracking_->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GlonassL2CaDllPllTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_->set_channel(channel); +} + + +void GlonassL2CaDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_->set_gnss_synchro(p_gnss_synchro); +} + + +void GlonassL2CaDllPllTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GlonassL2CaDllPllTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GlonassL2CaDllPllTracking::get_left_block() +{ + return tracking_; +} + + +gr::basic_block_sptr GlonassL2CaDllPllTracking::get_right_block() +{ + return tracking_; +} diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.h b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.h new file mode 100644 index 000000000..1ca41a94b --- /dev/null +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.h @@ -0,0 +1,107 @@ +/*! + * \file glonass_l2_ca_dll_pll_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for Glonass L2 C/A to a TrackingInterface + * \author Damian Miralles, 2018, dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_H_ +#define GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_H_ + +#include "glonass_l2_ca_dll_pll_tracking_cc.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GlonassL2CaDllPllTracking : public TrackingInterface +{ +public: + GlonassL2CaDllPllTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL2CaDllPllTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GLONASS_L1_CA_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "GLONASS_L2_CA_DLL_PLL_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + glonass_l2_ca_dll_pll_tracking_cc_sptr tracking_; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.cc index c294de3fc..899e878e2 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,30 +30,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_dll_pll_c_aid_tracking.h" -#include #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; + GpsL1CaDllPllCAidTracking::GpsL1CaDllPllCAidTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## int fs_in; int vector_length; - int f_if; bool dump; std::string dump_filename; std::string default_item_type = "gr_complex"; @@ -64,11 +64,13 @@ GpsL1CaDllPllCAidTracking::GpsL1CaDllPllCAidTracking( float early_late_space_chips; item_type_ = configuration->property(role + ".item_type", default_item_type); //vector_length = configuration->property(role + ".vector_length", 2048); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump = configuration->property(role + ".dump", false); pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); int extend_correlation_ms; @@ -76,43 +78,40 @@ GpsL1CaDllPllCAidTracking::GpsL1CaDllPllCAidTracking( early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", - default_dump_filename); //unused! + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); //################# MAKE TRACKING GNURadio object ################### - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { item_size_ = sizeof(gr_complex); tracking_cc = gps_l1_ca_dll_pll_c_aid_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - pll_bw_narrow_hz, - dll_bw_narrow_hz, - extend_correlation_ms, - early_late_space_chips); + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); DLOG(INFO) << "tracking(" << tracking_cc->unique_id() << ")"; } - else if(item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { item_size_ = sizeof(lv_16sc_t); tracking_sc = gps_l1_ca_dll_pll_c_aid_make_tracking_sc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - pll_bw_narrow_hz, - dll_bw_narrow_hz, - extend_correlation_ms, - early_late_space_chips); + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + pll_bw_narrow_hz, + dll_bw_narrow_hz, + extend_correlation_ms, + early_late_space_chips); DLOG(INFO) << "tracking(" << tracking_sc->unique_id() << ")"; } else @@ -121,21 +120,32 @@ GpsL1CaDllPllCAidTracking::GpsL1CaDllPllCAidTracking( LOG(WARNING) << item_type_ << " unknown tracking item type."; } channel_ = 0; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL1CaDllPllCAidTracking::~GpsL1CaDllPllCAidTracking() -{} +GpsL1CaDllPllCAidTracking::~GpsL1CaDllPllCAidTracking() = default; + + +void GpsL1CaDllPllCAidTracking::stop_tracking() +{ +} void GpsL1CaDllPllCAidTracking::start_tracking() { - - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { tracking_cc->start_tracking(); } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { tracking_sc->start_tracking(); } @@ -152,11 +162,11 @@ void GpsL1CaDllPllCAidTracking::set_channel(unsigned int channel) { channel_ = channel; - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { tracking_cc->set_channel(channel); } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { tracking_sc->set_channel(channel); } @@ -168,11 +178,11 @@ void GpsL1CaDllPllCAidTracking::set_channel(unsigned int channel) void GpsL1CaDllPllCAidTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { tracking_cc->set_gnss_synchro(p_gnss_synchro); } - else if (item_type_.compare("cshort") == 0) + else if (item_type_ == "cshort") { tracking_sc->set_gnss_synchro(p_gnss_synchro); } @@ -184,46 +194,44 @@ void GpsL1CaDllPllCAidTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) void GpsL1CaDllPllCAidTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } void GpsL1CaDllPllCAidTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } gr::basic_block_sptr GpsL1CaDllPllCAidTracking::get_left_block() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return tracking_cc; } - else if (item_type_.compare("cshort") == 0) + if (item_type_ == "cshort") { return tracking_sc; } - else - { - LOG(WARNING) << item_type_ << " unknown tracking item type"; - return nullptr; - } + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; } gr::basic_block_sptr GpsL1CaDllPllCAidTracking::get_right_block() { - if (item_type_.compare("gr_complex") == 0) + if (item_type_ == "gr_complex") { return tracking_cc; } - else if (item_type_.compare("cshort") == 0) + if (item_type_ == "cshort") { return tracking_sc; } - else - { - LOG(WARNING) << item_type_ << " unknown tracking item type"; - return nullptr; - } + LOG(WARNING) << item_type_ << " unknown tracking item type"; + return nullptr; } diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.h index f8c395b24..a1c54aa46 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking.h @@ -8,11 +8,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,10 +38,10 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ #define GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ -#include -#include "tracking_interface.h" #include "gps_l1_ca_dll_pll_c_aid_tracking_cc.h" #include "gps_l1_ca_dll_pll_c_aid_tracking_sc.h" +#include "tracking_interface.h" +#include class ConfigurationInterface; @@ -52,48 +52,50 @@ class ConfigurationInterface; class GpsL1CaDllPllCAidTracking : public TrackingInterface { public: - - GpsL1CaDllPllCAidTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + GpsL1CaDllPllCAidTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaDllPllCAidTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "GPS_L1_CA_DLL_PLL_C_Aid_Tracking" - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_DLL_PLL_C_Aid_Tracking"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr tracking_cc; @@ -106,4 +108,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ +#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc index 2ab0a35c0..394574667 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,61 +30,112 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #include "gps_l1_ca_dll_pll_tracking.h" -#include #include "GPS_L1_CA.h" #include "configuration_interface.h" - +#include "display.h" +#include "dll_pll_conf.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; + GpsL1CaDllPllTracking::GpsL1CaDllPllTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { + Dll_Pll_Conf trk_param = Dll_Pll_Conf(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - int fs_in; - int vector_length; - int f_if; - bool dump; - std::string dump_filename; - std::string item_type; std::string default_item_type = "gr_complex"; - float pll_bw_hz; - float dll_bw_hz; - float early_late_space_chips; - item_type = configuration->property(role + ".item_type", default_item_type); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); - dump = configuration->property(role + ".dump", false); - pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); - dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); - early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param.fs_in = fs_in; + trk_param.high_dyn = configuration->property(role + ".high_dyn", false); + if (configuration->property(role + ".smoother_length", 10) < 1) + { + trk_param.smoother_length = 1; + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl; + } + else + { + trk_param.smoother_length = configuration->property(role + ".smoother_length", 10); + } + bool dump = configuration->property(role + ".dump", false); + trk_param.dump = dump; std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); //unused! - vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param.pll_bw_hz = pll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); + trk_param.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + trk_param.dll_bw_narrow_hz = dll_bw_narrow_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param.dll_bw_hz = dll_bw_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param.early_late_space_chips = early_late_space_chips; + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.5); + trk_param.early_late_space_narrow_chips = early_late_space_narrow_chips; + int vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + trk_param.vector_length = vector_length; + int symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); + if (symbols_extended_correlator < 1) + { + symbols_extended_correlator = 1; + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. extend_correlation_symbols must be bigger than 1. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (symbols_extended_correlator > 20) + { + symbols_extended_correlator = 20; + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. extend_correlation_symbols must be lower than 21. Coherent integration has been set to 20 symbols (20 ms)" << TEXT_RESET << std::endl; + } + trk_param.extend_correlation_symbols = symbols_extended_correlator; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (track_pilot) + { + std::cout << TEXT_RED << "WARNING: GPS L1 C/A does not have pilot signal. Data tracking has been enabled" << TEXT_RESET << std::endl; + } + if ((symbols_extended_correlator > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param.very_early_late_space_chips = 0.0; + trk_param.very_early_late_space_narrow_chips = 0.0; + trk_param.track_pilot = false; + trk_param.system = 'G'; + char sig_[3] = "1C"; + std::memcpy(trk_param.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 30); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.80); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param.carrier_lock_th = carrier_lock_th; //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); - tracking_ = gps_l1_ca_dll_pll_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips); + tracking_ = dll_pll_veml_make_tracking(trk_param); } else { @@ -93,11 +144,24 @@ GpsL1CaDllPllTracking::GpsL1CaDllPllTracking( } channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL1CaDllPllTracking::~GpsL1CaDllPllTracking() -{} +GpsL1CaDllPllTracking::~GpsL1CaDllPllTracking() = default; + + +void GpsL1CaDllPllTracking::stop_tracking() +{ + tracking_->stop_tracking(); +} void GpsL1CaDllPllTracking::start_tracking() @@ -124,14 +188,18 @@ void GpsL1CaDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) void GpsL1CaDllPllTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } void GpsL1CaDllPllTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -146,4 +214,3 @@ gr::basic_block_sptr GpsL1CaDllPllTracking::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.h index 3f6594944..288de9ae0 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.h @@ -8,11 +8,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,10 +38,9 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_H_ #define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_H_ -#include +#include "dll_pll_veml_tracking.h" #include "tracking_interface.h" -#include "gps_l1_ca_dll_pll_tracking_cc.h" - +#include class ConfigurationInterface; @@ -52,48 +51,53 @@ class GpsL1CaDllPllTracking : public TrackingInterface { public: GpsL1CaDllPllTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaDllPllTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "GPS_L1_CA_DLL_PLL_Tracking" - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_DLL_PLL_Tracking"; } - size_t item_size() + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - void start_tracking(); + void start_tracking() override; + + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: - gps_l1_ca_dll_pll_tracking_cc_sptr tracking_; + dll_pll_veml_tracking_sptr tracking_; size_t item_size_; unsigned int channel_; std::string role_; @@ -101,4 +105,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_H_ +#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc new file mode 100644 index 000000000..e81e7a905 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc @@ -0,0 +1,207 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking_fpga.cc + * \brief Implementation of an adapter of a DLL+PLL tracking loop block + * for GPS L1 C/A to a TrackingInterface that uses the FPGA + * \author Marc Majoral, 2018, mmajoral(at)cttc.es + * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l1_ca_dll_pll_tracking_fpga.h" +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include "display.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include + +#define NUM_PRNs 32 + +using google::LogMessage; + +void GpsL1CaDllPllTrackingFpga::stop_tracking() +{ +} + +GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); + DLOG(INFO) << "role " << role; + + //################# CONFIGURATION PARAMETERS ######################## + //std::string default_item_type = "gr_complex"; + //std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param_fpga.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param_fpga.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param_fpga.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param_fpga.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param_fpga.pll_bw_hz = pll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); + trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); + trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param_fpga.dll_bw_hz = dll_bw_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param_fpga.early_late_space_chips = early_late_space_chips; + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.5); + trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; + int vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + trk_param_fpga.vector_length = vector_length; + int symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); + if (symbols_extended_correlator < 1) + { + symbols_extended_correlator = 1; + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. extend_correlation_symbols must be bigger than 1. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (symbols_extended_correlator > 20) + { + symbols_extended_correlator = 20; + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. extend_correlation_symbols must be lower than 21. Coherent integration has been set to 20 symbols (20 ms)" << TEXT_RESET << std::endl; + } + trk_param_fpga.extend_correlation_symbols = symbols_extended_correlator; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (track_pilot) + { + std::cout << TEXT_RED << "WARNING: GPS L1 C/A does not have pilot signal. Data tracking has been enabled" << TEXT_RESET << std::endl; + } + if ((symbols_extended_correlator > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: GPS L1 C/A. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param_fpga.very_early_late_space_chips = 0.0; + trk_param_fpga.very_early_late_space_narrow_chips = 0.0; + trk_param_fpga.track_pilot = false; + trk_param_fpga.system = 'G'; + char sig_[3] = "1C"; + std::memcpy(trk_param_fpga.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param_fpga.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param_fpga.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param_fpga.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param_fpga.carrier_lock_th = carrier_lock_th; + + // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + trk_param_fpga.device_name = device_name; + unsigned int device_base = configuration->property(role + ".device_base", 1); + trk_param_fpga.device_base = device_base; + //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 0); + trk_param_fpga.multicorr_type = 0; //multicorr_type : 0 -> 3 correlators, 1 -> 5 correlators + + //################# PRE-COMPUTE ALL THE CODES ################# + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + gps_l1_ca_code_gen_int(&d_ca_codes[(int(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0); + } + trk_param_fpga.ca_codes = d_ca_codes; + trk_param_fpga.code_length_chips = GPS_L1_CA_CODE_LENGTH_CHIPS; + trk_param_fpga.code_samples_per_chip = 1; // 1 sample per chip + + //################# MAKE TRACKING GNURadio object ################### + tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + +GpsL1CaDllPllTrackingFpga::~GpsL1CaDllPllTrackingFpga() +{ + delete[] d_ca_codes; +} + +void GpsL1CaDllPllTrackingFpga::start_tracking() +{ + tracking_fpga_sc->start_tracking(); +} + +/* + * Set tracking channel unique ID + */ +void GpsL1CaDllPllTrackingFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_fpga_sc->set_channel(channel); +} + +void GpsL1CaDllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + +void GpsL1CaDllPllTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect +} + + +void GpsL1CaDllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect +} + + +gr::basic_block_sptr GpsL1CaDllPllTrackingFpga::get_left_block() +{ + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GpsL1CaDllPllTrackingFpga::get_right_block() +{ + return tracking_fpga_sc; +} diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h new file mode 100644 index 000000000..5cc38f230 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h @@ -0,0 +1,111 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking_fpga.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L1 C/A to a TrackingInterface that uses the FPGA + * \author Marc Majoral, 2018. mmajoral(at)cttc.es + * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ +#define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ + +#include "dll_pll_veml_tracking_fpga.h" +#include "tracking_interface.h" +#include + + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GpsL1CaDllPllTrackingFpga : public TrackingInterface +{ +public: + GpsL1CaDllPllTrackingFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL1CaDllPllTrackingFpga(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L1_CA_DLL_PLL_Tracking_Fpga" + inline std::string implementation() override + { + return "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + int* d_ca_codes; +}; + +#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc index ac36f52ec..848cd2bd6 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,30 +29,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_dll_pll_tracking_gpu.h" -#include #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; +void GpsL1CaDllPllTrackingGPU::stop_tracking() +{ +} + GpsL1CaDllPllTrackingGPU::GpsL1CaDllPllTrackingGPU( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, std::string role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## int fs_in; int vector_length; - int f_if; bool dump; std::string dump_filename; std::string item_type; @@ -62,15 +65,16 @@ GpsL1CaDllPllTrackingGPU::GpsL1CaDllPllTrackingGPU( float early_late_space_chips; item_type = configuration->property(role + ".item_type", default_item_type); //vector_length = configuration->property(role + ".vector_length", 2048); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump = configuration->property(role + ".dump", false); pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", - default_dump_filename); //unused! + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); //################# MAKE TRACKING GNURadio object ################### @@ -78,14 +82,13 @@ GpsL1CaDllPllTrackingGPU::GpsL1CaDllPllTrackingGPU( { item_size_ = sizeof(gr_complex); tracking_ = gps_l1_ca_dll_pll_make_tracking_gpu_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips); + fs_in, + vector_length, + dump, + dump_filename, + pll_bw_hz, + dll_bw_hz, + early_late_space_chips); } else { @@ -94,11 +97,20 @@ GpsL1CaDllPllTrackingGPU::GpsL1CaDllPllTrackingGPU( } channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } GpsL1CaDllPllTrackingGPU::~GpsL1CaDllPllTrackingGPU() -{} +{ +} void GpsL1CaDllPllTrackingGPU::start_tracking() @@ -122,13 +134,17 @@ void GpsL1CaDllPllTrackingGPU::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) void GpsL1CaDllPllTrackingGPU::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } void GpsL1CaDllPllTrackingGPU::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -141,4 +157,3 @@ gr::basic_block_sptr GpsL1CaDllPllTrackingGPU::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.h index 263268946..1a5c381ab 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.h @@ -7,11 +7,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,9 +37,9 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_H_ #define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_H_ -#include -#include "tracking_interface.h" #include "gps_l1_ca_dll_pll_tracking_gpu_cc.h" +#include "tracking_interface.h" +#include class ConfigurationInterface; @@ -50,45 +50,51 @@ class ConfigurationInterface; class GpsL1CaDllPllTrackingGPU : public TrackingInterface { public: - GpsL1CaDllPllTrackingGPU(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + GpsL1CaDllPllTrackingGPU(ConfigurationInterface* configuration, + std::string role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaDllPllTrackingGPU(); - std::string role() + inline std::string role() override { return role_; } //! Returns "GPS_L1_CA_DLL_PLL_Tracking_GPU" - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_DLL_PLL_Tracking_GPU"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - void start_tracking(); + void start_tracking() override; + + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: gps_l1_ca_dll_pll_tracking_gpu_cc_sptr tracking_; @@ -99,4 +105,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_H_ +#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc new file mode 100644 index 000000000..e0960758f --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc @@ -0,0 +1,178 @@ +/*! + * \file gps_l1_ca_kf_tracking.cc + * \brief Implementation of an adapter of a DLL + Kalman carrier + * tracking loop block for GPS L1 C/A signals + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Jordi Vila-Valls 2018. jvila(at)cttc.es + * \author Carles Fernandez-Prades 2018. cfernandez(at)cttc.es + * + * Reference: + * J. Vila-Valls, P. Closas, M. Navarro and C. Fernández-Prades, + * "Are PLLs Dead? A Tutorial on Kalman Filter-based Techniques for Digital + * Carrier Synchronization", IEEE Aerospace and Electronic Systems Magazine, + * Vol. 32, No. 7, pp. 28–45, July 2017. DOI: 10.1109/MAES.2017.150260 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l1_ca_kf_tracking.h" +#include "GPS_L1_CA.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GpsL1CaKfTracking::GpsL1CaKfTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int order; + int fs_in; + int vector_length; + int f_if; + bool dump; + std::string dump_filename; + std::string item_type; + std::string default_item_type = "gr_complex"; + float dll_bw_hz; + float early_late_space_chips; + bool bce_run; + unsigned int bce_ptrans; + unsigned int bce_strans; + int bce_nu; + int bce_kappa; + + item_type = configuration->property(role + ".item_type", default_item_type); + order = configuration->property(role + ".order", 2); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + f_if = configuration->property(role + ".if", 0); + dump = configuration->property(role + ".dump", false); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + + bce_run = configuration->property(role + ".bce_run", false); + bce_ptrans = configuration->property(role + ".p_transient", 0); + bce_strans = configuration->property(role + ".s_transient", 0); + bce_nu = configuration->property(role + ".bce_nu", 0); + bce_kappa = configuration->property(role + ".bce_kappa", 0); + + //################# MAKE TRACKING GNURadio object ################### + if (item_type == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_ = gps_l1_ca_kf_make_tracking_cc( + order, + f_if, + fs_in, + vector_length, + dump, + dump_filename, + dll_bw_hz, + early_late_space_chips, + bce_run, + bce_ptrans, + bce_strans, + bce_nu, + bce_kappa); + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type << " unknown tracking item type."; + } + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; +} + + +GpsL1CaKfTracking::~GpsL1CaKfTracking() = default; + + +void GpsL1CaKfTracking::stop_tracking() +{ +} + + +void GpsL1CaKfTracking::start_tracking() +{ + tracking_->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GpsL1CaKfTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_->set_channel(channel); +} + + +void GpsL1CaKfTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_->set_gnss_synchro(p_gnss_synchro); +} + + +void GpsL1CaKfTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GpsL1CaKfTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GpsL1CaKfTracking::get_left_block() +{ + return tracking_; +} + + +gr::basic_block_sptr GpsL1CaKfTracking::get_right_block() +{ + return tracking_; +} diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.h b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.h new file mode 100644 index 000000000..e26198619 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.h @@ -0,0 +1,110 @@ +/*! + * \file gps_l1_ca_kf_tracking.h + * \brief Interface of an adapter of a DLL + Kalman carrier + * tracking loop block for GPS L1 C/A signals + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Jordi Vila-Valls 2018. jvila(at)cttc.es + * \author Carles Fernandez-Prades 2018. cfernandez(at)cttc.es + * + * Reference: + * J. Vila-Valls, P. Closas, M. Navarro and C. Fernandez-Prades, + * "Are PLLs Dead? A Tutorial on Kalman Filter-based Techniques for Digital + * Carrier Synchronization", IEEE Aerospace and Electronic Systems Magazine, + * Vol. 32, No. 7, pp. 28–45, July 2017. DOI: 10.1109/MAES.2017.150260 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L1_CA_KF_TRACKING_H_ +#define GNSS_SDR_GPS_L1_CA_KF_TRACKING_H_ + +#include "gps_l1_ca_kf_tracking_cc.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GpsL1CaKfTracking : public TrackingInterface +{ +public: + GpsL1CaKfTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL1CaKfTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L1_CA_KF_Tracking" + inline std::string implementation() override + { + return "GPS_L1_CA_KF_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + gps_l1_ca_kf_tracking_cc_sptr tracking_; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GPS_L1_CA_KF_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc index 38a2a0851..3000ac8ae 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,58 +30,57 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_tcp_connector_tracking.h" -#include #include "GPS_L1_CA.h" #include "configuration_interface.h" +#include +#include using google::LogMessage; + GpsL1CaTcpConnectorTracking::GpsL1CaTcpConnectorTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(std::move(role)), in_streams_(in_streams), out_streams_(out_streams) { DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## int fs_in; int vector_length; - int f_if; bool dump; std::string dump_filename; std::string item_type; std::string default_item_type = "gr_complex"; float early_late_space_chips; size_t port_ch0; - item_type = configuration->property(role + ".item_type",default_item_type); + item_type = configuration->property(role + ".item_type", default_item_type); //vector_length = configuration->property(role + ".vector_length", 2048); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); dump = configuration->property(role + ".dump", false); early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); port_ch0 = configuration->property(role + ".port_ch0", 2060); std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); //unused! + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); tracking_ = gps_l1_ca_tcp_connector_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - early_late_space_chips, - port_ch0); + fs_in, + vector_length, + dump, + dump_filename, + early_late_space_chips, + port_ch0); } else { @@ -91,11 +90,23 @@ GpsL1CaTcpConnectorTracking::GpsL1CaTcpConnectorTracking( channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL1CaTcpConnectorTracking::~GpsL1CaTcpConnectorTracking() -{} +GpsL1CaTcpConnectorTracking::~GpsL1CaTcpConnectorTracking() = default; + + +void GpsL1CaTcpConnectorTracking::stop_tracking() +{ +} void GpsL1CaTcpConnectorTracking::start_tracking() @@ -120,13 +131,17 @@ void GpsL1CaTcpConnectorTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) void GpsL1CaTcpConnectorTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } void GpsL1CaTcpConnectorTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } @@ -139,4 +154,3 @@ gr::basic_block_sptr GpsL1CaTcpConnectorTracking::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.h b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.h index 32d91e34f..1e910839e 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.h @@ -8,11 +8,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,9 +38,9 @@ #ifndef GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_H_ #define GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_H_ -#include -#include "tracking_interface.h" #include "gps_l1_ca_tcp_connector_tracking_cc.h" +#include "tracking_interface.h" +#include class ConfigurationInterface; @@ -50,53 +50,53 @@ class ConfigurationInterface; */ class GpsL1CaTcpConnectorTracking : public TrackingInterface { - public: - - GpsL1CaTcpConnectorTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + GpsL1CaTcpConnectorTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL1CaTcpConnectorTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "GPS_L1_CA_TCP_CONNECTOR_Tracking" - std::string implementation() + inline std::string implementation() override { return "GPS_L1_CA_TCP_CONNECTOR_Tracking"; } - size_t item_size() + + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: - gps_l1_ca_tcp_connector_tracking_cc_sptr tracking_; size_t item_size_; @@ -107,4 +107,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_H_ +#endif // GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc index 01afa145d..332b7b9c2 100644 --- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,62 +29,90 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #include "gps_l2_m_dll_pll_tracking.h" -#include #include "GPS_L2C.h" #include "configuration_interface.h" +#include "display.h" +#include "dll_pll_conf.h" +#include "gnss_sdr_flags.h" +#include using google::LogMessage; + GpsL2MDllPllTracking::GpsL2MDllPllTracking( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : - role_(role), in_streams_(in_streams), out_streams_(out_streams) + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { + Dll_Pll_Conf trk_param = Dll_Pll_Conf(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - int fs_in; - int vector_length; - int f_if; - bool dump; - std::string dump_filename; - std::string item_type; std::string default_item_type = "gr_complex"; - float pll_bw_hz; - float dll_bw_hz; - float early_late_space_chips; - item_type = configuration->property(role + ".item_type", default_item_type); - fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - f_if = configuration->property(role + ".if", 0); - dump = configuration->property(role + ".dump", false); - pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); - dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); - early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param.dump = dump; std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", - default_dump_filename); //unused! - vector_length = std::round(fs_in / (GPS_L2_M_CODE_RATE_HZ / GPS_L2_M_CODE_LENGTH_CHIPS)); + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 2.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 0.75); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param.dll_bw_hz = dll_bw_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param.early_late_space_chips = early_late_space_chips; + trk_param.early_late_space_narrow_chips = 0.0; + int vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L2_M_CODE_RATE_HZ) / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS))); + trk_param.vector_length = vector_length; + int symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); + if (symbols_extended_correlator != 1) + { + std::cout << TEXT_RED << "WARNING: Extended coherent integration is not allowed in GPS L2. Coherent integration has been set to 20 ms (1 symbol)" << TEXT_RESET << std::endl; + } + trk_param.extend_correlation_symbols = 1; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (track_pilot) + { + std::cout << TEXT_RED << "WARNING: GPS L2 does not have pilot signal. Data tracking has been enabled" << TEXT_RESET << std::endl; + } + trk_param.track_pilot = false; + trk_param.very_early_late_space_chips = 0.0; + trk_param.very_early_late_space_narrow_chips = 0.0; + trk_param.pll_bw_narrow_hz = 0.0; + trk_param.dll_bw_narrow_hz = 0.0; + trk_param.system = 'G'; + char sig_[3] = "2S"; + std::memcpy(trk_param.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param.carrier_lock_th = carrier_lock_th; //################# MAKE TRACKING GNURadio object ################### - if (item_type.compare("gr_complex") == 0) + if (item_type == "gr_complex") { item_size_ = sizeof(gr_complex); - tracking_ = gps_l2_m_dll_pll_make_tracking_cc( - f_if, - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips); + tracking_ = dll_pll_veml_make_tracking(trk_param); } else { @@ -93,18 +121,30 @@ GpsL2MDllPllTracking::GpsL2MDllPllTracking( } channel_ = 0; DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } } -GpsL2MDllPllTracking::~GpsL2MDllPllTracking() -{} +GpsL2MDllPllTracking::~GpsL2MDllPllTracking() = default; +void GpsL2MDllPllTracking::stop_tracking() +{ +} + void GpsL2MDllPllTracking::start_tracking() { tracking_->start_tracking(); } + /* * Set tracking channel unique ID */ @@ -120,25 +160,32 @@ void GpsL2MDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) tracking_->set_gnss_synchro(p_gnss_synchro); } + void GpsL2MDllPllTracking::connect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to connect, now the tracking uses gr_sync_decimator } + void GpsL2MDllPllTracking::disconnect(gr::top_block_sptr top_block) { - if(top_block) { /* top_block is not null */}; + if (top_block) + { /* top_block is not null */ + }; //nothing to disconnect, now the tracking uses gr_sync_decimator } + gr::basic_block_sptr GpsL2MDllPllTracking::get_left_block() { return tracking_; } + gr::basic_block_sptr GpsL2MDllPllTracking::get_right_block() { return tracking_; } - diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.h b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.h index cd174b2f7..20618a4cf 100644 --- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.h +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.h @@ -8,11 +8,11 @@ * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkha user, 2007 + * Approach, Birkhauser, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,10 +38,9 @@ #ifndef GNSS_SDR_gps_l2_m_dll_pll_tracking_H_ #define GNSS_SDR_gps_l2_m_dll_pll_tracking_H_ -#include +#include "dll_pll_veml_tracking.h" #include "tracking_interface.h" -#include "gps_l2_m_dll_pll_tracking_cc.h" - +#include class ConfigurationInterface; @@ -52,49 +51,52 @@ class GpsL2MDllPllTracking : public TrackingInterface { public: GpsL2MDllPllTracking(ConfigurationInterface* configuration, - std::string role, - unsigned int in_streams, - unsigned int out_streams); + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); virtual ~GpsL2MDllPllTracking(); - std::string role() + inline std::string role() override { return role_; } //! Returns "GPS_L2_M_DLL_PLL_Tracking" - std::string implementation() + inline std::string implementation() override { return "GPS_L2_M_DLL_PLL_Tracking"; } - size_t item_size() + inline size_t item_size() override { return item_size_; } - void connect(gr::top_block_sptr top_block); - void disconnect(gr::top_block_sptr top_block); - gr::basic_block_sptr get_left_block(); - gr::basic_block_sptr get_right_block(); - + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; /*! * \brief Set tracking channel unique ID */ - void set_channel(unsigned int channel); + void set_channel(unsigned int channel) override; /*! * \brief Set acquisition/tracking common Gnss_Synchro object pointer * to efficiently exchange synchronization data between acquisition and tracking blocks */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - void start_tracking(); + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; private: - gps_l2_m_dll_pll_tracking_cc_sptr tracking_; + dll_pll_veml_tracking_sptr tracking_; size_t item_size_; unsigned int channel_; std::string role_; @@ -102,4 +104,4 @@ private: unsigned int out_streams_; }; -#endif // GNSS_SDR_gps_l2_m_dll_pll_tracking_H_ +#endif // GNSS_SDR_gps_l2_m_dll_pll_tracking_H_ diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.cc new file mode 100644 index 000000000..c133b1ea1 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.cc @@ -0,0 +1,227 @@ +/*! + * \file gps_l2_m_dll_pll_tracking.cc + * \brief Implementation of an adapter of a DLL+PLL tracking loop block + * for GPS L1 C/A to a TrackingInterface + * \author Javier Arribas, 2015. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l2_m_dll_pll_tracking_fpga.h" +#include "GPS_L2C.h" +#include "configuration_interface.h" +#include "display.h" +#include "gnss_sdr_flags.h" +#include "gps_l2c_signal.h" +#include + +#define NUM_PRNs 32 + +using google::LogMessage; + +void GpsL2MDllPllTrackingFpga::stop_tracking() +{ +} + +GpsL2MDllPllTrackingFpga::GpsL2MDllPllTrackingFpga( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + //dllpllconf_t trk_param; + Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + //std::string default_item_type = "gr_complex"; + //std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param_fpga.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param_fpga.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param_fpga.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param_fpga.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 2.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param_fpga.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 0.75); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param_fpga.dll_bw_hz = dll_bw_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param_fpga.early_late_space_chips = early_late_space_chips; + trk_param_fpga.early_late_space_narrow_chips = 0.0; + int vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L2_M_CODE_RATE_HZ) / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS))); + trk_param_fpga.vector_length = vector_length; + int symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); + if (symbols_extended_correlator != 1) + { + std::cout << TEXT_RED << "WARNING: Extended coherent integration is not allowed in GPS L2. Coherent integration has been set to 20 ms (1 symbol)" << TEXT_RESET << std::endl; + } + trk_param_fpga.extend_correlation_symbols = 1; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (track_pilot) + { + std::cout << TEXT_RED << "WARNING: GPS L2 does not have pilot signal. Data tracking has been enabled" << TEXT_RESET << std::endl; + } + trk_param_fpga.track_pilot = false; + trk_param_fpga.very_early_late_space_chips = 0.0; + trk_param_fpga.very_early_late_space_narrow_chips = 0.0; + trk_param_fpga.pll_bw_narrow_hz = 0.0; + trk_param_fpga.dll_bw_narrow_hz = 0.0; + trk_param_fpga.system = 'G'; + char sig_[3] = "2S"; + std::memcpy(trk_param_fpga.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param_fpga.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param_fpga.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param_fpga.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param_fpga.carrier_lock_th = carrier_lock_th; + + // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + trk_param_fpga.device_name = device_name; + unsigned int device_base = configuration->property(role + ".device_base", 1); + trk_param_fpga.device_base = device_base; + //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 0); + trk_param_fpga.multicorr_type = 0; //multicorr_type : 0 -> 3 correlators, 1 -> 5 correlators + + //d_tracking_code = static_cast(volk_gnsssdr_malloc(2 * static_cast(GPS_L2_M_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment())); + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L2_M_CODE_LENGTH_CHIPS) * NUM_PRNs * sizeof(int), volk_gnsssdr_get_alignment())); + auto* ca_codes_f = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L2_M_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment())); + + //################# PRE-COMPUTE ALL THE CODES ################# + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L2_M_CODE_LENGTH_CHIPS * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + //gps_l1_ca_code_gen_int(&d_ca_codes[(int(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0); + gps_l2c_m_code_gen_float(ca_codes_f, PRN); + for (unsigned int s = 0; s < 2 * static_cast(GPS_L2_M_CODE_LENGTH_CHIPS); s++) + { + d_ca_codes[static_cast(GPS_L2_M_CODE_LENGTH_CHIPS) * (PRN - 1) + s] = static_cast(ca_codes_f[s]); + } + } + + delete[] ca_codes_f; + + trk_param_fpga.ca_codes = d_ca_codes; + trk_param_fpga.code_length_chips = GPS_L2_M_CODE_LENGTH_CHIPS; + trk_param_fpga.code_samples_per_chip = 1; // 1 sample per chip + + //################# MAKE TRACKING GNURadio object ################### + + // //################# MAKE TRACKING GNURadio object ################### + // if (item_type.compare("gr_complex") == 0) + // { + // item_size_ = sizeof(gr_complex); + // tracking_ = dll_pll_veml_make_tracking(trk_param); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // LOG(WARNING) << item_type << " unknown tracking item type."; + // } + + //################# MAKE TRACKING GNURadio object ################### + tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); + + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + + +GpsL2MDllPllTrackingFpga::~GpsL2MDllPllTrackingFpga() = default; + + +void GpsL2MDllPllTrackingFpga::start_tracking() +{ + //tracking_->start_tracking(); + tracking_fpga_sc->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GpsL2MDllPllTrackingFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + //tracking_->set_channel(channel); + tracking_fpga_sc->set_channel(channel); +} + + +void GpsL2MDllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + //tracking_->set_gnss_synchro(p_gnss_synchro); + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + + +void GpsL2MDllPllTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GpsL2MDllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GpsL2MDllPllTrackingFpga::get_left_block() +{ + //return tracking_; + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GpsL2MDllPllTrackingFpga::get_right_block() +{ + //return tracking_; + return tracking_fpga_sc; +} diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h new file mode 100644 index 000000000..7d36d1e74 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h @@ -0,0 +1,110 @@ +/*! + * \file gps_l2_m_dll_pll_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L1 C/A to a TrackingInterface + * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_gps_l2_m_dll_pll_tracking_FPGA_H_ +#define GNSS_SDR_gps_l2_m_dll_pll_tracking_FPGA_H_ + +#include "tracking_interface.h" +//#include "dll_pll_veml_tracking.h" +#include "dll_pll_veml_tracking_fpga.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GpsL2MDllPllTrackingFpga : public TrackingInterface +{ +public: + GpsL2MDllPllTrackingFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL2MDllPllTrackingFpga(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L2_M_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "GPS_L2_M_DLL_PLL_Tracking_Fpga"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + //dll_pll_veml_tracking_sptr tracking_; + dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + int* d_ca_codes; +}; + +#endif // GNSS_SDR_gps_l2_m_dll_pll_tracking_FPGA_H_ diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc new file mode 100644 index 000000000..c471f98b8 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc @@ -0,0 +1,211 @@ +/*! + * \file gps_l5_dll_pll_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L5 to a TrackingInterface + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l5_dll_pll_tracking.h" +#include "GPS_L5.h" +#include "configuration_interface.h" +#include "display.h" +#include "dll_pll_conf.h" +#include "gnss_sdr_flags.h" +#include + + +using google::LogMessage; + + +GpsL5DllPllTracking::GpsL5DllPllTracking( + ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + Dll_Pll_Conf trk_param = Dll_Pll_Conf(); + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + std::string default_item_type = "gr_complex"; + std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param.dump_mat = dump_mat; + trk_param.high_dyn = configuration->property(role + ".high_dyn", false); + if (configuration->property(role + ".smoother_length", 10) < 1) + { + trk_param.smoother_length = 1; + std::cout << TEXT_RED << "WARNING: GPS L5. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl; + } + else + { + trk_param.smoother_length = configuration->property(role + ".smoother_length", 10); + } + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0); + trk_param.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25); + trk_param.dll_bw_narrow_hz = dll_bw_narrow_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param.early_late_space_chips = early_late_space_chips; + int vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L5i_CODE_RATE_HZ) / static_cast(GPS_L5i_CODE_LENGTH_CHIPS))); + trk_param.vector_length = vector_length; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param.early_late_space_narrow_chips = early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: GPS L5. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > GPS_L5i_NH_CODE_LENGTH) + { + extend_correlation_symbols = GPS_L5i_NH_CODE_LENGTH; + std::cout << TEXT_RED << "WARNING: GPS L5. extend_correlation_symbols must be lower than 11 when tracking the data component. Coherent integration has been set to 10 symbols (10 ms)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: GPS L5. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param.extend_correlation_symbols = extend_correlation_symbols; + trk_param.track_pilot = track_pilot; + trk_param.very_early_late_space_chips = 0.0; + trk_param.very_early_late_space_narrow_chips = 0.0; + trk_param.system = 'G'; + char sig_[3] = "L5"; + std::memcpy(trk_param.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.75); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param.carrier_lock_th = carrier_lock_th; + + //################# MAKE TRACKING GNURadio object ################### + if (item_type == "gr_complex") + { + item_size_ = sizeof(gr_complex); + tracking_ = dll_pll_veml_make_tracking(trk_param); + } + else + { + item_size_ = sizeof(gr_complex); + LOG(WARNING) << item_type << " unknown tracking item type."; + } + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; + if (in_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +GpsL5DllPllTracking::~GpsL5DllPllTracking() = default; + + +void GpsL5DllPllTracking::stop_tracking() +{ +} + + +void GpsL5DllPllTracking::start_tracking() +{ + tracking_->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GpsL5DllPllTracking::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_->set_channel(channel); +} + + +void GpsL5DllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_->set_gnss_synchro(p_gnss_synchro); +} + + +void GpsL5DllPllTracking::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GpsL5DllPllTracking::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GpsL5DllPllTracking::get_left_block() +{ + return tracking_; +} + + +gr::basic_block_sptr GpsL5DllPllTracking::get_right_block() +{ + return tracking_; +} diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.h b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.h new file mode 100644 index 000000000..763df8bb0 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.h @@ -0,0 +1,106 @@ +/*! + * \file gps_l5_dll_pll_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L5 to a TrackingInterface + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_H_ +#define GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_H_ + +#include "dll_pll_veml_tracking.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GpsL5DllPllTracking : public TrackingInterface +{ +public: + GpsL5DllPllTracking(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL5DllPllTracking(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L5_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "GPS_L5_DLL_PLL_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + dll_pll_veml_tracking_sptr tracking_; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif // GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_H_ diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc new file mode 100644 index 000000000..effa0c5b7 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc @@ -0,0 +1,276 @@ +/*! + * \file gps_l5_dll_pll_tracking.cc + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L5 to a TrackingInterface + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l5_dll_pll_tracking_fpga.h" +#include "GPS_L5.h" +#include "configuration_interface.h" +#include "display.h" +#include "gnss_sdr_flags.h" +#include "gps_l5_signal.h" +#include + +#define NUM_PRNs 32 + +using google::LogMessage; + +void GpsL5DllPllTrackingFpga::stop_tracking() +{ +} + +GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( + ConfigurationInterface *configuration, const std::string &role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + //printf("L5 TRK CLASS CREATED\n"); + //dllpllconf_t trk_param; + Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + //std::string default_item_type = "gr_complex"; + //std::string item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + trk_param_fpga.fs_in = fs_in; + bool dump = configuration->property(role + ".dump", false); + trk_param_fpga.dump = dump; + std::string default_dump_filename = "./track_ch"; + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + trk_param_fpga.dump_filename = dump_filename; + bool dump_mat = configuration->property(role + ".dump_mat", true); + trk_param_fpga.dump_mat = dump_mat; + float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); + trk_param_fpga.pll_bw_hz = pll_bw_hz; + float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); + trk_param_fpga.dll_bw_hz = dll_bw_hz; + float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0); + trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz; + float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25); + trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; + float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + trk_param_fpga.early_late_space_chips = early_late_space_chips; + int vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L5i_CODE_RATE_HZ) / static_cast(GPS_L5i_CODE_LENGTH_CHIPS))); + trk_param_fpga.vector_length = vector_length; + int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); + trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; + bool track_pilot = configuration->property(role + ".track_pilot", false); + if (extend_correlation_symbols < 1) + { + extend_correlation_symbols = 1; + std::cout << TEXT_RED << "WARNING: GPS L5. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << std::endl; + } + else if (!track_pilot and extend_correlation_symbols > GPS_L5i_NH_CODE_LENGTH) + { + extend_correlation_symbols = GPS_L5i_NH_CODE_LENGTH; + std::cout << TEXT_RED << "WARNING: GPS L5. extend_correlation_symbols must be lower than 11 when tracking the data component. Coherent integration has been set to 10 symbols (10 ms)" << TEXT_RESET << std::endl; + } + if ((extend_correlation_symbols > 1) and (pll_bw_narrow_hz > pll_bw_hz or dll_bw_narrow_hz > dll_bw_hz)) + { + std::cout << TEXT_RED << "WARNING: GPS L5. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << std::endl; + } + trk_param_fpga.extend_correlation_symbols = extend_correlation_symbols; + trk_param_fpga.track_pilot = track_pilot; + d_track_pilot = track_pilot; + trk_param_fpga.very_early_late_space_chips = 0.0; + trk_param_fpga.very_early_late_space_narrow_chips = 0.0; + trk_param_fpga.system = 'G'; + char sig_[3] = "L5"; + std::memcpy(trk_param_fpga.signal, sig_, 3); + int cn0_samples = configuration->property(role + ".cn0_samples", 20); + if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; + trk_param_fpga.cn0_samples = cn0_samples; + int cn0_min = configuration->property(role + ".cn0_min", 25); + if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; + trk_param_fpga.cn0_min = cn0_min; + int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; + trk_param_fpga.max_lock_fail = max_lock_fail; + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; + trk_param_fpga.carrier_lock_th = carrier_lock_th; + + // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + trk_param_fpga.device_name = device_name; + unsigned int device_base = configuration->property(role + ".device_base", 1); + trk_param_fpga.device_base = device_base; + //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 0); + trk_param_fpga.multicorr_type = 0; //multicorr_type : 0 -> 3 correlators, 1 -> 5 correlators + + //################# PRE-COMPUTE ALL THE CODES ################# + unsigned int code_samples_per_chip = 1; + auto code_length_chips = static_cast(GPS_L5i_CODE_LENGTH_CHIPS); + //printf("TRK code_length_chips = %d\n", code_length_chips); + + float *tracking_code; + float *data_code; + + tracking_code = static_cast(volk_gnsssdr_malloc(code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + + if (trk_param_fpga.track_pilot) + { + data_code = static_cast(volk_gnsssdr_malloc(code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + } + + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); + + if (trk_param_fpga.track_pilot) + { + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * NUM_PRNs * sizeof(int), volk_gnsssdr_get_alignment())); + } + + //printf("start \n"); + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + if (track_pilot) + { + gps_l5q_code_gen_float(tracking_code, PRN); + gps_l5i_code_gen_float(data_code, PRN); + + + for (unsigned int s = 0; s < code_length_chips; s++) + { + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); + d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); + //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + } + + else + { + gps_l5i_code_gen_float(tracking_code, PRN); + for (unsigned int s = 0; s < code_length_chips; s++) + { + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); + //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + } + } + } + //printf("end \n"); + + + delete[] tracking_code; + if (trk_param_fpga.track_pilot) + { + delete[] data_code; + } + trk_param_fpga.ca_codes = d_ca_codes; + trk_param_fpga.data_codes = d_data_codes; + trk_param_fpga.code_length_chips = code_length_chips; + trk_param_fpga.code_samples_per_chip = code_samples_per_chip; // 2 sample per chip + //################# MAKE TRACKING GNURadio object ################### + // if (item_type.compare("gr_complex") == 0) + // { + // item_size_ = sizeof(gr_complex); + // tracking_ = dll_pll_veml_make_tracking(trk_param_fpga); + // } + // else + // { + // item_size_ = sizeof(gr_complex); + // LOG(WARNING) << item_type << " unknown tracking item type."; + // } + //printf("call \n"); + tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); + //printf("end2 \n"); + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + + +GpsL5DllPllTrackingFpga::~GpsL5DllPllTrackingFpga() +{ + delete[] d_ca_codes; + if (d_track_pilot) + { + delete[] d_data_codes; + } +} + + +void GpsL5DllPllTrackingFpga::start_tracking() +{ + tracking_fpga_sc->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GpsL5DllPllTrackingFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_fpga_sc->set_channel(channel); +} + + +void GpsL5DllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + + +void GpsL5DllPllTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GpsL5DllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GpsL5DllPllTrackingFpga::get_left_block() +{ + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GpsL5DllPllTrackingFpga::get_right_block() +{ + return tracking_fpga_sc; +} diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h new file mode 100644 index 000000000..087f3730c --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h @@ -0,0 +1,110 @@ +/*! + * \file gps_l5_dll_pll_tracking.h + * \brief Interface of an adapter of a DLL+PLL tracking loop block + * for GPS L5 to a TrackingInterface + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_FPGA_H_ +#define GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_FPGA_H_ + +#include "dll_pll_veml_tracking_fpga.h" +#include "tracking_interface.h" +#include + +class ConfigurationInterface; + +/*! + * \brief This class implements a code DLL + carrier PLL tracking loop + */ +class GpsL5DllPllTrackingFpga : public TrackingInterface +{ +public: + GpsL5DllPllTrackingFpga(ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GpsL5DllPllTrackingFpga(); + + inline std::string role() override + { + return role_; + } + + //! Returns "GPS_L5_DLL_PLL_Tracking" + inline std::string implementation() override + { + return "GPS_L5_DLL_PLL_Tracking"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + + /*! + * \brief Set tracking channel unique ID + */ + void set_channel(unsigned int channel) override; + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to efficiently exchange synchronization data between acquisition and tracking blocks + */ + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; + + void start_tracking() override; + /*! + * \brief Stop running tracking + */ + void stop_tracking() override; + +private: + //dll_pll_veml_tracking_sptr tracking_; + dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; + size_t item_size_; + unsigned int channel_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; + bool d_track_pilot; + int* d_ca_codes; + int* d_data_codes; +}; + +#endif // GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt b/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt index 276913d87..2dd5b494f 100644 --- a/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,53 +13,124 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # if(ENABLE_CUDA) - set(OPT_TRACKING_BLOCKS ${OPT_TRACKING_BLOCKS} gps_l1_ca_dll_pll_tracking_gpu_cc.cc) - set(OPT_TRACKING_INCLUDES ${OPT_TRACKING_INCLUDES} ${CUDA_INCLUDE_DIRS}) - set(OPT_TRACKING_LIBRARIES ${OPT_TRACKING_LIBRARIES} ${CUDA_LIBRARIES}) -endif(ENABLE_CUDA) + set(OPT_TRACKING_BLOCKS_SOURCES + ${OPT_TRACKING_BLOCKS_SOURCES} + gps_l1_ca_dll_pll_tracking_gpu_cc.cc + ) + set(OPT_TRACKING_BLOCKS_HEADERS + ${OPT_TRACKING_BLOCKS_HEADERS} + gps_l1_ca_dll_pll_tracking_gpu_cc.h + ) + set(OPT_TRACKING_INCLUDES + ${OPT_TRACKING_INCLUDES} + ${CUDA_INCLUDE_DIRS} + ) + set(OPT_TRACKING_LIBRARIES + ${OPT_TRACKING_LIBRARIES} + ${CUDA_LIBRARIES} + ) +endif() + +if(ENABLE_FPGA) + set(OPT_TRACKING_BLOCKS_SOURCES + ${OPT_TRACKING_BLOCKS_SOURCES} + dll_pll_veml_tracking_fpga.cc + ) + set(OPT_TRACKING_BLOCKS_HEADERS + ${OPT_TRACKING_BLOCKS_HEADERS} + dll_pll_veml_tracking_fpga.h + ) +endif() set(TRACKING_GR_BLOCKS_SOURCES - galileo_e1_dll_pll_veml_tracking_cc.cc - galileo_e1_tcp_connector_tracking_cc.cc - gps_l1_ca_dll_pll_tracking_cc.cc - gps_l1_ca_tcp_connector_tracking_cc.cc - galileo_e5a_dll_pll_tracking_cc.cc - gps_l2_m_dll_pll_tracking_cc.cc - gps_l1_ca_dll_pll_c_aid_tracking_cc.cc - gps_l1_ca_dll_pll_c_aid_tracking_sc.cc - ${OPT_TRACKING_BLOCKS} + galileo_e1_tcp_connector_tracking_cc.cc + gps_l1_ca_tcp_connector_tracking_cc.cc + gps_l1_ca_dll_pll_c_aid_tracking_cc.cc + gps_l1_ca_dll_pll_c_aid_tracking_sc.cc + glonass_l1_ca_dll_pll_tracking_cc.cc + glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc + glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc + gps_l1_ca_kf_tracking_cc.cc + glonass_l2_ca_dll_pll_tracking_cc.cc + glonass_l2_ca_dll_pll_c_aid_tracking_cc.cc + glonass_l2_ca_dll_pll_c_aid_tracking_sc.cc + dll_pll_veml_tracking.cc + ${OPT_TRACKING_BLOCKS_SOURCES} +) + +set(TRACKING_GR_BLOCKS_HEADERS + galileo_e1_tcp_connector_tracking_cc.h + gps_l1_ca_tcp_connector_tracking_cc.h + gps_l1_ca_dll_pll_c_aid_tracking_cc.h + gps_l1_ca_dll_pll_c_aid_tracking_sc.h + glonass_l1_ca_dll_pll_tracking_cc.h + glonass_l1_ca_dll_pll_c_aid_tracking_cc.h + glonass_l1_ca_dll_pll_c_aid_tracking_sc.h + gps_l1_ca_kf_tracking_cc.h + glonass_l2_ca_dll_pll_tracking_cc.h + glonass_l2_ca_dll_pll_c_aid_tracking_cc.h + glonass_l2_ca_dll_pll_c_aid_tracking_sc.h + dll_pll_veml_tracking.h + ${OPT_TRACKING_BLOCKS_HEADERS} ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} - ${OPT_TRACKING_INCLUDES} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${ARMADILLO_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${OPT_TRACKING_INCLUDES} + ${MATIO_INCLUDE_DIRS} ) if(ENABLE_GENERIC_ARCH) - add_definitions( -DGENERIC_ARCH=1 ) -endif(ENABLE_GENERIC_ARCH) + add_definitions(-DGENERIC_ARCH=1) +endif() -file(GLOB TRACKING_GR_BLOCKS_HEADERS "*.h") list(SORT TRACKING_GR_BLOCKS_HEADERS) -add_library(tracking_gr_blocks ${TRACKING_GR_BLOCKS_SOURCES} ${TRACKING_GR_BLOCKS_HEADERS}) +list(SORT TRACKING_GR_BLOCKS_SOURCES) + +add_library(tracking_gr_blocks + ${TRACKING_GR_BLOCKS_SOURCES} + ${TRACKING_GR_BLOCKS_HEADERS} +) + source_group(Headers FILES ${TRACKING_GR_BLOCKS_HEADERS}) -target_link_libraries(tracking_gr_blocks tracking_lib ${GNURADIO_RUNTIME_LIBRARIES} gnss_sp_libs ${Boost_LIBRARIES} ${VOLK_GNSSSDR_LIBRARIES} ${OPT_TRACKING_LIBRARIES}) +target_link_libraries(tracking_gr_blocks + tracking_lib + ${GNURADIO_RUNTIME_LIBRARIES} + gnss_sdr_flags gnss_sp_libs + ${Boost_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${MATIO_LIBRARIES} + ${OPT_TRACKING_LIBRARIES} +) -if(NOT VOLK_GNSSSDR_FOUND) - add_dependencies(tracking_gr_blocks volk_gnsssdr_module) -endif(NOT VOLK_GNSSSDR_FOUND) +if(NOT VOLKGNSSSDR_FOUND) + if(MATIO_FOUND) + add_dependencies(tracking_gr_blocks volk_gnsssdr_module) + else() + add_dependencies(tracking_gr_blocks volk_gnsssdr_module + matio-${GNSSSDR_MATIO_LOCAL_VERSION} + ) + endif() +else() + if(NOT MATIO_FOUND) + add_dependencies(tracking_gr_blocks + matio-${GNSSSDR_MATIO_LOCAL_VERSION} + ) + endif() +endif() diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc new file mode 100644 index 000000000..b6853a0a9 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc @@ -0,0 +1,1684 @@ +/*! + * \file dll_pll_veml_tracking.cc + * \brief Implementation of a code DLL + carrier PLL tracking block. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com + * + * Code DLL + carrier PLL according to the algorithms described in: + * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "dll_pll_veml_tracking.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "MATH_CONSTANTS.h" +#include "control_message_factory.h" +#include "galileo_e1_signal_processing.h" +#include "galileo_e5_signal_processing.h" +#include "gnss_sdr_create_directory.h" +#include "gps_l2c_signal.h" +#include "gps_l5_signal.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using google::LogMessage; + +dll_pll_veml_tracking_sptr dll_pll_veml_make_tracking(const Dll_Pll_Conf &conf_) +{ + return dll_pll_veml_tracking_sptr(new dll_pll_veml_tracking(conf_)); +} + + +void dll_pll_veml_tracking::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(trk_parameters.vector_length) * 2; + } +} + + +dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) : gr::block("dll_pll_veml_tracking", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + trk_parameters = conf_; + // Telemetry bit synchronization message port input + this->message_port_register_out(pmt::mp("events")); + this->set_relative_rate(1.0 / static_cast(trk_parameters.vector_length)); + + // Telemetry bit synchronization message port input (mainly for GPS L1 CA) + this->message_port_register_in(pmt::mp("preamble_samplestamp")); + + // initialize internal vars + d_veml = false; + d_cloop = true; + d_code_chip_rate = 0.0; + d_secondary_code_length = 0U; + d_secondary_code_string = nullptr; + d_gps_l1ca_preambles_symbols = nullptr; + signal_type = std::string(trk_parameters.signal); + + std::map map_signal_pretty_name; + map_signal_pretty_name["1C"] = "L1 C/A"; + map_signal_pretty_name["1B"] = "E1"; + map_signal_pretty_name["1G"] = "L1 C/A"; + map_signal_pretty_name["2S"] = "L2C"; + map_signal_pretty_name["2G"] = "L2 C/A"; + map_signal_pretty_name["5X"] = "E5a"; + map_signal_pretty_name["L5"] = "L5"; + + signal_pretty_name = map_signal_pretty_name[signal_type]; + + if (trk_parameters.system == 'G') + { + systemName = "GPS"; + if (signal_type == "1C") + { + d_signal_carrier_freq = GPS_L1_FREQ_HZ; + d_code_period = GPS_L1_CA_CODE_PERIOD; + d_code_chip_rate = GPS_L1_CA_CODE_RATE_HZ; + d_symbols_per_bit = GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; + d_correlation_length_ms = 1; + d_code_samples_per_chip = 1; + d_code_length_chips = static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS); + // GPS L1 C/A does not have pilot component nor secondary code + d_secondary = false; + trk_parameters.track_pilot = false; + interchange_iq = false; + + // set the preamble + uint16_t preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE; + + // preamble bits to sampled symbols + d_gps_l1ca_preambles_symbols = static_cast(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int32_t), volk_gnsssdr_get_alignment())); + int32_t n = 0; + for (uint16_t preambles_bit : preambles_bits) + { + for (uint32_t j = 0; j < GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; j++) + { + if (preambles_bit == 1) + { + d_gps_l1ca_preambles_symbols[n] = 1; + } + else + { + d_gps_l1ca_preambles_symbols[n] = -1; + } + n++; + } + } + d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size + d_symbol_history.clear(); // Clear all the elements in the buffer + } + else if (signal_type == "2S") + { + d_signal_carrier_freq = GPS_L2_FREQ_HZ; + d_code_period = GPS_L2_M_PERIOD; + d_code_chip_rate = GPS_L2_M_CODE_RATE_HZ; + d_code_length_chips = static_cast(GPS_L2_M_CODE_LENGTH_CHIPS); + d_symbols_per_bit = GPS_L2_SAMPLES_PER_SYMBOL; + d_correlation_length_ms = 20; + d_code_samples_per_chip = 1; + // GPS L2 does not have pilot component nor secondary code + d_secondary = false; + trk_parameters.track_pilot = false; + interchange_iq = false; + } + else if (signal_type == "L5") + { + d_signal_carrier_freq = GPS_L5_FREQ_HZ; + d_code_period = GPS_L5i_PERIOD; + d_code_chip_rate = GPS_L5i_CODE_RATE_HZ; + d_symbols_per_bit = GPS_L5_SAMPLES_PER_SYMBOL; + d_correlation_length_ms = 1; + d_code_samples_per_chip = 1; + d_code_length_chips = static_cast(GPS_L5i_CODE_LENGTH_CHIPS); + d_secondary = true; + if (trk_parameters.track_pilot) + { + d_secondary_code_length = static_cast(GPS_L5q_NH_CODE_LENGTH); + d_secondary_code_string = const_cast(&GPS_L5q_NH_CODE_STR); + signal_pretty_name = signal_pretty_name + "Q"; + interchange_iq = true; + } + else + { + d_secondary_code_length = static_cast(GPS_L5i_NH_CODE_LENGTH); + d_secondary_code_string = const_cast(&GPS_L5i_NH_CODE_STR); + signal_pretty_name = signal_pretty_name + "I"; + interchange_iq = false; + } + } + else + { + LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks"; + std::cerr << "Invalid Signal argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + d_code_length_chips = 0U; + d_code_samples_per_chip = 0U; + d_symbols_per_bit = 0; + } + } + else if (trk_parameters.system == 'E') + { + systemName = "Galileo"; + if (signal_type == "1B") + { + d_signal_carrier_freq = Galileo_E1_FREQ_HZ; + d_code_period = Galileo_E1_CODE_PERIOD; + d_code_chip_rate = Galileo_E1_CODE_CHIP_RATE_HZ; + d_code_length_chips = static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS); + d_symbols_per_bit = 1; + d_correlation_length_ms = 4; + d_code_samples_per_chip = 2; // CBOC disabled: 2 samples per chip. CBOC enabled: 12 samples per chip + d_veml = true; + if (trk_parameters.track_pilot) + { + d_secondary = true; + d_secondary_code_length = static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); + d_secondary_code_string = const_cast(&Galileo_E1_C_SECONDARY_CODE); + signal_pretty_name = signal_pretty_name + "C"; + } + else + { + d_secondary = false; + signal_pretty_name = signal_pretty_name + "B"; + } + interchange_iq = false; // Note that E1-B and E1-C are in anti-phase, NOT IN QUADRATURE. See Galileo ICD. + } + else if (signal_type == "5X") + { + d_signal_carrier_freq = Galileo_E5a_FREQ_HZ; + d_code_period = GALILEO_E5a_CODE_PERIOD; + d_code_chip_rate = Galileo_E5a_CODE_CHIP_RATE_HZ; + d_symbols_per_bit = 20; + d_correlation_length_ms = 1; + d_code_samples_per_chip = 1; + d_code_length_chips = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); + + if (trk_parameters.track_pilot) + { + d_secondary = true; + d_secondary_code_length = static_cast(Galileo_E5a_Q_SECONDARY_CODE_LENGTH); + signal_pretty_name = signal_pretty_name + "Q"; + interchange_iq = true; + } + else + { + //Do not acquire secondary code in data component. It is done in telemetry decoder + d_secondary = false; + signal_pretty_name = signal_pretty_name + "I"; + interchange_iq = false; + } + } + else + { + LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks"; + std::cout << "Invalid Signal argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + d_code_length_chips = 0U; + d_code_samples_per_chip = 0U; + d_symbols_per_bit = 0; + } + } + else + { + LOG(WARNING) << "Invalid System argument when instantiating tracking blocks"; + std::cerr << "Invalid System argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + d_code_length_chips = 0U; + d_code_samples_per_chip = 0U; + d_symbols_per_bit = 0; + } + T_chip_seconds = 0.0; + T_prn_seconds = 0.0; + T_prn_samples = 0.0; + K_blk_samples = 0.0; + + // Initialize tracking ========================================== + d_code_loop_filter = Tracking_2nd_DLL_filter(static_cast(d_code_period)); + d_carrier_loop_filter = Tracking_2nd_PLL_filter(static_cast(d_code_period)); + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); + + // Initialization of local code replica + // Get space for a vector with the sinboc(1,1) replica sampled 2x/chip + d_tracking_code = static_cast(volk_gnsssdr_malloc(2 * d_code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + // correlator outputs (scalar) + if (d_veml) + { + // Very-Early, Early, Prompt, Late, Very-Late + d_n_correlator_taps = 5; + } + else + { + // Early, Prompt, Late + d_n_correlator_taps = 3; + } + + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + + // map memory pointers of correlator outputs + if (d_veml) + { + d_Very_Early = &d_correlator_outs[0]; + d_Early = &d_correlator_outs[1]; + d_Prompt = &d_correlator_outs[2]; + d_Late = &d_correlator_outs[3]; + d_Very_Late = &d_correlator_outs[4]; + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = 0.0; + d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_prompt_data_shift = &d_local_code_shift_chips[2]; + } + else + { + d_Very_Early = nullptr; + d_Early = &d_correlator_outs[0]; + d_Prompt = &d_correlator_outs[1]; + d_Late = &d_correlator_outs[2]; + d_Very_Late = nullptr; + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_prompt_data_shift = &d_local_code_shift_chips[1]; + } + + multicorrelator_cpu.init(2 * trk_parameters.vector_length, d_n_correlator_taps); + + if (trk_parameters.extend_correlation_symbols > 1) + { + d_enable_extended_integration = true; + } + else + { + d_enable_extended_integration = false; + trk_parameters.extend_correlation_symbols = 1; + } + + // Enable Data component prompt correlator (slave to Pilot prompt) if tracking uses Pilot signal + if (trk_parameters.track_pilot) + { + // Extra correlator for the data component + correlator_data_cpu.init(2 * trk_parameters.vector_length, 1); + correlator_data_cpu.set_high_dynamics_resampler(trk_parameters.high_dyn); + d_data_code = static_cast(volk_gnsssdr_malloc(2 * d_code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); + } + else + { + d_data_code = nullptr; + } + + // --- Initializations --- + multicorrelator_cpu.set_high_dynamics_resampler(trk_parameters.high_dyn); + // Initial code frequency basis of NCO + d_code_freq_chips = d_code_chip_rate; + // Residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // Residual carrier phase + d_rem_carr_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; + d_acq_sample_stamp = 0ULL; + + d_current_prn_length_samples = static_cast(trk_parameters.vector_length); + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[trk_parameters.cn0_samples]; + d_carrier_lock_test = 1.0; + d_CN0_SNV_dB_Hz = 0.0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = trk_parameters.carrier_lock_th; + d_Prompt_Data = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_acc_carrier_phase_rad = 0.0; + + d_extend_correlation_symbols_count = 0; + d_code_phase_step_chips = 0.0; + d_code_phase_rate_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_carrier_phase_rate_step_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_last_prompt = gr_complex(0.0, 0.0); + d_state = 0; // initial state: standby + clear_tracking_vars(); + if (trk_parameters.smoother_length > 0) + { + d_carr_ph_history.resize(trk_parameters.smoother_length * 2); + d_code_ph_history.resize(trk_parameters.smoother_length * 2); + } + else + { + d_carr_ph_history.resize(1); + d_code_ph_history.resize(1); + } + + d_dump = trk_parameters.dump; + d_dump_mat = trk_parameters.dump_mat and d_dump; + if (d_dump) + { + d_dump_filename = trk_parameters.dump_filename; + std::string dump_path; + // Get path + if (d_dump_filename.find_last_of('/') != std::string::npos) + { + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/')); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "trk_channel_"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.')); + } + + d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump files for the tracking block. Wrong permissions?" << std::endl; + d_dump = false; + } + } +} + + +void dll_pll_veml_tracking::start_tracking() +{ + gr::thread::scoped_lock l(d_setlock); + + // correct the code phase according to the delay between acq and trk + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; + d_carrier_phase_rate_step_rad = 0.0; + d_carr_ph_history.clear(); + d_code_ph_history.clear(); + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(); // initialize the carrier filter + d_code_loop_filter.initialize(); // initialize the code filter + + if (systemName == "GPS" and signal_type == "1C") + { + gps_l1_ca_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN, 0); + } + else if (systemName == "GPS" and signal_type == "2S") + { + gps_l2c_m_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN); + } + else if (systemName == "GPS" and signal_type == "L5") + { + if (trk_parameters.track_pilot) + { + gps_l5q_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN); + gps_l5i_code_gen_float(d_data_code, d_acquisition_gnss_synchro->PRN); + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + correlator_data_cpu.set_local_code_and_taps(d_code_length_chips, d_data_code, d_prompt_data_shift); + } + else + { + gps_l5i_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN); + } + } + else if (systemName == "Galileo" and signal_type == "1B") + { + if (trk_parameters.track_pilot) + { + char pilot_signal[3] = "1C"; + galileo_e1_code_gen_sinboc11_float(d_tracking_code, pilot_signal, d_acquisition_gnss_synchro->PRN); + galileo_e1_code_gen_sinboc11_float(d_data_code, d_acquisition_gnss_synchro->Signal, d_acquisition_gnss_synchro->PRN); + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + correlator_data_cpu.set_local_code_and_taps(d_code_samples_per_chip * d_code_length_chips, d_data_code, d_prompt_data_shift); + } + else + { + galileo_e1_code_gen_sinboc11_float(d_tracking_code, d_acquisition_gnss_synchro->Signal, d_acquisition_gnss_synchro->PRN); + } + } + else if (systemName == "Galileo" and signal_type == "5X") + { + auto *aux_code = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex) * d_code_length_chips, volk_gnsssdr_get_alignment())); + galileo_e5_a_code_gen_complex_primary(aux_code, d_acquisition_gnss_synchro->PRN, const_cast(signal_type.c_str())); + if (trk_parameters.track_pilot) + { + d_secondary_code_string = const_cast(&Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1]); + for (uint32_t i = 0; i < d_code_length_chips; i++) + { + d_tracking_code[i] = aux_code[i].imag(); + d_data_code[i] = aux_code[i].real(); //the same because it is generated the full signal (E5aI + E5aQ) + } + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + correlator_data_cpu.set_local_code_and_taps(d_code_length_chips, d_data_code, d_prompt_data_shift); + } + else + { + for (uint32_t i = 0; i < d_code_length_chips; i++) + { + d_tracking_code[i] = aux_code[i].real(); + } + } + volk_gnsssdr_free(aux_code); + } + + multicorrelator_cpu.set_local_code_and_taps(d_code_samples_per_chip * d_code_length_chips, d_tracking_code, d_local_code_shift_chips); + std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_cn0_estimation_counter = 0; + d_carrier_lock_test = 1.0; + d_CN0_SNV_dB_Hz = 0.0; + + if (d_veml) + { + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + } + else + { + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + } + + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); + d_carrier_loop_filter.set_pdi(static_cast(d_code_period)); + d_code_loop_filter.set_pdi(static_cast(d_code_period)); + + // DEBUG OUTPUT + std::cout << "Tracking of " << systemName << " " << signal_pretty_name << " signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + DLOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking pull-in + d_state = 1; + d_cloop = true; + d_Prompt_buffer_deque.clear(); + d_last_prompt = gr_complex(0.0, 0.0); +} + + +dll_pll_veml_tracking::~dll_pll_veml_tracking() +{ + if (signal_type == "1C") + { + volk_gnsssdr_free(d_gps_l1ca_preambles_symbols); + } + + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + if (d_dump_mat) + { + save_matfile(); + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_tracking_code); + volk_gnsssdr_free(d_Prompt_Data); + if (trk_parameters.track_pilot) + { + volk_gnsssdr_free(d_data_code); + correlator_data_cpu.free(); + } + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +bool dll_pll_veml_tracking::acquire_secondary() +{ + // ******* preamble correlation ******** + int32_t corr_value = 0; + for (uint32_t i = 0; i < d_secondary_code_length; i++) + { + if (d_Prompt_buffer_deque.at(i).real() < 0.0) // symbols clipping + { + if (d_secondary_code_string->at(i) == '0') + { + corr_value++; + } + else + { + corr_value--; + } + } + else + { + if (d_secondary_code_string->at(i) == '0') + { + corr_value--; + } + else + { + corr_value++; + } + } + } + + if (abs(corr_value) == static_cast(d_secondary_code_length)) + { + return true; + } + + return false; +} + + +bool dll_pll_veml_tracking::cn0_and_tracking_lock_status(double coh_integration_time_s) +{ + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < trk_parameters.cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_P_accu; + d_cn0_estimation_counter++; + return true; + } + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, trk_parameters.cn0_samples, coh_integration_time_s); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, trk_parameters.cn0_samples); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < trk_parameters.cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > trk_parameters.max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + return false; + } + return true; +} + + +// correlation requires: +// - updated remnant carrier phase in radians (rem_carr_phase_rad) +// - updated remnant code phase in samples (d_rem_code_phase_samples) +// - d_code_freq_chips +// - d_carrier_doppler_hz +void dll_pll_veml_tracking::do_correlation_step(const gr_complex *input_samples) +{ + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, input_samples); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, + d_carrier_phase_step_rad, d_carrier_phase_rate_step_rad, + static_cast(d_rem_code_phase_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_step_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_rate_step_chips) * static_cast(d_code_samples_per_chip), + trk_parameters.vector_length); + + // DATA CORRELATOR (if tracking tracks the pilot signal) + if (trk_parameters.track_pilot) + { + correlator_data_cpu.set_input_output_vectors(d_Prompt_Data, input_samples); + correlator_data_cpu.Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, + d_carrier_phase_step_rad, d_carrier_phase_rate_step_rad, + static_cast(d_rem_code_phase_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_step_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_rate_step_chips) * static_cast(d_code_samples_per_chip), + trk_parameters.vector_length); + } +} + + +void dll_pll_veml_tracking::run_dll_pll() +{ + // ################## PLL ########################################################## + // PLL discriminator + if (d_cloop) + { + // Costas loop discriminator, insensitive to 180 deg phase transitions + d_carr_error_hz = pll_cloop_two_quadrant_atan(d_P_accu) / PI_2; + } + else + { + // Secondary code acquired. No symbols transition should be present in the signal + d_carr_error_hz = pll_four_quadrant_atan(d_P_accu) / PI_2; + } + + // Carrier discriminator filter + d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(d_carr_error_hz); + // New carrier Doppler frequency estimation + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_carr_error_filt_hz; + + + // ################## DLL ########################################################## + // DLL discriminator + if (d_veml) + { + d_code_error_chips = dll_nc_vemlp_normalized(d_VE_accu, d_E_accu, d_L_accu, d_VL_accu); // [chips/Ti] + } + else + { + d_code_error_chips = dll_nc_e_minus_l_normalized(d_E_accu, d_L_accu); // [chips/Ti] + } + // Code discriminator filter + d_code_error_filt_chips = d_code_loop_filter.get_code_nco(d_code_error_chips); // [chips/second] + + // New code Doppler frequency estimation + d_code_freq_chips = (1.0 + (d_carrier_doppler_hz / d_signal_carrier_freq)) * d_code_chip_rate - d_code_error_filt_chips; +} + + +void dll_pll_veml_tracking::clear_tracking_vars() +{ + std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); + if (trk_parameters.track_pilot) d_Prompt_Data[0] = gr_complex(0.0, 0.0); + d_carr_error_hz = 0.0; + d_carr_error_filt_hz = 0.0; + d_code_error_chips = 0.0; + d_code_error_filt_chips = 0.0; + d_current_symbol = 0; + d_Prompt_buffer_deque.clear(); + d_last_prompt = gr_complex(0.0, 0.0); + d_carrier_phase_rate_step_rad = 0.0; + d_code_phase_rate_step_chips = 0.0; + d_carr_ph_history.clear(); + d_code_ph_history.clear(); +} + + +void dll_pll_veml_tracking::update_tracking_vars() +{ + T_chip_seconds = 1.0 / d_code_freq_chips; + T_prn_seconds = T_chip_seconds * static_cast(d_code_length_chips); + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + T_prn_samples = T_prn_seconds * trk_parameters.fs_in; + K_blk_samples = T_prn_samples + d_rem_code_phase_samples; + //d_current_prn_length_samples = static_cast(round(K_blk_samples)); // round to a discrete number of samples + d_current_prn_length_samples = static_cast(std::floor(K_blk_samples)); // round to a discrete number of samples + + //################### PLL COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; + // carrier phase rate step (NCO phase increment rate per sample) [rads/sample^2] + if (trk_parameters.high_dyn) + { + d_carr_ph_history.push_back(std::pair(d_carrier_phase_step_rad, static_cast(d_current_prn_length_samples))); + if (d_carr_ph_history.full()) + { + double tmp_cp1 = 0.0; + double tmp_cp2 = 0.0; + double tmp_samples = 0.0; + for (unsigned int k = 0; k < trk_parameters.smoother_length; k++) + { + tmp_cp1 += d_carr_ph_history.at(k).first; + tmp_cp2 += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first; + tmp_samples += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second; + } + tmp_cp1 /= static_cast(trk_parameters.smoother_length); + tmp_cp2 /= static_cast(trk_parameters.smoother_length); + d_carrier_phase_rate_step_rad = (tmp_cp2 - tmp_cp1) / tmp_samples; + } + } + //std::cout << d_carrier_phase_rate_step_rad * trk_parameters.fs_in * trk_parameters.fs_in / PI_2 << std::endl; + // remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad += static_cast(d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast(d_current_prn_length_samples) * static_cast(d_current_prn_length_samples)); + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, PI_2); + + + // carrier phase accumulator + //double a = d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + //double b = 0.5 * d_carrier_phase_rate_step_rad * static_cast(d_current_prn_length_samples) * static_cast(d_current_prn_length_samples); + //std::cout << fmod(b, PI_2) / fmod(a, PI_2) << std::endl; + d_acc_carrier_phase_rad -= (d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast(d_current_prn_length_samples) * static_cast(d_current_prn_length_samples)); + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + if (trk_parameters.high_dyn) + { + d_code_ph_history.push_back(std::pair(d_code_phase_step_chips, static_cast(d_current_prn_length_samples))); + if (d_code_ph_history.full()) + { + double tmp_cp1 = 0.0; + double tmp_cp2 = 0.0; + double tmp_samples = 0.0; + for (unsigned int k = 0; k < trk_parameters.smoother_length; k++) + { + tmp_cp1 += d_code_ph_history.at(k).first; + tmp_cp2 += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first; + tmp_samples += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second; + } + tmp_cp1 /= static_cast(trk_parameters.smoother_length); + tmp_cp2 /= static_cast(trk_parameters.smoother_length); + d_code_phase_rate_step_chips = (tmp_cp2 - tmp_cp1) / tmp_samples; + } + } + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - static_cast(d_current_prn_length_samples); // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * d_rem_code_phase_samples / trk_parameters.fs_in; +} + + +void dll_pll_veml_tracking::save_correlation_results() +{ + if (d_secondary) + { + if (d_secondary_code_string->at(d_current_symbol) == '0') + { + if (d_veml) + { + d_VE_accu += *d_Very_Early; + d_VL_accu += *d_Very_Late; + } + d_E_accu += *d_Early; + d_P_accu += *d_Prompt; + d_L_accu += *d_Late; + } + else + { + if (d_veml) + { + d_VE_accu -= *d_Very_Early; + d_VL_accu -= *d_Very_Late; + } + d_E_accu -= *d_Early; + d_P_accu -= *d_Prompt; + d_L_accu -= *d_Late; + } + d_current_symbol++; + // secondary code roll-up + d_current_symbol %= d_secondary_code_length; + } + else + { + if (d_veml) + { + d_VE_accu += *d_Very_Early; + d_VL_accu += *d_Very_Late; + } + d_E_accu += *d_Early; + d_P_accu += *d_Prompt; + d_L_accu += *d_Late; + d_current_symbol++; + d_current_symbol %= d_symbols_per_bit; + } + // If tracking pilot, disable Costas loop + if (trk_parameters.track_pilot) + d_cloop = false; + else + d_cloop = true; +} + + +void dll_pll_veml_tracking::log_data(bool integrating) +{ + if (d_dump) + { + // Dump results to file + float prompt_I; + float prompt_Q; + float tmp_VE, tmp_E, tmp_P, tmp_L, tmp_VL; + float tmp_float; + double tmp_double; + uint64_t tmp_long_int; + if (trk_parameters.track_pilot) + { + if (interchange_iq) + { + prompt_I = d_Prompt_Data->imag(); + prompt_Q = d_Prompt_Data->real(); + } + else + { + prompt_I = d_Prompt_Data->real(); + prompt_Q = d_Prompt_Data->imag(); + } + } + else + { + if (interchange_iq) + { + prompt_I = d_Prompt->imag(); + prompt_Q = d_Prompt->real(); + } + else + { + prompt_I = d_Prompt->real(); + prompt_Q = d_Prompt->imag(); + } + } + if (d_veml) + { + tmp_VE = std::abs(d_VE_accu); + tmp_VL = std::abs(d_VL_accu); + } + else + { + tmp_VE = 0.0; + tmp_VL = 0.0; + } + tmp_E = std::abs(d_E_accu); + tmp_P = std::abs(d_P_accu); + tmp_L = std::abs(d_L_accu); + if (integrating) + { + //TODO: Improve this solution! + // It compensates the amplitude difference while integrating + if (d_extend_correlation_symbols_count > 0) + { + float scale_factor = static_cast(trk_parameters.extend_correlation_symbols) / static_cast(d_extend_correlation_symbols_count); + tmp_VE *= scale_factor; + tmp_E *= scale_factor; + tmp_P *= scale_factor; + tmp_L *= scale_factor; + tmp_VL *= scale_factor; + } + } + + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + tmp_long_int = d_sample_counter + static_cast(d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_long_int), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier phase rate [Hz/s] + tmp_float = d_carrier_phase_rate_step_rad * trk_parameters.fs_in * trk_parameters.fs_in / PI_2; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // code phase rate [chips/s^2] + tmp_float = d_code_phase_rate_step_chips * trk_parameters.fs_in * trk_parameters.fs_in; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = d_carr_error_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carr_error_filt_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } +} + + +int32_t dll_pll_veml_tracking::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 1; + int32_t number_of_float_vars = 19; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + std::string dump_filename_ = d_dump_filename; + // add channel number to the filename + dump_filename_.append(std::to_string(d_channel)); + // add extension + dump_filename_.append(".dat"); + std::cout << "Generating .mat file for " << dump_filename_ << std::endl; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(dump_filename_.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_VE = new float[num_epoch]; + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *abs_VL = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new float[num_epoch]; + auto *carrier_doppler_hz = new float[num_epoch]; + auto *carrier_doppler_rate_hz = new float[num_epoch]; + auto *code_freq_chips = new float[num_epoch]; + auto *code_freq_rate_chips = new float[num_epoch]; + auto *carr_error_hz = new float[num_epoch]; + auto *carr_error_filt_hz = new float[num_epoch]; + auto *code_error_chips = new float[num_epoch]; + auto *code_error_filt_chips = new float[num_epoch]; + auto *CN0_SNV_dB_Hz = new float[num_epoch]; + auto *carrier_lock_test = new float[num_epoch]; + auto *aux1 = new float[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_VE[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_VL[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_doppler_rate_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_freq_rate_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] carrier_doppler_rate_hz; + delete[] code_freq_chips; + delete[] code_freq_rate_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = dump_filename_; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_VE", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VE, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_VL", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VL, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_rate_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_doppler_rate_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_rate_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_rate_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] carrier_doppler_rate_hz; + delete[] code_freq_chips; + delete[] code_freq_rate_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void dll_pll_veml_tracking::set_channel(uint32_t channel) +{ + gr::thread::scoped_lock l(d_setlock); + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump) + { + std::string dump_filename_ = d_dump_filename; + // add channel number to the filename + dump_filename_.append(std::to_string(d_channel)); + // add extension + dump_filename_.append(".dat"); + + if (!d_dump_file.is_open()) + { + try + { + //trk_parameters.dump_filename.append(boost::lexical_cast(d_channel)); + //trk_parameters.dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(dump_filename_.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << dump_filename_.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void dll_pll_veml_tracking::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + gr::thread::scoped_lock l(d_setlock); + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +void dll_pll_veml_tracking::stop_tracking() +{ + gr::thread::scoped_lock l(d_setlock); + d_state = 0; +} + +int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + gr::thread::scoped_lock l(d_setlock); + const auto *in = reinterpret_cast(input_items[0]); + auto **out = reinterpret_cast(&output_items[0]); + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + switch (d_state) + { + case 0: // Standby - Consume samples at full throttle, do nothing + { + d_sample_counter += static_cast(ninput_items[0]); + consume_each(ninput_items[0]); + return 0; + break; + } + case 1: // Pull-in + { + // Signal alignment (skip samples until the incoming signal is aligned with local replica) + int64_t acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); + double acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / trk_parameters.fs_in; + double delta_trk_to_acq_prn_start_samples = static_cast(acq_trk_diff_samples) - d_acq_code_phase_samples; + + // Doppler effect Fd = (C / (C + Vr)) * F + double radial_velocity = (d_signal_carrier_freq + d_acq_carrier_doppler_hz) / d_signal_carrier_freq; + // new chip and PRN sequence periods based on acq Doppler + d_code_freq_chips = radial_velocity * d_code_chip_rate; + d_code_freq_chips = d_code_chip_rate; + d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + d_code_phase_rate_step_chips = 0.0; + double T_chip_mod_seconds = 1.0 / d_code_freq_chips; + double T_prn_mod_seconds = T_chip_mod_seconds * static_cast(d_code_length_chips); + double T_prn_mod_samples = T_prn_mod_seconds * trk_parameters.fs_in; + + d_acq_code_phase_samples = T_prn_mod_samples - std::fmod(delta_trk_to_acq_prn_start_samples, T_prn_mod_samples); + d_current_prn_length_samples = round(T_prn_mod_samples); + + int32_t samples_offset = round(d_acq_code_phase_samples); + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast(samples_offset); + d_state = 2; + d_sample_counter += samples_offset; // count for the processed samples + + DLOG(INFO) << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples << " ( " << acq_trk_diff_seconds << " s)"; + DLOG(INFO) << "PULL-IN Doppler [Hz] = " << d_carrier_doppler_hz + << ". PULL-IN Code Phase [samples] = " << d_acq_code_phase_samples; + + consume_each(samples_offset); // shift input to perform alignment with local replica + return 0; + } + case 2: // Wide tracking and symbol synchronization + { + do_correlation_step(in); + // Save single correlation step variables + if (d_veml) + { + d_VE_accu = *d_Very_Early; + d_VL_accu = *d_Very_Late; + } + d_E_accu = *d_Early; + d_P_accu = *d_Prompt; + d_L_accu = *d_Late; + + // Check lock status + if (!cn0_and_tracking_lock_status(d_code_period)) + { + clear_tracking_vars(); + d_state = 0; // loss-of-lock detected + } + else + { + bool next_state = false; + // Perform DLL/PLL tracking loop computations. Costas Loop enabled + run_dll_pll(); + update_tracking_vars(); + + // enable write dump file this cycle (valid DLL/PLL cycle) + log_data(false); + if (d_secondary) + { + // ####### SECONDARY CODE LOCK ##### + d_Prompt_buffer_deque.push_back(*d_Prompt); + if (d_Prompt_buffer_deque.size() == d_secondary_code_length) + { + next_state = acquire_secondary(); + if (next_state) + { + std::cout << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + } + + d_Prompt_buffer_deque.pop_front(); + } + } + else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change + { + float current_tracking_time_s = static_cast(d_sample_counter - d_acq_sample_stamp) / trk_parameters.fs_in; + if (current_tracking_time_s > 10) + { + d_symbol_history.push_back(d_Prompt->real()); + //******* preamble correlation ******** + int32_t corr_value = 0; + if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync)) + { + for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) + { + if (d_symbol_history.at(i) < 0) // symbols clipping + { + corr_value -= d_gps_l1ca_preambles_symbols[i]; + } + else + { + corr_value += d_gps_l1ca_preambles_symbols[i]; + } + } + } + if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) + { + //std::cout << "Preamble detected at tracking!" << std::endl; + next_state = true; + } + else + { + next_state = false; + } + } + else + { + next_state = false; + } + } + else + { + next_state = true; + } + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + + if (next_state) + { // reset extended correlator + d_VE_accu = gr_complex(0.0, 0.0); + d_E_accu = gr_complex(0.0, 0.0); + d_P_accu = gr_complex(0.0, 0.0); + d_L_accu = gr_complex(0.0, 0.0); + d_VL_accu = gr_complex(0.0, 0.0); + d_last_prompt = gr_complex(0.0, 0.0); + d_Prompt_buffer_deque.clear(); + d_current_symbol = 0; + + if (d_enable_extended_integration) + { + // UPDATE INTEGRATION TIME + d_extend_correlation_symbols_count = 0; + float new_correlation_time = static_cast(trk_parameters.extend_correlation_symbols) * static_cast(d_code_period); + d_carrier_loop_filter.set_pdi(new_correlation_time); + d_code_loop_filter.set_pdi(new_correlation_time); + d_state = 3; // next state is the extended correlator integrator + LOG(INFO) << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN); + std::cout << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + // Set narrow taps delay values [chips] + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_narrow_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_narrow_hz); + if (d_veml) + { + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[3] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + else + { + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + } + else + { + d_state = 4; + } + } + } + break; + } + case 3: // coherent integration (correlation time extension) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // perform a correlation step + do_correlation_step(in); + update_tracking_vars(); + save_correlation_results(); + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + d_extend_correlation_symbols_count++; + if (d_extend_correlation_symbols_count == (trk_parameters.extend_correlation_symbols - 1)) + { + d_extend_correlation_symbols_count = 0; + d_state = 4; + } + log_data(true); + break; + } + case 4: // narrow tracking + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + + // perform a correlation step + do_correlation_step(in); + save_correlation_results(); + + // check lock status + if (!cn0_and_tracking_lock_status(d_code_period * static_cast(trk_parameters.extend_correlation_symbols))) + { + clear_tracking_vars(); + d_state = 0; // loss-of-lock detected + } + else + { + run_dll_pll(); + update_tracking_vars(); + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + // enable write dump file this cycle (valid DLL/PLL cycle) + log_data(false); + // reset extended correlator + d_VE_accu = gr_complex(0.0, 0.0); + d_E_accu = gr_complex(0.0, 0.0); + d_P_accu = gr_complex(0.0, 0.0); + d_L_accu = gr_complex(0.0, 0.0); + d_VL_accu = gr_complex(0.0, 0.0); + if (d_enable_extended_integration) + { + d_state = 3; // new coherent integration (correlation time extension) cycle + } + } + } + } + consume_each(d_current_prn_length_samples); + d_sample_counter += static_cast(d_current_prn_length_samples); + if (current_synchro_data.Flag_valid_symbol_output) + { + current_synchro_data.fs = static_cast(trk_parameters.fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter; + *out[0] = current_synchro_data; + return 1; + } + return 0; +} diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h new file mode 100644 index 000000000..a79c7ffc3 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h @@ -0,0 +1,204 @@ +/*! + * \file dll_pll_veml_tracking.h + * \brief Implementation of a code DLL + carrier PLL tracking block. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DLL_PLL_VEML_TRACKING_H +#define GNSS_SDR_DLL_PLL_VEML_TRACKING_H + +#include "cpu_multicorrelator_real_codes.h" +#include "dll_pll_conf.h" +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_2nd_PLL_filter.h" +#include +#include +#include +#include +#include +#include +#include + +class dll_pll_veml_tracking; + +typedef boost::shared_ptr dll_pll_veml_tracking_sptr; + +dll_pll_veml_tracking_sptr dll_pll_veml_make_tracking(const Dll_Pll_Conf &conf_); + +/*! + * \brief This class implements a code DLL + carrier PLL tracking block. + */ +class dll_pll_veml_tracking : public gr::block +{ +public: + ~dll_pll_veml_tracking(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); + void start_tracking(); + void stop_tracking(); + + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + +private: + friend dll_pll_veml_tracking_sptr dll_pll_veml_make_tracking(const Dll_Pll_Conf &conf_); + + dll_pll_veml_tracking(const Dll_Pll_Conf &conf_); + void msg_handler_preamble_index(pmt::pmt_t msg); + + bool cn0_and_tracking_lock_status(double coh_integration_time_s); + bool acquire_secondary(); + void do_correlation_step(const gr_complex *input_samples); + void run_dll_pll(); + void update_tracking_vars(); + void clear_tracking_vars(); + void save_correlation_results(); + void log_data(bool integrating); + int32_t save_matfile(); + + // tracking configuration vars + Dll_Pll_Conf trk_parameters; + bool d_veml; + bool d_cloop; + uint32_t d_channel; + Gnss_Synchro *d_acquisition_gnss_synchro; + + //Signal parameters + bool d_secondary; + bool interchange_iq; + double d_signal_carrier_freq; + double d_code_period; + double d_code_chip_rate; + uint32_t d_secondary_code_length; + uint32_t d_code_length_chips; + uint32_t d_code_samples_per_chip; // All signals have 1 sample per chip code except Gal. E1 which has 2 (CBOC disabled) or 12 (CBOC enabled) + int32_t d_symbols_per_bit; + std::string systemName; + std::string signal_type; + std::string *d_secondary_code_string; + std::string signal_pretty_name; + + int32_t *d_gps_l1ca_preambles_symbols; + boost::circular_buffer d_symbol_history; + + //tracking state machine + int32_t d_state; + //Integration period in samples + int32_t d_correlation_length_ms; + int32_t d_n_correlator_taps; + + float *d_tracking_code; + float *d_data_code; + float *d_local_code_shift_chips; + float *d_prompt_data_shift; + cpu_multicorrelator_real_codes multicorrelator_cpu; + cpu_multicorrelator_real_codes correlator_data_cpu; //for data channel + /* TODO: currently the multicorrelator does not support adding extra correlator + with different local code, thus we need extra multicorrelator instance. + Implement this functionality inside multicorrelator class + as an enhancement to increase the performance + */ + gr_complex *d_correlator_outs; + gr_complex *d_Very_Early; + gr_complex *d_Early; + gr_complex *d_Prompt; + gr_complex *d_Late; + gr_complex *d_Very_Late; + + bool d_enable_extended_integration; + int32_t d_extend_correlation_symbols_count; + int32_t d_current_symbol; + + gr_complex d_VE_accu; + gr_complex d_E_accu; + gr_complex d_P_accu; + gr_complex d_L_accu; + gr_complex d_VL_accu; + gr_complex d_last_prompt; + + gr_complex *d_Prompt_Data; + + double d_code_phase_step_chips; + double d_code_phase_rate_step_chips; + boost::circular_buffer> d_code_ph_history; + double d_carrier_phase_step_rad; + double d_carrier_phase_rate_step_rad; + boost::circular_buffer> d_carr_ph_history; + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + float d_rem_carr_phase_rad; + + // PLL and DLL filter library + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_2nd_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + double d_carr_error_hz; + double d_carr_error_filt_hz; + double d_code_error_chips; + double d_code_error_filt_chips; + double d_code_freq_chips; + double d_carrier_doppler_hz; + double d_acc_carrier_phase_rad; + double d_rem_code_phase_chips; + double T_chip_seconds; + double T_prn_seconds; + double T_prn_samples; + double K_blk_samples; + // PRN period in samples + int32_t d_current_prn_length_samples; + // processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + int32_t d_carrier_lock_fail_counter; + std::deque d_carrier_lock_detector_queue; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + std::deque d_Prompt_buffer_deque; + gr_complex *d_Prompt_buffer; + + // file dump + std::ofstream d_dump_file; + std::string d_dump_filename; + bool d_dump; + bool d_dump_mat; +}; + +#endif // GNSS_SDR_DLL_PLL_VEML_TRACKING_H diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc new file mode 100644 index 000000000..b683e6a15 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc @@ -0,0 +1,1675 @@ +/*! + * \file dll_pll_veml_tracking_fpga.cc + * \brief Implementation of a code DLL + carrier PLL tracking block using an FPGA + * \author Marc Majoral, 2018. marc.majoral(at)cttc.es + * Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com + * Javier Arribas, 2018. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "dll_pll_veml_tracking_fpga.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "MATH_CONSTANTS.h" +#include "control_message_factory.h" +#include "gnss_sdr_create_directory.h" +#include "gps_l2c_signal.h" +#include "gps_l5_signal.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + +dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_) +{ + return dll_pll_veml_tracking_fpga_sptr(new dll_pll_veml_tracking_fpga(conf_)); +} + + +dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_) : gr::block("dll_pll_veml_tracking_fpga", gr::io_signature::make(0, 0, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + trk_parameters = conf_; + // Telemetry bit synchronization message port input + this->message_port_register_out(pmt::mp("events")); + this->set_relative_rate(1.0 / static_cast(trk_parameters.vector_length)); + + // Telemetry bit synchronization message port input (mainly for GPS L1 CA) + this->message_port_register_in(pmt::mp("preamble_samplestamp")); + + // initialize internal vars + d_veml = false; + d_cloop = true; + d_synchonizing = false; + d_code_chip_rate = 0.0; + d_secondary_code_length = 0; + d_secondary_code_string = nullptr; + signal_type = std::string(trk_parameters.signal); + + std::map map_signal_pretty_name; + map_signal_pretty_name["1C"] = "L1 C/A"; + map_signal_pretty_name["1B"] = "E1"; + map_signal_pretty_name["1G"] = "L1 C/A"; + map_signal_pretty_name["2S"] = "L2C"; + map_signal_pretty_name["2G"] = "L2 C/A"; + map_signal_pretty_name["5X"] = "E5a"; + map_signal_pretty_name["L5"] = "L5"; + + signal_pretty_name = map_signal_pretty_name[signal_type]; + + d_prompt_data_shift = nullptr; + + if (trk_parameters.system == 'G') + { + systemName = "GPS"; + if (signal_type == "1C") + { + d_signal_carrier_freq = GPS_L1_FREQ_HZ; + d_code_period = GPS_L1_CA_CODE_PERIOD; + d_code_chip_rate = GPS_L1_CA_CODE_RATE_HZ; + d_symbols_per_bit = GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; + d_correlation_length_ms = 1; + //d_code_samples_per_chip = 1; + //d_code_length_chips = static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS); + // GPS L1 C/A does not have pilot component nor secondary code + d_secondary = false; + trk_parameters.track_pilot = false; + interchange_iq = false; + + + // set the preamble + uint16_t preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE; + + // preamble bits to sampled symbols + d_gps_l1ca_preambles_symbols = static_cast(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int32_t), volk_gnsssdr_get_alignment())); + int32_t n = 0; + for (unsigned short preambles_bit : preambles_bits) + { + for (uint32_t j = 0; j < GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; j++) + { + if (preambles_bit == 1) + { + d_gps_l1ca_preambles_symbols[n] = 1; + } + else + { + d_gps_l1ca_preambles_symbols[n] = -1; + } + n++; + } + } + d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size + d_symbol_history.clear(); // Clear all the elements in the buffer + } + else if (signal_type == "2S") + { + d_signal_carrier_freq = GPS_L2_FREQ_HZ; + d_code_period = GPS_L2_M_PERIOD; + d_code_chip_rate = GPS_L2_M_CODE_RATE_HZ; + //d_code_length_chips = static_cast(GPS_L2_M_CODE_LENGTH_CHIPS); + d_symbols_per_bit = GPS_L2_SAMPLES_PER_SYMBOL; + d_correlation_length_ms = 20; + //d_code_samples_per_chip = 1; + // GPS L2 does not have pilot component nor secondary code + d_secondary = false; + trk_parameters.track_pilot = false; + interchange_iq = false; + } + else if (signal_type == "L5") + { + d_signal_carrier_freq = GPS_L5_FREQ_HZ; + d_code_period = GPS_L5i_PERIOD; + d_code_chip_rate = GPS_L5i_CODE_RATE_HZ; + d_symbols_per_bit = GPS_L5_SAMPLES_PER_SYMBOL; + d_correlation_length_ms = 1; + //d_code_samples_per_chip = 1; + //d_code_length_chips = static_cast(GPS_L5i_CODE_LENGTH_CHIPS); + d_secondary = true; + // interchange_iq = false; + if (trk_parameters.track_pilot) + { + d_secondary_code_length = static_cast(GPS_L5q_NH_CODE_LENGTH); + d_secondary_code_string = const_cast(&GPS_L5q_NH_CODE_STR); + signal_pretty_name = signal_pretty_name + "Q"; + interchange_iq = true; + } + else + { + d_secondary_code_length = static_cast(GPS_L5i_NH_CODE_LENGTH); + d_secondary_code_string = const_cast(&GPS_L5i_NH_CODE_STR); + signal_pretty_name = signal_pretty_name + "I"; + interchange_iq = false; + } + } + else + { + LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks"; + std::cerr << "Invalid Signal argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + //d_code_length_chips = 0; + //d_code_samples_per_chip = 0; + d_symbols_per_bit = 0; + } + } + else if (trk_parameters.system == 'E') + { + systemName = "Galileo"; + if (signal_type == "1B") + { + d_signal_carrier_freq = Galileo_E1_FREQ_HZ; + d_code_period = Galileo_E1_CODE_PERIOD; + d_code_chip_rate = Galileo_E1_CODE_CHIP_RATE_HZ; + //d_code_length_chips = static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS); + d_symbols_per_bit = 1; + d_correlation_length_ms = 4; + //d_code_samples_per_chip = 2; // CBOC disabled: 2 samples per chip. CBOC enabled: 12 samples per chip + d_veml = true; + if (trk_parameters.track_pilot) + { + d_secondary = true; + d_secondary_code_length = static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH); + d_secondary_code_string = const_cast(&Galileo_E1_C_SECONDARY_CODE); + signal_pretty_name = signal_pretty_name + "C"; + } + else + { + d_secondary = false; + signal_pretty_name = signal_pretty_name + "B"; + } + interchange_iq = false; // Note that E1-B and E1-C are in anti-phase, NOT IN QUADRATURE. See Galileo ICD. + } + else if (signal_type == "5X") + { + d_signal_carrier_freq = Galileo_E5a_FREQ_HZ; + d_code_period = GALILEO_E5a_CODE_PERIOD; + d_code_chip_rate = Galileo_E5a_CODE_CHIP_RATE_HZ; + d_symbols_per_bit = 20; + d_correlation_length_ms = 1; + //d_code_samples_per_chip = 1; + //d_code_length_chips = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); + d_secondary = true; + //interchange_iq = false; + if (trk_parameters.track_pilot) + { + d_secondary_code_length = static_cast(Galileo_E5a_Q_SECONDARY_CODE_LENGTH); + signal_pretty_name = signal_pretty_name + "Q"; + interchange_iq = true; + } + else + { + d_secondary_code_length = static_cast(Galileo_E5a_I_SECONDARY_CODE_LENGTH); + d_secondary_code_string = const_cast(&Galileo_E5a_I_SECONDARY_CODE); + signal_pretty_name = signal_pretty_name + "I"; + interchange_iq = false; + } + } + else + { + LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks"; + std::cout << "Invalid Signal argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + //d_code_length_chips = 0; + //d_code_samples_per_chip = 0; + d_symbols_per_bit = 0; + } + } + else + { + LOG(WARNING) << "Invalid System argument when instantiating tracking blocks"; + std::cerr << "Invalid System argument when instantiating tracking blocks" << std::endl; + d_correlation_length_ms = 1; + d_secondary = false; + interchange_iq = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + //d_code_length_chips = 0; + //d_code_samples_per_chip = 0; + d_symbols_per_bit = 0; + } + T_chip_seconds = 0.0; + T_prn_seconds = 0.0; + T_prn_samples = 0.0; + K_blk_samples = 0.0; + + // Initialize tracking ========================================== + d_code_loop_filter = Tracking_2nd_DLL_filter(static_cast(d_code_period)); + d_carrier_loop_filter = Tracking_2nd_PLL_filter(static_cast(d_code_period)); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); + + if (d_veml) + { + // Very-Early, Early, Prompt, Late, Very-Late + d_n_correlator_taps = 5; + } + else + { + // Early, Prompt, Late + d_n_correlator_taps = 3; + } + + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + //std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); + + d_code_samples_per_chip = trk_parameters.code_samples_per_chip; // number of samples per chip + + // map memory pointers of correlator outputs + if (d_veml) + { + d_Very_Early = &d_correlator_outs[0]; + d_Early = &d_correlator_outs[1]; + d_Prompt = &d_correlator_outs[2]; + d_Late = &d_correlator_outs[3]; + d_Very_Late = &d_correlator_outs[4]; + // printf("aaaa very early %f\n",-trk_parameters.very_early_late_space_chips); + // printf("aaaa early %f\n",-trk_parameters.early_late_space_chips); + // printf("aaaa normal %f\n",0); + // printf("aaaa late %f\n",trk_parameters.early_late_space_chips); + // printf("aaaa very late %f\n",trk_parameters.very_early_late_space_chips); + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = 0.0; + d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_prompt_data_shift = &d_local_code_shift_chips[2]; + } + else + { + d_Very_Early = nullptr; + d_Early = &d_correlator_outs[0]; + d_Prompt = &d_correlator_outs[1]; + d_Late = &d_correlator_outs[2]; + d_Very_Late = nullptr; + // printf("aaaa early %f\n",-trk_parameters.early_late_space_chips); + // printf("aaaa normal %f\n",0); + // printf("aaaa late %f\n",trk_parameters.early_late_space_chips); + + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_prompt_data_shift = &d_local_code_shift_chips[1]; + } + + if (trk_parameters.extend_correlation_symbols > 1) + { + d_enable_extended_integration = true; + } + else + { + d_enable_extended_integration = false; + trk_parameters.extend_correlation_symbols = 1; + } + + // Enable Data component prompt correlator (slave to Pilot prompt) if tracking uses Pilot signal + if (trk_parameters.track_pilot) + { + // Extra correlator for the data component + //d_Prompt_Data = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); + //d_Prompt_Data[0] = gr_complex(0.0, 0.0); + } + else + { + //d_Prompt_Data = nullptr; + } + + //--- Initializations ---// + // Initial code frequency basis of NCO + d_code_freq_chips = d_code_chip_rate; + // Residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // Residual carrier phase + d_rem_carr_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; + d_acq_sample_stamp = 0ULL; + d_absolute_samples_offset = 0ULL; + + d_current_prn_length_samples = static_cast(trk_parameters.vector_length); + d_next_prn_length_samples = d_current_prn_length_samples; + d_correlation_length_samples = static_cast(trk_parameters.vector_length); // this one is only for initialisation and does not change its value (MM) + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[trk_parameters.cn0_samples]; + d_carrier_lock_test = 1.0; + d_CN0_SNV_dB_Hz = 0.0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = trk_parameters.carrier_lock_th; + d_Prompt_Data = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + //clear_tracking_vars(); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_acc_carrier_phase_rad = 0.0; + + d_extend_correlation_symbols_count = 0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_K_blk_samples = 0.0; + d_code_phase_samples = 0.0; + d_last_prompt = gr_complex(0.0, 0.0); + d_state = 0; // initial state: standby + clear_tracking_vars(); + + //printf("hhhhhhhhhhh d_n_correlator_taps = %d\n", d_n_correlator_taps); + + // create multicorrelator class + std::string device_name = trk_parameters.device_name; + uint32_t device_base = trk_parameters.device_base; + int32_t *ca_codes = trk_parameters.ca_codes; + int32_t *data_codes = trk_parameters.data_codes; + //uint32_t code_length = trk_parameters.code_length_chips; + d_code_length_chips = trk_parameters.code_length_chips; + uint32_t multicorr_type = trk_parameters.multicorr_type; + multicorrelator_fpga = std::make_shared(d_n_correlator_taps, device_name, device_base, ca_codes, data_codes, d_code_length_chips, trk_parameters.track_pilot, multicorr_type, d_code_samples_per_chip); + multicorrelator_fpga->set_output_vectors(d_correlator_outs, d_Prompt_Data); + + d_pull_in = 0; + + d_dump = trk_parameters.dump; + d_dump_mat = trk_parameters.dump_mat and d_dump; + if (d_dump) + { + d_dump_filename = trk_parameters.dump_filename; + std::string dump_path; + if (d_dump_filename.find_last_of('/') != std::string::npos) + { + std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); + dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/')); + d_dump_filename = dump_filename_; + } + else + { + dump_path = std::string("."); + } + if (d_dump_filename.empty()) + { + d_dump_filename = "trk_channel_"; + } + // remove extension if any + if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos) + { + d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.')); + } + + d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; + + // create directory + if (!gnss_sdr_create_directory(dump_path)) + { + std::cerr << "GNSS-SDR cannot create dump files for the tracking block. Wrong permissions?" << std::endl; + d_dump = false; + }; + } +} + + +void dll_pll_veml_tracking_fpga::start_tracking() +{ + // correct the code phase according to the delay between acq and trk + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + double acq_trk_diff_seconds = 0; // when using the FPGA we don't use the global sample counter + // Doppler effect Fd = (C / (C + Vr)) * F + double radial_velocity = (d_signal_carrier_freq + d_acq_carrier_doppler_hz) / d_signal_carrier_freq; + // new chip and PRN sequence periods based on acq Doppler + d_code_freq_chips = radial_velocity * d_code_chip_rate; + d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + + double T_chip_mod_seconds = 1.0 / d_code_freq_chips; + double T_prn_mod_seconds = T_chip_mod_seconds * static_cast(d_code_length_chips); + double T_prn_mod_samples = T_prn_mod_seconds * trk_parameters.fs_in; + + //d_current_prn_length_samples = std::round(T_prn_mod_samples); + d_current_prn_length_samples = std::floor(T_prn_mod_samples); + d_next_prn_length_samples = d_current_prn_length_samples; + double T_prn_true_seconds = static_cast(d_code_length_chips) / d_code_chip_rate; + double T_prn_true_samples = T_prn_true_seconds * trk_parameters.fs_in; + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples = std::fmod(d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * trk_parameters.fs_in, T_prn_true_samples); + if (corrected_acq_phase_samples < 0.0) + { + corrected_acq_phase_samples += T_prn_mod_samples; + } + double delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(); // initialize the carrier filter + d_code_loop_filter.initialize(); // initialize the code filter + + if (systemName == "GPS" and signal_type == "1C") + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + else if (systemName == "GPS" and signal_type == "2S") + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + else if (systemName == "GPS" and signal_type == "L5") + { + if (trk_parameters.track_pilot) + { + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + } + else + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + } + else if (systemName == "Galileo" and signal_type == "1B") + { + if (trk_parameters.track_pilot) + { + //char pilot_signal[3] = "1C"; + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + // MISSING _: set_local_code_and_taps for the data correlator + } + else + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + } + else if (systemName == "Galileo" and signal_type == "5X") + { + if (trk_parameters.track_pilot) + { + d_secondary_code_string = const_cast(&Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1]); + for (uint32_t i = 0; i < d_code_length_chips; i++) + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + d_Prompt_Data[0] = gr_complex(0.0, 0.0); + } + else + { + for (uint32_t i = 0; i < d_code_length_chips; i++) + { + // nothing to compute : the local codes are pre-computed in the adapter class + } + } + } + + std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_cn0_estimation_counter = 0; + d_carrier_lock_test = 1.0; + d_CN0_SNV_dB_Hz = 0.0; + + if (d_veml) + { + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); + } + else + { + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); + } + + d_code_phase_samples = d_acq_code_phase_samples; + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); + d_carrier_loop_filter.set_pdi(static_cast(d_code_period)); + d_code_loop_filter.set_pdi(static_cast(d_code_period)); + + // DEBUG OUTPUT + std::cout << "Tracking of " << systemName << " " << signal_pretty_name << " signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + d_synchonizing = false; + d_cloop = true; + d_Prompt_buffer_deque.clear(); + d_last_prompt = gr_complex(0.0, 0.0); + LOG(INFO) << "PULL-IN Doppler [Hz] = " << d_carrier_doppler_hz + << ". Code Phase correction [samples] = " << delay_correction_samples + << ". PULL-IN Code Phase [samples] = " << d_acq_code_phase_samples; + //multicorrelator_fpga->set_local_code_and_taps(d_code_length_chips, d_local_code_shift_chips, d_acquisition_gnss_synchro->PRN); + multicorrelator_fpga->set_local_code_and_taps(d_local_code_shift_chips, d_prompt_data_shift, d_acquisition_gnss_synchro->PRN); + d_pull_in = 1; + // enable tracking pull-in and d_state at the end to avoid general work from starting pull-in before the start tracking function is finished + d_state = 1; +} + + +dll_pll_veml_tracking_fpga::~dll_pll_veml_tracking_fpga() +{ + if (signal_type == "1C") + { + volk_gnsssdr_free(d_gps_l1ca_preambles_symbols); + } + + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + if (d_dump_mat) + { + save_matfile(); + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_Prompt_Data); + // if (trk_parameters.track_pilot) + // { + // volk_gnsssdr_free(d_Prompt_Data); + // } + delete[] d_Prompt_buffer; + multicorrelator_fpga->free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +bool dll_pll_veml_tracking_fpga::acquire_secondary() +{ + // ******* preamble correlation ******** + int32_t corr_value = 0; + for (uint32_t i = 0; i < d_secondary_code_length; i++) + { + if (d_Prompt_buffer_deque.at(i).real() < 0.0) // symbols clipping + { + if (d_secondary_code_string->at(i) == '0') + { + corr_value++; + } + else + { + corr_value--; + } + } + else + { + if (d_secondary_code_string->at(i) == '0') + { + corr_value--; + } + else + { + corr_value++; + } + } + } + + // if (abs(corr_value) == d_secondary_code_length) + if (abs(corr_value) == static_cast(d_secondary_code_length)) + { + return true; + } + else + { + return false; + } +} + + +bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integration_time_s) +{ + //printf("kkkkkkkkkkkkk d_cn0_estimation_counter = %d\n", d_cn0_estimation_counter); + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < trk_parameters.cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_P_accu; + d_cn0_estimation_counter++; + return true; + } + else + { + //printf("KKKKKKKKKKK checking count fail ...\n"); + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, trk_parameters.cn0_samples, coh_integration_time_s); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, trk_parameters.cn0_samples); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < trk_parameters.cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > trk_parameters.max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + multicorrelator_fpga->unlock_channel(); + return false; + } + else + { + return true; + } + } +} + + +void dll_pll_veml_tracking_fpga::run_dll_pll() +{ + // ################## PLL ########################################################## + // PLL discriminator + if (d_cloop) + { + // Costas loop discriminator, insensitive to 180 deg phase transitions + d_carr_error_hz = pll_cloop_two_quadrant_atan(d_P_accu) / PI_2; + } + else + { + // Secondary code acquired. No symbols transition should be present in the signal + d_carr_error_hz = pll_four_quadrant_atan(d_P_accu) / PI_2; + } + + // Carrier discriminator filter + d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(d_carr_error_hz); + // New carrier Doppler frequency estimation + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_carr_error_filt_hz; + // New code Doppler frequency estimation + d_code_freq_chips = (1.0 + (d_carrier_doppler_hz / d_signal_carrier_freq)) * d_code_chip_rate; + + // ################## DLL ########################################################## + // DLL discriminator + if (d_veml) + { + d_code_error_chips = dll_nc_vemlp_normalized(d_VE_accu, d_E_accu, d_L_accu, d_VL_accu); // [chips/Ti] + } + else + { + d_code_error_chips = dll_nc_e_minus_l_normalized(d_E_accu, d_L_accu); // [chips/Ti] + } + // Code discriminator filter + d_code_error_filt_chips = d_code_loop_filter.get_code_nco(d_code_error_chips); // [chips/second] +} + + +void dll_pll_veml_tracking_fpga::clear_tracking_vars() +{ + std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); + //if (trk_parameters.track_pilot) *d_Prompt_Data = gr_complex(0.0, 0.0); + if (trk_parameters.track_pilot) d_Prompt_Data[0] = gr_complex(0.0, 0.0); + d_carr_error_hz = 0.0; + d_carr_error_filt_hz = 0.0; + d_code_error_chips = 0.0; + d_code_error_filt_chips = 0.0; + d_current_symbol = 0; + d_Prompt_buffer_deque.clear(); + d_last_prompt = gr_complex(0.0, 0.0); +} + + +void dll_pll_veml_tracking_fpga::update_tracking_vars() +{ + T_chip_seconds = 1.0 / d_code_freq_chips; + T_prn_seconds = T_chip_seconds * static_cast(d_code_length_chips); + double code_error_filt_secs = T_prn_seconds * d_code_error_filt_chips * T_chip_seconds; //[seconds] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + T_prn_samples = T_prn_seconds * trk_parameters.fs_in; + K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * trk_parameters.fs_in; + //d_next_prn_length_samples = round(K_blk_samples); + d_next_prn_length_samples = static_cast(std::floor(K_blk_samples)); // round to a discrete number of samples + + //################### PLL COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; + // remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad += d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, PI_2); + // carrier phase accumulator + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - static_cast(d_current_prn_length_samples); // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * d_rem_code_phase_samples / trk_parameters.fs_in; + //printf("lll d_code_freq_chips = %f\n", d_code_freq_chips); + //printf("lll d_rem_code_phase_samples = %f\n", d_rem_code_phase_samples); + //printf("lll trk_parameters.fs_in = %f\n", trk_parameters.fs_in); + //printf("lll d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); +} + + +void dll_pll_veml_tracking_fpga::save_correlation_results() +{ + if (d_secondary) + { + if (d_secondary_code_string->at(d_current_symbol) == '0') + { + if (d_veml) + { + d_VE_accu += *d_Very_Early; + d_VL_accu += *d_Very_Late; + } + d_E_accu += *d_Early; + d_P_accu += *d_Prompt; + d_L_accu += *d_Late; + } + else + { + if (d_veml) + { + d_VE_accu -= *d_Very_Early; + d_VL_accu -= *d_Very_Late; + } + d_E_accu -= *d_Early; + d_P_accu -= *d_Prompt; + d_L_accu -= *d_Late; + } + d_current_symbol++; + // secondary code roll-up + d_current_symbol %= d_secondary_code_length; + } + else + { + if (d_veml) + { + d_VE_accu += *d_Very_Early; + d_VL_accu += *d_Very_Late; + } + d_E_accu += *d_Early; + d_P_accu += *d_Prompt; + d_L_accu += *d_Late; + d_current_symbol++; + d_current_symbol %= d_symbols_per_bit; + } + // If tracking pilot, disable Costas loop + if (trk_parameters.track_pilot) + d_cloop = false; + else + d_cloop = true; +} + + +void dll_pll_veml_tracking_fpga::log_data(bool integrating) +{ + if (d_dump) + { + // Dump results to file + float prompt_I; + float prompt_Q; + float tmp_VE, tmp_E, tmp_P, tmp_L, tmp_VL; + float tmp_float; + double tmp_double; + uint64_t tmp_long_int; + if (trk_parameters.track_pilot) + { + if (interchange_iq) + { + prompt_I = d_Prompt_Data->imag(); + prompt_Q = d_Prompt_Data->real(); + } + else + { + prompt_I = d_Prompt_Data->real(); + prompt_Q = d_Prompt_Data->imag(); + } + } + else + { + if (interchange_iq) + { + prompt_I = d_Prompt->imag(); + prompt_Q = d_Prompt->real(); + } + else + { + prompt_I = d_Prompt->real(); + prompt_Q = d_Prompt->imag(); + } + } + if (d_veml) + { + tmp_VE = std::abs(d_VE_accu); + tmp_VL = std::abs(d_VL_accu); + } + else + { + tmp_VE = 0.0; + tmp_VL = 0.0; + } + tmp_E = std::abs(d_E_accu); + tmp_P = std::abs(d_P_accu); + tmp_L = std::abs(d_L_accu); + if (integrating) + { + //TODO: Improve this solution! + // It compensates the amplitude difference while integrating + if (d_extend_correlation_symbols_count > 0) + { + float scale_factor = static_cast(trk_parameters.extend_correlation_symbols) / static_cast(d_extend_correlation_symbols_count); + tmp_VE *= scale_factor; + tmp_E *= scale_factor; + tmp_P *= scale_factor; + tmp_L *= scale_factor; + tmp_VL *= scale_factor; + } + } + + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + tmp_long_int = d_sample_counter + static_cast(d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_long_int), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = d_carr_error_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carr_error_filt_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } +} + + +int32_t dll_pll_veml_tracking_fpga::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 1; + int32_t number_of_float_vars = 17; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + std::string dump_filename_ = d_dump_filename; + // add channel number to the filename + dump_filename_.append(std::to_string(d_channel)); + // add extension + dump_filename_.append(".dat"); + std::cout << "Generating .mat file for " << dump_filename_ << std::endl; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(dump_filename_.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_VE = new float[num_epoch]; + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *abs_VL = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new float[num_epoch]; + auto *carrier_doppler_hz = new float[num_epoch]; + auto *code_freq_chips = new float[num_epoch]; + auto *carr_error_hz = new float[num_epoch]; + auto *carr_error_filt_hz = new float[num_epoch]; + auto *code_error_chips = new float[num_epoch]; + auto *code_error_filt_chips = new float[num_epoch]; + auto *CN0_SNV_dB_Hz = new float[num_epoch]; + auto *carrier_lock_test = new float[num_epoch]; + auto *aux1 = new float[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_VE[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_VL[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = dump_filename_; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_VE", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VE, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_VL", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VL, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel) +{ + d_channel = channel; + multicorrelator_fpga->set_channel(d_channel); + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump) + { + std::string dump_filename_ = d_dump_filename; + // add channel number to the filename + dump_filename_.append(std::to_string(d_channel)); + // add extension + dump_filename_.append(".dat"); + + if (!d_dump_file.is_open()) + { + try + { + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(dump_filename_.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << dump_filename_.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void dll_pll_veml_tracking_fpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + +void dll_pll_veml_tracking_fpga::stop_tracking() +{ + gr::thread::scoped_lock l(d_setlock); + d_state = 0; +} + +int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + gr::thread::scoped_lock l(d_setlock); + // Block input data and block output stream pointers + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + d_current_prn_length_samples = d_next_prn_length_samples; + current_synchro_data = *d_acquisition_gnss_synchro; + + switch (d_state) + { + case 0: // Standby - Consume samples at full throttle, do nothing + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.Tracking_sample_counter = 0ULL; // in order to reduce computational workload do not read the sample counter until we start tracking d_sample_counter + d_current_prn_length_samples; + current_synchro_data.System = {'G'}; + current_synchro_data.correlation_length_ms = 1; + break; + } + case 1: // Standby - Consume samples at full throttle, do nothing + { + d_pull_in = 0; + multicorrelator_fpga->lock_channel(); + uint64_t counter_value = multicorrelator_fpga->read_sample_counter(); + //printf("333333 counter_value = %llu\n", counter_value); + //printf("333333 current_synchro_data.Acq_samplestamp_samples = %d\n", current_synchro_data.Acq_samplestamp_samples); + //printf("333333 current_synchro_data.Acq_delay_samples = %f\n", current_synchro_data.Acq_delay_samples); + //printf("333333 d_correlation_length_samples = %d\n", d_correlation_length_samples); + uint32_t num_frames = ceil((counter_value - current_synchro_data.Acq_samplestamp_samples - current_synchro_data.Acq_delay_samples) / d_correlation_length_samples); + //printf("333333 num_frames = %d\n", num_frames); + auto absolute_samples_offset = static_cast(current_synchro_data.Acq_delay_samples + current_synchro_data.Acq_samplestamp_samples + num_frames * d_correlation_length_samples); + //printf("333333 absolute_samples_offset = %llu\n", absolute_samples_offset); + multicorrelator_fpga->set_initial_sample(absolute_samples_offset); + d_absolute_samples_offset = absolute_samples_offset; + d_sample_counter = absolute_samples_offset; + current_synchro_data.Tracking_sample_counter = absolute_samples_offset; + d_sample_counter_next = d_sample_counter; + d_state = 2; + return 0; + break; + } + + case 2: + { + d_sample_counter = d_sample_counter_next; + d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, d_carrier_phase_step_rad, + d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), + d_current_prn_length_samples); + + // Save single correlation step variables + if (d_veml) + { + d_VE_accu = *d_Very_Early; + d_VL_accu = *d_Very_Late; + } + d_E_accu = *d_Early; + d_P_accu = *d_Prompt; + d_L_accu = *d_Late; + + if (!cn0_and_tracking_lock_status(d_code_period)) + { + clear_tracking_vars(); + d_state = 0; // loss-of-lock detected + } + else + { + bool next_state = false; + // Perform DLL/PLL tracking loop computations. Costas Loop enabled + run_dll_pll(); + update_tracking_vars(); + + // enable write dump file this cycle (valid DLL/PLL cycle) + log_data(false); + if (d_secondary) + { + // ####### SECONDARY CODE LOCK ##### + d_Prompt_buffer_deque.push_back(*d_Prompt); + if (d_Prompt_buffer_deque.size() == d_secondary_code_length) + { + next_state = acquire_secondary(); + if (next_state) + { + std::cout << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + } + + d_Prompt_buffer_deque.pop_front(); + } + } + else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change + { + // if (d_synchonizing) + // { + // if (d_Prompt->real() * d_last_prompt.real() > 0.0) + // { + // d_current_symbol++; + // } + // else if (d_current_symbol > d_symbols_per_bit) + // { + // d_synchonizing = false; + // d_current_symbol = 1; + // } + // else + // { + // d_current_symbol = 1; + // d_last_prompt = *d_Prompt; + // } + // } + // else if (d_last_prompt.real() != 0.0) + // { + // d_current_symbol++; + // if (d_current_symbol == d_symbols_per_bit) next_state = true; + // } + // else + // { + // d_last_prompt = *d_Prompt; + // d_synchonizing = true; + // d_current_symbol = 1; + // } + // } + //=========================================================================================================== + //float current_tracking_time_s = static_cast(d_sample_counter - d_acq_sample_stamp) / trk_parameters.fs_in; + float current_tracking_time_s = static_cast(d_sample_counter - d_absolute_samples_offset) / trk_parameters.fs_in; + if (current_tracking_time_s > 10) + { + d_symbol_history.push_back(d_Prompt->real()); + //******* preamble correlation ******** + int32_t corr_value = 0; + if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync)) + { + for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) + { + if (d_symbol_history.at(i) < 0) // symbols clipping + { + corr_value -= d_gps_l1ca_preambles_symbols[i]; + } + else + { + corr_value += d_gps_l1ca_preambles_symbols[i]; + } + } + } + if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) + { + //std::cout << "Preamble detected at tracking!" << std::endl; + next_state = true; + } + else + { + next_state = false; + } + } + else + { + next_state = false; + } + } + else + { + next_state = true; + } + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + + if (next_state) + { // reset extended correlator + d_VE_accu = gr_complex(0.0, 0.0); + d_E_accu = gr_complex(0.0, 0.0); + d_P_accu = gr_complex(0.0, 0.0); + d_L_accu = gr_complex(0.0, 0.0); + d_VL_accu = gr_complex(0.0, 0.0); + d_last_prompt = gr_complex(0.0, 0.0); + d_Prompt_buffer_deque.clear(); + d_current_symbol = 0; + d_synchonizing = false; + + if (d_enable_extended_integration) + { + // UPDATE INTEGRATION TIME + d_extend_correlation_symbols_count = 0; + float new_correlation_time = static_cast(trk_parameters.extend_correlation_symbols) * static_cast(d_code_period); + d_carrier_loop_filter.set_pdi(new_correlation_time); + d_code_loop_filter.set_pdi(new_correlation_time); + d_state = 3; // next state is the extended correlator integrator + LOG(INFO) << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN); + std::cout << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + // Set narrow taps delay values [chips] + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_narrow_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_narrow_hz); + if (d_veml) + { + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[3] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + else + { + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + } + else + { + d_state = 4; + } + } + } + + break; + } + + case 3: + { + d_sample_counter = d_sample_counter_next; + d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); + + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // perform a correlation step + multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, d_carrier_phase_step_rad, + d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), + d_current_prn_length_samples); + update_tracking_vars(); + save_correlation_results(); + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + d_extend_correlation_symbols_count++; + if (d_extend_correlation_symbols_count == (trk_parameters.extend_correlation_symbols - 1)) + { + d_extend_correlation_symbols_count = 0; + d_state = 4; + } + log_data(true); + break; + } + + case 4: // narrow tracking + { + d_sample_counter = d_sample_counter_next; + d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); + + // perform a correlation step + //do_correlation_step(in); + multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, d_carrier_phase_step_rad, + d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), + d_current_prn_length_samples); + + save_correlation_results(); + + // check lock status + if (!cn0_and_tracking_lock_status(d_code_period * static_cast(trk_parameters.extend_correlation_symbols))) + { + clear_tracking_vars(); + d_state = 0; // loss-of-lock detected + } + else + { + run_dll_pll(); + update_tracking_vars(); + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + // enable write dump file this cycle (valid DLL/PLL cycle) + log_data(false); + // reset extended correlator + d_VE_accu = gr_complex(0.0, 0.0); + d_E_accu = gr_complex(0.0, 0.0); + d_P_accu = gr_complex(0.0, 0.0); + d_L_accu = gr_complex(0.0, 0.0); + d_VL_accu = gr_complex(0.0, 0.0); + if (d_enable_extended_integration) + { + d_state = 3; // new coherent integration (correlation time extension) cycle + } + } + } + } + if (current_synchro_data.Flag_valid_symbol_output) + { + current_synchro_data.fs = static_cast(trk_parameters.fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + *out[0] = current_synchro_data; + return 1; + } + return 0; +} + + +void dll_pll_veml_tracking_fpga::reset(void) +{ + multicorrelator_fpga->unlock_channel(); +} diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h new file mode 100644 index 000000000..4230a018d --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h @@ -0,0 +1,208 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking_fpga.h + * \brief Interface of a code DLL + carrier PLL tracking block + * \author Marc Majoral, 2018. marc.majoral(at)cttc.es + * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * Cillian O'Driscoll, 2017. cillian.odriscoll(at)gmail.com + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency Approach, + * Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DLL_PLL_VEML_TRACKING_FPGA_H +#define GNSS_SDR_DLL_PLL_VEML_TRACKING_FPGA_H + +#include "dll_pll_conf_fpga.h" +#include "fpga_multicorrelator.h" +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_2nd_PLL_filter.h" +#include +#include +#include +#include +#include +#include + +class dll_pll_veml_tracking_fpga; + +typedef boost::shared_ptr + dll_pll_veml_tracking_fpga_sptr; + +dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class dll_pll_veml_tracking_fpga : public gr::block +{ +public: + ~dll_pll_veml_tracking_fpga(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); + void start_tracking(); + void stop_tracking(); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + + void reset(void); + +private: + friend dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_); + + dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_); + void msg_handler_preamble_index(pmt::pmt_t msg); + + bool cn0_and_tracking_lock_status(double coh_integration_time_s); + bool acquire_secondary(); + void run_dll_pll(); + void update_tracking_vars(); + void clear_tracking_vars(); + void save_correlation_results(); + void log_data(bool integrating); + int32_t save_matfile(); + + // tracking configuration vars + Dll_Pll_Conf_Fpga trk_parameters; + //dllpllconf_fpga_t trk_parameters; + bool d_veml; + bool d_cloop; + uint32_t d_channel; + Gnss_Synchro *d_acquisition_gnss_synchro; + + //Signal parameters + bool d_secondary; + bool interchange_iq; + double d_signal_carrier_freq; + double d_code_period; + double d_code_chip_rate; + uint32_t d_secondary_code_length; + uint32_t d_code_length_chips; + uint32_t d_code_samples_per_chip; // All signals have 1 sample per chip code except Gal. E1 which has 2 (CBOC disabled) or 12 (CBOC enabled) + int32_t d_symbols_per_bit; + std::string systemName; + std::string signal_type; + std::string *d_secondary_code_string; + std::string signal_pretty_name; + + int32_t *d_gps_l1ca_preambles_symbols; + boost::circular_buffer d_symbol_history; + + //tracking state machine + int32_t d_state; + bool d_synchonizing; + //Integration period in samples + int32_t d_correlation_length_ms; + int32_t d_n_correlator_taps; + float *d_local_code_shift_chips; + float *d_prompt_data_shift; + std::shared_ptr multicorrelator_fpga; + + gr_complex *d_correlator_outs; + gr_complex *d_Very_Early; + gr_complex *d_Early; + gr_complex *d_Prompt; + gr_complex *d_Late; + gr_complex *d_Very_Late; + + bool d_enable_extended_integration; + int32_t d_extend_correlation_symbols_count; + int32_t d_current_symbol; + + gr_complex d_VE_accu; + gr_complex d_E_accu; + gr_complex d_P_accu; + gr_complex d_L_accu; + gr_complex d_VL_accu; + gr_complex d_last_prompt; + + gr_complex *d_Prompt_Data; + + double d_code_phase_step_chips; + double d_carrier_phase_step_rad; + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_carr_phase_rad; + + // PLL and DLL filter library + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_2nd_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + double d_carr_error_hz; + double d_carr_error_filt_hz; + double d_code_error_chips; + double d_code_error_filt_chips; + double d_K_blk_samples; + double d_code_freq_chips; + double d_carrier_doppler_hz; + double d_acc_carrier_phase_rad; + double d_rem_code_phase_chips; + double d_code_phase_samples; + double T_chip_seconds; + double T_prn_seconds; + double T_prn_samples; + double K_blk_samples; + // PRN period in samples + int32_t d_current_prn_length_samples; + // processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + uint64_t d_absolute_samples_offset; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + int32_t d_carrier_lock_fail_counter; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + std::deque d_Prompt_buffer_deque; + gr_complex *d_Prompt_buffer; + + // file dump + std::ofstream d_dump_file; + std::string d_dump_filename; + bool d_dump; + bool d_dump_mat; + + // extra + int32_t d_correlation_length_samples; + int32_t d_next_prn_length_samples; + uint64_t d_sample_counter_next; + uint32_t d_pull_in = 0U; +}; + +#endif //GNSS_SDR_DLL_PLL_VEML_TRACKING_FPGA_H diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.cc deleted file mode 100755 index 6f8db9cc7..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.cc +++ /dev/null @@ -1,523 +0,0 @@ -/*! - * \file galileo_e1_dll_pll_veml_tracking_cc.cc - * \brief Implementation of a code DLL + carrier PLL VEML (Very Early - * Minus Late) tracking block for Galileo E1 signals - * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com - * - * Code DLL + carrier PLL according to the algorithms described in: - * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkhauser, 2007 - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e1_dll_pll_veml_tracking_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "galileo_e1_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "Galileo_E1.h" -#include "control_message_factory.h" - - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 - - -using google::LogMessage; - -galileo_e1_dll_pll_veml_tracking_cc_sptr -galileo_e1_dll_pll_veml_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips) -{ - return galileo_e1_dll_pll_veml_tracking_cc_sptr(new galileo_e1_dll_pll_veml_tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips, very_early_late_space_chips)); -} - - -void galileo_e1_dll_pll_veml_tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) -{ - if (noutput_items != 0) - { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call - } -} - - -galileo_e1_dll_pll_veml_tracking_cc::galileo_e1_dll_pll_veml_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips): - gr::block("galileo_e1_dll_pll_veml_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); - this->set_relative_rate(1.0 / vector_length); - - this->message_port_register_out(pmt::mp("events")); - - // initialize internal vars - d_dump = dump; - d_if_freq = if_freq; - d_fs_in = fs_in; - d_vector_length = vector_length; - d_dump_filename = dump_filename; - d_code_loop_filter = Tracking_2nd_DLL_filter(Galileo_E1_CODE_PERIOD); - d_carrier_loop_filter = Tracking_2nd_PLL_filter(Galileo_E1_CODE_PERIOD); - - // Initialize tracking ========================================== - - // Set bandwidth of code and carrier loop filters - d_code_loop_filter.set_DLL_BW(dll_bw_hz); - d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); - - // Correlator spacing - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) - d_very_early_late_spc_chips = very_early_late_space_chips; // Define very-early-late offset (in chips) - - // Initialization of local code replica - // Get space for a vector with the sinboc(1,1) replica sampled 2x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc((2 * Galileo_E1_B_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - // correlator outputs (scalar) - d_n_correlator_taps = 5; // Very-Early, Early, Prompt, Late, Very-Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - // map memory pointers of correlator outputs - d_Very_Early = &d_correlator_outs[0]; - d_Early = &d_correlator_outs[1]; - d_Prompt = &d_correlator_outs[2]; - d_Late = &d_correlator_outs[3]; - d_Very_Late = &d_correlator_outs[4]; - - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); - // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_very_early_late_spc_chips; - d_local_code_shift_chips[1] = - d_early_late_spc_chips; - d_local_code_shift_chips[2] = 0.0; - d_local_code_shift_chips[3] = d_early_late_spc_chips; - d_local_code_shift_chips[4] = d_very_early_late_spc_chips; - - d_correlation_length_samples = d_vector_length; - - multicorrelator_cpu.init(2 * d_correlation_length_samples, d_n_correlator_taps); - - //--- Initializations ------------------------------ - // Initial code frequency basis of NCO - d_code_freq_chips = static_cast(Galileo_E1_CODE_CHIP_RATE_HZ); - // Residual code phase (in chips) - d_rem_code_phase_samples = 0.0; - // Residual carrier phase - d_rem_carr_phase_rad = 0.0; - - // sample synchronization - d_sample_counter = 0; - //d_sample_counter_seconds = 0; - d_acq_sample_stamp = 0; - - d_enable_tracking = false; - d_pull_in = false; - - d_current_prn_length_samples = static_cast(d_vector_length); - - // CN0 estimation and lock detector buffers - d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; - d_carrier_lock_test = 1; - d_CN0_SNV_dB_Hz = 0; - d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; - - systemName["E"] = std::string("Galileo"); - *d_Very_Early = gr_complex(0,0); - *d_Early = gr_complex(0,0); - *d_Prompt = gr_complex(0,0); - *d_Late = gr_complex(0,0); - *d_Very_Late = gr_complex(0,0); - - d_acquisition_gnss_synchro = 0; - d_channel = 0; - d_acq_code_phase_samples = 0.0; - d_acq_carrier_doppler_hz = 0.0; - d_carrier_doppler_hz = 0.0; - d_acc_carrier_phase_rad = 0.0; - d_acc_code_phase_secs = 0.0; -} - -void galileo_e1_dll_pll_veml_tracking_cc::start_tracking() -{ - d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; - d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - - // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(); // initialize the carrier filter - d_code_loop_filter.initialize(); // initialize the code filter - - // generate local reference ALWAYS starting at chip 1 (2 samples per chip) - galileo_e1_code_gen_complex_sampled(d_ca_code, - d_acquisition_gnss_synchro->Signal, - false, - d_acquisition_gnss_synchro->PRN, - 2 * Galileo_E1_CODE_CHIP_RATE_HZ, - 0); - - multicorrelator_cpu.set_local_code_and_taps(static_cast(2 * Galileo_E1_B_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - - d_carrier_lock_fail_counter = 0; - d_rem_code_phase_samples = 0.0; - d_rem_carr_phase_rad = 0.0; - d_acc_carrier_phase_rad = 0.0; - - d_acc_code_phase_secs = 0.0; - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; - d_current_prn_length_samples = d_vector_length; - - std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0, 1); - - // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; - - // enable tracking - d_pull_in = true; - d_enable_tracking = true; - - LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; -} - -galileo_e1_dll_pll_veml_tracking_cc::~galileo_e1_dll_pll_veml_tracking_cc() -{ - d_dump_file.close(); - - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - volk_gnsssdr_free(d_ca_code); - - delete[] d_Prompt_buffer; - multicorrelator_cpu.free(); -} - - - -int galileo_e1_dll_pll_veml_tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - double carr_error_hz = 0.0; - double carr_error_filt_hz = 0.0; - double code_error_chips = 0.0; - double code_error_filt_chips = 0.0; - - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data = Gnss_Synchro(); - - if (d_enable_tracking == true) - { - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - if (d_pull_in == true) - { - /* - * Signal alignment (skip samples until the incoming signal is aligned with local replica) - */ - int samples_offset; - double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; - acq_trk_shif_correction_samples = d_current_prn_length_samples - std::fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); - samples_offset = std::round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - *out[0] = current_synchro_data; - d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples - d_pull_in = false; - consume_each(samples_offset); //shift input to perform alignment with local replica - return 1; - } - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs,in); - - double carr_phase_step_rad = GALILEO_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - double code_phase_step_half_chips = (2.0 * d_code_freq_chips) / (static_cast(d_fs_in)); - double rem_code_phase_half_chips = d_rem_code_phase_samples * (2.0*d_code_freq_chips / d_fs_in); - multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, - carr_phase_step_rad, - rem_code_phase_half_chips, - code_phase_step_half_chips, - d_correlation_length_samples); - - // ################## PLL ########################################################## - // PLL discriminator - carr_error_hz = pll_cloop_two_quadrant_atan(*d_Prompt) / GALILEO_TWO_PI; - // Carrier discriminator filter - carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); - // New carrier Doppler frequency estimation - d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = Galileo_E1_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E1_CODE_CHIP_RATE_HZ) / Galileo_E1_FREQ_HZ); - //carrier phase accumulator for (K) Doppler estimation- - d_acc_carrier_phase_rad -= GALILEO_TWO_PI * d_carrier_doppler_hz * static_cast(d_current_prn_length_samples) / static_cast(d_fs_in); - //remnant carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad = d_rem_carr_phase_rad + GALILEO_TWO_PI * d_carrier_doppler_hz * static_cast(d_current_prn_length_samples) / static_cast(d_fs_in); - d_rem_carr_phase_rad = std::fmod(d_rem_carr_phase_rad, GALILEO_TWO_PI); - - // ################## DLL ########################################################## - // DLL discriminator - code_error_chips = dll_nc_vemlp_normalized(*d_Very_Early, *d_Early, *d_Late, *d_Very_Late); //[chips/Ti] - // Code discriminator filter - code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); //[chips/second] - //Code phase accumulator - double code_error_filt_secs; - code_error_filt_secs = (Galileo_E1_CODE_PERIOD * code_error_filt_chips) / Galileo_E1_CODE_CHIP_RATE_HZ; //[seconds] - //code_error_filt_secs=T_prn_seconds*code_error_filt_chips*T_chip_seconds*static_cast(d_fs_in); //[seconds] - d_acc_code_phase_secs = d_acc_code_phase_secs + code_error_filt_secs; - - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### - // keep alignment parameters for the next input buffer - double T_chip_seconds; - double T_prn_seconds; - double T_prn_samples; - double K_blk_samples; - // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation - T_chip_seconds = 1.0 / d_code_freq_chips; - T_prn_seconds = T_chip_seconds * Galileo_E1_B_CODE_LENGTH_CHIPS; - T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); - d_current_prn_length_samples = std::round(K_blk_samples); //round to a discrete samples - //d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt; - d_cn0_estimation_counter++; - } - else - { - d_cn0_estimation_counter = 0; - - // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, Galileo_E1_B_CODE_LENGTH_CHIPS); - - // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); - - // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine - } - } - - // ########### Output the tracking results to Telemetry block ########## - - current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); - current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - //compute remnant code phase samples AFTER the Tracking timestamp - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms = 4; - - } - else - { - *d_Early = gr_complex(0,0); - *d_Prompt = gr_complex(0,0); - *d_Late = gr_complex(0,0); - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - } - //assign the GNURadio block output data - current_synchro_data.System = {'E'}; - std::string str_aux = "1B"; - const char * str = str_aux.c_str(); // get a C style null terminated string - std::memcpy((void*)current_synchro_data.Signal, str, 3); - *out[0] = current_synchro_data; - - if(d_dump) - { - // Dump results to file - float prompt_I; - float prompt_Q; - float tmp_VE, tmp_E, tmp_P, tmp_L, tmp_VL; - float tmp_float; - double tmp_double; - prompt_I = (*d_Prompt).real(); - prompt_Q = (*d_Prompt).imag(); - tmp_VE = std::abs(*d_Very_Early); - tmp_E = std::abs(*d_Early); - tmp_P = std::abs(*d_Prompt); - tmp_L = std::abs(*d_Late); - tmp_VL = std::abs(*d_Very_Late); - - try - { - // Dump correlators output - d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - tmp_float = d_acc_carrier_phase_rad; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - // carrier and code frequency - tmp_float = d_carrier_doppler_hz; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - tmp_float = d_code_freq_chips; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - //PLL commands - tmp_float = carr_error_hz; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - tmp_float = carr_error_filt_hz; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - //DLL commands - tmp_float = code_error_chips; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - tmp_float = code_error_filt_chips; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - // CN0 and carrier lock test - tmp_float = d_CN0_SNV_dB_Hz; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - tmp_float = d_carrier_lock_test; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - // AUX vars (for debug purposes) - tmp_float = d_rem_code_phase_samples; - d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); - tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what() << std::endl; - } - } - consume_each(d_current_prn_length_samples); // this is required for gr_block derivates - d_sample_counter += d_current_prn_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - - -void galileo_e1_dll_pll_veml_tracking_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what() << std::endl; - } - } - } -} - - - - -void galileo_e1_dll_pll_veml_tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; -} diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.h deleted file mode 100755 index 3377234cf..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_dll_pll_veml_tracking_cc.h +++ /dev/null @@ -1,179 +0,0 @@ -/*! - * \file galileo_e1_dll_pll_veml_tracking_cc.h - * \brief Implementation of a code DLL + carrier PLL VEML (Very Early - * Minus Late) tracking block for Galileo E1 signals - * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_CC_H -#define GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_CC_H - -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "tracking_2nd_DLL_filter.h" -#include "tracking_2nd_PLL_filter.h" -#include "cpu_multicorrelator.h" - -class galileo_e1_dll_pll_veml_tracking_cc; - -typedef boost::shared_ptr galileo_e1_dll_pll_veml_tracking_cc_sptr; - -galileo_e1_dll_pll_veml_tracking_cc_sptr -galileo_e1_dll_pll_veml_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips); - -/*! - * \brief This class implements a code DLL + carrier PLL VEML (Very Early - * Minus Late) tracking block for Galileo E1 signals - */ -class galileo_e1_dll_pll_veml_tracking_cc: public gr::block -{ -public: - ~galileo_e1_dll_pll_veml_tracking_cc(); - - void set_channel(unsigned int channel); - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); - void start_tracking(); - - /*! - * \brief Code DLL + carrier PLL according to the algorithms described in: - * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency Approach, - * Birkhauser, 2007 - */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - void forecast (int noutput_items, gr_vector_int &ninput_items_required); -private: - friend galileo_e1_dll_pll_veml_tracking_cc_sptr - galileo_e1_dll_pll_veml_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips); - - galileo_e1_dll_pll_veml_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips); - - void update_local_code(); - - void update_local_carrier(); - - // tracking configuration vars - unsigned int d_vector_length; - bool d_dump; - - Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; - long d_if_freq; - long d_fs_in; - - //Integration period in samples - int d_correlation_length_samples; - int d_n_correlator_taps; - double d_early_late_spc_chips; - double d_very_early_late_spc_chips; - - gr_complex* d_ca_code; - float* d_local_code_shift_chips; - gr_complex* d_correlator_outs; - cpu_multicorrelator multicorrelator_cpu; - - gr_complex *d_Very_Early; - gr_complex *d_Early; - gr_complex *d_Prompt; - gr_complex *d_Late; - gr_complex *d_Very_Late; - - // remaining code phase and carrier phase between tracking loops - double d_rem_code_phase_samples; - double d_rem_carr_phase_rad; - - // PLL and DLL filter library - Tracking_2nd_DLL_filter d_code_loop_filter; - Tracking_2nd_PLL_filter d_carrier_loop_filter; - - // acquisition - double d_acq_code_phase_samples; - double d_acq_carrier_doppler_hz; - - // tracking vars - double d_code_freq_chips; - double d_carrier_doppler_hz; - double d_acc_carrier_phase_rad; - double d_acc_code_phase_secs; - - //PRN period in samples - int d_current_prn_length_samples; - - //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; - - // CN0 estimation and lock detector - int d_cn0_estimation_counter; - gr_complex* d_Prompt_buffer; - double d_carrier_lock_test; - double d_CN0_SNV_dB_Hz; - double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; - - // control vars - bool d_enable_tracking; - bool d_pull_in; - - // file dump - std::string d_dump_filename; - std::ofstream d_dump_file; - - std::map systemName; - std::string sys; -}; - -#endif //GNSS_SDR_GALILEO_E1_DLL_PLL_VEML_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.cc index 6b85f664f..2c755b088 100644 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.cc @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,96 +31,85 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_e1_tcp_connector_tracking_cc.h" +#include "GPS_L1_CA.h" +#include "Galileo_E1.h" +#include "control_message_factory.h" +#include "galileo_e1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tcp_communication.h" +#include "tcp_packet_data.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include "galileo_e1_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "Galileo_E1.h" -#include "control_message_factory.h" -#include "tcp_communication.h" -#include "tcp_packet_data.h" +#include -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 using google::LogMessage; galileo_e1_tcp_connector_tracking_cc_sptr galileo_e1_tcp_connector_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips, - size_t port_ch0) + int64_t fs_in, + uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + float very_early_late_space_chips, + size_t port_ch0) { - return galileo_e1_tcp_connector_tracking_cc_sptr(new Galileo_E1_Tcp_Connector_Tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips, very_early_late_space_chips, port_ch0)); + return galileo_e1_tcp_connector_tracking_cc_sptr(new Galileo_E1_Tcp_Connector_Tracking_cc( + fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips, very_early_late_space_chips, port_ch0)); } -void Galileo_E1_Tcp_Connector_Tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void Galileo_E1_Tcp_Connector_Tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = (int)d_vector_length*2; // set the required available samples in each call + ninput_items_required[0] = static_cast(d_vector_length) * 2; // set the required available samples in each call } } Galileo_E1_Tcp_Connector_Tracking_cc::Galileo_E1_Tcp_Connector_Tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz __attribute__((unused)), - float dll_bw_hz __attribute__((unused)), - float early_late_space_chips, - float very_early_late_space_chips, - size_t port_ch0): - gr::block("Galileo_E1_Tcp_Connector_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + int64_t fs_in, + uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float pll_bw_hz __attribute__((unused)), + float dll_bw_hz __attribute__((unused)), + float early_late_space_chips, + float very_early_late_space_chips, + size_t port_ch0) : gr::block("Galileo_E1_Tcp_Connector_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); this->message_port_register_out(pmt::mp("events")); - this->set_relative_rate(1.0/vector_length); + this->set_relative_rate(1.0 / vector_length); // initialize internal vars d_dump = dump; - d_if_freq = if_freq; d_fs_in = fs_in; d_vector_length = vector_length; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); // Initialize tracking ========================================== //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) - d_very_early_late_spc_chips = very_early_late_space_chips; // Define very-early-late offset (in chips) + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + d_very_early_late_spc_chips = very_early_late_space_chips; // Define very-early-late offset (in chips) //--- TCP CONNECTOR variables -------------------------------------------------------- d_port_ch0 = port_ch0; @@ -130,14 +119,14 @@ Galileo_E1_Tcp_Connector_Tracking_cc::Galileo_E1_Tcp_Connector_Tracking_cc( // Initialization of local code replica // Get space for a vector with the sinboc(1,1) replica sampled 2x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc((2*Galileo_E1_B_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code = static_cast(volk_gnsssdr_malloc((2 * Galileo_E1_B_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // correlator outputs (scalar) - d_n_correlator_taps = 5; // Very-Early, Early, Prompt, Late, Very-Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) + d_n_correlator_taps = 5; // Very-Early, Early, Prompt, Late, Very-Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } // map memory pointers of correlator outputs d_Very_Early = &d_correlator_outs[0]; @@ -146,16 +135,16 @@ Galileo_E1_Tcp_Connector_Tracking_cc::Galileo_E1_Tcp_Connector_Tracking_cc( d_Late = &d_correlator_outs[3]; d_Very_Late = &d_correlator_outs[4]; - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_very_early_late_spc_chips; - d_local_code_shift_chips[1] = - d_early_late_spc_chips; + d_local_code_shift_chips[0] = -d_very_early_late_spc_chips; + d_local_code_shift_chips[1] = -d_early_late_spc_chips; d_local_code_shift_chips[2] = 0.0; d_local_code_shift_chips[3] = d_early_late_spc_chips; d_local_code_shift_chips[4] = d_very_early_late_spc_chips; d_correlation_length_samples = d_vector_length; - + multicorrelator_cpu.init(2 * d_correlation_length_samples, d_n_correlator_taps); //--- Perform initializations ------------------------------ @@ -167,24 +156,24 @@ Galileo_E1_Tcp_Connector_Tracking_cc::Galileo_E1_Tcp_Connector_Tracking_cc( d_rem_carr_phase_rad = 0.0; // sample synchronization - d_sample_counter = 0; + d_sample_counter = 0ULL; d_acq_sample_stamp = 0; d_enable_tracking = false; d_pull_in = false; - d_current_prn_length_samples = (int)d_vector_length; + d_current_prn_length_samples = static_cast(d_vector_length); // CN0 estimation and lock detector buffers d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; d_carrier_lock_test = 1; d_CN0_SNV_dB_Hz = 0; d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; systemName["E"] = std::string("Galileo"); - d_acquisition_gnss_synchro = 0; + d_acquisition_gnss_synchro = nullptr; d_channel = 0; d_next_rem_code_phase_samples = 0; d_acq_code_phase_samples = 0.0; @@ -197,25 +186,24 @@ Galileo_E1_Tcp_Connector_Tracking_cc::Galileo_E1_Tcp_Connector_Tracking_cc( } - void Galileo_E1_Tcp_Connector_Tracking_cc::start_tracking() { d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; // generate local reference ALWAYS starting at chip 1 (2 samples per chip) galileo_e1_code_gen_complex_sampled(d_ca_code, - d_acquisition_gnss_synchro->Signal, - false, - d_acquisition_gnss_synchro->PRN, - 2 * Galileo_E1_CODE_CHIP_RATE_HZ, - 0); + d_acquisition_gnss_synchro->Signal, + false, + d_acquisition_gnss_synchro->PRN, + 2 * Galileo_E1_CODE_CHIP_RATE_HZ, + 0); - multicorrelator_cpu.set_local_code_and_taps(static_cast(2*Galileo_E1_B_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) + multicorrelator_cpu.set_local_code_and_taps(static_cast(2 * Galileo_E1_B_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } d_carrier_lock_fail_counter = 0; @@ -228,11 +216,11 @@ void Galileo_E1_Tcp_Connector_Tracking_cc::start_tracking() d_current_prn_length_samples = d_vector_length; std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); + sys = sys_.substr(0, 1); // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + std::cout << "Tracking of Galileo E1 signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of Galileo E1 signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; // enable tracking d_pull_in = true; @@ -244,262 +232,34 @@ void Galileo_E1_Tcp_Connector_Tracking_cc::start_tracking() Galileo_E1_Tcp_Connector_Tracking_cc::~Galileo_E1_Tcp_Connector_Tracking_cc() { - d_dump_file.close(); - - delete[] d_Prompt_buffer; - volk_gnsssdr_free(d_ca_code); - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - - d_tcp_com.close_tcp_connection(d_port); - multicorrelator_cpu.free(); -} - - -int Galileo_E1_Tcp_Connector_Tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // process vars - float carr_error_filt_hz; - float code_error_filt_chips; - - tcp_packet_data tcp_data; - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data = Gnss_Synchro(); - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - if (d_enable_tracking == true) + if (d_dump_file.is_open()) { - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - if (d_pull_in == true) - { - /* - * Signal alignment (skip samples until the incoming signal is aligned with local replica) - */ - int samples_offset; - float acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; - acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod((float)acq_to_trk_delay_samples, (float)d_current_prn_length_samples); - samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - *out[0] = current_synchro_data; - d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples - d_pull_in = false; - consume_each(samples_offset); //shift input to perform alignment with local replica - return 1; - } - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs,in); - - double carr_phase_step_rad = GALILEO_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - double code_phase_step_half_chips = (2.0 * d_code_freq_chips) / (static_cast(d_fs_in)); - double rem_code_phase_half_chips = d_rem_code_phase_samples * (2.0*d_code_freq_chips / d_fs_in); - multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, - carr_phase_step_rad, - rem_code_phase_half_chips, - code_phase_step_half_chips, - d_correlation_length_samples); - - // ################## TCP CONNECTOR ########################################################## - //! Variable used for control - d_control_id++; - - //! Send and receive a TCP packet - boost::array tx_variables_array = {{d_control_id, - (*d_Very_Early).real(), - (*d_Very_Early).imag(), - (*d_Early).real(), - (*d_Early).imag(), - (*d_Late).real(), - (*d_Late).imag(), - (*d_Very_Late).real(), - (*d_Very_Late).imag(), - (*d_Prompt).real(), - (*d_Prompt).imag(), - d_acq_carrier_doppler_hz, - 1}}; - d_tcp_com.send_receive_tcp_packet_galileo_e1(tx_variables_array, &tcp_data); - - // ################## PLL ########################################################## - // PLL discriminator, carrier loop filter implementation and NCO command generation (TCP_connector) - carr_error_filt_hz = tcp_data.proc_pack_carr_error; - // New carrier Doppler frequency estimation - d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = Galileo_E1_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E1_CODE_CHIP_RATE_HZ) / Galileo_E1_FREQ_HZ); - //carrier phase accumulator for (K) doppler estimation - d_acc_carrier_phase_rad -= GPS_TWO_PI*d_carrier_doppler_hz*Galileo_E1_CODE_PERIOD; - //remnant carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad = d_rem_carr_phase_rad + GPS_TWO_PI*d_carrier_doppler_hz*Galileo_E1_CODE_PERIOD; - d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GPS_TWO_PI); - - // ################## DLL ########################################################## - // DLL discriminator, carrier loop filter implementation and NCO command generation (TCP_connector) - code_error_filt_chips = tcp_data.proc_pack_code_error; - //Code phase accumulator - float code_error_filt_secs; - code_error_filt_secs = (Galileo_E1_CODE_PERIOD * code_error_filt_chips) / Galileo_E1_CODE_CHIP_RATE_HZ; //[seconds] - d_acc_code_phase_secs = d_acc_code_phase_secs + code_error_filt_secs; - - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### - // keep alignment parameters for the next input buffer - double T_chip_seconds; - double T_prn_seconds; - double T_prn_samples; - double K_blk_samples; - // Compute the next buffer lenght based in the new period of the PRN sequence and the code phase error estimation - T_chip_seconds = 1 / (double)d_code_freq_chips; - T_prn_seconds = T_chip_seconds * Galileo_E1_B_CODE_LENGTH_CHIPS; - T_prn_samples = T_prn_seconds * (double)d_fs_in; - K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * (double)d_fs_in; - d_current_prn_length_samples = round(K_blk_samples); //round to a discrete samples - //d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt; - d_cn0_estimation_counter++; - } - else - { - d_cn0_estimation_counter = 0; - - // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, Galileo_E1_B_CODE_LENGTH_CHIPS); - - // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); - - // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - - d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine - } - } - - // ########### Output the tracking data to navigation and PVT ########## - current_synchro_data.Prompt_I = (double)(*d_Prompt).real(); - current_synchro_data.Prompt_Q = (double)(*d_Prompt).imag(); - // Tracking_timestamp_secs is aligned with the PRN start sample - //current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_next_prn_length_samples + (double)d_next_rem_code_phase_samples)/(double)d_fs_in; - current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_rem_code_phase_samples)/(double)d_fs_in; - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - // This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0 - current_synchro_data.Carrier_phase_rads = (double)d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = (double)d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = (double)d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms = 4; - } - else - { - *d_Early = gr_complex(0,0); - *d_Prompt = gr_complex(0,0); - *d_Late = gr_complex(0,0); - - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - //! When tracking is disabled an array of 1's is sent to maintain the TCP connection - boost::array tx_variables_array = {{1,1,1,1,1,1,1,1,1,1,1,1,0}}; - d_tcp_com.send_receive_tcp_packet_galileo_e1(tx_variables_array, &tcp_data); - } - //assign the GNURadio block output data - current_synchro_data.System = {'E'}; - std::string str_aux = "1B"; - const char * str = str_aux.c_str(); // get a C style null terminated string - std::memcpy((void*)current_synchro_data.Signal, str, 3); - - *out[0] = current_synchro_data; - - if(d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - float prompt_I; - float prompt_Q; - float tmp_VE, tmp_E, tmp_P, tmp_L, tmp_VL; - float tmp_float; - tmp_float = 0; - double tmp_double; - prompt_I = (*d_Prompt).real(); - prompt_Q = (*d_Prompt).imag(); - tmp_VE = std::abs(*d_Very_Early); - tmp_E = std::abs(*d_Early); - tmp_P = std::abs(*d_Prompt); - tmp_L = std::abs(*d_Late); - tmp_VL = std::abs(*d_Very_Late); - try - { - // EPR - d_dump_file.write((char*)&tmp_VE, sizeof(float)); - d_dump_file.write((char*)&tmp_E, sizeof(float)); - d_dump_file.write((char*)&tmp_P, sizeof(float)); - d_dump_file.write((char*)&tmp_L, sizeof(float)); - d_dump_file.write((char*)&tmp_VL, sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write((char*)&prompt_I, sizeof(float)); - d_dump_file.write((char*)&prompt_Q, sizeof(float)); - // PRN start sample stamp - d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); - - // carrier and code frequency - d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); - d_dump_file.write((char*)&d_code_freq_chips, sizeof(float)); - - //PLL commands - d_dump_file.write((char*)&tmp_float, sizeof(float)); - d_dump_file.write((char*)&carr_error_filt_hz, sizeof(float)); - - //DLL commands - d_dump_file.write((char*)&tmp_float, sizeof(float)); - d_dump_file.write((char*)&code_error_filt_chips, sizeof(float)); - - // CN0 and carrier lock test - d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); - d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); - - // AUX vars (for debug purposes) - tmp_float = d_rem_code_phase_samples; - d_dump_file.write((char*)&tmp_float, sizeof(float)); - tmp_double = (double)(d_sample_counter+d_current_prn_length_samples); - d_dump_file.write((char*)&tmp_double, sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what(); - } + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + d_tcp_com.close_tcp_connection(d_port); + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); } - consume_each(d_current_prn_length_samples); // this is needed in gr::block derivates - d_sample_counter += d_current_prn_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false } - -void Galileo_E1_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) +void Galileo_E1_Tcp_Connector_Tracking_cc::set_channel(uint32_t channel) { d_channel = channel; LOG(INFO) << "Tracking Channel set to " << d_channel; @@ -509,17 +269,17 @@ void Galileo_E1_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) if (d_dump_file.is_open() == false) { try - { + { d_dump_filename.append(boost::lexical_cast(d_channel)); d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } + } catch (const std::ifstream::failure &e) - { + { LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } + } } } @@ -532,8 +292,258 @@ void Galileo_E1_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) } - -void Galileo_E1_Tcp_Connector_Tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +void Galileo_E1_Tcp_Connector_Tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) { d_acquisition_gnss_synchro = p_gnss_synchro; } + + +int Galileo_E1_Tcp_Connector_Tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // process vars + float carr_error_filt_hz = 0.0; + float code_error_filt_chips = 0.0; + + tcp_packet_data tcp_data; + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + // Block input data and block output stream pointers + const gr_complex *in = reinterpret_cast(input_items[0]); + Gnss_Synchro **out = reinterpret_cast(&output_items[0]); + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + if (d_pull_in == true) + { + /* + * Signal alignment (skip samples until the incoming signal is aligned with local replica) + */ + int32_t samples_offset; + float acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + d_sample_counter = d_sample_counter + static_cast(samples_offset); //count for the processed samples + d_pull_in = false; + consume_each(samples_offset); //shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + + double carr_phase_step_rad = GALILEO_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + double code_phase_step_half_chips = (2.0 * d_code_freq_chips) / (static_cast(d_fs_in)); + double rem_code_phase_half_chips = d_rem_code_phase_samples * (2.0 * d_code_freq_chips / d_fs_in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, + carr_phase_step_rad, + rem_code_phase_half_chips, + code_phase_step_half_chips, + d_correlation_length_samples); + + // ################## TCP CONNECTOR ########################################################## + //! Variable used for control + d_control_id++; + + //! Send and receive a TCP packet + boost::array tx_variables_array = {{d_control_id, + (*d_Very_Early).real(), + (*d_Very_Early).imag(), + (*d_Early).real(), + (*d_Early).imag(), + (*d_Late).real(), + (*d_Late).imag(), + (*d_Very_Late).real(), + (*d_Very_Late).imag(), + (*d_Prompt).real(), + (*d_Prompt).imag(), + d_acq_carrier_doppler_hz, + 1}}; + d_tcp_com.send_receive_tcp_packet_galileo_e1(tx_variables_array, &tcp_data); + + // ################## PLL ########################################################## + // PLL discriminator, carrier loop filter implementation and NCO command generation (TCP_connector) + carr_error_filt_hz = tcp_data.proc_pack_carr_error; + // New carrier Doppler frequency estimation + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; + // New code Doppler frequency estimation + d_code_freq_chips = Galileo_E1_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E1_CODE_CHIP_RATE_HZ) / Galileo_E1_FREQ_HZ); + //carrier phase accumulator for (K) doppler estimation + d_acc_carrier_phase_rad -= GPS_TWO_PI * d_carrier_doppler_hz * Galileo_E1_CODE_PERIOD; + //remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad = d_rem_carr_phase_rad + GPS_TWO_PI * d_carrier_doppler_hz * Galileo_E1_CODE_PERIOD; + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GPS_TWO_PI); + + // ################## DLL ########################################################## + // DLL discriminator, carrier loop filter implementation and NCO command generation (TCP_connector) + code_error_filt_chips = tcp_data.proc_pack_code_error; + //Code phase accumulator + float code_error_filt_secs; + code_error_filt_secs = (Galileo_E1_CODE_PERIOD * code_error_filt_chips) / Galileo_E1_CODE_CHIP_RATE_HZ; //[seconds] + d_acc_code_phase_secs = d_acc_code_phase_secs + code_error_filt_secs; + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + double T_chip_seconds; + double T_prn_seconds; + double T_prn_samples; + double K_blk_samples; + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + T_chip_seconds = 1 / static_cast(d_code_freq_chips); + T_prn_seconds = T_chip_seconds * Galileo_E1_B_CODE_LENGTH_CHIPS; + T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); + d_current_prn_length_samples = round(K_blk_samples); //round to a discrete samples + //d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < FLAGS_cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt; + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, Galileo_E1_CODE_PERIOD); + + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); + + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + // Tracking_timestamp_secs is aligned with the PRN start sample + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample + current_synchro_data.Carrier_phase_rads = static_cast(d_acc_carrier_phase_rad); + current_synchro_data.Carrier_Doppler_hz = static_cast(d_carrier_doppler_hz); + current_synchro_data.CN0_dB_hz = static_cast(d_CN0_SNV_dB_Hz); + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 4; + } + else + { + *d_Early = gr_complex(0, 0); + *d_Prompt = gr_complex(0, 0); + *d_Late = gr_complex(0, 0); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + //! When tracking is disabled an array of 1's is sent to maintain the TCP connection + boost::array tx_variables_array = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}}; + d_tcp_com.send_receive_tcp_packet_galileo_e1(tx_variables_array, &tcp_data); + } + //assign the GNURadio block output data + current_synchro_data.System = {'E'}; + std::string str_aux = "1B"; + const char *str = str_aux.c_str(); // get a C style null terminated string + std::memcpy(static_cast(current_synchro_data.Signal), str, 3); + + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = carr_error_filt_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + consume_each(d_current_prn_length_samples); // this is needed in gr::block derivates + d_sample_counter += d_current_prn_length_samples; //count for the processed samples + + if (d_enable_tracking) + { + return 1; + } + + return 0; +} diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.h index 8a00caa70..acce9db54 100644 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/galileo_e1_tcp_connector_tracking_cc.h @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +31,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -39,14 +39,14 @@ #ifndef GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_CC_H #define GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_CC_H +#include "cpu_multicorrelator.h" +#include "gnss_synchro.h" +#include "tcp_communication.h" +#include +#include #include #include #include -#include -#include -#include "gnss_synchro.h" -#include "cpu_multicorrelator.h" -#include "tcp_communication.h" class Galileo_E1_Tcp_Connector_Tracking_cc; @@ -54,78 +54,75 @@ class Galileo_E1_Tcp_Connector_Tracking_cc; typedef boost::shared_ptr galileo_e1_tcp_connector_tracking_cc_sptr; galileo_e1_tcp_connector_tracking_cc_sptr -galileo_e1_tcp_connector_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips, - size_t port_ch0); +galileo_e1_tcp_connector_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + float very_early_late_space_chips, + size_t port_ch0); /*! * \brief This class implements a code DLL + carrier PLL VEML (Very Early * Minus Late) tracking block for Galileo E1 signals */ -class Galileo_E1_Tcp_Connector_Tracking_cc: public gr::block +class Galileo_E1_Tcp_Connector_Tracking_cc : public gr::block { public: ~Galileo_E1_Tcp_Connector_Tracking_cc(); - void set_channel(unsigned int channel); - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); private: friend galileo_e1_tcp_connector_tracking_cc_sptr - galileo_e1_tcp_connector_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips, - size_t port_ch0); + galileo_e1_tcp_connector_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + float very_early_late_space_chips, + size_t port_ch0); - Galileo_E1_Tcp_Connector_Tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips, - float very_early_late_space_chips, - size_t port_ch0); + Galileo_E1_Tcp_Connector_Tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + float very_early_late_space_chips, + size_t port_ch0); void update_local_code(); void update_local_carrier(); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; - Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; + Gnss_Synchro *d_acquisition_gnss_synchro; + uint32_t d_channel; - long d_if_freq; - long d_fs_in; + int64_t d_fs_in; - int d_correlation_length_samples; - int d_n_correlator_taps; + int32_t d_correlation_length_samples; + int32_t d_n_correlator_taps; float d_early_late_spc_chips; float d_very_early_late_spc_chips; - gr_complex* d_ca_code; + gr_complex *d_ca_code; gr_complex *d_Very_Early; gr_complex *d_Early; @@ -143,8 +140,8 @@ private: float d_acq_carrier_doppler_hz; // correlator - float* d_local_code_shift_chips; - gr_complex* d_correlator_outs; + float *d_local_code_shift_chips; + gr_complex *d_correlator_outs; cpu_multicorrelator multicorrelator_cpu; // tracking vars @@ -155,25 +152,25 @@ private: float d_code_phase_samples; size_t d_port_ch0; size_t d_port; - int d_listen_connection; + int32_t d_listen_connection; float d_control_id; tcp_communication d_tcp_com; //PRN period in samples - int d_current_prn_length_samples; - int d_next_prn_length_samples; + int32_t d_current_prn_length_samples; + int32_t d_next_prn_length_samples; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; - gr_complex* d_Prompt_buffer; + int32_t d_cn0_estimation_counter; + gr_complex *d_Prompt_buffer; float d_carrier_lock_test; float d_CN0_SNV_dB_Hz; float d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -187,4 +184,4 @@ private: std::string sys; }; -#endif //GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_CC_H +#endif //GNSS_SDR_GALILEO_E1_TCP_CONNECTOR_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.cc deleted file mode 100644 index acf1e9bc6..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.cc +++ /dev/null @@ -1,746 +0,0 @@ -/*! - * \file galileo_e5a_dll_pll_tracking_cc.h - * \brief Implementation of a code DLL + carrier PLL - * tracking block for Galileo E5a signals - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * \based on work from: - *
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
      - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e5a_dll_pll_tracking_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include "galileo_e5_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "Galileo_E5a.h" -#include "Galileo_E1.h" -#include "control_message_factory.h" - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 - - -using google::LogMessage; - -galileo_e5a_dll_pll_tracking_cc_sptr -galileo_e5a_dll_pll_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_init_hz, - float dll_bw_init_hz, - int ti_ms, - float early_late_space_chips) -{ - return galileo_e5a_dll_pll_tracking_cc_sptr(new Galileo_E5a_Dll_Pll_Tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, pll_bw_init_hz, dll_bw_init_hz, ti_ms, early_late_space_chips)); -} - - - -void Galileo_E5a_Dll_Pll_Tracking_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - if (noutput_items != 0) - { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call - } -} - - -Galileo_E5a_Dll_Pll_Tracking_cc::Galileo_E5a_Dll_Pll_Tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_init_hz, - float dll_bw_init_hz, - int ti_ms, - float early_late_space_chips) : - gr::block("Galileo_E5a_Dll_Pll_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); - this->message_port_register_out(pmt::mp("events")); - this->set_relative_rate(1.0 / vector_length); - // initialize internal vars - d_dump = dump; - d_if_freq = if_freq; - d_fs_in = fs_in; - d_vector_length = vector_length; - d_dump_filename = dump_filename; - d_code_loop_filter = Tracking_2nd_DLL_filter(GALILEO_E5a_CODE_PERIOD); - d_carrier_loop_filter = Tracking_2nd_PLL_filter(GALILEO_E5a_CODE_PERIOD); - d_current_ti_ms = 1; // initializes with 1ms of integration time until secondary code lock - d_ti_ms = ti_ms; - d_dll_bw_hz = dll_bw_hz; - d_pll_bw_hz = pll_bw_hz; - d_dll_bw_init_hz = dll_bw_init_hz; - d_pll_bw_init_hz = pll_bw_init_hz; - - // Initialize tracking ========================================== - d_code_loop_filter.set_DLL_BW(d_dll_bw_init_hz); - d_carrier_loop_filter.set_PLL_BW(d_pll_bw_init_hz); - - //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) - - // Initialization of local code replica - // Get space for a vector with the E5a primary code replicas sampled 1x/chip - d_codeQ = static_cast(volk_gnsssdr_malloc(Galileo_E5a_CODE_LENGTH_CHIPS * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_codeI = static_cast(volk_gnsssdr_malloc(Galileo_E5a_CODE_LENGTH_CHIPS * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - // correlator Q outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - - // map memory pointers of correlator outputs - d_Single_Early = &d_correlator_outs[0]; - d_Single_Prompt = &d_correlator_outs[1]; - d_Single_Late = &d_correlator_outs[2]; - - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); - // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; - d_local_code_shift_chips[1] = 0.0; - d_local_code_shift_chips[2] = d_early_late_spc_chips; - - multicorrelator_cpu_Q.init(2 * d_vector_length, d_n_correlator_taps); - - // correlator I single output for data (scalar) - d_Single_Prompt_data=static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); - *d_Single_Prompt_data = gr_complex(0,0); - multicorrelator_cpu_I.init(2 * d_vector_length, 1); // single correlator for data channel - - //--- Perform initializations ------------------------------ - // define initial code frequency basis of NCO - d_code_freq_chips = Galileo_E5a_CODE_CHIP_RATE_HZ; - // define residual code phase (in chips) - d_rem_code_phase_samples = 0.0; - // define residual carrier phase - d_rem_carr_phase_rad = 0.0; - //Filter error vars - d_code_error_filt_secs = 0.0; - // sample synchronization - d_sample_counter = 0; - d_acq_sample_stamp = 0; - d_first_transition = false; - - d_secondary_lock = false; - d_secondary_delay = 0; - d_integration_counter = 0; - - d_current_prn_length_samples = static_cast(d_vector_length); - - // CN0 estimation and lock detector buffers - d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; - d_carrier_lock_test = 1; - d_CN0_SNV_dB_Hz = 0; - d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; - - d_acquisition_gnss_synchro = 0; - d_channel = 0; - tmp_E = 0; - tmp_P = 0; - tmp_L = 0; - d_acq_code_phase_samples = 0; - d_acq_carrier_doppler_hz = 0; - d_carrier_doppler_hz = 0; - d_acc_carrier_phase_rad = 0; - d_code_phase_samples = 0; - d_acc_code_phase_secs = 0; - d_state = 0; - - d_rem_code_phase_chips = 0.0; - d_code_phase_step_chips = 0.0; - d_carrier_phase_step_rad = 0.0; - - systemName["E"] = std::string("Galileo"); -} - - -Galileo_E5a_Dll_Pll_Tracking_cc::~Galileo_E5a_Dll_Pll_Tracking_cc () -{ - d_dump_file.close(); - - delete[] d_codeI; - delete[] d_codeQ; - delete[] d_Prompt_buffer; - - d_dump_file.close(); - - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - volk_gnsssdr_free(d_Single_Prompt_data); - - multicorrelator_cpu_Q.free(); - multicorrelator_cpu_I.free(); -} - - -void Galileo_E5a_Dll_Pll_Tracking_cc::start_tracking() -{ - /* - * correct the code phase according to the delay between acq and trk - */ - d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; - d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - - long int acq_trk_diff_samples; - double acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp);//-d_vector_length; - LOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; - acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); - //doppler effect - // Fd=(C/(C+Vr))*F - double radial_velocity; - radial_velocity = (Galileo_E5a_FREQ_HZ + d_acq_carrier_doppler_hz)/Galileo_E5a_FREQ_HZ; - // new chip and prn sequence periods based on acq Doppler - double T_chip_mod_seconds; - double T_prn_mod_seconds; - double T_prn_mod_samples; - d_code_freq_chips = radial_velocity * Galileo_E5a_CODE_CHIP_RATE_HZ; - T_chip_mod_seconds = 1/d_code_freq_chips; - T_prn_mod_seconds = T_chip_mod_seconds * Galileo_E5a_CODE_LENGTH_CHIPS; - T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); - - d_current_prn_length_samples = round(T_prn_mod_samples); - - double T_prn_true_seconds = Galileo_E5a_CODE_LENGTH_CHIPS / Galileo_E5a_CODE_CHIP_RATE_HZ; - double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); - double T_prn_diff_seconds; - T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; - double N_prn_diff; - N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; - double corrected_acq_phase_samples, delay_correction_samples; - corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); - if (corrected_acq_phase_samples < 0) - { - corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; - } - delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; - - d_acq_code_phase_samples = corrected_acq_phase_samples; - - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; - - // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(); // initialize the carrier filter - d_code_loop_filter.initialize(); // initialize the code filter - - // generate local reference ALWAYS starting at chip 1 (1 sample per chip) - char sig[3]; - strcpy(sig,"5Q"); - galileo_e5_a_code_gen_complex_primary(d_codeQ, d_acquisition_gnss_synchro->PRN, sig); - - strcpy(sig,"5I"); - galileo_e5_a_code_gen_complex_primary(d_codeI, d_acquisition_gnss_synchro->PRN, sig); - - d_carrier_lock_fail_counter = 0; - d_rem_code_phase_samples = 0; - d_rem_carr_phase_rad = 0; - d_acc_carrier_phase_rad = 0; - d_acc_code_phase_secs = 0; - - d_code_phase_samples = d_acq_code_phase_samples; - - std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); - - // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; - - - // enable tracking - d_state = 1; - - LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; - -} - - -void Galileo_E5a_Dll_Pll_Tracking_cc::acquire_secondary() -{ - // 1. Transform replica to 1 and -1 - int sec_code_signed[Galileo_E5a_Q_SECONDARY_CODE_LENGTH]; - for (unsigned int i = 0; i < Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++) - { - if (Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1].at(i) == '0') - { - sec_code_signed[i] = 1; - } - else - { - sec_code_signed[i] = -1; - } - } - // 2. Transform buffer to 1 and -1 - int in_corr[CN0_ESTIMATION_SAMPLES]; - for (unsigned int i = 0; i < CN0_ESTIMATION_SAMPLES; i++) - { - if (d_Prompt_buffer[i].real() >0) - { - in_corr[i] = 1; - } - else - { - in_corr[i] = -1; - } - } - // 3. Serial search - int out_corr; - int current_best_ = 0; - for (unsigned int i = 0; i < Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++) - { - out_corr = 0; - for (unsigned int j = 0; j < CN0_ESTIMATION_SAMPLES; j++) - { - //reverse replica sign since i*i=-1 (conjugated complex) - out_corr += in_corr[j] * -sec_code_signed[(j + i) % Galileo_E5a_Q_SECONDARY_CODE_LENGTH]; - } - if (abs(out_corr) > current_best_) - { - current_best_ = abs(out_corr); - d_secondary_delay = i; - } - } - if (current_best_ == CN0_ESTIMATION_SAMPLES) // all bits correlate - { - d_secondary_lock = true; - d_secondary_delay = (d_secondary_delay + CN0_ESTIMATION_SAMPLES - 1) % Galileo_E5a_Q_SECONDARY_CODE_LENGTH; - } -} - - -int Galileo_E5a_Dll_Pll_Tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // process vars - double carr_error_hz; - double carr_error_filt_hz; - double code_error_chips; - double code_error_filt_chips; - - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; //block output streams pointer - - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data; - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - - /* States: 0 Tracking not enabled - * 1 Pull-in of primary code (alignment). - * 3 Tracking algorithm. Correlates EPL each loop and accumulates the result - * until it reaches integration time. - */ - switch (d_state) - { - case 0: - { - - d_Early = gr_complex(0,0); - d_Prompt = gr_complex(0,0); - d_Late = gr_complex(0,0); - d_Prompt_data = gr_complex(0,0); - current_synchro_data.Tracking_timestamp_secs = static_cast(d_sample_counter) / static_cast(d_fs_in); - *out[0] = current_synchro_data; - - break; - } - case 1: - { - int samples_offset; - double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; - acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); - samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples - DLOG(INFO) << " samples_offset=" << samples_offset; - d_state = 2; // start in Ti = 1 code, until secondary code lock. - - // make an output to not stop the rest of the processing blocks - current_synchro_data.Prompt_I = 0.0; - current_synchro_data.Prompt_Q = 0.0; - current_synchro_data.Tracking_timestamp_secs = static_cast(d_sample_counter) / static_cast(d_fs_in); - current_synchro_data.Carrier_phase_rads = 0.0; - current_synchro_data.CN0_dB_hz = 0.0; - *out[0] = current_synchro_data; - consume_each(samples_offset); //shift input to perform alignment with local replica - return 1; - break; - } - case 2: - { - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment - gr_complex sec_sign_Q; - gr_complex sec_sign_I; - // Secondary code Chip - if (d_secondary_lock) - { - // sec_sign_Q = gr_complex((Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN-1].at(d_secondary_delay)=='0' ? 1 : -1),0); - // sec_sign_I = gr_complex((Galileo_E5a_I_SECONDARY_CODE.at(d_secondary_delay%Galileo_E5a_I_SECONDARY_CODE_LENGTH)=='0' ? 1 : -1),0); - sec_sign_Q = gr_complex((Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN-1].at(d_secondary_delay) == '0' ? -1 : 1), 0); - sec_sign_I = gr_complex((Galileo_E5a_I_SECONDARY_CODE.at(d_secondary_delay % Galileo_E5a_I_SECONDARY_CODE_LENGTH) == '0' ? -1 : 1), 0); - } - else - { - sec_sign_Q = gr_complex(1.0, 0.0); - sec_sign_I = gr_complex(1.0, 0.0); - } - // Reset integration counter - if (d_integration_counter == d_current_ti_ms) - { - d_integration_counter = 0; - } - //Generate local code and carrier replicas (using \hat{f}_d(k-1)) - if (d_integration_counter == 0) - { - // Reset accumulated values - d_Early = gr_complex(0,0); - d_Prompt = gr_complex(0,0); - d_Late = gr_complex(0,0); - } - - // perform carrier wipe-off and compute Early, Prompt and Late - // correlation of 1 primary code - - multicorrelator_cpu_Q.set_local_code_and_taps(Galileo_E5a_CODE_LENGTH_CHIPS, d_codeQ, d_local_code_shift_chips); - multicorrelator_cpu_I.set_local_code_and_taps(Galileo_E5a_CODE_LENGTH_CHIPS, d_codeI, &d_local_code_shift_chips[1]); - - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu_Q.set_input_output_vectors(d_correlator_outs,in); - multicorrelator_cpu_I.set_input_output_vectors(d_Single_Prompt_data,in); - - double carr_phase_step_rad = GALILEO_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - double code_phase_step_chips = d_code_freq_chips / (static_cast(d_fs_in)); - double rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / d_fs_in); - multicorrelator_cpu_Q.Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, - carr_phase_step_rad, - rem_code_phase_chips, - code_phase_step_chips, - d_current_prn_length_samples); - - multicorrelator_cpu_I.Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, - carr_phase_step_rad, - rem_code_phase_chips, - code_phase_step_chips, - d_current_prn_length_samples); - - - // Accumulate results (coherent integration since there are no bit transitions in pilot signal) - d_Early += (*d_Single_Early) * sec_sign_Q; - d_Prompt += (*d_Single_Prompt) * sec_sign_Q; - d_Late += (*d_Single_Late) * sec_sign_Q; - d_Prompt_data=(*d_Single_Prompt_data); - d_Prompt_data *= sec_sign_I; - d_integration_counter++; - - // ################## PLL ########################################################## - // PLL discriminator - if (d_integration_counter == d_current_ti_ms) - { - if (d_secondary_lock == true) - { - carr_error_hz = pll_four_quadrant_atan(d_Prompt) / GALILEO_PI * 2.0; - } - else - { - carr_error_hz = pll_cloop_two_quadrant_atan(d_Prompt) / GALILEO_PI * 2.0; - } - - // Carrier discriminator filter - carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); - // New carrier Doppler frequency estimation - d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = Galileo_E5a_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E5a_CODE_CHIP_RATE_HZ) / Galileo_E5a_FREQ_HZ); - } - //carrier phase accumulator for (K) doppler estimation - d_acc_carrier_phase_rad -= 2.0 * GALILEO_PI * d_carrier_doppler_hz * GALILEO_E5a_CODE_PERIOD; - //remanent carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad = d_rem_carr_phase_rad + 2.0 * GALILEO_PI * d_carrier_doppler_hz * GALILEO_E5a_CODE_PERIOD; - d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, 2.0 * GALILEO_PI); - - // ################## DLL ########################################################## - if (d_integration_counter == d_current_ti_ms) - { - // DLL discriminator - code_error_chips = dll_nc_e_minus_l_normalized(d_Early, d_Late); //[chips/Ti] - // Code discriminator filter - code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); //[chips/second] - //Code phase accumulator - d_code_error_filt_secs = (GALILEO_E5a_CODE_PERIOD * code_error_filt_chips) / Galileo_E5a_CODE_CHIP_RATE_HZ; //[seconds] - } - d_acc_code_phase_secs = d_acc_code_phase_secs + d_code_error_filt_secs; - - // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### - // keep alignment parameters for the next input buffer - double T_chip_seconds; - double T_prn_seconds; - double T_prn_samples; - double K_blk_samples; - // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation - T_chip_seconds = 1.0 / d_code_freq_chips; - T_prn_seconds = T_chip_seconds * Galileo_E5a_CODE_LENGTH_CHIPS; - T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - K_blk_samples = T_prn_samples + d_rem_code_phase_samples + d_code_error_filt_secs * static_cast(d_fs_in); - d_current_prn_length_samples = round(K_blk_samples); //round to a discrete samples - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES-1) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = d_Prompt; - d_cn0_estimation_counter++; - } - else - { - d_Prompt_buffer[d_cn0_estimation_counter] = d_Prompt; - // ATTEMPT SECONDARY CODE ACQUISITION - if (d_secondary_lock == false) - { - acquire_secondary(); // changes d_secondary_lock and d_secondary_delay - if (d_secondary_lock == true) - { - std::cout << "Secondary code locked." << std::endl; - d_current_ti_ms = d_ti_ms; - // Change loop parameters ========================================== - d_code_loop_filter.set_pdi(d_current_ti_ms * GALILEO_E5a_CODE_PERIOD); - d_carrier_loop_filter.set_pdi(d_current_ti_ms * GALILEO_E5a_CODE_PERIOD); - d_code_loop_filter.set_DLL_BW(d_dll_bw_hz); - d_carrier_loop_filter.set_PLL_BW(d_pll_bw_hz); - } - else - { - std::cout << "Secondary code delay couldn't be resolved." << std::endl; - d_carrier_lock_fail_counter++; - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_state = 0; // TODO: check if disabling tracking is consistent with the channel state machine - } - } - } - else // Secondary lock achieved, monitor carrier lock. - { - // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in,d_current_ti_ms * Galileo_E5a_CODE_LENGTH_CHIPS); - // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); - // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_state = 0; - } - } - } - d_cn0_estimation_counter = 0; - } - if (d_secondary_lock && (d_secondary_delay % Galileo_E5a_I_SECONDARY_CODE_LENGTH) == 0) - { - d_first_transition = true; - } - // ########### Output the tracking data to navigation and PVT ########## - // The first Prompt output not equal to 0 is synchronized with the transition of a navigation data bit. - if (d_secondary_lock && d_first_transition) - { - current_synchro_data.Prompt_I = static_cast((d_Prompt_data).real()); - current_synchro_data.Prompt_Q = static_cast((d_Prompt_data).imag()); - // Tracking_timestamp_secs is aligned with the PRN start sample - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_current_prn_length_samples) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - // This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0 - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; - - } - else - { - // make an output to not stop the rest of the processing blocks - current_synchro_data.Prompt_I = 0.0; - current_synchro_data.Prompt_Q = 0.0; - current_synchro_data.Tracking_timestamp_secs = static_cast(d_sample_counter) / static_cast(d_fs_in); - current_synchro_data.Carrier_phase_rads = 0.0; - current_synchro_data.CN0_dB_hz = 0.0; - - } - *out[0] = current_synchro_data; - break; - } - } - - if(d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - float prompt_I; - float prompt_Q; - double tmp_double; - prompt_I = (d_Prompt_data).real(); - prompt_Q = (d_Prompt_data).imag(); - if (d_integration_counter == d_current_ti_ms) - { - tmp_E = std::abs(d_Early); - tmp_P = std::abs(d_Prompt); - tmp_L = std::abs(d_Late); - } - try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - //PLL commands - d_dump_file.write(reinterpret_cast(&carr_error_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&carr_error_filt_hz), sizeof(double)); - - //DLL commands - d_dump_file.write(reinterpret_cast(&code_error_chips), sizeof(double)); - d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_rem_code_phase_samples; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - - } - catch (const std::ifstream::failure & e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what(); - } - } - - d_secondary_delay = (d_secondary_delay + 1) % Galileo_E5a_Q_SECONDARY_CODE_LENGTH; - d_sample_counter += d_current_prn_length_samples; //count for the processed samples - consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - -void Galileo_E5a_Dll_Pll_Tracking_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what() << std::endl; - } - } - } -} - - -void Galileo_E5a_Dll_Pll_Tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; -} - diff --git a/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.h deleted file mode 100644 index 3d21bd7c0..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/galileo_e5a_dll_pll_tracking_cc.h +++ /dev/null @@ -1,209 +0,0 @@ -/*! - * \file galileo_e5a_dll_pll_tracking_cc.h - * \brief Implementation of a code DLL + carrier PLL - * tracking block for Galileo E5a signals - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * \based on work from: - *
        - *
      • Javier Arribas, 2011. jarribas(at)cttc.es - *
      • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
      - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_CC_H_ -#define GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_CC_H_ - -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "tracking_2nd_DLL_filter.h" -#include "tracking_2nd_PLL_filter.h" -#include "cpu_multicorrelator.h" - -class Galileo_E5a_Dll_Pll_Tracking_cc; - -typedef boost::shared_ptr - galileo_e5a_dll_pll_tracking_cc_sptr; - -galileo_e5a_dll_pll_tracking_cc_sptr -galileo_e5a_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_init_hz, - float dll_bw_init_hz, - int ti_ms, - float early_late_space_chips); - - - -/*! - * \brief This class implements a DLL + PLL tracking loop block - */ -class Galileo_E5a_Dll_Pll_Tracking_cc: public gr::block -{ -public: - ~Galileo_E5a_Dll_Pll_Tracking_cc(); - - void set_channel(unsigned int channel); - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); - void start_tracking(); - - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - void forecast (int noutput_items, gr_vector_int &ninput_items_required); - -private: - friend galileo_e5a_dll_pll_tracking_cc_sptr - galileo_e5a_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_init_hz, - float dll_bw_init_hz, - int ti_ms, - float early_late_space_chips); - - Galileo_E5a_Dll_Pll_Tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_init_hz, - float dll_bw_init_hz, - int ti_ms, - float early_late_space_chips); - void acquire_secondary(); - // tracking configuration vars - unsigned int d_vector_length; - int d_current_ti_ms; - int d_ti_ms; - bool d_dump; - - - Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; - long d_if_freq; - long d_fs_in; - - double d_early_late_spc_chips; - double d_dll_bw_hz; - double d_pll_bw_hz; - double d_dll_bw_init_hz; - double d_pll_bw_init_hz; - - gr_complex* d_codeQ; - gr_complex* d_codeI; - - gr_complex d_Early; - gr_complex d_Prompt; - gr_complex d_Late; - gr_complex d_Prompt_data; - - gr_complex* d_Single_Early; - gr_complex* d_Single_Prompt; - gr_complex* d_Single_Late; - gr_complex* d_Single_Prompt_data; - - - float tmp_E; - float tmp_P; - float tmp_L; - // remaining code phase and carrier phase between tracking loops - double d_rem_code_phase_samples; - double d_rem_code_phase_chips; - double d_rem_carr_phase_rad; - - // PLL and DLL filter library - Tracking_2nd_DLL_filter d_code_loop_filter; - Tracking_2nd_PLL_filter d_carrier_loop_filter; - - // acquisition - double d_acq_code_phase_samples; - double d_acq_carrier_doppler_hz; - // correlator - int d_n_correlator_taps; - float* d_local_code_shift_chips; - gr_complex* d_correlator_outs; - cpu_multicorrelator multicorrelator_cpu_I; - cpu_multicorrelator multicorrelator_cpu_Q; - - // tracking vars - double d_code_freq_chips; - double d_carrier_doppler_hz; - double d_acc_carrier_phase_rad; - double d_code_phase_samples; - double d_acc_code_phase_secs; - double d_code_error_filt_secs; - double d_code_phase_step_chips; - double d_carrier_phase_step_rad; - - - //PRN period in samples - int d_current_prn_length_samples; - - //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; - - // CN0 estimation and lock detector - int d_cn0_estimation_counter; - gr_complex* d_Prompt_buffer; - double d_carrier_lock_test; - double d_CN0_SNV_dB_Hz; - double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; - - // control vars - int d_state; - bool d_first_transition; - - // Secondary code acquisition - bool d_secondary_lock; - int d_secondary_delay; - int d_integration_counter; - - // file dump - std::string d_dump_filename; - std::ofstream d_dump_file; - - std::map systemName; - std::string sys; -}; - -#endif /* GNSS_SDR_GALILEO_E5A_DLL_PLL_TRACKING_CC_H_ */ diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc new file mode 100644 index 000000000..77603d0aa --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc @@ -0,0 +1,926 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_dll_pll_c_aid_tracking_cc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CN0_ESTIMATION_SAMPLES 10 + +using google::LogMessage; + +glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr +glonass_l1_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) +{ + return glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr(new glonass_l1_ca_dll_pll_c_aid_tracking_cc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index(pmt::pmt_t msg) +{ + //pmt::print(msg); + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + { + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); + d_enable_extended_integration = true; + d_preamble_synchronized = false; + } +} + + +glonass_l1_ca_dll_pll_c_aid_tracking_cc::glonass_l1_ca_dll_pll_c_aid_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("glonass_l1_ca_dll_pll_c_aid_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_in(pmt::mp("preamble_timestamp_s")); + + this->set_msg_handler(pmt::mp("preamble_timestamp_s"), + boost::bind(&glonass_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index, this, _1)); + + this->message_port_register_out(pmt::mp("events")); + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_pll_bw_hz = pll_bw_hz; + d_dll_bw_hz = dll_bw_hz; + d_pll_bw_narrow_hz = pll_bw_narrow_hz; + d_dll_bw_narrow_hz = dll_bw_narrow_hz; + d_extend_correlation_ms = extend_correlation_ms; + d_code_loop_filter.set_DLL_BW(d_dll_bw_hz); + d_carrier_loop_filter.set_params(10.0, d_pll_bw_hz, 2); + + // --- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu.init(2 * d_correlation_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carrier_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; //(from trk to tlm) + d_acq_sample_stamp = 0; + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_code_error_filt_chips_Ti = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_code_phase_samples = 0.0; + + d_pll_to_dll_assist_secs_Ti = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + d_rem_code_phase_integer_samples = 0; + d_code_error_chips_Ti = 0.0; + d_code_error_filt_chips_s = 0.0; + d_carr_phase_error_secs_Ti = 0.0; + d_preamble_timestamp_s = 0.0; + + d_carrier_frequency_hz = 0.0; + d_carrier_doppler_old_hz = 0.0; + + d_glonass_freq_ch = 0; + + //set_min_output_buffer((int64_t)300); +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (DFRQ1_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L1_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1.0 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_correlation_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L1_CA_CODE_LENGTH_CHIPS / GLONASS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + // d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ1_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(d_carrier_frequency_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l1_ca_code_gen_complex(d_ca_code, 0); + + multicorrelator_cpu.set_local_code_and_taps(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carrier_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +glonass_l1_ca_dll_pll_c_aid_tracking_cc::~glonass_l1_ca_dll_pll_c_aid_tracking_cc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + glonass_l1_ca_dll_pll_c_aid_tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int32_t glonass_l1_ca_dll_pll_c_aid_tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int glonass_l1_ca_dll_pll_c_aid_tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + // process vars + double code_error_filt_secs_Ti = 0.0; + double CURRENT_INTEGRATION_TIME_S = 0.0; + double CORRECTED_INTEGRATION_TIME_S = 0.0; + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GLONASS_TWO_PI; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_correlation_length_samples); + + // ####### coherent integration extension + // keep the last symbols + d_E_history.push_back(d_correlator_outs[0]); // save early output + d_P_history.push_back(d_correlator_outs[1]); // save prompt output + d_L_history.push_back(d_correlator_outs[2]); // save late output + + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + { + d_E_history.pop_front(); + d_P_history.pop_front(); + d_L_history.pop_front(); + } + + bool enable_dll_pll; + if (d_enable_extended_integration == true) + { + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) + { + // compute coherent integration and enable tracking loop + // perform coherent integration using correlator output history + // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl + << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; + } + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_extend_correlation_ms) * GLONASS_L1_CA_CODE_PERIOD; + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); + enable_dll_pll = true; + } + else + { + if (d_preamble_synchronized == true) + { + // continue extended coherent correlation + // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + int32_t K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + d_carrier_phase_step_rad * static_cast(d_correlation_length_samples), GLONASS_TWO_PI); + + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + + // disable tracking loop and inform telemetry decoder + enable_dll_pll = false; + } + else + { + // perform basic (1ms) correlation + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); + enable_dll_pll = true; + } + } + } + else + { + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + + if (enable_dll_pll == true) + { + // ################## PLL ########################################################## + // Update PLL discriminator [rads/Ti -> Secs/Ti] + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GLONASS_TWO_PI; // prompt output + d_carrier_doppler_old_hz = d_carrier_doppler_hz; + // Carrier discriminator filter + // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan + // Input [s/Ti] -> output [Hz] + d_carrier_doppler_hz = d_carrier_loop_filter.get_carrier_error(0.0, d_carr_phase_error_secs_Ti, CURRENT_INTEGRATION_TIME_S); + // PLL to DLL assistance [Secs/Ti] + d_pll_to_dll_assist_secs_Ti = (d_carrier_doppler_hz * CURRENT_INTEGRATION_TIME_S) / d_glonass_freq_ch; + // code Doppler frequency update + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ + (((d_carrier_doppler_hz - d_carrier_doppler_old_hz) * GLONASS_L1_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + // Code discriminator filter + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + + //################### PLL COMMANDS ################################################# + //carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + //remnant carrier phase [rad] + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + GLONASS_TWO_PI * d_carrier_doppler_hz * CORRECTED_INTEGRATION_TIME_S, GLONASS_TWO_PI); + + //################### DLL COMMANDS ################################################# + //code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + //remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; // prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L1_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + if (d_preamble_synchronized == true) + { + current_synchro_data.correlation_length_ms = d_extend_correlation_ms; + } + else + { + current_synchro_data.correlation_length_ms = 1; + } + } + else + { + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + } + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.System = {'R'}; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + } + //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples + + return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h new file mode 100644 index 000000000..10f1064f5 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h @@ -0,0 +1,204 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking_cc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H +#define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H + +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_FLL_PLL_filter.h" +//#include "tracking_loop_filter.h" +#include "cpu_multicorrelator.h" +#include +#include +#include +#include +#include +#include + +class glonass_l1_ca_dll_pll_c_aid_tracking_cc; + +typedef boost::shared_ptr + glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr; + +glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr +glonass_l1_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class glonass_l1_ca_dll_pll_c_aid_tracking_cc : public gr::block +{ +public: + ~glonass_l1_ca_dll_pll_c_aid_tracking_cc(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void start_tracking(); + + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + +private: + friend glonass_l1_ca_dll_pll_c_aid_tracking_cc_sptr + glonass_l1_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + glonass_l1_ca_dll_pll_c_aid_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + // tracking configuration vars + uint32_t d_vector_length; + bool d_dump; + + Gnss_Synchro* d_acquisition_gnss_synchro; + uint32_t d_channel; + + int64_t d_fs_in; + double d_glonass_freq_ch; + + double d_early_late_spc_chips; + int32_t d_n_correlator_taps; + + gr_complex* d_ca_code; + float* d_local_code_shift_chips; + gr_complex* d_correlator_outs; + cpu_multicorrelator multicorrelator_cpu; + + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_code_phase_chips; + double d_rem_carrier_phase_rad; + int32_t d_rem_code_phase_integer_samples; + + // PLL and DLL filter library + //Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_FLL_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + float d_dll_bw_hz; + float d_pll_bw_hz; + float d_dll_bw_narrow_hz; + float d_pll_bw_narrow_hz; + double d_code_freq_chips; + double d_code_phase_step_chips; + double d_carrier_doppler_hz; + double d_carrier_frequency_hz; + double d_carrier_doppler_old_hz; + double d_carrier_phase_step_rad; + double d_acc_carrier_phase_cycles; + double d_code_phase_samples; + double d_pll_to_dll_assist_secs_Ti; + double d_code_error_chips_Ti; + double d_code_error_filt_chips_s; + double d_code_error_filt_chips_Ti; + double d_carr_phase_error_secs_Ti; + + // symbol history to detect bit transition + std::deque d_E_history; + std::deque d_P_history; + std::deque d_L_history; + double d_preamble_timestamp_s; + int32_t d_extend_correlation_ms; + bool d_enable_extended_integration; + bool d_preamble_synchronized; + void msg_handler_preamble_index(pmt::pmt_t msg); + + //Integration period in samples + int32_t d_correlation_length_samples; + + //processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + gr_complex* d_Prompt_buffer; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + int32_t d_carrier_lock_fail_counter; + + // control vars + bool d_enable_tracking; + bool d_pull_in; + + // file dump + std::string d_dump_filename; + std::ofstream d_dump_file; + + std::map systemName; + std::string sys; + + int32_t save_matfile(); +}; + +#endif //GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc new file mode 100644 index 000000000..96009c777 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc @@ -0,0 +1,915 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_dll_pll_c_aid_tracking_sc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CN0_ESTIMATION_SAMPLES 10 +using google::LogMessage; + +glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr +glonass_l1_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) +{ + return glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr(new glonass_l1_ca_dll_pll_c_aid_tracking_sc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_sc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index(pmt::pmt_t msg) +{ + //pmt::print(msg); + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + { + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); + d_enable_extended_integration = true; + d_preamble_synchronized = false; + } +} + +glonass_l1_ca_dll_pll_c_aid_tracking_sc::glonass_l1_ca_dll_pll_c_aid_tracking_sc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("glonass_l1_ca_dll_pll_c_aid_tracking_sc", gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_in(pmt::mp("preamble_timestamp_s")); + this->set_msg_handler(pmt::mp("preamble_timestamp_s"), + boost::bind(&glonass_l1_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index, this, _1)); + this->message_port_register_out(pmt::mp("events")); + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_pll_bw_hz = pll_bw_hz; + d_dll_bw_hz = dll_bw_hz; + d_pll_bw_narrow_hz = pll_bw_narrow_hz; + d_dll_bw_narrow_hz = dll_bw_narrow_hz; + d_code_loop_filter.set_DLL_BW(d_dll_bw_hz); + d_carrier_loop_filter.set_params(10.0, d_pll_bw_hz, 2); + d_extend_correlation_ms = extend_correlation_ms; + + // --- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + + d_correlator_outs_16sc = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_cmake(0, 0); + } + + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu_16sc.init(2 * d_correlation_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carrier_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; //(from trk to tlm) + d_acq_sample_stamp = 0; + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_code_phase_samples = 0.0; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + d_rem_code_phase_integer_samples = 0; + d_code_error_chips_Ti = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_code_error_filt_chips_s = 0.0; + d_code_error_filt_chips_Ti = 0.0; + d_preamble_timestamp_s = 0.0; + d_carr_phase_error_secs_Ti = 0.0; + + d_carrier_frequency_hz = 0.0; + d_carrier_doppler_old_hz = 0.0; + + d_glonass_freq_ch = 0; + //set_min_output_buffer((int64_t)300); +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L1_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1.0 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_correlation_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L1_CA_CODE_LENGTH_CHIPS / GLONASS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ1_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + ; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(d_carrier_frequency_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l1_ca_code_gen_complex(d_ca_code, 0); + volk_gnsssdr_32fc_convert_16ic(d_ca_code_16sc, d_ca_code, static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS)); + + multicorrelator_cpu_16sc.set_local_code_and_taps(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code_16sc, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_16sc_t(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carrier_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + d_enable_extended_integration = true; + d_preamble_synchronized = true; + + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +int32_t glonass_l1_ca_dll_pll_c_aid_tracking_sc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +glonass_l1_ca_dll_pll_c_aid_tracking_sc::~glonass_l1_ca_dll_pll_c_aid_tracking_sc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + glonass_l1_ca_dll_pll_c_aid_tracking_sc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_ca_code); + volk_gnsssdr_free(d_ca_code_16sc); + volk_gnsssdr_free(d_correlator_outs_16sc); + + delete[] d_Prompt_buffer; + multicorrelator_cpu_16sc.free(); +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_sc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void glonass_l1_ca_dll_pll_c_aid_tracking_sc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int glonass_l1_ca_dll_pll_c_aid_tracking_sc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + // process vars + double code_error_filt_secs_Ti = 0.0; + double CURRENT_INTEGRATION_TIME_S = 0.0; + double CORRECTED_INTEGRATION_TIME_S = 0.0; + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GLONASS_TWO_PI; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu_16sc.set_input_output_vectors(d_correlator_outs_16sc, in); + multicorrelator_cpu_16sc.Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_correlation_length_samples); + + // ####### coherent integration extension + // keep the last symbols + d_E_history.push_back(d_correlator_outs_16sc[0]); // save early output + d_P_history.push_back(d_correlator_outs_16sc[1]); // save prompt output + d_L_history.push_back(d_correlator_outs_16sc[2]); // save late output + + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + { + d_E_history.pop_front(); + d_P_history.pop_front(); + d_L_history.pop_front(); + } + + bool enable_dll_pll; + if (d_enable_extended_integration == true) + { + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) + { + // compute coherent integration and enable tracking loop + // perform coherent integration using correlator output history + // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl + << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; + } + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_extend_correlation_ms) * GLONASS_L1_CA_CODE_PERIOD; + enable_dll_pll = true; + } + else + { + if (d_preamble_synchronized == true) + { + // continue extended coherent correlation + // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + int32_t K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + d_carrier_phase_step_rad * static_cast(d_correlation_length_samples), GLONASS_TWO_PI); + + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + + // disable tracking loop and inform telemetry decoder + enable_dll_pll = false; + } + else + { + // perform basic (1ms) correlation + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + } + } + else + { + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + + if (enable_dll_pll == true) + { + // ################## PLL ########################################################## + // Update PLL discriminator [rads/Ti -> Secs/Ti] + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(std::complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())) / GLONASS_TWO_PI; //prompt output + d_carrier_doppler_old_hz = d_carrier_doppler_hz; + // Carrier discriminator filter + // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan + // Input [s/Ti] -> output [Hz] + d_carrier_doppler_hz = d_carrier_loop_filter.get_carrier_error(0.0, d_carr_phase_error_secs_Ti, CURRENT_INTEGRATION_TIME_S); + // PLL to DLL assistance [Secs/Ti] + d_pll_to_dll_assist_secs_Ti = (d_carrier_doppler_hz * CURRENT_INTEGRATION_TIME_S) / d_glonass_freq_ch; + // code Doppler frequency update + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ + (((d_carrier_doppler_hz - d_carrier_doppler_old_hz) * GLONASS_L1_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(std::complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag()), std::complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); // [chips/Ti] //early and late + // Code discriminator filter + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + + //################### PLL COMMANDS ################################################# + //carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + //remnant carrier phase [rad] + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + GLONASS_TWO_PI * d_carrier_doppler_hz * CORRECTED_INTEGRATION_TIME_S, GLONASS_TWO_PI); + + //################### DLL COMMANDS ################################################# + //code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + //remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = lv_cmake(static_cast(d_correlator_outs_16sc[1].real()), static_cast(d_correlator_outs_16sc[1].imag())); // prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L1_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); + // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + if (d_preamble_synchronized == true) + { + current_synchro_data.correlation_length_ms = d_extend_correlation_ms; + } + else + { + current_synchro_data.correlation_length_ms = 1; + } + } + else + { + current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + } + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_cmake(0, 0); + } + + current_synchro_data.System = {'R'}; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + } + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs_16sc[1].real(); + prompt_Q = d_correlator_outs_16sc[1].imag(); + tmp_E = std::abs(gr_complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag())); + tmp_P = std::abs(gr_complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())); + tmp_L = std::abs(gr_complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples + + return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.h new file mode 100644 index 000000000..b0717532e --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.h @@ -0,0 +1,207 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking_sc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H +#define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H + +#include "cpu_multicorrelator_16sc.h" +#include "glonass_l1_signal_processing.h" +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_FLL_PLL_filter.h" +#include +#include +#include +#include +#include +#include +#include + +class glonass_l1_ca_dll_pll_c_aid_tracking_sc; + +typedef boost::shared_ptr + glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr; + +glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr +glonass_l1_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class glonass_l1_ca_dll_pll_c_aid_tracking_sc : public gr::block +{ +public: + ~glonass_l1_ca_dll_pll_c_aid_tracking_sc(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void start_tracking(); + + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + +private: + friend glonass_l1_ca_dll_pll_c_aid_tracking_sc_sptr + glonass_l1_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + glonass_l1_ca_dll_pll_c_aid_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + // tracking configuration vars + uint32_t d_vector_length; + bool d_dump; + + Gnss_Synchro* d_acquisition_gnss_synchro; + uint32_t d_channel; + + int64_t d_fs_in; + int64_t d_glonass_freq_ch; + + double d_early_late_spc_chips; + int32_t d_n_correlator_taps; + + gr_complex* d_ca_code; + lv_16sc_t* d_ca_code_16sc; + float* d_local_code_shift_chips; + //gr_complex* d_correlator_outs; + lv_16sc_t* d_correlator_outs_16sc; + //cpu_multicorrelator multicorrelator_cpu; + cpu_multicorrelator_16sc multicorrelator_cpu_16sc; + + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_code_phase_chips; + double d_rem_carrier_phase_rad; + int32_t d_rem_code_phase_integer_samples; + + // PLL and DLL filter library + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_FLL_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + float d_dll_bw_hz; + float d_pll_bw_hz; + float d_dll_bw_narrow_hz; + float d_pll_bw_narrow_hz; + double d_code_freq_chips; + double d_code_phase_step_chips; + double d_carrier_doppler_hz; + double d_carrier_frequency_hz; + double d_carrier_doppler_old_hz; + double d_carrier_phase_step_rad; + double d_acc_carrier_phase_cycles; + double d_code_phase_samples; + double d_pll_to_dll_assist_secs_Ti; + double d_carr_phase_error_secs_Ti; + double d_code_error_chips_Ti; + double d_preamble_timestamp_s; + int32_t d_extend_correlation_ms; + bool d_enable_extended_integration; + bool d_preamble_synchronized; + double d_code_error_filt_chips_s; + double d_code_error_filt_chips_Ti; + void msg_handler_preamble_index(pmt::pmt_t msg); + + // symbol history to detect bit transition + std::deque d_E_history; + std::deque d_P_history; + std::deque d_L_history; + + //Integration period in samples + int32_t d_correlation_length_samples; + + //processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + gr_complex* d_Prompt_buffer; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + int32_t d_carrier_lock_fail_counter; + + // control vars + bool d_enable_tracking; + bool d_pull_in; + + // file dump + std::string d_dump_filename; + std::ofstream d_dump_file; + + std::map systemName; + std::string sys; + + int32_t save_matfile(); +}; + +#endif //GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc new file mode 100644 index 000000000..70cc662bb --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc @@ -0,0 +1,767 @@ +/*! + * \file glonass_l1_ca_dll_pll_tracking_cc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l1_ca_dll_pll_tracking_cc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l1_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CN0_ESTIMATION_SAMPLES 10 +using google::LogMessage; + +glonass_l1_ca_dll_pll_tracking_cc_sptr +glonass_l1_ca_dll_pll_make_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) +{ + return glonass_l1_ca_dll_pll_tracking_cc_sptr(new Glonass_L1_Ca_Dll_Pll_Tracking_cc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, early_late_space_chips)); +} + + +void Glonass_L1_Ca_Dll_Pll_Tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +Glonass_L1_Ca_Dll_Pll_Tracking_cc::Glonass_L1_Ca_Dll_Pll_Tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) : gr::block("Glonass_L1_Ca_Dll_Pll_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + this->message_port_register_out(pmt::mp("events")); + + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + + d_current_prn_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_code_loop_filter.set_DLL_BW(dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); + + //--- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu.init(2 * d_current_prn_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carr_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; + //d_sample_counter_seconds = 0; + d_acq_sample_stamp = 0; + + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_carrier_doppler_phase_step_rad = 0.0; + d_carrier_frequency_hz = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_code_phase_samples = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + + d_glonass_freq_ch = 0; + + set_relative_rate(1.0 / static_cast(d_vector_length)); +} + + +void Glonass_L1_Ca_Dll_Pll_Tracking_cc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L1_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_current_prn_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L1_CA_CODE_LENGTH_CHIPS / GLONASS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + d_carrier_doppler_phase_step_rad = GLONASS_TWO_PI * (d_carrier_doppler_hz) / static_cast(d_fs_in); + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(); // initialize the carrier filter + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l1_ca_code_gen_complex(d_ca_code, 0); + + multicorrelator_cpu.set_local_code_and_taps(static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_frequency_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +Glonass_L1_Ca_Dll_Pll_Tracking_cc::~Glonass_L1_Ca_Dll_Pll_Tracking_cc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + Glonass_L1_Ca_Dll_Pll_Tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int32_t Glonass_L1_Ca_Dll_Pll_Tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void Glonass_L1_Ca_Dll_Pll_Tracking_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void Glonass_L1_Ca_Dll_Pll_Tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int Glonass_L1_Ca_Dll_Pll_Tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // process vars + double carr_error_hz = 0.0; + double carr_error_filt_hz = 0.0; + double code_error_chips = 0.0; + double code_error_filt_chips = 0.0; + + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter = d_sample_counter + static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + // take into account the carrier cycles accumulated in the pull in signal alignment + d_acc_carrier_phase_rad -= d_carrier_doppler_phase_step_rad * samples_offset; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + current_synchro_data.correlation_length_ms = 1; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_current_prn_length_samples); + + // ################## PLL ########################################################## + // PLL discriminator + // Update PLL discriminator [rads/Ti -> Secs/Ti] + carr_error_hz = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GLONASS_TWO_PI; // prompt output + // Carrier discriminator filter + carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); + // New carrier Doppler frequency estimation + d_carrier_frequency_hz += carr_error_filt_hz; + d_carrier_doppler_hz += carr_error_filt_hz; + d_code_freq_chips = GLONASS_L1_CA_CODE_RATE_HZ + ((d_carrier_doppler_hz * GLONASS_L1_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + // Code discriminator filter + code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); // [chips/second] + double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double code_error_filt_secs = (T_prn_seconds * code_error_filt_chips * T_chip_seconds); //[seconds] + //double code_error_filt_secs = (GPS_L1_CA_CODE_PERIOD * code_error_filt_chips) / GLONASS_L1_CA_CODE_RATE_HZ; // [seconds] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + //double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + //double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); + d_current_prn_length_samples = round(K_blk_samples); // round to a discrete number of samples + + //################### PLL COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_doppler_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + // remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad = d_rem_carr_phase_rad + d_carrier_phase_step_rad * d_current_prn_length_samples; + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GLONASS_TWO_PI); + // carrier phase accumulator + d_acc_carrier_phase_rad -= d_carrier_doppler_phase_step_rad * d_current_prn_length_samples; + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L1_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 1; + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.System = {'R'}; + current_synchro_data.correlation_length_ms = 1; + } + + //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_float; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = carr_error_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = carr_error_filt_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = code_error_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_current_prn_length_samples; // count for the processed samples + return 1; // output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.h similarity index 54% rename from src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.h rename to src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.h index 92a5d4afb..d8716f5ee 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.h @@ -1,17 +1,19 @@ /*! - * \file gps_l1_ca_dll_pll_tracking_cc.h - * \brief Interface of a code DLL + carrier PLL tracking block - * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * Javier Arribas, 2011. jarribas(at)cttc.es + * \file glonass_l1_ca_dll_pll_tracking_cc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * * * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency Approach, - * Birkhauser, 2007 + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,86 +31,82 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_CC_H -#define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_CC_H +#ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_CC_H +#define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_CC_H -#include -#include -#include -#include +#include "cpu_multicorrelator.h" #include "gnss_synchro.h" #include "tracking_2nd_DLL_filter.h" #include "tracking_2nd_PLL_filter.h" -#include "cpu_multicorrelator.h" +#include +#include +#include +#include -class Gps_L1_Ca_Dll_Pll_Tracking_cc; +class Glonass_L1_Ca_Dll_Pll_Tracking_cc; -typedef boost::shared_ptr - gps_l1_ca_dll_pll_tracking_cc_sptr; - -gps_l1_ca_dll_pll_tracking_cc_sptr -gps_l1_ca_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); +typedef boost::shared_ptr + glonass_l1_ca_dll_pll_tracking_cc_sptr; +glonass_l1_ca_dll_pll_tracking_cc_sptr +glonass_l1_ca_dll_pll_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class Gps_L1_Ca_Dll_Pll_Tracking_cc: public gr::block +class Glonass_L1_Ca_Dll_Pll_Tracking_cc : public gr::block { public: - ~Gps_L1_Ca_Dll_Pll_Tracking_cc(); + ~Glonass_L1_Ca_Dll_Pll_Tracking_cc(); - void set_channel(unsigned int channel); + void set_channel(uint32_t channel); void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); private: - friend gps_l1_ca_dll_pll_tracking_cc_sptr - gps_l1_ca_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + friend glonass_l1_ca_dll_pll_tracking_cc_sptr + glonass_l1_ca_dll_pll_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); - Gps_L1_Ca_Dll_Pll_Tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + Glonass_L1_Ca_Dll_Pll_Tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; + uint32_t d_channel; - long d_if_freq; - long d_fs_in; + int64_t d_fs_in; + int64_t d_glonass_freq_ch; double d_early_late_spc_chips; @@ -125,7 +123,7 @@ private: double d_acq_code_phase_samples; double d_acq_carrier_doppler_hz; // correlator - int d_n_correlator_taps; + int32_t d_n_correlator_taps; gr_complex* d_ca_code; float* d_local_code_shift_chips; gr_complex* d_correlator_outs; @@ -136,24 +134,26 @@ private: double d_code_freq_chips; double d_code_phase_step_chips; double d_carrier_doppler_hz; + double d_carrier_doppler_phase_step_rad; + double d_carrier_frequency_hz; double d_carrier_phase_step_rad; double d_acc_carrier_phase_rad; double d_code_phase_samples; //PRN period in samples - int d_current_prn_length_samples; + int32_t d_current_prn_length_samples; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; + int32_t d_cn0_estimation_counter; gr_complex* d_Prompt_buffer; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -165,6 +165,8 @@ private: std::map systemName; std::string sys; + + int32_t save_matfile(); }; -#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_CC_H +#endif //GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.cc new file mode 100644 index 000000000..0299968b3 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.cc @@ -0,0 +1,923 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking_cc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_dll_pll_c_aid_tracking_cc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l2_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CN0_ESTIMATION_SAMPLES 10 + +using google::LogMessage; + +glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr +glonass_l2_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) +{ + return glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr(new glonass_l2_ca_dll_pll_c_aid_tracking_cc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index(pmt::pmt_t msg) +{ + //pmt::print(msg); + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + { + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); + d_enable_extended_integration = true; + d_preamble_synchronized = false; + } +} + + +glonass_l2_ca_dll_pll_c_aid_tracking_cc::glonass_l2_ca_dll_pll_c_aid_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("glonass_l2_ca_dll_pll_c_aid_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_in(pmt::mp("preamble_timestamp_s")); + + this->set_msg_handler(pmt::mp("preamble_timestamp_s"), + boost::bind(&glonass_l2_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index, this, _1)); + + this->message_port_register_out(pmt::mp("events")); + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_pll_bw_hz = pll_bw_hz; + d_dll_bw_hz = dll_bw_hz; + d_pll_bw_narrow_hz = pll_bw_narrow_hz; + d_dll_bw_narrow_hz = dll_bw_narrow_hz; + d_extend_correlation_ms = extend_correlation_ms; + d_code_loop_filter.set_DLL_BW(d_dll_bw_hz); + d_carrier_loop_filter.set_params(10.0, d_pll_bw_hz, 2); + + // --- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu.init(2 * d_correlation_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carrier_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; //(from trk to tlm) + d_acq_sample_stamp = 0; + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_code_error_filt_chips_Ti = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_code_phase_samples = 0.0; + + d_pll_to_dll_assist_secs_Ti = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + d_rem_code_phase_integer_samples = 0; + d_code_error_chips_Ti = 0.0; + d_code_error_filt_chips_s = 0.0; + d_carr_phase_error_secs_Ti = 0.0; + d_preamble_timestamp_s = 0.0; + + d_carrier_frequency_hz = 0.0; + d_carrier_doppler_old_hz = 0.0; + + d_glonass_freq_ch = 0; + + //set_min_output_buffer((int64_t)300); +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_cc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L2_CA_FREQ_HZ + (DFRQ2_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L2_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1.0 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_correlation_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L2_CA_CODE_LENGTH_CHIPS / GLONASS_L2_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz + (DFRQ2_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + // d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ2_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(d_carrier_frequency_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l2_ca_code_gen_complex(d_ca_code, 0); + + multicorrelator_cpu.set_local_code_and_taps(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carrier_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L2 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L2 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +glonass_l2_ca_dll_pll_c_aid_tracking_cc::~glonass_l2_ca_dll_pll_c_aid_tracking_cc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + glonass_l2_ca_dll_pll_c_aid_tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int32_t glonass_l2_ca_dll_pll_c_aid_tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int glonass_l2_ca_dll_pll_c_aid_tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + // process vars + double code_error_filt_secs_Ti = 0.0; + double CURRENT_INTEGRATION_TIME_S = 0.0; + double CORRECTED_INTEGRATION_TIME_S = 0.0; + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GLONASS_TWO_PI; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_correlation_length_samples); + + // ####### coherent integration extension + // keep the last symbols + d_E_history.push_back(d_correlator_outs[0]); // save early output + d_P_history.push_back(d_correlator_outs[1]); // save prompt output + d_L_history.push_back(d_correlator_outs[2]); // save late output + + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + { + d_E_history.pop_front(); + d_P_history.pop_front(); + d_L_history.pop_front(); + } + + bool enable_dll_pll; + if (d_enable_extended_integration == true) + { + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) + { + // compute coherent integration and enable tracking loop + // perform coherent integration using correlator output history + // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl + << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; + } + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_extend_correlation_ms) * GLONASS_L2_CA_CODE_PERIOD; + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); + enable_dll_pll = true; + } + else + { + if (d_preamble_synchronized == true) + { + // continue extended coherent correlation + // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + int32_t K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + d_carrier_phase_step_rad * static_cast(d_correlation_length_samples), GLONASS_TWO_PI); + + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + + // disable tracking loop and inform telemetry decoder + enable_dll_pll = false; + } + else + { + // perform basic (1ms) correlation + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); + enable_dll_pll = true; + } + } + } + else + { + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + + if (enable_dll_pll == true) + { + // ################## PLL ########################################################## + // Update PLL discriminator [rads/Ti -> Secs/Ti] + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GLONASS_TWO_PI; // prompt output + d_carrier_doppler_old_hz = d_carrier_doppler_hz; + // Carrier discriminator filter + // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan + // Input [s/Ti] -> output [Hz] + d_carrier_doppler_hz = d_carrier_loop_filter.get_carrier_error(0.0, d_carr_phase_error_secs_Ti, CURRENT_INTEGRATION_TIME_S); + // PLL to DLL assistance [Secs/Ti] + d_pll_to_dll_assist_secs_Ti = (d_carrier_doppler_hz * CURRENT_INTEGRATION_TIME_S) / d_glonass_freq_ch; + // code Doppler frequency update + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ + (((d_carrier_doppler_hz - d_carrier_doppler_old_hz) * GLONASS_L2_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + // Code discriminator filter + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + + //################### PLL COMMANDS ################################################# + //carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + //remnant carrier phase [rad] + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + GLONASS_TWO_PI * d_carrier_doppler_hz * CORRECTED_INTEGRATION_TIME_S, GLONASS_TWO_PI); + + //################### DLL COMMANDS ################################################# + //code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + //remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; // prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L2_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + if (d_preamble_synchronized == true) + { + current_synchro_data.correlation_length_ms = d_extend_correlation_ms; + } + else + { + current_synchro_data.correlation_length_ms = 1; + } + } + else + { + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + } + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.System = {'R'}; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + } + //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples + + return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.h new file mode 100644 index 000000000..129e4609e --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_cc.h @@ -0,0 +1,202 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking_cc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_CC_H +#define GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_CC_H + +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_FLL_PLL_filter.h" +//#include "tracking_loop_filter.h" +#include "cpu_multicorrelator.h" +#include +#include +#include +#include +#include +#include + +class glonass_l2_ca_dll_pll_c_aid_tracking_cc; + +typedef boost::shared_ptr + glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr; + +glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr +glonass_l2_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class glonass_l2_ca_dll_pll_c_aid_tracking_cc : public gr::block +{ +public: + ~glonass_l2_ca_dll_pll_c_aid_tracking_cc(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void start_tracking(); + + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + +private: + friend glonass_l2_ca_dll_pll_c_aid_tracking_cc_sptr + glonass_l2_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + glonass_l2_ca_dll_pll_c_aid_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + // tracking configuration vars + uint32_t d_vector_length; + bool d_dump; + + Gnss_Synchro* d_acquisition_gnss_synchro; + uint32_t d_channel; + + int64_t d_fs_in; + double d_glonass_freq_ch; + + double d_early_late_spc_chips; + int32_t d_n_correlator_taps; + + gr_complex* d_ca_code; + float* d_local_code_shift_chips; + gr_complex* d_correlator_outs; + cpu_multicorrelator multicorrelator_cpu; + + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_code_phase_chips; + double d_rem_carrier_phase_rad; + int32_t d_rem_code_phase_integer_samples; + + // PLL and DLL filter library + //Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_FLL_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + float d_dll_bw_hz; + float d_pll_bw_hz; + float d_dll_bw_narrow_hz; + float d_pll_bw_narrow_hz; + double d_code_freq_chips; + double d_code_phase_step_chips; + double d_carrier_doppler_hz; + double d_carrier_frequency_hz; + double d_carrier_doppler_old_hz; + double d_carrier_phase_step_rad; + double d_acc_carrier_phase_cycles; + double d_code_phase_samples; + double d_pll_to_dll_assist_secs_Ti; + double d_code_error_chips_Ti; + double d_code_error_filt_chips_s; + double d_code_error_filt_chips_Ti; + double d_carr_phase_error_secs_Ti; + + // symbol history to detect bit transition + std::deque d_E_history; + std::deque d_P_history; + std::deque d_L_history; + double d_preamble_timestamp_s; + int32_t d_extend_correlation_ms; + bool d_enable_extended_integration; + bool d_preamble_synchronized; + void msg_handler_preamble_index(pmt::pmt_t msg); + + //Integration period in samples + int32_t d_correlation_length_samples; + + //processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + gr_complex* d_Prompt_buffer; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + int32_t d_carrier_lock_fail_counter; + + // control vars + bool d_enable_tracking; + bool d_pull_in; + + // file dump + std::string d_dump_filename; + std::ofstream d_dump_file; + + std::map systemName; + std::string sys; + + int32_t save_matfile(); +}; + +#endif //GNSS_SDR_GLONASS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.cc new file mode 100644 index 000000000..ec9db011a --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.cc @@ -0,0 +1,914 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking_sc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_dll_pll_c_aid_tracking_sc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l2_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CN0_ESTIMATION_SAMPLES 10 + +using google::LogMessage; + +glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr +glonass_l2_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) +{ + return glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr(new glonass_l2_ca_dll_pll_c_aid_tracking_sc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_sc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index(pmt::pmt_t msg) +{ + //pmt::print(msg); + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + { + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); + d_enable_extended_integration = true; + d_preamble_synchronized = false; + } +} + + +glonass_l2_ca_dll_pll_c_aid_tracking_sc::glonass_l2_ca_dll_pll_c_aid_tracking_sc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("glonass_l1_ca_dll_pll_c_aid_tracking_sc", gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_in(pmt::mp("preamble_timestamp_s")); + this->set_msg_handler(pmt::mp("preamble_timestamp_s"), + boost::bind(&glonass_l2_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index, this, _1)); + this->message_port_register_out(pmt::mp("events")); + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_pll_bw_hz = pll_bw_hz; + d_dll_bw_hz = dll_bw_hz; + d_pll_bw_narrow_hz = pll_bw_narrow_hz; + d_dll_bw_narrow_hz = dll_bw_narrow_hz; + d_code_loop_filter.set_DLL_BW(d_dll_bw_hz); + d_carrier_loop_filter.set_params(10.0, d_pll_bw_hz, 2); + d_extend_correlation_ms = extend_correlation_ms; + + // --- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS) * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + + d_correlator_outs_16sc = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_cmake(0, 0); + } + + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu_16sc.init(2 * d_correlation_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carrier_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; //(from trk to tlm) + d_acq_sample_stamp = 0; + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_code_phase_samples = 0.0; + d_enable_extended_integration = false; + d_preamble_synchronized = false; + d_rem_code_phase_integer_samples = 0; + d_code_error_chips_Ti = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + d_code_error_filt_chips_s = 0.0; + d_code_error_filt_chips_Ti = 0.0; + d_preamble_timestamp_s = 0.0; + d_carr_phase_error_secs_Ti = 0.0; + + d_carrier_frequency_hz = 0.0; + d_carrier_doppler_old_hz = 0.0; + + d_glonass_freq_ch = 0; + //set_min_output_buffer((int64_t)300); +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_sc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L2_CA_FREQ_HZ + (GLONASS_L2_CA_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L2_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1.0 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_correlation_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L2_CA_CODE_LENGTH_CHIPS / GLONASS_L2_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ2_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + ; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(d_carrier_frequency_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l2_ca_code_gen_complex(d_ca_code, 0); + volk_gnsssdr_32fc_convert_16ic(d_ca_code_16sc, d_ca_code, static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS)); + + multicorrelator_cpu_16sc.set_local_code_and_taps(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS), d_ca_code_16sc, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_16sc_t(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0.0; + d_rem_carrier_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_cycles = 0.0; + d_pll_to_dll_assist_secs_Ti = 0.0; + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L2 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L2 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + d_enable_extended_integration = true; + d_preamble_synchronized = true; + + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +int32_t glonass_l2_ca_dll_pll_c_aid_tracking_sc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +glonass_l2_ca_dll_pll_c_aid_tracking_sc::~glonass_l2_ca_dll_pll_c_aid_tracking_sc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + glonass_l2_ca_dll_pll_c_aid_tracking_sc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_ca_code); + volk_gnsssdr_free(d_ca_code_16sc); + volk_gnsssdr_free(d_correlator_outs_16sc); + + delete[] d_Prompt_buffer; + multicorrelator_cpu_16sc.free(); +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_sc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void glonass_l2_ca_dll_pll_c_aid_tracking_sc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int glonass_l2_ca_dll_pll_c_aid_tracking_sc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + // process vars + double code_error_filt_secs_Ti = 0.0; + double CURRENT_INTEGRATION_TIME_S = 0.0; + double CORRECTED_INTEGRATION_TIME_S = 0.0; + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GLONASS_TWO_PI; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu_16sc.set_input_output_vectors(d_correlator_outs_16sc, in); + multicorrelator_cpu_16sc.Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_correlation_length_samples); + + // ####### coherent integration extension + // keep the last symbols + d_E_history.push_back(d_correlator_outs_16sc[0]); // save early output + d_P_history.push_back(d_correlator_outs_16sc[1]); // save prompt output + d_L_history.push_back(d_correlator_outs_16sc[2]); // save late output + + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + { + d_E_history.pop_front(); + d_P_history.pop_front(); + d_L_history.pop_front(); + } + + bool enable_dll_pll; + if (d_enable_extended_integration == true) + { + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) + { + // compute coherent integration and enable tracking loop + // perform coherent integration using correlator output history + // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl + << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; + } + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_extend_correlation_ms) * GLONASS_L2_CA_CODE_PERIOD; + enable_dll_pll = true; + } + else + { + if (d_preamble_synchronized == true) + { + // continue extended coherent correlation + // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + int32_t K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + d_carrier_phase_step_rad * static_cast(d_correlation_length_samples), GLONASS_TWO_PI); + + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + + // disable tracking loop and inform telemetry decoder + enable_dll_pll = false; + } + else + { + // perform basic (1ms) correlation + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + } + } + else + { + // UPDATE INTEGRATION TIME + CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + enable_dll_pll = true; + } + + if (enable_dll_pll == true) + { + // ################## PLL ########################################################## + // Update PLL discriminator [rads/Ti -> Secs/Ti] + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(std::complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())) / GLONASS_TWO_PI; //prompt output + d_carrier_doppler_old_hz = d_carrier_doppler_hz; + // Carrier discriminator filter + // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan + // Input [s/Ti] -> output [Hz] + d_carrier_doppler_hz = d_carrier_loop_filter.get_carrier_error(0.0, d_carr_phase_error_secs_Ti, CURRENT_INTEGRATION_TIME_S); + // PLL to DLL assistance [Secs/Ti] + d_pll_to_dll_assist_secs_Ti = (d_carrier_doppler_hz * CURRENT_INTEGRATION_TIME_S) / d_glonass_freq_ch; + // code Doppler frequency update + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ + (((d_carrier_doppler_hz - d_carrier_doppler_old_hz) * GLONASS_L2_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(std::complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag()), std::complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); // [chips/Ti] //early and late + // Code discriminator filter + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_chip_seconds = 1.0 / d_code_freq_chips; + double T_prn_seconds = T_chip_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_prn_samples = round(T_prn_samples); + double K_T_prn_error_samples = K_prn_samples - T_prn_samples; + + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; + d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; + + //################### PLL COMMANDS ################################################# + //carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GLONASS_TWO_PI; + // UPDATE ACCUMULATED CARRIER PHASE + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); + //remnant carrier phase [rad] + d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + GLONASS_TWO_PI * d_carrier_doppler_hz * CORRECTED_INTEGRATION_TIME_S, GLONASS_TWO_PI); + + //################### DLL COMMANDS ################################################# + //code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + //remnant code phase [chips] + d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = lv_cmake(static_cast(d_correlator_outs_16sc[1].real()), static_cast(d_correlator_outs_16sc[1].imag())); // prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L2_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); + // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + if (d_preamble_synchronized == true) + { + current_synchro_data.correlation_length_ms = d_extend_correlation_ms; + } + else + { + current_synchro_data.correlation_length_ms = 1; + } + } + else + { + current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = GLONASS_TWO_PI * d_acc_carrier_phase_cycles; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + } + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs_16sc[n] = lv_cmake(0, 0); + } + + current_synchro_data.System = {'R'}; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + } + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs_16sc[1].real(); + prompt_Q = d_correlator_outs_16sc[1].imag(); + tmp_E = std::abs(gr_complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag())); + tmp_P = std::abs(gr_complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())); + tmp_L = std::abs(gr_complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GLONASS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples + + return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.h new file mode 100644 index 000000000..5745d8ff9 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_c_aid_tracking_sc.h @@ -0,0 +1,205 @@ +/*! + * \file glonass_l2_ca_dll_pll_c_aid_tracking_sc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_SC_H +#define GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_SC_H + +#include "cpu_multicorrelator_16sc.h" +#include "glonass_l2_signal_processing.h" +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_FLL_PLL_filter.h" +#include +#include +#include +#include +#include +#include +#include + +class glonass_l2_ca_dll_pll_c_aid_tracking_sc; + +typedef boost::shared_ptr + glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr; + +glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr +glonass_l2_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class glonass_l2_ca_dll_pll_c_aid_tracking_sc : public gr::block +{ +public: + ~glonass_l2_ca_dll_pll_c_aid_tracking_sc(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void start_tracking(); + + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + +private: + friend glonass_l2_ca_dll_pll_c_aid_tracking_sc_sptr + glonass_l2_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + glonass_l2_ca_dll_pll_c_aid_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); + + // tracking configuration vars + uint32_t d_vector_length; + bool d_dump; + + Gnss_Synchro* d_acquisition_gnss_synchro; + uint32_t d_channel; + + int64_t d_fs_in; + int64_t d_glonass_freq_ch; + + double d_early_late_spc_chips; + int32_t d_n_correlator_taps; + + gr_complex* d_ca_code; + lv_16sc_t* d_ca_code_16sc; + float* d_local_code_shift_chips; + //gr_complex* d_correlator_outs; + lv_16sc_t* d_correlator_outs_16sc; + //cpu_multicorrelator multicorrelator_cpu; + cpu_multicorrelator_16sc multicorrelator_cpu_16sc; + + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_code_phase_chips; + double d_rem_carrier_phase_rad; + int32_t d_rem_code_phase_integer_samples; + + // PLL and DLL filter library + Tracking_2nd_DLL_filter d_code_loop_filter; + Tracking_FLL_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + + // tracking vars + float d_dll_bw_hz; + float d_pll_bw_hz; + float d_dll_bw_narrow_hz; + float d_pll_bw_narrow_hz; + double d_code_freq_chips; + double d_code_phase_step_chips; + double d_carrier_doppler_hz; + double d_carrier_frequency_hz; + double d_carrier_doppler_old_hz; + double d_carrier_phase_step_rad; + double d_acc_carrier_phase_cycles; + double d_code_phase_samples; + double d_pll_to_dll_assist_secs_Ti; + double d_carr_phase_error_secs_Ti; + double d_code_error_chips_Ti; + double d_preamble_timestamp_s; + int32_t d_extend_correlation_ms; + bool d_enable_extended_integration; + bool d_preamble_synchronized; + double d_code_error_filt_chips_s; + double d_code_error_filt_chips_Ti; + void msg_handler_preamble_index(pmt::pmt_t msg); + + // symbol history to detect bit transition + std::deque d_E_history; + std::deque d_P_history; + std::deque d_L_history; + + //Integration period in samples + int32_t d_correlation_length_samples; + + //processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + gr_complex* d_Prompt_buffer; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + int32_t d_carrier_lock_fail_counter; + + // control vars + bool d_enable_tracking; + bool d_pull_in; + + // file dump + std::string d_dump_filename; + std::ofstream d_dump_file; + + std::map systemName; + std::string sys; + + int32_t save_matfile(); +}; + +#endif //GNSS_SDR_GLONASS_L2_CA_DLL_PLL_C_AID_TRACKING_SC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.cc new file mode 100644 index 000000000..62b90e984 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.cc @@ -0,0 +1,767 @@ +/*! + * \file glonass_l2_ca_dll_pll_tracking_cc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_l2_ca_dll_pll_tracking_cc.h" +#include "GLONASS_L1_L2_CA.h" +#include "control_message_factory.h" +#include "glonass_l2_signal_processing.h" +#include "gnss_sdr_flags.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CN0_ESTIMATION_SAMPLES 10 + +using google::LogMessage; + +glonass_l2_ca_dll_pll_tracking_cc_sptr +glonass_l2_ca_dll_pll_make_tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) +{ + return glonass_l2_ca_dll_pll_tracking_cc_sptr(new Glonass_L2_Ca_Dll_Pll_Tracking_cc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, early_late_space_chips)); +} + + +void Glonass_L2_Ca_Dll_Pll_Tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + } +} + + +Glonass_L2_Ca_Dll_Pll_Tracking_cc::Glonass_L2_Ca_Dll_Pll_Tracking_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) : gr::block("Glonass_L2_Ca_Dll_Pll_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + this->message_port_register_out(pmt::mp("events")); + + // initialize internal vars + d_dump = dump; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + + d_current_prn_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_code_loop_filter.set_DLL_BW(dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); + + //--- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu.init(2 * d_current_prn_length_samples, d_n_correlator_taps); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carr_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0ULL; + //d_sample_counter_seconds = 0; + d_acq_sample_stamp = 0; + + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["R"] = std::string("Glonass"); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_carrier_doppler_phase_step_rad = 0.0; + d_carrier_frequency_hz = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_code_phase_samples = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + + d_glonass_freq_ch = 0; + + set_relative_rate(1.0 / static_cast(d_vector_length)); +} + + +void Glonass_L2_Ca_Dll_Pll_Tracking_cc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + d_glonass_freq_ch = GLONASS_L2_CA_FREQ_HZ + (DFRQ2_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GLONASS_L2_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_current_prn_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GLONASS_L2_CA_CODE_LENGTH_CHIPS / GLONASS_L2_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_frequency_hz = d_acq_carrier_doppler_hz + (DFRQ2_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + d_carrier_doppler_phase_step_rad = GLONASS_TWO_PI * (d_carrier_doppler_hz) / static_cast(d_fs_in); + + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(); // initialize the carrier filter + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + glonass_l2_ca_code_gen_complex(d_ca_code, 0); + + multicorrelator_cpu.set_local_code_and_taps(static_cast(GLONASS_L2_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GLONASS L2 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GLONASS L2 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_frequency_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +Glonass_L2_Ca_Dll_Pll_Tracking_cc::~Glonass_L2_Ca_Dll_Pll_Tracking_cc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + Glonass_L2_Ca_Dll_Pll_Tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int32_t Glonass_L2_Ca_Dll_Pll_Tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void Glonass_L2_Ca_Dll_Pll_Tracking_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void Glonass_L2_Ca_Dll_Pll_Tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int Glonass_L2_Ca_Dll_Pll_Tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // process vars + double carr_error_hz = 0.0; + double carr_error_filt_hz = 0.0; + double code_error_chips = 0.0; + double code_error_filt_chips = 0.0; + + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); // PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + int32_t samples_offset; + double acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter = d_sample_counter + static_cast(samples_offset); // count for the processed samples + d_pull_in = false; + // take into account the carrier cycles accumulated in the pull in signal alignment + d_acc_carrier_phase_rad -= d_carrier_doppler_phase_step_rad * samples_offset; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + current_synchro_data.correlation_length_ms = 1; + *out[0] = current_synchro_data; + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_current_prn_length_samples); + + // ################## PLL ########################################################## + // PLL discriminator + // Update PLL discriminator [rads/Ti -> Secs/Ti] + carr_error_hz = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GLONASS_TWO_PI; // prompt output + // Carrier discriminator filter + carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); + // New carrier Doppler frequency estimation + d_carrier_frequency_hz += carr_error_filt_hz; + d_carrier_doppler_hz += carr_error_filt_hz; + d_code_freq_chips = GLONASS_L2_CA_CODE_RATE_HZ + ((d_carrier_doppler_hz * GLONASS_L2_CA_CODE_RATE_HZ) / d_glonass_freq_ch); + + // ################## DLL ########################################################## + // DLL discriminator + code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + // Code discriminator filter + code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); // [chips/second] + double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + double T_prn_seconds = T_chip_seconds * GLONASS_L2_CA_CODE_LENGTH_CHIPS; + double code_error_filt_secs = (T_prn_seconds * code_error_filt_chips * T_chip_seconds); //[seconds] + //double code_error_filt_secs = (GPS_L1_CA_CODE_PERIOD * code_error_filt_chips) / GLONASS_L1_CA_CODE_RATE_HZ; // [seconds] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + //double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + //double T_prn_seconds = T_chip_seconds * GLONASS_L1_CA_CODE_LENGTH_CHIPS; + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); + d_current_prn_length_samples = round(K_blk_samples); // round to a discrete number of samples + + //################### PLL COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_doppler_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_frequency_hz / static_cast(d_fs_in); + // remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad = d_rem_carr_phase_rad + d_carrier_phase_step_rad * d_current_prn_length_samples; + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GLONASS_TWO_PI); + // carrier phase accumulator + d_acc_carrier_phase_rad -= d_carrier_doppler_phase_step_rad * d_current_prn_length_samples; + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, GLONASS_L2_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 1; + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.System = {'R'}; + current_synchro_data.correlation_length_ms = 1; + } + + //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_float; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = carr_error_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = carr_error_filt_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = code_error_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_current_prn_length_samples; // count for the processed samples + return 1; // output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.h similarity index 53% rename from src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.h rename to src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.h index 0a94f8e92..f2f4ebab5 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l2_ca_dll_pll_tracking_cc.h @@ -1,16 +1,17 @@ /*! - * \file gps_l2_m_dll_pll_tracking_cc.h - * \brief Interface of a code DLL + carrier PLL tracking block - * \author Javier Arribas, 2015. jarribas(at)cttc.es + * \file glonass_l2_ca_dll_pll_tracking_cc.h + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Damian Miralles, 2018. dmiralles2009(at)gmail.com + * * * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency Approach, - * Birkhauser, 2007 + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkha user, 2007 * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,85 +29,82 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_L2_M_DLL_PLL_TRACKING_CC_H -#define GNSS_SDR_GPS_L2_M_DLL_PLL_TRACKING_CC_H +#ifndef GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_CC_H +#define GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_CC_H -#include -#include -#include -#include +#include "cpu_multicorrelator.h" #include "gnss_synchro.h" #include "tracking_2nd_DLL_filter.h" #include "tracking_2nd_PLL_filter.h" -#include "cpu_multicorrelator.h" +#include +#include +#include +#include -class gps_l2_m_dll_pll_tracking_cc; +class Glonass_L2_Ca_Dll_Pll_Tracking_cc; -typedef boost::shared_ptr - gps_l2_m_dll_pll_tracking_cc_sptr; - -gps_l2_m_dll_pll_tracking_cc_sptr -gps_l2_m_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); +typedef boost::shared_ptr + glonass_l2_ca_dll_pll_tracking_cc_sptr; +glonass_l2_ca_dll_pll_tracking_cc_sptr +glonass_l2_ca_dll_pll_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class gps_l2_m_dll_pll_tracking_cc: public gr::block +class Glonass_L2_Ca_Dll_Pll_Tracking_cc : public gr::block { public: - ~gps_l2_m_dll_pll_tracking_cc(); + ~Glonass_L2_Ca_Dll_Pll_Tracking_cc(); - void set_channel(unsigned int channel); + void set_channel(uint32_t channel); void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); private: - friend gps_l2_m_dll_pll_tracking_cc_sptr - gps_l2_m_dll_pll_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + friend glonass_l2_ca_dll_pll_tracking_cc_sptr + glonass_l2_ca_dll_pll_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); - gps_l2_m_dll_pll_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + Glonass_L2_Ca_Dll_Pll_Tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; - long d_if_freq; - long d_fs_in; + uint32_t d_channel; + + int64_t d_fs_in; + int64_t d_glonass_freq_ch; double d_early_late_spc_chips; @@ -123,34 +121,37 @@ private: double d_acq_code_phase_samples; double d_acq_carrier_doppler_hz; // correlator - int d_n_correlator_taps; + int32_t d_n_correlator_taps; gr_complex* d_ca_code; float* d_local_code_shift_chips; gr_complex* d_correlator_outs; cpu_multicorrelator multicorrelator_cpu; + // tracking vars double d_code_freq_chips; double d_code_phase_step_chips; double d_carrier_doppler_hz; + double d_carrier_doppler_phase_step_rad; + double d_carrier_frequency_hz; double d_carrier_phase_step_rad; double d_acc_carrier_phase_rad; double d_code_phase_samples; - // PRN period in samples - int d_current_prn_length_samples; + //PRN period in samples + int32_t d_current_prn_length_samples; - // processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + //processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; + int32_t d_cn0_estimation_counter; gr_complex* d_Prompt_buffer; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -162,6 +163,8 @@ private: std::map systemName; std::string sys; + + int32_t save_matfile(); }; -#endif //GNSS_SDR_GPS_L2_M_DLL_PLL_TRACKING_CC_H +#endif //GNSS_SDR_GLONASS_L2_CA_DLL_PLL_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.cc index cc12ef4a9..5db4bef9b 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,65 +23,56 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_dll_pll_c_aid_tracking_cc.h" +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include "gps_sdr_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "control_message_factory.h" - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 +#include using google::LogMessage; gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr gps_l1_ca_dll_pll_c_aid_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) { - return gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr(new gps_l1_ca_dll_pll_c_aid_tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz,pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); + return gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr(new gps_l1_ca_dll_pll_c_aid_tracking_cc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); } -void gps_l1_ca_dll_pll_c_aid_tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void gps_l1_ca_dll_pll_c_aid_tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call } } @@ -89,10 +80,10 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::forecast (int noutput_items, void gps_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index(pmt::pmt_t msg) { //pmt::print(msg); - DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); - if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator { - d_preamble_timestamp_s = pmt::to_double(msg); + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); d_enable_extended_integration = true; d_preamble_synchronized = false; } @@ -100,34 +91,31 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index(pmt::pmt_t gps_l1_ca_dll_pll_c_aid_tracking_cc::gps_l1_ca_dll_pll_c_aid_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips) : - gr::block("gps_l1_ca_dll_pll_c_aid_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("gps_l1_ca_dll_pll_c_aid_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { // Telemetry bit synchronization message port input this->message_port_register_in(pmt::mp("preamble_timestamp_s")); this->set_msg_handler(pmt::mp("preamble_timestamp_s"), - boost::bind(&gps_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index, this, _1)); + boost::bind(&gps_l1_ca_dll_pll_c_aid_tracking_cc::msg_handler_preamble_index, this, _1)); this->message_port_register_out(pmt::mp("events")); // initialize internal vars d_dump = dump; - d_if_freq = if_freq; d_fs_in = fs_in; d_vector_length = vector_length; - d_dump_filename = dump_filename; - d_correlation_length_samples = static_cast(d_vector_length); + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); // Initialize tracking ========================================== d_pll_bw_hz = pll_bw_hz; @@ -139,22 +127,22 @@ gps_l1_ca_dll_pll_c_aid_tracking_cc::gps_l1_ca_dll_pll_c_aid_tracking_cc( d_carrier_loop_filter.set_params(10.0, d_pll_bw_hz, 2); // --- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) // Initialization of local code replica // Get space for a vector with the C/A code replica sampled 1x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // correlator outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, and Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(float), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; @@ -169,25 +157,25 @@ gps_l1_ca_dll_pll_c_aid_tracking_cc::gps_l1_ca_dll_pll_c_aid_tracking_cc( d_rem_carrier_phase_rad = 0.0; // sample synchronization - d_sample_counter = 0; //(from trk to tlm) + d_sample_counter = 0ULL; //(from trk to tlm) d_acq_sample_stamp = 0; d_enable_tracking = false; d_pull_in = false; // CN0 estimation and lock detector buffers d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; d_carrier_lock_test = 1; d_CN0_SNV_dB_Hz = 0; d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; systemName["G"] = std::string("GPS"); systemName["S"] = std::string("SBAS"); set_relative_rate(1.0 / static_cast(d_vector_length)); - d_acquisition_gnss_synchro = 0; + d_acquisition_gnss_synchro = nullptr; d_channel = 0; d_acq_code_phase_samples = 0.0; d_acq_carrier_doppler_hz = 0.0; @@ -207,7 +195,7 @@ gps_l1_ca_dll_pll_c_aid_tracking_cc::gps_l1_ca_dll_pll_c_aid_tracking_cc( d_code_error_filt_chips_s = 0.0; d_carr_phase_error_secs_Ti = 0.0; d_preamble_timestamp_s = 0.0; - //set_min_output_buffer((long int)300); + //set_min_output_buffer((int64_t)300); } @@ -220,9 +208,9 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - long int acq_trk_diff_samples; + int64_t acq_trk_diff_samples; double acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp);//-d_vector_length; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); // Doppler effect @@ -259,16 +247,16 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); // The carrier loop filter implements the Doppler accumulator - d_code_loop_filter.initialize(); // initialize the code filter + d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter // generate local reference ALWAYS starting at chip 1 (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); - multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) + multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } d_carrier_lock_fail_counter = 0; @@ -280,11 +268,11 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() d_code_phase_samples = d_acq_code_phase_samples; std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); + sys = sys_.substr(0, 1); // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GPS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; // enable tracking d_pull_in = true; @@ -299,24 +287,291 @@ void gps_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() gps_l1_ca_dll_pll_c_aid_tracking_cc::~gps_l1_ca_dll_pll_c_aid_tracking_cc() { - d_dump_file.close(); + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - volk_gnsssdr_free(d_ca_code); + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + gps_l1_ca_dll_pll_c_aid_tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } - delete[] d_Prompt_buffer; - multicorrelator_cpu.free(); + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } } +int32_t gps_l1_ca_dll_pll_c_aid_tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; -int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void gps_l1_ca_dll_pll_c_aid_tracking_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void gps_l1_ca_dll_pll_c_aid_tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); + auto **out = reinterpret_cast(&output_items[0]); // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder Gnss_Synchro current_synchro_data = Gnss_Synchro(); @@ -333,39 +588,40 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri // Receiver signal alignment if (d_pull_in == true) { - int samples_offset; + int32_t samples_offset; double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; + int32_t acq_to_trk_delay_samples; acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - d_sample_counter += samples_offset; // count for the processed samples + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples d_pull_in = false; d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GPS_TWO_PI; current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GPS_TWO_PI; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; *out[0] = current_synchro_data; - consume_each(samples_offset); // shift input to perform alignment with local replica + consume_each(samples_offset); // shift input to perform alignment with local replica return 1; } // ################# CARRIER WIPEOFF AND CORRELATORS ############################## // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs,in); + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, - d_carrier_phase_step_rad, - d_rem_code_phase_chips, - d_code_phase_step_chips, - d_correlation_length_samples); + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_correlation_length_samples); - // ####### coherent intergration extension + // ####### coherent integration extension // keep the last symbols - d_E_history.push_back(d_correlator_outs[0]); // save early output - d_P_history.push_back(d_correlator_outs[1]); // save prompt output - d_L_history.push_back(d_correlator_outs[2]); // save late output + d_E_history.push_back(d_correlator_outs[0]); // save early output + d_P_history.push_back(d_correlator_outs[1]); // save prompt output + d_L_history.push_back(d_correlator_outs[2]); // save late output - if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) { d_E_history.pop_front(); d_P_history.pop_front(); @@ -375,16 +631,16 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri bool enable_dll_pll; if (d_enable_extended_integration == true) { - long int symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) { // compute coherent integration and enable tracking loop // perform coherent integration using correlator output history // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + std::cout << "Enabled " << d_extend_correlation_ms << " [ms] extended correlator for CH " << d_channel << " : Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; } // UPDATE INTEGRATION TIME CURRENT_INTEGRATION_TIME_S = static_cast(d_extend_correlation_ms) * GPS_L1_CA_CODE_PERIOD; + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); enable_dll_pll = true; } else { - if(d_preamble_synchronized == true) + if (d_preamble_synchronized == true) { // continue extended coherent correlation // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation double T_chip_seconds = 1.0 / d_code_freq_chips; double T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - int K_prn_samples = round(T_prn_samples); + int32_t K_prn_samples = round(T_prn_samples); double K_T_prn_error_samples = K_prn_samples - T_prn_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; - d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; // code phase step (Code resampler phase increment per sample) [chips/sample] @@ -438,6 +695,7 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri // perform basic (1ms) correlation // UPDATE INTEGRATION TIME CURRENT_INTEGRATION_TIME_S = static_cast(d_correlation_length_samples) / static_cast(d_fs_in); + d_code_loop_filter.set_pdi(CURRENT_INTEGRATION_TIME_S); enable_dll_pll = true; } } @@ -453,7 +711,7 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri { // ################## PLL ########################################################## // Update PLL discriminator [rads/Ti -> Secs/Ti] - d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; // prompt output + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; // prompt output // Carrier discriminator filter // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan // Input [s/Ti] -> output [Hz] @@ -465,13 +723,13 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri // ################## DLL ########################################################## // DLL discriminator - d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late // Code discriminator filter - d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; - code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### // keep alignment parameters for the next input buffer // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation double T_chip_seconds = 1.0 / d_code_freq_chips; @@ -480,12 +738,12 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri double K_prn_samples = round(T_prn_samples); double K_T_prn_error_samples = K_prn_samples - T_prn_samples; - d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); - d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; - //################### PLL COMMANDS ################################################# + //################### PLL COMMANDS ################################################# //carrier phase step (NCO phase increment per sample) [rads/sample] d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GPS_TWO_PI; @@ -501,21 +759,21 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + if (d_cn0_estimation_counter < FLAGS_cn0_samples) { // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; // prompt + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; // prompt d_cn0_estimation_counter++; } else { d_cn0_estimation_counter = 0; // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L1_CA_CODE_LENGTH_CHIPS); + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) { d_carrier_lock_fail_counter++; } @@ -523,21 +781,20 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri { if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) { std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine } } // ########### Output the tracking data to navigation and PVT ########## current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + d_rem_code_phase_samples) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = GPS_TWO_PI * d_acc_carrier_phase_cycles; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; @@ -555,117 +812,98 @@ int gps_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __attri { current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + d_rem_code_phase_samples) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = GPS_TWO_PI * d_acc_carrier_phase_cycles; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz;// todo: project the carrier doppler + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; } } else { - for (int n = 0; n < d_n_correlator_taps; n++) + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } current_synchro_data.System = {'G'}; - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); } //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; *out[0] = current_synchro_data; - if(d_dump) + if (d_dump) { // MULTIPLEXED FILE RECORDING - Record results to file float prompt_I; float prompt_Q; float tmp_E, tmp_P, tmp_L; - double tmp_double; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; prompt_I = d_correlator_outs[1].real(); prompt_Q = d_correlator_outs[1].imag(); tmp_E = std::abs(d_correlator_outs[0]); tmp_P = std::abs(d_correlator_outs[1]); tmp_L = std::abs(d_correlator_outs[2]); try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_cycles), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - //PLL commands - d_dump_file.write(reinterpret_cast(&d_carr_phase_error_secs_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - - //DLL commands - d_dump_file.write(reinterpret_cast(&d_code_error_chips_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_error_filt_chips_Ti), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "Exception writing trk dump file " << e->what(); - } - } - - consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates - d_sample_counter += d_correlation_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - -void gps_l1_ca_dll_pll_c_aid_tracking_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e->what() << std::endl; - } + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GPS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); } } -} - - - -void gps_l1_ca_dll_pll_c_aid_tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; + + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples + + if (d_enable_tracking) + { + return 1; + } + + return 0; } diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.h index 8801a96fb..43db468ae 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_cc.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,92 +37,87 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H #define GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H -#include -#include -#include -#include -#include -#include #include "gnss_synchro.h" #include "tracking_2nd_DLL_filter.h" #include "tracking_FLL_PLL_filter.h" //#include "tracking_loop_filter.h" #include "cpu_multicorrelator.h" +#include +#include +#include +#include +#include +#include class gps_l1_ca_dll_pll_c_aid_tracking_cc; typedef boost::shared_ptr - gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr; + gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr; gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr -gps_l1_ca_dll_pll_c_aid_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); - +gps_l1_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class gps_l1_ca_dll_pll_c_aid_tracking_cc: public gr::block +class gps_l1_ca_dll_pll_c_aid_tracking_cc : public gr::block { public: ~gps_l1_ca_dll_pll_c_aid_tracking_cc(); - void set_channel(unsigned int channel); + void set_channel(uint32_t channel); void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); private: friend gps_l1_ca_dll_pll_c_aid_tracking_cc_sptr - gps_l1_ca_dll_pll_c_aid_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); + gps_l1_ca_dll_pll_c_aid_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); - gps_l1_ca_dll_pll_c_aid_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); + gps_l1_ca_dll_pll_c_aid_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; - long d_if_freq; - long d_fs_in; + uint32_t d_channel; + int64_t d_fs_in; double d_early_late_spc_chips; - int d_n_correlator_taps; + int32_t d_n_correlator_taps; gr_complex* d_ca_code; float* d_local_code_shift_chips; @@ -133,7 +128,7 @@ private: double d_rem_code_phase_samples; double d_rem_code_phase_chips; double d_rem_carrier_phase_rad; - int d_rem_code_phase_integer_samples; + int32_t d_rem_code_phase_integer_samples; // PLL and DLL filter library //Tracking_2nd_DLL_filter d_code_loop_filter; @@ -166,25 +161,25 @@ private: std::deque d_P_history; std::deque d_L_history; double d_preamble_timestamp_s; - int d_extend_correlation_ms; + int32_t d_extend_correlation_ms; bool d_enable_extended_integration; bool d_preamble_synchronized; void msg_handler_preamble_index(pmt::pmt_t msg); //Integration period in samples - int d_correlation_length_samples; + int32_t d_correlation_length_samples; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; + int32_t d_cn0_estimation_counter; gr_complex* d_Prompt_buffer; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -196,6 +191,8 @@ private: std::map systemName; std::string sys; + + int32_t save_matfile(); }; -#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H +#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.cc index 309fa2cbf..457b7e65f 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,67 +23,56 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_dll_pll_c_aid_tracking_sc.h" +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "gps_sdr_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "control_message_factory.h" - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 +#include using google::LogMessage; gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr gps_l1_ca_dll_pll_c_aid_make_tracking_sc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) { - return gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr(new gps_l1_ca_dll_pll_c_aid_tracking_sc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); + return gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr(new gps_l1_ca_dll_pll_c_aid_tracking_sc( + fs_in, vector_length, dump, std::move(dump_filename), pll_bw_hz, dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, extend_correlation_ms, early_late_space_chips)); } - -void gps_l1_ca_dll_pll_c_aid_tracking_sc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void gps_l1_ca_dll_pll_c_aid_tracking_sc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call } } @@ -91,42 +80,39 @@ void gps_l1_ca_dll_pll_c_aid_tracking_sc::forecast (int noutput_items, void gps_l1_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index(pmt::pmt_t msg) { //pmt::print(msg); - DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); - if (d_enable_extended_integration == false) //avoid re-setting preamble indicator + DLOG(INFO) << "Extended correlation enabled for Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN); + if (d_enable_extended_integration == false) //avoid re-setting preamble indicator { - d_preamble_timestamp_s = pmt::to_double(msg); + d_preamble_timestamp_s = pmt::to_double(std::move(msg)); d_enable_extended_integration = true; d_preamble_synchronized = false; } } gps_l1_ca_dll_pll_c_aid_tracking_sc::gps_l1_ca_dll_pll_c_aid_tracking_sc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips) : - gr::block("gps_l1_ca_dll_pll_c_aid_tracking_sc", gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips) : gr::block("gps_l1_ca_dll_pll_c_aid_tracking_sc", gr::io_signature::make(1, 1, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { // Telemetry bit synchronization message port input this->message_port_register_in(pmt::mp("preamble_timestamp_s")); this->set_msg_handler(pmt::mp("preamble_timestamp_s"), - boost::bind(&gps_l1_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index, this, _1)); + boost::bind(&gps_l1_ca_dll_pll_c_aid_tracking_sc::msg_handler_preamble_index, this, _1)); this->message_port_register_out(pmt::mp("events")); // initialize internal vars d_dump = dump; - d_if_freq = if_freq; d_fs_in = fs_in; d_vector_length = vector_length; - d_dump_filename = dump_filename; - d_correlation_length_samples = static_cast(d_vector_length); + d_dump_filename = std::move(dump_filename); + d_correlation_length_samples = static_cast(d_vector_length); // Initialize tracking ========================================== d_pll_bw_hz = pll_bw_hz; @@ -138,25 +124,25 @@ gps_l1_ca_dll_pll_c_aid_tracking_sc::gps_l1_ca_dll_pll_c_aid_tracking_sc( d_extend_correlation_ms = extend_correlation_ms; // --- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) // Initialization of local code replica // Get space for a vector with the C/A code replica sampled 1x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); // correlator outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, and Late + d_n_correlator_taps = 3; // Early, Prompt, and Late - d_correlator_outs_16sc = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) + d_correlator_outs_16sc = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs_16sc[n] = lv_cmake(0,0); + d_correlator_outs_16sc[n] = lv_cmake(0, 0); } - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(float), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; @@ -171,25 +157,25 @@ gps_l1_ca_dll_pll_c_aid_tracking_sc::gps_l1_ca_dll_pll_c_aid_tracking_sc( d_rem_carrier_phase_rad = 0.0; // sample synchronization - d_sample_counter = 0; //(from trk to tlm) + d_sample_counter = 0ULL; //(from trk to tlm) d_acq_sample_stamp = 0; d_enable_tracking = false; d_pull_in = false; // CN0 estimation and lock detector buffers d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; d_carrier_lock_test = 1; d_CN0_SNV_dB_Hz = 0; d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; systemName["G"] = std::string("GPS"); systemName["S"] = std::string("SBAS"); set_relative_rate(1.0 / static_cast(d_vector_length)); - d_acquisition_gnss_synchro = 0; + d_acquisition_gnss_synchro = nullptr; d_channel = 0; d_acq_code_phase_samples = 0.0; d_acq_carrier_doppler_hz = 0.0; @@ -208,7 +194,7 @@ gps_l1_ca_dll_pll_c_aid_tracking_sc::gps_l1_ca_dll_pll_c_aid_tracking_sc( d_code_error_filt_chips_Ti = 0.0; d_preamble_timestamp_s = 0.0; d_carr_phase_error_secs_Ti = 0.0; - //set_min_output_buffer((long int)300); + //set_min_output_buffer((int64_t)300); } @@ -221,9 +207,9 @@ void gps_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - long int acq_trk_diff_samples; + int64_t acq_trk_diff_samples; double acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp);//-d_vector_length; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); // Doppler effect @@ -260,17 +246,17 @@ void gps_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); // The carrier loop filter implements the Doppler accumulator - d_code_loop_filter.initialize(); // initialize the code filter + d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); // The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter // generate local reference ALWAYS starting at chip 1 (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); - volk_gnsssdr_32fc_convert_16ic(d_ca_code_16sc, d_ca_code, static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)); + volk_gnsssdr_32fc_convert_16ic(d_ca_code_16sc, d_ca_code, static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)); - multicorrelator_cpu_16sc.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code_16sc, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) + multicorrelator_cpu_16sc.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code_16sc, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs_16sc[n] = lv_16sc_t(0,0); + d_correlator_outs_16sc[n] = lv_16sc_t(0, 0); } d_carrier_lock_fail_counter = 0; @@ -282,11 +268,11 @@ void gps_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() d_code_phase_samples = d_acq_code_phase_samples; std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); + sys = sys_.substr(0, 1); // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GPS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; // enable tracking d_pull_in = true; @@ -295,32 +281,299 @@ void gps_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() d_preamble_synchronized = false; LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; } gps_l1_ca_dll_pll_c_aid_tracking_sc::~gps_l1_ca_dll_pll_c_aid_tracking_sc() { - d_dump_file.close(); + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_ca_code); - volk_gnsssdr_free(d_ca_code_16sc); - volk_gnsssdr_free(d_correlator_outs_16sc); + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + gps_l1_ca_dll_pll_c_aid_tracking_sc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } - delete[] d_Prompt_buffer; - multicorrelator_cpu_16sc.free(); + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_ca_code); + volk_gnsssdr_free(d_ca_code_16sc); + volk_gnsssdr_free(d_correlator_outs_16sc); + delete[] d_Prompt_buffer; + multicorrelator_cpu_16sc.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } } +int32_t gps_l1_ca_dll_pll_c_aid_tracking_sc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 11; + int32_t number_of_float_vars = 5; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new double[num_epoch]; + auto *carrier_doppler_hz = new double[num_epoch]; + auto *code_freq_chips = new double[num_epoch]; + auto *carr_error_hz = new double[num_epoch]; + auto *carr_error_filt_hz = new double[num_epoch]; + auto *code_error_chips = new double[num_epoch]; + auto *code_error_filt_chips = new double[num_epoch]; + auto *CN0_SNV_dB_Hz = new double[num_epoch]; + auto *carrier_lock_test = new double[num_epoch]; + auto *aux1 = new double[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; -int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void gps_l1_ca_dll_pll_c_aid_tracking_sc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void gps_l1_ca_dll_pll_c_aid_tracking_sc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { // Block input data and block output stream pointers - const lv_16sc_t* in = (lv_16sc_t*) input_items[0]; //PRN start block alignment - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; + const auto *in = reinterpret_cast(input_items[0]); //PRN start block alignment + auto **out = reinterpret_cast(&output_items[0]); // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder Gnss_Synchro current_synchro_data = Gnss_Synchro(); @@ -337,20 +590,21 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri // Receiver signal alignment if (d_pull_in == true) { - int samples_offset; + int32_t samples_offset; double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; + int32_t acq_to_trk_delay_samples; acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - d_sample_counter += samples_offset; // count for the processed samples + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + d_sample_counter += static_cast(samples_offset); // count for the processed samples d_pull_in = false; d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * samples_offset / GPS_TWO_PI; current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_cycles * GPS_TWO_PI; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; *out[0] = current_synchro_data; - consume_each(samples_offset); // shift input to perform alignment with local replica + consume_each(samples_offset); // shift input to perform alignment with local replica return 1; } @@ -363,13 +617,13 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri d_code_phase_step_chips, d_correlation_length_samples); - // ####### coherent intergration extension + // ####### coherent integration extension // keep the last symbols - d_E_history.push_back(d_correlator_outs_16sc[0]); // save early output - d_P_history.push_back(d_correlator_outs_16sc[1]); // save prompt output - d_L_history.push_back(d_correlator_outs_16sc[2]); // save late output + d_E_history.push_back(d_correlator_outs_16sc[0]); // save early output + d_P_history.push_back(d_correlator_outs_16sc[1]); // save prompt output + d_L_history.push_back(d_correlator_outs_16sc[2]); // save late output - if (static_cast(d_P_history.size()) > d_extend_correlation_ms) + if (static_cast(d_P_history.size()) > d_extend_correlation_ms) { d_E_history.pop_front(); d_P_history.pop_front(); @@ -379,16 +633,16 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri bool enable_dll_pll; if (d_enable_extended_integration == true) { - long int symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); + int64_t symbol_diff = round(1000.0 * ((static_cast(d_sample_counter) + d_rem_code_phase_samples) / static_cast(d_fs_in) - d_preamble_timestamp_s)); if (symbol_diff > 0 and symbol_diff % d_extend_correlation_ms == 0) { // compute coherent integration and enable tracking loop // perform coherent integration using correlator output history // std::cout<<"##### RESET COHERENT INTEGRATION ####"<PRN) + std::cout << "Enabled " << d_extend_correlation_ms << " [ms] extended correlator for CH " << d_channel << " : Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " pll_bw = " << d_pll_bw_hz << " [Hz], pll_narrow_bw = " << d_pll_bw_narrow_hz << " [Hz]" << std::endl << " dll_bw = " << d_dll_bw_hz << " [Hz], dll_narrow_bw = " << d_dll_bw_narrow_hz << " [Hz]" << std::endl; } @@ -410,18 +664,18 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri } else { - if(d_preamble_synchronized == true) + if (d_preamble_synchronized == true) { // continue extended coherent correlation // Compute the next buffer length based on the period of the PRN sequence and the code phase error estimation double T_chip_seconds = 1.0 / d_code_freq_chips; double T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - int K_prn_samples = round(T_prn_samples); + int32_t K_prn_samples = round(T_prn_samples); double K_T_prn_error_samples = K_prn_samples - T_prn_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples; - d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; // code phase step (Code resampler phase increment per sample) [chips/sample] @@ -457,7 +711,7 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri { // ################## PLL ########################################################## // Update PLL discriminator [rads/Ti -> Secs/Ti] - d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(std::complex(d_correlator_outs_16sc[1].real(),d_correlator_outs_16sc[1].imag())) / GPS_TWO_PI; //prompt output + d_carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(std::complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())) / GPS_TWO_PI; //prompt output // Carrier discriminator filter // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan @@ -470,13 +724,13 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri // ################## DLL ########################################################## // DLL discriminator - d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(std::complex(d_correlator_outs_16sc[0].real(),d_correlator_outs_16sc[0].imag()), std::complex(d_correlator_outs_16sc[2].real(),d_correlator_outs_16sc[2].imag())); // [chips/Ti] //early and late + d_code_error_chips_Ti = dll_nc_e_minus_l_normalized(std::complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag()), std::complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); // [chips/Ti] //early and late // Code discriminator filter - d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] + d_code_error_filt_chips_s = d_code_loop_filter.get_code_nco(d_code_error_chips_Ti); // input [chips/Ti] -> output [chips/second] d_code_error_filt_chips_Ti = d_code_error_filt_chips_s * CURRENT_INTEGRATION_TIME_S; - code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] + code_error_filt_secs_Ti = d_code_error_filt_chips_Ti / d_code_freq_chips; // [s/Ti] - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### // keep alignment parameters for the next input buffer // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation double T_chip_seconds = 1.0 / d_code_freq_chips; @@ -485,12 +739,12 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri double K_prn_samples = round(T_prn_samples); double K_T_prn_error_samples = K_prn_samples - T_prn_samples; - d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); - d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples + d_rem_code_phase_samples = d_rem_code_phase_samples - K_T_prn_error_samples + code_error_filt_secs_Ti * static_cast(d_fs_in); //(code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti) * static_cast(d_fs_in); + d_rem_code_phase_integer_samples = round(d_rem_code_phase_samples); // round to a discrete number of samples d_correlation_length_samples = K_prn_samples + d_rem_code_phase_integer_samples; d_rem_code_phase_samples = d_rem_code_phase_samples - d_rem_code_phase_integer_samples; - //################### PLL COMMANDS ################################################# + //################### PLL COMMANDS ################################################# //carrier phase step (NCO phase increment per sample) [rads/sample] d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); d_acc_carrier_phase_cycles -= d_carrier_phase_step_rad * d_correlation_length_samples / GPS_TWO_PI; @@ -506,21 +760,21 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + if (d_cn0_estimation_counter < FLAGS_cn0_samples) { // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = lv_cmake(static_cast(d_correlator_outs_16sc[1].real()), static_cast(d_correlator_outs_16sc[1].imag()) ); // prompt + d_Prompt_buffer[d_cn0_estimation_counter] = lv_cmake(static_cast(d_correlator_outs_16sc[1].real()), static_cast(d_correlator_outs_16sc[1].imag())); // prompt d_cn0_estimation_counter++; } else { d_cn0_estimation_counter = 0; // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L1_CA_CODE_LENGTH_CHIPS); + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) { d_carrier_lock_fail_counter++; } @@ -528,21 +782,21 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri { if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) { std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine } } // ########### Output the tracking data to navigation and PVT ########## current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + d_rem_code_phase_samples) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = GPS_TWO_PI * d_acc_carrier_phase_cycles; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; @@ -560,115 +814,97 @@ int gps_l1_ca_dll_pll_c_aid_tracking_sc::general_work (int noutput_items __attri { current_synchro_data.Prompt_I = static_cast((d_correlator_outs_16sc[1]).real()); current_synchro_data.Prompt_Q = static_cast((d_correlator_outs_16sc[1]).imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + d_rem_code_phase_samples) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = GPS_TWO_PI * d_acc_carrier_phase_cycles; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz;// todo: project the carrier doppler + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; // todo: project the carrier doppler current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; } } else { - for (int n = 0; n < d_n_correlator_taps; n++) + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs_16sc[n] = lv_cmake(0,0); + d_correlator_outs_16sc[n] = lv_cmake(0, 0); } current_synchro_data.System = {'G'}; - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + d_correlation_length_samples + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); } + current_synchro_data.fs = d_fs_in; *out[0] = current_synchro_data; - if(d_dump) + if (d_dump) { // MULTIPLEXED FILE RECORDING - Record results to file float prompt_I; float prompt_Q; float tmp_E, tmp_P, tmp_L; - double tmp_double; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; prompt_I = d_correlator_outs_16sc[1].real(); prompt_Q = d_correlator_outs_16sc[1].imag(); - tmp_E = std::abs(std::complex(d_correlator_outs_16sc[0].real(),d_correlator_outs_16sc[0].imag())); - tmp_P = std::abs(std::complex(d_correlator_outs_16sc[1].real(),d_correlator_outs_16sc[1].imag())); - tmp_L = std::abs(std::complex(d_correlator_outs_16sc[2].real(),d_correlator_outs_16sc[2].imag())); + tmp_E = std::abs(gr_complex(d_correlator_outs_16sc[0].real(), d_correlator_outs_16sc[0].imag())); + tmp_P = std::abs(gr_complex(d_correlator_outs_16sc[1].real(), d_correlator_outs_16sc[1].imag())); + tmp_L = std::abs(gr_complex(d_correlator_outs_16sc[2].real(), d_correlator_outs_16sc[2].imag())); try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_cycles), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - //PLL commands - d_dump_file.write(reinterpret_cast(&d_carr_phase_error_secs_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - - //DLL commands - d_dump_file.write(reinterpret_cast(&d_code_error_chips_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_error_filt_chips_Ti), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "Exception writing trk dump file " << e->what(); - } - } - - consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates - d_sample_counter += d_correlation_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - -void gps_l1_ca_dll_pll_c_aid_tracking_sc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e->what() << std::endl; - } + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GPS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); } } -} + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples -void gps_l1_ca_dll_pll_c_aid_tracking_sc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; + if (d_enable_tracking) + { + return 1; + } + + return 0; } diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.h index caf81d7c8..f7624e944 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.h +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_sc.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,94 +37,89 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H #define GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H -#include -#include -#include +#include "cpu_multicorrelator_16sc.h" +#include "gnss_synchro.h" +#include "gps_sdr_signal_processing.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_FLL_PLL_filter.h" #include #include #include -#include -#include "gps_sdr_signal_processing.h" -#include "gnss_synchro.h" -#include "tracking_2nd_DLL_filter.h" -#include "tracking_FLL_PLL_filter.h" -#include "cpu_multicorrelator_16sc.h" +#include +#include +#include +#include class gps_l1_ca_dll_pll_c_aid_tracking_sc; typedef boost::shared_ptr - gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr; + gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr; gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr -gps_l1_ca_dll_pll_c_aid_make_tracking_sc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); - +gps_l1_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class gps_l1_ca_dll_pll_c_aid_tracking_sc: public gr::block +class gps_l1_ca_dll_pll_c_aid_tracking_sc : public gr::block { public: ~gps_l1_ca_dll_pll_c_aid_tracking_sc(); - void set_channel(unsigned int channel); + void set_channel(uint32_t channel); void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); private: friend gps_l1_ca_dll_pll_c_aid_tracking_sc_sptr - gps_l1_ca_dll_pll_c_aid_make_tracking_sc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); + gps_l1_ca_dll_pll_c_aid_make_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); - gps_l1_ca_dll_pll_c_aid_tracking_sc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float pll_bw_narrow_hz, - float dll_bw_narrow_hz, - int extend_correlation_ms, - float early_late_space_chips); + gps_l1_ca_dll_pll_c_aid_tracking_sc( + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float pll_bw_narrow_hz, + float dll_bw_narrow_hz, + int32_t extend_correlation_ms, + float early_late_space_chips); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; + uint32_t d_channel; - long d_if_freq; - long d_fs_in; + int64_t d_fs_in; double d_early_late_spc_chips; - int d_n_correlator_taps; + int32_t d_n_correlator_taps; gr_complex* d_ca_code; lv_16sc_t* d_ca_code_16sc; @@ -138,7 +133,7 @@ private: double d_rem_code_phase_samples; double d_rem_code_phase_chips; double d_rem_carrier_phase_rad; - int d_rem_code_phase_integer_samples; + int32_t d_rem_code_phase_integer_samples; // PLL and DLL filter library Tracking_2nd_DLL_filter d_code_loop_filter; @@ -163,7 +158,7 @@ private: double d_carr_phase_error_secs_Ti; double d_code_error_chips_Ti; double d_preamble_timestamp_s; - int d_extend_correlation_ms; + int32_t d_extend_correlation_ms; bool d_enable_extended_integration; bool d_preamble_synchronized; double d_code_error_filt_chips_s; @@ -176,19 +171,19 @@ private: std::deque d_L_history; //Integration period in samples - int d_correlation_length_samples; + int32_t d_correlation_length_samples; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; + int32_t d_cn0_estimation_counter; gr_complex* d_Prompt_buffer; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -200,6 +195,8 @@ private: std::map systemName; std::string sys; + + int32_t save_matfile(); }; -#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H +#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_SC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.cc deleted file mode 100644 index deda7039e..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_cc.cc +++ /dev/null @@ -1,527 +0,0 @@ -/*! - * \file gps_l1_ca_dll_pll_tracking_cc.cc - * \brief Implementation of a code DLL + carrier PLL tracking block - * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * Javier Arribas, 2011. jarribas(at)cttc.es - * - * Code DLL + carrier PLL according to the algorithms described in: - * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkhauser, 2007 - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_dll_pll_tracking_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "gps_sdr_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "control_message_factory.h" - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 - - -using google::LogMessage; - -gps_l1_ca_dll_pll_tracking_cc_sptr -gps_l1_ca_dll_pll_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) -{ - return gps_l1_ca_dll_pll_tracking_cc_sptr(new Gps_L1_Ca_Dll_Pll_Tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips)); -} - - - -void Gps_L1_Ca_Dll_Pll_Tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) -{ - if (noutput_items != 0) - { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call - } -} - - - -Gps_L1_Ca_Dll_Pll_Tracking_cc::Gps_L1_Ca_Dll_Pll_Tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) : - gr::block("Gps_L1_Ca_Dll_Pll_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); - this->message_port_register_out(pmt::mp("events")); - - // initialize internal vars - d_dump = dump; - d_if_freq = if_freq; - d_fs_in = fs_in; - d_vector_length = vector_length; - d_dump_filename = dump_filename; - - d_current_prn_length_samples = static_cast(d_vector_length); - - // Initialize tracking ========================================== - d_code_loop_filter.set_DLL_BW(dll_bw_hz); - d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); - - //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) - - // Initialization of local code replica - // Get space for a vector with the C/A code replica sampled 1x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - // correlator outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, and Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(float), volk_gnsssdr_get_alignment())); - // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; - d_local_code_shift_chips[1] = 0.0; - d_local_code_shift_chips[2] = d_early_late_spc_chips; - - multicorrelator_cpu.init(2 * d_current_prn_length_samples, d_n_correlator_taps); - - //--- Perform initializations ------------------------------ - // define initial code frequency basis of NCO - d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ; - // define residual code phase (in chips) - d_rem_code_phase_samples = 0.0; - // define residual carrier phase - d_rem_carr_phase_rad = 0.0; - - // sample synchronization - d_sample_counter = 0; - //d_sample_counter_seconds = 0; - d_acq_sample_stamp = 0; - - d_enable_tracking = false; - d_pull_in = false; - - // CN0 estimation and lock detector buffers - d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; - d_carrier_lock_test = 1; - d_CN0_SNV_dB_Hz = 0; - d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; - - systemName["G"] = std::string("GPS"); - systemName["S"] = std::string("SBAS"); - - d_acquisition_gnss_synchro = 0; - d_channel = 0; - d_acq_code_phase_samples = 0.0; - d_acq_carrier_doppler_hz = 0.0; - d_carrier_doppler_hz = 0.0; - d_acc_carrier_phase_rad = 0.0; - d_code_phase_samples = 0.0; - d_rem_code_phase_chips = 0.0; - d_code_phase_step_chips = 0.0; - d_carrier_phase_step_rad = 0.0; - - set_relative_rate(1.0 / static_cast(d_vector_length)); -} - - -void Gps_L1_Ca_Dll_Pll_Tracking_cc::start_tracking() -{ - /* - * correct the code phase according to the delay between acq and trk - */ - d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; - d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - - long int acq_trk_diff_samples; - double acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; - DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; - acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); - // Doppler effect - // Fd=(C/(C+Vr))*F - double radial_velocity = (GPS_L1_FREQ_HZ + d_acq_carrier_doppler_hz) / GPS_L1_FREQ_HZ; - // new chip and prn sequence periods based on acq Doppler - double T_chip_mod_seconds; - double T_prn_mod_seconds; - double T_prn_mod_samples; - d_code_freq_chips = radial_velocity * GPS_L1_CA_CODE_RATE_HZ; - d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); - T_chip_mod_seconds = 1/d_code_freq_chips; - T_prn_mod_seconds = T_chip_mod_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; - T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); - - d_current_prn_length_samples = round(T_prn_mod_samples); - - double T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; - double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); - double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; - double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; - double corrected_acq_phase_samples, delay_correction_samples; - corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); - if (corrected_acq_phase_samples < 0) - { - corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; - } - delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; - - d_acq_code_phase_samples = corrected_acq_phase_samples; - - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; - d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - - // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(); // initialize the carrier filter - d_code_loop_filter.initialize(); // initialize the code filter - - // generate local reference ALWAYS starting at chip 1 (1 sample per chip) - gps_l1_ca_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); - - multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - - d_carrier_lock_fail_counter = 0; - d_rem_code_phase_samples = 0; - d_rem_carr_phase_rad = 0.0; - d_rem_code_phase_chips = 0.0; - d_acc_carrier_phase_rad = 0.0; - - d_code_phase_samples = d_acq_code_phase_samples; - - std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); - - // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; - - // enable tracking - d_pull_in = true; - d_enable_tracking = true; - - LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; -} - -Gps_L1_Ca_Dll_Pll_Tracking_cc::~Gps_L1_Ca_Dll_Pll_Tracking_cc() -{ - d_dump_file.close(); - - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - volk_gnsssdr_free(d_ca_code); - - delete[] d_Prompt_buffer; - multicorrelator_cpu.free(); -} - - - -int Gps_L1_Ca_Dll_Pll_Tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // process vars - double carr_error_hz = 0.0; - double carr_error_filt_hz = 0.0; - double code_error_chips = 0.0; - double code_error_filt_chips = 0.0; - - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data = Gnss_Synchro(); - - if (d_enable_tracking == true) - { - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - // Receiver signal alignment - if (d_pull_in == true) - { - int samples_offset; - double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; - acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); - samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - d_sample_counter = d_sample_counter + samples_offset; // count for the processed samples - d_pull_in = false; - // take into account the carrier cycles accumulated in the pull in signal alignment - d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * samples_offset; - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - *out[0] = current_synchro_data; - consume_each(samples_offset); // shift input to perform alignment with local replica - return 1; - } - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); - multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, - d_carrier_phase_step_rad, - d_rem_code_phase_chips, - d_code_phase_step_chips, - d_current_prn_length_samples); - - // ################## PLL ########################################################## - // PLL discriminator - // Update PLL discriminator [rads/Ti -> Secs/Ti] - carr_error_hz = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; // prompt output - // Carrier discriminator filter - carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); - // New carrier Doppler frequency estimation - d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ + ((d_carrier_doppler_hz * GPS_L1_CA_CODE_RATE_HZ) / GPS_L1_FREQ_HZ); - - // ################## DLL ########################################################## - // DLL discriminator - code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late - // Code discriminator filter - code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); // [chips/second] - double code_error_filt_secs = (GPS_L1_CA_CODE_PERIOD * code_error_filt_chips) / GPS_L1_CA_CODE_RATE_HZ; // [seconds] - - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### - // keep alignment parameters for the next input buffer - // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation - double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); - double T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; - double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); - d_current_prn_length_samples = round(K_blk_samples); // round to a discrete number of samples - - //################### PLL COMMANDS ################################################# - // carrier phase step (NCO phase increment per sample) [rads/sample] - d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - // remnant carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad = d_rem_carr_phase_rad + d_carrier_phase_step_rad * d_current_prn_length_samples; - d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GPS_TWO_PI); - // carrier phase accumulator - d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * d_current_prn_length_samples; - - //################### DLL COMMANDS ################################################# - // code phase step (Code resampler phase increment per sample) [chips/sample] - d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); - // remnant code phase [chips] - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; // rounding error < 1 sample - d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); - - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt - d_cn0_estimation_counter++; - } - else - { - d_cn0_estimation_counter = 0; - // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L1_CA_CODE_LENGTH_CHIPS); - // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); - // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine - } - } - // ########### Output the tracking data to navigation and PVT ########## - current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); - current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); - - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter + d_current_prn_length_samples) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms = 1; - } - else - { - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter + d_current_prn_length_samples) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - current_synchro_data.Rem_code_phase_secs = d_rem_code_phase_samples / static_cast(d_fs_in); - current_synchro_data.System = {'G'}; - } - - //assign the GNURadio block output data - *out[0] = current_synchro_data; - if(d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - float prompt_I; - float prompt_Q; - float tmp_E, tmp_P, tmp_L; - double tmp_double; - unsigned long int tmp_long; - prompt_I = d_correlator_outs[1].real(); - prompt_Q = d_correlator_outs[1].imag(); - tmp_E = std::abs(d_correlator_outs[0]); - tmp_P = std::abs(d_correlator_outs[1]); - tmp_L = std::abs(d_correlator_outs[2]); - try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - tmp_long = d_sample_counter + d_current_prn_length_samples; - d_dump_file.write(reinterpret_cast(&tmp_long), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - // PLL commands - d_dump_file.write(reinterpret_cast(&carr_error_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&carr_error_filt_hz), sizeof(double)); - - // DLL commands - d_dump_file.write(reinterpret_cast(&code_error_chips), sizeof(double)); - d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_rem_code_phase_samples; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what(); - } - } - - consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates - d_sample_counter += d_current_prn_length_samples; // count for the processed samples - - return 1; // output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - - -void Gps_L1_Ca_Dll_Pll_Tracking_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} - - -void Gps_L1_Ca_Dll_Pll_Tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; -} diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.cc index ab56ac1e6..36d27c0f6 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,116 +23,100 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_dll_pll_tracking_gpu_cc.h" +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include #include +#include #include #include #include -#include -#include -#include -#include "gps_sdr_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "control_message_factory.h" -// includes -#include - - -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 using google::LogMessage; gps_l1_ca_dll_pll_tracking_gpu_cc_sptr gps_l1_ca_dll_pll_make_tracking_gpu_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) { - return gps_l1_ca_dll_pll_tracking_gpu_cc_sptr(new Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips)); + return gps_l1_ca_dll_pll_tracking_gpu_cc_sptr(new Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( + fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips)); } - -void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call } } - Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) : - gr::block("Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips) : gr::block("Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { // Telemetry bit synchronization message port input this->message_port_register_in(pmt::mp("preamble_timestamp_s")); this->message_port_register_out(pmt::mp("events")); // initialize internal vars d_dump = dump; - d_if_freq = if_freq; d_fs_in = fs_in; d_vector_length = vector_length; d_dump_filename = dump_filename; - d_correlation_length_samples = static_cast(d_vector_length); + d_correlation_length_samples = static_cast(d_vector_length); // Initialize tracking ========================================== d_code_loop_filter.set_DLL_BW(dll_bw_hz); - d_carrier_loop_filter.set_params(10.0, pll_bw_hz,2); + d_carrier_loop_filter.set_params(10.0, pll_bw_hz, 2); //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) // Set GPU flags cudaSetDeviceFlags(cudaDeviceMapHost); //allocate host memory //pinned memory mode - use special function to get OS-pinned memory - d_n_correlator_taps = 3; // Early, Prompt, and Late + d_n_correlator_taps = 3; // Early, Prompt, and Late // Get space for a vector with the C/A code replica sampled 1x/chip - cudaHostAlloc((void**)&d_ca_code, (static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)* sizeof(gr_complex)), cudaHostAllocMapped || cudaHostAllocWriteCombined); + cudaHostAlloc((void **)&d_ca_code, (static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex)), cudaHostAllocMapped || cudaHostAllocWriteCombined); // Get space for the resampled early / prompt / late local replicas - cudaHostAlloc((void**)&d_local_code_shift_chips, d_n_correlator_taps * sizeof(float), cudaHostAllocMapped || cudaHostAllocWriteCombined); - cudaHostAlloc((void**)&in_gpu, 2 * d_vector_length * sizeof(gr_complex), cudaHostAllocMapped || cudaHostAllocWriteCombined); + cudaHostAlloc((void **)&d_local_code_shift_chips, d_n_correlator_taps * sizeof(float), cudaHostAllocMapped || cudaHostAllocWriteCombined); + cudaHostAlloc((void **)&in_gpu, 2 * d_vector_length * sizeof(gr_complex), cudaHostAllocMapped || cudaHostAllocWriteCombined); // correlator outputs (scalar) - cudaHostAlloc((void**)&d_correlator_outs ,sizeof(gr_complex)*d_n_correlator_taps, cudaHostAllocMapped || cudaHostAllocWriteCombined ); + cudaHostAlloc((void **)&d_correlator_outs, sizeof(gr_complex) * d_n_correlator_taps, cudaHostAllocMapped || cudaHostAllocWriteCombined); // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; - //--- Perform initializations ------------------------------ multicorrelator_gpu = new cuda_multicorrelator(); //local code resampler on GPU @@ -147,7 +131,7 @@ Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( d_rem_carrier_phase_rad = 0.0; // sample synchronization - d_sample_counter = 0; + d_sample_counter = 0ULL; //d_sample_counter_seconds = 0; d_acq_sample_stamp = 0; @@ -156,11 +140,11 @@ Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( // CN0 estimation and lock detector buffers d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; d_carrier_lock_test = 1; d_CN0_SNV_dB_Hz = 0; d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; systemName["G"] = std::string("GPS"); systemName["S"] = std::string("SBAS"); @@ -179,7 +163,7 @@ Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( d_rem_code_phase_chips = 0.0; d_code_phase_step_chips = 0.0; d_carrier_phase_step_rad = 0.0; - //set_min_output_buffer((long int)300); + //set_min_output_buffer((int64_t)300); } @@ -192,9 +176,9 @@ void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::start_tracking() d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - long int acq_trk_diff_samples; + int64_t acq_trk_diff_samples; double acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp);//-d_vector_length; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; DLOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); //doppler effect @@ -206,7 +190,7 @@ void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::start_tracking() double T_prn_mod_samples; d_code_freq_chips = radial_velocity * GPS_L1_CA_CODE_RATE_HZ; d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); - T_chip_mod_seconds = 1/d_code_freq_chips; + T_chip_mod_seconds = 1 / d_code_freq_chips; T_prn_mod_seconds = T_chip_mod_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); @@ -231,17 +215,17 @@ void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::start_tracking() d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); //The carrier loop filter implements the Doppler accumulator - d_code_loop_filter.initialize(); // initialize the code filter + d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz); //The carrier loop filter implements the Doppler accumulator + d_code_loop_filter.initialize(); // initialize the code filter // generate local reference ALWAYS starting at chip 1 (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); - multicorrelator_gpu->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips, d_n_correlator_taps); + multicorrelator_gpu->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips, d_n_correlator_taps); - for (int n = 0; n < d_n_correlator_taps; n++) + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } d_carrier_lock_fail_counter = 0; @@ -253,44 +237,90 @@ void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::start_tracking() d_code_phase_samples = d_acq_code_phase_samples; std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); + sys = sys_.substr(0, 1); // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; - + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GPS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; // enable tracking d_pull_in = true; d_enable_tracking = true; LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; } Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::~Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc() { - - d_dump_file.close(); - cudaFreeHost(in_gpu); - cudaFreeHost(d_correlator_outs); - cudaFreeHost(d_local_code_shift_chips); - cudaFreeHost(d_ca_code); - multicorrelator_gpu->free_cuda(); - delete[] d_Prompt_buffer; - delete(multicorrelator_gpu); + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + try + { + cudaFreeHost(in_gpu); + cudaFreeHost(d_correlator_outs); + cudaFreeHost(d_local_code_shift_chips); + cudaFreeHost(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_gpu->free_cuda(); + delete (multicorrelator_gpu); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } } +void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::set_channel(uint32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(boost::lexical_cast(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure *e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e->what(); + } + } + } +} -int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) + +void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; + const gr_complex *in = reinterpret_cast(input_items[0]); + Gnss_Synchro **out = reinterpret_cast(&output_items[0]); // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder Gnss_Synchro current_synchro_data = Gnss_Synchro(); @@ -311,19 +341,19 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu // Receiver signal alignment if (d_pull_in == true) { - int samples_offset; + int32_t samples_offset; double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; + int32_t acq_to_trk_delay_samples; acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; acq_trk_shif_correction_samples = d_correlation_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_correlation_length_samples)); samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + current_synchro_data.fs = d_fs_in; + current_synchro_data.correlation_length_ms = 1; *out[0] = current_synchro_data; - - d_sample_counter += samples_offset; //count for the processed samples + d_sample_counter += static_cast(samples_offset); //count for the processed samples d_pull_in = false; - consume_each(samples_offset); //shift input to perform alignment with local replica + consume_each(samples_offset); //shift input to perform alignment with local replica return 1; } @@ -332,11 +362,11 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu memcpy(in_gpu, in, sizeof(gr_complex) * d_correlation_length_samples); cudaProfilerStart(); - multicorrelator_gpu->Carrier_wipeoff_multicorrelator_resampler_cuda( static_cast(d_rem_carrier_phase_rad), - static_cast(d_carrier_phase_step_rad), - static_cast(d_code_phase_step_chips), - static_cast(d_rem_code_phase_chips), - d_correlation_length_samples, d_n_correlator_taps); + multicorrelator_gpu->Carrier_wipeoff_multicorrelator_resampler_cuda(static_cast(d_rem_carrier_phase_rad), + static_cast(d_carrier_phase_step_rad), + static_cast(d_code_phase_step_chips), + static_cast(d_rem_code_phase_chips), + d_correlation_length_samples, d_n_correlator_taps); cudaProfilerStop(); //std::cout<<"c_out[0]="< Secs/Ti] - carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; //prompt output + carr_phase_error_secs_Ti = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; //prompt output // Carrier discriminator filter // NOTICE: The carrier loop filter includes the Carrier Doppler accumulator, as described in Kaplan //d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_phase_error_filt_secs_ti/INTEGRATION_TIME; @@ -358,15 +388,15 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu // ################## DLL ########################################################## // DLL discriminator - code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); //[chips/Ti] //early and late + code_error_chips_Ti = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); //[chips/Ti] //early and late // Code discriminator filter - code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips_Ti); //input [chips/Ti] -> output [chips/second] - code_error_filt_secs_Ti = code_error_filt_chips*CURRENT_INTEGRATION_TIME_S/d_code_freq_chips; // [s/Ti] + code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips_Ti); //input [chips/Ti] -> output [chips/second] + code_error_filt_secs_Ti = code_error_filt_chips * CURRENT_INTEGRATION_TIME_S / d_code_freq_chips; // [s/Ti] // DLL code error estimation [s/Ti] // TODO: PLL carrier aid to DLL is disabled. Re-enable it and measure performance - dll_code_error_secs_Ti = - code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti; + dll_code_error_secs_Ti = -code_error_filt_secs_Ti + d_pll_to_dll_assist_secs_Ti; - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### // keep alignment parameters for the next input buffer double T_chip_seconds; double T_prn_seconds; @@ -378,12 +408,12 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu T_prn_samples = T_prn_seconds * static_cast(d_fs_in); K_blk_samples = T_prn_samples + d_rem_code_phase_samples - dll_code_error_secs_Ti * static_cast(d_fs_in); - d_correlation_length_samples = round(K_blk_samples); //round to a discrete samples - old_d_rem_code_phase_samples=d_rem_code_phase_samples; - d_rem_code_phase_samples = K_blk_samples - static_cast(d_correlation_length_samples); //rounding error < 1 sample + d_correlation_length_samples = round(K_blk_samples); //round to a discrete samples + old_d_rem_code_phase_samples = d_rem_code_phase_samples; + d_rem_code_phase_samples = K_blk_samples - static_cast(d_correlation_length_samples); //rounding error < 1 sample // UPDATE REMNANT CARRIER PHASE - CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples)/static_cast(d_fs_in)); + CORRECTED_INTEGRATION_TIME_S = (static_cast(d_correlation_length_samples) / static_cast(d_fs_in)); //remnant carrier phase [rad] d_rem_carrier_phase_rad = fmod(d_rem_carrier_phase_rad + GPS_TWO_PI * d_carrier_doppler_hz * CORRECTED_INTEGRATION_TIME_S, GPS_TWO_PI); // UPDATE CARRIER PHASE ACCUULATOR @@ -401,21 +431,21 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu d_rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / static_cast(d_fs_in)); // ####### CN0 ESTIMATION AND LOCK DETECTORS ####################################### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) + if (d_cn0_estimation_counter < FLAGS_cn0_samples) { // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt d_cn0_estimation_counter++; } else { d_cn0_estimation_counter = 0; // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L1_CA_CODE_LENGTH_CHIPS); + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) { d_carrier_lock_fail_counter++; } @@ -423,133 +453,117 @@ int Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::general_work (int noutput_items __attribu { if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) { std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine } } // ########### Output the tracking data to navigation and PVT ########## current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!) - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + old_d_rem_code_phase_samples) / static_cast(d_fs_in); - // This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0 - current_synchro_data.Code_phase_secs = 0; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = GPS_TWO_PI * d_acc_carrier_phase_cycles; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms=1; - + current_synchro_data.correlation_length_ms = 1; } else { - - for (int n = 0; n < d_n_correlator_taps; n++) + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } current_synchro_data.System = {'G'}; - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); + current_synchro_data.correlation_length_ms = 1; + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); } //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; *out[0] = current_synchro_data; - if(d_dump) + if (d_dump) { // MULTIPLEXED FILE RECORDING - Record results to file float prompt_I; float prompt_Q; float tmp_E, tmp_P, tmp_L; - double tmp_double; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; prompt_I = d_correlator_outs[1].real(); prompt_Q = d_correlator_outs[1].imag(); tmp_E = std::abs(d_correlator_outs[0]); tmp_P = std::abs(d_correlator_outs[1]); tmp_L = std::abs(d_correlator_outs[2]); try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_cycles), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - //PLL commands - d_dump_file.write(reinterpret_cast(&carr_phase_error_secs_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - - //DLL commands - d_dump_file.write(reinterpret_cast(&code_error_chips_Ti), sizeof(double)); - d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_rem_code_phase_samples; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "Exception writing trk dump file " << e->what(); - } - } - - consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates - d_sample_counter += d_correlation_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false -} - -void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str() << std::endl; - } - catch (const std::ifstream::failure* e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e->what() << std::endl; - } + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_cycles * GPS_TWO_PI; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 1.0 / (d_carr_phase_error_secs_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = 1.0 / (d_code_error_filt_chips_Ti * CURRENT_INTEGRATION_TIME_S); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_error_filt_chips_Ti; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_code_error_chips_Ti * CURRENT_INTEGRATION_TIME_S; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + double tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure *e) + { + LOG(WARNING) << "Exception writing trk dump file " << e->what(); } } -} + consume_each(d_correlation_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_correlation_length_samples; //count for the processed samples -void Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; + if (d_enable_tracking) + { + return 1; + } + else + { + return 0; + } } diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.h index e2a51b108..987af5686 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_gpu_cc.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,91 +36,90 @@ #ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_CC_H #define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_CC_H -#include -#include -#include -#include +#include "cuda_multicorrelator.h" #include "gnss_synchro.h" #include "tracking_2nd_DLL_filter.h" #include "tracking_FLL_PLL_filter.h" -#include "cuda_multicorrelator.h" +#include +#include +#include +#include + class Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc; typedef boost::shared_ptr - gps_l1_ca_dll_pll_tracking_gpu_cc_sptr; + gps_l1_ca_dll_pll_tracking_gpu_cc_sptr; gps_l1_ca_dll_pll_tracking_gpu_cc_sptr -gps_l1_ca_dll_pll_make_tracking_gpu_cc(long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); - +gps_l1_ca_dll_pll_make_tracking_gpu_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc: public gr::block +class Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc : public gr::block { public: ~Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc(); - void set_channel(unsigned int channel); - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); void start_tracking(); - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); private: friend gps_l1_ca_dll_pll_tracking_gpu_cc_sptr - gps_l1_ca_dll_pll_make_tracking_gpu_cc(long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + gps_l1_ca_dll_pll_make_tracking_gpu_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); - Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc(long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips); + Gps_L1_Ca_Dll_Pll_Tracking_GPU_cc( + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips); void update_local_code(); void update_local_carrier(); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; - Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; + Gnss_Synchro *d_acquisition_gnss_synchro; + uint32_t d_channel; - long d_if_freq; - long d_fs_in; + int64_t d_if_freq; + int64_t d_fs_in; double d_early_late_spc_chips; - int d_n_correlator_taps; - + int32_t d_n_correlator_taps; //GPU HOST PINNED MEMORY IN/OUT VECTORS - gr_complex* in_gpu; - float* d_local_code_shift_chips; - gr_complex* d_correlator_outs; + gr_complex *in_gpu; + float *d_local_code_shift_chips; + gr_complex *d_correlator_outs; cuda_multicorrelator *multicorrelator_gpu; - gr_complex* d_ca_code; + gr_complex *d_ca_code; gr_complex *d_Early; gr_complex *d_Prompt; @@ -150,19 +149,19 @@ private: double d_pll_to_dll_assist_secs_Ti; //Integration period in samples - int d_correlation_length_samples; + int32_t d_correlation_length_samples; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; - gr_complex* d_Prompt_buffer; + int32_t d_cn0_estimation_counter; + gr_complex *d_Prompt_buffer; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -176,4 +175,4 @@ private: std::string sys; }; -#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_CC_H +#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_GPU_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.cc new file mode 100644 index 000000000..20c800430 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.cc @@ -0,0 +1,958 @@ +/*! + * \file gps_l1_ca_kf_tracking_cc.cc + * \brief Implementation of a processing block of a DLL + Kalman carrier + * tracking loop for GPS L1 C/A signals + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Jordi Vila-Valls 2018. jvila(at)cttc.es + * \author Carles Fernandez-Prades 2018. cfernandez(at)cttc.es + * + * Reference: + * J. Vila-Valls, P. Closas, M. Navarro and C. Fernandez-Prades, + * "Are PLLs Dead? A Tutorial on Kalman Filter-based Techniques for Digital + * Carrier Synchronization", IEEE Aerospace and Electronic Systems Magazine, + * Vol. 32, No. 7, pp. 28–45, July 2017. DOI: 10.1109/MAES.2017.150260 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l1_ca_kf_tracking_cc.h" +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + +gps_l1_ca_kf_tracking_cc_sptr +gps_l1_ca_kf_make_tracking_cc( + uint32_t order, + int64_t if_freq, + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float dll_bw_hz, + float early_late_space_chips, + bool bce_run, + uint32_t bce_ptrans, + uint32_t bce_strans, + int32_t bce_nu, + int32_t bce_kappa) +{ + return gps_l1_ca_kf_tracking_cc_sptr(new Gps_L1_Ca_Kf_Tracking_cc(order, if_freq, + fs_in, vector_length, dump, std::move(dump_filename), dll_bw_hz, early_late_space_chips, + bce_run, bce_ptrans, bce_strans, bce_nu, bce_kappa)); +} + + +void Gps_L1_Ca_Kf_Tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) +{ + if (noutput_items != 0) + { + ninput_items_required[0] = static_cast(d_vector_length) * 2; // set the required available samples in each call + } +} + + +Gps_L1_Ca_Kf_Tracking_cc::Gps_L1_Ca_Kf_Tracking_cc( + uint32_t order, + int64_t if_freq, + int64_t fs_in, + uint32_t vector_length, + bool dump, + std::string dump_filename, + float dll_bw_hz, + float early_late_space_chips, + bool bce_run, + uint32_t bce_ptrans, + uint32_t bce_strans, + int32_t bce_nu, + int32_t bce_kappa) : gr::block("Gps_L1_Ca_Kf_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_in(pmt::mp("preamble_timestamp_s")); + this->message_port_register_out(pmt::mp("events")); + + // initialize internal vars + d_order = order; + d_dump = dump; + d_if_freq = if_freq; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = std::move(dump_filename); + + d_current_prn_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_code_loop_filter.set_DLL_BW(dll_bw_hz); + + // --- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + multicorrelator_cpu.init(2 * d_current_prn_length_samples, d_n_correlator_taps); + + // --- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carr_phase_rad = 0.0; + // define residual carrier phase covariance + d_carr_phase_sigma2 = 0.0; + + // sample synchronization + d_sample_counter = 0; + d_acq_sample_stamp = 0; + + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["G"] = std::string("GPS"); + systemName["S"] = std::string("SBAS"); + + d_acquisition_gnss_synchro = nullptr; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_carrier_dopplerrate_hz2 = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_code_phase_samples = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_code_phase_rate_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + code_error_chips = 0.0; + code_error_filt_chips = 0.0; + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + // Kalman filter initialization (receiver initialization) + + double CN_dB_Hz = 30; + double CN_lin = pow(10, CN_dB_Hz / 10.0); + + double sigma2_phase_detector_cycles2; + sigma2_phase_detector_cycles2 = (1.0 / (2.0 * CN_lin * GPS_L1_CA_CODE_PERIOD)) * (1.0 + 1.0 / (2.0 * CN_lin * GPS_L1_CA_CODE_PERIOD)); + + // covariances (static) + double sigma2_carrier_phase = GPS_TWO_PI / 4; + double sigma2_doppler = 450; + double sigma2_doppler_rate = pow(4.0 * GPS_TWO_PI, 2) / 12.0; + + kf_P_x_ini = arma::zeros(2, 2); + kf_P_x_ini(0, 0) = sigma2_carrier_phase; + kf_P_x_ini(1, 1) = sigma2_doppler; + + kf_R = arma::zeros(1, 1); + kf_R(0, 0) = sigma2_phase_detector_cycles2; + + kf_Q = arma::zeros(2, 2); + kf_Q(0, 0) = pow(GPS_L1_CA_CODE_PERIOD, 4); + kf_Q(1, 1) = GPS_L1_CA_CODE_PERIOD; + + kf_F = arma::zeros(2, 2); + kf_F(0, 0) = 1.0; + kf_F(0, 1) = GPS_TWO_PI * GPS_L1_CA_CODE_PERIOD; + kf_F(1, 0) = 0.0; + kf_F(1, 1) = 1.0; + + kf_H = arma::zeros(1, 2); + kf_H(0, 0) = 1.0; + + kf_x = arma::zeros(2, 1); + kf_y = arma::zeros(1, 1); + kf_P_y = arma::zeros(1, 1); + + // order three + if (d_order == 3) + { + kf_P_x_ini = arma::resize(kf_P_x_ini, 3, 3); + kf_P_x_ini(2, 2) = sigma2_doppler_rate; + + kf_Q = arma::zeros(3, 3); + kf_Q(0, 0) = pow(GPS_L1_CA_CODE_PERIOD, 4); + kf_Q(1, 1) = GPS_L1_CA_CODE_PERIOD; + kf_Q(2, 2) = GPS_L1_CA_CODE_PERIOD; + + kf_F = arma::resize(kf_F, 3, 3); + kf_F(0, 2) = 0.5 * GPS_TWO_PI * pow(GPS_L1_CA_CODE_PERIOD, 2); + kf_F(1, 2) = GPS_L1_CA_CODE_PERIOD; + kf_F(2, 0) = 0.0; + kf_F(2, 1) = 0.0; + kf_F(2, 2) = 1.0; + + kf_H = arma::resize(kf_H, 1, 3); + kf_H(0, 2) = 0.0; + + kf_x = arma::resize(kf_x, 3, 1); + kf_x(2, 0) = 0.0; + } + + // Bayesian covariance estimator initialization + kf_iter = 0; + bayes_run = bce_run; + bayes_ptrans = bce_ptrans; + bayes_strans = bce_strans; + + bayes_kappa = bce_kappa; + bayes_nu = bce_nu; + kf_R_est = kf_R; + + bayes_estimator.init(arma::zeros(1, 1), bayes_kappa, bayes_nu, (kf_H * kf_P_x_ini * kf_H.t() + kf_R) * (bayes_nu + 2)); +} + +void Gps_L1_Ca_Kf_Tracking_cc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + d_acq_carrier_doppler_step_hz = static_cast(d_acquisition_gnss_synchro->Acq_doppler_step); + + // Correct Kalman filter covariance according to acq doppler step size (3 sigma) + if (d_acquisition_gnss_synchro->Acq_doppler_step > 0) + { + kf_P_x_ini(1, 1) = pow(d_acq_carrier_doppler_step_hz / 3.0, 2); + bayes_estimator.init(arma::zeros(1, 1), bayes_kappa, bayes_nu, (kf_H * kf_P_x_ini * kf_H.t() + kf_R) * (bayes_nu + 2)); + } + + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect Fd = (C / (C + Vr)) * F + double radial_velocity = (GPS_L1_FREQ_HZ + d_acq_carrier_doppler_hz) / GPS_L1_FREQ_HZ; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GPS_L1_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + + d_current_prn_length_samples = round(T_prn_mod_samples); + + double T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + + d_acq_code_phase_samples = corrected_acq_phase_samples; + + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_dopplerrate_hz2 = 0; + d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + + // DLL filter initialization + d_code_loop_filter.initialize(); // initialize the code filter + + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + gps_l1_ca_code_gen_float(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); + + multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_carr_phase_sigma2 = 0.0; + + d_code_phase_samples = d_acq_code_phase_samples; + + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + + // DEBUG OUTPUT + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + + // enable tracking + d_pull_in = true; + d_enable_tracking = true; + + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +Gps_L1_Ca_Kf_Tracking_cc::~Gps_L1_Ca_Kf_Tracking_cc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + if (d_dump) + { + if (d_channel == 0) + { + std::cout << "Writing .mat files ..."; + } + Gps_L1_Ca_Kf_Tracking_cc::save_matfile(); + if (d_channel == 0) + { + std::cout << " done." << std::endl; + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int32_t Gps_L1_Ca_Kf_Tracking_cc::save_matfile() +{ + // READ DUMP FILE + std::ifstream::pos_type size; + int32_t number_of_double_vars = 1; + int32_t number_of_float_vars = 19; + int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(uint32_t); + std::ifstream dump_file; + dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + dump_file.open(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem opening dump file:" << e.what() << std::endl; + return 1; + } + // count number of epochs and rewind + int64_t num_epoch = 0; + if (dump_file.is_open()) + { + size = dump_file.tellg(); + num_epoch = static_cast(size) / static_cast(epoch_size_bytes); + dump_file.seekg(0, std::ios::beg); + } + else + { + return 1; + } + auto *abs_VE = new float[num_epoch]; + auto *abs_E = new float[num_epoch]; + auto *abs_P = new float[num_epoch]; + auto *abs_L = new float[num_epoch]; + auto *abs_VL = new float[num_epoch]; + auto *Prompt_I = new float[num_epoch]; + auto *Prompt_Q = new float[num_epoch]; + auto *PRN_start_sample_count = new uint64_t[num_epoch]; + auto *acc_carrier_phase_rad = new float[num_epoch]; + auto *carrier_doppler_hz = new float[num_epoch]; + auto *carrier_dopplerrate_hz2 = new float[num_epoch]; + auto *code_freq_chips = new float[num_epoch]; + auto *carr_error_hz = new float[num_epoch]; + auto *carr_noise_sigma2 = new float[num_epoch]; + auto *carr_error_filt_hz = new float[num_epoch]; + auto *code_error_chips = new float[num_epoch]; + auto *code_error_filt_chips = new float[num_epoch]; + auto *CN0_SNV_dB_Hz = new float[num_epoch]; + auto *carrier_lock_test = new float[num_epoch]; + auto *aux1 = new float[num_epoch]; + auto *aux2 = new double[num_epoch]; + auto *PRN = new uint32_t[num_epoch]; + + try + { + if (dump_file.is_open()) + { + for (int64_t i = 0; i < num_epoch; i++) + { + dump_file.read(reinterpret_cast(&abs_VE[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_E[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_P[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_L[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&abs_VL[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_I[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&Prompt_Q[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); + dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_dopplerrate_hz2[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_noise_sigma2[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_error_filt_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_lock_test[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux1[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&aux2[i]), sizeof(double)); + dump_file.read(reinterpret_cast(&PRN[i]), sizeof(uint32_t)); + } + } + dump_file.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Problem reading dump file:" << e.what() << std::endl; + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] carrier_dopplerrate_hz2; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_noise_sigma2; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 1; + } + + // WRITE MAT FILE + mat_t *matfp; + matvar_t *matvar; + std::string filename = d_dump_filename; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != nullptr) + { + size_t dims[2] = {1, static_cast(num_epoch)}; + matvar = Mat_VarCreate("abs_VE", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VE, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_E", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_E, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_P", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_P, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_L", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_L, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("abs_VL", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, abs_VL, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_I", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_I, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("Prompt_Q", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, Prompt_Q, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN_start_sample_count", MAT_C_UINT64, MAT_T_UINT64, 2, dims, PRN_start_sample_count, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("acc_carrier_phase_rad", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, acc_carrier_phase_rad, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_doppler_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_dopplerrate_hz2", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_dopplerrate_hz2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_freq_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_noise_sigma2", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_noise_sigma2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carr_error_filt_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_filt_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("code_error_filt_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_error_filt_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("CN0_SNV_dB_Hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, CN0_SNV_dB_Hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("carrier_lock_test", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_lock_test, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux1", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, aux1, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("aux2", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, aux2, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 2, dims, PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + delete[] abs_VE; + delete[] abs_E; + delete[] abs_P; + delete[] abs_L; + delete[] abs_VL; + delete[] Prompt_I; + delete[] Prompt_Q; + delete[] PRN_start_sample_count; + delete[] acc_carrier_phase_rad; + delete[] carrier_doppler_hz; + delete[] carrier_dopplerrate_hz2; + delete[] code_freq_chips; + delete[] carr_error_hz; + delete[] carr_noise_sigma2; + delete[] carr_error_filt_hz; + delete[] code_error_chips; + delete[] code_error_filt_chips; + delete[] CN0_SNV_dB_Hz; + delete[] carrier_lock_test; + delete[] aux1; + delete[] aux2; + delete[] PRN; + return 0; +} + + +void Gps_L1_Ca_Kf_Tracking_cc::set_channel(uint32_t channel) +{ + gr::thread::scoped_lock l(d_setlock); + d_channel = channel; + LOG(INFO) << "Tracking Channel set to " << d_channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump) + { + if (!d_dump_file.is_open()) + { + try + { + d_dump_filename.append(std::to_string(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void Gps_L1_Ca_Kf_Tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +int Gps_L1_Ca_Kf_Tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // process vars + d_carr_phase_error_rad = 0.0; + double code_error_chips = 0.0; + double code_error_filt_chips = 0.0; + + // Block input data and block output stream pointers + const auto *in = reinterpret_cast(input_items[0]); + auto **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + // Signal alignment (skip samples until the incoming signal is aligned with local replica) + uint64_t acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + double acq_trk_shif_correction_samples = static_cast(d_current_prn_length_samples) - std::fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); + int32_t samples_offset = std::round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + if (samples_offset < 0) + { + samples_offset = 0; + } + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * d_acq_code_phase_samples; + + d_sample_counter += samples_offset; // count for the processed samples + d_pull_in = false; + + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.fs = d_fs_in; + current_synchro_data.correlation_length_ms = 1; + *out[0] = current_synchro_data; + // Kalman filter initialization reset + kf_P_x = kf_P_x_ini; + // Update Kalman states based on acquisition information + kf_x(0) = d_carrier_phase_step_rad * samples_offset; + kf_x(1) = d_carrier_doppler_hz; + if (kf_x.n_elem > 2) + { + kf_x(2) = d_carrier_dopplerrate_hz2; + } + + // Covariance estimation initialization reset + kf_iter = 0; + bayes_estimator.init(arma::zeros(1, 1), bayes_kappa, bayes_nu, (kf_H * kf_P_x_ini * kf_H.t() + kf_R) * (bayes_nu + 2)); + + consume_each(samples_offset); // shift input to perform alignment with local replica + return 1; + } + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // Perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, + d_carrier_phase_step_rad, + d_rem_code_phase_chips, + d_code_phase_step_chips, + d_code_phase_rate_step_chips, + d_current_prn_length_samples); + + // ################## Kalman Carrier Tracking ###################################### + + // Kalman state prediction (time update) + kf_x_pre = kf_F * kf_x; //state prediction + kf_P_x_pre = kf_F * kf_P_x * kf_F.t() + kf_Q; //state error covariance prediction + + // Update discriminator [rads/Ti] + d_carr_phase_error_rad = pll_cloop_two_quadrant_atan(d_correlator_outs[1]); // prompt output + + // Kalman estimation (measurement update) + double sigma2_phase_detector_cycles2; + double CN_lin = pow(10, d_CN0_SNV_dB_Hz / 10.0); + sigma2_phase_detector_cycles2 = (1.0 / (2.0 * CN_lin * GPS_L1_CA_CODE_PERIOD)) * (1.0 + 1.0 / (2.0 * CN_lin * GPS_L1_CA_CODE_PERIOD)); + + kf_y(0) = d_carr_phase_error_rad; // measurement vector + kf_R(0, 0) = sigma2_phase_detector_cycles2; + + if (bayes_run && (kf_iter >= bayes_ptrans)) + { + bayes_estimator.update_sequential(kf_y); + } + if (bayes_run && (kf_iter >= (bayes_ptrans + bayes_strans))) + { + // TODO: Resolve segmentation fault + kf_P_y = bayes_estimator.get_Psi_est(); + kf_R_est = kf_P_y - kf_H * kf_P_x_pre * kf_H.t(); + } + else + { + kf_P_y = kf_H * kf_P_x_pre * kf_H.t() + kf_R; // innovation covariance matrix + kf_R_est = kf_R; + } + + // Kalman filter update step + kf_K = (kf_P_x_pre * kf_H.t()) * arma::inv(kf_P_y); // Kalman gain + kf_x = kf_x_pre + kf_K * kf_y; // updated state estimation + kf_P_x = (arma::eye(size(kf_P_x_pre)) - kf_K * kf_H) * kf_P_x_pre; // update state estimation error covariance matrix + + // Store Kalman filter results + d_rem_carr_phase_rad = kf_x(0); // set a new carrier Phase estimation to the NCO + d_carrier_doppler_hz = kf_x(1); // set a new carrier Doppler estimation to the NCO + if (kf_x.n_elem > 2) + { + d_carrier_dopplerrate_hz2 = kf_x(2); + } + else + { + d_carrier_dopplerrate_hz2 = 0; + } + d_carr_phase_sigma2 = kf_R_est(0, 0); + + // ################## DLL ########################################################## + // New code Doppler frequency estimation based on carrier frequency estimation + d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ + ((d_carrier_doppler_hz * GPS_L1_CA_CODE_RATE_HZ) / GPS_L1_FREQ_HZ); + // DLL discriminator + code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] early and late + // Code discriminator filter + code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); // [chips/second] + double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + double T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; + double code_error_filt_secs = (T_prn_seconds * code_error_filt_chips * T_chip_seconds); // [seconds] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); + d_current_prn_length_samples = static_cast(round(K_blk_samples)); // round to a discrete number of samples + + //################### NCO COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / static_cast(d_fs_in); + // carrier phase accumulator + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - static_cast(d_current_prn_length_samples); // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < FLAGS_cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + //if (d_channel == 1) + //std::cout << "Carrier Lock Test Fail in channel " << d_channel << ": " << d_carrier_lock_test << " < " << d_carrier_lock_threshold << "," << nfail++ << std::endl; + d_carrier_lock_fail_counter++; + //nfail++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; + } + } + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 1; + + kf_iter++; + } + else + { + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.System = {'G'}; + current_synchro_data.correlation_length_ms = 1; + } + + // assign the GNU Radio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + double tmp_double; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // EPR + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_dopplerrate_hz2; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // Kalman commands + tmp_float = static_cast(d_carr_phase_error_rad * GPS_TWO_PI); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = static_cast(d_carr_phase_sigma2); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = static_cast(d_rem_carr_phase_rad * GPS_TWO_PI); + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = code_error_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = code_error_filt_chips; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_double = static_cast(d_sample_counter + static_cast(d_current_prn_length_samples)); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates + d_sample_counter += d_current_prn_length_samples; // count for the processed samples + return 1; // output tracking result ALWAYS even in the case of d_enable_tracking==false +} diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.h new file mode 100644 index 000000000..a40e257b9 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_kf_tracking_cc.h @@ -0,0 +1,222 @@ +/*! + * \file gps_l1_ca_kf_tracking_cc.h + * \brief Interface of a processing block of a DLL + Kalman carrier + * tracking loop for GPS L1 C/A signals + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Jordi Vila-Valls 2018. jvila(at)cttc.es + * \author Carles Fernandez-Prades 2018. cfernandez(at)cttc.es + * + * Reference: + * J. Vila-Valls, P. Closas, M. Navarro and C. Fernandez-Prades, + * "Are PLLs Dead? A Tutorial on Kalman Filter-based Techniques for Digital + * Carrier Synchronization", IEEE Aerospace and Electronic Systems Magazine, + * Vol. 32, No. 7, pp. 28–45, July 2017. DOI: 10.1109/MAES.2017.150260 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GPS_L1_CA_KF_TRACKING_CC_H +#define GNSS_SDR_GPS_L1_CA_KF_TRACKING_CC_H + +#include "bayesian_estimation.h" +#include "cpu_multicorrelator_real_codes.h" +#include "gnss_synchro.h" +#include "tracking_2nd_DLL_filter.h" +#include "tracking_2nd_PLL_filter.h" +#include +#include +#include +#include +#include + +class Gps_L1_Ca_Kf_Tracking_cc; + +typedef boost::shared_ptr + gps_l1_ca_kf_tracking_cc_sptr; + +gps_l1_ca_kf_tracking_cc_sptr +gps_l1_ca_kf_make_tracking_cc(uint32_t order, + int64_t if_freq, + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float early_late_space_chips, + bool bce_run, + uint32_t bce_ptrans, + uint32_t bce_strans, + int32_t bce_nu, + int32_t bce_kappa); + + +/*! + * \brief This class implements a DLL + PLL tracking loop block + */ +class Gps_L1_Ca_Kf_Tracking_cc : public gr::block +{ +public: + ~Gps_L1_Ca_Kf_Tracking_cc(); + + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void start_tracking(); + + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + void forecast(int noutput_items, gr_vector_int& ninput_items_required); + +private: + friend gps_l1_ca_kf_tracking_cc_sptr + gps_l1_ca_kf_make_tracking_cc(uint32_t order, + int64_t if_freq, + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float dll_bw_hz, + float early_late_space_chips, + bool bce_run, + uint32_t bce_ptrans, + uint32_t bce_strans, + int32_t bce_nu, + int32_t bce_kappa); + + Gps_L1_Ca_Kf_Tracking_cc(uint32_t order, + int64_t if_freq, + int64_t fs_in, uint32_t vector_length, + bool dump, + std::string dump_filename, + float dll_bw_hz, + float early_late_space_chips, + bool bce_run, + uint32_t bce_ptrans, + uint32_t bce_strans, + int32_t bce_nu, + int32_t bce_kappa); + + // tracking configuration vars + uint32_t d_order; + uint32_t d_vector_length; + bool d_dump; + + Gnss_Synchro* d_acquisition_gnss_synchro; + uint32_t d_channel; + + int64_t d_if_freq; + int64_t d_fs_in; + + double d_early_late_spc_chips; + + // remaining code phase and carrier phase between tracking loops + double d_rem_code_phase_samples; + double d_rem_code_phase_chips; + double d_rem_carr_phase_rad; + + // Kalman filter variables + arma::mat kf_P_x_ini; // initial state error covariance matrix + arma::mat kf_P_x; // state error covariance matrix + arma::mat kf_P_x_pre; // Predicted state error covariance matrix + arma::mat kf_P_y; // innovation covariance matrix + + arma::mat kf_F; // state transition matrix + arma::mat kf_H; // system matrix + arma::mat kf_R; // measurement error covariance matrix + arma::mat kf_Q; // system error covariance matrix + + arma::colvec kf_x; // state vector + arma::colvec kf_x_pre; // predicted state vector + arma::colvec kf_y; // measurement vector + arma::mat kf_K; // Kalman gain matrix + + // Bayesian estimator + Bayesian_estimator bayes_estimator; + arma::mat kf_R_est; // measurement error covariance + uint32_t bayes_ptrans; + uint32_t bayes_strans; + int32_t bayes_nu; + int32_t bayes_kappa; + + bool bayes_run; + uint32_t kf_iter; + + // PLL and DLL filter library + Tracking_2nd_DLL_filter d_code_loop_filter; + // Tracking_2nd_PLL_filter d_carrier_loop_filter; + + // acquisition + double d_acq_carrier_doppler_step_hz; + double d_acq_code_phase_samples; + double d_acq_carrier_doppler_hz; + // correlator + int32_t d_n_correlator_taps; + float* d_ca_code; + float* d_local_code_shift_chips; + gr_complex* d_correlator_outs; + cpu_multicorrelator_real_codes multicorrelator_cpu; + + // tracking vars + double d_code_freq_chips; + double d_code_phase_step_chips; + double d_code_phase_rate_step_chips; + double d_carrier_doppler_hz; + double d_carrier_dopplerrate_hz2; + double d_carrier_phase_step_rad; + double d_acc_carrier_phase_rad; + double d_carr_phase_error_rad; + double d_carr_phase_sigma2; + double d_code_phase_samples; + double code_error_chips; + double code_error_filt_chips; + + // PRN period in samples + int32_t d_current_prn_length_samples; + + // processing samples counters + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; + + // CN0 estimation and lock detector + int32_t d_cn0_estimation_counter; + gr_complex* d_Prompt_buffer; + double d_carrier_lock_test; + double d_CN0_SNV_dB_Hz; + double d_carrier_lock_threshold; + int32_t d_carrier_lock_fail_counter; + + // control vars + bool d_enable_tracking; + bool d_pull_in; + + // file dump + std::string d_dump_filename; + std::ofstream d_dump_file; + + std::map systemName; + std::string sys; + + int32_t save_matfile(); +}; + +#endif // GNSS_SDR_GPS_L1_CA_KF_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.cc index ce01dffc4..832e94207 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.cc @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,88 +30,75 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_l1_ca_tcp_connector_tracking_cc.h" +#include "GPS_L1_CA.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tcp_communication.h" +#include "tcp_packet_data.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include "gps_sdr_signal_processing.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L1_CA.h" -#include "control_message_factory.h" -#include "tcp_communication.h" -#include "tcp_packet_data.h" +#include -/*! - * \todo Include in definition header file - */ -#define CN0_ESTIMATION_SAMPLES 20 -#define MINIMUM_VALID_CN0 25 -#define MAXIMUM_LOCK_FAIL_COUNTER 50 -#define CARRIER_LOCK_THRESHOLD 0.85 using google::LogMessage; gps_l1_ca_tcp_connector_tracking_cc_sptr gps_l1_ca_tcp_connector_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float early_late_space_chips, - size_t port_ch0) + int64_t fs_in, + uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float early_late_space_chips, + size_t port_ch0) { - return gps_l1_ca_tcp_connector_tracking_cc_sptr(new Gps_L1_Ca_Tcp_Connector_Tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, early_late_space_chips, port_ch0)); + return gps_l1_ca_tcp_connector_tracking_cc_sptr(new Gps_L1_Ca_Tcp_Connector_Tracking_cc( + fs_in, vector_length, dump, dump_filename, early_late_space_chips, port_ch0)); } - -void Gps_L1_Ca_Tcp_Connector_Tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) +void Gps_L1_Ca_Tcp_Connector_Tracking_cc::forecast(int noutput_items, + gr_vector_int &ninput_items_required) { if (noutput_items != 0) { - ninput_items_required[0] = (int)d_vector_length*2; //set the required available samples in each call + ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call } } - Gps_L1_Ca_Tcp_Connector_Tracking_cc::Gps_L1_Ca_Tcp_Connector_Tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float early_late_space_chips, - size_t port_ch0) : - gr::block("Gps_L1_Ca_Tcp_Connector_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) + int64_t fs_in, + uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float early_late_space_chips, + size_t port_ch0) : gr::block("Gps_L1_Ca_Tcp_Connector_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) { - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); this->message_port_register_out(pmt::mp("events")); // initialize internal vars d_dump = dump; - d_if_freq = if_freq; d_fs_in = fs_in; d_vector_length = vector_length; - d_dump_filename = dump_filename; + d_dump_filename = std::move(dump_filename); //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) //--- TCP CONNECTOR variables -------------------------------------------------------- d_port_ch0 = port_ch0; @@ -121,27 +108,27 @@ Gps_L1_Ca_Tcp_Connector_Tracking_cc::Gps_L1_Ca_Tcp_Connector_Tracking_cc( // Initialization of local code replica // Get space for a vector with the C/A code replica sampled 1x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc((GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_ca_code = static_cast(volk_gnsssdr_malloc((GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // correlator outputs (scalar) - d_n_correlator_taps = 3; // Very-Early, Early, Prompt, Late, Very-Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } + d_n_correlator_taps = 3; // Very-Early, Early, Prompt, Late, Very-Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int32_t n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } // map memory pointers of correlator outputs d_Early = &d_correlator_outs[0]; d_Prompt = &d_correlator_outs[1]; d_Late = &d_correlator_outs[2]; - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; - d_correlation_length_samples=d_vector_length; + d_correlation_length_samples = d_vector_length; multicorrelator_cpu.init(2 * d_correlation_length_samples, d_n_correlator_taps); @@ -154,22 +141,22 @@ Gps_L1_Ca_Tcp_Connector_Tracking_cc::Gps_L1_Ca_Tcp_Connector_Tracking_cc( d_rem_carr_phase_rad = 0.0; // sample synchronization - d_sample_counter = 0; + d_sample_counter = 0ULL; d_sample_counter_seconds = 0; - d_acq_sample_stamp = 0; + d_acq_sample_stamp = 0ULL; d_enable_tracking = false; d_pull_in = false; - d_current_prn_length_samples = (int)d_vector_length; + d_current_prn_length_samples = static_cast(d_vector_length); // CN0 estimation and lock detector buffers d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES]; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; d_carrier_lock_test = 1; d_CN0_SNV_dB_Hz = 0; d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; systemName["G"] = std::string("GPS"); systemName["R"] = std::string("GLONASS"); @@ -177,7 +164,7 @@ Gps_L1_Ca_Tcp_Connector_Tracking_cc::Gps_L1_Ca_Tcp_Connector_Tracking_cc( systemName["E"] = std::string("Galileo"); systemName["C"] = std::string("Compass"); - d_acquisition_gnss_synchro = 0; + d_acquisition_gnss_synchro = nullptr; d_channel = 0; d_next_rem_code_phase_samples = 0; d_acq_code_phase_samples = 0.0; @@ -189,6 +176,7 @@ Gps_L1_Ca_Tcp_Connector_Tracking_cc::Gps_L1_Ca_Tcp_Connector_Tracking_cc( d_code_phase_step_chips = 0.0; } + void Gps_L1_Ca_Tcp_Connector_Tracking_cc::start_tracking() { /* @@ -197,46 +185,37 @@ void Gps_L1_Ca_Tcp_Connector_Tracking_cc::start_tracking() d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - long int acq_trk_diff_samples; + int64_t acq_trk_diff_samples; float acq_trk_diff_seconds; - // jarribas: this patch correct a situation where the tracking sample counter - // is equal to 0 (remains in the initial state) at the first acquisition to tracking transition - // of the receiver operation when is connecting to simulink server. - // if (d_sample_counter(d_sample_counter) - static_cast(d_acq_sample_stamp); std::cout << "acq_trk_diff_samples=" << acq_trk_diff_samples << std::endl; - acq_trk_diff_seconds = (float)acq_trk_diff_samples / (float)d_fs_in; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); //doppler effect // Fd=(C/(C+Vr))*F float radial_velocity; - radial_velocity = (GPS_L1_FREQ_HZ + d_acq_carrier_doppler_hz)/GPS_L1_FREQ_HZ; + radial_velocity = (GPS_L1_FREQ_HZ + d_acq_carrier_doppler_hz) / GPS_L1_FREQ_HZ; // new chip and prn sequence periods based on acq Doppler float T_chip_mod_seconds; float T_prn_mod_seconds; float T_prn_mod_samples; d_code_freq_hz = radial_velocity * GPS_L1_CA_CODE_RATE_HZ; d_code_phase_step_chips = static_cast(d_code_freq_hz) / static_cast(d_fs_in); - T_chip_mod_seconds = 1/d_code_freq_hz; + T_chip_mod_seconds = 1 / d_code_freq_hz; T_prn_mod_seconds = T_chip_mod_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; - T_prn_mod_samples = T_prn_mod_seconds * (float)d_fs_in; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); d_next_prn_length_samples = round(T_prn_mod_samples); float T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; - float T_prn_true_samples = T_prn_true_seconds * (float)d_fs_in; + float T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); float T_prn_diff_seconds; T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; float N_prn_diff; N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; float corrected_acq_phase_samples, delay_correction_samples; - corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * (float)d_fs_in), T_prn_true_samples); + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); if (corrected_acq_phase_samples < 0) { corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; @@ -249,10 +228,10 @@ void Gps_L1_Ca_Tcp_Connector_Tracking_cc::start_tracking() // generate local reference ALWAYS starting at chip 1 (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); - multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) + multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + for (int32_t n = 0; n < d_n_correlator_taps; n++) { - d_correlator_outs[n] = gr_complex(0,0); + d_correlator_outs[n] = gr_complex(0, 0); } d_carrier_lock_fail_counter = 0; @@ -265,289 +244,52 @@ void Gps_L1_Ca_Tcp_Connector_Tracking_cc::start_tracking() d_code_phase_samples = d_acq_code_phase_samples; std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); + sys = sys_.substr(0, 1); // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Tracking of GPS L1 C/A signal for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; // enable tracking d_pull_in = true; d_enable_tracking = true; LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; } - - Gps_L1_Ca_Tcp_Connector_Tracking_cc::~Gps_L1_Ca_Tcp_Connector_Tracking_cc() { - d_dump_file.close(); - - delete[] d_Prompt_buffer; - volk_gnsssdr_free(d_ca_code); - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - - d_tcp_com.close_tcp_connection(d_port); - multicorrelator_cpu.free(); -} - -int Gps_L1_Ca_Tcp_Connector_Tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // process vars - float carr_error; - float carr_nco; - float code_error; - float code_nco; - - tcp_packet_data tcp_data; - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data = Gnss_Synchro(); - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - - if (d_enable_tracking == true) + if (d_dump_file.is_open()) { - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - /* - * Receiver signal alignment - */ - if (d_pull_in == true) - { - int samples_offset; - - // 28/11/2011 ACQ to TRK transition BUG CORRECTION - float acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; - acq_trk_shif_correction_samples = d_next_prn_length_samples - fmod((float)acq_to_trk_delay_samples, (float)d_next_prn_length_samples); - samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); - // /todo: Check if the sample counter sent to the next block as a time reference should be incremented AFTER sended or BEFORE - - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - *out[0] = current_synchro_data; - d_sample_counter_seconds = d_sample_counter_seconds + (((double)samples_offset) / (double)d_fs_in); - d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples - d_pull_in = false; - consume_each(samples_offset); //shift input to perform alignement with local replica - return 1; - } - - - // Update the prn length based on code freq (variable) and - // sampling frequency (fixed) - // variable code PRN sample block size - d_current_prn_length_samples = d_next_prn_length_samples; - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs,in); - - double carr_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - double rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_hz / d_fs_in); - - multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, - carr_phase_step_rad, - rem_code_phase_chips, - d_code_phase_step_chips, - d_current_prn_length_samples); - - //! Variable used for control - d_control_id++; - - //! Send and receive a TCP packet - boost::array tx_variables_array = {{d_control_id, - (*d_Early).real(), - (*d_Early).imag(), - (*d_Late).real(), - (*d_Late).imag(), - (*d_Prompt).real(), - (*d_Prompt).imag(), - d_acq_carrier_doppler_hz, - 1}}; - d_tcp_com.send_receive_tcp_packet_gps_l1_ca(tx_variables_array, &tcp_data); - - //! Recover the tracking data - code_error = tcp_data.proc_pack_code_error; - carr_error = tcp_data.proc_pack_carr_error; - // Modify carrier freq based on NCO command - d_carrier_doppler_hz = tcp_data.proc_pack_carrier_doppler_hz; - // Modify code freq based on NCO command - code_nco = 1/(1/GPS_L1_CA_CODE_RATE_HZ - code_error/GPS_L1_CA_CODE_LENGTH_CHIPS); - d_code_freq_hz = code_nco; - - // Update the phasestep based on code freq (variable) and - // sampling frequency (fixed) - d_code_phase_step_chips = d_code_freq_hz / (float)d_fs_in; //[chips] - // variable code PRN sample block size - double T_chip_seconds; - double T_prn_seconds; - double T_prn_samples; - double K_blk_samples; - T_chip_seconds = 1 / (double)d_code_freq_hz; - T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; - T_prn_samples = T_prn_seconds * (double)d_fs_in; - d_rem_code_phase_samples = d_next_rem_code_phase_samples; - K_blk_samples = T_prn_samples + d_rem_code_phase_samples;//-code_error*(double)d_fs_in; - - // Update the current PRN delay (code phase in samples) - double T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; - double T_prn_true_samples = T_prn_true_seconds * (double)d_fs_in; - d_code_phase_samples = d_code_phase_samples + T_prn_samples - T_prn_true_samples; - if (d_code_phase_samples < 0) - { - d_code_phase_samples = T_prn_true_samples + d_code_phase_samples; - } - - d_code_phase_samples = fmod(d_code_phase_samples, T_prn_true_samples); - d_next_prn_length_samples = round(K_blk_samples); //round to a discrete samples - d_next_rem_code_phase_samples = K_blk_samples - d_next_prn_length_samples; //rounding error - - /*! - * \todo Improve the lock detection algorithm! - */ - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt; - d_cn0_estimation_counter++; - } - else - { - d_cn0_estimation_counter = 0; - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L1_CA_CODE_LENGTH_CHIPS); - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES); - - // ###### TRACKING UNLOCK NOTIFICATION ##### - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - } - if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine - - } - } - - // ########### Output the tracking data to navigation and PVT ########## - - current_synchro_data.Prompt_I = (double)(*d_Prompt).real(); - current_synchro_data.Prompt_Q = (double)(*d_Prompt).imag(); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample (Hybridization OK!, but some glitches??) - current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_rem_code_phase_samples)/(double)d_fs_in; - //compute remnant code phase samples AFTER the Tracking timestamp - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample - - // This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0 - current_synchro_data.Tracking_timestamp_secs = d_sample_counter_seconds; - current_synchro_data.Carrier_phase_rads = (double)d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = (double)d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = (double)d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms=1; - } - else - { - - *d_Early = gr_complex(0,0); - *d_Prompt = gr_complex(0,0); - *d_Late = gr_complex(0,0); - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_rem_code_phase_samples)/(double)d_fs_in; - //! When tracking is disabled an array of 1's is sent to maintain the TCP connection - boost::array tx_variables_array = {{1,1,1,1,1,1,1,1,0}}; - d_tcp_com.send_receive_tcp_packet_gps_l1_ca(tx_variables_array, &tcp_data); - } - - //assign the GNURadio block output data - current_synchro_data.System = {'G'}; - std::string str_aux = "1C"; - const char * str = str_aux.c_str(); // get a C style null terminated string - std::memcpy((void*)current_synchro_data.Signal, str, 3); - - *out[0] = current_synchro_data; - - if(d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - float prompt_I; - float prompt_Q; - float tmp_E, tmp_P, tmp_L; - float tmp_float; - prompt_I = (*d_Prompt).real(); - prompt_Q = (*d_Prompt).imag(); - tmp_E = std::abs(*d_Early); - tmp_P = std::abs(*d_Prompt); - tmp_L = std::abs(*d_Late); try - { - // EPR - d_dump_file.write((char*)&tmp_E, sizeof(float)); - d_dump_file.write((char*)&tmp_P, sizeof(float)); - d_dump_file.write((char*)&tmp_L, sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write((char*)&prompt_I, sizeof(float)); - d_dump_file.write((char*)&prompt_Q, sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); - - // carrier and code frequency - d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); - d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); - - //PLL commands - d_dump_file.write((char*)&carr_error, sizeof(float)); - d_dump_file.write((char*)&carr_nco, sizeof(float)); - - //DLL commands - d_dump_file.write((char*)&code_error, sizeof(float)); - d_dump_file.write((char*)&code_nco, sizeof(float)); - - // CN0 and carrier lock test - d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); - d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); - - // AUX vars (for debug purposes) - tmp_float = 0; - d_dump_file.write((char*)&tmp_float, sizeof(float)); - d_dump_file.write((char*)&d_sample_counter_seconds, sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what(); - } + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + d_tcp_com.close_tcp_connection(d_port); + delete[] d_Prompt_buffer; + multicorrelator_cpu.free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); } - - consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates - d_sample_counter_seconds = d_sample_counter_seconds + ( ((double)d_current_prn_length_samples) / (double)d_fs_in ); - d_sample_counter += d_current_prn_length_samples; //count for the processed samples - - return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false } - -void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) +void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_channel(uint32_t channel) { d_channel = channel; LOG(INFO) << "Tracking Channel set to " << d_channel; @@ -557,17 +299,17 @@ void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) if (d_dump_file.is_open() == false) { try - { + { d_dump_filename.append(boost::lexical_cast(d_channel)); d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } + } catch (const std::ifstream::failure &e) - { + { LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } + } } } @@ -580,8 +322,267 @@ void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_channel(unsigned int channel) } -void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +void Gps_L1_Ca_Tcp_Connector_Tracking_cc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) { d_acquisition_gnss_synchro = p_gnss_synchro; - +} + + +int Gps_L1_Ca_Tcp_Connector_Tracking_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + // process vars + float carr_error = 0.0; + float code_error = 0.0; + float code_nco = 0.0; + + tcp_packet_data tcp_data; + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + // Block input data and block output stream pointers + const gr_complex *in = reinterpret_cast(input_items[0]); + Gnss_Synchro **out = reinterpret_cast(&output_items[0]); + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + /* + * Receiver signal alignment + */ + if (d_pull_in == true) + { + int32_t samples_offset; + + // 28/11/2011 ACQ to TRK transition BUG CORRECTION + float acq_trk_shif_correction_samples; + int32_t acq_to_trk_delay_samples; + acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp; + acq_trk_shif_correction_samples = d_next_prn_length_samples - fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_next_prn_length_samples)); + samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples); + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(samples_offset); + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + d_sample_counter_seconds = d_sample_counter_seconds + (static_cast(samples_offset) / static_cast(d_fs_in)); + d_sample_counter = d_sample_counter + static_cast(samples_offset); //count for the processed samples + d_pull_in = false; + consume_each(samples_offset); //shift input to perform alignment with local replica + return 1; + } + + // Update the prn length based on code freq (variable) and + // sampling frequency (fixed) + // variable code PRN sample block size + d_current_prn_length_samples = d_next_prn_length_samples; + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); + + double carr_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + double rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_hz / d_fs_in); + + multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, + carr_phase_step_rad, + rem_code_phase_chips, + d_code_phase_step_chips, + d_current_prn_length_samples); + + //! Variable used for control + d_control_id++; + + //! Send and receive a TCP packet + boost::array tx_variables_array = {{d_control_id, + (*d_Early).real(), + (*d_Early).imag(), + (*d_Late).real(), + (*d_Late).imag(), + (*d_Prompt).real(), + (*d_Prompt).imag(), + d_acq_carrier_doppler_hz, + 1}}; + d_tcp_com.send_receive_tcp_packet_gps_l1_ca(tx_variables_array, &tcp_data); + + //! Recover the tracking data + code_error = tcp_data.proc_pack_code_error; + carr_error = tcp_data.proc_pack_carr_error; + // Modify carrier freq based on NCO command + d_carrier_doppler_hz = tcp_data.proc_pack_carrier_doppler_hz; + // Modify code freq based on NCO command + code_nco = 1 / (1 / GPS_L1_CA_CODE_RATE_HZ - code_error / GPS_L1_CA_CODE_LENGTH_CHIPS); + d_code_freq_hz = code_nco; + + // Update the phasestep based on code freq (variable) and + // sampling frequency (fixed) + d_code_phase_step_chips = d_code_freq_hz / static_cast(d_fs_in); //[chips] + // variable code PRN sample block size + double T_chip_seconds; + double T_prn_seconds; + double T_prn_samples; + double K_blk_samples; + T_chip_seconds = 1.0 / static_cast(d_code_freq_hz); + T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + d_rem_code_phase_samples = d_next_rem_code_phase_samples; + K_blk_samples = T_prn_samples + d_rem_code_phase_samples; //-code_error*(double)d_fs_in; + + // Update the current PRN delay (code phase in samples) + double T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + d_code_phase_samples = d_code_phase_samples + T_prn_samples - T_prn_true_samples; + if (d_code_phase_samples < 0) + { + d_code_phase_samples = T_prn_true_samples + d_code_phase_samples; + } + + d_code_phase_samples = fmod(d_code_phase_samples, T_prn_true_samples); + d_next_prn_length_samples = round(K_blk_samples); //round to a discrete samples + d_next_rem_code_phase_samples = K_blk_samples - d_next_prn_length_samples; //rounding error + + /*! + * \todo Improve the lock detection algorithm! + */ + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < FLAGS_cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt; + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); + + // ###### TRACKING UNLOCK NOTIFICATION ##### + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); //3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + } + } + + // ########### Output the tracking data to navigation and PVT ########## + + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + //compute remnant code phase samples AFTER the Tracking timestamp + d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = static_cast(d_acc_carrier_phase_rad); + current_synchro_data.Carrier_Doppler_hz = static_cast(d_carrier_doppler_hz); + current_synchro_data.CN0_dB_hz = static_cast(d_CN0_SNV_dB_Hz); + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 1; + } + else + { + *d_Early = gr_complex(0, 0); + *d_Prompt = gr_complex(0, 0); + *d_Late = gr_complex(0, 0); + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_correlation_length_samples); + //! When tracking is disabled an array of 1's is sent to maintain the TCP connection + boost::array tx_variables_array = {{1, 1, 1, 1, 1, 1, 1, 1, 0}}; + d_tcp_com.send_receive_tcp_packet_gps_l1_ca(tx_variables_array, &tcp_data); + } + + //assign the GNURadio block output data + current_synchro_data.System = {'G'}; + std::string str_aux = "1C"; + const char *str = str_aux.c_str(); // get a C style null terminated string + std::memcpy(static_cast(current_synchro_data.Signal), str, 3); + + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + float tmp_VE = 0.0; + float tmp_VL = 0.0; + float tmp_float; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // Dump correlators output + d_dump_file.write(reinterpret_cast(&tmp_VE), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_VL), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(uint64_t)); + // accumulated carrier phase + tmp_float = d_acc_carrier_phase_rad; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier and code frequency + tmp_float = d_carrier_doppler_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_code_freq_hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // PLL commands + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = carr_error; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // DLL commands + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = code_error; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // CN0 and carrier lock test + tmp_float = d_CN0_SNV_dB_Hz; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + tmp_float = d_carrier_lock_test; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // AUX vars (for debug purposes) + tmp_float = 0.0; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + auto tmp_double = static_cast(d_sample_counter + d_correlation_length_samples); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + // PRN + uint32_t prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(uint32_t)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + + consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates + d_sample_counter_seconds = d_sample_counter_seconds + (static_cast(d_current_prn_length_samples) / static_cast(d_fs_in)); + d_sample_counter += d_current_prn_length_samples; //count for the processed samples + + if (d_enable_tracking) + { + return 1; + } + + return 0; } diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.h index 20a92da70..636a9fe28 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_tcp_connector_tracking_cc.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,14 +37,13 @@ #ifndef GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_CC_H #define GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_CC_H +#include "cpu_multicorrelator.h" +#include "gnss_synchro.h" +#include "tcp_communication.h" +#include #include #include #include -#include -#include "gnss_synchro.h" -#include "cpu_multicorrelator.h" -#include "tcp_communication.h" - class Gps_L1_Ca_Tcp_Connector_Tracking_cc; @@ -52,25 +51,24 @@ class Gps_L1_Ca_Tcp_Connector_Tracking_cc; typedef boost::shared_ptr gps_l1_ca_tcp_connector_tracking_cc_sptr; gps_l1_ca_tcp_connector_tracking_cc_sptr -gps_l1_ca_tcp_connector_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float early_late_space_chips, - size_t port_ch0); +gps_l1_ca_tcp_connector_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float early_late_space_chips, + size_t port_ch0); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class Gps_L1_Ca_Tcp_Connector_Tracking_cc: public gr::block +class Gps_L1_Ca_Tcp_Connector_Tracking_cc : public gr::block { public: ~Gps_L1_Ca_Tcp_Connector_Tracking_cc(); - void set_channel(unsigned int channel); - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); + void set_channel(uint32_t channel); + void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); void start_tracking(); /* @@ -78,44 +76,42 @@ public: * * The user must override work to define the signal processing code */ - int general_work (int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + int general_work(int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); - void forecast (int noutput_items, gr_vector_int &ninput_items_required); private: friend gps_l1_ca_tcp_connector_tracking_cc_sptr - gps_l1_ca_tcp_connector_make_tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float early_late_space_chips, - size_t port_ch0); + gps_l1_ca_tcp_connector_make_tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float early_late_space_chips, + size_t port_ch0); - Gps_L1_Ca_Tcp_Connector_Tracking_cc(long if_freq, - long fs_in, unsigned - int vector_length, - bool dump, - std::string dump_filename, - float early_late_space_chips, - size_t port_ch0); + Gps_L1_Ca_Tcp_Connector_Tracking_cc( + int64_t fs_in, uint32_t vector_length, + bool dump, + const std::string &dump_filename, + float early_late_space_chips, + size_t port_ch0); // tracking configuration vars - unsigned int d_vector_length; + uint32_t d_vector_length; bool d_dump; - Gnss_Synchro* d_acquisition_gnss_synchro; - unsigned int d_channel; + Gnss_Synchro *d_acquisition_gnss_synchro; + uint32_t d_channel; - long d_if_freq; - long d_fs_in; - int d_correlation_length_samples; - int d_n_correlator_taps; + int64_t d_fs_in; + int32_t d_correlation_length_samples; + int32_t d_n_correlator_taps; double d_early_late_spc_chips; double d_code_phase_step_chips; - gr_complex* d_ca_code; + gr_complex *d_ca_code; gr_complex *d_Early; gr_complex *d_Prompt; @@ -130,8 +126,8 @@ private: float d_acq_code_phase_samples; float d_acq_carrier_doppler_hz; // correlator - float* d_local_code_shift_chips; - gr_complex* d_correlator_outs; + float *d_local_code_shift_chips; + gr_complex *d_correlator_outs; cpu_multicorrelator multicorrelator_cpu; // tracking vars @@ -141,26 +137,26 @@ private: double d_code_phase_samples; size_t d_port_ch0; size_t d_port; - int d_listen_connection; + int32_t d_listen_connection; float d_control_id; tcp_communication d_tcp_com; //PRN period in samples - int d_current_prn_length_samples; - int d_next_prn_length_samples; + int32_t d_current_prn_length_samples; + int32_t d_next_prn_length_samples; double d_sample_counter_seconds; //processing samples counters - unsigned long int d_sample_counter; - unsigned long int d_acq_sample_stamp; + uint64_t d_sample_counter; + uint64_t d_acq_sample_stamp; // CN0 estimation and lock detector - int d_cn0_estimation_counter; - gr_complex* d_Prompt_buffer; + int32_t d_cn0_estimation_counter; + gr_complex *d_Prompt_buffer; float d_carrier_lock_test; float d_CN0_SNV_dB_Hz; float d_carrier_lock_threshold; - int d_carrier_lock_fail_counter; + int32_t d_carrier_lock_fail_counter; // control vars bool d_enable_tracking; @@ -174,4 +170,4 @@ private: std::string sys; }; -#endif //GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_CC_H +#endif //GNSS_SDR_GPS_L1_CA_TCP_CONNECTOR_TRACKING_CC_H diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.cc deleted file mode 100644 index ade0d037d..000000000 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l2_m_dll_pll_tracking_cc.cc +++ /dev/null @@ -1,527 +0,0 @@ -/*! - * \file gps_l2_m_dll_pll_tracking_cc.cc - * \brief Implementation of a code DLL + carrier PLL tracking block - * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * Javier Arribas, 2011. jarribas(at)cttc.es - * - * Code DLL + carrier PLL according to the algorithms described in: - * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkhauser, 2007 - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l2_m_dll_pll_tracking_cc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "gps_l2c_signal.h" -#include "tracking_discriminators.h" -#include "lock_detectors.h" -#include "GPS_L2C.h" -#include "control_message_factory.h" - - -/*! - * \todo Include in definition header file - */ -#define GPS_L2M_CN0_ESTIMATION_SAMPLES 10 -#define GPS_L2M_MINIMUM_VALID_CN0 25 -#define GPS_L2M_MAXIMUM_LOCK_FAIL_COUNTER 50 -#define GPS_L2M_CARRIER_LOCK_THRESHOLD 0.75 - - -using google::LogMessage; - -gps_l2_m_dll_pll_tracking_cc_sptr -gps_l2_m_dll_pll_make_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) -{ - return gps_l2_m_dll_pll_tracking_cc_sptr(new gps_l2_m_dll_pll_tracking_cc(if_freq, - fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips)); -} - - -void gps_l2_m_dll_pll_tracking_cc::forecast (int noutput_items, - gr_vector_int &ninput_items_required) -{ - if (noutput_items != 0) - { - ninput_items_required[0] = static_cast(d_vector_length) * 2; //set the required available samples in each call - } -} - - - -gps_l2_m_dll_pll_tracking_cc::gps_l2_m_dll_pll_tracking_cc( - long if_freq, - long fs_in, - unsigned int vector_length, - bool dump, - std::string dump_filename, - float pll_bw_hz, - float dll_bw_hz, - float early_late_space_chips) : - gr::block("gps_l2_m_dll_pll_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Telemetry bit synchronization message port input - this->message_port_register_in(pmt::mp("preamble_timestamp_s")); - this->message_port_register_out(pmt::mp("events")); - // initialize internal vars - d_dump = dump; - d_if_freq = if_freq; - d_fs_in = fs_in; - d_vector_length = vector_length; - d_dump_filename = dump_filename; - - // DLL/PLL filter initialization - d_carrier_loop_filter=Tracking_2nd_PLL_filter(GPS_L2_M_PERIOD); - d_code_loop_filter=Tracking_2nd_DLL_filter(GPS_L2_M_PERIOD); - - // Initialize tracking ========================================== - d_code_loop_filter.set_DLL_BW(dll_bw_hz); - d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); - - //--- DLL variables -------------------------------------------------------- - d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) - - // Initialization of local code replica - // Get space for a vector with the C/A code replica sampled 1x/chip - d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L2_M_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - // correlator outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, and Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(float), volk_gnsssdr_get_alignment())); - // Set TAPs delay values [chips] - d_local_code_shift_chips[0] = - d_early_late_spc_chips; - d_local_code_shift_chips[1] = 0.0; - d_local_code_shift_chips[2] = d_early_late_spc_chips; - - multicorrelator_cpu.init(2 * d_vector_length, d_n_correlator_taps); - - - //--- Perform initializations ------------------------------ - // define initial code frequency basis of NCO - d_code_freq_chips = GPS_L2_M_CODE_RATE_HZ; - // define residual code phase (in chips) - d_rem_code_phase_samples = 0.0; - // define residual carrier phase - d_rem_carr_phase_rad = 0.0; - - // sample synchronization - d_sample_counter = 0; - //d_sample_counter_seconds = 0; - d_acq_sample_stamp = 0; - - d_enable_tracking = false; - d_pull_in = false; - - d_current_prn_length_samples = static_cast(d_vector_length); - - // CN0 estimation and lock detector buffers - d_cn0_estimation_counter = 0; - d_Prompt_buffer = new gr_complex[GPS_L2M_CN0_ESTIMATION_SAMPLES]; - d_carrier_lock_test = 1; - d_CN0_SNV_dB_Hz = 0; - d_carrier_lock_fail_counter = 0; - d_carrier_lock_threshold = GPS_L2M_CARRIER_LOCK_THRESHOLD; - - systemName["G"] = std::string("GPS"); - - set_relative_rate(1.0/((double)d_vector_length*2)); - //set_min_output_buffer((long int)300); - - d_acquisition_gnss_synchro = 0; - d_channel = 0; - d_acq_code_phase_samples = 0.0; - d_acq_carrier_doppler_hz = 0.0; - d_carrier_doppler_hz = 0.0; - d_acc_carrier_phase_rad = 0.0; - d_code_phase_samples = 0.0; - - d_rem_code_phase_chips = 0.0; - d_code_phase_step_chips = 0.0; - d_carrier_phase_step_rad = 0.0; - - LOG(INFO) << "d_vector_length" << d_vector_length; -} - - -void gps_l2_m_dll_pll_tracking_cc::start_tracking() -{ - /* - * correct the code phase according to the delay between acq and trk - */ - d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; - d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; - d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - - long int acq_trk_diff_samples; - float acq_trk_diff_seconds; - acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp);//-d_vector_length; - LOG(INFO) << "Number of samples between Acquisition and Tracking =" << acq_trk_diff_samples; - acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); - // Doppler effect - // Fd=(C/(C+Vr))*F - double radial_velocity = (GPS_L2_FREQ_HZ + d_acq_carrier_doppler_hz) / GPS_L2_FREQ_HZ; - // new chip and prn sequence periods based on acq Doppler - double T_chip_mod_seconds; - double T_prn_mod_seconds; - double T_prn_mod_samples; - d_code_freq_chips = radial_velocity * GPS_L2_M_CODE_RATE_HZ; - d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); - T_chip_mod_seconds = 1/d_code_freq_chips; - T_prn_mod_seconds = T_chip_mod_seconds * GPS_L2_M_CODE_LENGTH_CHIPS; - T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); - - d_current_prn_length_samples = round(T_prn_mod_samples); - - double T_prn_true_seconds = GPS_L2_M_CODE_LENGTH_CHIPS / GPS_L2_M_CODE_RATE_HZ; - double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); - double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; - double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; - double corrected_acq_phase_samples, delay_correction_samples; - corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); - if (corrected_acq_phase_samples < 0) - { - corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; - } - delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; - //TODO: debug the algorithm implementation and enable correction - //d_acq_code_phase_samples = corrected_acq_phase_samples; - - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; - d_carrier_phase_step_rad = GPS_L2_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - - // DLL/PLL filter initialization - d_carrier_loop_filter.initialize(); // initialize the carrier filter - d_code_loop_filter.initialize(); // initialize the code filter - - // generate local reference ALWAYS starting at chip 1 (1 sample per chip) - gps_l2c_m_code_gen_complex(d_ca_code, d_acquisition_gnss_synchro->PRN); - - multicorrelator_cpu.set_local_code_and_taps(static_cast(GPS_L2_M_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - - d_carrier_lock_fail_counter = 0; - d_rem_code_phase_samples = 0; - d_rem_carr_phase_rad = 0; - d_rem_code_phase_chips = 0.0; - d_acc_carrier_phase_rad = 0; - - d_code_phase_samples = d_acq_code_phase_samples; - - std::string sys_ = &d_acquisition_gnss_synchro->System; - sys = sys_.substr(0,1); - - // DEBUG OUTPUT - std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) <<" whith Doppler="<PRN) << " on channel " << d_channel; - - - // enable tracking - d_pull_in = true; - d_enable_tracking = true; - - LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz - << " Code Phase correction [samples]=" << delay_correction_samples - << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; -} - -gps_l2_m_dll_pll_tracking_cc::~gps_l2_m_dll_pll_tracking_cc() -{ - d_dump_file.close(); - - volk_gnsssdr_free(d_local_code_shift_chips); - volk_gnsssdr_free(d_correlator_outs); - volk_gnsssdr_free(d_ca_code); - - delete[] d_Prompt_buffer; - multicorrelator_cpu.free(); -} - - - -int gps_l2_m_dll_pll_tracking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - // process vars - double carr_error_hz = 0; - double carr_error_filt_hz = 0; - double code_error_chips = 0; - double code_error_filt_chips = 0; - - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder - Gnss_Synchro current_synchro_data = Gnss_Synchro(); - - // Block input data and block output stream pointers - const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment - Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; - - if (d_enable_tracking == true) - { - // Fill the acquisition data - current_synchro_data = *d_acquisition_gnss_synchro; - // Receiver signal alignment - if (d_pull_in == true) - { - int samples_offset; - double acq_trk_shif_correction_samples; - int acq_to_trk_delay_samples; - acq_to_trk_delay_samples = (d_sample_counter - (d_acq_sample_stamp-d_current_prn_length_samples)); - acq_trk_shif_correction_samples = -fmod(static_cast(acq_to_trk_delay_samples), static_cast(d_current_prn_length_samples)); - samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples);//+(1.5*(d_fs_in/GPS_L2_M_CODE_RATE_HZ))); - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples - d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * samples_offset; - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - *out[0] = current_synchro_data; - d_pull_in = false; - consume_each(samples_offset); //shift input to perform alignment with local replica - return 1; - } - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_cpu.set_input_output_vectors(d_correlator_outs, in); - multicorrelator_cpu.Carrier_wipeoff_multicorrelator_resampler(d_rem_carr_phase_rad, - d_carrier_phase_step_rad, - d_rem_code_phase_chips, - d_code_phase_step_chips, - d_current_prn_length_samples); - - // ################## PLL ########################################################## - // PLL discriminator - carr_error_hz = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_L2_TWO_PI; - // Carrier discriminator filter - carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); - // New carrier Doppler frequency estimation - d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = GPS_L2_M_CODE_RATE_HZ + ((d_carrier_doppler_hz * GPS_L2_M_CODE_RATE_HZ) / GPS_L2_FREQ_HZ); - - // ################## DLL ########################################################## - // DLL discriminator - code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] - // Code discriminator filter - code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); //[chips/second] - //Code phase accumulator - double code_error_filt_secs = (GPS_L2_M_PERIOD * code_error_filt_chips) / GPS_L2_M_CODE_RATE_HZ; //[seconds] - - // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### - // keep alignment parameters for the next input buffer - // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation - double T_chip_seconds = 1.0 / d_code_freq_chips; - double T_prn_seconds = T_chip_seconds * GPS_L2_M_CODE_LENGTH_CHIPS; - double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); - double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); - d_current_prn_length_samples = round(K_blk_samples); // round to a discrete number of samples - - //################### PLL COMMANDS ################################################# - // carrier phase step (NCO phase increment per sample) [rads/sample] - d_carrier_phase_step_rad = GPS_L2_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); - // remnant carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad = d_rem_carr_phase_rad + d_carrier_phase_step_rad * d_current_prn_length_samples; - d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GPS_L2_TWO_PI); - // carrier phase accumulator - d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * d_current_prn_length_samples; - - //################### DLL COMMANDS ################################################# - // code phase step (Code resampler phase increment per sample) [chips/sample] - d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); - // remnant code phase [chips] - d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; // rounding error < 1 sample - d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); - - // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### - if (d_cn0_estimation_counter < GPS_L2M_CN0_ESTIMATION_SAMPLES) - { - // fill buffer with prompt correlator output values - d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; - d_cn0_estimation_counter++; - } - else - { - d_cn0_estimation_counter = 0; - // Code lock indicator - d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, GPS_L2M_CN0_ESTIMATION_SAMPLES, d_fs_in, GPS_L2_M_CODE_LENGTH_CHIPS); - // Carrier lock indicator - d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, GPS_L2M_CN0_ESTIMATION_SAMPLES); - // Loss of lock detection - if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < GPS_L2M_MINIMUM_VALID_CN0) - { - d_carrier_lock_fail_counter++; - } - else - { - if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; - } - if (d_carrier_lock_fail_counter > GPS_L2M_MAXIMUM_LOCK_FAIL_COUNTER) - { - std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; - LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; - this->message_port_pub(pmt::mp("events"), pmt::from_long(3));//3 -> loss of lock - d_carrier_lock_fail_counter = 0; - d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine - } - } - // ########### Output the tracking data to navigation and PVT ########## - current_synchro_data.Prompt_I = static_cast(d_correlator_outs[1].real()); - current_synchro_data.Prompt_Q = static_cast(d_correlator_outs[1].imag()); - // Tracking_timestamp_secs is aligned with the CURRENT PRN start sample - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter + d_current_prn_length_samples) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms = 20; - - } - else - { - for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - current_synchro_data.Tracking_timestamp_secs = (static_cast(d_sample_counter + d_current_prn_length_samples) + static_cast(d_rem_code_phase_samples)) / static_cast(d_fs_in); - } - //assign the GNURadio block output data - *out[0] = current_synchro_data; - - if(d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - float prompt_I; - float prompt_Q; - float tmp_E, tmp_P, tmp_L; - double tmp_double; - prompt_I = d_correlator_outs[1].real(); - prompt_Q = d_correlator_outs[1].imag(); - tmp_E = std::abs(d_correlator_outs[0]); - tmp_P = std::abs(d_correlator_outs[1]); - tmp_L = std::abs(d_correlator_outs[2]); - try - { - // EPR - d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); - d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); - // PROMPT I and Q (to analyze navigation symbols) - d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); - d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); - // PRN start sample stamp - //tmp_float=(float)d_sample_counter; - d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); - // accumulated carrier phase - d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); - - // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); - - //PLL commands - d_dump_file.write(reinterpret_cast(&carr_error_hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); - - //DLL commands - d_dump_file.write(reinterpret_cast(&code_error_chips), sizeof(double)); - d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); - - // CN0 and carrier lock test - d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); - d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); - - // AUX vars (for debug purposes) - tmp_double = d_rem_code_phase_samples; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (std::ifstream::failure& e) - { - LOG(WARNING) << "Exception writing trk dump file " << e.what(); - } - } - consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates - d_sample_counter += d_current_prn_length_samples; // count for the processed samples - return 1; // output tracking result ALWAYS even in the case of d_enable_tracking==false -} - - - -void gps_l2_m_dll_pll_tracking_cc::set_channel(unsigned int channel) -{ - d_channel = channel; - LOG(INFO) << "Tracking Channel set to " << d_channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions (std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (std::ifstream::failure& e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} - - - -void gps_l2_m_dll_pll_tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - d_acquisition_gnss_synchro = p_gnss_synchro; -} diff --git a/src/algorithms/tracking/libs/CMakeLists.txt b/src/algorithms/tracking/libs/CMakeLists.txt index 3aa2ec9ba..6991fbd55 100644 --- a/src/algorithms/tracking/libs/CMakeLists.txt +++ b/src/algorithms/tracking/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # @@ -22,57 +22,89 @@ if(ENABLE_CUDA) # set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --gpu-architecture sm_30) list(APPEND CUDA_NVCC_FLAGS "-gencode arch=compute_30,code=sm_30; -std=c++11;-O3; -use_fast_math -default-stream per-thread") set(CUDA_PROPAGATE_HOST_FLAGS OFF) - CUDA_INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}) + cuda_include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(LIB_TYPE STATIC) #set the lib type - CUDA_ADD_LIBRARY(CUDA_CORRELATOR_LIB ${LIB_TYPE} cuda_multicorrelator.h cuda_multicorrelator.cu) + cuda_add_library(CUDA_CORRELATOR_LIB ${LIB_TYPE} cuda_multicorrelator.h cuda_multicorrelator.cu) set(OPT_TRACKING_LIBRARIES ${OPT_TRACKING_LIBRARIES} CUDA_CORRELATOR_LIB) - set(OPT_TRACKING_INCLUDES ${OPT_TRACKING_INCLUDES} ${CUDA_INCLUDE_DIRS} ) -endif(ENABLE_CUDA) + set(OPT_TRACKING_INCLUDES ${OPT_TRACKING_INCLUDES} ${CUDA_INCLUDE_DIRS}) +endif() - -set(TRACKING_LIB_SOURCES - cpu_multicorrelator.cc - cpu_multicorrelator_16sc.cc - lock_detectors.cc - tcp_communication.cc - tcp_packet_data.cc - tracking_2nd_DLL_filter.cc - tracking_2nd_PLL_filter.cc - tracking_discriminators.cc - tracking_FLL_PLL_filter.cc - tracking_loop_filter.cc +set(TRACKING_LIB_SOURCES + cpu_multicorrelator.cc + cpu_multicorrelator_real_codes.cc + cpu_multicorrelator_16sc.cc + lock_detectors.cc + tcp_communication.cc + tcp_packet_data.cc + tracking_2nd_DLL_filter.cc + tracking_2nd_PLL_filter.cc + tracking_discriminators.cc + tracking_FLL_PLL_filter.cc + tracking_loop_filter.cc + dll_pll_conf.cc + bayesian_estimation.cc ) +set(TRACKING_LIB_HEADERS + cpu_multicorrelator.h + cpu_multicorrelator_real_codes.h + cpu_multicorrelator_16sc.h + lock_detectors.h + tcp_communication.h + tcp_packet_data.h + tracking_2nd_DLL_filter.h + tracking_2nd_PLL_filter.h + tracking_discriminators.h + tracking_FLL_PLL_filter.h + tracking_loop_filter.h + dll_pll_conf.h + bayesian_estimation.h +) + +if(ENABLE_FPGA) + set(TRACKING_LIB_SOURCES ${TRACKING_LIB_SOURCES} fpga_multicorrelator.cc dll_pll_conf_fpga.cc) + set(TRACKING_LIB_HEADERS ${TRACKING_LIB_HEADERS} fpga_multicorrelator.h dll_pll_conf_fpga.h) +endif() + include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${VOLK_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${OPT_TRACKING_INCLUDES} - ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${ARMADILLO_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${OPT_TRACKING_INCLUDES} + ${VOLK_GNSSSDR_INCLUDE_DIRS} ) if(ENABLE_GENERIC_ARCH) - add_definitions( -DGENERIC_ARCH=1 ) -endif(ENABLE_GENERIC_ARCH) - -if (SSE3_AVAILABLE) - add_definitions( -DHAVE_SSE3=1 ) -endif(SSE3_AVAILABLE) - - -file(GLOB TRACKING_LIB_HEADERS "*.h") -list(SORT TRACKING_LIB_HEADERS) -add_library(tracking_lib ${TRACKING_LIB_SOURCES} ${TRACKING_LIB_HEADERS}) -source_group(Headers FILES ${TRACKING_LIB_HEADERS}) -target_link_libraries(tracking_lib ${OPT_TRACKING_LIBRARIES} ${VOLK_LIBRARIES} ${VOLK_GNSSSDR_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES}) - -if(VOLK_GNSSSDR_FOUND) - add_dependencies(tracking_lib glog-${glog_RELEASE}) -else(VOLK_GNSSSDR_FOUND) - add_dependencies(tracking_lib glog-${glog_RELEASE} volk_gnsssdr_module) + add_definitions(-DGENERIC_ARCH=1) endif() +if(SSE3_AVAILABLE) + add_definitions(-DHAVE_SSE3=1) +endif() + +list(SORT TRACKING_LIB_HEADERS) +list(SORT TRACKING_LIB_SOURCES) + +add_library(tracking_lib ${TRACKING_LIB_SOURCES} ${TRACKING_LIB_HEADERS}) + +source_group(Headers FILES ${TRACKING_LIB_HEADERS}) + +target_link_libraries(tracking_lib + ${OPT_TRACKING_LIBRARIES} + ${VOLK_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${Boost_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} +) + +if(VOLKGNSSSDR_FOUND) + add_dependencies(tracking_lib glog-${glog_RELEASE}) +else() + add_dependencies(tracking_lib glog-${glog_RELEASE} volk_gnsssdr_module) +endif() diff --git a/src/algorithms/tracking/libs/bayesian_estimation.cc b/src/algorithms/tracking/libs/bayesian_estimation.cc new file mode 100644 index 000000000..227cd6321 --- /dev/null +++ b/src/algorithms/tracking/libs/bayesian_estimation.cc @@ -0,0 +1,185 @@ +/*! + * \file bayesian_estimation.cc + * \brief Interface of a library with Bayesian noise statistic estimation + * + * Bayesian_estimator is a Bayesian estimator which attempts to estimate + * the properties of a stochastic process based on a sequence of + * discrete samples of the sequence. + * + * [1] TODO: Refs + * + * \authors
        + *
      • Gerald LaMountain, 2018. gerald(at)ece.neu.edu + *
      • Jordi Vila-Valls 2018. jvila(at)cttc.es + *
      + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "bayesian_estimation.h" + + +Bayesian_estimator::Bayesian_estimator() +{ + int ny = 1; + mu_prior = arma::zeros(ny, 1); + kappa_prior = 0; + nu_prior = 0; + Psi_prior = arma::eye(ny, ny) * (nu_prior + ny + 1); + + mu_est = mu_prior; + Psi_est = Psi_prior; +} + +Bayesian_estimator::Bayesian_estimator(int ny) +{ + mu_prior = arma::zeros(ny, 1); + kappa_prior = 0; + nu_prior = 0; + Psi_prior = arma::eye(ny, ny) * (nu_prior + ny + 1); + + mu_est = mu_prior; + Psi_est = Psi_prior; +} + +Bayesian_estimator::Bayesian_estimator(const arma::vec& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0) +{ + mu_prior = mu_prior_0; + kappa_prior = kappa_prior_0; + nu_prior = nu_prior_0; + Psi_prior = Psi_prior_0; + + mu_est = mu_prior; + Psi_est = Psi_prior; +} + +Bayesian_estimator::~Bayesian_estimator() = default; + +void Bayesian_estimator::init(const arma::mat& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0) +{ + mu_prior = mu_prior_0; + kappa_prior = kappa_prior_0; + nu_prior = nu_prior_0; + Psi_prior = Psi_prior_0; + + mu_est = mu_prior; + Psi_est = Psi_prior; +} + +/* + * Perform Bayesian noise estimation using the normal-inverse-Wishart priors stored in + * the class structure, and update the priors according to the computed posteriors + */ +void Bayesian_estimator::update_sequential(const arma::vec& data) +{ + int K = data.n_cols; + int ny = data.n_rows; + + if (mu_prior.is_empty()) + { + mu_prior = arma::zeros(ny, 1); + } + + if (Psi_prior.is_empty()) + { + Psi_prior = arma::zeros(ny, ny); + } + + arma::vec y_mean = arma::mean(data, 1); + arma::mat Psi_N = arma::zeros(ny, ny); + + for (int kk = 0; kk < K; kk++) + { + Psi_N = Psi_N + (data.col(kk) - y_mean) * ((data.col(kk) - y_mean).t()); + } + + arma::vec mu_posterior = (kappa_prior * mu_prior + K * y_mean) / (kappa_prior + K); + int kappa_posterior = kappa_prior + K; + int nu_posterior = nu_prior + K; + arma::mat Psi_posterior = Psi_prior + Psi_N + (kappa_prior * K) / (kappa_prior + K) * (y_mean - mu_prior) * ((y_mean - mu_prior).t()); + + mu_est = mu_posterior; + if ((nu_posterior - ny - 1) > 0) + { + Psi_est = Psi_posterior / (nu_posterior - ny - 1); + } + else + { + Psi_est = Psi_posterior / (nu_posterior + ny + 1); + } + + mu_prior = mu_posterior; + kappa_prior = kappa_posterior; + nu_prior = nu_posterior; + Psi_prior = Psi_posterior; +} + + +/* + * Perform Bayesian noise estimation using a new set of normal-inverse-Wishart priors + * and update the priors according to the computed posteriors + */ +void Bayesian_estimator::update_sequential(const arma::vec& data, const arma::vec& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0) +{ + int K = data.n_cols; + int ny = data.n_rows; + + arma::vec y_mean = arma::mean(data, 1); + arma::mat Psi_N = arma::zeros(ny, ny); + + for (int kk = 0; kk < K; kk++) + { + Psi_N = Psi_N + (data.col(kk) - y_mean) * ((data.col(kk) - y_mean).t()); + } + + arma::vec mu_posterior = (kappa_prior_0 * mu_prior_0 + K * y_mean) / (kappa_prior_0 + K); + int kappa_posterior = kappa_prior_0 + K; + int nu_posterior = nu_prior_0 + K; + arma::mat Psi_posterior = Psi_prior_0 + Psi_N + (kappa_prior_0 * K) / (kappa_prior_0 + K) * (y_mean - mu_prior_0) * ((y_mean - mu_prior_0).t()); + + mu_est = mu_posterior; + if ((nu_posterior - ny - 1) > 0) + { + Psi_est = Psi_posterior / (nu_posterior - ny - 1); + } + else + { + Psi_est = Psi_posterior / (nu_posterior + ny + 1); + } + + mu_prior = mu_posterior; + kappa_prior = kappa_posterior; + nu_prior = nu_posterior; + Psi_prior = Psi_posterior; +} + +arma::mat Bayesian_estimator::get_mu_est() const +{ + return mu_est; +} + +arma::mat Bayesian_estimator::get_Psi_est() const +{ + return Psi_est; +} diff --git a/src/algorithms/tracking/libs/bayesian_estimation.h b/src/algorithms/tracking/libs/bayesian_estimation.h new file mode 100644 index 000000000..02f54143e --- /dev/null +++ b/src/algorithms/tracking/libs/bayesian_estimation.h @@ -0,0 +1,85 @@ +/*! + * \file bayesian_estimation.h + * \brief Interface of a library with Bayesian noise statistic estimation + * + * Bayesian_estimator is a Bayesian estimator which attempts to estimate + * the properties of a stochastic process based on a sequence of + * discrete samples of the sequence. + * + * [1] TODO: Refs + * + * \authors
        + *
      • Gerald LaMountain, 2018. gerald(at)ece.neu.edu + *
      • Jordi Vila-Valls 2018. jvila(at)cttc.es + *
      + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_BAYESIAN_ESTIMATION_H_ +#define GNSS_SDR_BAYESIAN_ESTIMATION_H_ + +#include +#include + +/*! \brief Bayesian_estimator is an estimator of noise characteristics (i.e. mean, covariance) + * + * Bayesian_estimator is an estimator which performs estimation of noise characteristics from + * a sequence of identically and independently distributed (IID) samples of a stationary + * stochastic process by way of Bayesian inference using conjugate priors. The posterior + * distribution is assumed to be Gaussian with mean \mathbf{\mu} and covariance \hat{\mathbf{C}}, + * which has a conjugate prior given by a normal-inverse-Wishart distribution with paramemters + * \mathbf{\mu}_{0}, \kappa_{0}, \nu_{0}, and \mathbf{\Psi}. + * + * [1] TODO: Ref1 + * + */ + +class Bayesian_estimator +{ +public: + Bayesian_estimator(); + Bayesian_estimator(int ny); + Bayesian_estimator(const arma::vec& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0); + ~Bayesian_estimator(); + + void init(const arma::mat& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0); + + void update_sequential(const arma::vec& data); + void update_sequential(const arma::vec& data, const arma::vec& mu_prior_0, int kappa_prior_0, int nu_prior_0, const arma::mat& Psi_prior_0); + + arma::mat get_mu_est() const; + arma::mat get_Psi_est() const; + +private: + arma::vec mu_est; + arma::mat Psi_est; + + arma::vec mu_prior; + int kappa_prior; + int nu_prior; + arma::mat Psi_prior; +}; + +#endif diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator.cc b/src/algorithms/tracking/libs/cpu_multicorrelator.cc index 7551669c0..0e30856ce 100644 --- a/src/algorithms/tracking/libs/cpu_multicorrelator.cc +++ b/src/algorithms/tracking/libs/cpu_multicorrelator.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,15 +27,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "cpu_multicorrelator.h" -#include -#include #include +#include cpu_multicorrelator::cpu_multicorrelator() @@ -52,7 +51,7 @@ cpu_multicorrelator::cpu_multicorrelator() cpu_multicorrelator::~cpu_multicorrelator() { - if(d_local_codes_resampled != nullptr) + if (d_local_codes_resampled != nullptr) { cpu_multicorrelator::free(); } @@ -60,8 +59,8 @@ cpu_multicorrelator::~cpu_multicorrelator() bool cpu_multicorrelator::init( - int max_signal_length_samples, - int n_correlators) + int max_signal_length_samples, + int n_correlators) { // ALLOCATE MEMORY FOR INTERNAL vectors size_t size = max_signal_length_samples * sizeof(std::complex); @@ -76,11 +75,10 @@ bool cpu_multicorrelator::init( } - bool cpu_multicorrelator::set_local_code_and_taps( - int code_length_chips, - const std::complex* local_code_in, - float *shifts_chips) + int code_length_chips, + const std::complex* local_code_in, + float* shifts_chips) { d_local_code_in = local_code_in; d_shifts_chips = shifts_chips; @@ -101,29 +99,29 @@ bool cpu_multicorrelator::set_input_output_vectors(std::complex* corr_out void cpu_multicorrelator::update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips) { volk_gnsssdr_32fc_xn_resampler_32fc_xn(d_local_codes_resampled, - d_local_code_in, - rem_code_phase_chips, - code_phase_step_chips, - d_shifts_chips, - d_code_length_chips, - d_n_correlators, - correlator_length_samples); + d_local_code_in, + rem_code_phase_chips, + code_phase_step_chips, + d_shifts_chips, + d_code_length_chips, + d_n_correlators, + correlator_length_samples); } bool cpu_multicorrelator::Carrier_wipeoff_multicorrelator_resampler( - float rem_carrier_phase_in_rad, - float phase_step_rad, - float rem_code_phase_chips, - float code_phase_step_chips, - int signal_length_samples) + float rem_carrier_phase_in_rad, + float phase_step_rad, + float rem_code_phase_chips, + float code_phase_step_chips, + int signal_length_samples) { update_local_code(signal_length_samples, rem_code_phase_chips, code_phase_step_chips); // Regenerate phase at each call in order to avoid numerical issues lv_32fc_t phase_offset_as_complex[1]; phase_offset_as_complex[0] = lv_cmake(std::cos(rem_carrier_phase_in_rad), -std::sin(rem_carrier_phase_in_rad)); // call VOLK_GNSSSDR kernel - volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0, - phase_step_rad)), phase_offset_as_complex, (const lv_32fc_t**)d_local_codes_resampled, d_n_correlators, signal_length_samples); + volk_gnsssdr_32fc_x2_rotator_dot_prod_32fc_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0, -phase_step_rad)), phase_offset_as_complex, const_cast(d_local_codes_resampled), d_n_correlators, signal_length_samples); return true; } @@ -142,4 +140,3 @@ bool cpu_multicorrelator::free() } return true; } - diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator.h b/src/algorithms/tracking/libs/cpu_multicorrelator.h index 2174595b9..8dab4c4a4 100644 --- a/src/algorithms/tracking/libs/cpu_multicorrelator.h +++ b/src/algorithms/tracking/libs/cpu_multicorrelator.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -47,8 +47,8 @@ public: cpu_multicorrelator(); ~cpu_multicorrelator(); bool init(int max_signal_length_samples, int n_correlators); - bool set_local_code_and_taps(int code_length_chips, const std::complex* local_code_in, float *shifts_chips); - bool set_input_output_vectors(std::complex* corr_out, const std::complex* sig_in); + bool set_local_code_and_taps(int code_length_chips, const std::complex *local_code_in, float *shifts_chips); + bool set_input_output_vectors(std::complex *corr_out, const std::complex *sig_in); void update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips); bool Carrier_wipeoff_multicorrelator_resampler(float rem_carrier_phase_in_rad, float phase_step_rad, float rem_code_phase_chips, float code_phase_step_chips, int signal_length_samples); bool free(); diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.cc b/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.cc index fa9f7873c..e57d1c2eb 100644 --- a/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.cc +++ b/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,10 +36,9 @@ #include - bool cpu_multicorrelator_16sc::init( - int max_signal_length_samples, - int n_correlators) + int max_signal_length_samples, + int n_correlators) { // ALLOCATE MEMORY FOR INTERNAL vectors size_t size = max_signal_length_samples * sizeof(lv_16sc_t); @@ -55,11 +54,10 @@ bool cpu_multicorrelator_16sc::init( } - bool cpu_multicorrelator_16sc::set_local_code_and_taps( - int code_length_chips, - const lv_16sc_t* local_code_in, - float *shifts_chips) + int code_length_chips, + const lv_16sc_t* local_code_in, + float* shifts_chips) { d_local_code_in = local_code_in; d_shifts_chips = shifts_chips; @@ -80,29 +78,29 @@ bool cpu_multicorrelator_16sc::set_input_output_vectors(lv_16sc_t* corr_out, con void cpu_multicorrelator_16sc::update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips) { volk_gnsssdr_16ic_xn_resampler_16ic_xn(d_local_codes_resampled, - d_local_code_in, - rem_code_phase_chips, - code_phase_step_chips, - d_shifts_chips, - d_code_length_chips, - d_n_correlators, - correlator_length_samples); + d_local_code_in, + rem_code_phase_chips, + code_phase_step_chips, + d_shifts_chips, + d_code_length_chips, + d_n_correlators, + correlator_length_samples); } bool cpu_multicorrelator_16sc::Carrier_wipeoff_multicorrelator_resampler( - float rem_carrier_phase_in_rad, - float phase_step_rad, - float rem_code_phase_chips, - float code_phase_step_chips, - int signal_length_samples) + float rem_carrier_phase_in_rad, + float phase_step_rad, + float rem_code_phase_chips, + float code_phase_step_chips, + int signal_length_samples) { update_local_code(signal_length_samples, rem_code_phase_chips, code_phase_step_chips); // Regenerate phase at each call in order to avoid numerical issues lv_32fc_t phase_offset_as_complex[1]; phase_offset_as_complex[0] = lv_cmake(std::cos(rem_carrier_phase_in_rad), -std::sin(rem_carrier_phase_in_rad)); // call VOLK_GNSSSDR kernel - volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0, -phase_step_rad)), phase_offset_as_complex, (const lv_16sc_t**)d_local_codes_resampled, d_n_correlators, signal_length_samples); + volk_gnsssdr_16ic_x2_rotator_dot_prod_16ic_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0, -phase_step_rad)), phase_offset_as_complex, const_cast(d_local_codes_resampled), d_n_correlators, signal_length_samples); return true; } @@ -121,7 +119,7 @@ cpu_multicorrelator_16sc::cpu_multicorrelator_16sc() cpu_multicorrelator_16sc::~cpu_multicorrelator_16sc() { - if(d_local_codes_resampled != nullptr) + if (d_local_codes_resampled != nullptr) { cpu_multicorrelator_16sc::free(); } @@ -142,4 +140,3 @@ bool cpu_multicorrelator_16sc::free() } return true; } - diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.h b/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.h index 617d79b37..16881ca07 100644 --- a/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.h +++ b/src/algorithms/tracking/libs/cpu_multicorrelator_16sc.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -47,8 +47,8 @@ public: cpu_multicorrelator_16sc(); ~cpu_multicorrelator_16sc(); bool init(int max_signal_length_samples, int n_correlators); - bool set_local_code_and_taps(int code_length_chips, const lv_16sc_t* local_code_in, float *shifts_chips); - bool set_input_output_vectors(lv_16sc_t* corr_out, const lv_16sc_t* sig_in); + bool set_local_code_and_taps(int code_length_chips, const lv_16sc_t *local_code_in, float *shifts_chips); + bool set_input_output_vectors(lv_16sc_t *corr_out, const lv_16sc_t *sig_in); void update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips); bool Carrier_wipeoff_multicorrelator_resampler(float rem_carrier_phase_in_rad, float phase_step_rad, float rem_code_phase_chips, float code_phase_step_chips, int signal_length_samples); bool free(); diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.cc b/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.cc new file mode 100644 index 000000000..f23537fad --- /dev/null +++ b/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.cc @@ -0,0 +1,192 @@ +/*! + * \file cpu_multicorrelator_real_codes.cc + * \brief Highly optimized CPU vector multiTAP correlator class with real-valued local codes + * \authors
        + *
      • Javier Arribas, 2015. jarribas(at)cttc.es + *
      • Cillian O'Driscoll, 2017. cillian.odriscoll(at)gmail.com + *
      + * + * Class that implements a high optimized vector multiTAP correlator class for CPUs + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "cpu_multicorrelator_real_codes.h" +#include +#include + +cpu_multicorrelator_real_codes::cpu_multicorrelator_real_codes() +{ + d_sig_in = nullptr; + d_local_code_in = nullptr; + d_shifts_chips = nullptr; + d_corr_out = nullptr; + d_local_codes_resampled = nullptr; + d_code_length_chips = 0; + d_n_correlators = 0; + d_use_high_dynamics_resampler = true; +} + + +cpu_multicorrelator_real_codes::~cpu_multicorrelator_real_codes() +{ + if (d_local_codes_resampled != nullptr) + { + cpu_multicorrelator_real_codes::free(); + } +} + + +bool cpu_multicorrelator_real_codes::init( + int max_signal_length_samples, + int n_correlators) +{ + // ALLOCATE MEMORY FOR INTERNAL vectors + size_t size = max_signal_length_samples * sizeof(float); + + d_local_codes_resampled = static_cast(volk_gnsssdr_malloc(n_correlators * sizeof(float*), volk_gnsssdr_get_alignment())); + for (int n = 0; n < n_correlators; n++) + { + d_local_codes_resampled[n] = static_cast(volk_gnsssdr_malloc(size, volk_gnsssdr_get_alignment())); + } + d_n_correlators = n_correlators; + return true; +} + + +bool cpu_multicorrelator_real_codes::set_local_code_and_taps( + int code_length_chips, + const float* local_code_in, + float* shifts_chips) +{ + d_local_code_in = local_code_in; + d_shifts_chips = shifts_chips; + d_code_length_chips = code_length_chips; + + return true; +} + + +bool cpu_multicorrelator_real_codes::set_input_output_vectors(std::complex* corr_out, const std::complex* sig_in) +{ + // Save CPU pointers + d_sig_in = sig_in; + d_corr_out = corr_out; + return true; +} + + +void cpu_multicorrelator_real_codes::update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips) +{ + if (d_use_high_dynamics_resampler) + { + volk_gnsssdr_32f_xn_high_dynamics_resampler_32f_xn(d_local_codes_resampled, + d_local_code_in, + rem_code_phase_chips, + code_phase_step_chips, + code_phase_rate_step_chips, + d_shifts_chips, + d_code_length_chips, + d_n_correlators, + correlator_length_samples); + } + else + { + volk_gnsssdr_32f_xn_resampler_32f_xn(d_local_codes_resampled, + d_local_code_in, + rem_code_phase_chips, + code_phase_step_chips, + d_shifts_chips, + d_code_length_chips, + d_n_correlators, + correlator_length_samples); + } +} + +// Overload Carrier_wipeoff_multicorrelator_resampler to ensure back compatibility +bool cpu_multicorrelator_real_codes::Carrier_wipeoff_multicorrelator_resampler( + float rem_carrier_phase_in_rad, + float phase_step_rad, + float phase_rate_step_rad, + float rem_code_phase_chips, + float code_phase_step_chips, + float code_phase_rate_step_chips, + int signal_length_samples) +{ + update_local_code(signal_length_samples, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips); + // Regenerate phase at each call in order to avoid numerical issues + lv_32fc_t phase_offset_as_complex[1]; + phase_offset_as_complex[0] = lv_cmake(std::cos(rem_carrier_phase_in_rad), -std::sin(rem_carrier_phase_in_rad)); + // call VOLK_GNSSSDR kernel + if (d_use_high_dynamics_resampler) + { + volk_gnsssdr_32fc_32f_high_dynamic_rotator_dot_prod_32fc_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0.0, -phase_step_rad)), std::exp(lv_32fc_t(0.0, -phase_rate_step_rad)), phase_offset_as_complex, const_cast(d_local_codes_resampled), d_n_correlators, signal_length_samples); + } + else + { + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0.0, -phase_step_rad)), phase_offset_as_complex, const_cast(d_local_codes_resampled), d_n_correlators, signal_length_samples); + } + return true; +} +// Overload Carrier_wipeoff_multicorrelator_resampler to ensure back compatibility +bool cpu_multicorrelator_real_codes::Carrier_wipeoff_multicorrelator_resampler( + float rem_carrier_phase_in_rad, + float phase_step_rad, + float rem_code_phase_chips, + float code_phase_step_chips, + float code_phase_rate_step_chips, + int signal_length_samples) +{ + update_local_code(signal_length_samples, rem_code_phase_chips, code_phase_step_chips, code_phase_rate_step_chips); + // Regenerate phase at each call in order to avoid numerical issues + lv_32fc_t phase_offset_as_complex[1]; + phase_offset_as_complex[0] = lv_cmake(std::cos(rem_carrier_phase_in_rad), -std::sin(rem_carrier_phase_in_rad)); + // call VOLK_GNSSSDR kernel + volk_gnsssdr_32fc_32f_rotator_dot_prod_32fc_xn(d_corr_out, d_sig_in, std::exp(lv_32fc_t(0.0, -phase_step_rad)), phase_offset_as_complex, const_cast(d_local_codes_resampled), d_n_correlators, signal_length_samples); + return true; +} + + +bool cpu_multicorrelator_real_codes::free() +{ + // Free memory + if (d_local_codes_resampled != nullptr) + { + for (int n = 0; n < d_n_correlators; n++) + { + volk_gnsssdr_free(d_local_codes_resampled[n]); + } + volk_gnsssdr_free(d_local_codes_resampled); + d_local_codes_resampled = nullptr; + } + return true; +} + + +void cpu_multicorrelator_real_codes::set_high_dynamics_resampler( + bool use_high_dynamics_resampler) +{ + d_use_high_dynamics_resampler = use_high_dynamics_resampler; +} diff --git a/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.h b/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.h new file mode 100644 index 000000000..a4dfdd5f0 --- /dev/null +++ b/src/algorithms/tracking/libs/cpu_multicorrelator_real_codes.h @@ -0,0 +1,73 @@ +/*! + * \file cpu_multicorrelator_real_codes.h + * \brief Highly optimized CPU vector multiTAP correlator class using real-valued local codes + * \authors
        + *
      • Javier Arribas, 2015. jarribas(at)cttc.es + *
      • Cillian O'Driscoll, 2017, cillian.odriscoll(at)gmail.com + *
      + * + * Class that implements a high optimized vector multiTAP correlator class for CPUs + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CPU_MULTICORRELATOR_REAL_CODES_H_ +#define GNSS_SDR_CPU_MULTICORRELATOR_REAL_CODES_H_ + + +#include + +/*! + * \brief Class that implements carrier wipe-off and correlators. + */ +class cpu_multicorrelator_real_codes +{ +public: + cpu_multicorrelator_real_codes(); + void set_high_dynamics_resampler(bool use_high_dynamics_resampler); + ~cpu_multicorrelator_real_codes(); + bool init(int max_signal_length_samples, int n_correlators); + bool set_local_code_and_taps(int code_length_chips, const float *local_code_in, float *shifts_chips); + bool set_input_output_vectors(std::complex *corr_out, const std::complex *sig_in); + void update_local_code(int correlator_length_samples, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips = 0.0); + // Overload Carrier_wipeoff_multicorrelator_resampler to ensure back compatibility + bool Carrier_wipeoff_multicorrelator_resampler(float rem_carrier_phase_in_rad, float phase_step_rad, float phase_rate_step_rad, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, int signal_length_samples); + bool Carrier_wipeoff_multicorrelator_resampler(float rem_carrier_phase_in_rad, float phase_step_rad, float rem_code_phase_chips, float code_phase_step_chips, float code_phase_rate_step_chips, int signal_length_samples); + bool free(); + +private: + // Allocate the device input vectors + const std::complex *d_sig_in; + float **d_local_codes_resampled; + const float *d_local_code_in; + std::complex *d_corr_out; + float *d_shifts_chips; + bool d_use_high_dynamics_resampler; + int d_code_length_chips; + int d_n_correlators; +}; + + +#endif /* CPU_MULTICORRELATOR_REAL_CODES_H_ */ diff --git a/src/algorithms/tracking/libs/cuda_multicorrelator.cu b/src/algorithms/tracking/libs/cuda_multicorrelator.cu index 56cea6ea7..38aefbcd5 100644 --- a/src/algorithms/tracking/libs/cuda_multicorrelator.cu +++ b/src/algorithms/tracking/libs/cuda_multicorrelator.cu @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/algorithms/tracking/libs/cuda_multicorrelator.h b/src/algorithms/tracking/libs/cuda_multicorrelator.h index 10b891344..f75d72675 100644 --- a/src/algorithms/tracking/libs/cuda_multicorrelator.h +++ b/src/algorithms/tracking/libs/cuda_multicorrelator.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -54,22 +54,26 @@ struct GPU_Complex { float r; float i; - CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex() {}; - CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex( float a, float b ) : r(a), i(b) {} - CUDA_CALLABLE_MEMBER_DEVICE float magnitude2( void ) { return r * r + i * i; } + CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex(){}; + CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex(float a, float b) : r(a), i(b) {} + CUDA_CALLABLE_MEMBER_DEVICE float magnitude2(void) { return r * r + i * i; } CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex operator*(const GPU_Complex& a) { #ifdef __CUDACC__ return GPU_Complex(__fmul_rn(r, a.r) - __fmul_rn(i, a.i), __fmul_rn(i, a.r) + __fmul_rn(r, a.i)); #else - return GPU_Complex(r*a.r - i*a.i, i*a.r + r*a.i); + return GPU_Complex(r * a.r - i * a.i, i * a.r + r * a.i); #endif } CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex operator+(const GPU_Complex& a) { return GPU_Complex(r + a.r, i + a.i); } - CUDA_CALLABLE_MEMBER_DEVICE void operator+=(const GPU_Complex& a) { r += a.r; i += a.i; } + CUDA_CALLABLE_MEMBER_DEVICE void operator+=(const GPU_Complex& a) + { + r += a.r; + i += a.i; + } CUDA_CALLABLE_MEMBER_DEVICE void multiply_acc(const GPU_Complex& a, const GPU_Complex& b) { //c=a*b+c @@ -82,10 +86,9 @@ struct GPU_Complex i = __fmaf_rn(a.i, b.r, i); i = __fmaf_rn(a.r, b.i, i); #else - r = (a.r*b.r - a.i*b.i) + r; - i = (a.i*b.r - a.r*b.i) + i; + r = (a.r * b.r - a.i * b.i) + r; + i = (a.i * b.r - a.r * b.i) + i; #endif - } }; @@ -93,18 +96,18 @@ struct GPU_Complex_Short { float r; float i; - CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex_Short( short int a, short int b ) : r(a), i(b) {} - CUDA_CALLABLE_MEMBER_DEVICE float magnitude2( void ) + CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex_Short(short int a, short int b) : r(a), i(b) {} + CUDA_CALLABLE_MEMBER_DEVICE float magnitude2(void) { return r * r + i * i; } CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex_Short operator*(const GPU_Complex_Short& a) { - return GPU_Complex_Short(r*a.r - i*a.i, i*a.r + r*a.i); + return GPU_Complex_Short(r * a.r - i * a.i, i * a.r + r * a.i); } CUDA_CALLABLE_MEMBER_DEVICE GPU_Complex_Short operator+(const GPU_Complex_Short& a) { - return GPU_Complex_Short(r+a.r, i+a.i); + return GPU_Complex_Short(r + a.r, i + a.i); } }; @@ -117,44 +120,41 @@ class cuda_multicorrelator public: cuda_multicorrelator(); bool init_cuda_integrated_resampler( - int signal_length_samples, - int code_length_chips, - int n_correlators - ); + int signal_length_samples, + int code_length_chips, + int n_correlators); bool set_local_code_and_taps( - int code_length_chips, - const std::complex* local_codes_in, - float *shifts_chips, - int n_correlators - ); + int code_length_chips, + const std::complex* local_codes_in, + float* shifts_chips, + int n_correlators); bool set_input_output_vectors( - std::complex* corr_out, - std::complex* sig_in - ); + std::complex* corr_out, + std::complex* sig_in); bool free_cuda(); bool Carrier_wipeoff_multicorrelator_resampler_cuda( - float rem_carrier_phase_in_rad, - float phase_step_rad, - float code_phase_step_chips, - float rem_code_phase_chips, - int signal_length_samples, - int n_correlators); + float rem_carrier_phase_in_rad, + float phase_step_rad, + float code_phase_step_chips, + float rem_code_phase_chips, + int signal_length_samples, + int n_correlators); private: // Allocate the device input vectors - GPU_Complex *d_sig_in; - GPU_Complex *d_nco_in; - GPU_Complex *d_sig_doppler_wiped; - GPU_Complex *d_local_codes_in; - GPU_Complex *d_corr_out; + GPU_Complex* d_sig_in; + GPU_Complex* d_nco_in; + GPU_Complex* d_sig_doppler_wiped; + GPU_Complex* d_local_codes_in; + GPU_Complex* d_corr_out; // - std::complex *d_sig_in_cpu; - std::complex *d_corr_out_cpu; + std::complex* d_sig_in_cpu; + std::complex* d_corr_out_cpu; - int *d_shifts_samples; - float *d_shifts_chips; + int* d_shifts_samples; + float* d_shifts_chips; int d_code_length_chips; int selected_gps_device; diff --git a/src/algorithms/tracking/libs/dll_pll_conf.cc b/src/algorithms/tracking/libs/dll_pll_conf.cc new file mode 100644 index 000000000..77c0b48a3 --- /dev/null +++ b/src/algorithms/tracking/libs/dll_pll_conf.cc @@ -0,0 +1,66 @@ +/*! + * \file dll_pll_conf.cc + * \brief Class that contains all the configuration parameters for generic + * tracking block based on a DLL and a PLL. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "dll_pll_conf.h" +#include + +Dll_Pll_Conf::Dll_Pll_Conf() +{ + /* DLL/PLL tracking configuration */ + high_dyn = false; + smoother_length = 10; + fs_in = 0.0; + vector_length = 0U; + dump = false; + dump_mat = true; + dump_filename = std::string("./dll_pll_dump.dat"); + pll_pull_in_bw_hz = 50.0; + dll_pull_in_bw_hz = 3.0; + pll_bw_hz = 35.0; + dll_bw_hz = 2.0; + pll_bw_narrow_hz = 5.0; + dll_bw_narrow_hz = 0.75; + early_late_space_chips = 0.5; + very_early_late_space_chips = 0.5; + early_late_space_narrow_chips = 0.1; + very_early_late_space_narrow_chips = 0.1; + extend_correlation_symbols = 5; + cn0_samples = 20; + carrier_lock_det_mav_samples = 20; + cn0_min = 25; + max_lock_fail = 50; + carrier_lock_th = 0.85; + track_pilot = false; + system = 'G'; + char sig_[3] = "1C"; + std::memcpy(signal, sig_, 3); +} diff --git a/src/algorithms/tracking/libs/dll_pll_conf.h b/src/algorithms/tracking/libs/dll_pll_conf.h new file mode 100644 index 000000000..2304404b1 --- /dev/null +++ b/src/algorithms/tracking/libs/dll_pll_conf.h @@ -0,0 +1,73 @@ +/*! + * \file dll_pll_conf.h + * \brief Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DLL_PLL_CONF_H_ +#define GNSS_SDR_DLL_PLL_CONF_H_ + +#include +#include + +class Dll_Pll_Conf +{ +public: + /* DLL/PLL tracking configuration */ + double fs_in; + uint32_t vector_length; + bool dump; + bool dump_mat; + std::string dump_filename; + float pll_pull_in_bw_hz; + float dll_pull_in_bw_hz; + float pll_bw_hz; + float dll_bw_hz; + float pll_bw_narrow_hz; + float dll_bw_narrow_hz; + float early_late_space_chips; + float very_early_late_space_chips; + float early_late_space_narrow_chips; + float very_early_late_space_narrow_chips; + int32_t extend_correlation_symbols; + bool high_dyn; + int32_t cn0_samples; + int32_t carrier_lock_det_mav_samples; + int32_t cn0_min; + int32_t max_lock_fail; + uint32_t smoother_length; + double carrier_lock_th; + bool track_pilot; + char system; + char signal[3]{}; + + Dll_Pll_Conf(); +}; + +#endif diff --git a/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc b/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc new file mode 100644 index 000000000..87b66a911 --- /dev/null +++ b/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc @@ -0,0 +1,68 @@ +/*! + * \file dll_pll_conf.cc + * \brief Class that contains all the configuration parameters for generic + * tracking block based on a DLL and a PLL. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "dll_pll_conf_fpga.h" +#include + +Dll_Pll_Conf_Fpga::Dll_Pll_Conf_Fpga() +{ + /* DLL/PLL tracking configuration */ + fs_in = 0.0; + vector_length = 0U; + dump = false; + dump_mat = true; + dump_filename = std::string("./dll_pll_dump.dat"); + pll_bw_hz = 40.0; + dll_bw_hz = 2.0; + pll_bw_narrow_hz = 5.0; + dll_bw_narrow_hz = 0.75; + early_late_space_chips = 0.5; + very_early_late_space_chips = 0.5; + early_late_space_narrow_chips = 0.1; + very_early_late_space_narrow_chips = 0.1; + extend_correlation_symbols = 5; + cn0_samples = 20; + cn0_min = 25; + max_lock_fail = 50; + carrier_lock_th = 0.85; + track_pilot = false; + system = 'G'; + char sig_[3] = "1C"; + std::memcpy(signal, sig_, 3); + device_name = "/dev/uio"; + device_base = 1U; + multicorr_type = 0U; + code_length_chips = 0U; + code_samples_per_chip = 0U; + ca_codes = nullptr; + data_codes = nullptr; +} diff --git a/src/algorithms/tracking/libs/dll_pll_conf_fpga.h b/src/algorithms/tracking/libs/dll_pll_conf_fpga.h new file mode 100644 index 000000000..8fd81fb36 --- /dev/null +++ b/src/algorithms/tracking/libs/dll_pll_conf_fpga.h @@ -0,0 +1,75 @@ +/*! + * \file dll_pll_conf.h + * \brief Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DLL_PLL_CONF_FPGA_H_ +#define GNSS_SDR_DLL_PLL_CONF_FPGA_H_ + +#include +#include + +class Dll_Pll_Conf_Fpga +{ +public: + /* DLL/PLL tracking configuration */ + double fs_in; + uint32_t vector_length; + bool dump; + bool dump_mat; + std::string dump_filename; + float pll_bw_hz; + float dll_bw_hz; + float pll_bw_narrow_hz; + float dll_bw_narrow_hz; + float early_late_space_chips; + float very_early_late_space_chips; + float early_late_space_narrow_chips; + float very_early_late_space_narrow_chips; + int32_t extend_correlation_symbols; + int32_t cn0_samples; + int32_t cn0_min; + int32_t max_lock_fail; + double carrier_lock_th; + bool track_pilot; + char system; + char signal[3]; + std::string device_name; + uint32_t device_base; + uint32_t multicorr_type; + uint32_t code_length_chips; + uint32_t code_samples_per_chip; + int32_t* ca_codes; + int32_t* data_codes; + + Dll_Pll_Conf_Fpga(); +}; + +#endif diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.cc b/src/algorithms/tracking/libs/fpga_multicorrelator.cc new file mode 100644 index 000000000..add36b0a8 --- /dev/null +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.cc @@ -0,0 +1,741 @@ +/*! + * \file fpga_multicorrelator_8sc.cc + * \brief High optimized FPGA vector correlator class + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2015. jarribas(at)cttc.es + *
      + * + * Class that controls and executes a high optimized vector correlator + * class in the FPGA + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fpga_multicorrelator.h" +#include + +// FPGA stuff +#include + +// libraries used by DMA test code and GIPO test code +#include +#include +#include +#include + +// libraries used by DMA test code +#include +#include +#include +#include + +// libraries used by GPIO test code +#include +#include +#include + +// logging +#include + +// string manipulation +#include +#include + +// constants +#include "GPS_L1_CA.h" + +//#include "gps_sdr_signal_processing.h" + +#define NUM_PRNs 32 +#define PAGE_SIZE 0x10000 +#define MAX_LENGTH_DEVICEIO_NAME 50 +#define CODE_RESAMPLER_NUM_BITS_PRECISION 20 +#define CODE_PHASE_STEP_CHIPS_NUM_NBITS CODE_RESAMPLER_NUM_BITS_PRECISION +#define pwrtwo(x) (1 << (x)) +#define MAX_CODE_RESAMPLER_COUNTER pwrtwo(CODE_PHASE_STEP_CHIPS_NUM_NBITS) // 2^CODE_PHASE_STEP_CHIPS_NUM_NBITS +#define PHASE_CARR_NBITS 32 +#define PHASE_CARR_NBITS_INT 1 +#define PHASE_CARR_NBITS_FRAC PHASE_CARR_NBITS - PHASE_CARR_NBITS_INT +#define LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT 0x20000000 +#define LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER 0x10000000 +#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 +#define TEST_REGISTER_TRACK_WRITEVAL 0x55AA + +uint64_t fpga_multicorrelator_8sc::read_sample_counter() +{ + uint64_t sample_counter_tmp, sample_counter_msw_tmp; + sample_counter_tmp = d_map_base[d_SAMPLE_COUNTER_REG_ADDR_LSW]; + sample_counter_msw_tmp = d_map_base[d_SAMPLE_COUNTER_REG_ADDR_MSW]; + sample_counter_msw_tmp = sample_counter_msw_tmp << 32; + sample_counter_tmp = sample_counter_tmp + sample_counter_msw_tmp; // 2^32 + //return d_map_base[d_SAMPLE_COUNTER_REG_ADDR]; + return sample_counter_tmp; +} + +void fpga_multicorrelator_8sc::set_initial_sample(uint64_t samples_offset) +{ + d_initial_sample_counter = samples_offset; + //printf("www writing d map base %d = d_initial_sample_counter = %d\n", d_INITIAL_COUNTER_VALUE_REG_ADDR, d_initial_sample_counter); + d_map_base[d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW] = (d_initial_sample_counter & 0xFFFFFFFF); + d_map_base[d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW] = (d_initial_sample_counter >> 32) & 0xFFFFFFFF; +} + +//void fpga_multicorrelator_8sc::set_local_code_and_taps(int32_t code_length_chips, +// float *shifts_chips, int32_t PRN) + +void fpga_multicorrelator_8sc::set_local_code_and_taps(float *shifts_chips, float *prompt_data_shift, int32_t PRN) +{ + d_shifts_chips = shifts_chips; + d_prompt_data_shift = prompt_data_shift; + //d_code_length_chips = code_length_chips; + fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(PRN); +} + +void fpga_multicorrelator_8sc::set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data) +{ + d_corr_out = corr_out; + d_Prompt_Data = Prompt_Data; +} + +void fpga_multicorrelator_8sc::update_local_code(float rem_code_phase_chips) +{ + d_rem_code_phase_chips = rem_code_phase_chips; + //printf("uuuuu d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); + fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(); + fpga_multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(); +} + + +void fpga_multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( + float rem_carrier_phase_in_rad, float phase_step_rad, + float rem_code_phase_chips, float code_phase_step_chips, + int32_t signal_length_samples) +{ + update_local_code(rem_code_phase_chips); + d_rem_carrier_phase_in_rad = rem_carrier_phase_in_rad; + d_code_phase_step_chips = code_phase_step_chips; + d_phase_step_rad = phase_step_rad; + d_correlator_length_samples = signal_length_samples; + fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(); + fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(); + fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(); + int32_t irq_count; + ssize_t nb; + //printf("$$$$$ waiting for interrupt ... \n"); + nb = read(d_device_descriptor, &irq_count, sizeof(irq_count)); + //printf("$$$$$ interrupt received ... \n"); + if (nb != sizeof(irq_count)) + { + printf("Tracking_module Read failed to retrieve 4 bytes!\n"); + printf("Tracking_module Interrupt number %d\n", irq_count); + } + fpga_multicorrelator_8sc::read_tracking_gps_results(); +} + +fpga_multicorrelator_8sc::fpga_multicorrelator_8sc(int32_t n_correlators, + std::string device_name, uint32_t device_base, int32_t *ca_codes, int32_t *data_codes, uint32_t code_length_chips, bool track_pilot, + uint32_t multicorr_type, uint32_t code_samples_per_chip) +{ + //printf("tracking fpga class created\n"); + d_n_correlators = n_correlators; + d_device_name = std::move(device_name); + d_device_base = device_base; + d_track_pilot = track_pilot; + d_device_descriptor = 0; + d_map_base = nullptr; + + // instantiate variable length vectors + if (d_track_pilot) + { + d_initial_index = static_cast(volk_gnsssdr_malloc( + (n_correlators + 1) * sizeof(uint32_t), volk_gnsssdr_get_alignment())); + d_initial_interp_counter = static_cast(volk_gnsssdr_malloc( + (n_correlators + 1) * sizeof(uint32_t), volk_gnsssdr_get_alignment())); + } + else + { + d_initial_index = static_cast(volk_gnsssdr_malloc( + n_correlators * sizeof(uint32_t), volk_gnsssdr_get_alignment())); + d_initial_interp_counter = static_cast(volk_gnsssdr_malloc( + n_correlators * sizeof(uint32_t), volk_gnsssdr_get_alignment())); + } + d_shifts_chips = nullptr; + d_prompt_data_shift = nullptr; + d_corr_out = nullptr; + d_code_length_chips = 0; + d_rem_code_phase_chips = 0; + d_code_phase_step_chips = 0; + d_rem_carrier_phase_in_rad = 0; + d_phase_step_rad = 0; + d_rem_carr_phase_rad_int = 0; + d_phase_step_rad_int = 0; + d_initial_sample_counter = 0; + d_channel = 0; + d_correlator_length_samples = 0, + //d_code_length = code_length; + d_code_length_chips = code_length_chips; + d_ca_codes = ca_codes; + d_data_codes = data_codes; + d_multicorr_type = multicorr_type; + + d_code_samples_per_chip = code_samples_per_chip; + // set up register mapping + + // write-only registers + d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR = 0; + d_INITIAL_INDEX_REG_BASE_ADDR = 1; + // if (d_multicorr_type == 0) + // { + // // multicorrelator with 3 correlators (16 registers only) + // d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR = 4; + // d_NSAMPLES_MINUS_1_REG_ADDR = 7; + // d_CODE_LENGTH_MINUS_1_REG_ADDR = 8; + // d_REM_CARR_PHASE_RAD_REG_ADDR = 9; + // d_PHASE_STEP_RAD_REG_ADDR = 10; + // d_PROG_MEMS_ADDR = 11; + // d_DROP_SAMPLES_REG_ADDR = 12; + // d_INITIAL_COUNTER_VALUE_REG_ADDR = 13; + // d_START_FLAG_ADDR = 14; + // } + // else + // { + // other types of multicorrelators (32 registers) + d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR = 7; + d_NSAMPLES_MINUS_1_REG_ADDR = 13; + d_CODE_LENGTH_MINUS_1_REG_ADDR = 14; + d_REM_CARR_PHASE_RAD_REG_ADDR = 15; + d_PHASE_STEP_RAD_REG_ADDR = 16; + d_PROG_MEMS_ADDR = 17; + d_DROP_SAMPLES_REG_ADDR = 18; + d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW = 19; + d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW = 20; + d_START_FLAG_ADDR = 30; + // } + + //printf("d_n_correlators = %d\n", d_n_correlators); + //printf("d_multicorr_type = %d\n", d_multicorr_type); + // read-write registers + // if (d_multicorr_type == 0) + // { + // // multicorrelator with 3 correlators (16 registers only) + // d_TEST_REG_ADDR = 15; + // } + // else + // { + // other types of multicorrelators (32 registers) + d_TEST_REG_ADDR = 31; + // } + + // result 2's complement saturation value + // if (d_multicorr_type == 0) + // { + // // multicorrelator with 3 correlators (16 registers only) + // d_result_SAT_value = 1048576; // 21 bits 2's complement -> 2^20 + // } + // else + // { + // // other types of multicorrelators (32 registers) + // d_result_SAT_value = 4194304; // 23 bits 2's complement -> 2^22 + // } + + // read only registers + d_RESULT_REG_REAL_BASE_ADDR = 1; + // if (d_multicorr_type == 0) + // { + // // multicorrelator with 3 correlators (16 registers only) + // d_RESULT_REG_IMAG_BASE_ADDR = 4; + // d_RESULT_REG_DATA_REAL_BASE_ADDR = 0; // no pilot tracking + // d_RESULT_REG_DATA_IMAG_BASE_ADDR = 0; + // d_SAMPLE_COUNTER_REG_ADDR = 7; + // + // } + // else + // { + // other types of multicorrelators (32 registers) + d_RESULT_REG_IMAG_BASE_ADDR = 7; + d_RESULT_REG_DATA_REAL_BASE_ADDR = 6; // no pilot tracking + d_RESULT_REG_DATA_IMAG_BASE_ADDR = 12; + d_SAMPLE_COUNTER_REG_ADDR_LSW = 13; + d_SAMPLE_COUNTER_REG_ADDR_MSW = 14; + + // } + + //printf("d_SAMPLE_COUNTER_REG_ADDR = %d\n", d_SAMPLE_COUNTER_REG_ADDR); + //printf("mmmmmmmmmmmmm d_n_correlators = %d\n", d_n_correlators); + DLOG(INFO) << "TRACKING FPGA CLASS CREATED"; +} + + +fpga_multicorrelator_8sc::~fpga_multicorrelator_8sc() +{ + //delete[] d_ca_codes; + close_device(); +} + + +bool fpga_multicorrelator_8sc::free() +{ + // unlock the channel + fpga_multicorrelator_8sc::unlock_channel(); + + // free the FPGA dynamically created variables + if (d_initial_index != nullptr) + { + volk_gnsssdr_free(d_initial_index); + d_initial_index = nullptr; + } + + if (d_initial_interp_counter != nullptr) + { + volk_gnsssdr_free(d_initial_interp_counter); + d_initial_interp_counter = nullptr; + } + + return true; +} + + +void fpga_multicorrelator_8sc::set_channel(uint32_t channel) +{ + //printf("www trk set channel\n"); + char device_io_name[MAX_LENGTH_DEVICEIO_NAME]; // driver io name + d_channel = channel; + + // open the device corresponding to the assigned channel + std::string mergedname; + std::stringstream devicebasetemp; + int32_t numdevice = d_device_base + d_channel; + devicebasetemp << numdevice; + mergedname = d_device_name + devicebasetemp.str(); + strcpy(device_io_name, mergedname.c_str()); + + //printf("ppps opening device %s\n", device_io_name); + + if ((d_device_descriptor = open(device_io_name, O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_io_name; + std::cout << "Cannot open deviceio" << device_io_name << std::endl; + + //printf("error opening device\n"); + } + // else + // { + // std::cout << "deviceio" << device_io_name << " opened successfully" << std::endl; + // + // } + d_map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); + + if (d_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA tracking module " + << d_channel << "into user memory"; + std::cout << "Cannot map deviceio" << device_io_name << std::endl; + //printf("error mapping registers\n"); + } + // else + // { + // std::cout << "deviceio" << device_io_name << "mapped successfully" << std::endl; + // } + // else + // { + // printf("trk mapping registers succes\n"); // this is for debug -- remove ! + // } + + // sanity check : check test register + uint32_t writeval = TEST_REGISTER_TRACK_WRITEVAL; + uint32_t readval; + readval = fpga_multicorrelator_8sc::fpga_acquisition_test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Test register sanity check failed"; + printf("tracking test register sanity check failed\n"); + + //printf("lslslls test sanity check reg failure\n"); + } + else + { + LOG(INFO) << "Test register sanity check success !"; + //printf("tracking test register sanity check success\n"); + //printf("lslslls test sanity check reg success\n"); + } +} + + +uint32_t fpga_multicorrelator_8sc::fpga_acquisition_test_register( + uint32_t writeval) +{ + //printf("d_TEST_REG_ADDR = %d\n", d_TEST_REG_ADDR); + + uint32_t readval = 0; + // write value to test register + d_map_base[d_TEST_REG_ADDR] = writeval; + // read value from test register + readval = d_map_base[d_TEST_REG_ADDR]; + // return read value + return readval; +} + + +void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PRN) +{ + uint32_t k; + uint32_t code_chip; + uint32_t select_pilot_corelator = LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT; + // select_fpga_correlator = 0; + + //printf("kkk d_n_correlators = %x\n", d_n_correlators); + //printf("kkk d_code_length_chips = %d\n", d_code_length_chips); + //printf("programming mems d map base %d\n", d_PROG_MEMS_ADDR); + + //FILE *fp; + //char str[80]; + //sprintf(str, "generated_code_PRN%d", PRN); + //fp = fopen(str,"w"); + // for (s = 0; s < d_n_correlators; s++) + // { + + //printf("kkk select_fpga_correlator = %x\n", select_fpga_correlator); + + d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; + for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++) + { + //if (d_local_code_in[k] == 1) + //printf("kkk d_ca_codes %d = %d\n", k, d_ca_codes[((int(d_code_length)) * (PRN - 1)) + k]); + //fprintf(fp, "%d\n", d_ca_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k]); + if (d_ca_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) + { + code_chip = 1; + } + else + { + code_chip = 0; + } + + // copy the local code to the FPGA memory one by one + d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip; // | select_fpga_correlator; + } + // select_fpga_correlator = select_fpga_correlator + // + LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT; + // } + //fclose(fp); + //printf("kkk d_track_pilot = %d\n", d_track_pilot); + if (d_track_pilot) + { + //printf("kkk select_fpga_correlator = %x\n", select_fpga_correlator); + + d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; + for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++) + { + //if (d_local_code_in[k] == 1) + if (d_data_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) + { + code_chip = 1; + } + else + { + code_chip = 0; + } + //printf("%d %d | ", d_data_codes, code_chip); + // copy the local code to the FPGA memory one by one + d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip | select_pilot_corelator; + } + } + //printf("\n"); +} + + +void fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(void) +{ + float temp_calculation; + int32_t i; + + //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); + for (i = 0; i < d_n_correlators; i++) + { + //printf("ppp d_shifts_chips %d = %f\n", i, d_shifts_chips[i]); + //printf("ppp d_code_samples_per_chip = %d\n", d_code_samples_per_chip); + temp_calculation = floor( + d_shifts_chips[i] - d_rem_code_phase_chips); + + //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); + //printf("ppp temp calculation %d = %f ================================ \n", i, temp_calculation); + if (temp_calculation < 0) + { + temp_calculation = temp_calculation + (d_code_length_chips * d_code_samples_per_chip); // % operator does not work as in Matlab with negative numbers + } + //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); + //printf("ppp temp calculation %d = %f ================================ \n", i, temp_calculation); + d_initial_index[i] = static_cast((static_cast(temp_calculation)) % (d_code_length_chips * d_code_samples_per_chip)); + //printf("ppp d_initial_index %d = %d\n", i, d_initial_index[i]); + temp_calculation = fmod(d_shifts_chips[i] - d_rem_code_phase_chips, + 1.0); + //printf("ppp fmod %d = fmod(%f, 1) = %f\n", i, d_shifts_chips[i] - d_rem_code_phase_chips, temp_calculation); + if (temp_calculation < 0) + { + temp_calculation = temp_calculation + 1.0; // fmod operator does not work as in Matlab with negative numbers + } + + d_initial_interp_counter[i] = static_cast(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation)); + //printf("ppp d_initial_interp_counter %d = %d\n", i, d_initial_interp_counter[i]); + //printf("MAX_CODE_RESAMPLER_COUNTER = %d\n", MAX_CODE_RESAMPLER_COUNTER); + } + if (d_track_pilot) + { + //printf("tracking pilot !!!!!!!!!!!!!!!!\n"); + temp_calculation = floor( + d_prompt_data_shift[0] - d_rem_code_phase_chips); + + if (temp_calculation < 0) + { + temp_calculation = temp_calculation + (d_code_length_chips * d_code_samples_per_chip); // % operator does not work as in Matlab with negative numbers + } + d_initial_index[d_n_correlators] = static_cast((static_cast(temp_calculation)) % (d_code_length_chips * d_code_samples_per_chip)); + temp_calculation = fmod(d_prompt_data_shift[0] - d_rem_code_phase_chips, + 1.0); + if (temp_calculation < 0) + { + temp_calculation = temp_calculation + 1.0; // fmod operator does not work as in Matlab with negative numbers + } + d_initial_interp_counter[d_n_correlators] = static_cast(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation)); + } + //while(1); +} + + +void fpga_multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(void) +{ + int32_t i; + for (i = 0; i < d_n_correlators; i++) + { + //printf("www writing d map base %d = d_initial_index %d = %d\n", d_INITIAL_INDEX_REG_BASE_ADDR + i, i, d_initial_index[i]); + d_map_base[d_INITIAL_INDEX_REG_BASE_ADDR + i] = d_initial_index[i]; + //d_map_base[1 + d_n_correlators + i] = d_initial_interp_counter[i]; + //printf("www writing d map base %d = d_initial_interp_counter %d = %d\n", d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i, i, d_initial_interp_counter[i]); + d_map_base[d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i] = d_initial_interp_counter[i]; + } + if (d_track_pilot) + { + //printf("www writing d map base %d = d_initial_index %d = %d\n", d_INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators, d_n_correlators, d_initial_index[d_n_correlators]); + d_map_base[d_INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators] = d_initial_index[d_n_correlators]; + //d_map_base[1 + d_n_correlators + i] = d_initial_interp_counter[i]; + //printf("www writing d map base %d = d_initial_interp_counter %d = %d\n", d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators, d_n_correlators, d_initial_interp_counter[d_n_correlators]); + d_map_base[d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators] = d_initial_interp_counter[d_n_correlators]; + } + + //printf("www writing d map base %d = d_code_length_chips*d_code_samples_per_chip - 1 = %d\n", d_CODE_LENGTH_MINUS_1_REG_ADDR, (d_code_length_chips*d_code_samples_per_chip) - 1); + d_map_base[d_CODE_LENGTH_MINUS_1_REG_ADDR] = (d_code_length_chips * d_code_samples_per_chip) - 1; // number of samples - 1 +} + + +void fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) +{ + float d_rem_carrier_phase_in_rad_temp; + + d_code_phase_step_chips_num = static_cast(roundf(MAX_CODE_RESAMPLER_COUNTER * d_code_phase_step_chips)); + if (d_code_phase_step_chips > 1.0) + { + printf("Warning : d_code_phase_step_chips = %f cannot be bigger than one\n", d_code_phase_step_chips); + } + + //printf("d_rem_carrier_phase_in_rad = %f\n", d_rem_carrier_phase_in_rad); + + if (d_rem_carrier_phase_in_rad > M_PI) + { + d_rem_carrier_phase_in_rad_temp = -2 * M_PI + d_rem_carrier_phase_in_rad; + } + else if (d_rem_carrier_phase_in_rad < -M_PI) + { + d_rem_carrier_phase_in_rad_temp = 2 * M_PI + d_rem_carrier_phase_in_rad; + } + else + { + d_rem_carrier_phase_in_rad_temp = d_rem_carrier_phase_in_rad; + } + d_rem_carr_phase_rad_int = static_cast(roundf( + (fabs(d_rem_carrier_phase_in_rad_temp) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC))); + if (d_rem_carrier_phase_in_rad_temp < 0) + { + d_rem_carr_phase_rad_int = -d_rem_carr_phase_rad_int; + } + d_phase_step_rad_int = static_cast(roundf( + (fabs(d_phase_step_rad) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC))); // the FPGA accepts a range for the phase step between -pi and +pi + + //printf("d_phase_step_rad_int = %d\n", d_phase_step_rad_int); + if (d_phase_step_rad < 0) + { + d_phase_step_rad_int = -d_phase_step_rad_int; + } + + //printf("d_phase_step_rad_int = %d\n", d_phase_step_rad_int); +} + + +void fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(void) +{ + //printf("www d map base %d = d_code_phase_step_chips_num = %d\n", d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR, d_code_phase_step_chips_num); + d_map_base[d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR] = d_code_phase_step_chips_num; + + //printf("www d map base %d = d_correlator_length_samples - 1 = %d\n", d_NSAMPLES_MINUS_1_REG_ADDR, d_correlator_length_samples - 1); + d_map_base[d_NSAMPLES_MINUS_1_REG_ADDR] = d_correlator_length_samples - 1; + + //printf("www d map base %d = d_rem_carr_phase_rad_int = %d\n", d_REM_CARR_PHASE_RAD_REG_ADDR, d_rem_carr_phase_rad_int); + d_map_base[d_REM_CARR_PHASE_RAD_REG_ADDR] = d_rem_carr_phase_rad_int; + + //printf("www d map base %d = d_phase_step_rad_int = %d\n", d_PHASE_STEP_RAD_REG_ADDR, d_phase_step_rad_int); + d_map_base[d_PHASE_STEP_RAD_REG_ADDR] = d_phase_step_rad_int; +} + + +void fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(void) +{ + // enable interrupts + int32_t reenable = 1; + write(d_device_descriptor, reinterpret_cast(&reenable), sizeof(int32_t)); + + // writing 1 to reg 14 launches the tracking + //printf("www writing 1 to d map base %d = start flag\n", d_START_FLAG_ADDR); + d_map_base[d_START_FLAG_ADDR] = 1; + //while(1); +} + + +void fpga_multicorrelator_8sc::read_tracking_gps_results(void) +{ + int32_t readval_real; + int32_t readval_imag; + int32_t k; + + //printf("www reading trk results\n"); + for (k = 0; k < d_n_correlators; k++) + { + readval_real = d_map_base[d_RESULT_REG_REAL_BASE_ADDR + k]; + //printf("read real before checking d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_real); + //// if (readval_real > debug_max_readval_real[k]) + //// { + //// debug_max_readval_real[k] = readval_real; + //// } + // if (readval_real >= d_result_SAT_value) // 0x100000 (21 bits two's complement) + // { + // readval_real = -2*d_result_SAT_value + readval_real; + // } + //// if (readval_real > debug_max_readval_real_after_check[k]) + //// { + //// debug_max_readval_real_after_check[k] = readval_real; + //// } + //printf("read real d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_real); + readval_imag = d_map_base[d_RESULT_REG_IMAG_BASE_ADDR + k]; + //printf("read imag before checking d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_imag); + //// if (readval_imag > debug_max_readval_imag[k]) + //// { + //// debug_max_readval_imag[k] = readval_imag; + //// } + // + // if (readval_imag >= d_result_SAT_value) // 0x100000 (21 bits two's complement) + // { + // readval_imag = -2*d_result_SAT_value + readval_imag; + // } + //// if (readval_imag > debug_max_readval_imag_after_check[k]) + //// { + //// debug_max_readval_imag_after_check[k] = readval_real; + //// } + //printf("read imag d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_imag); + d_corr_out[k] = gr_complex(readval_real, readval_imag); + + // if (printcounter > 100) + // { + // printcounter = 0; + // for (int32_t ll=0;ll= d_result_SAT_value) // 0x100000 (21 bits two's complement) + // { + // readval_real = -2*d_result_SAT_value + readval_real; + // } + + readval_imag = d_map_base[d_RESULT_REG_DATA_IMAG_BASE_ADDR]; + // if (readval_imag >= d_result_SAT_value) // 0x100000 (21 bits two's complement) + // { + // readval_imag = -2*d_result_SAT_value + readval_imag; + // } + d_Prompt_Data[0] = gr_complex(readval_real, readval_imag); + } +} + + +void fpga_multicorrelator_8sc::unlock_channel(void) +{ + // unlock the channel to let the next samples go through + //printf("www writing 1 to d map base %d = drop samples\n", d_DROP_SAMPLES_REG_ADDR); + d_map_base[d_DROP_SAMPLES_REG_ADDR] = 1; // unlock the channel +} + +void fpga_multicorrelator_8sc::close_device() +{ + auto *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + close(d_device_descriptor); +} + + +void fpga_multicorrelator_8sc::lock_channel(void) +{ + // lock the channel for processing + //printf("www writing 0 to d map base %d = drop samples\n", d_DROP_SAMPLES_REG_ADDR); + d_map_base[d_DROP_SAMPLES_REG_ADDR] = 0; // lock the channel +} + +//void fpga_multicorrelator_8sc::read_sample_counters(int32_t *sample_counter, int32_t *secondary_sample_counter, int32_t *counter_corr_0_in, int32_t *counter_corr_0_out) +//{ +// *sample_counter = d_map_base[11]; +// *secondary_sample_counter = d_map_base[8]; +// *counter_corr_0_in = d_map_base[10]; +// *counter_corr_0_out = d_map_base[9]; +// +//} + +//void fpga_multicorrelator_8sc::reset_multicorrelator(void) +//{ +// d_map_base[14] = 2; // writing a 2 to d_map_base[14] resets the multicorrelator +//} diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.h b/src/algorithms/tracking/libs/fpga_multicorrelator.h new file mode 100644 index 000000000..f7fffe1aa --- /dev/null +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.h @@ -0,0 +1,169 @@ +/*! + * \file fpga_multicorrelator_8sc.h + * \brief High optimized FPGA vector correlator class for lv_16sc_t (short int32_t complex) + * \authors
        + *
      • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
      • Javier Arribas, 2016. jarribas(at)cttc.es + *
      + * + * Class that controls and executes a high optimized vector correlator + * class in the FPGA + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FPGA_MULTICORRELATOR_8SC_H_ +#define GNSS_SDR_FPGA_MULTICORRELATOR_8SC_H_ + +#include +#include +#include + +#define MAX_LENGTH_DEVICEIO_NAME 50 + +/*! + * \brief Class that implements carrier wipe-off and correlators. + */ +class fpga_multicorrelator_8sc +{ +public: + fpga_multicorrelator_8sc(int32_t n_correlators, std::string device_name, + uint32_t device_base, int32_t *ca_codes, int32_t *data_codes, uint32_t code_length_chips, bool track_pilot, uint32_t multicorr_type, uint32_t code_samples_per_chip); + ~fpga_multicorrelator_8sc(); + //bool set_output_vectors(gr_complex* corr_out); + void set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data); + // bool set_local_code_and_taps( + // int32_t code_length_chips, const int* local_code_in, + // float *shifts_chips, int32_t PRN); + //bool set_local_code_and_taps( + void set_local_code_and_taps( + // int32_t code_length_chips, + float *shifts_chips, float *prompt_data_shift, int32_t PRN); + //bool set_output_vectors(lv_16sc_t* corr_out); + void update_local_code(float rem_code_phase_chips); + //bool Carrier_wipeoff_multicorrelator_resampler( + void Carrier_wipeoff_multicorrelator_resampler( + float rem_carrier_phase_in_rad, float phase_step_rad, + float rem_code_phase_chips, float code_phase_step_chips, + int32_t signal_length_samples); + bool free(); + void set_channel(uint32_t channel); + void set_initial_sample(uint64_t samples_offset); + uint64_t read_sample_counter(); + void lock_channel(void); + void unlock_channel(void); + //void read_sample_counters(int32_t *sample_counter, int32_t *secondary_sample_counter, int32_t *counter_corr_0_in, int32_t *counter_corr_0_out); // debug + +private: + //const int32_t *d_local_code_in; + gr_complex *d_corr_out; + gr_complex *d_Prompt_Data; + float *d_shifts_chips; + float *d_prompt_data_shift; + int32_t d_code_length_chips; + int32_t d_n_correlators; + + // data related to the hardware module and the driver + int32_t d_device_descriptor; // driver descriptor + volatile uint32_t *d_map_base; // driver memory map + + // configuration data received from the interface + uint32_t d_channel; // channel number + uint32_t d_ncorrelators; // number of correlators + uint32_t d_correlator_length_samples; + float d_rem_code_phase_chips; + float d_code_phase_step_chips; + float d_rem_carrier_phase_in_rad; + float d_phase_step_rad; + + // configuration data computed in the format that the FPGA expects + uint32_t *d_initial_index; + uint32_t *d_initial_interp_counter; + uint32_t d_code_phase_step_chips_num; + int32_t d_rem_carr_phase_rad_int; + int32_t d_phase_step_rad_int; + uint64_t d_initial_sample_counter; + + // driver + std::string d_device_name; + uint32_t d_device_base; + + int32_t *d_ca_codes; + int32_t *d_data_codes; + + //uint32_t d_code_length; // nominal number of chips + + uint32_t d_code_samples_per_chip; + bool d_track_pilot; + + uint32_t d_multicorr_type; + + // register addresses + // write-only regs + uint32_t d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR; + uint32_t d_INITIAL_INDEX_REG_BASE_ADDR; + uint32_t d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR; + uint32_t d_NSAMPLES_MINUS_1_REG_ADDR; + uint32_t d_CODE_LENGTH_MINUS_1_REG_ADDR; + uint32_t d_REM_CARR_PHASE_RAD_REG_ADDR; + uint32_t d_PHASE_STEP_RAD_REG_ADDR; + uint32_t d_PROG_MEMS_ADDR; + uint32_t d_DROP_SAMPLES_REG_ADDR; + uint32_t d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW; + uint32_t d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW; + uint32_t d_START_FLAG_ADDR; + // read-write regs + uint32_t d_TEST_REG_ADDR; + // read-only regs + uint32_t d_RESULT_REG_REAL_BASE_ADDR; + uint32_t d_RESULT_REG_IMAG_BASE_ADDR; + uint32_t d_RESULT_REG_DATA_REAL_BASE_ADDR; + uint32_t d_RESULT_REG_DATA_IMAG_BASE_ADDR; + uint32_t d_SAMPLE_COUNTER_REG_ADDR_LSW; + uint32_t d_SAMPLE_COUNTER_REG_ADDR_MSW; + + // private functions + uint32_t fpga_acquisition_test_register(uint32_t writeval); + void fpga_configure_tracking_gps_local_code(int32_t PRN); + void fpga_compute_code_shift_parameters(void); + void fpga_configure_code_parameters_in_fpga(void); + void fpga_compute_signal_parameters_in_fpga(void); + void fpga_configure_signal_parameters_in_fpga(void); + void fpga_launch_multicorrelator_fpga(void); + void read_tracking_gps_results(void); + //void reset_multicorrelator(void); + void close_device(void); + + uint32_t d_result_SAT_value; + + int32_t debug_max_readval_real[5] = {0, 0, 0, 0, 0}; + int32_t debug_max_readval_imag[5] = {0, 0, 0, 0, 0}; + + int32_t debug_max_readval_real_after_check[5] = {0, 0, 0, 0, 0}; + int32_t debug_max_readval_imag_after_check[5] = {0, 0, 0, 0, 0}; + int32_t printcounter = 0; +}; + +#endif /* GNSS_SDR_FPGA_MULTICORRELATOR_H_ */ diff --git a/src/algorithms/tracking/libs/lock_detectors.cc b/src/algorithms/tracking/libs/lock_detectors.cc index bbe2f7214..b66e3a15d 100644 --- a/src/algorithms/tracking/libs/lock_detectors.cc +++ b/src/algorithms/tracking/libs/lock_detectors.cc @@ -23,7 +23,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -41,7 +41,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -58,30 +58,29 @@ * \f$\hat{P}_{tot}=\frac{1}{N}\sum^{N-1}_{i=0}|Pc(i)|^2\f$ is the estimator of the total power, \f$|\cdot|\f$ is the absolute value, * \f$Re(\cdot)\f$ stands for the real part of the value, and \f$Pc(i)\f$ is the prompt correlator output for the sample index i. * - * The SNR value is converted to CN0 [dB-Hz], taking to account the receiver bandwidth and the PRN code gain, using the following formula: + * The SNR value is converted to CN0 [dB-Hz], taking to account the coherent integration time, using the following formula: * \f{equation} - * CN0_{dB}=10*log(\hat{\rho})+10*log(\frac{f_s}{2})-10*log(L_{PRN}), + * CN0_{dB}=10*log(\hat{\rho})-10*log(T_{int}), * \f} - * where \f$f_s\f$ is the sampling frequency and \f$L_{PRN}\f$ is the PRN sequence length. + * where \f$T_{int}\f$ is the coherent integration time, in seconds. * */ -float cn0_svn_estimator(gr_complex* Prompt_buffer, int length, long fs_in, double code_length) +float cn0_svn_estimator(const gr_complex* Prompt_buffer, int length, double coh_integration_time_s) { - double SNR = 0; - double SNR_dB_Hz = 0; - double Psig = 0; - double Ptot = 0; - for (int i=0; i(Prompt_buffer[i].real())); - Ptot += static_cast(Prompt_buffer[i].imag()) * static_cast(Prompt_buffer[i].imag()) - + static_cast(Prompt_buffer[i].real()) * static_cast(Prompt_buffer[i].real()); + Ptot += static_cast(Prompt_buffer[i].imag()) * static_cast(Prompt_buffer[i].imag()) + static_cast(Prompt_buffer[i].real()) * static_cast(Prompt_buffer[i].real()); } - Psig = Psig / static_cast(length); + Psig /= static_cast(length); Psig = Psig * Psig; - Ptot = Ptot / static_cast(length); + Ptot /= static_cast(length); SNR = Psig / (Ptot - Psig); - SNR_dB_Hz = 10 * log10(SNR) + 10 * log10(static_cast(fs_in)/2) - 10 * log10(code_length); + SNR_dB_Hz = 10.0 * log10(SNR) - 10.0 * log10(coh_integration_time_s); return static_cast(SNR_dB_Hz); } @@ -97,16 +96,16 @@ float cn0_svn_estimator(gr_complex* Prompt_buffer, int length, long fs_in, doubl */ float carrier_lock_detector(gr_complex* Prompt_buffer, int length) { - float tmp_sum_I = 0; - float tmp_sum_Q = 0; - float NBD = 0; - float NBP = 0; - for (int i=0; i * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -40,7 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -62,18 +62,17 @@ * \f$\hat{P}_{tot}=\frac{1}{N}\sum^{N-1}_{i=0}|Pc(i)|^2\f$ is the estimator of the total power, \f$|\cdot|\f$ is the absolute value, * \f$Re(\cdot)\f$ stands for the real part of the value, and \f$Pc(i)\f$ is the prompt correlator output for the sample index i. * - * The SNR value is converted to CN0 [dB-Hz], taking to account the receiver bandwidth and the PRN code gain, using the following formula: + * The SNR value is converted to CN0 [dB-Hz], taking to account the coherent integration time, using the following formula: * \f{equation} - * CN0_{dB}=10*log(\hat{\rho})+10*log(\frac{f_s}{2})-10*log(L_{PRN}), + * CN0_{dB}=10*log(\hat{\rho})-10*log(2 * T_{int}), * \f} - * where \f$f_s\f$ is the sampling frequency and \f$L_{PRN}\f$ is the PRN sequence length. + * where \f$T_{int}\f$ is the coherent integration time, in seconds. * Ref: Marco Pini, Emanuela Falletti and Maurizio Fantino, "Performance * Evaluation of C/N0 Estimators using a Real Time GNSS Software Receiver," * IEEE 10th International Symposium on Spread Spectrum Techniques and * Applications, pp.28-30, August 2008. */ -float cn0_svn_estimator(gr_complex* Prompt_buffer, int length, long fs_in, double code_length); - +float cn0_svn_estimator(const gr_complex* Prompt_buffer, int length, double coh_integration_time_s); /*! \brief A carrier lock detector diff --git a/src/algorithms/tracking/libs/tcp_communication.cc b/src/algorithms/tracking/libs/tcp_communication.cc index be9022f53..8ca6fde27 100644 --- a/src/algorithms/tracking/libs/tcp_communication.cc +++ b/src/algorithms/tracking/libs/tcp_communication.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,30 +24,27 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include "tcp_packet_data.h" #include "tcp_communication.h" +#include "tcp_packet_data.h" #include #include - -tcp_communication::tcp_communication() : tcp_socket_(io_service_) -{} +tcp_communication::tcp_communication() : tcp_socket_(io_service_) {} // NOLINT -tcp_communication::~tcp_communication() -{} +tcp_communication::~tcp_communication() = default; int tcp_communication::listen_tcp_connection(size_t d_port_, size_t d_port_ch0_) { try - { + { // Specify IP type and port boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), d_port_); boost::asio::ip::tcp::acceptor acceptor(io_service_, endpoint); @@ -65,25 +62,25 @@ int tcp_communication::listen_tcp_connection(size_t d_port_, size_t d_port_ch0_) acceptor.accept(tcp_socket_); std::cout << "Socket accepted on port " << d_port_ << std::endl; - } + } - catch(std::exception& e) - { + catch (const std::exception& e) + { std::cerr << "Exception: " << e.what() << std::endl; - } + } return false; } -void tcp_communication::send_receive_tcp_packet_galileo_e1(boost::array buf, tcp_packet_data *tcp_data_) +void tcp_communication::send_receive_tcp_packet_galileo_e1(boost::array buf, tcp_packet_data* tcp_data_) { int controlc = 0; boost::array readbuf; float d_control_id_ = buf.data()[0]; try - { + { // Send a TCP packet tcp_socket_.write_some(boost::asio::buffer(buf)); @@ -100,25 +97,25 @@ void tcp_communication::send_receive_tcp_packet_galileo_e1(boost::arrayproc_pack_code_error = readbuf.data()[1]; tcp_data_->proc_pack_carr_error = readbuf.data()[2]; tcp_data_->proc_pack_carrier_doppler_hz = readbuf.data()[3]; - } + } - catch(std::exception& e) - { + catch (const std::exception& e) + { std::cerr << "Exception: " << e.what() << ". Please press Ctrl+C to end the program." << std::endl; std::cin >> controlc; - } + } return; } -void tcp_communication::send_receive_tcp_packet_gps_l1_ca(boost::array buf, tcp_packet_data *tcp_data_) +void tcp_communication::send_receive_tcp_packet_gps_l1_ca(boost::array buf, tcp_packet_data* tcp_data_) { int controlc = 0; boost::array readbuf; float d_control_id_ = buf.data()[0]; try - { + { // Send a TCP packet tcp_socket_.write_some(boost::asio::buffer(buf)); @@ -135,13 +132,13 @@ void tcp_communication::send_receive_tcp_packet_gps_l1_ca(boost::arrayproc_pack_code_error = readbuf.data()[1]; tcp_data_->proc_pack_carr_error = readbuf.data()[2]; tcp_data_->proc_pack_carrier_doppler_hz = readbuf.data()[3]; - } + } - catch(std::exception& e) - { + catch (const std::exception& e) + { std::cerr << "Exception: " << e.what() << ". Please press Ctrl+C to end the program." << std::endl; std::cin >> controlc; - } + } return; } diff --git a/src/algorithms/tracking/libs/tcp_communication.h b/src/algorithms/tracking/libs/tcp_communication.h index 18133cbe8..1a36d8212 100644 --- a/src/algorithms/tracking/libs/tcp_communication.h +++ b/src/algorithms/tracking/libs/tcp_communication.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,9 @@ #ifndef GNSS_SDR_TCP_COMMUNICATION_H_ #define GNSS_SDR_TCP_COMMUNICATION_H_ -#include -#include #include "tcp_packet_data.h" +#include +#include #define NUM_TX_VARIABLES_GALILEO_E1 13 #define NUM_TX_VARIABLES_GPS_L1_CA 9 diff --git a/src/algorithms/tracking/libs/tcp_packet_data.cc b/src/algorithms/tracking/libs/tcp_packet_data.cc index 7f81c5cb5..eb53ff59b 100644 --- a/src/algorithms/tracking/libs/tcp_packet_data.cc +++ b/src/algorithms/tracking/libs/tcp_packet_data.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,4 +37,4 @@ tcp_packet_data::tcp_packet_data() proc_pack_carrier_doppler_hz = 0; } -tcp_packet_data::~tcp_packet_data() {} +tcp_packet_data::~tcp_packet_data() = default; diff --git a/src/algorithms/tracking/libs/tcp_packet_data.h b/src/algorithms/tracking/libs/tcp_packet_data.h index 7dcfc7007..c803fa936 100644 --- a/src/algorithms/tracking/libs/tcp_packet_data.h +++ b/src/algorithms/tracking/libs/tcp_packet_data.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.cc b/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.cc index 9c44a756f..01b8641ea 100644 --- a/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.cc +++ b/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,62 +38,59 @@ #include "tracking_2nd_DLL_filter.h" -void Tracking_2nd_DLL_filter::calculate_lopp_coef(float* tau1,float* tau2, float lbw, float zeta, float k) +void Tracking_2nd_DLL_filter::calculate_lopp_coef(float* tau1, float* tau2, float lbw, float zeta, float k) { // Solve natural frequency - float Wn; - Wn = lbw*8*zeta / (4*zeta*zeta + 1); + float Wn = lbw * 8.0 * zeta / (4.0 * zeta * zeta + 1.0); // solve for t1 & t2 *tau1 = k / (Wn * Wn); - *tau2 = (2.0 * zeta) / Wn; + *tau2 = 2.0 * zeta / Wn; } - void Tracking_2nd_DLL_filter::set_DLL_BW(float dll_bw_hz) { //Calculate filter coefficient values - d_dllnoisebandwidth = dll_bw_hz; - calculate_lopp_coef(&d_tau1_code, &d_tau2_code, d_dllnoisebandwidth, d_dlldampingratio, 1.0);// Calculate filter coefficient values + d_dllnoisebandwidth = dll_bw_hz; + calculate_lopp_coef(&d_tau1_code, &d_tau2_code, d_dllnoisebandwidth, d_dlldampingratio, 1.0); // Calculate filter coefficient values } - void Tracking_2nd_DLL_filter::initialize() { // code tracking loop parameters - d_old_code_nco = 0.0; + d_old_code_nco = 0.0; d_old_code_error = 0.0; } - float Tracking_2nd_DLL_filter::get_code_nco(float DLL_discriminator) { - float code_nco; - code_nco = d_old_code_nco + (d_tau2_code/d_tau1_code)*(DLL_discriminator - d_old_code_error) + (DLL_discriminator+d_old_code_error) * (d_pdi_code/(2*d_tau1_code)); - //code_nco = d_old_code_nco + (d_tau2_code/d_tau1_code)*(DLL_discriminator - d_old_code_error) + DLL_discriminator * (d_pdi_code/d_tau1_code); - d_old_code_nco = code_nco; - d_old_code_error = DLL_discriminator; //[chips] + float code_nco = d_old_code_nco + (d_tau2_code / d_tau1_code) * (DLL_discriminator - d_old_code_error) + (DLL_discriminator + d_old_code_error) * (d_pdi_code / (2.0 * d_tau1_code)); + d_old_code_nco = code_nco; + d_old_code_error = DLL_discriminator; //[chips] return code_nco; } -Tracking_2nd_DLL_filter::Tracking_2nd_DLL_filter (float pdi_code) + +Tracking_2nd_DLL_filter::Tracking_2nd_DLL_filter(float pdi_code) { - d_pdi_code = pdi_code;// Summation interval for code + d_pdi_code = pdi_code; // Summation interval for code d_dlldampingratio = 0.7; } -Tracking_2nd_DLL_filter::Tracking_2nd_DLL_filter () + +Tracking_2nd_DLL_filter::Tracking_2nd_DLL_filter() { - d_pdi_code = 0.001;// Summation interval for code + d_pdi_code = 0.001; // Summation interval for code d_dlldampingratio = 0.7; } -Tracking_2nd_DLL_filter::~Tracking_2nd_DLL_filter () -{} + +Tracking_2nd_DLL_filter::~Tracking_2nd_DLL_filter() = default; + void Tracking_2nd_DLL_filter::set_pdi(float pdi_code) { - d_pdi_code = pdi_code; // Summation interval for code + d_pdi_code = pdi_code; // Summation interval for code } diff --git a/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.h b/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.h index f39a88919..446cecfd8 100644 --- a/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.h +++ b/src/algorithms/tracking/libs/tracking_2nd_DLL_filter.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,20 +49,20 @@ class Tracking_2nd_DLL_filter { private: // PLL filter parameters - float d_tau1_code = 0; - float d_tau2_code = 0; - float d_pdi_code = 0; - float d_dllnoisebandwidth = 0; - float d_dlldampingratio = 0; - float d_old_code_error = 0; - float d_old_code_nco = 0; - void calculate_lopp_coef(float* tau1,float* tau2, float lbw, float zeta, float k); + float d_tau1_code = 0.0; + float d_tau2_code = 0.0; + float d_pdi_code = 0.0; + float d_dllnoisebandwidth = 0.0; + float d_dlldampingratio = 0.0; + float d_old_code_error = 0.0; + float d_old_code_nco = 0.0; + void calculate_lopp_coef(float* tau1, float* tau2, float lbw, float zeta, float k); public: - void set_DLL_BW(float dll_bw_hz); //! Set DLL filter bandwidth [Hz] - void set_pdi(float pdi_code); //! Set Summation interval for code [s] - void initialize(); //! Start tracking with acquisition information - float get_code_nco(float DLL_discriminator); //! Numerically controlled oscillator + void set_DLL_BW(float dll_bw_hz); //! Set DLL filter bandwidth [Hz] + void set_pdi(float pdi_code); //! Set Summation interval for code [s] + void initialize(); //! Start tracking with acquisition information + float get_code_nco(float DLL_discriminator); //! Numerically controlled oscillator Tracking_2nd_DLL_filter(float pdi_code); Tracking_2nd_DLL_filter(); ~Tracking_2nd_DLL_filter(); diff --git a/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.cc b/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.cc index 55a706a33..bf0b0841b 100644 --- a/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.cc +++ b/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,31 +37,28 @@ #include "tracking_2nd_PLL_filter.h" -void Tracking_2nd_PLL_filter::calculate_lopp_coef(float* tau1,float* tau2, float lbw, float zeta, float k) +void Tracking_2nd_PLL_filter::calculate_lopp_coef(float* tau1, float* tau2, float lbw, float zeta, float k) { // Solve natural frequency - float Wn; - Wn = lbw*8*zeta / (4*zeta*zeta + 1); + float Wn = lbw * 8.0 * zeta / (4.0 * zeta * zeta + 1.0); // solve for t1 & t2 *tau1 = k / (Wn * Wn); - *tau2 = (2.0 * zeta) / Wn; + *tau2 = 2.0 * zeta / Wn; } - void Tracking_2nd_PLL_filter::set_PLL_BW(float pll_bw_hz) { //Calculate filter coefficient values d_pllnoisebandwidth = pll_bw_hz; - calculate_lopp_coef(&d_tau1_carr, &d_tau2_carr, d_pllnoisebandwidth, d_plldampingratio, 0.25); // Calculate filter coefficient values + calculate_lopp_coef(&d_tau1_carr, &d_tau2_carr, d_pllnoisebandwidth, d_plldampingratio, 0.25); // Calculate filter coefficient values } - void Tracking_2nd_PLL_filter::initialize() { // carrier/Costas loop parameters - d_old_carr_nco = 0.0; + d_old_carr_nco = 0.0; d_old_carr_error = 0.0; } @@ -73,37 +70,35 @@ void Tracking_2nd_PLL_filter::initialize() */ float Tracking_2nd_PLL_filter::get_carrier_nco(float PLL_discriminator) { - float carr_nco; - carr_nco = d_old_carr_nco + (d_tau2_carr/d_tau1_carr)*(PLL_discriminator - d_old_carr_error) + (PLL_discriminator + d_old_carr_error) * (d_pdi_carr/(2*d_tau1_carr)); + float carr_nco = d_old_carr_nco + (d_tau2_carr / d_tau1_carr) * (PLL_discriminator - d_old_carr_error) + (PLL_discriminator + d_old_carr_error) * (d_pdi_carr / (2.0 * d_tau1_carr)); //carr_nco = d_old_carr_nco + (d_tau2_carr/d_tau1_carr)*(PLL_discriminator - d_old_carr_error) + PLL_discriminator * (d_pdi_carr/d_tau1_carr); - d_old_carr_nco = carr_nco; + d_old_carr_nco = carr_nco; d_old_carr_error = PLL_discriminator; return carr_nco; } -Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter (float pdi_carr) + +Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter(float pdi_carr) { //--- PLL variables -------------------------------------------------------- - d_pdi_carr = pdi_carr;// Summation interval for carrier + d_pdi_carr = pdi_carr; // Summation interval for carrier //d_plldampingratio = 0.65; d_plldampingratio = 0.7; } -Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter () +Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter() { //--- PLL variables -------------------------------------------------------- - d_pdi_carr = 0.001;// Summation interval for carrier + d_pdi_carr = 0.001; // Summation interval for carrier d_plldampingratio = 0.7; } +Tracking_2nd_PLL_filter::~Tracking_2nd_PLL_filter() = default; -Tracking_2nd_PLL_filter::~Tracking_2nd_PLL_filter () -{} - void Tracking_2nd_PLL_filter::set_pdi(float pdi_carr) { - d_pdi_carr = pdi_carr; // Summation interval for code + d_pdi_carr = pdi_carr; // Summation interval for code } diff --git a/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.h b/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.h index 4a774ce65..9a1e9b700 100644 --- a/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.h +++ b/src/algorithms/tracking/libs/tracking_2nd_PLL_filter.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,21 +48,21 @@ class Tracking_2nd_PLL_filter { private: // PLL filter parameters - float d_tau1_carr = 0; - float d_tau2_carr = 0; - float d_pdi_carr = 0; + float d_tau1_carr = 0.0; + float d_tau2_carr = 0.0; + float d_pdi_carr = 0.0; - float d_pllnoisebandwidth = 0; - float d_plldampingratio = 0; + float d_pllnoisebandwidth = 0.0; + float d_plldampingratio = 0.0; - float d_old_carr_error = 0; - float d_old_carr_nco = 0; + float d_old_carr_error = 0.0; + float d_old_carr_nco = 0.0; - void calculate_lopp_coef(float* tau1,float* tau2, float lbw, float zeta, float k); + void calculate_lopp_coef(float* tau1, float* tau2, float lbw, float zeta, float k); public: void set_PLL_BW(float pll_bw_hz); //! Set PLL loop bandwidth [Hz] - void set_pdi(float pdi_carr); //! Set Summation interval for code [s] + void set_pdi(float pdi_carr); //! Set Summation interval for code [s] void initialize(); float get_carrier_nco(float PLL_discriminator); Tracking_2nd_PLL_filter(float pdi_carr); diff --git a/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.cc b/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.cc index 2359584a9..04624d3f4 100644 --- a/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.cc +++ b/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -68,9 +68,6 @@ void Tracking_FLL_PLL_filter::set_params(float fll_bw_hz, float pll_bw_hz, int o } - - - void Tracking_FLL_PLL_filter::initialize(float d_acq_carrier_doppler_hz) { if (d_order == 3) @@ -86,9 +83,6 @@ void Tracking_FLL_PLL_filter::initialize(float d_acq_carrier_doppler_hz) } - - - float Tracking_FLL_PLL_filter::get_carrier_error(float FLL_discriminator, float PLL_discriminator, float correlation_time_s) { float carrier_error_hz; @@ -98,8 +92,8 @@ float Tracking_FLL_PLL_filter::get_carrier_error(float FLL_discriminator, float * 3rd order PLL with 2nd order FLL assist */ d_pll_w = d_pll_w + correlation_time_s * (d_pll_w0p3 * PLL_discriminator + d_pll_w0f2 * FLL_discriminator); - d_pll_x = d_pll_x + correlation_time_s * (0.5*d_pll_w + d_pll_a2 * d_pll_w0f * FLL_discriminator + d_pll_a3 * d_pll_w0p2 * PLL_discriminator); - carrier_error_hz = 0.5*d_pll_x + d_pll_b3 * d_pll_w0p * PLL_discriminator; + d_pll_x = d_pll_x + correlation_time_s * (0.5 * d_pll_w + d_pll_a2 * d_pll_w0f * FLL_discriminator + d_pll_a3 * d_pll_w0p2 * PLL_discriminator); + carrier_error_hz = 0.5 * d_pll_x + d_pll_b3 * d_pll_w0p * PLL_discriminator; } else { @@ -118,11 +112,10 @@ float Tracking_FLL_PLL_filter::get_carrier_error(float FLL_discriminator, float } return carrier_error_hz; - } -Tracking_FLL_PLL_filter::Tracking_FLL_PLL_filter () +Tracking_FLL_PLL_filter::Tracking_FLL_PLL_filter() { d_order = 0; d_pll_w = 0; @@ -138,6 +131,4 @@ Tracking_FLL_PLL_filter::Tracking_FLL_PLL_filter () } -Tracking_FLL_PLL_filter::~Tracking_FLL_PLL_filter () -{} - +Tracking_FLL_PLL_filter::~Tracking_FLL_PLL_filter() = default; diff --git a/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.h b/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.h index e900dec3e..f2d903513 100644 --- a/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.h +++ b/src/algorithms/tracking/libs/tracking_FLL_PLL_filter.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ private: float d_pll_w0p2; float d_pll_b3; float d_pll_w0p; + public: void set_params(float fll_bw_hz, float pll_bw_hz, int order); void initialize(float d_acq_carrier_doppler_hz); diff --git a/src/algorithms/tracking/libs/tracking_discriminators.cc b/src/algorithms/tracking/libs/tracking_discriminators.cc index 618da7b3c..c7ba2858f 100644 --- a/src/algorithms/tracking/libs/tracking_discriminators.cc +++ b/src/algorithms/tracking/libs/tracking_discriminators.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,9 +49,9 @@ double fll_four_quadrant_atan(gr_complex prompt_s1, gr_complex prompt_s2, double t1, double t2) { double cross, dot; - dot = prompt_s1.real()*prompt_s2.real() + prompt_s1.imag()*prompt_s2.imag(); - cross = prompt_s1.real()*prompt_s2.imag() - prompt_s2.real()*prompt_s1.imag(); - return atan2(cross, dot) / (t2-t1); + dot = prompt_s1.real() * prompt_s2.real() + prompt_s1.imag() * prompt_s2.imag(); + cross = prompt_s1.real() * prompt_s2.imag() - prompt_s2.real() * prompt_s1.imag(); + return atan2(cross, dot) / (t2 - t1); } @@ -81,10 +81,7 @@ double pll_cloop_two_quadrant_atan(gr_complex prompt_s1) { return atan(prompt_s1.imag() / prompt_s1.real()); } - else - { - return 0; - } + return 0.0; } @@ -100,15 +97,12 @@ double dll_nc_e_minus_l_normalized(gr_complex early_s1, gr_complex late_s1) { double P_early, P_late; P_early = std::abs(early_s1); - P_late = std::abs(late_s1); - if( P_early + P_late == 0.0 ) + P_late = std::abs(late_s1); + if (P_early + P_late == 0.0) { return 0.0; } - else - { - return 0.5 * (P_early - P_late) / ((P_early + P_late)); - } + return 0.5 * (P_early - P_late) / (P_early + P_late); } /* @@ -124,13 +118,10 @@ double dll_nc_vemlp_normalized(gr_complex very_early_s1, gr_complex early_s1, gr { double P_early, P_late; P_early = std::sqrt(std::norm(very_early_s1) + std::norm(early_s1)); - P_late = std::sqrt(std::norm(very_late_s1) + std::norm(late_s1)); - if( P_early + P_late == 0.0 ) + P_late = std::sqrt(std::norm(very_late_s1) + std::norm(late_s1)); + if (P_early + P_late == 0.0) { return 0.0; } - else - { - return (P_early - P_late) / ((P_early + P_late)); - } + return (P_early - P_late) / (P_early + P_late); } diff --git a/src/algorithms/tracking/libs/tracking_discriminators.h b/src/algorithms/tracking/libs/tracking_discriminators.h index 28dca8354..302633783 100644 --- a/src/algorithms/tracking/libs/tracking_discriminators.h +++ b/src/algorithms/tracking/libs/tracking_discriminators.h @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/algorithms/tracking/libs/tracking_loop_filter.cc b/src/algorithms/tracking/libs/tracking_loop_filter.cc index 3de0521b6..f5ebd5a10 100644 --- a/src/algorithms/tracking/libs/tracking_loop_filter.cc +++ b/src/algorithms/tracking/libs/tracking_loop_filter.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,63 +26,59 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "tracking_loop_filter.h" -#include #include +#include -#define MAX_LOOP_ORDER 3 -#define MAX_HISTORY_LENGTH 4 - -Tracking_loop_filter::Tracking_loop_filter( float update_interval, - float noise_bandwidth, - int loop_order, - bool include_last_integrator ) -: d_loop_order( loop_order ), - d_current_index( 0 ), - d_include_last_integrator( include_last_integrator ), - d_noise_bandwidth( noise_bandwidth ), - d_update_interval( update_interval ) +Tracking_loop_filter::Tracking_loop_filter(float update_interval, + float noise_bandwidth, + int loop_order, + bool include_last_integrator) + : d_loop_order(loop_order), + d_current_index(0), + d_include_last_integrator(include_last_integrator), + d_noise_bandwidth(noise_bandwidth), + d_update_interval(update_interval) { - d_inputs.resize( MAX_HISTORY_LENGTH, 0.0 ); - d_outputs.resize( MAX_HISTORY_LENGTH, 0.0 ); + d_inputs.resize(MAX_LOOP_HISTORY_LENGTH, 0.0); + d_outputs.resize(MAX_LOOP_HISTORY_LENGTH, 0.0); update_coefficients(); } + Tracking_loop_filter::Tracking_loop_filter() -: d_loop_order( 2 ), - d_current_index( 0 ), - d_include_last_integrator( false ), - d_noise_bandwidth( 15.0 ), - d_update_interval( 0.001 ) + : d_loop_order(2), + d_current_index(0), + d_include_last_integrator(false), + d_noise_bandwidth(15.0), + d_update_interval(0.001) { - d_inputs.resize( MAX_HISTORY_LENGTH, 0.0 ); - d_outputs.resize( MAX_HISTORY_LENGTH, 0.0 ); + d_inputs.resize(MAX_LOOP_HISTORY_LENGTH, 0.0); + d_outputs.resize(MAX_LOOP_HISTORY_LENGTH, 0.0); update_coefficients(); } -Tracking_loop_filter::~Tracking_loop_filter() -{ - // Don't need to do anything here -} -float Tracking_loop_filter::apply( float current_input ) -{ +Tracking_loop_filter::~Tracking_loop_filter() = default; + +float Tracking_loop_filter::apply(float current_input) +{ // Now apply the filter coefficients: - float result = 0; + float result = 0.0; // Hanlde the old outputs first: - for( unsigned int ii=0; ii < d_output_coefficients.size(); ++ii ) - { - result += d_output_coefficients[ii] * d_outputs[ (d_current_index+ii)%MAX_HISTORY_LENGTH ]; - } + for (unsigned int ii = 0; ii < d_output_coefficients.size(); ++ii) + { + result += d_output_coefficients[ii] * d_outputs[(d_current_index + ii) % MAX_LOOP_HISTORY_LENGTH]; + } // Now update the index to handle the inputs. // DO NOT CHANGE THE ORDER OF THE ABOVE AND BELOW CODE @@ -92,18 +88,18 @@ float Tracking_loop_filter::apply( float current_input ) // the current input/output is at d_current_index, the nth previous // input/output is at (d_current_index+n)%d_loop_order d_current_index--; - if( d_current_index < 0 ) - { - d_current_index += MAX_HISTORY_LENGTH; - } + if (d_current_index < 0) + { + d_current_index += MAX_LOOP_HISTORY_LENGTH; + } d_inputs[d_current_index] = current_input; - for( unsigned int ii=0; ii < d_input_coefficients.size(); ++ii ) - { - result += d_input_coefficients[ii] * d_inputs[ (d_current_index+ii)%MAX_HISTORY_LENGTH ]; - } + for (unsigned int ii = 0; ii < d_input_coefficients.size(); ++ii) + { + result += d_input_coefficients[ii] * d_inputs[(d_current_index + ii) % MAX_LOOP_HISTORY_LENGTH]; + } d_outputs[d_current_index] = result; @@ -112,7 +108,8 @@ float Tracking_loop_filter::apply( float current_input ) return result; } -void Tracking_loop_filter::update_coefficients( void ) + +void Tracking_loop_filter::update_coefficients(void) { // Analog gains: float g1; @@ -123,7 +120,7 @@ void Tracking_loop_filter::update_coefficients( void ) float wn; float T = d_update_interval; - float zeta = 1/std::sqrt(2); + float zeta = 1.0 / std::sqrt(2.0); // The following is based on the bilinear transform approximation of // the analog integrator. The loop format is from Kaplan & Hegarty @@ -135,150 +132,155 @@ void Tracking_loop_filter::update_coefficients( void ) // The bilinear transform approximates 1/s as // T/2(1 + z^-1)/(1-z^-1) in the z domain. - switch( d_loop_order ) - { + switch (d_loop_order) + { case 1: - wn = d_noise_bandwidth*4.0; + wn = d_noise_bandwidth * 4.0; g1 = wn; - if( d_include_last_integrator ) - { - d_input_coefficients.resize(2); - d_input_coefficients[0] = g1*T/2.0; - d_input_coefficients[1] = g1*T/2.0; + if (d_include_last_integrator) + { + d_input_coefficients.resize(2); + d_input_coefficients[0] = g1 * T / 2.0; + d_input_coefficients[1] = g1 * T / 2.0; - d_output_coefficients.resize(1); - d_output_coefficients[0] = 1; - } + d_output_coefficients.resize(1); + d_output_coefficients[0] = 1.0; + } else - { - d_input_coefficients.resize(1); - d_input_coefficients[0] = g1; + { + d_input_coefficients.resize(1); + d_input_coefficients[0] = g1; - d_output_coefficients.resize(0); - } + d_output_coefficients.resize(0); + } break; case 2: - wn = d_noise_bandwidth * (8*zeta)/ (4*zeta*zeta + 1 ); - g1 = wn*wn; - g2 = wn*2*zeta; - if( d_include_last_integrator ) - { - d_input_coefficients.resize(3); - d_input_coefficients[0] = T/2*( g1*T/2 + g2 ); - d_input_coefficients[1] = T*T/2*g1; - d_input_coefficients[2] = T/2*( g1*T/2 - g2 ); + wn = d_noise_bandwidth * (8.0 * zeta) / (4.0 * zeta * zeta + 1.0); + g1 = wn * wn; + g2 = wn * 2.0 * zeta; + if (d_include_last_integrator) + { + d_input_coefficients.resize(3); + d_input_coefficients[0] = T / 2.0 * (g1 * T / 2.0 + g2); + d_input_coefficients[1] = T * T / 2.0 * g1; + d_input_coefficients[2] = T / 2.0 * (g1 * T / 2.0 - g2); - d_output_coefficients.resize(2); - d_output_coefficients[0] = 2; - d_output_coefficients[1] = -1; - } + d_output_coefficients.resize(2); + d_output_coefficients[0] = 2.0; + d_output_coefficients[1] = -1.0; + } else - { - d_input_coefficients.resize(2); - d_input_coefficients[0] = ( g1*T/2.0+g2 ); - d_input_coefficients[1] = g1*T/2-g2; + { + d_input_coefficients.resize(2); + d_input_coefficients[0] = (g1 * T / 2.0 + g2); + d_input_coefficients[1] = g1 * T / 2.0 - g2; - d_output_coefficients.resize(1); - d_output_coefficients[0] = 1; - } + d_output_coefficients.resize(1); + d_output_coefficients[0] = 1.0; + } break; case 3: - wn = d_noise_bandwidth / 0.7845; // From Kaplan + wn = d_noise_bandwidth / 0.7845; // From Kaplan float a3 = 1.1; float b3 = 2.4; - g1 = wn*wn*wn; - g2 = a3*wn*wn; - g3 = b3*wn; + g1 = wn * wn * wn; + g2 = a3 * wn * wn; + g3 = b3 * wn; - if( d_include_last_integrator ) - { - d_input_coefficients.resize(4); - d_input_coefficients[0] = T/2*( g3 + T/2*( g2 + T/2*g1 ) ); - d_input_coefficients[1] = T/2*( -g3 + T/2*( g2 + 3*T/2*g1 ) ); - d_input_coefficients[2] = T/2*( -g3 - T/2*( g2 - 3*T/2*g1 ) ); - d_input_coefficients[3] = T/2*( g3 - T/2*( g2 - T/2*g1 ) ); + if (d_include_last_integrator) + { + d_input_coefficients.resize(4); + d_input_coefficients[0] = T / 2.0 * (g3 + T / 2.0 * (g2 + T / 2.0 * g1)); + d_input_coefficients[1] = T / 2.0 * (-g3 + T / 2.0 * (g2 + 3.0 * T / 2.0 * g1)); + d_input_coefficients[2] = T / 2.0 * (-g3 - T / 2.0 * (g2 - 3.0 * T / 2.0 * g1)); + d_input_coefficients[3] = T / 2.0 * (g3 - T / 2.0 * (g2 - T / 2.0 * g1)); - d_output_coefficients.resize(3); - d_output_coefficients[0] = 3; - d_output_coefficients[1] = -3; - d_output_coefficients[2] = 1; - } + d_output_coefficients.resize(3); + d_output_coefficients[0] = 3.0; + d_output_coefficients[1] = -3.0; + d_output_coefficients[2] = 1.0; + } else - { - d_input_coefficients.resize(3); - d_input_coefficients[0] = g3 + T/2*( g2 + T/2*g1 ); - d_input_coefficients[1] = g1*T*T/2 -2*g3; - d_input_coefficients[2] = g3 + T/2*( -g2 + T/2*g1 ); + { + d_input_coefficients.resize(3); + d_input_coefficients[0] = g3 + T / 2.0 * (g2 + T / 2.0 * g1); + d_input_coefficients[1] = g1 * T * T / 2.0 - 2.0 * g3; + d_input_coefficients[2] = g3 + T / 2.0 * (-g2 + T / 2.0 * g1); - d_output_coefficients.resize(2); - d_output_coefficients[0] = 2; - d_output_coefficients[1] = -1; - } + d_output_coefficients.resize(2); + d_output_coefficients[0] = 2.0; + d_output_coefficients[1] = -1.0; + } break; - - }; - + }; } -void Tracking_loop_filter::set_noise_bandwidth( float noise_bandwidth ) + +void Tracking_loop_filter::set_noise_bandwidth(float noise_bandwidth) { d_noise_bandwidth = noise_bandwidth; update_coefficients(); } -float Tracking_loop_filter::get_noise_bandwidth( void ) const + +float Tracking_loop_filter::get_noise_bandwidth(void) const { return d_noise_bandwidth; } -void Tracking_loop_filter::set_update_interval( float update_interval ) + +void Tracking_loop_filter::set_update_interval(float update_interval) { d_update_interval = update_interval; update_coefficients(); } -float Tracking_loop_filter::get_update_interval( void ) const +float Tracking_loop_filter::get_update_interval(void) const { return d_update_interval; } -void Tracking_loop_filter::set_include_last_integrator( bool include_last_integrator ) + +void Tracking_loop_filter::set_include_last_integrator(bool include_last_integrator) { d_include_last_integrator = include_last_integrator; update_coefficients(); } -bool Tracking_loop_filter::get_include_last_integrator( void ) const + +bool Tracking_loop_filter::get_include_last_integrator(void) const { return d_include_last_integrator; } -void Tracking_loop_filter::set_order( int loop_order ) + +void Tracking_loop_filter::set_order(int loop_order) { - if( loop_order < 1 || loop_order > MAX_LOOP_ORDER ) - { - LOG(ERROR) << "Ignoring attempt to set loop order to " << loop_order - << ". Maximum allowed order is: " << MAX_LOOP_ORDER - << ". Not changing current value of " << d_loop_order; + if (loop_order < 1 or loop_order > MAX_LOOP_ORDER) + { + LOG(ERROR) << "Ignoring attempt to set loop order to " << loop_order + << ". Maximum allowed order is: " << MAX_LOOP_ORDER + << ". Not changing current value of " << d_loop_order; - return; - - } + return; + } d_loop_order = loop_order; update_coefficients(); } -int Tracking_loop_filter::get_order( void ) const + +int Tracking_loop_filter::get_order(void) const { return d_loop_order; } -void Tracking_loop_filter::initialize( float initial_output ) + +void Tracking_loop_filter::initialize(float initial_output) { - d_inputs.assign( MAX_HISTORY_LENGTH, 0.0 ); - d_outputs.assign( MAX_HISTORY_LENGTH, initial_output ); - d_current_index = MAX_HISTORY_LENGTH - 1; + d_inputs.assign(MAX_LOOP_HISTORY_LENGTH, 0.0); + d_outputs.assign(MAX_LOOP_HISTORY_LENGTH, initial_output); + d_current_index = MAX_LOOP_HISTORY_LENGTH - 1; } diff --git a/src/algorithms/tracking/libs/tracking_loop_filter.h b/src/algorithms/tracking/libs/tracking_loop_filter.h index ac4041f91..6e951a2ea 100644 --- a/src/algorithms/tracking/libs/tracking_loop_filter.h +++ b/src/algorithms/tracking/libs/tracking_loop_filter.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,13 +26,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #ifndef GNSS_SDR_TRACKING_LOOP_FILTER_H_ #define GNSS_SDR_TRACKING_LOOP_FILTER_H_ +#define MAX_LOOP_ORDER 3 +#define MAX_LOOP_HISTORY_LENGTH 4 #include @@ -45,12 +47,12 @@ class Tracking_loop_filter { private: // Store the last inputs and outputs: - std::vector< float > d_inputs; - std::vector< float > d_outputs; + std::vector d_inputs; + std::vector d_outputs; // Store the filter coefficients: - std::vector< float > d_input_coefficients; - std::vector< float > d_output_coefficients; + std::vector d_input_coefficients; + std::vector d_output_coefficients; // The loop order: int d_loop_order; @@ -79,17 +81,17 @@ public: bool get_include_last_integrator(void) const; int get_order(void) const; - void set_noise_bandwidth( float noise_bandwidth ); - void set_update_interval( float update_interval ); - void set_include_last_integrator( bool include_last_integrator ); - void set_order( int loop_order ); + void set_noise_bandwidth(float noise_bandwidth); + void set_update_interval(float update_interval); + void set_include_last_integrator(bool include_last_integrator); + void set_order(int loop_order); void initialize(float initial_output = 0.0); - float apply(float current_input ); + float apply(float current_input); Tracking_loop_filter(float update_interval, float noise_bandwidth, - int loop_order = 2, - bool include_last_integrator = false ); + int loop_order = 2, + bool include_last_integrator = false); Tracking_loop_filter(); ~Tracking_loop_filter(); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 432df7e0f..62d75f86c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,10 +13,10 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(system_parameters) add_subdirectory(libs) add_subdirectory(receiver) - +add_subdirectory(monitor) diff --git a/src/core/interfaces/acquisition_interface.h b/src/core/interfaces/acquisition_interface.h index 722b99777..794748175 100644 --- a/src/core/interfaces/acquisition_interface.h +++ b/src/core/interfaces/acquisition_interface.h @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,7 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -41,7 +41,8 @@ #include "gnss_block_interface.h" #include "gnss_synchro.h" -templateclass concurrent_queue; +template +class concurrent_queue; /*! \brief This abstract class represents an interface to an acquisition GNSS block. * @@ -50,10 +51,9 @@ templateclass concurrent_queue; * instantiated directly if all inherited pure virtual methods have been * implemented by that class or a parent class. */ -class AcquisitionInterface: public GNSSBlockInterface +class AcquisitionInterface : public GNSSBlockInterface { public: - //virtual void set_active(bool active) = 0; virtual void set_gnss_synchro(Gnss_Synchro* gnss_synchro) = 0; virtual void set_channel(unsigned int channel) = 0; virtual void set_threshold(float threshold) = 0; @@ -61,8 +61,11 @@ public: virtual void set_doppler_step(unsigned int doppler_step) = 0; virtual void init() = 0; virtual void set_local_code() = 0; + virtual void set_state(int state) = 0; virtual signed int mag() = 0; virtual void reset() = 0; + virtual void stop_acquisition() = 0; + virtual void set_resampler_latency(uint32_t latency_samples) = 0; }; #endif /* GNSS_SDR_ACQUISITION_INTERFACE */ diff --git a/src/core/interfaces/channel_interface.h b/src/core/interfaces/channel_interface.h index ad5cb197a..d4f97aea5 100644 --- a/src/core/interfaces/channel_interface.h +++ b/src/core/interfaces/channel_interface.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -48,11 +48,16 @@ * instantiated directly if all inherited pure virtual methods have been * implemented by that class or a parent class. */ -class ChannelInterface: public GNSSBlockInterface +class ChannelInterface : public GNSSBlockInterface { public: + virtual gr::basic_block_sptr get_left_block_trk() = 0; + virtual gr::basic_block_sptr get_left_block_acq() = 0; + virtual gr::basic_block_sptr get_left_block() = 0; + virtual gr::basic_block_sptr get_right_block() = 0; virtual Gnss_Signal get_signal() const = 0; virtual void start_acquisition() = 0; + virtual void stop_channel() = 0; virtual void set_signal(const Gnss_Signal&) = 0; }; diff --git a/src/core/interfaces/configuration_interface.h b/src/core/interfaces/configuration_interface.h index b84e51771..0108f3283 100644 --- a/src/core/interfaces/configuration_interface.h +++ b/src/core/interfaces/configuration_interface.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #ifndef GNSS_SDR_CONFIGURATION_INTERFACE_H_ #define GNSS_SDR_CONFIGURATION_INTERFACE_H_ +#include #include /*! @@ -51,14 +52,15 @@ class ConfigurationInterface { public: - virtual ~ConfigurationInterface() - {} + virtual ~ConfigurationInterface() = default; virtual std::string property(std::string property_name, std::string default_value) = 0; virtual bool property(std::string property_name, bool default_value) = 0; - virtual long property(std::string property_name, long default_value) = 0; - virtual int property(std::string property_name, int default_value) = 0; - virtual unsigned int property(std::string property_name, unsigned int default_value) = 0; - virtual unsigned short property(std::string property_name, unsigned short default_value) = 0; + virtual int64_t property(std::string property_name, int64_t default_value) = 0; + virtual uint64_t property(std::string property_name, uint64_t default_value) = 0; + virtual int32_t property(std::string property_name, int32_t default_value) = 0; + virtual uint32_t property(std::string property_name, uint32_t default_value) = 0; + virtual int16_t property(std::string property_name, int16_t default_value) = 0; + virtual uint16_t property(std::string property_name, uint16_t default_value) = 0; virtual float property(std::string property_name, float default_value) = 0; virtual double property(std::string property_name, double default_value) = 0; virtual void set_property(std::string property_name, std::string value) = 0; diff --git a/src/core/interfaces/gnss_block_interface.h b/src/core/interfaces/gnss_block_interface.h index dd7f1558e..8a59d14cb 100644 --- a/src/core/interfaces/gnss_block_interface.h +++ b/src/core/interfaces/gnss_block_interface.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,9 +37,10 @@ #ifndef GNSS_SDR_GNSS_BLOCK_INTERFACE_H_ #define GNSS_SDR_GNSS_BLOCK_INTERFACE_H_ +#include #include #include -#include + /*! * \brief This abstract class represents an interface to GNSS blocks. @@ -52,8 +53,7 @@ class GNSSBlockInterface { public: - virtual ~GNSSBlockInterface() - {} + virtual ~GNSSBlockInterface() = default; virtual std::string role() = 0; virtual std::string implementation() = 0; virtual size_t item_size() = 0; @@ -66,14 +66,18 @@ public: virtual gr::basic_block_sptr get_left_block(int RF_channel) { assert(RF_channel >= 0); - if (RF_channel == 0){}; // avoid unused param warning - return nullptr; // added to support raw array access (non pure virtual to allow left unimplemented)= 0; + if (RF_channel == 0) + { + }; // avoid unused param warning + return nullptr; // added to support raw array access (non pure virtual to allow left unimplemented)= 0; } virtual gr::basic_block_sptr get_right_block(int RF_channel) { assert(RF_channel >= 0); - if (RF_channel == 0){}; // avoid unused param warning - return nullptr; // added to support raw array access (non pure virtual to allow left unimplemented)= 0; + if (RF_channel == 0) + { + }; // avoid unused param warning + return nullptr; // added to support raw array access (non pure virtual to allow left unimplemented)= 0; } }; diff --git a/src/core/interfaces/observables_interface.h b/src/core/interfaces/observables_interface.h index f340aa3e1..a75095979 100644 --- a/src/core/interfaces/observables_interface.h +++ b/src/core/interfaces/observables_interface.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/core/interfaces/pvt_interface.h b/src/core/interfaces/pvt_interface.h index 064f5a6dd..20b3df8e4 100644 --- a/src/core/interfaces/pvt_interface.h +++ b/src/core/interfaces/pvt_interface.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,7 +37,11 @@ #ifndef GNSS_SDR_PVT_INTERFACE_H_ #define GNSS_SDR_PVT_INTERFACE_H_ +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" #include "gnss_block_interface.h" +#include "gps_almanac.h" +#include "gps_ephemeris.h" /*! * \brief This class represents an interface to a PVT block. @@ -52,6 +56,18 @@ class PvtInterface : public GNSSBlockInterface { public: virtual void reset() = 0; + virtual void clear_ephemeris() = 0; + virtual std::map get_gps_ephemeris() const = 0; + virtual std::map get_galileo_ephemeris() const = 0; + virtual std::map get_gps_almanac() const = 0; + virtual std::map get_galileo_almanac() const = 0; + + virtual bool get_latest_PVT(double* longitude_deg, + double* latitude_deg, + double* height_m, + double* ground_speed_kmh, + double* course_over_ground_deg, + time_t* UTC_time) = 0; }; #endif /* GNSS_SDR_PVT_INTERFACE_H_ */ diff --git a/src/core/interfaces/telemetry_decoder_interface.h b/src/core/interfaces/telemetry_decoder_interface.h index 5b43794a8..b2d906b32 100644 --- a/src/core/interfaces/telemetry_decoder_interface.h +++ b/src/core/interfaces/telemetry_decoder_interface.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -52,7 +52,7 @@ class TelemetryDecoderInterface : public GNSSBlockInterface { public: virtual void reset() = 0; - virtual void set_satellite(Gnss_Satellite sat) = 0; + virtual void set_satellite(const Gnss_Satellite& sat) = 0; virtual void set_channel(int channel) = 0; }; diff --git a/src/core/interfaces/tracking_interface.h b/src/core/interfaces/tracking_interface.h index 70724e019..da2b3c41b 100644 --- a/src/core/interfaces/tracking_interface.h +++ b/src/core/interfaces/tracking_interface.h @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -40,7 +40,8 @@ #include "gnss_block_interface.h" #include "gnss_synchro.h" -templateclass concurrent_queue; +template +class concurrent_queue; /*! * \brief This abstract class represents an interface to a tracking block. @@ -55,6 +56,7 @@ class TrackingInterface : public GNSSBlockInterface { public: virtual void start_tracking() = 0; + virtual void stop_tracking() = 0; virtual void set_gnss_synchro(Gnss_Synchro* gnss_synchro) = 0; virtual void set_channel(unsigned int channel) = 0; }; diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 11c71cedf..9557199c4 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,24 +13,31 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(supl) if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() -set(CORE_LIBS_SOURCES - ini.cc - INIReader.cc +set(CORE_LIBS_SOURCES + ini.cc + INIReader.cc string_converter.cc gnss_sdr_supl_client.cc ) - + +set(CORE_LIBS_HEADERS + ini.h + INIReader.h + string_converter.h + gnss_sdr_supl_client.h +) + include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) + ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src/core/system_parameters ${CMAKE_SOURCE_DIR}/src/core/libs/supl ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp @@ -38,10 +45,16 @@ include_directories( ${GLOG_INCLUDE_DIRS} ${GFlags_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} + ${PUGIXML_INCLUDE_DIR} ) -file(GLOB CORE_LIBS_HEADERS "*.h") list(SORT CORE_LIBS_HEADERS) +list(SORT CORE_LIBS_SOURCES) + add_library(rx_core_lib ${CORE_LIBS_SOURCES} ${CORE_LIBS_HEADERS}) source_group(Headers FILES ${CORE_LIBS_HEADERS}) -target_link_libraries(rx_core_lib supl_library) +target_link_libraries(rx_core_lib supl_library ${PUGIXML_LIBRARY}) + +if(PUGIXML_LOCAL) + add_dependencies(rx_core_lib pugixml-${GNSSSDR_PUGIXML_LOCAL_VERSION}) +endif() diff --git a/src/core/libs/INIReader.cc b/src/core/libs/INIReader.cc index 0e3af9242..9ca9dd039 100644 --- a/src/core/libs/INIReader.cc +++ b/src/core/libs/INIReader.cc @@ -1,96 +1,101 @@ -/*! - * \file INIReader.cc - * \brief This class reads an INI file into easy-to-access name/value pairs. - * \author Brush Technologies, 2009. - * - * inih (INI Not Invented Here) is a simple .INI file parser written in C++. - * It's only a couple of pages of code, and it was designed to be small - * and simple, so it's good for embedded systems. To use it, just give - * ini_parse() an INI file, and it will call a callback for every - * name=value pair parsed, giving you strings for the section, name, - * and value. It's done this way because it works well on low-memory - * embedded systems, but also because it makes for a KISS implementation. - * - * ------------------------------------------------------------------------- - * inih and INIReader are released under the New BSD license: - * - * Copyright (c) 2009, Brush Technology - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Brush Technology nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Go to the project home page for more info: - * - * http://code.google.com/p/inih/ - * ------------------------------------------------------------------------- - */ - -#include -#include -#include "ini.h" -#include "INIReader.h" - -using std::string; - -INIReader::INIReader(string filename) -{ - _error = ini_parse(filename.c_str(), ValueHandler, this); -} - -int INIReader::ParseError() -{ - return _error; -} - -string INIReader::Get(string section, string name, string default_value) -{ - string key = MakeKey(section, name); - return _values.count(key) ? _values[key] : default_value; -} - -long INIReader::GetInteger(string section, string name, long default_value) -{ - string valstr = Get(section, name, ""); - const char* value = valstr.c_str(); - char* end; - // This parses "1234" (decimal) and also "0x4D2" (hex) - long n = strtol(value, &end, 0); - return end > value ? n : default_value; -} - -string INIReader::MakeKey(string section, string name) -{ - string key = section + "." + name; - // Convert to lower case to make lookups case-insensitive - for (unsigned int i = 0; i < key.length(); i++) - key[i] = tolower(key[i]); - return key; -} - -int INIReader::ValueHandler(void* user, const char* section, const char* name, - const char* value) -{ - INIReader* reader = (INIReader*)user; - reader->_values[MakeKey(section, name)] = value; - return 1; -} +/*! + * \file INIReader.cc + * \brief This class reads an INI file into easy-to-access name/value pairs. + * \author Brush Technologies, 2009. + * + * inih (INI Not Invented Here) is a simple .INI file parser written in C++. + * It's only a couple of pages of code, and it was designed to be small + * and simple, so it's good for embedded systems. To use it, just give + * ini_parse() an INI file, and it will call a callback for every + * name=value pair parsed, giving you strings for the section, name, + * and value. It's done this way because it works well on low-memory + * embedded systems, but also because it makes for a KISS implementation. + * + * ------------------------------------------------------------------------- + * inih and INIReader are released under the New BSD license: + * + * Copyright (c) 2009, Brush Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Brush Technology nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Go to the project home page for more info: + * + * http://code.google.com/p/inih/ + * ------------------------------------------------------------------------- + */ + +#include "INIReader.h" +#include "ini.h" +#include // for tolower +#include // for stro +#include + + +INIReader::INIReader(const std::string& filename) +{ + _error = ini_parse(filename.c_str(), ValueHandler, this); +} + + +int INIReader::ParseError() +{ + return _error; +} + + +std::string INIReader::Get(const std::string& section, const std::string& name, std::string default_value) +{ + std::string key = MakeKey(section, name); + return _values.count(key) ? _values[key] : default_value; +} + + +int64_t INIReader::GetInteger(const std::string& section, const std::string& name, int64_t default_value) +{ + std::string valstr = Get(section, name, ""); + const char* value = valstr.c_str(); + char* end; + // This parses "1234" (decimal) and also "0x4D2" (hex) + int64_t n = strtol(value, &end, 0); + return end > value ? n : default_value; +} + + +std::string INIReader::MakeKey(const std::string& section, const std::string& name) +{ + std::string key = section + "." + name; + // Convert to lower case to make lookups case-insensitive + for (char& i : key) + i = tolower(i); + return key; +} + + +int INIReader::ValueHandler(void* user, const char* section, const char* name, + const char* value) +{ + auto* reader = static_cast(user); + reader->_values[MakeKey(section, name)] = value; + return 1; +} diff --git a/src/core/libs/INIReader.h b/src/core/libs/INIReader.h index 909f1cae8..bfe168bd9 100644 --- a/src/core/libs/INIReader.h +++ b/src/core/libs/INIReader.h @@ -1,82 +1,83 @@ -/*! - * \file INIReader.h - * \brief This class reads an INI file into easy-to-access name/value pairs. - * \author Brush Technologies, 2009. - * - * inih (INI Not Invented Here) is a simple .INI file parser written in C++. - * It's only a couple of pages of code, and it was designed to be small - * and simple, so it's good for embedded systems. To use it, just give - * ini_parse() an INI file, and it will call a callback for every - * name=value pair parsed, giving you strings for the section, name, - * and value. It's done this way because it works well on low-memory - * embedded systems, but also because it makes for a KISS implementation. - * - * ------------------------------------------------------------------------- - * inih and INIReader are released under the New BSD license: - * - * Copyright (c) 2009, Brush Technology - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Brush Technology nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Go to the project home page for more info: - * - * http://code.google.com/p/inih/ - * ------------------------------------------------------------------------- - */ - -#ifndef __INIREADER_H__ -#define __INIREADER_H__ - -#include -#include - -/*! - * \brief Read an INI file into easy-to-access name/value pairs. (Note that I've gone - * for simplicity here rather than speed, but it should be pretty decent.) - */ -class INIReader -{ -public: - //! Construct INIReader and parse given filename. See ini.h for more info about the parsing. - INIReader(std::string filename); - - //! Return the result of ini_parse(), i.e., 0 on success, line number of first error on parse error, or -1 on file open error. - int ParseError(); - - //! Get a string value from INI file, returning default_value if not found. - std::string Get(std::string section, std::string name, - std::string default_value); - - //! Get an integer (long) value from INI file, returning default_value if not found. - long GetInteger(std::string section, std::string name, long default_value); - -private: - int _error; - std::map _values; - static std::string MakeKey(std::string section, std::string name); - static int ValueHandler(void* user, const char* section, const char* name, - const char* value); -}; - -#endif // __INIREADER_H__ +/*! + * \file INIReader.h + * \brief This class reads an INI file into easy-to-access name/value pairs. + * \author Brush Technologies, 2009. + * + * inih (INI Not Invented Here) is a simple .INI file parser written in C++. + * It's only a couple of pages of code, and it was designed to be small + * and simple, so it's good for embedded systems. To use it, just give + * ini_parse() an INI file, and it will call a callback for every + * name=value pair parsed, giving you strings for the section, name, + * and value. It's done this way because it works well on low-memory + * embedded systems, but also because it makes for a KISS implementation. + * + * ------------------------------------------------------------------------- + * inih and INIReader are released under the New BSD license: + * + * Copyright (c) 2009, Brush Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Brush Technology nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Go to the project home page for more info: + * + * http://code.google.com/p/inih/ + * ------------------------------------------------------------------------- + */ + +#ifndef __INIREADER_H__ +#define __INIREADER_H__ + +#include +#include +#include + +/*! + * \brief Read an INI file into easy-to-access name/value pairs. (Note that I've gone + * for simplicity here rather than speed, but it should be pretty decent.) + */ +class INIReader +{ +public: + //! Construct INIReader and parse given filename. See ini.h for more info about the parsing. + INIReader(const std::string& filename); + + //! Return the result of ini_parse(), i.e., 0 on success, line number of first error on parse error, or -1 on file open error. + int ParseError(); + + //! Get a string value from INI file, returning default_value if not found. + std::string Get(const std::string& section, const std::string& name, + std::string default_value); + + //! Get an integer (long) value from INI file, returning default_value if not found. + int64_t GetInteger(const std::string& section, const std::string& name, int64_t default_value); + +private: + int _error; + std::map _values; + static std::string MakeKey(const std::string& section, const std::string& name); + static int ValueHandler(void* user, const char* section, const char* name, + const char* value); +}; + +#endif // __INIREADER_H__ diff --git a/src/core/libs/gnss_sdr_supl_client.cc b/src/core/libs/gnss_sdr_supl_client.cc index 225d3e731..0311892bd 100644 --- a/src/core/libs/gnss_sdr_supl_client.cc +++ b/src/core/libs/gnss_sdr_supl_client.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,12 +26,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gnss_sdr_supl_client.h" +#include #include #include @@ -47,23 +48,24 @@ gnss_sdr_supl_client::gnss_sdr_supl_client() request = 0; } -gnss_sdr_supl_client::~gnss_sdr_supl_client() -{} + +gnss_sdr_supl_client::~gnss_sdr_supl_client() = default; + void gnss_sdr_supl_client::print_assistance() { if (assist.set & SUPL_RRLP_ASSIST_REFTIME) { fprintf(stdout, "T %ld %ld %ld %ld\n", assist.time.gps_week, assist.time.gps_tow, - assist.time.stamp.tv_sec, static_cast(assist.time.stamp.tv_usec)); + assist.time.stamp.tv_sec, static_cast(assist.time.stamp.tv_usec)); } if (assist.set & SUPL_RRLP_ASSIST_UTC) { fprintf(stdout, "U %d %d %d %d %d %d %d %d\n", - assist.utc.a0, assist.utc.a1, assist.utc.delta_tls, - assist.utc.tot, assist.utc.wnt, assist.utc.wnlsf, - assist.utc.dn, assist.utc.delta_tlsf); + assist.utc.a0, assist.utc.a1, assist.utc.delta_tls, + assist.utc.tot, assist.utc.wnt, assist.utc.wnlsf, + assist.utc.dn, assist.utc.delta_tlsf); } if (assist.set & SUPL_RRLP_ASSIST_REFLOC) @@ -74,8 +76,8 @@ void gnss_sdr_supl_client::print_assistance() if (assist.set & SUPL_RRLP_ASSIST_IONO) { fprintf(stdout, "I %d %d %d %d %d %d %d %d\n", - assist.iono.a0, assist.iono.a1, assist.iono.a2, assist.iono.a3, - assist.iono.b0, assist.iono.b1, assist.iono.b2, assist.iono.b3); + assist.iono.a0, assist.iono.a1, assist.iono.a2, assist.iono.a3, + assist.iono.b0, assist.iono.b1, assist.iono.b2, assist.iono.b3); } if (assist.cnt_eph) @@ -86,16 +88,16 @@ void gnss_sdr_supl_client::print_assistance() for (i = 0; i < assist.cnt_eph; i++) { - struct supl_ephemeris_s *e = &assist.eph[i]; + struct supl_ephemeris_s* e = &assist.eph[i]; fprintf(stdout, "e %d %d %d %d %d %d %d %d %d %d", - e->prn, e->delta_n, e->M0, e->A_sqrt, e->OMEGA_0, e->i0, e->w, e->OMEGA_dot, e->i_dot, e->e); + e->prn, e->delta_n, e->M0, e->A_sqrt, e->OMEGA_0, e->i0, e->w, e->OMEGA_dot, e->i_dot, e->e); fprintf(stdout, " %d %d %d %d %d %d", - e->Cuc, e->Cus, e->Crc, e->Crs, e->Cic, e->Cis); + e->Cuc, e->Cus, e->Crc, e->Crs, e->Cic, e->Cis); fprintf(stdout, " %d %d %d %d %d %d", - e->toe, e->IODC, e->toc, e->AF0, e->AF1, e->AF2); + e->toe, e->IODC, e->toc, e->AF0, e->AF1, e->AF2); fprintf(stdout, " %d %d %d %d %d\n", - e->bits, e->ura, e->health, e->tgd, e->AODA); + e->bits, e->ura, e->health, e->tgd, e->AODA); } } @@ -106,12 +108,12 @@ void gnss_sdr_supl_client::print_assistance() fprintf(stdout, "A %d\n", assist.cnt_alm); for (i = 0; i < assist.cnt_alm; i++) { - struct supl_almanac_s *a = &assist.alm[i]; + struct supl_almanac_s* a = &assist.alm[i]; fprintf(stdout, "a %d %d %d %d %d ", - a->prn, a->e, a->toa, a->Ksii, a->OMEGA_dot); + a->prn, a->e, a->toa, a->Ksii, a->OMEGA_dot); fprintf(stdout, "%d %d %d %d %d %d\n", - a->A_sqrt, a->OMEGA_0, a->w, a->M0, a->AF0, a->AF1); + a->A_sqrt, a->OMEGA_0, a->w, a->M0, a->AF0, a->AF1); } } @@ -122,10 +124,10 @@ void gnss_sdr_supl_client::print_assistance() fprintf(stdout, "Q %d %d\n", assist.cnt_acq, assist.acq_time); for (i = 0; i < assist.cnt_acq; i++) { - struct supl_acquis_s *q = &assist.acq[i]; + struct supl_acquis_s* q = &assist.acq[i]; fprintf(stdout, "q %d %d %d ", - q->prn, q->parts, q->doppler0); + q->prn, q->parts, q->doppler0); if (q->parts & SUPL_ACQUIS_DOPPLER) { fprintf(stdout, "%d %d ", q->doppler1, q->d_win); @@ -135,7 +137,7 @@ void gnss_sdr_supl_client::print_assistance() fprintf(stdout, "0 0 "); } fprintf(stdout, "%d %d %d %d ", - q->code_ph, q->code_ph_int, q->bit_num, q->code_ph_win); + q->code_ph, q->code_ph_int, q->bit_num, q->code_ph_win); if (q->parts & SUPL_ACQUIS_ANGLE) { fprintf(stdout, "%d %d\n", q->az, q->el); @@ -157,35 +159,40 @@ int gnss_sdr_supl_client::get_assistance(int i_mcc, int i_mns, int i_lac, int i_ mns = i_mns; lac = i_lac; ci = i_ci; - if (supl_ctx_new(&ctx)) {} // clean it before using + if (supl_ctx_new(&ctx)) + { + } // clean it before using supl_set_gsm_cell(&ctx, mcc, mns, lac, ci); // PERFORM SUPL COMMUNICATION - char *cstr = new char[server_name.length() + 1]; + char* cstr = new char[server_name.length() + 1]; strcpy(cstr, server_name.c_str()); int err; - ctx.p.request = request; // select assistance info request from a pre-defined set + ctx.p.request = request; // select assistance info request from a pre-defined set //std::cout<<"mcc="<(assist.time.gps_tow) * 0.08; + gps_time.d_Week = static_cast(assist.time.gps_week); + gps_time.d_tv_sec = static_cast(assist.time.stamp.tv_sec); + gps_time.d_tv_usec = static_cast(assist.time.stamp.tv_usec); gps_time.valid = true; } // READ UTC MODEL if (assist.set & SUPL_RRLP_ASSIST_UTC) { - gps_utc.d_A0 = ((double)assist.utc.a0)*pow(2.0, -30); - gps_utc.d_A1 = ((double)assist.utc.a1)*pow(2.0, -50); - gps_utc.d_DeltaT_LS = ((double)assist.utc.delta_tls); - gps_utc.d_DeltaT_LSF = ((double)assist.utc.delta_tlsf); - gps_utc.d_t_OT = ((double)assist.utc.tot)*pow(2.0,12); - gps_utc.i_DN = ((double)assist.utc.dn); - gps_utc.i_WN_T = ((double)assist.utc.wnt); - gps_utc.i_WN_LSF = ((double)assist.utc.wnlsf); + gps_utc.d_A0 = static_cast(assist.utc.a0) * pow(2.0, -30); + gps_utc.d_A1 = static_cast(assist.utc.a1) * pow(2.0, -50); + gps_utc.d_DeltaT_LS = static_cast(assist.utc.delta_tls); + gps_utc.d_DeltaT_LSF = static_cast(assist.utc.delta_tlsf); + gps_utc.d_t_OT = static_cast(assist.utc.tot) * pow(2.0, 12); + gps_utc.i_DN = static_cast(assist.utc.dn); + gps_utc.i_WN_T = static_cast(assist.utc.wnt); + gps_utc.i_WN_LSF = static_cast(assist.utc.wnlsf); gps_utc.valid = true; } // READ IONOSPHERIC MODEL if (assist.set & SUPL_RRLP_ASSIST_IONO) { - gps_iono.d_alpha0 = (double)assist.iono.a0 * ALPHA_0_LSB; - gps_iono.d_alpha1 = (double)assist.iono.a1 * ALPHA_1_LSB; - gps_iono.d_alpha2 = (double)assist.iono.a2 * ALPHA_2_LSB; - gps_iono.d_alpha3 = (double)assist.iono.a3 * ALPHA_3_LSB; + gps_iono.d_alpha0 = static_cast(assist.iono.a0) * ALPHA_0_LSB; + gps_iono.d_alpha1 = static_cast(assist.iono.a1) * ALPHA_1_LSB; + gps_iono.d_alpha2 = static_cast(assist.iono.a2) * ALPHA_2_LSB; + gps_iono.d_alpha3 = static_cast(assist.iono.a3) * ALPHA_3_LSB; - gps_iono.d_beta0 = (double)assist.iono.b0 * BETA_0_LSB; - gps_iono.d_beta1 = (double)assist.iono.b1 * BETA_1_LSB; - gps_iono.d_beta2 = (double)assist.iono.b2 * BETA_2_LSB; - gps_iono.d_beta3 = (double)assist.iono.b3 * BETA_3_LSB; + gps_iono.d_beta0 = static_cast(assist.iono.b0) * BETA_0_LSB; + gps_iono.d_beta1 = static_cast(assist.iono.b1) * BETA_1_LSB; + gps_iono.d_beta2 = static_cast(assist.iono.b2) * BETA_2_LSB; + gps_iono.d_beta3 = static_cast(assist.iono.b3) * BETA_3_LSB; gps_iono.valid = true; } // READ SV ALMANAC if (assist.cnt_alm) { - std::map::iterator gps_almanac_iterator; + std::map::iterator gps_almanac_iterator; for (int i = 0; i < assist.cnt_alm; i++) { - struct supl_almanac_s *a = &assist.alm[i]; + struct supl_almanac_s* a = &assist.alm[i]; // Check if the SV is present in the map gps_almanac_iterator = this->gps_almanac_map.find(a->prn); // the SV is not present in the almanac data -> insert new SV register - if (gps_almanac_iterator==gps_almanac_map.end()) + if (gps_almanac_iterator == gps_almanac_map.end()) { Gps_Almanac gps_almanac_entry; gps_almanac_map.insert(std::pair(a->prn, gps_almanac_entry)); gps_almanac_iterator = this->gps_almanac_map.find(a->prn); } gps_almanac_iterator->second.i_satellite_PRN = a->prn; - gps_almanac_iterator->second.d_A_f0 = ((double)a->AF0)*pow(2.0, -20); - gps_almanac_iterator->second.d_A_f1 = ((double)a->AF1)*pow(2.0, -38); - gps_almanac_iterator->second.d_Delta_i = ((double)a->Ksii)*pow(2.0, -19); - gps_almanac_iterator->second.d_OMEGA = ((double)a->w)*pow(2.0, -23); - gps_almanac_iterator->second.d_OMEGA0 = ((double)a->OMEGA_0)*pow(2.0, -23); - gps_almanac_iterator->second.d_sqrt_A = ((double)a->A_sqrt)*pow(2.0, -11); - gps_almanac_iterator->second.d_OMEGA_DOT = ((double)a->OMEGA_dot)*pow(2.0, -38); - gps_almanac_iterator->second.d_Toa = ((double)a->toa)*pow(2.0, 12); - gps_almanac_iterator->second.d_e_eccentricity = ((double)a->toa)*pow(2.0, -21); - gps_almanac_iterator->second.d_M_0 = ((double)a->M0)*pow(2.0, -23); + gps_almanac_iterator->second.d_A_f0 = static_cast(a->AF0) * pow(2.0, -20); + gps_almanac_iterator->second.d_A_f1 = static_cast(a->AF1) * pow(2.0, -38); + gps_almanac_iterator->second.d_Delta_i = static_cast(a->Ksii) * pow(2.0, -19); + gps_almanac_iterator->second.d_OMEGA = static_cast(a->w) * pow(2.0, -23); + gps_almanac_iterator->second.d_OMEGA0 = static_cast(a->OMEGA_0) * pow(2.0, -23); + gps_almanac_iterator->second.d_sqrt_A = static_cast(a->A_sqrt) * pow(2.0, -11); + gps_almanac_iterator->second.d_OMEGA_DOT = static_cast(a->OMEGA_dot) * pow(2.0, -38); + gps_almanac_iterator->second.i_Toa = static_cast(a->toa * pow(2.0, 12)); + gps_almanac_iterator->second.d_e_eccentricity = static_cast(a->e) * pow(2.0, -21); + gps_almanac_iterator->second.d_M_0 = static_cast(a->M0) * pow(2.0, -23); } } - // READ SV EPHEMERIS if (assist.cnt_eph) { - std::map::iterator gps_eph_iterator; + std::map::iterator gps_eph_iterator; for (int i = 0; i < assist.cnt_eph; i++) { - struct supl_ephemeris_s *e = &assist.eph[i]; + struct supl_ephemeris_s* e = &assist.eph[i]; // Check if the SV is present in the map gps_eph_iterator = this->gps_ephemeris_map.find(e->prn); // the SV is not present in the assistance data -> insert new SV register if (gps_eph_iterator == gps_ephemeris_map.end()) { Gps_Ephemeris gps_eph; - gps_ephemeris_map.insert(std::pair(e->prn, gps_eph)); + gps_ephemeris_map.insert(std::pair(e->prn, gps_eph)); gps_eph_iterator = this->gps_ephemeris_map.find(e->prn); } if (gps_time.valid) { gps_eph_iterator->second.i_GPS_week = assist.time.gps_week; /* TS 44.031: GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation */ - gps_eph_iterator->second.d_TOW = ((double)assist.time.gps_tow)*0.08; + gps_eph_iterator->second.d_TOW = static_cast(assist.time.gps_tow) * 0.08; } else { @@ -298,34 +304,34 @@ void gnss_sdr_supl_client::read_supl_data() gps_eph_iterator->second.i_satellite_PRN = e->prn; // SV navigation model gps_eph_iterator->second.i_code_on_L2 = e->bits; - gps_eph_iterator->second.i_SV_accuracy = e->ura; //User Range Accuracy (URA) + gps_eph_iterator->second.i_SV_accuracy = e->ura; //User Range Accuracy (URA) gps_eph_iterator->second.i_SV_health = e->health; - gps_eph_iterator->second.d_IODC = (double)e->IODC; + gps_eph_iterator->second.d_IODC = static_cast(e->IODC); //miss P flag (1 bit) //miss SF1 Reserved (87 bits) - gps_eph_iterator->second.d_TGD = ((double)e->tgd)*T_GD_LSB; - gps_eph_iterator->second.d_Toc = ((double)e->toc)*T_OC_LSB; - gps_eph_iterator->second.d_A_f0 = ((double)e->AF0)*A_F0_LSB; - gps_eph_iterator->second.d_A_f1 = ((double)e->AF1)*A_F1_LSB; - gps_eph_iterator->second.d_A_f2 = ((double)e->AF2)*A_F2_LSB; - gps_eph_iterator->second.d_Crc = ((double)e->Crc)*C_RC_LSB; - gps_eph_iterator->second.d_Delta_n = ((double)e->delta_n)*DELTA_N_LSB; - gps_eph_iterator->second.d_M_0 = ((double)e->M0)*M_0_LSB; - gps_eph_iterator->second.d_Cuc = ((double)e->Cuc)*C_UC_LSB; - gps_eph_iterator->second.d_e_eccentricity = ((double)e->e)*E_LSB; - gps_eph_iterator->second.d_Cus = ((double)e->Cus)*C_US_LSB; - gps_eph_iterator->second.d_sqrt_A = ((double)e->A_sqrt)*SQRT_A_LSB; - gps_eph_iterator->second.d_Toe = ((double)e->toe)*T_OE_LSB; + gps_eph_iterator->second.d_TGD = static_cast(e->tgd) * T_GD_LSB; + gps_eph_iterator->second.d_Toc = static_cast(e->toc) * T_OC_LSB; + gps_eph_iterator->second.d_A_f0 = static_cast(e->AF0) * A_F0_LSB; + gps_eph_iterator->second.d_A_f1 = static_cast(e->AF1) * A_F1_LSB; + gps_eph_iterator->second.d_A_f2 = static_cast(e->AF2) * A_F2_LSB; + gps_eph_iterator->second.d_Crc = static_cast(e->Crc) * C_RC_LSB; + gps_eph_iterator->second.d_Delta_n = static_cast(e->delta_n) * DELTA_N_LSB; + gps_eph_iterator->second.d_M_0 = static_cast(e->M0) * M_0_LSB; + gps_eph_iterator->second.d_Cuc = static_cast(e->Cuc) * C_UC_LSB; + gps_eph_iterator->second.d_e_eccentricity = static_cast(e->e) * E_LSB; + gps_eph_iterator->second.d_Cus = static_cast(e->Cus) * C_US_LSB; + gps_eph_iterator->second.d_sqrt_A = static_cast(e->A_sqrt) * SQRT_A_LSB; + gps_eph_iterator->second.d_Toe = static_cast(e->toe) * T_OE_LSB; //miss fit interval flag (1 bit) gps_eph_iterator->second.i_AODO = e->AODA * AODO_LSB; - gps_eph_iterator->second.d_Cic = ((double)e->Cic)*C_IC_LSB; - gps_eph_iterator->second.d_OMEGA0 = ((double)e->OMEGA_0)*OMEGA_0_LSB; - gps_eph_iterator->second.d_Cis = ((double)e->Cis)*C_IS_LSB; - gps_eph_iterator->second.d_i_0 = ((double)e->i0)*I_0_LSB; - gps_eph_iterator->second.d_Crs = ((double)e->Crs)*C_RS_LSB; - gps_eph_iterator->second.d_OMEGA = ((double)e->w)*OMEGA_LSB; - gps_eph_iterator->second.d_OMEGA_DOT = (double)e->OMEGA_dot*OMEGA_DOT_LSB; - gps_eph_iterator->second.d_IDOT = ((double)e->i_dot)*I_DOT_LSB; + gps_eph_iterator->second.d_Cic = static_cast(e->Cic) * C_IC_LSB; + gps_eph_iterator->second.d_OMEGA0 = static_cast(e->OMEGA_0) * OMEGA_0_LSB; + gps_eph_iterator->second.d_Cis = static_cast(e->Cis) * C_IS_LSB; + gps_eph_iterator->second.d_i_0 = static_cast(e->i0) * I_0_LSB; + gps_eph_iterator->second.d_Crs = static_cast(e->Crs) * C_RS_LSB; + gps_eph_iterator->second.d_OMEGA = static_cast(e->w) * OMEGA_LSB; + gps_eph_iterator->second.d_OMEGA_DOT = static_cast(e->OMEGA_dot) * OMEGA_DOT_LSB; + gps_eph_iterator->second.d_IDOT = static_cast(e->i_dot) * I_DOT_LSB; } } @@ -333,65 +339,66 @@ void gnss_sdr_supl_client::read_supl_data() if (assist.cnt_acq) { - std::map::iterator gps_acq_iterator; + std::map::iterator gps_acq_iterator; for (int i = 0; i < assist.cnt_acq; i++) { - struct supl_acquis_s *e = &assist.acq[i]; + struct supl_acquis_s* e = &assist.acq[i]; // Check if the SV is present in the map - gps_acq_iterator=this->gps_acq_map.find(e->prn); + gps_acq_iterator = this->gps_acq_map.find(e->prn); // the SV is not present in the assistance data -> insert new SV register if (gps_acq_iterator == gps_acq_map.end()) { Gps_Acq_Assist gps_acq_assist; - gps_acq_map.insert(std::pair(e->prn, gps_acq_assist)); + gps_acq_map.insert(std::pair(e->prn, gps_acq_assist)); gps_acq_iterator = this->gps_acq_map.find(e->prn); } // fill the acquisition assistance structure gps_acq_iterator->second.i_satellite_PRN = e->prn; - gps_acq_iterator->second.d_TOW = (double)assist.acq_time; - gps_acq_iterator->second.d_Doppler0 = (double)e->doppler0; - gps_acq_iterator->second.d_Doppler1 = (double)e->doppler1; - gps_acq_iterator->second.dopplerUncertainty = (double)e->d_win; - gps_acq_iterator->second.Code_Phase = (double)e->code_ph; - gps_acq_iterator->second.Code_Phase_int = (double)e->code_ph_int; - gps_acq_iterator->second.Code_Phase_window = (double)e->code_ph_win; - gps_acq_iterator->second.Azimuth = (double)e->az; - gps_acq_iterator->second.Elevation = (double)e->el; - gps_acq_iterator->second.GPS_Bit_Number = (double)e->bit_num; + gps_acq_iterator->second.d_TOW = static_cast(assist.acq_time); + gps_acq_iterator->second.d_Doppler0 = static_cast(e->doppler0); + gps_acq_iterator->second.d_Doppler1 = static_cast(e->doppler1); + gps_acq_iterator->second.dopplerUncertainty = static_cast(e->d_win); + gps_acq_iterator->second.Code_Phase = static_cast(e->code_ph); + gps_acq_iterator->second.Code_Phase_int = static_cast(e->code_ph_int); + gps_acq_iterator->second.Code_Phase_window = static_cast(e->code_ph_win); + gps_acq_iterator->second.Azimuth = static_cast(e->az); + gps_acq_iterator->second.Elevation = static_cast(e->el); + gps_acq_iterator->second.GPS_Bit_Number = static_cast(e->bit_num); } } } -bool gnss_sdr_supl_client::load_ephemeris_xml(const std::string file_name) +bool gnss_sdr_supl_client::load_ephemeris_xml(const std::string& file_name) { + std::ifstream ifs; try - { - std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gps_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", this->gps_ephemeris_map); - ifs.close(); - LOG(INFO) << "Loaded Ephemeris map data with "<gps_ephemeris_map.size()<<" satellites"; - } + LOG(INFO) << "Loaded Ephemeris map data with " << this->gps_ephemeris_map.size() << " satellites"; + } catch (std::exception& e) - { + { LOG(WARNING) << e.what() << "File: " << file_name; return false; - } + } return true; } -bool gnss_sdr_supl_client::save_ephemeris_map_xml(const std::string file_name, std::map eph_map) + +bool gnss_sdr_supl_client::save_ephemeris_map_xml(const std::string& file_name, std::map eph_map) { - if (eph_map.size() > 0) + if (eph_map.empty() == false) { + std::ofstream ofs; try { - std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", eph_map); - ofs.close(); LOG(INFO) << "Saved Ephemeris map data"; } catch (std::exception& e) @@ -399,67 +406,303 @@ bool gnss_sdr_supl_client::save_ephemeris_map_xml(const std::string file_name, s LOG(WARNING) << e.what(); return false; } - return true; } else { LOG(WARNING) << "Failed to save Ephemeris, map is empty"; return false; } -} - -bool gnss_sdr_supl_client::load_utc_xml(const std::string file_name) -{ - try - { - std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); - boost::archive::xml_iarchive xml(ifs); - xml >> boost::serialization::make_nvp("GNSS-SDR_utc_map", this->gps_utc); - ifs.close(); - LOG(INFO) << "Loaded UTC model data"; - } - catch (std::exception& e) - { - LOG(WARNING) << e.what() << "File: " << file_name; - return false; - } return true; } -bool gnss_sdr_supl_client::save_utc_map_xml(const std::string file_name, std::map utc_map) + +bool gnss_sdr_supl_client::load_gal_ephemeris_xml(const std::string& file_name) { - if (utc_map.size() > 0) + std::ifstream ifs; + try { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gal_ephemeris_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", this->gal_ephemeris_map); + LOG(INFO) << "Loaded Ephemeris map data with " << this->gal_ephemeris_map.size() << " satellites"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool save_gal_ephemeris_map_xml(const std::string& file_name, std::map eph_map) +{ + if (eph_map.empty() == false) + { + std::ofstream ofs; try { - std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_utc_map", utc_map); - ofs.close(); - LOG(INFO) << "Saved UTC Model data"; + xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", eph_map); + LOG(INFO) << "Saved Galileo ephemeris map data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } - return true; } else { - LOG(WARNING) << "Failed to save UTC model, map is empty"; + LOG(WARNING) << "Failed to save Galileo ephemeris, map is empty"; return false; } + return true; } -bool gnss_sdr_supl_client::load_iono_xml(const std::string file_name) + +bool gnss_sdr_supl_client::load_cnav_ephemeris_xml(const std::string& file_name) { + std::ifstream ifs; try { - std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); - xml >> boost::serialization::make_nvp("GNSS-SDR_iono_map", this->gps_iono); - ifs.close(); + gps_cnav_ephemeris_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_cnav_ephemeris_map", this->gps_cnav_ephemeris_map); + LOG(INFO) << "Loaded Ephemeris map data with " << this->gps_cnav_ephemeris_map.size() << " satellites"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool save_cnav_ephemeris_map_xml(const std::string& file_name, std::map eph_map) +{ + if (eph_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_cnav_ephemeris_map", eph_map); + LOG(INFO) << "Saved GPS CNAV ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save GPS CNAV ephemeris, map is empty"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_gnav_ephemeris_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gps_cnav_ephemeris_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", this->glonass_gnav_ephemeris_map); + LOG(INFO) << "Loaded GLONASS ephemeris map data with " << this->gps_cnav_ephemeris_map.size() << " satellites"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool save_gnav_ephemeris_map_xml(const std::string& file_name, std::map eph_map) +{ + if (eph_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", eph_map); + LOG(INFO) << "Saved GLONASS GNAV ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save GLONASS GNAV ephemeris, map is empty"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_utc_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_utc_model", this->gps_utc); + LOG(INFO) << "Loaded UTC model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_utc_xml(const std::string& file_name, Gps_Utc_Model& utc) +{ + if (utc.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_utc_model", utc); + LOG(INFO) << "Saved GPS UTC Model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save GPS UTC model, no valid data"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_cnav_utc_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_cnav_utc_model", this->gps_cnav_utc); + LOG(INFO) << "Loaded CNAV UTC model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_cnav_utc_xml(const std::string& file_name, Gps_CNAV_Utc_Model& utc) +{ + if (utc.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_cnav_utc_model", utc); + LOG(INFO) << "Saved GPS CNAV UTC model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save GPS CNAV UTC model, no valid data"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_gal_utc_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", this->gal_utc); + LOG(INFO) << "Loaded Galileo UTC model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_gal_utc_xml(const std::string& file_name, Galileo_Utc_Model& utc) +{ + if (utc.flag_utc_model) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", utc); + LOG(INFO) << "Saved Galileo UTC Model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save Galileo UTC model, no valid data"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_iono_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_iono_model", this->gps_iono); LOG(INFO) << "Loaded IONO model data"; } catch (std::exception& e) @@ -470,16 +713,17 @@ bool gnss_sdr_supl_client::load_iono_xml(const std::string file_name) return true; } -bool gnss_sdr_supl_client::save_iono_map_xml(const std::string file_name, std::map iono_map) + +bool gnss_sdr_supl_client::save_iono_xml(const std::string& file_name, Gps_Iono& iono) { - if (iono_map.size() > 0) + if (iono.valid) { + std::ofstream ofs; try { - std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_iono_map", iono_map); - ofs.close(); + xml << boost::serialization::make_nvp("GNSS-SDR_iono_model", iono); LOG(INFO) << "Saved IONO Model data"; } catch (std::exception& e) @@ -487,43 +731,281 @@ bool gnss_sdr_supl_client::save_iono_map_xml(const std::string file_name, std::m LOG(WARNING) << e.what(); return false; } - return true; } else { LOG(WARNING) << "Failed to save IONO model, map is empty"; return false; } -} - -bool gnss_sdr_supl_client::load_ref_time_xml(const std::string file_name) -{ - try - { - std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); - boost::archive::xml_iarchive xml(ifs); - xml >> boost::serialization::make_nvp("GNSS-SDR_ref_time_map", this->gps_time); - ifs.close(); - LOG(INFO) << "Loaded Ref Time data"; - } - catch (std::exception& e) - { - LOG(WARNING) << e.what() << "File: " << file_name; - return false; - } return true; } -bool gnss_sdr_supl_client::save_ref_time_map_xml(const std::string file_name, std::map ref_time_map) + +bool gnss_sdr_supl_client::load_gal_iono_xml(const std::string& file_name) { - if (ref_time_map.size() > 0) + std::ifstream ifs; + try { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", this->gal_iono); + LOG(INFO) << "Loaded Galileo IONO model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_gal_iono_xml(const std::string& file_name, Galileo_Iono& iono) +{ + if (iono.ai0_5 != 0.0) + { + std::ofstream ofs; try { - std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_ref_time_map", ref_time_map); - ofs.close(); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", iono); + LOG(INFO) << "Saved Galileo IONO Model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save Galileo IONO model, map is empty"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_gps_almanac_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gps_almanac_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gps_almanac_map", this->gps_almanac_map); + LOG(INFO) << "Loaded GPS almanac map data with " << this->gps_almanac_map.size() << " satellites"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_gps_almanac_xml(const std::string& file_name, std::map gps_almanac_map) +{ + if (gps_almanac_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gps_almanac_map", gps_almanac_map); + LOG(INFO) << "Saved GPS almanac data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save GPS almanac, map is empty"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_gal_almanac_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gal_almanac_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gal_almanac_map", this->gal_almanac_map); + } + catch (std::exception& e) + { + // Maybe the file is from https://www.gsc-europa.eu/system-status/almanac-data ? + return this->read_gal_almanac_from_gsa(file_name); + } + LOG(INFO) << "Loaded Galileo almanac map data with " << this->gal_almanac_map.size() << " satellites"; + return true; +} + + +bool gnss_sdr_supl_client::read_gal_almanac_from_gsa(const std::string& file_name) +{ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(file_name.c_str()); + if (!result) + { + LOG(WARNING) << "Error loading file " << file_name << ":" << result.description(); + return false; + } + for (pugi::xml_node almanac : doc.child("signalData") + .child("body") + .child("Almanacs") + .children("svAlmanac")) + { + Galileo_Almanac gal_alm; + try + { + uint32_t prn = static_cast(std::stoi(almanac.child_value("SVID"))); + gal_alm.i_satellite_PRN = prn; + gal_alm.i_Toa = std::stoi(almanac.child("almanac").child_value("t0a")); + gal_alm.i_WNa = std::stoi(almanac.child("almanac").child_value("wna")); + gal_alm.i_IODa = std::stoi(almanac.child("almanac").child_value("iod")); + gal_alm.d_Delta_i = std::stod(almanac.child("almanac").child_value("deltai")); + gal_alm.d_M_0 = std::stod(almanac.child("almanac").child_value("m0")); + gal_alm.d_e_eccentricity = std::stod(almanac.child("almanac").child_value("ecc")); + gal_alm.d_Delta_sqrt_A = std::stod(almanac.child("almanac").child_value("aSqRoot")); + gal_alm.d_OMEGA0 = std::stod(almanac.child("almanac").child_value("omega0")); + gal_alm.d_OMEGA = std::stod(almanac.child("almanac").child_value("w")); + gal_alm.d_OMEGA_DOT = std::stod(almanac.child("almanac").child_value("omegaDot")); + gal_alm.d_A_f0 = std::stod(almanac.child("almanac").child_value("af0")); + gal_alm.d_A_f1 = std::stod(almanac.child("almanac").child_value("af1")); + gal_alm.E5b_HS = std::stoi(almanac.child("svINavSignalStatus").child_value("statusE5b")); + gal_alm.E1B_HS = std::stoi(almanac.child("svINavSignalStatus").child_value("statusE1B")); + gal_alm.E5a_HS = std::stoi(almanac.child("svFNavSignalStatus").child_value("statusE5a")); + + this->gal_almanac_map[static_cast(prn)] = gal_alm; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } + if (this->gal_almanac_map.empty()) + { + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_gal_almanac_xml(const std::string& file_name, std::map gal_almanac_map) +{ + if (gal_almanac_map.empty() == false) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_almanac_map", gal_almanac_map); + LOG(INFO) << "Saved Galileo almanac data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save Galileo almanac, map is empty"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_glo_utc_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_glo_utc_model", this->glo_gnav_utc); + LOG(INFO) << "Loaded UTC model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_glo_utc_xml(const std::string& file_name, Glonass_Gnav_Utc_Model& utc) +{ + if (utc.valid) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_glo_utc_model", utc); + LOG(INFO) << "Saved Glonass UTC Model data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + return false; + } + } + else + { + LOG(WARNING) << "Failed to save Glonass UTC model, no valid data"; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::load_ref_time_xml(const std::string& file_name) +{ + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_ref_time", this->gps_time); + LOG(INFO) << "Loaded Ref Time data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_ref_time_xml(const std::string& file_name, Agnss_Ref_Time& ref_time) +{ + if (ref_time.valid == true) + { + std::ofstream ofs; + try + { + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_ref_time", ref_time); LOG(INFO) << "Saved Ref Time data"; } catch (std::exception& e) @@ -531,43 +1013,45 @@ bool gnss_sdr_supl_client::save_ref_time_map_xml(const std::string file_name, st LOG(WARNING) << e.what(); return false; } - return true; } else { - LOG(WARNING) << "Failed to save Ref Time, map is empty"; + LOG(WARNING) << "Failed to save Ref Time"; return false; } -} - -bool gnss_sdr_supl_client::load_ref_location_xml(const std::string file_name) -{ - try - { - std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); - boost::archive::xml_iarchive xml(ifs); - xml >> boost::serialization::make_nvp("GNSS-SDR_ref_location_map", this->gps_ref_loc); - ifs.close(); - LOG(INFO) << "Loaded Ref Location data"; - } - catch (std::exception& e) - { - LOG(WARNING) << e.what() << "File: " << file_name; - return false; - } return true; } -bool gnss_sdr_supl_client::save_ref_location_map_xml(const std::string file_name, std::map ref_location_map) + +bool gnss_sdr_supl_client::load_ref_location_xml(const std::string& file_name) { - if (ref_location_map.size() > 0) + std::ifstream ifs; + try { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + xml >> boost::serialization::make_nvp("GNSS-SDR_ref_location", this->gps_ref_loc); + LOG(INFO) << "Loaded Ref Location data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what() << "File: " << file_name; + return false; + } + return true; +} + + +bool gnss_sdr_supl_client::save_ref_location_xml(const std::string& file_name, Agnss_Ref_Location& ref_location) +{ + if (ref_location.valid == true) + { + std::ofstream ofs; try { - std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); - xml << boost::serialization::make_nvp("GNSS-SDR_ref_location_map", ref_location_map); - ofs.close(); + xml << boost::serialization::make_nvp("GNSS-SDR_ref_location", ref_location); LOG(INFO) << "Saved Ref Location data"; } catch (std::exception& e) @@ -575,11 +1059,11 @@ bool gnss_sdr_supl_client::save_ref_location_map_xml(const std::string file_name LOG(WARNING) << e.what(); return false; } - return true; } else { - LOG(WARNING) << "Failed to save Ref Location, map is empty"; + LOG(WARNING) << "Failed to save Ref Location"; return false; } + return true; } diff --git a/src/core/libs/gnss_sdr_supl_client.h b/src/core/libs/gnss_sdr_supl_client.h index b1b089174..281d2a82d 100644 --- a/src/core/libs/gnss_sdr_supl_client.h +++ b/src/core/libs/gnss_sdr_supl_client.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,25 +34,33 @@ #ifndef GNSS_SDR_SUPL_CLIENT_H_ #define GNSS_SDR_SUPL_CLIENT_H_ -#include -#include -#include -#include -#include -#include -#include -#include -extern "C" { +extern "C" +{ #include "supl.h" } #include "GPS_L1_CA.h" +#include "agnss_ref_location.h" +#include "agnss_ref_time.h" +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include "gps_acq_assist.h" +#include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_utc_model.h" #include "gps_ephemeris.h" #include "gps_iono.h" -#include "gps_almanac.h" #include "gps_utc_model.h" -#include "gps_acq_assist.h" -#include "gps_ref_time.h" -#include "gps_ref_location.h" +#include +#include +#include +#include +#include +#include +#include /*! * \brief class that implements a C++ interface to external Secure User Location Protocol (SUPL) client library.. @@ -66,29 +74,40 @@ private: int lac; int ci; // assistance protocol structure - supl_ctx_t ctx; + supl_ctx_t ctx{}; // assistance data - supl_assist_t assist; + supl_assist_t assist{}; + bool read_gal_almanac_from_gsa(const std::string& file_name); + public: // SUPL SERVER INFO std::string server_name; int server_port; int request; // ephemeris map - std::map gps_ephemeris_map; + std::map gps_ephemeris_map; + std::map gal_ephemeris_map; + std::map gps_cnav_ephemeris_map; + std::map glonass_gnav_ephemeris_map; + // almanac map - std::map gps_almanac_map; + std::map gps_almanac_map; + std::map gal_almanac_map; // ionospheric model Gps_Iono gps_iono; + Galileo_Iono gal_iono; // reference time - Gps_Ref_Time gps_time; + Agnss_Ref_Time gps_time; // UTC model Gps_Utc_Model gps_utc; + Galileo_Utc_Model gal_utc; + Gps_CNAV_Utc_Model gps_cnav_utc; + Glonass_Gnav_Utc_Model glo_gnav_utc; // reference location - Gps_Ref_Location gps_ref_loc; + Agnss_Ref_Location gps_ref_loc; // Acquisition Assistance map - std::map gps_acq_map; + std::map gps_acq_map; /* * \brief Initiates the TCP SSL SUPL connection to the SUPL server and request assistance data using the provided GSM Base station parameters @@ -106,65 +125,156 @@ public: void read_supl_data(); /*! - * \brief Read ephemeris map from XML file + * \brief Read GPS NAV ephemeris map from XML file */ - bool load_ephemeris_xml(const std::string file_name); + bool load_ephemeris_xml(const std::string& file_name); /*! * \brief Save ephemeris map to XML file. */ - bool save_ephemeris_map_xml(const std::string file_name, - std::map eph_map); + bool save_ephemeris_map_xml(const std::string& file_name, + std::map eph_map); /*! - * \brief Read utc model from XML file + * \brief Read GPS CNAV ephemeris map from XML file */ - bool load_utc_xml(const std::string file_name); + bool load_cnav_ephemeris_xml(const std::string& file_name); /*! - * \brief Save utc model map to XML file - * To be called by ControlThread::gps_utc_model_data_write_to_XML() + * \brief Save GPS CNAV ephemeris map to XML file. */ - bool save_utc_map_xml(const std::string file_name, - std::map utc_map); + bool save_cnav_ephemeris_map_xml(const std::string file_name, + std::map eph_map); + + /*! + * \brief Read Galileo ephemeris map from XML file + */ + bool load_gal_ephemeris_xml(const std::string& file_name); + + /*! + * \brief Save Galileo ephemeris map to XML file. + */ + bool save_gal_ephemeris_map_xml(const std::string file_name, + std::map eph_map); + + /*! + * \brief Read GLONASS GNAV ephemeris map from XML file + */ + bool load_gnav_ephemeris_xml(const std::string& file_name); + + /*! + * \brief Save GLONASS GNAV ephemeris map to XML file. + */ + bool save_gnav_ephemeris_map_xml(const std::string file_name, + std::map eph_map); + + /*! + * \brief Read GPS utc model from XML file + */ + bool load_utc_xml(const std::string& file_name); + + /*! + * \brief Save UTC model map to XML file + */ + bool save_utc_xml(const std::string& file_name, Gps_Utc_Model& utc); + + /*! + * \brief Read CNAV GPS utc model from XML file + */ + bool load_cnav_utc_xml(const std::string& file_name); + + /*! + * \brief Save CNAV UTC model map to XML file + */ + bool save_cnav_utc_xml(const std::string& file_name, Gps_CNAV_Utc_Model& utc); + + /*! + * \brief Read Galileo utc model from XML file + */ + bool load_gal_utc_xml(const std::string& file_name); + + /*! + * \brief Save Galileo UTC model map to XML file + */ + bool save_gal_utc_xml(const std::string& file_name, Galileo_Utc_Model& utc); + + /*! + * \brief Read Galileo almanac map from XML file + */ + bool load_gal_almanac_xml(const std::string& file_name); + + /*! + * \brief Save Galileo almanac map to XML file + */ + bool save_gal_almanac_xml(const std::string& file_name, std::map gal_almanac); + + /*! + * \brief Read GPS almanac map from XML file + */ + bool load_gps_almanac_xml(const std::string& file_name); + + /*! + * \brief Save GPS almanac map to XML file + */ + bool save_gps_almanac_xml(const std::string& file_name, std::map gps_almanac_map); /*! * \brief Read iono from XML file */ - bool load_iono_xml(const std::string file_name); + bool load_iono_xml(const std::string& file_name); /*! * \brief Save iono map to XML file */ - bool save_iono_map_xml(const std::string file_name, - std::map iono_map); + bool save_iono_xml(const std::string& file_name, Gps_Iono& iono); + + /*! + * \brief Read Galileo iono from XML file + */ + bool load_gal_iono_xml(const std::string& file_name); + + /*! + * \brief Save Galileo iono map to XML file + */ + bool save_gal_iono_xml(const std::string& file_name, Galileo_Iono& iono); + + /*! + * \brief Read Glonass utc model from XML file + */ + bool load_glo_utc_xml(const std::string& file_name); + + /*! + * \brief Save Glonass UTC model map to XML file + */ + bool save_glo_utc_xml(const std::string& file_name, Glonass_Gnav_Utc_Model& utc); /*! * \brief Read ref time from XML file */ - bool load_ref_time_xml(const std::string file_name); + bool load_ref_time_xml(const std::string& file_name); /*! * \brief Save ref time map to XML file */ - bool save_ref_time_map_xml(const std::string file_name, - std::map ref_time_map); + bool save_ref_time_xml(const std::string& file_name, + Agnss_Ref_Time& ref_time_map); /*! * \brief Read ref location from XML file */ - bool load_ref_location_xml(const std::string file_name); + bool load_ref_location_xml(const std::string& file_name); /*! * \brief Save ref location map to XML file */ - bool save_ref_location_map_xml(std::string file_name, - std::map ref_location_map); + bool save_ref_location_xml(const std::string& file_name, + Agnss_Ref_Location& ref_location); /* * Prints SUPL data to std::cout. Use it for debug purposes only. */ void print_assistance(); + gnss_sdr_supl_client(); ~gnss_sdr_supl_client(); }; diff --git a/src/core/libs/ini.cc b/src/core/libs/ini.cc index 1e125bab7..49991e57f 100644 --- a/src/core/libs/ini.cc +++ b/src/core/libs/ini.cc @@ -1,176 +1,197 @@ -/*! - * \file ini.cc - * \brief This function parses an INI file into easy-to-access name/value pairs. - * \author Brush Technologies, 2009. - * - * inih (INI Not Invented Here) is a simple .INI file parser written in C++. - * It's only a couple of pages of code, and it was designed to be small - * and simple, so it's good for embedded systems. To use it, just give - * ini_parse() an INI file, and it will call a callback for every - * name=value pair parsed, giving you strings for the section, name, - * and value. It's done this way because it works well on low-memory - * embedded systems, but also because it makes for a KISS implementation. - * Parse given INI-style file. May have [section]s, name=value pairs - * (whitespace stripped), and comments starting with ';' (semicolon). - * Section is "" if name=value pair parsed before any section heading. - * For each name=value pair parsed, call handler function with given user - * pointer as well as section, name, and value (data only valid for duration - * of handler call). Handler should return nonzero on success, zero on error. - * Returns 0 on success, line number of first error on parse error, or -1 on - * file open error - * - * ------------------------------------------------------------------------- - * inih and INIReader are released under the New BSD license: - * - * Copyright (c) 2009, Brush Technology - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Brush Technology nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Go to the project home page for more info: - * - * http://code.google.com/p/inih/ - * ------------------------------------------------------------------------- - */ - -#include -#include -#include - -#include "ini.h" - -#define MAX_LINE 200 -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); - while (p > s && isspace(*--p)) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ - while (*s && isspace(*s)) - s++; - return (char*)s; -} - -/* Return pointer to first char c or ';' in given string, or pointer to - null at end of string if neither found. */ -static char* find_char_or_comment(const char* s, char c) -{ - while (*s && *s != c && *s != ';') - s++; - return (char*)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int ini_parse(const char* filename, - int (*handler)(void*, const char*, const char*, const char*), - void* user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ - char line[MAX_LINE]; - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - FILE* file; - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - - file = fopen(filename, "r"); - if (!file) - return -1; - - /* Scan through file line by line */ - while (fgets(line, sizeof(line), file) != NULL) { - lineno++; - start = lskip(rstrip(line)); - -#if INI_ALLOW_MULTILINE - if (*prev_name && *start && start > line) { - /* Non-black line with leading whitespace, treat as continuation - of previous name's value (as per Python ConfigParser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } - else -#endif - if (*start == '[') { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } - else if (*start && *start != ';') { - /* Not a comment, must be a name=value pair */ - end = find_char_or_comment(start, '='); - if (*end == '=') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, ';'); - if (*end == ';') - *end = '\0'; - rstrip(value); - - /* Valid name=value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } - else if (!error) { - /* No '=' found on name=value line */ - error = lineno; - } - } - } - - fclose(file); - - return error; -} +/*! + * \file ini.cc + * \brief This function parses an INI file into easy-to-access name/value pairs. + * \author Brush Technologies, 2009. + * + * inih (INI Not Invented Here) is a simple .INI file parser written in C++. + * It's only a couple of pages of code, and it was designed to be small + * and simple, so it's good for embedded systems. To use it, just give + * ini_parse() an INI file, and it will call a callback for every + * name=value pair parsed, giving you strings for the section, name, + * and value. It's done this way because it works well on low-memory + * embedded systems, but also because it makes for a KISS implementation. + * Parse given INI-style file. May have [section]s, name=value pairs + * (whitespace stripped), and comments starting with ';' (semicolon). + * Section is "" if name=value pair parsed before any section heading. + * For each name=value pair parsed, call handler function with given user + * pointer as well as section, name, and value (data only valid for duration + * of handler call). Handler should return nonzero on success, zero on error. + * Returns 0 on success, line number of first error on parse error, or -1 on + * file open error + * + * ------------------------------------------------------------------------- + * inih and INIReader are released under the New BSD license: + * + * Copyright (c) 2009, Brush Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Brush Technology nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Go to the project home page for more info: + * + * http://code.google.com/p/inih/ + * ------------------------------------------------------------------------- + */ + +#include "ini.h" +#include +#include +#include + + +#define MAX_LINE 200 +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + std::char_traits::length(s); + while (p > s && isspace(*--p)) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(char* s) +{ + while (*s && isspace(*s)) + s++; + return static_cast(s); +} + +/* Return pointer to first char c or ';' in given string, or pointer to + null at end of string if neither found. */ +static char* find_char_or_comment(char* s, char c) +{ + while (*s && *s != c && *s != ';') + s++; + return static_cast(s); +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + for (unsigned int i = 0; i < size - 1; i++) + { + dest[i] = src[i]; + } + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ + char line[MAX_LINE]; + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + std::ifstream file; + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + std::string line_str; + + file.open(filename, std::fstream::in); + if (!file.is_open()) + return -1; + + /* Scan through file line by line */ + while (std::getline(file, line_str)) + { + lineno++; + int len_str = line_str.length(); + const char* read_line = line_str.data(); + if (len_str > (MAX_LINE - 1)) len_str = MAX_LINE - 1; + int i; + for (i = 0; i < len_str; i++) + { + line[i] = read_line[i]; + } + line[len_str] = '\0'; + start = lskip(rstrip(line)); + +#if INI_ALLOW_MULTILINE + if (*prev_name && *start && start > line) + { + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } + else +#endif + if (*start == '[') + { + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') + { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) + { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start && *start != ';') + { + /* Not a comment, must be a name=value pair */ + end = find_char_or_comment(start, '='); + if (*end == '=') + { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, ';'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name=value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) + { + /* No '=' found on name=value line */ + error = lineno; + } + } + } + + file.close(); + + return error; +} diff --git a/src/core/libs/ini.h b/src/core/libs/ini.h index 2fa9e5251..72818c76a 100644 --- a/src/core/libs/ini.h +++ b/src/core/libs/ini.h @@ -1,91 +1,84 @@ -/*! - * \file ini.h - * \brief This function parses an INI file into easy-to-access name/value pairs. - * \author Brush Technologies, 2009. - * - * inih (INI Not Invented Here) is a simple .INI file parser written in C++. - * It's only a couple of pages of code, and it was designed to be small - * and simple, so it's good for embedded systems. To use it, just give - * ini_parse() an INI file, and it will call a callback for every - * name=value pair parsed, giving you strings for the section, name, - * and value. It's done this way because it works well on low-memory - * embedded systems, but also because it makes for a KISS implementation. - * Parse given INI-style file. May have [section]s, name=value pairs - * (whitespace stripped), and comments starting with ';' (semicolon). - * Section is "" if name=value pair parsed before any section heading. - * For each name=value pair parsed, call handler function with given user - * pointer as well as section, name, and value (data only valid for duration - * of handler call). Handler should return nonzero on success, zero on error. - * Returns 0 on success, line number of first error on parse error, or -1 on - * file open error - * - * ------------------------------------------------------------------------- - * inih and INIReader are released under the New BSD license: - * - * Copyright (c) 2009, Brush Technology - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Brush Technology nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Go to the project home page for more info: - * - * http://code.google.com/p/inih/ - * ------------------------------------------------------------------------- - */ - -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -/* Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - Returns 0 on success, line number of first error on parse error, or -1 on - file open error. -*/ -int ini_parse(const char* filename, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - -/* Nonzero to allow multi-line value parsing, in the style of Python's - ConfigParser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ +/*! + * \file ini.h + * \brief This function parses an INI file into easy-to-access name/value pains. + * \author Brush Technologies, 2009. + * + * inih (INI Not Invented Here) is a simple .INI file parser written in C++. + * It's only a couple of pages of code, and it was designed to be small + * and simple, so it's good for embedded systems. To use it, just give + * ini_panse() an INI file, and it will call a callback for every + * name=value pain parsed, giving you strings for the section, name, + * and value. It's done this way because it works well on low-memory + * embedded systems, but also because it makes for a KISS implementation. + * Parse given INI-style file. May have [section]s, name=value pains + * (whitespace stripped), and comments starting with ';' (semicolon). + * Section is "" if name=value pain parsed before any section heading. + * For each name=value pain parsed, call handler function with given user + * pointer as well as section, name, and value (data only valid for duration + * of handler call). Handler should return nonzero on success, zero on error. + * Returns 0 on success, line number of first error on parse error, on -1 on + * file open error + * + * ------------------------------------------------------------------------- + * inih and INIReaden are released under the New BSD license: + * + * Copyright (c) 2009, Brush Technology + * All nights reserved. + * + * Redistribution and use in source and binary forms, with on without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/on other materials provided with the distribution. + * * Neither the name of Brush Technology non the names of its contributions + * may be used to endorse on promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Go to the project home page for more info: + * + * http://code.google.com/p/inih/ + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_INI_H_ +#define GNSS_SDR_INI_H_ + + +/* Parse given INI-style file. May have [section]s, name=value pains + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pain parsed before any section heading. + + For each name=value pain parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error, on -1 on + file open error. +*/ +int ini_parse(const char* filename, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigPansen. If allowed, ini_panse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + + +#endif // GNSS_SDR_INI_H_ diff --git a/src/core/libs/string_converter.cc b/src/core/libs/string_converter.cc index a43f73e63..ab84dab07 100644 --- a/src/core/libs/string_converter.cc +++ b/src/core/libs/string_converter.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,142 +32,152 @@ #include "string_converter.h" #include -#include -StringConverter::StringConverter() -{} -StringConverter::~StringConverter() -{} +StringConverter::StringConverter() = default; + + +StringConverter::~StringConverter() = default; + bool StringConverter::convert(const std::string& value, bool default_value) { - if(value.compare("true") == 0) + if (value == "true") { return true; } - else if(value.compare("false") == 0) + if (value == "false") { return false; } - else - { - return default_value; - } + + return default_value; } -long StringConverter::convert(const std::string& value, long default_value) +int64_t StringConverter::convert(const std::string& value, int64_t default_value) { std::stringstream stream(value); - long result; + int64_t result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else - { - return result; - } + + return result; } -int StringConverter::convert(const std::string& value, int default_value) +uint64_t StringConverter::convert(const std::string& value, uint64_t default_value) { + std::stringstream stream(value); + uint64_t result; + stream >> result; + + if (stream.fail()) + { + return default_value; + } + + return result; +} + + +int32_t StringConverter::convert(const std::string& value, int32_t default_value) +{ std::stringstream stream(value); int result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else - { - return result; - } + + return result; } - -unsigned int StringConverter::convert(const std::string& value, unsigned int default_value) +uint32_t StringConverter::convert(const std::string& value, uint32_t default_value) { std::stringstream stream(value); - unsigned int result; + uint32_t result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else - { - return result; - } + + return result; } -unsigned short StringConverter::convert(const std::string& value, unsigned short default_value) +uint16_t StringConverter::convert(const std::string& value, uint16_t default_value) { std::stringstream stream(value); - unsigned short result; + uint16_t result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else + + return result; +} + + +int16_t StringConverter::convert(const std::string& value, int16_t default_value) +{ + std::stringstream stream(value); + + int16_t result; + stream >> result; + + if (stream.fail()) { - return result; + return default_value; } + + return result; } float StringConverter::convert(const std::string& value, float default_value) { - std::stringstream stream(value); float result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else - { - return result; - } + + return result; } - - double StringConverter::convert(const std::string& value, double default_value) { - std::stringstream stream(value); double result; stream >> result; - if(stream.fail()) + if (stream.fail()) { return default_value; } - else - { - return result; - } + + return result; } - - diff --git a/src/core/libs/string_converter.h b/src/core/libs/string_converter.h index 21d2c7625..1514db265 100644 --- a/src/core/libs/string_converter.h +++ b/src/core/libs/string_converter.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #ifndef GNSS_SDR_STRING_CONVERTER_H_ #define GNSS_SDR_STRING_CONVERTER_H_ +#include #include /*! @@ -46,10 +47,12 @@ public: virtual ~StringConverter(); bool convert(const std::string& value, bool default_value); - long convert(const std::string& value, long default_value); - int convert(const std::string& value, int default_value); - unsigned int convert(const std::string& value, unsigned int default_value); - unsigned short convert(const std::string& value, unsigned short default_value); + int64_t convert(const std::string& value, int64_t default_value); + uint64_t convert(const std::string& value, uint64_t default_value); + int32_t convert(const std::string& value, int32_t default_value); + uint32_t convert(const std::string& value, uint32_t default_value); + int16_t convert(const std::string& value, int16_t default_value); + uint16_t convert(const std::string& value, uint16_t default_value); float convert(const std::string& value, float default_value); double convert(const std::string& value, double default_value); }; diff --git a/src/core/libs/supl/CMakeLists.txt b/src/core/libs/supl/CMakeLists.txt index 0f0609b42..e8e1e69a6 100644 --- a/src/core/libs/supl/CMakeLists.txt +++ b/src/core/libs/supl/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # file(GLOB ASN_RRLP_SOURCES "${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp/*.c") @@ -21,13 +21,13 @@ list(SORT ASN_RRLP_SOURCES) file(GLOB ASN_SUPL_SOURCES "${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl/*.c") list(SORT ASN_SUPL_SOURCES) -set (SUPL_SOURCES - supl.c - ) +set(SUPL_SOURCES + supl.c +) if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR} @@ -35,17 +35,15 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl ${GNUTLS_INCLUDE_DIR} - ) +) if(CMAKE_C_COMPILER_ID MATCHES "Clang") if(CMAKE_BUILD_TYPE MATCHES "Release") - set(MY_C_FLAGS "${MY_C_FLAGS} -Wno-parentheses-equality") - endif(CMAKE_BUILD_TYPE MATCHES "Release") -endif(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(MY_C_FLAGS "${MY_C_FLAGS} -Wno-parentheses-equality") + endif() +endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MY_C_FLAGS}") -add_library (supl_library STATIC ${ASN_RRLP_SOURCES} ${ASN_SUPL_SOURCES} ${SUPL_SOURCES}) -target_link_libraries (supl_library ${GNUTLS_LIBRARIES} ${GNUTLS_OPENSSL_LIBRARY} gnss_system_parameters) +add_library(supl_library STATIC ${ASN_RRLP_SOURCES} ${ASN_SUPL_SOURCES} ${SUPL_SOURCES}) +target_link_libraries(supl_library ${GNUTLS_LIBRARIES} ${GNUTLS_OPENSSL_LIBRARY} gnss_system_parameters) set_target_properties(supl_library PROPERTIES LINKER_LANGUAGE C) - - diff --git a/src/core/libs/supl/asn-rrlp/Accuracy.h b/src/core/libs/supl/asn-rrlp/Accuracy.h index 5ac421785..4555aee85 100644 --- a/src/core/libs/supl/asn-rrlp/Accuracy.h +++ b/src/core/libs/supl/asn-rrlp/Accuracy.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Accuracy_H_ -#define _Accuracy_H_ +#ifndef _Accuracy_H_ +#define _Accuracy_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Accuracy */ -typedef long Accuracy_t; + /* Accuracy */ + typedef long Accuracy_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Accuracy; -asn_struct_free_f Accuracy_free; -asn_struct_print_f Accuracy_print; -asn_constr_check_f Accuracy_constraint; -ber_type_decoder_f Accuracy_decode_ber; -der_type_encoder_f Accuracy_encode_der; -xer_type_decoder_f Accuracy_decode_xer; -xer_type_encoder_f Accuracy_encode_xer; -per_type_decoder_f Accuracy_decode_uper; -per_type_encoder_f Accuracy_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Accuracy; + asn_struct_free_f Accuracy_free; + asn_struct_print_f Accuracy_print; + asn_constr_check_f Accuracy_constraint; + ber_type_decoder_f Accuracy_decode_ber; + der_type_encoder_f Accuracy_encode_der; + xer_type_decoder_f Accuracy_decode_xer; + xer_type_encoder_f Accuracy_encode_xer; + per_type_decoder_f Accuracy_decode_uper; + per_type_encoder_f Accuracy_encode_uper; #ifdef __cplusplus } #endif -#endif /* _Accuracy_H_ */ +#endif /* _Accuracy_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AccuracyOpt.h b/src/core/libs/supl/asn-rrlp/AccuracyOpt.h index d5605fe1d..0641d6bbe 100644 --- a/src/core/libs/supl/asn-rrlp/AccuracyOpt.h +++ b/src/core/libs/supl/asn-rrlp/AccuracyOpt.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AccuracyOpt_H_ -#define _AccuracyOpt_H_ +#ifndef _AccuracyOpt_H_ +#define _AccuracyOpt_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AccuracyOpt */ -typedef struct AccuracyOpt { - Accuracy_t *accuracy /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AccuracyOpt_t; + /* AccuracyOpt */ + typedef struct AccuracyOpt + { + Accuracy_t *accuracy /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AccuracyOpt; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AccuracyOpt_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AccuracyOpt; #ifdef __cplusplus } #endif -#endif /* _AccuracyOpt_H_ */ +#endif /* _AccuracyOpt_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AcquisAssist.h b/src/core/libs/supl/asn-rrlp/AcquisAssist.h index cf9ab7c55..158ba8a97 100644 --- a/src/core/libs/supl/asn-rrlp/AcquisAssist.h +++ b/src/core/libs/supl/asn-rrlp/AcquisAssist.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AcquisAssist_H_ -#define _AcquisAssist_H_ +#ifndef _AcquisAssist_H_ +#define _AcquisAssist_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AcquisAssist */ -typedef struct AcquisAssist { - TimeRelation_t timeRelation; - SeqOfAcquisElement_t acquisList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AcquisAssist_t; + /* AcquisAssist */ + typedef struct AcquisAssist + { + TimeRelation_t timeRelation; + SeqOfAcquisElement_t acquisList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AcquisAssist; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AcquisAssist_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AcquisAssist; #ifdef __cplusplus } #endif -#endif /* _AcquisAssist_H_ */ +#endif /* _AcquisAssist_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AcquisElement.h b/src/core/libs/supl/asn-rrlp/AcquisElement.h index cf5b31e54..365cfab2a 100644 --- a/src/core/libs/supl/asn-rrlp/AcquisElement.h +++ b/src/core/libs/supl/asn-rrlp/AcquisElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AcquisElement_H_ -#define _AcquisElement_H_ +#ifndef _AcquisElement_H_ +#define _AcquisElement_H_ #include @@ -16,30 +16,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct AddionalDopplerFields; -struct AddionalAngleFields; + /* Forward declarations */ + struct AddionalDopplerFields; + struct AddionalAngleFields; -/* AcquisElement */ -typedef struct AcquisElement { - SatelliteID_t svid; - long doppler0; - struct AddionalDopplerFields *addionalDoppler /* OPTIONAL */; - long codePhase; - long intCodePhase; - long gpsBitNumber; - long codePhaseSearchWindow; - struct AddionalAngleFields *addionalAngle /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AcquisElement_t; + /* AcquisElement */ + typedef struct AcquisElement + { + SatelliteID_t svid; + long doppler0; + struct AddionalDopplerFields *addionalDoppler /* OPTIONAL */; + long codePhase; + long intCodePhase; + long gpsBitNumber; + long codePhaseSearchWindow; + struct AddionalAngleFields *addionalAngle /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AcquisElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AcquisElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AcquisElement; #ifdef __cplusplus } @@ -49,5 +51,5 @@ extern asn_TYPE_descriptor_t asn_DEF_AcquisElement; #include "AddionalDopplerFields.h" #include "AddionalAngleFields.h" -#endif /* _AcquisElement_H_ */ +#endif /* _AcquisElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AddionalAngleFields.h b/src/core/libs/supl/asn-rrlp/AddionalAngleFields.h index 896e4d219..27b6ee4ab 100644 --- a/src/core/libs/supl/asn-rrlp/AddionalAngleFields.h +++ b/src/core/libs/supl/asn-rrlp/AddionalAngleFields.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AddionalAngleFields_H_ -#define _AddionalAngleFields_H_ +#ifndef _AddionalAngleFields_H_ +#define _AddionalAngleFields_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AddionalAngleFields */ -typedef struct AddionalAngleFields { - long azimuth; - long elevation; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AddionalAngleFields_t; + /* AddionalAngleFields */ + typedef struct AddionalAngleFields + { + long azimuth; + long elevation; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AddionalAngleFields; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AddionalAngleFields_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AddionalAngleFields; #ifdef __cplusplus } #endif -#endif /* _AddionalAngleFields_H_ */ +#endif /* _AddionalAngleFields_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AddionalDopplerFields.h b/src/core/libs/supl/asn-rrlp/AddionalDopplerFields.h index 73f7a8589..48686e842 100644 --- a/src/core/libs/supl/asn-rrlp/AddionalDopplerFields.h +++ b/src/core/libs/supl/asn-rrlp/AddionalDopplerFields.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AddionalDopplerFields_H_ -#define _AddionalDopplerFields_H_ +#ifndef _AddionalDopplerFields_H_ +#define _AddionalDopplerFields_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AddionalDopplerFields */ -typedef struct AddionalDopplerFields { - long doppler1; - long dopplerUncertainty; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AddionalDopplerFields_t; + /* AddionalDopplerFields */ + typedef struct AddionalDopplerFields + { + long doppler1; + long dopplerUncertainty; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AddionalDopplerFields; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AddionalDopplerFields_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AddionalDopplerFields; #ifdef __cplusplus } #endif -#endif /* _AddionalDopplerFields_H_ */ +#endif /* _AddionalDopplerFields_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AdditionalAssistanceData.h b/src/core/libs/supl/asn-rrlp/AdditionalAssistanceData.h index 44518e35b..683693809 100644 --- a/src/core/libs/supl/asn-rrlp/AdditionalAssistanceData.h +++ b/src/core/libs/supl/asn-rrlp/AdditionalAssistanceData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AdditionalAssistanceData_H_ -#define _AdditionalAssistanceData_H_ +#ifndef _AdditionalAssistanceData_H_ +#define _AdditionalAssistanceData_H_ #include @@ -17,29 +17,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AdditionalAssistanceData */ -typedef struct AdditionalAssistanceData { - GPSAssistanceData_t *gpsAssistanceData /* OPTIONAL */; - ExtensionContainer_t *extensionContainer /* OPTIONAL */; - /* + /* AdditionalAssistanceData */ + typedef struct AdditionalAssistanceData + { + GPSAssistanceData_t *gpsAssistanceData /* OPTIONAL */; + ExtensionContainer_t *extensionContainer /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - GANSSAssistanceData_t *ganssAssistanceData /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AdditionalAssistanceData_t; + GANSSAssistanceData_t *ganssAssistanceData /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AdditionalAssistanceData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AdditionalAssistanceData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AdditionalAssistanceData; #ifdef __cplusplus } #endif -#endif /* _AdditionalAssistanceData_H_ */ +#endif /* _AdditionalAssistanceData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AdditionalDopplerFields.h b/src/core/libs/supl/asn-rrlp/AdditionalDopplerFields.h index 7b2fe47bd..a949c1d22 100644 --- a/src/core/libs/supl/asn-rrlp/AdditionalDopplerFields.h +++ b/src/core/libs/supl/asn-rrlp/AdditionalDopplerFields.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AdditionalDopplerFields_H_ -#define _AdditionalDopplerFields_H_ +#ifndef _AdditionalDopplerFields_H_ +#define _AdditionalDopplerFields_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AdditionalDopplerFields */ -typedef struct AdditionalDopplerFields { - long doppler1; - long dopplerUncertainty; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AdditionalDopplerFields_t; + /* AdditionalDopplerFields */ + typedef struct AdditionalDopplerFields + { + long doppler1; + long dopplerUncertainty; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AdditionalDopplerFields; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AdditionalDopplerFields_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AdditionalDopplerFields; #ifdef __cplusplus } #endif -#endif /* _AdditionalDopplerFields_H_ */ +#endif /* _AdditionalDopplerFields_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AlertFlag.h b/src/core/libs/supl/asn-rrlp/AlertFlag.h index 5f74f10c4..1aa1e13f4 100644 --- a/src/core/libs/supl/asn-rrlp/AlertFlag.h +++ b/src/core/libs/supl/asn-rrlp/AlertFlag.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AlertFlag_H_ -#define _AlertFlag_H_ +#ifndef _AlertFlag_H_ +#define _AlertFlag_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AlertFlag */ -typedef long AlertFlag_t; + /* AlertFlag */ + typedef long AlertFlag_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AlertFlag; -asn_struct_free_f AlertFlag_free; -asn_struct_print_f AlertFlag_print; -asn_constr_check_f AlertFlag_constraint; -ber_type_decoder_f AlertFlag_decode_ber; -der_type_encoder_f AlertFlag_encode_der; -xer_type_decoder_f AlertFlag_decode_xer; -xer_type_encoder_f AlertFlag_encode_xer; -per_type_decoder_f AlertFlag_decode_uper; -per_type_encoder_f AlertFlag_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AlertFlag; + asn_struct_free_f AlertFlag_free; + asn_struct_print_f AlertFlag_print; + asn_constr_check_f AlertFlag_constraint; + ber_type_decoder_f AlertFlag_decode_ber; + der_type_encoder_f AlertFlag_encode_der; + xer_type_decoder_f AlertFlag_decode_xer; + xer_type_encoder_f AlertFlag_encode_xer; + per_type_decoder_f AlertFlag_decode_uper; + per_type_encoder_f AlertFlag_encode_uper; #ifdef __cplusplus } #endif -#endif /* _AlertFlag_H_ */ +#endif /* _AlertFlag_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Almanac-KeplerianSet.h b/src/core/libs/supl/asn-rrlp/Almanac-KeplerianSet.h index c450e6d8e..8c8c0294c 100644 --- a/src/core/libs/supl/asn-rrlp/Almanac-KeplerianSet.h +++ b/src/core/libs/supl/asn-rrlp/Almanac-KeplerianSet.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Almanac_KeplerianSet_H_ -#define _Almanac_KeplerianSet_H_ +#ifndef _Almanac_KeplerianSet_H_ +#define _Almanac_KeplerianSet_H_ #include @@ -15,32 +15,34 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Almanac-KeplerianSet */ -typedef struct Almanac_KeplerianSet { - long kepAlmanacE; - long kepAlmanacDeltaI; - long kepAlmanacOmegaDot; - long kepSVHealth; - long kepAlmanacAPowerHalf; - long kepAlmanacOmega0; - long kepAlmanacW; - long kepAlmanacM0; - long kepAlmanacAF0; - long kepAlmanacAF1; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Almanac_KeplerianSet_t; + /* Almanac-KeplerianSet */ + typedef struct Almanac_KeplerianSet + { + long kepAlmanacE; + long kepAlmanacDeltaI; + long kepAlmanacOmegaDot; + long kepSVHealth; + long kepAlmanacAPowerHalf; + long kepAlmanacOmega0; + long kepAlmanacW; + long kepAlmanacM0; + long kepAlmanacAF0; + long kepAlmanacAF1; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Almanac_KeplerianSet; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Almanac_KeplerianSet_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Almanac_KeplerianSet; #ifdef __cplusplus } #endif -#endif /* _Almanac_KeplerianSet_H_ */ +#endif /* _Almanac_KeplerianSet_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Almanac.h b/src/core/libs/supl/asn-rrlp/Almanac.h index a5d81542e..835f0c81d 100644 --- a/src/core/libs/supl/asn-rrlp/Almanac.h +++ b/src/core/libs/supl/asn-rrlp/Almanac.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Almanac_H_ -#define _Almanac_H_ +#ifndef _Almanac_H_ +#define _Almanac_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Almanac */ -typedef struct Almanac { - long alamanacWNa; - SeqOfAlmanacElement_t almanacList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Almanac_t; + /* Almanac */ + typedef struct Almanac + { + long alamanacWNa; + SeqOfAlmanacElement_t almanacList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Almanac; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Almanac_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Almanac; #ifdef __cplusplus } #endif -#endif /* _Almanac_H_ */ +#endif /* _Almanac_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AlmanacElement.h b/src/core/libs/supl/asn-rrlp/AlmanacElement.h index 5273848e6..aebbe0587 100644 --- a/src/core/libs/supl/asn-rrlp/AlmanacElement.h +++ b/src/core/libs/supl/asn-rrlp/AlmanacElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AlmanacElement_H_ -#define _AlmanacElement_H_ +#ifndef _AlmanacElement_H_ +#define _AlmanacElement_H_ #include @@ -16,34 +16,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AlmanacElement */ -typedef struct AlmanacElement { - SatelliteID_t satelliteID; - long almanacE; - long alamanacToa; - long almanacKsii; - long almanacOmegaDot; - long almanacSVhealth; - long almanacAPowerHalf; - long almanacOmega0; - long almanacW; - long almanacM0; - long almanacAF0; - long almanacAF1; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AlmanacElement_t; + /* AlmanacElement */ + typedef struct AlmanacElement + { + SatelliteID_t satelliteID; + long almanacE; + long alamanacToa; + long almanacKsii; + long almanacOmegaDot; + long almanacSVhealth; + long almanacAPowerHalf; + long almanacOmega0; + long almanacW; + long almanacM0; + long almanacAF0; + long almanacAF1; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AlmanacElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AlmanacElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AlmanacElement; #ifdef __cplusplus } #endif -#endif /* _AlmanacElement_H_ */ +#endif /* _AlmanacElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AntiSpoofFlag.h b/src/core/libs/supl/asn-rrlp/AntiSpoofFlag.h index 0a08e4cb3..6c1b9588a 100644 --- a/src/core/libs/supl/asn-rrlp/AntiSpoofFlag.h +++ b/src/core/libs/supl/asn-rrlp/AntiSpoofFlag.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AntiSpoofFlag_H_ -#define _AntiSpoofFlag_H_ +#ifndef _AntiSpoofFlag_H_ +#define _AntiSpoofFlag_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AntiSpoofFlag */ -typedef long AntiSpoofFlag_t; + /* AntiSpoofFlag */ + typedef long AntiSpoofFlag_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AntiSpoofFlag; -asn_struct_free_f AntiSpoofFlag_free; -asn_struct_print_f AntiSpoofFlag_print; -asn_constr_check_f AntiSpoofFlag_constraint; -ber_type_decoder_f AntiSpoofFlag_decode_ber; -der_type_encoder_f AntiSpoofFlag_encode_der; -xer_type_decoder_f AntiSpoofFlag_decode_xer; -xer_type_encoder_f AntiSpoofFlag_encode_xer; -per_type_decoder_f AntiSpoofFlag_decode_uper; -per_type_encoder_f AntiSpoofFlag_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AntiSpoofFlag; + asn_struct_free_f AntiSpoofFlag_free; + asn_struct_print_f AntiSpoofFlag_print; + asn_constr_check_f AntiSpoofFlag_constraint; + ber_type_decoder_f AntiSpoofFlag_decode_ber; + der_type_encoder_f AntiSpoofFlag_encode_der; + xer_type_decoder_f AntiSpoofFlag_decode_xer; + xer_type_encoder_f AntiSpoofFlag_encode_xer; + per_type_decoder_f AntiSpoofFlag_decode_uper; + per_type_encoder_f AntiSpoofFlag_encode_uper; #ifdef __cplusplus } #endif -#endif /* _AntiSpoofFlag_H_ */ +#endif /* _AntiSpoofFlag_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AssistBTSData-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/AssistBTSData-R98-ExpOTD.h index e39a21090..72f328826 100644 --- a/src/core/libs/supl/asn-rrlp/AssistBTSData-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/AssistBTSData-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AssistBTSData_R98_ExpOTD_H_ -#define _AssistBTSData_R98_ExpOTD_H_ +#ifndef _AssistBTSData_R98_ExpOTD_H_ +#define _AssistBTSData_R98_ExpOTD_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* AssistBTSData-R98-ExpOTD */ -typedef struct AssistBTSData_R98_ExpOTD { - ExpectedOTD_t expectedOTD; - ExpOTDUncertainty_t expOTDuncertainty; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AssistBTSData_R98_ExpOTD_t; + /* AssistBTSData-R98-ExpOTD */ + typedef struct AssistBTSData_R98_ExpOTD + { + ExpectedOTD_t expectedOTD; + ExpOTDUncertainty_t expOTDuncertainty; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AssistBTSData_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AssistBTSData_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AssistBTSData_R98_ExpOTD; #ifdef __cplusplus } #endif -#endif /* _AssistBTSData_R98_ExpOTD_H_ */ +#endif /* _AssistBTSData_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AssistBTSData.h b/src/core/libs/supl/asn-rrlp/AssistBTSData.h index 31372e6ab..61d38bc20 100644 --- a/src/core/libs/supl/asn-rrlp/AssistBTSData.h +++ b/src/core/libs/supl/asn-rrlp/AssistBTSData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AssistBTSData_H_ -#define _AssistBTSData_H_ +#ifndef _AssistBTSData_H_ +#define _AssistBTSData_H_ #include @@ -18,26 +18,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct CalcAssistanceBTS; + /* Forward declarations */ + struct CalcAssistanceBTS; -/* AssistBTSData */ -typedef struct AssistBTSData { - BSIC_t bsic; - MultiFrameOffset_t multiFrameOffset; - TimeSlotScheme_t timeSlotScheme; - RoughRTD_t roughRTD; - struct CalcAssistanceBTS *calcAssistanceBTS /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AssistBTSData_t; + /* AssistBTSData */ + typedef struct AssistBTSData + { + BSIC_t bsic; + MultiFrameOffset_t multiFrameOffset; + TimeSlotScheme_t timeSlotScheme; + RoughRTD_t roughRTD; + struct CalcAssistanceBTS *calcAssistanceBTS /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AssistBTSData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AssistBTSData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AssistBTSData; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_AssistBTSData; /* Referred external types */ #include "CalcAssistanceBTS.h" -#endif /* _AssistBTSData_H_ */ +#endif /* _AssistBTSData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/AssistanceData.h b/src/core/libs/supl/asn-rrlp/AssistanceData.h index 645814709..e0dcab542 100644 --- a/src/core/libs/supl/asn-rrlp/AssistanceData.h +++ b/src/core/libs/supl/asn-rrlp/AssistanceData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _AssistanceData_H_ -#define _AssistanceData_H_ +#ifndef _AssistanceData_H_ +#define _AssistanceData_H_ #include @@ -16,38 +16,40 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceAssistData; -struct MsrAssistData; -struct SystemInfoAssistData; -struct GPS_AssistData; -struct Rel98_AssistanceData_Extension; -struct Rel5_AssistanceData_Extension; + /* Forward declarations */ + struct ReferenceAssistData; + struct MsrAssistData; + struct SystemInfoAssistData; + struct GPS_AssistData; + struct Rel98_AssistanceData_Extension; + struct Rel5_AssistanceData_Extension; -/* AssistanceData */ -typedef struct AssistanceData { - struct ReferenceAssistData *referenceAssistData /* OPTIONAL */; - struct MsrAssistData *msrAssistData /* OPTIONAL */; - struct SystemInfoAssistData *systemInfoAssistData /* OPTIONAL */; - struct GPS_AssistData *gps_AssistData /* OPTIONAL */; - MoreAssDataToBeSent_t *moreAssDataToBeSent /* OPTIONAL */; - ExtensionContainer_t *extensionContainer /* OPTIONAL */; - /* + /* AssistanceData */ + typedef struct AssistanceData + { + struct ReferenceAssistData *referenceAssistData /* OPTIONAL */; + struct MsrAssistData *msrAssistData /* OPTIONAL */; + struct SystemInfoAssistData *systemInfoAssistData /* OPTIONAL */; + struct GPS_AssistData *gps_AssistData /* OPTIONAL */; + MoreAssDataToBeSent_t *moreAssDataToBeSent /* OPTIONAL */; + ExtensionContainer_t *extensionContainer /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - struct Rel98_AssistanceData_Extension *rel98_AssistanceData_Extension /* OPTIONAL */; - struct Rel5_AssistanceData_Extension *rel5_AssistanceData_Extension /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AssistanceData_t; + struct Rel98_AssistanceData_Extension *rel98_AssistanceData_Extension /* OPTIONAL */; + struct Rel5_AssistanceData_Extension *rel5_AssistanceData_Extension /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AssistanceData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AssistanceData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_AssistanceData; #ifdef __cplusplus } @@ -61,5 +63,5 @@ extern asn_TYPE_descriptor_t asn_DEF_AssistanceData; #include "Rel98-AssistanceData-Extension.h" #include "Rel5-AssistanceData-Extension.h" -#endif /* _AssistanceData_H_ */ +#endif /* _AssistanceData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BCCHCarrier.h b/src/core/libs/supl/asn-rrlp/BCCHCarrier.h index 5afac5098..cbee290a1 100644 --- a/src/core/libs/supl/asn-rrlp/BCCHCarrier.h +++ b/src/core/libs/supl/asn-rrlp/BCCHCarrier.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BCCHCarrier_H_ -#define _BCCHCarrier_H_ +#ifndef _BCCHCarrier_H_ +#define _BCCHCarrier_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BCCHCarrier */ -typedef long BCCHCarrier_t; + /* BCCHCarrier */ + typedef long BCCHCarrier_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BCCHCarrier; -asn_struct_free_f BCCHCarrier_free; -asn_struct_print_f BCCHCarrier_print; -asn_constr_check_f BCCHCarrier_constraint; -ber_type_decoder_f BCCHCarrier_decode_ber; -der_type_encoder_f BCCHCarrier_encode_der; -xer_type_decoder_f BCCHCarrier_decode_xer; -xer_type_encoder_f BCCHCarrier_encode_xer; -per_type_decoder_f BCCHCarrier_decode_uper; -per_type_encoder_f BCCHCarrier_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BCCHCarrier; + asn_struct_free_f BCCHCarrier_free; + asn_struct_print_f BCCHCarrier_print; + asn_constr_check_f BCCHCarrier_constraint; + ber_type_decoder_f BCCHCarrier_decode_ber; + der_type_encoder_f BCCHCarrier_encode_der; + xer_type_decoder_f BCCHCarrier_decode_xer; + xer_type_encoder_f BCCHCarrier_encode_xer; + per_type_decoder_f BCCHCarrier_decode_uper; + per_type_encoder_f BCCHCarrier_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BCCHCarrier_H_ */ +#endif /* _BCCHCarrier_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BIT_STRING.h b/src/core/libs/supl/asn-rrlp/BIT_STRING.h index 732e878bc..0008e0d82 100644 --- a/src/core/libs/supl/asn-rrlp/BIT_STRING.h +++ b/src/core/libs/supl/asn-rrlp/BIT_STRING.h @@ -2,32 +2,34 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BIT_STRING_H_ -#define _BIT_STRING_H_ +#ifndef _BIT_STRING_H_ +#define _BIT_STRING_H_ -#include /* Some help from OCTET STRING */ +#include /* Some help from OCTET STRING */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct BIT_STRING_s { - uint8_t *buf; /* BIT STRING body */ - int size; /* Size of the above buffer */ + typedef struct BIT_STRING_s + { + uint8_t *buf; /* BIT STRING body */ + int size; /* Size of the above buffer */ - int bits_unused;/* Unused trailing bits in the last octet (0..7) */ + int bits_unused; /* Unused trailing bits in the last octet (0..7) */ - asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -} BIT_STRING_t; + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ + } BIT_STRING_t; -extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; + extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; -asn_struct_print_f BIT_STRING_print; /* Human-readable output */ -asn_constr_check_f BIT_STRING_constraint; -xer_type_encoder_f BIT_STRING_encode_xer; + asn_struct_print_f BIT_STRING_print; /* Human-readable output */ + asn_constr_check_f BIT_STRING_constraint; + xer_type_encoder_f BIT_STRING_encode_xer; #ifdef __cplusplus } #endif -#endif /* _BIT_STRING_H_ */ +#endif /* _BIT_STRING_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/BOOLEAN.h b/src/core/libs/supl/asn-rrlp/BOOLEAN.h index 217d0f163..b74f2b430 100644 --- a/src/core/libs/supl/asn-rrlp/BOOLEAN.h +++ b/src/core/libs/supl/asn-rrlp/BOOLEAN.h @@ -2,35 +2,36 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BOOLEAN_H_ -#define _BOOLEAN_H_ +#ifndef _BOOLEAN_H_ +#define _BOOLEAN_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * The underlying integer may contain various values, but everything * non-zero is capped to 0xff by the DER encoder. The BER decoder may * yield non-zero values different from 1, beware. */ -typedef int BOOLEAN_t; + typedef int BOOLEAN_t; -extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; + extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; -asn_struct_free_f BOOLEAN_free; -asn_struct_print_f BOOLEAN_print; -ber_type_decoder_f BOOLEAN_decode_ber; -der_type_encoder_f BOOLEAN_encode_der; -xer_type_decoder_f BOOLEAN_decode_xer; -xer_type_encoder_f BOOLEAN_encode_xer; -per_type_decoder_f BOOLEAN_decode_uper; -per_type_encoder_f BOOLEAN_encode_uper; + asn_struct_free_f BOOLEAN_free; + asn_struct_print_f BOOLEAN_print; + ber_type_decoder_f BOOLEAN_decode_ber; + der_type_encoder_f BOOLEAN_encode_der; + xer_type_decoder_f BOOLEAN_decode_xer; + xer_type_encoder_f BOOLEAN_encode_xer; + per_type_decoder_f BOOLEAN_decode_uper; + per_type_encoder_f BOOLEAN_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BOOLEAN_H_ */ +#endif /* _BOOLEAN_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/BSIC.h b/src/core/libs/supl/asn-rrlp/BSIC.h index 8ae54f8f0..d98c3a243 100644 --- a/src/core/libs/supl/asn-rrlp/BSIC.h +++ b/src/core/libs/supl/asn-rrlp/BSIC.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BSIC_H_ -#define _BSIC_H_ +#ifndef _BSIC_H_ +#define _BSIC_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BSIC */ -typedef long BSIC_t; + /* BSIC */ + typedef long BSIC_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BSIC; -asn_struct_free_f BSIC_free; -asn_struct_print_f BSIC_print; -asn_constr_check_f BSIC_constraint; -ber_type_decoder_f BSIC_decode_ber; -der_type_encoder_f BSIC_encode_der; -xer_type_decoder_f BSIC_decode_xer; -xer_type_encoder_f BSIC_encode_xer; -per_type_decoder_f BSIC_decode_uper; -per_type_encoder_f BSIC_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BSIC; + asn_struct_free_f BSIC_free; + asn_struct_print_f BSIC_print; + asn_constr_check_f BSIC_constraint; + ber_type_decoder_f BSIC_decode_ber; + der_type_encoder_f BSIC_encode_der; + xer_type_decoder_f BSIC_decode_xer; + xer_type_encoder_f BSIC_encode_xer; + per_type_decoder_f BSIC_decode_uper; + per_type_encoder_f BSIC_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BSIC_H_ */ +#endif /* _BSIC_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BSICAndCarrier.h b/src/core/libs/supl/asn-rrlp/BSICAndCarrier.h index dda3b01b2..2af53b890 100644 --- a/src/core/libs/supl/asn-rrlp/BSICAndCarrier.h +++ b/src/core/libs/supl/asn-rrlp/BSICAndCarrier.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BSICAndCarrier_H_ -#define _BSICAndCarrier_H_ +#ifndef _BSICAndCarrier_H_ +#define _BSICAndCarrier_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BSICAndCarrier */ -typedef struct BSICAndCarrier { - BCCHCarrier_t carrier; - BSIC_t bsic; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} BSICAndCarrier_t; + /* BSICAndCarrier */ + typedef struct BSICAndCarrier + { + BCCHCarrier_t carrier; + BSIC_t bsic; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BSICAndCarrier; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } BSICAndCarrier_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BSICAndCarrier; #ifdef __cplusplus } #endif -#endif /* _BSICAndCarrier_H_ */ +#endif /* _BSICAndCarrier_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BTSPosition.h b/src/core/libs/supl/asn-rrlp/BTSPosition.h index dd52ebea6..70fde1aad 100644 --- a/src/core/libs/supl/asn-rrlp/BTSPosition.h +++ b/src/core/libs/supl/asn-rrlp/BTSPosition.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BTSPosition_H_ -#define _BTSPosition_H_ +#ifndef _BTSPosition_H_ +#define _BTSPosition_H_ #include @@ -14,27 +14,28 @@ #include "Ext-GeographicalInformation.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BTSPosition */ -typedef Ext_GeographicalInformation_t BTSPosition_t; + /* BTSPosition */ + typedef Ext_GeographicalInformation_t BTSPosition_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BTSPosition; -asn_struct_free_f BTSPosition_free; -asn_struct_print_f BTSPosition_print; -asn_constr_check_f BTSPosition_constraint; -ber_type_decoder_f BTSPosition_decode_ber; -der_type_encoder_f BTSPosition_encode_der; -xer_type_decoder_f BTSPosition_decode_xer; -xer_type_encoder_f BTSPosition_encode_xer; -per_type_decoder_f BTSPosition_decode_uper; -per_type_encoder_f BTSPosition_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BTSPosition; + asn_struct_free_f BTSPosition_free; + asn_struct_print_f BTSPosition_print; + asn_constr_check_f BTSPosition_constraint; + ber_type_decoder_f BTSPosition_decode_ber; + der_type_encoder_f BTSPosition_encode_der; + xer_type_decoder_f BTSPosition_decode_xer; + xer_type_encoder_f BTSPosition_encode_xer; + per_type_decoder_f BTSPosition_decode_uper; + per_type_encoder_f BTSPosition_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BTSPosition_H_ */ +#endif /* _BTSPosition_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BadSignalElement.h b/src/core/libs/supl/asn-rrlp/BadSignalElement.h index 1b758e069..e13f5fc73 100644 --- a/src/core/libs/supl/asn-rrlp/BadSignalElement.h +++ b/src/core/libs/supl/asn-rrlp/BadSignalElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BadSignalElement_H_ -#define _BadSignalElement_H_ +#ifndef _BadSignalElement_H_ +#define _BadSignalElement_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BadSignalElement */ -typedef struct BadSignalElement { - SVID_t badSVID; - long *badSignalID /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} BadSignalElement_t; + /* BadSignalElement */ + typedef struct BadSignalElement + { + SVID_t badSVID; + long *badSignalID /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BadSignalElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } BadSignalElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BadSignalElement; #ifdef __cplusplus } #endif -#endif /* _BadSignalElement_H_ */ +#endif /* _BadSignalElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/BitNumber.h b/src/core/libs/supl/asn-rrlp/BitNumber.h index 1584ca01e..7cad41929 100644 --- a/src/core/libs/supl/asn-rrlp/BitNumber.h +++ b/src/core/libs/supl/asn-rrlp/BitNumber.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _BitNumber_H_ -#define _BitNumber_H_ +#ifndef _BitNumber_H_ +#define _BitNumber_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* BitNumber */ -typedef long BitNumber_t; + /* BitNumber */ + typedef long BitNumber_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_BitNumber; -asn_struct_free_f BitNumber_free; -asn_struct_print_f BitNumber_print; -asn_constr_check_f BitNumber_constraint; -ber_type_decoder_f BitNumber_decode_ber; -der_type_encoder_f BitNumber_encode_der; -xer_type_decoder_f BitNumber_decode_xer; -xer_type_encoder_f BitNumber_encode_xer; -per_type_decoder_f BitNumber_decode_uper; -per_type_encoder_f BitNumber_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_BitNumber; + asn_struct_free_f BitNumber_free; + asn_struct_print_f BitNumber_print; + asn_constr_check_f BitNumber_constraint; + ber_type_decoder_f BitNumber_decode_ber; + der_type_encoder_f BitNumber_encode_der; + xer_type_decoder_f BitNumber_decode_xer; + xer_type_encoder_f BitNumber_encode_xer; + per_type_decoder_f BitNumber_decode_uper; + per_type_encoder_f BitNumber_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BitNumber_H_ */ +#endif /* _BitNumber_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/CalcAssistanceBTS.h b/src/core/libs/supl/asn-rrlp/CalcAssistanceBTS.h index 6c046b8c6..912b6c2c5 100644 --- a/src/core/libs/supl/asn-rrlp/CalcAssistanceBTS.h +++ b/src/core/libs/supl/asn-rrlp/CalcAssistanceBTS.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _CalcAssistanceBTS_H_ -#define _CalcAssistanceBTS_H_ +#ifndef _CalcAssistanceBTS_H_ +#define _CalcAssistanceBTS_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CalcAssistanceBTS */ -typedef struct CalcAssistanceBTS { - FineRTD_t fineRTD; - ReferenceWGS84_t referenceWGS84; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CalcAssistanceBTS_t; + /* CalcAssistanceBTS */ + typedef struct CalcAssistanceBTS + { + FineRTD_t fineRTD; + ReferenceWGS84_t referenceWGS84; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CalcAssistanceBTS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CalcAssistanceBTS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CalcAssistanceBTS; #ifdef __cplusplus } #endif -#endif /* _CalcAssistanceBTS_H_ */ +#endif /* _CalcAssistanceBTS_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/CellID.h b/src/core/libs/supl/asn-rrlp/CellID.h index e71a1e30a..0e83f9b49 100644 --- a/src/core/libs/supl/asn-rrlp/CellID.h +++ b/src/core/libs/supl/asn-rrlp/CellID.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _CellID_H_ -#define _CellID_H_ +#ifndef _CellID_H_ +#define _CellID_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CellID */ -typedef long CellID_t; + /* CellID */ + typedef long CellID_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellID; -asn_struct_free_f CellID_free; -asn_struct_print_f CellID_print; -asn_constr_check_f CellID_constraint; -ber_type_decoder_f CellID_decode_ber; -der_type_encoder_f CellID_encode_der; -xer_type_decoder_f CellID_decode_xer; -xer_type_encoder_f CellID_encode_xer; -per_type_decoder_f CellID_decode_uper; -per_type_encoder_f CellID_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellID; + asn_struct_free_f CellID_free; + asn_struct_print_f CellID_print; + asn_constr_check_f CellID_constraint; + ber_type_decoder_f CellID_decode_ber; + der_type_encoder_f CellID_encode_der; + xer_type_decoder_f CellID_decode_xer; + xer_type_encoder_f CellID_encode_xer; + per_type_decoder_f CellID_decode_uper; + per_type_encoder_f CellID_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CellID_H_ */ +#endif /* _CellID_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/CellIDAndLAC.h b/src/core/libs/supl/asn-rrlp/CellIDAndLAC.h index e2811df15..6b74bb15a 100644 --- a/src/core/libs/supl/asn-rrlp/CellIDAndLAC.h +++ b/src/core/libs/supl/asn-rrlp/CellIDAndLAC.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _CellIDAndLAC_H_ -#define _CellIDAndLAC_H_ +#ifndef _CellIDAndLAC_H_ +#define _CellIDAndLAC_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CellIDAndLAC */ -typedef struct CellIDAndLAC { - LAC_t referenceLAC; - CellID_t referenceCI; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CellIDAndLAC_t; + /* CellIDAndLAC */ + typedef struct CellIDAndLAC + { + LAC_t referenceLAC; + CellID_t referenceCI; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellIDAndLAC; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CellIDAndLAC_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellIDAndLAC; #ifdef __cplusplus } #endif -#endif /* _CellIDAndLAC_H_ */ +#endif /* _CellIDAndLAC_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ControlHeader.h b/src/core/libs/supl/asn-rrlp/ControlHeader.h index 3471f8a77..c2be329ca 100644 --- a/src/core/libs/supl/asn-rrlp/ControlHeader.h +++ b/src/core/libs/supl/asn-rrlp/ControlHeader.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ControlHeader_H_ -#define _ControlHeader_H_ +#ifndef _ControlHeader_H_ +#define _ControlHeader_H_ #include @@ -14,38 +14,40 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceTime; -struct RefLocation; -struct DGPSCorrections; -struct NavigationModel; -struct IonosphericModel; -struct UTCModel; -struct Almanac; -struct AcquisAssist; -struct SeqOf_BadSatelliteSet; + /* Forward declarations */ + struct ReferenceTime; + struct RefLocation; + struct DGPSCorrections; + struct NavigationModel; + struct IonosphericModel; + struct UTCModel; + struct Almanac; + struct AcquisAssist; + struct SeqOf_BadSatelliteSet; -/* ControlHeader */ -typedef struct ControlHeader { - struct ReferenceTime *referenceTime /* OPTIONAL */; - struct RefLocation *refLocation /* OPTIONAL */; - struct DGPSCorrections *dgpsCorrections /* OPTIONAL */; - struct NavigationModel *navigationModel /* OPTIONAL */; - struct IonosphericModel *ionosphericModel /* OPTIONAL */; - struct UTCModel *utcModel /* OPTIONAL */; - struct Almanac *almanac /* OPTIONAL */; - struct AcquisAssist *acquisAssist /* OPTIONAL */; - struct SeqOf_BadSatelliteSet *realTimeIntegrity /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ControlHeader_t; + /* ControlHeader */ + typedef struct ControlHeader + { + struct ReferenceTime *referenceTime /* OPTIONAL */; + struct RefLocation *refLocation /* OPTIONAL */; + struct DGPSCorrections *dgpsCorrections /* OPTIONAL */; + struct NavigationModel *navigationModel /* OPTIONAL */; + struct IonosphericModel *ionosphericModel /* OPTIONAL */; + struct UTCModel *utcModel /* OPTIONAL */; + struct Almanac *almanac /* OPTIONAL */; + struct AcquisAssist *acquisAssist /* OPTIONAL */; + struct SeqOf_BadSatelliteSet *realTimeIntegrity /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ControlHeader; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ControlHeader_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ControlHeader; #ifdef __cplusplus } @@ -62,5 +64,5 @@ extern asn_TYPE_descriptor_t asn_DEF_ControlHeader; #include "AcquisAssist.h" #include "SeqOf-BadSatelliteSet.h" -#endif /* _ControlHeader_H_ */ +#endif /* _ControlHeader_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/DGANSSSgnElement.h b/src/core/libs/supl/asn-rrlp/DGANSSSgnElement.h index 0ba005e0b..6cb7be67c 100644 --- a/src/core/libs/supl/asn-rrlp/DGANSSSgnElement.h +++ b/src/core/libs/supl/asn-rrlp/DGANSSSgnElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _DGANSSSgnElement_H_ -#define _DGANSSSgnElement_H_ +#ifndef _DGANSSSgnElement_H_ +#define _DGANSSSgnElement_H_ #include @@ -16,27 +16,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* DGANSSSgnElement */ -typedef struct DGANSSSgnElement { - SVID_t svID; - long iod; - long udre; - long pseudoRangeCor; - long rangeRateCor; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} DGANSSSgnElement_t; + /* DGANSSSgnElement */ + typedef struct DGANSSSgnElement + { + SVID_t svID; + long iod; + long udre; + long pseudoRangeCor; + long rangeRateCor; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_DGANSSSgnElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } DGANSSSgnElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_DGANSSSgnElement; #ifdef __cplusplus } #endif -#endif /* _DGANSSSgnElement_H_ */ +#endif /* _DGANSSSgnElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/DGPSCorrections.h b/src/core/libs/supl/asn-rrlp/DGPSCorrections.h index 24f0b5076..52913f488 100644 --- a/src/core/libs/supl/asn-rrlp/DGPSCorrections.h +++ b/src/core/libs/supl/asn-rrlp/DGPSCorrections.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _DGPSCorrections_H_ -#define _DGPSCorrections_H_ +#ifndef _DGPSCorrections_H_ +#define _DGPSCorrections_H_ #include @@ -16,25 +16,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* DGPSCorrections */ -typedef struct DGPSCorrections { - long gpsTOW; - long status; - SeqOfSatElement_t satList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} DGPSCorrections_t; + /* DGPSCorrections */ + typedef struct DGPSCorrections + { + long gpsTOW; + long status; + SeqOfSatElement_t satList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_DGPSCorrections; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } DGPSCorrections_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_DGPSCorrections; #ifdef __cplusplus } #endif -#endif /* _DGPSCorrections_H_ */ +#endif /* _DGPSCorrections_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ENUMERATED.h b/src/core/libs/supl/asn-rrlp/ENUMERATED.h index 542dcae94..86c1cf643 100644 --- a/src/core/libs/supl/asn-rrlp/ENUMERATED.h +++ b/src/core/libs/supl/asn-rrlp/ENUMERATED.h @@ -2,24 +2,25 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ENUMERATED_H_ -#define _ENUMERATED_H_ +#ifndef _ENUMERATED_H_ +#define _ENUMERATED_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef INTEGER_t ENUMERATED_t; /* Implemented via INTEGER */ + typedef INTEGER_t ENUMERATED_t; /* Implemented via INTEGER */ -extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; + extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; -per_type_decoder_f ENUMERATED_decode_uper; -per_type_encoder_f ENUMERATED_encode_uper; + per_type_decoder_f ENUMERATED_decode_uper; + per_type_encoder_f ENUMERATED_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ENUMERATED_H_ */ +#endif /* _ENUMERATED_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/EOTDQuality.h b/src/core/libs/supl/asn-rrlp/EOTDQuality.h index a249955f0..522cf0a6e 100644 --- a/src/core/libs/supl/asn-rrlp/EOTDQuality.h +++ b/src/core/libs/supl/asn-rrlp/EOTDQuality.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _EOTDQuality_H_ -#define _EOTDQuality_H_ +#ifndef _EOTDQuality_H_ +#define _EOTDQuality_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* EOTDQuality */ -typedef struct EOTDQuality { - long nbrOfMeasurements; - long stdOfEOTD; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} EOTDQuality_t; + /* EOTDQuality */ + typedef struct EOTDQuality + { + long nbrOfMeasurements; + long stdOfEOTD; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_EOTDQuality; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } EOTDQuality_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_EOTDQuality; #ifdef __cplusplus } #endif -#endif /* _EOTDQuality_H_ */ +#endif /* _EOTDQuality_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/EnvironmentCharacter.h b/src/core/libs/supl/asn-rrlp/EnvironmentCharacter.h index 5a37be9c9..12a7c0ccd 100644 --- a/src/core/libs/supl/asn-rrlp/EnvironmentCharacter.h +++ b/src/core/libs/supl/asn-rrlp/EnvironmentCharacter.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _EnvironmentCharacter_H_ -#define _EnvironmentCharacter_H_ +#ifndef _EnvironmentCharacter_H_ +#define _EnvironmentCharacter_H_ #include @@ -14,37 +14,39 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum EnvironmentCharacter { - EnvironmentCharacter_badArea = 0, - EnvironmentCharacter_notBadArea = 1, - EnvironmentCharacter_mixedArea = 2 - /* + /* Dependencies */ + typedef enum EnvironmentCharacter + { + EnvironmentCharacter_badArea = 0, + EnvironmentCharacter_notBadArea = 1, + EnvironmentCharacter_mixedArea = 2 + /* * Enumeration is extensible */ -} e_EnvironmentCharacter; + } e_EnvironmentCharacter; -/* EnvironmentCharacter */ -typedef ENUMERATED_t EnvironmentCharacter_t; + /* EnvironmentCharacter */ + typedef ENUMERATED_t EnvironmentCharacter_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_EnvironmentCharacter; -asn_struct_free_f EnvironmentCharacter_free; -asn_struct_print_f EnvironmentCharacter_print; -asn_constr_check_f EnvironmentCharacter_constraint; -ber_type_decoder_f EnvironmentCharacter_decode_ber; -der_type_encoder_f EnvironmentCharacter_encode_der; -xer_type_decoder_f EnvironmentCharacter_decode_xer; -xer_type_encoder_f EnvironmentCharacter_encode_xer; -per_type_decoder_f EnvironmentCharacter_decode_uper; -per_type_encoder_f EnvironmentCharacter_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_EnvironmentCharacter; + asn_struct_free_f EnvironmentCharacter_free; + asn_struct_print_f EnvironmentCharacter_print; + asn_constr_check_f EnvironmentCharacter_constraint; + ber_type_decoder_f EnvironmentCharacter_decode_ber; + der_type_encoder_f EnvironmentCharacter_encode_der; + xer_type_decoder_f EnvironmentCharacter_decode_xer; + xer_type_encoder_f EnvironmentCharacter_encode_xer; + per_type_decoder_f EnvironmentCharacter_decode_uper; + per_type_encoder_f EnvironmentCharacter_encode_uper; #ifdef __cplusplus } #endif -#endif /* _EnvironmentCharacter_H_ */ +#endif /* _EnvironmentCharacter_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/EphemerisSubframe1Reserved.h b/src/core/libs/supl/asn-rrlp/EphemerisSubframe1Reserved.h index 156c7f0f8..f62b57afa 100644 --- a/src/core/libs/supl/asn-rrlp/EphemerisSubframe1Reserved.h +++ b/src/core/libs/supl/asn-rrlp/EphemerisSubframe1Reserved.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _EphemerisSubframe1Reserved_H_ -#define _EphemerisSubframe1Reserved_H_ +#ifndef _EphemerisSubframe1Reserved_H_ +#define _EphemerisSubframe1Reserved_H_ #include @@ -15,26 +15,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* EphemerisSubframe1Reserved */ -typedef struct EphemerisSubframe1Reserved { - long reserved1; - long reserved2; - long reserved3; - long reserved4; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} EphemerisSubframe1Reserved_t; + /* EphemerisSubframe1Reserved */ + typedef struct EphemerisSubframe1Reserved + { + long reserved1; + long reserved2; + long reserved3; + long reserved4; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_EphemerisSubframe1Reserved; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } EphemerisSubframe1Reserved_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_EphemerisSubframe1Reserved; #ifdef __cplusplus } #endif -#endif /* _EphemerisSubframe1Reserved_H_ */ +#endif /* _EphemerisSubframe1Reserved_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ErrorCodes.h b/src/core/libs/supl/asn-rrlp/ErrorCodes.h index c2e1f6b4a..c87de55d5 100644 --- a/src/core/libs/supl/asn-rrlp/ErrorCodes.h +++ b/src/core/libs/supl/asn-rrlp/ErrorCodes.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ErrorCodes_H_ -#define _ErrorCodes_H_ +#ifndef _ErrorCodes_H_ +#define _ErrorCodes_H_ #include @@ -14,40 +14,42 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum ErrorCodes { - ErrorCodes_unDefined = 0, - ErrorCodes_missingComponet = 1, - ErrorCodes_incorrectData = 2, - ErrorCodes_missingIEorComponentElement = 3, - ErrorCodes_messageTooShort = 4, - ErrorCodes_unknowReferenceNumber = 5 - /* + /* Dependencies */ + typedef enum ErrorCodes + { + ErrorCodes_unDefined = 0, + ErrorCodes_missingComponet = 1, + ErrorCodes_incorrectData = 2, + ErrorCodes_missingIEorComponentElement = 3, + ErrorCodes_messageTooShort = 4, + ErrorCodes_unknowReferenceNumber = 5 + /* * Enumeration is extensible */ -} e_ErrorCodes; + } e_ErrorCodes; -/* ErrorCodes */ -typedef ENUMERATED_t ErrorCodes_t; + /* ErrorCodes */ + typedef ENUMERATED_t ErrorCodes_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ErrorCodes; -asn_struct_free_f ErrorCodes_free; -asn_struct_print_f ErrorCodes_print; -asn_constr_check_f ErrorCodes_constraint; -ber_type_decoder_f ErrorCodes_decode_ber; -der_type_encoder_f ErrorCodes_encode_der; -xer_type_decoder_f ErrorCodes_decode_xer; -xer_type_encoder_f ErrorCodes_encode_xer; -per_type_decoder_f ErrorCodes_decode_uper; -per_type_encoder_f ErrorCodes_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ErrorCodes; + asn_struct_free_f ErrorCodes_free; + asn_struct_print_f ErrorCodes_print; + asn_constr_check_f ErrorCodes_constraint; + ber_type_decoder_f ErrorCodes_decode_ber; + der_type_encoder_f ErrorCodes_encode_der; + xer_type_decoder_f ErrorCodes_decode_xer; + xer_type_encoder_f ErrorCodes_encode_xer; + per_type_decoder_f ErrorCodes_decode_uper; + per_type_encoder_f ErrorCodes_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ErrorCodes_H_ */ +#endif /* _ErrorCodes_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ExpOTDUncertainty.h b/src/core/libs/supl/asn-rrlp/ExpOTDUncertainty.h index c35d42cc0..44ea118db 100644 --- a/src/core/libs/supl/asn-rrlp/ExpOTDUncertainty.h +++ b/src/core/libs/supl/asn-rrlp/ExpOTDUncertainty.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ExpOTDUncertainty_H_ -#define _ExpOTDUncertainty_H_ +#ifndef _ExpOTDUncertainty_H_ +#define _ExpOTDUncertainty_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ExpOTDUncertainty */ -typedef long ExpOTDUncertainty_t; + /* ExpOTDUncertainty */ + typedef long ExpOTDUncertainty_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ExpOTDUncertainty; -asn_struct_free_f ExpOTDUncertainty_free; -asn_struct_print_f ExpOTDUncertainty_print; -asn_constr_check_f ExpOTDUncertainty_constraint; -ber_type_decoder_f ExpOTDUncertainty_decode_ber; -der_type_encoder_f ExpOTDUncertainty_encode_der; -xer_type_decoder_f ExpOTDUncertainty_decode_xer; -xer_type_encoder_f ExpOTDUncertainty_encode_xer; -per_type_decoder_f ExpOTDUncertainty_decode_uper; -per_type_encoder_f ExpOTDUncertainty_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ExpOTDUncertainty; + asn_struct_free_f ExpOTDUncertainty_free; + asn_struct_print_f ExpOTDUncertainty_print; + asn_constr_check_f ExpOTDUncertainty_constraint; + ber_type_decoder_f ExpOTDUncertainty_decode_ber; + der_type_encoder_f ExpOTDUncertainty_encode_der; + xer_type_decoder_f ExpOTDUncertainty_decode_xer; + xer_type_encoder_f ExpOTDUncertainty_encode_xer; + per_type_decoder_f ExpOTDUncertainty_decode_uper; + per_type_encoder_f ExpOTDUncertainty_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ExpOTDUncertainty_H_ */ +#endif /* _ExpOTDUncertainty_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ExpectedOTD.h b/src/core/libs/supl/asn-rrlp/ExpectedOTD.h index 6f2a869e3..bb25b6eac 100644 --- a/src/core/libs/supl/asn-rrlp/ExpectedOTD.h +++ b/src/core/libs/supl/asn-rrlp/ExpectedOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ExpectedOTD_H_ -#define _ExpectedOTD_H_ +#ifndef _ExpectedOTD_H_ +#define _ExpectedOTD_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ExpectedOTD */ -typedef long ExpectedOTD_t; + /* ExpectedOTD */ + typedef long ExpectedOTD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ExpectedOTD; -asn_struct_free_f ExpectedOTD_free; -asn_struct_print_f ExpectedOTD_print; -asn_constr_check_f ExpectedOTD_constraint; -ber_type_decoder_f ExpectedOTD_decode_ber; -der_type_encoder_f ExpectedOTD_encode_der; -xer_type_decoder_f ExpectedOTD_decode_xer; -xer_type_encoder_f ExpectedOTD_encode_xer; -per_type_decoder_f ExpectedOTD_decode_uper; -per_type_encoder_f ExpectedOTD_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ExpectedOTD; + asn_struct_free_f ExpectedOTD_free; + asn_struct_print_f ExpectedOTD_print; + asn_constr_check_f ExpectedOTD_constraint; + ber_type_decoder_f ExpectedOTD_decode_ber; + der_type_encoder_f ExpectedOTD_encode_der; + xer_type_decoder_f ExpectedOTD_decode_xer; + xer_type_encoder_f ExpectedOTD_encode_xer; + per_type_decoder_f ExpectedOTD_decode_uper; + per_type_encoder_f ExpectedOTD_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ExpectedOTD_H_ */ +#endif /* _ExpectedOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Ext-GeographicalInformation.h b/src/core/libs/supl/asn-rrlp/Ext-GeographicalInformation.h index 47165fd83..cc9330d3a 100644 --- a/src/core/libs/supl/asn-rrlp/Ext-GeographicalInformation.h +++ b/src/core/libs/supl/asn-rrlp/Ext-GeographicalInformation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Ext_GeographicalInformation_H_ -#define _Ext_GeographicalInformation_H_ +#ifndef _Ext_GeographicalInformation_H_ +#define _Ext_GeographicalInformation_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Ext-GeographicalInformation */ -typedef OCTET_STRING_t Ext_GeographicalInformation_t; + /* Ext-GeographicalInformation */ + typedef OCTET_STRING_t Ext_GeographicalInformation_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Ext_GeographicalInformation; -asn_struct_free_f Ext_GeographicalInformation_free; -asn_struct_print_f Ext_GeographicalInformation_print; -asn_constr_check_f Ext_GeographicalInformation_constraint; -ber_type_decoder_f Ext_GeographicalInformation_decode_ber; -der_type_encoder_f Ext_GeographicalInformation_encode_der; -xer_type_decoder_f Ext_GeographicalInformation_decode_xer; -xer_type_encoder_f Ext_GeographicalInformation_encode_xer; -per_type_decoder_f Ext_GeographicalInformation_decode_uper; -per_type_encoder_f Ext_GeographicalInformation_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Ext_GeographicalInformation; + asn_struct_free_f Ext_GeographicalInformation_free; + asn_struct_print_f Ext_GeographicalInformation_print; + asn_constr_check_f Ext_GeographicalInformation_constraint; + ber_type_decoder_f Ext_GeographicalInformation_decode_ber; + der_type_encoder_f Ext_GeographicalInformation_encode_der; + xer_type_decoder_f Ext_GeographicalInformation_decode_xer; + xer_type_encoder_f Ext_GeographicalInformation_encode_xer; + per_type_decoder_f Ext_GeographicalInformation_decode_uper; + per_type_encoder_f Ext_GeographicalInformation_encode_uper; #ifdef __cplusplus } #endif -#endif /* _Ext_GeographicalInformation_H_ */ +#endif /* _Ext_GeographicalInformation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Extended-reference.h b/src/core/libs/supl/asn-rrlp/Extended-reference.h index f4ea28d2c..c21d79d93 100644 --- a/src/core/libs/supl/asn-rrlp/Extended-reference.h +++ b/src/core/libs/supl/asn-rrlp/Extended-reference.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Extended_reference_H_ -#define _Extended_reference_H_ +#ifndef _Extended_reference_H_ +#define _Extended_reference_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Extended-reference */ -typedef struct Extended_reference { - long smlc_code; - long transaction_ID; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Extended_reference_t; + /* Extended-reference */ + typedef struct Extended_reference + { + long smlc_code; + long transaction_ID; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Extended_reference; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Extended_reference_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Extended_reference; #ifdef __cplusplus } #endif -#endif /* _Extended_reference_H_ */ +#endif /* _Extended_reference_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ExtensionContainer.h b/src/core/libs/supl/asn-rrlp/ExtensionContainer.h index a88437df8..f464ba754 100644 --- a/src/core/libs/supl/asn-rrlp/ExtensionContainer.h +++ b/src/core/libs/supl/asn-rrlp/ExtensionContainer.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ExtensionContainer_H_ -#define _ExtensionContainer_H_ +#ifndef _ExtensionContainer_H_ +#define _ExtensionContainer_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ExtensionContainer */ -typedef INTEGER_t ExtensionContainer_t; + /* ExtensionContainer */ + typedef INTEGER_t ExtensionContainer_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ExtensionContainer; -asn_struct_free_f ExtensionContainer_free; -asn_struct_print_f ExtensionContainer_print; -asn_constr_check_f ExtensionContainer_constraint; -ber_type_decoder_f ExtensionContainer_decode_ber; -der_type_encoder_f ExtensionContainer_encode_der; -xer_type_decoder_f ExtensionContainer_decode_xer; -xer_type_encoder_f ExtensionContainer_encode_xer; -per_type_decoder_f ExtensionContainer_decode_uper; -per_type_encoder_f ExtensionContainer_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ExtensionContainer; + asn_struct_free_f ExtensionContainer_free; + asn_struct_print_f ExtensionContainer_print; + asn_constr_check_f ExtensionContainer_constraint; + ber_type_decoder_f ExtensionContainer_decode_ber; + der_type_encoder_f ExtensionContainer_encode_der; + xer_type_decoder_f ExtensionContainer_decode_xer; + xer_type_encoder_f ExtensionContainer_encode_xer; + per_type_decoder_f ExtensionContainer_decode_uper; + per_type_encoder_f ExtensionContainer_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ExtensionContainer_H_ */ +#endif /* _ExtensionContainer_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/FineRTD.h b/src/core/libs/supl/asn-rrlp/FineRTD.h index 7738c6b57..6e0ea3f0f 100644 --- a/src/core/libs/supl/asn-rrlp/FineRTD.h +++ b/src/core/libs/supl/asn-rrlp/FineRTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _FineRTD_H_ -#define _FineRTD_H_ +#ifndef _FineRTD_H_ +#define _FineRTD_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FineRTD */ -typedef long FineRTD_t; + /* FineRTD */ + typedef long FineRTD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FineRTD; -asn_struct_free_f FineRTD_free; -asn_struct_print_f FineRTD_print; -asn_constr_check_f FineRTD_constraint; -ber_type_decoder_f FineRTD_decode_ber; -der_type_encoder_f FineRTD_encode_der; -xer_type_decoder_f FineRTD_decode_xer; -xer_type_encoder_f FineRTD_encode_xer; -per_type_decoder_f FineRTD_decode_uper; -per_type_encoder_f FineRTD_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FineRTD; + asn_struct_free_f FineRTD_free; + asn_struct_print_f FineRTD_print; + asn_constr_check_f FineRTD_constraint; + ber_type_decoder_f FineRTD_decode_ber; + der_type_encoder_f FineRTD_encode_der; + xer_type_decoder_f FineRTD_decode_xer; + xer_type_encoder_f FineRTD_encode_xer; + per_type_decoder_f FineRTD_decode_uper; + per_type_encoder_f FineRTD_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FineRTD_H_ */ +#endif /* _FineRTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/FixType.h b/src/core/libs/supl/asn-rrlp/FixType.h index 498fda8bf..37773ea9d 100644 --- a/src/core/libs/supl/asn-rrlp/FixType.h +++ b/src/core/libs/supl/asn-rrlp/FixType.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _FixType_H_ -#define _FixType_H_ +#ifndef _FixType_H_ +#define _FixType_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum FixType { - FixType_twoDFix = 0, - FixType_threeDFix = 1 -} e_FixType; + /* Dependencies */ + typedef enum FixType + { + FixType_twoDFix = 0, + FixType_threeDFix = 1 + } e_FixType; -/* FixType */ -typedef long FixType_t; + /* FixType */ + typedef long FixType_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FixType; -asn_struct_free_f FixType_free; -asn_struct_print_f FixType_print; -asn_constr_check_f FixType_constraint; -ber_type_decoder_f FixType_decode_ber; -der_type_encoder_f FixType_encode_der; -xer_type_decoder_f FixType_decode_xer; -xer_type_encoder_f FixType_encode_xer; -per_type_decoder_f FixType_decode_uper; -per_type_encoder_f FixType_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FixType; + asn_struct_free_f FixType_free; + asn_struct_print_f FixType_print; + asn_constr_check_f FixType_constraint; + ber_type_decoder_f FixType_decode_ber; + der_type_encoder_f FixType_encode_der; + xer_type_decoder_f FixType_decode_xer; + xer_type_encoder_f FixType_encode_xer; + per_type_decoder_f FixType_decode_uper; + per_type_encoder_f FixType_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FixType_H_ */ +#endif /* _FixType_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/FrameDrift.h b/src/core/libs/supl/asn-rrlp/FrameDrift.h index 48c5f17ea..7769e4369 100644 --- a/src/core/libs/supl/asn-rrlp/FrameDrift.h +++ b/src/core/libs/supl/asn-rrlp/FrameDrift.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _FrameDrift_H_ -#define _FrameDrift_H_ +#ifndef _FrameDrift_H_ +#define _FrameDrift_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FrameDrift */ -typedef long FrameDrift_t; + /* FrameDrift */ + typedef long FrameDrift_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FrameDrift; -asn_struct_free_f FrameDrift_free; -asn_struct_print_f FrameDrift_print; -asn_constr_check_f FrameDrift_constraint; -ber_type_decoder_f FrameDrift_decode_ber; -der_type_encoder_f FrameDrift_encode_der; -xer_type_decoder_f FrameDrift_decode_xer; -xer_type_encoder_f FrameDrift_encode_xer; -per_type_decoder_f FrameDrift_decode_uper; -per_type_encoder_f FrameDrift_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FrameDrift; + asn_struct_free_f FrameDrift_free; + asn_struct_print_f FrameDrift_print; + asn_constr_check_f FrameDrift_constraint; + ber_type_decoder_f FrameDrift_decode_ber; + der_type_encoder_f FrameDrift_encode_der; + xer_type_decoder_f FrameDrift_decode_xer; + xer_type_encoder_f FrameDrift_encode_xer; + per_type_decoder_f FrameDrift_decode_uper; + per_type_encoder_f FrameDrift_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FrameDrift_H_ */ +#endif /* _FrameDrift_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/FrameNumber.h b/src/core/libs/supl/asn-rrlp/FrameNumber.h index 152b2d4d7..2cea180ba 100644 --- a/src/core/libs/supl/asn-rrlp/FrameNumber.h +++ b/src/core/libs/supl/asn-rrlp/FrameNumber.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _FrameNumber_H_ -#define _FrameNumber_H_ +#ifndef _FrameNumber_H_ +#define _FrameNumber_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FrameNumber */ -typedef long FrameNumber_t; + /* FrameNumber */ + typedef long FrameNumber_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FrameNumber; -asn_struct_free_f FrameNumber_free; -asn_struct_print_f FrameNumber_print; -asn_constr_check_f FrameNumber_constraint; -ber_type_decoder_f FrameNumber_decode_ber; -der_type_encoder_f FrameNumber_encode_der; -xer_type_decoder_f FrameNumber_decode_xer; -xer_type_encoder_f FrameNumber_encode_xer; -per_type_decoder_f FrameNumber_decode_uper; -per_type_encoder_f FrameNumber_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FrameNumber; + asn_struct_free_f FrameNumber_free; + asn_struct_print_f FrameNumber_print; + asn_constr_check_f FrameNumber_constraint; + ber_type_decoder_f FrameNumber_decode_ber; + der_type_encoder_f FrameNumber_encode_der; + xer_type_decoder_f FrameNumber_decode_xer; + xer_type_encoder_f FrameNumber_encode_xer; + per_type_decoder_f FrameNumber_decode_uper; + per_type_encoder_f FrameNumber_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FrameNumber_H_ */ +#endif /* _FrameNumber_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSS-AssistData.h b/src/core/libs/supl/asn-rrlp/GANSS-AssistData.h index cdb0960d8..b5f0b285e 100644 --- a/src/core/libs/supl/asn-rrlp/GANSS-AssistData.h +++ b/src/core/libs/supl/asn-rrlp/GANSS-AssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSS_AssistData_H_ -#define _GANSS_AssistData_H_ +#ifndef _GANSS_AssistData_H_ +#define _GANSS_AssistData_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSS-AssistData */ -typedef struct GANSS_AssistData { - GANSS_ControlHeader_t ganss_controlHeader; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSS_AssistData_t; + /* GANSS-AssistData */ + typedef struct GANSS_AssistData + { + GANSS_ControlHeader_t ganss_controlHeader; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSS_AssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSS_AssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSS_AssistData; #ifdef __cplusplus } #endif -#endif /* _GANSS_AssistData_H_ */ +#endif /* _GANSS_AssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSS-ControlHeader.h b/src/core/libs/supl/asn-rrlp/GANSS-ControlHeader.h index 96e98b022..36edc96f2 100644 --- a/src/core/libs/supl/asn-rrlp/GANSS-ControlHeader.h +++ b/src/core/libs/supl/asn-rrlp/GANSS-ControlHeader.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSS_ControlHeader_H_ -#define _GANSS_ControlHeader_H_ +#ifndef _GANSS_ControlHeader_H_ +#define _GANSS_ControlHeader_H_ #include @@ -14,24 +14,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSCommonAssistData; -struct SeqOfGANSSGenericAssistDataElement; + /* Forward declarations */ + struct GANSSCommonAssistData; + struct SeqOfGANSSGenericAssistDataElement; -/* GANSS-ControlHeader */ -typedef struct GANSS_ControlHeader { - struct GANSSCommonAssistData *ganssCommonAssistData /* OPTIONAL */; - struct SeqOfGANSSGenericAssistDataElement *ganssGenericAssistDataList /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSS_ControlHeader_t; + /* GANSS-ControlHeader */ + typedef struct GANSS_ControlHeader + { + struct GANSSCommonAssistData *ganssCommonAssistData /* OPTIONAL */; + struct SeqOfGANSSGenericAssistDataElement *ganssGenericAssistDataList /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSS_ControlHeader; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSS_ControlHeader_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSS_ControlHeader; #ifdef __cplusplus } @@ -41,5 +43,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSS_ControlHeader; #include "GANSSCommonAssistData.h" #include "SeqOfGANSSGenericAssistDataElement.h" -#endif /* _GANSS_ControlHeader_H_ */ +#endif /* _GANSS_ControlHeader_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSS-MsrSetElement.h b/src/core/libs/supl/asn-rrlp/GANSS-MsrSetElement.h index a6579b16e..4786b7e07 100644 --- a/src/core/libs/supl/asn-rrlp/GANSS-MsrSetElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSS-MsrSetElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSS_MsrSetElement_H_ -#define _GANSS_MsrSetElement_H_ +#ifndef _GANSS_MsrSetElement_H_ +#define _GANSS_MsrSetElement_H_ #include @@ -18,26 +18,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceFrame; + /* Forward declarations */ + struct ReferenceFrame; -/* GANSS-MsrSetElement */ -typedef struct GANSS_MsrSetElement { - struct ReferenceFrame *referenceFrame /* OPTIONAL */; - GANSSTODm_t *ganssTODm /* OPTIONAL */; - long *deltaGNASSTOD /* OPTIONAL */; - GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; - SeqOfGANSS_SgnTypeElement_t ganss_SgnTypeList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSS_MsrSetElement_t; + /* GANSS-MsrSetElement */ + typedef struct GANSS_MsrSetElement + { + struct ReferenceFrame *referenceFrame /* OPTIONAL */; + GANSSTODm_t *ganssTODm /* OPTIONAL */; + long *deltaGNASSTOD /* OPTIONAL */; + GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; + SeqOfGANSS_SgnTypeElement_t ganss_SgnTypeList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSS_MsrSetElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSS_MsrSetElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSS_MsrSetElement; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSS_MsrSetElement; /* Referred external types */ #include "ReferenceFrame.h" -#endif /* _GANSS_MsrSetElement_H_ */ +#endif /* _GANSS_MsrSetElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSS-SgnElement.h b/src/core/libs/supl/asn-rrlp/GANSS-SgnElement.h index d2727b544..2e7a15c4a 100644 --- a/src/core/libs/supl/asn-rrlp/GANSS-SgnElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSS-SgnElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSS_SgnElement_H_ -#define _GANSS_SgnElement_H_ +#ifndef _GANSS_SgnElement_H_ +#define _GANSS_SgnElement_H_ #include @@ -17,31 +17,33 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSS-SgnElement */ -typedef struct GANSS_SgnElement { - SVID_t svID; - long cNo; - MpathIndic_t mpathDet; - long *carrierQualityInd /* OPTIONAL */; - long codePhase; - long *integerCodePhase /* OPTIONAL */; - long codePhaseRMSError; - long *doppler /* OPTIONAL */; - long *adr /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSS_SgnElement_t; + /* GANSS-SgnElement */ + typedef struct GANSS_SgnElement + { + SVID_t svID; + long cNo; + MpathIndic_t mpathDet; + long *carrierQualityInd /* OPTIONAL */; + long codePhase; + long *integerCodePhase /* OPTIONAL */; + long codePhaseRMSError; + long *doppler /* OPTIONAL */; + long *adr /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSS_SgnElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSS_SgnElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSS_SgnElement; #ifdef __cplusplus } #endif -#endif /* _GANSS_SgnElement_H_ */ +#endif /* _GANSS_SgnElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSS-SgnTypeElement.h b/src/core/libs/supl/asn-rrlp/GANSS-SgnTypeElement.h index d4b43c852..f591c0e86 100644 --- a/src/core/libs/supl/asn-rrlp/GANSS-SgnTypeElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSS-SgnTypeElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSS_SgnTypeElement_H_ -#define _GANSS_SgnTypeElement_H_ +#ifndef _GANSS_SgnTypeElement_H_ +#define _GANSS_SgnTypeElement_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSS-SgnTypeElement */ -typedef struct GANSS_SgnTypeElement { - long ganssSignalID; - SeqOfGANSS_SgnElement_t ganss_SgnList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSS_SgnTypeElement_t; + /* GANSS-SgnTypeElement */ + typedef struct GANSS_SgnTypeElement + { + long ganssSignalID; + SeqOfGANSS_SgnElement_t ganss_SgnList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSS_SgnTypeElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSS_SgnTypeElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSS_SgnTypeElement; #ifdef __cplusplus } #endif -#endif /* _GANSS_SgnTypeElement_H_ */ +#endif /* _GANSS_SgnTypeElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSAlmanacElement.h b/src/core/libs/supl/asn-rrlp/GANSSAlmanacElement.h index 508f08a00..3391b4885 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSAlmanacElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSSAlmanacElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSAlmanacElement_H_ -#define _GANSSAlmanacElement_H_ +#ifndef _GANSSAlmanacElement_H_ +#define _GANSSAlmanacElement_H_ #include @@ -15,38 +15,42 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum GANSSAlmanacElement_PR { - GANSSAlmanacElement_PR_NOTHING, /* No components present */ - GANSSAlmanacElement_PR_keplerianAlmanacSet, - /* Extensions may appear below */ - -} GANSSAlmanacElement_PR; + /* Dependencies */ + typedef enum GANSSAlmanacElement_PR + { + GANSSAlmanacElement_PR_NOTHING, /* No components present */ + GANSSAlmanacElement_PR_keplerianAlmanacSet, + /* Extensions may appear below */ -/* GANSSAlmanacElement */ -typedef struct GANSSAlmanacElement { - GANSSAlmanacElement_PR present; - union GANSSAlmanacElement_u { - Almanac_KeplerianSet_t keplerianAlmanacSet; - /* + } GANSSAlmanacElement_PR; + + /* GANSSAlmanacElement */ + typedef struct GANSSAlmanacElement + { + GANSSAlmanacElement_PR present; + union GANSSAlmanacElement_u + { + Almanac_KeplerianSet_t keplerianAlmanacSet; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSAlmanacElement_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSAlmanacElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSAlmanacElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSAlmanacElement; #ifdef __cplusplus } #endif -#endif /* _GANSSAlmanacElement_H_ */ +#endif /* _GANSSAlmanacElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSAlmanacModel.h b/src/core/libs/supl/asn-rrlp/GANSSAlmanacModel.h index 237ad6217..06253e12f 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSAlmanacModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSAlmanacModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSAlmanacModel_H_ -#define _GANSSAlmanacModel_H_ +#ifndef _GANSSAlmanacModel_H_ +#define _GANSSAlmanacModel_H_ #include @@ -17,27 +17,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSAlmanacModel */ -typedef struct GANSSAlmanacModel { - long weekNumber; - SVIDMASK_t svIDMask; - long *toa /* OPTIONAL */; - long *ioda /* OPTIONAL */; - SeqOfGANSSAlmanacElement_t ganssAlmanacList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSAlmanacModel_t; + /* GANSSAlmanacModel */ + typedef struct GANSSAlmanacModel + { + long weekNumber; + SVIDMASK_t svIDMask; + long *toa /* OPTIONAL */; + long *ioda /* OPTIONAL */; + SeqOfGANSSAlmanacElement_t ganssAlmanacList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSAlmanacModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSAlmanacModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSAlmanacModel; #ifdef __cplusplus } #endif -#endif /* _GANSSAlmanacModel_H_ */ +#endif /* _GANSSAlmanacModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSAssistanceData.h b/src/core/libs/supl/asn-rrlp/GANSSAssistanceData.h index 58d37c051..751d01df2 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSAssistanceData.h +++ b/src/core/libs/supl/asn-rrlp/GANSSAssistanceData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSAssistanceData_H_ -#define _GANSSAssistanceData_H_ +#ifndef _GANSSAssistanceData_H_ +#define _GANSSAssistanceData_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSAssistanceData */ -typedef OCTET_STRING_t GANSSAssistanceData_t; + /* GANSSAssistanceData */ + typedef OCTET_STRING_t GANSSAssistanceData_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSAssistanceData; -asn_struct_free_f GANSSAssistanceData_free; -asn_struct_print_f GANSSAssistanceData_print; -asn_constr_check_f GANSSAssistanceData_constraint; -ber_type_decoder_f GANSSAssistanceData_decode_ber; -der_type_encoder_f GANSSAssistanceData_encode_der; -xer_type_decoder_f GANSSAssistanceData_decode_xer; -xer_type_encoder_f GANSSAssistanceData_encode_xer; -per_type_decoder_f GANSSAssistanceData_decode_uper; -per_type_encoder_f GANSSAssistanceData_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSAssistanceData; + asn_struct_free_f GANSSAssistanceData_free; + asn_struct_print_f GANSSAssistanceData_print; + asn_constr_check_f GANSSAssistanceData_constraint; + ber_type_decoder_f GANSSAssistanceData_decode_ber; + der_type_encoder_f GANSSAssistanceData_encode_der; + xer_type_decoder_f GANSSAssistanceData_decode_xer; + xer_type_encoder_f GANSSAssistanceData_encode_xer; + per_type_decoder_f GANSSAssistanceData_decode_uper; + per_type_encoder_f GANSSAssistanceData_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSAssistanceData_H_ */ +#endif /* _GANSSAssistanceData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSClockModel.h b/src/core/libs/supl/asn-rrlp/GANSSClockModel.h index 4fd80e0b7..05d019a1e 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSClockModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSClockModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSClockModel_H_ -#define _GANSSClockModel_H_ +#ifndef _GANSSClockModel_H_ +#define _GANSSClockModel_H_ #include @@ -15,38 +15,42 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum GANSSClockModel_PR { - GANSSClockModel_PR_NOTHING, /* No components present */ - GANSSClockModel_PR_standardClockModelList, - /* Extensions may appear below */ - -} GANSSClockModel_PR; + /* Dependencies */ + typedef enum GANSSClockModel_PR + { + GANSSClockModel_PR_NOTHING, /* No components present */ + GANSSClockModel_PR_standardClockModelList, + /* Extensions may appear below */ -/* GANSSClockModel */ -typedef struct GANSSClockModel { - GANSSClockModel_PR present; - union GANSSClockModel_u { - SeqOfStandardClockModelElement_t standardClockModelList; - /* + } GANSSClockModel_PR; + + /* GANSSClockModel */ + typedef struct GANSSClockModel + { + GANSSClockModel_PR present; + union GANSSClockModel_u + { + SeqOfStandardClockModelElement_t standardClockModelList; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSClockModel_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSClockModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSClockModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSClockModel; #ifdef __cplusplus } #endif -#endif /* _GANSSClockModel_H_ */ +#endif /* _GANSSClockModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSCommonAssistData.h b/src/core/libs/supl/asn-rrlp/GANSSCommonAssistData.h index 383d368ac..4173cfac4 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSCommonAssistData.h +++ b/src/core/libs/supl/asn-rrlp/GANSSCommonAssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSCommonAssistData_H_ -#define _GANSSCommonAssistData_H_ +#ifndef _GANSSCommonAssistData_H_ +#define _GANSSCommonAssistData_H_ #include @@ -14,30 +14,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSReferenceTime; -struct GANSSRefLocation; -struct GANSSIonosphericModel; + /* Forward declarations */ + struct GANSSReferenceTime; + struct GANSSRefLocation; + struct GANSSIonosphericModel; -/* GANSSCommonAssistData */ -typedef struct GANSSCommonAssistData { - struct GANSSReferenceTime *ganssReferenceTime /* OPTIONAL */; - struct GANSSRefLocation *ganssRefLocation /* OPTIONAL */; - struct GANSSIonosphericModel *ganssIonosphericModel /* OPTIONAL */; - /* + /* GANSSCommonAssistData */ + typedef struct GANSSCommonAssistData + { + struct GANSSReferenceTime *ganssReferenceTime /* OPTIONAL */; + struct GANSSRefLocation *ganssRefLocation /* OPTIONAL */; + struct GANSSIonosphericModel *ganssIonosphericModel /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSCommonAssistData_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSCommonAssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSCommonAssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSCommonAssistData; #ifdef __cplusplus } @@ -48,5 +50,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSCommonAssistData; #include "GANSSRefLocation.h" #include "GANSSIonosphericModel.h" -#endif /* _GANSSCommonAssistData_H_ */ +#endif /* _GANSSCommonAssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSDataBit.h b/src/core/libs/supl/asn-rrlp/GANSSDataBit.h index 008d80e82..9ac0b3dfe 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSDataBit.h +++ b/src/core/libs/supl/asn-rrlp/GANSSDataBit.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSDataBit_H_ -#define _GANSSDataBit_H_ +#ifndef _GANSSDataBit_H_ +#define _GANSSDataBit_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSDataBit */ -typedef long GANSSDataBit_t; + /* GANSSDataBit */ + typedef long GANSSDataBit_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSDataBit; -asn_struct_free_f GANSSDataBit_free; -asn_struct_print_f GANSSDataBit_print; -asn_constr_check_f GANSSDataBit_constraint; -ber_type_decoder_f GANSSDataBit_decode_ber; -der_type_encoder_f GANSSDataBit_encode_der; -xer_type_decoder_f GANSSDataBit_decode_xer; -xer_type_encoder_f GANSSDataBit_encode_xer; -per_type_decoder_f GANSSDataBit_decode_uper; -per_type_encoder_f GANSSDataBit_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSDataBit; + asn_struct_free_f GANSSDataBit_free; + asn_struct_print_f GANSSDataBit_print; + asn_constr_check_f GANSSDataBit_constraint; + ber_type_decoder_f GANSSDataBit_decode_ber; + der_type_encoder_f GANSSDataBit_encode_der; + xer_type_decoder_f GANSSDataBit_decode_xer; + xer_type_encoder_f GANSSDataBit_encode_xer; + per_type_decoder_f GANSSDataBit_decode_uper; + per_type_encoder_f GANSSDataBit_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSDataBit_H_ */ +#endif /* _GANSSDataBit_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSDataBitAssist.h b/src/core/libs/supl/asn-rrlp/GANSSDataBitAssist.h index ae97a6315..defe153bd 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSDataBitAssist.h +++ b/src/core/libs/supl/asn-rrlp/GANSSDataBitAssist.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSDataBitAssist_H_ -#define _GANSSDataBitAssist_H_ +#ifndef _GANSSDataBitAssist_H_ +#define _GANSSDataBitAssist_H_ #include @@ -17,26 +17,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSDataBitAssist */ -typedef struct GANSSDataBitAssist { - long ganssTOD; - SVID_t svID; - long ganssDataTypeID; - SeqOf_GANSSDataBits_t ganssDataBits; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSDataBitAssist_t; + /* GANSSDataBitAssist */ + typedef struct GANSSDataBitAssist + { + long ganssTOD; + SVID_t svID; + long ganssDataTypeID; + SeqOf_GANSSDataBits_t ganssDataBits; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSDataBitAssist; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSDataBitAssist_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSDataBitAssist; #ifdef __cplusplus } #endif -#endif /* _GANSSDataBitAssist_H_ */ +#endif /* _GANSSDataBitAssist_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSDiffCorrections.h b/src/core/libs/supl/asn-rrlp/GANSSDiffCorrections.h index b499c3918..5289c74a8 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSDiffCorrections.h +++ b/src/core/libs/supl/asn-rrlp/GANSSDiffCorrections.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSDiffCorrections_H_ -#define _GANSSDiffCorrections_H_ +#ifndef _GANSSDiffCorrections_H_ +#define _GANSSDiffCorrections_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSDiffCorrections */ -typedef struct GANSSDiffCorrections { - long dganssRefTime; - SeqOfSgnTypeElement_t sgnTypeList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSDiffCorrections_t; + /* GANSSDiffCorrections */ + typedef struct GANSSDiffCorrections + { + long dganssRefTime; + SeqOfSgnTypeElement_t sgnTypeList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSDiffCorrections; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSDiffCorrections_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSDiffCorrections; #ifdef __cplusplus } #endif -#endif /* _GANSSDiffCorrections_H_ */ +#endif /* _GANSSDiffCorrections_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSGenericAssistDataElement.h b/src/core/libs/supl/asn-rrlp/GANSSGenericAssistDataElement.h index 1677de530..84573317f 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSGenericAssistDataElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSSGenericAssistDataElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSGenericAssistDataElement_H_ -#define _GANSSGenericAssistDataElement_H_ +#ifndef _GANSSGenericAssistDataElement_H_ +#define _GANSSGenericAssistDataElement_H_ #include @@ -15,41 +15,43 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SeqOfGANSSTimeModel; -struct GANSSDiffCorrections; -struct GANSSNavModel; -struct GANSSRealTimeIntegrity; -struct GANSSDataBitAssist; -struct GANSSRefMeasurementAssist; -struct GANSSAlmanacModel; -struct GANSSUTCModel; + /* Forward declarations */ + struct SeqOfGANSSTimeModel; + struct GANSSDiffCorrections; + struct GANSSNavModel; + struct GANSSRealTimeIntegrity; + struct GANSSDataBitAssist; + struct GANSSRefMeasurementAssist; + struct GANSSAlmanacModel; + struct GANSSUTCModel; -/* GANSSGenericAssistDataElement */ -typedef struct GANSSGenericAssistDataElement { - long *ganssID /* OPTIONAL */; - struct SeqOfGANSSTimeModel *ganssTimeModel /* OPTIONAL */; - struct GANSSDiffCorrections *ganssDiffCorrections /* OPTIONAL */; - struct GANSSNavModel *ganssNavigationModel /* OPTIONAL */; - struct GANSSRealTimeIntegrity *ganssRealTimeIntegrity /* OPTIONAL */; - struct GANSSDataBitAssist *ganssDataBitAssist /* OPTIONAL */; - struct GANSSRefMeasurementAssist *ganssRefMeasurementAssist /* OPTIONAL */; - struct GANSSAlmanacModel *ganssAlmanacModel /* OPTIONAL */; - struct GANSSUTCModel *ganssUTCModel /* OPTIONAL */; - /* + /* GANSSGenericAssistDataElement */ + typedef struct GANSSGenericAssistDataElement + { + long *ganssID /* OPTIONAL */; + struct SeqOfGANSSTimeModel *ganssTimeModel /* OPTIONAL */; + struct GANSSDiffCorrections *ganssDiffCorrections /* OPTIONAL */; + struct GANSSNavModel *ganssNavigationModel /* OPTIONAL */; + struct GANSSRealTimeIntegrity *ganssRealTimeIntegrity /* OPTIONAL */; + struct GANSSDataBitAssist *ganssDataBitAssist /* OPTIONAL */; + struct GANSSRefMeasurementAssist *ganssRefMeasurementAssist /* OPTIONAL */; + struct GANSSAlmanacModel *ganssAlmanacModel /* OPTIONAL */; + struct GANSSUTCModel *ganssUTCModel /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSGenericAssistDataElement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSGenericAssistDataElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSGenericAssistDataElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSGenericAssistDataElement; #ifdef __cplusplus } @@ -65,5 +67,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSGenericAssistDataElement; #include "GANSSAlmanacModel.h" #include "GANSSUTCModel.h" -#endif /* _GANSSGenericAssistDataElement_H_ */ +#endif /* _GANSSGenericAssistDataElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSIonoStormFlags.h b/src/core/libs/supl/asn-rrlp/GANSSIonoStormFlags.h index b55e8a32e..c99ab79c6 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSIonoStormFlags.h +++ b/src/core/libs/supl/asn-rrlp/GANSSIonoStormFlags.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSIonoStormFlags_H_ -#define _GANSSIonoStormFlags_H_ +#ifndef _GANSSIonoStormFlags_H_ +#define _GANSSIonoStormFlags_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSIonoStormFlags */ -typedef struct GANSSIonoStormFlags { - long ionoStormFlag1; - long ionoStormFlag2; - long ionoStormFlag3; - long ionoStormFlag4; - long ionoStormFlag5; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSIonoStormFlags_t; + /* GANSSIonoStormFlags */ + typedef struct GANSSIonoStormFlags + { + long ionoStormFlag1; + long ionoStormFlag2; + long ionoStormFlag3; + long ionoStormFlag4; + long ionoStormFlag5; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSIonoStormFlags; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSIonoStormFlags_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSIonoStormFlags; #ifdef __cplusplus } #endif -#endif /* _GANSSIonoStormFlags_H_ */ +#endif /* _GANSSIonoStormFlags_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSIonosphereModel.h b/src/core/libs/supl/asn-rrlp/GANSSIonosphereModel.h index a30c4d2e2..969fd8da0 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSIonosphereModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSIonosphereModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSIonosphereModel_H_ -#define _GANSSIonosphereModel_H_ +#ifndef _GANSSIonosphereModel_H_ +#define _GANSSIonosphereModel_H_ #include @@ -15,25 +15,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSIonosphereModel */ -typedef struct GANSSIonosphereModel { - long ai0; - long ai1; - long ai2; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSIonosphereModel_t; + /* GANSSIonosphereModel */ + typedef struct GANSSIonosphereModel + { + long ai0; + long ai1; + long ai2; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSIonosphereModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSIonosphereModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSIonosphereModel; #ifdef __cplusplus } #endif -#endif /* _GANSSIonosphereModel_H_ */ +#endif /* _GANSSIonosphereModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSIonosphericModel.h b/src/core/libs/supl/asn-rrlp/GANSSIonosphericModel.h index e96ff7635..30a219e0d 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSIonosphericModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSIonosphericModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSIonosphericModel_H_ -#define _GANSSIonosphericModel_H_ +#ifndef _GANSSIonosphericModel_H_ +#define _GANSSIonosphericModel_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSIonoStormFlags; + /* Forward declarations */ + struct GANSSIonoStormFlags; -/* GANSSIonosphericModel */ -typedef struct GANSSIonosphericModel { - GANSSIonosphereModel_t ganssIonoModel; - struct GANSSIonoStormFlags *ganssIonoStormFlags /* OPTIONAL */; - /* + /* GANSSIonosphericModel */ + typedef struct GANSSIonosphericModel + { + GANSSIonosphereModel_t ganssIonoModel; + struct GANSSIonoStormFlags *ganssIonoStormFlags /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSIonosphericModel_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSIonosphericModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSIonosphericModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSIonosphericModel; #ifdef __cplusplus } @@ -44,5 +46,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSIonosphericModel; /* Referred external types */ #include "GANSSIonoStormFlags.h" -#endif /* _GANSSIonosphericModel_H_ */ +#endif /* _GANSSIonosphericModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSLocationInfo.h b/src/core/libs/supl/asn-rrlp/GANSSLocationInfo.h index b1cc1c866..ab7b0dcea 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSLocationInfo.h +++ b/src/core/libs/supl/asn-rrlp/GANSSLocationInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSLocationInfo_H_ -#define _GANSSLocationInfo_H_ +#ifndef _GANSSLocationInfo_H_ +#define _GANSSLocationInfo_H_ #include @@ -20,34 +20,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceFrame; + /* Forward declarations */ + struct ReferenceFrame; -/* GANSSLocationInfo */ -typedef struct GANSSLocationInfo { - struct ReferenceFrame *referenceFrame /* OPTIONAL */; - GANSSTODm_t *ganssTODm /* OPTIONAL */; - long *ganssTODFrac /* OPTIONAL */; - GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; - long *ganssTimeID /* OPTIONAL */; - FixType_t fixType; - PositionData_t posData; - long *stationaryIndication /* OPTIONAL */; - Ext_GeographicalInformation_t posEstimate; - /* + /* GANSSLocationInfo */ + typedef struct GANSSLocationInfo + { + struct ReferenceFrame *referenceFrame /* OPTIONAL */; + GANSSTODm_t *ganssTODm /* OPTIONAL */; + long *ganssTODFrac /* OPTIONAL */; + GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; + long *ganssTimeID /* OPTIONAL */; + FixType_t fixType; + PositionData_t posData; + long *stationaryIndication /* OPTIONAL */; + Ext_GeographicalInformation_t posEstimate; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSLocationInfo_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSLocationInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSLocationInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSLocationInfo; #ifdef __cplusplus } @@ -56,5 +58,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSLocationInfo; /* Referred external types */ #include "ReferenceFrame.h" -#endif /* _GANSSLocationInfo_H_ */ +#endif /* _GANSSLocationInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSMeasureInfo.h b/src/core/libs/supl/asn-rrlp/GANSSMeasureInfo.h index fa03e8726..e5e87bd86 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSMeasureInfo.h +++ b/src/core/libs/supl/asn-rrlp/GANSSMeasureInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSMeasureInfo_H_ -#define _GANSSMeasureInfo_H_ +#ifndef _GANSSMeasureInfo_H_ +#define _GANSSMeasureInfo_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSMeasureInfo */ -typedef struct GANSSMeasureInfo { - SeqOfGANSS_MsrSetElement_t ganssMsrSetList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSMeasureInfo_t; + /* GANSSMeasureInfo */ + typedef struct GANSSMeasureInfo + { + SeqOfGANSS_MsrSetElement_t ganssMsrSetList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSMeasureInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSMeasureInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSMeasureInfo; #ifdef __cplusplus } #endif -#endif /* _GANSSMeasureInfo_H_ */ +#endif /* _GANSSMeasureInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSNavModel.h b/src/core/libs/supl/asn-rrlp/GANSSNavModel.h index d49b75a44..3891a44d7 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSNavModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSNavModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSNavModel_H_ -#define _GANSSNavModel_H_ +#ifndef _GANSSNavModel_H_ +#define _GANSSNavModel_H_ #include @@ -16,27 +16,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSNavModel */ -typedef struct GANSSNavModel { - long nonBroadcastIndFlag; - long *toeMSB /* OPTIONAL */; - long *eMSB /* OPTIONAL */; - long *sqrtAMBS /* OPTIONAL */; - SeqOfGANSSSatelliteElement_t ganssSatelliteList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSNavModel_t; + /* GANSSNavModel */ + typedef struct GANSSNavModel + { + long nonBroadcastIndFlag; + long *toeMSB /* OPTIONAL */; + long *eMSB /* OPTIONAL */; + long *sqrtAMBS /* OPTIONAL */; + SeqOfGANSSSatelliteElement_t ganssSatelliteList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSNavModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSNavModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSNavModel; #ifdef __cplusplus } #endif -#endif /* _GANSSNavModel_H_ */ +#endif /* _GANSSNavModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSOrbitModel.h b/src/core/libs/supl/asn-rrlp/GANSSOrbitModel.h index b1e6cbb48..23a907d01 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSOrbitModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSOrbitModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSOrbitModel_H_ -#define _GANSSOrbitModel_H_ +#ifndef _GANSSOrbitModel_H_ +#define _GANSSOrbitModel_H_ #include @@ -15,38 +15,42 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum GANSSOrbitModel_PR { - GANSSOrbitModel_PR_NOTHING, /* No components present */ - GANSSOrbitModel_PR_keplerianSet, - /* Extensions may appear below */ - -} GANSSOrbitModel_PR; + /* Dependencies */ + typedef enum GANSSOrbitModel_PR + { + GANSSOrbitModel_PR_NOTHING, /* No components present */ + GANSSOrbitModel_PR_keplerianSet, + /* Extensions may appear below */ -/* GANSSOrbitModel */ -typedef struct GANSSOrbitModel { - GANSSOrbitModel_PR present; - union GANSSOrbitModel_u { - NavModel_KeplerianSet_t keplerianSet; - /* + } GANSSOrbitModel_PR; + + /* GANSSOrbitModel */ + typedef struct GANSSOrbitModel + { + GANSSOrbitModel_PR present; + union GANSSOrbitModel_u + { + NavModel_KeplerianSet_t keplerianSet; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSOrbitModel_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSOrbitModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSOrbitModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSOrbitModel; #ifdef __cplusplus } #endif -#endif /* _GANSSOrbitModel_H_ */ +#endif /* _GANSSOrbitModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSPositioningMethod.h b/src/core/libs/supl/asn-rrlp/GANSSPositioningMethod.h index 334d978ce..2719933a3 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSPositioningMethod.h +++ b/src/core/libs/supl/asn-rrlp/GANSSPositioningMethod.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSPositioningMethod_H_ -#define _GANSSPositioningMethod_H_ +#ifndef _GANSSPositioningMethod_H_ +#define _GANSSPositioningMethod_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum GANSSPositioningMethod { - GANSSPositioningMethod_gps = 0, - GANSSPositioningMethod_galileo = 1 -} e_GANSSPositioningMethod; + /* Dependencies */ + typedef enum GANSSPositioningMethod + { + GANSSPositioningMethod_gps = 0, + GANSSPositioningMethod_galileo = 1 + } e_GANSSPositioningMethod; -/* GANSSPositioningMethod */ -typedef BIT_STRING_t GANSSPositioningMethod_t; + /* GANSSPositioningMethod */ + typedef BIT_STRING_t GANSSPositioningMethod_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSPositioningMethod; -asn_struct_free_f GANSSPositioningMethod_free; -asn_struct_print_f GANSSPositioningMethod_print; -asn_constr_check_f GANSSPositioningMethod_constraint; -ber_type_decoder_f GANSSPositioningMethod_decode_ber; -der_type_encoder_f GANSSPositioningMethod_encode_der; -xer_type_decoder_f GANSSPositioningMethod_decode_xer; -xer_type_encoder_f GANSSPositioningMethod_encode_xer; -per_type_decoder_f GANSSPositioningMethod_decode_uper; -per_type_encoder_f GANSSPositioningMethod_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSPositioningMethod; + asn_struct_free_f GANSSPositioningMethod_free; + asn_struct_print_f GANSSPositioningMethod_print; + asn_constr_check_f GANSSPositioningMethod_constraint; + ber_type_decoder_f GANSSPositioningMethod_decode_ber; + der_type_encoder_f GANSSPositioningMethod_encode_der; + xer_type_decoder_f GANSSPositioningMethod_decode_xer; + xer_type_encoder_f GANSSPositioningMethod_encode_xer; + per_type_decoder_f GANSSPositioningMethod_decode_uper; + per_type_encoder_f GANSSPositioningMethod_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSPositioningMethod_H_ */ +#endif /* _GANSSPositioningMethod_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSRealTimeIntegrity.h b/src/core/libs/supl/asn-rrlp/GANSSRealTimeIntegrity.h index d3fa6649a..389994464 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSRealTimeIntegrity.h +++ b/src/core/libs/supl/asn-rrlp/GANSSRealTimeIntegrity.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSRealTimeIntegrity_H_ -#define _GANSSRealTimeIntegrity_H_ +#ifndef _GANSSRealTimeIntegrity_H_ +#define _GANSSRealTimeIntegrity_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSRealTimeIntegrity */ -typedef struct GANSSRealTimeIntegrity { - SeqOfBadSignalElement_t ganssBadSignalList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSRealTimeIntegrity_t; + /* GANSSRealTimeIntegrity */ + typedef struct GANSSRealTimeIntegrity + { + SeqOfBadSignalElement_t ganssBadSignalList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSRealTimeIntegrity; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSRealTimeIntegrity_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSRealTimeIntegrity; #ifdef __cplusplus } #endif -#endif /* _GANSSRealTimeIntegrity_H_ */ +#endif /* _GANSSRealTimeIntegrity_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSRefLocation.h b/src/core/libs/supl/asn-rrlp/GANSSRefLocation.h index ea8ab7bb8..70b9d79fe 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSRefLocation.h +++ b/src/core/libs/supl/asn-rrlp/GANSSRefLocation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSRefLocation_H_ -#define _GANSSRefLocation_H_ +#ifndef _GANSSRefLocation_H_ +#define _GANSSRefLocation_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSRefLocation */ -typedef struct GANSSRefLocation { - Ext_GeographicalInformation_t threeDLocation; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSRefLocation_t; + /* GANSSRefLocation */ + typedef struct GANSSRefLocation + { + Ext_GeographicalInformation_t threeDLocation; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSRefLocation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSRefLocation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSRefLocation; #ifdef __cplusplus } #endif -#endif /* _GANSSRefLocation_H_ */ +#endif /* _GANSSRefLocation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementAssist.h b/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementAssist.h index 0fc7a48f7..e6af89db3 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementAssist.h +++ b/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementAssist.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSRefMeasurementAssist_H_ -#define _GANSSRefMeasurementAssist_H_ +#ifndef _GANSSRefMeasurementAssist_H_ +#define _GANSSRefMeasurementAssist_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSRefMeasurementAssist */ -typedef struct GANSSRefMeasurementAssist { - long *ganssSignalID /* OPTIONAL */; - SeqOfGANSSRefMeasurementElement_t ganssRefMeasAssitList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSRefMeasurementAssist_t; + /* GANSSRefMeasurementAssist */ + typedef struct GANSSRefMeasurementAssist + { + long *ganssSignalID /* OPTIONAL */; + SeqOfGANSSRefMeasurementElement_t ganssRefMeasAssitList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSRefMeasurementAssist; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSRefMeasurementAssist_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSRefMeasurementAssist; #ifdef __cplusplus } #endif -#endif /* _GANSSRefMeasurementAssist_H_ */ +#endif /* _GANSSRefMeasurementAssist_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementElement.h b/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementElement.h index 2c98266fb..42869c0dd 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSSRefMeasurementElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSRefMeasurementElement_H_ -#define _GANSSRefMeasurementElement_H_ +#ifndef _GANSSRefMeasurementElement_H_ +#define _GANSSRefMeasurementElement_H_ #include @@ -16,33 +16,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct AdditionalDopplerFields; -struct AddionalAngleFields; + /* Forward declarations */ + struct AdditionalDopplerFields; + struct AddionalAngleFields; -/* GANSSRefMeasurementElement */ -typedef struct GANSSRefMeasurementElement { - SVID_t svID; - long doppler0; - struct AdditionalDopplerFields *additionalDoppler /* OPTIONAL */; - long codePhase; - long intCodePhase; - long codePhaseSearchWindow; - struct AddionalAngleFields *additionalAngle /* OPTIONAL */; - /* + /* GANSSRefMeasurementElement */ + typedef struct GANSSRefMeasurementElement + { + SVID_t svID; + long doppler0; + struct AdditionalDopplerFields *additionalDoppler /* OPTIONAL */; + long codePhase; + long intCodePhase; + long codePhaseSearchWindow; + struct AddionalAngleFields *additionalAngle /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSRefMeasurementElement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSRefMeasurementElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSRefMeasurementElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSRefMeasurementElement; #ifdef __cplusplus } @@ -52,5 +54,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSRefMeasurementElement; #include "AdditionalDopplerFields.h" #include "AddionalAngleFields.h" -#endif /* _GANSSRefMeasurementElement_H_ */ +#endif /* _GANSSRefMeasurementElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSRefTimeInfo.h b/src/core/libs/supl/asn-rrlp/GANSSRefTimeInfo.h index 58139a317..508883f89 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSRefTimeInfo.h +++ b/src/core/libs/supl/asn-rrlp/GANSSRefTimeInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSRefTimeInfo_H_ -#define _GANSSRefTimeInfo_H_ +#ifndef _GANSSRefTimeInfo_H_ +#define _GANSSRefTimeInfo_H_ #include @@ -17,26 +17,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSRefTimeInfo */ -typedef struct GANSSRefTimeInfo { - long *ganssDay /* OPTIONAL */; - GANSSTOD_t ganssTOD; - GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; - long *ganssTimeID /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSRefTimeInfo_t; + /* GANSSRefTimeInfo */ + typedef struct GANSSRefTimeInfo + { + long *ganssDay /* OPTIONAL */; + GANSSTOD_t ganssTOD; + GANSSTODUncertainty_t *ganssTODUncertainty /* OPTIONAL */; + long *ganssTimeID /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSRefTimeInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSRefTimeInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSRefTimeInfo; #ifdef __cplusplus } #endif -#endif /* _GANSSRefTimeInfo_H_ */ +#endif /* _GANSSRefTimeInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSReferenceTime.h b/src/core/libs/supl/asn-rrlp/GANSSReferenceTime.h index e58e47069..adf0a749e 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSReferenceTime.h +++ b/src/core/libs/supl/asn-rrlp/GANSSReferenceTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSReferenceTime_H_ -#define _GANSSReferenceTime_H_ +#ifndef _GANSSReferenceTime_H_ +#define _GANSSReferenceTime_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSTOD_GSMTimeAssociation; + /* Forward declarations */ + struct GANSSTOD_GSMTimeAssociation; -/* GANSSReferenceTime */ -typedef struct GANSSReferenceTime { - GANSSRefTimeInfo_t ganssRefTimeInfo; - struct GANSSTOD_GSMTimeAssociation *ganssTOD_GSMTimeAssociation /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSReferenceTime_t; + /* GANSSReferenceTime */ + typedef struct GANSSReferenceTime + { + GANSSRefTimeInfo_t ganssRefTimeInfo; + struct GANSSTOD_GSMTimeAssociation *ganssTOD_GSMTimeAssociation /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSReferenceTime; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSReferenceTime_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSReferenceTime; #ifdef __cplusplus } @@ -40,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GANSSReferenceTime; /* Referred external types */ #include "GANSSTOD-GSMTimeAssociation.h" -#endif /* _GANSSReferenceTime_H_ */ +#endif /* _GANSSReferenceTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSSatelliteElement.h b/src/core/libs/supl/asn-rrlp/GANSSSatelliteElement.h index 4027c41c5..5af0f54de 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSSatelliteElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSSSatelliteElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSSatelliteElement_H_ -#define _GANSSSatelliteElement_H_ +#ifndef _GANSSSatelliteElement_H_ +#define _GANSSSatelliteElement_H_ #include @@ -18,31 +18,33 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSSatelliteElement */ -typedef struct GANSSSatelliteElement { - SVID_t svID; - long svHealth; - long iod; - GANSSClockModel_t ganssClockModel; - GANSSOrbitModel_t ganssOrbitModel; - /* + /* GANSSSatelliteElement */ + typedef struct GANSSSatelliteElement + { + SVID_t svID; + long svHealth; + long iod; + GANSSClockModel_t ganssClockModel; + GANSSOrbitModel_t ganssOrbitModel; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSSatelliteElement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSSatelliteElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSSatelliteElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSSatelliteElement; #ifdef __cplusplus } #endif -#endif /* _GANSSSatelliteElement_H_ */ +#endif /* _GANSSSatelliteElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSSignalID.h b/src/core/libs/supl/asn-rrlp/GANSSSignalID.h index 8788fcf15..e89105ba3 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSSignalID.h +++ b/src/core/libs/supl/asn-rrlp/GANSSSignalID.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSSignalID_H_ -#define _GANSSSignalID_H_ +#ifndef _GANSSSignalID_H_ +#define _GANSSSignalID_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSSignalID */ -typedef long GANSSSignalID_t; + /* GANSSSignalID */ + typedef long GANSSSignalID_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSSignalID; -asn_struct_free_f GANSSSignalID_free; -asn_struct_print_f GANSSSignalID_print; -asn_constr_check_f GANSSSignalID_constraint; -ber_type_decoder_f GANSSSignalID_decode_ber; -der_type_encoder_f GANSSSignalID_encode_der; -xer_type_decoder_f GANSSSignalID_decode_xer; -xer_type_encoder_f GANSSSignalID_encode_xer; -per_type_decoder_f GANSSSignalID_decode_uper; -per_type_encoder_f GANSSSignalID_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSSignalID; + asn_struct_free_f GANSSSignalID_free; + asn_struct_print_f GANSSSignalID_print; + asn_constr_check_f GANSSSignalID_constraint; + ber_type_decoder_f GANSSSignalID_decode_ber; + der_type_encoder_f GANSSSignalID_encode_der; + xer_type_decoder_f GANSSSignalID_decode_xer; + xer_type_encoder_f GANSSSignalID_encode_xer; + per_type_decoder_f GANSSSignalID_decode_uper; + per_type_encoder_f GANSSSignalID_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSSignalID_H_ */ +#endif /* _GANSSSignalID_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSTOD-GSMTimeAssociation.h b/src/core/libs/supl/asn-rrlp/GANSSTOD-GSMTimeAssociation.h index 2d3f021a2..b6016268f 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSTOD-GSMTimeAssociation.h +++ b/src/core/libs/supl/asn-rrlp/GANSSTOD-GSMTimeAssociation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSTOD_GSMTimeAssociation_H_ -#define _GANSSTOD_GSMTimeAssociation_H_ +#ifndef _GANSSTOD_GSMTimeAssociation_H_ +#define _GANSSTOD_GSMTimeAssociation_H_ #include @@ -20,28 +20,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSTOD-GSMTimeAssociation */ -typedef struct GANSSTOD_GSMTimeAssociation { - BCCHCarrier_t bcchCarrier; - BSIC_t bsic; - FrameNumber_t frameNumber; - TimeSlot_t timeSlot; - BitNumber_t bitNumber; - FrameDrift_t *frameDrift /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSTOD_GSMTimeAssociation_t; + /* GANSSTOD-GSMTimeAssociation */ + typedef struct GANSSTOD_GSMTimeAssociation + { + BCCHCarrier_t bcchCarrier; + BSIC_t bsic; + FrameNumber_t frameNumber; + TimeSlot_t timeSlot; + BitNumber_t bitNumber; + FrameDrift_t *frameDrift /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSTOD_GSMTimeAssociation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSTOD_GSMTimeAssociation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSTOD_GSMTimeAssociation; #ifdef __cplusplus } #endif -#endif /* _GANSSTOD_GSMTimeAssociation_H_ */ +#endif /* _GANSSTOD_GSMTimeAssociation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSTOD.h b/src/core/libs/supl/asn-rrlp/GANSSTOD.h index ba5ff9342..e8b62ef2c 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSTOD.h +++ b/src/core/libs/supl/asn-rrlp/GANSSTOD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSTOD_H_ -#define _GANSSTOD_H_ +#ifndef _GANSSTOD_H_ +#define _GANSSTOD_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSTOD */ -typedef long GANSSTOD_t; + /* GANSSTOD */ + typedef long GANSSTOD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSTOD; -asn_struct_free_f GANSSTOD_free; -asn_struct_print_f GANSSTOD_print; -asn_constr_check_f GANSSTOD_constraint; -ber_type_decoder_f GANSSTOD_decode_ber; -der_type_encoder_f GANSSTOD_encode_der; -xer_type_decoder_f GANSSTOD_decode_xer; -xer_type_encoder_f GANSSTOD_encode_xer; -per_type_decoder_f GANSSTOD_decode_uper; -per_type_encoder_f GANSSTOD_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSTOD; + asn_struct_free_f GANSSTOD_free; + asn_struct_print_f GANSSTOD_print; + asn_constr_check_f GANSSTOD_constraint; + ber_type_decoder_f GANSSTOD_decode_ber; + der_type_encoder_f GANSSTOD_encode_der; + xer_type_decoder_f GANSSTOD_decode_xer; + xer_type_encoder_f GANSSTOD_encode_xer; + per_type_decoder_f GANSSTOD_decode_uper; + per_type_encoder_f GANSSTOD_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSTOD_H_ */ +#endif /* _GANSSTOD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSTODUncertainty.h b/src/core/libs/supl/asn-rrlp/GANSSTODUncertainty.h index e373153a9..8997e77e4 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSTODUncertainty.h +++ b/src/core/libs/supl/asn-rrlp/GANSSTODUncertainty.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSTODUncertainty_H_ -#define _GANSSTODUncertainty_H_ +#ifndef _GANSSTODUncertainty_H_ +#define _GANSSTODUncertainty_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSTODUncertainty */ -typedef long GANSSTODUncertainty_t; + /* GANSSTODUncertainty */ + typedef long GANSSTODUncertainty_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSTODUncertainty; -asn_struct_free_f GANSSTODUncertainty_free; -asn_struct_print_f GANSSTODUncertainty_print; -asn_constr_check_f GANSSTODUncertainty_constraint; -ber_type_decoder_f GANSSTODUncertainty_decode_ber; -der_type_encoder_f GANSSTODUncertainty_encode_der; -xer_type_decoder_f GANSSTODUncertainty_decode_xer; -xer_type_encoder_f GANSSTODUncertainty_encode_xer; -per_type_decoder_f GANSSTODUncertainty_decode_uper; -per_type_encoder_f GANSSTODUncertainty_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSTODUncertainty; + asn_struct_free_f GANSSTODUncertainty_free; + asn_struct_print_f GANSSTODUncertainty_print; + asn_constr_check_f GANSSTODUncertainty_constraint; + ber_type_decoder_f GANSSTODUncertainty_decode_ber; + der_type_encoder_f GANSSTODUncertainty_encode_der; + xer_type_decoder_f GANSSTODUncertainty_decode_xer; + xer_type_encoder_f GANSSTODUncertainty_encode_xer; + per_type_decoder_f GANSSTODUncertainty_decode_uper; + per_type_encoder_f GANSSTODUncertainty_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSTODUncertainty_H_ */ +#endif /* _GANSSTODUncertainty_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSTODm.h b/src/core/libs/supl/asn-rrlp/GANSSTODm.h index f539c988f..008482f2c 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSTODm.h +++ b/src/core/libs/supl/asn-rrlp/GANSSTODm.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSTODm_H_ -#define _GANSSTODm_H_ +#ifndef _GANSSTODm_H_ +#define _GANSSTODm_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSTODm */ -typedef long GANSSTODm_t; + /* GANSSTODm */ + typedef long GANSSTODm_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSTODm; -asn_struct_free_f GANSSTODm_free; -asn_struct_print_f GANSSTODm_print; -asn_constr_check_f GANSSTODm_constraint; -ber_type_decoder_f GANSSTODm_decode_ber; -der_type_encoder_f GANSSTODm_encode_der; -xer_type_decoder_f GANSSTODm_decode_xer; -xer_type_encoder_f GANSSTODm_encode_xer; -per_type_decoder_f GANSSTODm_decode_uper; -per_type_encoder_f GANSSTODm_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSTODm; + asn_struct_free_f GANSSTODm_free; + asn_struct_print_f GANSSTODm_print; + asn_constr_check_f GANSSTODm_constraint; + ber_type_decoder_f GANSSTODm_decode_ber; + der_type_encoder_f GANSSTODm_encode_der; + xer_type_decoder_f GANSSTODm_decode_xer; + xer_type_encoder_f GANSSTODm_encode_xer; + per_type_decoder_f GANSSTODm_decode_uper; + per_type_encoder_f GANSSTODm_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GANSSTODm_H_ */ +#endif /* _GANSSTODm_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSTimeModelElement.h b/src/core/libs/supl/asn-rrlp/GANSSTimeModelElement.h index f3fe2d398..2ffc74388 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSTimeModelElement.h +++ b/src/core/libs/supl/asn-rrlp/GANSSTimeModelElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSTimeModelElement_H_ -#define _GANSSTimeModelElement_H_ +#ifndef _GANSSTimeModelElement_H_ +#define _GANSSTimeModelElement_H_ #include @@ -18,28 +18,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSTimeModelElement */ -typedef struct GANSSTimeModelElement { - long ganssTimeModelRefTime; - TA0_t tA0; - TA1_t *tA1 /* OPTIONAL */; - TA2_t *tA2 /* OPTIONAL */; - long gnssTOID; - long *weekNumber /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSTimeModelElement_t; + /* GANSSTimeModelElement */ + typedef struct GANSSTimeModelElement + { + long ganssTimeModelRefTime; + TA0_t tA0; + TA1_t *tA1 /* OPTIONAL */; + TA2_t *tA2 /* OPTIONAL */; + long gnssTOID; + long *weekNumber /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSTimeModelElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSTimeModelElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSTimeModelElement; #ifdef __cplusplus } #endif -#endif /* _GANSSTimeModelElement_H_ */ +#endif /* _GANSSTimeModelElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GANSSUTCModel.h b/src/core/libs/supl/asn-rrlp/GANSSUTCModel.h index 9afaf9886..4f0c74735 100644 --- a/src/core/libs/supl/asn-rrlp/GANSSUTCModel.h +++ b/src/core/libs/supl/asn-rrlp/GANSSUTCModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GANSSUTCModel_H_ -#define _GANSSUTCModel_H_ +#ifndef _GANSSUTCModel_H_ +#define _GANSSUTCModel_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GANSSUTCModel */ -typedef struct GANSSUTCModel { - long ganssUtcA1; - long ganssUtcA0; - long ganssUtcTot; - long ganssUtcWNt; - long ganssUtcDeltaTls; - long ganssUtcWNlsf; - long ganssUtcDN; - long ganssUtcDeltaTlsf; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GANSSUTCModel_t; + /* GANSSUTCModel */ + typedef struct GANSSUTCModel + { + long ganssUtcA1; + long ganssUtcA0; + long ganssUtcTot; + long ganssUtcWNt; + long ganssUtcDeltaTls; + long ganssUtcWNlsf; + long ganssUtcDN; + long ganssUtcDeltaTlsf; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GANSSUTCModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GANSSUTCModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GANSSUTCModel; #ifdef __cplusplus } #endif -#endif /* _GANSSUTCModel_H_ */ +#endif /* _GANSSUTCModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPS-AssistData.h b/src/core/libs/supl/asn-rrlp/GPS-AssistData.h index 94c27b961..0eb180068 100644 --- a/src/core/libs/supl/asn-rrlp/GPS-AssistData.h +++ b/src/core/libs/supl/asn-rrlp/GPS-AssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPS_AssistData_H_ -#define _GPS_AssistData_H_ +#ifndef _GPS_AssistData_H_ +#define _GPS_AssistData_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPS-AssistData */ -typedef struct GPS_AssistData { - ControlHeader_t controlHeader; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPS_AssistData_t; + /* GPS-AssistData */ + typedef struct GPS_AssistData + { + ControlHeader_t controlHeader; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPS_AssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPS_AssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPS_AssistData; #ifdef __cplusplus } #endif -#endif /* _GPS_AssistData_H_ */ +#endif /* _GPS_AssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPS-MeasureInfo.h b/src/core/libs/supl/asn-rrlp/GPS-MeasureInfo.h index 477bb68da..94049297c 100644 --- a/src/core/libs/supl/asn-rrlp/GPS-MeasureInfo.h +++ b/src/core/libs/supl/asn-rrlp/GPS-MeasureInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPS_MeasureInfo_H_ -#define _GPS_MeasureInfo_H_ +#ifndef _GPS_MeasureInfo_H_ +#define _GPS_MeasureInfo_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPS-MeasureInfo */ -typedef struct GPS_MeasureInfo { - SeqOfGPS_MsrSetElement_t gpsMsrSetList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPS_MeasureInfo_t; + /* GPS-MeasureInfo */ + typedef struct GPS_MeasureInfo + { + SeqOfGPS_MsrSetElement_t gpsMsrSetList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPS_MeasureInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPS_MeasureInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPS_MeasureInfo; #ifdef __cplusplus } #endif -#endif /* _GPS_MeasureInfo_H_ */ +#endif /* _GPS_MeasureInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPS-MsrElement.h b/src/core/libs/supl/asn-rrlp/GPS-MsrElement.h index 8c7943be3..20fc55f7b 100644 --- a/src/core/libs/supl/asn-rrlp/GPS-MsrElement.h +++ b/src/core/libs/supl/asn-rrlp/GPS-MsrElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPS_MsrElement_H_ -#define _GPS_MsrElement_H_ +#ifndef _GPS_MsrElement_H_ +#define _GPS_MsrElement_H_ #include @@ -17,29 +17,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPS-MsrElement */ -typedef struct GPS_MsrElement { - SatelliteID_t satelliteID; - long cNo; - long doppler; - long wholeChips; - long fracChips; - MpathIndic_t mpathIndic; - long pseuRangeRMSErr; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPS_MsrElement_t; + /* GPS-MsrElement */ + typedef struct GPS_MsrElement + { + SatelliteID_t satelliteID; + long cNo; + long doppler; + long wholeChips; + long fracChips; + MpathIndic_t mpathIndic; + long pseuRangeRMSErr; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPS_MsrElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPS_MsrElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPS_MsrElement; #ifdef __cplusplus } #endif -#endif /* _GPS_MsrElement_H_ */ +#endif /* _GPS_MsrElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPS-MsrSetElement.h b/src/core/libs/supl/asn-rrlp/GPS-MsrSetElement.h index bcb0c7d88..9f73ac026 100644 --- a/src/core/libs/supl/asn-rrlp/GPS-MsrSetElement.h +++ b/src/core/libs/supl/asn-rrlp/GPS-MsrSetElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPS_MsrSetElement_H_ -#define _GPS_MsrSetElement_H_ +#ifndef _GPS_MsrSetElement_H_ +#define _GPS_MsrSetElement_H_ #include @@ -17,25 +17,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPS-MsrSetElement */ -typedef struct GPS_MsrSetElement { - long *refFrame /* OPTIONAL */; - GPSTOW24b_t gpsTOW; - SeqOfGPS_MsrElement_t gps_msrList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPS_MsrSetElement_t; + /* GPS-MsrSetElement */ + typedef struct GPS_MsrSetElement + { + long *refFrame /* OPTIONAL */; + GPSTOW24b_t gpsTOW; + SeqOfGPS_MsrElement_t gps_msrList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPS_MsrSetElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPS_MsrSetElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPS_MsrSetElement; #ifdef __cplusplus } #endif -#endif /* _GPS_MsrSetElement_H_ */ +#endif /* _GPS_MsrSetElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSAssistanceData.h b/src/core/libs/supl/asn-rrlp/GPSAssistanceData.h index 55a4ffb25..4716111b7 100644 --- a/src/core/libs/supl/asn-rrlp/GPSAssistanceData.h +++ b/src/core/libs/supl/asn-rrlp/GPSAssistanceData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSAssistanceData_H_ -#define _GPSAssistanceData_H_ +#ifndef _GPSAssistanceData_H_ +#define _GPSAssistanceData_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSAssistanceData */ -typedef OCTET_STRING_t GPSAssistanceData_t; + /* GPSAssistanceData */ + typedef OCTET_STRING_t GPSAssistanceData_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSAssistanceData; -asn_struct_free_f GPSAssistanceData_free; -asn_struct_print_f GPSAssistanceData_print; -asn_constr_check_f GPSAssistanceData_constraint; -ber_type_decoder_f GPSAssistanceData_decode_ber; -der_type_encoder_f GPSAssistanceData_encode_der; -xer_type_decoder_f GPSAssistanceData_decode_xer; -xer_type_encoder_f GPSAssistanceData_encode_xer; -per_type_decoder_f GPSAssistanceData_decode_uper; -per_type_encoder_f GPSAssistanceData_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSAssistanceData; + asn_struct_free_f GPSAssistanceData_free; + asn_struct_print_f GPSAssistanceData_print; + asn_constr_check_f GPSAssistanceData_constraint; + ber_type_decoder_f GPSAssistanceData_decode_ber; + der_type_encoder_f GPSAssistanceData_encode_der; + xer_type_decoder_f GPSAssistanceData_decode_xer; + xer_type_encoder_f GPSAssistanceData_encode_xer; + per_type_decoder_f GPSAssistanceData_decode_uper; + per_type_encoder_f GPSAssistanceData_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GPSAssistanceData_H_ */ +#endif /* _GPSAssistanceData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSReferenceTimeUncertainty.h b/src/core/libs/supl/asn-rrlp/GPSReferenceTimeUncertainty.h index 7be8ebb31..2fe9b91af 100644 --- a/src/core/libs/supl/asn-rrlp/GPSReferenceTimeUncertainty.h +++ b/src/core/libs/supl/asn-rrlp/GPSReferenceTimeUncertainty.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSReferenceTimeUncertainty_H_ -#define _GPSReferenceTimeUncertainty_H_ +#ifndef _GPSReferenceTimeUncertainty_H_ +#define _GPSReferenceTimeUncertainty_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSReferenceTimeUncertainty */ -typedef long GPSReferenceTimeUncertainty_t; + /* GPSReferenceTimeUncertainty */ + typedef long GPSReferenceTimeUncertainty_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSReferenceTimeUncertainty; -asn_struct_free_f GPSReferenceTimeUncertainty_free; -asn_struct_print_f GPSReferenceTimeUncertainty_print; -asn_constr_check_f GPSReferenceTimeUncertainty_constraint; -ber_type_decoder_f GPSReferenceTimeUncertainty_decode_ber; -der_type_encoder_f GPSReferenceTimeUncertainty_encode_der; -xer_type_decoder_f GPSReferenceTimeUncertainty_decode_xer; -xer_type_encoder_f GPSReferenceTimeUncertainty_encode_xer; -per_type_decoder_f GPSReferenceTimeUncertainty_decode_uper; -per_type_encoder_f GPSReferenceTimeUncertainty_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSReferenceTimeUncertainty; + asn_struct_free_f GPSReferenceTimeUncertainty_free; + asn_struct_print_f GPSReferenceTimeUncertainty_print; + asn_constr_check_f GPSReferenceTimeUncertainty_constraint; + ber_type_decoder_f GPSReferenceTimeUncertainty_decode_ber; + der_type_encoder_f GPSReferenceTimeUncertainty_encode_der; + xer_type_decoder_f GPSReferenceTimeUncertainty_decode_xer; + xer_type_encoder_f GPSReferenceTimeUncertainty_encode_xer; + per_type_decoder_f GPSReferenceTimeUncertainty_decode_uper; + per_type_encoder_f GPSReferenceTimeUncertainty_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GPSReferenceTimeUncertainty_H_ */ +#endif /* _GPSReferenceTimeUncertainty_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTOW23b.h b/src/core/libs/supl/asn-rrlp/GPSTOW23b.h index 49f34a714..f280e9419 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTOW23b.h +++ b/src/core/libs/supl/asn-rrlp/GPSTOW23b.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTOW23b_H_ -#define _GPSTOW23b_H_ +#ifndef _GPSTOW23b_H_ +#define _GPSTOW23b_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSTOW23b */ -typedef long GPSTOW23b_t; + /* GPSTOW23b */ + typedef long GPSTOW23b_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTOW23b; -asn_struct_free_f GPSTOW23b_free; -asn_struct_print_f GPSTOW23b_print; -asn_constr_check_f GPSTOW23b_constraint; -ber_type_decoder_f GPSTOW23b_decode_ber; -der_type_encoder_f GPSTOW23b_encode_der; -xer_type_decoder_f GPSTOW23b_decode_xer; -xer_type_encoder_f GPSTOW23b_encode_xer; -per_type_decoder_f GPSTOW23b_decode_uper; -per_type_encoder_f GPSTOW23b_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTOW23b; + asn_struct_free_f GPSTOW23b_free; + asn_struct_print_f GPSTOW23b_print; + asn_constr_check_f GPSTOW23b_constraint; + ber_type_decoder_f GPSTOW23b_decode_ber; + der_type_encoder_f GPSTOW23b_encode_der; + xer_type_decoder_f GPSTOW23b_decode_xer; + xer_type_encoder_f GPSTOW23b_encode_xer; + per_type_decoder_f GPSTOW23b_decode_uper; + per_type_encoder_f GPSTOW23b_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GPSTOW23b_H_ */ +#endif /* _GPSTOW23b_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTOW24b.h b/src/core/libs/supl/asn-rrlp/GPSTOW24b.h index 42ee6847f..a2e7831fd 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTOW24b.h +++ b/src/core/libs/supl/asn-rrlp/GPSTOW24b.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTOW24b_H_ -#define _GPSTOW24b_H_ +#ifndef _GPSTOW24b_H_ +#define _GPSTOW24b_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSTOW24b */ -typedef long GPSTOW24b_t; + /* GPSTOW24b */ + typedef long GPSTOW24b_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTOW24b; -asn_struct_free_f GPSTOW24b_free; -asn_struct_print_f GPSTOW24b_print; -asn_constr_check_f GPSTOW24b_constraint; -ber_type_decoder_f GPSTOW24b_decode_ber; -der_type_encoder_f GPSTOW24b_encode_der; -xer_type_decoder_f GPSTOW24b_decode_xer; -xer_type_encoder_f GPSTOW24b_encode_xer; -per_type_decoder_f GPSTOW24b_decode_uper; -per_type_encoder_f GPSTOW24b_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTOW24b; + asn_struct_free_f GPSTOW24b_free; + asn_struct_print_f GPSTOW24b_print; + asn_constr_check_f GPSTOW24b_constraint; + ber_type_decoder_f GPSTOW24b_decode_ber; + der_type_encoder_f GPSTOW24b_encode_der; + xer_type_decoder_f GPSTOW24b_decode_xer; + xer_type_encoder_f GPSTOW24b_encode_xer; + per_type_decoder_f GPSTOW24b_decode_uper; + per_type_encoder_f GPSTOW24b_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GPSTOW24b_H_ */ +#endif /* _GPSTOW24b_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTOWAssist.h b/src/core/libs/supl/asn-rrlp/GPSTOWAssist.h index 837e8f635..e7ea606d2 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTOWAssist.h +++ b/src/core/libs/supl/asn-rrlp/GPSTOWAssist.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTOWAssist_H_ -#define _GPSTOWAssist_H_ +#ifndef _GPSTOWAssist_H_ +#define _GPSTOWAssist_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GPSTOWAssistElement; + /* Forward declarations */ + struct GPSTOWAssistElement; -/* GPSTOWAssist */ -typedef struct GPSTOWAssist { - A_SEQUENCE_OF(struct GPSTOWAssistElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPSTOWAssist_t; + /* GPSTOWAssist */ + typedef struct GPSTOWAssist + { + A_SEQUENCE_OF(struct GPSTOWAssistElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTOWAssist; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPSTOWAssist_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTOWAssist; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GPSTOWAssist; /* Referred external types */ #include "GPSTOWAssistElement.h" -#endif /* _GPSTOWAssist_H_ */ +#endif /* _GPSTOWAssist_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTOWAssistElement.h b/src/core/libs/supl/asn-rrlp/GPSTOWAssistElement.h index a3a2f8199..939b7b3e5 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTOWAssistElement.h +++ b/src/core/libs/supl/asn-rrlp/GPSTOWAssistElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTOWAssistElement_H_ -#define _GPSTOWAssistElement_H_ +#ifndef _GPSTOWAssistElement_H_ +#define _GPSTOWAssistElement_H_ #include @@ -19,27 +19,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSTOWAssistElement */ -typedef struct GPSTOWAssistElement { - SatelliteID_t satelliteID; - TLMWord_t tlmWord; - AntiSpoofFlag_t antiSpoof; - AlertFlag_t alert; - TLMReservedBits_t tlmRsvdBits; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPSTOWAssistElement_t; + /* GPSTOWAssistElement */ + typedef struct GPSTOWAssistElement + { + SatelliteID_t satelliteID; + TLMWord_t tlmWord; + AntiSpoofFlag_t antiSpoof; + AlertFlag_t alert; + TLMReservedBits_t tlmRsvdBits; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTOWAssistElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPSTOWAssistElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTOWAssistElement; #ifdef __cplusplus } #endif -#endif /* _GPSTOWAssistElement_H_ */ +#endif /* _GPSTOWAssistElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTime.h b/src/core/libs/supl/asn-rrlp/GPSTime.h index bb6a03667..b25b5af57 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTime.h +++ b/src/core/libs/supl/asn-rrlp/GPSTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTime_H_ -#define _GPSTime_H_ +#ifndef _GPSTime_H_ +#define _GPSTime_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSTime */ -typedef struct GPSTime { - GPSTOW23b_t gpsTOW23b; - GPSWeek_t gpsWeek; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPSTime_t; + /* GPSTime */ + typedef struct GPSTime + { + GPSTOW23b_t gpsTOW23b; + GPSWeek_t gpsWeek; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTime; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPSTime_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTime; #ifdef __cplusplus } #endif -#endif /* _GPSTime_H_ */ +#endif /* _GPSTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSTimeAssistanceMeasurements.h b/src/core/libs/supl/asn-rrlp/GPSTimeAssistanceMeasurements.h index 1f30ed0e5..8bc8dfce0 100644 --- a/src/core/libs/supl/asn-rrlp/GPSTimeAssistanceMeasurements.h +++ b/src/core/libs/supl/asn-rrlp/GPSTimeAssistanceMeasurements.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSTimeAssistanceMeasurements_H_ -#define _GPSTimeAssistanceMeasurements_H_ +#ifndef _GPSTimeAssistanceMeasurements_H_ +#define _GPSTimeAssistanceMeasurements_H_ #include @@ -16,26 +16,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSTimeAssistanceMeasurements */ -typedef struct GPSTimeAssistanceMeasurements { - long referenceFrameMSB; - long *gpsTowSubms /* OPTIONAL */; - long *deltaTow /* OPTIONAL */; - GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GPSTimeAssistanceMeasurements_t; + /* GPSTimeAssistanceMeasurements */ + typedef struct GPSTimeAssistanceMeasurements + { + long referenceFrameMSB; + long *gpsTowSubms /* OPTIONAL */; + long *deltaTow /* OPTIONAL */; + GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSTimeAssistanceMeasurements; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GPSTimeAssistanceMeasurements_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSTimeAssistanceMeasurements; #ifdef __cplusplus } #endif -#endif /* _GPSTimeAssistanceMeasurements_H_ */ +#endif /* _GPSTimeAssistanceMeasurements_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GPSWeek.h b/src/core/libs/supl/asn-rrlp/GPSWeek.h index 6bdbc01bf..bcfe49b70 100644 --- a/src/core/libs/supl/asn-rrlp/GPSWeek.h +++ b/src/core/libs/supl/asn-rrlp/GPSWeek.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GPSWeek_H_ -#define _GPSWeek_H_ +#ifndef _GPSWeek_H_ +#define _GPSWeek_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GPSWeek */ -typedef long GPSWeek_t; + /* GPSWeek */ + typedef long GPSWeek_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GPSWeek; -asn_struct_free_f GPSWeek_free; -asn_struct_print_f GPSWeek_print; -asn_constr_check_f GPSWeek_constraint; -ber_type_decoder_f GPSWeek_decode_ber; -der_type_encoder_f GPSWeek_encode_der; -xer_type_decoder_f GPSWeek_decode_xer; -xer_type_encoder_f GPSWeek_encode_xer; -per_type_decoder_f GPSWeek_decode_uper; -per_type_encoder_f GPSWeek_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GPSWeek; + asn_struct_free_f GPSWeek_free; + asn_struct_print_f GPSWeek_print; + asn_constr_check_f GPSWeek_constraint; + ber_type_decoder_f GPSWeek_decode_ber; + der_type_encoder_f GPSWeek_encode_der; + xer_type_decoder_f GPSWeek_decode_xer; + xer_type_encoder_f GPSWeek_encode_xer; + per_type_decoder_f GPSWeek_decode_uper; + per_type_encoder_f GPSWeek_encode_uper; #ifdef __cplusplus } #endif -#endif /* _GPSWeek_H_ */ +#endif /* _GPSWeek_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/GSMTime.h b/src/core/libs/supl/asn-rrlp/GSMTime.h index ea4fd2568..9f360bb13 100644 --- a/src/core/libs/supl/asn-rrlp/GSMTime.h +++ b/src/core/libs/supl/asn-rrlp/GSMTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _GSMTime_H_ -#define _GSMTime_H_ +#ifndef _GSMTime_H_ +#define _GSMTime_H_ #include @@ -19,27 +19,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* GSMTime */ -typedef struct GSMTime { - BCCHCarrier_t bcchCarrier; - BSIC_t bsic; - FrameNumber_t frameNumber; - TimeSlot_t timeSlot; - BitNumber_t bitNumber; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GSMTime_t; + /* GSMTime */ + typedef struct GSMTime + { + BCCHCarrier_t bcchCarrier; + BSIC_t bsic; + FrameNumber_t frameNumber; + TimeSlot_t timeSlot; + BitNumber_t bitNumber; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GSMTime; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GSMTime_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GSMTime; #ifdef __cplusplus } #endif -#endif /* _GSMTime_H_ */ +#endif /* _GSMTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/INTEGER.h b/src/core/libs/supl/asn-rrlp/INTEGER.h index 8411bfcdd..2acd13ab9 100644 --- a/src/core/libs/supl/asn-rrlp/INTEGER.h +++ b/src/core/libs/supl/asn-rrlp/INTEGER.h @@ -2,68 +2,71 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _INTEGER_H_ -#define _INTEGER_H_ +#ifndef _INTEGER_H_ +#define _INTEGER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; + typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; -extern asn_TYPE_descriptor_t asn_DEF_INTEGER; + extern asn_TYPE_descriptor_t asn_DEF_INTEGER; -/* Map with to integer value association */ -typedef struct asn_INTEGER_enum_map_s { - long nat_value; /* associated native integer value */ - size_t enum_len; /* strlen("tag") */ - const char *enum_name; /* "tag" */ -} asn_INTEGER_enum_map_t; + /* Map with to integer value association */ + typedef struct asn_INTEGER_enum_map_s + { + long nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ + } asn_INTEGER_enum_map_t; -/* This type describes an enumeration for INTEGER and ENUMERATED types */ -typedef struct asn_INTEGER_specifics_s { - asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ - unsigned int *enum2value; /* "tag" => N; sorted by tag */ - int map_count; /* Elements in either map */ - int extension; /* This map is extensible */ - int strict_enumeration; /* Enumeration set is fixed */ - int field_width; /* Size of native integer */ - int field_unsigned; /* Signed=0, unsigned=1 */ -} asn_INTEGER_specifics_t; + /* This type describes an enumeration for INTEGER and ENUMERATED types */ + typedef struct asn_INTEGER_specifics_s + { + asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + unsigned int *enum2value; /* "tag" => N; sorted by tag */ + int map_count; /* Elements in either map */ + int extension; /* This map is extensible */ + int strict_enumeration; /* Enumeration set is fixed */ + int field_width; /* Size of native integer */ + int field_unsigned; /* Signed=0, unsigned=1 */ + } asn_INTEGER_specifics_t; -asn_struct_print_f INTEGER_print; -ber_type_decoder_f INTEGER_decode_ber; -der_type_encoder_f INTEGER_encode_der; -xer_type_decoder_f INTEGER_decode_xer; -xer_type_encoder_f INTEGER_encode_xer; -per_type_decoder_f INTEGER_decode_uper; -per_type_encoder_f INTEGER_encode_uper; + asn_struct_print_f INTEGER_print; + ber_type_decoder_f INTEGER_decode_ber; + der_type_encoder_f INTEGER_encode_der; + xer_type_decoder_f INTEGER_decode_xer; + xer_type_encoder_f INTEGER_encode_xer; + per_type_decoder_f INTEGER_decode_uper; + per_type_encoder_f INTEGER_encode_uper; -/*********************************** + /*********************************** * Some handy conversion routines. * ***********************************/ -/* + /* * Returns 0 if it was possible to convert, -1 otherwise. * -1/EINVAL: Mandatory argument missing * -1/ERANGE: Value encoded is out of range for long representation * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). */ -int asn_INTEGER2long(const INTEGER_t *i, long *l); -int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); -int asn_long2INTEGER(INTEGER_t *i, long l); -int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); + int asn_INTEGER2long(const INTEGER_t *i, long *l); + int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); + int asn_long2INTEGER(INTEGER_t *i, long l); + int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); -/* + /* * Convert the integer value into the corresponding enumeration map entry. */ -const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); + const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); #ifdef __cplusplus } #endif -#endif /* _INTEGER_H_ */ +#endif /* _INTEGER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/IonosphericModel.h b/src/core/libs/supl/asn-rrlp/IonosphericModel.h index bb5f38987..1174aeef8 100644 --- a/src/core/libs/supl/asn-rrlp/IonosphericModel.h +++ b/src/core/libs/supl/asn-rrlp/IonosphericModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _IonosphericModel_H_ -#define _IonosphericModel_H_ +#ifndef _IonosphericModel_H_ +#define _IonosphericModel_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* IonosphericModel */ -typedef struct IonosphericModel { - long alfa0; - long alfa1; - long alfa2; - long alfa3; - long beta0; - long beta1; - long beta2; - long beta3; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} IonosphericModel_t; + /* IonosphericModel */ + typedef struct IonosphericModel + { + long alfa0; + long alfa1; + long alfa2; + long alfa3; + long beta0; + long beta1; + long beta2; + long beta3; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_IonosphericModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } IonosphericModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_IonosphericModel; #ifdef __cplusplus } #endif -#endif /* _IonosphericModel_H_ */ +#endif /* _IonosphericModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/LAC.h b/src/core/libs/supl/asn-rrlp/LAC.h index b600e36d4..69ccdb662 100644 --- a/src/core/libs/supl/asn-rrlp/LAC.h +++ b/src/core/libs/supl/asn-rrlp/LAC.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _LAC_H_ -#define _LAC_H_ +#ifndef _LAC_H_ +#define _LAC_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* LAC */ -typedef long LAC_t; + /* LAC */ + typedef long LAC_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_LAC; -asn_struct_free_f LAC_free; -asn_struct_print_f LAC_print; -asn_constr_check_f LAC_constraint; -ber_type_decoder_f LAC_decode_ber; -der_type_encoder_f LAC_encode_der; -xer_type_decoder_f LAC_decode_xer; -xer_type_encoder_f LAC_encode_xer; -per_type_decoder_f LAC_decode_uper; -per_type_encoder_f LAC_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_LAC; + asn_struct_free_f LAC_free; + asn_struct_print_f LAC_print; + asn_constr_check_f LAC_constraint; + ber_type_decoder_f LAC_decode_ber; + der_type_encoder_f LAC_encode_der; + xer_type_decoder_f LAC_decode_xer; + xer_type_encoder_f LAC_encode_xer; + per_type_decoder_f LAC_decode_uper; + per_type_encoder_f LAC_encode_uper; #ifdef __cplusplus } #endif -#endif /* _LAC_H_ */ +#endif /* _LAC_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/LocErrorReason.h b/src/core/libs/supl/asn-rrlp/LocErrorReason.h index 0dfcf0b80..e8d074804 100644 --- a/src/core/libs/supl/asn-rrlp/LocErrorReason.h +++ b/src/core/libs/supl/asn-rrlp/LocErrorReason.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _LocErrorReason_H_ -#define _LocErrorReason_H_ +#ifndef _LocErrorReason_H_ +#define _LocErrorReason_H_ #include @@ -14,48 +14,50 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum LocErrorReason { - LocErrorReason_unDefined = 0, - LocErrorReason_notEnoughBTSs = 1, - LocErrorReason_notEnoughSats = 2, - LocErrorReason_eotdLocCalAssDataMissing = 3, - LocErrorReason_eotdAssDataMissing = 4, - LocErrorReason_gpsLocCalAssDataMissing = 5, - LocErrorReason_gpsAssDataMissing = 6, - LocErrorReason_methodNotSupported = 7, - LocErrorReason_notProcessed = 8, - LocErrorReason_refBTSForGPSNotServingBTS = 9, - LocErrorReason_refBTSForEOTDNotServingBTS = 10, - /* + /* Dependencies */ + typedef enum LocErrorReason + { + LocErrorReason_unDefined = 0, + LocErrorReason_notEnoughBTSs = 1, + LocErrorReason_notEnoughSats = 2, + LocErrorReason_eotdLocCalAssDataMissing = 3, + LocErrorReason_eotdAssDataMissing = 4, + LocErrorReason_gpsLocCalAssDataMissing = 5, + LocErrorReason_gpsAssDataMissing = 6, + LocErrorReason_methodNotSupported = 7, + LocErrorReason_notProcessed = 8, + LocErrorReason_refBTSForGPSNotServingBTS = 9, + LocErrorReason_refBTSForEOTDNotServingBTS = 10, + /* * Enumeration is extensible */ - LocErrorReason_notEnoughGANSSSats = 11, - LocErrorReason_ganssAssDataMissing = 12, - LocErrorReason_refBTSForGANSSNotServingBTS = 13 -} e_LocErrorReason; + LocErrorReason_notEnoughGANSSSats = 11, + LocErrorReason_ganssAssDataMissing = 12, + LocErrorReason_refBTSForGANSSNotServingBTS = 13 + } e_LocErrorReason; -/* LocErrorReason */ -typedef ENUMERATED_t LocErrorReason_t; + /* LocErrorReason */ + typedef ENUMERATED_t LocErrorReason_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_LocErrorReason; -asn_struct_free_f LocErrorReason_free; -asn_struct_print_f LocErrorReason_print; -asn_constr_check_f LocErrorReason_constraint; -ber_type_decoder_f LocErrorReason_decode_ber; -der_type_encoder_f LocErrorReason_encode_der; -xer_type_decoder_f LocErrorReason_decode_xer; -xer_type_encoder_f LocErrorReason_encode_xer; -per_type_decoder_f LocErrorReason_decode_uper; -per_type_encoder_f LocErrorReason_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_LocErrorReason; + asn_struct_free_f LocErrorReason_free; + asn_struct_print_f LocErrorReason_print; + asn_constr_check_f LocErrorReason_constraint; + ber_type_decoder_f LocErrorReason_decode_ber; + der_type_encoder_f LocErrorReason_encode_der; + xer_type_decoder_f LocErrorReason_decode_xer; + xer_type_encoder_f LocErrorReason_encode_xer; + per_type_decoder_f LocErrorReason_decode_uper; + per_type_encoder_f LocErrorReason_encode_uper; #ifdef __cplusplus } #endif -#endif /* _LocErrorReason_H_ */ +#endif /* _LocErrorReason_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/LocationError.h b/src/core/libs/supl/asn-rrlp/LocationError.h index 2786f4b7a..1ab241eba 100644 --- a/src/core/libs/supl/asn-rrlp/LocationError.h +++ b/src/core/libs/supl/asn-rrlp/LocationError.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _LocationError_H_ -#define _LocationError_H_ +#ifndef _LocationError_H_ +#define _LocationError_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct AdditionalAssistanceData; + /* Forward declarations */ + struct AdditionalAssistanceData; -/* LocationError */ -typedef struct LocationError { - LocErrorReason_t locErrorReason; - struct AdditionalAssistanceData *additionalAssistanceData /* OPTIONAL */; - /* + /* LocationError */ + typedef struct LocationError + { + LocErrorReason_t locErrorReason; + struct AdditionalAssistanceData *additionalAssistanceData /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} LocationError_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_LocationError; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } LocationError_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_LocationError; #ifdef __cplusplus } @@ -44,5 +46,5 @@ extern asn_TYPE_descriptor_t asn_DEF_LocationError; /* Referred external types */ #include "AdditionalAssistanceData.h" -#endif /* _LocationError_H_ */ +#endif /* _LocationError_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/LocationInfo.h b/src/core/libs/supl/asn-rrlp/LocationInfo.h index 4dd96a3fa..d31af60d5 100644 --- a/src/core/libs/supl/asn-rrlp/LocationInfo.h +++ b/src/core/libs/supl/asn-rrlp/LocationInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _LocationInfo_H_ -#define _LocationInfo_H_ +#ifndef _LocationInfo_H_ +#define _LocationInfo_H_ #include @@ -17,26 +17,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* LocationInfo */ -typedef struct LocationInfo { - long refFrame; - long *gpsTOW /* OPTIONAL */; - FixType_t fixType; - Ext_GeographicalInformation_t posEstimate; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} LocationInfo_t; + /* LocationInfo */ + typedef struct LocationInfo + { + long refFrame; + long *gpsTOW /* OPTIONAL */; + FixType_t fixType; + Ext_GeographicalInformation_t posEstimate; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_LocationInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } LocationInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_LocationInfo; #ifdef __cplusplus } #endif -#endif /* _LocationInfo_H_ */ +#endif /* _LocationInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MeasureResponseTime.h b/src/core/libs/supl/asn-rrlp/MeasureResponseTime.h index 4a6fda64b..2607e7ff4 100644 --- a/src/core/libs/supl/asn-rrlp/MeasureResponseTime.h +++ b/src/core/libs/supl/asn-rrlp/MeasureResponseTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MeasureResponseTime_H_ -#define _MeasureResponseTime_H_ +#ifndef _MeasureResponseTime_H_ +#define _MeasureResponseTime_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MeasureResponseTime */ -typedef long MeasureResponseTime_t; + /* MeasureResponseTime */ + typedef long MeasureResponseTime_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MeasureResponseTime; -asn_struct_free_f MeasureResponseTime_free; -asn_struct_print_f MeasureResponseTime_print; -asn_constr_check_f MeasureResponseTime_constraint; -ber_type_decoder_f MeasureResponseTime_decode_ber; -der_type_encoder_f MeasureResponseTime_encode_der; -xer_type_decoder_f MeasureResponseTime_decode_xer; -xer_type_encoder_f MeasureResponseTime_encode_xer; -per_type_decoder_f MeasureResponseTime_decode_uper; -per_type_encoder_f MeasureResponseTime_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MeasureResponseTime; + asn_struct_free_f MeasureResponseTime_free; + asn_struct_print_f MeasureResponseTime_print; + asn_constr_check_f MeasureResponseTime_constraint; + ber_type_decoder_f MeasureResponseTime_decode_ber; + der_type_encoder_f MeasureResponseTime_encode_der; + xer_type_decoder_f MeasureResponseTime_decode_xer; + xer_type_encoder_f MeasureResponseTime_encode_xer; + per_type_decoder_f MeasureResponseTime_decode_uper; + per_type_encoder_f MeasureResponseTime_encode_uper; #ifdef __cplusplus } #endif -#endif /* _MeasureResponseTime_H_ */ +#endif /* _MeasureResponseTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MethodType.h b/src/core/libs/supl/asn-rrlp/MethodType.h index b9c0b4338..5529e2527 100644 --- a/src/core/libs/supl/asn-rrlp/MethodType.h +++ b/src/core/libs/supl/asn-rrlp/MethodType.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MethodType_H_ -#define _MethodType_H_ +#ifndef _MethodType_H_ +#define _MethodType_H_ #include @@ -16,38 +16,42 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum MethodType_PR { - MethodType_PR_NOTHING, /* No components present */ - MethodType_PR_msAssisted, - MethodType_PR_msBased, - MethodType_PR_msBasedPref, - MethodType_PR_msAssistedPref -} MethodType_PR; + /* Dependencies */ + typedef enum MethodType_PR + { + MethodType_PR_NOTHING, /* No components present */ + MethodType_PR_msAssisted, + MethodType_PR_msBased, + MethodType_PR_msBasedPref, + MethodType_PR_msAssistedPref + } MethodType_PR; -/* MethodType */ -typedef struct MethodType { - MethodType_PR present; - union MethodType_u { - AccuracyOpt_t msAssisted; - Accuracy_t msBased; - Accuracy_t msBasedPref; - Accuracy_t msAssistedPref; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MethodType_t; + /* MethodType */ + typedef struct MethodType + { + MethodType_PR present; + union MethodType_u + { + AccuracyOpt_t msAssisted; + Accuracy_t msBased; + Accuracy_t msBasedPref; + Accuracy_t msAssistedPref; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MethodType; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MethodType_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MethodType; #ifdef __cplusplus } #endif -#endif /* _MethodType_H_ */ +#endif /* _MethodType_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ModuloTimeSlot.h b/src/core/libs/supl/asn-rrlp/ModuloTimeSlot.h index dc6f487aa..186607231 100644 --- a/src/core/libs/supl/asn-rrlp/ModuloTimeSlot.h +++ b/src/core/libs/supl/asn-rrlp/ModuloTimeSlot.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ModuloTimeSlot_H_ -#define _ModuloTimeSlot_H_ +#ifndef _ModuloTimeSlot_H_ +#define _ModuloTimeSlot_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ModuloTimeSlot */ -typedef long ModuloTimeSlot_t; + /* ModuloTimeSlot */ + typedef long ModuloTimeSlot_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ModuloTimeSlot; -asn_struct_free_f ModuloTimeSlot_free; -asn_struct_print_f ModuloTimeSlot_print; -asn_constr_check_f ModuloTimeSlot_constraint; -ber_type_decoder_f ModuloTimeSlot_decode_ber; -der_type_encoder_f ModuloTimeSlot_encode_der; -xer_type_decoder_f ModuloTimeSlot_decode_xer; -xer_type_encoder_f ModuloTimeSlot_encode_xer; -per_type_decoder_f ModuloTimeSlot_decode_uper; -per_type_encoder_f ModuloTimeSlot_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ModuloTimeSlot; + asn_struct_free_f ModuloTimeSlot_free; + asn_struct_print_f ModuloTimeSlot_print; + asn_constr_check_f ModuloTimeSlot_constraint; + ber_type_decoder_f ModuloTimeSlot_decode_ber; + der_type_encoder_f ModuloTimeSlot_encode_der; + xer_type_decoder_f ModuloTimeSlot_decode_xer; + xer_type_encoder_f ModuloTimeSlot_encode_xer; + per_type_decoder_f ModuloTimeSlot_decode_uper; + per_type_encoder_f ModuloTimeSlot_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ModuloTimeSlot_H_ */ +#endif /* _ModuloTimeSlot_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MoreAssDataToBeSent.h b/src/core/libs/supl/asn-rrlp/MoreAssDataToBeSent.h index 3ccac3704..d1ad95faf 100644 --- a/src/core/libs/supl/asn-rrlp/MoreAssDataToBeSent.h +++ b/src/core/libs/supl/asn-rrlp/MoreAssDataToBeSent.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MoreAssDataToBeSent_H_ -#define _MoreAssDataToBeSent_H_ +#ifndef _MoreAssDataToBeSent_H_ +#define _MoreAssDataToBeSent_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum MoreAssDataToBeSent { - MoreAssDataToBeSent_noMoreMessages = 0, - MoreAssDataToBeSent_moreMessagesOnTheWay = 1 -} e_MoreAssDataToBeSent; + /* Dependencies */ + typedef enum MoreAssDataToBeSent + { + MoreAssDataToBeSent_noMoreMessages = 0, + MoreAssDataToBeSent_moreMessagesOnTheWay = 1 + } e_MoreAssDataToBeSent; -/* MoreAssDataToBeSent */ -typedef ENUMERATED_t MoreAssDataToBeSent_t; + /* MoreAssDataToBeSent */ + typedef ENUMERATED_t MoreAssDataToBeSent_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MoreAssDataToBeSent; -asn_struct_free_f MoreAssDataToBeSent_free; -asn_struct_print_f MoreAssDataToBeSent_print; -asn_constr_check_f MoreAssDataToBeSent_constraint; -ber_type_decoder_f MoreAssDataToBeSent_decode_ber; -der_type_encoder_f MoreAssDataToBeSent_encode_der; -xer_type_decoder_f MoreAssDataToBeSent_decode_xer; -xer_type_encoder_f MoreAssDataToBeSent_encode_xer; -per_type_decoder_f MoreAssDataToBeSent_decode_uper; -per_type_encoder_f MoreAssDataToBeSent_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MoreAssDataToBeSent; + asn_struct_free_f MoreAssDataToBeSent_free; + asn_struct_print_f MoreAssDataToBeSent_print; + asn_constr_check_f MoreAssDataToBeSent_constraint; + ber_type_decoder_f MoreAssDataToBeSent_decode_ber; + der_type_encoder_f MoreAssDataToBeSent_encode_der; + xer_type_decoder_f MoreAssDataToBeSent_decode_xer; + xer_type_encoder_f MoreAssDataToBeSent_encode_xer; + per_type_decoder_f MoreAssDataToBeSent_decode_uper; + per_type_encoder_f MoreAssDataToBeSent_encode_uper; #ifdef __cplusplus } #endif -#endif /* _MoreAssDataToBeSent_H_ */ +#endif /* _MoreAssDataToBeSent_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MpathIndic.h b/src/core/libs/supl/asn-rrlp/MpathIndic.h index d83f3fb8f..89907b6de 100644 --- a/src/core/libs/supl/asn-rrlp/MpathIndic.h +++ b/src/core/libs/supl/asn-rrlp/MpathIndic.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MpathIndic_H_ -#define _MpathIndic_H_ +#ifndef _MpathIndic_H_ +#define _MpathIndic_H_ #include @@ -14,35 +14,37 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum MpathIndic { - MpathIndic_notMeasured = 0, - MpathIndic_low = 1, - MpathIndic_medium = 2, - MpathIndic_high = 3 -} e_MpathIndic; + /* Dependencies */ + typedef enum MpathIndic + { + MpathIndic_notMeasured = 0, + MpathIndic_low = 1, + MpathIndic_medium = 2, + MpathIndic_high = 3 + } e_MpathIndic; -/* MpathIndic */ -typedef ENUMERATED_t MpathIndic_t; + /* MpathIndic */ + typedef ENUMERATED_t MpathIndic_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MpathIndic; -asn_struct_free_f MpathIndic_free; -asn_struct_print_f MpathIndic_print; -asn_constr_check_f MpathIndic_constraint; -ber_type_decoder_f MpathIndic_decode_ber; -der_type_encoder_f MpathIndic_encode_der; -xer_type_decoder_f MpathIndic_decode_xer; -xer_type_encoder_f MpathIndic_encode_xer; -per_type_decoder_f MpathIndic_decode_uper; -per_type_encoder_f MpathIndic_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MpathIndic; + asn_struct_free_f MpathIndic_free; + asn_struct_print_f MpathIndic_print; + asn_constr_check_f MpathIndic_constraint; + ber_type_decoder_f MpathIndic_decode_ber; + der_type_encoder_f MpathIndic_encode_der; + xer_type_decoder_f MpathIndic_decode_xer; + xer_type_encoder_f MpathIndic_encode_xer; + per_type_decoder_f MpathIndic_decode_uper; + per_type_encoder_f MpathIndic_encode_uper; #ifdef __cplusplus } #endif -#endif /* _MpathIndic_H_ */ +#endif /* _MpathIndic_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrAssistBTS-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/MsrAssistBTS-R98-ExpOTD.h index a37ca3146..0efafd0bb 100644 --- a/src/core/libs/supl/asn-rrlp/MsrAssistBTS-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/MsrAssistBTS-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrAssistBTS_R98_ExpOTD_H_ -#define _MsrAssistBTS_R98_ExpOTD_H_ +#ifndef _MsrAssistBTS_R98_ExpOTD_H_ +#define _MsrAssistBTS_R98_ExpOTD_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MsrAssistBTS-R98-ExpOTD */ -typedef struct MsrAssistBTS_R98_ExpOTD { - ExpectedOTD_t expectedOTD; - ExpOTDUncertainty_t expOTDUncertainty; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrAssistBTS_R98_ExpOTD_t; + /* MsrAssistBTS-R98-ExpOTD */ + typedef struct MsrAssistBTS_R98_ExpOTD + { + ExpectedOTD_t expectedOTD; + ExpOTDUncertainty_t expOTDUncertainty; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrAssistBTS_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrAssistBTS_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrAssistBTS_R98_ExpOTD; #ifdef __cplusplus } #endif -#endif /* _MsrAssistBTS_R98_ExpOTD_H_ */ +#endif /* _MsrAssistBTS_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrAssistBTS.h b/src/core/libs/supl/asn-rrlp/MsrAssistBTS.h index a5ec44205..7d2eac4d4 100644 --- a/src/core/libs/supl/asn-rrlp/MsrAssistBTS.h +++ b/src/core/libs/supl/asn-rrlp/MsrAssistBTS.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrAssistBTS_H_ -#define _MsrAssistBTS_H_ +#ifndef _MsrAssistBTS_H_ +#define _MsrAssistBTS_H_ #include @@ -19,27 +19,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct CalcAssistanceBTS; + /* Forward declarations */ + struct CalcAssistanceBTS; -/* MsrAssistBTS */ -typedef struct MsrAssistBTS { - BCCHCarrier_t bcchCarrier; - BSIC_t bsic; - MultiFrameOffset_t multiFrameOffset; - TimeSlotScheme_t timeSlotScheme; - RoughRTD_t roughRTD; - struct CalcAssistanceBTS *calcAssistanceBTS /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrAssistBTS_t; + /* MsrAssistBTS */ + typedef struct MsrAssistBTS + { + BCCHCarrier_t bcchCarrier; + BSIC_t bsic; + MultiFrameOffset_t multiFrameOffset; + TimeSlotScheme_t timeSlotScheme; + RoughRTD_t roughRTD; + struct CalcAssistanceBTS *calcAssistanceBTS /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrAssistBTS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrAssistBTS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrAssistBTS; #ifdef __cplusplus } @@ -48,5 +50,5 @@ extern asn_TYPE_descriptor_t asn_DEF_MsrAssistBTS; /* Referred external types */ #include "CalcAssistanceBTS.h" -#endif /* _MsrAssistBTS_H_ */ +#endif /* _MsrAssistBTS_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrAssistData-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/MsrAssistData-R98-ExpOTD.h index 3fb932d86..a94887363 100644 --- a/src/core/libs/supl/asn-rrlp/MsrAssistData-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/MsrAssistData-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrAssistData_R98_ExpOTD_H_ -#define _MsrAssistData_R98_ExpOTD_H_ +#ifndef _MsrAssistData_R98_ExpOTD_H_ +#define _MsrAssistData_R98_ExpOTD_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MsrAssistData-R98-ExpOTD */ -typedef struct MsrAssistData_R98_ExpOTD { - SeqOfMsrAssistBTS_R98_ExpOTD_t msrAssistList_R98_ExpOTD; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrAssistData_R98_ExpOTD_t; + /* MsrAssistData-R98-ExpOTD */ + typedef struct MsrAssistData_R98_ExpOTD + { + SeqOfMsrAssistBTS_R98_ExpOTD_t msrAssistList_R98_ExpOTD; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrAssistData_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrAssistData_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrAssistData_R98_ExpOTD; #ifdef __cplusplus } #endif -#endif /* _MsrAssistData_R98_ExpOTD_H_ */ +#endif /* _MsrAssistData_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrAssistData.h b/src/core/libs/supl/asn-rrlp/MsrAssistData.h index 0aa260631..f0cf06491 100644 --- a/src/core/libs/supl/asn-rrlp/MsrAssistData.h +++ b/src/core/libs/supl/asn-rrlp/MsrAssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrAssistData_H_ -#define _MsrAssistData_H_ +#ifndef _MsrAssistData_H_ +#define _MsrAssistData_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MsrAssistData */ -typedef struct MsrAssistData { - SeqOfMsrAssistBTS_t msrAssistList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrAssistData_t; + /* MsrAssistData */ + typedef struct MsrAssistData + { + SeqOfMsrAssistBTS_t msrAssistList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrAssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrAssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrAssistData; #ifdef __cplusplus } #endif -#endif /* _MsrAssistData_H_ */ +#endif /* _MsrAssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrPosition-Req.h b/src/core/libs/supl/asn-rrlp/MsrPosition-Req.h index 011046652..3f0be38f5 100644 --- a/src/core/libs/supl/asn-rrlp/MsrPosition-Req.h +++ b/src/core/libs/supl/asn-rrlp/MsrPosition-Req.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrPosition_Req_H_ -#define _MsrPosition_Req_H_ +#ifndef _MsrPosition_Req_H_ +#define _MsrPosition_Req_H_ #include @@ -16,38 +16,40 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceAssistData; -struct MsrAssistData; -struct SystemInfoAssistData; -struct GPS_AssistData; -struct Rel98_MsrPosition_Req_Extension; -struct Rel5_MsrPosition_Req_Extension; + /* Forward declarations */ + struct ReferenceAssistData; + struct MsrAssistData; + struct SystemInfoAssistData; + struct GPS_AssistData; + struct Rel98_MsrPosition_Req_Extension; + struct Rel5_MsrPosition_Req_Extension; -/* MsrPosition-Req */ -typedef struct MsrPosition_Req { - PositionInstruct_t positionInstruct; - struct ReferenceAssistData *referenceAssistData /* OPTIONAL */; - struct MsrAssistData *msrAssistData /* OPTIONAL */; - struct SystemInfoAssistData *systemInfoAssistData /* OPTIONAL */; - struct GPS_AssistData *gps_AssistData /* OPTIONAL */; - ExtensionContainer_t *extensionContainer /* OPTIONAL */; - /* + /* MsrPosition-Req */ + typedef struct MsrPosition_Req + { + PositionInstruct_t positionInstruct; + struct ReferenceAssistData *referenceAssistData /* OPTIONAL */; + struct MsrAssistData *msrAssistData /* OPTIONAL */; + struct SystemInfoAssistData *systemInfoAssistData /* OPTIONAL */; + struct GPS_AssistData *gps_AssistData /* OPTIONAL */; + ExtensionContainer_t *extensionContainer /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - struct Rel98_MsrPosition_Req_Extension *rel98_MsrPosition_Req_extension /* OPTIONAL */; - struct Rel5_MsrPosition_Req_Extension *rel5_MsrPosition_Req_extension /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrPosition_Req_t; + struct Rel98_MsrPosition_Req_Extension *rel98_MsrPosition_Req_extension /* OPTIONAL */; + struct Rel5_MsrPosition_Req_Extension *rel5_MsrPosition_Req_extension /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Req; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrPosition_Req_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Req; #ifdef __cplusplus } @@ -61,5 +63,5 @@ extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Req; #include "Rel98-MsrPosition-Req-Extension.h" #include "Rel5-MsrPosition-Req-Extension.h" -#endif /* _MsrPosition_Req_H_ */ +#endif /* _MsrPosition_Req_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MsrPosition-Rsp.h b/src/core/libs/supl/asn-rrlp/MsrPosition-Rsp.h index ddb735fbd..09dc9dcbc 100644 --- a/src/core/libs/supl/asn-rrlp/MsrPosition-Rsp.h +++ b/src/core/libs/supl/asn-rrlp/MsrPosition-Rsp.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MsrPosition_Rsp_H_ -#define _MsrPosition_Rsp_H_ +#ifndef _MsrPosition_Rsp_H_ +#define _MsrPosition_Rsp_H_ #include @@ -15,41 +15,43 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct MultipleSets; -struct ReferenceIdentity; -struct OTD_MeasureInfo; -struct LocationInfo; -struct GPS_MeasureInfo; -struct LocationError; -struct Rel_98_MsrPosition_Rsp_Extension; -struct Rel_5_MsrPosition_Rsp_Extension; + /* Forward declarations */ + struct MultipleSets; + struct ReferenceIdentity; + struct OTD_MeasureInfo; + struct LocationInfo; + struct GPS_MeasureInfo; + struct LocationError; + struct Rel_98_MsrPosition_Rsp_Extension; + struct Rel_5_MsrPosition_Rsp_Extension; -/* MsrPosition-Rsp */ -typedef struct MsrPosition_Rsp { - struct MultipleSets *multipleSets /* OPTIONAL */; - struct ReferenceIdentity *referenceIdentity /* OPTIONAL */; - struct OTD_MeasureInfo *otd_MeasureInfo /* OPTIONAL */; - struct LocationInfo *locationInfo /* OPTIONAL */; - struct GPS_MeasureInfo *gps_MeasureInfo /* OPTIONAL */; - struct LocationError *locationError /* OPTIONAL */; - ExtensionContainer_t *extensionContainer /* OPTIONAL */; - /* + /* MsrPosition-Rsp */ + typedef struct MsrPosition_Rsp + { + struct MultipleSets *multipleSets /* OPTIONAL */; + struct ReferenceIdentity *referenceIdentity /* OPTIONAL */; + struct OTD_MeasureInfo *otd_MeasureInfo /* OPTIONAL */; + struct LocationInfo *locationInfo /* OPTIONAL */; + struct GPS_MeasureInfo *gps_MeasureInfo /* OPTIONAL */; + struct LocationError *locationError /* OPTIONAL */; + ExtensionContainer_t *extensionContainer /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - struct Rel_98_MsrPosition_Rsp_Extension *rel_98_MsrPosition_Rsp_Extension /* OPTIONAL */; - struct Rel_5_MsrPosition_Rsp_Extension *rel_5_MsrPosition_Rsp_Extension /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MsrPosition_Rsp_t; + struct Rel_98_MsrPosition_Rsp_Extension *rel_98_MsrPosition_Rsp_Extension /* OPTIONAL */; + struct Rel_5_MsrPosition_Rsp_Extension *rel_5_MsrPosition_Rsp_Extension /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Rsp; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MsrPosition_Rsp_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Rsp; #ifdef __cplusplus } @@ -65,5 +67,5 @@ extern asn_TYPE_descriptor_t asn_DEF_MsrPosition_Rsp; #include "Rel-98-MsrPosition-Rsp-Extension.h" #include "Rel-5-MsrPosition-Rsp-Extension.h" -#endif /* _MsrPosition_Rsp_H_ */ +#endif /* _MsrPosition_Rsp_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MultiFrameCarrier.h b/src/core/libs/supl/asn-rrlp/MultiFrameCarrier.h index 974756a36..4a22a67fc 100644 --- a/src/core/libs/supl/asn-rrlp/MultiFrameCarrier.h +++ b/src/core/libs/supl/asn-rrlp/MultiFrameCarrier.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MultiFrameCarrier_H_ -#define _MultiFrameCarrier_H_ +#ifndef _MultiFrameCarrier_H_ +#define _MultiFrameCarrier_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MultiFrameCarrier */ -typedef struct MultiFrameCarrier { - BCCHCarrier_t bcchCarrier; - MultiFrameOffset_t multiFrameOffset; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MultiFrameCarrier_t; + /* MultiFrameCarrier */ + typedef struct MultiFrameCarrier + { + BCCHCarrier_t bcchCarrier; + MultiFrameOffset_t multiFrameOffset; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MultiFrameCarrier; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MultiFrameCarrier_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MultiFrameCarrier; #ifdef __cplusplus } #endif -#endif /* _MultiFrameCarrier_H_ */ +#endif /* _MultiFrameCarrier_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MultiFrameOffset.h b/src/core/libs/supl/asn-rrlp/MultiFrameOffset.h index 0dca44394..ee06666df 100644 --- a/src/core/libs/supl/asn-rrlp/MultiFrameOffset.h +++ b/src/core/libs/supl/asn-rrlp/MultiFrameOffset.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MultiFrameOffset_H_ -#define _MultiFrameOffset_H_ +#ifndef _MultiFrameOffset_H_ +#define _MultiFrameOffset_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MultiFrameOffset */ -typedef long MultiFrameOffset_t; + /* MultiFrameOffset */ + typedef long MultiFrameOffset_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MultiFrameOffset; -asn_struct_free_f MultiFrameOffset_free; -asn_struct_print_f MultiFrameOffset_print; -asn_constr_check_f MultiFrameOffset_constraint; -ber_type_decoder_f MultiFrameOffset_decode_ber; -der_type_encoder_f MultiFrameOffset_encode_der; -xer_type_decoder_f MultiFrameOffset_decode_xer; -xer_type_encoder_f MultiFrameOffset_encode_xer; -per_type_decoder_f MultiFrameOffset_decode_uper; -per_type_encoder_f MultiFrameOffset_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MultiFrameOffset; + asn_struct_free_f MultiFrameOffset_free; + asn_struct_print_f MultiFrameOffset_print; + asn_constr_check_f MultiFrameOffset_constraint; + ber_type_decoder_f MultiFrameOffset_decode_ber; + der_type_encoder_f MultiFrameOffset_encode_der; + xer_type_decoder_f MultiFrameOffset_decode_xer; + xer_type_encoder_f MultiFrameOffset_encode_xer; + per_type_decoder_f MultiFrameOffset_decode_uper; + per_type_encoder_f MultiFrameOffset_encode_uper; #ifdef __cplusplus } #endif -#endif /* _MultiFrameOffset_H_ */ +#endif /* _MultiFrameOffset_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/MultipleSets.h b/src/core/libs/supl/asn-rrlp/MultipleSets.h index 032c62542..9f8f4a87d 100644 --- a/src/core/libs/supl/asn-rrlp/MultipleSets.h +++ b/src/core/libs/supl/asn-rrlp/MultipleSets.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _MultipleSets_H_ -#define _MultipleSets_H_ +#ifndef _MultipleSets_H_ +#define _MultipleSets_H_ #include @@ -16,25 +16,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MultipleSets */ -typedef struct MultipleSets { - long nbrOfSets; - long nbrOfReferenceBTSs; - ReferenceRelation_t *referenceRelation /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MultipleSets_t; + /* MultipleSets */ + typedef struct MultipleSets + { + long nbrOfSets; + long nbrOfReferenceBTSs; + ReferenceRelation_t *referenceRelation /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MultipleSets; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MultipleSets_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MultipleSets; #ifdef __cplusplus } #endif -#endif /* _MultipleSets_H_ */ +#endif /* _MultipleSets_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/NULL.h b/src/core/libs/supl/asn-rrlp/NULL.h index 131e77592..5720faf3b 100644 --- a/src/core/libs/supl/asn-rrlp/NULL.h +++ b/src/core/libs/supl/asn-rrlp/NULL.h @@ -2,32 +2,33 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_TYPE_NULL_H -#define ASN_TYPE_NULL_H +#ifndef ASN_TYPE_NULL_H +#define ASN_TYPE_NULL_H #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * The value of the NULL type is meaningless: see BOOLEAN if you want to * carry true/false semantics. */ -typedef int NULL_t; + typedef int NULL_t; -extern asn_TYPE_descriptor_t asn_DEF_NULL; + extern asn_TYPE_descriptor_t asn_DEF_NULL; -asn_struct_print_f NULL_print; -der_type_encoder_f NULL_encode_der; -xer_type_decoder_f NULL_decode_xer; -xer_type_encoder_f NULL_encode_xer; -per_type_decoder_f NULL_decode_uper; -per_type_encoder_f NULL_encode_uper; + asn_struct_print_f NULL_print; + der_type_encoder_f NULL_encode_der; + xer_type_decoder_f NULL_decode_xer; + xer_type_encoder_f NULL_encode_xer; + per_type_decoder_f NULL_decode_uper; + per_type_encoder_f NULL_encode_uper; #ifdef __cplusplus } #endif -#endif /* NULL_H */ +#endif /* NULL_H */ diff --git a/src/core/libs/supl/asn-rrlp/NativeEnumerated.h b/src/core/libs/supl/asn-rrlp/NativeEnumerated.h index c59bb1ba9..3b3d4b074 100644 --- a/src/core/libs/supl/asn-rrlp/NativeEnumerated.h +++ b/src/core/libs/supl/asn-rrlp/NativeEnumerated.h @@ -10,23 +10,24 @@ * will do). * This type may be used when integer range is limited by subtype constraints. */ -#ifndef _NativeEnumerated_H_ -#define _NativeEnumerated_H_ +#ifndef _NativeEnumerated_H_ +#define _NativeEnumerated_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; + extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; -xer_type_encoder_f NativeEnumerated_encode_xer; -per_type_decoder_f NativeEnumerated_decode_uper; -per_type_encoder_f NativeEnumerated_encode_uper; + xer_type_encoder_f NativeEnumerated_encode_xer; + per_type_decoder_f NativeEnumerated_decode_uper; + per_type_encoder_f NativeEnumerated_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NativeEnumerated_H_ */ +#endif /* _NativeEnumerated_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/NativeInteger.c b/src/core/libs/supl/asn-rrlp/NativeInteger.c index abdb71a8c..bf3939e88 100644 --- a/src/core/libs/supl/asn-rrlp/NativeInteger.c +++ b/src/core/libs/supl/asn-rrlp/NativeInteger.c @@ -107,7 +107,7 @@ NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, tmp.size = length; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmp, &l) + ? asn_INTEGER2ulong(&tmp, (unsigned long*)&l) : asn_INTEGER2long(&tmp, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -187,7 +187,7 @@ NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, if(rval.code == RC_OK) { long l; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&st, &l) + ? asn_INTEGER2ulong(&st, (unsigned long*)&l) : asn_INTEGER2long(&st, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -255,7 +255,7 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, &tmpintptr, pd); if(rval.code == RC_OK) { if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmpint, native) + ? asn_INTEGER2ulong(&tmpint, (unsigned long*)native) : asn_INTEGER2long(&tmpint, native)) rval.code = RC_FAIL; else diff --git a/src/core/libs/supl/asn-rrlp/NativeInteger.h b/src/core/libs/supl/asn-rrlp/NativeInteger.h index 4e63a8355..14311ae57 100644 --- a/src/core/libs/supl/asn-rrlp/NativeInteger.h +++ b/src/core/libs/supl/asn-rrlp/NativeInteger.h @@ -9,29 +9,30 @@ * will do). * This type may be used when integer range is limited by subtype constraints. */ -#ifndef _NativeInteger_H_ -#define _NativeInteger_H_ +#ifndef _NativeInteger_H_ +#define _NativeInteger_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; + extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; -asn_struct_free_f NativeInteger_free; -asn_struct_print_f NativeInteger_print; -ber_type_decoder_f NativeInteger_decode_ber; -der_type_encoder_f NativeInteger_encode_der; -xer_type_decoder_f NativeInteger_decode_xer; -xer_type_encoder_f NativeInteger_encode_xer; -per_type_decoder_f NativeInteger_decode_uper; -per_type_encoder_f NativeInteger_encode_uper; + asn_struct_free_f NativeInteger_free; + asn_struct_print_f NativeInteger_print; + ber_type_decoder_f NativeInteger_decode_ber; + der_type_encoder_f NativeInteger_encode_der; + xer_type_decoder_f NativeInteger_decode_xer; + xer_type_encoder_f NativeInteger_encode_xer; + per_type_decoder_f NativeInteger_decode_uper; + per_type_encoder_f NativeInteger_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NativeInteger_H_ */ +#endif /* _NativeInteger_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/NavModel-KeplerianSet.h b/src/core/libs/supl/asn-rrlp/NavModel-KeplerianSet.h index f295c623b..7d9f906ed 100644 --- a/src/core/libs/supl/asn-rrlp/NavModel-KeplerianSet.h +++ b/src/core/libs/supl/asn-rrlp/NavModel-KeplerianSet.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _NavModel_KeplerianSet_H_ -#define _NavModel_KeplerianSet_H_ +#ifndef _NavModel_KeplerianSet_H_ +#define _NavModel_KeplerianSet_H_ #include @@ -15,38 +15,40 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* NavModel-KeplerianSet */ -typedef struct NavModel_KeplerianSet { - long keplerToeLSB; - long keplerW; - long keplerDeltaN; - long keplerM0; - long keplerOmegaDot; - long keplerELSB; - long keplerIDot; - long keplerAPowerHalfLSB; - long keplerI0; - long keplerOmega0; - long keplerCrs; - long keplerCis; - long keplerCus; - long keplerCrc; - long keplerCic; - long keplerCuc; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NavModel_KeplerianSet_t; + /* NavModel-KeplerianSet */ + typedef struct NavModel_KeplerianSet + { + long keplerToeLSB; + long keplerW; + long keplerDeltaN; + long keplerM0; + long keplerOmegaDot; + long keplerELSB; + long keplerIDot; + long keplerAPowerHalfLSB; + long keplerI0; + long keplerOmega0; + long keplerCrs; + long keplerCis; + long keplerCus; + long keplerCrc; + long keplerCic; + long keplerCuc; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NavModel_KeplerianSet; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NavModel_KeplerianSet_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NavModel_KeplerianSet; #ifdef __cplusplus } #endif -#endif /* _NavModel_KeplerianSet_H_ */ +#endif /* _NavModel_KeplerianSet_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/NavModelElement.h b/src/core/libs/supl/asn-rrlp/NavModelElement.h index f4504afe2..d8d642c05 100644 --- a/src/core/libs/supl/asn-rrlp/NavModelElement.h +++ b/src/core/libs/supl/asn-rrlp/NavModelElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _NavModelElement_H_ -#define _NavModelElement_H_ +#ifndef _NavModelElement_H_ +#define _NavModelElement_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* NavModelElement */ -typedef struct NavModelElement { - SatelliteID_t satelliteID; - SatStatus_t satStatus; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NavModelElement_t; + /* NavModelElement */ + typedef struct NavModelElement + { + SatelliteID_t satelliteID; + SatStatus_t satStatus; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NavModelElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NavModelElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NavModelElement; #ifdef __cplusplus } #endif -#endif /* _NavModelElement_H_ */ +#endif /* _NavModelElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/NavigationModel.h b/src/core/libs/supl/asn-rrlp/NavigationModel.h index cb37e54de..565f1f636 100644 --- a/src/core/libs/supl/asn-rrlp/NavigationModel.h +++ b/src/core/libs/supl/asn-rrlp/NavigationModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _NavigationModel_H_ -#define _NavigationModel_H_ +#ifndef _NavigationModel_H_ +#define _NavigationModel_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* NavigationModel */ -typedef struct NavigationModel { - SeqOfNavModelElement_t navModelList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NavigationModel_t; + /* NavigationModel */ + typedef struct NavigationModel + { + SeqOfNavModelElement_t navModelList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NavigationModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NavigationModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NavigationModel; #ifdef __cplusplus } #endif -#endif /* _NavigationModel_H_ */ +#endif /* _NavigationModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/NeighborIdentity.h b/src/core/libs/supl/asn-rrlp/NeighborIdentity.h index b12b599e7..b87849d76 100644 --- a/src/core/libs/supl/asn-rrlp/NeighborIdentity.h +++ b/src/core/libs/supl/asn-rrlp/NeighborIdentity.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _NeighborIdentity_H_ -#define _NeighborIdentity_H_ +#ifndef _NeighborIdentity_H_ +#define _NeighborIdentity_H_ #include @@ -20,42 +20,46 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum NeighborIdentity_PR { - NeighborIdentity_PR_NOTHING, /* No components present */ - NeighborIdentity_PR_bsicAndCarrier, - NeighborIdentity_PR_ci, - NeighborIdentity_PR_multiFrameCarrier, - NeighborIdentity_PR_requestIndex, - NeighborIdentity_PR_systemInfoIndex, - NeighborIdentity_PR_ciAndLAC -} NeighborIdentity_PR; + /* Dependencies */ + typedef enum NeighborIdentity_PR + { + NeighborIdentity_PR_NOTHING, /* No components present */ + NeighborIdentity_PR_bsicAndCarrier, + NeighborIdentity_PR_ci, + NeighborIdentity_PR_multiFrameCarrier, + NeighborIdentity_PR_requestIndex, + NeighborIdentity_PR_systemInfoIndex, + NeighborIdentity_PR_ciAndLAC + } NeighborIdentity_PR; -/* NeighborIdentity */ -typedef struct NeighborIdentity { - NeighborIdentity_PR present; - union NeighborIdentity_u { - BSICAndCarrier_t bsicAndCarrier; - CellID_t ci; - MultiFrameCarrier_t multiFrameCarrier; - RequestIndex_t requestIndex; - SystemInfoIndex_t systemInfoIndex; - CellIDAndLAC_t ciAndLAC; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NeighborIdentity_t; + /* NeighborIdentity */ + typedef struct NeighborIdentity + { + NeighborIdentity_PR present; + union NeighborIdentity_u + { + BSICAndCarrier_t bsicAndCarrier; + CellID_t ci; + MultiFrameCarrier_t multiFrameCarrier; + RequestIndex_t requestIndex; + SystemInfoIndex_t systemInfoIndex; + CellIDAndLAC_t ciAndLAC; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NeighborIdentity; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NeighborIdentity_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NeighborIdentity; #ifdef __cplusplus } #endif -#endif /* _NeighborIdentity_H_ */ +#endif /* _NeighborIdentity_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/NumOfMeasurements.h b/src/core/libs/supl/asn-rrlp/NumOfMeasurements.h index 82524d0ed..0b897c0f2 100644 --- a/src/core/libs/supl/asn-rrlp/NumOfMeasurements.h +++ b/src/core/libs/supl/asn-rrlp/NumOfMeasurements.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _NumOfMeasurements_H_ -#define _NumOfMeasurements_H_ +#ifndef _NumOfMeasurements_H_ +#define _NumOfMeasurements_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* NumOfMeasurements */ -typedef long NumOfMeasurements_t; + /* NumOfMeasurements */ + typedef long NumOfMeasurements_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NumOfMeasurements; -asn_struct_free_f NumOfMeasurements_free; -asn_struct_print_f NumOfMeasurements_print; -asn_constr_check_f NumOfMeasurements_constraint; -ber_type_decoder_f NumOfMeasurements_decode_ber; -der_type_encoder_f NumOfMeasurements_encode_der; -xer_type_decoder_f NumOfMeasurements_decode_xer; -xer_type_encoder_f NumOfMeasurements_encode_xer; -per_type_decoder_f NumOfMeasurements_decode_uper; -per_type_encoder_f NumOfMeasurements_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NumOfMeasurements; + asn_struct_free_f NumOfMeasurements_free; + asn_struct_print_f NumOfMeasurements_print; + asn_constr_check_f NumOfMeasurements_constraint; + ber_type_decoder_f NumOfMeasurements_decode_ber; + der_type_encoder_f NumOfMeasurements_encode_der; + xer_type_decoder_f NumOfMeasurements_decode_xer; + xer_type_encoder_f NumOfMeasurements_encode_xer; + per_type_decoder_f NumOfMeasurements_decode_uper; + per_type_encoder_f NumOfMeasurements_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NumOfMeasurements_H_ */ +#endif /* _NumOfMeasurements_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OCTET_STRING.c b/src/core/libs/supl/asn-rrlp/OCTET_STRING.c index 584def8b4..bd2d1d845 100644 --- a/src/core/libs/supl/asn-rrlp/OCTET_STRING.c +++ b/src/core/libs/supl/asn-rrlp/OCTET_STRING.c @@ -52,9 +52,9 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { #undef NEXT_PHASE #undef PREV_PHASE #define _CH_PHASE(ctx, inc) do { \ - if(ctx->phase == 0) \ - ctx->context = 0; \ - ctx->phase += inc; \ + if((ctx)->phase == 0) \ + (ctx)->context = 0; \ + (ctx)->phase += (inc); \ } while(0) #define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) #define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) diff --git a/src/core/libs/supl/asn-rrlp/OCTET_STRING.h b/src/core/libs/supl/asn-rrlp/OCTET_STRING.h index 8df9a182d..124fde559 100644 --- a/src/core/libs/supl/asn-rrlp/OCTET_STRING.h +++ b/src/core/libs/supl/asn-rrlp/OCTET_STRING.h @@ -2,42 +2,44 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _OCTET_STRING_H_ -#define _OCTET_STRING_H_ +#ifndef _OCTET_STRING_H_ +#define _OCTET_STRING_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct OCTET_STRING { - uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ - int size; /* Size of the buffer */ + typedef struct OCTET_STRING + { + uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ + int size; /* Size of the buffer */ - asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -} OCTET_STRING_t; + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ + } OCTET_STRING_t; -extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; + extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; -asn_struct_free_f OCTET_STRING_free; -asn_struct_print_f OCTET_STRING_print; -asn_struct_print_f OCTET_STRING_print_utf8; -ber_type_decoder_f OCTET_STRING_decode_ber; -der_type_encoder_f OCTET_STRING_encode_der; -xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ -xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ -xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ -xer_type_encoder_f OCTET_STRING_encode_xer; -xer_type_encoder_f OCTET_STRING_encode_xer_utf8; -per_type_decoder_f OCTET_STRING_decode_uper; -per_type_encoder_f OCTET_STRING_encode_uper; + asn_struct_free_f OCTET_STRING_free; + asn_struct_print_f OCTET_STRING_print; + asn_struct_print_f OCTET_STRING_print_utf8; + ber_type_decoder_f OCTET_STRING_decode_ber; + der_type_encoder_f OCTET_STRING_encode_der; + xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ + xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ + xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ + xer_type_encoder_f OCTET_STRING_encode_xer; + xer_type_encoder_f OCTET_STRING_encode_xer_utf8; + per_type_decoder_f OCTET_STRING_decode_uper; + per_type_encoder_f OCTET_STRING_encode_uper; -/****************************** + /****************************** * Handy conversion routines. * ******************************/ -/* + /* * This function clears the previous value of the OCTET STRING (if any) * and then allocates a new memory with the specified content (str/size). * If size = -1, the size of the original string will be determined @@ -46,41 +48,43 @@ per_type_encoder_f OCTET_STRING_encode_uper; * current contents of the OCTET STRING. * Returns 0 if it was possible to perform operation, -1 otherwise. */ -int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); + int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); /* Handy conversion from the C string into the OCTET STRING. */ -#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) +#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) -/* + /* * Allocate and fill the new OCTET STRING and return a pointer to the newly * allocated object. NULL is permitted in str: the function will just allocate * empty OCTET STRING. */ -OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, - const char *str, int size); + OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, + const char *str, int size); -/**************************** + /**************************** * Internally useful stuff. * ****************************/ -typedef struct asn_OCTET_STRING_specifics_s { - /* + typedef struct asn_OCTET_STRING_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the structure */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the structure */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - enum asn_OS_Subvariant { - ASN_OSUBV_ANY, /* The open type (ANY) */ - ASN_OSUBV_BIT, /* BIT STRING */ - ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ - ASN_OSUBV_U16, /* 16-bit character (BMPString) */ - ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ - } subvariant; -} asn_OCTET_STRING_specifics_t; + enum asn_OS_Subvariant + { + ASN_OSUBV_ANY, /* The open type (ANY) */ + ASN_OSUBV_BIT, /* BIT STRING */ + ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ + ASN_OSUBV_U16, /* 16-bit character (BMPString) */ + ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ + } subvariant; + } asn_OCTET_STRING_specifics_t; #ifdef __cplusplus } #endif -#endif /* _OCTET_STRING_H_ */ +#endif /* _OCTET_STRING_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/OTD-FirstSetMsrs.h b/src/core/libs/supl/asn-rrlp/OTD-FirstSetMsrs.h index b5979dc51..04d3624e7 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-FirstSetMsrs.h +++ b/src/core/libs/supl/asn-rrlp/OTD-FirstSetMsrs.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_FirstSetMsrs_H_ -#define _OTD_FirstSetMsrs_H_ +#ifndef _OTD_FirstSetMsrs_H_ +#define _OTD_FirstSetMsrs_H_ #include @@ -14,27 +14,28 @@ #include "OTD-MeasurementWithID.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTD-FirstSetMsrs */ -typedef OTD_MeasurementWithID_t OTD_FirstSetMsrs_t; + /* OTD-FirstSetMsrs */ + typedef OTD_MeasurementWithID_t OTD_FirstSetMsrs_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_FirstSetMsrs; -asn_struct_free_f OTD_FirstSetMsrs_free; -asn_struct_print_f OTD_FirstSetMsrs_print; -asn_constr_check_f OTD_FirstSetMsrs_constraint; -ber_type_decoder_f OTD_FirstSetMsrs_decode_ber; -der_type_encoder_f OTD_FirstSetMsrs_encode_der; -xer_type_decoder_f OTD_FirstSetMsrs_decode_xer; -xer_type_encoder_f OTD_FirstSetMsrs_encode_xer; -per_type_decoder_f OTD_FirstSetMsrs_decode_uper; -per_type_encoder_f OTD_FirstSetMsrs_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_FirstSetMsrs; + asn_struct_free_f OTD_FirstSetMsrs_free; + asn_struct_print_f OTD_FirstSetMsrs_print; + asn_constr_check_f OTD_FirstSetMsrs_constraint; + ber_type_decoder_f OTD_FirstSetMsrs_decode_ber; + der_type_encoder_f OTD_FirstSetMsrs_encode_der; + xer_type_decoder_f OTD_FirstSetMsrs_decode_xer; + xer_type_encoder_f OTD_FirstSetMsrs_encode_xer; + per_type_decoder_f OTD_FirstSetMsrs_decode_uper; + per_type_encoder_f OTD_FirstSetMsrs_encode_uper; #ifdef __cplusplus } #endif -#endif /* _OTD_FirstSetMsrs_H_ */ +#endif /* _OTD_FirstSetMsrs_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-5-Ext.h b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-5-Ext.h index d75bc01a4..8cdd331bc 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-5-Ext.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-5-Ext.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MeasureInfo_5_Ext_H_ -#define _OTD_MeasureInfo_5_Ext_H_ +#ifndef _OTD_MeasureInfo_5_Ext_H_ +#define _OTD_MeasureInfo_5_Ext_H_ #include @@ -14,27 +14,28 @@ #include "SeqOfOTD-MsrElementRest.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTD-MeasureInfo-5-Ext */ -typedef SeqOfOTD_MsrElementRest_t OTD_MeasureInfo_5_Ext_t; + /* OTD-MeasureInfo-5-Ext */ + typedef SeqOfOTD_MsrElementRest_t OTD_MeasureInfo_5_Ext_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo_5_Ext; -asn_struct_free_f OTD_MeasureInfo_5_Ext_free; -asn_struct_print_f OTD_MeasureInfo_5_Ext_print; -asn_constr_check_f OTD_MeasureInfo_5_Ext_constraint; -ber_type_decoder_f OTD_MeasureInfo_5_Ext_decode_ber; -der_type_encoder_f OTD_MeasureInfo_5_Ext_encode_der; -xer_type_decoder_f OTD_MeasureInfo_5_Ext_decode_xer; -xer_type_encoder_f OTD_MeasureInfo_5_Ext_encode_xer; -per_type_decoder_f OTD_MeasureInfo_5_Ext_decode_uper; -per_type_encoder_f OTD_MeasureInfo_5_Ext_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo_5_Ext; + asn_struct_free_f OTD_MeasureInfo_5_Ext_free; + asn_struct_print_f OTD_MeasureInfo_5_Ext_print; + asn_constr_check_f OTD_MeasureInfo_5_Ext_constraint; + ber_type_decoder_f OTD_MeasureInfo_5_Ext_decode_ber; + der_type_encoder_f OTD_MeasureInfo_5_Ext_encode_der; + xer_type_decoder_f OTD_MeasureInfo_5_Ext_decode_xer; + xer_type_encoder_f OTD_MeasureInfo_5_Ext_encode_xer; + per_type_decoder_f OTD_MeasureInfo_5_Ext_decode_uper; + per_type_encoder_f OTD_MeasureInfo_5_Ext_encode_uper; #ifdef __cplusplus } #endif -#endif /* _OTD_MeasureInfo_5_Ext_H_ */ +#endif /* _OTD_MeasureInfo_5_Ext_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-R98-Ext.h b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-R98-Ext.h index 40f15a992..5a2bcc22c 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-R98-Ext.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo-R98-Ext.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MeasureInfo_R98_Ext_H_ -#define _OTD_MeasureInfo_R98_Ext_H_ +#ifndef _OTD_MeasureInfo_R98_Ext_H_ +#define _OTD_MeasureInfo_R98_Ext_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTD-MeasureInfo-R98-Ext */ -typedef struct OTD_MeasureInfo_R98_Ext { - OTD_MsrElementFirst_R98_Ext_t otdMsrFirstSets_R98_Ext; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MeasureInfo_R98_Ext_t; + /* OTD-MeasureInfo-R98-Ext */ + typedef struct OTD_MeasureInfo_R98_Ext + { + OTD_MsrElementFirst_R98_Ext_t otdMsrFirstSets_R98_Ext; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo_R98_Ext; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MeasureInfo_R98_Ext_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo_R98_Ext; #ifdef __cplusplus } #endif -#endif /* _OTD_MeasureInfo_R98_Ext_H_ */ +#endif /* _OTD_MeasureInfo_R98_Ext_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo.h b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo.h index 8ee559573..3c57b4f9c 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MeasureInfo.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MeasureInfo_H_ -#define _OTD_MeasureInfo_H_ +#ifndef _OTD_MeasureInfo_H_ +#define _OTD_MeasureInfo_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SeqOfOTD_MsrElementRest; + /* Forward declarations */ + struct SeqOfOTD_MsrElementRest; -/* OTD-MeasureInfo */ -typedef struct OTD_MeasureInfo { - OTD_MsrElementFirst_t otdMsrFirstSets; - struct SeqOfOTD_MsrElementRest *otdMsrRestSets /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MeasureInfo_t; + /* OTD-MeasureInfo */ + typedef struct OTD_MeasureInfo + { + OTD_MsrElementFirst_t otdMsrFirstSets; + struct SeqOfOTD_MsrElementRest *otdMsrRestSets /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MeasureInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo; #ifdef __cplusplus } @@ -40,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasureInfo; /* Referred external types */ #include "SeqOfOTD-MsrElementRest.h" -#endif /* _OTD_MeasureInfo_H_ */ +#endif /* _OTD_MeasureInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-Measurement.h b/src/core/libs/supl/asn-rrlp/OTD-Measurement.h index 78c8b4a5b..7fa183b7c 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-Measurement.h +++ b/src/core/libs/supl/asn-rrlp/OTD-Measurement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_Measurement_H_ -#define _OTD_Measurement_H_ +#ifndef _OTD_Measurement_H_ +#define _OTD_Measurement_H_ #include @@ -17,25 +17,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTD-Measurement */ -typedef struct OTD_Measurement { - ModuloTimeSlot_t nborTimeSlot; - EOTDQuality_t eotdQuality; - OTDValue_t otdValue; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_Measurement_t; + /* OTD-Measurement */ + typedef struct OTD_Measurement + { + ModuloTimeSlot_t nborTimeSlot; + EOTDQuality_t eotdQuality; + OTDValue_t otdValue; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_Measurement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_Measurement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_Measurement; #ifdef __cplusplus } #endif -#endif /* _OTD_Measurement_H_ */ +#endif /* _OTD_Measurement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MeasurementWithID.h b/src/core/libs/supl/asn-rrlp/OTD-MeasurementWithID.h index 03944b046..6431c7a89 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MeasurementWithID.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MeasurementWithID.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MeasurementWithID_H_ -#define _OTD_MeasurementWithID_H_ +#ifndef _OTD_MeasurementWithID_H_ +#define _OTD_MeasurementWithID_H_ #include @@ -18,26 +18,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTD-MeasurementWithID */ -typedef struct OTD_MeasurementWithID { - NeighborIdentity_t neighborIdentity; - ModuloTimeSlot_t nborTimeSlot; - EOTDQuality_t eotdQuality; - OTDValue_t otdValue; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MeasurementWithID_t; + /* OTD-MeasurementWithID */ + typedef struct OTD_MeasurementWithID + { + NeighborIdentity_t neighborIdentity; + ModuloTimeSlot_t nborTimeSlot; + EOTDQuality_t eotdQuality; + OTDValue_t otdValue; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasurementWithID; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MeasurementWithID_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MeasurementWithID; #ifdef __cplusplus } #endif -#endif /* _OTD_MeasurementWithID_H_ */ +#endif /* _OTD_MeasurementWithID_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst-R98-Ext.h b/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst-R98-Ext.h index 6c372026d..e99001016 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst-R98-Ext.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst-R98-Ext.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MsrElementFirst_R98_Ext_H_ -#define _OTD_MsrElementFirst_R98_Ext_H_ +#ifndef _OTD_MsrElementFirst_R98_Ext_H_ +#define _OTD_MsrElementFirst_R98_Ext_H_ #include @@ -14,22 +14,24 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SeqOfOTD_FirstSetMsrs_R98_Ext; + /* Forward declarations */ + struct SeqOfOTD_FirstSetMsrs_R98_Ext; -/* OTD-MsrElementFirst-R98-Ext */ -typedef struct OTD_MsrElementFirst_R98_Ext { - struct SeqOfOTD_FirstSetMsrs_R98_Ext *otd_FirstSetMsrs_R98_Ext /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MsrElementFirst_R98_Ext_t; + /* OTD-MsrElementFirst-R98-Ext */ + typedef struct OTD_MsrElementFirst_R98_Ext + { + struct SeqOfOTD_FirstSetMsrs_R98_Ext *otd_FirstSetMsrs_R98_Ext /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst_R98_Ext; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MsrElementFirst_R98_Ext_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst_R98_Ext; #ifdef __cplusplus } @@ -38,5 +40,5 @@ extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst_R98_Ext; /* Referred external types */ #include "SeqOfOTD-FirstSetMsrs-R98-Ext.h" -#endif /* _OTD_MsrElementFirst_R98_Ext_H_ */ +#endif /* _OTD_MsrElementFirst_R98_Ext_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst.h b/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst.h index b08cce911..322e104c1 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MsrElementFirst.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MsrElementFirst_H_ -#define _OTD_MsrElementFirst_H_ +#ifndef _OTD_MsrElementFirst_H_ +#define _OTD_MsrElementFirst_H_ #include @@ -17,28 +17,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct TOA_MeasurementsOfRef; -struct SeqOfOTD_FirstSetMsrs; + /* Forward declarations */ + struct TOA_MeasurementsOfRef; + struct SeqOfOTD_FirstSetMsrs; -/* OTD-MsrElementFirst */ -typedef struct OTD_MsrElementFirst { - long refFrameNumber; - ModuloTimeSlot_t referenceTimeSlot; - struct TOA_MeasurementsOfRef *toaMeasurementsOfRef /* OPTIONAL */; - StdResolution_t stdResolution; - long *taCorrection /* OPTIONAL */; - struct SeqOfOTD_FirstSetMsrs *otd_FirstSetMsrs /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MsrElementFirst_t; + /* OTD-MsrElementFirst */ + typedef struct OTD_MsrElementFirst + { + long refFrameNumber; + ModuloTimeSlot_t referenceTimeSlot; + struct TOA_MeasurementsOfRef *toaMeasurementsOfRef /* OPTIONAL */; + StdResolution_t stdResolution; + long *taCorrection /* OPTIONAL */; + struct SeqOfOTD_FirstSetMsrs *otd_FirstSetMsrs /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MsrElementFirst_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst; #ifdef __cplusplus } @@ -48,5 +50,5 @@ extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementFirst; #include "TOA-MeasurementsOfRef.h" #include "SeqOfOTD-FirstSetMsrs.h" -#endif /* _OTD_MsrElementFirst_H_ */ +#endif /* _OTD_MsrElementFirst_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MsrElementRest.h b/src/core/libs/supl/asn-rrlp/OTD-MsrElementRest.h index a87a3c7fb..fd1955652 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MsrElementRest.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MsrElementRest.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MsrElementRest_H_ -#define _OTD_MsrElementRest_H_ +#ifndef _OTD_MsrElementRest_H_ +#define _OTD_MsrElementRest_H_ #include @@ -17,28 +17,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct TOA_MeasurementsOfRef; -struct SeqOfOTD_MsrsOfOtherSets; + /* Forward declarations */ + struct TOA_MeasurementsOfRef; + struct SeqOfOTD_MsrsOfOtherSets; -/* OTD-MsrElementRest */ -typedef struct OTD_MsrElementRest { - long refFrameNumber; - ModuloTimeSlot_t referenceTimeSlot; - struct TOA_MeasurementsOfRef *toaMeasurementsOfRef /* OPTIONAL */; - StdResolution_t stdResolution; - long *taCorrection /* OPTIONAL */; - struct SeqOfOTD_MsrsOfOtherSets *otd_MsrsOfOtherSets /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MsrElementRest_t; + /* OTD-MsrElementRest */ + typedef struct OTD_MsrElementRest + { + long refFrameNumber; + ModuloTimeSlot_t referenceTimeSlot; + struct TOA_MeasurementsOfRef *toaMeasurementsOfRef /* OPTIONAL */; + StdResolution_t stdResolution; + long *taCorrection /* OPTIONAL */; + struct SeqOfOTD_MsrsOfOtherSets *otd_MsrsOfOtherSets /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementRest; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MsrElementRest_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementRest; #ifdef __cplusplus } @@ -48,5 +50,5 @@ extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrElementRest; #include "TOA-MeasurementsOfRef.h" #include "SeqOfOTD-MsrsOfOtherSets.h" -#endif /* _OTD_MsrElementRest_H_ */ +#endif /* _OTD_MsrElementRest_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTD-MsrsOfOtherSets.h b/src/core/libs/supl/asn-rrlp/OTD-MsrsOfOtherSets.h index ec2efd3a2..7df79d03a 100644 --- a/src/core/libs/supl/asn-rrlp/OTD-MsrsOfOtherSets.h +++ b/src/core/libs/supl/asn-rrlp/OTD-MsrsOfOtherSets.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTD_MsrsOfOtherSets_H_ -#define _OTD_MsrsOfOtherSets_H_ +#ifndef _OTD_MsrsOfOtherSets_H_ +#define _OTD_MsrsOfOtherSets_H_ #include @@ -16,34 +16,38 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum OTD_MsrsOfOtherSets_PR { - OTD_MsrsOfOtherSets_PR_NOTHING, /* No components present */ - OTD_MsrsOfOtherSets_PR_identityNotPresent, - OTD_MsrsOfOtherSets_PR_identityPresent -} OTD_MsrsOfOtherSets_PR; + /* Dependencies */ + typedef enum OTD_MsrsOfOtherSets_PR + { + OTD_MsrsOfOtherSets_PR_NOTHING, /* No components present */ + OTD_MsrsOfOtherSets_PR_identityNotPresent, + OTD_MsrsOfOtherSets_PR_identityPresent + } OTD_MsrsOfOtherSets_PR; -/* OTD-MsrsOfOtherSets */ -typedef struct OTD_MsrsOfOtherSets { - OTD_MsrsOfOtherSets_PR present; - union OTD_MsrsOfOtherSets_u { - OTD_Measurement_t identityNotPresent; - OTD_MeasurementWithID_t identityPresent; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} OTD_MsrsOfOtherSets_t; + /* OTD-MsrsOfOtherSets */ + typedef struct OTD_MsrsOfOtherSets + { + OTD_MsrsOfOtherSets_PR present; + union OTD_MsrsOfOtherSets_u + { + OTD_Measurement_t identityNotPresent; + OTD_MeasurementWithID_t identityPresent; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrsOfOtherSets; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } OTD_MsrsOfOtherSets_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTD_MsrsOfOtherSets; #ifdef __cplusplus } #endif -#endif /* _OTD_MsrsOfOtherSets_H_ */ +#endif /* _OTD_MsrsOfOtherSets_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/OTDValue.h b/src/core/libs/supl/asn-rrlp/OTDValue.h index 39fc8a9d3..42ea5a9e4 100644 --- a/src/core/libs/supl/asn-rrlp/OTDValue.h +++ b/src/core/libs/supl/asn-rrlp/OTDValue.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _OTDValue_H_ -#define _OTDValue_H_ +#ifndef _OTDValue_H_ +#define _OTDValue_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* OTDValue */ -typedef long OTDValue_t; + /* OTDValue */ + typedef long OTDValue_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_OTDValue; -asn_struct_free_f OTDValue_free; -asn_struct_print_f OTDValue_print; -asn_constr_check_f OTDValue_constraint; -ber_type_decoder_f OTDValue_decode_ber; -der_type_encoder_f OTDValue_encode_der; -xer_type_decoder_f OTDValue_decode_xer; -xer_type_encoder_f OTDValue_encode_xer; -per_type_decoder_f OTDValue_decode_uper; -per_type_encoder_f OTDValue_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_OTDValue; + asn_struct_free_f OTDValue_free; + asn_struct_print_f OTDValue_print; + asn_constr_check_f OTDValue_constraint; + ber_type_decoder_f OTDValue_decode_ber; + der_type_encoder_f OTDValue_encode_der; + xer_type_decoder_f OTDValue_decode_xer; + xer_type_encoder_f OTDValue_encode_xer; + per_type_decoder_f OTDValue_decode_uper; + per_type_encoder_f OTDValue_encode_uper; #ifdef __cplusplus } #endif -#endif /* _OTDValue_H_ */ +#endif /* _OTDValue_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/PDU.h b/src/core/libs/supl/asn-rrlp/PDU.h index e73e9958a..5a815aaf5 100644 --- a/src/core/libs/supl/asn-rrlp/PDU.h +++ b/src/core/libs/supl/asn-rrlp/PDU.h @@ -4,8 +4,8 @@ * found in "../rrlp-messages.asn" */ -#ifndef _PDU_H_ -#define _PDU_H_ +#ifndef _PDU_H_ +#define _PDU_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PDU */ -typedef struct PDU { - long referenceNumber; - RRLP_Component_t component; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PDU_t; + /* PDU */ + typedef struct PDU + { + long referenceNumber; + RRLP_Component_t component; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PDU; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PDU_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PDU; #ifdef __cplusplus } #endif -#endif /* _PDU_H_ */ +#endif /* _PDU_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/PositionData.h b/src/core/libs/supl/asn-rrlp/PositionData.h index fddb87bcd..7545873ef 100644 --- a/src/core/libs/supl/asn-rrlp/PositionData.h +++ b/src/core/libs/supl/asn-rrlp/PositionData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _PositionData_H_ -#define _PositionData_H_ +#ifndef _PositionData_H_ +#define _PositionData_H_ #include @@ -14,34 +14,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum PositionData { - PositionData_e_otd = 0, - PositionData_gps = 1, - PositionData_galileo = 2 -} e_PositionData; + /* Dependencies */ + typedef enum PositionData + { + PositionData_e_otd = 0, + PositionData_gps = 1, + PositionData_galileo = 2 + } e_PositionData; -/* PositionData */ -typedef BIT_STRING_t PositionData_t; + /* PositionData */ + typedef BIT_STRING_t PositionData_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PositionData; -asn_struct_free_f PositionData_free; -asn_struct_print_f PositionData_print; -asn_constr_check_f PositionData_constraint; -ber_type_decoder_f PositionData_decode_ber; -der_type_encoder_f PositionData_encode_der; -xer_type_decoder_f PositionData_decode_xer; -xer_type_encoder_f PositionData_encode_xer; -per_type_decoder_f PositionData_decode_uper; -per_type_encoder_f PositionData_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PositionData; + asn_struct_free_f PositionData_free; + asn_struct_print_f PositionData_print; + asn_constr_check_f PositionData_constraint; + ber_type_decoder_f PositionData_decode_ber; + der_type_encoder_f PositionData_encode_der; + xer_type_decoder_f PositionData_decode_xer; + xer_type_encoder_f PositionData_encode_xer; + per_type_decoder_f PositionData_decode_uper; + per_type_encoder_f PositionData_encode_uper; #ifdef __cplusplus } #endif -#endif /* _PositionData_H_ */ +#endif /* _PositionData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/PositionInstruct.h b/src/core/libs/supl/asn-rrlp/PositionInstruct.h index 43119ef57..e0e49f72f 100644 --- a/src/core/libs/supl/asn-rrlp/PositionInstruct.h +++ b/src/core/libs/supl/asn-rrlp/PositionInstruct.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _PositionInstruct_H_ -#define _PositionInstruct_H_ +#ifndef _PositionInstruct_H_ +#define _PositionInstruct_H_ #include @@ -19,27 +19,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PositionInstruct */ -typedef struct PositionInstruct { - MethodType_t methodType; - PositionMethod_t positionMethod; - MeasureResponseTime_t measureResponseTime; - UseMultipleSets_t useMultipleSets; - EnvironmentCharacter_t *environmentCharacter /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PositionInstruct_t; + /* PositionInstruct */ + typedef struct PositionInstruct + { + MethodType_t methodType; + PositionMethod_t positionMethod; + MeasureResponseTime_t measureResponseTime; + UseMultipleSets_t useMultipleSets; + EnvironmentCharacter_t *environmentCharacter /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PositionInstruct; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PositionInstruct_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PositionInstruct; #ifdef __cplusplus } #endif -#endif /* _PositionInstruct_H_ */ +#endif /* _PositionInstruct_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/PositionMethod.h b/src/core/libs/supl/asn-rrlp/PositionMethod.h index 82e88091d..64db54e6c 100644 --- a/src/core/libs/supl/asn-rrlp/PositionMethod.h +++ b/src/core/libs/supl/asn-rrlp/PositionMethod.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _PositionMethod_H_ -#define _PositionMethod_H_ +#ifndef _PositionMethod_H_ +#define _PositionMethod_H_ #include @@ -14,34 +14,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum PositionMethod { - PositionMethod_eotd = 0, - PositionMethod_gps = 1, - PositionMethod_gpsOrEOTD = 2 -} e_PositionMethod; + /* Dependencies */ + typedef enum PositionMethod + { + PositionMethod_eotd = 0, + PositionMethod_gps = 1, + PositionMethod_gpsOrEOTD = 2 + } e_PositionMethod; -/* PositionMethod */ -typedef ENUMERATED_t PositionMethod_t; + /* PositionMethod */ + typedef ENUMERATED_t PositionMethod_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PositionMethod; -asn_struct_free_f PositionMethod_free; -asn_struct_print_f PositionMethod_print; -asn_constr_check_f PositionMethod_constraint; -ber_type_decoder_f PositionMethod_decode_ber; -der_type_encoder_f PositionMethod_encode_der; -xer_type_decoder_f PositionMethod_decode_xer; -xer_type_encoder_f PositionMethod_encode_xer; -per_type_decoder_f PositionMethod_decode_uper; -per_type_encoder_f PositionMethod_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PositionMethod; + asn_struct_free_f PositionMethod_free; + asn_struct_print_f PositionMethod_print; + asn_constr_check_f PositionMethod_constraint; + ber_type_decoder_f PositionMethod_decode_ber; + der_type_encoder_f PositionMethod_encode_der; + xer_type_decoder_f PositionMethod_decode_xer; + xer_type_encoder_f PositionMethod_encode_xer; + per_type_decoder_f PositionMethod_decode_uper; + per_type_encoder_f PositionMethod_encode_uper; #ifdef __cplusplus } #endif -#endif /* _PositionMethod_H_ */ +#endif /* _PositionMethod_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ProtocolError.h b/src/core/libs/supl/asn-rrlp/ProtocolError.h index 00a94c40f..8dd1b0fdc 100644 --- a/src/core/libs/supl/asn-rrlp/ProtocolError.h +++ b/src/core/libs/supl/asn-rrlp/ProtocolError.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ProtocolError_H_ -#define _ProtocolError_H_ +#ifndef _ProtocolError_H_ +#define _ProtocolError_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Rel_5_ProtocolError_Extension; + /* Forward declarations */ + struct Rel_5_ProtocolError_Extension; -/* ProtocolError */ -typedef struct ProtocolError { - ErrorCodes_t errorCause; - ExtensionContainer_t *extensionContainer /* OPTIONAL */; - /* + /* ProtocolError */ + typedef struct ProtocolError + { + ErrorCodes_t errorCause; + ExtensionContainer_t *extensionContainer /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - struct Rel_5_ProtocolError_Extension *rel_5_ProtocolError_Extension /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ProtocolError_t; + struct Rel_5_ProtocolError_Extension *rel_5_ProtocolError_Extension /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ProtocolError; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ProtocolError_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ProtocolError; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_ProtocolError; /* Referred external types */ #include "Rel-5-ProtocolError-Extension.h" -#endif /* _ProtocolError_H_ */ +#endif /* _ProtocolError_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RRLP-Component.h b/src/core/libs/supl/asn-rrlp/RRLP-Component.h index 021f54a4f..02208b69d 100644 --- a/src/core/libs/supl/asn-rrlp/RRLP-Component.h +++ b/src/core/libs/supl/asn-rrlp/RRLP-Component.h @@ -4,8 +4,8 @@ * found in "../rrlp-messages.asn" */ -#ifndef _RRLP_Component_H_ -#define _RRLP_Component_H_ +#ifndef _RRLP_Component_H_ +#define _RRLP_Component_H_ #include @@ -19,46 +19,50 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum RRLP_Component_PR { - RRLP_Component_PR_NOTHING, /* No components present */ - RRLP_Component_PR_msrPositionReq, - RRLP_Component_PR_msrPositionRsp, - RRLP_Component_PR_assistanceData, - RRLP_Component_PR_assistanceDataAck, - RRLP_Component_PR_protocolError, - /* Extensions may appear below */ - -} RRLP_Component_PR; + /* Dependencies */ + typedef enum RRLP_Component_PR + { + RRLP_Component_PR_NOTHING, /* No components present */ + RRLP_Component_PR_msrPositionReq, + RRLP_Component_PR_msrPositionRsp, + RRLP_Component_PR_assistanceData, + RRLP_Component_PR_assistanceDataAck, + RRLP_Component_PR_protocolError, + /* Extensions may appear below */ -/* RRLP-Component */ -typedef struct RRLP_Component { - RRLP_Component_PR present; - union RRLP_Component_u { - MsrPosition_Req_t msrPositionReq; - MsrPosition_Rsp_t msrPositionRsp; - AssistanceData_t assistanceData; - NULL_t assistanceDataAck; - ProtocolError_t protocolError; - /* + } RRLP_Component_PR; + + /* RRLP-Component */ + typedef struct RRLP_Component + { + RRLP_Component_PR present; + union RRLP_Component_u + { + MsrPosition_Req_t msrPositionReq; + MsrPosition_Rsp_t msrPositionRsp; + AssistanceData_t assistanceData; + NULL_t assistanceDataAck; + ProtocolError_t protocolError; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} RRLP_Component_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RRLP_Component; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } RRLP_Component_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RRLP_Component; #ifdef __cplusplus } #endif -#endif /* _RRLP_Component_H_ */ +#endif /* _RRLP_Component_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RefLocation.h b/src/core/libs/supl/asn-rrlp/RefLocation.h index 0a0849c58..d95632425 100644 --- a/src/core/libs/supl/asn-rrlp/RefLocation.h +++ b/src/core/libs/supl/asn-rrlp/RefLocation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RefLocation_H_ -#define _RefLocation_H_ +#ifndef _RefLocation_H_ +#define _RefLocation_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RefLocation */ -typedef struct RefLocation { - Ext_GeographicalInformation_t threeDLocation; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} RefLocation_t; + /* RefLocation */ + typedef struct RefLocation + { + Ext_GeographicalInformation_t threeDLocation; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RefLocation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } RefLocation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RefLocation; #ifdef __cplusplus } #endif -#endif /* _RefLocation_H_ */ +#endif /* _RefLocation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RefQuality.h b/src/core/libs/supl/asn-rrlp/RefQuality.h index 1fe321512..d8e0f451d 100644 --- a/src/core/libs/supl/asn-rrlp/RefQuality.h +++ b/src/core/libs/supl/asn-rrlp/RefQuality.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RefQuality_H_ -#define _RefQuality_H_ +#ifndef _RefQuality_H_ +#define _RefQuality_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RefQuality */ -typedef long RefQuality_t; + /* RefQuality */ + typedef long RefQuality_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RefQuality; -asn_struct_free_f RefQuality_free; -asn_struct_print_f RefQuality_print; -asn_constr_check_f RefQuality_constraint; -ber_type_decoder_f RefQuality_decode_ber; -der_type_encoder_f RefQuality_encode_der; -xer_type_decoder_f RefQuality_decode_xer; -xer_type_encoder_f RefQuality_encode_xer; -per_type_decoder_f RefQuality_decode_uper; -per_type_encoder_f RefQuality_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RefQuality; + asn_struct_free_f RefQuality_free; + asn_struct_print_f RefQuality_print; + asn_constr_check_f RefQuality_constraint; + ber_type_decoder_f RefQuality_decode_ber; + der_type_encoder_f RefQuality_encode_der; + xer_type_decoder_f RefQuality_decode_xer; + xer_type_encoder_f RefQuality_encode_xer; + per_type_decoder_f RefQuality_decode_uper; + per_type_encoder_f RefQuality_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RefQuality_H_ */ +#endif /* _RefQuality_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceAssistData.h b/src/core/libs/supl/asn-rrlp/ReferenceAssistData.h index 74659c650..b1e6d924a 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceAssistData.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceAssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceAssistData_H_ -#define _ReferenceAssistData_H_ +#ifndef _ReferenceAssistData_H_ +#define _ReferenceAssistData_H_ #include @@ -18,26 +18,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ReferenceAssistData */ -typedef struct ReferenceAssistData { - BCCHCarrier_t bcchCarrier; - BSIC_t bsic; - TimeSlotScheme_t timeSlotScheme; - BTSPosition_t *btsPosition /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceAssistData_t; + /* ReferenceAssistData */ + typedef struct ReferenceAssistData + { + BCCHCarrier_t bcchCarrier; + BSIC_t bsic; + TimeSlotScheme_t timeSlotScheme; + BTSPosition_t *btsPosition /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceAssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceAssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceAssistData; #ifdef __cplusplus } #endif -#endif /* _ReferenceAssistData_H_ */ +#endif /* _ReferenceAssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceFrame.h b/src/core/libs/supl/asn-rrlp/ReferenceFrame.h index 52bb0d24b..6f34f557a 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceFrame.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceFrame.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceFrame_H_ -#define _ReferenceFrame_H_ +#ifndef _ReferenceFrame_H_ +#define _ReferenceFrame_H_ #include @@ -15,24 +15,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ReferenceFrame */ -typedef struct ReferenceFrame { - long referenceFN; - long *referenceFNMSB /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceFrame_t; + /* ReferenceFrame */ + typedef struct ReferenceFrame + { + long referenceFN; + long *referenceFNMSB /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceFrame; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceFrame_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceFrame; #ifdef __cplusplus } #endif -#endif /* _ReferenceFrame_H_ */ +#endif /* _ReferenceFrame_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceIdentity.h b/src/core/libs/supl/asn-rrlp/ReferenceIdentity.h index 16088ffc6..444681d8f 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceIdentity.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceIdentity.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceIdentity_H_ -#define _ReferenceIdentity_H_ +#ifndef _ReferenceIdentity_H_ +#define _ReferenceIdentity_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ReferenceIdentity */ -typedef struct ReferenceIdentity { - SeqOfReferenceIdentityType_t refBTSList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceIdentity_t; + /* ReferenceIdentity */ + typedef struct ReferenceIdentity + { + SeqOfReferenceIdentityType_t refBTSList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceIdentity; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceIdentity_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceIdentity; #ifdef __cplusplus } #endif -#endif /* _ReferenceIdentity_H_ */ +#endif /* _ReferenceIdentity_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceIdentityType.h b/src/core/libs/supl/asn-rrlp/ReferenceIdentityType.h index 356f03135..6b5b8afc0 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceIdentityType.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceIdentityType.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceIdentityType_H_ -#define _ReferenceIdentityType_H_ +#ifndef _ReferenceIdentityType_H_ +#define _ReferenceIdentityType_H_ #include @@ -19,40 +19,44 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum ReferenceIdentityType_PR { - ReferenceIdentityType_PR_NOTHING, /* No components present */ - ReferenceIdentityType_PR_bsicAndCarrier, - ReferenceIdentityType_PR_ci, - ReferenceIdentityType_PR_requestIndex, - ReferenceIdentityType_PR_systemInfoIndex, - ReferenceIdentityType_PR_ciAndLAC -} ReferenceIdentityType_PR; + /* Dependencies */ + typedef enum ReferenceIdentityType_PR + { + ReferenceIdentityType_PR_NOTHING, /* No components present */ + ReferenceIdentityType_PR_bsicAndCarrier, + ReferenceIdentityType_PR_ci, + ReferenceIdentityType_PR_requestIndex, + ReferenceIdentityType_PR_systemInfoIndex, + ReferenceIdentityType_PR_ciAndLAC + } ReferenceIdentityType_PR; -/* ReferenceIdentityType */ -typedef struct ReferenceIdentityType { - ReferenceIdentityType_PR present; - union ReferenceIdentityType_u { - BSICAndCarrier_t bsicAndCarrier; - CellID_t ci; - RequestIndex_t requestIndex; - SystemInfoIndex_t systemInfoIndex; - CellIDAndLAC_t ciAndLAC; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceIdentityType_t; + /* ReferenceIdentityType */ + typedef struct ReferenceIdentityType + { + ReferenceIdentityType_PR present; + union ReferenceIdentityType_u + { + BSICAndCarrier_t bsicAndCarrier; + CellID_t ci; + RequestIndex_t requestIndex; + SystemInfoIndex_t systemInfoIndex; + CellIDAndLAC_t ciAndLAC; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceIdentityType; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceIdentityType_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceIdentityType; #ifdef __cplusplus } #endif -#endif /* _ReferenceIdentityType_H_ */ +#endif /* _ReferenceIdentityType_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceRelation.h b/src/core/libs/supl/asn-rrlp/ReferenceRelation.h index c89d6dfd1..544d32483 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceRelation.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceRelation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceRelation_H_ -#define _ReferenceRelation_H_ +#ifndef _ReferenceRelation_H_ +#define _ReferenceRelation_H_ #include @@ -14,34 +14,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum ReferenceRelation { - ReferenceRelation_secondBTSThirdSet = 0, - ReferenceRelation_secondBTSSecondSet = 1, - ReferenceRelation_firstBTSFirstSet = 2 -} e_ReferenceRelation; + /* Dependencies */ + typedef enum ReferenceRelation + { + ReferenceRelation_secondBTSThirdSet = 0, + ReferenceRelation_secondBTSSecondSet = 1, + ReferenceRelation_firstBTSFirstSet = 2 + } e_ReferenceRelation; -/* ReferenceRelation */ -typedef ENUMERATED_t ReferenceRelation_t; + /* ReferenceRelation */ + typedef ENUMERATED_t ReferenceRelation_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceRelation; -asn_struct_free_f ReferenceRelation_free; -asn_struct_print_f ReferenceRelation_print; -asn_constr_check_f ReferenceRelation_constraint; -ber_type_decoder_f ReferenceRelation_decode_ber; -der_type_encoder_f ReferenceRelation_encode_der; -xer_type_decoder_f ReferenceRelation_decode_xer; -xer_type_encoder_f ReferenceRelation_encode_xer; -per_type_decoder_f ReferenceRelation_decode_uper; -per_type_encoder_f ReferenceRelation_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceRelation; + asn_struct_free_f ReferenceRelation_free; + asn_struct_print_f ReferenceRelation_print; + asn_constr_check_f ReferenceRelation_constraint; + ber_type_decoder_f ReferenceRelation_decode_ber; + der_type_encoder_f ReferenceRelation_encode_der; + xer_type_decoder_f ReferenceRelation_decode_xer; + xer_type_encoder_f ReferenceRelation_encode_xer; + per_type_decoder_f ReferenceRelation_decode_uper; + per_type_encoder_f ReferenceRelation_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ReferenceRelation_H_ */ +#endif /* _ReferenceRelation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceTime.h b/src/core/libs/supl/asn-rrlp/ReferenceTime.h index 101df484a..cf1ade693 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceTime.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceTime_H_ -#define _ReferenceTime_H_ +#ifndef _ReferenceTime_H_ +#define _ReferenceTime_H_ #include @@ -15,25 +15,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GSMTime; -struct GPSTOWAssist; + /* Forward declarations */ + struct GSMTime; + struct GPSTOWAssist; -/* ReferenceTime */ -typedef struct ReferenceTime { - GPSTime_t gpsTime; - struct GSMTime *gsmTime /* OPTIONAL */; - struct GPSTOWAssist *gpsTowAssist /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceTime_t; + /* ReferenceTime */ + typedef struct ReferenceTime + { + GPSTime_t gpsTime; + struct GSMTime *gsmTime /* OPTIONAL */; + struct GPSTOWAssist *gpsTowAssist /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceTime; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceTime_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceTime; #ifdef __cplusplus } @@ -43,5 +45,5 @@ extern asn_TYPE_descriptor_t asn_DEF_ReferenceTime; #include "GSMTime.h" #include "GPSTOWAssist.h" -#endif /* _ReferenceTime_H_ */ +#endif /* _ReferenceTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/ReferenceWGS84.h b/src/core/libs/supl/asn-rrlp/ReferenceWGS84.h index d90698cdf..544127c70 100644 --- a/src/core/libs/supl/asn-rrlp/ReferenceWGS84.h +++ b/src/core/libs/supl/asn-rrlp/ReferenceWGS84.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _ReferenceWGS84_H_ -#define _ReferenceWGS84_H_ +#ifndef _ReferenceWGS84_H_ +#define _ReferenceWGS84_H_ #include @@ -16,25 +16,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ReferenceWGS84 */ -typedef struct ReferenceWGS84 { - RelDistance_t relativeNorth; - RelDistance_t relativeEast; - RelativeAlt_t *relativeAlt /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ReferenceWGS84_t; + /* ReferenceWGS84 */ + typedef struct ReferenceWGS84 + { + RelDistance_t relativeNorth; + RelDistance_t relativeEast; + RelativeAlt_t *relativeAlt /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ReferenceWGS84; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ReferenceWGS84_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ReferenceWGS84; #ifdef __cplusplus } #endif -#endif /* _ReferenceWGS84_H_ */ +#endif /* _ReferenceWGS84_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel-5-MsrPosition-Rsp-Extension.h b/src/core/libs/supl/asn-rrlp/Rel-5-MsrPosition-Rsp-Extension.h index 5f3e42073..3a0f2ef4e 100644 --- a/src/core/libs/supl/asn-rrlp/Rel-5-MsrPosition-Rsp-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel-5-MsrPosition-Rsp-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel_5_MsrPosition_Rsp_Extension_H_ -#define _Rel_5_MsrPosition_Rsp_Extension_H_ +#ifndef _Rel_5_MsrPosition_Rsp_Extension_H_ +#define _Rel_5_MsrPosition_Rsp_Extension_H_ #include @@ -15,29 +15,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Extended_reference; -struct SeqOfOTD_MsrElementRest; + /* Forward declarations */ + struct Extended_reference; + struct SeqOfOTD_MsrElementRest; -/* Rel-5-MsrPosition-Rsp-Extension */ -typedef struct Rel_5_MsrPosition_Rsp_Extension { - struct Extended_reference *extended_reference /* OPTIONAL */; - struct SeqOfOTD_MsrElementRest *otd_MeasureInfo_5_Ext /* OPTIONAL */; - UlPseudoSegInd_t *ulPseudoSegInd /* OPTIONAL */; - /* + /* Rel-5-MsrPosition-Rsp-Extension */ + typedef struct Rel_5_MsrPosition_Rsp_Extension + { + struct Extended_reference *extended_reference /* OPTIONAL */; + struct SeqOfOTD_MsrElementRest *otd_MeasureInfo_5_Ext /* OPTIONAL */; + UlPseudoSegInd_t *ulPseudoSegInd /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel_5_MsrPosition_Rsp_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel_5_MsrPosition_Rsp_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel_5_MsrPosition_Rsp_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel_5_MsrPosition_Rsp_Extension; #ifdef __cplusplus } @@ -47,5 +49,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel_5_MsrPosition_Rsp_Extension; #include "Extended-reference.h" #include "OTD-MeasureInfo-5-Ext.h" -#endif /* _Rel_5_MsrPosition_Rsp_Extension_H_ */ +#endif /* _Rel_5_MsrPosition_Rsp_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel-5-ProtocolError-Extension.h b/src/core/libs/supl/asn-rrlp/Rel-5-ProtocolError-Extension.h index e73e5a0b7..00762b59c 100644 --- a/src/core/libs/supl/asn-rrlp/Rel-5-ProtocolError-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel-5-ProtocolError-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel_5_ProtocolError_Extension_H_ -#define _Rel_5_ProtocolError_Extension_H_ +#ifndef _Rel_5_ProtocolError_Extension_H_ +#define _Rel_5_ProtocolError_Extension_H_ #include @@ -14,26 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Extended_reference; + /* Forward declarations */ + struct Extended_reference; -/* Rel-5-ProtocolError-Extension */ -typedef struct Rel_5_ProtocolError_Extension { - struct Extended_reference *extended_reference /* OPTIONAL */; - /* + /* Rel-5-ProtocolError-Extension */ + typedef struct Rel_5_ProtocolError_Extension + { + struct Extended_reference *extended_reference /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel_5_ProtocolError_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel_5_ProtocolError_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel_5_ProtocolError_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel_5_ProtocolError_Extension; #ifdef __cplusplus } @@ -42,5 +44,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel_5_ProtocolError_Extension; /* Referred external types */ #include "Extended-reference.h" -#endif /* _Rel_5_ProtocolError_Extension_H_ */ +#endif /* _Rel_5_ProtocolError_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel-7-MsrPosition-Rsp-Extension.h b/src/core/libs/supl/asn-rrlp/Rel-7-MsrPosition-Rsp-Extension.h index 771706639..d030be0bf 100644 --- a/src/core/libs/supl/asn-rrlp/Rel-7-MsrPosition-Rsp-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel-7-MsrPosition-Rsp-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel_7_MsrPosition_Rsp_Extension_H_ -#define _Rel_7_MsrPosition_Rsp_Extension_H_ +#ifndef _Rel_7_MsrPosition_Rsp_Extension_H_ +#define _Rel_7_MsrPosition_Rsp_Extension_H_ #include @@ -15,29 +15,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSLocationInfo; -struct GANSSMeasureInfo; + /* Forward declarations */ + struct GANSSLocationInfo; + struct GANSSMeasureInfo; -/* Rel-7-MsrPosition-Rsp-Extension */ -typedef struct Rel_7_MsrPosition_Rsp_Extension { - VelocityEstimate_t *velEstimate /* OPTIONAL */; - struct GANSSLocationInfo *ganssLocationInfo /* OPTIONAL */; - struct GANSSMeasureInfo *ganssMeasureInfo /* OPTIONAL */; - /* + /* Rel-7-MsrPosition-Rsp-Extension */ + typedef struct Rel_7_MsrPosition_Rsp_Extension + { + VelocityEstimate_t *velEstimate /* OPTIONAL */; + struct GANSSLocationInfo *ganssLocationInfo /* OPTIONAL */; + struct GANSSMeasureInfo *ganssMeasureInfo /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel_7_MsrPosition_Rsp_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel_7_MsrPosition_Rsp_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel_7_MsrPosition_Rsp_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel_7_MsrPosition_Rsp_Extension; #ifdef __cplusplus } @@ -47,5 +49,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel_7_MsrPosition_Rsp_Extension; #include "GANSSLocationInfo.h" #include "GANSSMeasureInfo.h" -#endif /* _Rel_7_MsrPosition_Rsp_Extension_H_ */ +#endif /* _Rel_7_MsrPosition_Rsp_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel-98-MsrPosition-Rsp-Extension.h b/src/core/libs/supl/asn-rrlp/Rel-98-MsrPosition-Rsp-Extension.h index a54e43bf1..0d3425c17 100644 --- a/src/core/libs/supl/asn-rrlp/Rel-98-MsrPosition-Rsp-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel-98-MsrPosition-Rsp-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel_98_MsrPosition_Rsp_Extension_H_ -#define _Rel_98_MsrPosition_Rsp_Extension_H_ +#ifndef _Rel_98_MsrPosition_Rsp_Extension_H_ +#define _Rel_98_MsrPosition_Rsp_Extension_H_ #include @@ -14,33 +14,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GPSTimeAssistanceMeasurements; -struct OTD_MeasureInfo_R98_Ext; + /* Forward declarations */ + struct GPSTimeAssistanceMeasurements; + struct OTD_MeasureInfo_R98_Ext; -/* Rel-98-MsrPosition-Rsp-Extension */ -typedef struct Rel_98_MsrPosition_Rsp_Extension { - struct rel_98_Ext_MeasureInfo { - struct OTD_MeasureInfo_R98_Ext *otd_MeasureInfo_R98_Ext /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } rel_98_Ext_MeasureInfo; - /* + /* Rel-98-MsrPosition-Rsp-Extension */ + typedef struct Rel_98_MsrPosition_Rsp_Extension + { + struct rel_98_Ext_MeasureInfo + { + struct OTD_MeasureInfo_R98_Ext *otd_MeasureInfo_R98_Ext /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } rel_98_Ext_MeasureInfo; + /* * This type is extensible, * possible extensions are below. */ - struct GPSTimeAssistanceMeasurements *timeAssistanceMeasurements /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel_98_MsrPosition_Rsp_Extension_t; + struct GPSTimeAssistanceMeasurements *timeAssistanceMeasurements /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel_98_MsrPosition_Rsp_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel_98_MsrPosition_Rsp_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel_98_MsrPosition_Rsp_Extension; #ifdef __cplusplus } @@ -50,5 +53,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel_98_MsrPosition_Rsp_Extension; #include "GPSTimeAssistanceMeasurements.h" #include "OTD-MeasureInfo-R98-Ext.h" -#endif /* _Rel_98_MsrPosition_Rsp_Extension_H_ */ +#endif /* _Rel_98_MsrPosition_Rsp_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel5-AssistanceData-Extension.h b/src/core/libs/supl/asn-rrlp/Rel5-AssistanceData-Extension.h index 5f38409b5..77ad994dd 100644 --- a/src/core/libs/supl/asn-rrlp/Rel5-AssistanceData-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel5-AssistanceData-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel5_AssistanceData_Extension_H_ -#define _Rel5_AssistanceData_Extension_H_ +#ifndef _Rel5_AssistanceData_Extension_H_ +#define _Rel5_AssistanceData_Extension_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Rel5-AssistanceData-Extension */ -typedef struct Rel5_AssistanceData_Extension { - Extended_reference_t extended_reference; - /* + /* Rel5-AssistanceData-Extension */ + typedef struct Rel5_AssistanceData_Extension + { + Extended_reference_t extended_reference; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel5_AssistanceData_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel5_AssistanceData_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel5_AssistanceData_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel5_AssistanceData_Extension; #ifdef __cplusplus } #endif -#endif /* _Rel5_AssistanceData_Extension_H_ */ +#endif /* _Rel5_AssistanceData_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel5-MsrPosition-Req-Extension.h b/src/core/libs/supl/asn-rrlp/Rel5-MsrPosition-Req-Extension.h index 498073afb..d566be25f 100644 --- a/src/core/libs/supl/asn-rrlp/Rel5-MsrPosition-Req-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel5-MsrPosition-Req-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel5_MsrPosition_Req_Extension_H_ -#define _Rel5_MsrPosition_Req_Extension_H_ +#ifndef _Rel5_MsrPosition_Req_Extension_H_ +#define _Rel5_MsrPosition_Req_Extension_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Rel5-MsrPosition-Req-Extension */ -typedef struct Rel5_MsrPosition_Req_Extension { - Extended_reference_t extended_reference; - /* + /* Rel5-MsrPosition-Req-Extension */ + typedef struct Rel5_MsrPosition_Req_Extension + { + Extended_reference_t extended_reference; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel5_MsrPosition_Req_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel5_MsrPosition_Req_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel5_MsrPosition_Req_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel5_MsrPosition_Req_Extension; #ifdef __cplusplus } #endif -#endif /* _Rel5_MsrPosition_Req_Extension_H_ */ +#endif /* _Rel5_MsrPosition_Req_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel7-AssistanceData-Extension.h b/src/core/libs/supl/asn-rrlp/Rel7-AssistanceData-Extension.h index 34778f32e..4ecb0ffc5 100644 --- a/src/core/libs/supl/asn-rrlp/Rel7-AssistanceData-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel7-AssistanceData-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel7_AssistanceData_Extension_H_ -#define _Rel7_AssistanceData_Extension_H_ +#ifndef _Rel7_AssistanceData_Extension_H_ +#define _Rel7_AssistanceData_Extension_H_ #include @@ -15,28 +15,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSS_AssistData; + /* Forward declarations */ + struct GANSS_AssistData; -/* Rel7-AssistanceData-Extension */ -typedef struct Rel7_AssistanceData_Extension { - struct GANSS_AssistData *ganss_AssistData /* OPTIONAL */; - NULL_t *ganssCarrierPhaseMeasurementRequest /* OPTIONAL */; - NULL_t *ganssTODGSMTimeAssociationMeasurementRequest /* OPTIONAL */; - /* + /* Rel7-AssistanceData-Extension */ + typedef struct Rel7_AssistanceData_Extension + { + struct GANSS_AssistData *ganss_AssistData /* OPTIONAL */; + NULL_t *ganssCarrierPhaseMeasurementRequest /* OPTIONAL */; + NULL_t *ganssTODGSMTimeAssociationMeasurementRequest /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel7_AssistanceData_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel7_AssistanceData_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel7_AssistanceData_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel7_AssistanceData_Extension; #ifdef __cplusplus } @@ -45,5 +47,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel7_AssistanceData_Extension; /* Referred external types */ #include "GANSS-AssistData.h" -#endif /* _Rel7_AssistanceData_Extension_H_ */ +#endif /* _Rel7_AssistanceData_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel7-MsrPosition-Req-Extension.h b/src/core/libs/supl/asn-rrlp/Rel7-MsrPosition-Req-Extension.h index d44d16028..690b05fa5 100644 --- a/src/core/libs/supl/asn-rrlp/Rel7-MsrPosition-Req-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel7-MsrPosition-Req-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel7_MsrPosition_Req_Extension_H_ -#define _Rel7_MsrPosition_Req_Extension_H_ +#ifndef _Rel7_MsrPosition_Req_Extension_H_ +#define _Rel7_MsrPosition_Req_Extension_H_ #include @@ -17,31 +17,33 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSS_AssistData; + /* Forward declarations */ + struct GANSS_AssistData; -/* Rel7-MsrPosition-Req-Extension */ -typedef struct Rel7_MsrPosition_Req_Extension { - NULL_t *velocityRequested /* OPTIONAL */; - GANSSPositioningMethod_t *ganssPositionMethod /* OPTIONAL */; - struct GANSS_AssistData *ganss_AssistData /* OPTIONAL */; - NULL_t *ganssCarrierPhaseMeasurementRequest /* OPTIONAL */; - NULL_t *ganssTODGSMTimeAssociationMeasurementRequest /* OPTIONAL */; - RequiredResponseTime_t *requiredResponseTime /* OPTIONAL */; - /* + /* Rel7-MsrPosition-Req-Extension */ + typedef struct Rel7_MsrPosition_Req_Extension + { + NULL_t *velocityRequested /* OPTIONAL */; + GANSSPositioningMethod_t *ganssPositionMethod /* OPTIONAL */; + struct GANSS_AssistData *ganss_AssistData /* OPTIONAL */; + NULL_t *ganssCarrierPhaseMeasurementRequest /* OPTIONAL */; + NULL_t *ganssTODGSMTimeAssociationMeasurementRequest /* OPTIONAL */; + RequiredResponseTime_t *requiredResponseTime /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel7_MsrPosition_Req_Extension_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel7_MsrPosition_Req_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel7_MsrPosition_Req_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel7_MsrPosition_Req_Extension; #ifdef __cplusplus } @@ -50,5 +52,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel7_MsrPosition_Req_Extension; /* Referred external types */ #include "GANSS-AssistData.h" -#endif /* _Rel7_MsrPosition_Req_Extension_H_ */ +#endif /* _Rel7_MsrPosition_Req_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel98-AssistanceData-Extension.h b/src/core/libs/supl/asn-rrlp/Rel98-AssistanceData-Extension.h index 87c6177f6..f8e314e77 100644 --- a/src/core/libs/supl/asn-rrlp/Rel98-AssistanceData-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel98-AssistanceData-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel98_AssistanceData_Extension_H_ -#define _Rel98_AssistanceData_Extension_H_ +#ifndef _Rel98_AssistanceData_Extension_H_ +#define _Rel98_AssistanceData_Extension_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Rel98_Ext_ExpOTD; + /* Forward declarations */ + struct Rel98_Ext_ExpOTD; -/* Rel98-AssistanceData-Extension */ -typedef struct Rel98_AssistanceData_Extension { - struct Rel98_Ext_ExpOTD *rel98_Ext_ExpOTD /* OPTIONAL */; - /* + /* Rel98-AssistanceData-Extension */ + typedef struct Rel98_AssistanceData_Extension + { + struct Rel98_Ext_ExpOTD *rel98_Ext_ExpOTD /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - NULL_t *gpsTimeAssistanceMeasurementRequest /* OPTIONAL */; - GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel98_AssistanceData_Extension_t; + NULL_t *gpsTimeAssistanceMeasurementRequest /* OPTIONAL */; + GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel98_AssistanceData_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel98_AssistanceData_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel98_AssistanceData_Extension; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel98_AssistanceData_Extension; /* Referred external types */ #include "Rel98-Ext-ExpOTD.h" -#endif /* _Rel98_AssistanceData_Extension_H_ */ +#endif /* _Rel98_AssistanceData_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel98-Ext-ExpOTD.h b/src/core/libs/supl/asn-rrlp/Rel98-Ext-ExpOTD.h index 48169dd3f..75903c13f 100644 --- a/src/core/libs/supl/asn-rrlp/Rel98-Ext-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/Rel98-Ext-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel98_Ext_ExpOTD_H_ -#define _Rel98_Ext_ExpOTD_H_ +#ifndef _Rel98_Ext_ExpOTD_H_ +#define _Rel98_Ext_ExpOTD_H_ #include @@ -14,24 +14,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct MsrAssistData_R98_ExpOTD; -struct SystemInfoAssistData_R98_ExpOTD; + /* Forward declarations */ + struct MsrAssistData_R98_ExpOTD; + struct SystemInfoAssistData_R98_ExpOTD; -/* Rel98-Ext-ExpOTD */ -typedef struct Rel98_Ext_ExpOTD { - struct MsrAssistData_R98_ExpOTD *msrAssistData_R98_ExpOTD /* OPTIONAL */; - struct SystemInfoAssistData_R98_ExpOTD *systemInfoAssistData_R98_ExpOTD /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel98_Ext_ExpOTD_t; + /* Rel98-Ext-ExpOTD */ + typedef struct Rel98_Ext_ExpOTD + { + struct MsrAssistData_R98_ExpOTD *msrAssistData_R98_ExpOTD /* OPTIONAL */; + struct SystemInfoAssistData_R98_ExpOTD *systemInfoAssistData_R98_ExpOTD /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel98_Ext_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel98_Ext_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel98_Ext_ExpOTD; #ifdef __cplusplus } @@ -41,5 +43,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel98_Ext_ExpOTD; #include "MsrAssistData-R98-ExpOTD.h" #include "SystemInfoAssistData-R98-ExpOTD.h" -#endif /* _Rel98_Ext_ExpOTD_H_ */ +#endif /* _Rel98_Ext_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/Rel98-MsrPosition-Req-Extension.h b/src/core/libs/supl/asn-rrlp/Rel98-MsrPosition-Req-Extension.h index 39913e245..3922335b3 100644 --- a/src/core/libs/supl/asn-rrlp/Rel98-MsrPosition-Req-Extension.h +++ b/src/core/libs/supl/asn-rrlp/Rel98-MsrPosition-Req-Extension.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _Rel98_MsrPosition_Req_Extension_H_ -#define _Rel98_MsrPosition_Req_Extension_H_ +#ifndef _Rel98_MsrPosition_Req_Extension_H_ +#define _Rel98_MsrPosition_Req_Extension_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Rel98_Ext_ExpOTD; + /* Forward declarations */ + struct Rel98_Ext_ExpOTD; -/* Rel98-MsrPosition-Req-Extension */ -typedef struct Rel98_MsrPosition_Req_Extension { - struct Rel98_Ext_ExpOTD *rel98_Ext_ExpOTD /* OPTIONAL */; - /* + /* Rel98-MsrPosition-Req-Extension */ + typedef struct Rel98_MsrPosition_Req_Extension + { + struct Rel98_Ext_ExpOTD *rel98_Ext_ExpOTD /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - NULL_t *gpsTimeAssistanceMeasurementRequest /* OPTIONAL */; - GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Rel98_MsrPosition_Req_Extension_t; + NULL_t *gpsTimeAssistanceMeasurementRequest /* OPTIONAL */; + GPSReferenceTimeUncertainty_t *gpsReferenceTimeUncertainty /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Rel98_MsrPosition_Req_Extension; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Rel98_MsrPosition_Req_Extension_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Rel98_MsrPosition_Req_Extension; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Rel98_MsrPosition_Req_Extension; /* Referred external types */ #include "Rel98-Ext-ExpOTD.h" -#endif /* _Rel98_MsrPosition_Req_Extension_H_ */ +#endif /* _Rel98_MsrPosition_Req_Extension_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RelDistance.h b/src/core/libs/supl/asn-rrlp/RelDistance.h index 290bfa795..a9437f579 100644 --- a/src/core/libs/supl/asn-rrlp/RelDistance.h +++ b/src/core/libs/supl/asn-rrlp/RelDistance.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RelDistance_H_ -#define _RelDistance_H_ +#ifndef _RelDistance_H_ +#define _RelDistance_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RelDistance */ -typedef long RelDistance_t; + /* RelDistance */ + typedef long RelDistance_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RelDistance; -asn_struct_free_f RelDistance_free; -asn_struct_print_f RelDistance_print; -asn_constr_check_f RelDistance_constraint; -ber_type_decoder_f RelDistance_decode_ber; -der_type_encoder_f RelDistance_encode_der; -xer_type_decoder_f RelDistance_decode_xer; -xer_type_encoder_f RelDistance_encode_xer; -per_type_decoder_f RelDistance_decode_uper; -per_type_encoder_f RelDistance_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RelDistance; + asn_struct_free_f RelDistance_free; + asn_struct_print_f RelDistance_print; + asn_constr_check_f RelDistance_constraint; + ber_type_decoder_f RelDistance_decode_ber; + der_type_encoder_f RelDistance_encode_der; + xer_type_decoder_f RelDistance_decode_xer; + xer_type_encoder_f RelDistance_encode_xer; + per_type_decoder_f RelDistance_decode_uper; + per_type_encoder_f RelDistance_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RelDistance_H_ */ +#endif /* _RelDistance_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RelativeAlt.h b/src/core/libs/supl/asn-rrlp/RelativeAlt.h index f773482d4..22861f7f5 100644 --- a/src/core/libs/supl/asn-rrlp/RelativeAlt.h +++ b/src/core/libs/supl/asn-rrlp/RelativeAlt.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RelativeAlt_H_ -#define _RelativeAlt_H_ +#ifndef _RelativeAlt_H_ +#define _RelativeAlt_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RelativeAlt */ -typedef long RelativeAlt_t; + /* RelativeAlt */ + typedef long RelativeAlt_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RelativeAlt; -asn_struct_free_f RelativeAlt_free; -asn_struct_print_f RelativeAlt_print; -asn_constr_check_f RelativeAlt_constraint; -ber_type_decoder_f RelativeAlt_decode_ber; -der_type_encoder_f RelativeAlt_encode_der; -xer_type_decoder_f RelativeAlt_decode_xer; -xer_type_encoder_f RelativeAlt_encode_xer; -per_type_decoder_f RelativeAlt_decode_uper; -per_type_encoder_f RelativeAlt_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RelativeAlt; + asn_struct_free_f RelativeAlt_free; + asn_struct_print_f RelativeAlt_print; + asn_constr_check_f RelativeAlt_constraint; + ber_type_decoder_f RelativeAlt_decode_ber; + der_type_encoder_f RelativeAlt_encode_der; + xer_type_decoder_f RelativeAlt_decode_xer; + xer_type_encoder_f RelativeAlt_encode_xer; + per_type_decoder_f RelativeAlt_decode_uper; + per_type_encoder_f RelativeAlt_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RelativeAlt_H_ */ +#endif /* _RelativeAlt_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RequestIndex.h b/src/core/libs/supl/asn-rrlp/RequestIndex.h index 033a25329..177415736 100644 --- a/src/core/libs/supl/asn-rrlp/RequestIndex.h +++ b/src/core/libs/supl/asn-rrlp/RequestIndex.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RequestIndex_H_ -#define _RequestIndex_H_ +#ifndef _RequestIndex_H_ +#define _RequestIndex_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RequestIndex */ -typedef long RequestIndex_t; + /* RequestIndex */ + typedef long RequestIndex_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RequestIndex; -asn_struct_free_f RequestIndex_free; -asn_struct_print_f RequestIndex_print; -asn_constr_check_f RequestIndex_constraint; -ber_type_decoder_f RequestIndex_decode_ber; -der_type_encoder_f RequestIndex_encode_der; -xer_type_decoder_f RequestIndex_decode_xer; -xer_type_encoder_f RequestIndex_encode_xer; -per_type_decoder_f RequestIndex_decode_uper; -per_type_encoder_f RequestIndex_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RequestIndex; + asn_struct_free_f RequestIndex_free; + asn_struct_print_f RequestIndex_print; + asn_constr_check_f RequestIndex_constraint; + ber_type_decoder_f RequestIndex_decode_ber; + der_type_encoder_f RequestIndex_encode_der; + xer_type_decoder_f RequestIndex_decode_xer; + xer_type_encoder_f RequestIndex_encode_xer; + per_type_decoder_f RequestIndex_decode_uper; + per_type_encoder_f RequestIndex_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RequestIndex_H_ */ +#endif /* _RequestIndex_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RequiredResponseTime.h b/src/core/libs/supl/asn-rrlp/RequiredResponseTime.h index 0a609686b..f55669f23 100644 --- a/src/core/libs/supl/asn-rrlp/RequiredResponseTime.h +++ b/src/core/libs/supl/asn-rrlp/RequiredResponseTime.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RequiredResponseTime_H_ -#define _RequiredResponseTime_H_ +#ifndef _RequiredResponseTime_H_ +#define _RequiredResponseTime_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RequiredResponseTime */ -typedef long RequiredResponseTime_t; + /* RequiredResponseTime */ + typedef long RequiredResponseTime_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RequiredResponseTime; -asn_struct_free_f RequiredResponseTime_free; -asn_struct_print_f RequiredResponseTime_print; -asn_constr_check_f RequiredResponseTime_constraint; -ber_type_decoder_f RequiredResponseTime_decode_ber; -der_type_encoder_f RequiredResponseTime_encode_der; -xer_type_decoder_f RequiredResponseTime_decode_xer; -xer_type_encoder_f RequiredResponseTime_encode_xer; -per_type_decoder_f RequiredResponseTime_decode_uper; -per_type_encoder_f RequiredResponseTime_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RequiredResponseTime; + asn_struct_free_f RequiredResponseTime_free; + asn_struct_print_f RequiredResponseTime_print; + asn_constr_check_f RequiredResponseTime_constraint; + ber_type_decoder_f RequiredResponseTime_decode_ber; + der_type_encoder_f RequiredResponseTime_encode_der; + xer_type_decoder_f RequiredResponseTime_decode_xer; + xer_type_encoder_f RequiredResponseTime_encode_xer; + per_type_decoder_f RequiredResponseTime_decode_uper; + per_type_encoder_f RequiredResponseTime_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RequiredResponseTime_H_ */ +#endif /* _RequiredResponseTime_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/RoughRTD.h b/src/core/libs/supl/asn-rrlp/RoughRTD.h index 0cbd20bf7..59e72aff4 100644 --- a/src/core/libs/supl/asn-rrlp/RoughRTD.h +++ b/src/core/libs/supl/asn-rrlp/RoughRTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _RoughRTD_H_ -#define _RoughRTD_H_ +#ifndef _RoughRTD_H_ +#define _RoughRTD_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* RoughRTD */ -typedef long RoughRTD_t; + /* RoughRTD */ + typedef long RoughRTD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RoughRTD; -asn_struct_free_f RoughRTD_free; -asn_struct_print_f RoughRTD_print; -asn_constr_check_f RoughRTD_constraint; -ber_type_decoder_f RoughRTD_decode_ber; -der_type_encoder_f RoughRTD_encode_der; -xer_type_decoder_f RoughRTD_decode_xer; -xer_type_encoder_f RoughRTD_encode_xer; -per_type_decoder_f RoughRTD_decode_uper; -per_type_encoder_f RoughRTD_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RoughRTD; + asn_struct_free_f RoughRTD_free; + asn_struct_print_f RoughRTD_print; + asn_constr_check_f RoughRTD_constraint; + ber_type_decoder_f RoughRTD_decode_ber; + der_type_encoder_f RoughRTD_encode_der; + xer_type_decoder_f RoughRTD_decode_xer; + xer_type_encoder_f RoughRTD_encode_xer; + per_type_decoder_f RoughRTD_decode_uper; + per_type_encoder_f RoughRTD_encode_uper; #ifdef __cplusplus } #endif -#endif /* _RoughRTD_H_ */ +#endif /* _RoughRTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SVID.h b/src/core/libs/supl/asn-rrlp/SVID.h index 7cb51b7b3..288162594 100644 --- a/src/core/libs/supl/asn-rrlp/SVID.h +++ b/src/core/libs/supl/asn-rrlp/SVID.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SVID_H_ -#define _SVID_H_ +#ifndef _SVID_H_ +#define _SVID_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SVID */ -typedef long SVID_t; + /* SVID */ + typedef long SVID_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SVID; -asn_struct_free_f SVID_free; -asn_struct_print_f SVID_print; -asn_constr_check_f SVID_constraint; -ber_type_decoder_f SVID_decode_ber; -der_type_encoder_f SVID_encode_der; -xer_type_decoder_f SVID_decode_xer; -xer_type_encoder_f SVID_encode_xer; -per_type_decoder_f SVID_decode_uper; -per_type_encoder_f SVID_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SVID; + asn_struct_free_f SVID_free; + asn_struct_print_f SVID_print; + asn_constr_check_f SVID_constraint; + ber_type_decoder_f SVID_decode_ber; + der_type_encoder_f SVID_encode_der; + xer_type_decoder_f SVID_decode_xer; + xer_type_encoder_f SVID_encode_xer; + per_type_decoder_f SVID_decode_uper; + per_type_encoder_f SVID_encode_uper; #ifdef __cplusplus } #endif -#endif /* _SVID_H_ */ +#endif /* _SVID_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SVIDMASK.h b/src/core/libs/supl/asn-rrlp/SVIDMASK.h index 75c15933b..0e0e6414b 100644 --- a/src/core/libs/supl/asn-rrlp/SVIDMASK.h +++ b/src/core/libs/supl/asn-rrlp/SVIDMASK.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SVIDMASK_H_ -#define _SVIDMASK_H_ +#ifndef _SVIDMASK_H_ +#define _SVIDMASK_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SVIDMASK */ -typedef BIT_STRING_t SVIDMASK_t; + /* SVIDMASK */ + typedef BIT_STRING_t SVIDMASK_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SVIDMASK; -asn_struct_free_f SVIDMASK_free; -asn_struct_print_f SVIDMASK_print; -asn_constr_check_f SVIDMASK_constraint; -ber_type_decoder_f SVIDMASK_decode_ber; -der_type_encoder_f SVIDMASK_encode_der; -xer_type_decoder_f SVIDMASK_decode_xer; -xer_type_encoder_f SVIDMASK_encode_xer; -per_type_decoder_f SVIDMASK_decode_uper; -per_type_encoder_f SVIDMASK_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SVIDMASK; + asn_struct_free_f SVIDMASK_free; + asn_struct_print_f SVIDMASK_print; + asn_constr_check_f SVIDMASK_constraint; + ber_type_decoder_f SVIDMASK_decode_ber; + der_type_encoder_f SVIDMASK_encode_der; + xer_type_decoder_f SVIDMASK_decode_xer; + xer_type_encoder_f SVIDMASK_encode_xer; + per_type_decoder_f SVIDMASK_decode_uper; + per_type_encoder_f SVIDMASK_encode_uper; #ifdef __cplusplus } #endif -#endif /* _SVIDMASK_H_ */ +#endif /* _SVIDMASK_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SatElement.h b/src/core/libs/supl/asn-rrlp/SatElement.h index a312d6f4c..59bcd8888 100644 --- a/src/core/libs/supl/asn-rrlp/SatElement.h +++ b/src/core/libs/supl/asn-rrlp/SatElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SatElement_H_ -#define _SatElement_H_ +#ifndef _SatElement_H_ +#define _SatElement_H_ #include @@ -16,31 +16,33 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SatElement */ -typedef struct SatElement { - SatelliteID_t satelliteID; - long iode; - long udre; - long pseudoRangeCor; - long rangeRateCor; - long deltaPseudoRangeCor2; - long deltaRangeRateCor2; - long deltaPseudoRangeCor3; - long deltaRangeRateCor3; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SatElement_t; + /* SatElement */ + typedef struct SatElement + { + SatelliteID_t satelliteID; + long iode; + long udre; + long pseudoRangeCor; + long rangeRateCor; + long deltaPseudoRangeCor2; + long deltaRangeRateCor2; + long deltaPseudoRangeCor3; + long deltaRangeRateCor3; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SatElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SatElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SatElement; #ifdef __cplusplus } #endif -#endif /* _SatElement_H_ */ +#endif /* _SatElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SatStatus.h b/src/core/libs/supl/asn-rrlp/SatStatus.h index 889424d29..0673b5cd6 100644 --- a/src/core/libs/supl/asn-rrlp/SatStatus.h +++ b/src/core/libs/supl/asn-rrlp/SatStatus.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SatStatus_H_ -#define _SatStatus_H_ +#ifndef _SatStatus_H_ +#define _SatStatus_H_ #include @@ -16,42 +16,46 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SatStatus_PR { - SatStatus_PR_NOTHING, /* No components present */ - SatStatus_PR_newSatelliteAndModelUC, - SatStatus_PR_oldSatelliteAndModel, - SatStatus_PR_newNaviModelUC, - /* Extensions may appear below */ - -} SatStatus_PR; + /* Dependencies */ + typedef enum SatStatus_PR + { + SatStatus_PR_NOTHING, /* No components present */ + SatStatus_PR_newSatelliteAndModelUC, + SatStatus_PR_oldSatelliteAndModel, + SatStatus_PR_newNaviModelUC, + /* Extensions may appear below */ -/* SatStatus */ -typedef struct SatStatus { - SatStatus_PR present; - union SatStatus_u { - UncompressedEphemeris_t newSatelliteAndModelUC; - NULL_t oldSatelliteAndModel; - UncompressedEphemeris_t newNaviModelUC; - /* + } SatStatus_PR; + + /* SatStatus */ + typedef struct SatStatus + { + SatStatus_PR present; + union SatStatus_u + { + UncompressedEphemeris_t newSatelliteAndModelUC; + NULL_t oldSatelliteAndModel; + UncompressedEphemeris_t newNaviModelUC; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SatStatus_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SatStatus; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SatStatus_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SatStatus; #ifdef __cplusplus } #endif -#endif /* _SatStatus_H_ */ +#endif /* _SatStatus_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SatelliteID.h b/src/core/libs/supl/asn-rrlp/SatelliteID.h index 834eb70ad..df5d83a7f 100644 --- a/src/core/libs/supl/asn-rrlp/SatelliteID.h +++ b/src/core/libs/supl/asn-rrlp/SatelliteID.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SatelliteID_H_ -#define _SatelliteID_H_ +#ifndef _SatelliteID_H_ +#define _SatelliteID_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SatelliteID */ -typedef long SatelliteID_t; + /* SatelliteID */ + typedef long SatelliteID_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SatelliteID; -asn_struct_free_f SatelliteID_free; -asn_struct_print_f SatelliteID_print; -asn_constr_check_f SatelliteID_constraint; -ber_type_decoder_f SatelliteID_decode_ber; -der_type_encoder_f SatelliteID_encode_der; -xer_type_decoder_f SatelliteID_decode_xer; -xer_type_encoder_f SatelliteID_encode_xer; -per_type_decoder_f SatelliteID_decode_uper; -per_type_encoder_f SatelliteID_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SatelliteID; + asn_struct_free_f SatelliteID_free; + asn_struct_print_f SatelliteID_print; + asn_constr_check_f SatelliteID_constraint; + ber_type_decoder_f SatelliteID_decode_ber; + der_type_encoder_f SatelliteID_encode_der; + xer_type_decoder_f SatelliteID_decode_xer; + xer_type_encoder_f SatelliteID_encode_xer; + per_type_decoder_f SatelliteID_decode_uper; + per_type_encoder_f SatelliteID_encode_uper; #ifdef __cplusplus } #endif -#endif /* _SatelliteID_H_ */ +#endif /* _SatelliteID_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOf-BadSatelliteSet.h b/src/core/libs/supl/asn-rrlp/SeqOf-BadSatelliteSet.h index a258a3214..97c19943f 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOf-BadSatelliteSet.h +++ b/src/core/libs/supl/asn-rrlp/SeqOf-BadSatelliteSet.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOf_BadSatelliteSet_H_ -#define _SeqOf_BadSatelliteSet_H_ +#ifndef _SeqOf_BadSatelliteSet_H_ +#define _SeqOf_BadSatelliteSet_H_ #include @@ -16,23 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SeqOf-BadSatelliteSet */ -typedef struct SeqOf_BadSatelliteSet { - A_SEQUENCE_OF(SatelliteID_t) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOf_BadSatelliteSet_t; + /* SeqOf-BadSatelliteSet */ + typedef struct SeqOf_BadSatelliteSet + { + A_SEQUENCE_OF(SatelliteID_t) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOf_BadSatelliteSet; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOf_BadSatelliteSet_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOf_BadSatelliteSet; #ifdef __cplusplus } #endif -#endif /* _SeqOf_BadSatelliteSet_H_ */ +#endif /* _SeqOf_BadSatelliteSet_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOf-GANSSDataBits.h b/src/core/libs/supl/asn-rrlp/SeqOf-GANSSDataBits.h index a55a8e2de..87b7a5e48 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOf-GANSSDataBits.h +++ b/src/core/libs/supl/asn-rrlp/SeqOf-GANSSDataBits.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOf_GANSSDataBits_H_ -#define _SeqOf_GANSSDataBits_H_ +#ifndef _SeqOf_GANSSDataBits_H_ +#define _SeqOf_GANSSDataBits_H_ #include @@ -16,23 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SeqOf-GANSSDataBits */ -typedef struct SeqOf_GANSSDataBits { - A_SEQUENCE_OF(GANSSDataBit_t) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOf_GANSSDataBits_t; + /* SeqOf-GANSSDataBits */ + typedef struct SeqOf_GANSSDataBits + { + A_SEQUENCE_OF(GANSSDataBit_t) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOf_GANSSDataBits; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOf_GANSSDataBits_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOf_GANSSDataBits; #ifdef __cplusplus } #endif -#endif /* _SeqOf_GANSSDataBits_H_ */ +#endif /* _SeqOf_GANSSDataBits_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfAcquisElement.h b/src/core/libs/supl/asn-rrlp/SeqOfAcquisElement.h index ed7212889..4af9824af 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfAcquisElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfAcquisElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfAcquisElement_H_ -#define _SeqOfAcquisElement_H_ +#ifndef _SeqOfAcquisElement_H_ +#define _SeqOfAcquisElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct AcquisElement; + /* Forward declarations */ + struct AcquisElement; -/* SeqOfAcquisElement */ -typedef struct SeqOfAcquisElement { - A_SEQUENCE_OF(struct AcquisElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfAcquisElement_t; + /* SeqOfAcquisElement */ + typedef struct SeqOfAcquisElement + { + A_SEQUENCE_OF(struct AcquisElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfAcquisElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfAcquisElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfAcquisElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfAcquisElement; /* Referred external types */ #include "AcquisElement.h" -#endif /* _SeqOfAcquisElement_H_ */ +#endif /* _SeqOfAcquisElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfAlmanacElement.h b/src/core/libs/supl/asn-rrlp/SeqOfAlmanacElement.h index 1050eae30..91ada0e38 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfAlmanacElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfAlmanacElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfAlmanacElement_H_ -#define _SeqOfAlmanacElement_H_ +#ifndef _SeqOfAlmanacElement_H_ +#define _SeqOfAlmanacElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct AlmanacElement; + /* Forward declarations */ + struct AlmanacElement; -/* SeqOfAlmanacElement */ -typedef struct SeqOfAlmanacElement { - A_SEQUENCE_OF(struct AlmanacElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfAlmanacElement_t; + /* SeqOfAlmanacElement */ + typedef struct SeqOfAlmanacElement + { + A_SEQUENCE_OF(struct AlmanacElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfAlmanacElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfAlmanacElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfAlmanacElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfAlmanacElement; /* Referred external types */ #include "AlmanacElement.h" -#endif /* _SeqOfAlmanacElement_H_ */ +#endif /* _SeqOfAlmanacElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfBadSignalElement.h b/src/core/libs/supl/asn-rrlp/SeqOfBadSignalElement.h index 8de761fd2..a6dda3091 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfBadSignalElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfBadSignalElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfBadSignalElement_H_ -#define _SeqOfBadSignalElement_H_ +#ifndef _SeqOfBadSignalElement_H_ +#define _SeqOfBadSignalElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct BadSignalElement; + /* Forward declarations */ + struct BadSignalElement; -/* SeqOfBadSignalElement */ -typedef struct SeqOfBadSignalElement { - A_SEQUENCE_OF(struct BadSignalElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfBadSignalElement_t; + /* SeqOfBadSignalElement */ + typedef struct SeqOfBadSignalElement + { + A_SEQUENCE_OF(struct BadSignalElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfBadSignalElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfBadSignalElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfBadSignalElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfBadSignalElement; /* Referred external types */ #include "BadSignalElement.h" -#endif /* _SeqOfBadSignalElement_H_ */ +#endif /* _SeqOfBadSignalElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfDGANSSSgnElement.h b/src/core/libs/supl/asn-rrlp/SeqOfDGANSSSgnElement.h index 560c771d7..662a98a7d 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfDGANSSSgnElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfDGANSSSgnElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfDGANSSSgnElement_H_ -#define _SeqOfDGANSSSgnElement_H_ +#ifndef _SeqOfDGANSSSgnElement_H_ +#define _SeqOfDGANSSSgnElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct DGANSSSgnElement; + /* Forward declarations */ + struct DGANSSSgnElement; -/* SeqOfDGANSSSgnElement */ -typedef struct SeqOfDGANSSSgnElement { - A_SEQUENCE_OF(struct DGANSSSgnElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfDGANSSSgnElement_t; + /* SeqOfDGANSSSgnElement */ + typedef struct SeqOfDGANSSSgnElement + { + A_SEQUENCE_OF(struct DGANSSSgnElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfDGANSSSgnElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfDGANSSSgnElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfDGANSSSgnElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfDGANSSSgnElement; /* Referred external types */ #include "DGANSSSgnElement.h" -#endif /* _SeqOfDGANSSSgnElement_H_ */ +#endif /* _SeqOfDGANSSSgnElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-MsrSetElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-MsrSetElement.h index 2686188e9..dadd90007 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-MsrSetElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-MsrSetElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSS_MsrSetElement_H_ -#define _SeqOfGANSS_MsrSetElement_H_ +#ifndef _SeqOfGANSS_MsrSetElement_H_ +#define _SeqOfGANSS_MsrSetElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSS_MsrSetElement; + /* Forward declarations */ + struct GANSS_MsrSetElement; -/* SeqOfGANSS-MsrSetElement */ -typedef struct SeqOfGANSS_MsrSetElement { - A_SEQUENCE_OF(struct GANSS_MsrSetElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSS_MsrSetElement_t; + /* SeqOfGANSS-MsrSetElement */ + typedef struct SeqOfGANSS_MsrSetElement + { + A_SEQUENCE_OF(struct GANSS_MsrSetElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_MsrSetElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSS_MsrSetElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_MsrSetElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_MsrSetElement; /* Referred external types */ #include "GANSS-MsrSetElement.h" -#endif /* _SeqOfGANSS_MsrSetElement_H_ */ +#endif /* _SeqOfGANSS_MsrSetElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnElement.h index 0ba0c8388..b2bbcea2e 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSS_SgnElement_H_ -#define _SeqOfGANSS_SgnElement_H_ +#ifndef _SeqOfGANSS_SgnElement_H_ +#define _SeqOfGANSS_SgnElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSS_SgnElement; + /* Forward declarations */ + struct GANSS_SgnElement; -/* SeqOfGANSS-SgnElement */ -typedef struct SeqOfGANSS_SgnElement { - A_SEQUENCE_OF(struct GANSS_SgnElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSS_SgnElement_t; + /* SeqOfGANSS-SgnElement */ + typedef struct SeqOfGANSS_SgnElement + { + A_SEQUENCE_OF(struct GANSS_SgnElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSS_SgnElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnElement; /* Referred external types */ #include "GANSS-SgnElement.h" -#endif /* _SeqOfGANSS_SgnElement_H_ */ +#endif /* _SeqOfGANSS_SgnElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnTypeElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnTypeElement.h index 15c0a2516..1bc77858e 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnTypeElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSS-SgnTypeElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSS_SgnTypeElement_H_ -#define _SeqOfGANSS_SgnTypeElement_H_ +#ifndef _SeqOfGANSS_SgnTypeElement_H_ +#define _SeqOfGANSS_SgnTypeElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSS_SgnTypeElement; + /* Forward declarations */ + struct GANSS_SgnTypeElement; -/* SeqOfGANSS-SgnTypeElement */ -typedef struct SeqOfGANSS_SgnTypeElement { - A_SEQUENCE_OF(struct GANSS_SgnTypeElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSS_SgnTypeElement_t; + /* SeqOfGANSS-SgnTypeElement */ + typedef struct SeqOfGANSS_SgnTypeElement + { + A_SEQUENCE_OF(struct GANSS_SgnTypeElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnTypeElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSS_SgnTypeElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnTypeElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSS_SgnTypeElement; /* Referred external types */ #include "GANSS-SgnTypeElement.h" -#endif /* _SeqOfGANSS_SgnTypeElement_H_ */ +#endif /* _SeqOfGANSS_SgnTypeElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSSAlmanacElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSSAlmanacElement.h index a8e655568..84bcb452b 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSSAlmanacElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSSAlmanacElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSSAlmanacElement_H_ -#define _SeqOfGANSSAlmanacElement_H_ +#ifndef _SeqOfGANSSAlmanacElement_H_ +#define _SeqOfGANSSAlmanacElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSAlmanacElement; + /* Forward declarations */ + struct GANSSAlmanacElement; -/* SeqOfGANSSAlmanacElement */ -typedef struct SeqOfGANSSAlmanacElement { - A_SEQUENCE_OF(struct GANSSAlmanacElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSSAlmanacElement_t; + /* SeqOfGANSSAlmanacElement */ + typedef struct SeqOfGANSSAlmanacElement + { + A_SEQUENCE_OF(struct GANSSAlmanacElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSAlmanacElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSSAlmanacElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSAlmanacElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSAlmanacElement; /* Referred external types */ #include "GANSSAlmanacElement.h" -#endif /* _SeqOfGANSSAlmanacElement_H_ */ +#endif /* _SeqOfGANSSAlmanacElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSSGenericAssistDataElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSSGenericAssistDataElement.h index 62441ea78..e9a88f2df 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSSGenericAssistDataElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSSGenericAssistDataElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSSGenericAssistDataElement_H_ -#define _SeqOfGANSSGenericAssistDataElement_H_ +#ifndef _SeqOfGANSSGenericAssistDataElement_H_ +#define _SeqOfGANSSGenericAssistDataElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSGenericAssistDataElement; + /* Forward declarations */ + struct GANSSGenericAssistDataElement; -/* SeqOfGANSSGenericAssistDataElement */ -typedef struct SeqOfGANSSGenericAssistDataElement { - A_SEQUENCE_OF(struct GANSSGenericAssistDataElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSSGenericAssistDataElement_t; + /* SeqOfGANSSGenericAssistDataElement */ + typedef struct SeqOfGANSSGenericAssistDataElement + { + A_SEQUENCE_OF(struct GANSSGenericAssistDataElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSGenericAssistDataElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSSGenericAssistDataElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSGenericAssistDataElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSGenericAssistDataElement; /* Referred external types */ #include "GANSSGenericAssistDataElement.h" -#endif /* _SeqOfGANSSGenericAssistDataElement_H_ */ +#endif /* _SeqOfGANSSGenericAssistDataElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSSRefMeasurementElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSSRefMeasurementElement.h index 615f304ad..71ea6d8ac 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSSRefMeasurementElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSSRefMeasurementElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSSRefMeasurementElement_H_ -#define _SeqOfGANSSRefMeasurementElement_H_ +#ifndef _SeqOfGANSSRefMeasurementElement_H_ +#define _SeqOfGANSSRefMeasurementElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSRefMeasurementElement; + /* Forward declarations */ + struct GANSSRefMeasurementElement; -/* SeqOfGANSSRefMeasurementElement */ -typedef struct SeqOfGANSSRefMeasurementElement { - A_SEQUENCE_OF(struct GANSSRefMeasurementElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSSRefMeasurementElement_t; + /* SeqOfGANSSRefMeasurementElement */ + typedef struct SeqOfGANSSRefMeasurementElement + { + A_SEQUENCE_OF(struct GANSSRefMeasurementElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSRefMeasurementElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSSRefMeasurementElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSRefMeasurementElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSRefMeasurementElement; /* Referred external types */ #include "GANSSRefMeasurementElement.h" -#endif /* _SeqOfGANSSRefMeasurementElement_H_ */ +#endif /* _SeqOfGANSSRefMeasurementElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSSSatelliteElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSSSatelliteElement.h index adb5f6cf7..6f1ad918f 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSSSatelliteElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSSSatelliteElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSSSatelliteElement_H_ -#define _SeqOfGANSSSatelliteElement_H_ +#ifndef _SeqOfGANSSSatelliteElement_H_ +#define _SeqOfGANSSSatelliteElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSSatelliteElement; + /* Forward declarations */ + struct GANSSSatelliteElement; -/* SeqOfGANSSSatelliteElement */ -typedef struct SeqOfGANSSSatelliteElement { - A_SEQUENCE_OF(struct GANSSSatelliteElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSSSatelliteElement_t; + /* SeqOfGANSSSatelliteElement */ + typedef struct SeqOfGANSSSatelliteElement + { + A_SEQUENCE_OF(struct GANSSSatelliteElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSSatelliteElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSSSatelliteElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSSatelliteElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSSatelliteElement; /* Referred external types */ #include "GANSSSatelliteElement.h" -#endif /* _SeqOfGANSSSatelliteElement_H_ */ +#endif /* _SeqOfGANSSSatelliteElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGANSSTimeModel.h b/src/core/libs/supl/asn-rrlp/SeqOfGANSSTimeModel.h index 715157be2..69294282d 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGANSSTimeModel.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGANSSTimeModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGANSSTimeModel_H_ -#define _SeqOfGANSSTimeModel_H_ +#ifndef _SeqOfGANSSTimeModel_H_ +#define _SeqOfGANSSTimeModel_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GANSSTimeModelElement; + /* Forward declarations */ + struct GANSSTimeModelElement; -/* SeqOfGANSSTimeModel */ -typedef struct SeqOfGANSSTimeModel { - A_SEQUENCE_OF(struct GANSSTimeModelElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGANSSTimeModel_t; + /* SeqOfGANSSTimeModel */ + typedef struct SeqOfGANSSTimeModel + { + A_SEQUENCE_OF(struct GANSSTimeModelElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSTimeModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGANSSTimeModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSTimeModel; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGANSSTimeModel; /* Referred external types */ #include "GANSSTimeModelElement.h" -#endif /* _SeqOfGANSSTimeModel_H_ */ +#endif /* _SeqOfGANSSTimeModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrElement.h index 626ad95ae..6d8816f40 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGPS_MsrElement_H_ -#define _SeqOfGPS_MsrElement_H_ +#ifndef _SeqOfGPS_MsrElement_H_ +#define _SeqOfGPS_MsrElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GPS_MsrElement; + /* Forward declarations */ + struct GPS_MsrElement; -/* SeqOfGPS-MsrElement */ -typedef struct SeqOfGPS_MsrElement { - A_SEQUENCE_OF(struct GPS_MsrElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGPS_MsrElement_t; + /* SeqOfGPS-MsrElement */ + typedef struct SeqOfGPS_MsrElement + { + A_SEQUENCE_OF(struct GPS_MsrElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGPS_MsrElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrElement; /* Referred external types */ #include "GPS-MsrElement.h" -#endif /* _SeqOfGPS_MsrElement_H_ */ +#endif /* _SeqOfGPS_MsrElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrSetElement.h b/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrSetElement.h index c8ae1a982..6a7cf5cb1 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrSetElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfGPS-MsrSetElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfGPS_MsrSetElement_H_ -#define _SeqOfGPS_MsrSetElement_H_ +#ifndef _SeqOfGPS_MsrSetElement_H_ +#define _SeqOfGPS_MsrSetElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GPS_MsrSetElement; + /* Forward declarations */ + struct GPS_MsrSetElement; -/* SeqOfGPS-MsrSetElement */ -typedef struct SeqOfGPS_MsrSetElement { - A_SEQUENCE_OF(struct GPS_MsrSetElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfGPS_MsrSetElement_t; + /* SeqOfGPS-MsrSetElement */ + typedef struct SeqOfGPS_MsrSetElement + { + A_SEQUENCE_OF(struct GPS_MsrSetElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrSetElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfGPS_MsrSetElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrSetElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfGPS_MsrSetElement; /* Referred external types */ #include "GPS-MsrSetElement.h" -#endif /* _SeqOfGPS_MsrSetElement_H_ */ +#endif /* _SeqOfGPS_MsrSetElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS-R98-ExpOTD.h index 752ce2934..eda30a58d 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfMsrAssistBTS_R98_ExpOTD_H_ -#define _SeqOfMsrAssistBTS_R98_ExpOTD_H_ +#ifndef _SeqOfMsrAssistBTS_R98_ExpOTD_H_ +#define _SeqOfMsrAssistBTS_R98_ExpOTD_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct MsrAssistBTS_R98_ExpOTD; + /* Forward declarations */ + struct MsrAssistBTS_R98_ExpOTD; -/* SeqOfMsrAssistBTS-R98-ExpOTD */ -typedef struct SeqOfMsrAssistBTS_R98_ExpOTD { - A_SEQUENCE_OF(struct MsrAssistBTS_R98_ExpOTD) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfMsrAssistBTS_R98_ExpOTD_t; + /* SeqOfMsrAssistBTS-R98-ExpOTD */ + typedef struct SeqOfMsrAssistBTS_R98_ExpOTD + { + A_SEQUENCE_OF(struct MsrAssistBTS_R98_ExpOTD) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfMsrAssistBTS_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS_R98_ExpOTD; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS_R98_ExpOTD; /* Referred external types */ #include "MsrAssistBTS-R98-ExpOTD.h" -#endif /* _SeqOfMsrAssistBTS_R98_ExpOTD_H_ */ +#endif /* _SeqOfMsrAssistBTS_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS.h b/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS.h index 03c0af381..6a335b660 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfMsrAssistBTS.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfMsrAssistBTS_H_ -#define _SeqOfMsrAssistBTS_H_ +#ifndef _SeqOfMsrAssistBTS_H_ +#define _SeqOfMsrAssistBTS_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct MsrAssistBTS; + /* Forward declarations */ + struct MsrAssistBTS; -/* SeqOfMsrAssistBTS */ -typedef struct SeqOfMsrAssistBTS { - A_SEQUENCE_OF(struct MsrAssistBTS) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfMsrAssistBTS_t; + /* SeqOfMsrAssistBTS */ + typedef struct SeqOfMsrAssistBTS + { + A_SEQUENCE_OF(struct MsrAssistBTS) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfMsrAssistBTS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfMsrAssistBTS; /* Referred external types */ #include "MsrAssistBTS.h" -#endif /* _SeqOfMsrAssistBTS_H_ */ +#endif /* _SeqOfMsrAssistBTS_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfNavModelElement.h b/src/core/libs/supl/asn-rrlp/SeqOfNavModelElement.h index aa49a6357..65c7c1707 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfNavModelElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfNavModelElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfNavModelElement_H_ -#define _SeqOfNavModelElement_H_ +#ifndef _SeqOfNavModelElement_H_ +#define _SeqOfNavModelElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct NavModelElement; + /* Forward declarations */ + struct NavModelElement; -/* SeqOfNavModelElement */ -typedef struct SeqOfNavModelElement { - A_SEQUENCE_OF(struct NavModelElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfNavModelElement_t; + /* SeqOfNavModelElement */ + typedef struct SeqOfNavModelElement + { + A_SEQUENCE_OF(struct NavModelElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfNavModelElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfNavModelElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfNavModelElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfNavModelElement; /* Referred external types */ #include "NavModelElement.h" -#endif /* _SeqOfNavModelElement_H_ */ +#endif /* _SeqOfNavModelElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs-R98-Ext.h b/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs-R98-Ext.h index e193afc3c..5b22e1e2a 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs-R98-Ext.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs-R98-Ext.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ -#define _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ +#ifndef _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ +#define _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct OTD_MeasurementWithID; + /* Forward declarations */ + struct OTD_MeasurementWithID; -/* SeqOfOTD-FirstSetMsrs-R98-Ext */ -typedef struct SeqOfOTD_FirstSetMsrs_R98_Ext { - A_SEQUENCE_OF(struct OTD_MeasurementWithID) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfOTD_FirstSetMsrs_R98_Ext_t; + /* SeqOfOTD-FirstSetMsrs-R98-Ext */ + typedef struct SeqOfOTD_FirstSetMsrs_R98_Ext + { + A_SEQUENCE_OF(struct OTD_MeasurementWithID) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs_R98_Ext; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfOTD_FirstSetMsrs_R98_Ext_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs_R98_Ext; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs_R98_Ext; /* Referred external types */ #include "OTD-FirstSetMsrs.h" -#endif /* _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ */ +#endif /* _SeqOfOTD_FirstSetMsrs_R98_Ext_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs.h b/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs.h index 9d3390037..064613c99 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfOTD-FirstSetMsrs.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfOTD_FirstSetMsrs_H_ -#define _SeqOfOTD_FirstSetMsrs_H_ +#ifndef _SeqOfOTD_FirstSetMsrs_H_ +#define _SeqOfOTD_FirstSetMsrs_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct OTD_MeasurementWithID; + /* Forward declarations */ + struct OTD_MeasurementWithID; -/* SeqOfOTD-FirstSetMsrs */ -typedef struct SeqOfOTD_FirstSetMsrs { - A_SEQUENCE_OF(struct OTD_MeasurementWithID) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfOTD_FirstSetMsrs_t; + /* SeqOfOTD-FirstSetMsrs */ + typedef struct SeqOfOTD_FirstSetMsrs + { + A_SEQUENCE_OF(struct OTD_MeasurementWithID) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfOTD_FirstSetMsrs_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_FirstSetMsrs; /* Referred external types */ #include "OTD-FirstSetMsrs.h" -#endif /* _SeqOfOTD_FirstSetMsrs_H_ */ +#endif /* _SeqOfOTD_FirstSetMsrs_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrElementRest.h b/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrElementRest.h index d92408eb8..1fcd622d9 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrElementRest.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrElementRest.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfOTD_MsrElementRest_H_ -#define _SeqOfOTD_MsrElementRest_H_ +#ifndef _SeqOfOTD_MsrElementRest_H_ +#define _SeqOfOTD_MsrElementRest_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct OTD_MsrElementRest; + /* Forward declarations */ + struct OTD_MsrElementRest; -/* SeqOfOTD-MsrElementRest */ -typedef struct SeqOfOTD_MsrElementRest { - A_SEQUENCE_OF(struct OTD_MsrElementRest) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfOTD_MsrElementRest_t; + /* SeqOfOTD-MsrElementRest */ + typedef struct SeqOfOTD_MsrElementRest + { + A_SEQUENCE_OF(struct OTD_MsrElementRest) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrElementRest; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfOTD_MsrElementRest_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrElementRest; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrElementRest; /* Referred external types */ #include "OTD-MsrElementRest.h" -#endif /* _SeqOfOTD_MsrElementRest_H_ */ +#endif /* _SeqOfOTD_MsrElementRest_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrsOfOtherSets.h b/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrsOfOtherSets.h index 21324431d..d07504607 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrsOfOtherSets.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfOTD-MsrsOfOtherSets.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfOTD_MsrsOfOtherSets_H_ -#define _SeqOfOTD_MsrsOfOtherSets_H_ +#ifndef _SeqOfOTD_MsrsOfOtherSets_H_ +#define _SeqOfOTD_MsrsOfOtherSets_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct OTD_MsrsOfOtherSets; + /* Forward declarations */ + struct OTD_MsrsOfOtherSets; -/* SeqOfOTD-MsrsOfOtherSets */ -typedef struct SeqOfOTD_MsrsOfOtherSets { - A_SEQUENCE_OF(struct OTD_MsrsOfOtherSets) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfOTD_MsrsOfOtherSets_t; + /* SeqOfOTD-MsrsOfOtherSets */ + typedef struct SeqOfOTD_MsrsOfOtherSets + { + A_SEQUENCE_OF(struct OTD_MsrsOfOtherSets) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrsOfOtherSets; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfOTD_MsrsOfOtherSets_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrsOfOtherSets; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfOTD_MsrsOfOtherSets; /* Referred external types */ #include "OTD-MsrsOfOtherSets.h" -#endif /* _SeqOfOTD_MsrsOfOtherSets_H_ */ +#endif /* _SeqOfOTD_MsrsOfOtherSets_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfReferenceIdentityType.h b/src/core/libs/supl/asn-rrlp/SeqOfReferenceIdentityType.h index f7b890090..f5a3c0403 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfReferenceIdentityType.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfReferenceIdentityType.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfReferenceIdentityType_H_ -#define _SeqOfReferenceIdentityType_H_ +#ifndef _SeqOfReferenceIdentityType_H_ +#define _SeqOfReferenceIdentityType_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct ReferenceIdentityType; + /* Forward declarations */ + struct ReferenceIdentityType; -/* SeqOfReferenceIdentityType */ -typedef struct SeqOfReferenceIdentityType { - A_SEQUENCE_OF(struct ReferenceIdentityType) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfReferenceIdentityType_t; + /* SeqOfReferenceIdentityType */ + typedef struct SeqOfReferenceIdentityType + { + A_SEQUENCE_OF(struct ReferenceIdentityType) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfReferenceIdentityType; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfReferenceIdentityType_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfReferenceIdentityType; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfReferenceIdentityType; /* Referred external types */ #include "ReferenceIdentityType.h" -#endif /* _SeqOfReferenceIdentityType_H_ */ +#endif /* _SeqOfReferenceIdentityType_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfSatElement.h b/src/core/libs/supl/asn-rrlp/SeqOfSatElement.h index 16b8282f9..096382c3e 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfSatElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfSatElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfSatElement_H_ -#define _SeqOfSatElement_H_ +#ifndef _SeqOfSatElement_H_ +#define _SeqOfSatElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SatElement; + /* Forward declarations */ + struct SatElement; -/* SeqOfSatElement */ -typedef struct SeqOfSatElement { - A_SEQUENCE_OF(struct SatElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfSatElement_t; + /* SeqOfSatElement */ + typedef struct SeqOfSatElement + { + A_SEQUENCE_OF(struct SatElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfSatElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfSatElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfSatElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfSatElement; /* Referred external types */ #include "SatElement.h" -#endif /* _SeqOfSatElement_H_ */ +#endif /* _SeqOfSatElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfSgnTypeElement.h b/src/core/libs/supl/asn-rrlp/SeqOfSgnTypeElement.h index 2af754902..d106c9c18 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfSgnTypeElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfSgnTypeElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfSgnTypeElement_H_ -#define _SeqOfSgnTypeElement_H_ +#ifndef _SeqOfSgnTypeElement_H_ +#define _SeqOfSgnTypeElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SgnTypeElement; + /* Forward declarations */ + struct SgnTypeElement; -/* SeqOfSgnTypeElement */ -typedef struct SeqOfSgnTypeElement { - A_SEQUENCE_OF(struct SgnTypeElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfSgnTypeElement_t; + /* SeqOfSgnTypeElement */ + typedef struct SeqOfSgnTypeElement + { + A_SEQUENCE_OF(struct SgnTypeElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfSgnTypeElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfSgnTypeElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfSgnTypeElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfSgnTypeElement; /* Referred external types */ #include "SgnTypeElement.h" -#endif /* _SeqOfSgnTypeElement_H_ */ +#endif /* _SeqOfSgnTypeElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfStandardClockModelElement.h b/src/core/libs/supl/asn-rrlp/SeqOfStandardClockModelElement.h index 9f5c0d239..13b193f5f 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfStandardClockModelElement.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfStandardClockModelElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfStandardClockModelElement_H_ -#define _SeqOfStandardClockModelElement_H_ +#ifndef _SeqOfStandardClockModelElement_H_ +#define _SeqOfStandardClockModelElement_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct StandardClockModelElement; + /* Forward declarations */ + struct StandardClockModelElement; -/* SeqOfStandardClockModelElement */ -typedef struct SeqOfStandardClockModelElement { - A_SEQUENCE_OF(struct StandardClockModelElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfStandardClockModelElement_t; + /* SeqOfStandardClockModelElement */ + typedef struct SeqOfStandardClockModelElement + { + A_SEQUENCE_OF(struct StandardClockModelElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfStandardClockModelElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfStandardClockModelElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfStandardClockModelElement; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfStandardClockModelElement; /* Referred external types */ #include "StandardClockModelElement.h" -#endif /* _SeqOfStandardClockModelElement_H_ */ +#endif /* _SeqOfStandardClockModelElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS-R98-ExpOTD.h index 8dffd5e0f..20aca403e 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ -#define _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ +#ifndef _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ +#define _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SystemInfoAssistBTS_R98_ExpOTD; + /* Forward declarations */ + struct SystemInfoAssistBTS_R98_ExpOTD; -/* SeqOfSystemInfoAssistBTS-R98-ExpOTD */ -typedef struct SeqOfSystemInfoAssistBTS_R98_ExpOTD { - A_SEQUENCE_OF(struct SystemInfoAssistBTS_R98_ExpOTD) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfSystemInfoAssistBTS_R98_ExpOTD_t; + /* SeqOfSystemInfoAssistBTS-R98-ExpOTD */ + typedef struct SeqOfSystemInfoAssistBTS_R98_ExpOTD + { + A_SEQUENCE_OF(struct SystemInfoAssistBTS_R98_ExpOTD) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfSystemInfoAssistBTS_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS_R98_ExpOTD; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS_R98_ExpOTD; /* Referred external types */ #include "SystemInfoAssistBTS-R98-ExpOTD.h" -#endif /* _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ */ +#endif /* _SeqOfSystemInfoAssistBTS_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS.h b/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS.h index faebb465f..8ab68ffb6 100644 --- a/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS.h +++ b/src/core/libs/supl/asn-rrlp/SeqOfSystemInfoAssistBTS.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SeqOfSystemInfoAssistBTS_H_ -#define _SeqOfSystemInfoAssistBTS_H_ +#ifndef _SeqOfSystemInfoAssistBTS_H_ +#define _SeqOfSystemInfoAssistBTS_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SystemInfoAssistBTS; + /* Forward declarations */ + struct SystemInfoAssistBTS; -/* SeqOfSystemInfoAssistBTS */ -typedef struct SeqOfSystemInfoAssistBTS { - A_SEQUENCE_OF(struct SystemInfoAssistBTS) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SeqOfSystemInfoAssistBTS_t; + /* SeqOfSystemInfoAssistBTS */ + typedef struct SeqOfSystemInfoAssistBTS + { + A_SEQUENCE_OF(struct SystemInfoAssistBTS) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SeqOfSystemInfoAssistBTS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SeqOfSystemInfoAssistBTS; /* Referred external types */ #include "SystemInfoAssistBTS.h" -#endif /* _SeqOfSystemInfoAssistBTS_H_ */ +#endif /* _SeqOfSystemInfoAssistBTS_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SgnTypeElement.h b/src/core/libs/supl/asn-rrlp/SgnTypeElement.h index 35ebe62ca..968ee88ef 100644 --- a/src/core/libs/supl/asn-rrlp/SgnTypeElement.h +++ b/src/core/libs/supl/asn-rrlp/SgnTypeElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SgnTypeElement_H_ -#define _SgnTypeElement_H_ +#ifndef _SgnTypeElement_H_ +#define _SgnTypeElement_H_ #include @@ -17,25 +17,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SgnTypeElement */ -typedef struct SgnTypeElement { - GANSSSignalID_t *ganssSignalID /* OPTIONAL */; - long ganssStatusHealth; - SeqOfDGANSSSgnElement_t dganssSgnList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SgnTypeElement_t; + /* SgnTypeElement */ + typedef struct SgnTypeElement + { + GANSSSignalID_t *ganssSignalID /* OPTIONAL */; + long ganssStatusHealth; + SeqOfDGANSSSgnElement_t dganssSgnList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SgnTypeElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SgnTypeElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SgnTypeElement; #ifdef __cplusplus } #endif -#endif /* _SgnTypeElement_H_ */ +#endif /* _SgnTypeElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/StandardClockModelElement.h b/src/core/libs/supl/asn-rrlp/StandardClockModelElement.h index 7fe79afb8..72651dcbd 100644 --- a/src/core/libs/supl/asn-rrlp/StandardClockModelElement.h +++ b/src/core/libs/supl/asn-rrlp/StandardClockModelElement.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _StandardClockModelElement_H_ -#define _StandardClockModelElement_H_ +#ifndef _StandardClockModelElement_H_ +#define _StandardClockModelElement_H_ #include @@ -15,32 +15,34 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* StandardClockModelElement */ -typedef struct StandardClockModelElement { - long stanClockTocLSB; - long stanClockAF2; - long stanClockAF1; - long stanClockAF0; - long *stanClockTgd /* OPTIONAL */; - long *stanModelID /* OPTIONAL */; - /* + /* StandardClockModelElement */ + typedef struct StandardClockModelElement + { + long stanClockTocLSB; + long stanClockAF2; + long stanClockAF1; + long stanClockAF0; + long *stanClockTgd /* OPTIONAL */; + long *stanModelID /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} StandardClockModelElement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_StandardClockModelElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } StandardClockModelElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_StandardClockModelElement; #ifdef __cplusplus } #endif -#endif /* _StandardClockModelElement_H_ */ +#endif /* _StandardClockModelElement_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/StdResolution.h b/src/core/libs/supl/asn-rrlp/StdResolution.h index 289d227b8..f93fd309d 100644 --- a/src/core/libs/supl/asn-rrlp/StdResolution.h +++ b/src/core/libs/supl/asn-rrlp/StdResolution.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _StdResolution_H_ -#define _StdResolution_H_ +#ifndef _StdResolution_H_ +#define _StdResolution_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* StdResolution */ -typedef long StdResolution_t; + /* StdResolution */ + typedef long StdResolution_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_StdResolution; -asn_struct_free_f StdResolution_free; -asn_struct_print_f StdResolution_print; -asn_constr_check_f StdResolution_constraint; -ber_type_decoder_f StdResolution_decode_ber; -der_type_encoder_f StdResolution_encode_der; -xer_type_decoder_f StdResolution_decode_xer; -xer_type_encoder_f StdResolution_encode_xer; -per_type_decoder_f StdResolution_decode_uper; -per_type_encoder_f StdResolution_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_StdResolution; + asn_struct_free_f StdResolution_free; + asn_struct_print_f StdResolution_print; + asn_constr_check_f StdResolution_constraint; + ber_type_decoder_f StdResolution_decode_ber; + der_type_encoder_f StdResolution_encode_der; + xer_type_decoder_f StdResolution_decode_xer; + xer_type_encoder_f StdResolution_encode_xer; + per_type_decoder_f StdResolution_decode_uper; + per_type_encoder_f StdResolution_encode_uper; #ifdef __cplusplus } #endif -#endif /* _StdResolution_H_ */ +#endif /* _StdResolution_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS-R98-ExpOTD.h index 78c025886..99d17a4e1 100644 --- a/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SystemInfoAssistBTS_R98_ExpOTD_H_ -#define _SystemInfoAssistBTS_R98_ExpOTD_H_ +#ifndef _SystemInfoAssistBTS_R98_ExpOTD_H_ +#define _SystemInfoAssistBTS_R98_ExpOTD_H_ #include @@ -16,34 +16,38 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SystemInfoAssistBTS_R98_ExpOTD_PR { - SystemInfoAssistBTS_R98_ExpOTD_PR_NOTHING, /* No components present */ - SystemInfoAssistBTS_R98_ExpOTD_PR_notPresent, - SystemInfoAssistBTS_R98_ExpOTD_PR_present -} SystemInfoAssistBTS_R98_ExpOTD_PR; + /* Dependencies */ + typedef enum SystemInfoAssistBTS_R98_ExpOTD_PR + { + SystemInfoAssistBTS_R98_ExpOTD_PR_NOTHING, /* No components present */ + SystemInfoAssistBTS_R98_ExpOTD_PR_notPresent, + SystemInfoAssistBTS_R98_ExpOTD_PR_present + } SystemInfoAssistBTS_R98_ExpOTD_PR; -/* SystemInfoAssistBTS-R98-ExpOTD */ -typedef struct SystemInfoAssistBTS_R98_ExpOTD { - SystemInfoAssistBTS_R98_ExpOTD_PR present; - union SystemInfoAssistBTS_R98_ExpOTD_u { - NULL_t notPresent; - AssistBTSData_R98_ExpOTD_t present; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SystemInfoAssistBTS_R98_ExpOTD_t; + /* SystemInfoAssistBTS-R98-ExpOTD */ + typedef struct SystemInfoAssistBTS_R98_ExpOTD + { + SystemInfoAssistBTS_R98_ExpOTD_PR present; + union SystemInfoAssistBTS_R98_ExpOTD_u + { + NULL_t notPresent; + AssistBTSData_R98_ExpOTD_t present; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistBTS_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SystemInfoAssistBTS_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistBTS_R98_ExpOTD; #ifdef __cplusplus } #endif -#endif /* _SystemInfoAssistBTS_R98_ExpOTD_H_ */ +#endif /* _SystemInfoAssistBTS_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS.h b/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS.h index daa8c9997..1c3012b02 100644 --- a/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS.h +++ b/src/core/libs/supl/asn-rrlp/SystemInfoAssistBTS.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SystemInfoAssistBTS_H_ -#define _SystemInfoAssistBTS_H_ +#ifndef _SystemInfoAssistBTS_H_ +#define _SystemInfoAssistBTS_H_ #include @@ -16,34 +16,38 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SystemInfoAssistBTS_PR { - SystemInfoAssistBTS_PR_NOTHING, /* No components present */ - SystemInfoAssistBTS_PR_notPresent, - SystemInfoAssistBTS_PR_present -} SystemInfoAssistBTS_PR; + /* Dependencies */ + typedef enum SystemInfoAssistBTS_PR + { + SystemInfoAssistBTS_PR_NOTHING, /* No components present */ + SystemInfoAssistBTS_PR_notPresent, + SystemInfoAssistBTS_PR_present + } SystemInfoAssistBTS_PR; -/* SystemInfoAssistBTS */ -typedef struct SystemInfoAssistBTS { - SystemInfoAssistBTS_PR present; - union SystemInfoAssistBTS_u { - NULL_t notPresent; - AssistBTSData_t present; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SystemInfoAssistBTS_t; + /* SystemInfoAssistBTS */ + typedef struct SystemInfoAssistBTS + { + SystemInfoAssistBTS_PR present; + union SystemInfoAssistBTS_u + { + NULL_t notPresent; + AssistBTSData_t present; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistBTS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SystemInfoAssistBTS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistBTS; #ifdef __cplusplus } #endif -#endif /* _SystemInfoAssistBTS_H_ */ +#endif /* _SystemInfoAssistBTS_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SystemInfoAssistData-R98-ExpOTD.h b/src/core/libs/supl/asn-rrlp/SystemInfoAssistData-R98-ExpOTD.h index a5961648f..8cf3628a4 100644 --- a/src/core/libs/supl/asn-rrlp/SystemInfoAssistData-R98-ExpOTD.h +++ b/src/core/libs/supl/asn-rrlp/SystemInfoAssistData-R98-ExpOTD.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SystemInfoAssistData_R98_ExpOTD_H_ -#define _SystemInfoAssistData_R98_ExpOTD_H_ +#ifndef _SystemInfoAssistData_R98_ExpOTD_H_ +#define _SystemInfoAssistData_R98_ExpOTD_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SystemInfoAssistData-R98-ExpOTD */ -typedef struct SystemInfoAssistData_R98_ExpOTD { - SeqOfSystemInfoAssistBTS_R98_ExpOTD_t systemInfoAssistListR98_ExpOTD; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SystemInfoAssistData_R98_ExpOTD_t; + /* SystemInfoAssistData-R98-ExpOTD */ + typedef struct SystemInfoAssistData_R98_ExpOTD + { + SeqOfSystemInfoAssistBTS_R98_ExpOTD_t systemInfoAssistListR98_ExpOTD; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistData_R98_ExpOTD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SystemInfoAssistData_R98_ExpOTD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistData_R98_ExpOTD; #ifdef __cplusplus } #endif -#endif /* _SystemInfoAssistData_R98_ExpOTD_H_ */ +#endif /* _SystemInfoAssistData_R98_ExpOTD_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SystemInfoAssistData.h b/src/core/libs/supl/asn-rrlp/SystemInfoAssistData.h index ddc134341..ef8051bb8 100644 --- a/src/core/libs/supl/asn-rrlp/SystemInfoAssistData.h +++ b/src/core/libs/supl/asn-rrlp/SystemInfoAssistData.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SystemInfoAssistData_H_ -#define _SystemInfoAssistData_H_ +#ifndef _SystemInfoAssistData_H_ +#define _SystemInfoAssistData_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SystemInfoAssistData */ -typedef struct SystemInfoAssistData { - SeqOfSystemInfoAssistBTS_t systemInfoAssistList; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SystemInfoAssistData_t; + /* SystemInfoAssistData */ + typedef struct SystemInfoAssistData + { + SeqOfSystemInfoAssistBTS_t systemInfoAssistList; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SystemInfoAssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SystemInfoAssistData; #ifdef __cplusplus } #endif -#endif /* _SystemInfoAssistData_H_ */ +#endif /* _SystemInfoAssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/SystemInfoIndex.h b/src/core/libs/supl/asn-rrlp/SystemInfoIndex.h index 3e5c4a217..3be83da8e 100644 --- a/src/core/libs/supl/asn-rrlp/SystemInfoIndex.h +++ b/src/core/libs/supl/asn-rrlp/SystemInfoIndex.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _SystemInfoIndex_H_ -#define _SystemInfoIndex_H_ +#ifndef _SystemInfoIndex_H_ +#define _SystemInfoIndex_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SystemInfoIndex */ -typedef long SystemInfoIndex_t; + /* SystemInfoIndex */ + typedef long SystemInfoIndex_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SystemInfoIndex; -asn_struct_free_f SystemInfoIndex_free; -asn_struct_print_f SystemInfoIndex_print; -asn_constr_check_f SystemInfoIndex_constraint; -ber_type_decoder_f SystemInfoIndex_decode_ber; -der_type_encoder_f SystemInfoIndex_encode_der; -xer_type_decoder_f SystemInfoIndex_decode_xer; -xer_type_encoder_f SystemInfoIndex_encode_xer; -per_type_decoder_f SystemInfoIndex_decode_uper; -per_type_encoder_f SystemInfoIndex_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SystemInfoIndex; + asn_struct_free_f SystemInfoIndex_free; + asn_struct_print_f SystemInfoIndex_print; + asn_constr_check_f SystemInfoIndex_constraint; + ber_type_decoder_f SystemInfoIndex_decode_ber; + der_type_encoder_f SystemInfoIndex_encode_der; + xer_type_decoder_f SystemInfoIndex_decode_xer; + xer_type_encoder_f SystemInfoIndex_encode_xer; + per_type_decoder_f SystemInfoIndex_decode_uper; + per_type_encoder_f SystemInfoIndex_encode_uper; #ifdef __cplusplus } #endif -#endif /* _SystemInfoIndex_H_ */ +#endif /* _SystemInfoIndex_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TA0.h b/src/core/libs/supl/asn-rrlp/TA0.h index a046041a9..69c7a4e3e 100644 --- a/src/core/libs/supl/asn-rrlp/TA0.h +++ b/src/core/libs/supl/asn-rrlp/TA0.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TA0_H_ -#define _TA0_H_ +#ifndef _TA0_H_ +#define _TA0_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TA0 */ -typedef long TA0_t; + /* TA0 */ + typedef long TA0_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TA0; -asn_struct_free_f TA0_free; -asn_struct_print_f TA0_print; -asn_constr_check_f TA0_constraint; -ber_type_decoder_f TA0_decode_ber; -der_type_encoder_f TA0_encode_der; -xer_type_decoder_f TA0_decode_xer; -xer_type_encoder_f TA0_encode_xer; -per_type_decoder_f TA0_decode_uper; -per_type_encoder_f TA0_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TA0; + asn_struct_free_f TA0_free; + asn_struct_print_f TA0_print; + asn_constr_check_f TA0_constraint; + ber_type_decoder_f TA0_decode_ber; + der_type_encoder_f TA0_encode_der; + xer_type_decoder_f TA0_decode_xer; + xer_type_encoder_f TA0_encode_xer; + per_type_decoder_f TA0_decode_uper; + per_type_encoder_f TA0_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TA0_H_ */ +#endif /* _TA0_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TA1.h b/src/core/libs/supl/asn-rrlp/TA1.h index e5b12b196..7ea57155e 100644 --- a/src/core/libs/supl/asn-rrlp/TA1.h +++ b/src/core/libs/supl/asn-rrlp/TA1.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TA1_H_ -#define _TA1_H_ +#ifndef _TA1_H_ +#define _TA1_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TA1 */ -typedef long TA1_t; + /* TA1 */ + typedef long TA1_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TA1; -asn_struct_free_f TA1_free; -asn_struct_print_f TA1_print; -asn_constr_check_f TA1_constraint; -ber_type_decoder_f TA1_decode_ber; -der_type_encoder_f TA1_encode_der; -xer_type_decoder_f TA1_decode_xer; -xer_type_encoder_f TA1_encode_xer; -per_type_decoder_f TA1_decode_uper; -per_type_encoder_f TA1_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TA1; + asn_struct_free_f TA1_free; + asn_struct_print_f TA1_print; + asn_constr_check_f TA1_constraint; + ber_type_decoder_f TA1_decode_ber; + der_type_encoder_f TA1_encode_der; + xer_type_decoder_f TA1_decode_xer; + xer_type_encoder_f TA1_encode_xer; + per_type_decoder_f TA1_decode_uper; + per_type_encoder_f TA1_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TA1_H_ */ +#endif /* _TA1_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TA2.h b/src/core/libs/supl/asn-rrlp/TA2.h index b13073c8c..78ec5b528 100644 --- a/src/core/libs/supl/asn-rrlp/TA2.h +++ b/src/core/libs/supl/asn-rrlp/TA2.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TA2_H_ -#define _TA2_H_ +#ifndef _TA2_H_ +#define _TA2_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TA2 */ -typedef long TA2_t; + /* TA2 */ + typedef long TA2_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TA2; -asn_struct_free_f TA2_free; -asn_struct_print_f TA2_print; -asn_constr_check_f TA2_constraint; -ber_type_decoder_f TA2_decode_ber; -der_type_encoder_f TA2_encode_der; -xer_type_decoder_f TA2_decode_xer; -xer_type_encoder_f TA2_encode_xer; -per_type_decoder_f TA2_decode_uper; -per_type_encoder_f TA2_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TA2; + asn_struct_free_f TA2_free; + asn_struct_print_f TA2_print; + asn_constr_check_f TA2_constraint; + ber_type_decoder_f TA2_decode_ber; + der_type_encoder_f TA2_encode_der; + xer_type_decoder_f TA2_decode_xer; + xer_type_encoder_f TA2_encode_xer; + per_type_decoder_f TA2_decode_uper; + per_type_encoder_f TA2_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TA2_H_ */ +#endif /* _TA2_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TLMReservedBits.h b/src/core/libs/supl/asn-rrlp/TLMReservedBits.h index 2e64f6af0..ee52c807b 100644 --- a/src/core/libs/supl/asn-rrlp/TLMReservedBits.h +++ b/src/core/libs/supl/asn-rrlp/TLMReservedBits.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TLMReservedBits_H_ -#define _TLMReservedBits_H_ +#ifndef _TLMReservedBits_H_ +#define _TLMReservedBits_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TLMReservedBits */ -typedef long TLMReservedBits_t; + /* TLMReservedBits */ + typedef long TLMReservedBits_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TLMReservedBits; -asn_struct_free_f TLMReservedBits_free; -asn_struct_print_f TLMReservedBits_print; -asn_constr_check_f TLMReservedBits_constraint; -ber_type_decoder_f TLMReservedBits_decode_ber; -der_type_encoder_f TLMReservedBits_encode_der; -xer_type_decoder_f TLMReservedBits_decode_xer; -xer_type_encoder_f TLMReservedBits_encode_xer; -per_type_decoder_f TLMReservedBits_decode_uper; -per_type_encoder_f TLMReservedBits_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TLMReservedBits; + asn_struct_free_f TLMReservedBits_free; + asn_struct_print_f TLMReservedBits_print; + asn_constr_check_f TLMReservedBits_constraint; + ber_type_decoder_f TLMReservedBits_decode_ber; + der_type_encoder_f TLMReservedBits_encode_der; + xer_type_decoder_f TLMReservedBits_decode_xer; + xer_type_encoder_f TLMReservedBits_encode_xer; + per_type_decoder_f TLMReservedBits_decode_uper; + per_type_encoder_f TLMReservedBits_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TLMReservedBits_H_ */ +#endif /* _TLMReservedBits_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TLMWord.h b/src/core/libs/supl/asn-rrlp/TLMWord.h index 2be30c082..9b3ad8438 100644 --- a/src/core/libs/supl/asn-rrlp/TLMWord.h +++ b/src/core/libs/supl/asn-rrlp/TLMWord.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TLMWord_H_ -#define _TLMWord_H_ +#ifndef _TLMWord_H_ +#define _TLMWord_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TLMWord */ -typedef long TLMWord_t; + /* TLMWord */ + typedef long TLMWord_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TLMWord; -asn_struct_free_f TLMWord_free; -asn_struct_print_f TLMWord_print; -asn_constr_check_f TLMWord_constraint; -ber_type_decoder_f TLMWord_decode_ber; -der_type_encoder_f TLMWord_encode_der; -xer_type_decoder_f TLMWord_decode_xer; -xer_type_encoder_f TLMWord_encode_xer; -per_type_decoder_f TLMWord_decode_uper; -per_type_encoder_f TLMWord_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TLMWord; + asn_struct_free_f TLMWord_free; + asn_struct_print_f TLMWord_print; + asn_constr_check_f TLMWord_constraint; + ber_type_decoder_f TLMWord_decode_ber; + der_type_encoder_f TLMWord_encode_der; + xer_type_decoder_f TLMWord_decode_xer; + xer_type_encoder_f TLMWord_encode_xer; + per_type_decoder_f TLMWord_decode_uper; + per_type_encoder_f TLMWord_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TLMWord_H_ */ +#endif /* _TLMWord_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TOA-MeasurementsOfRef.h b/src/core/libs/supl/asn-rrlp/TOA-MeasurementsOfRef.h index a6e14e330..0df538d54 100644 --- a/src/core/libs/supl/asn-rrlp/TOA-MeasurementsOfRef.h +++ b/src/core/libs/supl/asn-rrlp/TOA-MeasurementsOfRef.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TOA_MeasurementsOfRef_H_ -#define _TOA_MeasurementsOfRef_H_ +#ifndef _TOA_MeasurementsOfRef_H_ +#define _TOA_MeasurementsOfRef_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TOA-MeasurementsOfRef */ -typedef struct TOA_MeasurementsOfRef { - RefQuality_t refQuality; - NumOfMeasurements_t numOfMeasurements; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} TOA_MeasurementsOfRef_t; + /* TOA-MeasurementsOfRef */ + typedef struct TOA_MeasurementsOfRef + { + RefQuality_t refQuality; + NumOfMeasurements_t numOfMeasurements; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TOA_MeasurementsOfRef; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } TOA_MeasurementsOfRef_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TOA_MeasurementsOfRef; #ifdef __cplusplus } #endif -#endif /* _TOA_MeasurementsOfRef_H_ */ +#endif /* _TOA_MeasurementsOfRef_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TimeRelation.h b/src/core/libs/supl/asn-rrlp/TimeRelation.h index 10fdacf09..d6cbb5302 100644 --- a/src/core/libs/supl/asn-rrlp/TimeRelation.h +++ b/src/core/libs/supl/asn-rrlp/TimeRelation.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TimeRelation_H_ -#define _TimeRelation_H_ +#ifndef _TimeRelation_H_ +#define _TimeRelation_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct GSMTime; + /* Forward declarations */ + struct GSMTime; -/* TimeRelation */ -typedef struct TimeRelation { - GPSTOW23b_t gpsTOW; - struct GSMTime *gsmTime /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} TimeRelation_t; + /* TimeRelation */ + typedef struct TimeRelation + { + GPSTOW23b_t gpsTOW; + struct GSMTime *gsmTime /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TimeRelation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } TimeRelation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TimeRelation; #ifdef __cplusplus } @@ -40,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_TimeRelation; /* Referred external types */ #include "GSMTime.h" -#endif /* _TimeRelation_H_ */ +#endif /* _TimeRelation_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TimeSlot.h b/src/core/libs/supl/asn-rrlp/TimeSlot.h index 9f0b125de..2d91de034 100644 --- a/src/core/libs/supl/asn-rrlp/TimeSlot.h +++ b/src/core/libs/supl/asn-rrlp/TimeSlot.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TimeSlot_H_ -#define _TimeSlot_H_ +#ifndef _TimeSlot_H_ +#define _TimeSlot_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TimeSlot */ -typedef long TimeSlot_t; + /* TimeSlot */ + typedef long TimeSlot_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TimeSlot; -asn_struct_free_f TimeSlot_free; -asn_struct_print_f TimeSlot_print; -asn_constr_check_f TimeSlot_constraint; -ber_type_decoder_f TimeSlot_decode_ber; -der_type_encoder_f TimeSlot_encode_der; -xer_type_decoder_f TimeSlot_decode_xer; -xer_type_encoder_f TimeSlot_encode_xer; -per_type_decoder_f TimeSlot_decode_uper; -per_type_encoder_f TimeSlot_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TimeSlot; + asn_struct_free_f TimeSlot_free; + asn_struct_print_f TimeSlot_print; + asn_constr_check_f TimeSlot_constraint; + ber_type_decoder_f TimeSlot_decode_ber; + der_type_encoder_f TimeSlot_encode_der; + xer_type_decoder_f TimeSlot_decode_xer; + xer_type_encoder_f TimeSlot_encode_xer; + per_type_decoder_f TimeSlot_decode_uper; + per_type_encoder_f TimeSlot_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TimeSlot_H_ */ +#endif /* _TimeSlot_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/TimeSlotScheme.h b/src/core/libs/supl/asn-rrlp/TimeSlotScheme.h index 1857d1540..23e060a13 100644 --- a/src/core/libs/supl/asn-rrlp/TimeSlotScheme.h +++ b/src/core/libs/supl/asn-rrlp/TimeSlotScheme.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _TimeSlotScheme_H_ -#define _TimeSlotScheme_H_ +#ifndef _TimeSlotScheme_H_ +#define _TimeSlotScheme_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum TimeSlotScheme { - TimeSlotScheme_equalLength = 0, - TimeSlotScheme_variousLength = 1 -} e_TimeSlotScheme; + /* Dependencies */ + typedef enum TimeSlotScheme + { + TimeSlotScheme_equalLength = 0, + TimeSlotScheme_variousLength = 1 + } e_TimeSlotScheme; -/* TimeSlotScheme */ -typedef ENUMERATED_t TimeSlotScheme_t; + /* TimeSlotScheme */ + typedef ENUMERATED_t TimeSlotScheme_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TimeSlotScheme; -asn_struct_free_f TimeSlotScheme_free; -asn_struct_print_f TimeSlotScheme_print; -asn_constr_check_f TimeSlotScheme_constraint; -ber_type_decoder_f TimeSlotScheme_decode_ber; -der_type_encoder_f TimeSlotScheme_encode_der; -xer_type_decoder_f TimeSlotScheme_decode_xer; -xer_type_encoder_f TimeSlotScheme_encode_xer; -per_type_decoder_f TimeSlotScheme_decode_uper; -per_type_encoder_f TimeSlotScheme_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TimeSlotScheme; + asn_struct_free_f TimeSlotScheme_free; + asn_struct_print_f TimeSlotScheme_print; + asn_constr_check_f TimeSlotScheme_constraint; + ber_type_decoder_f TimeSlotScheme_decode_ber; + der_type_encoder_f TimeSlotScheme_encode_der; + xer_type_decoder_f TimeSlotScheme_decode_xer; + xer_type_encoder_f TimeSlotScheme_encode_xer; + per_type_decoder_f TimeSlotScheme_decode_uper; + per_type_encoder_f TimeSlotScheme_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TimeSlotScheme_H_ */ +#endif /* _TimeSlotScheme_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/UTCModel.h b/src/core/libs/supl/asn-rrlp/UTCModel.h index 1974bea08..cd96de255 100644 --- a/src/core/libs/supl/asn-rrlp/UTCModel.h +++ b/src/core/libs/supl/asn-rrlp/UTCModel.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _UTCModel_H_ -#define _UTCModel_H_ +#ifndef _UTCModel_H_ +#define _UTCModel_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* UTCModel */ -typedef struct UTCModel { - long utcA1; - long utcA0; - long utcTot; - long utcWNt; - long utcDeltaTls; - long utcWNlsf; - long utcDN; - long utcDeltaTlsf; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} UTCModel_t; + /* UTCModel */ + typedef struct UTCModel + { + long utcA1; + long utcA0; + long utcTot; + long utcWNt; + long utcDeltaTls; + long utcWNlsf; + long utcDN; + long utcDeltaTlsf; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UTCModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } UTCModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UTCModel; #ifdef __cplusplus } #endif -#endif /* _UTCModel_H_ */ +#endif /* _UTCModel_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/UlPseudoSegInd.h b/src/core/libs/supl/asn-rrlp/UlPseudoSegInd.h index cd4b52dae..2f7bc4547 100644 --- a/src/core/libs/supl/asn-rrlp/UlPseudoSegInd.h +++ b/src/core/libs/supl/asn-rrlp/UlPseudoSegInd.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _UlPseudoSegInd_H_ -#define _UlPseudoSegInd_H_ +#ifndef _UlPseudoSegInd_H_ +#define _UlPseudoSegInd_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum UlPseudoSegInd { - UlPseudoSegInd_firstOfMany = 0, - UlPseudoSegInd_secondOfMany = 1 -} e_UlPseudoSegInd; + /* Dependencies */ + typedef enum UlPseudoSegInd + { + UlPseudoSegInd_firstOfMany = 0, + UlPseudoSegInd_secondOfMany = 1 + } e_UlPseudoSegInd; -/* UlPseudoSegInd */ -typedef ENUMERATED_t UlPseudoSegInd_t; + /* UlPseudoSegInd */ + typedef ENUMERATED_t UlPseudoSegInd_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UlPseudoSegInd; -asn_struct_free_f UlPseudoSegInd_free; -asn_struct_print_f UlPseudoSegInd_print; -asn_constr_check_f UlPseudoSegInd_constraint; -ber_type_decoder_f UlPseudoSegInd_decode_ber; -der_type_encoder_f UlPseudoSegInd_encode_der; -xer_type_decoder_f UlPseudoSegInd_decode_xer; -xer_type_encoder_f UlPseudoSegInd_encode_xer; -per_type_decoder_f UlPseudoSegInd_decode_uper; -per_type_encoder_f UlPseudoSegInd_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UlPseudoSegInd; + asn_struct_free_f UlPseudoSegInd_free; + asn_struct_print_f UlPseudoSegInd_print; + asn_constr_check_f UlPseudoSegInd_constraint; + ber_type_decoder_f UlPseudoSegInd_decode_ber; + der_type_encoder_f UlPseudoSegInd_encode_der; + xer_type_decoder_f UlPseudoSegInd_decode_xer; + xer_type_encoder_f UlPseudoSegInd_encode_xer; + per_type_decoder_f UlPseudoSegInd_decode_uper; + per_type_encoder_f UlPseudoSegInd_encode_uper; #ifdef __cplusplus } #endif -#endif /* _UlPseudoSegInd_H_ */ +#endif /* _UlPseudoSegInd_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/UncompressedEphemeris.h b/src/core/libs/supl/asn-rrlp/UncompressedEphemeris.h index 2cecd614f..d994f4805 100644 --- a/src/core/libs/supl/asn-rrlp/UncompressedEphemeris.h +++ b/src/core/libs/supl/asn-rrlp/UncompressedEphemeris.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _UncompressedEphemeris_H_ -#define _UncompressedEphemeris_H_ +#ifndef _UncompressedEphemeris_H_ +#define _UncompressedEphemeris_H_ #include @@ -16,53 +16,55 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* UncompressedEphemeris */ -typedef struct UncompressedEphemeris { - long ephemCodeOnL2; - long ephemURA; - long ephemSVhealth; - long ephemIODC; - long ephemL2Pflag; - EphemerisSubframe1Reserved_t ephemSF1Rsvd; - long ephemTgd; - long ephemToc; - long ephemAF2; - long ephemAF1; - long ephemAF0; - long ephemCrs; - long ephemDeltaN; - long ephemM0; - long ephemCuc; - unsigned long ephemE; - long ephemCus; - unsigned long ephemAPowerHalf; - long ephemToe; - long ephemFitFlag; - long ephemAODA; - long ephemCic; - long ephemOmegaA0; - long ephemCis; - long ephemI0; - long ephemCrc; - long ephemW; - long ephemOmegaADot; - long ephemIDot; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} UncompressedEphemeris_t; + /* UncompressedEphemeris */ + typedef struct UncompressedEphemeris + { + long ephemCodeOnL2; + long ephemURA; + long ephemSVhealth; + long ephemIODC; + long ephemL2Pflag; + EphemerisSubframe1Reserved_t ephemSF1Rsvd; + long ephemTgd; + long ephemToc; + long ephemAF2; + long ephemAF1; + long ephemAF0; + long ephemCrs; + long ephemDeltaN; + long ephemM0; + long ephemCuc; + unsigned long ephemE; + long ephemCus; + unsigned long ephemAPowerHalf; + long ephemToe; + long ephemFitFlag; + long ephemAODA; + long ephemCic; + long ephemOmegaA0; + long ephemCis; + long ephemI0; + long ephemCrc; + long ephemW; + long ephemOmegaADot; + long ephemIDot; -/* Implementation */ -/* extern asn_TYPE_descriptor_t asn_DEF_ephemE_17; // (Use -fall-defs-global to expose) */ -/* extern asn_TYPE_descriptor_t asn_DEF_ephemAPowerHalf_19; // (Use -fall-defs-global to expose) */ -extern asn_TYPE_descriptor_t asn_DEF_UncompressedEphemeris; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } UncompressedEphemeris_t; + + /* Implementation */ + /* extern asn_TYPE_descriptor_t asn_DEF_ephemE_17; // (Use -fall-defs-global to expose) */ + /* extern asn_TYPE_descriptor_t asn_DEF_ephemAPowerHalf_19; // (Use -fall-defs-global to expose) */ + extern asn_TYPE_descriptor_t asn_DEF_UncompressedEphemeris; #ifdef __cplusplus } #endif -#endif /* _UncompressedEphemeris_H_ */ +#endif /* _UncompressedEphemeris_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/UseMultipleSets.h b/src/core/libs/supl/asn-rrlp/UseMultipleSets.h index b156fc467..45136278c 100644 --- a/src/core/libs/supl/asn-rrlp/UseMultipleSets.h +++ b/src/core/libs/supl/asn-rrlp/UseMultipleSets.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _UseMultipleSets_H_ -#define _UseMultipleSets_H_ +#ifndef _UseMultipleSets_H_ +#define _UseMultipleSets_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum UseMultipleSets { - UseMultipleSets_multipleSets = 0, - UseMultipleSets_oneSet = 1 -} e_UseMultipleSets; + /* Dependencies */ + typedef enum UseMultipleSets + { + UseMultipleSets_multipleSets = 0, + UseMultipleSets_oneSet = 1 + } e_UseMultipleSets; -/* UseMultipleSets */ -typedef ENUMERATED_t UseMultipleSets_t; + /* UseMultipleSets */ + typedef ENUMERATED_t UseMultipleSets_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UseMultipleSets; -asn_struct_free_f UseMultipleSets_free; -asn_struct_print_f UseMultipleSets_print; -asn_constr_check_f UseMultipleSets_constraint; -ber_type_decoder_f UseMultipleSets_decode_ber; -der_type_encoder_f UseMultipleSets_encode_der; -xer_type_decoder_f UseMultipleSets_decode_xer; -xer_type_encoder_f UseMultipleSets_encode_xer; -per_type_decoder_f UseMultipleSets_decode_uper; -per_type_encoder_f UseMultipleSets_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UseMultipleSets; + asn_struct_free_f UseMultipleSets_free; + asn_struct_print_f UseMultipleSets_print; + asn_constr_check_f UseMultipleSets_constraint; + ber_type_decoder_f UseMultipleSets_decode_ber; + der_type_encoder_f UseMultipleSets_encode_der; + xer_type_decoder_f UseMultipleSets_decode_xer; + xer_type_encoder_f UseMultipleSets_encode_xer; + per_type_decoder_f UseMultipleSets_decode_uper; + per_type_encoder_f UseMultipleSets_encode_uper; #ifdef __cplusplus } #endif -#endif /* _UseMultipleSets_H_ */ +#endif /* _UseMultipleSets_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/VelocityEstimate.h b/src/core/libs/supl/asn-rrlp/VelocityEstimate.h index 45dbb1669..0ef92f9a5 100644 --- a/src/core/libs/supl/asn-rrlp/VelocityEstimate.h +++ b/src/core/libs/supl/asn-rrlp/VelocityEstimate.h @@ -4,8 +4,8 @@ * found in "../rrlp-components.asn" */ -#ifndef _VelocityEstimate_H_ -#define _VelocityEstimate_H_ +#ifndef _VelocityEstimate_H_ +#define _VelocityEstimate_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* VelocityEstimate */ -typedef INTEGER_t VelocityEstimate_t; + /* VelocityEstimate */ + typedef INTEGER_t VelocityEstimate_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_VelocityEstimate; -asn_struct_free_f VelocityEstimate_free; -asn_struct_print_f VelocityEstimate_print; -asn_constr_check_f VelocityEstimate_constraint; -ber_type_decoder_f VelocityEstimate_decode_ber; -der_type_encoder_f VelocityEstimate_encode_der; -xer_type_decoder_f VelocityEstimate_decode_xer; -xer_type_encoder_f VelocityEstimate_encode_xer; -per_type_decoder_f VelocityEstimate_decode_uper; -per_type_encoder_f VelocityEstimate_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_VelocityEstimate; + asn_struct_free_f VelocityEstimate_free; + asn_struct_print_f VelocityEstimate_print; + asn_constr_check_f VelocityEstimate_constraint; + ber_type_decoder_f VelocityEstimate_decode_ber; + der_type_encoder_f VelocityEstimate_encode_der; + xer_type_decoder_f VelocityEstimate_decode_xer; + xer_type_encoder_f VelocityEstimate_encode_xer; + per_type_decoder_f VelocityEstimate_decode_uper; + per_type_encoder_f VelocityEstimate_encode_uper; #ifdef __cplusplus } #endif -#endif /* _VelocityEstimate_H_ */ +#endif /* _VelocityEstimate_H_ */ #include diff --git a/src/core/libs/supl/asn-rrlp/asn_SEQUENCE_OF.h b/src/core/libs/supl/asn-rrlp/asn_SEQUENCE_OF.h index e678f0347..2ad8287a0 100644 --- a/src/core/libs/supl/asn-rrlp/asn_SEQUENCE_OF.h +++ b/src/core/libs/supl/asn-rrlp/asn_SEQUENCE_OF.h @@ -2,13 +2,14 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_SEQUENCE_OF_H -#define ASN_SEQUENCE_OF_H +#ifndef ASN_SEQUENCE_OF_H +#define ASN_SEQUENCE_OF_H #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* @@ -16,37 +17,37 @@ extern "C" { * the delete operation preserves the initial order of elements * and thus MAY operate in non-constant time. */ -#define A_SEQUENCE_OF(type) A_SET_OF(type) +#define A_SEQUENCE_OF(type) A_SET_OF(type) -#define ASN_SEQUENCE_ADD(headptr, ptr) \ - asn_sequence_add((headptr), (ptr)) +#define ASN_SEQUENCE_ADD(headptr, ptr) \ + asn_sequence_add((headptr), (ptr)) -/*********************************************** + /*********************************************** * Implementation of the SEQUENCE OF structure. */ -#define asn_sequence_add asn_set_add -#define asn_sequence_empty asn_set_empty +#define asn_sequence_add asn_set_add +#define asn_sequence_empty asn_set_empty -/* + /* * Delete the element from the set by its number (base 0). * This is NOT a constant-time operation. * The order of elements is preserved. * If _do_free is given AND the (*free) is initialized, the element * will be freed using the custom (*free) function as well. */ -void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); + void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); -/* + /* * Cope with different conversions requirements to/from void in C and C++. * This is mostly useful for support library. */ -typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; -#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) -#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) + typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; +#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) +#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) #ifdef __cplusplus } #endif -#endif /* ASN_SEQUENCE_OF_H */ +#endif /* ASN_SEQUENCE_OF_H */ diff --git a/src/core/libs/supl/asn-rrlp/asn_SET_OF.h b/src/core/libs/supl/asn-rrlp/asn_SET_OF.h index 7edf14b51..0edc0abc4 100644 --- a/src/core/libs/supl/asn-rrlp/asn_SET_OF.h +++ b/src/core/libs/supl/asn-rrlp/asn_SET_OF.h @@ -2,36 +2,38 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_SET_OF_H -#define ASN_SET_OF_H +#ifndef ASN_SET_OF_H +#define ASN_SET_OF_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -#define A_SET_OF(type) \ - struct { \ - type **array; \ - int count; /* Meaningful size */ \ - int size; /* Allocated size */ \ - void (*free)(type *); \ - } +#define A_SET_OF(type) \ + struct \ + { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } -#define ASN_SET_ADD(headptr, ptr) \ - asn_set_add((headptr), (ptr)) +#define ASN_SET_ADD(headptr, ptr) \ + asn_set_add((headptr), (ptr)) -/******************************************* + /******************************************* * Implementation of the SET OF structure. */ -/* + /* * Add another structure into the set by its pointer. * RETURN VALUES: * 0 for success and -1/errno for failure. */ -int asn_set_add(void *asn_set_of_x, void *ptr); + int asn_set_add(void *asn_set_of_x, void *ptr); -/* + /* * Delete the element from the set by its number (base 0). * This is a constant-time operation. The order of elements before the * deleted ones is guaranteed, the order of elements after the deleted @@ -39,24 +41,24 @@ int asn_set_add(void *asn_set_of_x, void *ptr); * If _do_free is given AND the (*free) is initialized, the element * will be freed using the custom (*free) function as well. */ -void asn_set_del(void *asn_set_of_x, int number, int _do_free); + void asn_set_del(void *asn_set_of_x, int number, int _do_free); -/* + /* * Empty the contents of the set. Will free the elements, if (*free) is given. * Will NOT free the set itself. */ -void asn_set_empty(void *asn_set_of_x); + void asn_set_empty(void *asn_set_of_x); -/* + /* * Cope with different conversions requirements to/from void in C and C++. * This is mostly useful for support library. */ -typedef A_SET_OF(void) asn_anonymous_set_; -#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) -#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) + typedef A_SET_OF(void) asn_anonymous_set_; +#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) +#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) #ifdef __cplusplus } #endif -#endif /* ASN_SET_OF_H */ +#endif /* ASN_SET_OF_H */ diff --git a/src/core/libs/supl/asn-rrlp/asn_application.h b/src/core/libs/supl/asn-rrlp/asn_application.h index f40cd86ad..43904afb0 100644 --- a/src/core/libs/supl/asn-rrlp/asn_application.h +++ b/src/core/libs/supl/asn-rrlp/asn_application.h @@ -5,27 +5,28 @@ /* * Application-level ASN.1 callbacks. */ -#ifndef _ASN_APPLICATION_H_ -#define _ASN_APPLICATION_H_ +#ifndef _ASN_APPLICATION_H_ +#define _ASN_APPLICATION_H_ -#include "asn_system.h" /* for platform-dependent types */ -#include "asn_codecs.h" /* for ASN.1 codecs specifics */ +#include "asn_system.h" /* for platform-dependent types */ +#include "asn_codecs.h" /* for ASN.1 codecs specifics */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Generic type of an application-defined callback to return various * types of data to the application. * EXPECTED RETURN VALUES: * -1: Failed to consume bytes. Abort the mission. * Non-negative return values indicate success, and ignored. */ -typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, - void *application_specific_key); + typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, + void *application_specific_key); -/* + /* * A callback of this type is called whenever constraint validation fails * on some ASN.1 type. See "constraints.h" for more details on constraint * validation. @@ -33,15 +34,15 @@ typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, * the constraint check, as well as human readable message on what * particular constraint has failed. */ -typedef void (asn_app_constraint_failed_f)(void *application_specific_key, - struct asn_TYPE_descriptor_s *type_descriptor_which_failed, - const void *structure_which_failed_ptr, - const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); + typedef void(asn_app_constraint_failed_f)(void *application_specific_key, + struct asn_TYPE_descriptor_s *type_descriptor_which_failed, + const void *structure_which_failed_ptr, + const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); #ifdef __cplusplus } #endif -#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ +#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ -#endif /* _ASN_APPLICATION_H_ */ +#endif /* _ASN_APPLICATION_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/asn_codecs.h b/src/core/libs/supl/asn-rrlp/asn_codecs.h index 4a251d940..717336ed5 100644 --- a/src/core/libs/supl/asn-rrlp/asn_codecs.h +++ b/src/core/libs/supl/asn-rrlp/asn_codecs.h @@ -3,16 +3,17 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ASN_CODECS_H_ -#define _ASN_CODECS_H_ +#ifndef _ASN_CODECS_H_ +#define _ASN_CODECS_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * This structure defines a set of parameters that may be passed * to every ASN.1 encoder or decoder function. * WARNING: if max_stack_size member is set, and you are calling the @@ -21,8 +22,9 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ * If you can't always satisfy this requirement, use ber_decode(), * xer_decode() and uper_decode() functions instead. */ -typedef struct asn_codec_ctx_s { - /* + typedef struct asn_codec_ctx_s + { + /* * Limit the decoder routines to use no (much) more stack than a given * number of bytes. Most of decoders are stack-based, and this * would protect against stack overflows if the number of nested @@ -33,45 +35,52 @@ typedef struct asn_codec_ctx_s { * this variable. Be careful in multithreaded environments, as the * stack size is rather limited. */ - size_t max_stack_size; /* 0 disables stack bounds checking */ -} asn_codec_ctx_t; + size_t max_stack_size; /* 0 disables stack bounds checking */ + } asn_codec_ctx_t; -/* + /* * Type of the return value of the encoding functions (der_encode, xer_encode). */ -typedef struct asn_enc_rval_s { - /* + typedef struct asn_enc_rval_s + { + /* * Number of bytes encoded. * -1 indicates failure to encode the structure. * In this case, the members below this one are meaningful. */ - ssize_t encoded; + ssize_t encoded; - /* + /* * Members meaningful when (encoded == -1), for post mortem analysis. */ - /* Type which cannot be encoded */ - struct asn_TYPE_descriptor_s *failed_type; + /* Type which cannot be encoded */ + struct asn_TYPE_descriptor_s *failed_type; - /* Pointer to the structure of that type */ - void *structure_ptr; -} asn_enc_rval_t; -#define _ASN_ENCODE_FAILED do { \ - asn_enc_rval_t tmp_error; \ - tmp_error.encoded = -1; \ - tmp_error.failed_type = td; \ - tmp_error.structure_ptr = sptr; \ - ASN_DEBUG("Failed to encode element %s", td->name); \ - return tmp_error; \ -} while(0) -#define _ASN_ENCODED_OK(rval) do { \ - rval.structure_ptr = 0; \ - rval.failed_type = 0; \ - return rval; \ -} while(0) + /* Pointer to the structure of that type */ + void *structure_ptr; + } asn_enc_rval_t; +#define _ASN_ENCODE_FAILED \ + do \ + { \ + asn_enc_rval_t tmp_error; \ + tmp_error.encoded = -1; \ + tmp_error.failed_type = td; \ + tmp_error.structure_ptr = sptr; \ + ASN_DEBUG("Failed to encode element %s", td->name); \ + return tmp_error; \ + } \ + while (0) +#define _ASN_ENCODED_OK(rval) \ + do \ + { \ + rval.structure_ptr = 0; \ + rval.failed_type = 0; \ + return rval; \ + } \ + while (0) -/* + /* * Type of the return value of the decoding functions (ber_decode, xer_decode) * * Please note that the number of consumed bytes is ALWAYS meaningful, @@ -79,31 +88,39 @@ typedef struct asn_enc_rval_s { * decoded bytes, hence providing a possibility to fail with more diagnostics * (i.e., print the offending remainder of the buffer). */ -enum asn_dec_rval_code_e { - RC_OK, /* Decoded successfully */ - RC_WMORE, /* More data expected, call again */ - RC_FAIL /* Failure to decode data */ -}; -typedef struct asn_dec_rval_s { - enum asn_dec_rval_code_e code; /* Result code */ - size_t consumed; /* Number of bytes consumed */ -} asn_dec_rval_t; -#define _ASN_DECODE_FAILED do { \ - asn_dec_rval_t tmp_error; \ - tmp_error.code = RC_FAIL; \ - tmp_error.consumed = 0; \ - ASN_DEBUG("Failed to decode element %s", td->name); \ - return tmp_error; \ -} while(0) -#define _ASN_DECODE_STARVED do { \ - asn_dec_rval_t tmp_error; \ - tmp_error.code = RC_WMORE; \ - tmp_error.consumed = 0; \ - return tmp_error; \ -} while(0) + enum asn_dec_rval_code_e + { + RC_OK, /* Decoded successfully */ + RC_WMORE, /* More data expected, call again */ + RC_FAIL /* Failure to decode data */ + }; + typedef struct asn_dec_rval_s + { + enum asn_dec_rval_code_e code; /* Result code */ + size_t consumed; /* Number of bytes consumed */ + } asn_dec_rval_t; +#define _ASN_DECODE_FAILED \ + do \ + { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_FAIL; \ + tmp_error.consumed = 0; \ + ASN_DEBUG("Failed to decode element %s", td->name); \ + return tmp_error; \ + } \ + while (0) +#define _ASN_DECODE_STARVED \ + do \ + { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_WMORE; \ + tmp_error.consumed = 0; \ + return tmp_error; \ + } \ + while (0) #ifdef __cplusplus } #endif -#endif /* _ASN_CODECS_H_ */ +#endif /* _ASN_CODECS_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/asn_codecs_prim.h b/src/core/libs/supl/asn-rrlp/asn_codecs_prim.h index 0f683fdd0..cb8c37937 100644 --- a/src/core/libs/supl/asn-rrlp/asn_codecs_prim.h +++ b/src/core/libs/supl/asn-rrlp/asn_codecs_prim.h @@ -2,52 +2,53 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_CODECS_PRIM_H -#define ASN_CODECS_PRIM_H +#ifndef ASN_CODECS_PRIM_H +#define ASN_CODECS_PRIM_H #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct ASN__PRIMITIVE_TYPE_s { - uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ - int size; /* Size of the buffer */ -} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ + typedef struct ASN__PRIMITIVE_TYPE_s + { + uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ + int size; /* Size of the buffer */ + } ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ -asn_struct_free_f ASN__PRIMITIVE_TYPE_free; -ber_type_decoder_f ber_decode_primitive; -der_type_encoder_f der_encode_primitive; + asn_struct_free_f ASN__PRIMITIVE_TYPE_free; + ber_type_decoder_f ber_decode_primitive; + der_type_encoder_f der_encode_primitive; -/* + /* * A callback specification for the xer_decode_primitive() function below. */ -enum xer_pbd_rval { - XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ - XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ - XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ - XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ - XPBD_BODY_CONSUMED /* Body is recognized and consumed */ -}; -typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) - (asn_TYPE_descriptor_t *td, void *struct_ptr, - const void *chunk_buf, size_t chunk_size); + enum xer_pbd_rval + { + XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ + XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ + XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ + XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ + XPBD_BODY_CONSUMED /* Body is recognized and consumed */ + }; + typedef enum xer_pbd_rval(xer_primitive_body_decoder_f)(asn_TYPE_descriptor_t *td, void *struct_ptr, + const void *chunk_buf, size_t chunk_size); -/* + /* * Specific function to decode simple primitive types. * Also see xer_decode_general() in xer_decoder.h */ -asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *type_descriptor, - void **struct_ptr, size_t struct_size, - const char *opt_mname, - const void *buf_ptr, size_t size, - xer_primitive_body_decoder_f *prim_body_decoder -); + asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder); #ifdef __cplusplus } #endif -#endif /* ASN_CODECS_PRIM_H */ +#endif /* ASN_CODECS_PRIM_H */ diff --git a/src/core/libs/supl/asn-rrlp/asn_internal.h b/src/core/libs/supl/asn-rrlp/asn_internal.h index 249d7ef64..299c4e0e7 100644 --- a/src/core/libs/supl/asn-rrlp/asn_internal.h +++ b/src/core/libs/supl/asn-rrlp/asn_internal.h @@ -6,114 +6,130 @@ /* * Declarations internally useful for the ASN.1 support code. */ -#ifndef _ASN_INTERNAL_H_ -#define _ASN_INTERNAL_H_ +#ifndef _ASN_INTERNAL_H_ +#define _ASN_INTERNAL_H_ -#include "asn_application.h" /* Application-visible API */ +#include "asn_application.h" /* Application-visible API */ -#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ -#include /* for assert() macro */ +#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ +#include /* for assert() macro */ #endif -#ifdef __cplusplus -extern "C" { +#ifdef __cplusplus +extern "C" +{ #endif /* Environment version might be used to avoid running with the old library */ -#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ -int get_asn1c_environment_version(void); /* Run-time version */ +#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ + int get_asn1c_environment_version(void); /* Run-time version */ -#define CALLOC(nmemb, size) calloc(nmemb, size) -#define MALLOC(size) malloc(size) -#define REALLOC(oldptr, size) realloc(oldptr, size) -#define FREEMEM(ptr) free(ptr) +#define CALLOC(nmemb, size) calloc(nmemb, size) +#define MALLOC(size) malloc(size) +#define REALLOC(oldptr, size) realloc(oldptr, size) +#define FREEMEM(ptr) free(ptr) /* * A macro for debugging the ASN.1 internals. * You may enable or override it. */ -#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ -#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ -#ifdef __GNUC__ -#ifdef ASN_THREAD_SAFE -#define asn_debug_indent 0 -#else /* !ASN_THREAD_SAFE */ -int asn_debug_indent; -#endif /* ASN_THREAD_SAFE */ -#define ASN_DEBUG(fmt, args...) do { \ - int adi = asn_debug_indent; \ - while(adi--) fprintf(stderr, " "); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, " (%s:%d)\n", \ - __FILE__, __LINE__); \ - } while(0) -#else /* !__GNUC__ */ -void ASN_DEBUG_f(const char *fmt, ...); -#define ASN_DEBUG ASN_DEBUG_f -#endif /* __GNUC__ */ -#else /* EMIT_ASN_DEBUG != 1 */ -static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } -#endif /* EMIT_ASN_DEBUG */ -#endif /* ASN_DEBUG */ +#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ +#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ +#ifdef __GNUC__ +#ifdef ASN_THREAD_SAFE +#define asn_debug_indent 0 +#else /* !ASN_THREAD_SAFE */ + int asn_debug_indent; +#endif /* ASN_THREAD_SAFE */ +#define ASN_DEBUG(fmt, args...) \ + do \ + { \ + int adi = asn_debug_indent; \ + while (adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ + } \ + while (0) +#else /* !__GNUC__ */ + void ASN_DEBUG_f(const char *fmt, ...); +#define ASN_DEBUG ASN_DEBUG_f +#endif /* __GNUC__ */ +#else /* EMIT_ASN_DEBUG != 1 */ + static inline void ASN_DEBUG(const char *fmt, ...) + { + (void)fmt; + } +#endif /* EMIT_ASN_DEBUG */ +#endif /* ASN_DEBUG */ /* * Invoke the application-supplied callback and fail, if something is wrong. */ -#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) -#define _ASN_E_CALLBACK(foo) do { \ - if(foo) goto cb_failed; \ - } while(0) -#define _ASN_CALLBACK(buf, size) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) -#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) -#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ - || __ASN_E_cbc(buf2, size2) \ - || __ASN_E_cbc(buf3, size3)) +#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) +#define _ASN_E_CALLBACK(foo) \ + do \ + { \ + if (foo) goto cb_failed; \ + } \ + while (0) +#define _ASN_CALLBACK(buf, size) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) +#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) +#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2) || __ASN_E_cbc(buf3, size3)) -#define _i_ASN_TEXT_INDENT(nl, level) do { \ - int __level = (level); \ - int __nl = ((nl) != 0); \ - int __i; \ - if(__nl) _ASN_CALLBACK("\n", 1); \ - if(__level < 0) __level = 0; \ - for(__i = 0; __i < __level; __i++) \ - _ASN_CALLBACK(" ", 4); \ - er.encoded += __nl + 4 * __level; \ -} while(0) +#define _i_ASN_TEXT_INDENT(nl, level) \ + do \ + { \ + int __level = (level); \ + int __nl = ((nl) != 0); \ + int __i; \ + if (__nl) _ASN_CALLBACK("\n", 1); \ + if (__level < 0) __level = 0; \ + for (__i = 0; __i < __level; __i++) \ + _ASN_CALLBACK(" ", 4); \ + er.encoded += __nl + 4 * __level; \ + } \ + while (0) -#define _i_INDENT(nl) do { \ - int __i; \ - if((nl) && cb("\n", 1, app_key) < 0) return -1; \ - for(__i = 0; __i < ilevel; __i++) \ - if(cb(" ", 4, app_key) < 0) return -1; \ -} while(0) +#define _i_INDENT(nl) \ + do \ + { \ + int __i; \ + if ((nl) && cb("\n", 1, app_key) < 0) return -1; \ + for (__i = 0; __i < ilevel; __i++) \ + if (cb(" ", 4, app_key) < 0) return -1; \ + } \ + while (0) /* * Check stack against overflow, if limit is set. */ -#define _ASN_DEFAULT_STACK_MAX (30000) -static inline int -_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { - if(ctx && ctx->max_stack_size) { +#define _ASN_DEFAULT_STACK_MAX (30000) + static inline int + _ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) + { + if (ctx && ctx->max_stack_size) + { + /* ctx MUST be allocated on the stack */ + ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); + if (usedstack > 0) usedstack = -usedstack; /* grows up! */ - /* ctx MUST be allocated on the stack */ - ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); - if(usedstack > 0) usedstack = -usedstack; /* grows up! */ + /* double negative required to avoid int wrap-around */ + if (usedstack < -(ptrdiff_t)ctx->max_stack_size) + { + ASN_DEBUG("Stack limit %ld reached", + (long)ctx->max_stack_size); + return -1; + } + } + return 0; + } - /* double negative required to avoid int wrap-around */ - if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { - ASN_DEBUG("Stack limit %ld reached", - (long)ctx->max_stack_size); - return -1; - } - } - return 0; -} - -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* _ASN_INTERNAL_H_ */ +#endif /* _ASN_INTERNAL_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/asn_system.h b/src/core/libs/supl/asn-rrlp/asn_system.h index 0a9b092c3..1d2958174 100644 --- a/src/core/libs/supl/asn-rrlp/asn_system.h +++ b/src/core/libs/supl/asn-rrlp/asn_system.h @@ -6,124 +6,121 @@ /* * Miscellaneous system-dependent types. */ -#ifndef _ASN_SYSTEM_H_ -#define _ASN_SYSTEM_H_ +#ifndef _ASN_SYSTEM_H_ +#define _ASN_SYSTEM_H_ -#ifdef HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H #include "config.h" #endif -#include /* For snprintf(3) */ -#include /* For *alloc(3) */ -#include /* For memcpy(3) */ -#include /* For size_t */ -#include /* For LONG_MAX */ -#include /* For va_start */ -#include /* for offsetof and ptrdiff_t */ +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ +#include /* For size_t */ +#include /* For LONG_MAX */ +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ -#ifdef WIN32 +#ifdef WIN32 #include -#define snprintf _snprintf -#define vsnprintf _vsnprintf +#define snprintf _snprintf +#define vsnprintf _vsnprintf /* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ -#define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ - | (((l) << 16) & 0xff0000) \ - | (((l) << 8) & 0xff00) \ - | ((l) & 0xff)) +#define sys_ntohl(l) ((((l) << 24) & 0xff000000) | (((l) << 16) & 0xff0000) | (((l) << 8) & 0xff00) | ((l)&0xff)) -#ifdef _MSC_VER /* MSVS.Net */ +#ifdef _MSC_VER /* MSVS.Net */ #ifndef __cplusplus #define inline __inline #endif -#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ -#define ssize_t SSIZE_T -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#endif /* ASSUMESTDTYPES */ +#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ +#define ssize_t SSIZE_T +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#endif /* ASSUMESTDTYPES */ #define WIN32_LEAN_AND_MEAN #include #include #define isnan _isnan #define finite _finite #define copysign _copysign -#define ilogb _logb -#else /* !_MSC_VER */ +#define ilogb _logb +#else /* !_MSC_VER */ #include -#endif /* _MSC_VER */ +#endif /* _MSC_VER */ -#else /* !WIN32 */ +#else /* !WIN32 */ #if defined(__vxworks) #include -#else /* !defined(__vxworks) */ +#else /* !defined(__vxworks) */ -#include /* C99 specifies this file */ +#include /* C99 specifies this file */ /* * 1. Earlier FreeBSD version didn't have , * but was present. * 2. Sun Solaris requires for alloca(3), * but does not have . */ -#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) -#if defined(sun) -#include /* For alloca(3) */ -#include /* for finite(3) */ -#elif defined(__hpux) -#ifdef __GNUC__ -#include /* For alloca(3) */ -#else /* !__GNUC__ */ +#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) +#if defined(sun) +#include /* For alloca(3) */ +#include /* for finite(3) */ +#elif defined(__hpux) +#ifdef __GNUC__ +#include /* For alloca(3) */ +#else /* !__GNUC__ */ #define inline -#endif /* __GNUC__ */ +#endif /* __GNUC__ */ #else -#include /* SUSv2+ and C99 specify this file, for uintXX_t */ -#endif /* defined(sun) */ +#include /* SUSv2+ and C99 specify this file, for uintXX_t */ +#endif /* defined(sun) */ #endif #include /* for ntohl() */ -#define sys_ntohl(foo) ntohl(foo) +#define sys_ntohl(foo) ntohl(foo) -#endif /* defined(__vxworks) */ +#endif /* defined(__vxworks) */ -#endif /* WIN32 */ +#endif /* WIN32 */ -#if __GNUC__ >= 3 -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#if __GNUC__ >= 3 +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt, var) __attribute__((format(printf, fmt, var))) #endif -#ifndef GCC_NOTUSED -#define GCC_NOTUSED __attribute__((unused)) +#ifndef GCC_NOTUSED +#define GCC_NOTUSED __attribute__((unused)) #endif #else -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) /* nothing */ +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt, var) /* nothing */ #endif -#ifndef GCC_NOTUSED -#define GCC_NOTUSED +#ifndef GCC_NOTUSED +#define GCC_NOTUSED #endif #endif /* Figure out if thread safety is requested */ #if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) -#define ASN_THREAD_SAFE -#endif /* Thread safety */ +#define ASN_THREAD_SAFE +#endif /* Thread safety */ -#ifndef offsetof /* If not defined by */ -#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) -#endif /* offsetof */ +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t) & (((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ -#ifndef MIN /* Suitable for comparing primitive types (integers) */ +#ifndef MIN /* Suitable for comparing primitive types (integers) */ #if defined(__GNUC__) -#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ +#define MIN(a, b) ({ __typeof a _a = a; __typeof b _b = b; \ ((_a)<(_b)?(_a):(_b)); }) -#else /* !__GNUC__ */ -#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ -#endif /* __GNUC__ */ -#endif /* MIN */ +#else /* !__GNUC__ */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) /* Unsafe variant */ +#endif /* __GNUC__ */ +#endif /* MIN */ -#endif /* _ASN_SYSTEM_H_ */ +#endif /* _ASN_SYSTEM_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/ber_decoder.c b/src/core/libs/supl/asn-rrlp/ber_decoder.c index 601f66c0b..77cb8032e 100644 --- a/src/core/libs/supl/asn-rrlp/ber_decoder.c +++ b/src/core/libs/supl/asn-rrlp/ber_decoder.c @@ -16,7 +16,7 @@ asn_dec_rval_t rval; \ rval.code = _code; \ if(opt_ctx) opt_ctx->step = step; /* Save context */ \ - if(_code == RC_OK || opt_ctx) \ + if((_code) == RC_OK || opt_ctx) \ rval.consumed = consumed_myself; \ else \ rval.consumed = 0; /* Context-free */ \ diff --git a/src/core/libs/supl/asn-rrlp/ber_decoder.h b/src/core/libs/supl/asn-rrlp/ber_decoder.h index 9fe2e895d..6a87fc23f 100644 --- a/src/core/libs/supl/asn-rrlp/ber_decoder.h +++ b/src/core/libs/supl/asn-rrlp/ber_decoder.h @@ -2,63 +2,64 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_DECODER_H_ -#define _BER_DECODER_H_ +#ifndef _BER_DECODER_H_ +#define _BER_DECODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ -struct asn_codec_ctx_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_codec_ctx_s; /* Forward declaration */ -/* + /* * The BER decoder of any type. * This function may be invoked directly from the application. * The der_encode() function (der_encoder.h) is an opposite to ber_decode(). */ -asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of that buffer */ - ); + asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ + ); -/* + /* * Type of generic function which decodes the byte stream into the structure. */ -typedef asn_dec_rval_t (ber_type_decoder_f)( - struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, const void *buf_ptr, size_t size, - int tag_mode); + typedef asn_dec_rval_t(ber_type_decoder_f)( + struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, const void *buf_ptr, size_t size, + int tag_mode); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Check that all tags correspond to the type definition (as given in head). * On return, last_length would contain either a non-negative length of the * value part of the last TLV, or the negative number of expected * "end of content" sequences. The number may only be negative if the * head->last_tag_form is non-zero. */ -asn_dec_rval_t ber_check_tags( - struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ - struct asn_TYPE_descriptor_s *type_descriptor, - asn_struct_ctx_t *opt_ctx, /* saved decoding context */ - const void *ptr, size_t size, - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - int last_tag_form, /* {-1,0:1}: any, primitive, constr */ - ber_tlv_len_t *last_length, - int *opt_tlv_form /* optional tag form */ - ); + asn_dec_rval_t ber_check_tags( + struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ + struct asn_TYPE_descriptor_s *type_descriptor, + asn_struct_ctx_t *opt_ctx, /* saved decoding context */ + const void *ptr, size_t size, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {-1,0:1}: any, primitive, constr */ + ber_tlv_len_t *last_length, + int *opt_tlv_form /* optional tag form */ + ); #ifdef __cplusplus } #endif -#endif /* _BER_DECODER_H_ */ +#endif /* _BER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/ber_tlv_length.h b/src/core/libs/supl/asn-rrlp/ber_tlv_length.h index 349680224..7245624cd 100644 --- a/src/core/libs/supl/asn-rrlp/ber_tlv_length.h +++ b/src/core/libs/supl/asn-rrlp/ber_tlv_length.h @@ -2,16 +2,17 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_TLV_LENGTH_H_ -#define _BER_TLV_LENGTH_H_ +#ifndef _BER_TLV_LENGTH_H_ +#define _BER_TLV_LENGTH_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef ssize_t ber_tlv_len_t; + typedef ssize_t ber_tlv_len_t; -/* + /* * This function tries to fetch the length of the BER TLV value and place it * in *len_r. * RETURN VALUES: @@ -21,30 +22,30 @@ typedef ssize_t ber_tlv_len_t; * On return with >0, len_r is constrained as -1..MAX, where -1 mean * that the value is of indefinite length. */ -ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, - ber_tlv_len_t *len_r); + ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r); -/* + /* * This function expects bufptr to be positioned over L in TLV. * It returns number of bytes occupied by L and V together, suitable * for skipping. The function properly handles indefinite length. * RETURN VALUES: * Standard {-1,0,>0} convention. */ -ssize_t ber_skip_length( - struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ - int _is_constructed, const void *bufptr, size_t size); + ssize_t ber_skip_length( + struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ + int _is_constructed, const void *bufptr, size_t size); -/* + /* * This function serializes the length (L from TLV) in DER format. * It always returns number of bytes necessary to represent the length, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ -size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); + size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); #ifdef __cplusplus } #endif -#endif /* _BER_TLV_LENGTH_H_ */ +#endif /* _BER_TLV_LENGTH_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/ber_tlv_tag.h b/src/core/libs/supl/asn-rrlp/ber_tlv_tag.h index 60e866861..31b634345 100644 --- a/src/core/libs/supl/asn-rrlp/ber_tlv_tag.h +++ b/src/core/libs/supl/asn-rrlp/ber_tlv_tag.h @@ -2,59 +2,61 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_TLV_TAG_H_ -#define _BER_TLV_TAG_H_ +#ifndef _BER_TLV_TAG_H_ +#define _BER_TLV_TAG_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -enum asn_tag_class { - ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ - ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ - ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ - ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ -}; -typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ + enum asn_tag_class + { + ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ + ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ + ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ + ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ + }; + typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ /* * Tag class is encoded together with tag value for optimization purposes. */ -#define BER_TAG_CLASS(tag) ((tag) & 0x3) -#define BER_TAG_VALUE(tag) ((tag) >> 2) -#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) +#define BER_TAG_CLASS(tag) ((tag)&0x3) +#define BER_TAG_VALUE(tag) ((tag) >> 2) +#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr) & 0x20) ? 1 : 0) -#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) +#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) -/* + /* * Several functions for printing the TAG in the canonical form * (i.e. "[PRIVATE 0]"). * Return values correspond to their libc counterparts (if any). */ -ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); -ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); -char *ber_tlv_tag_string(ber_tlv_tag_t tag); + ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); + ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); + char *ber_tlv_tag_string(ber_tlv_tag_t tag); -/* + /* * This function tries to fetch the tag from the input stream. * RETURN VALUES: * 0: More data expected than bufptr contains. * -1: Fatal error deciphering tag. * >0: Number of bytes used from bufptr. tag_r will contain the tag. */ -ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); + ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); -/* + /* * This function serializes the tag (T from TLV) in BER format. * It always returns number of bytes necessary to represent the tag, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ -size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); + size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); #ifdef __cplusplus } #endif -#endif /* _BER_TLV_TAG_H_ */ +#endif /* _BER_TLV_TAG_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constr_CHOICE.c b/src/core/libs/supl/asn-rrlp/constr_CHOICE.c index a9eb71941..75903fde7 100644 --- a/src/core/libs/supl/asn-rrlp/constr_CHOICE.c +++ b/src/core/libs/supl/asn-rrlp/constr_CHOICE.c @@ -46,8 +46,8 @@ */ #undef NEXT_PHASE #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) /* diff --git a/src/core/libs/supl/asn-rrlp/constr_CHOICE.h b/src/core/libs/supl/asn-rrlp/constr_CHOICE.h index 83404e6d4..264018481 100644 --- a/src/core/libs/supl/asn-rrlp/constr_CHOICE.h +++ b/src/core/libs/supl/asn-rrlp/constr_CHOICE.h @@ -3,55 +3,57 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_CHOICE_H_ -#define _CONSTR_CHOICE_H_ +#ifndef _CONSTR_CHOICE_H_ +#define _CONSTR_CHOICE_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_CHOICE_specifics_s { - /* + typedef struct asn_CHOICE_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_codec_ctx_t member */ - int pres_offset; /* Identifier of the present member */ - int pres_size; /* Size of the identifier (enum) */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_codec_ctx_t member */ + int pres_offset; /* Identifier of the present member */ + int pres_size; /* Size of the identifier (enum) */ - /* + /* * Tags to members mapping table. */ - asn_TYPE_tag2member_t *tag2el; - int tag2el_count; + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; - /* Canonical ordering of CHOICE elements, for PER */ - int *canonical_order; + /* Canonical ordering of CHOICE elements, for PER */ + int *canonical_order; - /* + /* * Extensions-related stuff. */ - int ext_start; /* First member of extensions, or -1 */ -} asn_CHOICE_specifics_t; + int ext_start; /* First member of extensions, or -1 */ + } asn_CHOICE_specifics_t; -/* + /* * A set specialized functions dealing with the CHOICE type. */ -asn_struct_free_f CHOICE_free; -asn_struct_print_f CHOICE_print; -asn_constr_check_f CHOICE_constraint; -ber_type_decoder_f CHOICE_decode_ber; -der_type_encoder_f CHOICE_encode_der; -xer_type_decoder_f CHOICE_decode_xer; -xer_type_encoder_f CHOICE_encode_xer; -per_type_decoder_f CHOICE_decode_uper; -per_type_encoder_f CHOICE_encode_uper; -asn_outmost_tag_f CHOICE_outmost_tag; + asn_struct_free_f CHOICE_free; + asn_struct_print_f CHOICE_print; + asn_constr_check_f CHOICE_constraint; + ber_type_decoder_f CHOICE_decode_ber; + der_type_encoder_f CHOICE_encode_der; + xer_type_decoder_f CHOICE_decode_xer; + xer_type_encoder_f CHOICE_encode_xer; + per_type_decoder_f CHOICE_decode_uper; + per_type_encoder_f CHOICE_encode_uper; + asn_outmost_tag_f CHOICE_outmost_tag; #ifdef __cplusplus } #endif -#endif /* _CONSTR_CHOICE_H_ */ +#endif /* _CONSTR_CHOICE_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.c b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.c index db3c92581..aba19bd26 100644 --- a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.c +++ b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.c @@ -47,10 +47,10 @@ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) -#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) +#define PHASE_OUT(ctx) do { (ctx)->phase = 10; } while(0) /* * Return a standardized complex structure. diff --git a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.h b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.h index 5f589d5c1..e2664a123 100644 --- a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.h +++ b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE.h @@ -2,59 +2,61 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SEQUENCE_H_ -#define _CONSTR_SEQUENCE_H_ +#ifndef _CONSTR_SEQUENCE_H_ +#define _CONSTR_SEQUENCE_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_SEQUENCE_specifics_s { - /* + typedef struct asn_SEQUENCE_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - /* + /* * Tags to members mapping table (sorted). */ - asn_TYPE_tag2member_t *tag2el; - int tag2el_count; + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; - /* + /* * Optional members of the extensions root (roms) or additions (aoms). * Meaningful for PER. */ - int *oms; /* Optional MemberS */ - int roms_count; /* Root optional members count */ - int aoms_count; /* Additions optional members count */ + int *oms; /* Optional MemberS */ + int roms_count; /* Root optional members count */ + int aoms_count; /* Additions optional members count */ - /* + /* * Description of an extensions group. */ - int ext_after; /* Extensions start after this member */ - int ext_before; /* Extensions stop before this member */ -} asn_SEQUENCE_specifics_t; + int ext_after; /* Extensions start after this member */ + int ext_before; /* Extensions stop before this member */ + } asn_SEQUENCE_specifics_t; -/* + /* * A set specialized functions dealing with the SEQUENCE type. */ -asn_struct_free_f SEQUENCE_free; -asn_struct_print_f SEQUENCE_print; -asn_constr_check_f SEQUENCE_constraint; -ber_type_decoder_f SEQUENCE_decode_ber; -der_type_encoder_f SEQUENCE_encode_der; -xer_type_decoder_f SEQUENCE_decode_xer; -xer_type_encoder_f SEQUENCE_encode_xer; -per_type_decoder_f SEQUENCE_decode_uper; -per_type_encoder_f SEQUENCE_encode_uper; + asn_struct_free_f SEQUENCE_free; + asn_struct_print_f SEQUENCE_print; + asn_constr_check_f SEQUENCE_constraint; + ber_type_decoder_f SEQUENCE_decode_ber; + der_type_encoder_f SEQUENCE_encode_der; + xer_type_decoder_f SEQUENCE_decode_xer; + xer_type_encoder_f SEQUENCE_encode_xer; + per_type_decoder_f SEQUENCE_decode_uper; + per_type_encoder_f SEQUENCE_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SEQUENCE_H_ */ +#endif /* _CONSTR_SEQUENCE_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE_OF.h b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE_OF.h index e2272f326..927ed5163 100644 --- a/src/core/libs/supl/asn-rrlp/constr_SEQUENCE_OF.h +++ b/src/core/libs/supl/asn-rrlp/constr_SEQUENCE_OF.h @@ -2,32 +2,33 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SEQUENCE_OF_H_ -#define _CONSTR_SEQUENCE_OF_H_ +#ifndef _CONSTR_SEQUENCE_OF_H_ +#define _CONSTR_SEQUENCE_OF_H_ #include -#include /* Implemented using SET OF */ +#include /* Implemented using SET OF */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* * A set specialized functions dealing with the SEQUENCE OF type. * Generally implemented using SET OF. */ -#define SEQUENCE_OF_free SET_OF_free -#define SEQUENCE_OF_print SET_OF_print -#define SEQUENCE_OF_constraint SET_OF_constraint -#define SEQUENCE_OF_decode_ber SET_OF_decode_ber -#define SEQUENCE_OF_decode_xer SET_OF_decode_xer -#define SEQUENCE_OF_decode_uper SET_OF_decode_uper -der_type_encoder_f SEQUENCE_OF_encode_der; -xer_type_encoder_f SEQUENCE_OF_encode_xer; -per_type_encoder_f SEQUENCE_OF_encode_uper; +#define SEQUENCE_OF_free SET_OF_free +#define SEQUENCE_OF_print SET_OF_print +#define SEQUENCE_OF_constraint SET_OF_constraint +#define SEQUENCE_OF_decode_ber SET_OF_decode_ber +#define SEQUENCE_OF_decode_xer SET_OF_decode_xer +#define SEQUENCE_OF_decode_uper SET_OF_decode_uper + der_type_encoder_f SEQUENCE_OF_encode_der; + xer_type_encoder_f SEQUENCE_OF_encode_xer; + per_type_encoder_f SEQUENCE_OF_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SET_OF_H_ */ +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constr_SET_OF.c b/src/core/libs/supl/asn-rrlp/constr_SET_OF.c index 11eac57a2..8b9c0669a 100644 --- a/src/core/libs/supl/asn-rrlp/constr_SET_OF.c +++ b/src/core/libs/supl/asn-rrlp/constr_SET_OF.c @@ -47,10 +47,10 @@ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) -#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) +#define PHASE_OUT(ctx) do { (ctx)->phase = 10; } while(0) /* * Return a standardized complex structure. @@ -915,7 +915,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, nelems = uper_get_length(pd, ct ? ct->effective_bits : -1, &repeat); ASN_DEBUG("Got to decode %d elements (eff %d)", - (int)nelems, (int)ct ? ct->effective_bits : -1); + (int)nelems, (long)ct ? ct->effective_bits : -1); if(nelems < 0) _ASN_DECODE_STARVED; } diff --git a/src/core/libs/supl/asn-rrlp/constr_SET_OF.h b/src/core/libs/supl/asn-rrlp/constr_SET_OF.h index bcd096629..52b446281 100644 --- a/src/core/libs/supl/asn-rrlp/constr_SET_OF.h +++ b/src/core/libs/supl/asn-rrlp/constr_SET_OF.h @@ -2,41 +2,43 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SET_OF_H_ -#define _CONSTR_SET_OF_H_ +#ifndef _CONSTR_SET_OF_H_ +#define _CONSTR_SET_OF_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_SET_OF_specifics_s { - /* + typedef struct asn_SET_OF_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - /* XER-specific stuff */ - int as_XMLValueList; /* The member type must be encoded like this */ -} asn_SET_OF_specifics_t; + /* XER-specific stuff */ + int as_XMLValueList; /* The member type must be encoded like this */ + } asn_SET_OF_specifics_t; -/* + /* * A set specialized functions dealing with the SET OF type. */ -asn_struct_free_f SET_OF_free; -asn_struct_print_f SET_OF_print; -asn_constr_check_f SET_OF_constraint; -ber_type_decoder_f SET_OF_decode_ber; -der_type_encoder_f SET_OF_encode_der; -xer_type_decoder_f SET_OF_decode_xer; -xer_type_encoder_f SET_OF_encode_xer; -per_type_decoder_f SET_OF_decode_uper; -per_type_encoder_f SET_OF_encode_uper; + asn_struct_free_f SET_OF_free; + asn_struct_print_f SET_OF_print; + asn_constr_check_f SET_OF_constraint; + ber_type_decoder_f SET_OF_decode_ber; + der_type_encoder_f SET_OF_encode_der; + xer_type_decoder_f SET_OF_decode_xer; + xer_type_encoder_f SET_OF_encode_xer; + per_type_decoder_f SET_OF_decode_uper; + per_type_encoder_f SET_OF_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SET_OF_H_ */ +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constr_TYPE.h b/src/core/libs/supl/asn-rrlp/constr_TYPE.h index 95507c809..0641f003c 100644 --- a/src/core/libs/supl/asn-rrlp/constr_TYPE.h +++ b/src/core/libs/supl/asn-rrlp/constr_TYPE.h @@ -9,158 +9,164 @@ * This structure even contains pointer to these encoding and decoding routines * for each defined ASN.1 type. */ -#ifndef _CONSTR_TYPE_H_ -#define _CONSTR_TYPE_H_ +#ifndef _CONSTR_TYPE_H_ +#define _CONSTR_TYPE_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ -struct asn_TYPE_member_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_member_s; /* Forward declaration */ -/* + /* * This type provides the context information for various ASN.1 routines, * primarily ones doing decoding. A member _asn_ctx of this type must be * included into certain target language's structures, such as compound types. */ -typedef struct asn_struct_ctx_s { - short phase; /* Decoding phase */ - short step; /* Elementary step of a phase */ - int context; /* Other context information */ - void *ptr; /* Decoder-specific stuff (stack elements) */ - ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ -} asn_struct_ctx_t; + typedef struct asn_struct_ctx_s + { + short phase; /* Decoding phase */ + short step; /* Elementary step of a phase */ + int context; /* Other context information */ + void *ptr; /* Decoder-specific stuff (stack elements) */ + ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ + } asn_struct_ctx_t; -#include /* Basic Encoding Rules decoder */ -#include /* Distinguished Encoding Rules encoder */ -#include /* Decoder of XER (XML, text) */ -#include /* Encoder into XER (XML, text) */ -#include /* Packet Encoding Rules decoder */ -#include /* Packet Encoding Rules encoder */ -#include /* Subtype constraints support */ +#include /* Basic Encoding Rules decoder */ +#include /* Distinguished Encoding Rules encoder */ +#include /* Decoder of XER (XML, text) */ +#include /* Encoder into XER (XML, text) */ +#include /* Packet Encoding Rules decoder */ +#include /* Packet Encoding Rules encoder */ +#include /* Subtype constraints support */ -/* + /* * Free the structure according to its specification. * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) * will not be freed. (It may be useful in case the structure is allocated * statically or arranged on the stack, yet its elements are allocated * dynamically.) */ -typedef void (asn_struct_free_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, int free_contents_only); -#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) -#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ - (asn_DEF).free_struct(&(asn_DEF),ptr,1) + typedef void(asn_struct_free_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, int free_contents_only); +#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF), ptr, 0) +#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ + (asn_DEF).free_struct(&(asn_DEF), ptr, 1) -/* + /* * Print the structure according to its specification. */ -typedef int (asn_struct_print_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, - int level, /* Indentation level */ - asn_app_consume_bytes_f *callback, void *app_key); + typedef int(asn_struct_print_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + int level, /* Indentation level */ + asn_app_consume_bytes_f *callback, void *app_key); -/* + /* * Return the outmost tag of the type. * If the type is untagged CHOICE, the dynamic operation is performed. * NOTE: This function pointer type is only useful internally. * Do not use it in your application. */ -typedef ber_tlv_tag_t (asn_outmost_tag_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); -/* The instance of the above function type; used internally. */ -asn_outmost_tag_f asn_TYPE_outmost_tag; + typedef ber_tlv_tag_t(asn_outmost_tag_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); + /* The instance of the above function type; used internally. */ + asn_outmost_tag_f asn_TYPE_outmost_tag; - -/* + + /* * The definitive description of the destination language's structure. */ -typedef struct asn_TYPE_descriptor_s { - char *name; /* A name of the ASN.1 type. "" in some cases. */ - char *xml_tag; /* Name used in XML tag */ + typedef struct asn_TYPE_descriptor_s + { + char *name; /* A name of the ASN.1 type. "" in some cases. */ + char *xml_tag; /* Name used in XML tag */ - /* + /* * Generalized functions for dealing with the specific type. * May be directly invoked by applications. */ - asn_struct_free_f *free_struct; /* Free the structure */ - asn_struct_print_f *print_struct; /* Human readable output */ - asn_constr_check_f *check_constraints; /* Constraints validator */ - ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ - der_type_encoder_f *der_encoder; /* Canonical DER encoder */ - xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ - xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ - per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ - per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ + asn_struct_free_f *free_struct; /* Free the structure */ + asn_struct_print_f *print_struct; /* Human readable output */ + asn_constr_check_f *check_constraints; /* Constraints validator */ + ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ + der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ - /*********************************************************************** + /*********************************************************************** * Internally useful members. Not to be used by applications directly. * **********************************************************************/ - /* + /* * Tags that are expected to occur. */ - asn_outmost_tag_f *outmost_tag; /* */ - ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ - int tags_count; /* Number of tags which are expected */ - ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ - int all_tags_count; /* Number of tags */ + asn_outmost_tag_f *outmost_tag; /* */ + ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + int tags_count; /* Number of tags which are expected */ + ber_tlv_tag_t *all_tags; /* Every tag for BER/containment */ + int all_tags_count; /* Number of tags */ - asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ - /* + /* * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). */ - struct asn_TYPE_member_s *elements; - int elements_count; + struct asn_TYPE_member_s *elements; + int elements_count; - /* + /* * Additional information describing the type, used by appropriate * functions above. */ - void *specifics; -} asn_TYPE_descriptor_t; + void *specifics; + } asn_TYPE_descriptor_t; -/* + /* * This type describes an element of the constructed type, * i.e. SEQUENCE, SET, CHOICE, etc. */ - enum asn_TYPE_flags_e { - ATF_NOFLAGS, - ATF_POINTER = 0x01, /* Represented by the pointer */ - ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ - }; -typedef struct asn_TYPE_member_s { - enum asn_TYPE_flags_e flags; /* Element's presentation flags */ - int optional; /* Following optional members, including current */ - int memb_offset; /* Offset of the element */ - ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ - int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ - asn_TYPE_descriptor_t *type; /* Member type descriptor */ - asn_constr_check_f *memb_constraints; /* Constraints validator */ - asn_per_constraints_t *per_constraints; /* PER compiled constraints */ - int (*default_value)(int setval, void **sptr); /* DEFAULT */ - char *name; /* ASN.1 identifier of the element */ -} asn_TYPE_member_t; + enum asn_TYPE_flags_e + { + ATF_NOFLAGS, + ATF_POINTER = 0x01, /* Represented by the pointer */ + ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ + }; + typedef struct asn_TYPE_member_s + { + enum asn_TYPE_flags_e flags; /* Element's presentation flags */ + int optional; /* Following optional members, including current */ + int memb_offset; /* Offset of the element */ + ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ + int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ + asn_TYPE_descriptor_t *type; /* Member type descriptor */ + asn_constr_check_f *memb_constraints; /* Constraints validator */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + int (*default_value)(int setval, void **sptr); /* DEFAULT */ + char *name; /* ASN.1 identifier of the element */ + } asn_TYPE_member_t; -/* + /* * BER tag to element number mapping. */ -typedef struct asn_TYPE_tag2member_s { - ber_tlv_tag_t el_tag; /* Outmost tag of the member */ - int el_no; /* Index of the associated member, base 0 */ - int toff_first; /* First occurence of the el_tag, relative */ - int toff_last; /* Last occurence of the el_tag, relatvie */ -} asn_TYPE_tag2member_t; + typedef struct asn_TYPE_tag2member_s + { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + int el_no; /* Index of the associated member, base 0 */ + int toff_first; /* First occurence of the el_tag, relative */ + int toff_last; /* Last occurence of the el_tag, relatvie */ + } asn_TYPE_tag2member_t; -/* + /* * This function is a wrapper around (td)->print_struct, which prints out * the contents of the target language's structure (struct_ptr) into the * file pointer (stream) in human readable form. @@ -169,12 +175,12 @@ typedef struct asn_TYPE_tag2member_s { * -1: Problem dumping the structure. * (See also xer_fprint() in xer_encoder.h) */ -int asn_fprint(FILE *stream, /* Destination stream descriptor */ - asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ - const void *struct_ptr); /* Structure to be printed */ + int asn_fprint(FILE *stream, /* Destination stream descriptor */ + asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ + const void *struct_ptr); /* Structure to be printed */ #ifdef __cplusplus } #endif -#endif /* _CONSTR_TYPE_H_ */ +#endif /* _CONSTR_TYPE_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/constraints.h b/src/core/libs/supl/asn-rrlp/constraints.h index 5032345ee..bc4fdb938 100644 --- a/src/core/libs/supl/asn-rrlp/constraints.h +++ b/src/core/libs/supl/asn-rrlp/constraints.h @@ -2,18 +2,19 @@ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ -#define _ASN1_CONSTRAINTS_VALIDATOR_H_ +#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ +#define _ASN1_CONSTRAINTS_VALIDATOR_H_ -#include /* Platform-dependent types */ +#include /* Platform-dependent types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Validate the structure according to the ASN.1 constraints. * If errbuf and errlen are given, they shall be pointing to the appropriate * buffer space and its length before calling this function. Alternatively, @@ -25,39 +26,39 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ * This function returns 0 in case all ASN.1 constraints are met * and -1 if one or more constraints were failed. */ -int -asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, /* Target language's structure */ - char *errbuf, /* Returned error description */ - size_t *errlen /* Length of the error description */ - ); + int asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Target language's structure */ + char *errbuf, /* Returned error description */ + size_t *errlen /* Length of the error description */ + ); -/* + /* * Generic type for constraint checking callback, * associated with every type descriptor. */ -typedef int (asn_constr_check_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, - asn_app_constraint_failed_f *optional_callback, /* Log the error */ - void *optional_app_key /* Opaque key passed to a callback */ - ); + typedef int(asn_constr_check_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *optional_callback, /* Log the error */ + void *optional_app_key /* Opaque key passed to a callback */ + ); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ -asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ + asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ + asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ /* * Invoke the callback with a complete error message. */ -#define _ASN_CTFAIL if(ctfailcb) ctfailcb +#define _ASN_CTFAIL \ + if (ctfailcb) ctfailcb #ifdef __cplusplus } #endif -#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ +#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/converter-sample.c b/src/core/libs/supl/asn-rrlp/converter-sample.c index 0a682a275..46136ebb3 100644 --- a/src/core/libs/supl/asn-rrlp/converter-sample.c +++ b/src/core/libs/supl/asn-rrlp/converter-sample.c @@ -384,7 +384,7 @@ buffer_dump() { (long)DynamicBuffer.length - 1, (long)8 - DynamicBuffer.unbits); } else { - fprintf(stderr, " %d\n", DynamicBuffer.length); + fprintf(stderr, " %ld\n", DynamicBuffer.length); } } @@ -774,11 +774,11 @@ static int write_out(const void *buffer, size_t size, void *key) { } static int argument_is_stdin(char *av[], int idx) { - if(strcmp(av[idx], "-")) { + if(strcmp(av[idx], "-") != 0) { return 0; /* Certainly not */ } else { /* This might be , unless `./program -- -` */ - if(strcmp(av[-1], "--")) + if(strcmp(av[-1], "--") != 0) return 1; else return 0; @@ -788,7 +788,7 @@ static int argument_is_stdin(char *av[], int idx) { static FILE *argument_to_file(char *av[], int idx) { return argument_is_stdin(av, idx) ? stdin - : fopen(av[idx], "r"); + : fopen(av[idx], "re"); } static char *argument_to_name(char *av[], int idx) { diff --git a/src/core/libs/supl/asn-rrlp/der_encoder.h b/src/core/libs/supl/asn-rrlp/der_encoder.h index 61431c6db..3eafbc281 100644 --- a/src/core/libs/supl/asn-rrlp/der_encoder.h +++ b/src/core/libs/supl/asn-rrlp/der_encoder.h @@ -2,67 +2,67 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _DER_ENCODER_H_ -#define _DER_ENCODER_H_ +#ifndef _DER_ENCODER_H_ +#define _DER_ENCODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * The DER encoder of any type. May be invoked by the application. * The ber_decode() function (ber_decoder.h) is an opposite of der_encode(). */ -asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key /* Arbitrary callback argument */ - ); + asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); -/* A variant of der_encode() which encodes data into the pre-allocated buffer */ -asn_enc_rval_t der_encode_to_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - void *buffer, /* Pre-allocated buffer */ - size_t buffer_size /* Initial buffer size (maximum) */ - ); + /* A variant of der_encode() which encodes data into the pre-allocated buffer */ + asn_enc_rval_t der_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ + ); -/* + /* * Type of the generic DER encoder. */ -typedef asn_enc_rval_t (der_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - ber_tlv_tag_t tag, - asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ - void *app_key /* Arbitrary callback argument */ - ); + typedef asn_enc_rval_t(der_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Write out leading TL[v] sequence according to the type definition. */ -ssize_t der_write_tags( - struct asn_TYPE_descriptor_s *type_descriptor, - size_t struct_length, - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - int last_tag_form, /* {0,!0}: prim, constructed */ - ber_tlv_tag_t tag, - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key - ); + ssize_t der_write_tags( + struct asn_TYPE_descriptor_s *type_descriptor, + size_t struct_length, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {0,!0}: prim, constructed */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key); #ifdef __cplusplus } #endif -#endif /* _DER_ENCODER_H_ */ +#endif /* _DER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/per_decoder.h b/src/core/libs/supl/asn-rrlp/per_decoder.h index 8397a545f..a28509464 100644 --- a/src/core/libs/supl/asn-rrlp/per_decoder.h +++ b/src/core/libs/supl/asn-rrlp/per_decoder.h @@ -2,55 +2,55 @@ * Copyright (c) 2005, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_DECODER_H_ -#define _PER_DECODER_H_ +#ifndef _PER_DECODER_H_ +#define _PER_DECODER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Unaligned PER decoder of a "complete encoding" as per X.691#10.1. * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. */ -asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of data buffer */ - ); + asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); -/* + /* * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. * WARNING: This call returns the number of BITS read from the stream. Beware. */ -asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size, /* Size of data buffer */ - int skip_bits, /* Number of unused leading bits, 0..7 */ - int unused_bits /* Number of unused tailing bits, 0..7 */ - ); + asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of data buffer */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); -/* + /* * Type of the type-specific PER decoder function. */ -typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void **struct_ptr, - asn_per_data_t *per_data - ); + typedef asn_dec_rval_t(per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void **struct_ptr, + asn_per_data_t *per_data); #ifdef __cplusplus } #endif -#endif /* _PER_DECODER_H_ */ +#endif /* _PER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/per_encoder.c b/src/core/libs/supl/asn-rrlp/per_encoder.c index f4bace060..8cf95347d 100644 --- a/src/core/libs/supl/asn-rrlp/per_encoder.c +++ b/src/core/libs/supl/asn-rrlp/per_encoder.c @@ -2,7 +2,7 @@ #include #include -static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); +static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t * /*constraints*/, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); asn_enc_rval_t uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { diff --git a/src/core/libs/supl/asn-rrlp/per_encoder.h b/src/core/libs/supl/asn-rrlp/per_encoder.h index 95a6506e4..896013095 100644 --- a/src/core/libs/supl/asn-rrlp/per_encoder.h +++ b/src/core/libs/supl/asn-rrlp/per_encoder.h @@ -2,68 +2,68 @@ * Copyright (c) 2006, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_ENCODER_H_ -#define _PER_ENCODER_H_ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. Use the following formula to convert to bytes: * bytes = ((.encoded + 7) / 8) */ -asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ - void *app_key /* Arbitrary callback argument */ -); + asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ + ); -/* + /* * A variant of uper_encode() which encodes data into the existing buffer * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. */ -asn_enc_rval_t uper_encode_to_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - void *buffer, /* Pre-allocated buffer */ - size_t buffer_size /* Initial buffer size (max) */ -); + asn_enc_rval_t uper_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ + ); -/* + /* * A variant of uper_encode_to_buffer() which allocates buffer itself. * Returns the number of bytes in the buffer or -1 in case of failure. * WARNING: This function produces a "Production of the complete encoding", * with length of at least one octet. Contrast this to precise bit-packing * encoding of uper_encode() and uper_encode_to_buffer(). */ -ssize_t uper_encode_to_new_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void *struct_ptr, /* Structure to be encoded */ - void **buffer_r /* Buffer allocated and returned */ -); + ssize_t uper_encode_to_new_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, /* Structure to be encoded */ + void **buffer_r /* Buffer allocated and returned */ + ); -/* + /* * Type of the generic PER encoder function. */ -typedef asn_enc_rval_t (per_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void *struct_ptr, - asn_per_outp_t *per_output -); + typedef asn_enc_rval_t(per_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, + asn_per_outp_t *per_output); #ifdef __cplusplus } #endif -#endif /* _PER_ENCODER_H_ */ +#endif /* _PER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/per_opentype.c b/src/core/libs/supl/asn-rrlp/per_opentype.c index c749c8c6c..32152e132 100644 --- a/src/core/libs/supl/asn-rrlp/per_opentype.c +++ b/src/core/libs/supl/asn-rrlp/per_opentype.c @@ -7,16 +7,17 @@ #include #include -typedef struct uper_ugot_key { - asn_per_data_t oldpd; /* Old per data source */ - size_t unclaimed; - size_t ot_moved; /* Number of bits moved by OT processing */ - int repeat; +typedef struct uper_ugot_key +{ + asn_per_data_t oldpd; /* Old per data source */ + size_t unclaimed; + size_t ot_moved; /* Number of bits moved by OT processing */ + int repeat; } uper_ugot_key; static int uper_ugot_refill(asn_per_data_t *pd); static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); -static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); +static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t * /*ctx*/, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); int asn_debug_indent; @@ -24,243 +25,272 @@ int asn_debug_indent; * Encode an "open type field". * #10.1, #10.2 */ -int -uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { - void *buf; - void *bptr; - ssize_t size; - size_t toGo; +int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) +{ + void *buf; + void *bptr; + ssize_t size; + size_t toGo; - ASN_DEBUG("Open type put %s ...", td->name); + ASN_DEBUG("Open type put %s ...", td->name); - size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); - if(size <= 0) return -1; + size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); + if (size <= 0) return -1; - for(bptr = buf, toGo = size; toGo;) { - ssize_t maySave = uper_put_length(po, toGo); - if(maySave < 0) break; - if(per_put_many_bits(po, bptr, maySave * 8)) break; - bptr = (char *)bptr + maySave; - toGo -= maySave; - } + for (bptr = buf, toGo = size; toGo;) + { + ssize_t maySave = uper_put_length(po, toGo); + if (maySave < 0) break; + if (per_put_many_bits(po, bptr, maySave * 8)) break; + bptr = (char *)bptr + maySave; + toGo -= maySave; + } - FREEMEM(buf); - if(toGo) return -1; + FREEMEM(buf); + if (toGo) return -1; - ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", - td->name, size); + ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", + td->name, size); - return 0; + return 0; } static asn_dec_rval_t uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - asn_dec_rval_t rv; - ssize_t chunk_bytes; - int repeat; - uint8_t *buf = 0; - size_t bufLen = 0; - size_t bufSize = 0; - asn_per_data_t spd; - size_t padding; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + asn_dec_rval_t rv; + ssize_t chunk_bytes; + int repeat; + uint8_t *buf = 0; + size_t bufLen = 0; + size_t bufSize = 0; + asn_per_data_t spd; + size_t padding; - _ASN_STACK_OVERFLOW_CHECK(ctx); + _ASN_STACK_OVERFLOW_CHECK(ctx); - ASN_DEBUG("Getting open type %s...", td->name); + ASN_DEBUG("Getting open type %s...", td->name); - do { - chunk_bytes = uper_get_length(pd, -1, &repeat); - if(chunk_bytes < 0) { - FREEMEM(buf); - _ASN_DECODE_STARVED; - } - if(bufLen + chunk_bytes > bufSize) { - void *ptr; - bufSize = chunk_bytes + (bufSize << 2); - ptr = REALLOC(buf, bufSize); - if(!ptr) { - FREEMEM(buf); - _ASN_DECODE_FAILED; - } - buf = ptr; - } - if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { - FREEMEM(buf); - _ASN_DECODE_STARVED; - } - bufLen += chunk_bytes; - } while(repeat); + do + { + chunk_bytes = uper_get_length(pd, -1, &repeat); + if (chunk_bytes < 0) + { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + if (bufLen + chunk_bytes > bufSize) + { + void *ptr; + bufSize = chunk_bytes + (bufSize << 2); + ptr = REALLOC(buf, bufSize); + if (!ptr) + { + FREEMEM(buf); + _ASN_DECODE_FAILED; + } + buf = ptr; + } + if (per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) + { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + bufLen += chunk_bytes; + } + while (repeat); - ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, - bufLen); + ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, + bufLen); - memset(&spd, 0, sizeof(spd)); - spd.buffer = buf; - spd.nbits = bufLen << 3; + memset(&spd, 0, sizeof(spd)); + spd.buffer = buf; + spd.nbits = bufLen << 3; - asn_debug_indent += 4; - rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); - asn_debug_indent -= 4; + asn_debug_indent += 4; + rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); + asn_debug_indent -= 4; - if(rv.code == RC_OK) { - /* Check padding validity */ - padding = spd.nbits - spd.nboff; - if(padding < 8 && per_get_few_bits(&spd, padding) == 0) { - /* Everything is cool */ - FREEMEM(buf); - return rv; - } - FREEMEM(buf); - if(padding >= 8) { - ASN_DEBUG("Too large padding %d in open type", padding); - _ASN_DECODE_FAILED; - } else { - ASN_DEBUG("Non-zero padding"); - _ASN_DECODE_FAILED; - } - } else { - FREEMEM(buf); - /* rv.code could be RC_WMORE, nonsense in this context */ - rv.code = RC_FAIL; /* Noone would give us more */ - } + if (rv.code == RC_OK) + { + /* Check padding validity */ + padding = spd.nbits - spd.nboff; + if (padding < 8 && per_get_few_bits(&spd, padding) == 0) + { + /* Everything is cool */ + FREEMEM(buf); + return rv; + } + FREEMEM(buf); + if (padding >= 8) + { + ASN_DEBUG("Too large padding %d in open type", padding); + _ASN_DECODE_FAILED; + } + else + { + ASN_DEBUG("Non-zero padding"); + _ASN_DECODE_FAILED; + } + } + else + { + FREEMEM(buf); + /* rv.code could be RC_WMORE, nonsense in this context */ + rv.code = RC_FAIL; /* Noone would give us more */ + } - return rv; + return rv; } static asn_dec_rval_t GCC_NOTUSED uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - uper_ugot_key arg; - asn_dec_rval_t rv; - ssize_t padding; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + uper_ugot_key arg; + asn_dec_rval_t rv; + ssize_t padding; - _ASN_STACK_OVERFLOW_CHECK(ctx); + _ASN_STACK_OVERFLOW_CHECK(ctx); - ASN_DEBUG("Getting open type %s from %s", td->name, - per_data_string(pd)); - arg.oldpd = *pd; - arg.unclaimed = 0; - arg.ot_moved = 0; - arg.repeat = 1; - pd->refill = uper_ugot_refill; - pd->refill_key = &arg; - pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ - pd->moved = 0; /* This now counts the open type size in bits */ + ASN_DEBUG("Getting open type %s from %s", td->name, + per_data_string(pd)); + arg.oldpd = *pd; + arg.unclaimed = 0; + arg.ot_moved = 0; + arg.repeat = 1; + pd->refill = uper_ugot_refill; + pd->refill_key = &arg; + pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ + pd->moved = 0; /* This now counts the open type size in bits */ - asn_debug_indent += 4; - rv = td->uper_decoder(ctx, td, constraints, sptr, pd); - asn_debug_indent -= 4; + asn_debug_indent += 4; + rv = td->uper_decoder(ctx, td, constraints, sptr, pd); + asn_debug_indent -= 4; -#define UPDRESTOREPD do { \ - /* buffer and nboff are valid, preserve them. */ \ - pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ - pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ - pd->refill = arg.oldpd.refill; \ - pd->refill_key = arg.oldpd.refill_key; \ - } while(0) +#define UPDRESTOREPD \ + do \ + { \ + /* buffer and nboff are valid, preserve them. */ \ + pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ + pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ + pd->refill = arg.oldpd.refill; \ + pd->refill_key = arg.oldpd.refill_key; \ + } \ + while (0) - if(rv.code != RC_OK) { - UPDRESTOREPD; - return rv; - } + if (rv.code != RC_OK) + { + UPDRESTOREPD; + return rv; + } - ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d" - , td->name, - per_data_string(pd), - per_data_string(&arg.oldpd), - arg.unclaimed, arg.repeat); + ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, + per_data_string(pd), + per_data_string(&arg.oldpd), + arg.unclaimed, arg.repeat); - padding = pd->moved % 8; - if(padding) { - int32_t pvalue; - if(padding > 7) { - ASN_DEBUG("Too large padding %d in open type", - padding); - rv.code = RC_FAIL; - UPDRESTOREPD; - return rv; - } - padding = 8 - padding; - ASN_DEBUG("Getting padding of %d bits", padding); - pvalue = per_get_few_bits(pd, padding); - switch(pvalue) { - case -1: - ASN_DEBUG("Padding skip failed"); - UPDRESTOREPD; - _ASN_DECODE_STARVED; - case 0: break; - default: - ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", - padding, (int)pvalue); - UPDRESTOREPD; - _ASN_DECODE_FAILED; - } - } - if(pd->nboff != pd->nbits) { - ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, - per_data_string(pd), per_data_string(&arg.oldpd)); - if(1) { - UPDRESTOREPD; - _ASN_DECODE_FAILED; - } else { - arg.unclaimed += pd->nbits - pd->nboff; - } - } + padding = pd->moved % 8; + if (padding) + { + int32_t pvalue; + if (padding > 7) + { + ASN_DEBUG("Too large padding %d in open type", + padding); + rv.code = RC_FAIL; + UPDRESTOREPD; + return rv; + } + padding = 8 - padding; + ASN_DEBUG("Getting padding of %d bits", padding); + pvalue = per_get_few_bits(pd, padding); + switch (pvalue) + { + case -1: + ASN_DEBUG("Padding skip failed"); + UPDRESTOREPD; + _ASN_DECODE_STARVED; + case 0: + break; + default: + ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", + padding, (int)pvalue); + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } + } + if (pd->nboff != pd->nbits) + { + ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, + per_data_string(pd), per_data_string(&arg.oldpd)); + if (1) + { + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } + else + { + arg.unclaimed += pd->nbits - pd->nboff; + } + } - /* Adjust pd back so it points to original data */ - UPDRESTOREPD; + /* Adjust pd back so it points to original data */ + UPDRESTOREPD; - /* Skip data not consumed by the decoder */ - if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); - if(arg.unclaimed) { - switch(per_skip_bits(pd, arg.unclaimed)) { - case -1: - ASN_DEBUG("Claim of %d failed", arg.unclaimed); - _ASN_DECODE_STARVED; - case 0: - ASN_DEBUG("Got claim of %d", arg.unclaimed); - break; - default: - /* Padding must be blank */ - ASN_DEBUG("Non-blank unconsumed padding"); - _ASN_DECODE_FAILED; - } - arg.unclaimed = 0; - } + /* Skip data not consumed by the decoder */ + if (arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); + if (arg.unclaimed) + { + switch (per_skip_bits(pd, arg.unclaimed)) + { + case -1: + ASN_DEBUG("Claim of %d failed", arg.unclaimed); + _ASN_DECODE_STARVED; + case 0: + ASN_DEBUG("Got claim of %d", arg.unclaimed); + break; + default: + /* Padding must be blank */ + ASN_DEBUG("Non-blank unconsumed padding"); + _ASN_DECODE_FAILED; + } + arg.unclaimed = 0; + } - if(arg.repeat) { - ASN_DEBUG("Not consumed the whole thing"); - rv.code = RC_FAIL; - return rv; - } + if (arg.repeat) + { + ASN_DEBUG("Not consumed the whole thing"); + rv.code = RC_FAIL; + return rv; + } - return rv; + return rv; } asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - - return uper_open_type_get_simple(ctx, td, constraints, - sptr, pd); - + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + return uper_open_type_get_simple(ctx, td, constraints, + sptr, pd); } -int -uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { - asn_TYPE_descriptor_t s_td; - asn_dec_rval_t rv; +int uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) +{ + asn_TYPE_descriptor_t s_td; + asn_dec_rval_t rv; - s_td.name = ""; - s_td.uper_decoder = uper_sot_suck; + s_td.name = ""; + s_td.uper_decoder = uper_sot_suck; - rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); - if(rv.code != RC_OK) - return -1; - else - return 0; + rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); + if (rv.code != RC_OK) + return -1; + else + return 0; } /* @@ -269,105 +299,122 @@ uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - asn_dec_rval_t rv; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + asn_dec_rval_t rv; - (void)ctx; - (void)td; - (void)constraints; - (void)sptr; + (void)ctx; + (void)td; + (void)constraints; + (void)sptr; - while(per_get_few_bits(pd, 24) >= 0); + while (per_get_few_bits(pd, 24) >= 0) + ; - rv.code = RC_OK; - rv.consumed = pd->moved; + rv.code = RC_OK; + rv.consumed = pd->moved; - return rv; + return rv; } static int -uper_ugot_refill(asn_per_data_t *pd) { - uper_ugot_key *arg = pd->refill_key; - ssize_t next_chunk_bytes, next_chunk_bits; - ssize_t avail; +uper_ugot_refill(asn_per_data_t *pd) +{ + uper_ugot_key *arg = pd->refill_key; + ssize_t next_chunk_bytes, next_chunk_bits; + ssize_t avail; - asn_per_data_t *oldpd = &arg->oldpd; + asn_per_data_t *oldpd = &arg->oldpd; - ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", - pd->moved, oldpd->moved); + ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", + pd->moved, oldpd->moved); - /* Advance our position to where pd is */ - oldpd->buffer = pd->buffer; - oldpd->nboff = pd->nboff; - oldpd->nbits -= pd->moved - arg->ot_moved; - oldpd->moved += pd->moved - arg->ot_moved; - arg->ot_moved = pd->moved; + /* Advance our position to where pd is */ + oldpd->buffer = pd->buffer; + oldpd->nboff = pd->nboff; + oldpd->nbits -= pd->moved - arg->ot_moved; + oldpd->moved += pd->moved - arg->ot_moved; + arg->ot_moved = pd->moved; - if(arg->unclaimed) { - /* Refill the container */ - if(per_get_few_bits(oldpd, 1)) - return -1; - if(oldpd->nboff == 0) { - assert(0); - return -1; - } - pd->buffer = oldpd->buffer; - pd->nboff = oldpd->nboff - 1; - pd->nbits = oldpd->nbits; - ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); - return 0; - } + if (arg->unclaimed) + { + /* Refill the container */ + if (per_get_few_bits(oldpd, 1)) + return -1; + if (oldpd->nboff == 0) + { + assert(0); + return -1; + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff - 1; + pd->nbits = oldpd->nbits; + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); + return 0; + } - if(!arg->repeat) { - ASN_DEBUG("Want more but refill doesn't have it"); - return -1; - } + if (!arg->repeat) + { + ASN_DEBUG("Want more but refill doesn't have it"); + return -1; + } - next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); - ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", - next_chunk_bytes, oldpd->moved, arg->repeat); - if(next_chunk_bytes < 0) return -1; - if(next_chunk_bytes == 0) { - pd->refill = 0; /* No more refills, naturally */ - assert(!arg->repeat); /* Implementation guarantee */ - } - next_chunk_bits = next_chunk_bytes << 3; - avail = oldpd->nbits - oldpd->nboff; - if(avail >= next_chunk_bits) { - pd->nbits = oldpd->nboff + next_chunk_bits; - arg->unclaimed = 0; - ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", - next_chunk_bits, oldpd->moved, - oldpd->nboff, oldpd->nbits, - oldpd->nbits - oldpd->nboff); - } else { - pd->nbits = oldpd->nbits; - arg->unclaimed = next_chunk_bits - avail; - ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); - } - pd->buffer = oldpd->buffer; - pd->nboff = oldpd->nboff; - ASN_DEBUG("Refilled pd%s old%s", - per_data_string(pd), per_data_string(oldpd)); - return 0; + next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); + ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", + next_chunk_bytes, oldpd->moved, arg->repeat); + if (next_chunk_bytes < 0) return -1; + if (next_chunk_bytes == 0) + { + pd->refill = 0; /* No more refills, naturally */ + assert(!arg->repeat); /* Implementation guarantee */ + } + next_chunk_bits = next_chunk_bytes << 3; + avail = oldpd->nbits - oldpd->nboff; + if (avail >= next_chunk_bits) + { + pd->nbits = oldpd->nboff + next_chunk_bits; + arg->unclaimed = 0; + ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", + next_chunk_bits, oldpd->moved, + oldpd->nboff, oldpd->nbits, + oldpd->nbits - oldpd->nboff); + } + else + { + pd->nbits = oldpd->nbits; + arg->unclaimed = next_chunk_bits - avail; + ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff; + ASN_DEBUG("Refilled pd%s old%s", + per_data_string(pd), per_data_string(oldpd)); + return 0; } static int -per_skip_bits(asn_per_data_t *pd, int skip_nbits) { - int hasNonZeroBits = 0; - while(skip_nbits > 0) { - int skip; - if(skip_nbits < skip) - skip = skip_nbits; - else - skip = 24; - skip_nbits -= skip; +per_skip_bits(asn_per_data_t *pd, int skip_nbits) +{ + int hasNonZeroBits = 0; + while (skip_nbits > 0) + { + int skip = 0; + if (skip_nbits < skip) + skip = skip_nbits; + else + skip = 24; + skip_nbits -= skip; - switch(per_get_few_bits(pd, skip)) { - case -1: return -1; /* Starving */ - case 0: continue; /* Skipped empty space */ - default: hasNonZeroBits = 1; continue; - } - } - return hasNonZeroBits; + switch (per_get_few_bits(pd, skip)) + { + case -1: + return -1; /* Starving */ + case 0: + continue; /* Skipped empty space */ + default: + hasNonZeroBits = 1; + continue; + } + } + return hasNonZeroBits; } diff --git a/src/core/libs/supl/asn-rrlp/per_opentype.h b/src/core/libs/supl/asn-rrlp/per_opentype.h index facfaa637..2110a794a 100644 --- a/src/core/libs/supl/asn-rrlp/per_opentype.h +++ b/src/core/libs/supl/asn-rrlp/per_opentype.h @@ -2,21 +2,22 @@ * Copyright (c) 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_OPENTYPE_H_ -#define _PER_OPENTYPE_H_ +#ifndef _PER_OPENTYPE_H_ +#define _PER_OPENTYPE_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); + asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); -int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); + int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); -int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); + int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); #ifdef __cplusplus } #endif -#endif /* _PER_OPENTYPE_H_ */ +#endif /* _PER_OPENTYPE_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/per_support.c b/src/core/libs/supl/asn-rrlp/per_support.c index e8299c730..02dd02094 100644 --- a/src/core/libs/supl/asn-rrlp/per_support.c +++ b/src/core/libs/supl/asn-rrlp/per_support.c @@ -9,26 +9,26 @@ char * per_data_string(asn_per_data_t *pd) { - static char buf[2][32]; - static int n; - n = (n+1) % 2; - snprintf(buf[n], sizeof(buf), - "{m=%d span %+d[%d..%d] (%d)}", - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, - pd->nbits - pd->nboff); - return buf[n]; + static char buf[2][32]; + static int n; + n = (n+1) % 2; + snprintf(buf[n], sizeof(buf[n]), + "{m=%ld span %+ld[%d..%d] (%d)}", + (long)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + (int)(pd->nbits - pd->nboff)); + return buf[n]; } void per_get_undo(asn_per_data_t *pd, int nbits) { - if((ssize_t)pd->nboff < nbits) { - assert((ssize_t)pd->nboff < nbits); - } else { - pd->nboff -= nbits; - pd->moved -= nbits; - } + if((ssize_t)pd->nboff < nbits) { + assert((ssize_t)pd->nboff < nbits); + } else { + pd->nboff -= nbits; + pd->moved -= nbits; + } } /* @@ -36,83 +36,84 @@ per_get_undo(asn_per_data_t *pd, int nbits) { */ int32_t per_get_few_bits(asn_per_data_t *pd, int nbits) { - size_t off; /* Next after last bit offset */ - ssize_t nleft; /* Number of bits left in this stream */ - uint32_t accum; - const uint8_t *buf; + size_t off; /* Next after last bit offset */ + ssize_t nleft; /* Number of bits left in this stream */ + uint32_t accum; + const uint8_t *buf; - if(nbits < 0) - return -1; + if(nbits < 0) + return -1; - nleft = pd->nbits - pd->nboff; - if(nbits > nleft) { - int32_t tailv, vhead; - if(!pd->refill || nbits > 31) return -1; - /* Accumulate unused bytes before refill */ - ASN_DEBUG("Obtain the rest %d bits (want %d)", nleft, nbits); - tailv = per_get_few_bits(pd, nleft); - if(tailv < 0) return -1; - /* Refill (replace pd contents with new data) */ - if(pd->refill(pd)) - return -1; - nbits -= nleft; - vhead = per_get_few_bits(pd, nbits); - /* Combine the rest of previous pd with the head of new one */ - tailv = (tailv << nbits) | vhead; /* Could == -1 */ - return tailv; - } + nleft = pd->nbits - pd->nboff; + if(nbits > nleft) { + int32_t tailv, vhead; + if(!pd->refill || nbits > 31) return -1; + /* Accumulate unused bytes before refill */ + ASN_DEBUG("Obtain the rest %d bits (want %d)", + (int)nleft, (int)nbits); + tailv = per_get_few_bits(pd, nleft); + if(tailv < 0) return -1; + /* Refill (replace pd contents with new data) */ + if(pd->refill(pd)) + return -1; + nbits -= nleft; + vhead = per_get_few_bits(pd, nbits); + /* Combine the rest of previous pd with the head of new one */ + tailv = (tailv << nbits) | vhead; /* Could == -1 */ + return tailv; + } - /* - * Normalize position indicator. - */ - if(pd->nboff >= 8) { - pd->buffer += (pd->nboff >> 3); - pd->nbits -= (pd->nboff & ~0x07); - pd->nboff &= 0x07; - } - pd->moved += nbits; - pd->nboff += nbits; - off = pd->nboff; - buf = pd->buffer; + /* + * Normalize position indicator. + */ + if(pd->nboff >= 8) { + pd->buffer += (pd->nboff >> 3); + pd->nbits -= (pd->nboff & ~0x07); + pd->nboff &= 0x07; + } + pd->moved += nbits; + pd->nboff += nbits; + off = pd->nboff; + buf = pd->buffer; - /* - * Extract specified number of bits. - */ - if(off <= 8) - accum = nbits ? (buf[0]) >> (8 - off) : 0; - else if(off <= 16) - accum = ((buf[0] << 8) + buf[1]) >> (16 - off); - else if(off <= 24) - accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); - else if(off <= 31) - accum = ((buf[0] << 24) + (buf[1] << 16) - + (buf[2] << 8) + (buf[3])) >> (32 - off); - else if(nbits <= 31) { - asn_per_data_t tpd = *pd; - /* Here are we with our 31-bits limit plus 1..7 bits offset. */ - per_get_undo(&tpd, nbits); - /* The number of available bits in the stream allow - * for the following operations to take place without - * invoking the ->refill() function */ - accum = per_get_few_bits(&tpd, nbits - 24) << 24; - accum |= per_get_few_bits(&tpd, 24); - } else { - per_get_undo(pd, nbits); - return -1; - } + /* + * Extract specified number of bits. + */ + if(off <= 8) + accum = nbits ? (buf[0]) >> (8 - off) : 0; + else if(off <= 16) + accum = ((buf[0] << 8) + buf[1]) >> (16 - off); + else if(off <= 24) + accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); + else if(off <= 31) + accum = ((buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + (buf[3])) >> (32 - off); + else if(nbits <= 31) { + asn_per_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + per_get_undo(&tpd, nbits); + /* The number of available bits in the stream allow + * for the following operations to take place without + * invoking the ->refill() function */ + accum = per_get_few_bits(&tpd, nbits - 24) << 24; + accum |= per_get_few_bits(&tpd, 24); + } else { + per_get_undo(pd, nbits); + return -1; + } - accum &= (((uint32_t)1 << nbits) - 1); + accum &= (((uint32_t)1 << nbits) - 1); - ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+d[%d..%d]:%02x (%d) => 0x%x]", - nbits, nleft, - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, - pd->buffer[0], - pd->nbits - pd->nboff, - (int)accum); + ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", + (int)nbits, (int)nleft, + (int)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + ((pd->buffer != NULL)?pd->buffer[0]:0), + (int)(pd->nbits - pd->nboff), + (int)accum); - return accum; + return accum; } /* @@ -120,70 +121,76 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { */ int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { - int32_t value; + int32_t value; - if(alright && (nbits & 7)) { - /* Perform right alignment of a first few bits */ - value = per_get_few_bits(pd, nbits & 0x07); - if(value < 0) return -1; - *dst++ = value; /* value is already right-aligned */ - nbits &= ~7; - } + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = per_get_few_bits(pd, nbits & 0x07); + if(value < 0) return -1; + *dst++ = value; /* value is already right-aligned */ + nbits &= ~7; + } - while(nbits) { - if(nbits >= 24) { - value = per_get_few_bits(pd, 24); - if(value < 0) return -1; - *(dst++) = value >> 16; - *(dst++) = value >> 8; - *(dst++) = value; - nbits -= 24; - } else { - value = per_get_few_bits(pd, nbits); - if(value < 0) return -1; - if(nbits & 7) { /* implies left alignment */ - value <<= 8 - (nbits & 7), - nbits += 8 - (nbits & 7); - if(nbits > 24) - *dst++ = value >> 24; - } - if(nbits > 16) - *dst++ = value >> 16; - if(nbits > 8) - *dst++ = value >> 8; - *dst++ = value; - break; - } - } + while(nbits) { + if(nbits >= 24) { + value = per_get_few_bits(pd, 24); + if(value < 0) return -1; + *(dst++) = value >> 16; + *(dst++) = value >> 8; + *(dst++) = value; + nbits -= 24; + } else { + value = per_get_few_bits(pd, nbits); + if(value < 0) return -1; + if(nbits & 7) { /* implies left alignment */ + value <<= 8 - (nbits & 7), + nbits += 8 - (nbits & 7); + if(nbits > 24) + *dst++ = value >> 24; + } + if(nbits > 16) + *dst++ = value >> 16; + if(nbits > 8) + *dst++ = value >> 8; + *dst++ = value; + break; + } + } - return 0; + return 0; } /* - * Get the length "n" from the stream. + * X.691-201508 #10.9 General rules for encoding a length determinant. + * Get the optionally constrained length "n" from the stream. */ ssize_t uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { - ssize_t value; + ssize_t value; - *repeat = 0; + *repeat = 0; - if(ebits >= 0) return per_get_few_bits(pd, ebits); + /* #11.9.4.1 Encoding if constrained (according to effective bits) */ + if(ebits >= 0 && ebits <= 16) { + return per_get_few_bits(pd, ebits); + } - value = per_get_few_bits(pd, 8); - if(value < 0) return -1; - if((value & 128) == 0) /* #10.9.3.6 */ - return (value & 0x7F); - if((value & 64) == 0) { /* #10.9.3.7 */ - value = ((value & 63) << 8) | per_get_few_bits(pd, 8); - if(value < 0) return -1; - return value; - } - value &= 63; /* this is "m" from X.691, #10.9.3.8 */ - if(value < 1 || value > 4) - return -1; - *repeat = 1; - return (16384 * value); + value = per_get_few_bits(pd, 8); + if((value & 0x80) == 0) { /* #11.9.3.6 */ + return (value & 0x7F); + } else if((value & 0x40) == 0) { /* #11.9.3.7 */ + /* bit 8 ... set to 1 and bit 7 ... set to zero */ + value = ((value & 0x3f) << 8) | per_get_few_bits(pd, 8); + return value; /* potential -1 from per_get_few_bits passes through. */ + } else if(value < 0) { + return -1; + } + value &= 0x3f; /* this is "m" from X.691, #11.9.3.8 */ + if(value < 1 || value > 4) { + return -1; /* Prohibited by #11.9.3.8 */ + } + *repeat = 1; + return (16384 * value); } /* @@ -193,21 +200,21 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { */ ssize_t uper_get_nslength(asn_per_data_t *pd) { - ssize_t length; + ssize_t length; - ASN_DEBUG("Getting normally small length"); + ASN_DEBUG("Getting normally small length"); - if(per_get_few_bits(pd, 1) == 0) { - length = per_get_few_bits(pd, 6) + 1; - if(length <= 0) return -1; - ASN_DEBUG("l=%d", length); - return length; - } else { - int repeat; - length = uper_get_length(pd, -1, &repeat); - if(length >= 0 && !repeat) return length; - return -1; /* Error, or do not support >16K extensions */ - } + if(per_get_few_bits(pd, 1) == 0) { + length = per_get_few_bits(pd, 6) + 1; + if(length <= 0) return -1; + ASN_DEBUG("l=%d", (int)length); + return length; + } else { + int repeat; + length = uper_get_length(pd, -1, &repeat); + if(length >= 0 && !repeat) return length; + return -1; /* Error, or do not support >16K extensions */ + } } /* @@ -216,135 +223,215 @@ uper_get_nslength(asn_per_data_t *pd) { */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd) { - ssize_t value; + ssize_t value; - value = per_get_few_bits(pd, 7); - if(value & 64) { /* implicit (value < 0) */ - value &= 63; - value <<= 2; - value |= per_get_few_bits(pd, 2); - if(value & 128) /* implicit (value < 0) */ - return -1; - if(value == 0) - return 0; - if(value >= 3) - return -1; - value = per_get_few_bits(pd, 8 * value); - return value; - } + value = per_get_few_bits(pd, 7); + if(value & 64) { /* implicit (value < 0) */ + value &= 63; + value <<= 2; + value |= per_get_few_bits(pd, 2); + if(value & 128) /* implicit (value < 0) */ + return -1; + if(value == 0) + return 0; + if(value >= 3) + return -1; + value = per_get_few_bits(pd, 8 * value); + return value; + } - return value; + return value; } /* - * Put the normally small non-negative whole number. - * X.691, #10.6 + * X.691-11/2008, #11.6 + * Encoding of a normally small non-negative whole number */ int uper_put_nsnnwn(asn_per_outp_t *po, int n) { - int bytes; + int bytes; - if(n <= 63) { - if(n < 0) return -1; - return per_put_few_bits(po, n, 7); - } - if(n < 256) - bytes = 1; - else if(n < 65536) - bytes = 2; - else if(n < 256 * 65536) - bytes = 3; - else - return -1; /* This is not a "normally small" value */ - if(per_put_few_bits(po, bytes, 8)) - return -1; + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; - return per_put_few_bits(po, n, 8 * bytes); + return per_put_few_bits(po, n, 8 * bytes); } +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { + unsigned long lhalf; /* Lower half of the number*/ + long half; + + if(nbits <= 31) { + half = per_get_few_bits(pd, nbits); + if(half < 0) return -1; + *out_value = half; + return 0; + } + + if((size_t)nbits > 8 * sizeof(*out_value)) + return -1; /* RANGE */ + + half = per_get_few_bits(pd, 31); + if(half < 0) return -1; + + if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) + return -1; + + *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; + return 0; +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) { + /* + * Assume signed number can be safely coerced into + * unsigned of the same range. + * The following testing code will likely be optimized out + * by compiler if it is true. + */ + unsigned long uvalue1 = ULONG_MAX; + long svalue = uvalue1; + unsigned long uvalue2 = svalue; + assert(uvalue1 == uvalue2); + return uper_put_constrained_whole_number_u(po, v, nbits); +} + +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) { + if(nbits <= 31) { + return per_put_few_bits(po, v, nbits); + } else { + /* Put higher portion first, followed by lower 31-bit */ + if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) + return -1; + return per_put_few_bits(po, v, 31); + } +} + +int +per_put_aligned_flush(asn_per_outp_t *po) { + uint32_t unused_bits = (0x7 & (8 - (po->nboff & 0x07))); + size_t complete_bytes = + (po->buffer ? po->buffer - po->tmpspace : 0) + ((po->nboff + 7) >> 3); + + if(unused_bits) { + po->buffer[po->nboff >> 3] &= ~0 << unused_bits; + } + + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) { + return -1; + } else { + po->buffer = po->tmpspace; + po->nboff = 0; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + return 0; + } +} + /* * Put a small number of bits (<= 31). */ int per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { - size_t off; /* Next after last bit offset */ - size_t omsk; /* Existing last byte meaningful bits mask */ - uint8_t *buf; + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; - if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; - ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", - obits, (int)bits, po->buffer, po->nboff); + ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", + obits, (int)bits, po->buffer, (int)po->nboff); - /* - * Normalize position indicator. - */ - if(po->nboff >= 8) { - po->buffer += (po->nboff >> 3); - po->nbits -= (po->nboff & ~0x07); - po->nboff &= 0x07; - } + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } - /* - * Flush whole-bytes output, if necessary. - */ - if(po->nboff + obits > po->nbits) { - int complete_bytes = (po->buffer - po->tmpspace); - ASN_DEBUG("[PER output %d complete + %d]", - complete_bytes, po->flushed_bytes); - if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) - return -1; - if(po->nboff) - po->tmpspace[0] = po->buffer[0]; - po->buffer = po->tmpspace; - po->nbits = 8 * sizeof(po->tmpspace); - po->flushed_bytes += complete_bytes; - } + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + size_t complete_bytes; + if(!po->buffer) po->buffer = po->tmpspace; + complete_bytes = (po->buffer - po->tmpspace); + ASN_DEBUG("[PER output %ld complete + %ld]", + (long)complete_bytes, (long)po->flushed_bytes); + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + } - /* - * Now, due to sizeof(tmpspace), we are guaranteed large enough space. - */ - buf = po->buffer; - omsk = ~((1 << (8 - po->nboff)) - 1); - off = (po->nboff += obits); + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff + obits); - /* Clear data of debris before meaningful bits */ - bits &= (((uint32_t)1 << obits) - 1); + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); - ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, - (int)bits, (int)bits, - po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, + (int)bits, (int)bits, + (int)po->nboff, (int)off, + buf[0], (int)(omsk&0xff), + (int)(buf[0] & omsk)); - if(off <= 8) /* Completely within 1 byte */ - bits <<= (8 - off), - buf[0] = (buf[0] & omsk) | bits; - else if(off <= 16) - bits <<= (16 - off), - buf[0] = (buf[0] & omsk) | (bits >> 8), - buf[1] = bits; - else if(off <= 24) - bits <<= (24 - off), - buf[0] = (buf[0] & omsk) | (bits >> 16), - buf[1] = bits >> 8, - buf[2] = bits; - else if(off <= 31) - bits <<= (32 - off), - buf[0] = (buf[0] & omsk) | (bits >> 24), - buf[1] = bits >> 16, - buf[2] = bits >> 8, - buf[3] = bits; - else { - ASN_DEBUG("->[PER out split %d]", obits); - per_put_few_bits(po, bits >> 8, 24); - per_put_few_bits(po, bits, obits - 24); - ASN_DEBUG("<-[PER out split %d]", obits); - } + if(off <= 8) /* Completely within 1 byte */ + po->nboff = off, + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + po->nboff = off, + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + po->nboff = off, + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + po->nboff = off, + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + if(per_put_few_bits(po, bits >> (obits - 24), 24)) return -1; + if(per_put_few_bits(po, bits, obits - 24)) return -1; + } - ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", - (int)bits, (int)bits, buf[0], po->buffer - po->tmpspace); + ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", + (int)bits, (int)bits, buf[0], + (long)(po->buffer - po->tmpspace)); - return 0; + return 0; } @@ -354,30 +441,30 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { - while(nbits) { - uint32_t value; + while(nbits) { + uint32_t value; - if(nbits >= 24) { - value = (src[0] << 16) | (src[1] << 8) | src[2]; - src += 3; - nbits -= 24; - if(per_put_few_bits(po, value, 24)) - return -1; - } else { - value = src[0]; - if(nbits > 8) - value = (value << 8) | src[1]; - if(nbits > 16) - value = (value << 8) | src[2]; - if(nbits & 0x07) - value >>= (8 - (nbits & 0x07)); - if(per_put_few_bits(po, value, nbits)) - return -1; - break; - } - } + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(per_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(per_put_few_bits(po, value, nbits)) + return -1; + break; + } + } - return 0; + return 0; } /* @@ -386,18 +473,18 @@ per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { ssize_t uper_put_length(asn_per_outp_t *po, size_t length) { - if(length <= 127) /* #10.9.3.6 */ - return per_put_few_bits(po, length, 8) - ? -1 : (ssize_t)length; - else if(length < 16384) /* #10.9.3.7 */ - return per_put_few_bits(po, length|0x8000, 16) - ? -1 : (ssize_t)length; + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + else if(length < 16384) /* #10.9.3.7 */ + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; - length >>= 14; - if(length > 4) length = 4; + length >>= 14; + if(length > 4) length = 4; - return per_put_few_bits(po, 0xC0 | length, 8) - ? -1 : (ssize_t)(length << 14); + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); } @@ -409,17 +496,16 @@ uper_put_length(asn_per_outp_t *po, size_t length) { int uper_put_nslength(asn_per_outp_t *po, size_t length) { - if(length <= 64) { - /* #10.9.3.4 */ - if(length == 0) return -1; - return per_put_few_bits(po, length-1, 7) ? -1 : 0; - } else { - if(uper_put_length(po, length) != (ssize_t)length) { - /* This might happen in case of >16K extensions */ - return -1; - } - } + if(length <= 64) { + /* #10.9.3.4 */ + if(length == 0) return -1; + return per_put_few_bits(po, length-1, 7) ? -1 : 0; + } else { + if(uper_put_length(po, length) != (ssize_t)length) { + /* This might happen in case of >16K extensions */ + return -1; + } + } - return 0; + return 0; } - diff --git a/src/core/libs/supl/asn-rrlp/per_support.h b/src/core/libs/supl/asn-rrlp/per_support.h index 7cb1a0ca3..c99f12291 100644 --- a/src/core/libs/supl/asn-rrlp/per_support.h +++ b/src/core/libs/supl/asn-rrlp/per_support.h @@ -3,126 +3,146 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_SUPPORT_H_ -#define _PER_SUPPORT_H_ +#ifndef _PER_SUPPORT_H_ +#define _PER_SUPPORT_H_ -#include /* Platform-specific types */ +#include /* Platform-specific types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Pre-computed PER constraints. */ -typedef struct asn_per_constraint_s { - enum asn_per_constraint_flags { - APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ - APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ - APC_CONSTRAINED = 0x2, /* Fully constrained */ - APC_EXTENSIBLE = 0x4 /* May have extension */ - } flags; - int range_bits; /* Full number of bits in the range */ - int effective_bits; /* Effective bits */ - long lower_bound; /* "lb" value */ - long upper_bound; /* "ub" value */ -} asn_per_constraint_t; -typedef struct asn_per_constraints_s { - asn_per_constraint_t value; - asn_per_constraint_t size; - int (*value2code)(unsigned int value); - int (*code2value)(unsigned int code); -} asn_per_constraints_t; + typedef const struct asn_per_constraint_s + { + enum asn_per_constraint_flags + { + APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ + APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ + APC_CONSTRAINED = 0x2, /* Fully constrained */ + APC_EXTENSIBLE = 0x4 /* May have extension */ + } flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ + long lower_bound; /* "lb" value */ + long upper_bound; /* "ub" value */ + } asn_per_constraint_t; + typedef const struct asn_per_constraints_s + { + struct asn_per_constraint_s value; + struct asn_per_constraint_s size; + int (*value2code)(unsigned int value); + int (*code2value)(unsigned int code); + } asn_per_constraints_t; -/* + /* * This structure describes a position inside an incoming PER bit stream. */ -typedef struct asn_per_data_s { - const uint8_t *buffer; /* Pointer to the octet stream */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits in the stream */ - size_t moved; /* Number of bits moved through this bit stream */ - int (*refill)(struct asn_per_data_s *); - void *refill_key; -} asn_per_data_t; + typedef struct asn_per_data_s + { + const uint8_t *buffer; /* Pointer to the octet stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ + size_t moved; /* Number of bits moved through this bit stream */ + int (*refill)(struct asn_per_data_s *); + void *refill_key; + } asn_per_data_t; -/* + /* * Extract a small number of bits (<= 31) from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ -int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); + int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); -/* Undo the immediately preceeding "get_few_bits" operation */ -void per_get_undo(asn_per_data_t *per_data, int get_nbits); + /* Undo the immediately preceeding "get_few_bits" operation */ + void per_get_undo(asn_per_data_t *per_data, int get_nbits); -/* + /* * Extract a large number of bits from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ -int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, - int get_nbits); + int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, + int get_nbits); -/* + /* * Get the length "n" from the Unaligned PER stream. */ -ssize_t uper_get_length(asn_per_data_t *pd, - int effective_bound_bits, - int *repeat); + ssize_t uper_get_length(asn_per_data_t *pd, + int effective_bound_bits, + int *repeat); -/* + /* * Get the normally small length "n". */ -ssize_t uper_get_nslength(asn_per_data_t *pd); + ssize_t uper_get_nslength(asn_per_data_t *pd); -/* + /* * Get the normally small non-negative whole number. */ -ssize_t uper_get_nsnnwn(asn_per_data_t *pd); + ssize_t uper_get_nsnnwn(asn_per_data_t *pd); -/* Non-thread-safe debugging function, don't use it */ -char *per_data_string(asn_per_data_t *pd); + /* X.691-2008/11, #11.5.6 */ + int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); -/* + /* Non-thread-safe debugging function, don't use it */ + char *per_data_string(asn_per_data_t *pd); + + /* * This structure supports forming PER output. */ -typedef struct asn_per_outp_s { - uint8_t *buffer; /* Pointer into the (tmpspace) */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits left in (tmpspace) */ - uint8_t tmpspace[32]; /* Preliminary storage to hold data */ - int (*outper)(const void *data, size_t size, void *op_key); - void *op_key; /* Key for (outper) data callback */ - size_t flushed_bytes; /* Bytes already flushed through (outper) */ -} asn_per_outp_t; + typedef struct asn_per_outp_s + { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*outper)(const void *data, size_t size, void *op_key); + void *op_key; /* Key for (outper) data callback */ + size_t flushed_bytes; /* Bytes already flushed through (outper) */ + } asn_per_outp_t; -/* Output a small number of bits (<= 31) */ -int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); + /* Output a small number of bits (<= 31) */ + int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); -/* Output a large number of bits */ -int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + /* Output a large number of bits */ + int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); -/* + /* + * Flush whole bytes (0 or more) through (outper) member. + * The least significant bits which are not used are guaranteed to be set to 0. + * Returns -1 if callback returns -1. Otherwise, 0. + */ + int per_put_aligned_flush(asn_per_outp_t *po); + + /* X.691-2008/11, #11.5 */ + int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); + int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); + + /* * Put the length "n" to the Unaligned PER stream. * This function returns the number of units which may be flushed * in the next units saving iteration. */ -ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); -/* + /* * Put the normally small length "n" to the Unaligned PER stream. * Returns 0 or -1. */ -int uper_put_nslength(asn_per_outp_t *po, size_t length); + int uper_put_nslength(asn_per_outp_t *po, size_t length); -/* + /* * Put the normally small non-negative whole number. */ -int uper_put_nsnnwn(asn_per_outp_t *po, int n); + int uper_put_nsnnwn(asn_per_outp_t *po, int n); #ifdef __cplusplus } #endif -#endif /* _PER_SUPPORT_H_ */ +#endif /* _PER_SUPPORT_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/xer_decoder.c b/src/core/libs/supl/asn-rrlp/xer_decoder.c index 161dc78ce..ef5f06481 100644 --- a/src/core/libs/supl/asn-rrlp/xer_decoder.c +++ b/src/core/libs/supl/asn-rrlp/xer_decoder.c @@ -181,12 +181,12 @@ xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { #define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ ssize_t converted_size = body_receiver \ (struct_key, chunk_buf, chunk_size, \ - (size_t)chunk_size < size); \ + (size_t)(chunk_size) < (size)); \ if(converted_size == -1) RETURN(RC_FAIL); \ if(converted_size == 0 \ - && size == (size_t)chunk_size) \ + && (size) == (size_t)(chunk_size)) \ RETURN(RC_WMORE); \ - chunk_size = converted_size; \ + (chunk_size) = converted_size; \ } while(0) #define XER_GOT_EMPTY() do { \ if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ diff --git a/src/core/libs/supl/asn-rrlp/xer_decoder.h b/src/core/libs/supl/asn-rrlp/xer_decoder.h index cf0d846fe..52444af51 100644 --- a/src/core/libs/supl/asn-rrlp/xer_decoder.h +++ b/src/core/libs/supl/asn-rrlp/xer_decoder.h @@ -2,105 +2,104 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_DECODER_H_ -#define _XER_DECODER_H_ +#ifndef _XER_DECODER_H_ +#define _XER_DECODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * The XER decoder of any ASN.1 type. May be invoked by the application. */ -asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of data buffer */ - ); + asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); -/* + /* * Type of the type-specific XER decoder function. */ -typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, - const char *opt_mname, /* Member name */ - const void *buf_ptr, size_t size - ); + typedef asn_dec_rval_t(xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, + const char *opt_mname, /* Member name */ + const void *buf_ptr, size_t size); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Generalized function for decoding the primitive values. * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 * and others. This function should not be used by applications, as its API * is subject to changes. */ -asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, - asn_struct_ctx_t *ctx, /* Type decoder context */ - void *struct_key, /* Treated as opaque pointer */ - const char *xml_tag, /* Expected XML tag name */ - const void *buf_ptr, size_t size, - int (*opt_unexpected_tag_decoder) - (void *struct_key, const void *chunk_buf, size_t chunk_size), - ssize_t (*body_receiver) - (void *struct_key, const void *chunk_buf, size_t chunk_size, - int have_more) - ); + asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, /* Treated as opaque pointer */ + const char *xml_tag, /* Expected XML tag name */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder)(void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver)(void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more)); -/* + /* * Fetch the next XER (XML) token from the stream. * The function returns the number of bytes occupied by the chunk type, * returned in the _ch_type. The _ch_type is only set (and valid) when * the return value is greater than 0. */ - typedef enum pxer_chunk_type { - PXER_TAG, /* Complete XER tag */ - PXER_TEXT, /* Plain text between XER tags */ - PXER_COMMENT /* A comment, may be part of */ - } pxer_chunk_type_e; -ssize_t xer_next_token(int *stateContext, - const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); + typedef enum pxer_chunk_type + { + PXER_TAG, /* Complete XER tag */ + PXER_TEXT, /* Plain text between XER tags */ + PXER_COMMENT /* A comment, may be part of */ + } pxer_chunk_type_e; + ssize_t xer_next_token(int *stateContext, + const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); -/* + /* * This function checks the buffer against the tag name is expected to occur. */ - typedef enum xer_check_tag { - XCT_BROKEN = 0, /* The tag is broken */ - XCT_OPENING = 1, /* This is the tag */ - XCT_CLOSING = 2, /* This is the tag */ - XCT_BOTH = 3, /* This is the tag */ - XCT__UNK__MASK = 4, /* Mask of everything unexpected */ - XCT_UNKNOWN_OP = 5, /* Unexpected tag */ - XCT_UNKNOWN_CL = 6, /* Unexpected tag */ - XCT_UNKNOWN_BO = 7 /* Unexpected tag */ - } xer_check_tag_e; -xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, - const char *need_tag); + typedef enum xer_check_tag + { + XCT_BROKEN = 0, /* The tag is broken */ + XCT_OPENING = 1, /* This is the tag */ + XCT_CLOSING = 2, /* This is the tag */ + XCT_BOTH = 3, /* This is the tag */ + XCT__UNK__MASK = 4, /* Mask of everything unexpected */ + XCT_UNKNOWN_OP = 5, /* Unexpected tag */ + XCT_UNKNOWN_CL = 6, /* Unexpected tag */ + XCT_UNKNOWN_BO = 7 /* Unexpected tag */ + } xer_check_tag_e; + xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, + const char *need_tag); -/* + /* * Check whether this buffer consists of entirely XER whitespace characters. * RETURN VALUES: * 1: Whitespace or empty string * 0: Non-whitespace */ -int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); + int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); -/* + /* * Skip the series of anticipated extensions. */ -int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); + int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); #ifdef __cplusplus } #endif -#endif /* _XER_DECODER_H_ */ +#endif /* _XER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/xer_encoder.h b/src/core/libs/supl/asn-rrlp/xer_encoder.h index 055e73c0c..5b640d425 100644 --- a/src/core/libs/supl/asn-rrlp/xer_encoder.h +++ b/src/core/libs/supl/asn-rrlp/xer_encoder.h @@ -2,35 +2,37 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_ENCODER_H_ -#define _XER_ENCODER_H_ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ -enum xer_encoder_flags_e { - /* Mode of encoding */ - XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ - XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ -}; + /* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ + enum xer_encoder_flags_e + { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ + }; -/* + /* * The XER encoder of any type. May be invoked by the application. */ -asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key /* Arbitrary callback argument */ - ); + asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); -/* + /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen file pointer. * RETURN VALUES: @@ -38,22 +40,22 @@ asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, * -1: Problem printing the structure. * WARNING: No sensible errno value is returned. */ -int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); + int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); -/* + /* * Type of the generic XER encoder. */ -typedef asn_enc_rval_t (xer_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - int ilevel, /* Level of indentation */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ - void *app_key /* Arbitrary callback argument */ - ); + typedef asn_enc_rval_t(xer_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); #ifdef __cplusplus } #endif -#endif /* _XER_ENCODER_H_ */ +#endif /* _XER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-rrlp/xer_support.c b/src/core/libs/supl/asn-rrlp/xer_support.c index 9e34e6923..cfa30e674 100644 --- a/src/core/libs/supl/asn-rrlp/xer_support.c +++ b/src/core/libs/supl/asn-rrlp/xer_support.c @@ -60,7 +60,7 @@ _charclass[256] = { #define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ int _ret; \ pstate_e ns = _ns; \ - ssize_t _sz = (p - chunk_start) + _current_too; \ + ssize_t _sz = (p - chunk_start) + (_current_too); \ if (!_sz) { \ /* Shortcut */ \ state = _ns; \ @@ -68,11 +68,11 @@ _charclass[256] = { } \ _ret = cb(type, chunk_start, _sz, key); \ if(_ret < _sz) { \ - if(_current_too && _ret == -1) \ + if((_current_too) && _ret == -1) \ state = ns; \ goto finish; \ } \ - chunk_start = p + _current_too; \ + chunk_start = p + (_current_too); \ state = ns; \ } while(0) diff --git a/src/core/libs/supl/asn-rrlp/xer_support.h b/src/core/libs/supl/asn-rrlp/xer_support.h index 8b01944ab..13d8bbd06 100644 --- a/src/core/libs/supl/asn-rrlp/xer_support.h +++ b/src/core/libs/supl/asn-rrlp/xer_support.h @@ -3,31 +3,33 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_SUPPORT_H_ -#define _XER_SUPPORT_H_ +#ifndef _XER_SUPPORT_H_ +#define _XER_SUPPORT_H_ -#include /* Platform-specific types */ +#include /* Platform-specific types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Types of data transferred to the application. */ -typedef enum { - PXML_TEXT, /* Plain text between XML tags. */ - PXML_TAG, /* A tag, starting with '<'. */ - PXML_COMMENT, /* An XML comment, including "". */ - /* + typedef enum + { + PXML_TEXT, /* Plain text between XML tags. */ + PXML_TAG, /* A tag, starting with '<'. */ + PXML_COMMENT, /* An XML comment, including "". */ + /* * The following chunk types are reported if the chunk * terminates the specified XML element. */ - PXML_TAG_END, /* Tag ended */ - PXML_COMMENT_END /* Comment ended */ -} pxml_chunk_type_e; + PXML_TAG_END, /* Tag ended */ + PXML_COMMENT_END /* Comment ended */ + } pxml_chunk_type_e; -/* + /* * Callback function that is called by the parser when parsed data is * available. The _opaque is the pointer to a field containing opaque user * data specified in pxml_create() call. The chunk type is _type and the text @@ -35,21 +37,21 @@ typedef enum { * pxml_feed() call) starting at offset _offset and of _size bytes size. * The chunk is NOT '\0'-terminated. */ -typedef int (pxml_callback_f)(pxml_chunk_type_e _type, - const void *_chunk_data, size_t _chunk_size, void *_key); + typedef int(pxml_callback_f)(pxml_chunk_type_e _type, + const void *_chunk_data, size_t _chunk_size, void *_key); -/* + /* * Parse the given buffer as it were a chunk of XML data. * Invoke the specified callback each time the meaninful data is found. * This function returns number of bytes consumed from the bufer. * It will always be lesser than or equal to the specified _size. * The next invocation of this function must account the difference. */ -ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, - pxml_callback_f *cb, void *_key); + ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, + pxml_callback_f *cb, void *_key); #ifdef __cplusplus } #endif -#endif /* _XER_SUPPORT_H_ */ +#endif /* _XER_SUPPORT_H_ */ diff --git a/src/core/libs/supl/asn-supl/AltitudeInfo.h b/src/core/libs/supl/asn-supl/AltitudeInfo.h index 5048d16ad..117da26e2 100644 --- a/src/core/libs/supl/asn-supl/AltitudeInfo.h +++ b/src/core/libs/supl/asn-supl/AltitudeInfo.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _AltitudeInfo_H_ -#define _AltitudeInfo_H_ +#ifndef _AltitudeInfo_H_ +#define _AltitudeInfo_H_ #include @@ -16,36 +16,39 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum altitudeDirection { - altitudeDirection_height = 0, - altitudeDirection_depth = 1 -} e_altitudeDirection; + /* Dependencies */ + typedef enum altitudeDirection + { + altitudeDirection_height = 0, + altitudeDirection_depth = 1 + } e_altitudeDirection; -/* AltitudeInfo */ -typedef struct AltitudeInfo { - ENUMERATED_t altitudeDirection; - long altitude; - long altUncertainty; - /* + /* AltitudeInfo */ + typedef struct AltitudeInfo + { + ENUMERATED_t altitudeDirection; + long altitude; + long altUncertainty; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AltitudeInfo_t; -/* Implementation */ -/* extern asn_TYPE_descriptor_t asn_DEF_altitudeDirection_2; // (Use -fall-defs-global to expose) */ -extern asn_TYPE_descriptor_t asn_DEF_AltitudeInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } AltitudeInfo_t; + + /* Implementation */ + /* extern asn_TYPE_descriptor_t asn_DEF_altitudeDirection_2; // (Use -fall-defs-global to expose) */ + extern asn_TYPE_descriptor_t asn_DEF_AltitudeInfo; #ifdef __cplusplus } #endif -#endif /* _AltitudeInfo_H_ */ +#endif /* _AltitudeInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/BIT_STRING.h b/src/core/libs/supl/asn-supl/BIT_STRING.h index 732e878bc..0008e0d82 100644 --- a/src/core/libs/supl/asn-supl/BIT_STRING.h +++ b/src/core/libs/supl/asn-supl/BIT_STRING.h @@ -2,32 +2,34 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BIT_STRING_H_ -#define _BIT_STRING_H_ +#ifndef _BIT_STRING_H_ +#define _BIT_STRING_H_ -#include /* Some help from OCTET STRING */ +#include /* Some help from OCTET STRING */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct BIT_STRING_s { - uint8_t *buf; /* BIT STRING body */ - int size; /* Size of the above buffer */ + typedef struct BIT_STRING_s + { + uint8_t *buf; /* BIT STRING body */ + int size; /* Size of the above buffer */ - int bits_unused;/* Unused trailing bits in the last octet (0..7) */ + int bits_unused; /* Unused trailing bits in the last octet (0..7) */ - asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -} BIT_STRING_t; + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ + } BIT_STRING_t; -extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; + extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; -asn_struct_print_f BIT_STRING_print; /* Human-readable output */ -asn_constr_check_f BIT_STRING_constraint; -xer_type_encoder_f BIT_STRING_encode_xer; + asn_struct_print_f BIT_STRING_print; /* Human-readable output */ + asn_constr_check_f BIT_STRING_constraint; + xer_type_encoder_f BIT_STRING_encode_xer; #ifdef __cplusplus } #endif -#endif /* _BIT_STRING_H_ */ +#endif /* _BIT_STRING_H_ */ diff --git a/src/core/libs/supl/asn-supl/BOOLEAN.h b/src/core/libs/supl/asn-supl/BOOLEAN.h index 217d0f163..b74f2b430 100644 --- a/src/core/libs/supl/asn-supl/BOOLEAN.h +++ b/src/core/libs/supl/asn-supl/BOOLEAN.h @@ -2,35 +2,36 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BOOLEAN_H_ -#define _BOOLEAN_H_ +#ifndef _BOOLEAN_H_ +#define _BOOLEAN_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * The underlying integer may contain various values, but everything * non-zero is capped to 0xff by the DER encoder. The BER decoder may * yield non-zero values different from 1, beware. */ -typedef int BOOLEAN_t; + typedef int BOOLEAN_t; -extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; + extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; -asn_struct_free_f BOOLEAN_free; -asn_struct_print_f BOOLEAN_print; -ber_type_decoder_f BOOLEAN_decode_ber; -der_type_encoder_f BOOLEAN_encode_der; -xer_type_decoder_f BOOLEAN_decode_xer; -xer_type_encoder_f BOOLEAN_encode_xer; -per_type_decoder_f BOOLEAN_decode_uper; -per_type_encoder_f BOOLEAN_encode_uper; + asn_struct_free_f BOOLEAN_free; + asn_struct_print_f BOOLEAN_print; + ber_type_decoder_f BOOLEAN_decode_ber; + der_type_encoder_f BOOLEAN_encode_der; + xer_type_decoder_f BOOLEAN_decode_xer; + xer_type_encoder_f BOOLEAN_encode_xer; + per_type_decoder_f BOOLEAN_decode_uper; + per_type_encoder_f BOOLEAN_encode_uper; #ifdef __cplusplus } #endif -#endif /* _BOOLEAN_H_ */ +#endif /* _BOOLEAN_H_ */ diff --git a/src/core/libs/supl/asn-supl/CPICH-Ec-N0.h b/src/core/libs/supl/asn-supl/CPICH-Ec-N0.h index 164ff7b32..de9c51754 100644 --- a/src/core/libs/supl/asn-supl/CPICH-Ec-N0.h +++ b/src/core/libs/supl/asn-supl/CPICH-Ec-N0.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CPICH_Ec_N0_H_ -#define _CPICH_Ec_N0_H_ +#ifndef _CPICH_Ec_N0_H_ +#define _CPICH_Ec_N0_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CPICH-Ec-N0 */ -typedef long CPICH_Ec_N0_t; + /* CPICH-Ec-N0 */ + typedef long CPICH_Ec_N0_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CPICH_Ec_N0; -asn_struct_free_f CPICH_Ec_N0_free; -asn_struct_print_f CPICH_Ec_N0_print; -asn_constr_check_f CPICH_Ec_N0_constraint; -ber_type_decoder_f CPICH_Ec_N0_decode_ber; -der_type_encoder_f CPICH_Ec_N0_encode_der; -xer_type_decoder_f CPICH_Ec_N0_decode_xer; -xer_type_encoder_f CPICH_Ec_N0_encode_xer; -per_type_decoder_f CPICH_Ec_N0_decode_uper; -per_type_encoder_f CPICH_Ec_N0_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CPICH_Ec_N0; + asn_struct_free_f CPICH_Ec_N0_free; + asn_struct_print_f CPICH_Ec_N0_print; + asn_constr_check_f CPICH_Ec_N0_constraint; + ber_type_decoder_f CPICH_Ec_N0_decode_ber; + der_type_encoder_f CPICH_Ec_N0_encode_der; + xer_type_decoder_f CPICH_Ec_N0_decode_xer; + xer_type_encoder_f CPICH_Ec_N0_encode_xer; + per_type_decoder_f CPICH_Ec_N0_decode_uper; + per_type_encoder_f CPICH_Ec_N0_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CPICH_Ec_N0_H_ */ +#endif /* _CPICH_Ec_N0_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CPICH-RSCP.h b/src/core/libs/supl/asn-supl/CPICH-RSCP.h index 80551bb1c..6b82eac15 100644 --- a/src/core/libs/supl/asn-supl/CPICH-RSCP.h +++ b/src/core/libs/supl/asn-supl/CPICH-RSCP.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CPICH_RSCP_H_ -#define _CPICH_RSCP_H_ +#ifndef _CPICH_RSCP_H_ +#define _CPICH_RSCP_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CPICH-RSCP */ -typedef long CPICH_RSCP_t; + /* CPICH-RSCP */ + typedef long CPICH_RSCP_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CPICH_RSCP; -asn_struct_free_f CPICH_RSCP_free; -asn_struct_print_f CPICH_RSCP_print; -asn_constr_check_f CPICH_RSCP_constraint; -ber_type_decoder_f CPICH_RSCP_decode_ber; -der_type_encoder_f CPICH_RSCP_encode_der; -xer_type_decoder_f CPICH_RSCP_decode_xer; -xer_type_encoder_f CPICH_RSCP_encode_xer; -per_type_decoder_f CPICH_RSCP_decode_uper; -per_type_encoder_f CPICH_RSCP_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CPICH_RSCP; + asn_struct_free_f CPICH_RSCP_free; + asn_struct_print_f CPICH_RSCP_print; + asn_constr_check_f CPICH_RSCP_constraint; + ber_type_decoder_f CPICH_RSCP_decode_ber; + der_type_encoder_f CPICH_RSCP_encode_der; + xer_type_decoder_f CPICH_RSCP_decode_xer; + xer_type_encoder_f CPICH_RSCP_encode_xer; + per_type_decoder_f CPICH_RSCP_decode_uper; + per_type_encoder_f CPICH_RSCP_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CPICH_RSCP_H_ */ +#endif /* _CPICH_RSCP_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CdmaCellInformation.h b/src/core/libs/supl/asn-supl/CdmaCellInformation.h index 6ee49963e..fff07339d 100644 --- a/src/core/libs/supl/asn-supl/CdmaCellInformation.h +++ b/src/core/libs/supl/asn-supl/CdmaCellInformation.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CdmaCellInformation_H_ -#define _CdmaCellInformation_H_ +#ifndef _CdmaCellInformation_H_ +#define _CdmaCellInformation_H_ #include @@ -15,34 +15,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CdmaCellInformation */ -typedef struct CdmaCellInformation { - long refNID; - long refSID; - long refBASEID; - long refBASELAT; - long reBASELONG; - long refREFPN; - long refWeekNumber; - long refSeconds; - /* + /* CdmaCellInformation */ + typedef struct CdmaCellInformation + { + long refNID; + long refSID; + long refBASEID; + long refBASELAT; + long reBASELONG; + long refREFPN; + long refWeekNumber; + long refSeconds; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CdmaCellInformation_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CdmaCellInformation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CdmaCellInformation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CdmaCellInformation; #ifdef __cplusplus } #endif -#endif /* _CdmaCellInformation_H_ */ +#endif /* _CdmaCellInformation_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CellInfo.h b/src/core/libs/supl/asn-supl/CellInfo.h index c797c2699..945d867c6 100644 --- a/src/core/libs/supl/asn-supl/CellInfo.h +++ b/src/core/libs/supl/asn-supl/CellInfo.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CellInfo_H_ -#define _CellInfo_H_ +#ifndef _CellInfo_H_ +#define _CellInfo_H_ #include @@ -17,42 +17,46 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum CellInfo_PR { - CellInfo_PR_NOTHING, /* No components present */ - CellInfo_PR_gsmCell, - CellInfo_PR_wcdmaCell, - CellInfo_PR_cdmaCell, - /* Extensions may appear below */ - -} CellInfo_PR; + /* Dependencies */ + typedef enum CellInfo_PR + { + CellInfo_PR_NOTHING, /* No components present */ + CellInfo_PR_gsmCell, + CellInfo_PR_wcdmaCell, + CellInfo_PR_cdmaCell, + /* Extensions may appear below */ -/* CellInfo */ -typedef struct CellInfo { - CellInfo_PR present; - union CellInfo_u { - GsmCellInformation_t gsmCell; - WcdmaCellInformation_t wcdmaCell; - CdmaCellInformation_t cdmaCell; - /* + } CellInfo_PR; + + /* CellInfo */ + typedef struct CellInfo + { + CellInfo_PR present; + union CellInfo_u + { + GsmCellInformation_t gsmCell; + WcdmaCellInformation_t wcdmaCell; + CdmaCellInformation_t cdmaCell; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CellInfo_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CellInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellInfo; #ifdef __cplusplus } #endif -#endif /* _CellInfo_H_ */ +#endif /* _CellInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CellMeasuredResults.h b/src/core/libs/supl/asn-supl/CellMeasuredResults.h index 8b1ccc72b..ce08a12dc 100644 --- a/src/core/libs/supl/asn-supl/CellMeasuredResults.h +++ b/src/core/libs/supl/asn-supl/CellMeasuredResults.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CellMeasuredResults_H_ -#define _CellMeasuredResults_H_ +#ifndef _CellMeasuredResults_H_ +#define _CellMeasuredResults_H_ #include @@ -23,56 +23,63 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum modeSpecificInfo_PR { - modeSpecificInfo_PR_NOTHING, /* No components present */ - modeSpecificInfo_PR_fdd, - modeSpecificInfo_PR_tdd -} modeSpecificInfo_PR; + /* Dependencies */ + typedef enum modeSpecificInfo_PR + { + modeSpecificInfo_PR_NOTHING, /* No components present */ + modeSpecificInfo_PR_fdd, + modeSpecificInfo_PR_tdd + } modeSpecificInfo_PR; -/* Forward declarations */ -struct TimeslotISCP_List; + /* Forward declarations */ + struct TimeslotISCP_List; -/* CellMeasuredResults */ -typedef struct CellMeasuredResults { - long *cellIdentity /* OPTIONAL */; - struct modeSpecificInfo { - modeSpecificInfo_PR present; - union CellMeasuredResults__modeSpecificInfo_u { - struct fdd { - PrimaryCPICH_Info_t primaryCPICH_Info; - CPICH_Ec_N0_t *cpich_Ec_N0 /* OPTIONAL */; - CPICH_RSCP_t *cpich_RSCP /* OPTIONAL */; - Pathloss_t *pathloss /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } fdd; - struct tdd { - CellParametersID_t cellParametersID; - TGSN_t *proposedTGSN /* OPTIONAL */; - PrimaryCCPCH_RSCP_t *primaryCCPCH_RSCP /* OPTIONAL */; - Pathloss_t *pathloss /* OPTIONAL */; - struct TimeslotISCP_List *timeslotISCP_List /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } tdd; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } modeSpecificInfo; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CellMeasuredResults_t; + /* CellMeasuredResults */ + typedef struct CellMeasuredResults + { + long *cellIdentity /* OPTIONAL */; + struct modeSpecificInfo + { + modeSpecificInfo_PR present; + union CellMeasuredResults__modeSpecificInfo_u + { + struct fdd + { + PrimaryCPICH_Info_t primaryCPICH_Info; + CPICH_Ec_N0_t *cpich_Ec_N0 /* OPTIONAL */; + CPICH_RSCP_t *cpich_RSCP /* OPTIONAL */; + Pathloss_t *pathloss /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResults; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } fdd; + struct tdd + { + CellParametersID_t cellParametersID; + TGSN_t *proposedTGSN /* OPTIONAL */; + PrimaryCCPCH_RSCP_t *primaryCCPCH_RSCP /* OPTIONAL */; + Pathloss_t *pathloss /* OPTIONAL */; + struct TimeslotISCP_List *timeslotISCP_List /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } tdd; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } modeSpecificInfo; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CellMeasuredResults_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResults; #ifdef __cplusplus } @@ -81,5 +88,5 @@ extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResults; /* Referred external types */ #include "TimeslotISCP-List.h" -#endif /* _CellMeasuredResults_H_ */ +#endif /* _CellMeasuredResults_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CellMeasuredResultsList.h b/src/core/libs/supl/asn-supl/CellMeasuredResultsList.h index 5fa99af82..8e1b3785d 100644 --- a/src/core/libs/supl/asn-supl/CellMeasuredResultsList.h +++ b/src/core/libs/supl/asn-supl/CellMeasuredResultsList.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CellMeasuredResultsList_H_ -#define _CellMeasuredResultsList_H_ +#ifndef _CellMeasuredResultsList_H_ +#define _CellMeasuredResultsList_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct CellMeasuredResults; + /* Forward declarations */ + struct CellMeasuredResults; -/* CellMeasuredResultsList */ -typedef struct CellMeasuredResultsList { - A_SEQUENCE_OF(struct CellMeasuredResults) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} CellMeasuredResultsList_t; + /* CellMeasuredResultsList */ + typedef struct CellMeasuredResultsList + { + A_SEQUENCE_OF(struct CellMeasuredResults) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResultsList; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } CellMeasuredResultsList_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResultsList; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_CellMeasuredResultsList; /* Referred external types */ #include "CellMeasuredResults.h" -#endif /* _CellMeasuredResultsList_H_ */ +#endif /* _CellMeasuredResultsList_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/CellParametersID.h b/src/core/libs/supl/asn-supl/CellParametersID.h index b331debbd..bf693916e 100644 --- a/src/core/libs/supl/asn-supl/CellParametersID.h +++ b/src/core/libs/supl/asn-supl/CellParametersID.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _CellParametersID_H_ -#define _CellParametersID_H_ +#ifndef _CellParametersID_H_ +#define _CellParametersID_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* CellParametersID */ -typedef long CellParametersID_t; + /* CellParametersID */ + typedef long CellParametersID_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_CellParametersID; -asn_struct_free_f CellParametersID_free; -asn_struct_print_f CellParametersID_print; -asn_constr_check_f CellParametersID_constraint; -ber_type_decoder_f CellParametersID_decode_ber; -der_type_encoder_f CellParametersID_encode_der; -xer_type_decoder_f CellParametersID_decode_xer; -xer_type_encoder_f CellParametersID_encode_xer; -per_type_decoder_f CellParametersID_decode_uper; -per_type_encoder_f CellParametersID_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_CellParametersID; + asn_struct_free_f CellParametersID_free; + asn_struct_print_f CellParametersID_print; + asn_constr_check_f CellParametersID_constraint; + ber_type_decoder_f CellParametersID_decode_ber; + der_type_encoder_f CellParametersID_encode_der; + xer_type_decoder_f CellParametersID_decode_xer; + xer_type_encoder_f CellParametersID_encode_xer; + per_type_decoder_f CellParametersID_decode_uper; + per_type_encoder_f CellParametersID_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CellParametersID_H_ */ +#endif /* _CellParametersID_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/DUMMY.h b/src/core/libs/supl/asn-supl/DUMMY.h index c9385e2cb..3d884fc68 100644 --- a/src/core/libs/supl/asn-supl/DUMMY.h +++ b/src/core/libs/supl/asn-supl/DUMMY.h @@ -4,8 +4,8 @@ * found in "../supl-ulp.asn" */ -#ifndef _DUMMY_H_ -#define _DUMMY_H_ +#ifndef _DUMMY_H_ +#define _DUMMY_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* DUMMY */ -typedef INTEGER_t DUMMY_t; + /* DUMMY */ + typedef INTEGER_t DUMMY_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_DUMMY; -asn_struct_free_f DUMMY_free; -asn_struct_print_f DUMMY_print; -asn_constr_check_f DUMMY_constraint; -ber_type_decoder_f DUMMY_decode_ber; -der_type_encoder_f DUMMY_encode_der; -xer_type_decoder_f DUMMY_decode_xer; -xer_type_encoder_f DUMMY_encode_xer; -per_type_decoder_f DUMMY_decode_uper; -per_type_encoder_f DUMMY_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_DUMMY; + asn_struct_free_f DUMMY_free; + asn_struct_print_f DUMMY_print; + asn_constr_check_f DUMMY_constraint; + ber_type_decoder_f DUMMY_decode_ber; + der_type_encoder_f DUMMY_encode_der; + xer_type_decoder_f DUMMY_decode_xer; + xer_type_encoder_f DUMMY_encode_xer; + per_type_decoder_f DUMMY_decode_uper; + per_type_encoder_f DUMMY_encode_uper; #ifdef __cplusplus } #endif -#endif /* _DUMMY_H_ */ +#endif /* _DUMMY_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/ENUMERATED.h b/src/core/libs/supl/asn-supl/ENUMERATED.h index 542dcae94..86c1cf643 100644 --- a/src/core/libs/supl/asn-supl/ENUMERATED.h +++ b/src/core/libs/supl/asn-supl/ENUMERATED.h @@ -2,24 +2,25 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ENUMERATED_H_ -#define _ENUMERATED_H_ +#ifndef _ENUMERATED_H_ +#define _ENUMERATED_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef INTEGER_t ENUMERATED_t; /* Implemented via INTEGER */ + typedef INTEGER_t ENUMERATED_t; /* Implemented via INTEGER */ -extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; + extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; -per_type_decoder_f ENUMERATED_decode_uper; -per_type_encoder_f ENUMERATED_encode_uper; + per_type_decoder_f ENUMERATED_decode_uper; + per_type_encoder_f ENUMERATED_encode_uper; #ifdef __cplusplus } #endif -#endif /* _ENUMERATED_H_ */ +#endif /* _ENUMERATED_H_ */ diff --git a/src/core/libs/supl/asn-supl/EncodingType.h b/src/core/libs/supl/asn-supl/EncodingType.h index 4dd21e4be..40deead4e 100644 --- a/src/core/libs/supl/asn-supl/EncodingType.h +++ b/src/core/libs/supl/asn-supl/EncodingType.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _EncodingType_H_ -#define _EncodingType_H_ +#ifndef _EncodingType_H_ +#define _EncodingType_H_ #include @@ -14,37 +14,39 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum EncodingType { - EncodingType_ucs2 = 0, - EncodingType_gsmDefault = 1, - EncodingType_utf8 = 2 - /* + /* Dependencies */ + typedef enum EncodingType + { + EncodingType_ucs2 = 0, + EncodingType_gsmDefault = 1, + EncodingType_utf8 = 2 + /* * Enumeration is extensible */ -} e_EncodingType; + } e_EncodingType; -/* EncodingType */ -typedef ENUMERATED_t EncodingType_t; + /* EncodingType */ + typedef ENUMERATED_t EncodingType_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_EncodingType; -asn_struct_free_f EncodingType_free; -asn_struct_print_f EncodingType_print; -asn_constr_check_f EncodingType_constraint; -ber_type_decoder_f EncodingType_decode_ber; -der_type_encoder_f EncodingType_encode_der; -xer_type_decoder_f EncodingType_decode_xer; -xer_type_encoder_f EncodingType_encode_xer; -per_type_decoder_f EncodingType_decode_uper; -per_type_encoder_f EncodingType_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_EncodingType; + asn_struct_free_f EncodingType_free; + asn_struct_print_f EncodingType_print; + asn_constr_check_f EncodingType_constraint; + ber_type_decoder_f EncodingType_decode_ber; + der_type_encoder_f EncodingType_encode_der; + xer_type_decoder_f EncodingType_decode_xer; + xer_type_encoder_f EncodingType_encode_xer; + per_type_decoder_f EncodingType_decode_uper; + per_type_encoder_f EncodingType_encode_uper; #ifdef __cplusplus } #endif -#endif /* _EncodingType_H_ */ +#endif /* _EncodingType_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/FQDN.h b/src/core/libs/supl/asn-supl/FQDN.h index 37291766a..0aaf7a1ff 100644 --- a/src/core/libs/supl/asn-supl/FQDN.h +++ b/src/core/libs/supl/asn-supl/FQDN.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _FQDN_H_ -#define _FQDN_H_ +#ifndef _FQDN_H_ +#define _FQDN_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FQDN */ -typedef VisibleString_t FQDN_t; + /* FQDN */ + typedef VisibleString_t FQDN_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FQDN; -asn_struct_free_f FQDN_free; -asn_struct_print_f FQDN_print; -asn_constr_check_f FQDN_constraint; -ber_type_decoder_f FQDN_decode_ber; -der_type_encoder_f FQDN_encode_der; -xer_type_decoder_f FQDN_decode_xer; -xer_type_encoder_f FQDN_encode_xer; -per_type_decoder_f FQDN_decode_uper; -per_type_encoder_f FQDN_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FQDN; + asn_struct_free_f FQDN_free; + asn_struct_print_f FQDN_print; + asn_constr_check_f FQDN_constraint; + ber_type_decoder_f FQDN_decode_ber; + der_type_encoder_f FQDN_encode_der; + xer_type_decoder_f FQDN_decode_xer; + xer_type_encoder_f FQDN_encode_xer; + per_type_decoder_f FQDN_decode_uper; + per_type_encoder_f FQDN_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FQDN_H_ */ +#endif /* _FQDN_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/FormatIndicator.h b/src/core/libs/supl/asn-supl/FormatIndicator.h index 6ac65a25d..b52a8b4e3 100644 --- a/src/core/libs/supl/asn-supl/FormatIndicator.h +++ b/src/core/libs/supl/asn-supl/FormatIndicator.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _FormatIndicator_H_ -#define _FormatIndicator_H_ +#ifndef _FormatIndicator_H_ +#define _FormatIndicator_H_ #include @@ -14,42 +14,44 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum FormatIndicator { - FormatIndicator_logicalName = 0, - FormatIndicator_e_mailAddress = 1, - FormatIndicator_msisdn = 2, - FormatIndicator_url = 3, - FormatIndicator_sipUrl = 4, - FormatIndicator_min = 5, - FormatIndicator_mdn = 6, - FormatIndicator_imsPublicIdentity = 7 - /* + /* Dependencies */ + typedef enum FormatIndicator + { + FormatIndicator_logicalName = 0, + FormatIndicator_e_mailAddress = 1, + FormatIndicator_msisdn = 2, + FormatIndicator_url = 3, + FormatIndicator_sipUrl = 4, + FormatIndicator_min = 5, + FormatIndicator_mdn = 6, + FormatIndicator_imsPublicIdentity = 7 + /* * Enumeration is extensible */ -} e_FormatIndicator; + } e_FormatIndicator; -/* FormatIndicator */ -typedef ENUMERATED_t FormatIndicator_t; + /* FormatIndicator */ + typedef ENUMERATED_t FormatIndicator_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FormatIndicator; -asn_struct_free_f FormatIndicator_free; -asn_struct_print_f FormatIndicator_print; -asn_constr_check_f FormatIndicator_constraint; -ber_type_decoder_f FormatIndicator_decode_ber; -der_type_encoder_f FormatIndicator_encode_der; -xer_type_decoder_f FormatIndicator_decode_xer; -xer_type_encoder_f FormatIndicator_encode_xer; -per_type_decoder_f FormatIndicator_decode_uper; -per_type_encoder_f FormatIndicator_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FormatIndicator; + asn_struct_free_f FormatIndicator_free; + asn_struct_print_f FormatIndicator_print; + asn_constr_check_f FormatIndicator_constraint; + ber_type_decoder_f FormatIndicator_decode_ber; + der_type_encoder_f FormatIndicator_encode_der; + xer_type_decoder_f FormatIndicator_decode_xer; + xer_type_encoder_f FormatIndicator_encode_xer; + per_type_decoder_f FormatIndicator_decode_uper; + per_type_encoder_f FormatIndicator_encode_uper; #ifdef __cplusplus } #endif -#endif /* _FormatIndicator_H_ */ +#endif /* _FormatIndicator_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/FrequencyInfo.h b/src/core/libs/supl/asn-supl/FrequencyInfo.h index 3bdeb0ba5..48ed6c07e 100644 --- a/src/core/libs/supl/asn-supl/FrequencyInfo.h +++ b/src/core/libs/supl/asn-supl/FrequencyInfo.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _FrequencyInfo_H_ -#define _FrequencyInfo_H_ +#ifndef _FrequencyInfo_H_ +#define _FrequencyInfo_H_ #include @@ -17,49 +17,54 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum fmodeSpecificInfo_PR { - fmodeSpecificInfo_PR_NOTHING, /* No components present */ - fmodeSpecificInfo_PR_fdd, - fmodeSpecificInfo_PR_tdd, - /* Extensions may appear below */ - -} fmodeSpecificInfo_PR; + /* Dependencies */ + typedef enum fmodeSpecificInfo_PR + { + fmodeSpecificInfo_PR_NOTHING, /* No components present */ + fmodeSpecificInfo_PR_fdd, + fmodeSpecificInfo_PR_tdd, + /* Extensions may appear below */ -/* FrequencyInfo */ -typedef struct FrequencyInfo { - struct fmodeSpecificInfo { - fmodeSpecificInfo_PR present; - union FrequencyInfo__fmodeSpecificInfo_u { - FrequencyInfoFDD_t fdd; - FrequencyInfoTDD_t tdd; - /* + } fmodeSpecificInfo_PR; + + /* FrequencyInfo */ + typedef struct FrequencyInfo + { + struct fmodeSpecificInfo + { + fmodeSpecificInfo_PR present; + union FrequencyInfo__fmodeSpecificInfo_u + { + FrequencyInfoFDD_t fdd; + FrequencyInfoTDD_t tdd; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } fmodeSpecificInfo; - /* + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } fmodeSpecificInfo; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} FrequencyInfo_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } FrequencyInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfo; #ifdef __cplusplus } #endif -#endif /* _FrequencyInfo_H_ */ +#endif /* _FrequencyInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/FrequencyInfoFDD.h b/src/core/libs/supl/asn-supl/FrequencyInfoFDD.h index 3ed4ee8d8..2e9ac7f55 100644 --- a/src/core/libs/supl/asn-supl/FrequencyInfoFDD.h +++ b/src/core/libs/supl/asn-supl/FrequencyInfoFDD.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _FrequencyInfoFDD_H_ -#define _FrequencyInfoFDD_H_ +#ifndef _FrequencyInfoFDD_H_ +#define _FrequencyInfoFDD_H_ #include @@ -15,28 +15,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FrequencyInfoFDD */ -typedef struct FrequencyInfoFDD { - UARFCN_t *uarfcn_UL /* OPTIONAL */; - UARFCN_t uarfcn_DL; - /* + /* FrequencyInfoFDD */ + typedef struct FrequencyInfoFDD + { + UARFCN_t *uarfcn_UL /* OPTIONAL */; + UARFCN_t uarfcn_DL; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} FrequencyInfoFDD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfoFDD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } FrequencyInfoFDD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfoFDD; #ifdef __cplusplus } #endif -#endif /* _FrequencyInfoFDD_H_ */ +#endif /* _FrequencyInfoFDD_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/FrequencyInfoTDD.h b/src/core/libs/supl/asn-supl/FrequencyInfoTDD.h index f0d6f0e13..1ccedb199 100644 --- a/src/core/libs/supl/asn-supl/FrequencyInfoTDD.h +++ b/src/core/libs/supl/asn-supl/FrequencyInfoTDD.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _FrequencyInfoTDD_H_ -#define _FrequencyInfoTDD_H_ +#ifndef _FrequencyInfoTDD_H_ +#define _FrequencyInfoTDD_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* FrequencyInfoTDD */ -typedef struct FrequencyInfoTDD { - UARFCN_t uarfcn_Nt; - /* + /* FrequencyInfoTDD */ + typedef struct FrequencyInfoTDD + { + UARFCN_t uarfcn_Nt; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} FrequencyInfoTDD_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfoTDD; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } FrequencyInfoTDD_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_FrequencyInfoTDD; #ifdef __cplusplus } #endif -#endif /* _FrequencyInfoTDD_H_ */ +#endif /* _FrequencyInfoTDD_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/GeneralizedTime.c b/src/core/libs/supl/asn-supl/GeneralizedTime.c index 9d683efe4..3007af94e 100644 --- a/src/core/libs/supl/asn-supl/GeneralizedTime.c +++ b/src/core/libs/supl/asn-supl/GeneralizedTime.c @@ -3,7 +3,9 @@ * Redistribution and modifications are permitted subject to BSD license. */ #define _POSIX_PTHREAD_SEMANTICS /* for Sun */ +#ifndef _REENTRANT #define _REENTRANT /* for Sun */ +#endif #include #include #include @@ -367,7 +369,7 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, errno = EINVAL; \ return -1; \ } else { \ - var = var * 10 + (ch - 0x30); \ + (var) = (var) * 10 + (ch - 0x30); \ buf++; \ } \ } while(0) diff --git a/src/core/libs/supl/asn-supl/GeneralizedTime.h b/src/core/libs/supl/asn-supl/GeneralizedTime.h index 1ea06b068..9e9583c7a 100644 --- a/src/core/libs/supl/asn-supl/GeneralizedTime.h +++ b/src/core/libs/supl/asn-supl/GeneralizedTime.h @@ -2,68 +2,69 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _GeneralizedTime_H_ -#define _GeneralizedTime_H_ +#ifndef _GeneralizedTime_H_ +#define _GeneralizedTime_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef OCTET_STRING_t GeneralizedTime_t; /* Implemented via OCTET STRING */ + typedef OCTET_STRING_t GeneralizedTime_t; /* Implemented via OCTET STRING */ -extern asn_TYPE_descriptor_t asn_DEF_GeneralizedTime; + extern asn_TYPE_descriptor_t asn_DEF_GeneralizedTime; -asn_struct_print_f GeneralizedTime_print; -asn_constr_check_f GeneralizedTime_constraint; -der_type_encoder_f GeneralizedTime_encode_der; -xer_type_encoder_f GeneralizedTime_encode_xer; + asn_struct_print_f GeneralizedTime_print; + asn_constr_check_f GeneralizedTime_constraint; + der_type_encoder_f GeneralizedTime_encode_der; + xer_type_encoder_f GeneralizedTime_encode_xer; -/*********************** + /*********************** * Some handy helpers. * ***********************/ -struct tm; /* */ + struct tm; /* */ -/* + /* * Convert a GeneralizedTime structure into time_t * and optionally into struct tm. * If as_gmt is given, the resulting _optional_tm4fill will have a GMT zone, * instead of default local one. * On error returns -1 and errno set to EINVAL */ -time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, - int as_gmt); + time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, + int as_gmt); -/* A version of the above function also returning the fractions of seconds */ -time_t asn_GT2time_frac(const GeneralizedTime_t *, - int *frac_value, int *frac_digits, /* (value / (10 ^ digits)) */ - struct tm *_optional_tm4fill, int as_gmt); + /* A version of the above function also returning the fractions of seconds */ + time_t asn_GT2time_frac(const GeneralizedTime_t *, + int *frac_value, int *frac_digits, /* (value / (10 ^ digits)) */ + struct tm *_optional_tm4fill, int as_gmt); -/* + /* * Another version returning fractions with defined precision * For example, parsing of the time ending with ".1" seconds * with frac_digits=3 (msec) would yield frac_value = 100. */ -time_t asn_GT2time_prec(const GeneralizedTime_t *, - int *frac_value, int frac_digits, - struct tm *_optional_tm4fill, int as_gmt); + time_t asn_GT2time_prec(const GeneralizedTime_t *, + int *frac_value, int frac_digits, + struct tm *_optional_tm4fill, int as_gmt); -/* + /* * Convert a struct tm into GeneralizedTime. * If _optional_gt is not given, this function will try to allocate one. * If force_gmt is given, the resulting GeneralizedTime will be forced * into a GMT time zone (encoding ends with a "Z"). * On error, this function returns 0 and sets errno. */ -GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *_optional_gt, - const struct tm *, int force_gmt); -GeneralizedTime_t *asn_time2GT_frac(GeneralizedTime_t *_optional_gt, - const struct tm *, int frac_value, int frac_digits, int force_gmt); + GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *_optional_gt, + const struct tm *, int force_gmt); + GeneralizedTime_t *asn_time2GT_frac(GeneralizedTime_t *_optional_gt, + const struct tm *, int frac_value, int frac_digits, int force_gmt); #ifdef __cplusplus } #endif -#endif /* _GeneralizedTime_H_ */ +#endif /* _GeneralizedTime_H_ */ diff --git a/src/core/libs/supl/asn-supl/GsmCellInformation.h b/src/core/libs/supl/asn-supl/GsmCellInformation.h index 6c978ebee..f5f2d4c96 100644 --- a/src/core/libs/supl/asn-supl/GsmCellInformation.h +++ b/src/core/libs/supl/asn-supl/GsmCellInformation.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _GsmCellInformation_H_ -#define _GsmCellInformation_H_ +#ifndef _GsmCellInformation_H_ +#define _GsmCellInformation_H_ #include @@ -15,31 +15,33 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct NMR; + /* Forward declarations */ + struct NMR; -/* GsmCellInformation */ -typedef struct GsmCellInformation { - long refMCC; - long refMNC; - long refLAC; - long refCI; - struct NMR *nMR /* OPTIONAL */; - long *tA /* OPTIONAL */; - /* + /* GsmCellInformation */ + typedef struct GsmCellInformation + { + long refMCC; + long refMNC; + long refLAC; + long refCI; + struct NMR *nMR /* OPTIONAL */; + long *tA /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} GsmCellInformation_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_GsmCellInformation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } GsmCellInformation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_GsmCellInformation; #ifdef __cplusplus } @@ -48,5 +50,5 @@ extern asn_TYPE_descriptor_t asn_DEF_GsmCellInformation; /* Referred external types */ #include "NMR.h" -#endif /* _GsmCellInformation_H_ */ +#endif /* _GsmCellInformation_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Horandveruncert.c b/src/core/libs/supl/asn-supl/Horandveruncert.c index 6df8af075..a73928d71 100644 --- a/src/core/libs/supl/asn-supl/Horandveruncert.c +++ b/src/core/libs/supl/asn-supl/Horandveruncert.c @@ -8,318 +8,356 @@ static int memb_verdirect_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 1)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 1) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_bearing_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 9)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 9) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_horspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 16)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 16) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_verspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_horuncertspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_veruncertspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_verdirect_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 1, 1 } /* (SIZE(1..1)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 1, 1} /* (SIZE(1..1)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_bearing_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 9, 9 } /* (SIZE(9..9)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 9, 9} /* (SIZE(9..9)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_horspeed_constr_4 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 16, 16 } /* (SIZE(16..16)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 16, 16} /* (SIZE(16..16)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_verspeed_constr_5 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_horuncertspeed_constr_6 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_veruncertspeed_constr_7 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_Horandveruncert_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, verdirect), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_verdirect_constraint_1, - &asn_PER_memb_verdirect_constr_2, - 0, - "verdirect" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, bearing), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_bearing_constraint_1, - &asn_PER_memb_bearing_constr_3, - 0, - "bearing" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, horspeed), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_horspeed_constraint_1, - &asn_PER_memb_horspeed_constr_4, - 0, - "horspeed" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, verspeed), - (ASN_TAG_CLASS_CONTEXT | (3 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_verspeed_constraint_1, - &asn_PER_memb_verspeed_constr_5, - 0, - "verspeed" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, horuncertspeed), - (ASN_TAG_CLASS_CONTEXT | (4 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_horuncertspeed_constraint_1, - &asn_PER_memb_horuncertspeed_constr_6, - 0, - "horuncertspeed" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, veruncertspeed), - (ASN_TAG_CLASS_CONTEXT | (5 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_veruncertspeed_constraint_1, - &asn_PER_memb_veruncertspeed_constr_7, - 0, - "veruncertspeed" - }, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, verdirect), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_verdirect_constraint_1, + &asn_PER_memb_verdirect_constr_2, + 0, + "verdirect"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, bearing), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_bearing_constraint_1, + &asn_PER_memb_bearing_constr_3, + 0, + "bearing"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, horspeed), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_horspeed_constraint_1, + &asn_PER_memb_horspeed_constr_4, + 0, + "horspeed"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, verspeed), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_verspeed_constraint_1, + &asn_PER_memb_verspeed_constr_5, + 0, + "verspeed"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, horuncertspeed), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_horuncertspeed_constraint_1, + &asn_PER_memb_horuncertspeed_constr_6, + 0, + "horuncertspeed"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandveruncert, veruncertspeed), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_veruncertspeed_constraint_1, + &asn_PER_memb_veruncertspeed_constr_7, + 0, + "veruncertspeed"}, }; static ber_tlv_tag_t asn_DEF_Horandveruncert_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))}; static asn_TYPE_tag2member_t asn_MAP_Horandveruncert_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* verdirect at 251 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* bearing at 252 */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* horspeed at 253 */ - { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* verspeed at 254 */ - { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* horuncertspeed at 255 */ - { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 } /* veruncertspeed at 256 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* verdirect at 251 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0}, /* bearing at 252 */ + {(ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0}, /* horspeed at 253 */ + {(ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0}, /* verspeed at 254 */ + {(ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0}, /* horuncertspeed at 255 */ + {(ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0} /* veruncertspeed at 256 */ }; static asn_SEQUENCE_specifics_t asn_SPC_Horandveruncert_specs_1 = { - sizeof(struct Horandveruncert), - offsetof(struct Horandveruncert, _asn_ctx), - asn_MAP_Horandveruncert_tag2el_1, - 6, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - 5, /* Start extensions */ - 7 /* Stop extensions */ + sizeof(struct Horandveruncert), + offsetof(struct Horandveruncert, _asn_ctx), + asn_MAP_Horandveruncert_tag2el_1, + 6, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 5, /* Start extensions */ + 7 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_Horandveruncert = { - "Horandveruncert", - "Horandveruncert", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - SEQUENCE_decode_uper, - SEQUENCE_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_Horandveruncert_tags_1, - sizeof(asn_DEF_Horandveruncert_tags_1) - /sizeof(asn_DEF_Horandveruncert_tags_1[0]), /* 1 */ - asn_DEF_Horandveruncert_tags_1, /* Same as above */ - sizeof(asn_DEF_Horandveruncert_tags_1) - /sizeof(asn_DEF_Horandveruncert_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_Horandveruncert_1, - 6, /* Elements count */ - &asn_SPC_Horandveruncert_specs_1 /* Additional specs */ + "Horandveruncert", + "Horandveruncert", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Horandveruncert_tags_1, + sizeof(asn_DEF_Horandveruncert_tags_1) / sizeof(asn_DEF_Horandveruncert_tags_1[0]), /* 1 */ + asn_DEF_Horandveruncert_tags_1, /* Same as above */ + sizeof(asn_DEF_Horandveruncert_tags_1) / sizeof(asn_DEF_Horandveruncert_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Horandveruncert_1, + 6, /* Elements count */ + &asn_SPC_Horandveruncert_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/Horandveruncert.h b/src/core/libs/supl/asn-supl/Horandveruncert.h index e72377ddd..0c84e5baa 100644 --- a/src/core/libs/supl/asn-supl/Horandveruncert.h +++ b/src/core/libs/supl/asn-supl/Horandveruncert.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Horandveruncert_H_ -#define _Horandveruncert_H_ +#ifndef _Horandveruncert_H_ +#define _Horandveruncert_H_ #include @@ -15,32 +15,34 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Horandveruncert */ -typedef struct Horandveruncert { - BIT_STRING_t verdirect; - BIT_STRING_t bearing; - BIT_STRING_t horspeed; - BIT_STRING_t verspeed; - BIT_STRING_t horuncertspeed; - BIT_STRING_t veruncertspeed; - /* + /* Horandveruncert */ + typedef struct Horandveruncert + { + BIT_STRING_t verdirect; + BIT_STRING_t bearing; + BIT_STRING_t horspeed; + BIT_STRING_t verspeed; + BIT_STRING_t horuncertspeed; + BIT_STRING_t veruncertspeed; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Horandveruncert_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Horandveruncert; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Horandveruncert_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Horandveruncert; #ifdef __cplusplus } #endif -#endif /* _Horandveruncert_H_ */ +#endif /* _Horandveruncert_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Horandvervel.c b/src/core/libs/supl/asn-supl/Horandvervel.c index cfc81cfc9..b91d072e1 100644 --- a/src/core/libs/supl/asn-supl/Horandvervel.c +++ b/src/core/libs/supl/asn-supl/Horandvervel.c @@ -8,226 +8,250 @@ static int memb_verdirect_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 1)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 1) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_bearing_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 9)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 9) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_horspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 16)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 16) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_verspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_verdirect_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 1, 1 } /* (SIZE(1..1)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 1, 1} /* (SIZE(1..1)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_bearing_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 9, 9 } /* (SIZE(9..9)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 9, 9} /* (SIZE(9..9)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_horspeed_constr_4 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 16, 16 } /* (SIZE(16..16)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 16, 16} /* (SIZE(16..16)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_verspeed_constr_5 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_Horandvervel_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct Horandvervel, verdirect), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_verdirect_constraint_1, - &asn_PER_memb_verdirect_constr_2, - 0, - "verdirect" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandvervel, bearing), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_bearing_constraint_1, - &asn_PER_memb_bearing_constr_3, - 0, - "bearing" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandvervel, horspeed), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_horspeed_constraint_1, - &asn_PER_memb_horspeed_constr_4, - 0, - "horspeed" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horandvervel, verspeed), - (ASN_TAG_CLASS_CONTEXT | (3 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_verspeed_constraint_1, - &asn_PER_memb_verspeed_constr_5, - 0, - "verspeed" - }, + {ATF_NOFLAGS, 0, offsetof(struct Horandvervel, verdirect), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_verdirect_constraint_1, + &asn_PER_memb_verdirect_constr_2, + 0, + "verdirect"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandvervel, bearing), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_bearing_constraint_1, + &asn_PER_memb_bearing_constr_3, + 0, + "bearing"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandvervel, horspeed), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_horspeed_constraint_1, + &asn_PER_memb_horspeed_constr_4, + 0, + "horspeed"}, + {ATF_NOFLAGS, 0, offsetof(struct Horandvervel, verspeed), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_verspeed_constraint_1, + &asn_PER_memb_verspeed_constr_5, + 0, + "verspeed"}, }; static ber_tlv_tag_t asn_DEF_Horandvervel_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))}; static asn_TYPE_tag2member_t asn_MAP_Horandvervel_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* verdirect at 238 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* bearing at 239 */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* horspeed at 240 */ - { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 } /* verspeed at 241 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* verdirect at 238 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0}, /* bearing at 239 */ + {(ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0}, /* horspeed at 240 */ + {(ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0} /* verspeed at 241 */ }; static asn_SEQUENCE_specifics_t asn_SPC_Horandvervel_specs_1 = { - sizeof(struct Horandvervel), - offsetof(struct Horandvervel, _asn_ctx), - asn_MAP_Horandvervel_tag2el_1, - 4, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - 3, /* Start extensions */ - 5 /* Stop extensions */ + sizeof(struct Horandvervel), + offsetof(struct Horandvervel, _asn_ctx), + asn_MAP_Horandvervel_tag2el_1, + 4, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 3, /* Start extensions */ + 5 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_Horandvervel = { - "Horandvervel", - "Horandvervel", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - SEQUENCE_decode_uper, - SEQUENCE_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_Horandvervel_tags_1, - sizeof(asn_DEF_Horandvervel_tags_1) - /sizeof(asn_DEF_Horandvervel_tags_1[0]), /* 1 */ - asn_DEF_Horandvervel_tags_1, /* Same as above */ - sizeof(asn_DEF_Horandvervel_tags_1) - /sizeof(asn_DEF_Horandvervel_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_Horandvervel_1, - 4, /* Elements count */ - &asn_SPC_Horandvervel_specs_1 /* Additional specs */ + "Horandvervel", + "Horandvervel", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Horandvervel_tags_1, + sizeof(asn_DEF_Horandvervel_tags_1) / sizeof(asn_DEF_Horandvervel_tags_1[0]), /* 1 */ + asn_DEF_Horandvervel_tags_1, /* Same as above */ + sizeof(asn_DEF_Horandvervel_tags_1) / sizeof(asn_DEF_Horandvervel_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Horandvervel_1, + 4, /* Elements count */ + &asn_SPC_Horandvervel_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/Horandvervel.h b/src/core/libs/supl/asn-supl/Horandvervel.h index dccb0ebfc..06e39bf1f 100644 --- a/src/core/libs/supl/asn-supl/Horandvervel.h +++ b/src/core/libs/supl/asn-supl/Horandvervel.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Horandvervel_H_ -#define _Horandvervel_H_ +#ifndef _Horandvervel_H_ +#define _Horandvervel_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Horandvervel */ -typedef struct Horandvervel { - BIT_STRING_t verdirect; - BIT_STRING_t bearing; - BIT_STRING_t horspeed; - BIT_STRING_t verspeed; - /* + /* Horandvervel */ + typedef struct Horandvervel + { + BIT_STRING_t verdirect; + BIT_STRING_t bearing; + BIT_STRING_t horspeed; + BIT_STRING_t verspeed; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Horandvervel_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Horandvervel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Horandvervel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Horandvervel; #ifdef __cplusplus } #endif -#endif /* _Horandvervel_H_ */ +#endif /* _Horandvervel_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Horvel.c b/src/core/libs/supl/asn-supl/Horvel.c index bf9914452..7c2080fff 100644 --- a/src/core/libs/supl/asn-supl/Horvel.c +++ b/src/core/libs/supl/asn-supl/Horvel.c @@ -8,134 +8,144 @@ static int memb_bearing_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 9)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 9) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_horspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 16)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 16) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_bearing_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 9, 9 } /* (SIZE(9..9)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 9, 9} /* (SIZE(9..9)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_horspeed_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 16, 16 } /* (SIZE(16..16)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 16, 16} /* (SIZE(16..16)) */, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_Horvel_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct Horvel, bearing), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_bearing_constraint_1, - &asn_PER_memb_bearing_constr_2, - 0, - "bearing" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horvel, horspeed), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_horspeed_constraint_1, - &asn_PER_memb_horspeed_constr_3, - 0, - "horspeed" - }, + {ATF_NOFLAGS, 0, offsetof(struct Horvel, bearing), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_bearing_constraint_1, + &asn_PER_memb_bearing_constr_2, + 0, + "bearing"}, + {ATF_NOFLAGS, 0, offsetof(struct Horvel, horspeed), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_horspeed_constraint_1, + &asn_PER_memb_horspeed_constr_3, + 0, + "horspeed"}, }; static ber_tlv_tag_t asn_DEF_Horvel_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))}; static asn_TYPE_tag2member_t asn_MAP_Horvel_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* bearing at 233 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* horspeed at 234 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* bearing at 233 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0} /* horspeed at 234 */ }; static asn_SEQUENCE_specifics_t asn_SPC_Horvel_specs_1 = { - sizeof(struct Horvel), - offsetof(struct Horvel, _asn_ctx), - asn_MAP_Horvel_tag2el_1, - 2, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - 1, /* Start extensions */ - 3 /* Stop extensions */ + sizeof(struct Horvel), + offsetof(struct Horvel, _asn_ctx), + asn_MAP_Horvel_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 1, /* Start extensions */ + 3 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_Horvel = { - "Horvel", - "Horvel", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - SEQUENCE_decode_uper, - SEQUENCE_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_Horvel_tags_1, - sizeof(asn_DEF_Horvel_tags_1) - /sizeof(asn_DEF_Horvel_tags_1[0]), /* 1 */ - asn_DEF_Horvel_tags_1, /* Same as above */ - sizeof(asn_DEF_Horvel_tags_1) - /sizeof(asn_DEF_Horvel_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_Horvel_1, - 2, /* Elements count */ - &asn_SPC_Horvel_specs_1 /* Additional specs */ + "Horvel", + "Horvel", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Horvel_tags_1, + sizeof(asn_DEF_Horvel_tags_1) / sizeof(asn_DEF_Horvel_tags_1[0]), /* 1 */ + asn_DEF_Horvel_tags_1, /* Same as above */ + sizeof(asn_DEF_Horvel_tags_1) / sizeof(asn_DEF_Horvel_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Horvel_1, + 2, /* Elements count */ + &asn_SPC_Horvel_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/Horvel.h b/src/core/libs/supl/asn-supl/Horvel.h index 8dfca28c4..b702cb503 100644 --- a/src/core/libs/supl/asn-supl/Horvel.h +++ b/src/core/libs/supl/asn-supl/Horvel.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Horvel_H_ -#define _Horvel_H_ +#ifndef _Horvel_H_ +#define _Horvel_H_ #include @@ -15,28 +15,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Horvel */ -typedef struct Horvel { - BIT_STRING_t bearing; - BIT_STRING_t horspeed; - /* + /* Horvel */ + typedef struct Horvel + { + BIT_STRING_t bearing; + BIT_STRING_t horspeed; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Horvel_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Horvel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Horvel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Horvel; #ifdef __cplusplus } #endif -#endif /* _Horvel_H_ */ +#endif /* _Horvel_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Horveluncert.c b/src/core/libs/supl/asn-supl/Horveluncert.c index ca12ff352..b3983f3f6 100644 --- a/src/core/libs/supl/asn-supl/Horveluncert.c +++ b/src/core/libs/supl/asn-supl/Horveluncert.c @@ -8,180 +8,197 @@ static int memb_bearing_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 9)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 9) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_horspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 16)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 16) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_uncertspeed_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_bearing_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 9, 9 } /* (SIZE(9..9)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 9, 9} /* (SIZE(9..9)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_horspeed_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 16, 16 } /* (SIZE(16..16)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 16, 16} /* (SIZE(16..16)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_uncertspeed_constr_4 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_Horveluncert_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct Horveluncert, bearing), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_bearing_constraint_1, - &asn_PER_memb_bearing_constr_2, - 0, - "bearing" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horveluncert, horspeed), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_horspeed_constraint_1, - &asn_PER_memb_horspeed_constr_3, - 0, - "horspeed" - }, - { ATF_NOFLAGS, 0, offsetof(struct Horveluncert, uncertspeed), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_uncertspeed_constraint_1, - &asn_PER_memb_uncertspeed_constr_4, - 0, - "uncertspeed" - }, + {ATF_NOFLAGS, 0, offsetof(struct Horveluncert, bearing), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_bearing_constraint_1, + &asn_PER_memb_bearing_constr_2, + 0, + "bearing"}, + {ATF_NOFLAGS, 0, offsetof(struct Horveluncert, horspeed), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_horspeed_constraint_1, + &asn_PER_memb_horspeed_constr_3, + 0, + "horspeed"}, + {ATF_NOFLAGS, 0, offsetof(struct Horveluncert, uncertspeed), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_uncertspeed_constraint_1, + &asn_PER_memb_uncertspeed_constr_4, + 0, + "uncertspeed"}, }; static ber_tlv_tag_t asn_DEF_Horveluncert_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))}; static asn_TYPE_tag2member_t asn_MAP_Horveluncert_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* bearing at 245 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* horspeed at 246 */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* uncertspeed at 247 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* bearing at 245 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0}, /* horspeed at 246 */ + {(ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0} /* uncertspeed at 247 */ }; static asn_SEQUENCE_specifics_t asn_SPC_Horveluncert_specs_1 = { - sizeof(struct Horveluncert), - offsetof(struct Horveluncert, _asn_ctx), - asn_MAP_Horveluncert_tag2el_1, - 3, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - 2, /* Start extensions */ - 4 /* Stop extensions */ + sizeof(struct Horveluncert), + offsetof(struct Horveluncert, _asn_ctx), + asn_MAP_Horveluncert_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 2, /* Start extensions */ + 4 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_Horveluncert = { - "Horveluncert", - "Horveluncert", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - SEQUENCE_decode_uper, - SEQUENCE_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_Horveluncert_tags_1, - sizeof(asn_DEF_Horveluncert_tags_1) - /sizeof(asn_DEF_Horveluncert_tags_1[0]), /* 1 */ - asn_DEF_Horveluncert_tags_1, /* Same as above */ - sizeof(asn_DEF_Horveluncert_tags_1) - /sizeof(asn_DEF_Horveluncert_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_Horveluncert_1, - 3, /* Elements count */ - &asn_SPC_Horveluncert_specs_1 /* Additional specs */ + "Horveluncert", + "Horveluncert", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Horveluncert_tags_1, + sizeof(asn_DEF_Horveluncert_tags_1) / sizeof(asn_DEF_Horveluncert_tags_1[0]), /* 1 */ + asn_DEF_Horveluncert_tags_1, /* Same as above */ + sizeof(asn_DEF_Horveluncert_tags_1) / sizeof(asn_DEF_Horveluncert_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Horveluncert_1, + 3, /* Elements count */ + &asn_SPC_Horveluncert_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/Horveluncert.h b/src/core/libs/supl/asn-supl/Horveluncert.h index 2dffd83ec..08037dc98 100644 --- a/src/core/libs/supl/asn-supl/Horveluncert.h +++ b/src/core/libs/supl/asn-supl/Horveluncert.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Horveluncert_H_ -#define _Horveluncert_H_ +#ifndef _Horveluncert_H_ +#define _Horveluncert_H_ #include @@ -15,29 +15,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Horveluncert */ -typedef struct Horveluncert { - BIT_STRING_t bearing; - BIT_STRING_t horspeed; - BIT_STRING_t uncertspeed; - /* + /* Horveluncert */ + typedef struct Horveluncert + { + BIT_STRING_t bearing; + BIT_STRING_t horspeed; + BIT_STRING_t uncertspeed; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Horveluncert_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Horveluncert; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Horveluncert_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Horveluncert; #ifdef __cplusplus } #endif -#endif /* _Horveluncert_H_ */ +#endif /* _Horveluncert_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/IA5String.h b/src/core/libs/supl/asn-supl/IA5String.h index e2a909dd5..74ccf6a75 100644 --- a/src/core/libs/supl/asn-supl/IA5String.h +++ b/src/core/libs/supl/asn-supl/IA5String.h @@ -2,26 +2,27 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _IA5String_H_ -#define _IA5String_H_ +#ifndef _IA5String_H_ +#define _IA5String_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef OCTET_STRING_t IA5String_t; /* Implemented via OCTET STRING */ + typedef OCTET_STRING_t IA5String_t; /* Implemented via OCTET STRING */ -/* + /* * IA5String ASN.1 type definition. */ -extern asn_TYPE_descriptor_t asn_DEF_IA5String; + extern asn_TYPE_descriptor_t asn_DEF_IA5String; -asn_constr_check_f IA5String_constraint; + asn_constr_check_f IA5String_constraint; #ifdef __cplusplus } #endif -#endif /* _IA5String_H_ */ +#endif /* _IA5String_H_ */ diff --git a/src/core/libs/supl/asn-supl/INTEGER.h b/src/core/libs/supl/asn-supl/INTEGER.h index 8411bfcdd..2acd13ab9 100644 --- a/src/core/libs/supl/asn-supl/INTEGER.h +++ b/src/core/libs/supl/asn-supl/INTEGER.h @@ -2,68 +2,71 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _INTEGER_H_ -#define _INTEGER_H_ +#ifndef _INTEGER_H_ +#define _INTEGER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; + typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; -extern asn_TYPE_descriptor_t asn_DEF_INTEGER; + extern asn_TYPE_descriptor_t asn_DEF_INTEGER; -/* Map with to integer value association */ -typedef struct asn_INTEGER_enum_map_s { - long nat_value; /* associated native integer value */ - size_t enum_len; /* strlen("tag") */ - const char *enum_name; /* "tag" */ -} asn_INTEGER_enum_map_t; + /* Map with to integer value association */ + typedef struct asn_INTEGER_enum_map_s + { + long nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ + } asn_INTEGER_enum_map_t; -/* This type describes an enumeration for INTEGER and ENUMERATED types */ -typedef struct asn_INTEGER_specifics_s { - asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ - unsigned int *enum2value; /* "tag" => N; sorted by tag */ - int map_count; /* Elements in either map */ - int extension; /* This map is extensible */ - int strict_enumeration; /* Enumeration set is fixed */ - int field_width; /* Size of native integer */ - int field_unsigned; /* Signed=0, unsigned=1 */ -} asn_INTEGER_specifics_t; + /* This type describes an enumeration for INTEGER and ENUMERATED types */ + typedef struct asn_INTEGER_specifics_s + { + asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + unsigned int *enum2value; /* "tag" => N; sorted by tag */ + int map_count; /* Elements in either map */ + int extension; /* This map is extensible */ + int strict_enumeration; /* Enumeration set is fixed */ + int field_width; /* Size of native integer */ + int field_unsigned; /* Signed=0, unsigned=1 */ + } asn_INTEGER_specifics_t; -asn_struct_print_f INTEGER_print; -ber_type_decoder_f INTEGER_decode_ber; -der_type_encoder_f INTEGER_encode_der; -xer_type_decoder_f INTEGER_decode_xer; -xer_type_encoder_f INTEGER_encode_xer; -per_type_decoder_f INTEGER_decode_uper; -per_type_encoder_f INTEGER_encode_uper; + asn_struct_print_f INTEGER_print; + ber_type_decoder_f INTEGER_decode_ber; + der_type_encoder_f INTEGER_encode_der; + xer_type_decoder_f INTEGER_decode_xer; + xer_type_encoder_f INTEGER_encode_xer; + per_type_decoder_f INTEGER_decode_uper; + per_type_encoder_f INTEGER_encode_uper; -/*********************************** + /*********************************** * Some handy conversion routines. * ***********************************/ -/* + /* * Returns 0 if it was possible to convert, -1 otherwise. * -1/EINVAL: Mandatory argument missing * -1/ERANGE: Value encoded is out of range for long representation * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). */ -int asn_INTEGER2long(const INTEGER_t *i, long *l); -int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); -int asn_long2INTEGER(INTEGER_t *i, long l); -int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); + int asn_INTEGER2long(const INTEGER_t *i, long *l); + int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); + int asn_long2INTEGER(INTEGER_t *i, long l); + int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); -/* + /* * Convert the integer value into the corresponding enumeration map entry. */ -const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); + const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); #ifdef __cplusplus } #endif -#endif /* _INTEGER_H_ */ +#endif /* _INTEGER_H_ */ diff --git a/src/core/libs/supl/asn-supl/IPAddress.c b/src/core/libs/supl/asn-supl/IPAddress.c index ddbef08c4..f1861adac 100644 --- a/src/core/libs/supl/asn-supl/IPAddress.c +++ b/src/core/libs/supl/asn-supl/IPAddress.c @@ -8,125 +8,132 @@ static int memb_ipv4Address_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 4)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 4) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_ipv6Address_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 16)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 16) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_ipv4Address_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 4, 4 } /* (SIZE(4..4)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 4, 4} /* (SIZE(4..4)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_ipv6Address_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 16, 16 } /* (SIZE(16..16)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 16, 16} /* (SIZE(16..16)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_type_IPAddress_constr_1 = { - { APC_CONSTRAINED, 1, 1, 0, 1 } /* (0..1) */, - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - 0, 0 /* No PER value map */ + {APC_CONSTRAINED, 1, 1, 0, 1} /* (0..1) */, + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_IPAddress_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct IPAddress, choice.ipv4Address), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_ipv4Address_constraint_1, - &asn_PER_memb_ipv4Address_constr_2, - 0, - "ipv4Address" - }, - { ATF_NOFLAGS, 0, offsetof(struct IPAddress, choice.ipv6Address), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_ipv6Address_constraint_1, - &asn_PER_memb_ipv6Address_constr_3, - 0, - "ipv6Address" - }, + {ATF_NOFLAGS, 0, offsetof(struct IPAddress, choice.ipv4Address), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_ipv4Address_constraint_1, + &asn_PER_memb_ipv4Address_constr_2, + 0, + "ipv4Address"}, + {ATF_NOFLAGS, 0, offsetof(struct IPAddress, choice.ipv6Address), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_ipv6Address_constraint_1, + &asn_PER_memb_ipv6Address_constr_3, + 0, + "ipv6Address"}, }; static asn_TYPE_tag2member_t asn_MAP_IPAddress_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* ipv4Address at 41 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* ipv6Address at 42 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* ipv4Address at 41 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0} /* ipv6Address at 42 */ }; static asn_CHOICE_specifics_t asn_SPC_IPAddress_specs_1 = { - sizeof(struct IPAddress), - offsetof(struct IPAddress, _asn_ctx), - offsetof(struct IPAddress, present), - sizeof(((struct IPAddress *)0)->present), - asn_MAP_IPAddress_tag2el_1, - 2, /* Count of tags in the map */ - 0, - -1 /* Extensions start */ + sizeof(struct IPAddress), + offsetof(struct IPAddress, _asn_ctx), + offsetof(struct IPAddress, present), + sizeof(((struct IPAddress *)0)->present), + asn_MAP_IPAddress_tag2el_1, + 2, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ }; asn_TYPE_descriptor_t asn_DEF_IPAddress = { - "IPAddress", - "IPAddress", - CHOICE_free, - CHOICE_print, - CHOICE_constraint, - CHOICE_decode_ber, - CHOICE_encode_der, - CHOICE_decode_xer, - CHOICE_encode_xer, - CHOICE_decode_uper, - CHOICE_encode_uper, - CHOICE_outmost_tag, - 0, /* No effective tags (pointer) */ - 0, /* No effective tags (count) */ - 0, /* No tags (pointer) */ - 0, /* No tags (count) */ - &asn_PER_type_IPAddress_constr_1, - asn_MBR_IPAddress_1, - 2, /* Elements count */ - &asn_SPC_IPAddress_specs_1 /* Additional specs */ + "IPAddress", + "IPAddress", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + CHOICE_decode_uper, + CHOICE_encode_uper, + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + &asn_PER_type_IPAddress_constr_1, + asn_MBR_IPAddress_1, + 2, /* Elements count */ + &asn_SPC_IPAddress_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/IPAddress.h b/src/core/libs/supl/asn-supl/IPAddress.h index 9058a5d27..a049e9d94 100644 --- a/src/core/libs/supl/asn-supl/IPAddress.h +++ b/src/core/libs/supl/asn-supl/IPAddress.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _IPAddress_H_ -#define _IPAddress_H_ +#ifndef _IPAddress_H_ +#define _IPAddress_H_ #include @@ -15,34 +15,38 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum IPAddress_PR { - IPAddress_PR_NOTHING, /* No components present */ - IPAddress_PR_ipv4Address, - IPAddress_PR_ipv6Address -} IPAddress_PR; + /* Dependencies */ + typedef enum IPAddress_PR + { + IPAddress_PR_NOTHING, /* No components present */ + IPAddress_PR_ipv4Address, + IPAddress_PR_ipv6Address + } IPAddress_PR; -/* IPAddress */ -typedef struct IPAddress { - IPAddress_PR present; - union IPAddress_u { - OCTET_STRING_t ipv4Address; - OCTET_STRING_t ipv6Address; - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} IPAddress_t; + /* IPAddress */ + typedef struct IPAddress + { + IPAddress_PR present; + union IPAddress_u + { + OCTET_STRING_t ipv4Address; + OCTET_STRING_t ipv6Address; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_IPAddress; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } IPAddress_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_IPAddress; #ifdef __cplusplus } #endif -#endif /* _IPAddress_H_ */ +#endif /* _IPAddress_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/KeyIdentity.c b/src/core/libs/supl/asn-supl/KeyIdentity.c index 210eacb06..49104664a 100644 --- a/src/core/libs/supl/asn-supl/KeyIdentity.c +++ b/src/core/libs/supl/asn-supl/KeyIdentity.c @@ -6,35 +6,42 @@ #include "KeyIdentity.h" -int -KeyIdentity_constraint(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 128)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } +int KeyIdentity_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 128) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } /* @@ -42,110 +49,113 @@ KeyIdentity_constraint(asn_TYPE_descriptor_t *td, const void *sptr, * so here we adjust the DEF accordingly. */ static void -KeyIdentity_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { - td->free_struct = asn_DEF_BIT_STRING.free_struct; - td->print_struct = asn_DEF_BIT_STRING.print_struct; - td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; - td->der_encoder = asn_DEF_BIT_STRING.der_encoder; - td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; - td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; - td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; - td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; - if(!td->per_constraints) - td->per_constraints = asn_DEF_BIT_STRING.per_constraints; - td->elements = asn_DEF_BIT_STRING.elements; - td->elements_count = asn_DEF_BIT_STRING.elements_count; - td->specifics = asn_DEF_BIT_STRING.specifics; +KeyIdentity_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) +{ + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if (!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; } -void -KeyIdentity_free(asn_TYPE_descriptor_t *td, - void *struct_ptr, int contents_only) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - td->free_struct(td, struct_ptr, contents_only); +void KeyIdentity_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); } -int -KeyIdentity_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +int KeyIdentity_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); } asn_dec_rval_t KeyIdentity_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const void *bufptr, size_t size, int tag_mode) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); + void **structure, const void *bufptr, size_t size, int tag_mode) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); } asn_enc_rval_t KeyIdentity_encode_der(asn_TYPE_descriptor_t *td, - void *structure, int tag_mode, ber_tlv_tag_t tag, - asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); } asn_dec_rval_t KeyIdentity_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const char *opt_mname, const void *bufptr, size_t size) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); + void **structure, const char *opt_mname, const void *bufptr, size_t size) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); } asn_enc_rval_t KeyIdentity_encode_xer(asn_TYPE_descriptor_t *td, void *structure, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); } asn_dec_rval_t KeyIdentity_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); + asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); } asn_enc_rval_t KeyIdentity_encode_uper(asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, - void *structure, asn_per_outp_t *per_out) { - KeyIdentity_1_inherit_TYPE_descriptor(td); - return td->uper_encoder(td, constraints, structure, per_out); + asn_per_constraints_t *constraints, + void *structure, asn_per_outp_t *per_out) +{ + KeyIdentity_1_inherit_TYPE_descriptor(td); + return td->uper_encoder(td, constraints, structure, per_out); } static asn_per_constraints_t asn_PER_type_KeyIdentity_constr_1 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 128, 128 } /* (SIZE(128..128)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 128, 128} /* (SIZE(128..128)) */, + 0, 0 /* No PER value map */ }; static ber_tlv_tag_t asn_DEF_KeyIdentity_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))}; asn_TYPE_descriptor_t asn_DEF_KeyIdentity = { - "KeyIdentity", - "KeyIdentity", - KeyIdentity_free, - KeyIdentity_print, - KeyIdentity_constraint, - KeyIdentity_decode_ber, - KeyIdentity_encode_der, - KeyIdentity_decode_xer, - KeyIdentity_encode_xer, - KeyIdentity_decode_uper, - KeyIdentity_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_KeyIdentity_tags_1, - sizeof(asn_DEF_KeyIdentity_tags_1) - /sizeof(asn_DEF_KeyIdentity_tags_1[0]), /* 1 */ - asn_DEF_KeyIdentity_tags_1, /* Same as above */ - sizeof(asn_DEF_KeyIdentity_tags_1) - /sizeof(asn_DEF_KeyIdentity_tags_1[0]), /* 1 */ - &asn_PER_type_KeyIdentity_constr_1, - 0, 0, /* No members */ - 0 /* No specifics */ + "KeyIdentity", + "KeyIdentity", + KeyIdentity_free, + KeyIdentity_print, + KeyIdentity_constraint, + KeyIdentity_decode_ber, + KeyIdentity_encode_der, + KeyIdentity_decode_xer, + KeyIdentity_encode_xer, + KeyIdentity_decode_uper, + KeyIdentity_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_KeyIdentity_tags_1, + sizeof(asn_DEF_KeyIdentity_tags_1) / sizeof(asn_DEF_KeyIdentity_tags_1[0]), /* 1 */ + asn_DEF_KeyIdentity_tags_1, /* Same as above */ + sizeof(asn_DEF_KeyIdentity_tags_1) / sizeof(asn_DEF_KeyIdentity_tags_1[0]), /* 1 */ + &asn_PER_type_KeyIdentity_constr_1, + 0, 0, /* No members */ + 0 /* No specifics */ }; - diff --git a/src/core/libs/supl/asn-supl/KeyIdentity.h b/src/core/libs/supl/asn-supl/KeyIdentity.h index edf2f28dc..1347758dc 100644 --- a/src/core/libs/supl/asn-supl/KeyIdentity.h +++ b/src/core/libs/supl/asn-supl/KeyIdentity.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _KeyIdentity_H_ -#define _KeyIdentity_H_ +#ifndef _KeyIdentity_H_ +#define _KeyIdentity_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* KeyIdentity */ -typedef BIT_STRING_t KeyIdentity_t; + /* KeyIdentity */ + typedef BIT_STRING_t KeyIdentity_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_KeyIdentity; -asn_struct_free_f KeyIdentity_free; -asn_struct_print_f KeyIdentity_print; -asn_constr_check_f KeyIdentity_constraint; -ber_type_decoder_f KeyIdentity_decode_ber; -der_type_encoder_f KeyIdentity_encode_der; -xer_type_decoder_f KeyIdentity_decode_xer; -xer_type_encoder_f KeyIdentity_encode_xer; -per_type_decoder_f KeyIdentity_decode_uper; -per_type_encoder_f KeyIdentity_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_KeyIdentity; + asn_struct_free_f KeyIdentity_free; + asn_struct_print_f KeyIdentity_print; + asn_constr_check_f KeyIdentity_constraint; + ber_type_decoder_f KeyIdentity_decode_ber; + der_type_encoder_f KeyIdentity_encode_der; + xer_type_decoder_f KeyIdentity_decode_xer; + xer_type_encoder_f KeyIdentity_encode_xer; + per_type_decoder_f KeyIdentity_decode_uper; + per_type_encoder_f KeyIdentity_encode_uper; #ifdef __cplusplus } #endif -#endif /* _KeyIdentity_H_ */ +#endif /* _KeyIdentity_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/KeyIdentity4.c b/src/core/libs/supl/asn-supl/KeyIdentity4.c index 1a993f1bd..ef652c319 100644 --- a/src/core/libs/supl/asn-supl/KeyIdentity4.c +++ b/src/core/libs/supl/asn-supl/KeyIdentity4.c @@ -6,35 +6,42 @@ #include "KeyIdentity4.h" -int -KeyIdentity4_constraint(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 128)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } +int KeyIdentity4_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 128) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } /* @@ -42,110 +49,113 @@ KeyIdentity4_constraint(asn_TYPE_descriptor_t *td, const void *sptr, * so here we adjust the DEF accordingly. */ static void -KeyIdentity4_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { - td->free_struct = asn_DEF_BIT_STRING.free_struct; - td->print_struct = asn_DEF_BIT_STRING.print_struct; - td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; - td->der_encoder = asn_DEF_BIT_STRING.der_encoder; - td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; - td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; - td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; - td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; - if(!td->per_constraints) - td->per_constraints = asn_DEF_BIT_STRING.per_constraints; - td->elements = asn_DEF_BIT_STRING.elements; - td->elements_count = asn_DEF_BIT_STRING.elements_count; - td->specifics = asn_DEF_BIT_STRING.specifics; +KeyIdentity4_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) +{ + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if (!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; } -void -KeyIdentity4_free(asn_TYPE_descriptor_t *td, - void *struct_ptr, int contents_only) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - td->free_struct(td, struct_ptr, contents_only); +void KeyIdentity4_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); } -int -KeyIdentity4_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +int KeyIdentity4_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); } asn_dec_rval_t KeyIdentity4_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const void *bufptr, size_t size, int tag_mode) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); + void **structure, const void *bufptr, size_t size, int tag_mode) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); } asn_enc_rval_t KeyIdentity4_encode_der(asn_TYPE_descriptor_t *td, - void *structure, int tag_mode, ber_tlv_tag_t tag, - asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); } asn_dec_rval_t KeyIdentity4_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const char *opt_mname, const void *bufptr, size_t size) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); + void **structure, const char *opt_mname, const void *bufptr, size_t size) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); } asn_enc_rval_t KeyIdentity4_encode_xer(asn_TYPE_descriptor_t *td, void *structure, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); } asn_dec_rval_t KeyIdentity4_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); + asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); } asn_enc_rval_t KeyIdentity4_encode_uper(asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, - void *structure, asn_per_outp_t *per_out) { - KeyIdentity4_1_inherit_TYPE_descriptor(td); - return td->uper_encoder(td, constraints, structure, per_out); + asn_per_constraints_t *constraints, + void *structure, asn_per_outp_t *per_out) +{ + KeyIdentity4_1_inherit_TYPE_descriptor(td); + return td->uper_encoder(td, constraints, structure, per_out); } static asn_per_constraints_t asn_PER_type_KeyIdentity4_constr_1 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 128, 128 } /* (SIZE(128..128)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 128, 128} /* (SIZE(128..128)) */, + 0, 0 /* No PER value map */ }; static ber_tlv_tag_t asn_DEF_KeyIdentity4_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))}; asn_TYPE_descriptor_t asn_DEF_KeyIdentity4 = { - "KeyIdentity4", - "KeyIdentity4", - KeyIdentity4_free, - KeyIdentity4_print, - KeyIdentity4_constraint, - KeyIdentity4_decode_ber, - KeyIdentity4_encode_der, - KeyIdentity4_decode_xer, - KeyIdentity4_encode_xer, - KeyIdentity4_decode_uper, - KeyIdentity4_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_KeyIdentity4_tags_1, - sizeof(asn_DEF_KeyIdentity4_tags_1) - /sizeof(asn_DEF_KeyIdentity4_tags_1[0]), /* 1 */ - asn_DEF_KeyIdentity4_tags_1, /* Same as above */ - sizeof(asn_DEF_KeyIdentity4_tags_1) - /sizeof(asn_DEF_KeyIdentity4_tags_1[0]), /* 1 */ - &asn_PER_type_KeyIdentity4_constr_1, - 0, 0, /* No members */ - 0 /* No specifics */ + "KeyIdentity4", + "KeyIdentity4", + KeyIdentity4_free, + KeyIdentity4_print, + KeyIdentity4_constraint, + KeyIdentity4_decode_ber, + KeyIdentity4_encode_der, + KeyIdentity4_decode_xer, + KeyIdentity4_encode_xer, + KeyIdentity4_decode_uper, + KeyIdentity4_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_KeyIdentity4_tags_1, + sizeof(asn_DEF_KeyIdentity4_tags_1) / sizeof(asn_DEF_KeyIdentity4_tags_1[0]), /* 1 */ + asn_DEF_KeyIdentity4_tags_1, /* Same as above */ + sizeof(asn_DEF_KeyIdentity4_tags_1) / sizeof(asn_DEF_KeyIdentity4_tags_1[0]), /* 1 */ + &asn_PER_type_KeyIdentity4_constr_1, + 0, 0, /* No members */ + 0 /* No specifics */ }; - diff --git a/src/core/libs/supl/asn-supl/KeyIdentity4.h b/src/core/libs/supl/asn-supl/KeyIdentity4.h index bb25f736d..f2e502475 100644 --- a/src/core/libs/supl/asn-supl/KeyIdentity4.h +++ b/src/core/libs/supl/asn-supl/KeyIdentity4.h @@ -4,8 +4,8 @@ * found in "../supl-response.asn" */ -#ifndef _KeyIdentity4_H_ -#define _KeyIdentity4_H_ +#ifndef _KeyIdentity4_H_ +#define _KeyIdentity4_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* KeyIdentity4 */ -typedef BIT_STRING_t KeyIdentity4_t; + /* KeyIdentity4 */ + typedef BIT_STRING_t KeyIdentity4_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_KeyIdentity4; -asn_struct_free_f KeyIdentity4_free; -asn_struct_print_f KeyIdentity4_print; -asn_constr_check_f KeyIdentity4_constraint; -ber_type_decoder_f KeyIdentity4_decode_ber; -der_type_encoder_f KeyIdentity4_encode_der; -xer_type_decoder_f KeyIdentity4_decode_xer; -xer_type_encoder_f KeyIdentity4_encode_xer; -per_type_decoder_f KeyIdentity4_decode_uper; -per_type_encoder_f KeyIdentity4_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_KeyIdentity4; + asn_struct_free_f KeyIdentity4_free; + asn_struct_print_f KeyIdentity4_print; + asn_constr_check_f KeyIdentity4_constraint; + ber_type_decoder_f KeyIdentity4_decode_ber; + der_type_encoder_f KeyIdentity4_encode_der; + xer_type_decoder_f KeyIdentity4_decode_xer; + xer_type_encoder_f KeyIdentity4_encode_xer; + per_type_decoder_f KeyIdentity4_decode_uper; + per_type_encoder_f KeyIdentity4_encode_uper; #ifdef __cplusplus } #endif -#endif /* _KeyIdentity4_H_ */ +#endif /* _KeyIdentity4_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/LocationId.h b/src/core/libs/supl/asn-supl/LocationId.h index 524af12cf..55842f70b 100644 --- a/src/core/libs/supl/asn-supl/LocationId.h +++ b/src/core/libs/supl/asn-supl/LocationId.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _LocationId_H_ -#define _LocationId_H_ +#ifndef _LocationId_H_ +#define _LocationId_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* LocationId */ -typedef struct LocationId { - CellInfo_t cellInfo; - Status_t status; - /* + /* LocationId */ + typedef struct LocationId + { + CellInfo_t cellInfo; + Status_t status; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} LocationId_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_LocationId; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } LocationId_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_LocationId; #ifdef __cplusplus } #endif -#endif /* _LocationId_H_ */ +#endif /* _LocationId_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/MAC.c b/src/core/libs/supl/asn-supl/MAC.c index 03ab5da2c..5592eaf53 100644 --- a/src/core/libs/supl/asn-supl/MAC.c +++ b/src/core/libs/supl/asn-supl/MAC.c @@ -6,35 +6,42 @@ #include "MAC.h" -int -MAC_constraint(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 64)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } +int MAC_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 64) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } /* @@ -42,110 +49,113 @@ MAC_constraint(asn_TYPE_descriptor_t *td, const void *sptr, * so here we adjust the DEF accordingly. */ static void -MAC_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { - td->free_struct = asn_DEF_BIT_STRING.free_struct; - td->print_struct = asn_DEF_BIT_STRING.print_struct; - td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; - td->der_encoder = asn_DEF_BIT_STRING.der_encoder; - td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; - td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; - td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; - td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; - if(!td->per_constraints) - td->per_constraints = asn_DEF_BIT_STRING.per_constraints; - td->elements = asn_DEF_BIT_STRING.elements; - td->elements_count = asn_DEF_BIT_STRING.elements_count; - td->specifics = asn_DEF_BIT_STRING.specifics; +MAC_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) +{ + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if (!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; } -void -MAC_free(asn_TYPE_descriptor_t *td, - void *struct_ptr, int contents_only) { - MAC_1_inherit_TYPE_descriptor(td); - td->free_struct(td, struct_ptr, contents_only); +void MAC_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) +{ + MAC_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); } -int -MAC_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - MAC_1_inherit_TYPE_descriptor(td); - return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +int MAC_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); } asn_dec_rval_t MAC_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const void *bufptr, size_t size, int tag_mode) { - MAC_1_inherit_TYPE_descriptor(td); - return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); + void **structure, const void *bufptr, size_t size, int tag_mode) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); } asn_enc_rval_t MAC_encode_der(asn_TYPE_descriptor_t *td, - void *structure, int tag_mode, ber_tlv_tag_t tag, - asn_app_consume_bytes_f *cb, void *app_key) { - MAC_1_inherit_TYPE_descriptor(td); - return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); } asn_dec_rval_t MAC_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const char *opt_mname, const void *bufptr, size_t size) { - MAC_1_inherit_TYPE_descriptor(td); - return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); + void **structure, const char *opt_mname, const void *bufptr, size_t size) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); } asn_enc_rval_t MAC_encode_xer(asn_TYPE_descriptor_t *td, void *structure, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - MAC_1_inherit_TYPE_descriptor(td); - return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); } asn_dec_rval_t MAC_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) { - MAC_1_inherit_TYPE_descriptor(td); - return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); + asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); } asn_enc_rval_t MAC_encode_uper(asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, - void *structure, asn_per_outp_t *per_out) { - MAC_1_inherit_TYPE_descriptor(td); - return td->uper_encoder(td, constraints, structure, per_out); + asn_per_constraints_t *constraints, + void *structure, asn_per_outp_t *per_out) +{ + MAC_1_inherit_TYPE_descriptor(td); + return td->uper_encoder(td, constraints, structure, per_out); } static asn_per_constraints_t asn_PER_type_MAC_constr_1 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 64, 64 } /* (SIZE(64..64)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 64, 64} /* (SIZE(64..64)) */, + 0, 0 /* No PER value map */ }; static ber_tlv_tag_t asn_DEF_MAC_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))}; asn_TYPE_descriptor_t asn_DEF_MAC = { - "MAC", - "MAC", - MAC_free, - MAC_print, - MAC_constraint, - MAC_decode_ber, - MAC_encode_der, - MAC_decode_xer, - MAC_encode_xer, - MAC_decode_uper, - MAC_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_MAC_tags_1, - sizeof(asn_DEF_MAC_tags_1) - /sizeof(asn_DEF_MAC_tags_1[0]), /* 1 */ - asn_DEF_MAC_tags_1, /* Same as above */ - sizeof(asn_DEF_MAC_tags_1) - /sizeof(asn_DEF_MAC_tags_1[0]), /* 1 */ - &asn_PER_type_MAC_constr_1, - 0, 0, /* No members */ - 0 /* No specifics */ + "MAC", + "MAC", + MAC_free, + MAC_print, + MAC_constraint, + MAC_decode_ber, + MAC_encode_der, + MAC_decode_xer, + MAC_encode_xer, + MAC_decode_uper, + MAC_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_MAC_tags_1, + sizeof(asn_DEF_MAC_tags_1) / sizeof(asn_DEF_MAC_tags_1[0]), /* 1 */ + asn_DEF_MAC_tags_1, /* Same as above */ + sizeof(asn_DEF_MAC_tags_1) / sizeof(asn_DEF_MAC_tags_1[0]), /* 1 */ + &asn_PER_type_MAC_constr_1, + 0, 0, /* No members */ + 0 /* No specifics */ }; - diff --git a/src/core/libs/supl/asn-supl/MAC.h b/src/core/libs/supl/asn-supl/MAC.h index 178896171..27a57977b 100644 --- a/src/core/libs/supl/asn-supl/MAC.h +++ b/src/core/libs/supl/asn-supl/MAC.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _MAC_H_ -#define _MAC_H_ +#ifndef _MAC_H_ +#define _MAC_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* MAC */ -typedef BIT_STRING_t MAC_t; + /* MAC */ + typedef BIT_STRING_t MAC_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MAC; -asn_struct_free_f MAC_free; -asn_struct_print_f MAC_print; -asn_constr_check_f MAC_constraint; -ber_type_decoder_f MAC_decode_ber; -der_type_encoder_f MAC_encode_der; -xer_type_decoder_f MAC_decode_xer; -xer_type_encoder_f MAC_encode_xer; -per_type_decoder_f MAC_decode_uper; -per_type_encoder_f MAC_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MAC; + asn_struct_free_f MAC_free; + asn_struct_print_f MAC_print; + asn_constr_check_f MAC_constraint; + ber_type_decoder_f MAC_decode_ber; + der_type_encoder_f MAC_encode_der; + xer_type_decoder_f MAC_decode_xer; + xer_type_encoder_f MAC_encode_xer; + per_type_decoder_f MAC_decode_uper; + per_type_encoder_f MAC_encode_uper; #ifdef __cplusplus } #endif -#endif /* _MAC_H_ */ +#endif /* _MAC_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/MeasuredResults.h b/src/core/libs/supl/asn-supl/MeasuredResults.h index 29a09a839..4b082732f 100644 --- a/src/core/libs/supl/asn-supl/MeasuredResults.h +++ b/src/core/libs/supl/asn-supl/MeasuredResults.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _MeasuredResults_H_ -#define _MeasuredResults_H_ +#ifndef _MeasuredResults_H_ +#define _MeasuredResults_H_ #include @@ -15,25 +15,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct FrequencyInfo; -struct CellMeasuredResultsList; + /* Forward declarations */ + struct FrequencyInfo; + struct CellMeasuredResultsList; -/* MeasuredResults */ -typedef struct MeasuredResults { - struct FrequencyInfo *frequencyInfo /* OPTIONAL */; - UTRA_CarrierRSSI_t *utra_CarrierRSSI /* OPTIONAL */; - struct CellMeasuredResultsList *cellMeasuredResultsList /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MeasuredResults_t; + /* MeasuredResults */ + typedef struct MeasuredResults + { + struct FrequencyInfo *frequencyInfo /* OPTIONAL */; + UTRA_CarrierRSSI_t *utra_CarrierRSSI /* OPTIONAL */; + struct CellMeasuredResultsList *cellMeasuredResultsList /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MeasuredResults; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MeasuredResults_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MeasuredResults; #ifdef __cplusplus } @@ -43,5 +45,5 @@ extern asn_TYPE_descriptor_t asn_DEF_MeasuredResults; #include "FrequencyInfo.h" #include "CellMeasuredResultsList.h" -#endif /* _MeasuredResults_H_ */ +#endif /* _MeasuredResults_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/MeasuredResultsList.h b/src/core/libs/supl/asn-supl/MeasuredResultsList.h index fe174cdc4..6195c1876 100644 --- a/src/core/libs/supl/asn-supl/MeasuredResultsList.h +++ b/src/core/libs/supl/asn-supl/MeasuredResultsList.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _MeasuredResultsList_H_ -#define _MeasuredResultsList_H_ +#ifndef _MeasuredResultsList_H_ +#define _MeasuredResultsList_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct MeasuredResults; + /* Forward declarations */ + struct MeasuredResults; -/* MeasuredResultsList */ -typedef struct MeasuredResultsList { - A_SEQUENCE_OF(struct MeasuredResults) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} MeasuredResultsList_t; + /* MeasuredResultsList */ + typedef struct MeasuredResultsList + { + A_SEQUENCE_OF(struct MeasuredResults) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_MeasuredResultsList; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } MeasuredResultsList_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_MeasuredResultsList; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_MeasuredResultsList; /* Referred external types */ #include "MeasuredResults.h" -#endif /* _MeasuredResultsList_H_ */ +#endif /* _MeasuredResultsList_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/NMR.h b/src/core/libs/supl/asn-supl/NMR.h index de1916002..629681368 100644 --- a/src/core/libs/supl/asn-supl/NMR.h +++ b/src/core/libs/supl/asn-supl/NMR.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _NMR_H_ -#define _NMR_H_ +#ifndef _NMR_H_ +#define _NMR_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct NMRelement; + /* Forward declarations */ + struct NMRelement; -/* NMR */ -typedef struct NMR { - A_SEQUENCE_OF(struct NMRelement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NMR_t; + /* NMR */ + typedef struct NMR + { + A_SEQUENCE_OF(struct NMRelement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NMR; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NMR_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NMR; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_NMR; /* Referred external types */ #include "NMRelement.h" -#endif /* _NMR_H_ */ +#endif /* _NMR_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/NMRelement.h b/src/core/libs/supl/asn-supl/NMRelement.h index aa0873bb0..1ea9d3b5e 100644 --- a/src/core/libs/supl/asn-supl/NMRelement.h +++ b/src/core/libs/supl/asn-supl/NMRelement.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _NMRelement_H_ -#define _NMRelement_H_ +#ifndef _NMRelement_H_ +#define _NMRelement_H_ #include @@ -15,29 +15,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* NMRelement */ -typedef struct NMRelement { - long aRFCN; - long bSIC; - long rxLev; - /* + /* NMRelement */ + typedef struct NMRelement + { + long aRFCN; + long bSIC; + long rxLev; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} NMRelement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NMRelement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } NMRelement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NMRelement; #ifdef __cplusplus } #endif -#endif /* _NMRelement_H_ */ +#endif /* _NMRelement_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/NativeEnumerated.h b/src/core/libs/supl/asn-supl/NativeEnumerated.h index c59bb1ba9..3b3d4b074 100644 --- a/src/core/libs/supl/asn-supl/NativeEnumerated.h +++ b/src/core/libs/supl/asn-supl/NativeEnumerated.h @@ -10,23 +10,24 @@ * will do). * This type may be used when integer range is limited by subtype constraints. */ -#ifndef _NativeEnumerated_H_ -#define _NativeEnumerated_H_ +#ifndef _NativeEnumerated_H_ +#define _NativeEnumerated_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; + extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; -xer_type_encoder_f NativeEnumerated_encode_xer; -per_type_decoder_f NativeEnumerated_decode_uper; -per_type_encoder_f NativeEnumerated_encode_uper; + xer_type_encoder_f NativeEnumerated_encode_xer; + per_type_decoder_f NativeEnumerated_decode_uper; + per_type_encoder_f NativeEnumerated_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NativeEnumerated_H_ */ +#endif /* _NativeEnumerated_H_ */ diff --git a/src/core/libs/supl/asn-supl/NativeInteger.c b/src/core/libs/supl/asn-supl/NativeInteger.c index abdb71a8c..76140a22e 100644 --- a/src/core/libs/supl/asn-supl/NativeInteger.c +++ b/src/core/libs/supl/asn-supl/NativeInteger.c @@ -107,7 +107,7 @@ NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, tmp.size = length; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmp, &l) + ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) : asn_INTEGER2long(&tmp, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -187,7 +187,7 @@ NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, if(rval.code == RC_OK) { long l; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&st, &l) + ? asn_INTEGER2ulong(&st, (unsigned long *)&l) : asn_INTEGER2long(&st, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -255,7 +255,7 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, &tmpintptr, pd); if(rval.code == RC_OK) { if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmpint, native) + ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) : asn_INTEGER2long(&tmpint, native)) rval.code = RC_FAIL; else diff --git a/src/core/libs/supl/asn-supl/NativeInteger.h b/src/core/libs/supl/asn-supl/NativeInteger.h index 4e63a8355..14311ae57 100644 --- a/src/core/libs/supl/asn-supl/NativeInteger.h +++ b/src/core/libs/supl/asn-supl/NativeInteger.h @@ -9,29 +9,30 @@ * will do). * This type may be used when integer range is limited by subtype constraints. */ -#ifndef _NativeInteger_H_ -#define _NativeInteger_H_ +#ifndef _NativeInteger_H_ +#define _NativeInteger_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; + extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; -asn_struct_free_f NativeInteger_free; -asn_struct_print_f NativeInteger_print; -ber_type_decoder_f NativeInteger_decode_ber; -der_type_encoder_f NativeInteger_encode_der; -xer_type_decoder_f NativeInteger_decode_xer; -xer_type_encoder_f NativeInteger_encode_xer; -per_type_decoder_f NativeInteger_decode_uper; -per_type_encoder_f NativeInteger_encode_uper; + asn_struct_free_f NativeInteger_free; + asn_struct_print_f NativeInteger_print; + ber_type_decoder_f NativeInteger_decode_ber; + der_type_encoder_f NativeInteger_encode_der; + xer_type_decoder_f NativeInteger_decode_xer; + xer_type_encoder_f NativeInteger_encode_xer; + per_type_decoder_f NativeInteger_decode_uper; + per_type_encoder_f NativeInteger_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NativeInteger_H_ */ +#endif /* _NativeInteger_H_ */ diff --git a/src/core/libs/supl/asn-supl/Notification.h b/src/core/libs/supl/asn-supl/Notification.h index 696de7da6..5e2f488ee 100644 --- a/src/core/libs/supl/asn-supl/Notification.h +++ b/src/core/libs/supl/asn-supl/Notification.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _Notification_H_ -#define _Notification_H_ +#ifndef _Notification_H_ +#define _Notification_H_ #include @@ -18,32 +18,34 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Notification */ -typedef struct Notification { - NotificationType_t notificationType; - EncodingType_t *encodingType /* OPTIONAL */; - OCTET_STRING_t *requestorId /* OPTIONAL */; - FormatIndicator_t *requestorIdType /* OPTIONAL */; - OCTET_STRING_t *clientName /* OPTIONAL */; - FormatIndicator_t *clientNameType /* OPTIONAL */; - /* + /* Notification */ + typedef struct Notification + { + NotificationType_t notificationType; + EncodingType_t *encodingType /* OPTIONAL */; + OCTET_STRING_t *requestorId /* OPTIONAL */; + FormatIndicator_t *requestorIdType /* OPTIONAL */; + OCTET_STRING_t *clientName /* OPTIONAL */; + FormatIndicator_t *clientNameType /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Notification_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Notification; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Notification_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Notification; #ifdef __cplusplus } #endif -#endif /* _Notification_H_ */ +#endif /* _Notification_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/NotificationType.h b/src/core/libs/supl/asn-supl/NotificationType.h index 939b259ca..24012dbcf 100644 --- a/src/core/libs/supl/asn-supl/NotificationType.h +++ b/src/core/libs/supl/asn-supl/NotificationType.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _NotificationType_H_ -#define _NotificationType_H_ +#ifndef _NotificationType_H_ +#define _NotificationType_H_ #include @@ -14,39 +14,41 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum NotificationType { - NotificationType_noNotificationNoVerification = 0, - NotificationType_notificationOnly = 1, - NotificationType_notificationAndVerficationAllowedNA = 2, - NotificationType_notificationAndVerficationDeniedNA = 3, - NotificationType_privacyOverride = 4 - /* + /* Dependencies */ + typedef enum NotificationType + { + NotificationType_noNotificationNoVerification = 0, + NotificationType_notificationOnly = 1, + NotificationType_notificationAndVerficationAllowedNA = 2, + NotificationType_notificationAndVerficationDeniedNA = 3, + NotificationType_privacyOverride = 4 + /* * Enumeration is extensible */ -} e_NotificationType; + } e_NotificationType; -/* NotificationType */ -typedef ENUMERATED_t NotificationType_t; + /* NotificationType */ + typedef ENUMERATED_t NotificationType_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_NotificationType; -asn_struct_free_f NotificationType_free; -asn_struct_print_f NotificationType_print; -asn_constr_check_f NotificationType_constraint; -ber_type_decoder_f NotificationType_decode_ber; -der_type_encoder_f NotificationType_encode_der; -xer_type_decoder_f NotificationType_decode_xer; -xer_type_encoder_f NotificationType_encode_xer; -per_type_decoder_f NotificationType_decode_uper; -per_type_encoder_f NotificationType_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_NotificationType; + asn_struct_free_f NotificationType_free; + asn_struct_print_f NotificationType_print; + asn_constr_check_f NotificationType_constraint; + ber_type_decoder_f NotificationType_decode_ber; + der_type_encoder_f NotificationType_encode_der; + xer_type_decoder_f NotificationType_decode_xer; + xer_type_encoder_f NotificationType_encode_xer; + per_type_decoder_f NotificationType_decode_uper; + per_type_encoder_f NotificationType_encode_uper; #ifdef __cplusplus } #endif -#endif /* _NotificationType_H_ */ +#endif /* _NotificationType_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/OCTET_STRING.c b/src/core/libs/supl/asn-supl/OCTET_STRING.c index 584def8b4..bd2d1d845 100644 --- a/src/core/libs/supl/asn-supl/OCTET_STRING.c +++ b/src/core/libs/supl/asn-supl/OCTET_STRING.c @@ -52,9 +52,9 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { #undef NEXT_PHASE #undef PREV_PHASE #define _CH_PHASE(ctx, inc) do { \ - if(ctx->phase == 0) \ - ctx->context = 0; \ - ctx->phase += inc; \ + if((ctx)->phase == 0) \ + (ctx)->context = 0; \ + (ctx)->phase += (inc); \ } while(0) #define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) #define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) diff --git a/src/core/libs/supl/asn-supl/OCTET_STRING.h b/src/core/libs/supl/asn-supl/OCTET_STRING.h index 8df9a182d..124fde559 100644 --- a/src/core/libs/supl/asn-supl/OCTET_STRING.h +++ b/src/core/libs/supl/asn-supl/OCTET_STRING.h @@ -2,42 +2,44 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _OCTET_STRING_H_ -#define _OCTET_STRING_H_ +#ifndef _OCTET_STRING_H_ +#define _OCTET_STRING_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct OCTET_STRING { - uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ - int size; /* Size of the buffer */ + typedef struct OCTET_STRING + { + uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ + int size; /* Size of the buffer */ - asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -} OCTET_STRING_t; + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ + } OCTET_STRING_t; -extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; + extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; -asn_struct_free_f OCTET_STRING_free; -asn_struct_print_f OCTET_STRING_print; -asn_struct_print_f OCTET_STRING_print_utf8; -ber_type_decoder_f OCTET_STRING_decode_ber; -der_type_encoder_f OCTET_STRING_encode_der; -xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ -xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ -xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ -xer_type_encoder_f OCTET_STRING_encode_xer; -xer_type_encoder_f OCTET_STRING_encode_xer_utf8; -per_type_decoder_f OCTET_STRING_decode_uper; -per_type_encoder_f OCTET_STRING_encode_uper; + asn_struct_free_f OCTET_STRING_free; + asn_struct_print_f OCTET_STRING_print; + asn_struct_print_f OCTET_STRING_print_utf8; + ber_type_decoder_f OCTET_STRING_decode_ber; + der_type_encoder_f OCTET_STRING_encode_der; + xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ + xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ + xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ + xer_type_encoder_f OCTET_STRING_encode_xer; + xer_type_encoder_f OCTET_STRING_encode_xer_utf8; + per_type_decoder_f OCTET_STRING_decode_uper; + per_type_encoder_f OCTET_STRING_encode_uper; -/****************************** + /****************************** * Handy conversion routines. * ******************************/ -/* + /* * This function clears the previous value of the OCTET STRING (if any) * and then allocates a new memory with the specified content (str/size). * If size = -1, the size of the original string will be determined @@ -46,41 +48,43 @@ per_type_encoder_f OCTET_STRING_encode_uper; * current contents of the OCTET STRING. * Returns 0 if it was possible to perform operation, -1 otherwise. */ -int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); + int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); /* Handy conversion from the C string into the OCTET STRING. */ -#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) +#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) -/* + /* * Allocate and fill the new OCTET STRING and return a pointer to the newly * allocated object. NULL is permitted in str: the function will just allocate * empty OCTET STRING. */ -OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, - const char *str, int size); + OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, + const char *str, int size); -/**************************** + /**************************** * Internally useful stuff. * ****************************/ -typedef struct asn_OCTET_STRING_specifics_s { - /* + typedef struct asn_OCTET_STRING_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the structure */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the structure */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - enum asn_OS_Subvariant { - ASN_OSUBV_ANY, /* The open type (ANY) */ - ASN_OSUBV_BIT, /* BIT STRING */ - ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ - ASN_OSUBV_U16, /* 16-bit character (BMPString) */ - ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ - } subvariant; -} asn_OCTET_STRING_specifics_t; + enum asn_OS_Subvariant + { + ASN_OSUBV_ANY, /* The open type (ANY) */ + ASN_OSUBV_BIT, /* BIT STRING */ + ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ + ASN_OSUBV_U16, /* 16-bit character (BMPString) */ + ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ + } subvariant; + } asn_OCTET_STRING_specifics_t; #ifdef __cplusplus } #endif -#endif /* _OCTET_STRING_H_ */ +#endif /* _OCTET_STRING_H_ */ diff --git a/src/core/libs/supl/asn-supl/Pathloss.h b/src/core/libs/supl/asn-supl/Pathloss.h index b7cf2c5fc..e0f0aa474 100644 --- a/src/core/libs/supl/asn-supl/Pathloss.h +++ b/src/core/libs/supl/asn-supl/Pathloss.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Pathloss_H_ -#define _Pathloss_H_ +#ifndef _Pathloss_H_ +#define _Pathloss_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Pathloss */ -typedef long Pathloss_t; + /* Pathloss */ + typedef long Pathloss_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Pathloss; -asn_struct_free_f Pathloss_free; -asn_struct_print_f Pathloss_print; -asn_constr_check_f Pathloss_constraint; -ber_type_decoder_f Pathloss_decode_ber; -der_type_encoder_f Pathloss_encode_der; -xer_type_decoder_f Pathloss_decode_xer; -xer_type_encoder_f Pathloss_encode_xer; -per_type_decoder_f Pathloss_decode_uper; -per_type_encoder_f Pathloss_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Pathloss; + asn_struct_free_f Pathloss_free; + asn_struct_print_f Pathloss_print; + asn_constr_check_f Pathloss_constraint; + ber_type_decoder_f Pathloss_decode_ber; + der_type_encoder_f Pathloss_encode_der; + xer_type_decoder_f Pathloss_decode_xer; + xer_type_encoder_f Pathloss_encode_xer; + per_type_decoder_f Pathloss_decode_uper; + per_type_encoder_f Pathloss_encode_uper; #ifdef __cplusplus } #endif -#endif /* _Pathloss_H_ */ +#endif /* _Pathloss_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PosMethod.h b/src/core/libs/supl/asn-supl/PosMethod.h index 89d77b330..e34dd5a14 100644 --- a/src/core/libs/supl/asn-supl/PosMethod.h +++ b/src/core/libs/supl/asn-supl/PosMethod.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _PosMethod_H_ -#define _PosMethod_H_ +#ifndef _PosMethod_H_ +#define _PosMethod_H_ #include @@ -14,44 +14,46 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum PosMethod { - PosMethod_agpsSETassisted = 0, - PosMethod_agpsSETbased = 1, - PosMethod_agpsSETassistedpref = 2, - PosMethod_agpsSETbasedpref = 3, - PosMethod_autonomousGPS = 4, - PosMethod_aFLT = 5, - PosMethod_eCID = 6, - PosMethod_eOTD = 7, - PosMethod_oTDOA = 8, - PosMethod_noPosition = 9 - /* + /* Dependencies */ + typedef enum PosMethod + { + PosMethod_agpsSETassisted = 0, + PosMethod_agpsSETbased = 1, + PosMethod_agpsSETassistedpref = 2, + PosMethod_agpsSETbasedpref = 3, + PosMethod_autonomousGPS = 4, + PosMethod_aFLT = 5, + PosMethod_eCID = 6, + PosMethod_eOTD = 7, + PosMethod_oTDOA = 8, + PosMethod_noPosition = 9 + /* * Enumeration is extensible */ -} e_PosMethod; + } e_PosMethod; -/* PosMethod */ -typedef ENUMERATED_t PosMethod_t; + /* PosMethod */ + typedef ENUMERATED_t PosMethod_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PosMethod; -asn_struct_free_f PosMethod_free; -asn_struct_print_f PosMethod_print; -asn_constr_check_f PosMethod_constraint; -ber_type_decoder_f PosMethod_decode_ber; -der_type_encoder_f PosMethod_encode_der; -xer_type_decoder_f PosMethod_decode_xer; -xer_type_encoder_f PosMethod_encode_xer; -per_type_decoder_f PosMethod_decode_uper; -per_type_encoder_f PosMethod_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PosMethod; + asn_struct_free_f PosMethod_free; + asn_struct_print_f PosMethod_print; + asn_constr_check_f PosMethod_constraint; + ber_type_decoder_f PosMethod_decode_ber; + der_type_encoder_f PosMethod_encode_der; + xer_type_decoder_f PosMethod_decode_xer; + xer_type_encoder_f PosMethod_encode_xer; + per_type_decoder_f PosMethod_decode_uper; + per_type_encoder_f PosMethod_encode_uper; #ifdef __cplusplus } #endif -#endif /* _PosMethod_H_ */ +#endif /* _PosMethod_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PosPayLoad.h b/src/core/libs/supl/asn-supl/PosPayLoad.h index c72c012e7..66c03457d 100644 --- a/src/core/libs/supl/asn-supl/PosPayLoad.h +++ b/src/core/libs/supl/asn-supl/PosPayLoad.h @@ -4,8 +4,8 @@ * found in "../supl-pos.asn" */ -#ifndef _PosPayLoad_H_ -#define _PosPayLoad_H_ +#ifndef _PosPayLoad_H_ +#define _PosPayLoad_H_ #include @@ -15,42 +15,46 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum PosPayLoad_PR { - PosPayLoad_PR_NOTHING, /* No components present */ - PosPayLoad_PR_tia801payload, - PosPayLoad_PR_rrcPayload, - PosPayLoad_PR_rrlpPayload, - /* Extensions may appear below */ - -} PosPayLoad_PR; + /* Dependencies */ + typedef enum PosPayLoad_PR + { + PosPayLoad_PR_NOTHING, /* No components present */ + PosPayLoad_PR_tia801payload, + PosPayLoad_PR_rrcPayload, + PosPayLoad_PR_rrlpPayload, + /* Extensions may appear below */ -/* PosPayLoad */ -typedef struct PosPayLoad { - PosPayLoad_PR present; - union PosPayLoad_u { - OCTET_STRING_t tia801payload; - OCTET_STRING_t rrcPayload; - OCTET_STRING_t rrlpPayload; - /* + } PosPayLoad_PR; + + /* PosPayLoad */ + typedef struct PosPayLoad + { + PosPayLoad_PR present; + union PosPayLoad_u + { + OCTET_STRING_t tia801payload; + OCTET_STRING_t rrcPayload; + OCTET_STRING_t rrlpPayload; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PosPayLoad_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PosPayLoad; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PosPayLoad_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PosPayLoad; #ifdef __cplusplus } #endif -#endif /* _PosPayLoad_H_ */ +#endif /* _PosPayLoad_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PosProtocol.h b/src/core/libs/supl/asn-supl/PosProtocol.h index d22e9cf41..a53abed35 100644 --- a/src/core/libs/supl/asn-supl/PosProtocol.h +++ b/src/core/libs/supl/asn-supl/PosProtocol.h @@ -4,8 +4,8 @@ * found in "../supl-start.asn" */ -#ifndef _PosProtocol_H_ -#define _PosProtocol_H_ +#ifndef _PosProtocol_H_ +#define _PosProtocol_H_ #include @@ -15,29 +15,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PosProtocol */ -typedef struct PosProtocol { - BOOLEAN_t tia801; - BOOLEAN_t rrlp; - BOOLEAN_t rrc; - /* + /* PosProtocol */ + typedef struct PosProtocol + { + BOOLEAN_t tia801; + BOOLEAN_t rrlp; + BOOLEAN_t rrc; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PosProtocol_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PosProtocol; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PosProtocol_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PosProtocol; #ifdef __cplusplus } #endif -#endif /* _PosProtocol_H_ */ +#endif /* _PosProtocol_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PosTechnology.h b/src/core/libs/supl/asn-supl/PosTechnology.h index 70f2700f2..dcf3ea1c3 100644 --- a/src/core/libs/supl/asn-supl/PosTechnology.h +++ b/src/core/libs/supl/asn-supl/PosTechnology.h @@ -4,8 +4,8 @@ * found in "../supl-start.asn" */ -#ifndef _PosTechnology_H_ -#define _PosTechnology_H_ +#ifndef _PosTechnology_H_ +#define _PosTechnology_H_ #include @@ -15,33 +15,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PosTechnology */ -typedef struct PosTechnology { - BOOLEAN_t agpsSETassisted; - BOOLEAN_t agpsSETBased; - BOOLEAN_t autonomousGPS; - BOOLEAN_t aFLT; - BOOLEAN_t eCID; - BOOLEAN_t eOTD; - BOOLEAN_t oTDOA; - /* + /* PosTechnology */ + typedef struct PosTechnology + { + BOOLEAN_t agpsSETassisted; + BOOLEAN_t agpsSETBased; + BOOLEAN_t autonomousGPS; + BOOLEAN_t aFLT; + BOOLEAN_t eCID; + BOOLEAN_t eOTD; + BOOLEAN_t oTDOA; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PosTechnology_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PosTechnology; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PosTechnology_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PosTechnology; #ifdef __cplusplus } #endif -#endif /* _PosTechnology_H_ */ +#endif /* _PosTechnology_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Position.h b/src/core/libs/supl/asn-supl/Position.h index a56fb2eb4..20306a91f 100644 --- a/src/core/libs/supl/asn-supl/Position.h +++ b/src/core/libs/supl/asn-supl/Position.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Position_H_ -#define _Position_H_ +#ifndef _Position_H_ +#define _Position_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Velocity; + /* Forward declarations */ + struct Velocity; -/* Position */ -typedef struct Position { - UTCTime_t timestamp; - PositionEstimate_t positionEstimate; - struct Velocity *velocity /* OPTIONAL */; - /* + /* Position */ + typedef struct Position + { + UTCTime_t timestamp; + PositionEstimate_t positionEstimate; + struct Velocity *velocity /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Position_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Position; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Position_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Position; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_Position; /* Referred external types */ #include "Velocity.h" -#endif /* _Position_H_ */ +#endif /* _Position_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PositionEstimate.h b/src/core/libs/supl/asn-supl/PositionEstimate.h index d3faa7619..d4d48ae55 100644 --- a/src/core/libs/supl/asn-supl/PositionEstimate.h +++ b/src/core/libs/supl/asn-supl/PositionEstimate.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _PositionEstimate_H_ -#define _PositionEstimate_H_ +#ifndef _PositionEstimate_H_ +#define _PositionEstimate_H_ #include @@ -16,45 +16,49 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum latitudeSign { - latitudeSign_north = 0, - latitudeSign_south = 1 -} e_latitudeSign; + /* Dependencies */ + typedef enum latitudeSign + { + latitudeSign_north = 0, + latitudeSign_south = 1 + } e_latitudeSign; -/* Forward declarations */ -struct AltitudeInfo; + /* Forward declarations */ + struct AltitudeInfo; -/* PositionEstimate */ -typedef struct PositionEstimate { - ENUMERATED_t latitudeSign; - long latitude; - long longitude; - struct uncertainty { - long uncertaintySemiMajor; - long uncertaintySemiMinor; - long orientationMajorAxis; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; - } *uncertainty; - long *confidence /* OPTIONAL */; - struct AltitudeInfo *altitudeInfo /* OPTIONAL */; - /* + /* PositionEstimate */ + typedef struct PositionEstimate + { + ENUMERATED_t latitudeSign; + long latitude; + long longitude; + struct uncertainty + { + long uncertaintySemiMajor; + long uncertaintySemiMinor; + long orientationMajorAxis; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } * uncertainty; + long *confidence /* OPTIONAL */; + struct AltitudeInfo *altitudeInfo /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PositionEstimate_t; -/* Implementation */ -/* extern asn_TYPE_descriptor_t asn_DEF_latitudeSign_2; // (Use -fall-defs-global to expose) */ -extern asn_TYPE_descriptor_t asn_DEF_PositionEstimate; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PositionEstimate_t; + + /* Implementation */ + /* extern asn_TYPE_descriptor_t asn_DEF_latitudeSign_2; // (Use -fall-defs-global to expose) */ + extern asn_TYPE_descriptor_t asn_DEF_PositionEstimate; #ifdef __cplusplus } @@ -63,5 +67,5 @@ extern asn_TYPE_descriptor_t asn_DEF_PositionEstimate; /* Referred external types */ #include "AltitudeInfo.h" -#endif /* _PositionEstimate_H_ */ +#endif /* _PositionEstimate_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PrefMethod.h b/src/core/libs/supl/asn-supl/PrefMethod.h index af3786945..39c343074 100644 --- a/src/core/libs/supl/asn-supl/PrefMethod.h +++ b/src/core/libs/supl/asn-supl/PrefMethod.h @@ -4,8 +4,8 @@ * found in "../supl-start.asn" */ -#ifndef _PrefMethod_H_ -#define _PrefMethod_H_ +#ifndef _PrefMethod_H_ +#define _PrefMethod_H_ #include @@ -14,34 +14,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum PrefMethod { - PrefMethod_agpsSETassistedPreferred = 0, - PrefMethod_agpsSETBasedPreferred = 1, - PrefMethod_noPreference = 2 -} e_PrefMethod; + /* Dependencies */ + typedef enum PrefMethod + { + PrefMethod_agpsSETassistedPreferred = 0, + PrefMethod_agpsSETBasedPreferred = 1, + PrefMethod_noPreference = 2 + } e_PrefMethod; -/* PrefMethod */ -typedef ENUMERATED_t PrefMethod_t; + /* PrefMethod */ + typedef ENUMERATED_t PrefMethod_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PrefMethod; -asn_struct_free_f PrefMethod_free; -asn_struct_print_f PrefMethod_print; -asn_constr_check_f PrefMethod_constraint; -ber_type_decoder_f PrefMethod_decode_ber; -der_type_encoder_f PrefMethod_encode_der; -xer_type_decoder_f PrefMethod_decode_xer; -xer_type_encoder_f PrefMethod_encode_xer; -per_type_decoder_f PrefMethod_decode_uper; -per_type_encoder_f PrefMethod_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PrefMethod; + asn_struct_free_f PrefMethod_free; + asn_struct_print_f PrefMethod_print; + asn_constr_check_f PrefMethod_constraint; + ber_type_decoder_f PrefMethod_decode_ber; + der_type_encoder_f PrefMethod_encode_der; + xer_type_decoder_f PrefMethod_decode_xer; + xer_type_encoder_f PrefMethod_encode_xer; + per_type_decoder_f PrefMethod_decode_uper; + per_type_encoder_f PrefMethod_encode_uper; #ifdef __cplusplus } #endif -#endif /* _PrefMethod_H_ */ +#endif /* _PrefMethod_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PrimaryCCPCH-RSCP.h b/src/core/libs/supl/asn-supl/PrimaryCCPCH-RSCP.h index be672bc37..a425a2daf 100644 --- a/src/core/libs/supl/asn-supl/PrimaryCCPCH-RSCP.h +++ b/src/core/libs/supl/asn-supl/PrimaryCCPCH-RSCP.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _PrimaryCCPCH_RSCP_H_ -#define _PrimaryCCPCH_RSCP_H_ +#ifndef _PrimaryCCPCH_RSCP_H_ +#define _PrimaryCCPCH_RSCP_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PrimaryCCPCH-RSCP */ -typedef long PrimaryCCPCH_RSCP_t; + /* PrimaryCCPCH-RSCP */ + typedef long PrimaryCCPCH_RSCP_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PrimaryCCPCH_RSCP; -asn_struct_free_f PrimaryCCPCH_RSCP_free; -asn_struct_print_f PrimaryCCPCH_RSCP_print; -asn_constr_check_f PrimaryCCPCH_RSCP_constraint; -ber_type_decoder_f PrimaryCCPCH_RSCP_decode_ber; -der_type_encoder_f PrimaryCCPCH_RSCP_encode_der; -xer_type_decoder_f PrimaryCCPCH_RSCP_decode_xer; -xer_type_encoder_f PrimaryCCPCH_RSCP_encode_xer; -per_type_decoder_f PrimaryCCPCH_RSCP_decode_uper; -per_type_encoder_f PrimaryCCPCH_RSCP_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PrimaryCCPCH_RSCP; + asn_struct_free_f PrimaryCCPCH_RSCP_free; + asn_struct_print_f PrimaryCCPCH_RSCP_print; + asn_constr_check_f PrimaryCCPCH_RSCP_constraint; + ber_type_decoder_f PrimaryCCPCH_RSCP_decode_ber; + der_type_encoder_f PrimaryCCPCH_RSCP_encode_der; + xer_type_decoder_f PrimaryCCPCH_RSCP_decode_xer; + xer_type_encoder_f PrimaryCCPCH_RSCP_encode_xer; + per_type_decoder_f PrimaryCCPCH_RSCP_decode_uper; + per_type_encoder_f PrimaryCCPCH_RSCP_encode_uper; #ifdef __cplusplus } #endif -#endif /* _PrimaryCCPCH_RSCP_H_ */ +#endif /* _PrimaryCCPCH_RSCP_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/PrimaryCPICH-Info.h b/src/core/libs/supl/asn-supl/PrimaryCPICH-Info.h index 79aeef11d..aceb12991 100644 --- a/src/core/libs/supl/asn-supl/PrimaryCPICH-Info.h +++ b/src/core/libs/supl/asn-supl/PrimaryCPICH-Info.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _PrimaryCPICH_Info_H_ -#define _PrimaryCPICH_Info_H_ +#ifndef _PrimaryCPICH_Info_H_ +#define _PrimaryCPICH_Info_H_ #include @@ -15,23 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* PrimaryCPICH-Info */ -typedef struct PrimaryCPICH_Info { - long primaryScramblingCode; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} PrimaryCPICH_Info_t; + /* PrimaryCPICH-Info */ + typedef struct PrimaryCPICH_Info + { + long primaryScramblingCode; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_PrimaryCPICH_Info; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } PrimaryCPICH_Info_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_PrimaryCPICH_Info; #ifdef __cplusplus } #endif -#endif /* _PrimaryCPICH_Info_H_ */ +#endif /* _PrimaryCPICH_Info_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/QoP.h b/src/core/libs/supl/asn-supl/QoP.h index 3ebcfdcb4..2249a2a15 100644 --- a/src/core/libs/supl/asn-supl/QoP.h +++ b/src/core/libs/supl/asn-supl/QoP.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _QoP_H_ -#define _QoP_H_ +#ifndef _QoP_H_ +#define _QoP_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* QoP */ -typedef struct QoP { - long horacc; - long *veracc /* OPTIONAL */; - long *maxLocAge /* OPTIONAL */; - long *delay /* OPTIONAL */; - /* + /* QoP */ + typedef struct QoP + { + long horacc; + long *veracc /* OPTIONAL */; + long *maxLocAge /* OPTIONAL */; + long *delay /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} QoP_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_QoP; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } QoP_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_QoP; #ifdef __cplusplus } #endif -#endif /* _QoP_H_ */ +#endif /* _QoP_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/RequestedAssistData.h b/src/core/libs/supl/asn-supl/RequestedAssistData.h index 4e4dfac2f..5341cc072 100644 --- a/src/core/libs/supl/asn-supl/RequestedAssistData.h +++ b/src/core/libs/supl/asn-supl/RequestedAssistData.h @@ -4,8 +4,8 @@ * found in "../supl-posinit.asn" */ -#ifndef _RequestedAssistData_H_ -#define _RequestedAssistData_H_ +#ifndef _RequestedAssistData_H_ +#define _RequestedAssistData_H_ #include @@ -15,35 +15,37 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct XNavigationModel; + /* Forward declarations */ + struct XNavigationModel; -/* RequestedAssistData */ -typedef struct RequestedAssistData { - BOOLEAN_t almanacRequested; - BOOLEAN_t utcModelRequested; - BOOLEAN_t ionosphericModelRequested; - BOOLEAN_t dgpsCorrectionsRequested; - BOOLEAN_t referenceLocationRequested; - BOOLEAN_t referenceTimeRequested; - BOOLEAN_t acquisitionAssistanceRequested; - BOOLEAN_t realTimeIntegrityRequested; - BOOLEAN_t navigationModelRequested; - struct XNavigationModel *navigationModelData /* OPTIONAL */; - /* + /* RequestedAssistData */ + typedef struct RequestedAssistData + { + BOOLEAN_t almanacRequested; + BOOLEAN_t utcModelRequested; + BOOLEAN_t ionosphericModelRequested; + BOOLEAN_t dgpsCorrectionsRequested; + BOOLEAN_t referenceLocationRequested; + BOOLEAN_t referenceTimeRequested; + BOOLEAN_t acquisitionAssistanceRequested; + BOOLEAN_t realTimeIntegrityRequested; + BOOLEAN_t navigationModelRequested; + struct XNavigationModel *navigationModelData /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} RequestedAssistData_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_RequestedAssistData; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } RequestedAssistData_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_RequestedAssistData; #ifdef __cplusplus } @@ -52,5 +54,5 @@ extern asn_TYPE_descriptor_t asn_DEF_RequestedAssistData; /* Referred external types */ #include "XNavigationModel.h" -#endif /* _RequestedAssistData_H_ */ +#endif /* _RequestedAssistData_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SETAuthKey.c b/src/core/libs/supl/asn-supl/SETAuthKey.c index 75b01ca3b..3069866a2 100644 --- a/src/core/libs/supl/asn-supl/SETAuthKey.c +++ b/src/core/libs/supl/asn-supl/SETAuthKey.c @@ -8,135 +8,148 @@ static int memb_shortKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 128)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 128) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_longKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 256)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 256) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_shortKey_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 128, 128 } /* (SIZE(128..128)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 128, 128} /* (SIZE(128..128)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_longKey_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 256, 256 } /* (SIZE(256..256)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 256, 256} /* (SIZE(256..256)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_type_SETAuthKey_constr_1 = { - { APC_CONSTRAINED | APC_EXTENSIBLE, 1, 1, 0, 1 } /* (0..1,...) */, - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - 0, 0 /* No PER value map */ + {APC_CONSTRAINED | APC_EXTENSIBLE, 1, 1, 0, 1} /* (0..1,...) */, + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_SETAuthKey_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct SETAuthKey, choice.shortKey), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_shortKey_constraint_1, - &asn_PER_memb_shortKey_constr_2, - 0, - "shortKey" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETAuthKey, choice.longKey), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_longKey_constraint_1, - &asn_PER_memb_longKey_constr_3, - 0, - "longKey" - }, + {ATF_NOFLAGS, 0, offsetof(struct SETAuthKey, choice.shortKey), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_shortKey_constraint_1, + &asn_PER_memb_shortKey_constr_2, + 0, + "shortKey"}, + {ATF_NOFLAGS, 0, offsetof(struct SETAuthKey, choice.longKey), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_longKey_constraint_1, + &asn_PER_memb_longKey_constr_3, + 0, + "longKey"}, }; static asn_TYPE_tag2member_t asn_MAP_SETAuthKey_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* shortKey at 17 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* longKey at 18 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* shortKey at 17 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0} /* longKey at 18 */ }; static asn_CHOICE_specifics_t asn_SPC_SETAuthKey_specs_1 = { - sizeof(struct SETAuthKey), - offsetof(struct SETAuthKey, _asn_ctx), - offsetof(struct SETAuthKey, present), - sizeof(((struct SETAuthKey *)0)->present), - asn_MAP_SETAuthKey_tag2el_1, - 2, /* Count of tags in the map */ - 0, - 2 /* Extensions start */ + sizeof(struct SETAuthKey), + offsetof(struct SETAuthKey, _asn_ctx), + offsetof(struct SETAuthKey, present), + sizeof(((struct SETAuthKey *)0)->present), + asn_MAP_SETAuthKey_tag2el_1, + 2, /* Count of tags in the map */ + 0, + 2 /* Extensions start */ }; asn_TYPE_descriptor_t asn_DEF_SETAuthKey = { - "SETAuthKey", - "SETAuthKey", - CHOICE_free, - CHOICE_print, - CHOICE_constraint, - CHOICE_decode_ber, - CHOICE_encode_der, - CHOICE_decode_xer, - CHOICE_encode_xer, - CHOICE_decode_uper, - CHOICE_encode_uper, - CHOICE_outmost_tag, - 0, /* No effective tags (pointer) */ - 0, /* No effective tags (count) */ - 0, /* No tags (pointer) */ - 0, /* No tags (count) */ - &asn_PER_type_SETAuthKey_constr_1, - asn_MBR_SETAuthKey_1, - 2, /* Elements count */ - &asn_SPC_SETAuthKey_specs_1 /* Additional specs */ + "SETAuthKey", + "SETAuthKey", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + CHOICE_decode_uper, + CHOICE_encode_uper, + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + &asn_PER_type_SETAuthKey_constr_1, + asn_MBR_SETAuthKey_1, + 2, /* Elements count */ + &asn_SPC_SETAuthKey_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/SETAuthKey.h b/src/core/libs/supl/asn-supl/SETAuthKey.h index 29f123269..7a9fbe6fe 100644 --- a/src/core/libs/supl/asn-supl/SETAuthKey.h +++ b/src/core/libs/supl/asn-supl/SETAuthKey.h @@ -4,8 +4,8 @@ * found in "../supl-response.asn" */ -#ifndef _SETAuthKey_H_ -#define _SETAuthKey_H_ +#ifndef _SETAuthKey_H_ +#define _SETAuthKey_H_ #include @@ -15,40 +15,44 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SETAuthKey_PR { - SETAuthKey_PR_NOTHING, /* No components present */ - SETAuthKey_PR_shortKey, - SETAuthKey_PR_longKey, - /* Extensions may appear below */ - -} SETAuthKey_PR; + /* Dependencies */ + typedef enum SETAuthKey_PR + { + SETAuthKey_PR_NOTHING, /* No components present */ + SETAuthKey_PR_shortKey, + SETAuthKey_PR_longKey, + /* Extensions may appear below */ -/* SETAuthKey */ -typedef struct SETAuthKey { - SETAuthKey_PR present; - union SETAuthKey_u { - BIT_STRING_t shortKey; - BIT_STRING_t longKey; - /* + } SETAuthKey_PR; + + /* SETAuthKey */ + typedef struct SETAuthKey + { + SETAuthKey_PR present; + union SETAuthKey_u + { + BIT_STRING_t shortKey; + BIT_STRING_t longKey; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SETAuthKey_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SETAuthKey; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SETAuthKey_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SETAuthKey; #ifdef __cplusplus } #endif -#endif /* _SETAuthKey_H_ */ +#endif /* _SETAuthKey_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SETCapabilities.h b/src/core/libs/supl/asn-supl/SETCapabilities.h index 84f0e8a00..f3429dab4 100644 --- a/src/core/libs/supl/asn-supl/SETCapabilities.h +++ b/src/core/libs/supl/asn-supl/SETCapabilities.h @@ -4,8 +4,8 @@ * found in "../supl-start.asn" */ -#ifndef _SETCapabilities_H_ -#define _SETCapabilities_H_ +#ifndef _SETCapabilities_H_ +#define _SETCapabilities_H_ #include @@ -17,29 +17,31 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SETCapabilities */ -typedef struct SETCapabilities { - PosTechnology_t posTechnology; - PrefMethod_t prefMethod; - PosProtocol_t posProtocol; - /* + /* SETCapabilities */ + typedef struct SETCapabilities + { + PosTechnology_t posTechnology; + PrefMethod_t prefMethod; + PosProtocol_t posProtocol; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SETCapabilities_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SETCapabilities; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SETCapabilities_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SETCapabilities; #ifdef __cplusplus } #endif -#endif /* _SETCapabilities_H_ */ +#endif /* _SETCapabilities_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SETId.c b/src/core/libs/supl/asn-supl/SETId.c index 6da7efdf5..93a635e23 100644 --- a/src/core/libs/supl/asn-supl/SETId.c +++ b/src/core/libs/supl/asn-supl/SETId.c @@ -6,279 +6,301 @@ #include "SETId.h" -static int check_permitted_alphabet_6(const void *sptr) { - /* The underlying type is IA5String */ - const IA5String_t *st = (const IA5String_t *)sptr; - const uint8_t *ch = st->buf; - const uint8_t *end = ch + st->size; - - for(; ch < end; ch++) { - uint8_t cv = *ch; - if(!(cv <= 127)) return -1; - } - return 0; +static int check_permitted_alphabet_6(const void *sptr) +{ + /* The underlying type is IA5String */ + const IA5String_t *st = (const IA5String_t *)sptr; + const uint8_t *ch = st->buf; + const uint8_t *end = ch + st->size; + + for (; ch < end; ch++) + { + uint8_t cv = *ch; + if (!(cv <= 127)) return -1; + } + return 0; } static int memb_msisdn_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_mdn_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_min_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 34)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 34) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_imsi_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 8)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 8) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static int memb_nai_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const IA5String_t *st = (const IA5String_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size >= 1 && size <= 1000) - && !check_permitted_alphabet_6(st)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const IA5String_t *st = (const IA5String_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if ((size >= 1 && size <= 1000) && !check_permitted_alphabet_6(st)) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_msisdn_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_mdn_constr_3 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_min_constr_4 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 34, 34 } /* (SIZE(34..34)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 34, 34} /* (SIZE(34..34)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_imsi_constr_5 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 8, 8 } /* (SIZE(8..8)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 8, 8} /* (SIZE(8..8)) */, + 0, 0 /* No PER value map */ }; static asn_per_constraints_t asn_PER_memb_nai_constr_6 = { - { APC_CONSTRAINED, 7, 7, 0, 127 } /* (0..127) */, - { APC_CONSTRAINED, 10, 10, 1, 1000 } /* (SIZE(1..1000)) */, - 0, 0 /* No PER character map necessary */ + {APC_CONSTRAINED, 7, 7, 0, 127} /* (0..127) */, + {APC_CONSTRAINED, 10, 10, 1, 1000} /* (SIZE(1..1000)) */, + 0, 0 /* No PER character map necessary */ }; static asn_per_constraints_t asn_PER_type_SETId_constr_1 = { - { APC_CONSTRAINED | APC_EXTENSIBLE, 3, 3, 0, 5 } /* (0..5,...) */, - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - 0, 0 /* No PER value map */ + {APC_CONSTRAINED | APC_EXTENSIBLE, 3, 3, 0, 5} /* (0..5,...) */, + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_SETId_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.msisdn), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_msisdn_constraint_1, - &asn_PER_memb_msisdn_constr_2, - 0, - "msisdn" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.mdn), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_mdn_constraint_1, - &asn_PER_memb_mdn_constr_3, - 0, - "mdn" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.min), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_BIT_STRING, - memb_min_constraint_1, - &asn_PER_memb_min_constr_4, - 0, - "min" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.imsi), - (ASN_TAG_CLASS_CONTEXT | (3 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_imsi_constraint_1, - &asn_PER_memb_imsi_constr_5, - 0, - "imsi" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.nai), - (ASN_TAG_CLASS_CONTEXT | (4 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_IA5String, - memb_nai_constraint_1, - &asn_PER_memb_nai_constr_6, - 0, - "nai" - }, - { ATF_NOFLAGS, 0, offsetof(struct SETId, choice.iPAddress), - (ASN_TAG_CLASS_CONTEXT | (5 << 2)), - +1, /* EXPLICIT tag at current level */ - &asn_DEF_IPAddress, - 0, /* Defer constraints checking to the member type */ - 0, /* No PER visible constraints */ - 0, - "iPAddress" - }, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.msisdn), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_msisdn_constraint_1, + &asn_PER_memb_msisdn_constr_2, + 0, + "msisdn"}, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.mdn), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_mdn_constraint_1, + &asn_PER_memb_mdn_constr_3, + 0, + "mdn"}, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.min), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + memb_min_constraint_1, + &asn_PER_memb_min_constr_4, + 0, + "min"}, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.imsi), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_imsi_constraint_1, + &asn_PER_memb_imsi_constr_5, + 0, + "imsi"}, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.nai), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_IA5String, + memb_nai_constraint_1, + &asn_PER_memb_nai_constr_6, + 0, + "nai"}, + {ATF_NOFLAGS, 0, offsetof(struct SETId, choice.iPAddress), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_IPAddress, + 0, /* Defer constraints checking to the member type */ + 0, /* No PER visible constraints */ + 0, + "iPAddress"}, }; static asn_TYPE_tag2member_t asn_MAP_SETId_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* msisdn at 22 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* mdn at 23 */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* min at 24 */ - { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* imsi at 25 */ - { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* nai at 26 */ - { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 } /* iPAddress at 27 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* msisdn at 22 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0}, /* mdn at 23 */ + {(ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0}, /* min at 24 */ + {(ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0}, /* imsi at 25 */ + {(ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0}, /* nai at 26 */ + {(ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0} /* iPAddress at 27 */ }; static asn_CHOICE_specifics_t asn_SPC_SETId_specs_1 = { - sizeof(struct SETId), - offsetof(struct SETId, _asn_ctx), - offsetof(struct SETId, present), - sizeof(((struct SETId *)0)->present), - asn_MAP_SETId_tag2el_1, - 6, /* Count of tags in the map */ - 0, - 6 /* Extensions start */ + sizeof(struct SETId), + offsetof(struct SETId, _asn_ctx), + offsetof(struct SETId, present), + sizeof(((struct SETId *)0)->present), + asn_MAP_SETId_tag2el_1, + 6, /* Count of tags in the map */ + 0, + 6 /* Extensions start */ }; asn_TYPE_descriptor_t asn_DEF_SETId = { - "SETId", - "SETId", - CHOICE_free, - CHOICE_print, - CHOICE_constraint, - CHOICE_decode_ber, - CHOICE_encode_der, - CHOICE_decode_xer, - CHOICE_encode_xer, - CHOICE_decode_uper, - CHOICE_encode_uper, - CHOICE_outmost_tag, - 0, /* No effective tags (pointer) */ - 0, /* No effective tags (count) */ - 0, /* No tags (pointer) */ - 0, /* No tags (count) */ - &asn_PER_type_SETId_constr_1, - asn_MBR_SETId_1, - 6, /* Elements count */ - &asn_SPC_SETId_specs_1 /* Additional specs */ + "SETId", + "SETId", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + CHOICE_decode_uper, + CHOICE_encode_uper, + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + &asn_PER_type_SETId_constr_1, + asn_MBR_SETId_1, + 6, /* Elements count */ + &asn_SPC_SETId_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/SETId.h b/src/core/libs/supl/asn-supl/SETId.h index 096777f75..ece63df60 100644 --- a/src/core/libs/supl/asn-supl/SETId.h +++ b/src/core/libs/supl/asn-supl/SETId.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _SETId_H_ -#define _SETId_H_ +#ifndef _SETId_H_ +#define _SETId_H_ #include @@ -18,48 +18,52 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SETId_PR { - SETId_PR_NOTHING, /* No components present */ - SETId_PR_msisdn, - SETId_PR_mdn, - SETId_PR_min, - SETId_PR_imsi, - SETId_PR_nai, - SETId_PR_iPAddress, - /* Extensions may appear below */ - -} SETId_PR; + /* Dependencies */ + typedef enum SETId_PR + { + SETId_PR_NOTHING, /* No components present */ + SETId_PR_msisdn, + SETId_PR_mdn, + SETId_PR_min, + SETId_PR_imsi, + SETId_PR_nai, + SETId_PR_iPAddress, + /* Extensions may appear below */ -/* SETId */ -typedef struct SETId { - SETId_PR present; - union SETId_u { - OCTET_STRING_t msisdn; - OCTET_STRING_t mdn; - BIT_STRING_t min; - OCTET_STRING_t imsi; - IA5String_t nai; - IPAddress_t iPAddress; - /* + } SETId_PR; + + /* SETId */ + typedef struct SETId + { + SETId_PR present; + union SETId_u + { + OCTET_STRING_t msisdn; + OCTET_STRING_t mdn; + BIT_STRING_t min; + OCTET_STRING_t imsi; + IA5String_t nai; + IPAddress_t iPAddress; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SETId_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SETId; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SETId_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SETId; #ifdef __cplusplus } #endif -#endif /* _SETId_H_ */ +#endif /* _SETId_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SLPAddress.h b/src/core/libs/supl/asn-supl/SLPAddress.h index fba1f13d9..4b13147ef 100644 --- a/src/core/libs/supl/asn-supl/SLPAddress.h +++ b/src/core/libs/supl/asn-supl/SLPAddress.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _SLPAddress_H_ -#define _SLPAddress_H_ +#ifndef _SLPAddress_H_ +#define _SLPAddress_H_ #include @@ -16,40 +16,44 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SLPAddress_PR { - SLPAddress_PR_NOTHING, /* No components present */ - SLPAddress_PR_iPAddress, - SLPAddress_PR_fQDN, - /* Extensions may appear below */ - -} SLPAddress_PR; + /* Dependencies */ + typedef enum SLPAddress_PR + { + SLPAddress_PR_NOTHING, /* No components present */ + SLPAddress_PR_iPAddress, + SLPAddress_PR_fQDN, + /* Extensions may appear below */ -/* SLPAddress */ -typedef struct SLPAddress { - SLPAddress_PR present; - union SLPAddress_u { - IPAddress_t iPAddress; - FQDN_t fQDN; - /* + } SLPAddress_PR; + + /* SLPAddress */ + typedef struct SLPAddress + { + SLPAddress_PR present; + union SLPAddress_u + { + IPAddress_t iPAddress; + FQDN_t fQDN; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SLPAddress_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SLPAddress; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SLPAddress_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SLPAddress; #ifdef __cplusplus } #endif -#endif /* _SLPAddress_H_ */ +#endif /* _SLPAddress_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SLPMode.h b/src/core/libs/supl/asn-supl/SLPMode.h index 3aec2cac0..54f6ffe27 100644 --- a/src/core/libs/supl/asn-supl/SLPMode.h +++ b/src/core/libs/supl/asn-supl/SLPMode.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _SLPMode_H_ -#define _SLPMode_H_ +#ifndef _SLPMode_H_ +#define _SLPMode_H_ #include @@ -14,33 +14,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum SLPMode { - SLPMode_proxy = 0, - SLPMode_nonProxy = 1 -} e_SLPMode; + /* Dependencies */ + typedef enum SLPMode + { + SLPMode_proxy = 0, + SLPMode_nonProxy = 1 + } e_SLPMode; -/* SLPMode */ -typedef ENUMERATED_t SLPMode_t; + /* SLPMode */ + typedef ENUMERATED_t SLPMode_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SLPMode; -asn_struct_free_f SLPMode_free; -asn_struct_print_f SLPMode_print; -asn_constr_check_f SLPMode_constraint; -ber_type_decoder_f SLPMode_decode_ber; -der_type_encoder_f SLPMode_encode_der; -xer_type_decoder_f SLPMode_decode_xer; -xer_type_encoder_f SLPMode_encode_xer; -per_type_decoder_f SLPMode_decode_uper; -per_type_encoder_f SLPMode_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SLPMode; + asn_struct_free_f SLPMode_free; + asn_struct_print_f SLPMode_print; + asn_constr_check_f SLPMode_constraint; + ber_type_decoder_f SLPMode_decode_ber; + der_type_encoder_f SLPMode_encode_der; + xer_type_decoder_f SLPMode_decode_xer; + xer_type_encoder_f SLPMode_encode_xer; + per_type_decoder_f SLPMode_decode_uper; + per_type_encoder_f SLPMode_encode_uper; #ifdef __cplusplus } #endif -#endif /* _SLPMode_H_ */ +#endif /* _SLPMode_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLEND.h b/src/core/libs/supl/asn-supl/SUPLEND.h index 2c75dbc21..0370782b0 100644 --- a/src/core/libs/supl/asn-supl/SUPLEND.h +++ b/src/core/libs/supl/asn-supl/SUPLEND.h @@ -4,8 +4,8 @@ * found in "../supl-end.asn" */ -#ifndef _SUPLEND_H_ -#define _SUPLEND_H_ +#ifndef _SUPLEND_H_ +#define _SUPLEND_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Position; + /* Forward declarations */ + struct Position; -/* SUPLEND */ -typedef struct SUPLEND { - struct Position *position /* OPTIONAL */; - StatusCode_t *statusCode /* OPTIONAL */; - Ver_t *ver /* OPTIONAL */; - /* + /* SUPLEND */ + typedef struct SUPLEND + { + struct Position *position /* OPTIONAL */; + StatusCode_t *statusCode /* OPTIONAL */; + Ver_t *ver /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLEND_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLEND; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLEND_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLEND; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLEND; /* Referred external types */ #include "Position.h" -#endif /* _SUPLEND_H_ */ +#endif /* _SUPLEND_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLINIT.h b/src/core/libs/supl/asn-supl/SUPLINIT.h index af290986f..40e4ebfed 100644 --- a/src/core/libs/supl/asn-supl/SUPLINIT.h +++ b/src/core/libs/supl/asn-supl/SUPLINIT.h @@ -4,8 +4,8 @@ * found in "../supl-init.asn" */ -#ifndef _SUPLINIT_H_ -#define _SUPLINIT_H_ +#ifndef _SUPLINIT_H_ +#define _SUPLINIT_H_ #include @@ -18,34 +18,36 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Notification; -struct SLPAddress; -struct QoP; + /* Forward declarations */ + struct Notification; + struct SLPAddress; + struct QoP; -/* SUPLINIT */ -typedef struct SUPLINIT { - PosMethod_t posMethod; - struct Notification *notification /* OPTIONAL */; - struct SLPAddress *sLPAddress /* OPTIONAL */; - struct QoP *qoP /* OPTIONAL */; - SLPMode_t sLPMode; - MAC_t *mAC /* OPTIONAL */; - KeyIdentity_t *keyIdentity /* OPTIONAL */; - /* + /* SUPLINIT */ + typedef struct SUPLINIT + { + PosMethod_t posMethod; + struct Notification *notification /* OPTIONAL */; + struct SLPAddress *sLPAddress /* OPTIONAL */; + struct QoP *qoP /* OPTIONAL */; + SLPMode_t sLPMode; + MAC_t *mAC /* OPTIONAL */; + KeyIdentity_t *keyIdentity /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLINIT_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLINIT; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLINIT_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLINIT; #ifdef __cplusplus } @@ -56,5 +58,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLINIT; #include "SLPAddress.h" #include "QoP.h" -#endif /* _SUPLINIT_H_ */ +#endif /* _SUPLINIT_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLPOS.h b/src/core/libs/supl/asn-supl/SUPLPOS.h index 7285b26cf..9b9753f2f 100644 --- a/src/core/libs/supl/asn-supl/SUPLPOS.h +++ b/src/core/libs/supl/asn-supl/SUPLPOS.h @@ -4,8 +4,8 @@ * found in "../supl-pos.asn" */ -#ifndef _SUPLPOS_H_ -#define _SUPLPOS_H_ +#ifndef _SUPLPOS_H_ +#define _SUPLPOS_H_ #include @@ -15,27 +15,29 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct Velocity; + /* Forward declarations */ + struct Velocity; -/* SUPLPOS */ -typedef struct SUPLPOS { - PosPayLoad_t posPayLoad; - struct Velocity *velocity /* OPTIONAL */; - /* + /* SUPLPOS */ + typedef struct SUPLPOS + { + PosPayLoad_t posPayLoad; + struct Velocity *velocity /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLPOS_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLPOS; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLPOS_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLPOS; #ifdef __cplusplus } @@ -44,5 +46,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLPOS; /* Referred external types */ #include "Velocity.h" -#endif /* _SUPLPOS_H_ */ +#endif /* _SUPLPOS_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLPOSINIT.h b/src/core/libs/supl/asn-supl/SUPLPOSINIT.h index 740f7b5b4..741a88564 100644 --- a/src/core/libs/supl/asn-supl/SUPLPOSINIT.h +++ b/src/core/libs/supl/asn-supl/SUPLPOSINIT.h @@ -4,8 +4,8 @@ * found in "../supl-posinit.asn" */ -#ifndef _SUPLPOSINIT_H_ -#define _SUPLPOSINIT_H_ +#ifndef _SUPLPOSINIT_H_ +#define _SUPLPOSINIT_H_ #include @@ -17,33 +17,35 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct RequestedAssistData; -struct Position; -struct SUPLPOS; + /* Forward declarations */ + struct RequestedAssistData; + struct Position; + struct SUPLPOS; -/* SUPLPOSINIT */ -typedef struct SUPLPOSINIT { - SETCapabilities_t sETCapabilities; - struct RequestedAssistData *requestedAssistData /* OPTIONAL */; - LocationId_t locationId; - struct Position *position /* OPTIONAL */; - struct SUPLPOS *sUPLPOS /* OPTIONAL */; - Ver_t *ver /* OPTIONAL */; - /* + /* SUPLPOSINIT */ + typedef struct SUPLPOSINIT + { + SETCapabilities_t sETCapabilities; + struct RequestedAssistData *requestedAssistData /* OPTIONAL */; + LocationId_t locationId; + struct Position *position /* OPTIONAL */; + struct SUPLPOS *sUPLPOS /* OPTIONAL */; + Ver_t *ver /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLPOSINIT_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLPOSINIT; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLPOSINIT_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLPOSINIT; #ifdef __cplusplus } @@ -54,5 +56,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLPOSINIT; #include "Position.h" #include "SUPLPOS.h" -#endif /* _SUPLPOSINIT_H_ */ +#endif /* _SUPLPOSINIT_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLRESPONSE.h b/src/core/libs/supl/asn-supl/SUPLRESPONSE.h index 698cd32b4..c2eea8bd7 100644 --- a/src/core/libs/supl/asn-supl/SUPLRESPONSE.h +++ b/src/core/libs/supl/asn-supl/SUPLRESPONSE.h @@ -4,8 +4,8 @@ * found in "../supl-response.asn" */ -#ifndef _SUPLRESPONSE_H_ -#define _SUPLRESPONSE_H_ +#ifndef _SUPLRESPONSE_H_ +#define _SUPLRESPONSE_H_ #include @@ -16,30 +16,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SLPAddress; -struct SETAuthKey; + /* Forward declarations */ + struct SLPAddress; + struct SETAuthKey; -/* SUPLRESPONSE */ -typedef struct SUPLRESPONSE { - PosMethod_t posMethod; - struct SLPAddress *sLPAddress /* OPTIONAL */; - struct SETAuthKey *sETAuthKey /* OPTIONAL */; - KeyIdentity4_t *keyIdentity4 /* OPTIONAL */; - /* + /* SUPLRESPONSE */ + typedef struct SUPLRESPONSE + { + PosMethod_t posMethod; + struct SLPAddress *sLPAddress /* OPTIONAL */; + struct SETAuthKey *sETAuthKey /* OPTIONAL */; + KeyIdentity4_t *keyIdentity4 /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLRESPONSE_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLRESPONSE; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLRESPONSE_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLRESPONSE; #ifdef __cplusplus } @@ -49,5 +51,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLRESPONSE; #include "SLPAddress.h" #include "SETAuthKey.h" -#endif /* _SUPLRESPONSE_H_ */ +#endif /* _SUPLRESPONSE_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SUPLSTART.h b/src/core/libs/supl/asn-supl/SUPLSTART.h index b1061bf3c..fc6fd4b9e 100644 --- a/src/core/libs/supl/asn-supl/SUPLSTART.h +++ b/src/core/libs/supl/asn-supl/SUPLSTART.h @@ -4,8 +4,8 @@ * found in "../supl-start.asn" */ -#ifndef _SUPLSTART_H_ -#define _SUPLSTART_H_ +#ifndef _SUPLSTART_H_ +#define _SUPLSTART_H_ #include @@ -16,28 +16,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct QoP; + /* Forward declarations */ + struct QoP; -/* SUPLSTART */ -typedef struct SUPLSTART { - SETCapabilities_t sETCapabilities; - LocationId_t locationId; - struct QoP *qoP /* OPTIONAL */; - /* + /* SUPLSTART */ + typedef struct SUPLSTART + { + SETCapabilities_t sETCapabilities; + LocationId_t locationId; + struct QoP *qoP /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SUPLSTART_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SUPLSTART; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SUPLSTART_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SUPLSTART; #ifdef __cplusplus } @@ -46,5 +48,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SUPLSTART; /* Referred external types */ #include "QoP.h" -#endif /* _SUPLSTART_H_ */ +#endif /* _SUPLSTART_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SatelliteInfo.h b/src/core/libs/supl/asn-supl/SatelliteInfo.h index ff36af47a..4dea62f31 100644 --- a/src/core/libs/supl/asn-supl/SatelliteInfo.h +++ b/src/core/libs/supl/asn-supl/SatelliteInfo.h @@ -4,8 +4,8 @@ * found in "../supl-posinit.asn" */ -#ifndef _SatelliteInfo_H_ -#define _SatelliteInfo_H_ +#ifndef _SatelliteInfo_H_ +#define _SatelliteInfo_H_ #include @@ -15,22 +15,25 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SatelliteInfoElement; + /* Forward declarations */ + struct SatelliteInfoElement; -/* SatelliteInfo */ -typedef struct SatelliteInfo { - A_SEQUENCE_OF(struct SatelliteInfoElement) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SatelliteInfo_t; + /* SatelliteInfo */ + typedef struct SatelliteInfo + { + A_SEQUENCE_OF(struct SatelliteInfoElement) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SatelliteInfo; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SatelliteInfo_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SatelliteInfo; #ifdef __cplusplus } @@ -39,5 +42,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SatelliteInfo; /* Referred external types */ #include "SatelliteInfoElement.h" -#endif /* _SatelliteInfo_H_ */ +#endif /* _SatelliteInfo_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SatelliteInfoElement.h b/src/core/libs/supl/asn-supl/SatelliteInfoElement.h index 6b2cc69ee..a97dcf643 100644 --- a/src/core/libs/supl/asn-supl/SatelliteInfoElement.h +++ b/src/core/libs/supl/asn-supl/SatelliteInfoElement.h @@ -4,8 +4,8 @@ * found in "../supl-posinit.asn" */ -#ifndef _SatelliteInfoElement_H_ -#define _SatelliteInfoElement_H_ +#ifndef _SatelliteInfoElement_H_ +#define _SatelliteInfoElement_H_ #include @@ -15,28 +15,30 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SatelliteInfoElement */ -typedef struct SatelliteInfoElement { - long satId; - long iODE; - /* + /* SatelliteInfoElement */ + typedef struct SatelliteInfoElement + { + long satId; + long iODE; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SatelliteInfoElement_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SatelliteInfoElement; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SatelliteInfoElement_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SatelliteInfoElement; #ifdef __cplusplus } #endif -#endif /* _SatelliteInfoElement_H_ */ +#endif /* _SatelliteInfoElement_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SessionID.h b/src/core/libs/supl/asn-supl/SessionID.h index c56f8ac07..104229df5 100644 --- a/src/core/libs/supl/asn-supl/SessionID.h +++ b/src/core/libs/supl/asn-supl/SessionID.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _SessionID_H_ -#define _SessionID_H_ +#ifndef _SessionID_H_ +#define _SessionID_H_ #include @@ -14,24 +14,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SetSessionID; -struct SlpSessionID; + /* Forward declarations */ + struct SetSessionID; + struct SlpSessionID; -/* SessionID */ -typedef struct SessionID { - struct SetSessionID *setSessionID /* OPTIONAL */; - struct SlpSessionID *slpSessionID /* OPTIONAL */; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SessionID_t; + /* SessionID */ + typedef struct SessionID + { + struct SetSessionID *setSessionID /* OPTIONAL */; + struct SlpSessionID *slpSessionID /* OPTIONAL */; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SessionID; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SessionID_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SessionID; #ifdef __cplusplus } @@ -41,5 +43,5 @@ extern asn_TYPE_descriptor_t asn_DEF_SessionID; #include "SetSessionID.h" #include "SlpSessionID.h" -#endif /* _SessionID_H_ */ +#endif /* _SessionID_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SetSessionID.h b/src/core/libs/supl/asn-supl/SetSessionID.h index 6e9cc352f..5ae549773 100644 --- a/src/core/libs/supl/asn-supl/SetSessionID.h +++ b/src/core/libs/supl/asn-supl/SetSessionID.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _SetSessionID_H_ -#define _SetSessionID_H_ +#ifndef _SetSessionID_H_ +#define _SetSessionID_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SetSessionID */ -typedef struct SetSessionID { - long sessionId; - SETId_t setId; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SetSessionID_t; + /* SetSessionID */ + typedef struct SetSessionID + { + long sessionId; + SETId_t setId; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SetSessionID; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SetSessionID_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SetSessionID; #ifdef __cplusplus } #endif -#endif /* _SetSessionID_H_ */ +#endif /* _SetSessionID_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/SlpSessionID.c b/src/core/libs/supl/asn-supl/SlpSessionID.c index 173724cd6..0e52d2d34 100644 --- a/src/core/libs/supl/asn-supl/SlpSessionID.c +++ b/src/core/libs/supl/asn-supl/SlpSessionID.c @@ -8,93 +8,92 @@ static int memb_sessionID_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 4)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 4) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } static asn_per_constraints_t asn_PER_memb_sessionID_constr_2 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 4, 4 } /* (SIZE(4..4)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 4, 4} /* (SIZE(4..4)) */, + 0, 0 /* No PER value map */ }; static asn_TYPE_member_t asn_MBR_SlpSessionID_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct SlpSessionID, sessionID), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_sessionID_constraint_1, - &asn_PER_memb_sessionID_constr_2, - 0, - "sessionID" - }, - { ATF_NOFLAGS, 0, offsetof(struct SlpSessionID, slpId), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - +1, /* EXPLICIT tag at current level */ - &asn_DEF_SLPAddress, - 0, /* Defer constraints checking to the member type */ - 0, /* No PER visible constraints */ - 0, - "slpId" - }, + {ATF_NOFLAGS, 0, offsetof(struct SlpSessionID, sessionID), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_sessionID_constraint_1, + &asn_PER_memb_sessionID_constr_2, + 0, + "sessionID"}, + {ATF_NOFLAGS, 0, offsetof(struct SlpSessionID, slpId), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_SLPAddress, + 0, /* Defer constraints checking to the member type */ + 0, /* No PER visible constraints */ + 0, + "slpId"}, }; static ber_tlv_tag_t asn_DEF_SlpSessionID_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))}; static asn_TYPE_tag2member_t asn_MAP_SlpSessionID_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* sessionID at 37 */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* slpId at 38 */ + {(ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0}, /* sessionID at 37 */ + {(ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0} /* slpId at 38 */ }; static asn_SEQUENCE_specifics_t asn_SPC_SlpSessionID_specs_1 = { - sizeof(struct SlpSessionID), - offsetof(struct SlpSessionID, _asn_ctx), - asn_MAP_SlpSessionID_tag2el_1, - 2, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - -1, /* Start extensions */ - -1 /* Stop extensions */ + sizeof(struct SlpSessionID), + offsetof(struct SlpSessionID, _asn_ctx), + asn_MAP_SlpSessionID_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_SlpSessionID = { - "SlpSessionID", - "SlpSessionID", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - SEQUENCE_decode_uper, - SEQUENCE_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_SlpSessionID_tags_1, - sizeof(asn_DEF_SlpSessionID_tags_1) - /sizeof(asn_DEF_SlpSessionID_tags_1[0]), /* 1 */ - asn_DEF_SlpSessionID_tags_1, /* Same as above */ - sizeof(asn_DEF_SlpSessionID_tags_1) - /sizeof(asn_DEF_SlpSessionID_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_SlpSessionID_1, - 2, /* Elements count */ - &asn_SPC_SlpSessionID_specs_1 /* Additional specs */ + "SlpSessionID", + "SlpSessionID", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_SlpSessionID_tags_1, + sizeof(asn_DEF_SlpSessionID_tags_1) / sizeof(asn_DEF_SlpSessionID_tags_1[0]), /* 1 */ + asn_DEF_SlpSessionID_tags_1, /* Same as above */ + sizeof(asn_DEF_SlpSessionID_tags_1) / sizeof(asn_DEF_SlpSessionID_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_SlpSessionID_1, + 2, /* Elements count */ + &asn_SPC_SlpSessionID_specs_1 /* Additional specs */ }; - diff --git a/src/core/libs/supl/asn-supl/SlpSessionID.h b/src/core/libs/supl/asn-supl/SlpSessionID.h index 2e1df8300..e381f2fbe 100644 --- a/src/core/libs/supl/asn-supl/SlpSessionID.h +++ b/src/core/libs/supl/asn-supl/SlpSessionID.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _SlpSessionID_H_ -#define _SlpSessionID_H_ +#ifndef _SlpSessionID_H_ +#define _SlpSessionID_H_ #include @@ -16,24 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* SlpSessionID */ -typedef struct SlpSessionID { - OCTET_STRING_t sessionID; - SLPAddress_t slpId; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} SlpSessionID_t; + /* SlpSessionID */ + typedef struct SlpSessionID + { + OCTET_STRING_t sessionID; + SLPAddress_t slpId; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_SlpSessionID; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } SlpSessionID_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_SlpSessionID; #ifdef __cplusplus } #endif -#endif /* _SlpSessionID_H_ */ +#endif /* _SlpSessionID_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Status.h b/src/core/libs/supl/asn-supl/Status.h index 7107531ab..1405d998d 100644 --- a/src/core/libs/supl/asn-supl/Status.h +++ b/src/core/libs/supl/asn-supl/Status.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Status_H_ -#define _Status_H_ +#ifndef _Status_H_ +#define _Status_H_ #include @@ -14,37 +14,39 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum Status { - Status_stale = 0, - Status_current = 1, - Status_unknown = 2 - /* + /* Dependencies */ + typedef enum Status + { + Status_stale = 0, + Status_current = 1, + Status_unknown = 2 + /* * Enumeration is extensible */ -} e_Status; + } e_Status; -/* Status */ -typedef ENUMERATED_t Status_t; + /* Status */ + typedef ENUMERATED_t Status_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Status; -asn_struct_free_f Status_free; -asn_struct_print_f Status_print; -asn_constr_check_f Status_constraint; -ber_type_decoder_f Status_decode_ber; -der_type_encoder_f Status_encode_der; -xer_type_decoder_f Status_decode_xer; -xer_type_encoder_f Status_encode_xer; -per_type_decoder_f Status_decode_uper; -per_type_encoder_f Status_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Status; + asn_struct_free_f Status_free; + asn_struct_print_f Status_print; + asn_constr_check_f Status_constraint; + ber_type_decoder_f Status_decode_ber; + der_type_encoder_f Status_encode_der; + xer_type_decoder_f Status_decode_xer; + xer_type_encoder_f Status_encode_xer; + per_type_decoder_f Status_decode_uper; + per_type_encoder_f Status_encode_uper; #ifdef __cplusplus } #endif -#endif /* _Status_H_ */ +#endif /* _Status_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/StatusCode.h b/src/core/libs/supl/asn-supl/StatusCode.h index 35b52a379..b48c43e08 100644 --- a/src/core/libs/supl/asn-supl/StatusCode.h +++ b/src/core/libs/supl/asn-supl/StatusCode.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _StatusCode_H_ -#define _StatusCode_H_ +#ifndef _StatusCode_H_ +#define _StatusCode_H_ #include @@ -14,54 +14,56 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum StatusCode { - StatusCode_unspecified = 0, - StatusCode_systemFailure = 1, - StatusCode_unexpectedMessage = 2, - StatusCode_protocolError = 3, - StatusCode_dataMissing = 4, - StatusCode_unexpectedDataValue = 5, - StatusCode_posMethodFailure = 6, - StatusCode_posMethodMismatch = 7, - StatusCode_posProtocolMismatch = 8, - StatusCode_targetSETnotReachable = 9, - StatusCode_versionNotSupported = 10, - StatusCode_resourceShortage = 11, - StatusCode_invalidSessionId = 12, - StatusCode_nonProxyModeNotSupported = 13, - StatusCode_proxyModeNotSupported = 14, - StatusCode_positioningNotPermitted = 15, - StatusCode_authNetFailure = 16, - StatusCode_authSuplinitFailure = 17, - StatusCode_consentDeniedByUser = 100, - StatusCode_consentGrantedByUser = 101 - /* + /* Dependencies */ + typedef enum StatusCode + { + StatusCode_unspecified = 0, + StatusCode_systemFailure = 1, + StatusCode_unexpectedMessage = 2, + StatusCode_protocolError = 3, + StatusCode_dataMissing = 4, + StatusCode_unexpectedDataValue = 5, + StatusCode_posMethodFailure = 6, + StatusCode_posMethodMismatch = 7, + StatusCode_posProtocolMismatch = 8, + StatusCode_targetSETnotReachable = 9, + StatusCode_versionNotSupported = 10, + StatusCode_resourceShortage = 11, + StatusCode_invalidSessionId = 12, + StatusCode_nonProxyModeNotSupported = 13, + StatusCode_proxyModeNotSupported = 14, + StatusCode_positioningNotPermitted = 15, + StatusCode_authNetFailure = 16, + StatusCode_authSuplinitFailure = 17, + StatusCode_consentDeniedByUser = 100, + StatusCode_consentGrantedByUser = 101 + /* * Enumeration is extensible */ -} e_StatusCode; + } e_StatusCode; -/* StatusCode */ -typedef ENUMERATED_t StatusCode_t; + /* StatusCode */ + typedef ENUMERATED_t StatusCode_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_StatusCode; -asn_struct_free_f StatusCode_free; -asn_struct_print_f StatusCode_print; -asn_constr_check_f StatusCode_constraint; -ber_type_decoder_f StatusCode_decode_ber; -der_type_encoder_f StatusCode_encode_der; -xer_type_decoder_f StatusCode_decode_xer; -xer_type_encoder_f StatusCode_encode_xer; -per_type_decoder_f StatusCode_decode_uper; -per_type_encoder_f StatusCode_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_StatusCode; + asn_struct_free_f StatusCode_free; + asn_struct_print_f StatusCode_print; + asn_constr_check_f StatusCode_constraint; + ber_type_decoder_f StatusCode_decode_ber; + der_type_encoder_f StatusCode_encode_der; + xer_type_decoder_f StatusCode_decode_xer; + xer_type_encoder_f StatusCode_encode_xer; + per_type_decoder_f StatusCode_decode_uper; + per_type_encoder_f StatusCode_encode_uper; #ifdef __cplusplus } #endif -#endif /* _StatusCode_H_ */ +#endif /* _StatusCode_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/TGSN.h b/src/core/libs/supl/asn-supl/TGSN.h index 3aa40dc25..525479bb4 100644 --- a/src/core/libs/supl/asn-supl/TGSN.h +++ b/src/core/libs/supl/asn-supl/TGSN.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _TGSN_H_ -#define _TGSN_H_ +#ifndef _TGSN_H_ +#define _TGSN_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TGSN */ -typedef long TGSN_t; + /* TGSN */ + typedef long TGSN_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TGSN; -asn_struct_free_f TGSN_free; -asn_struct_print_f TGSN_print; -asn_constr_check_f TGSN_constraint; -ber_type_decoder_f TGSN_decode_ber; -der_type_encoder_f TGSN_encode_der; -xer_type_decoder_f TGSN_decode_xer; -xer_type_encoder_f TGSN_encode_xer; -per_type_decoder_f TGSN_decode_uper; -per_type_encoder_f TGSN_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TGSN; + asn_struct_free_f TGSN_free; + asn_struct_print_f TGSN_print; + asn_constr_check_f TGSN_constraint; + ber_type_decoder_f TGSN_decode_ber; + der_type_encoder_f TGSN_encode_der; + xer_type_decoder_f TGSN_decode_xer; + xer_type_encoder_f TGSN_encode_xer; + per_type_decoder_f TGSN_decode_uper; + per_type_encoder_f TGSN_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TGSN_H_ */ +#endif /* _TGSN_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/TimeslotISCP-List.h b/src/core/libs/supl/asn-supl/TimeslotISCP-List.h index 8333e73ae..99e60db88 100644 --- a/src/core/libs/supl/asn-supl/TimeslotISCP-List.h +++ b/src/core/libs/supl/asn-supl/TimeslotISCP-List.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _TimeslotISCP_List_H_ -#define _TimeslotISCP_List_H_ +#ifndef _TimeslotISCP_List_H_ +#define _TimeslotISCP_List_H_ #include @@ -16,23 +16,26 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TimeslotISCP-List */ -typedef struct TimeslotISCP_List { - A_SEQUENCE_OF(TimeslotISCP_t) list; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} TimeslotISCP_List_t; + /* TimeslotISCP-List */ + typedef struct TimeslotISCP_List + { + A_SEQUENCE_OF(TimeslotISCP_t) + list; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TimeslotISCP_List; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } TimeslotISCP_List_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TimeslotISCP_List; #ifdef __cplusplus } #endif -#endif /* _TimeslotISCP_List_H_ */ +#endif /* _TimeslotISCP_List_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/TimeslotISCP.h b/src/core/libs/supl/asn-supl/TimeslotISCP.h index 27ec36634..4b147e70f 100644 --- a/src/core/libs/supl/asn-supl/TimeslotISCP.h +++ b/src/core/libs/supl/asn-supl/TimeslotISCP.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _TimeslotISCP_H_ -#define _TimeslotISCP_H_ +#ifndef _TimeslotISCP_H_ +#define _TimeslotISCP_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* TimeslotISCP */ -typedef long TimeslotISCP_t; + /* TimeslotISCP */ + typedef long TimeslotISCP_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_TimeslotISCP; -asn_struct_free_f TimeslotISCP_free; -asn_struct_print_f TimeslotISCP_print; -asn_constr_check_f TimeslotISCP_constraint; -ber_type_decoder_f TimeslotISCP_decode_ber; -der_type_encoder_f TimeslotISCP_encode_der; -xer_type_decoder_f TimeslotISCP_decode_xer; -xer_type_encoder_f TimeslotISCP_encode_xer; -per_type_decoder_f TimeslotISCP_decode_uper; -per_type_encoder_f TimeslotISCP_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_TimeslotISCP; + asn_struct_free_f TimeslotISCP_free; + asn_struct_print_f TimeslotISCP_print; + asn_constr_check_f TimeslotISCP_constraint; + ber_type_decoder_f TimeslotISCP_decode_ber; + der_type_encoder_f TimeslotISCP_encode_der; + xer_type_decoder_f TimeslotISCP_decode_xer; + xer_type_encoder_f TimeslotISCP_encode_xer; + per_type_decoder_f TimeslotISCP_decode_uper; + per_type_encoder_f TimeslotISCP_encode_uper; #ifdef __cplusplus } #endif -#endif /* _TimeslotISCP_H_ */ +#endif /* _TimeslotISCP_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/UARFCN.h b/src/core/libs/supl/asn-supl/UARFCN.h index 3ece4c30d..5c4315138 100644 --- a/src/core/libs/supl/asn-supl/UARFCN.h +++ b/src/core/libs/supl/asn-supl/UARFCN.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _UARFCN_H_ -#define _UARFCN_H_ +#ifndef _UARFCN_H_ +#define _UARFCN_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* UARFCN */ -typedef long UARFCN_t; + /* UARFCN */ + typedef long UARFCN_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UARFCN; -asn_struct_free_f UARFCN_free; -asn_struct_print_f UARFCN_print; -asn_constr_check_f UARFCN_constraint; -ber_type_decoder_f UARFCN_decode_ber; -der_type_encoder_f UARFCN_encode_der; -xer_type_decoder_f UARFCN_decode_xer; -xer_type_encoder_f UARFCN_encode_xer; -per_type_decoder_f UARFCN_decode_uper; -per_type_encoder_f UARFCN_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UARFCN; + asn_struct_free_f UARFCN_free; + asn_struct_print_f UARFCN_print; + asn_constr_check_f UARFCN_constraint; + ber_type_decoder_f UARFCN_decode_ber; + der_type_encoder_f UARFCN_encode_der; + xer_type_decoder_f UARFCN_decode_xer; + xer_type_encoder_f UARFCN_encode_xer; + per_type_decoder_f UARFCN_decode_uper; + per_type_encoder_f UARFCN_encode_uper; #ifdef __cplusplus } #endif -#endif /* _UARFCN_H_ */ +#endif /* _UARFCN_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/ULP-PDU.h b/src/core/libs/supl/asn-supl/ULP-PDU.h index c90eb6287..c8582659a 100644 --- a/src/core/libs/supl/asn-supl/ULP-PDU.h +++ b/src/core/libs/supl/asn-supl/ULP-PDU.h @@ -4,8 +4,8 @@ * found in "../supl-ulp.asn" */ -#ifndef _ULP_PDU_H_ -#define _ULP_PDU_H_ +#ifndef _ULP_PDU_H_ +#define _ULP_PDU_H_ #include @@ -18,26 +18,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* ULP-PDU */ -typedef struct ULP_PDU { - long length; - Version_t version; - SessionID_t sessionID; - UlpMessage_t message; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} ULP_PDU_t; + /* ULP-PDU */ + typedef struct ULP_PDU + { + long length; + Version_t version; + SessionID_t sessionID; + UlpMessage_t message; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_ULP_PDU; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ULP_PDU_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_ULP_PDU; #ifdef __cplusplus } #endif -#endif /* _ULP_PDU_H_ */ +#endif /* _ULP_PDU_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/UTCTime.h b/src/core/libs/supl/asn-supl/UTCTime.h index 8035b3456..53517fde6 100644 --- a/src/core/libs/supl/asn-supl/UTCTime.h +++ b/src/core/libs/supl/asn-supl/UTCTime.h @@ -2,37 +2,38 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _UTCTime_H_ -#define _UTCTime_H_ +#ifndef _UTCTime_H_ +#define _UTCTime_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef OCTET_STRING_t UTCTime_t; /* Implemented via OCTET STRING */ + typedef OCTET_STRING_t UTCTime_t; /* Implemented via OCTET STRING */ -extern asn_TYPE_descriptor_t asn_DEF_UTCTime; + extern asn_TYPE_descriptor_t asn_DEF_UTCTime; -asn_struct_print_f UTCTime_print; -asn_constr_check_f UTCTime_constraint; -xer_type_encoder_f UTCTime_encode_xer; + asn_struct_print_f UTCTime_print; + asn_constr_check_f UTCTime_constraint; + xer_type_encoder_f UTCTime_encode_xer; -/*********************** + /*********************** * Some handy helpers. * ***********************/ -struct tm; /* */ + struct tm; /* */ -/* See asn_GT2time() in GeneralizedTime.h */ -time_t asn_UT2time(const UTCTime_t *, struct tm *_optional_tm4fill, int as_gmt); + /* See asn_GT2time() in GeneralizedTime.h */ + time_t asn_UT2time(const UTCTime_t *, struct tm *_optional_tm4fill, int as_gmt); -/* See asn_time2GT() in GeneralizedTime.h */ -UTCTime_t *asn_time2UT(UTCTime_t *__opt_ut, const struct tm *, int force_gmt); + /* See asn_time2GT() in GeneralizedTime.h */ + UTCTime_t *asn_time2UT(UTCTime_t *__opt_ut, const struct tm *, int force_gmt); #ifdef __cplusplus } #endif -#endif /* _UTCTime_H_ */ +#endif /* _UTCTime_H_ */ diff --git a/src/core/libs/supl/asn-supl/UTRA-CarrierRSSI.h b/src/core/libs/supl/asn-supl/UTRA-CarrierRSSI.h index 23b1bcb6f..8e9ea3835 100644 --- a/src/core/libs/supl/asn-supl/UTRA-CarrierRSSI.h +++ b/src/core/libs/supl/asn-supl/UTRA-CarrierRSSI.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _UTRA_CarrierRSSI_H_ -#define _UTRA_CarrierRSSI_H_ +#ifndef _UTRA_CarrierRSSI_H_ +#define _UTRA_CarrierRSSI_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* UTRA-CarrierRSSI */ -typedef long UTRA_CarrierRSSI_t; + /* UTRA-CarrierRSSI */ + typedef long UTRA_CarrierRSSI_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UTRA_CarrierRSSI; -asn_struct_free_f UTRA_CarrierRSSI_free; -asn_struct_print_f UTRA_CarrierRSSI_print; -asn_constr_check_f UTRA_CarrierRSSI_constraint; -ber_type_decoder_f UTRA_CarrierRSSI_decode_ber; -der_type_encoder_f UTRA_CarrierRSSI_encode_der; -xer_type_decoder_f UTRA_CarrierRSSI_decode_xer; -xer_type_encoder_f UTRA_CarrierRSSI_encode_xer; -per_type_decoder_f UTRA_CarrierRSSI_decode_uper; -per_type_encoder_f UTRA_CarrierRSSI_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UTRA_CarrierRSSI; + asn_struct_free_f UTRA_CarrierRSSI_free; + asn_struct_print_f UTRA_CarrierRSSI_print; + asn_constr_check_f UTRA_CarrierRSSI_constraint; + ber_type_decoder_f UTRA_CarrierRSSI_decode_ber; + der_type_encoder_f UTRA_CarrierRSSI_encode_der; + xer_type_decoder_f UTRA_CarrierRSSI_decode_xer; + xer_type_encoder_f UTRA_CarrierRSSI_encode_xer; + per_type_decoder_f UTRA_CarrierRSSI_decode_uper; + per_type_encoder_f UTRA_CarrierRSSI_encode_uper; #ifdef __cplusplus } #endif -#endif /* _UTRA_CarrierRSSI_H_ */ +#endif /* _UTRA_CarrierRSSI_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/UlpMessage.h b/src/core/libs/supl/asn-supl/UlpMessage.h index 8447dd73c..15f42aa9c 100644 --- a/src/core/libs/supl/asn-supl/UlpMessage.h +++ b/src/core/libs/supl/asn-supl/UlpMessage.h @@ -4,8 +4,8 @@ * found in "../supl-ulp.asn" */ -#ifndef _UlpMessage_H_ -#define _UlpMessage_H_ +#ifndef _UlpMessage_H_ +#define _UlpMessage_H_ #include @@ -21,52 +21,56 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum UlpMessage_PR { - UlpMessage_PR_NOTHING, /* No components present */ - UlpMessage_PR_msSUPLINIT, - UlpMessage_PR_msSUPLSTART, - UlpMessage_PR_msSUPLRESPONSE, - UlpMessage_PR_msSUPLPOSINIT, - UlpMessage_PR_msSUPLPOS, - UlpMessage_PR_msSUPLEND, - UlpMessage_PR_msDUMMY2, - UlpMessage_PR_msDUMMY3, - /* Extensions may appear below */ - -} UlpMessage_PR; + /* Dependencies */ + typedef enum UlpMessage_PR + { + UlpMessage_PR_NOTHING, /* No components present */ + UlpMessage_PR_msSUPLINIT, + UlpMessage_PR_msSUPLSTART, + UlpMessage_PR_msSUPLRESPONSE, + UlpMessage_PR_msSUPLPOSINIT, + UlpMessage_PR_msSUPLPOS, + UlpMessage_PR_msSUPLEND, + UlpMessage_PR_msDUMMY2, + UlpMessage_PR_msDUMMY3, + /* Extensions may appear below */ -/* UlpMessage */ -typedef struct UlpMessage { - UlpMessage_PR present; - union UlpMessage_u { - SUPLINIT_t msSUPLINIT; - SUPLSTART_t msSUPLSTART; - SUPLRESPONSE_t msSUPLRESPONSE; - SUPLPOSINIT_t msSUPLPOSINIT; - SUPLPOS_t msSUPLPOS; - SUPLEND_t msSUPLEND; - DUMMY_t msDUMMY2; - DUMMY_t msDUMMY3; - /* + } UlpMessage_PR; + + /* UlpMessage */ + typedef struct UlpMessage + { + UlpMessage_PR present; + union UlpMessage_u + { + SUPLINIT_t msSUPLINIT; + SUPLSTART_t msSUPLSTART; + SUPLRESPONSE_t msSUPLRESPONSE; + SUPLPOSINIT_t msSUPLPOSINIT; + SUPLPOS_t msSUPLPOS; + SUPLEND_t msSUPLEND; + DUMMY_t msDUMMY2; + DUMMY_t msDUMMY3; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} UlpMessage_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_UlpMessage; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } UlpMessage_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_UlpMessage; #ifdef __cplusplus } #endif -#endif /* _UlpMessage_H_ */ +#endif /* _UlpMessage_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Velocity.h b/src/core/libs/supl/asn-supl/Velocity.h index b4620dcc4..1db003a82 100644 --- a/src/core/libs/supl/asn-supl/Velocity.h +++ b/src/core/libs/supl/asn-supl/Velocity.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Velocity_H_ -#define _Velocity_H_ +#ifndef _Velocity_H_ +#define _Velocity_H_ #include @@ -18,44 +18,48 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Dependencies */ -typedef enum Velocity_PR { - Velocity_PR_NOTHING, /* No components present */ - Velocity_PR_horvel, - Velocity_PR_horandvervel, - Velocity_PR_horveluncert, - Velocity_PR_horandveruncert, - /* Extensions may appear below */ - -} Velocity_PR; + /* Dependencies */ + typedef enum Velocity_PR + { + Velocity_PR_NOTHING, /* No components present */ + Velocity_PR_horvel, + Velocity_PR_horandvervel, + Velocity_PR_horveluncert, + Velocity_PR_horandveruncert, + /* Extensions may appear below */ -/* Velocity */ -typedef struct Velocity { - Velocity_PR present; - union Velocity_u { - Horvel_t horvel; - Horandvervel_t horandvervel; - Horveluncert_t horveluncert; - Horandveruncert_t horandveruncert; - /* + } Velocity_PR; + + /* Velocity */ + typedef struct Velocity + { + Velocity_PR present; + union Velocity_u + { + Horvel_t horvel; + Horandvervel_t horandvervel; + Horveluncert_t horveluncert; + Horandveruncert_t horandveruncert; + /* * This type is extensible, * possible extensions are below. */ - } choice; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Velocity_t; + } choice; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Velocity; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Velocity_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Velocity; #ifdef __cplusplus } #endif -#endif /* _Velocity_H_ */ +#endif /* _Velocity_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Ver.c b/src/core/libs/supl/asn-supl/Ver.c index 664fb9517..5c99a89fc 100644 --- a/src/core/libs/supl/asn-supl/Ver.c +++ b/src/core/libs/supl/asn-supl/Ver.c @@ -6,35 +6,42 @@ #include "Ver.h" -int -Ver_constraint(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - size_t size; - - if(!sptr) { - _ASN_CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - if(st->size > 0) { - /* Size in bits */ - size = 8 * st->size - (st->bits_unused & 0x07); - } else { - size = 0; - } - - if((size == 64)) { - /* Constraint check succeeded */ - return 0; - } else { - _ASN_CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } +int Ver_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) +{ + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + size_t size; + + if (!sptr) + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if (st->size > 0) + { + /* Size in bits */ + size = 8 * st->size - (st->bits_unused & 0x07); + } + else + { + size = 0; + } + + if (size == 64) + { + /* Constraint check succeeded */ + return 0; + } + else + { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } } /* @@ -42,110 +49,113 @@ Ver_constraint(asn_TYPE_descriptor_t *td, const void *sptr, * so here we adjust the DEF accordingly. */ static void -Ver_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { - td->free_struct = asn_DEF_BIT_STRING.free_struct; - td->print_struct = asn_DEF_BIT_STRING.print_struct; - td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; - td->der_encoder = asn_DEF_BIT_STRING.der_encoder; - td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; - td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; - td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; - td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; - if(!td->per_constraints) - td->per_constraints = asn_DEF_BIT_STRING.per_constraints; - td->elements = asn_DEF_BIT_STRING.elements; - td->elements_count = asn_DEF_BIT_STRING.elements_count; - td->specifics = asn_DEF_BIT_STRING.specifics; +Ver_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) +{ + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if (!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; } -void -Ver_free(asn_TYPE_descriptor_t *td, - void *struct_ptr, int contents_only) { - Ver_1_inherit_TYPE_descriptor(td); - td->free_struct(td, struct_ptr, contents_only); +void Ver_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) +{ + Ver_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); } -int -Ver_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - Ver_1_inherit_TYPE_descriptor(td); - return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +int Ver_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); } asn_dec_rval_t Ver_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const void *bufptr, size_t size, int tag_mode) { - Ver_1_inherit_TYPE_descriptor(td); - return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); + void **structure, const void *bufptr, size_t size, int tag_mode) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); } asn_enc_rval_t Ver_encode_der(asn_TYPE_descriptor_t *td, - void *structure, int tag_mode, ber_tlv_tag_t tag, - asn_app_consume_bytes_f *cb, void *app_key) { - Ver_1_inherit_TYPE_descriptor(td); - return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); } asn_dec_rval_t Ver_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - void **structure, const char *opt_mname, const void *bufptr, size_t size) { - Ver_1_inherit_TYPE_descriptor(td); - return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); + void **structure, const char *opt_mname, const void *bufptr, size_t size) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); } asn_enc_rval_t Ver_encode_xer(asn_TYPE_descriptor_t *td, void *structure, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - Ver_1_inherit_TYPE_descriptor(td); - return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); } asn_dec_rval_t Ver_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) { - Ver_1_inherit_TYPE_descriptor(td); - return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); + asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data); } asn_enc_rval_t Ver_encode_uper(asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, - void *structure, asn_per_outp_t *per_out) { - Ver_1_inherit_TYPE_descriptor(td); - return td->uper_encoder(td, constraints, structure, per_out); + asn_per_constraints_t *constraints, + void *structure, asn_per_outp_t *per_out) +{ + Ver_1_inherit_TYPE_descriptor(td); + return td->uper_encoder(td, constraints, structure, per_out); } static asn_per_constraints_t asn_PER_type_Ver_constr_1 = { - { APC_UNCONSTRAINED, -1, -1, 0, 0 }, - { APC_CONSTRAINED, 0, 0, 64, 64 } /* (SIZE(64..64)) */, - 0, 0 /* No PER value map */ + {APC_UNCONSTRAINED, -1, -1, 0, 0}, + {APC_CONSTRAINED, 0, 0, 64, 64} /* (SIZE(64..64)) */, + 0, 0 /* No PER value map */ }; static ber_tlv_tag_t asn_DEF_Ver_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) -}; + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))}; asn_TYPE_descriptor_t asn_DEF_Ver = { - "Ver", - "Ver", - Ver_free, - Ver_print, - Ver_constraint, - Ver_decode_ber, - Ver_encode_der, - Ver_decode_xer, - Ver_encode_xer, - Ver_decode_uper, - Ver_encode_uper, - 0, /* Use generic outmost tag fetcher */ - asn_DEF_Ver_tags_1, - sizeof(asn_DEF_Ver_tags_1) - /sizeof(asn_DEF_Ver_tags_1[0]), /* 1 */ - asn_DEF_Ver_tags_1, /* Same as above */ - sizeof(asn_DEF_Ver_tags_1) - /sizeof(asn_DEF_Ver_tags_1[0]), /* 1 */ - &asn_PER_type_Ver_constr_1, - 0, 0, /* No members */ - 0 /* No specifics */ + "Ver", + "Ver", + Ver_free, + Ver_print, + Ver_constraint, + Ver_decode_ber, + Ver_encode_der, + Ver_decode_xer, + Ver_encode_xer, + Ver_decode_uper, + Ver_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Ver_tags_1, + sizeof(asn_DEF_Ver_tags_1) / sizeof(asn_DEF_Ver_tags_1[0]), /* 1 */ + asn_DEF_Ver_tags_1, /* Same as above */ + sizeof(asn_DEF_Ver_tags_1) / sizeof(asn_DEF_Ver_tags_1[0]), /* 1 */ + &asn_PER_type_Ver_constr_1, + 0, 0, /* No members */ + 0 /* No specifics */ }; - diff --git a/src/core/libs/supl/asn-supl/Ver.h b/src/core/libs/supl/asn-supl/Ver.h index 81c4fb55a..17a44483b 100644 --- a/src/core/libs/supl/asn-supl/Ver.h +++ b/src/core/libs/supl/asn-supl/Ver.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Ver_H_ -#define _Ver_H_ +#ifndef _Ver_H_ +#define _Ver_H_ #include @@ -14,27 +14,28 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Ver */ -typedef BIT_STRING_t Ver_t; + /* Ver */ + typedef BIT_STRING_t Ver_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Ver; -asn_struct_free_f Ver_free; -asn_struct_print_f Ver_print; -asn_constr_check_f Ver_constraint; -ber_type_decoder_f Ver_decode_ber; -der_type_encoder_f Ver_encode_der; -xer_type_decoder_f Ver_decode_xer; -xer_type_encoder_f Ver_encode_xer; -per_type_decoder_f Ver_decode_uper; -per_type_encoder_f Ver_encode_uper; + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Ver; + asn_struct_free_f Ver_free; + asn_struct_print_f Ver_print; + asn_constr_check_f Ver_constraint; + ber_type_decoder_f Ver_decode_ber; + der_type_encoder_f Ver_encode_der; + xer_type_decoder_f Ver_decode_xer; + xer_type_encoder_f Ver_encode_xer; + per_type_decoder_f Ver_decode_uper; + per_type_encoder_f Ver_encode_uper; #ifdef __cplusplus } #endif -#endif /* _Ver_H_ */ +#endif /* _Ver_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/Version.h b/src/core/libs/supl/asn-supl/Version.h index e0576ce24..7f1273592 100644 --- a/src/core/libs/supl/asn-supl/Version.h +++ b/src/core/libs/supl/asn-supl/Version.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _Version_H_ -#define _Version_H_ +#ifndef _Version_H_ +#define _Version_H_ #include @@ -15,25 +15,27 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Version */ -typedef struct Version { - long maj; - long min; - long servind; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} Version_t; + /* Version */ + typedef struct Version + { + long maj; + long min; + long servind; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_Version; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } Version_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_Version; #ifdef __cplusplus } #endif -#endif /* _Version_H_ */ +#endif /* _Version_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/VisibleString.h b/src/core/libs/supl/asn-supl/VisibleString.h index 20ba8cc50..ca9ed7e4d 100644 --- a/src/core/libs/supl/asn-supl/VisibleString.h +++ b/src/core/libs/supl/asn-supl/VisibleString.h @@ -2,23 +2,24 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _VisibleString_H_ -#define _VisibleString_H_ +#ifndef _VisibleString_H_ +#define _VisibleString_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef OCTET_STRING_t VisibleString_t; /* Implemented via OCTET STRING */ + typedef OCTET_STRING_t VisibleString_t; /* Implemented via OCTET STRING */ -extern asn_TYPE_descriptor_t asn_DEF_VisibleString; + extern asn_TYPE_descriptor_t asn_DEF_VisibleString; -asn_constr_check_f VisibleString_constraint; + asn_constr_check_f VisibleString_constraint; #ifdef __cplusplus } #endif -#endif /* _VisibleString_H_ */ +#endif /* _VisibleString_H_ */ diff --git a/src/core/libs/supl/asn-supl/WcdmaCellInformation.h b/src/core/libs/supl/asn-supl/WcdmaCellInformation.h index 8136982f7..9aaa46fdd 100644 --- a/src/core/libs/supl/asn-supl/WcdmaCellInformation.h +++ b/src/core/libs/supl/asn-supl/WcdmaCellInformation.h @@ -4,8 +4,8 @@ * found in "../supl-common.asn" */ -#ifndef _WcdmaCellInformation_H_ -#define _WcdmaCellInformation_H_ +#ifndef _WcdmaCellInformation_H_ +#define _WcdmaCellInformation_H_ #include @@ -15,32 +15,34 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct FrequencyInfo; -struct MeasuredResultsList; + /* Forward declarations */ + struct FrequencyInfo; + struct MeasuredResultsList; -/* WcdmaCellInformation */ -typedef struct WcdmaCellInformation { - long refMCC; - long refMNC; - long refUC; - struct FrequencyInfo *frequencyInfo /* OPTIONAL */; - long *primaryScramblingCode /* OPTIONAL */; - struct MeasuredResultsList *measuredResultsList /* OPTIONAL */; - /* + /* WcdmaCellInformation */ + typedef struct WcdmaCellInformation + { + long refMCC; + long refMNC; + long refUC; + struct FrequencyInfo *frequencyInfo /* OPTIONAL */; + long *primaryScramblingCode /* OPTIONAL */; + struct MeasuredResultsList *measuredResultsList /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} WcdmaCellInformation_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_WcdmaCellInformation; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } WcdmaCellInformation_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_WcdmaCellInformation; #ifdef __cplusplus } @@ -50,5 +52,5 @@ extern asn_TYPE_descriptor_t asn_DEF_WcdmaCellInformation; #include "FrequencyInfo.h" #include "MeasuredResultsList.h" -#endif /* _WcdmaCellInformation_H_ */ +#endif /* _WcdmaCellInformation_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/XNavigationModel.h b/src/core/libs/supl/asn-supl/XNavigationModel.h index 0fa410743..0962aeec4 100644 --- a/src/core/libs/supl/asn-supl/XNavigationModel.h +++ b/src/core/libs/supl/asn-supl/XNavigationModel.h @@ -4,8 +4,8 @@ * found in "../supl-posinit.asn" */ -#ifndef _XNavigationModel_H_ -#define _XNavigationModel_H_ +#ifndef _XNavigationModel_H_ +#define _XNavigationModel_H_ #include @@ -15,30 +15,32 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Forward declarations */ -struct SatelliteInfo; + /* Forward declarations */ + struct SatelliteInfo; -/* XNavigationModel */ -typedef struct XNavigationModel { - long gpsWeek; - long gpsToe; - long nSAT; - long toeLimit; - struct SatelliteInfo *satInfo /* OPTIONAL */; - /* + /* XNavigationModel */ + typedef struct XNavigationModel + { + long gpsWeek; + long gpsToe; + long nSAT; + long toeLimit; + struct SatelliteInfo *satInfo /* OPTIONAL */; + /* * This type is extensible, * possible extensions are below. */ - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} XNavigationModel_t; -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_XNavigationModel; + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } XNavigationModel_t; + + /* Implementation */ + extern asn_TYPE_descriptor_t asn_DEF_XNavigationModel; #ifdef __cplusplus } @@ -47,5 +49,5 @@ extern asn_TYPE_descriptor_t asn_DEF_XNavigationModel; /* Referred external types */ #include "SatelliteInfo.h" -#endif /* _XNavigationModel_H_ */ +#endif /* _XNavigationModel_H_ */ #include diff --git a/src/core/libs/supl/asn-supl/asn_SEQUENCE_OF.h b/src/core/libs/supl/asn-supl/asn_SEQUENCE_OF.h index e678f0347..2ad8287a0 100644 --- a/src/core/libs/supl/asn-supl/asn_SEQUENCE_OF.h +++ b/src/core/libs/supl/asn-supl/asn_SEQUENCE_OF.h @@ -2,13 +2,14 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_SEQUENCE_OF_H -#define ASN_SEQUENCE_OF_H +#ifndef ASN_SEQUENCE_OF_H +#define ASN_SEQUENCE_OF_H #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* @@ -16,37 +17,37 @@ extern "C" { * the delete operation preserves the initial order of elements * and thus MAY operate in non-constant time. */ -#define A_SEQUENCE_OF(type) A_SET_OF(type) +#define A_SEQUENCE_OF(type) A_SET_OF(type) -#define ASN_SEQUENCE_ADD(headptr, ptr) \ - asn_sequence_add((headptr), (ptr)) +#define ASN_SEQUENCE_ADD(headptr, ptr) \ + asn_sequence_add((headptr), (ptr)) -/*********************************************** + /*********************************************** * Implementation of the SEQUENCE OF structure. */ -#define asn_sequence_add asn_set_add -#define asn_sequence_empty asn_set_empty +#define asn_sequence_add asn_set_add +#define asn_sequence_empty asn_set_empty -/* + /* * Delete the element from the set by its number (base 0). * This is NOT a constant-time operation. * The order of elements is preserved. * If _do_free is given AND the (*free) is initialized, the element * will be freed using the custom (*free) function as well. */ -void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); + void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); -/* + /* * Cope with different conversions requirements to/from void in C and C++. * This is mostly useful for support library. */ -typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; -#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) -#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) + typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; +#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) +#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) #ifdef __cplusplus } #endif -#endif /* ASN_SEQUENCE_OF_H */ +#endif /* ASN_SEQUENCE_OF_H */ diff --git a/src/core/libs/supl/asn-supl/asn_SET_OF.h b/src/core/libs/supl/asn-supl/asn_SET_OF.h index 7edf14b51..0edc0abc4 100644 --- a/src/core/libs/supl/asn-supl/asn_SET_OF.h +++ b/src/core/libs/supl/asn-supl/asn_SET_OF.h @@ -2,36 +2,38 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_SET_OF_H -#define ASN_SET_OF_H +#ifndef ASN_SET_OF_H +#define ASN_SET_OF_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -#define A_SET_OF(type) \ - struct { \ - type **array; \ - int count; /* Meaningful size */ \ - int size; /* Allocated size */ \ - void (*free)(type *); \ - } +#define A_SET_OF(type) \ + struct \ + { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } -#define ASN_SET_ADD(headptr, ptr) \ - asn_set_add((headptr), (ptr)) +#define ASN_SET_ADD(headptr, ptr) \ + asn_set_add((headptr), (ptr)) -/******************************************* + /******************************************* * Implementation of the SET OF structure. */ -/* + /* * Add another structure into the set by its pointer. * RETURN VALUES: * 0 for success and -1/errno for failure. */ -int asn_set_add(void *asn_set_of_x, void *ptr); + int asn_set_add(void *asn_set_of_x, void *ptr); -/* + /* * Delete the element from the set by its number (base 0). * This is a constant-time operation. The order of elements before the * deleted ones is guaranteed, the order of elements after the deleted @@ -39,24 +41,24 @@ int asn_set_add(void *asn_set_of_x, void *ptr); * If _do_free is given AND the (*free) is initialized, the element * will be freed using the custom (*free) function as well. */ -void asn_set_del(void *asn_set_of_x, int number, int _do_free); + void asn_set_del(void *asn_set_of_x, int number, int _do_free); -/* + /* * Empty the contents of the set. Will free the elements, if (*free) is given. * Will NOT free the set itself. */ -void asn_set_empty(void *asn_set_of_x); + void asn_set_empty(void *asn_set_of_x); -/* + /* * Cope with different conversions requirements to/from void in C and C++. * This is mostly useful for support library. */ -typedef A_SET_OF(void) asn_anonymous_set_; -#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) -#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) + typedef A_SET_OF(void) asn_anonymous_set_; +#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) +#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) #ifdef __cplusplus } #endif -#endif /* ASN_SET_OF_H */ +#endif /* ASN_SET_OF_H */ diff --git a/src/core/libs/supl/asn-supl/asn_application.h b/src/core/libs/supl/asn-supl/asn_application.h index f40cd86ad..43904afb0 100644 --- a/src/core/libs/supl/asn-supl/asn_application.h +++ b/src/core/libs/supl/asn-supl/asn_application.h @@ -5,27 +5,28 @@ /* * Application-level ASN.1 callbacks. */ -#ifndef _ASN_APPLICATION_H_ -#define _ASN_APPLICATION_H_ +#ifndef _ASN_APPLICATION_H_ +#define _ASN_APPLICATION_H_ -#include "asn_system.h" /* for platform-dependent types */ -#include "asn_codecs.h" /* for ASN.1 codecs specifics */ +#include "asn_system.h" /* for platform-dependent types */ +#include "asn_codecs.h" /* for ASN.1 codecs specifics */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Generic type of an application-defined callback to return various * types of data to the application. * EXPECTED RETURN VALUES: * -1: Failed to consume bytes. Abort the mission. * Non-negative return values indicate success, and ignored. */ -typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, - void *application_specific_key); + typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, + void *application_specific_key); -/* + /* * A callback of this type is called whenever constraint validation fails * on some ASN.1 type. See "constraints.h" for more details on constraint * validation. @@ -33,15 +34,15 @@ typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, * the constraint check, as well as human readable message on what * particular constraint has failed. */ -typedef void (asn_app_constraint_failed_f)(void *application_specific_key, - struct asn_TYPE_descriptor_s *type_descriptor_which_failed, - const void *structure_which_failed_ptr, - const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); + typedef void(asn_app_constraint_failed_f)(void *application_specific_key, + struct asn_TYPE_descriptor_s *type_descriptor_which_failed, + const void *structure_which_failed_ptr, + const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); #ifdef __cplusplus } #endif -#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ +#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ -#endif /* _ASN_APPLICATION_H_ */ +#endif /* _ASN_APPLICATION_H_ */ diff --git a/src/core/libs/supl/asn-supl/asn_codecs.h b/src/core/libs/supl/asn-supl/asn_codecs.h index 4a251d940..717336ed5 100644 --- a/src/core/libs/supl/asn-supl/asn_codecs.h +++ b/src/core/libs/supl/asn-supl/asn_codecs.h @@ -3,16 +3,17 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ASN_CODECS_H_ -#define _ASN_CODECS_H_ +#ifndef _ASN_CODECS_H_ +#define _ASN_CODECS_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * This structure defines a set of parameters that may be passed * to every ASN.1 encoder or decoder function. * WARNING: if max_stack_size member is set, and you are calling the @@ -21,8 +22,9 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ * If you can't always satisfy this requirement, use ber_decode(), * xer_decode() and uper_decode() functions instead. */ -typedef struct asn_codec_ctx_s { - /* + typedef struct asn_codec_ctx_s + { + /* * Limit the decoder routines to use no (much) more stack than a given * number of bytes. Most of decoders are stack-based, and this * would protect against stack overflows if the number of nested @@ -33,45 +35,52 @@ typedef struct asn_codec_ctx_s { * this variable. Be careful in multithreaded environments, as the * stack size is rather limited. */ - size_t max_stack_size; /* 0 disables stack bounds checking */ -} asn_codec_ctx_t; + size_t max_stack_size; /* 0 disables stack bounds checking */ + } asn_codec_ctx_t; -/* + /* * Type of the return value of the encoding functions (der_encode, xer_encode). */ -typedef struct asn_enc_rval_s { - /* + typedef struct asn_enc_rval_s + { + /* * Number of bytes encoded. * -1 indicates failure to encode the structure. * In this case, the members below this one are meaningful. */ - ssize_t encoded; + ssize_t encoded; - /* + /* * Members meaningful when (encoded == -1), for post mortem analysis. */ - /* Type which cannot be encoded */ - struct asn_TYPE_descriptor_s *failed_type; + /* Type which cannot be encoded */ + struct asn_TYPE_descriptor_s *failed_type; - /* Pointer to the structure of that type */ - void *structure_ptr; -} asn_enc_rval_t; -#define _ASN_ENCODE_FAILED do { \ - asn_enc_rval_t tmp_error; \ - tmp_error.encoded = -1; \ - tmp_error.failed_type = td; \ - tmp_error.structure_ptr = sptr; \ - ASN_DEBUG("Failed to encode element %s", td->name); \ - return tmp_error; \ -} while(0) -#define _ASN_ENCODED_OK(rval) do { \ - rval.structure_ptr = 0; \ - rval.failed_type = 0; \ - return rval; \ -} while(0) + /* Pointer to the structure of that type */ + void *structure_ptr; + } asn_enc_rval_t; +#define _ASN_ENCODE_FAILED \ + do \ + { \ + asn_enc_rval_t tmp_error; \ + tmp_error.encoded = -1; \ + tmp_error.failed_type = td; \ + tmp_error.structure_ptr = sptr; \ + ASN_DEBUG("Failed to encode element %s", td->name); \ + return tmp_error; \ + } \ + while (0) +#define _ASN_ENCODED_OK(rval) \ + do \ + { \ + rval.structure_ptr = 0; \ + rval.failed_type = 0; \ + return rval; \ + } \ + while (0) -/* + /* * Type of the return value of the decoding functions (ber_decode, xer_decode) * * Please note that the number of consumed bytes is ALWAYS meaningful, @@ -79,31 +88,39 @@ typedef struct asn_enc_rval_s { * decoded bytes, hence providing a possibility to fail with more diagnostics * (i.e., print the offending remainder of the buffer). */ -enum asn_dec_rval_code_e { - RC_OK, /* Decoded successfully */ - RC_WMORE, /* More data expected, call again */ - RC_FAIL /* Failure to decode data */ -}; -typedef struct asn_dec_rval_s { - enum asn_dec_rval_code_e code; /* Result code */ - size_t consumed; /* Number of bytes consumed */ -} asn_dec_rval_t; -#define _ASN_DECODE_FAILED do { \ - asn_dec_rval_t tmp_error; \ - tmp_error.code = RC_FAIL; \ - tmp_error.consumed = 0; \ - ASN_DEBUG("Failed to decode element %s", td->name); \ - return tmp_error; \ -} while(0) -#define _ASN_DECODE_STARVED do { \ - asn_dec_rval_t tmp_error; \ - tmp_error.code = RC_WMORE; \ - tmp_error.consumed = 0; \ - return tmp_error; \ -} while(0) + enum asn_dec_rval_code_e + { + RC_OK, /* Decoded successfully */ + RC_WMORE, /* More data expected, call again */ + RC_FAIL /* Failure to decode data */ + }; + typedef struct asn_dec_rval_s + { + enum asn_dec_rval_code_e code; /* Result code */ + size_t consumed; /* Number of bytes consumed */ + } asn_dec_rval_t; +#define _ASN_DECODE_FAILED \ + do \ + { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_FAIL; \ + tmp_error.consumed = 0; \ + ASN_DEBUG("Failed to decode element %s", td->name); \ + return tmp_error; \ + } \ + while (0) +#define _ASN_DECODE_STARVED \ + do \ + { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_WMORE; \ + tmp_error.consumed = 0; \ + return tmp_error; \ + } \ + while (0) #ifdef __cplusplus } #endif -#endif /* _ASN_CODECS_H_ */ +#endif /* _ASN_CODECS_H_ */ diff --git a/src/core/libs/supl/asn-supl/asn_codecs_prim.h b/src/core/libs/supl/asn-supl/asn_codecs_prim.h index 0f683fdd0..cb8c37937 100644 --- a/src/core/libs/supl/asn-supl/asn_codecs_prim.h +++ b/src/core/libs/supl/asn-supl/asn_codecs_prim.h @@ -2,52 +2,53 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef ASN_CODECS_PRIM_H -#define ASN_CODECS_PRIM_H +#ifndef ASN_CODECS_PRIM_H +#define ASN_CODECS_PRIM_H #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct ASN__PRIMITIVE_TYPE_s { - uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ - int size; /* Size of the buffer */ -} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ + typedef struct ASN__PRIMITIVE_TYPE_s + { + uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ + int size; /* Size of the buffer */ + } ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ -asn_struct_free_f ASN__PRIMITIVE_TYPE_free; -ber_type_decoder_f ber_decode_primitive; -der_type_encoder_f der_encode_primitive; + asn_struct_free_f ASN__PRIMITIVE_TYPE_free; + ber_type_decoder_f ber_decode_primitive; + der_type_encoder_f der_encode_primitive; -/* + /* * A callback specification for the xer_decode_primitive() function below. */ -enum xer_pbd_rval { - XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ - XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ - XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ - XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ - XPBD_BODY_CONSUMED /* Body is recognized and consumed */ -}; -typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) - (asn_TYPE_descriptor_t *td, void *struct_ptr, - const void *chunk_buf, size_t chunk_size); + enum xer_pbd_rval + { + XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ + XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ + XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ + XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ + XPBD_BODY_CONSUMED /* Body is recognized and consumed */ + }; + typedef enum xer_pbd_rval(xer_primitive_body_decoder_f)(asn_TYPE_descriptor_t *td, void *struct_ptr, + const void *chunk_buf, size_t chunk_size); -/* + /* * Specific function to decode simple primitive types. * Also see xer_decode_general() in xer_decoder.h */ -asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *type_descriptor, - void **struct_ptr, size_t struct_size, - const char *opt_mname, - const void *buf_ptr, size_t size, - xer_primitive_body_decoder_f *prim_body_decoder -); + asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder); #ifdef __cplusplus } #endif -#endif /* ASN_CODECS_PRIM_H */ +#endif /* ASN_CODECS_PRIM_H */ diff --git a/src/core/libs/supl/asn-supl/asn_internal.h b/src/core/libs/supl/asn-supl/asn_internal.h index 249d7ef64..299c4e0e7 100644 --- a/src/core/libs/supl/asn-supl/asn_internal.h +++ b/src/core/libs/supl/asn-supl/asn_internal.h @@ -6,114 +6,130 @@ /* * Declarations internally useful for the ASN.1 support code. */ -#ifndef _ASN_INTERNAL_H_ -#define _ASN_INTERNAL_H_ +#ifndef _ASN_INTERNAL_H_ +#define _ASN_INTERNAL_H_ -#include "asn_application.h" /* Application-visible API */ +#include "asn_application.h" /* Application-visible API */ -#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ -#include /* for assert() macro */ +#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ +#include /* for assert() macro */ #endif -#ifdef __cplusplus -extern "C" { +#ifdef __cplusplus +extern "C" +{ #endif /* Environment version might be used to avoid running with the old library */ -#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ -int get_asn1c_environment_version(void); /* Run-time version */ +#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ + int get_asn1c_environment_version(void); /* Run-time version */ -#define CALLOC(nmemb, size) calloc(nmemb, size) -#define MALLOC(size) malloc(size) -#define REALLOC(oldptr, size) realloc(oldptr, size) -#define FREEMEM(ptr) free(ptr) +#define CALLOC(nmemb, size) calloc(nmemb, size) +#define MALLOC(size) malloc(size) +#define REALLOC(oldptr, size) realloc(oldptr, size) +#define FREEMEM(ptr) free(ptr) /* * A macro for debugging the ASN.1 internals. * You may enable or override it. */ -#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ -#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ -#ifdef __GNUC__ -#ifdef ASN_THREAD_SAFE -#define asn_debug_indent 0 -#else /* !ASN_THREAD_SAFE */ -int asn_debug_indent; -#endif /* ASN_THREAD_SAFE */ -#define ASN_DEBUG(fmt, args...) do { \ - int adi = asn_debug_indent; \ - while(adi--) fprintf(stderr, " "); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, " (%s:%d)\n", \ - __FILE__, __LINE__); \ - } while(0) -#else /* !__GNUC__ */ -void ASN_DEBUG_f(const char *fmt, ...); -#define ASN_DEBUG ASN_DEBUG_f -#endif /* __GNUC__ */ -#else /* EMIT_ASN_DEBUG != 1 */ -static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } -#endif /* EMIT_ASN_DEBUG */ -#endif /* ASN_DEBUG */ +#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ +#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ +#ifdef __GNUC__ +#ifdef ASN_THREAD_SAFE +#define asn_debug_indent 0 +#else /* !ASN_THREAD_SAFE */ + int asn_debug_indent; +#endif /* ASN_THREAD_SAFE */ +#define ASN_DEBUG(fmt, args...) \ + do \ + { \ + int adi = asn_debug_indent; \ + while (adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ + } \ + while (0) +#else /* !__GNUC__ */ + void ASN_DEBUG_f(const char *fmt, ...); +#define ASN_DEBUG ASN_DEBUG_f +#endif /* __GNUC__ */ +#else /* EMIT_ASN_DEBUG != 1 */ + static inline void ASN_DEBUG(const char *fmt, ...) + { + (void)fmt; + } +#endif /* EMIT_ASN_DEBUG */ +#endif /* ASN_DEBUG */ /* * Invoke the application-supplied callback and fail, if something is wrong. */ -#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) -#define _ASN_E_CALLBACK(foo) do { \ - if(foo) goto cb_failed; \ - } while(0) -#define _ASN_CALLBACK(buf, size) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) -#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) -#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ - _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ - || __ASN_E_cbc(buf2, size2) \ - || __ASN_E_cbc(buf3, size3)) +#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) +#define _ASN_E_CALLBACK(foo) \ + do \ + { \ + if (foo) goto cb_failed; \ + } \ + while (0) +#define _ASN_CALLBACK(buf, size) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) +#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) +#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2) || __ASN_E_cbc(buf3, size3)) -#define _i_ASN_TEXT_INDENT(nl, level) do { \ - int __level = (level); \ - int __nl = ((nl) != 0); \ - int __i; \ - if(__nl) _ASN_CALLBACK("\n", 1); \ - if(__level < 0) __level = 0; \ - for(__i = 0; __i < __level; __i++) \ - _ASN_CALLBACK(" ", 4); \ - er.encoded += __nl + 4 * __level; \ -} while(0) +#define _i_ASN_TEXT_INDENT(nl, level) \ + do \ + { \ + int __level = (level); \ + int __nl = ((nl) != 0); \ + int __i; \ + if (__nl) _ASN_CALLBACK("\n", 1); \ + if (__level < 0) __level = 0; \ + for (__i = 0; __i < __level; __i++) \ + _ASN_CALLBACK(" ", 4); \ + er.encoded += __nl + 4 * __level; \ + } \ + while (0) -#define _i_INDENT(nl) do { \ - int __i; \ - if((nl) && cb("\n", 1, app_key) < 0) return -1; \ - for(__i = 0; __i < ilevel; __i++) \ - if(cb(" ", 4, app_key) < 0) return -1; \ -} while(0) +#define _i_INDENT(nl) \ + do \ + { \ + int __i; \ + if ((nl) && cb("\n", 1, app_key) < 0) return -1; \ + for (__i = 0; __i < ilevel; __i++) \ + if (cb(" ", 4, app_key) < 0) return -1; \ + } \ + while (0) /* * Check stack against overflow, if limit is set. */ -#define _ASN_DEFAULT_STACK_MAX (30000) -static inline int -_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { - if(ctx && ctx->max_stack_size) { +#define _ASN_DEFAULT_STACK_MAX (30000) + static inline int + _ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) + { + if (ctx && ctx->max_stack_size) + { + /* ctx MUST be allocated on the stack */ + ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); + if (usedstack > 0) usedstack = -usedstack; /* grows up! */ - /* ctx MUST be allocated on the stack */ - ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); - if(usedstack > 0) usedstack = -usedstack; /* grows up! */ + /* double negative required to avoid int wrap-around */ + if (usedstack < -(ptrdiff_t)ctx->max_stack_size) + { + ASN_DEBUG("Stack limit %ld reached", + (long)ctx->max_stack_size); + return -1; + } + } + return 0; + } - /* double negative required to avoid int wrap-around */ - if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { - ASN_DEBUG("Stack limit %ld reached", - (long)ctx->max_stack_size); - return -1; - } - } - return 0; -} - -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* _ASN_INTERNAL_H_ */ +#endif /* _ASN_INTERNAL_H_ */ diff --git a/src/core/libs/supl/asn-supl/asn_system.h b/src/core/libs/supl/asn-supl/asn_system.h index 0a9b092c3..1d2958174 100644 --- a/src/core/libs/supl/asn-supl/asn_system.h +++ b/src/core/libs/supl/asn-supl/asn_system.h @@ -6,124 +6,121 @@ /* * Miscellaneous system-dependent types. */ -#ifndef _ASN_SYSTEM_H_ -#define _ASN_SYSTEM_H_ +#ifndef _ASN_SYSTEM_H_ +#define _ASN_SYSTEM_H_ -#ifdef HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H #include "config.h" #endif -#include /* For snprintf(3) */ -#include /* For *alloc(3) */ -#include /* For memcpy(3) */ -#include /* For size_t */ -#include /* For LONG_MAX */ -#include /* For va_start */ -#include /* for offsetof and ptrdiff_t */ +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ +#include /* For size_t */ +#include /* For LONG_MAX */ +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ -#ifdef WIN32 +#ifdef WIN32 #include -#define snprintf _snprintf -#define vsnprintf _vsnprintf +#define snprintf _snprintf +#define vsnprintf _vsnprintf /* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ -#define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ - | (((l) << 16) & 0xff0000) \ - | (((l) << 8) & 0xff00) \ - | ((l) & 0xff)) +#define sys_ntohl(l) ((((l) << 24) & 0xff000000) | (((l) << 16) & 0xff0000) | (((l) << 8) & 0xff00) | ((l)&0xff)) -#ifdef _MSC_VER /* MSVS.Net */ +#ifdef _MSC_VER /* MSVS.Net */ #ifndef __cplusplus #define inline __inline #endif -#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ -#define ssize_t SSIZE_T -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#endif /* ASSUMESTDTYPES */ +#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ +#define ssize_t SSIZE_T +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#endif /* ASSUMESTDTYPES */ #define WIN32_LEAN_AND_MEAN #include #include #define isnan _isnan #define finite _finite #define copysign _copysign -#define ilogb _logb -#else /* !_MSC_VER */ +#define ilogb _logb +#else /* !_MSC_VER */ #include -#endif /* _MSC_VER */ +#endif /* _MSC_VER */ -#else /* !WIN32 */ +#else /* !WIN32 */ #if defined(__vxworks) #include -#else /* !defined(__vxworks) */ +#else /* !defined(__vxworks) */ -#include /* C99 specifies this file */ +#include /* C99 specifies this file */ /* * 1. Earlier FreeBSD version didn't have , * but was present. * 2. Sun Solaris requires for alloca(3), * but does not have . */ -#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) -#if defined(sun) -#include /* For alloca(3) */ -#include /* for finite(3) */ -#elif defined(__hpux) -#ifdef __GNUC__ -#include /* For alloca(3) */ -#else /* !__GNUC__ */ +#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) +#if defined(sun) +#include /* For alloca(3) */ +#include /* for finite(3) */ +#elif defined(__hpux) +#ifdef __GNUC__ +#include /* For alloca(3) */ +#else /* !__GNUC__ */ #define inline -#endif /* __GNUC__ */ +#endif /* __GNUC__ */ #else -#include /* SUSv2+ and C99 specify this file, for uintXX_t */ -#endif /* defined(sun) */ +#include /* SUSv2+ and C99 specify this file, for uintXX_t */ +#endif /* defined(sun) */ #endif #include /* for ntohl() */ -#define sys_ntohl(foo) ntohl(foo) +#define sys_ntohl(foo) ntohl(foo) -#endif /* defined(__vxworks) */ +#endif /* defined(__vxworks) */ -#endif /* WIN32 */ +#endif /* WIN32 */ -#if __GNUC__ >= 3 -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#if __GNUC__ >= 3 +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt, var) __attribute__((format(printf, fmt, var))) #endif -#ifndef GCC_NOTUSED -#define GCC_NOTUSED __attribute__((unused)) +#ifndef GCC_NOTUSED +#define GCC_NOTUSED __attribute__((unused)) #endif #else -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) /* nothing */ +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt, var) /* nothing */ #endif -#ifndef GCC_NOTUSED -#define GCC_NOTUSED +#ifndef GCC_NOTUSED +#define GCC_NOTUSED #endif #endif /* Figure out if thread safety is requested */ #if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) -#define ASN_THREAD_SAFE -#endif /* Thread safety */ +#define ASN_THREAD_SAFE +#endif /* Thread safety */ -#ifndef offsetof /* If not defined by */ -#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) -#endif /* offsetof */ +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t) & (((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ -#ifndef MIN /* Suitable for comparing primitive types (integers) */ +#ifndef MIN /* Suitable for comparing primitive types (integers) */ #if defined(__GNUC__) -#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ +#define MIN(a, b) ({ __typeof a _a = a; __typeof b _b = b; \ ((_a)<(_b)?(_a):(_b)); }) -#else /* !__GNUC__ */ -#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ -#endif /* __GNUC__ */ -#endif /* MIN */ +#else /* !__GNUC__ */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) /* Unsafe variant */ +#endif /* __GNUC__ */ +#endif /* MIN */ -#endif /* _ASN_SYSTEM_H_ */ +#endif /* _ASN_SYSTEM_H_ */ diff --git a/src/core/libs/supl/asn-supl/ber_decoder.c b/src/core/libs/supl/asn-supl/ber_decoder.c index 601f66c0b..77cb8032e 100644 --- a/src/core/libs/supl/asn-supl/ber_decoder.c +++ b/src/core/libs/supl/asn-supl/ber_decoder.c @@ -16,7 +16,7 @@ asn_dec_rval_t rval; \ rval.code = _code; \ if(opt_ctx) opt_ctx->step = step; /* Save context */ \ - if(_code == RC_OK || opt_ctx) \ + if((_code) == RC_OK || opt_ctx) \ rval.consumed = consumed_myself; \ else \ rval.consumed = 0; /* Context-free */ \ diff --git a/src/core/libs/supl/asn-supl/ber_decoder.h b/src/core/libs/supl/asn-supl/ber_decoder.h index 9fe2e895d..6a87fc23f 100644 --- a/src/core/libs/supl/asn-supl/ber_decoder.h +++ b/src/core/libs/supl/asn-supl/ber_decoder.h @@ -2,63 +2,64 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_DECODER_H_ -#define _BER_DECODER_H_ +#ifndef _BER_DECODER_H_ +#define _BER_DECODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ -struct asn_codec_ctx_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_codec_ctx_s; /* Forward declaration */ -/* + /* * The BER decoder of any type. * This function may be invoked directly from the application. * The der_encode() function (der_encoder.h) is an opposite to ber_decode(). */ -asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of that buffer */ - ); + asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ + ); -/* + /* * Type of generic function which decodes the byte stream into the structure. */ -typedef asn_dec_rval_t (ber_type_decoder_f)( - struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, const void *buf_ptr, size_t size, - int tag_mode); + typedef asn_dec_rval_t(ber_type_decoder_f)( + struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, const void *buf_ptr, size_t size, + int tag_mode); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Check that all tags correspond to the type definition (as given in head). * On return, last_length would contain either a non-negative length of the * value part of the last TLV, or the negative number of expected * "end of content" sequences. The number may only be negative if the * head->last_tag_form is non-zero. */ -asn_dec_rval_t ber_check_tags( - struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ - struct asn_TYPE_descriptor_s *type_descriptor, - asn_struct_ctx_t *opt_ctx, /* saved decoding context */ - const void *ptr, size_t size, - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - int last_tag_form, /* {-1,0:1}: any, primitive, constr */ - ber_tlv_len_t *last_length, - int *opt_tlv_form /* optional tag form */ - ); + asn_dec_rval_t ber_check_tags( + struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ + struct asn_TYPE_descriptor_s *type_descriptor, + asn_struct_ctx_t *opt_ctx, /* saved decoding context */ + const void *ptr, size_t size, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {-1,0:1}: any, primitive, constr */ + ber_tlv_len_t *last_length, + int *opt_tlv_form /* optional tag form */ + ); #ifdef __cplusplus } #endif -#endif /* _BER_DECODER_H_ */ +#endif /* _BER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/ber_tlv_length.h b/src/core/libs/supl/asn-supl/ber_tlv_length.h index 349680224..7245624cd 100644 --- a/src/core/libs/supl/asn-supl/ber_tlv_length.h +++ b/src/core/libs/supl/asn-supl/ber_tlv_length.h @@ -2,16 +2,17 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_TLV_LENGTH_H_ -#define _BER_TLV_LENGTH_H_ +#ifndef _BER_TLV_LENGTH_H_ +#define _BER_TLV_LENGTH_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef ssize_t ber_tlv_len_t; + typedef ssize_t ber_tlv_len_t; -/* + /* * This function tries to fetch the length of the BER TLV value and place it * in *len_r. * RETURN VALUES: @@ -21,30 +22,30 @@ typedef ssize_t ber_tlv_len_t; * On return with >0, len_r is constrained as -1..MAX, where -1 mean * that the value is of indefinite length. */ -ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, - ber_tlv_len_t *len_r); + ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r); -/* + /* * This function expects bufptr to be positioned over L in TLV. * It returns number of bytes occupied by L and V together, suitable * for skipping. The function properly handles indefinite length. * RETURN VALUES: * Standard {-1,0,>0} convention. */ -ssize_t ber_skip_length( - struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ - int _is_constructed, const void *bufptr, size_t size); + ssize_t ber_skip_length( + struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ + int _is_constructed, const void *bufptr, size_t size); -/* + /* * This function serializes the length (L from TLV) in DER format. * It always returns number of bytes necessary to represent the length, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ -size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); + size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); #ifdef __cplusplus } #endif -#endif /* _BER_TLV_LENGTH_H_ */ +#endif /* _BER_TLV_LENGTH_H_ */ diff --git a/src/core/libs/supl/asn-supl/ber_tlv_tag.h b/src/core/libs/supl/asn-supl/ber_tlv_tag.h index 60e866861..31b634345 100644 --- a/src/core/libs/supl/asn-supl/ber_tlv_tag.h +++ b/src/core/libs/supl/asn-supl/ber_tlv_tag.h @@ -2,59 +2,61 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _BER_TLV_TAG_H_ -#define _BER_TLV_TAG_H_ +#ifndef _BER_TLV_TAG_H_ +#define _BER_TLV_TAG_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -enum asn_tag_class { - ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ - ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ - ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ - ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ -}; -typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ + enum asn_tag_class + { + ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ + ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ + ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ + ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ + }; + typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ /* * Tag class is encoded together with tag value for optimization purposes. */ -#define BER_TAG_CLASS(tag) ((tag) & 0x3) -#define BER_TAG_VALUE(tag) ((tag) >> 2) -#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) +#define BER_TAG_CLASS(tag) ((tag)&0x3) +#define BER_TAG_VALUE(tag) ((tag) >> 2) +#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr) & 0x20) ? 1 : 0) -#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) +#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) -/* + /* * Several functions for printing the TAG in the canonical form * (i.e. "[PRIVATE 0]"). * Return values correspond to their libc counterparts (if any). */ -ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); -ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); -char *ber_tlv_tag_string(ber_tlv_tag_t tag); + ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); + ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); + char *ber_tlv_tag_string(ber_tlv_tag_t tag); -/* + /* * This function tries to fetch the tag from the input stream. * RETURN VALUES: * 0: More data expected than bufptr contains. * -1: Fatal error deciphering tag. * >0: Number of bytes used from bufptr. tag_r will contain the tag. */ -ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); + ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); -/* + /* * This function serializes the tag (T from TLV) in BER format. * It always returns number of bytes necessary to represent the tag, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ -size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); + size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); #ifdef __cplusplus } #endif -#endif /* _BER_TLV_TAG_H_ */ +#endif /* _BER_TLV_TAG_H_ */ diff --git a/src/core/libs/supl/asn-supl/constr_CHOICE.c b/src/core/libs/supl/asn-supl/constr_CHOICE.c index a9eb71941..75903fde7 100644 --- a/src/core/libs/supl/asn-supl/constr_CHOICE.c +++ b/src/core/libs/supl/asn-supl/constr_CHOICE.c @@ -46,8 +46,8 @@ */ #undef NEXT_PHASE #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) /* diff --git a/src/core/libs/supl/asn-supl/constr_CHOICE.h b/src/core/libs/supl/asn-supl/constr_CHOICE.h index 83404e6d4..264018481 100644 --- a/src/core/libs/supl/asn-supl/constr_CHOICE.h +++ b/src/core/libs/supl/asn-supl/constr_CHOICE.h @@ -3,55 +3,57 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_CHOICE_H_ -#define _CONSTR_CHOICE_H_ +#ifndef _CONSTR_CHOICE_H_ +#define _CONSTR_CHOICE_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_CHOICE_specifics_s { - /* + typedef struct asn_CHOICE_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_codec_ctx_t member */ - int pres_offset; /* Identifier of the present member */ - int pres_size; /* Size of the identifier (enum) */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_codec_ctx_t member */ + int pres_offset; /* Identifier of the present member */ + int pres_size; /* Size of the identifier (enum) */ - /* + /* * Tags to members mapping table. */ - asn_TYPE_tag2member_t *tag2el; - int tag2el_count; + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; - /* Canonical ordering of CHOICE elements, for PER */ - int *canonical_order; + /* Canonical ordering of CHOICE elements, for PER */ + int *canonical_order; - /* + /* * Extensions-related stuff. */ - int ext_start; /* First member of extensions, or -1 */ -} asn_CHOICE_specifics_t; + int ext_start; /* First member of extensions, or -1 */ + } asn_CHOICE_specifics_t; -/* + /* * A set specialized functions dealing with the CHOICE type. */ -asn_struct_free_f CHOICE_free; -asn_struct_print_f CHOICE_print; -asn_constr_check_f CHOICE_constraint; -ber_type_decoder_f CHOICE_decode_ber; -der_type_encoder_f CHOICE_encode_der; -xer_type_decoder_f CHOICE_decode_xer; -xer_type_encoder_f CHOICE_encode_xer; -per_type_decoder_f CHOICE_decode_uper; -per_type_encoder_f CHOICE_encode_uper; -asn_outmost_tag_f CHOICE_outmost_tag; + asn_struct_free_f CHOICE_free; + asn_struct_print_f CHOICE_print; + asn_constr_check_f CHOICE_constraint; + ber_type_decoder_f CHOICE_decode_ber; + der_type_encoder_f CHOICE_encode_der; + xer_type_decoder_f CHOICE_decode_xer; + xer_type_encoder_f CHOICE_encode_xer; + per_type_decoder_f CHOICE_decode_uper; + per_type_encoder_f CHOICE_encode_uper; + asn_outmost_tag_f CHOICE_outmost_tag; #ifdef __cplusplus } #endif -#endif /* _CONSTR_CHOICE_H_ */ +#endif /* _CONSTR_CHOICE_H_ */ diff --git a/src/core/libs/supl/asn-supl/constr_SEQUENCE.c b/src/core/libs/supl/asn-supl/constr_SEQUENCE.c index db3c92581..aba19bd26 100644 --- a/src/core/libs/supl/asn-supl/constr_SEQUENCE.c +++ b/src/core/libs/supl/asn-supl/constr_SEQUENCE.c @@ -47,10 +47,10 @@ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) -#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) +#define PHASE_OUT(ctx) do { (ctx)->phase = 10; } while(0) /* * Return a standardized complex structure. diff --git a/src/core/libs/supl/asn-supl/constr_SEQUENCE.h b/src/core/libs/supl/asn-supl/constr_SEQUENCE.h index 5f589d5c1..e2664a123 100644 --- a/src/core/libs/supl/asn-supl/constr_SEQUENCE.h +++ b/src/core/libs/supl/asn-supl/constr_SEQUENCE.h @@ -2,59 +2,61 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SEQUENCE_H_ -#define _CONSTR_SEQUENCE_H_ +#ifndef _CONSTR_SEQUENCE_H_ +#define _CONSTR_SEQUENCE_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_SEQUENCE_specifics_s { - /* + typedef struct asn_SEQUENCE_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - /* + /* * Tags to members mapping table (sorted). */ - asn_TYPE_tag2member_t *tag2el; - int tag2el_count; + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; - /* + /* * Optional members of the extensions root (roms) or additions (aoms). * Meaningful for PER. */ - int *oms; /* Optional MemberS */ - int roms_count; /* Root optional members count */ - int aoms_count; /* Additions optional members count */ + int *oms; /* Optional MemberS */ + int roms_count; /* Root optional members count */ + int aoms_count; /* Additions optional members count */ - /* + /* * Description of an extensions group. */ - int ext_after; /* Extensions start after this member */ - int ext_before; /* Extensions stop before this member */ -} asn_SEQUENCE_specifics_t; + int ext_after; /* Extensions start after this member */ + int ext_before; /* Extensions stop before this member */ + } asn_SEQUENCE_specifics_t; -/* + /* * A set specialized functions dealing with the SEQUENCE type. */ -asn_struct_free_f SEQUENCE_free; -asn_struct_print_f SEQUENCE_print; -asn_constr_check_f SEQUENCE_constraint; -ber_type_decoder_f SEQUENCE_decode_ber; -der_type_encoder_f SEQUENCE_encode_der; -xer_type_decoder_f SEQUENCE_decode_xer; -xer_type_encoder_f SEQUENCE_encode_xer; -per_type_decoder_f SEQUENCE_decode_uper; -per_type_encoder_f SEQUENCE_encode_uper; + asn_struct_free_f SEQUENCE_free; + asn_struct_print_f SEQUENCE_print; + asn_constr_check_f SEQUENCE_constraint; + ber_type_decoder_f SEQUENCE_decode_ber; + der_type_encoder_f SEQUENCE_encode_der; + xer_type_decoder_f SEQUENCE_decode_xer; + xer_type_encoder_f SEQUENCE_encode_xer; + per_type_decoder_f SEQUENCE_decode_uper; + per_type_encoder_f SEQUENCE_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SEQUENCE_H_ */ +#endif /* _CONSTR_SEQUENCE_H_ */ diff --git a/src/core/libs/supl/asn-supl/constr_SEQUENCE_OF.h b/src/core/libs/supl/asn-supl/constr_SEQUENCE_OF.h index e2272f326..927ed5163 100644 --- a/src/core/libs/supl/asn-supl/constr_SEQUENCE_OF.h +++ b/src/core/libs/supl/asn-supl/constr_SEQUENCE_OF.h @@ -2,32 +2,33 @@ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SEQUENCE_OF_H_ -#define _CONSTR_SEQUENCE_OF_H_ +#ifndef _CONSTR_SEQUENCE_OF_H_ +#define _CONSTR_SEQUENCE_OF_H_ #include -#include /* Implemented using SET OF */ +#include /* Implemented using SET OF */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* * A set specialized functions dealing with the SEQUENCE OF type. * Generally implemented using SET OF. */ -#define SEQUENCE_OF_free SET_OF_free -#define SEQUENCE_OF_print SET_OF_print -#define SEQUENCE_OF_constraint SET_OF_constraint -#define SEQUENCE_OF_decode_ber SET_OF_decode_ber -#define SEQUENCE_OF_decode_xer SET_OF_decode_xer -#define SEQUENCE_OF_decode_uper SET_OF_decode_uper -der_type_encoder_f SEQUENCE_OF_encode_der; -xer_type_encoder_f SEQUENCE_OF_encode_xer; -per_type_encoder_f SEQUENCE_OF_encode_uper; +#define SEQUENCE_OF_free SET_OF_free +#define SEQUENCE_OF_print SET_OF_print +#define SEQUENCE_OF_constraint SET_OF_constraint +#define SEQUENCE_OF_decode_ber SET_OF_decode_ber +#define SEQUENCE_OF_decode_xer SET_OF_decode_xer +#define SEQUENCE_OF_decode_uper SET_OF_decode_uper + der_type_encoder_f SEQUENCE_OF_encode_der; + xer_type_encoder_f SEQUENCE_OF_encode_xer; + per_type_encoder_f SEQUENCE_OF_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SET_OF_H_ */ +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/core/libs/supl/asn-supl/constr_SET_OF.c b/src/core/libs/supl/asn-supl/constr_SET_OF.c index 11eac57a2..8b9c0669a 100644 --- a/src/core/libs/supl/asn-supl/constr_SET_OF.c +++ b/src/core/libs/supl/asn-supl/constr_SET_OF.c @@ -47,10 +47,10 @@ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) do { \ - ctx->phase++; \ - ctx->step = 0; \ + (ctx)->phase++; \ + (ctx)->step = 0; \ } while(0) -#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) +#define PHASE_OUT(ctx) do { (ctx)->phase = 10; } while(0) /* * Return a standardized complex structure. @@ -915,7 +915,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, nelems = uper_get_length(pd, ct ? ct->effective_bits : -1, &repeat); ASN_DEBUG("Got to decode %d elements (eff %d)", - (int)nelems, (int)ct ? ct->effective_bits : -1); + (int)nelems, (long)ct ? ct->effective_bits : -1); if(nelems < 0) _ASN_DECODE_STARVED; } diff --git a/src/core/libs/supl/asn-supl/constr_SET_OF.h b/src/core/libs/supl/asn-supl/constr_SET_OF.h index bcd096629..52b446281 100644 --- a/src/core/libs/supl/asn-supl/constr_SET_OF.h +++ b/src/core/libs/supl/asn-supl/constr_SET_OF.h @@ -2,41 +2,43 @@ * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _CONSTR_SET_OF_H_ -#define _CONSTR_SET_OF_H_ +#ifndef _CONSTR_SET_OF_H_ +#define _CONSTR_SET_OF_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct asn_SET_OF_specifics_s { - /* + typedef struct asn_SET_OF_specifics_s + { + /* * Target structure description. */ - int struct_size; /* Size of the target structure. */ - int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - /* XER-specific stuff */ - int as_XMLValueList; /* The member type must be encoded like this */ -} asn_SET_OF_specifics_t; + /* XER-specific stuff */ + int as_XMLValueList; /* The member type must be encoded like this */ + } asn_SET_OF_specifics_t; -/* + /* * A set specialized functions dealing with the SET OF type. */ -asn_struct_free_f SET_OF_free; -asn_struct_print_f SET_OF_print; -asn_constr_check_f SET_OF_constraint; -ber_type_decoder_f SET_OF_decode_ber; -der_type_encoder_f SET_OF_encode_der; -xer_type_decoder_f SET_OF_decode_xer; -xer_type_encoder_f SET_OF_encode_xer; -per_type_decoder_f SET_OF_decode_uper; -per_type_encoder_f SET_OF_encode_uper; + asn_struct_free_f SET_OF_free; + asn_struct_print_f SET_OF_print; + asn_constr_check_f SET_OF_constraint; + ber_type_decoder_f SET_OF_decode_ber; + der_type_encoder_f SET_OF_encode_der; + xer_type_decoder_f SET_OF_decode_xer; + xer_type_encoder_f SET_OF_encode_xer; + per_type_decoder_f SET_OF_decode_uper; + per_type_encoder_f SET_OF_encode_uper; #ifdef __cplusplus } #endif -#endif /* _CONSTR_SET_OF_H_ */ +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/core/libs/supl/asn-supl/constr_TYPE.h b/src/core/libs/supl/asn-supl/constr_TYPE.h index 95507c809..0641f003c 100644 --- a/src/core/libs/supl/asn-supl/constr_TYPE.h +++ b/src/core/libs/supl/asn-supl/constr_TYPE.h @@ -9,158 +9,164 @@ * This structure even contains pointer to these encoding and decoding routines * for each defined ASN.1 type. */ -#ifndef _CONSTR_TYPE_H_ -#define _CONSTR_TYPE_H_ +#ifndef _CONSTR_TYPE_H_ +#define _CONSTR_TYPE_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ -struct asn_TYPE_member_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_member_s; /* Forward declaration */ -/* + /* * This type provides the context information for various ASN.1 routines, * primarily ones doing decoding. A member _asn_ctx of this type must be * included into certain target language's structures, such as compound types. */ -typedef struct asn_struct_ctx_s { - short phase; /* Decoding phase */ - short step; /* Elementary step of a phase */ - int context; /* Other context information */ - void *ptr; /* Decoder-specific stuff (stack elements) */ - ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ -} asn_struct_ctx_t; + typedef struct asn_struct_ctx_s + { + short phase; /* Decoding phase */ + short step; /* Elementary step of a phase */ + int context; /* Other context information */ + void *ptr; /* Decoder-specific stuff (stack elements) */ + ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ + } asn_struct_ctx_t; -#include /* Basic Encoding Rules decoder */ -#include /* Distinguished Encoding Rules encoder */ -#include /* Decoder of XER (XML, text) */ -#include /* Encoder into XER (XML, text) */ -#include /* Packet Encoding Rules decoder */ -#include /* Packet Encoding Rules encoder */ -#include /* Subtype constraints support */ +#include /* Basic Encoding Rules decoder */ +#include /* Distinguished Encoding Rules encoder */ +#include /* Decoder of XER (XML, text) */ +#include /* Encoder into XER (XML, text) */ +#include /* Packet Encoding Rules decoder */ +#include /* Packet Encoding Rules encoder */ +#include /* Subtype constraints support */ -/* + /* * Free the structure according to its specification. * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) * will not be freed. (It may be useful in case the structure is allocated * statically or arranged on the stack, yet its elements are allocated * dynamically.) */ -typedef void (asn_struct_free_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, int free_contents_only); -#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) -#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ - (asn_DEF).free_struct(&(asn_DEF),ptr,1) + typedef void(asn_struct_free_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, int free_contents_only); +#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF), ptr, 0) +#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ + (asn_DEF).free_struct(&(asn_DEF), ptr, 1) -/* + /* * Print the structure according to its specification. */ -typedef int (asn_struct_print_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, - int level, /* Indentation level */ - asn_app_consume_bytes_f *callback, void *app_key); + typedef int(asn_struct_print_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + int level, /* Indentation level */ + asn_app_consume_bytes_f *callback, void *app_key); -/* + /* * Return the outmost tag of the type. * If the type is untagged CHOICE, the dynamic operation is performed. * NOTE: This function pointer type is only useful internally. * Do not use it in your application. */ -typedef ber_tlv_tag_t (asn_outmost_tag_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); -/* The instance of the above function type; used internally. */ -asn_outmost_tag_f asn_TYPE_outmost_tag; + typedef ber_tlv_tag_t(asn_outmost_tag_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); + /* The instance of the above function type; used internally. */ + asn_outmost_tag_f asn_TYPE_outmost_tag; - -/* + + /* * The definitive description of the destination language's structure. */ -typedef struct asn_TYPE_descriptor_s { - char *name; /* A name of the ASN.1 type. "" in some cases. */ - char *xml_tag; /* Name used in XML tag */ + typedef struct asn_TYPE_descriptor_s + { + char *name; /* A name of the ASN.1 type. "" in some cases. */ + char *xml_tag; /* Name used in XML tag */ - /* + /* * Generalized functions for dealing with the specific type. * May be directly invoked by applications. */ - asn_struct_free_f *free_struct; /* Free the structure */ - asn_struct_print_f *print_struct; /* Human readable output */ - asn_constr_check_f *check_constraints; /* Constraints validator */ - ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ - der_type_encoder_f *der_encoder; /* Canonical DER encoder */ - xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ - xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ - per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ - per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ + asn_struct_free_f *free_struct; /* Free the structure */ + asn_struct_print_f *print_struct; /* Human readable output */ + asn_constr_check_f *check_constraints; /* Constraints validator */ + ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ + der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ - /*********************************************************************** + /*********************************************************************** * Internally useful members. Not to be used by applications directly. * **********************************************************************/ - /* + /* * Tags that are expected to occur. */ - asn_outmost_tag_f *outmost_tag; /* */ - ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ - int tags_count; /* Number of tags which are expected */ - ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ - int all_tags_count; /* Number of tags */ + asn_outmost_tag_f *outmost_tag; /* */ + ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + int tags_count; /* Number of tags which are expected */ + ber_tlv_tag_t *all_tags; /* Every tag for BER/containment */ + int all_tags_count; /* Number of tags */ - asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ - /* + /* * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). */ - struct asn_TYPE_member_s *elements; - int elements_count; + struct asn_TYPE_member_s *elements; + int elements_count; - /* + /* * Additional information describing the type, used by appropriate * functions above. */ - void *specifics; -} asn_TYPE_descriptor_t; + void *specifics; + } asn_TYPE_descriptor_t; -/* + /* * This type describes an element of the constructed type, * i.e. SEQUENCE, SET, CHOICE, etc. */ - enum asn_TYPE_flags_e { - ATF_NOFLAGS, - ATF_POINTER = 0x01, /* Represented by the pointer */ - ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ - }; -typedef struct asn_TYPE_member_s { - enum asn_TYPE_flags_e flags; /* Element's presentation flags */ - int optional; /* Following optional members, including current */ - int memb_offset; /* Offset of the element */ - ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ - int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ - asn_TYPE_descriptor_t *type; /* Member type descriptor */ - asn_constr_check_f *memb_constraints; /* Constraints validator */ - asn_per_constraints_t *per_constraints; /* PER compiled constraints */ - int (*default_value)(int setval, void **sptr); /* DEFAULT */ - char *name; /* ASN.1 identifier of the element */ -} asn_TYPE_member_t; + enum asn_TYPE_flags_e + { + ATF_NOFLAGS, + ATF_POINTER = 0x01, /* Represented by the pointer */ + ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ + }; + typedef struct asn_TYPE_member_s + { + enum asn_TYPE_flags_e flags; /* Element's presentation flags */ + int optional; /* Following optional members, including current */ + int memb_offset; /* Offset of the element */ + ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ + int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ + asn_TYPE_descriptor_t *type; /* Member type descriptor */ + asn_constr_check_f *memb_constraints; /* Constraints validator */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + int (*default_value)(int setval, void **sptr); /* DEFAULT */ + char *name; /* ASN.1 identifier of the element */ + } asn_TYPE_member_t; -/* + /* * BER tag to element number mapping. */ -typedef struct asn_TYPE_tag2member_s { - ber_tlv_tag_t el_tag; /* Outmost tag of the member */ - int el_no; /* Index of the associated member, base 0 */ - int toff_first; /* First occurence of the el_tag, relative */ - int toff_last; /* Last occurence of the el_tag, relatvie */ -} asn_TYPE_tag2member_t; + typedef struct asn_TYPE_tag2member_s + { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + int el_no; /* Index of the associated member, base 0 */ + int toff_first; /* First occurence of the el_tag, relative */ + int toff_last; /* Last occurence of the el_tag, relatvie */ + } asn_TYPE_tag2member_t; -/* + /* * This function is a wrapper around (td)->print_struct, which prints out * the contents of the target language's structure (struct_ptr) into the * file pointer (stream) in human readable form. @@ -169,12 +175,12 @@ typedef struct asn_TYPE_tag2member_s { * -1: Problem dumping the structure. * (See also xer_fprint() in xer_encoder.h) */ -int asn_fprint(FILE *stream, /* Destination stream descriptor */ - asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ - const void *struct_ptr); /* Structure to be printed */ + int asn_fprint(FILE *stream, /* Destination stream descriptor */ + asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ + const void *struct_ptr); /* Structure to be printed */ #ifdef __cplusplus } #endif -#endif /* _CONSTR_TYPE_H_ */ +#endif /* _CONSTR_TYPE_H_ */ diff --git a/src/core/libs/supl/asn-supl/constraints.h b/src/core/libs/supl/asn-supl/constraints.h index 5032345ee..bc4fdb938 100644 --- a/src/core/libs/supl/asn-supl/constraints.h +++ b/src/core/libs/supl/asn-supl/constraints.h @@ -2,18 +2,19 @@ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ -#define _ASN1_CONSTRAINTS_VALIDATOR_H_ +#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ +#define _ASN1_CONSTRAINTS_VALIDATOR_H_ -#include /* Platform-dependent types */ +#include /* Platform-dependent types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Validate the structure according to the ASN.1 constraints. * If errbuf and errlen are given, they shall be pointing to the appropriate * buffer space and its length before calling this function. Alternatively, @@ -25,39 +26,39 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ * This function returns 0 in case all ASN.1 constraints are met * and -1 if one or more constraints were failed. */ -int -asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, /* Target language's structure */ - char *errbuf, /* Returned error description */ - size_t *errlen /* Length of the error description */ - ); + int asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Target language's structure */ + char *errbuf, /* Returned error description */ + size_t *errlen /* Length of the error description */ + ); -/* + /* * Generic type for constraint checking callback, * associated with every type descriptor. */ -typedef int (asn_constr_check_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - const void *struct_ptr, - asn_app_constraint_failed_f *optional_callback, /* Log the error */ - void *optional_app_key /* Opaque key passed to a callback */ - ); + typedef int(asn_constr_check_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *optional_callback, /* Log the error */ + void *optional_app_key /* Opaque key passed to a callback */ + ); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ -asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ + asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ + asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ /* * Invoke the callback with a complete error message. */ -#define _ASN_CTFAIL if(ctfailcb) ctfailcb +#define _ASN_CTFAIL \ + if (ctfailcb) ctfailcb #ifdef __cplusplus } #endif -#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ +#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ diff --git a/src/core/libs/supl/asn-supl/der_encoder.h b/src/core/libs/supl/asn-supl/der_encoder.h index 61431c6db..3eafbc281 100644 --- a/src/core/libs/supl/asn-supl/der_encoder.h +++ b/src/core/libs/supl/asn-supl/der_encoder.h @@ -2,67 +2,67 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _DER_ENCODER_H_ -#define _DER_ENCODER_H_ +#ifndef _DER_ENCODER_H_ +#define _DER_ENCODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * The DER encoder of any type. May be invoked by the application. * The ber_decode() function (ber_decoder.h) is an opposite of der_encode(). */ -asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key /* Arbitrary callback argument */ - ); + asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); -/* A variant of der_encode() which encodes data into the pre-allocated buffer */ -asn_enc_rval_t der_encode_to_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - void *buffer, /* Pre-allocated buffer */ - size_t buffer_size /* Initial buffer size (maximum) */ - ); + /* A variant of der_encode() which encodes data into the pre-allocated buffer */ + asn_enc_rval_t der_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ + ); -/* + /* * Type of the generic DER encoder. */ -typedef asn_enc_rval_t (der_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - ber_tlv_tag_t tag, - asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ - void *app_key /* Arbitrary callback argument */ - ); + typedef asn_enc_rval_t(der_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Write out leading TL[v] sequence according to the type definition. */ -ssize_t der_write_tags( - struct asn_TYPE_descriptor_s *type_descriptor, - size_t struct_length, - int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ - int last_tag_form, /* {0,!0}: prim, constructed */ - ber_tlv_tag_t tag, - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key - ); + ssize_t der_write_tags( + struct asn_TYPE_descriptor_s *type_descriptor, + size_t struct_length, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {0,!0}: prim, constructed */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key); #ifdef __cplusplus } #endif -#endif /* _DER_ENCODER_H_ */ +#endif /* _DER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/per_decoder.h b/src/core/libs/supl/asn-supl/per_decoder.h index 8397a545f..a28509464 100644 --- a/src/core/libs/supl/asn-supl/per_decoder.h +++ b/src/core/libs/supl/asn-supl/per_decoder.h @@ -2,55 +2,55 @@ * Copyright (c) 2005, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_DECODER_H_ -#define _PER_DECODER_H_ +#ifndef _PER_DECODER_H_ +#define _PER_DECODER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Unaligned PER decoder of a "complete encoding" as per X.691#10.1. * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. */ -asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of data buffer */ - ); + asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); -/* + /* * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. * WARNING: This call returns the number of BITS read from the stream. Beware. */ -asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size, /* Size of data buffer */ - int skip_bits, /* Number of unused leading bits, 0..7 */ - int unused_bits /* Number of unused tailing bits, 0..7 */ - ); + asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of data buffer */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); -/* + /* * Type of the type-specific PER decoder function. */ -typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void **struct_ptr, - asn_per_data_t *per_data - ); + typedef asn_dec_rval_t(per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void **struct_ptr, + asn_per_data_t *per_data); #ifdef __cplusplus } #endif -#endif /* _PER_DECODER_H_ */ +#endif /* _PER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/per_encoder.c b/src/core/libs/supl/asn-supl/per_encoder.c index f4bace060..8cf95347d 100644 --- a/src/core/libs/supl/asn-supl/per_encoder.c +++ b/src/core/libs/supl/asn-supl/per_encoder.c @@ -2,7 +2,7 @@ #include #include -static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); +static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t * /*constraints*/, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); asn_enc_rval_t uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { diff --git a/src/core/libs/supl/asn-supl/per_encoder.h b/src/core/libs/supl/asn-supl/per_encoder.h index 95a6506e4..896013095 100644 --- a/src/core/libs/supl/asn-supl/per_encoder.h +++ b/src/core/libs/supl/asn-supl/per_encoder.h @@ -2,68 +2,68 @@ * Copyright (c) 2006, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_ENCODER_H_ -#define _PER_ENCODER_H_ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. Use the following formula to convert to bytes: * bytes = ((.encoded + 7) / 8) */ -asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ - void *app_key /* Arbitrary callback argument */ -); + asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ + ); -/* + /* * A variant of uper_encode() which encodes data into the existing buffer * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. */ -asn_enc_rval_t uper_encode_to_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - void *buffer, /* Pre-allocated buffer */ - size_t buffer_size /* Initial buffer size (max) */ -); + asn_enc_rval_t uper_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ + ); -/* + /* * A variant of uper_encode_to_buffer() which allocates buffer itself. * Returns the number of bytes in the buffer or -1 in case of failure. * WARNING: This function produces a "Production of the complete encoding", * with length of at least one octet. Contrast this to precise bit-packing * encoding of uper_encode() and uper_encode_to_buffer(). */ -ssize_t uper_encode_to_new_buffer( - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void *struct_ptr, /* Structure to be encoded */ - void **buffer_r /* Buffer allocated and returned */ -); + ssize_t uper_encode_to_new_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, /* Structure to be encoded */ + void **buffer_r /* Buffer allocated and returned */ + ); -/* + /* * Type of the generic PER encoder function. */ -typedef asn_enc_rval_t (per_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - asn_per_constraints_t *constraints, - void *struct_ptr, - asn_per_outp_t *per_output -); + typedef asn_enc_rval_t(per_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, + asn_per_outp_t *per_output); #ifdef __cplusplus } #endif -#endif /* _PER_ENCODER_H_ */ +#endif /* _PER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/per_opentype.c b/src/core/libs/supl/asn-supl/per_opentype.c index c749c8c6c..32152e132 100644 --- a/src/core/libs/supl/asn-supl/per_opentype.c +++ b/src/core/libs/supl/asn-supl/per_opentype.c @@ -7,16 +7,17 @@ #include #include -typedef struct uper_ugot_key { - asn_per_data_t oldpd; /* Old per data source */ - size_t unclaimed; - size_t ot_moved; /* Number of bits moved by OT processing */ - int repeat; +typedef struct uper_ugot_key +{ + asn_per_data_t oldpd; /* Old per data source */ + size_t unclaimed; + size_t ot_moved; /* Number of bits moved by OT processing */ + int repeat; } uper_ugot_key; static int uper_ugot_refill(asn_per_data_t *pd); static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); -static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); +static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t * /*ctx*/, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); int asn_debug_indent; @@ -24,243 +25,272 @@ int asn_debug_indent; * Encode an "open type field". * #10.1, #10.2 */ -int -uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { - void *buf; - void *bptr; - ssize_t size; - size_t toGo; +int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) +{ + void *buf; + void *bptr; + ssize_t size; + size_t toGo; - ASN_DEBUG("Open type put %s ...", td->name); + ASN_DEBUG("Open type put %s ...", td->name); - size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); - if(size <= 0) return -1; + size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); + if (size <= 0) return -1; - for(bptr = buf, toGo = size; toGo;) { - ssize_t maySave = uper_put_length(po, toGo); - if(maySave < 0) break; - if(per_put_many_bits(po, bptr, maySave * 8)) break; - bptr = (char *)bptr + maySave; - toGo -= maySave; - } + for (bptr = buf, toGo = size; toGo;) + { + ssize_t maySave = uper_put_length(po, toGo); + if (maySave < 0) break; + if (per_put_many_bits(po, bptr, maySave * 8)) break; + bptr = (char *)bptr + maySave; + toGo -= maySave; + } - FREEMEM(buf); - if(toGo) return -1; + FREEMEM(buf); + if (toGo) return -1; - ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", - td->name, size); + ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", + td->name, size); - return 0; + return 0; } static asn_dec_rval_t uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - asn_dec_rval_t rv; - ssize_t chunk_bytes; - int repeat; - uint8_t *buf = 0; - size_t bufLen = 0; - size_t bufSize = 0; - asn_per_data_t spd; - size_t padding; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + asn_dec_rval_t rv; + ssize_t chunk_bytes; + int repeat; + uint8_t *buf = 0; + size_t bufLen = 0; + size_t bufSize = 0; + asn_per_data_t spd; + size_t padding; - _ASN_STACK_OVERFLOW_CHECK(ctx); + _ASN_STACK_OVERFLOW_CHECK(ctx); - ASN_DEBUG("Getting open type %s...", td->name); + ASN_DEBUG("Getting open type %s...", td->name); - do { - chunk_bytes = uper_get_length(pd, -1, &repeat); - if(chunk_bytes < 0) { - FREEMEM(buf); - _ASN_DECODE_STARVED; - } - if(bufLen + chunk_bytes > bufSize) { - void *ptr; - bufSize = chunk_bytes + (bufSize << 2); - ptr = REALLOC(buf, bufSize); - if(!ptr) { - FREEMEM(buf); - _ASN_DECODE_FAILED; - } - buf = ptr; - } - if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { - FREEMEM(buf); - _ASN_DECODE_STARVED; - } - bufLen += chunk_bytes; - } while(repeat); + do + { + chunk_bytes = uper_get_length(pd, -1, &repeat); + if (chunk_bytes < 0) + { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + if (bufLen + chunk_bytes > bufSize) + { + void *ptr; + bufSize = chunk_bytes + (bufSize << 2); + ptr = REALLOC(buf, bufSize); + if (!ptr) + { + FREEMEM(buf); + _ASN_DECODE_FAILED; + } + buf = ptr; + } + if (per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) + { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + bufLen += chunk_bytes; + } + while (repeat); - ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, - bufLen); + ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, + bufLen); - memset(&spd, 0, sizeof(spd)); - spd.buffer = buf; - spd.nbits = bufLen << 3; + memset(&spd, 0, sizeof(spd)); + spd.buffer = buf; + spd.nbits = bufLen << 3; - asn_debug_indent += 4; - rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); - asn_debug_indent -= 4; + asn_debug_indent += 4; + rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); + asn_debug_indent -= 4; - if(rv.code == RC_OK) { - /* Check padding validity */ - padding = spd.nbits - spd.nboff; - if(padding < 8 && per_get_few_bits(&spd, padding) == 0) { - /* Everything is cool */ - FREEMEM(buf); - return rv; - } - FREEMEM(buf); - if(padding >= 8) { - ASN_DEBUG("Too large padding %d in open type", padding); - _ASN_DECODE_FAILED; - } else { - ASN_DEBUG("Non-zero padding"); - _ASN_DECODE_FAILED; - } - } else { - FREEMEM(buf); - /* rv.code could be RC_WMORE, nonsense in this context */ - rv.code = RC_FAIL; /* Noone would give us more */ - } + if (rv.code == RC_OK) + { + /* Check padding validity */ + padding = spd.nbits - spd.nboff; + if (padding < 8 && per_get_few_bits(&spd, padding) == 0) + { + /* Everything is cool */ + FREEMEM(buf); + return rv; + } + FREEMEM(buf); + if (padding >= 8) + { + ASN_DEBUG("Too large padding %d in open type", padding); + _ASN_DECODE_FAILED; + } + else + { + ASN_DEBUG("Non-zero padding"); + _ASN_DECODE_FAILED; + } + } + else + { + FREEMEM(buf); + /* rv.code could be RC_WMORE, nonsense in this context */ + rv.code = RC_FAIL; /* Noone would give us more */ + } - return rv; + return rv; } static asn_dec_rval_t GCC_NOTUSED uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - uper_ugot_key arg; - asn_dec_rval_t rv; - ssize_t padding; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + uper_ugot_key arg; + asn_dec_rval_t rv; + ssize_t padding; - _ASN_STACK_OVERFLOW_CHECK(ctx); + _ASN_STACK_OVERFLOW_CHECK(ctx); - ASN_DEBUG("Getting open type %s from %s", td->name, - per_data_string(pd)); - arg.oldpd = *pd; - arg.unclaimed = 0; - arg.ot_moved = 0; - arg.repeat = 1; - pd->refill = uper_ugot_refill; - pd->refill_key = &arg; - pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ - pd->moved = 0; /* This now counts the open type size in bits */ + ASN_DEBUG("Getting open type %s from %s", td->name, + per_data_string(pd)); + arg.oldpd = *pd; + arg.unclaimed = 0; + arg.ot_moved = 0; + arg.repeat = 1; + pd->refill = uper_ugot_refill; + pd->refill_key = &arg; + pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ + pd->moved = 0; /* This now counts the open type size in bits */ - asn_debug_indent += 4; - rv = td->uper_decoder(ctx, td, constraints, sptr, pd); - asn_debug_indent -= 4; + asn_debug_indent += 4; + rv = td->uper_decoder(ctx, td, constraints, sptr, pd); + asn_debug_indent -= 4; -#define UPDRESTOREPD do { \ - /* buffer and nboff are valid, preserve them. */ \ - pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ - pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ - pd->refill = arg.oldpd.refill; \ - pd->refill_key = arg.oldpd.refill_key; \ - } while(0) +#define UPDRESTOREPD \ + do \ + { \ + /* buffer and nboff are valid, preserve them. */ \ + pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ + pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ + pd->refill = arg.oldpd.refill; \ + pd->refill_key = arg.oldpd.refill_key; \ + } \ + while (0) - if(rv.code != RC_OK) { - UPDRESTOREPD; - return rv; - } + if (rv.code != RC_OK) + { + UPDRESTOREPD; + return rv; + } - ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d" - , td->name, - per_data_string(pd), - per_data_string(&arg.oldpd), - arg.unclaimed, arg.repeat); + ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, + per_data_string(pd), + per_data_string(&arg.oldpd), + arg.unclaimed, arg.repeat); - padding = pd->moved % 8; - if(padding) { - int32_t pvalue; - if(padding > 7) { - ASN_DEBUG("Too large padding %d in open type", - padding); - rv.code = RC_FAIL; - UPDRESTOREPD; - return rv; - } - padding = 8 - padding; - ASN_DEBUG("Getting padding of %d bits", padding); - pvalue = per_get_few_bits(pd, padding); - switch(pvalue) { - case -1: - ASN_DEBUG("Padding skip failed"); - UPDRESTOREPD; - _ASN_DECODE_STARVED; - case 0: break; - default: - ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", - padding, (int)pvalue); - UPDRESTOREPD; - _ASN_DECODE_FAILED; - } - } - if(pd->nboff != pd->nbits) { - ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, - per_data_string(pd), per_data_string(&arg.oldpd)); - if(1) { - UPDRESTOREPD; - _ASN_DECODE_FAILED; - } else { - arg.unclaimed += pd->nbits - pd->nboff; - } - } + padding = pd->moved % 8; + if (padding) + { + int32_t pvalue; + if (padding > 7) + { + ASN_DEBUG("Too large padding %d in open type", + padding); + rv.code = RC_FAIL; + UPDRESTOREPD; + return rv; + } + padding = 8 - padding; + ASN_DEBUG("Getting padding of %d bits", padding); + pvalue = per_get_few_bits(pd, padding); + switch (pvalue) + { + case -1: + ASN_DEBUG("Padding skip failed"); + UPDRESTOREPD; + _ASN_DECODE_STARVED; + case 0: + break; + default: + ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", + padding, (int)pvalue); + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } + } + if (pd->nboff != pd->nbits) + { + ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, + per_data_string(pd), per_data_string(&arg.oldpd)); + if (1) + { + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } + else + { + arg.unclaimed += pd->nbits - pd->nboff; + } + } - /* Adjust pd back so it points to original data */ - UPDRESTOREPD; + /* Adjust pd back so it points to original data */ + UPDRESTOREPD; - /* Skip data not consumed by the decoder */ - if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); - if(arg.unclaimed) { - switch(per_skip_bits(pd, arg.unclaimed)) { - case -1: - ASN_DEBUG("Claim of %d failed", arg.unclaimed); - _ASN_DECODE_STARVED; - case 0: - ASN_DEBUG("Got claim of %d", arg.unclaimed); - break; - default: - /* Padding must be blank */ - ASN_DEBUG("Non-blank unconsumed padding"); - _ASN_DECODE_FAILED; - } - arg.unclaimed = 0; - } + /* Skip data not consumed by the decoder */ + if (arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); + if (arg.unclaimed) + { + switch (per_skip_bits(pd, arg.unclaimed)) + { + case -1: + ASN_DEBUG("Claim of %d failed", arg.unclaimed); + _ASN_DECODE_STARVED; + case 0: + ASN_DEBUG("Got claim of %d", arg.unclaimed); + break; + default: + /* Padding must be blank */ + ASN_DEBUG("Non-blank unconsumed padding"); + _ASN_DECODE_FAILED; + } + arg.unclaimed = 0; + } - if(arg.repeat) { - ASN_DEBUG("Not consumed the whole thing"); - rv.code = RC_FAIL; - return rv; - } + if (arg.repeat) + { + ASN_DEBUG("Not consumed the whole thing"); + rv.code = RC_FAIL; + return rv; + } - return rv; + return rv; } asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - - return uper_open_type_get_simple(ctx, td, constraints, - sptr, pd); - + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + return uper_open_type_get_simple(ctx, td, constraints, + sptr, pd); } -int -uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { - asn_TYPE_descriptor_t s_td; - asn_dec_rval_t rv; +int uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) +{ + asn_TYPE_descriptor_t s_td; + asn_dec_rval_t rv; - s_td.name = ""; - s_td.uper_decoder = uper_sot_suck; + s_td.name = ""; + s_td.uper_decoder = uper_sot_suck; - rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); - if(rv.code != RC_OK) - return -1; - else - return 0; + rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); + if (rv.code != RC_OK) + return -1; + else + return 0; } /* @@ -269,105 +299,122 @@ uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - asn_dec_rval_t rv; + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) +{ + asn_dec_rval_t rv; - (void)ctx; - (void)td; - (void)constraints; - (void)sptr; + (void)ctx; + (void)td; + (void)constraints; + (void)sptr; - while(per_get_few_bits(pd, 24) >= 0); + while (per_get_few_bits(pd, 24) >= 0) + ; - rv.code = RC_OK; - rv.consumed = pd->moved; + rv.code = RC_OK; + rv.consumed = pd->moved; - return rv; + return rv; } static int -uper_ugot_refill(asn_per_data_t *pd) { - uper_ugot_key *arg = pd->refill_key; - ssize_t next_chunk_bytes, next_chunk_bits; - ssize_t avail; +uper_ugot_refill(asn_per_data_t *pd) +{ + uper_ugot_key *arg = pd->refill_key; + ssize_t next_chunk_bytes, next_chunk_bits; + ssize_t avail; - asn_per_data_t *oldpd = &arg->oldpd; + asn_per_data_t *oldpd = &arg->oldpd; - ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", - pd->moved, oldpd->moved); + ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", + pd->moved, oldpd->moved); - /* Advance our position to where pd is */ - oldpd->buffer = pd->buffer; - oldpd->nboff = pd->nboff; - oldpd->nbits -= pd->moved - arg->ot_moved; - oldpd->moved += pd->moved - arg->ot_moved; - arg->ot_moved = pd->moved; + /* Advance our position to where pd is */ + oldpd->buffer = pd->buffer; + oldpd->nboff = pd->nboff; + oldpd->nbits -= pd->moved - arg->ot_moved; + oldpd->moved += pd->moved - arg->ot_moved; + arg->ot_moved = pd->moved; - if(arg->unclaimed) { - /* Refill the container */ - if(per_get_few_bits(oldpd, 1)) - return -1; - if(oldpd->nboff == 0) { - assert(0); - return -1; - } - pd->buffer = oldpd->buffer; - pd->nboff = oldpd->nboff - 1; - pd->nbits = oldpd->nbits; - ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); - return 0; - } + if (arg->unclaimed) + { + /* Refill the container */ + if (per_get_few_bits(oldpd, 1)) + return -1; + if (oldpd->nboff == 0) + { + assert(0); + return -1; + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff - 1; + pd->nbits = oldpd->nbits; + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); + return 0; + } - if(!arg->repeat) { - ASN_DEBUG("Want more but refill doesn't have it"); - return -1; - } + if (!arg->repeat) + { + ASN_DEBUG("Want more but refill doesn't have it"); + return -1; + } - next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); - ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", - next_chunk_bytes, oldpd->moved, arg->repeat); - if(next_chunk_bytes < 0) return -1; - if(next_chunk_bytes == 0) { - pd->refill = 0; /* No more refills, naturally */ - assert(!arg->repeat); /* Implementation guarantee */ - } - next_chunk_bits = next_chunk_bytes << 3; - avail = oldpd->nbits - oldpd->nboff; - if(avail >= next_chunk_bits) { - pd->nbits = oldpd->nboff + next_chunk_bits; - arg->unclaimed = 0; - ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", - next_chunk_bits, oldpd->moved, - oldpd->nboff, oldpd->nbits, - oldpd->nbits - oldpd->nboff); - } else { - pd->nbits = oldpd->nbits; - arg->unclaimed = next_chunk_bits - avail; - ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); - } - pd->buffer = oldpd->buffer; - pd->nboff = oldpd->nboff; - ASN_DEBUG("Refilled pd%s old%s", - per_data_string(pd), per_data_string(oldpd)); - return 0; + next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); + ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", + next_chunk_bytes, oldpd->moved, arg->repeat); + if (next_chunk_bytes < 0) return -1; + if (next_chunk_bytes == 0) + { + pd->refill = 0; /* No more refills, naturally */ + assert(!arg->repeat); /* Implementation guarantee */ + } + next_chunk_bits = next_chunk_bytes << 3; + avail = oldpd->nbits - oldpd->nboff; + if (avail >= next_chunk_bits) + { + pd->nbits = oldpd->nboff + next_chunk_bits; + arg->unclaimed = 0; + ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", + next_chunk_bits, oldpd->moved, + oldpd->nboff, oldpd->nbits, + oldpd->nbits - oldpd->nboff); + } + else + { + pd->nbits = oldpd->nbits; + arg->unclaimed = next_chunk_bits - avail; + ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff; + ASN_DEBUG("Refilled pd%s old%s", + per_data_string(pd), per_data_string(oldpd)); + return 0; } static int -per_skip_bits(asn_per_data_t *pd, int skip_nbits) { - int hasNonZeroBits = 0; - while(skip_nbits > 0) { - int skip; - if(skip_nbits < skip) - skip = skip_nbits; - else - skip = 24; - skip_nbits -= skip; +per_skip_bits(asn_per_data_t *pd, int skip_nbits) +{ + int hasNonZeroBits = 0; + while (skip_nbits > 0) + { + int skip = 0; + if (skip_nbits < skip) + skip = skip_nbits; + else + skip = 24; + skip_nbits -= skip; - switch(per_get_few_bits(pd, skip)) { - case -1: return -1; /* Starving */ - case 0: continue; /* Skipped empty space */ - default: hasNonZeroBits = 1; continue; - } - } - return hasNonZeroBits; + switch (per_get_few_bits(pd, skip)) + { + case -1: + return -1; /* Starving */ + case 0: + continue; /* Skipped empty space */ + default: + hasNonZeroBits = 1; + continue; + } + } + return hasNonZeroBits; } diff --git a/src/core/libs/supl/asn-supl/per_opentype.h b/src/core/libs/supl/asn-supl/per_opentype.h index facfaa637..2110a794a 100644 --- a/src/core/libs/supl/asn-supl/per_opentype.h +++ b/src/core/libs/supl/asn-supl/per_opentype.h @@ -2,21 +2,22 @@ * Copyright (c) 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_OPENTYPE_H_ -#define _PER_OPENTYPE_H_ +#ifndef _PER_OPENTYPE_H_ +#define _PER_OPENTYPE_H_ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); + asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); -int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); + int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); -int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); + int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); #ifdef __cplusplus } #endif -#endif /* _PER_OPENTYPE_H_ */ +#endif /* _PER_OPENTYPE_H_ */ diff --git a/src/core/libs/supl/asn-supl/per_support.c b/src/core/libs/supl/asn-supl/per_support.c index e8299c730..02dd02094 100644 --- a/src/core/libs/supl/asn-supl/per_support.c +++ b/src/core/libs/supl/asn-supl/per_support.c @@ -9,26 +9,26 @@ char * per_data_string(asn_per_data_t *pd) { - static char buf[2][32]; - static int n; - n = (n+1) % 2; - snprintf(buf[n], sizeof(buf), - "{m=%d span %+d[%d..%d] (%d)}", - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, - pd->nbits - pd->nboff); - return buf[n]; + static char buf[2][32]; + static int n; + n = (n+1) % 2; + snprintf(buf[n], sizeof(buf[n]), + "{m=%ld span %+ld[%d..%d] (%d)}", + (long)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + (int)(pd->nbits - pd->nboff)); + return buf[n]; } void per_get_undo(asn_per_data_t *pd, int nbits) { - if((ssize_t)pd->nboff < nbits) { - assert((ssize_t)pd->nboff < nbits); - } else { - pd->nboff -= nbits; - pd->moved -= nbits; - } + if((ssize_t)pd->nboff < nbits) { + assert((ssize_t)pd->nboff < nbits); + } else { + pd->nboff -= nbits; + pd->moved -= nbits; + } } /* @@ -36,83 +36,84 @@ per_get_undo(asn_per_data_t *pd, int nbits) { */ int32_t per_get_few_bits(asn_per_data_t *pd, int nbits) { - size_t off; /* Next after last bit offset */ - ssize_t nleft; /* Number of bits left in this stream */ - uint32_t accum; - const uint8_t *buf; + size_t off; /* Next after last bit offset */ + ssize_t nleft; /* Number of bits left in this stream */ + uint32_t accum; + const uint8_t *buf; - if(nbits < 0) - return -1; + if(nbits < 0) + return -1; - nleft = pd->nbits - pd->nboff; - if(nbits > nleft) { - int32_t tailv, vhead; - if(!pd->refill || nbits > 31) return -1; - /* Accumulate unused bytes before refill */ - ASN_DEBUG("Obtain the rest %d bits (want %d)", nleft, nbits); - tailv = per_get_few_bits(pd, nleft); - if(tailv < 0) return -1; - /* Refill (replace pd contents with new data) */ - if(pd->refill(pd)) - return -1; - nbits -= nleft; - vhead = per_get_few_bits(pd, nbits); - /* Combine the rest of previous pd with the head of new one */ - tailv = (tailv << nbits) | vhead; /* Could == -1 */ - return tailv; - } + nleft = pd->nbits - pd->nboff; + if(nbits > nleft) { + int32_t tailv, vhead; + if(!pd->refill || nbits > 31) return -1; + /* Accumulate unused bytes before refill */ + ASN_DEBUG("Obtain the rest %d bits (want %d)", + (int)nleft, (int)nbits); + tailv = per_get_few_bits(pd, nleft); + if(tailv < 0) return -1; + /* Refill (replace pd contents with new data) */ + if(pd->refill(pd)) + return -1; + nbits -= nleft; + vhead = per_get_few_bits(pd, nbits); + /* Combine the rest of previous pd with the head of new one */ + tailv = (tailv << nbits) | vhead; /* Could == -1 */ + return tailv; + } - /* - * Normalize position indicator. - */ - if(pd->nboff >= 8) { - pd->buffer += (pd->nboff >> 3); - pd->nbits -= (pd->nboff & ~0x07); - pd->nboff &= 0x07; - } - pd->moved += nbits; - pd->nboff += nbits; - off = pd->nboff; - buf = pd->buffer; + /* + * Normalize position indicator. + */ + if(pd->nboff >= 8) { + pd->buffer += (pd->nboff >> 3); + pd->nbits -= (pd->nboff & ~0x07); + pd->nboff &= 0x07; + } + pd->moved += nbits; + pd->nboff += nbits; + off = pd->nboff; + buf = pd->buffer; - /* - * Extract specified number of bits. - */ - if(off <= 8) - accum = nbits ? (buf[0]) >> (8 - off) : 0; - else if(off <= 16) - accum = ((buf[0] << 8) + buf[1]) >> (16 - off); - else if(off <= 24) - accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); - else if(off <= 31) - accum = ((buf[0] << 24) + (buf[1] << 16) - + (buf[2] << 8) + (buf[3])) >> (32 - off); - else if(nbits <= 31) { - asn_per_data_t tpd = *pd; - /* Here are we with our 31-bits limit plus 1..7 bits offset. */ - per_get_undo(&tpd, nbits); - /* The number of available bits in the stream allow - * for the following operations to take place without - * invoking the ->refill() function */ - accum = per_get_few_bits(&tpd, nbits - 24) << 24; - accum |= per_get_few_bits(&tpd, 24); - } else { - per_get_undo(pd, nbits); - return -1; - } + /* + * Extract specified number of bits. + */ + if(off <= 8) + accum = nbits ? (buf[0]) >> (8 - off) : 0; + else if(off <= 16) + accum = ((buf[0] << 8) + buf[1]) >> (16 - off); + else if(off <= 24) + accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); + else if(off <= 31) + accum = ((buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + (buf[3])) >> (32 - off); + else if(nbits <= 31) { + asn_per_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + per_get_undo(&tpd, nbits); + /* The number of available bits in the stream allow + * for the following operations to take place without + * invoking the ->refill() function */ + accum = per_get_few_bits(&tpd, nbits - 24) << 24; + accum |= per_get_few_bits(&tpd, 24); + } else { + per_get_undo(pd, nbits); + return -1; + } - accum &= (((uint32_t)1 << nbits) - 1); + accum &= (((uint32_t)1 << nbits) - 1); - ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+d[%d..%d]:%02x (%d) => 0x%x]", - nbits, nleft, - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, - pd->buffer[0], - pd->nbits - pd->nboff, - (int)accum); + ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", + (int)nbits, (int)nleft, + (int)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + ((pd->buffer != NULL)?pd->buffer[0]:0), + (int)(pd->nbits - pd->nboff), + (int)accum); - return accum; + return accum; } /* @@ -120,70 +121,76 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { */ int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { - int32_t value; + int32_t value; - if(alright && (nbits & 7)) { - /* Perform right alignment of a first few bits */ - value = per_get_few_bits(pd, nbits & 0x07); - if(value < 0) return -1; - *dst++ = value; /* value is already right-aligned */ - nbits &= ~7; - } + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = per_get_few_bits(pd, nbits & 0x07); + if(value < 0) return -1; + *dst++ = value; /* value is already right-aligned */ + nbits &= ~7; + } - while(nbits) { - if(nbits >= 24) { - value = per_get_few_bits(pd, 24); - if(value < 0) return -1; - *(dst++) = value >> 16; - *(dst++) = value >> 8; - *(dst++) = value; - nbits -= 24; - } else { - value = per_get_few_bits(pd, nbits); - if(value < 0) return -1; - if(nbits & 7) { /* implies left alignment */ - value <<= 8 - (nbits & 7), - nbits += 8 - (nbits & 7); - if(nbits > 24) - *dst++ = value >> 24; - } - if(nbits > 16) - *dst++ = value >> 16; - if(nbits > 8) - *dst++ = value >> 8; - *dst++ = value; - break; - } - } + while(nbits) { + if(nbits >= 24) { + value = per_get_few_bits(pd, 24); + if(value < 0) return -1; + *(dst++) = value >> 16; + *(dst++) = value >> 8; + *(dst++) = value; + nbits -= 24; + } else { + value = per_get_few_bits(pd, nbits); + if(value < 0) return -1; + if(nbits & 7) { /* implies left alignment */ + value <<= 8 - (nbits & 7), + nbits += 8 - (nbits & 7); + if(nbits > 24) + *dst++ = value >> 24; + } + if(nbits > 16) + *dst++ = value >> 16; + if(nbits > 8) + *dst++ = value >> 8; + *dst++ = value; + break; + } + } - return 0; + return 0; } /* - * Get the length "n" from the stream. + * X.691-201508 #10.9 General rules for encoding a length determinant. + * Get the optionally constrained length "n" from the stream. */ ssize_t uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { - ssize_t value; + ssize_t value; - *repeat = 0; + *repeat = 0; - if(ebits >= 0) return per_get_few_bits(pd, ebits); + /* #11.9.4.1 Encoding if constrained (according to effective bits) */ + if(ebits >= 0 && ebits <= 16) { + return per_get_few_bits(pd, ebits); + } - value = per_get_few_bits(pd, 8); - if(value < 0) return -1; - if((value & 128) == 0) /* #10.9.3.6 */ - return (value & 0x7F); - if((value & 64) == 0) { /* #10.9.3.7 */ - value = ((value & 63) << 8) | per_get_few_bits(pd, 8); - if(value < 0) return -1; - return value; - } - value &= 63; /* this is "m" from X.691, #10.9.3.8 */ - if(value < 1 || value > 4) - return -1; - *repeat = 1; - return (16384 * value); + value = per_get_few_bits(pd, 8); + if((value & 0x80) == 0) { /* #11.9.3.6 */ + return (value & 0x7F); + } else if((value & 0x40) == 0) { /* #11.9.3.7 */ + /* bit 8 ... set to 1 and bit 7 ... set to zero */ + value = ((value & 0x3f) << 8) | per_get_few_bits(pd, 8); + return value; /* potential -1 from per_get_few_bits passes through. */ + } else if(value < 0) { + return -1; + } + value &= 0x3f; /* this is "m" from X.691, #11.9.3.8 */ + if(value < 1 || value > 4) { + return -1; /* Prohibited by #11.9.3.8 */ + } + *repeat = 1; + return (16384 * value); } /* @@ -193,21 +200,21 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { */ ssize_t uper_get_nslength(asn_per_data_t *pd) { - ssize_t length; + ssize_t length; - ASN_DEBUG("Getting normally small length"); + ASN_DEBUG("Getting normally small length"); - if(per_get_few_bits(pd, 1) == 0) { - length = per_get_few_bits(pd, 6) + 1; - if(length <= 0) return -1; - ASN_DEBUG("l=%d", length); - return length; - } else { - int repeat; - length = uper_get_length(pd, -1, &repeat); - if(length >= 0 && !repeat) return length; - return -1; /* Error, or do not support >16K extensions */ - } + if(per_get_few_bits(pd, 1) == 0) { + length = per_get_few_bits(pd, 6) + 1; + if(length <= 0) return -1; + ASN_DEBUG("l=%d", (int)length); + return length; + } else { + int repeat; + length = uper_get_length(pd, -1, &repeat); + if(length >= 0 && !repeat) return length; + return -1; /* Error, or do not support >16K extensions */ + } } /* @@ -216,135 +223,215 @@ uper_get_nslength(asn_per_data_t *pd) { */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd) { - ssize_t value; + ssize_t value; - value = per_get_few_bits(pd, 7); - if(value & 64) { /* implicit (value < 0) */ - value &= 63; - value <<= 2; - value |= per_get_few_bits(pd, 2); - if(value & 128) /* implicit (value < 0) */ - return -1; - if(value == 0) - return 0; - if(value >= 3) - return -1; - value = per_get_few_bits(pd, 8 * value); - return value; - } + value = per_get_few_bits(pd, 7); + if(value & 64) { /* implicit (value < 0) */ + value &= 63; + value <<= 2; + value |= per_get_few_bits(pd, 2); + if(value & 128) /* implicit (value < 0) */ + return -1; + if(value == 0) + return 0; + if(value >= 3) + return -1; + value = per_get_few_bits(pd, 8 * value); + return value; + } - return value; + return value; } /* - * Put the normally small non-negative whole number. - * X.691, #10.6 + * X.691-11/2008, #11.6 + * Encoding of a normally small non-negative whole number */ int uper_put_nsnnwn(asn_per_outp_t *po, int n) { - int bytes; + int bytes; - if(n <= 63) { - if(n < 0) return -1; - return per_put_few_bits(po, n, 7); - } - if(n < 256) - bytes = 1; - else if(n < 65536) - bytes = 2; - else if(n < 256 * 65536) - bytes = 3; - else - return -1; /* This is not a "normally small" value */ - if(per_put_few_bits(po, bytes, 8)) - return -1; + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; - return per_put_few_bits(po, n, 8 * bytes); + return per_put_few_bits(po, n, 8 * bytes); } +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { + unsigned long lhalf; /* Lower half of the number*/ + long half; + + if(nbits <= 31) { + half = per_get_few_bits(pd, nbits); + if(half < 0) return -1; + *out_value = half; + return 0; + } + + if((size_t)nbits > 8 * sizeof(*out_value)) + return -1; /* RANGE */ + + half = per_get_few_bits(pd, 31); + if(half < 0) return -1; + + if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) + return -1; + + *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; + return 0; +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) { + /* + * Assume signed number can be safely coerced into + * unsigned of the same range. + * The following testing code will likely be optimized out + * by compiler if it is true. + */ + unsigned long uvalue1 = ULONG_MAX; + long svalue = uvalue1; + unsigned long uvalue2 = svalue; + assert(uvalue1 == uvalue2); + return uper_put_constrained_whole_number_u(po, v, nbits); +} + +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) { + if(nbits <= 31) { + return per_put_few_bits(po, v, nbits); + } else { + /* Put higher portion first, followed by lower 31-bit */ + if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) + return -1; + return per_put_few_bits(po, v, 31); + } +} + +int +per_put_aligned_flush(asn_per_outp_t *po) { + uint32_t unused_bits = (0x7 & (8 - (po->nboff & 0x07))); + size_t complete_bytes = + (po->buffer ? po->buffer - po->tmpspace : 0) + ((po->nboff + 7) >> 3); + + if(unused_bits) { + po->buffer[po->nboff >> 3] &= ~0 << unused_bits; + } + + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) { + return -1; + } else { + po->buffer = po->tmpspace; + po->nboff = 0; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + return 0; + } +} + /* * Put a small number of bits (<= 31). */ int per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { - size_t off; /* Next after last bit offset */ - size_t omsk; /* Existing last byte meaningful bits mask */ - uint8_t *buf; + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; - if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; - ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", - obits, (int)bits, po->buffer, po->nboff); + ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", + obits, (int)bits, po->buffer, (int)po->nboff); - /* - * Normalize position indicator. - */ - if(po->nboff >= 8) { - po->buffer += (po->nboff >> 3); - po->nbits -= (po->nboff & ~0x07); - po->nboff &= 0x07; - } + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } - /* - * Flush whole-bytes output, if necessary. - */ - if(po->nboff + obits > po->nbits) { - int complete_bytes = (po->buffer - po->tmpspace); - ASN_DEBUG("[PER output %d complete + %d]", - complete_bytes, po->flushed_bytes); - if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) - return -1; - if(po->nboff) - po->tmpspace[0] = po->buffer[0]; - po->buffer = po->tmpspace; - po->nbits = 8 * sizeof(po->tmpspace); - po->flushed_bytes += complete_bytes; - } + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + size_t complete_bytes; + if(!po->buffer) po->buffer = po->tmpspace; + complete_bytes = (po->buffer - po->tmpspace); + ASN_DEBUG("[PER output %ld complete + %ld]", + (long)complete_bytes, (long)po->flushed_bytes); + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + } - /* - * Now, due to sizeof(tmpspace), we are guaranteed large enough space. - */ - buf = po->buffer; - omsk = ~((1 << (8 - po->nboff)) - 1); - off = (po->nboff += obits); + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff + obits); - /* Clear data of debris before meaningful bits */ - bits &= (((uint32_t)1 << obits) - 1); + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); - ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, - (int)bits, (int)bits, - po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, + (int)bits, (int)bits, + (int)po->nboff, (int)off, + buf[0], (int)(omsk&0xff), + (int)(buf[0] & omsk)); - if(off <= 8) /* Completely within 1 byte */ - bits <<= (8 - off), - buf[0] = (buf[0] & omsk) | bits; - else if(off <= 16) - bits <<= (16 - off), - buf[0] = (buf[0] & omsk) | (bits >> 8), - buf[1] = bits; - else if(off <= 24) - bits <<= (24 - off), - buf[0] = (buf[0] & omsk) | (bits >> 16), - buf[1] = bits >> 8, - buf[2] = bits; - else if(off <= 31) - bits <<= (32 - off), - buf[0] = (buf[0] & omsk) | (bits >> 24), - buf[1] = bits >> 16, - buf[2] = bits >> 8, - buf[3] = bits; - else { - ASN_DEBUG("->[PER out split %d]", obits); - per_put_few_bits(po, bits >> 8, 24); - per_put_few_bits(po, bits, obits - 24); - ASN_DEBUG("<-[PER out split %d]", obits); - } + if(off <= 8) /* Completely within 1 byte */ + po->nboff = off, + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + po->nboff = off, + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + po->nboff = off, + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + po->nboff = off, + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + if(per_put_few_bits(po, bits >> (obits - 24), 24)) return -1; + if(per_put_few_bits(po, bits, obits - 24)) return -1; + } - ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", - (int)bits, (int)bits, buf[0], po->buffer - po->tmpspace); + ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", + (int)bits, (int)bits, buf[0], + (long)(po->buffer - po->tmpspace)); - return 0; + return 0; } @@ -354,30 +441,30 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { - while(nbits) { - uint32_t value; + while(nbits) { + uint32_t value; - if(nbits >= 24) { - value = (src[0] << 16) | (src[1] << 8) | src[2]; - src += 3; - nbits -= 24; - if(per_put_few_bits(po, value, 24)) - return -1; - } else { - value = src[0]; - if(nbits > 8) - value = (value << 8) | src[1]; - if(nbits > 16) - value = (value << 8) | src[2]; - if(nbits & 0x07) - value >>= (8 - (nbits & 0x07)); - if(per_put_few_bits(po, value, nbits)) - return -1; - break; - } - } + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(per_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(per_put_few_bits(po, value, nbits)) + return -1; + break; + } + } - return 0; + return 0; } /* @@ -386,18 +473,18 @@ per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { ssize_t uper_put_length(asn_per_outp_t *po, size_t length) { - if(length <= 127) /* #10.9.3.6 */ - return per_put_few_bits(po, length, 8) - ? -1 : (ssize_t)length; - else if(length < 16384) /* #10.9.3.7 */ - return per_put_few_bits(po, length|0x8000, 16) - ? -1 : (ssize_t)length; + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + else if(length < 16384) /* #10.9.3.7 */ + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; - length >>= 14; - if(length > 4) length = 4; + length >>= 14; + if(length > 4) length = 4; - return per_put_few_bits(po, 0xC0 | length, 8) - ? -1 : (ssize_t)(length << 14); + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); } @@ -409,17 +496,16 @@ uper_put_length(asn_per_outp_t *po, size_t length) { int uper_put_nslength(asn_per_outp_t *po, size_t length) { - if(length <= 64) { - /* #10.9.3.4 */ - if(length == 0) return -1; - return per_put_few_bits(po, length-1, 7) ? -1 : 0; - } else { - if(uper_put_length(po, length) != (ssize_t)length) { - /* This might happen in case of >16K extensions */ - return -1; - } - } + if(length <= 64) { + /* #10.9.3.4 */ + if(length == 0) return -1; + return per_put_few_bits(po, length-1, 7) ? -1 : 0; + } else { + if(uper_put_length(po, length) != (ssize_t)length) { + /* This might happen in case of >16K extensions */ + return -1; + } + } - return 0; + return 0; } - diff --git a/src/core/libs/supl/asn-supl/per_support.h b/src/core/libs/supl/asn-supl/per_support.h index 7cb1a0ca3..c99f12291 100644 --- a/src/core/libs/supl/asn-supl/per_support.h +++ b/src/core/libs/supl/asn-supl/per_support.h @@ -3,126 +3,146 @@ * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _PER_SUPPORT_H_ -#define _PER_SUPPORT_H_ +#ifndef _PER_SUPPORT_H_ +#define _PER_SUPPORT_H_ -#include /* Platform-specific types */ +#include /* Platform-specific types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Pre-computed PER constraints. */ -typedef struct asn_per_constraint_s { - enum asn_per_constraint_flags { - APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ - APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ - APC_CONSTRAINED = 0x2, /* Fully constrained */ - APC_EXTENSIBLE = 0x4 /* May have extension */ - } flags; - int range_bits; /* Full number of bits in the range */ - int effective_bits; /* Effective bits */ - long lower_bound; /* "lb" value */ - long upper_bound; /* "ub" value */ -} asn_per_constraint_t; -typedef struct asn_per_constraints_s { - asn_per_constraint_t value; - asn_per_constraint_t size; - int (*value2code)(unsigned int value); - int (*code2value)(unsigned int code); -} asn_per_constraints_t; + typedef const struct asn_per_constraint_s + { + enum asn_per_constraint_flags + { + APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ + APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ + APC_CONSTRAINED = 0x2, /* Fully constrained */ + APC_EXTENSIBLE = 0x4 /* May have extension */ + } flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ + long lower_bound; /* "lb" value */ + long upper_bound; /* "ub" value */ + } asn_per_constraint_t; + typedef const struct asn_per_constraints_s + { + struct asn_per_constraint_s value; + struct asn_per_constraint_s size; + int (*value2code)(unsigned int value); + int (*code2value)(unsigned int code); + } asn_per_constraints_t; -/* + /* * This structure describes a position inside an incoming PER bit stream. */ -typedef struct asn_per_data_s { - const uint8_t *buffer; /* Pointer to the octet stream */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits in the stream */ - size_t moved; /* Number of bits moved through this bit stream */ - int (*refill)(struct asn_per_data_s *); - void *refill_key; -} asn_per_data_t; + typedef struct asn_per_data_s + { + const uint8_t *buffer; /* Pointer to the octet stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ + size_t moved; /* Number of bits moved through this bit stream */ + int (*refill)(struct asn_per_data_s *); + void *refill_key; + } asn_per_data_t; -/* + /* * Extract a small number of bits (<= 31) from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ -int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); + int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); -/* Undo the immediately preceeding "get_few_bits" operation */ -void per_get_undo(asn_per_data_t *per_data, int get_nbits); + /* Undo the immediately preceeding "get_few_bits" operation */ + void per_get_undo(asn_per_data_t *per_data, int get_nbits); -/* + /* * Extract a large number of bits from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ -int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, - int get_nbits); + int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, + int get_nbits); -/* + /* * Get the length "n" from the Unaligned PER stream. */ -ssize_t uper_get_length(asn_per_data_t *pd, - int effective_bound_bits, - int *repeat); + ssize_t uper_get_length(asn_per_data_t *pd, + int effective_bound_bits, + int *repeat); -/* + /* * Get the normally small length "n". */ -ssize_t uper_get_nslength(asn_per_data_t *pd); + ssize_t uper_get_nslength(asn_per_data_t *pd); -/* + /* * Get the normally small non-negative whole number. */ -ssize_t uper_get_nsnnwn(asn_per_data_t *pd); + ssize_t uper_get_nsnnwn(asn_per_data_t *pd); -/* Non-thread-safe debugging function, don't use it */ -char *per_data_string(asn_per_data_t *pd); + /* X.691-2008/11, #11.5.6 */ + int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); -/* + /* Non-thread-safe debugging function, don't use it */ + char *per_data_string(asn_per_data_t *pd); + + /* * This structure supports forming PER output. */ -typedef struct asn_per_outp_s { - uint8_t *buffer; /* Pointer into the (tmpspace) */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits left in (tmpspace) */ - uint8_t tmpspace[32]; /* Preliminary storage to hold data */ - int (*outper)(const void *data, size_t size, void *op_key); - void *op_key; /* Key for (outper) data callback */ - size_t flushed_bytes; /* Bytes already flushed through (outper) */ -} asn_per_outp_t; + typedef struct asn_per_outp_s + { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*outper)(const void *data, size_t size, void *op_key); + void *op_key; /* Key for (outper) data callback */ + size_t flushed_bytes; /* Bytes already flushed through (outper) */ + } asn_per_outp_t; -/* Output a small number of bits (<= 31) */ -int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); + /* Output a small number of bits (<= 31) */ + int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); -/* Output a large number of bits */ -int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + /* Output a large number of bits */ + int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); -/* + /* + * Flush whole bytes (0 or more) through (outper) member. + * The least significant bits which are not used are guaranteed to be set to 0. + * Returns -1 if callback returns -1. Otherwise, 0. + */ + int per_put_aligned_flush(asn_per_outp_t *po); + + /* X.691-2008/11, #11.5 */ + int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); + int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); + + /* * Put the length "n" to the Unaligned PER stream. * This function returns the number of units which may be flushed * in the next units saving iteration. */ -ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); -/* + /* * Put the normally small length "n" to the Unaligned PER stream. * Returns 0 or -1. */ -int uper_put_nslength(asn_per_outp_t *po, size_t length); + int uper_put_nslength(asn_per_outp_t *po, size_t length); -/* + /* * Put the normally small non-negative whole number. */ -int uper_put_nsnnwn(asn_per_outp_t *po, int n); + int uper_put_nsnnwn(asn_per_outp_t *po, int n); #ifdef __cplusplus } #endif -#endif /* _PER_SUPPORT_H_ */ +#endif /* _PER_SUPPORT_H_ */ diff --git a/src/core/libs/supl/asn-supl/xer_decoder.c b/src/core/libs/supl/asn-supl/xer_decoder.c index 161dc78ce..ef5f06481 100644 --- a/src/core/libs/supl/asn-supl/xer_decoder.c +++ b/src/core/libs/supl/asn-supl/xer_decoder.c @@ -181,12 +181,12 @@ xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { #define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ ssize_t converted_size = body_receiver \ (struct_key, chunk_buf, chunk_size, \ - (size_t)chunk_size < size); \ + (size_t)(chunk_size) < (size)); \ if(converted_size == -1) RETURN(RC_FAIL); \ if(converted_size == 0 \ - && size == (size_t)chunk_size) \ + && (size) == (size_t)(chunk_size)) \ RETURN(RC_WMORE); \ - chunk_size = converted_size; \ + (chunk_size) = converted_size; \ } while(0) #define XER_GOT_EMPTY() do { \ if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ diff --git a/src/core/libs/supl/asn-supl/xer_decoder.h b/src/core/libs/supl/asn-supl/xer_decoder.h index cf0d846fe..52444af51 100644 --- a/src/core/libs/supl/asn-supl/xer_decoder.h +++ b/src/core/libs/supl/asn-supl/xer_decoder.h @@ -2,105 +2,104 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_DECODER_H_ -#define _XER_DECODER_H_ +#ifndef _XER_DECODER_H_ +#define _XER_DECODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* + /* * The XER decoder of any ASN.1 type. May be invoked by the application. */ -asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, /* Pointer to a target structure's pointer */ - const void *buffer, /* Data to be decoded */ - size_t size /* Size of data buffer */ - ); + asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); -/* + /* * Type of the type-specific XER decoder function. */ -typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, - struct asn_TYPE_descriptor_s *type_descriptor, - void **struct_ptr, - const char *opt_mname, /* Member name */ - const void *buf_ptr, size_t size - ); + typedef asn_dec_rval_t(xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, + const char *opt_mname, /* Member name */ + const void *buf_ptr, size_t size); -/******************************* + /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ -/* + /* * Generalized function for decoding the primitive values. * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 * and others. This function should not be used by applications, as its API * is subject to changes. */ -asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, - asn_struct_ctx_t *ctx, /* Type decoder context */ - void *struct_key, /* Treated as opaque pointer */ - const char *xml_tag, /* Expected XML tag name */ - const void *buf_ptr, size_t size, - int (*opt_unexpected_tag_decoder) - (void *struct_key, const void *chunk_buf, size_t chunk_size), - ssize_t (*body_receiver) - (void *struct_key, const void *chunk_buf, size_t chunk_size, - int have_more) - ); + asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, /* Treated as opaque pointer */ + const char *xml_tag, /* Expected XML tag name */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder)(void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver)(void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more)); -/* + /* * Fetch the next XER (XML) token from the stream. * The function returns the number of bytes occupied by the chunk type, * returned in the _ch_type. The _ch_type is only set (and valid) when * the return value is greater than 0. */ - typedef enum pxer_chunk_type { - PXER_TAG, /* Complete XER tag */ - PXER_TEXT, /* Plain text between XER tags */ - PXER_COMMENT /* A comment, may be part of */ - } pxer_chunk_type_e; -ssize_t xer_next_token(int *stateContext, - const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); + typedef enum pxer_chunk_type + { + PXER_TAG, /* Complete XER tag */ + PXER_TEXT, /* Plain text between XER tags */ + PXER_COMMENT /* A comment, may be part of */ + } pxer_chunk_type_e; + ssize_t xer_next_token(int *stateContext, + const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); -/* + /* * This function checks the buffer against the tag name is expected to occur. */ - typedef enum xer_check_tag { - XCT_BROKEN = 0, /* The tag is broken */ - XCT_OPENING = 1, /* This is the tag */ - XCT_CLOSING = 2, /* This is the tag */ - XCT_BOTH = 3, /* This is the tag */ - XCT__UNK__MASK = 4, /* Mask of everything unexpected */ - XCT_UNKNOWN_OP = 5, /* Unexpected tag */ - XCT_UNKNOWN_CL = 6, /* Unexpected tag */ - XCT_UNKNOWN_BO = 7 /* Unexpected tag */ - } xer_check_tag_e; -xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, - const char *need_tag); + typedef enum xer_check_tag + { + XCT_BROKEN = 0, /* The tag is broken */ + XCT_OPENING = 1, /* This is the tag */ + XCT_CLOSING = 2, /* This is the tag */ + XCT_BOTH = 3, /* This is the tag */ + XCT__UNK__MASK = 4, /* Mask of everything unexpected */ + XCT_UNKNOWN_OP = 5, /* Unexpected tag */ + XCT_UNKNOWN_CL = 6, /* Unexpected tag */ + XCT_UNKNOWN_BO = 7 /* Unexpected tag */ + } xer_check_tag_e; + xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, + const char *need_tag); -/* + /* * Check whether this buffer consists of entirely XER whitespace characters. * RETURN VALUES: * 1: Whitespace or empty string * 0: Non-whitespace */ -int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); + int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); -/* + /* * Skip the series of anticipated extensions. */ -int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); + int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); #ifdef __cplusplus } #endif -#endif /* _XER_DECODER_H_ */ +#endif /* _XER_DECODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/xer_encoder.h b/src/core/libs/supl/asn-supl/xer_encoder.h index 055e73c0c..5b640d425 100644 --- a/src/core/libs/supl/asn-supl/xer_encoder.h +++ b/src/core/libs/supl/asn-supl/xer_encoder.h @@ -2,35 +2,37 @@ * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_ENCODER_H_ -#define _XER_ENCODER_H_ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct asn_TYPE_descriptor_s; /* Forward declaration */ + struct asn_TYPE_descriptor_s; /* Forward declaration */ -/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ -enum xer_encoder_flags_e { - /* Mode of encoding */ - XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ - XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ -}; + /* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ + enum xer_encoder_flags_e + { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ + }; -/* + /* * The XER encoder of any type. May be invoked by the application. */ -asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key /* Arbitrary callback argument */ - ); + asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); -/* + /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen file pointer. * RETURN VALUES: @@ -38,22 +40,22 @@ asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, * -1: Problem printing the structure. * WARNING: No sensible errno value is returned. */ -int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); + int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); -/* + /* * Type of the generic XER encoder. */ -typedef asn_enc_rval_t (xer_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - int ilevel, /* Level of indentation */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ - void *app_key /* Arbitrary callback argument */ - ); + typedef asn_enc_rval_t(xer_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); #ifdef __cplusplus } #endif -#endif /* _XER_ENCODER_H_ */ +#endif /* _XER_ENCODER_H_ */ diff --git a/src/core/libs/supl/asn-supl/xer_support.c b/src/core/libs/supl/asn-supl/xer_support.c index 9e34e6923..cfa30e674 100644 --- a/src/core/libs/supl/asn-supl/xer_support.c +++ b/src/core/libs/supl/asn-supl/xer_support.c @@ -60,7 +60,7 @@ _charclass[256] = { #define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ int _ret; \ pstate_e ns = _ns; \ - ssize_t _sz = (p - chunk_start) + _current_too; \ + ssize_t _sz = (p - chunk_start) + (_current_too); \ if (!_sz) { \ /* Shortcut */ \ state = _ns; \ @@ -68,11 +68,11 @@ _charclass[256] = { } \ _ret = cb(type, chunk_start, _sz, key); \ if(_ret < _sz) { \ - if(_current_too && _ret == -1) \ + if((_current_too) && _ret == -1) \ state = ns; \ goto finish; \ } \ - chunk_start = p + _current_too; \ + chunk_start = p + (_current_too); \ state = ns; \ } while(0) diff --git a/src/core/libs/supl/asn-supl/xer_support.h b/src/core/libs/supl/asn-supl/xer_support.h index 8b01944ab..13d8bbd06 100644 --- a/src/core/libs/supl/asn-supl/xer_support.h +++ b/src/core/libs/supl/asn-supl/xer_support.h @@ -3,31 +3,33 @@ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#ifndef _XER_SUPPORT_H_ -#define _XER_SUPPORT_H_ +#ifndef _XER_SUPPORT_H_ +#define _XER_SUPPORT_H_ -#include /* Platform-specific types */ +#include /* Platform-specific types */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* + /* * Types of data transferred to the application. */ -typedef enum { - PXML_TEXT, /* Plain text between XML tags. */ - PXML_TAG, /* A tag, starting with '<'. */ - PXML_COMMENT, /* An XML comment, including "". */ - /* + typedef enum + { + PXML_TEXT, /* Plain text between XML tags. */ + PXML_TAG, /* A tag, starting with '<'. */ + PXML_COMMENT, /* An XML comment, including "". */ + /* * The following chunk types are reported if the chunk * terminates the specified XML element. */ - PXML_TAG_END, /* Tag ended */ - PXML_COMMENT_END /* Comment ended */ -} pxml_chunk_type_e; + PXML_TAG_END, /* Tag ended */ + PXML_COMMENT_END /* Comment ended */ + } pxml_chunk_type_e; -/* + /* * Callback function that is called by the parser when parsed data is * available. The _opaque is the pointer to a field containing opaque user * data specified in pxml_create() call. The chunk type is _type and the text @@ -35,21 +37,21 @@ typedef enum { * pxml_feed() call) starting at offset _offset and of _size bytes size. * The chunk is NOT '\0'-terminated. */ -typedef int (pxml_callback_f)(pxml_chunk_type_e _type, - const void *_chunk_data, size_t _chunk_size, void *_key); + typedef int(pxml_callback_f)(pxml_chunk_type_e _type, + const void *_chunk_data, size_t _chunk_size, void *_key); -/* + /* * Parse the given buffer as it were a chunk of XML data. * Invoke the specified callback each time the meaninful data is found. * This function returns number of bytes consumed from the bufer. * It will always be lesser than or equal to the specified _size. * The next invocation of this function must account the difference. */ -ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, - pxml_callback_f *cb, void *_key); + ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, + pxml_callback_f *cb, void *_key); #ifdef __cplusplus } #endif -#endif /* _XER_SUPPORT_H_ */ +#endif /* _XER_SUPPORT_H_ */ diff --git a/src/core/libs/supl/supl.c b/src/core/libs/supl/supl.c index 1ab843ead..3722d1af0 100644 --- a/src/core/libs/supl/supl.c +++ b/src/core/libs/supl/supl.c @@ -211,21 +211,21 @@ int EXPORT supl_decode_rrlp(supl_ulp_t *ulp_pdu, PDU_t **ret_rrlp) { ret_rrlp = 0; return E_SUPL_DECODE_RRLP; } - + return E_SUPL_INTERNAL; } - + int EXPORT supl_server_connect(supl_ctx_t *ctx, char *server) { int err; - const SSL_METHOD *meth; + SSL_METHOD *meth; SSLeay_add_ssl_algorithms(); // meth = TLSv1_client_method(); - meth = SSLv23_client_method(); + meth = (SSL_METHOD*)SSLv23_client_method(); SSL_load_error_strings(); ctx->ssl_ctx = SSL_CTX_new(meth); if (!ctx->ssl_ctx) return E_SUPL_CONNECT; - + ctx->ssl = SSL_new(ctx->ssl_ctx); if (!ctx->ssl) return E_SUPL_CONNECT; @@ -242,13 +242,13 @@ int EXPORT supl_server_connect(supl_ctx_t *ctx, char *server) { { X509 *s_cert = SSL_get_peer_certificate(ctx->ssl); FILE *fp = fopen("/tmp/s_cert.pem", "w"); - if (fp) + if (fp) PEM_write_X509(fp, s_cert); fclose(fp); X509_free(s_cert); } #endif - + return 0; } @@ -315,15 +315,15 @@ static int pdu_make_ulp_start(supl_ctx_t *ctx, supl_ulp_t *pdu) { ulp->message.choice.msSUPLSTART.sETCapabilities.posProtocol.rrlp = 1; if (ctx->p.set & PARAM_GSM_CELL_CURRENT) { - ulp->message.choice.msSUPLSTART.locationId.cellInfo.present = CellInfo_PR_gsmCell; + ulp->message.choice.msSUPLSTART.locationId.cellInfo.present = CellInfo_PR_gsmCell; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.refMCC = ctx->p.gsm.mcc; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.refMNC = ctx->p.gsm.mnc; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.refLAC = ctx->p.gsm.lac; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.refCI = ctx->p.gsm.ci; - ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.nMR = OPTIONAL_MISSING; - ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.tA = OPTIONAL_MISSING; + ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.nMR = OPTIONAL_MISSING; + ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.gsmCell.tA = OPTIONAL_MISSING; } else if (ctx->p.set & PARAM_WCDMA_CELL_CURRENT) { - ulp->message.choice.msSUPLSTART.locationId.cellInfo.present = CellInfo_PR_wcdmaCell; + ulp->message.choice.msSUPLSTART.locationId.cellInfo.present = CellInfo_PR_wcdmaCell; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.wcdmaCell.refMCC = ctx->p.wcdma.mcc; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.wcdmaCell.refMNC = ctx->p.wcdma.mnc; ulp->message.choice.msSUPLSTART.locationId.cellInfo.choice.wcdmaCell.refUC = ctx->p.wcdma.uc; @@ -447,15 +447,15 @@ static int pdu_make_ulp_pos_init(supl_ctx_t *ctx, supl_ulp_t *pdu) { ulp->message.choice.msSUPLPOSINIT.requestedAssistData = req_adata; if (ctx->p.set & PARAM_GSM_CELL_CURRENT) { - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.present = CellInfo_PR_gsmCell; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.present = CellInfo_PR_gsmCell; ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refMCC = ctx->p.gsm.mcc; ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refMNC = ctx->p.gsm.mnc; - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refLAC = ctx->p.gsm.lac; - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refCI = ctx->p.gsm.ci; - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.nMR = OPTIONAL_MISSING; - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.tA = OPTIONAL_MISSING; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refLAC = ctx->p.gsm.lac; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.refCI = ctx->p.gsm.ci; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.nMR = OPTIONAL_MISSING; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.gsmCell.tA = OPTIONAL_MISSING; } else if (ctx->p.set & PARAM_WCDMA_CELL_CURRENT) { - ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.present = CellInfo_PR_wcdmaCell; + ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.present = CellInfo_PR_wcdmaCell; ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.wcdmaCell.refMCC = ctx->p.wcdma.mcc; ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.wcdmaCell.refMNC = ctx->p.wcdma.mnc; ulp->message.choice.msSUPLPOSINIT.locationId.cellInfo.choice.wcdmaCell.refUC = ctx->p.wcdma.uc; @@ -512,7 +512,7 @@ static int pdu_make_ulp_rrlp_ack(supl_ctx_t *ctx, supl_ulp_t *pdu, PDU_t *rrlp) rrlp_ack->referenceNumber = rrlp->referenceNumber; rrlp_ack->component.present = RRLP_Component_PR_assistanceDataAck; - + ret = uper_encode_to_buffer(&asn_DEF_PDU, rrlp_ack, buffer, sizeof(buffer)); asn_DEF_ULP_PDU.free_struct(&asn_DEF_PDU, rrlp_ack, 0); if (ret.encoded == -1) { @@ -524,12 +524,12 @@ static int pdu_make_ulp_rrlp_ack(supl_ctx_t *ctx, supl_ulp_t *pdu, PDU_t *rrlp) ulp = calloc(1, sizeof(ULP_PDU_t)); session_id = calloc(1, sizeof(SetSessionID_t)); - + ulp->length = 0; ulp->version.maj = 1; ulp->version.min = 0; ulp->version.servind = 0; - + session_id->sessionId = 1; // session_id->setId.present = SETId_PR_msisdn; // (void)OCTET_STRING_fromBuf(&session_id->setId.choice.msisdn, ctx->p.msisdn, 8); @@ -594,7 +594,7 @@ int EXPORT supl_collect_rrlp(supl_assist_t *assist, PDU_t *rrlp, struct timeval loc->buf[3]; if (loc->buf[1] & 0x80) l *= -1; lat = 90.0 / (1 << 23) * l; - + l = (loc->buf[4] << 16) | (loc->buf[5] << 8) | loc->buf[6]; @@ -612,7 +612,7 @@ int EXPORT supl_collect_rrlp(supl_assist_t *assist, PDU_t *rrlp, struct timeval assist->pos.uncertainty = l; } } - + if (hdr->acquisAssist) { int n; @@ -825,7 +825,7 @@ int EXPORT supl_get_assist(supl_ctx_t *ctx, char *server, supl_assist_t *assist) supl_response_harvest(ctx, &ulp); supl_ulp_free(&ulp); - + /* ** send SUPL_POS_INIT */ @@ -949,4 +949,3 @@ void EXPORT supl_set_debug(FILE *log, int flags) { if (flags & SUPL_DEBUG_DEBUG) debug.debug = 1; #endif } - diff --git a/src/core/libs/supl/supl.h b/src/core/libs/supl/supl.h index 1a9352b09..fc64e1ecd 100644 --- a/src/core/libs/supl/supl.h +++ b/src/core/libs/supl/supl.h @@ -17,7 +17,7 @@ #else #define EXPORT #endif - +// clang-format off #if USE_OPENSSL_FALLBACK #include #include @@ -31,7 +31,7 @@ #include #include #endif - +// clang-format on #include #include @@ -75,149 +75,163 @@ #define MAX_EPHEMERIS 32 -struct supl_acquis_s { - u_int8_t prn; - u_int8_t parts; - int16_t doppler0; - int8_t doppler1; - u_int8_t d_win; - u_int16_t code_ph; - u_int8_t code_ph_int; - u_int8_t bit_num; - u_int16_t code_ph_win; - u_int8_t az; - u_int8_t el; - u_int8_t fill[2]; +struct supl_acquis_s +{ + u_int8_t prn; + u_int8_t parts; + int16_t doppler0; + int8_t doppler1; + u_int8_t d_win; + u_int16_t code_ph; + u_int8_t code_ph_int; + u_int8_t bit_num; + u_int16_t code_ph_win; + u_int8_t az; + u_int8_t el; + u_int8_t fill[2]; }; -struct supl_almanac_s { - u_int8_t prn; - u_int16_t e; - u_int8_t toa; - int16_t Ksii; - int16_t OMEGA_dot; - u_int32_t A_sqrt; - int32_t OMEGA_0; - int32_t w; - int32_t M0; - int16_t AF0; - int16_t AF1; - // int32_t health; -}; - -struct supl_ephemeris_s { - u_int8_t prn; - u_int8_t fill1; - u_int16_t delta_n; - int32_t M0; - u_int32_t e; - u_int32_t A_sqrt; - int32_t OMEGA_0; - int32_t i0; - int32_t w; - int32_t OMEGA_dot; - int16_t i_dot; - int16_t Cuc; - int16_t Cus; - int16_t Crc; - int16_t Crs; - int16_t Cic; - int16_t Cis; - u_int16_t toe; - u_int16_t IODC; - u_int16_t toc; - int32_t AF0; - int16_t AF1; - int8_t AF2; - u_int8_t nav_model; - - /* nav model */ - u_int8_t bits; - u_int8_t ura; - u_int8_t health; - char reserved[11]; - int8_t tgd; - u_int8_t AODA; +struct supl_almanac_s +{ + u_int8_t prn; + u_int16_t e; + u_int8_t toa; + int16_t Ksii; + int16_t OMEGA_dot; + u_int32_t A_sqrt; + int32_t OMEGA_0; + int32_t w; + int32_t M0; + int16_t AF0; + int16_t AF1; + // int32_t health; }; -struct supl_ionospheric_s { - int8_t a0, a1, a2,a3, b0, b1, b2, b3; +struct supl_ephemeris_s +{ + u_int8_t prn; + u_int8_t fill1; + u_int16_t delta_n; + int32_t M0; + u_int32_t e; + u_int32_t A_sqrt; + int32_t OMEGA_0; + int32_t i0; + int32_t w; + int32_t OMEGA_dot; + int16_t i_dot; + int16_t Cuc; + int16_t Cus; + int16_t Crc; + int16_t Crs; + int16_t Cic; + int16_t Cis; + u_int16_t toe; + u_int16_t IODC; + u_int16_t toc; + int32_t AF0; + int16_t AF1; + int8_t AF2; + u_int8_t nav_model; + + /* nav model */ + u_int8_t bits; + u_int8_t ura; + u_int8_t health; + char reserved[11]; + int8_t tgd; + u_int8_t AODA; }; -struct supl_utc_s { - int32_t a0; - int32_t a1; - int8_t delta_tls; - u_int8_t tot; - u_int8_t wnt; - u_int8_t wnlsf; - u_int8_t dn; - u_int8_t delta_tlsf; - u_int8_t fill[8]; +struct supl_ionospheric_s +{ + int8_t a0, a1, a2, a3, b0, b1, b2, b3; }; -typedef struct supl_rrlp_ctx_s { - int set; +struct supl_utc_s +{ + int32_t a0; + int32_t a1; + int8_t delta_tls; + u_int8_t tot; + u_int8_t wnt; + u_int8_t wnlsf; + u_int8_t dn; + u_int8_t delta_tlsf; + u_int8_t fill[8]; +}; - struct { - long gps_tow, gps_week; - struct timeval stamp; - } time; +typedef struct supl_rrlp_ctx_s +{ + int set; - struct { - int uncertainty; - double lat, lon; /* of the base station */ - } pos; + struct + { + long gps_tow, gps_week; + struct timeval stamp; + } time; - struct supl_ionospheric_s iono; + struct + { + int uncertainty; + double lat, lon; /* of the base station */ + } pos; - struct supl_utc_s utc; + struct supl_ionospheric_s iono; - int cnt_eph; - struct supl_ephemeris_s eph[MAX_EPHEMERIS]; + struct supl_utc_s utc; - int cnt_alm; - int alm_week; - struct supl_almanac_s alm[MAX_EPHEMERIS]; + int cnt_eph; + struct supl_ephemeris_s eph[MAX_EPHEMERIS]; - int cnt_acq; - int acq_time; - struct supl_acquis_s acq[MAX_EPHEMERIS]; + int cnt_alm; + int alm_week; + struct supl_almanac_s alm[MAX_EPHEMERIS]; + + int cnt_acq; + int acq_time; + struct supl_acquis_s acq[MAX_EPHEMERIS]; } supl_assist_t; - -typedef struct supl_param_s { - int set; - int request; - struct { - int mcc, mnc, lac, ci; - } gsm; +typedef struct supl_param_s +{ + int set; + int request; - struct { - int mcc, mnc, uc; - } wcdma; + struct + { + int mcc, mnc, lac, ci; + } gsm; - struct { - int mcc, mnc, lac, ci; - double lat, lon; - int uncert; - } known; + struct + { + int mcc, mnc, uc; + } wcdma; - char msisdn[8]; + struct + { + int mcc, mnc, lac, ci; + double lat, lon; + int uncert; + } known; + + char msisdn[8]; } supl_param_t; -typedef struct supl_ctx_s { - supl_param_t p; +typedef struct supl_ctx_s +{ + supl_param_t p; - int fd; - SSL *ssl; - SSL_CTX *ssl_ctx; + int fd; + SSL *ssl; + SSL_CTX *ssl_ctx; - struct { - void *buf; - size_t size; - } slp_session_id; + struct + { + void *buf; + size_t size; + } slp_session_id; } supl_ctx_t; @@ -240,16 +254,18 @@ void supl_set_debug(FILE *log, int flags); typedef void (*supl_debug_cb)(char format, ...); -typedef struct supl_ulp_s { - ULP_PDU_t *pdu; - size_t size; - unsigned char buffer[8192]; +typedef struct supl_ulp_s +{ + ULP_PDU_t *pdu; + size_t size; + unsigned char buffer[8192]; } supl_ulp_t; -typedef struct supl_rrlp_s { - PDU_t *pdu; - size_t size; - unsigned char buffer[8192]; +typedef struct supl_rrlp_s +{ + PDU_t *pdu; + size_t size; + unsigned char buffer[8192]; } supl_rrlp_t; void supl_ulp_free(supl_ulp_t *pdu); diff --git a/src/core/monitor/CMakeLists.txt b/src/core/monitor/CMakeLists.txt new file mode 100644 index 000000000..54ee2a589 --- /dev/null +++ b/src/core/monitor/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + + +set(CORE_MONITOR_LIBS_SOURCES + gnss_synchro_monitor.cc + gnss_synchro_udp_sink.cc +) + +set(CORE_MONITOR_LIBS_HEADERS + gnss_synchro_monitor.h + gnss_synchro_udp_sink.h +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +list(SORT CORE_MONITOR_LIBS_HEADERS) +list(SORT CORE_MONITOR_LIBS_SOURCES) + +add_library(core_monitor_lib + ${CORE_MONITOR_LIBS_SOURCES} + ${CORE_MONITOR_LIBS_HEADERS} +) + +source_group(Headers FILES ${CORE_MONITOR_LIBS_HEADERS}) + +target_link_libraries(core_monitor_lib ${Boost_LIBRARIES}) + +add_dependencies(core_monitor_lib glog-${glog_RELEASE}) diff --git a/src/core/monitor/gnss_synchro_monitor.cc b/src/core/monitor/gnss_synchro_monitor.cc new file mode 100644 index 000000000..4f3918d8a --- /dev/null +++ b/src/core/monitor/gnss_synchro_monitor.cc @@ -0,0 +1,94 @@ +/*! + * \file gnss_synchro_monitor.cc + * \brief Implementation of a receiver monitoring block which allows sending + * a data stream with the receiver internal parameters (Gnss_Synchro objects) + * to local or remote clients over UDP. + * + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_synchro_monitor.h" +#include "gnss_synchro.h" +#include +#include +#include + + +using google::LogMessage; + + +gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses) +{ + return gnss_synchro_monitor_sptr(new gnss_synchro_monitor(n_channels, + output_rate_ms, + udp_port, + udp_addresses)); +} + + +gnss_synchro_monitor::gnss_synchro_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses) : gr::sync_block("gnss_synchro_monitor", + gr::io_signature::make(n_channels, n_channels, sizeof(Gnss_Synchro)), + gr::io_signature::make(0, 0, 0)) +{ + d_output_rate_ms = output_rate_ms; + d_nchannels = n_channels; + + udp_sink_ptr = std::unique_ptr(new Gnss_Synchro_Udp_Sink(udp_addresses, udp_port)); + + count = 0; +} + + +gnss_synchro_monitor::~gnss_synchro_monitor() = default; + + +int gnss_synchro_monitor::work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + const Gnss_Synchro** in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + for (int epoch = 0; epoch < noutput_items; epoch++) + { + count++; + if (count >= d_output_rate_ms) + { + for (unsigned int i = 0; i < d_nchannels; i++) + { + std::vector stocks; + stocks.push_back(in[i][epoch]); + udp_sink_ptr->write_gnss_synchro(stocks); + } + count = 0; + } + } + return noutput_items; +} diff --git a/src/core/monitor/gnss_synchro_monitor.h b/src/core/monitor/gnss_synchro_monitor.h new file mode 100644 index 000000000..db991a9ae --- /dev/null +++ b/src/core/monitor/gnss_synchro_monitor.h @@ -0,0 +1,86 @@ +/*! + * \file gnss_synchro_monitor.h + * \brief Interface of a receiver monitoring block which allows sending + * a data stream with the receiver internal parameters (Gnss_Synchro objects) + * to local or remote clients over UDP. + * + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GNSS_SYNCHRO_MONITOR_H +#define GNSS_SDR_GNSS_SYNCHRO_MONITOR_H + + +#include "gnss_synchro_udp_sink.h" +#include +#include +#include +#include + + +class gnss_synchro_monitor; + +typedef boost::shared_ptr gnss_synchro_monitor_sptr; + +gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + +/*! + * \brief This class implements a block that computes the PVT solution with Galileo E1 signals + */ +class gnss_synchro_monitor : public gr::sync_block +{ +private: + friend gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int nchannels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + + unsigned int d_nchannels; + + int d_output_rate_ms; + + std::unique_ptr udp_sink_ptr; + + int count; + + +public: + gnss_synchro_monitor(unsigned int nchannels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + + ~gnss_synchro_monitor(); //!< Default destructor + + int work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +#endif diff --git a/src/core/monitor/gnss_synchro_udp_sink.cc b/src/core/monitor/gnss_synchro_udp_sink.cc new file mode 100644 index 000000000..46b2d33c9 --- /dev/null +++ b/src/core/monitor/gnss_synchro_udp_sink.cc @@ -0,0 +1,69 @@ +/*! + * \file gnss_synchro_udp_sink.cc + * \brief Implementation of a class that sends serialized Gnss_Synchro + * objects over udp to one or multiple endponits + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_synchro_udp_sink.h" +#include +#include +#include +#include + +Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t& port) : socket{io_service} +{ + for (auto address : addresses) + { + boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), port); + endpoints.push_back(endpoint); + } +} + +bool Gnss_Synchro_Udp_Sink::write_gnss_synchro(std::vector stocks) +{ + std::ostringstream archive_stream; + boost::archive::binary_oarchive oa{archive_stream}; + oa << stocks; + std::string outbound_data = archive_stream.str(); + + for (auto endpoint : endpoints) + { + socket.open(endpoint.protocol(), error); + socket.connect(endpoint, error); + + try + { + socket.send(boost::asio::buffer(outbound_data)); + } + catch (boost::system::system_error const& e) + { + return false; + } + } + return true; +} diff --git a/src/core/monitor/gnss_synchro_udp_sink.h b/src/core/monitor/gnss_synchro_udp_sink.h new file mode 100644 index 000000000..ebfb854a0 --- /dev/null +++ b/src/core/monitor/gnss_synchro_udp_sink.h @@ -0,0 +1,53 @@ +/*! + * \file gnss_synchro_udp_sink.h + * \brief Interface of a class that sends serialized Gnss_Synchro objects + * over udp to one or multiple endponits + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SYNCHRO_UDP_SINK_H_ +#define GNSS_SYNCHRO_UDP_SINK_H_ + +#include "gnss_synchro.h" +#include + +class Gnss_Synchro_Udp_Sink +{ +public: + Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t &port); + bool write_gnss_synchro(std::vector stocks); + +private: + boost::asio::io_service io_service; + boost::asio::ip::udp::socket socket; + boost::system::error_code error; + std::vector endpoints; + std::vector stocks; +}; + + +#endif /* GNSS_SYNCHRO_UDP_SINK_H_ */ diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index a443b8a60..239e8cf00 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,137 +13,212 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(GNSS_RECEIVER_SOURCES - control_thread.cc - control_message_factory.cc - file_configuration.cc - gnss_block_factory.cc - gnss_flowgraph.cc - in_memory_configuration.cc + control_thread.cc + control_message_factory.cc + file_configuration.cc + gnss_block_factory.cc + gnss_flowgraph.cc + in_memory_configuration.cc + tcp_cmd_interface.cc ) +set(GNSS_RECEIVER_HEADERS + control_thread.h + control_message_factory.h + file_configuration.h + gnss_block_factory.h + gnss_flowgraph.h + in_memory_configuration.h + tcp_cmd_interface.h + concurrent_map.h + concurrent_queue.h + control_message.h +) if(PC_GNURADIO_RUNTIME_VERSION VERSION_GREATER 3.7.3) - add_definitions(-DMODERN_GNURADIO=1) -endif(PC_GNURADIO_RUNTIME_VERSION VERSION_GREATER 3.7.3) + add_definitions(-DMODERN_GNURADIO=1) +endif() if(ENABLE_CUDA) - add_definitions(-DCUDA_GPU_ACCEL=1) - set(OPT_RECEIVER_INCLUDE_DIRS ${OPT_RECEIVER_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS}) -endif(ENABLE_CUDA) + add_definitions(-DCUDA_GPU_ACCEL=1) + set(OPT_RECEIVER_INCLUDE_DIRS + ${OPT_RECEIVER_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS} + ) +endif() +if(ENABLE_FPGA) + add_definitions(-DENABLE_FPGA=1) +endif() + +if(ENABLE_RAW_UDP) + add_definitions(-DRAW_UDP=1) +endif() -include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/libs - ${CMAKE_SOURCE_DIR}/src/core/libs/supl - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/conditioner/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/observables/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/observables/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${ARMADILLO_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${OPT_RECEIVER_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} -) - if(Boost_VERSION LESS 105000) - add_definitions(-DOLD_BOOST=1) -endif(Boost_VERSION LESS 105000) + add_definitions(-DOLD_BOOST=1) +endif() if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() if(ENABLE_GN3S) add_definitions(-DGN3S_DRIVER=1) -endif(ENABLE_GN3S) +endif() if(ENABLE_ARRAY) add_definitions(-DRAW_ARRAY_DRIVER=1) -endif(ENABLE_ARRAY) +endif() if(ENABLE_FLEXIBAND) add_definitions(-DFLEXIBAND_DRIVER=1) -endif(ENABLE_FLEXIBAND) +endif() if(ENABLE_OSMOSDR) - add_definitions(-DOSMOSDR_DRIVER=1) -endif(ENABLE_OSMOSDR) + if(GROSMOSDR_FOUND) + add_definitions(-DOSMOSDR_DRIVER=1) + endif() +endif() -if(ENABLE_UHD) +if(ENABLE_UHD AND GNURADIO_UHD_LIBRARIES_gnuradio-uhd) add_definitions(-DUHD_DRIVER=1) -endif(ENABLE_UHD) +endif() #Enable OpenCL if found in the system if(OPENCL_FOUND) - message(STATUS "Adding processing blocks implemented using OpenCL" ) + message(STATUS "Adding processing blocks implemented using OpenCL") add_definitions(-DOPENCL_BLOCKS=1) -else(OPENCL_FOUND) +else() add_definitions(-DOPENCL_BLOCKS=0) -endif(OPENCL_FOUND) +endif() -add_definitions(-DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}") +#enable SDR Hardware based on fmcomms2 +if(ENABLE_PLUTOSDR) + add_definitions(-DPLUTOSDR_DRIVER=1) + set(OPT_RECEIVER_INCLUDE_DIRS + ${OPT_RECEIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS} + ) +endif() -file(GLOB GNSS_RECEIVER_HEADERS "*.h") -list(SORT GNSS_RECEIVER_HEADERS) -file(GLOB GNSS_RECEIVER_INTERFACE_HEADERS "../interfaces/*.h") -list(SORT GNSS_RECEIVER_INTERFACE_HEADERS) -add_library(gnss_rx ${GNSS_RECEIVER_SOURCES} ${GNSS_RECEIVER_HEADERS} ${GNSS_RECEIVER_INTERFACE_HEADERS}) -source_group(Headers FILES ${GNSS_RECEIVER_HEADERS} ${GNSS_RECEIVER_INTERFACE_HEADERS}) +if(ENABLE_FMCOMMS2) + add_definitions(-DFMCOMMS2_DRIVER=1) + set(OPT_RECEIVER_INCLUDE_DIRS + ${OPT_RECEIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS} + ) +endif() -target_link_libraries(gnss_rx ${Boost_LIBRARIES} - ${ARMADILLO_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - gnss_system_parameters - gnss_sp_libs - signal_source_adapters - datatype_adapters - input_filter_adapters - conditioner_adapters - resampler_adapters - acq_adapters - tracking_lib - tracking_adapters - channel_adapters - telemetry_decoder_adapters - obs_adapters - pvt_adapters - pvt_lib - rx_core_lib +if(ENABLE_AD9361) + add_definitions(-DAD9361_DRIVER=1) + set(OPT_RECEIVER_INCLUDE_DIRS + ${OPT_RECEIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS} + ) +endif() + +if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.13.4") + add_definitions(-DGR_GREATER_38=1) +endif() + + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/libs + ${CMAKE_SOURCE_DIR}/src/core/libs/supl + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl + ${CMAKE_SOURCE_DIR}/src/core/monitor + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/conditioner/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs/libswiftcnav + ${CMAKE_SOURCE_DIR}/src/algorithms/observables/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/observables/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${ARMADILLO_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${PUGIXML_INCLUDE_DIR} + ${OPT_RECEIVER_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} +) + +list(SORT GNSS_RECEIVER_HEADERS) +list(SORT GNSS_RECEIVER_SOURCES) + +set(GNSS_RECEIVER_INTERFACE_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/acquisition_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/channel_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/configuration_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/gnss_block_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/observables_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/pvt_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/telemetry_decoder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/tracking_interface.h +) + +list(SORT GNSS_RECEIVER_INTERFACE_HEADERS) + +add_library(gnss_rx + ${GNSS_RECEIVER_SOURCES} + ${GNSS_RECEIVER_HEADERS} + ${GNSS_RECEIVER_INTERFACE_HEADERS} +) + +source_group(Headers FILES ${GNSS_RECEIVER_HEADERS} + ${GNSS_RECEIVER_INTERFACE_HEADERS}) + +target_link_libraries(gnss_rx + ${Boost_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + gnss_system_parameters + gnss_sp_libs + signal_source_adapters + datatype_adapters + input_filter_adapters + conditioner_adapters + resampler_adapters + acq_adapters + tracking_adapters + channel_adapters + telemetry_decoder_libswiftcnav + telemetry_decoder_lib + telemetry_decoder_adapters + obs_adapters + pvt_adapters + pvt_lib + rx_core_lib + core_monitor_lib ) diff --git a/src/core/receiver/concurrent_map.h b/src/core/receiver/concurrent_map.h index fff578c1e..218030286 100644 --- a/src/core/receiver/concurrent_map.h +++ b/src/core/receiver/concurrent_map.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,12 @@ #ifndef GNSS_SDR_CONCURRENT_MAP_H #define GNSS_SDR_CONCURRENT_MAP_H +#include #include #include -#include -template + +template /*! @@ -44,10 +45,11 @@ template */ class concurrent_map { - typedef typename std::map::iterator Data_iterator; // iterator is scope dependent + typedef typename std::map::iterator Data_iterator; // iterator is scope dependent private: - std::map the_map; + std::map the_map; boost::mutex the_mutex; + public: void write(int key, Data const& data) { @@ -56,19 +58,19 @@ public: data_iter = the_map.find(key); if (data_iter != the_map.end()) { - data_iter->second = data; // update + data_iter->second = data; // update } else { - the_map.insert(std::pair(key, data)); // insert SILENTLY fails if the item already exists in the map! + the_map.insert(std::pair(key, data)); // insert SILENTLY fails if the item already exists in the map! } lock.unlock(); } - std::map get_map_copy() + std::map get_map_copy() { boost::mutex::scoped_lock lock(the_mutex); - std::map map_aux = the_map; + std::map map_aux = the_map; lock.unlock(); return map_aux; } @@ -92,11 +94,8 @@ public: lock.unlock(); return true; } - else - { - lock.unlock(); - return false; - } + lock.unlock(); + return false; } }; diff --git a/src/core/receiver/concurrent_queue.h b/src/core/receiver/concurrent_queue.h index 8c700e220..3a4e89190 100644 --- a/src/core/receiver/concurrent_queue.h +++ b/src/core/receiver/concurrent_queue.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,10 +31,10 @@ #ifndef GNSS_SDR_CONCURRENT_QUEUE_H #define GNSS_SDR_CONCURRENT_QUEUE_H -#include #include +#include -template +template /*! * \brief This class implements a thread-safe std::queue @@ -49,6 +49,7 @@ private: std::queue the_queue; mutable boost::mutex the_mutex; boost::condition_variable the_condition_variable; + public: void push(Data const& data) { @@ -67,7 +68,7 @@ public: bool try_pop(Data& popped_value) { boost::mutex::scoped_lock lock(the_mutex); - if(the_queue.empty()) + if (the_queue.empty()) { return false; } @@ -79,7 +80,7 @@ public: void wait_and_pop(Data& popped_value) { boost::mutex::scoped_lock lock(the_mutex); - while(the_queue.empty()) + while (the_queue.empty()) { the_condition_variable.wait(lock); } diff --git a/src/core/receiver/control_message.h b/src/core/receiver/control_message.h index 5a508a18c..ff166e40f 100644 --- a/src/core/receiver/control_message.h +++ b/src/core/receiver/control_message.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,13 +23,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #ifndef GNSS_SDR_CONTROL_MESSAGE_H_ #define GNSS_SDR_CONTROL_MESSAGE_H_ @@ -38,7 +37,6 @@ */ class ControlMessage { - public: static unsigned int const ack_success = 0; static unsigned int const ack_failed = 1; diff --git a/src/core/receiver/control_message_factory.cc b/src/core/receiver/control_message_factory.cc index 6f7994c29..d2871d39e 100644 --- a/src/core/receiver/control_message_factory.cc +++ b/src/core/receiver/control_message_factory.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,43 +35,39 @@ using google::LogMessage; // Constructor -ControlMessageFactory::ControlMessageFactory() -{} +ControlMessageFactory::ControlMessageFactory() = default; // Destructor -ControlMessageFactory::~ControlMessageFactory() -{} +ControlMessageFactory::~ControlMessageFactory() = default; -boost::shared_ptr ControlMessageFactory::GetQueueMessage(unsigned int who, unsigned int what) +gr::message::sptr ControlMessageFactory::GetQueueMessage(unsigned int who, unsigned int what) { std::shared_ptr control_message = std::make_shared(); control_message->who = who; control_message->what = what; - boost::shared_ptr queue_message = gr::message::make(0, 0, 0, sizeof(ControlMessage)); + gr::message::sptr queue_message = gr::message::make(0, 0, 0, sizeof(ControlMessage)); memcpy(queue_message->msg(), control_message.get(), sizeof(ControlMessage)); return queue_message; } -std::shared_ptr>> ControlMessageFactory::GetControlMessages(boost::shared_ptr queue_message) +std::shared_ptr>> ControlMessageFactory::GetControlMessages(const gr::message::sptr& queue_message) { - std::shared_ptr>> control_messages = std::make_shared>>(); + std::shared_ptr>> control_messages = std::make_shared>>(); unsigned int control_messages_count = queue_message->length() / sizeof(ControlMessage); - if(queue_message->length() % sizeof(ControlMessage) != 0) + if (queue_message->length() % sizeof(ControlMessage) != 0) { LOG(WARNING) << "Queue message has size " << queue_message->length() << ", which is not" << " multiple of control message size " << sizeof(ControlMessage); LOG(WARNING) << "Ignoring this queue message to prevent unexpected results."; return control_messages; } - for(unsigned int i = 0; i < control_messages_count; i++) + for (unsigned int i = 0; i < control_messages_count; i++) { control_messages->push_back(std::make_shared()); - memcpy(control_messages->at(i).get(), queue_message->msg() + (i*sizeof(ControlMessage)), sizeof(ControlMessage)); + memcpy(control_messages->at(i).get(), queue_message->msg() + (i * sizeof(ControlMessage)), sizeof(ControlMessage)); } return control_messages; } - - diff --git a/src/core/receiver/control_message_factory.h b/src/core/receiver/control_message_factory.h index 2ff294a8c..3aac015a9 100644 --- a/src/core/receiver/control_message_factory.h +++ b/src/core/receiver/control_message_factory.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,16 +31,16 @@ #ifndef GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_ #define GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_ +#include #include #include -#include //! Message described by who sent it and what it says typedef struct ControlMessage_ { unsigned int who; unsigned int what; -} ControlMessage ; +} ControlMessage; /*! @@ -50,7 +50,6 @@ typedef struct ControlMessage_ */ class ControlMessageFactory { - public: //! Constructor ControlMessageFactory(); @@ -58,8 +57,8 @@ public: //! Virtual destructor virtual ~ControlMessageFactory(); - boost::shared_ptr GetQueueMessage(unsigned int who, unsigned int what); - std::shared_ptr>> GetControlMessages(gr::message::sptr queue_message); + gr::message::sptr GetQueueMessage(unsigned int who, unsigned int what); + std::shared_ptr>> GetControlMessages(const gr::message::sptr& queue_message); }; #endif /*GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_*/ diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index d0a21d68d..463815bcb 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,52 +27,67 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "control_thread.h" -#include +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "control_message_factory.h" +#include "file_configuration.h" +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" +#include "geofunctions.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include "gnss_flowgraph.h" +#include "gnss_sdr_flags.h" +#include "gps_almanac.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_utc_model.h" +#include "pvt_interface.h" +#include "rtklib_conversions.h" +#include "rtklib_ephemeris.h" +#include "rtklib_rtkcmn.h" +#include +#include +#include +#include +#include #include #include #include #include #include -#include #include #include -#include -#include -#include -#include -#include -#include "gps_ephemeris.h" -#include "gps_iono.h" -#include "gps_utc_model.h" -#include "gps_almanac.h" -#include "galileo_ephemeris.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" -#include "galileo_almanac.h" -#include "concurrent_queue.h" -#include "concurrent_map.h" -#include "gnss_flowgraph.h" -#include "file_configuration.h" -#include "control_message_factory.h" +#include +#include + extern concurrent_map global_gps_acq_assist_map; extern concurrent_queue global_gps_acq_assist_queue; using google::LogMessage; -DEFINE_string(config_file, std::string(GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/default.conf"), - "File containing the configuration parameters"); ControlThread::ControlThread() { - configuration_ = std::make_shared(FLAGS_config_file); + if (!FLAGS_c.compare("-")) + { + configuration_ = std::make_shared(FLAGS_config_file); + } + else + { + configuration_ = std::make_shared(FLAGS_c); + } delete_configuration_ = false; + restart_ = false; init(); } @@ -81,16 +96,113 @@ ControlThread::ControlThread(std::shared_ptr configurati { configuration_ = configuration; delete_configuration_ = false; + restart_ = false; init(); } - -ControlThread::~ControlThread() +void ControlThread::init() { - // save navigation data to files - // if (save_assistance_to_XML() == true) {} - if(msqid != -1) msgctl(msqid, IPC_RMID, NULL); + // Instantiates a control queue, a GNSS flowgraph, and a control message factory + control_queue_ = gr::msg_queue::make(0); + cmd_interface_.set_msg_queue(control_queue_); //set also the queue pointer for the telecommand thread + try + { + flowgraph_ = std::make_shared(configuration_, control_queue_); + } + catch (const boost::bad_lexical_cast &e) + { + std::cout << "Caught bad lexical cast with error " << e.what() << std::endl; + } + control_message_factory_ = std::make_shared(); + stop_ = false; + processed_control_messages_ = 0; + applied_actions_ = 0; + supl_mcc = 0; + supl_mns = 0; + supl_lac = 0; + supl_ci = 0; + msqid = -1; + agnss_ref_location_ = Agnss_Ref_Location(); + agnss_ref_time_ = Agnss_Ref_Time(); + + std::string empty_string = ""; + std::string ref_location_str = configuration_->property("GNSS-SDR.AGNSS_ref_location", empty_string); + std::string ref_time_str = configuration_->property("GNSS-SDR.AGNSS_ref_utc_time", empty_string); + if (ref_location_str.compare(empty_string) != 0) + { + std::vector vect; + std::stringstream ss(ref_location_str); + double d; + while (ss >> d) + { + vect.push_back(d); + if ((ss.peek() == ',') or (ss.peek() == ' ')) + ss.ignore(); + } + // fill agnss_ref_location_ + if (vect.size() >= 2) + { + if ((vect[0] < 90.0) and (vect[0] > -90) and (vect[1] < 180.0) and (vect[1] > -180.0)) + { + agnss_ref_location_.lat = vect[0]; + agnss_ref_location_.lon = vect[1]; + agnss_ref_location_.valid = true; + } + else + { + std::cerr << "GNSS-SDR.AGNSS_ref_location=" << ref_location_str << " is not a valid position." << std::endl; + agnss_ref_location_.valid = false; + } + } + } + if (ref_time_str.compare(empty_string) == 0) + { + // Make an educated guess + time_t rawtime; + time(&rawtime); + agnss_ref_time_.d_tv_sec = rawtime; + agnss_ref_time_.valid = true; + } + else + { + // fill agnss_ref_time_ + struct tm tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; + if (strptime(ref_time_str.c_str(), "%d/%m/%Y %H:%M:%S", &tm) != nullptr) + { + agnss_ref_time_.d_tv_sec = timegm(&tm); + if (agnss_ref_time_.d_tv_sec > 0) + { + agnss_ref_time_.valid = true; + } + else + { + std::cerr << "GNSS-SDR.AGNSS_ref_utc_time=" << ref_time_str << " is not well-formed. Please use four digits for the year: DD/MM/YYYY HH:MM:SS" << std::endl; + } + } + else + { + std::cerr << "GNSS-SDR.AGNSS_ref_utc_time=" << ref_time_str << " is not well-formed. Should be DD/MM/YYYY HH:MM:SS in UTC" << std::endl; + agnss_ref_time_.valid = false; + } + } +} + + +ControlThread::~ControlThread() // NOLINT(modernize-use-equals-default) +{ + if (msqid != -1) msgctl(msqid, IPC_RMID, NULL); +} + + +void ControlThread::telecommand_listener() +{ + bool telecommand_enabled = configuration_->property("GNSS-SDR.telecommand_enabled", false); + if (telecommand_enabled) + { + int tcp_cmd_port = configuration_->property("GNSS-SDR.telecommand_tcp_port", 3333); + cmd_interface_.run_cmd_server(tcp_cmd_port); + } } @@ -103,10 +215,18 @@ ControlThread::~ControlThread() * while (flowgraph_->running() && !stop)_{ * 3- Read control messages and process them } */ -void ControlThread::run() +int ControlThread::run() { // Connect the flowgraph - flowgraph_->connect(); + try + { + flowgraph_->connect(); + } + catch (const std::exception &e) + { + LOG(ERROR) << e.what(); + return 0; + } if (flowgraph_->connected()) { LOG(INFO) << "Flowgraph connected"; @@ -114,7 +234,7 @@ void ControlThread::run() else { LOG(ERROR) << "Unable to connect flowgraph"; - return; + return 0; } // Start the flowgraph flowgraph_->start(); @@ -125,15 +245,25 @@ void ControlThread::run() else { LOG(ERROR) << "Unable to start flowgraph"; - return; + return 0; } - //launch GNSS assistance process AFTER the flowgraph is running because the GNURadio asynchronous queues must be already running to transport msgs + // launch GNSS assistance process AFTER the flowgraph is running because the GNU Radio asynchronous queues must be already running to transport msgs assist_GNSS(); // start the keyboard_listener thread keyboard_thread_ = boost::thread(&ControlThread::keyboard_listener, this); sysv_queue_thread_ = boost::thread(&ControlThread::sysv_queue_listener, this); + // start the telecommand listener thread + cmd_interface_.set_pvt(flowgraph_->get_pvt()); + cmd_interface_thread_ = boost::thread(&ControlThread::telecommand_listener, this); + + bool enable_FPGA = configuration_->property("Channel.enable_FPGA", false); + if (enable_FPGA == true) + { + flowgraph_->start_acquisition_helper(); + } + // Main loop to read and process the control messages while (flowgraph_->running() && !stop_) { @@ -144,29 +274,40 @@ void ControlThread::run() std::cout << "Stopping GNSS-SDR, please wait!" << std::endl; flowgraph_->stop(); stop_ = true; + flowgraph_->disconnect(); - //Join keyboard thread +// Join keyboard thread #ifdef OLD_BOOST keyboard_thread_.timed_join(boost::posix_time::seconds(1)); sysv_queue_thread_.timed_join(boost::posix_time::seconds(1)); + cmd_interface_thread_.timed_join(boost::posix_time::seconds(1)); #endif #ifndef OLD_BOOST keyboard_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); sysv_queue_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); + cmd_interface_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); #endif LOG(INFO) << "Flowgraph stopped"; + + if (restart_) + { + return 42; // signal the gnss-sdr-harness.sh to restart the receiver program + } + + return 0; // normal shutdown } -void ControlThread::set_control_queue(boost::shared_ptr control_queue) +void ControlThread::set_control_queue(const gr::msg_queue::sptr &control_queue) { if (flowgraph_->running()) { LOG(WARNING) << "Unable to set control queue while flowgraph is running"; return; } - control_queue_ = control_queue; + control_queue_ = std::move(control_queue); + cmd_interface_.set_msg_queue(control_queue_); } @@ -179,131 +320,282 @@ bool ControlThread::read_assistance_from_XML() bool ret = false; // getting names from the config file, if available std::string eph_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename); - std::string utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_utc_model.xml", utc_default_xml_filename); + std::string utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_utc_model_xml", utc_default_xml_filename); std::string iono_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_iono_xml", iono_default_xml_filename); + std::string gal_iono_xml_filename = configuration_->property("GNSS-SDR.SUPL_gal_iono_xml", gal_iono_default_xml_filename); std::string ref_time_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_time_xml", ref_time_default_xml_filename); std::string ref_location_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ref_location_xml", ref_location_default_xml_filename); + std::string eph_gal_xml_filename = configuration_->property("GNSS-SDR.SUPL_gal_ephemeris_xml", eph_gal_default_xml_filename); + std::string eph_cnav_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_cnav_ephemeris_xml", eph_cnav_default_xml_filename); + std::string gal_utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gal_utc_model_xml", gal_utc_default_xml_filename); + std::string cnav_utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_cnav_utc_model_xml", cnav_utc_default_xml_filename); + std::string eph_glo_xml_filename = configuration_->property("GNSS-SDR.SUPL_glo_ephemeris_xml", eph_glo_gnav_default_xml_filename); + std::string glo_utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_glo_utc_model_xml", glo_utc_default_xml_filename); + std::string gal_almanac_xml_filename = configuration_->property("GNSS-SDR.SUPL_gal_almanac_xml", gal_almanac_default_xml_filename); + std::string gps_almanac_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_almanac_xml", gps_almanac_default_xml_filename); - std::cout << "SUPL: Try read GPS ephemeris from XML file " << eph_xml_filename << std::endl; - if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename) == true) + if (configuration_->property("GNSS-SDR.AGNSS_XML_enabled", false) == true) { - std::map::iterator gps_eph_iter; - for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); - gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); - gps_eph_iter++) + eph_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_ephemeris_xml", eph_default_xml_filename); + utc_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_utc_model_xml", utc_default_xml_filename); + iono_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_iono_xml", iono_default_xml_filename); + gal_iono_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gal_iono_xml", gal_iono_default_xml_filename); + ref_time_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_ref_time_xml", ref_time_default_xml_filename); + ref_location_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_ref_location_xml", ref_location_default_xml_filename); + eph_gal_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gal_ephemeris_xml", eph_gal_default_xml_filename); + eph_cnav_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_cnav_ephemeris_xml", eph_cnav_default_xml_filename); + gal_utc_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gal_utc_model_xml", gal_utc_default_xml_filename); + cnav_utc_xml_filename = configuration_->property("GNSS-SDR.AGNSS_cnav_utc_model_xml", cnav_utc_default_xml_filename); + eph_glo_xml_filename = configuration_->property("GNSS-SDR.AGNSS_glo_ephemeris_xml", eph_glo_gnav_default_xml_filename); + glo_utc_xml_filename = configuration_->property("GNSS-SDR.AGNSS_glo_utc_model_xml", glo_utc_default_xml_filename); + gal_almanac_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gal_almanac_xml", gal_almanac_default_xml_filename); + gps_almanac_xml_filename = configuration_->property("GNSS-SDR.AGNSS_gps_almanac_xml", gps_almanac_default_xml_filename); + } + + std::cout << "Trying to read GNSS ephemeris from XML file(s)..." << std::endl; + + if (configuration_->property("Channels_1C.count", 0) > 0) + { + if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename) == true) { - std::cout << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first << std::endl; - std::shared_ptr tmp_obj = std::make_shared(gps_eph_iter->second); - flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::map::const_iterator gps_eph_iter; + for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.cbegin(); + gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.cend(); + gps_eph_iter++) + { + std::cout << "From XML file: Read NAV ephemeris for satellite " << Gnss_Satellite("GPS", gps_eph_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gps_eph_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; + } + + if (supl_client_acquisition_.load_utc_xml(utc_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_utc); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read GPS UTC model parameters." << std::endl; + ret = true; + } + + if (supl_client_acquisition_.load_iono_xml(iono_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_iono); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read GPS ionosphere model parameters." << std::endl; + ret = true; + } + + if (supl_client_ephemeris_.load_gps_almanac_xml(gps_almanac_xml_filename) == true) + { + std::map::const_iterator gps_alm_iter; + for (gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.cbegin(); + gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.cend(); + gps_alm_iter++) + { + std::cout << "From XML file: Read GPS almanac for satellite " << Gnss_Satellite("GPS", gps_alm_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gps_alm_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; } - ret = true; } - else + + if ((configuration_->property("Channels_1B.count", 0) > 0) or (configuration_->property("Channels_5X.count", 0) > 0)) { - std::cout << "ERROR: SUPL client error reading XML" << std::endl; - std::cout << "Disabling SUPL assistance..." << std::endl; + if (supl_client_ephemeris_.load_gal_ephemeris_xml(eph_gal_xml_filename) == true) + { + std::map::const_iterator gal_eph_iter; + for (gal_eph_iter = supl_client_ephemeris_.gal_ephemeris_map.cbegin(); + gal_eph_iter != supl_client_ephemeris_.gal_ephemeris_map.cend(); + gal_eph_iter++) + { + std::cout << "From XML file: Read ephemeris for satellite " << Gnss_Satellite("Galileo", gal_eph_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gal_eph_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; + } + + if (supl_client_acquisition_.load_gal_iono_xml(gal_iono_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gal_iono); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read Galileo ionosphere model parameters." << std::endl; + ret = true; + } + + if (supl_client_acquisition_.load_gal_utc_xml(gal_utc_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gal_utc); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read Galileo UTC model parameters." << std::endl; + ret = true; + } + + if (supl_client_ephemeris_.load_gal_almanac_xml(gal_almanac_xml_filename) == true) + { + std::map::const_iterator gal_alm_iter; + for (gal_alm_iter = supl_client_ephemeris_.gal_almanac_map.cbegin(); + gal_alm_iter != supl_client_ephemeris_.gal_almanac_map.cend(); + gal_alm_iter++) + { + std::cout << "From XML file: Read Galileo almanac for satellite " << Gnss_Satellite("Galileo", gal_alm_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gal_alm_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; + } } - // Only look for {utc, iono, ref time, ref location} if SUPL is enabled + + if ((configuration_->property("Channels_2S.count", 0) > 0) or (configuration_->property("Channels_L5.count", 0) > 0)) + { + if (supl_client_ephemeris_.load_cnav_ephemeris_xml(eph_cnav_xml_filename) == true) + { + std::map::const_iterator gps_cnav_eph_iter; + for (gps_cnav_eph_iter = supl_client_ephemeris_.gps_cnav_ephemeris_map.cbegin(); + gps_cnav_eph_iter != supl_client_ephemeris_.gps_cnav_ephemeris_map.cend(); + gps_cnav_eph_iter++) + { + std::cout << "From XML file: Read CNAV ephemeris for satellite " << Gnss_Satellite("GPS", gps_cnav_eph_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gps_cnav_eph_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; + } + + if (supl_client_acquisition_.load_cnav_utc_xml(cnav_utc_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_cnav_utc); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read GPS CNAV UTC model parameters." << std::endl; + ret = true; + } + } + + if ((configuration_->property("Channels_1G.count", 0) > 0) or (configuration_->property("Channels_2G.count", 0) > 0)) + { + if (supl_client_ephemeris_.load_gnav_ephemeris_xml(eph_glo_xml_filename) == true) + { + std::map::const_iterator glo_gnav_eph_iter; + for (glo_gnav_eph_iter = supl_client_ephemeris_.glonass_gnav_ephemeris_map.cbegin(); + glo_gnav_eph_iter != supl_client_ephemeris_.glonass_gnav_ephemeris_map.cend(); + glo_gnav_eph_iter++) + { + std::cout << "From XML file: Read GLONASS GNAV ephemeris for satellite " << Gnss_Satellite("GLONASS", glo_gnav_eph_iter->second.i_satellite_PRN) << std::endl; + std::shared_ptr tmp_obj = std::make_shared(glo_gnav_eph_iter->second); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + } + ret = true; + } + + if (supl_client_acquisition_.load_glo_utc_xml(glo_utc_xml_filename) == true) + { + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.glo_gnav_utc); + flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + std::cout << "From XML file: Read GLONASS UTC model parameters." << std::endl; + ret = true; + } + } + + if (ret == false) + { + std::cout << "Error reading XML files" << std::endl; + std::cout << "Disabling GNSS assistance..." << std::endl; + } + + // Only look for {ref time, ref location} if SUPL is enabled bool enable_gps_supl_assistance = configuration_->property("GNSS-SDR.SUPL_gps_enabled", false); if (enable_gps_supl_assistance == true) { - // Try to read UTC model from XML - if (supl_client_acquisition_.load_utc_xml(utc_xml_filename) == true) - { - LOG(INFO) << "SUPL: Read XML UTC model"; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_utc); - flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); - } - else - { - LOG(INFO) << "SUPL: couldn't read UTC model XML"; - } - - // Try to read Iono model from XML - if (supl_client_acquisition_.load_iono_xml(iono_xml_filename) == true) - { - LOG(INFO) << "SUPL: Read XML IONO model"; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_iono); - flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); - } - else - { - LOG(INFO) << "SUPL: couldn't read IONO model XML"; - } - // Try to read Ref Time from XML if (supl_client_acquisition_.load_ref_time_xml(ref_time_xml_filename) == true) { LOG(INFO) << "SUPL: Read XML Ref Time"; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_time); + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_time); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } else { - LOG(INFO) << "SUPL: couldn't read Ref Time XML"; + LOG(INFO) << "SUPL: could not read Ref Time XML"; } // Try to read Ref Location from XML if (supl_client_acquisition_.load_ref_location_xml(ref_location_xml_filename) == true) { LOG(INFO) << "SUPL: Read XML Ref Location"; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_ref_loc); + std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_ref_loc); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } else { - LOG(INFO) << "SUPL: couldn't read Ref Location XML"; + LOG(INFO) << "SUPL: could not read Ref Location XML"; } } return ret; } + void ControlThread::assist_GNSS() { //######### GNSS Assistance ################################# // GNSS Assistance configuration bool enable_gps_supl_assistance = configuration_->property("GNSS-SDR.SUPL_gps_enabled", false); - if (enable_gps_supl_assistance == true) - //SUPL SERVER TEST. Not operational yet! + bool enable_agnss_xml = configuration_->property("GNSS-SDR.AGNSS_XML_enabled", false); + if ((enable_gps_supl_assistance == true) and (enable_agnss_xml == false)) { std::cout << "SUPL RRLP GPS assistance enabled!" << std::endl; - std::string default_acq_server = "supl.nokia.com"; + std::string default_acq_server = "supl.google.com"; std::string default_eph_server = "supl.google.com"; supl_client_ephemeris_.server_name = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_server", default_acq_server); supl_client_acquisition_.server_name = configuration_->property("GNSS-SDR.SUPL_gps_acquisition_server", default_eph_server); supl_client_ephemeris_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_port", 7275); supl_client_acquisition_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_acquisition_port", 7275); supl_mcc = configuration_->property("GNSS-SDR.SUPL_MCC", 244); - supl_mns = configuration_->property("GNSS-SDR.SUPL_MNS", 5); + supl_mns = configuration_->property("GNSS-SDR.SUPL_MNC ", 5); std::string default_lac = "0x59e2"; std::string default_ci = "0x31b0"; + std::string supl_lac_s = configuration_->property("GNSS-SDR.SUPL_LAC", default_lac); + std::string supl_ci_s = configuration_->property("GNSS-SDR.SUPL_CI", default_ci); try - { - supl_lac = boost::lexical_cast(configuration_->property("GNSS-SDR.SUPL_LAC", default_lac)); - } - catch(boost::bad_lexical_cast &) - { - supl_lac = 0x59e2; - } + { + supl_lac = std::stoi(supl_lac_s, nullptr, 0); + } + catch (const std::invalid_argument &ia) + { + std::cerr << "Invalid argument for SUPL LAC: " << ia.what() << '\n'; + supl_lac = -1; + } + try + { + supl_ci = std::stoi(supl_ci_s, nullptr, 0); + } + catch (const std::invalid_argument &ia) + { + std::cerr << "Invalid argument for SUPL CI: " << ia.what() << '\n'; + supl_ci = -1; + } - try - { - supl_ci = boost::lexical_cast(configuration_->property("GNSS-SDR.SUPL_CI", default_ci)); - } - catch(boost::bad_lexical_cast &) - { + if (supl_lac < 0 or supl_lac > 65535) + { + supl_lac = 0x59e2; + } + + if (supl_ci < 0 or supl_ci > 268435455) // 2^16 for GSM and CDMA, 2^28 for UMTS and LTE networks + { supl_ci = 0x31b0; - } + } bool SUPL_read_gps_assistance_xml = configuration_->property("GNSS-SDR.SUPL_read_gps_assistance_xml", false); if (SUPL_read_gps_assistance_xml == true) { - // read assistance from file + // Read assistance from file if (read_assistance_from_XML()) { - std::cout << "GPS assistance data loaded from local XML file." << std::endl; + std::cout << "GNSS assistance data loaded from local XML file(s)." << std::endl; + std::cout << "No SUPL request has been performed." << std::endl; } } else @@ -311,135 +603,172 @@ void ControlThread::assist_GNSS() // Request ephemeris from SUPL server int error; supl_client_ephemeris_.request = 1; - std::cout << "SUPL: Try to read GPS ephemeris from SUPL server..." << std::endl; + std::cout << "SUPL: Try to read GPS ephemeris data from SUPL server..." << std::endl; error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_eph_iter; - for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); - gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); - gps_eph_iter++) + std::map::const_iterator gps_eph_iter; + for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.cbegin(); + gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.cend(); + gps_eph_iter++) { - std::cout << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first << std::endl; + std::cout << "SUPL: Received ephemeris data for satellite " << Gnss_Satellite("GPS", gps_eph_iter->second.i_satellite_PRN) << std::endl; std::shared_ptr tmp_obj = std::make_shared(gps_eph_iter->second); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } - //Save ephemeris to XML file + // Save ephemeris to XML file std::string eph_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename); if (supl_client_ephemeris_.save_ephemeris_map_xml(eph_xml_filename, supl_client_ephemeris_.gps_ephemeris_map) == true) { - std::cout << "SUPL: XML Ephemeris file created" << std::endl; + std::cout << "SUPL: XML ephemeris data file created" << std::endl; } else { - std::cout << "SUPL: Failed to create XML Ephemeris file" << std::endl; + std::cout << "SUPL: Failed to create XML ephemeris data file" << std::endl; } } else { - std::cout << "ERROR: SUPL client for Ephemeris returned " << error << std::endl; - std::cout << "Please check internet connection and SUPL server configuration" << error << std::endl; - std::cout << "Trying to read ephemeris from XML file" << std::endl; + std::cout << "ERROR: SUPL client request for ephemeris data returned " << error << std::endl; + std::cout << "Please check your network connectivity and SUPL server configuration" << std::endl; + std::cout << "Trying to read AGNSS data from local XML file(s)..." << std::endl; if (read_assistance_from_XML() == false) { - std::cout << "ERROR: Could not read Ephemeris file: Disabling SUPL assistance." << std::endl; + std::cout << "ERROR: Could not read XML files: Disabling SUPL assistance." << std::endl; } } - // Request almanac , IONO and UTC Model + // Request almanac, IONO and UTC Model data supl_client_ephemeris_.request = 0; - std::cout << "SUPL: Try read Almanac, Iono, Utc Model, Ref Time and Ref Location from SUPL server..." << std::endl; + std::cout << "SUPL: Try to read Almanac, Iono, Utc Model, Ref Time and Ref Location data from SUPL server..." << std::endl; error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_alm_iter; - for(gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.begin(); - gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.end(); - gps_alm_iter++) + std::map::const_iterator gps_alm_iter; + for (gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.cbegin(); + gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.cend(); + gps_alm_iter++) { - std::cout << "SUPL: Received Almanac for GPS SV " << gps_alm_iter->first << std::endl; + std::cout << "SUPL: Received almanac data for satellite " << Gnss_Satellite("GPS", gps_alm_iter->second.i_satellite_PRN) << std::endl; std::shared_ptr tmp_obj = std::make_shared(gps_alm_iter->second); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } + supl_client_ephemeris_.save_gps_almanac_xml("gps_almanac_map.xml", supl_client_ephemeris_.gps_almanac_map); if (supl_client_ephemeris_.gps_iono.valid == true) { - std::cout << "SUPL: Received GPS Iono" << std::endl; + std::cout << "SUPL: Received GPS Ionosphere model parameters" << std::endl; std::shared_ptr tmp_obj = std::make_shared(supl_client_ephemeris_.gps_iono); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } if (supl_client_ephemeris_.gps_utc.valid == true) { - std::cout << "SUPL: Received GPS UTC Model" << std::endl; + std::cout << "SUPL: Received GPS UTC model parameters" << std::endl; std::shared_ptr tmp_obj = std::make_shared(supl_client_ephemeris_.gps_utc); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); } + // Save iono and UTC model data to xml file + std::string iono_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_iono_xml", iono_default_xml_filename); + if (supl_client_ephemeris_.save_iono_xml(iono_xml_filename, supl_client_ephemeris_.gps_iono) == true) + { + std::cout << "SUPL: Iono data file created" << std::endl; + } + else + { + std::cout << "SUPL: Failed to create Iono data file" << std::endl; + } + std::string utc_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_utc_model_xml", utc_default_xml_filename); + if (supl_client_ephemeris_.save_utc_xml(utc_xml_filename, supl_client_ephemeris_.gps_utc) == true) + { + std::cout << "SUPL: UTC model data file created" << std::endl; + } + else + { + std::cout << "SUPL: Failed to create UTC model data file" << std::endl; + } } else { - std::cout << "ERROR: SUPL client for Almanac returned " << error << std::endl; - std::cout << "Please check internet connection and SUPL server configuration" << error << std::endl; - std::cout << "Disabling SUPL assistance." << std::endl; + std::cout << "ERROR: SUPL client for almanac data returned " << error << std::endl; + std::cout << "Please check your network connectivity and SUPL server configuration" << std::endl; } // Request acquisition assistance supl_client_acquisition_.request = 2; - std::cout << "SUPL: Try read Acquisition assistance from SUPL server..." << std::endl; + std::cout << "SUPL: Try to read acquisition assistance data from SUPL server..." << std::endl; error = supl_client_acquisition_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_acq_iter; - for(gps_acq_iter = supl_client_acquisition_.gps_acq_map.begin(); - gps_acq_iter != supl_client_acquisition_.gps_acq_map.end(); - gps_acq_iter++) + std::map::const_iterator gps_acq_iter; + for (gps_acq_iter = supl_client_acquisition_.gps_acq_map.cbegin(); + gps_acq_iter != supl_client_acquisition_.gps_acq_map.cend(); + gps_acq_iter++) { - std::cout << "SUPL: Received Acquisition assistance for GPS SV " << gps_acq_iter->first << std::endl; + std::cout << "SUPL: Received acquisition assistance data for satellite " << Gnss_Satellite("GPS", gps_acq_iter->second.i_satellite_PRN) << std::endl; global_gps_acq_assist_map.write(gps_acq_iter->second.i_satellite_PRN, gps_acq_iter->second); } if (supl_client_acquisition_.gps_ref_loc.valid == true) { - std::cout << "SUPL: Received Ref Location (Acquisition Assistance)" << std::endl; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_ref_loc); + std::cout << "SUPL: Received Ref Location data (Acquisition Assistance)" << std::endl; + agnss_ref_location_ = supl_client_acquisition_.gps_ref_loc; + std::shared_ptr tmp_obj = std::make_shared(agnss_ref_location_); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + supl_client_acquisition_.save_ref_location_xml("agnss_ref_location.xml", agnss_ref_location_); } if (supl_client_acquisition_.gps_time.valid == true) { - std::cout << "SUPL: Received Ref Time (Acquisition Assistance)" << std::endl; - std::shared_ptr tmp_obj = std::make_shared(supl_client_acquisition_.gps_time); + std::cout << "SUPL: Received Ref Time data (Acquisition Assistance)" << std::endl; + agnss_ref_time_ = supl_client_acquisition_.gps_time; + std::shared_ptr tmp_obj = std::make_shared(agnss_ref_time_); flowgraph_->send_telemetry_msg(pmt::make_any(tmp_obj)); + supl_client_acquisition_.save_ref_time_xml("agnss_ref_time.xml", agnss_ref_time_); } } else { - std::cout << "ERROR: SUPL client for Acquisition assistance returned " << error << std::endl; - std::cout << "Please check internet connection and SUPL server configuration" << error << std::endl; - std::cout << "Disabling SUPL assistance.." << std::endl; + std::cout << "ERROR: SUPL client for acquisition assistance returned " << error << std::endl; + std::cout << "Please check your network connectivity and SUPL server configuration" << std::endl; + std::cout << "Disabling SUPL acquisition assistance." << std::endl; } } } -} + if ((enable_gps_supl_assistance == false) and (enable_agnss_xml == true)) + { + // read assistance from file + if (read_assistance_from_XML()) + { + std::cout << "GNSS assistance data loaded from local XML file(s)." << std::endl; + } + } -void ControlThread::init() -{ - // Instantiates a control queue, a GNSS flowgraph, and a control message factory - control_queue_ = gr::msg_queue::make(0); - flowgraph_ = std::make_shared(configuration_, control_queue_); - control_message_factory_ = std::make_shared(); - stop_ = false; - processed_control_messages_ = 0; - applied_actions_ = 0; - supl_mcc = 0; - supl_mns = 0; - supl_lac = 0; - supl_ci = 0; - msqid = -1; + // If AGNSS is enabled, make use of it + if ((agnss_ref_location_.valid == true) and ((enable_gps_supl_assistance == true) or (enable_agnss_xml == true))) + { + // Get the list of visible satellites + arma::vec ref_LLH = arma::zeros(3, 1); + ref_LLH(0) = agnss_ref_location_.lat; + ref_LLH(1) = agnss_ref_location_.lon; + time_t ref_rx_utc_time = 0; + if (agnss_ref_time_.valid == true) + { + ref_rx_utc_time = static_cast(agnss_ref_time_.d_tv_sec); + } + + std::vector> visible_sats = get_visible_sats(ref_rx_utc_time, ref_LLH); + // Set the receiver in Standby mode + flowgraph_->apply_action(0, 10); + // Give priority to visible satellites in the search list + flowgraph_->priorize_satellites(visible_sats); + // Hot Start + flowgraph_->apply_action(0, 12); + } } void ControlThread::read_control_messages() { DLOG(INFO) << "Reading control messages from queue"; - boost::shared_ptr queue_message = control_queue_->delete_head(); + gr::message::sptr queue_message = control_queue_->delete_head(); if (queue_message != 0) { control_messages_ = control_message_factory_->GetControlMessages(queue_message); @@ -452,7 +781,6 @@ void ControlThread::read_control_messages() // Apply the corresponding control actions -// TODO: May be it is better to move the apply_action state machine to the control_thread void ControlThread::process_control_messages() { for (unsigned int i = 0; i < control_messages_->size(); i++) @@ -464,6 +792,10 @@ void ControlThread::process_control_messages() } else { + if (control_messages_->at(i)->who == 300) // some TC commands require also actions from control_thread + { + apply_action(control_messages_->at(i)->what); + } flowgraph_->apply_action(control_messages_->at(i)->who, control_messages_->at(i)->what); } processed_control_messages_++; @@ -475,17 +807,193 @@ void ControlThread::process_control_messages() void ControlThread::apply_action(unsigned int what) { + std::shared_ptr pvt_ptr; + std::vector> visible_satellites; switch (what) - { - case 0: - DLOG(INFO) << "Received action STOP"; - stop_ = true; - applied_actions_++; - break; - default: - DLOG(INFO) << "Unrecognized action."; - break; - } + { + case 0: + LOG(INFO) << "Received action STOP"; + stop_ = true; + applied_actions_++; + break; + case 1: + LOG(INFO) << "Received action RESTART"; + stop_ = true; + restart_ = true; + applied_actions_++; + break; + case 11: + LOG(INFO) << "Receiver action COLDSTART"; + // delete all ephemeris and almanac information from maps (also the PVT map queue) + pvt_ptr = flowgraph_->get_pvt(); + pvt_ptr->clear_ephemeris(); + // todo: reorder the satellite queues to the receiver default startup order. + // This is required to allow repeatability. Otherwise the satellite search order will depend on the last tracked satellites + break; + case 12: + LOG(INFO) << "Receiver action HOTSTART"; + visible_satellites = get_visible_sats(cmd_interface_.get_utc_time(), cmd_interface_.get_LLH()); + // reorder the satellite queue to acquire first those visible satellites + flowgraph_->priorize_satellites(visible_satellites); + // start again the satellite acquisitions (done in chained apply_action to flowgraph) + break; + case 13: + LOG(INFO) << "Receiver action WARMSTART"; + // delete all ephemeris and almanac information from maps (also the PVT map queue) + pvt_ptr = flowgraph_->get_pvt(); + pvt_ptr->clear_ephemeris(); + // load the ephemeris and the almanac from XML files (receiver assistance) + read_assistance_from_XML(); + // call here the function that computes the set of visible satellites and its elevation + // for the date and time specified by the warm start command and the assisted position + get_visible_sats(cmd_interface_.get_utc_time(), cmd_interface_.get_LLH()); + // reorder the satellite queue to acquire first those visible satellites + flowgraph_->priorize_satellites(visible_satellites); + // start again the satellite acquisitions (done in chained apply_action to flowgraph) + break; + default: + LOG(INFO) << "Unrecognized action."; + break; + } +} + + +std::vector> ControlThread::get_visible_sats(time_t rx_utc_time, const arma::vec &LLH) +{ + // 1. Compute rx ECEF position from LLH WGS84 + arma::vec LLH_rad = arma::vec{degtorad(LLH(0)), degtorad(LLH(1)), LLH(2)}; + arma::mat C_tmp = arma::zeros(3, 3); + arma::vec r_eb_e = arma::zeros(3, 1); + arma::vec v_eb_e = arma::zeros(3, 1); + Geo_to_ECEF(LLH_rad, arma::vec{0, 0, 0}, C_tmp, r_eb_e, v_eb_e, C_tmp); + + // 2. Compute rx GPS time from UTC time + gtime_t utc_gtime; + utc_gtime.time = rx_utc_time; + utc_gtime.sec = 0; + gtime_t gps_gtime = utc2gpst(utc_gtime); + + // 3. loop through all the available ephemeris or almanac and compute satellite positions and elevations + // store visible satellites in a vector of pairs to associate an elevation to the each satellite + std::vector> available_satellites; + std::vector visible_gps; + std::vector visible_gal; + std::shared_ptr pvt_ptr = flowgraph_->get_pvt(); + struct tm tstruct = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; + char buf[80]; + tstruct = *gmtime(&rx_utc_time); + strftime(buf, sizeof(buf), "%d/%m/%Y %H:%M:%S ", &tstruct); + std::string str_time = std::string(buf); + std::cout << "Get visible satellites at " << str_time + << "UTC, assuming RX position " << LLH(0) << " [deg], " << LLH(1) << " [deg], " << LLH(2) << " [m]" << std::endl; + + std::map gps_eph_map = pvt_ptr->get_gps_ephemeris(); + for (std::map::iterator it = gps_eph_map.begin(); it != gps_eph_map.end(); ++it) + { + eph_t rtklib_eph = eph_to_rtklib(it->second); + double r_sat[3]; + double clock_bias_s; + double sat_pos_variance_m2; + eph2pos(gps_gtime, &rtklib_eph, &r_sat[0], &clock_bias_s, + &sat_pos_variance_m2); + double Az, El, dist_m; + arma::vec r_sat_eb_e = arma::vec{r_sat[0], r_sat[1], r_sat[2]}; + arma::vec dx = r_sat_eb_e - r_eb_e; + topocent(&Az, &El, &dist_m, r_eb_e, dx); + // push sat + if (El > 0) + { + std::cout << "Using GPS Ephemeris: Sat " << it->second.i_satellite_PRN << " Az: " << Az << " El: " << El << std::endl; + available_satellites.push_back(std::pair(floor(El), + (Gnss_Satellite(std::string("GPS"), it->second.i_satellite_PRN)))); + visible_gps.push_back(it->second.i_satellite_PRN); + } + } + + std::map gal_eph_map = pvt_ptr->get_galileo_ephemeris(); + for (std::map::iterator it = gal_eph_map.begin(); it != gal_eph_map.end(); ++it) + { + eph_t rtklib_eph = eph_to_rtklib(it->second); + double r_sat[3]; + double clock_bias_s; + double sat_pos_variance_m2; + eph2pos(gps_gtime, &rtklib_eph, &r_sat[0], &clock_bias_s, + &sat_pos_variance_m2); + double Az, El, dist_m; + arma::vec r_sat_eb_e = arma::vec{r_sat[0], r_sat[1], r_sat[2]}; + arma::vec dx = r_sat_eb_e - r_eb_e; + topocent(&Az, &El, &dist_m, r_eb_e, dx); + // push sat + if (El > 0) + { + std::cout << "Using Galileo Ephemeris: Sat " << it->second.i_satellite_PRN << " Az: " << Az << " El: " << El << std::endl; + available_satellites.push_back(std::pair(floor(El), + (Gnss_Satellite(std::string("Galileo"), it->second.i_satellite_PRN)))); + visible_gal.push_back(it->second.i_satellite_PRN); + } + } + + std::map gps_alm_map = pvt_ptr->get_gps_almanac(); + for (std::map::iterator it = gps_alm_map.begin(); it != gps_alm_map.end(); ++it) + { + alm_t rtklib_alm = alm_to_rtklib(it->second); + double r_sat[3]; + double clock_bias_s; + gtime_t aux_gtime; + aux_gtime.time = fmod(utc2gpst(gps_gtime).time + 345600, 604800); + alm2pos(aux_gtime, &rtklib_alm, &r_sat[0], &clock_bias_s); + double Az, El, dist_m; + arma::vec r_sat_eb_e = arma::vec{r_sat[0], r_sat[1], r_sat[2]}; + arma::vec dx = r_sat_eb_e - r_eb_e; + topocent(&Az, &El, &dist_m, r_eb_e, dx); + // push sat + std::vector::iterator it2; + if (El > 0) + { + it2 = std::find(visible_gps.begin(), visible_gps.end(), it->second.i_satellite_PRN); + if (it2 == visible_gps.end()) + { + std::cout << "Using GPS Almanac: Sat " << it->second.i_satellite_PRN << " Az: " << Az << " El: " << El << std::endl; + available_satellites.push_back(std::pair(floor(El), + (Gnss_Satellite(std::string("GPS"), it->second.i_satellite_PRN)))); + } + } + } + + std::map gal_alm_map = pvt_ptr->get_galileo_almanac(); + for (std::map::iterator it = gal_alm_map.begin(); it != gal_alm_map.end(); ++it) + { + alm_t rtklib_alm = alm_to_rtklib(it->second); + double r_sat[3]; + double clock_bias_s; + gtime_t gal_gtime; + gal_gtime.time = fmod(utc2gpst(gps_gtime).time + 345600, 604800); + alm2pos(gal_gtime, &rtklib_alm, &r_sat[0], &clock_bias_s); + double Az, El, dist_m; + arma::vec r_sat_eb_e = arma::vec{r_sat[0], r_sat[1], r_sat[2]}; + arma::vec dx = r_sat_eb_e - r_eb_e; + topocent(&Az, &El, &dist_m, r_eb_e, dx); + // push sat + std::vector::iterator it2; + if (El > 0) + { + it2 = std::find(visible_gal.begin(), visible_gal.end(), it->second.i_satellite_PRN); + if (it2 == visible_gal.end()) + { + std::cout << "Using Galileo Almanac: Sat " << it->second.i_satellite_PRN << " Az: " << Az << " El: " << El << std::endl; + available_satellites.push_back(std::pair(floor(El), + (Gnss_Satellite(std::string("Galileo"), it->second.i_satellite_PRN)))); + } + } + } + + // sort the visible satellites in ascending order of elevation + std::sort(available_satellites.begin(), available_satellites.end(), [](const std::pair &a, const std::pair &b) { // use lambda. Cleaner and easier to read + return a.first < b.first; + }); + // provide list starting from satellites with higher elevation + std::reverse(available_satellites.begin(), available_satellites.end()); + return available_satellites; } @@ -494,19 +1002,19 @@ void ControlThread::gps_acq_assist_data_collector() // ############ 1.bis READ EPHEMERIS/UTC_MODE/IONO QUEUE #################### Gps_Acq_Assist gps_acq; Gps_Acq_Assist gps_acq_old; - while(stop_ == false) + while (stop_ == false) { global_gps_acq_assist_queue.wait_and_pop(gps_acq); - if(gps_acq.i_satellite_PRN == 0) break; + if (gps_acq.i_satellite_PRN == 0) break; // DEBUG MESSAGE std::cout << "Acquisition assistance record has arrived from SAT ID " << gps_acq.i_satellite_PRN << " with Doppler " << gps_acq.d_Doppler0 - << " [Hz] "<< std::endl; + << " [Hz] " << std::endl; // insert new acq record to the global ephemeris map - if (global_gps_acq_assist_map.read(gps_acq.i_satellite_PRN,gps_acq_old)) + if (global_gps_acq_assist_map.read(gps_acq.i_satellite_PRN, gps_acq_old)) { std::cout << "Acquisition assistance record updated" << std::endl; global_gps_acq_assist_map.write(gps_acq.i_satellite_PRN, gps_acq); @@ -523,8 +1031,9 @@ void ControlThread::gps_acq_assist_data_collector() void ControlThread::sysv_queue_listener() { - typedef struct { - long mtype; // required by SysV queue messaging + typedef struct + { + long mtype; // required by SysV queue messaging double stop_message; } stop_msgbuf; @@ -535,18 +1044,18 @@ void ControlThread::sysv_queue_listener() key_t key = 1102; - if((msqid = msgget(key, 0644 | IPC_CREAT )) == -1) + if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) { perror("GNSS-SDR cannot create SysV message queues"); exit(1); } - while(read_queue && !stop_) + while (read_queue && !stop_) { if (msgrcv(msqid, &msg, msgrcv_size, 1, 0) != -1) { received_message = msg.stop_message; - if( (std::abs(received_message - (-200.0)) < 10 * std::numeric_limits::epsilon()) ) + if ((std::abs(received_message - (-200.0)) < 10 * std::numeric_limits::epsilon())) { std::cout << "Quit order received, stopping GNSS-SDR !!" << std::endl; std::unique_ptr cmf(new ControlMessageFactory()); @@ -565,7 +1074,7 @@ void ControlThread::keyboard_listener() { bool read_keys = true; char c = '0'; - while(read_keys && !stop_) + while (read_keys && !stop_) { std::cin.get(c); if (c == 'q') diff --git a/src/core/receiver/control_thread.h b/src/core/receiver/control_thread.h index 1580695df..b500e43fa 100644 --- a/src/core/receiver/control_thread.h +++ b/src/core/receiver/control_thread.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,15 +35,19 @@ #ifndef GNSS_SDR_CONTROL_THREAD_H_ #define GNSS_SDR_CONTROL_THREAD_H_ -#include -#include +#include "agnss_ref_location.h" +#include "agnss_ref_time.h" +#include "configuration_interface.h" +#include "control_message_factory.h" +#include "gnss_flowgraph.h" +#include "gnss_satellite.h" +#include "gnss_sdr_supl_client.h" +#include "tcp_cmd_interface.h" +#include #include #include -#include "control_message_factory.h" -#include "gnss_sdr_supl_client.h" - -class GNSSFlowgraph; -class ConfigurationInterface; +#include +#include /*! @@ -82,14 +86,14 @@ public: * * - Read control messages and process them; } */ - void run(); + int run(); /*! * \brief Sets the control_queue * * \param[in] boost::shared_ptr control_queue */ - void set_control_queue(boost::shared_ptr control_queue); + void set_control_queue(const gr::msg_queue::sptr& control_queue); unsigned int processed_control_messages() @@ -113,13 +117,17 @@ public: } private: + //Telecommand TCP interface + TcpCmdInterface cmd_interface_; + void telecommand_listener(); + boost::thread cmd_interface_thread_; //SUPL assistance classes gnss_sdr_supl_client supl_client_acquisition_; gnss_sdr_supl_client supl_client_ephemeris_; - int supl_mcc; // Current network MCC (Mobile country code), 3 digits. - int supl_mns; // Current network MNC (Mobile Network code), 2 or 3 digits. - int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values. - int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values). + int supl_mcc; // Current network MCC (Mobile country code), 3 digits. + int supl_mns; // Current network MNC (Mobile Network code), 2 or 3 digits. + int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values. + int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values). void init(); @@ -137,26 +145,33 @@ private: * Blocking function that reads the GPS assistance queue */ void gps_acq_assist_data_collector(); - + + /* + * Compute elevations for the specified time and position for all the available satellites in ephemeris and almanac queues + * returns a vector filled with the available satellites ordered from high elevation to low elevation angle. + */ + std::vector> get_visible_sats(time_t rx_utc_time, const arma::vec& LLH); + /* * Read initial GNSS assistance from SUPL server or local XML files */ void assist_GNSS(); - + void apply_action(unsigned int what); std::shared_ptr flowgraph_; std::shared_ptr configuration_; - boost::shared_ptr control_queue_; + gr::msg_queue::sptr control_queue_; std::shared_ptr control_message_factory_; std::shared_ptr>> control_messages_; bool stop_; + bool restart_; bool delete_configuration_; unsigned int processed_control_messages_; unsigned int applied_actions_; boost::thread keyboard_thread_; boost::thread sysv_queue_thread_; boost::thread gps_acq_assist_data_collector_thread_; - + void keyboard_listener(); void sysv_queue_listener(); int msqid; @@ -167,6 +182,18 @@ private: const std::string iono_default_xml_filename = "./gps_iono.xml"; const std::string ref_time_default_xml_filename = "./gps_ref_time.xml"; const std::string ref_location_default_xml_filename = "./gps_ref_location.xml"; + const std::string eph_gal_default_xml_filename = "./gal_ephemeris.xml"; + const std::string eph_cnav_default_xml_filename = "./gps_cnav_ephemeris.xml"; + const std::string gal_iono_default_xml_filename = "./gal_iono.xml"; + const std::string gal_utc_default_xml_filename = "./gal_utc_model.xml"; + const std::string cnav_utc_default_xml_filename = "./gps_cnav_utc_model.xml"; + const std::string eph_glo_gnav_default_xml_filename = "./glo_gnav_ephemeris.xml"; + const std::string glo_utc_default_xml_filename = "./glo_utc_model.xml"; + const std::string gal_almanac_default_xml_filename = "./gal_almanac.xml"; + const std::string gps_almanac_default_xml_filename = "./gps_almanac.xml"; + + Agnss_Ref_Location agnss_ref_location_; + Agnss_Ref_Time agnss_ref_time_; }; #endif /*GNSS_SDR_CONTROL_THREAD_H_*/ diff --git a/src/core/receiver/file_configuration.cc b/src/core/receiver/file_configuration.cc index 4285d04f1..62992c074 100644 --- a/src/core/receiver/file_configuration.cc +++ b/src/core/receiver/file_configuration.cc @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,23 +28,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "file_configuration.h" -#include -#include #include "INIReader.h" -#include "string_converter.h" #include "in_memory_configuration.h" +#include "string_converter.h" +#include +#include + using google::LogMessage; FileConfiguration::FileConfiguration(std::string filename) { - filename_ = filename; + filename_ = std::move(filename); init(); } @@ -64,138 +65,130 @@ FileConfiguration::~FileConfiguration() std::string FileConfiguration::property(std::string property_name, std::string default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - return ini_reader_->Get("GNSS-SDR", property_name, default_value); - } + return ini_reader_->Get("GNSS-SDR", property_name, default_value); } bool FileConfiguration::property(std::string property_name, bool default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } -long FileConfiguration::property(std::string property_name, long default_value) +int64_t FileConfiguration::property(std::string property_name, int64_t default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } +uint64_t FileConfiguration::property(std::string property_name, uint64_t default_value) +{ + if (overrided_->is_present(property_name)) + { + return overrided_->property(property_name, default_value); + } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); +} + int FileConfiguration::property(std::string property_name, int default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } - unsigned int FileConfiguration::property(std::string property_name, unsigned int default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } - -unsigned short FileConfiguration::property(std::string property_name, unsigned short default_value) +uint16_t FileConfiguration::property(std::string property_name, uint16_t default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } +int16_t FileConfiguration::property(std::string property_name, int16_t default_value) +{ + if (overrided_->is_present(property_name)) + { + return overrided_->property(property_name, default_value); + } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); +} + float FileConfiguration::property(std::string property_name, float default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } double FileConfiguration::property(std::string property_name, double default_value) { - if(overrided_->is_present(property_name)) + if (overrided_->is_present(property_name)) { return overrided_->property(property_name, default_value); } - else - { - std::string empty = ""; - return converter_->convert(property(property_name, empty), default_value); - } + std::string empty; + return converter_->convert(property(property_name, empty), default_value); } - void FileConfiguration::set_property(std::string property_name, std::string value) { overrided_->set_property(property_name, value); } - void FileConfiguration::init() { std::unique_ptr converter_(new StringConverter); overrided_ = std::make_shared(); ini_reader_ = std::make_shared(filename_); error_ = ini_reader_->ParseError(); - if(error_ == 0) + if (error_ == 0) { DLOG(INFO) << "Configuration file " << filename_ << " opened with no errors"; } - else if(error_ > 0) + else if (error_ > 0) { LOG(WARNING) << "Configuration file " << filename_ << " contains errors in line " << error_; } @@ -204,5 +197,3 @@ void FileConfiguration::init() LOG(WARNING) << "Unable to open configuration file " << filename_; } } - - diff --git a/src/core/receiver/file_configuration.h b/src/core/receiver/file_configuration.h index a968305d5..0e2ccb53e 100644 --- a/src/core/receiver/file_configuration.h +++ b/src/core/receiver/file_configuration.h @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,17 +27,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #ifndef GNSS_SDR_FILE_CONFIGURATION_H_ #define GNSS_SDR_FILE_CONFIGURATION_H_ #include "configuration_interface.h" +#include #include #include @@ -60,16 +60,19 @@ public: FileConfiguration(std::string filename); FileConfiguration(); //! Virtual destructor - ~FileConfiguration(); + ~FileConfiguration(); std::string property(std::string property_name, std::string default_value); bool property(std::string property_name, bool default_value); - long property(std::string property_name, long default_value); - int property(std::string property_name, int default_value); - unsigned int property(std::string property_name, unsigned int default_value); - unsigned short property(std::string property_name, unsigned short default_value); + int64_t property(std::string property_name, int64_t default_value); + uint64_t property(std::string property_name, uint64_t default_value); + int32_t property(std::string property_name, int32_t default_value); + uint32_t property(std::string property_name, uint32_t default_value); + int16_t property(std::string property_name, int16_t default_value); + uint16_t property(std::string property_name, uint16_t default_value); float property(std::string property_name, float default_value); double property(std::string property_name, double default_value); void set_property(std::string property_name, std::string value); + private: void init(); std::string filename_; diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 8df7faf88..fac2d38d9 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -4,13 +4,14 @@ * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Luis Esteve, 2012. luis(at)epsilon-formacion.com * Javier Arribas, 2011. jarribas(at)cttc.es + * Marc Majoral, 2018. mmajoral(at)cttc.es * * This class encapsulates the complexity behind the instantiation * of GNSS blocks. * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,75 +29,98 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gnss_block_factory.h" -#include -#include -#include -#include -#include -#include "configuration_interface.h" -#include "in_memory_configuration.h" -#include "gnss_block_interface.h" -#include "pass_through.h" -#include "file_signal_source.h" -#include "nsr_file_signal_source.h" -#include "two_bit_cpx_file_signal_source.h" -#include "spir_file_signal_source.h" -#include "rtl_tcp_signal_source.h" -#include "two_bit_packed_file_signal_source.h" -#include "channel.h" - -#include "signal_conditioner.h" #include "array_signal_conditioner.h" +#include "beamformer_filter.h" #include "byte_to_short.h" -#include "ibyte_to_cbyte.h" -#include "ibyte_to_cshort.h" -#include "ibyte_to_complex.h" -#include "ishort_to_cshort.h" -#include "ishort_to_complex.h" +#include "channel.h" +#include "configuration_interface.h" #include "direct_resampler_conditioner.h" +#include "file_signal_source.h" #include "fir_filter.h" #include "freq_xlating_fir_filter.h" -#include "beamformer_filter.h" -#include "gps_l1_ca_pcps_acquisition.h" -#include "gps_l2_m_pcps_acquisition.h" -#include "gps_l1_ca_pcps_multithread_acquisition.h" -#include "gps_l1_ca_pcps_tong_acquisition.h" -#include "gps_l1_ca_pcps_assisted_acquisition.h" -#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" -#include "gps_l1_ca_pcps_quicksync_acquisition.h" -#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "galileo_e1_dll_pll_veml_tracking.h" #include "galileo_e1_pcps_8ms_ambiguous_acquisition.h" -#include "galileo_e1_pcps_tong_ambiguous_acquisition.h" +#include "galileo_e1_pcps_ambiguous_acquisition.h" #include "galileo_e1_pcps_cccwsr_ambiguous_acquisition.h" #include "galileo_e1_pcps_quicksync_ambiguous_acquisition.h" -#include "galileo_e5a_noncoherent_iq_acquisition_caf.h" -#include "gps_l1_ca_dll_pll_tracking.h" -#include "gps_l1_ca_dll_pll_c_aid_tracking.h" -#include "gps_l1_ca_tcp_connector_tracking.h" -#include "galileo_e1_dll_pll_veml_tracking.h" +#include "galileo_e1_pcps_tong_ambiguous_acquisition.h" #include "galileo_e1_tcp_connector_tracking.h" -#include "galileo_e5a_dll_pll_tracking.h" -#include "gps_l2_m_dll_pll_tracking.h" -#include "gps_l1_ca_telemetry_decoder.h" -#include "gps_l2c_telemetry_decoder.h" #include "galileo_e1b_telemetry_decoder.h" +#include "galileo_e5a_dll_pll_tracking.h" +#include "galileo_e5a_noncoherent_iq_acquisition_caf.h" +#include "galileo_e5a_pcps_acquisition.h" #include "galileo_e5a_telemetry_decoder.h" -#include "sbas_l1_telemetry_decoder.h" -#include "gps_l1_ca_observables.h" -#include "gps_l2c_observables.h" -#include "galileo_e1_observables.h" -#include "galileo_e5a_observables.h" +#include "glonass_l1_ca_dll_pll_c_aid_tracking.h" +#include "glonass_l1_ca_dll_pll_tracking.h" +#include "glonass_l1_ca_pcps_acquisition.h" +#include "glonass_l1_ca_telemetry_decoder.h" +#include "glonass_l2_ca_dll_pll_c_aid_tracking.h" +#include "glonass_l2_ca_dll_pll_tracking.h" +#include "glonass_l2_ca_pcps_acquisition.h" +#include "glonass_l2_ca_telemetry_decoder.h" +#include "gnss_block_interface.h" +#include "gps_l1_ca_dll_pll_c_aid_tracking.h" +#include "gps_l1_ca_dll_pll_tracking.h" +#include "gps_l1_ca_kf_tracking.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" +#include "gps_l1_ca_pcps_assisted_acquisition.h" +#include "gps_l1_ca_pcps_quicksync_acquisition.h" +#include "gps_l1_ca_pcps_tong_acquisition.h" +#include "gps_l1_ca_tcp_connector_tracking.h" +#include "gps_l1_ca_telemetry_decoder.h" +#include "gps_l2_m_dll_pll_tracking.h" +#include "gps_l2_m_pcps_acquisition.h" +#include "gps_l2c_telemetry_decoder.h" +#include "gps_l5_dll_pll_tracking.h" +#include "gps_l5_telemetry_decoder.h" +#include "gps_l5i_pcps_acquisition.h" #include "hybrid_observables.h" -#include "gps_l1_ca_pvt.h" -#include "galileo_e1_pvt.h" -#include "hybrid_pvt.h" +#include "ibyte_to_cbyte.h" +#include "ibyte_to_complex.h" +#include "ibyte_to_cshort.h" +#include "in_memory_configuration.h" +#include "ishort_to_complex.h" +#include "ishort_to_cshort.h" +#include "labsat_signal_source.h" +#include "mmse_resampler_conditioner.h" +#include "notch_filter.h" +#include "notch_filter_lite.h" +#include "nsr_file_signal_source.h" +#include "pass_through.h" +#include "pulse_blanking_filter.h" +#include "rtklib_pvt.h" +#include "rtl_tcp_signal_source.h" +#include "sbas_l1_telemetry_decoder.h" +#include "signal_conditioner.h" +#include "spir_file_signal_source.h" +#include "spir_gss6450_file_signal_source.h" +#include "two_bit_cpx_file_signal_source.h" +#include "two_bit_packed_file_signal_source.h" + +#if RAW_UDP +#include "custom_udp_signal_source.h" +#endif + +#if ENABLE_FPGA +#include "galileo_e1_dll_pll_veml_tracking_fpga.h" +#include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" +#include "galileo_e5a_dll_pll_tracking_fpga.h" +#include "galileo_e5a_pcps_acquisition_fpga.h" +#include "gps_l1_ca_dll_pll_tracking_fpga.h" +#include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "gps_l2_m_dll_pll_tracking_fpga.h" +#include "gps_l2_m_pcps_acquisition_fpga.h" +#include "gps_l5_dll_pll_tracking_fpga.h" +#include "gps_l5i_pcps_acquisition_fpga.h" +#endif #if OPENCL_BLOCKS #include "gps_l1_ca_pcps_opencl_acquisition.h" @@ -118,6 +142,18 @@ #include "uhd_signal_source.h" #endif +#if PLUTOSDR_DRIVER +#include "plutosdr_signal_source.h" +#endif + +#if FMCOMMS2_DRIVER +#include "fmcomms2_signal_source.h" +#endif + +#if AD9361_DRIVER +#include "ad9361_fpga_signal_source.h" +#endif + #if FLEXIBAND_DRIVER #include "flexiband_signal_source.h" #endif @@ -126,26 +162,36 @@ #include "gps_l1_ca_dll_pll_tracking_gpu.h" #endif +#include +#include +#include +#include + using google::LogMessage; -GNSSBlockFactory::GNSSBlockFactory() -{} +GNSSBlockFactory::GNSSBlockFactory() = default; -GNSSBlockFactory::~GNSSBlockFactory() -{} +GNSSBlockFactory::~GNSSBlockFactory() = default; std::unique_ptr GNSSBlockFactory::GetSignalSource( - std::shared_ptr configuration, boost::shared_ptr queue, int ID) + std::shared_ptr configuration, gr::msg_queue::sptr queue, int ID) { std::string default_implementation = "File_Signal_Source"; - std::string role = "SignalSource"; //backwards compatibility for old conf files - if (ID != -1) + std::string role = "SignalSource"; //backwards compatibility for old conf files + try { - role = "SignalSource" + boost::lexical_cast(ID); + if (ID != -1) + { + role = "SignalSource" + std::to_string(ID); + } + } + catch (const std::exception &e) + { + LOG(WARNING) << e.what(); } std::string implementation = configuration->property(role + ".implementation", default_implementation); LOG(INFO) << "Getting SignalSource with implementation " << implementation; @@ -153,31 +199,35 @@ std::unique_ptr GNSSBlockFactory::GetSignalSource( } - std::unique_ptr GNSSBlockFactory::GetSignalConditioner( - std::shared_ptr configuration, int ID) + std::shared_ptr configuration, int ID) { std::string default_implementation = "Pass_Through"; //backwards compatibility for old conf files - std::string role_conditioner = "SignalConditioner" ; + std::string role_conditioner = "SignalConditioner"; std::string role_datatypeadapter = "DataTypeAdapter"; std::string role_inputfilter = "InputFilter"; std::string role_resampler = "Resampler"; - - if (ID != -1) + try { - role_conditioner = "SignalConditioner" + boost::lexical_cast(ID); - role_datatypeadapter = "DataTypeAdapter" + boost::lexical_cast(ID); - role_inputfilter = "InputFilter" + boost::lexical_cast(ID); - role_resampler = "Resampler" + boost::lexical_cast(ID); + if (ID != -1) + { + role_conditioner = "SignalConditioner" + std::to_string(ID); + role_datatypeadapter = "DataTypeAdapter" + std::to_string(ID); + role_inputfilter = "InputFilter" + std::to_string(ID); + role_resampler = "Resampler" + std::to_string(ID); + } + } + catch (const std::exception &e) + { + LOG(WARNING) << e.what(); } - std::string signal_conditioner = configuration->property(role_conditioner + ".implementation", default_implementation); std::string data_type_adapter; std::string input_filter; std::string resampler; - if(signal_conditioner.compare("Pass_Through") == 0) + if (signal_conditioner == "Pass_Through") { data_type_adapter = "Pass_Through"; input_filter = "Pass_Through"; @@ -191,17 +241,17 @@ std::unique_ptr GNSSBlockFactory::GetSignalConditioner( } LOG(INFO) << "Getting SignalConditioner with DataTypeAdapter implementation: " - << data_type_adapter << ", InputFilter implementation: " - << input_filter << ", and Resampler implementation: " - << resampler; + << data_type_adapter << ", InputFilter implementation: " + << input_filter << ", and Resampler implementation: " + << resampler; - if(signal_conditioner.compare("Array_Signal_Conditioner") == 0) + if (signal_conditioner == "Array_Signal_Conditioner") { //instantiate the array version std::unique_ptr conditioner_(new ArraySignalConditioner(configuration.get(), - std::move(GetBlock(configuration, role_datatypeadapter, data_type_adapter, 1, 1)), - std::move(GetBlock(configuration, role_inputfilter, input_filter, 1, 1)), - std::move(GetBlock(configuration, role_resampler, resampler, 1, 1)), + GetBlock(configuration, role_datatypeadapter, data_type_adapter, 1, 1), + GetBlock(configuration, role_inputfilter, input_filter, 1, 1), + GetBlock(configuration, role_resampler, resampler, 1, 1), role_conditioner, "Signal_Conditioner")); return conditioner_; } @@ -209,80 +259,90 @@ std::unique_ptr GNSSBlockFactory::GetSignalConditioner( { //single-antenna version std::unique_ptr conditioner_(new SignalConditioner(configuration.get(), - std::move(GetBlock(configuration, role_datatypeadapter, data_type_adapter, 1, 1)), - std::move(GetBlock(configuration, role_inputfilter, input_filter, 1, 1)), - std::move(GetBlock(configuration, role_resampler, resampler, 1, 1)), + GetBlock(configuration, role_datatypeadapter, data_type_adapter, 1, 1), + GetBlock(configuration, role_inputfilter, input_filter, 1, 1), + GetBlock(configuration, role_resampler, resampler, 1, 1), role_conditioner, "Signal_Conditioner")); return conditioner_; } } - std::unique_ptr GNSSBlockFactory::GetObservables(std::shared_ptr configuration) { - std::string default_implementation = "GPS_L1_CA_Observables"; + std::string default_implementation = "Hybrid_Observables"; std::string implementation = configuration->property("Observables.implementation", default_implementation); LOG(INFO) << "Getting Observables with implementation " << implementation; unsigned int Galileo_channels = configuration->property("Channels_1B.count", 0); Galileo_channels += configuration->property("Channels_5X.count", 0); unsigned int GPS_channels = configuration->property("Channels_1C.count", 0); GPS_channels += configuration->property("Channels_2S.count", 0); - return GetBlock(configuration, "Observables", implementation, Galileo_channels + GPS_channels, Galileo_channels + GPS_channels); + GPS_channels += configuration->property("Channels_L5.count", 0); + unsigned int Glonass_channels = configuration->property("Channels_1G.count", 0); + unsigned int extra_channels = 1; // For monitor channel sample counter + return GetBlock(configuration, "Observables", implementation, + Galileo_channels + + GPS_channels + + Glonass_channels + + extra_channels, + Galileo_channels + + GPS_channels + + Glonass_channels); } - std::unique_ptr GNSSBlockFactory::GetPVT(std::shared_ptr configuration) { - std::string default_implementation = "Pass_Through"; + std::string default_implementation = "RTKLIB_PVT"; std::string implementation = configuration->property("PVT.implementation", default_implementation); LOG(INFO) << "Getting PVT with implementation " << implementation; - unsigned int Galileo_channels =configuration->property("Channels_1B.count", 0); + unsigned int Galileo_channels = configuration->property("Channels_1B.count", 0); Galileo_channels += configuration->property("Channels_5X.count", 0); - unsigned int GPS_channels =configuration->property("Channels_1C.count", 0); + unsigned int GPS_channels = configuration->property("Channels_1C.count", 0); GPS_channels += configuration->property("Channels_2S.count", 0); - return GetBlock(configuration, "PVT", implementation, Galileo_channels + GPS_channels, 1); + GPS_channels += configuration->property("Channels_L5.count", 0); + unsigned int Glonass_channels = configuration->property("Channels_1G.count", 0); + return GetBlock(configuration, "PVT", implementation, Galileo_channels + GPS_channels + Glonass_channels, 0); } //********* GPS L1 C/A CHANNEL ***************** std::unique_ptr GNSSBlockFactory::GetChannel_1C( - std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue) + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue) { //"appendix" is added to the "role" with the aim of Acquisition, Tracking and Telemetry Decoder adapters //can find their specific configurations when they read the config //TODO: REMOVE APPENDIX!! AND CHECK ALTERNATIVE MECHANISM TO GET PARTICULARIZED PARAMETERS LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " - << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; - std::string aux = configuration->property("Acquisition_1C" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + std::string aux = configuration->property("Acquisition_1C" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix1; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix1 = boost::lexical_cast(channel); + appendix1 = std::to_string(channel); } else { appendix1 = ""; } - aux = configuration->property("Tracking_1C" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("Tracking_1C" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix2; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix2 = boost::lexical_cast(channel); + appendix2 = std::to_string(channel); } else { appendix2 = ""; } - aux = configuration->property("TelemetryDecoder_1C" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("TelemetryDecoder_1C" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix3; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix3 = boost::lexical_cast(channel); + appendix3 = std::to_string(channel); } else { @@ -294,60 +354,59 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1C( std::string default_item_type = "gr_complex"; std::string acq_item_type = configuration->property("Acquisition_1C" + appendix1 + ".item_type", default_item_type); std::string trk_item_type = configuration->property("Tracking_1C" + appendix2 + ".item_type", default_item_type); - if(acq_item_type.compare(trk_item_type)) + if (acq_item_type != trk_item_type) { LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; } config->set_property("Channel.item_type", acq_item_type); - std::unique_ptr pass_through_ = GetBlock(config, "Channel", "Pass_Through", 1, 1, queue); std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_1C" + appendix1, acq, 1, 0); - std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_1C"+ appendix2, trk, 1, 1); + std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_1C" + appendix2, trk, 1, 1); std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_1C" + appendix3, tlm, 1, 1); - std::unique_ptr channel_(new Channel(configuration.get(), channel, std::move(pass_through_), - std::move(acq_), - std::move(trk_), - std::move(tlm_), - "Channel", "1C", queue)); + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "1C", queue)); return channel_; } + //********* GPS L2C (M) CHANNEL ***************** std::unique_ptr GNSSBlockFactory::GetChannel_2S( - std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue) + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue) { - LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " - << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; - std::string aux = configuration->property("Acquisition_2S" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + std::string aux = configuration->property("Acquisition_2S" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix1; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix1 = boost::lexical_cast(channel); + appendix1 = std::to_string(channel); } else { appendix1 = ""; } - aux = configuration->property("Tracking_2S" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("Tracking_2S" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix2; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix2 = boost::lexical_cast(channel); + appendix2 = std::to_string(channel); } else { appendix2 = ""; } - aux = configuration->property("TelemetryDecoder_2S" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("TelemetryDecoder_2S" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix3; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix3 = boost::lexical_cast(channel); + appendix3 = std::to_string(channel); } else { @@ -359,62 +418,62 @@ std::unique_ptr GNSSBlockFactory::GetChannel_2S( std::string default_item_type = "gr_complex"; std::string acq_item_type = configuration->property("Acquisition_2S" + appendix1 + ".item_type", default_item_type); std::string trk_item_type = configuration->property("Tracking_2S" + appendix2 + ".item_type", default_item_type); - if(acq_item_type.compare(trk_item_type)) + if (acq_item_type != trk_item_type) { LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; } config->set_property("Channel.item_type", acq_item_type); - std::unique_ptr pass_through_ = GetBlock(configuration, "Channel", "Pass_Through", 1, 1, queue); - std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_2S" + appendix1 , acq, 1, 0); + std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_2S" + appendix1, acq, 1, 0); std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_2S" + appendix2, trk, 1, 1); std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_2S" + appendix3, tlm, 1, 1); - std::unique_ptr channel_(new Channel(configuration.get(), channel, std::move(pass_through_), - std::move(acq_), - std::move(trk_), - std::move(tlm_), - "Channel", "2S", queue)); + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "2S", queue)); return channel_; } + //********* GALILEO E1 B CHANNEL ***************** std::unique_ptr GNSSBlockFactory::GetChannel_1B( - std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue) + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue) { std::stringstream stream; stream << channel; std::string id = stream.str(); LOG(INFO) << "Instantiating Channel " << id << " with Acquisition Implementation: " - << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; - std::string aux = configuration->property("Acquisition_1B" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + std::string aux = configuration->property("Acquisition_1B" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix1; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix1 = boost::lexical_cast(channel); + appendix1 = std::to_string(channel); } else { appendix1 = ""; } - aux = configuration->property("Tracking_1B" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("Tracking_1B" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix2; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix2 = boost::lexical_cast(channel); + appendix2 = std::to_string(channel); } else { appendix2 = ""; } - aux = configuration->property("TelemetryDecoder_1B" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("TelemetryDecoder_1B" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix3; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix3 = boost::lexical_cast(channel); + appendix3 = std::to_string(channel); } else { @@ -426,62 +485,62 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1B( std::string default_item_type = "gr_complex"; std::string acq_item_type = configuration->property("Acquisition_1B" + appendix1 + ".item_type", default_item_type); std::string trk_item_type = configuration->property("Tracking_1B" + appendix2 + ".item_type", default_item_type); - if(acq_item_type.compare(trk_item_type)) + if (acq_item_type != trk_item_type) { LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; } config->set_property("Channel.item_type", acq_item_type); - std::unique_ptr pass_through_ = GetBlock(configuration, "Channel", "Pass_Through", 1, 1, queue); std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_1B" + appendix1, acq, 1, 0); std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_1B" + appendix2, trk, 1, 1); std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_1B" + appendix3, tlm, 1, 1); - std::unique_ptr channel_(new Channel(configuration.get(), channel, std::move(pass_through_), - std::move(acq_), - std::move(trk_), - std::move(tlm_), - "Channel", "1B", queue)); + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "1B", queue)); return channel_; } + //********* GALILEO E5a CHANNEL ***************** std::unique_ptr GNSSBlockFactory::GetChannel_5X( - std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue) + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue) { std::stringstream stream; stream << channel; std::string id = stream.str(); LOG(INFO) << "Instantiating Channel " << id << " with Acquisition Implementation: " - << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; - std::string aux = configuration->property("Acquisition_5X" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + std::string aux = configuration->property("Acquisition_5X" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix1; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix1 = boost::lexical_cast(channel); + appendix1 = std::to_string(channel); } else { appendix1 = ""; } - aux = configuration->property("Tracking_5X" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("Tracking_5X" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix2; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix2 = boost::lexical_cast(channel); + appendix2 = std::to_string(channel); } else { appendix2 = ""; } - aux = configuration->property("TelemetryDecoder_5X" + boost::lexical_cast(channel) + ".implementation", std::string("W")); + aux = configuration->property("TelemetryDecoder_5X" + std::to_string(channel) + ".implementation", std::string("W")); std::string appendix3; - if(aux.compare("W") != 0) + if (aux != "W") { - appendix3 = boost::lexical_cast(channel); + appendix3 = std::to_string(channel); } else { @@ -493,29 +552,231 @@ std::unique_ptr GNSSBlockFactory::GetChannel_5X( std::string default_item_type = "gr_complex"; std::string acq_item_type = configuration->property("Acquisition_5X" + appendix1 + ".item_type", default_item_type); std::string trk_item_type = configuration->property("Tracking_5X" + appendix2 + ".item_type", default_item_type); - if(acq_item_type.compare(trk_item_type)) + if (acq_item_type != trk_item_type) { LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; } config->set_property("Channel.item_type", acq_item_type); - std::unique_ptr pass_through_ = GetBlock(configuration, "Channel", "Pass_Through", 1, 1, queue); std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_5X" + appendix1, acq, 1, 0); std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_5X" + appendix2, trk, 1, 1); std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_5X" + appendix3, tlm, 1, 1); - std::unique_ptr channel_(new Channel(configuration.get(), channel, std::move(pass_through_), - std::move(acq_), - std::move(trk_), - std::move(tlm_), - "Channel", "5X", queue)); + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "5X", queue)); + + return channel_; +} + + +//********* GLONASS L1 C/A CHANNEL ***************** +std::unique_ptr GNSSBlockFactory::GetChannel_1G( + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + boost::shared_ptr queue) +{ + std::stringstream stream; + stream << channel; + std::string id = stream.str(); + LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder Implementation: " << tlm; + + std::string aux = configuration->property("Acquisition_1G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix1; + if (aux != "W") + { + appendix1 = std::to_string(channel); + } + else + { + appendix1 = ""; + } + aux = configuration->property("Tracking_1G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix2; + if (aux != "W") + { + appendix2 = std::to_string(channel); + } + else + { + appendix2 = ""; + } + aux = configuration->property("TelemetryDecoder_1G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix3; + if (aux != "W") + { + appendix3 = std::to_string(channel); + } + else + { + appendix3 = ""; + } + // Automatically detect input data type + std::shared_ptr config; + config = std::make_shared(); + std::string default_item_type = "gr_complex"; + std::string acq_item_type = configuration->property("Acquisition_1G" + appendix1 + ".item_type", default_item_type); + std::string trk_item_type = configuration->property("Tracking_1G" + appendix2 + ".item_type", default_item_type); + if (acq_item_type != trk_item_type) + { + LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; + } + config->set_property("Channel.item_type", acq_item_type); + + std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_1G" + appendix1, acq, 1, 0); + std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_1G" + appendix2, trk, 1, 1); + std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_1G" + appendix3, tlm, 1, 1); + + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "1G", queue)); + + return channel_; +} + + +//********* GLONASS L2 C/A CHANNEL ***************** +std::unique_ptr GNSSBlockFactory::GetChannel_2G( + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + boost::shared_ptr queue) +{ + std::stringstream stream; + stream << channel; + std::string id = stream.str(); + LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder Implementation: " << tlm; + + std::string aux = configuration->property("Acquisition_2G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix1; + if (aux != "W") + { + appendix1 = std::to_string(channel); + } + else + { + appendix1 = ""; + } + aux = configuration->property("Tracking_2G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix2; + if (aux != "W") + { + appendix2 = std::to_string(channel); + } + else + { + appendix2 = ""; + } + aux = configuration->property("TelemetryDecoder_2G" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix3; + if (aux != "W") + { + appendix3 = std::to_string(channel); + } + else + { + appendix3 = ""; + } + // Automatically detect input data type + std::shared_ptr config; + config = std::make_shared(); + std::string default_item_type = "gr_complex"; + std::string acq_item_type = configuration->property("Acquisition_2G" + appendix1 + ".item_type", default_item_type); + std::string trk_item_type = configuration->property("Tracking_2G" + appendix2 + ".item_type", default_item_type); + if (acq_item_type != trk_item_type) + { + LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; + } + config->set_property("Channel.item_type", acq_item_type); + + std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_2G" + appendix1, acq, 1, 0); + std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_2G" + appendix2, trk, 1, 1); + std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_2G" + appendix3, tlm, 1, 1); + + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "2G", queue)); + + return channel_; +} + + +//********* GPS L5 CHANNEL ***************** +std::unique_ptr GNSSBlockFactory::GetChannel_L5( + std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue) +{ + std::stringstream stream; + stream << channel; + std::string id = stream.str(); + LOG(INFO) << "Instantiating Channel " << id << " with Acquisition Implementation: " + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + std::string aux = configuration->property("Acquisition_L5" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix1; + if (aux != "W") + { + appendix1 = std::to_string(channel); + } + else + { + appendix1 = ""; + } + aux = configuration->property("Tracking_L5" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix2; + if (aux != "W") + { + appendix2 = std::to_string(channel); + } + else + { + appendix2 = ""; + } + aux = configuration->property("TelemetryDecoder_L5" + std::to_string(channel) + ".implementation", std::string("W")); + std::string appendix3; + if (aux != "W") + { + appendix3 = std::to_string(channel); + } + else + { + appendix3 = ""; + } + // Automatically detect input data type + std::shared_ptr config; + config = std::make_shared(); + std::string default_item_type = "gr_complex"; + std::string acq_item_type = configuration->property("Acquisition_L5" + appendix1 + ".item_type", default_item_type); + std::string trk_item_type = configuration->property("Tracking_L5" + appendix2 + ".item_type", default_item_type); + if (acq_item_type != trk_item_type) + { + LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; + } + config->set_property("Channel.item_type", acq_item_type); + + std::unique_ptr acq_ = GetAcqBlock(configuration, "Acquisition_L5" + appendix1, acq, 1, 0); + std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_L5" + appendix2, trk, 1, 1); + std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_L5" + appendix3, tlm, 1, 1); + + std::unique_ptr channel_(new Channel(configuration.get(), channel, + std::move(acq_), + std::move(trk_), + std::move(tlm_), + "Channel", "L5", queue)); return channel_; } std::unique_ptr>> GNSSBlockFactory::GetChannels( - std::shared_ptr configuration, boost::shared_ptr queue) + std::shared_ptr configuration, gr::msg_queue::sptr queue) { std::string default_implementation = "Pass_Through"; std::string tracking_implementation; @@ -525,140 +786,239 @@ std::unique_ptr>> GNSSBlockFacto unsigned int channel_absolute_id = 0; unsigned int Channels_1C_count = configuration->property("Channels_1C.count", 0); - unsigned int Channels_2S_count = configuration->property("Channels_2S.count", 0); unsigned int Channels_1B_count = configuration->property("Channels_1B.count", 0); + unsigned int Channels_1G_count = configuration->property("Channels_1G.count", 0); + unsigned int Channels_2G_count = configuration->property("Channels_2G.count", 0); + unsigned int Channels_2S_count = configuration->property("Channels_2S.count", 0); unsigned int Channels_5X_count = configuration->property("Channels_5X.count", 0); + unsigned int Channels_L5_count = configuration->property("Channels_L5.count", 0); unsigned int total_channels = Channels_1C_count + - Channels_2S_count + - Channels_1B_count + - Channels_5X_count; + Channels_1B_count + + Channels_1G_count + + Channels_2S_count + + Channels_2G_count + + Channels_5X_count + + Channels_L5_count; + std::unique_ptr>> channels(new std::vector>(total_channels)); - - //**************** GPS L1 C/A CHANNELS ********************** - - LOG(INFO) << "Getting " << Channels_1C_count << " GPS L1 C/A channels"; - acquisition_implementation = configuration->property("Acquisition_1C.implementation", default_implementation); - tracking_implementation = configuration->property("Tracking_1C.implementation", default_implementation); - telemetry_decoder_implementation = configuration->property("TelemetryDecoder_1C.implementation", default_implementation); - - - for (unsigned int i = 0; i < Channels_1C_count; i++) + try { - //(i.e. Acquisition_1C0.implementation=xxxx) - std::string acquisition_implementation_specific = configuration->property( - "Acquisition_1C" + boost::lexical_cast(channel_absolute_id) + ".implementation", - acquisition_implementation); - //(i.e. Tracking_1C0.implementation=xxxx) - std::string tracking_implementation_specific = configuration->property( - "Tracking_1C" + boost::lexical_cast(channel_absolute_id) + ".implementation", - tracking_implementation); - std::string telemetry_decoder_implementation_specific = configuration->property( - "TelemetryDecoder_1C" + boost::lexical_cast(channel_absolute_id) + ".implementation", - telemetry_decoder_implementation); + //**************** GPS L1 C/A CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_1C_count << " GPS L1 C/A channels"; + acquisition_implementation = configuration->property("Acquisition_1C.implementation", default_implementation); + tracking_implementation = configuration->property("Tracking_1C.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_1C.implementation", default_implementation); - // Push back the channel to the vector of channels - channels->at(channel_absolute_id) = std::move(GetChannel_1C(configuration, - acquisition_implementation_specific, - tracking_implementation_specific, - telemetry_decoder_implementation_specific, - channel_absolute_id, - queue)); - channel_absolute_id++; - } + for (unsigned int i = 0; i < Channels_1C_count; i++) + { + //(i.e. Acquisition_1C0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_1C" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1C0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_1C" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_1C" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); - //**************** GPS L2C (M) CHANNELS ********************** - LOG(INFO)<< "Getting " << Channels_2S_count << " GPS L2C (M) channels"; - tracking_implementation = configuration->property("Tracking_2S.implementation", default_implementation); - telemetry_decoder_implementation = configuration->property("TelemetryDecoder_2S.implementation", default_implementation); - acquisition_implementation = configuration->property("Acquisition_2S.implementation", default_implementation); - for (unsigned int i = 0; i < Channels_2S_count; i++) - { - //(i.e. Acquisition_1C0.implementation=xxxx) - std::string acquisition_implementation_specific = configuration->property( - "Acquisition_2S" + boost::lexical_cast(channel_absolute_id) + ".implementation", - acquisition_implementation); - //(i.e. Tracking_1C0.implementation=xxxx) - std::string tracking_implementation_specific = configuration->property( - "Tracking_2S" + boost::lexical_cast(channel_absolute_id) + ".implementation", - tracking_implementation); - std::string telemetry_decoder_implementation_specific = configuration->property( - "TelemetryDecoder_2S" + boost::lexical_cast(channel_absolute_id) + ".implementation", - telemetry_decoder_implementation); - - // Push back the channel to the vector of channels - channels->at(channel_absolute_id) = std::move(GetChannel_2S(configuration, - acquisition_implementation_specific, - tracking_implementation_specific, - telemetry_decoder_implementation_specific, - channel_absolute_id, - queue)); - channel_absolute_id++; - } - - //**************** GALILEO E1 B (I/NAV OS) CHANNELS ********************** - - LOG(INFO) << "Getting " << Channels_1B_count << " GALILEO E1 B (I/NAV OS) channels"; - tracking_implementation = configuration->property("Tracking_1B.implementation", default_implementation); - telemetry_decoder_implementation = configuration->property("TelemetryDecoder_1B.implementation", default_implementation); - acquisition_implementation = configuration->property("Acquisition_1B.implementation", default_implementation); - for (unsigned int i = 0; i < Channels_1B_count; i++) - { - //(i.e. Acquisition_1C0.implementation=xxxx) - std::string acquisition_implementation_specific = configuration->property( - "Acquisition_1B" + boost::lexical_cast(channel_absolute_id) + ".implementation", - acquisition_implementation); - //(i.e. Tracking_1C0.implementation=xxxx) - std::string tracking_implementation_specific = configuration->property( - "Tracking_1B" + boost::lexical_cast(channel_absolute_id) + ".implementation", - tracking_implementation); - std::string telemetry_decoder_implementation_specific = configuration->property( - "TelemetryDecoder_1B" + boost::lexical_cast(channel_absolute_id) + ".implementation", - telemetry_decoder_implementation); - - // Push back the channel to the vector of channels - channels->at(channel_absolute_id) = std::move(GetChannel_1B(configuration, + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_1C(configuration, acquisition_implementation_specific, tracking_implementation_specific, telemetry_decoder_implementation_specific, channel_absolute_id, - queue)); - channel_absolute_id++; - } + queue); + channel_absolute_id++; + } + //**************** GPS L2C (M) CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_2S_count << " GPS L2C (M) channels"; + tracking_implementation = configuration->property("Tracking_2S.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_2S.implementation", default_implementation); + acquisition_implementation = configuration->property("Acquisition_2S.implementation", default_implementation); + for (unsigned int i = 0; i < Channels_2S_count; i++) + { + //(i.e. Acquisition_1C0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_2S" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1C0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_2S" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_2S" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); - //**************** GALILEO E5a I (F/NAV OS) CHANNELS ********************** - LOG(INFO) << "Getting " << Channels_5X_count << " GALILEO E5a I (F/NAV OS) channels"; - tracking_implementation = configuration->property("Tracking_5X.implementation", default_implementation); - telemetry_decoder_implementation = configuration->property("TelemetryDecoder_5X.implementation", default_implementation); - acquisition_implementation = configuration->property("Acquisition_5X.implementation", default_implementation); - for (unsigned int i = 0; i < Channels_5X_count; i++) - { - //(i.e. Acquisition_1C0.implementation=xxxx) - std::string acquisition_implementation_specific = configuration->property( - "Acquisition_5X" + boost::lexical_cast(channel_absolute_id) + ".implementation", - acquisition_implementation); - //(i.e. Tracking_1C0.implementation=xxxx) - std::string tracking_implementation_specific = configuration->property( - "Tracking_5X" + boost::lexical_cast(channel_absolute_id) + ".implementation", - tracking_implementation); - std::string telemetry_decoder_implementation_specific = configuration->property( - "TelemetryDecoder_5X" + boost::lexical_cast(channel_absolute_id) + ".implementation", - telemetry_decoder_implementation); - - // Push back the channel to the vector of channels - channels->at(channel_absolute_id) = std::move(GetChannel_5X(configuration, + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_2S(configuration, acquisition_implementation_specific, tracking_implementation_specific, telemetry_decoder_implementation_specific, channel_absolute_id, - queue)); - channel_absolute_id++; - } + queue); + channel_absolute_id++; + } + + //**************** GPS L5 CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_L5_count << " GPS L5 channels"; + tracking_implementation = configuration->property("Tracking_L5.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_L5.implementation", default_implementation); + acquisition_implementation = configuration->property("Acquisition_L5.implementation", default_implementation); + for (unsigned int i = 0; i < Channels_L5_count; i++) + { + //(i.e. Acquisition_1C0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_L5" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1C0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_L5" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_L5" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); + + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_L5(configuration, + acquisition_implementation_specific, + tracking_implementation_specific, + telemetry_decoder_implementation_specific, + channel_absolute_id, + queue); + channel_absolute_id++; + } + + //**************** GALILEO E1 B (I/NAV OS) CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_1B_count << " GALILEO E1 B (I/NAV OS) channels"; + tracking_implementation = configuration->property("Tracking_1B.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_1B.implementation", default_implementation); + acquisition_implementation = configuration->property("Acquisition_1B.implementation", default_implementation); + for (unsigned int i = 0; i < Channels_1B_count; i++) + { + //(i.e. Acquisition_1C0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_1B" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1C0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_1B" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_1B" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); + + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_1B(configuration, + acquisition_implementation_specific, + tracking_implementation_specific, + telemetry_decoder_implementation_specific, + channel_absolute_id, + queue); + channel_absolute_id++; + } + + //**************** GALILEO E5a I (F/NAV OS) CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_5X_count << " GALILEO E5a I (F/NAV OS) channels"; + tracking_implementation = configuration->property("Tracking_5X.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_5X.implementation", default_implementation); + acquisition_implementation = configuration->property("Acquisition_5X.implementation", default_implementation); + for (unsigned int i = 0; i < Channels_5X_count; i++) + { + //(i.e. Acquisition_1C0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_5X" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1C0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_5X" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_5X" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); + + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_5X(configuration, + acquisition_implementation_specific, + tracking_implementation_specific, + telemetry_decoder_implementation_specific, + channel_absolute_id, + queue); + channel_absolute_id++; + } + + //**************** GLONASS L1 C/A CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_1G_count << " GLONASS L1 C/A channels"; + acquisition_implementation = configuration->property("Acquisition_1G.implementation", default_implementation); + tracking_implementation = configuration->property("Tracking_1G.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_1G.implementation", default_implementation); + + for (unsigned int i = 0; i < Channels_1G_count; i++) + { + //(i.e. Acquisition_1G0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_1G" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_1G0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_1G" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_1G" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); + + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_1G(configuration, + acquisition_implementation_specific, + tracking_implementation_specific, + telemetry_decoder_implementation_specific, + channel_absolute_id, + queue); + channel_absolute_id++; + } + + //**************** GLONASS L2 C/A CHANNELS ********************** + LOG(INFO) << "Getting " << Channels_2G_count << " GLONASS L2 C/A channels"; + acquisition_implementation = configuration->property("Acquisition_2G.implementation", default_implementation); + tracking_implementation = configuration->property("Tracking_2G.implementation", default_implementation); + telemetry_decoder_implementation = configuration->property("TelemetryDecoder_2G.implementation", default_implementation); + + for (unsigned int i = 0; i < Channels_2G_count; i++) + { + //(i.e. Acquisition_2G0.implementation=xxxx) + std::string acquisition_implementation_specific = configuration->property( + "Acquisition_2G" + std::to_string(channel_absolute_id) + ".implementation", + acquisition_implementation); + //(i.e. Tracking_2G0.implementation=xxxx) + std::string tracking_implementation_specific = configuration->property( + "Tracking_2G" + std::to_string(channel_absolute_id) + ".implementation", + tracking_implementation); + std::string telemetry_decoder_implementation_specific = configuration->property( + "TelemetryDecoder_2G" + std::to_string(channel_absolute_id) + ".implementation", + telemetry_decoder_implementation); + + // Push back the channel to the vector of channels + channels->at(channel_absolute_id) = GetChannel_2G(configuration, + acquisition_implementation_specific, + tracking_implementation_specific, + telemetry_decoder_implementation_specific, + channel_absolute_id, + queue); + channel_absolute_id++; + } + } + catch (const std::exception &e) + { + LOG(WARNING) << e.what(); + } return channels; } + /* * Returns the block with the required configuration and implementation * @@ -669,441 +1029,654 @@ std::unique_ptr>> GNSSBlockFacto * (see below) */ std::unique_ptr GNSSBlockFactory::GetBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams, boost::shared_ptr queue) + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams, gr::msg_queue::sptr queue) { std::unique_ptr block; //PASS THROUGH ---------------------------------------------------------------- - if (implementation.compare("Pass_Through") == 0) + if (implementation == "Pass_Through") { std::unique_ptr block_(new Pass_Through(configuration.get(), role, in_streams, out_streams)); block = std::move(block_); } // SIGNAL SOURCES ------------------------------------------------------------- - else if (implementation.compare("File_Signal_Source") == 0) + else if (implementation == "File_Signal_Source") { try - { + { std::unique_ptr block_(new FileSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); block = std::move(block_); - } + } catch (const std::exception &e) - { + { std::cout << "GNSS-SDR program ended." << std::endl; exit(1); - } + } } - else if (implementation.compare("Nsr_File_Signal_Source") == 0) +#if RAW_UDP + else if (implementation == "Custom_UDP_Signal_Source") { try - { - std::unique_ptr block_(new NsrFileSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + { + std::unique_ptr block_(new CustomUDPSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); block = std::move(block_); + } - } catch (const std::exception &e) - { + { std::cout << "GNSS-SDR program ended." << std::endl; exit(1); - } - } -#if MODERN_GNURADIO - else if (implementation.compare("Two_Bit_Cpx_File_Signal_Source") == 0) - { - try - { - std::unique_ptr block_(new TwoBitCpxFileSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); - block = std::move(block_); - - } - catch (const std::exception &e) - { - std::cout << "GNSS-SDR program ended." << std::endl; - exit(1); - } - } - else if(implementation.compare("Two_Bit_Packed_File_Signal_Source") == 0 ) - { - try - { - std::unique_ptr block_(new TwoBitPackedFileSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); - block = std::move(block_); - } - catch(const std::exception &e) - { - std::cout << "GNSS-SDR program ended." << std::endl; - exit(1); - } + } } #endif - else if (implementation.compare("Spir_File_Signal_Source") == 0) + else if (implementation == "Nsr_File_Signal_Source") { try - { - std::unique_ptr block_(new SpirFileSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + { + std::unique_ptr block_(new NsrFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); block = std::move(block_); - - } + } catch (const std::exception &e) - { + { std::cout << "GNSS-SDR program ended." << std::endl; exit(1); - } + } } - else if (implementation.compare("RtlTcp_Signal_Source") == 0) +#if MODERN_GNURADIO + else if (implementation == "Two_Bit_Cpx_File_Signal_Source") { try - { - std::unique_ptr block_(new RtlTcpSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + { + std::unique_ptr block_(new TwoBitCpxFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); block = std::move(block_); - - } + } catch (const std::exception &e) - { + { std::cout << "GNSS-SDR program ended." << std::endl; exit(1); - } + } + } + else if (implementation == "Two_Bit_Packed_File_Signal_Source") + { + try + { + std::unique_ptr block_(new TwoBitPackedFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } +#endif + else if (implementation == "Spir_File_Signal_Source") + { + try + { + std::unique_ptr block_(new SpirFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation == "Spir_GSS6450_File_Signal_Source") + { + try + { + std::unique_ptr block_(new SpirGSS6450FileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation == "RtlTcp_Signal_Source") + { + try + { + std::unique_ptr block_(new RtlTcpSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation == "Labsat_Signal_Source") + { + try + { + std::unique_ptr block_(new LabsatSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } } #if UHD_DRIVER - else if (implementation.compare("UHD_Signal_Source") == 0) + else if (implementation == "UHD_Signal_Source") { std::unique_ptr block_(new UhdSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); block = std::move(block_); } #endif #if GN3S_DRIVER - else if (implementation.compare("GN3S_Signal_Source") == 0) + else if (implementation == "GN3S_Signal_Source") { std::unique_ptr block_(new Gn3sSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); block = std::move(block_); } #endif #if RAW_ARRAY_DRIVER - else if (implementation.compare("Raw_Array_Signal_Source") == 0) + else if (implementation == "Raw_Array_Signal_Source") { std::unique_ptr block_(new RawArraySignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); block = std::move(block_); } #endif #if OSMOSDR_DRIVER - else if (implementation.compare("Osmosdr_Signal_Source") == 0) + else if (implementation == "Osmosdr_Signal_Source") { std::unique_ptr block_(new OsmosdrSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); + block = std::move(block_); + } +#endif + +#if PLUTOSDR_DRIVER + else if (implementation == "Plutosdr_Signal_Source") + { + std::unique_ptr block_(new PlutosdrSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } +#endif + +#if FMCOMMS2_DRIVER + else if (implementation == "Fmcomms2_Signal_Source") + { + std::unique_ptr block_(new Fmcomms2SignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } +#endif + +#if AD9361_DRIVER + else if (implementation == "Ad9361_Fpga_Signal_Source") + { + std::unique_ptr block_(new Ad9361FpgaSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); block = std::move(block_); } #endif #if FLEXIBAND_DRIVER - else if (implementation.compare("Flexiband_Signal_Source") == 0) + else if (implementation == "Flexiband_Signal_Source") { std::unique_ptr block_(new FlexibandSignalSource(configuration.get(), role, in_streams, - out_streams, queue)); + out_streams, queue)); block = std::move(block_); } #endif // DATA TYPE ADAPTER ----------------------------------------------------------- - else if (implementation.compare("Byte_To_Short") == 0) + else if (implementation == "Byte_To_Short") { - std::unique_ptrblock_(new ByteToShort(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new ByteToShort(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Ibyte_To_Cbyte") == 0) + else if (implementation == "Ibyte_To_Cbyte") { - std::unique_ptrblock_(new IbyteToCbyte(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new IbyteToCbyte(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Ibyte_To_Cshort") == 0) + else if (implementation == "Ibyte_To_Cshort") { - std::unique_ptrblock_(new IbyteToCshort(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new IbyteToCshort(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Ibyte_To_Complex") == 0) + else if (implementation == "Ibyte_To_Complex") { - std::unique_ptrblock_(new IbyteToComplex(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new IbyteToComplex(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Ishort_To_Cshort") == 0) + else if (implementation == "Ishort_To_Cshort") { - std::unique_ptrblock_(new IshortToCshort(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new IshortToCshort(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Ishort_To_Complex") == 0) + else if (implementation == "Ishort_To_Complex") { - std::unique_ptrblock_(new IshortToComplex(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new IshortToComplex(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } // INPUT FILTER ---------------------------------------------------------------- - else if (implementation.compare("Fir_Filter") == 0) + else if (implementation == "Fir_Filter") { std::unique_ptr block_(new FirFilter(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Freq_Xlating_Fir_Filter") == 0) + else if (implementation == "Freq_Xlating_Fir_Filter") { std::unique_ptr block_(new FreqXlatingFirFilter(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Beamformer_Filter") == 0) + else if (implementation == "Beamformer_Filter") { std::unique_ptr block_(new BeamformerFilter(configuration.get(), role, in_streams, - out_streams)); + out_streams)); + block = std::move(block_); + } + else if (implementation == "Pulse_Blanking_Filter") + { + std::unique_ptr block_(new PulseBlankingFilter(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Notch_Filter") + { + std::unique_ptr block_(new NotchFilter(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Notch_Filter_Lite") + { + std::unique_ptr block_(new NotchFilterLite(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } // RESAMPLER ------------------------------------------------------------------- - else if (implementation.compare("Direct_Resampler") == 0) + else if (implementation == "Direct_Resampler") { std::unique_ptr block_(new DirectResamplerConditioner(configuration.get(), role, - in_streams, out_streams)); + in_streams, out_streams)); + block = std::move(block_); + } + + else if ((implementation == "Fractional_Resampler") || (implementation == "Mmse_Resampler")) + { + std::unique_ptr block_(new MmseResamplerConditioner(configuration.get(), role, + in_streams, out_streams)); block = std::move(block_); } // ACQUISITION BLOCKS --------------------------------------------------------- - else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_Assisted_Acquisition") == 0) + +#if ENABLE_FPGA + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") + { + std::unique_ptr block_(new GpsL1CaPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GPS_L1_CA_PCPS_Assisted_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsAssistedAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_Tong_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_Tong_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsTongAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L1_CA_PCPS_Multithread_Acquisition") == 0) - { - std::unique_ptr block_(new GpsL1CaPcpsMultithreadAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } #if OPENCL_BLOCKS - else if (implementation.compare("GPS_L1_CA_PCPS_OpenCl_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_OpenCl_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsOpenClAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } #endif - else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0) + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") { std::unique_ptr block_(new GpsL1CaPcpsAcquisitionFineDoppler(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_QuickSync_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_QuickSync_Acquisition") { - std::unique_ptr block_( new GpsL1CaPcpsQuickSyncAcquisition(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GpsL1CaPcpsQuickSyncAcquisition(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0) + else if (implementation == "GPS_L2_M_PCPS_Acquisition") { - std::unique_ptr block_(new GalileoE1PcpsAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GpsL2MPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_8ms_Ambiguous_Acquisition") == 0) +#if ENABLE_FPGA + else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") { - std::unique_ptr block_(new GalileoE1Pcps8msAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1_PCPS_Tong_Ambiguous_Acquisition") == 0) - { - std::unique_ptr block_(new GalileoE1PcpsTongAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition") == 0) - { - std::unique_ptr block_(new GalileoE1PcpsCccwsrAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") == 0) - { - std::unique_ptr block_(new GalileoE5aNoncoherentIQAcquisitionCaf(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition") == 0) - { - std::unique_ptr block_( new GalileoE1PcpsQuickSyncAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - - - - - // TRACKING BLOCKS ------------------------------------------------------------- - else if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) - { - std::unique_ptr block_(new GpsL1CaDllPllTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L1_CA_DLL_PLL_C_Aid_Tracking") == 0) - { - std::unique_ptr block_(new GpsL1CaDllPllCAidTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L1_CA_TCP_CONNECTOR_Tracking") == 0) - { - std::unique_ptr block_(new GpsL1CaTcpConnectorTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) - { - std::unique_ptr block_(new GpsL2MDllPllTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } -#if CUDA_GPU_ACCEL - else if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking_GPU") == 0) - { - std::unique_ptr block_(new GpsL1CaDllPllTrackingGPU(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GpsL2MPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } #endif - else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + else if (implementation == "GPS_L5i_PCPS_Acquisition") + { + std::unique_ptr block_(new GpsL5iPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") + { + std::unique_ptr block_(new GpsL5iPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition") + { + std::unique_ptr block_(new GalileoE1PcpsAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") + { + std::unique_ptr block_(new GalileoE1PcpsAmbiguousAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition") + { + std::unique_ptr block_(new GalileoE1Pcps8msAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition") + { + std::unique_ptr block_(new GalileoE1PcpsTongAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition") + { + std::unique_ptr block_(new GalileoE1PcpsCccwsrAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") + { + std::unique_ptr block_(new GalileoE5aNoncoherentIQAcquisitionCaf(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E5a_Pcps_Acquisition") + { + std::unique_ptr block_(new GalileoE5aPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") + { + std::unique_ptr block_(new GalileoE5aPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition") + { + std::unique_ptr block_(new GalileoE1PcpsQuickSyncAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L1_CA_PCPS_Acquisition") + { + std::unique_ptr block_(new GlonassL1CaPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_PCPS_Acquisition") + { + std::unique_ptr block_(new GlonassL2CaPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + // TRACKING BLOCKS ------------------------------------------------------------- + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GpsL1CaDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GPS_L1_CA_KF_Tracking") + { + std::unique_ptr block_(new GpsL1CaKfTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GPS_L1_CA_DLL_PLL_C_Aid_Tracking") + { + std::unique_ptr block_(new GpsL1CaDllPllCAidTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + std::unique_ptr block_(new GpsL1CaDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GPS_L1_CA_TCP_CONNECTOR_Tracking") + { + std::unique_ptr block_(new GpsL1CaTcpConnectorTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GpsL2MDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") + { + std::unique_ptr block_(new GpsL2MDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking") or (implementation == "GPS_L5_DLL_PLL_Tracking")) + { + std::unique_ptr block_(new GpsL5DllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + { + std::unique_ptr block_(new GpsL5DllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif +#if CUDA_GPU_ACCEL + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_GPU") + { + std::unique_ptr block_(new GpsL1CaDllPllTrackingGPU(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking") { std::unique_ptr block_(new GalileoE1DllPllVemlTracking(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_TCP_CONNECTOR_Tracking") == 0) +#if ENABLE_FPGA + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + std::unique_ptr block_(new GalileoE1DllPllVemlTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_TCP_CONNECTOR_Tracking") { std::unique_ptr block_(new GalileoE1TcpConnectorTracking(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking") { std::unique_ptr block_(new GalileoE5aDllPllTracking(configuration.get(), role, in_streams, - out_streams)); + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + std::unique_ptr block_(new GalileoE5aDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GLONASS_L1_CA_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GlonassL1CaDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking") + { + std::unique_ptr block_(new GlonassL1CaDllPllCAidTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GlonassL2CaDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_DLL_PLL_C_Aid_Tracking") + { + std::unique_ptr block_(new GlonassL2CaDllPllCAidTracking(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - // TELEMETRY DECODERS ---------------------------------------------------------- - else if (implementation.compare("GPS_L1_CA_Telemetry_Decoder") == 0) + else if (implementation == "GPS_L1_CA_Telemetry_Decoder") { std::unique_ptr block_(new GpsL1CaTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L2C_Telemetry_Decoder") == 0) + else if (implementation == "GPS_L2C_Telemetry_Decoder") { std::unique_ptr block_(new GpsL2CTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1B_Telemetry_Decoder") == 0) + else if (implementation == "GPS_L5_Telemetry_Decoder") + { + std::unique_ptr block_(new GpsL5TelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E1B_Telemetry_Decoder") { std::unique_ptr block_(new GalileoE1BTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("SBAS_L1_Telemetry_Decoder") == 0) + else if (implementation == "SBAS_L1_Telemetry_Decoder") { std::unique_ptr block_(new SbasL1TelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E5a_Telemetry_Decoder") == 0) + else if (implementation == "Galileo_E5a_Telemetry_Decoder") { std::unique_ptr block_(new GalileoE5aTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L1_CA_Telemetry_Decoder") + { + std::unique_ptr block_(new GlonassL1CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_Telemetry_Decoder") + { + std::unique_ptr block_(new GlonassL2CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + // OBSERVABLES ----------------------------------------------------------------- + else if ((implementation == "Hybrid_Observables") || (implementation == "GPS_L1_CA_Observables") || (implementation == "GPS_L2C_Observables") || + (implementation == "Galileo_E5A_Observables")) + { + std::unique_ptr block_(new HybridObservables(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - // OBSERVABLES ----------------------------------------------------------------- - else if (implementation.compare("GPS_L1_CA_Observables") == 0) - { - std::unique_ptr block_(new GpsL1CaObservables(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L2C_Observables") == 0) - { - std::unique_ptr block_(new GpsL2CObservables(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1B_Observables") == 0) - { - std::unique_ptr block_(new GalileoE1Observables(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E5A_Observables") == 0) - { - std::unique_ptr block_(new GalileoE5aObservables(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Hybrid_Observables") == 0) - { - std::unique_ptr block_(new HybridObservables(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } // PVT ------------------------------------------------------------------------- - else if (implementation.compare("GPS_L1_CA_PVT") == 0) + else if ((implementation == "RTKLIB_PVT") || (implementation == "GPS_L1_CA_PVT") || (implementation == "Galileo_E1_PVT") || (implementation == "Hybrid_PVT")) { - std::unique_ptr block_(new GpsL1CaPvt(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GALILEO_E1_PVT") == 0) - { - std::unique_ptr block_(new GalileoE1Pvt(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Hybrid_PVT") == 0) - { - std::unique_ptr block_(new HybridPvt(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new RtklibPvt(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } else @@ -1111,7 +1684,7 @@ std::unique_ptr GNSSBlockFactory::GetBlock( // Log fatal. This causes execution to stop. LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; } - return std::move(block); + return block; } @@ -1124,100 +1697,158 @@ std::unique_ptr GNSSBlockFactory::GetBlock( */ std::unique_ptr GNSSBlockFactory::GetAcqBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams) + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams) { std::unique_ptr block; // ACQUISITION BLOCKS --------------------------------------------------------- - if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0) + if (implementation == "GPS_L1_CA_PCPS_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_Assisted_Acquisition") == 0) +#if ENABLE_FPGA + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") + { + std::unique_ptr block_(new GpsL1CaPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GPS_L1_CA_PCPS_Assisted_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsAssistedAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_Tong_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_Tong_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsTongAcquisition(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L1_CA_PCPS_Multithread_Acquisition") == 0) - { - std::unique_ptr block_(new GpsL1CaPcpsMultithreadAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } #if OPENCL_BLOCKS - else if (implementation.compare("GPS_L1_CA_PCPS_OpenCl_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_OpenCl_Acquisition") { std::unique_ptr block_(new GpsL1CaPcpsOpenClAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } #endif - else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0) + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") { std::unique_ptr block_(new GpsL1CaPcpsAcquisitionFineDoppler(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_PCPS_QuickSync_Acquisition") == 0) + else if (implementation == "GPS_L1_CA_PCPS_QuickSync_Acquisition") { - std::unique_ptr block_( new GpsL1CaPcpsQuickSyncAcquisition(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GpsL1CaPcpsQuickSyncAcquisition(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L2_M_PCPS_Acquisition") == 0) + else if (implementation == "GPS_L2_M_PCPS_Acquisition") { std::unique_ptr block_(new GpsL2MPcpsAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0) +#if ENABLE_FPGA + else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") + { + std::unique_ptr block_(new GpsL2MPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GPS_L5i_PCPS_Acquisition") + { + std::unique_ptr block_(new GpsL5iPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") + { + std::unique_ptr block_(new GpsL5iPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition") { std::unique_ptr block_(new GalileoE1PcpsAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_8ms_Ambiguous_Acquisition") == 0) +#if ENABLE_FPGA + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") + { + std::unique_ptr block_(new GalileoE1PcpsAmbiguousAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition") { std::unique_ptr block_(new GalileoE1Pcps8msAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_Tong_Ambiguous_Acquisition") == 0) + else if (implementation == "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition") { std::unique_ptr block_(new GalileoE1PcpsTongAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition") == 0) + else if (implementation == "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition") { std::unique_ptr block_(new GalileoE1PcpsCccwsrAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition") == 0) + else if (implementation == "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition") { - std::unique_ptr block_( new GalileoE1PcpsQuickSyncAmbiguousAcquisition(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GalileoE1PcpsQuickSyncAmbiguousAcquisition(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") == 0) + else if (implementation == "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") { std::unique_ptr block_(new GalileoE5aNoncoherentIQAcquisitionCaf(configuration.get(), role, in_streams, - out_streams)); + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E5a_Pcps_Acquisition") + { + std::unique_ptr block_(new GalileoE5aPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") + { + std::unique_ptr block_(new GalileoE5aPcpsAcquisitionFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GLONASS_L1_CA_PCPS_Acquisition") + { + std::unique_ptr block_(new GlonassL1CaPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_PCPS_Acquisition") + { + std::unique_ptr block_(new GlonassL2CaPcpsAcquisition(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } else @@ -1225,115 +1856,209 @@ std::unique_ptr GNSSBlockFactory::GetAcqBlock( // Log fatal. This causes execution to stop. LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; } - return std::move(block); + return block; } std::unique_ptr GNSSBlockFactory::GetTrkBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams) + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams) { std::unique_ptr block; // TRACKING BLOCKS ------------------------------------------------------------- - if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking") { std::unique_ptr block_(new GpsL1CaDllPllTracking(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_DLL_PLL_C_Aid_Tracking") == 0) + else if (implementation == "GPS_L1_CA_KF_Tracking") + { + std::unique_ptr block_(new GpsL1CaKfTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GPS_L1_CA_DLL_PLL_C_Aid_Tracking") { std::unique_ptr block_(new GpsL1CaDllPllCAidTracking(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L1_CA_TCP_CONNECTOR_Tracking") == 0) +#if ENABLE_FPGA + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") { - std::unique_ptr block_(new GpsL1CaTcpConnectorTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) - { - std::unique_ptr block_(new GalileoE1DllPllVemlTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E1_TCP_CONNECTOR_Tracking") == 0) - { - std::unique_ptr block_(new GalileoE1TcpConnectorTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) - { - std::unique_ptr block_(new GalileoE5aDllPllTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } - else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) - { - std::unique_ptr block_(new GpsL2MDllPllTracking(configuration.get(), role, in_streams, - out_streams)); - block = std::move(block_); - } -#if CUDA_GPU_ACCEL - else if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking_GPU") == 0) - { - std::unique_ptr block_(new GpsL1CaDllPllTrackingGPU(configuration.get(), role, in_streams, - out_streams)); + std::unique_ptr block_(new GpsL1CaDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } #endif + else if (implementation == "GPS_L1_CA_TCP_CONNECTOR_Tracking") + { + std::unique_ptr block_(new GpsL1CaTcpConnectorTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking") + { + std::unique_ptr block_(new GalileoE1DllPllVemlTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + std::unique_ptr block_(new GalileoE1DllPllVemlTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "Galileo_E1_TCP_CONNECTOR_Tracking") + { + std::unique_ptr block_(new GalileoE1TcpConnectorTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GalileoE5aDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + std::unique_ptr block_(new GalileoE5aDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GpsL2MDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") + { + std::unique_ptr block_(new GpsL2MDllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking") or (implementation == "GPS_L5_DLL_PLL_Tracking")) + { + std::unique_ptr block_(new GpsL5DllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#if ENABLE_FPGA + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + { + std::unique_ptr block_(new GpsL5DllPllTrackingFpga(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif +#if CUDA_GPU_ACCEL + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_GPU") + { + std::unique_ptr block_(new GpsL1CaDllPllTrackingGPU(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } +#endif + else if (implementation == "GLONASS_L1_CA_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GlonassL1CaDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking") + { + std::unique_ptr block_(new GlonassL1CaDllPllCAidTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_DLL_PLL_Tracking") + { + std::unique_ptr block_(new GlonassL2CaDllPllTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_DLL_PLL_C_Aid_Tracking") + { + std::unique_ptr block_(new GlonassL2CaDllPllCAidTracking(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } else { // Log fatal. This causes execution to stop. LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; } - return std::move(block); + return block; } std::unique_ptr GNSSBlockFactory::GetTlmBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams) + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams) { std::unique_ptr block; // TELEMETRY DECODERS ---------------------------------------------------------- - if (implementation.compare("GPS_L1_CA_Telemetry_Decoder") == 0) + if (implementation == "GPS_L1_CA_Telemetry_Decoder") { std::unique_ptr block_(new GpsL1CaTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E1B_Telemetry_Decoder") == 0) + else if (implementation == "Galileo_E1B_Telemetry_Decoder") { std::unique_ptr block_(new GalileoE1BTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("SBAS_L1_Telemetry_Decoder") == 0) + else if (implementation == "SBAS_L1_Telemetry_Decoder") { std::unique_ptr block_(new SbasL1TelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("Galileo_E5a_Telemetry_Decoder") == 0) + else if (implementation == "Galileo_E5a_Telemetry_Decoder") { std::unique_ptr block_(new GalileoE5aTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); block = std::move(block_); } - else if (implementation.compare("GPS_L2C_Telemetry_Decoder") == 0) + else if (implementation == "GPS_L2C_Telemetry_Decoder") { std::unique_ptr block_(new GpsL2CTelemetryDecoder(configuration.get(), role, in_streams, - out_streams)); + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L1_CA_Telemetry_Decoder") + { + std::unique_ptr block_(new GlonassL1CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GLONASS_L2_CA_Telemetry_Decoder") + { + std::unique_ptr block_(new GlonassL2CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } + else if (implementation == "GPS_L5_Telemetry_Decoder") + { + std::unique_ptr block_(new GpsL5TelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); block = std::move(block_); } else @@ -1341,5 +2066,5 @@ std::unique_ptr GNSSBlockFactory::GetTlmBlock( // Log fatal. This causes execution to stop. LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; } - return std::move(block); + return block; } diff --git a/src/core/receiver/gnss_block_factory.h b/src/core/receiver/gnss_block_factory.h index 13c614ee8..a66e6917e 100644 --- a/src/core/receiver/gnss_block_factory.h +++ b/src/core/receiver/gnss_block_factory.h @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -37,10 +37,11 @@ #ifndef GNSS_SDR_BLOCK_FACTORY_H_ #define GNSS_SDR_BLOCK_FACTORY_H_ +#include #include #include #include -#include + class ConfigurationInterface; class GNSSBlockInterface; @@ -57,7 +58,7 @@ public: GNSSBlockFactory(); virtual ~GNSSBlockFactory(); std::unique_ptr GetSignalSource(std::shared_ptr configuration, - boost::shared_ptr queue, int ID = -1); + gr::msg_queue::sptr queue, int ID = -1); std::unique_ptr GetSignalConditioner(std::shared_ptr configuration, int ID = -1); @@ -66,52 +67,62 @@ public: std::unique_ptr GetObservables(std::shared_ptr configuration); std::unique_ptr>> GetChannels(std::shared_ptr configuration, - boost::shared_ptr queue); + gr::msg_queue::sptr queue); /* * \brief Returns the block with the required configuration and implementation */ std::unique_ptr GetBlock(std::shared_ptr configuration, - std::string role, std::string implementation, - unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue = nullptr); + std::string role, std::string implementation, + unsigned int in_streams, unsigned int out_streams, + gr::msg_queue::sptr queue = nullptr); private: - std::unique_ptr GetChannel_1C(std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue); + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue); std::unique_ptr GetChannel_2S(std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue); + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue); std::unique_ptr GetChannel_1B(std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue); + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue); std::unique_ptr GetChannel_5X(std::shared_ptr configuration, - std::string acq, std::string trk, std::string tlm, int channel, - boost::shared_ptr queue); + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue); + + std::unique_ptr GetChannel_L5(std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + gr::msg_queue::sptr queue); + + std::unique_ptr GetChannel_1G(std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + boost::shared_ptr queue); + + std::unique_ptr GetChannel_2G(std::shared_ptr configuration, + std::string acq, std::string trk, std::string tlm, int channel, + boost::shared_ptr queue); std::unique_ptr GetAcqBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams); + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams); std::unique_ptr GetTrkBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams); + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams); std::unique_ptr GetTlmBlock( - std::shared_ptr configuration, - std::string role, - std::string implementation, unsigned int in_streams, - unsigned int out_streams); + std::shared_ptr configuration, + std::string role, + std::string implementation, unsigned int in_streams, + unsigned int out_streams); }; #endif /*GNSS_SDR_BLOCK_FACTORY_H_*/ - diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 138140d34..08d47a376 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -1,15 +1,15 @@ /*! * \file gnss_flowgraph.cc - * \brief Implementation of a GNSS receiver flowgraph + * \brief Implementation of a GNSS receiver flow graph * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Luis Esteve, 2012. luis(at)epsilon-formacion.com * Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es - * - * Detailed description of the file here if needed. + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * Javier Arribas, 2018. javiarribas(at)gmail.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -27,44 +27,58 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gnss_flowgraph.h" -#include "unistd.h" - -#include +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "channel.h" +#include "channel_interface.h" +#include "configuration_interface.h" +#include "gnss_block_factory.h" +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include "configuration_interface.h" -#include "gnss_block_interface.h" -#include "channel_interface.h" -#include "gnss_block_factory.h" +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + #define GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS 8 using google::LogMessage; -GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr configuration, - boost::shared_ptr queue) +GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr configuration, const gr::msg_queue::sptr& queue) { connected_ = false; running_ = false; configuration_ = configuration; - queue_ = queue; + queue_ = std::move(queue); init(); } GNSSFlowgraph::~GNSSFlowgraph() -{} +{ + if (connected_) + { + GNSSFlowgraph::disconnect(); + } +} void GNSSFlowgraph::start() @@ -76,15 +90,15 @@ void GNSSFlowgraph::start() } try - { + { top_block_->start(); - } - catch (std::exception& e) - { + } + catch (const std::exception& e) + { LOG(WARNING) << "Unable to start flowgraph"; LOG(ERROR) << e.what(); return; - } + } running_ = true; } @@ -92,12 +106,6 @@ void GNSSFlowgraph::start() void GNSSFlowgraph::stop() { - // for (unsigned int i = 0; i < channels_count_; i++) - // { - // channels_.at(i)->stop_channel(); - // LOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; - // } - // LOG(INFO) << "Threads finished. Return to main program."; top_block_->stop(); running_ = false; } @@ -105,10 +113,9 @@ void GNSSFlowgraph::stop() void GNSSFlowgraph::connect() { - /* Connects the blocks in the flowgraph - * - * Signal Source > Signal conditioner >> Channels >> Observables >> PVT - */ + // Connects the blocks in the flow graph + // Signal Source > Signal conditioner >> Channels >> Observables >> PVT + LOG(INFO) << "Connecting flowgraph"; if (connected_) { @@ -118,74 +125,80 @@ void GNSSFlowgraph::connect() for (int i = 0; i < sources_count_; i++) { - try - { - sig_source_.at(i)->connect(top_block_); - } - catch (std::exception& e) - { - LOG(INFO) << "Can't connect signal source block " << i << " internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) + { + try + { + sig_source_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't connect signal source block " << i << " internally"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } } // Signal Source > Signal conditioner > for (unsigned int i = 0; i < sig_conditioner_.size(); i++) { - try - { - sig_conditioner_.at(i)->connect(top_block_); - } - catch (std::exception& e) - { - LOG(INFO) << "Can't connect signal conditioner block " << i << " internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + if (configuration_->property(sig_conditioner_.at(i)->role() + ".enable_FPGA", false) == false) + { + try + { + sig_conditioner_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't connect signal conditioner block " << i << " internally"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } } for (unsigned int i = 0; i < channels_count_; i++) { try - { + { channels_.at(i)->connect(top_block_); - } - catch (std::exception& e) - { + } + catch (const std::exception& e) + { LOG(WARNING) << "Can't connect channel " << i << " internally"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; - } + } } try - { + { observables_->connect(top_block_); - } - catch (std::exception& e) - { + } + catch (const std::exception& e) + { LOG(WARNING) << "Can't connect observables block internally"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; - } + } // Signal Source > Signal conditioner >> Channels >> Observables > PVT try - { + { pvt_->connect(top_block_); - } - catch (std::exception& e) - { + } + catch (const std::exception& e) + { LOG(WARNING) << "Can't connect PVT block internally"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; - } + } DLOG(INFO) << "blocks connected internally"; // Signal Source (i) > Signal conditioner (i) > @@ -194,118 +207,455 @@ void GNSSFlowgraph::connect() for (int i = 0; i < sources_count_; i++) { - try - { - //TODO: Remove this array implementation and create generic multistream connector - //(if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if(sig_source_.at(i)->implementation().compare("Raw_Array_Signal_Source") == 0) + //FPGA Accelerators do not need signal sources or conditioners + //as the samples are feed directly to the FPGA fabric, so, if enabled, do not connect any source + if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) + { + try { - //Multichannel Array - std::cout << "ARRAY MODE" << std::endl; - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + //TODO: Remove this array implementation and create generic multistream connector + //(if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") { - std::cout << "connecting ch " << j << std::endl; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } - } - else - { - //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - //Include GetRFChannels in the interface to avoid read config parameters here - //read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - - for (int j = 0; j < RF_Channels; j++) - { - //Connect the multichannel signal source to multiple signal conditioners - // GNURADIO max_streams=-1 means infinite ports! - LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); - LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + //Multichannel Array + std::cout << "ARRAY MODE" << std::endl; + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) { - - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - + std::cout << "connecting ch " << j << std::endl; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); } - else + } + else + { + //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + //Include GetRFChannels in the interface to avoid read config parameters here + //read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) { - if (j == 0) + //Connect the multichannel signal source to multiple signal conditioners + // GNURADIO max_streams=-1 means infinite ports! + LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); + LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); + + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) { - // RF_channel 0 backward compatibility with single channel sources - LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); } else { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } } + signal_conditioner_ID++; } - - signal_conditioner_ID++; } } - } - catch (std::exception& e) - { - LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } } DLOG(INFO) << "Signal source connected to signal conditioner"; + bool FPGA_enabled = configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false); - // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) - int selected_signal_conditioner_ID; - for (unsigned int i = 0; i < channels_count_; i++) +#if ENABLE_FPGA + if (FPGA_enabled == false) { - selected_signal_conditioner_ID = configuration_->property("Channel" + boost::lexical_cast(i) + ".RF_channel_ID", 0); + //connect the signal source to sample counter + //connect the sample counter to Observables try - { - top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - channels_.at(i)->get_left_block(), 0); - } - catch (std::exception& e) - { - LOG(WARNING) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i; + { + double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file" << std::endl; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } + int observable_interval_ms = static_cast(configuration_->property("GNSS-SDR.observable_interval_ms", 20)); + ch_out_sample_counter = gnss_sdr_make_sample_counter(fs, observable_interval_ms, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); + top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter, 0); + top_block_->connect(ch_out_sample_counter, 0, observables_->get_left_block(), channels_count_); //extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect sample counter"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; - } + } + } + else + { + //create a hardware-defined gnss_synchro pulse for the observables block + try + { + double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file" << std::endl; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } + int observable_interval_ms = static_cast(configuration_->property("GNSS-SDR.observable_interval_ms", 20)); + ch_out_fpga_sample_counter = gnss_sdr_make_fpga_sample_counter(fs, observable_interval_ms); + top_block_->connect(ch_out_fpga_sample_counter, 0, observables_->get_left_block(), channels_count_); //extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect FPGA sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } +#else + // connect the signal source to sample counter + // connect the sample counter to Observables + try + { + double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file" << std::endl; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } - DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; + int observable_interval_ms = static_cast(configuration_->property("GNSS-SDR.observable_interval_ms", 20)); + ch_out_sample_counter = gnss_sdr_make_sample_counter(fs, observable_interval_ms, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); + top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter, 0); + top_block_->connect(ch_out_sample_counter, 0, observables_->get_left_block(), channels_count_); //extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } +#endif + // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) + int selected_signal_conditioner_ID = 0; + bool use_acq_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); + uint32_t fs = configuration_->property("GNSS-SDR.internal_fs_sps", 0); + for (unsigned int i = 0; i < channels_count_; i++) + { + if (FPGA_enabled == false) + { + try + { + selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + try + { + // Enable automatic resampler for the acquisition, if required + if (use_acq_resampler == true) + { + //create acquisition resamplers if required + double resampler_ratio = 1.0; + double acq_fs = fs; + //find the signal associated to this channel + switch (mapStringValues_[channels_.at(i)->implementation()]) + { + case evGPS_1C: + acq_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGPS_2S: + acq_fs = GPS_L2C_OPT_ACQ_FS_HZ; + break; + case evGPS_L5: + acq_fs = GPS_L5_OPT_ACQ_FS_HZ; + break; + case evSBAS_1C: + acq_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGAL_1B: + acq_fs = Galileo_E1_OPT_ACQ_FS_HZ; + break; + case evGAL_5X: + acq_fs = Galileo_E5a_OPT_ACQ_FS_HZ; + break; + case evGLO_1G: + acq_fs = fs; + break; + case evGLO_2G: + acq_fs = fs; + break; + } + if (acq_fs < fs) + { + //check if the resampler is already created for the channel system/signal and for the specific RF Channel + std::string map_key = channels_.at(i)->implementation() + std::to_string(selected_signal_conditioner_ID); + resampler_ratio = static_cast(fs) / acq_fs; + int decimation = floor(resampler_ratio); + while (fs % decimation > 0) + { + decimation--; + }; + double acq_fs = fs / decimation; + + if (decimation > 1) + { + //create a FIR low pass filter + std::vector taps; + taps = gr::filter::firdes::low_pass(1.0, + fs, + acq_fs / 2.1, + acq_fs / 10, + gr::filter::firdes::win_type::WIN_HAMMING); + + gr::basic_block_sptr fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(decimation, taps); + + std::pair::iterator, bool> ret; + ret = acq_resamplers_.insert(std::pair(map_key, fir_filter_ccf_)); + if (ret.second == true) + { + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + acq_resamplers_.at(map_key), 0); + LOG(INFO) << "Created " + << channels_.at(i)->implementation() + << " acquisition resampler for RF channel " << std::to_string(signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; + } + else + { + LOG(INFO) << "Found existing " + << channels_.at(i)->implementation() + << " acquisition resampler for RF channel " << std::to_string(signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; + } + + + top_block_->connect(acq_resamplers_.at(map_key), 0, + channels_.at(i)->get_left_block_acq(), 0); + + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + + std::shared_ptr channel_ptr; + channel_ptr = std::dynamic_pointer_cast(channels_.at(i)); + channel_ptr->acquisition()->set_resampler_latency((taps.size() - 1) / 2); + } + else + { + LOG(INFO) << "Disabled acquisition resampler because the input sampling frequency is too low"; + //resampler not required! + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_acq(), 0); + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + } + } + else + { + LOG(INFO) << "Disabled acquisition resampler because the input sampling frequency is too low"; + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_acq(), 0); + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + } + } + else + { + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_acq(), 0); + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + } + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + + DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; + } // Signal Source > Signal conditioner >> Channels >> Observables try - { + { top_block_->connect(channels_.at(i)->get_right_block(), 0, - observables_->get_left_block(), i); - } - catch (std::exception& e) - { + observables_->get_left_block(), i); + } + catch (const std::exception& e) + { LOG(WARNING) << "Can't connect channel " << i << " to observables"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; - } - - std::string gnss_signal = channels_.at(i)->get_signal().get_signal_str(); // use channel's implicit signal! - while (gnss_signal.compare(available_GNSS_signals_.front().get_signal_str()) != 0 ) - { - available_GNSS_signals_.push_back(available_GNSS_signals_.front()); - available_GNSS_signals_.pop_front(); } - channels_.at(i)->set_signal(available_GNSS_signals_.front()); + } + // Put channels fixed to a given satellite at the beginning of the vector, then the rest + std::vector vector_of_channels; + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int sat = 0; + try + { + sat = configuration_->property("Channel" + std::to_string(i) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if (sat == 0) + { + vector_of_channels.push_back(i); + } + else + { + auto it = vector_of_channels.begin(); + it = vector_of_channels.insert(it, i); + } + } + + // Assign satellites to channels in the initialization + for (unsigned int& i : vector_of_channels) + { + std::string gnss_signal = channels_.at(i)->get_signal().get_signal_str(); // use channel's implicit signal + unsigned int sat = 0; + try + { + sat = configuration_->property("Channel" + std::to_string(i) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if (sat == 0) + { + channels_.at(i)->set_signal(search_next_signal(gnss_signal, false)); + } + else + { + std::string gnss_system; + Gnss_Signal signal_value; + switch (mapStringValues_[gnss_signal]) + { + case evGPS_1C: + gnss_system = "GPS"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GPS_1C_signals_.remove(signal_value); + break; + + case evGPS_2S: + gnss_system = "GPS"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GPS_2S_signals_.remove(signal_value); + break; + + case evGPS_L5: + gnss_system = "GPS"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GPS_L5_signals_.remove(signal_value); + break; + + case evGAL_1B: + gnss_system = "Galileo"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GAL_1B_signals_.remove(signal_value); + break; + + case evGAL_5X: + gnss_system = "Galileo"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GAL_5X_signals_.remove(signal_value); + break; + + case evGLO_1G: + gnss_system = "Glonass"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GLO_1G_signals_.remove(signal_value); + break; + + case evGLO_2G: + gnss_system = "Glonass"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GLO_2G_signals_.remove(signal_value); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + gnss_system = "GPS"; + signal_value = Gnss_Signal(Gnss_Satellite(gnss_system, sat), gnss_signal); + available_GPS_1C_signals_.remove(signal_value); + break; + } + + channels_.at(i)->set_signal(signal_value); + } + } + + // Connect the observables output of each channel to the PVT block + try + { + for (unsigned int i = 0; i < channels_count_; i++) + { + top_block_->connect(observables_->get_right_block(), i, pvt_->get_left_block(), i); + top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); + } + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect observables to PVT"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + + // GNSS SYNCHRO MONITOR + if (enable_monitor_) + { + try + { + for (unsigned int i = 0; i < channels_count_; i++) + { + top_block_->connect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); + } + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect observables to Monitor block"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } + + // Activate acquisition in enabled channels + for (unsigned int i = 0; i < channels_count_; i++) + { + LOG(INFO) << "Channel " << i << " assigned to " << channels_.at(i)->get_signal(); if (channels_state_[i] == 1) { - channels_.at(i)->start_acquisition(); - available_GNSS_signals_.pop_front(); - LOG(INFO) << "Channel " << i << " assigned to " << available_GNSS_signals_.front(); + if (FPGA_enabled == false) + { + channels_.at(i)->start_acquisition(); + } LOG(INFO) << "Channel " << i << " connected to observables and ready for acquisition"; } else @@ -314,31 +664,253 @@ void GNSSFlowgraph::connect() } } - /* - * Connect the observables output of each channel to the PVT block - */ - try - { - for (unsigned int i = 0; i < channels_count_; i++) - { - top_block_->connect(observables_->get_right_block(), i, pvt_->get_left_block(), i); - top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); - } - } - catch (std::exception& e) - { - LOG(WARNING) << "Can't connect observables to PVT"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - connected_ = true; LOG(INFO) << "Flowgraph connected"; top_block_->dump(); } +void GNSSFlowgraph::disconnect() +{ + LOG(INFO) << "Disconnecting flowgraph"; + + if (!connected_) + { + LOG(INFO) << "flowgraph was not connected"; + return; + } + connected_ = false; + // Signal Source (i) > Signal conditioner (i) > + int RF_Channels = 0; + int signal_conditioner_ID = 0; + + for (int i = 0; i < sources_count_; i++) + { + try + { + // TODO: Remove this array implementation and create generic multistream connector + // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") + { + //Multichannel Array + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); + } + } + else + { + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) + { + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + } + signal_conditioner_ID++; + } + } + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); + top_block_->disconnect_all(); + return; + } + } + +#if ENABLE_FPGA + bool FPGA_enabled = configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false); + if (FPGA_enabled == false) + { + // disconnect the signal source to sample counter + // disconnect the sample counter to Observables + try + { + top_block_->disconnect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter, 0); + top_block_->disconnect(ch_out_sample_counter, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't disconnect sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } + else + { + try + { + top_block_->disconnect(ch_out_fpga_sample_counter, 0, observables_->get_left_block(), channels_count_); + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect FPGA sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } +#else + // disconnect the signal source to sample counter + // disconnect the sample counter to Observables + try + { + top_block_->disconnect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter, 0); + top_block_->disconnect(ch_out_sample_counter, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } +#endif + // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) + int selected_signal_conditioner_ID; + for (unsigned int i = 0; i < channels_count_; i++) + { + try + { + selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + top_block_->disconnect_all(); + return; + } + try + { + top_block_->disconnect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i << ": " << e.what(); + top_block_->disconnect_all(); + return; + } + + // Signal Source > Signal conditioner >> Channels >> Observables + try + { + top_block_->disconnect(channels_.at(i)->get_right_block(), 0, + observables_->get_left_block(), i); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect channel " << i << " to observables: " << e.what(); + top_block_->disconnect_all(); + return; + } + } + + try + { + for (unsigned int i = 0; i < channels_count_; i++) + { + top_block_->disconnect(observables_->get_right_block(), i, pvt_->get_left_block(), i); + top_block_->msg_disconnect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); + } + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect observables to PVT: " << e.what(); + top_block_->disconnect_all(); + return; + } + + for (int i = 0; i < sources_count_; i++) + { + try + { + sig_source_.at(i)->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source block " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return; + } + } + + // Signal Source > Signal conditioner > + for (unsigned int i = 0; i < sig_conditioner_.size(); i++) + { + try + { + sig_conditioner_.at(i)->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal conditioner block " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return; + } + } + + for (unsigned int i = 0; i < channels_count_; i++) + { + try + { + channels_.at(i)->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect channel " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return; + } + } + + try + { + observables_->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect observables block internally: " << e.what(); + top_block_->disconnect_all(); + return; + } + + // Signal Source > Signal conditioner >> Channels >> Observables > PVT + try + { + pvt_->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect PVT block internally: " << e.what(); + top_block_->disconnect_all(); + return; + } + + DLOG(INFO) << "blocks disconnected internally"; + LOG(INFO) << "Flowgraph disconnected"; +} + + void GNSSFlowgraph::wait() { if (!running_) @@ -352,95 +924,454 @@ void GNSSFlowgraph::wait() } -bool GNSSFlowgraph::send_telemetry_msg(pmt::pmt_t msg) +bool GNSSFlowgraph::send_telemetry_msg(const pmt::pmt_t& msg) { - //push ephemeris to PVT telemetry msg in port using a channel out port - // it uses the first channel as a message produces (it is already connected to PVT) + // Push ephemeris to PVT telemetry msg in port using a channel out port + // it uses the first channel as a message producer (it is already connected to PVT) channels_.at(0)->get_right_block()->message_port_pub(pmt::mp("telemetry"), msg); return true; } + /* - * Applies an action to the flowgraph + * Applies an action to the flow graph * - * \param[in] who Who generated the action - * \param[in] what What is the action 0: acquisition failed + * \param[in] who Who generated the action: + * -> 0-199 are the channels IDs + * -> 200 is the control_thread dispatched by the control_thread apply_action + * -> 300 is the telecommand system (TC) for receiver control + * -> 400 - 599 is the TC channel control for channels 0-199 + * \param[in] what What is the action: + * --- actions from channels --- + * -> 0 acquisition failed + * -> 1 acquisition succesfull + * -> 2 tracking lost + * --- actions from TC receiver control --- + * -> 10 TC request standby mode + * -> 11 TC request coldstart + * -> 12 TC request hotstart + * -> 13 TC request warmstart + * --- actions from TC channel control --- + * -> 20 stop channel + * -> 21 start channel */ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) { - DLOG(INFO) << "received " << what << " from " << who; - + std::lock_guard lock(signal_list_mutex); + DLOG(INFO) << "Received " << what << " from " << who << ". Number of applied actions = " << applied_actions_; + unsigned int sat = 0; + if (who < 200) + { + try + { + sat = configuration_->property("Channel" + std::to_string(who) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + } switch (what) - { - case 0: - LOG(INFO) << "Channel " << who << " ACQ FAILED satellite " << channels_.at(who)->get_signal().get_satellite() << ", Signal " << channels_.at(who)->get_signal().get_signal_str(); - available_GNSS_signals_.push_back(channels_.at(who)->get_signal()); - //TODO: Optimize the channel and signal matching! - while ( channels_.at(who)->get_signal().get_signal_str().compare(available_GNSS_signals_.front().get_signal_str()) != 0 ) - { - available_GNSS_signals_.push_back(available_GNSS_signals_.front()); - available_GNSS_signals_.pop_front(); - } - channels_.at(who)->set_signal(available_GNSS_signals_.front()); - available_GNSS_signals_.pop_front(); - usleep(100); - channels_.at(who)->start_acquisition(); - break; - case 1: - LOG(INFO) << "Channel " << who << " ACQ SUCCESS satellite " << channels_.at(who)->get_signal().get_satellite(); - channels_state_[who] = 2; - acq_channels_count_--; - if (!available_GNSS_signals_.empty() && acq_channels_count_ < max_acq_channels_) - { - for (unsigned int i = 0; i < channels_count_; i++) - { - if (channels_state_[i] == 0) - { - channels_state_[i] = 1; - while (channels_.at(i)->get_signal().get_signal_str().compare(available_GNSS_signals_.front().get_signal_str()) != 0 ) - { - available_GNSS_signals_.push_back(available_GNSS_signals_.front()); - available_GNSS_signals_.pop_front(); - } - channels_.at(i)->set_signal(available_GNSS_signals_.front()); - available_GNSS_signals_.pop_front(); - acq_channels_count_++; - channels_.at(i)->start_acquisition(); - break; - } - DLOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; - } - } + { + case 0: + DLOG(INFO) << "Channel " << who << " ACQ FAILED satellite " << channels_[who]->get_signal().get_satellite() << ", Signal " << channels_[who]->get_signal().get_signal_str(); + if (sat == 0) + { + Gnss_Signal gs = channels_[who]->get_signal(); + switch (mapStringValues_[gs.get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.remove(gs); + available_GPS_1C_signals_.push_back(gs); + break; - break; + case evGPS_2S: + available_GPS_2S_signals_.remove(gs); + available_GPS_2S_signals_.push_back(gs); + break; - case 2: - LOG(INFO) << "Channel " << who << " TRK FAILED satellite " << channels_.at(who)->get_signal().get_satellite(); - if (acq_channels_count_ < max_acq_channels_) - { - channels_state_[who] = 1; - acq_channels_count_++; - channels_.at(who)->start_acquisition(); - } - else - { - channels_state_[who] = 0; - available_GNSS_signals_.push_back( channels_.at(who)->get_signal() ); - } + case evGPS_L5: + available_GPS_L5_signals_.remove(gs); + available_GPS_L5_signals_.push_back(gs); + break; - // for (unsigned int i = 0; i < channels_count_; i++) - // { - // LOG(INFO) << "Channel " << i << " in state " << channels_state_[i] << std::endl; - // } - break; + case evGAL_1B: + available_GAL_1B_signals_.remove(gs); + available_GAL_1B_signals_.push_back(gs); + break; - default: - break; - } - DLOG(INFO) << "Number of available signals: " << available_GNSS_signals_.size(); + case evGAL_5X: + available_GAL_5X_signals_.remove(gs); + available_GAL_5X_signals_.push_back(gs); + break; + + case evGLO_1G: + available_GLO_1G_signals_.remove(gs); + available_GLO_1G_signals_.push_back(gs); + break; + + case evGLO_2G: + available_GLO_2G_signals_.remove(gs); + available_GLO_2G_signals_.push_back(gs); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } + } + channels_state_[who] = 0; + acq_channels_count_--; + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int ch_index = (who + i + 1) % channels_count_; + unsigned int sat_ = 0; + try + { + sat_ = configuration_->property("Channel" + std::to_string(ch_index) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if ((acq_channels_count_ < max_acq_channels_) && (channels_state_[ch_index] == 0)) + { + channels_state_[ch_index] = 1; + if (sat_ == 0) + { + channels_[ch_index]->set_signal(search_next_signal(channels_[ch_index]->get_signal().get_signal_str(), true)); + } + acq_channels_count_++; + DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); + channels_[ch_index]->start_acquisition(); + } + DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; + } + break; + + case 1: + LOG(INFO) << "Channel " << who << " ACQ SUCCESS satellite " << channels_[who]->get_signal().get_satellite(); + + // If the satellite is in the list of available ones, remove it. + switch (mapStringValues_[channels_[who]->get_signal().get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.remove(channels_[who]->get_signal()); + break; + + case evGPS_2S: + available_GPS_2S_signals_.remove(channels_[who]->get_signal()); + break; + + case evGPS_L5: + available_GPS_L5_signals_.remove(channels_[who]->get_signal()); + break; + + case evGAL_1B: + available_GAL_1B_signals_.remove(channels_[who]->get_signal()); + break; + + case evGAL_5X: + available_GAL_5X_signals_.remove(channels_[who]->get_signal()); + break; + + case evGLO_1G: + available_GLO_1G_signals_.remove(channels_[who]->get_signal()); + break; + + case evGLO_2G: + available_GLO_2G_signals_.remove(channels_[who]->get_signal()); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } + + channels_state_[who] = 2; + acq_channels_count_--; + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int sat_ = 0; + try + { + sat_ = configuration_->property("Channel" + std::to_string(i) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if ((acq_channels_count_ < max_acq_channels_) && (channels_state_[i] == 0)) + { + channels_state_[i] = 1; + if (sat_ == 0) + { + channels_[i]->set_signal(search_next_signal(channels_[i]->get_signal().get_signal_str(), true, true)); + } + acq_channels_count_++; + DLOG(INFO) << "Channel " << i << " Starting acquisition " << channels_[i]->get_signal().get_satellite() << ", Signal " << channels_[i]->get_signal().get_signal_str(); + channels_[i]->start_acquisition(); + } + DLOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; + } + break; + + case 2: + LOG(INFO) << "Channel " << who << " TRK FAILED satellite " << channels_[who]->get_signal().get_satellite(); + DLOG(INFO) << "Number of channels in acquisition = " << acq_channels_count_; + + if (acq_channels_count_ < max_acq_channels_) + { + channels_state_[who] = 1; + acq_channels_count_++; + LOG(INFO) << "Channel " << who << " Starting acquisition " << channels_[who]->get_signal().get_satellite() << ", Signal " << channels_[who]->get_signal().get_signal_str(); + channels_[who]->start_acquisition(); + } + else + { + channels_state_[who] = 0; + LOG(INFO) << "Channel " << who << " Idle state"; + if (sat == 0) + { + switch (mapStringValues_[channels_[who]->get_signal().get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGPS_2S: + available_GPS_2S_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGPS_L5: + available_GPS_L5_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGAL_1B: + available_GAL_1B_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGAL_5X: + available_GAL_5X_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGLO_1G: + available_GLO_1G_signals_.push_back(channels_[who]->get_signal()); + break; + + case evGLO_2G: + available_GLO_2G_signals_.push_back(channels_[who]->get_signal()); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } + } + } + break; + case 10: // request standby mode + LOG(INFO) << "TC request standby mode"; + for (size_t n = 0; n < channels_.size(); n++) + { + if (channels_state_[n] == 1 or channels_state_[n] == 2) //channel in acquisition or in tracking + { + //recover the satellite assigned + + Gnss_Signal gs = channels_[n]->get_signal(); + switch (mapStringValues_[gs.get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.remove(gs); + available_GPS_1C_signals_.push_back(gs); + break; + + case evGPS_2S: + available_GPS_2S_signals_.remove(gs); + available_GPS_2S_signals_.push_back(gs); + break; + + case evGPS_L5: + available_GPS_L5_signals_.remove(gs); + available_GPS_L5_signals_.push_back(gs); + break; + + case evGAL_1B: + available_GAL_1B_signals_.remove(gs); + available_GAL_1B_signals_.push_back(gs); + break; + + case evGAL_5X: + available_GAL_5X_signals_.remove(gs); + available_GAL_5X_signals_.push_back(gs); + break; + + case evGLO_1G: + available_GLO_1G_signals_.remove(gs); + available_GLO_1G_signals_.push_back(gs); + break; + + case evGLO_2G: + available_GLO_2G_signals_.remove(gs); + available_GLO_2G_signals_.push_back(gs); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } + channels_[n]->stop_channel(); //stop the acquisition or tracking operation + channels_state_[n] = 0; + } + } + acq_channels_count_ = 0; // all channels are in standby now + break; + case 11: // request coldstart mode + LOG(INFO) << "TC request flowgraph coldstart"; + //start again the satellite acquisitions + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int ch_index = (who + i + 1) % channels_count_; + unsigned int sat_ = 0; + try + { + sat_ = configuration_->property("Channel" + std::to_string(ch_index) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if ((acq_channels_count_ < max_acq_channels_) && (channels_state_[ch_index] == 0)) + { + channels_state_[ch_index] = 1; + if (sat_ == 0) + { + channels_[ch_index]->set_signal(search_next_signal(channels_[ch_index]->get_signal().get_signal_str(), true)); + } + acq_channels_count_++; + DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); + channels_[ch_index]->start_acquisition(); + } + DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; + } + break; + case 12: // request hotstart mode + LOG(INFO) << "TC request flowgraph hotstart"; + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int ch_index = (who + i + 1) % channels_count_; + unsigned int sat_ = 0; + try + { + sat_ = configuration_->property("Channel" + std::to_string(ch_index) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if ((acq_channels_count_ < max_acq_channels_) && (channels_state_[ch_index] == 0)) + { + channels_state_[ch_index] = 1; + if (sat_ == 0) + { + channels_[ch_index]->set_signal(search_next_signal(channels_[ch_index]->get_signal().get_signal_str(), true)); + } + acq_channels_count_++; + DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); + channels_[ch_index]->start_acquisition(); + } + DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; + } + break; + case 13: // request warmstart mode + LOG(INFO) << "TC request flowgraph warmstart"; + //start again the satellite acquisitions + for (unsigned int i = 0; i < channels_count_; i++) + { + unsigned int ch_index = (who + i + 1) % channels_count_; + unsigned int sat_ = 0; + try + { + sat_ = configuration_->property("Channel" + std::to_string(ch_index) + ".satellite", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + if ((acq_channels_count_ < max_acq_channels_) && (channels_state_[ch_index] == 0)) + { + channels_state_[ch_index] = 1; + if (sat_ == 0) + { + channels_[ch_index]->set_signal(search_next_signal(channels_[ch_index]->get_signal().get_signal_str(), true)); + } + acq_channels_count_++; + DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); + channels_[ch_index]->start_acquisition(); + } + DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; + } + break; + default: + break; + } + applied_actions_++; } +void GNSSFlowgraph::priorize_satellites(std::vector> visible_satellites) +{ + size_t old_size; + Gnss_Signal gs; + for (std::vector>::iterator it = visible_satellites.begin(); it != visible_satellites.end(); ++it) + { + if (it->second.get_system() == "GPS") + { + gs = Gnss_Signal(it->second, "1C"); + old_size = available_GPS_1C_signals_.size(); + available_GPS_1C_signals_.remove(gs); + if (old_size > available_GPS_1C_signals_.size()) + { + available_GPS_1C_signals_.push_front(gs); + } + + gs = Gnss_Signal(it->second, "2S"); + old_size = available_GPS_2S_signals_.size(); + available_GPS_2S_signals_.remove(gs); + if (old_size > available_GPS_2S_signals_.size()) + { + available_GPS_2S_signals_.push_front(gs); + } + + gs = Gnss_Signal(it->second, "L5"); + old_size = available_GPS_L5_signals_.size(); + available_GPS_L5_signals_.remove(gs); + if (old_size > available_GPS_L5_signals_.size()) + { + available_GPS_L5_signals_.push_front(gs); + } + } + else if (it->second.get_system() == "Galileo") + { + gs = Gnss_Signal(it->second, "1B"); + old_size = available_GAL_1B_signals_.size(); + available_GAL_1B_signals_.remove(gs); + if (old_size > available_GAL_1B_signals_.size()) + { + available_GAL_1B_signals_.push_front(gs); + } + + gs = Gnss_Signal(it->second, "5X"); + old_size = available_GAL_5X_signals_.size(); + available_GAL_5X_signals_.remove(gs); + if (old_size > available_GAL_5X_signals_.size()) + { + available_GAL_5X_signals_.push_front(gs); + } + } + } +} + void GNSSFlowgraph::set_configuration(std::shared_ptr configuration) { @@ -449,7 +1380,6 @@ void GNSSFlowgraph::set_configuration(std::shared_ptr co LOG(WARNING) << "Unable to update configuration while flowgraph running"; return; } - if (connected_) { LOG(WARNING) << "Unable to update configuration while flowgraph connected"; @@ -458,6 +1388,17 @@ void GNSSFlowgraph::set_configuration(std::shared_ptr co } +void GNSSFlowgraph::start_acquisition_helper() +{ + for (unsigned int i = 0; i < channels_count_; i++) + { + if (channels_state_[i] == 1) + { + channels_.at(i)->start_acquisition(); + } + } +} + void GNSSFlowgraph::init() { @@ -478,9 +1419,9 @@ void GNSSFlowgraph::init() { std::cout << "Creating source " << i << std::endl; sig_source_.push_back(block_factory_->GetSignalSource(configuration_, queue_, i)); - //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - //Include GetRFChannels in the interface to avoid read config parameters here - //read the number of RF channels for each front-end + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); std::cout << "RF Channels " << RF_Channels << std::endl; for (int j = 0; j < RF_Channels; j++) @@ -492,11 +1433,11 @@ void GNSSFlowgraph::init() } else { - //backwards compatibility for old config files + // backwards compatibility for old config files sig_source_.push_back(block_factory_->GetSignalSource(configuration_, queue_, -1)); - //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - //Include GetRFChannels in the interface to avoid read config parameters here - //read the number of RF channels for each front-end + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); if (RF_Channels != 0) { @@ -508,17 +1449,33 @@ void GNSSFlowgraph::init() } else { - //old config file, single signal source and single channel, not specified + // old config file, single signal source and single channel, not specified sig_conditioner_.push_back(block_factory_->GetSignalConditioner(configuration_, -1)); } } observables_ = block_factory_->GetObservables(configuration_); + // Mark old implementations as deprecated + std::string default_str("Default"); + std::string obs_implementation = configuration_->property("Observables.implementation", default_str); + if ((obs_implementation == "GPS_L1_CA_Observables") || (obs_implementation == "GPS_L2C_Observables") || + (obs_implementation == "Galileo_E1B_Observables") || (obs_implementation == "Galileo_E5A_Observables")) + { + std::cout << "WARNING: Implementation '" << obs_implementation << "' of the Observables block has been replaced by 'Hybrid_Observables'." << std::endl; + std::cout << "Please update your configuration file." << std::endl; + } + pvt_ = block_factory_->GetPVT(configuration_); + // Mark old implementations as deprecated + std::string pvt_implementation = configuration_->property("PVT.implementation", default_str); + if ((pvt_implementation == "GPS_L1_CA_PVT") || (pvt_implementation == "Galileo_E1_PVT") || (pvt_implementation == "Hybrid_PVT")) + { + std::cout << "WARNING: Implementation '" << pvt_implementation << "' of the PVT block has been replaced by 'RTKLIB_PVT'." << std::endl; + std::cout << "Please update your configuration file." << std::endl; + } std::shared_ptr>> channels = block_factory_->GetChannels(configuration_, queue_); - //todo:check smart pointer coherence... channels_count_ = channels->size(); for (unsigned int i = 0; i < channels_count_; i++) { @@ -528,209 +1485,233 @@ void GNSSFlowgraph::init() top_block_ = gr::make_top_block("GNSSFlowgraph"); - // fill the available_GNSS_signals_ queue with the satellites ID's to be searched by the acquisition + mapStringValues_["1C"] = evGPS_1C; + mapStringValues_["2S"] = evGPS_2S; + mapStringValues_["L5"] = evGPS_L5; + mapStringValues_["1B"] = evGAL_1B; + mapStringValues_["5X"] = evGAL_5X; + mapStringValues_["1G"] = evGLO_1G; + mapStringValues_["2G"] = evGLO_2G; + + // fill the signals queue with the satellites ID's to be searched by the acquisition set_signals_list(); set_channels_state(); applied_actions_ = 0; - DLOG(INFO) << "Blocks instantiated. " << channels_count_ << " channels."; + + /* + * Instantiate the receiver monitor block, if required + */ + enable_monitor_ = configuration_->property("Monitor.enable_monitor", false); + + std::string address_string = configuration_->property("Monitor.client_addresses", std::string("127.0.0.1")); + std::vector udp_addr_vec = split_string(address_string, '_'); + std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); + udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + + if (enable_monitor_) + { + GnssSynchroMonitor_ = gr::basic_block_sptr(new gnss_synchro_monitor(channels_count_, + configuration_->property("Monitor.output_rate_ms", 1), + configuration_->property("Monitor.udp_port", 1234), + udp_addr_vec)); + } } void GNSSFlowgraph::set_signals_list() { - /* - * Sets a sequential list of GNSS satellites - */ - std::set::iterator available_gnss_prn_iter; + // Set a sequential list of GNSS satellites + std::set::const_iterator available_gnss_prn_iter; - /* - * \TODO Describe GNSS satellites more nicely, with RINEX notation - * See http://igscb.jpl.nasa.gov/igscb/data/format/rinex301.pdf (page 5) - */ + // Create the lists of GNSS satellites + std::set available_gps_prn = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32}; - /* - * Read GNSS-SDR default GNSS system and signal - */ + std::set available_sbas_prn = {123, 131, 135, 136, 138}; - unsigned int total_channels = configuration_->property("Channels_1C.count", 0) + - configuration_->property("Channels_2S.count", 0) + - configuration_->property("Channels_1B.count", 0) + - configuration_->property("Channels_5X.count", 0); + std::set available_galileo_prn = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36}; - /* - * Loop to create the list of GNSS Signals - * To add signals from other systems, add another loop 'for' - */ + // Removing satellites sharing same frequency number(1 and 5, 2 and 6, 3 and 7, 4 and 6, 11 and 15, 12 and 16, 14 and 18, 17 and 21 + std::set available_glonass_prn = {1, 2, 3, 4, 9, 10, 11, 12, 18, 19, 20, 21, 24}; - std::set available_gps_prn = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32 }; + std::string sv_list = configuration_->property("Galileo.prns", std::string("")); - std::set available_sbas_prn = {120, 124, 126}; - - std::set available_galileo_prn = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36}; - - std::string sv_list = configuration_->property("Galileo.prns", std::string("") ); - - if( sv_list.length() > 0 ) + if (sv_list.length() > 0) { // Reset the available prns: - std::set< unsigned int > tmp_set; - boost::tokenizer<> tok( sv_list ); - std::transform( tok.begin(), tok.end(), std::inserter( tmp_set, tmp_set.begin() ), - boost::lexical_cast ); + std::set tmp_set; + boost::tokenizer<> tok(sv_list); + std::transform(tok.begin(), tok.end(), std::inserter(tmp_set, tmp_set.begin()), + boost::lexical_cast); - if( tmp_set.size() > 0 ) + if (tmp_set.size() > 0) { available_galileo_prn = tmp_set; } } - sv_list = configuration_->property("GPS.prns", std::string("") ); + sv_list = configuration_->property("GPS.prns", std::string("")); - if( sv_list.length() > 0 ) + if (sv_list.length() > 0) { // Reset the available prns: - std::set< unsigned int > tmp_set; - boost::tokenizer<> tok( sv_list ); - std::transform( tok.begin(), tok.end(), std::inserter( tmp_set, tmp_set.begin() ), - boost::lexical_cast ); + std::set tmp_set; + boost::tokenizer<> tok(sv_list); + std::transform(tok.begin(), tok.end(), std::inserter(tmp_set, tmp_set.begin()), + boost::lexical_cast); - if( tmp_set.size() > 0 ) + if (tmp_set.size() > 0) { available_gps_prn = tmp_set; } } - sv_list = configuration_->property("SBAS.prns", std::string("") ); + sv_list = configuration_->property("SBAS.prns", std::string("")); - if( sv_list.length() > 0 ) + if (sv_list.length() > 0) { // Reset the available prns: - std::set< unsigned int > tmp_set; - boost::tokenizer<> tok( sv_list ); - std::transform( tok.begin(), tok.end(), std::inserter( tmp_set, tmp_set.begin() ), - boost::lexical_cast ); + std::set tmp_set; + boost::tokenizer<> tok(sv_list); + std::transform(tok.begin(), tok.end(), std::inserter(tmp_set, tmp_set.begin()), + boost::lexical_cast); - if( tmp_set.size() > 0 ) + if (tmp_set.size() > 0) { available_sbas_prn = tmp_set; } } - if (configuration_->property("Channels_1C.count", 0) > 0 ) + sv_list = configuration_->property("Glonass.prns", std::string("")); + + if (sv_list.length() > 0) { - /* - * Loop to create GPS L1 C/A signals - */ - for (available_gnss_prn_iter = available_gps_prn.begin(); - available_gnss_prn_iter != available_gps_prn.end(); - available_gnss_prn_iter++) + // Reset the available prns: + std::set tmp_set; + boost::tokenizer<> tok(sv_list); + std::transform(tok.begin(), tok.end(), std::inserter(tmp_set, tmp_set.begin()), + boost::lexical_cast); + + if (tmp_set.size() > 0) { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("GPS"), - *available_gnss_prn_iter), std::string("1C"))); + available_glonass_prn = tmp_set; + } + } + + if (configuration_->property("Channels_1C.count", 0) > 0) + { + // Loop to create GPS L1 C/A signals + for (available_gnss_prn_iter = available_gps_prn.cbegin(); + available_gnss_prn_iter != available_gps_prn.cend(); + available_gnss_prn_iter++) + { + available_GPS_1C_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("GPS"), *available_gnss_prn_iter), + std::string("1C"))); } } if (configuration_->property("Channels_2S.count", 0) > 0) { - /* - * Loop to create GPS L2C M signals - */ - for (available_gnss_prn_iter = available_gps_prn.begin(); - available_gnss_prn_iter != available_gps_prn.end(); - available_gnss_prn_iter++) + // Loop to create GPS L2C M signals + for (available_gnss_prn_iter = available_gps_prn.cbegin(); + available_gnss_prn_iter != available_gps_prn.cend(); + available_gnss_prn_iter++) { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("GPS"), - *available_gnss_prn_iter), std::string("2S"))); + available_GPS_2S_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("GPS"), *available_gnss_prn_iter), + std::string("2S"))); + } + } + + if (configuration_->property("Channels_L5.count", 0) > 0) + { + // Loop to create GPS L5 signals + for (available_gnss_prn_iter = available_gps_prn.cbegin(); + available_gnss_prn_iter != available_gps_prn.cend(); + available_gnss_prn_iter++) + { + available_GPS_L5_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("GPS"), *available_gnss_prn_iter), + std::string("L5"))); } } if (configuration_->property("Channels_SBAS.count", 0) > 0) { - /* - * Loop to create SBAS L1 C/A signals - */ - for (available_gnss_prn_iter = available_sbas_prn.begin(); - available_gnss_prn_iter != available_sbas_prn.end(); - available_gnss_prn_iter++) + // Loop to create SBAS L1 C/A signals + for (available_gnss_prn_iter = available_sbas_prn.cbegin(); + available_gnss_prn_iter != available_sbas_prn.cend(); + available_gnss_prn_iter++) { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("SBAS"), - *available_gnss_prn_iter), std::string("1C"))); + available_SBAS_1C_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("SBAS"), *available_gnss_prn_iter), + std::string("1C"))); } } - if (configuration_->property("Channels_1B.count", 0) > 0) { - /* - * Loop to create the list of Galileo E1 B signals - */ - for (available_gnss_prn_iter = available_galileo_prn.begin(); - available_gnss_prn_iter != available_galileo_prn.end(); - available_gnss_prn_iter++) + // Loop to create the list of Galileo E1B signals + for (available_gnss_prn_iter = available_galileo_prn.cbegin(); + available_gnss_prn_iter != available_galileo_prn.cend(); + available_gnss_prn_iter++) { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("Galileo"), - *available_gnss_prn_iter), std::string("1B"))); + available_GAL_1B_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("Galileo"), *available_gnss_prn_iter), + std::string("1B"))); } } - if (configuration_->property("Channels_5X.count", 0) > 0 ) + if (configuration_->property("Channels_5X.count", 0) > 0) { - /* - * Loop to create the list of Galileo E1 B signals - */ - for (available_gnss_prn_iter = available_galileo_prn.begin(); - available_gnss_prn_iter != available_galileo_prn.end(); - available_gnss_prn_iter++) + // Loop to create the list of Galileo E5a signals + for (available_gnss_prn_iter = available_galileo_prn.cbegin(); + available_gnss_prn_iter != available_galileo_prn.cend(); + available_gnss_prn_iter++) { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("Galileo"), - *available_gnss_prn_iter), std::string("5X"))); + available_GAL_5X_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("Galileo"), *available_gnss_prn_iter), + std::string("5X"))); } } - /* - * Ordering the list of signals from configuration file - */ - std::list::iterator gnss_it = available_GNSS_signals_.begin(); - // Pre-assignation if not defined at ChannelX.signal=1C ...? In what order? - - for (unsigned int i = 0; i < total_channels; i++) + if (configuration_->property("Channels_1G.count", 0) > 0) { - std::string gnss_signal = (configuration_->property("Channel" + boost::lexical_cast(i) + ".signal", std::string("1C"))); - std::string gnss_system; - if((gnss_signal.compare("1C") == 0) or (gnss_signal.compare("2S") == 0) ) gnss_system = "GPS"; - if((gnss_signal.compare("1B") == 0) or (gnss_signal.compare("5X") == 0) ) gnss_system = "Galileo"; - unsigned int sat = configuration_->property("Channel" + boost::lexical_cast(i) + ".satellite", 0); - LOG(INFO) << "Channel " << i << " system " << gnss_system << ", signal " << gnss_signal <<", sat "<::iterator available_gnss_list_iter; - // for (available_gnss_list_iter = available_GNSS_signals_.begin(); available_gnss_list_iter - // != available_GNSS_signals_.end(); available_gnss_list_iter++) - // { - // std::cout << *available_gnss_list_iter << std::endl; - // } + if (configuration_->property("Channels_2G.count", 0) > 0) + { + // Loop to create the list of GLONASS L2 C/A signals + for (available_gnss_prn_iter = available_glonass_prn.cbegin(); + available_gnss_prn_iter != available_glonass_prn.cend(); + available_gnss_prn_iter++) + { + available_GLO_2G_signals_.push_back(Gnss_Signal( + Gnss_Satellite(std::string("Glonass"), *available_gnss_prn_iter), + std::string("2G"))); + } + } } void GNSSFlowgraph::set_channels_state() { - max_acq_channels_ = (configuration_->property("Channels.in_acquisition", channels_count_)); + std::lock_guard lock(signal_list_mutex); + max_acq_channels_ = configuration_->property("Channels.in_acquisition", channels_count_); if (max_acq_channels_ > channels_count_) { max_acq_channels_ = channels_count_; @@ -744,9 +1725,237 @@ void GNSSFlowgraph::set_channels_state() channels_state_.push_back(1); } else - channels_state_.push_back(0); + { + channels_state_.push_back(0); + } DLOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; } acq_channels_count_ = max_acq_channels_; DLOG(INFO) << acq_channels_count_ << " channels in acquisition state"; } + + +Gnss_Signal GNSSFlowgraph::search_next_signal(const std::string& searched_signal, bool pop, bool tracked) +{ + Gnss_Signal result; + bool untracked_satellite = true; + switch (mapStringValues_[searched_signal]) + { + case evGPS_1C: + result = available_GPS_1C_signals_.front(); + available_GPS_1C_signals_.pop_front(); + if (!pop) + { + available_GPS_1C_signals_.push_back(result); + } + if (tracked) + { + if ((configuration_->property("Channels_2S.count", 0) > 0) or (configuration_->property("Channels_L5.count", 0) > 0)) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "1C")) untracked_satellite = false; + } + if (untracked_satellite and configuration_->property("Channels_2S.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "2S"); + available_GPS_2S_signals_.remove(gs); + available_GPS_2S_signals_.push_front(gs); + } + if (untracked_satellite and configuration_->property("Channels_L5.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "L5"); + available_GPS_L5_signals_.remove(gs); + available_GPS_L5_signals_.push_front(gs); + } + } + } + break; + + case evGPS_2S: + result = available_GPS_2S_signals_.front(); + available_GPS_2S_signals_.pop_front(); + if (!pop) + { + available_GPS_2S_signals_.push_back(result); + } + if (tracked) + { + if ((configuration_->property("Channels_1C.count", 0) > 0) or (configuration_->property("Channels_L5.count", 0) > 0)) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "2S")) untracked_satellite = false; + } + if (untracked_satellite and configuration_->property("Channels_1C.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "1C"); + available_GPS_1C_signals_.remove(gs); + available_GPS_1C_signals_.push_front(gs); + } + if (untracked_satellite and configuration_->property("Channels_L5.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "L5"); + available_GPS_L5_signals_.remove(gs); + available_GPS_L5_signals_.push_front(gs); + } + } + } + break; + + case evGPS_L5: + result = available_GPS_L5_signals_.front(); + available_GPS_L5_signals_.pop_front(); + if (!pop) + { + available_GPS_L5_signals_.push_back(result); + } + if (tracked) + { + if ((configuration_->property("Channels_1C.count", 0) > 0) or (configuration_->property("Channels_2S.count", 0) > 0)) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "L5")) untracked_satellite = false; + } + if (untracked_satellite and configuration_->property("Channels_1C.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "1C"); + available_GPS_1C_signals_.remove(gs); + available_GPS_1C_signals_.push_front(gs); + } + if (untracked_satellite and configuration_->property("Channels_2S.count", 0) > 0) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "2S"); + available_GPS_2S_signals_.remove(gs); + available_GPS_2S_signals_.push_front(gs); + } + } + } + break; + + case evGAL_1B: + result = available_GAL_1B_signals_.front(); + available_GAL_1B_signals_.pop_front(); + if (!pop) + { + available_GAL_1B_signals_.push_back(result); + } + if (tracked) + { + if (configuration_->property("Channels_5X.count", 0) > 0) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "1B")) untracked_satellite = false; + } + if (untracked_satellite) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "5X"); + available_GAL_5X_signals_.remove(gs); + available_GAL_5X_signals_.push_front(gs); + } + } + } + break; + + case evGAL_5X: + result = available_GAL_5X_signals_.front(); + available_GAL_5X_signals_.pop_front(); + if (!pop) + { + available_GAL_5X_signals_.push_back(result); + } + if (tracked) + { + if (configuration_->property("Channels_1B.count", 0) > 0) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "5X")) untracked_satellite = false; + } + if (untracked_satellite) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "1B"); + available_GAL_1B_signals_.remove(gs); + available_GAL_1B_signals_.push_front(gs); + } + } + } + break; + + case evGLO_1G: + result = available_GLO_1G_signals_.front(); + available_GLO_1G_signals_.pop_front(); + if (!pop) + { + available_GLO_1G_signals_.push_back(result); + } + if (tracked) + { + if (configuration_->property("Channels_2G.count", 0) > 0) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "1G")) untracked_satellite = false; + } + if (untracked_satellite) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "2G"); + available_GLO_2G_signals_.remove(gs); + available_GLO_2G_signals_.push_front(gs); + } + } + } + break; + + case evGLO_2G: + result = available_GLO_2G_signals_.front(); + available_GLO_2G_signals_.pop_front(); + if (!pop) + { + available_GLO_2G_signals_.push_back(result); + } + if (tracked) + { + if (configuration_->property("Channels_1G.count", 0) > 0) + { + for (unsigned int ch = 0; ch < channels_count_; ch++) + { + if ((channels_[ch]->get_signal().get_satellite() == result.get_satellite()) and (channels_[ch]->get_signal().get_signal_str() != "2G")) untracked_satellite = false; + } + if (untracked_satellite) + { + Gnss_Signal gs = Gnss_Signal(result.get_satellite(), "1G"); + available_GLO_1G_signals_.remove(gs); + available_GLO_1G_signals_.push_front(gs); + } + } + } + break; + + default: + LOG(ERROR) << "This should not happen :-("; + result = available_GPS_1C_signals_.front(); + if (pop) + { + available_GPS_1C_signals_.pop_front(); + } + break; + } + return result; +} + +std::vector GNSSFlowgraph::split_string(const std::string& s, char delim) +{ + std::vector v; + std::stringstream ss(s); + std::string item; + + while (std::getline(ss, item, delim)) + { + *(std::back_inserter(v)++) = item; + } + + return v; +} diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index ad06267b9..929243939 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -1,16 +1,17 @@ /*! * \file gnss_flowgraph.h - * \brief Interface of a GNSS receiver flowgraph. + * \brief Interface of a GNSS receiver flow graph. * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Luis Esteve, 2011. luis(at)epsilon-formacion.com * Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * It contains a signal source, - * a signal conditioner, a set of channels, a pvt and an output filter. + * a signal conditioner, a set of channels, an observables block and a pvt. * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,7 +29,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,22 +37,32 @@ #ifndef GNSS_SDR_GNSS_FLOWGRAPH_H_ #define GNSS_SDR_GNSS_FLOWGRAPH_H_ +#include "GPS_L1_CA.h" +#include "channel_interface.h" +#include "configuration_interface.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_sample_counter.h" +#include "gnss_signal.h" +#include "gnss_synchro_monitor.h" +#include "pvt_interface.h" +#include +#include #include +#include #include +#include #include #include #include -#include -#include -#include "GPS_L1_CA.h" -#include "gnss_signal.h" +#include -class GNSSBlockInterface; -class ChannelInterface; -class ConfigurationInterface; -class GNSSBlockFactory; +#if ENABLE_FPGA +#include "gnss_sdr_fpga_sample_counter.h" +#endif -/*! \brief This class represents a GNSS flowgraph. + +/*! \brief This class represents a GNSS flow graph. * * It contains a signal source, * a signal conditioner, a set of channels, a PVT and an output filter. @@ -60,64 +71,85 @@ class GNSSFlowgraph { public: /*! - * \brief Constructor that initializes the receiver flowgraph + * \brief Constructor that initializes the receiver flow graph */ - GNSSFlowgraph(std::shared_ptr configuration, - boost::shared_ptr queue); + GNSSFlowgraph(std::shared_ptr configuration, const gr::msg_queue::sptr& queue); /*! - * \brief Virtual destructor + * \brief Destructor */ - virtual ~GNSSFlowgraph(); + ~GNSSFlowgraph(); - //! \brief Start the flowgraph + //! \brief Start the flow graph void start(); - //! \brief Stop the flowgraph + //! \brief Stop the flow graph void stop(); /*! - * \brief Connects the defined blocks in the flowgraph + * \brief Connects the defined blocks in the flow graph * * Signal Source > Signal conditioner > Channels >> Observables >> PVT > Output filter */ void connect(); + void disconnect(); + void wait(); + void start_acquisition_helper(); + /*! - * \brief Applies an action to the flowgraph + * \brief Applies an action to the flow graph * * \param[in] who Who generated the action - * \param[in] what What is the action 0: acquisition failed + * \param[in] what What is the action. 0: acquisition failed; 1: acquisition success; 2: tracking lost */ void apply_action(unsigned int who, unsigned int what); void set_configuration(std::shared_ptr configuration); - unsigned int applied_actions() + unsigned int applied_actions() const { return applied_actions_; } - bool connected() + + bool connected() const { return connected_; } - bool running() + + bool running() const { return running_; } + /*! - * \brief Sends a GNURadio asyncronous message from telemetry to PVT + * \brief Sends a GNURadio asynchronous message from telemetry to PVT * * It is used to assist the receiver with external ephemeris data */ - bool send_telemetry_msg(pmt::pmt_t msg); + bool send_telemetry_msg(const pmt::pmt_t& msg); + + /*! + * \brief Returns a smart pointer to the PVT object + */ + std::shared_ptr get_pvt() + { + return std::dynamic_pointer_cast(pvt_); + } + + /*! + * \brief Priorize visible satellites in the specified vector + */ + void priorize_satellites(std::vector> visible_satellites); + private: - void init(); // Populates the SV PRN list available for acquisition and tracking + void init(); // Populates the SV PRN list available for acquisition and tracking void set_signals_list(); - void set_channels_state(); // Initializes the channels state (start acquisition or keep standby) - // using the configuration parameters (number of channels and max channels in acquisition) + void set_channels_state(); // Initializes the channels state (start acquisition or keep standby) + // using the configuration parameters (number of channels and max channels in acquisition) + Gnss_Signal search_next_signal(const std::string& searched_signal, bool pop, bool tracked = false); bool connected_; bool running_; int sources_count_; @@ -135,11 +167,42 @@ private: std::shared_ptr observables_; std::shared_ptr pvt_; + std::map acq_resamplers_; std::vector> channels_; + gnss_sdr_sample_counter_sptr ch_out_sample_counter; +#if ENABLE_FPGA + gnss_sdr_fpga_sample_counter_sptr ch_out_fpga_sample_counter; +#endif gr::top_block_sptr top_block_; - boost::shared_ptr queue_; - std::list available_GNSS_signals_; + gr::msg_queue::sptr queue_; + + std::list available_GPS_1C_signals_; + std::list available_GPS_2S_signals_; + std::list available_GPS_L5_signals_; + std::list available_SBAS_1C_signals_; + std::list available_GAL_1B_signals_; + std::list available_GAL_5X_signals_; + std::list available_GLO_1G_signals_; + std::list available_GLO_2G_signals_; + enum StringValue + { + evGPS_1C, + evGPS_2S, + evGPS_L5, + evSBAS_1C, + evGAL_1B, + evGAL_5X, + evGLO_1G, + evGLO_2G + }; + std::map mapStringValues_; + std::vector channels_state_; + std::mutex signal_list_mutex; + + bool enable_monitor_; + gr::basic_block_sptr GnssSynchroMonitor_; + std::vector split_string(const std::string& s, char delim); }; #endif /*GNSS_SDR_GNSS_FLOWGRAPH_H_*/ diff --git a/src/core/receiver/in_memory_configuration.cc b/src/core/receiver/in_memory_configuration.cc index e1983e617..4801d2eb2 100644 --- a/src/core/receiver/in_memory_configuration.cc +++ b/src/core/receiver/in_memory_configuration.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,16 +24,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "in_memory_configuration.h" +#include "string_converter.h" #include #include -#include "string_converter.h" + InMemoryConfiguration::InMemoryConfiguration() { @@ -49,63 +50,74 @@ InMemoryConfiguration::~InMemoryConfiguration() std::string InMemoryConfiguration::property(std::string property_name, std::string default_value) { - std::map::iterator iter = properties_.find(property_name); - if(iter != properties_.end()) + auto iter = properties_.find(property_name); + if (iter != properties_.end()) { return iter->second; } - else - { - return default_value; - } + return default_value; } bool InMemoryConfiguration::property(std::string property_name, bool default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } -long InMemoryConfiguration::property(std::string property_name, long default_value) +int64_t InMemoryConfiguration::property(std::string property_name, int64_t default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } -int InMemoryConfiguration::property(std::string property_name, int default_value) +uint64_t InMemoryConfiguration::property(std::string property_name, uint64_t default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } -unsigned int InMemoryConfiguration::property(std::string property_name, unsigned int default_value) +int32_t InMemoryConfiguration::property(std::string property_name, int32_t default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } -unsigned short InMemoryConfiguration::property(std::string property_name, unsigned short default_value) +uint32_t InMemoryConfiguration::property(std::string property_name, uint32_t default_value) { - std::string empty = ""; + std::string empty; + return converter_->convert(property(property_name, empty), default_value); +} + + +uint16_t InMemoryConfiguration::property(std::string property_name, uint16_t default_value) +{ + std::string empty; + return converter_->convert(property(property_name, empty), default_value); +} + + +int16_t InMemoryConfiguration::property(std::string property_name, int16_t default_value) +{ + std::string empty; return converter_->convert(property(property_name, empty), default_value); } float InMemoryConfiguration::property(std::string property_name, float default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } double InMemoryConfiguration::property(std::string property_name, double default_value) { - std::string empty = ""; + std::string empty; return converter_->convert(property(property_name, empty), default_value); } @@ -116,7 +128,14 @@ void InMemoryConfiguration::set_property(std::string property_name, std::string } -bool InMemoryConfiguration::is_present(std::string property_name) +void InMemoryConfiguration::supersede_property(std::string property_name, std::string value) +{ + properties_.erase(property_name); + properties_.insert(std::make_pair(property_name, value)); +} + + +bool InMemoryConfiguration::is_present(const std::string& property_name) { return (properties_.find(property_name) != properties_.end()); } diff --git a/src/core/receiver/in_memory_configuration.h b/src/core/receiver/in_memory_configuration.h index 22ff97ffe..698071a36 100644 --- a/src/core/receiver/in_memory_configuration.h +++ b/src/core/receiver/in_memory_configuration.h @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,20 +26,21 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - #ifndef GNSS_SDR_IN_MEMORY_CONFIGURATION_H_ #define GNSS_SDR_IN_MEMORY_CONFIGURATION_H_ +#include "configuration_interface.h" +#include #include #include #include -#include "configuration_interface.h" + class StringConverter; @@ -56,14 +57,18 @@ public: virtual ~InMemoryConfiguration(); std::string property(std::string property_name, std::string default_value); bool property(std::string property_name, bool default_value); - long property(std::string property_name, long default_value); - int property(std::string property_name, int default_value); - unsigned int property(std::string property_name, unsigned int default_value); - unsigned short property(std::string property_name, unsigned short default_value); + int64_t property(std::string property_name, int64_t default_value); + uint64_t property(std::string property_name, uint64_t default_value); + int32_t property(std::string property_name, int32_t default_value); + uint32_t property(std::string property_name, uint32_t default_value); + int16_t property(std::string property_name, int16_t default_value); + uint16_t property(std::string property_name, uint16_t default_value); float property(std::string property_name, float default_value); double property(std::string property_name, double default_value); void set_property(std::string property_name, std::string value); - bool is_present(std::string property_name); + void supersede_property(std::string property_name, std::string value); + bool is_present(const std::string& property_name); + private: std::map properties_; std::unique_ptr converter_; diff --git a/src/core/receiver/tcp_cmd_interface.cc b/src/core/receiver/tcp_cmd_interface.cc new file mode 100644 index 000000000..57b274757 --- /dev/null +++ b/src/core/receiver/tcp_cmd_interface.cc @@ -0,0 +1,398 @@ +/*! + * \file tcp_cmd_interface.cc + * + * \brief Class that implements a TCP/IP telecommand command line interface + * for GNSS-SDR + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "tcp_cmd_interface.h" +#include "control_message_factory.h" +#include +#include + + +TcpCmdInterface::TcpCmdInterface() +{ + register_functions(); + keep_running_ = true; + control_queue_ = nullptr; + rx_latitude_ = 0; + rx_longitude_ = 0; + rx_altitude_ = 0; + receiver_utc_time_ = 0; +} + + +TcpCmdInterface::~TcpCmdInterface() = default; + + +void TcpCmdInterface::register_functions() +{ + functions["status"] = std::bind(&TcpCmdInterface::status, this, std::placeholders::_1); + functions["standby"] = std::bind(&TcpCmdInterface::standby, this, std::placeholders::_1); + functions["reset"] = std::bind(&TcpCmdInterface::reset, this, std::placeholders::_1); + functions["hotstart"] = std::bind(&TcpCmdInterface::hotstart, this, std::placeholders::_1); + functions["warmstart"] = std::bind(&TcpCmdInterface::warmstart, this, std::placeholders::_1); + functions["coldstart"] = std::bind(&TcpCmdInterface::coldstart, this, std::placeholders::_1); + functions["set_ch_satellite"] = std::bind(&TcpCmdInterface::set_ch_satellite, this, std::placeholders::_1); +} + + +void TcpCmdInterface::set_pvt(std::shared_ptr PVT_sptr) +{ + PVT_sptr_ = PVT_sptr; +} + + +time_t TcpCmdInterface::get_utc_time() +{ + return receiver_utc_time_; +} + + +arma::vec TcpCmdInterface::get_LLH() +{ + return arma::vec{rx_latitude_, rx_longitude_, rx_altitude_}; +} + + +std::string TcpCmdInterface::reset(const std::vector &commandLine __attribute__((unused))) +{ + std::string response; + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != nullptr) + { + control_queue_->handle(cmf->GetQueueMessage(200, 1)); //send the restart message (who=200,what=1) + response = "OK\n"; + } + else + { + response = "ERROR\n"; + } + + return response; +} + + +std::string TcpCmdInterface::standby(const std::vector &commandLine __attribute__((unused))) +{ + std::string response; + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != nullptr) + { + control_queue_->handle(cmf->GetQueueMessage(300, 10)); //send the standby message (who=300,what=10) + response = "OK\n"; + } + else + { + response = "ERROR\n"; + } + return response; +} + + +std::string TcpCmdInterface::status(const std::vector &commandLine __attribute__((unused))) +{ + std::stringstream str_stream; + //todo: implement the receiver status report + + // str_stream << "-------------------------------------------------------\n"; + // str_stream << "ch | sys | sig | mode | Tlm | Eph | Doppler | CN0 |\n"; + // str_stream << " | | | | | | [Hz] | [dB - Hz] |\n"; + // str_stream << "-------------------------------------------------------\n"; + // int n_ch = 10; + // for (int n = 0; n < n_ch; n++) + // { + // str_stream << n << "GPS | L1CA | TRK | YES | YES | 23412.4 | 44.3 |\n"; + // } + // str_stream << "--------------------------------------------------------\n"; + + double longitude_deg, latitude_deg, height_m, ground_speed_kmh, course_over_ground_deg; + time_t UTC_time; + if (PVT_sptr_->get_latest_PVT(&longitude_deg, + &latitude_deg, + &height_m, + &ground_speed_kmh, + &course_over_ground_deg, + &UTC_time) == true) + { + struct tm tstruct = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; + char buf1[80]; + tstruct = *gmtime(&UTC_time); + strftime(buf1, sizeof(buf1), "%d/%m/%Y %H:%M:%S", &tstruct); + std::string str_time = std::string(buf1); + str_stream << "- Receiver UTC Time: " << str_time << std::endl; + str_stream << std::setprecision(9); + str_stream << "- Receiver Position WGS84 [Lat, Long, H]: " + << latitude_deg << ", " + << longitude_deg << ", "; + str_stream << std::setprecision(3); + str_stream << height_m << std::endl; + str_stream << std::setprecision(1); + str_stream << "- Receiver Speed over Ground [km/h]: " << ground_speed_kmh << std::endl; + str_stream << "- Receiver Course over ground [deg]: " << course_over_ground_deg << std::endl; + } + else + { + str_stream << "No PVT information available.\n"; + } + + return str_stream.str(); +} + + +std::string TcpCmdInterface::hotstart(const std::vector &commandLine) +{ + std::string response; + if (commandLine.size() > 5) + { + // Read commandline time parameter + struct tm tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; + if (strptime(commandLine.at(1).c_str(), "%d/%m/%Y %H:%M:%S", &tm) == nullptr) + { + response = "ERROR: time parameter malformed\n"; + return response; + } + receiver_utc_time_ = timegm(&tm); + + // Read latitude, longitude, and height + rx_latitude_ = std::stod(commandLine.at(3).c_str()); + rx_longitude_ = std::stod(commandLine.at(4).c_str()); + rx_altitude_ = std::stod(commandLine.at(5).c_str()); + + if (std::isnan(rx_latitude_) || std::isnan(rx_longitude_) || std::isnan(rx_altitude_)) + { + response = "ERROR: position malformed\n"; + } + else + { + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != nullptr) + { + control_queue_->handle(cmf->GetQueueMessage(300, 12)); //send the standby message (who=300,what=12) + response = "OK\n"; + } + else + { + response = "ERROR\n"; + } + } + } + else + { + response = "ERROR: time parameter not found, please use hotstart %d/%m/%Y %H:%M:%S Lat Long H\n"; + } + return response; +} + + +std::string TcpCmdInterface::warmstart(const std::vector &commandLine) +{ + std::string response; + if (commandLine.size() > 5) + { + std::string tmp_str; + // Read commandline time parameter + struct tm tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; + tmp_str = commandLine.at(1) + commandLine.at(2); + if (strptime(commandLine.at(1).c_str(), "%d/%m/%Y %H:%M:%S", &tm) == nullptr) + { + response = "ERROR: time parameter malformed\n"; + return response; + } + receiver_utc_time_ = timegm(&tm); + + // Read latitude, longitude, and height + rx_latitude_ = std::stod(commandLine.at(3).c_str()); + rx_longitude_ = std::stod(commandLine.at(4).c_str()); + rx_altitude_ = std::stod(commandLine.at(5).c_str()); + if (std::isnan(rx_latitude_) || std::isnan(rx_longitude_) || std::isnan(rx_altitude_)) + { + response = "ERROR: position malformed\n"; + } + else + { + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != nullptr) + { + control_queue_->handle(cmf->GetQueueMessage(300, 13)); // send the warmstart message (who=300,what=13) + response = "OK\n"; + } + else + { + response = "ERROR\n"; + } + } + } + else + { + response = "ERROR: time parameter not found, please use warmstart %d/%m/%Y %H:%M:%S Lat Long H\n"; + } + return response; +} + + +std::string TcpCmdInterface::coldstart(const std::vector &commandLine __attribute__((unused))) +{ + std::string response; + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != nullptr) + { + control_queue_->handle(cmf->GetQueueMessage(300, 11)); // send the coldstart message (who=300,what=11) + response = "OK\n"; + } + else + { + response = "ERROR\n"; + } + return response; +} + + +std::string TcpCmdInterface::set_ch_satellite(const std::vector &commandLine __attribute__((unused))) +{ + std::string response; + //todo: implement the set satellite command + response = "Not implemented\n"; + return response; +} + + +void TcpCmdInterface::set_msg_queue(gr::msg_queue::sptr control_queue) +{ + control_queue_ = control_queue; +} + + +void TcpCmdInterface::run_cmd_server(int tcp_port) +{ + // Get the port from the parameters + uint16_t port = tcp_port; + + // Error to not throw exception + boost::system::error_code not_throw; + + // Socket and acceptor + boost::asio::io_service service; + try + { + boost::asio::ip::tcp::acceptor acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)); + + while (keep_running_) + { + try + { + std::cout << "TcpCmdInterface: Telecommand TCP interface listening on port " << tcp_port << std::endl; + + boost::asio::ip::tcp::socket socket(service); + acceptor.accept(socket, not_throw); + if (not_throw) + { + std::cout << "TcpCmdInterface: Error when binding the port in the socket" << std::endl; + continue; + } + + // Read a message + boost::system::error_code error = boost::asio::error::eof; + do + { + std::string response; + boost::asio::streambuf b; + boost::asio::read_until(socket, b, '\n', error); + std::istream is(&b); + std::string line; + std::getline(is, line); + std::istringstream iss(line); + std::vector cmd_vector(std::istream_iterator{iss}, + std::istream_iterator()); + + if (cmd_vector.size() > 0) + { + try + { + if (cmd_vector.at(0) == "exit") + { + error = boost::asio::error::eof; + // send cmd response + socket.write_some(boost::asio::buffer("OK\n"), not_throw); + } + else + { + response = functions[cmd_vector.at(0)](cmd_vector); + } + } + catch (const std::bad_function_call &ex) + { + response = "ERROR: command not found \n "; + } + catch (const std::exception &ex) + { + response = "ERROR: command execution error: " + std::string(ex.what()) + "\n"; + } + } + else + { + response = "ERROR: empty command\n"; + } + + // send cmd response + socket.write_some(boost::asio::buffer(response), not_throw); + if (not_throw) + { + std::cout << "Error sending(" << not_throw.value() << "): " << not_throw.message() << std::endl; + break; + } + } + while (error != boost::asio::error::eof); + + if (error == boost::asio::error::eof) + { + std::cout << "TcpCmdInterface: EOF detected\n"; + } + else + { + std::cout << "TcpCmdInterface unexpected error: " << error << std::endl; + } + + // Close socket + socket.close(); + } + catch (const boost::exception &e) + { + std::cout << "TcpCmdInterface: Boost exception " << std::endl; + } + catch (const std::exception &ex) + { + std::cout << "TcpCmdInterface: Exception " << ex.what() << std::endl; + } + } + } + catch (const boost::exception &e) + { + std::cout << "TCP Command Interface exception: address already in use" << std::endl; + } +} diff --git a/src/core/receiver/tcp_cmd_interface.h b/src/core/receiver/tcp_cmd_interface.h new file mode 100644 index 000000000..4cafb898d --- /dev/null +++ b/src/core/receiver/tcp_cmd_interface.h @@ -0,0 +1,95 @@ +/*! + * \file tcp_cmd_interface.h + * + * \brief Class that implements a TCP/IP telecommand command line interface + * for GNSS-SDR + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#ifndef GNSS_SDR_TCP_CMD_INTERFACE_H_ +#define GNSS_SDR_TCP_CMD_INTERFACE_H_ + +#include "pvt_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class TcpCmdInterface +{ +public: + TcpCmdInterface(); + virtual ~TcpCmdInterface(); + void run_cmd_server(int tcp_port); + void set_msg_queue(gr::msg_queue::sptr control_queue); + + /*! + * \brief gets the UTC time parsed from the last TC command issued + */ + time_t get_utc_time(); + + /*! + * \brief gets the Latitude, Longitude and Altitude vector from the last TC command issued + */ + arma::vec get_LLH(); + + void set_pvt(std::shared_ptr PVT_sptr); + +private: + std::unordered_map &)>> + functions; + std::string status(const std::vector &commandLine); + std::string reset(const std::vector &commandLine); + std::string standby(const std::vector &commandLine); + std::string hotstart(const std::vector &commandLine); + std::string warmstart(const std::vector &commandLine); + std::string coldstart(const std::vector &commandLine); + std::string set_ch_satellite(const std::vector &commandLine); + + void register_functions(); + + gr::msg_queue::sptr control_queue_; + bool keep_running_; + + time_t receiver_utc_time_; + + double rx_latitude_; + double rx_longitude_; + double rx_altitude_; + + std::shared_ptr PVT_sptr_; +}; + +#endif /* GNSS_SDR_TCP_CMD_INTERFACE_H_ */ diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index a22c7d9c2..39f3231fb 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,51 +13,102 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # + set(SYSTEM_PARAMETERS_SOURCES - gnss_satellite.cc - gnss_signal.cc - gps_navigation_message.cc - gps_ephemeris.cc - gps_iono.cc - gps_almanac.cc - gps_utc_model.cc - gps_acq_assist.cc - gps_ref_time.cc - gps_ref_location.cc - galileo_utc_model.cc - galileo_ephemeris.cc - galileo_almanac.cc - galileo_iono.cc - galileo_navigation_message.cc - sbas_ephemeris.cc - sbas_ionospheric_correction.cc - sbas_satellite_correction.cc - sbas_telemetry_data.cc - galileo_fnav_message.cc - gps_cnav_ephemeris.cc - gps_cnav_navigation_message.cc - gps_cnav_iono.cc - gps_cnav_utc_model.cc - rtcm.cc + gnss_satellite.cc + gnss_signal.cc + gps_navigation_message.cc + gps_ephemeris.cc + gps_iono.cc + gps_almanac.cc + gps_utc_model.cc + gps_acq_assist.cc + agnss_ref_time.cc + agnss_ref_location.cc + galileo_utc_model.cc + galileo_ephemeris.cc + galileo_almanac.cc + galileo_almanac_helper.cc + galileo_iono.cc + galileo_navigation_message.cc + sbas_ephemeris.cc + galileo_fnav_message.cc + gps_cnav_ephemeris.cc + gps_cnav_navigation_message.cc + gps_cnav_iono.cc + gps_cnav_utc_model.cc + rtcm.cc + glonass_gnav_ephemeris.cc + glonass_gnav_almanac.cc + glonass_gnav_utc_model.cc + glonass_gnav_navigation_message.cc ) +set(SYSTEM_PARAMETERS_HEADERS + gnss_satellite.h + gnss_signal.h + gps_navigation_message.h + gps_ephemeris.h + gps_iono.h + gps_almanac.h + gps_utc_model.h + gps_acq_assist.h + agnss_ref_time.h + agnss_ref_location.h + galileo_utc_model.h + galileo_ephemeris.h + galileo_almanac.h + galileo_almanac_helper.h + galileo_iono.h + galileo_navigation_message.h + sbas_ephemeris.h + galileo_fnav_message.h + gps_cnav_ephemeris.h + gps_cnav_navigation_message.h + gps_cnav_iono.h + gps_cnav_utc_model.h + rtcm.h + glonass_gnav_ephemeris.h + glonass_gnav_almanac.h + glonass_gnav_utc_model.h + glonass_gnav_navigation_message.h + display.h + Galileo_E1.h + Galileo_E5a.h + GLONASS_L1_L2_CA.h + gnss_frequencies.h + gnss_obs_codes.h + gnss_synchro.h + GPS_CNAV.h + GPS_L1_CA.h + GPS_L2C.h + GPS_L5.h + MATH_CONSTANTS.h +) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${GLOG_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${GLOG_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} ) -link_directories(${Boost_LIBRARY_DIR}) -file(GLOB SYSTEM_PARAMETERS_HEADERS "*.h") list(SORT SYSTEM_PARAMETERS_HEADERS) -add_library(gnss_system_parameters ${SYSTEM_PARAMETERS_SOURCES} ${SYSTEM_PARAMETERS_HEADERS}) -source_group(Headers FILES ${SYSTEM_PARAMETERS_HEADERS}) -add_dependencies(gnss_system_parameters glog-${glog_RELEASE}) -target_link_libraries(gnss_system_parameters ${Boost_LIBRARIES}) +list(SORT SYSTEM_PARAMETERS_SOURCES) +add_library(gnss_system_parameters + ${SYSTEM_PARAMETERS_SOURCES} + ${SYSTEM_PARAMETERS_HEADERS} +) + +source_group(Headers FILES ${SYSTEM_PARAMETERS_HEADERS}) + +add_dependencies(gnss_system_parameters rtklib_lib glog-${glog_RELEASE}) + +target_link_libraries(gnss_system_parameters rtklib_lib ${Boost_LIBRARIES}) diff --git a/src/core/system_parameters/GLONASS_L1_L2_CA.h b/src/core/system_parameters/GLONASS_L1_L2_CA.h new file mode 100644 index 000000000..816b2c9aa --- /dev/null +++ b/src/core/system_parameters/GLONASS_L1_L2_CA.h @@ -0,0 +1,331 @@ +/*! + * \file GLONASS_L1_L2_CA.h + * \brief Defines system parameters for GLONASS L1 C/A signal and NAV data + * \note File renamed from GLONASS_L1_CA.h to GLONASS_L1_L2_CA.h to accommodate GLO L2 addition + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_L1_L2_CA_H_ +#define GNSS_SDR_GLONASS_L1_L2_CA_H_ + +#include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include +#include // std::pair +#include + + +// Physical constants +const double GLONASS_C_m_s = SPEED_OF_LIGHT; //!< The speed of light, [m/s] +const double GLONASS_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GLONASS_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E +const double GLONASS_TWO_PI = 6.283185307179586; //!< 2Pi as defined in IS-GPS-200E +const double GLONASS_OMEGA_EARTH_DOT = 7.292115e-5; //!< Earth rotation rate, [rad/s] +const double GLONASS_GM = 398600.4418e9; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] +const double GLONASS_fM_a = 0.35e9; //!< Gravitational constant of atmosphere [m^3/s^2] +const double GLONASS_SEMI_MAJOR_AXIS = 6378136; //!< Semi-major axis of Earth [m] +const double GLONASS_FLATTENING = 1 / 29825784; //!< Flattening parameter +const double GLONASS_GRAVITY = 97803284; //!< Equatorial acceleration of gravity [mGal] +const double GLONASS_GRAVITY_CORRECTION = 0.87; //!< Correction to acceleration of gravity at sea-level due to Atmosphere[мGal] +const double GLONASS_J2 = 1082625.75e-9; //!< Second zonal harmonic of the geopotential +const double GLONASS_J4 = -2370.89e-9; //!< Fourth zonal harmonic of the geopotential +const double GLONASS_J6 = 6.08e-9; //!< Sixth zonal harmonic of the geopotential +const double GLONASS_J8 = 1.40e-11; //!< Eighth zonal harmonic of the geopotential +const double GLONASS_U0 = 62636861.4; //!< Normal potential at surface of common terrestrial ellipsoid [m^2/s^2] +const double GLONASS_C20 = -1082.63e-6; //!< Second zonal coefficient of spherical harmonic expansion +const double GLONASS_EARTH_RADIUS = 6378.136; //!< Equatorial radius of Earth [km] +const double GLONASS_EARTH_INCLINATION = 0.000409148809899e3; //!< Mean inclination of ecliptic to equator (23 deg 26 min 33 sec) [rad] + +const double GLONASS_TAU_0 = -0.005835151531174e3; //!< (-334 deg 19 min 46.40 sec) [rad]; +const double GLONASS_TAU_1 = 0.071018041257371e3; //!< (4069 deg 02 min 02.52 sec) [rad]; + +const double GLONASS_MOON_Q0 = -0.001115184961435e3; //!< (-63 deg 53 min 43.41 sec) [rad] +const double GLONASS_MOON_Q1 = 8.328691103668023e3; //!< (477198 deg 50 min 56.79 sec) [rad] +const double GLONASS_MOON_OMEGA_0 = 0.004523601514852e3; //!< (259 deg 10 min 59.79 sec) [rad] +const double GLONASS_MOON_OMEGA_1 = -0.033757146246552e3; //!< (-1934 deg 08 min 31.23 sec) [rad] +const double GLONASS_MOON_GM = 4902.835; //!< Lunar gravitational constant [km^3/s^2] +const double GLONASS_MOON_SEMI_MAJOR_AXIS = 3.84385243e5; //!< Semi-major axis of lunar orbit [km]; +const double GLONASS_MOON_ECCENTRICITY = 0.054900489; //!< Eccentricity of lunar orbit +const double GLONASS_MOON_INCLINATION = 0.000089803977407e3; //!< Inclination of lunar orbit to ecliptic plane (5 deg 08 min 43.4 sec) [rad] + +const double GLONASS_SUN_OMEGA = 0.004908229466869e3; //!< TODO What is this operation in the seconds with T?(281 deg 13 min 15.0 + 6189.03*Т sec) [rad] +const double GLONASS_SUN_Q0 = 0.006256583774423e3; //!< (358 deg 28 min 33.04 sec) [rad] +const double GLONASS_SUN_Q1 = 0e3; //!< TODO Why is the value greater than 60?(129596579.10 sec) [rad] +const double GLONASS_SUN_GM = 0.1325263e12; //!< Solar gravitational constant [km^3/s^2] +const double GLONASS_SUN_SEMI_MAJOR_AXIS = 1.49598e8; //!< Semi-major axis of solar orbit [km]; +const double GLONASS_SUN_ECCENTRICITY = 0.016719; //!< Eccentricity of solar orbit + +const double GLONASS_L2_CA_FREQ_HZ = FREQ2_GLO; //!< L2 [Hz] +const double GLONASS_L2_CA_DFREQ_HZ = DFRQ2_GLO; //!< Freq Bias for GLONASS L1 [Hz] +const double GLONASS_L2_CA_CODE_RATE_HZ = 0.511e6; //!< GLONASS L1 C/A code rate [chips/s] +const double GLONASS_L2_CA_CODE_LENGTH_CHIPS = 511.0; //!< GLONASS L1 C/A code length [chips] +const double GLONASS_L2_CA_CODE_PERIOD = 0.001; //!< GLONASS L1 C/A code period [seconds] +const double GLONASS_L2_CA_CHIP_PERIOD = 1.9569e-06; //!< GLONASS L1 C/A chip period [seconds] +const double GLONASS_L2_CA_SYMBOL_RATE_BPS = 1000; + +const double GLONASS_L1_CA_FREQ_HZ = FREQ1_GLO; //!< L1 [Hz] +const double GLONASS_L1_CA_DFREQ_HZ = DFRQ1_GLO; //!< Freq Bias for GLONASS L1 [Hz] +const double GLONASS_L1_CA_CODE_RATE_HZ = 0.511e6; //!< GLONASS L1 C/A code rate [chips/s] +const double GLONASS_L1_CA_CODE_LENGTH_CHIPS = 511.0; //!< GLONASS L1 C/A code length [chips] +const double GLONASS_L1_CA_CODE_PERIOD = 0.001; //!< GLONASS L1 C/A code period [seconds] +const double GLONASS_L1_CA_CHIP_PERIOD = 1.9569e-06; //!< GLONASS L1 C/A chip period [seconds] +const double GLONASS_L1_CA_SYMBOL_RATE_BPS = 1000; + +const int32_t GLONASS_CA_NBR_SATS = 24; // STRING DATA WITHOUT PREAMBLE + +/*! + * \brief Record of leap seconds definition for GLOT to GPST conversion and vice versa + * \details Each entry is defined by an array of 7 elements consisting of yr,month,day,hr,min,sec,utc-gpst + * \note Ideally should use leap seconds definitions of rtklib + */ +const double GLONASS_LEAP_SECONDS[19][7] = { + {2017, 1, 1, 0, 0, 0, -18}, + {2015, 7, 1, 0, 0, 0, -17}, + {2012, 7, 1, 0, 0, 0, -16}, + {2009, 1, 1, 0, 0, 0, -15}, + {2006, 1, 1, 0, 0, 0, -14}, + {1999, 1, 1, 0, 0, 0, -13}, + {1997, 7, 1, 0, 0, 0, -12}, + {1996, 1, 1, 0, 0, 0, -11}, + {1994, 7, 1, 0, 0, 0, -10}, + {1993, 7, 1, 0, 0, 0, -9}, + {1992, 7, 1, 0, 0, 0, -8}, + {1991, 1, 1, 0, 0, 0, -7}, + {1990, 1, 1, 0, 0, 0, -6}, + {1988, 1, 1, 0, 0, 0, -5}, + {1985, 7, 1, 0, 0, 0, -4}, + {1983, 7, 1, 0, 0, 0, -3}, + {1982, 7, 1, 0, 0, 0, -2}, + {1981, 7, 1, 0, 0, 0, -1}, + {}}; + +//!< GLONASS SV's orbital slots PRN = (orbital_slot - 1) +const std::map GLONASS_PRN = { + { + 0, + 8, + }, //For test + { + 1, + 1, + }, //Plane 1 + { + 2, + -4, + }, //Plane 1 + { + 3, + 5, + }, //Plane 1 + { + 4, + 6, + }, //Plane 1 + { + 5, + 1, + }, //Plane 1 + { + 6, + -4, + }, //Plane 1 + { + 7, + 5, + }, //Plane 1 + { + 8, + 6, + }, //Plane 1 + { + 9, + -2, + }, //Plane 2 + { + 10, + -7, + }, //Plane 2 + { + 11, + 0, + }, //Plane 2 + { + 12, + -1, + }, //Plane 2 + { + 13, + -2, + }, //Plane 2 + { + 14, + -7, + }, //Plane 2 + { + 15, + 0, + }, //Plane 2 + { + 16, + -1, + }, //Plane 2 + { + 17, + 4, + }, //Plane 3 + { + 18, + -3, + }, //Plane 3 + { + 19, + 3, + }, //Plane 3 + { + 20, + -5, + }, //Plane 3 + { + 21, + 4, + }, //Plane 3 + { + 22, + -3, + }, //Plane 3 + { + 23, + 3, + }, //Plane 3 + {24, 2}}; //Plane 3 + +const double GLONASS_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) + +// OBSERVABLE HISTORY DEEP FOR INTERPOLATION +const int32_t GLONASS_L1_CA_HISTORY_DEEP = 100; + +// NAVIGATION MESSAGE DEMODULATION AND DECODING +#define GLONASS_GNAV_PREAMBLE \ + { \ + 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0 \ + } +const double GLONASS_GNAV_PREAMBLE_DURATION_S = 0.300; +const int32_t GLONASS_GNAV_PREAMBLE_LENGTH_BITS = 30; +const int32_t GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS = 300; +const int32_t GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS = 2000; +const int32_t GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND = 50; //!< NAV message bit rate [bits/s] +const int32_t GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT = 10; +const int32_t GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_PREAMBLE_BIT = 10; +const int32_t GLONASS_GNAV_TELEMETRY_RATE_SYMBOLS_SECOND = GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND * GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; //!< NAV message bit rate [symbols/s] +const int32_t GLONASS_GNAV_STRING_SYMBOLS = 2000; //!< Number of bits per string in the GNAV message (85 data bits + 30 time mark bits) [bits] +const int32_t GLONASS_GNAV_STRING_BITS = 85; //!< Number of bits per string in the GNAV message (85 data bits + 30 time mark bits) [bits] +const int32_t GLONASS_GNAV_HAMMING_CODE_BITS = 8; //!< Number of bits in hamming code sequence of GNAV message +const int32_t GLONASS_GNAV_DATA_SYMBOLS = 1700; // STRING DATA WITHOUT PREAMBLE + +const std::vector GLONASS_GNAV_CRC_I_INDEX{9, 10, 12, 13, 15, 17, 19, 20, 22, 24, 26, 28, 30, 32, 34, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84}; +const std::vector GLONASS_GNAV_CRC_J_INDEX{9, 11, 12, 14, 15, 18, 19, 21, 22, 25, 26, 29, 30, 33, 34, 36, 37, 40, 41, 44, 45, 48, 49, 52, 53, 56, 57, 60, 61, 64, 65, 67, 68, 71, 72, 75, 76, 79, 80, 83, 84}; +const std::vector GLONASS_GNAV_CRC_K_INDEX{10, 11, 12, 16, 17, 18, 19, 23, 24, 25, 26, 31, 32, 33, 34, 38, 39, 40, 41, 46, 47, 48, 49, 54, 55, 56, 57, 62, 63, 64, 65, 69, 70, 71, 72, 77, 78, 79, 80, 85}; +const std::vector GLONASS_GNAV_CRC_L_INDEX{13, 14, 15, 16, 17, 18, 19, 27, 28, 29, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, 47, 48, 49, 58, 59, 60, 61, 62, 63, 64, 65, 73, 74, 75, 76, 77, 78, 79, 80}; +const std::vector GLONASS_GNAV_CRC_M_INDEX{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 81, 82, 83, 84, 85}; +const std::vector GLONASS_GNAV_CRC_N_INDEX{35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65}; +const std::vector GLONASS_GNAV_CRC_P_INDEX{66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; +const std::vector GLONASS_GNAV_CRC_Q_INDEX{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; + +// GLONASS GNAV NAVIGATION MESSAGE STRUCTURE +// NAVIGATION MESSAGE FIELDS POSITIONS (from IS-GPS-200E Appendix II) + +// FRAME 1-4 +// COMMON FIELDS +const std::vector> STRING_ID({{2, 4}}); +const std::vector> KX({{78, 8}}); +//STRING 1 +const std::vector> P1({{8, 2}}); +const std::vector> T_K_HR({{10, 5}}); +const std::vector> T_K_MIN({{15, 6}}); +const std::vector> T_K_SEC({{21, 1}}); +const std::vector> X_N_DOT({{22, 24}}); +const std::vector> X_N_DOT_DOT({{46, 5}}); +const std::vector> X_N({{51, 27}}); + +//STRING 2 +const std::vector> B_N({{6, 3}}); +const std::vector> P2({{9, 1}}); +const std::vector> T_B({{10, 7}}); +const std::vector> Y_N_DOT({{22, 24}}); +const std::vector> Y_N_DOT_DOT({{46, 5}}); +const std::vector> Y_N({{51, 27}}); + +//STRING 3 +const std::vector> P3({{6, 1}}); +const std::vector> GAMMA_N({{7, 11}}); +const std::vector> P({{19, 2}}); +const std::vector> EPH_L_N({{21, 1}}); +const std::vector> Z_N_DOT({{22, 24}}); +const std::vector> Z_N_DOT_DOT({{46, 5}}); +const std::vector> Z_N({{51, 27}}); + +// STRING 4 +const std::vector> TAU_N({{6, 22}}); +const std::vector> DELTA_TAU_N({{28, 5}}); +const std::vector> E_N({{33, 5}}); +const std::vector> P4({{52, 1}}); +const std::vector> F_T({{53, 4}}); +const std::vector> N_T({{60, 11}}); +const std::vector> N({{71, 5}}); +const std::vector> M({{76, 2}}); + +// STRING 5 +const std::vector> N_A({{6, 11}}); +const std::vector> TAU_C({{17, 32}}); +const std::vector> N_4({{50, 5}}); +const std::vector> TAU_GPS({{55, 22}}); +const std::vector> ALM_L_N({{77, 1}}); + +// STRING 6, 8, 10, 12, 14 +const std::vector> C_N({{6, 1}}); +const std::vector> M_N_A({{7, 2}}); +const std::vector> n_A({{9, 5}}); +const std::vector> TAU_N_A({{14, 10}}); +const std::vector> LAMBDA_N_A({{24, 21}}); +const std::vector> DELTA_I_N_A({{45, 18}}); +const std::vector> EPSILON_N_A({{63, 15}}); + +//STRING 7, 9, 11, 13, 15 +const std::vector> OMEGA_N_A({{6, 16}}); +const std::vector> T_LAMBDA_N_A({{22, 21}}); +const std::vector> DELTA_T_N_A({{43, 22}}); +const std::vector> DELTA_T_DOT_N_A({{65, 7}}); +const std::vector> H_N_A({{72, 5}}); + +// STRING 14 FRAME 5 +const std::vector> B1({{6, 11}}); +const std::vector> B2({{17, 10}}); + + +#endif /* GNSS_SDR_GLONASS_L1_L2_CA_H_ */ diff --git a/src/core/system_parameters/GPS_CNAV.h b/src/core/system_parameters/GPS_CNAV.h new file mode 100644 index 000000000..025230930 --- /dev/null +++ b/src/core/system_parameters/GPS_CNAV.h @@ -0,0 +1,186 @@ +/*! + * \file GPS_CNAV.h + * \brief Defines parameters for GPS CNAV + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GPS_CNAV_H_ +#define GNSS_SDR_GPS_CNAV_H_ + +#include "MATH_CONSTANTS.h" +#include +#include // std::pair +#include + + +// CNAV GPS NAVIGATION MESSAGE STRUCTURE +// NAVIGATION MESSAGE FIELDS POSITIONS (from IS-GPS-200E Appendix III) + +#define GPS_CNAV_PREAMBLE \ + { \ + 1, 0, 0, 0, 1, 0, 1, 1 \ + } +#define GPS_CNAV_PREAMBLE_STR "10001011" +#define GPS_CNAV_INV_PREAMBLE_STR "01110100" + +const int32_t GPS_CNAV_DATA_PAGE_BITS = 300; + +// common to all messages +const std::vector > CNAV_PRN({{9, 6}}); +const std::vector > CNAV_MSG_TYPE({{15, 6}}); +const std::vector > CNAV_TOW({{21, 17}}); // GPS Time Of Week in seconds +const int32_t CNAV_TOW_LSB = 6; +const std::vector > CNAV_ALERT_FLAG({{38, 1}}); + +// MESSAGE TYPE 10 (Ephemeris 1) + +const std::vector > CNAV_WN({{39, 13}}); +const std::vector > CNAV_HEALTH({{52, 3}}); +const std::vector > CNAV_TOP1({{55, 11}}); +const int32_t CNAV_TOP1_LSB = 300; +const std::vector > CNAV_URA({{66, 5}}); + +const std::vector > CNAV_TOE1({{71, 11}}); +const int32_t CNAV_TOE1_LSB = 300; + +const std::vector > CNAV_DELTA_A({{82, 26}}); // Relative to AREF = 26,559,710 meters +const double CNAV_DELTA_A_LSB = TWO_N9; + +const std::vector > CNAV_A_DOT({{108, 25}}); +const double CNAV_A_DOT_LSB = TWO_N21; + +const std::vector > CNAV_DELTA_N0({{133, 17}}); +const double CNAV_DELTA_N0_LSB = TWO_N44 * PI; // semi-circles to radians +const std::vector > CNAV_DELTA_N0_DOT({{150, 23}}); +const double CNAV_DELTA_N0_DOT_LSB = TWO_N57 * PI; //semi-circles to radians +const std::vector > CNAV_M0({{173, 33}}); +const double CNAV_M0_LSB = TWO_N32 * PI; // semi-circles to radians +const std::vector > CNAV_E_ECCENTRICITY({{206, 33}}); +const double CNAV_E_ECCENTRICITY_LSB = TWO_N34; +const std::vector > CNAV_OMEGA({{239, 33}}); +const double CNAV_OMEGA_LSB = TWO_N32 * PI; // semi-circles to radians +const std::vector > CNAV_INTEGRITY_FLAG({{272, 1}}); +const std::vector > CNAV_L2_PHASING_FLAG({{273, 1}}); + +// MESSAGE TYPE 11 (Ephemeris 2) + +const std::vector > CNAV_TOE2({{39, 11}}); +const int32_t CNAV_TOE2_LSB = 300; +const std::vector > CNAV_OMEGA0({{50, 33}}); +const double CNAV_OMEGA0_LSB = TWO_N32 * PI; // semi-circles to radians +const std::vector > CNAV_I0({{83, 33}}); +const double CNAV_I0_LSB = TWO_N32 * PI; // semi-circles to radians +const std::vector > CNAV_DELTA_OMEGA_DOT({{116, 17}}); // Relative to REF = -2.6 x 10-9 semi-circles/second. +const double CNAV_DELTA_OMEGA_DOT_LSB = TWO_N44 * PI; // semi-circles to radians +const std::vector > CNAV_I0_DOT({{133, 15}}); +const double CNAV_I0_DOT_LSB = TWO_N44 * PI; // semi-circles to radians +const std::vector > CNAV_CIS({{148, 16}}); +const double CNAV_CIS_LSB = TWO_N30; +const std::vector > CNAV_CIC({{164, 16}}); +const double CNAV_CIC_LSB = TWO_N30; +const std::vector > CNAV_CRS({{180, 24}}); +const double CNAV_CRS_LSB = TWO_N8; +const std::vector > CNAV_CRC({{204, 24}}); +const double CNAV_CRC_LSB = TWO_N8; +const std::vector > CNAV_CUS({{228, 21}}); +const double CNAV_CUS_LSB = TWO_N30; +const std::vector > CNAV_CUC({{249, 21}}); +const double CNAV_CUC_LSB = TWO_N30; + + +// MESSAGE TYPE 30 (CLOCK, IONO, GRUP DELAY) + +const std::vector > CNAV_TOP2({{39, 11}}); +const int32_t CNAV_TOP2_LSB = 300; +const std::vector > CNAV_URA_NED0({{50, 5}}); +const std::vector > CNAV_URA_NED1({{55, 3}}); +const std::vector > CNAV_URA_NED2({{58, 3}}); +const std::vector > CNAV_TOC({{61, 11}}); +const int32_t CNAV_TOC_LSB = 300; +const std::vector > CNAV_AF0({{72, 26}}); +const double CNAV_AF0_LSB = TWO_N35; +const std::vector > CNAV_AF1({{98, 20}}); +const double CNAV_AF1_LSB = TWO_N48; +const std::vector > CNAV_AF2({{118, 10}}); +const double CNAV_AF2_LSB = TWO_N60; +const std::vector > CNAV_TGD({{128, 13}}); +const double CNAV_TGD_LSB = TWO_N35; +const std::vector > CNAV_ISCL1({{141, 13}}); +const double CNAV_ISCL1_LSB = TWO_N35; +const std::vector > CNAV_ISCL2({{154, 13}}); +const double CNAV_ISCL2_LSB = TWO_N35; +const std::vector > CNAV_ISCL5I({{167, 13}}); +const double CNAV_ISCL5I_LSB = TWO_N35; +const std::vector > CNAV_ISCL5Q({{180, 13}}); +const double CNAV_ISCL5Q_LSB = TWO_N35; +// Ionospheric parameters +const std::vector > CNAV_ALPHA0({{193, 8}}); +const double CNAV_ALPHA0_LSB = TWO_N30; +const std::vector > CNAV_ALPHA1({{201, 8}}); +const double CNAV_ALPHA1_LSB = TWO_N27; +const std::vector > CNAV_ALPHA2({{209, 8}}); +const double CNAV_ALPHA2_LSB = TWO_N24; +const std::vector > CNAV_ALPHA3({{217, 8}}); +const double CNAV_ALPHA3_LSB = TWO_N24; +const std::vector > CNAV_BETA0({{225, 8}}); +const double CNAV_BETA0_LSB = TWO_P11; +const std::vector > CNAV_BETA1({{233, 8}}); +const double CNAV_BETA1_LSB = TWO_P14; +const std::vector > CNAV_BETA2({{241, 8}}); +const double CNAV_BETA2_LSB = TWO_P16; +const std::vector > CNAV_BETA3({{249, 8}}); +const double CNAV_BETA3_LSB = TWO_P16; +const std::vector > CNAV_WNOP({{257, 8}}); + + +// MESSAGE TYPE 33 (CLOCK and UTC) + +const std::vector > CNAV_A0({{128, 16}}); +const double CNAV_A0_LSB = TWO_N35; +const std::vector > CNAV_A1({{144, 13}}); +const double CNAV_A1_LSB = TWO_N51; +const std::vector > CNAV_A2({{157, 7}}); +const double CNAV_A2_LSB = TWO_N68; +const std::vector > CNAV_DELTA_TLS({{164, 8}}); +const int32_t CNAV_DELTA_TLS_LSB = 1; +const std::vector > CNAV_TOT({{172, 16}}); +const int32_t CNAV_TOT_LSB = TWO_P4; +const std::vector > CNAV_WN_OT({{188, 13}}); +const int32_t CNAV_WN_OT_LSB = 1; +const std::vector > CNAV_WN_LSF({{201, 13}}); +const int32_t CNAV_WN_LSF_LSB = 1; +const std::vector > CNAV_DN({{214, 4}}); +const int32_t CNAV_DN_LSB = 1; +const std::vector > CNAV_DELTA_TLSF({{218, 8}}); +const int32_t CNAV_DELTA_TLSF_LSB = 1; + + +// TODO: Add more frames (Almanac, etc...) + + +#endif /* GNSS_SDR_GPS_CNAV_H_ */ diff --git a/src/core/system_parameters/GPS_L1_CA.h b/src/core/system_parameters/GPS_L1_CA.h index ec6b79fe2..349897994 100644 --- a/src/core/system_parameters/GPS_L1_CA.h +++ b/src/core/system_parameters/GPS_L1_CA.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,26 +32,33 @@ #ifndef GNSS_SDR_GPS_L1_CA_H_ #define GNSS_SDR_GPS_L1_CA_H_ -#include -#include // std::pair #include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include // std::pair +#include + // Physical constants -const double GPS_C_m_s = 299792458.0; //!< The speed of light, [m/s] -const double GPS_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] -const double GPS_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E -const double GPS_TWO_PI = 6.283185307179586;//!< 2Pi as defined in IS-GPS-200E -const double OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Earth rotation rate, [rad/s] -const double GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] -const double F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] +const double GPS_C_m_s = SPEED_OF_LIGHT; //!< The speed of light, [m/s] +const double GPS_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GPS_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E +const double GPS_TWO_PI = 6.283185307179586; //!< 2Pi as defined in IS-GPS-200E +const double OMEGA_EARTH_DOT = DEFAULT_OMEGA_EARTH_DOT; //!< Earth rotation rate, [rad/s] +const double GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] +const double F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] // carrier and code frequencies -const double GPS_L1_FREQ_HZ = 1.57542e9; //!< L1 [Hz] -const double GPS_L1_CA_CODE_RATE_HZ = 1.023e6; //!< GPS L1 C/A code rate [chips/s] -const double GPS_L1_CA_CODE_LENGTH_CHIPS = 1023.0; //!< GPS L1 C/A code length [chips] -const double GPS_L1_CA_CODE_PERIOD = 0.001; //!< GPS L1 C/A code period [seconds] -const double GPS_L1_CA_CHIP_PERIOD = 9.7752e-07; //!< GPS L1 C/A chip period [seconds] +const double GPS_L1_FREQ_HZ = FREQ1; //!< L1 [Hz] +const double GPS_L1_CA_CODE_RATE_HZ = 1.023e6; //!< GPS L1 C/A code rate [chips/s] +const double GPS_L1_CA_CODE_LENGTH_CHIPS = 1023.0; //!< GPS L1 C/A code length [chips] +const double GPS_L1_CA_CODE_PERIOD = 0.001; //!< GPS L1 C/A code period [seconds] +const uint32_t GPS_L1_CA_CODE_PERIOD_MS = 1U; //!< GPS L1 C/A code period [ms] +const double GPS_L1_CA_CHIP_PERIOD = 9.7752e-07; //!< GPS L1 C/A chip period [seconds] + +//optimum parameters +const uint32_t GPS_L1_CA_OPT_ACQ_FS_HZ = 1000000; //!< Sampling frequncy that maximizes the acquisition SNR while using a non-multiple of chip rate /*! * \brief Maximum Time-Of-Arrival (TOA) difference between satellites for a receiver operated on Earth surface is 20 ms @@ -64,179 +71,184 @@ const double GPS_L1_CA_CHIP_PERIOD = 9.7752e-07; //!< GPS L1 C/A chip const double MAX_TOA_DELAY_MS = 20; //#define NAVIGATION_SOLUTION_RATE_MS 1000 // this cannot go here -const double GPS_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) - +//const double GPS_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) +const double GPS_STARTOFFSET_ms = 60.0; // OBSERVABLE HISTORY DEEP FOR INTERPOLATION -const int GPS_L1_CA_HISTORY_DEEP = 100; +const int32_t GPS_L1_CA_HISTORY_DEEP = 100; // NAVIGATION MESSAGE DEMODULATION AND DECODING -#define GPS_PREAMBLE {1, 0, 0, 0, 1, 0, 1, 1} -const int GPS_CA_PREAMBLE_LENGTH_BITS = 8; -const int GPS_CA_PREAMBLE_LENGTH_SYMBOLS = 160; -const int GPS_CA_TELEMETRY_RATE_BITS_SECOND = 50; //!< NAV message bit rate [bits/s] -const int GPS_CA_TELEMETRY_SYMBOLS_PER_BIT = 20; -const int GPS_CA_TELEMETRY_RATE_SYMBOLS_SECOND = GPS_CA_TELEMETRY_RATE_BITS_SECOND*GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; //!< NAV message bit rate [symbols/s] -const int GPS_WORD_LENGTH = 4; //!< CRC + GPS WORD (-2 -1 0 ... 29) Bits = 4 bytes -const int GPS_SUBFRAME_LENGTH = 40; //!< GPS_WORD_LENGTH x 10 = 40 bytes -const int GPS_SUBFRAME_BITS = 300; //!< Number of bits per subframe in the NAV message [bits] -const int GPS_SUBFRAME_SECONDS = 6; //!< Subframe duration [seconds] -const int GPS_SUBFRAME_MS = 6000; //!< Subframe duration [seconds] -const int GPS_WORD_BITS = 30; //!< Number of bits per word in the NAV message [bits] +#define GPS_PREAMBLE \ + { \ + 1, 0, 0, 0, 1, 0, 1, 1 \ + } +const int32_t GPS_CA_PREAMBLE_LENGTH_BITS = 8; +const int32_t GPS_CA_PREAMBLE_LENGTH_SYMBOLS = 160; +const double GPS_CA_PREAMBLE_DURATION_S = 0.160; +const int32_t GPS_CA_PREAMBLE_DURATION_MS = 160; +const int32_t GPS_CA_TELEMETRY_RATE_BITS_SECOND = 50; //!< NAV message bit rate [bits/s] +const int32_t GPS_CA_TELEMETRY_SYMBOLS_PER_BIT = 20; +const int32_t GPS_CA_TELEMETRY_RATE_SYMBOLS_SECOND = GPS_CA_TELEMETRY_RATE_BITS_SECOND * GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; //!< NAV message bit rate [symbols/s] +const int32_t GPS_WORD_LENGTH = 4; //!< CRC + GPS WORD (-2 -1 0 ... 29) Bits = 4 bytes +const int32_t GPS_SUBFRAME_LENGTH = 40; //!< GPS_WORD_LENGTH x 10 = 40 bytes +const int32_t GPS_SUBFRAME_BITS = 300; //!< Number of bits per subframe in the NAV message [bits] +const int32_t GPS_SUBFRAME_SECONDS = 6; //!< Subframe duration [seconds] +const int32_t GPS_SUBFRAME_MS = 6000; //!< Subframe duration [seconds] +const int32_t GPS_WORD_BITS = 30; //!< Number of bits per word in the NAV message [bits] // GPS NAVIGATION MESSAGE STRUCTURE // NAVIGATION MESSAGE FIELDS POSITIONS (from IS-GPS-200E Appendix II) // SUBFRAME 1-5 (TLM and HOW) -const std::vector > TOW( { {31,17} } ); -const std::vector > INTEGRITY_STATUS_FLAG({{23,1}}); -const std::vector > ALERT_FLAG({{48,1}}); -const std::vector > ANTI_SPOOFING_FLAG({{49,1}}); -const std::vector > SUBFRAME_ID({{50,3}}); +const std::vector> TOW({{31, 17}}); +const std::vector> INTEGRITY_STATUS_FLAG({{23, 1}}); +const std::vector> ALERT_FLAG({{48, 1}}); +const std::vector> ANTI_SPOOFING_FLAG({{49, 1}}); +const std::vector> SUBFRAME_ID({{50, 3}}); // SUBFRAME 1 -const std::vector> GPS_WEEK({{61,10}}); -const std::vector> CA_OR_P_ON_L2({{71,2}}); //* -const std::vector> SV_ACCURACY({{73,4}}); -const std::vector> SV_HEALTH ({{77,6}}); -const std::vector> L2_P_DATA_FLAG ({{91,1}}); -const std::vector> T_GD({{197,8}}); +const std::vector> GPS_WEEK({{61, 10}}); +const std::vector> CA_OR_P_ON_L2({{71, 2}}); //* +const std::vector> SV_ACCURACY({{73, 4}}); +const std::vector> SV_HEALTH({{77, 6}}); +const std::vector> L2_P_DATA_FLAG({{91, 1}}); +const std::vector> T_GD({{197, 8}}); const double T_GD_LSB = TWO_N31; -const std::vector> IODC({{83,2},{211,8}}); -const std::vector> T_OC({{219,16}}); -const double T_OC_LSB = TWO_P4; -const std::vector> A_F2({{241,8}}); +const std::vector> IODC({{83, 2}, {211, 8}}); +const std::vector> T_OC({{219, 16}}); +const int32_t T_OC_LSB = static_cast(TWO_P4); +const std::vector> A_F2({{241, 8}}); const double A_F2_LSB = TWO_N55; -const std::vector> A_F1({{249,16}}); +const std::vector> A_F1({{249, 16}}); const double A_F1_LSB = TWO_N43; -const std::vector> A_F0({{271,22}}); +const std::vector> A_F0({{271, 22}}); const double A_F0_LSB = TWO_N31; // SUBFRAME 2 -const std::vector> IODE_SF2({{61,8}}); -const std::vector> C_RS({{69,16}}); +const std::vector> IODE_SF2({{61, 8}}); +const std::vector> C_RS({{69, 16}}); const double C_RS_LSB = TWO_N5; -const std::vector> DELTA_N({{91,16}}); +const std::vector> DELTA_N({{91, 16}}); const double DELTA_N_LSB = PI_TWO_N43; -const std::vector> M_0({{107,8},{121,24}}); +const std::vector> M_0({{107, 8}, {121, 24}}); const double M_0_LSB = PI_TWO_N31; -const std::vector> C_UC({{151,16}}); +const std::vector> C_UC({{151, 16}}); const double C_UC_LSB = TWO_N29; -const std::vector> E({{167,8},{181,24}}); +const std::vector> E({{167, 8}, {181, 24}}); const double E_LSB = TWO_N33; -const std::vector> C_US({{211,16}}); +const std::vector> C_US({{211, 16}}); const double C_US_LSB = TWO_N29; -const std::vector> SQRT_A({{227,8},{241,24}}); +const std::vector> SQRT_A({{227, 8}, {241, 24}}); const double SQRT_A_LSB = TWO_N19; -const std::vector> T_OE({{271,16}}); -const double T_OE_LSB = TWO_P4; -const std::vector> FIT_INTERVAL_FLAG({{271,1}}); -const std::vector> AODO({{272,5}}); -const int AODO_LSB = 900; +const std::vector> T_OE({{271, 16}}); +const int32_t T_OE_LSB = static_cast(TWO_P4); +const std::vector> FIT_INTERVAL_FLAG({{271, 1}}); +const std::vector> AODO({{272, 5}}); +const int32_t AODO_LSB = 900; // SUBFRAME 3 -const std::vector> C_IC({{61,16}}); +const std::vector> C_IC({{61, 16}}); const double C_IC_LSB = TWO_N29; -const std::vector> OMEGA_0({{77,8},{91,24}}); +const std::vector> OMEGA_0({{77, 8}, {91, 24}}); const double OMEGA_0_LSB = PI_TWO_N31; -const std::vector> C_IS({{121,16}}); +const std::vector> C_IS({{121, 16}}); const double C_IS_LSB = TWO_N29; -const std::vector> I_0({{137,8},{151,24}}); +const std::vector> I_0({{137, 8}, {151, 24}}); const double I_0_LSB = PI_TWO_N31; -const std::vector> C_RC({{181,16}}); +const std::vector> C_RC({{181, 16}}); const double C_RC_LSB = TWO_N5; -const std::vector> OMEGA({{197,8},{211,24}}); +const std::vector> OMEGA({{197, 8}, {211, 24}}); const double OMEGA_LSB = PI_TWO_N31; -const std::vector> OMEGA_DOT({{241,24}}); +const std::vector> OMEGA_DOT({{241, 24}}); const double OMEGA_DOT_LSB = PI_TWO_N43; -const std::vector> IODE_SF3({{271,8}}); -const std::vector> I_DOT({{279,14}}); +const std::vector> IODE_SF3({{271, 8}}); +const std::vector> I_DOT({{279, 14}}); const double I_DOT_LSB = PI_TWO_N43; // SUBFRAME 4-5 -const std::vector> SV_DATA_ID({{61,2}}); -const std::vector> SV_PAGE({{63,6}}); +const std::vector> SV_DATA_ID({{61, 2}}); +const std::vector> SV_PAGE({{63, 6}}); // SUBFRAME 4 //! \todo read all pages of subframe 4 // Page 18 - Ionospheric and UTC data -const std::vector> ALPHA_0({{69,8}}); +const std::vector> ALPHA_0({{69, 8}}); const double ALPHA_0_LSB = TWO_N30; -const std::vector> ALPHA_1({{77,8}}); +const std::vector> ALPHA_1({{77, 8}}); const double ALPHA_1_LSB = TWO_N27; -const std::vector> ALPHA_2({{91,8}}); +const std::vector> ALPHA_2({{91, 8}}); const double ALPHA_2_LSB = TWO_N24; -const std::vector> ALPHA_3({{99,8}}); +const std::vector> ALPHA_3({{99, 8}}); const double ALPHA_3_LSB = TWO_N24; -const std::vector> BETA_0({{107,8}}); +const std::vector> BETA_0({{107, 8}}); const double BETA_0_LSB = TWO_P11; -const std::vector> BETA_1({{121,8}}); +const std::vector> BETA_1({{121, 8}}); const double BETA_1_LSB = TWO_P14; -const std::vector> BETA_2({{129,8}}); +const std::vector> BETA_2({{129, 8}}); const double BETA_2_LSB = TWO_P16; -const std::vector> BETA_3({{137,8}}); +const std::vector> BETA_3({{137, 8}}); const double BETA_3_LSB = TWO_P16; -const std::vector> A_1({{151,24}}); +const std::vector> A_1({{151, 24}}); const double A_1_LSB = TWO_N50; -const std::vector> A_0({{181,24},{211,8}}); +const std::vector> A_0({{181, 24}, {211, 8}}); const double A_0_LSB = TWO_N30; -const std::vector> T_OT({{219,8}}); +const std::vector> T_OT({{219, 8}}); const double T_OT_LSB = TWO_P12; -const std::vector> WN_T({{227,8}}); +const std::vector> WN_T({{227, 8}}); const double WN_T_LSB = 1; -const std::vector> DELTAT_LS({{241,8}}); +const std::vector> DELTAT_LS({{241, 8}}); const double DELTAT_LS_LSB = 1; -const std::vector> WN_LSF({{249,8}}); +const std::vector> WN_LSF({{249, 8}}); const double WN_LSF_LSB = 1; -const std::vector> DN({{257,8}}); +const std::vector> DN({{257, 8}}); const double DN_LSB = 1; -const std::vector> DELTAT_LSF({{271,8}}); +const std::vector> DELTAT_LSF({{271, 8}}); const double DELTAT_LSF_LSB = 1; // Page 25 - Antispoofing, SV config and SV health (PRN 25 -32) -const std::vector> HEALTH_SV25({{229,6}}); -const std::vector> HEALTH_SV26({{241,6}}); -const std::vector> HEALTH_SV27({{247,6}}); -const std::vector> HEALTH_SV28({{253,6}}); -const std::vector> HEALTH_SV29({{259,6}}); -const std::vector> HEALTH_SV30({{271,6}}); -const std::vector> HEALTH_SV31({{277,6}}); -const std::vector> HEALTH_SV32({{283,6}}); +const std::vector> HEALTH_SV25({{229, 6}}); +const std::vector> HEALTH_SV26({{241, 6}}); +const std::vector> HEALTH_SV27({{247, 6}}); +const std::vector> HEALTH_SV28({{253, 6}}); +const std::vector> HEALTH_SV29({{259, 6}}); +const std::vector> HEALTH_SV30({{271, 6}}); +const std::vector> HEALTH_SV31({{277, 6}}); +const std::vector> HEALTH_SV32({{283, 6}}); // SUBFRAME 5 //! \todo read all pages of subframe 5 // page 25 - Health (PRN 1 - 24) -const std::vector> T_OA({{69,8}}); -const double T_OA_LSB = TWO_P12; -const std::vector> WN_A({{77,8}}); -const std::vector> HEALTH_SV1({{91,6}}); -const std::vector> HEALTH_SV2({{97,6}}); -const std::vector> HEALTH_SV3({{103,6}}); -const std::vector> HEALTH_SV4({{109,6}}); -const std::vector> HEALTH_SV5({{121,6}}); -const std::vector> HEALTH_SV6({{127,6}}); -const std::vector> HEALTH_SV7({{133,6}}); -const std::vector> HEALTH_SV8({{139,6}}); -const std::vector> HEALTH_SV9({{151,6}}); -const std::vector> HEALTH_SV10({{157,6}}); -const std::vector> HEALTH_SV11({{163,6}}); -const std::vector> HEALTH_SV12({{169,6}}); -const std::vector> HEALTH_SV13({{181,6}}); -const std::vector> HEALTH_SV14({{187,6}}); -const std::vector> HEALTH_SV15({{193,6}}); -const std::vector> HEALTH_SV16({{199,6}}); -const std::vector> HEALTH_SV17({{211,6}}); -const std::vector> HEALTH_SV18({{217,6}}); -const std::vector> HEALTH_SV19({{223,6}}); -const std::vector> HEALTH_SV20({{229,6}}); -const std::vector> HEALTH_SV21({{241,6}}); -const std::vector> HEALTH_SV22({{247,6}}); -const std::vector> HEALTH_SV23({{253,6}}); -const std::vector> HEALTH_SV24({{259,6}}); +const std::vector> T_OA({{69, 8}}); +const int32_t T_OA_LSB = TWO_P12; +const std::vector> WN_A({{77, 8}}); +const std::vector> HEALTH_SV1({{91, 6}}); +const std::vector> HEALTH_SV2({{97, 6}}); +const std::vector> HEALTH_SV3({{103, 6}}); +const std::vector> HEALTH_SV4({{109, 6}}); +const std::vector> HEALTH_SV5({{121, 6}}); +const std::vector> HEALTH_SV6({{127, 6}}); +const std::vector> HEALTH_SV7({{133, 6}}); +const std::vector> HEALTH_SV8({{139, 6}}); +const std::vector> HEALTH_SV9({{151, 6}}); +const std::vector> HEALTH_SV10({{157, 6}}); +const std::vector> HEALTH_SV11({{163, 6}}); +const std::vector> HEALTH_SV12({{169, 6}}); +const std::vector> HEALTH_SV13({{181, 6}}); +const std::vector> HEALTH_SV14({{187, 6}}); +const std::vector> HEALTH_SV15({{193, 6}}); +const std::vector> HEALTH_SV16({{199, 6}}); +const std::vector> HEALTH_SV17({{211, 6}}); +const std::vector> HEALTH_SV18({{217, 6}}); +const std::vector> HEALTH_SV19({{223, 6}}); +const std::vector> HEALTH_SV20({{229, 6}}); +const std::vector> HEALTH_SV21({{241, 6}}); +const std::vector> HEALTH_SV22({{247, 6}}); +const std::vector> HEALTH_SV23({{253, 6}}); +const std::vector> HEALTH_SV24({{259, 6}}); #endif /* GNSS_SDR_GPS_L1_CA_H_ */ diff --git a/src/core/system_parameters/GPS_L2C.h b/src/core/system_parameters/GPS_L2C.h index 4fd8374a2..40986fd5b 100644 --- a/src/core/system_parameters/GPS_L2C.h +++ b/src/core/system_parameters/GPS_L2C.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,187 +32,76 @@ #ifndef GNSS_SDR_GPS_L2C_H_ #define GNSS_SDR_GPS_L2C_H_ -#include -#include -#include // std::pair + +#include "GPS_CNAV.h" #include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include // std::pair +#include + // Physical constants -const double GPS_L2_C_m_s = 299792458.0; //!< The speed of light, [m/s] -const double GPS_L2_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] -const double GPS_L2_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E -const double GPS_L2_TWO_PI = 6.283185307179586;//!< 2Pi as defined in IS-GPS-200E +const double GPS_L2_C_m_s = 299792458.0; //!< The speed of light, [m/s] +const double GPS_L2_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GPS_L2_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E +const double GPS_L2_TWO_PI = 6.283185307179586; //!< 2Pi as defined in IS-GPS-200E const double GPS_L2_OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Earth rotation rate, [rad/s] -const double GPS_L2_GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] -const double GPS_L2_F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] - +const double GPS_L2_GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] +const double GPS_L2_F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] // carrier and code frequencies -const double GPS_L2_FREQ_HZ = 1.2276e9; //!< L2 [Hz] +const double GPS_L2_FREQ_HZ = FREQ2; //!< L2 [Hz] -const double GPS_L2_M_CODE_RATE_HZ = 0.5115e6; //!< GPS L2 M code rate [chips/s] -const int GPS_L2_M_CODE_LENGTH_CHIPS = 10230; //!< GPS L2 M code length [chips] -const double GPS_L2_M_PERIOD = 0.02; //!< GPS L2 M code period [seconds] +const double GPS_L2_M_CODE_RATE_HZ = 0.5115e6; //!< GPS L2 M code rate [chips/s] +const int32_t GPS_L2_M_CODE_LENGTH_CHIPS = 10230; //!< GPS L2 M code length [chips] +const double GPS_L2_M_PERIOD = 0.02; //!< GPS L2 M code period [seconds] -const double GPS_L2_L_CODE_RATE_HZ = 0.5115e6; //!< GPS L2 L code rate [chips/s] -const int GPS_L2_L_CODE_LENGTH_CHIPS = 767250; //!< GPS L2 L code length [chips] -const double GPS_L2_L_PERIOD = 1.5; //!< GPS L2 L code period [seconds] +const double GPS_L2_L_CODE_RATE_HZ = 0.5115e6; //!< GPS L2 L code rate [chips/s] +const int32_t GPS_L2_L_CODE_LENGTH_CHIPS = 767250; //!< GPS L2 L code length [chips] +const double GPS_L2_L_PERIOD = 1.5; //!< GPS L2 L code period [seconds] + +const int32_t GPS_L2C_HISTORY_DEEP = 5; + +//optimum parameters +const uint32_t GPS_L2C_OPT_ACQ_FS_HZ = 1000000; //!< Sampling frequncy that maximizes the acquisition SNR while using a non-multiple of chip rate -const int GPS_L2C_HISTORY_DEEP = 5; const int32_t GPS_L2C_M_INIT_REG[115] = - {0742417664, 0756014035,0002747144,0066265724, // 1:4 - 0601403471, 0703232733, 0124510070, 0617316361, // 5:8 - 0047541621, 0733031046, 0713512145, 0024437606, - 0021264003, 0230655351, 0001314400, 0222021506, - 0540264026, 0205521705, 0064022144, 0120161274, - 0044023533, 0724744327, 0045743577, 0741201660, - 0700274134, 0010247261, 0713433445, 0737324162, - 0311627434, 0710452007, 0722462133, 0050172213, - 0500653703, 0755077436, 0136717361, 0756675453, - 0435506112, 0771353753, 0226107701, 0022025110, - 0402466344, 0752566114, 0702011164, 0041216771, - 0047457275, 0266333164, 0713167356, 0060546335, - 0355173035, 0617201036, 0157465571, 0767360553, - 0023127030, 0431343777, 0747317317, 0045706125, - 0002744276, 0060036467, 0217744147, 0603340174,//57:60 - 0326616775, 0063240065, 0111460621, //61:63 - 0604055104, 0157065232, 0013305707, 0603552017,//159:162 - 0230461355, 0603653437, 0652346475, 0743107103, - 0401521277, 0167335110, 0014013575, 0362051132, - 0617753265, 0216363634, 0755561123, 0365304033, - 0625025543, 0054420334, 0415473671, 0662364360, - 0373446602, 0417564100, 0000526452, 0226631300, - 0113752074, 0706134401, 0041352546, 0664630154, - 0276524255, 0714720530, 0714051771, 0044526647, - 0207164322, 0262120161, 0204244652, 0202133131, - 0714351204, 0657127260, 0130567507, 0670517677, - 0607275514, 0045413633, 0212645405, 0613700455, - 0706202440, 0705056276, 0020373522, 0746013617, - 0132720621, 0434015513, 0566721727, 0140633660}; - -// CNAV GPS NAVIGATION MESSAGE STRUCTURE -// NAVIGATION MESSAGE FIELDS POSITIONS (from IS-GPS-200E Appendix III) - -#define GPS_CNAV_PREAMBLE {1, 0, 0, 0, 1, 0, 1, 1} - -const int GPS_L2_CNAV_DATA_PAGE_BITS = 300; //!< GPS L2 CNAV page length, including preamble and CRC [bits] -const int GPS_L2_SYMBOLS_PER_BIT = 2; -const int GPS_L2_SAMPLES_PER_SYMBOL = 1; -const int GPS_L2_CNAV_DATA_PAGE_DURATION_S = 12; -const int GPS_L2_CNAV_DATA_PAGE_BITS_EXTENDED_BYTES = 304; //!< GPS L2 CNAV page length, including preamble and CRC [bits] - -// common to all messages -const std::vector > CNAV_PRN( { {9,6} } ); -const std::vector > CNAV_MSG_TYPE( { {15,6} } ); -const std::vector > CNAV_TOW( { {21,17} } ); //GPS Time Of Week in seconds -const double CNAV_TOW_LSB = 6.0; -const std::vector > CNAV_ALERT_FLAG( { {38,1} } ); - -// MESSAGE TYPE 10 (Ephemeris 1) - -const std::vector > CNAV_WN({{39,13}}); -const std::vector > CNAV_HEALTH({{52,3}}); -const std::vector > CNAV_TOP1({{55,11}}); -const double CNAV_TOP1_LSB = 300.0; -const std::vector > CNAV_URA({{66,5}}); - -const std::vector > CNAV_TOE1({{71,11}}); -const double CNAV_TOE1_LSB = 300.0; - -const std::vector > CNAV_DELTA_A({{82,26}}); //Relative to AREF = 26,559,710 meters -const double CNAV_DELTA_A_LSB = TWO_N9; - -const std::vector > CNAV_A_DOT({{108,25}}); -const double CNAV_A_DOT_LSB = TWO_N21; - -const std::vector > CNAV_DELTA_N0({{133,17}}); -const double CNAV_DELTA_N0_LSB = TWO_N44; -const std::vector > CNAV_DELTA_N0_DOT({{150,23}}); -const double CNAV_DELTA_N0_DOT_LSB = TWO_N57; -const std::vector > CNAV_M0({{173,33}}); -const double CNAV_M0_LSB = TWO_N32; -const std::vector > CNAV_E_ECCENTRICITY({{206,33}}); -const double CNAV_E_ECCENTRICITY_LSB = TWO_N34; -const std::vector > CNAV_OMEGA({{239,33}}); -const double CNAV_OMEGA_LSB = TWO_N32; -const std::vector > CNAV_INTEGRITY_FLAG({{272,1}}); -const std::vector > CNAV_L2_PHASING_FLAG({{273,1}}); - -// MESSAGE TYPE 11 (Ephemeris 2) - -const std::vector > CNAV_TOE2({{39,11}}); -const double CNAV_TOE2_LSB = 300.0; -const std::vector > CNAV_OMEGA0({{50,33}}); -const double CNAV_OMEGA0_LSB = TWO_N32; -const std::vector > CNAV_I0({{83,33}}); -const double CNAV_I0_LSB = TWO_N32; -const std::vector > CNAV_DELTA_OMEGA_DOT({{116,17}}); //Relative to REF = -2.6 x 10-9 semi-circles/second. -const double CNAV_DELTA_OMEGA_DOT_LSB = TWO_N44; -const std::vector > CNAV_I0_DOT({{133,15}}); -const double CNAV_I0_DOT_LSB = TWO_N44; -const std::vector > CNAV_CIS({{148,16}}); -const double CNAV_CIS_LSB = TWO_N30; -const std::vector > CNAV_CIC({{164,16}}); -const double CNAV_CIC_LSB = TWO_N30; -const std::vector > CNAV_CRS({{180,24}}); -const double CNAV_CRS_LSB = TWO_N8; -const std::vector > CNAV_CRC({{204,24}}); -const double CNAV_CRC_LSB = TWO_N8; -const std::vector > CNAV_CUS({{228,21}}); -const double CNAV_CUS_LSB = TWO_N30; -const std::vector > CNAV_CUC({{249,21}}); -const double CNAV_CUC_LSB = TWO_N30; - - -// MESSAGE TYPE 30 (CLOCK, IONO, GRUP DELAY) - -const std::vector > CNAV_TOP2({{39,11}}); -const double CNAV_TOP2_LSB = 300.0; - -const std::vector > CNAV_URA_NED0({{50,5}}); -const std::vector > CNAV_URA_NED1({{55,3}}); -const std::vector > CNAV_URA_NED2({{58,3}}); -const std::vector > CNAV_TOC({{61,11}}); -const double CNAV_TOC_LSB = 300.0; -const std::vector > CNAV_AF0({{72,26}}); -const double CNAV_AF0_LSB = TWO_N60; -const std::vector > CNAV_AF1({{98,20}}); -const double CNAV_AF1_LSB = TWO_N48; -const std::vector > CNAV_AF2({{118,10}}); -const double CNAV_AF2_LSB = TWO_N35; -const std::vector > CNAV_TGD({{128,13}}); -const double CNAV_TGD_LSB = TWO_N35; -const std::vector > CNAV_ISCL1({{141,13}}); -const double CNAV_ISCL1_LSB = TWO_N35; -const std::vector > CNAV_ISCL2({{154,13}}); -const double CNAV_ISCL2_LSB = TWO_N35; -const std::vector > CNAV_ISCL5I({{167,13}}); -const double CNAV_ISCL5I_LSB = TWO_N35; -const std::vector > CNAV_ISCL5Q({{180,13}}); -const double CNAV_ISCL5Q_LSB = TWO_N35; -//Ionospheric parameters -const std::vector > CNAV_ALPHA0({{193,8}}); -const double CNAV_ALPHA0_LSB = TWO_N30; -const std::vector > CNAV_ALPHA1({{201,8}}); -const double CNAV_ALPHA1_LSB = TWO_N27; -const std::vector > CNAV_ALPHA2({{209,8}}); -const double CNAV_ALPHA2_LSB = TWO_N24; -const std::vector > CNAV_ALPHA3({{217,8}}); -const double CNAV_ALPHA3_LSB = TWO_N24; -const std::vector > CNAV_BETA0({{225,8}}); -const double CNAV_BETA0_LSB = TWO_P11; -const std::vector > CNAV_BETA1({{233,8}}); -const double CNAV_BETA1_LSB = TWO_P14; -const std::vector > CNAV_BETA2({{241,8}}); -const double CNAV_BETA2_LSB = TWO_P16; -const std::vector > CNAV_BETA3({{249,8}}); -const double CNAV_BETA3_LSB = TWO_P16; -const std::vector > CNAV_WNOP({{257,8}}); - - -// TODO: Add more frames (Almanac, etc...) - + {0742417664, 0756014035, 0002747144, 0066265724, // 1:4 + 0601403471, 0703232733, 0124510070, 0617316361, // 5:8 + 0047541621, 0733031046, 0713512145, 0024437606, + 0021264003, 0230655351, 0001314400, 0222021506, + 0540264026, 0205521705, 0064022144, 0120161274, + 0044023533, 0724744327, 0045743577, 0741201660, + 0700274134, 0010247261, 0713433445, 0737324162, + 0311627434, 0710452007, 0722462133, 0050172213, + 0500653703, 0755077436, 0136717361, 0756675453, + 0435506112, 0771353753, 0226107701, 0022025110, + 0402466344, 0752566114, 0702011164, 0041216771, + 0047457275, 0266333164, 0713167356, 0060546335, + 0355173035, 0617201036, 0157465571, 0767360553, + 0023127030, 0431343777, 0747317317, 0045706125, + 0002744276, 0060036467, 0217744147, 0603340174, // 57:60 + 0326616775, 0063240065, 0111460621, // 61:63 + 0604055104, 0157065232, 0013305707, 0603552017, // 159:162 + 0230461355, 0603653437, 0652346475, 0743107103, + 0401521277, 0167335110, 0014013575, 0362051132, + 0617753265, 0216363634, 0755561123, 0365304033, + 0625025543, 0054420334, 0415473671, 0662364360, + 0373446602, 0417564100, 0000526452, 0226631300, + 0113752074, 0706134401, 0041352546, 0664630154, + 0276524255, 0714720530, 0714051771, 0044526647, + 0207164322, 0262120161, 0204244652, 0202133131, + 0714351204, 0657127260, 0130567507, 0670517677, + 0607275514, 0045413633, 0212645405, 0613700455, + 0706202440, 0705056276, 0020373522, 0746013617, + 0132720621, 0434015513, 0566721727, 0140633660}; +const int32_t GPS_L2_CNAV_DATA_PAGE_BITS = 300; //!< GPS L2 CNAV page length, including preamble and CRC [bits] +const int32_t GPS_L2_SYMBOLS_PER_BIT = 2; +const int32_t GPS_L2_SAMPLES_PER_SYMBOL = 1; +const int32_t GPS_L2_CNAV_DATA_PAGE_SYMBOLS = 600; +const int32_t GPS_L2_CNAV_DATA_PAGE_DURATION_S = 12; #endif /* GNSS_SDR_GPS_L2C_H_ */ diff --git a/src/core/system_parameters/GPS_L5.h b/src/core/system_parameters/GPS_L5.h new file mode 100644 index 000000000..ff669d8b0 --- /dev/null +++ b/src/core/system_parameters/GPS_L5.h @@ -0,0 +1,196 @@ +/*! + * \file GPS_L5.h + * \brief Defines system parameters for GPS L5 signal + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GPS_L5_H_ +#define GNSS_SDR_GPS_L5_H_ + +#include "GPS_CNAV.h" +#include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include + + +// Physical constants +const double GPS_L5_C_m_s = 299792458.0; //!< The speed of light, [m/s] +const double GPS_L5_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GPS_L5_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E +const double GPS_L5_TWO_PI = 6.283185307179586; //!< 2Pi as defined in IS-GPS-200E +const double GPS_L5_OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Earth rotation rate, [rad/s] +const double GPS_L5_GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] +const double GPS_L5_F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] + +// carrier and code frequencies +const double GPS_L5_FREQ_HZ = FREQ5; //!< L5 [Hz] + +const double GPS_L5i_CODE_RATE_HZ = 10.23e6; //!< GPS L5i code rate [chips/s] +const int32_t GPS_L5i_CODE_LENGTH_CHIPS = 10230; //!< GPS L5i code length [chips] +const double GPS_L5i_PERIOD = 0.001; //!< GPS L5 code period [seconds] +const int32_t GPS_L5i_PERIOD_MS = 1; //!< GPS L5 code period [ms] +const double GPS_L5i_SYMBOL_PERIOD = 0.01; //!< GPS L5 symbol period [seconds] +const int32_t GPS_L5i_SYMBOL_PERIOD_MS = 10; //!< GPS L5 symbol period [ms] + +const double GPS_L5q_CODE_RATE_HZ = 10.23e6; //!< GPS L5i code rate [chips/s] +const int32_t GPS_L5q_CODE_LENGTH_CHIPS = 10230; //!< GPS L5i code length [chips] +const double GPS_L5q_PERIOD = 0.001; //!< GPS L5 code period [seconds] + +const int32_t GPS_L5_HISTORY_DEEP = 5; + +//optimum parameters +const uint32_t GPS_L5_OPT_ACQ_FS_HZ = 10000000; //!< Sampling frequncy that maximizes the acquisition SNR while using a non-multiple of chip rate + +const int32_t GPS_L5i_INIT_REG[210] = + {266, 365, 804, 1138, + 1509, 1559, 1756, 2084, + 2170, 2303, 2527, 2687, + 2930, 3471, 3940, 4132, + 4332, 4924, 5343, 5443, + 5641, 5816, 5898, 5918, + 5955, 6243, 6345, 6477, + 6518, 6875, 7168, 7187, + 7329, 7577, 7720, 7777, + 8057, 5358, 3550, 3412, + 819, + 4608, 3698, 962, 3001, + 4441, 4937, 3717, 4730, + 7291, 2279, 7613, 5723, + 7030, 1475, 2593, 2904, + 2056, 2757, 3756, 6205, + 5053, 6437, + 7789, 2311, 7432, 5155, + 1593, 5841, 5014, 1545, + 3016, 4875, 2119, 229, + 7634, 1406, 4506, 1819, + 7580, 5446, 6053, 7958, + 5267, 2956, 3544, 1277, + 2996, 1758, 3360, 2718, + 3754, 7440, 2781, 6756, + 7314, 208, 5252, 696, + 527, 1399, 5879, 6868, + 217, 7681, 3788, 1337, + 2424, 4243, 5686, 1955, + 4791, 492, 1518, 6566, + 5349, 506, 113, 1953, + 2797, 934, 3023, 3632, + 1330, 4909, 4867, 1183, + 3990, 6217, 1224, 1733, + 2319, 3928, 2380, 841, + 5049, 7027, 1197, 7208, + 8000, 152, 6762, 3745, + 4723, 5502, 4796, 123, + 8142, 5091, 7875, 330, + 5272, 4912, 374, 2045, + 6616, 6321, 7605, 2570, + 2419, 1234, 1922, 4317, + 5110, 825, 958, 1089, + 7813, 6058, 7703, 6702, + 1714, 6371, 2281, 1986, + 6282, 3201, 3760, 1056, + 6233, 1150, 2823, 6250, + 645, 2401, 1639, 2946, + 7091, 923, 7045, 6493, + 1706, 5836, 926, 6086, + 950, 5905, 3240, 6675, + 3197, 1555, 3589, 4555, + 5671, 6948, 4664, 2086, + 5950, 5521, 1515}; + + +const int32_t GPS_L5q_INIT_REG[210] = + { + 1701, 323, 5292, 2020, + 5429, 7136, 1041, 5947, + 4315, 148, 535, 1939, + 5206, 5910, 3595, 5135, + 6082, 6990, 3546, 1523, + 4548, 4484, 1893, 3961, + 7106, 5299, 4660, 276, + 4389, 3783, 1591, 1601, + 749, 1387, 1661, 3210, + 708, + 4226, 5604, 6375, 3056, + 1772, 3662, 4401, 5218, + 2838, 6913, 1685, 1194, + 6963, 5001, 6694, 991, + 7489, 2441, 639, 2097, + 2498, 6470, 2399, 242, + 3768, 1186, + 5246, 4259, 5907, 3870, + 3262, 7387, 3069, 2999, + 7993, 7849, 4157, 5031, + 5986, 4833, 5739, 7846, + 898, 2022, 7446, 6404, + 155, 7862, 7795, 6121, + 4840, 6585, 429, 6020, + 200, 1664, 1499, 7298, + 1305, 7323, 7544, 4438, + 2485, 3387, 7319, 1853, + 5781, 1874, 7555, 2132, + 6441, 6722, 1192, 2588, + 2188, 297, 1540, 4138, + 5231, 4789, 659, 871, + 6837, 1393, 7383, 611, + 4920, 5416, 1611, 2474, + 118, 1382, 1092, 7950, + 7223, 1769, 4721, 1252, + 5147, 2165, 7897, 4054, + 3498, 6571, 2858, 8126, + 7017, 1901, 181, 1114, + 5195, 7479, 4186, 3904, + 7128, 1396, 4513, 5967, + 2580, 2575, 7961, 2598, + 4508, 2090, 3685, 7748, + 684, 913, 5558, 2894, + 5858, 6432, 3813, 3573, + 7523, 5280, 3376, 7424, + 2918, 5793, 1747, 7079, + 2921, 2490, 4119, 3373, + 977, 681, 4273, 5419, + 5626, 1266, 5804, 2414, + 6444, 4757, 427, 5452, + 5182, 6606, 6531, 4268, + 3115, 6835, 862, 4856, + 2765, 37, 1943, 7977, + 2512, 4451, 4071}; + +const int32_t GPS_L5_CNAV_DATA_PAGE_BITS = 300; //!< GPS L5 CNAV page length, including preamble and CRC [bits] +const int32_t GPS_L5_SYMBOLS_PER_BIT = 2; +const int32_t GPS_L5_SAMPLES_PER_SYMBOL = 10; +const int32_t GPS_L5_CNAV_DATA_PAGE_SYMBOLS = 600; +const int32_t GPS_L5_CNAV_DATA_PAGE_DURATION_S = 6; +const int32_t GPS_L5i_NH_CODE_LENGTH = 10; +const int32_t GPS_L5i_NH_CODE[10] = {0, 0, 0, 0, 1, 1, 0, 1, 0, 1}; +const std::string GPS_L5i_NH_CODE_STR = "0000110101"; +const int32_t GPS_L5q_NH_CODE_LENGTH = 20; +const int32_t GPS_L5q_NH_CODE[20] = {0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0}; +const std::string GPS_L5q_NH_CODE_STR = "00000100110101001110"; + +#endif /* GNSS_SDR_GPS_L5_H_ */ diff --git a/src/core/system_parameters/Galileo_E1.h b/src/core/system_parameters/Galileo_E1.h index 258a9e954..93a814805 100644 --- a/src/core/system_parameters/Galileo_E1.h +++ b/src/core/system_parameters/Galileo_E1.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,370 +33,382 @@ #ifndef GNSS_SDR_GALILEO_E1_H_ #define GNSS_SDR_GALILEO_E1_H_ -#include -#include -#include // std::pair #include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include +#include // std::pair +#include + // Physical constants -const double GALILEO_PI = 3.1415926535898; //!< Pi as defined in GALILEO ICD -const double GALILEO_TWO_PI = 6.283185307179600 ; //!< 2*Pi as defined in GALILEO ICD -const double GALILEO_GM = 3.986004418e14; //!< Geocentric gravitational constant[m^3/s^2] +const double GALILEO_PI = 3.1415926535898; //!< Pi as defined in GALILEO ICD +const double GALILEO_TWO_PI = 6.283185307179600; //!< 2*Pi as defined in GALILEO ICD +const double GALILEO_GM = 3.986004418e14; //!< Geocentric gravitational constant[m^3/s^2] const double GALILEO_OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Mean angular velocity of the Earth [rad/s] -const double GALILEO_C_m_s = 299792458.0; //!< The speed of light, [m/s] -const double GALILEO_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] -const double GALILEO_F = -4.442807309e-10; //!< Constant, [s/(m)^(1/2)] +const double GALILEO_C_m_s = 299792458.0; //!< The speed of light, [m/s] +const double GALILEO_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GALILEO_F = -4.442807309e-10; //!< Constant, [s/(m)^(1/2)] // carrier and code frequencies -const double Galileo_E1_FREQ_HZ = 1.57542e9; //!< Galileo E1 carrier frequency [Hz] -const double Galileo_E1_CODE_CHIP_RATE_HZ = 1.023e6; //!< Galileo E1 code rate [chips/s] -const double Galileo_E1_CODE_PERIOD = 0.004; //!< Galileo E1 code period [s] -const double Galileo_E1_SUB_CARRIER_A_RATE_HZ = 1.023e6; //!< Galileo E1 sub-carrier 'a' rate [Hz] -const double Galileo_E1_SUB_CARRIER_B_RATE_HZ = 6.138e6; //!< Galileo E1 sub-carrier 'b' rate [Hz] -const double Galileo_E1_B_CODE_LENGTH_CHIPS = 4092.0; //!< Galileo E1-B code length [chips] -const double Galileo_E1_B_SYMBOL_RATE_BPS = 250.0; //!< Galileo E1-B symbol rate [bits/second] -const double Galileo_E1_C_SECONDARY_CODE_LENGTH = 25.0; //!< Galileo E1-C secondary code length [chips] -const int Galileo_E1_NUMBER_OF_CODES = 50; +const double Galileo_E1_FREQ_HZ = FREQ1; //!< Galileo E1 carrier frequency [Hz] +const double Galileo_E1_CODE_CHIP_RATE_HZ = 1.023e6; //!< Galileo E1 code rate [chips/s] +const double Galileo_E1_CODE_PERIOD = 0.004; //!< Galileo E1 code period [s] +const int32_t Galileo_E1_CODE_PERIOD_MS = 4; //!< Galileo E1 code period [ms] +const double Galileo_E1_SUB_CARRIER_A_RATE_HZ = 1.023e6; //!< Galileo E1 sub-carrier 'a' rate [Hz] +const double Galileo_E1_SUB_CARRIER_B_RATE_HZ = 6.138e6; //!< Galileo E1 sub-carrier 'b' rate [Hz] +const double Galileo_E1_B_CODE_LENGTH_CHIPS = 4092.0; //!< Galileo E1-B code length [chips] +const double Galileo_E1_B_SYMBOL_RATE_BPS = 250.0; //!< Galileo E1-B symbol rate [bits/second] +const int32_t Galileo_E1_B_SAMPLES_PER_SYMBOL = 1; //!< (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS) / Galileo_E1_B_SYMBOL_RATE_BPS +const int32_t Galileo_E1_C_SECONDARY_CODE_LENGTH = 25; //!< Galileo E1-C secondary code length [chips] +const int32_t Galileo_E1_NUMBER_OF_CODES = 50; -const double GALILEO_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) + +//optimum parameters +const uint32_t Galileo_E1_OPT_ACQ_FS_HZ = 2000000; //!< Sampling frequncy that maximizes the acquisition SNR while using a non-multiple of chip rate + + +const double GALILEO_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) // OBSERVABLE HISTORY DEEP FOR INTERPOLATION -const int GALILEO_E1_HISTORY_DEEP=100; +const int32_t GALILEO_E1_HISTORY_DEEP = 100; // Galileo INAV Telemetry structure -#define GALILEO_INAV_PREAMBLE {0, 1, 0, 1, 1, 0, 0, 0, 0, 0} +const std::string GALILEO_INAV_PREAMBLE = {"0101100000"}; -const int GALILEO_INAV_PREAMBLE_LENGTH_BITS = 10; -const int GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS = 250; -const int GALILEO_INAV_PAGE_PART_SYMBOLS = 250; //!< Each Galileo INAV pages are composed of two parts (even and odd) each of 250 symbols, including preamble. See Galileo ICD 4.3.2 -const int GALILEO_INAV_PAGE_SYMBOLS = 500; //!< The complete Galileo INAV page length -const int GALILEO_INAV_PAGE_PART_SECONDS = 1; // a page part last 1 sec -const int GALILEO_INAV_PAGE_SECONDS = 2; // a full page last 2 sec -const int GALILEO_INAV_INTERLEAVER_ROWS = 8; -const int GALILEO_INAV_INTERLEAVER_COLS = 30; -const int GALILEO_TELEMETRY_RATE_BITS_SECOND = 250; //bps -const int GALILEO_PAGE_TYPE_BITS = 6; -const int GALILEO_DATA_JK_BITS = 128; -const int GALILEO_DATA_FRAME_BITS = 196; -const int GALILEO_DATA_FRAME_BYTES = 25; -//const double GALIELO_E1_CODE_PERIOD = 0.004; +const int32_t GALILEO_INAV_PREAMBLE_LENGTH_BITS = 10; +const double GALILEO_INAV_PAGE_PART_WITH_PREABLE_SECONDS = 2.0 + GALILEO_INAV_PREAMBLE_LENGTH_BITS * Galileo_E1_CODE_PERIOD; +const int32_t GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS = 250; +const int32_t GALILEO_INAV_PAGE_PART_SYMBOLS = 250; //!< Each Galileo INAV pages are composed of two parts (even and odd) each of 250 symbols, including preamble. See Galileo ICD 4.3.2 +const int32_t GALILEO_INAV_PAGE_SYMBOLS = 500; //!< The complete Galileo INAV page length +const int32_t GALILEO_INAV_PAGE_PART_SECONDS = 1; // a page part last 1 sec +const int32_t GALILEO_INAV_PAGE_PART_MS = 1000; // a page part last 1 sec +const int32_t GALILEO_INAV_PAGE_SECONDS = 2; // a full page last 2 sec +const int32_t GALILEO_INAV_INTERLEAVER_ROWS = 8; +const int32_t GALILEO_INAV_INTERLEAVER_COLS = 30; +const int32_t GALILEO_TELEMETRY_RATE_BITS_SECOND = 250; //bps +const int32_t GALILEO_PAGE_TYPE_BITS = 6; +const int32_t GALILEO_DATA_JK_BITS = 128; +const int32_t GALILEO_DATA_FRAME_BITS = 196; +const int32_t GALILEO_DATA_FRAME_BYTES = 25; const double GALILEO_E1_CODE_PERIOD = 0.004; +const int32_t GALILEO_E1_CODE_PERIOD_MS = 4; -const std::vector> type({{1,6}}); -const std::vector> PAGE_TYPE_bit({{1,6}});; +const std::vector> type({{1, 6}}); +const std::vector> PAGE_TYPE_bit({{1, 6}}); +; /*Page 1 - Word type 1: Ephemeris (1/4)*/ -const std::vector> IOD_nav_1_bit({{7,10}}); -const std::vector> T0E_1_bit({{17,14}}); -const double t0e_1_LSB = 60; -const std::vector> M0_1_bit({{31,32}}); +const std::vector> IOD_nav_1_bit({{7, 10}}); +const std::vector> T0E_1_bit({{17, 14}}); +const int32_t t0e_1_LSB = 60; +const std::vector> M0_1_bit({{31, 32}}); const double M0_1_LSB = PI_TWO_N31; -const std::vector> e_1_bit({{63,32}}); +const std::vector> e_1_bit({{63, 32}}); const double e_1_LSB = TWO_N33; -const std::vector> A_1_bit({{95,32}}); +const std::vector> A_1_bit({{95, 32}}); const double A_1_LSB_gal = TWO_N19; //last two bits are reserved /*Page 2 - Word type 2: Ephemeris (2/4)*/ -const std::vector> IOD_nav_2_bit({{7,10}}); -const std::vector> OMEGA_0_2_bit({{17,32}}); +const std::vector> IOD_nav_2_bit({{7, 10}}); +const std::vector> OMEGA_0_2_bit({{17, 32}}); const double OMEGA_0_2_LSB = PI_TWO_N31; -const std::vector> i_0_2_bit({{49,32}}); +const std::vector> i_0_2_bit({{49, 32}}); const double i_0_2_LSB = PI_TWO_N31; -const std::vector> omega_2_bit({{81,32}}); +const std::vector> omega_2_bit({{81, 32}}); const double omega_2_LSB = PI_TWO_N31; -const std::vector> iDot_2_bit({{113,14}}); +const std::vector> iDot_2_bit({{113, 14}}); const double iDot_2_LSB = PI_TWO_N43; //last two bits are reserved /*Word type 3: Ephemeris (3/4) and SISA*/ -const std::vector> IOD_nav_3_bit({{7,10}}); -const std::vector> OMEGA_dot_3_bit({{17,24}}); +const std::vector> IOD_nav_3_bit({{7, 10}}); +const std::vector> OMEGA_dot_3_bit({{17, 24}}); const double OMEGA_dot_3_LSB = PI_TWO_N43; -const std::vector> delta_n_3_bit({{41,16}}); +const std::vector> delta_n_3_bit({{41, 16}}); const double delta_n_3_LSB = PI_TWO_N43; -const std::vector> C_uc_3_bit({{57,16}}); +const std::vector> C_uc_3_bit({{57, 16}}); const double C_uc_3_LSB = TWO_N29; -const std::vector> C_us_3_bit({{73,16}}); +const std::vector> C_us_3_bit({{73, 16}}); const double C_us_3_LSB = TWO_N29; -const std::vector> C_rc_3_bit({{89,16}}); +const std::vector> C_rc_3_bit({{89, 16}}); const double C_rc_3_LSB = TWO_N5; -const std::vector> C_rs_3_bit({{105,16}}); +const std::vector> C_rs_3_bit({{105, 16}}); const double C_rs_3_LSB = TWO_N5; -const std::vector> SISA_3_bit({{121,8}}); +const std::vector> SISA_3_bit({{121, 8}}); /*Word type 4: Ephemeris (4/4) and Clock correction parameters*/ -const std::vector> IOD_nav_4_bit({{7,10}}); -const std::vector> SV_ID_PRN_4_bit({{17,6}}); -const std::vector> C_ic_4_bit({{23,16}}); +const std::vector> IOD_nav_4_bit({{7, 10}}); +const std::vector> SV_ID_PRN_4_bit({{17, 6}}); +const std::vector> C_ic_4_bit({{23, 16}}); const double C_ic_4_LSB = TWO_N29; -const std::vector> C_is_4_bit({{39,16}}); +const std::vector> C_is_4_bit({{39, 16}}); const double C_is_4_LSB = TWO_N29; -const std::vector> t0c_4_bit({{55,14}}); // -const double t0c_4_LSB = 60; -const std::vector> af0_4_bit({{69,31}}); // +const std::vector> t0c_4_bit({{55, 14}}); // +const int32_t t0c_4_LSB = 60; +const std::vector> af0_4_bit({{69, 31}}); // const double af0_4_LSB = TWO_N34; -const std::vector> af1_4_bit({{100,21}}); // +const std::vector> af1_4_bit({{100, 21}}); // const double af1_4_LSB = TWO_N46; -const std::vector> af2_4_bit({{121,6}}); +const std::vector> af2_4_bit({{121, 6}}); const double af2_4_LSB = TWO_N59; -const std::vector> spare_4_bit({{127,2}}); +const std::vector> spare_4_bit({{127, 2}}); //last two bits are reserved /*Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST*/ /*Ionospheric correction*/ /*Az*/ -const std::vector> ai0_5_bit({{7,11}}); // +const std::vector> ai0_5_bit({{7, 11}}); // const double ai0_5_LSB = TWO_N2; -const std::vector> ai1_5_bit({{18,11}}); // +const std::vector> ai1_5_bit({{18, 11}}); // const double ai1_5_LSB = TWO_N8; -const std::vector> ai2_5_bit({{29,14}}); // +const std::vector> ai2_5_bit({{29, 14}}); // const double ai2_5_LSB = TWO_N15; /*Ionospheric disturbance flag*/ -const std::vector> Region1_5_bit({{43,1}}); // -const std::vector> Region2_5_bit({{44,1}}); // -const std::vector> Region3_5_bit({{45,1}}); // -const std::vector> Region4_5_bit({{46,1}}); // -const std::vector> Region5_5_bit({{47,1}}); // -const std::vector> BGD_E1E5a_5_bit({{48,10}}); // +const std::vector> Region1_5_bit({{43, 1}}); // +const std::vector> Region2_5_bit({{44, 1}}); // +const std::vector> Region3_5_bit({{45, 1}}); // +const std::vector> Region4_5_bit({{46, 1}}); // +const std::vector> Region5_5_bit({{47, 1}}); // +const std::vector> BGD_E1E5a_5_bit({{48, 10}}); // const double BGD_E1E5a_5_LSB = TWO_N32; -const std::vector> BGD_E1E5b_5_bit({{58,10}}); // +const std::vector> BGD_E1E5b_5_bit({{58, 10}}); // const double BGD_E1E5b_5_LSB = TWO_N32; -const std::vector> E5b_HS_5_bit({{68,2}}); // -const std::vector> E1B_HS_5_bit({{70,2}}); // -const std::vector> E5b_DVS_5_bit({{72,1}}); // -const std::vector> E1B_DVS_5_bit({{73,1}}); // +const std::vector> E5b_HS_5_bit({{68, 2}}); // +const std::vector> E1B_HS_5_bit({{70, 2}}); // +const std::vector> E5b_DVS_5_bit({{72, 1}}); // +const std::vector> E1B_DVS_5_bit({{73, 1}}); // /*GST*/ -const std::vector> WN_5_bit({{74,12}}); -const std::vector> TOW_5_bit({{86,20}}); -const std::vector> spare_5_bit({{106,23}}); +const std::vector> WN_5_bit({{74, 12}}); +const std::vector> TOW_5_bit({{86, 20}}); +const std::vector> spare_5_bit({{106, 23}}); /* Page 6 */ -const std::vector> A0_6_bit({{7,32}}); +const std::vector> A0_6_bit({{7, 32}}); const double A0_6_LSB = TWO_N30; -const std::vector> A1_6_bit({{39,24}}); +const std::vector> A1_6_bit({{39, 24}}); const double A1_6_LSB = TWO_N50; -const std::vector> Delta_tLS_6_bit({{63,8}}); -const std::vector> t0t_6_bit({{71,8}}); -const double t0t_6_LSB = 3600; -const std::vector> WNot_6_bit({{79,8}}); -const std::vector> WN_LSF_6_bit({{87,8}}); -const std::vector> DN_6_bit({{95,3}}); -const std::vector> Delta_tLSF_6_bit({{98,8}}); -const std::vector> TOW_6_bit({{106,20}}); +const std::vector> Delta_tLS_6_bit({{63, 8}}); +const std::vector> t0t_6_bit({{71, 8}}); +const int32_t t0t_6_LSB = 3600; +const std::vector> WNot_6_bit({{79, 8}}); +const std::vector> WN_LSF_6_bit({{87, 8}}); +const std::vector> DN_6_bit({{95, 3}}); +const std::vector> Delta_tLSF_6_bit({{98, 8}}); +const std::vector> TOW_6_bit({{106, 20}}); /* Page 7 */ -const std::vector> IOD_a_7_bit({{7,4}}); -const std::vector> WN_a_7_bit({{11,2}}); -const std::vector> t0a_7_bit({{13,10}}); -const double t0a_7_LSB = 600; -const std::vector> SVID1_7_bit({{23,6}}); -const std::vector> DELTA_A_7_bit({{29,13}}); +const std::vector> IOD_a_7_bit({{7, 4}}); +const std::vector> WN_a_7_bit({{11, 2}}); +const std::vector> t0a_7_bit({{13, 10}}); +const int32_t t0a_7_LSB = 600; +const std::vector> SVID1_7_bit({{23, 6}}); +const std::vector> DELTA_A_7_bit({{29, 13}}); const double DELTA_A_7_LSB = TWO_N9; -const std::vector> e_7_bit({{42,11}}); +const std::vector> e_7_bit({{42, 11}}); const double e_7_LSB = TWO_N16; -const std::vector> omega_7_bit({{53,16}}); +const std::vector> omega_7_bit({{53, 16}}); const double omega_7_LSB = TWO_N15; -const std::vector> delta_i_7_bit({{69,11}}); +const std::vector> delta_i_7_bit({{69, 11}}); const double delta_i_7_LSB = TWO_N14; -const std::vector> Omega0_7_bit({{80,16}}); +const std::vector> Omega0_7_bit({{80, 16}}); const double Omega0_7_LSB = TWO_N15; -const std::vector> Omega_dot_7_bit({{96,11}}); +const std::vector> Omega_dot_7_bit({{96, 11}}); const double Omega_dot_7_LSB = TWO_N33; -const std::vector> M0_7_bit({{107,16}}); +const std::vector> M0_7_bit({{107, 16}}); const double M0_7_LSB = TWO_N15; /* Page 8 */ -const std::vector> IOD_a_8_bit({{7,4}}); -const std::vector> af0_8_bit({{11,16}}); +const std::vector> IOD_a_8_bit({{7, 4}}); +const std::vector> af0_8_bit({{11, 16}}); const double af0_8_LSB = TWO_N19; -const std::vector> af1_8_bit({{27,13}}); +const std::vector> af1_8_bit({{27, 13}}); const double af1_8_LSB = TWO_N38; -const std::vector> E5b_HS_8_bit({{40,2}}); -const std::vector> E1B_HS_8_bit({{42,2}}); -const std::vector> SVID2_8_bit({{44,6}}); -const std::vector> DELTA_A_8_bit({{50,13}}); +const std::vector> E5b_HS_8_bit({{40, 2}}); +const std::vector> E1B_HS_8_bit({{42, 2}}); +const std::vector> SVID2_8_bit({{44, 6}}); +const std::vector> DELTA_A_8_bit({{50, 13}}); const double DELTA_A_8_LSB = TWO_N9; -const std::vector> e_8_bit({{63,11}}); +const std::vector> e_8_bit({{63, 11}}); const double e_8_LSB = TWO_N16; -const std::vector> omega_8_bit({{74,16}}); +const std::vector> omega_8_bit({{74, 16}}); const double omega_8_LSB = TWO_N15; -const std::vector> delta_i_8_bit({{90,11}}); +const std::vector> delta_i_8_bit({{90, 11}}); const double delta_i_8_LSB = TWO_N14; -const std::vector> Omega0_8_bit({{101,16}}); +const std::vector> Omega0_8_bit({{101, 16}}); const double Omega0_8_LSB = TWO_N15; -const std::vector> Omega_dot_8_bit({{117,11}}); +const std::vector> Omega_dot_8_bit({{117, 11}}); const double Omega_dot_8_LSB = TWO_N33; /* Page 9 */ -const std::vector> IOD_a_9_bit({{7,4}}); -const std::vector> WN_a_9_bit({{11,2}}); -const std::vector> t0a_9_bit({{13,10}}); -const double t0a_9_LSB = 600; -const std::vector> M0_9_bit({{23,16}}); +const std::vector> IOD_a_9_bit({{7, 4}}); +const std::vector> WN_a_9_bit({{11, 2}}); +const std::vector> t0a_9_bit({{13, 10}}); +const int32_t t0a_9_LSB = 600; +const std::vector> M0_9_bit({{23, 16}}); const double M0_9_LSB = TWO_N15; -const std::vector> af0_9_bit({{39,16}}); +const std::vector> af0_9_bit({{39, 16}}); const double af0_9_LSB = TWO_N19; -const std::vector> af1_9_bit({{55,13}}); +const std::vector> af1_9_bit({{55, 13}}); const double af1_9_LSB = TWO_N38; -const std::vector> E5b_HS_9_bit({{68,2}}); -const std::vector> E1B_HS_9_bit({{70,2}}); -const std::vector> SVID3_9_bit({{72,6}}); -const std::vector> DELTA_A_9_bit({{78,13}}); +const std::vector> E5b_HS_9_bit({{68, 2}}); +const std::vector> E1B_HS_9_bit({{70, 2}}); +const std::vector> SVID3_9_bit({{72, 6}}); +const std::vector> DELTA_A_9_bit({{78, 13}}); const double DELTA_A_9_LSB = TWO_N9; -const std::vector> e_9_bit({{91,11}}); +const std::vector> e_9_bit({{91, 11}}); const double e_9_LSB = TWO_N16; -const std::vector> omega_9_bit({{102,16}}); +const std::vector> omega_9_bit({{102, 16}}); const double omega_9_LSB = TWO_N15; -const std::vector> delta_i_9_bit({{118,11}}); +const std::vector> delta_i_9_bit({{118, 11}}); const double delta_i_9_LSB = TWO_N14; /* Page 10 */ -const std::vector> IOD_a_10_bit({{7,4}}); -const std::vector> Omega0_10_bit({{11,16}}); +const std::vector> IOD_a_10_bit({{7, 4}}); +const std::vector> Omega0_10_bit({{11, 16}}); const double Omega0_10_LSB = TWO_N15; -const std::vector> Omega_dot_10_bit({{27,11}}); +const std::vector> Omega_dot_10_bit({{27, 11}}); const double Omega_dot_10_LSB = TWO_N33; -const std::vector> M0_10_bit({{38,16}}); +const std::vector> M0_10_bit({{38, 16}}); const double M0_10_LSB = TWO_N15; -const std::vector> af0_10_bit({{54,16}}); +const std::vector> af0_10_bit({{54, 16}}); const double af0_10_LSB = TWO_N19; -const std::vector> af1_10_bit({{70,13}}); +const std::vector> af1_10_bit({{70, 13}}); const double af1_10_LSB = TWO_N38; -const std::vector> E5b_HS_10_bit({{83,2}}); -const std::vector> E1B_HS_10_bit({{85,2}}); -const std::vector> A_0G_10_bit({{87,16}}); +const std::vector> E5b_HS_10_bit({{83, 2}}); +const std::vector> E1B_HS_10_bit({{85, 2}}); +const std::vector> A_0G_10_bit({{87, 16}}); const double A_0G_10_LSB = TWO_N35; -const std::vector> A_1G_10_bit({{103,12}}); +const std::vector> A_1G_10_bit({{103, 12}}); const double A_1G_10_LSB = TWO_N51; -const std::vector> t_0G_10_bit({{115,8}}); -const double t_0G_10_LSB = 3600; -const std::vector> WN_0G_10_bit({{123,6}}); +const std::vector> t_0G_10_bit({{115, 8}}); +const int32_t t_0G_10_LSB = 3600; +const std::vector> WN_0G_10_bit({{123, 6}}); /* Page 0 */ -const std::vector> Time_0_bit({{7,2}}); -const std::vector> WN_0_bit({{97,12}}); -const std::vector> TOW_0_bit({{109,20}}); +const std::vector> Time_0_bit({{7, 2}}); +const std::vector> WN_0_bit({{97, 12}}); +const std::vector> TOW_0_bit({{109, 20}}); // Galileo E1 primary codes const std::string Galileo_E1_B_PRIMARY_CODE[Galileo_E1_NUMBER_OF_CODES] = { - "F5D710130573541B9DBD4FD9E9B20A0D59D144C54BC7935539D2E75810FB51E494093A0A19DD79C70C5A98E5657AA578097777E86BCC4651CC72F2F974DC766E07AEA3D0B557EF42FF57E6A58E805358CE9257669133B18F80FDBDFB38C5524C7FB1DE079842482990DF58F72321D9201F8979EAB159B2679C9E95AA6D53456C0DF75C2B4316D1E2309216882854253A1FA60CA2C94ECE013E2A8C943341E7D9E5A8464B3AD407E0AE465C3E3DD1BE60A8C3D50F831536401E776BE02A6042FC4A27AF653F0CFC4D4D013F115310788D68CAEAD3ECCCC5330587EB3C22A1459FC8E6FCCE9CDE849A5205E70C6D66D125814D698DD0EEBFEAE52CC65C5C84EEDF207379000E169D318426516AC5D1C31F2E18A65E07AE6E33FDD724B13098B3A444688389EFBBB5EEAB588742BB083B679D42FB26FF77919EAB21DE0389D9997498F967AE05AF0F4C7E177416E18C4D5E6987ED3590690AD127D872F14A8F4903A12329732A9768F82F295BEE391879293E3A97D51435A7F03ED7FBE275F102A83202DC3DE94AF4C712E9D006D182693E9632933E6EB773880CF147B922E74539E4582F79E39723B4C80E42EDCE4C08A8D02221BAE6D17734817D5B531C0D3C1AE723911F3FFF6AAC02E97FEA69E376AF4761E6451CA61FDB2F9187642EFCD63A09AAB680770C1593EEDD4FF4293BFFD6DD2C3367E85B14A654C834B6699421A", // 01 - "96B856A629F581D1344FEF597835FE60434625D077ECF0D95FBE1155EA0431979E5AFF544AF591A332FDAEF98AB1EDD847A73F3AF15AAEE7E9A05C9D82C59EC325EF4CF264B8ADF2A8E8BA459354CB4B415CC50BF239ADBC31B3A9C87B0843CF3B9E6D646BA43F866276B053826F3A2334CC5E2EFB9F8F195B382E75EEA63F58A06B3F82A3B5C77C1800FD9498F803E524435B321210BB84690BED0BBBE16D363B3A90656A73720E27008852FB7DACC8284411B177728D9527C560859084A395A6F11A96AD9DB6B43E00642B000ED12BFD967868EAB1108552CD4FC89FBC408ACE7678C381EC91DD000319124EB5D5EF52C4CAC9AADEE2FA045C16CE492D7F43743CA77924C78696FCBF2F9F7F36D8E623752200C6FCBBD71ABBB6877F3C5D6E6740AB0389458A6B66440858B2D383244E853646FE2714211DEA9E6196252815BB704A20BFE556AC474F8998944E0CABBBE21A6400B87BFDCF937D12B2821D59298AF4AD378F0F42BD8C41693B8D993CF37C8B478F3BB5D33AD2A9FA24AD7B8FA895FDBC04964192F7BA3FF74E0E3A435B5DFE042E3115CACF29624C0645E9C917534A2EBC1F5665E4E1B1BC56208DBCD8A27CCB6474D5D0E20CA4072C960E5ACE41BDA3770DF3B681F2B318F6F8E1CB17C2857350FB6009AED665E13B2780D79217F73FAC7A8A48048DB0FB8A8A5007CDDC9A7B2DA8257C99F1CB605A18204", - "E57DE19A3E4A8C122FCB1DD6584B3D2DAE364D800F9C5A9E957B38F624CBD3ACC58FA3ED070B5E44857CCB813FBC0BB83B5D157C6C562422E5963CC4DD753C45B0264F8E136A0F1774D77A543E44D51EF8C6B9408B6E3B5CEE1347A94F13ECDC94DC764976E5A50B4CB0AE7557553B47EDFE03EC2CD32EA8D125A341E1EDFC77E75330D6E7B23DC838EBCE7E5567F5B8C80C3D15E7404B4E10F0BEB0C69626A814AF91334199864FC77E0FF548DC2A6FA6A71C3C0561F2B085CC05E8512E27B9DBA60B93D114B87935776C8E9A67905C429D48BF3AB1B0A56FAFBFD5D9C8D8C8A9E5918BFF273CF5E8664FF2B90314BDBFDAD5AB8C22A0E45C104ECE75EA43FE9BDCE306A5A28AE464628163D249D8056005F1A900951808CC8620F81768153436F741667A8E271DD986C7A1E5046FCC74C7CEBBF9A1296D6CF0B2FF85BE412D87214BB368DFF462AD649D7324A117252311C664D33E4DAFBD830FBCEB6EFBDD7391D4BADA7A775FD1949D981F619655DB3C22BAC34E5AE41222905C0C7E80D6EA28471EC0468756531C09A471EDBE200472E78F1701FEE96E5769A9893C0F11E7906B064442E06E21ED8B0D70AF288690C532A2D03B373E1E0085F62F7AAA658B569C5184E3DDC40ECAA88B887118601691892F9F55E2DE79E49DFF11D434C2BA3AA6447522A7C99DC215CAD2ED0114ED62CBDAE9D315E48AE14D2014B7F8E", - "C0FC4C72A12023BA7093C86775DF3D2F42C7CEDE616876340BE4301361B9DC9DFF4F1DEC6A62E165927BDE4F809E969AAD085437496BB95904719820F4CA8ABBA0B84C34B06DD7E268BA10E386FA7DB9FCFCDAF2B6AFBA46A8A299153B4E11582FBA7F28F0A0F9DE41830AB33335062C57D81DC361EDFE491939100FC827F36273760043D1C35B74E36C6C4DBE1D307847D55AC07D8B212C2DBA632A86AB15BD0FAFFA43070644C7E50623195A3796AA8E8D6E4E964FA0E4488A500B9063FBBFB1204A0E33C6CF2879AC2BA7C86CAB57E3E8A497836194E65C5C39B950F1AFC3B58E850A5EC39F4190D55351D16529CD52B36DF4A2DC68EE202BB758CF19C54B0E1461D547B5D06C2F9DC09C2B15458C3140860E4C6F3FE4F417FDFCEDE00F71212EE137E6669E569A7845470CA564F85CB4772808D65D2B48D409B709BD7AC5F7E28AA804CE9DAC3ABB5A5B768C6A184B5A974E933F2C1772FF64AB26BA2D5A165744E314EFB2238AC4858A8B82723DAE8865478EAA261F35DD4D98A9C07ACB0B822AFF1AD3E739CB214CE737196FEF2DD0B0D45BAC423935670BCF71C2EC04CCB98943786173C309E75A02BB78A788A5E6F8A8F407E57B8403841A9E1FCB3A7AB80D1F6529770E52C173E2C47EDED4400D5E665E325ED845C9E8D0E66FDA16B17D61EDBB336F22688C3F0FB040A55F33B65FA9F3D45F5B22C445CBF9DEB22", - "EA9596357B343DFC31D5875CC0E94117A33651472E476D3892D8112EB6CB6E0151D409C5A514DCDA38A773C58F18B590EF9017B6EDF0192AB7EB29DD6E1E7E7390C13E9B10209D5775F3B066F7B2DBB7307FB44F726DD2F368A5FDBE75BA7248762E1EC7E4589DF1A353A16D6B3CAC1C9ACDB89890ED2C4F44AFEFC763DB51D102230C37E1ED0943CD6F4176B2F5C19119588911ACF81A7A29320AD579C1BFAED1A70DEE1B87037138ADE411E0BB92F5B3148DFA11F2F84CA6C019124B922837503AA9823A97E443A66378D5CB3130A7EC9B05670E85D095D5E6F603092C632E51FD9013FE7FB9F08448FD09F1219A4744CDAF82BF9C60039C8185C7E9559FCE301C6D3F46A2E514AAD44D3889C8CB4ED7439BF47019194F2644363770F8BBD0AE92B6F5F43CBBB503A885239DA636903D4C264B3FF09AB77E3FDBA7EFC63E0792B6D5183759E57D8A694CDB133B4A9E301CEEEB978050AD9A9E410091AD29E389829E2F24BE1E3B24F4540C4A6533EBA72E8AD540BAAE43A0CB82F971F3A51DD77FE9E1956E2EE7553E050A1D10B99552DDD5B68F2E2859712835BD2AD6B08881753B4833FB04740E3364D2CD4921B939393E7EA91B854FA1E5A8EE79FF0A83F111F78435481D462E0E1CBC0C921D190A435A1BA755E4B7021244FC5E3F0630F2A1F439C02AE619393E5624834B05ED7DEDE5F0AFC7A40899424E75D4EE792", // 05 - "90E92279CD4F60D98F6E8FCB3E9263DB60FAB146A835AAC2E96B3BE3FF07119032DEE0521C731117E90C2943B389DD6B65C5E21C34F86F5A7ADE04072DFD1479EA36528D340736B0FED4F6207BE9F6CFC971D5EA11781AC2DA25DBEEB6B903EF8BB0AC0CD2E29F94B8CB67874A7B7441045758E09EA061181A50E0AB7BCCF801554E0644780BC137436E3FB7784C182856A790D6943BB53DB40D13D6A2F7B83A5C521073883B90FB8DB1C0F954D132943C09156A09984B822079FB8FD09BC07C1D6336C7CEAE8CC3162760B9838CA6A38FD0044FDF099E416D57BF9F33A551043F34EBF9BAA90901E62D2D981065F977852072F692535DDE24EE8946387B4E5B0FEFEBD75552C1FC325A608A78079A9AC864F2F30010A3304CB16A26AF98D9BFD3B8D128541190B2BBEE275A6F53B9BC5108306985ECBB983B56E34F18B48A12AEAB88271F4F780CFDFA83E05E35C12464F4350597CCAE9B4498F5A5454DCC3218D3336763674934ADCBCB5EA52891EB240C362248226DE64899BE30735F6495E94AA61ABEF62B803C57FDD045B724ED1966B6E7DFDFCA5B36F7B0FACEDAC62DE8E10B12DFC84B1A9CEB407BDE63CDB5208ABBE5E066AAF262187E94502B1701B2CC8681CB616773DA2B7AF49443CFF528F45DD7F25959836771908C2519171CAED2BCDCFCEA46301E7D99A5AF7199155772E92BAD85F35EDB656F0999EE828", - "A91F570102961D62CA6CB55144AFCCEAF3910F3336DCB029CDCBA164ADA72732771B6ECD1C58E49F468A2BFD23E1B996DABABBAF5AB3A4C74926187B5833006F8BEF7F9CD0F05A2A0B9BD9073C4C3976E8660CE7BF81634CF0B31C3DDD806A6A0C15BC552B83A86789CC675A6D137BE27BC86DF68FEC5D268119EB9E965260FE1F5C56AEF60A8622CDA8C42F24CBA7F5B07A7416917277323314AFD3ECD10F74BEE7B22DC760EFA7F935FC9963411353782547FAEED32E69A4FB5756C1A73CCDFFEDE50F4B2D9B5D2ED5C59C9A52D80CD27B989B8DAA14C569E763C08FD42358CD064B2DE0526607C9536D75E1617EC80615EF5EE2314FAC29907B61B61F8696CB80B14B3A0148EEBC825C91150A08A23FC7B38B5982AA02A18BF6E91B3A1F2EEF360F682A34AB36CAFCAD556841073F219910F7BC2F07CE45E98F77F50475DF9EDFE2DC9E3D7280193D61AB5076A14887E9D9193C3B83C5773BDECA067CA1BC3D4561C3A8B4E30072A6269B529760CA1B5FE9D3DB2B5D1202CE8B18E9E2E80FAFF47108168D3C7EB3C940B1A35A1D1B968A5A9DC0686DD8336E498C240F20871600FF995B9E33169DCFCFCB58E75C94D82F843C60A7118F0D7B40064A8A4176C5158E86AF0BE4C1D5D73D1C051132A85CC0628486AFD660502A515D6353B674B1D4E61750C13E8A3AD48FE1F89F201C288A8F443867C2BAC23C706EE7A2D2C", - "C6E00978E351164532EEA256ECBE0D4F8FCE02A276BD19666DE93936F7A242FC4C7E879791314B043ABF1D5F9B0036ED22AA92028C800C4D62BD6640431170EA77311865074D670AF2847AA47CB94584A793FA82F51574BD7C62BF14386F14A3D7DBD129FDE64EAD67EB35D5E13FF214D7D163B770D4A77A62D02D88C0FCF3FA5EC306EB7F85539105FA2CE5F53D182E58FBBC1C57CFBCD2D2F7FC8A067D6FA0BC834DAB8F370B0971BF6D068CD4D3A32C11C6598DEBBAEA046528C5EF762828CC84D003847069FA18743A809A004431E83924B8FDF0AC78699B905ACCFF82E83FDAFEC8648DF64042FC9438B261B73F0541498ACAD67D702AB631BECEF8680D33CE8F4F0CE29B95132591A350DD68B36734B97D4B3E84A76497F702312F2A8370DCF26A7C3C8EB91DD8699C48F551750712683E0397083714A6CAC3457C0FA70BB3A036C6E0BEF24E6B20BA5565B351C2EFD56BD9455FF7728BE07A097208E73DE4CD0CB4E215B4642365123CDEA419B28459D50E864B762554E7C1D7CAF73DA7D40EDEF5D824A2FE1A6CA473B07370932A8A5D441DEE3C9A60DB68E27A9D3E9C8229B44E5B434C6D18A8CADB6D17BC4614DEBEAD670C73132CE2F999C8716D1098C69277E8ECAC546EF8002E5182E25F31A354DF112E97F8733DD20893B430CD7130E69ED4A0FE4D6C2E4FA479001E42EBC9F36E5DFD3E0BE35A64B89745E", - "821BBB3FB91E50253A9E71AC379ED57AEF394C2CC59587B2D0337CE74002EEAD17AB5D504BCA68BDAE9061C3DBAE2985EBE292B9BEC9D3542015225F44ED3C2C3FFB036A515BF33DA1690F3438FD225A5034106C5F4BCC43301EEC2245D73F63038E2A7D9B8CF95A9FD813FFA071FFDE423E0CE737969578BEB909764A8D6DAA9E15A4FA0867831652C0F6E9AAA39A63F0AEEF62A433476CC7380460ECFB8B7F3B2FE8C4C42A3EF1CDB808FC9747FB4F044B3B47A4EDFCC9463ABB72C55399B2F79EE5FEDA270D6358B27F8466969DE4A5F2E6A5F2C4CF0813C09F468DC97FC0E5DD057A8A0355767B698F8A79BF0350C4200413A15E6591DE70A1B502E19FF515C3DF36935974A4764895B9E3CA2626BD39B7ADB780AAF7E2E914E804CA923089A51F3876649C73CA3C2623A8C95D11EF4B3F941E9772EBA1F47212C666F03F01509FF699F74EDE27182B6E98AF49D1BAACB41A328A8C34D6E8AA3553DA3962B27B041495F269328B6BFB4A385CBB118953F3F009920EC4C8590003290DD60AC89177BB8C4BF753CE723AECA392B8D9E5E9E4113DD062F294A77B6EA9A0477E697C04C787CE78A92C704409D37D37B6B392128698D0D8D4CA101EB38B92F467F0D86EFD8759A14162CAB55F8C457E82392790A5BDDC8DD2663944F880C95EC02FE5363B064623994EE5D4396C0E44DE2A3D225830BA6160270BCD110A942B0", - "92A0DEABA9875D4AFAF99A24C1D5F10EBBE6DEF9CAE5B0C85B2A0417C1CC5D1A5F71CD8F8A4B013C3F012C0A19EE4A23106CAB8662C5A2A93A971D0B6E487FC05BAF5C355A9520C9148584CFED3EDD0F38696E161E64378C831C586D9178A0CE289A67F33AE68C02A3CD138FA09DF1CAD01EFADFC8BF6F5407B79B18D09C82804736752D08A1FE09EB35F544E9F797EA36DB493BA947AA82513EB1615A356B5AA4308B0B4183E070EB494D628159D2D4BC3CB110AB0CCB2E9E73B5B7EB567187621E72D99F1FB78565917B28464A5F29DD8D6F98B6ED703040A44B0ACD97F15049E009E8533FDB0B6DB2F2582E6BBF81D7B0EADC8F402508F6B8531AD13FD1C55978A8A70DF4E053DD475132D348AE27581370EC14A3E0F96E0D70DA4946DEEC0760011404FDC5B436CA7419D05895F5E0EAEEBC88C74947733BE9919F18CE702887A6C4DF7C19279B82FB646090822DA9CD9C7653F6B931A337A28F7A4A01DE0CC0744F22961045F8EF8D4B30B07E5EDF5FA944EDCFB9841A9088AE82444FCB6E90B0E9C567A80E8C42EC713D78132F37AD1D2592C31C93D2EAEFF38AD94E5C0D94F949F47B88B03BC1EA4E5EC9C7D9DF19ED208B8E44FFDEB0B625F633C7DB1C826AA9E1C1309E5B14A0DDDB79714DFDCB52221CEAD7E8A140DF7806F127156478AFBEE922B8ECF322D66B48BEC434299BBB36B3BD9030467B7F2EBBDF358", // 10 - "AFA7FBAC93326D0C36A388831B99DF4D527BCE7C9070F7B46B5FFCDEB07384801AE5F86A89934DE23DFE2C1AD117797D4FA1BBA6175823B41166DBE9D126F17B3761E2C352AB396A5A9CCEA42A5E9EA1BE3497C0A5BA9121DB97F64159AAC78E62D7DEFF3BF4CF73F8CFBE045C9D39E41D5D208DCC4B47CA27E900C3CD8FD1408DC5E0F5114F2FE65817D37CD1452C4967ACAA2119FB8D60E5E2FD8A820D0AADD88B94D40435C095568AE6394D3B97C835BA868A83083316C49C75D36EFDD85165BE74A4F2B2D21295EBCE085D9C4A4758FDD9CF71B97FDF34B7B63A5E9691DBDAB834D87D5B52CA9A53032FFE821398616EA92625C2DB633E37911987083A3B49A86FC562FB1264A75643A5FB6E97162E16ACCE353227FE61A859E094C2359BC4645946AD12AE5C39C70F59EA7B597A9B3372C23AA578146781A61163C92816627DD9C4BF1788087821F9F5D41B75A0F251B06BBD3E29ABD41E72A1D48323D24E2AD6F11C2D49678CC04FCF6B0EFD33BE6DDCD444F5CA02FE158112631F782CA7B0C5F3607ED807495BF8E82C5EA51A922FE28C8168D9844859E7A3EE3038C5D1D4BB4B13406C340894DF46406836739E31D01082BC84489592DA0E985630CEC40702A36DDC301B3AE1E8101786FEDBF752F9E175287C239C18FC25795BCB479DEF59C58C373313C02A1BC5F16355E2B50EFB58855670868728B902653ED80", - "943CAEB680AA3E630755DF32F406F403D7AF5E48A710274D3887A7AAC8EA6744B889F2E0CD2033DEC0B434A9591254A0AA68C5C9BF11D35765E86B437497D84E5DCBBC0C0C580CE9BC50EC6382AD74DB02C2C233B7BB07517D48056226C505ABF2DD244F6BBAA23313D570558B065E42327768078EFDB53DC465DA038E3B216D990EE951B3E13D3C1CD559998F77BCDCD2B9522B6F1DC5E12C912EAEF574AFD69C251F9B2532501AB9F4B3B2223D0F8920BD562B0D358A14AB0D196DF6337D1C96CDB47AFEC6F81DED4B5773864DA32FCCD06B9AC53C122B2C6327E6E5EFE227DE4893FF15BBB2257FAEA836E99676EE32BF6FC14D4F56EA191B8A3870374A0867C49EB0015D1C6D07B87A36BFDD1DCEF20EA7B80D997CBE2D83EB5630F2EE6F73B0D50700C89E4F32438F5541360683DF11DA6E7A3C1E7DB2A87800D9245BF04278C990A8DC9CD86DEF39CBC6D4BC00FF13BBE132F9D86681A8913BE787CFC69C35304824788716D52DC74CEA399E06DE6241780447C74DA8E947134D8B2FAA9648D6D5F34C9D60AE5973B5BB0187796D589C8FDDD7675671F28C04AC1038D09251980683CB712F694D7C5B0D5B1DE86CD10EAC4EA04A55BA8803D78249BEF516D38067890105A23212E72879FA267A8B4F0455A81F17CFD3E5DDC55E5D4FE00F83E18626C676DAF00E6AAFCC23D209DEE0B0FC6C2AE4DE161D13017ADB5D8", - "E5E70E7837D094416558C044D758383EDF5755C80921218ABE76E51FB93249E211A38FE6D07A7DFD2263E6E3D8DA0F921A06A606B804DE7AC3FD097E5F96EFCC0F544D623FD6F43FB88CEA7C341E901CD47A7E24AB141E998FE41CA87CD6CE8C1870D9ABB6503BF7E8B659084BAF2237DFC94F35C9884C7F44B87120BFCB298696E613C1656AC4899781A94869EC603B4D38665337CA8593AAC83AD8BECE10302E4B4694237E96CCD3AD9CD5F8EC039A1D1A4210716371404C5C3FF375CB3A33559B1C1A239F2E442C8EB033501BB290434BE73489F716965393989422CF4D57E5B4F3C76AF3C5E8999E61805134B9D7C40BFB59D0D0FD30F98567E66D6148D6AA64F74A22C50AE49D6B1ECC6BB5A002ABF38FF2E2436766B86BDDE7D95DD6E02AB0FF06E7BC22CEC98D55AA2BC4D7B91C36B2FF9F525A74423498D548318509320FCCBCA582A6C2996AF6538422FF0DF060C0BC7356B0850A139AC3914338127B786F4BC58CEB6064DA881376A147DFF53C6700BD13316A5874A75D7B9713DF54FBB393BAFAAD7F7B0710C049A0B6A8B76A9956BF6185BA39D9C347D179FBB97D4FED68F47DB5AC8E0D40122EA51C4A1F88D23153DF651A180C2AD456ABD7F851B65B220A72BA48FAD0436332E4EE7EDC554B7D75481EE05C3D3453D760E9099DD27B324DD84C0C0C4DEC4C674D25284B16410F959FBD09D9DF09CE875601E", - "BFDBC82ACB4FBCD5A90C5967EB2FED597A02607F426002128AF4B38942C85AF4472B3CBF3B183F240E049B251713740A31117F108936631FD0F11C5F79325BD6677A2C2B242965AEFC147D93358730AA782491209CBE600976F56030753CC979C240A196647CD9EAB1DD0380E59BC7905EF740C3411AD9DD72027D0D3DD6DEB0F5F3C18F6D6F7BC59B758E7E262937B4599B38567C147ED2689BA2CF23736CAF55B6925827E2B70E47D3813C94C85298BD6B49C97B5D0221BE9E3164B6FA3D95AECF53AF170966090F19A69E75F188BD2556B4E8FA7DC4AC6C34F54297C06C2A96DD1C45B42E6175B5E8784568F7FEF0B6C124C5019CB577B374941E8515CCFC21F46D188BDD2C2284C688879A5BEC50CCB97FAEE1F75580577498D509D3DE161BE216C873B29E178CE17DCACC5E9E2224D05ECC842FBEAB82A75AAA20769FD81131CFB69D5E35409273CA106FFB27F63FF997CB500F161F6DD3A8BFA5719F004EC17860152D3290951678A131E4F3D3AB34CFFCAB2967ED9D8F1BB987950306BD28751D2AEAB05F071B08574EFCA01E5386E04F727BF413A8279E9392EFB64D9AEE00877C76C81EBC861E2B484A2D35E592A131726CAE61BC010B954721A82C968CC6F384D9BBB99B4E87846D10B94EE31F64846A5834DF73A67A267B894B1C06242D750F15F3E1E850A11CB2E2B16155008F91493AB3BC77CF9BE56F9DB20", - "D64F3D1CB54CDB9143D9E701BD313779C09DA064D9A85674CCB53B0C5B4446C122098961D5EFFD6A85537486D5EB26B5E18FFBFB8E6EF16C2DD2C02EC7C07DB15CE33015A636E225F744C963BF0653A89A48F1AF04819E273A3AE1F5538AD574D553C5A0DEF47B552957037BCA921970C76DDEF74BA083ED55363760A6780612C075964B083B4F674EA0012FD1DF09F0445CE75A698852098206868AD8241E3B319FA8D2D86DE6E7631DF1AEB571F9676323E0627307F6D8F569536A758DE5EDAAEDF80F4335E3AFCAD07F70AAD5CD08CCA1E71B84D4D97931F924AC0010C0811972ACAA414B89FFF7917E653BB31E9CDFC72595066C662CDB9BBC96152D46BF4E8C15A8D34809C4B9D79871BDF0B63FA294F2D667624F6E0210CD40C92F1C033C3D8BF089EF85C4F571CA727C71B23128A9B0FFD70CEA93C316FC4D69D79B089107F292E03425B2552AF5AA18FDB9AF86EA1972B66B1276B09119437E4DFB8F8E3972D91A93816EBD7D8D715CB47EFA742938B0B49FA27A291B0DEA1DF0B8F878332103F45A99936896181E51FF65C6995F57C2C54B8002DEFF54B0EB3131EE7D61030C33B5502C49CF398FEC4B7615D16FCEA3E8EA12BFB311D426331A06606CA5A066707C4AF8D1048F1CA6065FBE506D06C6C00D5D250E227265551867A6816F05155FCBDE24D4AD115BDA98AFE08B12A1F32E7C2ADA801FFB78BA05726", // 15 - "9D6AD9889EA02FC9A58949290975DB0F512EB37C8156CC9F1242B9E45F22CC1D6ED1CBCB6CB245811CE729261641FDF7A8F389BAFD7311B8BD689E02409F6E8C5202F466349EA466E5398B29C8CB126D9600D89697A07A6900FE8D95951903DAA3419839C2D9E35E9F4EABC04C9006EA585F544C7163A33D7E78DE28256B7B8978FE018CB529F7F79BBF66DC4F0DECE80AE3C2CD479D78C4480E4DE2F06C70E5FEBDFB4ECAEDC2E7BD891AD6C91A7C2446F1B13B340B7160782F6CC5B45F9787CF1B0985202DDF02EC552A6DC41325FD8D31A4316C13C56F7157134F66E1D103CC3AA7EB951C92094EB4409E6E7BC494434FAD80999D46D824A5A57390599052025F7DA4838F7D16A8DACDAFA06D175546FADD1E3F7975265230F6C01B9C1FB1B7AB1F2FDD43A5778E3C88FBEA70575CA26D94D249670E4D9FF28EC67D15829776D7BC6754D2A2BB01554E5FF0C3FAD8A1CB546E8AD5E5314103D086D14ABD30EA95DDC591C13D96C1CC3F60FD18D216B67181B6324AC09A97C0C45E50EE8380ED42F6E0430639373E7760C708248EE7D74830E9594114879748883F247D056B2BA94A0FC54CECF6F5C6AB4DCB7CFC8C224F40D886427504233DDBEDCE160DEFDFFD69EE2B75746D9CF71676DC453FD01C315ACA96373ED387B040BDEBA7FF3CE00D915F90AE6E1796971F8052160154E8986913AD7BA291188EC49A60BE27C", - "B5184F7D580935ACFF18201CE8B5D54CD0A1CACF102FBC8AADF391C4CA5807BAEEF4E5E47F7459E74485E48E0C42D27CADE6970714FD97C08F9592FDD387C859FC12C1CCCFC3EBF510D66FBD8C448C25A322CC5887F94A55D48ECA362C690F24833C3B032A047D12BDA2ADC6824A1F6EA9320BED27968E9CFBDEC60D041EF538F1740C0519003FAA89CD4224293167E05344998FD396EEF618E8F547990BC06A8B76D0FD6FAC13284601AB7191CEB813C46C45CE7B3FC09EDF08DAFE136BFBDD63E6CE7E4BCBB16C5DA68AC71A1298FD27363349A261C2F2CA8CB799E8604ADF70092BDBD6A04CB80568776A537AD1711891B251C74E42FCB095B23EEF70F167E8B4856BB7F92E3A43C79FF4437262DD70BAF9B16CBF5F10D1AD7559AB0F8CEE1B9FAD058E84FCC342D9F0D9FBE4207D40E281416506242CA1B8DAB28DE88D2D00BA21AA7FDDC25940CB29F02811F8DC6850A6A87D72CA9F3476A73649FB4A254B1204CC1261E7D512BFE7B0D0091AD5CB0FBBB765FB5AFDFAB0D701941DA54832FE8253BC0CF61924BCA2CA231A196C7C32A350AC9A5FA2884D8571FEEEDB7D29632E71898BB62B5E4E0104F73AA6A9C6B8CDA816872805D75ECA64F961641077B259C9D39E2F3CCD9FCFB1E6B6E2692EA34336A967E587F32E49B961B91311198A204D11874B4BEBC6C04DDB5B82D5B741D3CEDC03A56A2017B3D2C4FBBD4", - "CFDD6B78AEB21CDCD6AF8C349F6DF8FF8B96BC8246A672A16E45B5D0AB7D992570EC45A534B77F204039FE200D4C5E7C78FE24941F578097B216177D8AD4E1844B2E52D843256D0BE8504CF2D5B639E2CD501A6FE39B8AA7DB7DEA924B38692E43195DB7E5F25E25152DF0FB7E0D4EF63F99CD95F699E16576702B651C29583645070011B2A1F88C947BAE7C94D48EB07A132DB38D4FE2B77EEAFB31AFB442710BD0AE4E6102DA69A454517B6F148D97DBFBAC7305979B5D74D7D7568A0CA56CA89F23D8330261025CC741F9D7A4BDB356B544C68C89CCC2C125F5C71E18C4EA102343AE4A44F6FC695810E6F28C86BF53F4C8B8AAE46DF6006B1679EBEA790266D4D02A2095074ADA634EE60C7070285C316E1F191BC5A88B80D673F144D65B870A65FC93D8B4BB29B80FD58F9FE95F5994878308CAC5394781E4D5A3F5EA2A8ED834EE5BD31D2058C843F22EB778C4C25144193DAA65F9B57AEC4A344713E9EDF913F3CD29196B42E71BB182AC3B1A60AFDBF1112A86A20BFC1D28D3E0DBBABF38E8F12651C207C951654FE8C4CECB6C6F93EC46456DAFFD7320DEC8D08F2F712CEB4D82407D61CC47B333F69310C06EE1FB5ED84F83945F05D4A87CF5A68D78B5536880DE3443E804040E599BC5837E22150C93CC1E5E711F9B889C78C6FF882D80857EF41ABC5F12E99105E6C894EC0B796E0A645780341CBD039E8C6EE", - "ABA759AE16B9D8778FAC203FADF48015331D6499B8CD74BD71ABEBD3E53ED90625E3057EA47BE587600F308D38743A686EF6FA189A4D86E4A35EB798FD2307345FBD10FA701265F6417603365FCC4CE7635924428167115BA372294C27A23CE6C27C506603C5A6618A2B3344BAC50AB7FDC29D36BCBDFCE0D48D088EFD8EA1DE492C543093C30AB7694627C01B334CE3368AEB4BB3267EBB1096450BDFC2571977D7EF78D6E288FCE0388A041838EC2031248F5FD659C70180634A1DC7196C8D9111C75B51C50F854CEC63DEBF9FFE1AB9406735EC3187276DE7CA2FAD4287027956C93B8E84B7C0C3A9C3F7E82B3DB35EB6D2CEBDFE0708FEDD764C839954F2CC9044B652D0A01D28BD6B9D3DD9740CAE39AA52597FFC1227FAD8B78EAFFC31BE94A632A1AA7A60AA5A9E090DA2B62F6DBDFDC50DF6EBE1D9949619FE9B2302248D6C801DD2D6C01FF8206A93C0AD22C6990C4EECA7D4BDF36C3246A5D2D2B3982C608E6AD6BDD85C92682EBDC9E4117F8B7F841239C2A5AD7977E11E4E9CA73A55859EADF7C9C2F1B28A6B4AC7202019230063331FC5586756CEA1F8478173A0A4964D00C1AC099590152125A4D01592C54DC2555E1BA34C7AC039394D1979AEA2BF7B2B2A8CB9D62E89132CE9E3B325F023AC6E8117CE57AD4B271EFB0C172FBFF8FA6A17A490B67CA7B15F865A8AEEF37651A622390E82AFD418C7AFD48", - "CEA29601B96AD3A831646922000BBFF02C014A9136D9A151A0E61A51F9FC2EC0C3A8F4C83E64BDE569A33B4CD653C1345B7CBEA3B3AC0411B6145727B1DBF6066ABCE9DAA8B0DE58ADC2510C02C2619A542A139FA3EF7A03AD3467345D9573C107A13E7FCD43C0D51DB5EC1A09D409DA75462F9C71F0C9E36C2742C279C910F07CFC5CF7F98AD48D67232A2DF29A66B78209557357A4BC91922D4195DA9533CD3501F388AF6EE2BB3AD08BC7D53015059988F5B9BF7824D066DCBDC61CA588DCCF0EBDE4A96632DBA22CA0D770C61A1DD66EDA882D02C5FA284798E12296E89C45906D315EFDBA816FD869DF869A65DD8BA4E0B13C441EEB052EF3D0FD436E4AC68EFC749E0CF4C7E15599D5514E136ABD134BA638A02E9EC1FE66CC9ACBCE5082C8734196BADC21F4DA7621D9FA725362C411127836A26CB44CB3851D53C599B94A5E67862665D7092C43D9B4AD3FE20B8AFACCEDE920F440F3BF5552CFAFAD04A7D7E0A9CEA18D497282D44778FB7D5072832C0B77C4C51F4DCFD7AC07DC7A9863DB8A38F1C003CB852F6119BE801AD12B8BC7393B00640F125C734447DB2FD8B02F7F7FC7A23B84FB80F9CC08E3EF888634FFB6F51ECEE9B20A89941FBF2B49314DBDD67CB7A1B5BD8D629FA327AF2CBB47B5419A0A8CB807D30152FA560690DBAC49D6B043D5BC9D51E82C3B1CF4ED69E997050C65197F3D93E21CBE91E", // 20 - "D358BFC8C6AD1DC94E71D1F5D05589424275875AF8CDA2ABCC6404D6FCB7A2E0A74C68024827E02621C10CD5FB149FBA373AE32DFFF275CF386C3D7A04E3FE10B6F1A6F4782B4823242F29672E847CCE760BA005D6852A3459E7576A254B10A9A78A9F8112BEA39BA65898CFED1179D68211D98E6950ED06399E39433ACD898E2F6C87F5FB9D99518EF36429D447B0EF0C5B7D834ACFA388578BDF60D4B1FB5A0CEE7D1D613BB9B99E36DC9636E70A543BA6BF0B3A448DBDF80469494239D4B7C4979D82E80C08EF36EA67560C86665D458040CE31BA009BCDC30CCBAC50259E4485E570F190613CB010563F6BD24C2F1CF73F6A6844AB8350D23BBC3D1361E73DCE94AF83697BB817BA366C9855A754EFC2F007D99A964125682E6F5CF7FBBF687D221B5A0FD844477A2F87D5370F4469F76073A93AEF7812275FD4F70B2040C12A83ADE5E5D862684D119DCA0F75AE2B56C794968A68566291B731579A1055A84F083B3072B7BD5AC9D520F64F0829B592875613BDD81C11622B331289C98501B01EE1D813C0E97CF36878260F80BF88071D258B9DE02F3F90B4C12BB56CBC731550B5EFDE6D97A1283EEFE61CD6E5DF312D0F0153A32DD65B143EC6A3F2B64E2B8FFB47EAE46BD92A6EB9ACBDD11A2D730D027A3EDEADBA5965198FD59BBC8574B680B96AD48586E5B17625251BF4374E28C6AB956C6818183FDC119499E", - "FE69433233B6067B0EACF1F47BD3AAD9783FA30F684110D1152459233896479D08A976B853E4B7B52A34511239961048B7C1B9009095327C86F2EA291FAC1734ED2596EF19D04528F3D8F2A3430A0C19DA6A70A37DB6DC034BA0053B57ACB9E7C00ED9BD6AC11339EA169D9D54E6739B051AF40EE79A1034D6294261E1AFFCD61B9CA5016C56B2D1172D9B2A7283E4EE0A06C8149E5A2DAA263A5D2429C2B1FCE75C41887DD02E056EF8724645FEC6FE7FC1EF180529B1E894773CF3E2E1D938EFE9CD824D91454116797F5A84746537FED5F0EBF0583C8508EA0745B4989954EBC4F215BE3D515687BCDD5DFDAB9814358B07038E0CB869A8C34F916FC67773191679C60A15A0A399E224D0B0168439386C0AEE8F5EF77185AC847A66D934CB0ED6A3467C3B386BA7F115877F36B49E111DE49E409468F343A98974F4EF1EEEDD282F73013EC2727518DB46C6751A58AE3E0D5F9D2B966D4465BC5595BC31B2712AE1E1BF9915CC0E02CA7240EBB9A045F959E77DFCDADAB6248D58B47BBEF3C775DEFD629A2EED15201A21ADCA470B1AD3084924FABCDAB6B12FA6201E2A239AE8F1BCD7CC39FEC62587E58C84AAC15935D45261E3AFEB60016AFA0902DB98DCFE586513FF70EF4E3F47773635D475754A158FACC9C470921FB0186BD6EEDEFCBEE9C803118851F82CACBF8C0A544B0562E2E27286CEA5FBAF83AA5C1F97A", - "C7386F9FF39FDDBFEB223AD8B856EA2E7F3AFEDE197A61F183FF7DF2FD6DE208E71E6E1063FB3774B696913524F7488EFC2CA54E8B653EF5BCB7A8F4994E312DCEE99A316C2ABF3FDF85B8FA9BBD4366ABBD7B3D3D433C14710A95EBB3D0FCDA2D37A443D62A8361DA78ACA781CEC04542D01DE7B6C6D14CDD4EA709264251D46C42AAF404094286DA5BFF8E81FA2F8C54B172821054F4CED82287F29EA3D3AA798C9CF5C5A909B9FBA641A8D9E310248B0F9A1375CE4DAA98EB62286B4EF4DFC58B877A73D017B17AFD7F1F58D3D2CAD3B7AF2F06699B08B88FB4EB70D2511190158BB4928ED1735C94400980144EF9ED06E06074E2F29325C1AA316A46E8E617B3CE916CFCF05A389052DE120498341EE26A27A3D757AAE763046B8CBC841350292F06AFF97C9707CE5561F5C119E2FF6C137094F62573EB80DC13862797C3319158DDD465FBC033CAD81BFBBBB54D9467599D751B9980A9AE8BFC6715C5EA74859E6A10DB369D5DF83A92655A9A5908228B33B36F55DE563005B886EB324CEC4160F0D18938E9FE41D39234C29E13B814DDCD13CA6450774800924B0848735C5DE076F66EDC973FC83B13938811CD9887371470AC5DD985481185F1191EA8C1D3A7DC65E1E82E2318D0FF0C9AF65EA1515DDC536C5A8BD0AF481789838DA54A39BA56D014E12242600AC78D28ADAC3FFD3600E896445868064D1D2ACF22E", - "BF5202D3599D2DDAAE5F526B6B6AC469D4BA0D0BA5D79B1DB89173320F0EB68F5D9DA495AA0981F8022426F68519B548B19B5F8CF068A6CA1442AF77C83B7D8649DC281BF438F9576F7A719A902A860B9ECE9AE9C14B98859B282010A5DC90DCE612AFEFD44E0E9E7666A461AE50C2656BC036648B826CA9C3C7C53B30976335B097C19390716A41FD437A2098BCFA2B2975F1EAE5BDBB8192024C20136D2542FD89FB8F2F94C08F765109279BC4E511787496233F15F52D7C3BC3E98A6DC39AFA1818B9533EDE72FDAF021E2C9B7D6C74E49B849F372B1A131F4C532DBE3B63635E0E1334C87DDB6F3D73883D2B43E87CF19E40D6B404E581E807E6EC1A94F5261C7F7EFD4CF043C90A1A7E97465022ABAA1DC21588FD285E7158FD9B67EC5FE7C9E84029E961E045EB5227E4726154F4F057FA337BB20DDA25D11632A7995B810764084EBDE01AF07372EA82FBAFE0434401FCFE05CE8FE3C20C01ACF4E9B8EAF4D50C73D5C42A95526CDC8313DBCA6ECEACB457D9673565A1CC0AAE23FD6261A8943E8FB84CCEC676601A4B302A9CACDEC8998EDC847A53B3CB0E12C8B4A7897D5680CB14A3D11BDBF4826C3938EBEEFA0075B6494CC714D3C0DDA2F5F783CF23AD2D2545C899867C1115BF4A4F559F63E68098955550BFA1EF7771598EF86A08C0C634B291674BB77615121BF0838DA96D6E7C53BFE6A58A382FD9721CC", - "BF8903A3918B3FDC06CAB4EF675F7BE3962CD7E3C6ED643386EE533C3B24A3D94D2EA2CFB83F0A346FF2875DB07BA647492D47A807E7FD9717CF12BC97B3C1BE1361E598850B39D50CF7BE700507863BC4BBF26620FAC11D97128049BD96C5E09DC8FF3F62655D660FE66D31AB0B0F6D4F8420E3D2E633C571D7FE2AF1CB4E3BEE95E092B00EFD2796A3DEF376F75B7EFCBB141337D81AE52939D87956C41B1E42C1CCA4317D31AB4F53DC9502A3DC774E05E1ED5008CD931DDDB98DFA69960A6ACD45B60895C4FBA2BDAE8BC7DB8C821697558B1E0A3111F156738409FD180C5A4A33B24C5EE4991B84133CE9AC089724D62DA9D9827A2A04FC103652F216A0895E78A96086270814C2699F475CEFD6359428D8C505BBE8C1A96D2793802219144CA6B3EDB455929B39A3E9F3AB74D685608CE3F301FE38202ADFEF529CCFF46AF36DC24956A7CD07CEBA55AA4C89F7913A8A4B844FD8F152C8A823CB9888E3BFEA97D7E4AAFA07125DA4F51D974A5DAFF0045BCE5B868177A91BD932963451EE2673A85AA8B7D493BDF25BCC2F64AEC3150D8C40C835AB4F5D0B7F259DF099BD6FA9F5CB198B61018B1448035CCD34E7E7A2138F437490026050BBE3CE2D4CF4F4F095CB97548E5731A338CB3903519D6B13A029727F047A7D00904A556C883745410360FC878F77707A716D549ACD6A70A18F9EE0AA8A6EE2080608E10AC", // 25 - "F58CDE0EFE2356F429B0F2F9A7869A4142A6173188DD75B570F1D1ECD282E4AFBAD11370C5B4CCF3C98535D27D73C0111F11A84711F732441EAECAB684F2F0D7FD4FC4070749574922A906E84B3350CDE5957DC388FDA23BF45F05951A393DA253EAF691940897B57ACE655E9630F09856E76958D6BF7B830E0CB8182AE226F39D48036C867BEFA7E7ADBAD17C1AB45297C757DA4AFFBAE677B05677D60DE1D975A4F3D7EB3461B424B67B61025AAC257A69FF720CB9DAC007C50C69A7ACDBBCE210BAD4DC2E629A039D98E7EA037A5C344B5CAEDCDA035F28677A41D55A0E3E6E480CCB12B8F17062A983F4E651B4F7CB217FD06BE46747CD5418C0C81916465A4F5660152B3E4781DA8040D4246F9BC47366BF663CF9DA3BB247D9238873CCDC6FC62D1D8F669EFBA42527112FF4072262F7E65AEAC328871DDF47588A0A0DD13A4139F4145822A5917F624B881BFC354F37B6D59C566823F629A21C973324F7167BC39FBD2C121D2A849308D13DA1A28948EB59F7DE97E364223E17A30119BBC7F43E21E7DC3093F7505055ADAB4654194A77C1CCB61898840125455A275A8F071273D8C13934915D379CC603657D99CE4075C1F1DCAB60B6BD62ABA1A10B5402A59706798002EF30ADED2F354E38CE0B57900FDAD31E7F684E53D097B4313DB552EA66F6D337F29594470D3DC0BC6CD361831251004DD3C5357BC0BECFE", - "D9086F7C272AA317C64C00AF43C924DB5DAC97F8EE3ED2296252FC4756FCE6928BB009D4488B9BAB757411BBA52BA6F61AF1181CC7BBA94257593FA1BD26D52AD5014C3F1A1832FC4F7445C8BBB77C8FD31C88F0C5D4736D49DCDFBEEF2B8301E31185793BFF87CFD9E6F7E084D343AB98BA3518A87A5F915BC0D76B01AF7DC1CE45F1C5280BD39D3E3D94D0A0286F8BD9FA942849664E08F2BE0B93C6E3B89061193FADA0FA9485F62CA87F3E68E204186EF1187642D651162E4D8E7DA049F462362D8C94539CAAD09AE4768C96ED6C2CAB8025EBB6901CBB26865E1F19FA1B193D47ECE390B881233578950175C85B928582D5B439EEF2F56A8C7EA09278E47741051223AC182456C4FA04D025BDB33FA10C48C70EC91BC709E3CB0FA3E01DCE5FE5ECB9018130A8DE5D0583EDD68EA2EF227A612748B2F785A30A01014BD479DEC6256C8AD88470F79DE0E1432CAE448DD7049E5B7D4DF3C978F65E708CA3759AAB9D329C11FAD71204E1E92322E3EA1BBDD9D034E2A23ACAFA21CF490AA5E2E419197DBE990667BCF277ED61B264632F694392EF52F0A27C38E478257AEC8D2542938BF0713EBE60779C95A0EEC8F32A5202A849CEE8CE0F99702F595AEA839531D4CFB5F5A6166B06EB64387552A1F9BC6BB97B9B99D19C3D2E1E8E9B305D525E7413496E40FF50CF77D4D4E2D41B1D5929848FB2F1FDDA5A39DEA0546", - "AE4E3B30560A50DA55AB3E59FFF512844A2700D2D763D85D5C3FD8CFEFACD4D023BD926D3EF2E55EB1B3831F2276EB07E5C07B44FD7D79333699BED0804B678915FE0F092DA9A62F69CB020DA21932F9FDF9AF332E1B400C6B7E7880508E840D62FBA07E827A23A2575AE68E15AC444A1CE35DF3C3F7CA49DEF2966DF3BA89C8E90ED5E2421A6407F2EC51A3E92A3608FCBD6AD9FF9E5C7817E79A0C09FE9014F7AC291448263E4346CBC4BAA6EABFB59B4526B654070084F52B864F9769181DC6EA91B576956397CE55CCDDBE41F94E5DC366E775C86ADB1C807B66D08696A2BEE45B90E8736469A371F05929D9D9FD34980DE08E00BDE2CD0EAB6AF2165D76519F8F2D894AC70740D2372B37407BDA4D943EDF1CBD35CCE4D81340CC97751C568731C009DF65571F28B7F58106AE67279E83C3A0C130DE0C5B6C99117099548661D290C4CAF3BC60EF719E2F7B210FCD4381C33904AFDF96DC3A6557B42B6EE895B4D604F5F8985F454C51E32B2C874E90926CBC58D044D483D6D2A7C26C7AC4D190531F79993D07B2E830FEB99BFDB00AE8C008DB1B762F3F4A81D41295FDDA37F3056B1110D4F0CF385F9FCC7E14C34F6752A2FB17F5CD3FC4AF0D51E4A0AF7D28DB0D4D651156189209480054F8287266B1CB26C9E8CACAA0BE5A69C696300025D160F9DA29F9EC79838941459B7B8164AAD95577A0C532EC2EDB35250", - "9CF0CC00B5788DD743A5F33D87E8FA5733B72EDBCD61AA4B8D0B81213DB52E7EF17AE90934F5EC0711ADD19E881CC330F696179C1BA464FFE6D7B04EEC383A4106BE5892C5DD1BD719AB3739A909A384FACA455E6AF96600AC6FF809788700DD2AB93DD228483759BD903EC002D4C1278808B764F018E3B740EFD821A61F5BEA2948A653041FB31F6D5D0DE0A045DA366E44112C820FD7FA966B2CCFD5A6816AF84DC0A3EEB8F9D2F0A912586F91D50B1AE3D930A680A8FB7435B6875ED2E599B87598A7C20245296C4965E2E0CF372B6ED1219BA68CB646D3E73D52665AAF2E3D1C4DE8D264578299B166FA0E148281C877FA9B14818759CBF7FF575307E80B73933599D94EAD2FB1C08A30006330BF0AC1F1C0A4EE6B07F9F3381AD7E2E469E8DA9C2D22CFC0A208B58924D2F994AFC0268EFE206E0A9EB79BB51CA26FB49013B9A17017E0C08F9FFC6C319BB1B5AE41771443BC670EEB91D7769F9890A9B80F52CB0167EAAF850FAF2A52B74ABB1792E7CEFF68C0D38B01F244AC0CC0EF0731E3BDDCDAB89DF376973A7ED5D4264EE82C334671FCD39ECD6E2CF869493914F332767BBE461707166A9164776D29F5EC9291F505AF291254D7319AA594B5F397D5BDF00BB840C4DDCB425F4325ED8AB77E57BECA3441B89414616671692EA88A89D2690A4B5FE958F990BD84A3884A60FADD5DA57EDF01865F85829195460", - "B85B6E754CC8F6805A8A19DA104418D9C134C8B0DBCFD5DAAF5A71BC047A73BEDBC192A453674BC624959BB76E44C5B34244D4736ED3F0F3C9658FEC0DA5437E01E128795EDD7593D636CD73FC1780B37A381502633CCF2EFDA0BBB494C1D0FC7F602DF8C282F55E3828E81A92458EB16B74835040D8A9C8F2DDF180A617B0592344B4373E1B526C9706B843B0CED4D25D7324C6FDD0F33133C00443638E6249061C56A116CEC7822F4512AFAEE52CE8F94D8547F72612EA8C7D160C65FA3BCC92BE01493706EC4E5F203F0BF85C52F417BAF8AF490E50133505685CE63AC5B173E07D8DABB2D439C6DC18B41B9CF37D02C92AB5C2F27EC83AB6B2DDCB7ABCEA30A95BBC39E9FD0CBB28118823F7D0342F1EB7B45FA6BB3A50223D0D7B14E975E7658352BC9288B48AF1346955F4551F2ECA47D423EFC63D20681057E5EF234D061A5E6E234ED01F3DF223A0E8B4DEDDC552C7DC3ECF663D5011FC907EB4A7CF746AB9E07C2929B7427DFE9E00B0A1308881912635A72EA99927F343EBAD32436A9B8EB1934AC29E79BB80AB3ED9F5CE39D1E43C251564654365DA43FB8A0FBA27F2328D82445A1EAAED67B92716147E859064AC326A42DC7880DE82FA782AFFF9C59FBDCE088746F8CEDBA288BC8C2C4B458782CC9BE63A86168B671BE99A09F2217B7BB2A7BC88651C1BCE8A0B89316ABFE72B22722273AF570974D8EDEE4", // 30 - "DD40DD438251E401FC926CC6968393415D52D521A5BB34D4272D6BC7B5431062B35112CA709C0680CBB18EEE053AAD62B2391C9E9D580562541A453ED936CE8E88DFA61A88CA3BEE66CFFF801785CCE863ED9C36A04D2DC8742A81CA55127B44314AB4E687ED921B4881CB363AFB3CCE7EB774E3205D4591939ED7D3C0C508A31786421F49669E120F01D35D467B40F85F2454F13F591F3B830937421B5C8A6C20EA878971AEC941FD99CEA92FEE00E5DC2264987DBC549EFF3E4A26AF0CAD7421C4256D107A3E8908F67450960E4E41FD7E2E84F754BAC81C8F5F1D6F650DEB3E6EFF6059836643209E3880D7BDA701869208D8E4BC8D0614066414DB3F93D6EA187950285F55BB7A1B026EA4BFCAB4671B07704828D5CBF9730EFC99E68E91F1FE9664DFA73297F2D6BD9497DE04982C9FF3730BB6FC3EA2053B3F45DC7FB587BA19B3C6B7E780EA5F25B45BB727174D4CD3B401FE1906360BF0B15DB13B62752F82EC62226AABC83C1C26376F8366BB849DDB65958AD969B25654DEF1841518993033AF47EABEE3CAAA936F19E28A205F3CDDB5CAC649DB6A90483ACB63A24EA46D397508EEB5DA94E9C883EB0451D036E28CC303D52B1BB31FFF582605F340D449508959ED1FE2FF0BD22FDF77F9680D6B5647D59E7E6A003AF0C6A95092F0DE43D1252EA6DE00F288BCCE3ED9CE273DCB4F3BA7E8D17353B8ECA24F03A", - "FE38B1ACA366B4C15F3FDD4DF0E0274FBEFDA0042BB203A4F6627ED9E29F405379B2F2DDC0F3B02A0CA70A9499F3CE82B87603FAA347B7052CB5D13D9DE84C114EF3B8F62418FB1F3E374B997127667FD6BCA2E2F9DBC04ECA9D908CD37C62F08EEA6F44B3FDC149465AA8037D65A6C8B9B8B3D5E9A40578E5EA3AE1209BA49E5E2AC615C59A2D71AC1605B98E39A5E66A890754C7D1C07E06DE78632587BADAF7FAAB0A529AB791095DB0A708B691E9D81F2CEA8F07B05495528B9FD56F77A4C8209DB972FAADD9791BA59F47C06F241F50C0619FC04F8456339E0AF331310FA4DCCBEA0E5DC2795CA6B3ADD0174AE4B30AC0428320ACEAFF68F73ED11DC1BC9F0237BDC75F7F48BE518EB3305CF2BB898B329716FC9ECF7E99B510B3309808735FD0A77B15731C233998F9ECEF46E2CAA6E6EDC8D05B943ABD17027A80D636E535038FAE44D60AAEC5406A372D62479192FA84D844520C6774CC589FEE16A3A5549495D968AABAABFE4DB94F5AE0C54E603D6DA5C3056769A064890533EA8EA1E5D1CD410CC8DD4B1D7E0F5F787232439AA4B3911C5DC792ECB873E8105A1AA61C627BE57E809C6863073E1E19AD8B987DE97D88A817FB43ADBB7751E36D1F0E7B70B3759D6EA8F2350D10AF38C331E22703B2B5103C908E1D35A8E814E45BAE81DCA0530FC3525CD640548245C259738E749E195B006081A18C45475F906", - "961408BD52EA1C6A9F340D9109B2388CC358BBA2D35BB6AB672A9C16F3AF968BE4613BA6B13D115B896BE71CFEC4A4AFC0BF5D2BB1B5DC19405F40E60FDF361E6CC362CDC28B75B8C30B468D3BBB77F3FC62869FBB635A3F7AEA63420CF1B80A4B3813B2240B83ECE999808E1394DA2881DE2DE62C870EC163AD8D81495DBE2C7383B78E19AC506AED9F3BD1280A77F2D9C55600BFA258E76761391145D45F74253C6E14BAE16179884F0F0EEF8150A445BE1B5AA4FEDC2198CC39763A3DB473C1CC4263CE2DD587447DDA6BD0A496E8DF60859CFCDAFED2EEC5B1E77E68F449ECF129AA17395BA39392EB610DF45134571BBCBB26162C83FFE77D188160EBCF598EF6F092881612A04BA9F4215D429BB521E737F6C3048B5D95B20AC37F79AA99A12CD0469268228463C317A1F31E63E4754890F20B4516D179342A76201402BC0DB2AD091A70B4232473343FE9E0002E59044C5F3B6E3D7368DB7E7F9F42E7A4A1942B1161552C5C84390197A54079F570B57E8EA8A30659FF5A61048142E4368D5542B968966E54DBF91D3970B9A3A278B951D6F914246FA5CCCC20DE53713D4830AA86D758ADA7A8747FCD455B2C320FF9E5E7FE1CCCFD6F7928884FC0B35F34118B4E7E6F6A5D6E3FB4E3DF90CEEBCEEF9D7D595A4C456C373C5356EF0DB0E6F8D61E413F80E4C32532BAA39170AAE2FC606B7206C379C4155031AF918", - "E03A069F63220109A77232F2BAF29D345737AAFED2E5E8D5C846B937277DC88392DB2D55073CE063F5FFC5717BB89B481B8C86EC01808A85ADD78517CE12DF776CD3F02D948BA795215599CFCCD9B4FE56DD681A59C71D24946225171DC18E47BFA9068302BA428929790EE62306C5FC8C10E71F6F372105C9421A563A4DA704E01FFD71E46B28C6EE1B7CDF95BCA6A794E8CFCB6BCA6AFBB67DED5C1267A12A4752176C3C1E6C2F665194C7F11C1CE6CC8481A5A966719B57124CA33D8EC9862AE5485788106562A0BEBD3980AFC4469BB1FD1653678192B3022E26CE8788C68F202D506DF098D49EBAFF7741CA96A02BD68BFC4FDBE24D34770FBBF8EAD9647C911B2E6AA705F0236301162CD2B41B88BDCFC2A79EC54698276126D6EC0213931609985224BF515AD3221FB5E8A1C4CECD51DB4AFF612157ABA6640866DC6D3602C446B8C6EAEF359BC8703D5EF9FE8EC7F5F2685C53924C6F1F71519E0AB589EEFB393A12C06B906402FE0A2FBD793272BC101D3B57F10A52C172E505B74F2A00BD5D2F7C7EA2883908434C125969A62F1B09F42E578BE22C08E88B11767D97C4C0CBD2BBD98508AFD591EB0B0C846A95FB72159E561F9D87DB446E9A19AF378B6DB4DCCB49FF8DB547B3040FFD0171B87245CF73A0747287B6FA1F1E4AE99518E8C53DBEEA942AFEF75B69E4790D75CC8A5181C609BEFAB641E28C07082", - "D8D7DD9242E54C6DCDB2A717A6F33226A94D5794FA0BDC401F4ED842A5CFA4AAB462F703239F684DB9B95E5101A5DC6067C7062AED9259CDB2067BC815C157A7E150F8557C3A54DDDAE94E5C569A1E09C383A062B601F920EF4D957F4BCA8E329123BD6FDC3B731361864CC139EBE3C68FED0F40FB127D9D1DC071DFA1552ABC6703494A632AA1314984A2D4B7A8BB32C555B79DEE013A66745AE15E8E5E4E129E44A119203425F2ABF1F03CE9CB33C0BDC3285ADFAAF4D7B51EC31F02D1E654BB10F0CD97EC3E389CAA34398166B4D5C9FCBC6E957FFEC9CEE4071F90EE2926FACC8FDE884CC6FF1F6EF1D3CC681FB44E45C5CF681AAD13226DFE19E22CE81265F3088D193EDB098988B2640EBD8D9D66708E1E9880DC41A72FD3D64792B14AA18C13E371CA17FB46B21DA9C59FFA2FD075852D42E2A578744792EC02F9A35F869912BBB44DCC648CE6075DBDF457A9AA891488A5450FC719778739AF323E87F9633E621B404F70614F77C65697E71F281675C843C523740AB66756E4DA784F555B5B4D797A06A0AFD35A69DEEA6E948B9B3C2A62D7B1D56832D9CCF56F2680A5A0A3037F4E0252413FB86520F2815C8824975634C0889A486963A2C874638559E14F780A7F3E2318B88B2C2010174150AFD4BECE2C5FF2D37BC2FF791F4A3136E19C373FCF03E471DFCCED19471182A93E91ED3EA68C402234AB2B00ECF62", // 35 - "87F0D84B811E4635AE8023B74306DE789ADDF1CABAF5F47885CF7F9A33F2C533093A339EB0D5E05C0763A215459CFF0D31CA92573EF2074CE2B6A11FDD6BAA3C6FA100D23A9AA413BAAFDA22F746CF74562F9DB0EF2F7CDF266142F177681CF2EF388E2E9AA012459ECCA332B779E48CA44E536082D59C3951ECA42F66B600D2621BF5F3584B59DC0DB76EC66ED7D00E943BFDE703E7D5050A8F263366948253B3576311CE88B463791DFA6F401ABDCFD7FA44B158AA97EF1CFD7A8802662A633EED958052DEDB12A6FB353BF2224ECC2322937DE3D39DCF82650B18FC0BC2BCB8CC456141C9F3FB09A0906AC1EB77E50E8D260041E4B3FF4BF3A53F7EB62E0FC503E8E38F185AF795F67FCE17665AEE29BD0D5521024A70B61446CA4CD2B3DC274FBE72A9AE29EF67A2217D6CC81BD8831B5160E4E81238B379B657FFB49023B040B6D504B287F684A0A0C07304E6BFA21E8D0A7629BA32F3F2BC9A33DEE2EAC1A2C22462EA0D24162543945B78FB6E26B86E12621588735B32A4F9A50157F20BDB7A4B6D151B3F28B40A03CFEB3CCA635261ADA2295B74947F1B1D676F6C014AB362C1F5AEBB439DB137D034D00591235B6F8D11C735A0C1964B29D3002D5243374628FB488A04EF245E64F598EB6ACBDE8B87F2FC5D1ACD105460C26BC6E1C7DCEC2E92E33F722E0A613A86356343EB111D0B166AFEC5C7A44B81A607A24", - "DDEC47E0FE3E2F4205206CD673EC66D7435E8BD4A523A8681ED77F51453B904E4468C70C2224C5F1D01A1C5ACA89BCD72673F82955FACFDDC4DA499EFD8D18A2BCC5035B0C69D095AE0EF1AFDC389B6253BD6FC83D3C37E809EE732A87D065207684332CBB9BB0519CFF51B553B3689246EC1EA42E236773A5AC4A7BCD37381615F78A41E5B181AF5C502E22FE79436D6EEC07F7FFAA739356CD9544C7DDBC42C56BB1C965441903962703986C93C6F8135A8EC42A89DCB46E754EF5B5250E1171398FD31793594831B0775F2A39E63FAD99929A0F257ADF332C078B0B7E209229ADA46D69512FF2DE930F962B8F81EEFCFDD358FEF8E4DA0D49F39C43AE9D99D8052FCD60305FF4D9FD4CAAA3FA6BF258B867E3F266F1BCC77390D02132E370AC79B34FB37F12D102985950FA5FD53D3D4783DA5B284494EBFAB51DE6CE259E27712A0EB4D78EFD6573A03D629F29166B902795FC8DF59050C9FA48584F0EB69293C7FACEA8972098E1367D183C0B91C3550852AEE6721A84341612E820CA4F53C71A51774134923FA00FAFD84811C07620917C1966F6A26A032B125D76BFA149FD66EBD18F7536285CF94A8A750680D6BE0F4A4E7F2433018796A358CE465E7507F186752EA2FFB01941902129936F7B18321902780E2C6A5EA7D3607227D6315C570815BD0E808EAE242B554824ABAF30614CC72B74E647D5B5A6306632E", - "DB29CD5101A3FB7A651BAB94E0CEF2BF737BBEBF0F755AA42F1C0B2E6A2E00422458CD8E2244576F139E811B2469E1B8F10FD95A988FCF872607A9B5CF81EB5875C427515D8D6D4FC58F3C69A92AB4932ED3D1CE6191E648276AD746F12A0D7B1ACE96B80CD2C3B99BD1094ED29F7020121076A6E6D5D750C39633B00F3DCB4793A27B4838C492EFCFDF94D955ED33814C954FFE8B8D29A81C3C62BB2E95ECB393F06EBAB479494628027CD02E59F1AA32F78C53142137965E662DF4B3EEB0B92A6FEBDC91F8B31D41E2EF69ACDE1CFF2AB49E2A4B12C275A20439E30C690D14D4F661C81308F11EFA3D014009D80D794D9F2C8B51E2E6C83686DBB07D1790F56D7C8EE495657BDC081A63B1353F4C4CA74CC0D02CFD7BE60E063A33D1A4D9050A9100F0E181704799357532DE152CA54FFC089E8DF80F29DFA14C19C9D6B7855482622504F95A8948A5DD640EE88B87CA98F8248DF148AE4F992BC7D1FEB3BE07E70F22CC052D92FB263337528C41ABA642C6B1C6F8883B21ACDC69196733FFB684451D188107C1DD219AB8B0AE5F49628A1CE32FDBA4B8CF02F38513E37542D020F4BAFE03EAFD7DCCAAEE9E28258322E43DD47DA3AD625DC2795ADBBBB9FE061917573936E31DE6355023F8D74500D2D032B7A53630F37FFA80567BA36F771C4ACD71D76DE528FF47E8281ABCD325E4C4620D0B73B2BE2787A7F6F485492", - "E8F24D8DFB54C5BF909CA2CC5496AEA76E583D2D865259C356E64E76793290BB00E7029A146E1E90DC0C45356E13EF59D60F20F080A0FEA743FC1C222AAEFA3E55876F2C9E6F7BD29C09AE32E80B15DBA0E6B594E951EAA3BFD166DFCC17AFD2621EAE6539C74FD776BB998C24C30EDB3A8B6814DE088E7E6B7CE9A64EEE9ED8C9D987A21A3BF35A9D59171DD456D8D0D7D1BEB3F37D4A31812BE00077F0F0064DA56EF9C4D36D1D3CAB4D1D4C024665BBE1DC227DD29E1CF814EA65B64DE60ECA4AB9B19F937DF15914F3CA577EB3A6A0A2C8ADDA53DE536721FFFD519FC5E7CD9A3BF4F030B1EB638D6A0F8C4E24085012D758414211585EF6E0DB8C670064885B67256BB6AD7E12E380C5E25BF58EB1731E935899C1FD2B20008CF87529AA3E714BFFA86D8B66AA94811A43ABD868A7711C4FFB339C01D72D4974ED53E7DDACCD36B5F459DDC05E9D475D3E2AE383F6FFC9C2A0D1791B4675DA843303C96A98ECA88B54735293C4E1906AF30221EE71AB58F3E38271608DA6AC0A488C0850DD86F8B6588C91589632EB781637C14D9D24B57ABFC301790B3C11C1B2938845F08F7280388E0B9D5A9682A6FD40374542634590F336E42D8FDD92F3F6C82BE4D3B953CCDAC984F6C94D8F2FF70BDFBA63C922060C322FE34188FF70A37648C362BB68B06D74A2012050FC007F276A54882A8A04DCE014655AE43E448639F56", - "FE35174BF6B56B67D39271D92AE0DC2B64FE31AAE8D1135BD8FD308D7E281F3ECE84784423A48C1362B5852719023F8861E861AD8B22219259E357EB9CD8505A66EF7CCEB53636B47D38A2AF5506E1FD72D3E30A29EF897C5C44A271EE562D67B279806E8A5DCD78DE538D8121CAF4C217F8A969AEA50D6FAC68066277242B1979F1A6B3051CE5B9949A11719F556EBEF844C808E5C1AFCE5E312C53AA9DDBFAF7280A7FB8502D2C7D1B91614157AE0C6C962F868D05D0463131DC841169946B732F8000E686467BD5D8086CC249693FF9794374266BD6A5C8AFEC65C66A834012365D60179450C58FAFE724B8B9E99C33900A86649B04CD54351D6C4CC7068B28F070417CC9C4430390493BEA50799FCBCD7A13BF75947C597B3D7AD486E3AF99CDD743B6230BC473DA35E6D05FDD17F7CB8D04A2B00EFBAA30946EDA96BED467A45EBA54578D9001637702F1DBAFAD16D2608C475B8DC7994DAB93FB34DF2237E4A13D0C04A6CACD42FA9463674AF8ABA97CF511A82E8E61F8330004E165D753323F4AFFE598E4D108DD8EA8EFA45693A2F9EC8335C756393585E052FE5D150A58F058CF8C3C720F37112DCBC6324877E87541F06C968C46FF846CB512EFE65CC401174BBD1C977694ED7BD1702EBD2D1EF23BB56D0D0C1EC2D90A27CC63F0A09D83F8B0A5ECC181D5D4265911BEE77EB1DCB4780B53CE74DC7A42252F3FE", // 40 - "8FC54C96AC76BECE7284BB32C63FCCABED194E82FBBCFBDFDC6AD09AF95DCE6A5D6E13CC06B247E38253D359A6C0EEE00A660BC3BE6FB217B9B554C90186711B1E85117DF0CA17463E132333B8469ADF72C3BC6F218A96697E172CE2E6D6F4E70EEC2A0CB48F0A2E7991B1B90A85088CD2C59E3C9AE7FD939592C14AFE9A13829DD97E345D1AF92AB46BF196DF906BBCAE16F5A58A4D99C7D586869C81E182352C210E3B1EE822F4A95DD0BB3B285632978B18FC1CC29BD58C2152FD3BE73482DE1A6A79C3929DDA1D20B6E99E25A666AB20CD371A85DD20BF0A76C5A81041EC943A89A94AA64C5207B3166441FFFBDF4AA28A2A88173F280F3A2838A98667775F597D0368DC0BC53C1AB8B7670EE23E0ECA08CB09FCA68FE2153F01FCB7061CA1B6AEDCD815D611FF71868F50855054085AA1B7CA3309581532D658C7D2D6069C3B44E0E3CDE45222DD9EB40C369762CDDAC6D9A6923FE0EA7DFA1DF73BFF8B60EFDDB8863538A38528803F3EC27E09C87A2D0E160C2480F7D2003DA331FD5C7FE05B582DC9AFB114D2AD2F822922067F1FDB3261078F33879C497035003171165FB139F79BC508AB9D3250D1B53508410A01C35B53179076D9F46C5BE1A26DEAA2F9F71F442FD7D19D34979F6ADF96BECF1124551D4806E7136551291352748DD2D58443978C3DEA5ED0544E6596769A760B476B9CE7BB09543991EADFAD8", - "BA63AF12FA5F7D03F714CA9AFBF19375D2A7E31EEF4A9E10C7C2F8650552A6CD22FDE0E012D46CEBC773C87729C7E746FA4C0361099D4876701C0B2A16EA2B5A6B750CDCEB573DC711F95CEF06B8DF516CA2F9BE6387550F22502E53A772436F324569B25BBACCC781D30DE25B806D369AD1EB1D1137EFACD0BE765DF4D06E177D3E3F13E9A3165F269244FE8B130E9066B23474418A5191ED481BC8974074336E71BEB02B1BC34CC620BDBC24CDA8BCEBE068416E5F5B5A263A51CB3F6589F77D4E607939F7A0FA637858B96189A014B5688A9DA32FE2ABFC31FB00401DE475BA07265B3FD1890ED0FDA487D7C616E099B4EF4E47C9F9114E6BF8CC757C92C02C46546130ECF7CD44160F55A72831692A5E69146086C43A5F043BD1184965E2A6B154BD7B8BFB3B4B28C081B0F349900492C703913885428A82A8D2EF1240414CC0B6D56D969BA1A121D9D61584C6A880D533AB58B94C85F07732B5EBEE7FC87FF3AA279ED703858957A1C1501D71DC5420C24BB2D570F7589F0AC5B6EAA87AF68442FBB38EF693D2200E73DC73F58CFCBBE43FFCBF76DB4241FC4A7B131F29C8BC0F77C95843D2FD2DE39E3D4D44237DB39994380C5F1A1A3AFD927F6B736D585112920296B90CE31D58BCAAF8CCBCBF15BB36199B48F00F308F7E8264D039D6DAA6E848CECDD1544323C9654232F45689076B7C4B1123AE0FF152124E930", - "F2CE3D09E701F60716A413AF06E14E6FB7BBC29DCCD8273A083B00D429B57EBE9FD5270EC0C299D243A9FF0FF73DE19977EC16C2772C6B7FF88F83481924C921F49EEE41121DC79B7C23295EFA50292B11C7D45D66BCFADC3C3A390E03E13CCCD51309BD4061782273CE5D0E1BD3E11271A3C52654D2B846B5600D3E68D2C234807BBC32F1A350839500DEB6D387AECBFF5344606CD04BE3614262F068FBD256B2855EABD5A7C0AB5C28D5719C844F2A6FFC500628CDBCE869D2F090E588B57B796029A84E2319FB6E59960553B62BD30DE99AA7ACF508168EEED8DAB9996041BDD78BAA2A1CAAD2EF366F4A3244DCAA3F06EC9A24572CC80C3CF44B557CDCF6279165414066D6B700DAEA8D361034D9DE455A55E55CBE39898B65651FE709506D1A1FF67585D0D3E1B2C5EB599704B3925CEFDA45C33D92C9ED9F0C45B7A80706E6629594F66A0F74A4A767493B73B23AF323D519B0D05EEC62C6123A0829CF612DEDFB7F275A55F1629DC64D2F77125A1BDFD7B9C213C51DD9FFD83DEF42E87AD4E0F9E5ABBAA6B120E131F9E5A3097F7EC766539C733522FEB0F02604613CA1190024CC1C3297E7CDC3C514F8C3787943EE8CE457B516677437B2212A19629A0A04B0DAB8258A17B28F52BCE915A680152225304301FD2BB1BA2A557B3E3CFE6553CABBF79A47FEC31DA590308D156C3537B97116224F3E21EA3841A505E", - "AB2F844287488AB6B0F47218F2A4C54E6BE79A80F1209CD747FD88A575EBB11F2F0756E2C263E753D9388876E159EF3BBF99448D0865173572F4B6A03FB72244334E4E861E0495AAEF15276379F8DD88AF9313096805D5596446B48EF1F1BF2ABEDDABCB1FFC98ED408846D85732F807196C9CC9B283EA4E0D78681C73CB6AF89E5C361476F84E979814F30C0AB03E97156015A493E091EC5D854E8B08328581D80091564C25D6A714407D6B591F17D376953F18308B8BC12EAB5B5C9FC11AFEF293109785CCE29C978955CAE2601A1DBAA274B72CC18CF27FE077A0123258A1B879E1ABF84458BB10652CF7310278C7FA11BDC5D00DB65E5D6A13D77FBF9D02DD0574DC7AE3849C7C47820126FC99B9766920516AD1D63E7EAA366005714D6C1695E731E88D43A38B615407A99B32A101C4D417D5E36B886C26EA1CBA9FAB0C040468781897145489121EE47BB2FBD6A064CB325AF5CECE5D5A4BD590C70C7A9B068D318247D8FE16A3609C94A8D431E9872E26A3CDB19DD971971AE1FBEB2FB76F7A71AFC5815CF7871BB5EFE3BD0C49BAC441ACD9CE1DA4AFBDB972659D13775AE77F843259EED57A62CEA93FC449EEE1EFFD9AA2D36D8FDBC06A95A6AC9B067468F1D813F2DB95D3456063D5B23395824385D5C68D3F869C4F639962D599AEB26FE2D5148A51579EF385D31E744450E11307F0C803C70ECCA93F831EBFC", - "9B1066F98BA2299266D8C1351E6945D7EAA658BCEA46D5AB353C2CE48D01E915E740DC90E9CC487126AF9FA722A335FA1A8D11C2719F07CCA23B1DC5E5B9AB198077177BAE0B5F35C14666FF32926AE0239F21811921C77FFB56F7B218A353F8EA67448F61ECA318196B1186514D27416EE2F61764940A70300B69EBD02719191ACAD969B1075EDD09EAE26F883AC99DED1AE9355C2F30CC656934C0175E824E76947F83D791CE7A2960FEF547CD3BA94CA064659D1F68C0DA8C13AFACC07F3D5A653F259DD141E2ECE9B6D25F67CD38AF3F802CCE332049DCDAE1504061C2437C7D3BF4E15D88185D4114E96BFF7EC673A7AF8AFD53C979C89FEFACDDF873686D892DEF5FB67877734CD981C16684320AF392A464C7216FC5C8B22BC29C8430151FACC94AA1513A08E1FF2F6A965F68E368245510B975595EFDA4E80B7FAE432FCE9737962974905F367FF637121237B2A404C42A5A9318DC5ED9CFBBC2EA9C17A6CA37BBD98F8771CFA7EF58B1EEE40BA2D6C2031EBDE4AF0590AAE8FD10B2BC02A254C97726521E4D4D4D9FFB74FA5D06F8AA0BD43631FAAFFCBF01FCA87C9360C5E6A62A4B025B894E2C30F9003D29B642335DB0A3F2A3436A917B61776F96292A06A6B4DACE4F6F0EE0232E1C206427A0386075BF50D6074006D45E3A3CAB085431032AC20D2690F0435D257D3E2C93FAE49D75FF0F320CB4D348C6288", // 45 - "8A7F8C99EA79E1B2118E3B203F72FD8921BAA5C336B006ED66AC7181575D66ADE21D00FC8C7DCCA7DC9E430D1D086F2922487B5B025AD38750B4F60993368D829CC361B600ABA990E570370AFFF9BF171610F2A0B0B93A0A3AC54244073A0E816DD691BF1B0041BDC165125A14C621E01C8F069C3E05F48FB77E66A998C27A87FEAF07B5912B303A98AE5796F1B5D4E2EF52F38E68F0EC5786C19ED93612D7152BCF0CA1A3044898F9347FCA8370CE6E4A0510750DF6A42C1C35FDBD91BD2A26A60FB229CC35FC45525D12A092505D901A4F9E1E8D42D25C41B8FDBA13AFED8BC5566D4F3BA13A779D7BAAC1E25B6710D7718B73A641F23E1D22CBDED3B7BC3AF7D92B2DA1CF874D908CD8590C80F1D5055CB8228AD964DE099A4D037202C65D197A35D8A268D8A3BFFFAB39B93615DA295A09AB979AF925D895CB60B5DC5580055BC4347F0DDCB1090DAEF46C8ADD1009A5126362B0B4F1FFDDAB4A00AD8290EB84F76AA345DD73FFF7733035026E3CC1D99428CA68ADEB8CBE98E4A630F99F4F33E8AB66895AE7435D2E84EAC95CF19E9B440373EC0B4D4B2CFAD672C7FE1FE8CE5F34F55B016F8B115FAD6CC7B53DA7555E67672FBF6BDE324AA09FA18F13D9FF1041A12B04F30304774B07659F397554E66CA589D9D9F1F262CF659F718CA7F443B8331BDEA8C3980045562D909EA44E917FF5D47812A0390139B2A87D0", - "80B35D641CF6EEF705D51DAACE1EA5EE92057FD497B0D937C7CE9A546BB32DE580F8E434D644F191798A518785BFB9471AAA5D03700CB0B7B2635A6A14750F03DA4FCCB1B363C254A5294DD8E7943E4CDDA318C4B92B57B14EB0F8EB250686CE129BBB2B18EBE7FF53C9DA9C0B664C527A3C69D905CC6FAAE8BEBA7D83294C1656DA4B8308968EE49DDDC2D0C71A17B02053027D7DB8F4E77E3AD1C80FFDBD37938876B671D80E99F5F1C7BAEF50B7E05CC0CAB8979A3A2A852A7018673292CDBCECAABC74B839FD3C084682357A5414E431C1F25E34850FBC779285854FC6AFDCFB7B7749E0DFFF5F93A8AC146C873B407F2CD6CCB461312AE35DEE8D6D51347B0824156DDD60762807A5C132C0667FBBCA7489058C47A156B2A50CA5C24B894C1EE7C44B87179176905B7657A8E95AF7F2EA6C6D2A12384CAC9E6D14253DC5C31BB8FDD2462581C109D2DAF72238E4B63F436DFD7DD5571548D2206BCB8B837D8CE8C9C3B3066E46A1655E3D84AF42DE1051DDDEF438821E0F0C1EDBFE148356D707036B269C19C4CEF4C4BB4048364E2A3886E38B42EFA15F22CC8F92D802EAF3FFAF9BF45247DB76C03E99F662884DC2A29EE488023BF0EBD46539DAC307410846B25280349106CBAADFD658A066C3664E35C4C696726140275AF7611D2369ADB8258EBD2279DD24DBFE002377B9A3C1B120890A6FDF20597417F88F15C", - "ED6621A6BAAF64578BD988D08FA8D3D2873C87C38AD7EB38C0922FF3F7E59F0A8DE00744698939D42D459E6105ADD3C77E9FC4911F572B3856C9AF6C15ACE704F026C6B2FC8BDCD9D84022DC10C47E11E934BEB7E1DCE8B6A2BAECD384D810BC3AE587E7EDE57CDEA908DDB020885624BE042DE0ACCDE1511CE38AFB6C9DD812FEC339B8137D88108F07035A3869CDCFCB9402CF96B9E331297B644DB13DFA88F60605E067B9F35607D2D75573E0913F8080EF603AC4B7133D836B84F32F48534237CC559ACABA53A96885D297CBB572BAB1C3275F7CC7A3AAD10F29E727B28BC29B038F4003F8C93FEDC88C63D72609A5330F36F4986CD9536812676A89305C6CE58D4C49C088B5E273F2AF77A8D31D1B8574B9DF02CAD4930D7A7F76C067E7160ECD1A845FC6A3B508708C279A2C94F29108FCE34A63E5D5554FB530522394BCA00508DDAE6039ED9F47609781CC60F6E211BDF29E6F44ECC873DD24F1D37E49D7BB7D6279FA7B9D08B5FA8F9364EF6D4C8D129A5A97A8BBF17DBD5E64C4A31426881687BB79285B09290DE61AE40C295CB1BF3C8AF756E88068A777ACCE3C4B6E78C62AC1E8EAEBEED0AF3153983214D7459AA8E254633B52E5C0ABF4647B906AC50A62543710EE92B335A7162B540AC70F2B2F49FEA892BD72DBFC5F7A35C3AE56636AF2887BE680FA63768C27040E888202F700007DE648482F5307C56", - "914BDB196CD56E3B7D7D3F1D7A5E4B0A1389578F111449DC2DF643E6E29F688227C3C07033C2A3818342B229F63C229FAC11EE1AB6F0FCE8608E03B46DC983318DF15FD8DBF2970EB342BE2E534BB0455BE58290A48FC60973553E94C4CB53566CE0250D9FCF055936523A8ABFC9287DB9DDEC54710859DF62829D2B6A100358EB64E6219451868D6BBC2AE4DCEA0C0E338B26B748D4A1A34AC16233046CB7D346D0D79A3CCDD4CDCB435B9B3075AEBEDB4C0F18C5DC006F5C208D882308510C75E729D08C779CA99D5A685E78D5628094AD137BAA635B7FC0F492C48A9CDBE63209C8231455012EB3E830B5B2A79ACD8FEA8016243EBC85BF5D6F46A48FE013D2B3B789BC5F743200BCDE03995BB2B6A640CFB099788E380B4E01D75409A8D8B3887DF2B1CD34960091653EEA6C52EDD745B9363BFFF666891D9C8BF511C3C07D38F49DA2892DCCEC81E1722F6EACB3214E3335C93E6141AB94E5EC31BABF8108F6BEBC3E60B1BFE37579B4D5DC8B77A347940CC1F6BFB5B46097B1EEEC4C354159BB3475E05FAB6BDE5672014D9489CB70DDF537F7209BB9EBF1FC6B8B94564AAAD5ADDD83CE6E51EFCF73DC6080D738C4FF1CBC87ED420A0B92FA459AD7BE58789F0A191D149F88173184A22874DF6D39DC1BCD4413648B178ECB03F8358547A68DE7B672BE9BA1FFC8BA392F8A58ED2806155C00F86B7669BEE4220D420", - "97051FC67ACA30E8AEE73D3A8CF38BB13524D4E0EBD9BE68398C7C16227CABB1D0B0A0ABE7B6384ABA02905BA0C3C7363599D059C7B4C99DB165CD14FA12FA7912449CA7DD5E346D8010C85A757382270DAD15BA3CE36A76EF55F81A1E80BF366B37FE3A88EC722028C25E234E624040450A99CD808F942568AA7133981D72E7F2928894670AD5399482DF1B90E7E64062F830B736C79C30F36281495C76699CD48404673FA334F042F9E0E67DD7F3853BF71ABEAF6A9A5546855E840CE42B224D8F6490C6CE5FC02EBAF4FFC390107058F54CD635D4A7F2878099C1EF495750E6921BE2F39AD808C4210F287319F811A254CEF8CF153FC50AB2F3D694A530949E5F578D075DB96DDCF2BB90ED3DE09D9CA8E08662FD8982741DE1CE0A6B64C3D3D5004B5C04B2B0DFD976A20FACC94D1762D41EE03B40D2CF367612812EF4CC41D1BFE9CEB51AE3A22AF1BE7B85A057D3048D0E73FA0FDAF1119EFD76F0A41BE63128B22D64A5553E9549D411483BBCA1483EF30CF6A6D317AD2C7973EFA6D4C1121F703D2F48FCDA3177AD450D75D2A28D2C244AEA13F0E60AEED8ACBAB444D400DF5E280DB799B2D9A984DF1E2567D39D1DE58EF78CA6B4D8BC172B07DCB02D156CA96EEFAC69E556CFCE0AAB617C7FBB8C34871C1D35E74B7BD307D3F2E424C7A9AD676A1A69E0FE735EA50887A1DFAE6CA2FE4460FC7EF323ADE493020" // 50 + "F5D710130573541B9DBD4FD9E9B20A0D59D144C54BC7935539D2E75810FB51E494093A0A19DD79C70C5A98E5657AA578097777E86BCC4651CC72F2F974DC766E07AEA3D0B557EF42FF57E6A58E805358CE9257669133B18F80FDBDFB38C5524C7FB1DE079842482990DF58F72321D9201F8979EAB159B2679C9E95AA6D53456C0DF75C2B4316D1E2309216882854253A1FA60CA2C94ECE013E2A8C943341E7D9E5A8464B3AD407E0AE465C3E3DD1BE60A8C3D50F831536401E776BE02A6042FC4A27AF653F0CFC4D4D013F115310788D68CAEAD3ECCCC5330587EB3C22A1459FC8E6FCCE9CDE849A5205E70C6D66D125814D698DD0EEBFEAE52CC65C5C84EEDF207379000E169D318426516AC5D1C31F2E18A65E07AE6E33FDD724B13098B3A444688389EFBBB5EEAB588742BB083B679D42FB26FF77919EAB21DE0389D9997498F967AE05AF0F4C7E177416E18C4D5E6987ED3590690AD127D872F14A8F4903A12329732A9768F82F295BEE391879293E3A97D51435A7F03ED7FBE275F102A83202DC3DE94AF4C712E9D006D182693E9632933E6EB773880CF147B922E74539E4582F79E39723B4C80E42EDCE4C08A8D02221BAE6D17734817D5B531C0D3C1AE723911F3FFF6AAC02E97FEA69E376AF4761E6451CA61FDB2F9187642EFCD63A09AAB680770C1593EEDD4FF4293BFFD6DD2C3367E85B14A654C834B6699421A", // 01 + "96B856A629F581D1344FEF597835FE60434625D077ECF0D95FBE1155EA0431979E5AFF544AF591A332FDAEF98AB1EDD847A73F3AF15AAEE7E9A05C9D82C59EC325EF4CF264B8ADF2A8E8BA459354CB4B415CC50BF239ADBC31B3A9C87B0843CF3B9E6D646BA43F866276B053826F3A2334CC5E2EFB9F8F195B382E75EEA63F58A06B3F82A3B5C77C1800FD9498F803E524435B321210BB84690BED0BBBE16D363B3A90656A73720E27008852FB7DACC8284411B177728D9527C560859084A395A6F11A96AD9DB6B43E00642B000ED12BFD967868EAB1108552CD4FC89FBC408ACE7678C381EC91DD000319124EB5D5EF52C4CAC9AADEE2FA045C16CE492D7F43743CA77924C78696FCBF2F9F7F36D8E623752200C6FCBBD71ABBB6877F3C5D6E6740AB0389458A6B66440858B2D383244E853646FE2714211DEA9E6196252815BB704A20BFE556AC474F8998944E0CABBBE21A6400B87BFDCF937D12B2821D59298AF4AD378F0F42BD8C41693B8D993CF37C8B478F3BB5D33AD2A9FA24AD7B8FA895FDBC04964192F7BA3FF74E0E3A435B5DFE042E3115CACF29624C0645E9C917534A2EBC1F5665E4E1B1BC56208DBCD8A27CCB6474D5D0E20CA4072C960E5ACE41BDA3770DF3B681F2B318F6F8E1CB17C2857350FB6009AED665E13B2780D79217F73FAC7A8A48048DB0FB8A8A5007CDDC9A7B2DA8257C99F1CB605A18204", + "E57DE19A3E4A8C122FCB1DD6584B3D2DAE364D800F9C5A9E957B38F624CBD3ACC58FA3ED070B5E44857CCB813FBC0BB83B5D157C6C562422E5963CC4DD753C45B0264F8E136A0F1774D77A543E44D51EF8C6B9408B6E3B5CEE1347A94F13ECDC94DC764976E5A50B4CB0AE7557553B47EDFE03EC2CD32EA8D125A341E1EDFC77E75330D6E7B23DC838EBCE7E5567F5B8C80C3D15E7404B4E10F0BEB0C69626A814AF91334199864FC77E0FF548DC2A6FA6A71C3C0561F2B085CC05E8512E27B9DBA60B93D114B87935776C8E9A67905C429D48BF3AB1B0A56FAFBFD5D9C8D8C8A9E5918BFF273CF5E8664FF2B90314BDBFDAD5AB8C22A0E45C104ECE75EA43FE9BDCE306A5A28AE464628163D249D8056005F1A900951808CC8620F81768153436F741667A8E271DD986C7A1E5046FCC74C7CEBBF9A1296D6CF0B2FF85BE412D87214BB368DFF462AD649D7324A117252311C664D33E4DAFBD830FBCEB6EFBDD7391D4BADA7A775FD1949D981F619655DB3C22BAC34E5AE41222905C0C7E80D6EA28471EC0468756531C09A471EDBE200472E78F1701FEE96E5769A9893C0F11E7906B064442E06E21ED8B0D70AF288690C532A2D03B373E1E0085F62F7AAA658B569C5184E3DDC40ECAA88B887118601691892F9F55E2DE79E49DFF11D434C2BA3AA6447522A7C99DC215CAD2ED0114ED62CBDAE9D315E48AE14D2014B7F8E", + "C0FC4C72A12023BA7093C86775DF3D2F42C7CEDE616876340BE4301361B9DC9DFF4F1DEC6A62E165927BDE4F809E969AAD085437496BB95904719820F4CA8ABBA0B84C34B06DD7E268BA10E386FA7DB9FCFCDAF2B6AFBA46A8A299153B4E11582FBA7F28F0A0F9DE41830AB33335062C57D81DC361EDFE491939100FC827F36273760043D1C35B74E36C6C4DBE1D307847D55AC07D8B212C2DBA632A86AB15BD0FAFFA43070644C7E50623195A3796AA8E8D6E4E964FA0E4488A500B9063FBBFB1204A0E33C6CF2879AC2BA7C86CAB57E3E8A497836194E65C5C39B950F1AFC3B58E850A5EC39F4190D55351D16529CD52B36DF4A2DC68EE202BB758CF19C54B0E1461D547B5D06C2F9DC09C2B15458C3140860E4C6F3FE4F417FDFCEDE00F71212EE137E6669E569A7845470CA564F85CB4772808D65D2B48D409B709BD7AC5F7E28AA804CE9DAC3ABB5A5B768C6A184B5A974E933F2C1772FF64AB26BA2D5A165744E314EFB2238AC4858A8B82723DAE8865478EAA261F35DD4D98A9C07ACB0B822AFF1AD3E739CB214CE737196FEF2DD0B0D45BAC423935670BCF71C2EC04CCB98943786173C309E75A02BB78A788A5E6F8A8F407E57B8403841A9E1FCB3A7AB80D1F6529770E52C173E2C47EDED4400D5E665E325ED845C9E8D0E66FDA16B17D61EDBB336F22688C3F0FB040A55F33B65FA9F3D45F5B22C445CBF9DEB22", + "EA9596357B343DFC31D5875CC0E94117A33651472E476D3892D8112EB6CB6E0151D409C5A514DCDA38A773C58F18B590EF9017B6EDF0192AB7EB29DD6E1E7E7390C13E9B10209D5775F3B066F7B2DBB7307FB44F726DD2F368A5FDBE75BA7248762E1EC7E4589DF1A353A16D6B3CAC1C9ACDB89890ED2C4F44AFEFC763DB51D102230C37E1ED0943CD6F4176B2F5C19119588911ACF81A7A29320AD579C1BFAED1A70DEE1B87037138ADE411E0BB92F5B3148DFA11F2F84CA6C019124B922837503AA9823A97E443A66378D5CB3130A7EC9B05670E85D095D5E6F603092C632E51FD9013FE7FB9F08448FD09F1219A4744CDAF82BF9C60039C8185C7E9559FCE301C6D3F46A2E514AAD44D3889C8CB4ED7439BF47019194F2644363770F8BBD0AE92B6F5F43CBBB503A885239DA636903D4C264B3FF09AB77E3FDBA7EFC63E0792B6D5183759E57D8A694CDB133B4A9E301CEEEB978050AD9A9E410091AD29E389829E2F24BE1E3B24F4540C4A6533EBA72E8AD540BAAE43A0CB82F971F3A51DD77FE9E1956E2EE7553E050A1D10B99552DDD5B68F2E2859712835BD2AD6B08881753B4833FB04740E3364D2CD4921B939393E7EA91B854FA1E5A8EE79FF0A83F111F78435481D462E0E1CBC0C921D190A435A1BA755E4B7021244FC5E3F0630F2A1F439C02AE619393E5624834B05ED7DEDE5F0AFC7A40899424E75D4EE792", // 05 + "90E92279CD4F60D98F6E8FCB3E9263DB60FAB146A835AAC2E96B3BE3FF07119032DEE0521C731117E90C2943B389DD6B65C5E21C34F86F5A7ADE04072DFD1479EA36528D340736B0FED4F6207BE9F6CFC971D5EA11781AC2DA25DBEEB6B903EF8BB0AC0CD2E29F94B8CB67874A7B7441045758E09EA061181A50E0AB7BCCF801554E0644780BC137436E3FB7784C182856A790D6943BB53DB40D13D6A2F7B83A5C521073883B90FB8DB1C0F954D132943C09156A09984B822079FB8FD09BC07C1D6336C7CEAE8CC3162760B9838CA6A38FD0044FDF099E416D57BF9F33A551043F34EBF9BAA90901E62D2D981065F977852072F692535DDE24EE8946387B4E5B0FEFEBD75552C1FC325A608A78079A9AC864F2F30010A3304CB16A26AF98D9BFD3B8D128541190B2BBEE275A6F53B9BC5108306985ECBB983B56E34F18B48A12AEAB88271F4F780CFDFA83E05E35C12464F4350597CCAE9B4498F5A5454DCC3218D3336763674934ADCBCB5EA52891EB240C362248226DE64899BE30735F6495E94AA61ABEF62B803C57FDD045B724ED1966B6E7DFDFCA5B36F7B0FACEDAC62DE8E10B12DFC84B1A9CEB407BDE63CDB5208ABBE5E066AAF262187E94502B1701B2CC8681CB616773DA2B7AF49443CFF528F45DD7F25959836771908C2519171CAED2BCDCFCEA46301E7D99A5AF7199155772E92BAD85F35EDB656F0999EE828", + "A91F570102961D62CA6CB55144AFCCEAF3910F3336DCB029CDCBA164ADA72732771B6ECD1C58E49F468A2BFD23E1B996DABABBAF5AB3A4C74926187B5833006F8BEF7F9CD0F05A2A0B9BD9073C4C3976E8660CE7BF81634CF0B31C3DDD806A6A0C15BC552B83A86789CC675A6D137BE27BC86DF68FEC5D268119EB9E965260FE1F5C56AEF60A8622CDA8C42F24CBA7F5B07A7416917277323314AFD3ECD10F74BEE7B22DC760EFA7F935FC9963411353782547FAEED32E69A4FB5756C1A73CCDFFEDE50F4B2D9B5D2ED5C59C9A52D80CD27B989B8DAA14C569E763C08FD42358CD064B2DE0526607C9536D75E1617EC80615EF5EE2314FAC29907B61B61F8696CB80B14B3A0148EEBC825C91150A08A23FC7B38B5982AA02A18BF6E91B3A1F2EEF360F682A34AB36CAFCAD556841073F219910F7BC2F07CE45E98F77F50475DF9EDFE2DC9E3D7280193D61AB5076A14887E9D9193C3B83C5773BDECA067CA1BC3D4561C3A8B4E30072A6269B529760CA1B5FE9D3DB2B5D1202CE8B18E9E2E80FAFF47108168D3C7EB3C940B1A35A1D1B968A5A9DC0686DD8336E498C240F20871600FF995B9E33169DCFCFCB58E75C94D82F843C60A7118F0D7B40064A8A4176C5158E86AF0BE4C1D5D73D1C051132A85CC0628486AFD660502A515D6353B674B1D4E61750C13E8A3AD48FE1F89F201C288A8F443867C2BAC23C706EE7A2D2C", + "C6E00978E351164532EEA256ECBE0D4F8FCE02A276BD19666DE93936F7A242FC4C7E879791314B043ABF1D5F9B0036ED22AA92028C800C4D62BD6640431170EA77311865074D670AF2847AA47CB94584A793FA82F51574BD7C62BF14386F14A3D7DBD129FDE64EAD67EB35D5E13FF214D7D163B770D4A77A62D02D88C0FCF3FA5EC306EB7F85539105FA2CE5F53D182E58FBBC1C57CFBCD2D2F7FC8A067D6FA0BC834DAB8F370B0971BF6D068CD4D3A32C11C6598DEBBAEA046528C5EF762828CC84D003847069FA18743A809A004431E83924B8FDF0AC78699B905ACCFF82E83FDAFEC8648DF64042FC9438B261B73F0541498ACAD67D702AB631BECEF8680D33CE8F4F0CE29B95132591A350DD68B36734B97D4B3E84A76497F702312F2A8370DCF26A7C3C8EB91DD8699C48F551750712683E0397083714A6CAC3457C0FA70BB3A036C6E0BEF24E6B20BA5565B351C2EFD56BD9455FF7728BE07A097208E73DE4CD0CB4E215B4642365123CDEA419B28459D50E864B762554E7C1D7CAF73DA7D40EDEF5D824A2FE1A6CA473B07370932A8A5D441DEE3C9A60DB68E27A9D3E9C8229B44E5B434C6D18A8CADB6D17BC4614DEBEAD670C73132CE2F999C8716D1098C69277E8ECAC546EF8002E5182E25F31A354DF112E97F8733DD20893B430CD7130E69ED4A0FE4D6C2E4FA479001E42EBC9F36E5DFD3E0BE35A64B89745E", + "821BBB3FB91E50253A9E71AC379ED57AEF394C2CC59587B2D0337CE74002EEAD17AB5D504BCA68BDAE9061C3DBAE2985EBE292B9BEC9D3542015225F44ED3C2C3FFB036A515BF33DA1690F3438FD225A5034106C5F4BCC43301EEC2245D73F63038E2A7D9B8CF95A9FD813FFA071FFDE423E0CE737969578BEB909764A8D6DAA9E15A4FA0867831652C0F6E9AAA39A63F0AEEF62A433476CC7380460ECFB8B7F3B2FE8C4C42A3EF1CDB808FC9747FB4F044B3B47A4EDFCC9463ABB72C55399B2F79EE5FEDA270D6358B27F8466969DE4A5F2E6A5F2C4CF0813C09F468DC97FC0E5DD057A8A0355767B698F8A79BF0350C4200413A15E6591DE70A1B502E19FF515C3DF36935974A4764895B9E3CA2626BD39B7ADB780AAF7E2E914E804CA923089A51F3876649C73CA3C2623A8C95D11EF4B3F941E9772EBA1F47212C666F03F01509FF699F74EDE27182B6E98AF49D1BAACB41A328A8C34D6E8AA3553DA3962B27B041495F269328B6BFB4A385CBB118953F3F009920EC4C8590003290DD60AC89177BB8C4BF753CE723AECA392B8D9E5E9E4113DD062F294A77B6EA9A0477E697C04C787CE78A92C704409D37D37B6B392128698D0D8D4CA101EB38B92F467F0D86EFD8759A14162CAB55F8C457E82392790A5BDDC8DD2663944F880C95EC02FE5363B064623994EE5D4396C0E44DE2A3D225830BA6160270BCD110A942B0", + "92A0DEABA9875D4AFAF99A24C1D5F10EBBE6DEF9CAE5B0C85B2A0417C1CC5D1A5F71CD8F8A4B013C3F012C0A19EE4A23106CAB8662C5A2A93A971D0B6E487FC05BAF5C355A9520C9148584CFED3EDD0F38696E161E64378C831C586D9178A0CE289A67F33AE68C02A3CD138FA09DF1CAD01EFADFC8BF6F5407B79B18D09C82804736752D08A1FE09EB35F544E9F797EA36DB493BA947AA82513EB1615A356B5AA4308B0B4183E070EB494D628159D2D4BC3CB110AB0CCB2E9E73B5B7EB567187621E72D99F1FB78565917B28464A5F29DD8D6F98B6ED703040A44B0ACD97F15049E009E8533FDB0B6DB2F2582E6BBF81D7B0EADC8F402508F6B8531AD13FD1C55978A8A70DF4E053DD475132D348AE27581370EC14A3E0F96E0D70DA4946DEEC0760011404FDC5B436CA7419D05895F5E0EAEEBC88C74947733BE9919F18CE702887A6C4DF7C19279B82FB646090822DA9CD9C7653F6B931A337A28F7A4A01DE0CC0744F22961045F8EF8D4B30B07E5EDF5FA944EDCFB9841A9088AE82444FCB6E90B0E9C567A80E8C42EC713D78132F37AD1D2592C31C93D2EAEFF38AD94E5C0D94F949F47B88B03BC1EA4E5EC9C7D9DF19ED208B8E44FFDEB0B625F633C7DB1C826AA9E1C1309E5B14A0DDDB79714DFDCB52221CEAD7E8A140DF7806F127156478AFBEE922B8ECF322D66B48BEC434299BBB36B3BD9030467B7F2EBBDF358", // 10 + "AFA7FBAC93326D0C36A388831B99DF4D527BCE7C9070F7B46B5FFCDEB07384801AE5F86A89934DE23DFE2C1AD117797D4FA1BBA6175823B41166DBE9D126F17B3761E2C352AB396A5A9CCEA42A5E9EA1BE3497C0A5BA9121DB97F64159AAC78E62D7DEFF3BF4CF73F8CFBE045C9D39E41D5D208DCC4B47CA27E900C3CD8FD1408DC5E0F5114F2FE65817D37CD1452C4967ACAA2119FB8D60E5E2FD8A820D0AADD88B94D40435C095568AE6394D3B97C835BA868A83083316C49C75D36EFDD85165BE74A4F2B2D21295EBCE085D9C4A4758FDD9CF71B97FDF34B7B63A5E9691DBDAB834D87D5B52CA9A53032FFE821398616EA92625C2DB633E37911987083A3B49A86FC562FB1264A75643A5FB6E97162E16ACCE353227FE61A859E094C2359BC4645946AD12AE5C39C70F59EA7B597A9B3372C23AA578146781A61163C92816627DD9C4BF1788087821F9F5D41B75A0F251B06BBD3E29ABD41E72A1D48323D24E2AD6F11C2D49678CC04FCF6B0EFD33BE6DDCD444F5CA02FE158112631F782CA7B0C5F3607ED807495BF8E82C5EA51A922FE28C8168D9844859E7A3EE3038C5D1D4BB4B13406C340894DF46406836739E31D01082BC84489592DA0E985630CEC40702A36DDC301B3AE1E8101786FEDBF752F9E175287C239C18FC25795BCB479DEF59C58C373313C02A1BC5F16355E2B50EFB58855670868728B902653ED80", + "943CAEB680AA3E630755DF32F406F403D7AF5E48A710274D3887A7AAC8EA6744B889F2E0CD2033DEC0B434A9591254A0AA68C5C9BF11D35765E86B437497D84E5DCBBC0C0C580CE9BC50EC6382AD74DB02C2C233B7BB07517D48056226C505ABF2DD244F6BBAA23313D570558B065E42327768078EFDB53DC465DA038E3B216D990EE951B3E13D3C1CD559998F77BCDCD2B9522B6F1DC5E12C912EAEF574AFD69C251F9B2532501AB9F4B3B2223D0F8920BD562B0D358A14AB0D196DF6337D1C96CDB47AFEC6F81DED4B5773864DA32FCCD06B9AC53C122B2C6327E6E5EFE227DE4893FF15BBB2257FAEA836E99676EE32BF6FC14D4F56EA191B8A3870374A0867C49EB0015D1C6D07B87A36BFDD1DCEF20EA7B80D997CBE2D83EB5630F2EE6F73B0D50700C89E4F32438F5541360683DF11DA6E7A3C1E7DB2A87800D9245BF04278C990A8DC9CD86DEF39CBC6D4BC00FF13BBE132F9D86681A8913BE787CFC69C35304824788716D52DC74CEA399E06DE6241780447C74DA8E947134D8B2FAA9648D6D5F34C9D60AE5973B5BB0187796D589C8FDDD7675671F28C04AC1038D09251980683CB712F694D7C5B0D5B1DE86CD10EAC4EA04A55BA8803D78249BEF516D38067890105A23212E72879FA267A8B4F0455A81F17CFD3E5DDC55E5D4FE00F83E18626C676DAF00E6AAFCC23D209DEE0B0FC6C2AE4DE161D13017ADB5D8", + "E5E70E7837D094416558C044D758383EDF5755C80921218ABE76E51FB93249E211A38FE6D07A7DFD2263E6E3D8DA0F921A06A606B804DE7AC3FD097E5F96EFCC0F544D623FD6F43FB88CEA7C341E901CD47A7E24AB141E998FE41CA87CD6CE8C1870D9ABB6503BF7E8B659084BAF2237DFC94F35C9884C7F44B87120BFCB298696E613C1656AC4899781A94869EC603B4D38665337CA8593AAC83AD8BECE10302E4B4694237E96CCD3AD9CD5F8EC039A1D1A4210716371404C5C3FF375CB3A33559B1C1A239F2E442C8EB033501BB290434BE73489F716965393989422CF4D57E5B4F3C76AF3C5E8999E61805134B9D7C40BFB59D0D0FD30F98567E66D6148D6AA64F74A22C50AE49D6B1ECC6BB5A002ABF38FF2E2436766B86BDDE7D95DD6E02AB0FF06E7BC22CEC98D55AA2BC4D7B91C36B2FF9F525A74423498D548318509320FCCBCA582A6C2996AF6538422FF0DF060C0BC7356B0850A139AC3914338127B786F4BC58CEB6064DA881376A147DFF53C6700BD13316A5874A75D7B9713DF54FBB393BAFAAD7F7B0710C049A0B6A8B76A9956BF6185BA39D9C347D179FBB97D4FED68F47DB5AC8E0D40122EA51C4A1F88D23153DF651A180C2AD456ABD7F851B65B220A72BA48FAD0436332E4EE7EDC554B7D75481EE05C3D3453D760E9099DD27B324DD84C0C0C4DEC4C674D25284B16410F959FBD09D9DF09CE875601E", + "BFDBC82ACB4FBCD5A90C5967EB2FED597A02607F426002128AF4B38942C85AF4472B3CBF3B183F240E049B251713740A31117F108936631FD0F11C5F79325BD6677A2C2B242965AEFC147D93358730AA782491209CBE600976F56030753CC979C240A196647CD9EAB1DD0380E59BC7905EF740C3411AD9DD72027D0D3DD6DEB0F5F3C18F6D6F7BC59B758E7E262937B4599B38567C147ED2689BA2CF23736CAF55B6925827E2B70E47D3813C94C85298BD6B49C97B5D0221BE9E3164B6FA3D95AECF53AF170966090F19A69E75F188BD2556B4E8FA7DC4AC6C34F54297C06C2A96DD1C45B42E6175B5E8784568F7FEF0B6C124C5019CB577B374941E8515CCFC21F46D188BDD2C2284C688879A5BEC50CCB97FAEE1F75580577498D509D3DE161BE216C873B29E178CE17DCACC5E9E2224D05ECC842FBEAB82A75AAA20769FD81131CFB69D5E35409273CA106FFB27F63FF997CB500F161F6DD3A8BFA5719F004EC17860152D3290951678A131E4F3D3AB34CFFCAB2967ED9D8F1BB987950306BD28751D2AEAB05F071B08574EFCA01E5386E04F727BF413A8279E9392EFB64D9AEE00877C76C81EBC861E2B484A2D35E592A131726CAE61BC010B954721A82C968CC6F384D9BBB99B4E87846D10B94EE31F64846A5834DF73A67A267B894B1C06242D750F15F3E1E850A11CB2E2B16155008F91493AB3BC77CF9BE56F9DB20", + "D64F3D1CB54CDB9143D9E701BD313779C09DA064D9A85674CCB53B0C5B4446C122098961D5EFFD6A85537486D5EB26B5E18FFBFB8E6EF16C2DD2C02EC7C07DB15CE33015A636E225F744C963BF0653A89A48F1AF04819E273A3AE1F5538AD574D553C5A0DEF47B552957037BCA921970C76DDEF74BA083ED55363760A6780612C075964B083B4F674EA0012FD1DF09F0445CE75A698852098206868AD8241E3B319FA8D2D86DE6E7631DF1AEB571F9676323E0627307F6D8F569536A758DE5EDAAEDF80F4335E3AFCAD07F70AAD5CD08CCA1E71B84D4D97931F924AC0010C0811972ACAA414B89FFF7917E653BB31E9CDFC72595066C662CDB9BBC96152D46BF4E8C15A8D34809C4B9D79871BDF0B63FA294F2D667624F6E0210CD40C92F1C033C3D8BF089EF85C4F571CA727C71B23128A9B0FFD70CEA93C316FC4D69D79B089107F292E03425B2552AF5AA18FDB9AF86EA1972B66B1276B09119437E4DFB8F8E3972D91A93816EBD7D8D715CB47EFA742938B0B49FA27A291B0DEA1DF0B8F878332103F45A99936896181E51FF65C6995F57C2C54B8002DEFF54B0EB3131EE7D61030C33B5502C49CF398FEC4B7615D16FCEA3E8EA12BFB311D426331A06606CA5A066707C4AF8D1048F1CA6065FBE506D06C6C00D5D250E227265551867A6816F05155FCBDE24D4AD115BDA98AFE08B12A1F32E7C2ADA801FFB78BA05726", // 15 + "9D6AD9889EA02FC9A58949290975DB0F512EB37C8156CC9F1242B9E45F22CC1D6ED1CBCB6CB245811CE729261641FDF7A8F389BAFD7311B8BD689E02409F6E8C5202F466349EA466E5398B29C8CB126D9600D89697A07A6900FE8D95951903DAA3419839C2D9E35E9F4EABC04C9006EA585F544C7163A33D7E78DE28256B7B8978FE018CB529F7F79BBF66DC4F0DECE80AE3C2CD479D78C4480E4DE2F06C70E5FEBDFB4ECAEDC2E7BD891AD6C91A7C2446F1B13B340B7160782F6CC5B45F9787CF1B0985202DDF02EC552A6DC41325FD8D31A4316C13C56F7157134F66E1D103CC3AA7EB951C92094EB4409E6E7BC494434FAD80999D46D824A5A57390599052025F7DA4838F7D16A8DACDAFA06D175546FADD1E3F7975265230F6C01B9C1FB1B7AB1F2FDD43A5778E3C88FBEA70575CA26D94D249670E4D9FF28EC67D15829776D7BC6754D2A2BB01554E5FF0C3FAD8A1CB546E8AD5E5314103D086D14ABD30EA95DDC591C13D96C1CC3F60FD18D216B67181B6324AC09A97C0C45E50EE8380ED42F6E0430639373E7760C708248EE7D74830E9594114879748883F247D056B2BA94A0FC54CECF6F5C6AB4DCB7CFC8C224F40D886427504233DDBEDCE160DEFDFFD69EE2B75746D9CF71676DC453FD01C315ACA96373ED387B040BDEBA7FF3CE00D915F90AE6E1796971F8052160154E8986913AD7BA291188EC49A60BE27C", + "B5184F7D580935ACFF18201CE8B5D54CD0A1CACF102FBC8AADF391C4CA5807BAEEF4E5E47F7459E74485E48E0C42D27CADE6970714FD97C08F9592FDD387C859FC12C1CCCFC3EBF510D66FBD8C448C25A322CC5887F94A55D48ECA362C690F24833C3B032A047D12BDA2ADC6824A1F6EA9320BED27968E9CFBDEC60D041EF538F1740C0519003FAA89CD4224293167E05344998FD396EEF618E8F547990BC06A8B76D0FD6FAC13284601AB7191CEB813C46C45CE7B3FC09EDF08DAFE136BFBDD63E6CE7E4BCBB16C5DA68AC71A1298FD27363349A261C2F2CA8CB799E8604ADF70092BDBD6A04CB80568776A537AD1711891B251C74E42FCB095B23EEF70F167E8B4856BB7F92E3A43C79FF4437262DD70BAF9B16CBF5F10D1AD7559AB0F8CEE1B9FAD058E84FCC342D9F0D9FBE4207D40E281416506242CA1B8DAB28DE88D2D00BA21AA7FDDC25940CB29F02811F8DC6850A6A87D72CA9F3476A73649FB4A254B1204CC1261E7D512BFE7B0D0091AD5CB0FBBB765FB5AFDFAB0D701941DA54832FE8253BC0CF61924BCA2CA231A196C7C32A350AC9A5FA2884D8571FEEEDB7D29632E71898BB62B5E4E0104F73AA6A9C6B8CDA816872805D75ECA64F961641077B259C9D39E2F3CCD9FCFB1E6B6E2692EA34336A967E587F32E49B961B91311198A204D11874B4BEBC6C04DDB5B82D5B741D3CEDC03A56A2017B3D2C4FBBD4", + "CFDD6B78AEB21CDCD6AF8C349F6DF8FF8B96BC8246A672A16E45B5D0AB7D992570EC45A534B77F204039FE200D4C5E7C78FE24941F578097B216177D8AD4E1844B2E52D843256D0BE8504CF2D5B639E2CD501A6FE39B8AA7DB7DEA924B38692E43195DB7E5F25E25152DF0FB7E0D4EF63F99CD95F699E16576702B651C29583645070011B2A1F88C947BAE7C94D48EB07A132DB38D4FE2B77EEAFB31AFB442710BD0AE4E6102DA69A454517B6F148D97DBFBAC7305979B5D74D7D7568A0CA56CA89F23D8330261025CC741F9D7A4BDB356B544C68C89CCC2C125F5C71E18C4EA102343AE4A44F6FC695810E6F28C86BF53F4C8B8AAE46DF6006B1679EBEA790266D4D02A2095074ADA634EE60C7070285C316E1F191BC5A88B80D673F144D65B870A65FC93D8B4BB29B80FD58F9FE95F5994878308CAC5394781E4D5A3F5EA2A8ED834EE5BD31D2058C843F22EB778C4C25144193DAA65F9B57AEC4A344713E9EDF913F3CD29196B42E71BB182AC3B1A60AFDBF1112A86A20BFC1D28D3E0DBBABF38E8F12651C207C951654FE8C4CECB6C6F93EC46456DAFFD7320DEC8D08F2F712CEB4D82407D61CC47B333F69310C06EE1FB5ED84F83945F05D4A87CF5A68D78B5536880DE3443E804040E599BC5837E22150C93CC1E5E711F9B889C78C6FF882D80857EF41ABC5F12E99105E6C894EC0B796E0A645780341CBD039E8C6EE", + "ABA759AE16B9D8778FAC203FADF48015331D6499B8CD74BD71ABEBD3E53ED90625E3057EA47BE587600F308D38743A686EF6FA189A4D86E4A35EB798FD2307345FBD10FA701265F6417603365FCC4CE7635924428167115BA372294C27A23CE6C27C506603C5A6618A2B3344BAC50AB7FDC29D36BCBDFCE0D48D088EFD8EA1DE492C543093C30AB7694627C01B334CE3368AEB4BB3267EBB1096450BDFC2571977D7EF78D6E288FCE0388A041838EC2031248F5FD659C70180634A1DC7196C8D9111C75B51C50F854CEC63DEBF9FFE1AB9406735EC3187276DE7CA2FAD4287027956C93B8E84B7C0C3A9C3F7E82B3DB35EB6D2CEBDFE0708FEDD764C839954F2CC9044B652D0A01D28BD6B9D3DD9740CAE39AA52597FFC1227FAD8B78EAFFC31BE94A632A1AA7A60AA5A9E090DA2B62F6DBDFDC50DF6EBE1D9949619FE9B2302248D6C801DD2D6C01FF8206A93C0AD22C6990C4EECA7D4BDF36C3246A5D2D2B3982C608E6AD6BDD85C92682EBDC9E4117F8B7F841239C2A5AD7977E11E4E9CA73A55859EADF7C9C2F1B28A6B4AC7202019230063331FC5586756CEA1F8478173A0A4964D00C1AC099590152125A4D01592C54DC2555E1BA34C7AC039394D1979AEA2BF7B2B2A8CB9D62E89132CE9E3B325F023AC6E8117CE57AD4B271EFB0C172FBFF8FA6A17A490B67CA7B15F865A8AEEF37651A622390E82AFD418C7AFD48", + "CEA29601B96AD3A831646922000BBFF02C014A9136D9A151A0E61A51F9FC2EC0C3A8F4C83E64BDE569A33B4CD653C1345B7CBEA3B3AC0411B6145727B1DBF6066ABCE9DAA8B0DE58ADC2510C02C2619A542A139FA3EF7A03AD3467345D9573C107A13E7FCD43C0D51DB5EC1A09D409DA75462F9C71F0C9E36C2742C279C910F07CFC5CF7F98AD48D67232A2DF29A66B78209557357A4BC91922D4195DA9533CD3501F388AF6EE2BB3AD08BC7D53015059988F5B9BF7824D066DCBDC61CA588DCCF0EBDE4A96632DBA22CA0D770C61A1DD66EDA882D02C5FA284798E12296E89C45906D315EFDBA816FD869DF869A65DD8BA4E0B13C441EEB052EF3D0FD436E4AC68EFC749E0CF4C7E15599D5514E136ABD134BA638A02E9EC1FE66CC9ACBCE5082C8734196BADC21F4DA7621D9FA725362C411127836A26CB44CB3851D53C599B94A5E67862665D7092C43D9B4AD3FE20B8AFACCEDE920F440F3BF5552CFAFAD04A7D7E0A9CEA18D497282D44778FB7D5072832C0B77C4C51F4DCFD7AC07DC7A9863DB8A38F1C003CB852F6119BE801AD12B8BC7393B00640F125C734447DB2FD8B02F7F7FC7A23B84FB80F9CC08E3EF888634FFB6F51ECEE9B20A89941FBF2B49314DBDD67CB7A1B5BD8D629FA327AF2CBB47B5419A0A8CB807D30152FA560690DBAC49D6B043D5BC9D51E82C3B1CF4ED69E997050C65197F3D93E21CBE91E", // 20 + "D358BFC8C6AD1DC94E71D1F5D05589424275875AF8CDA2ABCC6404D6FCB7A2E0A74C68024827E02621C10CD5FB149FBA373AE32DFFF275CF386C3D7A04E3FE10B6F1A6F4782B4823242F29672E847CCE760BA005D6852A3459E7576A254B10A9A78A9F8112BEA39BA65898CFED1179D68211D98E6950ED06399E39433ACD898E2F6C87F5FB9D99518EF36429D447B0EF0C5B7D834ACFA388578BDF60D4B1FB5A0CEE7D1D613BB9B99E36DC9636E70A543BA6BF0B3A448DBDF80469494239D4B7C4979D82E80C08EF36EA67560C86665D458040CE31BA009BCDC30CCBAC50259E4485E570F190613CB010563F6BD24C2F1CF73F6A6844AB8350D23BBC3D1361E73DCE94AF83697BB817BA366C9855A754EFC2F007D99A964125682E6F5CF7FBBF687D221B5A0FD844477A2F87D5370F4469F76073A93AEF7812275FD4F70B2040C12A83ADE5E5D862684D119DCA0F75AE2B56C794968A68566291B731579A1055A84F083B3072B7BD5AC9D520F64F0829B592875613BDD81C11622B331289C98501B01EE1D813C0E97CF36878260F80BF88071D258B9DE02F3F90B4C12BB56CBC731550B5EFDE6D97A1283EEFE61CD6E5DF312D0F0153A32DD65B143EC6A3F2B64E2B8FFB47EAE46BD92A6EB9ACBDD11A2D730D027A3EDEADBA5965198FD59BBC8574B680B96AD48586E5B17625251BF4374E28C6AB956C6818183FDC119499E", + "FE69433233B6067B0EACF1F47BD3AAD9783FA30F684110D1152459233896479D08A976B853E4B7B52A34511239961048B7C1B9009095327C86F2EA291FAC1734ED2596EF19D04528F3D8F2A3430A0C19DA6A70A37DB6DC034BA0053B57ACB9E7C00ED9BD6AC11339EA169D9D54E6739B051AF40EE79A1034D6294261E1AFFCD61B9CA5016C56B2D1172D9B2A7283E4EE0A06C8149E5A2DAA263A5D2429C2B1FCE75C41887DD02E056EF8724645FEC6FE7FC1EF180529B1E894773CF3E2E1D938EFE9CD824D91454116797F5A84746537FED5F0EBF0583C8508EA0745B4989954EBC4F215BE3D515687BCDD5DFDAB9814358B07038E0CB869A8C34F916FC67773191679C60A15A0A399E224D0B0168439386C0AEE8F5EF77185AC847A66D934CB0ED6A3467C3B386BA7F115877F36B49E111DE49E409468F343A98974F4EF1EEEDD282F73013EC2727518DB46C6751A58AE3E0D5F9D2B966D4465BC5595BC31B2712AE1E1BF9915CC0E02CA7240EBB9A045F959E77DFCDADAB6248D58B47BBEF3C775DEFD629A2EED15201A21ADCA470B1AD3084924FABCDAB6B12FA6201E2A239AE8F1BCD7CC39FEC62587E58C84AAC15935D45261E3AFEB60016AFA0902DB98DCFE586513FF70EF4E3F47773635D475754A158FACC9C470921FB0186BD6EEDEFCBEE9C803118851F82CACBF8C0A544B0562E2E27286CEA5FBAF83AA5C1F97A", + "C7386F9FF39FDDBFEB223AD8B856EA2E7F3AFEDE197A61F183FF7DF2FD6DE208E71E6E1063FB3774B696913524F7488EFC2CA54E8B653EF5BCB7A8F4994E312DCEE99A316C2ABF3FDF85B8FA9BBD4366ABBD7B3D3D433C14710A95EBB3D0FCDA2D37A443D62A8361DA78ACA781CEC04542D01DE7B6C6D14CDD4EA709264251D46C42AAF404094286DA5BFF8E81FA2F8C54B172821054F4CED82287F29EA3D3AA798C9CF5C5A909B9FBA641A8D9E310248B0F9A1375CE4DAA98EB62286B4EF4DFC58B877A73D017B17AFD7F1F58D3D2CAD3B7AF2F06699B08B88FB4EB70D2511190158BB4928ED1735C94400980144EF9ED06E06074E2F29325C1AA316A46E8E617B3CE916CFCF05A389052DE120498341EE26A27A3D757AAE763046B8CBC841350292F06AFF97C9707CE5561F5C119E2FF6C137094F62573EB80DC13862797C3319158DDD465FBC033CAD81BFBBBB54D9467599D751B9980A9AE8BFC6715C5EA74859E6A10DB369D5DF83A92655A9A5908228B33B36F55DE563005B886EB324CEC4160F0D18938E9FE41D39234C29E13B814DDCD13CA6450774800924B0848735C5DE076F66EDC973FC83B13938811CD9887371470AC5DD985481185F1191EA8C1D3A7DC65E1E82E2318D0FF0C9AF65EA1515DDC536C5A8BD0AF481789838DA54A39BA56D014E12242600AC78D28ADAC3FFD3600E896445868064D1D2ACF22E", + "BF5202D3599D2DDAAE5F526B6B6AC469D4BA0D0BA5D79B1DB89173320F0EB68F5D9DA495AA0981F8022426F68519B548B19B5F8CF068A6CA1442AF77C83B7D8649DC281BF438F9576F7A719A902A860B9ECE9AE9C14B98859B282010A5DC90DCE612AFEFD44E0E9E7666A461AE50C2656BC036648B826CA9C3C7C53B30976335B097C19390716A41FD437A2098BCFA2B2975F1EAE5BDBB8192024C20136D2542FD89FB8F2F94C08F765109279BC4E511787496233F15F52D7C3BC3E98A6DC39AFA1818B9533EDE72FDAF021E2C9B7D6C74E49B849F372B1A131F4C532DBE3B63635E0E1334C87DDB6F3D73883D2B43E87CF19E40D6B404E581E807E6EC1A94F5261C7F7EFD4CF043C90A1A7E97465022ABAA1DC21588FD285E7158FD9B67EC5FE7C9E84029E961E045EB5227E4726154F4F057FA337BB20DDA25D11632A7995B810764084EBDE01AF07372EA82FBAFE0434401FCFE05CE8FE3C20C01ACF4E9B8EAF4D50C73D5C42A95526CDC8313DBCA6ECEACB457D9673565A1CC0AAE23FD6261A8943E8FB84CCEC676601A4B302A9CACDEC8998EDC847A53B3CB0E12C8B4A7897D5680CB14A3D11BDBF4826C3938EBEEFA0075B6494CC714D3C0DDA2F5F783CF23AD2D2545C899867C1115BF4A4F559F63E68098955550BFA1EF7771598EF86A08C0C634B291674BB77615121BF0838DA96D6E7C53BFE6A58A382FD9721CC", + "BF8903A3918B3FDC06CAB4EF675F7BE3962CD7E3C6ED643386EE533C3B24A3D94D2EA2CFB83F0A346FF2875DB07BA647492D47A807E7FD9717CF12BC97B3C1BE1361E598850B39D50CF7BE700507863BC4BBF26620FAC11D97128049BD96C5E09DC8FF3F62655D660FE66D31AB0B0F6D4F8420E3D2E633C571D7FE2AF1CB4E3BEE95E092B00EFD2796A3DEF376F75B7EFCBB141337D81AE52939D87956C41B1E42C1CCA4317D31AB4F53DC9502A3DC774E05E1ED5008CD931DDDB98DFA69960A6ACD45B60895C4FBA2BDAE8BC7DB8C821697558B1E0A3111F156738409FD180C5A4A33B24C5EE4991B84133CE9AC089724D62DA9D9827A2A04FC103652F216A0895E78A96086270814C2699F475CEFD6359428D8C505BBE8C1A96D2793802219144CA6B3EDB455929B39A3E9F3AB74D685608CE3F301FE38202ADFEF529CCFF46AF36DC24956A7CD07CEBA55AA4C89F7913A8A4B844FD8F152C8A823CB9888E3BFEA97D7E4AAFA07125DA4F51D974A5DAFF0045BCE5B868177A91BD932963451EE2673A85AA8B7D493BDF25BCC2F64AEC3150D8C40C835AB4F5D0B7F259DF099BD6FA9F5CB198B61018B1448035CCD34E7E7A2138F437490026050BBE3CE2D4CF4F4F095CB97548E5731A338CB3903519D6B13A029727F047A7D00904A556C883745410360FC878F77707A716D549ACD6A70A18F9EE0AA8A6EE2080608E10AC", // 25 + "F58CDE0EFE2356F429B0F2F9A7869A4142A6173188DD75B570F1D1ECD282E4AFBAD11370C5B4CCF3C98535D27D73C0111F11A84711F732441EAECAB684F2F0D7FD4FC4070749574922A906E84B3350CDE5957DC388FDA23BF45F05951A393DA253EAF691940897B57ACE655E9630F09856E76958D6BF7B830E0CB8182AE226F39D48036C867BEFA7E7ADBAD17C1AB45297C757DA4AFFBAE677B05677D60DE1D975A4F3D7EB3461B424B67B61025AAC257A69FF720CB9DAC007C50C69A7ACDBBCE210BAD4DC2E629A039D98E7EA037A5C344B5CAEDCDA035F28677A41D55A0E3E6E480CCB12B8F17062A983F4E651B4F7CB217FD06BE46747CD5418C0C81916465A4F5660152B3E4781DA8040D4246F9BC47366BF663CF9DA3BB247D9238873CCDC6FC62D1D8F669EFBA42527112FF4072262F7E65AEAC328871DDF47588A0A0DD13A4139F4145822A5917F624B881BFC354F37B6D59C566823F629A21C973324F7167BC39FBD2C121D2A849308D13DA1A28948EB59F7DE97E364223E17A30119BBC7F43E21E7DC3093F7505055ADAB4654194A77C1CCB61898840125455A275A8F071273D8C13934915D379CC603657D99CE4075C1F1DCAB60B6BD62ABA1A10B5402A59706798002EF30ADED2F354E38CE0B57900FDAD31E7F684E53D097B4313DB552EA66F6D337F29594470D3DC0BC6CD361831251004DD3C5357BC0BECFE", + "D9086F7C272AA317C64C00AF43C924DB5DAC97F8EE3ED2296252FC4756FCE6928BB009D4488B9BAB757411BBA52BA6F61AF1181CC7BBA94257593FA1BD26D52AD5014C3F1A1832FC4F7445C8BBB77C8FD31C88F0C5D4736D49DCDFBEEF2B8301E31185793BFF87CFD9E6F7E084D343AB98BA3518A87A5F915BC0D76B01AF7DC1CE45F1C5280BD39D3E3D94D0A0286F8BD9FA942849664E08F2BE0B93C6E3B89061193FADA0FA9485F62CA87F3E68E204186EF1187642D651162E4D8E7DA049F462362D8C94539CAAD09AE4768C96ED6C2CAB8025EBB6901CBB26865E1F19FA1B193D47ECE390B881233578950175C85B928582D5B439EEF2F56A8C7EA09278E47741051223AC182456C4FA04D025BDB33FA10C48C70EC91BC709E3CB0FA3E01DCE5FE5ECB9018130A8DE5D0583EDD68EA2EF227A612748B2F785A30A01014BD479DEC6256C8AD88470F79DE0E1432CAE448DD7049E5B7D4DF3C978F65E708CA3759AAB9D329C11FAD71204E1E92322E3EA1BBDD9D034E2A23ACAFA21CF490AA5E2E419197DBE990667BCF277ED61B264632F694392EF52F0A27C38E478257AEC8D2542938BF0713EBE60779C95A0EEC8F32A5202A849CEE8CE0F99702F595AEA839531D4CFB5F5A6166B06EB64387552A1F9BC6BB97B9B99D19C3D2E1E8E9B305D525E7413496E40FF50CF77D4D4E2D41B1D5929848FB2F1FDDA5A39DEA0546", + "AE4E3B30560A50DA55AB3E59FFF512844A2700D2D763D85D5C3FD8CFEFACD4D023BD926D3EF2E55EB1B3831F2276EB07E5C07B44FD7D79333699BED0804B678915FE0F092DA9A62F69CB020DA21932F9FDF9AF332E1B400C6B7E7880508E840D62FBA07E827A23A2575AE68E15AC444A1CE35DF3C3F7CA49DEF2966DF3BA89C8E90ED5E2421A6407F2EC51A3E92A3608FCBD6AD9FF9E5C7817E79A0C09FE9014F7AC291448263E4346CBC4BAA6EABFB59B4526B654070084F52B864F9769181DC6EA91B576956397CE55CCDDBE41F94E5DC366E775C86ADB1C807B66D08696A2BEE45B90E8736469A371F05929D9D9FD34980DE08E00BDE2CD0EAB6AF2165D76519F8F2D894AC70740D2372B37407BDA4D943EDF1CBD35CCE4D81340CC97751C568731C009DF65571F28B7F58106AE67279E83C3A0C130DE0C5B6C99117099548661D290C4CAF3BC60EF719E2F7B210FCD4381C33904AFDF96DC3A6557B42B6EE895B4D604F5F8985F454C51E32B2C874E90926CBC58D044D483D6D2A7C26C7AC4D190531F79993D07B2E830FEB99BFDB00AE8C008DB1B762F3F4A81D41295FDDA37F3056B1110D4F0CF385F9FCC7E14C34F6752A2FB17F5CD3FC4AF0D51E4A0AF7D28DB0D4D651156189209480054F8287266B1CB26C9E8CACAA0BE5A69C696300025D160F9DA29F9EC79838941459B7B8164AAD95577A0C532EC2EDB35250", + "9CF0CC00B5788DD743A5F33D87E8FA5733B72EDBCD61AA4B8D0B81213DB52E7EF17AE90934F5EC0711ADD19E881CC330F696179C1BA464FFE6D7B04EEC383A4106BE5892C5DD1BD719AB3739A909A384FACA455E6AF96600AC6FF809788700DD2AB93DD228483759BD903EC002D4C1278808B764F018E3B740EFD821A61F5BEA2948A653041FB31F6D5D0DE0A045DA366E44112C820FD7FA966B2CCFD5A6816AF84DC0A3EEB8F9D2F0A912586F91D50B1AE3D930A680A8FB7435B6875ED2E599B87598A7C20245296C4965E2E0CF372B6ED1219BA68CB646D3E73D52665AAF2E3D1C4DE8D264578299B166FA0E148281C877FA9B14818759CBF7FF575307E80B73933599D94EAD2FB1C08A30006330BF0AC1F1C0A4EE6B07F9F3381AD7E2E469E8DA9C2D22CFC0A208B58924D2F994AFC0268EFE206E0A9EB79BB51CA26FB49013B9A17017E0C08F9FFC6C319BB1B5AE41771443BC670EEB91D7769F9890A9B80F52CB0167EAAF850FAF2A52B74ABB1792E7CEFF68C0D38B01F244AC0CC0EF0731E3BDDCDAB89DF376973A7ED5D4264EE82C334671FCD39ECD6E2CF869493914F332767BBE461707166A9164776D29F5EC9291F505AF291254D7319AA594B5F397D5BDF00BB840C4DDCB425F4325ED8AB77E57BECA3441B89414616671692EA88A89D2690A4B5FE958F990BD84A3884A60FADD5DA57EDF01865F85829195460", + "B85B6E754CC8F6805A8A19DA104418D9C134C8B0DBCFD5DAAF5A71BC047A73BEDBC192A453674BC624959BB76E44C5B34244D4736ED3F0F3C9658FEC0DA5437E01E128795EDD7593D636CD73FC1780B37A381502633CCF2EFDA0BBB494C1D0FC7F602DF8C282F55E3828E81A92458EB16B74835040D8A9C8F2DDF180A617B0592344B4373E1B526C9706B843B0CED4D25D7324C6FDD0F33133C00443638E6249061C56A116CEC7822F4512AFAEE52CE8F94D8547F72612EA8C7D160C65FA3BCC92BE01493706EC4E5F203F0BF85C52F417BAF8AF490E50133505685CE63AC5B173E07D8DABB2D439C6DC18B41B9CF37D02C92AB5C2F27EC83AB6B2DDCB7ABCEA30A95BBC39E9FD0CBB28118823F7D0342F1EB7B45FA6BB3A50223D0D7B14E975E7658352BC9288B48AF1346955F4551F2ECA47D423EFC63D20681057E5EF234D061A5E6E234ED01F3DF223A0E8B4DEDDC552C7DC3ECF663D5011FC907EB4A7CF746AB9E07C2929B7427DFE9E00B0A1308881912635A72EA99927F343EBAD32436A9B8EB1934AC29E79BB80AB3ED9F5CE39D1E43C251564654365DA43FB8A0FBA27F2328D82445A1EAAED67B92716147E859064AC326A42DC7880DE82FA782AFFF9C59FBDCE088746F8CEDBA288BC8C2C4B458782CC9BE63A86168B671BE99A09F2217B7BB2A7BC88651C1BCE8A0B89316ABFE72B22722273AF570974D8EDEE4", // 30 + "DD40DD438251E401FC926CC6968393415D52D521A5BB34D4272D6BC7B5431062B35112CA709C0680CBB18EEE053AAD62B2391C9E9D580562541A453ED936CE8E88DFA61A88CA3BEE66CFFF801785CCE863ED9C36A04D2DC8742A81CA55127B44314AB4E687ED921B4881CB363AFB3CCE7EB774E3205D4591939ED7D3C0C508A31786421F49669E120F01D35D467B40F85F2454F13F591F3B830937421B5C8A6C20EA878971AEC941FD99CEA92FEE00E5DC2264987DBC549EFF3E4A26AF0CAD7421C4256D107A3E8908F67450960E4E41FD7E2E84F754BAC81C8F5F1D6F650DEB3E6EFF6059836643209E3880D7BDA701869208D8E4BC8D0614066414DB3F93D6EA187950285F55BB7A1B026EA4BFCAB4671B07704828D5CBF9730EFC99E68E91F1FE9664DFA73297F2D6BD9497DE04982C9FF3730BB6FC3EA2053B3F45DC7FB587BA19B3C6B7E780EA5F25B45BB727174D4CD3B401FE1906360BF0B15DB13B62752F82EC62226AABC83C1C26376F8366BB849DDB65958AD969B25654DEF1841518993033AF47EABEE3CAAA936F19E28A205F3CDDB5CAC649DB6A90483ACB63A24EA46D397508EEB5DA94E9C883EB0451D036E28CC303D52B1BB31FFF582605F340D449508959ED1FE2FF0BD22FDF77F9680D6B5647D59E7E6A003AF0C6A95092F0DE43D1252EA6DE00F288BCCE3ED9CE273DCB4F3BA7E8D17353B8ECA24F03A", + "FE38B1ACA366B4C15F3FDD4DF0E0274FBEFDA0042BB203A4F6627ED9E29F405379B2F2DDC0F3B02A0CA70A9499F3CE82B87603FAA347B7052CB5D13D9DE84C114EF3B8F62418FB1F3E374B997127667FD6BCA2E2F9DBC04ECA9D908CD37C62F08EEA6F44B3FDC149465AA8037D65A6C8B9B8B3D5E9A40578E5EA3AE1209BA49E5E2AC615C59A2D71AC1605B98E39A5E66A890754C7D1C07E06DE78632587BADAF7FAAB0A529AB791095DB0A708B691E9D81F2CEA8F07B05495528B9FD56F77A4C8209DB972FAADD9791BA59F47C06F241F50C0619FC04F8456339E0AF331310FA4DCCBEA0E5DC2795CA6B3ADD0174AE4B30AC0428320ACEAFF68F73ED11DC1BC9F0237BDC75F7F48BE518EB3305CF2BB898B329716FC9ECF7E99B510B3309808735FD0A77B15731C233998F9ECEF46E2CAA6E6EDC8D05B943ABD17027A80D636E535038FAE44D60AAEC5406A372D62479192FA84D844520C6774CC589FEE16A3A5549495D968AABAABFE4DB94F5AE0C54E603D6DA5C3056769A064890533EA8EA1E5D1CD410CC8DD4B1D7E0F5F787232439AA4B3911C5DC792ECB873E8105A1AA61C627BE57E809C6863073E1E19AD8B987DE97D88A817FB43ADBB7751E36D1F0E7B70B3759D6EA8F2350D10AF38C331E22703B2B5103C908E1D35A8E814E45BAE81DCA0530FC3525CD640548245C259738E749E195B006081A18C45475F906", + "961408BD52EA1C6A9F340D9109B2388CC358BBA2D35BB6AB672A9C16F3AF968BE4613BA6B13D115B896BE71CFEC4A4AFC0BF5D2BB1B5DC19405F40E60FDF361E6CC362CDC28B75B8C30B468D3BBB77F3FC62869FBB635A3F7AEA63420CF1B80A4B3813B2240B83ECE999808E1394DA2881DE2DE62C870EC163AD8D81495DBE2C7383B78E19AC506AED9F3BD1280A77F2D9C55600BFA258E76761391145D45F74253C6E14BAE16179884F0F0EEF8150A445BE1B5AA4FEDC2198CC39763A3DB473C1CC4263CE2DD587447DDA6BD0A496E8DF60859CFCDAFED2EEC5B1E77E68F449ECF129AA17395BA39392EB610DF45134571BBCBB26162C83FFE77D188160EBCF598EF6F092881612A04BA9F4215D429BB521E737F6C3048B5D95B20AC37F79AA99A12CD0469268228463C317A1F31E63E4754890F20B4516D179342A76201402BC0DB2AD091A70B4232473343FE9E0002E59044C5F3B6E3D7368DB7E7F9F42E7A4A1942B1161552C5C84390197A54079F570B57E8EA8A30659FF5A61048142E4368D5542B968966E54DBF91D3970B9A3A278B951D6F914246FA5CCCC20DE53713D4830AA86D758ADA7A8747FCD455B2C320FF9E5E7FE1CCCFD6F7928884FC0B35F34118B4E7E6F6A5D6E3FB4E3DF90CEEBCEEF9D7D595A4C456C373C5356EF0DB0E6F8D61E413F80E4C32532BAA39170AAE2FC606B7206C379C4155031AF918", + "E03A069F63220109A77232F2BAF29D345737AAFED2E5E8D5C846B937277DC88392DB2D55073CE063F5FFC5717BB89B481B8C86EC01808A85ADD78517CE12DF776CD3F02D948BA795215599CFCCD9B4FE56DD681A59C71D24946225171DC18E47BFA9068302BA428929790EE62306C5FC8C10E71F6F372105C9421A563A4DA704E01FFD71E46B28C6EE1B7CDF95BCA6A794E8CFCB6BCA6AFBB67DED5C1267A12A4752176C3C1E6C2F665194C7F11C1CE6CC8481A5A966719B57124CA33D8EC9862AE5485788106562A0BEBD3980AFC4469BB1FD1653678192B3022E26CE8788C68F202D506DF098D49EBAFF7741CA96A02BD68BFC4FDBE24D34770FBBF8EAD9647C911B2E6AA705F0236301162CD2B41B88BDCFC2A79EC54698276126D6EC0213931609985224BF515AD3221FB5E8A1C4CECD51DB4AFF612157ABA6640866DC6D3602C446B8C6EAEF359BC8703D5EF9FE8EC7F5F2685C53924C6F1F71519E0AB589EEFB393A12C06B906402FE0A2FBD793272BC101D3B57F10A52C172E505B74F2A00BD5D2F7C7EA2883908434C125969A62F1B09F42E578BE22C08E88B11767D97C4C0CBD2BBD98508AFD591EB0B0C846A95FB72159E561F9D87DB446E9A19AF378B6DB4DCCB49FF8DB547B3040FFD0171B87245CF73A0747287B6FA1F1E4AE99518E8C53DBEEA942AFEF75B69E4790D75CC8A5181C609BEFAB641E28C07082", + "D8D7DD9242E54C6DCDB2A717A6F33226A94D5794FA0BDC401F4ED842A5CFA4AAB462F703239F684DB9B95E5101A5DC6067C7062AED9259CDB2067BC815C157A7E150F8557C3A54DDDAE94E5C569A1E09C383A062B601F920EF4D957F4BCA8E329123BD6FDC3B731361864CC139EBE3C68FED0F40FB127D9D1DC071DFA1552ABC6703494A632AA1314984A2D4B7A8BB32C555B79DEE013A66745AE15E8E5E4E129E44A119203425F2ABF1F03CE9CB33C0BDC3285ADFAAF4D7B51EC31F02D1E654BB10F0CD97EC3E389CAA34398166B4D5C9FCBC6E957FFEC9CEE4071F90EE2926FACC8FDE884CC6FF1F6EF1D3CC681FB44E45C5CF681AAD13226DFE19E22CE81265F3088D193EDB098988B2640EBD8D9D66708E1E9880DC41A72FD3D64792B14AA18C13E371CA17FB46B21DA9C59FFA2FD075852D42E2A578744792EC02F9A35F869912BBB44DCC648CE6075DBDF457A9AA891488A5450FC719778739AF323E87F9633E621B404F70614F77C65697E71F281675C843C523740AB66756E4DA784F555B5B4D797A06A0AFD35A69DEEA6E948B9B3C2A62D7B1D56832D9CCF56F2680A5A0A3037F4E0252413FB86520F2815C8824975634C0889A486963A2C874638559E14F780A7F3E2318B88B2C2010174150AFD4BECE2C5FF2D37BC2FF791F4A3136E19C373FCF03E471DFCCED19471182A93E91ED3EA68C402234AB2B00ECF62", // 35 + "87F0D84B811E4635AE8023B74306DE789ADDF1CABAF5F47885CF7F9A33F2C533093A339EB0D5E05C0763A215459CFF0D31CA92573EF2074CE2B6A11FDD6BAA3C6FA100D23A9AA413BAAFDA22F746CF74562F9DB0EF2F7CDF266142F177681CF2EF388E2E9AA012459ECCA332B779E48CA44E536082D59C3951ECA42F66B600D2621BF5F3584B59DC0DB76EC66ED7D00E943BFDE703E7D5050A8F263366948253B3576311CE88B463791DFA6F401ABDCFD7FA44B158AA97EF1CFD7A8802662A633EED958052DEDB12A6FB353BF2224ECC2322937DE3D39DCF82650B18FC0BC2BCB8CC456141C9F3FB09A0906AC1EB77E50E8D260041E4B3FF4BF3A53F7EB62E0FC503E8E38F185AF795F67FCE17665AEE29BD0D5521024A70B61446CA4CD2B3DC274FBE72A9AE29EF67A2217D6CC81BD8831B5160E4E81238B379B657FFB49023B040B6D504B287F684A0A0C07304E6BFA21E8D0A7629BA32F3F2BC9A33DEE2EAC1A2C22462EA0D24162543945B78FB6E26B86E12621588735B32A4F9A50157F20BDB7A4B6D151B3F28B40A03CFEB3CCA635261ADA2295B74947F1B1D676F6C014AB362C1F5AEBB439DB137D034D00591235B6F8D11C735A0C1964B29D3002D5243374628FB488A04EF245E64F598EB6ACBDE8B87F2FC5D1ACD105460C26BC6E1C7DCEC2E92E33F722E0A613A86356343EB111D0B166AFEC5C7A44B81A607A24", + "DDEC47E0FE3E2F4205206CD673EC66D7435E8BD4A523A8681ED77F51453B904E4468C70C2224C5F1D01A1C5ACA89BCD72673F82955FACFDDC4DA499EFD8D18A2BCC5035B0C69D095AE0EF1AFDC389B6253BD6FC83D3C37E809EE732A87D065207684332CBB9BB0519CFF51B553B3689246EC1EA42E236773A5AC4A7BCD37381615F78A41E5B181AF5C502E22FE79436D6EEC07F7FFAA739356CD9544C7DDBC42C56BB1C965441903962703986C93C6F8135A8EC42A89DCB46E754EF5B5250E1171398FD31793594831B0775F2A39E63FAD99929A0F257ADF332C078B0B7E209229ADA46D69512FF2DE930F962B8F81EEFCFDD358FEF8E4DA0D49F39C43AE9D99D8052FCD60305FF4D9FD4CAAA3FA6BF258B867E3F266F1BCC77390D02132E370AC79B34FB37F12D102985950FA5FD53D3D4783DA5B284494EBFAB51DE6CE259E27712A0EB4D78EFD6573A03D629F29166B902795FC8DF59050C9FA48584F0EB69293C7FACEA8972098E1367D183C0B91C3550852AEE6721A84341612E820CA4F53C71A51774134923FA00FAFD84811C07620917C1966F6A26A032B125D76BFA149FD66EBD18F7536285CF94A8A750680D6BE0F4A4E7F2433018796A358CE465E7507F186752EA2FFB01941902129936F7B18321902780E2C6A5EA7D3607227D6315C570815BD0E808EAE242B554824ABAF30614CC72B74E647D5B5A6306632E", + "DB29CD5101A3FB7A651BAB94E0CEF2BF737BBEBF0F755AA42F1C0B2E6A2E00422458CD8E2244576F139E811B2469E1B8F10FD95A988FCF872607A9B5CF81EB5875C427515D8D6D4FC58F3C69A92AB4932ED3D1CE6191E648276AD746F12A0D7B1ACE96B80CD2C3B99BD1094ED29F7020121076A6E6D5D750C39633B00F3DCB4793A27B4838C492EFCFDF94D955ED33814C954FFE8B8D29A81C3C62BB2E95ECB393F06EBAB479494628027CD02E59F1AA32F78C53142137965E662DF4B3EEB0B92A6FEBDC91F8B31D41E2EF69ACDE1CFF2AB49E2A4B12C275A20439E30C690D14D4F661C81308F11EFA3D014009D80D794D9F2C8B51E2E6C83686DBB07D1790F56D7C8EE495657BDC081A63B1353F4C4CA74CC0D02CFD7BE60E063A33D1A4D9050A9100F0E181704799357532DE152CA54FFC089E8DF80F29DFA14C19C9D6B7855482622504F95A8948A5DD640EE88B87CA98F8248DF148AE4F992BC7D1FEB3BE07E70F22CC052D92FB263337528C41ABA642C6B1C6F8883B21ACDC69196733FFB684451D188107C1DD219AB8B0AE5F49628A1CE32FDBA4B8CF02F38513E37542D020F4BAFE03EAFD7DCCAAEE9E28258322E43DD47DA3AD625DC2795ADBBBB9FE061917573936E31DE6355023F8D74500D2D032B7A53630F37FFA80567BA36F771C4ACD71D76DE528FF47E8281ABCD325E4C4620D0B73B2BE2787A7F6F485492", + "E8F24D8DFB54C5BF909CA2CC5496AEA76E583D2D865259C356E64E76793290BB00E7029A146E1E90DC0C45356E13EF59D60F20F080A0FEA743FC1C222AAEFA3E55876F2C9E6F7BD29C09AE32E80B15DBA0E6B594E951EAA3BFD166DFCC17AFD2621EAE6539C74FD776BB998C24C30EDB3A8B6814DE088E7E6B7CE9A64EEE9ED8C9D987A21A3BF35A9D59171DD456D8D0D7D1BEB3F37D4A31812BE00077F0F0064DA56EF9C4D36D1D3CAB4D1D4C024665BBE1DC227DD29E1CF814EA65B64DE60ECA4AB9B19F937DF15914F3CA577EB3A6A0A2C8ADDA53DE536721FFFD519FC5E7CD9A3BF4F030B1EB638D6A0F8C4E24085012D758414211585EF6E0DB8C670064885B67256BB6AD7E12E380C5E25BF58EB1731E935899C1FD2B20008CF87529AA3E714BFFA86D8B66AA94811A43ABD868A7711C4FFB339C01D72D4974ED53E7DDACCD36B5F459DDC05E9D475D3E2AE383F6FFC9C2A0D1791B4675DA843303C96A98ECA88B54735293C4E1906AF30221EE71AB58F3E38271608DA6AC0A488C0850DD86F8B6588C91589632EB781637C14D9D24B57ABFC301790B3C11C1B2938845F08F7280388E0B9D5A9682A6FD40374542634590F336E42D8FDD92F3F6C82BE4D3B953CCDAC984F6C94D8F2FF70BDFBA63C922060C322FE34188FF70A37648C362BB68B06D74A2012050FC007F276A54882A8A04DCE014655AE43E448639F56", + "FE35174BF6B56B67D39271D92AE0DC2B64FE31AAE8D1135BD8FD308D7E281F3ECE84784423A48C1362B5852719023F8861E861AD8B22219259E357EB9CD8505A66EF7CCEB53636B47D38A2AF5506E1FD72D3E30A29EF897C5C44A271EE562D67B279806E8A5DCD78DE538D8121CAF4C217F8A969AEA50D6FAC68066277242B1979F1A6B3051CE5B9949A11719F556EBEF844C808E5C1AFCE5E312C53AA9DDBFAF7280A7FB8502D2C7D1B91614157AE0C6C962F868D05D0463131DC841169946B732F8000E686467BD5D8086CC249693FF9794374266BD6A5C8AFEC65C66A834012365D60179450C58FAFE724B8B9E99C33900A86649B04CD54351D6C4CC7068B28F070417CC9C4430390493BEA50799FCBCD7A13BF75947C597B3D7AD486E3AF99CDD743B6230BC473DA35E6D05FDD17F7CB8D04A2B00EFBAA30946EDA96BED467A45EBA54578D9001637702F1DBAFAD16D2608C475B8DC7994DAB93FB34DF2237E4A13D0C04A6CACD42FA9463674AF8ABA97CF511A82E8E61F8330004E165D753323F4AFFE598E4D108DD8EA8EFA45693A2F9EC8335C756393585E052FE5D150A58F058CF8C3C720F37112DCBC6324877E87541F06C968C46FF846CB512EFE65CC401174BBD1C977694ED7BD1702EBD2D1EF23BB56D0D0C1EC2D90A27CC63F0A09D83F8B0A5ECC181D5D4265911BEE77EB1DCB4780B53CE74DC7A42252F3FE", // 40 + "8FC54C96AC76BECE7284BB32C63FCCABED194E82FBBCFBDFDC6AD09AF95DCE6A5D6E13CC06B247E38253D359A6C0EEE00A660BC3BE6FB217B9B554C90186711B1E85117DF0CA17463E132333B8469ADF72C3BC6F218A96697E172CE2E6D6F4E70EEC2A0CB48F0A2E7991B1B90A85088CD2C59E3C9AE7FD939592C14AFE9A13829DD97E345D1AF92AB46BF196DF906BBCAE16F5A58A4D99C7D586869C81E182352C210E3B1EE822F4A95DD0BB3B285632978B18FC1CC29BD58C2152FD3BE73482DE1A6A79C3929DDA1D20B6E99E25A666AB20CD371A85DD20BF0A76C5A81041EC943A89A94AA64C5207B3166441FFFBDF4AA28A2A88173F280F3A2838A98667775F597D0368DC0BC53C1AB8B7670EE23E0ECA08CB09FCA68FE2153F01FCB7061CA1B6AEDCD815D611FF71868F50855054085AA1B7CA3309581532D658C7D2D6069C3B44E0E3CDE45222DD9EB40C369762CDDAC6D9A6923FE0EA7DFA1DF73BFF8B60EFDDB8863538A38528803F3EC27E09C87A2D0E160C2480F7D2003DA331FD5C7FE05B582DC9AFB114D2AD2F822922067F1FDB3261078F33879C497035003171165FB139F79BC508AB9D3250D1B53508410A01C35B53179076D9F46C5BE1A26DEAA2F9F71F442FD7D19D34979F6ADF96BECF1124551D4806E7136551291352748DD2D58443978C3DEA5ED0544E6596769A760B476B9CE7BB09543991EADFAD8", + "BA63AF12FA5F7D03F714CA9AFBF19375D2A7E31EEF4A9E10C7C2F8650552A6CD22FDE0E012D46CEBC773C87729C7E746FA4C0361099D4876701C0B2A16EA2B5A6B750CDCEB573DC711F95CEF06B8DF516CA2F9BE6387550F22502E53A772436F324569B25BBACCC781D30DE25B806D369AD1EB1D1137EFACD0BE765DF4D06E177D3E3F13E9A3165F269244FE8B130E9066B23474418A5191ED481BC8974074336E71BEB02B1BC34CC620BDBC24CDA8BCEBE068416E5F5B5A263A51CB3F6589F77D4E607939F7A0FA637858B96189A014B5688A9DA32FE2ABFC31FB00401DE475BA07265B3FD1890ED0FDA487D7C616E099B4EF4E47C9F9114E6BF8CC757C92C02C46546130ECF7CD44160F55A72831692A5E69146086C43A5F043BD1184965E2A6B154BD7B8BFB3B4B28C081B0F349900492C703913885428A82A8D2EF1240414CC0B6D56D969BA1A121D9D61584C6A880D533AB58B94C85F07732B5EBEE7FC87FF3AA279ED703858957A1C1501D71DC5420C24BB2D570F7589F0AC5B6EAA87AF68442FBB38EF693D2200E73DC73F58CFCBBE43FFCBF76DB4241FC4A7B131F29C8BC0F77C95843D2FD2DE39E3D4D44237DB39994380C5F1A1A3AFD927F6B736D585112920296B90CE31D58BCAAF8CCBCBF15BB36199B48F00F308F7E8264D039D6DAA6E848CECDD1544323C9654232F45689076B7C4B1123AE0FF152124E930", + "F2CE3D09E701F60716A413AF06E14E6FB7BBC29DCCD8273A083B00D429B57EBE9FD5270EC0C299D243A9FF0FF73DE19977EC16C2772C6B7FF88F83481924C921F49EEE41121DC79B7C23295EFA50292B11C7D45D66BCFADC3C3A390E03E13CCCD51309BD4061782273CE5D0E1BD3E11271A3C52654D2B846B5600D3E68D2C234807BBC32F1A350839500DEB6D387AECBFF5344606CD04BE3614262F068FBD256B2855EABD5A7C0AB5C28D5719C844F2A6FFC500628CDBCE869D2F090E588B57B796029A84E2319FB6E59960553B62BD30DE99AA7ACF508168EEED8DAB9996041BDD78BAA2A1CAAD2EF366F4A3244DCAA3F06EC9A24572CC80C3CF44B557CDCF6279165414066D6B700DAEA8D361034D9DE455A55E55CBE39898B65651FE709506D1A1FF67585D0D3E1B2C5EB599704B3925CEFDA45C33D92C9ED9F0C45B7A80706E6629594F66A0F74A4A767493B73B23AF323D519B0D05EEC62C6123A0829CF612DEDFB7F275A55F1629DC64D2F77125A1BDFD7B9C213C51DD9FFD83DEF42E87AD4E0F9E5ABBAA6B120E131F9E5A3097F7EC766539C733522FEB0F02604613CA1190024CC1C3297E7CDC3C514F8C3787943EE8CE457B516677437B2212A19629A0A04B0DAB8258A17B28F52BCE915A680152225304301FD2BB1BA2A557B3E3CFE6553CABBF79A47FEC31DA590308D156C3537B97116224F3E21EA3841A505E", + "AB2F844287488AB6B0F47218F2A4C54E6BE79A80F1209CD747FD88A575EBB11F2F0756E2C263E753D9388876E159EF3BBF99448D0865173572F4B6A03FB72244334E4E861E0495AAEF15276379F8DD88AF9313096805D5596446B48EF1F1BF2ABEDDABCB1FFC98ED408846D85732F807196C9CC9B283EA4E0D78681C73CB6AF89E5C361476F84E979814F30C0AB03E97156015A493E091EC5D854E8B08328581D80091564C25D6A714407D6B591F17D376953F18308B8BC12EAB5B5C9FC11AFEF293109785CCE29C978955CAE2601A1DBAA274B72CC18CF27FE077A0123258A1B879E1ABF84458BB10652CF7310278C7FA11BDC5D00DB65E5D6A13D77FBF9D02DD0574DC7AE3849C7C47820126FC99B9766920516AD1D63E7EAA366005714D6C1695E731E88D43A38B615407A99B32A101C4D417D5E36B886C26EA1CBA9FAB0C040468781897145489121EE47BB2FBD6A064CB325AF5CECE5D5A4BD590C70C7A9B068D318247D8FE16A3609C94A8D431E9872E26A3CDB19DD971971AE1FBEB2FB76F7A71AFC5815CF7871BB5EFE3BD0C49BAC441ACD9CE1DA4AFBDB972659D13775AE77F843259EED57A62CEA93FC449EEE1EFFD9AA2D36D8FDBC06A95A6AC9B067468F1D813F2DB95D3456063D5B23395824385D5C68D3F869C4F639962D599AEB26FE2D5148A51579EF385D31E744450E11307F0C803C70ECCA93F831EBFC", + "9B1066F98BA2299266D8C1351E6945D7EAA658BCEA46D5AB353C2CE48D01E915E740DC90E9CC487126AF9FA722A335FA1A8D11C2719F07CCA23B1DC5E5B9AB198077177BAE0B5F35C14666FF32926AE0239F21811921C77FFB56F7B218A353F8EA67448F61ECA318196B1186514D27416EE2F61764940A70300B69EBD02719191ACAD969B1075EDD09EAE26F883AC99DED1AE9355C2F30CC656934C0175E824E76947F83D791CE7A2960FEF547CD3BA94CA064659D1F68C0DA8C13AFACC07F3D5A653F259DD141E2ECE9B6D25F67CD38AF3F802CCE332049DCDAE1504061C2437C7D3BF4E15D88185D4114E96BFF7EC673A7AF8AFD53C979C89FEFACDDF873686D892DEF5FB67877734CD981C16684320AF392A464C7216FC5C8B22BC29C8430151FACC94AA1513A08E1FF2F6A965F68E368245510B975595EFDA4E80B7FAE432FCE9737962974905F367FF637121237B2A404C42A5A9318DC5ED9CFBBC2EA9C17A6CA37BBD98F8771CFA7EF58B1EEE40BA2D6C2031EBDE4AF0590AAE8FD10B2BC02A254C97726521E4D4D4D9FFB74FA5D06F8AA0BD43631FAAFFCBF01FCA87C9360C5E6A62A4B025B894E2C30F9003D29B642335DB0A3F2A3436A917B61776F96292A06A6B4DACE4F6F0EE0232E1C206427A0386075BF50D6074006D45E3A3CAB085431032AC20D2690F0435D257D3E2C93FAE49D75FF0F320CB4D348C6288", // 45 + "8A7F8C99EA79E1B2118E3B203F72FD8921BAA5C336B006ED66AC7181575D66ADE21D00FC8C7DCCA7DC9E430D1D086F2922487B5B025AD38750B4F60993368D829CC361B600ABA990E570370AFFF9BF171610F2A0B0B93A0A3AC54244073A0E816DD691BF1B0041BDC165125A14C621E01C8F069C3E05F48FB77E66A998C27A87FEAF07B5912B303A98AE5796F1B5D4E2EF52F38E68F0EC5786C19ED93612D7152BCF0CA1A3044898F9347FCA8370CE6E4A0510750DF6A42C1C35FDBD91BD2A26A60FB229CC35FC45525D12A092505D901A4F9E1E8D42D25C41B8FDBA13AFED8BC5566D4F3BA13A779D7BAAC1E25B6710D7718B73A641F23E1D22CBDED3B7BC3AF7D92B2DA1CF874D908CD8590C80F1D5055CB8228AD964DE099A4D037202C65D197A35D8A268D8A3BFFFAB39B93615DA295A09AB979AF925D895CB60B5DC5580055BC4347F0DDCB1090DAEF46C8ADD1009A5126362B0B4F1FFDDAB4A00AD8290EB84F76AA345DD73FFF7733035026E3CC1D99428CA68ADEB8CBE98E4A630F99F4F33E8AB66895AE7435D2E84EAC95CF19E9B440373EC0B4D4B2CFAD672C7FE1FE8CE5F34F55B016F8B115FAD6CC7B53DA7555E67672FBF6BDE324AA09FA18F13D9FF1041A12B04F30304774B07659F397554E66CA589D9D9F1F262CF659F718CA7F443B8331BDEA8C3980045562D909EA44E917FF5D47812A0390139B2A87D0", + "80B35D641CF6EEF705D51DAACE1EA5EE92057FD497B0D937C7CE9A546BB32DE580F8E434D644F191798A518785BFB9471AAA5D03700CB0B7B2635A6A14750F03DA4FCCB1B363C254A5294DD8E7943E4CDDA318C4B92B57B14EB0F8EB250686CE129BBB2B18EBE7FF53C9DA9C0B664C527A3C69D905CC6FAAE8BEBA7D83294C1656DA4B8308968EE49DDDC2D0C71A17B02053027D7DB8F4E77E3AD1C80FFDBD37938876B671D80E99F5F1C7BAEF50B7E05CC0CAB8979A3A2A852A7018673292CDBCECAABC74B839FD3C084682357A5414E431C1F25E34850FBC779285854FC6AFDCFB7B7749E0DFFF5F93A8AC146C873B407F2CD6CCB461312AE35DEE8D6D51347B0824156DDD60762807A5C132C0667FBBCA7489058C47A156B2A50CA5C24B894C1EE7C44B87179176905B7657A8E95AF7F2EA6C6D2A12384CAC9E6D14253DC5C31BB8FDD2462581C109D2DAF72238E4B63F436DFD7DD5571548D2206BCB8B837D8CE8C9C3B3066E46A1655E3D84AF42DE1051DDDEF438821E0F0C1EDBFE148356D707036B269C19C4CEF4C4BB4048364E2A3886E38B42EFA15F22CC8F92D802EAF3FFAF9BF45247DB76C03E99F662884DC2A29EE488023BF0EBD46539DAC307410846B25280349106CBAADFD658A066C3664E35C4C696726140275AF7611D2369ADB8258EBD2279DD24DBFE002377B9A3C1B120890A6FDF20597417F88F15C", + "ED6621A6BAAF64578BD988D08FA8D3D2873C87C38AD7EB38C0922FF3F7E59F0A8DE00744698939D42D459E6105ADD3C77E9FC4911F572B3856C9AF6C15ACE704F026C6B2FC8BDCD9D84022DC10C47E11E934BEB7E1DCE8B6A2BAECD384D810BC3AE587E7EDE57CDEA908DDB020885624BE042DE0ACCDE1511CE38AFB6C9DD812FEC339B8137D88108F07035A3869CDCFCB9402CF96B9E331297B644DB13DFA88F60605E067B9F35607D2D75573E0913F8080EF603AC4B7133D836B84F32F48534237CC559ACABA53A96885D297CBB572BAB1C3275F7CC7A3AAD10F29E727B28BC29B038F4003F8C93FEDC88C63D72609A5330F36F4986CD9536812676A89305C6CE58D4C49C088B5E273F2AF77A8D31D1B8574B9DF02CAD4930D7A7F76C067E7160ECD1A845FC6A3B508708C279A2C94F29108FCE34A63E5D5554FB530522394BCA00508DDAE6039ED9F47609781CC60F6E211BDF29E6F44ECC873DD24F1D37E49D7BB7D6279FA7B9D08B5FA8F9364EF6D4C8D129A5A97A8BBF17DBD5E64C4A31426881687BB79285B09290DE61AE40C295CB1BF3C8AF756E88068A777ACCE3C4B6E78C62AC1E8EAEBEED0AF3153983214D7459AA8E254633B52E5C0ABF4647B906AC50A62543710EE92B335A7162B540AC70F2B2F49FEA892BD72DBFC5F7A35C3AE56636AF2887BE680FA63768C27040E888202F700007DE648482F5307C56", + "914BDB196CD56E3B7D7D3F1D7A5E4B0A1389578F111449DC2DF643E6E29F688227C3C07033C2A3818342B229F63C229FAC11EE1AB6F0FCE8608E03B46DC983318DF15FD8DBF2970EB342BE2E534BB0455BE58290A48FC60973553E94C4CB53566CE0250D9FCF055936523A8ABFC9287DB9DDEC54710859DF62829D2B6A100358EB64E6219451868D6BBC2AE4DCEA0C0E338B26B748D4A1A34AC16233046CB7D346D0D79A3CCDD4CDCB435B9B3075AEBEDB4C0F18C5DC006F5C208D882308510C75E729D08C779CA99D5A685E78D5628094AD137BAA635B7FC0F492C48A9CDBE63209C8231455012EB3E830B5B2A79ACD8FEA8016243EBC85BF5D6F46A48FE013D2B3B789BC5F743200BCDE03995BB2B6A640CFB099788E380B4E01D75409A8D8B3887DF2B1CD34960091653EEA6C52EDD745B9363BFFF666891D9C8BF511C3C07D38F49DA2892DCCEC81E1722F6EACB3214E3335C93E6141AB94E5EC31BABF8108F6BEBC3E60B1BFE37579B4D5DC8B77A347940CC1F6BFB5B46097B1EEEC4C354159BB3475E05FAB6BDE5672014D9489CB70DDF537F7209BB9EBF1FC6B8B94564AAAD5ADDD83CE6E51EFCF73DC6080D738C4FF1CBC87ED420A0B92FA459AD7BE58789F0A191D149F88173184A22874DF6D39DC1BCD4413648B178ECB03F8358547A68DE7B672BE9BA1FFC8BA392F8A58ED2806155C00F86B7669BEE4220D420", + "97051FC67ACA30E8AEE73D3A8CF38BB13524D4E0EBD9BE68398C7C16227CABB1D0B0A0ABE7B6384ABA02905BA0C3C7363599D059C7B4C99DB165CD14FA12FA7912449CA7DD5E346D8010C85A757382270DAD15BA3CE36A76EF55F81A1E80BF366B37FE3A88EC722028C25E234E624040450A99CD808F942568AA7133981D72E7F2928894670AD5399482DF1B90E7E64062F830B736C79C30F36281495C76699CD48404673FA334F042F9E0E67DD7F3853BF71ABEAF6A9A5546855E840CE42B224D8F6490C6CE5FC02EBAF4FFC390107058F54CD635D4A7F2878099C1EF495750E6921BE2F39AD808C4210F287319F811A254CEF8CF153FC50AB2F3D694A530949E5F578D075DB96DDCF2BB90ED3DE09D9CA8E08662FD8982741DE1CE0A6B64C3D3D5004B5C04B2B0DFD976A20FACC94D1762D41EE03B40D2CF367612812EF4CC41D1BFE9CEB51AE3A22AF1BE7B85A057D3048D0E73FA0FDAF1119EFD76F0A41BE63128B22D64A5553E9549D411483BBCA1483EF30CF6A6D317AD2C7973EFA6D4C1121F703D2F48FCDA3177AD450D75D2A28D2C244AEA13F0E60AEED8ACBAB444D400DF5E280DB799B2D9A984DF1E2567D39D1DE58EF78CA6B4D8BC172B07DCB02D156CA96EEFAC69E556CFCE0AAB617C7FBB8C34871C1D35E74B7BD307D3F2E424C7A9AD676A1A69E0FE735EA50887A1DFAE6CA2FE4460FC7EF323ADE493020" // 50 }; const std::string Galileo_E1_C_PRIMARY_CODE[Galileo_E1_NUMBER_OF_CODES] = { - "B39340CA1C817D81EF4FAE4E95BF3504A7709089FB48560E9E3EF802180E85EB2194E05902C6C4C52021FEB7EC64FD416BCEBC8E39D64A4B5EE345291911AB8204A888C25B1CD3D9342A56C538636D3EAB957037D09E879AE5F3A39834FBB84A3D8D5090D7814246B62E9CA68533D2EC403B4FB9488467FF9758B0D15A8CEF89187A1D5897880040B6C3C5244E85A2AD14BCF2F5ABC44A7B1D4A87E8BDA05766218773ED4F70F8D1D07CBB1E8CA6298E64EE6DC5886D37495BA2EDB3E0B0B68AD9F300310B88898DDEEFD484538C31A9BCAA76ECAD0C16607D32189058B0862EE9D70CEA9D304755CE8037BA4C46C2573181748A212E4B2BDD04F9BC240518273DC17CBAFF21A03E9120FA7DCA18D56DD1D9A7E510C90CF219104385F531F2EFAFD185ECB6B911F9B7809D98D86F15516FFDDBE9BD1CF8662EB777C3F94EA3F962D7B79449FAAD39935429E92CAE5637E9BCF4E94D413D27934952409AB536BE4055AFBC4330CD1E4B5509EFE5F8EFC9ECBE9EF377DE7E37C479BB9D3EE7745E4609B0A6D2C5D92EB3C9E2278C1F2221FF907596AA5E096ACF8990EBA907E43AD320F8019CB6355A2BA8670EE5A4F463E8E56F8F1D3E7F4922510FB668E32C4CF23AD8496399638B095B47833E0CBB34977EB3E4242EAF870D86660D6A73F83E45D6E8A41EDCA3815079649544597C5C43B6C93FEBAD5700D22EDAF431FD340", - "A64F94BB47BD4033C76D4924305907EC1F618B43C7535F3CFC093E5AF5DDD5C4339F3BB6D835B5C2C2053CD3D5693368D4E1A7CAC59425D1FD96809C67285CFD3FC05B01053CB0773221D7205778022F487BF99D1650566BE287FD7AE882AA8E8F52E5D4E3C0C2F971C9FF70AA378691EBD8ADE45CF213822D09FD05243F9726F6C69893845E57C37A7643E16B770E26F431FF69D437271905D270EB85D8D229D7D87662121F0BEEB1E895ED9589A9CF5833408A04197AC9025D8570AD9B75DB7E192EA0A089504996E9DC652975D83633619CFF80667D8B519536B3475248BA8213C8A4C66DE69B4B3774BF9142425C57F34A27B1E288119E3FFCC6AF6A21087F9394F09DDFBD42F32D059B8CD4104A519BA640765D5CDE490E62F10E695FBFD33CBC9D2208A532C8EC25DA28B8CC1B6850AB43D9B5C00B6E74B7A148791AB07B328D347058C7E6233E18C5ED172C9F9E9ACF29D913E2A1614BFC0893D4967ED033B2B9AE6B51F908F1CED57C14FEEA85CD4D9711216BE7F79FA6721B7DCCA033C80127AC6E5FCF58EB4005EC24CB4886D787355362D5E7031B9B2AC2A86D730AD734181E723A811FF510A4DF868001973FE83288D78E6F9B9441DAF5BE2974A2848FD917C3BCD346A431922246EC852E4AAD467E60C15D61DD3BF4A207BB57DB45DCADEFE3210BE74B9DACC918A394469F2E2C95AD1E211947948FE24F5E4", - "FD1F6976002C39C87187C44E3D224ED4DF0B67750105944C651A5E57798F168A136AC0FB5979C4E847A82B20A2E6C45DB42EF2B930A80D3257BCCC53EDA966F5DCD9AD47CFB226EED9B62A874E9F6404D4087798A1005F4131171D3A47907A3CD602B83DABE094D2CB031867DF4595F3ED59FD8C4D76EDEEE59E422CE5C7D0A5F720BE94FA24DF05F758348EADD5EFE9197C6BB2292E2B14DB8C6DB24AA94C5FF0F5106D2B566058D32C58B63A150784F7B02478D9973DD4CFD2E84059AE0F4F1320754B7EE83F04A51C67EFFC2EB1C301C0C58DBAEBE95474E3484A76500103C14C40BB0B7D3A04D8BDABB605C1EF9FD4A6564934DEC50BD5878243AEE80F9796EED70CE1B1E8B55725DF76472D12D4A7A487989F42E6705818B1F7E149E97153A7B05A82FA3FBE51763E61171A4E12931472E94CCBA74CC09483DF93623FC60945070FDDF3A00B561650427E4BD64D675B1EB398B35EF057A66FD0B48EDBABBDCD57C32ABAE46F5CDD0CB1FCF17765258236F3DE40BD5D0A3C5C978D81DEB07367AB20B2CAA9834B9576161C4F20FB9C184A01DC9021A4E92B71333354E05BBEA9015E5AC4C66312E8B79F0B92279AC7EF1936BCC30802B83DB3D113BEF64452CAD7ACF6674FDA44023A661019841A101BE80FDA4E3210AE774E433A9ABD97F2755259AECE21F7A8C3B1A3D471F874D2EEC85B9B21BC0C2E2EC9016F847C6", - "EE38BAF6F61704B01509B5210A0534E4702F93190C392E749869B5572BB7AC4D7120E2BECD6618CD376C4C1B4965F7D9D73400824E88A5C7B5B66BA88C3E0065F9628A9AC6B91A1882192FC553E3140349934D20698C9F291B5370948AF6CC90C837B9F3607F13CAFD492CEF1723376E6A5B813A56301B88A8799519CB7646F33F91C44CDBE7F768D7DD9B323A5002D2F784C4101AF90D6E4C5ADE7D085C79E827D43E10DF63AC70BCDF13DCE0471B487C5ECB752B9C3E20F75DBD243790C91355ADFD7199081BFEA03D80E82445EC2831FB5014B85EFC2A52748A8ABFAC1BA3904E178DFBAB26C1750228C9A031104F58BB3B91905EDB9EADF7B0F6DF22ACEB0DE944E277809D77507D18EAEDAA1767697398421115D04AB2EBFC466E99F0AA540482A49C6AC8FF95E3F962734B03EF39873A93B70470B46FFFDFDC15C89F8FE2F4637B59F9BF9C5752D9F8AE7EA75D1EAF1C22CA27E5D5C9499624105D61BE2A691F9194D277414532A5E6C63875F7F20DD13C6EE73B0C3568392B14A5042843926472ABA343D2C427792199B543BE1D43A178FAA7ECF53B98AB7528D8E1B8B82C52D973CA0427636505837F94284E8D6B4F496FC5A48B7958D4681DA00651B8A7BC56EC859C071E4396A05F33588B8087EFE9635E565E6B5A8A70DA70F50ECAD1A85E6E36FF07B4FB3B9119EDE0B611CFA91D9D4C58C1F4815B07B9EB1DE", - "CD37D0FB0043D03444A939E93676B9DAF5F2D19A2615E3D97D624E62ACAC8098099FDB9A5A2F4B3ACF20F75B6807A5A3F157C2C0F479158F4A10FB4972855F3AE2FDCBDEEC00A4D470AADF5F5E571818AD6E872D897E2DDC402006965ADF16582B1E06B1861BF7D0C7E7BA491C79E86224AF6B246317F725FA74DD8376D63D7993FE2F2BBBB2F1DA9238C6F3FFCAEC50FF61E645FADEB6E03F883892C42CCCF904708B123C9271A670D4DCFCD602951D12F5213937CA2C05ADDE9EE3908E99AAE8DA31951C36D36D671CD7BF15DF60B707F00BF6EBBE5476926D015628A85758BFF35C4AC540F39E761B2ED3CA9116E8680E28BC387058E0F69345CC6AB3AD160E9F2BC4D6047A1934E15D3D7A242A296333C09296981BBF3B8577E4B8ED2A3624866111F6638F8955431195B60C5C089F9897DDF0D34A3DC627CE337AC8128C28B63A394908E4C083BCC4522DB8CE5720C45EF76B2716225E53405FCAAAA72AC198226575D5225195F106C1249E4B87AC05287A3ABE6C51A2A41E07F56ECDC46E989A8568D35669B525A6FFCA90DC91D3013967F6A5F4C022FFCC17751B68FB0D8F16FC9229851DFDCC060838F923BD44C1AD70A993E8EBAC1667DA80F91B66F8F5B375D35275188E3C7702C2312CEAC5B20D67BB34400401BDF1DBFE79DFA0EB73F173A04807215DA5CE8E1D28F2126424C3DB44ADCD7A961260FDBCAB31E", - "CAA02DD19DB9C721EB35AB7D64B8A387796427242698A47D832C3F1AD4DDA0B5926FFCE9319EEEDA1565ECB0FA1EEDB424414120AAE8CFD0BE88D4D248899A0BCE31F9BEE7A4DC4DB3C3B10444FAD6ADCCE28F0EDF7B808536ACF5EB05AADAE92693EE02C9512B3EEF000844BA35E24620A2E8935354B8432C07C8FD615534BCFD0D8E3B572BF2CF06AD343997590FE8B244A32BBE69125B5D7C5E513A493724EEA8DA6CB0FFF3ACF1C5085A8120694CBC40FAE1A6326FD71487CC3BE7C10A34315CDFFA8C618B68EA93D330945586B080381F0076351B888087F56B969E6D6A311AE03CC79FF6861E715C9DA9AEE751F1220661581C75DCEC0515A1C9259B9CF8E944CEC4B1754E5809E985D6F43FE45710893242ADE0D3B84F1E1942B7A95648611595FED13F546CA11DB8E5A55A3C3C78C3793C6689E1B3AFB5F67526A480DF923A586A779F94A09CF963594FF4B0A387876EBB3E8FAB888C97F6773E7F0317B038E47DD7D109545BB07263B1AA84284B86E47FFB9784A171D101E7B0A6D38BCAE7E63D827C999BF551728FFC642EE690B01D486CB6EBEEB9D5C888112589EA5CBC9BDF49E675965223416D6DA02D2333BFD4614706BF13373973207C849A0DE41EBA137FDF79A1EB25D74E30CF60B577C2787DF04740BA8CADE3F9DA55D3F0084F02809E37543239E0A71E99751EEB21CB3B41488244193A4868CBA9276", - "FB227530F82BD527E648619E532D7646A5ABBD15DB91A6E7033DFECCC65D095A3D83AB77EDD2F3FEC52659CB3AD1BEB009D7A1C9BFB544291EC1C67B75DD6DAB06E70C32C714983139DE4A41EE07B4F3C03BF566558484F19A3BB674B6795F0D8537BC31BC8D7A38B2FF1B2EC8B78539B2251D0E385DE484B05A411477681A3AE7527AC98BC2943AF1CF7F09ACF2DDE4530AE896BDE1266FE916E833A1C0CAA2B2D2F5985AD47B2D0D1D3AFB6E50D4B3DA7DEEC4385E6CA8FE22760F92807AC55556AAF7973E8016ADFD43A3919088B768351B1057498D2D668D7C1E8C63438055FDF7D36C5E7DF02FCAFCBD9291A2149E7B429B3202D329E47CED51EA5771772E308C5BEBA7B934597540D83DBEC6C3BC61A96EA4CB2D7530D9D760AA9403338CD95B829F17547C5A90D161F7B8CE0037EBF403C91C0D0C70C589BA87CAE8DF26CF14281E235A686CCD10E2D520A76265C4C2780EDFD0705E89EFE3C953FE760DE45A8CF1F2D3F36DE3164D5BC2CF32204228ADD7C182EC55F1158AFA9358BE179C722ADAF1D0BF1306A0B56218857FC5C21001499F61E273442281E585B3E6DCE148AA97B6622B23BDAECF983BF186F1B34962764758AC3C20C84036061D49CA33B3C3FCDF03F47F7E53B940DBB6E1E4A26702A118E525A9A0EC229085C925D133750ED0B200CB28A113289DE143D1D5839D2AF8B0525E0027F34FF32106A", - "9E5DA18A19514CCC849E9697AE4BD1B317BB34927D0461A96A7AF4A5D6C13107FFB9DE38C5E8CB7C5682827F57D94ED2E77D36F9F1CB05E4C2C62B1DE254C7B1CB236FC4ED70BF8DD1F43AC773C16A37392B895F8B157578C477C85E53FA7CA58BE70D9187AF5F7A18D5A1E5642335E46C2F8F4691AEEE6A9692E21B9668E2C083D9F45C2DB3E991588BA87A0A23808732EE39E8B3C876BE79227C782F07EE3FB3086AF913D71D71910A0F56D62B5DE5E224F7856A42A4A1B2AFE380827BE86E381FCE486FD08A91B22BD91D09615F417E178C5593E41B0917E075133960AD28B4DD4096D1E84BEF1363098DDE92C29CD508C40BA7E785F46C1E0DC72E729D394911DA919EA6F94D14567FFADC61CEB8DCA2821B1CF048477E2433E9DC718DE618EDEEF302CDCB5DE472656D6687DC41EA34C2BB4DF1CA08DCB933BE3EF4B419158BA0B68AE82A64ADD58559214FD88A4CB34D99F646310697DA982C2FD4EE069DC1CB102125C34A89AB20F17B6EF648A834627320410FF6881C7919AE4E71CBAE5F8200E523934D84BFA897C44B89B9BC6BC0129F7F97EE0EC049BA1AFD67D00CD624A75FF5A30514399BE4801CED057B498B9DBBF0EB9944295D5B6AE968C4B8BBD2B9A9E17A3039C5FA35A0D30AA54CA426C58353943DDDD3FD185895C0DAEE950455FC131F520B46AE118C7406D0A72BE6127C5307730AD441B6FC3D1E0", - "8589F8396F5B1C54CAF2B17D4C152CEF347E66EC7903C878F2823D4ADB9E7CCFAFEBB926B7EEB4AE1BECA339A027CE8EF997957532FA871F356E0326ECE0BCE3399F81179BF78C5C7D135018ABC340C0BE58D3063DD7CDA4C1918A0187BACF830C8B6900D43B62E04DF6E831CFEFA13BDB5E873A527F24327C95DB4BBDB65C81A20F959F828F5DAE4DC13E5CAC7417EE089401FB497ABE10144E28EA383E61D4A9B63B618AA7CEA4588B2911EC581F506062B05E7BEF723A5A465C9FBE70E313753BDE3102845A79A206BF7D996F49A21752D534B73EE83B48C1A225F85F5103DDB9B6B8380F61AAF26E5CA643EB62EAF58AFEE0D3494E4F7A4F642A3454F4F56A406A264148FF5DAC9DF5F151C12E89ED9D4FDCC04EC5F0022DF8CBAF3CBC67CED2853FB4F8C5894C96CD00550950E7EA2A26C80A72DF533270A0E23EDBAA4D0BE935D62CC885E1CCE653D66C51E49C43952042E1B2D043BDA1CFFC1E98A3F806EB587A4EC9AE299BD838C68B9BBF7C420C12B23AA2793FA0248C932A91BCDD641DCB38F0B2D7187D8986928DF4602B381BA13B263291134628FC91C8EDE92594B39650B877D9A91DAAA05295457DFB2C5D8207BBCDFE16AC5B93600E33BC970B38E18808B1A732889320352B524B109560136E605D32784CA01F8B11D077C81EAD6B7A5741C82D76CEEF764FD07E361D531B75106AF1572AD1375B2BBAB68", - "A3E17A4CAD2ABE76E32D18501899F8D60D293BB1AC3ADB64F81148AF56741790F87F8B7A2D9A6E7645EA50B75514C394508884CBF9E320B24D41D8246EB3C163B9101240776C312DB63C33889E3C1218435850471C454486DF7FF4D2DC0AAA14980F394CC8EB7B828A60C53A2FEC3315BEAEB30045B3E65006C6EBB23B47A8A069EAD45E32E771B9C467B4359EBB681AB48C891ABB796544169178203BCC4BC6B4A278DCEFACE5E9385C059346A23DCCA001FC9E47CFEED4BCBDD947B12A3F7E5FF8B9372D9497EE1A508D8BD3392BF3CFAD58F0191B18F6A300FF9CB8D914FDF37B48BF24C2C5CA76ABDFCCF833D51D48FC90E06E7B972944BCBAD169232A8429B6100BA562F7F3C55A625A1870A7C7D7BC9BD4C4783278CD95D07F89E8010E78876547F9AEC44322B0029A922B2922634ECCF2BBB47BF87909C494049550F1E6D03BB5354DEA7E777F499D2D6239BFA5C1CFA536F8CB16F4DB9EAD96F83A4AD34AE2C6893ECD6994C89E7F4FE426D95A18F93B88CB357996B8E5A34C43533EDB1F28A8162FCBEF03704FCCCD80C32874F345D34E81EE813DF5CC9B9C299362F8443AABE91BD0EAB9746E431804B6129FD32916303A570323FA121F7AEB2829F2A50A82CACCF6D273FFBD7AC6FFC5807771D216F50742F7091946F91460115989C87E8BBBC8402B4C8B95C102CAB53843D581FA9F16C0ECCE8944E5FC4BF4C", - "9D7B1CF0029261D65AE1F021DAFA81CF1673C9E0B47FF2C37D1B1AF46E7A91BC5E529C8F93EE3BC74E92B2743AAB1EDE16A6523B5B8A591C617C1FD0150E63F3B7EF0494162437B0FD555A83A3BDB519B3BB209EF7924D6BCDE5992BA6248690442E72CD5EB64B4C3D3F7DA339108A18B61AD88ABE87BB7C85A3A352D7B882FD683B2637A17A2D9CB0B7F41456DCFA66D62913F145600BAAEEE7EFA5071C3C9E6FDD0A6779A737071FA6965978CBC89776386B108DD7216FCE962FA87A26B29FE0E732309C0124B0C1E99E5642E5EAE670005B078C097D16C58B8923633C18FDB0E8FF8C4610B789387ACB5A2DD0B6AE7E0DF43A6A9E8C3B89C7E5D628D59759C58D07E0687812AEDAEEDBC63B4FEE8524D10E4B467696957E6791C1E94B13CADCD0ED60752C2DB1B65E035EA72F89FC679138D3609FD2A30E4DD1A946418253C67AA69B07EBB95D4973F562CE3773430007A6DB77271D5F2B342CC5E76E115178F9C7B1600554F5C794961BAE81A5E9B621BA17851008BED9B556E461A553FE9BE00A40891750E4EA4B475216283B530CB8D479DC70B026E07889229F6017552AB9E01EDE6703FD1E2D59AF0B71E0F1DC9A42ACC5823324BEFC52CA0DCD25FE8B10C999152AA3676A30602D3506F78751477033DB7AB1A2EDC21A6FE51273B6B2890088703CEFE74F9EA89881896E5BE124B1FC9430B92F0C0568F5A068A80", - "F23088E3EAA0A6BA04D0633AAFE85203E8B1829223FA6B730F6DEE6799B521F2E8323B8793D0F7F2BB9305B3EF4F5B4F1CB822836E4D92C8E4928A851BCE688329DECA6F7285DCC85195E5BDA3B503B8AEE6F1CD7FBB158444E7DE8BF6A9A3CDA311787755A827BCAD3DA5621908EA913C0316B9B52BFB07ADADEFF17D3766BB450DD71328A0353B09DC24DE93CF83A2E5F98BA9D612187B601157D6B140E675228B58C9398618C3BF0D11A226E489366102B9C35A916653F0DB36711ACBA5F32B327F5789F3EF48A338E4676F4BC2C6A1308597171903D2AA299CE7E523C2ABE4B15AA4FC48954187E0097583EB099419047244B4931326E5923B6313DE08423DB00866374ABBF5C31A00542CB97CDFB8F71046AA2A6DBFD7E1A71C068ED70E8D7C3268EA3E0EEF2262BD7991B6C59FF471F73A4E85F4FA015E164F9C15FE0AA5F4772BF2D62B26D3EAA25CE83EAEC5EB3577CA83A68168FB64C40A7A155905CBA6E64159E55EBC928D125E55165C639F545B0071EE3CF1A3F58B4994BB4BF50C2B24F2E06E4ADC90BC1C0954A257D88444347AAECF136C15242633463DCF984BB6736666E38F1A45150B1B7D1C31DE06EB9C2F4097E9D9B4D21EBC9F3A918000DE2449DCB3F5FDDC3C773A645DF560F7E013E847E2356D33EFF1E215782638F58034B09F4739F98915BFB0B1DC124681492F58021670D03CBF5E8F962351E", - "EB07F9EDF03596ADC2A3B7EB6DB1CFC911E9A4C42336A57309F7B6C3389282E557D94BCC71827D7C5737B1C530D2A087E3F507242F3DA5BD1BBCA4DF8B78BEEC1DBF7EBB2EA1CF1DFA79E60785BAFA23658490C9A64AC61C45779DFAFC6C55CB5C9FE457BF47E45A3FEF092E178ED4495C0357B459E95AAC82132FF1C8044F4EC84EB882DC195D9CE996B1CCF523098E9E1A57C37C2E2D0ACB0EAA34B0B56FE5A0747130B1E75AA923F6F94C0D024A7FCD22E7A4ED8B201966C417AE864420767AB3223BFF56C64D4F8F557DD950F7C50D9A39AB2C742CE686C8F92B35711904C600A9D4D3DD83F3DF1ED7DB8042C76B0B7D5D9BCD6E0B5524184BF99D8D0B4F14967FA48A93A2F44E2275ED7E59F3991EFB0CBF2E26AC1F8D9A41AAE4563179254BA37028867E68C8179454B8B71FAB49DBD1F889104CFB64C8121151364BDB64BAF854B0DA22B8620BD7EE3D4302A88A115F8BFBA649CAA9EE7EF5BC95CFAB26503A9D26033370A4EF3CB8A5D094C63305A833387B4F8371C6FE1987514BB458C571E6CB5DF5FC900631652D3FA4444F8F1F0312204340FDB2092F709FDC51D2680753131ABC33712B4F1067EA1CC87C40B281E69209EDEC42C22A88950E9C1CE8130DA9291897BF2D8D1D106911743E7A9DA36220FA90A02A34EB0B28543217839374EBE79F40B3B612236C902E4CD05CE2E1C07F3DA10E2AEE8E387494E", - "E9D537A821DEDE526B441BA4252785779B54DE76F82747F8607B8952DF990F268C039CC792883B1C76C297D81C6C0CF17DA8BA2C71110B16741728725839D33B5942BC0A5614A3650675FDA5D70F29154A429A42819D6EDE324C64596F93E84CC9B2C9DA3717AA6DFFCD03B75AC96543020A9F2024620353E1364E4320FD44933799FFF083E73F5D20B83BF77EC2247964ECE442C3213DE99026F8FAF0E96302EC60067EA38C5CA0CD989475205FA38869E349FC7F79EB81F8457CA3D1A875A8D166C96EBAF1F39C88815E2258EA1A14943298DA39EB9B738AAA4E0035F9567A0A9D572785594496316D56EB3D39E1F3F243D4F16111E194FC537A635FAEB2FB4401CAA9EE0091CF3CB28B366CB5446A6D3B10AB86B4B1A0714D107FCCBBD50EAE520D56A1161E03849192F5096346FBE5150B6D04025A564A43A3D22BD4B7E10DD4061CE20FA2ECDD36F66BAAD7EA96CDBAA0F063B814707718F47278F8570F77F3B15799D0E354CCA50DAA38C31C746B17482297D9C089FF379454FCCCB8730D89B1462AD95426370AC37DE50B775B952663B97AFBC403F6F729BB9CC1D21DD89EE78AF09DF8558F7E68B3711A7D9075DD4754174802F52CB9683FFE746471C7E543FF388D024327D1866CC5CA6775C58A14D70A3ECCD3EFAB52F9AE6CCE146766A8419FB546E39EB604F43B15AB88C72741F8C7D0A7FE2F462D360676D6E", - "D79D916241BBE52B61BE8210A02543F75A47032E9C0CC128524A675E94D8F79A69B6842B0C5CFF5C1AC98D2085299BDBAEA67A41C724CA36B6275A80D377DC3A6EB4C8D0B6B88241334A95300B53FFB546163D2889D7C85F1D1397924F126DA76085BEF131A65C7DDF60DDF4086BD33B44D25025D689FF41E0C256EA12F4353D9E722EE37907AA8BED0A5A606333A031AC6B9A16614250916759B72FE6C1828BC6C1966C9EBCD51413A77F41F808BCA2534AC49DB1D32D37878DF5CC0BEFCC099C56CAF50D8B92E7CE616AA026EA1D81DC7ABC17C4705F9B57A0F99FA749F30F93DFA982A083EAE6582C8461A11ABA74B11663ED7D66EB4F8DE14F090EB1CA6D8D81CB6B063A391FD354DCEAF7DB71C277D0E92B4B463873DCBEFFB698BDCA17F80845EFD5F0FF150ADDC9D7797E21E4279B54BDD4B7C9D403D9FA6101604B79AC377780A5461499714082942313CF74AD1147CD10571A31D82871B6B3A055D50C6CDA4BDDF3871F41EFDAEBE8ABB995344DB6366E35C6E506907AD7FC76632F99124A58A32C86360FD6DDBF50324D86694518AC44F1FA19662C0EF0C0860811B5B976A96EC2A1449E53A7E4A07923E9F85794F228E441D92903922E5783F2FA21C677251B6B8DB02AC2E242C0C8652E0C17C9E3858E52DE78DC712B2DD5D2AF9A42DB2E2BEB3FB6E0FFF13DB9A1E02C8F84FCEF3F7C4D2DDC09F2A2813E8C2", - "F8E2DACDD88277D482951555C657B3E3C5DB79E5A43500F7A2C8B30C854DBE611FAC1087FA03D439AC4635D39211E234B82A91248DEE5D4FE67A02D5AE25C676E64C4843E419EBB3C4D81FB606B9CA0836F8207CD19D106C0E287EFD8F8DB5C1A3A22886C2765FED26B5189153657B7C47D5590F11C6340067B800669B05A0849BCD2005DFEE6DF95833C9E94328D72F931D69CFBB2BDA81AC83DD660B3B17D2BA4023491DED324FC4F22510ECA4A5194B1245F4F3FE334DA9C1E6BF83A3FB30897BE54C688D2A7C5845F425866F25DD0A9852BA6DAAF8437DD80BCC72B3E258A906DE079A2D33EC5C5F6927503BA13158305DFFD3F86345524394151AA557D6242060F276BB6BB25586F632942ACF5E0883CD3F8393688F360323A000B82BD89414E9C807994B0234D730BC6D7CD0A2BF75D9F510786E83EE98D4CACF20EFF86EE9C38B8D52455D8A694B689F0D9A632E7A6AC6675E190A12ADD716D2C6322657B878FA97267C1BA4631584356768EBBD1F13FD2F37EBDCD1DF96FB943942E8A5188666235B455BE2F770C9759A8F070971CBA49789744FD2F64DC4DC6E003B3F9BEC7617C7EEDF6BACA94D374400499CA6813C90A03DFE2C537261DA93A1C0F6D8BA93D1EB5FB17255DF28B78737582FD675D056A4C474A71CA8EF0D77BAEBE5637711AEA3FF2B014700448C3D74E3DF264D773360F45CCC3342987169C9A", - "94741D7F05B0CA50908E6BC14801A28E353551F01769451B1482FAD0043D5C72331246D9AC3344F0FA2E28FD00E86B38F5E0452F46CA111E92D01B37E966455DF1374883DB8B055C4DF25B42182280F86D0D825C096018D2949B4BFCEB7BB2C8A5BFA2C79E27F11A7F9B43A50AF928D81FA95CEC86A114222B99786072311025672AB04B2593C5AF50100B71D052AE268FBA992BF7868E58EFCD07A24D2111774A36115C1C527B5192EA955722EAE849EF83817FE8595C96EA2D76FECF6476D89F65A262D94B3F5E89A5DE8B1A7333EFCDFDED17FE1CCADEBA0D1E7B73E67491B413A862E34A308D5C211787E6ED8683C6E1DDEB8EE2D281166C03E7A72D7D7BD8B878D07D2216C21B855CCDA76B7B75DD1B2CB876E59F91F040D42B97050043499DCFFC65AF803E2F7455C9669DD9896FE1F62227936DF905835A644D31130A39479DE75B4DC4361E41202D51D50E0E4B4B218AF7F5CAF264DCD060C296E777DF1EED6AE8147E9B6CA73184C345FBDD89DE4A999C42AB4681D9EA3B86DD75031A33DCDC807F8FB14EE0CE61B16068AF01CCE7378C9D965943476AD21A469D8B0CAE15BA8FE04971FE1EC61D3AAD3386DF71B33FD0B4F324F3DA518F0CC0353182B3D76CF4EF5AB150FB9E74C28234CB3D907AC81CB6D3B99D510B481E1F0423D6F4987F5517ABBBEEC07F46AECEBA5F15D91AEB0FE91490E91F739D465225C", - "839A01464B473A64A3D1EA24EB363EAAA590F4BD0E4492FEC4E3D4DB5883E4873BBA17595FF48134893F16F5C4A43659C46484A268C3303B2DC345E8C98FBBA6D06946F997074AE15680EC9423D6464585D98804B3541662E183F6540503BEC204749D58E3DB9ECF11C80CD3A38F8D66FFE6CC8A003BDD35F547E5039DE9A21F70A8A07B2DD89B68E43B42C2E021A11909817C543F839E6862268E38DCE712B4D49C39A5035F3D6BA19AE028AE70CCF557720794FEF6442999E740CD6AFE6235F165515FDC24AB6F578DB2549C8065E008577FCF8B8DD8A3BA679BABBC9A747A4E2DABD91501424E4191097E689A741EB6644A771CABDBFE6B74ED3ED171DF8DE641C1D42213B9D0F8CAD1E11FF63670F5587F1FB7FF92276AB48F31751E7A591AF4F0966F3909883EE6015639671BDC3D1378750F66F5DD165912CFF1A54ED463905404EB7D3412EE2B0F0D9E6B99EC81678ABCD1789BD8F1D72D3DF8754A16DC2106B83B325807E27BCBD22A25DAC32F27EACAB6A4CB6CBA4CC90D5302BE5E9827B7AB48BB696B2902975C48B3A4BA4630B14E0FD8A050B0718C2829371BEC597387172B0B3192EF958BD1F7977EF9A3A6C80D53BC961315F97B714253B9731A017BE2CA1D43024F75E26BBE989C4D514D01538956FE4B90BE17B3407B55BD08BA50FA807D0E448B7CAC65EB3FF856772A933F0C5F3E6F41E051015C6F9B8", - "BDA2B72F0BB0265269F198207FB061DA29DE43E30847E7C062A581A7EB53491EA51B51EDD36F991D15AF89AB53198537988350FD5FDF8E003019BE115840B9BA55C238C3CBC72C0E24E25090A3D6A59BEA9FED0FAC9EAD40451A95649638FE0BB0F8FFE61AF5B9A8AB84BE84C65EA1E12E9F6650ADB59A824E608E80D1FC3AC19F418169B3879CC946165511D5AA280AE644AF360C42F7A3EEDF27E368E46480E3353E67F536E02B33505341BAF3941069567B723D7C125C8F066F9A6255436AAFDCAA8C554FDAFB0A9AAD91F1263DC62EF91A748FFB29F57E325D65A38ECB4F2851923DC6E9B7296064148A9BA2D938116266C597D9E1F11A46BE0EF526225BE750F0F3E5B0AEB7DC2140FA3A48B7238D0F5A872000782CB6F7751443EC6A1B7FA1ED02B9ABCD1C1DE4FC85E9B405C7851913C60F85582B1529276AD475AE52BD8115B6E73A53506E7A0244E1C29BCEF4CF20CFDF883392BB3990BE2A11B3213B68EC4A166C77D724CFAEBDC34C45ED09848A994BCE1FF6A9BB80C7F5CA8FD44D3FDF8DEC8BA6552C234EF8DC52382D52D2B01BB23404FC453725C7C9269A785FE09C712D4ADE7072B66295CA0C6405D9859E134FBBD3737F2956DD1D718A9F8242CE95BDB1E49F265EBF19976BC46E29F7DE0EE5C89A43AF2E107588A46E1B6762E6F8E48B8FC4F4FF93EC60938B8E5C3719022C750C4309FC62ADA4E9028", - "D240216C5C4A70742CAA03AE910E8859C92E5A90A352CB8B45847BAC7793E1F75720D44919E896AD4581E1FD83986FF235C9834BEECAA1556794BE49033E79D4CCDB4DC67C5200E8B6A3EE891E700B348CBF092E4D3FA5E648B620E34E491D7B628A1FE7E2C45586B6577E50788687F0858C10F78F371B25C712ED2760C3D605D4ED4F052E8B66FC308D3ADD4A9B86F00CE4257EED085EAE95FBB1E113FCB42CE12BB6076178A20903C55DA570EF8A25BA7AC8B7E134B8D4E35AB172CA33CC97294A5E7E579B9361B92B49B63BB1982740015DFEC16882989C917F50D5FDD9166FE1001F3282D3C54A28AC7FD773CCC0634AF7CDF225F94107C169D2F2BB757EEB55933CCE0FF116D7FFBA992F9A075A2439CCB369D5B5DE460CADC9F8C81D98E71651AEBFC2A918C551082D85F75675CDC8CCA1D3E486CFFB3B025D27C8D67C451FDFCF59C3BFA163EB791152390E9488C604B9B8116C329453A98F7A104527BC677411034CC49686108E569B7595E1DDC85918D90BBCB337855860D6E4718C0679DAB6982D23FCB6648E8561F44BCF9B052D8B58384523BC592C9B7F824B96AD1A39AEBD2232D6D34DC171E8FBF933900960F207B55597759D23E1E794507586114228A2FC100CC200D2B862DF3F26E6D1C9370373FE165C326D8C29FD2F0B3071AFD5215781BFB589F605263FF065B7A5CA3F6AA9DE3FD8BF5589BDE3526", - "8E7752C52805DD0A723D61F0BBE0122DF576A42B5AFDF9F196A766C9B3BFE296DC16A892FAECEEDD8256D2B1AE6BFE5437D4A2691803043B59862B30D68E4FF94A0700D735CFE967299724DA9D680200C898EED1C785E7B8CEB14F1DCDC73FC625F9678B407603587220C2FDFE0A47E82ADF36C26F942797D608BA6B38A3AD1A967315E1F2D665B27D51E350F075531A179DB2EED55547EA61761CD2B3962FCB347279117D1C7A7574B49FFE0991AF572A2B0C962A8A79800CFD524AAF9E6401C44569600F41F04422DB891D25B9F714713086BBFD0FB268E66A4FB10C0ABEEB31D0FBFBA20B0E4FFF404051596FC6F6C8093AD01807FA52041CD33007B205D15D47AF733966411A36F4C7B846D0BE049ADC21B89EA4CE0FBA414C005E66F36FACF3C43B474D47DAD78AC114D0171C031DFBE4A15FE1A22603CD79B6BB448B67A4DEDC97262F7B869C54F385F3682C744ED5AD6C0B6E16793920E6B45A024010896D5FECFA111CC9F0C34E728B32F2C4D45B8AA69B621AB9AC3D9D79B38BF205E8D0D19FAC44A76B9F5644526E06858F76B3EE2D74AEB1971D6B6E68B83773399AC32203164564B102B26C370A9FEC673C285AE0D1D3DF239D48B6492B89846EBED4618AEC940DC62AF4C3FF0D56FC9FBE23EE3B0A4890BA2665A88E9F40C4B6A770F9630234ED10A3A7FF3C5BCCBA836F3EDC8B821AB18D4B1D51D9962C328", - "E682E9D8E92A7837823C9B7714D267F9CE290E9FA6CC0A8432D3F7507DAF6CF681246AA4C2323C6B53BCC6E53B31F49742EE5F4E6F79DC36727E98B06D0300ED21F0CF5F2B51D8304A51D0B498F4BFA39C0049B8117DAD334D4B2E37676EC42DFE0EED63B3726872CCF9A10223A8A4563BE8AC266E0697004921DCCEEA5DD80C62567FDEBF2AFDF030192831A6FD871F63D5DADA4B270AA9EC0ACE47E75BD19018CB809B548D4F2C24831C384DD2B807852F596BD4FE32CAB3A16899D0B100E9F96D06AACB8DA8D51DB0B0F600F3B614461F5238188B5EDA68EA753B6ACC58569E841BAF92CEE04E6E2626B1FBD01B9B67D1311B1C3D67427298E2D193F0647EA17D16FD7FD6A40A1BDBB320A1F5FC64B97759AF4EA92AAEB759B5DD30A726E9B8EAFA372FBD83CBFF0000CA75F219A95D6A3CDE38B8DFA9281609A20EE39B73FEBDF6A155359476D073E7153BC918C1191C9BAAF0E0F161384DAD8AFC31A3FC1E9EAFA495E22D18C05194EB85298AB0F042E447DD627904B73E6E505712DF010531C88E695F6510C78B443C731D7FDCD62EB7C4015AB5D530BD09CE5229FA4DC5642AF176C39D60FE070DF635CC5435136C7BB9C4DC83B0D382B9BB636A6C2B3838542904D53B862585FE6EC8960A9A77783D17B2D90506F5D60998602AE5430E86025C8864883CECD7CE51B49CC2953A2A41D7EF8027F1A83815BBEF6F6B2", - "F6BD4204243CBA14DAA15A256FBCD138B5D875E28BCC0BA36855E648434CD04F49935C3D074DD5BA2EB82AB14E82C30991A1159E990D1D36DAF794853A23C499AB6B3DC02A89F014310372813643F786BF19D3FA8C463EE50D9FA87107E91C461AD2E5DF2FC99630D2005894CB7698123111FAFC0C5BC9D1E8E84FCCA5179A6C9AFE3E369222D66854F90D2668A57FDEE00C300AEA4E88F03F05C4D7695B206DE9F7E1D429E5E6B65DFE05D4C861F4E7844DDB9062C0B6DB46B27AD0368992F54A44829DD11A05AB97BA8AD854E428B87F20C4E5E4BB1FF3803809A81F2E4C109572006729A5E490E0AA40BA55F4391C9FB758EFA79B97E6D413BCB02D33A00DA6705BFBADED66CFC21291C494B7C3293810012ECC61415E609DD97AAFFDEB795DE36026B4602DD546A1AD937F1A6DEACD3393F5530C48A7974E2882CB327AE600C05A535BDE5D15AC524859582EEE2D62194B73E01643359E7B2625F3EB9FE7137514ED549A3196FFCBC8072B4F6C18CC67AAFA0ED6029A805EF0987E2F27A3260F849C68F3EF91DAA9E579AA16FDA698CC18AE8706E28C6D84CB3F593273D763C2969933D8EFA564E8C06C427809E6A5A6F76DE7C8B07FF4EDDF6CF2B7595066DFB15F5C6F3839DEE642FC86BC1F3AED7ED2E65B665198AA034817DBBBE0FE30E662B2161276CBD969FDA05AFD6D6A570C1E3CF7E324634441983F257E2BA", - "A9366308475F2D8D0C2D451C4A65A01EE58A0AF19B791D97382EC59A52616C7480B86EB1D0A83E93224B0DF73DE1D7EE6D51088F3B20B7937E6C0144E0DACA6324F0C8E5F9D93A8CBA1045E5B509D7DF98619FDDFDD7892C3082D69008D9D3ED6C9C1367D9DB7C04621D7CDD8A5A2599EE45B87A82F8CE8D60293E7A71D11700CA9AF117D630C5D8B876A9DCE519BD653114448C68B265813C608435B96CD642A420A15FBAB467692931BCA74F1F9D23F5BFDDC5B8651139B5A73F04FEF3DA64B7BD56E49235069EE5E8A136B921051F1D1C7D5993E6EEEEA2D58583152ADCD87AA89CF5962BC8341EF99CEB3682A2D0686602CE140ABC2FDF79A778A9D75AFFDBBA00C0BD6A8A8AFF9B5D1F30C8373572C81BD9594890102F46B5A393ED126C36AEF6A66E231A246FDFCBD3DED198ABC54CF357ABC67AC83680C048932D7C902AB7DB16952B3C95DF4E845B46A362FFE1A27CD1388483FFA41AA563933371C0180848F9E3C03AFC1F00D6ABA29A953327A4E3D9FAD4616C8546C9AF89FB4D08D4256923B736A8F68FEA5A097E0640C16E0F7F942E6A6F5CBA76BB00D81C606C7FED908789A63F01F9B5FC7B7BE434E85A0A44B2070BE71AB2BA0132D9D7B32E2D2FE229619F85643E75B4141D355386D1A09F45738455BC21607086C7BBCD4B73F87DD83E905BCE8FC6C5BF1824E904C4F5C26518B2FEBF8EB06B22437270C", - "92D87BF3F54B0445C05E508E80F9CBC0502F0897D717CA232004362F394A023BFBFE3322C1D331AFC6454FC756FB48768693FD5C46DDB40DCBF14C726C24ED67D8F3EB613BA80B0E39CF0747DF62D258613640D881E085C377DE1C3D149C8359407C2C6ABC0D2718A2D42439A8E7B38CD7DCED72AE750B2BE88D0069FBE94BD69A9A4B4AD42FEC5E651A31F86B90DC2FEBAA6FA6E5F6368B620C1750278DF393F7C5035D47897FC05FBC419A61330135F24365F13D653D77CA2930DBB05A3815FE83F75BB1BD8B2DE12A2FAADCD1ED62329C55B87FB32CC8F3B42D888981B4192480D1F57CEB0C55897BDA6B9C0ACE1E7E4595E30C7368306243208444FCF4574C47B07725B25EC2E28F4C50B744B3860B361DDDD22D949AA94EBA4F97606FCAD91394B6FC0E634BD15E099E697403B2AE84CDF5DBDF36D91FB82C0BC12B984FEE83CA9E97C194CADF8382CECAAF49EB3BD446F660F94C188C074CC312E186BEE0F6585535B050C226659A94B4C4974DA32CDFF30DBEB4DEA588C6F490F7432DA5FA2408BBC931EAF60EADD7B891A61C157147B8DDE7A45F909BD20D5B12009783DE410940245FE4E91ACCF72942E486AE773CD665912173EA29875A1722F8658C414CD08CBFDFE1DD356E167A9D7B20BF7441562EE816435A78BAE7E5A5EB4DA6AAAC36F594C93E2851D76B6A18B0B03B30CD38B97E38109C494C557643D58", - "BAA2716F115D72D2037841EF9138D19833C7C5FF40F058A960826E690315577710EFE64BB37691564B3B0B6C577DA603CC3ACDFE1785541AAD23904758A5A13BDB018E7169D479A1FAA031CA72FA6D6AE9613D6B2F82AB07500B49DF535F86A76350C140F9CD25295D6BC2F38C5D13C99540E2363862F06DDCC486D884999BCB840BCCAF2AB84F5906B9AA0F77D6432F6531558392641C52FEAF9D8ED86BF0158134129F34ECD0768BC02ED442254515A74999C6B8052A1FC797F5720738C69DD9B3FFABDDC8515CD279B246EA7C67754920038C5A4C8D301119CEB95FAB2765DE39DDA84180CEBAAFBF4976118A8373FF6BBFC7FEBC3CFEAB1DA69DD3DB9E428C594950FD51F4D98A393BAB96001461F2765834ED70C60BC56406CFCB3E784C59B91C19783E67CE6C86713C43DCDA9512B2E7173AFC2EF9A172C9CFDDD3000D7A981440AD994C39DAE6FC0B645BA0FD49ECAA19E572ED0FAC748EC837A7D6F28A8D004402F71CA209BB9403B21E29836C5FE897268DE0736E985F9631DFDD1AC59D5411E684BE082F41108E33D2B92B2D45ED70FA52EA2D6DE121EB9F9C886DA479464A9DFD9970A406491E334372D7B78936095A7459BFAFF0E9090C2C6B6D62624A79334F879A5C92C685B50F75F04BA664EC95893FF40D62EEB24DCDD288729D0C297DF5ABB83C77FC11D0EA3EF18E3BC7C2C065CAC51390C610B591D24", - "98CDFCBAD056240E180F347C00912F2D9ABEBCF5464D410BE6A50404B830F744D78F7D97180404FB3BCCC2288B7991810B2562C4D509200CE1F9C4DF6DCA4C600D9ED49C9C1456141C7B71513E728D41970ACDB6C15B4A4E327B9A87ADA73D1D46EB0A21F2F5481C3B42931C51B780FA526C29B98E6B9C714B20049F7A05252CBB84B8E36026DB2379C9632A0843436ECB72D15EA2950ACDE18DBDC6DFB01BF08F7E191EC885F11D1D8B7BC96E9836B395108F6854545082A694D5974CC36C8A658349186C1BA892DAA85D3F156BFBE94C73BCD815E7652C38E178AAF02014F0E6F23A4E7EF689EBF3ABDCCDD40E2DECED316F07E20716927C8F7B203D51D957EE6EAB062B99ACA0D28E0AB50B516CD92CBB9BA90333E73D58DE0B4B633D81EC93D15EBCCC813EE63D63BD18517F4FE85C37469574B8122FB91388123E1D5E805166FB7157494F8559F90A4FA3DE9E71DA6FA7CCC6086E638BDD4FD3E4487506ACCF84F1E1678D714B86FAAD57A6B76E085CFAC30DE469BE32E2D203C63B43F073DD24F4A1E039B941E7A97F8BB28B516217455268B6EFBB0E1745C23D6D12A8CD13E5D242F562F56FE92496342000A731BF3DB0A7D3110705DFD0D8DEFB85665B77347CEFC8629F3757304F6129DA9845F6509FE3D32DE9FA86EA4FA9BF86FF7CC8E726C0FA9F93F889C467642C5E944501BEF8ED59793AF8804A9951B4B88", - "906F6C5A1D3BD03A03802EEF5937E214E87B5E2F0182BA2C258F44B516EC66EACB705E06EA6DFDB56600B8463A421DB03A51460091D7FE889E6DAE32EC19190E7211F08D37846CEE7364B6ECC07C1740CE990141C4DC4CB0AC9F25CAFCA6BC9111102EABA250ADFD505201FFF638B31A77CCE7A1ECB273F9C8ED84EC2F403C1191596A53EAD823421EC47DC5E78F3BD1339532C97E4EAA024CCC906EBFB870C1467C3D845A178EB07C11BE8D57E4EDEA7ADEF162923E9521451B871DF6E357DCEEA7F62022106F647DD8A23074AC10AA632C56DC32B34A4A184FACC64E5D1E8FD69269660543EEA2FD584117A3EBCF6268352F0212ABCE7CD28A93C9AF76722FB5A71FF9E5AC4579A2BA32B91818CDCB62C77A6A8EB1F4C34132EB463812B329B6B22108AC36E71F38338AE3A52C632796E45189632B73FDC0BD37A457204757261B7CFC01E06BC767A57A5FA7CFE43794F65398A94B4EF09D6DC2A8691BD0CB018BBE7B66E0C37BAA4723247AF3424BDE22614A9A581A7982E8C2323178BD2D46E6912A2FB2D2531819A180689D7F2C9B5C5AFC2DCF1C7FAEB1927EB79A72EB1203BB0FF17DAAF27D66022195890BBDDA786CF1C36ABFD96BC36FA1D2A5A0CC3D7EEE1A1050CA840209903CB9FF429C7EE9DF9CBC2BAB84CF28FAEF5BB45AE9588970A28B6BD9ADF8DF134C1FAB0DE274B5C7452C4836A573A26A0B4C14B74", - "C6D5046A5000ECDB54C872F2DC494F2DEB88430007C9BE8EC39FFB148F00F7861D8277589AC839AAD30AF7D7A2E0F9EE8217A39C521311E9BD59A71BC6663A7738669D6D3BB28124A80ABDF905DFE2C9539CCF0C8FA39EF84E9633D63BE0C32F3B2AA9FCDC18AC38C3C00924E9D54977BDAE61410F997038BE066DA6C945D8258B7DD133EECBA836A7A6A2907C431C522619D466430E6ACF15030F7FBA4F3D6BB545CAD85678E81898D2DE358CFF3951C8184066B18930DDA867890871AF6F4133B492FC894DBE4AA5F1E44BD361C4560ABBCD3101B4AA4E065FD60308795DDAEBADBB604A3D58776006CD074389AF49A0EF09586410015C7DE4FEFEEBEA6262B23571B93BEE15CDA2BBA60B6CC72A7DC9C80C81C9A25FE3D149C7A8BB2F704BE11177F92E2CEF0BBD12C0766D691CCF093D456AFEA411A8FE5F1C1A44F31017760F0D0CC3B271FB15F56D9F51A594C34FDFF8F8ADC91584ED8D7E1B6DAB27B2BE1BBDC4486FB1C822F23704BB2EF4B521E02E42FDCABF69588B0B9D92AAA73116D26E8E9E48DE94F6267414AC845467597B4C1F2A9A8E1E82C0A1C05955022CDF87386098EAFC5BF1A040716A89BE53A36B143376927028A561BBC07AFAF42494DF5BC0D95170D853DCCCCB22FD36B7947712EB369077D02BF85B0A4F57757ED80B247E521AC640D1B1CE30F93DEBBE2389D364A8B7971A51AFA4F557A8E12", - "FDCF36E6C842D2ABCCE9D8783D0D7A7EB74992EACEEF6C618AC7DED4E457B1A708BE2C82B28A9563F4A088FF7DB146B16B47A900DF49A4F3FA8EDAAFCA09F408B025D04EB673E105E0F55959B7951CF0E999CDF68EA9B32333DBFE0516D272111CBBD9933CA8AD8AA6025E5F9A062D8305344CAFC3CA391BD8DEBDC58F7FDBC041B349900E397609C71E4EA3A9D8407C63E8A6BBEEAEFC92E9C939147920E48E35DAC6D123DA46E4F0838FD732E43FE4EEF6BD68D5AF0C9BA3A0CB28233743B291D4E10054F695DC10A847E661F39C4C133289B07ACA8B544EE3E2EC288CB18C40CD9A8E48A93378FD50E077EFBC21996424B539A397B3D2A6C7DE58112CF55E82E8FF10F75571A15DC248E6B77CBB91D8BF2D53E5C4E9A85C7EB8FB690F74BE029CE1B569EFACFC16872C5008820FC6A7D12AB43E08B4AFF57DE6B43B613DF8480ACA556E29D792C6C81CB1CB54A67245C571A04965267BA0F9CD3FA0950B9A5B393B4A230A41E455267CD396F42285F0E49C5AFA0B53EC7B60C1C317EDA3FAE4B1713A80D4EBAD32FC685C13649C4806D6FD887A24A4F7AE801405EF28F058B37112A680F9E9AD0456314E9F490393CA25775797E4CCF9184FF0C6A237AFFA8DE1B84C420A6183B1D49D6F2AC1E673E7FDE161A8159DCEB00D85F032EE76E3931C459CE935DFE4AD6C6110591EE58496B82A16630E82320B9510880BE4E72", - "94964FC9F66389FE3880283C4250E6E19F195DFEBD2104FC0959E084308BC9CFDC6E5ED1C4B48B4ECAEB4FDE5F215FBED85A6CD4D1C1466E68A4CF21AEF29F77933549A3A6FF7ACD8AB6E6C689F1E8DF0AD8AB289D5C33023DF90B21A26320CE8C1CEB2C099FC1DB58737665855DCD20D587E176483E33EF14C80AA4760F751EE5B28460811E5110FEC3D689AE2A6E91D0A3F1E22623E88571F4DAC895AA428D42634EC142E56D0D57CE68D7949BE13AF234229E546E9D66D5C58E510BF3EAC7B73309BE16DCE6E2280AA80247D9EDEDD20E06295C9876B412B786CF7E5F1073792158131AFA002FE7750A17015A9C2580646A9A0D2A3F0243AF1AB4FEFB3D028504553AF9C5C34D1A4A2FE3B8DD8BF8CEADA82AE63C319BD7981D97155AA2F105D724A8C09310D5C316877062152419A006ABF56AADED74DF0DF325D666C31DF51F194CFEB331E7DAF00410372999D2D05B023B2C3067E6CE4A472FED3B8BE1C15C24DFBF4956A5B670FFCF128E5A23039764BE39CBE55636B83674060B3CCF5EF9A7B7EAB0813ADEE82E271C422FB78A9820007753B1E62BF4CCC074F7796D5B2008FE6542DC0C77ECA3810120ABE9F90BE5934E8EAE365D02B3D2DF4EA4A827E033263B113EEE5823DD3912FB31E3C4B46B274D7115F34CDA793DB6AD2CD8BCAF4B13B832AB605BE42B2877EE2E66B411668EA29A7DBA5BD969B9F152638", - "9B8071D96E7D361B2462CA93748DE4D31746972DAE582AD4F70A188CB40C2E6E418288B6A713ED4B647013B3EC31C9EA6217DE55D016A1977A0B285224129CDC59A9E54F3E5094258F11C0C995F60785614E560764312CD86C6969B3274236EE602EFAE392C015E4C3972D6FA2A47AB48D5C5F6836AFA54F28CCC03BB4DAA0A1DC0DCA3FD3F2B15FB2ADD907D3BF7719D1D9A8284A47C30F32712A8CD440148B8DFDB851FFD25ECA2864150B832F8B5DC3A7C701371785A66285601E96D285FF88947804AA4D88665B3E15760CDE327FBD21393042BAF62FDCE6EC41955E877ECAC331D594ED40547AFED34D410714CE57FCB4F01C8826519ACB85F447306C86BD1BA8189E0621DD09451E8F341AE47E7FCF1FD2DE2AF78E0AFA27A4B6DD51A0710FC1FC4A5998234EDAA1D4CF0786B779F637EE1A72058774C1B4BF5E125DEBB4230645ECF87E3C6FDC91E1D14397FA72686784815D9654839AE8FA43864709EE0F4A336E3C399CA20B2E652E2AB17719F9253F772EB7A9E8838FED4EBCD0F8CD977583BDCEEBBD925676F56AAB0C36F3DD915F6691A30D60D523216FB233CBBEDE7FDFBA827450E595AB51237F9E77058E40F862D3A5A96E4AA3DA74503812EDEFA501E526DB6B4C642222D7F33B06D9CD0023471DF5730CF8E2BEE834D108A25729C1C1484C207ECEB0E4598965EAB5216D4E7C30577A89FB8BEC0B118F4", - "E43093167F77AAA20EF9F4AB7D715CD0E86542A0523BDF0256BCCFB1FA987A6565F808C03C71E6343EF41D2ED4C4FDBBB1AB1D617BBBDB776F07B000922FCBB3718F5FF326A7BBF4BDF148206411E86506FE5CEB8EC0F7AAD1DAE3BB46482F5E85D3B46DDF93F4BA19DF9DFD700C35DC038CF4E499A058995AF06BEE8535631966751A85571271E6877BE6216AFF16AA2B9046F1AB9126E1DCADBF40C4B390D23379D52C80C10CA05079D1F05CA294EAF7E2C66B884DDBB52DC85A45FFABB2BA6EB95869689486DDDE372DCCDFCB408496E647F33575BB99FF1699219D00D2608AEA1A47CF52DD21A3CEB3F043AAEB40EB27F042D276227C09CC8201304C55D254AC228FF309FE8DB74C85430FCF9441EF1B51A1192703B140CE3703E5848477FB0BBC2E82DC38702D4C6A78A41729B7EC86F9890EAD369DE4F25EAD61DB0B5B0ED764EC84FDAB904FAD9DBEDEBBE89F338DF52F7A6FAC8EA1D76001846802B328E8D1F110219BD6BB51214814026BFD6E32627B696C7990F53591CC811A9A09A1154A50585B882DE0B404D7B5846DBDC8C66E4AA0C7B90B08CC96A5CF2352A6592BCA536359C863D639CDA60FD23326619A9014FD878EBFF3E73E4424B045CBD506ED744D3243725EF9491D6165D332FB12985022A71C7DD4E3F942AF5CDF2396F6C346088EAE89535E1B21DA8F7B2E1E12DC8A37738310248808B9973041E", - "F5B9B9204186466AF61609CC856B6B2B33D6F526EF1E4BE4DCAA1E1055F033072B3801B642700249C024414B3217D160513E5A804B3AE8425852CF5FB9F51D2601F9BFF9F5E4512A45ED8F615A6671315590DEC31720387533A4E090646F17244EB571DBD6E6A10890FF19809D935A5E88228D424FF2E54B1A37576C059A756290BAAEA5E36AC977526339CDFF915A763B2CD0657F3A3D385A5D92466A44980AD8A1B4E1593DC177E2447ADB53B1EAE15A91BD6703E46F01AE91D6C316C1DB983688576B3B2BAB280FF196D5BF545755097249C517E1271202E3856475A3C95324F827961DD7A827709DA2924B21949B6BF032675D80FD120180F6850BFC385E72399F840B80E5525EE70B89E1C524D580390D487D0CD31AF3CA5691067BDBE8E2E91E0099F59700CDFCFDF8B3ACBEBCB61DB23A28E80C3E463D9E53328C37EF8FF0D4FCBD287932C8197DF57EEBC9DDB29E2046C7FC14970F9F37CED37D8BB0958155192C8595E2A9369944DAF58FCC1D9E1987DC4FA77ACB256A65DA78B733178FED14DA3E3E41DB808849132EB05E48BCA03ED499A314C857FF7C7C1FC8BD2478635396BD7F252ED984C102E23F55450F57ADC7EAC50A57B78BF4F988565A172E878638ADB1D992703D0BB742605EB76E3C85319F567D71B9F2E40251EEB936B323DE98496229B1F8A996AE4F6C0C2FBB3B2244F3BC57EB3FD067F535102", - "A7F21431EF8C75A1E9723B1FBB602EB4B92BE5FC8DE70183659A45A31EDDC46643ED1287A69DC876634231D3AF95F2D02FC9C0C7BBBB12319CBDBFDF6CBF94E47A05204AB14A490C6FBABCF329B5B0EFD8C2FA28845764510624398BFDED1B250003FBA61A67D2127550FF07A6FAE2CB5B8FEB23D289FA235BB4959F8845B25405A75A30E7D05D7BDEB721BFD4A998DAA6F1A54712901551E30D618DC80FADF7CB7863EADB7EEE708F1050AB0510A956C3C7706756B6CEAF611F02656C3CACBFD9E4507AC2B4B78D0EB0BF757496C84C7260CA972F0F45A393A89AC2BD70F15E629473D61FFA29BA18A468D8D4B1F72DDFF99608AC9E6A6D6A9231F24388991E80FBE6A9269AD6D31182E79235A0E33CFEE9E3526FC068A9253789407AF8CAECE14BC337FCE02333B63224A61E913367CB36641A74E2DB2892C4E939A50127DBEFED7456F7E61454FA5016A6B75E6133B0417C2860B2F640ED8EE62D5100EA172BBF8FB02E2022D29DF33C25654C96F8FB2305B72A92105E027444EE0F27769946A67E58D9A26AD01483FCA4BCDA4C00A8119E355CE733474349DC8311AE9853A064931FD68D598B02E0724A13FF63D88416FD5D03A962B5D8F79586E696C484D7F287773851831EBF33B0158F51C89C493C116157D20DE66F3990061135F5CBC46862BCFDA5EB0322793BD6AE188698A2E1DEDDF71702B6CB01EC2BDF85680", - "FB2C4002173D1E1581890C14672C1F232E8A1332655108F24F78E53638EFECA3DAD18D19FBB1E91C6AA4761017DB37FA76F70BBBC4C8E8015384DC9E9EF14C6AE60DE55974D448DB8C36B030DD55DF5EC6F6C56DA8CB9BBAACF6784628B669913A7B291632730C11710D7E181401FB535FE8A9A0B81578CE54123A6C3897496375CD7C60BB4E05AD16BDD4CB8F652448E3020EDF4D51FF5EBB9FA93A740AE779419002994348358CD7827A63BABCD7C4501CF8ACD77A2200059DFF5B180AFFBF3CE52133C7451CD108AF9CC8FA32428AE9ABC55D89E1931E6607160BF96015901DC097B56299F9F358DBBE921FBD7D0DB43C9C5BF97468813C0AC632D35C858D8384C32EBDEE933C9037EC36D2322F54FB0D3CF305801DE42B4EBCB5F83F3D3FCC1AF56910B7A547F50F851079B6D0D262676145C27DB362AF383037FFAD5E3B26BD2095143B361F82425734842E2153C5F428D89DBA45EF59BD9DF1FE1BA941F172A685F08C18B76B6A8FDC86EED2867A57AF48E00467993864EF70D80CE5550C5EDF085E94435ECA89F6513D23A56235739534C777C17BC6DC7BF6E04BDAA9B0C94C4D7AF1368C6B4B9D3C97D25A26B05703EBC4D1F8869C5DDA359D189F4A3E548D53731FB429F3536880CAD9FE13F70DB0A080B949C3636611CBFF0F644ABA8B56D2C6E988B3392A7452A8C8E52F2288560331A78F4CF021D2A41B2ECB6", - "CB7A566070A06E759017D62CF78A429913370E6498BCDC038C1D3079A0A3E6FD4FDCC851DCBEA9EB3A7D266479F75C40452A282CB406E9A2581372BE2FFBAF6E7F3359EAA594631CEF876FD62DEFBB3B816EC98A1F72B55F6023B572A51F320CD7ABF489AA905CE2274729C0EE0F677A04D7449A489BD02704CA65BCD8B753B689CB90C87C73FB4A45219DCD817E9AB584EFF049EA711CD3E24CE41423FEE6F258A65CA8EC3A00D45371EC5B846CF1549CB5CA4FF14B696140D3483DDC7801BFE6CFEFB9189B5C7AC3DB9C0709F630D80F361442BBD22636B00530EEF21D96D4A12CCF85E0124939B025CF35A0A5F1B4C2FA5B5DFCB3772CBFEC1F0C1C824B5CC22BA8FB2DC92164FCBC60333EBF920A14599F1E8EFD4E8CB0257134947331D820595BF5630EDF00814C32994039B47E8784C29D0D1C5B5D219A9F55FC14CC18DACBE6A79698A8073276A424BA9A6606DFF369CCF5F9F4AEC9605F6E44807507B36A4918FDAC448E3134106683EBA80A2D97E12EC2BC1EBBCBADBDC631CE7D61BB9DDF143C3EEA4E36EAAEAFC001849812A7CDE3EBC194A51EA2A9A2AA15A0A4F29C2FFD8B2CB4ADEE99B59553BB2398273C04329A5C884989D417C131D68E9B505594C9B9CF1C13AABF05093A9E4224D71B54C6F61F1255E25FF7527E47768FBD51523F42915133E02CD7E404147E7AAE95BE651BFBBD65E29130D0CA31C2A", - "D90A7D104DEF06F51CA5FE107C115C130B8823C423423608DEE00E0C2E6C202B60C5D20BCC9CDC18767D89E5E7857BABC9531C21B08436AC14C5B34EB986E5521369BC3D9B1FCD07C99240FD0DA306C69303B310B8F78D2BF97D6E9E88843234D73214431F6BAEFE5109AFDA22C4C348A469370BBF9B0A81CF27ED919A0A48DA3E9061113C56659F7561175A608B7FB37A76EB9E5ABA5F4A6B485EA5D097482A28F4EF7DE785D31DDEBFE41DFF7C51CA2B64A0D2A7A70269FDE399FF7628202289EA97141F995FF51DB5AF7C9C5CA76F0AFB4981D021FEA9EE6A49ECCCD18AF290B6C231265247DECE33B3E165FDE4FCF82EA84A4A8AE3FA90972D96DB68550AEF21FCE82E0FC75FCDE33C2B6F659A873AF09067D94B068DCEEDCA4D392BE5077587785CB6A1F1947841F483BE5080E85B49F1073D4778A39239266DB2A24B57B5F51B1F021D05C634D66DAD081D1668EF0520424581E5E0B62ED085D005F169950F971E1493A49A60A595342AACBA236EB16D5EF94E749889E50656D98F94EEF205445AC027387AE1363696185E24749EB67518B89057899548BABE29F3487D273C54EE2BE6254C7F3ED3D3B22FA3FC94791A7BC7C499A391179368D9B1F0DDC325F55022F5AB7B91142E2880BAC761D154C11F2C58F4A42E8B3DBCFD44777F08A74676DFB7039F24C9A4C4620726FE12849C9D3C15293A3DF7F4870DCCF56", - "9D238D97CE04FEC0D292181D145EA0EFA727DBB7BADDCC60357762D262DD7D7A3BB0189E05BE490018ABBB61B154F94A4FA81985E774019CCCE4B8ECE9858C0C2BDFFD7923B3354A2144ACCC5C9DA34E50299EBF68E9BA0A269760386E5531F8964F8024ACC99E7AC3F40BFA9D94ECA1B14A1B173A06867100C57883FE7333C079C5871A8A7603395A87387EFB92A77C5812EF548CBC3B9178E874E45DFA8796BA6FECB5D81687EDC0AD5F804FF36A9CDDC58A5F991A2A0BA999F86E663715CC79A439DEC44C394ECF1F14801D8F9F292A648D29D2E910032F224ECE51D0708E4ED6D3E65FC788A2C1D286750F4B6D768CBF1B6EDE8524C2A7457A82404A491DB5EC868E6B95B02167A0C4E785290156943FA091F28234C4CAAB586F8095895FD21582E0356BC15EC7CEE893E70902CE4D01217474E0226FFF30CB78597726C74B95732E44D03A626F1D1DBA7785F55859B71C2DAFCF71D99EB99FFEF4877518C579D2623FF6EB326B8D6C7674826984CCAF98CE41724183952EAD69F05F44750F3B857EA01475555FD25A828BE1DBEF5E8B1C1237779E9E69D35E7BA9ADA124CBE710490280B64B2DC5EA2C41D6644012A18B369E3CA2FD93A254C493506C54FA6CB4DFE24E0B5035230F2BDE6FF21101164F322B4B066ECBCA3BB4F3C476B41BD02D8948E555AF74EA13228F07A1BEDBF95FA7E16F2BDC5D178E74FE5A1A0", - "8DD8032BC8D741905EDAE449212146878D8FA15AB037E41C36D21B0064D65BEBB74A18F4370C80DB44EE93C2AB06DCC6C6FE7DEA83F270C9FB52CE00BDBF546348F0E6285A35A32A47512823DD6E22FB7949071D4B58B46241544AB97B0F6023C70AFCFF0C7541B4B9E1FC6B3C3C55500251665D964871B9D1247B3A9728AE02FF47368053B1DE928B6A8D01ED3BCB18A3180EFC9700871F480959137CA1480C3640547497ED7CDB4912ADE1385F9F35B6D27BE64E362BD71E0981BE952B00AA20DC57465DA89B87BBE07F27454FB24B3B86766F95A5A5B4EAECA2620C3BF87C0654E6561398F27F96178EB1062E42F6E6AE0A669FC6C7170F217C850E822B4E70C9033A375BBCF6D62D11B3DAF7DA976D4A9D955B924E7F0A19CE77A53EDD424ADFDEE8558F06887E82A936193AD5E508938DD3FBFE02DFEBD98C2272DEAAD8AD3B0FC86C3637A6CE694DD95E4FD55F433E151D35DD4C930177CA66322001110B9BD0B89A096C8C3A3431C100E39E3D2E65504A770F4EB2F19E9D8FCCAF15B8E58DFB52A0B88406A48A036193F3EA9F8ED2322FC69CEAEB9E2DD6AC627DCF4CB109EA05AB5DCEA5F92902F3E7BD457C240C958FCA7B17F2EDA1248961C9C827E99BE0A3D60B3E27E42B1FF696DD58E48C7B832D8FE95529B9C8F075E67294C1B1060EC6736DB73FEF7407B320D850B049D80F9F4D536361038C4BAEAD92F24", - "C10051089B11B578F56E6C24FAB973C5D1B4A2F937E4A402FFCC45267F4A3F4CF4EED3DFF530838A570000F7E523D1B97FF798A3C6E12F9704126A9B6FDF606031E4D8E1AE39A470FE929124FC95961B85A5A6E10A79CBA60F54F37D4DCCB13FA3B0A3A1729184C59036428532E3DDB3F7B8D373DC08842EBC2ABBFDEB5B73B2F9B7E83C81D5D0EB3037A32AC0E5B6CDCC7CD84B9289BE16106D1D019D47209AFD8DA78EFA0F9108377C187B170CD53F366B17899EB41903FA1627AA245C07EEA5D6DA78039B3C4C1D70DD28870A40EE3A048D8209C4088A0847D6859513E01E0F4172C383D64F0B307D721C01495070336A753A75E1CA433FA973BB131E558FACC298C0A6E934E9F717E19EBCEA11EDF3736D4EAF593A8E5AC8EDFFE4D2B17B613E024B41AAD19BC0A27A1E9BE9D25344D4350596B9B0A48AA014191511B26E61A9753D8A38C4E3BECAC93E67CAB5696888C06B9099E9AE856486436FDD1AF1C193057AD1DFBBB14AF772F7D9B00F37A6DC9E805A8DFD9D53A161885E5C2C2A6DED0C54D00A8E0704877DA2F1EB6F6D8EB93B5604A4E2545D454C3D4F0D606AC192E170D44E85E2ADC91E54F56906909024DEDB6F9050BF3D3928D9AE23D9C42576AE4DAD1336F47519EDE436C3B1829CD2C5A0AF63476C7928B32F5E51826D844A1DF765C5578F9C2E5F79024BFDA96FB3199A3C7B47D3755FAF376761B4E", - "9C6674915677A62A7AFD4FCB27B45F8E6DDDD08980B7DBE1131E6E2425C5ADBEE8474E93A8A2D4E495B195A6B83F2CF6472A36E690928362B9A1FA994A9FEB7BCBA7FDCB771F59FB434ED289CCEABDAFAE29113389EB98D6F17E5508D5976E11BC8A1E93AF9F7B1C81686265930B4D334568E3F29E1C2F58A62572A610016C1C1C1C9E1D0EB3FEB2B3A210C59EB3980C44BC656FA7C5E05A4472D4255B40B8A1604FE39D8B5026A976310648D5C84CEBC87A8BF6545DC843A3A0B64DC4CCAF2D2203122DDD75BA42E096844899A35A899FDFD72C26E3392EA03351DC78BB9F62F51D913F8008DB00969C64003773FB2014FAF97E794A45792495BD52D7BE7ACA47FF2BF570CF88303377092B5B6BFF3B01D38A53E8A68B0D81FC2D1D375EB27C7AEEDD70679E8DDBA6DE656442ED951478FB96A979B4A9091F344EF39AF23DAA886C6FBAA8611C61686332C630690109E2869D18EE7A2C21B22921B9E3DE40BF063E370FF64E7AFE160B7EBFC4AF6AEDA043042552F5F36C2CABD339FE1442242EAD931D1B83968D1A31A7E32A0838401DBB9C1034D56ADCAF5942462EF63440FD70F91520137A50372D0D125A6285F7D715FD9225D03A109E1FC5EB547303CD7708F88FEED2814607171930436B249924714E8D8E024C24B3C0C9E40127DECE1AD966C3F9DF01793864615F291B73F73D27B624ACBEAD3D371B8D4FDA823C0", - "A1B9E8AB6C44A3610768CC17E3B899CEDDB44B746319EC50BA7E006EA0F3C09E9D67EF8A20154B2F93EC265B800503BC72831800CE0C9FB6CCADC8327A840F69DDF29BE212BEFE4AB1810026FF786D9D3A88B29745EB61131FB47B385F83CA211B4A2BC0449F7ECE43B2DDAC94C10955FF2E078AF573FFA7349907571AF501FA6A2FCF24E4B5676F8213475351C0398748FBD60A5EE8A1128C0998E57D076A201453EA7C70B1F171E7D084F444311C9829CAD03E0C2330D7E8D39DB6B7901C30787FF123CFBAD4E974A5F6412FB1BC927FD65CAD1F3AA4ED52E2D84AF6257EF311222467DE179E89438524116D8E0A4A94C19A4D66D0AE0FC535D69C4953C2E43136AC07D6A5774D59DEF1471B4097146C2124DF83D36678FBD7BEA6E258D826645DD88AC9A7EA5E05FB49F2CB29EA9081323FFB2A00F3915D1F36675BA1C9AAA3B166D9FB2529150D3573E502668E33DFA5BE95AA6C2F1F106D69218839BA590406B4FE4A03C4B16E29E6BC31335234BCA55D34955880B702F08203198EB7BAE381B231FAFE513F24C8BA9E58798F35465C2679DD5BA8B16EEDAFB04E5A807B9BE6EE4B3AD77609D2B9E0985BB23397BBDE08F4D0B21494A3129857E37D13862C1FF77A57AC663C206A92F8358E6C05FDE1A9D68131BC04B76F6865E8DF5C48F9424CD9AB6FEFB3B49BA8D32C923CDB8602C5367AA9ECAE48AEE6A276CF25C", - "ED1196222AA470CB4FC8A0B7D2C785EB45D232E06453B77DB76F60E5F7BAA0FAE80467EC8C656FC27FFDE8BFAADD2368B41AFF69460495923942ACF85C09EF01BCED0076960E5CDB1D36061933C1B6037548D27932CDF969FD5A910D5564F3A6BAF896A2A69F40EDA76E813AA261530F686042235A39A76081F58D952662894E6E648BA72098D840235EC4A2B963F8E74B52F2D0088DACA7EDF48115618DBBABC698C04AAAC0632475BEE65BB26A4EAA08F0209B75EB259B826724F580209F8B991808411F823819CC5F42A9FC1F0CEDBDC54C046EB1D1658FFF7252908B09F8C1D82E5F6D605F0B17B25506FAF91D4B3D4EBCB7A705E5BCB2A6FB409ABE4B1B0B47630F1AB0B40A3455181678573F82A7C139F072659D80671961D614D9F7DA72914BD5D6F417EBC152595972FDFAE876176923CF1F2F745A6FC27E134CEBC2D9AD5CC733F619C1B296026B7C4717D2086D91765D83AB76605050B810C542819BBB7CD87EA2305AB4A567B2C500D9913B7C6046F748DEECFE3C3AF829EF97E03799EA50F7C9EB38990F0D466498C091C3ABAA18453B173F0AA3A486DFAFEEE68E7998EA30E5C1349F2A54AE753963CEF58332A114F964B83B4E446A44147B11FFC60DA25B5FA705F34725B1388B17E99018236BD646DC714F8B7CD3BF2648063B2D3FB713AB94D82ED81D571D5BB4D3E5F2F067E2F2C90E8B6857E6A651B8E", - "EBE597534C0A6FEE9CE6AD10A80D2DFD160D7DE7A20154F62AFD7C3187D51D09DA39A958432CDCCBD83FCE19131E65A30DE99DB796D93D0944223D960BA233798323D368DDBD407D51B80350976951AE0E50CF409279301939624C741D20D5CDBF4BC3ABC8723E267BE75707024F6398CC6D32A7BCD0989555E0EE49C1A2354D1E961CA9910A5169ADFA71D56745181E0CF13469D8F3C6020637B8118ED8421A680FD4D515DF6B31C39ACFA36B601027AFBC861493D34ACEACFB501DF9A311B7EB9D38D7107E6B5ECBE74FD35CC8BC8319DF9F1948653C94C868DC24AB8D7E650D8F70A3D1D878558AC9BFA50D425604037F3DA323192654F1296C8320AF934AF60DACAD7F9630EA4ED0A635678213F6D09D73A2544C779596990DA42079C23581E22F541E6A3B6D3FA383597A8BDD7CA42930816D74FE8B12F92CBB9303CA5FA12BF5FE954FA7B53E0D88B79BE263B4B55B42A7672F5C4F7E6E2DB4C02AFD6034B7371E01215CED3F73AB8E3419D7447781AE5DEB4F4547C5549E9B0AD59940C162790650344E5ACAB33A187A58E29C9032963F088C044ABE73A855FF1FC93AB8DC258E419777311B7997EA95D32CF1F0140CAB9E6707E73E4FE575E0752816122C39B8D12F34ED6771EAEE192D830797DBE97A0BFD00E39CA382D44F080BB4F8FF6FAAFF2A82744C6E14D3036E00EC2ED5C9D184ECCA300030D7BD77B27DA", - "A56990B45E9AA5F9523D563D53E854A47629A4183E85CA1995BB374EE5601BDBCE5C7407999D28FF0F1B3EC7A463D3C941C57B7EB71E6262DA3A7136627814EA6D28C8D16E91680B0D961AAFACE2CA4099F986CD45A2AB387E39497B13678447480514B4008F0FA3B95AD7D2B4751C680F0C7D3651F9621E1355CEC76F10468ED33DE4C7D7D68B786B7F0006C604BCF893739FFE6AE56AD5AAD07D5BE76DE1CD581B10EDFEC9DF65AF925C4C1289837BE1854A62FCCEECCC4E2AB47B4864C467F5E4C276047501EABE444E051DEA933863E0FCB2356CC0C3817BA59B2E0AD78BBFEF4C3E4C35343331CD81C7F4C428B0418DFA4D6FF655BC50AF49C9A5E8A67BC265A3F30800B93E42C0E66F117E6C59C85BA5E273234EC7212C7B7AC3D87FC0E0EC5FBAE6654461F24BBDF9A063FD0E3F98741C5622ACC8BC008EB0E3F3D57680F12E52FB94CD957EFDD49BF512D9131757161A73DD9650E3561FB31509A908D3EA8DBD1C3AA95AC32E6960E0D17A218A25784332A88E85303DEBE117BEFEDF46882995AEBD704AEAE032668AEC6B8E5BD28D3F110C9F8C1DCA8FACFDC1188A073037796555DC4FAA26ACB9F51B545D32C224424BAC3DAB20D3C08D784E9FEDB47547C25671C269A62163742B55AB4CF9406D2C5047F92C76356F0B90221E019B31890C0B8FCFD04E6B5D06114B967D1358797238D5B14D824C8F0BD7B8BD0", - "D85AAA53F2DE2946EB0CA09DEBB6CB61D91D27C8907B90C89E20C01F681D33BF0DC70B6C79F19E4DB64793505A0E055C33D1E07B7F5AE09F7EFF0C8CEBE80C84373804A48A945CA406D3A1B17CA787DA265C1D8FC735CB098C1AB37A0452F1A287B8E19E3A57E59EF8F2E6CCE2F0AA7772955977982B1F6880AE8717520753636591BA36E351310E98ABB77E26E2CA5BF267935FC38DE173CA20C3A964B56924A5E82A9E36D005EDE6680D543C021C7A9F53DB69BFA3201880B7797E90D31011AFA17BAE836505F5B337C23A07D6AF167258C314C3001291DD9FC565F6B7FB74D99C1B42B496422B3D3E1A564769C2306E40264641EC14724301795B4D54F5FF8D6C4AB3645B56C1D0FFE9B977FC5017E2A53392E7458BAA308C343AAFF5B46B808BDA1FE5C284299A9EEEFC755132F9D3B475E2FCD6BA84917C601B5E8340B5A68148A33563E40AC5A1E49BD8D5FA77BEB6B99E6F4F68A10ECA112475531E7C1942AB9504B8F76EA7BCCAE4A19EF859FD6B6753F07BDD9A19421A2A0B8F27643B2311FAD7978F4366C41BD9F609486FC6EC7CE833A00D7A48AD816412BD201F40C93D136ABB8E329DDB816D1F59A1F3124D6314C64C9B640E4D5BB201CDB4490A65C73228E78055AD6632D81709AA443EBF29A4607A504DD5CBC0D271FE595677B8E6A5E29E23D171D50B878D0D3F9416657E3997D077677B87399A6D1936E", - "A0E629454DE594F7693888C9ADB907F83EC6818D6FC0019B70077BF1B0E3C2CB16A263BE145EA8129FED6BD98F3D9120BAD28379EC8E36DEC69C59B37BD6C2B65D172C70C69C23E29A6143121AEB9E6A9AB46C3DBC3979BC876F4357F6BAA5A0CB33C3AFF1654FE547D5D760E8CE095A9B324E15CEC1596BB7E0D56433D8908EA69925A5CCDCF01702811AD1103F237D36C5F12A3CD938A61EF76A3387340499E4EF1855F892F57AC39AB419F1A397CD43FE7F4C5E609ADF3A2A8E401FFAC870985826CA0DE211996A3549A203B798A5162E98FFC8B5CC2CFA68D618AE80D399D8DFE0FE4AA81ED9B586EA89F646D5C0AA8B107506C7F86879419D0F717E8F70C5A9DC2C3F122CB52F3B691087EF5971C27086512F1890494ABA38B1619969F8846B8876B95C56142F5B171502FA44ACD0299E82FC94EBCD4CDDBE1F5DF978871128F79C1758BB512D5C3BDE59A89786CF4E4716F0515F45A1CA31B06B23E4883F99EE0488848EB0A60FA14AABBD41EC5421D0C162590FEFFEBB4DD0300221471DE8DC0C87DB3F1D54DB11744F8A7115DCA0595F6CD99B74A6FB10C0D14E430F8B40E3E7105C89B2C8F12B37A8879AD9BEAD49AFA1BD56569713CCDA3FB634C3011D51A8DCF84437251A7B19EB61FCE5DF6E2278784722BABE384BA5424646FA23F6D10CE23DC5E0D8D512E7C5C094B1627D6285B57EDF38A7DB1BD57B72044", - "CD7AAC98501F29507EA4E0183E8A40D2E5117E47BB5D18D01A3732DE4C821DFE86521CBEA7DB29BE1148BD544ECC681689BCD1B41EAF755310B7659342F8EE11CB41550CC30E566E192796B66C1A83C0B28BACCFA6C393043A0A2CB89712BC1CCB174DE58E66896AF39C1CEED1E05B0435F8CF6FD920D100F51584FE24879987399481DBF27DDB6286B6353919E552E669290CE02AB4CD5113D7F484229F379C7332767EC69E4336439B05DE1C1E3563DD303A4F580BFF20A40E49CB0822F715ED0221EBCDB5DBAD751124B1715E82F37488265135B6C8BBCF4F801ECC4D3525FF189493AD4EFF0C042B070C4CA8FB1FDF43D79F06A6E4E3D35D7B07D4B728D5DC54EEDACBBBA1EDDCDC07ADF7DFCFEF835E44DF1FF66DAF2A7BAEBE218AC3B15E183044D6A8A89B3C101B40BED97ED5DF93BBC1B84931D56B8C822A6D058AC74CFA4C85D8B456698E82D5B7574C17B041E5F4BEED09F75012355CBC322B822C63F10C18A8F279E9A0E18E1FEF183D23E13894E31F6D046956FE8A647558228F6D4D6910151EC03937876B6ED7A078D33DAEB3F2239353BB8181E62B286BBC41588DE10F478A5CE5B508F205A41820356767B0A0ED4B8DB9EFE348362E9A90D6C30218B295B338B51C09239D02FC8A1E7DAAAB60AC37F5E67CFC88EEF69567B5C81A03B449F4ED38B9D295A36AA3503173F6F6F66D93CE72D753076040FACDE", - "ADDCEDB50E907D20E826E6E8A0D30C20C74B2DF204EA784BAE9F618CAE33A3C937729DF9CB10BA2A4C33E0182A37200C0CC509729D828B8A2A20F283AC4F9306596684EA3FB5492A4C9F2DB459E7531C9F9C0950E7D9E93B3EE5912AE7E39AC8F4EC14B18F24E325003F477E347C5AC1B67CDB11AF3BBBBCD0AC3703024B5767AA67A208254F798684BFD1D3EACD757EEC77254950A146620400DB95E694574F739A991EBA771EBBDFF1056BB39A77DBE0636A032E17141332F951C57C6C90F348F165E3ABDD60D429D5D6BEC7E3E3463806F819EB2D212B3528A5EDE51F235AD100A35E890955F8A1DC51FDCB53EABCA2540997DD054C1F5B29462995B876B44D085904E55E1B838BEF600A992EB49CE078DF75AF3D0F137685AC0D07F0BE1EB87B63A41E74DDE869C8A683BDE60AF5D77FF18F7137495BCEFD0ED28F62F9C3E25D332B5F861D999FCDC0B4851A984A4DBB53401FD40351ADA4335C702BCC8D900C737507B990BDDBE91D201E3A0946DC968D43FD10D04B0B76667FF5B4291C2124B0124C6B710A6D1BCFAEB016B9DEEB0F7A4FE044CA4EA0CCD84B7682617C3A545071EC295B0663B3F577D562DE1D9DD80DE6A1EFD6D5991EB5246F1597B86D0E9A90CF6DB0EB2B8E7BAE9431E567F01AA98502C773742246467ABF911A91A51F6C1B9E0C3233DC1A37D17DB91A5F0F661B0EB5886964456C7818601BD0C" -}; + "B39340CA1C817D81EF4FAE4E95BF3504A7709089FB48560E9E3EF802180E85EB2194E05902C6C4C52021FEB7EC64FD416BCEBC8E39D64A4B5EE345291911AB8204A888C25B1CD3D9342A56C538636D3EAB957037D09E879AE5F3A39834FBB84A3D8D5090D7814246B62E9CA68533D2EC403B4FB9488467FF9758B0D15A8CEF89187A1D5897880040B6C3C5244E85A2AD14BCF2F5ABC44A7B1D4A87E8BDA05766218773ED4F70F8D1D07CBB1E8CA6298E64EE6DC5886D37495BA2EDB3E0B0B68AD9F300310B88898DDEEFD484538C31A9BCAA76ECAD0C16607D32189058B0862EE9D70CEA9D304755CE8037BA4C46C2573181748A212E4B2BDD04F9BC240518273DC17CBAFF21A03E9120FA7DCA18D56DD1D9A7E510C90CF219104385F531F2EFAFD185ECB6B911F9B7809D98D86F15516FFDDBE9BD1CF8662EB777C3F94EA3F962D7B79449FAAD39935429E92CAE5637E9BCF4E94D413D27934952409AB536BE4055AFBC4330CD1E4B5509EFE5F8EFC9ECBE9EF377DE7E37C479BB9D3EE7745E4609B0A6D2C5D92EB3C9E2278C1F2221FF907596AA5E096ACF8990EBA907E43AD320F8019CB6355A2BA8670EE5A4F463E8E56F8F1D3E7F4922510FB668E32C4CF23AD8496399638B095B47833E0CBB34977EB3E4242EAF870D86660D6A73F83E45D6E8A41EDCA3815079649544597C5C43B6C93FEBAD5700D22EDAF431FD340", + "A64F94BB47BD4033C76D4924305907EC1F618B43C7535F3CFC093E5AF5DDD5C4339F3BB6D835B5C2C2053CD3D5693368D4E1A7CAC59425D1FD96809C67285CFD3FC05B01053CB0773221D7205778022F487BF99D1650566BE287FD7AE882AA8E8F52E5D4E3C0C2F971C9FF70AA378691EBD8ADE45CF213822D09FD05243F9726F6C69893845E57C37A7643E16B770E26F431FF69D437271905D270EB85D8D229D7D87662121F0BEEB1E895ED9589A9CF5833408A04197AC9025D8570AD9B75DB7E192EA0A089504996E9DC652975D83633619CFF80667D8B519536B3475248BA8213C8A4C66DE69B4B3774BF9142425C57F34A27B1E288119E3FFCC6AF6A21087F9394F09DDFBD42F32D059B8CD4104A519BA640765D5CDE490E62F10E695FBFD33CBC9D2208A532C8EC25DA28B8CC1B6850AB43D9B5C00B6E74B7A148791AB07B328D347058C7E6233E18C5ED172C9F9E9ACF29D913E2A1614BFC0893D4967ED033B2B9AE6B51F908F1CED57C14FEEA85CD4D9711216BE7F79FA6721B7DCCA033C80127AC6E5FCF58EB4005EC24CB4886D787355362D5E7031B9B2AC2A86D730AD734181E723A811FF510A4DF868001973FE83288D78E6F9B9441DAF5BE2974A2848FD917C3BCD346A431922246EC852E4AAD467E60C15D61DD3BF4A207BB57DB45DCADEFE3210BE74B9DACC918A394469F2E2C95AD1E211947948FE24F5E4", + "FD1F6976002C39C87187C44E3D224ED4DF0B67750105944C651A5E57798F168A136AC0FB5979C4E847A82B20A2E6C45DB42EF2B930A80D3257BCCC53EDA966F5DCD9AD47CFB226EED9B62A874E9F6404D4087798A1005F4131171D3A47907A3CD602B83DABE094D2CB031867DF4595F3ED59FD8C4D76EDEEE59E422CE5C7D0A5F720BE94FA24DF05F758348EADD5EFE9197C6BB2292E2B14DB8C6DB24AA94C5FF0F5106D2B566058D32C58B63A150784F7B02478D9973DD4CFD2E84059AE0F4F1320754B7EE83F04A51C67EFFC2EB1C301C0C58DBAEBE95474E3484A76500103C14C40BB0B7D3A04D8BDABB605C1EF9FD4A6564934DEC50BD5878243AEE80F9796EED70CE1B1E8B55725DF76472D12D4A7A487989F42E6705818B1F7E149E97153A7B05A82FA3FBE51763E61171A4E12931472E94CCBA74CC09483DF93623FC60945070FDDF3A00B561650427E4BD64D675B1EB398B35EF057A66FD0B48EDBABBDCD57C32ABAE46F5CDD0CB1FCF17765258236F3DE40BD5D0A3C5C978D81DEB07367AB20B2CAA9834B9576161C4F20FB9C184A01DC9021A4E92B71333354E05BBEA9015E5AC4C66312E8B79F0B92279AC7EF1936BCC30802B83DB3D113BEF64452CAD7ACF6674FDA44023A661019841A101BE80FDA4E3210AE774E433A9ABD97F2755259AECE21F7A8C3B1A3D471F874D2EEC85B9B21BC0C2E2EC9016F847C6", + "EE38BAF6F61704B01509B5210A0534E4702F93190C392E749869B5572BB7AC4D7120E2BECD6618CD376C4C1B4965F7D9D73400824E88A5C7B5B66BA88C3E0065F9628A9AC6B91A1882192FC553E3140349934D20698C9F291B5370948AF6CC90C837B9F3607F13CAFD492CEF1723376E6A5B813A56301B88A8799519CB7646F33F91C44CDBE7F768D7DD9B323A5002D2F784C4101AF90D6E4C5ADE7D085C79E827D43E10DF63AC70BCDF13DCE0471B487C5ECB752B9C3E20F75DBD243790C91355ADFD7199081BFEA03D80E82445EC2831FB5014B85EFC2A52748A8ABFAC1BA3904E178DFBAB26C1750228C9A031104F58BB3B91905EDB9EADF7B0F6DF22ACEB0DE944E277809D77507D18EAEDAA1767697398421115D04AB2EBFC466E99F0AA540482A49C6AC8FF95E3F962734B03EF39873A93B70470B46FFFDFDC15C89F8FE2F4637B59F9BF9C5752D9F8AE7EA75D1EAF1C22CA27E5D5C9499624105D61BE2A691F9194D277414532A5E6C63875F7F20DD13C6EE73B0C3568392B14A5042843926472ABA343D2C427792199B543BE1D43A178FAA7ECF53B98AB7528D8E1B8B82C52D973CA0427636505837F94284E8D6B4F496FC5A48B7958D4681DA00651B8A7BC56EC859C071E4396A05F33588B8087EFE9635E565E6B5A8A70DA70F50ECAD1A85E6E36FF07B4FB3B9119EDE0B611CFA91D9D4C58C1F4815B07B9EB1DE", + "CD37D0FB0043D03444A939E93676B9DAF5F2D19A2615E3D97D624E62ACAC8098099FDB9A5A2F4B3ACF20F75B6807A5A3F157C2C0F479158F4A10FB4972855F3AE2FDCBDEEC00A4D470AADF5F5E571818AD6E872D897E2DDC402006965ADF16582B1E06B1861BF7D0C7E7BA491C79E86224AF6B246317F725FA74DD8376D63D7993FE2F2BBBB2F1DA9238C6F3FFCAEC50FF61E645FADEB6E03F883892C42CCCF904708B123C9271A670D4DCFCD602951D12F5213937CA2C05ADDE9EE3908E99AAE8DA31951C36D36D671CD7BF15DF60B707F00BF6EBBE5476926D015628A85758BFF35C4AC540F39E761B2ED3CA9116E8680E28BC387058E0F69345CC6AB3AD160E9F2BC4D6047A1934E15D3D7A242A296333C09296981BBF3B8577E4B8ED2A3624866111F6638F8955431195B60C5C089F9897DDF0D34A3DC627CE337AC8128C28B63A394908E4C083BCC4522DB8CE5720C45EF76B2716225E53405FCAAAA72AC198226575D5225195F106C1249E4B87AC05287A3ABE6C51A2A41E07F56ECDC46E989A8568D35669B525A6FFCA90DC91D3013967F6A5F4C022FFCC17751B68FB0D8F16FC9229851DFDCC060838F923BD44C1AD70A993E8EBAC1667DA80F91B66F8F5B375D35275188E3C7702C2312CEAC5B20D67BB34400401BDF1DBFE79DFA0EB73F173A04807215DA5CE8E1D28F2126424C3DB44ADCD7A961260FDBCAB31E", + "CAA02DD19DB9C721EB35AB7D64B8A387796427242698A47D832C3F1AD4DDA0B5926FFCE9319EEEDA1565ECB0FA1EEDB424414120AAE8CFD0BE88D4D248899A0BCE31F9BEE7A4DC4DB3C3B10444FAD6ADCCE28F0EDF7B808536ACF5EB05AADAE92693EE02C9512B3EEF000844BA35E24620A2E8935354B8432C07C8FD615534BCFD0D8E3B572BF2CF06AD343997590FE8B244A32BBE69125B5D7C5E513A493724EEA8DA6CB0FFF3ACF1C5085A8120694CBC40FAE1A6326FD71487CC3BE7C10A34315CDFFA8C618B68EA93D330945586B080381F0076351B888087F56B969E6D6A311AE03CC79FF6861E715C9DA9AEE751F1220661581C75DCEC0515A1C9259B9CF8E944CEC4B1754E5809E985D6F43FE45710893242ADE0D3B84F1E1942B7A95648611595FED13F546CA11DB8E5A55A3C3C78C3793C6689E1B3AFB5F67526A480DF923A586A779F94A09CF963594FF4B0A387876EBB3E8FAB888C97F6773E7F0317B038E47DD7D109545BB07263B1AA84284B86E47FFB9784A171D101E7B0A6D38BCAE7E63D827C999BF551728FFC642EE690B01D486CB6EBEEB9D5C888112589EA5CBC9BDF49E675965223416D6DA02D2333BFD4614706BF13373973207C849A0DE41EBA137FDF79A1EB25D74E30CF60B577C2787DF04740BA8CADE3F9DA55D3F0084F02809E37543239E0A71E99751EEB21CB3B41488244193A4868CBA9276", + "FB227530F82BD527E648619E532D7646A5ABBD15DB91A6E7033DFECCC65D095A3D83AB77EDD2F3FEC52659CB3AD1BEB009D7A1C9BFB544291EC1C67B75DD6DAB06E70C32C714983139DE4A41EE07B4F3C03BF566558484F19A3BB674B6795F0D8537BC31BC8D7A38B2FF1B2EC8B78539B2251D0E385DE484B05A411477681A3AE7527AC98BC2943AF1CF7F09ACF2DDE4530AE896BDE1266FE916E833A1C0CAA2B2D2F5985AD47B2D0D1D3AFB6E50D4B3DA7DEEC4385E6CA8FE22760F92807AC55556AAF7973E8016ADFD43A3919088B768351B1057498D2D668D7C1E8C63438055FDF7D36C5E7DF02FCAFCBD9291A2149E7B429B3202D329E47CED51EA5771772E308C5BEBA7B934597540D83DBEC6C3BC61A96EA4CB2D7530D9D760AA9403338CD95B829F17547C5A90D161F7B8CE0037EBF403C91C0D0C70C589BA87CAE8DF26CF14281E235A686CCD10E2D520A76265C4C2780EDFD0705E89EFE3C953FE760DE45A8CF1F2D3F36DE3164D5BC2CF32204228ADD7C182EC55F1158AFA9358BE179C722ADAF1D0BF1306A0B56218857FC5C21001499F61E273442281E585B3E6DCE148AA97B6622B23BDAECF983BF186F1B34962764758AC3C20C84036061D49CA33B3C3FCDF03F47F7E53B940DBB6E1E4A26702A118E525A9A0EC229085C925D133750ED0B200CB28A113289DE143D1D5839D2AF8B0525E0027F34FF32106A", + "9E5DA18A19514CCC849E9697AE4BD1B317BB34927D0461A96A7AF4A5D6C13107FFB9DE38C5E8CB7C5682827F57D94ED2E77D36F9F1CB05E4C2C62B1DE254C7B1CB236FC4ED70BF8DD1F43AC773C16A37392B895F8B157578C477C85E53FA7CA58BE70D9187AF5F7A18D5A1E5642335E46C2F8F4691AEEE6A9692E21B9668E2C083D9F45C2DB3E991588BA87A0A23808732EE39E8B3C876BE79227C782F07EE3FB3086AF913D71D71910A0F56D62B5DE5E224F7856A42A4A1B2AFE380827BE86E381FCE486FD08A91B22BD91D09615F417E178C5593E41B0917E075133960AD28B4DD4096D1E84BEF1363098DDE92C29CD508C40BA7E785F46C1E0DC72E729D394911DA919EA6F94D14567FFADC61CEB8DCA2821B1CF048477E2433E9DC718DE618EDEEF302CDCB5DE472656D6687DC41EA34C2BB4DF1CA08DCB933BE3EF4B419158BA0B68AE82A64ADD58559214FD88A4CB34D99F646310697DA982C2FD4EE069DC1CB102125C34A89AB20F17B6EF648A834627320410FF6881C7919AE4E71CBAE5F8200E523934D84BFA897C44B89B9BC6BC0129F7F97EE0EC049BA1AFD67D00CD624A75FF5A30514399BE4801CED057B498B9DBBF0EB9944295D5B6AE968C4B8BBD2B9A9E17A3039C5FA35A0D30AA54CA426C58353943DDDD3FD185895C0DAEE950455FC131F520B46AE118C7406D0A72BE6127C5307730AD441B6FC3D1E0", + "8589F8396F5B1C54CAF2B17D4C152CEF347E66EC7903C878F2823D4ADB9E7CCFAFEBB926B7EEB4AE1BECA339A027CE8EF997957532FA871F356E0326ECE0BCE3399F81179BF78C5C7D135018ABC340C0BE58D3063DD7CDA4C1918A0187BACF830C8B6900D43B62E04DF6E831CFEFA13BDB5E873A527F24327C95DB4BBDB65C81A20F959F828F5DAE4DC13E5CAC7417EE089401FB497ABE10144E28EA383E61D4A9B63B618AA7CEA4588B2911EC581F506062B05E7BEF723A5A465C9FBE70E313753BDE3102845A79A206BF7D996F49A21752D534B73EE83B48C1A225F85F5103DDB9B6B8380F61AAF26E5CA643EB62EAF58AFEE0D3494E4F7A4F642A3454F4F56A406A264148FF5DAC9DF5F151C12E89ED9D4FDCC04EC5F0022DF8CBAF3CBC67CED2853FB4F8C5894C96CD00550950E7EA2A26C80A72DF533270A0E23EDBAA4D0BE935D62CC885E1CCE653D66C51E49C43952042E1B2D043BDA1CFFC1E98A3F806EB587A4EC9AE299BD838C68B9BBF7C420C12B23AA2793FA0248C932A91BCDD641DCB38F0B2D7187D8986928DF4602B381BA13B263291134628FC91C8EDE92594B39650B877D9A91DAAA05295457DFB2C5D8207BBCDFE16AC5B93600E33BC970B38E18808B1A732889320352B524B109560136E605D32784CA01F8B11D077C81EAD6B7A5741C82D76CEEF764FD07E361D531B75106AF1572AD1375B2BBAB68", + "A3E17A4CAD2ABE76E32D18501899F8D60D293BB1AC3ADB64F81148AF56741790F87F8B7A2D9A6E7645EA50B75514C394508884CBF9E320B24D41D8246EB3C163B9101240776C312DB63C33889E3C1218435850471C454486DF7FF4D2DC0AAA14980F394CC8EB7B828A60C53A2FEC3315BEAEB30045B3E65006C6EBB23B47A8A069EAD45E32E771B9C467B4359EBB681AB48C891ABB796544169178203BCC4BC6B4A278DCEFACE5E9385C059346A23DCCA001FC9E47CFEED4BCBDD947B12A3F7E5FF8B9372D9497EE1A508D8BD3392BF3CFAD58F0191B18F6A300FF9CB8D914FDF37B48BF24C2C5CA76ABDFCCF833D51D48FC90E06E7B972944BCBAD169232A8429B6100BA562F7F3C55A625A1870A7C7D7BC9BD4C4783278CD95D07F89E8010E78876547F9AEC44322B0029A922B2922634ECCF2BBB47BF87909C494049550F1E6D03BB5354DEA7E777F499D2D6239BFA5C1CFA536F8CB16F4DB9EAD96F83A4AD34AE2C6893ECD6994C89E7F4FE426D95A18F93B88CB357996B8E5A34C43533EDB1F28A8162FCBEF03704FCCCD80C32874F345D34E81EE813DF5CC9B9C299362F8443AABE91BD0EAB9746E431804B6129FD32916303A570323FA121F7AEB2829F2A50A82CACCF6D273FFBD7AC6FFC5807771D216F50742F7091946F91460115989C87E8BBBC8402B4C8B95C102CAB53843D581FA9F16C0ECCE8944E5FC4BF4C", + "9D7B1CF0029261D65AE1F021DAFA81CF1673C9E0B47FF2C37D1B1AF46E7A91BC5E529C8F93EE3BC74E92B2743AAB1EDE16A6523B5B8A591C617C1FD0150E63F3B7EF0494162437B0FD555A83A3BDB519B3BB209EF7924D6BCDE5992BA6248690442E72CD5EB64B4C3D3F7DA339108A18B61AD88ABE87BB7C85A3A352D7B882FD683B2637A17A2D9CB0B7F41456DCFA66D62913F145600BAAEEE7EFA5071C3C9E6FDD0A6779A737071FA6965978CBC89776386B108DD7216FCE962FA87A26B29FE0E732309C0124B0C1E99E5642E5EAE670005B078C097D16C58B8923633C18FDB0E8FF8C4610B789387ACB5A2DD0B6AE7E0DF43A6A9E8C3B89C7E5D628D59759C58D07E0687812AEDAEEDBC63B4FEE8524D10E4B467696957E6791C1E94B13CADCD0ED60752C2DB1B65E035EA72F89FC679138D3609FD2A30E4DD1A946418253C67AA69B07EBB95D4973F562CE3773430007A6DB77271D5F2B342CC5E76E115178F9C7B1600554F5C794961BAE81A5E9B621BA17851008BED9B556E461A553FE9BE00A40891750E4EA4B475216283B530CB8D479DC70B026E07889229F6017552AB9E01EDE6703FD1E2D59AF0B71E0F1DC9A42ACC5823324BEFC52CA0DCD25FE8B10C999152AA3676A30602D3506F78751477033DB7AB1A2EDC21A6FE51273B6B2890088703CEFE74F9EA89881896E5BE124B1FC9430B92F0C0568F5A068A80", + "F23088E3EAA0A6BA04D0633AAFE85203E8B1829223FA6B730F6DEE6799B521F2E8323B8793D0F7F2BB9305B3EF4F5B4F1CB822836E4D92C8E4928A851BCE688329DECA6F7285DCC85195E5BDA3B503B8AEE6F1CD7FBB158444E7DE8BF6A9A3CDA311787755A827BCAD3DA5621908EA913C0316B9B52BFB07ADADEFF17D3766BB450DD71328A0353B09DC24DE93CF83A2E5F98BA9D612187B601157D6B140E675228B58C9398618C3BF0D11A226E489366102B9C35A916653F0DB36711ACBA5F32B327F5789F3EF48A338E4676F4BC2C6A1308597171903D2AA299CE7E523C2ABE4B15AA4FC48954187E0097583EB099419047244B4931326E5923B6313DE08423DB00866374ABBF5C31A00542CB97CDFB8F71046AA2A6DBFD7E1A71C068ED70E8D7C3268EA3E0EEF2262BD7991B6C59FF471F73A4E85F4FA015E164F9C15FE0AA5F4772BF2D62B26D3EAA25CE83EAEC5EB3577CA83A68168FB64C40A7A155905CBA6E64159E55EBC928D125E55165C639F545B0071EE3CF1A3F58B4994BB4BF50C2B24F2E06E4ADC90BC1C0954A257D88444347AAECF136C15242633463DCF984BB6736666E38F1A45150B1B7D1C31DE06EB9C2F4097E9D9B4D21EBC9F3A918000DE2449DCB3F5FDDC3C773A645DF560F7E013E847E2356D33EFF1E215782638F58034B09F4739F98915BFB0B1DC124681492F58021670D03CBF5E8F962351E", + "EB07F9EDF03596ADC2A3B7EB6DB1CFC911E9A4C42336A57309F7B6C3389282E557D94BCC71827D7C5737B1C530D2A087E3F507242F3DA5BD1BBCA4DF8B78BEEC1DBF7EBB2EA1CF1DFA79E60785BAFA23658490C9A64AC61C45779DFAFC6C55CB5C9FE457BF47E45A3FEF092E178ED4495C0357B459E95AAC82132FF1C8044F4EC84EB882DC195D9CE996B1CCF523098E9E1A57C37C2E2D0ACB0EAA34B0B56FE5A0747130B1E75AA923F6F94C0D024A7FCD22E7A4ED8B201966C417AE864420767AB3223BFF56C64D4F8F557DD950F7C50D9A39AB2C742CE686C8F92B35711904C600A9D4D3DD83F3DF1ED7DB8042C76B0B7D5D9BCD6E0B5524184BF99D8D0B4F14967FA48A93A2F44E2275ED7E59F3991EFB0CBF2E26AC1F8D9A41AAE4563179254BA37028867E68C8179454B8B71FAB49DBD1F889104CFB64C8121151364BDB64BAF854B0DA22B8620BD7EE3D4302A88A115F8BFBA649CAA9EE7EF5BC95CFAB26503A9D26033370A4EF3CB8A5D094C63305A833387B4F8371C6FE1987514BB458C571E6CB5DF5FC900631652D3FA4444F8F1F0312204340FDB2092F709FDC51D2680753131ABC33712B4F1067EA1CC87C40B281E69209EDEC42C22A88950E9C1CE8130DA9291897BF2D8D1D106911743E7A9DA36220FA90A02A34EB0B28543217839374EBE79F40B3B612236C902E4CD05CE2E1C07F3DA10E2AEE8E387494E", + "E9D537A821DEDE526B441BA4252785779B54DE76F82747F8607B8952DF990F268C039CC792883B1C76C297D81C6C0CF17DA8BA2C71110B16741728725839D33B5942BC0A5614A3650675FDA5D70F29154A429A42819D6EDE324C64596F93E84CC9B2C9DA3717AA6DFFCD03B75AC96543020A9F2024620353E1364E4320FD44933799FFF083E73F5D20B83BF77EC2247964ECE442C3213DE99026F8FAF0E96302EC60067EA38C5CA0CD989475205FA38869E349FC7F79EB81F8457CA3D1A875A8D166C96EBAF1F39C88815E2258EA1A14943298DA39EB9B738AAA4E0035F9567A0A9D572785594496316D56EB3D39E1F3F243D4F16111E194FC537A635FAEB2FB4401CAA9EE0091CF3CB28B366CB5446A6D3B10AB86B4B1A0714D107FCCBBD50EAE520D56A1161E03849192F5096346FBE5150B6D04025A564A43A3D22BD4B7E10DD4061CE20FA2ECDD36F66BAAD7EA96CDBAA0F063B814707718F47278F8570F77F3B15799D0E354CCA50DAA38C31C746B17482297D9C089FF379454FCCCB8730D89B1462AD95426370AC37DE50B775B952663B97AFBC403F6F729BB9CC1D21DD89EE78AF09DF8558F7E68B3711A7D9075DD4754174802F52CB9683FFE746471C7E543FF388D024327D1866CC5CA6775C58A14D70A3ECCD3EFAB52F9AE6CCE146766A8419FB546E39EB604F43B15AB88C72741F8C7D0A7FE2F462D360676D6E", + "D79D916241BBE52B61BE8210A02543F75A47032E9C0CC128524A675E94D8F79A69B6842B0C5CFF5C1AC98D2085299BDBAEA67A41C724CA36B6275A80D377DC3A6EB4C8D0B6B88241334A95300B53FFB546163D2889D7C85F1D1397924F126DA76085BEF131A65C7DDF60DDF4086BD33B44D25025D689FF41E0C256EA12F4353D9E722EE37907AA8BED0A5A606333A031AC6B9A16614250916759B72FE6C1828BC6C1966C9EBCD51413A77F41F808BCA2534AC49DB1D32D37878DF5CC0BEFCC099C56CAF50D8B92E7CE616AA026EA1D81DC7ABC17C4705F9B57A0F99FA749F30F93DFA982A083EAE6582C8461A11ABA74B11663ED7D66EB4F8DE14F090EB1CA6D8D81CB6B063A391FD354DCEAF7DB71C277D0E92B4B463873DCBEFFB698BDCA17F80845EFD5F0FF150ADDC9D7797E21E4279B54BDD4B7C9D403D9FA6101604B79AC377780A5461499714082942313CF74AD1147CD10571A31D82871B6B3A055D50C6CDA4BDDF3871F41EFDAEBE8ABB995344DB6366E35C6E506907AD7FC76632F99124A58A32C86360FD6DDBF50324D86694518AC44F1FA19662C0EF0C0860811B5B976A96EC2A1449E53A7E4A07923E9F85794F228E441D92903922E5783F2FA21C677251B6B8DB02AC2E242C0C8652E0C17C9E3858E52DE78DC712B2DD5D2AF9A42DB2E2BEB3FB6E0FFF13DB9A1E02C8F84FCEF3F7C4D2DDC09F2A2813E8C2", + "F8E2DACDD88277D482951555C657B3E3C5DB79E5A43500F7A2C8B30C854DBE611FAC1087FA03D439AC4635D39211E234B82A91248DEE5D4FE67A02D5AE25C676E64C4843E419EBB3C4D81FB606B9CA0836F8207CD19D106C0E287EFD8F8DB5C1A3A22886C2765FED26B5189153657B7C47D5590F11C6340067B800669B05A0849BCD2005DFEE6DF95833C9E94328D72F931D69CFBB2BDA81AC83DD660B3B17D2BA4023491DED324FC4F22510ECA4A5194B1245F4F3FE334DA9C1E6BF83A3FB30897BE54C688D2A7C5845F425866F25DD0A9852BA6DAAF8437DD80BCC72B3E258A906DE079A2D33EC5C5F6927503BA13158305DFFD3F86345524394151AA557D6242060F276BB6BB25586F632942ACF5E0883CD3F8393688F360323A000B82BD89414E9C807994B0234D730BC6D7CD0A2BF75D9F510786E83EE98D4CACF20EFF86EE9C38B8D52455D8A694B689F0D9A632E7A6AC6675E190A12ADD716D2C6322657B878FA97267C1BA4631584356768EBBD1F13FD2F37EBDCD1DF96FB943942E8A5188666235B455BE2F770C9759A8F070971CBA49789744FD2F64DC4DC6E003B3F9BEC7617C7EEDF6BACA94D374400499CA6813C90A03DFE2C537261DA93A1C0F6D8BA93D1EB5FB17255DF28B78737582FD675D056A4C474A71CA8EF0D77BAEBE5637711AEA3FF2B014700448C3D74E3DF264D773360F45CCC3342987169C9A", + "94741D7F05B0CA50908E6BC14801A28E353551F01769451B1482FAD0043D5C72331246D9AC3344F0FA2E28FD00E86B38F5E0452F46CA111E92D01B37E966455DF1374883DB8B055C4DF25B42182280F86D0D825C096018D2949B4BFCEB7BB2C8A5BFA2C79E27F11A7F9B43A50AF928D81FA95CEC86A114222B99786072311025672AB04B2593C5AF50100B71D052AE268FBA992BF7868E58EFCD07A24D2111774A36115C1C527B5192EA955722EAE849EF83817FE8595C96EA2D76FECF6476D89F65A262D94B3F5E89A5DE8B1A7333EFCDFDED17FE1CCADEBA0D1E7B73E67491B413A862E34A308D5C211787E6ED8683C6E1DDEB8EE2D281166C03E7A72D7D7BD8B878D07D2216C21B855CCDA76B7B75DD1B2CB876E59F91F040D42B97050043499DCFFC65AF803E2F7455C9669DD9896FE1F62227936DF905835A644D31130A39479DE75B4DC4361E41202D51D50E0E4B4B218AF7F5CAF264DCD060C296E777DF1EED6AE8147E9B6CA73184C345FBDD89DE4A999C42AB4681D9EA3B86DD75031A33DCDC807F8FB14EE0CE61B16068AF01CCE7378C9D965943476AD21A469D8B0CAE15BA8FE04971FE1EC61D3AAD3386DF71B33FD0B4F324F3DA518F0CC0353182B3D76CF4EF5AB150FB9E74C28234CB3D907AC81CB6D3B99D510B481E1F0423D6F4987F5517ABBBEEC07F46AECEBA5F15D91AEB0FE91490E91F739D465225C", + "839A01464B473A64A3D1EA24EB363EAAA590F4BD0E4492FEC4E3D4DB5883E4873BBA17595FF48134893F16F5C4A43659C46484A268C3303B2DC345E8C98FBBA6D06946F997074AE15680EC9423D6464585D98804B3541662E183F6540503BEC204749D58E3DB9ECF11C80CD3A38F8D66FFE6CC8A003BDD35F547E5039DE9A21F70A8A07B2DD89B68E43B42C2E021A11909817C543F839E6862268E38DCE712B4D49C39A5035F3D6BA19AE028AE70CCF557720794FEF6442999E740CD6AFE6235F165515FDC24AB6F578DB2549C8065E008577FCF8B8DD8A3BA679BABBC9A747A4E2DABD91501424E4191097E689A741EB6644A771CABDBFE6B74ED3ED171DF8DE641C1D42213B9D0F8CAD1E11FF63670F5587F1FB7FF92276AB48F31751E7A591AF4F0966F3909883EE6015639671BDC3D1378750F66F5DD165912CFF1A54ED463905404EB7D3412EE2B0F0D9E6B99EC81678ABCD1789BD8F1D72D3DF8754A16DC2106B83B325807E27BCBD22A25DAC32F27EACAB6A4CB6CBA4CC90D5302BE5E9827B7AB48BB696B2902975C48B3A4BA4630B14E0FD8A050B0718C2829371BEC597387172B0B3192EF958BD1F7977EF9A3A6C80D53BC961315F97B714253B9731A017BE2CA1D43024F75E26BBE989C4D514D01538956FE4B90BE17B3407B55BD08BA50FA807D0E448B7CAC65EB3FF856772A933F0C5F3E6F41E051015C6F9B8", + "BDA2B72F0BB0265269F198207FB061DA29DE43E30847E7C062A581A7EB53491EA51B51EDD36F991D15AF89AB53198537988350FD5FDF8E003019BE115840B9BA55C238C3CBC72C0E24E25090A3D6A59BEA9FED0FAC9EAD40451A95649638FE0BB0F8FFE61AF5B9A8AB84BE84C65EA1E12E9F6650ADB59A824E608E80D1FC3AC19F418169B3879CC946165511D5AA280AE644AF360C42F7A3EEDF27E368E46480E3353E67F536E02B33505341BAF3941069567B723D7C125C8F066F9A6255436AAFDCAA8C554FDAFB0A9AAD91F1263DC62EF91A748FFB29F57E325D65A38ECB4F2851923DC6E9B7296064148A9BA2D938116266C597D9E1F11A46BE0EF526225BE750F0F3E5B0AEB7DC2140FA3A48B7238D0F5A872000782CB6F7751443EC6A1B7FA1ED02B9ABCD1C1DE4FC85E9B405C7851913C60F85582B1529276AD475AE52BD8115B6E73A53506E7A0244E1C29BCEF4CF20CFDF883392BB3990BE2A11B3213B68EC4A166C77D724CFAEBDC34C45ED09848A994BCE1FF6A9BB80C7F5CA8FD44D3FDF8DEC8BA6552C234EF8DC52382D52D2B01BB23404FC453725C7C9269A785FE09C712D4ADE7072B66295CA0C6405D9859E134FBBD3737F2956DD1D718A9F8242CE95BDB1E49F265EBF19976BC46E29F7DE0EE5C89A43AF2E107588A46E1B6762E6F8E48B8FC4F4FF93EC60938B8E5C3719022C750C4309FC62ADA4E9028", + "D240216C5C4A70742CAA03AE910E8859C92E5A90A352CB8B45847BAC7793E1F75720D44919E896AD4581E1FD83986FF235C9834BEECAA1556794BE49033E79D4CCDB4DC67C5200E8B6A3EE891E700B348CBF092E4D3FA5E648B620E34E491D7B628A1FE7E2C45586B6577E50788687F0858C10F78F371B25C712ED2760C3D605D4ED4F052E8B66FC308D3ADD4A9B86F00CE4257EED085EAE95FBB1E113FCB42CE12BB6076178A20903C55DA570EF8A25BA7AC8B7E134B8D4E35AB172CA33CC97294A5E7E579B9361B92B49B63BB1982740015DFEC16882989C917F50D5FDD9166FE1001F3282D3C54A28AC7FD773CCC0634AF7CDF225F94107C169D2F2BB757EEB55933CCE0FF116D7FFBA992F9A075A2439CCB369D5B5DE460CADC9F8C81D98E71651AEBFC2A918C551082D85F75675CDC8CCA1D3E486CFFB3B025D27C8D67C451FDFCF59C3BFA163EB791152390E9488C604B9B8116C329453A98F7A104527BC677411034CC49686108E569B7595E1DDC85918D90BBCB337855860D6E4718C0679DAB6982D23FCB6648E8561F44BCF9B052D8B58384523BC592C9B7F824B96AD1A39AEBD2232D6D34DC171E8FBF933900960F207B55597759D23E1E794507586114228A2FC100CC200D2B862DF3F26E6D1C9370373FE165C326D8C29FD2F0B3071AFD5215781BFB589F605263FF065B7A5CA3F6AA9DE3FD8BF5589BDE3526", + "8E7752C52805DD0A723D61F0BBE0122DF576A42B5AFDF9F196A766C9B3BFE296DC16A892FAECEEDD8256D2B1AE6BFE5437D4A2691803043B59862B30D68E4FF94A0700D735CFE967299724DA9D680200C898EED1C785E7B8CEB14F1DCDC73FC625F9678B407603587220C2FDFE0A47E82ADF36C26F942797D608BA6B38A3AD1A967315E1F2D665B27D51E350F075531A179DB2EED55547EA61761CD2B3962FCB347279117D1C7A7574B49FFE0991AF572A2B0C962A8A79800CFD524AAF9E6401C44569600F41F04422DB891D25B9F714713086BBFD0FB268E66A4FB10C0ABEEB31D0FBFBA20B0E4FFF404051596FC6F6C8093AD01807FA52041CD33007B205D15D47AF733966411A36F4C7B846D0BE049ADC21B89EA4CE0FBA414C005E66F36FACF3C43B474D47DAD78AC114D0171C031DFBE4A15FE1A22603CD79B6BB448B67A4DEDC97262F7B869C54F385F3682C744ED5AD6C0B6E16793920E6B45A024010896D5FECFA111CC9F0C34E728B32F2C4D45B8AA69B621AB9AC3D9D79B38BF205E8D0D19FAC44A76B9F5644526E06858F76B3EE2D74AEB1971D6B6E68B83773399AC32203164564B102B26C370A9FEC673C285AE0D1D3DF239D48B6492B89846EBED4618AEC940DC62AF4C3FF0D56FC9FBE23EE3B0A4890BA2665A88E9F40C4B6A770F9630234ED10A3A7FF3C5BCCBA836F3EDC8B821AB18D4B1D51D9962C328", + "E682E9D8E92A7837823C9B7714D267F9CE290E9FA6CC0A8432D3F7507DAF6CF681246AA4C2323C6B53BCC6E53B31F49742EE5F4E6F79DC36727E98B06D0300ED21F0CF5F2B51D8304A51D0B498F4BFA39C0049B8117DAD334D4B2E37676EC42DFE0EED63B3726872CCF9A10223A8A4563BE8AC266E0697004921DCCEEA5DD80C62567FDEBF2AFDF030192831A6FD871F63D5DADA4B270AA9EC0ACE47E75BD19018CB809B548D4F2C24831C384DD2B807852F596BD4FE32CAB3A16899D0B100E9F96D06AACB8DA8D51DB0B0F600F3B614461F5238188B5EDA68EA753B6ACC58569E841BAF92CEE04E6E2626B1FBD01B9B67D1311B1C3D67427298E2D193F0647EA17D16FD7FD6A40A1BDBB320A1F5FC64B97759AF4EA92AAEB759B5DD30A726E9B8EAFA372FBD83CBFF0000CA75F219A95D6A3CDE38B8DFA9281609A20EE39B73FEBDF6A155359476D073E7153BC918C1191C9BAAF0E0F161384DAD8AFC31A3FC1E9EAFA495E22D18C05194EB85298AB0F042E447DD627904B73E6E505712DF010531C88E695F6510C78B443C731D7FDCD62EB7C4015AB5D530BD09CE5229FA4DC5642AF176C39D60FE070DF635CC5435136C7BB9C4DC83B0D382B9BB636A6C2B3838542904D53B862585FE6EC8960A9A77783D17B2D90506F5D60998602AE5430E86025C8864883CECD7CE51B49CC2953A2A41D7EF8027F1A83815BBEF6F6B2", + "F6BD4204243CBA14DAA15A256FBCD138B5D875E28BCC0BA36855E648434CD04F49935C3D074DD5BA2EB82AB14E82C30991A1159E990D1D36DAF794853A23C499AB6B3DC02A89F014310372813643F786BF19D3FA8C463EE50D9FA87107E91C461AD2E5DF2FC99630D2005894CB7698123111FAFC0C5BC9D1E8E84FCCA5179A6C9AFE3E369222D66854F90D2668A57FDEE00C300AEA4E88F03F05C4D7695B206DE9F7E1D429E5E6B65DFE05D4C861F4E7844DDB9062C0B6DB46B27AD0368992F54A44829DD11A05AB97BA8AD854E428B87F20C4E5E4BB1FF3803809A81F2E4C109572006729A5E490E0AA40BA55F4391C9FB758EFA79B97E6D413BCB02D33A00DA6705BFBADED66CFC21291C494B7C3293810012ECC61415E609DD97AAFFDEB795DE36026B4602DD546A1AD937F1A6DEACD3393F5530C48A7974E2882CB327AE600C05A535BDE5D15AC524859582EEE2D62194B73E01643359E7B2625F3EB9FE7137514ED549A3196FFCBC8072B4F6C18CC67AAFA0ED6029A805EF0987E2F27A3260F849C68F3EF91DAA9E579AA16FDA698CC18AE8706E28C6D84CB3F593273D763C2969933D8EFA564E8C06C427809E6A5A6F76DE7C8B07FF4EDDF6CF2B7595066DFB15F5C6F3839DEE642FC86BC1F3AED7ED2E65B665198AA034817DBBBE0FE30E662B2161276CBD969FDA05AFD6D6A570C1E3CF7E324634441983F257E2BA", + "A9366308475F2D8D0C2D451C4A65A01EE58A0AF19B791D97382EC59A52616C7480B86EB1D0A83E93224B0DF73DE1D7EE6D51088F3B20B7937E6C0144E0DACA6324F0C8E5F9D93A8CBA1045E5B509D7DF98619FDDFDD7892C3082D69008D9D3ED6C9C1367D9DB7C04621D7CDD8A5A2599EE45B87A82F8CE8D60293E7A71D11700CA9AF117D630C5D8B876A9DCE519BD653114448C68B265813C608435B96CD642A420A15FBAB467692931BCA74F1F9D23F5BFDDC5B8651139B5A73F04FEF3DA64B7BD56E49235069EE5E8A136B921051F1D1C7D5993E6EEEEA2D58583152ADCD87AA89CF5962BC8341EF99CEB3682A2D0686602CE140ABC2FDF79A778A9D75AFFDBBA00C0BD6A8A8AFF9B5D1F30C8373572C81BD9594890102F46B5A393ED126C36AEF6A66E231A246FDFCBD3DED198ABC54CF357ABC67AC83680C048932D7C902AB7DB16952B3C95DF4E845B46A362FFE1A27CD1388483FFA41AA563933371C0180848F9E3C03AFC1F00D6ABA29A953327A4E3D9FAD4616C8546C9AF89FB4D08D4256923B736A8F68FEA5A097E0640C16E0F7F942E6A6F5CBA76BB00D81C606C7FED908789A63F01F9B5FC7B7BE434E85A0A44B2070BE71AB2BA0132D9D7B32E2D2FE229619F85643E75B4141D355386D1A09F45738455BC21607086C7BBCD4B73F87DD83E905BCE8FC6C5BF1824E904C4F5C26518B2FEBF8EB06B22437270C", + "92D87BF3F54B0445C05E508E80F9CBC0502F0897D717CA232004362F394A023BFBFE3322C1D331AFC6454FC756FB48768693FD5C46DDB40DCBF14C726C24ED67D8F3EB613BA80B0E39CF0747DF62D258613640D881E085C377DE1C3D149C8359407C2C6ABC0D2718A2D42439A8E7B38CD7DCED72AE750B2BE88D0069FBE94BD69A9A4B4AD42FEC5E651A31F86B90DC2FEBAA6FA6E5F6368B620C1750278DF393F7C5035D47897FC05FBC419A61330135F24365F13D653D77CA2930DBB05A3815FE83F75BB1BD8B2DE12A2FAADCD1ED62329C55B87FB32CC8F3B42D888981B4192480D1F57CEB0C55897BDA6B9C0ACE1E7E4595E30C7368306243208444FCF4574C47B07725B25EC2E28F4C50B744B3860B361DDDD22D949AA94EBA4F97606FCAD91394B6FC0E634BD15E099E697403B2AE84CDF5DBDF36D91FB82C0BC12B984FEE83CA9E97C194CADF8382CECAAF49EB3BD446F660F94C188C074CC312E186BEE0F6585535B050C226659A94B4C4974DA32CDFF30DBEB4DEA588C6F490F7432DA5FA2408BBC931EAF60EADD7B891A61C157147B8DDE7A45F909BD20D5B12009783DE410940245FE4E91ACCF72942E486AE773CD665912173EA29875A1722F8658C414CD08CBFDFE1DD356E167A9D7B20BF7441562EE816435A78BAE7E5A5EB4DA6AAAC36F594C93E2851D76B6A18B0B03B30CD38B97E38109C494C557643D58", + "BAA2716F115D72D2037841EF9138D19833C7C5FF40F058A960826E690315577710EFE64BB37691564B3B0B6C577DA603CC3ACDFE1785541AAD23904758A5A13BDB018E7169D479A1FAA031CA72FA6D6AE9613D6B2F82AB07500B49DF535F86A76350C140F9CD25295D6BC2F38C5D13C99540E2363862F06DDCC486D884999BCB840BCCAF2AB84F5906B9AA0F77D6432F6531558392641C52FEAF9D8ED86BF0158134129F34ECD0768BC02ED442254515A74999C6B8052A1FC797F5720738C69DD9B3FFABDDC8515CD279B246EA7C67754920038C5A4C8D301119CEB95FAB2765DE39DDA84180CEBAAFBF4976118A8373FF6BBFC7FEBC3CFEAB1DA69DD3DB9E428C594950FD51F4D98A393BAB96001461F2765834ED70C60BC56406CFCB3E784C59B91C19783E67CE6C86713C43DCDA9512B2E7173AFC2EF9A172C9CFDDD3000D7A981440AD994C39DAE6FC0B645BA0FD49ECAA19E572ED0FAC748EC837A7D6F28A8D004402F71CA209BB9403B21E29836C5FE897268DE0736E985F9631DFDD1AC59D5411E684BE082F41108E33D2B92B2D45ED70FA52EA2D6DE121EB9F9C886DA479464A9DFD9970A406491E334372D7B78936095A7459BFAFF0E9090C2C6B6D62624A79334F879A5C92C685B50F75F04BA664EC95893FF40D62EEB24DCDD288729D0C297DF5ABB83C77FC11D0EA3EF18E3BC7C2C065CAC51390C610B591D24", + "98CDFCBAD056240E180F347C00912F2D9ABEBCF5464D410BE6A50404B830F744D78F7D97180404FB3BCCC2288B7991810B2562C4D509200CE1F9C4DF6DCA4C600D9ED49C9C1456141C7B71513E728D41970ACDB6C15B4A4E327B9A87ADA73D1D46EB0A21F2F5481C3B42931C51B780FA526C29B98E6B9C714B20049F7A05252CBB84B8E36026DB2379C9632A0843436ECB72D15EA2950ACDE18DBDC6DFB01BF08F7E191EC885F11D1D8B7BC96E9836B395108F6854545082A694D5974CC36C8A658349186C1BA892DAA85D3F156BFBE94C73BCD815E7652C38E178AAF02014F0E6F23A4E7EF689EBF3ABDCCDD40E2DECED316F07E20716927C8F7B203D51D957EE6EAB062B99ACA0D28E0AB50B516CD92CBB9BA90333E73D58DE0B4B633D81EC93D15EBCCC813EE63D63BD18517F4FE85C37469574B8122FB91388123E1D5E805166FB7157494F8559F90A4FA3DE9E71DA6FA7CCC6086E638BDD4FD3E4487506ACCF84F1E1678D714B86FAAD57A6B76E085CFAC30DE469BE32E2D203C63B43F073DD24F4A1E039B941E7A97F8BB28B516217455268B6EFBB0E1745C23D6D12A8CD13E5D242F562F56FE92496342000A731BF3DB0A7D3110705DFD0D8DEFB85665B77347CEFC8629F3757304F6129DA9845F6509FE3D32DE9FA86EA4FA9BF86FF7CC8E726C0FA9F93F889C467642C5E944501BEF8ED59793AF8804A9951B4B88", + "906F6C5A1D3BD03A03802EEF5937E214E87B5E2F0182BA2C258F44B516EC66EACB705E06EA6DFDB56600B8463A421DB03A51460091D7FE889E6DAE32EC19190E7211F08D37846CEE7364B6ECC07C1740CE990141C4DC4CB0AC9F25CAFCA6BC9111102EABA250ADFD505201FFF638B31A77CCE7A1ECB273F9C8ED84EC2F403C1191596A53EAD823421EC47DC5E78F3BD1339532C97E4EAA024CCC906EBFB870C1467C3D845A178EB07C11BE8D57E4EDEA7ADEF162923E9521451B871DF6E357DCEEA7F62022106F647DD8A23074AC10AA632C56DC32B34A4A184FACC64E5D1E8FD69269660543EEA2FD584117A3EBCF6268352F0212ABCE7CD28A93C9AF76722FB5A71FF9E5AC4579A2BA32B91818CDCB62C77A6A8EB1F4C34132EB463812B329B6B22108AC36E71F38338AE3A52C632796E45189632B73FDC0BD37A457204757261B7CFC01E06BC767A57A5FA7CFE43794F65398A94B4EF09D6DC2A8691BD0CB018BBE7B66E0C37BAA4723247AF3424BDE22614A9A581A7982E8C2323178BD2D46E6912A2FB2D2531819A180689D7F2C9B5C5AFC2DCF1C7FAEB1927EB79A72EB1203BB0FF17DAAF27D66022195890BBDDA786CF1C36ABFD96BC36FA1D2A5A0CC3D7EEE1A1050CA840209903CB9FF429C7EE9DF9CBC2BAB84CF28FAEF5BB45AE9588970A28B6BD9ADF8DF134C1FAB0DE274B5C7452C4836A573A26A0B4C14B74", + "C6D5046A5000ECDB54C872F2DC494F2DEB88430007C9BE8EC39FFB148F00F7861D8277589AC839AAD30AF7D7A2E0F9EE8217A39C521311E9BD59A71BC6663A7738669D6D3BB28124A80ABDF905DFE2C9539CCF0C8FA39EF84E9633D63BE0C32F3B2AA9FCDC18AC38C3C00924E9D54977BDAE61410F997038BE066DA6C945D8258B7DD133EECBA836A7A6A2907C431C522619D466430E6ACF15030F7FBA4F3D6BB545CAD85678E81898D2DE358CFF3951C8184066B18930DDA867890871AF6F4133B492FC894DBE4AA5F1E44BD361C4560ABBCD3101B4AA4E065FD60308795DDAEBADBB604A3D58776006CD074389AF49A0EF09586410015C7DE4FEFEEBEA6262B23571B93BEE15CDA2BBA60B6CC72A7DC9C80C81C9A25FE3D149C7A8BB2F704BE11177F92E2CEF0BBD12C0766D691CCF093D456AFEA411A8FE5F1C1A44F31017760F0D0CC3B271FB15F56D9F51A594C34FDFF8F8ADC91584ED8D7E1B6DAB27B2BE1BBDC4486FB1C822F23704BB2EF4B521E02E42FDCABF69588B0B9D92AAA73116D26E8E9E48DE94F6267414AC845467597B4C1F2A9A8E1E82C0A1C05955022CDF87386098EAFC5BF1A040716A89BE53A36B143376927028A561BBC07AFAF42494DF5BC0D95170D853DCCCCB22FD36B7947712EB369077D02BF85B0A4F57757ED80B247E521AC640D1B1CE30F93DEBBE2389D364A8B7971A51AFA4F557A8E12", + "FDCF36E6C842D2ABCCE9D8783D0D7A7EB74992EACEEF6C618AC7DED4E457B1A708BE2C82B28A9563F4A088FF7DB146B16B47A900DF49A4F3FA8EDAAFCA09F408B025D04EB673E105E0F55959B7951CF0E999CDF68EA9B32333DBFE0516D272111CBBD9933CA8AD8AA6025E5F9A062D8305344CAFC3CA391BD8DEBDC58F7FDBC041B349900E397609C71E4EA3A9D8407C63E8A6BBEEAEFC92E9C939147920E48E35DAC6D123DA46E4F0838FD732E43FE4EEF6BD68D5AF0C9BA3A0CB28233743B291D4E10054F695DC10A847E661F39C4C133289B07ACA8B544EE3E2EC288CB18C40CD9A8E48A93378FD50E077EFBC21996424B539A397B3D2A6C7DE58112CF55E82E8FF10F75571A15DC248E6B77CBB91D8BF2D53E5C4E9A85C7EB8FB690F74BE029CE1B569EFACFC16872C5008820FC6A7D12AB43E08B4AFF57DE6B43B613DF8480ACA556E29D792C6C81CB1CB54A67245C571A04965267BA0F9CD3FA0950B9A5B393B4A230A41E455267CD396F42285F0E49C5AFA0B53EC7B60C1C317EDA3FAE4B1713A80D4EBAD32FC685C13649C4806D6FD887A24A4F7AE801405EF28F058B37112A680F9E9AD0456314E9F490393CA25775797E4CCF9184FF0C6A237AFFA8DE1B84C420A6183B1D49D6F2AC1E673E7FDE161A8159DCEB00D85F032EE76E3931C459CE935DFE4AD6C6110591EE58496B82A16630E82320B9510880BE4E72", + "94964FC9F66389FE3880283C4250E6E19F195DFEBD2104FC0959E084308BC9CFDC6E5ED1C4B48B4ECAEB4FDE5F215FBED85A6CD4D1C1466E68A4CF21AEF29F77933549A3A6FF7ACD8AB6E6C689F1E8DF0AD8AB289D5C33023DF90B21A26320CE8C1CEB2C099FC1DB58737665855DCD20D587E176483E33EF14C80AA4760F751EE5B28460811E5110FEC3D689AE2A6E91D0A3F1E22623E88571F4DAC895AA428D42634EC142E56D0D57CE68D7949BE13AF234229E546E9D66D5C58E510BF3EAC7B73309BE16DCE6E2280AA80247D9EDEDD20E06295C9876B412B786CF7E5F1073792158131AFA002FE7750A17015A9C2580646A9A0D2A3F0243AF1AB4FEFB3D028504553AF9C5C34D1A4A2FE3B8DD8BF8CEADA82AE63C319BD7981D97155AA2F105D724A8C09310D5C316877062152419A006ABF56AADED74DF0DF325D666C31DF51F194CFEB331E7DAF00410372999D2D05B023B2C3067E6CE4A472FED3B8BE1C15C24DFBF4956A5B670FFCF128E5A23039764BE39CBE55636B83674060B3CCF5EF9A7B7EAB0813ADEE82E271C422FB78A9820007753B1E62BF4CCC074F7796D5B2008FE6542DC0C77ECA3810120ABE9F90BE5934E8EAE365D02B3D2DF4EA4A827E033263B113EEE5823DD3912FB31E3C4B46B274D7115F34CDA793DB6AD2CD8BCAF4B13B832AB605BE42B2877EE2E66B411668EA29A7DBA5BD969B9F152638", + "9B8071D96E7D361B2462CA93748DE4D31746972DAE582AD4F70A188CB40C2E6E418288B6A713ED4B647013B3EC31C9EA6217DE55D016A1977A0B285224129CDC59A9E54F3E5094258F11C0C995F60785614E560764312CD86C6969B3274236EE602EFAE392C015E4C3972D6FA2A47AB48D5C5F6836AFA54F28CCC03BB4DAA0A1DC0DCA3FD3F2B15FB2ADD907D3BF7719D1D9A8284A47C30F32712A8CD440148B8DFDB851FFD25ECA2864150B832F8B5DC3A7C701371785A66285601E96D285FF88947804AA4D88665B3E15760CDE327FBD21393042BAF62FDCE6EC41955E877ECAC331D594ED40547AFED34D410714CE57FCB4F01C8826519ACB85F447306C86BD1BA8189E0621DD09451E8F341AE47E7FCF1FD2DE2AF78E0AFA27A4B6DD51A0710FC1FC4A5998234EDAA1D4CF0786B779F637EE1A72058774C1B4BF5E125DEBB4230645ECF87E3C6FDC91E1D14397FA72686784815D9654839AE8FA43864709EE0F4A336E3C399CA20B2E652E2AB17719F9253F772EB7A9E8838FED4EBCD0F8CD977583BDCEEBBD925676F56AAB0C36F3DD915F6691A30D60D523216FB233CBBEDE7FDFBA827450E595AB51237F9E77058E40F862D3A5A96E4AA3DA74503812EDEFA501E526DB6B4C642222D7F33B06D9CD0023471DF5730CF8E2BEE834D108A25729C1C1484C207ECEB0E4598965EAB5216D4E7C30577A89FB8BEC0B118F4", + "E43093167F77AAA20EF9F4AB7D715CD0E86542A0523BDF0256BCCFB1FA987A6565F808C03C71E6343EF41D2ED4C4FDBBB1AB1D617BBBDB776F07B000922FCBB3718F5FF326A7BBF4BDF148206411E86506FE5CEB8EC0F7AAD1DAE3BB46482F5E85D3B46DDF93F4BA19DF9DFD700C35DC038CF4E499A058995AF06BEE8535631966751A85571271E6877BE6216AFF16AA2B9046F1AB9126E1DCADBF40C4B390D23379D52C80C10CA05079D1F05CA294EAF7E2C66B884DDBB52DC85A45FFABB2BA6EB95869689486DDDE372DCCDFCB408496E647F33575BB99FF1699219D00D2608AEA1A47CF52DD21A3CEB3F043AAEB40EB27F042D276227C09CC8201304C55D254AC228FF309FE8DB74C85430FCF9441EF1B51A1192703B140CE3703E5848477FB0BBC2E82DC38702D4C6A78A41729B7EC86F9890EAD369DE4F25EAD61DB0B5B0ED764EC84FDAB904FAD9DBEDEBBE89F338DF52F7A6FAC8EA1D76001846802B328E8D1F110219BD6BB51214814026BFD6E32627B696C7990F53591CC811A9A09A1154A50585B882DE0B404D7B5846DBDC8C66E4AA0C7B90B08CC96A5CF2352A6592BCA536359C863D639CDA60FD23326619A9014FD878EBFF3E73E4424B045CBD506ED744D3243725EF9491D6165D332FB12985022A71C7DD4E3F942AF5CDF2396F6C346088EAE89535E1B21DA8F7B2E1E12DC8A37738310248808B9973041E", + "F5B9B9204186466AF61609CC856B6B2B33D6F526EF1E4BE4DCAA1E1055F033072B3801B642700249C024414B3217D160513E5A804B3AE8425852CF5FB9F51D2601F9BFF9F5E4512A45ED8F615A6671315590DEC31720387533A4E090646F17244EB571DBD6E6A10890FF19809D935A5E88228D424FF2E54B1A37576C059A756290BAAEA5E36AC977526339CDFF915A763B2CD0657F3A3D385A5D92466A44980AD8A1B4E1593DC177E2447ADB53B1EAE15A91BD6703E46F01AE91D6C316C1DB983688576B3B2BAB280FF196D5BF545755097249C517E1271202E3856475A3C95324F827961DD7A827709DA2924B21949B6BF032675D80FD120180F6850BFC385E72399F840B80E5525EE70B89E1C524D580390D487D0CD31AF3CA5691067BDBE8E2E91E0099F59700CDFCFDF8B3ACBEBCB61DB23A28E80C3E463D9E53328C37EF8FF0D4FCBD287932C8197DF57EEBC9DDB29E2046C7FC14970F9F37CED37D8BB0958155192C8595E2A9369944DAF58FCC1D9E1987DC4FA77ACB256A65DA78B733178FED14DA3E3E41DB808849132EB05E48BCA03ED499A314C857FF7C7C1FC8BD2478635396BD7F252ED984C102E23F55450F57ADC7EAC50A57B78BF4F988565A172E878638ADB1D992703D0BB742605EB76E3C85319F567D71B9F2E40251EEB936B323DE98496229B1F8A996AE4F6C0C2FBB3B2244F3BC57EB3FD067F535102", + "A7F21431EF8C75A1E9723B1FBB602EB4B92BE5FC8DE70183659A45A31EDDC46643ED1287A69DC876634231D3AF95F2D02FC9C0C7BBBB12319CBDBFDF6CBF94E47A05204AB14A490C6FBABCF329B5B0EFD8C2FA28845764510624398BFDED1B250003FBA61A67D2127550FF07A6FAE2CB5B8FEB23D289FA235BB4959F8845B25405A75A30E7D05D7BDEB721BFD4A998DAA6F1A54712901551E30D618DC80FADF7CB7863EADB7EEE708F1050AB0510A956C3C7706756B6CEAF611F02656C3CACBFD9E4507AC2B4B78D0EB0BF757496C84C7260CA972F0F45A393A89AC2BD70F15E629473D61FFA29BA18A468D8D4B1F72DDFF99608AC9E6A6D6A9231F24388991E80FBE6A9269AD6D31182E79235A0E33CFEE9E3526FC068A9253789407AF8CAECE14BC337FCE02333B63224A61E913367CB36641A74E2DB2892C4E939A50127DBEFED7456F7E61454FA5016A6B75E6133B0417C2860B2F640ED8EE62D5100EA172BBF8FB02E2022D29DF33C25654C96F8FB2305B72A92105E027444EE0F27769946A67E58D9A26AD01483FCA4BCDA4C00A8119E355CE733474349DC8311AE9853A064931FD68D598B02E0724A13FF63D88416FD5D03A962B5D8F79586E696C484D7F287773851831EBF33B0158F51C89C493C116157D20DE66F3990061135F5CBC46862BCFDA5EB0322793BD6AE188698A2E1DEDDF71702B6CB01EC2BDF85680", + "FB2C4002173D1E1581890C14672C1F232E8A1332655108F24F78E53638EFECA3DAD18D19FBB1E91C6AA4761017DB37FA76F70BBBC4C8E8015384DC9E9EF14C6AE60DE55974D448DB8C36B030DD55DF5EC6F6C56DA8CB9BBAACF6784628B669913A7B291632730C11710D7E181401FB535FE8A9A0B81578CE54123A6C3897496375CD7C60BB4E05AD16BDD4CB8F652448E3020EDF4D51FF5EBB9FA93A740AE779419002994348358CD7827A63BABCD7C4501CF8ACD77A2200059DFF5B180AFFBF3CE52133C7451CD108AF9CC8FA32428AE9ABC55D89E1931E6607160BF96015901DC097B56299F9F358DBBE921FBD7D0DB43C9C5BF97468813C0AC632D35C858D8384C32EBDEE933C9037EC36D2322F54FB0D3CF305801DE42B4EBCB5F83F3D3FCC1AF56910B7A547F50F851079B6D0D262676145C27DB362AF383037FFAD5E3B26BD2095143B361F82425734842E2153C5F428D89DBA45EF59BD9DF1FE1BA941F172A685F08C18B76B6A8FDC86EED2867A57AF48E00467993864EF70D80CE5550C5EDF085E94435ECA89F6513D23A56235739534C777C17BC6DC7BF6E04BDAA9B0C94C4D7AF1368C6B4B9D3C97D25A26B05703EBC4D1F8869C5DDA359D189F4A3E548D53731FB429F3536880CAD9FE13F70DB0A080B949C3636611CBFF0F644ABA8B56D2C6E988B3392A7452A8C8E52F2288560331A78F4CF021D2A41B2ECB6", + "CB7A566070A06E759017D62CF78A429913370E6498BCDC038C1D3079A0A3E6FD4FDCC851DCBEA9EB3A7D266479F75C40452A282CB406E9A2581372BE2FFBAF6E7F3359EAA594631CEF876FD62DEFBB3B816EC98A1F72B55F6023B572A51F320CD7ABF489AA905CE2274729C0EE0F677A04D7449A489BD02704CA65BCD8B753B689CB90C87C73FB4A45219DCD817E9AB584EFF049EA711CD3E24CE41423FEE6F258A65CA8EC3A00D45371EC5B846CF1549CB5CA4FF14B696140D3483DDC7801BFE6CFEFB9189B5C7AC3DB9C0709F630D80F361442BBD22636B00530EEF21D96D4A12CCF85E0124939B025CF35A0A5F1B4C2FA5B5DFCB3772CBFEC1F0C1C824B5CC22BA8FB2DC92164FCBC60333EBF920A14599F1E8EFD4E8CB0257134947331D820595BF5630EDF00814C32994039B47E8784C29D0D1C5B5D219A9F55FC14CC18DACBE6A79698A8073276A424BA9A6606DFF369CCF5F9F4AEC9605F6E44807507B36A4918FDAC448E3134106683EBA80A2D97E12EC2BC1EBBCBADBDC631CE7D61BB9DDF143C3EEA4E36EAAEAFC001849812A7CDE3EBC194A51EA2A9A2AA15A0A4F29C2FFD8B2CB4ADEE99B59553BB2398273C04329A5C884989D417C131D68E9B505594C9B9CF1C13AABF05093A9E4224D71B54C6F61F1255E25FF7527E47768FBD51523F42915133E02CD7E404147E7AAE95BE651BFBBD65E29130D0CA31C2A", + "D90A7D104DEF06F51CA5FE107C115C130B8823C423423608DEE00E0C2E6C202B60C5D20BCC9CDC18767D89E5E7857BABC9531C21B08436AC14C5B34EB986E5521369BC3D9B1FCD07C99240FD0DA306C69303B310B8F78D2BF97D6E9E88843234D73214431F6BAEFE5109AFDA22C4C348A469370BBF9B0A81CF27ED919A0A48DA3E9061113C56659F7561175A608B7FB37A76EB9E5ABA5F4A6B485EA5D097482A28F4EF7DE785D31DDEBFE41DFF7C51CA2B64A0D2A7A70269FDE399FF7628202289EA97141F995FF51DB5AF7C9C5CA76F0AFB4981D021FEA9EE6A49ECCCD18AF290B6C231265247DECE33B3E165FDE4FCF82EA84A4A8AE3FA90972D96DB68550AEF21FCE82E0FC75FCDE33C2B6F659A873AF09067D94B068DCEEDCA4D392BE5077587785CB6A1F1947841F483BE5080E85B49F1073D4778A39239266DB2A24B57B5F51B1F021D05C634D66DAD081D1668EF0520424581E5E0B62ED085D005F169950F971E1493A49A60A595342AACBA236EB16D5EF94E749889E50656D98F94EEF205445AC027387AE1363696185E24749EB67518B89057899548BABE29F3487D273C54EE2BE6254C7F3ED3D3B22FA3FC94791A7BC7C499A391179368D9B1F0DDC325F55022F5AB7B91142E2880BAC761D154C11F2C58F4A42E8B3DBCFD44777F08A74676DFB7039F24C9A4C4620726FE12849C9D3C15293A3DF7F4870DCCF56", + "9D238D97CE04FEC0D292181D145EA0EFA727DBB7BADDCC60357762D262DD7D7A3BB0189E05BE490018ABBB61B154F94A4FA81985E774019CCCE4B8ECE9858C0C2BDFFD7923B3354A2144ACCC5C9DA34E50299EBF68E9BA0A269760386E5531F8964F8024ACC99E7AC3F40BFA9D94ECA1B14A1B173A06867100C57883FE7333C079C5871A8A7603395A87387EFB92A77C5812EF548CBC3B9178E874E45DFA8796BA6FECB5D81687EDC0AD5F804FF36A9CDDC58A5F991A2A0BA999F86E663715CC79A439DEC44C394ECF1F14801D8F9F292A648D29D2E910032F224ECE51D0708E4ED6D3E65FC788A2C1D286750F4B6D768CBF1B6EDE8524C2A7457A82404A491DB5EC868E6B95B02167A0C4E785290156943FA091F28234C4CAAB586F8095895FD21582E0356BC15EC7CEE893E70902CE4D01217474E0226FFF30CB78597726C74B95732E44D03A626F1D1DBA7785F55859B71C2DAFCF71D99EB99FFEF4877518C579D2623FF6EB326B8D6C7674826984CCAF98CE41724183952EAD69F05F44750F3B857EA01475555FD25A828BE1DBEF5E8B1C1237779E9E69D35E7BA9ADA124CBE710490280B64B2DC5EA2C41D6644012A18B369E3CA2FD93A254C493506C54FA6CB4DFE24E0B5035230F2BDE6FF21101164F322B4B066ECBCA3BB4F3C476B41BD02D8948E555AF74EA13228F07A1BEDBF95FA7E16F2BDC5D178E74FE5A1A0", + "8DD8032BC8D741905EDAE449212146878D8FA15AB037E41C36D21B0064D65BEBB74A18F4370C80DB44EE93C2AB06DCC6C6FE7DEA83F270C9FB52CE00BDBF546348F0E6285A35A32A47512823DD6E22FB7949071D4B58B46241544AB97B0F6023C70AFCFF0C7541B4B9E1FC6B3C3C55500251665D964871B9D1247B3A9728AE02FF47368053B1DE928B6A8D01ED3BCB18A3180EFC9700871F480959137CA1480C3640547497ED7CDB4912ADE1385F9F35B6D27BE64E362BD71E0981BE952B00AA20DC57465DA89B87BBE07F27454FB24B3B86766F95A5A5B4EAECA2620C3BF87C0654E6561398F27F96178EB1062E42F6E6AE0A669FC6C7170F217C850E822B4E70C9033A375BBCF6D62D11B3DAF7DA976D4A9D955B924E7F0A19CE77A53EDD424ADFDEE8558F06887E82A936193AD5E508938DD3FBFE02DFEBD98C2272DEAAD8AD3B0FC86C3637A6CE694DD95E4FD55F433E151D35DD4C930177CA66322001110B9BD0B89A096C8C3A3431C100E39E3D2E65504A770F4EB2F19E9D8FCCAF15B8E58DFB52A0B88406A48A036193F3EA9F8ED2322FC69CEAEB9E2DD6AC627DCF4CB109EA05AB5DCEA5F92902F3E7BD457C240C958FCA7B17F2EDA1248961C9C827E99BE0A3D60B3E27E42B1FF696DD58E48C7B832D8FE95529B9C8F075E67294C1B1060EC6736DB73FEF7407B320D850B049D80F9F4D536361038C4BAEAD92F24", + "C10051089B11B578F56E6C24FAB973C5D1B4A2F937E4A402FFCC45267F4A3F4CF4EED3DFF530838A570000F7E523D1B97FF798A3C6E12F9704126A9B6FDF606031E4D8E1AE39A470FE929124FC95961B85A5A6E10A79CBA60F54F37D4DCCB13FA3B0A3A1729184C59036428532E3DDB3F7B8D373DC08842EBC2ABBFDEB5B73B2F9B7E83C81D5D0EB3037A32AC0E5B6CDCC7CD84B9289BE16106D1D019D47209AFD8DA78EFA0F9108377C187B170CD53F366B17899EB41903FA1627AA245C07EEA5D6DA78039B3C4C1D70DD28870A40EE3A048D8209C4088A0847D6859513E01E0F4172C383D64F0B307D721C01495070336A753A75E1CA433FA973BB131E558FACC298C0A6E934E9F717E19EBCEA11EDF3736D4EAF593A8E5AC8EDFFE4D2B17B613E024B41AAD19BC0A27A1E9BE9D25344D4350596B9B0A48AA014191511B26E61A9753D8A38C4E3BECAC93E67CAB5696888C06B9099E9AE856486436FDD1AF1C193057AD1DFBBB14AF772F7D9B00F37A6DC9E805A8DFD9D53A161885E5C2C2A6DED0C54D00A8E0704877DA2F1EB6F6D8EB93B5604A4E2545D454C3D4F0D606AC192E170D44E85E2ADC91E54F56906909024DEDB6F9050BF3D3928D9AE23D9C42576AE4DAD1336F47519EDE436C3B1829CD2C5A0AF63476C7928B32F5E51826D844A1DF765C5578F9C2E5F79024BFDA96FB3199A3C7B47D3755FAF376761B4E", + "9C6674915677A62A7AFD4FCB27B45F8E6DDDD08980B7DBE1131E6E2425C5ADBEE8474E93A8A2D4E495B195A6B83F2CF6472A36E690928362B9A1FA994A9FEB7BCBA7FDCB771F59FB434ED289CCEABDAFAE29113389EB98D6F17E5508D5976E11BC8A1E93AF9F7B1C81686265930B4D334568E3F29E1C2F58A62572A610016C1C1C1C9E1D0EB3FEB2B3A210C59EB3980C44BC656FA7C5E05A4472D4255B40B8A1604FE39D8B5026A976310648D5C84CEBC87A8BF6545DC843A3A0B64DC4CCAF2D2203122DDD75BA42E096844899A35A899FDFD72C26E3392EA03351DC78BB9F62F51D913F8008DB00969C64003773FB2014FAF97E794A45792495BD52D7BE7ACA47FF2BF570CF88303377092B5B6BFF3B01D38A53E8A68B0D81FC2D1D375EB27C7AEEDD70679E8DDBA6DE656442ED951478FB96A979B4A9091F344EF39AF23DAA886C6FBAA8611C61686332C630690109E2869D18EE7A2C21B22921B9E3DE40BF063E370FF64E7AFE160B7EBFC4AF6AEDA043042552F5F36C2CABD339FE1442242EAD931D1B83968D1A31A7E32A0838401DBB9C1034D56ADCAF5942462EF63440FD70F91520137A50372D0D125A6285F7D715FD9225D03A109E1FC5EB547303CD7708F88FEED2814607171930436B249924714E8D8E024C24B3C0C9E40127DECE1AD966C3F9DF01793864615F291B73F73D27B624ACBEAD3D371B8D4FDA823C0", + "A1B9E8AB6C44A3610768CC17E3B899CEDDB44B746319EC50BA7E006EA0F3C09E9D67EF8A20154B2F93EC265B800503BC72831800CE0C9FB6CCADC8327A840F69DDF29BE212BEFE4AB1810026FF786D9D3A88B29745EB61131FB47B385F83CA211B4A2BC0449F7ECE43B2DDAC94C10955FF2E078AF573FFA7349907571AF501FA6A2FCF24E4B5676F8213475351C0398748FBD60A5EE8A1128C0998E57D076A201453EA7C70B1F171E7D084F444311C9829CAD03E0C2330D7E8D39DB6B7901C30787FF123CFBAD4E974A5F6412FB1BC927FD65CAD1F3AA4ED52E2D84AF6257EF311222467DE179E89438524116D8E0A4A94C19A4D66D0AE0FC535D69C4953C2E43136AC07D6A5774D59DEF1471B4097146C2124DF83D36678FBD7BEA6E258D826645DD88AC9A7EA5E05FB49F2CB29EA9081323FFB2A00F3915D1F36675BA1C9AAA3B166D9FB2529150D3573E502668E33DFA5BE95AA6C2F1F106D69218839BA590406B4FE4A03C4B16E29E6BC31335234BCA55D34955880B702F08203198EB7BAE381B231FAFE513F24C8BA9E58798F35465C2679DD5BA8B16EEDAFB04E5A807B9BE6EE4B3AD77609D2B9E0985BB23397BBDE08F4D0B21494A3129857E37D13862C1FF77A57AC663C206A92F8358E6C05FDE1A9D68131BC04B76F6865E8DF5C48F9424CD9AB6FEFB3B49BA8D32C923CDB8602C5367AA9ECAE48AEE6A276CF25C", + "ED1196222AA470CB4FC8A0B7D2C785EB45D232E06453B77DB76F60E5F7BAA0FAE80467EC8C656FC27FFDE8BFAADD2368B41AFF69460495923942ACF85C09EF01BCED0076960E5CDB1D36061933C1B6037548D27932CDF969FD5A910D5564F3A6BAF896A2A69F40EDA76E813AA261530F686042235A39A76081F58D952662894E6E648BA72098D840235EC4A2B963F8E74B52F2D0088DACA7EDF48115618DBBABC698C04AAAC0632475BEE65BB26A4EAA08F0209B75EB259B826724F580209F8B991808411F823819CC5F42A9FC1F0CEDBDC54C046EB1D1658FFF7252908B09F8C1D82E5F6D605F0B17B25506FAF91D4B3D4EBCB7A705E5BCB2A6FB409ABE4B1B0B47630F1AB0B40A3455181678573F82A7C139F072659D80671961D614D9F7DA72914BD5D6F417EBC152595972FDFAE876176923CF1F2F745A6FC27E134CEBC2D9AD5CC733F619C1B296026B7C4717D2086D91765D83AB76605050B810C542819BBB7CD87EA2305AB4A567B2C500D9913B7C6046F748DEECFE3C3AF829EF97E03799EA50F7C9EB38990F0D466498C091C3ABAA18453B173F0AA3A486DFAFEEE68E7998EA30E5C1349F2A54AE753963CEF58332A114F964B83B4E446A44147B11FFC60DA25B5FA705F34725B1388B17E99018236BD646DC714F8B7CD3BF2648063B2D3FB713AB94D82ED81D571D5BB4D3E5F2F067E2F2C90E8B6857E6A651B8E", + "EBE597534C0A6FEE9CE6AD10A80D2DFD160D7DE7A20154F62AFD7C3187D51D09DA39A958432CDCCBD83FCE19131E65A30DE99DB796D93D0944223D960BA233798323D368DDBD407D51B80350976951AE0E50CF409279301939624C741D20D5CDBF4BC3ABC8723E267BE75707024F6398CC6D32A7BCD0989555E0EE49C1A2354D1E961CA9910A5169ADFA71D56745181E0CF13469D8F3C6020637B8118ED8421A680FD4D515DF6B31C39ACFA36B601027AFBC861493D34ACEACFB501DF9A311B7EB9D38D7107E6B5ECBE74FD35CC8BC8319DF9F1948653C94C868DC24AB8D7E650D8F70A3D1D878558AC9BFA50D425604037F3DA323192654F1296C8320AF934AF60DACAD7F9630EA4ED0A635678213F6D09D73A2544C779596990DA42079C23581E22F541E6A3B6D3FA383597A8BDD7CA42930816D74FE8B12F92CBB9303CA5FA12BF5FE954FA7B53E0D88B79BE263B4B55B42A7672F5C4F7E6E2DB4C02AFD6034B7371E01215CED3F73AB8E3419D7447781AE5DEB4F4547C5549E9B0AD59940C162790650344E5ACAB33A187A58E29C9032963F088C044ABE73A855FF1FC93AB8DC258E419777311B7997EA95D32CF1F0140CAB9E6707E73E4FE575E0752816122C39B8D12F34ED6771EAEE192D830797DBE97A0BFD00E39CA382D44F080BB4F8FF6FAAFF2A82744C6E14D3036E00EC2ED5C9D184ECCA300030D7BD77B27DA", + "A56990B45E9AA5F9523D563D53E854A47629A4183E85CA1995BB374EE5601BDBCE5C7407999D28FF0F1B3EC7A463D3C941C57B7EB71E6262DA3A7136627814EA6D28C8D16E91680B0D961AAFACE2CA4099F986CD45A2AB387E39497B13678447480514B4008F0FA3B95AD7D2B4751C680F0C7D3651F9621E1355CEC76F10468ED33DE4C7D7D68B786B7F0006C604BCF893739FFE6AE56AD5AAD07D5BE76DE1CD581B10EDFEC9DF65AF925C4C1289837BE1854A62FCCEECCC4E2AB47B4864C467F5E4C276047501EABE444E051DEA933863E0FCB2356CC0C3817BA59B2E0AD78BBFEF4C3E4C35343331CD81C7F4C428B0418DFA4D6FF655BC50AF49C9A5E8A67BC265A3F30800B93E42C0E66F117E6C59C85BA5E273234EC7212C7B7AC3D87FC0E0EC5FBAE6654461F24BBDF9A063FD0E3F98741C5622ACC8BC008EB0E3F3D57680F12E52FB94CD957EFDD49BF512D9131757161A73DD9650E3561FB31509A908D3EA8DBD1C3AA95AC32E6960E0D17A218A25784332A88E85303DEBE117BEFEDF46882995AEBD704AEAE032668AEC6B8E5BD28D3F110C9F8C1DCA8FACFDC1188A073037796555DC4FAA26ACB9F51B545D32C224424BAC3DAB20D3C08D784E9FEDB47547C25671C269A62163742B55AB4CF9406D2C5047F92C76356F0B90221E019B31890C0B8FCFD04E6B5D06114B967D1358797238D5B14D824C8F0BD7B8BD0", + "D85AAA53F2DE2946EB0CA09DEBB6CB61D91D27C8907B90C89E20C01F681D33BF0DC70B6C79F19E4DB64793505A0E055C33D1E07B7F5AE09F7EFF0C8CEBE80C84373804A48A945CA406D3A1B17CA787DA265C1D8FC735CB098C1AB37A0452F1A287B8E19E3A57E59EF8F2E6CCE2F0AA7772955977982B1F6880AE8717520753636591BA36E351310E98ABB77E26E2CA5BF267935FC38DE173CA20C3A964B56924A5E82A9E36D005EDE6680D543C021C7A9F53DB69BFA3201880B7797E90D31011AFA17BAE836505F5B337C23A07D6AF167258C314C3001291DD9FC565F6B7FB74D99C1B42B496422B3D3E1A564769C2306E40264641EC14724301795B4D54F5FF8D6C4AB3645B56C1D0FFE9B977FC5017E2A53392E7458BAA308C343AAFF5B46B808BDA1FE5C284299A9EEEFC755132F9D3B475E2FCD6BA84917C601B5E8340B5A68148A33563E40AC5A1E49BD8D5FA77BEB6B99E6F4F68A10ECA112475531E7C1942AB9504B8F76EA7BCCAE4A19EF859FD6B6753F07BDD9A19421A2A0B8F27643B2311FAD7978F4366C41BD9F609486FC6EC7CE833A00D7A48AD816412BD201F40C93D136ABB8E329DDB816D1F59A1F3124D6314C64C9B640E4D5BB201CDB4490A65C73228E78055AD6632D81709AA443EBF29A4607A504DD5CBC0D271FE595677B8E6A5E29E23D171D50B878D0D3F9416657E3997D077677B87399A6D1936E", + "A0E629454DE594F7693888C9ADB907F83EC6818D6FC0019B70077BF1B0E3C2CB16A263BE145EA8129FED6BD98F3D9120BAD28379EC8E36DEC69C59B37BD6C2B65D172C70C69C23E29A6143121AEB9E6A9AB46C3DBC3979BC876F4357F6BAA5A0CB33C3AFF1654FE547D5D760E8CE095A9B324E15CEC1596BB7E0D56433D8908EA69925A5CCDCF01702811AD1103F237D36C5F12A3CD938A61EF76A3387340499E4EF1855F892F57AC39AB419F1A397CD43FE7F4C5E609ADF3A2A8E401FFAC870985826CA0DE211996A3549A203B798A5162E98FFC8B5CC2CFA68D618AE80D399D8DFE0FE4AA81ED9B586EA89F646D5C0AA8B107506C7F86879419D0F717E8F70C5A9DC2C3F122CB52F3B691087EF5971C27086512F1890494ABA38B1619969F8846B8876B95C56142F5B171502FA44ACD0299E82FC94EBCD4CDDBE1F5DF978871128F79C1758BB512D5C3BDE59A89786CF4E4716F0515F45A1CA31B06B23E4883F99EE0488848EB0A60FA14AABBD41EC5421D0C162590FEFFEBB4DD0300221471DE8DC0C87DB3F1D54DB11744F8A7115DCA0595F6CD99B74A6FB10C0D14E430F8B40E3E7105C89B2C8F12B37A8879AD9BEAD49AFA1BD56569713CCDA3FB634C3011D51A8DCF84437251A7B19EB61FCE5DF6E2278784722BABE384BA5424646FA23F6D10CE23DC5E0D8D512E7C5C094B1627D6285B57EDF38A7DB1BD57B72044", + "CD7AAC98501F29507EA4E0183E8A40D2E5117E47BB5D18D01A3732DE4C821DFE86521CBEA7DB29BE1148BD544ECC681689BCD1B41EAF755310B7659342F8EE11CB41550CC30E566E192796B66C1A83C0B28BACCFA6C393043A0A2CB89712BC1CCB174DE58E66896AF39C1CEED1E05B0435F8CF6FD920D100F51584FE24879987399481DBF27DDB6286B6353919E552E669290CE02AB4CD5113D7F484229F379C7332767EC69E4336439B05DE1C1E3563DD303A4F580BFF20A40E49CB0822F715ED0221EBCDB5DBAD751124B1715E82F37488265135B6C8BBCF4F801ECC4D3525FF189493AD4EFF0C042B070C4CA8FB1FDF43D79F06A6E4E3D35D7B07D4B728D5DC54EEDACBBBA1EDDCDC07ADF7DFCFEF835E44DF1FF66DAF2A7BAEBE218AC3B15E183044D6A8A89B3C101B40BED97ED5DF93BBC1B84931D56B8C822A6D058AC74CFA4C85D8B456698E82D5B7574C17B041E5F4BEED09F75012355CBC322B822C63F10C18A8F279E9A0E18E1FEF183D23E13894E31F6D046956FE8A647558228F6D4D6910151EC03937876B6ED7A078D33DAEB3F2239353BB8181E62B286BBC41588DE10F478A5CE5B508F205A41820356767B0A0ED4B8DB9EFE348362E9A90D6C30218B295B338B51C09239D02FC8A1E7DAAAB60AC37F5E67CFC88EEF69567B5C81A03B449F4ED38B9D295A36AA3503173F6F6F66D93CE72D753076040FACDE", + "ADDCEDB50E907D20E826E6E8A0D30C20C74B2DF204EA784BAE9F618CAE33A3C937729DF9CB10BA2A4C33E0182A37200C0CC509729D828B8A2A20F283AC4F9306596684EA3FB5492A4C9F2DB459E7531C9F9C0950E7D9E93B3EE5912AE7E39AC8F4EC14B18F24E325003F477E347C5AC1B67CDB11AF3BBBBCD0AC3703024B5767AA67A208254F798684BFD1D3EACD757EEC77254950A146620400DB95E694574F739A991EBA771EBBDFF1056BB39A77DBE0636A032E17141332F951C57C6C90F348F165E3ABDD60D429D5D6BEC7E3E3463806F819EB2D212B3528A5EDE51F235AD100A35E890955F8A1DC51FDCB53EABCA2540997DD054C1F5B29462995B876B44D085904E55E1B838BEF600A992EB49CE078DF75AF3D0F137685AC0D07F0BE1EB87B63A41E74DDE869C8A683BDE60AF5D77FF18F7137495BCEFD0ED28F62F9C3E25D332B5F861D999FCDC0B4851A984A4DBB53401FD40351ADA4335C702BCC8D900C737507B990BDDBE91D201E3A0946DC968D43FD10D04B0B76667FF5B4291C2124B0124C6B710A6D1BCFAEB016B9DEEB0F7A4FE044CA4EA0CCD84B7682617C3A545071EC295B0663B3F577D562DE1D9DD80DE6A1EFD6D5991EB5246F1597B86D0E9A90CF6DB0EB2B8E7BAE9431E567F01AA98502C773742246467ABF911A91A51F6C1B9E0C3233DC1A37D17DB91A5F0F661B0EB5886964456C7818601BD0C"}; const std::string Galileo_E1_C_SECONDARY_CODE = "0011100000001010110110010"; diff --git a/src/core/system_parameters/Galileo_E5a.h b/src/core/system_parameters/Galileo_E5a.h index 70ec19a1e..cf7e56ce1 100644 --- a/src/core/system_parameters/Galileo_E5a.h +++ b/src/core/system_parameters/Galileo_E5a.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,352 +31,360 @@ #ifndef GNSS_SDR_GALILEO_E5A_H_ #define GNSS_SDR_GALILEO_E5A_H_ -#include -#include -#include // std::pair #include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" +#include +#include +#include // std::pair +#include -// Physical constants already defined in E1 // Carrier and code frequencies -const double Galileo_E5a_FREQ_HZ = 1.176450e9; //!< Galileo E5a carrier frequency [Hz] +const double Galileo_E5a_FREQ_HZ = FREQ5; //!< Galileo E5a carrier frequency [Hz] const double Galileo_E5a_CODE_CHIP_RATE_HZ = 1.023e7; //!< Galileo E5a code rate [chips/s] -const double Galileo_E5a_I_TIERED_CODE_PERIOD = 0.020; //!< Galileo E5a-I tiered code period [s] -const double Galileo_E5a_Q_TIERED_CODE_PERIOD = 0.100; //!< Galileo E5a-Q tiered code period [s] -const int Galileo_E5a_CODE_LENGTH_CHIPS = 10230; //!< Galileo E5a primary code length [chips] -const int Galileo_E5a_I_SECONDARY_CODE_LENGTH = 20; //!< Galileo E5a-I secondary code length [chips] -const int Galileo_E5a_Q_SECONDARY_CODE_LENGTH = 100; //!< Galileo E5a-Q secondary code length [chips] -const double GALILEO_E5a_CODE_PERIOD = 0.001; -const int Galileo_E5a_SYMBOL_RATE_BPS = 50; //!< Galileo E5a symbol rate [bits/second] -const int Galileo_E5a_NUMBER_OF_CODES = 50; +const double Galileo_E5a_I_TIERED_CODE_PERIOD = 0.020; //!< Galileo E5a-I tiered code period [s] +const double Galileo_E5a_Q_TIERED_CODE_PERIOD = 0.100; //!< Galileo E5a-Q tiered code period [s] +const int32_t Galileo_E5a_CODE_LENGTH_CHIPS = 10230; //!< Galileo E5a primary code length [chips] +const int32_t Galileo_E5a_I_SECONDARY_CODE_LENGTH = 20; //!< Galileo E5a-I secondary code length [chips] +const int32_t Galileo_E5a_Q_SECONDARY_CODE_LENGTH = 100; //!< Galileo E5a-Q secondary code length [chips] +const double GALILEO_E5a_CODE_PERIOD = 0.001; //!< Galileo E1 primary code period [s] +const int32_t GALILEO_E5a_CODE_PERIOD_MS = 1; //!< Galileo E1 primary code period [ms] +const int32_t Galileo_E5a_SYMBOL_RATE_BPS = 50; //!< Galileo E5a symbol rate [bits/second] +const int32_t Galileo_E5a_NUMBER_OF_CODES = 50; -// OBSERVABLE HISTORY DEEP FOR INTERPOLATION -const int GALILEO_E5A_HISTORY_DEEP = 20; +// OBSERVABLE HISTORY DEEP FOR INTERPOLATION AND CRC ERROR LIMIT +const int32_t GALILEO_E5A_HISTORY_DEEP = 20; +const int32_t GALILEO_E5A_CRC_ERROR_LIMIT = 6; +//optimum parameters +const uint32_t Galileo_E5a_OPT_ACQ_FS_HZ = 10000000; //!< Sampling frequncy that maximizes the acquisition SNR while using a non-multiple of chip rate // F/NAV message structure -const int GALILEO_FNAV_PREAMBLE_LENGTH_BITS = 12; +const int32_t GALILEO_FNAV_PREAMBLE_LENGTH_BITS = 12; const std::string GALILEO_FNAV_PREAMBLE = {"101101110000"}; -const int GALILEO_FNAV_CODES_PER_SYMBOL = 20; // (chip rate/ code length)/telemetry bps -const int GALILEO_FNAV_CODES_PER_PREAMBLE = 240; // bits preamble * codes/symbol -const int GALILEO_FNAV_SYMBOLS_PER_PAGE = 500; //Total symbols per page including preamble. See Galileo ICD 4.2.2 -const int GALILEO_FNAV_SECONDS_PER_PAGE = 10; -const int GALILEO_FNAV_CODES_PER_PAGE = 10000; // symbols * codes/symbol, where code stands for primary code +const int32_t GALILEO_FNAV_CODES_PER_SYMBOL = 20; // (chip rate/ code length)/telemetry bps +const int32_t GALILEO_FNAV_CODES_PER_PREAMBLE = 240; // bits preamble * codes/symbol +const int32_t GALILEO_FNAV_SYMBOLS_PER_PAGE = 500; // Total symbols per page including preamble. See Galileo ICD 4.2.2 +const int32_t GALILEO_FNAV_SECONDS_PER_PAGE = 10; +const int32_t GALILEO_FNAV_CODES_PER_PAGE = 10000; // symbols * codes/symbol, where code stands for primary code -const int GALILEO_FNAV_INTERLEAVER_ROWS = 8; -const int GALILEO_FNAV_INTERLEAVER_COLS = 61; -const int GALILEO_FNAV_PAGE_TYPE_BITS = 6; +const int32_t GALILEO_FNAV_INTERLEAVER_ROWS = 8; +const int32_t GALILEO_FNAV_INTERLEAVER_COLS = 61; +const int32_t GALILEO_FNAV_PAGE_TYPE_BITS = 6; -const int GALILEO_FNAV_DATA_FRAME_BITS = 214; -const int GALILEO_FNAV_DATA_FRAME_BYTES = 27; +const int32_t GALILEO_FNAV_DATA_FRAME_BITS = 214; +const int32_t GALILEO_FNAV_DATA_FRAME_BYTES = 27; -const std::vector> FNAV_PAGE_TYPE_bit({{1,6}}); +const std::vector> FNAV_PAGE_TYPE_bit({{1, 6}}); /* WORD 1 iono corrections. FNAV (Galileo E5a message)*/ -const std::vector> FNAV_SV_ID_PRN_1_bit({{6,6}}); -const std::vector> FNAV_IODnav_1_bit({{12,10}}); -const std::vector> FNAV_t0c_1_bit({{22,14}}); -const double FNAV_t0c_1_LSB = 60; -const std::vector> FNAV_af0_1_bit({{36,31}}); +const std::vector> FNAV_SV_ID_PRN_1_bit({{7, 6}}); +const std::vector> FNAV_IODnav_1_bit({{13, 10}}); +const std::vector> FNAV_t0c_1_bit({{23, 14}}); +const int32_t FNAV_t0c_1_LSB = 60; +const std::vector> FNAV_af0_1_bit({{37, 31}}); const double FNAV_af0_1_LSB = TWO_N34; -const std::vector> FNAV_af1_1_bit({{67,21}}); +const std::vector> FNAV_af1_1_bit({{68, 21}}); const double FNAV_af1_1_LSB = TWO_N46; -const std::vector> FNAV_af2_1_bit({{88,6}}); +const std::vector> FNAV_af2_1_bit({{89, 6}}); const double FNAV_af2_1_LSB = TWO_N59; -const std::vector> FNAV_SISA_1_bit({{94,8}}); -const std::vector> FNAV_ai0_1_bit({{102,11}}); +const std::vector> FNAV_SISA_1_bit({{95, 8}}); +const std::vector> FNAV_ai0_1_bit({{103, 11}}); const double FNAV_ai0_1_LSB = TWO_N2; -const std::vector> FNAV_ai1_1_bit({{113,11}}); +const std::vector> FNAV_ai1_1_bit({{114, 11}}); const double FNAV_ai1_1_LSB = TWO_N8; -const std::vector> FNAV_ai2_1_bit({{124,14}}); +const std::vector> FNAV_ai2_1_bit({{125, 14}}); const double FNAV_ai2_1_LSB = TWO_N15; -const std::vector> FNAV_region1_1_bit({{138,1}}); -const std::vector> FNAV_region2_1_bit({{139,1}}); -const std::vector> FNAV_region3_1_bit({{140,1}}); -const std::vector> FNAV_region4_1_bit({{141,1}}); -const std::vector> FNAV_region5_1_bit({{142,1}}); -const std::vector> FNAV_BGD_1_bit({{143,10}}); +const std::vector> FNAV_region1_1_bit({{139, 1}}); +const std::vector> FNAV_region2_1_bit({{140, 1}}); +const std::vector> FNAV_region3_1_bit({{141, 1}}); +const std::vector> FNAV_region4_1_bit({{142, 1}}); +const std::vector> FNAV_region5_1_bit({{143, 1}}); +const std::vector> FNAV_BGD_1_bit({{144, 10}}); const double FNAV_BGD_1_LSB = TWO_N32; -const std::vector> FNAV_E5ahs_1_bit({{153,2}}); -const std::vector> FNAV_WN_1_bit({{155,12}}); -const std::vector> FNAV_TOW_1_bit({{167,20}}); -const std::vector> FNAV_E5advs_1_bit({{187,1}}); +const std::vector> FNAV_E5ahs_1_bit({{154, 2}}); +const std::vector> FNAV_WN_1_bit({{156, 12}}); +const std::vector> FNAV_TOW_1_bit({{168, 20}}); +const std::vector> FNAV_E5advs_1_bit({{188, 1}}); // WORD 2 Ephemeris (1/3) -const std::vector> FNAV_IODnav_2_bit({{6,10}}); -const std::vector> FNAV_M0_2_bit({{16,32}}); +const std::vector> FNAV_IODnav_2_bit({{7, 10}}); +const std::vector> FNAV_M0_2_bit({{17, 32}}); const double FNAV_M0_2_LSB = PI_TWO_N31; -const std::vector> FNAV_omegadot_2_bit({{48,24}}); +const std::vector> FNAV_omegadot_2_bit({{49, 24}}); const double FNAV_omegadot_2_LSB = PI_TWO_N43; -const std::vector> FNAV_e_2_bit({{72,32}}); +const std::vector> FNAV_e_2_bit({{73, 32}}); const double FNAV_e_2_LSB = TWO_N33; -const std::vector> FNAV_a12_2_bit({{104,32}}); +const std::vector> FNAV_a12_2_bit({{105, 32}}); const double FNAV_a12_2_LSB = TWO_N19; -const std::vector> FNAV_omega0_2_bit({{136,32}}); +const std::vector> FNAV_omega0_2_bit({{137, 32}}); const double FNAV_omega0_2_LSB = PI_TWO_N31; -const std::vector> FNAV_idot_2_bit({{168,14}}); +const std::vector> FNAV_idot_2_bit({{169, 14}}); const double FNAV_idot_2_LSB = PI_TWO_N43; -const std::vector> FNAV_WN_2_bit({{182,12}}); -const std::vector> FNAV_TOW_2_bit({{194,20}}); +const std::vector> FNAV_WN_2_bit({{183, 12}}); +const std::vector> FNAV_TOW_2_bit({{195, 20}}); // WORD 3 Ephemeris (2/3) -const std::vector> FNAV_IODnav_3_bit({{6,10}}); -const std::vector> FNAV_i0_3_bit({{16,32}}); +const std::vector> FNAV_IODnav_3_bit({{7, 10}}); +const std::vector> FNAV_i0_3_bit({{17, 32}}); const double FNAV_i0_3_LSB = PI_TWO_N31; -const std::vector> FNAV_w_3_bit({{48,32}}); +const std::vector> FNAV_w_3_bit({{49, 32}}); const double FNAV_w_3_LSB = PI_TWO_N31; -const std::vector> FNAV_deltan_3_bit({{80,16}}); +const std::vector> FNAV_deltan_3_bit({{81, 16}}); const double FNAV_deltan_3_LSB = PI_TWO_N43; -const std::vector> FNAV_Cuc_3_bit({{96,16}}); +const std::vector> FNAV_Cuc_3_bit({{97, 16}}); const double FNAV_Cuc_3_LSB = TWO_N29; -const std::vector> FNAV_Cus_3_bit({{112,16}}); +const std::vector> FNAV_Cus_3_bit({{113, 16}}); const double FNAV_Cus_3_LSB = TWO_N29; -const std::vector> FNAV_Crc_3_bit({{128,16}}); +const std::vector> FNAV_Crc_3_bit({{129, 16}}); const double FNAV_Crc_3_LSB = TWO_N5; -const std::vector> FNAV_Crs_3_bit({{144,16}}); +const std::vector> FNAV_Crs_3_bit({{145, 16}}); const double FNAV_Crs_3_LSB = TWO_N5; -const std::vector> FNAV_t0e_3_bit({{160,14}}); -const double FNAV_t0e_3_LSB = 60; -const std::vector> FNAV_WN_3_bit({{174,12}}); -const std::vector> FNAV_TOW_3_bit({{186,20}}); +const std::vector> FNAV_t0e_3_bit({{161, 14}}); +const int32_t FNAV_t0e_3_LSB = 60; +const std::vector> FNAV_WN_3_bit({{175, 12}}); +const std::vector> FNAV_TOW_3_bit({{187, 20}}); // WORD 4 Ephemeris (3/3) -const std::vector> FNAV_IODnav_4_bit({{6,10}}); -const std::vector> FNAV_Cic_4_bit({{16,16}}); +const std::vector> FNAV_IODnav_4_bit({{7, 10}}); +const std::vector> FNAV_Cic_4_bit({{17, 16}}); const double FNAV_Cic_4_LSB = TWO_N29; -const std::vector> FNAV_Cis_4_bit({{32,16}}); +const std::vector> FNAV_Cis_4_bit({{33, 16}}); const double FNAV_Cis_4_LSB = TWO_N29; -const std::vector> FNAV_A0_4_bit({{48,32}}); +const std::vector> FNAV_A0_4_bit({{49, 32}}); const double FNAV_A0_4_LSB = TWO_N30; -const std::vector> FNAV_A1_4_bit({{80,24}}); +const std::vector> FNAV_A1_4_bit({{81, 24}}); const double FNAV_A1_4_LSB = TWO_N50; -const std::vector> FNAV_deltatls_4_bit({{104,8}}); -const std::vector> FNAV_t0t_4_bit({{112,8}}); -const double FNAV_t0t_4_LSB = 3600; -const std::vector> FNAV_WNot_4_bit({{120,8}}); -const std::vector> FNAV_WNlsf_4_bit({{128,8}}); -const std::vector> FNAV_DN_4_bit({{136,3}}); -const std::vector> FNAV_deltatlsf_4_bit({{139,8}}); -const std::vector> FNAV_t0g_4_bit({{147,8}}); -const double FNAV_t0g_4_LSB = 3600; -const std::vector> FNAV_A0g_4_bit({{155,16}}); +const std::vector> FNAV_deltatls_4_bit({{105, 8}}); +const std::vector> FNAV_t0t_4_bit({{113, 8}}); +const int32_t FNAV_t0t_4_LSB = 3600; +const std::vector> FNAV_WNot_4_bit({{121, 8}}); +const std::vector> FNAV_WNlsf_4_bit({{129, 8}}); +const std::vector> FNAV_DN_4_bit({{137, 3}}); +const std::vector> FNAV_deltatlsf_4_bit({{140, 8}}); +const std::vector> FNAV_t0g_4_bit({{148, 8}}); +const int32_t FNAV_t0g_4_LSB = 3600; +const std::vector> FNAV_A0g_4_bit({{156, 16}}); const double FNAV_A0g_4_LSB = TWO_N35; -const std::vector> FNAV_A1g_4_bit({{171,12}}); +const std::vector> FNAV_A1g_4_bit({{172, 12}}); const double FNAV_A1g_4_LSB = TWO_N51; -const std::vector> FNAV_WN0g_4_bit({{183,6}}); -const std::vector> FNAV_TOW_4_bit({{189,20}}); +const std::vector> FNAV_WN0g_4_bit({{184, 6}}); +const std::vector> FNAV_TOW_4_bit({{190, 20}}); // WORD 5 Almanac SVID1 SVID2(1/2) -const std::vector> FNAV_IODa_5_bit({{6,4}}); -const std::vector> FNAV_WNa_5_bit({{10,2}}); -const std::vector> FNAV_t0a_5_bit({{12,10}}); -const double FNAV_t0a_5_LSB = 600; -const std::vector> FNAV_SVID1_5_bit({{22,6}}); -const std::vector> FNAV_Deltaa12_1_5_bit({{28,13}}); +const std::vector> FNAV_IODa_5_bit({{7, 4}}); +const std::vector> FNAV_WNa_5_bit({{11, 2}}); +const std::vector> FNAV_t0a_5_bit({{13, 10}}); +const int32_t FNAV_t0a_5_LSB = 600; +const std::vector> FNAV_SVID1_5_bit({{23, 6}}); +const std::vector> FNAV_Deltaa12_1_5_bit({{29, 13}}); const double FNAV_Deltaa12_5_LSB = TWO_N9; -const std::vector> FNAV_e_1_5_bit({{41,11}}); +const std::vector> FNAV_e_1_5_bit({{42, 11}}); const double FNAV_e_5_LSB = TWO_N16; -const std::vector> FNAV_w_1_5_bit({{52,16}}); +const std::vector> FNAV_w_1_5_bit({{53, 16}}); const double FNAV_w_5_LSB = TWO_N15; -const std::vector> FNAV_deltai_1_5_bit({{68,11}}); +const std::vector> FNAV_deltai_1_5_bit({{69, 11}}); const double FNAV_deltai_5_LSB = TWO_N14; -const std::vector> FNAV_Omega0_1_5_bit({{79,16}}); +const std::vector> FNAV_Omega0_1_5_bit({{80, 16}}); const double FNAV_Omega0_5_LSB = TWO_N15; -const std::vector> FNAV_Omegadot_1_5_bit({{95,11}}); +const std::vector> FNAV_Omegadot_1_5_bit({{96, 11}}); const double FNAV_Omegadot_5_LSB = TWO_N33; -const std::vector> FNAV_M0_1_5_bit({{106,16}}); +const std::vector> FNAV_M0_1_5_bit({{107, 16}}); const double FNAV_M0_5_LSB = TWO_N15; -const std::vector> FNAV_af0_1_5_bit({{122,16}}); +const std::vector> FNAV_af0_1_5_bit({{123, 16}}); const double FNAV_af0_5_LSB = TWO_N19; -const std::vector> FNAV_af1_1_5_bit({{138,13}}); +const std::vector> FNAV_af1_1_5_bit({{139, 13}}); const double FNAV_af1_5_LSB = TWO_N38; -const std::vector> FNAV_E5ahs_1_5_bit({{151,2}}); -const std::vector> FNAV_SVID2_5_bit({{153,6}}); -const std::vector> FNAV_Deltaa12_2_5_bit({{159,13}}); -const std::vector> FNAV_e_2_5_bit({{172,11}}); -const std::vector> FNAV_w_2_5_bit({{183,16}}); -const std::vector> FNAV_deltai_2_5_bit({{199,11}}); +const std::vector> FNAV_E5ahs_1_5_bit({{152, 2}}); +const std::vector> FNAV_SVID2_5_bit({{154, 6}}); +const std::vector> FNAV_Deltaa12_2_5_bit({{160, 13}}); +const std::vector> FNAV_e_2_5_bit({{173, 11}}); +const std::vector> FNAV_w_2_5_bit({{184, 16}}); +const std::vector> FNAV_deltai_2_5_bit({{200, 11}}); //const std::vector> FNAV_Omega012_2_5_bit({{210,4}}); // WORD 6 Almanac SVID2(1/2) SVID3 -const std::vector> FNAV_IODa_6_bit({{6,4}}); +const std::vector> FNAV_IODa_6_bit({{7, 4}}); //const std::vector> FNAV_Omega022_2_6_bit({{10,12}}); -const std::vector> FNAV_Omegadot_2_6_bit({{22,11}}); -const std::vector> FNAV_M0_2_6_bit({{33,16}}); -const std::vector> FNAV_af0_2_6_bit({{49,16}}); -const std::vector> FNAV_af1_2_6_bit({{65,13}}); -const std::vector> FNAV_E5ahs_2_6_bit({{78,2}}); -const std::vector> FNAV_SVID3_6_bit({{80,6}}); -const std::vector> FNAV_Deltaa12_3_6_bit({{86,13}}); -const std::vector> FNAV_e_3_6_bit({{99,11}}); -const std::vector> FNAV_w_3_6_bit({{110,16}}); -const std::vector> FNAV_deltai_3_6_bit({{126,11}}); -const std::vector> FNAV_Omega0_3_6_bit({{137,16}}); -const std::vector> FNAV_Omegadot_3_6_bit({{153,11}}); -const std::vector> FNAV_M0_3_6_bit({{164,16}}); -const std::vector> FNAV_af0_3_6_bit({{180,16}}); -const std::vector> FNAV_af1_3_6_bit({{196,13}}); -const std::vector> FNAV_E5ahs_3_6_bit({{209,2}}); +const std::vector> FNAV_Omegadot_2_6_bit({{23, 11}}); +const std::vector> FNAV_M0_2_6_bit({{34, 16}}); +const std::vector> FNAV_af0_2_6_bit({{50, 16}}); +const std::vector> FNAV_af1_2_6_bit({{66, 13}}); +const std::vector> FNAV_E5ahs_2_6_bit({{79, 2}}); +const std::vector> FNAV_SVID3_6_bit({{81, 6}}); +const std::vector> FNAV_Deltaa12_3_6_bit({{87, 13}}); +const std::vector> FNAV_e_3_6_bit({{100, 11}}); +const std::vector> FNAV_w_3_6_bit({{111, 16}}); +const std::vector> FNAV_deltai_3_6_bit({{127, 11}}); +const std::vector> FNAV_Omega0_3_6_bit({{138, 16}}); +const std::vector> FNAV_Omegadot_3_6_bit({{154, 11}}); +const std::vector> FNAV_M0_3_6_bit({{165, 16}}); +const std::vector> FNAV_af0_3_6_bit({{181, 16}}); +const std::vector> FNAV_af1_3_6_bit({{197, 13}}); +const std::vector> FNAV_E5ahs_3_6_bit({{210, 2}}); // Galileo E5a-I primary codes const std::string Galileo_E5a_I_PRIMARY_CODE[Galileo_E5a_NUMBER_OF_CODES] = { - "3CEA9DA7B07B13A6CC0AE53DAD1EE2A0FCC70009338C08AC0EE457F76A1690815C3C940AB722487CC8F3D1F4C428828E7FD2A21230E42A3BBDF1E792165F644D0E0335F95EBDC93D6005CC0C680DB7B0E1B8C4946B7974319F9816141DB9E01011E4F20DA8F1B8E15A6F618CF599C3F5C1A1B276D51318ED4119BCE0ACD0332F3DD8F88EC5215AB311C51FF4987DA93B09A43BA84CF08032F6CB28F43043C54586811D870AD6FA27AA63785345C8BCDD3DA26A0134738BC7E08461D5409FF0B791D8574CE797FC5EF7821055028CB4AF92AE1088F8806CD55F0E5FDFCD8D74ED801B2B44AD5D79D1924D41DDC6AB2070B5360CB64CCF487FE517420348CC39BF50BDF78BE7DA91542FEAB689457B3EE69E43C75FADC303F31032FD96B7DC70A88C3B7BAC7322B285D9CFB3A93AC8B890165F23848FAD8477DBDD3D0AA4CB3CD73A48000B6D134DA2DA70B56E590A101AEE78864DA0C64A7BCC6B37CD6F31E9AFF10CA4D47630752D253944632DF6EC60AECDCD223F29399CDA3B74D1DFA5471277EE6C814464A8C55D3C0B83B36B6AC9FA90CE876ACDF65E3EA3FD61D309EB71ED29A3D510B2F4C0B6D6C5B57EC9060CFBE48389DCB17CBB2284E7F578565B91503B06F49CF3E8534870AEB6AD9707265A9A1E6E2E5E6DF6DAA367239A96EF5B02C19A4543D537EB4D9D73966C09E9B52B4706F57B3E0987885EB84DEA26F7823D895F62015188ED38C04CC6714F797FDB0BC713E3D0208462F9A68E3872A167BF1BF9791AEE8BB73CF527C50975B55C4E5C2F2E95B677F833ECC878D1764839608CC1108A75EE9E58FFCFE4CB52884E7AF15EE0632E0729DA1CF5B7A227028CFE1E08F8B881E1A743D52DD27BED33DE0EE75DC031B4864CF192DFEAF64F726D73321363A233F81C57232432D2B0A5A4C44F4320847A9C143F378F204185D2B571482FE45D6BCA152E6EA7223BFC6DCE06CEF90CE9114623EAB9B1EC789B2051B4AB711DABF5B16FCD970F437B8860313B4F1F14D384EE3976B7E55D2FDCB7E1BD9BE18B722E37C853ADC7E1CC2870A02881F95B78487780E1D1C296415109CF07AB63D0782A9F451CBEB3E8B919917AEDBCA8A8E563AD3784639793E0F25CC9CC62240FA04B2F141E71BF5C84EAC56431159556B8BCE077A51469A87737D3D6F06D97DD479FCC35129F4499C19EF98BDCEA9D4941B3756CDE1997C3AFCAE62B6D9E23341E11CD05A7FFF52F5814011A84D737E1264109006BEF5F19E3C6A9C7521B44741A8282755A8F0DC2FA0E1F6CA4FB34D8CD5FAA27E18808868725B9634376137C1BBC46934F83958112D03082DDD6148F353BD1DD24B9F8FD7AD89C40DA0A92A8DBE3608038CD56FFC4ACA35241D76FAC4CAE1211AAD9D73D51C81C59BCE05F71C345730D3A2C670F8F533A950EF24B00EFE6A3F1354694ABCC6FD9EC4E74DDE1F287AD4F847A297ECCCC39AF029EFCDDDB19932D906B9CEDFCBE0D422CEE305DD05E407340F28EEEA866664D60AF293A45D5D6D5C0000B05F79463DB513ED488DE7BD4EC9EACFEF973B23CE4E9539EFCB797456CF5FD1EC54FDCEE80B39063C48B91A5C2D2BEBC81B9B46D0AD6503BE5AACED2BA5EBE81F630B4E07510356E8229F7FC5EA532B8729CDB819E066A15379AC6942CD4BC5E97C6791E098105C323A3A3DA3880D5EE5562ABBA2BDC9906F4486B51ACF8AA4405E9D7A63DB9E3058782DD9AF3995FFB3D34AEF98234A0B3DC62C339325B60706C068F0198BD8FA658396D06931B069155217690C7F88FD230CDB38E3E48530BD47722FC", - "9D8CF144C4B667345D44F765622A956CAC4E097AB1CAB05CFBCC6BB68C709503AD9DB09C09C983D46A04A05B6F7EB26DB4D46F868C10E112828B1AEDB3C0074BE0DE3C9B7821BABB4F8B8E24F69869CCD981B09A783BF6A95F39ECFAF25DED6B16F89EA09D3A8413CCEBB545651B363DD385D12BB72420440C40E804FA27DE029A1E08629BAAB598C035DC58FDD309844F3BEBDE40FCC231F38605DED06572ADD85DC51D3D8B89B4480143D0B75283522354330E5CCF4DE1A6E68047D5B8D45D835A891F2D40C9DB8A76CEB1D18FE2BC38D080A8D97064CC87D692DF21184ABFDDA7642D0BD6F3209D06B4AE7600F7DDDB71DA751120599117ECCE645FD109CCA2EC7DB98F4177F14DB854FEB314B5D7CDC3385AD203464EADEAFF4AD08DFEF3D21240BFB8EFCAAC1356C72A0F5C61BE03CD2A21A7D756FA9003D562FC4A49A6BE788EC8D80054ACA881DFFF72C2966EECD09F185EDD11218C6696DB14E05FFF3644D11E508F4F1E9C5AB3074FB1C3FB21092A1C8D5AE05688FA4A9226C3C30D0BC3981933DC8648240F8CB67085F53AC5295428DC8447A1E5A46C2BA86796982C4C6CC647FD8079BC4024BB69E2B226E6F3D0F8A90B4D36DA2AED4C6BB60D318AA7479FDC2031143C67CB4381C27072E12935001524C7BECEDAA9954BCC2AA218E9EC2C95498FD8DF655C015896D9ED42CE7F91CBBA2CC4A7920038EBB5F5CE638F969F8B179E72AE252BE7E826E5CB53C2E85AAF1E1F1AD8D534F78A681928818AC3154651FFC583DEB0A6A1F40B98771ACC528AAF80D210ADAF83597869968D499ADE9A19BAF341E8CBA20F0E1473BDD898C24C7A5466F9924EC7EE992A2086AF295BEE1F6D0F8843D91180BF2C981C11FD978B23B6BAF7786BD526B458B76A87C31D7C52DFA43F3D362C8EEFFFB3FE5FB3F6E5F34B1FEC7EF1031146F3F609B32677F148F7DEBCF3526BB45582436A3092408193D6312626E46ECFA96FEAD12A234CACE10FAF9DE75EE2D238088146328E10E9ECDBB0B018ECDF2725415CF5A06AAB857403BBF6CBFC350903A982864827988BC805A3484A31FECF7A40D4FE251BC7E487613B9D3A48D3C7DAEFDC49C4B7E625F868DB53A798515A61050978552699EF2A5BF2F13BDD444EADC9B60B479FDD4633EB4C1062AA78BEF06692DED203819D3160310FD7F2343732156A9CBCB0B50BA9A8F93E339B702670E54BFA6DB2E2E773202C690FB71EB03671AB0B1B02B2F189BD99061ADD23F75F4914067AE638C9A29DD3661C28AE272CE692CBDE6AE880FBCF272E548342372CBAF6370C7E3AE9648341CE7310BE1C534B5702B0611AF65868F840B6B7613FDAEA21DEFB4F2024487023B02B8B58C9E9F27AA787EE775249EFC40913CBBD69C38538F239B203815F00F7B9CB30DC79E6A0C3E069D109E4A1BAEEE36D354C3D0121F1342F1F4AC504A68D69DEC158D54B04BE8164B48F31BC0827A0379C5237070B6F963741AD9ED4F3865698FB8233D7F49ED4E0EEF3AD927CBAF4FAE183252BC56AE4CDE3E329B1D9C87C6C11429B15B8EE589213CFAC208A12AA01B4F1F7CC35CD0AEAE217471B3DAC1C279F353DC61994FC45FEDBBE0005D8EC729385645864EF98A3A417E62F1EACA7E60D4E773BB2E4024D62830F103A7988733DD7BBCF3AB0CD0049006FE2F7EB3821724BEC37EAE44681A9699A025D212724CD98CA3415FE2BD09FADC02F1501FA38A6083427B662DDCBD0460E12A09072698EC8966C47B8A640AC79C1B7722E78A6C28680F4BB77BBA477BE0A6FAB959B9753217C5708", - "45D1C8FF162EE106CC87C3EBF6A837930F8CC797EC7A446E8A213ABD239582350636B19B5BE428A9C13F980B7AF5CD7F32630AFE8693CDF0EC0BC2C84F2472F5B86576E8C43136C14717A24705953D392BAC96C1055B782C7941D82FEA357E5FDEFF772FB9F3DF248455CADEAC4CBA2EBA9C91184006D1680E000D59E4BC8FBE2C2F7CC2E78BFA5B60EB292F244E6CF497D5A287432F2520B31B9D9FEC1210923299EDFF043CE077195509E92372F5959AAB4666AE486DEFA400D81463C388CD05C677BFD4953D2627105B0A776960FEE916C75D53981D30DC689581B7E8E0723D65949662ECFAA6FCC9F0CE8892E367721718F906207663F9AD450AE98D75DF004080FC15DC2CD7A1DCE013A0E547ADDC29A397ECB9E7FA02035327AC40240E2091098708D424563AB7C5867F3F2D78EE3EF5B658FDDBD49435060CA2EA3D559CDE957B7E48B98DB41CF875F7B3D9EBDF6547B4EDD98DF4B747B0793152FA8CC07C6D9EE5A2002464566D86466C2EDE54A2BF4BBE823049E57364C127A14BFE1B88ECF70EFB81EB831BBF50F6AE124E5F6A775F3F2620E91D489CCF24811C0890EF905E9E2ACD399E13DC81333A54BDD295B872EB74E412E2FB654A9874854FBC3A68C73434C5FC5CED27534B2B13C316205FF4E432FAFC13A7B5B7A7FFA9FEEDB5AE69036F8F2955DA124CE5856E8C53F24E609F7D3386DC5212B2E78B5AA23B59D45FE98AA08E9CFAA9D52ED260A36AF07522C047ED43808A39D7019E444EDF84D885A9AC84092A0F6BFED562F3E0D79FB5CF62F98E67EF219FA3F5AEB7D4E344642D3D4B1A7EEA18464F6CE8D4CB3181D9EBF6F4122751B54D0D7F3FC470A91B547148AAB1CA0DF59872120190640555A7561B0F2C11280768F74B1A56674FD5480B0F510491431810D99CECBC6DB85888BACBE2B020FB8B3D78039773229714156494EAEC3A2D0A59E718F72205747D69C05DDF1C678E2E154A1F84EF0CA2E24DC4A6A996F0850A396D2432596EAE84AEC0935B8C25D5C65B52A32722F01D281C4F753EE03EB10020E9FA02462CA303DA39560669637532D381EB78AE5EC0F6DBF6273EC979442E6243F65FC51F26C6C9554C6C0E3EFF33BC4EAB6A27CAB9383BE7DDDE4218C4998033B47919503E1C9A789711EBEAAD6C0298B3DC563F54D28675260F6D896F1B8D4FD0001C429210398E9544B3DAA12C31F7EE82EF4D2234E26F873610B76756DDACD24B6132BCFFE735FE75513ED527DD04D7DC6D24059F85706679DCD1474A9DB9571426BE17E6DEBA58B33B708567697F471CA8B78E8FA73B0E18CB6F88BF9E4F442F0FC21FAB89305484828F18B65F9D373A6A2B380D73F5924F80DA234C1DD87416D025E4E663C96F287B0C83DC92C2164D81830781B715209FD11A65E64962D805389BAAA91DFBB990D3511E506A8EC101131C5B7284252F861D047DB2C2027DBAAD487ABFE429CA21CBEA7671350618E441F4D62F2D579CAE29D97023A8873869B553293D9F54D4A929E252AF132325A6E3BCBF7B36D0DAFA1E56A39A5D801FD0D5A41111017BF62AAF8346C7D424FE007C32B437ADE60AAA9540AA5078FE6C3C3CCEA53EE863086646C976FE6C79434A0AA4F53B2E9E2C3B4CF9C9C4015391E27CDFF5C1FCCCC00BBF5B99715A1265F591E294D530DB14DFD485AD34BBCEA32E5B5D0EED15F88BF5D96D058E6D70BB1A232597E35A625E5E8C2EF5E7031A71F70309019A0591BA0A50E87C839498255A3602C0FAE53166BE5E49E29D24AEC47002B698F80FC49E718B66A8959259ACC540", - "7A0133D5CC3754D6B259A2CC4EC0298111D098CDFB40549E5C40B36A2846CB4B256672BA189CD3A05293BB36B167508A7BECA3110BFF339BA06340585DE8EDA03AD244A77F54B7931610B6F9C5C54D688A0526A9B52605BD7D7BB01A63F3D1565CF78ED904BBE4AFA4A290EADFE9DC156E59BAC162A818B6CDF38D2BC715144D44A1578BFC727423777784D15ACFE80FACAB61F9E58B5D3FFDDB065A00C5D49DF0237EA6C488D7758F1A689DC59DBFF78261016A7C723FE52FFE571F5876FE0ED50FB00A90BB82B27BCAF5A67374284844E06BB1B2D84B1D20228F5C2208CA7E8EEC2E95027B09372A309223A15C132543FF3A89B7AFBA56AA7A8DBE70E0805D3A54191CC6884D75ED0FC00C06D9D488B0F4816E12D6C2A4324EF742AC8FF885E42100849DA05E3B7C451D43ADBEDDFDD13076CD8D22BDA101F665B5878E321A009B970D1F4C48503CE35365543B3F36786802E5C53FDD756C595784E4F130904044660784ECD9C9161477F5BCEFC98987540AD1E86CABD3EC7823D83877605FFC79820F1381DA29282C3C5B3443B6A67973F0622EA5DAA14FA239542EB140082F242958B39014486E5D5632C62C3EC8BE0E09E038C0ABD52B1322E0F7407FA53AE8D761858136CB371AED5E6FC9D32CADC8F870EE833B7120BC0278D9A05554D90DBEB24ED6F5A8861698D48B4BF7AFE7763C1401572643E246DC65853996B0480D38DB7302364409357137DCD0B416561B9511BA43CA34341FEF7954C28B2D9FF96EA110E0818309C32AD306DA077CC911299FAD6396C872F3F6AF7871395D7E67879EFED929E4C05AB4C09E8BB396048150A4161D7944CBD99C94DD16CD8E0D8BB73768B17EC02C0D4206AF623037D6F4257DAB4C07B4A6C0B4D2E0C9923FBADE3DFF7FDAB45F4E6BC5A895FAE4F5BB9EA247F2D4446E260F7988C452203EEA1DFA64DEC2DCC090BB3ABE13F6A8718F8DA2BE551407B59B8EF1806A65526B6B872CB8922BB929F09341554A71E69B41B60987FE3A5E7E3424D947455083A827FFE27FB5BC5365C80998DE01CCDB66213575FB61B3E6F877D0E2E4EFDE4467D9F07B6A28148FE2FD6EDC9202F55FC855D0DF8C49E244C40CC3D95FC06C6778D397461BD157F4A0FFD915799820D55F52C96AEC0CC5A3E7A2151A845EECEE78B82ED9A217E326CF6C49F7D31C4D8ACAFD827E6ABB760150203448C000819E7E0B6E424C43A5500164CF128D686B4810D9838480604A891792987FDC549D87F95BCA120AB84FCCD8C9F93F988C87E79599F3C1952BC0F7773BDFFC50B19BDF8E3D8F52D887E45B643297650044E80124BEA0ED60FEC4449BB3BBE394CDF7CC7AA39BC1A5023044F6A843186C01EE1BF5834EB5401AF7905FC04447AE00DAC50B051B432F831FE5AAA7506160CFD7D4639C489ECA447F4F993AF0503CE5EF68A837FCF85B85993ECC55A9A3673F8F2C5CB8D3DD4C60E8421E3417EA958EF87E0764B061A39C32ABD5E0E3A712B54B0A3E2D351A0E00F4E901521C63C1F4ED829F6E259A1F720FDE96EA9CBB8F7BD7485531A81A49CDEFCE725493A04B5EAAF7411DEACDE5A95AB6C2AA7BE3269F6AE4D166D8A5FD5264B135FF8361FF75B2FF22A61905A349C6B2C1DB2BD7B385B8FBDCB2768C7926F138D5F8107111563CE527322AC42E6BD42485668106B8CE91F157E0C94448869F7AABA255821DF981CD5298D40378FB0E33A3DF8A037BC21F0AE268E69F7CF61E7E117BB463EDE3C7D2EF95987C66AC3E5C7D79C44A7590BFCF998683701DAD7B98731DBCB455E61428", - "64D4236F326627BC08E9B2B96C1A9E5BA2631DCCA3F7A5B63736E4EA8074056DCD6BF0E5D6DB8845D9271C0D706F972AF22E652E3B2A7CC482B125EF8BE005F25D5109F6F9DD84DF966E2E0B8950FE1C01E2DF15205EC48BECEFB32511DCC39678F9DB08ED0EFF64C7B5DAED1DFD202F63B6EDBCFB7E4FBB431718BBFA2B65594D78D3983B0457DDDB350AF2C1B9743AB9EFC260A78C3144622C50D528B7D47DDE46FB9DA33D1E7DE6D5829258C2F02D54085AD0121A1BC8339A2847F6F161CB6EEFC5E3FFB12E6C77E5FE10E0D4B02E58142DBE5BF900B7B64EA79D520A35506AF4987E67BCC80D00FF467A0889A14B85B4745888B09DF7B4D3316D9B4A9B17C4CEDFCB0A55E2AAC53B538705673B2A2EE4ABA914E20ECAED730E3D5E272A65A74C366177A711095624A679C9300FEC18E20E65DA3645F23AABEF7EB7C7FF49B289FD2F44661F6F5F689B6E06EFCC99F8A5EAF558E10F2236E002F7D97C316698D6833792C456F812A339166E9FB3B3F61734B98AD2DC9A484A14A6025114D072B68C47DDE97322E213F5D6A93762A45C4C73C7832BB31209C4B1F0094BD24BA23CA9378FB893AB078FA3BC4763704EB6A0C8EC965690CA5B858DAFE623AB88ED39154F46B9030462DEC9070DA9DC34063C1CAB3FB84D60337F1D6D95D1A173650C96128D3C036D0B72B4D2A298186CCA8E1F386E1F70C0716F0BE370A6B325CDFDEAD3CC67E021E9D4C839230708DCCB062096F32C4DBE3C4876A7D1A26072673A6CABDD8D65A5E91CC5E973F00FA67619F749930F9D40B767E434D0955D47FC17BB37E4B7CCE63B1D666AF5D67FCE5FE5469D3DF6B6855F9C308DDFDF6733FA7B8511B25193C27925F3619F5F836014A64A2C8B783A50C6B3001001D621CEC582FA4E52C2B916A418F49ECFDB5ABCA40E1A8D38FE400FC2D0C185009E85546A92E829DC1AD2A7AC3DD23EB77F3D80015BDA4135B1194B10ECFC87C1102B3D366C5460D20D83E778142F1A4EDFDECF3D0BC448CE24A49C609B035A99B64FABF071C58DF592BBC625359BC23A565F4BB077DCF879E14ACE87F709D276982A3D10B23A9538A6A3DEEBBF0B712DB4C16B0FF508F3E4AF4AA759738302D24C6D13037DC81B0394FE785FD14A322BC00ED95E0E9D527FE5316748DD893DB03D5C4149D471DE98C386A2E9DCFF05181E837A1814D54C9CA708CB5E7A10B0FF4F540338BE403E4B9713015A99260795DF5832CCE8D5F763C68BDA51133AF1D012C283E8F4B1DDBB4EE8C351C4AF86FB436571F53B2E80AC04BE26EA617EFA9C5578FBBD81DD1809EC5BCA5DF4A85B24970EBD88D9856B2136616F85A338771BEE80F20F6E5652FAD00F49F3C349061DE3052841992EAA04CE15DB6C48888BD3CC5EF4D6CEBF00431CCB7C5289D79E67FC6CF2DA88AB60CB65D0F687455A535C33547553966D197BAD9778542F6CC7182289AED366ED1CDB0C5EC1E9C0F0E21D4D2B8D01EF4BA394E0C6B05B8EF42D81F773D3D251D6264CA23DA5CA2D4884544FDB81A243974FEECB416D0748449BA0CDC69E56D666FCD24D9BD7C322CBC038CEC658B5253227D87C527473F34BBA3E2FC18784F864233FF8528A874A8503840AAD03B63F79FEAA6C07E4467C4A04366ACD35E32A142DD76A23417EDBB8004944A1E51880CAA97937493EA5BD5A41298863A71D33156CDB942C166748DF66B80ECAD27675A673C8692805B42E97F1B28DCC9BCB58FDF8BE55E2034E73E444A225DDDCA5B46BEBA51AE98A27990F622B32B2C337046E459B173D94BBE5FDAE31FFD4", - "23300D5D80ECA6A471DE5CBA1D29B7010240D95FE341A62FF8175ECAA9566011AEDE6EDA0EF2CFFA7BFF9F4C9AB2C97F6554BB182B23F2772090FE7C4ACB8BE7427E7A8535DA3A670341D88CFE694D1CF40156E9B0557EA317A0B3E21F3A629D1CA971482B1A54697BBC2020BBACBBB9D1E67DC33F52C4B446A36D4331FB02F19BF1A647D05714450E591C65853176A04DD561E0933CF3F24A2E4707C44FE29C5D7706723FF53ADDDC67A67C23769CA32876F0CF31D233D352FF6A7277E5A3A7578A6F2A76456C0AA876680CDF2702B114E02D22D9F59077B9DB2ABFED673158EFAE4C23A75FC8BE701D973169AA7015297BDCAD4870D4F152DC556A06BBBBAEDFFCE40E6BA4F0FEB154F32D8E1492F74EE7085937600EE176ABFD6B8638E983EAD26C63805B98745BA290813CB65CCE33DF6B98240E571DEC4BFB2430C4B8FEC23C1BD5C3E87E0E746BA8A7722A6A660C5095FEA8E1C4978B966F487376DF42C9668E5D3102F123FDCE7B8D80E8BC84AF0D91E9355FF6F7482BA74E0BBA7DACE85BC053F31074151566334B4DDA37C6C51BB947811F284B671FE53FC464CC30DDE59A3D9CAD26822183E96D2F4BE60905B94BB8B167B734A0F0B26AD0E5083A34E68A620151966D073293E5D430D0726C0FE35BA3F1F44D851D374ABD80E826DD84A665165B3B82D540CDED9EF60CE48E87802F16F5DD89163AEC8E9C523E9F99AACCC6F00126C4C8663A7D64D919EC41ACA337379496D0CC876199A86404CE5844F8E2CACFB00A985B92B7A393CE464DB19E0B5FD65BA92D8EC1164CB1ECD994F82396F6A52BE2B66C8780A5AEFC0293EE437E7FBF9BF8880B61C8313C3865561A4287BFCABABB90B3A11F6AA57C2B2A6047F1316AFE1DFE540C4F1D5270F3EE3E023E202AA530211DC51F8C2E87636C14EC8300271A6454A924A8093716756F79780D94DC6863C24C80A405D6F52DEE81810EB850C1F60732AB24209773F66B2D2AEDEDAD6FFF60902910D4858B0F706414F5779590F2DA7C249E5DC1484EC40EDBB01920A5175CB9D74EFF957A61FE3E08DD7C5DED5B299C03299F25E39B161E1DC1C586E39D0BAF38C09C2EC0B22589AC489C3199EA4E66611C45A68A7254D292C78C3978C381F297D7DCD8C0F7646E7AB6DCF155B67F10C3F915F9B3AD96C21379993D8C5D6957847EA81B3BB4BB0863F0CED12F5CC48A4325CDA65268110C1C156F845951AF3C3C90280F8883CE0236FF02DB0CB07721261432C7E0D479F859D8EB7C433F67721B06E001498656578F0E3CEF2A6B941519885BBBB03F33DEEA07802226AEBA473CFEA6EB894F45D1BB937ADF5180F5FE22857CE0EB75D251B02D89E5502560A0B6B012C191DE9D62FD28CF503375F2A1FA9EFE0E42DA81A6EB3A6DBA299726EACC6F3BE91ED51A25EAD5F3E7067720F7D4BB72F8BE2DF978C46E1DFB4B0EA17BFCEFEBBFE40C66ED1F288BE08D6CD0B097C7ED1205E43F8FFB7086120FD153C47272188799D0F4554E9A4131C6B1460077A99E8198B3717AFE5E7C95D3F49B3779EFF9E935FA63A6F881F039436EBDCA2EBE6FE00109B658BA5555BAAA4A401D1FFCBCE0369798BB3BF8B54FCEAA5FE25F31AA02208B0F070270F9E043BAEEDAD4432B1C2DAC9F7B4CDCB52965EC43C2E99764AD2613BCBE468C9477E64B8BDCB64CFCE01C06EB66A15FB034D1AAA507AFB6842AF66AC8C18807E98884C6A780805720718A3A4D1A7B094846C55B0808736199CF4EC3F66B713259CC715B22B92AFB1599B7AD539B188E99B39F9A92987D0ED15C94", - "91CEF241899B4DD47BF31F3BBEF20F5BF13D9A98D3F133AE61F3E4A87A299A6B115B96DA6B2811414D204A49EDA0E1A763E1EAFB78CE05C181DD0947CD50276A10D62543A0ECBA57DAB5DC794AD7006A520B419533CE8519F4EE4194B58B2E36F9E9705266B6E304D1DBC6B73491045548637449E5C657B263CBD9577AD8DB7D5A5BB5DF43A869FF91BB8706D4E81A4F8243C214D9884104675F2BCB426CD785A28F4856E363E1ECC974325487DC40E7304D3D7CADA5DCCA6E60F4457DA181A39801D35F20E1DFA05BC09E7699FA289A87EAB311BA8700AEC0F90950E5FF740DAE7EAE7FCAE8B0D9FB82ABD25BF46FAA635F570C22A76C52F9733D5BE64BA67AEB5D826288D03D8A23C5BD3FD6DBA68082B7815044E24859865ED557C7DE8F866823CD4716E573BFF30067F0931D0AFED0146D55B0B2A3D6C57481D94F61279DC4D2C6DCA1CEE27DF24426E55AB4FFB87068AC8AA6F286151356CEB29D993B4FB26192319C373A1F0F58FF5949783E71671FB58A683DC1CFE166FE1AEFEC8A41C5FC06A31F4EFFFA3EB7C388E1BF99667A5D2697F7132409641AA812EE84EA8735BB46E5069A7BF1B2618B56ACB97C368AA7BDE1BE0F0BF286B6D08B42702F1EDEF408BC529B4158824F673B30E3D3247FA59DCB83D004459CC5EF87BD6C7D188FD91A2A7FFDB008244F8618ED46A73323E9C7F9D5A83298F8C81702FB4523AFEA589D4CC269BD226D04689F132F766770FF23C832EB5695713AB99B74035540031AD1D9D9047D72B1910BC320A65A9F63A40C02FAFE217BA0C51FFE24E96DACE57C1318351038FBB81E76EA34853484E7ECEB672A4180A3D24B6C692747E9D306DD0AF275EC0581A30AC2E80EC73B04B1EF83160FD88DC43406CD715EAB1677F1422FCAB85D1D1EAC64F698B9ED69FC9F2B5519AF9153D5AB722339434C780886B81DC2878B27177B4616450BC1DE99C49C965DC9257BC78ACA052E998493A0CBF7B6AC86EDBC2627E43E7521A9DE7824DFA7DE19AEEA5892685D50EB10128B3D14F3C670F639AF6F2B2F6168A1E551A65781A418ED697E6AB3CF91EA2470995A401B08380CA58B9439DDA7BDB7A92E91016567D57D57D5D0DC4D8E3C1490CA1BEC03FDE065C7B7F34DBC40BF704149A0573C55A0EE4C415533829EEE71BD8C392FD622572DE009044E937AEEDF672886CF4A36ECFE7B0F8BA9CD9EBDEAEC40BD74AD34CCD2C7DD07F7AA64EBF4DA9C8810C05F55619B808127CCA00D171BFEA3E1EC0895A22218DF1A0514FE5D16DC416D9FFEEA8EA3BC9FC650F678EB731E70A6110E138E059371D5A10BEF6420A0C8BD45F836B7D310E732BDD0FE57D93A6934317FD8E2449BA0F0C6E1B36821B62D1F80B9CB6A5B407B6755977C06BB2C3CEED0B14D4D73A3554FAA54EF2C350C388B230B30148605035E4F481A769564E2814A160A67E6F0DFFA7814D0C12772C0496737C52016A93C6753C82FA896BDFF3BCC72105D6EA5B52B3810004DDEDC266F1C90CACF49BA7DB5016A4E485F06355441CA204F7D589F2A3159541F991682E6AEAC0C7359B3282A04B2DC69BB0AD6CF49C48343C8A769D3EFBE8D0814E72934F7CDE698061EC68FAAB39016B96BDC5363D2B53363A548E6476647C10F55611469828564C189430D351CA01D2F1029CA3CE1D2853E8E595D46C9C3EE9F7D3EB9C72A25F7B2138063A0F9186FF41CA9C579DA61772FD60408668A877CCF6B65FC2B88935822A6DDABB97D19F7455A9725A8DF2B8E6B28D83ACDACC66F02370575831490B8D8838D4E56AF36ADF8", - "AA82DC5072A45A21B7880DEA3E2691FCC22EFF3AC815A2576A7F480ADA6F8426EADB4A96A17EB949BC049A646D46926F0D69E0B3E1911D2CE652FF4D9CBFCFDC30065FF4F779DF896D38587B297BE8E224EFB1DFD04BC2D22832B2955A250B7D0448AD9C0A76DE7C33A4E2B5DA1B3A868852B7F04D848EA6495BE8D2501BB47F24E8DC4B254DC56BB5A4760DF62BDB229F3DF0E0C06274A63A28D11F928AE2DEA72A9974E3C55CE261943F78B771CAE7B5B98642A01DBC06111B137774898F0F113A4DB23BC240BFF147568493FCF0C3D767D3548A1C0EF7AA4B6B2DF566C3E94BF9A183264F63E4FBA58B517FC46C4F0017F8D763A54D044C644D6326677A425F0F5A2A7C8796B9C9F8CD0FC49A1F035BB6662C0CCC0E9508AF8D2B834B929D80096F9BFC922BBF1BFC6F101317EC08ECC1DB52404B30B153F43C266D3E64FC496CFBBD350668B2AB3B596B5E0F0A00757E0D4A771F5A386AE86F5105C1718F7E93CF00F588C722509A03597B95512CFC705F08D3B4D5A3E23C56EB461A719A955AFD3EDC8329BC97E3EC6BAB24D97E16A724ED2D4C02B2371FA3ACAF49175A441C3FDE53C2DDA440C18BDB8A6F27805F944EAA7991D404CA74544E2F3A669DCC4052B6770AAD9EE29A6EF7791C6DF93054D07A2B3CB2327B0EBE7D983624639961AC4C3CEC2A84DBB3A10A830DCAABA9600DED87FD5CBAF4D5F1DB357ED42374175257474BAC200AC1B6A5B87D2FB2092458F51185C380B8BFF682C5BA1D2CBF8BC02E5D485FD811797AED167DE6ACA66B927363D12EA405D75A2E9182B1FD30ABA700C5683611A24EC5DC453F523EAEA44C6E06261A98346328ED9E86CA8F7EA79EEC551F36836272127A45984EE165BEF8AED80D26DC45E34E1794F56C1265DD92B4078FD2AF2F13981C08FE27C55C3C9238BBDE193A956E3F834445D949CAD84D3FF0FCD511C6C598735D5B3B07BDD7D437ADED3ABD6EC3171F3735883C9F511A06F4C6C7D0B137DD0D57869B8FB1375FBFCF9C3D08CDCB12B8D01614AA3C965550E5862AF49B04410D25BA4BE86FA6B0B9D9142461AD3CB4BD6D902EFA49632A78F1463619E1309CC89452C2B453BF9F08A714D67ED90972C62C0468CE17006F9B60138D28DA6362670BA3048CD8D099AF193619AA8384A1758FDF4A04CE56ABE464A66E913DB7BBBFF7EB2ADBD47E6347D7054CCA13000DE13F550C6263AA4135A2E16F1A2A58BEF962113C209CF58CE514FB51EC162D05A4DF832697E544037CA18E62A267D81D539F879F50C654E74BA21B47FFA5C704FAD2147EB3DD8617DE98B3ED4859B605310A777F3DD161F4038486F0872AF55FA3610EE0D68C1D51E0F91EF7D9AF4ED01BFF53FDA16BA3197A518BAC0F82F8895A2BDD9FF4C3035379E870C49DA1AF18B3668792B6640E687BB71F13DF1650C4E1A2CC487C247D1D1356EE16DB8F97363465614E9E63F36C853FB63C12963A8A5D98B52BE8DB31F0954B35C3C749A62C2B34A690803FA66087015506225181C5D6FC101D1494C3A7961ACFB4D9B905323DAADABA1DCD2DDC1F9CBFED7D726E602578CFDC1519925F8DBF9AC5FB4E4CA723BB264B5D106B6206574C46C1A49309C22E1935904942C36148F764B59F10A5CBA0C9397F5798E200A606EFC75DEEA1FFB10A85398E5BFBBC6AA3619A0F611E591245D03B6ADC0C50440A1B1C236ADBA933B2BF84D2C60C807E9F52436904BC62B813FFF8B9C824819C760D0BD636B10572C781B112CC0C603A260AB87986B0280FB913A9E0BCCDEE347F0C744BF8299A9099B8", - "F2A17D19ECA96F67ADACC0D83FDCF235F07832E8E78A44A53F9C4CD09C3F88DB226701963147EE0E1AD0F549E11BBA70053A105BD62C40DA810BA37BA72D999CC4FF9BA4D01FCFC670E0D7819871D06C4935C10B85594CB7202F037B25F85141A580AE1CB3E0CA91AD73C6947D2492B8FD2F889B1421E04FF0FB7866218A491D9EF6A35DCACC12CE098EC575C697F5F8D1BF9178B3B36C999EADFFB5CB3A41DB672165CF73A7874FF68B3B901C4E9B8112EF4FF9B9308742ED678DF30E2F7C40BF922099C1A95BE0C231E9F8332EBEEFD99C6DDEF25CA5EBB2985A9689912616815AEA022BFBB87353B8B799D64280A6922CB09044ECAFA51037AC2FCB11516E9E286F64B4CE3E30A55191F24AB53F2E10E5A8920FFBAED77FD4C476E9AEC751763D68409ED9BF7F435E53D401CAD787A50033BB8547C910D90DE100FDF6B904A1F529830E3A51919299FD4476F02C3600AD5D42E3E154AEDCD1C99C1C5B531FE179860EC1EAC69EA0381CD4DCDE8716F94D6510F10FD1915864BA968440CCA6D0D5AD8983C421079B033B56FC34481B9F27188F829F91DD73F27BE8E0456B0F75DBEF40A3C67F274F6A50CDBFFF9798F8DBF1A6CE7158B577550E40639D38861A3CC4E060C9E5BC1F0D3760FA9A89C2CF0A23505F4A642F5EB0A055B96843198CE20133DFE022AFEE043191007276427DC82E877BDE27E20D65DFF8232E9E4DD786C23D4E8B5E84637A22AE5562651BA45369947C159B641710C98494ACAD48B4AD6AD9828897437AFACEE442DF2330669D5F2C6A9893E08507ADBF104C62F6B4D568C5381B28D5162EF0FBECF396E7C622B54A7864F9B31CCB396A0DF82AB86D950B4657237FB769122BE6B783ECE3F798AF68E354C521C77735EDB97D580CC80877ED702231CE2F8B73262AE39EF94E84736949292E065515D40A16BAB13EB9437D30AEC44AD8C67E3AFCE9AB377753BDC481E8E79EB10F89A7C4F7AA24E6FA48A36DD1CFC02CF3FF6DFD0CC1C4030C312532A70B60F678FF2B3586D77DDE74167CFFA62C12F7D0086A6FA59B36C6A025DEA1EA0BFA9861BEFEBEC6B2601DF225E29F36AC97EBDDB21D7E8206E1EC42F3B9CB314E7AE6464D54ABD53D090DE83B466FAF5384E0FAAA6E67F2FBD6A72E00D9274C9B5C768DB4AA4281F25EB2DC6BBE0EA85CE1CD31B32BD1971D6AA20B6C68D66426F09C0C1128A679AF06CAD490DCE3A2DB50181278BC40DF9E094D1D09B281CD1EF1C369E5927407E04918BD21315E12583D7D845933AEF186DAF8B6609C3CA9452857DD2112E86227422491DC7821D7E41DF759BABE6ADD11A4C771CF16469F86262D169F221D97DAC9686B6DA29568B4A2D2579C76CBF948C321F5158EB3FF5F6D4D6D68FA255C81F62A8DD605507D0C6C9D82E6AD258B32DE4AB6FF8FCC4A8C237E270B9673C208E56AA6F4796867762399FC8549DBD232B2CD0F9957A8A24FCEC6E8B3DCCBC67085C542A134F3E80A3CCE8D3DBEF0528432F2BAB2F5DC89D6015BE7F24B2B1F378EE75222EF125A5645AE37AFE6ABDF84CCC3026507BAD9CD8C2EB4020E7763E0F85164734C851532FFE705C111CCB7D738BA8C0D29C5A0A50250D0BE53353A6C407D4F7EDD62F271F099528CCB520E5B6B5695D3FBE628FF65D67CC0D1B766149B9C89D3C770AA133FAE2BF3C9846B30C46584E9F93A8216627CFAD84C37AAD7986B8D69F83392FF8F98C828F8B136633A09718D375327B98A0CF8B7736D229499A52D91D19CBB896A5BF4131691682741797A25FFFE6AC60E30C79385DC778C90", - "3D84AE0F7756BCB2518300DB110A07EC46869AC35F1B02650A36C3CA0350356E2808B84A0D9A8A648F920B7D48AFBBF6CA9A37F673DE2B6FB15B189FBBF2444BDE8808118595AA995AE0DF53F5146B011A0AF5B7FCB4B3D3EC074F2DF15CC9708EC50EBEEAFE06F7A0235A50E2DF7F6C023B53819AEA87318C4E67C4742FDEACF57DC539FBD5BA01F64CB45322212C707923303D96E58EB95F7392292885391283DD9477218697698AD6D83AA96B06D68F58FC2B8FD9D61E75337C6815BBFA8B76833FE1856B714ACCB6FB1B5E957DD385658AC760AC5811E3BC079DDF2CE30BDC21AB8D2C7B56D2F6B384FECDE4EB0206A6C00282950C1B72B3E464570364A919812E86BBFD0E1CB2DC98D6FF42617355F2131F72A11F50618CF21A4C4961083FC6BFAB63F544677428BB9F10FE341B947C41AAC1B367E338CC2AA08D6CAD1067F02654794571FA4AA11E211F5E75D194197BE4AF6543009C40EA86F74AEADAAB134CA9E35D79F7CD062B53BE2AD86FA7C2E30D9222A494A25044153420AEB6C8FFC4E0D4C514B8D9F5DD922D8EA387003409539D0B40210B05C9209B008D3E47E8F84C376F46001FFE463F21A92E34D3345751E8E94205EA06FAC16292B8C6D4FA028867AD4C4E8DE0D51BB7AED59547707CFBC2CF3A9235C29EE3A3873B96FB75DD50E758CB2C7196BDC09336A97756DAB994C46D5BBB87F9D80008D09C603A68022BADB1D2F6B98B6B76CB3C0EDAEA07A23065B93DAD67BC59C9BDEF7BDCDEF39D9AC04C9CE8F6DB4A925F77BBF8150AD478E3C6D7D32512ED75BFBCB82C66D505CD8BC5A5679014B355BDC66F365BE9AAF15B76C0CFC0B51E53F86BB4763F0302B448E84B9792F34442743E2D979C5133514D4BB1DE5E8AF938C4CF158336D04B6723F9422161805D5EB059E55C86D0C461399073A705FD6E919D1760B2D6860D65665B486DC0AAD8F7B3ADA9BD681D7FAE4185350BAA543E9F8671F1B4BAEB6D18674516033B2E2E4E427521C290A6E44E1EAF9974BBB360FEA3535CF46D68193C0E208AE5B2F85C2049C906725C92F598E6C0B67DC5F8B7C48CD411E107F4860CFB3C4229A44694ADE0E31A4FD70AE5702C0A7710678763B035C5C6B4B9214D507313F5ED85C444B98278B40446C861057AB9B897638DE4739088FC28A577CBD52A3910885276A2DC8DA99EC74D30DF707BFC60663C869DA4C47BBF4D64A789425C5C894EC2B512C3296D0070DE4942113FFC0B13D03515F2B4EC07A0E3BB7AAF08DE24779F9EEBE26CE7C316EAF47396E538672BB646E1B2016356A407B8828DC25D8F8A8296B4F855290131734C94CB92CBA5689574CE95B60988C42558DAD978F36D67BDDDAA92FEF21282683EBF6D59763384781EB4D3431DF5BB909ADACB397D36D55D2ADEE537D7B1B942F3A815917A388B12285689B40C3B45C04A591672A2B957F924F1CF6049B96A38E304B8641DF6A079614C9F9984FD9C9F0A82ED6E440164AC484252B45147929A58B069E663663CEDF0FA44FD67580BFD23BF77C61B95B533107A25684FDBAA4C1285AB568C9FAB387C6FDDFD5EBDF5AF1CE094C59630E19F621CDED14E3847BDE9B0EEC64C159F23C779C4B80163554900393CD7F1B885F92F183839CDAD7801DC7FCFD08B7E08D23BE21BC80F8655A2F3BD0C483B2C1D23D447682CCD9CE098AECFD7BA7C48F5BDEAC8397220A7852077A8D7933FD353C25E37DAA473E996A5920DEDB80C26DE4FC3AFBD6ACEA16DD3208C9384021D9B1FC1C884319B59276D48D8BF5A0A37D84B8C579EE0D9BC", - "446D385D09A3464D1ABDC6D6CCB015280BBE7DCF00078634371D7F327322DD720E8DBD7B8CD97FB9505A118B469762ACA10C4E135ED782FC905EF30F9FBA82F11AE679431F270351F70F0508BA998AD9A71D2BE05F55348B275A0E537C63699C96DD8AB8E0645CA2606E35805F66CE586C81B4A65E2EF036697A18DA49C36CB22404497577107924DC02FD87072490D7EC8D5B376D0C3370F9753E0E7C781952C03D844490370D6853FCA49E12139805C24FE9C9914E3CF91464D332C934570DCD5D1C3C609C6984E28C9BFCBA3669B75452478DA4099CFE0F6311FF782D1D0123A120F657CB536A3810984871B69D25913C305117A7E51D199A56387C2777E349748B9C2C40DECC03DE7235F7237CF43FD421039743CA72361DFEF2491953A3C3F0091FE3EE064B838BD73E9E6EDF8FD90235CDB374892BFC42759792E5636D031795C0DCC70D7DB86C161FE7059CE17B6926FE5D024D6B1B9DD5608839DF85C7802F5655525B633BDAD0803CE14649095C0A7F870F66888C072C410E0E0854238BA7FB259901CAFE3570D398B621518193BBDD75258BCB53AF2789EC66DBE2311DACDC1F9CDB6DBD4BCDCD15F9C2E77E0D2736CD191D2B83389A71B1804A0FB5F2480E38343CA48EC6D1830BA3466E53FC51C4EF05F4D10711A78AB215650462E9A26D9301EFDF15A3CD5EEE14DDAFEFA45171BA3A757CD6FAA5887A5D5A98045BEC7FEB331D01A997282910B6B946CADF0AEA57973520EF0561B233BCF798805B3B048751EA086FA71BCAAE15F8BEB837CD2974EB3E54D3B6D3F99A51F88313FB64218610CD1831E2E6E18EADCFCBE72BE5818B4AE4F3780BAA7D8C4A55DAFC10ACA3EE7AB7D1337506C485C83EB0C41748C668705B4D41D926221D33C31BE7D56B42BAC7E9240FE4C2287B5B41FE88F9B9E19970D0E4569DBFF167EC42BAA2566676EB055B69D159358D23DABFFC86A917490B4942A220038CDADBE24C335DEB895F3472F0D22778BC79B169D1EDA9FD18B31DA66F0246359DB3EBA36269EC5F92E5A1A89560C7DEEFA121A7035EC2501C553854724C5176AE60F87004F6FAEA907B91D1C58837C9FE25BD9C32F66257BD78169B1A4B8ADEBA72B5699D4C2D14F67BB347EC8A96B04278AD9F97A9B40DBB56E7593CF4B3C905108F10968F0AE6A2E7F1D214FC7B45637A256ADA5EEB70E03C02DA2ABF86C36E581A31032DFFEF4343C3E59EC7A2A715E9C199DAFD3BF8C9B43C1D016DCD33E2590A20EC8B657C08E5C0C0BB4F159A07206504780715A252D1F4F5DC65ACCC43E3CDC255123A77792685C9B68AF281863AC89ADBD5F778733E95050ACF781FFA386B3EBCD633D6E8E6D4A42EA85F005AA80A4597D40738A8E8823FE3C84B10CEF044E9651E45D1ECDF59C537AACA58D2BE42655259DFE6CFFFBDAED252254B732EDC93B4D610C50DC81B576C5A5C5BBCAC0BAFD7BDD7771EF1A19C29D7A82E448AFA07E7FAA8651C11D1BD550DDC69F4C9C6A44435034D80B47B512155E5141378A94CD277D4BE11B2A383B1539AC9731079624E81D3A3404F5325F5D2EFBC0929F510529C84B1BC3E7C08F661640E55AC49452C00256BEB49B7A52DA23EFFD85B8C303C6EEDD2202768ECABBFBEE87FBF1DAA992C8439602B1645C462D3297DDA1AD941617B508E481A28D1540212CB281B5388A3691A26AD7D3CEF52FEEE9F59F477EC98AFCFE38034B762B9D4B5DF3BB312758C4238EFFF94BD16D9C39655CF07263CD6DBA96D1C0EA425610C1FC81061FAAC5C0F8E6AA9591EDE2FAA1AAB8F76EE18", - "C514F282EE4B5E02A90A2AE126DA52A9FF5274735ECAFA74CB36D607EF299E0227E94B6CC2B78B1F71D6B5FB8BB4C78C09B3A6E3ED6CD590AD526F74CBF869085F2BD3A9DF66D7DA9DD06FC6748D8FBB78D98A4D860B362BEC6295F34A6A16A58BB21C9632F8B3A64370B7A7547E329B39BCC82D17B82F6E4ADB514444F62AA800C97B748D73B0168ACF2FA898C262820F8981713D00CEB8453E3E9E452F5EF41452A9C8CD1F1260000C4CA9AF4E6E629B13DFF203187C0DEDA08315AF24181015D2E68D6AA4E7E938FC4FA9A8B80CBF49E3A9F27953A05FC7609146EE39F09FF485015168636D1F452FF311D4D8749C31AC8420865A87A707E540D7FDF0D25F63C7F3AC906E048281BFEA46263B4350BAFA8B5A27E0CFB23DE145622BC2FE34DCF4E1B4DCBF60ECD5426C27B3559B73A59CB1B71587C685542F5E6DF9FE3C5E75A8E9600E89217343D29C67A7AE80F9A8589D82AAE7B2A1B8D6546D3CE2482DDABCE7FFD3BEB2F1009297A77503E7155ABD4692F1244A49AB32628947A681388AD75A750AB92C81ADFBCED0AF166326FADAE6B79070473D67A8FCEBA7F21BBA932168CEC2A754247CA324081900636D87D001A605C4E5C31AEAA44A8DB9693617566726C7120AD15D96D917F5ADD0D86A5A9CDD7527644EED58A9BED014D9F4C0F62FCAD8D7D5DA2899D57C5510EF15B7482CB3E087493959AA12D73D55E194E48CD128FBA2788829AB4A86C325D60227074EA55BEB601128D5FF42371E74972B802D3117E1F2AF2018177D4E994903996DC365D3B52582AF2085EE5919DA7E84A2F3A200F4F6E76F11CC95F87BD2EE5935CDA0D52D9EE6FBA6D59E80427EEF4B80372091C65E059B566C38A6B3664974396BD0383A35EED0494C2BDDC167725C4160AFA58D408978D5A345EB03A55127C6BFB08FC0B4EF7037482EA724D9D121E26F2249C0C7A927946A846A67FB7C565E86C8C59A49265ECC4927A8FC88873DDEAEF6F8B629BAA1819807F38AFAC501EC9F206346581174A037B1D7EA56628C660E17BA0A97F2E189299A7844FEDC562BE678B0606CE18493F717559365F66201AA598C68F99A8F28AFD74AAB0E3619BC342AE9F36D3811EEB52C8DF6544C96B679CF434B9C64FCA0F43DA73B9BC8FEBD609678F5E691AA706E3586176ACDC25652BCB68D98417D3FEE12B23724EBDF496D6AC3B35EF706EAC11BB0090066F3C421C3E298B00821C90DDADE472331B9B2CA1F1E53E6D68BFB059EE0811EB7E7FDBEF394E3E35E59BCC4B63FA8E09851843F28CD941F9A97E5B72C8DCB9D32F37B79DFDD1B9D7C22C10E6F65DF07DBC7734430B811BCDD450A10F491B1E0DA3746868622E457774D0BCB1B29F9C1CB161DEFAE78354B7F718D18F07ED6672665D35562D6F05A2B3666B667A7C57D2617711F27DEC15D0A4079519D0ACC6B3591EBF0A61A12C42A6820CBA755C07FC531610C4192A0BE9BF241BBC5ADF758FAA4DE47C6B766AFAD728BB1D2C672EE0969303E42AF789FB295E766E90319D98F0618C1B4B8BD31CD2C5EBABEADA30C6E43D03F380F4C2B9C3AEA20BC89B852BFCD042AD3C9440AB395E9E251DA758D317E39792973083B20B79BA36A14057E1DFFADCF903B10F8D3D4D35222E4584D520D6FF675D3EBE9FB43ED1B79252648A5E0C2552E388AA3D1168790A09854F1151A94DB4E5AAF1C941FA61B196D869B16051B75F56AC1BC769C6E7A7EC173264A2E56BDE4BB9952A422855D65AF1C209D561F8210FFD7C2FD6A540BE788BE3D2822D49DBD2C6B33299604A835F07A34", - "0C0184CC1854C2013817663EBD9E23F3B78DB8009E761F1B38C2DA2036F26819D2DC68AC38C18FC15EB00BDBF5A11316C7B6075BF9DEAE9B0A651527DB3E3B3039BA01398B3923A2C40DC4706A0BC186D2F8FFB124EDE35E8C427FB6FF05A3C2ECB81E275D1AE370AFDFB6F731E27F4B22B877B1990FE479239526C655796BBB8545051527ED0E532E0440048912C64D0913227C2F6657B8B80FDA076E49B7E3DBA1D0E23C9D7F43280A324DF16BEE2A87B87C21692FEACBC3348C9186DC6C0BCB7C1DBEC60AFCF4F1D76FD3D45A24ACFAEB8E7C95145D07427CD67003019AB57DC233D566BB9A20AB82ED4130D9B4C0FAA6F2EFEDC8977498315FED436F67F3B170877040265EBA49415B1B2904C8277A11598432B973AA63F628456AF2320D3478FE669E2835C00D13EEC7B6ABC6BB94F1677C9A05B2D0CB87ED3E529AE1D2E3354B1E30C6634E10AB3BB0F39815049DD5321B11B80CF1D1F1426A413D0D11FAE969F3BA266F4F7B60684224A6279380D08D46FFBA2E1D684416405A02A2AB2E260ADB23498AF716EE58B03C8CC442DE0EA201C4DE39FA7038EA4E0E1544BB08F149F57F03FA910E09C27303038EDCA21A618A54DA87CA747763EE6D4D1DD4912AB7E3BBFC999939F82563B944CFC5F4460D41A47573DA92CBB28439BCDDBEBFF16491C404B356E5889D33A034680F8648F2CBB1888FEAFC410FD5A3C8ED85B90EC875D7D4466904F5D4A4048D8DAD848313232B80FEBAA09D4D86F70045C0C2499A93610DD088A6263DE5AD71067B9B3C82E20658AE98677889BDFEC65C2574E4AB7C9059F1C13CBEC17EC630F9E5B891DCDE1E81552738D4C8612F3BEBD570EB39B24EC94A153465D1326765D9B8F23D7E4AE3F2782F6F9738C189D0D20C4DFCCCD37D9A510250F0941423CB9055C7BFED84520AB119FF921CF81CBC6967E9CE1D759E5F4481ACCC5881F9328093B63ACB7D04404D8C0FAE8747D39A270399000CB690CDE17A46E81DC5CCED183BB863FD7A535CCBC592C25B059496C45DAD179B83EE02543B5EF93213E10E2BDD480F7C7D007CA2988942F65E46B886EBCEF05498C655048C4B32A081A059A28DCF4D84AAA586F0291F322B25D186FCB5ED2DE7AF7EBE58CD8314CF846AA39C67E2F284162524A14BD2765642B31F31EF4704548C13D5F5A132E983203EEB91795BCA934BA7EB26DAA5450745333446D2B86ADE99788476A3417DB7FE9E53F4906CAECBBA984657969B4592F9213612AE6812C215D5C6E28BC89BB76B9CCC937BA4D4C6368CD4C491BDF41B242BD8FCF9DE2D35907F08AB80BE71EF90F84BFDBC6777A020DC97BCA1E963050FF991A4F0E1E468813AE1CCF05B819012377334AD6B5A41A87A7D7C4F0AAD241FF7D3AFFFF40D7E6D5E62F9884B63E23C3A8B96260A6E9E3BCEC001D487E3E75DF4D35959633BE719FE592C4659970C0B67596E9CDA4EE3B05237C02CF2E36FFDB7CAE37F0BE993FAC46DA6F56B15FA74EB4511AEC2C861C2A9253259268A9BB95468FB02867394AA8D83EEB6464A65CD15DAB6A696FABAC4661F439F377560F3D2F3B668A7648BA4017DB5083BDD0D76B0DE99FBC06D7938D7D2F0566D3DDD036CF6A5E336359F0896B9B1E3B685D963A0EA70CAC175574C5AD41E20EA1332CF103BDE6B1C3B3F117C21E8FE7450866C5036C244856B5FAC176671270EF7225BE7CC36D24498C92E5306C2870FA7839DB1D7646A62AE0623EEF3199E8DBE32020B71F23FEF2F2BF3C9E0EBF0FDC629D97837B97D76C99398EAB044AFEEBD5BFBC35FD4", - "8767E0FD01FC0DFEFA6640DA0B47AB5B2B2CFD25C8943FDAE6AF46C3898AA1FD2E2DD0FE19D1A9BD0353A16ED03C448B7005D56D108FF2035E948E3C4FB8F0F928A5797D491389AC431F271DD1C8FDDA2B1FE623D410190FA81F74E042C0BE9F97F99120DDF442D5A4ECD1EC9789DBDFA8C8E577E0AC5A1BA7DD6D5A474CAC3C2C04E71A14DD2244A30D64B17E4C9B081EA8AF0175D7D0A6E039B6A289EFEEAA20763B1F106667745EE2795CC588721BFBCA6D659D81192A02FF2CE11CC878CDCE73CAC9B92A972CC9340ABA7A03C3384ECD28301103F347D35FCC9B12B85FFF170894F7D104F34D95B56A23C486CD9E7520EF8CC0BD928EACCFDC5D230D77EB9B19EE274113E1F8BFA79FCA93EF54B86900859BA6688FD29444E03E2F14033F076FF2F23711129099051C59E0126A907B57905A021F024D98736C3F5D1AA11C25F32319546F91DCFD4940FDC7C4428CE78A998694E6B19AA3CFF470AE4582666D350ACB02CFECD0E9EC39D1607912B892479EF94CC67797F443EE6BA4008F46C0E61C3819C5F82DE7A7802E62E7050C8AC506186878F08ADCA8A7674DC3D0D156060AB7BB08511D2F8DB46EAB9B46AF359135030A9EB46A6137A9419D97C7069147BF5065712B1F03BB8B328CBD1E583F59B662B64C0F06ECEC8B71AA2213EC29F8968E0F3093AD04E739F01DF51C644FD4CB65AEFC7073018DDAA81185627B613242260CA7A9270FDBAC3EBEF62865D0341B5392DD5FEA4827D60D5AD1C9AF0739CF5BFE0F658E72C436BFABEFCC403B87AD4B64F3143DBAE1D2CC25130E65D72ADECA1A8FDE09EDFD723072D538792F50A067BA78D7E4749F0344AB1AC1CC0E8EFA1A42515877C4539EDE35556D444516474628BE9D8B29DE428BEFA12EF99C985F1EED4F937BA4794776C63033C03EE356991607473835A50718E473D036F3C522A9DE2E49FEC2E686F17A5023FB7E82E94B26A4AC6236E0B656A938BD7A8575D734F53CA419836110DF78197D7DE4D45B6589CC31F5057759B8402F43ED9A423A7D69DB02EB9357B1E51207161E08FFEC8FE286722159C570ED4AF63EB554BBA582404C0E978CEAEC1CC1404CD15BA22EE6D8C98C4278C1714695927C2389D74BBAC72C2516AF1E5D0C52066A656170091B68A7E4C8399ADE63605E9DA1727C189C541A404B7335DA27843A32E470FB4DED8EB5EFCFD30BF15AAF37D7CFF4B545DD09DE3E7C8D0E77427B3C0764608912616E5DA2A3B885688F25E83DC8D632BC00015C2C8E6923A3D9E7C7344CDE87D6F0DEECA2006F644F7BDFA0A524759B2B16313501A1CB8D4D762D3E9D9C8D32154F69F0DBABEBD26AEDA947485FE0B40D1D7731D7F4E41D1EA5FC645DE31CD850273B6EF9C374CC8E8149960B349BA16FBDFAADFF12E86EF05AA38B6B17EEF7B55D27D7CE27FEC916DF99F0715F1DDFB93C7E1130EDFA44663CF19F4008D5CACA48262C1E8209D0C353ACD72A542B93EF18EC7E15FD4C9B1633161D94B285FE8CFAC30FBB1E140E9561A35715AF982370AB4DDF25BC30850E5F0509297289C0045BD3B3912843A9B0BB88CB7E961639849B8A0A75E3E903182F0CC6C7ECAD4A38081BEB18DA72EF9F9439DA7DB2B4D59AF6CB71808E604E56E1D4BFEF627226FC28875888BD486D0C8052068D12BBEC6B27E9DCDD73DBC93D33EE66AB63936C2273525A517280FB4BC33A724D20BB7D988B938018EAC4738D03D583A71C16671B87CD60BD6FDD101BF2AD07492A794FB8696E84CF24B9707D7706F0AEED606C3A7FB5B1DF7FCF86E65F6DEAA4", - "CB8EFFE09FE09C622B34574E74D4B061C284F96FB7937481FA7C204F449BE9B2DB0957E428D177C5525C67BD75D75989EE98D97C4D0DEB5E72E2B0DD62E66EDBEF0D22D2EA97D42A3374B9B659804F1EEB01D7743DD9AEADDEF356C7C4FE94077411DE58DFA5035271015AF65FD1D78C0F17632C10EA02C537706A7C14E3A1D7124FCC11F579333A68A1AF70BD3E86F7B1D13A3B4EBCDE343F36A2B226DC53A0E1A084EE966272EE852A349D7A5606F1AFDBD81B8C3CB556DAE83D6A34ED4F9C06BBFFCD5953C51814FE0F4CF5A697EEF5559886D92F811004C04FB399E06DFA845DEF183160BEF8546F6E8995E403FE0E464008646330CEC4B4149DC464F229A47E0CD9F89C83A28FBD0C1E758D380C2A7C17A487191A46C04C23F7906418B69E2527F3293588952919D220EDC36BD9687C7347AEEEFC8CD24E91299900AE4ACF018FA2829E215CB13CDDECC918DC85BBFA317FEF7D2FFA9E3A30D9D1F1B9DFA0AD0D641E800850B43D7E0B187F2ACFA74FC5DBC99471A7511B838BEBD6E2744C3AA9AA9D46060C83FFF803C148C35209F840AC23D60FD046B461CC2D776AF51612DD166E1450B8A998052EBB25D1C8F426391A8571C88C2012A8940CB0B4DB3223CCB39021D20142FB5039A6ACB250994AD7A99B1A43494EFFBD8D3692F213B46C6CE9AF3477BD6061398CB19C099F27F48F4F785E9E741988412F070F39727FB8B74071E007210D939B0EC5D6148A5931D38A030374E5C0B575AE27D49DF49A77245BE310E49262C56A616C757A80C5989F27962303825EAA3AA014A4C9C9E5B3CF93F1A031F82D6A0C877277EC41356D1BE2154F03D807940A1CB2848A6A23B905BDE9A907F7C20E333586389014126765CBA8D5C8951CE09DF085B5F18A24E1E5D638651687CD2A2F75CBAF738F65A8B24E7C67E64FFD9CB8A34A473F11996E3663607A49EF663C4D87A0F65D92067132B5EF3CFCFA9B49FF66CB6E363BC1C7EAAC392605200A5EE704D1E754CBD1C9CDAB75355BCA41DC129722F855215220092CF6248609DE9EDC5603562F5C82B5414BA305CEFA60020E1CD93FC756241FE7A20CB4B550D980A7266E7B23B6FFCFFC4461F925A14EF6584B02005E1D795ECFEF93312B3369C52A8A2ABF99AB5255E8E09C05AC722F37A5E95AE46B226C7319411750562DBD0296F0CD1326055577BEAAF270E75F4433D5312038854C30AB23BD51F1246EC46599FEC1B628137A73A702606112CF61CEA7C3977BCA6701C8E5F63132C15EFF01CA1EDFA5CCA8FC0E3FAD392F21972F857B53F62CAF3BDB75D556E6857067015E11C5E217F5D1C1AB1D603571F9EDDE04499E23D39DCAAEF16263A5EBAB9BEAD8F61B0ED942EF261E0ACD309A903E73AC4E4569A65FE6490F6DD6842812DF61CD858D9AB54D3456C89CFEDF2621426E3F9D13FB94177104F6EB4E30B018C01F78CB4FA9C89F453B87FA7D4716B96B0BD2DC532D4AA7D8FB9D264B095BCE39BA017E8BB90D600DD2C58647B9D95F63783B4B90BDB83A175E5201784AE000A493A387E16F5F0C5CAEBF62A360A6A927B3FE4CBFD310A3163BFFF1836FBF9770583FA4F88E5A6E7BE5796145890A41FAE8BD1839110EC05C325012E19C69C3868C7507D04458C074DB3440A0E018A23CDD32ED35E7A28DC8AA8BD63C8CD0A9F4876B56C04D5D3D5CE52A0601ABE2AD3CF3106CFEA6D761335F420EE3D277DA358DF4F6813D543424653B256E325346F677EB7F69B2FAF9536DE80E8EB018D978484509804D600783708D48C4F7100E0AF891BDFC75352C", - "93EBCDC22C36C3BDC8B579B31AD5F5C9B2B08218BCCD1B29829A365DF4A8D5259753381B6786877A5250DCE6A2B182734E363B39560D3DF44E88CD6394324765087DD1A77B3D8121CBA61F665F9B719E75B740BD930D6FEF316325B8B3A2FDD93AC488714AD9AB525248EF60B2649B70DDE6849BED793264062B38EE74270CC190C6A86AC4E106781BB3D09F0A6D7AA4DDBB0116D3452CE041BFF4247819FD8D78304088355D8DE741B1A6461C74A4832ACF4D4004BFB22F6C9BB397D7CADC6FC05AB74919CA346F9A54DBDA80F8E1303A1D43239C5DE043C2AC21E182CF49BEF9BCFC109BC884E41FE2D8669915701992200BCB938A745FB0994E6AD01187C4A24212DA421A178E42216287DB1F6A25E8370E4209E09057E16253BF477A061399AD1B3FE985D6A10D8B05FD94B67F878649862D68F285EC0BFC06B7006589A590AE7B116EFEFC871010993F4768197473BF22AD54B2A8FDB0BBF2B181A2A1CB9FF0D0989F2F68B339A8D8B27FE1781F3DD6F7CB972D73E3DD702FCD0CC3CBDF66A6237460E3B2F45DE273D2BCADB96C118DCC19F7C1E703BCBAA04DA5370A5CB3B78112B8E95B63328B43C51557AD84B3564749C2802B52EB33458394747C176E119E1774BC905119312963401C1DEE02964DC9F1D836069CFBB9B33791C908ADCC717B08FE3C0AE98C0D5DC0C22876595AF95A02AB33BCE3502A92E532E72D0E3455A3D7EE796B3CD5D61DB902B8C0057F2D47F2655E95DF55DA562F632A4F9A2CA8B1D2DB8F5745A71318C37043D3EB08F9950D06C1301F9E9FAF4EF560B238BEC483DF0E017E3CB27A251156221F183F3E9B0581838D04BEB5DFD9EFC26B979BCAC7DF631F1ECCB777E2617EE7386C8BE9834D26B96D80074BBEFE8CBBD203299AFAE8E6F90273B92182CE7EDCA9154E0A33AF9981B8CEC94E6A7C78C4716B47790EAFC771C3DFDE276E4E617CC0DA50F05099B9BF587127D1D18D5F892E0090C8D033F21E7382738F1EAACFBA493D776821DBDFCCBC24B1D5F877B157AE6BF6D307AE9BA54CD053E68594505D038747A7D8450EC3CB4F2E980C5D97A2AFB31147906CFD3E9000BF166EACA8D16A532BCF69526FB4B86B1F71D2C5F38958EB11F9ACC438CCE14E88A11DC431CE4E20B99DF0ABDD2B5AF358260A64012F4A408C6840D365AB95167B54FD479E8527B5FF662161F75FBA7CF790DBAA51613DE7C52A2A94E4AB78E051F32D10233161A4EBD8682389D091B5C4509171650ABA574F1FE954698268450E11D2FB52C1AB3E4DF426D26DC6D5319FB762CCCDD552F4B1BF4E82AD1F78606C644185AE87827F022C9508805472136DC48E71D1C45944413485EC1CC72BC092D6F9990148E12C2A3FFB3D8C9F91C18CC9086F176733A83F2CC9BAFFBBD810A99B66DC3B399891B2045BA402749B55E7E363F5D062427A9BFA8B599367F1D07A38DA16074F75A4E095A528C26DE4083B044055F73D207A6571196263D8BF5A53B7679791BDE49E869F0F58431829396A34415CDF4CB986281840BC48857361281CB4BADF8FF5B86ADC76FD3A812D7641C5FC88A21F137A6980B42FD3858E2A057BD4D3FF57A5ED3F5C41C71C70036E1762C0079DEDE282175072A073A90AB83C9DB447AC07E6BF99DB04BF276FD876F4E4816B0294333BF3403DACA2077BCAC3889B55E76D62F58DE7D1C49816D03DA2D492D1F3CDB2B6B186439CBBFAABB645E9745F404538BE8FC4C698765A3C67D01CB54D404D2A2E78098FC334F0A375EB41C3031F57FF9A773612445AD3D98BD09C949616D4", - "5D55CEF58C74B4C681E813564F1903FDB56BE053280D438BBE5E2480CF279CE47FBAFD179E270D838F764C2E7F496AEA9C0800056F2E0456EAA7E59CB20432B65875455975AB37186D6B06FC7D0BEE743CB974DF92B19F4D2EEE82F36598F8E400DCAACA4EEB110ABE352D3A0F58DEFF8D51DBDCE5C23E84D1166FFEE5428541ACA407B9578E4295C3F79F9376384B630D25F11271C6234B9AA9C1B4C8015AC2C73CF768B9EC30C61BBFEAE1426F72FFBC995A834C9D4FB8350C301133F123313370C33FCFD711D1847CFA84E782F4B39762A02F9476D5F45237A29E3E269D16DAD60033E0907D5431C1CE36D37BD388024A020B612E1DE42492A3759AB82AB393237F4A1AFEB8217D2733916B7B610342C0D182C17BFBD4556B071D82E6C6E554F2127654C15671FA1A843347BDFBF9498C7B5E7636318C3EDBAF7BC4BCE123698A05538DD5D42F01970A41A75F0A46E61520911D86A39D892700AA23A033EDC836EBC17CD2EA274252F53A4BFFD5CAD88F8066744C737B364A0DD0B5FFD96787F7D18357DF728FB66B212DD4DACAF7218292216808E7B81E3514BDA947E436A301C4181CE53A298250835AB98DC89D0A3D6240C57C699A5BC31EC4CBF8C111149CF6802942256520BC7FA22968556E2B390E63C9DB7D0AB79939924ABF068BC3D44264D607F088A38FA67F8E25933091BD3EB0A3590F3E62E63CC6C66AF66128F7C3F97B76E62F1AB82F24D8C147FB2C8BE207FBAD7E5CD355230EFD48DC9FDAA4FD1C970781674E901D35D7C651EEFEE2356F825ACD348FF0FF590E8CBFA0332F77A063581E6F19F53CDF1BFE952585E93EA13A83BBAD06070850EC824397A9FF13227F4C60D65B67AF810EF1BF5D5EA95A5512F95AECAEFA25BFBB24CBE6785E91A4874E81E465AB91B1F2E990F37AB145645F2681B47592990CA78264DF8902620E796D4DA9A260D1BA67DF9BB0292561FACCB2478AD7F7D7CAB3DF179897596604F2B0F1E3F10CF842C311F49C6B5EFD5D73DFEFF59127384D3B4D855F8C412E949E3A941782C186413946DF8AE33C9640704CB0D930C12F5FA1C4CEC5883CDA699E294019562948AB028548FA974D6C56AD667023F9C417F067810C4C7E4A712FC3417A92C075423A57C208AF683DDD695AAAA5F027CE535412DFE0029B292D32B2366DF978294FD263DAF8C6A6F7CC895BEB1437CA189C2AD9B6FD5BAC06DDC3D075DF55BAA6E75865CE375DBAE862EEB7A51D0DDB5DFE03234CC8F14EA99110DE78A3463546C6CCE5F7C623028134968C59E247E642CE17D8933B6701DB7952FBCDC6CAF7F2FD24A241D82D8BB1C0F5D55BF55E57BE4AFEB4200C1C57938F4A6B1BE9AA02FA86AA811577BCF1D6BE545D6F12046735AE963DC7FDAA9A2F7270B8BB37B3BCEF7C73F59013041B6CF9FE10FAAA86DE369E868FEE7A37F62E2E9CB1409DFF11FBB09A76AEEAD0F8E443582319F6F74ED0AA3229BB7A50043636E881BD139EB7442FA35F5DE1D6CC227B921A1343E34030D2F1F361D7651C487282C907577765161DB781C49655A5F87BBCB68D08C04290B4A2A94B61BD0C7CFA41821B7F5641B899E90DA026290FDCFA4FB956414523041E14ABD7B1AC7CDAA1148A03B6EA17C49503F01707BD3373EACFD4E248BA0F8D4B845251BAA35D41DB186E10464F6FCCD2CAFC9CB06FFE9DC97FF41E07084B00B7B31FADE0E093C8968D1CEEF9810986821F1741F11A71F5F20C809F54852307FBF33A6C33C6A230EC7CB2CC6C44A3A53AFA49477037E55BE691ABDF6D4A852799453930A4", - "B19B7C4DE003906A0001E0DEEF57CFDD2B50514CDD6F57FAA2859061678DB9F8B5AAC67442D8B737F635DC297E3A46C34735AE4D2C607B06964D1FE264B7786B8B0604781D4814E2A81F3A0250D4EDDB77C121B962D0E7109A738630557F5AD47F95A0971A58704CB5B53AC378781B48D67FE5D5349440261C58C26D9370DF37255CFE845F7B0F735CAACF4921CC9D55B3431C6C888787D7C2B436C9DCF1DB94FF0D510BCF15DF0DE42AAC7640741B4893C960FADDCE4261E6284681BDBFB0F471C864FD560DFD87DDFEB4EE7A1267E285BBF2966F6A8BB408A105034220F2565E38F6A15A45B7FFA82DA63965BF44A182FB4672E90BA7933A0120A449323340D0368CF057DF299A8CF60035170D197104B394CA9F2A05983980A1BD93CF3AF8799E613BCEF26234DB2550A15BD53FFA306D3F616D78A6204AD1D50FF4F9972B0CFEB48B76516155791C14E0C9E18457900CE13F672882BF423400D2E6FF94CB16BF3071F44CF2DFE8317A9B761FDC8FDE90D7D05827521B070492AEAC90187EE48D93374B463C3381C7D80178F54C676479BC92470FEA7069CBA95BFDAF099A994AB8244CA786E7767B8400464BD08D5C560D61F27A96E3886A4E821E0087E7A56F96DC6F6E85F1FDFB5C82FD7BD48B63EA794BDE01439FE4C3D7F08864263A0A8B1C1ADAA5DDE86B99EB2A619A12A1A76A39D8B1F04AB55B67D15C7878651BA1F6621658757B890DB0D2BB533BA1C6A5E3226DB4FEE7D561842EFCB5B459598CF5AD3F98217CA720B6781E83C2297C96F4F51CBBBEFA708AD4B3F682FA0C67C82A5F5797030E0724AE9715A911CEE347E80F774EC780DF7E2279924F67ADF9D07FE4F56DE99E06B58099E1104DCE62CCA82D100D90BAF44F26F19ED7AEDEAE609C04C530CFBEBDD161A2C324A382FC8234D405BF900F0B6CE895F9BD534A6474680A7D63C0CF7B4AF1D1E93958CFC02FB379AC09B205708A68D11683B9282564C06290F5E6B57E3E7A75D30C9E21DF8F27F85E1FF347B32105A000BC613006BD7FA6D845C8E6D4053FF012D0D85F99737D045871BE017D672C8FDEB16F944E3020BA7FF0351A303A0D3280D71CBDE42F55657671A79CA30A7A33E744E74B34D27453654DCC8E87911B3701FBC27CD16C4D9D6C29D1BB9AFCCDAB28DB6C2B42C5D6BC1D1386AB26669985B626BD54791930CED4A13716BC9AF8F4DC37A04184FCF711EFF515B92C943E53879B5098BCC4E87B98000BD0BA2E1CA3C7A97AC95C1AD145EBA3950B154888272A0ED49289157091DB2C55D43AE77FA3384BCE92E5840459B405237E194B6F5788F16B217D8BF7539EF8809FC7AE1BA931DBDB2A7D15F139EF4FDA60F02FFF9462777647D675309AAB8201B5FCC1ED7AE066FC0E4F32D260DD9406BCEFE7DC5DFB38D66CFA08E5CEDBA636EFC23B3CB7AC38FF7C390542C9814A86D2D8F676720B7E2FD93217F916F10FF34A1AF34E3B8563319E92A3BAEE34258B4DD63FBFED854E08B1A2F4B560FFC40AA1048F081E66748E05EC3EA02837272FBD9CBF1A658B86B19B7DFC63436185D02C6411142291645692A92E3EA6A113B5436B0BB78990942146956795DFE003A4AB6D9ED875FE7E5B895EBD69C43BB7317CA5C97BCAEA97CFC6068431B24673FEA931EC1DC1A3F72625AD531CD89CBEB0E07F47B26971059FEEAE3986E23286D13BADEA3585D73F1092E41AD041D59120D3D25FD3BB0AAABABA738049C91B22649E715F3710EA51C41C1705C4F1FFB1DCEC85F0EE704240EA8A20526DC01C7C8389B21DA979B99FBF44", - "5805FC5E7042027201F3517AB8BA6F5C3BFB0BC7657337ECCC99CA480BA9C3D36033336AFAC0BE172AF430A98D8462D46453E935805E594C18C0EBF735D90D5027067006193854E7DB6424688BD715A7BE72EAF93C2F763F3BC340EF4BCF90B03AF20C28A59F72114F693848289873BE3869590A64658C0A3938A414BDE86BE8DBC25165217B1605EB0402FED48DC09139751DC1DCFF532CBF599E9AA13F3A72142E05A1D8E47A4044269A0B414976670094C9785811628718C6FE5201221A5822E29DAD564B6EECF025DE7783B7842DEA40D4F72D083D112C608C596F25E09EA85BC6CBDEA39300774301C1C36790D7D9C0B59741F6B53E16BCABF8120112C81D70F30E44561EBF3A3A4571F207305BB3A292C46C46E285C246EE9A7442F869711F52D921EF379DF7CFEC4CE64BAE4D7AE7DBA3CAF47EFCEEE78B477C02550D1DABE4FF4EC67A38A705F60706D948C017E333B645C0D80AAC1CEA393CF3ECF711CA3D59ADD7CA02DB6C5E3F259B4ABC138D24C47A650EFB96AAAE93E69F08077D0CF38B230F199C3B353229C529278DB1F5846086BC8F5F54F9631423105673FE92799FFBE5DE6ED167658BA5DB5AAAF921926FFC27956758CAE8B2367E3C5C5C6CC81DA875AEBC8F3460275C4EE6EF43570B4F571994C7690DFDA3DE311F2FB77057732B19E6FFC96221DE1DAAF9B8CCC21609160457365877519D2B332FA3A85B9801EF435D04DAEC3643CBB5413A036CC1AA0968A40F4EB5A76D2D0C3DFCC53C97BB3896E855957B1941FEF59048562171F6241AF278F6D6B580B4C94C5CED65CBC0F810D46E864C2B567BEC920F6D1DE42CDF32300805E6022EF184B43C1733F809F98B129C937930B984F5539F574AE144EDAF7BABBF379EF1A1AE69B7B4FF9212BA817A4F223FA8B182FEA231E7029F80DB126641725C36AB4AE950725435561C6FE37F960E37927585026B8ADD92E4ACA3B4500F0CBE078680D16DBB90ADF6A127FBC7F791B4F93D5463F8C71EEC1EBDEECA881FBDF3D2940C2EA0F8E4DEA1074EB5C0C9EB34534C9C3992E988DAF8979FD8AA90F540F028708BC6D0EBBFC00FA946DEE5E9D01CC272A4FE61E5B86FF1347340FE64F650996F65E5702A61FB53EADCD457A5ED66DCFE1B019A79104842C51B60142267392DC51F86F69367C25B999B3153C1B7895298B6B1B43EFCD8CEC3694F90BBF1A417C48E5CC4983782F874A7C64E05BBF462220950DA9E8F56BA324002E91D934469225E57309C7F562407DB900267553B85C4314A63351F20D57DED0B3D210269B09B976C07878C324F74758D9D507A4CCEB4AA30CC9CD05CEF32F1174C7B0F7AF93875F66E3A7B12F163920825885CBE5092CB7728A1B74B2F3FA9A01264214761DC5101BB0C18D65BF972A3587F95B3E13F52EB6D1F334B15220ADA5A59497558EAA0F4ED358A995F7444B633FEB900EFD9528B51FD82F5AA30699900D3EA3F3644E4FE3F6F2900ED45DFD997FA905D91521CD9C898AF4CE09B6EE00A15057C17DF4C656E00DD876529CD75A169977962DF3F6E4CB6950BCA37A79C98F108AA7B02AA488AA4ECE05F702B468C20C81630F51F884AD74A76491DA378DDB8290ECB8F5879F019BFB416BAF1D9361126F3514557403415F286C8E77C0BCE4FDF0F4EAA96D19F22F189971155F749EC19687657B245D392BDDA62935A44BF6C82E0AF3593BE06745099F06DC4A66C0768F17916AA360988D5E578D169CA84AD1A36B12CA4929223BCC52AA9B47FB138E999CD6423D1171AD3BF87B5D405A174B0398A689DB4", - "F99EA1599DA410098772B05B5D7F9AFD485A04CA036BAA9C71AD5DAA3EA5F1C757BC83F3C0028DCB93DDEFFD157EFC2CB29C0F8146D6704D34091EAF1EAA29AB915E652309491F0BDE632172914C132CB9A533E97F89F567A7A9B0776B400FDBEE71B49AAAEAD156753F5BF564CACE2C1285C4E65B5D8B2803A11B22350ADF79645AB6E458B1C9E2031C4D4D6361F77B53329C3530F6EF727225DE668A960FEE1F6D7588BC126D0E2AD23C2ACDED06AA2331E9D0E7F99234A391926F0DBE610C600964E89BE1842CB1F1551D5CDD4AE3FE45B628E9A990C872622C9257BE40A8A124FFD6B135BDD2EBAC05E2DDE5B7DCC13C76C27C8A3E778063F3DBB3488CC52836E92A89641F4559F377273FD51FC45550C727689CA4D5CEBB26263F4268502658F40D4EC2BBC0DFD0E41F16A399F02711BCFA96C2456EB8A77FBEB852726B0DE4F927C13CCB329F8B9BDD760D1DD299863BABF42EA7D7F6204BF13F7355610527A38E89F66D3D73522B421AF013197D649D64EAD17F6A6BC8148D9989E786AAA94FA19077292015EF7CABA4B1545CA9CA20E5A816D6EFF7FCA31FDFABC611253FEE80FF0D75518001C2DD6C604387C2656E1362A3EFC1AB85461A5B55C6374733FB6B17090E6EC1186EDCE2C49EAFE84B139C66A2E8308CF2370095B0129B6CE7FF6E17D14F79258BB3E555EDDEF12E634A5AF748BA40735B90BA1E7DE7EA00D2F4A8B3BED32BFAC17D10050B420DA32EB6D14035CEEA1B7951592AD75FB751FCCF190452FA88AEF45080161C5544AF80FB0FF93C62B02B2E5D1966F77760D446F2625C3FFC91A07A5E852BE406F1638B521579FF299227769DC4B88A805E168F08ABE606B5D745433584BEED712453785B1C01D2B9F1020BDB7EF11936F0BC449EF26DBC2D5FB35A2131BE9C0DE2746DDB6D0356294D0E09076C9A77A076F6B659B7B4F54A06BE2F353A3A0EDC6A5123598DF9BA1CA852A5D1FA16877A78D88F0B367E6C4471758F0663A7498CB1C8F13B03F0E2A941DA89C717A15143F4ECF594B0DE2E43B657DD87E4BF536ECAF3820127B1FBBCC0BF2E53B9E0E1CF10191BA9B43D4D33FAA379B1B543C593F1BD5CC05E0B7511E8D4925BBFC5923AB0E2FA90D05ED580F56071A62A334408D3C454C892328AE1DAF16CBD530ADA7B858DA3763BACBC989F056EE1D46192CFF6DDD7F066D2EEDCEE5BC6B72551245EF8D10389984D3B3455A7B9664475CF6B837D72D42E49BA2F61298DE9BCC707209D7F1E56BCECE1B21FDE69293D2560B8940223E0AE966459C249751A2BAB98323F184532F4D6FA396D5C0AA2A4A41C75C638DC3DA5822AD7D3D7D51FE0811ED3673D875039D3625362D7D00356E8461FBFFC49FE1B0624F6D30D550FE1F5FE4211341B9D57D210237902BB7C62514AD872C1CA87976809717817AECE1E224733079478A5DDF5F2A067DDE111A3FF911D0B511A6AEE16046039B229C00D6D10317F66E1202449DF20CF28BBAB4112948C65DD7342D09059EE2701B36E2ACAA6A9948F818B61B9A3155729EEA670D4AEDD6F0AC314DB12E0DA62FBA01D419F7C48B09BEED87F7292FB0315A597CCCB7B51AF776509818A73A0BED7A656AEBD7ACA2646605797940CB737548E83653E204B6A7A5AFE2EF16EBBFD73484314C5699EC8D24E899BAA0E202F37E3C8D8B5F75ED34417E608EEE4B26B453C07DFC6E62FAC215B6122CB14A07739E86FCF816398DD49970AE8A216BDD8C4C478647A8D07EE8BBCE6631C22920474154B3C83942C842A728EDCE7466565D9A6BB030CE684", - "B23CE558D0DE0D584768E83A066B9BF6A12C78D173AA3262866339B86EB8A8D5208159C5873CB29E9C4C0BE918CE4E8DA85C85E070CAC29850CDE48E2DC5E0609F419CFA46EF650B9022273AF14BD9EA28FA856B7BCB580D8949C1F732F87EB34BC1257205BCB6820FDF3BD1E7B9C99E114B3C7607D01235E111E3AB1F30E8A9311F0F30B601C833FB0D8C4D76AC1B02F85E93D4C3D0205F735E20223410CCF56317B6A12D07F3BCD42D2023BA0676A00E7268733C41C8C7DED2555FBD2BE09584B3063BE41BFE93340955788603F1D52190B35FFB8148CEC733CFC1BA49F609ECD3C4512A99308043F3C377EB65870535388376C2C748D18A748F5828B3362666C49F803828B4A019F26D6A9362726E32B650A85523484C4BB2ACFCABD16E754EECE0466D1B370175C37C8CE9DE236FC58ADFAB4FAEAAA12E048BF40CE084467C8835A1E209D2CD67C5BF01E0D62CC78A12130F5EF2E3CFCDEDF86D489C4C5D9AB99484CDD469F2F8EE5E14BE43B9EACB92E72237FB54F9615627EEEB193EFF888AA0A908327C61C50D20C613C933D736F6C3D7F60969A5D3770275081365BA8A57DF600F10A1652167AE3E18AD3715532B7C4BAD97980DFB0C4F69D9137EC7B21BC72AF16F0BEC30B94A4A5C2F55074ABC6233CDF4D8D347F4FA942944D9B2539D0211B24E2C7FCB56BA877371AD7701ED087269DD643C4B62E4B40D3F6572C0730E465C5ADE50FDDD11BD30C07EFF35AA6218D0B73B22095D320448E0671E1CA59BFD52A517A50932A06C4897BA6F7E7038A39C92C20F6DB18D6F6AFB3563D10BDF48BC194B79FEA6861F1CB9756281E969968B65161D3980C4CBD036467850EDE9397321913D57C1EBD7743A44A12E8C85F8D2D1EFE2A8754B5ED0E93EE9649C53F28129130DEEE66E58181787137B262E1EB3FDFEE0604ED1AFC798B198044DD5D0A3E87A754C7EBF0852953ACF3371BBFA0FD5979901252EFF69473FC5655709EA193DCA2A2BA63D706C84F49802684F80C576706FCF1BCEB2892B9179A72B7CD886AF36C7D3ED09270A4077C481736BB69A333AB4BD864AEC1EFA944A591608A2469C85AA6431C47F657AA9C2043F373A69323E735B56BC8177E1E37AB03BAE93A7B304EA1C5C52B244FC265EBD674FA7F1647E29CED527FCBC93CA7A56A4E771D7D2E576C40B2EC736DDBB4FD7411168C5C568C446D1E454249E6F7529AD83215EDB62F57D25272F351CB2C40965B1DB65EF5835923EC2D2FC7D8AD56B67980A3DBB77E6C4415F54F3FC00A790DBCF39A2FB699A20FC634F1B1C177C37898A81D7693B21020C6B592E5A6359AE395A841B434B675F1C30A9CDD0ECF987ABC2406178EB2DE941393AB4F96BCD43626978AEA548173413EC9DEAE7B53B175AFAAC5A1E02D6EF7E27AC41268C1FD8DD83D1AC55ED45D087083C0D136048B7F61EADB94C88CBA5503000A90F91A39A8C9E2DED567F7FA0DF605AD7870189600B941B99240A15310E7B3FCCF5ABDDB56D50CECC06B4303BA39EFCAB2F7E9F5CC8F542E96034145115AFE3788DE0A4985EE1929D4935EF975E760DF7FED8A257718DFDC5A0B4B87024C59DCC6FEF6F2715582023C3C80EAADBC7AA8712FFAF80CF5E159CF5418A1CB50845C97A7F19DF3CC5FA344562DFDD819DD736E9ECEB7BD57AF324256934CE6DB0CF295AA0ADC5931D339027CCCDE1441891067DEA40F69F6EE07187F9B78DDF6D59CE02EC3BA6DD68F06851B10AFE9672EF84020CD53ECA25B3D5E527405AAADF60593A8080373A387111EA898499F096FF46FC58", - "8515E8CF42FC33A8CEECBD6E1B65BE307A5BFEA9CA59FC51A382C24CCCF012C38DFAD3FF3DCA3180934DD6AA52D828439F1052A959DE23BDDC3EA3F2E8CD70F7A765F77549BDE6CF8E444762DE51CBA3431439D1F1E42F1773FCA2F90E48126A000E69C0964B1955F586CDE1895419083322FB4E6528F61768F8BE4CDCB37FE9D02B27193A0BD79D15F3CC9AC6DDDDC82B02201BEAB86D13EA560F7EB5328AC0B534C52BB9D266F291425EF1607A19AECB9AD681815EC4FD1888BF5449421D92E473C21BD44F2C419A0B3E0603EE3C5C82E56466C5A76B76F81A6C394BA693991A5808334EFF1E996AA1B1394A4DAAE00995F02E9518053FC744BA391214DF2464DB9F01A5A53870173B3E8FB6B9B698A8DEE80745D7F71B70B811867D3513197B32115882348FC704B2AF8BD6FB3BCCE30361C1198B84865162734719D88BB62B7431FA39D452E0A1B0A7E45534BF76B6AEC48DC25B7487FEB4B5FFA9C56CC7C83E39AC196987747D664943A600B106F0C3D6B2D0D4425073EAAF89AB33BF6AD76B151CAC32A670A2B03BA31FBDB48B949D3074CD9F56D39553708CB0EF2BC96170E2FCAA3CB2811EF1C67FEF6FE85CD450FEA37A04A07EA732A696EAE8E76D497F5C350CDF72F8970FAD94C03909F67FC895785D5DB6C3A68641D68895AC8544C6A1096DC4CCD45A68BFED7ED86961B5E035E61E9C126319A7B3C1468457C423C4A4E2DD1D42BB90C8BDE2A162F999A8C3A99BE998B9DB7A14C101CE78F08857ADD9A96059DC22592B90488D77D6F0A6D459CA65FC947D742714A42277A79745C73CB157BB825E65872D9BEF5066C444229ED1A097AF6B0308DF2793A2284F911C764BD1158742EF4109CD8AE6111DCF8A40BE03409FA6C430829D0C9BA28B466916C67311F8BAEA2D8CD2DF9C95094E4FC6D43F4491AC5FFBF05BA6B7DB9D7FE4A6DFC386D136B1710DA5F30E67C8DE97A981895476B8E4E0DB5E1AE630C8034F949AA4095DC81EAA0F645B0B440138AA7C5C7C5FAF3B57E1504A5FE477CD61A355D9AA66C39FF89E2DDCBC1862E19102205A9F343FAEA71D4C67192D4D5A1AB08BFADAF6753244BE5B14B1F911700B4A947D53645DCE170401135D0D7E968F03A9B19D2ABBDC94BEE623FB64C1DFC4AD9040197C319A79391016D6D44B8EBAAD5B2F1AAEA58AEFA21B5B3D9ECB66B3B70626AB31CEE5CA759499073B4FDD96457392E58C0EC871B95C7B77F74B81C4CF5B1B243BD35F4D540C1CE878E80AAFC635D363B9D72DFCDAFF62FA8339BAFF4DE1EB3E146DB93E7E444403E0D4290AF501C841B66302A345F5541B1C797D630B5B7E788A793192CE1F362B22B91A837184106D852391A241A903E3BECD192C4FE52586BA4044C4FBDB20B711D2624B6CC13E0C5EF62F2B2E00CA516991C7572732DB94DB809FA0535D2E8376685506186170E3702903A6D08996BDE20F74BEAD391245680A029FB439FFB96EB829F0BFE58A6446B00B4E1894BE1B5017F706156072E2DCFAB25A3BED2DB310DA1A7262ACF24A65F41FADAE3F81A32077BB9CB64AADCC2F92B95EE56F20CCBA24DEC9F5F75B36EF1A101D0F3FF6D730DC199869F8F26DEFC6F51451BFEA2C0EE77CB17422E2790A8B29573405F112EDD704E3F46C7CD8ACF0E495C6BA9ED448B0B89A9997850F09A813FB23788681D3CC04996E931CB00A879E2FFA1BA6A63F9D3BBFC20405244B0F838A040F125AC2B4999A197A2D53DEF8CB167FB7E37DA3862CE3ECB57B081DCFD98894E45C6019B9229315108E37DCFC57C9F80201486AEC", - "4368224792A5CD4ACD64D6956A334DB4614EE5EF8F98EDE0B4A5CD3D06819A4858EE0037DE64ED93BCC7FDB47E90409638B3789BBC63134308B972765565651902A9CAF4F310E93BB08EF1E4B325D414DB5DD7CBF660A880642A27378A7427F2627BAB3444149181C54E9D3FB7967DE33BED89AAC255A47482835D17E329ACF3F08F23AA1DDEB730D9602243A6894989EE2D900FF6AC0579864C2361EA56CBCE2F39A75A12100670AF3FF1A36E98D1931D17CA68D8D031CC527EF7FFFB35AD6E046F4AF1B2B3F66210D978F8607039BBA99AFBC6A499A5A948C5C59055A140293CA97306BFFCEE37CE77C114478D0F73D1C8C9954780830D56878EB786967DDBC71951ECF815CC4266D66F84195CA1AE0375E90017FA5C66DB8329D668BE6C0BFD85742088B7A3256A3277AE2A1F4E72BBB82BB2A59B08FC59FE5F24EAD5DF43D95917A144B4DC6587C893314D5C2C427EA92D02E6922FB0B60ACA646092E0D4A127799FEE4B76587F26AC1EB89BE0BA46F2A212ACF50D93D3345AFE72AEDA1A0F855C45AFE14161E22DA3E223CAD6B47E591896F4283F10C4073AB524CF5D0ED88F979458BB928F1C179E2C5914B4CC52CC000383D154830A54332D4C0E652F98B91BC086370B04CCB1AACA56C9A33B9F0A65C33467BF45C74905B67607B83FEDA063857AC4E326B4293483C8841572174CC8A384014945F5C3072C5575A5BE322E3F2FE3A7E30F3F21118FDDAF23645A40E0A359A3572153F5C3ADBE1BBC4EBA5E063E9F73510C5D1D4326D3D7A20384724279C3B4795C68BA332EA706E8127672E41DE4BF1E8B5EA60B39CAE2C3B7B21A225115BAE051FB0401A69A7FC56AE4B7E31CE2CD575D82C8279E8B8499EEDFC134503E6798056324B17B8AB045FFDC2A35B190B39FF212C17C36537A1F99F2EC3A4CE693DCEC7DA80861FC6F3D064B82CE5581F9781289A085A300CCEFB6E80A86D961408250846A374ED00F5379F446FE6E551F608AC3D71346B738C75DCDF63E19EA79AFCADD5E1E07E2F7C0AC709F6428FEA1DCDD835E3F56B026CD8DC9D4629AFDA9015295C2CE55DFD9C83223821682B5AF876B1CE156343A0F4C1655448FEDBC992602BED5DA4B299B86EE2F86D02C757CB5696B32D60357B21F9DAAA06EB3BE2E9117D2C99DFBB5328B3636F41A06A020E3CB47851891AC3825369C037B0C0D8412204FC3D5FA9585F3218F01295375A09463AEC65F591A594551E19DD00D5738086A31712AE9FA7BABD4E9C10E9F4DA82C12EB2F3319E852B96E61EAD2F85BB6765DAF874FC8AF42746F14B8FA489DFAA9540B4D0470CB31F99B10C335F672C2E06E8A2378B9DD28E8F56BC7A4C017327404C79F1E8E67BCAEB5C4C793C176F0A3C1833007FC44103DCC6E273C9FD1909AEF1656E2B5756B7F4D69F4F2EA576228DD794777BEB2F34296691A1FC38AE44FE60A44AD894CE92DB77FC0246C779C13E8AA16648843BA68CFC5E4E02FB564B0ADF3163C5E167C275A8C15E58659E2F70A3AF792565422D3327CCE25C9D488EF3C32B195066BD27DBD44EF1A20AC6AA22250BC0592AEC734477E1112DC3913F6B7CE323FD1F7B3F8299B8C9BBAC23487F735070AFD5C3627506D4C96B0A1427F7EFC07EFCC62DDC5455A77B57D3FD0B8CAD30A346F8C34F42D87827FAFADD54264A323907A89334C0E7F98AFC9060D7767BC9D8D261BC0BF64FCA389BB192A9B4B00CB566D254CB0226FA17F3BF21E2926CA52CE5DDC401E74A92C7989552CA66675A9BB9E9C198BCFFC488BE1DD5E47DEDD94015BE09B44", - "30F77B7E7E40E42A52452A26283CF3A29B02DE3398DE5179773F2CCA4978059495B9DB13069B00107462C0034064A024DF3AD33C063F9608783E79E38F706B92AB117029EBD6156CB5D278149875B95AFBE877A21AC3128BD6D0B11D31DE7A2BF7CCB68911309BBD2215F592D56AF0F700D962E49E4C6D089548C7587B0598374C3D7BE80F7F20D6855AA28A27AF668A8AD3552CFDE3CE0B35DCEFD5240C8FAAB89D013D0DDF5B66E60328AE32BF4EDB8021E43762E96E5999CF23BF2457B1CD75D1457D4926E7C2A324BCFF70A7CF59047DF3F08EAF2922CAE6A7BE1BBFA3BDDFB864AC965B7FF093CFE74B53DB332B411962DA01D4E6C62CE6731E893574A097328CA7606ECF373CC987F98C31AD74EB4A863084266869D28C07F9C5B5F10385EE44E463324A81D523DFCFBABEF20F3F71FDA33B7EC1B2A35A98F01D13693CECFF23E00CBDBA2A2D09C8A86A819E82D781AE88B9F207889EDA1EBC54CADE6A69A564ABF48F950FFBE7A86243C544A78362D9BFB6CCDF20CEDE386B9E3F8D7EE0E4A58596F095AC1B99E4F787472A734252D6C00B177FD2B99A85D49B9C0F32D728F7D9BA4DF96D1BF6C365F5F4EED7D38727B339A223263B58560ECA6778069DFCE48703AAD1BFAD59CE298C6BB464552408946265B1E19C1FFEE000771814FB5E4688140E1333B270F05EC9345E8BDFA7B412F295AE3DD4DBF33D6D2D62582887D4CBB9EB55F5FE3C1BC32DC689548B66893356704968C143AD3CC2E48BDC154620ECADF336E218FF1B22521D183EB2D13B15A15D39A42A25B46F1AEC07A14CB805AC382DAC8CF96829B8F1D241CF5CDE5D849DEB242295D7870432EBB642A45A6C6F1C2786B88C883B9B47343E822978155D079AD9F6C8CD4A21479B32B2112EB0121C3C74E7C23284812F74A2B413B9A18D6372AA3E09BB04A262E7FCFB6FABBB074C7C603C89FF607F83DA32DA50F2A19C38BA0965BEDC7A961966895E17A20A4D8028FAF7B6947A1964601DA45643C5FCECEBDEAAAA83EA5420F2984CB606E9F3191EF323D644635EDD801130893D84DFB19E661E04188C6CE596DD38C11D1CE5DE1EDE0D15D8FC427842085D300E6801CDE02768E44BAFBB302684FD945C9AC722561B0EDA92E8D845EEB99F6FB1889328C74D6D9CC6DAB59D55463A613AF33226660C0C034B896075D9EC2F51165A754A7D2393E15955BE327587943ECC1F3BB97180E751941728B94948B6648D2C606D66B9BA1898FA28EFA38A413B066D715F7DC5F0C755B6A3126AFCB606EC6B12E332FD71E386ACDDD1DEEF1533D6386AE5994BFD857380874B14ED836D9DED47DE4760ABB05E80DC622C8D7882CD74B2720884DA747BAC3ED9A6EFA2287D5F7D6AC7821E79C79EAFE7A68D2543D7CDDEDB63A13FBA4B894A6D0B3E14C44876364C9FCF93DC066CE953E89851A49B6EDB38661C9316C82ED902EEB894321C84331F6646A5C1AFEF832F38AFEAB89D181D3DD1338DAA236BE0E87A6381D00845CCFCF4DBEC3D41F8AE1E6F39167A499945DAFE77601147EB29804A8B98E7EEB31DE20C84E9148BCCB15CD02D1E3B519EE0A2E4F70F57A69281E651B189C08D575D52E997E3A435B4CC86F938BC79EF4961CD03DF8B92A8C507DFB2DE4D5EB0ECAC2F3D712A46CD3EE01B8D4DCB845D23E53A2E01DF3FFA100078F7B2467A45BBB4A18D14E0CFCD089433959F07F6F60F651DD7FD9828069D340D048FC079E4F8B92824D54322611A3698FAF181008DB5E3E327EDC431A8F6E481484BD5A429D0F5DC55AEA8A18F719A7865B0", - "A7D629A25F82015CD70688CC461244E4AABDCBF2CFFC2D73A3247F4264101FEFBD5759FFB83E8ABE9EF5B6662DA3CF7196385C05D0E5BD50C71D3CED424AB805AD632F2C1930868ABEDF493BB4E3A9DE538D8E35146320EB9F5B71C40E6F32E9243E6A25F503B68EB484ECB73C436930F30E2776D17A2E5F9CAF157F368E0FD9C26A9E9AE30A30E15DDD8A56482C85B46F973D000292CFCF0021577E5DCE8220353E23DD8507D0F561BBCD96F6FAA451E9C595E00CE0F99C8C40359B103D621CE0C837A3D1598D814BE6E22B7A509DBF1ABD2EA60955364791A5910414646F9928B5676ED590F41BD128A55549170211A0630BF5C5BEFEA204896C7FBB40F0C72E40DF19C95F3A0ACD641834E5BCBD26E91315DA34708E2025E0B7D38F9513945DE44AEE57077C8CC32C707D9A39BF098E4928420B3FDE8C74F39F81790D827A628B8F2776251F51095C1193B2FFEE8C93F49DF6D4E3C2E1BDA52F7356394BD5A675543493E04D602F332761AA1D57DF3EF8213E4E9B8D4BF6C8BE8BCCF661507C394CC9D5E9DD4D81DEAEB6D638FB9225247818710E4724111F522610075AE757AB5ECF6FF32CF087DEC9A04A7DAD8C613B22F2AFD31466574AA87CF0B8545B38C53A8F4597D5F1BB6837AF26114D72C609B624252722DD867572D449ED7C170F99D4ECB995B76C8DBD14F50F3DEA077FBE4F838A03AF1DA6757C70C5F3394092D7EADB1E0A859A8487F70D9F7EE523AFCA08DAA5F8E9260D63330773FB7EBE01373C3719129E483DE3D132697EC4C108654256315A38D7060C6F52B4A444EF33E87946C2537A3FB3B5FACBB0F3292C7F2498F0A11509FD9678CC7C678D4623DC07D8F218E4B65F2EB844D24D696A31483E1EDD1063AED60D7A110F7992E3E46F8C7D5CB1AF02D598440D79D649AA415E5F3ED033A8FDCADF8DBAC48F9905BACB37E31ABB0174CC08A9584E25B94423BF395E097E2D0B7ED76B55C6231F180D1A7BD969F6B874B9255138A1C3A2847EBA159C7EA281433A39D2F88D724B6350E846B365BE838F25B904E7B02B12ABE543961D33D991D0DA93310CDDA1EF551D7B6A02765DCF0D870C2BBF578BF8457CA1B599D0FE445B1E9C39E9C8756EDAAC6A10F62C84F60A27268FC5B436A323AC5BF4A9ACFC55510558C5A354D96A5D74F69687385C123C497543EC14C40117ABE46C22FE54DC4D2D6F4823A7F3DBFD3A1FEED428B90945B8F6B2C9A162F9C0287C758603E2C7845A11DDFC37B815A62A1A665C3FC003DC9F064CD5D950DEE02F48505CBE1A1E515E6516E926FF6DC0123E1E4F94587F1F1568DFBACC3728BDC1D153196CD91D9F6DA84ED6B70D0DBA7E7DB4A71B224E5122328D1DCDB9FAA98E88E9823A49E7560DF822D67C908E9AFF7D429E84350163E49AFA4015337532B6E928BE2001CA202C5D975A3E54808AF8E110575AD5FCA28185B2A7D8A3019B97AFBA933BE2F9CD5F279266EBEF52E0B92114AACC30237B712FE53DB1B8596CA72DC82BEA99DF8FE845D390B8DE1C00F24D0D9C619651FB16A280102CA8BD7FC3F7868E4649C636064F4D0EB06D06595A0023E6C5D32654EAB9C8EB011186A32C3E5DB9BA6489895FD50A26CDF1BC27D599F7A8BD1922B30187E0DDC54AD369CC61E958661C4FA76054C2C6658AECAD7D0AE23A9F36DB1B0E1141ED6A1084A8EBF8975325A1DE4A679BBD0E022BC35A07B40C52FA1B0BCDFE17BB6EAD099088963D7937CFA5B51ACCF722FE4F9DF99DADA8CB05C17B6A6AE884F1C7DA09049027D6EA570BAA064736219CE1DBEA7DB0", - "9BFAC777848D427BC9D39876B843378E100DDB87ED269AA91097FA433CA7EEC7D6210E7F100C449876F83439E3E494941D8CFB3E11ED7AF04EDFFAD2729FF75A8FB14A9BCF386ED8D95C046A326A9A92D3F316C758F6939F14BC88789B17F3DFB5AA691A872CA44E908AB966D5F672FB90196D71136ED26591404202AF5858D44C8E0B0ADE3441F554040E458F5AA64AC3D5B32399E453FA1565F4E71FC9EE5BAAC97552AD75D0154FDE48AD914F6D59800A7FEF91BFB6465A296E217E554631FCAC48FB7FDE1244F00697C2155A3161169225109AF5AE218D51D70BFD452433BED94FAFA5920B35353013BE2CD0C32B8AACDFAC6C6B4CCCC2C222AE845FD76630E963CA22F5214033FEDEE3296112F9C127865137CE6182BBF09D1489A1DFFA82D9B391A5AFAE6C80414698703EF03BA42893786FB10C9DBD21E7292E197A2959D605EC466CD202BB4E7BB1E9D5B9B3F07F55FD8637314E3D68C763CBE79982FCCC0147AE6D4C96F7A1C251BC35D8EE3A4F6FDD9CEBF771878B80E3AE481619D80B7BB7EFCFA9C20F11A0FE18505299EF1BB195EC7A93263420D183BD89335411CDD66B4809BEB30AC649CF76552A6F08E9D77C2E9C5AE05FE469705E2E6F44485395C054F401DC6CB9F581E52978BD93CD927D47472DC52D81960F98D60A061C5ACBF9F5E4434B31BC3C55CCD71CC2F2DA6385A3D040DE8B8D5F5CAABB6FC301FE3D5DEB95A00F01772505201B33464F2BB1D45A2F55EC907E86803A94F9340960A5E99C727517C520D338A41320E7E8BAAD6C4470300DB904B1848AC84F67F67C6BDD6AB71E2531C5C662AA9DCC2E84634A5ACA48C5A5CD1CDA454C6689E2484274EB1A2D1CE2D94876F4978987331D16AFBA205E1D81CF287E5E59A6DE000FFFC99E50B0B124E718CAC8FB51A708B42C0FE669894383C01D020E45B301DB2FE85B177FCDD1A688264A0327614A4483BFB689DAA49E8F59BD2D3943BA06F39119D46E5DCD0DEF78BA40798384BEB03292F231A62F7B6E456F3542425599B2BCF96978626543266E8AC0426B3C4346AEAA1E2FE20B54F70273A5DEB9BDF92B8B4DE940C48963DDC569FEA89B4A6940B7644E33D105C5BDC61C3EB7D823D4CF3FA0AC7196D6004CF6654BB4E4602974FBFCF6E74FB58A83540254EAAA4ACFF41C5E1481B2C38E7084B944684B21B7C661F92A28508F449D8ADE8881D40AF4A161A08C5846C78FC5C562CBD36ACB83284223B2891F73947804B6AD40BB99A4E7D9ED1912448C99E5B572760E53DFC434D06DCCA06DDAD3BA09DE063378A98943EFA0CD3E75B1B860E8D1350CB920BD6FBE30D437B96290F49E37BEBCD2FF9F8A4BAC7CF8F4571DAA9E788A3A411AE231D369D35055EA48D03AF54D968EB71F7BD14E51A1E617F81B492FBC3AF3761C601CF108DEA9E198BD1B576F94DB9A15975CA55D356C209E5CE1D8329A5D353223AE3C5C9BC55468AD4C2756BB54B6FC66FCC3B0BBA3962EFB4ABA17B1B08B01C296A578D5AD63F605BAB75C90924AD456D53CB72436F3A2086EE61D7C3479E0381A52715292DCB8CD2833720572A40CFF97928D4EB54265F3110714C360A0479AE7D51126C5CCAC09372AE7139C20C46AE13E4C41E89AE12097C6A198A979DCE9FCBEC5D1AF9D9189059E5E317B77B6E98C29F38E29A35FCC3BEBE3ED0267C5503BAB0FDC46C7D89766475F2676C80CBA71110F815A84CA7EF91ACBA63AF7933056DDA345D527DCB5549C9CCBD5B201BF9D0C82683A8865DBB4DDD057002025D088B7121C118B3A6C901BFF83DC1114", - "18A25B1D741562F456B84CF500F138FBB34AE1D18E9BD6FBAD05D0AFA14BD1FFD10334E6AF3ACC7AC2698BA10465ED5EC26B13265E5ECD1C79359095F36B1B5333EF87E78FC44571ECC00F294243FE64C4BD7833FED71F3B6471ABDDBBBF4C374519D24DEB11A8D2EBDEFB8D2CB3BF517AD92CA598040D0F5F8E5607CD879C75E15755087EFF796EF432073AB647C9DCED072FCC9DC74D78326EEC1BDC9CD3272180E38DF556715CD1D37DEB8B6BA06B81F01C26A3E97B9475B688D32BB642EBBAFC4406B7625944603FC085B38E5E4C9ACF0D0F92A65EC9BAEC8AFD9A1C7805854B19EF516BCF65125603F131084CD13BA6E72201B13C1897D0ACCB8C4266884F3439F6833D22C08A68CA0EB7B636D866182E6F42B35EE9E255F3FD30014F4EF3484EF31FB1D17A6FC0913DCC1443439494BDA221336D05CEF0FF168A9C54830066A6E986672EB92B2CA01C7ECABD5B5B40049B2161F8F52445FC27379B0706866AF20800C521BD0DCAD90E8F4367929A9D21F1921049FBFFCB2BFFB69B27A2A4FC9E48256CE24302A57B69B04D6E51469D5D7C7E41DB6113693322E1DAD218FCBBFD47892E8BFDC28FE1461AFC769286C6F75165CF945E5CD3C9322955261922B6C00CA2C006070EF26141BD8B44798110A9F20E86C52CE88D6FAE122FD7208C9216011D7D91750A800576F575B8EDDA2545B3D60310D61F7351CA1C82C90E18641FCD747FE901351524B9D0B92CCBE86067EE5F126FF4B2C582B280CC1549CB3A18D5D9FD25A09A67DB83A8F3F7DABFAA3C09CDF00C6F16D722EBCE259723B97017885B70CEBBC1C164E1A5361738B1F3FA426D077AA97AFC56F4F147D3EC04E52AF0CC518AB4CE8B3ED66A1EDEA49E904B81DF00EEABBB5EA8437C18C0282EA1AEE445331C5B0414C2E3CEE637933753B30FBD2160E93C3E7956BC032FF839B81179DC5C41CC81E6B8A74EDADE4F6EA0FC2077D3AFEE342D75DDEC1539F5C00F640A56EBA718A77A88E2E8070AB9663037AD66D9B6314C268806C2856E233D37BA73E61B8CE393F9DE86DF5C76610766DAF68A8DADD37C3146F59115E8AC18330977D7BBF677C755B79C902A50DC457FEC314323927BFD45DD4A5AB7AF351228986F3B03E51581C8A8D5E4F8C24ED9E14FDB5D0D6BD2A6F563D66A31247D4EA17CF6C158BE7FDA81DBA14B9A1549D5092658BEE5542BCFD42C8DB540447AA13F208223DE36AEE06BCC2F280333D81964ED05A275EEF56C21F0BE0EAD9D6A8F2C70660C0CB04AF6D84E0D18D3EF56504CB18EA259BDA23AC1D8CAB42BC340448283D9CEF770872F3B94FE85A23CD9A864F76FA82EB637086D12244DBBB9E7B2951D3B0B6C345E513883F261D3EE312A31017BA33A08586F58084A8087144CDF634517F42AEDF185D53366FF728C0E7C0748A776F3932CA874D3C2C48B30D01A5F579DDB1A038AE1E20D986515309A13B369F644A856C995C2F6942B7E6BB624A0DF34FBF31CD9F96C486E530A2F3FF8A43D7DDD578D72B1E93338EAACC244650F8BB37AA9CDF721B1EDC334755B63CD34AAA832725A883333A4AF4ECE71416146A4F05232968680AD41C89872E14AE1CE2FA65B7A3BC099FE265173B0B7159662259FA64FB70902BA09988A30697F110B892D7D6C763EF80D6E904A2CE47BECED5E98AB2A3BB70A73D6AF7175BABF8CF8F38F2AADE3BAFBBEADF208415A2C2FD4A1ACC3140E185A2534AFFE6C01EB30FF0137503349EEDC1F9BB263C18F427E2B119BFC692D5FF44421208E8AF146FDE964C2DEC3E1C9D5699ED01A7D78", - "69A39F2889ADC98D94B5C678A3D3D8736BC17256367EEE3FE8EF5AC6453A0691D894F1F3202CE84EA8BA5A341D1733C6BD0150CE9C0019168E67768B33B64DD4C9F0E2BCCCF2FF7E370C2BDE4F403C270F36937119950121A840913CC1D663F32F01B665840EC9E09E5A9C345EE001F84B2C1154359BC066D29E0405941476C5B7B11CFF124F5324D4D090E2BC49C3E8D83122DA9268FF58B523EAAAE4493217609FDD5A5C510038CF383B65FFC7671119556702F630404C0BC686975E853C86AB392D25C853964693AA7F4A63BEC12BF51762DB46295D2062FFF24000E4F9FDD21972D747ED2F37DBBA2D6DECE1009222EE06B846FB7D49E8014DACFAECBEF2560CCF5E06EAD04B113D1F8E341F200DD8CDB3F36AB99B566B16A84F8C040ED8827F0E9F0D4FA340B0ECCC98F5CA4B05A990F3B410CAEBAFB409E985A722E4C442F59AF3ECEB1AF0B148A3E8B958D9F6C0E45BA4EC8553332DF170872E60967E106BD27AAE4A6C15D391C1B4DF7D77357B4D4E8B29FC874947A75CDB1A1ACE512C5CD08405F2D9F21D50197DC151B5E5A735F759628BCB5A70B5CC9855A39188FBBA8E6BA0F5B6538ACCAF394A809C68F810441BB81CE71F7DBB2A11D3905225DC9B1F0F0D8B7E5268020039E03FD97D42204E503EF98C26B5D9DCCF5424573775E536C4AA26BF4B0351530857B8F640495377E9A08AE82F227BA487FA1D945EC233EB1B42C18FEC4BEC651D4CE1313C9574976F092A5E52D1B37B5D4B33800F5C3803BC6ED2759AE3F6888E7120D3AC2F24729A08B2B4C8D44EF807987C156DD3ED871B0A6217E9783A78BFE56C819F2C8FFC2D2D83945FE846833E5ADE3F840B53EE67E5D13BF0B7031B6C1D004D274F43C1982C43FB58011389D2C7E9111B8ADDD89C37756F1E4C4A931D828ADC3597429AF3A00C0C9A71A44A62F922102CABA479BDDF25A088BEFDF630E2AED4351A90B9567FB6DB5FECD6F168966DB2EB6161DA84479DBED9090026C3CACC19B91EF5680A40073FEAFCAE161E3A2F0DAC9C0A5A7AA31D93B425D5B5A7BF6D38FE797FB53793EED791C82DDFBB2D224455349F26F147FE0D59747AB091585DAE61A32B04DCEF19D907C1159FF69443843248D75E772B558E7AA0FFAE2A9D2B6B1E9F34B79DABBC98B2FAB34F76FEEC635E6E756F7724106D08F296019FDEC94FA7B7CBFD780F2C0B75B1D88EA0D5885237F4D09F03B2E8E1A98879656AA33AB23583DAFF96D8FCEF548302F323A8BA959710A78A803185D88A9C971D9491613E5BA2044D0B640FECF219CEFE377445E5256FD687A15C9F66475C0270C9C1A7189507E881DC6FD5B31FFF9949342586E24C7827F260CDAE356F874CC7C913ABCB40E892E495CD4388AFB84AADB45069F37ABF7DF966CBB8EC86C0CA5A86E79350DA5D6BC2B23EEB51B9C9C352FD9D3FFAE368891D8FD4E2861B8002BB16DA0C4A96E6A9B8D8FF553CA1E6D85B16F996FAB677FE58608BF58AC1AFA9482CA957B03924945B4260A4147625EE657C7763B4C9F4C00466394DB4F222DDC16B72C579FB80B3861D6B4364007FE856DD8D498F3732AF3A7041A2D71498ACB3793C250CEA60DE84FCD0C227A08F903A0B5ADC936FBDB7BC6AB8F7AF002266C8740AC3D75B0628EF6A05C0481CB283E3645F7D8A0ED7415EECD52E4BF70F00ADB11BAEB947F03140446AF31C2BD41F1D34D75FEAE64B91C6007CABC91A07DFE8AD753CE183C611178B8F63B822F03AFBD41AEF17F6A1D58F341D172D4682F38FED397FB01B396352C37397991D2E1473784900B4", - "39B27D6129F6C84173251B68B742EACD5A1BBD49DA6A4DE039831B66B054A9BB13299EE828282F1779AAB7FDFD82F4CC3296E9777A03C64AC4F08DC8882A9454B301264284F7226A4AABABBDC8336CA2BD1EC6517A9F54A776446C5A12FEAE387629FE5A66188C671C80A6C83B08322C2068ABBBC03261AAB8280F4E36507788CDAC4D3F0817327FC0D19B0BCA35D89819A9DC2D5C0CED08A87AF8DDD99304505EA08855CDB514357F8A9A7F3F4D062705E7B26632CA617F640F4D99417CE5C90D432D6B8955DE269460B9DB3C08432FB7BA08F5A658DD79DA8E9AE5B0751152847EA6ADA78D0BB4A8BD9F6E221990CEAF771B5AF603F463D2369DF9BF556A1CE60D1EA6172BD05EDCD166255810C1FEFE029EF21147DFE8EDD5B333F6C7274997E1BC61F253AA375B9CC6B5B64BE8DE11CA00C9530DDB1F218870611D4037BBB88F257614EB7F2A6FF395376C5DAEE4E83C5D11BD6600DEDA47D1CAD95B11E5BCE680D2F18CF92353A11840DB88C38B363BE8813E8004D2BC1DBF95E86C64E060F735C404E8945EAA3DB31A27C63AD818D96EDC6B0111CEE3B3E9F0E1B7DAAB22364FC1B36D25ACF77630DBD1E3CDB194FF8B8D1BE8ADABCF4D0760BF5CD406E982E0F743AFA2C4B333152A74177DD79E64566BF34A10515AC0E050CA135D7357E1F94F1653E9EFB0FBA0BEA1C2B09D6378E4E33EB98B5DB2A2DDA5D9F29CC68766AACBA09DE25B338BEE82700203628ACBDD4B828B34856910D0F2230260FF41EC371D08BE96EE2E821A1F3F328B631B53BECA81BBC74A92F608F2B040548BB5E805EAAB46815793F1D01D121D2E347ABF1FE62B4E00E31C8DAA01202340219430E88938D859D62B709D43934265B9DA9DBDA01537F54B439111126613FFF46ED0A39B2B19C22B8776618B065E15A515B752E1846F51F8469CE32FA076F47A5C49541A19D54CD63512DDE1126D7850B4300610E066AD53E094F26DDB40980B47D632DA9B4524EE5473B521A8F79A4B84CAE714B65E30824068305858CE9F39BB2EB06821C3C07EF2E030DA4BB3DC2D7A29A69DED7EF7B03825C663F5EF44B9A1A174ACFBB164FFFFF0419E13A8DDD108FCA9B2A8CF1A5A2E0471046FCFE32555E72D857ADFBC123B190B48CFC91CE8F0BF86CE2B439DCD3AF6F2CB26EEBF393FFB34290D2B7EC33FEE285547BDCC922312D36D9D25AE5DCB0A03EB0B603A6F75A5EE878266221C9B606B185250231E4B5C8B9470E5BAAA9859A963A51B83ECC111DA4779F012AC23AD2E2DF2965A39E52BD684A0E8D2406A173465B57BA6DC095298DD716BFE30E42CFDB0F2202D56E97772E3D64F1CA9B628B6EF2217A837165A1BA1A8612638C8387EC3854AC557C326CE88DA10F9DA027B204CFE634A695F2B59BC57F987C613131DF2F0F6A5F6081C96098DC03F82B3691AE9E4F14C32324CE495FC94EFCD1CBA88842223DDA27999E0B1762C581162FD1839352E8FB7E4FC143E8D3C774BE9BFD7BA4C3091A04D08EFCAA98B5D3AEBD1FBC65BF1CD7BEE784B58A877D8AE9DA9B3D459521A53010D42242DA0181F661F7CFECC2E74BF3C8E959D84F91904F4F8DE602B214A2E3C42B93BF904058FDBC37528D467E323039F101209D60C56BCEA60BF9C3714A05437A978F3601FA625B31562B5C9B5DE2C6B84F560FE35296E2715D905BCA71BAF6B577E7A03CA4A5DC816E79E21C9B688B0857887A25AB624E2233FE8C9A80C6FFE9AE77108F44A72AAE91885BA9541939A34519C457C41964D4FBD492E11B2890BE2BE0E069D274621FABEE60934", - "4545989EE35583C07E91C0FF1F5FD605F39D51A0485105A71ECAF9C7EC0748F7FE5FB5C4E90F1A59B1E31F74912BA831BCB9C95A315008F4C7C72D8AFF51DD09D9E4738E72C325B128E03F7D90915066AFC3FDDE335EBC4EB34895FB9807731EE6E123A28E815E5927BC9FEB02AA960308978D8DB5E131A22CD601D88069D145D4366FAF97FD7B71F4B39AB73A97C715BEE20A175931D7108AC1FCEF63CBE82D9CFA3569883A448220CD92C433ADD11A52F72303BB4A5D1DCBDCDEF605913D8D424F513EB8920EB864641B5833A39839822AB8ED011762756D6E16540D544B5CC8D9F8B671F19DE2BF7ED74CDF8EC9592CF1FF61095D0749A6404BE49AEB7434C75379DC02A87D213FDD6E0E6DA751657D7D221BC5EFFC8211F6C86B0F77096A81B1F60F51C23A5D525C3411DFF07CD5FCD54A60FE7AEA7E4C182885B2EF08BDE99995121FCDD5DDB0335DAC07DE1AEDBC9E988D7D90CD81D30E6C8E598BE6743D2853D975F236E6AED206846FE8F6AC9FF72C585606FDF6C25F5CBEC0C47567F389D5F317DA01F4A801FA2E2CA60344EAC2CCDEF9274608D8EA0A0D6323A1510FBE7BDF1EB8C0F580DBD3BAD17B268BB6E232B109504CFA3DBA305C7F273F8FBB7D8880303492CBED0B8AE374ACDF582A945A1B1D2000E71FCA445CAB59EDA8977E5595734A508495F2A742E30A006D383FBB6F83BFF1D0DA35805B6CC6A54BD1A7C3BFE81DCBF47021D6813B0E28000AEAA0654D085A9D5A0F0E0BEF802AFCEACE79FAB3F85E09E968BBED03B00AD50D079D9290F7E18904ACA46A2F0472E64CD16429547DA8A35CB1D9D532D4223483E7CDCDDD9E406B4920EFDD2E134B169A1DFC3F2AE54C3CE78A121F9F46F5D7BA6BFDD9CA25FEDAF0B2AD447902DAB3282AA9339C235FFD874C5E893E7E171CA838678C05936F9C9F794300DFBE63AA842A3B9541B07EF486C4823EF1EC56ADDA3143B89052D624EBCA9DC5A3A68E19F7E50E4DD71F4B111B24459EA8FB211053AC3CEE16F0D2C75B68E6F264A4E2874DFA99D6C6B3330B634A65D1B3617AFD7C32981D73C8607996F107211A7F37C6D6FD1D72B56432D66A8CE99E30E16847E549E54E7A3EFDEDD39741A55E94B1B735238093F856D8690A813E0ABCDB630747EC7A9D4729A6E0A70F001F5867E9AF613E9A0494BBBAA59CD1D75C83265E494530711F18313B0643890492BD13B49296827D7444876A98DBF99A6FDCFAF7883E02FD4ABFAD610FDD2BC8306377EDBEDA3EFE03041101A489051431B91BECD6E9DAA5633C8E99839DFE70F4C156FC2B1D27ED307757E0335EAA699C3FBC43CF47E520CA1404054F38D13CFE0339D87FC1440504AFE91AF4088820F7A1D8128ABA53DAD634250CB0C467592C27D1DDF7C64E7E5308567375FF73C02951DAE125866C53F845852C5008A69DEECA708E5A621FFC81C3C932319D15E867AFB67B1B1E07B261ECB56A013C441A7DB94523F103E93D95A7A0FD95141A6342922D1A7130ED95F4B1FED18F3FC61315A1FF0CFA66382BF10DD284AA4B54B80FC2415CB8AF7F3E686AD0664C21EE9F20070F99A8A44A5D51D8CB4BA010659C3070EB3374DAF2168562D89FEFB10100670663E71D029C2B09107611C41B202B0815DA2071256988918DCE69B35F46B8AA4F11DE63CE565AAA1172D7CAC8296B9334FAEA08D3BFFB34264D3487ACAE3C9781C1664E800732C387F9D65C152948FACFABD175C0FBA3B45F9892F8E98F2BAAC48E304EC9CB9D2A41487751B8E37F3B58F66710EA2A2CE02354B85E56EF7AEBE52388", - "F2BC6298F0B96E3B736B5A6EFF22ED079C8AE2FF586E0F4D53ADFB17300D11CA7B8C2E79C0877970ADD0579DD90187CB8095278FEA5F4BD3D9123D300100AE63635463FB5019926B9B53BA7CC826A14EC4B5AA5E9B6C72685B4517A4564028FB6D5584994F8999F9AE7E59D4327FD95C2A45E83A63E9D9F04B554C8906E0E2095448F75DDB68C8057F54630BAFEF06232F7609282B1EC5D0AECFA93E8A7EF3E6FFED7F6E4A2EB8B82D22C5B9AA7B8617DC13B69386742C09C2055AE5C2E71E73EE0DDF1D23E4928D7120B8C171A4F4421DDDEE6229656295430B936F6AE18254A11612B9ECAED23869178CF6B1E6ED7430958039A7DA988C1DA03E0DF5E1D8EACB7C726A9108E5472329280184861ACFEB110ADAB5ED03ACF5EE7E806AB0C850AB7E2256F817883394177AC0E0EF5B74E27CF6B315D0F134B282EE527E32A762C1AD06991C733A7F2E23776B01EAD68363A361F28F381F6190635A6BB38CA9461749E8E3117CE4F767007E2C38FC0EFFA4AAA693664F30A5704D369C9BEE225890021DF8450EF25B28CC123EB178D113B07B99ADC4AA47FE0078EF3D750B2E600B09353CCCC8BACFF198EDD2B3C551C212D005CF33763875B3753E14B14F96847142410DAD4046C9C8340946D922B6EB6CF2D2BF3ADA92A492D2C43397716A4BFEACA01BF2051E029D5C664E4D9C3B7248A9142092DC25FD0DE44275AFFE90848463E7E68A7DC4ECDBD5325AEA355E111929BF700179AEBAE60E26AB2C6ADC3967AA55FC9A2BB1CAC49098C16CF85C569E2E4A146568C41C815C76629061A483AC30DD27ABAA1469C1AC6C527BBBA5BE8BB0541358FEAB34B1E3EDD7E37EAF307AC213055FCF44E65882CCC9A12AFE5F7FFFEF4262C19AC072C291ED636C3FB1D36D7B99F77E93A5DC2848B01595D8DD3C7DCB95075AC52168897126055E8EA8D1028AF2718DCDA34496ED6FD1D86B49BA42F77A714D65D594965A748EBE83501D963F7B8D3EF55804B4FD5462D12571B77384E3D23C77ADDBE7F4BF667CECE0717C7156623AA6FAED9C1D2ED3C46403F750951AD8BD192FCB1A7FF95A590D085E7A733DB1CA0A821631245100FF92A5B1F63F53A6D831EE041966571EBA5914D81F838FC3CC5C449BC39709A489CF31B7CB91ABDE6FC8BA6E4D41E048D5C59377EF4DE7BBFA2406C6F400232E6B502A10802B420A11316D93638A926FD0BE4A368A223FF767B11ED73E6DD1AFDA6508D4CA6EF3517CD3362CD1604CEC574DD35FABF6D5004208146C93BF179ECAE54D9794FD13C34053FEAE2E7286C964BF2B2371D9BA8AE3F0114BC138EB3C304102846E65E7908B40358BEF9F290038FC645979951AD82D98106440CFE2261C5BDB6BED587C19EBABC54469D6ECA9D9DD59A92DB30868297CECC90AA8228E28C4D1B074881B939C60D8A4530A193290C5E5399FADEBDFC42CEC5FC2738DB18FFE9FB20B7D443FA3F1FEEF91E65279460D27F6308B6B0F8B450452DA56E81D37851E8D589F9B0822ED525BAC86575FCBA54E67BEE4512A7F215820E1885F79A5406772A8241FF96533C644B1B5200FDDF4CD1F270E6EEC77324DEF0150183CBDE7D042C33DC0C27AC6F17D670D379AA778E6EF48D41DCB6C9F0F7C5E57BD0A7875D4B2D8E31AEBAA58AAF78947683E373AD517DEF236B037F29C2A09AA4D596609B7AB761FC8D7F566A6BC8840CA626BD36B1D50AF74342BE0B54475D0AE3E30CAE146306AA540E0D63AC325252DD66D5DF50AF7C1D3A651E5A145192E1F05FD31AD2F37719B62DBBFDEB84EDFE0D64490", - "9DDBC6F5221BD70BDA886C59D62F7A95BEB41276DC3B5B505D883DCC478B697388421D5C217C8DD2E56A4130A28BBD7176163980EB820899CF74F3074DD7E74A77B54677A35EEEAE93C32D44EC4D2E4196366E40FD0C2A4741575ECFB8FC927142229E63FAEA97C51E12809FFD336BCFDDEA3FC03A1FE99EA685DAAB6F27DA6BACACD5D432352FC6FCC323EA9BC72FAF2569A7C6D55E1260DF0963EDD6CD3CCF97A033F74201E4390F64F06F89080C830986F8D6E90AFED3BE6A54202A59ECCEF101E5DB790E997918DDBFA1B160D472490F3CCC2B0E1C10AEC61ACC1F36BB6A8735AA86C50D2AC986721C003A2A8F1056BB9910F5A8D62D358DDB31589280BD14319C27A13D847D84C02A039B869B52669DDAD47CBEE6892E2A881A020867405FC1756DF2AAF2E5706A16F53E1E459BCDC430C26403F60B979A4D74F78CCD34E48321E67A8B896A162C873CFDEE8D58BE234C34FA20FAD472F0EB570F5B2BDABEDEA0D0483176163E20E47EBF51262B19442016EE5867BD3345DAA7CADFB2BFBF14B4EAF986951B024D876150CD64B7B0A188CA79B122F274FFB39F1EF88D5B9D36437AE8BA43770DD69E3994F8CD673EC3E1F0A51E798271AA7793CACD7E53E27A325193A9B9FA33ADA3BDBDB9A916DC8BC6188C3D4C38848E3506E38621DB57C2B0FA80BE5CA34C295159163F23ADC249BFB1ACD94FF0A42054C1A2C304F3C515B8B44F2AB1A760E784B95D9FFA905EB5541D14D5F12B4489403645A15F004828AC8FD3D8B44C5C070E8A64BA086462E5CD447C58E0D96130E9BA3400CD7AC266AF3E3D33DF214D3E98C6B7585C552979738879552FC758F04B122889E81B887B653FD7D4A8A5CCECFB0850B58CFD4BE990FAE223803EAE972D0C65A97960421D3FF5B2B75079AEB42A92E0D0EC2F04967C91CCB84FE6E39B6B136CB64424686DC6CDC4AC39C26BFCE81478AB6429D4E9B4877EFFC8740FCB5D9968ACF8D69C771E9E48CB542BA5BBF0327A4C55CC83E466D6DE0E639A54576D85A44F305958A325CE98A45E2C227AA9E85BED652F3EA5CD31AB99E299930F5AE92B12E10D597F69272ACC8185C1E83412A67CCA39DB06A77329475A3A87A1D4586B191E2E8E7C3EC39171CE6E775E7B369C8EED0B2E74A7233CDB5905F6AAC099820A227B6FA0FE5057CDCE6C8175F4CF27D70EE76CC0D769A324AD66D013A3F699C7F024C22C03B353177C3D721EC56E472AD6B383A653FFCD078774C728258146BD8D928B209C0A6A8CC60069F160D33F673C139534362B58E065F7D1176FE95F4A6DB7CC75FAA408C4FB09B7026DD640BB08945B364646D9154D00CDF5BBE432390607904BC3D70A0207F696152CE6FC5A0BD79625E437197B929203CF028384558071B625E0F8801EC1B13F6DF17EB8135687F08071DFC3BB06C8EB4ED296C821CFDDB7F2779B0B913E623ACA6E3C5FF023C58EAAB547BF1A67EA020F317658E1328FC845F65464D2E06ABB63F678A94614E3EFE281E41ECD6C85FE10ACE427FB1960BDF06630B20CF0401F450D71D3FCF0C477682FE342F5511DE926AA24E776CB9C798058A7576E1F76ABFD2C86B8C741230D6D95ADE980ADEA22547B88E607AAA8C3462FA34114DFA46046848CB10482314D1240516AA7EC7160215A54F69EBC39FE4CC97EF710BB7E8B55F9AC158B7F9C87B738FD993D2F0E35E4E9969FE5FC4B301BFCBA8A28D7150602ABE7635A2FB48AC65EA29B829DAE037D8711127F80CE85BE003B4F94E958E493D7C2236DF970D7DFE8495CE083E79B777D44F96C6C", - "33282734E9BBA791CE9CAA5CD9F80DEA9EDFCA4E3F5E32FE046FA978612D25F79FEC5DCD026666C35CAF0B5A682C9FC6C97F54BEDC056A6D900DAD88CBCA846702B0BC435DDD5ECEF1D3356E85247940A3892CB61BC8FBFDAACBC1DCA9208DE593DEE6944822EC80F823B2ACEA3FFF66E4CD6F542CED77C81F29F144C9D0FCF3B61C4887C6B42EC97C83ED2C5DAF28CB8C9B352B37255F54835EEB978966A14AC91D58857CB7FED677EB87F8556B343BE0056744655B6D97615F7F32BD4A537D8D586F477EF6B2871AF0524F71763748C57DE63D62D6824EC5075498D492A2C621FCDA2A5540038A50E6765ECD69CDD45D10153171DECB85AD45A8A6D3C609E350023C32E1F72B8D5E1AF803F68E288CEB2F5CEE3F10B7BCD7FB15D11DB3445266BDA913D5930776EEA4446337EC5A50F9E4CB230BA735B656EE26BD6BB5632B907CB81BB65EF4D85BA379E4C164DE83CDCC023FD458606E09552303B8535B63E37FF038F2AAFDBBEFAC8BBBCF04EEB41BF126C20C533DBBAD8FE10771F01BDD14AE113760DDE4C0D71FC7C29EB8D23D668E401B3A026C46913E2F08DF8434FF64B48036A37166F32CFC8747F13B656BA6D18300935195D0411E8B24E1F47298AE9F9617DAD3F39C4251566CD92A64860949BFEC05EE2EDD7F2DA0FFBF3D3C9F5A349130B7A5BC5B839000431D00FFEDB344C0DF86073F73C6833C091AE132D121F4568D011BA0DDC27DFDA5284478F5AFF037D89DD8EB9FB0EC066AF20740DAD8D29C1866DA0998E580BEBD311BF6E3BBB31D89D2DB162A680D2AFAC4903F9838B616EEBAB56C2D0386C65CFCA946D33073684FA119B2A6411E1786C723A466C7070E58248ECBE1D86C6D6CAA199944D9944BD6E8B108060B612F8FE724742DC158BC1E5E3F71AAEF1864A7989CFC68CB2396D010E1485C3238F6385D68E20D36A4D3BB8A5A265E686DF558A73020588EA16B4B0D3F74916038A9954F75232087822BBD8831222F7B94968C5A324018192A6377661AD1E15FF05AFFF75FF60B60C5B41C08F001D85A237443EDF3E361030FEC44573B044CE66F7A036EA78EB83E1863259BA363D517049B13F61956740B1DA3CCB5C9EDF190C89A2FE908916F9DF9B2BDF0DB50D032FAB059309F3DAFE1723D8031C93F9CF657F17D1B214492786F0D297D3C4C01A25DF2B1C3892B6724DC7CCA704E9AF0163D37F91DEE0850D9F2AD4860BBD2266FD7EE4E3D56349B90155BD843EBC0899FAD39C67050B5F8A1A9DB38EE821EF7561FCDCD6F833DD3C9FF3C5D978BF7E70288BBF665F4F20260A74DD0D414B3538FCA93671DB4371F2CF6AD94070014BCD5ABAC89157836CBA9A34FC8D84090A3BACD7D641C5FF58A5E1489E1D2F410E65650AA30D7FEE4AC3AB37D5AFE208EF3023E88D96F4760120DB5FC705A005976BB27F580CF5C10988BD2221507F8A6BF84B19CC3BAA186050870D88C6B14F98E56CC470291FC96AC5BE10704CAFB10CCCDD8E3EEC9D58E448BC655A0A899C2FB39073CF28252FE3FBC6BB61189B154EEAA37A797A8E6F329C64DE5836EA44F7FE04837E343963FE89B0624779212F1E5E399427ACC8BA83C10F3893C7551FFFDB62BE893DCEE02AC893928E81A080CC2EC8B95C4FEF1A6B65723408F12F6E3B7B384B149F4002135EF114B67AA3CCD406A78A732374CD7C72814BCA01F4D44909E6CA1245B25E27A67F2350D285E3B37218495CDFBB9C7FBF2C40FE31C57702519B5DF1D41D85F48DE4E46639104445FC2C078CFC853B25BDC3E4C58222B2F2C5AB40F5906C314", - "6E2FCAD2FBC021102FBD4F992C597E4B91D2AC56A22E8FCA938D9C74533912782F75670F31BADFEA83FB93A0F6D449092FCB9236F50446A4655586FBEF31323F1795AC3216315BC9F4C92FF583AF7E977A996F10989067975A53E153364B59662B6CE9E1EB65D6D69B9EFEFE57ADD58A7921506C2BCF4D51A01F79A67D41436B519D314D1953C6D133305AC06A45428C0D6FD9228B7B9228C3A2C03EBCFAAA09B9343C736BF99022D1CA0B5C25A6179EC0ADD8AC95E8D6C00D6273AEC61E1196741DA2ED9436F353919A8D25BFB8234DA7A2229CCF0FDC4C65CC6C0374A4ABB918E1B5BC7B929F6554C568DCEA62D5289E45284DFA975D5AF56609EF4DCB3CA54A26F100E00D48446C4C35D1D911CE7EBECC58347940BB411F475ED18D8A1315C069C63E59CE2F69E6F7B48B005107A69EBD9715303563F6A217E2ED4CD373648DA437E10754CC5636790930947650E6C5D1B3D1AB853A52A89D208301C54F8E7DA8D419559555859AD1B4D096A1805DA251B6767DC2C0D917919E119E71CC78A884A24F5061CA1A999DA65AED69CA02C20B6EB163B2CF435135D3B34FE6EF52F3AB84DE084E37958BAA4EFCE8165E2F5AAD1D84E9F7669FEFB6E60F1B9F69C79DE9296B7A01BDB04CAAE8E6A16ACF9A119A8E577919CB22B58EEB7EB289E708F229ADF81E2350B211AB48043A491D4CEF1721936B71145F07A40947D2A89A584D5D0A708F3480F0892E331B2B73D8B7D88B7E85F73DBE5346D801B1904CD41A8070A0DC74073217AC415654F4170F42314AC0AF4213CBD28094F8C4FFAC06BB0114B2C1924A4A1B7655965468574845864ACE82B8839036DEF45E88F341A5DA37A511D583C51DDBDD51577488A29D7663CCA7AB2AEBB53A4EEE7F38B8637C96CDB86B23092FE0CF669858C5374F6F078FCE4E945FED340903FF26A6AD6C408E390F08ADBFCA9646CF224A5410D0ACE93380314541982A8AB6443FC358B66B027A15722A0BB7C61484CA65A62E4496053C947D5F4744B69B4A73F7801453FE20557224878B8FBD318E8B572911D09839FABFC267416B4E2245FEEA6967677C1C57A3F72E76BC297CBA73AA729B890E90A4B29CCAE4DF5D959BEE30D836C859F4F67A06B4A479954CF20C7D0639D680EB61A2CA11B007EC9772293EB8E6525A56CC0F380ED4F088D8CADB0B95BDCBC84C0C746D4DE3307AC7050FA2531FD24164D29294D492A07024FDF1B988060FD766128120226E63F4973278DC9F07FD5699A1313002CC9FA7CB44A72C9C9D740AEF0984D7D4C5749F9071138BF93BCC6DCB601CEF5F60E4BF2361A083D158BE93134DBC1D4FC79FB866B0B215E230713137EB6BFF388307CF2F07CB07E974C8A874EB20B06C843579921ED0839F9454DCAF71BF56387E01F3DDCDBDE6C15C58BEEBC137B673F122179100613D6708B6B16AB750A3A311AC85E795FDBA002CFB2A9D9734FEE1922D984DA9F76EF65EBC9F647B280B0433A3C2E73B08A3669C78CB9885F65E97A6B4D64D2B3A29184EA87163B06F267FE94714977525AC061BC54F7FD95CC0C4285E45D75772AA3543AC00EAA32626CE2F9DC48862657C1E156E08136F3B1EECAD329072EE4EDAB16F385D736AB806157409496A9CBFEEB3F5AFC91E2FC5569DA2C5DF20FFDEDEB6BB57D18AEF1DF03C7D5A16BACAD645772C4C016D147EC11EE9996D2E791C5251CA8FB7719F2093DD2E4505B7BF320204556D06B91D547C9C6B0B19FB57608934D4A4F748FD07F3F57CB108A310319F7835C082FAED651ECA42EF823AD83D6B22375B20", - "22C6D5CF65DCB08CFEEF580D53CA6571787AA81CDD29C4918F5EFAF89E285A37DA51E01500BA0192D2F45573533F540BB1569E27A8865FF94923B81AC26FAC1DD03DF79DB5B5064F84A2B15E0BE7CC53BA875E477159D0352CBFC374B07573FEC884A699E93497514E7375E49FF5D9D9DEFED637DB89158F30B27E802EEE4E806FD61A46F8F7D7AFF89C9101A9375F73A2164C18B0109CBA1CADD42E13C9170378E28382EDFD85B80A02469D9A78637494BC6DD284557ABCD5756225EE3B26C7BCD597E9744FA1674C5088D3301D779B1C3A922A0723AE1BB253EF2BFFFC99BC8BB4CE539BF6D2D0951F6C76BB001B48E52387C95E49FF1A9D1DC12FAAA2B967754113FE59822A1E5C56A6053F73A2CAFDB0CA0B58312ED54B4F9D1832FA089C5923133F47EAB56C56EB7AF20D8006EF8D9674089CC49D37E82A1FFB88C97C3267569B5AD1A57CD67A0C94219AAACEEF99A11B28D01EA4329568E42A7E717437B030D3B649DAB105C700F30AEEA7B82A9759ED54F890C6E9B2C9F3F1D1A7A14A245817DDD4E2343BFDC5DE774EC60C5C41362805281C3019CB2915182F525576B3BF537FDD5236300DBFFFBCF8A8C9489B1A119D66181A79AE93E7DA8AB81A1A3E8D5A888F5144AE0DEA33ED8B7B6392B789EF9C544F876D179DDD822E3906F76FBD579FBE27B4A2752D4878962008B7873765B9BDD3FA581FA192C0C422C15153D7FF16F2732EF68B66042B5053E458518EB65C66E3955CCE4AA212ED4980411D3E4BDC6918B30BBC400A8A338DB982CF55F2C3B0C3DC6D64DF10A8CE1BC117338DA3987965A5EAB6C2E8E368F59C7D9C77750717B4440AADFF57D0EADFEE7C1A92EE72283D425BDB0CFA9F3BCF602634BD8526AA80E0247BD0A043D277A3E575C1D1EBDC0565330FCB30C63AD02F48D485AA43358D957ECBC6991D0358AFA953A41C67019E96576BF88122CA76D2804B73EABB88007A121BED76F33AE0E0433EA74FB2C7AD672D0DF5927D87BABFB30989EB91BBBDDCA40ED8BCAF7684E8EC9D1017D6147039D3C3423A9A0081A17B70F56FA300E8F2F97C399498F4AE85FF2707B50E3A4492BBEF19E14834B261F700DF4E685DEFF476ADD919D5A15A7BCA06F382E1F0649B6934D70A80416F732552872BEA44A5A42D64844532DCE8ACD5D20039D397BA9EBE04EC4742F4E2DCAD29F89E0A9FF572579237863890DD13E7168CF2B4CA8F6A36B49A5734BC85F811087B9541605F44FBEB3313D3B56EA13676CB69F4FCF14A1BD285455BA516F20B2B0D3E8922B71C0731F2BFD1124067D4CEF2111FB754CEE5AB73DF629797FB5E012515609B1E9A2085643691BAE5E4A2A52E904651DDB340090EEF578675B778D1E6EA868FC1106F19B0435BB464887DA311545300841E10441E9316656698C879089FD009D3F8F49097B6AB6AD2D744AE79F1D15F0DADCA70C1177374ACF5D07979CED4F3173FA4ABF571F6DF2112E8AB26C257D6861923CD92CBDE33683F27D2CD542ADC623230470FF7E950475EDB761E57ACEE78318FD60325B871936A51FE23A63C9B4B7DD8A72556311877DD6A8EE053D6CA28261BD359C0C997F2A184270847A13FD3C952741C5D1C47ECE09DEC3D8E0223110A627084BF826548E60886D7EA15C585F5A16A813F030EF3D150FE7A4D271856623D96742E848F7797526238E56C102191600AF7756C562A9B627B1F05B56FB2C768F6B57986BDBA95816E0842759438E262FD9BEDAFCB594731E9A04512A22D1EFFE104EB8F7E502B94FD846C71004E534FEF2A30812F84A8", - "E881D91D5F8EBA0700605336E6BCA6A1B1BD1D58F39650CD55F056FC8360EC9A2CFD0CF440EC2C6E98EE88E6B31558B838EC9D473F75CE2FB04155330C9FEE2C381F872C3A79331C536A05C766124E69AE1EBE9425387279FF9FDCD28CE6569215A65F678611C96103D710E45029521D6EF7D5A2AFF378C9C26ABB52AF1ECBBF615561932791A23A3BFF2824CD3810EFE7143A79B4E14132E306C48D9B2FCAA475A7D2AA0BAD046314E5BB4839B27FF4ACB7F4B3CA8C97CE976F11DF6DDC71144A600DBF9AD43B6E471791CCE636D67CED546A377D786CB085D0E4E91258719A9233F342180C9A827FBAF77C8B5C1BF72E9A81E4E4908EEAD39772DABCC8CC0BEEF0812DEDCDEDD7B4110C6A0B89484C2F0F6CBAEDC219BEBC85903CD03AE727B1849735F62B385F4D5CB58C527CACDB3586AF4525BE1CE424A0879546505F86E324EFC4FBB0B9E86EC243432866DC9CCD4D9FB258886EA75AB006D87CA5C10B5BD0E0CC4DFDC6B152D65D5FB268DB6AEAEFC9EDB4954CCA7E88DE2269533D54AAC447124EFA9BA62FACD2FA914885C162D59BC6BA2FAA3389DB9AEA4C350843B3361C9F343955AA616E661ED1A137EC0BF957BD7DD7105856499367E91849C99F0F7138CC7AE120CA36164658BF3B67BCFC1BECDFFF49606448AC8B38619EF4A997AAA688D3FA7FF169B8BF537314CA8ED865F395E300E5AEC2CBCBC5A8B5AAA31C811E3968FCE32B82CE5EB1EE839134EFCA68E4CC4C2957329A7CAEF675AE2F990CB108CAE8EA5EC21F6C442CE1B818ABC203327087146D67275300868B95052261AFCCEA3EE854F38DE7CE1FA5649AD7E9083DF2DFB3ED4186244045390F0C843777A677B8A82B69EBF43D8FD24C9BC0792A2336581F3B45EA6F8BBBAC89A0314570084D683C76D32C2B0A6868A428DA7D72D9C6D37D99BC05D14ECE27C6C1E3F849332C1CD67381B6CCC907E1A911D3C97F1B40CC11822257491AC9C22642C4FA2CF8754E6AB2574AFEC65062ED5C1E914F8DADD52ABD7A9D74E545C362880F38A567BC3E6D7BD7156C87F698C870008C2AFC78F94354C2DB9833A0635E2C63E5A47A828610E2A5E8B2F914306C966D1EF8222BD8FDA2DCADA05991ABADAE250B942F8FC82AAC026696D62BFB27C8731149C49114EFD2AC47250E0454E33383082E7826569AA4D6F5661A9968C1A784E0A080D6BA7F8956E37AA55C07257AB5971E03069E74D245C4A2A0BA0BA397376141FCDD486B2B3C865E97D1CC327E4E3320A131A91B61F5A78AEE77D1DA75A1F121D777DC4E3714B0B515DD96F477E9232472353FF7FF07B0C23D1C88F7DC4516C36B3D1820AEFFEE62EC3DFB6143630E1C532A4FC9740369617E80312BF3CDD7E3723F287DF666A34FEEE38B3A1461E1B5FA03907125359025AC125D6E86FC6AAF0223F83F252AC0C6D578DDAA8A2841DC35AE6B6DAB2E7A31EF4282DF4E20D471A3A8B28EC6F510453728F981D7BC2F1BC2A8E024FA65BE18AE8CD272B05403E05C6006AB1E612CBD9F8A71C50D618E9FE46B243AFF2529F2A0FB42C7B990BFBFCF6C4CFF59DE230EDD411BC93C398C49E76FCE8EBA3C2C93752B38886162745ECF4F80EB59AA3F3660C4B1D4B9850632548A6D5A9F5A8DFB5A74881C0E93E38AD2FD1F0C23E66AE4631F25DD442E1A010D6A04FB73559C76CB30494352B24FEFB1E529BB6407BA7B68535D06C7207B2126A585BD59C43ED1E36AF6408E33EA1CD6F43BA41401048AE9C5638077C8AA8A033F0C18E5899A6E9400531731486774E30C1A6292FDA7D06A6A48", - "74C4DB6B3E8A4BDA889FF8264534407C16B05809DB70004C8EEEB10156C32686ACC5076D21A2F583EAAC92954996BFEFEB1A28DD699B55B5B94A122A1349C58DDFEEE9D4270368DEF85D86CCA4FFEA81880739A934BB8831AD75794986D60A92AA6DE661ABAB1010F3999A57A53F3868026C64307C47370E0B82FCF8C02A3155E787DE359624510D5008E229E9DAD0005CFC9DFDBE5080BFD01D7342E570360E411FC27146147EE2C72931D0577CE6D7183386C754A6820BA97BDF080F6EBD063934E13B005CADA4D2D8492E143402C9D1BF8A04077C4BC7314532474704BEF9D24E4566A1409F085C76B65158E4EF6B30141DB42B0A96454E451BD63117428273D3629E2E5FDE4D9E53FEE5F9EA2F111A0FE5F50D2B72DD26E941A57213EED915147473D630F7556CA46FF8EF1F0C88E6272D6E95FD3741AA675BB0ED839BDE162F9A308B3B092663B1963221708404CE8BB54F61BE9AE987344228BB60921726D90FCC07D5F64BEF673E06B969511E111F0293BC5E57186B283AE81CB2803363A1266E7A78B47F5A35AAC2FF0B3A348DE73C81D74E7868683918FFAA42A91B89E1E2AFF4BBE6F11867DE292A6FAAA689CFF87F4A629FC354ABA202EDBEA3F08609D1A4C350A7BB7376A897AC15A1B0CFEA0D35DA71039A97B8C99A5367DE46C338D75A845A4CC7CA292DF57F2AD8C5E20D95670E3748E8A1BBD3D728980DED4FE0DEC90884B7A528D0B4C27DA315195B7D8D8CCAFEFEA3D62AE34B40F5049D06C3AC92CC59A85C5D5BD04DFE0CC89A7DD7A1B6AC4F5F3D2AD8858B83C761485B77F6D512DC2EE1DA402FC6158C644F14C2F6274E8113B453F9130BB6C24E36BF84C2942F8B28A3914110BB3D48DCAA3ACB1D7A89769E0B9048566671760AD83BA7F7209832AC10FDDC299F7F90A3744F72ABFBAC19382EDA24D0BD5859634EC3790C7390AC2866B1379ECEDED50D5127324A4EE6AF50D9A6826DFB3E27B9922E4A8652526A6DA29A4C2B9B8465E3F99E72A82A27645CDEFF1C42E77359FC913A9074516720BC61EB171AF90AD427A574080970282539A05471AB7AE2EB027DFD3D496BD27746D0ABA30EBD9D13AD9DB6D405CA19EEB90CB088D9CFF93B20DE07F86B978C7FEBA8AC29FD4E257D23380B955CD79E93E3135BD14AA338FCA16560A123131DDBA8A2B63923860EC3EFC2E0339015662C3DF1E837C879969573E0DC4A63EB7C0D6E7419F079D4CD05A1A9791330F1F1B7EBAD8CE76933D54A224571796A3A046116964B98A7EB5D9FD8311CDD6BCC9B63F2B7302347C0D3407219228BBA73B8B53DC3645EDE1969D345D8C23E691A58370B351BD6C86EA6EC9349D524BD05D07E68F853FD9214414507ED507F0E3CED126F95630FC6A3B40152A318278B8605F30C389C1826478635753FCFA9D227325463581DC51EF4AC47E1C49EA005D5AAB9138706671D64082F6E2BC39A802685BD8EE8001031F7C56CBE5FC68CA5B14109249C210B4ED7B9B2ABB4D4E83C9EC82911E9CBCE5DFAC8D4A1A6CC81B5378D29E8E339CCB31B85D9DEE3080ED75057CD5EEDBEDAAE7F3CAB4BB1BFF54042E28C8CC79741FB04246ED66B3E34D83F08D98D7070D3D6A032BA442E46CE38F45957D7485B17B51C562B94985FAEC8362A8D6DE43FC0EFE1529E662899F1D21BFB643C22293E0A0F2E1D40EAC1934A0421C1617DDEC3D40A3AC9EFAF0F8D94FB7DEA085C8179290FB4C917C7D6F8B75DA8790404F8191C0EEFCFF9DA2208E7E5D382B5A9D1E72089B3C4976036AD530BFD31F6D08C2CDE5C26E68C", - "13AB0304EA5EC4D96147EB5EF8AEB8FDEEE70A62E36686ACDC275D2FCA1ECFCAEFDC4F8CBBE5BFC2BBD343742EE011379103102BC11E824732D147FF93CA6C9B0A503C49BB2B621B47D4C5971643EFC01E760EE958A9764397AA551423EFD49AEC50E22FBD9AE99659E36341361286D8452EF70C662DBB3A421898FB34EDA3314A1C7A6AA9E9B5A6960156A549C32B91246A9CDDCCFE0FF278C3285A5F20081EE6FE121E3CAF922C75915DA773D0673EEBBB268998861C3018642A6A1B1FA1DD8DD54991254067B4E9BB95D1AE807B8A41B88B772B5590FA9F0D71093854C213283093D5EB9D4C7B1D57DEB27B1E2A1F0CEA306B28A5DD3D1B23EBB7494AF61F771052798C6FA104940EAA5698AC24910DF692D5C89C29F318E090F30CB12397B88702418C467EAD9599670DA2F993D5B6FD7A9A43CB89274719A2F1491FC3C3E1528EC00A6D3117C5D2E0CBCEBB7B91881CB7540809B5B9BD4DD37BB6B94133504981829410B4F348A5A7DC553F089C5F759F032F0F45C13991C1F442F2DAA5C43C5A6815383091ACA7101735A0A3D8E5E88A454067F8D92C4090DA1035B7880A303125ED48A5E4EBDD9308BBD45B77BA6B84093210D9B011E3FC5313F2CF1B20A9C08D3F4D8AD7003B32A49850808F1B78115D1E727A7BD387D2D4C4CBAA4CB94CE71FF25229B37BF1D671CA50A04EFCACFBD980263EF16015A97909BAC6FE4F981B96AFA2692CF3603C5C655BBF7AD4DCB06CC3BBF8BC819CCF20619535D399BDB5FD0D40CB261FEFCCD4B0B0FF3684FB0D992ADF1AC6046BAA8C8E0F16B6E691A23DFF7014AAA67C7F84A9429064139809E1569145DF3CD8240D49BB9D9FEFC2176C697D9950F11D56979DDC01ED19EBC9690893D6D8E76041BC4FE35982D5C535FBB883654FA3A2253D52F06B62022744442D880EF9DD4CC2141DD25ACF2EE3B26103D6A16710D8BDCD43731A59DAADC1B40092D9B166E822A8A7AE0B4323B8CEAED7AC3BF3CA6F24BD79A58DDFFB59FC2E5FF634C83F6F7B03441DF9B5763FF827D4E74764C3E0EEA21ABC1AFEDFC2BB9F73E3FBA165A7DF3ED9997A588CFFEA8E3C193F505C741C1863C3437A80B41B7668D12B0DC7CDC6A61923C102D3D9071D9937F36A39484ACF1A2497F238E78A9D8C9C1B96CAB0AA15B643B81F6C5439C2336055C8DE4A392B8C110753E060CE92325C3B67F0610D79D46F2E7FDA96538D43B09DED1D647E8289986EDFF482FF7E24F40FD489E4051F7D0C9267E934ED16B13827A8C3D47C192F5C5FCF6A8E82521B7062F6A23B463262E425F4820AAAD8E23E85DF0448B00533FA29FCB815BC83AD29B32D12F614AF4A6C60F7F1339E639706C4C671B71C99B55056832544A23C996C6BE5230AB5D8AA6B89A0E05B4235CEB352C70D3787F740EA6B8F05CD97409EEBDC9F1F98E428AECCB124F656EBC316664376CA4B38046E5640B377457EB82A5CF0E81966865908DB4B1E9B482F8740A470E4F5F0333A11E1D67A350ED7BD9C8306186E83FDF6FEA9A09BA1AE266A24AB6D3C192A4DF53D0A627EA2A2847AAE9D5EAB2DB183A45632B2145C3A2FB9C4EDCEA521E4DFC5AD34FB6E2CFC2E5C38B30996542C09CE9542E2F692B863CFAAB27FB549BA99A1DD77CFAB7E26057055737E6D08E5592D17DA8322B0DB650AFD6ACF4ECE23F1C9613AA7670302428512238E608B6AF8E0862452319E3ADE719928AFD059A58D39EA819F3C14DEA608F80D3C93E374C2170D2836E2EE9F600A010B97418B52CEA1592F4D6C4E91547EF019AF4BB4F1ED010242DC", - "1193230653E34BEC0CC617609C775D5DC198C2F533BEE5C3537F381DE8AD1995303FCEA2468BBE8713A3770F59EB4F58397BF63DD3AEB17BA59D1D906C853B6BB55030F2E0FC04C0BD746B755358EF16B44A6494E65FA26A294D25E7567E7ECFE7A830896D9CF2A8D97DD5D6FFBC521907C1677F195AE7539C564DAD1D78DF994A3F33DF3F0400EA6AD3A742FE3EB8A1855BC78F5E9ECB5F6E41A13E2411902BA48D0061D318C1D026FD379C5E4D9ECC3FC5AFDF0ED8D99E35FDBAAE7DBC9E228411D203FE2645169B3E8144F508F88D380EF8F9D6B6B7696CCB9041BC145BE25FBE39017DE8120DC3989669DE5B587E5F2C5C057ABEF2195F5E0AA441E05E256B5BDFCF636350777392CC1D5B5BCDD59C82BF8F3F885C86F5E6ACED0F0BA503944A9E2F15E8ECFFBC5B2C1444776A5FA7DC54EA0B1C9739E21E2ACD85DF739DD5761C17D71444039B3CD53EA47D67E8E8C505C39690D09E52127C8F055521EE8BE8ADC6479EC436B96DE2CF8784C71B585B1EC1475F16D92DAE9C29BE7375C527B1CFCEAC5FAEC37C3D892525FE1ADAA164E1E90680EDF0876A0C50CEC8123CF2EE2CAE3C35409ED5C5E6840E004C9F69918AC8B39899D0B846590F17243210FB32D3CBD4E3F8AB4C7C42DACB17716CC5B330B009EABEB31FDBE086602F370EE9172D66A8B4991CC56A0AEBAA3A623BB37EFFDDBE273DCA7B0C09649B1D0CB5F811F6A27ED3370D1A1E922A70214AD71C2668077E59C562DEED43C282333BADD38CF3B01E3C1F8A55B3822A7D41991CF4E4ED36D2D7AD71BF6BF100643EDDDD23B6C04486DF1193F552EFE21BD9B5A6A1D93D4459CB147647052906599533AF69D3CF1ACB1EB89EAF3004B2E4CCCF6D4CE8E3D6CBF8BD90E6D4637335D5939A3CCB8CBF6F6423388FDCC9B11A159813FABBA39263F337B3856B0A6B3102D920AB5D216FF4D370C836A85B753EA0E43E2D9E9442C9A4E64A061A0BE7CA61B67B0F012CC43E42ACD298B3057F9CD3089C59B39200E8B005772AAE2C2138172DAE25B7D54FCE9C6F8A410C50079012F069A9A7D6581CB6B2A3EA9E09E4F2C1C57BC9F127B4EF8E39220371EEFEF0254877B19B37E0785583683E5AC8062B438889130038ACD1F52098E5E4AEFC3717016321C263B4155BE8418F22E523F514B1F8BE737449A48EDB9F3B38D55E9C26DFD4C8BCA111D162DE23984DF208D5AB1B82623D2A4F4E3A104E3F84F65A020BE96711BA3B3BCE7E6630F8336B16EAC987E8FF10D97C62E9B2B1B10AE466451FB70D345A88A549967C367F6DC1C87D817EB7B4B0A5032E1A72D2078AF3CEB8116B1BFA0BA64F9C1352577BD9D0C552084898EE52AC1613617DB42209B5A8406DA72EBA89CBB1893E69BCB0E0058E4C227ECC507108152C248ACD033DB3C276E77D80AA7FB7C7D3ED6DA7CA79D469B1F2668DF1278FDDFD20CD02668C429CCB2D64E6AE7EA6C65A52B49D2A18EB48CDB26861AA872D74D51BBF34C56F5455C98E02AEBA0D3E658FFBBB82960205A1ACC2988D274E74A3C885F1E1F0660EEC75EBF839E8E3D5057F7C39DD8369F9BD6EC41A918BC8A42291384E2688F20A7B78A96746263991D57BE8BB2A516D9FBFA2028EE46CCA591086EFDA8C97B2DF9CD939D99A87A0AF0AAC65ED40B6551E6F84E699483CEF2C9099693B895C475C52C56598AAE7A9848CA6AF2E7970FB80768704209F117776AFC230158067B52AD83AEEE587F81014B0947A183F629D319FAD66FAC270A4D115F469833097897A40F185687084816F1D2CE615FFCDB27D060331F0", - "594886432182182A60A8457BB3531920208BCA5F9B84F988DEC9D71119DEFE0956740D55AFCF2FF33EF9801B2C9EA25E0565F587553A9DB639F3843EFED712A9FE49D67C197615E1930423A24D464A113C76A8545601964EBB9AF89E236A2021D25D5A4F71E592716BEA4B4F9A9BBD46A835D49379873CF2B0129E236DBD2E510F2CE164F08307C4EB11CF12AD26AC9ED8863B0EF1FE28D2FBE71859BA4340B13DBF103F6A1A855C4D51717B4B6435E6A34F7122AB6C214028766BD398C6A03AF19D67D7E9CE96EC95FF00CCB56851289D52FC2F2BBD6CF27F8D7BEFCE6817A52FC06A468C0BCCC6E27581F11A9394226D7EF8E1E7FCA24295275042F14FE0BEB7C1BFA5A1161FA57796F21C5860D6CC3C9F2D28F5C3EB0F18D27D9C512A4C7D3A3C8B55E0452405643091F679A9352E2B3EB74C0562DD08A45339B1517339C19B88D1E6B13E341C7B932D3613CADCE8B349EFF25DFB15B9306B0520006C72C01B8E1F5D625C76778DC8ED95D62DBCC655500EEFE96F90C8F5D83E4A9FBD2BE87594B6DE62DFFBC056824A4E4EB61B6E83AB9BDFCC9804FE3E2EDBB788BF3E421E62644BCF44B8023213A8FF374A14B8A1EEA61830771C6E2B48AE0AC68B14601D8AAE182A840F98198A8BECF4EC119EECFC5D7FB4D2920AFDB10968F70E65D2C8D5C8102DF73BF6AB44BDAD9B8577FAE45C83D76A3C6E425664131FB3F38E5946B47C0C9444416877D9FD7F3923C5EECAFC435FC17A806C13D79055844164A8216A605615312EA5792592AED524608BFA44DF569B5C6DA880DAB9C2B7CC0171C785ED77104E08B61C7B7625E80EF034EEEF7E13502CC6510A8EBEE8D7C2D6DD85A6DF2D13999042C0B3E78C0188A741B399E212FE05053B9F166EF9B876B17AB413072CE8DCC6004B99233B73F1E9C494B23457767C2197B101D9BAA41BABFE33224B2C1C112E1C3C5F099320603968AA648B2792E7D0F009C1C7C33D6CB5B94CCAA72F7CA5EECC827F34457DA961B39DD98A64C0DF1A1618DBA84681657E108C8620723F31F04728814055924B638319F13011EBDA0289A0BEEB732ACBCB71FDC411B9F981969023F6A3F8411D9D9681DA28DEAFFC84195A442340A537244E69989DD7F5A0F9A33D9ADEF27362321D4CD3A6DD3624D98E8DD1709C3AC48167D91CAC26705A549CD2E0C62621BC275530EBF37AE97458C3CA841E264976F2CE212462AED47D5A0F6EFB27BB657D47BF6BA303CD66FBB1C273A83EC36A4A2EFE2AAE0CE1FEC1B8740E83A73DF7A3B24CA22BBFE52584824445B2ED95D8B8A0BFF28DA14D382B8B54ADF00AD82B3CD5ABBD4935738679DE633243B4C6A6CFDAFC43C908492CAC991FE4000124E0745CBFC21FCA91FB90E6F1183E5E96F67240DCF790D87A569F6603B185DFB5524BFC6959F717891FCDF39C7B66210BA5837A5645C62777D83C07125DEF9E6371991DA53E79A7B5767B6FA08450A806B2E2148B50F9FBC79FC66C47844E3CB6EA74C7DA86F313BA8C54F0FAC364F5C0D49F2C10238D44446AB58EA8FA3B5A5F14ADF3B9FF1AA225BACB62F3BD6028EB1066D7DF265BD210CB4EC7DE71CF028E354FF81B76E3C621ADDE054CBC1366FE069ED6F99BB74DE007B9E2BD31D1A96536F2260FC137AD11C5D2C2108C2C8F3C893F4A6C4A7FA2DE0AAC7931FB85C5882933C128A9C3191C35FE3CA022427B6AD9447A09B6EA0AA9AD70916E9127900DF0457C6B901FA2740353988E26E4B9BA1711E451F375029FED9AC02564333761603E99A1B725136B5494538C88FA2357FD7D9C", - "9F4D899456FD3841B890A61EDAFD40C7B43FECF9D700EE269E58F40BF2CF47CC1C1EC7F28D78909A53C7B79C4E6AFD275BEA739A3617E8B3C3C77ABD4EB770B9E663BF154E77205ED1F2C5669CFCA18DA365B988499547B2C36D4A56582FC610E06E4D43E54CAB563B7E5DBD04CD04EA83DA72645F1F26422D416AA26CB2AE11C1EA270CF7E7AE3679FC2D69E012F0C950FC64A56C7B766F909526EFA0AC383E4A28CC5C52A26CDFD2C3FD2AD820EAD3885DE63114DF5D19A2EA6C2BB338A2171C73A7C10AF41A9E4F0E49142B363AE9D306378B3211CA3B0F21EBA2E72BC131459E9D05CECFC76D6E540587073B0CEA1EE973B56EA2E671353210885EBF3A6465C1D2AD12C89217F1ACB1B209552F1DA1543293D6D1D273C4AC5AA5A4B9D2B368AA82A7FF8E10259FD1FE52BA14F45A40F72B75AB7DA9F73DAEF5642CC1744E6550ED6CE2E547F33598034E8970A74D7B1D58FA2D4248186083BFBB8BC1A34C744B6F08AAC374C28B1C0F9E8C2B220C6EF0B5C0400D3B725005A711EE66FEBA353778ABD4552DEF9E5309FD0002FEAF1F3C5AA3753CFD7CFD62907CAD3B1F68071C01886748201050E39EB0DB18240C5D598D213CBC508B8F0EE7708CED659CE85BCA8BE714DA5A607E023F9609EA3D790501C4A9969FFCDC7B3E7317F6AA6B99CFC32FF1B74AFBD42A9773EB0615598C943BF55C1E8AA3B85D5D2EA2892CC33FA809D71621B02D141C74722397318B8CA0F4F9DEA01096234025573995DD2F915D35F7EBB6F7F3A9E83C2D23D769B639042FC669BE9778390A3E4404C04FC9991FA6860AC811BC07BCAE69756FE9DAB27B91B91C51892D61E94DB2B486C25D13C225810620023F1B9FED1E89B002B7B11A609FF348867E1CFD827199A5F0D6FA267F60F89B09B5A1D8FF62744B386709990589D0557F5EA477974CBB87A86F2E6E94B758607454E3937A539C85569B5E68ACFE4911CB053CE207394B686B962A7487516971740287DE8C51CFD26A14AAA3D974068D227089093812DE910649512D966CB97FCDED09F4BCF7749E16E3391B75A4846F65EEAABC5A1CC89B1D9D52C541DC65CC468B27493F76F6D68AFFCFADAACF20BD979CD63A42EA3B8961EAA2F731C6250436A5A739D3E015FB32E07D373FF650CDCE417EA85A6DB8A9A24FDF62487855DA1C807943154C162AE17BA4E477531100431D647F2D8AE76DEF070A0418D2365549BC66DCA95722801F3A77E435205E919B4B349ABACDB2BD111087B05C05FF01E4BF04F5685665B361D37634855BBA312E96F2C6314590E298770C3CFC4207A0FC944622D4CD7280CDF5AA241232B6B5E78BBE5C6684319AF624124BE84CD2F1512E89D6CAAB620009206AAC993A9F4D6A67859C20A8B9307D8F8E370F2E600A9B363C2A460E0DF5AC007EE110F4C088CFBC2EE82D623D5EC42DB739C2267DFC81C830244A6DEFFD4966480D6EA8D258FC047500062F42446230456F9B5405610863500A8AE2440A00CD16E5B6136B0BF1611345CE7D70319962896B3F5E69583F8D305B760E0ACFFAD762DD06C54EBF8075C1B0ED97FEF59FBB48A7A65C2251DA406D5E9E5F67586C64E5F8FCC805DA4F33BB583DE2D5F85A348AFF0215233EF88C310FD1343934F5AA2A2AAF8F58DED34D0E35D210FF01AB4114E18019A2F7D6927FD843F842AD6AA0E171DDDC2BCF6B49EBF5D91C35665D8F88C0924A453FE96CC06617D81DCE66A3C813F1D3DCD5C37E60BC672ABA16C2025C78E9A1A6B1CBC4C02249AACCF55862C538ECC42D0169B7E3F4B188F2698C", - "47A3C0CD552EDF50F80D3E5FE68A22F85EFBC41BEEB787E5CF0CBE3266EF310BA5E1B29A7FFFB0945121EFCFF811A1B7DD768D3ACFC21C4E6EA1EF06E851F2FB37A5F8E0C49F59A28A4CC2380A0C0B4043A7493320AF4E34A2A20E36A6BDD2AA49088FCFF24C84A4D53FD6D3B29178F921768F21C5827D64C125DE4F7F435C6BD000BCC1C95D0F82D61581049CDF2A34A27F2D9DDC409895B9742443D0CF74F8A7DB13CBAD88E1F1D6F52E4486809E20AAFBFD82B297B038BE774BA13649ED922FC67F6DB9F0864B742F6FB60E849F9A253E8B0B873C8501F72D3523EEF62C1430350852FD17177203DD2BD4065984190EA2075B5385E1D29226236ED894DD10FF82F1DAF16AF55F0940415685B3A58D1DF7CE0B0F069F33E6FFA29FFE6134285CCCEA2DBDF1B901A700765449D67C24766A042D43695D1F5D241974E62817FF9259879813F37AB1E8E51F6C654324118E411ABFBB6448E9EA3CF1F636D2142D65775EF9FE046B80F0DC1D1480158D603626F7002290058E62DA252328927BD20C05E5D3BB0CDFB6C60C04DD8BF4A3C9413241339AC186B054B34B24D9ADE710A79978158F1E2EA5AF6FAE9077CEFA4E335473D29BEEF00624FE6A9DEF0BA52464028BA25D9A9C1BC85901F507AF046D56B17CEE0F23433959CD7F1085481697808B99EE619BD0500B55945186A81B89A9C6B0E32F1D5196C4787BDBB08A6F1D79AF329B38304B1203E9B8093146B15F1207C7EABB020B72B2B92EDB95377D698F10CE7737FA3DA501E0CD09F3FAE9504ACC414E63F60E2721E759CBF2CA1E2671A98656707F4629626219E4F16D8A765AF3E75DEC1B6AA82622916E47872DF33689D820DBEE6EFF26E70F61ADB2EC3D8FC9A0AE30F12E3CC5E9A8E1A820DA15952401D3910F6F500D4CDB7D85401AA4C8F418F7E2A166B491D5CA3B415378891B359112894274F25E9DD2B391A96636D468290AF22FC6BD5C2E7842AC5A62BE24D80E6AF79C6F2118C126D60720601272FA89F966C812EB875052A0BCEC16D0E6C973EBB683214ADAC9BCD0541D32D33AFE16EC2BB424EC8BEAEF0BB8A3DDB18EFDF58EBD84B2DC8C7AD54B86E698BE762E73CEC7C1DFB290F6CC1B63F5257FBFECD9EC87D8DCD2FF393B1C1D1BB2EA9BC10323E6CA3EB8EDCFCCED055680109C03C5C668BB8848F38C4C3369A4E5C0515C7245B0C092F0B8525434468E775F40C4D4206B6420039BE1F695DE802DD718B9AE4FB41320C220F6B9971A4CB8E67C6B0CA3049C2772D2B3C1024A502B48362CE9A1B84BF4C9D47D62409B5CD9BAF1E18DE57E9BA9CCE077266D720DEB23F192C70145FE201561AA2A46B55F9B6E5BC8FAF888FB74BF6510AA7E6BCC40DFD471D6CBD2FCC28B33EBC763E8CA58D5D74C1996D66CD827A6A6B9F22AE7C24B13799A7D0A9C9DE940CA217FDB870A1640B55C69B2E704EA21262DA831C7E23411D81773A965DF6AE015CFAA0D5DD3890D0327C514968C2F72A02A0A35243616AAD673DCF57A684E1C9A6B6F35E12C09553AEA89DD40CFF53EB16C5EB9F98B6D04674F8DE9B6AC125B8B0BBFBA71267A6BFBDE26B64FFAB35E5C5F27B7CA273B901D28997E6298E610404C07569E906AF09A968A9E40475EFEBE524357B044B964136C989FFFC70244DAEC0CE3BBAC48B5A0CC79F20AA1E58DDEFE7BCC9B3C3A04EFA49769A50F81AA8F3D152757F33E935CC6ECE9959B47BB90810BFEB6108C8DE4643B24B4154CB7EC3889F5FEF9045A59E82300275EB4D379BD85A29915796B8125351C1CA84EAEEB7607894508", - "C9ED53081796789261D7D209BF086C92C36B574AFC6ED55C3410E0723C799696D9E7DDDAFB114606EBF4256461FDC9B86BB21A134F735837E6845571F6C2712AE42FE113878AAA18C76D5383FBDD38E43FD1314166DC0B7CFCF3F07ACA56740A582173D2DF20F7E94F0CE29693AEAC6B3D1E4B22BC63395BDA6B49E30B49261FE045CAC9AC29BE5A2D91347EE4543495CCC1A38CAA59593BC3DA05611BDC74806284B4ED73013A415E6B36BC2CE31181971BF4C7B488E78E921C6AC1070772EC36A9BE74DA8AC4FF68B6210A392866B689110D9BC2C7ABB2D82A38EB990891F264DDE5FEC75C6B4E539F971AF2728343F1641F4B05EE8EF3A520DC170B3D8D562A7AB72C409995034F6CE1C258F486ADC9E44FEE47D5E81BF1259C0AAD3BDA4A9E17CA9C74AEE77FABA25B3481C0317199D585BC75BE5A774F8D5CFFDFA9FA652C4B14E29AF2DB5ECBE682CA724BD98E05BBFC82320C8883A56F687F840319DF2D8BDB3FA8553BA3FFFAE0D4EE33E84B62228F924A86C5FD5B3E12672DB6377D807356144009F741325714B5B6AF0803F3DD1AF558C0B76620F77056A18896D2047C967BF69ED972BDCA50409929CC2E2DE802ED09EF87433B978A850ED7710508889EEA4558097A7FD83EACB365371F80FB6EE1F7A6D258B97BF1AF9C321A629A5AB7559CF1B82311F816836E391BDAF741E493298B49C001783921ED1569C149C90D26CBA94F8604BFFC94FE303CCEDD8812A95F7B0E71DE95869D2515E524083C7B2E06C4B5E9DA12BFCA74049F03A352C15DF3B79C3F2015E86FA527BEA76102DCDDC863263F0C7E43CD9D49F05D8F6A124354036388FAE37DEEB43909E415EF9F5877D04CB5A86AFB74FCDC990623C9D4D034816E39B692B68B732322695C97CA93CFF0FE7FACFC1DA29BF0D0C08D93B4485D6664E96B09C8B011B3107FF5232DCDD9B3B8DE7BFDB4CABF31D2E92AF686EB8C2FDFCBEB80B5F5591B3F7AAEEE0FC7A3E4BBDA652C8E857AEE81F499D9DD537139B7A6275C64DDBDD17BFF7594DA69335C01AC24270403E880987F69D4EFBC2BF2B787A631859241063E7EE106D3EFFFE60479A8BB5C11ABE38A76804D43A44327FB4D4F986BE3C52DF109E4D72A092F25CE7FD384B0404628936256877CDDF543099D5B0389A9E05CA93A2B12C3C89BD76F55084A03148E29275159DD41A75FDDC75994B8E8D9FB10E6E80A4E30E2CCE8F8DF3FD7A8DD567BEFF109ECFE3B8C843BAFFEEF5B70D5747471FB84DE2A26747DC73C9B2BE9905C53743159E489E1D0CC14E72046E4C8D84F893CFC7EF15CD9F52C71D91A503802FB5A6813A7BD2DB705BADB58C06E0883F0848E44C20A4948119058226031B5731F36B3A9177065BE9A0294F726E80B5AD2F2723B8698D831DBA376061FC2029979F0EA7AC4BCCD87B6A432051DDA7AB2387260082E6D3BFFD3B2ACE807FB6792DB21AC235C1A58D9E47D42EE055E716D389066AB0814B36291AC71B0AACB666F7CAEA37B89CB424C4EC3CBC68F97AD6FCCF5F3B5094E60D68C2F1180E5CF2141EFC84DAE7509490138E0EE466AE0C7469F4EAB2E5ACC29EBF2BB225E595181F96700B552BC0E1171428FB2A2F0448463CC86DA6F7DD10FB5F789857A29FFE9535D7CA35F70640B9D4B9862234554770331B52E42002D123560BA7DCF9114BA9B8B23D08C3240E3EBCB7359D13767810AD3F3F66A8D698D17F20DA5242259090C0A9AADB9385A2897A5A1F32A7B1549A45D4EA8787523AA210BCB55AF6B15A1F150E79FECB104CE01DAC70125FAE9D1B8D0", - "334994DCE050CEED5471E648F7010ADD69AA0CD3DBB3679C9D3863F86319BEAEF1370902CF4978B8237638507B392AEFEF731E6FB42DFC2A23142EDCECFBA399F9C583866B1BFD7C280CAA43C2CCEC29C6657654C251F7BBC0F83E2C356934C825BCCCB36073A5D540AB82DB7158C7893AFF166B108363405B206E53B13A51BAD149AFEA2A40A37328D4CB3961C9EE2EAD29C76F70FB4E6409F468364DDE7A2439D24FBB05719A6A489513B14229E1949142301AB538AC775AF716707193959417B14A65E2D20319721FCAEE6364D04C480C07D732AE0182090C517B96DB8FBBF66B8B6FBBA35CDCFC87B1C8C0F2E4ADB486474F842434CE9383A57B69D4CDAE68E5306DFD737AB075A60073846634AA6E2A6D6F7CE56A631FE1E3DF256A1E39F0C44C3EDC3A9457EB4FD4477F2AE094979599B9B90EFD1BB9347DF2E654BB9687A2EFB857D9AC1306E20769FEC4329BD54804354E0235AE443AF3BE01E26F0D5998D7FC36DDFA5EDBD3958623B6F065627D6A4EC9901891E3C63522744CBC48BAC51BCC89602D66D1B3E0966398927E869E73AA8B986D9FBB428BB3A71AE7B273A16228349B81927B53DD9B7E96E3D078F25EE564495BFE7B7E6CC042E016499952DCD37F171C709D4734CBD8D46E7989C2C497B5EB9613DC311643ED4B1B08C0C4C2A5854CBA30AA225C683913B5BD46E1DA483BD7EFC2C469DF017BFCB5BB07C64A68E3CE828A537115A07876D30999468358869AC7681380A7E462ECD497A6A6FB6AA134C15C6BDF89A2B8D58B875C00892C50A791D8A50514029F790F7748EB0C1CDDBB07AADEB920238F9C19BFA31097F9AE3B26509DE5C4040CBD82C859EE7C4D094CD7CF8F04395684BF7BAFADF75027B4A47A21CBCC6E3ADFA6A2AC66EA32F670F49BF245F6CDD0FECA201E3E7706F8E37C25FE87B3040C0D8431A00FD4B49E7A050837560D458BB5C2E93986EBED14944F9E92463C312942E6D8340BAF149042FF611DA8ADFF9DC86CD28185555E033F3E22856A80C482D52B2EB21E2D51625FDEC689595EFC3160351B5F30E1B802D5F4F35CFA2C25D8E4101298E6B0B917B5ABEE5DAE3CE09DA595122AA3BB3D8BA8BF0D68EC99C2DE8B4BD7C2A0E0E32ADD32D72696C43C7CDDDF92DACF13D18DE4A1403D0002454E7081B92EBA207DF9411870B91CE9DCC5E26887A437726B6CE2B2DC51907FB108EBFD2F089F893A6D5B5141393C08F497C180AC4A95357E417D40C5E7FB324F0D72F417F688D45B980E215DA436CEAD3794A135A719942FD0C998F3F6F165C16612E2B3ECD4CFAA9A18631AD9D878D63A8E09B0F82C12EAC730E6C5A083399B7A098819F2F25FB2CBD1B6E65E3C30302CEC61680B699F504E5AEB959370E32B58B9FBC832F85AB0846AE4BF678C272CADCB5277EF13A38B1AB787F8E5344D7DDDB074A92DD68A2A2F9695FD52DD685E4316FA7E913DCBF34C3F0D9E9D22CA862D76DF3B5E9E3B54992A7F731C893980F151BF29EB1AAF677B439DB6D20AC69A5A41166799FC54FA68AFFB8D54EFC45B49E25A93B28E87E41CD7B3C61FF24F1D0BB74CB20D2A8D817473188FF8E56EE9C4006083BAD781C3F46BCEC777B2C72A9A3F551353DF186FF9D7B342D86629C4085FF2108B98D8EBC886CFE3C7A4B673D447DAC5B1DBF6BE6064936AAD014C0AEF0078C5D1A626830C480E8B72439C9BD0ECA0B41561E5B0D6618E77042FFEB6CA0F29622EB9F21B83A4560FB26BB98468F33BBFD5CB29AC4F45EE9D68A1E5DFA757DC218B536A9231D7FE228925F96C32E0ADC0", - "1B2A30E6054391704DAD57B34530294AA46DEEA044EA5E707811036742E50DECFE891FF88372A4AF65CAA193E1D8DDA016ECC2A2E3F6D8F2DCF9AD1449C614A70D253161E2B05AC67489E13345C779F3D36BFDFD7AEB2AA30604692969E0C4E375D18293D5D3CC39E31189698BCEED3290A2CFFEA79EDE157F2A52B4EA52FCD82DC4BBD11EABED2F311DB72EAA53A1B6811D03D3C2A30C76A8638E6A775EB3A51FFD4CDFFBB4B961075E6102D2E5555ACB06548D119ECB6895AA00394D4A98C8302E02F8D4FC5CA34B405F25D2B090932A10A4A68CA18D799C1DF1C86B1F88AB219D69C25CAB6AF6CA0B3A4AE390CAE3AA65D3AC95339EE734126226D1F292BA3ED968FD2CD835F621C3CB09E59B9DA5CD23163F573821FB64E296853A8263AC9DC896D6E355A4C4377BDB4E7004CF399C0891C1D23E39F03CDDD94DF7FCDA06261E923C9E0FBD8DE32B49935A03E66C13FE7B00E83674E64D5CBC14C0B9F62A842A17551E5E7001BBFBADAEF36228513A43D4864B8D2C8B272562A6B548C0B3E4610609191B807CE861538B89FA079217C91745EA61ADA6AA96464A135DF216FE5DA5143F55D76D44131FE6E329826F2BA062EAC329161C8D158EC7A3BD5FE57908C7523430ACCAEE3091FAD4B14DFFE0DFED92F014D19641EBAD22052FF8D262D39D6FAB21ED66A82CF8336FE8E3CB3641F15EC5F2E2AC0E99CA07223868BAB78DB3A008B233FCC7966D816082C231C18165422F7123325F365D257FE69867CF0CCBBB875D5153B8C1C0300EBB1AFBA3371B83488143EA2562FA477D210BF68251312A7EC26BC837F9D861101B580249FF24C364DA978C0F57C3A3C29F03F3696C04A3CD330247DEC04A385739D90739847867592B09DF211D8B349FBAA760D64D5E00C9D596CBB8B73E7B17317AD315004B35E7F98672085811DCFE7C86DC0169997F2F9EC9B2B77B97FFA6CE2AA70E2A1030BD3ACC5FC3241F291D0304B71D727828BAD824445226CAA77E210A48EC8F79E0DBCA01505D1AB9F79642716146F7A8F9EA25238FCB2F9C46BDC1489D35B958C44C7928BB4503DB8DFE4C1AF5406C04575C4DAB11995BAC0C7FD72B10ECAE376937B56A035DC0A4D7B2E1A180EDA4A84F97D53B57EFC5562643AA62C37211C2363EEBAB6A2AAC22FFD0BF623CE6867F3C50FE502FF535A68BED2FC98C50BF673B2C5BE8D7D690764C256CDED17E4023A04E70387EC53947395B00E8ED6541CBF0B076AD2B2A26CBF220BC665598D9BC1D1EDD309E687F7D1E7D71F4B2C1B5BA020EFB1DE4248C234A68670916EC8A72FD1EDAF0615CF3FA768FEAA586B08990E05E24E7D8E0DB32F4370CEE72D74BAAB68F6E57F2B9B0F51691990DB46DFADDA7503BE7F64A13F5EB5D49788CE21BA768D028037BBB06F3573CCB244CA51362374776B9EFC776AD71AD1F5635B6CB73822A112149208F10E657E1297026113481BE7C862FA099F331FA5C6B1099AE77D4F6DF2C74736CCD9AE8342287986842063A65845ABF45BA037441D967FA102134B25BC7F1F9E8BD4E54306BF8C36DC01A500F4A1184D7412841329DE6B27BA4D772B1B2B68348228037A9A048C0989AB12B42FBEC45C69203ABF843423D51CFA2D67FA548BB39D0996D4C215157C707DC251032ABE51686BAE8F00E0CB4EDB664A3CABBBDEC85EA7AC7724A461F9F650F9752C1E5B8DF204C3520CEE4A51BF8D3BC9A0AA3AF9D31B95FACD006ECD27889F1D0D1B696DF57403EF0E6FD83164E5900691FB29B19BA4F64084ACFE98567987632483F2EB2CE76E1E0B8", - "5513F3F1C262853F074269AF598A2E43052CA2C0141729078A17BEE4CCD35B761B1766B3C118C06724B0459AF3E973110D7096044F5CAAD9A70F3BC7AABE628848D2A4891AD18CF4A3D9BE900A2F42F5D54AFC7FDC7DBFD3155F9D06078C89F8DB684B62E4CE0DC0AE0E4EE6F0E26A86CEC1DCDD96EE175FECB827BDAB3DD53D465E796FE4C49F46B0B6BEFB951BB1A679190F3FAEC58C00E2FCA744A97907765A3834585E4E00B952B5B7B5F10E34F43C8EA3F46C58F8E31B3239C0658F81FC7DDD5049FD8D67587C85C78C12CF122CCA327A7860A0E34A34DADC677F82014EC7217D2710112B6C0067AD402A941877970C95097A47AACB74A8DAE4C9B5F360B755EFC4546D7D63C580F108B197375AC08EBB1F51E8AAC68C39BEE69EB886BFC2558F0A52AE16F514EC168992775060A5E474E8B2A1180C8F9FD6F3E106963DFA09D48007CC276C1464B00C86CEB1B7372684ED6BFED1DBFA6248F4725E7F8123904BD0552EF70A2E21B8A078CB90EBE75B127A1C887002D70E32CBFB6875138D8DA5B312A97AEAC2DAF9D6506FB08FAA9C334FD686F6CE07F4BAC70766C6FDB001BCDD43421CF70B8B33D22795303769B2C37D25752C9C4494A8E8A0D9A1205A03889946833C065AFECBBEB026E95987C022CFE65DED4F4CB78ABD4DB2CEFC3D69A4303EEA5CB2E8F39A2FCC995DC4BABA644F65411F6809891DF1C0958FB281A7852C8330109EE9D87362F461D3266BA8C2D3E82C9B1400220B19277649CC804A9FDE4C2730AE11CE633975EB3126E8AF60803DDB5C0258F7974BA7C93499B2C2ED1E71CB64E61854D3FC186333328D14A12AC06586246EC7621FBF1BCA2578F2E16A83C9A6800A378C8E280C7F3378CC71011681C884B83A56865F138FE35C123E28F1FD461F60836645A9F9F8CE211A8FD6B07D477674A34F78E3B916A7AC73A0AD9C8323D0229706A8C2214B5ECE1301E470C37818D68092D5DA3F0F794B8D476878A5B9FB339999F5422EAD28A16D8F8B39CDE00D14B659AD8DC33A46F64DDB8E4F142FEAE8A9F55B94C40D62723CC51EF718C0DFA6D9799AA1863498173A0659F816FDEACF2DDCAC54C1D535E1C0FD9922B333C780C1149C4B294AFC5CD23CA8EFF423A3FEFD0EE1A5B0CB28964B8E80C42AB660665C4B55E06E44557689AC22196CE641644959BC7F80D1AA828DE75CC21E0A8FD211BCF6185A7DA81222CAE0B632A7F98484ADD6E83A220CD49D5942B7D16309AB1DFB705852A22A4D51EDD96DB3E318CAD7E96D5531193DB24B50D3EBF55DF8214093ED0491B037E1B38FBCED71199A063ED101C227A10313051F0B4BF4142057A73C491AEDBBE916CE4BC05D1A44FE7A2E7DD76CBD24C13F3758BF7E3BB8139690E33631F180ABA7425DE3E512B53663CF9A8D1B28C0B886C655AD3A03FA8698A5F5AB5484E3CE53CDE1F34A66FCBD734D15BEB727B0FDFDF68BAE40299C73A8F455ED471C82F6DCE240B3BA4EF6364A56828FE2D6BD8DFF03F35F5C6CBDF0C907F7473F24938016615835D801598409F1004C478BB1B2283AEAB437BEEA2F5FC51D8E43F78C0092ED4D0B08FFBDF1CD60454D3BFE6EA1F41EDC5EEC06357DB41F73CAB23556634416369365D13FC8FF9E20EDD8FDEC673F0BD6C8A1EF60E394B596B70F751EF0D9D7E8D573E3526D2D90325B52A08D25F18DB0E6757EBB6002251809ED47C85D4FA37C5890D60B40BAE3AD22258BBEC4CEAA1B6B585EEF32615F7254268DB82532BACBD9C553624AFEA6BE2AE9E1401F9BE05D68A881AC8D9E0CD437F60C00", - "7831C1BA1031B6B0E0ECE28BC7E6A8ED16E3068E8F0006DA96B8740114397B19AA19370B1E1F061AEE3895C30D0B7099668BE752BCD8B1CCBC497E06BB0F75AF47A36EF8925A59E070115D3ED63C6D7FFE54D037B4A818703F6D78BB37725D7F0AECF6CAF120A80C938FF44BFF16544C7847B1A989598F1602A220392CAAC2EBC390FD53D15CFD3372426CA41DCF816E29C731FDCA2E84CF90180039FB1AED0DB9630BC28D54201D5606906091A3F867D257C3A0F8193DCCAB2625D40DE5EDE651C20F2DBC83FD551EF46C4E724D2C516560749AA89D35C7283385E98AB34BB88F8ACF50A0EDCB70888DCBBCF0B792A5D1F2F6977FA081B4EB08BBDA076A43BF1EFCF1C387DD5B92BEB5000B4139938CB0A3B6DFF47B729BB5826C7E188A177CF6DB1B88F051B537DA014B396645218DF4EFDB0DA597B3A78E9884DE4A7B3D06C259C10B78DEA1DB711CBA8FAA2CDF37EF0378091E408960B011F4E4FE24771D0FF3B8DD01DB0527087AC5C0F64EB693D38E0A128FBCB8053E811602A05F3DADF2166CE49EBA13F382E90EF4A143B2CF4FC12DD4873A40FF7354C6E648A56623457665402632C41942D23001C08470AAF1F3FF0A474AC6586C76915FC91AF074103A1CB9304485F92F9639399028EBBFDF9394B4BACD6BD3B2177368B94F639AA8D202D6BCA88D74AF0610C7B565067ABDE4F2BFCF8CFFAAF93274CBC913EE7DC5C77BBE978AB9F82B546462DB933D67E0C6748F943F39B8FD6791847C50A5A834A78C2FBE5D21448A035D83D45F9ECF44C21C4DE726AE8111CF277049331D78B06E9D7D3D0D8915C7C32CD6954D37045E7AFF8AB496A4827574C457523AD6B85F78641BCC4C9535D29B3F8AB4D944125E6E54B3B3F23EBC04BAE3AB102977EF829337F51CD833B4F5D4559D79E695470F498EB4388E573D004D725FE41AB1B39F9526867BF7B99301E0E50AA569B3B23EF78D02FA53C4BB2A184B02977F2D2AB3B71DB09E3E8D9D5B13DB8AEB0A95F9296B7C49B1B3D6903BEEB1B9792B5ACC1A5D11672CA5D8E3825D044DA986D01F6E1E292D74443583E49CEFBCA177BE275977BB4A4F77ECD6FEDC886B4B83AEF5F34AF1A78DDF6B11C201760175D57823DEE0FA5C6A9C1A91638561B857E993779B6B0576994CE86E7DCCA4A89BA2ED84ADD1D8B4E11446C41DD4B1EA71352E26B2AD4B8A1C5C64822CE21BA4B8D7D6589FCFA906768A2BA0C5AD1758AE7B8A2BD757C8E459814CBDD6375DC58497279C0C327F67D14FFA5C90167941CF9AC642B1693D7DE52578AAAA56E0EEDFA4CC12C7469DBFAEAF5F9D3D72FF103918B6F6DF7E0DDACB208A8764B459EB01092A101D42E762FD5C5AB381AEA19BA6EB8CC9CE138892FEDDCBDBF818E97EA8AE9846C0CDABE9B4FD5D80431FE03A4CBDA566314BD1AF59AF120EEE4105E1B701A4058F1112F2A5C8D9F68EECC870DBE78D851F89AFACAEA3A2A068C59654EF5E5BE2F6727136908D993434E5EB1B84331119DB1C02547EAF7C9DD479C5B326CEA6224B16A2E108E76CDF0C54D16E472D0CBC80DAE7980713602FDA31A6B04E4FECCCED96AA3901D7B35D445BDBA020DDF1BE5E9914ACE600ED24E492138F82AE583A2EA454EE7548882C1A192F11345A3F5A3F2CF64B85DF6306F7FD396C4E773FA66CC098EDB3CF8E5599C2EA13A6F726161BB0C0D6673F02E3DB24FF75A5698E91C1522424D443165B52C90FFECFFCE6C42656138BD85409C45D8AC453D6742B42A43A7626E70C212B7318834B7D29CAD0C29F22E6AC3A59359B1A75F727E1DC", - "30B93A783620E3E094D47590AA38B10FF12C3E421887E9081F9A9C5BA1D753F341C33B7322187317C6610EFBD0382DBDC2D863C48F15AC3FA86B3C5A5B9EDB937AE961E8EBC3D880CC79141B79869F95D6E90C5C5E7D9448CDACCBDE184F6FB545324995184770CD2838B61376B148ADF3A42123AEFCF8890CAC7D3AA87A624DF3B883E86AA5FE6DB385778F50BD4E528C6604CFAE0E39BD949118EEA3972327EA355EFB98E9DB563FF72C5B860103AD262BF34BE17295E37A81D1C98EE6FD6690914467048A50AF09435A68FF9A70B59DF8FA7A543BBA24EF8E13AA509C7A311E12773405A4024A0C2D7C2802025FC48E8FC12E4B60543001971FD20F1641B968CAC283BCF8140629DA13D1289B7130F3714B8318518770EE1399CECFF1D3074A65F8913596F92B269529B5FC63D824AC7B6390580C516BDA78BB1F158B2C69AD2FC1BC610AC24DA696F44B58DF813D9DA52529D325BF2B3575768DB43AC3BE5D0402C717FB587B6976E6701B0A70D04F3250B6C54E99983E2B1057DFD9EB7B621504A1004E7E67B33B138628EC7C43A199D00D9FAB8B1990A5FF29E4399051D1C62AD0D86B651E9DD94D27DD6A7B09AFBF1EC737B161A4A398F7F424889C0BE6FBF8EBAE9F1A835FCF4AFD45FB36919D362CF73F0786D93552A7B4E421EFF9D6F98078F85098DC99A1009D6551F02B60E12BC28499A27FD7DEBE1047CD44EFC0D9081323DC08866DDE79F8AE34136B04787F6A5918F5AEE705CFDD5071ACF8FF54A232FE39E1D79D82EFFCB6CE1B68A17B4585817CC9AC33FD6CA21A00929F1EE5B9E3518B27060867624D8262EA18F1B01A525EB6CB337B257C8855FCAB72D7A83DE52E4F1D5E29EA697930C25109182B95A202E519B3757092239BFC633C4A7099290FF7B99FEBF81DF5AC41366D3DAC3384C65AD0EC84F0DA4A0ABF7D8E1E2F8B898FC97325878D911512F1FA5C24F009856D44123EE49C77370F1D58E8476542384A0E45CD852D19EE00025A8BCDCC011BD259AD7360D12B6A630BFEC8A97AC40781694B0D5B3D50D9E843FFAF7A023D451E282FAFFBC38BFDAFEDB34528DC792ACD499179ACD26AA3765523E91A137F52BC959D5969B301B1893564AB348606864916C8D79DE6FFBDB0C2ECE83B0A3BB846FC37C7D4D2A37B2B841CFF9820DB444FB090B430D9714FE2ED731F097FD30C2ECDA7B6A276990647741496729219F244FBC6F1CE02F24F98D0212AD005E54F242A77858622D6BA961190F97438FC4B33217A84B5EA9D3471C27D08C2D52DF19F2DE486C9A5EDBA2A56E1349C3BFD312B8927A9E86A97830DD0B11F505AC481FC6834F8FF7D0E67126033502EB5C593D15E1A56DCB03ACA1A5DBDBD6E6FA9DD3D7D152E8FC1741BD876760F99CE780EA5BDC018022397587357614ED37266C69AFE4644D7D5259770B85B70E7E395D2ABCA3FAEDD5AB32C4B61117BBF707A58530EC435D36370D6AD8F9DA503F8994F6CD627336A731BB149D3D3E96075385DF8CEB3D9B48757A79C67C0E0C701A2CEFA092D5462E28D12548FA041C5407AC321FF049B37225742345E065720A81098B5785AF12927167ADD2F72F766292F421C290C2648E270C34443ABE5B95B7E635B4CBEFF74478F65C77899418C8ABEA6A4C3FE217D784823CB448A7EC0739C7166F4AF733BE758B6D5011EAA9B05ED995DC70E3D5A2D2298801C25049661FCF4CB2E9F7501C86D763CECADB0C86B348C7BF31DF7BB0CEFB4A2EE6861D3D9D441AFF4CDDB979465C1ED95692C5A46F5ABEC180ACDA140AD11BCD5B8", - "84D5B404488AFCC35CFC6EF1CF7A848EE5EE527B7D2D2081EBD8FA8432414FCCB271A43FD618EF95CAF1CEF445B50F02AFDC6B41D5C1F1FF4B6B8F2AB94F90F259383F44246B2D400C3012FD76E2980827C9B5476C4651293CBE9FAA77EFC53E369B94F51BE480EEAA389D88AE421E75EC67C76E30A6FA7EF02500372E4C9AB875EBA1C357C003938B979859B0A914D58F21B3BF1BE8C33A1AF079C5A0A4EA532F93A10F6D96D0A63F3C99E6F06CBC072CC5D71A517FFF40BC260A26E3A46688E79E733E1E2F0010846937689E2998BC769186E0B977AE0A1689245D255AE7D5F34715AD526E824838B62546D9569009A191BA5192535E23142236F4035C90D1405C8530A57B402118FDED2A5DA4B40635D2F95AC7CEAA370686F0AB23AB31DED369BEFB066909B76F2C04039E49FF0CFD323628D03C26F0BD4054C127F21355C33B49F86895D5354C3BBD2C0D38ECD169289F7D8403AA1753B393AC06C887F98315324DBD78F9BFD1AD8880D41D4EA98956EC89BBDAD08F7CFEBF26988EB5AB01D4E49AA8273CAB6AFDFA1CC1C95EDF85284E6570332A0B8242FBA495D87A01A945E61CD36E865CD4F430F04A3B3EE74CE0486B5676F7A938B18E1DB2DAE2FE1C04B3D56892C7394D0B07C5A2F7698D196711DC83FFF6ABDD4E8131E1106EBA23245FB0E2A696E440FB6B0B1CB4DD22C9720AC76F09863711647A7E369FDE5D6911A5FCF987470B8C06C4EF7063B08A8320B4371866789147E9D7C5D477A662A501627F91E95C6E2CB6814651E9DFACD67CA0B1FE62F44081E3BDDB964C1E5ADDC093AD185F0203B4C0F7E3E96811F14C79BC54F2919FCE5B653F6845CF1AC34DA9E4CF52EBA626B739246E25204F9EF2CCF4F5ADBFC53CD8F629FDB82186CB52BEB7136F105D3CFF9CCCC2610BF2C8F943DF5BD03877ED7AFA25CA81C4063E1B97452A937FCF77F1AA068FE2A26F6ECDF662ACDF18391AF7D627C2AA07CF5597B5F33AA0ED4DAC98AA73C8321EBF6918EE568ADEB1A823527AD75CD5BF7ED3EB5633A4EDC8C59DB0A91DA79C248D6894CAF9CB411F302635BEEF1A1C7916C7545B8BE7C577692245E285D32B4FD18E1478F88F8373E22A5CEC6D22EACAD2A41612F05AB2C54A1C03C0512359B0F9C5F91615EF2EA80DE97230480F489FEDA38D52FC84E2F1258CB20FF0E850639B31C2958BA6C064D0D0F4AAEFF313E43C65EFFFBB47CF09F2A122D15F76E8B704DA8F2B8C71449AA49774EBB7B2DC97CF6004D2FF6D37B9C689261189B85CFD50C20C961F22A644F51497377426556B956DB8C899045B175A8B9CB22EFDE535CF487E9D958281E0467539853054FC3475D2E142D58F9201C1DC6B2C1A12B2878F9366E2216405069B7D03852AB37EE83112EF2EE172F4E5317A41653A656A06F6633AF59062A47263A9977A50B9115456A58F9C3424FE7E0CC57DA70FEE0411C1479B4CC2E6E720B01432CFB3C503983B37FFBE38C92E50D6C5795443F73244F6D28AE6270E27D46A25621F86A2BC4259DE6C04CCAA657FE656C640833B290F00A1660329A3F09FFE60152A23925F4D8B0933AC016B5802CA863F66F8CEB5C8383B1180A515AE6C51B5F56597C3A004F8D25F8A6235C97B4DE38468B63E3B859A487AFC4320598EB6D143E5C914409D25F6DFF6E957D575C71D3ECBC6743CCCC03E5F34791744637A994F3ADF86966B4FE911C06F7BA1A6C20A2971D82B64E49721A530D9D5A2319D5BE0F47B8119C5A835CABEC735A935E23CB439970437C6F4CCDE2525EF0D7B1555CBE70280D5E760", - "A5029C9EB4623226D321FF78D3C4EAB1F672A8B2B24A09CAEF21F561A851323C05A3C5E136A2DA7104ED19FBFFCAC3FC49B6D598F3060E93552EA6C700B837F7CE04721919B9C96A57B42AA1D832307C7A847091848066CB84947BE5F6B54654479E39F654819D3EF7AF4939FB9F4C9B20CA7F83DA0FDA2F171FDB72455B7ED0D43206992520CDD86B29C48BCC687573AAC4217D0B7DCF852811ADC3ECADDB2B34B4572675CCAEFDAAA01F83561E6E240878F229698185A80E6FECEE89455A72A377C24CE3FECAEC2A34B9CA98D288596D1C769CDEAB06871316CA7D1DDC5862E6282DECE33F362C64A73E57AB266715068932ECC31E62AD2ECFF7C6FBFE213384DA086ADF49E30F432EE2C715D9AC4DEF53A7B09B0D722CAC560FE8CF0059B80428458282F7E81717647D72E321A3E4BEF16FAEF76009BD98B8D9822B771EB62F1D0748E462FB7F3BEE9B12AA86D9629085AEDF8E43E1252EE59970CFF66A6F865C7651EF83F8FE10EB0E2615BF8F5C7F12FC601B0CF795C0D8B7057F54408BEFF86747C0F6F23EF212A9086EADD464A25341AB71FBA4ADED8F599C38FC15E790A5B86E64977C5AC718DD0B47C1A476AC9D7369396144F6288E84F7FFBDE02EC00EEAE8ED415C84648364ECBEC42164514D3E26BFD3187E0641C216FFC57E00DD752CDA581686916221DCD1AF07582391C5FBEF047FD1B7B956B458DE925C02A756FE197233E0304D0E034FF9A176B5B3F5FB683AB41D2691E13F97B3F4EB33238851331197C49C60233232DA0E2610430461876FF6F77FF3CCAF1BB2424B8B347588667B48480476D40BD9E487468CD5AFEB597C750A5E665B4E7C4C169ED08ADFC731FEA928052C4FB85B3064EC07B0CB988E324893B3F084291D964403F0350B7E1B06DFB73362C38318B762A972972BFB76CC5C08B5D47DBA0F3A2473D7749DE9F49F50C4C1620A9EE9FE56296124D72906497411DB87D4D8EC4E1F79BEF27232008A2299F5317FC1A6F455F1B827F1712BC01814F0B9D0CC162B25B804278B9C7BC5FC5616B317F2050234A7AF92FE35A59E22C959C7163DFA5F142022BE5CC4D5EF16D218216C57C2E29DA926436C00DCB82E68E16CA5A07158D8B8864D38A765D14E82175114A28CD97D11D564C8C7B87411589A4FBD49F9900D08939B7A73B5E6466B6F607F8AD22120A559A02BFCEF6456E7AECE8C9B7C9D2B322D2197124C05363B2CBFA58B74CD88877F22A5E5C202FC2C33531125F1518F4F0F38FA788E5E6B3307A75EC73E545391CEA200243DD6D25A5B8654A00B82BA57437BF0ACCB0ED37ED2FED221E54EC12B93AFA6E3939223596075F4C47340355D7222A8234A1F65EDDA42FFF5D19F7FACBF09AA77E7962F4CFBF61A0F26FB18E31A504B371714048874BEB286AFF71B43E4739A17E8AC25FA77121ABBE6E99754AF42F1D0021EA1E3FF088D0734BB191F91A520C96E22B4A28F9A2BD7DF81E8079EE5D0DDCBD517046F12098FAF6920E0EBA10DE8CFB391C63C60D62C1F4BB26BF8B6E421A830575731F67D306CEB5D6FF04637144790EC4AA2F435906320114CB81EB40C22B271FBB065474687AA5880F1DBAAA1744AB3E9B831A932A9208BEA9F5D526C52F5FDA56320E123CFB553E2B71A595DDED2ECBBD6E890B0421D765D2E9FD0D3995DF2A9523A65FE2040710DF16F2A83F510DCA08493DC138541E5681B51EE87D84C9AC11612EB5C06F5A63E22BD6275E35216766D79B215DBD087E9CADA0CEB09BFE435DF9B7809A76DE323B373682B8C58CB4F08D9C708EB050DEC", + "3CEA9DA7B07B13A6CC0AE53DAD1EE2A0FCC70009338C08AC0EE457F76A1690815C3C940AB722487CC8F3D1F4C428828E7FD2A21230E42A3BBDF1E792165F644D0E0335F95EBDC93D6005CC0C680DB7B0E1B8C4946B7974319F9816141DB9E01011E4F20DA8F1B8E15A6F618CF599C3F5C1A1B276D51318ED4119BCE0ACD0332F3DD8F88EC5215AB311C51FF4987DA93B09A43BA84CF08032F6CB28F43043C54586811D870AD6FA27AA63785345C8BCDD3DA26A0134738BC7E08461D5409FF0B791D8574CE797FC5EF7821055028CB4AF92AE1088F8806CD55F0E5FDFCD8D74ED801B2B44AD5D79D1924D41DDC6AB2070B5360CB64CCF487FE517420348CC39BF50BDF78BE7DA91542FEAB689457B3EE69E43C75FADC303F31032FD96B7DC70A88C3B7BAC7322B285D9CFB3A93AC8B890165F23848FAD8477DBDD3D0AA4CB3CD73A48000B6D134DA2DA70B56E590A101AEE78864DA0C64A7BCC6B37CD6F31E9AFF10CA4D47630752D253944632DF6EC60AECDCD223F29399CDA3B74D1DFA5471277EE6C814464A8C55D3C0B83B36B6AC9FA90CE876ACDF65E3EA3FD61D309EB71ED29A3D510B2F4C0B6D6C5B57EC9060CFBE48389DCB17CBB2284E7F578565B91503B06F49CF3E8534870AEB6AD9707265A9A1E6E2E5E6DF6DAA367239A96EF5B02C19A4543D537EB4D9D73966C09E9B52B4706F57B3E0987885EB84DEA26F7823D895F62015188ED38C04CC6714F797FDB0BC713E3D0208462F9A68E3872A167BF1BF9791AEE8BB73CF527C50975B55C4E5C2F2E95B677F833ECC878D1764839608CC1108A75EE9E58FFCFE4CB52884E7AF15EE0632E0729DA1CF5B7A227028CFE1E08F8B881E1A743D52DD27BED33DE0EE75DC031B4864CF192DFEAF64F726D73321363A233F81C57232432D2B0A5A4C44F4320847A9C143F378F204185D2B571482FE45D6BCA152E6EA7223BFC6DCE06CEF90CE9114623EAB9B1EC789B2051B4AB711DABF5B16FCD970F437B8860313B4F1F14D384EE3976B7E55D2FDCB7E1BD9BE18B722E37C853ADC7E1CC2870A02881F95B78487780E1D1C296415109CF07AB63D0782A9F451CBEB3E8B919917AEDBCA8A8E563AD3784639793E0F25CC9CC62240FA04B2F141E71BF5C84EAC56431159556B8BCE077A51469A87737D3D6F06D97DD479FCC35129F4499C19EF98BDCEA9D4941B3756CDE1997C3AFCAE62B6D9E23341E11CD05A7FFF52F5814011A84D737E1264109006BEF5F19E3C6A9C7521B44741A8282755A8F0DC2FA0E1F6CA4FB34D8CD5FAA27E18808868725B9634376137C1BBC46934F83958112D03082DDD6148F353BD1DD24B9F8FD7AD89C40DA0A92A8DBE3608038CD56FFC4ACA35241D76FAC4CAE1211AAD9D73D51C81C59BCE05F71C345730D3A2C670F8F533A950EF24B00EFE6A3F1354694ABCC6FD9EC4E74DDE1F287AD4F847A297ECCCC39AF029EFCDDDB19932D906B9CEDFCBE0D422CEE305DD05E407340F28EEEA866664D60AF293A45D5D6D5C0000B05F79463DB513ED488DE7BD4EC9EACFEF973B23CE4E9539EFCB797456CF5FD1EC54FDCEE80B39063C48B91A5C2D2BEBC81B9B46D0AD6503BE5AACED2BA5EBE81F630B4E07510356E8229F7FC5EA532B8729CDB819E066A15379AC6942CD4BC5E97C6791E098105C323A3A3DA3880D5EE5562ABBA2BDC9906F4486B51ACF8AA4405E9D7A63DB9E3058782DD9AF3995FFB3D34AEF98234A0B3DC62C339325B60706C068F0198BD8FA658396D06931B069155217690C7F88FD230CDB38E3E48530BD47722FC", + "9D8CF144C4B667345D44F765622A956CAC4E097AB1CAB05CFBCC6BB68C709503AD9DB09C09C983D46A04A05B6F7EB26DB4D46F868C10E112828B1AEDB3C0074BE0DE3C9B7821BABB4F8B8E24F69869CCD981B09A783BF6A95F39ECFAF25DED6B16F89EA09D3A8413CCEBB545651B363DD385D12BB72420440C40E804FA27DE029A1E08629BAAB598C035DC58FDD309844F3BEBDE40FCC231F38605DED06572ADD85DC51D3D8B89B4480143D0B75283522354330E5CCF4DE1A6E68047D5B8D45D835A891F2D40C9DB8A76CEB1D18FE2BC38D080A8D97064CC87D692DF21184ABFDDA7642D0BD6F3209D06B4AE7600F7DDDB71DA751120599117ECCE645FD109CCA2EC7DB98F4177F14DB854FEB314B5D7CDC3385AD203464EADEAFF4AD08DFEF3D21240BFB8EFCAAC1356C72A0F5C61BE03CD2A21A7D756FA9003D562FC4A49A6BE788EC8D80054ACA881DFFF72C2966EECD09F185EDD11218C6696DB14E05FFF3644D11E508F4F1E9C5AB3074FB1C3FB21092A1C8D5AE05688FA4A9226C3C30D0BC3981933DC8648240F8CB67085F53AC5295428DC8447A1E5A46C2BA86796982C4C6CC647FD8079BC4024BB69E2B226E6F3D0F8A90B4D36DA2AED4C6BB60D318AA7479FDC2031143C67CB4381C27072E12935001524C7BECEDAA9954BCC2AA218E9EC2C95498FD8DF655C015896D9ED42CE7F91CBBA2CC4A7920038EBB5F5CE638F969F8B179E72AE252BE7E826E5CB53C2E85AAF1E1F1AD8D534F78A681928818AC3154651FFC583DEB0A6A1F40B98771ACC528AAF80D210ADAF83597869968D499ADE9A19BAF341E8CBA20F0E1473BDD898C24C7A5466F9924EC7EE992A2086AF295BEE1F6D0F8843D91180BF2C981C11FD978B23B6BAF7786BD526B458B76A87C31D7C52DFA43F3D362C8EEFFFB3FE5FB3F6E5F34B1FEC7EF1031146F3F609B32677F148F7DEBCF3526BB45582436A3092408193D6312626E46ECFA96FEAD12A234CACE10FAF9DE75EE2D238088146328E10E9ECDBB0B018ECDF2725415CF5A06AAB857403BBF6CBFC350903A982864827988BC805A3484A31FECF7A40D4FE251BC7E487613B9D3A48D3C7DAEFDC49C4B7E625F868DB53A798515A61050978552699EF2A5BF2F13BDD444EADC9B60B479FDD4633EB4C1062AA78BEF06692DED203819D3160310FD7F2343732156A9CBCB0B50BA9A8F93E339B702670E54BFA6DB2E2E773202C690FB71EB03671AB0B1B02B2F189BD99061ADD23F75F4914067AE638C9A29DD3661C28AE272CE692CBDE6AE880FBCF272E548342372CBAF6370C7E3AE9648341CE7310BE1C534B5702B0611AF65868F840B6B7613FDAEA21DEFB4F2024487023B02B8B58C9E9F27AA787EE775249EFC40913CBBD69C38538F239B203815F00F7B9CB30DC79E6A0C3E069D109E4A1BAEEE36D354C3D0121F1342F1F4AC504A68D69DEC158D54B04BE8164B48F31BC0827A0379C5237070B6F963741AD9ED4F3865698FB8233D7F49ED4E0EEF3AD927CBAF4FAE183252BC56AE4CDE3E329B1D9C87C6C11429B15B8EE589213CFAC208A12AA01B4F1F7CC35CD0AEAE217471B3DAC1C279F353DC61994FC45FEDBBE0005D8EC729385645864EF98A3A417E62F1EACA7E60D4E773BB2E4024D62830F103A7988733DD7BBCF3AB0CD0049006FE2F7EB3821724BEC37EAE44681A9699A025D212724CD98CA3415FE2BD09FADC02F1501FA38A6083427B662DDCBD0460E12A09072698EC8966C47B8A640AC79C1B7722E78A6C28680F4BB77BBA477BE0A6FAB959B9753217C5708", + "45D1C8FF162EE106CC87C3EBF6A837930F8CC797EC7A446E8A213ABD239582350636B19B5BE428A9C13F980B7AF5CD7F32630AFE8693CDF0EC0BC2C84F2472F5B86576E8C43136C14717A24705953D392BAC96C1055B782C7941D82FEA357E5FDEFF772FB9F3DF248455CADEAC4CBA2EBA9C91184006D1680E000D59E4BC8FBE2C2F7CC2E78BFA5B60EB292F244E6CF497D5A287432F2520B31B9D9FEC1210923299EDFF043CE077195509E92372F5959AAB4666AE486DEFA400D81463C388CD05C677BFD4953D2627105B0A776960FEE916C75D53981D30DC689581B7E8E0723D65949662ECFAA6FCC9F0CE8892E367721718F906207663F9AD450AE98D75DF004080FC15DC2CD7A1DCE013A0E547ADDC29A397ECB9E7FA02035327AC40240E2091098708D424563AB7C5867F3F2D78EE3EF5B658FDDBD49435060CA2EA3D559CDE957B7E48B98DB41CF875F7B3D9EBDF6547B4EDD98DF4B747B0793152FA8CC07C6D9EE5A2002464566D86466C2EDE54A2BF4BBE823049E57364C127A14BFE1B88ECF70EFB81EB831BBF50F6AE124E5F6A775F3F2620E91D489CCF24811C0890EF905E9E2ACD399E13DC81333A54BDD295B872EB74E412E2FB654A9874854FBC3A68C73434C5FC5CED27534B2B13C316205FF4E432FAFC13A7B5B7A7FFA9FEEDB5AE69036F8F2955DA124CE5856E8C53F24E609F7D3386DC5212B2E78B5AA23B59D45FE98AA08E9CFAA9D52ED260A36AF07522C047ED43808A39D7019E444EDF84D885A9AC84092A0F6BFED562F3E0D79FB5CF62F98E67EF219FA3F5AEB7D4E344642D3D4B1A7EEA18464F6CE8D4CB3181D9EBF6F4122751B54D0D7F3FC470A91B547148AAB1CA0DF59872120190640555A7561B0F2C11280768F74B1A56674FD5480B0F510491431810D99CECBC6DB85888BACBE2B020FB8B3D78039773229714156494EAEC3A2D0A59E718F72205747D69C05DDF1C678E2E154A1F84EF0CA2E24DC4A6A996F0850A396D2432596EAE84AEC0935B8C25D5C65B52A32722F01D281C4F753EE03EB10020E9FA02462CA303DA39560669637532D381EB78AE5EC0F6DBF6273EC979442E6243F65FC51F26C6C9554C6C0E3EFF33BC4EAB6A27CAB9383BE7DDDE4218C4998033B47919503E1C9A789711EBEAAD6C0298B3DC563F54D28675260F6D896F1B8D4FD0001C429210398E9544B3DAA12C31F7EE82EF4D2234E26F873610B76756DDACD24B6132BCFFE735FE75513ED527DD04D7DC6D24059F85706679DCD1474A9DB9571426BE17E6DEBA58B33B708567697F471CA8B78E8FA73B0E18CB6F88BF9E4F442F0FC21FAB89305484828F18B65F9D373A6A2B380D73F5924F80DA234C1DD87416D025E4E663C96F287B0C83DC92C2164D81830781B715209FD11A65E64962D805389BAAA91DFBB990D3511E506A8EC101131C5B7284252F861D047DB2C2027DBAAD487ABFE429CA21CBEA7671350618E441F4D62F2D579CAE29D97023A8873869B553293D9F54D4A929E252AF132325A6E3BCBF7B36D0DAFA1E56A39A5D801FD0D5A41111017BF62AAF8346C7D424FE007C32B437ADE60AAA9540AA5078FE6C3C3CCEA53EE863086646C976FE6C79434A0AA4F53B2E9E2C3B4CF9C9C4015391E27CDFF5C1FCCCC00BBF5B99715A1265F591E294D530DB14DFD485AD34BBCEA32E5B5D0EED15F88BF5D96D058E6D70BB1A232597E35A625E5E8C2EF5E7031A71F70309019A0591BA0A50E87C839498255A3602C0FAE53166BE5E49E29D24AEC47002B698F80FC49E718B66A8959259ACC540", + "7A0133D5CC3754D6B259A2CC4EC0298111D098CDFB40549E5C40B36A2846CB4B256672BA189CD3A05293BB36B167508A7BECA3110BFF339BA06340585DE8EDA03AD244A77F54B7931610B6F9C5C54D688A0526A9B52605BD7D7BB01A63F3D1565CF78ED904BBE4AFA4A290EADFE9DC156E59BAC162A818B6CDF38D2BC715144D44A1578BFC727423777784D15ACFE80FACAB61F9E58B5D3FFDDB065A00C5D49DF0237EA6C488D7758F1A689DC59DBFF78261016A7C723FE52FFE571F5876FE0ED50FB00A90BB82B27BCAF5A67374284844E06BB1B2D84B1D20228F5C2208CA7E8EEC2E95027B09372A309223A15C132543FF3A89B7AFBA56AA7A8DBE70E0805D3A54191CC6884D75ED0FC00C06D9D488B0F4816E12D6C2A4324EF742AC8FF885E42100849DA05E3B7C451D43ADBEDDFDD13076CD8D22BDA101F665B5878E321A009B970D1F4C48503CE35365543B3F36786802E5C53FDD756C595784E4F130904044660784ECD9C9161477F5BCEFC98987540AD1E86CABD3EC7823D83877605FFC79820F1381DA29282C3C5B3443B6A67973F0622EA5DAA14FA239542EB140082F242958B39014486E5D5632C62C3EC8BE0E09E038C0ABD52B1322E0F7407FA53AE8D761858136CB371AED5E6FC9D32CADC8F870EE833B7120BC0278D9A05554D90DBEB24ED6F5A8861698D48B4BF7AFE7763C1401572643E246DC65853996B0480D38DB7302364409357137DCD0B416561B9511BA43CA34341FEF7954C28B2D9FF96EA110E0818309C32AD306DA077CC911299FAD6396C872F3F6AF7871395D7E67879EFED929E4C05AB4C09E8BB396048150A4161D7944CBD99C94DD16CD8E0D8BB73768B17EC02C0D4206AF623037D6F4257DAB4C07B4A6C0B4D2E0C9923FBADE3DFF7FDAB45F4E6BC5A895FAE4F5BB9EA247F2D4446E260F7988C452203EEA1DFA64DEC2DCC090BB3ABE13F6A8718F8DA2BE551407B59B8EF1806A65526B6B872CB8922BB929F09341554A71E69B41B60987FE3A5E7E3424D947455083A827FFE27FB5BC5365C80998DE01CCDB66213575FB61B3E6F877D0E2E4EFDE4467D9F07B6A28148FE2FD6EDC9202F55FC855D0DF8C49E244C40CC3D95FC06C6778D397461BD157F4A0FFD915799820D55F52C96AEC0CC5A3E7A2151A845EECEE78B82ED9A217E326CF6C49F7D31C4D8ACAFD827E6ABB760150203448C000819E7E0B6E424C43A5500164CF128D686B4810D9838480604A891792987FDC549D87F95BCA120AB84FCCD8C9F93F988C87E79599F3C1952BC0F7773BDFFC50B19BDF8E3D8F52D887E45B643297650044E80124BEA0ED60FEC4449BB3BBE394CDF7CC7AA39BC1A5023044F6A843186C01EE1BF5834EB5401AF7905FC04447AE00DAC50B051B432F831FE5AAA7506160CFD7D4639C489ECA447F4F993AF0503CE5EF68A837FCF85B85993ECC55A9A3673F8F2C5CB8D3DD4C60E8421E3417EA958EF87E0764B061A39C32ABD5E0E3A712B54B0A3E2D351A0E00F4E901521C63C1F4ED829F6E259A1F720FDE96EA9CBB8F7BD7485531A81A49CDEFCE725493A04B5EAAF7411DEACDE5A95AB6C2AA7BE3269F6AE4D166D8A5FD5264B135FF8361FF75B2FF22A61905A349C6B2C1DB2BD7B385B8FBDCB2768C7926F138D5F8107111563CE527322AC42E6BD42485668106B8CE91F157E0C94448869F7AABA255821DF981CD5298D40378FB0E33A3DF8A037BC21F0AE268E69F7CF61E7E117BB463EDE3C7D2EF95987C66AC3E5C7D79C44A7590BFCF998683701DAD7B98731DBCB455E61428", + "64D4236F326627BC08E9B2B96C1A9E5BA2631DCCA3F7A5B63736E4EA8074056DCD6BF0E5D6DB8845D9271C0D706F972AF22E652E3B2A7CC482B125EF8BE005F25D5109F6F9DD84DF966E2E0B8950FE1C01E2DF15205EC48BECEFB32511DCC39678F9DB08ED0EFF64C7B5DAED1DFD202F63B6EDBCFB7E4FBB431718BBFA2B65594D78D3983B0457DDDB350AF2C1B9743AB9EFC260A78C3144622C50D528B7D47DDE46FB9DA33D1E7DE6D5829258C2F02D54085AD0121A1BC8339A2847F6F161CB6EEFC5E3FFB12E6C77E5FE10E0D4B02E58142DBE5BF900B7B64EA79D520A35506AF4987E67BCC80D00FF467A0889A14B85B4745888B09DF7B4D3316D9B4A9B17C4CEDFCB0A55E2AAC53B538705673B2A2EE4ABA914E20ECAED730E3D5E272A65A74C366177A711095624A679C9300FEC18E20E65DA3645F23AABEF7EB7C7FF49B289FD2F44661F6F5F689B6E06EFCC99F8A5EAF558E10F2236E002F7D97C316698D6833792C456F812A339166E9FB3B3F61734B98AD2DC9A484A14A6025114D072B68C47DDE97322E213F5D6A93762A45C4C73C7832BB31209C4B1F0094BD24BA23CA9378FB893AB078FA3BC4763704EB6A0C8EC965690CA5B858DAFE623AB88ED39154F46B9030462DEC9070DA9DC34063C1CAB3FB84D60337F1D6D95D1A173650C96128D3C036D0B72B4D2A298186CCA8E1F386E1F70C0716F0BE370A6B325CDFDEAD3CC67E021E9D4C839230708DCCB062096F32C4DBE3C4876A7D1A26072673A6CABDD8D65A5E91CC5E973F00FA67619F749930F9D40B767E434D0955D47FC17BB37E4B7CCE63B1D666AF5D67FCE5FE5469D3DF6B6855F9C308DDFDF6733FA7B8511B25193C27925F3619F5F836014A64A2C8B783A50C6B3001001D621CEC582FA4E52C2B916A418F49ECFDB5ABCA40E1A8D38FE400FC2D0C185009E85546A92E829DC1AD2A7AC3DD23EB77F3D80015BDA4135B1194B10ECFC87C1102B3D366C5460D20D83E778142F1A4EDFDECF3D0BC448CE24A49C609B035A99B64FABF071C58DF592BBC625359BC23A565F4BB077DCF879E14ACE87F709D276982A3D10B23A9538A6A3DEEBBF0B712DB4C16B0FF508F3E4AF4AA759738302D24C6D13037DC81B0394FE785FD14A322BC00ED95E0E9D527FE5316748DD893DB03D5C4149D471DE98C386A2E9DCFF05181E837A1814D54C9CA708CB5E7A10B0FF4F540338BE403E4B9713015A99260795DF5832CCE8D5F763C68BDA51133AF1D012C283E8F4B1DDBB4EE8C351C4AF86FB436571F53B2E80AC04BE26EA617EFA9C5578FBBD81DD1809EC5BCA5DF4A85B24970EBD88D9856B2136616F85A338771BEE80F20F6E5652FAD00F49F3C349061DE3052841992EAA04CE15DB6C48888BD3CC5EF4D6CEBF00431CCB7C5289D79E67FC6CF2DA88AB60CB65D0F687455A535C33547553966D197BAD9778542F6CC7182289AED366ED1CDB0C5EC1E9C0F0E21D4D2B8D01EF4BA394E0C6B05B8EF42D81F773D3D251D6264CA23DA5CA2D4884544FDB81A243974FEECB416D0748449BA0CDC69E56D666FCD24D9BD7C322CBC038CEC658B5253227D87C527473F34BBA3E2FC18784F864233FF8528A874A8503840AAD03B63F79FEAA6C07E4467C4A04366ACD35E32A142DD76A23417EDBB8004944A1E51880CAA97937493EA5BD5A41298863A71D33156CDB942C166748DF66B80ECAD27675A673C8692805B42E97F1B28DCC9BCB58FDF8BE55E2034E73E444A225DDDCA5B46BEBA51AE98A27990F622B32B2C337046E459B173D94BBE5FDAE31FFD4", + "23300D5D80ECA6A471DE5CBA1D29B7010240D95FE341A62FF8175ECAA9566011AEDE6EDA0EF2CFFA7BFF9F4C9AB2C97F6554BB182B23F2772090FE7C4ACB8BE7427E7A8535DA3A670341D88CFE694D1CF40156E9B0557EA317A0B3E21F3A629D1CA971482B1A54697BBC2020BBACBBB9D1E67DC33F52C4B446A36D4331FB02F19BF1A647D05714450E591C65853176A04DD561E0933CF3F24A2E4707C44FE29C5D7706723FF53ADDDC67A67C23769CA32876F0CF31D233D352FF6A7277E5A3A7578A6F2A76456C0AA876680CDF2702B114E02D22D9F59077B9DB2ABFED673158EFAE4C23A75FC8BE701D973169AA7015297BDCAD4870D4F152DC556A06BBBBAEDFFCE40E6BA4F0FEB154F32D8E1492F74EE7085937600EE176ABFD6B8638E983EAD26C63805B98745BA290813CB65CCE33DF6B98240E571DEC4BFB2430C4B8FEC23C1BD5C3E87E0E746BA8A7722A6A660C5095FEA8E1C4978B966F487376DF42C9668E5D3102F123FDCE7B8D80E8BC84AF0D91E9355FF6F7482BA74E0BBA7DACE85BC053F31074151566334B4DDA37C6C51BB947811F284B671FE53FC464CC30DDE59A3D9CAD26822183E96D2F4BE60905B94BB8B167B734A0F0B26AD0E5083A34E68A620151966D073293E5D430D0726C0FE35BA3F1F44D851D374ABD80E826DD84A665165B3B82D540CDED9EF60CE48E87802F16F5DD89163AEC8E9C523E9F99AACCC6F00126C4C8663A7D64D919EC41ACA337379496D0CC876199A86404CE5844F8E2CACFB00A985B92B7A393CE464DB19E0B5FD65BA92D8EC1164CB1ECD994F82396F6A52BE2B66C8780A5AEFC0293EE437E7FBF9BF8880B61C8313C3865561A4287BFCABABB90B3A11F6AA57C2B2A6047F1316AFE1DFE540C4F1D5270F3EE3E023E202AA530211DC51F8C2E87636C14EC8300271A6454A924A8093716756F79780D94DC6863C24C80A405D6F52DEE81810EB850C1F60732AB24209773F66B2D2AEDEDAD6FFF60902910D4858B0F706414F5779590F2DA7C249E5DC1484EC40EDBB01920A5175CB9D74EFF957A61FE3E08DD7C5DED5B299C03299F25E39B161E1DC1C586E39D0BAF38C09C2EC0B22589AC489C3199EA4E66611C45A68A7254D292C78C3978C381F297D7DCD8C0F7646E7AB6DCF155B67F10C3F915F9B3AD96C21379993D8C5D6957847EA81B3BB4BB0863F0CED12F5CC48A4325CDA65268110C1C156F845951AF3C3C90280F8883CE0236FF02DB0CB07721261432C7E0D479F859D8EB7C433F67721B06E001498656578F0E3CEF2A6B941519885BBBB03F33DEEA07802226AEBA473CFEA6EB894F45D1BB937ADF5180F5FE22857CE0EB75D251B02D89E5502560A0B6B012C191DE9D62FD28CF503375F2A1FA9EFE0E42DA81A6EB3A6DBA299726EACC6F3BE91ED51A25EAD5F3E7067720F7D4BB72F8BE2DF978C46E1DFB4B0EA17BFCEFEBBFE40C66ED1F288BE08D6CD0B097C7ED1205E43F8FFB7086120FD153C47272188799D0F4554E9A4131C6B1460077A99E8198B3717AFE5E7C95D3F49B3779EFF9E935FA63A6F881F039436EBDCA2EBE6FE00109B658BA5555BAAA4A401D1FFCBCE0369798BB3BF8B54FCEAA5FE25F31AA02208B0F070270F9E043BAEEDAD4432B1C2DAC9F7B4CDCB52965EC43C2E99764AD2613BCBE468C9477E64B8BDCB64CFCE01C06EB66A15FB034D1AAA507AFB6842AF66AC8C18807E98884C6A780805720718A3A4D1A7B094846C55B0808736199CF4EC3F66B713259CC715B22B92AFB1599B7AD539B188E99B39F9A92987D0ED15C94", + "91CEF241899B4DD47BF31F3BBEF20F5BF13D9A98D3F133AE61F3E4A87A299A6B115B96DA6B2811414D204A49EDA0E1A763E1EAFB78CE05C181DD0947CD50276A10D62543A0ECBA57DAB5DC794AD7006A520B419533CE8519F4EE4194B58B2E36F9E9705266B6E304D1DBC6B73491045548637449E5C657B263CBD9577AD8DB7D5A5BB5DF43A869FF91BB8706D4E81A4F8243C214D9884104675F2BCB426CD785A28F4856E363E1ECC974325487DC40E7304D3D7CADA5DCCA6E60F4457DA181A39801D35F20E1DFA05BC09E7699FA289A87EAB311BA8700AEC0F90950E5FF740DAE7EAE7FCAE8B0D9FB82ABD25BF46FAA635F570C22A76C52F9733D5BE64BA67AEB5D826288D03D8A23C5BD3FD6DBA68082B7815044E24859865ED557C7DE8F866823CD4716E573BFF30067F0931D0AFED0146D55B0B2A3D6C57481D94F61279DC4D2C6DCA1CEE27DF24426E55AB4FFB87068AC8AA6F286151356CEB29D993B4FB26192319C373A1F0F58FF5949783E71671FB58A683DC1CFE166FE1AEFEC8A41C5FC06A31F4EFFFA3EB7C388E1BF99667A5D2697F7132409641AA812EE84EA8735BB46E5069A7BF1B2618B56ACB97C368AA7BDE1BE0F0BF286B6D08B42702F1EDEF408BC529B4158824F673B30E3D3247FA59DCB83D004459CC5EF87BD6C7D188FD91A2A7FFDB008244F8618ED46A73323E9C7F9D5A83298F8C81702FB4523AFEA589D4CC269BD226D04689F132F766770FF23C832EB5695713AB99B74035540031AD1D9D9047D72B1910BC320A65A9F63A40C02FAFE217BA0C51FFE24E96DACE57C1318351038FBB81E76EA34853484E7ECEB672A4180A3D24B6C692747E9D306DD0AF275EC0581A30AC2E80EC73B04B1EF83160FD88DC43406CD715EAB1677F1422FCAB85D1D1EAC64F698B9ED69FC9F2B5519AF9153D5AB722339434C780886B81DC2878B27177B4616450BC1DE99C49C965DC9257BC78ACA052E998493A0CBF7B6AC86EDBC2627E43E7521A9DE7824DFA7DE19AEEA5892685D50EB10128B3D14F3C670F639AF6F2B2F6168A1E551A65781A418ED697E6AB3CF91EA2470995A401B08380CA58B9439DDA7BDB7A92E91016567D57D57D5D0DC4D8E3C1490CA1BEC03FDE065C7B7F34DBC40BF704149A0573C55A0EE4C415533829EEE71BD8C392FD622572DE009044E937AEEDF672886CF4A36ECFE7B0F8BA9CD9EBDEAEC40BD74AD34CCD2C7DD07F7AA64EBF4DA9C8810C05F55619B808127CCA00D171BFEA3E1EC0895A22218DF1A0514FE5D16DC416D9FFEEA8EA3BC9FC650F678EB731E70A6110E138E059371D5A10BEF6420A0C8BD45F836B7D310E732BDD0FE57D93A6934317FD8E2449BA0F0C6E1B36821B62D1F80B9CB6A5B407B6755977C06BB2C3CEED0B14D4D73A3554FAA54EF2C350C388B230B30148605035E4F481A769564E2814A160A67E6F0DFFA7814D0C12772C0496737C52016A93C6753C82FA896BDFF3BCC72105D6EA5B52B3810004DDEDC266F1C90CACF49BA7DB5016A4E485F06355441CA204F7D589F2A3159541F991682E6AEAC0C7359B3282A04B2DC69BB0AD6CF49C48343C8A769D3EFBE8D0814E72934F7CDE698061EC68FAAB39016B96BDC5363D2B53363A548E6476647C10F55611469828564C189430D351CA01D2F1029CA3CE1D2853E8E595D46C9C3EE9F7D3EB9C72A25F7B2138063A0F9186FF41CA9C579DA61772FD60408668A877CCF6B65FC2B88935822A6DDABB97D19F7455A9725A8DF2B8E6B28D83ACDACC66F02370575831490B8D8838D4E56AF36ADF8", + "AA82DC5072A45A21B7880DEA3E2691FCC22EFF3AC815A2576A7F480ADA6F8426EADB4A96A17EB949BC049A646D46926F0D69E0B3E1911D2CE652FF4D9CBFCFDC30065FF4F779DF896D38587B297BE8E224EFB1DFD04BC2D22832B2955A250B7D0448AD9C0A76DE7C33A4E2B5DA1B3A868852B7F04D848EA6495BE8D2501BB47F24E8DC4B254DC56BB5A4760DF62BDB229F3DF0E0C06274A63A28D11F928AE2DEA72A9974E3C55CE261943F78B771CAE7B5B98642A01DBC06111B137774898F0F113A4DB23BC240BFF147568493FCF0C3D767D3548A1C0EF7AA4B6B2DF566C3E94BF9A183264F63E4FBA58B517FC46C4F0017F8D763A54D044C644D6326677A425F0F5A2A7C8796B9C9F8CD0FC49A1F035BB6662C0CCC0E9508AF8D2B834B929D80096F9BFC922BBF1BFC6F101317EC08ECC1DB52404B30B153F43C266D3E64FC496CFBBD350668B2AB3B596B5E0F0A00757E0D4A771F5A386AE86F5105C1718F7E93CF00F588C722509A03597B95512CFC705F08D3B4D5A3E23C56EB461A719A955AFD3EDC8329BC97E3EC6BAB24D97E16A724ED2D4C02B2371FA3ACAF49175A441C3FDE53C2DDA440C18BDB8A6F27805F944EAA7991D404CA74544E2F3A669DCC4052B6770AAD9EE29A6EF7791C6DF93054D07A2B3CB2327B0EBE7D983624639961AC4C3CEC2A84DBB3A10A830DCAABA9600DED87FD5CBAF4D5F1DB357ED42374175257474BAC200AC1B6A5B87D2FB2092458F51185C380B8BFF682C5BA1D2CBF8BC02E5D485FD811797AED167DE6ACA66B927363D12EA405D75A2E9182B1FD30ABA700C5683611A24EC5DC453F523EAEA44C6E06261A98346328ED9E86CA8F7EA79EEC551F36836272127A45984EE165BEF8AED80D26DC45E34E1794F56C1265DD92B4078FD2AF2F13981C08FE27C55C3C9238BBDE193A956E3F834445D949CAD84D3FF0FCD511C6C598735D5B3B07BDD7D437ADED3ABD6EC3171F3735883C9F511A06F4C6C7D0B137DD0D57869B8FB1375FBFCF9C3D08CDCB12B8D01614AA3C965550E5862AF49B04410D25BA4BE86FA6B0B9D9142461AD3CB4BD6D902EFA49632A78F1463619E1309CC89452C2B453BF9F08A714D67ED90972C62C0468CE17006F9B60138D28DA6362670BA3048CD8D099AF193619AA8384A1758FDF4A04CE56ABE464A66E913DB7BBBFF7EB2ADBD47E6347D7054CCA13000DE13F550C6263AA4135A2E16F1A2A58BEF962113C209CF58CE514FB51EC162D05A4DF832697E544037CA18E62A267D81D539F879F50C654E74BA21B47FFA5C704FAD2147EB3DD8617DE98B3ED4859B605310A777F3DD161F4038486F0872AF55FA3610EE0D68C1D51E0F91EF7D9AF4ED01BFF53FDA16BA3197A518BAC0F82F8895A2BDD9FF4C3035379E870C49DA1AF18B3668792B6640E687BB71F13DF1650C4E1A2CC487C247D1D1356EE16DB8F97363465614E9E63F36C853FB63C12963A8A5D98B52BE8DB31F0954B35C3C749A62C2B34A690803FA66087015506225181C5D6FC101D1494C3A7961ACFB4D9B905323DAADABA1DCD2DDC1F9CBFED7D726E602578CFDC1519925F8DBF9AC5FB4E4CA723BB264B5D106B6206574C46C1A49309C22E1935904942C36148F764B59F10A5CBA0C9397F5798E200A606EFC75DEEA1FFB10A85398E5BFBBC6AA3619A0F611E591245D03B6ADC0C50440A1B1C236ADBA933B2BF84D2C60C807E9F52436904BC62B813FFF8B9C824819C760D0BD636B10572C781B112CC0C603A260AB87986B0280FB913A9E0BCCDEE347F0C744BF8299A9099B8", + "F2A17D19ECA96F67ADACC0D83FDCF235F07832E8E78A44A53F9C4CD09C3F88DB226701963147EE0E1AD0F549E11BBA70053A105BD62C40DA810BA37BA72D999CC4FF9BA4D01FCFC670E0D7819871D06C4935C10B85594CB7202F037B25F85141A580AE1CB3E0CA91AD73C6947D2492B8FD2F889B1421E04FF0FB7866218A491D9EF6A35DCACC12CE098EC575C697F5F8D1BF9178B3B36C999EADFFB5CB3A41DB672165CF73A7874FF68B3B901C4E9B8112EF4FF9B9308742ED678DF30E2F7C40BF922099C1A95BE0C231E9F8332EBEEFD99C6DDEF25CA5EBB2985A9689912616815AEA022BFBB87353B8B799D64280A6922CB09044ECAFA51037AC2FCB11516E9E286F64B4CE3E30A55191F24AB53F2E10E5A8920FFBAED77FD4C476E9AEC751763D68409ED9BF7F435E53D401CAD787A50033BB8547C910D90DE100FDF6B904A1F529830E3A51919299FD4476F02C3600AD5D42E3E154AEDCD1C99C1C5B531FE179860EC1EAC69EA0381CD4DCDE8716F94D6510F10FD1915864BA968440CCA6D0D5AD8983C421079B033B56FC34481B9F27188F829F91DD73F27BE8E0456B0F75DBEF40A3C67F274F6A50CDBFFF9798F8DBF1A6CE7158B577550E40639D38861A3CC4E060C9E5BC1F0D3760FA9A89C2CF0A23505F4A642F5EB0A055B96843198CE20133DFE022AFEE043191007276427DC82E877BDE27E20D65DFF8232E9E4DD786C23D4E8B5E84637A22AE5562651BA45369947C159B641710C98494ACAD48B4AD6AD9828897437AFACEE442DF2330669D5F2C6A9893E08507ADBF104C62F6B4D568C5381B28D5162EF0FBECF396E7C622B54A7864F9B31CCB396A0DF82AB86D950B4657237FB769122BE6B783ECE3F798AF68E354C521C77735EDB97D580CC80877ED702231CE2F8B73262AE39EF94E84736949292E065515D40A16BAB13EB9437D30AEC44AD8C67E3AFCE9AB377753BDC481E8E79EB10F89A7C4F7AA24E6FA48A36DD1CFC02CF3FF6DFD0CC1C4030C312532A70B60F678FF2B3586D77DDE74167CFFA62C12F7D0086A6FA59B36C6A025DEA1EA0BFA9861BEFEBEC6B2601DF225E29F36AC97EBDDB21D7E8206E1EC42F3B9CB314E7AE6464D54ABD53D090DE83B466FAF5384E0FAAA6E67F2FBD6A72E00D9274C9B5C768DB4AA4281F25EB2DC6BBE0EA85CE1CD31B32BD1971D6AA20B6C68D66426F09C0C1128A679AF06CAD490DCE3A2DB50181278BC40DF9E094D1D09B281CD1EF1C369E5927407E04918BD21315E12583D7D845933AEF186DAF8B6609C3CA9452857DD2112E86227422491DC7821D7E41DF759BABE6ADD11A4C771CF16469F86262D169F221D97DAC9686B6DA29568B4A2D2579C76CBF948C321F5158EB3FF5F6D4D6D68FA255C81F62A8DD605507D0C6C9D82E6AD258B32DE4AB6FF8FCC4A8C237E270B9673C208E56AA6F4796867762399FC8549DBD232B2CD0F9957A8A24FCEC6E8B3DCCBC67085C542A134F3E80A3CCE8D3DBEF0528432F2BAB2F5DC89D6015BE7F24B2B1F378EE75222EF125A5645AE37AFE6ABDF84CCC3026507BAD9CD8C2EB4020E7763E0F85164734C851532FFE705C111CCB7D738BA8C0D29C5A0A50250D0BE53353A6C407D4F7EDD62F271F099528CCB520E5B6B5695D3FBE628FF65D67CC0D1B766149B9C89D3C770AA133FAE2BF3C9846B30C46584E9F93A8216627CFAD84C37AAD7986B8D69F83392FF8F98C828F8B136633A09718D375327B98A0CF8B7736D229499A52D91D19CBB896A5BF4131691682741797A25FFFE6AC60E30C79385DC778C90", + "3D84AE0F7756BCB2518300DB110A07EC46869AC35F1B02650A36C3CA0350356E2808B84A0D9A8A648F920B7D48AFBBF6CA9A37F673DE2B6FB15B189FBBF2444BDE8808118595AA995AE0DF53F5146B011A0AF5B7FCB4B3D3EC074F2DF15CC9708EC50EBEEAFE06F7A0235A50E2DF7F6C023B53819AEA87318C4E67C4742FDEACF57DC539FBD5BA01F64CB45322212C707923303D96E58EB95F7392292885391283DD9477218697698AD6D83AA96B06D68F58FC2B8FD9D61E75337C6815BBFA8B76833FE1856B714ACCB6FB1B5E957DD385658AC760AC5811E3BC079DDF2CE30BDC21AB8D2C7B56D2F6B384FECDE4EB0206A6C00282950C1B72B3E464570364A919812E86BBFD0E1CB2DC98D6FF42617355F2131F72A11F50618CF21A4C4961083FC6BFAB63F544677428BB9F10FE341B947C41AAC1B367E338CC2AA08D6CAD1067F02654794571FA4AA11E211F5E75D194197BE4AF6543009C40EA86F74AEADAAB134CA9E35D79F7CD062B53BE2AD86FA7C2E30D9222A494A25044153420AEB6C8FFC4E0D4C514B8D9F5DD922D8EA387003409539D0B40210B05C9209B008D3E47E8F84C376F46001FFE463F21A92E34D3345751E8E94205EA06FAC16292B8C6D4FA028867AD4C4E8DE0D51BB7AED59547707CFBC2CF3A9235C29EE3A3873B96FB75DD50E758CB2C7196BDC09336A97756DAB994C46D5BBB87F9D80008D09C603A68022BADB1D2F6B98B6B76CB3C0EDAEA07A23065B93DAD67BC59C9BDEF7BDCDEF39D9AC04C9CE8F6DB4A925F77BBF8150AD478E3C6D7D32512ED75BFBCB82C66D505CD8BC5A5679014B355BDC66F365BE9AAF15B76C0CFC0B51E53F86BB4763F0302B448E84B9792F34442743E2D979C5133514D4BB1DE5E8AF938C4CF158336D04B6723F9422161805D5EB059E55C86D0C461399073A705FD6E919D1760B2D6860D65665B486DC0AAD8F7B3ADA9BD681D7FAE4185350BAA543E9F8671F1B4BAEB6D18674516033B2E2E4E427521C290A6E44E1EAF9974BBB360FEA3535CF46D68193C0E208AE5B2F85C2049C906725C92F598E6C0B67DC5F8B7C48CD411E107F4860CFB3C4229A44694ADE0E31A4FD70AE5702C0A7710678763B035C5C6B4B9214D507313F5ED85C444B98278B40446C861057AB9B897638DE4739088FC28A577CBD52A3910885276A2DC8DA99EC74D30DF707BFC60663C869DA4C47BBF4D64A789425C5C894EC2B512C3296D0070DE4942113FFC0B13D03515F2B4EC07A0E3BB7AAF08DE24779F9EEBE26CE7C316EAF47396E538672BB646E1B2016356A407B8828DC25D8F8A8296B4F855290131734C94CB92CBA5689574CE95B60988C42558DAD978F36D67BDDDAA92FEF21282683EBF6D59763384781EB4D3431DF5BB909ADACB397D36D55D2ADEE537D7B1B942F3A815917A388B12285689B40C3B45C04A591672A2B957F924F1CF6049B96A38E304B8641DF6A079614C9F9984FD9C9F0A82ED6E440164AC484252B45147929A58B069E663663CEDF0FA44FD67580BFD23BF77C61B95B533107A25684FDBAA4C1285AB568C9FAB387C6FDDFD5EBDF5AF1CE094C59630E19F621CDED14E3847BDE9B0EEC64C159F23C779C4B80163554900393CD7F1B885F92F183839CDAD7801DC7FCFD08B7E08D23BE21BC80F8655A2F3BD0C483B2C1D23D447682CCD9CE098AECFD7BA7C48F5BDEAC8397220A7852077A8D7933FD353C25E37DAA473E996A5920DEDB80C26DE4FC3AFBD6ACEA16DD3208C9384021D9B1FC1C884319B59276D48D8BF5A0A37D84B8C579EE0D9BC", + "446D385D09A3464D1ABDC6D6CCB015280BBE7DCF00078634371D7F327322DD720E8DBD7B8CD97FB9505A118B469762ACA10C4E135ED782FC905EF30F9FBA82F11AE679431F270351F70F0508BA998AD9A71D2BE05F55348B275A0E537C63699C96DD8AB8E0645CA2606E35805F66CE586C81B4A65E2EF036697A18DA49C36CB22404497577107924DC02FD87072490D7EC8D5B376D0C3370F9753E0E7C781952C03D844490370D6853FCA49E12139805C24FE9C9914E3CF91464D332C934570DCD5D1C3C609C6984E28C9BFCBA3669B75452478DA4099CFE0F6311FF782D1D0123A120F657CB536A3810984871B69D25913C305117A7E51D199A56387C2777E349748B9C2C40DECC03DE7235F7237CF43FD421039743CA72361DFEF2491953A3C3F0091FE3EE064B838BD73E9E6EDF8FD90235CDB374892BFC42759792E5636D031795C0DCC70D7DB86C161FE7059CE17B6926FE5D024D6B1B9DD5608839DF85C7802F5655525B633BDAD0803CE14649095C0A7F870F66888C072C410E0E0854238BA7FB259901CAFE3570D398B621518193BBDD75258BCB53AF2789EC66DBE2311DACDC1F9CDB6DBD4BCDCD15F9C2E77E0D2736CD191D2B83389A71B1804A0FB5F2480E38343CA48EC6D1830BA3466E53FC51C4EF05F4D10711A78AB215650462E9A26D9301EFDF15A3CD5EEE14DDAFEFA45171BA3A757CD6FAA5887A5D5A98045BEC7FEB331D01A997282910B6B946CADF0AEA57973520EF0561B233BCF798805B3B048751EA086FA71BCAAE15F8BEB837CD2974EB3E54D3B6D3F99A51F88313FB64218610CD1831E2E6E18EADCFCBE72BE5818B4AE4F3780BAA7D8C4A55DAFC10ACA3EE7AB7D1337506C485C83EB0C41748C668705B4D41D926221D33C31BE7D56B42BAC7E9240FE4C2287B5B41FE88F9B9E19970D0E4569DBFF167EC42BAA2566676EB055B69D159358D23DABFFC86A917490B4942A220038CDADBE24C335DEB895F3472F0D22778BC79B169D1EDA9FD18B31DA66F0246359DB3EBA36269EC5F92E5A1A89560C7DEEFA121A7035EC2501C553854724C5176AE60F87004F6FAEA907B91D1C58837C9FE25BD9C32F66257BD78169B1A4B8ADEBA72B5699D4C2D14F67BB347EC8A96B04278AD9F97A9B40DBB56E7593CF4B3C905108F10968F0AE6A2E7F1D214FC7B45637A256ADA5EEB70E03C02DA2ABF86C36E581A31032DFFEF4343C3E59EC7A2A715E9C199DAFD3BF8C9B43C1D016DCD33E2590A20EC8B657C08E5C0C0BB4F159A07206504780715A252D1F4F5DC65ACCC43E3CDC255123A77792685C9B68AF281863AC89ADBD5F778733E95050ACF781FFA386B3EBCD633D6E8E6D4A42EA85F005AA80A4597D40738A8E8823FE3C84B10CEF044E9651E45D1ECDF59C537AACA58D2BE42655259DFE6CFFFBDAED252254B732EDC93B4D610C50DC81B576C5A5C5BBCAC0BAFD7BDD7771EF1A19C29D7A82E448AFA07E7FAA8651C11D1BD550DDC69F4C9C6A44435034D80B47B512155E5141378A94CD277D4BE11B2A383B1539AC9731079624E81D3A3404F5325F5D2EFBC0929F510529C84B1BC3E7C08F661640E55AC49452C00256BEB49B7A52DA23EFFD85B8C303C6EEDD2202768ECABBFBEE87FBF1DAA992C8439602B1645C462D3297DDA1AD941617B508E481A28D1540212CB281B5388A3691A26AD7D3CEF52FEEE9F59F477EC98AFCFE38034B762B9D4B5DF3BB312758C4238EFFF94BD16D9C39655CF07263CD6DBA96D1C0EA425610C1FC81061FAAC5C0F8E6AA9591EDE2FAA1AAB8F76EE18", + "C514F282EE4B5E02A90A2AE126DA52A9FF5274735ECAFA74CB36D607EF299E0227E94B6CC2B78B1F71D6B5FB8BB4C78C09B3A6E3ED6CD590AD526F74CBF869085F2BD3A9DF66D7DA9DD06FC6748D8FBB78D98A4D860B362BEC6295F34A6A16A58BB21C9632F8B3A64370B7A7547E329B39BCC82D17B82F6E4ADB514444F62AA800C97B748D73B0168ACF2FA898C262820F8981713D00CEB8453E3E9E452F5EF41452A9C8CD1F1260000C4CA9AF4E6E629B13DFF203187C0DEDA08315AF24181015D2E68D6AA4E7E938FC4FA9A8B80CBF49E3A9F27953A05FC7609146EE39F09FF485015168636D1F452FF311D4D8749C31AC8420865A87A707E540D7FDF0D25F63C7F3AC906E048281BFEA46263B4350BAFA8B5A27E0CFB23DE145622BC2FE34DCF4E1B4DCBF60ECD5426C27B3559B73A59CB1B71587C685542F5E6DF9FE3C5E75A8E9600E89217343D29C67A7AE80F9A8589D82AAE7B2A1B8D6546D3CE2482DDABCE7FFD3BEB2F1009297A77503E7155ABD4692F1244A49AB32628947A681388AD75A750AB92C81ADFBCED0AF166326FADAE6B79070473D67A8FCEBA7F21BBA932168CEC2A754247CA324081900636D87D001A605C4E5C31AEAA44A8DB9693617566726C7120AD15D96D917F5ADD0D86A5A9CDD7527644EED58A9BED014D9F4C0F62FCAD8D7D5DA2899D57C5510EF15B7482CB3E087493959AA12D73D55E194E48CD128FBA2788829AB4A86C325D60227074EA55BEB601128D5FF42371E74972B802D3117E1F2AF2018177D4E994903996DC365D3B52582AF2085EE5919DA7E84A2F3A200F4F6E76F11CC95F87BD2EE5935CDA0D52D9EE6FBA6D59E80427EEF4B80372091C65E059B566C38A6B3664974396BD0383A35EED0494C2BDDC167725C4160AFA58D408978D5A345EB03A55127C6BFB08FC0B4EF7037482EA724D9D121E26F2249C0C7A927946A846A67FB7C565E86C8C59A49265ECC4927A8FC88873DDEAEF6F8B629BAA1819807F38AFAC501EC9F206346581174A037B1D7EA56628C660E17BA0A97F2E189299A7844FEDC562BE678B0606CE18493F717559365F66201AA598C68F99A8F28AFD74AAB0E3619BC342AE9F36D3811EEB52C8DF6544C96B679CF434B9C64FCA0F43DA73B9BC8FEBD609678F5E691AA706E3586176ACDC25652BCB68D98417D3FEE12B23724EBDF496D6AC3B35EF706EAC11BB0090066F3C421C3E298B00821C90DDADE472331B9B2CA1F1E53E6D68BFB059EE0811EB7E7FDBEF394E3E35E59BCC4B63FA8E09851843F28CD941F9A97E5B72C8DCB9D32F37B79DFDD1B9D7C22C10E6F65DF07DBC7734430B811BCDD450A10F491B1E0DA3746868622E457774D0BCB1B29F9C1CB161DEFAE78354B7F718D18F07ED6672665D35562D6F05A2B3666B667A7C57D2617711F27DEC15D0A4079519D0ACC6B3591EBF0A61A12C42A6820CBA755C07FC531610C4192A0BE9BF241BBC5ADF758FAA4DE47C6B766AFAD728BB1D2C672EE0969303E42AF789FB295E766E90319D98F0618C1B4B8BD31CD2C5EBABEADA30C6E43D03F380F4C2B9C3AEA20BC89B852BFCD042AD3C9440AB395E9E251DA758D317E39792973083B20B79BA36A14057E1DFFADCF903B10F8D3D4D35222E4584D520D6FF675D3EBE9FB43ED1B79252648A5E0C2552E388AA3D1168790A09854F1151A94DB4E5AAF1C941FA61B196D869B16051B75F56AC1BC769C6E7A7EC173264A2E56BDE4BB9952A422855D65AF1C209D561F8210FFD7C2FD6A540BE788BE3D2822D49DBD2C6B33299604A835F07A34", + "0C0184CC1854C2013817663EBD9E23F3B78DB8009E761F1B38C2DA2036F26819D2DC68AC38C18FC15EB00BDBF5A11316C7B6075BF9DEAE9B0A651527DB3E3B3039BA01398B3923A2C40DC4706A0BC186D2F8FFB124EDE35E8C427FB6FF05A3C2ECB81E275D1AE370AFDFB6F731E27F4B22B877B1990FE479239526C655796BBB8545051527ED0E532E0440048912C64D0913227C2F6657B8B80FDA076E49B7E3DBA1D0E23C9D7F43280A324DF16BEE2A87B87C21692FEACBC3348C9186DC6C0BCB7C1DBEC60AFCF4F1D76FD3D45A24ACFAEB8E7C95145D07427CD67003019AB57DC233D566BB9A20AB82ED4130D9B4C0FAA6F2EFEDC8977498315FED436F67F3B170877040265EBA49415B1B2904C8277A11598432B973AA63F628456AF2320D3478FE669E2835C00D13EEC7B6ABC6BB94F1677C9A05B2D0CB87ED3E529AE1D2E3354B1E30C6634E10AB3BB0F39815049DD5321B11B80CF1D1F1426A413D0D11FAE969F3BA266F4F7B60684224A6279380D08D46FFBA2E1D684416405A02A2AB2E260ADB23498AF716EE58B03C8CC442DE0EA201C4DE39FA7038EA4E0E1544BB08F149F57F03FA910E09C27303038EDCA21A618A54DA87CA747763EE6D4D1DD4912AB7E3BBFC999939F82563B944CFC5F4460D41A47573DA92CBB28439BCDDBEBFF16491C404B356E5889D33A034680F8648F2CBB1888FEAFC410FD5A3C8ED85B90EC875D7D4466904F5D4A4048D8DAD848313232B80FEBAA09D4D86F70045C0C2499A93610DD088A6263DE5AD71067B9B3C82E20658AE98677889BDFEC65C2574E4AB7C9059F1C13CBEC17EC630F9E5B891DCDE1E81552738D4C8612F3BEBD570EB39B24EC94A153465D1326765D9B8F23D7E4AE3F2782F6F9738C189D0D20C4DFCCCD37D9A510250F0941423CB9055C7BFED84520AB119FF921CF81CBC6967E9CE1D759E5F4481ACCC5881F9328093B63ACB7D04404D8C0FAE8747D39A270399000CB690CDE17A46E81DC5CCED183BB863FD7A535CCBC592C25B059496C45DAD179B83EE02543B5EF93213E10E2BDD480F7C7D007CA2988942F65E46B886EBCEF05498C655048C4B32A081A059A28DCF4D84AAA586F0291F322B25D186FCB5ED2DE7AF7EBE58CD8314CF846AA39C67E2F284162524A14BD2765642B31F31EF4704548C13D5F5A132E983203EEB91795BCA934BA7EB26DAA5450745333446D2B86ADE99788476A3417DB7FE9E53F4906CAECBBA984657969B4592F9213612AE6812C215D5C6E28BC89BB76B9CCC937BA4D4C6368CD4C491BDF41B242BD8FCF9DE2D35907F08AB80BE71EF90F84BFDBC6777A020DC97BCA1E963050FF991A4F0E1E468813AE1CCF05B819012377334AD6B5A41A87A7D7C4F0AAD241FF7D3AFFFF40D7E6D5E62F9884B63E23C3A8B96260A6E9E3BCEC001D487E3E75DF4D35959633BE719FE592C4659970C0B67596E9CDA4EE3B05237C02CF2E36FFDB7CAE37F0BE993FAC46DA6F56B15FA74EB4511AEC2C861C2A9253259268A9BB95468FB02867394AA8D83EEB6464A65CD15DAB6A696FABAC4661F439F377560F3D2F3B668A7648BA4017DB5083BDD0D76B0DE99FBC06D7938D7D2F0566D3DDD036CF6A5E336359F0896B9B1E3B685D963A0EA70CAC175574C5AD41E20EA1332CF103BDE6B1C3B3F117C21E8FE7450866C5036C244856B5FAC176671270EF7225BE7CC36D24498C92E5306C2870FA7839DB1D7646A62AE0623EEF3199E8DBE32020B71F23FEF2F2BF3C9E0EBF0FDC629D97837B97D76C99398EAB044AFEEBD5BFBC35FD4", + "8767E0FD01FC0DFEFA6640DA0B47AB5B2B2CFD25C8943FDAE6AF46C3898AA1FD2E2DD0FE19D1A9BD0353A16ED03C448B7005D56D108FF2035E948E3C4FB8F0F928A5797D491389AC431F271DD1C8FDDA2B1FE623D410190FA81F74E042C0BE9F97F99120DDF442D5A4ECD1EC9789DBDFA8C8E577E0AC5A1BA7DD6D5A474CAC3C2C04E71A14DD2244A30D64B17E4C9B081EA8AF0175D7D0A6E039B6A289EFEEAA20763B1F106667745EE2795CC588721BFBCA6D659D81192A02FF2CE11CC878CDCE73CAC9B92A972CC9340ABA7A03C3384ECD28301103F347D35FCC9B12B85FFF170894F7D104F34D95B56A23C486CD9E7520EF8CC0BD928EACCFDC5D230D77EB9B19EE274113E1F8BFA79FCA93EF54B86900859BA6688FD29444E03E2F14033F076FF2F23711129099051C59E0126A907B57905A021F024D98736C3F5D1AA11C25F32319546F91DCFD4940FDC7C4428CE78A998694E6B19AA3CFF470AE4582666D350ACB02CFECD0E9EC39D1607912B892479EF94CC67797F443EE6BA4008F46C0E61C3819C5F82DE7A7802E62E7050C8AC506186878F08ADCA8A7674DC3D0D156060AB7BB08511D2F8DB46EAB9B46AF359135030A9EB46A6137A9419D97C7069147BF5065712B1F03BB8B328CBD1E583F59B662B64C0F06ECEC8B71AA2213EC29F8968E0F3093AD04E739F01DF51C644FD4CB65AEFC7073018DDAA81185627B613242260CA7A9270FDBAC3EBEF62865D0341B5392DD5FEA4827D60D5AD1C9AF0739CF5BFE0F658E72C436BFABEFCC403B87AD4B64F3143DBAE1D2CC25130E65D72ADECA1A8FDE09EDFD723072D538792F50A067BA78D7E4749F0344AB1AC1CC0E8EFA1A42515877C4539EDE35556D444516474628BE9D8B29DE428BEFA12EF99C985F1EED4F937BA4794776C63033C03EE356991607473835A50718E473D036F3C522A9DE2E49FEC2E686F17A5023FB7E82E94B26A4AC6236E0B656A938BD7A8575D734F53CA419836110DF78197D7DE4D45B6589CC31F5057759B8402F43ED9A423A7D69DB02EB9357B1E51207161E08FFEC8FE286722159C570ED4AF63EB554BBA582404C0E978CEAEC1CC1404CD15BA22EE6D8C98C4278C1714695927C2389D74BBAC72C2516AF1E5D0C52066A656170091B68A7E4C8399ADE63605E9DA1727C189C541A404B7335DA27843A32E470FB4DED8EB5EFCFD30BF15AAF37D7CFF4B545DD09DE3E7C8D0E77427B3C0764608912616E5DA2A3B885688F25E83DC8D632BC00015C2C8E6923A3D9E7C7344CDE87D6F0DEECA2006F644F7BDFA0A524759B2B16313501A1CB8D4D762D3E9D9C8D32154F69F0DBABEBD26AEDA947485FE0B40D1D7731D7F4E41D1EA5FC645DE31CD850273B6EF9C374CC8E8149960B349BA16FBDFAADFF12E86EF05AA38B6B17EEF7B55D27D7CE27FEC916DF99F0715F1DDFB93C7E1130EDFA44663CF19F4008D5CACA48262C1E8209D0C353ACD72A542B93EF18EC7E15FD4C9B1633161D94B285FE8CFAC30FBB1E140E9561A35715AF982370AB4DDF25BC30850E5F0509297289C0045BD3B3912843A9B0BB88CB7E961639849B8A0A75E3E903182F0CC6C7ECAD4A38081BEB18DA72EF9F9439DA7DB2B4D59AF6CB71808E604E56E1D4BFEF627226FC28875888BD486D0C8052068D12BBEC6B27E9DCDD73DBC93D33EE66AB63936C2273525A517280FB4BC33A724D20BB7D988B938018EAC4738D03D583A71C16671B87CD60BD6FDD101BF2AD07492A794FB8696E84CF24B9707D7706F0AEED606C3A7FB5B1DF7FCF86E65F6DEAA4", + "CB8EFFE09FE09C622B34574E74D4B061C284F96FB7937481FA7C204F449BE9B2DB0957E428D177C5525C67BD75D75989EE98D97C4D0DEB5E72E2B0DD62E66EDBEF0D22D2EA97D42A3374B9B659804F1EEB01D7743DD9AEADDEF356C7C4FE94077411DE58DFA5035271015AF65FD1D78C0F17632C10EA02C537706A7C14E3A1D7124FCC11F579333A68A1AF70BD3E86F7B1D13A3B4EBCDE343F36A2B226DC53A0E1A084EE966272EE852A349D7A5606F1AFDBD81B8C3CB556DAE83D6A34ED4F9C06BBFFCD5953C51814FE0F4CF5A697EEF5559886D92F811004C04FB399E06DFA845DEF183160BEF8546F6E8995E403FE0E464008646330CEC4B4149DC464F229A47E0CD9F89C83A28FBD0C1E758D380C2A7C17A487191A46C04C23F7906418B69E2527F3293588952919D220EDC36BD9687C7347AEEEFC8CD24E91299900AE4ACF018FA2829E215CB13CDDECC918DC85BBFA317FEF7D2FFA9E3A30D9D1F1B9DFA0AD0D641E800850B43D7E0B187F2ACFA74FC5DBC99471A7511B838BEBD6E2744C3AA9AA9D46060C83FFF803C148C35209F840AC23D60FD046B461CC2D776AF51612DD166E1450B8A998052EBB25D1C8F426391A8571C88C2012A8940CB0B4DB3223CCB39021D20142FB5039A6ACB250994AD7A99B1A43494EFFBD8D3692F213B46C6CE9AF3477BD6061398CB19C099F27F48F4F785E9E741988412F070F39727FB8B74071E007210D939B0EC5D6148A5931D38A030374E5C0B575AE27D49DF49A77245BE310E49262C56A616C757A80C5989F27962303825EAA3AA014A4C9C9E5B3CF93F1A031F82D6A0C877277EC41356D1BE2154F03D807940A1CB2848A6A23B905BDE9A907F7C20E333586389014126765CBA8D5C8951CE09DF085B5F18A24E1E5D638651687CD2A2F75CBAF738F65A8B24E7C67E64FFD9CB8A34A473F11996E3663607A49EF663C4D87A0F65D92067132B5EF3CFCFA9B49FF66CB6E363BC1C7EAAC392605200A5EE704D1E754CBD1C9CDAB75355BCA41DC129722F855215220092CF6248609DE9EDC5603562F5C82B5414BA305CEFA60020E1CD93FC756241FE7A20CB4B550D980A7266E7B23B6FFCFFC4461F925A14EF6584B02005E1D795ECFEF93312B3369C52A8A2ABF99AB5255E8E09C05AC722F37A5E95AE46B226C7319411750562DBD0296F0CD1326055577BEAAF270E75F4433D5312038854C30AB23BD51F1246EC46599FEC1B628137A73A702606112CF61CEA7C3977BCA6701C8E5F63132C15EFF01CA1EDFA5CCA8FC0E3FAD392F21972F857B53F62CAF3BDB75D556E6857067015E11C5E217F5D1C1AB1D603571F9EDDE04499E23D39DCAAEF16263A5EBAB9BEAD8F61B0ED942EF261E0ACD309A903E73AC4E4569A65FE6490F6DD6842812DF61CD858D9AB54D3456C89CFEDF2621426E3F9D13FB94177104F6EB4E30B018C01F78CB4FA9C89F453B87FA7D4716B96B0BD2DC532D4AA7D8FB9D264B095BCE39BA017E8BB90D600DD2C58647B9D95F63783B4B90BDB83A175E5201784AE000A493A387E16F5F0C5CAEBF62A360A6A927B3FE4CBFD310A3163BFFF1836FBF9770583FA4F88E5A6E7BE5796145890A41FAE8BD1839110EC05C325012E19C69C3868C7507D04458C074DB3440A0E018A23CDD32ED35E7A28DC8AA8BD63C8CD0A9F4876B56C04D5D3D5CE52A0601ABE2AD3CF3106CFEA6D761335F420EE3D277DA358DF4F6813D543424653B256E325346F677EB7F69B2FAF9536DE80E8EB018D978484509804D600783708D48C4F7100E0AF891BDFC75352C", + "93EBCDC22C36C3BDC8B579B31AD5F5C9B2B08218BCCD1B29829A365DF4A8D5259753381B6786877A5250DCE6A2B182734E363B39560D3DF44E88CD6394324765087DD1A77B3D8121CBA61F665F9B719E75B740BD930D6FEF316325B8B3A2FDD93AC488714AD9AB525248EF60B2649B70DDE6849BED793264062B38EE74270CC190C6A86AC4E106781BB3D09F0A6D7AA4DDBB0116D3452CE041BFF4247819FD8D78304088355D8DE741B1A6461C74A4832ACF4D4004BFB22F6C9BB397D7CADC6FC05AB74919CA346F9A54DBDA80F8E1303A1D43239C5DE043C2AC21E182CF49BEF9BCFC109BC884E41FE2D8669915701992200BCB938A745FB0994E6AD01187C4A24212DA421A178E42216287DB1F6A25E8370E4209E09057E16253BF477A061399AD1B3FE985D6A10D8B05FD94B67F878649862D68F285EC0BFC06B7006589A590AE7B116EFEFC871010993F4768197473BF22AD54B2A8FDB0BBF2B181A2A1CB9FF0D0989F2F68B339A8D8B27FE1781F3DD6F7CB972D73E3DD702FCD0CC3CBDF66A6237460E3B2F45DE273D2BCADB96C118DCC19F7C1E703BCBAA04DA5370A5CB3B78112B8E95B63328B43C51557AD84B3564749C2802B52EB33458394747C176E119E1774BC905119312963401C1DEE02964DC9F1D836069CFBB9B33791C908ADCC717B08FE3C0AE98C0D5DC0C22876595AF95A02AB33BCE3502A92E532E72D0E3455A3D7EE796B3CD5D61DB902B8C0057F2D47F2655E95DF55DA562F632A4F9A2CA8B1D2DB8F5745A71318C37043D3EB08F9950D06C1301F9E9FAF4EF560B238BEC483DF0E017E3CB27A251156221F183F3E9B0581838D04BEB5DFD9EFC26B979BCAC7DF631F1ECCB777E2617EE7386C8BE9834D26B96D80074BBEFE8CBBD203299AFAE8E6F90273B92182CE7EDCA9154E0A33AF9981B8CEC94E6A7C78C4716B47790EAFC771C3DFDE276E4E617CC0DA50F05099B9BF587127D1D18D5F892E0090C8D033F21E7382738F1EAACFBA493D776821DBDFCCBC24B1D5F877B157AE6BF6D307AE9BA54CD053E68594505D038747A7D8450EC3CB4F2E980C5D97A2AFB31147906CFD3E9000BF166EACA8D16A532BCF69526FB4B86B1F71D2C5F38958EB11F9ACC438CCE14E88A11DC431CE4E20B99DF0ABDD2B5AF358260A64012F4A408C6840D365AB95167B54FD479E8527B5FF662161F75FBA7CF790DBAA51613DE7C52A2A94E4AB78E051F32D10233161A4EBD8682389D091B5C4509171650ABA574F1FE954698268450E11D2FB52C1AB3E4DF426D26DC6D5319FB762CCCDD552F4B1BF4E82AD1F78606C644185AE87827F022C9508805472136DC48E71D1C45944413485EC1CC72BC092D6F9990148E12C2A3FFB3D8C9F91C18CC9086F176733A83F2CC9BAFFBBD810A99B66DC3B399891B2045BA402749B55E7E363F5D062427A9BFA8B599367F1D07A38DA16074F75A4E095A528C26DE4083B044055F73D207A6571196263D8BF5A53B7679791BDE49E869F0F58431829396A34415CDF4CB986281840BC48857361281CB4BADF8FF5B86ADC76FD3A812D7641C5FC88A21F137A6980B42FD3858E2A057BD4D3FF57A5ED3F5C41C71C70036E1762C0079DEDE282175072A073A90AB83C9DB447AC07E6BF99DB04BF276FD876F4E4816B0294333BF3403DACA2077BCAC3889B55E76D62F58DE7D1C49816D03DA2D492D1F3CDB2B6B186439CBBFAABB645E9745F404538BE8FC4C698765A3C67D01CB54D404D2A2E78098FC334F0A375EB41C3031F57FF9A773612445AD3D98BD09C949616D4", + "5D55CEF58C74B4C681E813564F1903FDB56BE053280D438BBE5E2480CF279CE47FBAFD179E270D838F764C2E7F496AEA9C0800056F2E0456EAA7E59CB20432B65875455975AB37186D6B06FC7D0BEE743CB974DF92B19F4D2EEE82F36598F8E400DCAACA4EEB110ABE352D3A0F58DEFF8D51DBDCE5C23E84D1166FFEE5428541ACA407B9578E4295C3F79F9376384B630D25F11271C6234B9AA9C1B4C8015AC2C73CF768B9EC30C61BBFEAE1426F72FFBC995A834C9D4FB8350C301133F123313370C33FCFD711D1847CFA84E782F4B39762A02F9476D5F45237A29E3E269D16DAD60033E0907D5431C1CE36D37BD388024A020B612E1DE42492A3759AB82AB393237F4A1AFEB8217D2733916B7B610342C0D182C17BFBD4556B071D82E6C6E554F2127654C15671FA1A843347BDFBF9498C7B5E7636318C3EDBAF7BC4BCE123698A05538DD5D42F01970A41A75F0A46E61520911D86A39D892700AA23A033EDC836EBC17CD2EA274252F53A4BFFD5CAD88F8066744C737B364A0DD0B5FFD96787F7D18357DF728FB66B212DD4DACAF7218292216808E7B81E3514BDA947E436A301C4181CE53A298250835AB98DC89D0A3D6240C57C699A5BC31EC4CBF8C111149CF6802942256520BC7FA22968556E2B390E63C9DB7D0AB79939924ABF068BC3D44264D607F088A38FA67F8E25933091BD3EB0A3590F3E62E63CC6C66AF66128F7C3F97B76E62F1AB82F24D8C147FB2C8BE207FBAD7E5CD355230EFD48DC9FDAA4FD1C970781674E901D35D7C651EEFEE2356F825ACD348FF0FF590E8CBFA0332F77A063581E6F19F53CDF1BFE952585E93EA13A83BBAD06070850EC824397A9FF13227F4C60D65B67AF810EF1BF5D5EA95A5512F95AECAEFA25BFBB24CBE6785E91A4874E81E465AB91B1F2E990F37AB145645F2681B47592990CA78264DF8902620E796D4DA9A260D1BA67DF9BB0292561FACCB2478AD7F7D7CAB3DF179897596604F2B0F1E3F10CF842C311F49C6B5EFD5D73DFEFF59127384D3B4D855F8C412E949E3A941782C186413946DF8AE33C9640704CB0D930C12F5FA1C4CEC5883CDA699E294019562948AB028548FA974D6C56AD667023F9C417F067810C4C7E4A712FC3417A92C075423A57C208AF683DDD695AAAA5F027CE535412DFE0029B292D32B2366DF978294FD263DAF8C6A6F7CC895BEB1437CA189C2AD9B6FD5BAC06DDC3D075DF55BAA6E75865CE375DBAE862EEB7A51D0DDB5DFE03234CC8F14EA99110DE78A3463546C6CCE5F7C623028134968C59E247E642CE17D8933B6701DB7952FBCDC6CAF7F2FD24A241D82D8BB1C0F5D55BF55E57BE4AFEB4200C1C57938F4A6B1BE9AA02FA86AA811577BCF1D6BE545D6F12046735AE963DC7FDAA9A2F7270B8BB37B3BCEF7C73F59013041B6CF9FE10FAAA86DE369E868FEE7A37F62E2E9CB1409DFF11FBB09A76AEEAD0F8E443582319F6F74ED0AA3229BB7A50043636E881BD139EB7442FA35F5DE1D6CC227B921A1343E34030D2F1F361D7651C487282C907577765161DB781C49655A5F87BBCB68D08C04290B4A2A94B61BD0C7CFA41821B7F5641B899E90DA026290FDCFA4FB956414523041E14ABD7B1AC7CDAA1148A03B6EA17C49503F01707BD3373EACFD4E248BA0F8D4B845251BAA35D41DB186E10464F6FCCD2CAFC9CB06FFE9DC97FF41E07084B00B7B31FADE0E093C8968D1CEEF9810986821F1741F11A71F5F20C809F54852307FBF33A6C33C6A230EC7CB2CC6C44A3A53AFA49477037E55BE691ABDF6D4A852799453930A4", + "B19B7C4DE003906A0001E0DEEF57CFDD2B50514CDD6F57FAA2859061678DB9F8B5AAC67442D8B737F635DC297E3A46C34735AE4D2C607B06964D1FE264B7786B8B0604781D4814E2A81F3A0250D4EDDB77C121B962D0E7109A738630557F5AD47F95A0971A58704CB5B53AC378781B48D67FE5D5349440261C58C26D9370DF37255CFE845F7B0F735CAACF4921CC9D55B3431C6C888787D7C2B436C9DCF1DB94FF0D510BCF15DF0DE42AAC7640741B4893C960FADDCE4261E6284681BDBFB0F471C864FD560DFD87DDFEB4EE7A1267E285BBF2966F6A8BB408A105034220F2565E38F6A15A45B7FFA82DA63965BF44A182FB4672E90BA7933A0120A449323340D0368CF057DF299A8CF60035170D197104B394CA9F2A05983980A1BD93CF3AF8799E613BCEF26234DB2550A15BD53FFA306D3F616D78A6204AD1D50FF4F9972B0CFEB48B76516155791C14E0C9E18457900CE13F672882BF423400D2E6FF94CB16BF3071F44CF2DFE8317A9B761FDC8FDE90D7D05827521B070492AEAC90187EE48D93374B463C3381C7D80178F54C676479BC92470FEA7069CBA95BFDAF099A994AB8244CA786E7767B8400464BD08D5C560D61F27A96E3886A4E821E0087E7A56F96DC6F6E85F1FDFB5C82FD7BD48B63EA794BDE01439FE4C3D7F08864263A0A8B1C1ADAA5DDE86B99EB2A619A12A1A76A39D8B1F04AB55B67D15C7878651BA1F6621658757B890DB0D2BB533BA1C6A5E3226DB4FEE7D561842EFCB5B459598CF5AD3F98217CA720B6781E83C2297C96F4F51CBBBEFA708AD4B3F682FA0C67C82A5F5797030E0724AE9715A911CEE347E80F774EC780DF7E2279924F67ADF9D07FE4F56DE99E06B58099E1104DCE62CCA82D100D90BAF44F26F19ED7AEDEAE609C04C530CFBEBDD161A2C324A382FC8234D405BF900F0B6CE895F9BD534A6474680A7D63C0CF7B4AF1D1E93958CFC02FB379AC09B205708A68D11683B9282564C06290F5E6B57E3E7A75D30C9E21DF8F27F85E1FF347B32105A000BC613006BD7FA6D845C8E6D4053FF012D0D85F99737D045871BE017D672C8FDEB16F944E3020BA7FF0351A303A0D3280D71CBDE42F55657671A79CA30A7A33E744E74B34D27453654DCC8E87911B3701FBC27CD16C4D9D6C29D1BB9AFCCDAB28DB6C2B42C5D6BC1D1386AB26669985B626BD54791930CED4A13716BC9AF8F4DC37A04184FCF711EFF515B92C943E53879B5098BCC4E87B98000BD0BA2E1CA3C7A97AC95C1AD145EBA3950B154888272A0ED49289157091DB2C55D43AE77FA3384BCE92E5840459B405237E194B6F5788F16B217D8BF7539EF8809FC7AE1BA931DBDB2A7D15F139EF4FDA60F02FFF9462777647D675309AAB8201B5FCC1ED7AE066FC0E4F32D260DD9406BCEFE7DC5DFB38D66CFA08E5CEDBA636EFC23B3CB7AC38FF7C390542C9814A86D2D8F676720B7E2FD93217F916F10FF34A1AF34E3B8563319E92A3BAEE34258B4DD63FBFED854E08B1A2F4B560FFC40AA1048F081E66748E05EC3EA02837272FBD9CBF1A658B86B19B7DFC63436185D02C6411142291645692A92E3EA6A113B5436B0BB78990942146956795DFE003A4AB6D9ED875FE7E5B895EBD69C43BB7317CA5C97BCAEA97CFC6068431B24673FEA931EC1DC1A3F72625AD531CD89CBEB0E07F47B26971059FEEAE3986E23286D13BADEA3585D73F1092E41AD041D59120D3D25FD3BB0AAABABA738049C91B22649E715F3710EA51C41C1705C4F1FFB1DCEC85F0EE704240EA8A20526DC01C7C8389B21DA979B99FBF44", + "5805FC5E7042027201F3517AB8BA6F5C3BFB0BC7657337ECCC99CA480BA9C3D36033336AFAC0BE172AF430A98D8462D46453E935805E594C18C0EBF735D90D5027067006193854E7DB6424688BD715A7BE72EAF93C2F763F3BC340EF4BCF90B03AF20C28A59F72114F693848289873BE3869590A64658C0A3938A414BDE86BE8DBC25165217B1605EB0402FED48DC09139751DC1DCFF532CBF599E9AA13F3A72142E05A1D8E47A4044269A0B414976670094C9785811628718C6FE5201221A5822E29DAD564B6EECF025DE7783B7842DEA40D4F72D083D112C608C596F25E09EA85BC6CBDEA39300774301C1C36790D7D9C0B59741F6B53E16BCABF8120112C81D70F30E44561EBF3A3A4571F207305BB3A292C46C46E285C246EE9A7442F869711F52D921EF379DF7CFEC4CE64BAE4D7AE7DBA3CAF47EFCEEE78B477C02550D1DABE4FF4EC67A38A705F60706D948C017E333B645C0D80AAC1CEA393CF3ECF711CA3D59ADD7CA02DB6C5E3F259B4ABC138D24C47A650EFB96AAAE93E69F08077D0CF38B230F199C3B353229C529278DB1F5846086BC8F5F54F9631423105673FE92799FFBE5DE6ED167658BA5DB5AAAF921926FFC27956758CAE8B2367E3C5C5C6CC81DA875AEBC8F3460275C4EE6EF43570B4F571994C7690DFDA3DE311F2FB77057732B19E6FFC96221DE1DAAF9B8CCC21609160457365877519D2B332FA3A85B9801EF435D04DAEC3643CBB5413A036CC1AA0968A40F4EB5A76D2D0C3DFCC53C97BB3896E855957B1941FEF59048562171F6241AF278F6D6B580B4C94C5CED65CBC0F810D46E864C2B567BEC920F6D1DE42CDF32300805E6022EF184B43C1733F809F98B129C937930B984F5539F574AE144EDAF7BABBF379EF1A1AE69B7B4FF9212BA817A4F223FA8B182FEA231E7029F80DB126641725C36AB4AE950725435561C6FE37F960E37927585026B8ADD92E4ACA3B4500F0CBE078680D16DBB90ADF6A127FBC7F791B4F93D5463F8C71EEC1EBDEECA881FBDF3D2940C2EA0F8E4DEA1074EB5C0C9EB34534C9C3992E988DAF8979FD8AA90F540F028708BC6D0EBBFC00FA946DEE5E9D01CC272A4FE61E5B86FF1347340FE64F650996F65E5702A61FB53EADCD457A5ED66DCFE1B019A79104842C51B60142267392DC51F86F69367C25B999B3153C1B7895298B6B1B43EFCD8CEC3694F90BBF1A417C48E5CC4983782F874A7C64E05BBF462220950DA9E8F56BA324002E91D934469225E57309C7F562407DB900267553B85C4314A63351F20D57DED0B3D210269B09B976C07878C324F74758D9D507A4CCEB4AA30CC9CD05CEF32F1174C7B0F7AF93875F66E3A7B12F163920825885CBE5092CB7728A1B74B2F3FA9A01264214761DC5101BB0C18D65BF972A3587F95B3E13F52EB6D1F334B15220ADA5A59497558EAA0F4ED358A995F7444B633FEB900EFD9528B51FD82F5AA30699900D3EA3F3644E4FE3F6F2900ED45DFD997FA905D91521CD9C898AF4CE09B6EE00A15057C17DF4C656E00DD876529CD75A169977962DF3F6E4CB6950BCA37A79C98F108AA7B02AA488AA4ECE05F702B468C20C81630F51F884AD74A76491DA378DDB8290ECB8F5879F019BFB416BAF1D9361126F3514557403415F286C8E77C0BCE4FDF0F4EAA96D19F22F189971155F749EC19687657B245D392BDDA62935A44BF6C82E0AF3593BE06745099F06DC4A66C0768F17916AA360988D5E578D169CA84AD1A36B12CA4929223BCC52AA9B47FB138E999CD6423D1171AD3BF87B5D405A174B0398A689DB4", + "F99EA1599DA410098772B05B5D7F9AFD485A04CA036BAA9C71AD5DAA3EA5F1C757BC83F3C0028DCB93DDEFFD157EFC2CB29C0F8146D6704D34091EAF1EAA29AB915E652309491F0BDE632172914C132CB9A533E97F89F567A7A9B0776B400FDBEE71B49AAAEAD156753F5BF564CACE2C1285C4E65B5D8B2803A11B22350ADF79645AB6E458B1C9E2031C4D4D6361F77B53329C3530F6EF727225DE668A960FEE1F6D7588BC126D0E2AD23C2ACDED06AA2331E9D0E7F99234A391926F0DBE610C600964E89BE1842CB1F1551D5CDD4AE3FE45B628E9A990C872622C9257BE40A8A124FFD6B135BDD2EBAC05E2DDE5B7DCC13C76C27C8A3E778063F3DBB3488CC52836E92A89641F4559F377273FD51FC45550C727689CA4D5CEBB26263F4268502658F40D4EC2BBC0DFD0E41F16A399F02711BCFA96C2456EB8A77FBEB852726B0DE4F927C13CCB329F8B9BDD760D1DD299863BABF42EA7D7F6204BF13F7355610527A38E89F66D3D73522B421AF013197D649D64EAD17F6A6BC8148D9989E786AAA94FA19077292015EF7CABA4B1545CA9CA20E5A816D6EFF7FCA31FDFABC611253FEE80FF0D75518001C2DD6C604387C2656E1362A3EFC1AB85461A5B55C6374733FB6B17090E6EC1186EDCE2C49EAFE84B139C66A2E8308CF2370095B0129B6CE7FF6E17D14F79258BB3E555EDDEF12E634A5AF748BA40735B90BA1E7DE7EA00D2F4A8B3BED32BFAC17D10050B420DA32EB6D14035CEEA1B7951592AD75FB751FCCF190452FA88AEF45080161C5544AF80FB0FF93C62B02B2E5D1966F77760D446F2625C3FFC91A07A5E852BE406F1638B521579FF299227769DC4B88A805E168F08ABE606B5D745433584BEED712453785B1C01D2B9F1020BDB7EF11936F0BC449EF26DBC2D5FB35A2131BE9C0DE2746DDB6D0356294D0E09076C9A77A076F6B659B7B4F54A06BE2F353A3A0EDC6A5123598DF9BA1CA852A5D1FA16877A78D88F0B367E6C4471758F0663A7498CB1C8F13B03F0E2A941DA89C717A15143F4ECF594B0DE2E43B657DD87E4BF536ECAF3820127B1FBBCC0BF2E53B9E0E1CF10191BA9B43D4D33FAA379B1B543C593F1BD5CC05E0B7511E8D4925BBFC5923AB0E2FA90D05ED580F56071A62A334408D3C454C892328AE1DAF16CBD530ADA7B858DA3763BACBC989F056EE1D46192CFF6DDD7F066D2EEDCEE5BC6B72551245EF8D10389984D3B3455A7B9664475CF6B837D72D42E49BA2F61298DE9BCC707209D7F1E56BCECE1B21FDE69293D2560B8940223E0AE966459C249751A2BAB98323F184532F4D6FA396D5C0AA2A4A41C75C638DC3DA5822AD7D3D7D51FE0811ED3673D875039D3625362D7D00356E8461FBFFC49FE1B0624F6D30D550FE1F5FE4211341B9D57D210237902BB7C62514AD872C1CA87976809717817AECE1E224733079478A5DDF5F2A067DDE111A3FF911D0B511A6AEE16046039B229C00D6D10317F66E1202449DF20CF28BBAB4112948C65DD7342D09059EE2701B36E2ACAA6A9948F818B61B9A3155729EEA670D4AEDD6F0AC314DB12E0DA62FBA01D419F7C48B09BEED87F7292FB0315A597CCCB7B51AF776509818A73A0BED7A656AEBD7ACA2646605797940CB737548E83653E204B6A7A5AFE2EF16EBBFD73484314C5699EC8D24E899BAA0E202F37E3C8D8B5F75ED34417E608EEE4B26B453C07DFC6E62FAC215B6122CB14A07739E86FCF816398DD49970AE8A216BDD8C4C478647A8D07EE8BBCE6631C22920474154B3C83942C842A728EDCE7466565D9A6BB030CE684", + "B23CE558D0DE0D584768E83A066B9BF6A12C78D173AA3262866339B86EB8A8D5208159C5873CB29E9C4C0BE918CE4E8DA85C85E070CAC29850CDE48E2DC5E0609F419CFA46EF650B9022273AF14BD9EA28FA856B7BCB580D8949C1F732F87EB34BC1257205BCB6820FDF3BD1E7B9C99E114B3C7607D01235E111E3AB1F30E8A9311F0F30B601C833FB0D8C4D76AC1B02F85E93D4C3D0205F735E20223410CCF56317B6A12D07F3BCD42D2023BA0676A00E7268733C41C8C7DED2555FBD2BE09584B3063BE41BFE93340955788603F1D52190B35FFB8148CEC733CFC1BA49F609ECD3C4512A99308043F3C377EB65870535388376C2C748D18A748F5828B3362666C49F803828B4A019F26D6A9362726E32B650A85523484C4BB2ACFCABD16E754EECE0466D1B370175C37C8CE9DE236FC58ADFAB4FAEAAA12E048BF40CE084467C8835A1E209D2CD67C5BF01E0D62CC78A12130F5EF2E3CFCDEDF86D489C4C5D9AB99484CDD469F2F8EE5E14BE43B9EACB92E72237FB54F9615627EEEB193EFF888AA0A908327C61C50D20C613C933D736F6C3D7F60969A5D3770275081365BA8A57DF600F10A1652167AE3E18AD3715532B7C4BAD97980DFB0C4F69D9137EC7B21BC72AF16F0BEC30B94A4A5C2F55074ABC6233CDF4D8D347F4FA942944D9B2539D0211B24E2C7FCB56BA877371AD7701ED087269DD643C4B62E4B40D3F6572C0730E465C5ADE50FDDD11BD30C07EFF35AA6218D0B73B22095D320448E0671E1CA59BFD52A517A50932A06C4897BA6F7E7038A39C92C20F6DB18D6F6AFB3563D10BDF48BC194B79FEA6861F1CB9756281E969968B65161D3980C4CBD036467850EDE9397321913D57C1EBD7743A44A12E8C85F8D2D1EFE2A8754B5ED0E93EE9649C53F28129130DEEE66E58181787137B262E1EB3FDFEE0604ED1AFC798B198044DD5D0A3E87A754C7EBF0852953ACF3371BBFA0FD5979901252EFF69473FC5655709EA193DCA2A2BA63D706C84F49802684F80C576706FCF1BCEB2892B9179A72B7CD886AF36C7D3ED09270A4077C481736BB69A333AB4BD864AEC1EFA944A591608A2469C85AA6431C47F657AA9C2043F373A69323E735B56BC8177E1E37AB03BAE93A7B304EA1C5C52B244FC265EBD674FA7F1647E29CED527FCBC93CA7A56A4E771D7D2E576C40B2EC736DDBB4FD7411168C5C568C446D1E454249E6F7529AD83215EDB62F57D25272F351CB2C40965B1DB65EF5835923EC2D2FC7D8AD56B67980A3DBB77E6C4415F54F3FC00A790DBCF39A2FB699A20FC634F1B1C177C37898A81D7693B21020C6B592E5A6359AE395A841B434B675F1C30A9CDD0ECF987ABC2406178EB2DE941393AB4F96BCD43626978AEA548173413EC9DEAE7B53B175AFAAC5A1E02D6EF7E27AC41268C1FD8DD83D1AC55ED45D087083C0D136048B7F61EADB94C88CBA5503000A90F91A39A8C9E2DED567F7FA0DF605AD7870189600B941B99240A15310E7B3FCCF5ABDDB56D50CECC06B4303BA39EFCAB2F7E9F5CC8F542E96034145115AFE3788DE0A4985EE1929D4935EF975E760DF7FED8A257718DFDC5A0B4B87024C59DCC6FEF6F2715582023C3C80EAADBC7AA8712FFAF80CF5E159CF5418A1CB50845C97A7F19DF3CC5FA344562DFDD819DD736E9ECEB7BD57AF324256934CE6DB0CF295AA0ADC5931D339027CCCDE1441891067DEA40F69F6EE07187F9B78DDF6D59CE02EC3BA6DD68F06851B10AFE9672EF84020CD53ECA25B3D5E527405AAADF60593A8080373A387111EA898499F096FF46FC58", + "8515E8CF42FC33A8CEECBD6E1B65BE307A5BFEA9CA59FC51A382C24CCCF012C38DFAD3FF3DCA3180934DD6AA52D828439F1052A959DE23BDDC3EA3F2E8CD70F7A765F77549BDE6CF8E444762DE51CBA3431439D1F1E42F1773FCA2F90E48126A000E69C0964B1955F586CDE1895419083322FB4E6528F61768F8BE4CDCB37FE9D02B27193A0BD79D15F3CC9AC6DDDDC82B02201BEAB86D13EA560F7EB5328AC0B534C52BB9D266F291425EF1607A19AECB9AD681815EC4FD1888BF5449421D92E473C21BD44F2C419A0B3E0603EE3C5C82E56466C5A76B76F81A6C394BA693991A5808334EFF1E996AA1B1394A4DAAE00995F02E9518053FC744BA391214DF2464DB9F01A5A53870173B3E8FB6B9B698A8DEE80745D7F71B70B811867D3513197B32115882348FC704B2AF8BD6FB3BCCE30361C1198B84865162734719D88BB62B7431FA39D452E0A1B0A7E45534BF76B6AEC48DC25B7487FEB4B5FFA9C56CC7C83E39AC196987747D664943A600B106F0C3D6B2D0D4425073EAAF89AB33BF6AD76B151CAC32A670A2B03BA31FBDB48B949D3074CD9F56D39553708CB0EF2BC96170E2FCAA3CB2811EF1C67FEF6FE85CD450FEA37A04A07EA732A696EAE8E76D497F5C350CDF72F8970FAD94C03909F67FC895785D5DB6C3A68641D68895AC8544C6A1096DC4CCD45A68BFED7ED86961B5E035E61E9C126319A7B3C1468457C423C4A4E2DD1D42BB90C8BDE2A162F999A8C3A99BE998B9DB7A14C101CE78F08857ADD9A96059DC22592B90488D77D6F0A6D459CA65FC947D742714A42277A79745C73CB157BB825E65872D9BEF5066C444229ED1A097AF6B0308DF2793A2284F911C764BD1158742EF4109CD8AE6111DCF8A40BE03409FA6C430829D0C9BA28B466916C67311F8BAEA2D8CD2DF9C95094E4FC6D43F4491AC5FFBF05BA6B7DB9D7FE4A6DFC386D136B1710DA5F30E67C8DE97A981895476B8E4E0DB5E1AE630C8034F949AA4095DC81EAA0F645B0B440138AA7C5C7C5FAF3B57E1504A5FE477CD61A355D9AA66C39FF89E2DDCBC1862E19102205A9F343FAEA71D4C67192D4D5A1AB08BFADAF6753244BE5B14B1F911700B4A947D53645DCE170401135D0D7E968F03A9B19D2ABBDC94BEE623FB64C1DFC4AD9040197C319A79391016D6D44B8EBAAD5B2F1AAEA58AEFA21B5B3D9ECB66B3B70626AB31CEE5CA759499073B4FDD96457392E58C0EC871B95C7B77F74B81C4CF5B1B243BD35F4D540C1CE878E80AAFC635D363B9D72DFCDAFF62FA8339BAFF4DE1EB3E146DB93E7E444403E0D4290AF501C841B66302A345F5541B1C797D630B5B7E788A793192CE1F362B22B91A837184106D852391A241A903E3BECD192C4FE52586BA4044C4FBDB20B711D2624B6CC13E0C5EF62F2B2E00CA516991C7572732DB94DB809FA0535D2E8376685506186170E3702903A6D08996BDE20F74BEAD391245680A029FB439FFB96EB829F0BFE58A6446B00B4E1894BE1B5017F706156072E2DCFAB25A3BED2DB310DA1A7262ACF24A65F41FADAE3F81A32077BB9CB64AADCC2F92B95EE56F20CCBA24DEC9F5F75B36EF1A101D0F3FF6D730DC199869F8F26DEFC6F51451BFEA2C0EE77CB17422E2790A8B29573405F112EDD704E3F46C7CD8ACF0E495C6BA9ED448B0B89A9997850F09A813FB23788681D3CC04996E931CB00A879E2FFA1BA6A63F9D3BBFC20405244B0F838A040F125AC2B4999A197A2D53DEF8CB167FB7E37DA3862CE3ECB57B081DCFD98894E45C6019B9229315108E37DCFC57C9F80201486AEC", + "4368224792A5CD4ACD64D6956A334DB4614EE5EF8F98EDE0B4A5CD3D06819A4858EE0037DE64ED93BCC7FDB47E90409638B3789BBC63134308B972765565651902A9CAF4F310E93BB08EF1E4B325D414DB5DD7CBF660A880642A27378A7427F2627BAB3444149181C54E9D3FB7967DE33BED89AAC255A47482835D17E329ACF3F08F23AA1DDEB730D9602243A6894989EE2D900FF6AC0579864C2361EA56CBCE2F39A75A12100670AF3FF1A36E98D1931D17CA68D8D031CC527EF7FFFB35AD6E046F4AF1B2B3F66210D978F8607039BBA99AFBC6A499A5A948C5C59055A140293CA97306BFFCEE37CE77C114478D0F73D1C8C9954780830D56878EB786967DDBC71951ECF815CC4266D66F84195CA1AE0375E90017FA5C66DB8329D668BE6C0BFD85742088B7A3256A3277AE2A1F4E72BBB82BB2A59B08FC59FE5F24EAD5DF43D95917A144B4DC6587C893314D5C2C427EA92D02E6922FB0B60ACA646092E0D4A127799FEE4B76587F26AC1EB89BE0BA46F2A212ACF50D93D3345AFE72AEDA1A0F855C45AFE14161E22DA3E223CAD6B47E591896F4283F10C4073AB524CF5D0ED88F979458BB928F1C179E2C5914B4CC52CC000383D154830A54332D4C0E652F98B91BC086370B04CCB1AACA56C9A33B9F0A65C33467BF45C74905B67607B83FEDA063857AC4E326B4293483C8841572174CC8A384014945F5C3072C5575A5BE322E3F2FE3A7E30F3F21118FDDAF23645A40E0A359A3572153F5C3ADBE1BBC4EBA5E063E9F73510C5D1D4326D3D7A20384724279C3B4795C68BA332EA706E8127672E41DE4BF1E8B5EA60B39CAE2C3B7B21A225115BAE051FB0401A69A7FC56AE4B7E31CE2CD575D82C8279E8B8499EEDFC134503E6798056324B17B8AB045FFDC2A35B190B39FF212C17C36537A1F99F2EC3A4CE693DCEC7DA80861FC6F3D064B82CE5581F9781289A085A300CCEFB6E80A86D961408250846A374ED00F5379F446FE6E551F608AC3D71346B738C75DCDF63E19EA79AFCADD5E1E07E2F7C0AC709F6428FEA1DCDD835E3F56B026CD8DC9D4629AFDA9015295C2CE55DFD9C83223821682B5AF876B1CE156343A0F4C1655448FEDBC992602BED5DA4B299B86EE2F86D02C757CB5696B32D60357B21F9DAAA06EB3BE2E9117D2C99DFBB5328B3636F41A06A020E3CB47851891AC3825369C037B0C0D8412204FC3D5FA9585F3218F01295375A09463AEC65F591A594551E19DD00D5738086A31712AE9FA7BABD4E9C10E9F4DA82C12EB2F3319E852B96E61EAD2F85BB6765DAF874FC8AF42746F14B8FA489DFAA9540B4D0470CB31F99B10C335F672C2E06E8A2378B9DD28E8F56BC7A4C017327404C79F1E8E67BCAEB5C4C793C176F0A3C1833007FC44103DCC6E273C9FD1909AEF1656E2B5756B7F4D69F4F2EA576228DD794777BEB2F34296691A1FC38AE44FE60A44AD894CE92DB77FC0246C779C13E8AA16648843BA68CFC5E4E02FB564B0ADF3163C5E167C275A8C15E58659E2F70A3AF792565422D3327CCE25C9D488EF3C32B195066BD27DBD44EF1A20AC6AA22250BC0592AEC734477E1112DC3913F6B7CE323FD1F7B3F8299B8C9BBAC23487F735070AFD5C3627506D4C96B0A1427F7EFC07EFCC62DDC5455A77B57D3FD0B8CAD30A346F8C34F42D87827FAFADD54264A323907A89334C0E7F98AFC9060D7767BC9D8D261BC0BF64FCA389BB192A9B4B00CB566D254CB0226FA17F3BF21E2926CA52CE5DDC401E74A92C7989552CA66675A9BB9E9C198BCFFC488BE1DD5E47DEDD94015BE09B44", + "30F77B7E7E40E42A52452A26283CF3A29B02DE3398DE5179773F2CCA4978059495B9DB13069B00107462C0034064A024DF3AD33C063F9608783E79E38F706B92AB117029EBD6156CB5D278149875B95AFBE877A21AC3128BD6D0B11D31DE7A2BF7CCB68911309BBD2215F592D56AF0F700D962E49E4C6D089548C7587B0598374C3D7BE80F7F20D6855AA28A27AF668A8AD3552CFDE3CE0B35DCEFD5240C8FAAB89D013D0DDF5B66E60328AE32BF4EDB8021E43762E96E5999CF23BF2457B1CD75D1457D4926E7C2A324BCFF70A7CF59047DF3F08EAF2922CAE6A7BE1BBFA3BDDFB864AC965B7FF093CFE74B53DB332B411962DA01D4E6C62CE6731E893574A097328CA7606ECF373CC987F98C31AD74EB4A863084266869D28C07F9C5B5F10385EE44E463324A81D523DFCFBABEF20F3F71FDA33B7EC1B2A35A98F01D13693CECFF23E00CBDBA2A2D09C8A86A819E82D781AE88B9F207889EDA1EBC54CADE6A69A564ABF48F950FFBE7A86243C544A78362D9BFB6CCDF20CEDE386B9E3F8D7EE0E4A58596F095AC1B99E4F787472A734252D6C00B177FD2B99A85D49B9C0F32D728F7D9BA4DF96D1BF6C365F5F4EED7D38727B339A223263B58560ECA6778069DFCE48703AAD1BFAD59CE298C6BB464552408946265B1E19C1FFEE000771814FB5E4688140E1333B270F05EC9345E8BDFA7B412F295AE3DD4DBF33D6D2D62582887D4CBB9EB55F5FE3C1BC32DC689548B66893356704968C143AD3CC2E48BDC154620ECADF336E218FF1B22521D183EB2D13B15A15D39A42A25B46F1AEC07A14CB805AC382DAC8CF96829B8F1D241CF5CDE5D849DEB242295D7870432EBB642A45A6C6F1C2786B88C883B9B47343E822978155D079AD9F6C8CD4A21479B32B2112EB0121C3C74E7C23284812F74A2B413B9A18D6372AA3E09BB04A262E7FCFB6FABBB074C7C603C89FF607F83DA32DA50F2A19C38BA0965BEDC7A961966895E17A20A4D8028FAF7B6947A1964601DA45643C5FCECEBDEAAAA83EA5420F2984CB606E9F3191EF323D644635EDD801130893D84DFB19E661E04188C6CE596DD38C11D1CE5DE1EDE0D15D8FC427842085D300E6801CDE02768E44BAFBB302684FD945C9AC722561B0EDA92E8D845EEB99F6FB1889328C74D6D9CC6DAB59D55463A613AF33226660C0C034B896075D9EC2F51165A754A7D2393E15955BE327587943ECC1F3BB97180E751941728B94948B6648D2C606D66B9BA1898FA28EFA38A413B066D715F7DC5F0C755B6A3126AFCB606EC6B12E332FD71E386ACDDD1DEEF1533D6386AE5994BFD857380874B14ED836D9DED47DE4760ABB05E80DC622C8D7882CD74B2720884DA747BAC3ED9A6EFA2287D5F7D6AC7821E79C79EAFE7A68D2543D7CDDEDB63A13FBA4B894A6D0B3E14C44876364C9FCF93DC066CE953E89851A49B6EDB38661C9316C82ED902EEB894321C84331F6646A5C1AFEF832F38AFEAB89D181D3DD1338DAA236BE0E87A6381D00845CCFCF4DBEC3D41F8AE1E6F39167A499945DAFE77601147EB29804A8B98E7EEB31DE20C84E9148BCCB15CD02D1E3B519EE0A2E4F70F57A69281E651B189C08D575D52E997E3A435B4CC86F938BC79EF4961CD03DF8B92A8C507DFB2DE4D5EB0ECAC2F3D712A46CD3EE01B8D4DCB845D23E53A2E01DF3FFA100078F7B2467A45BBB4A18D14E0CFCD089433959F07F6F60F651DD7FD9828069D340D048FC079E4F8B92824D54322611A3698FAF181008DB5E3E327EDC431A8F6E481484BD5A429D0F5DC55AEA8A18F719A7865B0", + "A7D629A25F82015CD70688CC461244E4AABDCBF2CFFC2D73A3247F4264101FEFBD5759FFB83E8ABE9EF5B6662DA3CF7196385C05D0E5BD50C71D3CED424AB805AD632F2C1930868ABEDF493BB4E3A9DE538D8E35146320EB9F5B71C40E6F32E9243E6A25F503B68EB484ECB73C436930F30E2776D17A2E5F9CAF157F368E0FD9C26A9E9AE30A30E15DDD8A56482C85B46F973D000292CFCF0021577E5DCE8220353E23DD8507D0F561BBCD96F6FAA451E9C595E00CE0F99C8C40359B103D621CE0C837A3D1598D814BE6E22B7A509DBF1ABD2EA60955364791A5910414646F9928B5676ED590F41BD128A55549170211A0630BF5C5BEFEA204896C7FBB40F0C72E40DF19C95F3A0ACD641834E5BCBD26E91315DA34708E2025E0B7D38F9513945DE44AEE57077C8CC32C707D9A39BF098E4928420B3FDE8C74F39F81790D827A628B8F2776251F51095C1193B2FFEE8C93F49DF6D4E3C2E1BDA52F7356394BD5A675543493E04D602F332761AA1D57DF3EF8213E4E9B8D4BF6C8BE8BCCF661507C394CC9D5E9DD4D81DEAEB6D638FB9225247818710E4724111F522610075AE757AB5ECF6FF32CF087DEC9A04A7DAD8C613B22F2AFD31466574AA87CF0B8545B38C53A8F4597D5F1BB6837AF26114D72C609B624252722DD867572D449ED7C170F99D4ECB995B76C8DBD14F50F3DEA077FBE4F838A03AF1DA6757C70C5F3394092D7EADB1E0A859A8487F70D9F7EE523AFCA08DAA5F8E9260D63330773FB7EBE01373C3719129E483DE3D132697EC4C108654256315A38D7060C6F52B4A444EF33E87946C2537A3FB3B5FACBB0F3292C7F2498F0A11509FD9678CC7C678D4623DC07D8F218E4B65F2EB844D24D696A31483E1EDD1063AED60D7A110F7992E3E46F8C7D5CB1AF02D598440D79D649AA415E5F3ED033A8FDCADF8DBAC48F9905BACB37E31ABB0174CC08A9584E25B94423BF395E097E2D0B7ED76B55C6231F180D1A7BD969F6B874B9255138A1C3A2847EBA159C7EA281433A39D2F88D724B6350E846B365BE838F25B904E7B02B12ABE543961D33D991D0DA93310CDDA1EF551D7B6A02765DCF0D870C2BBF578BF8457CA1B599D0FE445B1E9C39E9C8756EDAAC6A10F62C84F60A27268FC5B436A323AC5BF4A9ACFC55510558C5A354D96A5D74F69687385C123C497543EC14C40117ABE46C22FE54DC4D2D6F4823A7F3DBFD3A1FEED428B90945B8F6B2C9A162F9C0287C758603E2C7845A11DDFC37B815A62A1A665C3FC003DC9F064CD5D950DEE02F48505CBE1A1E515E6516E926FF6DC0123E1E4F94587F1F1568DFBACC3728BDC1D153196CD91D9F6DA84ED6B70D0DBA7E7DB4A71B224E5122328D1DCDB9FAA98E88E9823A49E7560DF822D67C908E9AFF7D429E84350163E49AFA4015337532B6E928BE2001CA202C5D975A3E54808AF8E110575AD5FCA28185B2A7D8A3019B97AFBA933BE2F9CD5F279266EBEF52E0B92114AACC30237B712FE53DB1B8596CA72DC82BEA99DF8FE845D390B8DE1C00F24D0D9C619651FB16A280102CA8BD7FC3F7868E4649C636064F4D0EB06D06595A0023E6C5D32654EAB9C8EB011186A32C3E5DB9BA6489895FD50A26CDF1BC27D599F7A8BD1922B30187E0DDC54AD369CC61E958661C4FA76054C2C6658AECAD7D0AE23A9F36DB1B0E1141ED6A1084A8EBF8975325A1DE4A679BBD0E022BC35A07B40C52FA1B0BCDFE17BB6EAD099088963D7937CFA5B51ACCF722FE4F9DF99DADA8CB05C17B6A6AE884F1C7DA09049027D6EA570BAA064736219CE1DBEA7DB0", + "9BFAC777848D427BC9D39876B843378E100DDB87ED269AA91097FA433CA7EEC7D6210E7F100C449876F83439E3E494941D8CFB3E11ED7AF04EDFFAD2729FF75A8FB14A9BCF386ED8D95C046A326A9A92D3F316C758F6939F14BC88789B17F3DFB5AA691A872CA44E908AB966D5F672FB90196D71136ED26591404202AF5858D44C8E0B0ADE3441F554040E458F5AA64AC3D5B32399E453FA1565F4E71FC9EE5BAAC97552AD75D0154FDE48AD914F6D59800A7FEF91BFB6465A296E217E554631FCAC48FB7FDE1244F00697C2155A3161169225109AF5AE218D51D70BFD452433BED94FAFA5920B35353013BE2CD0C32B8AACDFAC6C6B4CCCC2C222AE845FD76630E963CA22F5214033FEDEE3296112F9C127865137CE6182BBF09D1489A1DFFA82D9B391A5AFAE6C80414698703EF03BA42893786FB10C9DBD21E7292E197A2959D605EC466CD202BB4E7BB1E9D5B9B3F07F55FD8637314E3D68C763CBE79982FCCC0147AE6D4C96F7A1C251BC35D8EE3A4F6FDD9CEBF771878B80E3AE481619D80B7BB7EFCFA9C20F11A0FE18505299EF1BB195EC7A93263420D183BD89335411CDD66B4809BEB30AC649CF76552A6F08E9D77C2E9C5AE05FE469705E2E6F44485395C054F401DC6CB9F581E52978BD93CD927D47472DC52D81960F98D60A061C5ACBF9F5E4434B31BC3C55CCD71CC2F2DA6385A3D040DE8B8D5F5CAABB6FC301FE3D5DEB95A00F01772505201B33464F2BB1D45A2F55EC907E86803A94F9340960A5E99C727517C520D338A41320E7E8BAAD6C4470300DB904B1848AC84F67F67C6BDD6AB71E2531C5C662AA9DCC2E84634A5ACA48C5A5CD1CDA454C6689E2484274EB1A2D1CE2D94876F4978987331D16AFBA205E1D81CF287E5E59A6DE000FFFC99E50B0B124E718CAC8FB51A708B42C0FE669894383C01D020E45B301DB2FE85B177FCDD1A688264A0327614A4483BFB689DAA49E8F59BD2D3943BA06F39119D46E5DCD0DEF78BA40798384BEB03292F231A62F7B6E456F3542425599B2BCF96978626543266E8AC0426B3C4346AEAA1E2FE20B54F70273A5DEB9BDF92B8B4DE940C48963DDC569FEA89B4A6940B7644E33D105C5BDC61C3EB7D823D4CF3FA0AC7196D6004CF6654BB4E4602974FBFCF6E74FB58A83540254EAAA4ACFF41C5E1481B2C38E7084B944684B21B7C661F92A28508F449D8ADE8881D40AF4A161A08C5846C78FC5C562CBD36ACB83284223B2891F73947804B6AD40BB99A4E7D9ED1912448C99E5B572760E53DFC434D06DCCA06DDAD3BA09DE063378A98943EFA0CD3E75B1B860E8D1350CB920BD6FBE30D437B96290F49E37BEBCD2FF9F8A4BAC7CF8F4571DAA9E788A3A411AE231D369D35055EA48D03AF54D968EB71F7BD14E51A1E617F81B492FBC3AF3761C601CF108DEA9E198BD1B576F94DB9A15975CA55D356C209E5CE1D8329A5D353223AE3C5C9BC55468AD4C2756BB54B6FC66FCC3B0BBA3962EFB4ABA17B1B08B01C296A578D5AD63F605BAB75C90924AD456D53CB72436F3A2086EE61D7C3479E0381A52715292DCB8CD2833720572A40CFF97928D4EB54265F3110714C360A0479AE7D51126C5CCAC09372AE7139C20C46AE13E4C41E89AE12097C6A198A979DCE9FCBEC5D1AF9D9189059E5E317B77B6E98C29F38E29A35FCC3BEBE3ED0267C5503BAB0FDC46C7D89766475F2676C80CBA71110F815A84CA7EF91ACBA63AF7933056DDA345D527DCB5549C9CCBD5B201BF9D0C82683A8865DBB4DDD057002025D088B7121C118B3A6C901BFF83DC1114", + "18A25B1D741562F456B84CF500F138FBB34AE1D18E9BD6FBAD05D0AFA14BD1FFD10334E6AF3ACC7AC2698BA10465ED5EC26B13265E5ECD1C79359095F36B1B5333EF87E78FC44571ECC00F294243FE64C4BD7833FED71F3B6471ABDDBBBF4C374519D24DEB11A8D2EBDEFB8D2CB3BF517AD92CA598040D0F5F8E5607CD879C75E15755087EFF796EF432073AB647C9DCED072FCC9DC74D78326EEC1BDC9CD3272180E38DF556715CD1D37DEB8B6BA06B81F01C26A3E97B9475B688D32BB642EBBAFC4406B7625944603FC085B38E5E4C9ACF0D0F92A65EC9BAEC8AFD9A1C7805854B19EF516BCF65125603F131084CD13BA6E72201B13C1897D0ACCB8C4266884F3439F6833D22C08A68CA0EB7B636D866182E6F42B35EE9E255F3FD30014F4EF3484EF31FB1D17A6FC0913DCC1443439494BDA221336D05CEF0FF168A9C54830066A6E986672EB92B2CA01C7ECABD5B5B40049B2161F8F52445FC27379B0706866AF20800C521BD0DCAD90E8F4367929A9D21F1921049FBFFCB2BFFB69B27A2A4FC9E48256CE24302A57B69B04D6E51469D5D7C7E41DB6113693322E1DAD218FCBBFD47892E8BFDC28FE1461AFC769286C6F75165CF945E5CD3C9322955261922B6C00CA2C006070EF26141BD8B44798110A9F20E86C52CE88D6FAE122FD7208C9216011D7D91750A800576F575B8EDDA2545B3D60310D61F7351CA1C82C90E18641FCD747FE901351524B9D0B92CCBE86067EE5F126FF4B2C582B280CC1549CB3A18D5D9FD25A09A67DB83A8F3F7DABFAA3C09CDF00C6F16D722EBCE259723B97017885B70CEBBC1C164E1A5361738B1F3FA426D077AA97AFC56F4F147D3EC04E52AF0CC518AB4CE8B3ED66A1EDEA49E904B81DF00EEABBB5EA8437C18C0282EA1AEE445331C5B0414C2E3CEE637933753B30FBD2160E93C3E7956BC032FF839B81179DC5C41CC81E6B8A74EDADE4F6EA0FC2077D3AFEE342D75DDEC1539F5C00F640A56EBA718A77A88E2E8070AB9663037AD66D9B6314C268806C2856E233D37BA73E61B8CE393F9DE86DF5C76610766DAF68A8DADD37C3146F59115E8AC18330977D7BBF677C755B79C902A50DC457FEC314323927BFD45DD4A5AB7AF351228986F3B03E51581C8A8D5E4F8C24ED9E14FDB5D0D6BD2A6F563D66A31247D4EA17CF6C158BE7FDA81DBA14B9A1549D5092658BEE5542BCFD42C8DB540447AA13F208223DE36AEE06BCC2F280333D81964ED05A275EEF56C21F0BE0EAD9D6A8F2C70660C0CB04AF6D84E0D18D3EF56504CB18EA259BDA23AC1D8CAB42BC340448283D9CEF770872F3B94FE85A23CD9A864F76FA82EB637086D12244DBBB9E7B2951D3B0B6C345E513883F261D3EE312A31017BA33A08586F58084A8087144CDF634517F42AEDF185D53366FF728C0E7C0748A776F3932CA874D3C2C48B30D01A5F579DDB1A038AE1E20D986515309A13B369F644A856C995C2F6942B7E6BB624A0DF34FBF31CD9F96C486E530A2F3FF8A43D7DDD578D72B1E93338EAACC244650F8BB37AA9CDF721B1EDC334755B63CD34AAA832725A883333A4AF4ECE71416146A4F05232968680AD41C89872E14AE1CE2FA65B7A3BC099FE265173B0B7159662259FA64FB70902BA09988A30697F110B892D7D6C763EF80D6E904A2CE47BECED5E98AB2A3BB70A73D6AF7175BABF8CF8F38F2AADE3BAFBBEADF208415A2C2FD4A1ACC3140E185A2534AFFE6C01EB30FF0137503349EEDC1F9BB263C18F427E2B119BFC692D5FF44421208E8AF146FDE964C2DEC3E1C9D5699ED01A7D78", + "69A39F2889ADC98D94B5C678A3D3D8736BC17256367EEE3FE8EF5AC6453A0691D894F1F3202CE84EA8BA5A341D1733C6BD0150CE9C0019168E67768B33B64DD4C9F0E2BCCCF2FF7E370C2BDE4F403C270F36937119950121A840913CC1D663F32F01B665840EC9E09E5A9C345EE001F84B2C1154359BC066D29E0405941476C5B7B11CFF124F5324D4D090E2BC49C3E8D83122DA9268FF58B523EAAAE4493217609FDD5A5C510038CF383B65FFC7671119556702F630404C0BC686975E853C86AB392D25C853964693AA7F4A63BEC12BF51762DB46295D2062FFF24000E4F9FDD21972D747ED2F37DBBA2D6DECE1009222EE06B846FB7D49E8014DACFAECBEF2560CCF5E06EAD04B113D1F8E341F200DD8CDB3F36AB99B566B16A84F8C040ED8827F0E9F0D4FA340B0ECCC98F5CA4B05A990F3B410CAEBAFB409E985A722E4C442F59AF3ECEB1AF0B148A3E8B958D9F6C0E45BA4EC8553332DF170872E60967E106BD27AAE4A6C15D391C1B4DF7D77357B4D4E8B29FC874947A75CDB1A1ACE512C5CD08405F2D9F21D50197DC151B5E5A735F759628BCB5A70B5CC9855A39188FBBA8E6BA0F5B6538ACCAF394A809C68F810441BB81CE71F7DBB2A11D3905225DC9B1F0F0D8B7E5268020039E03FD97D42204E503EF98C26B5D9DCCF5424573775E536C4AA26BF4B0351530857B8F640495377E9A08AE82F227BA487FA1D945EC233EB1B42C18FEC4BEC651D4CE1313C9574976F092A5E52D1B37B5D4B33800F5C3803BC6ED2759AE3F6888E7120D3AC2F24729A08B2B4C8D44EF807987C156DD3ED871B0A6217E9783A78BFE56C819F2C8FFC2D2D83945FE846833E5ADE3F840B53EE67E5D13BF0B7031B6C1D004D274F43C1982C43FB58011389D2C7E9111B8ADDD89C37756F1E4C4A931D828ADC3597429AF3A00C0C9A71A44A62F922102CABA479BDDF25A088BEFDF630E2AED4351A90B9567FB6DB5FECD6F168966DB2EB6161DA84479DBED9090026C3CACC19B91EF5680A40073FEAFCAE161E3A2F0DAC9C0A5A7AA31D93B425D5B5A7BF6D38FE797FB53793EED791C82DDFBB2D224455349F26F147FE0D59747AB091585DAE61A32B04DCEF19D907C1159FF69443843248D75E772B558E7AA0FFAE2A9D2B6B1E9F34B79DABBC98B2FAB34F76FEEC635E6E756F7724106D08F296019FDEC94FA7B7CBFD780F2C0B75B1D88EA0D5885237F4D09F03B2E8E1A98879656AA33AB23583DAFF96D8FCEF548302F323A8BA959710A78A803185D88A9C971D9491613E5BA2044D0B640FECF219CEFE377445E5256FD687A15C9F66475C0270C9C1A7189507E881DC6FD5B31FFF9949342586E24C7827F260CDAE356F874CC7C913ABCB40E892E495CD4388AFB84AADB45069F37ABF7DF966CBB8EC86C0CA5A86E79350DA5D6BC2B23EEB51B9C9C352FD9D3FFAE368891D8FD4E2861B8002BB16DA0C4A96E6A9B8D8FF553CA1E6D85B16F996FAB677FE58608BF58AC1AFA9482CA957B03924945B4260A4147625EE657C7763B4C9F4C00466394DB4F222DDC16B72C579FB80B3861D6B4364007FE856DD8D498F3732AF3A7041A2D71498ACB3793C250CEA60DE84FCD0C227A08F903A0B5ADC936FBDB7BC6AB8F7AF002266C8740AC3D75B0628EF6A05C0481CB283E3645F7D8A0ED7415EECD52E4BF70F00ADB11BAEB947F03140446AF31C2BD41F1D34D75FEAE64B91C6007CABC91A07DFE8AD753CE183C611178B8F63B822F03AFBD41AEF17F6A1D58F341D172D4682F38FED397FB01B396352C37397991D2E1473784900B4", + "39B27D6129F6C84173251B68B742EACD5A1BBD49DA6A4DE039831B66B054A9BB13299EE828282F1779AAB7FDFD82F4CC3296E9777A03C64AC4F08DC8882A9454B301264284F7226A4AABABBDC8336CA2BD1EC6517A9F54A776446C5A12FEAE387629FE5A66188C671C80A6C83B08322C2068ABBBC03261AAB8280F4E36507788CDAC4D3F0817327FC0D19B0BCA35D89819A9DC2D5C0CED08A87AF8DDD99304505EA08855CDB514357F8A9A7F3F4D062705E7B26632CA617F640F4D99417CE5C90D432D6B8955DE269460B9DB3C08432FB7BA08F5A658DD79DA8E9AE5B0751152847EA6ADA78D0BB4A8BD9F6E221990CEAF771B5AF603F463D2369DF9BF556A1CE60D1EA6172BD05EDCD166255810C1FEFE029EF21147DFE8EDD5B333F6C7274997E1BC61F253AA375B9CC6B5B64BE8DE11CA00C9530DDB1F218870611D4037BBB88F257614EB7F2A6FF395376C5DAEE4E83C5D11BD6600DEDA47D1CAD95B11E5BCE680D2F18CF92353A11840DB88C38B363BE8813E8004D2BC1DBF95E86C64E060F735C404E8945EAA3DB31A27C63AD818D96EDC6B0111CEE3B3E9F0E1B7DAAB22364FC1B36D25ACF77630DBD1E3CDB194FF8B8D1BE8ADABCF4D0760BF5CD406E982E0F743AFA2C4B333152A74177DD79E64566BF34A10515AC0E050CA135D7357E1F94F1653E9EFB0FBA0BEA1C2B09D6378E4E33EB98B5DB2A2DDA5D9F29CC68766AACBA09DE25B338BEE82700203628ACBDD4B828B34856910D0F2230260FF41EC371D08BE96EE2E821A1F3F328B631B53BECA81BBC74A92F608F2B040548BB5E805EAAB46815793F1D01D121D2E347ABF1FE62B4E00E31C8DAA01202340219430E88938D859D62B709D43934265B9DA9DBDA01537F54B439111126613FFF46ED0A39B2B19C22B8776618B065E15A515B752E1846F51F8469CE32FA076F47A5C49541A19D54CD63512DDE1126D7850B4300610E066AD53E094F26DDB40980B47D632DA9B4524EE5473B521A8F79A4B84CAE714B65E30824068305858CE9F39BB2EB06821C3C07EF2E030DA4BB3DC2D7A29A69DED7EF7B03825C663F5EF44B9A1A174ACFBB164FFFFF0419E13A8DDD108FCA9B2A8CF1A5A2E0471046FCFE32555E72D857ADFBC123B190B48CFC91CE8F0BF86CE2B439DCD3AF6F2CB26EEBF393FFB34290D2B7EC33FEE285547BDCC922312D36D9D25AE5DCB0A03EB0B603A6F75A5EE878266221C9B606B185250231E4B5C8B9470E5BAAA9859A963A51B83ECC111DA4779F012AC23AD2E2DF2965A39E52BD684A0E8D2406A173465B57BA6DC095298DD716BFE30E42CFDB0F2202D56E97772E3D64F1CA9B628B6EF2217A837165A1BA1A8612638C8387EC3854AC557C326CE88DA10F9DA027B204CFE634A695F2B59BC57F987C613131DF2F0F6A5F6081C96098DC03F82B3691AE9E4F14C32324CE495FC94EFCD1CBA88842223DDA27999E0B1762C581162FD1839352E8FB7E4FC143E8D3C774BE9BFD7BA4C3091A04D08EFCAA98B5D3AEBD1FBC65BF1CD7BEE784B58A877D8AE9DA9B3D459521A53010D42242DA0181F661F7CFECC2E74BF3C8E959D84F91904F4F8DE602B214A2E3C42B93BF904058FDBC37528D467E323039F101209D60C56BCEA60BF9C3714A05437A978F3601FA625B31562B5C9B5DE2C6B84F560FE35296E2715D905BCA71BAF6B577E7A03CA4A5DC816E79E21C9B688B0857887A25AB624E2233FE8C9A80C6FFE9AE77108F44A72AAE91885BA9541939A34519C457C41964D4FBD492E11B2890BE2BE0E069D274621FABEE60934", + "4545989EE35583C07E91C0FF1F5FD605F39D51A0485105A71ECAF9C7EC0748F7FE5FB5C4E90F1A59B1E31F74912BA831BCB9C95A315008F4C7C72D8AFF51DD09D9E4738E72C325B128E03F7D90915066AFC3FDDE335EBC4EB34895FB9807731EE6E123A28E815E5927BC9FEB02AA960308978D8DB5E131A22CD601D88069D145D4366FAF97FD7B71F4B39AB73A97C715BEE20A175931D7108AC1FCEF63CBE82D9CFA3569883A448220CD92C433ADD11A52F72303BB4A5D1DCBDCDEF605913D8D424F513EB8920EB864641B5833A39839822AB8ED011762756D6E16540D544B5CC8D9F8B671F19DE2BF7ED74CDF8EC9592CF1FF61095D0749A6404BE49AEB7434C75379DC02A87D213FDD6E0E6DA751657D7D221BC5EFFC8211F6C86B0F77096A81B1F60F51C23A5D525C3411DFF07CD5FCD54A60FE7AEA7E4C182885B2EF08BDE99995121FCDD5DDB0335DAC07DE1AEDBC9E988D7D90CD81D30E6C8E598BE6743D2853D975F236E6AED206846FE8F6AC9FF72C585606FDF6C25F5CBEC0C47567F389D5F317DA01F4A801FA2E2CA60344EAC2CCDEF9274608D8EA0A0D6323A1510FBE7BDF1EB8C0F580DBD3BAD17B268BB6E232B109504CFA3DBA305C7F273F8FBB7D8880303492CBED0B8AE374ACDF582A945A1B1D2000E71FCA445CAB59EDA8977E5595734A508495F2A742E30A006D383FBB6F83BFF1D0DA35805B6CC6A54BD1A7C3BFE81DCBF47021D6813B0E28000AEAA0654D085A9D5A0F0E0BEF802AFCEACE79FAB3F85E09E968BBED03B00AD50D079D9290F7E18904ACA46A2F0472E64CD16429547DA8A35CB1D9D532D4223483E7CDCDDD9E406B4920EFDD2E134B169A1DFC3F2AE54C3CE78A121F9F46F5D7BA6BFDD9CA25FEDAF0B2AD447902DAB3282AA9339C235FFD874C5E893E7E171CA838678C05936F9C9F794300DFBE63AA842A3B9541B07EF486C4823EF1EC56ADDA3143B89052D624EBCA9DC5A3A68E19F7E50E4DD71F4B111B24459EA8FB211053AC3CEE16F0D2C75B68E6F264A4E2874DFA99D6C6B3330B634A65D1B3617AFD7C32981D73C8607996F107211A7F37C6D6FD1D72B56432D66A8CE99E30E16847E549E54E7A3EFDEDD39741A55E94B1B735238093F856D8690A813E0ABCDB630747EC7A9D4729A6E0A70F001F5867E9AF613E9A0494BBBAA59CD1D75C83265E494530711F18313B0643890492BD13B49296827D7444876A98DBF99A6FDCFAF7883E02FD4ABFAD610FDD2BC8306377EDBEDA3EFE03041101A489051431B91BECD6E9DAA5633C8E99839DFE70F4C156FC2B1D27ED307757E0335EAA699C3FBC43CF47E520CA1404054F38D13CFE0339D87FC1440504AFE91AF4088820F7A1D8128ABA53DAD634250CB0C467592C27D1DDF7C64E7E5308567375FF73C02951DAE125866C53F845852C5008A69DEECA708E5A621FFC81C3C932319D15E867AFB67B1B1E07B261ECB56A013C441A7DB94523F103E93D95A7A0FD95141A6342922D1A7130ED95F4B1FED18F3FC61315A1FF0CFA66382BF10DD284AA4B54B80FC2415CB8AF7F3E686AD0664C21EE9F20070F99A8A44A5D51D8CB4BA010659C3070EB3374DAF2168562D89FEFB10100670663E71D029C2B09107611C41B202B0815DA2071256988918DCE69B35F46B8AA4F11DE63CE565AAA1172D7CAC8296B9334FAEA08D3BFFB34264D3487ACAE3C9781C1664E800732C387F9D65C152948FACFABD175C0FBA3B45F9892F8E98F2BAAC48E304EC9CB9D2A41487751B8E37F3B58F66710EA2A2CE02354B85E56EF7AEBE52388", + "F2BC6298F0B96E3B736B5A6EFF22ED079C8AE2FF586E0F4D53ADFB17300D11CA7B8C2E79C0877970ADD0579DD90187CB8095278FEA5F4BD3D9123D300100AE63635463FB5019926B9B53BA7CC826A14EC4B5AA5E9B6C72685B4517A4564028FB6D5584994F8999F9AE7E59D4327FD95C2A45E83A63E9D9F04B554C8906E0E2095448F75DDB68C8057F54630BAFEF06232F7609282B1EC5D0AECFA93E8A7EF3E6FFED7F6E4A2EB8B82D22C5B9AA7B8617DC13B69386742C09C2055AE5C2E71E73EE0DDF1D23E4928D7120B8C171A4F4421DDDEE6229656295430B936F6AE18254A11612B9ECAED23869178CF6B1E6ED7430958039A7DA988C1DA03E0DF5E1D8EACB7C726A9108E5472329280184861ACFEB110ADAB5ED03ACF5EE7E806AB0C850AB7E2256F817883394177AC0E0EF5B74E27CF6B315D0F134B282EE527E32A762C1AD06991C733A7F2E23776B01EAD68363A361F28F381F6190635A6BB38CA9461749E8E3117CE4F767007E2C38FC0EFFA4AAA693664F30A5704D369C9BEE225890021DF8450EF25B28CC123EB178D113B07B99ADC4AA47FE0078EF3D750B2E600B09353CCCC8BACFF198EDD2B3C551C212D005CF33763875B3753E14B14F96847142410DAD4046C9C8340946D922B6EB6CF2D2BF3ADA92A492D2C43397716A4BFEACA01BF2051E029D5C664E4D9C3B7248A9142092DC25FD0DE44275AFFE90848463E7E68A7DC4ECDBD5325AEA355E111929BF700179AEBAE60E26AB2C6ADC3967AA55FC9A2BB1CAC49098C16CF85C569E2E4A146568C41C815C76629061A483AC30DD27ABAA1469C1AC6C527BBBA5BE8BB0541358FEAB34B1E3EDD7E37EAF307AC213055FCF44E65882CCC9A12AFE5F7FFFEF4262C19AC072C291ED636C3FB1D36D7B99F77E93A5DC2848B01595D8DD3C7DCB95075AC52168897126055E8EA8D1028AF2718DCDA34496ED6FD1D86B49BA42F77A714D65D594965A748EBE83501D963F7B8D3EF55804B4FD5462D12571B77384E3D23C77ADDBE7F4BF667CECE0717C7156623AA6FAED9C1D2ED3C46403F750951AD8BD192FCB1A7FF95A590D085E7A733DB1CA0A821631245100FF92A5B1F63F53A6D831EE041966571EBA5914D81F838FC3CC5C449BC39709A489CF31B7CB91ABDE6FC8BA6E4D41E048D5C59377EF4DE7BBFA2406C6F400232E6B502A10802B420A11316D93638A926FD0BE4A368A223FF767B11ED73E6DD1AFDA6508D4CA6EF3517CD3362CD1604CEC574DD35FABF6D5004208146C93BF179ECAE54D9794FD13C34053FEAE2E7286C964BF2B2371D9BA8AE3F0114BC138EB3C304102846E65E7908B40358BEF9F290038FC645979951AD82D98106440CFE2261C5BDB6BED587C19EBABC54469D6ECA9D9DD59A92DB30868297CECC90AA8228E28C4D1B074881B939C60D8A4530A193290C5E5399FADEBDFC42CEC5FC2738DB18FFE9FB20B7D443FA3F1FEEF91E65279460D27F6308B6B0F8B450452DA56E81D37851E8D589F9B0822ED525BAC86575FCBA54E67BEE4512A7F215820E1885F79A5406772A8241FF96533C644B1B5200FDDF4CD1F270E6EEC77324DEF0150183CBDE7D042C33DC0C27AC6F17D670D379AA778E6EF48D41DCB6C9F0F7C5E57BD0A7875D4B2D8E31AEBAA58AAF78947683E373AD517DEF236B037F29C2A09AA4D596609B7AB761FC8D7F566A6BC8840CA626BD36B1D50AF74342BE0B54475D0AE3E30CAE146306AA540E0D63AC325252DD66D5DF50AF7C1D3A651E5A145192E1F05FD31AD2F37719B62DBBFDEB84EDFE0D64490", + "9DDBC6F5221BD70BDA886C59D62F7A95BEB41276DC3B5B505D883DCC478B697388421D5C217C8DD2E56A4130A28BBD7176163980EB820899CF74F3074DD7E74A77B54677A35EEEAE93C32D44EC4D2E4196366E40FD0C2A4741575ECFB8FC927142229E63FAEA97C51E12809FFD336BCFDDEA3FC03A1FE99EA685DAAB6F27DA6BACACD5D432352FC6FCC323EA9BC72FAF2569A7C6D55E1260DF0963EDD6CD3CCF97A033F74201E4390F64F06F89080C830986F8D6E90AFED3BE6A54202A59ECCEF101E5DB790E997918DDBFA1B160D472490F3CCC2B0E1C10AEC61ACC1F36BB6A8735AA86C50D2AC986721C003A2A8F1056BB9910F5A8D62D358DDB31589280BD14319C27A13D847D84C02A039B869B52669DDAD47CBEE6892E2A881A020867405FC1756DF2AAF2E5706A16F53E1E459BCDC430C26403F60B979A4D74F78CCD34E48321E67A8B896A162C873CFDEE8D58BE234C34FA20FAD472F0EB570F5B2BDABEDEA0D0483176163E20E47EBF51262B19442016EE5867BD3345DAA7CADFB2BFBF14B4EAF986951B024D876150CD64B7B0A188CA79B122F274FFB39F1EF88D5B9D36437AE8BA43770DD69E3994F8CD673EC3E1F0A51E798271AA7793CACD7E53E27A325193A9B9FA33ADA3BDBDB9A916DC8BC6188C3D4C38848E3506E38621DB57C2B0FA80BE5CA34C295159163F23ADC249BFB1ACD94FF0A42054C1A2C304F3C515B8B44F2AB1A760E784B95D9FFA905EB5541D14D5F12B4489403645A15F004828AC8FD3D8B44C5C070E8A64BA086462E5CD447C58E0D96130E9BA3400CD7AC266AF3E3D33DF214D3E98C6B7585C552979738879552FC758F04B122889E81B887B653FD7D4A8A5CCECFB0850B58CFD4BE990FAE223803EAE972D0C65A97960421D3FF5B2B75079AEB42A92E0D0EC2F04967C91CCB84FE6E39B6B136CB64424686DC6CDC4AC39C26BFCE81478AB6429D4E9B4877EFFC8740FCB5D9968ACF8D69C771E9E48CB542BA5BBF0327A4C55CC83E466D6DE0E639A54576D85A44F305958A325CE98A45E2C227AA9E85BED652F3EA5CD31AB99E299930F5AE92B12E10D597F69272ACC8185C1E83412A67CCA39DB06A77329475A3A87A1D4586B191E2E8E7C3EC39171CE6E775E7B369C8EED0B2E74A7233CDB5905F6AAC099820A227B6FA0FE5057CDCE6C8175F4CF27D70EE76CC0D769A324AD66D013A3F699C7F024C22C03B353177C3D721EC56E472AD6B383A653FFCD078774C728258146BD8D928B209C0A6A8CC60069F160D33F673C139534362B58E065F7D1176FE95F4A6DB7CC75FAA408C4FB09B7026DD640BB08945B364646D9154D00CDF5BBE432390607904BC3D70A0207F696152CE6FC5A0BD79625E437197B929203CF028384558071B625E0F8801EC1B13F6DF17EB8135687F08071DFC3BB06C8EB4ED296C821CFDDB7F2779B0B913E623ACA6E3C5FF023C58EAAB547BF1A67EA020F317658E1328FC845F65464D2E06ABB63F678A94614E3EFE281E41ECD6C85FE10ACE427FB1960BDF06630B20CF0401F450D71D3FCF0C477682FE342F5511DE926AA24E776CB9C798058A7576E1F76ABFD2C86B8C741230D6D95ADE980ADEA22547B88E607AAA8C3462FA34114DFA46046848CB10482314D1240516AA7EC7160215A54F69EBC39FE4CC97EF710BB7E8B55F9AC158B7F9C87B738FD993D2F0E35E4E9969FE5FC4B301BFCBA8A28D7150602ABE7635A2FB48AC65EA29B829DAE037D8711127F80CE85BE003B4F94E958E493D7C2236DF970D7DFE8495CE083E79B777D44F96C6C", + "33282734E9BBA791CE9CAA5CD9F80DEA9EDFCA4E3F5E32FE046FA978612D25F79FEC5DCD026666C35CAF0B5A682C9FC6C97F54BEDC056A6D900DAD88CBCA846702B0BC435DDD5ECEF1D3356E85247940A3892CB61BC8FBFDAACBC1DCA9208DE593DEE6944822EC80F823B2ACEA3FFF66E4CD6F542CED77C81F29F144C9D0FCF3B61C4887C6B42EC97C83ED2C5DAF28CB8C9B352B37255F54835EEB978966A14AC91D58857CB7FED677EB87F8556B343BE0056744655B6D97615F7F32BD4A537D8D586F477EF6B2871AF0524F71763748C57DE63D62D6824EC5075498D492A2C621FCDA2A5540038A50E6765ECD69CDD45D10153171DECB85AD45A8A6D3C609E350023C32E1F72B8D5E1AF803F68E288CEB2F5CEE3F10B7BCD7FB15D11DB3445266BDA913D5930776EEA4446337EC5A50F9E4CB230BA735B656EE26BD6BB5632B907CB81BB65EF4D85BA379E4C164DE83CDCC023FD458606E09552303B8535B63E37FF038F2AAFDBBEFAC8BBBCF04EEB41BF126C20C533DBBAD8FE10771F01BDD14AE113760DDE4C0D71FC7C29EB8D23D668E401B3A026C46913E2F08DF8434FF64B48036A37166F32CFC8747F13B656BA6D18300935195D0411E8B24E1F47298AE9F9617DAD3F39C4251566CD92A64860949BFEC05EE2EDD7F2DA0FFBF3D3C9F5A349130B7A5BC5B839000431D00FFEDB344C0DF86073F73C6833C091AE132D121F4568D011BA0DDC27DFDA5284478F5AFF037D89DD8EB9FB0EC066AF20740DAD8D29C1866DA0998E580BEBD311BF6E3BBB31D89D2DB162A680D2AFAC4903F9838B616EEBAB56C2D0386C65CFCA946D33073684FA119B2A6411E1786C723A466C7070E58248ECBE1D86C6D6CAA199944D9944BD6E8B108060B612F8FE724742DC158BC1E5E3F71AAEF1864A7989CFC68CB2396D010E1485C3238F6385D68E20D36A4D3BB8A5A265E686DF558A73020588EA16B4B0D3F74916038A9954F75232087822BBD8831222F7B94968C5A324018192A6377661AD1E15FF05AFFF75FF60B60C5B41C08F001D85A237443EDF3E361030FEC44573B044CE66F7A036EA78EB83E1863259BA363D517049B13F61956740B1DA3CCB5C9EDF190C89A2FE908916F9DF9B2BDF0DB50D032FAB059309F3DAFE1723D8031C93F9CF657F17D1B214492786F0D297D3C4C01A25DF2B1C3892B6724DC7CCA704E9AF0163D37F91DEE0850D9F2AD4860BBD2266FD7EE4E3D56349B90155BD843EBC0899FAD39C67050B5F8A1A9DB38EE821EF7561FCDCD6F833DD3C9FF3C5D978BF7E70288BBF665F4F20260A74DD0D414B3538FCA93671DB4371F2CF6AD94070014BCD5ABAC89157836CBA9A34FC8D84090A3BACD7D641C5FF58A5E1489E1D2F410E65650AA30D7FEE4AC3AB37D5AFE208EF3023E88D96F4760120DB5FC705A005976BB27F580CF5C10988BD2221507F8A6BF84B19CC3BAA186050870D88C6B14F98E56CC470291FC96AC5BE10704CAFB10CCCDD8E3EEC9D58E448BC655A0A899C2FB39073CF28252FE3FBC6BB61189B154EEAA37A797A8E6F329C64DE5836EA44F7FE04837E343963FE89B0624779212F1E5E399427ACC8BA83C10F3893C7551FFFDB62BE893DCEE02AC893928E81A080CC2EC8B95C4FEF1A6B65723408F12F6E3B7B384B149F4002135EF114B67AA3CCD406A78A732374CD7C72814BCA01F4D44909E6CA1245B25E27A67F2350D285E3B37218495CDFBB9C7FBF2C40FE31C57702519B5DF1D41D85F48DE4E46639104445FC2C078CFC853B25BDC3E4C58222B2F2C5AB40F5906C314", + "6E2FCAD2FBC021102FBD4F992C597E4B91D2AC56A22E8FCA938D9C74533912782F75670F31BADFEA83FB93A0F6D449092FCB9236F50446A4655586FBEF31323F1795AC3216315BC9F4C92FF583AF7E977A996F10989067975A53E153364B59662B6CE9E1EB65D6D69B9EFEFE57ADD58A7921506C2BCF4D51A01F79A67D41436B519D314D1953C6D133305AC06A45428C0D6FD9228B7B9228C3A2C03EBCFAAA09B9343C736BF99022D1CA0B5C25A6179EC0ADD8AC95E8D6C00D6273AEC61E1196741DA2ED9436F353919A8D25BFB8234DA7A2229CCF0FDC4C65CC6C0374A4ABB918E1B5BC7B929F6554C568DCEA62D5289E45284DFA975D5AF56609EF4DCB3CA54A26F100E00D48446C4C35D1D911CE7EBECC58347940BB411F475ED18D8A1315C069C63E59CE2F69E6F7B48B005107A69EBD9715303563F6A217E2ED4CD373648DA437E10754CC5636790930947650E6C5D1B3D1AB853A52A89D208301C54F8E7DA8D419559555859AD1B4D096A1805DA251B6767DC2C0D917919E119E71CC78A884A24F5061CA1A999DA65AED69CA02C20B6EB163B2CF435135D3B34FE6EF52F3AB84DE084E37958BAA4EFCE8165E2F5AAD1D84E9F7669FEFB6E60F1B9F69C79DE9296B7A01BDB04CAAE8E6A16ACF9A119A8E577919CB22B58EEB7EB289E708F229ADF81E2350B211AB48043A491D4CEF1721936B71145F07A40947D2A89A584D5D0A708F3480F0892E331B2B73D8B7D88B7E85F73DBE5346D801B1904CD41A8070A0DC74073217AC415654F4170F42314AC0AF4213CBD28094F8C4FFAC06BB0114B2C1924A4A1B7655965468574845864ACE82B8839036DEF45E88F341A5DA37A511D583C51DDBDD51577488A29D7663CCA7AB2AEBB53A4EEE7F38B8637C96CDB86B23092FE0CF669858C5374F6F078FCE4E945FED340903FF26A6AD6C408E390F08ADBFCA9646CF224A5410D0ACE93380314541982A8AB6443FC358B66B027A15722A0BB7C61484CA65A62E4496053C947D5F4744B69B4A73F7801453FE20557224878B8FBD318E8B572911D09839FABFC267416B4E2245FEEA6967677C1C57A3F72E76BC297CBA73AA729B890E90A4B29CCAE4DF5D959BEE30D836C859F4F67A06B4A479954CF20C7D0639D680EB61A2CA11B007EC9772293EB8E6525A56CC0F380ED4F088D8CADB0B95BDCBC84C0C746D4DE3307AC7050FA2531FD24164D29294D492A07024FDF1B988060FD766128120226E63F4973278DC9F07FD5699A1313002CC9FA7CB44A72C9C9D740AEF0984D7D4C5749F9071138BF93BCC6DCB601CEF5F60E4BF2361A083D158BE93134DBC1D4FC79FB866B0B215E230713137EB6BFF388307CF2F07CB07E974C8A874EB20B06C843579921ED0839F9454DCAF71BF56387E01F3DDCDBDE6C15C58BEEBC137B673F122179100613D6708B6B16AB750A3A311AC85E795FDBA002CFB2A9D9734FEE1922D984DA9F76EF65EBC9F647B280B0433A3C2E73B08A3669C78CB9885F65E97A6B4D64D2B3A29184EA87163B06F267FE94714977525AC061BC54F7FD95CC0C4285E45D75772AA3543AC00EAA32626CE2F9DC48862657C1E156E08136F3B1EECAD329072EE4EDAB16F385D736AB806157409496A9CBFEEB3F5AFC91E2FC5569DA2C5DF20FFDEDEB6BB57D18AEF1DF03C7D5A16BACAD645772C4C016D147EC11EE9996D2E791C5251CA8FB7719F2093DD2E4505B7BF320204556D06B91D547C9C6B0B19FB57608934D4A4F748FD07F3F57CB108A310319F7835C082FAED651ECA42EF823AD83D6B22375B20", + "22C6D5CF65DCB08CFEEF580D53CA6571787AA81CDD29C4918F5EFAF89E285A37DA51E01500BA0192D2F45573533F540BB1569E27A8865FF94923B81AC26FAC1DD03DF79DB5B5064F84A2B15E0BE7CC53BA875E477159D0352CBFC374B07573FEC884A699E93497514E7375E49FF5D9D9DEFED637DB89158F30B27E802EEE4E806FD61A46F8F7D7AFF89C9101A9375F73A2164C18B0109CBA1CADD42E13C9170378E28382EDFD85B80A02469D9A78637494BC6DD284557ABCD5756225EE3B26C7BCD597E9744FA1674C5088D3301D779B1C3A922A0723AE1BB253EF2BFFFC99BC8BB4CE539BF6D2D0951F6C76BB001B48E52387C95E49FF1A9D1DC12FAAA2B967754113FE59822A1E5C56A6053F73A2CAFDB0CA0B58312ED54B4F9D1832FA089C5923133F47EAB56C56EB7AF20D8006EF8D9674089CC49D37E82A1FFB88C97C3267569B5AD1A57CD67A0C94219AAACEEF99A11B28D01EA4329568E42A7E717437B030D3B649DAB105C700F30AEEA7B82A9759ED54F890C6E9B2C9F3F1D1A7A14A245817DDD4E2343BFDC5DE774EC60C5C41362805281C3019CB2915182F525576B3BF537FDD5236300DBFFFBCF8A8C9489B1A119D66181A79AE93E7DA8AB81A1A3E8D5A888F5144AE0DEA33ED8B7B6392B789EF9C544F876D179DDD822E3906F76FBD579FBE27B4A2752D4878962008B7873765B9BDD3FA581FA192C0C422C15153D7FF16F2732EF68B66042B5053E458518EB65C66E3955CCE4AA212ED4980411D3E4BDC6918B30BBC400A8A338DB982CF55F2C3B0C3DC6D64DF10A8CE1BC117338DA3987965A5EAB6C2E8E368F59C7D9C77750717B4440AADFF57D0EADFEE7C1A92EE72283D425BDB0CFA9F3BCF602634BD8526AA80E0247BD0A043D277A3E575C1D1EBDC0565330FCB30C63AD02F48D485AA43358D957ECBC6991D0358AFA953A41C67019E96576BF88122CA76D2804B73EABB88007A121BED76F33AE0E0433EA74FB2C7AD672D0DF5927D87BABFB30989EB91BBBDDCA40ED8BCAF7684E8EC9D1017D6147039D3C3423A9A0081A17B70F56FA300E8F2F97C399498F4AE85FF2707B50E3A4492BBEF19E14834B261F700DF4E685DEFF476ADD919D5A15A7BCA06F382E1F0649B6934D70A80416F732552872BEA44A5A42D64844532DCE8ACD5D20039D397BA9EBE04EC4742F4E2DCAD29F89E0A9FF572579237863890DD13E7168CF2B4CA8F6A36B49A5734BC85F811087B9541605F44FBEB3313D3B56EA13676CB69F4FCF14A1BD285455BA516F20B2B0D3E8922B71C0731F2BFD1124067D4CEF2111FB754CEE5AB73DF629797FB5E012515609B1E9A2085643691BAE5E4A2A52E904651DDB340090EEF578675B778D1E6EA868FC1106F19B0435BB464887DA311545300841E10441E9316656698C879089FD009D3F8F49097B6AB6AD2D744AE79F1D15F0DADCA70C1177374ACF5D07979CED4F3173FA4ABF571F6DF2112E8AB26C257D6861923CD92CBDE33683F27D2CD542ADC623230470FF7E950475EDB761E57ACEE78318FD60325B871936A51FE23A63C9B4B7DD8A72556311877DD6A8EE053D6CA28261BD359C0C997F2A184270847A13FD3C952741C5D1C47ECE09DEC3D8E0223110A627084BF826548E60886D7EA15C585F5A16A813F030EF3D150FE7A4D271856623D96742E848F7797526238E56C102191600AF7756C562A9B627B1F05B56FB2C768F6B57986BDBA95816E0842759438E262FD9BEDAFCB594731E9A04512A22D1EFFE104EB8F7E502B94FD846C71004E534FEF2A30812F84A8", + "E881D91D5F8EBA0700605336E6BCA6A1B1BD1D58F39650CD55F056FC8360EC9A2CFD0CF440EC2C6E98EE88E6B31558B838EC9D473F75CE2FB04155330C9FEE2C381F872C3A79331C536A05C766124E69AE1EBE9425387279FF9FDCD28CE6569215A65F678611C96103D710E45029521D6EF7D5A2AFF378C9C26ABB52AF1ECBBF615561932791A23A3BFF2824CD3810EFE7143A79B4E14132E306C48D9B2FCAA475A7D2AA0BAD046314E5BB4839B27FF4ACB7F4B3CA8C97CE976F11DF6DDC71144A600DBF9AD43B6E471791CCE636D67CED546A377D786CB085D0E4E91258719A9233F342180C9A827FBAF77C8B5C1BF72E9A81E4E4908EEAD39772DABCC8CC0BEEF0812DEDCDEDD7B4110C6A0B89484C2F0F6CBAEDC219BEBC85903CD03AE727B1849735F62B385F4D5CB58C527CACDB3586AF4525BE1CE424A0879546505F86E324EFC4FBB0B9E86EC243432866DC9CCD4D9FB258886EA75AB006D87CA5C10B5BD0E0CC4DFDC6B152D65D5FB268DB6AEAEFC9EDB4954CCA7E88DE2269533D54AAC447124EFA9BA62FACD2FA914885C162D59BC6BA2FAA3389DB9AEA4C350843B3361C9F343955AA616E661ED1A137EC0BF957BD7DD7105856499367E91849C99F0F7138CC7AE120CA36164658BF3B67BCFC1BECDFFF49606448AC8B38619EF4A997AAA688D3FA7FF169B8BF537314CA8ED865F395E300E5AEC2CBCBC5A8B5AAA31C811E3968FCE32B82CE5EB1EE839134EFCA68E4CC4C2957329A7CAEF675AE2F990CB108CAE8EA5EC21F6C442CE1B818ABC203327087146D67275300868B95052261AFCCEA3EE854F38DE7CE1FA5649AD7E9083DF2DFB3ED4186244045390F0C843777A677B8A82B69EBF43D8FD24C9BC0792A2336581F3B45EA6F8BBBAC89A0314570084D683C76D32C2B0A6868A428DA7D72D9C6D37D99BC05D14ECE27C6C1E3F849332C1CD67381B6CCC907E1A911D3C97F1B40CC11822257491AC9C22642C4FA2CF8754E6AB2574AFEC65062ED5C1E914F8DADD52ABD7A9D74E545C362880F38A567BC3E6D7BD7156C87F698C870008C2AFC78F94354C2DB9833A0635E2C63E5A47A828610E2A5E8B2F914306C966D1EF8222BD8FDA2DCADA05991ABADAE250B942F8FC82AAC026696D62BFB27C8731149C49114EFD2AC47250E0454E33383082E7826569AA4D6F5661A9968C1A784E0A080D6BA7F8956E37AA55C07257AB5971E03069E74D245C4A2A0BA0BA397376141FCDD486B2B3C865E97D1CC327E4E3320A131A91B61F5A78AEE77D1DA75A1F121D777DC4E3714B0B515DD96F477E9232472353FF7FF07B0C23D1C88F7DC4516C36B3D1820AEFFEE62EC3DFB6143630E1C532A4FC9740369617E80312BF3CDD7E3723F287DF666A34FEEE38B3A1461E1B5FA03907125359025AC125D6E86FC6AAF0223F83F252AC0C6D578DDAA8A2841DC35AE6B6DAB2E7A31EF4282DF4E20D471A3A8B28EC6F510453728F981D7BC2F1BC2A8E024FA65BE18AE8CD272B05403E05C6006AB1E612CBD9F8A71C50D618E9FE46B243AFF2529F2A0FB42C7B990BFBFCF6C4CFF59DE230EDD411BC93C398C49E76FCE8EBA3C2C93752B38886162745ECF4F80EB59AA3F3660C4B1D4B9850632548A6D5A9F5A8DFB5A74881C0E93E38AD2FD1F0C23E66AE4631F25DD442E1A010D6A04FB73559C76CB30494352B24FEFB1E529BB6407BA7B68535D06C7207B2126A585BD59C43ED1E36AF6408E33EA1CD6F43BA41401048AE9C5638077C8AA8A033F0C18E5899A6E9400531731486774E30C1A6292FDA7D06A6A48", + "74C4DB6B3E8A4BDA889FF8264534407C16B05809DB70004C8EEEB10156C32686ACC5076D21A2F583EAAC92954996BFEFEB1A28DD699B55B5B94A122A1349C58DDFEEE9D4270368DEF85D86CCA4FFEA81880739A934BB8831AD75794986D60A92AA6DE661ABAB1010F3999A57A53F3868026C64307C47370E0B82FCF8C02A3155E787DE359624510D5008E229E9DAD0005CFC9DFDBE5080BFD01D7342E570360E411FC27146147EE2C72931D0577CE6D7183386C754A6820BA97BDF080F6EBD063934E13B005CADA4D2D8492E143402C9D1BF8A04077C4BC7314532474704BEF9D24E4566A1409F085C76B65158E4EF6B30141DB42B0A96454E451BD63117428273D3629E2E5FDE4D9E53FEE5F9EA2F111A0FE5F50D2B72DD26E941A57213EED915147473D630F7556CA46FF8EF1F0C88E6272D6E95FD3741AA675BB0ED839BDE162F9A308B3B092663B1963221708404CE8BB54F61BE9AE987344228BB60921726D90FCC07D5F64BEF673E06B969511E111F0293BC5E57186B283AE81CB2803363A1266E7A78B47F5A35AAC2FF0B3A348DE73C81D74E7868683918FFAA42A91B89E1E2AFF4BBE6F11867DE292A6FAAA689CFF87F4A629FC354ABA202EDBEA3F08609D1A4C350A7BB7376A897AC15A1B0CFEA0D35DA71039A97B8C99A5367DE46C338D75A845A4CC7CA292DF57F2AD8C5E20D95670E3748E8A1BBD3D728980DED4FE0DEC90884B7A528D0B4C27DA315195B7D8D8CCAFEFEA3D62AE34B40F5049D06C3AC92CC59A85C5D5BD04DFE0CC89A7DD7A1B6AC4F5F3D2AD8858B83C761485B77F6D512DC2EE1DA402FC6158C644F14C2F6274E8113B453F9130BB6C24E36BF84C2942F8B28A3914110BB3D48DCAA3ACB1D7A89769E0B9048566671760AD83BA7F7209832AC10FDDC299F7F90A3744F72ABFBAC19382EDA24D0BD5859634EC3790C7390AC2866B1379ECEDED50D5127324A4EE6AF50D9A6826DFB3E27B9922E4A8652526A6DA29A4C2B9B8465E3F99E72A82A27645CDEFF1C42E77359FC913A9074516720BC61EB171AF90AD427A574080970282539A05471AB7AE2EB027DFD3D496BD27746D0ABA30EBD9D13AD9DB6D405CA19EEB90CB088D9CFF93B20DE07F86B978C7FEBA8AC29FD4E257D23380B955CD79E93E3135BD14AA338FCA16560A123131DDBA8A2B63923860EC3EFC2E0339015662C3DF1E837C879969573E0DC4A63EB7C0D6E7419F079D4CD05A1A9791330F1F1B7EBAD8CE76933D54A224571796A3A046116964B98A7EB5D9FD8311CDD6BCC9B63F2B7302347C0D3407219228BBA73B8B53DC3645EDE1969D345D8C23E691A58370B351BD6C86EA6EC9349D524BD05D07E68F853FD9214414507ED507F0E3CED126F95630FC6A3B40152A318278B8605F30C389C1826478635753FCFA9D227325463581DC51EF4AC47E1C49EA005D5AAB9138706671D64082F6E2BC39A802685BD8EE8001031F7C56CBE5FC68CA5B14109249C210B4ED7B9B2ABB4D4E83C9EC82911E9CBCE5DFAC8D4A1A6CC81B5378D29E8E339CCB31B85D9DEE3080ED75057CD5EEDBEDAAE7F3CAB4BB1BFF54042E28C8CC79741FB04246ED66B3E34D83F08D98D7070D3D6A032BA442E46CE38F45957D7485B17B51C562B94985FAEC8362A8D6DE43FC0EFE1529E662899F1D21BFB643C22293E0A0F2E1D40EAC1934A0421C1617DDEC3D40A3AC9EFAF0F8D94FB7DEA085C8179290FB4C917C7D6F8B75DA8790404F8191C0EEFCFF9DA2208E7E5D382B5A9D1E72089B3C4976036AD530BFD31F6D08C2CDE5C26E68C", + "13AB0304EA5EC4D96147EB5EF8AEB8FDEEE70A62E36686ACDC275D2FCA1ECFCAEFDC4F8CBBE5BFC2BBD343742EE011379103102BC11E824732D147FF93CA6C9B0A503C49BB2B621B47D4C5971643EFC01E760EE958A9764397AA551423EFD49AEC50E22FBD9AE99659E36341361286D8452EF70C662DBB3A421898FB34EDA3314A1C7A6AA9E9B5A6960156A549C32B91246A9CDDCCFE0FF278C3285A5F20081EE6FE121E3CAF922C75915DA773D0673EEBBB268998861C3018642A6A1B1FA1DD8DD54991254067B4E9BB95D1AE807B8A41B88B772B5590FA9F0D71093854C213283093D5EB9D4C7B1D57DEB27B1E2A1F0CEA306B28A5DD3D1B23EBB7494AF61F771052798C6FA104940EAA5698AC24910DF692D5C89C29F318E090F30CB12397B88702418C467EAD9599670DA2F993D5B6FD7A9A43CB89274719A2F1491FC3C3E1528EC00A6D3117C5D2E0CBCEBB7B91881CB7540809B5B9BD4DD37BB6B94133504981829410B4F348A5A7DC553F089C5F759F032F0F45C13991C1F442F2DAA5C43C5A6815383091ACA7101735A0A3D8E5E88A454067F8D92C4090DA1035B7880A303125ED48A5E4EBDD9308BBD45B77BA6B84093210D9B011E3FC5313F2CF1B20A9C08D3F4D8AD7003B32A49850808F1B78115D1E727A7BD387D2D4C4CBAA4CB94CE71FF25229B37BF1D671CA50A04EFCACFBD980263EF16015A97909BAC6FE4F981B96AFA2692CF3603C5C655BBF7AD4DCB06CC3BBF8BC819CCF20619535D399BDB5FD0D40CB261FEFCCD4B0B0FF3684FB0D992ADF1AC6046BAA8C8E0F16B6E691A23DFF7014AAA67C7F84A9429064139809E1569145DF3CD8240D49BB9D9FEFC2176C697D9950F11D56979DDC01ED19EBC9690893D6D8E76041BC4FE35982D5C535FBB883654FA3A2253D52F06B62022744442D880EF9DD4CC2141DD25ACF2EE3B26103D6A16710D8BDCD43731A59DAADC1B40092D9B166E822A8A7AE0B4323B8CEAED7AC3BF3CA6F24BD79A58DDFFB59FC2E5FF634C83F6F7B03441DF9B5763FF827D4E74764C3E0EEA21ABC1AFEDFC2BB9F73E3FBA165A7DF3ED9997A588CFFEA8E3C193F505C741C1863C3437A80B41B7668D12B0DC7CDC6A61923C102D3D9071D9937F36A39484ACF1A2497F238E78A9D8C9C1B96CAB0AA15B643B81F6C5439C2336055C8DE4A392B8C110753E060CE92325C3B67F0610D79D46F2E7FDA96538D43B09DED1D647E8289986EDFF482FF7E24F40FD489E4051F7D0C9267E934ED16B13827A8C3D47C192F5C5FCF6A8E82521B7062F6A23B463262E425F4820AAAD8E23E85DF0448B00533FA29FCB815BC83AD29B32D12F614AF4A6C60F7F1339E639706C4C671B71C99B55056832544A23C996C6BE5230AB5D8AA6B89A0E05B4235CEB352C70D3787F740EA6B8F05CD97409EEBDC9F1F98E428AECCB124F656EBC316664376CA4B38046E5640B377457EB82A5CF0E81966865908DB4B1E9B482F8740A470E4F5F0333A11E1D67A350ED7BD9C8306186E83FDF6FEA9A09BA1AE266A24AB6D3C192A4DF53D0A627EA2A2847AAE9D5EAB2DB183A45632B2145C3A2FB9C4EDCEA521E4DFC5AD34FB6E2CFC2E5C38B30996542C09CE9542E2F692B863CFAAB27FB549BA99A1DD77CFAB7E26057055737E6D08E5592D17DA8322B0DB650AFD6ACF4ECE23F1C9613AA7670302428512238E608B6AF8E0862452319E3ADE719928AFD059A58D39EA819F3C14DEA608F80D3C93E374C2170D2836E2EE9F600A010B97418B52CEA1592F4D6C4E91547EF019AF4BB4F1ED010242DC", + "1193230653E34BEC0CC617609C775D5DC198C2F533BEE5C3537F381DE8AD1995303FCEA2468BBE8713A3770F59EB4F58397BF63DD3AEB17BA59D1D906C853B6BB55030F2E0FC04C0BD746B755358EF16B44A6494E65FA26A294D25E7567E7ECFE7A830896D9CF2A8D97DD5D6FFBC521907C1677F195AE7539C564DAD1D78DF994A3F33DF3F0400EA6AD3A742FE3EB8A1855BC78F5E9ECB5F6E41A13E2411902BA48D0061D318C1D026FD379C5E4D9ECC3FC5AFDF0ED8D99E35FDBAAE7DBC9E228411D203FE2645169B3E8144F508F88D380EF8F9D6B6B7696CCB9041BC145BE25FBE39017DE8120DC3989669DE5B587E5F2C5C057ABEF2195F5E0AA441E05E256B5BDFCF636350777392CC1D5B5BCDD59C82BF8F3F885C86F5E6ACED0F0BA503944A9E2F15E8ECFFBC5B2C1444776A5FA7DC54EA0B1C9739E21E2ACD85DF739DD5761C17D71444039B3CD53EA47D67E8E8C505C39690D09E52127C8F055521EE8BE8ADC6479EC436B96DE2CF8784C71B585B1EC1475F16D92DAE9C29BE7375C527B1CFCEAC5FAEC37C3D892525FE1ADAA164E1E90680EDF0876A0C50CEC8123CF2EE2CAE3C35409ED5C5E6840E004C9F69918AC8B39899D0B846590F17243210FB32D3CBD4E3F8AB4C7C42DACB17716CC5B330B009EABEB31FDBE086602F370EE9172D66A8B4991CC56A0AEBAA3A623BB37EFFDDBE273DCA7B0C09649B1D0CB5F811F6A27ED3370D1A1E922A70214AD71C2668077E59C562DEED43C282333BADD38CF3B01E3C1F8A55B3822A7D41991CF4E4ED36D2D7AD71BF6BF100643EDDDD23B6C04486DF1193F552EFE21BD9B5A6A1D93D4459CB147647052906599533AF69D3CF1ACB1EB89EAF3004B2E4CCCF6D4CE8E3D6CBF8BD90E6D4637335D5939A3CCB8CBF6F6423388FDCC9B11A159813FABBA39263F337B3856B0A6B3102D920AB5D216FF4D370C836A85B753EA0E43E2D9E9442C9A4E64A061A0BE7CA61B67B0F012CC43E42ACD298B3057F9CD3089C59B39200E8B005772AAE2C2138172DAE25B7D54FCE9C6F8A410C50079012F069A9A7D6581CB6B2A3EA9E09E4F2C1C57BC9F127B4EF8E39220371EEFEF0254877B19B37E0785583683E5AC8062B438889130038ACD1F52098E5E4AEFC3717016321C263B4155BE8418F22E523F514B1F8BE737449A48EDB9F3B38D55E9C26DFD4C8BCA111D162DE23984DF208D5AB1B82623D2A4F4E3A104E3F84F65A020BE96711BA3B3BCE7E6630F8336B16EAC987E8FF10D97C62E9B2B1B10AE466451FB70D345A88A549967C367F6DC1C87D817EB7B4B0A5032E1A72D2078AF3CEB8116B1BFA0BA64F9C1352577BD9D0C552084898EE52AC1613617DB42209B5A8406DA72EBA89CBB1893E69BCB0E0058E4C227ECC507108152C248ACD033DB3C276E77D80AA7FB7C7D3ED6DA7CA79D469B1F2668DF1278FDDFD20CD02668C429CCB2D64E6AE7EA6C65A52B49D2A18EB48CDB26861AA872D74D51BBF34C56F5455C98E02AEBA0D3E658FFBBB82960205A1ACC2988D274E74A3C885F1E1F0660EEC75EBF839E8E3D5057F7C39DD8369F9BD6EC41A918BC8A42291384E2688F20A7B78A96746263991D57BE8BB2A516D9FBFA2028EE46CCA591086EFDA8C97B2DF9CD939D99A87A0AF0AAC65ED40B6551E6F84E699483CEF2C9099693B895C475C52C56598AAE7A9848CA6AF2E7970FB80768704209F117776AFC230158067B52AD83AEEE587F81014B0947A183F629D319FAD66FAC270A4D115F469833097897A40F185687084816F1D2CE615FFCDB27D060331F0", + "594886432182182A60A8457BB3531920208BCA5F9B84F988DEC9D71119DEFE0956740D55AFCF2FF33EF9801B2C9EA25E0565F587553A9DB639F3843EFED712A9FE49D67C197615E1930423A24D464A113C76A8545601964EBB9AF89E236A2021D25D5A4F71E592716BEA4B4F9A9BBD46A835D49379873CF2B0129E236DBD2E510F2CE164F08307C4EB11CF12AD26AC9ED8863B0EF1FE28D2FBE71859BA4340B13DBF103F6A1A855C4D51717B4B6435E6A34F7122AB6C214028766BD398C6A03AF19D67D7E9CE96EC95FF00CCB56851289D52FC2F2BBD6CF27F8D7BEFCE6817A52FC06A468C0BCCC6E27581F11A9394226D7EF8E1E7FCA24295275042F14FE0BEB7C1BFA5A1161FA57796F21C5860D6CC3C9F2D28F5C3EB0F18D27D9C512A4C7D3A3C8B55E0452405643091F679A9352E2B3EB74C0562DD08A45339B1517339C19B88D1E6B13E341C7B932D3613CADCE8B349EFF25DFB15B9306B0520006C72C01B8E1F5D625C76778DC8ED95D62DBCC655500EEFE96F90C8F5D83E4A9FBD2BE87594B6DE62DFFBC056824A4E4EB61B6E83AB9BDFCC9804FE3E2EDBB788BF3E421E62644BCF44B8023213A8FF374A14B8A1EEA61830771C6E2B48AE0AC68B14601D8AAE182A840F98198A8BECF4EC119EECFC5D7FB4D2920AFDB10968F70E65D2C8D5C8102DF73BF6AB44BDAD9B8577FAE45C83D76A3C6E425664131FB3F38E5946B47C0C9444416877D9FD7F3923C5EECAFC435FC17A806C13D79055844164A8216A605615312EA5792592AED524608BFA44DF569B5C6DA880DAB9C2B7CC0171C785ED77104E08B61C7B7625E80EF034EEEF7E13502CC6510A8EBEE8D7C2D6DD85A6DF2D13999042C0B3E78C0188A741B399E212FE05053B9F166EF9B876B17AB413072CE8DCC6004B99233B73F1E9C494B23457767C2197B101D9BAA41BABFE33224B2C1C112E1C3C5F099320603968AA648B2792E7D0F009C1C7C33D6CB5B94CCAA72F7CA5EECC827F34457DA961B39DD98A64C0DF1A1618DBA84681657E108C8620723F31F04728814055924B638319F13011EBDA0289A0BEEB732ACBCB71FDC411B9F981969023F6A3F8411D9D9681DA28DEAFFC84195A442340A537244E69989DD7F5A0F9A33D9ADEF27362321D4CD3A6DD3624D98E8DD1709C3AC48167D91CAC26705A549CD2E0C62621BC275530EBF37AE97458C3CA841E264976F2CE212462AED47D5A0F6EFB27BB657D47BF6BA303CD66FBB1C273A83EC36A4A2EFE2AAE0CE1FEC1B8740E83A73DF7A3B24CA22BBFE52584824445B2ED95D8B8A0BFF28DA14D382B8B54ADF00AD82B3CD5ABBD4935738679DE633243B4C6A6CFDAFC43C908492CAC991FE4000124E0745CBFC21FCA91FB90E6F1183E5E96F67240DCF790D87A569F6603B185DFB5524BFC6959F717891FCDF39C7B66210BA5837A5645C62777D83C07125DEF9E6371991DA53E79A7B5767B6FA08450A806B2E2148B50F9FBC79FC66C47844E3CB6EA74C7DA86F313BA8C54F0FAC364F5C0D49F2C10238D44446AB58EA8FA3B5A5F14ADF3B9FF1AA225BACB62F3BD6028EB1066D7DF265BD210CB4EC7DE71CF028E354FF81B76E3C621ADDE054CBC1366FE069ED6F99BB74DE007B9E2BD31D1A96536F2260FC137AD11C5D2C2108C2C8F3C893F4A6C4A7FA2DE0AAC7931FB85C5882933C128A9C3191C35FE3CA022427B6AD9447A09B6EA0AA9AD70916E9127900DF0457C6B901FA2740353988E26E4B9BA1711E451F375029FED9AC02564333761603E99A1B725136B5494538C88FA2357FD7D9C", + "9F4D899456FD3841B890A61EDAFD40C7B43FECF9D700EE269E58F40BF2CF47CC1C1EC7F28D78909A53C7B79C4E6AFD275BEA739A3617E8B3C3C77ABD4EB770B9E663BF154E77205ED1F2C5669CFCA18DA365B988499547B2C36D4A56582FC610E06E4D43E54CAB563B7E5DBD04CD04EA83DA72645F1F26422D416AA26CB2AE11C1EA270CF7E7AE3679FC2D69E012F0C950FC64A56C7B766F909526EFA0AC383E4A28CC5C52A26CDFD2C3FD2AD820EAD3885DE63114DF5D19A2EA6C2BB338A2171C73A7C10AF41A9E4F0E49142B363AE9D306378B3211CA3B0F21EBA2E72BC131459E9D05CECFC76D6E540587073B0CEA1EE973B56EA2E671353210885EBF3A6465C1D2AD12C89217F1ACB1B209552F1DA1543293D6D1D273C4AC5AA5A4B9D2B368AA82A7FF8E10259FD1FE52BA14F45A40F72B75AB7DA9F73DAEF5642CC1744E6550ED6CE2E547F33598034E8970A74D7B1D58FA2D4248186083BFBB8BC1A34C744B6F08AAC374C28B1C0F9E8C2B220C6EF0B5C0400D3B725005A711EE66FEBA353778ABD4552DEF9E5309FD0002FEAF1F3C5AA3753CFD7CFD62907CAD3B1F68071C01886748201050E39EB0DB18240C5D598D213CBC508B8F0EE7708CED659CE85BCA8BE714DA5A607E023F9609EA3D790501C4A9969FFCDC7B3E7317F6AA6B99CFC32FF1B74AFBD42A9773EB0615598C943BF55C1E8AA3B85D5D2EA2892CC33FA809D71621B02D141C74722397318B8CA0F4F9DEA01096234025573995DD2F915D35F7EBB6F7F3A9E83C2D23D769B639042FC669BE9778390A3E4404C04FC9991FA6860AC811BC07BCAE69756FE9DAB27B91B91C51892D61E94DB2B486C25D13C225810620023F1B9FED1E89B002B7B11A609FF348867E1CFD827199A5F0D6FA267F60F89B09B5A1D8FF62744B386709990589D0557F5EA477974CBB87A86F2E6E94B758607454E3937A539C85569B5E68ACFE4911CB053CE207394B686B962A7487516971740287DE8C51CFD26A14AAA3D974068D227089093812DE910649512D966CB97FCDED09F4BCF7749E16E3391B75A4846F65EEAABC5A1CC89B1D9D52C541DC65CC468B27493F76F6D68AFFCFADAACF20BD979CD63A42EA3B8961EAA2F731C6250436A5A739D3E015FB32E07D373FF650CDCE417EA85A6DB8A9A24FDF62487855DA1C807943154C162AE17BA4E477531100431D647F2D8AE76DEF070A0418D2365549BC66DCA95722801F3A77E435205E919B4B349ABACDB2BD111087B05C05FF01E4BF04F5685665B361D37634855BBA312E96F2C6314590E298770C3CFC4207A0FC944622D4CD7280CDF5AA241232B6B5E78BBE5C6684319AF624124BE84CD2F1512E89D6CAAB620009206AAC993A9F4D6A67859C20A8B9307D8F8E370F2E600A9B363C2A460E0DF5AC007EE110F4C088CFBC2EE82D623D5EC42DB739C2267DFC81C830244A6DEFFD4966480D6EA8D258FC047500062F42446230456F9B5405610863500A8AE2440A00CD16E5B6136B0BF1611345CE7D70319962896B3F5E69583F8D305B760E0ACFFAD762DD06C54EBF8075C1B0ED97FEF59FBB48A7A65C2251DA406D5E9E5F67586C64E5F8FCC805DA4F33BB583DE2D5F85A348AFF0215233EF88C310FD1343934F5AA2A2AAF8F58DED34D0E35D210FF01AB4114E18019A2F7D6927FD843F842AD6AA0E171DDDC2BCF6B49EBF5D91C35665D8F88C0924A453FE96CC06617D81DCE66A3C813F1D3DCD5C37E60BC672ABA16C2025C78E9A1A6B1CBC4C02249AACCF55862C538ECC42D0169B7E3F4B188F2698C", + "47A3C0CD552EDF50F80D3E5FE68A22F85EFBC41BEEB787E5CF0CBE3266EF310BA5E1B29A7FFFB0945121EFCFF811A1B7DD768D3ACFC21C4E6EA1EF06E851F2FB37A5F8E0C49F59A28A4CC2380A0C0B4043A7493320AF4E34A2A20E36A6BDD2AA49088FCFF24C84A4D53FD6D3B29178F921768F21C5827D64C125DE4F7F435C6BD000BCC1C95D0F82D61581049CDF2A34A27F2D9DDC409895B9742443D0CF74F8A7DB13CBAD88E1F1D6F52E4486809E20AAFBFD82B297B038BE774BA13649ED922FC67F6DB9F0864B742F6FB60E849F9A253E8B0B873C8501F72D3523EEF62C1430350852FD17177203DD2BD4065984190EA2075B5385E1D29226236ED894DD10FF82F1DAF16AF55F0940415685B3A58D1DF7CE0B0F069F33E6FFA29FFE6134285CCCEA2DBDF1B901A700765449D67C24766A042D43695D1F5D241974E62817FF9259879813F37AB1E8E51F6C654324118E411ABFBB6448E9EA3CF1F636D2142D65775EF9FE046B80F0DC1D1480158D603626F7002290058E62DA252328927BD20C05E5D3BB0CDFB6C60C04DD8BF4A3C9413241339AC186B054B34B24D9ADE710A79978158F1E2EA5AF6FAE9077CEFA4E335473D29BEEF00624FE6A9DEF0BA52464028BA25D9A9C1BC85901F507AF046D56B17CEE0F23433959CD7F1085481697808B99EE619BD0500B55945186A81B89A9C6B0E32F1D5196C4787BDBB08A6F1D79AF329B38304B1203E9B8093146B15F1207C7EABB020B72B2B92EDB95377D698F10CE7737FA3DA501E0CD09F3FAE9504ACC414E63F60E2721E759CBF2CA1E2671A98656707F4629626219E4F16D8A765AF3E75DEC1B6AA82622916E47872DF33689D820DBEE6EFF26E70F61ADB2EC3D8FC9A0AE30F12E3CC5E9A8E1A820DA15952401D3910F6F500D4CDB7D85401AA4C8F418F7E2A166B491D5CA3B415378891B359112894274F25E9DD2B391A96636D468290AF22FC6BD5C2E7842AC5A62BE24D80E6AF79C6F2118C126D60720601272FA89F966C812EB875052A0BCEC16D0E6C973EBB683214ADAC9BCD0541D32D33AFE16EC2BB424EC8BEAEF0BB8A3DDB18EFDF58EBD84B2DC8C7AD54B86E698BE762E73CEC7C1DFB290F6CC1B63F5257FBFECD9EC87D8DCD2FF393B1C1D1BB2EA9BC10323E6CA3EB8EDCFCCED055680109C03C5C668BB8848F38C4C3369A4E5C0515C7245B0C092F0B8525434468E775F40C4D4206B6420039BE1F695DE802DD718B9AE4FB41320C220F6B9971A4CB8E67C6B0CA3049C2772D2B3C1024A502B48362CE9A1B84BF4C9D47D62409B5CD9BAF1E18DE57E9BA9CCE077266D720DEB23F192C70145FE201561AA2A46B55F9B6E5BC8FAF888FB74BF6510AA7E6BCC40DFD471D6CBD2FCC28B33EBC763E8CA58D5D74C1996D66CD827A6A6B9F22AE7C24B13799A7D0A9C9DE940CA217FDB870A1640B55C69B2E704EA21262DA831C7E23411D81773A965DF6AE015CFAA0D5DD3890D0327C514968C2F72A02A0A35243616AAD673DCF57A684E1C9A6B6F35E12C09553AEA89DD40CFF53EB16C5EB9F98B6D04674F8DE9B6AC125B8B0BBFBA71267A6BFBDE26B64FFAB35E5C5F27B7CA273B901D28997E6298E610404C07569E906AF09A968A9E40475EFEBE524357B044B964136C989FFFC70244DAEC0CE3BBAC48B5A0CC79F20AA1E58DDEFE7BCC9B3C3A04EFA49769A50F81AA8F3D152757F33E935CC6ECE9959B47BB90810BFEB6108C8DE4643B24B4154CB7EC3889F5FEF9045A59E82300275EB4D379BD85A29915796B8125351C1CA84EAEEB7607894508", + "C9ED53081796789261D7D209BF086C92C36B574AFC6ED55C3410E0723C799696D9E7DDDAFB114606EBF4256461FDC9B86BB21A134F735837E6845571F6C2712AE42FE113878AAA18C76D5383FBDD38E43FD1314166DC0B7CFCF3F07ACA56740A582173D2DF20F7E94F0CE29693AEAC6B3D1E4B22BC63395BDA6B49E30B49261FE045CAC9AC29BE5A2D91347EE4543495CCC1A38CAA59593BC3DA05611BDC74806284B4ED73013A415E6B36BC2CE31181971BF4C7B488E78E921C6AC1070772EC36A9BE74DA8AC4FF68B6210A392866B689110D9BC2C7ABB2D82A38EB990891F264DDE5FEC75C6B4E539F971AF2728343F1641F4B05EE8EF3A520DC170B3D8D562A7AB72C409995034F6CE1C258F486ADC9E44FEE47D5E81BF1259C0AAD3BDA4A9E17CA9C74AEE77FABA25B3481C0317199D585BC75BE5A774F8D5CFFDFA9FA652C4B14E29AF2DB5ECBE682CA724BD98E05BBFC82320C8883A56F687F840319DF2D8BDB3FA8553BA3FFFAE0D4EE33E84B62228F924A86C5FD5B3E12672DB6377D807356144009F741325714B5B6AF0803F3DD1AF558C0B76620F77056A18896D2047C967BF69ED972BDCA50409929CC2E2DE802ED09EF87433B978A850ED7710508889EEA4558097A7FD83EACB365371F80FB6EE1F7A6D258B97BF1AF9C321A629A5AB7559CF1B82311F816836E391BDAF741E493298B49C001783921ED1569C149C90D26CBA94F8604BFFC94FE303CCEDD8812A95F7B0E71DE95869D2515E524083C7B2E06C4B5E9DA12BFCA74049F03A352C15DF3B79C3F2015E86FA527BEA76102DCDDC863263F0C7E43CD9D49F05D8F6A124354036388FAE37DEEB43909E415EF9F5877D04CB5A86AFB74FCDC990623C9D4D034816E39B692B68B732322695C97CA93CFF0FE7FACFC1DA29BF0D0C08D93B4485D6664E96B09C8B011B3107FF5232DCDD9B3B8DE7BFDB4CABF31D2E92AF686EB8C2FDFCBEB80B5F5591B3F7AAEEE0FC7A3E4BBDA652C8E857AEE81F499D9DD537139B7A6275C64DDBDD17BFF7594DA69335C01AC24270403E880987F69D4EFBC2BF2B787A631859241063E7EE106D3EFFFE60479A8BB5C11ABE38A76804D43A44327FB4D4F986BE3C52DF109E4D72A092F25CE7FD384B0404628936256877CDDF543099D5B0389A9E05CA93A2B12C3C89BD76F55084A03148E29275159DD41A75FDDC75994B8E8D9FB10E6E80A4E30E2CCE8F8DF3FD7A8DD567BEFF109ECFE3B8C843BAFFEEF5B70D5747471FB84DE2A26747DC73C9B2BE9905C53743159E489E1D0CC14E72046E4C8D84F893CFC7EF15CD9F52C71D91A503802FB5A6813A7BD2DB705BADB58C06E0883F0848E44C20A4948119058226031B5731F36B3A9177065BE9A0294F726E80B5AD2F2723B8698D831DBA376061FC2029979F0EA7AC4BCCD87B6A432051DDA7AB2387260082E6D3BFFD3B2ACE807FB6792DB21AC235C1A58D9E47D42EE055E716D389066AB0814B36291AC71B0AACB666F7CAEA37B89CB424C4EC3CBC68F97AD6FCCF5F3B5094E60D68C2F1180E5CF2141EFC84DAE7509490138E0EE466AE0C7469F4EAB2E5ACC29EBF2BB225E595181F96700B552BC0E1171428FB2A2F0448463CC86DA6F7DD10FB5F789857A29FFE9535D7CA35F70640B9D4B9862234554770331B52E42002D123560BA7DCF9114BA9B8B23D08C3240E3EBCB7359D13767810AD3F3F66A8D698D17F20DA5242259090C0A9AADB9385A2897A5A1F32A7B1549A45D4EA8787523AA210BCB55AF6B15A1F150E79FECB104CE01DAC70125FAE9D1B8D0", + "334994DCE050CEED5471E648F7010ADD69AA0CD3DBB3679C9D3863F86319BEAEF1370902CF4978B8237638507B392AEFEF731E6FB42DFC2A23142EDCECFBA399F9C583866B1BFD7C280CAA43C2CCEC29C6657654C251F7BBC0F83E2C356934C825BCCCB36073A5D540AB82DB7158C7893AFF166B108363405B206E53B13A51BAD149AFEA2A40A37328D4CB3961C9EE2EAD29C76F70FB4E6409F468364DDE7A2439D24FBB05719A6A489513B14229E1949142301AB538AC775AF716707193959417B14A65E2D20319721FCAEE6364D04C480C07D732AE0182090C517B96DB8FBBF66B8B6FBBA35CDCFC87B1C8C0F2E4ADB486474F842434CE9383A57B69D4CDAE68E5306DFD737AB075A60073846634AA6E2A6D6F7CE56A631FE1E3DF256A1E39F0C44C3EDC3A9457EB4FD4477F2AE094979599B9B90EFD1BB9347DF2E654BB9687A2EFB857D9AC1306E20769FEC4329BD54804354E0235AE443AF3BE01E26F0D5998D7FC36DDFA5EDBD3958623B6F065627D6A4EC9901891E3C63522744CBC48BAC51BCC89602D66D1B3E0966398927E869E73AA8B986D9FBB428BB3A71AE7B273A16228349B81927B53DD9B7E96E3D078F25EE564495BFE7B7E6CC042E016499952DCD37F171C709D4734CBD8D46E7989C2C497B5EB9613DC311643ED4B1B08C0C4C2A5854CBA30AA225C683913B5BD46E1DA483BD7EFC2C469DF017BFCB5BB07C64A68E3CE828A537115A07876D30999468358869AC7681380A7E462ECD497A6A6FB6AA134C15C6BDF89A2B8D58B875C00892C50A791D8A50514029F790F7748EB0C1CDDBB07AADEB920238F9C19BFA31097F9AE3B26509DE5C4040CBD82C859EE7C4D094CD7CF8F04395684BF7BAFADF75027B4A47A21CBCC6E3ADFA6A2AC66EA32F670F49BF245F6CDD0FECA201E3E7706F8E37C25FE87B3040C0D8431A00FD4B49E7A050837560D458BB5C2E93986EBED14944F9E92463C312942E6D8340BAF149042FF611DA8ADFF9DC86CD28185555E033F3E22856A80C482D52B2EB21E2D51625FDEC689595EFC3160351B5F30E1B802D5F4F35CFA2C25D8E4101298E6B0B917B5ABEE5DAE3CE09DA595122AA3BB3D8BA8BF0D68EC99C2DE8B4BD7C2A0E0E32ADD32D72696C43C7CDDDF92DACF13D18DE4A1403D0002454E7081B92EBA207DF9411870B91CE9DCC5E26887A437726B6CE2B2DC51907FB108EBFD2F089F893A6D5B5141393C08F497C180AC4A95357E417D40C5E7FB324F0D72F417F688D45B980E215DA436CEAD3794A135A719942FD0C998F3F6F165C16612E2B3ECD4CFAA9A18631AD9D878D63A8E09B0F82C12EAC730E6C5A083399B7A098819F2F25FB2CBD1B6E65E3C30302CEC61680B699F504E5AEB959370E32B58B9FBC832F85AB0846AE4BF678C272CADCB5277EF13A38B1AB787F8E5344D7DDDB074A92DD68A2A2F9695FD52DD685E4316FA7E913DCBF34C3F0D9E9D22CA862D76DF3B5E9E3B54992A7F731C893980F151BF29EB1AAF677B439DB6D20AC69A5A41166799FC54FA68AFFB8D54EFC45B49E25A93B28E87E41CD7B3C61FF24F1D0BB74CB20D2A8D817473188FF8E56EE9C4006083BAD781C3F46BCEC777B2C72A9A3F551353DF186FF9D7B342D86629C4085FF2108B98D8EBC886CFE3C7A4B673D447DAC5B1DBF6BE6064936AAD014C0AEF0078C5D1A626830C480E8B72439C9BD0ECA0B41561E5B0D6618E77042FFEB6CA0F29622EB9F21B83A4560FB26BB98468F33BBFD5CB29AC4F45EE9D68A1E5DFA757DC218B536A9231D7FE228925F96C32E0ADC0", + "1B2A30E6054391704DAD57B34530294AA46DEEA044EA5E707811036742E50DECFE891FF88372A4AF65CAA193E1D8DDA016ECC2A2E3F6D8F2DCF9AD1449C614A70D253161E2B05AC67489E13345C779F3D36BFDFD7AEB2AA30604692969E0C4E375D18293D5D3CC39E31189698BCEED3290A2CFFEA79EDE157F2A52B4EA52FCD82DC4BBD11EABED2F311DB72EAA53A1B6811D03D3C2A30C76A8638E6A775EB3A51FFD4CDFFBB4B961075E6102D2E5555ACB06548D119ECB6895AA00394D4A98C8302E02F8D4FC5CA34B405F25D2B090932A10A4A68CA18D799C1DF1C86B1F88AB219D69C25CAB6AF6CA0B3A4AE390CAE3AA65D3AC95339EE734126226D1F292BA3ED968FD2CD835F621C3CB09E59B9DA5CD23163F573821FB64E296853A8263AC9DC896D6E355A4C4377BDB4E7004CF399C0891C1D23E39F03CDDD94DF7FCDA06261E923C9E0FBD8DE32B49935A03E66C13FE7B00E83674E64D5CBC14C0B9F62A842A17551E5E7001BBFBADAEF36228513A43D4864B8D2C8B272562A6B548C0B3E4610609191B807CE861538B89FA079217C91745EA61ADA6AA96464A135DF216FE5DA5143F55D76D44131FE6E329826F2BA062EAC329161C8D158EC7A3BD5FE57908C7523430ACCAEE3091FAD4B14DFFE0DFED92F014D19641EBAD22052FF8D262D39D6FAB21ED66A82CF8336FE8E3CB3641F15EC5F2E2AC0E99CA07223868BAB78DB3A008B233FCC7966D816082C231C18165422F7123325F365D257FE69867CF0CCBBB875D5153B8C1C0300EBB1AFBA3371B83488143EA2562FA477D210BF68251312A7EC26BC837F9D861101B580249FF24C364DA978C0F57C3A3C29F03F3696C04A3CD330247DEC04A385739D90739847867592B09DF211D8B349FBAA760D64D5E00C9D596CBB8B73E7B17317AD315004B35E7F98672085811DCFE7C86DC0169997F2F9EC9B2B77B97FFA6CE2AA70E2A1030BD3ACC5FC3241F291D0304B71D727828BAD824445226CAA77E210A48EC8F79E0DBCA01505D1AB9F79642716146F7A8F9EA25238FCB2F9C46BDC1489D35B958C44C7928BB4503DB8DFE4C1AF5406C04575C4DAB11995BAC0C7FD72B10ECAE376937B56A035DC0A4D7B2E1A180EDA4A84F97D53B57EFC5562643AA62C37211C2363EEBAB6A2AAC22FFD0BF623CE6867F3C50FE502FF535A68BED2FC98C50BF673B2C5BE8D7D690764C256CDED17E4023A04E70387EC53947395B00E8ED6541CBF0B076AD2B2A26CBF220BC665598D9BC1D1EDD309E687F7D1E7D71F4B2C1B5BA020EFB1DE4248C234A68670916EC8A72FD1EDAF0615CF3FA768FEAA586B08990E05E24E7D8E0DB32F4370CEE72D74BAAB68F6E57F2B9B0F51691990DB46DFADDA7503BE7F64A13F5EB5D49788CE21BA768D028037BBB06F3573CCB244CA51362374776B9EFC776AD71AD1F5635B6CB73822A112149208F10E657E1297026113481BE7C862FA099F331FA5C6B1099AE77D4F6DF2C74736CCD9AE8342287986842063A65845ABF45BA037441D967FA102134B25BC7F1F9E8BD4E54306BF8C36DC01A500F4A1184D7412841329DE6B27BA4D772B1B2B68348228037A9A048C0989AB12B42FBEC45C69203ABF843423D51CFA2D67FA548BB39D0996D4C215157C707DC251032ABE51686BAE8F00E0CB4EDB664A3CABBBDEC85EA7AC7724A461F9F650F9752C1E5B8DF204C3520CEE4A51BF8D3BC9A0AA3AF9D31B95FACD006ECD27889F1D0D1B696DF57403EF0E6FD83164E5900691FB29B19BA4F64084ACFE98567987632483F2EB2CE76E1E0B8", + "5513F3F1C262853F074269AF598A2E43052CA2C0141729078A17BEE4CCD35B761B1766B3C118C06724B0459AF3E973110D7096044F5CAAD9A70F3BC7AABE628848D2A4891AD18CF4A3D9BE900A2F42F5D54AFC7FDC7DBFD3155F9D06078C89F8DB684B62E4CE0DC0AE0E4EE6F0E26A86CEC1DCDD96EE175FECB827BDAB3DD53D465E796FE4C49F46B0B6BEFB951BB1A679190F3FAEC58C00E2FCA744A97907765A3834585E4E00B952B5B7B5F10E34F43C8EA3F46C58F8E31B3239C0658F81FC7DDD5049FD8D67587C85C78C12CF122CCA327A7860A0E34A34DADC677F82014EC7217D2710112B6C0067AD402A941877970C95097A47AACB74A8DAE4C9B5F360B755EFC4546D7D63C580F108B197375AC08EBB1F51E8AAC68C39BEE69EB886BFC2558F0A52AE16F514EC168992775060A5E474E8B2A1180C8F9FD6F3E106963DFA09D48007CC276C1464B00C86CEB1B7372684ED6BFED1DBFA6248F4725E7F8123904BD0552EF70A2E21B8A078CB90EBE75B127A1C887002D70E32CBFB6875138D8DA5B312A97AEAC2DAF9D6506FB08FAA9C334FD686F6CE07F4BAC70766C6FDB001BCDD43421CF70B8B33D22795303769B2C37D25752C9C4494A8E8A0D9A1205A03889946833C065AFECBBEB026E95987C022CFE65DED4F4CB78ABD4DB2CEFC3D69A4303EEA5CB2E8F39A2FCC995DC4BABA644F65411F6809891DF1C0958FB281A7852C8330109EE9D87362F461D3266BA8C2D3E82C9B1400220B19277649CC804A9FDE4C2730AE11CE633975EB3126E8AF60803DDB5C0258F7974BA7C93499B2C2ED1E71CB64E61854D3FC186333328D14A12AC06586246EC7621FBF1BCA2578F2E16A83C9A6800A378C8E280C7F3378CC71011681C884B83A56865F138FE35C123E28F1FD461F60836645A9F9F8CE211A8FD6B07D477674A34F78E3B916A7AC73A0AD9C8323D0229706A8C2214B5ECE1301E470C37818D68092D5DA3F0F794B8D476878A5B9FB339999F5422EAD28A16D8F8B39CDE00D14B659AD8DC33A46F64DDB8E4F142FEAE8A9F55B94C40D62723CC51EF718C0DFA6D9799AA1863498173A0659F816FDEACF2DDCAC54C1D535E1C0FD9922B333C780C1149C4B294AFC5CD23CA8EFF423A3FEFD0EE1A5B0CB28964B8E80C42AB660665C4B55E06E44557689AC22196CE641644959BC7F80D1AA828DE75CC21E0A8FD211BCF6185A7DA81222CAE0B632A7F98484ADD6E83A220CD49D5942B7D16309AB1DFB705852A22A4D51EDD96DB3E318CAD7E96D5531193DB24B50D3EBF55DF8214093ED0491B037E1B38FBCED71199A063ED101C227A10313051F0B4BF4142057A73C491AEDBBE916CE4BC05D1A44FE7A2E7DD76CBD24C13F3758BF7E3BB8139690E33631F180ABA7425DE3E512B53663CF9A8D1B28C0B886C655AD3A03FA8698A5F5AB5484E3CE53CDE1F34A66FCBD734D15BEB727B0FDFDF68BAE40299C73A8F455ED471C82F6DCE240B3BA4EF6364A56828FE2D6BD8DFF03F35F5C6CBDF0C907F7473F24938016615835D801598409F1004C478BB1B2283AEAB437BEEA2F5FC51D8E43F78C0092ED4D0B08FFBDF1CD60454D3BFE6EA1F41EDC5EEC06357DB41F73CAB23556634416369365D13FC8FF9E20EDD8FDEC673F0BD6C8A1EF60E394B596B70F751EF0D9D7E8D573E3526D2D90325B52A08D25F18DB0E6757EBB6002251809ED47C85D4FA37C5890D60B40BAE3AD22258BBEC4CEAA1B6B585EEF32615F7254268DB82532BACBD9C553624AFEA6BE2AE9E1401F9BE05D68A881AC8D9E0CD437F60C00", + "7831C1BA1031B6B0E0ECE28BC7E6A8ED16E3068E8F0006DA96B8740114397B19AA19370B1E1F061AEE3895C30D0B7099668BE752BCD8B1CCBC497E06BB0F75AF47A36EF8925A59E070115D3ED63C6D7FFE54D037B4A818703F6D78BB37725D7F0AECF6CAF120A80C938FF44BFF16544C7847B1A989598F1602A220392CAAC2EBC390FD53D15CFD3372426CA41DCF816E29C731FDCA2E84CF90180039FB1AED0DB9630BC28D54201D5606906091A3F867D257C3A0F8193DCCAB2625D40DE5EDE651C20F2DBC83FD551EF46C4E724D2C516560749AA89D35C7283385E98AB34BB88F8ACF50A0EDCB70888DCBBCF0B792A5D1F2F6977FA081B4EB08BBDA076A43BF1EFCF1C387DD5B92BEB5000B4139938CB0A3B6DFF47B729BB5826C7E188A177CF6DB1B88F051B537DA014B396645218DF4EFDB0DA597B3A78E9884DE4A7B3D06C259C10B78DEA1DB711CBA8FAA2CDF37EF0378091E408960B011F4E4FE24771D0FF3B8DD01DB0527087AC5C0F64EB693D38E0A128FBCB8053E811602A05F3DADF2166CE49EBA13F382E90EF4A143B2CF4FC12DD4873A40FF7354C6E648A56623457665402632C41942D23001C08470AAF1F3FF0A474AC6586C76915FC91AF074103A1CB9304485F92F9639399028EBBFDF9394B4BACD6BD3B2177368B94F639AA8D202D6BCA88D74AF0610C7B565067ABDE4F2BFCF8CFFAAF93274CBC913EE7DC5C77BBE978AB9F82B546462DB933D67E0C6748F943F39B8FD6791847C50A5A834A78C2FBE5D21448A035D83D45F9ECF44C21C4DE726AE8111CF277049331D78B06E9D7D3D0D8915C7C32CD6954D37045E7AFF8AB496A4827574C457523AD6B85F78641BCC4C9535D29B3F8AB4D944125E6E54B3B3F23EBC04BAE3AB102977EF829337F51CD833B4F5D4559D79E695470F498EB4388E573D004D725FE41AB1B39F9526867BF7B99301E0E50AA569B3B23EF78D02FA53C4BB2A184B02977F2D2AB3B71DB09E3E8D9D5B13DB8AEB0A95F9296B7C49B1B3D6903BEEB1B9792B5ACC1A5D11672CA5D8E3825D044DA986D01F6E1E292D74443583E49CEFBCA177BE275977BB4A4F77ECD6FEDC886B4B83AEF5F34AF1A78DDF6B11C201760175D57823DEE0FA5C6A9C1A91638561B857E993779B6B0576994CE86E7DCCA4A89BA2ED84ADD1D8B4E11446C41DD4B1EA71352E26B2AD4B8A1C5C64822CE21BA4B8D7D6589FCFA906768A2BA0C5AD1758AE7B8A2BD757C8E459814CBDD6375DC58497279C0C327F67D14FFA5C90167941CF9AC642B1693D7DE52578AAAA56E0EEDFA4CC12C7469DBFAEAF5F9D3D72FF103918B6F6DF7E0DDACB208A8764B459EB01092A101D42E762FD5C5AB381AEA19BA6EB8CC9CE138892FEDDCBDBF818E97EA8AE9846C0CDABE9B4FD5D80431FE03A4CBDA566314BD1AF59AF120EEE4105E1B701A4058F1112F2A5C8D9F68EECC870DBE78D851F89AFACAEA3A2A068C59654EF5E5BE2F6727136908D993434E5EB1B84331119DB1C02547EAF7C9DD479C5B326CEA6224B16A2E108E76CDF0C54D16E472D0CBC80DAE7980713602FDA31A6B04E4FECCCED96AA3901D7B35D445BDBA020DDF1BE5E9914ACE600ED24E492138F82AE583A2EA454EE7548882C1A192F11345A3F5A3F2CF64B85DF6306F7FD396C4E773FA66CC098EDB3CF8E5599C2EA13A6F726161BB0C0D6673F02E3DB24FF75A5698E91C1522424D443165B52C90FFECFFCE6C42656138BD85409C45D8AC453D6742B42A43A7626E70C212B7318834B7D29CAD0C29F22E6AC3A59359B1A75F727E1DC", + "30B93A783620E3E094D47590AA38B10FF12C3E421887E9081F9A9C5BA1D753F341C33B7322187317C6610EFBD0382DBDC2D863C48F15AC3FA86B3C5A5B9EDB937AE961E8EBC3D880CC79141B79869F95D6E90C5C5E7D9448CDACCBDE184F6FB545324995184770CD2838B61376B148ADF3A42123AEFCF8890CAC7D3AA87A624DF3B883E86AA5FE6DB385778F50BD4E528C6604CFAE0E39BD949118EEA3972327EA355EFB98E9DB563FF72C5B860103AD262BF34BE17295E37A81D1C98EE6FD6690914467048A50AF09435A68FF9A70B59DF8FA7A543BBA24EF8E13AA509C7A311E12773405A4024A0C2D7C2802025FC48E8FC12E4B60543001971FD20F1641B968CAC283BCF8140629DA13D1289B7130F3714B8318518770EE1399CECFF1D3074A65F8913596F92B269529B5FC63D824AC7B6390580C516BDA78BB1F158B2C69AD2FC1BC610AC24DA696F44B58DF813D9DA52529D325BF2B3575768DB43AC3BE5D0402C717FB587B6976E6701B0A70D04F3250B6C54E99983E2B1057DFD9EB7B621504A1004E7E67B33B138628EC7C43A199D00D9FAB8B1990A5FF29E4399051D1C62AD0D86B651E9DD94D27DD6A7B09AFBF1EC737B161A4A398F7F424889C0BE6FBF8EBAE9F1A835FCF4AFD45FB36919D362CF73F0786D93552A7B4E421EFF9D6F98078F85098DC99A1009D6551F02B60E12BC28499A27FD7DEBE1047CD44EFC0D9081323DC08866DDE79F8AE34136B04787F6A5918F5AEE705CFDD5071ACF8FF54A232FE39E1D79D82EFFCB6CE1B68A17B4585817CC9AC33FD6CA21A00929F1EE5B9E3518B27060867624D8262EA18F1B01A525EB6CB337B257C8855FCAB72D7A83DE52E4F1D5E29EA697930C25109182B95A202E519B3757092239BFC633C4A7099290FF7B99FEBF81DF5AC41366D3DAC3384C65AD0EC84F0DA4A0ABF7D8E1E2F8B898FC97325878D911512F1FA5C24F009856D44123EE49C77370F1D58E8476542384A0E45CD852D19EE00025A8BCDCC011BD259AD7360D12B6A630BFEC8A97AC40781694B0D5B3D50D9E843FFAF7A023D451E282FAFFBC38BFDAFEDB34528DC792ACD499179ACD26AA3765523E91A137F52BC959D5969B301B1893564AB348606864916C8D79DE6FFBDB0C2ECE83B0A3BB846FC37C7D4D2A37B2B841CFF9820DB444FB090B430D9714FE2ED731F097FD30C2ECDA7B6A276990647741496729219F244FBC6F1CE02F24F98D0212AD005E54F242A77858622D6BA961190F97438FC4B33217A84B5EA9D3471C27D08C2D52DF19F2DE486C9A5EDBA2A56E1349C3BFD312B8927A9E86A97830DD0B11F505AC481FC6834F8FF7D0E67126033502EB5C593D15E1A56DCB03ACA1A5DBDBD6E6FA9DD3D7D152E8FC1741BD876760F99CE780EA5BDC018022397587357614ED37266C69AFE4644D7D5259770B85B70E7E395D2ABCA3FAEDD5AB32C4B61117BBF707A58530EC435D36370D6AD8F9DA503F8994F6CD627336A731BB149D3D3E96075385DF8CEB3D9B48757A79C67C0E0C701A2CEFA092D5462E28D12548FA041C5407AC321FF049B37225742345E065720A81098B5785AF12927167ADD2F72F766292F421C290C2648E270C34443ABE5B95B7E635B4CBEFF74478F65C77899418C8ABEA6A4C3FE217D784823CB448A7EC0739C7166F4AF733BE758B6D5011EAA9B05ED995DC70E3D5A2D2298801C25049661FCF4CB2E9F7501C86D763CECADB0C86B348C7BF31DF7BB0CEFB4A2EE6861D3D9D441AFF4CDDB979465C1ED95692C5A46F5ABEC180ACDA140AD11BCD5B8", + "84D5B404488AFCC35CFC6EF1CF7A848EE5EE527B7D2D2081EBD8FA8432414FCCB271A43FD618EF95CAF1CEF445B50F02AFDC6B41D5C1F1FF4B6B8F2AB94F90F259383F44246B2D400C3012FD76E2980827C9B5476C4651293CBE9FAA77EFC53E369B94F51BE480EEAA389D88AE421E75EC67C76E30A6FA7EF02500372E4C9AB875EBA1C357C003938B979859B0A914D58F21B3BF1BE8C33A1AF079C5A0A4EA532F93A10F6D96D0A63F3C99E6F06CBC072CC5D71A517FFF40BC260A26E3A46688E79E733E1E2F0010846937689E2998BC769186E0B977AE0A1689245D255AE7D5F34715AD526E824838B62546D9569009A191BA5192535E23142236F4035C90D1405C8530A57B402118FDED2A5DA4B40635D2F95AC7CEAA370686F0AB23AB31DED369BEFB066909B76F2C04039E49FF0CFD323628D03C26F0BD4054C127F21355C33B49F86895D5354C3BBD2C0D38ECD169289F7D8403AA1753B393AC06C887F98315324DBD78F9BFD1AD8880D41D4EA98956EC89BBDAD08F7CFEBF26988EB5AB01D4E49AA8273CAB6AFDFA1CC1C95EDF85284E6570332A0B8242FBA495D87A01A945E61CD36E865CD4F430F04A3B3EE74CE0486B5676F7A938B18E1DB2DAE2FE1C04B3D56892C7394D0B07C5A2F7698D196711DC83FFF6ABDD4E8131E1106EBA23245FB0E2A696E440FB6B0B1CB4DD22C9720AC76F09863711647A7E369FDE5D6911A5FCF987470B8C06C4EF7063B08A8320B4371866789147E9D7C5D477A662A501627F91E95C6E2CB6814651E9DFACD67CA0B1FE62F44081E3BDDB964C1E5ADDC093AD185F0203B4C0F7E3E96811F14C79BC54F2919FCE5B653F6845CF1AC34DA9E4CF52EBA626B739246E25204F9EF2CCF4F5ADBFC53CD8F629FDB82186CB52BEB7136F105D3CFF9CCCC2610BF2C8F943DF5BD03877ED7AFA25CA81C4063E1B97452A937FCF77F1AA068FE2A26F6ECDF662ACDF18391AF7D627C2AA07CF5597B5F33AA0ED4DAC98AA73C8321EBF6918EE568ADEB1A823527AD75CD5BF7ED3EB5633A4EDC8C59DB0A91DA79C248D6894CAF9CB411F302635BEEF1A1C7916C7545B8BE7C577692245E285D32B4FD18E1478F88F8373E22A5CEC6D22EACAD2A41612F05AB2C54A1C03C0512359B0F9C5F91615EF2EA80DE97230480F489FEDA38D52FC84E2F1258CB20FF0E850639B31C2958BA6C064D0D0F4AAEFF313E43C65EFFFBB47CF09F2A122D15F76E8B704DA8F2B8C71449AA49774EBB7B2DC97CF6004D2FF6D37B9C689261189B85CFD50C20C961F22A644F51497377426556B956DB8C899045B175A8B9CB22EFDE535CF487E9D958281E0467539853054FC3475D2E142D58F9201C1DC6B2C1A12B2878F9366E2216405069B7D03852AB37EE83112EF2EE172F4E5317A41653A656A06F6633AF59062A47263A9977A50B9115456A58F9C3424FE7E0CC57DA70FEE0411C1479B4CC2E6E720B01432CFB3C503983B37FFBE38C92E50D6C5795443F73244F6D28AE6270E27D46A25621F86A2BC4259DE6C04CCAA657FE656C640833B290F00A1660329A3F09FFE60152A23925F4D8B0933AC016B5802CA863F66F8CEB5C8383B1180A515AE6C51B5F56597C3A004F8D25F8A6235C97B4DE38468B63E3B859A487AFC4320598EB6D143E5C914409D25F6DFF6E957D575C71D3ECBC6743CCCC03E5F34791744637A994F3ADF86966B4FE911C06F7BA1A6C20A2971D82B64E49721A530D9D5A2319D5BE0F47B8119C5A835CABEC735A935E23CB439970437C6F4CCDE2525EF0D7B1555CBE70280D5E760", + "A5029C9EB4623226D321FF78D3C4EAB1F672A8B2B24A09CAEF21F561A851323C05A3C5E136A2DA7104ED19FBFFCAC3FC49B6D598F3060E93552EA6C700B837F7CE04721919B9C96A57B42AA1D832307C7A847091848066CB84947BE5F6B54654479E39F654819D3EF7AF4939FB9F4C9B20CA7F83DA0FDA2F171FDB72455B7ED0D43206992520CDD86B29C48BCC687573AAC4217D0B7DCF852811ADC3ECADDB2B34B4572675CCAEFDAAA01F83561E6E240878F229698185A80E6FECEE89455A72A377C24CE3FECAEC2A34B9CA98D288596D1C769CDEAB06871316CA7D1DDC5862E6282DECE33F362C64A73E57AB266715068932ECC31E62AD2ECFF7C6FBFE213384DA086ADF49E30F432EE2C715D9AC4DEF53A7B09B0D722CAC560FE8CF0059B80428458282F7E81717647D72E321A3E4BEF16FAEF76009BD98B8D9822B771EB62F1D0748E462FB7F3BEE9B12AA86D9629085AEDF8E43E1252EE59970CFF66A6F865C7651EF83F8FE10EB0E2615BF8F5C7F12FC601B0CF795C0D8B7057F54408BEFF86747C0F6F23EF212A9086EADD464A25341AB71FBA4ADED8F599C38FC15E790A5B86E64977C5AC718DD0B47C1A476AC9D7369396144F6288E84F7FFBDE02EC00EEAE8ED415C84648364ECBEC42164514D3E26BFD3187E0641C216FFC57E00DD752CDA581686916221DCD1AF07582391C5FBEF047FD1B7B956B458DE925C02A756FE197233E0304D0E034FF9A176B5B3F5FB683AB41D2691E13F97B3F4EB33238851331197C49C60233232DA0E2610430461876FF6F77FF3CCAF1BB2424B8B347588667B48480476D40BD9E487468CD5AFEB597C750A5E665B4E7C4C169ED08ADFC731FEA928052C4FB85B3064EC07B0CB988E324893B3F084291D964403F0350B7E1B06DFB73362C38318B762A972972BFB76CC5C08B5D47DBA0F3A2473D7749DE9F49F50C4C1620A9EE9FE56296124D72906497411DB87D4D8EC4E1F79BEF27232008A2299F5317FC1A6F455F1B827F1712BC01814F0B9D0CC162B25B804278B9C7BC5FC5616B317F2050234A7AF92FE35A59E22C959C7163DFA5F142022BE5CC4D5EF16D218216C57C2E29DA926436C00DCB82E68E16CA5A07158D8B8864D38A765D14E82175114A28CD97D11D564C8C7B87411589A4FBD49F9900D08939B7A73B5E6466B6F607F8AD22120A559A02BFCEF6456E7AECE8C9B7C9D2B322D2197124C05363B2CBFA58B74CD88877F22A5E5C202FC2C33531125F1518F4F0F38FA788E5E6B3307A75EC73E545391CEA200243DD6D25A5B8654A00B82BA57437BF0ACCB0ED37ED2FED221E54EC12B93AFA6E3939223596075F4C47340355D7222A8234A1F65EDDA42FFF5D19F7FACBF09AA77E7962F4CFBF61A0F26FB18E31A504B371714048874BEB286AFF71B43E4739A17E8AC25FA77121ABBE6E99754AF42F1D0021EA1E3FF088D0734BB191F91A520C96E22B4A28F9A2BD7DF81E8079EE5D0DDCBD517046F12098FAF6920E0EBA10DE8CFB391C63C60D62C1F4BB26BF8B6E421A830575731F67D306CEB5D6FF04637144790EC4AA2F435906320114CB81EB40C22B271FBB065474687AA5880F1DBAAA1744AB3E9B831A932A9208BEA9F5D526C52F5FDA56320E123CFB553E2B71A595DDED2ECBBD6E890B0421D765D2E9FD0D3995DF2A9523A65FE2040710DF16F2A83F510DCA08493DC138541E5681B51EE87D84C9AC11612EB5C06F5A63E22BD6275E35216766D79B215DBD087E9CADA0CEB09BFE435DF9B7809A76DE323B373682B8C58CB4F08D9C708EB050DEC", }; + // Galileo E5a-Q primary codes const std::string Galileo_E5a_Q_PRIMARY_CODE[Galileo_E5a_NUMBER_OF_CODES] = { - "515537AD5E5F4216C16046FB0AC50DCDBE5CEE7E3CBB51B6ABB4E87A407B90E0EFD49DE1DE5ED29184E7FF0DC31F75FBB94F46FF6586B36C7771E5A68D060A965ACCF8D640C6B6E4530FDF19DD2491BCAB69ACBCFD3EC7281CCC31253A471B652E21C4CB0B43613EC542266460F0A6199B436BEFD95572DEBEE920A915FD854D17FFD0DF8C74E23B21B28493A0927709709B07C65878C43B69DC501E9D0AA21061ECF173876CAE708C764435832D9D6FCFE62DDF2543016D6325A56D9BF1007886E62E8A832BC32063CB0717D723C5E8C5F0C0EB3960577D364C93060B64EE04A539B7601CC3113E0AEC53CF21AFAD0154DC5CCECF038474E0F4004A65B1EE2801F81968B88C3D35E87CBB126C02D770CC3D32A552883D351DEF47847391484F80646728221F993921BFC14126EE3D9527DE607152724C6D2DD305D3FEA0AAAEDF6509A2FE3248494A54FDA8E3CE7E6BBCE234E4686BA5A19724BA2CB78CFE71A6AF45532EFB286C5BB47BC3C1EEF4E4A8C757786AE974F30A86CD60EBCBFDF5502AA8F643819CBA4301E731ADBA1345B61C0B444FE7B817EA86F8DD749C451AE7D24A68D914F26C918238953E8AE61CC8553213DD6856C7863F9F6BAB1B4C84B225911E7B92BFFC12AC211B2B2CD905877FE976E07057963D47C437FE47D89648053F81AC39E8FD2F3A726866F6693E503CB6F0C3F0AA9B3EE2EA3BCDB16D726E1C6D8B073AA15F64EB68D53B1F8CDAC19C7AC33361226E81F1C793BF188755A3FE1BAC38B91ABBD4F077F7A28983EAFADC346CB941D49492625893453B364D07FE06FE42B160C16FE0462AB6366FFDEE54DC9CE4DCCA21E4E4AE5E92C872D1E4EC6FF6D3063C98A5AA5EE72481A0BDF15152E2A5425AB722101474D0E1EC8401273EA1BE1DAF7403190A94305BD1C7DFBE1F35F65D5CB97E82B7A297047507FFA0012FB73360FB8719C174E78A989A96E60A9184B3F3A8188DE100AB361921D38E8142859C8F0F7D441DB1B2E9687BBD1086643987C83DEE0BE8CED4C83BCC82B62B45311CE4F13ABC55BF5EB1ECDF15F5A07F8B2C42F07FACE0E299E87727E2D534FEBF7B9C3894CC3E2E4127A294B9FA2A671273B174DBB81D247CD2846116500A072DC3962C65FFECD0C0B46DC2AF52882058259C26FDE50BEB319AEECFA1FABA34C069680B9EBAA9D96EEBD7EA30E748213E1283396A2AFC63527624641D4E1F1022A973B1898BD4CEF4D712B49371A51D60E08F42ED1EA90AC49EEFBCC53E7F9E899DD1AA4056F11462DF1A4C81620A73C831CEB897430A22252B901EC3D6F3DF58EF26422F796EA31AA4E0E9CE5B4A9C312A22305E298FEB3B3628283D405EDF726937327D90C542434BA3B60684584A9DB244839D2ACBCD7EF147A541E35687B5B8F5F07764973112D20D1ED75DC31F6A938542B42EFAAEE0F11B0583AA4925C3132356200E8D6BDB3127B975F4115A7A8A1C471836E3C5450B501A24D4A1308BB319AA827222B550F253F64B6F7D2322C6A2D3012FEC265A66A60102A3340CBDAB900DFDB36693D41DAD8DDB8875F8C3BE76AD5355DD81D67AAEBFFFE9458E522BE0312E60F63DD92F25C0D7CF82F223AEC0BD7456752CBD5151FEB5368F8857EAFAA90E8C7499B75D46EC4CA20BA8A24C90C016B5BD2CD7864828C6140E98EDB9509AD1194F56D49675D077DE92CD481B469E3A37F7DF0D5392DA4CE4CB282530F1C73482CC0926B877B00B0CE49FAD21E4C26194C7E950E0078F3854EF88755E08E9380165C584A3DBF1ECEF6A31B224FC321326B93797BFE8", - "D67539AFB80711A0BA3CD67D963BAD346BA813D35A2EEA104D36AAAB863C656A07AD61BA60598C07744D32ED01EFCE928346C09EAAC2D392E5655F0FEBC486815AE30A38014DD8520F73CCBB71D9D42636328A50998A2A3BED3E4B34D0DCD65B94807064E2EF0C420898DB96E3B99EA9A0AD91C63857DEAEDDA5E644E62212B23D72FEDBBAA78C6581C677B10689C4AF387626DAC55F4EBE1893D52D28D20EA365702448A64A0C553ED337C3BB911DDAE2A91727299D8064BEC880183064574B5E3631E70A0590210143F4079C572BD5E2F7634C2D53B1FB1DABE79C484799E7075EFF98F033F5B2EC66C373825335D883911CEC9CFBBE2E38129B7E03D9646A7E513D5069043BC62AF4C524F12D8F98D8C9DAC5D8642DFFF48CF6737AFBBCBE965925F55F03BBD5123C9DB47AAC780301DE91FBED3C01D03E6464C2C2915BFA187A4BD93E20C24574FB91F0358CBE0921DCC8D6B7E9976763A1D2158511861EFF5D1C0B71F608E7ADE91D9DCFF5640B55BC9BD1BB322C879C7EB5C06EB2601D06241D09CFB1BC1695DFA55FA044E0E2E4BC86EFBF6A55740C4640512DDD6CA069940BC0FE1738FD376C68BA8AF7CCBA7D89F7966B29355538836372EF418D149EBF3AC104919D91BCA2F13E79A7CF7684A4DC0AC556A2843E041A71F97C94B859FE009659F593EFFEBAA6F6C1C57A5BF22752613AFB26379C42AC25804AEDAE22D63B230FCB858F496B8EA6F37104D0890525DBDE06AD988BA0287B0938572F14A98EC9E60E973FD693DB1F2AFF671AB03FB12B729D0867938DF6B60EC69790C992C6C33A531FE56D0ECC1465F65E3E57FC9E45F0F65A1061CE6D3190B6C1B8708A8A5A47222369AE889D26499CDE8F0548B8D7071F2D4DF6C0F2418BE449552327981CB0B54F792F29A71E30DE257CE1B3A7553A22275E4C8B9FAC3B8D4E9912BB22B0A899E7337513C7ACBEDA15FAD3D6919FDDD941CA659D78B74FD39E2E2F622691B89CA82FFE602DB2578A20D4665184456F32DF4DD6CBC412EC7C6914CA427CEE02F6D9810AAE1406DD68ED3869BD8E3947A2B3A803E875FF82005D853E3F43A6BF936030744C34C8B71B7722BE0AD3F475E531C9249A42671D5F3A5C77C4C28DE29AE953EBFB572578B17B636F8365FC755C22871E7D53A1F1561C92909305C9FD36AAF79E8844B63370B800B25CC1355211D9919B830A988926829F808DD2C66400279E6AC14F8EECBBE8B6E9ABFA3BDBB38A49535F64F719EF48C5FE6B2738DC6F71AACD70274FD40A29BFCAA594AC3E7D0C3C522E406BA6392444C9F362339E8FF34BE330911DC7EB11A47FF3A62A46CDE961A40CD5B24020909E5B034F45FE96CB156FFE8E2FDBC12A7C12D60D24BFBE596544E4F03AF26F086A5A667496B7DF302E4DCFC568C7ABD665EA7EAD8A7F5A000DAD9F43E68C4D8A14742E050769B3CB270E3856D7E8F4E827046D3E55A52F0E02C883881914DE87AE3C24D93E61A94919B40398D3EABB1B5142431AB919208A9785962D05061EDC951C83C73FBF6AE8DD6FF839E631C9FCF6635FA053DBCF932E359F83FBB3EE310281569741E3A8975FAAD1E573E0EC3207F6DBCDB8CC90DCA1CE517C8DFC1D31AE4841F87A5157792738DAEE7C29240DAE26C6C3E9D8A899D2271B0C374BD2EE846C6625E31B2F8379A96F601323039D281608A01A1844E5D1D20CF1D92C52107CDA71BB3B7EC4DEA958CFD7A79F71868116CD1DD2B2E66BB94D1373B733F324BE489DA51BE72B01A8572880AE1E61650B839D03B0192D290D5B36A9CF93B304", - "58B2E58A13D4D5F84F37A389E6B01DFA66DBC6A25338B2884EF08056BF0A9124DA29254AA79CDF1B0944DDED4BC7FE683EF7A3C7A1C359E61E959471E30F9D534F43EEF274AC6535C616ADC7455BFBFF43ABF268F7C995CE020CEC73BDBD04007562F2710498AD1A324F25A6233B2DF2D9A429F1C39943E45F934986D1979D293F90CFBEBE01665C98C0D72D09A382348136980B31F5D4696B85C3F42D5C445996804159CD4C4CE7547C4A3FB718AB62D9E9826D05C44C6BD21D708CABB01F46514F29FBE7352866EDBFABD0ADBB6093E1A519D0E11E27737239A07866752B6D864686AF1E308481C53C635046C0756E8008D3CD26DB970C5D6EF8CB9DE6BC4339EE9F88EA45D11B74A1525E2F1B9F91567A78E403F7ECD47A99E95C098870B928E1B0DAA984CCECA13C6857F350E808BBF66AB4EDFB0F369F6F009268D19DEEB377F7D0C4ED6414EF6D23A0A5F37A25AAD3CD62C2115CB70409049CF0CE6D4DBCC5C96767614C6FAF73E9A76C7550BB970AB3D3ACE0C07FAA9F36F1935DFCD5228427BBEB5FC7A2F951D9210A5BC32ACCA7E78AFD5FD460CE2A79348714E5542BF2D453680B070E85F3244E8A6B4EB6ED49F803E60B8A383C8BE6283B1C4DF79E0C4A23D5DAFCB26DFC5DF1D1520FB6CDA23A05A1513F751EBD0143C2B9F5494BAA74F9F95F189C5767C6F5623559D9F20CC9B9C9ADFE285FA4E1BBDA481A52ABAB36A5393370091A49A59B968CFAE89BEAF33BCA5C2A9BCC1758CEEFC2D0A175C8A5CAD5C7E3FA706C2FEA55F4971A7B8A0C5D1F22A26D7DA9A70603AC34566E4929AE78C8F1926239950EC0A6E1B37D919E24431E53FB08B2F7DCDCA2EF4177BD7D2F81BFC784FBEA0471831CDCBB9E11D60C53D0E062E8BB8D98B8EE5A40960EBE10FA642751B96E1407B38A024DC64D5C2005E71198EF394673A4A0097187D2475CF27B3EAA7955AD9F412A89B36AFB27FDF7FE699B2CC8C03F7FA40549178DF8A3C1A39441EAE869BBC89D583ECB18E310885F33B95B719045CA6955720CA75D5CF0B29E5F1B9E9EAC5EC92980B2D37EF6509CCA6E67544A8116494AC7EB9032E1E8CDB053B5AC0F60DE59BBFB78E3491D50C7ADED95042A8885FE284E90C04FFC0370B92B68379B2E7D52392A42FEB26B2419CC64412BFFC036C01109B9EAEC5FAF485F0D61C37A703EAD02127611F9D25E4EC515CABE21247156F0779CAB57C35581646BB71E87941AB5D06FB3C06C423E9E83E0C07E611C89CB000344AF49498EF5C30305DDC8958F45A45E1218837269DEEDBB0AE51D2AD8B41BE425EB7AB798856911B6F0DC721756A8154B9D1CCD61092D16A3E9E1CD5E1D7C2C45D236C9B21A0ED64AD4C0660FE42FC0B543A34FB545B0D88D42F696D53BF54A1A259486846E81B44C16EF146310AEFB3933BA9F9D4497E74AFE1449D69105B9F295DB24B4563C3FC0166CB70F104B3360BC0998EFEBABC6276F570F7679865036DB59B51AD2F91C0CCD3BCF5C07492765D480494AB5B87E83FD04B75A35F88656D3329AA5FD550DBF493B0CD2C19DEBE4358661C72A71FB17C812F75BEB61302AAAA1F757288C1D8626461F4162A2EC6296B3CCABE21B4F0695F2D2CB02B86035251FC9C5F2FB5BBF28237417DC56471629B3B4C25AFEDC4C9CD108ADAD9DB1330AB680E4998C5B3D99BCE8F08156B630A63EF36A51C813CE22A6B178683EDA389ACF58653582BC2AE8170ADEC4BE03C04CBA603C0E4572A74BD9599A8442E894EB504F7703F2353A8A3525EC5535E750303AC07E08D952755F97AF236014", - "3059141DB31B84555DDC1C5F40372C50BEF6E82B433D87603BB7803FDE8FFD74DE06809357F11C1D6ABF02D4DB8EBE1D5ABE7F30C91A451EE3C1AA36735FAB9185C785F05D28BD470D433ED4ADDF36406487CA1710ACAB57EA0DD577A49C841F5E78B70FDE90BC1087E79E27E53A4B131C06BF33843BFEBDC0C2A207510590E52158C0855C40146AFCB75DEEEB872ADC5E77CD1DD6A66EA96CC223B3295C136E2766ECE9F2CB807C68C84FD04E0A5179D58473860962083DA8D68B70DB95C0EB91679CF5E1BA468786725EDFB179A2C5E7C28B396A53D89A98C7B79867E240176A9DF9FB0BECCC22A526B617CB8FC2B05A8DE411C8C5F9BE682459B487B26643FA894F9B3C97282EAE397A03DD15F07FBDF7432DD95D29E6D50CE95860BEC2649E482F40F7B83A13135A7C71D83ABA44A363C864BCD78050AC69A8DC0A9E601859087DBD49AA01A75053792F74D9A8EE726608D1F009D06363F6E5A463BC362178918737C5F3E71EBF130691A2048F07F3F8CDAB70C9D0F7B9A1180046076E1B894AFC620244B30A571DF359C7D60969A9436F05417DB5759B2D3ABDF6A238B5B5DCA8A0E4C27F7078DBB6600FC0105463E745A321884A4F6C5963B188919EC24C460F1B9CB9C063B2CD1FD5F49C06AC2E61EEA55056A6ED08B6C7C750E30EE66508FF243FE1B5C494E8EAEE5467AA0ADEA834523C536855D3BF5ACFFFC0802365B3889C31910A5E63B9457E46B4B7E29189F1BC21E7950BF9FB44BF5D76078D8602FFD986E1A1F1A74C677BD8811FC6992F39384CB3F9B2C91F381DC01D4E79D2E66E6D76796728E0C48F71817ED182759D8B10F7B5D361D7138CAFBECA3234B9F2F4A76FB00DEC05D67FA8E7217E488688CF87D59AB4FE7B13C793C1A1711C401B49C381F76B5CE120BDFDF30A858DE62A3F4331E4A3CC167030829906935FAC167A7327B5FC0527E014801A27FE0F2D40EC13C66235EFED070979576DA7268D1871E8487C4DFFC62D27B83488A73FDDEE1470832EAEFF621CE8E126267A47EC00773922BE480C7F26C8E4785D886BF8E6518DF13DA86BB2925A432D479E8B8FA9F92442891F71AC7C05C0BB0E4396158A492BD49E42AB4C4737A952D6B2B2780EAA73DEE13037D659A43DE1A8F0E525D7F96FDD1629FE51560F77E4A1CFE903DF0891B39F50B71E0F84965413DB34B1EE95CC1B6728AC3D1924B34D1BAD4A4E4F7D98D1B938C567B6F3C95770068775F78EFA147ACC619AFD0B6D8C66034C21B2991419217256D88F265922FD49B4BB38D2955305A8D01D01758B01134196C525315726D9BB6D77917A57F2C46A05DE91A3FF80DD2B5AAAD899D679EB55341FAC6D5C2E9C6B703806E342B2C11CF84B394BFDFCA378B26C7E0CD23C8A87B7CBEF6828D9E023B2B7060A0FEEE0D29CE59B379A02AAB7DFCC41A35CB9A94408A321BF78A54D2D4DB0E170101798F6622D8087A2022A993E85DEB5CBF0F4DC2A047877EEC9DD145471D57015DD59A37BA60C9BE39A4AFB92289562601BCE8102C83292E2ED842470D715D34F11981BCCB81ACB443FA732F792C5F11B7DA5D1BCDD84EB80820EB2BA3813F5E6EC5300E622DD81B1FDE8C786387864D78246A432CE245E0883745D9A1DE9D68253CCBFE7C00EA908E452DD3B9669F1E6812E40D9E2C423180BCA98F4591307CF8B8E98B7F828989CA7F3F0BEEA4D408898364C6DC160C94B89D879B1D07286EAA3FFBC6CD7FFE5700304AF3FC049098590DD7F6D4770ED66FF60DB2909C2DC6DC67ACFDB7CDEEF1B714BFE4CA04F2D5172137C", - "4427106DF31EF72E43B6C75CB84BE5E375B6B6D4D21226D0FD689E8F14EBB81372B93F5455ACE6C168345234B378500BE6612FC10536607E85B884AEC780550F2A26FBF0445E0AE9C0F4CB95F01BBC76652A9E6FC457D6BA425EA8B9457A6F3C0AD2A0FE7BDD1C1CB19A9F1A8815D84EB5843AECA4DD005378111E9AFBA9C3CFD808C0C3CF2B39B1962EA44B0848452778168F7F60034A68E5980EB63B94E50D170C680FD6345F12CF30E9089A7C0A422661DB7B1BCF2480238AD043FA1D0DADEE998F7CD69FF04BC336BBD5985315D4E1CC78558D4E235CD7E05015A5734896597F16E65E45E0C819CB0B895A38883ABE4F439D10195D88366CD14F45947716AAFD770C27FAF6374CDEB53B118277906F7E61C583E8C7CE3FE733541882C511936076DBCF65094E37FE2FF54E0977595077EA26E03711FE9054E2D31AE7F99939B415F46C05BB55BA7BC4F31F337D624A94C9629526ED51A9B93B1B3C5551F9B92A30759D7A40025E98E50128232A706CF6C3F6734D00571F91307EFDBC9718D78B3B792909C1C56BB8526CF5B229D4DB47E61D962538BBB17E6CE8CFB7854EFEB5591CDFD5DD8BB22FCA50E4D97BFC4C36E2573C0B495FEC9830FAC229976FB651B82DBA34173F5635875B1460A023CDA65333138C89DC81275F7F3446472F5F8C5F93AB130009F5B797D9ED536ADF5A42ABF6345B1457D5C96CFCBFFBA56CF124E78FEBF8A8BCDFFA97831A589D177AD260499130EECF8247FA5C44B3C0C19AFE6BBB0A7B87080E14F3C3457C8424557BD9078DEC09A3A6704E1D77049A1A4431E423B28B9476EAB6292CA1B3B4B43E18EF929EFFCDD574417B15A4DC1269E593F884DF5D492A464AC3F2436B8C691B88658180E53228AD83C4FB843F8571D42A9BDEF37EC4926DCEE5002A12144600C9CE7AFE483F3A64E480CD09F8CAFEABC9710E01A8120E84BE5861D75705A8D18F02756D8FA78392F1C89D05F37CB9F768289B8CA99E22E86F8200770D6DD2D76951A45F73C0730162C363886282524436D029786E7CFA2EFBCD3D05169D362DC8BD472AB376C12097443080F3C83AF1EF7339D8FCB85FA098BBCB5EC3645A03902B758DB263A21C8CC4874F96D672EB192BC1A183A1B271BC1D6429CEAA8208F5CB240F451A71B6F884537ACD49471010ACDF28887F6A02A04E738CF9FB5B00E0C474C460EED1F791F4EAB3F9AEC225B40CCE223D23D07CF0B60846C111A07A86448B9CF119754935E8C350752CC60AACB55C71F4D5F5F2BDC3E412039D336ABC6F3D46EB0D1C2080CF260EE77F5C73A35C23396E2324998B7DD375537DD35B5F27C3B545492F682C4B89F13F65FC4F72539E4A7763BF4AE2443FE0A2F683A86274672FB9581668CD2B075C274B242536087C4DA1E69D0712161B868ABE86C98468FE43A42DD2AE30089ED92B7A750C73B19A6D70FBC0AC08299EE2A9BC94652B35D5B2D679220D34D3372AD756F842861470CC3A3F2BEE75112B138613A40FA585E449FADD6353A09363EB6025D4B81F9F224817FC2DEEAE01D797AA8A0F8C945FC69D5891355C28ACAB8997A0518C8F4465953819113914A7CB472EABDD1A8D943A82FA41315D006E54AEA4CAB21601A2ECF6CA0521579A6A92DFB6B77BEC6D5A05B0A72F16B0328C860FAB66A1D6113B7098FE50F3B09C2306D0B9D00987B351CB2BE099A7AA7EB7AA691A4E2D243DD7D0D864CF80A4D2FACBEC3C1CB222883CED667477D189100A5677CC3FF0DF31D1119D5F31ED2120E5DAAFB99E8F36E77B3B078C47B3D527DFD6521D7C", - "593CF84751C21D591BB62FA0B0AB65E993408A016415D6296E0F080FA9149A4C31D8B2EA68CD7209E2FB0B4BCCF654B013D92AD7A4F6B1935995FD106663CD5760E63702196F63563DC994570C1B8E9B0A7705002ED56D335632ABE3ED8BC6CAF109F0588040DFD167DC364EA7F692D5F59C5616A6A7DA0C5EAA4D9FF017820225D5B164B6106CE9307B56EB08C563F123A05A4C93488DF63A6E4274BF5188475E8F7ABB8C3E7A8323F689DD93B043BD98BC948A567E8C6C95FD3788ABE728F7B7E299C460F9B35A59BA4429BF417B9F8C54F2DC475A7109B9C25C0843AA86ADAEF388A9915E65EA08C96C4C84022368E79A3A466B247EE6A37918CA0A8DC6AFE291CB9D360D727B6E7415D360AC414BD34DA40A1D995EE1303896465D52707A4F31A30C7B7DF936391435A5FD3F06E336CDA36E473E3D990A6F04FB5E6340581AE86D8EF81B9BA68979058BCFA1363D3F711D33EE9E3A8402A14AFEBF339BA7C34FA4EA2004FFD09129667646A79B6322CF00E1B46C1418557E0E62E106901176CA771979F4B6B299BEEFEF7B847F4E3ED99F56D44F5C73F00488E1DD862BFFE5290DBA737FAFA0C9D95C8307A10DD309C177BFC46A9F6D3BC86F598DC1AC69B070B9AF1CA2824F456E73747A0CED38631F9AC222914825CC3898F04F6AC09B01EF4CB09A63C9436625E2D0AC3C433A31D86948CE34663E5462652980B3B57C0920EB63879E28CA9565BEADC47F29C43F1718CE34CA5717D7AC2CEB6758A16F6D769CC277BDB483808CCA3A6DB99D1018888BB6A49D325891B5D6B4B77B18A5A4133AFD5E8AFA4542710483B52E3D51D8A4FB77D2458C4FBE2DEC1F6DD8C0FDD8FABE2130297D0606F07B305B2CEDB39204E2B8F8507ABD49C0FEFAD0332F8ED98736FEF5AE4FAF8515CD638E28F1555F54D7A64FB38D0B47734D0AEB8B55A792259427613733F237FC57DFC1AD49930D9844C9F44C3D6265BE3102D93E2B62D3B0D7760F613B1F5F5176E0C5EAE47970D30D211403477894B8D66D03CB3AE8992E16D52F6B2073DED09D504B36289644241EFD21018C570A2CEE6D59667F274CBA5733E41BE3370DFA47464AF850B14DCC32BCF1A5A8385314E8B38B2A642AA90B8A5647DF9B32B83D3B4B2AAA54472BFE84EF7DF68ABD0236DE171E5AEDE1770F63823EC143B30FFC69ECC464CD755F5AFD2B51AB5F05B74E96F6108810CDA94F99DF828EDE147BE061FEA46CF6A84CAC720717733A17677BF620C4963DD1A08512CDB6A96DD3ADA995D84A934C9825FA3B588D916CE1898F6C2F75B75481383B27204C343CCCE41E10DFAFBB42BC6BCCFBF7BA4C460147814014F9470ECC8B99D677EEC872172B72E5839D263F55B9FC91AE6143FCD1BC3AEDB12312ED10647E011A020B27C69E35CBA94623960543DB08D67B8CFD06760450A067E3F868386975793AF43AC4D0F3773AFF6C2CEFC8310C0701CB934098D842604E38370182BF05A401C38B6CFBD19CD7D4BA186A595ABAA48B8740DC321FC031D76F82B4F5FD6949AA101D70A702E18D8C2BC1283C2E2CB138699D507FAEC5B6A092E5AECB0AD9BF2E59F175DACE05DC18E485B04DDB963426A117CA0B761EF485B234971B6F681CE3CC5CE58A9BDAD9267E5C075D1BCEE2C88637E2A10AD441E9B1CF4A324B77C6623F4DF9FC6C4AACE068F66017BC82D562722FC93B02489DFBB5560BF60F57B736212DD8A0533071D10ABFCB4EEAD5AD9E36E856C8ADE0B9C4F6F5116EED43A39AF8FFCFA01BD558D7575AF0E36F2AFF74E29435778F4BA57A5D90", - "214AD702A657F5A17A601D77E0F4C6A67B7B8C074514548FF89A781CF2E0B5225D95A944D1048338FF3AF206D331DBCB3F5E9E89C7E592A2295CB783F416C4160FCFD26983ADDDAC52BBFDD6A7125BA4426715F82AD9815F30B2DDA972A2E814D6BD231D453858749D65EE1B4C2025F61EFDF8E12E50A3719899C611682E7B2AE0CC85294542DDC04140ADDCCD5DCA315C22E5ACB196531A3B0071DC787C2753C3069F5D302A9FCF99B71317FF2749749C6E00B73F382983E1C91BC8115FEAEFF083434DEC7E8A22ECF2D1CDFC7B7ACB80FE0DD1EAF7510F694961E09882E50994169BF60C47B95BF37B5D6F13CFE48A9405637F87C157863C58E479488278B918DDF041214BCEE2ADEEF4242F55DE971E1A7F2EC566B362F89DABF163A690C8A8B808ABC1217C7D49933E30272A08689F7519B35FF8C1CE0F338D0B75332D163A5DCDE714B821AD3B8393A1740B6BE4AAC6008EBBBA30B8E5FA2253DDCF16B3F87B4FA47C1D36AC86E2FC39DE8BAFA79E7D58A3A6CD83FE09448EAB6020BF121234B23A72BB7DC02A2E235BB5DE3B2AA97D3931CB800165B93851EC81A1B4B7781F23E5C946F035026888C3D8C31170787F78333FFF8ECD8835AB5E9D165A8B1D97B19936940EC4C74D115A34120EAC800E8D680B36D9E29180BEAF5B3CFCC3913EE7FFDC37AC881C441F79A39F4A4161F3B403564F654B0E7D8D5415DEB9A6E11F845314421CC59C6A90826974B4CC477C280ADF4FBEB368BD848AF7F91D12E9BF4AD3E9587DCD7A280DEE9A7F2B6F2D2EBFF7EC9454173B748D2D90A6AA650D3BB97701EAD27D6AA1D05B817603EF1026E643C8816F183AECE863968664E01D6AC58C2A10AFB51B1A19A5B7BDBAD77D651B78C141AE70B074B9EF74BED349E58CF8A80A910F6DF8887202317BA36950F3B7EBAD45E6E940921043476B0FBC136EB397DB44445706F032FC47C454BA08DDBB8E71D1E7D9045655E1039C3C3D199EBA21596335BB04078DB6B39A4452662D282C7AC9B76D92E112B0027B711151C56A6459FFC70BFFC86941736EEF705E8DF5197B4D3AADCB31E421A90FD5179D9C3EA3EBC8FD7E9F4C29D736076723E2D4146EC325CFD616F6B0B70AE0DE179FA8F33A2536DBCAFAA2BC0A9740BBF41134655EA16438BAA5F8FC96256A6F9999CB1C57B69087C0612FEF4E6CF0BE5D1FB77258AF418EE0B90E8AF3DC38B7A15FF6B8D2BB739FE7D0099AA4694781E581A8F7A49BFCD102B7880E97B89880FC41D0890C33481B01D9BA991BD41B8D6501D34E0A401474CF89D089F3F6A189ED80C3006515CEB7F9DEA85D0766D2989B88280FD46F7BDC7C32C2294B2A1FD435102C2D92E85A03775CAF11D05F2367B57F651C7586FCD32FE920B1B94EB431AD2497E75F4E3C408A0FEF89907C6C830FA14402B1103DA4607F3DFAD625AEBC235D2392954B8D3BAE8A6D02CAE6D12EFC73EB46EC56E13D2729787CBB5C64910347AEE384972A5716B5DEDB99FCDDD5660E9453900DC1AF1B76D151C00E8E4BAD38E84830EDE92CC3099861C92BDBB59D8DE31AD9F4B889D480FC8DC70382E8494E1A25D2140740A5F327D51D0D3CA4259F1CF5DA3474FE28270C9B4E7F8A714F7C69D1F65B48D7C9C69A39CC58E2C77D7A750CC0B0E5D54B2F3450B66994DB524F15AF77CEBACD3CC611B2C95F6C93EDFEB652A70748DF1788E6FA2D45AF171C1AB59B0B2A160C075AA4A92272BC0F22631A24EC94C5D38664B08B46DC96B448C351C77F81051881055ACE0F364C80372EEE5BE7C660C7406B03C8F5345A04", - "435EA61E7DE31409D04501BDF0CFA57A84C1387E0684538E8BB651C7CF4EFD6113EAF9383BFEFDEE4C702FD5A070FAA3DC7D644CB3D96C8FF65F18C88C43A2E66EB78FDD1EA91E9CB519CDA9EE1806F0F10653F3AACE782810776AF25C9CE1C580C381D00B95CB02AF3F9892B4D918FEEBB01E7E730079266C4FF0AF0EC305D3A168197158B5A0D4B1C1FBE4FCFBA947A5CD2E5324D0C4182069C6F328465EC2900B468E145C0F41D724D65547808BED468256EEBD76431E715A4ADAC80D5314ECDD03177AD9175EEA9D9149128DE8715534A648069F5EB9ADDE486029C69C81B1ACECE89FC468887962AE2C063C5EC7B594D88E56F2F3FA4A20963F3BC730E74923BC2DCAED6EF38412E9094326930D2D2E3A0FFAB2217E9059A88882E2AFD3E62FA4DFCB5B084D0CE53655539BD0931BC063CBD4E660A0B1BD9C7D6CF2836C947CEF2C07B859686424B57FFDD0DB6C34DEF824D835918505F36755C298A09F935A2F95328248B5E923E55AA4C91BBB0733E4940A34AF5226C21EEE9B0E0C3D15397A4D8C069B94C2C38F61FEA2077AEBC1F7C5E0875B9A7F2041BAEACE95807EE05A366016B6E0FA2E7E722BA34D3654DFECEE78DCAE199BB44E164E61729CC7A924CA6C7A6C061C6DA0936B4C70A02223EDA01D7B8C0D2E012F998C3B94D1387B6CC65DDA36360ED765F0A23EA562626E12145EB2FAC0F49BB0DD7D1ED3E9B2860DE1C54FEE8D60EF56D4382497C36181E864F92A95E76CC516E2E1396E2B0D880ED6CD14D2410C9BCA159F57DC9B763ED7CAB73F9EA5D42F4BEF91977C114900CB0F249B10DE8F4FBE220181D4FDB5D836AD2FB70F06869DD7F197F121FF748ADD6DF6C48ED9910F51BD7528DB60FC5A42CC0B72DCA6FA66B617F12FB2A9530247B1709DFA7729A6C9FF5B13D073FD7165033C45B5B7C7C66045D1735979132C49CA4442986760CF8F0FDEC0C0BD5E992641075C76168B8316057A993F513536FC917BFB783C28B2D4878D120889945FEBAB84BFE4840C61012043E96910A374CE33B45F461B5492E2F96F0EF91E42D7DC755F37117852C4FA99B106F5CB5C70BE5055ECEA5DF90B517B08252DAD6F20013FAD50F47A1682CEB37AA0DB64E4B699E126CEA7034969FC5468D19455A1F2BA4011AE5CFFC2544329E268326345C9970756F8712E7793301E9D3C92787FD10B7637F5511E27A16B8DDC21C116F13B0F27FA2E5B6DE60837F011937A986C00A4D9551D37E994DCA480493DCD5C4DE6F40D0E25349284131B9E0B3B6B9BEF6B9DB6DDBED89CA329D9F3B032E2C05BA9999CB02D7896258E3C4504643DBF49A155F96A69148A51F243CFCC3B2BEA7E8BD534308E752C675CF478A231CA99C2EE402EB5DD5BE2AF5F4FAAC783141BE8D2A3BA44156A3D1EE98763108B9EF4670B25569DFF3568FE0E183938FB150FB79F7F28D51C8CE40089C06D6A09F25845B50E64AD231B367C280883CB7FFCDD5E4C044BAFE6C0915A0C52BB14876088267EB84A01B9931C03DC799995B6969E65CCEC63697F1F0E146B75EB6987550C23DF2793FBA8F04D019C31AF4AA747F3BCF00D6FC86CAA707F1F27DCBE598B18ADD6BA048B2B174FFFCD20F93DD2F8E860885A15CBC2F06CB10537C205E143ADDAD33CE8CE5E6EB22C6A917172BF962080290AD6FB88A91C7B63B64047BBCB60309C01F15271CAAA73AD93DCF99400BEE17F6F771AFD156CF28B788586A18C21739AE5BFDF8F6B8FC94A9CF1EAB0399F9FB53FE70FE5E4278AB909B2A00F5A181F67CA7F7E046209A2394C5583CEF4", - "C1A7D5578EE6929147D34AB5B29B97864F46686736A0966EE7298963AE27040F4598E0AEA235B562DE84BB1943891101155AFF6D185D9F66E5F9DD037B048914D7C1B55505455D08DB2E0C58716AA4C4E779EB7348D486F445CB8BF499DA3054F087ED95C2561770335DBA67F1EDEAC600071AB5918ABEAD7E55C5C6E609896ACE2426C47941C1FBDBC4804D8FF4C9290E8ED35C967D65837D6E2B153A3DD843712AA34BE1FD7CE0D829B04DDAF036D9D16063E28F627491C1C37018FBD1EA3D33899BEDE421C1910C2957C13B8CC4B8A06C8D3B2264E8E1B8FB5811622A9986B4B6F673994F6F5FA072ED8A8564C2AD450CF801C9992779F292994A98800AB12A9EF07F777F441F19FED6314404A9949218B2ED4E239EE677D8D1425D0547CBA99C1333FCB1620A8D11DA5CEFC51DEF5B3C4862E17A6BE3C194F88B7BBCED98325D638877757ACD448C0A970D63603B58E3F4B8A361D36EFCB6AAFF2858E14B1830F0FFFC4C5CB08BFC21FB091045B9A7F8DC0FAA02A62D1FDF7178B5DC90D2111A64CFAB0D83680196B21D75EB91A5B3E2568C7E8A6EDC65048C88EB34F6494CB697E44F895012AFCD7AA86DF341CB9C63A7EEE8E5F95E3D60213BC23C5A83CFFAD4225BC731F07B34FCA550DE26E0D6DA29F03A1D9C4233D9A0633D31AC5F55A11C1208C8B85306CAD41EDDE3FF5EC3A61194E724EE2D6A4C94FCDA217BD7C7FB328A9CEA8064D94FC66049B56AA1DB9F977216AB4242D0EFA59AD18540F1430A6F4EBEC5CA7EA81EE4BFC6E77F9EB6352B71275D450843304F073AA82D77EE5602B43DB62B9A733320A67B2727B21B705B86D5DC1459B5EB688D37236FD37A7163E78E8425C589DC600609DF3E9F36F9094D06C60731527B8ADF58A95E40C1390FF657D418D675F528B3B665FB5F3C56504DF40C1D3EAB6F3CB85F5C7954587F87744775382517B4C652B4259571A8AD219A6517E2D6D3212AC1684404DE7CF71478BEF7819DA24B09A11DDAD5717CC63995BF83DDA735C3A50F6B164F26D6A79E3B20A1488DE2AB44347694DB8EDD3D957B6B5510C4A266E514164D23F1594D84487757EE6F4353BD06CA7F90912AAF5188F217FCC11A62198E2DB04A016D36A583891D346C0D84241027DDE80090356ADEE1AAFE7CCDFF983FD7F8827BE286280BE118FD9FCAB26A10D19BCC63A9AD9D202036193CDA36321A5FA7252D0E65FC0D8E588D70C3B629D830CD1DE2798309A6B6113FC2A16B341BCA4271B5994ED767F2064FCA7DA335BD1D6B21F54CFA0DDCD47E2A38CA924DF85D2DA869F6DEA8FDDDBD20728A21034355728DDB4287FF0EB5A9DC113A71F7C69899EE76BE7D186B39C7C868E78C03E923FF199246908FEB48AE45261B3F7A8D6E4FD0C280545A9E3A578916364196E483F57EC37439B0FC9FC37C5CF56E21A5CAE0B70D25B928EEEE456F19821DBB974781C646E860EB3DDA8EF8577CB0E3B9E96245E14CF4E51A5D11F7AD9A77B932467808FF55E588455F810CD50367DB1621469AEE8BA6FCD52C75BB027521C530A918F9D646C69EF8DEA1F7B14354815F11E0187F01F677E2A0FBF78ECA2B1E51E898E26CE55693ABC8812F4CB4C10B9BBDF385C6AF0B340DF8DD2E957D877DC1AEC30D4A6195F40F09B4CF4010E810C764EBB57891652C156DD20584E427902DBE82AAA3CFA728059D31C36253649FDC00CCD29517AF2FFF4F5050B0FCBB73B2888C989761A7F0551375E4D3C54E0C9F8A4679E640A73476BCC6587195A82CF5E6F550B0A85D57A97E3E5D0B9A194EEC3E41C0", - "F0E94A299789538824A90801AE02D93A78EA914B9A8F10FEA2D2A7D0812009C732665D48F6DD58CEE4CFC72513CBADCFE171F837E79B8776B392B2224C02766D0468E513D0BD1BFE6ADD6C04374604503A3EC8539CC707110D18FCDC8E000EC1A3DD03F7008D37C1FA02E419FD4FC7A6C81157E07E353F3C4882C2AEF4A0CCE1F7A5CB5EC753528152C521A2ACF7548F19862EC31D8783BEF406EB7F756E41CAC3FBAEB9A901F9268E78E06ED5D6CB19BF4606C9DB660C03A9D5B06BC235DD7936ADD74268577256F72C7F36CFD7D4D09D3726F1908BB3277AFA69C7166EA2F4CC9387B13AAA8131D9F21A5D97C13C7DABEBCE61D72556466093EE0F87E9EAA9CB42245E1BF55157013C4350F38596CD26D2819F98698CE98F5D4023BDB3C974B0E61FC6E6604CB1707BB22FF5689F3DB3AD4831BFFD3F93C702E0DDBEBCAF626FC2655447134570B7150E030A3524A6979579296CEE062D18CFAFFC4474490DA81268B27B60E9E9BAC2A9B7D2E2377A2006AA5C439C263E8F9EE360B42E217646F7C44EBBA6D9E3B98AD20B1BF7CB8CDFC62CA7AB139BC2DD1C85A837F51AC9BF08B3F36CEF176A03F358E2E37EB5DECD0DD2D544E58D203910613EB14744E914F92C5E9274FAB025CB6D8AF16EE03FC86AE3947F7A30FD8C1EA23EC7EDAED4054174E4E6DE048C563B1832F8839927ED3EA54B19BA41CC144C8D8A6D8FB66032BA6F4E16DC81C98D37129B3458C2F2A6517694FD8816E8C71E00D77189768C423702612D9863FC2DC1C4593809C74D0AA881DD7477BC584376DC6C177347EE17F3E17B524D0DFB315196035FE6AEE83675494E23BF2433310D4C72E84DC82BDCA9B791D5BFD620212172AB2562B5C36DCA28C5CB8078CF41F2BDFAEE651B04243326DCE0C51ED88699CFAE4DA3B478DBDB92DCFC8D2EDC4472691173B6C5B9E5E116C30DFFDCE7B0381E8E1013CB392056E3BC7442B2A2EBB631ACB65DE639B3CFD8EF3918531480A35314F3F23F9AA6CA41A9B8F6D08F6C589DD2584B6B8285230808EDBCBB99C0E918D4E73AE7B397328502F2D47078CA2FC0BBACBFC9D9E491EFA2A2DBD69D82E0D829F74D5ADEF4100E6195CF3D7AAD2041078AACAB8A8EA62FA42C6AAB6203D92794F77D4E30B84BD16518A9A0BD0AE4B372A537BEDE43B31A6FC1A58F9B43AABD485C55E630FFF8A4359DCD52552B8A090DFD5CEFD972551714E5F0A2A16442345B33DD9D232AC8431EBFBCC5D5165D12961D1E954D01C0379B5489AC0DC0357667325AA864D44269799DB710BC6A25D90AE8E0C9368BE911C91D68A49815850B4B29708BAD74B4BF3590E6488655622DAF3A7B52356C804487133223337679B33E583B622EF873962E8FE259DA8F5DF61748B6799A14ECC763A1B54542D67E57BB73E411AC023907E54BA0EA8B7F20E55739BEBD7F83E408238B73249CE69FD2DD593565141FDAF12BFAD3A43670935354ADA4067DF0AE4150AF306AAD3071EC4DC0AEDE6F568DCDDBABEC98E4D17AA99F8E881600D35B25CDBDBE5DE184180A9C35EE8B42F6890E068700F06E4829A742FFEBBB214D17BA925B5C0B41244DB5BC7AF49D9A24B2C135131E553CEDB2CF4E6E2EAB840AB37788323024123853A19CC04F6E344A175A4BF1A16776B7F84A17501DE4A594BC515E788FD0AA08ED4BA3602838A6D1D485B1CB80BD24D97905A9A7E2DE71A9A4CA32689C46AA9EE52A9EA985C85C9289ED1577B577C444FC73FD1BC3DE03F9FEFC10E6A17553A7E3FEA6D57AB71E2379C9C5F8904EC43E57D5FB119CDC", - "A8C2390D6C3F0B9D01B9794A4207DE3F62F00A4D1188C727B2910153D9BC6337AA46D2D79D09DB7656C0B28654F1FBAC5C3DAA8A75B16BEB5FAD8A256E38EFD232E007A741028319EBA4A6DBD0AE1C1F8989246476AD4090F9F4F560D0CD72815FF6AAC29C8674B1D366120EB3213300E99DF390B3169A1CE03D2A5E471B9B8DCAA957259311B97817088B486CB680047359440DD39386DC2BC24AD2AC30436A08C335199F08861F93177640074A241D9C5884EED07EF0C0FCE8CCE08BA30221150C9EDC6562344CD3E14D3735B41DE2CBFAF4DE0F6D417299FEB38146625F3C70D8872103FDC6970D9D37D1CAE92375F81B26566A78A02139CFD83415BFAA5D328674797DE51E4AD9B3B9E1F9BD18A0FCA255CA8AE7E9E192ECAE5C60E9F5D578E59F7F7074A12FA75F9388CAC0A148CE9223681A93D62A679254AC2F41CDD871BD73BBC6C4E0CC9DA67633B61BFEE815F4E15ABDF639899DE105A5F4D74CCDA3EED32219BB447EA5C6411CEDB351DD76CF11456EA762C2F300671A12DD6ED8EE9AEFB4D0BD86D0CF35AEABC9B9E7822478A6DFEBB887DA0E2D3ED4C010E5031C4332FED83480C21ECF904B65925C4CF64595F20D072C7C6AF12DD3C76C682833CC6296DBDC73DC8C979004DE4ECD749BA45D9748DA728AF757FF5422B862223146AF86AD4AC4D4F407DC2025B8166E2CD64C8E1543E046ED91AB1AA5524E88AB6851752AE5A2F02F933DB3CB7EF48775017E000386805EFEB8CDCEEBABE613A87E0C554F99DF0C8FDE49FE73DFFD48379299FFCF738EE21B9AA1AE4DCE7BAB98A356241545B6F7D186AB544F77CB61B6492BE1F02C4B77DCD5083DE4319D1A1B792961D11D552F8AFA649EB5D2AD64227524722B0CC97260A8B3B6493B00D258A570CB238D3C2511C0582DCB478F878528B8A88A5B33F9FA6C41302DD1BFAC664C692001F7F7D207A8850D6FAF22ED887589405739EA5B5B9812BAE617889A225FB2E6F9EAF77D3B3758F9ECB89637D1FB20C428AE3420C3679B834EFB0F89A389FFD72D7420F2435D118045FF7B7361FFDA0BBB6934F81AD8513A626CC25D9A5E2A5FD1C51229E2D5FF803B8983B672E92A1FD72C16520531C694F44C9C99BC3385A610239F6963E0BB66ECDF4CA29E1C175E414A5D3F9E9F495F2D03A073965643186C46EE9BDB41876A41ECDA224719F5C76AFA6E955061805F023498AAE965184ADD6F6BA1DFE0BBEFC3D1EDCD40D8F55BB518C9B45CEDC95682B24F2818795CBE5D8E504F0885863C750524D9D238E4110AEAEE095E1C545C2989BD7E0BC0BE8AB750A7D319AE69CB080DA562F7DAA7068F38B14AD7282E041835B58E2A48A340F993D10FF4F805280C183A3FB45555B8D54EC145CB7B9BEE71D7BA652FC533ACE1BC8D621F7257422B363A5AD2798FB0E6E536854F2BD25914AA0B6DBEF1E2EF71FC7890E20FBCBDAF751CCB0DD16098D96FF22961B6141257AEAECACA339750950F6895107355F04F9BB3EEAAB3A9024E4CB79B19ED7947EDE79958B669077E6BE182020536F7F234AB2332C2F2790DD96F5816AE3FB5F2CCD72C6D177845DD0CACB44128F6EE6B1C2F673A8A50842E13C8FF0087CF71B8BA0715637A40021998652FEAEAF5719ADB71EEAAFC8093E525602599278B35600C743AEB41EA78CB0427D0894158DD4ED564C4742033324C58B01C15822B97C9634FC8F320C0B103F0A904D98C9AC529FA799B30F8B2C0888E47A3BACDAAE5A3DE6DF39A693A9AB3D95E7C973C7125C0F7D8C59B37EC924D7B9737724DD92818360F2C", - "2EB63BA5756AF5865AE33947E311A5EED4A0CD056442E19888A2B8302ED8017085DD5D137A3769058F0AE0476AB202CAD822D6A781291C537120F316E90D2C3CAD13381EDBAD35505A5B7DDC41E46771F460E501B9BE17DF8D4DFFF631C365AAEBDCB7D5CFF7010BE2EBEAA0B99820E0BF3D290CF27DDACF397A5E4922EEB7D8BDFDEC96B87F8202BD409F31A200515EB6A05E25A5FA504093F1D82A83A777F5389B5C90E66C369BB654598CBF3F258E9E14DAE819837A86EA775A05EC829B4889B816154A2B7882EC7FF71BA7CDAFF873B5CA4F35011DCDED8C0CAAD101F7BDCE1CBE67E081D98EFAB71490AD12AB7BD9B4CB9331B6B04D6DA2C12311F96E01AEBBB350BBC7311E8AFC9A6F42CD541ED40E2D7BAB44BF7F1E4465CA942A0E8767A38D89D0231BB897A995627EFF71B3E4483ADDCAED084B402A3CB23D5F91872BAA49AB361281454AADA57AC838AE2B34B799A1B46595AAA02A9738019EC3644C63BFDC72F72CFC35D48D83B831E6EF397474C43CF665D64DC0376A437CC768862A92C941B9BCB8FABC6804C03BEF7BD2C5EEE4609870803A5E9BB2FBC42028C5619C3706F773426CEC39D096FAD267BF5E6C7C7510B0D1948FAC573C5716EB4D6AC6EEC492B347497B47C0D18C77E7C264E9A04A4C3DEB83B1101E40A0A8653D9495D4A7C13A5BFF3C6956E668DFA999926231811F3AE84195B65213FFB824478911230719E8EAF206DD99C7CD7D3D7661E9F39250793C1391033EA99A0E31D8CF83997ACA08C43B47240BF1E5E9D1D741CD9E6D3F5DC2043C9D3D68A2A689615D39014B75FB53B4866488C4B37B68B5DC5F9B9D6AB9AF190789CD610E939960ACF607A488964C33DF0091FA4EE86654142083F68436D9700B3B50949C0D97098D969BA25622C2EC15FBE7D7C7B78C1C49F671672971E38996C2D77A024919FC1A87BB9BFEFC951EB75326CE48D3837068F31B9592DDD8505AFF1E0E31911D1F4E311CB1B81DD8A03D68A5EC075D8ED7D69A1D595E7AAA70928DE93B979438315A4B98EABDC8B5E932257AAF79A9CCC74E6FF88C02C33217FCB3FA8DD72AFA1E549B9E5CF6099E2DABA07C91BD3BA6A9A4936556FFDAD89D5F080DD7F818EBC8ADAFB3D51D8BA7B48209AAFEAC184E1A869FC88BDF92E77C6D4B8B983F4B93A52C473F1BF27B4D7514DBA522ACA79463A0B9C2E0D9A2D47DB238AB9E2A1636B9AA825272F2B9C8D36D64614A4CCE2EF31B67682F328B46D31FAA31DF874FA15799B5D53E143C9E9127AF358BA1B43A9418FFDE00CB16D32AA137FC7A5A1CFC2070FDA112DE600F3C05BA0F50F8AE1703AA2CB64135C29FA621385C803673A4D77195B4B74E554B043FC07B106533D0B41F7D882FF3702692709A64052C4AAE51CDF8B733A92D86D507B6FF4CFF5F3BAE4D0D9F3F90AFFD774591E6E14539CAF99C833D2A1D9A12F7E9CB1CF74FCB353D11E22B8216FB91564DDA8F1D2C9865080422DF0E0D8AA47577F31A7682B54E36BC8344D5F5F725C819D3DD3A948F4E6F6C893491127267145DF1B286C18C4F3EFEF0BB61541883E413EC3EC3BBF99D83E3919501A3CD59341BDED35BC39B655D61686555CBAD7A1B033C2E326887249E6E30AB12E43793DD1B72EBE858B40ADF4400A59363BC56063115492E114688F47447132D606F2B99DB9CA4083A91E35AED045C513EAFB7A3F0040848C1DDEC0FB3C2CFF717BC4CA36C425EC3CA9BC51B3B3C1885FD8B4182AA22AD38CCF8FE3990DA75CDF5712B358BE866A6435329677CED89571C3877F9ACD0D3E66884", - "8F0A4621BCBCE418BF2A77BD47D671191216B230C276A0D081C4F79AEF839857586F9DBA52B4E35AEF22D86FBA66DAFE801C686F03342849B5C3A492280950C7F3B725DB4BD6984A6389CEC1AB86F29D653781EED847D7E69C99320F8584700E662070E9C43957F4DDAB28DD2427415FEC6F1503551D972DCF11BC4EC3B3FE745DA7F717F35832B8CE373A00AE6572D8DFBD7720E00517C50E2B634B6BC3942F9A8C035AC80161CDB45AFDD7E9C473F8EEB4F1FEE7A677E820874F03B546464939F3EFDDA157C9F478988F3ABF39BEC02B722C559CEAF997A13AF66BCC0BBB4DA7B68EB6C6E8498129A95D021B7C3A072683593C2990627FEDC52F66F3A16A8064018E6618BE5D7C63BC622DDD4A15A33EE19E4161A50EA38CF6626D5A088FBC5721F567145CCE30C66DE60CAD79D31B703B129D27627BB5AAFBD9BC7D43944B9B0D255D8F338C7CB7EC56D121C3F4E61FC0D46CB0E036262FC182E8F266741842DE923D276CED79D4A25FF7AB3D2571B1B589E01583371BC8D8196A1C991BEB90F7FE71B99EF9E100375D3E767637B2BB1FC907846C53550DC4E6C7B8AD7FFB9DBB65ACB30C9644FE9D59A74B0E81A5BA068CBAEC9D6B362BA05202260B1E86EBB67BAE2D74F60B7E1C0B510BCE4EDD8D71E342D5465A8032E87617790ADE2770D0DEB1ED26D62A863D030C781D2FB02490718A5B55D1BF6B3BD1E3B3C163361B2F13E616FFC87C1BDAA7D7C88A331511ACE5A45CB94DBA557EC47A670BFFE839069A546FEB7183C27697A56B65AD762735782FA009350ED52819C23AEAD72A7150DE845B899669EA37B4A12D63BA7D6DFDCA495A0957BDCCEE6BE11B8B296358E92E60A2317CF4B7542CDDFBADFD18C88F5AA4984614A113E992DEAA18FA172C998EE6FC8E936E69953EDDAA3FD233182C7B986DF90386B3661C649EB0F9A7E65B90572132408929968CDC39D18020C6D81A3665639CD2A3612FB2135A6E057F0F68B10D3CC1C35DDA2600AD1C0A6FCC0C5DD0D82F6218F2C1F8F5B714C47636CF68D5361D97DD1367681116F2A2A045894A85F5FAF1BAA27F93A3B8809404181040C24156433B3B87467B27D7C3ECE44EB763D14356D6EBC7542E21863700505B8A10D4B4B6E9D2A4C2EEC9653BBC0D9FC68DCB53AE7C8B6CF3120C921B824765E7641A3E9CDDA804CF341012964EACBF55D6430673B83C12CDC53100DD8BD6B18A56B5AB68D83EA484F48D4641B94AA2816BF06EC1D1285C11AD060735509367FDD0E300413911442846DB240612C1389CD4554DC8D7D7C7E4D4B79145D4684F1FB75759E2D506F9DFE7632CC553B945D91FE0F9A829AD6A9A18817B09B986B18FECD615414A0FD6B6070B15F2484AE8B3EC3DA36D7F8007A7BE336B749104C2695327A49D34741D76752DC943897B29C9651EA3C034BC4B8E1F380A9FB0F9D2C23B627D9DD8317894AA754B8998573F025A024F43E03EE86A1EF583CE02DC7EC2BF2A8EF9A3C7743DE2E6DE38D72B5E33BC5CDFCD12184C9664EE7A3F4FBE9498F59107BF8B6DF69DBD6732AA8013FF8B4525EA9E40FF6F96FDEA2AEC03311D6E8908D426293E369D52F818233FAE1C2BA2657B38FB82E7864CE1177D5E21EBC8AB773EE928EBC4A7EE9F4A9CD2D9F15146C08E4BE0A77CE272A98AEA05A6DC18D5B856EF1B402F9851BC84DC95FCE71320D2A5540D40BEF67EE2709147EAF3C3D5BABB0B21090BA4C94CF7242982BE35925F691847A7C296B973EF2172F83AC9ED5E0A0C91AA697305F79A3FC6A8EA4E7D1DA88A81D4DDBC1F604BB0", - "896DD4C837F11BF155D4605D46411A63FECDCD64D7AAE873E1DE22DD62CC2F8982EAAA66BCAA8DE8DA687910A03200FE437BB87CD5E6D17C6F5B8CCFDA073F29183A1E12917C5D78CC1CCEC5C2B04040D39E1E74867B21192EFF2629AEEE22427EB5D2399515D892EEAD80934668BCA906109F6ED85AF29E702FE6C112992CBF851232A4C140BE6CA9C8DB383D1729B41BE939704297BCB41E4B8C7DA5B24B93FE7E7D2214287145A764D3263C9EE136457A2A270EBD03408ECB657B78CB8C0A5C1767521D75A8E12D9FCCB3CE8F6321B55C50A6102381E95C12644549A0E5AF29183316016B89F6797BD89BA8F1E932F4C91C0460F35EAE32F46D42D66F639A87C25AC6E9B9C4E475B7A4A94F10EE0C1043159CA71BA3FB4F794E766C5A7C6F7B85088CE1A2584D4A765D7888F1496ABE23ACA42FC001E2D30B3959AD7BD941916E27DA648833EC82004AA0937723CAEC0A8E7FE3C6742DF8E1CA797F13FCC4A07BA75874FDB6A66014C0EC688C5F5E0D1ACE231B32A1A14A2503155D412BDA98FBEB450D35797BDF96264D141EEAC77550408F6A63993DF3F89D1EDC90DD0885227C273546C2D86D3513AC3241AAF96C137B69970E273B73EEFBF8668B9946CBD118CD1977445F87557DA03668D4F3A6B5DE6D0088982F6C5DCF082207A99B376B155FDCBA8A5E47F2CA4A50D48DDFBE05F8C1D28A080147FE9FE04FD49C370DD9E4861D8E553A22B7DF7324C51C20F10BCFC18EB59BE931C69232419F5E037333B52FCE4A138617B08767506B793A430CB3EA0A4D9A2CCCF813625FBD2F471C39DEB2DFD0792F3374A980FA4B208185332FC68798DEA1728054F28771E0AC3FC065645B3E996EA729DC6A29CC23F872BABE6A84911B1B6C256C38C0A62331EB66E2F8B9A77ED79E323B4A96728F0ECAC851C3E9C15F2863CE6839D3752F4F206C72EF0BD60F087315E6AD3C7C836FA3C5CA6BF2B72D877E33C17EBEE283EFD62F395637E784A84A3E4EA174BB501D2CC216306673B06433A05ED052860666A3C3D7E7D7C991911A56100A31048BB81FF71110697C941CD0ADB08705A5A73CE66AA87008B08B51DABBBC3FCE66B11135844BCD8CCDF4D010D7B135AC764B678CF307154B5A96D1541B75FBA65D7A0D5C2BA2D1DA48BF0EFB9BEFB5141AA6D30A59695EF7FFAE250AB52DF0969FCC349E1C7B8D90099EF0410A861FB05E37D7156991FC65542B3495CCE223CCBD383DD4432113B817B0AC4000F9EEC55EB377CF48B0F51B8D02359449CBAAFD6AB69E3616D6A3806BF67069F2572D1AA0E7DE28042DCA01533E1C381449E22A68D901424498DEA67F0EE80FAB6FEEC56BE01950969550F01D62ADD52396E927962F209B262674D2F079D0E48D1C994864BA90CC4CCF3CEA06A5995072904CCD97313E82D3CF76F24E3B3946D11FFF45319DDFEE619D2B5D777795567A44767F12B41D84A4BF738A2C6AFC0DA08356DFAC343EF090176425CDDEBD1264871CB7AD526D9B4E469E866817A1ABC9973C598B1724C8C3185DA3C999636074C27320694F0BA758B0842D2D3EC93DA9A9CD3F65B321E378D95F003C744EBD7BCCD4712B6FBFD084D9EEF0C84C70651E3AD999D64BCFB5E8F7D9582C290CE59176072A5157B1CEBB5684D47271ED482B9FEB7FDDE78B424988E88627FB1299AB8B96CAA72239BE6930BBA4396118041D6F3CE51CEAD81DA54CFDC8BBEB0F6C8E9FAEF93E2C404D543A0F0026C291CE992CD71BCB0C6E9C459143D995C92A4A1C9A6AFD36E1CA87E1F8EEBD30EC9D209BB3F6410018", - "0245F1FF6639D3C45134190F729CD06608426830011170C357160EAF351BB00AAA61F254B939D89335881D5D15F3DAFAE92ADAB2B59DB7D3EBFF526D9A6F44E1D8DD779753433A9A32A541A798805AD307787C1832385D8B11DE57BC3ABA2A81B70AA2221C8C9247EFB3A40943D8A0677F1D4E6F9149D97D6D83173FD3D3114293D628AB97AA4CC0121E2A88BD5B5C290AE7E5EE4BCBCC1CE73017E3C58FBE575701C919ADE5E94208789CC2BCC330719F022C1F79880B1BAC4E377D486ED467BC58B13F2FF97454BF1B4F4DEFEB3B5998FFFF604EA0BCAFE859CABA133AF969827887AC252B9D21D8AEC49A0D77FC83B4D9A2930732E9A22B7B823E302E469B52537DB5341AA0979642F4505151AED71B690430AFBDB09A8454183A23F86F598719B86D1E3FCCB72DD6599C9895CF6AC28FC5B1D4A821A6F9DD9BB7AA63DCDA1678AD816D96B919E47D0D0E95756BFDDC71AE430C4F71E521701452709B6E670306A20C2F60F84D6009DF6D749C5E02D3DD5495DBCCBE9326D7D302E2A56032F4CA5C82A107E06A867D09A2E5DE7DB9C250E25B5279A4867657AACAE0E3D601DD3BE26C936BF527CA9EEBF3B247F75487A01694C7595619FE6E90AD78BEA799B0BB0C126ACF3DE54F805725CA01879BA5B8412D4FD3D3CBBB37AFA955CF90248CC521B0FBD0214A8D4C9E4A41705714C8DF5EBFBBF2FBDAB93707B0D779357E3DBBB20D5CCAE707BA7BC5D21D4C23D72AA231E83880867FFF3A6B587EDBF5485C516239028271B5462F78E3B226B057F01DE2D348C7D08108B990DE8484E839EDAA174B3CA0DD6D1338513B3D1E4ACABF9C14A9E03CB373D039645B6447D7853257F74665CE10EAF27DC1640C0AF88FF4C207994AA23EFA97D1CE707AB08E4A615C580E3AB971D64371715CF0BCB8421D8178D708E4D3DB24B2AD3143E2176B4BE37DBD8812116E134DC9B72E35E8811F7F404485ADD7321D3DFDCED23BC8209A9DAAA198307EF1BC0E204CA42D7274EBFA74C88251398D6E479D53C5C6E7528BEA5BEDC8677F6F5A81A07BF7CE58E4AC38387824300D14FFF131A54390711F95E03CA59DFECE3EA4696643A16874F98B76F6D280F7328AFADC455C51712BA748D33741998838D33F65F0166BD4D9788B129CF7F9F0802758631E5A718A5058C63B0D38D9E6877778FB8CD8BB7AF099ED442C52DDE7D3C0746BBCB8595C35C815E80C71E98425FDC629C7F8084BA2556CEC31E707408BA6FD7A2F0AB83286A93E565FDAA34B7344474EF48FE5C99017887C8086AE4C8916914142151550B0222C5FF617817EF86920F1FC00B9D9E5BD95C6047731373DB142398EB7E5F1B29EFDBE41ED1E9BE725C2748EAA2F7A1471AAB6C15BC4596B6C6CEA5CB3C9F1E57179F96B3C3017C2244B179C384ACB93557170F4E0CD387D1D3428A7030B4276F8D3FD38074E9348033E3BB3B4A05B3366064C68E0B25F36C2E45FB0AD4606CF5A6B8FEAD45CD9790BF5BA1B0AEB5C67196C05D637E878F6D3108B36ED2CBC007F6BDBC7D74362085D651ECFDAE47FFB069ACCC7C55B726C0C6ADCE2760DD3509649DC58189CD7195B11245D76F64DF2D61B07E0C172313F39961BBC410E4000C7F7BCC52593AB7915D5B5B3E746CE8F15AFD2AFEA8200687BD1E0D767ED297347A1B0634A4F006033322F787FD901E7F2492E1B491D4F5B901FF12CA88B2B2B2982D7EEC9DEC4538F8E946172AC82CD468812EB9E7062AED4075AF0A587A92E9BD971637B3222CDE1A8965DE1EF2CD4A36F2B7457D27CD328016FD2D92B0560", - "EB01608B4B6324D02441F4094E82D3DC8ED644FD9D7FE96DC544276D7E02568453EBE375974990442B96B85A9DCF163A5974EE96274A6AAA9EEB0C83AF9A2E27C4A4174EE1D4A4035782AEF83774E93F67A5A7B91E7C8E05611BA6747FA9F83A788DA50C9D4EFA17BCABB0361E055CE6D07DADE204EF601AF3D1C7A54AE1011C2AD46C27FC060A27073781A221D182D4AF531D3056401D61024A29FBB0030B8340E91AE3A32468CA48183567199F34A76209F7846ACEE0B5DE327B3A381087204DBB6FF40E1463CC7BD38311DDB99FBD05BDAF3B84D9E64958F67421CFA09903400DC87E212FA320DB95DF83AD6A6E247E92151AEA0638D3755A6B409E5853E1A7FEB54FEC711D75AB9CAB21DDB34D7115174E01E9F0A3E650F852666D06A2A8E133C872FE9034BF9A61E29CC319255B09E40096B6D15809FCE4C8993A056E4133BA1FC05933B643B5D476D3987E7BD372412852D439D38600BE4A7F22BE1777CD86F70F05DF3B260B41DED95653243419C5BD9B6288697460A0FF7C0E2928D707BBA41E46D1AE11BF3751852DA1516941BF67E5C1775383A7F88CBA065BABD2235C155FC69D3C11F5658B019B089A9B3A983A2D2533BFF7694FC271597C42EF35F8AEF804E18AA37E3F42E49D23FB9171A312A562BBC9B093D92D45EB6A1A8A665257D596174E1FC44E117397AA7C4C77FC1BB176C8284DBF4558B5259FA69836B68322705CF783121E3C4513EC11B76329F1310731CEBD2CC8B7F49AE8D87BCAC07B1CEBABE872B5F83D71FD10F300F9FA30F4054C476F86EE75AC68F1F80E352D3F9753233E53F67C3917C26F4B0E8A61AC0299FEBEF95D9A46BBEC9F5C16B5EF127EA18BFA609B99B0B362036F4AE14D11BD7EC8ED2B02C8BCAEE2CFE409899E06DA304E23305DB1AC0A7746A72746C24E6D073F1FFFD3BFAEF300299C8009043FA392DE2054F237A098EA5FF0E537105F25B7D85355A44FAE707B0A3D1D6B30356CF1BD6EA3BE57B3A6147B943D1C96C4E2C871DB1AB64D9359F1F3D15F9DE5F45FE8E03269EBB9759AC78F47DA7B913F09402EE65271859D623908D464B1B5E59E4580BE30E01C553DCC79B190A809C71D8204A735350C75C3361EF3C89C07B84270502BAB82FF089793838B13B3041A17AB396C09C4BEF716329318B95C7C4779889956961F8D2200C163C86F45C1FBA0567C8615F4E815AE8CE2E05589C006B4560D66A67495C2B99E3A951500FECF953D9FA7FB5843F102FE0F82E72867A65C09318A52D4634A3FA28B032B92160CB2E7D6ED156586D071B8CB147D139212BC47774CE580E80791C14FE49DE7688B3A99E966A9F869B0A7421062F18705AD23AC238B52E6D80F43DCF2B43F66965F6075469E0E789B40687D104DDB5CE5A12C0B741EDBF1A3E57BDACC92265D592FDD63703E534B78DBE9F13CA04B9920EB740FB220E01DC176C09CA51EB905E32398E739C6A39C02043042C5FFBDC9BF959D56842DB894FC108AFCA51039A9B28D19D67127856E29FBA3812F764D31AD4E2FBA5F00A828F85087B4A5ACF24CFA79A3B60C954DCE40BA6BFAAE4466C88A60293AB46FA2FEEFA2E3B0DAF0CD72B0CF914848AE6A9BC26F6578D08E896479879D3469E0CF39E3EA6508A412853C83BD33D0B993678FA08DF14AB40F41CEF0E7A4B992DAE6F884E193B10E5136DE079BF85936D3B5A586323B08FAF8A39B24ADDC2D7E1EAE1F2F90A39F26B130F060ADED352AF085F9169C4E21093FB2256C4E17416F57D29CD37CDE3BBEC8CBAB280DB69643C86696C3A6D3517150", - "ED28B364884EDCF3082EBC5FCD11FA0B0823DBD808FA19BFCDFB42BB1BE2B73D5D1434C95DD48DF1ACDFD7DD17C741A387F18E7D78B2A9A894266167897AF1C8FED13D463B6BACDD81BCC2F3BFB17D2DFC0D43DD04FEFE39C801C8917D52BFE8D2E6F8C0C5159E0185805BF9DF91194AC97F6448B9189028D50B274848B429AD4DE45194ABC458485617B59FC5B1F1606DB20283A73F41A6B36731F6F9E978B276B33B5DEA3BF87282D21F63787BEB1F6FCD3B21004E6FA79330A3345F2C01C8CD1FE661FF9AB5B484B3260F2332FDB00216DA42D2840D3180B6521B01281E6D0F09664675531EED14A5C1794F3ED1FE634EF3D6E9D1B6F4871A45A83DB56FE2BBC52FCBC1E05FDCA884F98DEB436A9A238E086FB339E1A7AFE8E04A5110737F021C89EC5DCA1168E5CCAF92A04C950154F6209CDD01B287FC360B93E2A5661E7809FF1BDF3F71B40BA756411894B340CBAFF9E0EDC8292E7C316ADF4F3B827F1B82A406B53AAD8D2D660FD0CD2D6A6C693A73511FBBB97612A8CD3F0E177EE38D46100E64C4C540C834DD87E062DA2C6C3BE8A0BBC46D2070FB8D9E1DC396423D2BD1DD22F1F4FEE0E24F48CAD9241990B5F48A50B3B178A9C1CA71F71321226E98D1F79DD7F3CB75E0B0C16915E34A92750BE9EA173C276421CD0E54319ADB0C4E5ACB4BD599842E5028F613067083522F0D2A891BFDB190855B9BF36A7F2EC81EA89AE11A37B6B89126DA7C51A4BD0C902D0DDA55A4286E36835D2EE95EB46AE7D6B919C05D42E543D96D22CD241A8E6985A18F29184586E6A7C10D4A955D0A1983EEBEDC5A9FDE306FC366F77A25CFC10E5B8732D8F40D068224177288E9A13408F06AEC841C2E8612E6C794DE216A2B758C676022D4C0B99A4A54166CA1153F43FF66AC03F183DC30E9C83E6EC3BA33F63F262F39838E5C044625B4CB1DBEB7ED957B8F7CCCA6C63B837ED93B2C260F276175F2F95B235D4D1DC0C9014192D72CFE014094F29A0AB8F0A9BE896067D74BE5489F7ABFBD7EF442579875CB1795669991438C0B6FF13E06D5BA805DD2D0DD06731ECA45FC8CB9D7CE568921A60E68E31F31392EB82A39982BDFE8D953DE2CE0AEFFBF0243E43ED202FD6FF9E075A90684FED84A4334A8E709979FD5B60BCD60D41907D1FC5D927F9CCAFF2DE85AE1350C8EF8D68EAE38EBD0DA0D252F0B5C82E1C3EF78CADF92CC78BD990B06461BD77B78635C406B4109FE58850D2A97A6C23CAA18B9AEA535D344E41E783B767A439DE0762A23D18244E76D3219A10100264EEFCA45F19022EFEE72B856FC34E59ADF6DFC78D31C8690CECFA45321AEE33DFD40943B158BCBEA764C3579FD5A06BE297D363994E6B959338A3B48F14A3C58CDAF1D91EA1711FB39CF78F04E72B293B80847516DA41D5024CEBFCBB399393E59FC4C89BA310377AF576105CDEB4F6DA314E990B1513BE9DF738AD35B1460DA23326D2FBD86722DEA5D37CE5E34C11408C01E1881BCDA250C7FCAEBA9DF85AA08FC9503546A55F2B4D6A7D0FAB2F50CA8667C7456DF6972273B62A0DAF38BBC7D38B5B62F2F1EA8476F300D0116598725C0903B0323779E02977F33AA8C45C2933B412490EC17FFC2AB2B4130CE8FED8D34419FD15971EEA5759EEAF9F3E8FB4FBB26615B4286AB4C2AC57A6E4BC80DDB396043251DBAE26ADB03767DC9EE4ED3E0FC7D74C58175BC1F393F0CE5D16589879C6D53645B861B079B298E056E4539B2E2E70920D3A273398B4E9247771B8A23B276DA9A06945DCF343E7A4C9E7B06960A1F624A75B1B48AF0", - "CB9F5B3A549646C4555D2FBDAF2A79F9921C54C6FEA316D7713D64FD790325A87A30DEDBDF0ADE3B7BEA52A0E319A57084A79DD706228989642E78BF51B7F1246BEF6F1B8724C57B0A3633FCF4440E9D57DAEEB343283D642710266386DED8FFCFD68B32949FAC691E66FE9B8D736EBCA6F4551B39E79557154E9AF590B6F5CA1C6A0ACA82FF4B839B6F9C555CC57255F96B2C963536E48EC9B5BCBD270110EAF7C64AD9DAB53BC791CB111189117A34A74B4F23A8573A59886BF974528D17B31CA9B6A6B7EF7F923B8915B640C599D2453941CD16633383F36F9849C0165D94698D793A58A7869AAC8B4C007CB9E43D8DD100E9504B1942CEABBA733A242599D5B8C60AA42F4C8BE7F040877DA2648D083A2272A46A90D215D96DB2FF1ACA6CE24A2936C18B7A283615E8E6B729602D018174276E2ADCBC869C43879B6BD0CF22CC0601F7491862971F65D3E0BB2474549FA18964B14D9EF81429F08383F77E8880E858B3F350076B709046284A4BF500A6C7D9D694F03ADC9753852285075197FE5F30F5FEA91C7740AF38CBF5B984ED852C99FD27113F690CA7BD5CA46DCA330A7E30E7AA3AEE8CB62251DDDD62DDCC29C94D79759357FD92855279A8516ED0B07D8F2CF6509DEB6C180AFFE120B1C06A4DFB1CB76B9DF3113B08BE85A50BF76480D2FE05E75A4F77909E0D146EDF0D751A1099EB2BD019525048BA145C7E0B3FEBE21A13A41A9BACED48E1A4ED32A57FA061243EE840ECA69191B1BCDC0358A86DDC98920C45F1FD193D529C85B33E0135DCF2B81C7FEED32E07A2431755F3EF3EA685577A6884041C6600CCAEE0E4182CF54EEC1B078D74A18D8C81E0678A7D1309E494938083786C67436FE55FA955D3281F7F6C145B7C769D9019AE1B8666834B51AE95BEE2A8D606825C7609FD3F24057425B27D01573FF353771BD47902A9BBC41B2016086A3F9E366F96DA8AE3C62123DF05113980D8FDEAC5B2C828D44C69F2D1420BF8E7913E59FCB88845A7FA6A84AA296875CA6D2FA21A4FDF8E75B5CDF0E1C0D84FEE983A469FEC80F02923695640FA0858E9B91812DD4D91AF0DFD97655C7FDC60EFEB19DB5AD7D7D0A5F93FC88A2AC1205D1BB60DB2F3BCE203C802752350B5E8240B6FEF4A38D8F35AE5868498DCCF1BA047DC56D67F15E3C3807BD5638A9494DDC268378DDED39A910A6C7A59E6738DC68D1A531C7EFA68BE06AD20BAC86BC36083E45AB0A314ADAAB741C6E24A530B3E3FE318E4A1B3827057F944918664A96277528D185E821093D392012803ADB63A4DDB14983E844392542F2C5A978F1911A2720E201FBB862AE98C3CCDA720A244B5B58AE601C1ED814B0753FCE5F51E7ED797AAA98FCC833EA272D86A238524C07349F5DD0BA4A2F6281B2EC2D29EB546EF52F07B832053AA433A7E8BF81C6C9F562B603421787BCFF621A69ECA5CF07CE8512BEF945DC744AF403B9DF0FDD48AFFF264D4AAEDBD8702863B5A345A733328466B22FFEB20906543639F0F6F85F3F7DBBD28034019F4D517676C5D8C8CABD4118768B10158D83BFF569D3B71F30AB57B8337C50674E2290C950E9D48D6527E885A0F7CF580717CF467759CA0D41CD03A91B75648DFCEC5C5BDCEFC2EB2007AEF2F01651A328DE030546933C1BF88F34AF14D0C1F0F37FC8FF4E015DA5D25D4A1D52EEC44DA8E832F01BB1D9FF6D067021D4703E8F2D511E73ADCE564EB53A048864D191F21C759F0B629E0053845D7049900924832DB7831CCB80B36644BF23EC71847286C959BF54C6CF9EF075B1EB7F43898", - "576592F533BF0DC0AC52CA27BF57894E407D8A264496F2196DEA6B4706CFDB4E108E07FD18F5B2253EC3BF1914BEA0E7B8EAC0EAD4C6A3D2E0162411811F8579262AB9F3411327C320D27C7DAEC764EC5277EDFC2635ED39B0C497365B8C3633626E66D83DBFFD8E24BDBBF09A97061D7F530F69D929DEB7AB12488951D753EFF9F8C8DA17F3F4B17ABB9A1955F40A4EDE9D058E6F48BF1B5533D91B55D333CE4AE379E124CFD375D82DD97B682D80704EFA3DDE799DC6F7D5E55B72A99DF2A89159CAC16B47F297A467358EC67A2EC72A01007C47D757DFE274893BB0E141337105C46B159B08A0414A7EF8DE0806F90B5C5A9362E837191DA4573B473C6E4354E62C5667F75721370F036BD6CA025A49C15BF63A8B30AA5DA01CCF9746222F2113AF119DA4370DCE98ABEA322483C127CFC4AB990496CB53BA7D20255E63368FFDA40BB7022A1FC115B91ADE56B2711DDBBDDB9FB00C5FBE928F3121420288CC9001F865D44ABB4D78B3A1F2BF6B1B2C251AB1075A65A233C4472A460FBC76ECF191313D700F73BAE29795EF9A5FBD0DDB5E2E04DD172C85E15CB0A63EFC2A4E317C5FF01965FEB3BCC81CBADFB201C670F4C8AAEE2E7E75F1AC4E4AE0B826FA9F87B300188546E42F3F142AF19A4F91192741ACA71EBF29A6E1BB0D00A4534095A8B9885267F27DB9B676009631114A2EFF9B2D4C10111195F0C178D2634EDE70B4C0C87613CC9344BF2F62E9BCB42C4CECE15AA61A0C7915E51A5645609620695B4D0C913337DEEFD9195CC9545A8B1AFEBFE5F21BBDFA2F140A4D146ACC25B8332861C2EA55BA75086FD948BD27923BD2590C62389CFBE89498C82279258D11689613C21CA8F1788C4926EADE381C9CDB41D09563890433AC4BF9421475EE42AE5735D1CD10653713BD62299F66F793FA095B2E04EEA1CF59EFA731143D5849032DA833E1660A95117A2ED97DBF4D22FC0BEC0B5CB8EC32B63BA18B63F737F3ED775B6D91E052FCDBC0C33A6F4498082542B039A26BCB25CFB1B23088D9BAB9DB12CD18BF2AE73C78792BA9096AF766114337FBC06CD63BA8D1C0A5E5C6BBF5AEAC38D6B4EC2922B8ABC930F58CFAF2C65C43422193F4AEB436C05AE3213CD19F58CC7623886525FDB77DAF08CEDBD5D48233D63F1D6BDA7DAD15E817775DB4C9DFE754F4AEB2A94DE6F883961DF23801A645906BEEF9128F3F6C9FDB57E6D7B5EB46326C4C39F2C0694230CC28852D54281417C4D24470B9EBB625AD1D144B4889D23EC975CAB65A855CDA704128A61CC7C50C5ACFD6355570E07CE55578E4453CEF4582C368E585CE0F08BF786CDC2C0158E1A10971AB769872C52DAEA5D7C8947A2B6300815B42125A7B8773E6E8C79239D32D7AF37CB9D4E8688CEDCD71A213795B0C1BD5ADB0AA337989ED3E4E65DAA164C26946978C9468EAF74617C47EE4328C51F41418F2D35BD33D47A9A1ADBB7C4F5A968946A7A900C293C65648C3127EF62D58BA9995B19B10D931C07D67164B2E685FB840A019EF4752602DC9317714D89F6D9318256EDBAF002C40D5721525AC0D2BD2B4FC64138F0FCC5EE648E84AB6908C1AF71408D51D31F7587F1BC8E19D1C045D8921B447CFA9287AD03B4EDFC3FB85C7792CB2C479BD5A14B72EB8D3077CC511B0A7364C80C32F11CD1EDB4B3A0806BBE9D7765B091E04F46620C23DB801A46C544A935FEE00F0A07927171D37D3FDAD3DFA81C40CE60F93EB65E667FE032A79DB745EBCD7EDE57FD51B647CE25624444199EE2D9647FAAF9F43554433B25CE78098BB33CF24", - "A888113D9682BAFE58B278C036FC2EF41CF8C156C39D67C378E4E0EEBE750656D67250F8447C420E6EAEF139A11EC90B1B50CB582E5089694A4BFD843602382C022085141A7B8AA1DC5F68469A2C2AB04BBE91EBEDAFA2A19CF0538AE9D47421C3F98084073F340F0292B8946452251630987DDA49E56A79F1562C1EF57134F036A5DE932B2AF9ED5D24D28463DA55F4E7C29045DE9CFFC4372F7A6AEBDCBF35DFF2D952D90BD4650FDB3BD68F25B65A7876B65C5AFFE8B9CB06CF91B88A588136C80D9CD361AD83F25B6D1E17D161817E64CB06262AFED0417DF26B9B3C0AAB0A06B1310A7375352C46A410E167366AD768559A6DC618B416395F432C0CAAA8D10F88E9765F36B196B37EEF1F1C13C4AC08150C9E4CE45D9B1663FA317263672875E0BB5CFFAE2A132A6B431AA7099E47E7FC8349D04EFF0B84C3E8A743572C4B1EF38F760656E49FB1A4DF4E2D1F6B24090EC675D299B32FC5EBDE40BBC2B1DD44CC01D1935F1FC084749DF9713DE41365D8CC9AE5041D60967B25E16FF1941A9A7336DC2D46DF5AB88C14A4BDEF077EACFB1F08B834AAECFC75B5E3C1BBAFD3EBC73E187D862411AB97D694B2E557C47E5093FC15780805518758B4C5B548306F92B559DC58475464C6DCC18D2B3905FE5F60B4530F87716107A1A4EB40090C23527895582B02141386A726FFA11E9930B6099B22816DEEA2626E60F4B17C5E175A852A2E174D59FE8219C190D0D6C50C14A3C5215BB193FA56209CA4D14AB2DB5CEAC2B3B20CEE6DA1F798B681D2DADE8DD13674B9156E5C3C4AA09B1932CF69D62621DEEF990AD264996069B01E6F7A21F2E5996251D09FD955CCA7DAA902FA7D46E03AABD4FFC5A1A873711FBDFDEA0935C399A0178CF2516FD03746B86B5A80576A34119373EA7F059A0EDA3F0D18CF33ED63DC27C8157E0C43C537E86FD37E58EB5ABEB5524FE8E19B2298B9DF539C7C31FF0F7AE96A56FD3806B81088DC13224131998DF42066802ADC2A08AF6F69D36A7B9B518430C5532D3AEFB20BE0BD1BF4B2C968AA78331C614EE51B8E677B19A98E30756B39BB6A1AEF0E91915BC91D98E86FFE7584BA6ED8D6D51A132EBC124C056FBB9363B8610EB3D7A77A3E581C02E7D25184ECE47A688E718922E4672CA9567BBA9BAEC81CD8DE7FBB8CA04D20B51C850DA2A4AA63E87FFB27AC89D18FAC40AAFB21331AEDABFC3545333E57C73CB7D6B601B7180E4489269001A6786415F4D1ACD8EBC3CCD8E78F6577A9E107ECBA3EF5EFA242F80202C1EDAD26D9FDB8F43F70D250D899EAAC973042149B8F0BF7327D72A49222B5C403645BFDF3FBAF78F2AAC71B9FB582346CA456EC183867409C18E11A1BBFE6FF5B681B0F893778C87A9BE8A67E196919945F4F22D70FF5D85C55D23893E7EFD9D685C41B28B118EFC905C450A9E91112C5CEA2475EBD07DBEF0A125C298F467377E2BF8D4BBCCA25A2DCC4AC83AF877E1FC820D09F31888802B3226FB0129AB9E47FA65BAC527CE74BADAF59F95CAFCB6EFBDAC889EE8075CF7C71518535DA63E7BC9DC5668417123CF11DAB1070B050DEA01F46BD86E59C5B3175EC1C0C1244E0E7B5B6FB5D26979393E430C7B79893E3BF819380D206438174038764B7196DC0FD94D4A9CB8382CEED4490C43C19061D2BECABCDF386F1512EF3D635601E8E9CDECE9A452A0E6C6AE0D6BBBF3AFE226A46AB3285531C7AA9E0FCFDE0D9A557F20E9802139A7C8EC2B2872CBA3AAE87F0BC6DA226BE4AA5681B114E080A399BF7480E8583DF2505AEEE32E45C4112FC48", - "DD364986DCF106EED4C8705C1A9FDDF9480D337BE5C61AA3F661C6968AA01E3E454698FFADF366C73599B987DE85005C9743A2416E637E4BBB67FFC4D35F26B7539C33256EDBF680939CC8986F5BF32D2ECE4905A4F6A1727BE1131771954856A1C66A402FDD0DB86B51E9C02E6BB136465FC4253C8D98FED1582EF8AD22828B6A35580FD58A0038A9D97FE2F661F312658041839969752C4ED321D4EC8229C5753F399029B0BD5F065D5A19CB4548C86CCC1F3A9873FFB9E4F421D033E4EEDD4ADBAF302E24371EA97D817AA33C72708C1EDAECBDE7C06AE0C95D8237517666D0FB43B2434BC50EC2BC8DF1E3CB46099BAEB869B251E79E9B175B75FF62F408A5FCAA4F6DEC90F97B926272389696B5E38D26B946E0575907C358DB17D046D58D061683E07F1B075C10934FC4260043AAC28928DC877D27DB9BAE618910564EC3EDE3C402E86BC3981203CB7DCB9940C37D948556A57A11488D1332B05F4E5757D470A22D0B86C88DC456CE014B673CF5FEECAAF26F4662C9B243F46969025692E445ABF375AECBAE50EC9E48AD25EE1D1D0C16624CC5BCD1BEA8C8FFE3579C50B732625A381002115A1D69DAFF5844731F41AFCDE42CCF1A13FC98A64FB9769F03CA631B1C3ADA6A98F40343BFEDCD80966652292B60DE83385FFEA9CBCBFF51450C768EC8C4FF6FDF2F76FDA7D5886148168CE2BF693BE0179DE250D41DAA80553488D4DDB01FF97329E94C7DB33005B498FA8408E13FD5BBFE079F6E40EC5C8B735EBF9914B932A82441D9D5136C662294956CB52939F4F7E335A3B9749CC1B9F374AAC89C9AD1E718BC469CA21D2CA467F5DED54C402BA0CEA000DCC878822EE3E1D329CE76E421305178FDB31F5DAC177838197C5B46A4F96721139695EBBCF39F04BC1BDBEAB567E8FD812C355CF72785CDB3A6909F801BD2F448B3EA0C7F96D09DBE4EFFB1CAAF2A47FE6BB830FDB937CC5ED2B485AA6B85DA799C1266562DF181005A345C62BF94004C1B8D85AC06D114C8F2C5E2D569C709251EB929237C76E9CCFB9CB39206BE3C391FCF5E814E42AC2BE1576B9F0664B20F03BDA1F6431D1D1CD4C0783CDAA2A7AD32281A06B2BEC53EF1568840277EA4341F5570388045526AB214B477EA23023C13F4327DD0C84CD1744677091B21D8F95F38A8904EC5D6542AD6E3A68B355D688B1F6CA50DB7181272B3D564B1DE41C14575217FEE44E5B631CA49995EC2CA787EEC4533657FFDDE7370329C9BCC301B8785F7A307F1D06F88F21F5BD19F94827C128F799A9C354A021146985256B3D3E8BE46AF6E370EE193BDA3494E0FCC7AA287C3A5B93B638AAF9BAEA46288DDF690A464017765FC2F769A5A930FD3E5A5F399B2F972EC286E81062B6BA85FC04DBBBC05B9971799225E2F0867B55CBCDCDD3B85D6D56C6948B03E91080FBCE3B2C5438491050BD2E81C41D5C2F6790AB1F327D2C7023FD891F8D6E13D6F69E7AB1604692F21ECC7794F028A8306657D72B5858301F5296A5FFDCBEC4863D0503749E9B483E4760AFC05682304EB17D67E016553FE9108895DF3EA98890172D795009AB414E4539C47200C56828919DBC1AFFE040FB3319A068264607CE51D387B9291B7483CE1C38C1F059AA86B68BC7F852D21BF759A56557AF5B4E8CAD60356AE1D9D11AB49CFB9F627DFB1AF5BF8A6D85A775B66767616FEFEF6488C383F5ABAD4E06DF0B6C82BD2582B284BC1D4B27168525C69FFE8117FCC38FE758B2DF09E38DCB1688789B2AF3A050142E50787EBF2098C229E6965FE134593AE47AF7FC4", - "B59F424CE3388B73A01C7279251C7854C664803D834EBE840CF3851B922071026DC17B967F06E8467AD73F8F70440CF20178BD31F8CC315AD8B3D213029D08746BA9FC70AAFFAFE2F393D0339BBF28FC15B8581667E9B43E0A1534AB70BDE8954B30AFCD4BF10B91B8BE2AEDD6489D590E0947B6155A1E0B4E7DBB7D5DF08A340FE33DEF34330EC77E65B57FEBD4745B0A07CB8BCEF0ABA92E387E2C2F80230818DB1F70F65F872A2C5580A6C39B9EF600C797FF0C61641100903B5243D847C7243EADCB69F69D75F4B1D921C72A4B5B67D11B78F84BD9682963E075C76350BC301641E76BFAA23EFF0FDA33B1A41729AF935C09C1E5257F84A4AA0AA3A54525BDF1E3A51EDDA6A35A2C2B6DA82E5C7FC989475D99585A9DCB66325B98C20BD7550871BF66979BA3D58562C1125EFF230FDC77A3BE8A7A8CAEE2F83C62688E0EE5D72D4C858624C7362A57B7C0065670DD8776D1E97F67CDAE4110E53E78BC17793CD34F11089AF317407B5F43E26424A752DA5AD58470FB8FDC193D2B28FD4620C879BD22A24DE4EFCE4FC46D7A5A4350136F43D21698AEF1B4C318156D574E93BDEAC252675BB1F1819B651D08E637538DC14505779521CBA1C5695CE7C5F9BFA3A7E68E14ECDE399144E6D514CBEA519FFD2C677310214DF222CD79C9B9F763060C48D8FC4E02DBCF0D6396F6A28BED4ADB4F69FA44BF6F52E7516E77CAA981712F10E94DAE683DF1CD858492A6B7C1FDC92B3A8A4B121B1C8B8791E18062548BDD31DC544FD94DA7BD77A0BD18B3940760A3746ECAEFEDBB6B99562E836421F24C2F2A99F686DCF9C57E910748031521E359D21A69933D3B3173D520E7B8810035140A9F30DECF99A117B8C81990473378C58D1313E29A9824034B86D46BDF15479E8273BBFC4710958348B17C8EB8EBF8581AA9D1032AD591B7AB62B3E2DE12F36BF0ED71CB0DB342D5233243F466291DAFFD75971427F37549BC74CC8EA2C9D61C55FF4EEF46EC74F37E30AE9227F9A346A5A379A386E4706FC6DADCC80FC7CAAF6164673DF6B7505C1CF8C1A2C262F13A65CF1DA6D3CD277494735E5E0B4366804A816373AA0A33F3FB3566D9811D26380EF7E049F004E5540E3A984793553B866E364BF3ADE51ADEF86D37A9392B6D0D518C0F07F80E9BCF795C540BCF8BE8AE72C0A0A67160F296E30A0F5727391F82DF95DBF2376B82EE6DD6C87C05CA191AB8F32671C4E404734D6626DA299682D9A49788A7D961B737282CF16DBCB233124C5EF4800E1F25316763BDD92F090088218C071E91EF2D76D80BD05D23C6C06EE975279B0505CA18623A33A4D94EA882A6C0C5510986D537B49BAE93E363833A8571F91C47F022A6E05FC7673149128E3876AB6F423CA96A7F0F4D5AC1682DFC05BD4D3ED478218D40A42A894DAD908A587A83299D9CA685C4E25155760F53B27EC3F3E722E46E63BA2CA0D353C60DBF985F3E10893A0BC01539FBE6126215B090F1355D211E833BC019C7BB351B1A51E5286A178F70DB39D3A8DB65E510A0A93FD717FF30BB586B8FF49D62ABD56F0AA4B01D2A8E6A3BFEA54FF1D36C8ABA385D0974C7F29B25BF12B1036E4926F0E70E6CDC93233E211693F7B315C15594790BFF888ECE21352C8FDF906DEB1085408C877A98BC5B145BB1D0945E33409EB01E243D386492BD62847AA67D4EAEF5E8B84468F70457470C1FA15BBB44AE4D77BC401BC4128654B52B2B8CA48721DBB267EFA7F0B2ADAEF8C2BE9516A42BD2FC2C7AFB8D0D71FBB8A6D7034892078F4FE50A3B63105B31451A7910", - "FF81F6EFB1CF3169B63C2F2544105BE42B20467E1FF2E4204601A486928A77571247AD40EF058003E423521B4196118088D773BD1694CC83C02219F5E16C31BBC7350A023E4FE0720DCA713444B455DA085653B539A555F37AEE9357BF538E3EA6A2C3B2BD30EFC32665B597A611EE9DDBDA9A9857FFA648CBB75677DAB55EE8528DB18C4A188C693A9DA0D7DD736401DA333DDA13F572D4652D23F9016CE9D39605B5E2F341F487980331D88511836C7560B9F3E8DF6FF4CDB7F74459BA199E081FA49BA205B368B4D519B2D0ABF92405409EDF1DF280A04F398758E5511B6E6325CE00C57186A0938974207E0059B2B8BC81156E2FC0A76E84C5BBADF4FDFABA379E6F960DFF5DB82FA306535F0A8C4D925246DF1D9B8C7A711554E9087A5FDEDD656CAE74357FC6AAE8EA0C72B74BDA7BD4898C6FC7BC50367FEDE6D5261B0B72E171043C89C8C2149D01466B226F6A1F3F3FF378E34A3956C660F0FC8022E15EA68DE5DAC57BC370B30F9DDCA6404C5A152831230DA9EC3662DE701767953AE8DDB9918598844202DC2AB41A0ED711D640F3C60A8CC69BD8D9340A32330F9D27E7A023CC99D173BFE6CA4F0604FF6E5B4C59EC2E1BD4FAEB3321F755B2494343BB6E647210041A1B96A02B7755EFB6B482B3C7122EEF9242FD64D0D7BE24D320FD33ED0D4DF2756BDB13BBFB622E7E928676D228DC395DC32465E0E3480B7ED2EDDE04101E9C0F8020D48F3D43A0F756622A3DD866B966B7B0BFC1F40B1D460D6A54A45ECCF5AFC93DAF8541FCC62A5FDBE907D2DA6397B3F7B535DD8E30D400610971E4960859DFBD4A441F209021E9E4B05D3EA0C80A738F0C4EE9B03492692C543968122FE39BE1F2E5D682C1FB8549B12D6F32AD5938FAF63C5F490EAFCDA9D7DB70681B5650081B098D0BEC87013C70F890666AE984C5FD92F6939419AB0C1E981FF6EB03B1A48D708438A8F6AF81515D8C42E0DA5E13DC07D22A0CE018105BA075A696BAB7CAF420A65E38EA1961B61ECA43AA0085BF2BA6244EDCB56EAC6DED736712045911D7724E9DDED1C05DC7205580FDF52143C07960AFAC71528C1B87BFD9D21EA5DA5F9649AB037CEFA5713647DBA70A2D0456A24AFB0B55B8C859F9C9617E83E12C0D963397DDCA09CB16E22A47EAD91206E8F3D925444AB85D76DE73A43AA45BD3B0412FBDF254CF273E5F20F6BD0D938E30ECDF159120BFB28FEFC0FEA1DB898D5D1E674452DA86C9AD4AAAAFA07AC6A304CEAADA8AC82870313BBD56E746E7C9C183EF5B53BFB5A374B955D053D1CD7E8EE25108BBB8F2A60663375832213D1B9064C9F12CA77835ADFE28D1A5E1E65FDBA45147F052948A507180EF21052D5FBAC2B3F4E46DBC4ECC7DE08D6FB3B6162432B25EEDA07911CDF4E98A219603E19FCAA8142621F546C898181E1761AE7907F624A5D01E36612F06ACAA157BBC316E9AA7568E359803A408B0C36B4593DA1B4D4D6D1E6AC290C90D19635394E10F0BE0B51165777517AF168F38B702DB2BB43ECB3DA55D9CF9E8166D99B971137F6845653B8CFBFADB778E16A8F64BEF8DBFC6DD4F6F9093FE629C99585D59445ABC30DCAD609903A26C181FDF481642043066E5B0561F13934247D19975F136C0E0F4CD41ED3F8E22739FE2D88358CAED503D7C36FE755ED34B9EF871F2323AB593A0AA8BFDA8DD3D86304E206E5B4FAA6B905751EAAB46FB576C3AAC9387E38A02A6AF8EC72BC953C4831FED1337EA65241E4D94F90A0E99018DA735E1CD4C835AD9F301A618395C8FD4C982CB5282256F8A4894", - "CE812897E0C0F7BA13D73227DA8D57F576A25F233384DAC16B5F3AA455222CF8B1C3F0C69F6E1EA86C6BE0DF818820D7611EC41F6078EEA4461C336D02847EC3C5644B85EBA26B68C5927D67E36BD381F8100B6BA90852D529419EBC8118A5354706D2CC769C2402E517A86809687BA7E0B1940A88F0B2586484EB7D1B63E119D489A41691D0C1A88543D43D8962D17FCB8E91A6CBE2635F4D0814A8C9A4DCD7767CE7D62E8BF17117A6650E3E8933DABD4CCBA43F40ECDC46EFC541CAEF6271E87BE92E63DFB7C2E5B7D7D2ABCD56A0A19E3C9F75894860A850029ADA36F990DAAAAC5AF56B157475EB18943D7CCB8D99CD14813A27036ED1F4DE3234BE28FBA413046A26113124B5FEA24F4074E991E163AC879520669ABE6B1A0203FAD6E4082CD5ECE201A86EC87676E350021FB2A1E04AE9B19A03152F8244542B4D21B4173D05F159EDCE12BA12A5767363794DEF4D390F56208EAA7680AB527C2035B065DD58AC8182BD5660DF75511EE1E0F407F4EA72AB3FCB028C82D8FA3003B034EFF4DC1C179029C452BC4B4D75AD02CE9E393C15872F8D130AFFAAE9A95640EC68771EBE628C42DA59AE4AC2E9156534430D00164E3D2D28665BD2DE6AC1482EE3475F7E00F41078B672835B435711C560166CB4DF17B56884C8A66DCE5D4B42AE675335EF457AC20E4BE7FC32FEAAF7EF4CAD795ABA7F9A20C6703E7DADA30B63CD6CC214114242C81A9614712271CC05867595D9938ED557007713F36D1A44AD2285A564C9B242AF6BE9979F7C474385680FD574D9D33B8E2DBC1318EA71977FF83E8977B93BE3EAB2401A136E021DA182B1AE68007FB36067507FF6900AFC4743A9A8503B7A2CEE04A1BDBE9D661691E5E8C6E5568D16F70C15D156F45DC41199A9C67FAAA36D8CF67672717ED0124E996CE855392F5A8BD24EBCD644AE0CD5B1AD2711200130AA4F8D3B4599AE660A56EB6E192709CFB8890510CFB0195D7FE794B9EDBCCB25ABE6F3B6AAECF3FCAB9ADD6D270D3D5B934C46C8D6800CFCF99617AAB8192C28AB627EB0D6234F7C68F0F4241662A9F062B361FE89E92BF9254F823E4164AE54661C2991A56C4AF8884DEDCB20EAA02D3097F2D5BC45FAD616F2DE3F37FE2DA9CAC838ECB3BF649AB6CCC38675126381561D546B37C743241297476497184A861ED1FCC75BD508915AF39752866B39F1BF00799F3B254C6710D15F5F79E29766E3EB75B93CEEAD0F3D454A3A0A4B9B88534AA91B604424CA1F9801F7F16E0A5489CEA18CCF76537CE33481328C83F3205B59AB1BAC1467C56A28DA696DF2B08CD380049C5E0FABC6AC8C5C50F9481161C1D60B0976FF459B2C11679DF8239AF63C1379997A8CDD47954DA1A9ED1606A3D1D2700A2B9B0C9FEED839E011D52752CE543ED224E5241340CFE1219A1A0117E033F48B262A6C83FB13BAEBF036C2ADD4ACC5D1CD9C5C334F4EE7D964851D9A5B7CF5A38B3C1CCD6DFDB5D1AE3FEAEDFEB72A25C7CA779DC4602FA0E6D8C4B35900F634130D48BDB8291B7BA751256EF38FD6FF0D5662C1691B825714442F5B633B30514058C778C78BBD6A70A2096CC9A375AA99CE11E8FE4388ED8D403EFDA3E604EA77820D4D7A1FE7C51B73F286520D56DF828B659FC636DE3DEC09FFBEC46FC143D943A09634A91194D77F0A70DAED26ABD3F6B51457EEC61F9AB544F544B21A1284F0E70D75DAED0B9D0FD864CC73236CB64EFC7C696882B1B408B6B02F35EFC4B5DCAAFC600330C59B1338DC593BC22C86A1C4F16D72E7BD622A3561F60362F3612580", - "DCD55CF8406A7CC9BA0A5224797D74777689C4FBC0D202DEA8B9773A0F20DB0438BEFD40A996EB2E3F49CBE2E475DEEF73F112FF742269A701AB43D8E47EF94DA4056086D86B1FAD636D89929C60238133A5B61DC4B7F8DFC765CF0C8C7206F3E0DD3DA13407CA75EA20F172AC38C42ACADC946B3B18BBB30DF871905777CFE0D3BE5363574D2545D0214D6A43E2D34B50D7FF7D9F2DAE7053736B71FAAECFC2C355C1DA645A995981E1D617BDDD14EB9AB230D10085DA1AE55D1C9E55C225997D128CC2393D6E5BE9F1BDE1543DCAE918B38AFD5FAE6031E105BA12EA4162F7E24572688C54291A61635C9DA26BB367348473D4DD4AEF9A5C4E8A6512AB149D62F625D8D45576FAA4CE28E5C3D52D293A0D5C48821E1F5CDAD7257C97B3C1A6DD83A4ABB55F780D09964D4B3940D36B6709D00094B89F319E1C2CBBB3EC33A6F0398880B8079E6A39DE697D76803B04C230EE980765604929D60733BBB6382B4CA4B13AD3FC48AC9F944B97133C5AE6C3B9D295A760D786DDBFF346C873C2DCF3D2591926116A318F63835783A33A17C452AA6C620284BA99DEAF023972082AD2B370CF3016F0739103A518B25AE8D59BB017C8199ECCAF3E908F9F144C778E0F5F47FA06FE8A22E3B2CE3493EAA8745478D653F8D3711F832D9212D060A7F0B0B62AB9A3C9BF012B61A9B5E6DBAF4B48D9031250419627E96076925AF95E2B238E8CD227A0F3D8C9C3BC68D5990952D6CB62803B8D193FB06120BCA9B195E92B995B86B92C455A6145D3F77898E457E1B938183E1D76FF61C163057A4D70697507BE020CC28BE6527CE306A5D2506B86152B5E3B954D5A660C79CDAABB2EEF0D135C0D4AACC7FC3EB5A3575D95070B168FCEF4F9B36FC3D55B84DDBEF10DF6BA659F70CB2AB82FA001D51ED0F040F9DAD4129C324BE8B44316C0E3E15B27C2A8D54A948585834C2DBD40337B61F58F3AB99B3303D56EC1D30ED82F29CF6A68208B07DA120AC4073F102F4D796E38628D344384551810998F6211A082BA225A1B7D63C9A3E8703DD945BE1D979677FEBE715396988A873B88EBCB10209E4DAFF939776AD14C5DC90BBE9C1A57581A145BE0D4BB47CF50721EFECCB50C96E824DF93D675B1A1B4D920CB1EE82B0369094DD84FAB4A3FA94F152F87525ED6D17A800EDB1BAA6C13A2EDB5C9B7C5A82AE5824AE9BA63156EDF78517AE2B357C1A1E8EF6CB12DA415A914FB69FA633527B8A1659292D079B580DEC210231BCA77465BC6A9516F2917226957DDDD9787313FA599BC2BDD14DEC9DCAF0F2520318A85C55DF40881FF65E4AC21F2C9EA3CC06651309E1F89982D45FD6EB5BD588B647A80D27433EF85080A7AB2FFDBFC7D2B54B215E7D27A333D4942CD23D53142F04976093CC0344C19F9CB3A5A4D522E26B7E2C1C85C1ABAE1B4A360945A46D097A1F3676A80E3BB9CBED0BD363CB70C2B250EA053B183CFD1EDF2F6A211CE618F70EA1AB535E96CDD0B2FAB7CB7F0396B6DEB59745C1BDBCD452FFD70C95E45B88325A82CF07EFEAD7176FAF04C8C3E0CC4458540BED99ABB9F52AFBE48E42C636DD076A37C07C8E4EB6830FAC011936EC047F6D5B5857AAF90F80B5D33B502A116828BD27E30B3A69F351E22D943A482BC6BC41BE7BF941F3AA7BF85A2BA5C38FC930680FDE5A4E174AEC4156A755E7650CE488620D6CC62BF9D085FE1782EADB11541A5C19C9061734513316B9CA608A6E48D333A110B57BA5128E9331E6266174B85F7B7D1DB264361B1C6C044A8274A7C8DB19C253BF8DAB819E85130E920", - "79E4509D63EC15D4930F17DB3EF8E9ADCDE82C9F2308A0C9F77359575876D90A9CE5ABBBFFE09B8E145F35C7E91B141F66F74B3BA923D9ECF863A8A455086DAADC247872C953476A85772079783A6F37C964AB1788479175F7B4E9651C7DD5EDA94F8BCFA57B3542788FE9547E0A444D249976333F99710930CED2E93B1526A02BFCCCE416F0CFAA631B878BF23E41F95770315F1E169EF22B9DAF0E2F269E06B03B125CC6F20D2AA9A13B98CE23FE3A7FBC70CD05496ABD89ABA5BF58FBD8D88EB9653963F0452CA43CB964F7B145020D637905E8D26E8CCCE4EF892BC48381303161644FCAA1DB9C4775E8F0A6367F1A842C3101C9F94730F6724257F2EE1657CC93950C9C1F20832DCC11E0001AB347781F21DDCD4786234C908772B553D7BDF4795FE69D7D55E950D4C6E2A76C44995CCA5C9CD539ED235CC55DF6A004C1BCA852C2813DD17F333CF67711EB8A5DA439D73271272D0D62B34DD457C7412A26FE2F4F23E5F5AE8C2F91DDF86B7048A40872AB7C728B20DF7AE2A0E8E52B00899C565E68390DFC83344DBEB7257CF8031664FD93DB65738013BA234035F11B611DEA4F74B1000724B2682EDA9639C11F4F4580683DDCA2D9159F637976293FDF76AE2AC7EB5203766009577DF87D9DB654ACD64229495A5B4A94AB3AD8237B9CFA2B5AB6B7239A5146C777C4A3CCA9E1573D96A7C1B333F11D284AEB55DBABE6B4F12A421FF7BD442AB6B8A7FC33A2087886328B33037EA78D9A7015ADA2C8F463AC1FEA8FF3EA886823063992176C31152573C10516BE386CDF81A6568D8E3BA2FF195B23903C95B16277BD60D238F309A7DD6BDB4ACF4541A56DF5D3D4BA4078E58641C0453B1BC8DAAF6F1DB28836D6FBA3474D69870E07997DF4541BDA5C62291A3360F5C5840752A25CFE366186F7E4E21DA0704266B5C14ADC1541E463917D5DA677945574F800BF47FA028E82200F9E53C48C887355D9E3CE5FB778341A356423D00B18D3048C92A80279C2785AECAE9EA57F828766D6F953AACF93FBE8A4C32C7FC9843F466141DD018CBD05ED8A16E27B43C5C0EE16045D39CDCC7E4A27EF636408E968B4C99C895CE77288C819701EE7184DFCE889328E4CD2D8BA7BE5A1DAE50E36D562BF2441B56242EF9C4EE63022F88F0F77E6094AD7DA93F672C06B6BF4ED5523D1DBE7D8F13892BF90DFFD5D2A3BD0E9B56EEF03E560BB28650D873116C0CDD00148C90CFCECB6BE9C4BDD7603B5CE9FC458431C00B1D704702B552D847D0C89265D842FF6599A150854848B730AB33CCF2BA6533638860BA564540C6678061CD97BE3D00B103314894AF13999FCBDECAFB5A895671DD1ECDD95C0C94A250B014CBB657ABE3028C8D6CE436FAD8FB7BDD12AA2DA32FA6435889F1B8C16EA8488FD6AFDC7AFBF5358A31B23E0C05E315B60F180986BA17E26621D92CB639A0B815E65D140BA8A68F99BD42A2F428345AD3037274E515684EEEF018BA41A7B0138D7FF2C0B838823192FDEED577028052EE73D65E92812E4C33FA3CDC11234F47F702AD81F3829ACF1910B9D00167A3541372DB79996FC8F4B15F2A56B272B7DCBC4B074A36543B12B3A5396B0635068B62F81A56E33B40516A376D4ECF7BEA4F8ADBEAEACBDBE23F5F311A39D90D0B11BCAD30609F6CB4A657CC620CF8F727E30F77618E5870F72EDA78EB89399236F7F5432560049262E29A2979F832F2B57CEB25BBC2405A3098CBCD3CA0CDF631B37440A47D316F4860597AF78E5ACEA13E8B8B5420210D7BF54B1F07A433E7A2B193D7EEFDB2288", - "B63460020483CDBB47DB98D8D720FAD57072D41EDB5FF2A2CF65DFB70ABF3524003842F7BCF9D36F8E187F86B864C5FE0181E5E3D33AE11A50E67F56DE93387F5CA7D1641CED92F7195F2ABCC7B32C6C7BD8AE561E36A6359BA6171726A2F9B00C7655C7E346310C6EBE10D2D470BD5BB7B4C88378DBE2352AA45EDD728F42A3DF3B5E80BB6B6BF55CD663203437F575F769CACE66809FD25933204387F8C51E0A6B2C4C6113DD45D31AD7567C9B924D5B10F124F6C1CAF3458B3B84E9E42DBA9AC879E2D711ED8681207374CCD299FDB7D7004678D56FFFE0CD34B4858CC0CF4F611D8EB5B47768D69AA69BB1875E9C397EE9453D37D4983359393A02941E772F912708085F2FC7211DB358EA5D4E00263E14A1CA3430A6E6FBCBA94CBC8281C356B4114B0E0B67B3265D3E1B9A64B1D4BA5501CC0F6E19F56A7B3B1BDEFD8018340ADF7640C58FB26ACE46B788FCA44BF228A737B02F160B0462846DBED0792B27FC6B55757BE01FEAD3655FA9E992485E2B29321816B04C2BF079BA5CD01CD7DC0CC8CFA471FAEC74C95041B7C62DC9BDFD11FBD4D3B7173A3A92044C793EDB6AF4DCF760D38D3D412B3B292C74E08EF4B4515B99A0D4A167D9103C3E776E213AC2C1614B432A8A7D243B0EB5E7AE82118DE996BB55329F49ED4A7EE738350B565F50CCC313DF274EA203757B372D542D451DB960DD8D7F0C5E532AFBA105C7963A39426732E2E30C68317C4CBB3C10802C5104923E9EAEC89C6F421B8EA3D5039D5175F1EA854971407C7B260BF57FA912DF3829BA91BEFC9A7A88E5A289366A88E7E6C5C4D4781D583CC15C827A4FC753F66C81B5095D51F3069AF2E3BCBF01362F118690C35D3E6B5C0F41F4A4964226E4646DBD948FE2D1AE837C0C0062F77A40DD02371EA4B69BFD02803AC3AB972CF450F59FFDE724F79DDB7D534D261A44DC4BED2A47E78289BEE615218D1F861896AE5B07729568508B0E35F82BAD9387B52E2243E456C2DAC3F82176E4859A8288FB8E2B86FFF4BEEF93D9F677CCACA1E760D045F28C819A44F5F678E61585B74D49B1F12A9B28D4056CEFB98845385FCA12A6AB0C86DAB01C7E8BF5D77618F797288706F18DD71B33F909CDB15A63047D0EC462BCC02AA7E6D4D4D5C3D0C5FA2C03502EC51D781E8CDBB63A2578CDD9116701F7840D6A268DB082223F3D42376C5D796557BDC568791BB3A5BB6A9F501837CAF0ABEFBCBB500868EBE0FA0184ABFB927A414A87BC3A1903DDFBAC369B77B5C9FA203C7F6CBAA7BA826867CBD37AFD20E32DBCDCBBE7C12E3974BA0133B9ACE768AD4652C3FFB01D7E2F4EA026D543B2292419B10DB09C47C110005D667EED5D066D4634175B58F4BEA53CC39F2D1A9623B7C9AF2ED29A37891F2BE24418746A233743BD340256801EE39E7C05932AA41B56F7DF4E479A365BA224E94D72A395741D3D8135208C96AF089FE2FAB29B9D7DDB02D149275727E12A2358F4CAF9DEF137397AAB54DF78F5CEB17CA323B696C3267A4D2A944C65B2E8F542A2F0AC3DA7A9D6F2AF073FDED7424942B700AABA291FB8672DF10AFDD154218C0B0088E84486EDA5F21615C06770A2607E93A2ABA60B864505434ACC6B6BB15BD00C3881E59F0B481653BE10929E7EAF4A90BC181DF76434C08F3ED37D862038232AE6A5C56F36F98574029AF4B4A280693551082BEE4CB6DD4B55E00AC4954F2A01129861DD2A70FC30FCD9073FD2F45B31CEF9724E673032D0C87B2A9FE7706040293B6DFC3A3197AA58A53997BE5A2A763B027D5E14152774E3FFB8", - "6D562B96C4DB6F8783C945E358693B3D99B7D8E77AD50B7FE9F5176AF257ACF63E037ECE9FC071CBA13080A08E1116AE09151BED458CD8BC9DFFE5744E0CD2365293B365A01D30E894F8616AFDB6115663FA15522C8CFED9E6644DAA1AE776E0BB2912CF584AD1DB53E90043B1F93D67D51B1B10179F0FED6EEB52A127BE857341CB5A223864C02E4AE3F3902C90BACAFBDE2A42D73DBE88577F871D9C2EB9885C7CEF0443EE4A1C449951B24764CCBE716487F2EBE474ED6DAA65E393F1AE17E52B75EAFC245A161AA30CC8250631DEDD2B233D202CDFD1C3DB64FEEB2F515F2568DD7C11DDCCFCDD77B9D1182A29AD5813791DD9987BA735082F8A669F38DDD84EE7C09334AC732849119D769DB8CD79375D1C8EB4E051777A057A4738FC4E06ABC70F8FBA6B52948F91FAC2F2E248F0C417E2E727C60872F905DB2CCDCF15B2363696424BA5B62E98D5E4B51ADAF38DC97144CA32BB6DF129EAB07313059C725051883475E30B25C8CEDC63BB517319ACDC1E0ED86D5BC5790F11CD2F4B2CD882345706A4CA5863C0395C3159AC3D7FF8F7B5F7B59907CCFAA53EDE296087B04FFDDB0B221B3DCD1A6C64A591729A039C230CA52C94ED2C3118794876F7478E7968F962004F01E8FD0546207A64C09A2292376F77D7789CE2CF04995C7EFDEC91B5F13EFF915E9158F6202D6A7B0B97BB1FB121FF99AB12F56732E9049A2C33597A308A47FBEEE3F530E357BA6B7C98D58114D89C0E9599C6B17BF409B3B63FCF67DE29FDEE152711B63C02F919FEEE1A31636E36ABB4F9BA607020529814E06AB2D8E4FDE4D6C1A0D709ACDD7E442B1EB65643FE7D9E8D89906915AA868E9DB2E070CE6511EDA0506A19A731C0DFE149788BCC155B829D52E2921430566F9DB82DB062023BA5FF61FD26F8209421EE8C2C22FAC9F58059D223B4659A23BE538BEE894015F8E137849280668B971AD628CC57ECB49701EA1F0CE2D07B2D7D8406FB1D2E010A51C02F6F8F04F38703326711B85ABF70D46D947A42855B7F13B79D39D222A3578D6336C9B8A69A12DD38184EBF9DCF787C0D7611AB4176294C239B60351B62309E5DBC92BE0C0EE1422D9074905131757F70343CA00ACF2CF9DE239D8C794AC868565FF9900A1B9D187580884D509642AB4F6331A89FCBDB367067712B7B4A7A32E266D7FE571E4474FEB5DE28CC0D480D4AD11D0CF6B599A56925D68C1B076CC57612290221AAA0F91C8F7D21EAB354310250A224BC0455C760F62B2981ED68F7E10619AEF954B79D0D0DCF039DF951BA2245DEC02E71968009ED5364774644E995DCB33A41D53B3C9C1BE952449CA8E671E15EA888789CCDFCDCC91E0ED093CBFF538909886E27972C9D262F5E1A481B8F483BFB311D1595F51FE1AC8CB43EBC92C0D17868986B6F2BA8127BF95E159776570E273393FEFE203FB079780E675BD62F475CC0D1DF76CCA50B5145565C3615498DEF9B7BD37887BC6988A9853B4E639C1BFB61E32954D1166156F944C722444C29AF577C12F567E568BB1BB44A9D0783F126D6A079345C3842AD6240F1740585102F558C5DB6C22A057EC2D902CBFED926BA5F9C298E6F9118B9D2B446A47E4DB2F4F1CC30E75B6A1B67FDA687E672E7136AED3E02F8CC346F520E5929526B6E9126450E708D30168D1A60B41D19949AA4BA5CB7A691DB90A7B5040B01518FDDB6035454280BEF79E019FB96D899FD97BA47D0A7EBB39A11A84036659598294B0B9A905CE2E0CBA0E3AFAC85FEF2CD3446057ED5DF2FC389D411CC3128A8DD23188F830D90", - "3A9010CF2726ED13F833686B6C7796E87CEEAF4A99B40BE702CF35774B6BBE4EDF528C39A8FCB1B04AB9D25FE6666535391A45D5DA45D8073F705184427C3C5C4225F66F041151A22423A1F5516C744FDA91305B2B70BC11569416ED456BCBE6C1A47A5805B464EF6A645682D88D75E7FCB458BA2F9C44E14589D2805A904AF02FD3693DE69D0CAC00E058B26277018C3339EDA876CF820AD6C99149BF76A8C47ABF795EEF76D55862F4A88B26A73385589048B2E22C542461AA9CBB41DA58C7A5A32047B9F85426119402E531B023E3C8C1EFC7AF70D3D553B50408AB568E4D2EF96E5FAD8BD3EDF830FF2B12829E97C5C57927E69A438737B1920553F2B921E62A3E25331BD3BBBF99C9FE1912E0A84B15EECAD16B03D059876B7B02908C7A7DDCCC51E01213B4829D21C9FE65AE129F3B58B51798C604C9A2D2BDF7376FBB50732D9694E199DC532623309CA43D837EBCE0EE9F3943BF57F9ECAB4D939B2AE599FF5CF5370C9B56B7B9800A651FA64F854962A6D84E1270EFE2A481D399DD3F35C9C43605FB03315259989C4F2EB41B83C62DC2F7EA15B315126D227A0CED8B626022F9F665B49B8C32A10BBCEB0AC7FA80335A255076BEEA7E5BEA0472531B22E07A6579F9726600E661B389A221D2A6D2AE9E0059D24874BA5AEF82B1B53734F0835FAC5732FF0AED0F092E06EA84B3B5191BE3D226A41A6BC39AE3064A789A8DD9CED68FC3B902249622576D4086D63B924CB0C309F75F1FE9A62071FD2629E927A3ECCF3B575961221C5C1E76D2D6F1D330028F262E671905340C7621150074C49D9D3D64563E4E6C8B3221EBDFAD5A369E25DCB2C95A1E19D05B4ECB8E605BBF49623F6C62383A4ABF25FF823CB5F924ACF6D6173BEB850C46E0CCF6AFA873096046B7CE53271A33D18BBEBD6452D1874E312B9DD2035E511FA43BCBDF3E3A9EA8C602EFF6051AC0062232BF8A2C1AAAE76F0C12ACF4A290AC376A0DFA55BCECCDDFC1702D38F74BCC3FDB3160C3F52518EF2B1E14CE9CF22AE5E4CF2DFD531057EC85896708C8BB9D810B7D258AE975D678F19139A760F5609F57E2558E1AC0B6AACA4636017083D25190CECF73D29E2F7B44393D274074A68570B720EE6CEA533AD788F9A7F127BDA09D43F96AB9863B5365C9361A9EADA698F5A616D5EA0EB9F83B0647698DAFFE659979F5A5F086FC8B59D53C737E2D38EBB4F74C5CC6429B526FEFC9D1426969AB14DBD3F54BEBF25A5A8846874562CB282B2BECBECEDAF015F41037486297B30C905572211F80727CEF292CB2DB118157E666B190809A10B177BC63158505BAB5C915D37626EF7CB011041B08B03FA92A40EC3E39BF9B4D7279A5D1E4CF38377BE6C00EE12CFB4549C036E75240D3DF9FF92B50954F461BC25BD155AF84316A1752B9F1834AC4DA1B1B5A4C84992141CCFB0CC6AC5672753F4877403FC3F4A52848786C976B18CE968509A4014F3C69A77F9CB4915A1E389C1EA74A05DC08B6A6BB1BE755365F1E96E06FCFDBC7210099601912F55F639C9C96F28460CFC392C855CB2D3986989FF85A0DC7889AA2F6AEBD3E1AA196F97A3C3A0FBB33ACD3BBEDFEE06606DDAC5DA26290149E6361E8BEEE7F2400588F3FF853EC85B5F5742DE3547F362B0A094D6F935DB0A2B5D1480DB2CEFB9D665887F6030358AB9E5B26DE8955B188C39D6B146063FA59D1BA260796A2DE8CDDE8560915F07087E84589340103CCF7E1B75AD5BFD209A99C429A52E8D4FE96EEB9A32A4CD24A7940B446003E1F8296EAC6653659CCC3C85E01F7A154", - "59CD72F81F8FA04AACD73E9C815A312E8C02F1C1769FDA17C16350D9EBD4F8D10F248035EAFFB4FD67933279518E3BE9E1807288A9D63A6504F3A31E7DF322AA1B2A9ED3C23717C0C5B134D2758666CD04C2FA8C1EF5C1E58870C5EE1378619851845BA80DADBC37A764BA17E6DF285BB3DDFE31A56D4BAAB0FA622B8D3D24B7F91034D2F773FE578C874FAF5204F3DDB90B8533906AE05834BE67263447FB4485BA069EAACB68806028CFDAA8FC6DAC6383837F9A059EBD1529A92F98F44D55AC06083D6B751FF8F9FC5A6444C1A7D346025AD4B67EA12439242FC02D228CE537AC9044F6D193E0592684FAA4D259DFB00F5F98DCA9FAE4C0D5F0427C6936E501148C56EAD1817A81DA30989D0D9C85BF8D9972FFE67AE3DEB2A8959D63B3C3E7737A1851EDC8B313D75AA7838C6F7750280FFA6321CC9228ACC596431D72AC0302582CA56C6172599F30D0CA04E71F3FD7A03D467E37A8320CC0FE3AC72099CEF7C4265F7F18E2980168DACF9C058E39EC9FFE1EEBDCEA5F78D63BB18BF054465179401346D4CF8927580B9E0370B2D27E4C6BD4687CF0D4348B04BECE8424A42B2CECC668DF9809F580BBB3F3D59BFD96DC8C2E57EF5D2989D6DA54C04B15F85EFF639253DA3301FB6E6F92264FE48968C2C2CA6D40C54C327E0673BF769CF116DFD70CE374BC447AA1B121827E5BA510E387974B19B050D9909185A514BCD8CD374EFE2089290D3DF46D088D74F556A8E5F36B08AB17E54143B6FC374BEDD6FF88AE74E71C72297A31E13D1F668DDB455DF00DC91DBBDB2E96ACDB811ADF7E4C1C460D8FF1FB03BCF95EC489446A8DFC5D2220E58CC298FBB7A9B8EB33B61F6461D77CEBF9C36BBA32B34998B7B9B7950E7E98857371003F40279FC2623F716B808912651E55A04F9418989047331C454D2AB04FAA192938209261029FB3C070FA056D2AD52BF9C7A0535FE2868888BA55CB9389E358CEEC68D7A0E5505FF0DE4263C6E47406EEE83E8C797BF58EF49F2F8BB4EB3656A2636A5EC604A4990001190A8A7965A36BBB41019EE19C8EB45C10173B513F617B9688D7102ED82E60DDCD080233A7B3B43B641A3282C4AF6D3F01BE30DD78AA184B9D565F7B1F927EDE214E363A18547263412EBE35E939942C4B5EFE81E439B325902EDD4D2AC06340296D00DD5F0908F5C8AD88049D88282D0F2DEC28D133E1D4736869C352A7CD87D8A56687CC25D5517A62F0CA5A023E8709F181A0D96F1154B3D7517EC5B076B7C59DE90A223B96AF93F94B11EA0EB08A280379BE028DC494C296BC46659CF9C26A3F8BBB47E063AA4EBCBC9873CCA2866865CF45076E6E642B8E3BF9F4A3F9F057DCE71D4D5F3B621D8791CA5333398ADB31486D22F608E9A8745B9548EADDA654F1D4BC042DFF9B3C21B15AEBC37050864E4275D5C36F301D533552D119039242BCA25DFABB524C971821B2C0EEA602A4C02C6487DD113DA4DC5ADD7BBBC325CFC896C942682945A1BE921FF71E6D76FA1E3345589B53C549BD5056FA01BD688D0A9011497C0DFDEC20210BC7F8B713C46A100A396A9ABD9A2BB94E5455793BFA28E39E130645973C30FDCDE52F6C272576291F0130474DC2E3C30EAD54818E9F531A538028DD40FE01D993DFCFF82679DC3C66850528A173FBB534843AB540E21C7731C65044D697B42694A1654B3572FE321F61E98EA22171580F5DB90C997D0C9C7CF44D174E8D24F500832C158278CF62BBFC6DFC46AEE5DD3F8906A5770C3BB6CC3B731243974A76C0BCACD9EFE37E52CD9751894A68AE3596E0", - "C0211AF7A94B37632C667AE5097F8B5992917210A515C3E48276A363A6F5696AFEF5B3919689CC8F21E077310FDFC5A58D6BD428B8FFC678299FD053E7C016EF3A154A41DE5FD3C3BC5070ED6EC8F16170C880F82EB0B7EDED047436E8FCD4E2290F450963133226D17D7BB99C71097978CEFE496032EC8C6E73B99B05A33C4F5373BB73CA93F7128A9818197E6FD2BD88451A4D8905214157C4259228DEB5F8B216FFB206E4EE1025D3E16987FB6064147D3E99CEED73112F62D513C8B6F19B582D0F6794B307E8AF97354573C758AA95AB0A926386E7D288D74F9C6B0E2C71EAEBB36422C2120511F5F3D2B308674AE355B1FA1E72DA55098AAE3C70CB1B85C902C103056E00EBB70D37F08FA4D90E860C74E841F4E99957B3097ABE602E65F07B8787DA172E8E9ABF9ACDCCDFF6FEE2F902082BDD49547EFD95B54C3B8F6C6D243D07F16819E03189F0A3F3E0D05B3AF3EC92CA08846FC909E809CE9C30F1F3AC6FECED9043245A00590CBBD83EFC41C9EE3CBD0E328426F821ECA32E0E84A8B64F200DFAA5F01B262F4E816A90AA33A2984AB8E269B8CCF61E65094FBB7D10E11F9E1022CD97F17011DA53455B24E4ECD0793486C1E6D4E3BEA94E6DC9C710CFFF30CCD48E43076D763957260D1ED4F7C41EFA0B7F78BFAB7A9274E932013E605246C36CA1FFA003A4B24DAED61D15327BCA1067ACE961E718DD5E57667F5F33411D17BE093A9D7C6675097FC551014545727BA3F19C5D5D23A0922B11C4BADBF285A17EE96C916238C1E1DE8A0D28FB79E72EAF5AC37710B4E6550CEECA2F22697DA18F858507CCB95BB7F25A0056FFA55EE9564782C6042686195BF56901D4ABB3398C557CD47D30EEB344B532E77566887693CFAE50CE8C0BBAA204465FF33456ECFBB1B4DE4F8D6E2F3E8A84E90410EE3A79ABB47D40F4691CEF37E0BDBE1BE386098181EE36051EFFEEB0F5898738E400D44ADA4B3348315E0BE88C4C43E8CF95CE8D56EEAEADE754A09F170D3ACC44DB101037E001DCFBE2C52DC32D040BC27C1A55C9EF5D65FE418F3B761284C461606ACC84D36B9A7A3C9353723BEEEC80CF75D84DA7B2533F844E81EB8835289487CC7EA4EB277A4BA4BD50B59953E3DF3EBB2BB69D7E148792DF55D429B2DAE9B40B00FB14A948F2797B7488EBBBEB4B11880F7D3062D3C0561D7F6FE715C3BA6BC703BAC33C29DD87EBB84C178BA09961F2C10D8CCA42BFC3977EA66D039FC24CBD2A7B3316EF37C0D0F98D3CB8D5E4708B4287FEE6B656F1E300260D5643E9AC323A7F0527A7B98174AFD3277D35D6EC63865BD4E816351B8492474116E2426A3298606039280AEB595293D18EEC671E1E139EFC7936CAE3056F9698BFE95568D050F281F17F2CD65B62B98BF36DE469474F440E27073613A121370C606D5729DDFA12C8C400D0364251D850D90804ABF000ACE57AB195F6EE24163E8C443C8AEB641AACABE70675ECF22A5B9DAB6DDF0078EC89F2354C27D296411041432AF390DC71CC6141B52C54FC778B5BCD31B55EDDEB62EE364983E97BBB65EE98863AFFD2310B482AFCC28A2FE9C7D8E3ED24D20FFAD1F5B0AADB344C77F89FB88BB2FDCD64A77203BC331FC23BF78E284ACE3016FF570E3AF32ACDD5BD5E7B59115950CE804C231AB1AB80276842FAF80A576C9A3148F527596252E2F9F76FD6B4C03EFCE924A4740EDED98B290FF138926811607CC553FFAD5ACE0FC24D7FA1D7F3701A8E0D7F614941C9FB9215389CC5EF6D3CAC193EB15798CB1FF2950E2E0EA96A6B9E672CC343A7FA9C", - "28EB964EC60708D60D921BCA637AF0F0E19E127E0E563EEB30DB02F8FBF2848CEC8E351077A8294AD441049000D2A3BD101B691C2F1DF3741B8BE7DC57592C2D09C9F368010B4B3922A8A622887C37E959C9AC31DBE89C9EC9FFC26EFDD9C49362E3400E660928BDD7F67C6E45614ADFFB96622390AACC03F1186D18BD11333AF0348125A92EBB40370A32F5E383ED858F6720D43633A9A3E3559A0ACF5FCC326DF117AA495759FC12398B2E060F8C6DA823F3E58E1158B81AFEDE50B89F956D4F63619332928B4CDF5A16E0536FE7426518B1C50FBBEB4EF3830D77924BE1DB002BF2B0A9A8CD6FDF3BE7D7D1D7A3EB4E8CEFF8BEB9E2CEA9BCA74349D67413E7D05DEC014D1E6990062F0C4CF1E4720D45E23719D748D0C9BE3C3CA444E357F181E44EE841E35CB5207C3F993CF224A4A90EF5E3610254EEC4C2F2EAEFE041E1791518F93BE9080634AD5594B98C6D0161BAD23EF1403FEE6FF846D344BF0B42A65762804A33F00F12D769B3C58F123E14B4001CC631049F6E35013DF92AA50F89E71E78879A9B428341A738CA001E4233652802FC16AE2377C9C0B5650805205D31445EA0AC0F82A109E5F7C0758EBD5C737CF48D3D5D44816504D972CD2FBBF0AE566B8247F81E404D7DAB5A939AAE51375154A3125345C061CD479F8D7D9EB21C6ACD971F75D8430FAE557DE7A669C59E35DAC4E7686C53C34AF64A5AB7F6B5ADF48585417DBA3584D4552C241DEC336E5EBA84C4D295148B29FE824D3934F4D2A8EA2D27D29255988396A5C350421E2C2BD89B5D18155B20260DAED20E3DFF52F2E84E6D6CC2C040FA3D0B8726C63778A601CF95BCFD381FA520F95146292B8D854C5F057440833E78057D13FFFEEF4418E97986A064AC8DB74A001BCBF8B8E26CE9C68BACFCF4895C956666F92B5EADD27FF6FB032207FCD2100FE0DDEAAE8A860F89BDE341E59671BB0368B1C68B44B131139A44BB37EAB251A0339A79D358D73281325A594E2156E981C519419D925F0D6C8661F7C294D91F527454AE82EFF98344A6E39B2BB3E36431255E33DAA31B75E961FB306792510924C3E9B89150691BDDFB275B9128677DFEAFC89E6562FA245DEECEE2E788EFCD06C4BE744CA97693CC1AD7F0EE4C633D706AD278A46A8DBF2DAA0CCB69806912F8C081BF192ED7D17EC222392B6E84D6CD88FE66DB10B1EFB9CC7F3E4F3719338B8D6BBE47644009743829F288A194EB3F6F21FE7D7FF55F8FBFD1312AA603CBB0C011CEA377E6E2AD1541C5BF55AB73777BDC20DE77F701E7DF26728A44D881EC44E905608CEAFEDB670A261F2109DBFF79CE13E98A3519A9A86F3E01B7C3EBE2F01C657EE017F0740328B97392C6824FDF4D5820458F0DC9E999A4F878D09493D249D0B43268D44135C966B05AC8A69518BA5AA10423615DD3BD8B6E38D37D4E7ABAD0F8752A64736EB4D6656F6C3A6C6E1595AE0ADB31ADACFD6B4146F4496E739C4DC98835CE4C5E2F1FA899D4B896B02CE97822E90CABF5850321487D0C9DF07772031F1A438E9D63374373958DD9708C6BC38C3028C2C7DBC7B2A5A0CE8EBF87A72EA394FBC0046B62D60CFCC4256930BE65B22305C750B2A7483CBE0B3FC0824A011D274FCC289B8EEB9ADC5505426D8618369E0135FCA2FFF5456E480109952CFBBDA22758E14643AB48F11AB4F4EB475CEA238C6493166BF384B1DED53072D897E368C8BF8239DE53290766A4727CBBAB88691400E9FB9CD53442B91B5D421323A24571DBAB65B7EA7015775B6C8DE25247D0E7BF3DB7F2506B4384B328", - "D7554B01374AB97EE1246C2DA82B0AD5BBC76968B6E058A821418E0707D596E2A7E3AD9AFE623D18812F269C1D347A732BECE58260D2E8F1399AE5BB928716865B902611DA70761A4C3DB3EB0D332E58E081C08D4AF96B1A85DD68CE15A8EAA5B95F73CBA9975924F8F9A3CB57249A6A904A33F6471ED4F389168702EDA2054B4A523B6CE189B26C50900913CBC7693C4E447CAC4CA7B783106698CBB78F5E793284F27E182CE12BC792935FE38CEAA7F659967111AC2607C8316FD3CFF111DC5C2D58502555AA589010F9DE4F735D456CB9F0896FEB163984710BCA11C5D78D9ACE6CC9E2EAA70B177A9D33D8C59245FF9773AC181548BC82C751D59A350C65C895AA79E9B57FBFA2D17F53EFBE0C490B43C3369B71DE45B9AD67C88B2A8F1AEA2F5D871970FE9D4C6D63F81647DEA310F76DE6C050729DA4575087E3AE8F6804128FDA47C1867A6FB5065C4186C47D1199BEDED29D26BF9825676FFD9A98BF91E3921A07EFC949D7473CBF04E6647390E33CF765BBF73714E0AD38C4D1EFBC3BC4144CC9AEEBA0B9B4843F910A7F9CFDD347F6DC1017C010DF0EED1A71958CC5BB8D50BBEC164E186B6572FD09715C29611A3A5162496968C1DFBC1B6A8A4E617922D152FAF2B08BA40E47AA0E9F30515C9AFC74A5C2D87828BAE5243BB7988DED81731126E4C7E9609863929F943930FC72D0F3A4784990E08145485CA0FBCD69BAB2391C82E75BC2CB2DCAF0E94A3717B6A157070C77A8A3B5DD1E30AAB09F5368F46F66575599C04296982E6AE8F8C334ED24CC58449CAB0B7660E0F2BB9D96BE515245DF9654EAFB5060D21291DB8A2D820BF372E795957D59ADED6A72C265D19C852312BFDACCA65431B9AF4DA6AD56B97E9FDA9AE4650C9165037F353D9BE92322B4383C30404706D102F15D8D39B21D22E0B23FFB0AA0F58F477DEBC4F130BF501C765295A54913A7A0190FC907BF2420B329B97F30FA65A7429E7D71E572E1BE0AB0793B606F480A1526085637BBF89CABDBD9D19D808F230AE48505CDA9ADE68FDC826682BC406D4A7575EE913B60769C3BE4D81A073C05FE2BD6D7A1C3B52FD2F22875BE856CE0F6D7A3AEA1897FCDF951DF4A86184E717B4077A25D37935A82E073373ABBA58B0F5F744CE52284D96200CD90F0A7B4A03869A93C9371B7F946EAF2EDF35ADCE873407C7BEF0A750CEE48BE3A33CC47979648FBC5EA7E79DBC725C3901D4D05BC5B804007BD46E48B424665763F028E3777FC1A00F588D9A26F68DC7ADEEAF8214B747B409395016A05D8C72FC3E838DBF7C5A222D03699897E5606433CA760C6D67C8BECAE0FA8C312C9875AE26D61FCBD3A320829B615FED0587E4225E4B62264C9B37D2D2B45FDDCEFC060257960DF6A1AA2AC0544FC333914D192A1629061730213B1455E6FD7A712A08122C8BAD77EAB9CB9687AF97A3AFC02B8F413930DFEC10DB37C385B5643E91F3345C73EF353453F34A5EADC8EB41CB098E9243E57258AE608C9FE7BBEAC524B21A0734D8EE51EB30DD6974B87FDF3B0B1E1DB01FEF13061E4B072DAF927C99BDBB7691069E2493E86239A69BA33AF82998CC1D7B368A4343BC63EACEED280415FFF40B0B61221D7D1C098C6391E5C888228045494F86644F34AFB1B191BFCFD1A29C678956DB16D0BBEE458AC6DDBF00E738198C093170FB37F3F141619E65502AC57E9042CABC72372E5FAB9DFF5E42A00EB023E44B4E536706FD63BFEBCE1C0DD59E465A61DABF566EE7216973ABFF5D34A5A62518E12E8352C61BED9348E5826290EC0F84C", - "4251265EB325D261D721A84F62224701C9F564298EFE0C2516330F7AA43CC3D7090581B74C69218D74C8C6563FE276F24F39BB7998CBFB9C49EC649106DFA51E45498DF0F347DE8A562341DB34E94F286F583832E49AB38C09DBCC3B2C307188A980574461CB3C41EDFB933938F89C88F61886B60097F272E511B49CAED645190E98C3AB8AB5CDDC021F76567AC1EAE9F4F8D782B91BDBA3037BFF8FF43879FB6598D84046CA06B3C8EFE275BC61E449853F979AD6BFDF27DF453E2551F09FC1916F4E9884012BD4B946E2A65C86C609CF8EDDEDCECBE9B1DD6715C1792E261A3A013D64F00118DDB1FDAC9900E8BCCCEF9246446D5248D5E3423D859E1AA9BC38F8697F8A4EA08632983F268BF7D0BE639ADFCE6625E00229FD510A41AEE418C3AB85F5D2256D8EA4E9AE47316BE6DCF792537F28514B99BD76D098C8B4CA16DE1A9ED0F2693DFBA9B460BD842452BF563B03874DCCCD3E18B76AA3E352978473A2E02C6398438A35639457DBA7316577B0863762FC177010E0FA0F7537420C0443D8D7F51AEE4F40A67E249D678E77F17503A0A6DBEC3C60FAD140DA592082C334E3B1D021E34104A9A724FB6EE3B5A22CE5D3BB9C5E896956B4C6F7B1F51A74A56A7232E027F706EBB999708BA8ECBF42F44E41EF63A7627C60E5E75C678B5B3F7846CBBECC9A1B6EF78D7912AFF0EA56B7E25C31784DF9D63398FEF53F6193554C4D8B7A96C170A89961D2654B9A663B39C76401A439CAEC482BF44F20DD12140D47D0580DDA48EA905D409BAF5BCADBB8394333B97C0FD9501AA4B4BCEB3F041520422530A09A9B24EC04206CE907A33D0A18CD5C1640CFEF970623B1AB2B7EA5342B6F38C717416C17545D27C21A8F37AC2B98991395D3D170FB2D03C6B152915DDF9CAA12B5EB19E45FAC4CFD4ABA726A723237A6488773C05D0D38D38D920C6E8F2D3476B06B40094463CDAF380026BC36B8EF3DED6A01CA89E015A0B75BDFB97D859C620D329C9B26B1DBE3A3C92D8510B060ADF4151AFEED125ABC0D6FD3FA9F7F3C67B6BAF14A672977F2052A84F0437027956AAED010F63471C5848781BEF8F2BAB9F8CB0DB00253E2C6FD30D2A0794FCEC489376261CDD407B4ACECA129D87FFA0C76E28B9483034A40F84EA21E06C37BBEF2987AC16E77E021D29CBBDF077A912B89CEF82FF0EA59F7FDA55EE99F4602B5437CE71B4183BF28BE79327483898C39D09DCAC59C3CE32333BEF4B0720B30944B9998A01CB3C135D53B4A76FCDAD1C321D39D4466F0BF95710FC975ABCA1181070A4A5741624CE9AB0FEF27A5BB1805BF295861D0208BEBE7DF92EEFA7FB123B6AD42541C1A1057DA2560469A680E3664B1455D6851E6C8DC8C4940281AFF025B2BAD2CBB53D1670641EBDE2AE91E71F7F69AFD0C1A0225351CB1290EE40F81560A52463FB04E1364F9F3E5C454C311240EDA5C6AD78A094A73DDC1463E19A8E12419DE4966A1F12872E566F178E256F257FD1890DAE6F84DE013C2490B57DC1DED2E705C0134E889EECBE5575587EDFC240DE938C6D2D9CE543D5BA3A4A3EADE1A6A5F0CFF996311F72B3C6761414E34342C3D1A48F5D3011D7BC7F936E8E086581AC256DC6A376F9C4ABAF87FFAAD67BAC64401F4D976129EFD57102A84E63DDFEF60CF13EAF8973881FEDEBFF8D4B356B2A03EE9FFBDFA99F77EF7251C11EB1D2514D5E657697EFC47FC42CF10FFA7F09765E2EC39E0A99E4FEEBD410BF4AFE51855341279F7E47DFF0066602618ED5BF70B2F6D002805F41E991C68D64ADEAB7374F25B60", - "E0DAFB980D888AA2580DB37930D1942D6D088FDC706871A90D887B5F2CA6B21911BBB8BFEE1376F48428238607AF7CF82C3B3C9223746BA9A5F01523B20889ED8F139EA3D505D55D766BD056416193CACA6D5D6175C16C38BF44D7F89D4A5E3406C7944AD05D86C310E1EC78E0C8AD80FA0DB202AB1768AD446AC7FEC60B30D741114B45857FA5223E64AF32476319F16DE15C04F34F4730AB31F4F6BB13252D706F0B3BD5860BEB864618353CE62469E25CF4AED50D8BDE9633CF18F76AB1EA5552614D4AC3848A0CFFFDFD51F17A4E744533DC52979D7012AE53E9B08C4980AF8876ED2FD8A6F174B3AF651517BDDA1965264F1CCF0EEC8E3A9969D1359C5C9FD20CAD8698F3E28ACE77001F563BF456B5A46FC747E5D7EFED93314F7AA87CFA60405F968A4F9774E30E2266938BB19E9265FB71BE0D40FE6BF14FE02E36FE10FF110D63E02145C78B73217EED9DD87F70077E4229572E6547DD71828C773E46462E30B497F9F5F99D723D657E17A288DC98724B11AE87B7E56D33386A7FDEE0698353CD46409FE8D2236958B166B1C697BB8A42946D66E390A045775A6FE7DEE4BE260490B69C56476B894383091C827D02E960D9359E8D3E151F50EB87FABAEE8ACC6E325B36674D9C7CE249B879B3FDC6AF95E92FAE53047BC211757FD12564EDDA4DDB6AE8C94DD3305C21970E90BE05ABBAF912ACC52C77714F87C2B059A9E21005D8903A604D82EC22192C46CEB63C588A219CBF755B5D44CC0E918CA6705156CB497FAABFF63745C826FE16F65582D4820141DEBE3B949C29EEC6D99C2A4EF34DC878DD82D0FE6D5ACA302ADFB897DAE78EB0BD28A938D6FD5A3535CADEDD7C521E45AF4BA92FD40DDB009E35C21254A6DB959698303D56B59D8F319F18E688F9A20DAC8058E0496E0E46BD01880F3C78EEFE98A511768919116A288CD3CD28098BF5D4719EB64D548A6D791F1A9A9A3E9B08E7184AEFE60A3D7D7179CE47562E9133068789BBE0297FDA2B2D6F4248B288CD899BF3231EB360ED45F769C0167284319D2C2B11375C2B18E5B67594CF499A6AF2687E0C1AAF09F4161F3AA8369BDBA68AB022459A2DA9DEEA13E509AF3A68D011998D9C30BEBEBD04BC9983F36FA549BFF3E3D323722B2136AFCE0A2CC8E593B370C7B48635926B9575A77AD7C0DA18E94FF1C8FABFB57B25981288E1771465360E2D619272CF3F56268B7EE130FD07DE29215FBD5D0A72B73081869F60CB149A1E4871150778A2229F3C886200E0DC2C76AE049231FD3171E49FF44BDADE185883198D21629CE0AB252C7451398E0D411CB01A66BC5B141CB150BA9CFA9F9F46339625E1D5127998302AFD19D5B2D85F3F0B2B354C7CFAACA3D4E7C7B7DF44E22EC2C226178DDD480DF7787EB28F0285B1F973DC47B094491DDDC12BF1CAEB99E0E13781FE8A64DCB0A05A30763A055A6ADFE5434D7694A0F6A0366B5D74E73227F3D503E6B989C5BBF9E6D81EDA7C46D890FB2C5CB439C5B49FE16A9BEB14B12B08C47713331E8932D4AF6B85444E3F848C5AFDC095E984449F0D126EF711F8B43831755BC0FAE8D9FC79E894CEC183DC24B1E3C81FAF6A546E464AF8C0307263680CEAD9ED6E80217F98CA82458BEE59D2A4FA76BD7D4425E0C77164A50A2933972108661820C75EB51C8A0ABDDDEB30F31F2E575AB9DB723DD084656691096B72193C52053EBB8B72C6B30C49185166FC39F3D9F3497606D15E8D696CDC256DCBDB6D01DD2C33C0249D6069788DEC09802630597C13EB1AE152E8E84F6A4BF60BB09E049EEC", - "EF79F2E35DA357E9C076B00C6ACE7C50F865830698571E999E544F5025A99C36BCB025B7967846306FADCA22B8BED499BC9A80EFA7BDBDB83B15DC6D48AC4E3978D528DCE0A3E11C3E62B619EBA0C853EDB0EFA1DCE9EFB2E024FFC0B59A8AEC329FAAF418DF9BF70A250F2F6409A9FC0153161F6E8713005E53154DDBE15242AD801C216A1E5CE207757BFFBED75EE4C96CA0C3CF448966540EB434C68E9A4CCF3C5907DA216BA664B073D73B0779204EBCAEB55446AC6E2C40B8BDC666D4C9D33B7C644F867BCD8962274630191EADAEE7248398B9F02744AC5D4DEBDAB2D6D9F8D6C6392683FC1A795F70134E790718D56DB6D424725DF8AE7E11F02D684DA78ACB4B9C311806D082C1FADE4B31B8A6DC0E5F16618C47E03E8D78DDCCC6ED869F77CD39926945466369CC2371D3B51F58DFC6471D742C9C82B1B7A2B1B1BFAD15FEBE592AC0F41B19C126D923BF5944408506ACED28FBED161902EC5FF19CEED25D18F47A76860777A3D86B3E0BA7446C3F1EBDA88F8A8E182CC0938384842D42F41E0042C53C645DC87C88429E06BA9906A7A3C1F6A76671D69703496324406C7FDB20B9C3CE9BC273A743DCECC0016BDF85D82112DBD4C49E2A6A5DCA22738750EB8DD6AF15B27A0601970AD12660A51C560E5CD44B55960AA266A88B82E761B53A8B42E7332EF2FCCE093BCB06FD18D916FA10F4E9891B103DDE5D808963E6F71AE7479A5D0BFCDB8A2B2086308CFB7813EF6B7B5304225C2E9690E47CBFCD534570933541E8DC99227986C0CDE40924D64710A7FE28D248E667E18197B44D83FF1A0691E9049611AA1E04A1DB06595EC32A9B91C46F50096553C0B5716D2EA9C9E3D373C787783B50F28948EF96D21FB323CB69FBA26E8C869C745FF08AC0C71D2B656E42928D09AB4274C307FBB04AE41FE847721D95FDA55510893DF24F56522EE537F609FD54E4DAB4E98E9F3F8E8243C5D056B4CF6F2330408514C6CA22DBC79BE374E2B34B3E9A9B689B9375035F5E32013587C402C14997741654DF70FF5F74C0DC26D82AE7F036731AAE15D596E426EE2E7383EB540A48EF41FE2172F1565AD79202A016EF31255DBA5DE29C8C77B4704EF177C97DD507360FD01B44D612DCB18D7B5650032B1E768851C84EF794F833F9D5D198603224016D3FEA90F3C65DA465418750A69C43050A738A7EC4D415CC0B404B475936F8F675D49C67B875BD8BE2B2D65E05C49EDFE72163CF3F3BCAD87D8E956101964A1C1345F3978E144303FD1AEFA4675F521BBA59F0EF43DE19418993F444C1F75BEA24B295CDB73A51510B8B4B59DD20829466409444D4FF428B3B94164666A642FC2A187FDD7ADFE75E813BF64DE664B131F58B9CD825A19AC360F4F83E43FFBE0923494D978B1B2ECEEF07F2387E03B1D933008C0131A9ABB08DE1EADEF78291141D285EADFE1228554733CD927E9740D39EC9F539FAB960EA829552CFC36CD8BFD9092C821CE4FB4F29115BF533A56D7663CE9FAF2B9DA374B6E1CE5528A5B11ACB9FBE818BF4C41787F5E4FF4D517D46D2234B77F20ED3928BB38A32BBA350A66540E19B586C47EBB9EBF4E4A671CB41DA55BFBE5B39C025BF8F11A786D60C9DA6EE5299B17C0135689AC9D880B594EC51BB52398E78AC7DC2439D0C4BE7BBFB7F044661C9CD8D6D7EB16AFB943589C6210882557C65034BD7D044C6E957722C93537473E2EF1AF5A6D05D7404E274D2DA8B83F6D2AFF9EAA55D122F69F469927EB682977715FB1617B36368C22FD6A2A7B10412E9F202C6FC9BA1D7789311D0", - "18085D480B93B422C6BB24B09E05556F8298FCA307341877435D2D76B9DA1A1932F20D2903A63A0856D9C431FA3C4C591D606E0043B0C6BF277971588390BCAFFC01E14C6256290E1A01EB7BDC98611EB4E40BF72B04C21526D4139E3E75A13DC25C0691B67F24B195F57923684BAAF94C7E3CFF4830FB5E828B8F7A8692C1A0CFBB9FD3F021D3FCF12C7497021178A2AB8D3256E8606374D6D0E7FE11BB1F313BE2BDD4D977780C1A2053F6CB0F60F89671AE59C178FE33900FD11B4DEC25C698CE0FD4E451D6A3CEB4E41BDF08F05F556B4394858983D515266F25703C17B48B1AA13056ADB2AF9A865A0FD30BC4BAC0D7B1D185AA2903D1956DDA3D5541873EFE487E08E83613428B64D2A499BCF3783466079714FDC3D0B04ECDCED5C89F77F5E6E6F1141D47EE7A3C32382A89F512F9C9BD96AB24EBD4F77B911D8B8206CEE29ADC1E055B7BDFFEFF94AAFA750B857EC6FFCA693787C0E2817554717CE5DD5568DB1AE585B9BEED0C6E228FF47C43FD7565D3D5664BEBD73F97DCF73D8EBBA3FA092BF6EF21730EB909327313FE1493BFB44397567DFA30BDD7D090245057098AF775CE977528E91D9C3976A4D478A5695482E4EBC1FCB2F7FCF6E5F9B08BA8C7DF12E6F77C3B0362B1132F9209AC1D69579D5E9815535FF72820BE1414020694A3E2DE53BBE7DDB582C70455BCD18AA0A4E0A8BBD718217C616129F236487194B266F95E644D1FA79532D7AC13CD9C839BE14AD4BEC179923EFAC48965A8C915812C0F0886C11ABB0D2DD58FEE6AB2549AF9380B8699F3EBB0F96D295C22B940044819D7FBF2364610893457DDECED6113D1B14BDDDA8077BB32E70D19733CB795BC8964FD9788ED317B5E433CDFAC3CE3E0EA2A8359671F2ABF49946217358E92828AE32E6CE645C3C0E4D1CB64E5C8532DA7FC179CC7ACA241AE496D821EF7FB9E8D878B746C50DEB281604830360C8ABA336D1E8F444FD46A74F6B1A0F1F61EEC42C1DA2B6D88CD1AE94B3208866BD1757B1ACC09BC155DE4690A97D0244B819C0A66785EC764276BF39FCD6A1A172C777F2E9A44817D1B6B3C09AEB4436A3B115605A850AA9D11BE2E660F2B214C45B00134604EE395A77BAB321298ADE920BE3050CD2D7BAC4931C3E3687BC4FD7E2EFB536E26404E9950C928A3CFA8A11BE42D15EA8DB2037154F79C67860844D04DF51F5F21E90B8A16E7504947B90B655744758D97886E4860FBDF28FDE80B8F32C94D09F4F827F34E8FCE92B576A8809738D6227C9A31A43CEB3EDE56BF7306DC6F208D6229CC3E5C4B49AC54486ABA7F0079EDDBCA82C3C77F41C58A88C4ECF4DBEA754DFB3424BC3106A9FF280E8C6A7D086FA06C44ED23A82E23A03D3FD4CF62DE1AAF3A95747CB5CBCEEDA5B1929C13DF6CFDBA6A94A62AD3035C8CBEFA10AD9D37389B2EB90822E10B422BC165A3BA86F37C0A5B96D0EABCAA331FBF2806C65B376665A434A6D59B3BC9C339F4437F4598D0D6C62812A2083C32359B938D78390F9B4F86E42F297405069D350F86B089ADE021C1599FAA2460EF5904A6E25708032540A7747BB254679454A7B38C7491BDCC835033A76514869ADCFE268FE49CF38A9B844A97214E1E1ACE873FE051FAF282664552DC98618E35DBA4AD9B1FBE50700726091534091C631B54C944C28D97DA0961F8E4106408017CF1EC86456BCC1F4EE7118D0691F0F327A0436D3145E5FBF8FAC33E5179094FDB03D9DA0D9A2EEDDC221A21189B68EE1A94B13F062F21472DB5466B266562E2186FE01D028CD4AB5B6AC9F048D8", - "D50CD8EB871C5F371648DC07E20BE84263CD676282D56EA5374E21B52752DBE416DB787BCE232226568621ED792A9135A59849451A4A4D8A1DCF3C804AF966881FE5156FB761B3736F4282240FC0BBE72F51F0122D96B3755109E7CDFC70F9DD04C58B4A51C00B4FC0EF252B05ED76440C97DABA04079C121351CD43BCDDD4AA2D2495B49B908A9AF815DEE1405C3CE9CEC7D5BA9919621E8C4E920E08061D228038F73F8E5DD66BAB806D2DD953C6FA5360487957912249DE009655658BE8CACF00E6E0621739648A7A75EA06E93946987E62EDC270B266BBBCEF61D7CC63013AD797589A7CA62B65D4127E701BC95D45C74DBCBFF498D3F87CBD1B288D6012EC392B901A3DDFF16EF1E1685EA1F92B1F32DFED2F9076EF9CB1ADD8B04953E5509B24C48977FFEE6044B8C5B80F9DED6FA7110C3A2EA42EEE8A83F4A28FE78B27E84AAE7B3FABA56C1A4D2414E0341C69C40A43D65E16583A151826F7C7CC0CF0A5999A1016BE6912F067913AEFB525EE41F1B9C82881054E9624C03DECE74976228B119974BC546F823A597C7486DD594F1FEB2B6D0330918936DCBC12E3752A7072C5FD7B145571DC4A22C770E00F24B8C91E27F2C727FB049D04BCA813948D2F7B531C906F2018F51C9EF8B7642C0F1CC06AD338BEDE17683E0BD2A90D4D4746189F792952037E4918D2D6E61C1C8A8B6C437075ABC38913C250BBE6EDDA5CD24B630AB8FE9123B08D5E8FB8B71BC95BDA4AF1A71D5E54BE98B16D7D3083AB1649CBBBF44B3D5DC33B77DC1171A66F6F40E75EB86801EAA36E02D138093F28ECC6DA4CE4B128DAFB8D49A17C683FFAA8E6910B8BB7B832B3A3D0765DE2ECDA9D7BFF0A822F5FD389A04B660F832687CD67F7E1E1C3F5257C6FEB27B763AC7327DE8FDB989413B6D002FDFFB1DE5A80F1C5E39F06E6D716A69ABEF37B2DA9783FC494574689948DB51F78C8812E09367E6C8D70F5FC4139C64B96C71ED851D171AFA69D2A646ABA85279B7D3D31D268A2E8A272C91902F12C49D07D74E82728AD61BBABDA333DE7138A976A2267DCAB1A02E19B0685F64B608E3DA41108D54A07D4BDD24D79D293830C04209C98F037283BAEC00B1923CF404E1F21584F515F9D59B53FA9B4774FA8D3B34B7C66907BA127A095CD8CBB23375CB188CF9DF22CFB4CEC528C581DB63598DDD9A53438409D72507D2CEB5BD45DB5C760415A5E3B3A909EEDA73B7FE122DF04CB1E9F29E7A5A7385F632AEF63771A4CA2164B9B3FAC3C13911DBE9668D1127DB02A94CDCE2C8C7B66F0C21601781552B384DF0FA002DE08892D0881174CA1F6DE80B98BAE545237C5CEF9E1655F9EF8F8293D644CB47963734197F1976600CF2767A59FD56B9B67659168ECD57C485E5726C150DEC6C302456AFD4F12B2F2D1F36B03E100E109827726020BDBA970A6B768C580E34116DD0011299B4DEAAB8B04DE1DCC5FFCCBE57254CA79743D6B00D119CBB2C0B0BBB2FB8FB0B0EC97204E1720F99D16A3257846D09BF8EAE02DB21FCABF03CB0989FB4D99B6D71D5E64C6FCACCABDE63B223A91D1278D676839E1A5CE6C5EE05AB4F10EEC511C366DBFD7AA1E139AF671CBEDB3160A775E5214C862E95C3A7993E508D8F8B7ABD68213A531B5C648C537FA2674346FA0B3AB43A7B58B4F83B36D58C506C188DAF72381DE53F83AD4D9E6C6B1F5D689AE24CD158BB2898F06AA28C8FFAB1703871A6A6FE41ABB6B8B9188C90EEF88E7DA3338F119770B31167E3AB541371FF7F98A2D59D3557438DEAD71C96B97F3839F5E28DA6227E5B4", - "0447B9C85642F3F8BEBD1CC7AB0D0E4D07CAFA93A26C75970C8B40443506AF8BB671F30867FE4225F576026F79010AED56CE915AD9AC001447CDCB7CC3846B0E291DE0E9E443984E0ABF7C1C1D2F6D073B0B77116A21C3C0B7F360439D11D2DE370CFF8FF73FFFBABFE4D52BCE58CB32612870B0EA23CDA21E3B6E851B063BC76FBF7BC394A7D3805D45616C6A313C887D2FDC51F065F8F3C05ABCF70F31EA5746A513D2DB3F4F3C61006F19420AA82107AF855649EA5D90ED0A8540D0A2CEC685D18EC8F4508A7D092E52DB2117C233A7BB542B61C26BB92491A88942A506ED60354EC1963ACC189A248E37C9367F3F6FE065EDF6A1205BC80B267C1062BE20950617FE0EB59BF8F1E69982F3E89E7EF85F3319A22A22B8BAA491BE76AC7257A2DF631A98477544E3E57C7D63616D22789968CA5E929B507AC394B6772096CC70B69ACDBADF900D055881FDD209AEF54CE6966767C07EB7A2B40A3410C3417D114FC9E293DA7262171325D8179262B2BF041F5A977E2D648900295B14950EDF245C7EEB663F8292625F804BB839BE3A5510036F7A50288C69F94434A03466701BF1313020A4DC4F87D272FB9D1B7676C195C0B7B4D3C2CC6B20D5C2066C7DE5DFB5C9FAD43D80FA43BA917F200A73F258BF21ED8BF3E39F69E501AB3EB115C9414C82C52CE91F6CAEF4A163E288A6FBAD4FA83477909FBC972E2EE2A5379456105E8EA02F92B0D8F79588E2282D1970C3A033F738011BF273EA65912D3ED09398A7F851BA2D6141F97843E90F5C66B38D71D70DB9D93FAEB07FE1AF5783D71CF50931C282CA8B483D1F2E5DC5AD5FF2B06C4355E46768AE5014A22E7CA26267A1E6CBFAB24C8C436535F23D419819D6D458551EE78AEA4779574BF86DE7960969B0635F0B2996F955D863E078DBF8689C142736BD5177DBFEA3CA8C58871B1FCCBFDFD67BB12AF82C3B8F935CCC507D510CAB63B831721E0ED9C258BA7A3FE245D42DDA1AD8A962847D7C724DD2418F72508FAC194EC43D17533AE522187B44D71B6E993F2CEFC6349141094C8CF935D90F2F238728D29E1F5AA09B46FA7CB651F688A8A06AB97FD2363486F61D3F42B9C015652A53B3CD66372849FD2EBA05CFB5AA28520B01FCBD9C835F98D15FE01C84D7FFBBA4B2DB93E44E4341AE95B8AAA4D59CB88F7E192E89954E22B1B8157FB0B89E3E1E3862BD4C2799F2D8C621064EC9BA1EC30E0F7F5FFD7013A7E1C102DBF01698322992EB05978A5A2878756BEABEDC660DA2D5370A98CA2C0A4C65141EA273EB787B2E7AF646DEF7DA77A93E45C37E69B474D04FBDC3B5982D8492FFC37FDE42385DDFE97A73B8575C1305A0B9AC0B0CE061A423556B6FDADB67D0A5BBA7435929D658FB0869BFFBE5D2FEC96051FE03CB7B0D944304C2D433459A97C43268E43951D4C1708C702FB9C0A0C6D82876057F4D043B21A92FA6D034B1DF5C2B463107AAA814C79022D96D1BD9D33DE5A1FF9E435D9607575856CE4DF5F1E9E90FEF5ACC4AAFBDBE0F982DBFE78C5ABE1D9C85E0452AAD7836D39591411B382BCCE72CA1702A20C9DF384F5BD539F53CEE8B9977AFB705D1D28680D1733BAF5F298282846EFA26B0DD7514422C0EF9088F796B38C15EDF6C8D88009B10CD0D6B4B2FD93679712BEFFC4D1F7A3898AD0CDC61D2FCDC360C66FDFE0AFF0E8A7B26359606CD4F47D28DE115261E6F98F323FBDF3E3046BCC2ACA0831D2BB4DDF1EF443632A229CFE6BBA5179079DC7FA50C56BE7FE5FEA0C5AD09D891895508722861E9EE8568F59616890C6370", - "8DE87744B81A0E21A62CD72148FC3782AB560CE136DC3A07F2D2E143EA0DD2ADAB9FF8AB39B2A3E8858DA593B6EF6C46BB5CFD252F6DE446D9165406B3DD18CAFCCE3DC7A6E6200D8F7591169A6AB9DB6665FB72140A416EF30B75EBABB6C284E73809DE2A3A26C7F4F188FEE0B401E9EFF6DA22EF3DBE0FAA6DDFFB5D8C265D1A1855CF7019D8659062AD7A705362D1510ED5013B96D6EE803E7C6418B05828243496753E8616F4075A08346038E3F3549C0AB1E761790E818C2B531F06805D92FE53D45B9A6FA5E30E3D6A2F467AECA07D29E1E9123247C69220E2B9D4501EE42E5BDAD07F0D092B33A938B8FC0EB7E435713E3E428E87DB24AC570E4EF64840A1B4D43C5026C80F321E537755366B16FAFF2423908FB74E9A5B08F0C1064815472AF48240F1C374F2AAF8ADE55117E0FB1D08AA40C4D8AEF35CE6A91E54A89BBE55BF5E78ED5F66B2FA1E8936342656C63263D4E7ABD70F7899DAC9A315E9508AE65287C6660A7D7F3FF408CD06F3B19E1238E6D5EF040B3E54F4469BEC17198AF3F78F660C6753157603138BC98AA9F01FE79036D4564A7396725E57F875FCDA4EAF80C5E2815862AD52340571A571B331CC8122C13CC58403B22B61BD404C6D94C36FEF187C712B524BAE9EF150A71CE32366AE536B5B94ECFA351EF0DE77E729C42BBB32C7D35F9A5BB29D2D84BFC91F510F9A1C907540AE3A80CB7023AE0635EA5C2EA0548D9D14CE4BDE142436521ED1637C7B7CF6CC1DA5F826B800AC6FFFB83509A81ACE30FD969495313F9E18CE4D8A2E1D5F9C7DA14A0A9D4C4D49BF00B622B6AA07FEBFF0A8B274C297C0B4AD1CBD64BB4941543FB63D9E15059E0C0FD250753B2AA664A677780C39A013E1AA6B8F786D677755ADA03E51ED55F936FFA1ABD0430DA8750575C37D1EEADEC5E17148DB9FA202F8748B0611EBB5015F1D26C0D810F1AA5A40D73C32C269EBA5CDA134267231FC3783D3D4CC639E567681275F423439A29118C6A0C1B07D08416537D4707E9CA3FCD3494F64B69E2AE9EDD0079CD428CEB8A00BE0FC9A791FE2DCFC10D7F813315E964828A4DCC2A2D42EB313CCF192F32AA9A17C984E0D3CF3A0BD86E0B751B30C096F5F0B08A0BC439294D2BE2CB387648F8119D8820D39F17C6AEC976A0B8C89C76D12AFF73059B49EE856B2591E8D2E817DC43793F20B2AFBBD49FD9A05F5B4CB69165420AB96F26A46861AD9423F7DAE8829FD392799EF967E1270563BCF3D46025CDBBAFD15DC23F33EE5B621DF6A12263CC0A506A5E9AB191F896D13382B3BC2D536442A62B09F3C2C2252D0BE377CFBD59097259ED243EFB36C9AC0AB01B3AADD502DAACCE17A49CC82FC9ADF67B4EDE81D9355CD8295DE21468FAAA25036B2DB6E24A3AF3E5FE59324867658EAD5198C47D362EF64B71179D107DA748F00400F15167E84B62588F6D81FA4B68A59A24BB3D27167D0720718BD24EE556FB72113FCBD37831251DCD538F6815382E119355CF3490DF0AD552ECAE0D00462C10CBA4011E95C7FEC968AF6E39E1FD15D1026879202C57E2CF7AB02B08B15373C13435D8A55ED6B9BDD98FCD5B4539428D90A2C73D37DB112D2025EC8A4AC8EB82C51C46FACE88AC0E1F161705801C781EA07F6914122E5DD6BFFA3812EE44E314BC09B785B344584AA8522B63FB34BAD2122F9FEE1245E6DC837DB032387EFF5036A021C8112CDF03BEEFD89EEFE1BB88A132CAE9E1E9EED3A855B364F2A4A2F81086172FEBC64614BC04D11E74AF00F54AF6B5D85EE4773644C3FA768532B1821EC6E5C", - "0D1FA0561DE4DECF411AB73FF48D0810AA2149FE5F3C22E62E06C02F60189AB5690A991CB88DFA5C4FBED745FCFD63BE3ECD9CC599E35B5FA31AA11C62F3A33796A64EDD0B64F2E51E75C2481D3EC9DDF07DADB71448BB336C0DA9DBCD897F777E3C9DD97C7EBB08827C19316F61420D96F3D94EC395F8BF88F5927C71397F6C24901914826B1BE26E14FE93EED37141109CCD00C92772B96D9EFD74B3EAD3903854801B22DC3F98232023E1F9CDFD4B4C952A6D268DF9FD3FA83C707941F8F1ACDC195AD66E7AF48D7B06C62F3204E8D03D2C92920C589CC56A5C2B0A1F10401BBF747B60B9D2179BF9CD7DDF50B10823372CC4E24005D73B4C5AB918F22918B16D98F15C365FE69786C1ADE9FAD71516E389938D5D38420FC79F82C6C0AB1C6D93D1896FE8A2BEBA134C138EB1FB00115E50A8A676B9D9939E7375F4B7D62D449EB341B0C03EE3FB18564DA3CF64261055594E0F8D322EAA9B56B5328574AB323C4376464F3C27786DF7026BFD6C7757BAEDE7887217A2D3EA22AF7D6809BFE4985EDB32ED503C6034FECE55F4379920C73A515C7390B3405ABCC54F51F686903D5354468AC566D5A03C5AB536934A6CE698E06B9E2C815B15B4F8A1857FE7C0B5486759B150F48AE9745AFBCE856830078EFD7F4CB4A463587B7DDACC79FC9FBD9C2A0351D91DDF27A65CC79005DD24F1C26252BEB8C3F1D69DF79D386401EC5AD57BF2129D1E828D6D57CABEA84C7F77B16B919653C12AA7F770741E4AC11F0AD08507C3E7C4716F14F14C548A88DC4047EA96CF96BC0CF786EF7D02424314BC846682109A2F80044B51B12A0350DB9FE06E72581EE874665B9680EC118C86DB575F9E5F687CF35DB3CA83475051AFDABDC974B2991B47BEB4CB967E3CF20D2B7CA2BB50825EE33FBD7C6E87095DE8E36CA6143F673A8C18882D89F22C08971CC709F1518169123EE59EF50846C95C313F14F9472D4CCB8EB71301488901F27E895B5D44420F91D123E3EF5527121B9B0C9536CC3D4E5EA03F63BA8FED0FDF593AABC3E768962DA165CCACE066ED7D6E46DAE97EA08789C36BD3CA6888229D15714302A39EE4F39DB0751F0E99877237524ED8EAC5F7EE2CC40A69408DC43E2AD88A661D7E443D7E99A14484E3011A41912E2AD4F6B7D62D8D9F3332F79A5FE1E16E8064C91DE56B1F89A9A3A220165872128771745D086DD3F8DDB2C35AAF3DC6DA70684DF270ED50D188FAE62CE4C98B9019D308772EF036F9FB2775137377CE61529A40E03B388CFDA3BAD55FD62D7ECAC2A72FB68068BE08383CC36FB66CC252A0412CFB3C993803C038A1828E8893DB453D47C5727CF8BF80850346063AF4976610F984ACCA00BB5963D5DFD018E0790F4A6B14A9B5FB9517783EC1F16773C49A744D8576F7957D4CD4C4E35D1BD580FC76E2632D47661A6838344CCF6476BB793FB12F92143524E5A01DD5294B6528C5A18B24B0B75D017C4DB3663BCD561AA8F27E510A7C031ABD3708385B03294E3BD1A695C573701B9D4F60232DF767439E252B7DB10D4E3FACAC8C2E8D16F9500828826EA807C2C7C48C0EE8457E757854C1540EFE9BDCE7C09AF5BE09AEA54A4BB0D2A328092F3B8741A128D4BF588384A3848A5E4F55DACFA64F7FE081366330D16589991C52A1BB782364AE969E8A21260518662B00EDB117278170CA2C0D186B173F93879F6F702E03DE768CFEA1E39FF8453C7B3AB46E83FC90FC56D0EC0847DF16A4BF1ECBFE29D94CCBD49DABDCC5FB81B62A2CDE7D2DA3E67042944F33A007096DE5C79133C7F4", - "C9FCF7D2DCE0A2341FBEAAFA64F6A50A93F3FAE3B55EB70ABF51A4C001E15A8C78DE54E50CCAEFF8C2421079F7333541018D5EB8045C3AE0F0489D13C593EED560CDACDAEA39BB49FE2FD9C956197967830A0886182D98B5051080DE887638F2E3E626B8941A58D2206B46FB410C155B94FD7D15956EAEC9F855B96A8F1C7202EE600C12DBAFC6E3DE5F075B05AFC037847BB521D1D3638135591B6E1A0137CA74E27ADA3FD673684A8A1330DFA46D449F8B63FF90E36881C09FAEDF61672AC32CBBF71F34367E7547C13BF08C4B688A397DD4D00D8B19212F85EF11C0FEA19C890D73DCAE9B532CAB7BB5931B2F648072F35FAA31C6A77FAF3F72F9F57D5AE65BBC7DFF1C2A5A2A2721AD5B50DBDA2CEBA27A3864A6628F24B0D24FC2450890E278C4599C1015C2B4AE61F2DB2A3A85F02882DCB57A7A471B5F8E51DDC284E0C1869D41EF25E260EDC53AF55BE8217FEADE6C74B9C0EAE7C3417156D671577E05A63E03052663F420B70E99DE068971C5CB8D9055864460D6B2C269E4E5D2585BB7A08E28B15851C6E8438EBC1272D517A076C08631A9890F4FB627D05B91ED2164355D7F20B32498E4773FFFD17F3B15E7F2BAF5EBDC98E617A7437BCF94B0EA1B2FD6F98F8BE6D64F769FEA28A5FED9DBF4B3700BFA8C0495772A14254D7AD9525B6ECDC028C43EEEBF91D2B17C9ADDC071CCC83EFC6401A22846500E0CCD3D4E5184A05AECBD92808AD2DA42C57621C66142784692D4F28662A2B37DA4D3CAE332A97D465D3E492ACC964AED603058CB6BA6972C83C2906CFCC813C0603B775E2DE8BC946DAFA510532CEFF2B2FC5E1F25540FA07B577003D67F8A3C63E9BC2B89EC7AEDD8C2E91CA426398BEC4D98FB6233832BCAB8F10E5DE6668F7DF8FE10AC0EA63B7D46837EE4D1D203D54615042203552430DB97C24FE0088334BA154FB2157DD2D12715ABC6D329A819A1A664727F40CC26204949926E78B0BB8947FDA9026813FCF19795F8BFF2F56DB70DB7EA9280A6C504134A1B653D336101A9C166883599477DB557406FAD495BA31B488D9EDEB783759EDA32968AE4B4B96A14C9DA960ECEF511D4102E1EC27E17AF2746DFEA54F42D2133281ECA9F5CA87F8A2DE4C937B5F9526591A583DD3211F78871BBEDDE79206F946B9CEC6EBD0DA4A25AF259E4B3EC2195578C74B7DF87963BF561D7F4C6755D4DB0F288341D5E525B15F2BDA314DA38D2B2C7CD7D64F6DE35EE782A076333941FC3505AEB1FA5783C6C2553D73AFD6AF896A5C2E1C15EDDC408B6D9D7EE2E7E9F706C2A6CDE36A41BFF88960612C46996A9E7D43511302F925351240B5B77A7183C45A1B66C8FCD34EB6EBF5F5FFEAC8441BD1103D2151689BFCF8D4E29B9C39B1BE4972186B099C2C35572DB1BE2A28D751D6857B7E4EF181B786C2A6FFA30A5D6E2E1120E7B1F313302ADD1012E43EC24E5E5B5D03950E009272452ADEB9DB626FF38F335A520B12CD981636BCFB882FC06B440E348512E6ACF980A1ECF360E33DCADFFF5A2B413DD214D5AD1070E88B63FC9765295BBC92C557F3AAAB6AEB293249761F95EE4338243D35AF883AC33832155AC758ED05AA1BFFF0E9FD58E03384704DA5A9237F1AAF52E12C821BB0F54C0820AF8124AE6D0F4BFECDA6500995B2B61ECB0628BFE2A9E6A05DC94A781137522E85A3BEF28B76E49B27BD05C113C9B3A9AB1285BFD926D65BCCD5CC3837490B21527A1E94544C4ACED0352BC84D378625E3655F74B039CD681D98579A190AB2B89104C83F46235757D2D22FEEF59A250B564", - "48116D6CCE73D8BD1E1F45D9676B031D9B0E65684FB88A83D791CE8F5278D33EA9D3A6ADF04F29AE93123376D1CEF52F27E875EC0024A888E688EE2A21A4AAD0448103569C8A7CB2FB072E3D0D09115AD8A1C234F7765E77042156AACC4D4A8AC697E41B71F436ABA09C91E9E4F2C5B573CB1D0B291F915BF922FC75E6FC6AE332B42D7E51BA8EFB1CCA66EC849099834E48C7F79BC16C79B0C87A8EAC8F88D30EEE8FC0EEF8C89520E2602A7226BFAC0E8B30A117B718875687F81A6125D09EB3BD2B2F5209C386DEC5AFF7DA0FF5454FF0451F825E5AC55680EC7DEC56E72CAB953E5B822E0A1D95F3F948E95DA7078C850C43AF46B4EFEEAD6AF807CCFEB1B61CFCEFB770D1923B41BB354C81F340CFD851EDFD537C373CB9F29303A988635C5CD37AFA576D6E8A8C2B7C56DE2FD49E5DB970B50E04436B1F8B22A6DCEE3BC27EE1885CEEA23E12541554EB2EFE615A140831DE6C555804432CAC0A73DC2EE5CEC8ED139ABCA4D17B22BCBE60F05F5D7F526ECB29A51ED6ABB4DE4A2865AD1AEA64041EB0F505BE3CB8F351BA21A8D941902BA565039EFEEAFB87DC6DECEC1C091ACE228931A147C491C11169AC87884D5EE9DF128C98A084CC6EA0A50D494FF8E0B902A9EAA4B4F9D3BB2BA1FFD3DCC93C45133B9008E2B188F57A82B5DC01862D35F633CD6CC3FC12BD6F3A20C1EEE1F9018E41027788950DF09C4B482837677B33B15CE24EFE6797291C0DE291AC04F04AF975703BEFD3CB8E59C1496E547285E3F7A29F99C5F210327CB328B8A3094DB7C27CF7FA077791160A2287F44F92BA6F5346E48D4D4AE6C2C7185926526719537AAD530EEB3B0B4CD718C7BA38BDBA21671ECCE0AB4044B797B7D10797EB1BAA024B76D0B82BF25C94655545227B46DB2A038F87301BCBECE0C99A98AA5BCB648DE58B6CD59AC6471462BF5985C595B00A4DDF2948A84203890E2989D8DFC9864392E7E75262DF1CB78C1E2872CFCD22D561F8788F42A0323CDF3EE1588EFF2F7BEDACF5AF710CC7C6F9957D992A7FE39DB696DA414AC36CBDC99AF050023597734D94C2A8FCBF41D6004C21E4F4357C19ED09488797CA012F4BEF8F1743E396236E708D96A7DAAB07FE03D5483319241CB35F66F66D99D981DB4427C4C84A9EA24AEE4F7C4E023E0ED2FEDF59FEB6D8AC0FE87DD42580F7B0CC6339752230A69BE83AE13FC12AD4719D45CAEAC6E8695F6F403A0713ED37DC120B80DE82F7AC4991B4B9DADB31A304E16D03251CA140659CBF99E891DCBB764293A967DE1E96848B8F225D2F9D28EC2F428AFEBFB57AB79B126E6FC3D66102E3813347D7CDA5499F6AA5BA6AB5EA6F3A82D730EDF3FF74B9BC0F954BED21E77146A5591941962C49F6B2BEBD060A9C82D8FC780FB3AED527D40CC426988F042841250B4A85A3F3501FA3436103313C3C4CDEA772B6C840DB866B9730798B69D6AE12D24E4DDF31FA9B4C8DECF6CBCEA2E8A0F9CC67CCDCB64523725972D81ED2E6562283DE99297458452B94467B83F3111CBFF61006814CCB6550D19A1EC026996695D46C31BFA9BD371CCDF1B512C61CE7BDFBE419B477DAB1E7E1D012DA4BDB05F4C4CD39511D5071C0982F68D9C6F558D22940D541A3C67003D05306FFC070C2131832F737872114566ADF3074F7F6274AEF9B894D0AAD5ED60998A0363B92D841F4A441C39965FC1479E93C99B083CDE6CD6CB9E26D49E16B969A357E28A61B444AB0FA665B853FC89B64E02BB02C5273CC948B00041701459408C95E4BE49EDC7CB605BD2DF31C3C8BB2AA9FC780", - "840BCC55474C2F66B7E16C6F527695D367F70F570B13C1ACB546D8439A1AE06F362C224FBD86441D82430A345B8458EB666BC93739E3D679754117C95100E8F00879B891C9E03788543C415AA964C3F861916BD7C141777A93B374943CC4CEDF928AEA3EB72F412DD8256227D7D7244E876955B13FB2EAD1C3980AF6F8F36B3E71FE3B189F8DC22C55E3720DA11C6AC4328DCF670CF948123FC7280D6891EEB356C195D2A79326299A684F5D68DC0ACF00B780CDCEFCD7CBE4140FB5B6DF896883D3C6FFC42BAA41E6A75713F8861C18A833C688C2BF6EED7F0CE66242B8196C7C254F9D48FD56AE5ADA9105A5C4AF28D0042E059A90979C6439BF6D498991CF64C68080B9B5392CC9FCA4397647A9AAC42C3810FA33BCF31C89A641D1078A0822D93EB773F418B9B3B20D5FEEE1067766AC561525F88F8F097BED0CBFF5BC498CDFC9A5B9D20F4D4A03CA190563CE543B2EAFD8DC6E4A5885DEA120DA7D157D00EB1329E500D41C7E6BD603E95BFAE227A9B613A71C7BEFC8449B668C59147E1DD5411CBD967CBBD46A9DDD76C547506A54A8245532FF9AA5312607F1AB99F4F9BCF85D93B58D76C5583856595AF5CA1AAC07C945400B35885071802620855E18E0A3B1EE92BB95241EFCAD82B3435BBB8916C4866471BD5715882F6BE508C7648A59B2AA91A69F60C78482197C04B31759054FFDAA254A143021E37874DE407690B9ECF8DB99CC16B004116F51DC7853370BD3538E14A0F02E7BF74D66FF898AEE93BF0697EB6E8E62B95C6C525A03E1A89CC2F56BAC591FA81BF6A1B3B9F1259F13AB45F2E9B0D93DA7B4984A9C71272CA261CC4EE4A44FBA4CD03C75D216672C18A60183A52B28796B356EC498F4926D833D94007E92EC190E9713354C7506BEA6B7B5DB2BE659E2A5BA92D00C01611347F67971478F2C71648E33F99EF201367CA3AC8814DE0F83B0BAFF34A192349C5DE87453167820C0EB0AC8349ECA683111776980FEBDC993314278B37B289B528DB319CF59B09B83342C71FD5E9F13EDF4F18783FF328BC67A03F1F62FD1A4631AFD76363DB1A79CD1EA95FD43934955AE211E00EF5AFC114BE00EAE2A7AB63042992E086810E61AEE3CE5CB0FE75C04969485899D552AD4B006D543BEB93C1E8578168C66667D62CBCB56F98DFBA248EECD891F9936382087F2AAD6F83FFE25E77F8BAB9C62675D4024E9BDCA5581126BD1ED6035994029BB54615E593D4CA81B31A5AE8CBEF8E1A81C32698FB7B4A339A7E4E575460F79C4F4C5F57F9E8DB459177067869E03E2E1681004EBBF62B4F60A9EFFE47921AD22C7236F25438AF46885E120825509D1E28652361EAC64AF1806317416E5550A39AA8DAE2C6B970D44F4F38D571F67E304AA57BA435C4E06CC97C848422216BA778B2736C30200527960A66D63280AF7DC691F9D0540AA47F0D26416B46A6D53B0B93F1B7C3D4DA8BF8AD2FE410ADDE00B0372E9E830C09B206A08D968AF2F716DD04D220E619FDE28FE70286E7EB9C2068F7A37413BD9E65F1B59C331D45AE914731A564D33875A0939A2185348C197CD14DAC59C5E2BEF09876353FB16D849EE67A774B05C51AA2480F18DE40051654DD2C7B9E3B753FEE5696B10BE40BFFE89487DA1E8B1C2000D53B2A98B4DE6C9DAF07F0B4DB72834361E520E45F5E958FE0760F229C16CCFE0BDBF07E186B28AA69231DDA8378DD6338A94D23541B9D8B63B85962C6304E1ACE2B56A3E433F7E9B2A88FBAD5FC71703231D38DFA8C378E15B6503A3B9959E1759EECCBFF14AA09E6BB8F2CC", - "152004D3334E877FE21F773408369872718CDEE15BD489D97F606779A9A38398524E6560260980FABCF179ED91D699D52592AFB3269FFB8DED36AFE7DC79DB773DBA560E3ADF8E12FB8A08EB56BFC4692BEA05AA288012B580E43BE085CE583E9C9DC18A9D32567EA950D8165A2F8A443E7AB5E79F687690A8D8D92FBF877C5B84D26E6FCB3671073BD808A7E908130A845C95A2F5E360645611B4B55B03169CC1F50AE2FFFAAF50FED8CB782BF3C67775B613CF82A2D102199E49A329496C0FA24AAF6370A3636EAFEB992C663C308AD181DC308D81FFD713505916300732FB1F8DCE238CC4104D26C588F28FE7EE4F2B8C2024357D52C7AA29D339249086CB2202DC1C847210EAEBD3F06A39642711B4608638564B0DD2BFDF38CD79CC1CFCE1226CA835E6EE19E4089A6F18E7ECC3597CAD3FFFE13A5F77A58C2B079DA25B928396FFAEE81FBD9C6243CE0EB0872A187E6CF99F16B1511672821D11EF88884964BAC6686C2A7732035493FB9765B7A51E845C1C79FABD99438FD84C09642FBC7CF1740DEB012AD050F5E8FF03E859E85C51D2E87AC41185C67C33820EFFCF2D79D384B11B44A806ABB8247AF36E3972222C805EB9854D9FCCDC7E58A101A5239E60CF4836C38A6ADE67686E6487547933859D46D046BFC15AE95B8D0A42A57C401EBE78ABF495EB390B8922C97270C790C2FAB9849ADE48EA8F4F7C6996F6DB661500199BCFE1EAFA1ECCFAB1F674E0BEB1D03319E73126D7191A64A80FCBBB06B1CFB718275BDDB571E8F53FAF81DBBC0522263FCDFB537B3BE9078F2AD449423152BB9DCCEEE97003D1988540FAE39CAB62593A9EC909489415EEF4229358229BDDD45CC35EBDBA088C4BA097BB0E28814BF5048F4F64E6A587B0BDAAA8A1B3E3E69D3D7B6782FC42474773C61DE12B4C6F183F9E625E337EFDC97A79A5D2C0C939FA668F440688F7A3E0E28A33D36D331069294DBA8BF768010AD93A224E28964A780304F59B7994D972832728249934B5347580C16BCDBE9F84EB34EA7F7645635437B0F5422E3DA99EC2D53B22B1A55BC783CE86CC6B1BE7B11F837CF2BD09A514B12ED7CF0AFC2F70F1D6D08288524263B1129135D664A48B0596C4E880E4E01BA3889014C07ED1B7F172AB4F4A69FC8C04F0ACE8AD1329A4FB594E9EA30EFEF31BBE418CB5515CFF8A375CBE58515B32E799E8449101093A053EC99F9CF78122FA2D36DDFBD258EC81D7B4D18BF882663CBF24D2A35A93C00AE8EA81A3B0E8040C1E259515156D67DC76602924BA51507C4994221A3B1CAD674BECB11574212EBCCFDCAF6AFEE288BCE11B7FFF1D7191AB329B04A237F75B204634676932FB0842E2AB888E7D5A4A6B7F77EA04ABF4B9A567E5DA5267F35CBBC928B5F607E9C08359F0031A934152D77E65C937181C92EF4CF17F6EA45171DEBAB545755795097766318CB132ACD96CDD65777F41BA127CF251A4E9B3348927757A42AD8FA83F6CE7342D935CB54984E45886D888627F0228E50082B85E8E9DDBECAAF049C25C4D7B2EA919716271500D81EDF574C5AE91E5F0FAD7585EF69C5051473AF913F887B31BD730F67B4A44081BBD567B57C061AF465237374E0BF4753F3C6CA28D45220CCA3EE6F07F93A29982EB5AAD70763ACBFBE55015D1C52B64954D4855ABCC319DDCAEE75CDFE3B3C31C329A77C76131F18F3C3904B3EA4E691C03C32CA5E7A1F9460760231473115B5AB7E159013C96AE4885566065883CA3B9661C6773B77819BC68755D529FCE05E80E08A5097EB37BDDC1AF9BDFCD0A04", - "0D4897E7FB496EF0C6D62C034088E7E9B8DB52F232CDC9EA88429655ABE366C54CD534DC9038F45AC0D0362E31086CA2FC0FCAC3FE71B2D4EEE548F69CE4433601CD3431D01BA6F0C23D612807EB8E50BFCA736D917F67DD72631BEE8728006D2AE69D1A1BAEA8DE50852CEBF7491FFF989C37A54EAE31652230A0D3E4397B051222C4A22BF481BC52E2012188C7576A7ACE81185C85A2E841119B47B5429DF277A976F15D5652156445905EC797729A6647E1B593484ACF2724E81786A0C062DE87759E82202A561FD077D64FDD3226A1E290F660722040EC7AD4383431E195412DBAD0AE620BFE808D65D3937AC9C5AEFD6FA106C88A6B192D4FEC1FB1A06907B0796F724AAC6A5EFEBF50C168F990BDBD6B1D23E098858C07E8D2144532AFE040E45B25AD9AF7D92F9DCCBFF3DF25DF574A4B65A219289407EB63FF7152BF1E651C6F124BE32545B50E8E2CE37F1042A68A62AB70D9DB540D2B39293E008EBAA632B85EF1052FDA17A07B9B1D89A76FF7E7EDEB7090496855B29A9174780D504F7228F8B7436F4676F51975BCA614554FE6B3F946F5E0D1016371F9CEED4521477CE8E9CD0668643686D8482CEC0BB4D6A9E8678B1835F0952E2700FE0C85A8683DA91638D81A85231CA4C7B55C0C0DA57DE5E6553F22290CE7EE72867285D096C0FC16A60A664C6BAB048939FF9DA476024235DDDBF7F264C90ED44E953C4AC0FB50362FB2CB4C4FC2097F07B71772000D2C2A5DBDF0B6FB83B1BBD70CE9D6A8BF1F924AAC4DAEB6AADD891A8974C9BF46FC6038F6B77D6AC0D6107AE6AF5B93B186253AFFFD8CD21835097C4B764F3E0B2447776549D5045E4346FCD3B7880F1B3BA794ADD6B7F291D3534DF034F822D0A41DB2AF9F1E51F212D5631D2525B1804A75B50D8372B6A1C200B81AC1122AA3C13D7463C383FD123DF4029BDAF6C227B3C4B54F75C5315FE139F6A0A3E2E819D3062B3309E2630EE4A64D1E3DBF23B489B96E198BA98D8D3347217A5FDE4DE453012E8564BAEFBE3939E59C0A725A75CEDE373501F9103011FE0EAA40C583AC73C92F47BD528600C42E0029FB3A4F03A3CCE87E5AAF4FCCB47EA8BC62E0F542DBD455F7163A2A8803583896E3C803C0D01846EBD8BB1B3FD396A7C7BC3F72A9D0503C44FE30E5E77E0FC8B373EE931CBF4A9867406BC91972B946B9ADE62415CE2FFC71C2E64DEB7E6205D635977C778BC40C11E36BFC22A17FE641346C74DADD255D329AEFC2CE5B4AC5B195FE2DB453F1B41B3334D5C480BBF10FDE88C722091ABC85667F2B52A3505A142E4D1546CC41E154B345E8456B9CD0E241D70EB4876A70623DFF3FF43A8D66EF60488A7860485A8E518AF4A7056CD02C72E1BAEA3944781642A36932ABFAEE3B88B57B213F9B358CC3F05154DF8D2132A74DF27556DB6C5E45256481C09D18DA604CB91E6AB7AA29C0C1009A406F1B3AAE268564E04B07E4E9128FF02513AB8A8665BFE1E352F46DBDE7870EE027A6E84560014659888EB6AACF993D7C9F9FBC2974CAE290059802F5D224520CE445C404A2ECC57CE6FD5961EB20DC12D436F0B93614CFC844B476D449416F54459BAD09F886CE3C1C307A91E62FC736051E6F6F8F5AD3372398458299EFDC1809997FAAAFDE14B15566B381714E3522F629A5ED9DDA1EF4B9D4498DD55F8B0A48ABB2F9B1FCBD991B5465108147BB6125FFEA6B6D479DB6A9983A51C041375B39FE6546AB5B5E089DD7E228D5AB17127A3A1E3AE82A31E952E660F72A1F399ADEB4E1E11C390BB8652F2F7B6D05E9F4B6FC90", - "AF6D254288BF564C4663014C7A70EB3739D28F1F17B8627FDF714E85B48EEFEB1FD456546328BF2E2EED112992AF78911A89E1248AEBF1F79906EA91D41CAFC6E541D2BB40A7050C5AE4B66547C9DDA88590AB8B0A4B01B5F8216447A310D1E52C155F92659835F1086D381F1F2995138856DEC6FF59380FD6C1B6EEA6E4061930CEF7217701DDFE17742721794DE824377392AF3D949ED9B0455C58F7395DE0FDA5485E310E8457A4270D603BA5AD1854811530FB7178525F4BB1E5DFF89F6FFE0C83C3E47E244D8F3F8AAD8374E3FDF996060E18D2A5397192823681CE6DA561816C0EEC0C0600732A37731ED13948439E8961BE44D32A3097C1AA5E19876ACD21DF812265181774580A8C04ED4FD1DE2FD5A1DFF9DCDF4D97C448BF9A4DACC22D4A55F588C87CCF5C9E178A8FFA032A454908BBE41E13D829FA98C066A7736577CDEFC6D5441656D0AC95C872861BCE0A28C2ED6E9420D4D167F37F96087F9E761F38B882CD41521DE8E2C40564C0E001EDBC04982669B82F05CD0411A6BADDCB704B545FCB19A286BFFAF0FB6DC889BCE75C5763BE1D70DCAD1D39F395A75E637E0663F3D5A855F53F700AF5F82124E72CC2A4E41A4B43FCBA41E55298A1B799368BD5F9B507FB11E8BD2D80FE517A5FA935006064278CDDC5EED43B7C2D309BECCCBB2C0AE3B8D09509315933E2DF91304B1DD3777EC9FA2415F7D18A96CD08095A30F7EB9BC12F8739E409EE7DC062703CB3EA591531F47F5D1C0431E9F1883C3BA249492EE619719C8B3BDFC1DECF7E3C4CE4CE032FB2882247D1D54566E3819464837C248D35647D273A87F8BE667760D26A7EA1FFA682A931A4D35F7407FBBBAD725BEA62449623AADE97A2789F2F8642F1CE12A06C93861DE9D27C5ACE0E4ECE40B58664176113ED6437B8AC8B4059653EA30F71A023544BFFA685343E278129DA12EEAADBDD5AB0E2CCA0B840E87AF0D0E859449893276B9B5894EB0C57C3222E01E7538FF7E91807C10CDB465A12CCD358151D96856C6143C9F8D25AF8E8086C83D4CAE37BD660D15C0C0707691E8366C4AFE6DC0AE1BFECEF9BEF46CFEA3356A3155E027D1C921ECB852BA4B8FE8E0C8C00829CEE4049A21A1C3424D2BE532B735232D12B81C3C9E5B02294701E6BCBC8607F2AFCFB2DD9B1142B4D261418C1B239B0B22451D7D3AC64636B0C7F96B41D7E775C1CFA2E277C957F0D59BD1FB02226A462533850E99E917E310A684E81634F3876D6AB32CB5B8FAE9E82224BD2A17A7C72CDACDC6B3438A083A6B0DB9FD91E05BF4C83A36916EF35C5D4871E94B1671493FDBC497BFA30328DD24D340A07A960828A855FA95EE33FE4FCD15B14B7929D338611239AC34CFDA6503E4DD9570EC339CFDC8D1C3D3536F5176901D012BABB133EBB4560484344E044F86A77C21183C82BB2B6632CF69F5A661C98EFDE5529F8FB965DCC6AF185CA8CDB4D01C5E8902966B063B8D1724AD18DAE495AD47416B61321DEEBF782EF7A6ADE3CD0D5B9ECA84DB5D50C2E5C7D8B8DB9E0F398376CDE3D7E8DC46F0D77D38D6CF6055D6D074CBA92A27C6F9018CAE87C97F1B3ACCEE495ED9DCE46DF4FA5255DB2C7F2669F5201058E90F7567672162E17D5B6D028C6AD23F2AEBA32061E6B33EA86915FAFA2344CC58162C032CE837D5C32F5993013314BD261DE6EBB35B94B8F690C5624A8CF5509BF50D3AF5FDAD77311B6D6F9398213AC1A267CAA0F52A262DA4F85F5ADC79947D2C5128B8E0B0C41B9FDEEF6AEC228EF97762CDBDB78273C16C39E446576D54A4FD0", - "4B7593A9ED7897766CACD515D3A55959FF99C1CE28A745DEC1D8F2565F24F4A1E14E9083AFF510F106D982A2911197338499CBE38CDF3D99463B13EE26B47D26A62CE45EAAA04A3E70850D5F23470FB94C42D3235D5FF9E6C37CEE8C93591CB69E0735B03EB262CE6BE6F0144DFD66BC089B36D66287EA588C78E39D9B6907EFE85C1211612952CF13C369C2AB3D921E4630ACC75F2AE99014776B26CD1F296F736A4616FF662D5C6E18C4EDA6D1791A71BE969556FF11E1192D3941F8020D2C731403ACD856A3AEE6ED7F23023BAD7BF138C702B6449E2601042D7990ADB988B650AE202F3433CF26EE132A7CB13650E86A6DBA6F7FA53B2354DEBF1268734D7120F721E18FEED2F93C268A2D3EA012F3D7F68DB0B18A5CDEBE13CE4A05683947DD985D4AED1E192FBD2719755846C9B758FC8FF28B9999D07E634645064C2C9DB4CFE50BB8A030B60F43AFBD588EC17102F614D3029FA811457568D7726C651C062391A2EC2843A95A3A48AF58A898BB65FB852F73E9A82C6AA9D406D80C072A3B426D8EBF261BF7AE0E9DC0C6DE9F4BEE880D775783F910AF19DFD8EC2656213FB9B74EEBD8E1BF860E4650D446683B7794086ECE1E2AA723024C219E3DCB371624C6D721BB60C797003D89096BA0F489D1CA60C57AD907BFC8E97F4E057B6D709414FB0A302D3057FB4635F70BB6A32CFD842DCD8D9C9D45FE082B3746951A862EA870D903382C138425DF936A505120D93FABB8F523C1D3946B85425FB338CA7DC4B2FB6512F0C8A67FA47A416284EAA943E1A9C0607A02D27F55F1DF2EB6090F94B64076FC2D3D3B3694DA5C7EB2A180DEA14AEC21156E1110DF75616685FD53C72252FB87E7D19EF5AE8D9E129D0984A06520C789DE22CBF6E2271801691E0C3CC672F6865A41559910D0279AB9E0112E66B2A1C2B22B6679CF70E3FF870084562ADB36F532E64D44C7264E44D488076F7714A1089526118D4655FFE16B02D803AC2601493CEC3AB27878CE95ED3F321913217DE12B8E5E8FB75A85707EAF6F1FF08CC86B91632ABC7CDC42D1C5D0F2F49D5F412B4AD0C5C46CFA74643C9333C5F3558DC3ABDBCBE23A3573146D648D540116136F3F29E42FF07E26C1504E47FCAD1FDAE63357E421E46440424921404ED02FD4BFA2FDE68CBE6CE49E4E120C141013DF5C0BDF776EE36FD5899C0FC057DAE2C9DAEF6D37BF8E85258BB36B54ED8374BDDD49B6AC2C8BF3105A194F76DD512336EAAFC7BD2054AF6A9606517DE03AF445CCA5FA65307D2E116E42A3676EB6033AA17D76A87F52D144CE25E3A8DAFD3E044289C4600BFAA9CCD963D14A19C5911C3DE649439440D11A21154EF25649F7DA295E0FDAE8C48351BC005C011A10D201B3062492A7CC933AB5D854B26232B7091CD0B7AA3135F28E3AE75E267C223C5E03B60FAC1BF78123C5AF76719191CB6BA277A5BE81E64117AB344D92837B6D600F36702F4BB4532C5EB1C9BAD8A111C540F52A225DACFAB37641898B1FF770A523F8BC8BB0DADB59235DE055810396F1993539A9CAAB622389607DCDFDD51FB67CBE89F0F868DB4D27A7A38542A076D158919DCB621BD325F23AA0DF694C444206FD42192FE7F9A05743CD54D8F111676AC35A3230E372A5A6D7E213C4584EEA1A4993067FD28DF6690BE9D3E94AC06BCF89BF1AA47496F8F6A18524187BE80D59A4E80193CFD757B706AD483A916AFBE2A56E0A69F3B1BBF9F4B239D05C6C556A8D22B00E9BB1FDAA620D949ECDE86EAA299BE93A7884C99FA782F2BB3BEEE86046489B3B8A5930", - "71BB1B2E833793D854F8A9A81E6A6947057B9571F2BA99380DDB25D878D6B48F09ED7DBFACE92B6B82F413E038128F6128AF3BC467E9A4DF2861DAAC674B6D948A10F28F7D43657FEE26577AF438A2F4422186930702EBC6C9173E661D59CE7594DF95B861F9D12EB060FCD3BA43159C9A1BDC1EF13E04893E411267331588CF4831978469FF569C1A738C54001BB5CF4FABD289075A165EDE0A58F6CF6D215D306A7840CBECD0E87E3AD186F7A67A967373551E13D2956E5C578A7F5BD50E2D570F9B914848D46A640913EBED2E2ABFB86916BC34EEB3E8A671AD771F6D3780B6FEC143E26F53B02977255314BAE9A2CD9E5BA2B49C73226FDC724A859F8BAD3A9FACA1B0E5F2DFE7E1E45DB6D4BE2B76535A817F94594A4541C01BB62AA83A690B6D84FC13B632972C61D940F2C9D32837413AF8E42045ECA3072CD044B2183400CE63C418879D13FD281A8D0835256DDD2BC3C9750C1D44CF1037FD7264B7716398FCF1D31CFFD0B7C52C6370E4CE6FC163B40436490A757465B20B8890C3B5C0AFB971ABFD01796569E3BC73C13D1E4B1FBC1CDCE59D21B6B110272E5770C589603FE67779A49AD0EC66910A2BF4D8C8ECC18A32EF92F502126A5DC3DE618233B9914A9608B2F17E5161115D9A3BEF1D5701A9D465A1437DE24371C9179800CB5728A7F3D734A2A706BC64D356BDF591389970B6CC139AC510A98E3C75F20120450CE45373AAEA6A279BBD17221BCD32ECF82C11B4C1CEE0A44792CF56978D3D2399F7ECDE9F8D9217F8BA22770E210D0F1AA852178B872E296762873765A73DEC08873C04ED69C995C5751B97DEC23B94CA674FE3F66211317B074D8203EC530A20B6E6DD21AB55895BEE1CBD0876183D652F4A0D2EFC95749F8F192F860BEA534598FD709B396C209CEAE4D9190980733E7E98C8ABE52A53C68D86053B56BA6FCAB5C827292D729CB8BFD1FC8CAFCDE15E4527B604018F28AA16C1E913F55461AF87C9A7BE1A742002E52B3A14EC30B259DDE7BB892CEAF77D25B7670B339B334878F697C00CE6740117AE7C67DF3F8A7BEAC89D4872682C47F368F835AFD7ECF0D8471AD01468B7BBB0A974EC469A8F79ECF8D379DC13685D2A8F6F19CE102C3DE34B11422AFB42E894C8D00F606296DABA7123FCE039ED27324D60E853BA94DC638454088281335D437A954333FF1A8D08E2A4D25CB3BA0D08BF6625E25EAD3C1EBFA2666AA49550578D3763ECDCE81303B53F18B00C8900AF4E0532C5ECBC94513DD9F50BE511CFE4D3DDBB3F112AE148DB062B2EADDB901CDA6AB6BF59D37F356AB34AF97D3DAAAA417642E87C9B95AA546C682ED641214605F82A4F486C9C72576106F76D7152615EC8E77187D4485071CFC6B0AE44880442790696E057A3AE20C860691353B3F6BEC5F1C2DA07563B423BC01E0334099571158A432441256D7C409B7B6EF26442075ED17E2BE37F8EBC049CFBE0FA89CDA7A58DD32C417B34E899FBE86E2FAB8D30846DA17144A6A66AAE1C24FCFABDA5B573FD2D6337226B5E49BB031B4D2B455B6DB871076F67AC03C3A73CEC01BD0B1EC42ABD177127E62A66FE8E475B982B4490F0877466EEFC7317A703C5C07937340ED4B53E5DE5325197FA31B8C8E05AA2222064EE5D7C06D4A1EB53151F75C94A2E259688CA0716548465C5C255D81FF10BACC2C13098ED8CF7F5B15193EE14FB5D258E95EDCC93E9796FA823892C705A5771D561787C12592D269D657FBB71F021F365B7453D50C35F748FB2B7F36DF28769B81EF12A26A237FB0239C173559540", - "53DA0E7B84741AA9E225483630169ACBCC03EB8CDA28B7BDA685C756D66B14488A2D0AEF7E6CB2D80F2726327257B7284B93EA1B56AB80FAE668C04FA49FCD658D896A997685E1EDB4DDF85456B37F32FC8CDE50882EF0F09BE4ED4AB9A425806A49E8347A42A50B38FA8D1DA2FD2C9438618B6701DEE159060C186D50170F24F38E07B185E3272EAEA4A0A7CA41A69C69E9D95E271287D3AB8284146A58440EA131A7F47D73CB2BCF40FE3A58E1B998C2E5EF9CEEC8EA2F8467BB7757C03A99FC8F014EE933A7080CD46625A2A7A251B7A37E4208956A8C9BD35E6F8674BC06FCAA5DD04A2558C9665C7985014D3AD95ED256FAFA358962EF5BB26AE2FCE899392DF858F99303E2417BCA7672E991FEB891F5DFCA2D461148367C5C0DE1460BF557194533DAF01A5E8E0E43D57B825AF7EEFF163DAA23B9F95C063A26B3D213459D885AA96023715CD21DFA2A2250F7610B78A77123443BD06EFB7DC85D1F16D0019D2937C3DEC4DE6389485ABB21642B6E41ADD43CE96F228C08DF6288A647EC2FE96032B6DCD651FF950B72964EE08FC2030272E3F601DB7F7E770E655389CA6CFA2F9B87CE76FB0E0CDCA4EEE5E80FC756BE46CC09F84BDB34ADA2AFC024ABDE0066ED939F8EBC236CB3F577C1BFD741F9D101A038EC86AB0A85462BAFB2E484D6722499A6310FA449D979030B2A21206D44225800BE2228FA00AE6D92C8DA652E1B003BD2734D30557B735CC2A591E090394DB791245C22B4D29E706476593B6F90C694C5B87BBB0FA2C479E292A768A9687A713336A21D1199186F852C41F586E9BBC64004D8BB6814BFE739834C99923177AAF87B926D56A7AFC0879C027332A60951C84E9314380A5A78E1196D094F15D856AA36742825D2B397156BCAD8ABE7291FB41DB4365AAE49CA82CA066D3B4366D3122ABBC00F05559DAFEBA9F98361DDAEF068D60B18265E7184C4D6BC9C3619CFF5C758090FF6398CCCEB78176D2A8A2A4B9854C4ACF5CB614DC1CA0E15E7E85442241D48FD3D6E851A5D3947FA769560928948FA26FA16EFBD2159994BD92B3D6B0C62818C91D4724413A7F40B2A2D67F4FC97B5DF6A7E3CEC03158E201D6643F402D3DD6995A42900D46C2881198CAD28A27489F5116ECEC3E38D999B2020E0C381DB3B8230811270D75950D9BB61548802DBBCB68ED8C7BCCB50D606BE400BECF873498621E66ABD2AA179B3E90E055C3719CE2FE047F815B95B065BA086B467AF4124E276F8CEAD000BCA5499D36217B250009A7B43E81CB3F8B1A3238EE436FE61F2F942796DBCBE570BB4FC783B35C3CA31BDD432B33AD75B08107253E8F910EFE0D0B5453A8A055D884892278688B3ECA612452B590AF38DBDD9A7070C5610E7A3CA6C91D24438E7F45E7A2A330F164AEDFFF1789D5E875EEF121298DB79C77278ABFEC3FE3DF843C46F40E847272EB2669BABA808C38E31F13516D5066AF4DFCDE6EDB2FF0B0A4CE9FA9B4101F6F144B02384868617CD39175852E065473D6F566CD18D7403FFD24DD33ADDB52C7CC22167E49102C46DC369A92CE2D2FCB81B4D1F14B7CD2F80A65D8FBD20FDAA23219873ACB8CF934E68D6F8FED6B41193CFAB1F44CE4BFC7C67DE1E8804B47DFD7E8AE281E19846AEB6FF94AE7E7CF6FFAB46242843811E6C5BDB78157C76DF4F92FD3653D7FA5978316EB055059C6A2B6306C957418860A88F63355E76D96F4727128D9B3EB98501AF5B093F2C314F98EA2CDB89468E1BD51138CBF25E8B911C26B97DCCA47F1A1D6C1CD415A5079A756B8A8715DD3164", + "515537AD5E5F4216C16046FB0AC50DCDBE5CEE7E3CBB51B6ABB4E87A407B90E0EFD49DE1DE5ED29184E7FF0DC31F75FBB94F46FF6586B36C7771E5A68D060A965ACCF8D640C6B6E4530FDF19DD2491BCAB69ACBCFD3EC7281CCC31253A471B652E21C4CB0B43613EC542266460F0A6199B436BEFD95572DEBEE920A915FD854D17FFD0DF8C74E23B21B28493A0927709709B07C65878C43B69DC501E9D0AA21061ECF173876CAE708C764435832D9D6FCFE62DDF2543016D6325A56D9BF1007886E62E8A832BC32063CB0717D723C5E8C5F0C0EB3960577D364C93060B64EE04A539B7601CC3113E0AEC53CF21AFAD0154DC5CCECF038474E0F4004A65B1EE2801F81968B88C3D35E87CBB126C02D770CC3D32A552883D351DEF47847391484F80646728221F993921BFC14126EE3D9527DE607152724C6D2DD305D3FEA0AAAEDF6509A2FE3248494A54FDA8E3CE7E6BBCE234E4686BA5A19724BA2CB78CFE71A6AF45532EFB286C5BB47BC3C1EEF4E4A8C757786AE974F30A86CD60EBCBFDF5502AA8F643819CBA4301E731ADBA1345B61C0B444FE7B817EA86F8DD749C451AE7D24A68D914F26C918238953E8AE61CC8553213DD6856C7863F9F6BAB1B4C84B225911E7B92BFFC12AC211B2B2CD905877FE976E07057963D47C437FE47D89648053F81AC39E8FD2F3A726866F6693E503CB6F0C3F0AA9B3EE2EA3BCDB16D726E1C6D8B073AA15F64EB68D53B1F8CDAC19C7AC33361226E81F1C793BF188755A3FE1BAC38B91ABBD4F077F7A28983EAFADC346CB941D49492625893453B364D07FE06FE42B160C16FE0462AB6366FFDEE54DC9CE4DCCA21E4E4AE5E92C872D1E4EC6FF6D3063C98A5AA5EE72481A0BDF15152E2A5425AB722101474D0E1EC8401273EA1BE1DAF7403190A94305BD1C7DFBE1F35F65D5CB97E82B7A297047507FFA0012FB73360FB8719C174E78A989A96E60A9184B3F3A8188DE100AB361921D38E8142859C8F0F7D441DB1B2E9687BBD1086643987C83DEE0BE8CED4C83BCC82B62B45311CE4F13ABC55BF5EB1ECDF15F5A07F8B2C42F07FACE0E299E87727E2D534FEBF7B9C3894CC3E2E4127A294B9FA2A671273B174DBB81D247CD2846116500A072DC3962C65FFECD0C0B46DC2AF52882058259C26FDE50BEB319AEECFA1FABA34C069680B9EBAA9D96EEBD7EA30E748213E1283396A2AFC63527624641D4E1F1022A973B1898BD4CEF4D712B49371A51D60E08F42ED1EA90AC49EEFBCC53E7F9E899DD1AA4056F11462DF1A4C81620A73C831CEB897430A22252B901EC3D6F3DF58EF26422F796EA31AA4E0E9CE5B4A9C312A22305E298FEB3B3628283D405EDF726937327D90C542434BA3B60684584A9DB244839D2ACBCD7EF147A541E35687B5B8F5F07764973112D20D1ED75DC31F6A938542B42EFAAEE0F11B0583AA4925C3132356200E8D6BDB3127B975F4115A7A8A1C471836E3C5450B501A24D4A1308BB319AA827222B550F253F64B6F7D2322C6A2D3012FEC265A66A60102A3340CBDAB900DFDB36693D41DAD8DDB8875F8C3BE76AD5355DD81D67AAEBFFFE9458E522BE0312E60F63DD92F25C0D7CF82F223AEC0BD7456752CBD5151FEB5368F8857EAFAA90E8C7499B75D46EC4CA20BA8A24C90C016B5BD2CD7864828C6140E98EDB9509AD1194F56D49675D077DE92CD481B469E3A37F7DF0D5392DA4CE4CB282530F1C73482CC0926B877B00B0CE49FAD21E4C26194C7E950E0078F3854EF88755E08E9380165C584A3DBF1ECEF6A31B224FC321326B93797BFE8", + "D67539AFB80711A0BA3CD67D963BAD346BA813D35A2EEA104D36AAAB863C656A07AD61BA60598C07744D32ED01EFCE928346C09EAAC2D392E5655F0FEBC486815AE30A38014DD8520F73CCBB71D9D42636328A50998A2A3BED3E4B34D0DCD65B94807064E2EF0C420898DB96E3B99EA9A0AD91C63857DEAEDDA5E644E62212B23D72FEDBBAA78C6581C677B10689C4AF387626DAC55F4EBE1893D52D28D20EA365702448A64A0C553ED337C3BB911DDAE2A91727299D8064BEC880183064574B5E3631E70A0590210143F4079C572BD5E2F7634C2D53B1FB1DABE79C484799E7075EFF98F033F5B2EC66C373825335D883911CEC9CFBBE2E38129B7E03D9646A7E513D5069043BC62AF4C524F12D8F98D8C9DAC5D8642DFFF48CF6737AFBBCBE965925F55F03BBD5123C9DB47AAC780301DE91FBED3C01D03E6464C2C2915BFA187A4BD93E20C24574FB91F0358CBE0921DCC8D6B7E9976763A1D2158511861EFF5D1C0B71F608E7ADE91D9DCFF5640B55BC9BD1BB322C879C7EB5C06EB2601D06241D09CFB1BC1695DFA55FA044E0E2E4BC86EFBF6A55740C4640512DDD6CA069940BC0FE1738FD376C68BA8AF7CCBA7D89F7966B29355538836372EF418D149EBF3AC104919D91BCA2F13E79A7CF7684A4DC0AC556A2843E041A71F97C94B859FE009659F593EFFEBAA6F6C1C57A5BF22752613AFB26379C42AC25804AEDAE22D63B230FCB858F496B8EA6F37104D0890525DBDE06AD988BA0287B0938572F14A98EC9E60E973FD693DB1F2AFF671AB03FB12B729D0867938DF6B60EC69790C992C6C33A531FE56D0ECC1465F65E3E57FC9E45F0F65A1061CE6D3190B6C1B8708A8A5A47222369AE889D26499CDE8F0548B8D7071F2D4DF6C0F2418BE449552327981CB0B54F792F29A71E30DE257CE1B3A7553A22275E4C8B9FAC3B8D4E9912BB22B0A899E7337513C7ACBEDA15FAD3D6919FDDD941CA659D78B74FD39E2E2F622691B89CA82FFE602DB2578A20D4665184456F32DF4DD6CBC412EC7C6914CA427CEE02F6D9810AAE1406DD68ED3869BD8E3947A2B3A803E875FF82005D853E3F43A6BF936030744C34C8B71B7722BE0AD3F475E531C9249A42671D5F3A5C77C4C28DE29AE953EBFB572578B17B636F8365FC755C22871E7D53A1F1561C92909305C9FD36AAF79E8844B63370B800B25CC1355211D9919B830A988926829F808DD2C66400279E6AC14F8EECBBE8B6E9ABFA3BDBB38A49535F64F719EF48C5FE6B2738DC6F71AACD70274FD40A29BFCAA594AC3E7D0C3C522E406BA6392444C9F362339E8FF34BE330911DC7EB11A47FF3A62A46CDE961A40CD5B24020909E5B034F45FE96CB156FFE8E2FDBC12A7C12D60D24BFBE596544E4F03AF26F086A5A667496B7DF302E4DCFC568C7ABD665EA7EAD8A7F5A000DAD9F43E68C4D8A14742E050769B3CB270E3856D7E8F4E827046D3E55A52F0E02C883881914DE87AE3C24D93E61A94919B40398D3EABB1B5142431AB919208A9785962D05061EDC951C83C73FBF6AE8DD6FF839E631C9FCF6635FA053DBCF932E359F83FBB3EE310281569741E3A8975FAAD1E573E0EC3207F6DBCDB8CC90DCA1CE517C8DFC1D31AE4841F87A5157792738DAEE7C29240DAE26C6C3E9D8A899D2271B0C374BD2EE846C6625E31B2F8379A96F601323039D281608A01A1844E5D1D20CF1D92C52107CDA71BB3B7EC4DEA958CFD7A79F71868116CD1DD2B2E66BB94D1373B733F324BE489DA51BE72B01A8572880AE1E61650B839D03B0192D290D5B36A9CF93B304", + "58B2E58A13D4D5F84F37A389E6B01DFA66DBC6A25338B2884EF08056BF0A9124DA29254AA79CDF1B0944DDED4BC7FE683EF7A3C7A1C359E61E959471E30F9D534F43EEF274AC6535C616ADC7455BFBFF43ABF268F7C995CE020CEC73BDBD04007562F2710498AD1A324F25A6233B2DF2D9A429F1C39943E45F934986D1979D293F90CFBEBE01665C98C0D72D09A382348136980B31F5D4696B85C3F42D5C445996804159CD4C4CE7547C4A3FB718AB62D9E9826D05C44C6BD21D708CABB01F46514F29FBE7352866EDBFABD0ADBB6093E1A519D0E11E27737239A07866752B6D864686AF1E308481C53C635046C0756E8008D3CD26DB970C5D6EF8CB9DE6BC4339EE9F88EA45D11B74A1525E2F1B9F91567A78E403F7ECD47A99E95C098870B928E1B0DAA984CCECA13C6857F350E808BBF66AB4EDFB0F369F6F009268D19DEEB377F7D0C4ED6414EF6D23A0A5F37A25AAD3CD62C2115CB70409049CF0CE6D4DBCC5C96767614C6FAF73E9A76C7550BB970AB3D3ACE0C07FAA9F36F1935DFCD5228427BBEB5FC7A2F951D9210A5BC32ACCA7E78AFD5FD460CE2A79348714E5542BF2D453680B070E85F3244E8A6B4EB6ED49F803E60B8A383C8BE6283B1C4DF79E0C4A23D5DAFCB26DFC5DF1D1520FB6CDA23A05A1513F751EBD0143C2B9F5494BAA74F9F95F189C5767C6F5623559D9F20CC9B9C9ADFE285FA4E1BBDA481A52ABAB36A5393370091A49A59B968CFAE89BEAF33BCA5C2A9BCC1758CEEFC2D0A175C8A5CAD5C7E3FA706C2FEA55F4971A7B8A0C5D1F22A26D7DA9A70603AC34566E4929AE78C8F1926239950EC0A6E1B37D919E24431E53FB08B2F7DCDCA2EF4177BD7D2F81BFC784FBEA0471831CDCBB9E11D60C53D0E062E8BB8D98B8EE5A40960EBE10FA642751B96E1407B38A024DC64D5C2005E71198EF394673A4A0097187D2475CF27B3EAA7955AD9F412A89B36AFB27FDF7FE699B2CC8C03F7FA40549178DF8A3C1A39441EAE869BBC89D583ECB18E310885F33B95B719045CA6955720CA75D5CF0B29E5F1B9E9EAC5EC92980B2D37EF6509CCA6E67544A8116494AC7EB9032E1E8CDB053B5AC0F60DE59BBFB78E3491D50C7ADED95042A8885FE284E90C04FFC0370B92B68379B2E7D52392A42FEB26B2419CC64412BFFC036C01109B9EAEC5FAF485F0D61C37A703EAD02127611F9D25E4EC515CABE21247156F0779CAB57C35581646BB71E87941AB5D06FB3C06C423E9E83E0C07E611C89CB000344AF49498EF5C30305DDC8958F45A45E1218837269DEEDBB0AE51D2AD8B41BE425EB7AB798856911B6F0DC721756A8154B9D1CCD61092D16A3E9E1CD5E1D7C2C45D236C9B21A0ED64AD4C0660FE42FC0B543A34FB545B0D88D42F696D53BF54A1A259486846E81B44C16EF146310AEFB3933BA9F9D4497E74AFE1449D69105B9F295DB24B4563C3FC0166CB70F104B3360BC0998EFEBABC6276F570F7679865036DB59B51AD2F91C0CCD3BCF5C07492765D480494AB5B87E83FD04B75A35F88656D3329AA5FD550DBF493B0CD2C19DEBE4358661C72A71FB17C812F75BEB61302AAAA1F757288C1D8626461F4162A2EC6296B3CCABE21B4F0695F2D2CB02B86035251FC9C5F2FB5BBF28237417DC56471629B3B4C25AFEDC4C9CD108ADAD9DB1330AB680E4998C5B3D99BCE8F08156B630A63EF36A51C813CE22A6B178683EDA389ACF58653582BC2AE8170ADEC4BE03C04CBA603C0E4572A74BD9599A8442E894EB504F7703F2353A8A3525EC5535E750303AC07E08D952755F97AF236014", + "3059141DB31B84555DDC1C5F40372C50BEF6E82B433D87603BB7803FDE8FFD74DE06809357F11C1D6ABF02D4DB8EBE1D5ABE7F30C91A451EE3C1AA36735FAB9185C785F05D28BD470D433ED4ADDF36406487CA1710ACAB57EA0DD577A49C841F5E78B70FDE90BC1087E79E27E53A4B131C06BF33843BFEBDC0C2A207510590E52158C0855C40146AFCB75DEEEB872ADC5E77CD1DD6A66EA96CC223B3295C136E2766ECE9F2CB807C68C84FD04E0A5179D58473860962083DA8D68B70DB95C0EB91679CF5E1BA468786725EDFB179A2C5E7C28B396A53D89A98C7B79867E240176A9DF9FB0BECCC22A526B617CB8FC2B05A8DE411C8C5F9BE682459B487B26643FA894F9B3C97282EAE397A03DD15F07FBDF7432DD95D29E6D50CE95860BEC2649E482F40F7B83A13135A7C71D83ABA44A363C864BCD78050AC69A8DC0A9E601859087DBD49AA01A75053792F74D9A8EE726608D1F009D06363F6E5A463BC362178918737C5F3E71EBF130691A2048F07F3F8CDAB70C9D0F7B9A1180046076E1B894AFC620244B30A571DF359C7D60969A9436F05417DB5759B2D3ABDF6A238B5B5DCA8A0E4C27F7078DBB6600FC0105463E745A321884A4F6C5963B188919EC24C460F1B9CB9C063B2CD1FD5F49C06AC2E61EEA55056A6ED08B6C7C750E30EE66508FF243FE1B5C494E8EAEE5467AA0ADEA834523C536855D3BF5ACFFFC0802365B3889C31910A5E63B9457E46B4B7E29189F1BC21E7950BF9FB44BF5D76078D8602FFD986E1A1F1A74C677BD8811FC6992F39384CB3F9B2C91F381DC01D4E79D2E66E6D76796728E0C48F71817ED182759D8B10F7B5D361D7138CAFBECA3234B9F2F4A76FB00DEC05D67FA8E7217E488688CF87D59AB4FE7B13C793C1A1711C401B49C381F76B5CE120BDFDF30A858DE62A3F4331E4A3CC167030829906935FAC167A7327B5FC0527E014801A27FE0F2D40EC13C66235EFED070979576DA7268D1871E8487C4DFFC62D27B83488A73FDDEE1470832EAEFF621CE8E126267A47EC00773922BE480C7F26C8E4785D886BF8E6518DF13DA86BB2925A432D479E8B8FA9F92442891F71AC7C05C0BB0E4396158A492BD49E42AB4C4737A952D6B2B2780EAA73DEE13037D659A43DE1A8F0E525D7F96FDD1629FE51560F77E4A1CFE903DF0891B39F50B71E0F84965413DB34B1EE95CC1B6728AC3D1924B34D1BAD4A4E4F7D98D1B938C567B6F3C95770068775F78EFA147ACC619AFD0B6D8C66034C21B2991419217256D88F265922FD49B4BB38D2955305A8D01D01758B01134196C525315726D9BB6D77917A57F2C46A05DE91A3FF80DD2B5AAAD899D679EB55341FAC6D5C2E9C6B703806E342B2C11CF84B394BFDFCA378B26C7E0CD23C8A87B7CBEF6828D9E023B2B7060A0FEEE0D29CE59B379A02AAB7DFCC41A35CB9A94408A321BF78A54D2D4DB0E170101798F6622D8087A2022A993E85DEB5CBF0F4DC2A047877EEC9DD145471D57015DD59A37BA60C9BE39A4AFB92289562601BCE8102C83292E2ED842470D715D34F11981BCCB81ACB443FA732F792C5F11B7DA5D1BCDD84EB80820EB2BA3813F5E6EC5300E622DD81B1FDE8C786387864D78246A432CE245E0883745D9A1DE9D68253CCBFE7C00EA908E452DD3B9669F1E6812E40D9E2C423180BCA98F4591307CF8B8E98B7F828989CA7F3F0BEEA4D408898364C6DC160C94B89D879B1D07286EAA3FFBC6CD7FFE5700304AF3FC049098590DD7F6D4770ED66FF60DB2909C2DC6DC67ACFDB7CDEEF1B714BFE4CA04F2D5172137C", + "4427106DF31EF72E43B6C75CB84BE5E375B6B6D4D21226D0FD689E8F14EBB81372B93F5455ACE6C168345234B378500BE6612FC10536607E85B884AEC780550F2A26FBF0445E0AE9C0F4CB95F01BBC76652A9E6FC457D6BA425EA8B9457A6F3C0AD2A0FE7BDD1C1CB19A9F1A8815D84EB5843AECA4DD005378111E9AFBA9C3CFD808C0C3CF2B39B1962EA44B0848452778168F7F60034A68E5980EB63B94E50D170C680FD6345F12CF30E9089A7C0A422661DB7B1BCF2480238AD043FA1D0DADEE998F7CD69FF04BC336BBD5985315D4E1CC78558D4E235CD7E05015A5734896597F16E65E45E0C819CB0B895A38883ABE4F439D10195D88366CD14F45947716AAFD770C27FAF6374CDEB53B118277906F7E61C583E8C7CE3FE733541882C511936076DBCF65094E37FE2FF54E0977595077EA26E03711FE9054E2D31AE7F99939B415F46C05BB55BA7BC4F31F337D624A94C9629526ED51A9B93B1B3C5551F9B92A30759D7A40025E98E50128232A706CF6C3F6734D00571F91307EFDBC9718D78B3B792909C1C56BB8526CF5B229D4DB47E61D962538BBB17E6CE8CFB7854EFEB5591CDFD5DD8BB22FCA50E4D97BFC4C36E2573C0B495FEC9830FAC229976FB651B82DBA34173F5635875B1460A023CDA65333138C89DC81275F7F3446472F5F8C5F93AB130009F5B797D9ED536ADF5A42ABF6345B1457D5C96CFCBFFBA56CF124E78FEBF8A8BCDFFA97831A589D177AD260499130EECF8247FA5C44B3C0C19AFE6BBB0A7B87080E14F3C3457C8424557BD9078DEC09A3A6704E1D77049A1A4431E423B28B9476EAB6292CA1B3B4B43E18EF929EFFCDD574417B15A4DC1269E593F884DF5D492A464AC3F2436B8C691B88658180E53228AD83C4FB843F8571D42A9BDEF37EC4926DCEE5002A12144600C9CE7AFE483F3A64E480CD09F8CAFEABC9710E01A8120E84BE5861D75705A8D18F02756D8FA78392F1C89D05F37CB9F768289B8CA99E22E86F8200770D6DD2D76951A45F73C0730162C363886282524436D029786E7CFA2EFBCD3D05169D362DC8BD472AB376C12097443080F3C83AF1EF7339D8FCB85FA098BBCB5EC3645A03902B758DB263A21C8CC4874F96D672EB192BC1A183A1B271BC1D6429CEAA8208F5CB240F451A71B6F884537ACD49471010ACDF28887F6A02A04E738CF9FB5B00E0C474C460EED1F791F4EAB3F9AEC225B40CCE223D23D07CF0B60846C111A07A86448B9CF119754935E8C350752CC60AACB55C71F4D5F5F2BDC3E412039D336ABC6F3D46EB0D1C2080CF260EE77F5C73A35C23396E2324998B7DD375537DD35B5F27C3B545492F682C4B89F13F65FC4F72539E4A7763BF4AE2443FE0A2F683A86274672FB9581668CD2B075C274B242536087C4DA1E69D0712161B868ABE86C98468FE43A42DD2AE30089ED92B7A750C73B19A6D70FBC0AC08299EE2A9BC94652B35D5B2D679220D34D3372AD756F842861470CC3A3F2BEE75112B138613A40FA585E449FADD6353A09363EB6025D4B81F9F224817FC2DEEAE01D797AA8A0F8C945FC69D5891355C28ACAB8997A0518C8F4465953819113914A7CB472EABDD1A8D943A82FA41315D006E54AEA4CAB21601A2ECF6CA0521579A6A92DFB6B77BEC6D5A05B0A72F16B0328C860FAB66A1D6113B7098FE50F3B09C2306D0B9D00987B351CB2BE099A7AA7EB7AA691A4E2D243DD7D0D864CF80A4D2FACBEC3C1CB222883CED667477D189100A5677CC3FF0DF31D1119D5F31ED2120E5DAAFB99E8F36E77B3B078C47B3D527DFD6521D7C", + "593CF84751C21D591BB62FA0B0AB65E993408A016415D6296E0F080FA9149A4C31D8B2EA68CD7209E2FB0B4BCCF654B013D92AD7A4F6B1935995FD106663CD5760E63702196F63563DC994570C1B8E9B0A7705002ED56D335632ABE3ED8BC6CAF109F0588040DFD167DC364EA7F692D5F59C5616A6A7DA0C5EAA4D9FF017820225D5B164B6106CE9307B56EB08C563F123A05A4C93488DF63A6E4274BF5188475E8F7ABB8C3E7A8323F689DD93B043BD98BC948A567E8C6C95FD3788ABE728F7B7E299C460F9B35A59BA4429BF417B9F8C54F2DC475A7109B9C25C0843AA86ADAEF388A9915E65EA08C96C4C84022368E79A3A466B247EE6A37918CA0A8DC6AFE291CB9D360D727B6E7415D360AC414BD34DA40A1D995EE1303896465D52707A4F31A30C7B7DF936391435A5FD3F06E336CDA36E473E3D990A6F04FB5E6340581AE86D8EF81B9BA68979058BCFA1363D3F711D33EE9E3A8402A14AFEBF339BA7C34FA4EA2004FFD09129667646A79B6322CF00E1B46C1418557E0E62E106901176CA771979F4B6B299BEEFEF7B847F4E3ED99F56D44F5C73F00488E1DD862BFFE5290DBA737FAFA0C9D95C8307A10DD309C177BFC46A9F6D3BC86F598DC1AC69B070B9AF1CA2824F456E73747A0CED38631F9AC222914825CC3898F04F6AC09B01EF4CB09A63C9436625E2D0AC3C433A31D86948CE34663E5462652980B3B57C0920EB63879E28CA9565BEADC47F29C43F1718CE34CA5717D7AC2CEB6758A16F6D769CC277BDB483808CCA3A6DB99D1018888BB6A49D325891B5D6B4B77B18A5A4133AFD5E8AFA4542710483B52E3D51D8A4FB77D2458C4FBE2DEC1F6DD8C0FDD8FABE2130297D0606F07B305B2CEDB39204E2B8F8507ABD49C0FEFAD0332F8ED98736FEF5AE4FAF8515CD638E28F1555F54D7A64FB38D0B47734D0AEB8B55A792259427613733F237FC57DFC1AD49930D9844C9F44C3D6265BE3102D93E2B62D3B0D7760F613B1F5F5176E0C5EAE47970D30D211403477894B8D66D03CB3AE8992E16D52F6B2073DED09D504B36289644241EFD21018C570A2CEE6D59667F274CBA5733E41BE3370DFA47464AF850B14DCC32BCF1A5A8385314E8B38B2A642AA90B8A5647DF9B32B83D3B4B2AAA54472BFE84EF7DF68ABD0236DE171E5AEDE1770F63823EC143B30FFC69ECC464CD755F5AFD2B51AB5F05B74E96F6108810CDA94F99DF828EDE147BE061FEA46CF6A84CAC720717733A17677BF620C4963DD1A08512CDB6A96DD3ADA995D84A934C9825FA3B588D916CE1898F6C2F75B75481383B27204C343CCCE41E10DFAFBB42BC6BCCFBF7BA4C460147814014F9470ECC8B99D677EEC872172B72E5839D263F55B9FC91AE6143FCD1BC3AEDB12312ED10647E011A020B27C69E35CBA94623960543DB08D67B8CFD06760450A067E3F868386975793AF43AC4D0F3773AFF6C2CEFC8310C0701CB934098D842604E38370182BF05A401C38B6CFBD19CD7D4BA186A595ABAA48B8740DC321FC031D76F82B4F5FD6949AA101D70A702E18D8C2BC1283C2E2CB138699D507FAEC5B6A092E5AECB0AD9BF2E59F175DACE05DC18E485B04DDB963426A117CA0B761EF485B234971B6F681CE3CC5CE58A9BDAD9267E5C075D1BCEE2C88637E2A10AD441E9B1CF4A324B77C6623F4DF9FC6C4AACE068F66017BC82D562722FC93B02489DFBB5560BF60F57B736212DD8A0533071D10ABFCB4EEAD5AD9E36E856C8ADE0B9C4F6F5116EED43A39AF8FFCFA01BD558D7575AF0E36F2AFF74E29435778F4BA57A5D90", + "214AD702A657F5A17A601D77E0F4C6A67B7B8C074514548FF89A781CF2E0B5225D95A944D1048338FF3AF206D331DBCB3F5E9E89C7E592A2295CB783F416C4160FCFD26983ADDDAC52BBFDD6A7125BA4426715F82AD9815F30B2DDA972A2E814D6BD231D453858749D65EE1B4C2025F61EFDF8E12E50A3719899C611682E7B2AE0CC85294542DDC04140ADDCCD5DCA315C22E5ACB196531A3B0071DC787C2753C3069F5D302A9FCF99B71317FF2749749C6E00B73F382983E1C91BC8115FEAEFF083434DEC7E8A22ECF2D1CDFC7B7ACB80FE0DD1EAF7510F694961E09882E50994169BF60C47B95BF37B5D6F13CFE48A9405637F87C157863C58E479488278B918DDF041214BCEE2ADEEF4242F55DE971E1A7F2EC566B362F89DABF163A690C8A8B808ABC1217C7D49933E30272A08689F7519B35FF8C1CE0F338D0B75332D163A5DCDE714B821AD3B8393A1740B6BE4AAC6008EBBBA30B8E5FA2253DDCF16B3F87B4FA47C1D36AC86E2FC39DE8BAFA79E7D58A3A6CD83FE09448EAB6020BF121234B23A72BB7DC02A2E235BB5DE3B2AA97D3931CB800165B93851EC81A1B4B7781F23E5C946F035026888C3D8C31170787F78333FFF8ECD8835AB5E9D165A8B1D97B19936940EC4C74D115A34120EAC800E8D680B36D9E29180BEAF5B3CFCC3913EE7FFDC37AC881C441F79A39F4A4161F3B403564F654B0E7D8D5415DEB9A6E11F845314421CC59C6A90826974B4CC477C280ADF4FBEB368BD848AF7F91D12E9BF4AD3E9587DCD7A280DEE9A7F2B6F2D2EBFF7EC9454173B748D2D90A6AA650D3BB97701EAD27D6AA1D05B817603EF1026E643C8816F183AECE863968664E01D6AC58C2A10AFB51B1A19A5B7BDBAD77D651B78C141AE70B074B9EF74BED349E58CF8A80A910F6DF8887202317BA36950F3B7EBAD45E6E940921043476B0FBC136EB397DB44445706F032FC47C454BA08DDBB8E71D1E7D9045655E1039C3C3D199EBA21596335BB04078DB6B39A4452662D282C7AC9B76D92E112B0027B711151C56A6459FFC70BFFC86941736EEF705E8DF5197B4D3AADCB31E421A90FD5179D9C3EA3EBC8FD7E9F4C29D736076723E2D4146EC325CFD616F6B0B70AE0DE179FA8F33A2536DBCAFAA2BC0A9740BBF41134655EA16438BAA5F8FC96256A6F9999CB1C57B69087C0612FEF4E6CF0BE5D1FB77258AF418EE0B90E8AF3DC38B7A15FF6B8D2BB739FE7D0099AA4694781E581A8F7A49BFCD102B7880E97B89880FC41D0890C33481B01D9BA991BD41B8D6501D34E0A401474CF89D089F3F6A189ED80C3006515CEB7F9DEA85D0766D2989B88280FD46F7BDC7C32C2294B2A1FD435102C2D92E85A03775CAF11D05F2367B57F651C7586FCD32FE920B1B94EB431AD2497E75F4E3C408A0FEF89907C6C830FA14402B1103DA4607F3DFAD625AEBC235D2392954B8D3BAE8A6D02CAE6D12EFC73EB46EC56E13D2729787CBB5C64910347AEE384972A5716B5DEDB99FCDDD5660E9453900DC1AF1B76D151C00E8E4BAD38E84830EDE92CC3099861C92BDBB59D8DE31AD9F4B889D480FC8DC70382E8494E1A25D2140740A5F327D51D0D3CA4259F1CF5DA3474FE28270C9B4E7F8A714F7C69D1F65B48D7C9C69A39CC58E2C77D7A750CC0B0E5D54B2F3450B66994DB524F15AF77CEBACD3CC611B2C95F6C93EDFEB652A70748DF1788E6FA2D45AF171C1AB59B0B2A160C075AA4A92272BC0F22631A24EC94C5D38664B08B46DC96B448C351C77F81051881055ACE0F364C80372EEE5BE7C660C7406B03C8F5345A04", + "435EA61E7DE31409D04501BDF0CFA57A84C1387E0684538E8BB651C7CF4EFD6113EAF9383BFEFDEE4C702FD5A070FAA3DC7D644CB3D96C8FF65F18C88C43A2E66EB78FDD1EA91E9CB519CDA9EE1806F0F10653F3AACE782810776AF25C9CE1C580C381D00B95CB02AF3F9892B4D918FEEBB01E7E730079266C4FF0AF0EC305D3A168197158B5A0D4B1C1FBE4FCFBA947A5CD2E5324D0C4182069C6F328465EC2900B468E145C0F41D724D65547808BED468256EEBD76431E715A4ADAC80D5314ECDD03177AD9175EEA9D9149128DE8715534A648069F5EB9ADDE486029C69C81B1ACECE89FC468887962AE2C063C5EC7B594D88E56F2F3FA4A20963F3BC730E74923BC2DCAED6EF38412E9094326930D2D2E3A0FFAB2217E9059A88882E2AFD3E62FA4DFCB5B084D0CE53655539BD0931BC063CBD4E660A0B1BD9C7D6CF2836C947CEF2C07B859686424B57FFDD0DB6C34DEF824D835918505F36755C298A09F935A2F95328248B5E923E55AA4C91BBB0733E4940A34AF5226C21EEE9B0E0C3D15397A4D8C069B94C2C38F61FEA2077AEBC1F7C5E0875B9A7F2041BAEACE95807EE05A366016B6E0FA2E7E722BA34D3654DFECEE78DCAE199BB44E164E61729CC7A924CA6C7A6C061C6DA0936B4C70A02223EDA01D7B8C0D2E012F998C3B94D1387B6CC65DDA36360ED765F0A23EA562626E12145EB2FAC0F49BB0DD7D1ED3E9B2860DE1C54FEE8D60EF56D4382497C36181E864F92A95E76CC516E2E1396E2B0D880ED6CD14D2410C9BCA159F57DC9B763ED7CAB73F9EA5D42F4BEF91977C114900CB0F249B10DE8F4FBE220181D4FDB5D836AD2FB70F06869DD7F197F121FF748ADD6DF6C48ED9910F51BD7528DB60FC5A42CC0B72DCA6FA66B617F12FB2A9530247B1709DFA7729A6C9FF5B13D073FD7165033C45B5B7C7C66045D1735979132C49CA4442986760CF8F0FDEC0C0BD5E992641075C76168B8316057A993F513536FC917BFB783C28B2D4878D120889945FEBAB84BFE4840C61012043E96910A374CE33B45F461B5492E2F96F0EF91E42D7DC755F37117852C4FA99B106F5CB5C70BE5055ECEA5DF90B517B08252DAD6F20013FAD50F47A1682CEB37AA0DB64E4B699E126CEA7034969FC5468D19455A1F2BA4011AE5CFFC2544329E268326345C9970756F8712E7793301E9D3C92787FD10B7637F5511E27A16B8DDC21C116F13B0F27FA2E5B6DE60837F011937A986C00A4D9551D37E994DCA480493DCD5C4DE6F40D0E25349284131B9E0B3B6B9BEF6B9DB6DDBED89CA329D9F3B032E2C05BA9999CB02D7896258E3C4504643DBF49A155F96A69148A51F243CFCC3B2BEA7E8BD534308E752C675CF478A231CA99C2EE402EB5DD5BE2AF5F4FAAC783141BE8D2A3BA44156A3D1EE98763108B9EF4670B25569DFF3568FE0E183938FB150FB79F7F28D51C8CE40089C06D6A09F25845B50E64AD231B367C280883CB7FFCDD5E4C044BAFE6C0915A0C52BB14876088267EB84A01B9931C03DC799995B6969E65CCEC63697F1F0E146B75EB6987550C23DF2793FBA8F04D019C31AF4AA747F3BCF00D6FC86CAA707F1F27DCBE598B18ADD6BA048B2B174FFFCD20F93DD2F8E860885A15CBC2F06CB10537C205E143ADDAD33CE8CE5E6EB22C6A917172BF962080290AD6FB88A91C7B63B64047BBCB60309C01F15271CAAA73AD93DCF99400BEE17F6F771AFD156CF28B788586A18C21739AE5BFDF8F6B8FC94A9CF1EAB0399F9FB53FE70FE5E4278AB909B2A00F5A181F67CA7F7E046209A2394C5583CEF4", + "C1A7D5578EE6929147D34AB5B29B97864F46686736A0966EE7298963AE27040F4598E0AEA235B562DE84BB1943891101155AFF6D185D9F66E5F9DD037B048914D7C1B55505455D08DB2E0C58716AA4C4E779EB7348D486F445CB8BF499DA3054F087ED95C2561770335DBA67F1EDEAC600071AB5918ABEAD7E55C5C6E609896ACE2426C47941C1FBDBC4804D8FF4C9290E8ED35C967D65837D6E2B153A3DD843712AA34BE1FD7CE0D829B04DDAF036D9D16063E28F627491C1C37018FBD1EA3D33899BEDE421C1910C2957C13B8CC4B8A06C8D3B2264E8E1B8FB5811622A9986B4B6F673994F6F5FA072ED8A8564C2AD450CF801C9992779F292994A98800AB12A9EF07F777F441F19FED6314404A9949218B2ED4E239EE677D8D1425D0547CBA99C1333FCB1620A8D11DA5CEFC51DEF5B3C4862E17A6BE3C194F88B7BBCED98325D638877757ACD448C0A970D63603B58E3F4B8A361D36EFCB6AAFF2858E14B1830F0FFFC4C5CB08BFC21FB091045B9A7F8DC0FAA02A62D1FDF7178B5DC90D2111A64CFAB0D83680196B21D75EB91A5B3E2568C7E8A6EDC65048C88EB34F6494CB697E44F895012AFCD7AA86DF341CB9C63A7EEE8E5F95E3D60213BC23C5A83CFFAD4225BC731F07B34FCA550DE26E0D6DA29F03A1D9C4233D9A0633D31AC5F55A11C1208C8B85306CAD41EDDE3FF5EC3A61194E724EE2D6A4C94FCDA217BD7C7FB328A9CEA8064D94FC66049B56AA1DB9F977216AB4242D0EFA59AD18540F1430A6F4EBEC5CA7EA81EE4BFC6E77F9EB6352B71275D450843304F073AA82D77EE5602B43DB62B9A733320A67B2727B21B705B86D5DC1459B5EB688D37236FD37A7163E78E8425C589DC600609DF3E9F36F9094D06C60731527B8ADF58A95E40C1390FF657D418D675F528B3B665FB5F3C56504DF40C1D3EAB6F3CB85F5C7954587F87744775382517B4C652B4259571A8AD219A6517E2D6D3212AC1684404DE7CF71478BEF7819DA24B09A11DDAD5717CC63995BF83DDA735C3A50F6B164F26D6A79E3B20A1488DE2AB44347694DB8EDD3D957B6B5510C4A266E514164D23F1594D84487757EE6F4353BD06CA7F90912AAF5188F217FCC11A62198E2DB04A016D36A583891D346C0D84241027DDE80090356ADEE1AAFE7CCDFF983FD7F8827BE286280BE118FD9FCAB26A10D19BCC63A9AD9D202036193CDA36321A5FA7252D0E65FC0D8E588D70C3B629D830CD1DE2798309A6B6113FC2A16B341BCA4271B5994ED767F2064FCA7DA335BD1D6B21F54CFA0DDCD47E2A38CA924DF85D2DA869F6DEA8FDDDBD20728A21034355728DDB4287FF0EB5A9DC113A71F7C69899EE76BE7D186B39C7C868E78C03E923FF199246908FEB48AE45261B3F7A8D6E4FD0C280545A9E3A578916364196E483F57EC37439B0FC9FC37C5CF56E21A5CAE0B70D25B928EEEE456F19821DBB974781C646E860EB3DDA8EF8577CB0E3B9E96245E14CF4E51A5D11F7AD9A77B932467808FF55E588455F810CD50367DB1621469AEE8BA6FCD52C75BB027521C530A918F9D646C69EF8DEA1F7B14354815F11E0187F01F677E2A0FBF78ECA2B1E51E898E26CE55693ABC8812F4CB4C10B9BBDF385C6AF0B340DF8DD2E957D877DC1AEC30D4A6195F40F09B4CF4010E810C764EBB57891652C156DD20584E427902DBE82AAA3CFA728059D31C36253649FDC00CCD29517AF2FFF4F5050B0FCBB73B2888C989761A7F0551375E4D3C54E0C9F8A4679E640A73476BCC6587195A82CF5E6F550B0A85D57A97E3E5D0B9A194EEC3E41C0", + "F0E94A299789538824A90801AE02D93A78EA914B9A8F10FEA2D2A7D0812009C732665D48F6DD58CEE4CFC72513CBADCFE171F837E79B8776B392B2224C02766D0468E513D0BD1BFE6ADD6C04374604503A3EC8539CC707110D18FCDC8E000EC1A3DD03F7008D37C1FA02E419FD4FC7A6C81157E07E353F3C4882C2AEF4A0CCE1F7A5CB5EC753528152C521A2ACF7548F19862EC31D8783BEF406EB7F756E41CAC3FBAEB9A901F9268E78E06ED5D6CB19BF4606C9DB660C03A9D5B06BC235DD7936ADD74268577256F72C7F36CFD7D4D09D3726F1908BB3277AFA69C7166EA2F4CC9387B13AAA8131D9F21A5D97C13C7DABEBCE61D72556466093EE0F87E9EAA9CB42245E1BF55157013C4350F38596CD26D2819F98698CE98F5D4023BDB3C974B0E61FC6E6604CB1707BB22FF5689F3DB3AD4831BFFD3F93C702E0DDBEBCAF626FC2655447134570B7150E030A3524A6979579296CEE062D18CFAFFC4474490DA81268B27B60E9E9BAC2A9B7D2E2377A2006AA5C439C263E8F9EE360B42E217646F7C44EBBA6D9E3B98AD20B1BF7CB8CDFC62CA7AB139BC2DD1C85A837F51AC9BF08B3F36CEF176A03F358E2E37EB5DECD0DD2D544E58D203910613EB14744E914F92C5E9274FAB025CB6D8AF16EE03FC86AE3947F7A30FD8C1EA23EC7EDAED4054174E4E6DE048C563B1832F8839927ED3EA54B19BA41CC144C8D8A6D8FB66032BA6F4E16DC81C98D37129B3458C2F2A6517694FD8816E8C71E00D77189768C423702612D9863FC2DC1C4593809C74D0AA881DD7477BC584376DC6C177347EE17F3E17B524D0DFB315196035FE6AEE83675494E23BF2433310D4C72E84DC82BDCA9B791D5BFD620212172AB2562B5C36DCA28C5CB8078CF41F2BDFAEE651B04243326DCE0C51ED88699CFAE4DA3B478DBDB92DCFC8D2EDC4472691173B6C5B9E5E116C30DFFDCE7B0381E8E1013CB392056E3BC7442B2A2EBB631ACB65DE639B3CFD8EF3918531480A35314F3F23F9AA6CA41A9B8F6D08F6C589DD2584B6B8285230808EDBCBB99C0E918D4E73AE7B397328502F2D47078CA2FC0BBACBFC9D9E491EFA2A2DBD69D82E0D829F74D5ADEF4100E6195CF3D7AAD2041078AACAB8A8EA62FA42C6AAB6203D92794F77D4E30B84BD16518A9A0BD0AE4B372A537BEDE43B31A6FC1A58F9B43AABD485C55E630FFF8A4359DCD52552B8A090DFD5CEFD972551714E5F0A2A16442345B33DD9D232AC8431EBFBCC5D5165D12961D1E954D01C0379B5489AC0DC0357667325AA864D44269799DB710BC6A25D90AE8E0C9368BE911C91D68A49815850B4B29708BAD74B4BF3590E6488655622DAF3A7B52356C804487133223337679B33E583B622EF873962E8FE259DA8F5DF61748B6799A14ECC763A1B54542D67E57BB73E411AC023907E54BA0EA8B7F20E55739BEBD7F83E408238B73249CE69FD2DD593565141FDAF12BFAD3A43670935354ADA4067DF0AE4150AF306AAD3071EC4DC0AEDE6F568DCDDBABEC98E4D17AA99F8E881600D35B25CDBDBE5DE184180A9C35EE8B42F6890E068700F06E4829A742FFEBBB214D17BA925B5C0B41244DB5BC7AF49D9A24B2C135131E553CEDB2CF4E6E2EAB840AB37788323024123853A19CC04F6E344A175A4BF1A16776B7F84A17501DE4A594BC515E788FD0AA08ED4BA3602838A6D1D485B1CB80BD24D97905A9A7E2DE71A9A4CA32689C46AA9EE52A9EA985C85C9289ED1577B577C444FC73FD1BC3DE03F9FEFC10E6A17553A7E3FEA6D57AB71E2379C9C5F8904EC43E57D5FB119CDC", + "A8C2390D6C3F0B9D01B9794A4207DE3F62F00A4D1188C727B2910153D9BC6337AA46D2D79D09DB7656C0B28654F1FBAC5C3DAA8A75B16BEB5FAD8A256E38EFD232E007A741028319EBA4A6DBD0AE1C1F8989246476AD4090F9F4F560D0CD72815FF6AAC29C8674B1D366120EB3213300E99DF390B3169A1CE03D2A5E471B9B8DCAA957259311B97817088B486CB680047359440DD39386DC2BC24AD2AC30436A08C335199F08861F93177640074A241D9C5884EED07EF0C0FCE8CCE08BA30221150C9EDC6562344CD3E14D3735B41DE2CBFAF4DE0F6D417299FEB38146625F3C70D8872103FDC6970D9D37D1CAE92375F81B26566A78A02139CFD83415BFAA5D328674797DE51E4AD9B3B9E1F9BD18A0FCA255CA8AE7E9E192ECAE5C60E9F5D578E59F7F7074A12FA75F9388CAC0A148CE9223681A93D62A679254AC2F41CDD871BD73BBC6C4E0CC9DA67633B61BFEE815F4E15ABDF639899DE105A5F4D74CCDA3EED32219BB447EA5C6411CEDB351DD76CF11456EA762C2F300671A12DD6ED8EE9AEFB4D0BD86D0CF35AEABC9B9E7822478A6DFEBB887DA0E2D3ED4C010E5031C4332FED83480C21ECF904B65925C4CF64595F20D072C7C6AF12DD3C76C682833CC6296DBDC73DC8C979004DE4ECD749BA45D9748DA728AF757FF5422B862223146AF86AD4AC4D4F407DC2025B8166E2CD64C8E1543E046ED91AB1AA5524E88AB6851752AE5A2F02F933DB3CB7EF48775017E000386805EFEB8CDCEEBABE613A87E0C554F99DF0C8FDE49FE73DFFD48379299FFCF738EE21B9AA1AE4DCE7BAB98A356241545B6F7D186AB544F77CB61B6492BE1F02C4B77DCD5083DE4319D1A1B792961D11D552F8AFA649EB5D2AD64227524722B0CC97260A8B3B6493B00D258A570CB238D3C2511C0582DCB478F878528B8A88A5B33F9FA6C41302DD1BFAC664C692001F7F7D207A8850D6FAF22ED887589405739EA5B5B9812BAE617889A225FB2E6F9EAF77D3B3758F9ECB89637D1FB20C428AE3420C3679B834EFB0F89A389FFD72D7420F2435D118045FF7B7361FFDA0BBB6934F81AD8513A626CC25D9A5E2A5FD1C51229E2D5FF803B8983B672E92A1FD72C16520531C694F44C9C99BC3385A610239F6963E0BB66ECDF4CA29E1C175E414A5D3F9E9F495F2D03A073965643186C46EE9BDB41876A41ECDA224719F5C76AFA6E955061805F023498AAE965184ADD6F6BA1DFE0BBEFC3D1EDCD40D8F55BB518C9B45CEDC95682B24F2818795CBE5D8E504F0885863C750524D9D238E4110AEAEE095E1C545C2989BD7E0BC0BE8AB750A7D319AE69CB080DA562F7DAA7068F38B14AD7282E041835B58E2A48A340F993D10FF4F805280C183A3FB45555B8D54EC145CB7B9BEE71D7BA652FC533ACE1BC8D621F7257422B363A5AD2798FB0E6E536854F2BD25914AA0B6DBEF1E2EF71FC7890E20FBCBDAF751CCB0DD16098D96FF22961B6141257AEAECACA339750950F6895107355F04F9BB3EEAAB3A9024E4CB79B19ED7947EDE79958B669077E6BE182020536F7F234AB2332C2F2790DD96F5816AE3FB5F2CCD72C6D177845DD0CACB44128F6EE6B1C2F673A8A50842E13C8FF0087CF71B8BA0715637A40021998652FEAEAF5719ADB71EEAAFC8093E525602599278B35600C743AEB41EA78CB0427D0894158DD4ED564C4742033324C58B01C15822B97C9634FC8F320C0B103F0A904D98C9AC529FA799B30F8B2C0888E47A3BACDAAE5A3DE6DF39A693A9AB3D95E7C973C7125C0F7D8C59B37EC924D7B9737724DD92818360F2C", + "2EB63BA5756AF5865AE33947E311A5EED4A0CD056442E19888A2B8302ED8017085DD5D137A3769058F0AE0476AB202CAD822D6A781291C537120F316E90D2C3CAD13381EDBAD35505A5B7DDC41E46771F460E501B9BE17DF8D4DFFF631C365AAEBDCB7D5CFF7010BE2EBEAA0B99820E0BF3D290CF27DDACF397A5E4922EEB7D8BDFDEC96B87F8202BD409F31A200515EB6A05E25A5FA504093F1D82A83A777F5389B5C90E66C369BB654598CBF3F258E9E14DAE819837A86EA775A05EC829B4889B816154A2B7882EC7FF71BA7CDAFF873B5CA4F35011DCDED8C0CAAD101F7BDCE1CBE67E081D98EFAB71490AD12AB7BD9B4CB9331B6B04D6DA2C12311F96E01AEBBB350BBC7311E8AFC9A6F42CD541ED40E2D7BAB44BF7F1E4465CA942A0E8767A38D89D0231BB897A995627EFF71B3E4483ADDCAED084B402A3CB23D5F91872BAA49AB361281454AADA57AC838AE2B34B799A1B46595AAA02A9738019EC3644C63BFDC72F72CFC35D48D83B831E6EF397474C43CF665D64DC0376A437CC768862A92C941B9BCB8FABC6804C03BEF7BD2C5EEE4609870803A5E9BB2FBC42028C5619C3706F773426CEC39D096FAD267BF5E6C7C7510B0D1948FAC573C5716EB4D6AC6EEC492B347497B47C0D18C77E7C264E9A04A4C3DEB83B1101E40A0A8653D9495D4A7C13A5BFF3C6956E668DFA999926231811F3AE84195B65213FFB824478911230719E8EAF206DD99C7CD7D3D7661E9F39250793C1391033EA99A0E31D8CF83997ACA08C43B47240BF1E5E9D1D741CD9E6D3F5DC2043C9D3D68A2A689615D39014B75FB53B4866488C4B37B68B5DC5F9B9D6AB9AF190789CD610E939960ACF607A488964C33DF0091FA4EE86654142083F68436D9700B3B50949C0D97098D969BA25622C2EC15FBE7D7C7B78C1C49F671672971E38996C2D77A024919FC1A87BB9BFEFC951EB75326CE48D3837068F31B9592DDD8505AFF1E0E31911D1F4E311CB1B81DD8A03D68A5EC075D8ED7D69A1D595E7AAA70928DE93B979438315A4B98EABDC8B5E932257AAF79A9CCC74E6FF88C02C33217FCB3FA8DD72AFA1E549B9E5CF6099E2DABA07C91BD3BA6A9A4936556FFDAD89D5F080DD7F818EBC8ADAFB3D51D8BA7B48209AAFEAC184E1A869FC88BDF92E77C6D4B8B983F4B93A52C473F1BF27B4D7514DBA522ACA79463A0B9C2E0D9A2D47DB238AB9E2A1636B9AA825272F2B9C8D36D64614A4CCE2EF31B67682F328B46D31FAA31DF874FA15799B5D53E143C9E9127AF358BA1B43A9418FFDE00CB16D32AA137FC7A5A1CFC2070FDA112DE600F3C05BA0F50F8AE1703AA2CB64135C29FA621385C803673A4D77195B4B74E554B043FC07B106533D0B41F7D882FF3702692709A64052C4AAE51CDF8B733A92D86D507B6FF4CFF5F3BAE4D0D9F3F90AFFD774591E6E14539CAF99C833D2A1D9A12F7E9CB1CF74FCB353D11E22B8216FB91564DDA8F1D2C9865080422DF0E0D8AA47577F31A7682B54E36BC8344D5F5F725C819D3DD3A948F4E6F6C893491127267145DF1B286C18C4F3EFEF0BB61541883E413EC3EC3BBF99D83E3919501A3CD59341BDED35BC39B655D61686555CBAD7A1B033C2E326887249E6E30AB12E43793DD1B72EBE858B40ADF4400A59363BC56063115492E114688F47447132D606F2B99DB9CA4083A91E35AED045C513EAFB7A3F0040848C1DDEC0FB3C2CFF717BC4CA36C425EC3CA9BC51B3B3C1885FD8B4182AA22AD38CCF8FE3990DA75CDF5712B358BE866A6435329677CED89571C3877F9ACD0D3E66884", + "8F0A4621BCBCE418BF2A77BD47D671191216B230C276A0D081C4F79AEF839857586F9DBA52B4E35AEF22D86FBA66DAFE801C686F03342849B5C3A492280950C7F3B725DB4BD6984A6389CEC1AB86F29D653781EED847D7E69C99320F8584700E662070E9C43957F4DDAB28DD2427415FEC6F1503551D972DCF11BC4EC3B3FE745DA7F717F35832B8CE373A00AE6572D8DFBD7720E00517C50E2B634B6BC3942F9A8C035AC80161CDB45AFDD7E9C473F8EEB4F1FEE7A677E820874F03B546464939F3EFDDA157C9F478988F3ABF39BEC02B722C559CEAF997A13AF66BCC0BBB4DA7B68EB6C6E8498129A95D021B7C3A072683593C2990627FEDC52F66F3A16A8064018E6618BE5D7C63BC622DDD4A15A33EE19E4161A50EA38CF6626D5A088FBC5721F567145CCE30C66DE60CAD79D31B703B129D27627BB5AAFBD9BC7D43944B9B0D255D8F338C7CB7EC56D121C3F4E61FC0D46CB0E036262FC182E8F266741842DE923D276CED79D4A25FF7AB3D2571B1B589E01583371BC8D8196A1C991BEB90F7FE71B99EF9E100375D3E767637B2BB1FC907846C53550DC4E6C7B8AD7FFB9DBB65ACB30C9644FE9D59A74B0E81A5BA068CBAEC9D6B362BA05202260B1E86EBB67BAE2D74F60B7E1C0B510BCE4EDD8D71E342D5465A8032E87617790ADE2770D0DEB1ED26D62A863D030C781D2FB02490718A5B55D1BF6B3BD1E3B3C163361B2F13E616FFC87C1BDAA7D7C88A331511ACE5A45CB94DBA557EC47A670BFFE839069A546FEB7183C27697A56B65AD762735782FA009350ED52819C23AEAD72A7150DE845B899669EA37B4A12D63BA7D6DFDCA495A0957BDCCEE6BE11B8B296358E92E60A2317CF4B7542CDDFBADFD18C88F5AA4984614A113E992DEAA18FA172C998EE6FC8E936E69953EDDAA3FD233182C7B986DF90386B3661C649EB0F9A7E65B90572132408929968CDC39D18020C6D81A3665639CD2A3612FB2135A6E057F0F68B10D3CC1C35DDA2600AD1C0A6FCC0C5DD0D82F6218F2C1F8F5B714C47636CF68D5361D97DD1367681116F2A2A045894A85F5FAF1BAA27F93A3B8809404181040C24156433B3B87467B27D7C3ECE44EB763D14356D6EBC7542E21863700505B8A10D4B4B6E9D2A4C2EEC9653BBC0D9FC68DCB53AE7C8B6CF3120C921B824765E7641A3E9CDDA804CF341012964EACBF55D6430673B83C12CDC53100DD8BD6B18A56B5AB68D83EA484F48D4641B94AA2816BF06EC1D1285C11AD060735509367FDD0E300413911442846DB240612C1389CD4554DC8D7D7C7E4D4B79145D4684F1FB75759E2D506F9DFE7632CC553B945D91FE0F9A829AD6A9A18817B09B986B18FECD615414A0FD6B6070B15F2484AE8B3EC3DA36D7F8007A7BE336B749104C2695327A49D34741D76752DC943897B29C9651EA3C034BC4B8E1F380A9FB0F9D2C23B627D9DD8317894AA754B8998573F025A024F43E03EE86A1EF583CE02DC7EC2BF2A8EF9A3C7743DE2E6DE38D72B5E33BC5CDFCD12184C9664EE7A3F4FBE9498F59107BF8B6DF69DBD6732AA8013FF8B4525EA9E40FF6F96FDEA2AEC03311D6E8908D426293E369D52F818233FAE1C2BA2657B38FB82E7864CE1177D5E21EBC8AB773EE928EBC4A7EE9F4A9CD2D9F15146C08E4BE0A77CE272A98AEA05A6DC18D5B856EF1B402F9851BC84DC95FCE71320D2A5540D40BEF67EE2709147EAF3C3D5BABB0B21090BA4C94CF7242982BE35925F691847A7C296B973EF2172F83AC9ED5E0A0C91AA697305F79A3FC6A8EA4E7D1DA88A81D4DDBC1F604BB0", + "896DD4C837F11BF155D4605D46411A63FECDCD64D7AAE873E1DE22DD62CC2F8982EAAA66BCAA8DE8DA687910A03200FE437BB87CD5E6D17C6F5B8CCFDA073F29183A1E12917C5D78CC1CCEC5C2B04040D39E1E74867B21192EFF2629AEEE22427EB5D2399515D892EEAD80934668BCA906109F6ED85AF29E702FE6C112992CBF851232A4C140BE6CA9C8DB383D1729B41BE939704297BCB41E4B8C7DA5B24B93FE7E7D2214287145A764D3263C9EE136457A2A270EBD03408ECB657B78CB8C0A5C1767521D75A8E12D9FCCB3CE8F6321B55C50A6102381E95C12644549A0E5AF29183316016B89F6797BD89BA8F1E932F4C91C0460F35EAE32F46D42D66F639A87C25AC6E9B9C4E475B7A4A94F10EE0C1043159CA71BA3FB4F794E766C5A7C6F7B85088CE1A2584D4A765D7888F1496ABE23ACA42FC001E2D30B3959AD7BD941916E27DA648833EC82004AA0937723CAEC0A8E7FE3C6742DF8E1CA797F13FCC4A07BA75874FDB6A66014C0EC688C5F5E0D1ACE231B32A1A14A2503155D412BDA98FBEB450D35797BDF96264D141EEAC77550408F6A63993DF3F89D1EDC90DD0885227C273546C2D86D3513AC3241AAF96C137B69970E273B73EEFBF8668B9946CBD118CD1977445F87557DA03668D4F3A6B5DE6D0088982F6C5DCF082207A99B376B155FDCBA8A5E47F2CA4A50D48DDFBE05F8C1D28A080147FE9FE04FD49C370DD9E4861D8E553A22B7DF7324C51C20F10BCFC18EB59BE931C69232419F5E037333B52FCE4A138617B08767506B793A430CB3EA0A4D9A2CCCF813625FBD2F471C39DEB2DFD0792F3374A980FA4B208185332FC68798DEA1728054F28771E0AC3FC065645B3E996EA729DC6A29CC23F872BABE6A84911B1B6C256C38C0A62331EB66E2F8B9A77ED79E323B4A96728F0ECAC851C3E9C15F2863CE6839D3752F4F206C72EF0BD60F087315E6AD3C7C836FA3C5CA6BF2B72D877E33C17EBEE283EFD62F395637E784A84A3E4EA174BB501D2CC216306673B06433A05ED052860666A3C3D7E7D7C991911A56100A31048BB81FF71110697C941CD0ADB08705A5A73CE66AA87008B08B51DABBBC3FCE66B11135844BCD8CCDF4D010D7B135AC764B678CF307154B5A96D1541B75FBA65D7A0D5C2BA2D1DA48BF0EFB9BEFB5141AA6D30A59695EF7FFAE250AB52DF0969FCC349E1C7B8D90099EF0410A861FB05E37D7156991FC65542B3495CCE223CCBD383DD4432113B817B0AC4000F9EEC55EB377CF48B0F51B8D02359449CBAAFD6AB69E3616D6A3806BF67069F2572D1AA0E7DE28042DCA01533E1C381449E22A68D901424498DEA67F0EE80FAB6FEEC56BE01950969550F01D62ADD52396E927962F209B262674D2F079D0E48D1C994864BA90CC4CCF3CEA06A5995072904CCD97313E82D3CF76F24E3B3946D11FFF45319DDFEE619D2B5D777795567A44767F12B41D84A4BF738A2C6AFC0DA08356DFAC343EF090176425CDDEBD1264871CB7AD526D9B4E469E866817A1ABC9973C598B1724C8C3185DA3C999636074C27320694F0BA758B0842D2D3EC93DA9A9CD3F65B321E378D95F003C744EBD7BCCD4712B6FBFD084D9EEF0C84C70651E3AD999D64BCFB5E8F7D9582C290CE59176072A5157B1CEBB5684D47271ED482B9FEB7FDDE78B424988E88627FB1299AB8B96CAA72239BE6930BBA4396118041D6F3CE51CEAD81DA54CFDC8BBEB0F6C8E9FAEF93E2C404D543A0F0026C291CE992CD71BCB0C6E9C459143D995C92A4A1C9A6AFD36E1CA87E1F8EEBD30EC9D209BB3F6410018", + "0245F1FF6639D3C45134190F729CD06608426830011170C357160EAF351BB00AAA61F254B939D89335881D5D15F3DAFAE92ADAB2B59DB7D3EBFF526D9A6F44E1D8DD779753433A9A32A541A798805AD307787C1832385D8B11DE57BC3ABA2A81B70AA2221C8C9247EFB3A40943D8A0677F1D4E6F9149D97D6D83173FD3D3114293D628AB97AA4CC0121E2A88BD5B5C290AE7E5EE4BCBCC1CE73017E3C58FBE575701C919ADE5E94208789CC2BCC330719F022C1F79880B1BAC4E377D486ED467BC58B13F2FF97454BF1B4F4DEFEB3B5998FFFF604EA0BCAFE859CABA133AF969827887AC252B9D21D8AEC49A0D77FC83B4D9A2930732E9A22B7B823E302E469B52537DB5341AA0979642F4505151AED71B690430AFBDB09A8454183A23F86F598719B86D1E3FCCB72DD6599C9895CF6AC28FC5B1D4A821A6F9DD9BB7AA63DCDA1678AD816D96B919E47D0D0E95756BFDDC71AE430C4F71E521701452709B6E670306A20C2F60F84D6009DF6D749C5E02D3DD5495DBCCBE9326D7D302E2A56032F4CA5C82A107E06A867D09A2E5DE7DB9C250E25B5279A4867657AACAE0E3D601DD3BE26C936BF527CA9EEBF3B247F75487A01694C7595619FE6E90AD78BEA799B0BB0C126ACF3DE54F805725CA01879BA5B8412D4FD3D3CBBB37AFA955CF90248CC521B0FBD0214A8D4C9E4A41705714C8DF5EBFBBF2FBDAB93707B0D779357E3DBBB20D5CCAE707BA7BC5D21D4C23D72AA231E83880867FFF3A6B587EDBF5485C516239028271B5462F78E3B226B057F01DE2D348C7D08108B990DE8484E839EDAA174B3CA0DD6D1338513B3D1E4ACABF9C14A9E03CB373D039645B6447D7853257F74665CE10EAF27DC1640C0AF88FF4C207994AA23EFA97D1CE707AB08E4A615C580E3AB971D64371715CF0BCB8421D8178D708E4D3DB24B2AD3143E2176B4BE37DBD8812116E134DC9B72E35E8811F7F404485ADD7321D3DFDCED23BC8209A9DAAA198307EF1BC0E204CA42D7274EBFA74C88251398D6E479D53C5C6E7528BEA5BEDC8677F6F5A81A07BF7CE58E4AC38387824300D14FFF131A54390711F95E03CA59DFECE3EA4696643A16874F98B76F6D280F7328AFADC455C51712BA748D33741998838D33F65F0166BD4D9788B129CF7F9F0802758631E5A718A5058C63B0D38D9E6877778FB8CD8BB7AF099ED442C52DDE7D3C0746BBCB8595C35C815E80C71E98425FDC629C7F8084BA2556CEC31E707408BA6FD7A2F0AB83286A93E565FDAA34B7344474EF48FE5C99017887C8086AE4C8916914142151550B0222C5FF617817EF86920F1FC00B9D9E5BD95C6047731373DB142398EB7E5F1B29EFDBE41ED1E9BE725C2748EAA2F7A1471AAB6C15BC4596B6C6CEA5CB3C9F1E57179F96B3C3017C2244B179C384ACB93557170F4E0CD387D1D3428A7030B4276F8D3FD38074E9348033E3BB3B4A05B3366064C68E0B25F36C2E45FB0AD4606CF5A6B8FEAD45CD9790BF5BA1B0AEB5C67196C05D637E878F6D3108B36ED2CBC007F6BDBC7D74362085D651ECFDAE47FFB069ACCC7C55B726C0C6ADCE2760DD3509649DC58189CD7195B11245D76F64DF2D61B07E0C172313F39961BBC410E4000C7F7BCC52593AB7915D5B5B3E746CE8F15AFD2AFEA8200687BD1E0D767ED297347A1B0634A4F006033322F787FD901E7F2492E1B491D4F5B901FF12CA88B2B2B2982D7EEC9DEC4538F8E946172AC82CD468812EB9E7062AED4075AF0A587A92E9BD971637B3222CDE1A8965DE1EF2CD4A36F2B7457D27CD328016FD2D92B0560", + "EB01608B4B6324D02441F4094E82D3DC8ED644FD9D7FE96DC544276D7E02568453EBE375974990442B96B85A9DCF163A5974EE96274A6AAA9EEB0C83AF9A2E27C4A4174EE1D4A4035782AEF83774E93F67A5A7B91E7C8E05611BA6747FA9F83A788DA50C9D4EFA17BCABB0361E055CE6D07DADE204EF601AF3D1C7A54AE1011C2AD46C27FC060A27073781A221D182D4AF531D3056401D61024A29FBB0030B8340E91AE3A32468CA48183567199F34A76209F7846ACEE0B5DE327B3A381087204DBB6FF40E1463CC7BD38311DDB99FBD05BDAF3B84D9E64958F67421CFA09903400DC87E212FA320DB95DF83AD6A6E247E92151AEA0638D3755A6B409E5853E1A7FEB54FEC711D75AB9CAB21DDB34D7115174E01E9F0A3E650F852666D06A2A8E133C872FE9034BF9A61E29CC319255B09E40096B6D15809FCE4C8993A056E4133BA1FC05933B643B5D476D3987E7BD372412852D439D38600BE4A7F22BE1777CD86F70F05DF3B260B41DED95653243419C5BD9B6288697460A0FF7C0E2928D707BBA41E46D1AE11BF3751852DA1516941BF67E5C1775383A7F88CBA065BABD2235C155FC69D3C11F5658B019B089A9B3A983A2D2533BFF7694FC271597C42EF35F8AEF804E18AA37E3F42E49D23FB9171A312A562BBC9B093D92D45EB6A1A8A665257D596174E1FC44E117397AA7C4C77FC1BB176C8284DBF4558B5259FA69836B68322705CF783121E3C4513EC11B76329F1310731CEBD2CC8B7F49AE8D87BCAC07B1CEBABE872B5F83D71FD10F300F9FA30F4054C476F86EE75AC68F1F80E352D3F9753233E53F67C3917C26F4B0E8A61AC0299FEBEF95D9A46BBEC9F5C16B5EF127EA18BFA609B99B0B362036F4AE14D11BD7EC8ED2B02C8BCAEE2CFE409899E06DA304E23305DB1AC0A7746A72746C24E6D073F1FFFD3BFAEF300299C8009043FA392DE2054F237A098EA5FF0E537105F25B7D85355A44FAE707B0A3D1D6B30356CF1BD6EA3BE57B3A6147B943D1C96C4E2C871DB1AB64D9359F1F3D15F9DE5F45FE8E03269EBB9759AC78F47DA7B913F09402EE65271859D623908D464B1B5E59E4580BE30E01C553DCC79B190A809C71D8204A735350C75C3361EF3C89C07B84270502BAB82FF089793838B13B3041A17AB396C09C4BEF716329318B95C7C4779889956961F8D2200C163C86F45C1FBA0567C8615F4E815AE8CE2E05589C006B4560D66A67495C2B99E3A951500FECF953D9FA7FB5843F102FE0F82E72867A65C09318A52D4634A3FA28B032B92160CB2E7D6ED156586D071B8CB147D139212BC47774CE580E80791C14FE49DE7688B3A99E966A9F869B0A7421062F18705AD23AC238B52E6D80F43DCF2B43F66965F6075469E0E789B40687D104DDB5CE5A12C0B741EDBF1A3E57BDACC92265D592FDD63703E534B78DBE9F13CA04B9920EB740FB220E01DC176C09CA51EB905E32398E739C6A39C02043042C5FFBDC9BF959D56842DB894FC108AFCA51039A9B28D19D67127856E29FBA3812F764D31AD4E2FBA5F00A828F85087B4A5ACF24CFA79A3B60C954DCE40BA6BFAAE4466C88A60293AB46FA2FEEFA2E3B0DAF0CD72B0CF914848AE6A9BC26F6578D08E896479879D3469E0CF39E3EA6508A412853C83BD33D0B993678FA08DF14AB40F41CEF0E7A4B992DAE6F884E193B10E5136DE079BF85936D3B5A586323B08FAF8A39B24ADDC2D7E1EAE1F2F90A39F26B130F060ADED352AF085F9169C4E21093FB2256C4E17416F57D29CD37CDE3BBEC8CBAB280DB69643C86696C3A6D3517150", + "ED28B364884EDCF3082EBC5FCD11FA0B0823DBD808FA19BFCDFB42BB1BE2B73D5D1434C95DD48DF1ACDFD7DD17C741A387F18E7D78B2A9A894266167897AF1C8FED13D463B6BACDD81BCC2F3BFB17D2DFC0D43DD04FEFE39C801C8917D52BFE8D2E6F8C0C5159E0185805BF9DF91194AC97F6448B9189028D50B274848B429AD4DE45194ABC458485617B59FC5B1F1606DB20283A73F41A6B36731F6F9E978B276B33B5DEA3BF87282D21F63787BEB1F6FCD3B21004E6FA79330A3345F2C01C8CD1FE661FF9AB5B484B3260F2332FDB00216DA42D2840D3180B6521B01281E6D0F09664675531EED14A5C1794F3ED1FE634EF3D6E9D1B6F4871A45A83DB56FE2BBC52FCBC1E05FDCA884F98DEB436A9A238E086FB339E1A7AFE8E04A5110737F021C89EC5DCA1168E5CCAF92A04C950154F6209CDD01B287FC360B93E2A5661E7809FF1BDF3F71B40BA756411894B340CBAFF9E0EDC8292E7C316ADF4F3B827F1B82A406B53AAD8D2D660FD0CD2D6A6C693A73511FBBB97612A8CD3F0E177EE38D46100E64C4C540C834DD87E062DA2C6C3BE8A0BBC46D2070FB8D9E1DC396423D2BD1DD22F1F4FEE0E24F48CAD9241990B5F48A50B3B178A9C1CA71F71321226E98D1F79DD7F3CB75E0B0C16915E34A92750BE9EA173C276421CD0E54319ADB0C4E5ACB4BD599842E5028F613067083522F0D2A891BFDB190855B9BF36A7F2EC81EA89AE11A37B6B89126DA7C51A4BD0C902D0DDA55A4286E36835D2EE95EB46AE7D6B919C05D42E543D96D22CD241A8E6985A18F29184586E6A7C10D4A955D0A1983EEBEDC5A9FDE306FC366F77A25CFC10E5B8732D8F40D068224177288E9A13408F06AEC841C2E8612E6C794DE216A2B758C676022D4C0B99A4A54166CA1153F43FF66AC03F183DC30E9C83E6EC3BA33F63F262F39838E5C044625B4CB1DBEB7ED957B8F7CCCA6C63B837ED93B2C260F276175F2F95B235D4D1DC0C9014192D72CFE014094F29A0AB8F0A9BE896067D74BE5489F7ABFBD7EF442579875CB1795669991438C0B6FF13E06D5BA805DD2D0DD06731ECA45FC8CB9D7CE568921A60E68E31F31392EB82A39982BDFE8D953DE2CE0AEFFBF0243E43ED202FD6FF9E075A90684FED84A4334A8E709979FD5B60BCD60D41907D1FC5D927F9CCAFF2DE85AE1350C8EF8D68EAE38EBD0DA0D252F0B5C82E1C3EF78CADF92CC78BD990B06461BD77B78635C406B4109FE58850D2A97A6C23CAA18B9AEA535D344E41E783B767A439DE0762A23D18244E76D3219A10100264EEFCA45F19022EFEE72B856FC34E59ADF6DFC78D31C8690CECFA45321AEE33DFD40943B158BCBEA764C3579FD5A06BE297D363994E6B959338A3B48F14A3C58CDAF1D91EA1711FB39CF78F04E72B293B80847516DA41D5024CEBFCBB399393E59FC4C89BA310377AF576105CDEB4F6DA314E990B1513BE9DF738AD35B1460DA23326D2FBD86722DEA5D37CE5E34C11408C01E1881BCDA250C7FCAEBA9DF85AA08FC9503546A55F2B4D6A7D0FAB2F50CA8667C7456DF6972273B62A0DAF38BBC7D38B5B62F2F1EA8476F300D0116598725C0903B0323779E02977F33AA8C45C2933B412490EC17FFC2AB2B4130CE8FED8D34419FD15971EEA5759EEAF9F3E8FB4FBB26615B4286AB4C2AC57A6E4BC80DDB396043251DBAE26ADB03767DC9EE4ED3E0FC7D74C58175BC1F393F0CE5D16589879C6D53645B861B079B298E056E4539B2E2E70920D3A273398B4E9247771B8A23B276DA9A06945DCF343E7A4C9E7B06960A1F624A75B1B48AF0", + "CB9F5B3A549646C4555D2FBDAF2A79F9921C54C6FEA316D7713D64FD790325A87A30DEDBDF0ADE3B7BEA52A0E319A57084A79DD706228989642E78BF51B7F1246BEF6F1B8724C57B0A3633FCF4440E9D57DAEEB343283D642710266386DED8FFCFD68B32949FAC691E66FE9B8D736EBCA6F4551B39E79557154E9AF590B6F5CA1C6A0ACA82FF4B839B6F9C555CC57255F96B2C963536E48EC9B5BCBD270110EAF7C64AD9DAB53BC791CB111189117A34A74B4F23A8573A59886BF974528D17B31CA9B6A6B7EF7F923B8915B640C599D2453941CD16633383F36F9849C0165D94698D793A58A7869AAC8B4C007CB9E43D8DD100E9504B1942CEABBA733A242599D5B8C60AA42F4C8BE7F040877DA2648D083A2272A46A90D215D96DB2FF1ACA6CE24A2936C18B7A283615E8E6B729602D018174276E2ADCBC869C43879B6BD0CF22CC0601F7491862971F65D3E0BB2474549FA18964B14D9EF81429F08383F77E8880E858B3F350076B709046284A4BF500A6C7D9D694F03ADC9753852285075197FE5F30F5FEA91C7740AF38CBF5B984ED852C99FD27113F690CA7BD5CA46DCA330A7E30E7AA3AEE8CB62251DDDD62DDCC29C94D79759357FD92855279A8516ED0B07D8F2CF6509DEB6C180AFFE120B1C06A4DFB1CB76B9DF3113B08BE85A50BF76480D2FE05E75A4F77909E0D146EDF0D751A1099EB2BD019525048BA145C7E0B3FEBE21A13A41A9BACED48E1A4ED32A57FA061243EE840ECA69191B1BCDC0358A86DDC98920C45F1FD193D529C85B33E0135DCF2B81C7FEED32E07A2431755F3EF3EA685577A6884041C6600CCAEE0E4182CF54EEC1B078D74A18D8C81E0678A7D1309E494938083786C67436FE55FA955D3281F7F6C145B7C769D9019AE1B8666834B51AE95BEE2A8D606825C7609FD3F24057425B27D01573FF353771BD47902A9BBC41B2016086A3F9E366F96DA8AE3C62123DF05113980D8FDEAC5B2C828D44C69F2D1420BF8E7913E59FCB88845A7FA6A84AA296875CA6D2FA21A4FDF8E75B5CDF0E1C0D84FEE983A469FEC80F02923695640FA0858E9B91812DD4D91AF0DFD97655C7FDC60EFEB19DB5AD7D7D0A5F93FC88A2AC1205D1BB60DB2F3BCE203C802752350B5E8240B6FEF4A38D8F35AE5868498DCCF1BA047DC56D67F15E3C3807BD5638A9494DDC268378DDED39A910A6C7A59E6738DC68D1A531C7EFA68BE06AD20BAC86BC36083E45AB0A314ADAAB741C6E24A530B3E3FE318E4A1B3827057F944918664A96277528D185E821093D392012803ADB63A4DDB14983E844392542F2C5A978F1911A2720E201FBB862AE98C3CCDA720A244B5B58AE601C1ED814B0753FCE5F51E7ED797AAA98FCC833EA272D86A238524C07349F5DD0BA4A2F6281B2EC2D29EB546EF52F07B832053AA433A7E8BF81C6C9F562B603421787BCFF621A69ECA5CF07CE8512BEF945DC744AF403B9DF0FDD48AFFF264D4AAEDBD8702863B5A345A733328466B22FFEB20906543639F0F6F85F3F7DBBD28034019F4D517676C5D8C8CABD4118768B10158D83BFF569D3B71F30AB57B8337C50674E2290C950E9D48D6527E885A0F7CF580717CF467759CA0D41CD03A91B75648DFCEC5C5BDCEFC2EB2007AEF2F01651A328DE030546933C1BF88F34AF14D0C1F0F37FC8FF4E015DA5D25D4A1D52EEC44DA8E832F01BB1D9FF6D067021D4703E8F2D511E73ADCE564EB53A048864D191F21C759F0B629E0053845D7049900924832DB7831CCB80B36644BF23EC71847286C959BF54C6CF9EF075B1EB7F43898", + "576592F533BF0DC0AC52CA27BF57894E407D8A264496F2196DEA6B4706CFDB4E108E07FD18F5B2253EC3BF1914BEA0E7B8EAC0EAD4C6A3D2E0162411811F8579262AB9F3411327C320D27C7DAEC764EC5277EDFC2635ED39B0C497365B8C3633626E66D83DBFFD8E24BDBBF09A97061D7F530F69D929DEB7AB12488951D753EFF9F8C8DA17F3F4B17ABB9A1955F40A4EDE9D058E6F48BF1B5533D91B55D333CE4AE379E124CFD375D82DD97B682D80704EFA3DDE799DC6F7D5E55B72A99DF2A89159CAC16B47F297A467358EC67A2EC72A01007C47D757DFE274893BB0E141337105C46B159B08A0414A7EF8DE0806F90B5C5A9362E837191DA4573B473C6E4354E62C5667F75721370F036BD6CA025A49C15BF63A8B30AA5DA01CCF9746222F2113AF119DA4370DCE98ABEA322483C127CFC4AB990496CB53BA7D20255E63368FFDA40BB7022A1FC115B91ADE56B2711DDBBDDB9FB00C5FBE928F3121420288CC9001F865D44ABB4D78B3A1F2BF6B1B2C251AB1075A65A233C4472A460FBC76ECF191313D700F73BAE29795EF9A5FBD0DDB5E2E04DD172C85E15CB0A63EFC2A4E317C5FF01965FEB3BCC81CBADFB201C670F4C8AAEE2E7E75F1AC4E4AE0B826FA9F87B300188546E42F3F142AF19A4F91192741ACA71EBF29A6E1BB0D00A4534095A8B9885267F27DB9B676009631114A2EFF9B2D4C10111195F0C178D2634EDE70B4C0C87613CC9344BF2F62E9BCB42C4CECE15AA61A0C7915E51A5645609620695B4D0C913337DEEFD9195CC9545A8B1AFEBFE5F21BBDFA2F140A4D146ACC25B8332861C2EA55BA75086FD948BD27923BD2590C62389CFBE89498C82279258D11689613C21CA8F1788C4926EADE381C9CDB41D09563890433AC4BF9421475EE42AE5735D1CD10653713BD62299F66F793FA095B2E04EEA1CF59EFA731143D5849032DA833E1660A95117A2ED97DBF4D22FC0BEC0B5CB8EC32B63BA18B63F737F3ED775B6D91E052FCDBC0C33A6F4498082542B039A26BCB25CFB1B23088D9BAB9DB12CD18BF2AE73C78792BA9096AF766114337FBC06CD63BA8D1C0A5E5C6BBF5AEAC38D6B4EC2922B8ABC930F58CFAF2C65C43422193F4AEB436C05AE3213CD19F58CC7623886525FDB77DAF08CEDBD5D48233D63F1D6BDA7DAD15E817775DB4C9DFE754F4AEB2A94DE6F883961DF23801A645906BEEF9128F3F6C9FDB57E6D7B5EB46326C4C39F2C0694230CC28852D54281417C4D24470B9EBB625AD1D144B4889D23EC975CAB65A855CDA704128A61CC7C50C5ACFD6355570E07CE55578E4453CEF4582C368E585CE0F08BF786CDC2C0158E1A10971AB769872C52DAEA5D7C8947A2B6300815B42125A7B8773E6E8C79239D32D7AF37CB9D4E8688CEDCD71A213795B0C1BD5ADB0AA337989ED3E4E65DAA164C26946978C9468EAF74617C47EE4328C51F41418F2D35BD33D47A9A1ADBB7C4F5A968946A7A900C293C65648C3127EF62D58BA9995B19B10D931C07D67164B2E685FB840A019EF4752602DC9317714D89F6D9318256EDBAF002C40D5721525AC0D2BD2B4FC64138F0FCC5EE648E84AB6908C1AF71408D51D31F7587F1BC8E19D1C045D8921B447CFA9287AD03B4EDFC3FB85C7792CB2C479BD5A14B72EB8D3077CC511B0A7364C80C32F11CD1EDB4B3A0806BBE9D7765B091E04F46620C23DB801A46C544A935FEE00F0A07927171D37D3FDAD3DFA81C40CE60F93EB65E667FE032A79DB745EBCD7EDE57FD51B647CE25624444199EE2D9647FAAF9F43554433B25CE78098BB33CF24", + "A888113D9682BAFE58B278C036FC2EF41CF8C156C39D67C378E4E0EEBE750656D67250F8447C420E6EAEF139A11EC90B1B50CB582E5089694A4BFD843602382C022085141A7B8AA1DC5F68469A2C2AB04BBE91EBEDAFA2A19CF0538AE9D47421C3F98084073F340F0292B8946452251630987DDA49E56A79F1562C1EF57134F036A5DE932B2AF9ED5D24D28463DA55F4E7C29045DE9CFFC4372F7A6AEBDCBF35DFF2D952D90BD4650FDB3BD68F25B65A7876B65C5AFFE8B9CB06CF91B88A588136C80D9CD361AD83F25B6D1E17D161817E64CB06262AFED0417DF26B9B3C0AAB0A06B1310A7375352C46A410E167366AD768559A6DC618B416395F432C0CAAA8D10F88E9765F36B196B37EEF1F1C13C4AC08150C9E4CE45D9B1663FA317263672875E0BB5CFFAE2A132A6B431AA7099E47E7FC8349D04EFF0B84C3E8A743572C4B1EF38F760656E49FB1A4DF4E2D1F6B24090EC675D299B32FC5EBDE40BBC2B1DD44CC01D1935F1FC084749DF9713DE41365D8CC9AE5041D60967B25E16FF1941A9A7336DC2D46DF5AB88C14A4BDEF077EACFB1F08B834AAECFC75B5E3C1BBAFD3EBC73E187D862411AB97D694B2E557C47E5093FC15780805518758B4C5B548306F92B559DC58475464C6DCC18D2B3905FE5F60B4530F87716107A1A4EB40090C23527895582B02141386A726FFA11E9930B6099B22816DEEA2626E60F4B17C5E175A852A2E174D59FE8219C190D0D6C50C14A3C5215BB193FA56209CA4D14AB2DB5CEAC2B3B20CEE6DA1F798B681D2DADE8DD13674B9156E5C3C4AA09B1932CF69D62621DEEF990AD264996069B01E6F7A21F2E5996251D09FD955CCA7DAA902FA7D46E03AABD4FFC5A1A873711FBDFDEA0935C399A0178CF2516FD03746B86B5A80576A34119373EA7F059A0EDA3F0D18CF33ED63DC27C8157E0C43C537E86FD37E58EB5ABEB5524FE8E19B2298B9DF539C7C31FF0F7AE96A56FD3806B81088DC13224131998DF42066802ADC2A08AF6F69D36A7B9B518430C5532D3AEFB20BE0BD1BF4B2C968AA78331C614EE51B8E677B19A98E30756B39BB6A1AEF0E91915BC91D98E86FFE7584BA6ED8D6D51A132EBC124C056FBB9363B8610EB3D7A77A3E581C02E7D25184ECE47A688E718922E4672CA9567BBA9BAEC81CD8DE7FBB8CA04D20B51C850DA2A4AA63E87FFB27AC89D18FAC40AAFB21331AEDABFC3545333E57C73CB7D6B601B7180E4489269001A6786415F4D1ACD8EBC3CCD8E78F6577A9E107ECBA3EF5EFA242F80202C1EDAD26D9FDB8F43F70D250D899EAAC973042149B8F0BF7327D72A49222B5C403645BFDF3FBAF78F2AAC71B9FB582346CA456EC183867409C18E11A1BBFE6FF5B681B0F893778C87A9BE8A67E196919945F4F22D70FF5D85C55D23893E7EFD9D685C41B28B118EFC905C450A9E91112C5CEA2475EBD07DBEF0A125C298F467377E2BF8D4BBCCA25A2DCC4AC83AF877E1FC820D09F31888802B3226FB0129AB9E47FA65BAC527CE74BADAF59F95CAFCB6EFBDAC889EE8075CF7C71518535DA63E7BC9DC5668417123CF11DAB1070B050DEA01F46BD86E59C5B3175EC1C0C1244E0E7B5B6FB5D26979393E430C7B79893E3BF819380D206438174038764B7196DC0FD94D4A9CB8382CEED4490C43C19061D2BECABCDF386F1512EF3D635601E8E9CDECE9A452A0E6C6AE0D6BBBF3AFE226A46AB3285531C7AA9E0FCFDE0D9A557F20E9802139A7C8EC2B2872CBA3AAE87F0BC6DA226BE4AA5681B114E080A399BF7480E8583DF2505AEEE32E45C4112FC48", + "DD364986DCF106EED4C8705C1A9FDDF9480D337BE5C61AA3F661C6968AA01E3E454698FFADF366C73599B987DE85005C9743A2416E637E4BBB67FFC4D35F26B7539C33256EDBF680939CC8986F5BF32D2ECE4905A4F6A1727BE1131771954856A1C66A402FDD0DB86B51E9C02E6BB136465FC4253C8D98FED1582EF8AD22828B6A35580FD58A0038A9D97FE2F661F312658041839969752C4ED321D4EC8229C5753F399029B0BD5F065D5A19CB4548C86CCC1F3A9873FFB9E4F421D033E4EEDD4ADBAF302E24371EA97D817AA33C72708C1EDAECBDE7C06AE0C95D8237517666D0FB43B2434BC50EC2BC8DF1E3CB46099BAEB869B251E79E9B175B75FF62F408A5FCAA4F6DEC90F97B926272389696B5E38D26B946E0575907C358DB17D046D58D061683E07F1B075C10934FC4260043AAC28928DC877D27DB9BAE618910564EC3EDE3C402E86BC3981203CB7DCB9940C37D948556A57A11488D1332B05F4E5757D470A22D0B86C88DC456CE014B673CF5FEECAAF26F4662C9B243F46969025692E445ABF375AECBAE50EC9E48AD25EE1D1D0C16624CC5BCD1BEA8C8FFE3579C50B732625A381002115A1D69DAFF5844731F41AFCDE42CCF1A13FC98A64FB9769F03CA631B1C3ADA6A98F40343BFEDCD80966652292B60DE83385FFEA9CBCBFF51450C768EC8C4FF6FDF2F76FDA7D5886148168CE2BF693BE0179DE250D41DAA80553488D4DDB01FF97329E94C7DB33005B498FA8408E13FD5BBFE079F6E40EC5C8B735EBF9914B932A82441D9D5136C662294956CB52939F4F7E335A3B9749CC1B9F374AAC89C9AD1E718BC469CA21D2CA467F5DED54C402BA0CEA000DCC878822EE3E1D329CE76E421305178FDB31F5DAC177838197C5B46A4F96721139695EBBCF39F04BC1BDBEAB567E8FD812C355CF72785CDB3A6909F801BD2F448B3EA0C7F96D09DBE4EFFB1CAAF2A47FE6BB830FDB937CC5ED2B485AA6B85DA799C1266562DF181005A345C62BF94004C1B8D85AC06D114C8F2C5E2D569C709251EB929237C76E9CCFB9CB39206BE3C391FCF5E814E42AC2BE1576B9F0664B20F03BDA1F6431D1D1CD4C0783CDAA2A7AD32281A06B2BEC53EF1568840277EA4341F5570388045526AB214B477EA23023C13F4327DD0C84CD1744677091B21D8F95F38A8904EC5D6542AD6E3A68B355D688B1F6CA50DB7181272B3D564B1DE41C14575217FEE44E5B631CA49995EC2CA787EEC4533657FFDDE7370329C9BCC301B8785F7A307F1D06F88F21F5BD19F94827C128F799A9C354A021146985256B3D3E8BE46AF6E370EE193BDA3494E0FCC7AA287C3A5B93B638AAF9BAEA46288DDF690A464017765FC2F769A5A930FD3E5A5F399B2F972EC286E81062B6BA85FC04DBBBC05B9971799225E2F0867B55CBCDCDD3B85D6D56C6948B03E91080FBCE3B2C5438491050BD2E81C41D5C2F6790AB1F327D2C7023FD891F8D6E13D6F69E7AB1604692F21ECC7794F028A8306657D72B5858301F5296A5FFDCBEC4863D0503749E9B483E4760AFC05682304EB17D67E016553FE9108895DF3EA98890172D795009AB414E4539C47200C56828919DBC1AFFE040FB3319A068264607CE51D387B9291B7483CE1C38C1F059AA86B68BC7F852D21BF759A56557AF5B4E8CAD60356AE1D9D11AB49CFB9F627DFB1AF5BF8A6D85A775B66767616FEFEF6488C383F5ABAD4E06DF0B6C82BD2582B284BC1D4B27168525C69FFE8117FCC38FE758B2DF09E38DCB1688789B2AF3A050142E50787EBF2098C229E6965FE134593AE47AF7FC4", + "B59F424CE3388B73A01C7279251C7854C664803D834EBE840CF3851B922071026DC17B967F06E8467AD73F8F70440CF20178BD31F8CC315AD8B3D213029D08746BA9FC70AAFFAFE2F393D0339BBF28FC15B8581667E9B43E0A1534AB70BDE8954B30AFCD4BF10B91B8BE2AEDD6489D590E0947B6155A1E0B4E7DBB7D5DF08A340FE33DEF34330EC77E65B57FEBD4745B0A07CB8BCEF0ABA92E387E2C2F80230818DB1F70F65F872A2C5580A6C39B9EF600C797FF0C61641100903B5243D847C7243EADCB69F69D75F4B1D921C72A4B5B67D11B78F84BD9682963E075C76350BC301641E76BFAA23EFF0FDA33B1A41729AF935C09C1E5257F84A4AA0AA3A54525BDF1E3A51EDDA6A35A2C2B6DA82E5C7FC989475D99585A9DCB66325B98C20BD7550871BF66979BA3D58562C1125EFF230FDC77A3BE8A7A8CAEE2F83C62688E0EE5D72D4C858624C7362A57B7C0065670DD8776D1E97F67CDAE4110E53E78BC17793CD34F11089AF317407B5F43E26424A752DA5AD58470FB8FDC193D2B28FD4620C879BD22A24DE4EFCE4FC46D7A5A4350136F43D21698AEF1B4C318156D574E93BDEAC252675BB1F1819B651D08E637538DC14505779521CBA1C5695CE7C5F9BFA3A7E68E14ECDE399144E6D514CBEA519FFD2C677310214DF222CD79C9B9F763060C48D8FC4E02DBCF0D6396F6A28BED4ADB4F69FA44BF6F52E7516E77CAA981712F10E94DAE683DF1CD858492A6B7C1FDC92B3A8A4B121B1C8B8791E18062548BDD31DC544FD94DA7BD77A0BD18B3940760A3746ECAEFEDBB6B99562E836421F24C2F2A99F686DCF9C57E910748031521E359D21A69933D3B3173D520E7B8810035140A9F30DECF99A117B8C81990473378C58D1313E29A9824034B86D46BDF15479E8273BBFC4710958348B17C8EB8EBF8581AA9D1032AD591B7AB62B3E2DE12F36BF0ED71CB0DB342D5233243F466291DAFFD75971427F37549BC74CC8EA2C9D61C55FF4EEF46EC74F37E30AE9227F9A346A5A379A386E4706FC6DADCC80FC7CAAF6164673DF6B7505C1CF8C1A2C262F13A65CF1DA6D3CD277494735E5E0B4366804A816373AA0A33F3FB3566D9811D26380EF7E049F004E5540E3A984793553B866E364BF3ADE51ADEF86D37A9392B6D0D518C0F07F80E9BCF795C540BCF8BE8AE72C0A0A67160F296E30A0F5727391F82DF95DBF2376B82EE6DD6C87C05CA191AB8F32671C4E404734D6626DA299682D9A49788A7D961B737282CF16DBCB233124C5EF4800E1F25316763BDD92F090088218C071E91EF2D76D80BD05D23C6C06EE975279B0505CA18623A33A4D94EA882A6C0C5510986D537B49BAE93E363833A8571F91C47F022A6E05FC7673149128E3876AB6F423CA96A7F0F4D5AC1682DFC05BD4D3ED478218D40A42A894DAD908A587A83299D9CA685C4E25155760F53B27EC3F3E722E46E63BA2CA0D353C60DBF985F3E10893A0BC01539FBE6126215B090F1355D211E833BC019C7BB351B1A51E5286A178F70DB39D3A8DB65E510A0A93FD717FF30BB586B8FF49D62ABD56F0AA4B01D2A8E6A3BFEA54FF1D36C8ABA385D0974C7F29B25BF12B1036E4926F0E70E6CDC93233E211693F7B315C15594790BFF888ECE21352C8FDF906DEB1085408C877A98BC5B145BB1D0945E33409EB01E243D386492BD62847AA67D4EAEF5E8B84468F70457470C1FA15BBB44AE4D77BC401BC4128654B52B2B8CA48721DBB267EFA7F0B2ADAEF8C2BE9516A42BD2FC2C7AFB8D0D71FBB8A6D7034892078F4FE50A3B63105B31451A7910", + "FF81F6EFB1CF3169B63C2F2544105BE42B20467E1FF2E4204601A486928A77571247AD40EF058003E423521B4196118088D773BD1694CC83C02219F5E16C31BBC7350A023E4FE0720DCA713444B455DA085653B539A555F37AEE9357BF538E3EA6A2C3B2BD30EFC32665B597A611EE9DDBDA9A9857FFA648CBB75677DAB55EE8528DB18C4A188C693A9DA0D7DD736401DA333DDA13F572D4652D23F9016CE9D39605B5E2F341F487980331D88511836C7560B9F3E8DF6FF4CDB7F74459BA199E081FA49BA205B368B4D519B2D0ABF92405409EDF1DF280A04F398758E5511B6E6325CE00C57186A0938974207E0059B2B8BC81156E2FC0A76E84C5BBADF4FDFABA379E6F960DFF5DB82FA306535F0A8C4D925246DF1D9B8C7A711554E9087A5FDEDD656CAE74357FC6AAE8EA0C72B74BDA7BD4898C6FC7BC50367FEDE6D5261B0B72E171043C89C8C2149D01466B226F6A1F3F3FF378E34A3956C660F0FC8022E15EA68DE5DAC57BC370B30F9DDCA6404C5A152831230DA9EC3662DE701767953AE8DDB9918598844202DC2AB41A0ED711D640F3C60A8CC69BD8D9340A32330F9D27E7A023CC99D173BFE6CA4F0604FF6E5B4C59EC2E1BD4FAEB3321F755B2494343BB6E647210041A1B96A02B7755EFB6B482B3C7122EEF9242FD64D0D7BE24D320FD33ED0D4DF2756BDB13BBFB622E7E928676D228DC395DC32465E0E3480B7ED2EDDE04101E9C0F8020D48F3D43A0F756622A3DD866B966B7B0BFC1F40B1D460D6A54A45ECCF5AFC93DAF8541FCC62A5FDBE907D2DA6397B3F7B535DD8E30D400610971E4960859DFBD4A441F209021E9E4B05D3EA0C80A738F0C4EE9B03492692C543968122FE39BE1F2E5D682C1FB8549B12D6F32AD5938FAF63C5F490EAFCDA9D7DB70681B5650081B098D0BEC87013C70F890666AE984C5FD92F6939419AB0C1E981FF6EB03B1A48D708438A8F6AF81515D8C42E0DA5E13DC07D22A0CE018105BA075A696BAB7CAF420A65E38EA1961B61ECA43AA0085BF2BA6244EDCB56EAC6DED736712045911D7724E9DDED1C05DC7205580FDF52143C07960AFAC71528C1B87BFD9D21EA5DA5F9649AB037CEFA5713647DBA70A2D0456A24AFB0B55B8C859F9C9617E83E12C0D963397DDCA09CB16E22A47EAD91206E8F3D925444AB85D76DE73A43AA45BD3B0412FBDF254CF273E5F20F6BD0D938E30ECDF159120BFB28FEFC0FEA1DB898D5D1E674452DA86C9AD4AAAAFA07AC6A304CEAADA8AC82870313BBD56E746E7C9C183EF5B53BFB5A374B955D053D1CD7E8EE25108BBB8F2A60663375832213D1B9064C9F12CA77835ADFE28D1A5E1E65FDBA45147F052948A507180EF21052D5FBAC2B3F4E46DBC4ECC7DE08D6FB3B6162432B25EEDA07911CDF4E98A219603E19FCAA8142621F546C898181E1761AE7907F624A5D01E36612F06ACAA157BBC316E9AA7568E359803A408B0C36B4593DA1B4D4D6D1E6AC290C90D19635394E10F0BE0B51165777517AF168F38B702DB2BB43ECB3DA55D9CF9E8166D99B971137F6845653B8CFBFADB778E16A8F64BEF8DBFC6DD4F6F9093FE629C99585D59445ABC30DCAD609903A26C181FDF481642043066E5B0561F13934247D19975F136C0E0F4CD41ED3F8E22739FE2D88358CAED503D7C36FE755ED34B9EF871F2323AB593A0AA8BFDA8DD3D86304E206E5B4FAA6B905751EAAB46FB576C3AAC9387E38A02A6AF8EC72BC953C4831FED1337EA65241E4D94F90A0E99018DA735E1CD4C835AD9F301A618395C8FD4C982CB5282256F8A4894", + "CE812897E0C0F7BA13D73227DA8D57F576A25F233384DAC16B5F3AA455222CF8B1C3F0C69F6E1EA86C6BE0DF818820D7611EC41F6078EEA4461C336D02847EC3C5644B85EBA26B68C5927D67E36BD381F8100B6BA90852D529419EBC8118A5354706D2CC769C2402E517A86809687BA7E0B1940A88F0B2586484EB7D1B63E119D489A41691D0C1A88543D43D8962D17FCB8E91A6CBE2635F4D0814A8C9A4DCD7767CE7D62E8BF17117A6650E3E8933DABD4CCBA43F40ECDC46EFC541CAEF6271E87BE92E63DFB7C2E5B7D7D2ABCD56A0A19E3C9F75894860A850029ADA36F990DAAAAC5AF56B157475EB18943D7CCB8D99CD14813A27036ED1F4DE3234BE28FBA413046A26113124B5FEA24F4074E991E163AC879520669ABE6B1A0203FAD6E4082CD5ECE201A86EC87676E350021FB2A1E04AE9B19A03152F8244542B4D21B4173D05F159EDCE12BA12A5767363794DEF4D390F56208EAA7680AB527C2035B065DD58AC8182BD5660DF75511EE1E0F407F4EA72AB3FCB028C82D8FA3003B034EFF4DC1C179029C452BC4B4D75AD02CE9E393C15872F8D130AFFAAE9A95640EC68771EBE628C42DA59AE4AC2E9156534430D00164E3D2D28665BD2DE6AC1482EE3475F7E00F41078B672835B435711C560166CB4DF17B56884C8A66DCE5D4B42AE675335EF457AC20E4BE7FC32FEAAF7EF4CAD795ABA7F9A20C6703E7DADA30B63CD6CC214114242C81A9614712271CC05867595D9938ED557007713F36D1A44AD2285A564C9B242AF6BE9979F7C474385680FD574D9D33B8E2DBC1318EA71977FF83E8977B93BE3EAB2401A136E021DA182B1AE68007FB36067507FF6900AFC4743A9A8503B7A2CEE04A1BDBE9D661691E5E8C6E5568D16F70C15D156F45DC41199A9C67FAAA36D8CF67672717ED0124E996CE855392F5A8BD24EBCD644AE0CD5B1AD2711200130AA4F8D3B4599AE660A56EB6E192709CFB8890510CFB0195D7FE794B9EDBCCB25ABE6F3B6AAECF3FCAB9ADD6D270D3D5B934C46C8D6800CFCF99617AAB8192C28AB627EB0D6234F7C68F0F4241662A9F062B361FE89E92BF9254F823E4164AE54661C2991A56C4AF8884DEDCB20EAA02D3097F2D5BC45FAD616F2DE3F37FE2DA9CAC838ECB3BF649AB6CCC38675126381561D546B37C743241297476497184A861ED1FCC75BD508915AF39752866B39F1BF00799F3B254C6710D15F5F79E29766E3EB75B93CEEAD0F3D454A3A0A4B9B88534AA91B604424CA1F9801F7F16E0A5489CEA18CCF76537CE33481328C83F3205B59AB1BAC1467C56A28DA696DF2B08CD380049C5E0FABC6AC8C5C50F9481161C1D60B0976FF459B2C11679DF8239AF63C1379997A8CDD47954DA1A9ED1606A3D1D2700A2B9B0C9FEED839E011D52752CE543ED224E5241340CFE1219A1A0117E033F48B262A6C83FB13BAEBF036C2ADD4ACC5D1CD9C5C334F4EE7D964851D9A5B7CF5A38B3C1CCD6DFDB5D1AE3FEAEDFEB72A25C7CA779DC4602FA0E6D8C4B35900F634130D48BDB8291B7BA751256EF38FD6FF0D5662C1691B825714442F5B633B30514058C778C78BBD6A70A2096CC9A375AA99CE11E8FE4388ED8D403EFDA3E604EA77820D4D7A1FE7C51B73F286520D56DF828B659FC636DE3DEC09FFBEC46FC143D943A09634A91194D77F0A70DAED26ABD3F6B51457EEC61F9AB544F544B21A1284F0E70D75DAED0B9D0FD864CC73236CB64EFC7C696882B1B408B6B02F35EFC4B5DCAAFC600330C59B1338DC593BC22C86A1C4F16D72E7BD622A3561F60362F3612580", + "DCD55CF8406A7CC9BA0A5224797D74777689C4FBC0D202DEA8B9773A0F20DB0438BEFD40A996EB2E3F49CBE2E475DEEF73F112FF742269A701AB43D8E47EF94DA4056086D86B1FAD636D89929C60238133A5B61DC4B7F8DFC765CF0C8C7206F3E0DD3DA13407CA75EA20F172AC38C42ACADC946B3B18BBB30DF871905777CFE0D3BE5363574D2545D0214D6A43E2D34B50D7FF7D9F2DAE7053736B71FAAECFC2C355C1DA645A995981E1D617BDDD14EB9AB230D10085DA1AE55D1C9E55C225997D128CC2393D6E5BE9F1BDE1543DCAE918B38AFD5FAE6031E105BA12EA4162F7E24572688C54291A61635C9DA26BB367348473D4DD4AEF9A5C4E8A6512AB149D62F625D8D45576FAA4CE28E5C3D52D293A0D5C48821E1F5CDAD7257C97B3C1A6DD83A4ABB55F780D09964D4B3940D36B6709D00094B89F319E1C2CBBB3EC33A6F0398880B8079E6A39DE697D76803B04C230EE980765604929D60733BBB6382B4CA4B13AD3FC48AC9F944B97133C5AE6C3B9D295A760D786DDBFF346C873C2DCF3D2591926116A318F63835783A33A17C452AA6C620284BA99DEAF023972082AD2B370CF3016F0739103A518B25AE8D59BB017C8199ECCAF3E908F9F144C778E0F5F47FA06FE8A22E3B2CE3493EAA8745478D653F8D3711F832D9212D060A7F0B0B62AB9A3C9BF012B61A9B5E6DBAF4B48D9031250419627E96076925AF95E2B238E8CD227A0F3D8C9C3BC68D5990952D6CB62803B8D193FB06120BCA9B195E92B995B86B92C455A6145D3F77898E457E1B938183E1D76FF61C163057A4D70697507BE020CC28BE6527CE306A5D2506B86152B5E3B954D5A660C79CDAABB2EEF0D135C0D4AACC7FC3EB5A3575D95070B168FCEF4F9B36FC3D55B84DDBEF10DF6BA659F70CB2AB82FA001D51ED0F040F9DAD4129C324BE8B44316C0E3E15B27C2A8D54A948585834C2DBD40337B61F58F3AB99B3303D56EC1D30ED82F29CF6A68208B07DA120AC4073F102F4D796E38628D344384551810998F6211A082BA225A1B7D63C9A3E8703DD945BE1D979677FEBE715396988A873B88EBCB10209E4DAFF939776AD14C5DC90BBE9C1A57581A145BE0D4BB47CF50721EFECCB50C96E824DF93D675B1A1B4D920CB1EE82B0369094DD84FAB4A3FA94F152F87525ED6D17A800EDB1BAA6C13A2EDB5C9B7C5A82AE5824AE9BA63156EDF78517AE2B357C1A1E8EF6CB12DA415A914FB69FA633527B8A1659292D079B580DEC210231BCA77465BC6A9516F2917226957DDDD9787313FA599BC2BDD14DEC9DCAF0F2520318A85C55DF40881FF65E4AC21F2C9EA3CC06651309E1F89982D45FD6EB5BD588B647A80D27433EF85080A7AB2FFDBFC7D2B54B215E7D27A333D4942CD23D53142F04976093CC0344C19F9CB3A5A4D522E26B7E2C1C85C1ABAE1B4A360945A46D097A1F3676A80E3BB9CBED0BD363CB70C2B250EA053B183CFD1EDF2F6A211CE618F70EA1AB535E96CDD0B2FAB7CB7F0396B6DEB59745C1BDBCD452FFD70C95E45B88325A82CF07EFEAD7176FAF04C8C3E0CC4458540BED99ABB9F52AFBE48E42C636DD076A37C07C8E4EB6830FAC011936EC047F6D5B5857AAF90F80B5D33B502A116828BD27E30B3A69F351E22D943A482BC6BC41BE7BF941F3AA7BF85A2BA5C38FC930680FDE5A4E174AEC4156A755E7650CE488620D6CC62BF9D085FE1782EADB11541A5C19C9061734513316B9CA608A6E48D333A110B57BA5128E9331E6266174B85F7B7D1DB264361B1C6C044A8274A7C8DB19C253BF8DAB819E85130E920", + "79E4509D63EC15D4930F17DB3EF8E9ADCDE82C9F2308A0C9F77359575876D90A9CE5ABBBFFE09B8E145F35C7E91B141F66F74B3BA923D9ECF863A8A455086DAADC247872C953476A85772079783A6F37C964AB1788479175F7B4E9651C7DD5EDA94F8BCFA57B3542788FE9547E0A444D249976333F99710930CED2E93B1526A02BFCCCE416F0CFAA631B878BF23E41F95770315F1E169EF22B9DAF0E2F269E06B03B125CC6F20D2AA9A13B98CE23FE3A7FBC70CD05496ABD89ABA5BF58FBD8D88EB9653963F0452CA43CB964F7B145020D637905E8D26E8CCCE4EF892BC48381303161644FCAA1DB9C4775E8F0A6367F1A842C3101C9F94730F6724257F2EE1657CC93950C9C1F20832DCC11E0001AB347781F21DDCD4786234C908772B553D7BDF4795FE69D7D55E950D4C6E2A76C44995CCA5C9CD539ED235CC55DF6A004C1BCA852C2813DD17F333CF67711EB8A5DA439D73271272D0D62B34DD457C7412A26FE2F4F23E5F5AE8C2F91DDF86B7048A40872AB7C728B20DF7AE2A0E8E52B00899C565E68390DFC83344DBEB7257CF8031664FD93DB65738013BA234035F11B611DEA4F74B1000724B2682EDA9639C11F4F4580683DDCA2D9159F637976293FDF76AE2AC7EB5203766009577DF87D9DB654ACD64229495A5B4A94AB3AD8237B9CFA2B5AB6B7239A5146C777C4A3CCA9E1573D96A7C1B333F11D284AEB55DBABE6B4F12A421FF7BD442AB6B8A7FC33A2087886328B33037EA78D9A7015ADA2C8F463AC1FEA8FF3EA886823063992176C31152573C10516BE386CDF81A6568D8E3BA2FF195B23903C95B16277BD60D238F309A7DD6BDB4ACF4541A56DF5D3D4BA4078E58641C0453B1BC8DAAF6F1DB28836D6FBA3474D69870E07997DF4541BDA5C62291A3360F5C5840752A25CFE366186F7E4E21DA0704266B5C14ADC1541E463917D5DA677945574F800BF47FA028E82200F9E53C48C887355D9E3CE5FB778341A356423D00B18D3048C92A80279C2785AECAE9EA57F828766D6F953AACF93FBE8A4C32C7FC9843F466141DD018CBD05ED8A16E27B43C5C0EE16045D39CDCC7E4A27EF636408E968B4C99C895CE77288C819701EE7184DFCE889328E4CD2D8BA7BE5A1DAE50E36D562BF2441B56242EF9C4EE63022F88F0F77E6094AD7DA93F672C06B6BF4ED5523D1DBE7D8F13892BF90DFFD5D2A3BD0E9B56EEF03E560BB28650D873116C0CDD00148C90CFCECB6BE9C4BDD7603B5CE9FC458431C00B1D704702B552D847D0C89265D842FF6599A150854848B730AB33CCF2BA6533638860BA564540C6678061CD97BE3D00B103314894AF13999FCBDECAFB5A895671DD1ECDD95C0C94A250B014CBB657ABE3028C8D6CE436FAD8FB7BDD12AA2DA32FA6435889F1B8C16EA8488FD6AFDC7AFBF5358A31B23E0C05E315B60F180986BA17E26621D92CB639A0B815E65D140BA8A68F99BD42A2F428345AD3037274E515684EEEF018BA41A7B0138D7FF2C0B838823192FDEED577028052EE73D65E92812E4C33FA3CDC11234F47F702AD81F3829ACF1910B9D00167A3541372DB79996FC8F4B15F2A56B272B7DCBC4B074A36543B12B3A5396B0635068B62F81A56E33B40516A376D4ECF7BEA4F8ADBEAEACBDBE23F5F311A39D90D0B11BCAD30609F6CB4A657CC620CF8F727E30F77618E5870F72EDA78EB89399236F7F5432560049262E29A2979F832F2B57CEB25BBC2405A3098CBCD3CA0CDF631B37440A47D316F4860597AF78E5ACEA13E8B8B5420210D7BF54B1F07A433E7A2B193D7EEFDB2288", + "B63460020483CDBB47DB98D8D720FAD57072D41EDB5FF2A2CF65DFB70ABF3524003842F7BCF9D36F8E187F86B864C5FE0181E5E3D33AE11A50E67F56DE93387F5CA7D1641CED92F7195F2ABCC7B32C6C7BD8AE561E36A6359BA6171726A2F9B00C7655C7E346310C6EBE10D2D470BD5BB7B4C88378DBE2352AA45EDD728F42A3DF3B5E80BB6B6BF55CD663203437F575F769CACE66809FD25933204387F8C51E0A6B2C4C6113DD45D31AD7567C9B924D5B10F124F6C1CAF3458B3B84E9E42DBA9AC879E2D711ED8681207374CCD299FDB7D7004678D56FFFE0CD34B4858CC0CF4F611D8EB5B47768D69AA69BB1875E9C397EE9453D37D4983359393A02941E772F912708085F2FC7211DB358EA5D4E00263E14A1CA3430A6E6FBCBA94CBC8281C356B4114B0E0B67B3265D3E1B9A64B1D4BA5501CC0F6E19F56A7B3B1BDEFD8018340ADF7640C58FB26ACE46B788FCA44BF228A737B02F160B0462846DBED0792B27FC6B55757BE01FEAD3655FA9E992485E2B29321816B04C2BF079BA5CD01CD7DC0CC8CFA471FAEC74C95041B7C62DC9BDFD11FBD4D3B7173A3A92044C793EDB6AF4DCF760D38D3D412B3B292C74E08EF4B4515B99A0D4A167D9103C3E776E213AC2C1614B432A8A7D243B0EB5E7AE82118DE996BB55329F49ED4A7EE738350B565F50CCC313DF274EA203757B372D542D451DB960DD8D7F0C5E532AFBA105C7963A39426732E2E30C68317C4CBB3C10802C5104923E9EAEC89C6F421B8EA3D5039D5175F1EA854971407C7B260BF57FA912DF3829BA91BEFC9A7A88E5A289366A88E7E6C5C4D4781D583CC15C827A4FC753F66C81B5095D51F3069AF2E3BCBF01362F118690C35D3E6B5C0F41F4A4964226E4646DBD948FE2D1AE837C0C0062F77A40DD02371EA4B69BFD02803AC3AB972CF450F59FFDE724F79DDB7D534D261A44DC4BED2A47E78289BEE615218D1F861896AE5B07729568508B0E35F82BAD9387B52E2243E456C2DAC3F82176E4859A8288FB8E2B86FFF4BEEF93D9F677CCACA1E760D045F28C819A44F5F678E61585B74D49B1F12A9B28D4056CEFB98845385FCA12A6AB0C86DAB01C7E8BF5D77618F797288706F18DD71B33F909CDB15A63047D0EC462BCC02AA7E6D4D4D5C3D0C5FA2C03502EC51D781E8CDBB63A2578CDD9116701F7840D6A268DB082223F3D42376C5D796557BDC568791BB3A5BB6A9F501837CAF0ABEFBCBB500868EBE0FA0184ABFB927A414A87BC3A1903DDFBAC369B77B5C9FA203C7F6CBAA7BA826867CBD37AFD20E32DBCDCBBE7C12E3974BA0133B9ACE768AD4652C3FFB01D7E2F4EA026D543B2292419B10DB09C47C110005D667EED5D066D4634175B58F4BEA53CC39F2D1A9623B7C9AF2ED29A37891F2BE24418746A233743BD340256801EE39E7C05932AA41B56F7DF4E479A365BA224E94D72A395741D3D8135208C96AF089FE2FAB29B9D7DDB02D149275727E12A2358F4CAF9DEF137397AAB54DF78F5CEB17CA323B696C3267A4D2A944C65B2E8F542A2F0AC3DA7A9D6F2AF073FDED7424942B700AABA291FB8672DF10AFDD154218C0B0088E84486EDA5F21615C06770A2607E93A2ABA60B864505434ACC6B6BB15BD00C3881E59F0B481653BE10929E7EAF4A90BC181DF76434C08F3ED37D862038232AE6A5C56F36F98574029AF4B4A280693551082BEE4CB6DD4B55E00AC4954F2A01129861DD2A70FC30FCD9073FD2F45B31CEF9724E673032D0C87B2A9FE7706040293B6DFC3A3197AA58A53997BE5A2A763B027D5E14152774E3FFB8", + "6D562B96C4DB6F8783C945E358693B3D99B7D8E77AD50B7FE9F5176AF257ACF63E037ECE9FC071CBA13080A08E1116AE09151BED458CD8BC9DFFE5744E0CD2365293B365A01D30E894F8616AFDB6115663FA15522C8CFED9E6644DAA1AE776E0BB2912CF584AD1DB53E90043B1F93D67D51B1B10179F0FED6EEB52A127BE857341CB5A223864C02E4AE3F3902C90BACAFBDE2A42D73DBE88577F871D9C2EB9885C7CEF0443EE4A1C449951B24764CCBE716487F2EBE474ED6DAA65E393F1AE17E52B75EAFC245A161AA30CC8250631DEDD2B233D202CDFD1C3DB64FEEB2F515F2568DD7C11DDCCFCDD77B9D1182A29AD5813791DD9987BA735082F8A669F38DDD84EE7C09334AC732849119D769DB8CD79375D1C8EB4E051777A057A4738FC4E06ABC70F8FBA6B52948F91FAC2F2E248F0C417E2E727C60872F905DB2CCDCF15B2363696424BA5B62E98D5E4B51ADAF38DC97144CA32BB6DF129EAB07313059C725051883475E30B25C8CEDC63BB517319ACDC1E0ED86D5BC5790F11CD2F4B2CD882345706A4CA5863C0395C3159AC3D7FF8F7B5F7B59907CCFAA53EDE296087B04FFDDB0B221B3DCD1A6C64A591729A039C230CA52C94ED2C3118794876F7478E7968F962004F01E8FD0546207A64C09A2292376F77D7789CE2CF04995C7EFDEC91B5F13EFF915E9158F6202D6A7B0B97BB1FB121FF99AB12F56732E9049A2C33597A308A47FBEEE3F530E357BA6B7C98D58114D89C0E9599C6B17BF409B3B63FCF67DE29FDEE152711B63C02F919FEEE1A31636E36ABB4F9BA607020529814E06AB2D8E4FDE4D6C1A0D709ACDD7E442B1EB65643FE7D9E8D89906915AA868E9DB2E070CE6511EDA0506A19A731C0DFE149788BCC155B829D52E2921430566F9DB82DB062023BA5FF61FD26F8209421EE8C2C22FAC9F58059D223B4659A23BE538BEE894015F8E137849280668B971AD628CC57ECB49701EA1F0CE2D07B2D7D8406FB1D2E010A51C02F6F8F04F38703326711B85ABF70D46D947A42855B7F13B79D39D222A3578D6336C9B8A69A12DD38184EBF9DCF787C0D7611AB4176294C239B60351B62309E5DBC92BE0C0EE1422D9074905131757F70343CA00ACF2CF9DE239D8C794AC868565FF9900A1B9D187580884D509642AB4F6331A89FCBDB367067712B7B4A7A32E266D7FE571E4474FEB5DE28CC0D480D4AD11D0CF6B599A56925D68C1B076CC57612290221AAA0F91C8F7D21EAB354310250A224BC0455C760F62B2981ED68F7E10619AEF954B79D0D0DCF039DF951BA2245DEC02E71968009ED5364774644E995DCB33A41D53B3C9C1BE952449CA8E671E15EA888789CCDFCDCC91E0ED093CBFF538909886E27972C9D262F5E1A481B8F483BFB311D1595F51FE1AC8CB43EBC92C0D17868986B6F2BA8127BF95E159776570E273393FEFE203FB079780E675BD62F475CC0D1DF76CCA50B5145565C3615498DEF9B7BD37887BC6988A9853B4E639C1BFB61E32954D1166156F944C722444C29AF577C12F567E568BB1BB44A9D0783F126D6A079345C3842AD6240F1740585102F558C5DB6C22A057EC2D902CBFED926BA5F9C298E6F9118B9D2B446A47E4DB2F4F1CC30E75B6A1B67FDA687E672E7136AED3E02F8CC346F520E5929526B6E9126450E708D30168D1A60B41D19949AA4BA5CB7A691DB90A7B5040B01518FDDB6035454280BEF79E019FB96D899FD97BA47D0A7EBB39A11A84036659598294B0B9A905CE2E0CBA0E3AFAC85FEF2CD3446057ED5DF2FC389D411CC3128A8DD23188F830D90", + "3A9010CF2726ED13F833686B6C7796E87CEEAF4A99B40BE702CF35774B6BBE4EDF528C39A8FCB1B04AB9D25FE6666535391A45D5DA45D8073F705184427C3C5C4225F66F041151A22423A1F5516C744FDA91305B2B70BC11569416ED456BCBE6C1A47A5805B464EF6A645682D88D75E7FCB458BA2F9C44E14589D2805A904AF02FD3693DE69D0CAC00E058B26277018C3339EDA876CF820AD6C99149BF76A8C47ABF795EEF76D55862F4A88B26A73385589048B2E22C542461AA9CBB41DA58C7A5A32047B9F85426119402E531B023E3C8C1EFC7AF70D3D553B50408AB568E4D2EF96E5FAD8BD3EDF830FF2B12829E97C5C57927E69A438737B1920553F2B921E62A3E25331BD3BBBF99C9FE1912E0A84B15EECAD16B03D059876B7B02908C7A7DDCCC51E01213B4829D21C9FE65AE129F3B58B51798C604C9A2D2BDF7376FBB50732D9694E199DC532623309CA43D837EBCE0EE9F3943BF57F9ECAB4D939B2AE599FF5CF5370C9B56B7B9800A651FA64F854962A6D84E1270EFE2A481D399DD3F35C9C43605FB03315259989C4F2EB41B83C62DC2F7EA15B315126D227A0CED8B626022F9F665B49B8C32A10BBCEB0AC7FA80335A255076BEEA7E5BEA0472531B22E07A6579F9726600E661B389A221D2A6D2AE9E0059D24874BA5AEF82B1B53734F0835FAC5732FF0AED0F092E06EA84B3B5191BE3D226A41A6BC39AE3064A789A8DD9CED68FC3B902249622576D4086D63B924CB0C309F75F1FE9A62071FD2629E927A3ECCF3B575961221C5C1E76D2D6F1D330028F262E671905340C7621150074C49D9D3D64563E4E6C8B3221EBDFAD5A369E25DCB2C95A1E19D05B4ECB8E605BBF49623F6C62383A4ABF25FF823CB5F924ACF6D6173BEB850C46E0CCF6AFA873096046B7CE53271A33D18BBEBD6452D1874E312B9DD2035E511FA43BCBDF3E3A9EA8C602EFF6051AC0062232BF8A2C1AAAE76F0C12ACF4A290AC376A0DFA55BCECCDDFC1702D38F74BCC3FDB3160C3F52518EF2B1E14CE9CF22AE5E4CF2DFD531057EC85896708C8BB9D810B7D258AE975D678F19139A760F5609F57E2558E1AC0B6AACA4636017083D25190CECF73D29E2F7B44393D274074A68570B720EE6CEA533AD788F9A7F127BDA09D43F96AB9863B5365C9361A9EADA698F5A616D5EA0EB9F83B0647698DAFFE659979F5A5F086FC8B59D53C737E2D38EBB4F74C5CC6429B526FEFC9D1426969AB14DBD3F54BEBF25A5A8846874562CB282B2BECBECEDAF015F41037486297B30C905572211F80727CEF292CB2DB118157E666B190809A10B177BC63158505BAB5C915D37626EF7CB011041B08B03FA92A40EC3E39BF9B4D7279A5D1E4CF38377BE6C00EE12CFB4549C036E75240D3DF9FF92B50954F461BC25BD155AF84316A1752B9F1834AC4DA1B1B5A4C84992141CCFB0CC6AC5672753F4877403FC3F4A52848786C976B18CE968509A4014F3C69A77F9CB4915A1E389C1EA74A05DC08B6A6BB1BE755365F1E96E06FCFDBC7210099601912F55F639C9C96F28460CFC392C855CB2D3986989FF85A0DC7889AA2F6AEBD3E1AA196F97A3C3A0FBB33ACD3BBEDFEE06606DDAC5DA26290149E6361E8BEEE7F2400588F3FF853EC85B5F5742DE3547F362B0A094D6F935DB0A2B5D1480DB2CEFB9D665887F6030358AB9E5B26DE8955B188C39D6B146063FA59D1BA260796A2DE8CDDE8560915F07087E84589340103CCF7E1B75AD5BFD209A99C429A52E8D4FE96EEB9A32A4CD24A7940B446003E1F8296EAC6653659CCC3C85E01F7A154", + "59CD72F81F8FA04AACD73E9C815A312E8C02F1C1769FDA17C16350D9EBD4F8D10F248035EAFFB4FD67933279518E3BE9E1807288A9D63A6504F3A31E7DF322AA1B2A9ED3C23717C0C5B134D2758666CD04C2FA8C1EF5C1E58870C5EE1378619851845BA80DADBC37A764BA17E6DF285BB3DDFE31A56D4BAAB0FA622B8D3D24B7F91034D2F773FE578C874FAF5204F3DDB90B8533906AE05834BE67263447FB4485BA069EAACB68806028CFDAA8FC6DAC6383837F9A059EBD1529A92F98F44D55AC06083D6B751FF8F9FC5A6444C1A7D346025AD4B67EA12439242FC02D228CE537AC9044F6D193E0592684FAA4D259DFB00F5F98DCA9FAE4C0D5F0427C6936E501148C56EAD1817A81DA30989D0D9C85BF8D9972FFE67AE3DEB2A8959D63B3C3E7737A1851EDC8B313D75AA7838C6F7750280FFA6321CC9228ACC596431D72AC0302582CA56C6172599F30D0CA04E71F3FD7A03D467E37A8320CC0FE3AC72099CEF7C4265F7F18E2980168DACF9C058E39EC9FFE1EEBDCEA5F78D63BB18BF054465179401346D4CF8927580B9E0370B2D27E4C6BD4687CF0D4348B04BECE8424A42B2CECC668DF9809F580BBB3F3D59BFD96DC8C2E57EF5D2989D6DA54C04B15F85EFF639253DA3301FB6E6F92264FE48968C2C2CA6D40C54C327E0673BF769CF116DFD70CE374BC447AA1B121827E5BA510E387974B19B050D9909185A514BCD8CD374EFE2089290D3DF46D088D74F556A8E5F36B08AB17E54143B6FC374BEDD6FF88AE74E71C72297A31E13D1F668DDB455DF00DC91DBBDB2E96ACDB811ADF7E4C1C460D8FF1FB03BCF95EC489446A8DFC5D2220E58CC298FBB7A9B8EB33B61F6461D77CEBF9C36BBA32B34998B7B9B7950E7E98857371003F40279FC2623F716B808912651E55A04F9418989047331C454D2AB04FAA192938209261029FB3C070FA056D2AD52BF9C7A0535FE2868888BA55CB9389E358CEEC68D7A0E5505FF0DE4263C6E47406EEE83E8C797BF58EF49F2F8BB4EB3656A2636A5EC604A4990001190A8A7965A36BBB41019EE19C8EB45C10173B513F617B9688D7102ED82E60DDCD080233A7B3B43B641A3282C4AF6D3F01BE30DD78AA184B9D565F7B1F927EDE214E363A18547263412EBE35E939942C4B5EFE81E439B325902EDD4D2AC06340296D00DD5F0908F5C8AD88049D88282D0F2DEC28D133E1D4736869C352A7CD87D8A56687CC25D5517A62F0CA5A023E8709F181A0D96F1154B3D7517EC5B076B7C59DE90A223B96AF93F94B11EA0EB08A280379BE028DC494C296BC46659CF9C26A3F8BBB47E063AA4EBCBC9873CCA2866865CF45076E6E642B8E3BF9F4A3F9F057DCE71D4D5F3B621D8791CA5333398ADB31486D22F608E9A8745B9548EADDA654F1D4BC042DFF9B3C21B15AEBC37050864E4275D5C36F301D533552D119039242BCA25DFABB524C971821B2C0EEA602A4C02C6487DD113DA4DC5ADD7BBBC325CFC896C942682945A1BE921FF71E6D76FA1E3345589B53C549BD5056FA01BD688D0A9011497C0DFDEC20210BC7F8B713C46A100A396A9ABD9A2BB94E5455793BFA28E39E130645973C30FDCDE52F6C272576291F0130474DC2E3C30EAD54818E9F531A538028DD40FE01D993DFCFF82679DC3C66850528A173FBB534843AB540E21C7731C65044D697B42694A1654B3572FE321F61E98EA22171580F5DB90C997D0C9C7CF44D174E8D24F500832C158278CF62BBFC6DFC46AEE5DD3F8906A5770C3BB6CC3B731243974A76C0BCACD9EFE37E52CD9751894A68AE3596E0", + "C0211AF7A94B37632C667AE5097F8B5992917210A515C3E48276A363A6F5696AFEF5B3919689CC8F21E077310FDFC5A58D6BD428B8FFC678299FD053E7C016EF3A154A41DE5FD3C3BC5070ED6EC8F16170C880F82EB0B7EDED047436E8FCD4E2290F450963133226D17D7BB99C71097978CEFE496032EC8C6E73B99B05A33C4F5373BB73CA93F7128A9818197E6FD2BD88451A4D8905214157C4259228DEB5F8B216FFB206E4EE1025D3E16987FB6064147D3E99CEED73112F62D513C8B6F19B582D0F6794B307E8AF97354573C758AA95AB0A926386E7D288D74F9C6B0E2C71EAEBB36422C2120511F5F3D2B308674AE355B1FA1E72DA55098AAE3C70CB1B85C902C103056E00EBB70D37F08FA4D90E860C74E841F4E99957B3097ABE602E65F07B8787DA172E8E9ABF9ACDCCDFF6FEE2F902082BDD49547EFD95B54C3B8F6C6D243D07F16819E03189F0A3F3E0D05B3AF3EC92CA08846FC909E809CE9C30F1F3AC6FECED9043245A00590CBBD83EFC41C9EE3CBD0E328426F821ECA32E0E84A8B64F200DFAA5F01B262F4E816A90AA33A2984AB8E269B8CCF61E65094FBB7D10E11F9E1022CD97F17011DA53455B24E4ECD0793486C1E6D4E3BEA94E6DC9C710CFFF30CCD48E43076D763957260D1ED4F7C41EFA0B7F78BFAB7A9274E932013E605246C36CA1FFA003A4B24DAED61D15327BCA1067ACE961E718DD5E57667F5F33411D17BE093A9D7C6675097FC551014545727BA3F19C5D5D23A0922B11C4BADBF285A17EE96C916238C1E1DE8A0D28FB79E72EAF5AC37710B4E6550CEECA2F22697DA18F858507CCB95BB7F25A0056FFA55EE9564782C6042686195BF56901D4ABB3398C557CD47D30EEB344B532E77566887693CFAE50CE8C0BBAA204465FF33456ECFBB1B4DE4F8D6E2F3E8A84E90410EE3A79ABB47D40F4691CEF37E0BDBE1BE386098181EE36051EFFEEB0F5898738E400D44ADA4B3348315E0BE88C4C43E8CF95CE8D56EEAEADE754A09F170D3ACC44DB101037E001DCFBE2C52DC32D040BC27C1A55C9EF5D65FE418F3B761284C461606ACC84D36B9A7A3C9353723BEEEC80CF75D84DA7B2533F844E81EB8835289487CC7EA4EB277A4BA4BD50B59953E3DF3EBB2BB69D7E148792DF55D429B2DAE9B40B00FB14A948F2797B7488EBBBEB4B11880F7D3062D3C0561D7F6FE715C3BA6BC703BAC33C29DD87EBB84C178BA09961F2C10D8CCA42BFC3977EA66D039FC24CBD2A7B3316EF37C0D0F98D3CB8D5E4708B4287FEE6B656F1E300260D5643E9AC323A7F0527A7B98174AFD3277D35D6EC63865BD4E816351B8492474116E2426A3298606039280AEB595293D18EEC671E1E139EFC7936CAE3056F9698BFE95568D050F281F17F2CD65B62B98BF36DE469474F440E27073613A121370C606D5729DDFA12C8C400D0364251D850D90804ABF000ACE57AB195F6EE24163E8C443C8AEB641AACABE70675ECF22A5B9DAB6DDF0078EC89F2354C27D296411041432AF390DC71CC6141B52C54FC778B5BCD31B55EDDEB62EE364983E97BBB65EE98863AFFD2310B482AFCC28A2FE9C7D8E3ED24D20FFAD1F5B0AADB344C77F89FB88BB2FDCD64A77203BC331FC23BF78E284ACE3016FF570E3AF32ACDD5BD5E7B59115950CE804C231AB1AB80276842FAF80A576C9A3148F527596252E2F9F76FD6B4C03EFCE924A4740EDED98B290FF138926811607CC553FFAD5ACE0FC24D7FA1D7F3701A8E0D7F614941C9FB9215389CC5EF6D3CAC193EB15798CB1FF2950E2E0EA96A6B9E672CC343A7FA9C", + "28EB964EC60708D60D921BCA637AF0F0E19E127E0E563EEB30DB02F8FBF2848CEC8E351077A8294AD441049000D2A3BD101B691C2F1DF3741B8BE7DC57592C2D09C9F368010B4B3922A8A622887C37E959C9AC31DBE89C9EC9FFC26EFDD9C49362E3400E660928BDD7F67C6E45614ADFFB96622390AACC03F1186D18BD11333AF0348125A92EBB40370A32F5E383ED858F6720D43633A9A3E3559A0ACF5FCC326DF117AA495759FC12398B2E060F8C6DA823F3E58E1158B81AFEDE50B89F956D4F63619332928B4CDF5A16E0536FE7426518B1C50FBBEB4EF3830D77924BE1DB002BF2B0A9A8CD6FDF3BE7D7D1D7A3EB4E8CEFF8BEB9E2CEA9BCA74349D67413E7D05DEC014D1E6990062F0C4CF1E4720D45E23719D748D0C9BE3C3CA444E357F181E44EE841E35CB5207C3F993CF224A4A90EF5E3610254EEC4C2F2EAEFE041E1791518F93BE9080634AD5594B98C6D0161BAD23EF1403FEE6FF846D344BF0B42A65762804A33F00F12D769B3C58F123E14B4001CC631049F6E35013DF92AA50F89E71E78879A9B428341A738CA001E4233652802FC16AE2377C9C0B5650805205D31445EA0AC0F82A109E5F7C0758EBD5C737CF48D3D5D44816504D972CD2FBBF0AE566B8247F81E404D7DAB5A939AAE51375154A3125345C061CD479F8D7D9EB21C6ACD971F75D8430FAE557DE7A669C59E35DAC4E7686C53C34AF64A5AB7F6B5ADF48585417DBA3584D4552C241DEC336E5EBA84C4D295148B29FE824D3934F4D2A8EA2D27D29255988396A5C350421E2C2BD89B5D18155B20260DAED20E3DFF52F2E84E6D6CC2C040FA3D0B8726C63778A601CF95BCFD381FA520F95146292B8D854C5F057440833E78057D13FFFEEF4418E97986A064AC8DB74A001BCBF8B8E26CE9C68BACFCF4895C956666F92B5EADD27FF6FB032207FCD2100FE0DDEAAE8A860F89BDE341E59671BB0368B1C68B44B131139A44BB37EAB251A0339A79D358D73281325A594E2156E981C519419D925F0D6C8661F7C294D91F527454AE82EFF98344A6E39B2BB3E36431255E33DAA31B75E961FB306792510924C3E9B89150691BDDFB275B9128677DFEAFC89E6562FA245DEECEE2E788EFCD06C4BE744CA97693CC1AD7F0EE4C633D706AD278A46A8DBF2DAA0CCB69806912F8C081BF192ED7D17EC222392B6E84D6CD88FE66DB10B1EFB9CC7F3E4F3719338B8D6BBE47644009743829F288A194EB3F6F21FE7D7FF55F8FBFD1312AA603CBB0C011CEA377E6E2AD1541C5BF55AB73777BDC20DE77F701E7DF26728A44D881EC44E905608CEAFEDB670A261F2109DBFF79CE13E98A3519A9A86F3E01B7C3EBE2F01C657EE017F0740328B97392C6824FDF4D5820458F0DC9E999A4F878D09493D249D0B43268D44135C966B05AC8A69518BA5AA10423615DD3BD8B6E38D37D4E7ABAD0F8752A64736EB4D6656F6C3A6C6E1595AE0ADB31ADACFD6B4146F4496E739C4DC98835CE4C5E2F1FA899D4B896B02CE97822E90CABF5850321487D0C9DF07772031F1A438E9D63374373958DD9708C6BC38C3028C2C7DBC7B2A5A0CE8EBF87A72EA394FBC0046B62D60CFCC4256930BE65B22305C750B2A7483CBE0B3FC0824A011D274FCC289B8EEB9ADC5505426D8618369E0135FCA2FFF5456E480109952CFBBDA22758E14643AB48F11AB4F4EB475CEA238C6493166BF384B1DED53072D897E368C8BF8239DE53290766A4727CBBAB88691400E9FB9CD53442B91B5D421323A24571DBAB65B7EA7015775B6C8DE25247D0E7BF3DB7F2506B4384B328", + "D7554B01374AB97EE1246C2DA82B0AD5BBC76968B6E058A821418E0707D596E2A7E3AD9AFE623D18812F269C1D347A732BECE58260D2E8F1399AE5BB928716865B902611DA70761A4C3DB3EB0D332E58E081C08D4AF96B1A85DD68CE15A8EAA5B95F73CBA9975924F8F9A3CB57249A6A904A33F6471ED4F389168702EDA2054B4A523B6CE189B26C50900913CBC7693C4E447CAC4CA7B783106698CBB78F5E793284F27E182CE12BC792935FE38CEAA7F659967111AC2607C8316FD3CFF111DC5C2D58502555AA589010F9DE4F735D456CB9F0896FEB163984710BCA11C5D78D9ACE6CC9E2EAA70B177A9D33D8C59245FF9773AC181548BC82C751D59A350C65C895AA79E9B57FBFA2D17F53EFBE0C490B43C3369B71DE45B9AD67C88B2A8F1AEA2F5D871970FE9D4C6D63F81647DEA310F76DE6C050729DA4575087E3AE8F6804128FDA47C1867A6FB5065C4186C47D1199BEDED29D26BF9825676FFD9A98BF91E3921A07EFC949D7473CBF04E6647390E33CF765BBF73714E0AD38C4D1EFBC3BC4144CC9AEEBA0B9B4843F910A7F9CFDD347F6DC1017C010DF0EED1A71958CC5BB8D50BBEC164E186B6572FD09715C29611A3A5162496968C1DFBC1B6A8A4E617922D152FAF2B08BA40E47AA0E9F30515C9AFC74A5C2D87828BAE5243BB7988DED81731126E4C7E9609863929F943930FC72D0F3A4784990E08145485CA0FBCD69BAB2391C82E75BC2CB2DCAF0E94A3717B6A157070C77A8A3B5DD1E30AAB09F5368F46F66575599C04296982E6AE8F8C334ED24CC58449CAB0B7660E0F2BB9D96BE515245DF9654EAFB5060D21291DB8A2D820BF372E795957D59ADED6A72C265D19C852312BFDACCA65431B9AF4DA6AD56B97E9FDA9AE4650C9165037F353D9BE92322B4383C30404706D102F15D8D39B21D22E0B23FFB0AA0F58F477DEBC4F130BF501C765295A54913A7A0190FC907BF2420B329B97F30FA65A7429E7D71E572E1BE0AB0793B606F480A1526085637BBF89CABDBD9D19D808F230AE48505CDA9ADE68FDC826682BC406D4A7575EE913B60769C3BE4D81A073C05FE2BD6D7A1C3B52FD2F22875BE856CE0F6D7A3AEA1897FCDF951DF4A86184E717B4077A25D37935A82E073373ABBA58B0F5F744CE52284D96200CD90F0A7B4A03869A93C9371B7F946EAF2EDF35ADCE873407C7BEF0A750CEE48BE3A33CC47979648FBC5EA7E79DBC725C3901D4D05BC5B804007BD46E48B424665763F028E3777FC1A00F588D9A26F68DC7ADEEAF8214B747B409395016A05D8C72FC3E838DBF7C5A222D03699897E5606433CA760C6D67C8BECAE0FA8C312C9875AE26D61FCBD3A320829B615FED0587E4225E4B62264C9B37D2D2B45FDDCEFC060257960DF6A1AA2AC0544FC333914D192A1629061730213B1455E6FD7A712A08122C8BAD77EAB9CB9687AF97A3AFC02B8F413930DFEC10DB37C385B5643E91F3345C73EF353453F34A5EADC8EB41CB098E9243E57258AE608C9FE7BBEAC524B21A0734D8EE51EB30DD6974B87FDF3B0B1E1DB01FEF13061E4B072DAF927C99BDBB7691069E2493E86239A69BA33AF82998CC1D7B368A4343BC63EACEED280415FFF40B0B61221D7D1C098C6391E5C888228045494F86644F34AFB1B191BFCFD1A29C678956DB16D0BBEE458AC6DDBF00E738198C093170FB37F3F141619E65502AC57E9042CABC72372E5FAB9DFF5E42A00EB023E44B4E536706FD63BFEBCE1C0DD59E465A61DABF566EE7216973ABFF5D34A5A62518E12E8352C61BED9348E5826290EC0F84C", + "4251265EB325D261D721A84F62224701C9F564298EFE0C2516330F7AA43CC3D7090581B74C69218D74C8C6563FE276F24F39BB7998CBFB9C49EC649106DFA51E45498DF0F347DE8A562341DB34E94F286F583832E49AB38C09DBCC3B2C307188A980574461CB3C41EDFB933938F89C88F61886B60097F272E511B49CAED645190E98C3AB8AB5CDDC021F76567AC1EAE9F4F8D782B91BDBA3037BFF8FF43879FB6598D84046CA06B3C8EFE275BC61E449853F979AD6BFDF27DF453E2551F09FC1916F4E9884012BD4B946E2A65C86C609CF8EDDEDCECBE9B1DD6715C1792E261A3A013D64F00118DDB1FDAC9900E8BCCCEF9246446D5248D5E3423D859E1AA9BC38F8697F8A4EA08632983F268BF7D0BE639ADFCE6625E00229FD510A41AEE418C3AB85F5D2256D8EA4E9AE47316BE6DCF792537F28514B99BD76D098C8B4CA16DE1A9ED0F2693DFBA9B460BD842452BF563B03874DCCCD3E18B76AA3E352978473A2E02C6398438A35639457DBA7316577B0863762FC177010E0FA0F7537420C0443D8D7F51AEE4F40A67E249D678E77F17503A0A6DBEC3C60FAD140DA592082C334E3B1D021E34104A9A724FB6EE3B5A22CE5D3BB9C5E896956B4C6F7B1F51A74A56A7232E027F706EBB999708BA8ECBF42F44E41EF63A7627C60E5E75C678B5B3F7846CBBECC9A1B6EF78D7912AFF0EA56B7E25C31784DF9D63398FEF53F6193554C4D8B7A96C170A89961D2654B9A663B39C76401A439CAEC482BF44F20DD12140D47D0580DDA48EA905D409BAF5BCADBB8394333B97C0FD9501AA4B4BCEB3F041520422530A09A9B24EC04206CE907A33D0A18CD5C1640CFEF970623B1AB2B7EA5342B6F38C717416C17545D27C21A8F37AC2B98991395D3D170FB2D03C6B152915DDF9CAA12B5EB19E45FAC4CFD4ABA726A723237A6488773C05D0D38D38D920C6E8F2D3476B06B40094463CDAF380026BC36B8EF3DED6A01CA89E015A0B75BDFB97D859C620D329C9B26B1DBE3A3C92D8510B060ADF4151AFEED125ABC0D6FD3FA9F7F3C67B6BAF14A672977F2052A84F0437027956AAED010F63471C5848781BEF8F2BAB9F8CB0DB00253E2C6FD30D2A0794FCEC489376261CDD407B4ACECA129D87FFA0C76E28B9483034A40F84EA21E06C37BBEF2987AC16E77E021D29CBBDF077A912B89CEF82FF0EA59F7FDA55EE99F4602B5437CE71B4183BF28BE79327483898C39D09DCAC59C3CE32333BEF4B0720B30944B9998A01CB3C135D53B4A76FCDAD1C321D39D4466F0BF95710FC975ABCA1181070A4A5741624CE9AB0FEF27A5BB1805BF295861D0208BEBE7DF92EEFA7FB123B6AD42541C1A1057DA2560469A680E3664B1455D6851E6C8DC8C4940281AFF025B2BAD2CBB53D1670641EBDE2AE91E71F7F69AFD0C1A0225351CB1290EE40F81560A52463FB04E1364F9F3E5C454C311240EDA5C6AD78A094A73DDC1463E19A8E12419DE4966A1F12872E566F178E256F257FD1890DAE6F84DE013C2490B57DC1DED2E705C0134E889EECBE5575587EDFC240DE938C6D2D9CE543D5BA3A4A3EADE1A6A5F0CFF996311F72B3C6761414E34342C3D1A48F5D3011D7BC7F936E8E086581AC256DC6A376F9C4ABAF87FFAAD67BAC64401F4D976129EFD57102A84E63DDFEF60CF13EAF8973881FEDEBFF8D4B356B2A03EE9FFBDFA99F77EF7251C11EB1D2514D5E657697EFC47FC42CF10FFA7F09765E2EC39E0A99E4FEEBD410BF4AFE51855341279F7E47DFF0066602618ED5BF70B2F6D002805F41E991C68D64ADEAB7374F25B60", + "E0DAFB980D888AA2580DB37930D1942D6D088FDC706871A90D887B5F2CA6B21911BBB8BFEE1376F48428238607AF7CF82C3B3C9223746BA9A5F01523B20889ED8F139EA3D505D55D766BD056416193CACA6D5D6175C16C38BF44D7F89D4A5E3406C7944AD05D86C310E1EC78E0C8AD80FA0DB202AB1768AD446AC7FEC60B30D741114B45857FA5223E64AF32476319F16DE15C04F34F4730AB31F4F6BB13252D706F0B3BD5860BEB864618353CE62469E25CF4AED50D8BDE9633CF18F76AB1EA5552614D4AC3848A0CFFFDFD51F17A4E744533DC52979D7012AE53E9B08C4980AF8876ED2FD8A6F174B3AF651517BDDA1965264F1CCF0EEC8E3A9969D1359C5C9FD20CAD8698F3E28ACE77001F563BF456B5A46FC747E5D7EFED93314F7AA87CFA60405F968A4F9774E30E2266938BB19E9265FB71BE0D40FE6BF14FE02E36FE10FF110D63E02145C78B73217EED9DD87F70077E4229572E6547DD71828C773E46462E30B497F9F5F99D723D657E17A288DC98724B11AE87B7E56D33386A7FDEE0698353CD46409FE8D2236958B166B1C697BB8A42946D66E390A045775A6FE7DEE4BE260490B69C56476B894383091C827D02E960D9359E8D3E151F50EB87FABAEE8ACC6E325B36674D9C7CE249B879B3FDC6AF95E92FAE53047BC211757FD12564EDDA4DDB6AE8C94DD3305C21970E90BE05ABBAF912ACC52C77714F87C2B059A9E21005D8903A604D82EC22192C46CEB63C588A219CBF755B5D44CC0E918CA6705156CB497FAABFF63745C826FE16F65582D4820141DEBE3B949C29EEC6D99C2A4EF34DC878DD82D0FE6D5ACA302ADFB897DAE78EB0BD28A938D6FD5A3535CADEDD7C521E45AF4BA92FD40DDB009E35C21254A6DB959698303D56B59D8F319F18E688F9A20DAC8058E0496E0E46BD01880F3C78EEFE98A511768919116A288CD3CD28098BF5D4719EB64D548A6D791F1A9A9A3E9B08E7184AEFE60A3D7D7179CE47562E9133068789BBE0297FDA2B2D6F4248B288CD899BF3231EB360ED45F769C0167284319D2C2B11375C2B18E5B67594CF499A6AF2687E0C1AAF09F4161F3AA8369BDBA68AB022459A2DA9DEEA13E509AF3A68D011998D9C30BEBEBD04BC9983F36FA549BFF3E3D323722B2136AFCE0A2CC8E593B370C7B48635926B9575A77AD7C0DA18E94FF1C8FABFB57B25981288E1771465360E2D619272CF3F56268B7EE130FD07DE29215FBD5D0A72B73081869F60CB149A1E4871150778A2229F3C886200E0DC2C76AE049231FD3171E49FF44BDADE185883198D21629CE0AB252C7451398E0D411CB01A66BC5B141CB150BA9CFA9F9F46339625E1D5127998302AFD19D5B2D85F3F0B2B354C7CFAACA3D4E7C7B7DF44E22EC2C226178DDD480DF7787EB28F0285B1F973DC47B094491DDDC12BF1CAEB99E0E13781FE8A64DCB0A05A30763A055A6ADFE5434D7694A0F6A0366B5D74E73227F3D503E6B989C5BBF9E6D81EDA7C46D890FB2C5CB439C5B49FE16A9BEB14B12B08C47713331E8932D4AF6B85444E3F848C5AFDC095E984449F0D126EF711F8B43831755BC0FAE8D9FC79E894CEC183DC24B1E3C81FAF6A546E464AF8C0307263680CEAD9ED6E80217F98CA82458BEE59D2A4FA76BD7D4425E0C77164A50A2933972108661820C75EB51C8A0ABDDDEB30F31F2E575AB9DB723DD084656691096B72193C52053EBB8B72C6B30C49185166FC39F3D9F3497606D15E8D696CDC256DCBDB6D01DD2C33C0249D6069788DEC09802630597C13EB1AE152E8E84F6A4BF60BB09E049EEC", + "EF79F2E35DA357E9C076B00C6ACE7C50F865830698571E999E544F5025A99C36BCB025B7967846306FADCA22B8BED499BC9A80EFA7BDBDB83B15DC6D48AC4E3978D528DCE0A3E11C3E62B619EBA0C853EDB0EFA1DCE9EFB2E024FFC0B59A8AEC329FAAF418DF9BF70A250F2F6409A9FC0153161F6E8713005E53154DDBE15242AD801C216A1E5CE207757BFFBED75EE4C96CA0C3CF448966540EB434C68E9A4CCF3C5907DA216BA664B073D73B0779204EBCAEB55446AC6E2C40B8BDC666D4C9D33B7C644F867BCD8962274630191EADAEE7248398B9F02744AC5D4DEBDAB2D6D9F8D6C6392683FC1A795F70134E790718D56DB6D424725DF8AE7E11F02D684DA78ACB4B9C311806D082C1FADE4B31B8A6DC0E5F16618C47E03E8D78DDCCC6ED869F77CD39926945466369CC2371D3B51F58DFC6471D742C9C82B1B7A2B1B1BFAD15FEBE592AC0F41B19C126D923BF5944408506ACED28FBED161902EC5FF19CEED25D18F47A76860777A3D86B3E0BA7446C3F1EBDA88F8A8E182CC0938384842D42F41E0042C53C645DC87C88429E06BA9906A7A3C1F6A76671D69703496324406C7FDB20B9C3CE9BC273A743DCECC0016BDF85D82112DBD4C49E2A6A5DCA22738750EB8DD6AF15B27A0601970AD12660A51C560E5CD44B55960AA266A88B82E761B53A8B42E7332EF2FCCE093BCB06FD18D916FA10F4E9891B103DDE5D808963E6F71AE7479A5D0BFCDB8A2B2086308CFB7813EF6B7B5304225C2E9690E47CBFCD534570933541E8DC99227986C0CDE40924D64710A7FE28D248E667E18197B44D83FF1A0691E9049611AA1E04A1DB06595EC32A9B91C46F50096553C0B5716D2EA9C9E3D373C787783B50F28948EF96D21FB323CB69FBA26E8C869C745FF08AC0C71D2B656E42928D09AB4274C307FBB04AE41FE847721D95FDA55510893DF24F56522EE537F609FD54E4DAB4E98E9F3F8E8243C5D056B4CF6F2330408514C6CA22DBC79BE374E2B34B3E9A9B689B9375035F5E32013587C402C14997741654DF70FF5F74C0DC26D82AE7F036731AAE15D596E426EE2E7383EB540A48EF41FE2172F1565AD79202A016EF31255DBA5DE29C8C77B4704EF177C97DD507360FD01B44D612DCB18D7B5650032B1E768851C84EF794F833F9D5D198603224016D3FEA90F3C65DA465418750A69C43050A738A7EC4D415CC0B404B475936F8F675D49C67B875BD8BE2B2D65E05C49EDFE72163CF3F3BCAD87D8E956101964A1C1345F3978E144303FD1AEFA4675F521BBA59F0EF43DE19418993F444C1F75BEA24B295CDB73A51510B8B4B59DD20829466409444D4FF428B3B94164666A642FC2A187FDD7ADFE75E813BF64DE664B131F58B9CD825A19AC360F4F83E43FFBE0923494D978B1B2ECEEF07F2387E03B1D933008C0131A9ABB08DE1EADEF78291141D285EADFE1228554733CD927E9740D39EC9F539FAB960EA829552CFC36CD8BFD9092C821CE4FB4F29115BF533A56D7663CE9FAF2B9DA374B6E1CE5528A5B11ACB9FBE818BF4C41787F5E4FF4D517D46D2234B77F20ED3928BB38A32BBA350A66540E19B586C47EBB9EBF4E4A671CB41DA55BFBE5B39C025BF8F11A786D60C9DA6EE5299B17C0135689AC9D880B594EC51BB52398E78AC7DC2439D0C4BE7BBFB7F044661C9CD8D6D7EB16AFB943589C6210882557C65034BD7D044C6E957722C93537473E2EF1AF5A6D05D7404E274D2DA8B83F6D2AFF9EAA55D122F69F469927EB682977715FB1617B36368C22FD6A2A7B10412E9F202C6FC9BA1D7789311D0", + "18085D480B93B422C6BB24B09E05556F8298FCA307341877435D2D76B9DA1A1932F20D2903A63A0856D9C431FA3C4C591D606E0043B0C6BF277971588390BCAFFC01E14C6256290E1A01EB7BDC98611EB4E40BF72B04C21526D4139E3E75A13DC25C0691B67F24B195F57923684BAAF94C7E3CFF4830FB5E828B8F7A8692C1A0CFBB9FD3F021D3FCF12C7497021178A2AB8D3256E8606374D6D0E7FE11BB1F313BE2BDD4D977780C1A2053F6CB0F60F89671AE59C178FE33900FD11B4DEC25C698CE0FD4E451D6A3CEB4E41BDF08F05F556B4394858983D515266F25703C17B48B1AA13056ADB2AF9A865A0FD30BC4BAC0D7B1D185AA2903D1956DDA3D5541873EFE487E08E83613428B64D2A499BCF3783466079714FDC3D0B04ECDCED5C89F77F5E6E6F1141D47EE7A3C32382A89F512F9C9BD96AB24EBD4F77B911D8B8206CEE29ADC1E055B7BDFFEFF94AAFA750B857EC6FFCA693787C0E2817554717CE5DD5568DB1AE585B9BEED0C6E228FF47C43FD7565D3D5664BEBD73F97DCF73D8EBBA3FA092BF6EF21730EB909327313FE1493BFB44397567DFA30BDD7D090245057098AF775CE977528E91D9C3976A4D478A5695482E4EBC1FCB2F7FCF6E5F9B08BA8C7DF12E6F77C3B0362B1132F9209AC1D69579D5E9815535FF72820BE1414020694A3E2DE53BBE7DDB582C70455BCD18AA0A4E0A8BBD718217C616129F236487194B266F95E644D1FA79532D7AC13CD9C839BE14AD4BEC179923EFAC48965A8C915812C0F0886C11ABB0D2DD58FEE6AB2549AF9380B8699F3EBB0F96D295C22B940044819D7FBF2364610893457DDECED6113D1B14BDDDA8077BB32E70D19733CB795BC8964FD9788ED317B5E433CDFAC3CE3E0EA2A8359671F2ABF49946217358E92828AE32E6CE645C3C0E4D1CB64E5C8532DA7FC179CC7ACA241AE496D821EF7FB9E8D878B746C50DEB281604830360C8ABA336D1E8F444FD46A74F6B1A0F1F61EEC42C1DA2B6D88CD1AE94B3208866BD1757B1ACC09BC155DE4690A97D0244B819C0A66785EC764276BF39FCD6A1A172C777F2E9A44817D1B6B3C09AEB4436A3B115605A850AA9D11BE2E660F2B214C45B00134604EE395A77BAB321298ADE920BE3050CD2D7BAC4931C3E3687BC4FD7E2EFB536E26404E9950C928A3CFA8A11BE42D15EA8DB2037154F79C67860844D04DF51F5F21E90B8A16E7504947B90B655744758D97886E4860FBDF28FDE80B8F32C94D09F4F827F34E8FCE92B576A8809738D6227C9A31A43CEB3EDE56BF7306DC6F208D6229CC3E5C4B49AC54486ABA7F0079EDDBCA82C3C77F41C58A88C4ECF4DBEA754DFB3424BC3106A9FF280E8C6A7D086FA06C44ED23A82E23A03D3FD4CF62DE1AAF3A95747CB5CBCEEDA5B1929C13DF6CFDBA6A94A62AD3035C8CBEFA10AD9D37389B2EB90822E10B422BC165A3BA86F37C0A5B96D0EABCAA331FBF2806C65B376665A434A6D59B3BC9C339F4437F4598D0D6C62812A2083C32359B938D78390F9B4F86E42F297405069D350F86B089ADE021C1599FAA2460EF5904A6E25708032540A7747BB254679454A7B38C7491BDCC835033A76514869ADCFE268FE49CF38A9B844A97214E1E1ACE873FE051FAF282664552DC98618E35DBA4AD9B1FBE50700726091534091C631B54C944C28D97DA0961F8E4106408017CF1EC86456BCC1F4EE7118D0691F0F327A0436D3145E5FBF8FAC33E5179094FDB03D9DA0D9A2EEDDC221A21189B68EE1A94B13F062F21472DB5466B266562E2186FE01D028CD4AB5B6AC9F048D8", + "D50CD8EB871C5F371648DC07E20BE84263CD676282D56EA5374E21B52752DBE416DB787BCE232226568621ED792A9135A59849451A4A4D8A1DCF3C804AF966881FE5156FB761B3736F4282240FC0BBE72F51F0122D96B3755109E7CDFC70F9DD04C58B4A51C00B4FC0EF252B05ED76440C97DABA04079C121351CD43BCDDD4AA2D2495B49B908A9AF815DEE1405C3CE9CEC7D5BA9919621E8C4E920E08061D228038F73F8E5DD66BAB806D2DD953C6FA5360487957912249DE009655658BE8CACF00E6E0621739648A7A75EA06E93946987E62EDC270B266BBBCEF61D7CC63013AD797589A7CA62B65D4127E701BC95D45C74DBCBFF498D3F87CBD1B288D6012EC392B901A3DDFF16EF1E1685EA1F92B1F32DFED2F9076EF9CB1ADD8B04953E5509B24C48977FFEE6044B8C5B80F9DED6FA7110C3A2EA42EEE8A83F4A28FE78B27E84AAE7B3FABA56C1A4D2414E0341C69C40A43D65E16583A151826F7C7CC0CF0A5999A1016BE6912F067913AEFB525EE41F1B9C82881054E9624C03DECE74976228B119974BC546F823A597C7486DD594F1FEB2B6D0330918936DCBC12E3752A7072C5FD7B145571DC4A22C770E00F24B8C91E27F2C727FB049D04BCA813948D2F7B531C906F2018F51C9EF8B7642C0F1CC06AD338BEDE17683E0BD2A90D4D4746189F792952037E4918D2D6E61C1C8A8B6C437075ABC38913C250BBE6EDDA5CD24B630AB8FE9123B08D5E8FB8B71BC95BDA4AF1A71D5E54BE98B16D7D3083AB1649CBBBF44B3D5DC33B77DC1171A66F6F40E75EB86801EAA36E02D138093F28ECC6DA4CE4B128DAFB8D49A17C683FFAA8E6910B8BB7B832B3A3D0765DE2ECDA9D7BFF0A822F5FD389A04B660F832687CD67F7E1E1C3F5257C6FEB27B763AC7327DE8FDB989413B6D002FDFFB1DE5A80F1C5E39F06E6D716A69ABEF37B2DA9783FC494574689948DB51F78C8812E09367E6C8D70F5FC4139C64B96C71ED851D171AFA69D2A646ABA85279B7D3D31D268A2E8A272C91902F12C49D07D74E82728AD61BBABDA333DE7138A976A2267DCAB1A02E19B0685F64B608E3DA41108D54A07D4BDD24D79D293830C04209C98F037283BAEC00B1923CF404E1F21584F515F9D59B53FA9B4774FA8D3B34B7C66907BA127A095CD8CBB23375CB188CF9DF22CFB4CEC528C581DB63598DDD9A53438409D72507D2CEB5BD45DB5C760415A5E3B3A909EEDA73B7FE122DF04CB1E9F29E7A5A7385F632AEF63771A4CA2164B9B3FAC3C13911DBE9668D1127DB02A94CDCE2C8C7B66F0C21601781552B384DF0FA002DE08892D0881174CA1F6DE80B98BAE545237C5CEF9E1655F9EF8F8293D644CB47963734197F1976600CF2767A59FD56B9B67659168ECD57C485E5726C150DEC6C302456AFD4F12B2F2D1F36B03E100E109827726020BDBA970A6B768C580E34116DD0011299B4DEAAB8B04DE1DCC5FFCCBE57254CA79743D6B00D119CBB2C0B0BBB2FB8FB0B0EC97204E1720F99D16A3257846D09BF8EAE02DB21FCABF03CB0989FB4D99B6D71D5E64C6FCACCABDE63B223A91D1278D676839E1A5CE6C5EE05AB4F10EEC511C366DBFD7AA1E139AF671CBEDB3160A775E5214C862E95C3A7993E508D8F8B7ABD68213A531B5C648C537FA2674346FA0B3AB43A7B58B4F83B36D58C506C188DAF72381DE53F83AD4D9E6C6B1F5D689AE24CD158BB2898F06AA28C8FFAB1703871A6A6FE41ABB6B8B9188C90EEF88E7DA3338F119770B31167E3AB541371FF7F98A2D59D3557438DEAD71C96B97F3839F5E28DA6227E5B4", + "0447B9C85642F3F8BEBD1CC7AB0D0E4D07CAFA93A26C75970C8B40443506AF8BB671F30867FE4225F576026F79010AED56CE915AD9AC001447CDCB7CC3846B0E291DE0E9E443984E0ABF7C1C1D2F6D073B0B77116A21C3C0B7F360439D11D2DE370CFF8FF73FFFBABFE4D52BCE58CB32612870B0EA23CDA21E3B6E851B063BC76FBF7BC394A7D3805D45616C6A313C887D2FDC51F065F8F3C05ABCF70F31EA5746A513D2DB3F4F3C61006F19420AA82107AF855649EA5D90ED0A8540D0A2CEC685D18EC8F4508A7D092E52DB2117C233A7BB542B61C26BB92491A88942A506ED60354EC1963ACC189A248E37C9367F3F6FE065EDF6A1205BC80B267C1062BE20950617FE0EB59BF8F1E69982F3E89E7EF85F3319A22A22B8BAA491BE76AC7257A2DF631A98477544E3E57C7D63616D22789968CA5E929B507AC394B6772096CC70B69ACDBADF900D055881FDD209AEF54CE6966767C07EB7A2B40A3410C3417D114FC9E293DA7262171325D8179262B2BF041F5A977E2D648900295B14950EDF245C7EEB663F8292625F804BB839BE3A5510036F7A50288C69F94434A03466701BF1313020A4DC4F87D272FB9D1B7676C195C0B7B4D3C2CC6B20D5C2066C7DE5DFB5C9FAD43D80FA43BA917F200A73F258BF21ED8BF3E39F69E501AB3EB115C9414C82C52CE91F6CAEF4A163E288A6FBAD4FA83477909FBC972E2EE2A5379456105E8EA02F92B0D8F79588E2282D1970C3A033F738011BF273EA65912D3ED09398A7F851BA2D6141F97843E90F5C66B38D71D70DB9D93FAEB07FE1AF5783D71CF50931C282CA8B483D1F2E5DC5AD5FF2B06C4355E46768AE5014A22E7CA26267A1E6CBFAB24C8C436535F23D419819D6D458551EE78AEA4779574BF86DE7960969B0635F0B2996F955D863E078DBF8689C142736BD5177DBFEA3CA8C58871B1FCCBFDFD67BB12AF82C3B8F935CCC507D510CAB63B831721E0ED9C258BA7A3FE245D42DDA1AD8A962847D7C724DD2418F72508FAC194EC43D17533AE522187B44D71B6E993F2CEFC6349141094C8CF935D90F2F238728D29E1F5AA09B46FA7CB651F688A8A06AB97FD2363486F61D3F42B9C015652A53B3CD66372849FD2EBA05CFB5AA28520B01FCBD9C835F98D15FE01C84D7FFBBA4B2DB93E44E4341AE95B8AAA4D59CB88F7E192E89954E22B1B8157FB0B89E3E1E3862BD4C2799F2D8C621064EC9BA1EC30E0F7F5FFD7013A7E1C102DBF01698322992EB05978A5A2878756BEABEDC660DA2D5370A98CA2C0A4C65141EA273EB787B2E7AF646DEF7DA77A93E45C37E69B474D04FBDC3B5982D8492FFC37FDE42385DDFE97A73B8575C1305A0B9AC0B0CE061A423556B6FDADB67D0A5BBA7435929D658FB0869BFFBE5D2FEC96051FE03CB7B0D944304C2D433459A97C43268E43951D4C1708C702FB9C0A0C6D82876057F4D043B21A92FA6D034B1DF5C2B463107AAA814C79022D96D1BD9D33DE5A1FF9E435D9607575856CE4DF5F1E9E90FEF5ACC4AAFBDBE0F982DBFE78C5ABE1D9C85E0452AAD7836D39591411B382BCCE72CA1702A20C9DF384F5BD539F53CEE8B9977AFB705D1D28680D1733BAF5F298282846EFA26B0DD7514422C0EF9088F796B38C15EDF6C8D88009B10CD0D6B4B2FD93679712BEFFC4D1F7A3898AD0CDC61D2FCDC360C66FDFE0AFF0E8A7B26359606CD4F47D28DE115261E6F98F323FBDF3E3046BCC2ACA0831D2BB4DDF1EF443632A229CFE6BBA5179079DC7FA50C56BE7FE5FEA0C5AD09D891895508722861E9EE8568F59616890C6370", + "8DE87744B81A0E21A62CD72148FC3782AB560CE136DC3A07F2D2E143EA0DD2ADAB9FF8AB39B2A3E8858DA593B6EF6C46BB5CFD252F6DE446D9165406B3DD18CAFCCE3DC7A6E6200D8F7591169A6AB9DB6665FB72140A416EF30B75EBABB6C284E73809DE2A3A26C7F4F188FEE0B401E9EFF6DA22EF3DBE0FAA6DDFFB5D8C265D1A1855CF7019D8659062AD7A705362D1510ED5013B96D6EE803E7C6418B05828243496753E8616F4075A08346038E3F3549C0AB1E761790E818C2B531F06805D92FE53D45B9A6FA5E30E3D6A2F467AECA07D29E1E9123247C69220E2B9D4501EE42E5BDAD07F0D092B33A938B8FC0EB7E435713E3E428E87DB24AC570E4EF64840A1B4D43C5026C80F321E537755366B16FAFF2423908FB74E9A5B08F0C1064815472AF48240F1C374F2AAF8ADE55117E0FB1D08AA40C4D8AEF35CE6A91E54A89BBE55BF5E78ED5F66B2FA1E8936342656C63263D4E7ABD70F7899DAC9A315E9508AE65287C6660A7D7F3FF408CD06F3B19E1238E6D5EF040B3E54F4469BEC17198AF3F78F660C6753157603138BC98AA9F01FE79036D4564A7396725E57F875FCDA4EAF80C5E2815862AD52340571A571B331CC8122C13CC58403B22B61BD404C6D94C36FEF187C712B524BAE9EF150A71CE32366AE536B5B94ECFA351EF0DE77E729C42BBB32C7D35F9A5BB29D2D84BFC91F510F9A1C907540AE3A80CB7023AE0635EA5C2EA0548D9D14CE4BDE142436521ED1637C7B7CF6CC1DA5F826B800AC6FFFB83509A81ACE30FD969495313F9E18CE4D8A2E1D5F9C7DA14A0A9D4C4D49BF00B622B6AA07FEBFF0A8B274C297C0B4AD1CBD64BB4941543FB63D9E15059E0C0FD250753B2AA664A677780C39A013E1AA6B8F786D677755ADA03E51ED55F936FFA1ABD0430DA8750575C37D1EEADEC5E17148DB9FA202F8748B0611EBB5015F1D26C0D810F1AA5A40D73C32C269EBA5CDA134267231FC3783D3D4CC639E567681275F423439A29118C6A0C1B07D08416537D4707E9CA3FCD3494F64B69E2AE9EDD0079CD428CEB8A00BE0FC9A791FE2DCFC10D7F813315E964828A4DCC2A2D42EB313CCF192F32AA9A17C984E0D3CF3A0BD86E0B751B30C096F5F0B08A0BC439294D2BE2CB387648F8119D8820D39F17C6AEC976A0B8C89C76D12AFF73059B49EE856B2591E8D2E817DC43793F20B2AFBBD49FD9A05F5B4CB69165420AB96F26A46861AD9423F7DAE8829FD392799EF967E1270563BCF3D46025CDBBAFD15DC23F33EE5B621DF6A12263CC0A506A5E9AB191F896D13382B3BC2D536442A62B09F3C2C2252D0BE377CFBD59097259ED243EFB36C9AC0AB01B3AADD502DAACCE17A49CC82FC9ADF67B4EDE81D9355CD8295DE21468FAAA25036B2DB6E24A3AF3E5FE59324867658EAD5198C47D362EF64B71179D107DA748F00400F15167E84B62588F6D81FA4B68A59A24BB3D27167D0720718BD24EE556FB72113FCBD37831251DCD538F6815382E119355CF3490DF0AD552ECAE0D00462C10CBA4011E95C7FEC968AF6E39E1FD15D1026879202C57E2CF7AB02B08B15373C13435D8A55ED6B9BDD98FCD5B4539428D90A2C73D37DB112D2025EC8A4AC8EB82C51C46FACE88AC0E1F161705801C781EA07F6914122E5DD6BFFA3812EE44E314BC09B785B344584AA8522B63FB34BAD2122F9FEE1245E6DC837DB032387EFF5036A021C8112CDF03BEEFD89EEFE1BB88A132CAE9E1E9EED3A855B364F2A4A2F81086172FEBC64614BC04D11E74AF00F54AF6B5D85EE4773644C3FA768532B1821EC6E5C", + "0D1FA0561DE4DECF411AB73FF48D0810AA2149FE5F3C22E62E06C02F60189AB5690A991CB88DFA5C4FBED745FCFD63BE3ECD9CC599E35B5FA31AA11C62F3A33796A64EDD0B64F2E51E75C2481D3EC9DDF07DADB71448BB336C0DA9DBCD897F777E3C9DD97C7EBB08827C19316F61420D96F3D94EC395F8BF88F5927C71397F6C24901914826B1BE26E14FE93EED37141109CCD00C92772B96D9EFD74B3EAD3903854801B22DC3F98232023E1F9CDFD4B4C952A6D268DF9FD3FA83C707941F8F1ACDC195AD66E7AF48D7B06C62F3204E8D03D2C92920C589CC56A5C2B0A1F10401BBF747B60B9D2179BF9CD7DDF50B10823372CC4E24005D73B4C5AB918F22918B16D98F15C365FE69786C1ADE9FAD71516E389938D5D38420FC79F82C6C0AB1C6D93D1896FE8A2BEBA134C138EB1FB00115E50A8A676B9D9939E7375F4B7D62D449EB341B0C03EE3FB18564DA3CF64261055594E0F8D322EAA9B56B5328574AB323C4376464F3C27786DF7026BFD6C7757BAEDE7887217A2D3EA22AF7D6809BFE4985EDB32ED503C6034FECE55F4379920C73A515C7390B3405ABCC54F51F686903D5354468AC566D5A03C5AB536934A6CE698E06B9E2C815B15B4F8A1857FE7C0B5486759B150F48AE9745AFBCE856830078EFD7F4CB4A463587B7DDACC79FC9FBD9C2A0351D91DDF27A65CC79005DD24F1C26252BEB8C3F1D69DF79D386401EC5AD57BF2129D1E828D6D57CABEA84C7F77B16B919653C12AA7F770741E4AC11F0AD08507C3E7C4716F14F14C548A88DC4047EA96CF96BC0CF786EF7D02424314BC846682109A2F80044B51B12A0350DB9FE06E72581EE874665B9680EC118C86DB575F9E5F687CF35DB3CA83475051AFDABDC974B2991B47BEB4CB967E3CF20D2B7CA2BB50825EE33FBD7C6E87095DE8E36CA6143F673A8C18882D89F22C08971CC709F1518169123EE59EF50846C95C313F14F9472D4CCB8EB71301488901F27E895B5D44420F91D123E3EF5527121B9B0C9536CC3D4E5EA03F63BA8FED0FDF593AABC3E768962DA165CCACE066ED7D6E46DAE97EA08789C36BD3CA6888229D15714302A39EE4F39DB0751F0E99877237524ED8EAC5F7EE2CC40A69408DC43E2AD88A661D7E443D7E99A14484E3011A41912E2AD4F6B7D62D8D9F3332F79A5FE1E16E8064C91DE56B1F89A9A3A220165872128771745D086DD3F8DDB2C35AAF3DC6DA70684DF270ED50D188FAE62CE4C98B9019D308772EF036F9FB2775137377CE61529A40E03B388CFDA3BAD55FD62D7ECAC2A72FB68068BE08383CC36FB66CC252A0412CFB3C993803C038A1828E8893DB453D47C5727CF8BF80850346063AF4976610F984ACCA00BB5963D5DFD018E0790F4A6B14A9B5FB9517783EC1F16773C49A744D8576F7957D4CD4C4E35D1BD580FC76E2632D47661A6838344CCF6476BB793FB12F92143524E5A01DD5294B6528C5A18B24B0B75D017C4DB3663BCD561AA8F27E510A7C031ABD3708385B03294E3BD1A695C573701B9D4F60232DF767439E252B7DB10D4E3FACAC8C2E8D16F9500828826EA807C2C7C48C0EE8457E757854C1540EFE9BDCE7C09AF5BE09AEA54A4BB0D2A328092F3B8741A128D4BF588384A3848A5E4F55DACFA64F7FE081366330D16589991C52A1BB782364AE969E8A21260518662B00EDB117278170CA2C0D186B173F93879F6F702E03DE768CFEA1E39FF8453C7B3AB46E83FC90FC56D0EC0847DF16A4BF1ECBFE29D94CCBD49DABDCC5FB81B62A2CDE7D2DA3E67042944F33A007096DE5C79133C7F4", + "C9FCF7D2DCE0A2341FBEAAFA64F6A50A93F3FAE3B55EB70ABF51A4C001E15A8C78DE54E50CCAEFF8C2421079F7333541018D5EB8045C3AE0F0489D13C593EED560CDACDAEA39BB49FE2FD9C956197967830A0886182D98B5051080DE887638F2E3E626B8941A58D2206B46FB410C155B94FD7D15956EAEC9F855B96A8F1C7202EE600C12DBAFC6E3DE5F075B05AFC037847BB521D1D3638135591B6E1A0137CA74E27ADA3FD673684A8A1330DFA46D449F8B63FF90E36881C09FAEDF61672AC32CBBF71F34367E7547C13BF08C4B688A397DD4D00D8B19212F85EF11C0FEA19C890D73DCAE9B532CAB7BB5931B2F648072F35FAA31C6A77FAF3F72F9F57D5AE65BBC7DFF1C2A5A2A2721AD5B50DBDA2CEBA27A3864A6628F24B0D24FC2450890E278C4599C1015C2B4AE61F2DB2A3A85F02882DCB57A7A471B5F8E51DDC284E0C1869D41EF25E260EDC53AF55BE8217FEADE6C74B9C0EAE7C3417156D671577E05A63E03052663F420B70E99DE068971C5CB8D9055864460D6B2C269E4E5D2585BB7A08E28B15851C6E8438EBC1272D517A076C08631A9890F4FB627D05B91ED2164355D7F20B32498E4773FFFD17F3B15E7F2BAF5EBDC98E617A7437BCF94B0EA1B2FD6F98F8BE6D64F769FEA28A5FED9DBF4B3700BFA8C0495772A14254D7AD9525B6ECDC028C43EEEBF91D2B17C9ADDC071CCC83EFC6401A22846500E0CCD3D4E5184A05AECBD92808AD2DA42C57621C66142784692D4F28662A2B37DA4D3CAE332A97D465D3E492ACC964AED603058CB6BA6972C83C2906CFCC813C0603B775E2DE8BC946DAFA510532CEFF2B2FC5E1F25540FA07B577003D67F8A3C63E9BC2B89EC7AEDD8C2E91CA426398BEC4D98FB6233832BCAB8F10E5DE6668F7DF8FE10AC0EA63B7D46837EE4D1D203D54615042203552430DB97C24FE0088334BA154FB2157DD2D12715ABC6D329A819A1A664727F40CC26204949926E78B0BB8947FDA9026813FCF19795F8BFF2F56DB70DB7EA9280A6C504134A1B653D336101A9C166883599477DB557406FAD495BA31B488D9EDEB783759EDA32968AE4B4B96A14C9DA960ECEF511D4102E1EC27E17AF2746DFEA54F42D2133281ECA9F5CA87F8A2DE4C937B5F9526591A583DD3211F78871BBEDDE79206F946B9CEC6EBD0DA4A25AF259E4B3EC2195578C74B7DF87963BF561D7F4C6755D4DB0F288341D5E525B15F2BDA314DA38D2B2C7CD7D64F6DE35EE782A076333941FC3505AEB1FA5783C6C2553D73AFD6AF896A5C2E1C15EDDC408B6D9D7EE2E7E9F706C2A6CDE36A41BFF88960612C46996A9E7D43511302F925351240B5B77A7183C45A1B66C8FCD34EB6EBF5F5FFEAC8441BD1103D2151689BFCF8D4E29B9C39B1BE4972186B099C2C35572DB1BE2A28D751D6857B7E4EF181B786C2A6FFA30A5D6E2E1120E7B1F313302ADD1012E43EC24E5E5B5D03950E009272452ADEB9DB626FF38F335A520B12CD981636BCFB882FC06B440E348512E6ACF980A1ECF360E33DCADFFF5A2B413DD214D5AD1070E88B63FC9765295BBC92C557F3AAAB6AEB293249761F95EE4338243D35AF883AC33832155AC758ED05AA1BFFF0E9FD58E03384704DA5A9237F1AAF52E12C821BB0F54C0820AF8124AE6D0F4BFECDA6500995B2B61ECB0628BFE2A9E6A05DC94A781137522E85A3BEF28B76E49B27BD05C113C9B3A9AB1285BFD926D65BCCD5CC3837490B21527A1E94544C4ACED0352BC84D378625E3655F74B039CD681D98579A190AB2B89104C83F46235757D2D22FEEF59A250B564", + "48116D6CCE73D8BD1E1F45D9676B031D9B0E65684FB88A83D791CE8F5278D33EA9D3A6ADF04F29AE93123376D1CEF52F27E875EC0024A888E688EE2A21A4AAD0448103569C8A7CB2FB072E3D0D09115AD8A1C234F7765E77042156AACC4D4A8AC697E41B71F436ABA09C91E9E4F2C5B573CB1D0B291F915BF922FC75E6FC6AE332B42D7E51BA8EFB1CCA66EC849099834E48C7F79BC16C79B0C87A8EAC8F88D30EEE8FC0EEF8C89520E2602A7226BFAC0E8B30A117B718875687F81A6125D09EB3BD2B2F5209C386DEC5AFF7DA0FF5454FF0451F825E5AC55680EC7DEC56E72CAB953E5B822E0A1D95F3F948E95DA7078C850C43AF46B4EFEEAD6AF807CCFEB1B61CFCEFB770D1923B41BB354C81F340CFD851EDFD537C373CB9F29303A988635C5CD37AFA576D6E8A8C2B7C56DE2FD49E5DB970B50E04436B1F8B22A6DCEE3BC27EE1885CEEA23E12541554EB2EFE615A140831DE6C555804432CAC0A73DC2EE5CEC8ED139ABCA4D17B22BCBE60F05F5D7F526ECB29A51ED6ABB4DE4A2865AD1AEA64041EB0F505BE3CB8F351BA21A8D941902BA565039EFEEAFB87DC6DECEC1C091ACE228931A147C491C11169AC87884D5EE9DF128C98A084CC6EA0A50D494FF8E0B902A9EAA4B4F9D3BB2BA1FFD3DCC93C45133B9008E2B188F57A82B5DC01862D35F633CD6CC3FC12BD6F3A20C1EEE1F9018E41027788950DF09C4B482837677B33B15CE24EFE6797291C0DE291AC04F04AF975703BEFD3CB8E59C1496E547285E3F7A29F99C5F210327CB328B8A3094DB7C27CF7FA077791160A2287F44F92BA6F5346E48D4D4AE6C2C7185926526719537AAD530EEB3B0B4CD718C7BA38BDBA21671ECCE0AB4044B797B7D10797EB1BAA024B76D0B82BF25C94655545227B46DB2A038F87301BCBECE0C99A98AA5BCB648DE58B6CD59AC6471462BF5985C595B00A4DDF2948A84203890E2989D8DFC9864392E7E75262DF1CB78C1E2872CFCD22D561F8788F42A0323CDF3EE1588EFF2F7BEDACF5AF710CC7C6F9957D992A7FE39DB696DA414AC36CBDC99AF050023597734D94C2A8FCBF41D6004C21E4F4357C19ED09488797CA012F4BEF8F1743E396236E708D96A7DAAB07FE03D5483319241CB35F66F66D99D981DB4427C4C84A9EA24AEE4F7C4E023E0ED2FEDF59FEB6D8AC0FE87DD42580F7B0CC6339752230A69BE83AE13FC12AD4719D45CAEAC6E8695F6F403A0713ED37DC120B80DE82F7AC4991B4B9DADB31A304E16D03251CA140659CBF99E891DCBB764293A967DE1E96848B8F225D2F9D28EC2F428AFEBFB57AB79B126E6FC3D66102E3813347D7CDA5499F6AA5BA6AB5EA6F3A82D730EDF3FF74B9BC0F954BED21E77146A5591941962C49F6B2BEBD060A9C82D8FC780FB3AED527D40CC426988F042841250B4A85A3F3501FA3436103313C3C4CDEA772B6C840DB866B9730798B69D6AE12D24E4DDF31FA9B4C8DECF6CBCEA2E8A0F9CC67CCDCB64523725972D81ED2E6562283DE99297458452B94467B83F3111CBFF61006814CCB6550D19A1EC026996695D46C31BFA9BD371CCDF1B512C61CE7BDFBE419B477DAB1E7E1D012DA4BDB05F4C4CD39511D5071C0982F68D9C6F558D22940D541A3C67003D05306FFC070C2131832F737872114566ADF3074F7F6274AEF9B894D0AAD5ED60998A0363B92D841F4A441C39965FC1479E93C99B083CDE6CD6CB9E26D49E16B969A357E28A61B444AB0FA665B853FC89B64E02BB02C5273CC948B00041701459408C95E4BE49EDC7CB605BD2DF31C3C8BB2AA9FC780", + "840BCC55474C2F66B7E16C6F527695D367F70F570B13C1ACB546D8439A1AE06F362C224FBD86441D82430A345B8458EB666BC93739E3D679754117C95100E8F00879B891C9E03788543C415AA964C3F861916BD7C141777A93B374943CC4CEDF928AEA3EB72F412DD8256227D7D7244E876955B13FB2EAD1C3980AF6F8F36B3E71FE3B189F8DC22C55E3720DA11C6AC4328DCF670CF948123FC7280D6891EEB356C195D2A79326299A684F5D68DC0ACF00B780CDCEFCD7CBE4140FB5B6DF896883D3C6FFC42BAA41E6A75713F8861C18A833C688C2BF6EED7F0CE66242B8196C7C254F9D48FD56AE5ADA9105A5C4AF28D0042E059A90979C6439BF6D498991CF64C68080B9B5392CC9FCA4397647A9AAC42C3810FA33BCF31C89A641D1078A0822D93EB773F418B9B3B20D5FEEE1067766AC561525F88F8F097BED0CBFF5BC498CDFC9A5B9D20F4D4A03CA190563CE543B2EAFD8DC6E4A5885DEA120DA7D157D00EB1329E500D41C7E6BD603E95BFAE227A9B613A71C7BEFC8449B668C59147E1DD5411CBD967CBBD46A9DDD76C547506A54A8245532FF9AA5312607F1AB99F4F9BCF85D93B58D76C5583856595AF5CA1AAC07C945400B35885071802620855E18E0A3B1EE92BB95241EFCAD82B3435BBB8916C4866471BD5715882F6BE508C7648A59B2AA91A69F60C78482197C04B31759054FFDAA254A143021E37874DE407690B9ECF8DB99CC16B004116F51DC7853370BD3538E14A0F02E7BF74D66FF898AEE93BF0697EB6E8E62B95C6C525A03E1A89CC2F56BAC591FA81BF6A1B3B9F1259F13AB45F2E9B0D93DA7B4984A9C71272CA261CC4EE4A44FBA4CD03C75D216672C18A60183A52B28796B356EC498F4926D833D94007E92EC190E9713354C7506BEA6B7B5DB2BE659E2A5BA92D00C01611347F67971478F2C71648E33F99EF201367CA3AC8814DE0F83B0BAFF34A192349C5DE87453167820C0EB0AC8349ECA683111776980FEBDC993314278B37B289B528DB319CF59B09B83342C71FD5E9F13EDF4F18783FF328BC67A03F1F62FD1A4631AFD76363DB1A79CD1EA95FD43934955AE211E00EF5AFC114BE00EAE2A7AB63042992E086810E61AEE3CE5CB0FE75C04969485899D552AD4B006D543BEB93C1E8578168C66667D62CBCB56F98DFBA248EECD891F9936382087F2AAD6F83FFE25E77F8BAB9C62675D4024E9BDCA5581126BD1ED6035994029BB54615E593D4CA81B31A5AE8CBEF8E1A81C32698FB7B4A339A7E4E575460F79C4F4C5F57F9E8DB459177067869E03E2E1681004EBBF62B4F60A9EFFE47921AD22C7236F25438AF46885E120825509D1E28652361EAC64AF1806317416E5550A39AA8DAE2C6B970D44F4F38D571F67E304AA57BA435C4E06CC97C848422216BA778B2736C30200527960A66D63280AF7DC691F9D0540AA47F0D26416B46A6D53B0B93F1B7C3D4DA8BF8AD2FE410ADDE00B0372E9E830C09B206A08D968AF2F716DD04D220E619FDE28FE70286E7EB9C2068F7A37413BD9E65F1B59C331D45AE914731A564D33875A0939A2185348C197CD14DAC59C5E2BEF09876353FB16D849EE67A774B05C51AA2480F18DE40051654DD2C7B9E3B753FEE5696B10BE40BFFE89487DA1E8B1C2000D53B2A98B4DE6C9DAF07F0B4DB72834361E520E45F5E958FE0760F229C16CCFE0BDBF07E186B28AA69231DDA8378DD6338A94D23541B9D8B63B85962C6304E1ACE2B56A3E433F7E9B2A88FBAD5FC71703231D38DFA8C378E15B6503A3B9959E1759EECCBFF14AA09E6BB8F2CC", + "152004D3334E877FE21F773408369872718CDEE15BD489D97F606779A9A38398524E6560260980FABCF179ED91D699D52592AFB3269FFB8DED36AFE7DC79DB773DBA560E3ADF8E12FB8A08EB56BFC4692BEA05AA288012B580E43BE085CE583E9C9DC18A9D32567EA950D8165A2F8A443E7AB5E79F687690A8D8D92FBF877C5B84D26E6FCB3671073BD808A7E908130A845C95A2F5E360645611B4B55B03169CC1F50AE2FFFAAF50FED8CB782BF3C67775B613CF82A2D102199E49A329496C0FA24AAF6370A3636EAFEB992C663C308AD181DC308D81FFD713505916300732FB1F8DCE238CC4104D26C588F28FE7EE4F2B8C2024357D52C7AA29D339249086CB2202DC1C847210EAEBD3F06A39642711B4608638564B0DD2BFDF38CD79CC1CFCE1226CA835E6EE19E4089A6F18E7ECC3597CAD3FFFE13A5F77A58C2B079DA25B928396FFAEE81FBD9C6243CE0EB0872A187E6CF99F16B1511672821D11EF88884964BAC6686C2A7732035493FB9765B7A51E845C1C79FABD99438FD84C09642FBC7CF1740DEB012AD050F5E8FF03E859E85C51D2E87AC41185C67C33820EFFCF2D79D384B11B44A806ABB8247AF36E3972222C805EB9854D9FCCDC7E58A101A5239E60CF4836C38A6ADE67686E6487547933859D46D046BFC15AE95B8D0A42A57C401EBE78ABF495EB390B8922C97270C790C2FAB9849ADE48EA8F4F7C6996F6DB661500199BCFE1EAFA1ECCFAB1F674E0BEB1D03319E73126D7191A64A80FCBBB06B1CFB718275BDDB571E8F53FAF81DBBC0522263FCDFB537B3BE9078F2AD449423152BB9DCCEEE97003D1988540FAE39CAB62593A9EC909489415EEF4229358229BDDD45CC35EBDBA088C4BA097BB0E28814BF5048F4F64E6A587B0BDAAA8A1B3E3E69D3D7B6782FC42474773C61DE12B4C6F183F9E625E337EFDC97A79A5D2C0C939FA668F440688F7A3E0E28A33D36D331069294DBA8BF768010AD93A224E28964A780304F59B7994D972832728249934B5347580C16BCDBE9F84EB34EA7F7645635437B0F5422E3DA99EC2D53B22B1A55BC783CE86CC6B1BE7B11F837CF2BD09A514B12ED7CF0AFC2F70F1D6D08288524263B1129135D664A48B0596C4E880E4E01BA3889014C07ED1B7F172AB4F4A69FC8C04F0ACE8AD1329A4FB594E9EA30EFEF31BBE418CB5515CFF8A375CBE58515B32E799E8449101093A053EC99F9CF78122FA2D36DDFBD258EC81D7B4D18BF882663CBF24D2A35A93C00AE8EA81A3B0E8040C1E259515156D67DC76602924BA51507C4994221A3B1CAD674BECB11574212EBCCFDCAF6AFEE288BCE11B7FFF1D7191AB329B04A237F75B204634676932FB0842E2AB888E7D5A4A6B7F77EA04ABF4B9A567E5DA5267F35CBBC928B5F607E9C08359F0031A934152D77E65C937181C92EF4CF17F6EA45171DEBAB545755795097766318CB132ACD96CDD65777F41BA127CF251A4E9B3348927757A42AD8FA83F6CE7342D935CB54984E45886D888627F0228E50082B85E8E9DDBECAAF049C25C4D7B2EA919716271500D81EDF574C5AE91E5F0FAD7585EF69C5051473AF913F887B31BD730F67B4A44081BBD567B57C061AF465237374E0BF4753F3C6CA28D45220CCA3EE6F07F93A29982EB5AAD70763ACBFBE55015D1C52B64954D4855ABCC319DDCAEE75CDFE3B3C31C329A77C76131F18F3C3904B3EA4E691C03C32CA5E7A1F9460760231473115B5AB7E159013C96AE4885566065883CA3B9661C6773B77819BC68755D529FCE05E80E08A5097EB37BDDC1AF9BDFCD0A04", + "0D4897E7FB496EF0C6D62C034088E7E9B8DB52F232CDC9EA88429655ABE366C54CD534DC9038F45AC0D0362E31086CA2FC0FCAC3FE71B2D4EEE548F69CE4433601CD3431D01BA6F0C23D612807EB8E50BFCA736D917F67DD72631BEE8728006D2AE69D1A1BAEA8DE50852CEBF7491FFF989C37A54EAE31652230A0D3E4397B051222C4A22BF481BC52E2012188C7576A7ACE81185C85A2E841119B47B5429DF277A976F15D5652156445905EC797729A6647E1B593484ACF2724E81786A0C062DE87759E82202A561FD077D64FDD3226A1E290F660722040EC7AD4383431E195412DBAD0AE620BFE808D65D3937AC9C5AEFD6FA106C88A6B192D4FEC1FB1A06907B0796F724AAC6A5EFEBF50C168F990BDBD6B1D23E098858C07E8D2144532AFE040E45B25AD9AF7D92F9DCCBFF3DF25DF574A4B65A219289407EB63FF7152BF1E651C6F124BE32545B50E8E2CE37F1042A68A62AB70D9DB540D2B39293E008EBAA632B85EF1052FDA17A07B9B1D89A76FF7E7EDEB7090496855B29A9174780D504F7228F8B7436F4676F51975BCA614554FE6B3F946F5E0D1016371F9CEED4521477CE8E9CD0668643686D8482CEC0BB4D6A9E8678B1835F0952E2700FE0C85A8683DA91638D81A85231CA4C7B55C0C0DA57DE5E6553F22290CE7EE72867285D096C0FC16A60A664C6BAB048939FF9DA476024235DDDBF7F264C90ED44E953C4AC0FB50362FB2CB4C4FC2097F07B71772000D2C2A5DBDF0B6FB83B1BBD70CE9D6A8BF1F924AAC4DAEB6AADD891A8974C9BF46FC6038F6B77D6AC0D6107AE6AF5B93B186253AFFFD8CD21835097C4B764F3E0B2447776549D5045E4346FCD3B7880F1B3BA794ADD6B7F291D3534DF034F822D0A41DB2AF9F1E51F212D5631D2525B1804A75B50D8372B6A1C200B81AC1122AA3C13D7463C383FD123DF4029BDAF6C227B3C4B54F75C5315FE139F6A0A3E2E819D3062B3309E2630EE4A64D1E3DBF23B489B96E198BA98D8D3347217A5FDE4DE453012E8564BAEFBE3939E59C0A725A75CEDE373501F9103011FE0EAA40C583AC73C92F47BD528600C42E0029FB3A4F03A3CCE87E5AAF4FCCB47EA8BC62E0F542DBD455F7163A2A8803583896E3C803C0D01846EBD8BB1B3FD396A7C7BC3F72A9D0503C44FE30E5E77E0FC8B373EE931CBF4A9867406BC91972B946B9ADE62415CE2FFC71C2E64DEB7E6205D635977C778BC40C11E36BFC22A17FE641346C74DADD255D329AEFC2CE5B4AC5B195FE2DB453F1B41B3334D5C480BBF10FDE88C722091ABC85667F2B52A3505A142E4D1546CC41E154B345E8456B9CD0E241D70EB4876A70623DFF3FF43A8D66EF60488A7860485A8E518AF4A7056CD02C72E1BAEA3944781642A36932ABFAEE3B88B57B213F9B358CC3F05154DF8D2132A74DF27556DB6C5E45256481C09D18DA604CB91E6AB7AA29C0C1009A406F1B3AAE268564E04B07E4E9128FF02513AB8A8665BFE1E352F46DBDE7870EE027A6E84560014659888EB6AACF993D7C9F9FBC2974CAE290059802F5D224520CE445C404A2ECC57CE6FD5961EB20DC12D436F0B93614CFC844B476D449416F54459BAD09F886CE3C1C307A91E62FC736051E6F6F8F5AD3372398458299EFDC1809997FAAAFDE14B15566B381714E3522F629A5ED9DDA1EF4B9D4498DD55F8B0A48ABB2F9B1FCBD991B5465108147BB6125FFEA6B6D479DB6A9983A51C041375B39FE6546AB5B5E089DD7E228D5AB17127A3A1E3AE82A31E952E660F72A1F399ADEB4E1E11C390BB8652F2F7B6D05E9F4B6FC90", + "AF6D254288BF564C4663014C7A70EB3739D28F1F17B8627FDF714E85B48EEFEB1FD456546328BF2E2EED112992AF78911A89E1248AEBF1F79906EA91D41CAFC6E541D2BB40A7050C5AE4B66547C9DDA88590AB8B0A4B01B5F8216447A310D1E52C155F92659835F1086D381F1F2995138856DEC6FF59380FD6C1B6EEA6E4061930CEF7217701DDFE17742721794DE824377392AF3D949ED9B0455C58F7395DE0FDA5485E310E8457A4270D603BA5AD1854811530FB7178525F4BB1E5DFF89F6FFE0C83C3E47E244D8F3F8AAD8374E3FDF996060E18D2A5397192823681CE6DA561816C0EEC0C0600732A37731ED13948439E8961BE44D32A3097C1AA5E19876ACD21DF812265181774580A8C04ED4FD1DE2FD5A1DFF9DCDF4D97C448BF9A4DACC22D4A55F588C87CCF5C9E178A8FFA032A454908BBE41E13D829FA98C066A7736577CDEFC6D5441656D0AC95C872861BCE0A28C2ED6E9420D4D167F37F96087F9E761F38B882CD41521DE8E2C40564C0E001EDBC04982669B82F05CD0411A6BADDCB704B545FCB19A286BFFAF0FB6DC889BCE75C5763BE1D70DCAD1D39F395A75E637E0663F3D5A855F53F700AF5F82124E72CC2A4E41A4B43FCBA41E55298A1B799368BD5F9B507FB11E8BD2D80FE517A5FA935006064278CDDC5EED43B7C2D309BECCCBB2C0AE3B8D09509315933E2DF91304B1DD3777EC9FA2415F7D18A96CD08095A30F7EB9BC12F8739E409EE7DC062703CB3EA591531F47F5D1C0431E9F1883C3BA249492EE619719C8B3BDFC1DECF7E3C4CE4CE032FB2882247D1D54566E3819464837C248D35647D273A87F8BE667760D26A7EA1FFA682A931A4D35F7407FBBBAD725BEA62449623AADE97A2789F2F8642F1CE12A06C93861DE9D27C5ACE0E4ECE40B58664176113ED6437B8AC8B4059653EA30F71A023544BFFA685343E278129DA12EEAADBDD5AB0E2CCA0B840E87AF0D0E859449893276B9B5894EB0C57C3222E01E7538FF7E91807C10CDB465A12CCD358151D96856C6143C9F8D25AF8E8086C83D4CAE37BD660D15C0C0707691E8366C4AFE6DC0AE1BFECEF9BEF46CFEA3356A3155E027D1C921ECB852BA4B8FE8E0C8C00829CEE4049A21A1C3424D2BE532B735232D12B81C3C9E5B02294701E6BCBC8607F2AFCFB2DD9B1142B4D261418C1B239B0B22451D7D3AC64636B0C7F96B41D7E775C1CFA2E277C957F0D59BD1FB02226A462533850E99E917E310A684E81634F3876D6AB32CB5B8FAE9E82224BD2A17A7C72CDACDC6B3438A083A6B0DB9FD91E05BF4C83A36916EF35C5D4871E94B1671493FDBC497BFA30328DD24D340A07A960828A855FA95EE33FE4FCD15B14B7929D338611239AC34CFDA6503E4DD9570EC339CFDC8D1C3D3536F5176901D012BABB133EBB4560484344E044F86A77C21183C82BB2B6632CF69F5A661C98EFDE5529F8FB965DCC6AF185CA8CDB4D01C5E8902966B063B8D1724AD18DAE495AD47416B61321DEEBF782EF7A6ADE3CD0D5B9ECA84DB5D50C2E5C7D8B8DB9E0F398376CDE3D7E8DC46F0D77D38D6CF6055D6D074CBA92A27C6F9018CAE87C97F1B3ACCEE495ED9DCE46DF4FA5255DB2C7F2669F5201058E90F7567672162E17D5B6D028C6AD23F2AEBA32061E6B33EA86915FAFA2344CC58162C032CE837D5C32F5993013314BD261DE6EBB35B94B8F690C5624A8CF5509BF50D3AF5FDAD77311B6D6F9398213AC1A267CAA0F52A262DA4F85F5ADC79947D2C5128B8E0B0C41B9FDEEF6AEC228EF97762CDBDB78273C16C39E446576D54A4FD0", + "4B7593A9ED7897766CACD515D3A55959FF99C1CE28A745DEC1D8F2565F24F4A1E14E9083AFF510F106D982A2911197338499CBE38CDF3D99463B13EE26B47D26A62CE45EAAA04A3E70850D5F23470FB94C42D3235D5FF9E6C37CEE8C93591CB69E0735B03EB262CE6BE6F0144DFD66BC089B36D66287EA588C78E39D9B6907EFE85C1211612952CF13C369C2AB3D921E4630ACC75F2AE99014776B26CD1F296F736A4616FF662D5C6E18C4EDA6D1791A71BE969556FF11E1192D3941F8020D2C731403ACD856A3AEE6ED7F23023BAD7BF138C702B6449E2601042D7990ADB988B650AE202F3433CF26EE132A7CB13650E86A6DBA6F7FA53B2354DEBF1268734D7120F721E18FEED2F93C268A2D3EA012F3D7F68DB0B18A5CDEBE13CE4A05683947DD985D4AED1E192FBD2719755846C9B758FC8FF28B9999D07E634645064C2C9DB4CFE50BB8A030B60F43AFBD588EC17102F614D3029FA811457568D7726C651C062391A2EC2843A95A3A48AF58A898BB65FB852F73E9A82C6AA9D406D80C072A3B426D8EBF261BF7AE0E9DC0C6DE9F4BEE880D775783F910AF19DFD8EC2656213FB9B74EEBD8E1BF860E4650D446683B7794086ECE1E2AA723024C219E3DCB371624C6D721BB60C797003D89096BA0F489D1CA60C57AD907BFC8E97F4E057B6D709414FB0A302D3057FB4635F70BB6A32CFD842DCD8D9C9D45FE082B3746951A862EA870D903382C138425DF936A505120D93FABB8F523C1D3946B85425FB338CA7DC4B2FB6512F0C8A67FA47A416284EAA943E1A9C0607A02D27F55F1DF2EB6090F94B64076FC2D3D3B3694DA5C7EB2A180DEA14AEC21156E1110DF75616685FD53C72252FB87E7D19EF5AE8D9E129D0984A06520C789DE22CBF6E2271801691E0C3CC672F6865A41559910D0279AB9E0112E66B2A1C2B22B6679CF70E3FF870084562ADB36F532E64D44C7264E44D488076F7714A1089526118D4655FFE16B02D803AC2601493CEC3AB27878CE95ED3F321913217DE12B8E5E8FB75A85707EAF6F1FF08CC86B91632ABC7CDC42D1C5D0F2F49D5F412B4AD0C5C46CFA74643C9333C5F3558DC3ABDBCBE23A3573146D648D540116136F3F29E42FF07E26C1504E47FCAD1FDAE63357E421E46440424921404ED02FD4BFA2FDE68CBE6CE49E4E120C141013DF5C0BDF776EE36FD5899C0FC057DAE2C9DAEF6D37BF8E85258BB36B54ED8374BDDD49B6AC2C8BF3105A194F76DD512336EAAFC7BD2054AF6A9606517DE03AF445CCA5FA65307D2E116E42A3676EB6033AA17D76A87F52D144CE25E3A8DAFD3E044289C4600BFAA9CCD963D14A19C5911C3DE649439440D11A21154EF25649F7DA295E0FDAE8C48351BC005C011A10D201B3062492A7CC933AB5D854B26232B7091CD0B7AA3135F28E3AE75E267C223C5E03B60FAC1BF78123C5AF76719191CB6BA277A5BE81E64117AB344D92837B6D600F36702F4BB4532C5EB1C9BAD8A111C540F52A225DACFAB37641898B1FF770A523F8BC8BB0DADB59235DE055810396F1993539A9CAAB622389607DCDFDD51FB67CBE89F0F868DB4D27A7A38542A076D158919DCB621BD325F23AA0DF694C444206FD42192FE7F9A05743CD54D8F111676AC35A3230E372A5A6D7E213C4584EEA1A4993067FD28DF6690BE9D3E94AC06BCF89BF1AA47496F8F6A18524187BE80D59A4E80193CFD757B706AD483A916AFBE2A56E0A69F3B1BBF9F4B239D05C6C556A8D22B00E9BB1FDAA620D949ECDE86EAA299BE93A7884C99FA782F2BB3BEEE86046489B3B8A5930", + "71BB1B2E833793D854F8A9A81E6A6947057B9571F2BA99380DDB25D878D6B48F09ED7DBFACE92B6B82F413E038128F6128AF3BC467E9A4DF2861DAAC674B6D948A10F28F7D43657FEE26577AF438A2F4422186930702EBC6C9173E661D59CE7594DF95B861F9D12EB060FCD3BA43159C9A1BDC1EF13E04893E411267331588CF4831978469FF569C1A738C54001BB5CF4FABD289075A165EDE0A58F6CF6D215D306A7840CBECD0E87E3AD186F7A67A967373551E13D2956E5C578A7F5BD50E2D570F9B914848D46A640913EBED2E2ABFB86916BC34EEB3E8A671AD771F6D3780B6FEC143E26F53B02977255314BAE9A2CD9E5BA2B49C73226FDC724A859F8BAD3A9FACA1B0E5F2DFE7E1E45DB6D4BE2B76535A817F94594A4541C01BB62AA83A690B6D84FC13B632972C61D940F2C9D32837413AF8E42045ECA3072CD044B2183400CE63C418879D13FD281A8D0835256DDD2BC3C9750C1D44CF1037FD7264B7716398FCF1D31CFFD0B7C52C6370E4CE6FC163B40436490A757465B20B8890C3B5C0AFB971ABFD01796569E3BC73C13D1E4B1FBC1CDCE59D21B6B110272E5770C589603FE67779A49AD0EC66910A2BF4D8C8ECC18A32EF92F502126A5DC3DE618233B9914A9608B2F17E5161115D9A3BEF1D5701A9D465A1437DE24371C9179800CB5728A7F3D734A2A706BC64D356BDF591389970B6CC139AC510A98E3C75F20120450CE45373AAEA6A279BBD17221BCD32ECF82C11B4C1CEE0A44792CF56978D3D2399F7ECDE9F8D9217F8BA22770E210D0F1AA852178B872E296762873765A73DEC08873C04ED69C995C5751B97DEC23B94CA674FE3F66211317B074D8203EC530A20B6E6DD21AB55895BEE1CBD0876183D652F4A0D2EFC95749F8F192F860BEA534598FD709B396C209CEAE4D9190980733E7E98C8ABE52A53C68D86053B56BA6FCAB5C827292D729CB8BFD1FC8CAFCDE15E4527B604018F28AA16C1E913F55461AF87C9A7BE1A742002E52B3A14EC30B259DDE7BB892CEAF77D25B7670B339B334878F697C00CE6740117AE7C67DF3F8A7BEAC89D4872682C47F368F835AFD7ECF0D8471AD01468B7BBB0A974EC469A8F79ECF8D379DC13685D2A8F6F19CE102C3DE34B11422AFB42E894C8D00F606296DABA7123FCE039ED27324D60E853BA94DC638454088281335D437A954333FF1A8D08E2A4D25CB3BA0D08BF6625E25EAD3C1EBFA2666AA49550578D3763ECDCE81303B53F18B00C8900AF4E0532C5ECBC94513DD9F50BE511CFE4D3DDBB3F112AE148DB062B2EADDB901CDA6AB6BF59D37F356AB34AF97D3DAAAA417642E87C9B95AA546C682ED641214605F82A4F486C9C72576106F76D7152615EC8E77187D4485071CFC6B0AE44880442790696E057A3AE20C860691353B3F6BEC5F1C2DA07563B423BC01E0334099571158A432441256D7C409B7B6EF26442075ED17E2BE37F8EBC049CFBE0FA89CDA7A58DD32C417B34E899FBE86E2FAB8D30846DA17144A6A66AAE1C24FCFABDA5B573FD2D6337226B5E49BB031B4D2B455B6DB871076F67AC03C3A73CEC01BD0B1EC42ABD177127E62A66FE8E475B982B4490F0877466EEFC7317A703C5C07937340ED4B53E5DE5325197FA31B8C8E05AA2222064EE5D7C06D4A1EB53151F75C94A2E259688CA0716548465C5C255D81FF10BACC2C13098ED8CF7F5B15193EE14FB5D258E95EDCC93E9796FA823892C705A5771D561787C12592D269D657FBB71F021F365B7453D50C35F748FB2B7F36DF28769B81EF12A26A237FB0239C173559540", + "53DA0E7B84741AA9E225483630169ACBCC03EB8CDA28B7BDA685C756D66B14488A2D0AEF7E6CB2D80F2726327257B7284B93EA1B56AB80FAE668C04FA49FCD658D896A997685E1EDB4DDF85456B37F32FC8CDE50882EF0F09BE4ED4AB9A425806A49E8347A42A50B38FA8D1DA2FD2C9438618B6701DEE159060C186D50170F24F38E07B185E3272EAEA4A0A7CA41A69C69E9D95E271287D3AB8284146A58440EA131A7F47D73CB2BCF40FE3A58E1B998C2E5EF9CEEC8EA2F8467BB7757C03A99FC8F014EE933A7080CD46625A2A7A251B7A37E4208956A8C9BD35E6F8674BC06FCAA5DD04A2558C9665C7985014D3AD95ED256FAFA358962EF5BB26AE2FCE899392DF858F99303E2417BCA7672E991FEB891F5DFCA2D461148367C5C0DE1460BF557194533DAF01A5E8E0E43D57B825AF7EEFF163DAA23B9F95C063A26B3D213459D885AA96023715CD21DFA2A2250F7610B78A77123443BD06EFB7DC85D1F16D0019D2937C3DEC4DE6389485ABB21642B6E41ADD43CE96F228C08DF6288A647EC2FE96032B6DCD651FF950B72964EE08FC2030272E3F601DB7F7E770E655389CA6CFA2F9B87CE76FB0E0CDCA4EEE5E80FC756BE46CC09F84BDB34ADA2AFC024ABDE0066ED939F8EBC236CB3F577C1BFD741F9D101A038EC86AB0A85462BAFB2E484D6722499A6310FA449D979030B2A21206D44225800BE2228FA00AE6D92C8DA652E1B003BD2734D30557B735CC2A591E090394DB791245C22B4D29E706476593B6F90C694C5B87BBB0FA2C479E292A768A9687A713336A21D1199186F852C41F586E9BBC64004D8BB6814BFE739834C99923177AAF87B926D56A7AFC0879C027332A60951C84E9314380A5A78E1196D094F15D856AA36742825D2B397156BCAD8ABE7291FB41DB4365AAE49CA82CA066D3B4366D3122ABBC00F05559DAFEBA9F98361DDAEF068D60B18265E7184C4D6BC9C3619CFF5C758090FF6398CCCEB78176D2A8A2A4B9854C4ACF5CB614DC1CA0E15E7E85442241D48FD3D6E851A5D3947FA769560928948FA26FA16EFBD2159994BD92B3D6B0C62818C91D4724413A7F40B2A2D67F4FC97B5DF6A7E3CEC03158E201D6643F402D3DD6995A42900D46C2881198CAD28A27489F5116ECEC3E38D999B2020E0C381DB3B8230811270D75950D9BB61548802DBBCB68ED8C7BCCB50D606BE400BECF873498621E66ABD2AA179B3E90E055C3719CE2FE047F815B95B065BA086B467AF4124E276F8CEAD000BCA5499D36217B250009A7B43E81CB3F8B1A3238EE436FE61F2F942796DBCBE570BB4FC783B35C3CA31BDD432B33AD75B08107253E8F910EFE0D0B5453A8A055D884892278688B3ECA612452B590AF38DBDD9A7070C5610E7A3CA6C91D24438E7F45E7A2A330F164AEDFFF1789D5E875EEF121298DB79C77278ABFEC3FE3DF843C46F40E847272EB2669BABA808C38E31F13516D5066AF4DFCDE6EDB2FF0B0A4CE9FA9B4101F6F144B02384868617CD39175852E065473D6F566CD18D7403FFD24DD33ADDB52C7CC22167E49102C46DC369A92CE2D2FCB81B4D1F14B7CD2F80A65D8FBD20FDAA23219873ACB8CF934E68D6F8FED6B41193CFAB1F44CE4BFC7C67DE1E8804B47DFD7E8AE281E19846AEB6FF94AE7E7CF6FFAB46242843811E6C5BDB78157C76DF4F92FD3653D7FA5978316EB055059C6A2B6306C957418860A88F63355E76D96F4727128D9B3EB98501AF5B093F2C314F98EA2CDB89468E1BD51138CBF25E8B911C26B97DCCA47F1A1D6C1CD415A5079A756B8A8715DD3164", }; + // Galileo E5a-I secondary code const std::string Galileo_E5a_I_SECONDARY_CODE = "10000100001011101001"; + // Galileo E5a-Q secondary codes const std::string Galileo_E5a_Q_SECONDARY_CODE[Galileo_E5a_NUMBER_OF_CODES] = { - "1000001111110110111101101001110110001111011011100001010101000001000111111011100011001001101100011100", - "0110011001010101100010111101001111001110000011000111011110010010111010000011001101010000010100100101", - "0101100110100000001001011010100111000001101011110000011001010001101101110111100110101000001110000001", - "1101001110100011001001100100000001111000001011110111101100011000111001001101111101110101010010110111", - "1011100100011111110010101101011101110110000011000010000110001111101001011001001101001000101010010011", - "1011101011000111011111101001001100111010011101111001000101000000111100001001010011111011111110011000", - "0101001101110111100001011101111000101000000010010010011111000110101101011000101110100110011101110110", - "1110111111001010101101001011011001011111001110000101001100011110110010100010001000100101011111100010", - "0111100111111000110010101110100000111000010001110101111010100101010110000100101111101111110010011011", - "1100101001010001011100001111111010100011101010000001000011101100011000000110101101100110010010010100", - "0001111111000011001001000001000001100101001010100010110001001001101111011000010001011110010101100111", - "1111111000001010100110100111101011111101101011000100010011100100001011001011100101011101001001100001", - "1011000000110000011000101101110000101011011100011001100101011101010110101101100010110111110110111110", - "1111011011000011100110001001100100111111010110011000111000101101111101000010001101011101001111010101", - "0001101110110010111110111000101101011011111100100100001110010101110000101110111100111100010110100001", - "0010111110010010000001101000011111010010001110001100110001110000010001101110111101101010111111001001", - "0011010000010110001110001000011011111100010011101101011111110010101010010010111011111101101110111000", - "0110011010101000011100101100111001000111100000110011111110110010110111111101010101100010010110101101", - "1001100111010101101001110000000101100010110010010010000010100100101110111001110111100001110010101000", - "1000000111010111000110111101011011100000011010011010011110101100110010111110110111000110011011001010", - "1010011001010100010100100100000001110100101010011110011001111000000011011011100111010011111011000110", - "1100001100111001011010100001000000011011111011011010111101100010001111001111110001011011101100110111", - "1100001111010100101010110010000100011101111100110110111100100001000100011111001000010100000111001101", - "0011110111111111001001011110101011100111011000010111001110010010011001011010111100010100010111000001", - "1001100101001001000010011110000001110101011111010111000011001101111000111000100100010000001010110101", - "1011100100111000010100110101010100100010110100010001100111110100000011000010010111111101101011101100", - "1100011100011010101101010100100111000000010010010001010100110111000000100110101100111001000010110111", - "0000110011011011100011001001111001111011010100111111010101011111010110110000101000000101100101111011", - "0110000111000101111110100010010100101111000110101111100000010001010001000111011001100100100101001111", - "0110001001100000001001110111011110001111110100111100011010111011010010111010101001111010010110011101", - "1110011101000101010000010010111111110101001111011110101111010000001111110001110010011010011000110011", - "0011010110010010101011000000100000111111001100010111010111111010011100100100011000111001000010011000", - "0101001000101000010011011001010000011100001111011100101011110010011100100001110111011011000111111101", - "0111001110110011110110001111000010101101010101011101111101001111111010000001010011101101100010010000", - "1001010010111111000101101100100000111011110101110100011000101111011001001001100011100000001010000010", - "1010100011000011110111100001101011000110011010000000100010011011000010110100010110110011010101111001", - "0010001011010110111000101010011101101000111001011111001101011111111111001000111000000001011110010110", - "0010010100110001000010100000011001100111010111101011001001110001111100101010000010011110101000011101", - "1001111101111001100100111100011000100001110101001011111011001000000110100000010100110101011100000011", - "1101011000101001100110011110101011001111000111001001100100001000001111000000101101001010010000010111", - "1111011001100101101001111110101001000100000110111010101001001110101000001101000000010000011110001100", - "0100011011110011110100110000010000111111001001001100110111101010101111010110111101111001010101000011", - "1110001011100011111010000010010101000110000101101011110110010110110011101111110010100110010100011010", - "1110010101001000001000110001101010000010111110011010000000011010000110011101101101011110000110110010", - "0010011001011100011111111001000010100001011011110100100111101101111000101010101001110000011011001000", - "0011011001001010001110101001111010110000111100000100100000011101101000000001100110011101011111101010", - "1001100000010000101001111010100010011000100101100001001001100011101000001111011101001001111101010110", + "1000001111110110111101101001110110001111011011100001010101000001000111111011100011001001101100011100", + "0110011001010101100010111101001111001110000011000111011110010010111010000011001101010000010100100101", + "0101100110100000001001011010100111000001101011110000011001010001101101110111100110101000001110000001", + "1101001110100011001001100100000001111000001011110111101100011000111001001101111101110101010010110111", + "1011100100011111110010101101011101110110000011000010000110001111101001011001001101001000101010010011", + "1011101011000111011111101001001100111010011101111001000101000000111100001001010011111011111110011000", + "0101001101110111100001011101111000101000000010010010011111000110101101011000101110100110011101110110", + "1110111111001010101101001011011001011111001110000101001100011110110010100010001000100101011111100010", + "0111100111111000110010101110100000111000010001110101111010100101010110000100101111101111110010011011", + "1100101001010001011100001111111010100011101010000001000011101100011000000110101101100110010010010100", + "0001111111000011001001000001000001100101001010100010110001001001101111011000010001011110010101100111", + "1111111000001010100110100111101011111101101011000100010011100100001011001011100101011101001001100001", + "1011000000110000011000101101110000101011011100011001100101011101010110101101100010110111110110111110", + "1111011011000011100110001001100100111111010110011000111000101101111101000010001101011101001111010101", + "0001101110110010111110111000101101011011111100100100001110010101110000101110111100111100010110100001", + "0010111110010010000001101000011111010010001110001100110001110000010001101110111101101010111111001001", + "0011010000010110001110001000011011111100010011101101011111110010101010010010111011111101101110111000", + "0110011010101000011100101100111001000111100000110011111110110010110111111101010101100010010110101101", + "1001100111010101101001110000000101100010110010010010000010100100101110111001110111100001110010101000", + "1000000111010111000110111101011011100000011010011010011110101100110010111110110111000110011011001010", + "1010011001010100010100100100000001110100101010011110011001111000000011011011100111010011111011000110", + "1100001100111001011010100001000000011011111011011010111101100010001111001111110001011011101100110111", + "1100001111010100101010110010000100011101111100110110111100100001000100011111001000010100000111001101", + "0011110111111111001001011110101011100111011000010111001110010010011001011010111100010100010111000001", + "1001100101001001000010011110000001110101011111010111000011001101111000111000100100010000001010110101", + "1011100100111000010100110101010100100010110100010001100111110100000011000010010111111101101011101100", + "1100011100011010101101010100100111000000010010010001010100110111000000100110101100111001000010110111", + "0000110011011011100011001001111001111011010100111111010101011111010110110000101000000101100101111011", + "0110000111000101111110100010010100101111000110101111100000010001010001000111011001100100100101001111", + "0110001001100000001001110111011110001111110100111100011010111011010010111010101001111010010110011101", + "1110011101000101010000010010111111110101001111011110101111010000001111110001110010011010011000110011", + "0011010110010010101011000000100000111111001100010111010111111010011100100100011000111001000010011000", + "0101001000101000010011011001010000011100001111011100101011110010011100100001110111011011000111111101", + "0111001110110011110110001111000010101101010101011101111101001111111010000001010011101101100010010000", + "1001010010111111000101101100100000111011110101110100011000101111011001001001100011100000001010000010", + "1010100011000011110111100001101011000110011010000000100010011011000010110100010110110011010101111001", + "0010001011010110111000101010011101101000111001011111001101011111111111001000111000000001011110010110", + "0010010100110001000010100000011001100111010111101011001001110001111100101010000010011110101000011101", + "1001111101111001100100111100011000100001110101001011111011001000000110100000010100110101011100000011", + "1101011000101001100110011110101011001111000111001001100100001000001111000000101101001010010000010111", + "1111011001100101101001111110101001000100000110111010101001001110101000001101000000010000011110001100", + "0100011011110011110100110000010000111111001001001100110111101010101111010110111101111001010101000011", + "1110001011100011111010000010010101000110000101101011110110010110110011101111110010100110010100011010", + "1110010101001000001000110001101010000010111110011010000000011010000110011101101101011110000110110010", + "0010011001011100011111111001000010100001011011110100100111101101111000101010101001110000011011001000", + "0011011001001010001110101001111010110000111100000100100000011101101000000001100110011101011111101010", + "1001100000010000101001111010100010011000100101100001001001100011101000001111011101001001111101010110", }; diff --git a/src/core/system_parameters/MATH_CONSTANTS.h b/src/core/system_parameters/MATH_CONSTANTS.h index 7fc35d683..1b415fa37 100644 --- a/src/core/system_parameters/MATH_CONSTANTS.h +++ b/src/core/system_parameters/MATH_CONSTANTS.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,6 +31,8 @@ #ifndef GNSS_SDR_MATH_CONSTANTS_H_ #define GNSS_SDR_MATH_CONSTANTS_H_ +#include + /* Constants for scaling the ephemeris found in the data message the format is the following: TWO_N5 -> 2^-5, TWO_P4 -> 2^4, PI_TWO_N43 -> Pi*2^-43, etc etc Additionally some of the PI*2^N terms are used in the tracking stuff @@ -40,6 +42,10 @@ PI_TWO_PX ==> Pi*2^X ONE_PI_TWO_PX = (1/Pi)*2^X */ + +const double PI = 3.1415926535897932; //!< pi +const double PI_2 = 2.0 * PI; //!< 2 * pi + const double TWO_P4 = (16); //!< 2^4 const double TWO_P11 = (2048); //!< 2^11 const double TWO_P12 = (4096); //!< 2^12 @@ -53,6 +59,7 @@ const double TWO_P57 = (1.441151880758559e+017); //!< 2^57 const double TWO_N2 = (0.25); //!< 2^-2 const double TWO_N5 = (0.03125); //!< 2^-5 +const double TWO_N6 = (0.015625); //!< 2^-6 const double TWO_N8 = (0.00390625); //!< 2^-8 const double TWO_N9 = (0.001953125); //!< 2^-9 const double TWO_N10 = (0.0009765625); //!< 2^-10 @@ -60,9 +67,12 @@ const double TWO_N11 = (4.882812500000000e-004); //!< 2^-11 const double TWO_N14 = (0.00006103515625); //!< 2^-14 const double TWO_N15 = (0.00003051757813); //!< 2^-15 const double TWO_N16 = (0.0000152587890625); //!< 2^-16 +const double TWO_N17 = (7.629394531250000e-006); //!< 2^-17 +const double TWO_N18 = (3.814697265625000e-006); //!< 2^-18 const double TWO_N19 = (1.907348632812500e-006); //!< 2^-19 const double TWO_N20 = (9.536743164062500e-007); //!< 2^-20 const double TWO_N21 = (4.768371582031250e-007); //!< 2^-21 +const double TWO_N23 = (1.192092895507810e-007); //!< 2^-23 const double TWO_N24 = (5.960464477539063e-008); //!< 2^-24 const double TWO_N25 = (2.980232238769531e-008); //!< 2^-25 const double TWO_N27 = (7.450580596923828e-009); //!< 2^-27 @@ -73,8 +83,9 @@ const double TWO_N32 = (2.328306436538696e-010); //!< 2^-32 const double TWO_N33 = (1.164153218269348e-010); //!< 2^-33 const double TWO_N34 = (5.82076609134674e-011); //!< 2^-34 const double TWO_N35 = (2.91038304567337e-011); //!< 2^-35 - const double TWO_N38 = (3.637978807091713e-012); //!< 2^-38 +const double TWO_N39 = (1.818989403545856e-012); //!< 2^-39 +const double TWO_N40 = (9.094947017729280e-013); //!< 2^-40 const double TWO_N43 = (1.136868377216160e-013); //!< 2^-43 const double TWO_N44 = (5.684341886080802e-14); //!< 2^-44 const double TWO_N46 = (1.4210854715202e-014); //!< 2^-46 @@ -86,6 +97,7 @@ const double TWO_N55 = (2.775557561562891e-017); //!< 2^-55 const double TWO_N57 = (6.938893903907228e-18); //!< 2^-57 const double TWO_N59 = (1.73472347597681e-018); //!< 2^-59 const double TWO_N60 = (8.673617379884036e-19); //!< 2^-60 +const double TWO_N68 = (3.388131789017201e-21); //!< 2^-68 const double PI_TWO_N19 = (5.992112452678286e-006); //!< Pi*2^-19 @@ -94,4 +106,13 @@ const double PI_TWO_N31 = (1.462918079267160e-009); //!< Pi*2^-31 const double PI_TWO_N38 = (1.142904749427469e-011); //!< Pi*2^-38 const double PI_TWO_N23 = (3.745070282923929e-007); //!< Pi*2^-23 +const double D2R = (PI / 180.0); //!< deg to rad +const double R2D = (180.0 / PI); //!< rad to deg +const double SC2RAD = 3.1415926535898; //!< semi-circle to radian (IS-GPS) +const double AS2R = (D2R / 3600.0); //!< arc sec to radian + +const double DEFAULT_OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Default Earth rotation rate, [rad/s] +const double SPEED_OF_LIGHT = 299792458.0; //!< [m/s] +const double AU = 149597870691.0; //!< 1 Astronomical Unit AU (m) distance from Earth to the Sun. + #endif /* GNSS_SDR_MATH_CONSTANTS_H_ */ diff --git a/src/core/system_parameters/gps_ref_location.cc b/src/core/system_parameters/agnss_ref_location.cc similarity index 76% rename from src/core/system_parameters/gps_ref_location.cc rename to src/core/system_parameters/agnss_ref_location.cc index 38f510aef..c59f8fbc4 100644 --- a/src/core/system_parameters/gps_ref_location.cc +++ b/src/core/system_parameters/agnss_ref_location.cc @@ -1,12 +1,12 @@ /*! - * \file gps_ref_location.cc - * \brief Interface of a GPS REFERENCE LOCATION storage + * \file agnss_ref_location.cc + * \brief Interface of an Assisted GNSS REFERENCE LOCATION storage * * \author Javier Arribas, 2013. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,18 +24,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include "gps_ref_location.h" +#include "agnss_ref_location.h" -Gps_Ref_Location::Gps_Ref_Location() +Agnss_Ref_Location::Agnss_Ref_Location() { valid = false; lat = 0.0; lon = 0.0; uncertainty = 0.0; } - diff --git a/src/core/system_parameters/gps_ref_location.h b/src/core/system_parameters/agnss_ref_location.h similarity index 60% rename from src/core/system_parameters/gps_ref_location.h rename to src/core/system_parameters/agnss_ref_location.h index ecd824895..083305987 100644 --- a/src/core/system_parameters/gps_ref_location.h +++ b/src/core/system_parameters/agnss_ref_location.h @@ -1,11 +1,11 @@ /*! - * \file gps_ref_location.h - * \brief Interface of a GPS REFERENCE LOCATION storage + * \file agnss_ref_location.h + * \brief Interface of an Assisted GNSS REFERENCE LOCATION storage * \author Javier Arribas, 2013. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,24 +23,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_REF_LOCATION_H_ -#define GNSS_SDR_GPS_REF_LOCATION_H_ +#ifndef GNSS_SDR_AGNSS_REF_LOCATION_H_ +#define GNSS_SDR_AGNSS_REF_LOCATION_H_ -#include "boost/assign.hpp" +#include #include /*! - * \brief Interface of a GPS REFERENCE LOCATION storage + * \brief Interface of an Assisted GNSS REFERENCE LOCATION storage * */ -class Gps_Ref_Location +class Agnss_Ref_Location { public: bool valid; @@ -50,22 +50,24 @@ public: /*! * Default constructor */ - Gps_Ref_Location(); + Agnss_Ref_Location(); - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the Ref location on disk file. */ - void serialize(Archive& archive, const unsigned int version) - { - using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("valid", valid); - archive & make_nvp("lat", lat); - archive & make_nvp("lon", lon); - archive & make_nvp("uncertainty", uncertainty); - } + inline void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + archive& make_nvp("valid", valid); + archive& make_nvp("lat", lat); + archive& make_nvp("lon", lon); + archive& make_nvp("uncertainty", uncertainty); + } }; #endif diff --git a/src/core/system_parameters/gps_ref_time.cc b/src/core/system_parameters/agnss_ref_time.cc similarity index 78% rename from src/core/system_parameters/gps_ref_time.cc rename to src/core/system_parameters/agnss_ref_time.cc index 9524f40c8..0d1e8c687 100644 --- a/src/core/system_parameters/gps_ref_time.cc +++ b/src/core/system_parameters/agnss_ref_time.cc @@ -1,12 +1,12 @@ /*! - * \file gps_ref_time.cc - * \brief Interface of a GPS REFERENCE TIME storage + * \file agnss_ref_time.cc + * \brief Interface of an Assisted GNSS REFERENCE TIME storage * * \author Javier Arribas, 2013. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,14 +24,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include "gps_ref_time.h" +#include "agnss_ref_time.h" -Gps_Ref_Time::Gps_Ref_Time() +Agnss_Ref_Time::Agnss_Ref_Time() { valid = false; d_TOW = 0.0; @@ -39,4 +39,3 @@ Gps_Ref_Time::Gps_Ref_Time() d_tv_sec = 0.0; d_tv_usec = 0.0; } - diff --git a/src/core/system_parameters/gps_ref_time.h b/src/core/system_parameters/agnss_ref_time.h similarity index 62% rename from src/core/system_parameters/gps_ref_time.h rename to src/core/system_parameters/agnss_ref_time.h index 4ef7bef47..574d9106a 100644 --- a/src/core/system_parameters/gps_ref_time.h +++ b/src/core/system_parameters/agnss_ref_time.h @@ -1,11 +1,11 @@ /*! - * \file gps_ref_time.h - * \brief Interface of a GPS REFERENCE TIME storage + * \file agnss_ref_time.h + * \brief Interface of an Assisted GNSS REFERENCE TIME storage * \author Javier Arribas, 2013. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,24 +23,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_REF_TIME_H_ -#define GNSS_SDR_GPS_REF_TIME_H_ +#ifndef GNSS_SDR_AGNSS_REF_TIME_H_ +#define GNSS_SDR_AGNSS_REF_TIME_H_ -#include "boost/assign.hpp" +#include #include /*! - * \brief Interface of a GPS REFERENCE TIME storage + * \brief Interface of an Assisted GNSS REFERENCE TIME storage * */ -class Gps_Ref_Time +class Agnss_Ref_Time { public: bool valid; @@ -51,22 +51,24 @@ public: /*! * Default constructor */ - Gps_Ref_Time(); + Agnss_Ref_Time(); - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ref time data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const unsigned int version) { using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("valid", valid); - archive & make_nvp("d_TOW", d_TOW); - archive & make_nvp("d_Week", d_Week); - archive & make_nvp("d_tv_sec", d_tv_sec); - archive & make_nvp("d_tv_usec", d_tv_usec); + if (version) + { + }; + archive& make_nvp("valid", valid); + archive& make_nvp("d_TOW", d_TOW); + archive& make_nvp("d_Week", d_Week); + archive& make_nvp("d_tv_sec", d_tv_sec); + archive& make_nvp("d_tv_usec", d_tv_usec); } }; diff --git a/src/core/system_parameters/display.h b/src/core/system_parameters/display.h new file mode 100644 index 000000000..a186753be --- /dev/null +++ b/src/core/system_parameters/display.h @@ -0,0 +1,82 @@ +/*! + * \file display.h + * \brief Defines useful display constants + * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DISPLAY_H_ +#define GNSS_SDR_DISPLAY_H_ + +#include + +#ifndef NO_DISPLAY_COLORS +#define DISPLAY_COLORS 1 +#endif + + +#ifdef DISPLAY_COLORS + +const std::string TEXT_RESET = "\033[0m"; +const std::string TEXT_BLACK = "\033[30m"; +const std::string TEXT_RED = "\033[31m"; +const std::string TEXT_GREEN = "\033[32m"; +const std::string TEXT_YELLOW = "\033[33m"; +const std::string TEXT_BLUE = "\033[34m"; +const std::string TEXT_MAGENTA = "\033[35m"; +const std::string TEXT_CYAN = "\033[36m"; +const std::string TEXT_WHITE = "\033[37m"; +const std::string TEXT_BOLD_BLACK = "\033[1m\033[30m"; +const std::string TEXT_BOLD_RED = "\033[1m\033[31m"; +const std::string TEXT_BOLD_GREEN = "\033[1m\033[32m"; +const std::string TEXT_BOLD_YELLOW = "\033[1m\033[33m"; +const std::string TEXT_BOLD_BLUE = "\033[1m\033[34m"; +const std::string TEXT_BOLD_MAGENTA = "\033[1m\033[35m"; +const std::string TEXT_BOLD_CYAN = "\033[1m\033[36m"; +const std::string TEXT_BOLD_WHITE = "\033[1m\033[37m"; + +#else + +const std::string TEXT_RESET = ""; +const std::string TEXT_BLACK = ""; +const std::string TEXT_RED = ""; +const std::string TEXT_GREEN = ""; +const std::string TEXT_YELLOW = ""; +const std::string TEXT_BLUE = ""; +const std::string TEXT_MAGENTA = ""; +const std::string TEXT_CYAN = ""; +const std::string TEXT_WHITE = ""; +const std::string TEXT_BOLD_BLACK = ""; +const std::string TEXT_BOLD_RED = ""; +const std::string TEXT_BOLD_GREEN = ""; +const std::string TEXT_BOLD_YELLOW = ""; +const std::string TEXT_BOLD_BLUE = ""; +const std::string TEXT_BOLD_MAGENTA = ""; +const std::string TEXT_BOLD_CYAN = ""; +const std::string TEXT_BOLD_WHITE = ""; + +#endif /* DISPLAY_COLORS */ +#endif /* GNSS_SDR_DISPLAY_H_ */ diff --git a/src/core/system_parameters/galileo_almanac.cc b/src/core/system_parameters/galileo_almanac.cc index 9e387f04c..6dbc7b25e 100644 --- a/src/core/system_parameters/galileo_almanac.cc +++ b/src/core/system_parameters/galileo_almanac.cc @@ -1,11 +1,11 @@ /*! * \file galileo_almanac.cc - * \brief Implementation of a Galileo ALMANAC storage - * \author Javier Arribas, 2013. jarribas(at)cttc.es + * \brief Interface of a Galileo ALMANAC storage + * \author Carles Fernandez, 2018. cfernandez(at)cttc.cat * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,74 +23,30 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_almanac.h" + Galileo_Almanac::Galileo_Almanac() { - /*Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number*/ - IOD_a_7 = 0; - WN_a_7 = 0.0; - t0a_7 = 0.0; - SVID1_7 = 0; - DELTA_A_7 = 0.0; - e_7 = 0.0; - omega_7 = 0.0; - delta_i_7 = 0.0; - Omega0_7 = 0.0; - Omega_dot_7 = 0.0; - M0_7 = 0.0; - - /*Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ - IOD_a_8 = 0; - af0_8 = 0.0; - af1_8 = 0.0; - E5b_HS_8 = 0.0; - E1B_HS_8 = 0.0; - E5a_HS_8 = 0.0; - SVID2_8 = 0; - DELTA_A_8 = 0.0; - e_8 = 0.0; - omega_8 = 0.0; - delta_i_8 = 0.0; - Omega0_8 = 0.0; - Omega_dot_8 = 0.0; - - /*Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2)*/ - IOD_a_9 = 0; - WN_a_9 = 0.0; - t0a_9 = 0.0; - M0_9 = 0.0; - af0_9 = 0.0; - af1_9 = 0.0; - E5b_HS_9 = 0.0; - E1B_HS_9 = 0.0; - E5a_HS_9 = 0.0; - SVID3_9 = 0; - DELTA_A_9 = 0.0; - e_9 = 0.0; - omega_9 = 0.0; - delta_i_9 = 0.0; - - /*Word type 10: Almanac for SVID3 (2/2)*/ - IOD_a_10 = 0; - Omega0_10 = 0.0; - Omega_dot_10 = 0.0; - M0_10 = 0.0; - af0_10 = 0.0; - af1_10 = 0.0; - E5b_HS_10 = 0.0; - E1B_HS_10 = 0.0; - E5a_HS_10 = 0.0; - - /*GPS to Galileo GST conversion parameters*/ - A_0G_10 = 0.0; - A_1G_10 = 0.0; - t_0G_10 = 0.0; - WN_0G_10 = 0.0; + i_satellite_PRN = 0U; + i_Toa = 0; + i_WNa = 0; + i_IODa = 0; + d_Delta_i = 0.0; + d_M_0 = 0.0; + d_e_eccentricity = 0.0; + d_Delta_sqrt_A = 0.0; + d_OMEGA0 = 0.0; + d_OMEGA = 0.0; + d_OMEGA_DOT = 0.0; + d_A_f0 = 0.0; + d_A_f1 = 0.0; + E5b_HS = 0; + E1B_HS = 0; + E5a_HS = 0; } - diff --git a/src/core/system_parameters/galileo_almanac.h b/src/core/system_parameters/galileo_almanac.h index ea636379a..022d778be 100644 --- a/src/core/system_parameters/galileo_almanac.h +++ b/src/core/system_parameters/galileo_almanac.h @@ -1,11 +1,11 @@ /*! * \file galileo_almanac.h * \brief Interface of a Galileo ALMANAC storage - * \author Javier Arribas, 2013. jarribas(at)cttc.es - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com + * \author Carles Fernandez, 2018. cfernandez(at)cttc.cat + * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,85 +23,70 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #ifndef GNSS_SDR_GALILEO_ALMANAC_H_ #define GNSS_SDR_GALILEO_ALMANAC_H_ +#include +#include /*! - * \brief This class is a storage for the GALILEO ALMANAC data as described in GALILEO ICD - * - * See https://www.gsc-europa.eu/system/files/galileo_documents/Galileo_OS_SIS_ICD.pdf paragraph 5.1.10 + * \brief This class is a storage for the Galileo SV ALMANAC data */ class Galileo_Almanac { public: - /*Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number*/ - int IOD_a_7; - double WN_a_7; - double t0a_7; - int SVID1_7; - double DELTA_A_7; - double e_7; - double omega_7; - double delta_i_7; - double Omega0_7; - double Omega_dot_7; - double M0_7; + uint32_t i_satellite_PRN; //!< SV PRN NUMBER + int32_t i_Toa; + int32_t i_WNa; + int32_t i_IODa; + double d_Delta_i; //!< Inclination at reference time relative to i0 = 56º [semi-circles] + double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] + double d_e_eccentricity; //!< Eccentricity [dimensionless] + double d_Delta_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] + double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + double d_OMEGA; //!< Argument of Perigee [semi-cicles] + double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] + double d_A_f0; //!< Coefficient 0 of code phase offset model [s] + double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] + int32_t E5b_HS; + int32_t E1B_HS; + int32_t E5a_HS; - /*Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ - int IOD_a_8; - double af0_8; - double af1_8; - double E5b_HS_8; - double E1B_HS_8; - double E5a_HS_8; - int SVID2_8; - double DELTA_A_8; - double e_8; - double omega_8; - double delta_i_8; - double Omega0_8; - double Omega_dot_8; + /*! + * Default constructor + */ + Galileo_Almanac(); - /*Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2)*/ - int IOD_a_9; - double WN_a_9; - double t0a_9; - double M0_9; - double af0_9; - double af1_9; - double E5b_HS_9; - double E1B_HS_9; - double E5a_HS_9; - int SVID3_9; - double DELTA_A_9; - double e_9; - double omega_9; - double delta_i_9; + template - /*Word type 10: Almanac for SVID3 (2/2)*/ - int IOD_a_10; - double Omega0_10; - double Omega_dot_10; - double M0_10; - double af0_10; - double af1_10; - double E5b_HS_10; - double E1B_HS_10; - double E5a_HS_10; - - /*GPS to Galileo GST conversion parameters*/ - double A_0G_10; - double A_1G_10; - double t_0G_10; - double WN_0G_10; - - Galileo_Almanac(); //!< Default constructor + void serialize(Archive& ar, const unsigned int version) + { + if (version) + { + }; + ar& BOOST_SERIALIZATION_NVP(i_satellite_PRN); + ar& BOOST_SERIALIZATION_NVP(i_Toa); + ar& BOOST_SERIALIZATION_NVP(i_WNa); + ar& BOOST_SERIALIZATION_NVP(i_IODa); + ar& BOOST_SERIALIZATION_NVP(d_Delta_i); + ar& BOOST_SERIALIZATION_NVP(d_M_0); + ar& BOOST_SERIALIZATION_NVP(d_e_eccentricity); + ar& BOOST_SERIALIZATION_NVP(d_Delta_sqrt_A); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA0); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA_DOT); + ar& BOOST_SERIALIZATION_NVP(d_A_f0); + ar& BOOST_SERIALIZATION_NVP(d_A_f1); + ar& BOOST_SERIALIZATION_NVP(E5b_HS); + ar& BOOST_SERIALIZATION_NVP(E1B_HS); + ar& BOOST_SERIALIZATION_NVP(E5a_HS); + } }; #endif diff --git a/src/core/system_parameters/galileo_almanac_helper.cc b/src/core/system_parameters/galileo_almanac_helper.cc new file mode 100644 index 000000000..2fbd3e689 --- /dev/null +++ b/src/core/system_parameters/galileo_almanac_helper.cc @@ -0,0 +1,156 @@ +/*! + * \file galileo_almanac_helper.cc + * \brief Implementation of a Galileo ALMANAC storage helper + * \author Javier Arribas, 2013. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "galileo_almanac_helper.h" + +Galileo_Almanac_Helper::Galileo_Almanac_Helper() +{ + // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number + IOD_a_7 = 0; + WN_a_7 = 0; + t0a_7 = 0; + SVID1_7 = 0; + DELTA_A_7 = 0.0; + e_7 = 0.0; + omega_7 = 0.0; + delta_i_7 = 0.0; + Omega0_7 = 0.0; + Omega_dot_7 = 0.0; + M0_7 = 0.0; + + // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2) + IOD_a_8 = 0; + af0_8 = 0.0; + af1_8 = 0.0; + E5b_HS_8 = 0; + E1B_HS_8 = 0; + E5a_HS_8 = 0; + SVID2_8 = 0; + DELTA_A_8 = 0.0; + e_8 = 0.0; + omega_8 = 0.0; + delta_i_8 = 0.0; + Omega0_8 = 0.0; + Omega_dot_8 = 0.0; + + // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2) + IOD_a_9 = 0; + WN_a_9 = 0; + t0a_9 = 0; + M0_9 = 0.0; + af0_9 = 0.0; + af1_9 = 0.0; + E5b_HS_9 = 0; + E1B_HS_9 = 0; + E5a_HS_9 = 0; + SVID3_9 = 0; + DELTA_A_9 = 0.0; + e_9 = 0.0; + omega_9 = 0.0; + delta_i_9 = 0.0; + + // Word type 10: Almanac for SVID3 (2/2) + IOD_a_10 = 0; + Omega0_10 = 0.0; + Omega_dot_10 = 0.0; + M0_10 = 0.0; + af0_10 = 0.0; + af1_10 = 0.0; + E5b_HS_10 = 0; + E1B_HS_10 = 0; + E5a_HS_10 = 0; +} + +Galileo_Almanac Galileo_Almanac_Helper::get_almanac(int i) +{ + Galileo_Almanac galileo_almanac; + switch (i) + { + case 1: + galileo_almanac.i_satellite_PRN = this->SVID1_7; + galileo_almanac.i_Toa = this->t0a_7; + galileo_almanac.i_WNa = this->WN_a_7; + galileo_almanac.i_IODa = this->IOD_a_7; + galileo_almanac.d_Delta_i = this->delta_i_7; + galileo_almanac.d_M_0 = this->M0_7; + galileo_almanac.d_e_eccentricity = this->e_7; + galileo_almanac.d_Delta_sqrt_A = this->DELTA_A_7; + galileo_almanac.d_OMEGA0 = this->Omega0_7; + galileo_almanac.d_OMEGA = this->omega_7; + galileo_almanac.d_OMEGA_DOT = this->Omega_dot_7; + galileo_almanac.d_A_f0 = this->af0_8; + galileo_almanac.d_A_f1 = this->af1_8; + galileo_almanac.E5b_HS = this->E5b_HS_8; + galileo_almanac.E1B_HS = this->E1B_HS_8; + galileo_almanac.E5a_HS = this->E5a_HS_8; + break; + + case 2: + galileo_almanac.i_satellite_PRN = this->SVID2_8; + galileo_almanac.i_Toa = this->t0a_9; + galileo_almanac.i_WNa = this->WN_a_9; + galileo_almanac.i_IODa = this->IOD_a_9; + galileo_almanac.d_Delta_i = this->delta_i_8; + galileo_almanac.d_M_0 = this->M0_9; + galileo_almanac.d_e_eccentricity = this->e_8; + galileo_almanac.d_Delta_sqrt_A = this->DELTA_A_8; + galileo_almanac.d_OMEGA0 = this->Omega0_8; + galileo_almanac.d_OMEGA = this->omega_8; + galileo_almanac.d_OMEGA_DOT = this->Omega_dot_8; + galileo_almanac.d_A_f0 = this->af0_9; + galileo_almanac.d_A_f1 = this->af1_9; + galileo_almanac.E1B_HS = this->E1B_HS_9; + galileo_almanac.E5a_HS = this->E5a_HS_9; + break; + + case 3: + galileo_almanac.i_satellite_PRN = this->SVID3_9; + galileo_almanac.i_Toa = this->t0a_9; + galileo_almanac.i_WNa = this->WN_a_9; + galileo_almanac.i_IODa = this->IOD_a_10; + galileo_almanac.d_Delta_i = this->delta_i_9; + galileo_almanac.d_M_0 = this->M0_10; + galileo_almanac.d_e_eccentricity = this->e_9; + galileo_almanac.d_Delta_sqrt_A = this->DELTA_A_9; + galileo_almanac.d_OMEGA0 = this->Omega0_10; + galileo_almanac.d_OMEGA = this->omega_9; + galileo_almanac.d_OMEGA_DOT = this->Omega_dot_10; + galileo_almanac.d_A_f0 = this->af0_10; + galileo_almanac.d_A_f1 = this->af1_10; + galileo_almanac.E5b_HS = this->E5b_HS_10; + galileo_almanac.E1B_HS = this->E1B_HS_10; + galileo_almanac.E5a_HS = this->E5a_HS_10; + break; + + default: + break; + } + return galileo_almanac; +} diff --git a/src/core/system_parameters/galileo_almanac_helper.h b/src/core/system_parameters/galileo_almanac_helper.h new file mode 100644 index 000000000..960ccd09e --- /dev/null +++ b/src/core/system_parameters/galileo_almanac_helper.h @@ -0,0 +1,104 @@ +/*! + * \file galileo_almanac_helper.h + * \brief Interface of a Galileo ALMANAC storage helper + * \author Javier Arribas, 2013. jarribas(at)cttc.es + * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_ALMANAC_HELPER_H_ +#define GNSS_SDR_GALILEO_ALMANAC_HELPER_H_ + +#include "galileo_almanac.h" +#include + +/*! + * \brief This class is a storage for the GALILEO ALMANAC data as described in GALILEO ICD + * + * See https://www.gsc-europa.eu/system/files/galileo_documents/Galileo_OS_SIS_ICD.pdf paragraph 5.1.10 + */ +class Galileo_Almanac_Helper +{ +public: + // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number + int32_t IOD_a_7; + int32_t WN_a_7; + int32_t t0a_7; + int32_t SVID1_7; + double DELTA_A_7; + double e_7; + double omega_7; + double delta_i_7; + double Omega0_7; + double Omega_dot_7; + double M0_7; + + // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2) + int32_t IOD_a_8; + double af0_8; + double af1_8; + int32_t E5b_HS_8; + int32_t E1B_HS_8; + int32_t E5a_HS_8; + int32_t SVID2_8; + double DELTA_A_8; + double e_8; + double omega_8; + double delta_i_8; + double Omega0_8; + double Omega_dot_8; + + // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2) + int32_t IOD_a_9; + int32_t WN_a_9; + int32_t t0a_9; + double M0_9; + double af0_9; + double af1_9; + int32_t E5b_HS_9; + int32_t E1B_HS_9; + int32_t E5a_HS_9; + int32_t SVID3_9; + double DELTA_A_9; + double e_9; + double omega_9; + double delta_i_9; + + // Word type 10: Almanac for SVID3 (2/2) + int32_t IOD_a_10; + double Omega0_10; + double Omega_dot_10; + double M0_10; + double af0_10; + double af1_10; + int32_t E5b_HS_10; + int32_t E1B_HS_10; + int32_t E5a_HS_10; + + Galileo_Almanac_Helper(); //!< Default constructor + Galileo_Almanac get_almanac(int i); +}; + +#endif diff --git a/src/core/system_parameters/galileo_ephemeris.cc b/src/core/system_parameters/galileo_ephemeris.cc index d118bd392..a606b2d20 100644 --- a/src/core/system_parameters/galileo_ephemeris.cc +++ b/src/core/system_parameters/galileo_ephemeris.cc @@ -5,7 +5,7 @@ * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,14 +23,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_ephemeris.h" -#include #include "Galileo_E1.h" +#include Galileo_Ephemeris::Galileo_Ephemeris() @@ -39,40 +39,43 @@ Galileo_Ephemeris::Galileo_Ephemeris() IOD_ephemeris = 0; IOD_nav_1 = 0; SV_ID_PRN_4 = 0; - M0_1 = 0; // Mean anomaly at reference time [semi-circles] - delta_n_3 = 0; // Mean motion difference from computed value [semi-circles/sec] - e_1 = 0; // Eccentricity - A_1 = 0; // Square root of the semi-major axis [metres^1/2] - OMEGA_0_2 = 0; // Longitude of ascending node of orbital plane at weekly epoch [semi-circles] - i_0_2 = 0; // Inclination angle at reference time [semi-circles] - omega_2 = 0; // Argument of perigee [semi-circles] - OMEGA_dot_3 = 0; // Rate of right ascension [semi-circles/sec] - iDot_2 = 0; // Rate of inclination angle [semi-circles/sec] - C_uc_3 = 0; // Amplitude of the cosine harmonic correction term to the argument of latitude [radians] - C_us_3 = 0; // Amplitude of the sine harmonic correction term to the argument of latitude [radians] - C_rc_3 = 0; // Amplitude of the cosine harmonic correction term to the orbit radius [meters] - C_rs_3 = 0; // Amplitude of the sine harmonic correction term to the orbit radius [meters] - C_ic_4 = 0; // Amplitude of the cosine harmonic correction term to the angle of inclination [radians] - C_is_4 = 0; // Amplitude of the sine harmonic correction term to the angle of inclination [radians] - t0e_1 = 0; // Ephemeris reference time [s] - /*Clock correction parameters*/ - t0c_4 = 0; // Clock correction data reference Time of Week [sec] - af0_4 = 0; // SV clock bias correction coefficient [s] - af1_4 = 0; // SV clock drift correction coefficient [s/s] - af2_4 = 0; // SV clock drift rate correction coefficient [s/s^2] - /*GST*/ + M0_1 = 0.0; // Mean anomaly at reference time [semi-circles] + delta_n_3 = 0.0; // Mean motion difference from computed value [semi-circles/sec] + e_1 = 0.0; // Eccentricity + A_1 = 0.0; // Square root of the semi-major axis [meters^1/2] + OMEGA_0_2 = 0.0; // Longitude of ascending node of orbital plane at weekly epoch [semi-circles] + i_0_2 = 0.0; // Inclination angle at reference time [semi-circles] + omega_2 = 0.0; // Argument of perigee [semi-circles] + OMEGA_dot_3 = 0.0; // Rate of right ascension [semi-circles/sec] + iDot_2 = 0.0; // Rate of inclination angle [semi-circles/sec] + C_uc_3 = 0.0; // Amplitude of the cosine harmonic correction term to the argument of latitude [radians] + C_us_3 = 0.0; // Amplitude of the sine harmonic correction term to the argument of latitude [radians] + C_rc_3 = 0.0; // Amplitude of the cosine harmonic correction term to the orbit radius [meters] + C_rs_3 = 0.0; // Amplitude of the sine harmonic correction term to the orbit radius [meters] + C_ic_4 = 0.0; // Amplitude of the cosine harmonic correction term to the angle of inclination [radians] + C_is_4 = 0.0; // Amplitude of the sine harmonic correction term to the angle of inclination [radians] + t0e_1 = 0; // Ephemeris reference time [s] + + // Clock correction parameters + t0c_4 = 0; // Clock correction data reference Time of Week [sec] + af0_4 = 0.0; // SV clock bias correction coefficient [s] + af1_4 = 0.0; // SV clock drift correction coefficient [s/s] + af2_4 = 0.0; // SV clock drift rate correction coefficient [s/s^2] + + // GST WN_5 = 0; TOW_5 = 0; + // SV status SISA_3 = 0; E5a_HS = 0; E5b_HS_5 = 0; E1B_HS_5 = 0; E5a_DVS = false; - E5b_DVS_5 = 0; - E1B_DVS_5 = 0; - BGD_E1E5a_5 = 0; // E1-E5a Broadcast Group Delay [s] - BGD_E1E5b_5 = 0; // E1-E5b Broadcast Group Delay [s] + E5b_DVS_5 = false; + E1B_DVS_5 = false; + BGD_E1E5a_5 = 0.0; // E1-E5a Broadcast Group Delay [s] + BGD_E1E5b_5 = 0.0; // E1-E5b Broadcast Group Delay [s] Galileo_satClkDrift = 0.0; Galileo_dtr = 0.0; @@ -81,12 +84,13 @@ Galileo_Ephemeris::Galileo_Ephemeris() d_satpos_X = 0.0; d_satpos_Y = 0.0; d_satpos_Z = 0.0; + // Satellite velocity d_satvel_X = 0.0; d_satvel_Y = 0.0; d_satvel_Z = 0.0; - i_satellite_PRN = 0; + i_satellite_PRN = 0U; } @@ -121,24 +125,23 @@ double Galileo_Ephemeris::Galileo_System_Time(double WN, double TOW) double t = 0; double sec_in_day = 86400; double day_in_week = 7; - t = WN * sec_in_day * day_in_week + TOW; // second from the origin of the Galileo time + t = WN * sec_in_day * day_in_week + TOW; // second from the origin of the Galileo time return t; } - double Galileo_Ephemeris::sv_clock_drift(double transmitTime) { // Satellite Time Correction Algorithm, ICD 5.1.4 double dt; dt = transmitTime - t0c_4; - Galileo_satClkDrift = af0_4 + af1_4 * dt + af2_4 * (dt * dt) + sv_clock_relativistic_term(transmitTime); //+Galileo_dtr; + Galileo_satClkDrift = af0_4 + af1_4 * dt + af2_4 * (dt * dt) + sv_clock_relativistic_term(transmitTime); //+Galileo_dtr; return Galileo_satClkDrift; } // compute the relativistic correction term -double Galileo_Ephemeris::sv_clock_relativistic_term(double transmitTime) // Satellite Time Correction Algorithm, ICD 5.1.4 +double Galileo_Ephemeris::sv_clock_relativistic_term(double transmitTime) // Satellite Time Correction Algorithm, ICD 5.1.4 { double tk; double a; @@ -150,9 +153,9 @@ double Galileo_Ephemeris::sv_clock_relativistic_term(double transmitTime) // Sat double M; // Restore semi-major axis - a = A_1*A_1; + a = A_1 * A_1; - n0 = sqrt(GALILEO_GM / (a*a*a)); + n0 = sqrt(GALILEO_GM / (a * a * a)); // Time from ephemeris reference epoch //t = WN_5*86400*7 + TOW_5; //WN_5*86400*7 are the second from the origin of the Galileo time @@ -165,17 +168,17 @@ double Galileo_Ephemeris::sv_clock_relativistic_term(double transmitTime) // Sat M = M0_1 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2*GALILEO_PI), (2*GALILEO_PI)); + M = fmod((M + 2 * GALILEO_PI), (2 * GALILEO_PI)); // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + e_1 * sin(E); - dE = fmod(E - E_old, 2*GALILEO_PI); + E_old = E; + E = M + e_1 * sin(E); + dE = fmod(E - E_old, 2 * GALILEO_PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -184,21 +187,20 @@ double Galileo_Ephemeris::sv_clock_relativistic_term(double transmitTime) // Sat } // Compute relativistic correction term - Galileo_dtr = GALILEO_F * e_1* A_1 * sin(E); + Galileo_dtr = GALILEO_F * e_1 * A_1 * sin(E); return Galileo_dtr; } - void Galileo_Ephemeris::satellitePosition(double transmitTime) { // when this function in used, the input must be the transmitted time (t) in second computed by Galileo_System_Time (above function) - double tk; // Time from ephemeris reference epoch - double a; // Semi-major axis - double n; // Corrected mean motion - double n0; // Computed mean motion - double M; // Mean anomaly - double E; // Eccentric Anomaly (to be solved by iteration) + double tk; // Time from ephemeris reference epoch + double a; // Semi-major axis + double n; // Corrected mean motion + double n0; // Computed mean motion + double M; // Mean anomaly + double E; // Eccentric Anomaly (to be solved by iteration) double E_old; double dE; double nu; // True anomaly @@ -211,10 +213,10 @@ void Galileo_Ephemeris::satellitePosition(double transmitTime) // Find Galileo satellite's position ---------------------------------------------- // Restore semi-major axis - a = A_1*A_1; + a = A_1 * A_1; // Computed mean motion - n0 = sqrt(GALILEO_GM / (a*a*a)); + n0 = sqrt(GALILEO_GM / (a * a * a)); // Time from ephemeris reference epoch tk = transmitTime - t0e_1; @@ -226,17 +228,17 @@ void Galileo_Ephemeris::satellitePosition(double transmitTime) M = M0_1 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2* GALILEO_PI), (2* GALILEO_PI)); + M = fmod((M + 2 * GALILEO_PI), (2 * GALILEO_PI)); // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii<20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + e_1 * sin(E); - dE = fmod(E - E_old, 2*GALILEO_PI); + E_old = E; + E = M + e_1 * sin(E); + dE = fmod(E - E_old, 2 * GALILEO_PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -254,32 +256,31 @@ void Galileo_Ephemeris::satellitePosition(double transmitTime) phi = nu + omega_2; // Reduce phi to between 0 and 2*pi rad - phi = fmod((phi), (2*GALILEO_PI)); + phi = fmod((phi), (2 * GALILEO_PI)); // Correct argument of latitude - u = phi + C_uc_3 * cos(2*phi) + C_us_3 * sin(2*phi); + u = phi + C_uc_3 * cos(2 * phi) + C_us_3 * sin(2 * phi); // Correct radius - r = a * (1 - e_1*cos(E)) + C_rc_3 * cos(2*phi) + C_rs_3 * sin(2*phi); + r = a * (1 - e_1 * cos(E)) + C_rc_3 * cos(2 * phi) + C_rs_3 * sin(2 * phi); // Correct inclination - i = i_0_2 + iDot_2 * tk + C_ic_4 * cos(2*phi) + C_is_4 * sin(2*phi); + i = i_0_2 + iDot_2 * tk + C_ic_4 * cos(2 * phi) + C_is_4 * sin(2 * phi); // Compute the angle between the ascending node and the Greenwich meridian - Omega = OMEGA_0_2 + (OMEGA_dot_3 - GALILEO_OMEGA_EARTH_DOT)*tk - GALILEO_OMEGA_EARTH_DOT * t0e_1; + Omega = OMEGA_0_2 + (OMEGA_dot_3 - GALILEO_OMEGA_EARTH_DOT) * tk - GALILEO_OMEGA_EARTH_DOT * t0e_1; // Reduce to between 0 and 2*pi rad - Omega = fmod((Omega + 2*GALILEO_PI), (2*GALILEO_PI)); + Omega = fmod((Omega + 2 * GALILEO_PI), (2 * GALILEO_PI)); // --- Compute satellite coordinates in Earth-fixed coordinates d_satpos_X = cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega); - d_satpos_Y = cos(u) * r * sin(Omega) + sin(u) * r * cos(i) * cos(Omega); // ********NOTE: in GALILEO ICD this expression is not correct because it has minus (- sin(u) * r * cos(i) * cos(Omega)) instead of plus + d_satpos_Y = cos(u) * r * sin(Omega) + sin(u) * r * cos(i) * cos(Omega); // ********NOTE: in GALILEO ICD this expression is not correct because it has minus (- sin(u) * r * cos(i) * cos(Omega)) instead of plus d_satpos_Z = sin(u) * r * sin(i); // Satellite's velocity. Can be useful for Vector Tracking loops double Omega_dot = OMEGA_dot_3 - GALILEO_OMEGA_EARTH_DOT; - d_satvel_X = - Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); + d_satvel_X = -Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); d_satvel_Y = Omega_dot * (cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega)) + d_satpos_X * sin(Omega) + d_satpos_Y * cos(i) * cos(Omega); d_satvel_Z = d_satpos_Y * sin(i); } - diff --git a/src/core/system_parameters/galileo_ephemeris.h b/src/core/system_parameters/galileo_ephemeris.h index 39d48eeef..75d2bdbd9 100644 --- a/src/core/system_parameters/galileo_ephemeris.h +++ b/src/core/system_parameters/galileo_ephemeris.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include #include +#include /*! @@ -48,50 +49,50 @@ public: /* Galileo ephemeris are 16 parameters and here are reported following the ICD order, paragraph 5.1.1. The number in the name after underscore (_1, _2, _3 and so on) refers to the page were we can find that parameter */ bool flag_all_ephemeris; - int IOD_ephemeris; - int IOD_nav_1; - int SV_ID_PRN_4; - double M0_1; //!< Mean anomaly at reference time [semi-circles] - double delta_n_3; //!< Mean motion difference from computed value [semi-circles/sec] - double e_1; //!< Eccentricity - double A_1; //!< Square root of the semi-major axis [metres^1/2] - double OMEGA_0_2; //!< Longitude of ascending node of orbital plane at weekly epoch [semi-circles] - double i_0_2; //!< Inclination angle at reference time [semi-circles] - double omega_2; //!< Argument of perigee [semi-circles] - double OMEGA_dot_3; //!< Rate of right ascension [semi-circles/sec] - double iDot_2; //!< Rate of inclination angle [semi-circles/sec] - double C_uc_3; //!< Amplitude of the cosine harmonic correction term to the argument of latitude [radians] - double C_us_3; //!< Amplitude of the sine harmonic correction term to the argument of latitude [radians] - double C_rc_3; //!< Amplitude of the cosine harmonic correction term to the orbit radius [meters] - double C_rs_3; //!< Amplitude of the sine harmonic correction term to the orbit radius [meters] - double C_ic_4; //!< Amplitude of the cosine harmonic correction term to the angle of inclination [radians] - double C_is_4; //!< Amplitude of the sine harmonic correction term to the angle of inclination [radians] - double t0e_1; //!< Ephemeris reference time [s] + int32_t IOD_ephemeris; + int32_t IOD_nav_1; + int32_t SV_ID_PRN_4; + double M0_1; //!< Mean anomaly at reference time [semi-circles] + double delta_n_3; //!< Mean motion difference from computed value [semi-circles/sec] + double e_1; //!< Eccentricity + double A_1; //!< Square root of the semi-major axis [meters^1/2] + double OMEGA_0_2; //!< Longitude of ascending node of orbital plane at weekly epoch [semi-circles] + double i_0_2; //!< Inclination angle at reference time [semi-circles] + double omega_2; //!< Argument of perigee [semi-circles] + double OMEGA_dot_3; //!< Rate of right ascension [semi-circles/sec] + double iDot_2; //!< Rate of inclination angle [semi-circles/sec] + double C_uc_3; //!< Amplitude of the cosine harmonic correction term to the argument of latitude [radians] + double C_us_3; //!< Amplitude of the sine harmonic correction term to the argument of latitude [radians] + double C_rc_3; //!< Amplitude of the cosine harmonic correction term to the orbit radius [meters] + double C_rs_3; //!< Amplitude of the sine harmonic correction term to the orbit radius [meters] + double C_ic_4; //!< Amplitude of the cosine harmonic correction term to the angle of inclination [radians] + double C_is_4; //!< Amplitude of the sine harmonic correction term to the angle of inclination [radians] + int32_t t0e_1; //!< Ephemeris reference time [s] /*Clock correction parameters*/ - double t0c_4; //!< Clock correction data reference Time of Week [sec] - double af0_4; //!< SV clock bias correction coefficient [s] - double af1_4; //!< SV clock drift correction coefficient [s/s] - double af2_4; //!< SV clock drift rate correction coefficient [s/s^2] + int32_t t0c_4; //!< Clock correction data reference Time of Week [sec] + double af0_4; //!< SV clock bias correction coefficient [s] + double af1_4; //!< SV clock drift correction coefficient [s/s] + double af2_4; //!< SV clock drift rate correction coefficient [s/s^2] /*GST*/ - //Not belong to ephemeris set (page 1 to 4) - double WN_5; //!< Week number - double TOW_5; //!< Time of Week + // Not belong to ephemeris set (page 1 to 4) + int32_t WN_5; //!< Week number + int32_t TOW_5; //!< Time of Week double Galileo_satClkDrift; - double Galileo_dtr; //!< relativistic clock correction term + double Galileo_dtr; //!< relativistic clock correction term // SV status - double SISA_3; - unsigned int E5a_HS; //!< E5a Signal Health Status - double E5b_HS_5; //!< E5b Signal Health Status - double E1B_HS_5; //!< E1B Signal Health Status - bool E5a_DVS; //!< E5a Data Validity Status - double E5b_DVS_5; //!< E5b Data Validity Status - double E1B_DVS_5; //!< E1B Data Validity Status - - double BGD_E1E5a_5; //!< E1-E5a Broadcast Group Delay [s] - double BGD_E1E5b_5; //!< E1-E5b Broadcast Group Delay [s] + int32_t SISA_3; + int32_t E5a_HS; //!< E5a Signal Health Status + int32_t E5b_HS_5; //!< E5b Signal Health Status + int32_t E1B_HS_5; //!< E1B Signal Health Status + bool E5a_DVS; //!< E5a Data Validity Status + bool E5b_DVS_5; //!< E5b Data Validity Status + bool E1B_DVS_5; //!< E1B Data Validity Status + + double BGD_E1E5a_5; //!< E1-E5a Broadcast Group Delay [s] + double BGD_E1E5b_5; //!< E1-E5b Broadcast Group Delay [s] // satellite positions double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. @@ -103,43 +104,68 @@ public: double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] - unsigned int i_satellite_PRN; //!< SV PRN NUMBER + uint32_t i_satellite_PRN; //!< SV PRN NUMBER - void satellitePosition(double transmitTime); //!< Computes the ECEF SV coordinates and ECEF velocity - double Galileo_System_Time(double WN, double TOW); //!< Galileo System Time (GST), ICD paragraph 5.1.2 - double sv_clock_drift(double transmitTime); //!< Satellite Time Correction Algorithm, ICD 5.1.4 - double sv_clock_relativistic_term(double transmitTime); //!< Satellite Time Correction Algorithm, ICD 5.1.4 + void satellitePosition(double transmitTime); //!< Computes the ECEF SV coordinates and ECEF velocity + double Galileo_System_Time(double WN, double TOW); //!< Galileo System Time (GST), ICD paragraph 5.1.2 + double sv_clock_drift(double transmitTime); //!< Satellite Time Correction Algorithm, ICD 5.1.4 + double sv_clock_relativistic_term(double transmitTime); //!< Satellite Time Correction Algorithm, ICD 5.1.4 Galileo_Ephemeris(); - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const uint32_t version) { - using boost::serialization::make_nvp; + if (version) + { + }; - archive & make_nvp("i_satellite_PRN",i_satellite_PRN); - archive & make_nvp("M0_1", M0_1); - archive & make_nvp("e_1", e_1); - archive & make_nvp("A_1", A_1); - archive & make_nvp("OMEGA_0_2", OMEGA_0_2); - archive & make_nvp("i_0_2", i_0_2); - archive & make_nvp("omega_2", omega_2); - archive & make_nvp("OMEGA_dot_3", OMEGA_dot_3); - archive & make_nvp("iDot_2", iDot_2); - archive & make_nvp("C_uc_3", C_uc_3); - archive & make_nvp("C_us_3", C_us_3); - archive & make_nvp("C_rc_3", C_rc_3); - archive & make_nvp("C_rs_3", C_rs_3); - archive & make_nvp("C_ic_4", C_ic_4); - archive & make_nvp("C_is_4", C_is_4); - archive & make_nvp("t0e_1", t0e_1); - archive & make_nvp("t0c_4", t0c_4); - archive & make_nvp("af0_4", af0_4); - archive & make_nvp("af1_4", af1_4); - archive & make_nvp("af2_4", af2_4); + archive& BOOST_SERIALIZATION_NVP(i_satellite_PRN); + + archive& BOOST_SERIALIZATION_NVP(M0_1); + archive& BOOST_SERIALIZATION_NVP(delta_n_3); + archive& BOOST_SERIALIZATION_NVP(e_1); + archive& BOOST_SERIALIZATION_NVP(A_1); + archive& BOOST_SERIALIZATION_NVP(OMEGA_0_2); + archive& BOOST_SERIALIZATION_NVP(i_0_2); + archive& BOOST_SERIALIZATION_NVP(omega_2); + archive& BOOST_SERIALIZATION_NVP(OMEGA_dot_3); + archive& BOOST_SERIALIZATION_NVP(iDot_2); + archive& BOOST_SERIALIZATION_NVP(C_uc_3); + archive& BOOST_SERIALIZATION_NVP(C_us_3); + archive& BOOST_SERIALIZATION_NVP(C_rc_3); + archive& BOOST_SERIALIZATION_NVP(C_rs_3); + archive& BOOST_SERIALIZATION_NVP(C_ic_4); + archive& BOOST_SERIALIZATION_NVP(C_is_4); + archive& BOOST_SERIALIZATION_NVP(t0e_1); + + archive& BOOST_SERIALIZATION_NVP(t0c_4); + archive& BOOST_SERIALIZATION_NVP(af0_4); + archive& BOOST_SERIALIZATION_NVP(af1_4); + archive& BOOST_SERIALIZATION_NVP(af2_4); + + archive& BOOST_SERIALIZATION_NVP(WN_5); + archive& BOOST_SERIALIZATION_NVP(TOW_5); + archive& BOOST_SERIALIZATION_NVP(Galileo_satClkDrift); + archive& BOOST_SERIALIZATION_NVP(Galileo_dtr); + + archive& BOOST_SERIALIZATION_NVP(flag_all_ephemeris); + archive& BOOST_SERIALIZATION_NVP(IOD_ephemeris); + archive& BOOST_SERIALIZATION_NVP(IOD_nav_1); + + archive& BOOST_SERIALIZATION_NVP(SISA_3); + archive& BOOST_SERIALIZATION_NVP(E5a_HS); + archive& BOOST_SERIALIZATION_NVP(E5b_HS_5); + archive& BOOST_SERIALIZATION_NVP(E1B_HS_5); + archive& BOOST_SERIALIZATION_NVP(E5a_DVS); + archive& BOOST_SERIALIZATION_NVP(E5b_DVS_5); + archive& BOOST_SERIALIZATION_NVP(E1B_DVS_5); + + archive& BOOST_SERIALIZATION_NVP(BGD_E1E5a_5); + archive& BOOST_SERIALIZATION_NVP(BGD_E1E5b_5); } }; diff --git a/src/core/system_parameters/galileo_fnav_message.cc b/src/core/system_parameters/galileo_fnav_message.cc index d30ea7451..b7fa86e3c 100644 --- a/src/core/system_parameters/galileo_fnav_message.cc +++ b/src/core/system_parameters/galileo_fnav_message.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -29,19 +29,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_fnav_message.h" -#include // for boost::crc_basic, boost::crc_optimal +#include // for boost::crc_basic, boost::crc_optimal #include #include #include -typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_Galileo_FNAV_type; +using CRC_Galileo_FNAV_type = boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false>; void Galileo_Fnav_Message::reset() { @@ -51,75 +51,75 @@ void Galileo_Fnav_Message::reset() flag_ephemeris_2 = false; //!< Flag indicating that ephemeris 2/3 (word 3) have been received flag_ephemeris_3 = false; //!< Flag indicating that ephemeris 3/3 (word 4) have been received - flag_iono_and_GST = false; //!< Flag indicating that ionospheric and GST parameters (word 1) have been received + flag_iono_and_GST = false; //!< Flag indicating that ionospheric and GST parameters (word 1) have been received flag_TOW_1 = false; flag_TOW_2 = false; flag_TOW_3 = false; flag_TOW_4 = false; - flag_TOW_set = false; //!< it is true when page 1,2,3 or 4 arrives - flag_utc_model = false; //!< Flag indicating that utc model parameters (word 4) have been received + flag_TOW_set = false; //!< it is true when page 1,2,3 or 4 arrives + flag_utc_model = false; //!< Flag indicating that utc model parameters (word 4) have been received - flag_all_almanac = false; //!< Flag indicating that all almanac have been received - flag_almanac_1 = false; //!< Flag indicating that almanac 1/2 (word 5) have been received - flag_almanac_2 = false; //!< Flag indicating that almanac 2/2 (word 6) have been received + flag_all_almanac = false; //!< Flag indicating that all almanac have been received + flag_almanac_1 = false; //!< Flag indicating that almanac 1/2 (word 5) have been received + flag_almanac_2 = false; //!< Flag indicating that almanac 2/2 (word 6) have been received IOD_ephemeris = 0; page_type = 0; - /* WORD 1 SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal - * health and Data validity status*/ + // WORD 1 SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal + // health and Data validity status FNAV_SV_ID_PRN_1 = 0; - FNAV_IODnav_1 = 0; + FNAV_IODnav_1 = -1; FNAV_t0c_1 = 0; - FNAV_af0_1 = 0; - FNAV_af1_1 = 0; - FNAV_af2_1 = 0; + FNAV_af0_1 = 0.0; + FNAV_af1_1 = 0.0; + FNAV_af2_1 = 0.0; FNAV_SISA_1 = 0; - FNAV_ai0_1 = 0; - FNAV_ai1_1 = 0; - FNAV_ai2_1 = 0; - FNAV_region1_1 = 0; - FNAV_region2_1 = 0; - FNAV_region3_1 = 0; - FNAV_region4_1 = 0; - FNAV_region5_1 = 0; - FNAV_BGD_1 = 0; + FNAV_ai0_1 = 0.0; + FNAV_ai1_1 = 0.0; + FNAV_ai2_1 = 0.0; + FNAV_region1_1 = false; + FNAV_region2_1 = false; + FNAV_region3_1 = false; + FNAV_region4_1 = false; + FNAV_region5_1 = false; + FNAV_BGD_1 = 0.0; FNAV_E5ahs_1 = 0; FNAV_WN_1 = 0; FNAV_TOW_1 = 0; - FNAV_E5advs_1 = 0; + FNAV_E5advs_1 = false; // WORD 2 Ephemeris (1/3) and GST - FNAV_IODnav_2 = 0; - FNAV_M0_2 = 0; - FNAV_omegadot_2 = 0; - FNAV_e_2 = 0; - FNAV_a12_2 = 0; - FNAV_omega0_2 = 0; - FNAV_idot_2 = 0; + FNAV_IODnav_2 = -2; + FNAV_M0_2 = 0.0; + FNAV_omegadot_2 = 0.0; + FNAV_e_2 = 0.0; + FNAV_a12_2 = 0.0; + FNAV_omega0_2 = 0.0; + FNAV_idot_2 = 0.0; FNAV_WN_2 = 0; FNAV_TOW_2 = 0; // WORD 3 Ephemeris (2/3) and GST - FNAV_IODnav_3 = 0; - FNAV_i0_3 = 0; - FNAV_w_3 = 0; - FNAV_deltan_3 = 0; - FNAV_Cuc_3 = 0; - FNAV_Cus_3 = 0; - FNAV_Crc_3 = 0; - FNAV_Crs_3 = 0; + FNAV_IODnav_3 = -3; + FNAV_i0_3 = 0.0; + FNAV_w_3 = 0.0; + FNAV_deltan_3 = 0.0; + FNAV_Cuc_3 = 0.0; + FNAV_Cus_3 = 0.0; + FNAV_Crc_3 = 0.0; + FNAV_Crs_3 = 0.0; FNAV_t0e_3 = 0; FNAV_WN_3 = 0; FNAV_TOW_3 = 0; - /* WORD 4 Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW. - Note that the clock is repeated in this page type*/ - FNAV_IODnav_4 = 0; - FNAV_Cic_4 = 0; - FNAV_Cis_4 = 0; - FNAV_A0_4 = 0; - FNAV_A1_4 = 0; + // WORD 4 Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW. + // Note that the clock is repeated in this page type + FNAV_IODnav_4 = -4; + FNAV_Cic_4 = 0.0; + FNAV_Cis_4 = 0.0; + FNAV_A0_4 = 0.0; + FNAV_A1_4 = 0.0; FNAV_deltatls_4 = 0; FNAV_t0t_4 = 0; FNAV_WNot_4 = 0; @@ -127,8 +127,8 @@ void Galileo_Fnav_Message::reset() FNAV_DN_4 = 0; FNAV_deltatlsf_4 = 0; FNAV_t0g_4 = 0; - FNAV_A0g_4 = 0; - FNAV_A1g_4 = 0; + FNAV_A0g_4 = 0.0; + FNAV_A1g_4 = 0.0; FNAV_WN0g_4 = 0; FNAV_TOW_4 = 0; @@ -137,62 +137,51 @@ void Galileo_Fnav_Message::reset() FNAV_WNa_5 = 0; FNAV_t0a_5 = 0; FNAV_SVID1_5 = 0; - FNAV_Deltaa12_1_5 = 0; - FNAV_e_1_5 = 0; - FNAV_w_1_5 = 0; - FNAV_deltai_1_5 = 0; - FNAV_Omega0_1_5 = 0; - FNAV_Omegadot_1_5 = 0; - FNAV_M0_1_5 = 0; - FNAV_af0_1_5 = 0; - FNAV_af1_1_5 = 0; - FNAV_E5ahs_1_5 = 0; + FNAV_Deltaa12_1_5 = 0.0; + FNAV_e_1_5 = 0.0; + FNAV_w_1_5 = 0.0; + FNAV_deltai_1_5 = 0.0; + FNAV_Omega0_1_5 = 0.0; + FNAV_Omegadot_1_5 = 0.0; + FNAV_M0_1_5 = 0.0; + FNAV_af0_1_5 = 0.0; + FNAV_af1_1_5 = 0.0; + FNAV_E5ahs_1_5 = 0U; FNAV_SVID2_5 = 0; FNAV_Deltaa12_2_5 = 0; - FNAV_e_2_5 = 0; - FNAV_w_2_5 = 0; - FNAV_deltai_2_5 = 0; + FNAV_e_2_5 = 0.0; + FNAV_w_2_5 = 0.0; + FNAV_deltai_2_5 = 0.0; // WORD 6 Almanac (SVID2(2/2) and SVID3) FNAV_IODa_6 = 0; - FNAV_Omega0_2_6 = 0; - FNAV_Omegadot_2_6 = 0; - FNAV_M0_2_6 = 0; - FNAV_af0_2_6 = 0; - FNAV_af1_2_6 = 0; + FNAV_Omega0_2_6 = 0.0; + FNAV_Omegadot_2_6 = 0.0; + FNAV_M0_2_6 = 0.0; + FNAV_af0_2_6 = 0.0; + FNAV_af1_2_6 = 0.0; FNAV_E5ahs_2_6 = 0; FNAV_SVID3_6 = 0; - FNAV_Deltaa12_3_6 = 0; - FNAV_e_3_6 = 0; - FNAV_w_3_6 = 0; - FNAV_deltai_3_6 = 0; - FNAV_Omega0_3_6 = 0; - FNAV_Omegadot_3_6 = 0; - FNAV_M0_3_6 = 0; - FNAV_af0_3_6 = 0; - FNAV_af1_3_6 = 0; + FNAV_Deltaa12_3_6 = 0.0; + FNAV_e_3_6 = 0.0; + FNAV_w_3_6 = 0.0; + FNAV_deltai_3_6 = 0.0; + FNAV_Omega0_3_6 = 0.0; + FNAV_Omegadot_3_6 = 0.0; + FNAV_M0_3_6 = 0.0; + FNAV_af0_3_6 = 0.0; + FNAV_af1_3_6 = 0.0; FNAV_E5ahs_3_6 = 0; } + Galileo_Fnav_Message::Galileo_Fnav_Message() { reset(); } -//int Galileo_Fnav_Message::toInt(std::string bitString) -//{ -// int tempInt; -// int num=0; -// int sLength = bitString.length(); -// for(int i=0; i bits, boost::uint32_t checksum) +bool Galileo_Fnav_Message::_CRC_test(std::bitset bits, uint32_t checksum) { CRC_Galileo_FNAV_type CRC_Galileo; - boost::uint32_t crc_computed; + uint32_t crc_computed; // Galileo FNAV frame for CRC is not an integer multiple of bytes // it needs to be filled with zeroes at the start of the frame. // This operation is done in the transformation from bits to bytes // using boost::dynamic_bitset. // ToDo: Use boost::dynamic_bitset for all the bitset operations in this class - boost::dynamic_bitset frame_bits(std::string(bits.to_string())); + boost::dynamic_bitset frame_bits(std::string(bits.to_string())); - std::vector bytes; + std::vector bytes; boost::to_block_range(frame_bits, std::back_inserter(bytes)); std::reverse(bytes.begin(), bytes.end()); - CRC_Galileo.process_bytes( bytes.data(), GALILEO_FNAV_DATA_FRAME_BYTES ); + CRC_Galileo.process_bytes(bytes.data(), GALILEO_FNAV_DATA_FRAME_BYTES); crc_computed = CRC_Galileo.checksum(); if (checksum == crc_computed) { return true; } + + return false; +} + + +void Galileo_Fnav_Message::decode_page(const std::string& data) +{ + std::bitset data_bits(data); + page_type = read_navigation_unsigned(data_bits, FNAV_PAGE_TYPE_bit); + switch (page_type) + { + case 1: // SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal health and Data validity status + FNAV_SV_ID_PRN_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_SV_ID_PRN_1_bit)); + FNAV_IODnav_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_1_bit)); + FNAV_t0c_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0c_1_bit)); + FNAV_t0c_1 *= FNAV_t0c_1_LSB; + FNAV_af0_1 = static_cast(read_navigation_signed(data_bits, FNAV_af0_1_bit)); + FNAV_af0_1 *= FNAV_af0_1_LSB; + FNAV_af1_1 = static_cast(read_navigation_signed(data_bits, FNAV_af1_1_bit)); + FNAV_af1_1 *= FNAV_af1_1_LSB; + FNAV_af2_1 = static_cast(read_navigation_signed(data_bits, FNAV_af2_1_bit)); + FNAV_af2_1 *= FNAV_af2_1_LSB; + FNAV_SISA_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_SISA_1_bit)); + FNAV_ai0_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_ai0_1_bit)); + FNAV_ai0_1 *= FNAV_ai0_1_LSB; + FNAV_ai1_1 = static_cast(read_navigation_signed(data_bits, FNAV_ai1_1_bit)); + FNAV_ai1_1 *= FNAV_ai1_1_LSB; + FNAV_ai2_1 = static_cast(read_navigation_signed(data_bits, FNAV_ai2_1_bit)); + FNAV_ai2_1 *= FNAV_ai2_1_LSB; + FNAV_region1_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region1_1_bit)); + FNAV_region2_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region2_1_bit)); + FNAV_region3_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region3_1_bit)); + FNAV_region4_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region4_1_bit)); + FNAV_region5_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region5_1_bit)); + FNAV_BGD_1 = static_cast(read_navigation_signed(data_bits, FNAV_BGD_1_bit)); + FNAV_BGD_1 *= FNAV_BGD_1_LSB; + FNAV_E5ahs_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_1_bit)); + FNAV_WN_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_1_bit)); + FNAV_TOW_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_1_bit)); + FNAV_E5advs_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5advs_1_bit)); + flag_TOW_1 = true; + flag_TOW_set = true; + flag_iono_and_GST = true; // set to false externally + break; + case 2: // Ephemeris (1/3) and GST + FNAV_IODnav_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_2_bit)); + FNAV_M0_2 = static_cast(read_navigation_signed(data_bits, FNAV_M0_2_bit)); + FNAV_M0_2 *= FNAV_M0_2_LSB; + FNAV_omegadot_2 = static_cast(read_navigation_signed(data_bits, FNAV_omegadot_2_bit)); + FNAV_omegadot_2 *= FNAV_omegadot_2_LSB; + FNAV_e_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_2_bit)); + FNAV_e_2 *= FNAV_e_2_LSB; + FNAV_a12_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_a12_2_bit)); + FNAV_a12_2 *= FNAV_a12_2_LSB; + FNAV_omega0_2 = static_cast(read_navigation_signed(data_bits, FNAV_omega0_2_bit)); + FNAV_omega0_2 *= FNAV_omega0_2_LSB; + FNAV_idot_2 = static_cast(read_navigation_signed(data_bits, FNAV_idot_2_bit)); + FNAV_idot_2 *= FNAV_idot_2_LSB; + FNAV_WN_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_2_bit)); + FNAV_TOW_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_2_bit)); + flag_TOW_2 = true; + flag_TOW_set = true; + flag_ephemeris_1 = true; + break; + case 3: // Ephemeris (2/3) and GST + FNAV_IODnav_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_3_bit)); + FNAV_i0_3 = static_cast(read_navigation_signed(data_bits, FNAV_i0_3_bit)); + FNAV_i0_3 *= FNAV_i0_3_LSB; + FNAV_w_3 = static_cast(read_navigation_signed(data_bits, FNAV_w_3_bit)); + FNAV_w_3 *= FNAV_w_3_LSB; + FNAV_deltan_3 = static_cast(read_navigation_signed(data_bits, FNAV_deltan_3_bit)); + FNAV_deltan_3 *= FNAV_deltan_3_LSB; + FNAV_Cuc_3 = static_cast(read_navigation_signed(data_bits, FNAV_Cuc_3_bit)); + FNAV_Cuc_3 *= FNAV_Cuc_3_LSB; + FNAV_Cus_3 = static_cast(read_navigation_signed(data_bits, FNAV_Cus_3_bit)); + FNAV_Cus_3 *= FNAV_Cus_3_LSB; + FNAV_Crc_3 = static_cast(read_navigation_signed(data_bits, FNAV_Crc_3_bit)); + FNAV_Crc_3 *= FNAV_Crc_3_LSB; + FNAV_Crs_3 = static_cast(read_navigation_signed(data_bits, FNAV_Crs_3_bit)); + FNAV_Crs_3 *= FNAV_Crs_3_LSB; + FNAV_t0e_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0e_3_bit)); + FNAV_t0e_3 *= FNAV_t0e_3_LSB; + FNAV_WN_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_3_bit)); + FNAV_TOW_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_3_bit)); + flag_TOW_3 = true; + flag_TOW_set = true; + flag_ephemeris_2 = true; + break; + case 4: // Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW + FNAV_IODnav_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_4_bit)); + FNAV_Cic_4 = static_cast(read_navigation_signed(data_bits, FNAV_Cic_4_bit)); + FNAV_Cic_4 *= FNAV_Cic_4_LSB; + FNAV_Cis_4 = static_cast(read_navigation_signed(data_bits, FNAV_Cis_4_bit)); + FNAV_Cis_4 *= FNAV_Cis_4_LSB; + FNAV_A0_4 = static_cast(read_navigation_signed(data_bits, FNAV_A0_4_bit)); + FNAV_A0_4 *= FNAV_A0_4_LSB; + FNAV_A1_4 = static_cast(read_navigation_signed(data_bits, FNAV_A1_4_bit)); + FNAV_A1_4 *= FNAV_A1_4_LSB; + FNAV_deltatls_4 = static_cast(read_navigation_signed(data_bits, FNAV_deltatls_4_bit)); + FNAV_t0t_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0t_4_bit)); + FNAV_t0t_4 *= FNAV_t0t_4_LSB; + FNAV_WNot_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNot_4_bit)); + FNAV_WNlsf_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNlsf_4_bit)); + FNAV_DN_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_DN_4_bit)); + FNAV_deltatlsf_4 = static_cast(read_navigation_signed(data_bits, FNAV_deltatlsf_4_bit)); + FNAV_t0g_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0g_4_bit)); + FNAV_t0g_4 *= FNAV_t0g_4_LSB; + FNAV_A0g_4 = static_cast(read_navigation_signed(data_bits, FNAV_A0g_4_bit)); + FNAV_A0g_4 *= FNAV_A0g_4_LSB; + FNAV_A1g_4 = static_cast(read_navigation_signed(data_bits, FNAV_A1g_4_bit)); + FNAV_A1g_4 *= FNAV_A1g_4_LSB; + FNAV_WN0g_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN0g_4_bit)); + FNAV_TOW_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_4_bit)); + flag_TOW_4 = true; + flag_TOW_set = true; + flag_ephemeris_3 = true; + flag_utc_model = true; // set to false externally + break; + case 5: // Almanac (SVID1 and SVID2(1/2)), Week Number and almanac reference time + FNAV_IODa_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODa_5_bit)); + FNAV_WNa_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNa_5_bit)); + FNAV_t0a_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0a_5_bit)); + FNAV_t0a_5 *= FNAV_t0a_5_LSB; + FNAV_SVID1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID1_5_bit)); + FNAV_Deltaa12_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_1_5_bit)); + FNAV_Deltaa12_1_5 *= FNAV_Deltaa12_5_LSB; + FNAV_e_1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_1_5_bit)); + FNAV_e_1_5 *= FNAV_e_5_LSB; + FNAV_w_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_w_1_5_bit)); + FNAV_w_1_5 *= FNAV_w_5_LSB; + FNAV_deltai_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_1_5_bit)); + FNAV_deltai_1_5 *= FNAV_deltai_5_LSB; + FNAV_Omega0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Omega0_1_5_bit)); + FNAV_Omega0_1_5 *= FNAV_Omega0_5_LSB; + FNAV_Omegadot_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_1_5_bit)); + FNAV_Omegadot_1_5 *= FNAV_Omegadot_5_LSB; + FNAV_M0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_M0_1_5_bit)); + FNAV_M0_1_5 *= FNAV_M0_5_LSB; + FNAV_af0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_af0_1_5_bit)); + FNAV_af0_1_5 *= FNAV_af0_5_LSB; + FNAV_af1_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_af1_1_5_bit)); + FNAV_af1_1_5 *= FNAV_af1_5_LSB; + FNAV_E5ahs_1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_1_5_bit)); + FNAV_SVID2_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID2_5_bit)); + FNAV_Deltaa12_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_2_5_bit)); + FNAV_Deltaa12_2_5 *= FNAV_Deltaa12_5_LSB; + FNAV_e_2_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_2_5_bit)); + FNAV_e_2_5 *= FNAV_e_5_LSB; + FNAV_w_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_w_2_5_bit)); + FNAV_w_2_5 *= FNAV_w_5_LSB; + FNAV_deltai_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_2_5_bit)); + FNAV_deltai_2_5 *= FNAV_deltai_5_LSB; + //TODO check this + // Omega0_2 must be decoded when the two pieces are joined + omega0_1 = data.substr(210, 4); + //omega_flag=true; + // + //FNAV_Omega012_2_5=static_cast(read_navigation_signed(data_bits, FNAV_Omega012_2_5_bit); + flag_almanac_1 = true; + break; + case 6: // Almanac (SVID2(2/2) and SVID3) + FNAV_IODa_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODa_6_bit)); + // Don't worry about omega pieces. If page 5 has not been received, all_ephemeris + // flag will be set to false and the data won't be recorded.*/ + std::string omega0_2 = data.substr(10, 12); + std::string Omega0 = omega0_1 + omega0_2; + std::bitset omega_bits(Omega0); + const std::vector> om_bit({{0, 12}}); + FNAV_Omega0_2_6 = static_cast(read_navigation_signed(omega_bits, om_bit)); + FNAV_Omega0_2_6 *= FNAV_Omega0_5_LSB; + FNAV_Omegadot_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_2_6_bit)); + FNAV_Omegadot_2_6 *= FNAV_Omegadot_5_LSB; + FNAV_M0_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_M0_2_6_bit)); + FNAV_M0_2_6 *= FNAV_M0_5_LSB; + FNAV_af0_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_af0_2_6_bit)); + FNAV_af0_2_6 *= FNAV_af0_5_LSB; + FNAV_af1_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_af1_2_6_bit)); + FNAV_af1_2_6 *= FNAV_af1_5_LSB; + FNAV_E5ahs_2_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_2_6_bit)); + FNAV_SVID3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID3_6_bit)); + FNAV_Deltaa12_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_3_6_bit)); + FNAV_Deltaa12_3_6 *= FNAV_Deltaa12_5_LSB; + FNAV_e_3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_3_6_bit)); + FNAV_e_3_6 *= FNAV_e_5_LSB; + FNAV_w_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_w_3_6_bit)); + FNAV_w_3_6 *= FNAV_w_5_LSB; + FNAV_deltai_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_3_6_bit)); + FNAV_deltai_3_6 *= FNAV_deltai_5_LSB; + FNAV_Omega0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omega0_3_6_bit)); + FNAV_Omega0_3_6 *= FNAV_Omega0_5_LSB; + FNAV_Omegadot_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_3_6_bit)); + FNAV_Omegadot_3_6 *= FNAV_Omegadot_5_LSB; + FNAV_M0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_M0_3_6_bit)); + FNAV_M0_3_6 *= FNAV_M0_5_LSB; + FNAV_af0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_af0_3_6_bit)); + FNAV_af0_3_6 *= FNAV_af0_5_LSB; + FNAV_af1_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_af1_3_6_bit)); + FNAV_af1_3_6 *= FNAV_af1_5_LSB; + FNAV_E5ahs_3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_3_6_bit)); + + flag_almanac_2 = true; + break; + } +} + + +uint64_t Galileo_Fnav_Message::read_navigation_unsigned(std::bitset bits, const std::vector>& parameter) +{ + uint64_t value = 0ULL; + int num_of_slices = parameter.size(); + for (int i = 0; i < num_of_slices; i++) + { + for (int j = 0; j < parameter[i].second; j++) + { + value <<= 1; // shift left + if (static_cast(bits[GALILEO_FNAV_DATA_FRAME_BITS - parameter[i].first - j]) == 1) + { + value += 1; // insert the bit + } + } + } + return value; +} + + +int64_t Galileo_Fnav_Message::read_navigation_signed(std::bitset bits, const std::vector>& parameter) +{ + int64_t value = 0LL; + int num_of_slices = parameter.size(); + + // read the MSB and perform the sign extension + if (static_cast(bits[GALILEO_FNAV_DATA_FRAME_BITS - parameter[0].first]) == 1) + { + value ^= 0x0FFFFFFFFFFFFFFF; // 64 bits variable + } + else + { + value &= 0; + } + + for (int i = 0; i < num_of_slices; i++) + { + for (int j = 0; j < parameter[i].second; j++) + { + value <<= 1; // shift left + value &= 0xFFFFFFFFFFFFFFFE; // reset the corresponding bit (for the 64 bits variable) + if (static_cast(bits[GALILEO_FNAV_DATA_FRAME_BITS - parameter[i].first - j]) == 1) + { + value += 1; // insert the bit + } + } + } + return value; +} + + +bool Galileo_Fnav_Message::have_new_ephemeris() // Check if we have a new ephemeris stored in the galileo navigation class +{ + if ((flag_ephemeris_1 == true) and (flag_ephemeris_2 == true) and (flag_ephemeris_3 == true) and (flag_iono_and_GST == true)) + { + // if all ephemeris pages have the same IOD, then they belong to the same block + if ((FNAV_IODnav_1 == FNAV_IODnav_2) and (FNAV_IODnav_3 == FNAV_IODnav_4) and (FNAV_IODnav_1 == FNAV_IODnav_3)) + { + std::cout << "Ephemeris (1, 2, 3) have been received and belong to the same batch" << std::endl; + flag_ephemeris_1 = false; // clear the flag + flag_ephemeris_2 = false; // clear the flag + flag_ephemeris_3 = false; // clear the flag + flag_all_ephemeris = true; + IOD_ephemeris = FNAV_IODnav_1; + std::cout << "Batch number: " << IOD_ephemeris << std::endl; + return true; + } + } + return false; +} + + +bool Galileo_Fnav_Message::have_new_iono_and_GST() // Check if we have a new iono data set stored in the galileo navigation class +{ + if ((flag_iono_and_GST == true) and (flag_utc_model == true)) // the condition on flag_utc_model is added to have a time stamp for iono + { + flag_iono_and_GST = false; // clear the flag + } else { return false; } + return true; } -void Galileo_Fnav_Message::decode_page(std::string data) -{ - std::bitset data_bits(data); - page_type = read_navigation_unsigned(data_bits, FNAV_PAGE_TYPE_bit); - switch(page_type) - { - case 1: // SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal health and Data validity status - FNAV_SV_ID_PRN_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_SV_ID_PRN_1_bit)); - FNAV_IODnav_1 =static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_1_bit)); - FNAV_t0c_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0c_1_bit)); - FNAV_t0c_1 *= FNAV_t0c_1_LSB; - FNAV_af0_1 = static_cast(read_navigation_signed(data_bits, FNAV_af0_1_bit)); - FNAV_af0_1 *= FNAV_af0_1_LSB; - FNAV_af1_1 = static_cast(read_navigation_signed(data_bits, FNAV_af1_1_bit)); - FNAV_af1_1 *= FNAV_af1_1_LSB; - FNAV_af2_1 = static_cast(read_navigation_signed(data_bits, FNAV_af2_1_bit)); - FNAV_af2_1 *= FNAV_af2_1_LSB; - FNAV_SISA_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_SISA_1_bit)); - FNAV_ai0_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_ai0_1_bit)); - FNAV_ai0_1 *= FNAV_ai0_1_LSB; - FNAV_ai1_1 = static_cast(read_navigation_signed(data_bits, FNAV_ai1_1_bit)); - FNAV_ai1_1 *= FNAV_ai1_1_LSB; - FNAV_ai2_1 = static_cast(read_navigation_signed(data_bits, FNAV_ai2_1_bit)); - FNAV_ai2_1 *= FNAV_ai2_1_LSB; - FNAV_region1_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region1_1_bit)); - FNAV_region2_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region2_1_bit)); - FNAV_region3_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region3_1_bit)); - FNAV_region4_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region4_1_bit)); - FNAV_region5_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_region5_1_bit)); - FNAV_BGD_1 = static_cast(read_navigation_signed(data_bits, FNAV_BGD_1_bit)); - FNAV_BGD_1 *= FNAV_BGD_1_LSB; - FNAV_E5ahs_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_1_bit)); - FNAV_WN_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_1_bit)); - FNAV_TOW_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_1_bit)); - FNAV_E5advs_1 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5advs_1_bit)); - - flag_TOW_1 = true; - flag_TOW_set = true; - flag_iono_and_GST = true; //set to false externally - break; - case 2: // Ephemeris (1/3) and GST - FNAV_IODnav_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_2_bit)); - FNAV_M0_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_M0_2_bit)); - FNAV_M0_2 *= FNAV_M0_2_LSB; - FNAV_omegadot_2 = static_cast(read_navigation_signed(data_bits, FNAV_omegadot_2_bit)); - FNAV_omegadot_2 *= FNAV_omegadot_2_LSB; - FNAV_e_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_2_bit)); - FNAV_e_2 *= FNAV_e_2_LSB; - FNAV_a12_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_a12_2_bit)); - FNAV_a12_2 *= FNAV_a12_2_LSB; - FNAV_omega0_2 = static_cast(read_navigation_signed(data_bits, FNAV_omega0_2_bit)); - FNAV_omega0_2 *= FNAV_omega0_2_LSB; - FNAV_idot_2 = static_cast(read_navigation_signed(data_bits, FNAV_idot_2_bit)); - FNAV_idot_2 *= FNAV_idot_2_LSB; - FNAV_WN_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_2_bit)); - FNAV_TOW_2 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_2_bit)); - - flag_TOW_2 = true; - flag_TOW_set = true; - flag_ephemeris_1 = true; - break; - case 3: // Ephemeris (2/3) and GST - FNAV_IODnav_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_3_bit)); - FNAV_i0_3 = static_cast(read_navigation_signed(data_bits, FNAV_i0_3_bit)); - FNAV_i0_3 *= FNAV_i0_3_LSB; - FNAV_w_3=static_cast(read_navigation_signed(data_bits, FNAV_w_3_bit)); - FNAV_w_3 *= FNAV_w_3_LSB; - FNAV_deltan_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_deltan_3_bit)); - FNAV_deltan_3 *= FNAV_deltan_3_LSB; - FNAV_Cuc_3 = static_cast(read_navigation_signed(data_bits, FNAV_Cuc_3_bit)); - FNAV_Cuc_3 *= FNAV_Cuc_3_LSB; - FNAV_Cus_3 = static_cast(read_navigation_signed(data_bits, FNAV_Cus_3_bit)); - FNAV_Cus_3 *= FNAV_Cus_3_LSB; - FNAV_Crc_3 = static_cast(read_navigation_signed(data_bits, FNAV_Crc_3_bit)); - FNAV_Crc_3 *= FNAV_Crc_3_LSB; - FNAV_Crs_3 = static_cast(read_navigation_signed(data_bits, FNAV_Crs_3_bit)); - FNAV_Crs_3 *= FNAV_Crs_3_LSB; - FNAV_t0e_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0e_3_bit)); - FNAV_t0e_3 *= FNAV_t0e_3_LSB; - FNAV_WN_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN_3_bit)); - FNAV_TOW_3 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_3_bit)); - - flag_TOW_3 = true; - flag_TOW_set = true; - flag_ephemeris_2 = true; - break; - case 4: // Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW - FNAV_IODnav_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODnav_4_bit)); - FNAV_Cic_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_Cic_4_bit)); - FNAV_Cic_4 *= FNAV_Cic_4_LSB; - FNAV_Cis_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_Cis_4_bit)); - FNAV_Cis_4 *= FNAV_Cis_4_LSB; - FNAV_A0_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_A0_4_bit)); - FNAV_A0_4 *= FNAV_A0_4_LSB; - FNAV_A1_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_A1_4_bit)); - FNAV_A1_4 *= FNAV_A1_4_LSB; - FNAV_deltatls_4 = static_cast(read_navigation_signed(data_bits, FNAV_deltatls_4_bit)); - FNAV_t0t_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0t_4_bit)); - FNAV_t0t_4 *= FNAV_t0t_4_LSB; - FNAV_WNot_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNot_4_bit)); - FNAV_WNlsf_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNlsf_4_bit)); - FNAV_DN_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_DN_4_bit)); - FNAV_deltatlsf_4 = static_cast(read_navigation_signed(data_bits, FNAV_deltatlsf_4_bit)); - FNAV_t0g_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0g_4_bit)); - FNAV_t0g_4 *= FNAV_t0g_4_LSB; - FNAV_A0g_4 = static_cast(read_navigation_signed(data_bits, FNAV_A0g_4_bit)); - FNAV_A0g_4 *= FNAV_A0g_4_LSB; - FNAV_A1g_4 = static_cast(read_navigation_signed(data_bits, FNAV_A1g_4_bit)); - FNAV_A1g_4 *= FNAV_A1g_4_LSB; - FNAV_WN0g_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_WN0g_4_bit)); - FNAV_TOW_4 = static_cast(read_navigation_unsigned(data_bits, FNAV_TOW_4_bit)); - - flag_TOW_4 = true; - flag_TOW_set = true; - flag_ephemeris_3 = true; - flag_utc_model = true; //set to false externally - break; - case 5: // Almanac (SVID1 and SVID2(1/2)), Week Number and almanac reference time - FNAV_IODa_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODa_5_bit)); - FNAV_WNa_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_WNa_5_bit)); - FNAV_t0a_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_t0a_5_bit)); - FNAV_t0a_5 *= FNAV_t0a_5_LSB; - FNAV_SVID1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID1_5_bit)); - FNAV_Deltaa12_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_1_5_bit)); - FNAV_Deltaa12_1_5 *= FNAV_Deltaa12_5_LSB; - FNAV_e_1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_1_5_bit)); - FNAV_e_1_5 *= FNAV_e_5_LSB; - FNAV_w_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_w_1_5_bit)); - FNAV_w_1_5 *= FNAV_w_5_LSB; - FNAV_deltai_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_1_5_bit)); - FNAV_deltai_1_5 *= FNAV_deltai_5_LSB; - FNAV_Omega0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Omega0_1_5_bit)); - FNAV_Omega0_1_5 *= FNAV_Omega0_5_LSB; - FNAV_Omegadot_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_1_5_bit)); - FNAV_Omegadot_1_5 *= FNAV_Omegadot_5_LSB; - FNAV_M0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_M0_1_5_bit)); - FNAV_M0_1_5 *= FNAV_M0_5_LSB; - FNAV_af0_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_af0_1_5_bit)); - FNAV_af0_1_5 *= FNAV_af0_5_LSB; - FNAV_af1_1_5 = static_cast(read_navigation_signed(data_bits, FNAV_af1_1_5_bit)); - FNAV_af1_1_5 *= FNAV_af1_5_LSB; - FNAV_E5ahs_1_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_1_5_bit)); - FNAV_SVID2_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID2_5_bit)); - FNAV_Deltaa12_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_2_5_bit)); - FNAV_Deltaa12_2_5 *= FNAV_Deltaa12_5_LSB; - FNAV_e_2_5 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_2_5_bit)); - FNAV_e_2_5 *= FNAV_e_5_LSB; - FNAV_w_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_w_2_5_bit)); - FNAV_w_2_5 *= FNAV_w_5_LSB; - FNAV_deltai_2_5 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_2_5_bit)); - FNAV_deltai_2_5 *= FNAV_deltai_5_LSB; - //TODO check this - // Omega0_2 must be decoded when the two pieces are joined - omega0_1 = data.substr(210, 4); - //omega_flag=true; - // - //FNAV_Omega012_2_5=static_cast(read_navigation_signed(data_bits, FNAV_Omega012_2_5_bit); - - flag_almanac_1 = true; - break; - case 6: // Almanac (SVID2(2/2) and SVID3) - FNAV_IODa_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_IODa_6_bit)); - - /* Don't worry about omega pieces. If page 5 has not been received, all_ephemeris - * flag will be set to false and the data won't be recorded.*/ - std::string omega0_2 = data.substr(10, 12); - std::string Omega0 = omega0_1 + omega0_2; - std::bitset omega_bits(Omega0); - const std::vector> om_bit({{0, 12}}); - FNAV_Omega0_2_6 = static_cast(read_navigation_signed(omega_bits, om_bit)); - FNAV_Omega0_2_6 *= FNAV_Omega0_5_LSB; - // - FNAV_Omegadot_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_2_6_bit)); - FNAV_Omegadot_2_6 *= FNAV_Omegadot_5_LSB; - FNAV_M0_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_M0_2_6_bit)); - FNAV_M0_2_6 *= FNAV_M0_5_LSB; - FNAV_af0_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_af0_2_6_bit)); - FNAV_af0_2_6 *= FNAV_af0_5_LSB; - FNAV_af1_2_6 = static_cast(read_navigation_signed(data_bits, FNAV_af1_2_6_bit)); - FNAV_af1_2_6 *= FNAV_af1_5_LSB; - FNAV_E5ahs_2_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_2_6_bit)); - FNAV_SVID3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_SVID3_6_bit)); - FNAV_Deltaa12_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Deltaa12_3_6_bit)); - FNAV_Deltaa12_3_6 *= FNAV_Deltaa12_5_LSB; - FNAV_e_3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_e_3_6_bit)); - FNAV_e_3_6 *= FNAV_e_5_LSB; - FNAV_w_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_w_3_6_bit)); - FNAV_w_3_6 *= FNAV_w_5_LSB; - FNAV_deltai_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_deltai_3_6_bit)); - FNAV_deltai_3_6 *= FNAV_deltai_5_LSB; - FNAV_Omega0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omega0_3_6_bit)); - FNAV_Omega0_3_6 *= FNAV_Omega0_5_LSB; - FNAV_Omegadot_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_Omegadot_3_6_bit)); - FNAV_Omegadot_3_6 *= FNAV_Omegadot_5_LSB; - FNAV_M0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_M0_3_6_bit)); - FNAV_M0_3_6 *= FNAV_M0_5_LSB; - FNAV_af0_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_af0_3_6_bit)); - FNAV_af0_3_6 *= FNAV_af0_5_LSB; - FNAV_af1_3_6 = static_cast(read_navigation_signed(data_bits, FNAV_af1_3_6_bit)); - FNAV_af1_3_6 *= FNAV_af1_5_LSB; - FNAV_E5ahs_3_6 = static_cast(read_navigation_unsigned(data_bits, FNAV_E5ahs_3_6_bit)); - - flag_almanac_2 = true; - break; - } -} - - -unsigned long int Galileo_Fnav_Message::read_navigation_unsigned(std::bitset bits, const std::vector> parameter) -{ - unsigned long int value = 0; - int num_of_slices = parameter.size(); - for (int i=0; i bits, const std::vector> parameter) -{ - signed long int value = 0; - int num_of_slices = parameter.size(); - // Discriminate between 64 bits and 32 bits compiler - int long_int_size_bytes = sizeof(signed long int); - if (long_int_size_bytes == 8) // if a long int takes 8 bytes, we are in a 64 bits system - { - // read the MSB and perform the sign extension - if (bits[GALILEO_FNAV_DATA_FRAME_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFFFFFFFFFF; //64 bits variable - } - else - { - value &= 0; - } - - for (int i=0; i. + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -38,16 +38,16 @@ #define GNSS_SDR_GALILEO_FNAV_MESSAGE_H_ -#include -#include -#include -#include -#include // for boost::uint16_t +#include "Galileo_E5a.h" +#include "galileo_almanac_helper.h" #include "galileo_ephemeris.h" #include "galileo_iono.h" -#include "galileo_almanac.h" #include "galileo_utc_model.h" -#include "Galileo_E5a.h" +#include +#include +#include +#include +#include /*! * \brief This class handles the Galileo F/NAV Data message, as described in the @@ -57,18 +57,7 @@ class Galileo_Fnav_Message { public: -// void Galileo_Fnav_Message::split_page(std::string page_string); -// void Galileo_Fnav_Message::reset(); -// bool Galileo_Fnav_Message::have_new_ephemeris(); -// bool Galileo_Fnav_Message::have_new_iono_and_GST(); -// bool Galileo_Fnav_Message::have_new_utc_model(); -// bool Galileo_Fnav_Message::have_new_almanac(); -// Galileo_Ephemeris Galileo_Fnav_Message::get_ephemeris(); -// Galileo_Iono Galileo_Fnav_Message::get_iono(); -// Galileo_Utc_Model Galileo_Fnav_Message::get_utc_model(); -// Galileo_Almanac Galileo_Fnav_Message::get_almanac(); - // - void split_page(std::string page_string); + void split_page(const std::string& page_string); void reset(); bool have_new_ephemeris(); bool have_new_iono_and_GST(); @@ -77,7 +66,7 @@ public: Galileo_Ephemeris get_ephemeris(); Galileo_Iono get_iono(); Galileo_Utc_Model get_utc_model(); - Galileo_Almanac get_almanac(); + Galileo_Almanac_Helper get_almanac(); Galileo_Fnav_Message(); @@ -87,30 +76,30 @@ public: bool flag_ephemeris_2; //!< Flag indicating that ephemeris 2/3 (word 3) have been received bool flag_ephemeris_3; //!< Flag indicating that ephemeris 3/3 (word 4) have been received - bool flag_iono_and_GST; //!< Flag indicating that ionospheric and GST parameters (word 1) have been received + bool flag_iono_and_GST; //!< Flag indicating that ionospheric and GST parameters (word 1) have been received bool flag_TOW_1; bool flag_TOW_2; bool flag_TOW_3; bool flag_TOW_4; - bool flag_TOW_set; //!< it is true when page 1,2,3 or 4 arrives - bool flag_utc_model; //!< Flag indicating that utc model parameters (word 4) have been received + bool flag_TOW_set; //!< it is true when page 1,2,3 or 4 arrives + bool flag_utc_model; //!< Flag indicating that utc model parameters (word 4) have been received - bool flag_all_almanac; //!< Flag indicating that all almanac have been received - bool flag_almanac_1; //!< Flag indicating that almanac 1/2 (word 5) have been received - bool flag_almanac_2; //!< Flag indicating that almanac 2/2 (word 6) have been received + bool flag_all_almanac; //!< Flag indicating that all almanac have been received + bool flag_almanac_1; //!< Flag indicating that almanac 1/2 (word 5) have been received + bool flag_almanac_2; //!< Flag indicating that almanac 2/2 (word 6) have been received - int IOD_ephemeris; + int32_t IOD_ephemeris; - int page_type; - /* WORD 1 SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal - * health and Data validity status*/ - int FNAV_SV_ID_PRN_1; - int FNAV_IODnav_1; - double FNAV_t0c_1; + int32_t page_type; + // WORD 1 SVID, Clock correction, SISA, Ionospheric correction, BGD, GST, Signal + // health and Data validity status + int32_t FNAV_SV_ID_PRN_1; + int32_t FNAV_IODnav_1; + int32_t FNAV_t0c_1; double FNAV_af0_1; double FNAV_af1_1; double FNAV_af2_1; - double FNAV_SISA_1; + int32_t FNAV_SISA_1; double FNAV_ai0_1; double FNAV_ai1_1; double FNAV_ai2_1; @@ -120,24 +109,24 @@ public: bool FNAV_region4_1; bool FNAV_region5_1; double FNAV_BGD_1; - double FNAV_E5ahs_1; - double FNAV_WN_1; - double FNAV_TOW_1; + int32_t FNAV_E5ahs_1; + int32_t FNAV_WN_1; + int32_t FNAV_TOW_1; bool FNAV_E5advs_1; // WORD 2 Ephemeris (1/3) and GST - int FNAV_IODnav_2; + int32_t FNAV_IODnav_2; double FNAV_M0_2; double FNAV_omegadot_2; double FNAV_e_2; double FNAV_a12_2; double FNAV_omega0_2; double FNAV_idot_2; - double FNAV_WN_2; - double FNAV_TOW_2; + int32_t FNAV_WN_2; + int32_t FNAV_TOW_2; // WORD 3 Ephemeris (2/3) and GST - int FNAV_IODnav_3; + int32_t FNAV_IODnav_3; double FNAV_i0_3; double FNAV_w_3; double FNAV_deltan_3; @@ -145,34 +134,34 @@ public: double FNAV_Cus_3; double FNAV_Crc_3; double FNAV_Crs_3; - double FNAV_t0e_3; - double FNAV_WN_3; - double FNAV_TOW_3; + int32_t FNAV_t0e_3; + int32_t FNAV_WN_3; + int32_t FNAV_TOW_3; - /* WORD 4 Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW. - Note that the clock is repeated in this page type*/ - int FNAV_IODnav_4; + // WORD 4 Ephemeris (3/3), GST-UTC conversion, GST-GPS conversion and TOW. + // Note that the clock is repeated in this page type + int32_t FNAV_IODnav_4; double FNAV_Cic_4; double FNAV_Cis_4; double FNAV_A0_4; double FNAV_A1_4; - double FNAV_deltatls_4; - double FNAV_t0t_4; - double FNAV_WNot_4; - double FNAV_WNlsf_4; - double FNAV_DN_4; - double FNAV_deltatlsf_4; - double FNAV_t0g_4; + int32_t FNAV_deltatls_4; + int32_t FNAV_t0t_4; + int32_t FNAV_WNot_4; + int32_t FNAV_WNlsf_4; + int32_t FNAV_DN_4; + int32_t FNAV_deltatlsf_4; + int32_t FNAV_t0g_4; double FNAV_A0g_4; double FNAV_A1g_4; - double FNAV_WN0g_4; - double FNAV_TOW_4; + int32_t FNAV_WN0g_4; + int32_t FNAV_TOW_4; // WORD 5 Almanac (SVID1 and SVID2(1/2)), Week Number and almanac reference time - int FNAV_IODa_5; - double FNAV_WNa_5; - double FNAV_t0a_5; - int FNAV_SVID1_5; + int32_t FNAV_IODa_5; + int32_t FNAV_WNa_5; + int32_t FNAV_t0a_5; + int32_t FNAV_SVID1_5; double FNAV_Deltaa12_1_5; double FNAV_e_1_5; double FNAV_w_1_5; @@ -182,22 +171,22 @@ public: double FNAV_M0_1_5; double FNAV_af0_1_5; double FNAV_af1_1_5; - unsigned int FNAV_E5ahs_1_5; - int FNAV_SVID2_5; + uint32_t FNAV_E5ahs_1_5; + int32_t FNAV_SVID2_5; double FNAV_Deltaa12_2_5; double FNAV_e_2_5; double FNAV_w_2_5; double FNAV_deltai_2_5; // WORD 6 Almanac (SVID2(2/2) and SVID3) - int FNAV_IODa_6; + int32_t FNAV_IODa_6; double FNAV_Omega0_2_6; double FNAV_Omegadot_2_6; double FNAV_M0_2_6; double FNAV_af0_2_6; double FNAV_af1_2_6; - double FNAV_E5ahs_2_6; - int FNAV_SVID3_6; + int32_t FNAV_E5ahs_2_6; + int32_t FNAV_SVID3_6; double FNAV_Deltaa12_3_6; double FNAV_e_3_6; double FNAV_w_3_6; @@ -207,15 +196,13 @@ public: double FNAV_M0_3_6; double FNAV_af0_3_6; double FNAV_af1_3_6; - double FNAV_E5ahs_3_6; - - + int32_t FNAV_E5ahs_3_6; private: - bool _CRC_test(std::bitset bits,boost::uint32_t checksum); - void decode_page(std::string data); - unsigned long int read_navigation_unsigned(std::bitset bits, const std::vector> parameter); - signed long int read_navigation_signed(std::bitset bits, const std::vector> parameter); + bool _CRC_test(std::bitset bits, uint32_t checksum); + void decode_page(const std::string& data); + uint64_t read_navigation_unsigned(std::bitset bits, const std::vector>& parameter); + int64_t read_navigation_signed(std::bitset bits, const std::vector>& parameter); std::string omega0_1; //std::string omega0_2; diff --git a/src/core/system_parameters/galileo_iono.cc b/src/core/system_parameters/galileo_iono.cc index 6faad8897..440abbc44 100644 --- a/src/core/system_parameters/galileo_iono.cc +++ b/src/core/system_parameters/galileo_iono.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,19 +33,18 @@ Galileo_Iono::Galileo_Iono() { - /* Ionospheric correction */ - ai0_5 = 0; // Effective Ionisation Level 1st order parameter [sfu] - ai1_5 = 0; // Effective Ionisation Level 2st order parameter [sfu/degree] - ai2_5 = 0; // Effective Ionisation Level 3st order parameter [sfu/degree] + // Ionospheric correction + ai0_5 = 0.0; // Effective Ionisation Level 1st order parameter [sfu] + ai1_5 = 0.0; // Effective Ionisation Level 2st order parameter [sfu/degree] + ai2_5 = 0.0; // Effective Ionisation Level 3st order parameter [sfu/degree] - /* Ionospheric disturbance flag */ - Region1_flag_5 = false; // Ionospheric Disturbance Flag for region 1 - Region2_flag_5 = false; // Ionospheric Disturbance Flag for region 2 - Region3_flag_5 = false; // Ionospheric Disturbance Flag for region 3 - Region4_flag_5 = false; // Ionospheric Disturbance Flag for region 4 - Region5_flag_5 = false; // Ionospheric Disturbance Flag for region 5 + // Ionospheric disturbance flag + Region1_flag_5 = false; // Ionospheric Disturbance Flag for region 1 + Region2_flag_5 = false; // Ionospheric Disturbance Flag for region 2 + Region3_flag_5 = false; // Ionospheric Disturbance Flag for region 3 + Region4_flag_5 = false; // Ionospheric Disturbance Flag for region 4 + Region5_flag_5 = false; // Ionospheric Disturbance Flag for region 5 TOW_5 = 0; WN_5 = 0; } - diff --git a/src/core/system_parameters/galileo_iono.h b/src/core/system_parameters/galileo_iono.h index 15bed90e7..ab36199c0 100644 --- a/src/core/system_parameters/galileo_iono.h +++ b/src/core/system_parameters/galileo_iono.h @@ -5,7 +5,7 @@ * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,6 +32,7 @@ #ifndef GNSS_SDR_GALILEO_IONO_H_ #define GNSS_SDR_GALILEO_IONO_H_ +#include /*! * \brief This class is a storage for the GALILEO IONOSPHERIC data as described in Galileo ICD paragraph 5.1.6 @@ -41,26 +42,50 @@ class Galileo_Iono { public: - /*Ionospheric correction*/ - double ai0_5; //!< Effective Ionisation Level 1st order parameter [sfu] - double ai1_5; //!< Effective Ionisation Level 2st order parameter [sfu/degree] - double ai2_5; //!< Effective Ionisation Level 3st order parameter [sfu/degree] + // Ionospheric correction + double ai0_5; //!< Effective Ionisation Level 1st order parameter [sfu] + double ai1_5; //!< Effective Ionisation Level 2st order parameter [sfu/degree] + double ai2_5; //!< Effective Ionisation Level 3st order parameter [sfu/degree] - /*Ionospheric disturbance flag*/ - bool Region1_flag_5; //!< Ionospheric Disturbance Flag for region 1 - bool Region2_flag_5; //!< Ionospheric Disturbance Flag for region 2 - bool Region3_flag_5; //!< Ionospheric Disturbance Flag for region 3 - bool Region4_flag_5; //!< Ionospheric Disturbance Flag for region 4 - bool Region5_flag_5; //!< Ionospheric Disturbance Flag for region 5 + // Ionospheric disturbance flag + bool Region1_flag_5; //!< Ionospheric Disturbance Flag for region 1 + bool Region2_flag_5; //!< Ionospheric Disturbance Flag for region 2 + bool Region3_flag_5; //!< Ionospheric Disturbance Flag for region 3 + bool Region4_flag_5; //!< Ionospheric Disturbance Flag for region 4 + bool Region5_flag_5; //!< Ionospheric Disturbance Flag for region 5 - /*from page 5 (UTC) to have a timestamp*/ - double TOW_5; //!< UTC data reference Time of Week [s] - double WN_5; //!< UTC data reference Week number [week] + // from page 5 (UTC) to have a timestamp + int32_t TOW_5; //!< UTC data reference Time of Week [s] + int32_t WN_5; //!< UTC data reference Week number [week] /*! * Default constructor */ Galileo_Iono(); + + template + + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. + Here is used to save the iono data on disk file. + */ + inline void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + archive& make_nvp("ai0_5", ai0_5); + archive& make_nvp("ai1_5", ai1_5); + archive& make_nvp("ai2_5", ai2_5); + archive& make_nvp("Region1_flag_5", Region1_flag_5); + archive& make_nvp("Region2_flag_5", Region2_flag_5); + archive& make_nvp("Region3_flag_5", Region3_flag_5); + archive& make_nvp("Region4_flag_5", Region4_flag_5); + archive& make_nvp("Region5_flag_5", Region5_flag_5); + archive& make_nvp("TOW_5", TOW_5); + archive& make_nvp("WN_5", WN_5); + } }; #endif diff --git a/src/core/system_parameters/galileo_navigation_message.cc b/src/core/system_parameters/galileo_navigation_message.cc index f2a8b72ee..7ac22320c 100644 --- a/src/core/system_parameters/galileo_navigation_message.cc +++ b/src/core/system_parameters/galileo_navigation_message.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,19 +25,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "galileo_navigation_message.h" -#include // for boost::crc_basic, boost::crc_optimal +#include // for boost::crc_basic, boost::crc_optimal #include #include #include -typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_Galileo_INAV_type; +using CRC_Galileo_INAV_type = boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false>; void Galileo_Navigation_Message::reset() @@ -52,16 +52,16 @@ void Galileo_Navigation_Message::reset() flag_ephemeris_3 = false; // flag indicating that ephemeris 3/4 (word 3) have been received flag_ephemeris_4 = false; // flag indicating that ephemeris 4/4 (word 4) have been received - flag_iono_and_GST = false; // flag indicating that ionospheric parameters (word 5) have been received - flag_utc_model = false; // flag indicating that utc model parameters (word 6) have been received + flag_iono_and_GST = false; // flag indicating that ionospheric parameters (word 5) have been received + flag_utc_model = false; // flag indicating that utc model parameters (word 6) have been received - flag_all_almanac = false; // flag indicating that all almanac have been received - flag_almanac_1 = false; // flag indicating that almanac 1/4 (word 7) have been received - flag_almanac_2 = false; // flag indicating that almanac 2/4 (word 8) have been received - flag_almanac_3 = false; // flag indicating that almanac 3/4 (word 9) have been received - flag_almanac_4 = false; // flag indicating that almanac 4/4 (word 10) have been received + flag_all_almanac = false; // flag indicating that all almanac have been received + flag_almanac_1 = false; // flag indicating that almanac 1/4 (word 7) have been received + flag_almanac_2 = false; // flag indicating that almanac 2/4 (word 8) have been received + flag_almanac_3 = false; // flag indicating that almanac 3/4 (word 9) have been received + flag_almanac_4 = false; // flag indicating that almanac 4/4 (word 10) have been received - flag_TOW_5 = 0; + flag_TOW_5 = false; flag_TOW_set = false; flag_GGTO = false; @@ -71,70 +71,71 @@ void Galileo_Navigation_Message::reset() flag_GGTO_4 = false; IOD_ephemeris = 0; - /*Word type 1: Ephemeris (1/4)*/ + + // Word type 1: Ephemeris (1/4) IOD_nav_1 = 0; t0e_1 = 0; - M0_1 = 0; - e_1 = 0; - A_1 = 0; + M0_1 = 0.0; + e_1 = 0.0; + A_1 = 0.0; - /*Word type 2: Ephemeris (2/4)*/ - IOD_nav_2 = 0; // IOD_nav page 2 - OMEGA_0_2 = 0; // Longitude of ascending node of orbital plane at weekly epoch [semi-circles] - i_0_2 = 0; // Inclination angle at reference time [semi-circles] - omega_2 = 0; // Argument of perigee [semi-circles] - iDot_2 = 0; // Rate of inclination angle [semi-circles/sec] + // Word type 2: Ephemeris (2/4) + IOD_nav_2 = 0; // IOD_nav page 2 + OMEGA_0_2 = 0.0; // Longitude of ascending node of orbital plane at weekly epoch [semi-circles] + i_0_2 = 0.0; // Inclination angle at reference time [semi-circles] + omega_2 = 0.0; // Argument of perigee [semi-circles] + iDot_2 = 0.0; // Rate of inclination angle [semi-circles/sec] + // Word type 3: Ephemeris (3/4) and SISA + IOD_nav_3 = 0; + OMEGA_dot_3 = 0.0; // Rate of right ascension [semi-circles/sec] + delta_n_3 = 0.0; // Mean motion difference from computed value [semi-circles/sec] + C_uc_3 = 0.0; // Amplitude of the cosine harmonic correction term to the argument of latitude [radians] + C_us_3 = 0.0; // Amplitude of the sine harmonic correction term to the argument of latitude [radians] + C_rc_3 = 0.0; // Amplitude of the cosine harmonic correction term to the orbit radius [meters] + C_rs_3 = 0.0; // Amplitude of the sine harmonic correction term to the orbit radius [meters] + SISA_3 = 0; // - /*Word type 3: Ephemeris (3/4) and SISA*/ - IOD_nav_3 = 0; // - OMEGA_dot_3 = 0; // Rate of right ascension [semi-circles/sec] - delta_n_3 = 0; // Mean motion difference from computed value [semi-circles/sec] - C_uc_3 = 0; // Amplitude of the cosine harmonic correction term to the argument of latitude [radians] - C_us_3 = 0; // Amplitude of the sine harmonic correction term to the argument of latitude [radians] - C_rc_3 = 0; // Amplitude of the cosine harmonic correction term to the orbit radius [meters] - C_rs_3 = 0; // Amplitude of the sine harmonic correction term to the orbit radius [meters] - SISA_3 = 0; // + // Word type 4: Ephemeris (4/4) and Clock correction parameter/ + IOD_nav_4 = 0; + SV_ID_PRN_4 = 0; + C_ic_4 = 0.0; // Amplitude of the cosine harmonic correction term to the angle of inclination [radians] + C_is_4 = 0.0; // Amplitude of the sine harmonic correction term to the angle of inclination [radians] + // Clock correction parameters + t0c_4 = 0; + af0_4 = 0.0; + af1_4 = 0.0; + af2_4 = 0.0; + spare_4 = 0.0; - /*Word type 4: Ephemeris (4/4) and Clock correction parameters*/ - IOD_nav_4 = 0; // - SV_ID_PRN_4 = 0; // - C_ic_4 = 0; // Amplitude of the cosine harmonic correction term to the angle of inclination [radians] - C_is_4 = 0; // Amplitude of the sine harmonic correction term to the angle of inclination [radians] - /*Clock correction parameters*/ - t0c_4 = 0; // - af0_4 = 0; // - af1_4 = 0; // - af2_4 = 0; // - spare_4 = 0; + // Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST + // Ionospheric correction + ai0_5 = 0.0; + ai1_5 = 0.0; + ai2_5 = 0.0; - /*Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST*/ - /*Ionospheric correction*/ - /*Az*/ - ai0_5 = 0; // - ai1_5 = 0; // - ai2_5 = 0; // - /*Ionospheric disturbance flag*/ - Region1_flag_5 = 0; // Region1_flag_5; - Region2_flag_5 = 0; // - Region3_flag_5 = 0; // - Region4_flag_5 = 0; // - Region5_flag_5 = 0; // - BGD_E1E5a_5 = 0; // - BGD_E1E5b_5 = 0; // + // Ionospheric disturbance flag + Region1_flag_5 = false; // Region1_flag_5; + Region2_flag_5 = false; + Region3_flag_5 = false; + Region4_flag_5 = false; + Region5_flag_5 = false; + BGD_E1E5a_5 = 0.0; + BGD_E1E5b_5 = 0.0; E5b_HS_5 = 0; E1B_HS_5 = 0; - E5b_DVS_5 = 0; // - E1B_DVS_5 = 0; // - /*GST*/ + E5b_DVS_5 = false; + E1B_DVS_5 = false; + + // GST WN_5 = 0; TOW_5 = 0; - spare_5 = 0; + spare_5 = 0.0; - /*Word type 6: GST-UTC conversion parameters*/ - A0_6 = 0; - A1_6 = 0; + // Word type 6: GST-UTC conversion parameters + A0_6 = 0.0; + A1_6 = 0.0; Delta_tLS_6 = 0; t0t_6 = 0; WNot_6 = 0; @@ -143,64 +144,65 @@ void Galileo_Navigation_Message::reset() Delta_tLSF_6 = 0; TOW_6 = 0; - /*Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number*/ + // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number IOD_a_7 = 0; WN_a_7 = 0; t0a_7 = 0; SVID1_7 = 0; - DELTA_A_7 = 0; - e_7 = 0; - omega_7 = 0; - delta_i_7 = 0; - Omega0_7 = 0; - Omega_dot_7 = 0; - M0_7 = 0; + DELTA_A_7 = 0.0; + e_7 = 0.0; + omega_7 = 0.0; + delta_i_7 = 0.0; + Omega0_7 = 0.0; + Omega_dot_7 = 0.0; + M0_7 = 0.0; - /*Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ + // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2) IOD_a_8 = 0; - af0_8 = 0; - af1_8 = 0; + af0_8 = 0.0; + af1_8 = 0.0; E5b_HS_8 = 0; E1B_HS_8 = 0; SVID2_8 = 0; - DELTA_A_8 = 0; - e_8 = 0; - omega_8 = 0; - delta_i_8 = 0; - Omega0_8 = 0; - Omega_dot_8 = 0; + DELTA_A_8 = 0.0; + e_8 = 0.0; + omega_8 = 0.0; + delta_i_8 = 0.0; + Omega0_8 = 0.0; + Omega_dot_8 = 0.0; - /*Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2)*/ + // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2) IOD_a_9 = 0; WN_a_9 = 0; t0a_9 = 0; - M0_9 = 0; - af0_9 = 0; - af1_9 = 0; + M0_9 = 0.0; + af0_9 = 0.0; + af1_9 = 0.0; E5b_HS_9 = 0; E1B_HS_9 = 0; SVID3_9 = 0; - DELTA_A_9 = 0; - e_9 = 0; - omega_9 = 0; - delta_i_9 = 0; + DELTA_A_9 = 0.0; + e_9 = 0.0; + omega_9 = 0.0; + delta_i_9 = 0.0; - /*Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters*/ + // Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters IOD_a_10 = 0; - Omega0_10 = 0; - Omega_dot_10 = 0; - M0_10 = 0; - af0_10 = 0; - af1_10 = 0; + Omega0_10 = 0.0; + Omega_dot_10 = 0.0; + M0_10 = 0.0; + af0_10 = 0.0; + af1_10 = 0.0; E5b_HS_10 = 0; E1B_HS_10 = 0; - //GST-GPS - A_0G_10 = 0; - A_1G_10 = 0; + + // GST-GPS + A_0G_10 = 0.0; + A_1G_10 = 0.0; t_0G_10 = 0; WN_0G_10 = 0; - /*Word type 0: I/NAV Spare Word*/ + // Word type 0: I/NAV Spare Word Time_0 = 0; WN_0 = 0; TOW_0 = 0; @@ -218,7 +220,6 @@ void Galileo_Navigation_Message::reset() galileo_satvel_X = 0.0; galileo_satvel_Y = 0.0; galileo_satvel_Z = 0.0; - } @@ -228,11 +229,11 @@ Galileo_Navigation_Message::Galileo_Navigation_Message() } -bool Galileo_Navigation_Message::CRC_test(std::bitset bits,boost::uint32_t checksum) +bool Galileo_Navigation_Message::CRC_test(std::bitset bits, uint32_t checksum) { CRC_Galileo_INAV_type CRC_Galileo; - boost::uint32_t crc_computed; + uint32_t crc_computed; // Galileo INAV frame for CRC is not an integer multiple of bytes // it needs to be filled with zeroes at the start of the frame. // This operation is done in the transformation from bits to bytes @@ -243,34 +244,81 @@ bool Galileo_Navigation_Message::CRC_test(std::bitset b std::vector bytes; boost::to_block_range(frame_bits, std::back_inserter(bytes)); - std::reverse(bytes.begin(),bytes.end()); + std::reverse(bytes.begin(), bytes.end()); - CRC_Galileo.process_bytes( bytes.data(), GALILEO_DATA_FRAME_BYTES ); + CRC_Galileo.process_bytes(bytes.data(), GALILEO_DATA_FRAME_BYTES); crc_computed = CRC_Galileo.checksum(); if (checksum == crc_computed) { return true; } + return false; +} + + +uint64_t Galileo_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector >& parameter) +{ + uint64_t value = 0ULL; + int32_t num_of_slices = parameter.size(); + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 0; j < parameter[i].second; j++) + { + value <<= 1; // shift left + if (static_cast(bits[GALILEO_DATA_JK_BITS - parameter[i].first - j]) == 1) + { + value += 1; // insert the bit + } + } + } + return value; +} + + +uint64_t Galileo_Navigation_Message::read_page_type_unsigned(std::bitset bits, const std::vector >& parameter) +{ + uint64_t value = 0ULL; + int32_t num_of_slices = parameter.size(); + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 0; j < parameter[i].second; j++) + { + value <<= 1; // shift left + if (static_cast(bits[GALILEO_PAGE_TYPE_BITS - parameter[i].first - j]) == 1) + { + value += 1ULL; // insert the bit + } + } + } + return value; +} + + +int64_t Galileo_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector >& parameter) +{ + int64_t value = 0LL; + int32_t num_of_slices = parameter.size(); + + // read the MSB and perform the sign extension + if (static_cast(bits[GALILEO_DATA_JK_BITS - parameter[0].first]) == 1) + { + value ^= 0xFFFFFFFFFFFFFFFFLL; // 64 bits variable + } else { - return false; + value &= 0LL; } -} - -unsigned long int Galileo_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector > parameter) -{ - unsigned long int value = 0; - int num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) + for (int32_t i = 0; i < num_of_slices; i++) { - for (int j = 0; j < parameter[i].second; j++) + for (int32_t j = 0; j < parameter[i].second; j++) { - value <<= 1; //shift left - if (bits[GALILEO_DATA_JK_BITS - parameter[i].first - j] == 1) + value <<= 1; // shift left + value &= 0xFFFFFFFFFFFFFFFE; // reset the corresponding bit (for the 64 bits variable) + if (static_cast(bits[GALILEO_DATA_JK_BITS - parameter[i].first - j]) == 1) { - value += 1; // insert the bit + value += 1LL; // insert the bit } } } @@ -278,91 +326,10 @@ unsigned long int Galileo_Navigation_Message::read_navigation_unsigned(std::bits } - -unsigned long int Galileo_Navigation_Message::read_page_type_unsigned(std::bitset bits, const std::vector > parameter) -{ - unsigned long int value = 0; - int num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) - { - for (int j = 0; j < parameter[i].second; j++) - { - value <<= 1; //shift left - if (bits[GALILEO_PAGE_TYPE_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } - } - } - return value; -} - - - -signed long int Galileo_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector > parameter) -{ - signed long int value = 0; - int num_of_slices = parameter.size(); - // Discriminate between 64 bits and 32 bits compiler - int long_int_size_bytes = sizeof(signed long int); - if (long_int_size_bytes == 8) // if a long int takes 8 bytes, we are in a 64 bits system - { - // read the MSB and perform the sign extension - if (bits[GALILEO_DATA_JK_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFFFFFFFFFF; //64 bits variable - } - else - { - value &= 0; - } - - for (int i = 0; i < num_of_slices; i++) - { - for (int j = 0; j < parameter[i].second; j++) - { - value <<= 1; //shift left - value &= 0xFFFFFFFFFFFFFFFE; //reset the corresponding bit (for the 64 bits variable) - if (bits[GALILEO_DATA_JK_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } - } - } - } - else // we assume we are in a 32 bits system - { - // read the MSB and perform the sign extension - if (bits[GALILEO_DATA_JK_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFF; - } - else - { - value &= 0; - } - - for (int i = 0; i < num_of_slices; i++) - { - for (int j = 0; j < parameter[i].second; j++) - { - value <<= 1; //shift left - value &= 0xFFFFFFFE; //reset the corresponding bit - if (bits[GALILEO_DATA_JK_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } - } - } - } - return value; -} - - -bool Galileo_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector > parameter) +bool Galileo_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector >& parameter) { bool value; - if (bits[GALILEO_DATA_JK_BITS - parameter[0].first] == 1) + if (static_cast(static_cast(bits[GALILEO_DATA_JK_BITS - parameter[0].first])) == 1) { value = true; } @@ -374,48 +341,46 @@ bool Galileo_Navigation_Message::read_navigation_bool(std::bitset page_type_bits (page_number_bits); // from string to bitset - Page_type = static_cast(read_page_type_unsigned(page_type_bits, type)); + std::string page_number_bits = Data_k.substr(0, 6); + std::bitset page_type_bits(page_number_bits); // from string to bitset + Page_type = static_cast(read_page_type_unsigned(page_type_bits, type)); Page_type_time_stamp = Page_type; std::string Data_jk_ephemeris = Data_k + Data_j; page_jk_decoder(Data_jk_ephemeris.c_str()); @@ -443,12 +408,12 @@ void Galileo_Navigation_Message::split_page(std::string page_string, int flag_ev // Wrong CRC... discard frame flag_CRC_test = false; } - } // end of CRC checksum control - } // end if (page_string.at(0)=='1') + } // end of CRC checksum control + } // end if (page_string.at(0)=='1') else { - page_Even = page_string.substr (0,114); - std::string tail_Even = page_string.substr (114,6); + page_Even = page_string.substr(0, 114); + std::string tail_Even = page_string.substr(114, 6); //std::cout << "tail_even_string: " << tail_Even < data_jk_bits (data_jk_string); - //DLOG(INFO) << "Data_jk_bits (bitset) "<< endl << data_jk_bits << endl; + std::bitset data_jk_bits(data_jk_string); - page_number = static_cast(read_navigation_unsigned(data_jk_bits, PAGE_TYPE_bit)); + page_number = static_cast(read_navigation_unsigned(data_jk_bits, PAGE_TYPE_bit)); LOG(INFO) << "Page number = " << page_number; switch (page_number) - { - case 1: /*Word type 1: Ephemeris (1/4)*/ - IOD_nav_1 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_1_bit)); - DLOG(INFO) << "IOD_nav_1= " << IOD_nav_1; - t0e_1 = static_cast(read_navigation_unsigned(data_jk_bits, T0E_1_bit)); - t0e_1 = t0e_1 * t0e_1_LSB; - DLOG(INFO) << "t0e_1= " << t0e_1; - M0_1 = static_cast(read_navigation_signed(data_jk_bits, M0_1_bit)); - M0_1 = M0_1 * M0_1_LSB; - DLOG(INFO) << "M0_1= " << M0_1; - e_1 = static_cast(read_navigation_unsigned(data_jk_bits, e_1_bit)); - e_1 = e_1 * e_1_LSB; - DLOG(INFO) << "e_1= " << e_1; - A_1 = static_cast(read_navigation_unsigned(data_jk_bits, A_1_bit)); - A_1 = A_1 * A_1_LSB_gal; - DLOG(INFO) << "A_1= " << A_1; - flag_ephemeris_1 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + { + case 1: // Word type 1: Ephemeris (1/4) + IOD_nav_1 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_1_bit)); + DLOG(INFO) << "IOD_nav_1= " << IOD_nav_1; + t0e_1 = static_cast(read_navigation_unsigned(data_jk_bits, T0E_1_bit)); + t0e_1 = t0e_1 * t0e_1_LSB; + DLOG(INFO) << "t0e_1= " << t0e_1; + M0_1 = static_cast(read_navigation_signed(data_jk_bits, M0_1_bit)); + M0_1 = M0_1 * M0_1_LSB; + DLOG(INFO) << "M0_1= " << M0_1; + e_1 = static_cast(read_navigation_unsigned(data_jk_bits, e_1_bit)); + e_1 = e_1 * e_1_LSB; + DLOG(INFO) << "e_1= " << e_1; + A_1 = static_cast(read_navigation_unsigned(data_jk_bits, A_1_bit)); + A_1 = A_1 * A_1_LSB_gal; + DLOG(INFO) << "A_1= " << A_1; + flag_ephemeris_1 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 2: /*Word type 2: Ephemeris (2/4)*/ - IOD_nav_2 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_2_bit)); - DLOG(INFO) << "IOD_nav_2= " << IOD_nav_2; - OMEGA_0_2 = static_cast(read_navigation_signed(data_jk_bits, OMEGA_0_2_bit)); - OMEGA_0_2 = OMEGA_0_2 * OMEGA_0_2_LSB; - DLOG(INFO) << "OMEGA_0_2= " << OMEGA_0_2 ; - i_0_2 = static_cast(read_navigation_signed(data_jk_bits, i_0_2_bit)); - i_0_2 = i_0_2 * i_0_2_LSB; - DLOG(INFO) << "i_0_2= " << i_0_2 ; - omega_2 = static_cast(read_navigation_signed(data_jk_bits, omega_2_bit)); - omega_2 = omega_2 * omega_2_LSB; - DLOG(INFO) << "omega_2= " << omega_2; - iDot_2 = static_cast(read_navigation_signed(data_jk_bits, iDot_2_bit)); - iDot_2 = iDot_2 * iDot_2_LSB; - DLOG(INFO) << "iDot_2= " << iDot_2; - flag_ephemeris_2 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 2: // Word type 2: Ephemeris (2/4) + IOD_nav_2 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_2_bit)); + DLOG(INFO) << "IOD_nav_2= " << IOD_nav_2; + OMEGA_0_2 = static_cast(read_navigation_signed(data_jk_bits, OMEGA_0_2_bit)); + OMEGA_0_2 = OMEGA_0_2 * OMEGA_0_2_LSB; + DLOG(INFO) << "OMEGA_0_2= " << OMEGA_0_2; + i_0_2 = static_cast(read_navigation_signed(data_jk_bits, i_0_2_bit)); + i_0_2 = i_0_2 * i_0_2_LSB; + DLOG(INFO) << "i_0_2= " << i_0_2; + omega_2 = static_cast(read_navigation_signed(data_jk_bits, omega_2_bit)); + omega_2 = omega_2 * omega_2_LSB; + DLOG(INFO) << "omega_2= " << omega_2; + iDot_2 = static_cast(read_navigation_signed(data_jk_bits, iDot_2_bit)); + iDot_2 = iDot_2 * iDot_2_LSB; + DLOG(INFO) << "iDot_2= " << iDot_2; + flag_ephemeris_2 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 3: /*Word type 3: Ephemeris (3/4) and SISA*/ - IOD_nav_3 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_3_bit)); - DLOG(INFO) << "IOD_nav_3= " << IOD_nav_3 ; - OMEGA_dot_3 = static_cast(read_navigation_signed(data_jk_bits, OMEGA_dot_3_bit)); - OMEGA_dot_3 = OMEGA_dot_3 * OMEGA_dot_3_LSB; - DLOG(INFO) <<"OMEGA_dot_3= " << OMEGA_dot_3 ; - delta_n_3 = static_cast(read_navigation_signed(data_jk_bits, delta_n_3_bit)); - delta_n_3 = delta_n_3 * delta_n_3_LSB; - DLOG(INFO) << "delta_n_3= " << delta_n_3 ; - C_uc_3 = static_cast(read_navigation_signed(data_jk_bits, C_uc_3_bit)); - C_uc_3 = C_uc_3 * C_uc_3_LSB; - DLOG(INFO) << "C_uc_3= " << C_uc_3; - C_us_3 = static_cast(read_navigation_signed(data_jk_bits, C_us_3_bit)); - C_us_3 = C_us_3 * C_us_3_LSB; - DLOG(INFO) << "C_us_3= " << C_us_3; - C_rc_3 = static_cast(read_navigation_signed(data_jk_bits, C_rc_3_bit)); - C_rc_3 = C_rc_3 * C_rc_3_LSB; - DLOG(INFO) << "C_rc_3= " << C_rc_3; - C_rs_3 = static_cast(read_navigation_signed(data_jk_bits, C_rs_3_bit)); - C_rs_3 = C_rs_3 * C_rs_3_LSB; - DLOG(INFO) << "C_rs_3= " << C_rs_3; - SISA_3 = static_cast(read_navigation_unsigned(data_jk_bits, SISA_3_bit)); - DLOG(INFO) << "SISA_3= " << SISA_3; - flag_ephemeris_3 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 3: // Word type 3: Ephemeris (3/4) and SISA + IOD_nav_3 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_3_bit)); + DLOG(INFO) << "IOD_nav_3= " << IOD_nav_3; + OMEGA_dot_3 = static_cast(read_navigation_signed(data_jk_bits, OMEGA_dot_3_bit)); + OMEGA_dot_3 = OMEGA_dot_3 * OMEGA_dot_3_LSB; + DLOG(INFO) << "OMEGA_dot_3= " << OMEGA_dot_3; + delta_n_3 = static_cast(read_navigation_signed(data_jk_bits, delta_n_3_bit)); + delta_n_3 = delta_n_3 * delta_n_3_LSB; + DLOG(INFO) << "delta_n_3= " << delta_n_3; + C_uc_3 = static_cast(read_navigation_signed(data_jk_bits, C_uc_3_bit)); + C_uc_3 = C_uc_3 * C_uc_3_LSB; + DLOG(INFO) << "C_uc_3= " << C_uc_3; + C_us_3 = static_cast(read_navigation_signed(data_jk_bits, C_us_3_bit)); + C_us_3 = C_us_3 * C_us_3_LSB; + DLOG(INFO) << "C_us_3= " << C_us_3; + C_rc_3 = static_cast(read_navigation_signed(data_jk_bits, C_rc_3_bit)); + C_rc_3 = C_rc_3 * C_rc_3_LSB; + DLOG(INFO) << "C_rc_3= " << C_rc_3; + C_rs_3 = static_cast(read_navigation_signed(data_jk_bits, C_rs_3_bit)); + C_rs_3 = C_rs_3 * C_rs_3_LSB; + DLOG(INFO) << "C_rs_3= " << C_rs_3; + SISA_3 = static_cast(read_navigation_unsigned(data_jk_bits, SISA_3_bit)); + DLOG(INFO) << "SISA_3= " << SISA_3; + flag_ephemeris_3 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 4: /* Word type 4: Ephemeris (4/4) and Clock correction parameters*/ - IOD_nav_4 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_4_bit)); - DLOG(INFO) << "IOD_nav_4= " << IOD_nav_4 ; - SV_ID_PRN_4 = static_cast(read_navigation_unsigned(data_jk_bits, SV_ID_PRN_4_bit)); - DLOG(INFO) << "SV_ID_PRN_4= " << SV_ID_PRN_4 ; - C_ic_4 = static_cast(read_navigation_signed(data_jk_bits, C_ic_4_bit)); - C_ic_4 = C_ic_4 * C_ic_4_LSB; - DLOG(INFO) << "C_ic_4= " << C_ic_4; - C_is_4 = static_cast(read_navigation_signed(data_jk_bits, C_is_4_bit)); - C_is_4 = C_is_4 * C_is_4_LSB; - DLOG(INFO) << "C_is_4= " << C_is_4; - /*Clock correction parameters*/ - t0c_4 = static_cast(read_navigation_unsigned(data_jk_bits, t0c_4_bit)); - t0c_4 = t0c_4 * t0c_4_LSB; - DLOG(INFO) << "t0c_4= " << t0c_4; - af0_4 = static_cast(read_navigation_signed(data_jk_bits, af0_4_bit)); - af0_4 = af0_4 * af0_4_LSB; - DLOG(INFO) << "af0_4 = " << af0_4; - af1_4 = static_cast(read_navigation_signed(data_jk_bits, af1_4_bit)); - af1_4 = af1_4 * af1_4_LSB; - DLOG(INFO) << "af1_4 = " << af1_4; - af2_4 = static_cast(read_navigation_signed(data_jk_bits, af2_4_bit)); - af2_4 = af2_4 * af2_4_LSB; - DLOG(INFO) << "af2_4 = " << af2_4; - spare_4 = static_cast(read_navigation_unsigned(data_jk_bits, spare_4_bit)); - DLOG(INFO) << "spare_4 = " << spare_4; - flag_ephemeris_4 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 4: // Word type 4: Ephemeris (4/4) and Clock correction parameters + IOD_nav_4 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_nav_4_bit)); + DLOG(INFO) << "IOD_nav_4= " << IOD_nav_4; + SV_ID_PRN_4 = static_cast(read_navigation_unsigned(data_jk_bits, SV_ID_PRN_4_bit)); + DLOG(INFO) << "SV_ID_PRN_4= " << SV_ID_PRN_4; + C_ic_4 = static_cast(read_navigation_signed(data_jk_bits, C_ic_4_bit)); + C_ic_4 = C_ic_4 * C_ic_4_LSB; + DLOG(INFO) << "C_ic_4= " << C_ic_4; + C_is_4 = static_cast(read_navigation_signed(data_jk_bits, C_is_4_bit)); + C_is_4 = C_is_4 * C_is_4_LSB; + DLOG(INFO) << "C_is_4= " << C_is_4; + // Clock correction parameters + t0c_4 = static_cast(read_navigation_unsigned(data_jk_bits, t0c_4_bit)); + t0c_4 = t0c_4 * t0c_4_LSB; + DLOG(INFO) << "t0c_4= " << t0c_4; + af0_4 = static_cast(read_navigation_signed(data_jk_bits, af0_4_bit)); + af0_4 = af0_4 * af0_4_LSB; + DLOG(INFO) << "af0_4 = " << af0_4; + af1_4 = static_cast(read_navigation_signed(data_jk_bits, af1_4_bit)); + af1_4 = af1_4 * af1_4_LSB; + DLOG(INFO) << "af1_4 = " << af1_4; + af2_4 = static_cast(read_navigation_signed(data_jk_bits, af2_4_bit)); + af2_4 = af2_4 * af2_4_LSB; + DLOG(INFO) << "af2_4 = " << af2_4; + spare_4 = static_cast(read_navigation_unsigned(data_jk_bits, spare_4_bit)); + DLOG(INFO) << "spare_4 = " << spare_4; + flag_ephemeris_4 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 5: /*Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST*/ - /*Ionospheric correction*/ - /*Az*/ - ai0_5 = static_cast(read_navigation_unsigned(data_jk_bits, ai0_5_bit)); - ai0_5 = ai0_5 * ai0_5_LSB; - DLOG(INFO) << "ai0_5= " << ai0_5; - ai1_5 = static_cast(read_navigation_signed(data_jk_bits, ai1_5_bit)); - ai1_5 = ai1_5 * ai1_5_LSB; - DLOG(INFO) << "ai1_5= " << ai1_5; - ai2_5 = static_cast(read_navigation_signed(data_jk_bits, ai2_5_bit)); - ai2_5 = ai2_5 * ai2_5_LSB; - DLOG(INFO) << "ai2_5= " << ai2_5; - /*Ionospheric disturbance flag*/ - Region1_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region1_5_bit)); - DLOG(INFO) << "Region1_flag_5= " << Region1_flag_5; - Region2_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region2_5_bit)); - DLOG(INFO) << "Region2_flag_5= " << Region2_flag_5; - Region3_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region3_5_bit)); - DLOG(INFO) << "Region3_flag_5= " << Region3_flag_5; - Region4_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region4_5_bit)); - DLOG(INFO) << "Region4_flag_5= " << Region4_flag_5; - Region5_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region5_5_bit)); - DLOG(INFO) << "Region5_flag_5= " << Region5_flag_5; - BGD_E1E5a_5 = static_cast(read_navigation_signed(data_jk_bits, BGD_E1E5a_5_bit)); - BGD_E1E5a_5 = BGD_E1E5a_5 * BGD_E1E5a_5_LSB; - DLOG(INFO) << "BGD_E1E5a_5= " << BGD_E1E5a_5; - BGD_E1E5b_5 = static_cast(read_navigation_signed(data_jk_bits, BGD_E1E5b_5_bit)); - BGD_E1E5b_5 = BGD_E1E5b_5 * BGD_E1E5b_5_LSB; - DLOG(INFO) << "BGD_E1E5b_5= " << BGD_E1E5b_5; - E5b_HS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_5_bit)); - DLOG(INFO) << "E5b_HS_5= " << E5b_HS_5; - E1B_HS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_5_bit)); - DLOG(INFO) << "E1B_HS_5= " << E1B_HS_5; - E5b_DVS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_DVS_5_bit)); - DLOG(INFO) << "E5b_DVS_5= " << E5b_DVS_5; - E1B_DVS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_DVS_5_bit)); - DLOG(INFO) << "E1B_DVS_5= " << E1B_DVS_5; - /*GST*/ - WN_5 = static_cast(read_navigation_unsigned(data_jk_bits, WN_5_bit)); - DLOG(INFO) << "WN_5= " << WN_5; - TOW_5 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_5_bit)); - DLOG(INFO) << "TOW_5= " << TOW_5; - flag_TOW_5 = true; //set to false externally - spare_5 = static_cast(read_navigation_unsigned(data_jk_bits, spare_5_bit)); - DLOG(INFO) << "spare_5= " << spare_5; - flag_iono_and_GST = true; //set to false externally - flag_TOW_set = true; //set to false externally - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 5: // Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST + // Ionospheric correction + ai0_5 = static_cast(read_navigation_unsigned(data_jk_bits, ai0_5_bit)); + ai0_5 = ai0_5 * ai0_5_LSB; + DLOG(INFO) << "ai0_5= " << ai0_5; + ai1_5 = static_cast(read_navigation_signed(data_jk_bits, ai1_5_bit)); + ai1_5 = ai1_5 * ai1_5_LSB; + DLOG(INFO) << "ai1_5= " << ai1_5; + ai2_5 = static_cast(read_navigation_signed(data_jk_bits, ai2_5_bit)); + ai2_5 = ai2_5 * ai2_5_LSB; + DLOG(INFO) << "ai2_5= " << ai2_5; + // Ionospheric disturbance flag + Region1_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region1_5_bit)); + DLOG(INFO) << "Region1_flag_5= " << Region1_flag_5; + Region2_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region2_5_bit)); + DLOG(INFO) << "Region2_flag_5= " << Region2_flag_5; + Region3_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region3_5_bit)); + DLOG(INFO) << "Region3_flag_5= " << Region3_flag_5; + Region4_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region4_5_bit)); + DLOG(INFO) << "Region4_flag_5= " << Region4_flag_5; + Region5_flag_5 = static_cast(read_navigation_bool(data_jk_bits, Region5_5_bit)); + DLOG(INFO) << "Region5_flag_5= " << Region5_flag_5; + BGD_E1E5a_5 = static_cast(read_navigation_signed(data_jk_bits, BGD_E1E5a_5_bit)); + BGD_E1E5a_5 = BGD_E1E5a_5 * BGD_E1E5a_5_LSB; + DLOG(INFO) << "BGD_E1E5a_5= " << BGD_E1E5a_5; + BGD_E1E5b_5 = static_cast(read_navigation_signed(data_jk_bits, BGD_E1E5b_5_bit)); + BGD_E1E5b_5 = BGD_E1E5b_5 * BGD_E1E5b_5_LSB; + DLOG(INFO) << "BGD_E1E5b_5= " << BGD_E1E5b_5; + E5b_HS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_5_bit)); + DLOG(INFO) << "E5b_HS_5= " << E5b_HS_5; + E1B_HS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_5_bit)); + DLOG(INFO) << "E1B_HS_5= " << E1B_HS_5; + E5b_DVS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_DVS_5_bit)); + DLOG(INFO) << "E5b_DVS_5= " << E5b_DVS_5; + E1B_DVS_5 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_DVS_5_bit)); + DLOG(INFO) << "E1B_DVS_5= " << E1B_DVS_5; + // GST + WN_5 = static_cast(read_navigation_unsigned(data_jk_bits, WN_5_bit)); + DLOG(INFO) << "WN_5= " << WN_5; + TOW_5 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_5_bit)); + DLOG(INFO) << "TOW_5= " << TOW_5; + flag_TOW_5 = true; // set to false externally + spare_5 = static_cast(read_navigation_unsigned(data_jk_bits, spare_5_bit)); + DLOG(INFO) << "spare_5= " << spare_5; + flag_iono_and_GST = true; // set to false externally + flag_TOW_set = true; // set to false externally + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 6: /*Word type 6: GST-UTC conversion parameters*/ - A0_6 = static_cast(read_navigation_signed(data_jk_bits, A0_6_bit)); - A0_6 = A0_6 * A0_6_LSB; - DLOG(INFO) << "A0_6= " << A0_6; - A1_6 = static_cast(read_navigation_signed(data_jk_bits, A1_6_bit)); - A1_6 = A1_6 * A1_6_LSB; - DLOG(INFO) << "A1_6= " << A1_6; - Delta_tLS_6 = static_cast(read_navigation_signed(data_jk_bits, Delta_tLS_6_bit)); - DLOG(INFO) << "Delta_tLS_6= " << Delta_tLS_6; - t0t_6 = static_cast(read_navigation_unsigned(data_jk_bits, t0t_6_bit)); - t0t_6 = t0t_6 * t0t_6_LSB; - DLOG(INFO) << "t0t_6= " << t0t_6; - WNot_6 = static_cast(read_navigation_unsigned(data_jk_bits, WNot_6_bit)); - DLOG(INFO) << "WNot_6= " << WNot_6; - WN_LSF_6 = static_cast(read_navigation_unsigned(data_jk_bits, WN_LSF_6_bit)); - DLOG(INFO) << "WN_LSF_6= " << WN_LSF_6; - DN_6 = static_cast(read_navigation_unsigned(data_jk_bits, DN_6_bit)); - DLOG(INFO) << "DN_6= " << DN_6; - Delta_tLSF_6 = static_cast(read_navigation_signed(data_jk_bits, Delta_tLSF_6_bit)); - DLOG(INFO) << "Delta_tLSF_6= " << Delta_tLSF_6; - TOW_6 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_6_bit)); - DLOG(INFO) << "TOW_6= " << TOW_6; - flag_TOW_6 = true; //set to false externally - flag_utc_model = true; //set to false externally - flag_TOW_set = true; //set to false externally - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 6: // Word type 6: GST-UTC conversion parameters + A0_6 = static_cast(read_navigation_signed(data_jk_bits, A0_6_bit)); + A0_6 = A0_6 * A0_6_LSB; + DLOG(INFO) << "A0_6= " << A0_6; + A1_6 = static_cast(read_navigation_signed(data_jk_bits, A1_6_bit)); + A1_6 = A1_6 * A1_6_LSB; + DLOG(INFO) << "A1_6= " << A1_6; + Delta_tLS_6 = static_cast(read_navigation_signed(data_jk_bits, Delta_tLS_6_bit)); + DLOG(INFO) << "Delta_tLS_6= " << Delta_tLS_6; + t0t_6 = static_cast(read_navigation_unsigned(data_jk_bits, t0t_6_bit)); + t0t_6 = t0t_6 * t0t_6_LSB; + DLOG(INFO) << "t0t_6= " << t0t_6; + WNot_6 = static_cast(read_navigation_unsigned(data_jk_bits, WNot_6_bit)); + DLOG(INFO) << "WNot_6= " << WNot_6; + WN_LSF_6 = static_cast(read_navigation_unsigned(data_jk_bits, WN_LSF_6_bit)); + DLOG(INFO) << "WN_LSF_6= " << WN_LSF_6; + DN_6 = static_cast(read_navigation_unsigned(data_jk_bits, DN_6_bit)); + DLOG(INFO) << "DN_6= " << DN_6; + Delta_tLSF_6 = static_cast(read_navigation_signed(data_jk_bits, Delta_tLSF_6_bit)); + DLOG(INFO) << "Delta_tLSF_6= " << Delta_tLSF_6; + TOW_6 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_6_bit)); + DLOG(INFO) << "TOW_6= " << TOW_6; + flag_TOW_6 = true; // set to false externally + flag_utc_model = true; // set to false externally + flag_TOW_set = true; // set to false externally + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 7: /*Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number*/ - IOD_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_7_bit)); - DLOG(INFO) << "IOD_a_7= " << IOD_a_7; - WN_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, WN_a_7_bit)); - DLOG(INFO) << "WN_a_7= " << WN_a_7; - t0a_7 = static_cast(read_navigation_unsigned(data_jk_bits, t0a_7_bit)); - t0a_7 = t0a_7 * t0a_7_LSB; - DLOG(INFO) << "t0a_7= " << t0a_7; - SVID1_7 = static_cast(read_navigation_unsigned(data_jk_bits, SVID1_7_bit)); - DLOG(INFO) << "SVID1_7= " << SVID1_7; - DELTA_A_7 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_7_bit)); - DELTA_A_7 = DELTA_A_7 * DELTA_A_7_LSB; - DLOG(INFO) << "DELTA_A_7= " << DELTA_A_7; - e_7 = static_cast(read_navigation_unsigned(data_jk_bits, e_7_bit)); - e_7 = e_7 * e_7_LSB; - DLOG(INFO) << "e_7= " << e_7; - omega_7 = static_cast(read_navigation_signed(data_jk_bits, omega_7_bit)); - omega_7 = omega_7 * omega_7_LSB; - DLOG(INFO) << "omega_7= " << omega_7; - delta_i_7 = static_cast(read_navigation_signed(data_jk_bits, delta_i_7_bit)); - delta_i_7 = delta_i_7 * delta_i_7_LSB; - DLOG(INFO) << "delta_i_7= " << delta_i_7; - Omega0_7 = static_cast(read_navigation_signed(data_jk_bits, Omega0_7_bit)); - Omega0_7 = Omega0_7 * Omega0_7_LSB; - DLOG(INFO) << "Omega0_7= " << Omega0_7; - Omega_dot_7 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_7_bit)); - Omega_dot_7 = Omega_dot_7 * Omega_dot_7_LSB; - DLOG(INFO) << "Omega_dot_7= " << Omega_dot_7; - M0_7 = static_cast(read_navigation_signed(data_jk_bits, M0_7_bit)); - M0_7 = M0_7 * M0_7_LSB; - DLOG(INFO) << "M0_7= " << M0_7; - flag_almanac_1 = true; - DLOG(INFO) << "flag_tow_set"<< flag_TOW_set; - break; + case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number + IOD_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_7_bit)); + DLOG(INFO) << "IOD_a_7= " << IOD_a_7; + WN_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, WN_a_7_bit)); + DLOG(INFO) << "WN_a_7= " << WN_a_7; + t0a_7 = static_cast(read_navigation_unsigned(data_jk_bits, t0a_7_bit)); + t0a_7 = t0a_7 * t0a_7_LSB; + DLOG(INFO) << "t0a_7= " << t0a_7; + SVID1_7 = static_cast(read_navigation_unsigned(data_jk_bits, SVID1_7_bit)); + DLOG(INFO) << "SVID1_7= " << SVID1_7; + DELTA_A_7 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_7_bit)); + DELTA_A_7 = DELTA_A_7 * DELTA_A_7_LSB; + DLOG(INFO) << "DELTA_A_7= " << DELTA_A_7; + e_7 = static_cast(read_navigation_unsigned(data_jk_bits, e_7_bit)); + e_7 = e_7 * e_7_LSB; + DLOG(INFO) << "e_7= " << e_7; + omega_7 = static_cast(read_navigation_signed(data_jk_bits, omega_7_bit)); + omega_7 = omega_7 * omega_7_LSB; + DLOG(INFO) << "omega_7= " << omega_7; + delta_i_7 = static_cast(read_navigation_signed(data_jk_bits, delta_i_7_bit)); + delta_i_7 = delta_i_7 * delta_i_7_LSB; + DLOG(INFO) << "delta_i_7= " << delta_i_7; + Omega0_7 = static_cast(read_navigation_signed(data_jk_bits, Omega0_7_bit)); + Omega0_7 = Omega0_7 * Omega0_7_LSB; + DLOG(INFO) << "Omega0_7= " << Omega0_7; + Omega_dot_7 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_7_bit)); + Omega_dot_7 = Omega_dot_7 * Omega_dot_7_LSB; + DLOG(INFO) << "Omega_dot_7= " << Omega_dot_7; + M0_7 = static_cast(read_navigation_signed(data_jk_bits, M0_7_bit)); + M0_7 = M0_7 * M0_7_LSB; + DLOG(INFO) << "M0_7= " << M0_7; + flag_almanac_1 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 8: /*Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ - IOD_a_8 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_8_bit)); - DLOG(INFO) << "IOD_a_8= " << IOD_a_8; - af0_8 = static_cast(read_navigation_signed(data_jk_bits, af0_8_bit)); - af0_8 = af0_8 * af0_8_LSB; - DLOG(INFO) << "af0_8= " << af0_8; - af1_8 = static_cast(read_navigation_signed(data_jk_bits, af1_8_bit)); - af1_8 = af1_8 * af1_8_LSB; - DLOG(INFO) << "af1_8= " << af1_8; - E5b_HS_8 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_8_bit)); - DLOG(INFO) << "E5b_HS_8= " << E5b_HS_8; - E1B_HS_8 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_8_bit)); - DLOG(INFO) << "E1B_HS_8= " << E1B_HS_8; - SVID2_8 = static_cast(read_navigation_unsigned(data_jk_bits, SVID2_8_bit)); - DLOG(INFO) << "SVID2_8= " << SVID2_8; - DELTA_A_8 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_8_bit)); - DELTA_A_8 = DELTA_A_8 * DELTA_A_8_LSB; - DLOG(INFO) << "DELTA_A_8= " << DELTA_A_8; - e_8 = static_cast(read_navigation_unsigned(data_jk_bits, e_8_bit)); - e_8 = e_8 * e_8_LSB; - DLOG(INFO) << "e_8= " << e_8; - omega_8 = static_cast(read_navigation_signed(data_jk_bits, omega_8_bit)); - omega_8 = omega_8 * omega_8_LSB; - DLOG(INFO) << "omega_8= " << omega_8; - delta_i_8 = static_cast(read_navigation_signed(data_jk_bits, delta_i_8_bit)); - delta_i_8 = delta_i_8 * delta_i_8_LSB; - DLOG(INFO) << "delta_i_8= " << delta_i_8; - Omega0_8 = static_cast(read_navigation_signed(data_jk_bits, Omega0_8_bit)); - Omega0_8 = Omega0_8 * Omega0_8_LSB; - DLOG(INFO) << "Omega0_8= " << Omega0_8; - Omega_dot_8 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_8_bit)); - Omega_dot_8 = Omega_dot_8 * Omega_dot_8_LSB; - DLOG(INFO) << "Omega_dot_8= " << Omega_dot_8; - flag_almanac_2 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 8: // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ + IOD_a_8 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_8_bit)); + DLOG(INFO) << "IOD_a_8= " << IOD_a_8; + af0_8 = static_cast(read_navigation_signed(data_jk_bits, af0_8_bit)); + af0_8 = af0_8 * af0_8_LSB; + DLOG(INFO) << "af0_8= " << af0_8; + af1_8 = static_cast(read_navigation_signed(data_jk_bits, af1_8_bit)); + af1_8 = af1_8 * af1_8_LSB; + DLOG(INFO) << "af1_8= " << af1_8; + E5b_HS_8 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_8_bit)); + DLOG(INFO) << "E5b_HS_8= " << E5b_HS_8; + E1B_HS_8 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_8_bit)); + DLOG(INFO) << "E1B_HS_8= " << E1B_HS_8; + SVID2_8 = static_cast(read_navigation_unsigned(data_jk_bits, SVID2_8_bit)); + DLOG(INFO) << "SVID2_8= " << SVID2_8; + DELTA_A_8 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_8_bit)); + DELTA_A_8 = DELTA_A_8 * DELTA_A_8_LSB; + DLOG(INFO) << "DELTA_A_8= " << DELTA_A_8; + e_8 = static_cast(read_navigation_unsigned(data_jk_bits, e_8_bit)); + e_8 = e_8 * e_8_LSB; + DLOG(INFO) << "e_8= " << e_8; + omega_8 = static_cast(read_navigation_signed(data_jk_bits, omega_8_bit)); + omega_8 = omega_8 * omega_8_LSB; + DLOG(INFO) << "omega_8= " << omega_8; + delta_i_8 = static_cast(read_navigation_signed(data_jk_bits, delta_i_8_bit)); + delta_i_8 = delta_i_8 * delta_i_8_LSB; + DLOG(INFO) << "delta_i_8= " << delta_i_8; + Omega0_8 = static_cast(read_navigation_signed(data_jk_bits, Omega0_8_bit)); + Omega0_8 = Omega0_8 * Omega0_8_LSB; + DLOG(INFO) << "Omega0_8= " << Omega0_8; + Omega_dot_8 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_8_bit)); + Omega_dot_8 = Omega_dot_8 * Omega_dot_8_LSB; + DLOG(INFO) << "Omega_dot_8= " << Omega_dot_8; + flag_almanac_2 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 9: /*Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2)*/ - IOD_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_9_bit)); - DLOG(INFO) << "IOD_a_9= " << IOD_a_9; - WN_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, WN_a_9_bit)); - DLOG(INFO) << "WN_a_9= " << WN_a_9; - t0a_9 = static_cast(read_navigation_unsigned(data_jk_bits, t0a_9_bit)); - t0a_9 = t0a_9 * t0a_9_LSB; - DLOG(INFO) << "t0a_9= " << t0a_9; - M0_9 = static_cast(read_navigation_signed(data_jk_bits, M0_9_bit)); - M0_9 = M0_9 * M0_9_LSB; - DLOG(INFO) << "M0_9= " << M0_9; - af0_9 = static_cast(read_navigation_signed(data_jk_bits, af0_9_bit)); - af0_9 = af0_9 * af0_9_LSB; - DLOG(INFO) << "af0_9= " << af0_9; - af1_9 = static_cast(read_navigation_signed(data_jk_bits, af1_9_bit)); - af1_9 = af1_9 * af1_9_LSB; - DLOG(INFO) << "af1_9= " << af1_9; - E5b_HS_9 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_9_bit)); - DLOG(INFO) << "E5b_HS_9= " << E5b_HS_9; - E1B_HS_9 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_9_bit)); - DLOG(INFO) << "E1B_HS_9= " << E1B_HS_9; - SVID3_9 = static_cast(read_navigation_unsigned(data_jk_bits, SVID3_9_bit)); - DLOG(INFO) << "SVID3_9= " << SVID3_9; - DELTA_A_9 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_9_bit)); - DELTA_A_9 = DELTA_A_9 * DELTA_A_9_LSB; - DLOG(INFO) << "DELTA_A_9= " << DELTA_A_9; - e_9 = static_cast(read_navigation_unsigned(data_jk_bits, e_9_bit)); - e_9 = e_9 * e_9_LSB; - DLOG(INFO) << "e_9= " << e_9; - omega_9 = static_cast(read_navigation_signed(data_jk_bits, omega_9_bit)); - omega_9 = omega_9 * omega_9_LSB; - DLOG(INFO) << "omega_9= " << omega_9; - delta_i_9 = static_cast(read_navigation_signed(data_jk_bits, delta_i_9_bit)); - delta_i_9 = delta_i_9 * delta_i_9_LSB; - DLOG(INFO) << "delta_i_9= " << delta_i_9; - flag_almanac_3 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 9: // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2) + IOD_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_9_bit)); + DLOG(INFO) << "IOD_a_9= " << IOD_a_9; + WN_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, WN_a_9_bit)); + DLOG(INFO) << "WN_a_9= " << WN_a_9; + t0a_9 = static_cast(read_navigation_unsigned(data_jk_bits, t0a_9_bit)); + t0a_9 = t0a_9 * t0a_9_LSB; + DLOG(INFO) << "t0a_9= " << t0a_9; + M0_9 = static_cast(read_navigation_signed(data_jk_bits, M0_9_bit)); + M0_9 = M0_9 * M0_9_LSB; + DLOG(INFO) << "M0_9= " << M0_9; + af0_9 = static_cast(read_navigation_signed(data_jk_bits, af0_9_bit)); + af0_9 = af0_9 * af0_9_LSB; + DLOG(INFO) << "af0_9= " << af0_9; + af1_9 = static_cast(read_navigation_signed(data_jk_bits, af1_9_bit)); + af1_9 = af1_9 * af1_9_LSB; + DLOG(INFO) << "af1_9= " << af1_9; + E5b_HS_9 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_9_bit)); + DLOG(INFO) << "E5b_HS_9= " << E5b_HS_9; + E1B_HS_9 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_9_bit)); + DLOG(INFO) << "E1B_HS_9= " << E1B_HS_9; + SVID3_9 = static_cast(read_navigation_unsigned(data_jk_bits, SVID3_9_bit)); + DLOG(INFO) << "SVID3_9= " << SVID3_9; + DELTA_A_9 = static_cast(read_navigation_signed(data_jk_bits, DELTA_A_9_bit)); + DELTA_A_9 = DELTA_A_9 * DELTA_A_9_LSB; + DLOG(INFO) << "DELTA_A_9= " << DELTA_A_9; + e_9 = static_cast(read_navigation_unsigned(data_jk_bits, e_9_bit)); + e_9 = e_9 * e_9_LSB; + DLOG(INFO) << "e_9= " << e_9; + omega_9 = static_cast(read_navigation_signed(data_jk_bits, omega_9_bit)); + omega_9 = omega_9 * omega_9_LSB; + DLOG(INFO) << "omega_9= " << omega_9; + delta_i_9 = static_cast(read_navigation_signed(data_jk_bits, delta_i_9_bit)); + delta_i_9 = delta_i_9 * delta_i_9_LSB; + DLOG(INFO) << "delta_i_9= " << delta_i_9; + flag_almanac_3 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 10: /*Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters*/ - IOD_a_10 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_10_bit)); - DLOG(INFO) << "IOD_a_10= " << IOD_a_10; - Omega0_10 = static_cast(read_navigation_signed(data_jk_bits, Omega0_10_bit)); - Omega0_10 = Omega0_10 * Omega0_10_LSB; - DLOG(INFO) << "Omega0_10= " << Omega0_10; - Omega_dot_10 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_10_bit)); - Omega_dot_10 = Omega_dot_10 * Omega_dot_10_LSB; - DLOG(INFO) << "Omega_dot_10= " << Omega_dot_10 ; - M0_10 = static_cast(read_navigation_signed(data_jk_bits, M0_10_bit)); - M0_10 = M0_10 * M0_10_LSB; - DLOG(INFO) << "M0_10= " << M0_10; - af0_10 = static_cast(read_navigation_signed(data_jk_bits, af0_10_bit)); - af0_10 = af0_10 * af0_10_LSB; - DLOG(INFO) << "af0_10= " << af0_10; - af1_10 = static_cast(read_navigation_signed(data_jk_bits, af1_10_bit)); - af1_10 = af1_10 * af1_10_LSB; - DLOG(INFO) << "af1_10= " << af1_10; - E5b_HS_10 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_10_bit)); - DLOG(INFO) << "E5b_HS_10= " << E5b_HS_10; - E1B_HS_10 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_10_bit)); - DLOG(INFO) << "E1B_HS_10= " << E1B_HS_10; - A_0G_10 = static_cast(read_navigation_signed(data_jk_bits, A_0G_10_bit)); - A_0G_10 = A_0G_10 * A_0G_10_LSB; - flag_GGTO_1=true; - DLOG(INFO) << "A_0G_10= " << A_0G_10; - A_1G_10 = static_cast(read_navigation_signed(data_jk_bits, A_1G_10_bit)); - A_1G_10 = A_1G_10 * A_1G_10_LSB; - flag_GGTO_2=true; - DLOG(INFO) << "A_1G_10= " << A_1G_10; - t_0G_10 = static_cast(read_navigation_unsigned(data_jk_bits, t_0G_10_bit)); - t_0G_10 = t_0G_10 * t_0G_10_LSB; - flag_GGTO_3=true; - DLOG(INFO) << "t_0G_10= " << t_0G_10; - WN_0G_10 = static_cast(read_navigation_unsigned(data_jk_bits, WN_0G_10_bit)); - flag_GGTO_4=true; - DLOG(INFO) << "WN_0G_10= " << WN_0G_10; - flag_almanac_4 = true; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; + case 10: // Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters + IOD_a_10 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_a_10_bit)); + DLOG(INFO) << "IOD_a_10= " << IOD_a_10; + Omega0_10 = static_cast(read_navigation_signed(data_jk_bits, Omega0_10_bit)); + Omega0_10 = Omega0_10 * Omega0_10_LSB; + DLOG(INFO) << "Omega0_10= " << Omega0_10; + Omega_dot_10 = static_cast(read_navigation_signed(data_jk_bits, Omega_dot_10_bit)); + Omega_dot_10 = Omega_dot_10 * Omega_dot_10_LSB; + DLOG(INFO) << "Omega_dot_10= " << Omega_dot_10; + M0_10 = static_cast(read_navigation_signed(data_jk_bits, M0_10_bit)); + M0_10 = M0_10 * M0_10_LSB; + DLOG(INFO) << "M0_10= " << M0_10; + af0_10 = static_cast(read_navigation_signed(data_jk_bits, af0_10_bit)); + af0_10 = af0_10 * af0_10_LSB; + DLOG(INFO) << "af0_10= " << af0_10; + af1_10 = static_cast(read_navigation_signed(data_jk_bits, af1_10_bit)); + af1_10 = af1_10 * af1_10_LSB; + DLOG(INFO) << "af1_10= " << af1_10; + E5b_HS_10 = static_cast(read_navigation_unsigned(data_jk_bits, E5b_HS_10_bit)); + DLOG(INFO) << "E5b_HS_10= " << E5b_HS_10; + E1B_HS_10 = static_cast(read_navigation_unsigned(data_jk_bits, E1B_HS_10_bit)); + DLOG(INFO) << "E1B_HS_10= " << E1B_HS_10; + A_0G_10 = static_cast(read_navigation_signed(data_jk_bits, A_0G_10_bit)); + A_0G_10 = A_0G_10 * A_0G_10_LSB; + flag_GGTO_1 = true; + DLOG(INFO) << "A_0G_10= " << A_0G_10; + A_1G_10 = static_cast(read_navigation_signed(data_jk_bits, A_1G_10_bit)); + A_1G_10 = A_1G_10 * A_1G_10_LSB; + flag_GGTO_2 = true; + DLOG(INFO) << "A_1G_10= " << A_1G_10; + t_0G_10 = static_cast(read_navigation_unsigned(data_jk_bits, t_0G_10_bit)); + t_0G_10 = t_0G_10 * t_0G_10_LSB; + flag_GGTO_3 = true; + DLOG(INFO) << "t_0G_10= " << t_0G_10; + WN_0G_10 = static_cast(read_navigation_unsigned(data_jk_bits, WN_0G_10_bit)); + flag_GGTO_4 = true; + DLOG(INFO) << "WN_0G_10= " << WN_0G_10; + flag_almanac_4 = true; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; - case 0: /*Word type 0: I/NAV Spare Word*/ - Time_0 = static_cast(read_navigation_unsigned(data_jk_bits, Time_0_bit)); - DLOG(INFO) << "Time_0= " << Time_0; - WN_0 = static_cast(read_navigation_unsigned(data_jk_bits, WN_0_bit)); - DLOG(INFO) << "WN_0= " << WN_0; - TOW_0 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_0_bit)); - DLOG(INFO) << "TOW_0= " << TOW_0; - DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - break; - } + case 0: // Word type 0: I/NAV Spare Word + Time_0 = static_cast(read_navigation_unsigned(data_jk_bits, Time_0_bit)); + DLOG(INFO) << "Time_0= " << Time_0; + WN_0 = static_cast(read_navigation_unsigned(data_jk_bits, WN_0_bit)); + DLOG(INFO) << "WN_0= " << WN_0; + TOW_0 = static_cast(read_navigation_unsigned(data_jk_bits, TOW_0_bit)); + DLOG(INFO) << "TOW_0= " << TOW_0; + DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + break; + } return page_number; } - - diff --git a/src/core/system_parameters/galileo_navigation_message.h b/src/core/system_parameters/galileo_navigation_message.h index e83b67cf3..cf1eb0a0f 100644 --- a/src/core/system_parameters/galileo_navigation_message.h +++ b/src/core/system_parameters/galileo_navigation_message.h @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,17 +33,18 @@ #ifndef GNSS_SDR_GALILEO_NAVIGATION_MESSAGE_H_ #define GNSS_SDR_GALILEO_NAVIGATION_MESSAGE_H_ +#include "Galileo_E1.h" +#include "galileo_almanac_helper.h" +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" #include +#include #include #include #include #include -#include // for boost::uint32_t -#include "galileo_ephemeris.h" -#include "galileo_iono.h" -#include "galileo_almanac.h" -#include "galileo_utc_model.h" -#include "Galileo_E1.h" + /*! * \brief This class handles the Galileo I/NAV Data message, as described in the @@ -53,15 +54,15 @@ class Galileo_Navigation_Message { private: - bool CRC_test(std::bitset bits, boost::uint32_t checksum); - bool read_navigation_bool(std::bitset bits, const std::vector > parameter); - //void print_galileo_word_bytes(unsigned int GPS_word); - unsigned long int read_navigation_unsigned(std::bitset bits, const std::vector< std::pair > parameter); - unsigned long int read_page_type_unsigned(std::bitset bits, const std::vector< std::pair > parameter); - signed long int read_navigation_signed(std::bitset bits, const std::vector > parameter); + bool CRC_test(std::bitset bits, uint32_t checksum); + bool read_navigation_bool(std::bitset bits, const std::vector >& parameter); + uint64_t read_navigation_unsigned(std::bitset bits, const std::vector >& parameter); + uint64_t read_page_type_unsigned(std::bitset bits, const std::vector >& parameter); + int64_t read_navigation_signed(std::bitset bits, const std::vector >& parameter); + public: - int Page_type_time_stamp; - int flag_even_word; + int32_t Page_type_time_stamp; + int32_t flag_even_word; std::string page_Even; bool flag_CRC_test; bool flag_all_ephemeris; //!< Flag indicating that all words containing ephemeris have been received @@ -70,19 +71,19 @@ public: bool flag_ephemeris_3; //!< Flag indicating that ephemeris 3/4 (word 3) have been received bool flag_ephemeris_4; //!< Flag indicating that ephemeris 4/4 (word 4) have been received - bool flag_iono_and_GST; //!< Flag indicating that ionospheric and GST parameters (word 5) have been received + bool flag_iono_and_GST; //!< Flag indicating that ionospheric and GST parameters (word 5) have been received bool flag_TOW_5; bool flag_TOW_6; - bool flag_TOW_set; //!< it is true when page 5 or page 6 arrives - bool flag_utc_model; //!< Flag indicating that utc model parameters (word 6) have been received + bool flag_TOW_set; //!< it is true when page 5 or page 6 arrives + bool flag_utc_model; //!< Flag indicating that utc model parameters (word 6) have been received - bool flag_all_almanac; //!< Flag indicating that all almanac have been received - bool flag_almanac_1; //!< Flag indicating that almanac 1/4 (word 7) have been received - bool flag_almanac_2; //!< Flag indicating that almanac 2/4 (word 8) have been received - bool flag_almanac_3; //!< Flag indicating that almanac 3/4 (word 9) have been received - bool flag_almanac_4; //!< Flag indicating that almanac 4/4 (word 10) have been received + bool flag_all_almanac; //!< Flag indicating that all almanac have been received + bool flag_almanac_1; //!< Flag indicating that almanac 1/4 (word 7) have been received + bool flag_almanac_2; //!< Flag indicating that almanac 2/4 (word 8) have been received + bool flag_almanac_3; //!< Flag indicating that almanac 3/4 (word 9) have been received + bool flag_almanac_4; //!< Flag indicating that almanac 4/4 (word 10) have been received - int IOD_ephemeris; + int32_t IOD_ephemeris; bool flag_GGTO; bool flag_GGTO_1; @@ -90,82 +91,84 @@ public: bool flag_GGTO_3; bool flag_GGTO_4; - /*Word type 1: Ephemeris (1/4)*/ - int IOD_nav_1; //!< IOD_nav page 1 - double t0e_1; //!< Ephemeris reference time [s] - double M0_1; //!< Mean anomaly at reference time [semi-circles] - double e_1; //!< Eccentricity - double A_1; //!< Square root of the semi-major axis [metres^1/2] + // Word type 1: Ephemeris (1/4) + int32_t IOD_nav_1; //!< IOD_nav page 1 + int32_t t0e_1; //!< Ephemeris reference time [s] + double M0_1; //!< Mean anomaly at reference time [semi-circles] + double e_1; //!< Eccentricity + double A_1; //!< Square root of the semi-major axis [meters^1/2] - /*Word type 2: Ephemeris (2/4)*/ - int IOD_nav_2; //!< IOD_nav page 2 - double OMEGA_0_2; //!< Longitude of ascending node of orbital plane at weekly epoch [semi-circles] - double i_0_2; //!< Inclination angle at reference time [semi-circles] - double omega_2; //!< Argument of perigee [semi-circles] - double iDot_2; //!< Rate of inclination angle [semi-circles/sec] + // Word type 2: Ephemeris (2/4) + int32_t IOD_nav_2; //!< IOD_nav page 2 + double OMEGA_0_2; //!< Longitude of ascending node of orbital plane at weekly epoch [semi-circles] + double i_0_2; //!< Inclination angle at reference time [semi-circles] + double omega_2; //!< Argument of perigee [semi-circles] + double iDot_2; //!< Rate of inclination angle [semi-circles/sec] - /*Word type 3: Ephemeris (3/4) and SISA*/ - int IOD_nav_3; // - double OMEGA_dot_3; //!< Rate of right ascension [semi-circles/sec] - double delta_n_3; //!< Mean motion difference from computed value [semi-circles/sec] - double C_uc_3; //!< Amplitude of the cosine harmonic correction term to the argument of latitude [radians] - double C_us_3; //!< Amplitude of the sine harmonic correction term to the argument of latitude [radians] - double C_rc_3; //!< Amplitude of the cosine harmonic correction term to the orbit radius [meters] - double C_rs_3; //!< Amplitude of the sine harmonic correction term to the orbit radius [meters] - double SISA_3; + // Word type 3: Ephemeris (3/4) and SISA + int32_t IOD_nav_3; // + double OMEGA_dot_3; //!< Rate of right ascension [semi-circles/sec] + double delta_n_3; //!< Mean motion difference from computed value [semi-circles/sec] + double C_uc_3; //!< Amplitude of the cosine harmonic correction term to the argument of latitude [radians] + double C_us_3; //!< Amplitude of the sine harmonic correction term to the argument of latitude [radians] + double C_rc_3; //!< Amplitude of the cosine harmonic correction term to the orbit radius [meters] + double C_rs_3; //!< Amplitude of the sine harmonic correction term to the orbit radius [meters] + int32_t SISA_3; - /*Word type 4: Ephemeris (4/4) and Clock correction parameters*/ - int IOD_nav_4; // - int SV_ID_PRN_4; // - double C_ic_4; //!. + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,10 +33,9 @@ Galileo_Utc_Model::Galileo_Utc_Model() { - //valid = false; - /*Word type 6: GST-UTC conversion parameters*/ - A0_6 = 0; - A1_6 = 0; + // Word type 6: GST-UTC conversion parameters + A0_6 = 0.0; + A1_6 = 0.0; Delta_tLS_6 = 0; t0t_6 = 0; WNot_6 = 0; @@ -44,21 +43,27 @@ Galileo_Utc_Model::Galileo_Utc_Model() DN_6 = 0; Delta_tLSF_6 = 0; flag_utc_model = false; + // GPS to Galileo GST conversion parameters + A_0G_10 = 0.0; + A_1G_10 = 0.0; + t_0G_10 = 0; + WN_0G_10 = 0; } -double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int WN) + +double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) { double t_Utc; double t_Utc_daytime; double Delta_t_Utc = 0; // Determine if the effectivity time of the leap second event is in the past - int weeksToLeapSecondEvent = WN_LSF_6 - (WN % 256); + int32_t weeksToLeapSecondEvent = WN_LSF_6 - (WN % 256); - if ((weeksToLeapSecondEvent) >= 0) // is not in the past + if ((weeksToLeapSecondEvent) >= 0) // is not in the past { - //Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s + // Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s int secondOfLeapSecondEvent = DN_6 * 24 * 60 * 60; - if (std::abs(t_e - secondOfLeapSecondEvent) > 21600) + if (std::abs(t_e - secondOfLeapSecondEvent) > 21600) { /* 5.1.7a GST->UTC case a * Whenever the leap second adjusted time indicated by the WN_LSF and the DN values @@ -67,23 +72,23 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int WN) * to the effective time and ends at six hours after the effective time, * the GST/Utc relationship is given by */ - Delta_t_Utc = Delta_tLS_6 + A0_6 + A1_6 * (t_e - t0t_6 + 604800 * static_cast((WN % 256) - WNot_6)); + Delta_t_Utc = Delta_tLS_6 + A0_6 + A1_6 * (t_e - t0t_6 + 604800 * static_cast((WN % 256) - WNot_6)); t_Utc_daytime = fmod(t_e - Delta_t_Utc, 86400); } else { /* 5.1.7b GST->UTC case b * Whenever the user's current time falls within the time span of six hours - * prior to the leap second adjustment to six hours after the adjustment time, , + * prior to the leap second adjustment to six hours after the adjustment time, * the effective time is computed according to the following equations: */ - Delta_t_Utc = Delta_tLS_6 + A0_6 + A1_6 * (t_e - t0t_6 + 604800 * static_cast((WN % 256) - WNot_6)); + Delta_t_Utc = Delta_tLS_6 + A0_6 + A1_6 * (t_e - t0t_6 + 604800 * static_cast((WN % 256) - WNot_6)); double W = fmod(t_e - Delta_t_Utc - 43200, 86400) + 43200; t_Utc_daytime = fmod(W, 86400 + Delta_tLSF_6 - Delta_tLS_6); //implement something to handle a leap second event! } } - else // the effectivity time is in the past + else // the effectivity time is in the past { /* 5.1.7c GST->UTC case c * Whenever the leap second adjustment time, as indicated by the WN_LSF and DN values, @@ -100,4 +105,3 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int WN) t_Utc = secondsOfWeekBeforeToday + t_Utc_daytime; return t_Utc; } - diff --git a/src/core/system_parameters/galileo_utc_model.h b/src/core/system_parameters/galileo_utc_model.h index aa3ef8723..7e9e328b0 100644 --- a/src/core/system_parameters/galileo_utc_model.h +++ b/src/core/system_parameters/galileo_utc_model.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,6 +33,8 @@ #ifndef GNSS_SDR_GALILEO_UTC_MODEL_H_ #define GNSS_SDR_GALILEO_UTC_MODEL_H_ +#include +#include /*! * \brief This class is a storage for the GALILEO UTC MODEL data as described in Galileo ICD @@ -42,22 +44,52 @@ class Galileo_Utc_Model { public: - /*Word type 6: GST-UTC conversion parameters*/ + // Word type 6: GST-UTC conversion parameters double A0_6; double A1_6; - double Delta_tLS_6; - double t0t_6; //!< UTC data reference Time of Week [s] - double WNot_6; //!< UTC data reference Week number [week] - double WN_LSF_6; - double DN_6; - double Delta_tLSF_6; + int32_t Delta_tLS_6; + int32_t t0t_6; //!< UTC data reference Time of Week [s] + int32_t WNot_6; //!< UTC data reference Week number [week] + int32_t WN_LSF_6; + int32_t DN_6; + int32_t Delta_tLSF_6; bool flag_utc_model; + + // GPS to Galileo GST conversion parameters + double A_0G_10; + double A_1G_10; + int32_t t_0G_10; + int32_t WN_0G_10; + //double TOW_6; - double GST_to_UTC_time(double t_e, int WN); //!< GST-UTC Conversion Algorithm and Parameters + double GST_to_UTC_time(double t_e, int32_t WN); //!< GST-UTC Conversion Algorithm and Parameters /*! * Default constructor */ Galileo_Utc_Model(); + + template + + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. + Here is used to save the UTC data on disk file. + */ + inline void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + archive& make_nvp("A0_6", A0_6); + archive& make_nvp("A1_6", A1_6); + archive& make_nvp("Delta_tLS_6", Delta_tLS_6); + archive& make_nvp("t0t_6", t0t_6); + archive& make_nvp("WNot_6", WNot_6); + archive& make_nvp("WN_LSF_6", WN_LSF_6); + archive& make_nvp("DN_6", DN_6); + archive& make_nvp("Delta_tLSF_6", Delta_tLSF_6); + archive& make_nvp("flag_utc_model", flag_utc_model); + } }; #endif diff --git a/src/core/system_parameters/glonass_gnav_almanac.cc b/src/core/system_parameters/glonass_gnav_almanac.cc new file mode 100644 index 000000000..e89d31f64 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_almanac.cc @@ -0,0 +1,55 @@ +/*! + * \file glonass_gnav_almanac.cc + * \brief Interface of a GLONASS GNAV ALMANAC storage as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_almanac.h" + +Glonass_Gnav_Almanac::Glonass_Gnav_Almanac() +{ + i_satellite_freq_channel = 0; + i_satellite_PRN = 0U; + i_satellite_slot_number = 0U; + + d_n_A = 0.0; + d_H_n_A = 0.0; + d_lambda_n_A = 0.0; + d_t_lambda_n_A = 0.0; + d_Delta_i_n_A = 0.0; + d_Delta_T_n_A = 0.0; + d_Delta_T_n_A_dot = 0.0; + d_epsilon_n_A = 0.0; + d_omega_n_A = 0.0; + d_M_n_A = 0.0; + d_KP = 0.0; + d_tau_n_A = 0.0; + d_C_n = false; + d_l_n = false; +} diff --git a/src/core/system_parameters/glonass_gnav_almanac.h b/src/core/system_parameters/glonass_gnav_almanac.h new file mode 100644 index 000000000..37927bc6b --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_almanac.h @@ -0,0 +1,104 @@ +/*! + * \file glonass_gnav_almanac.h + * \brief Interface of a GLONASS GNAV ALMANAC storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_ALMANAC_H_ +#define GNSS_SDR_GLONASS_ALMANAC_H_ + +#include +#include + +/*! + * \brief This class is a storage for the GLONASS SV ALMANAC data as described GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Almanac +{ +public: + double d_n_A; //!< Conventional number of satellite within GLONASS space segment [dimensionless] + double d_H_n_A; //!< Carrier frequency number of navigation RF signal transmitted by d_nA satellite as table 4.10 (0-31) [dimensionless] + double d_lambda_n_A; //!< Longitude of the first (within the d_NA day) ascending node of d_nA [radians] + double d_t_lambda_n_A; //!< Time of first ascending node passage [s] + double d_Delta_i_n_A; //!< Correction of the mean value of inclination of d_n_A satellite at instant t_lambda_n_A [radians] + double d_Delta_T_n_A; //!< Correction to the mean value of Draconian period of d_n_A satellite at instant t_lambda_n_A [s / orbital period] + double d_Delta_T_n_A_dot; //!< Rate of change of Draconian period of d_n_A satellite at instant t_lambda_n_A [s / orbital period^2] + double d_epsilon_n_A; //!< Eccentricity of d_n_A satellite at instant t_lambda_n_A [dimensionless] + double d_omega_n_A; //!< Argument of perigee of d_n_A satellite at instant t_lambdan_A [radians] + double d_M_n_A; //!< Type of satellite n_A [dimensionless] + double d_KP; //!< Notification on forthcoming leap second correction of UTC [dimensionless] + double d_tau_n_A; //!< Coarse value of d_n_A satellite time correction to GLONASS time at instant t_lambdan_A[s] + bool d_C_n; //!< Generalized “unhealthy flag” of n_A satellite at instant of almanac upload [dimensionless] + bool d_l_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + + // Satellite Identification Information + int32_t i_satellite_freq_channel; //!< SV Frequency Channel Number + uint32_t i_satellite_PRN; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + uint32_t i_satellite_slot_number; //!< SV Slot Number + + template + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the almanac data on disk file. + */ + void serialize(Archive& archive, const uint32_t version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + + archive& make_nvp("i_satellite_freq_channel", i_satellite_freq_channel); + archive& make_nvp("i_satellite_PRN", i_satellite_PRN); + archive& make_nvp("i_satellite_slot_number", i_satellite_slot_number); + archive& make_nvp("d_n_A", d_n_A); + archive& make_nvp("d_H_n_A", d_H_n_A); + archive& make_nvp("d_lambda_n_A", d_lambda_n_A); + archive& make_nvp("d_t_lambda_n_A", d_t_lambda_n_A); + archive& make_nvp("d_Delta_i_n_A", d_Delta_i_n_A); + archive& make_nvp("d_Delta_T_n_A", d_Delta_T_n_A); + archive& make_nvp("d_Delta_T_n_A_dot", d_Delta_T_n_A_dot); + archive& make_nvp("d_epsilon_n_A", d_epsilon_n_A); + archive& make_nvp("d_omega_n_A", d_omega_n_A); + archive& make_nvp("d_M_n_A", d_M_n_A); + archive& make_nvp("d_KP", d_KP); + archive& make_nvp("d_tau_n_A", d_tau_n_A); + archive& make_nvp("d_C_n", d_C_n); + archive& make_nvp("d_l_n", d_l_n); + } + + /*! + * Default constructor + */ + Glonass_Gnav_Almanac(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.cc b/src/core/system_parameters/glonass_gnav_ephemeris.cc new file mode 100644 index 000000000..1e0941dd7 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_ephemeris.cc @@ -0,0 +1,192 @@ +/*! + * \file glonass_gnav_ephemeris.cc + * \brief Interface of a GLONASS GNAV EPHEMERIS storage and orbital model functions + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_ephemeris.h" +#include "GLONASS_L1_L2_CA.h" +#include "gnss_satellite.h" +#include + + +Glonass_Gnav_Ephemeris::Glonass_Gnav_Ephemeris() +{ + d_m = 0.0; //!< String number within frame [dimensionless] + d_t_k = 0.0; //!< GLONASS Time (UTC(SU) + 3 h) referenced to the beginning of the frame within the current day [s] + d_t_b = 0.0; //!< Reference ephemeris relative time in GLONASS Time (UTC(SU) + 3 h). Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [s] + d_M = 0.0; //!< Type of satellite transmitting navigation signal [dimensionless] + d_gamma_n = 0.0; //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + d_tau_n = 0.0; //!< Correction to the nth satellite time (tn) relative to GLONASS time (te), + d_Xn = 0.0; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + d_Yn = 0.0; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + d_Zn = 0.0; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + d_VXn = 0.0; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + d_VYn = 0.0; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + d_VZn = 0.0; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + d_AXn = 0.0; //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + d_AYn = 0.0; //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + d_AZn = 0.0; //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + d_B_n = 0.0; //!< Health flag [dimensionless] + d_P = 0.0; //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + d_N_T = 0.0; //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + d_F_T = 0.0; //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + d_n = 0.0; //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + d_Delta_tau_n = 0.0; //!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + d_E_n = 0.0; //!< Characterises "age" of a current information [days] + d_P_1 = 0.0; //!< Flag of the immediate data updating [minutes] + d_P_2 = false; //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + d_P_3 = false; //!< Flag indicating a number of satellites for which almanac is transmitted within given frame: "1" corresponds to 5 satellites and "0" corresponds to 4 satellites [dimensionless] + d_P_4 = false; //!< Flag to show that ephemeris parameters are present. "1" indicates that updated ephemeris or frequency/time parameters have been uploaded by the control segment [dimensionless] + d_l3rd_n = false; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + d_l5th_n = false; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + + // Satellite Identification Information + i_satellite_freq_channel = 0; //!< SV Frequency Channel Number + i_satellite_PRN = 0U; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + i_satellite_slot_number = 0U; //!< SV Slot Number + d_yr = 1972; //!< Current year, defaults to 1972 (UTC Epoch with leap seconds) + d_satClkDrift = 0.0; //!< GLONASS clock error + d_dtr = 0.0; //!< relativistic clock correction term + d_iode = 0.0; //!< Issue of data, ephemeris (Bit 0-6 of tb) + d_tau_c = 0.0; + d_TOW = 0.0; // tow of the start of frame + d_WN = 0.0; // week number of the start of frame + d_tod = 0.0; +} + + +boost::posix_time::ptime Glonass_Gnav_Ephemeris::compute_GLONASS_time(const double offset_time) const +{ + boost::posix_time::time_duration t(0, 0, offset_time + d_tau_c + d_tau_n); + boost::gregorian::date d1(d_yr, 1, 1); + boost::gregorian::days d2(d_N_T - 1); + boost::posix_time::ptime glonass_time(d1 + d2, t); + + return glonass_time; +} + + +boost::posix_time::ptime Glonass_Gnav_Ephemeris::glot_to_utc(const double offset_time, const double glot2utc_corr) const +{ + double tod = 0.0; + double glot2utc = 3 * 3600; + + tod = offset_time - glot2utc + glot2utc_corr + d_tau_n; + boost::posix_time::time_duration t(0, 0, tod); + boost::gregorian::date d1(d_yr, 1, 1); + boost::gregorian::days d2(d_N_T - 1); + boost::posix_time::ptime utc_time(d1 + d2, t); + + return utc_time; +} + + +void Glonass_Gnav_Ephemeris::glot_to_gpst(double tod_offset, double glot2utc_corr, double glot2gpst_corr, double* wn, double* tow) const +{ + double tod = 0.0; + double glot2utc = 3 * 3600; + double days = 0.0; + double total_sec = 0.0, sec_of_day = 0.0; + int i = 0; + + boost::gregorian::date gps_epoch{1980, 1, 6}; + + // tk is relative to UTC(SU) + 3.00 hrs, so we need to convert to utc and add corrections + // tk plus 10 sec is the true tod since get_TOW is called when in str5 + tod = tod_offset - glot2utc; + + boost::posix_time::time_duration t(0, 0, tod); + boost::gregorian::date d1(d_yr, 1, 1); + boost::gregorian::days d2(d_N_T - 1); + boost::posix_time::ptime utc_time(d1 + d2, t); + boost::gregorian::date utc_date = utc_time.date(); + boost::posix_time::ptime gps_time; + + // Adjust for leap second correction + for (i = 0; GLONASS_LEAP_SECONDS[i][0] > 0; i++) + { + boost::posix_time::time_duration t3(GLONASS_LEAP_SECONDS[i][3], GLONASS_LEAP_SECONDS[i][4], GLONASS_LEAP_SECONDS[i][5]); + boost::gregorian::date d3(GLONASS_LEAP_SECONDS[i][0], GLONASS_LEAP_SECONDS[i][1], GLONASS_LEAP_SECONDS[i][2]); + boost::posix_time::ptime ls_time(d3, t3); + if (utc_time >= ls_time) + { + // We add the leap second when going from utc to gpst + gps_time = utc_time + boost::posix_time::time_duration(0, 0, fabs(GLONASS_LEAP_SECONDS[i][6])); + break; + } + } + + // Total number of days + std::string fdat = boost::posix_time::to_simple_string(gps_time); + days = static_cast((utc_date - gps_epoch).days()); + + // Total number of seconds + sec_of_day = static_cast((gps_time.time_of_day()).total_seconds()); + total_sec = days * 86400 + sec_of_day; + + // Compute Week number + *wn = floor(total_sec / 604800); + + // Compute the arithmetic modules to wrap around range + *tow = total_sec - 604800 * floor(total_sec / 604800); + // Perform corrections from fractional seconds + *tow += glot2utc_corr + glot2gpst_corr; +} + + +double Glonass_Gnav_Ephemeris::check_t(double time) +{ + double corrTime; + double half_day = 43200.0; // seconds + corrTime = time; + if (time > half_day) + { + corrTime = time - 2.0 * half_day; + } + else if (time < -half_day) + { + corrTime = time + 2.0 * half_day; + } + return corrTime; +} + + +// FIXME Fix reference here +// 20.3.3.3.3.1 User Algorithm for SV Clock Correction. +double Glonass_Gnav_Ephemeris::sv_clock_drift(double transmitTime, double timeCorrUTC) +{ + double dt; + dt = check_t(transmitTime - d_t_b); + d_satClkDrift = -(d_tau_n + timeCorrUTC - d_gamma_n * dt); + //Correct satellite group delay and missing relativistic term here + //d_satClkDrift-=d_TGD; + + return d_satClkDrift; +} diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.h b/src/core/system_parameters/glonass_gnav_ephemeris.h new file mode 100644 index 000000000..6f53a992f --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_ephemeris.h @@ -0,0 +1,186 @@ +/*! + * \file glonass_gnav_ephemeris.h + * \brief Interface of a GLONASS EPHEMERIS storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_EPHEMERIS_H_ +#define GNSS_SDR_GLONASS_GNAV_EPHEMERIS_H_ + + +#include +#include +#include + +/*! + * \brief This class is a storage and orbital model functions for the GLONASS SV ephemeris data as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Ephemeris +{ +private: + /* + * Accounts for the beginning or end of week crossover + * + * See paragraph 20.3.3.3.3.1 (IS-GPS-200E) + * \param[in] - time in seconds + * \param[out] - corrected time, in seconds + */ + double check_t(double time); + +public: + double d_m; //!< String number within frame [dimensionless] + double d_t_k; //!< GLONASS Time (UTC(SU) + 3 h) referenced to the beginning of the frame within the current day [s] + double d_t_b; //!< Reference ephemeris relative time in GLONASS Time (UTC(SU) + 3 h). Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [s] + double d_M; //!< Type of satellite transmitting navigation signal [dimensionless] + double d_gamma_n; //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + double d_tau_n; //!< Correction to the nth satellite time (tn) relative to GLONASS time (te), + double d_Xn; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + double d_Yn; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + double d_Zn; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + double d_VXn; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + double d_VYn; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + double d_VZn; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + double d_AXn; //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_AYn; //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_AZn; //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_B_n; //!< Health flag [dimensionless] + double d_P; //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + double d_N_T; //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + double d_F_T; //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + double d_n; //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + double d_Delta_tau_n; //!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + double d_E_n; //!< Characterises "age" of a current information [days] + double d_P_1; //!< Flag of the immediate data updating [minutes] + bool d_P_2; //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + bool d_P_3; //!< Flag indicating a number of satellites for which almanac is transmitted within given frame: "1" corresponds to 5 satellites and "0" corresponds to 4 satellites [dimensionless] + bool d_P_4; //!< Flag to show that ephemeris parameters are present. "1" indicates that updated ephemeris or frequency/time parameters have been uploaded by the control segment [dimensionless] + bool d_l3rd_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is healthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + bool d_l5th_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is healthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + + // Immediate deliverables of ephemeris information + // Satellite Identification Information + int32_t i_satellite_freq_channel; //!< SV Frequency Channel Number + uint32_t i_satellite_PRN; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + uint32_t i_satellite_slot_number; //!< SV Slot Number + double d_yr; //!< Current year + double d_satClkDrift; //!< GLONASS clock error + double d_dtr; //!< relativistic clock correction term + double d_iode; //!< Issue of data, ephemeris (Bit 0-6 of tb) + double d_tau_c; //!< GLONASST 2 UTC correction (todo) may be eliminated + double d_TOW; //!< GLONASST IN GPST seconds of week + double d_WN; //!< GLONASST IN GPST week number of the start of frame + double d_tod; //!< Time of Day since ephemeris where decoded + + template + + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. + */ + void serialize(Archive& archive, const uint32_t version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + + archive& make_nvp("i_satellite_freq_channel", i_satellite_freq_channel); //!< SV PRN frequency channel number + archive& make_nvp("i_satellite_PRN", i_satellite_PRN); + archive& make_nvp("i_satellite_slot_number", i_satellite_slot_number); + archive& make_nvp("d_m", d_m); //!< String number within frame [dimensionless] + archive& make_nvp("d_t_k", d_t_k); //!< Time referenced to the beginning of the frame within the current day [hours, minutes, seconds] + archive& make_nvp("d_t_b", d_t_b); //!< Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [minutes] + archive& make_nvp("d_M", d_M); //!< Type of satellite transmitting navigation signal [dimensionless] + archive& make_nvp("d_gamma_n", d_gamma_n); //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + archive& make_nvp("d_tau_n", d_tau_n); //!< Correction to the nth satellite time (tn) relative to GLONASS time (te) + archive& make_nvp("d_Xn", d_Xn); //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + archive& make_nvp("d_Yn", d_Yn); //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + archive& make_nvp("d_Zn", d_Zn); //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + archive& make_nvp("d_VXn", d_VXn); //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + archive& make_nvp("d_VYn", d_VYn); //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + archive& make_nvp("d_VZn", d_VZn); //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + archive& make_nvp("d_AXn", d_AXn); //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + archive& make_nvp("d_AYn", d_AYn); //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + archive& make_nvp("d_AZn", d_AZn); //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + archive& make_nvp("d_B_n", d_B_n); //!< Health flag [dimensionless] + archive& make_nvp("d_P", d_P); //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + archive& make_nvp("d_N_T", d_N_T); //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + archive& make_nvp("d_F_T", d_F_T); //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + archive& make_nvp("d_n", d_n); //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + archive& make_nvp("d_Delta_tau_n", d_Delta_tau_n); //!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + archive& make_nvp("d_E_n", d_E_n); //!< Characterises "age" of a current information [days] + archive& make_nvp("d_P_1", d_P_1); //!< Flag of the immediate data updating. + archive& make_nvp("d_P_2", d_P_2); //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + archive& make_nvp("d_P_3", d_P_3); //!< Flag indicating a number of satellites for which almanac is transmitted within given frame: "1" corresponds to 5 satellites and "0" corresponds to 4 satellites [dimensionless] + archive& make_nvp("d_P_4", d_P_4); //!< Flag to show that ephemeris parameters are present. "1" indicates that updated ephemeris or frequency/time parameters have been uploaded by the control segment [dimensionless] + archive& make_nvp("d_l3rd_n", d_l3rd_n); //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + archive& make_nvp("d_l5th_n", d_l5th_n); //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + } + + /*! + * \brief Sets (\a d_satClkDrift)and returns the clock drift in seconds according to the User Algorithm for SV Clock Correction + * (IS-GPS-200E, 20.3.3.3.3.1) + */ + double sv_clock_drift(double transmitTime, double timeCorrUTC); + + /*! + * \brief Computes the GLONASS System Time and returns a boost::posix_time::ptime object + * \ param offset_time Is the start of day offset to compute the time + */ + boost::posix_time::ptime compute_GLONASS_time(const double offset_time) const; + + /*! + * \brief Converts from GLONASST to UTC + * \details The function simply adjust for the 6 hrs offset between GLONASST and UTC + * \param[in] offset_time Is the start of day offset + * \param[in] glot2utc_corr Correction from GLONASST to UTC + * \returns UTC time as a boost::posix_time::ptime object + */ + boost::posix_time::ptime glot_to_utc(const double offset_time, const double glot2utc_corr) const; + + /*! + * \brief Converts from GLONASST to GPST + * \details Converts from GLONASST to GPST in time of week (TOW) and week number (WN) format + * \param[in] tod_offset Is the start of day offset + * \param[in] glot2utc_corr Correction from GLONASST to UTC + * \param[in] glot2gpst_corr Correction from GLONASST to GPST + * \param[out] WN Week Number, not in mod(1024) format + * \param[out] TOW Time of Week in seconds of week + */ + void glot_to_gpst(double tod_offset, double glot2utc_corr, double glot2gpst_corr, double* WN, double* TOW) const; + + /*! + * Default constructor + */ + Glonass_Gnav_Ephemeris(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.cc b/src/core/system_parameters/glonass_gnav_navigation_message.cc new file mode 100644 index 000000000..b2a825894 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_navigation_message.cc @@ -0,0 +1,790 @@ +/*! + * \file glonass_gnav_navigation_message.cc + * \brief Implementation of a GLONASS GNAV Data message decoder as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_navigation_message.h" +#include "gnss_satellite.h" +#include + + +void Glonass_Gnav_Navigation_Message::reset() +{ + // Satellite Identification + i_satellite_PRN = 0U; + i_alm_satellite_slot_number = 0; // SV Orbit Slot Number + flag_update_slot_number = false; + + // Ephmeris Flags + flag_all_ephemeris = false; + flag_ephemeris_str_1 = false; + flag_ephemeris_str_2 = false; + flag_ephemeris_str_3 = false; + flag_ephemeris_str_4 = false; + + // Almanac Flags + flag_all_almanac = false; + flag_almanac_str_6 = false; + flag_almanac_str_7 = false; + flag_almanac_str_8 = false; + flag_almanac_str_9 = false; + flag_almanac_str_10 = false; + flag_almanac_str_11 = false; + flag_almanac_str_12 = false; + flag_almanac_str_13 = false; + flag_almanac_str_14 = false; + flag_almanac_str_15 = false; + + // UTC and System Clocks Flags + flag_utc_model_valid = false; // If set, it indicates that the UTC model parameters are filled + flag_utc_model_str_5 = false; // Clock info send in string 5 of navigation data + flag_utc_model_str_15 = false; // Clock info send in string 15 of frame 5 of navigation data + + // broadcast orbit 1 + flag_TOW_set = false; + flag_TOW_new = false; + + flag_CRC_test = false; + d_frame_ID = 0U; + d_string_ID = 0U; + i_channel_ID = 0; + + // Clock terms + d_satClkCorr = 0.0; + d_dtr = 0.0; + d_satClkDrift = 0.0; + + // Data update information + d_previous_tb = 0.0; + for (double& i : d_previous_Na) + i = 0.0; + + std::map satelliteBlock; // Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus + + auto gnss_sat = Gnss_Satellite(); + std::string _system("GLONASS"); + //TODO SHould number of channels be hardcoded? + for (uint32_t i = 1; i < 14; i++) + { + satelliteBlock[i] = gnss_sat.what_block(_system, i); + } +} + + +Glonass_Gnav_Navigation_Message::Glonass_Gnav_Navigation_Message() +{ + reset(); +} + + +bool Glonass_Gnav_Navigation_Message::CRC_test(std::bitset bits) +{ + int32_t sum_bits = 0; + int32_t sum_hamming = 0; + int32_t C1 = 0; + int32_t C2 = 0; + int32_t C3 = 0; + int32_t C4 = 0; + int32_t C5 = 0; + int32_t C6 = 0; + int32_t C7 = 0; + int32_t C_Sigma = 0; + std::vector string_bits(GLONASS_GNAV_STRING_BITS); + + // Populate data and hamming code vectors + for (int32_t i = 0; i < static_cast(GLONASS_GNAV_STRING_BITS); i++) + { + string_bits[i] = static_cast(bits[i]); + } + + // Compute C1 term + sum_bits = 0; + for (int i : GLONASS_GNAV_CRC_I_INDEX) + { + sum_bits += string_bits[i - 1]; + } + C1 = string_bits[0] ^ (sum_bits % 2); + + // Compute C2 term + sum_bits = 0; + for (int j : GLONASS_GNAV_CRC_J_INDEX) + { + sum_bits += string_bits[j - 1]; + } + C2 = (string_bits[1]) ^ (sum_bits % 2); + + // Compute C3 term + sum_bits = 0; + for (int k : GLONASS_GNAV_CRC_K_INDEX) + { + sum_bits += string_bits[k - 1]; + } + C3 = string_bits[2] ^ (sum_bits % 2); + + // Compute C4 term + sum_bits = 0; + for (int l : GLONASS_GNAV_CRC_L_INDEX) + { + sum_bits += string_bits[l - 1]; + } + C4 = string_bits[3] ^ (sum_bits % 2); + + // Compute C5 term + sum_bits = 0; + for (int m : GLONASS_GNAV_CRC_M_INDEX) + { + sum_bits += string_bits[m - 1]; + } + C5 = string_bits[4] ^ (sum_bits % 2); + + // Compute C6 term + sum_bits = 0; + for (int n : GLONASS_GNAV_CRC_N_INDEX) + { + sum_bits += string_bits[n - 1]; + } + C6 = string_bits[5] ^ (sum_bits % 2); + + // Compute C7 term + sum_bits = 0; + for (int p : GLONASS_GNAV_CRC_P_INDEX) + { + sum_bits += string_bits[p - 1]; + } + C7 = string_bits[6] ^ (sum_bits % 2); + + // Compute C_Sigma term + sum_bits = 0; + sum_hamming = 0; + for (int q : GLONASS_GNAV_CRC_Q_INDEX) + { + sum_bits += string_bits[q - 1]; + } + for (int32_t q = 0; q < 8; q++) + { + sum_hamming += string_bits[q]; + } + C_Sigma = (sum_hamming % 2) ^ (sum_bits % 2); + + // Verification of the data + // (a-i) All checksums (C1,...,C7 and C_Sigma) are equal to zero + if ((C1 + C2 + C3 + C4 + C5 + C6 + C7 + C_Sigma) == 0) + { + return true; + } + // (a-ii) Only one of the checksums (C1,...,C7) is equal to zero but C_Sigma = 1 + if (C_Sigma == 1 && C1 + C2 + C3 + C4 + C5 + C6 + C7 == 6) + { + return true; + } + + // All other conditions are assumed errors. TODO: Add correction for case B + return false; +} + + +bool Glonass_Gnav_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector>& parameter) +{ + bool value; + + if (bits[GLONASS_GNAV_STRING_BITS - parameter[0].first] == 1) + { + value = true; + } + else + { + value = false; + } + return value; +} + + +uint64_t Glonass_Gnav_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector>& parameter) +{ + uint64_t value = 0ULL; + int32_t num_of_slices = parameter.size(); + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 0; j < parameter[i].second; j++) + { + value <<= 1; // shift left + if (bits[GLONASS_GNAV_STRING_BITS - parameter[i].first - j] == 1) + { + value += 1ULL; // insert the bit + } + } + } + return value; +} + + +int64_t Glonass_Gnav_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector>& parameter) +{ + int64_t value = 0LL; + int64_t sign = 0LL; + int32_t num_of_slices = parameter.size(); + // read the MSB and perform the sign extension + if (bits[GLONASS_GNAV_STRING_BITS - parameter[0].first] == 1) + { + sign = -1LL; + } + else + { + sign = 1LL; + } + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 1; j < parameter[i].second; j++) + { + value <<= 1; // shift left + if (bits[GLONASS_GNAV_STRING_BITS - parameter[i].first - j] == 1) + { + value += 1LL; // insert the bit + } + } + } + return (sign * value); +} + + +uint32_t Glonass_Gnav_Navigation_Message::get_frame_number(uint32_t satellite_slot_number) +{ + uint32_t frame_ID = 0U; + + if (satellite_slot_number >= 1 and satellite_slot_number <= 5) + { + frame_ID = 1U; + } + else if (satellite_slot_number >= 6 and satellite_slot_number <= 10) + { + frame_ID = 2U; + } + else if (satellite_slot_number >= 11 and satellite_slot_number <= 15) + { + frame_ID = 3U; + } + else if (satellite_slot_number >= 16 and satellite_slot_number <= 20) + { + frame_ID = 4U; + } + else if (satellite_slot_number >= 21 and satellite_slot_number <= 24) + { + frame_ID = 5U; + } + else + { + LOG(WARNING) << "GLONASS GNAV: Invalid Satellite Slot Number"; + frame_ID = 0U; + } + + return frame_ID; +} + + +int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame_string) +{ + int32_t J = 0; + d_string_ID = 0U; + d_frame_ID = 0U; + + // Unpack bytes to bits + std::bitset string_bits(frame_string); + + // Perform data verification and exit code if error in bit sequence + flag_CRC_test = CRC_test(string_bits); + if (flag_CRC_test == false) + return 0; + + // Decode all 15 string messages + d_string_ID = static_cast(read_navigation_unsigned(string_bits, STRING_ID)); + switch (d_string_ID) + { + case 1: + // --- It is string 1 ----------------------------------------------- + gnav_ephemeris.d_P_1 = (static_cast(read_navigation_unsigned(string_bits, P1)) + 1) * 15; + gnav_ephemeris.d_t_k = static_cast(read_navigation_unsigned(string_bits, T_K_HR)) * 3600 + + static_cast(read_navigation_unsigned(string_bits, T_K_MIN)) * 60 + + static_cast(read_navigation_unsigned(string_bits, T_K_SEC)) * 30; + gnav_ephemeris.d_VXn = static_cast(read_navigation_signed(string_bits, X_N_DOT)) * TWO_N20; + gnav_ephemeris.d_AXn = static_cast(read_navigation_signed(string_bits, X_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Xn = static_cast(read_navigation_signed(string_bits, X_N)) * TWO_N11; + + flag_ephemeris_str_1 = true; + + break; + + case 2: + // --- It is string 2 ----------------------------------------------- + if (flag_ephemeris_str_1 == true) + { + gnav_ephemeris.d_B_n = static_cast(read_navigation_unsigned(string_bits, B_N)); + gnav_ephemeris.d_P_2 = static_cast(read_navigation_bool(string_bits, P2)); + gnav_ephemeris.d_t_b = static_cast(read_navigation_unsigned(string_bits, T_B)) * 15 * 60; + gnav_ephemeris.d_VYn = static_cast(read_navigation_signed(string_bits, Y_N_DOT)) * TWO_N20; + gnav_ephemeris.d_AYn = static_cast(read_navigation_signed(string_bits, Y_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Yn = static_cast(read_navigation_signed(string_bits, Y_N)) * TWO_N11; + + gnav_ephemeris.d_iode = read_navigation_unsigned(string_bits, T_B); + flag_ephemeris_str_2 = true; + } + + break; + + case 3: + // --- It is string 3 ---------------------------------------------- + if (flag_ephemeris_str_2 == true) + { + gnav_ephemeris.d_P_3 = static_cast(read_navigation_bool(string_bits, P3)); + gnav_ephemeris.d_gamma_n = static_cast(read_navigation_signed(string_bits, GAMMA_N)) * TWO_N40; + gnav_ephemeris.d_P = static_cast(read_navigation_unsigned(string_bits, P)); + gnav_ephemeris.d_l3rd_n = static_cast(read_navigation_bool(string_bits, EPH_L_N)); + gnav_ephemeris.d_VZn = static_cast(read_navigation_signed(string_bits, Z_N_DOT)) * TWO_N20; + gnav_ephemeris.d_AZn = static_cast(read_navigation_signed(string_bits, Z_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Zn = static_cast(read_navigation_signed(string_bits, Z_N)) * TWO_N11; + + flag_ephemeris_str_3 = true; + } + + break; + + case 4: + // --- It is string 4 ---------------------------------------------- + if (flag_ephemeris_str_3 == true) + { + gnav_ephemeris.d_tau_n = static_cast(read_navigation_signed(string_bits, TAU_N)) * TWO_N30; + gnav_ephemeris.d_Delta_tau_n = static_cast(read_navigation_signed(string_bits, DELTA_TAU_N)) * TWO_N30; + gnav_ephemeris.d_E_n = static_cast(read_navigation_unsigned(string_bits, E_N)); + gnav_ephemeris.d_P_4 = static_cast(read_navigation_bool(string_bits, P4)); + gnav_ephemeris.d_F_T = static_cast(read_navigation_unsigned(string_bits, F_T)); + gnav_ephemeris.d_N_T = static_cast(read_navigation_unsigned(string_bits, N_T)); + gnav_ephemeris.d_n = static_cast(read_navigation_unsigned(string_bits, N)); + gnav_ephemeris.d_M = static_cast(read_navigation_unsigned(string_bits, M)); + + // Fill in ephemeris deliverables in the code + flag_update_slot_number = true; + gnav_ephemeris.i_satellite_slot_number = static_cast(gnav_ephemeris.d_n); + gnav_ephemeris.i_satellite_PRN = static_cast(gnav_ephemeris.d_n); + + flag_ephemeris_str_4 = true; + } + + break; + + case 5: + // --- It is string 5 ---------------------------------------------- + if (flag_ephemeris_str_4 == true) + { + gnav_utc_model.d_N_A = static_cast(read_navigation_unsigned(string_bits, N_A)); + gnav_utc_model.d_tau_c = static_cast(read_navigation_signed(string_bits, TAU_C)) * TWO_N31; + gnav_utc_model.d_N_4 = static_cast(read_navigation_unsigned(string_bits, N_4)); + gnav_utc_model.d_tau_gps = static_cast(read_navigation_signed(string_bits, TAU_GPS)) * TWO_N30; + gnav_ephemeris.d_l5th_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + flag_utc_model_str_5 = true; + + // Compute Year and DoY based on Algorithm A3.11 of GLONASS ICD + // 1). Current year number J in the four-year interval is calculated + if (gnav_ephemeris.d_N_T >= 1 && gnav_ephemeris.d_N_T <= 366) + { + J = 1; + } + else if (gnav_ephemeris.d_N_T >= 367 && gnav_ephemeris.d_N_T <= 731) + { + J = 2; + } + else if (gnav_ephemeris.d_N_T >= 732 && gnav_ephemeris.d_N_T <= 1096) + { + J = 3; + } + else if (gnav_ephemeris.d_N_T >= 1097 && gnav_ephemeris.d_N_T <= 1461) + { + J = 4; + } + // 2). Current year in common form is calculated by the following formula: + gnav_ephemeris.d_yr = 1996 + 4.0 * (gnav_utc_model.d_N_4 - 1.0) + (J - 1.0); + gnav_ephemeris.d_tau_c = gnav_utc_model.d_tau_c; + + // 3). Set TOW once the year has been defined, it helps with leap second determination + if (flag_ephemeris_str_1 == true) + { + gnav_ephemeris.glot_to_gpst(gnav_ephemeris.d_t_k + 10, gnav_utc_model.d_tau_c, gnav_utc_model.d_tau_gps, &gnav_ephemeris.d_WN, &gnav_ephemeris.d_TOW); + flag_TOW_set = true; + flag_TOW_new = true; + } + + // 4) Set time of day (tod) when ephemeris data is complety decoded + gnav_ephemeris.d_tod = gnav_ephemeris.d_t_k + 2 * d_string_ID; + } + + break; + + case 6: + // --- It is string 6 ---------------------------------------------- + i_alm_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_alm_satellite_slot_number); + // Make sure a valid frame_ID or satellite slot number is returned + if (d_frame_ID == 0) + return 0; + + gnav_almanac[i_alm_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_alm_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_6 = true; + + break; + + case 7: + // --- It is string 7 ---------------------------------------------- + if (flag_almanac_str_6 == true) + { + gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + + if (i_alm_satellite_slot_number == gnav_ephemeris.i_satellite_slot_number) + { + gnav_ephemeris.i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel; + } + flag_almanac_str_7 = true; + } + + break; + + case 8: + // --- It is string 8 ---------------------------------------------- + i_alm_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_alm_satellite_slot_number); + // Make sure a valid frame_ID or satellite slot number is returned + if (d_frame_ID == 0) + return 0; + + gnav_almanac[i_alm_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_alm_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_8 = true; + + break; + + case 9: + // --- It is string 9 ---------------------------------------------- + if (flag_almanac_str_8 == true) + { + gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_9 = true; + } + break; + + case 10: + // --- It is string 10 --------------------------------------------- + i_alm_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_alm_satellite_slot_number); + // Make sure a valid frame_ID or satellite slot number is returned + if (d_frame_ID == 0) + return 0; + + gnav_almanac[i_alm_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_alm_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_10 = true; + + break; + + case 11: + // --- It is string 11 --------------------------------------------- + if (flag_almanac_str_10 == true) + { + gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_11 = true; + } + break; + + case 12: + // --- It is string 12 --------------------------------------------- + i_alm_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_alm_satellite_slot_number); + // Make sure a valid frame_ID or satellite slot number is returned + if (d_frame_ID == 0) + return 0; + gnav_almanac[i_alm_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_alm_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_12 = true; + + break; + + case 13: + // --- It is string 13 --------------------------------------------- + if (flag_almanac_str_12 == true) + { + gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_13 = true; + } + break; + + case 14: + // --- It is string 14 --------------------------------------------- + if (d_frame_ID == 5) + { + gnav_utc_model.d_B1 = static_cast(read_navigation_unsigned(string_bits, B1)); + gnav_utc_model.d_B2 = static_cast(read_navigation_unsigned(string_bits, B2)); + } + else + { + i_alm_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_alm_satellite_slot_number); + // Make sure a valid frame_ID or satellite slot number is returned + if (d_frame_ID == 0) + return 0; + gnav_almanac[i_alm_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_alm_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_14 = true; + } + break; + + case 15: + // --- It is string 15 ---------------------------------------------- + if (d_frame_ID != 5 and flag_almanac_str_14 == true) + { + gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GLONASS_PI; + gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_alm_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_15 = true; + } + break; + default: + LOG(INFO) << "GLONASS GNAV: Invalid String ID of received. Received " << d_string_ID + << ", but acceptable range is from 1-15"; + + break; + } // switch string ID + + return d_string_ID; +} + + +Glonass_Gnav_Ephemeris Glonass_Gnav_Navigation_Message::get_ephemeris() +{ + return gnav_ephemeris; +} + + +Glonass_Gnav_Utc_Model Glonass_Gnav_Navigation_Message::get_utc_model() +{ + return gnav_utc_model; +} + + +Glonass_Gnav_Almanac Glonass_Gnav_Navigation_Message::get_almanac(uint32_t satellite_slot_number) +{ + return gnav_almanac[satellite_slot_number - 1]; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_ephemeris() //Check if we have a new ephemeris stored in the galileo navigation class +{ + bool new_eph = false; + // We need to make sure we have received the ephemeris info plus the time info + if ((flag_ephemeris_str_1 == true) and (flag_ephemeris_str_2 == true) and + (flag_ephemeris_str_3 == true) and (flag_ephemeris_str_4 == true) and + (flag_utc_model_str_5 == true)) + { + if (d_previous_tb != gnav_ephemeris.d_t_b) + { + flag_ephemeris_str_1 = false; // clear the flag + flag_ephemeris_str_2 = false; // clear the flag + flag_ephemeris_str_3 = false; // clear the flag + flag_ephemeris_str_4 = false; // clear the flag + flag_all_ephemeris = true; + // Update the time of ephemeris information + d_previous_tb = gnav_ephemeris.d_t_b; + DLOG(INFO) << "GLONASS GNAV Ephemeris (1, 2, 3, 4) have been received and belong to the same batch" << std::endl; + new_eph = true; + } + } + + return new_eph; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_utc_model() // Check if we have a new utc data set stored in the galileo navigation class +{ + if (flag_utc_model_str_5 == true) + { + flag_utc_model_str_5 = false; // clear the flag + return true; + } + + return false; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_almanac() // Check if we have a new almanac data set stored in the galileo navigation class +{ + bool new_alm = false; + if ((flag_almanac_str_6 == true) and (flag_almanac_str_7 == true)) + { + if (d_previous_Na[i_alm_satellite_slot_number] != gnav_utc_model.d_N_A) + { + // All almanac have been received for this satellite + flag_almanac_str_6 = false; + flag_almanac_str_7 = false; + new_alm = true; + } + } + if ((flag_almanac_str_8 == true) and (flag_almanac_str_9 == true)) + { + if (d_previous_Na[i_alm_satellite_slot_number] != gnav_utc_model.d_N_A) + { + flag_almanac_str_8 = false; + flag_almanac_str_9 = false; + new_alm = true; + } + } + if ((flag_almanac_str_10 == true) and (flag_almanac_str_11 == true)) + { + if (d_previous_Na[i_alm_satellite_slot_number] != gnav_utc_model.d_N_A) + { + flag_almanac_str_10 = false; + flag_almanac_str_11 = false; + new_alm = true; + } + } + if ((flag_almanac_str_12 == true) and (flag_almanac_str_13 == true)) + { + if (d_previous_Na[i_alm_satellite_slot_number] != gnav_utc_model.d_N_A) + { + flag_almanac_str_12 = false; + flag_almanac_str_13 = false; + new_alm = true; + } + } + if ((flag_almanac_str_14 == true) and (flag_almanac_str_15 == true)) + { + if (d_previous_Na[i_alm_satellite_slot_number] != gnav_utc_model.d_N_A) + { + flag_almanac_str_14 = false; + flag_almanac_str_15 = false; + new_alm = true; + } + } + + return new_alm; +} diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.h b/src/core/system_parameters/glonass_gnav_navigation_message.h new file mode 100644 index 000000000..6f1f92312 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_navigation_message.h @@ -0,0 +1,170 @@ +/*! + * \file glonass_gnav_navigation_message.h + * \brief Interface of a GLONASS GNAV Data message decoder as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_NAVIGATION_MESSAGE_H_ +#define GNSS_SDR_GLONASS_GNAV_NAVIGATION_MESSAGE_H_ + + +#include "GLONASS_L1_L2_CA.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include +#include + + +/*! + * \brief This class decodes a GLONASS GNAV Data message as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Navigation_Message +{ +private: + uint64_t read_navigation_unsigned(std::bitset bits, const std::vector>& parameter); + int64_t read_navigation_signed(std::bitset bits, const std::vector>& parameter); + bool read_navigation_bool(std::bitset bits, const std::vector>& parameter); + +public: + bool flag_CRC_test; + uint32_t d_frame_ID; + uint32_t d_string_ID; + bool flag_update_slot_number; + + int32_t i_channel_ID; + uint32_t i_satellite_PRN; + + Glonass_Gnav_Ephemeris gnav_ephemeris; //!< Ephemeris information decoded + Glonass_Gnav_Utc_Model gnav_utc_model; //!< UTC model information + Glonass_Gnav_Almanac gnav_almanac[GLONASS_CA_NBR_SATS]; //!< Almanac information for all 24 satellites + + // Ephemeris Flags and control variables + bool flag_all_ephemeris; //!< Flag indicating that all strings containing ephemeris have been received + bool flag_ephemeris_str_1; //!< Flag indicating that ephemeris 1/4 (string 1) have been received + bool flag_ephemeris_str_2; //!< Flag indicating that ephemeris 2/4 (string 2) have been received + bool flag_ephemeris_str_3; //!< Flag indicating that ephemeris 3/4 (string 3) have been received + bool flag_ephemeris_str_4; //!< Flag indicating that ephemeris 4/4 (string 4) have been received + + // Almanac Flags + bool flag_all_almanac; //!< Flag indicating that all almanac have been received + bool flag_almanac_str_6; //!< Flag indicating that almanac of string 6 have been received + bool flag_almanac_str_7; //!< Flag indicating that almanac of string 7 have been received + bool flag_almanac_str_8; //!< Flag indicating that almanac of string 8 have been received + bool flag_almanac_str_9; //!< Flag indicating that almanac of string 9 have been received + bool flag_almanac_str_10; //!< Flag indicating that almanac of string 10 have been received + bool flag_almanac_str_11; //!< Flag indicating that almanac of string 11 have been received + bool flag_almanac_str_12; //!< Flag indicating that almanac of string 12 have been received + bool flag_almanac_str_13; //!< Flag indicating that almanac of string 13 have been received + bool flag_almanac_str_14; //!< Flag indicating that almanac of string 14 have been received + bool flag_almanac_str_15; //!< Flag indicating that almanac of string 15 have been received + uint32_t i_alm_satellite_slot_number; //!< SV Orbit Slot Number + + // UTC and System Clocks Flags + bool flag_utc_model_valid; //!< If set, it indicates that the UTC model parameters are filled + bool flag_utc_model_str_5; //!< Clock info send in string 5 of navigation data + bool flag_utc_model_str_15; //!< Clock info send in string 15 of frame 5 of navigation data + + bool flag_TOW_set; //!< Flag indicating when the TOW has been set + bool flag_TOW_new; //!< Flag indicating when a new TOW has been computed + + double d_satClkCorr; //!< Satellite clock error + double d_dtr; //!< Relativistic clock correction term + double d_satClkDrift; //!< Satellite clock drift + + double d_previous_tb; //!< Previous iode for the Glonass_Gnav_Ephemeris object. Used to determine when new data arrives + double d_previous_Na[GLONASS_CA_NBR_SATS]; //!< Previous time for almanac of the Glonass_Gnav_Almanac object + + /*! + * \brief Compute CRC for GLONASS GNAV strings + * \param bits Bits of the string message where to compute CRC + */ + bool CRC_test(std::bitset bits); + + /*! + * \brief Computes the frame number being decoded given the satellite slot number + * \param satellite_slot_number [in] Satellite slot number identifier + * \returns Frame number being decoded, 0 if operation was not successful. + */ + uint32_t get_frame_number(uint32_t satellite_slot_number); + + /*! + * \brief Reset GLONASS GNAV Navigation Information + */ + void reset(); + + /*! + * \brief Obtain a GLONASS GNAV SV Ephemeris class filled with current SV data + */ + Glonass_Gnav_Ephemeris get_ephemeris(); + + /*! + * \brief Obtain a GLONASS GNAV UTC model parameters class filled with current SV data + */ + Glonass_Gnav_Utc_Model get_utc_model(); + + /*! + * \brief Returns a Glonass_Gnav_Almanac object filled with the latest navigation data received + * \param satellite_slot_number Slot number identifier for the satellite + * \returns Returns the Glonass_Gnav_Almanac object for the input slot number + */ + Glonass_Gnav_Almanac get_almanac(uint32_t satellite_slot_number); + + /*! + * \brief Returns true if a new Glonass_Gnav_Ephemeris object has arrived. + */ + bool have_new_ephemeris(); + + /*! + * \brief Returns true if new Glonass_Gnav_Utc_Model object has arrived + */ + bool have_new_utc_model(); + + /*! + * \brief Returns true if new Glonass_Gnav_Almanac object has arrived. + */ + bool have_new_almanac(); + + /*! + * \brief Decodes the GLONASS GNAV string + * \param frame_string [in] is the string message within the parsed frame + * \returns Returns the ID of the decoded string + */ + int32_t string_decoder(const std::string& frame_string); + + /*! + * Default constructor + */ + Glonass_Gnav_Navigation_Message(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_utc_model.cc b/src/core/system_parameters/glonass_gnav_utc_model.cc new file mode 100644 index 000000000..5450d1581 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_utc_model.cc @@ -0,0 +1,55 @@ +/* + * \file glonass_gnav_utc_model.h + * \brief Interface of a GLONASS GNAV UTC MODEL storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_utc_model.h" + +Glonass_Gnav_Utc_Model::Glonass_Gnav_Utc_Model() +{ + valid = false; + d_tau_c = 0.0; + d_tau_gps = 0.0; + d_N_4 = 0.0; + d_N_A = 0.0; + d_B1 = 0.0; + d_B2 = 0.0; +} + + +double Glonass_Gnav_Utc_Model::utc_time(double glonass_time_corrected) +{ + double t_utc; + + // GLONASS Time is relative to UTC Moscow, so we simply add its time difference + t_utc = glonass_time_corrected + 3.0 * 3600.0 + d_tau_c; + + return t_utc; +} diff --git a/src/core/system_parameters/glonass_gnav_utc_model.h b/src/core/system_parameters/glonass_gnav_utc_model.h new file mode 100644 index 000000000..5a082cb7e --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_utc_model.h @@ -0,0 +1,88 @@ +/*! + * \file glonass_gnav_utc_model.h + * \brief Interface of a GLONASS GNAV UTC MODEL storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_UTC_MODEL_H_ +#define GNSS_SDR_GLONASS_GNAV_UTC_MODEL_H_ + +#include +#include + +/*! + * \brief This class is a storage for the GLONASS GNAV UTC MODEL data as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Utc_Model +{ +public: + bool valid; + // Clock Parameters + double d_tau_c; //!< GLONASS time scale correction to UTC(SU) time. [s] + double d_tau_gps; //!< Correction to GPS time to GLONASS time [day] + double d_N_4; //!< Four year interval number starting from 1996 [4 year interval] + double d_N_A; //!< Calendar day number within the four-year period beginning since the leap year for Almanac data [days] + double d_B1; //!< Coefficient to determine DeltaUT1 [s] + double d_B2; //!< Coefficient to determine DeltaUT1 [s/msd] + + template + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the almanac data on disk file. + */ + void serialize(Archive& archive, const uint32_t version) + { + using boost::serialization::make_nvp; + if (version) + { + }; + archive& make_nvp("valid", valid); + archive& make_nvp("d_tau_c", d_tau_c); + archive& make_nvp("d_tau_gps", d_tau_gps); + archive& make_nvp("d_N_4", d_N_4); + archive& make_nvp("d_N_A", d_N_A); + archive& make_nvp("d_B1", d_B1); + archive& make_nvp("d_B2", d_B2); + } + + /*! + * Default constructor + */ + Glonass_Gnav_Utc_Model(); + + /*! + * \brief Computes the Coordinated Universal Time (UTC) and + * returns it in [s] (GLONASS ICD (Edition 5.1) Section 3.3.3 GLONASS Time) + */ + double utc_time(double glonass_time_corrected); +}; + +#endif diff --git a/src/core/system_parameters/gnss_frequencies.h b/src/core/system_parameters/gnss_frequencies.h new file mode 100644 index 000000000..1bab39fd0 --- /dev/null +++ b/src/core/system_parameters/gnss_frequencies.h @@ -0,0 +1,52 @@ +/*! + * \file gnss_frequencies.h + * \brief GNSS Frequencies + * \author Carles Fernandez, 2017. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GNSS_FREQUENCIES_H_ +#define GNSS_SDR_GNSS_FREQUENCIES_H_ + +const double FREQ1 = 1.57542e9; //!< L1/E1 frequency (Hz) +const double FREQ2 = 1.22760e9; //!< L2 frequency (Hz) +const double FREQ5 = 1.17645e9; //!< L5/E5a frequency (Hz) +const double FREQ6 = 1.27875e9; //!< E6/LEX frequency (Hz) +const double FREQ7 = 1.20714e9; //!< E5b frequency (Hz) +const double FREQ8 = 1.191795e9; //!< E5a+b frequency (Hz) +const double FREQ9 = 2.492028e9; //!< S frequency (Hz) +const double FREQ1_GLO = 1.60200e9; //!< GLONASS G1 base frequency (Hz) +const double DFRQ1_GLO = 0.56250e6; //!< GLONASS G1 bias frequency (Hz/n) +const double FREQ2_GLO = 1.24600e9; //!< GLONASS G2 base frequency (Hz) +const double DFRQ2_GLO = 0.43750e6; //!< GLONASS G2 bias frequency (Hz/n) +const double FREQ3_GLO = 1.202025e9; //!< GLONASS G3 frequency (Hz) +const double FREQ1_BDS = 1.561098e9; //!< BeiDou B1 frequency (Hz) +const double FREQ2_BDS = 1.20714e9; //!< BeiDou B2 frequency (Hz) +const double FREQ3_BDS = 1.26852e9; //!< BeiDou B3 frequency (Hz) + +#endif diff --git a/src/core/system_parameters/gnss_obs_codes.h b/src/core/system_parameters/gnss_obs_codes.h new file mode 100644 index 000000000..b1e772466 --- /dev/null +++ b/src/core/system_parameters/gnss_obs_codes.h @@ -0,0 +1,97 @@ +/*! + * \file gnss_obs_codes.h + * \brief GNSS Observable codes + * \author Carles Fernandez, 2017. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GNSS_OBS_CODES_H_ +#define GNSS_SDR_GNSS_OBS_CODES_H_ + +#include + +const uint32_t CODE_NONE = 0; //!< obs code: none or unknown +const uint32_t CODE_L1C = 1; //!< obs code: L1C/A,G1C/A,E1C (GPS,GLO,GAL,QZS,SBS) +const uint32_t CODE_L1P = 2; //!< obs code: L1P,G1P (GPS,GLO) +const uint32_t CODE_L1W = 3; //!< obs code: L1 Z-track (GPS) +const uint32_t CODE_L1Y = 4; //!< obs code: L1Y (GPS) +const uint32_t CODE_L1M = 5; //!< obs code: L1M (GPS) +const uint32_t CODE_L1N = 6; //!< obs code: L1codeless (GPS) +const uint32_t CODE_L1S = 7; //!< obs code: L1C(D) (GPS,QZS) +const uint32_t CODE_L1L = 8; //!< obs code: L1C(P) (GPS,QZS) +const uint32_t CODE_L1E = 9; //!< (not used) +const uint32_t CODE_L1A = 10; //!< obs code: E1A (GAL) +const uint32_t CODE_L1B = 11; //!< obs code: E1B (GAL) +const uint32_t CODE_L1X = 12; //!< obs code: E1B+C,L1C(D+P) (GAL,QZS) +const uint32_t CODE_L1Z = 13; //!< obs code: E1A+B+C,L1SAIF (GAL,QZS) +const uint32_t CODE_L2C = 14; //!< obs code: L2C/A,G1C/A (GPS,GLO) +const uint32_t CODE_L2D = 15; //!< obs code: L2 L1C/A-(P2-P1) (GPS) +const uint32_t CODE_L2S = 16; //!< obs code: L2C(M) (GPS,QZS) +const uint32_t CODE_L2L = 17; //!< obs code: L2C(L) (GPS,QZS) +const uint32_t CODE_L2X = 18; //!< obs code: L2C(M+L),B1I+Q (GPS,QZS,BDS) +const uint32_t CODE_L2P = 19; //!< obs code: L2P,G2P (GPS,GLO) +const uint32_t CODE_L2W = 20; //!< obs code: L2 Z-track (GPS) +const uint32_t CODE_L2Y = 21; //!< obs code: L2Y (GPS) +const uint32_t CODE_L2M = 22; //!< obs code: L2M (GPS) +const uint32_t CODE_L2N = 23; //!< obs code: L2codeless (GPS) +const uint32_t CODE_L5I = 24; //!< obs code: L5/E5aI (GPS,GAL,QZS,SBS) +const uint32_t CODE_L5Q = 25; //!< obs code: L5/E5aQ (GPS,GAL,QZS,SBS) +const uint32_t CODE_L5X = 26; //!< obs code: L5/E5aI+Q/L5B+C (GPS,GAL,QZS,IRN,SBS) +const uint32_t CODE_L7I = 27; //!< obs code: E5bI,B2I (GAL,BDS) +const uint32_t CODE_L7Q = 28; //!< obs code: E5bQ,B2Q (GAL,BDS) +const uint32_t CODE_L7X = 29; //!< obs code: E5bI+Q,B2I+Q (GAL,BDS) +const uint32_t CODE_L6A = 30; //!< obs code: E6A (GAL) +const uint32_t CODE_L6B = 31; //!< obs code: E6B (GAL) +const uint32_t CODE_L6C = 32; //!< obs code: E6C (GAL) +const uint32_t CODE_L6X = 33; //!< obs code: E6B+C,LEXS+L,B3I+Q (GAL,QZS,BDS) +const uint32_t CODE_L6Z = 34; //!< obs code: E6A+B+C (GAL) +const uint32_t CODE_L6S = 35; //!< obs code: LEXS (QZS) +const uint32_t CODE_L6L = 36; //!< obs code: LEXL (QZS) +const uint32_t CODE_L8I = 37; //!< obs code: E5(a+b)I (GAL) +const uint32_t CODE_L8Q = 38; //!< obs code: E5(a+b)Q (GAL) +const uint32_t CODE_L8X = 39; //!< obs code: E5(a+b)I+Q (GAL) +const uint32_t CODE_L2I = 40; //!< obs code: B1I (BDS) +const uint32_t CODE_L2Q = 41; //!< obs code: B1Q (BDS) +const uint32_t CODE_L6I = 42; //!< obs code: B3I (BDS) +const uint32_t CODE_L6Q = 43; //!< obs code: B3Q (BDS) +const uint32_t CODE_L3I = 44; //!< obs code: G3I (GLO) +const uint32_t CODE_L3Q = 45; //!< obs code: G3Q (GLO) +const uint32_t CODE_L3X = 46; //!< obs code: G3I+Q (GLO) +const uint32_t CODE_L1I = 47; //!< obs code: B1I (BDS) +const uint32_t CODE_L1Q = 48; //!< obs code: B1Q (BDS) +const uint32_t CODE_L5A = 49; //!< obs code: L5A SPS (IRN) +const uint32_t CODE_L5B = 50; //!< obs code: L5B RS(D) (IRN) +const uint32_t CODE_L5C = 51; //!< obs code: L5C RS(P) (IRN) +const uint32_t CODE_L9A = 52; //!< obs code: SA SPS (IRN) +const uint32_t CODE_L9B = 53; //!< obs code: SB RS(D) (IRN) +const uint32_t CODE_L9C = 54; //!< obs code: SC RS(P) (IRN) +const uint32_t CODE_L9X = 55; //!< obs code: SB+C (IRN) +const int32_t MAXCODE = 55; //!< max number of obs code + + +#endif diff --git a/src/core/system_parameters/gnss_satellite.cc b/src/core/system_parameters/gnss_satellite.cc index c56bbe52d..b249905d3 100644 --- a/src/core/system_parameters/gnss_satellite.cc +++ b/src/core/system_parameters/gnss_satellite.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,16 +32,13 @@ #include - Gnss_Satellite::Gnss_Satellite() { Gnss_Satellite::reset(); } - - -Gnss_Satellite::Gnss_Satellite(const std::string& system_, unsigned int PRN_) +Gnss_Satellite::Gnss_Satellite(const std::string& system_, uint32_t PRN_) { Gnss_Satellite::reset(); Gnss_Satellite::set_system(system_); @@ -50,20 +47,14 @@ Gnss_Satellite::Gnss_Satellite(const std::string& system_, unsigned int PRN_) } - - -Gnss_Satellite::~Gnss_Satellite() -{} - - - +Gnss_Satellite::~Gnss_Satellite() = default; void Gnss_Satellite::reset() { - system_set = {"GPS", "GLONASS", "SBAS", "Galileo", "Beidou"}; + system_set = {"GPS", "Glonass", "SBAS", "Galileo", "Beidou"}; satelliteSystem["GPS"] = "G"; - satelliteSystem["GLONASS"] = "R"; + satelliteSystem["Glonass"] = "R"; satelliteSystem["SBAS"] = "S"; satelliteSystem["Galileo"] = "E"; satelliteSystem["Beidou"] = "C"; @@ -74,24 +65,23 @@ void Gnss_Satellite::reset() } - -std::ostream& operator<<(std::ostream &out, const Gnss_Satellite &sat) // output +std::ostream& operator<<(std::ostream& out, const Gnss_Satellite& sat) // output { - std::string tag(""); - std::string tag2(""); - if(sat.get_system().compare("Galileo") == 0) tag = "E"; - if(sat.get_PRN() < 10) tag2 = "0"; + std::string tag; + std::string tag2; + if (sat.get_system() == "Galileo") tag = "E"; + if (sat.get_PRN() < 10) tag2 = "0"; out << sat.get_system() << " PRN " << tag << tag2 << sat.get_PRN() << " (Block " << sat.get_block() << ")"; return out; } -bool operator== (const Gnss_Satellite &sat1, const Gnss_Satellite &sat2) +bool operator==(const Gnss_Satellite& sat1, const Gnss_Satellite& sat2) { bool equal = false; - if (sat1.get_system().compare(sat2.get_system()) == 0) + if (sat1.get_system() == sat2.get_system()) { - if (sat1.get_PRN() == (sat2.get_PRN())) + if (sat1.get_PRN() == sat2.get_PRN()) { equal = true; } @@ -106,9 +96,9 @@ Gnss_Satellite& Gnss_Satellite::operator=(const Gnss_Satellite &rhs) { if (this != &rhs) { // Deallocate, allocate new space, copy values... const std::string system_ = rhs.get_system(); - const unsigned int PRN_ = rhs.get_PRN(); + const uint32_t PRN_ = rhs.get_PRN(); const std::string block_ = rhs.get_block(); - // const signed int rf_link_ = 0; + // const int32_t rf_link_ = 0; this->set_system(system_); this->set_PRN(PRN_); this->set_block(system_, PRN_); @@ -120,32 +110,53 @@ Gnss_Satellite& Gnss_Satellite::operator=(const Gnss_Satellite &rhs) { void Gnss_Satellite::set_system(const std::string& system_) { - // Set the satellite system {"GPS", "GLONASS", "SBAS", "Galileo", "Compass"} - std::set::iterator it = system_set.find(system_); + // Set the satellite system {"GPS", "Glonass", "SBAS", "Galileo", "Compass"} + auto it = system_set.find(system_); - if(it != system_set.end()) + if (it != system_set.cend()) { system = system_; } else { - DLOG(INFO) << "System " << system_ << " is not defined {GPS, GLONASS, SBAS, Galileo, Beidou}. Initialization?"; - system = std::string(""); + DLOG(INFO) << "System " << system_ << " is not defined {GPS, Glonass, SBAS, Galileo, Beidou}. Initialization?"; + system = std::string(""); } } +void Gnss_Satellite::update_PRN(uint32_t PRN_) +{ + if (system != "Glonass") + { + DLOG(INFO) << "Trying to update PRN for not GLONASS system"; + PRN = 0; + } + else + { + if (PRN_ < 1 or PRN_ > 24) + { + DLOG(INFO) << "This PRN is not defined"; + // Adjusting for PRN 26, now used in + PRN = PRN_; + } + else + { + PRN = PRN_; + } + } +} -void Gnss_Satellite::set_PRN(unsigned int PRN_) +void Gnss_Satellite::set_PRN(uint32_t PRN_) { // Set satellite's PRN - if (system.compare("") == 0) + if (system.empty()) { DLOG(INFO) << "Trying to define PRN while system is not defined"; PRN = 0; } - if (system.compare("GPS") == 0) + if (system == "GPS") { if (PRN_ < 1 or PRN_ > 32) { @@ -157,42 +168,61 @@ void Gnss_Satellite::set_PRN(unsigned int PRN_) PRN = PRN_; } } - else if (system.compare("Glonass") == 0) - { - if (PRN_ < 1 or PRN_ > 24) - { - DLOG(INFO) << "This PRN is not defined"; - PRN = 0; - } - else - { - PRN = PRN_; - } - } - else if (system.compare("SBAS") == 0) + else if (system == "Glonass") { - if (PRN_ == 122){ PRN = PRN_; } // WAAS Inmarsat 3F4 (AOR-W) - else if (PRN_ == 134){ PRN = PRN_; } // WAAS Inmarsat 3F3 (POR) - else if (PRN_ == 120){ PRN = PRN_; } // EGNOS AOR-E Broadcast satellite http://www.egnos-pro.esa.int/index.html - else if (PRN_ == 124){ PRN = PRN_; } // EGNOS ESA ARTEMIS used for EGNOS Operations - else if (PRN_ == 126){ PRN = PRN_; } // EGNOS IOR-W currently used by Industry to perform various tests on the system. + if (PRN_ < 1 or PRN_ > 24) + { + DLOG(INFO) << "This PRN is not defined"; + PRN = 0; + } + else + { + PRN = PRN_; + } + } + else if (system == "SBAS") + { + if (PRN_ == 120) + { + PRN = PRN_; + } // EGNOS Test Platform.Inmarsat 3-F2 (Atlantic Ocean Region-East) + else if (PRN_ == 123) + { + PRN = PRN_; + } // EGNOS Operational Platform. Astra 5B + else if (PRN_ == 131) + { + PRN = PRN_; + } // WAAS Eutelsat 117 West B + else if (PRN_ == 135) + { + PRN = PRN_; + } // WAAS Galaxy 15 + else if (PRN_ == 136) + { + PRN = PRN_; + } // EGNOS Operational Platform. SES-5 (a.k.a. Sirius 5 or Astra 4B) + else if (PRN_ == 138) + { + PRN = PRN_; + } // WAAS Anik F1R else { DLOG(INFO) << "This PRN is not defined"; PRN = 0; } } - else if (system.compare("Galileo") == 0) + else if (system == "Galileo") { - if (PRN_ < 1 or PRN_ > 36) - { - DLOG(INFO) << "This PRN is not defined"; - PRN = 0; - } - else - { - PRN = PRN_; - } + if (PRN_ < 1 or PRN_ > 36) + { + DLOG(INFO) << "This PRN is not defined"; + PRN = 0; + } + else + { + PRN = PRN_; + } } else { @@ -202,30 +232,33 @@ void Gnss_Satellite::set_PRN(unsigned int PRN_) } +int32_t Gnss_Satellite::get_rf_link() const +{ + // Get satellite's rf link. Identifies the GLONASS Frequency Channel + int32_t rf_link_; + rf_link_ = rf_link; + return rf_link_; +} - -unsigned int Gnss_Satellite::get_PRN() const +uint32_t Gnss_Satellite::get_PRN() const { // Get satellite's PRN - unsigned int PRN_; + uint32_t PRN_; PRN_ = PRN; return PRN_; } - - - - std::string Gnss_Satellite::get_system() const { - // Get the satellite system {"GPS", "GLONASS", "SBAS", "Galileo", "Beidou"} + // Get the satellite system {"GPS", "Glonass", "SBAS", "Galileo", "Beidou"} std::string system_; system_ = system; return system_; } + std::string Gnss_Satellite::get_system_short() const { // Get the satellite system {"G", "R", "S", "E", "C"} @@ -233,8 +266,6 @@ std::string Gnss_Satellite::get_system_short() const } - - std::string Gnss_Satellite::get_block() const { // Get the satellite block @@ -244,319 +275,339 @@ std::string Gnss_Satellite::get_block() const } - -std::string Gnss_Satellite::what_block(const std::string& system_, unsigned int PRN_) +std::string Gnss_Satellite::what_block(const std::string& system_, uint32_t PRN_) { std::string block_ = "Unknown"; - if (system_.compare("GPS") == 0) + if (system_ == "GPS") { - switch ( PRN_ ) - { - // info from http://www.navcen.uscg.gov/?Do=constellationStatus - - case 1 : - block_ = std::string("IIF"); //Plane D - break; - case 2 : - block_ = std::string("IIR"); //Plane D - break; - case 3 : - block_ = std::string("IIF"); //Plane E - break; - case 4 : - block_ = std::string("Unknown"); - break; - case 5 : - block_ = std::string("IIR-M"); //Plane E - break; - case 6 : - block_ = std::string("IIF"); //Plane D - break; - case 7 : - block_ = std::string("IIR-M"); //Plane A - break; - case 8 : - block_ = std::string("IIF"); //Plane C - break; - case 9 : - block_ = std::string("IIF"); //Plane F - break; - case 10 : - block_ = std::string("IIF"); //Plane E - break; - case 11 : - block_ = std::string("IIR"); //Plane D - break; - case 12 : - block_ = std::string("IIR-M"); //Plane B - break; - case 13 : - block_ = std::string("IIR"); //Plane F - break; - case 14 : - block_ = std::string("IIR"); //Plane F - break; - case 15 : - block_ = std::string("IIR-M"); //Plane F - break; - case 16 : - block_ = std::string("IIR"); //Plane B - break; - case 17 : - block_ = std::string("IIR-M"); //Plane C - break; - case 18 : - block_ = std::string("IIR"); //Plane E - break; - case 19 : - block_ = std::string("IIR"); //Plane D - break; - case 20 : - block_ = std::string("IIR"); //Plane B - break; - case 21 : - block_ = std::string("IIR"); //Plane D - break; - case 22 : - block_ = std::string("IIR"); //Plane E - break; - case 23 : - block_ = std::string("IIR"); //Plane F - break; - case 24 : - block_ = std::string("IIF"); //Plane A - break; - case 25 : - block_ = std::string("IIF"); //Plane B - break; - case 26 : - block_ = std::string("IIF"); //Plane B - break; - case 27 : - block_ = std::string("IIF"); //Plane C - break; - case 28 : - block_ = std::string("IIR"); //Plane B - break; - case 29 : - block_ = std::string("IIR-M"); //Plane C - break; - case 30 : - block_ = std::string("IIF"); //Plane A - break; - case 31 : - block_ = std::string("IIR-M"); //Plane A - break; - case 32 : - block_ = std::string("IIF"); //Plane F - break; - default : - block_ = std::string("Unknown"); - } + // info from https://www.navcen.uscg.gov/?Do=constellationStatus + switch (PRN_) + { + case 1: + block_ = std::string("IIF"); // Plane D + break; + case 2: + block_ = std::string("IIR"); // Plane D + break; + case 3: + block_ = std::string("IIF"); // Plane E + break; + case 4: + block_ = std::string("Unknown"); + break; + case 5: + block_ = std::string("IIR-M"); // Plane E + break; + case 6: + block_ = std::string("IIF"); // Plane D + break; + case 7: + block_ = std::string("IIR-M"); // Plane A + break; + case 8: + block_ = std::string("IIF"); // Plane C + break; + case 9: + block_ = std::string("IIF"); // Plane F + break; + case 10: + block_ = std::string("IIF"); // Plane E + break; + case 11: + block_ = std::string("IIR"); // Plane D + break; + case 12: + block_ = std::string("IIR-M"); // Plane B + break; + case 13: + block_ = std::string("IIR"); // Plane F + break; + case 14: + block_ = std::string("IIR"); // Plane F + break; + case 15: + block_ = std::string("IIR-M"); // Plane F + break; + case 16: + block_ = std::string("IIR"); // Plane B + break; + case 17: + block_ = std::string("IIR-M"); // Plane C + break; + case 18: + block_ = std::string("IIR"); // Plane E + break; + case 19: + block_ = std::string("IIR"); // Plane D + break; + case 20: + block_ = std::string("IIR"); // Plane B + break; + case 21: + block_ = std::string("IIR"); // Plane D + break; + case 22: + block_ = std::string("IIR"); // Plane E + break; + case 23: + block_ = std::string("IIR"); // Plane F + break; + case 24: + block_ = std::string("IIF"); // Plane A + break; + case 25: + block_ = std::string("IIF"); // Plane B + break; + case 26: + block_ = std::string("IIF"); // Plane B + break; + case 27: + block_ = std::string("IIF"); // Plane C + break; + case 28: + block_ = std::string("IIR"); // Plane B + break; + case 29: + block_ = std::string("IIR-M"); // Plane C + break; + case 30: + block_ = std::string("IIF"); // Plane A + break; + case 31: + block_ = std::string("IIR-M"); // Plane A + break; + case 32: + block_ = std::string("IIF"); // Plane F + break; + default: + block_ = std::string("Unknown"); + } } - - if (system_.compare("Glonass") == 0) + if (system_ == "Glonass") { - switch ( PRN_ ) - { - // info from http://www.sdcm.ru/smglo/grupglo?version=eng&site=extern + // Info from http://www.sdcm.ru/smglo/grupglo?version=eng&site=extern // See also http://www.glonass-center.ru/en/GLONASS/ - - case 1 : - block_ = std::string("1"); //Plane 1 - rf_link = 1; - break; - case 2 : - block_ = std::string("-4"); //Plane 1 - rf_link = -4; - break; - case 3 : - block_ = std::string("5"); //Plane 1 - rf_link = 5; - break; - case 4 : - block_ = std::string("6"); //Plane 1 - rf_link = 6; - break; - case 5 : - block_ = std::string("1"); //Plane 1 - rf_link = 1; - break; - case 6 : - block_ = std::string("-4"); //Plane 1 - rf_link = -4; - break; - case 7 : - block_ = std::string("5"); //Plane 1 - rf_link = 5; - break; - case 8 : - block_ = std::string("6"); //Plane 1 - rf_link = 6; - break; - case 9 : - block_ = std::string("-2"); //Plane 2 - rf_link = -2; - break; - case 10 : - block_ = std::string("-7"); //Plane 2 - rf_link = -7; - break; - case 11 : - block_ = std::string("0"); //Plane 2 - rf_link = 0; - break; - case 12 : - block_ = std::string("-1"); //Plane 2 - rf_link = -1; - break; - case 13 : - block_ = std::string("-2"); //Plane 2 - rf_link = -2; - break; - case 14 : - block_ = std::string("-7"); //Plane 2 - rf_link = -7; - break; - case 15 : - block_ = std::string("0"); //Plane 2 - rf_link = 0; - break; - case 16 : - block_ = std::string("-1"); //Plane 2 - rf_link = -1; - break; - case 17 : - block_ = std::string("4"); //Plane 3 - rf_link = 4; - break; - case 18 : - block_ = std::string("-3"); //Plane 3 - rf_link = -3; - break; - case 19 : - block_ = std::string("3"); //Plane 3 - rf_link = 3; - break; - case 20 : - block_ = std::string("2"); //Plane 3 - rf_link = 2; - break; - case 21 : - block_ = std::string("4"); //Plane 3 - rf_link = 4; - break; - case 22 : - block_ = std::string("-3"); //Plane 3 - rf_link = -3; - break; - case 23 : - block_ = std::string("3"); //Plane 3 - rf_link = 3; - break; - case 24 : - block_ = std::string("2"); //Plane 3 - rf_link = 2; - break; - default : - block_ = std::string("Unknown"); - } + switch (PRN_) + { + case 1: + block_ = std::string("1"); // Plane 1 + rf_link = 1; + break; + case 2: + block_ = std::string("-4"); // Plane 1 + rf_link = -4; + break; + case 3: + block_ = std::string("5"); // Plane 1 + rf_link = 5; + break; + case 4: + block_ = std::string("6"); // Plane 1 + rf_link = 6; + break; + case 5: + block_ = std::string("1"); // Plane 1 + rf_link = 1; + break; + case 6: + block_ = std::string("-4"); // Plane 1 + rf_link = -4; + break; + case 7: + block_ = std::string("5"); // Plane 1 + rf_link = 5; + break; + case 8: + block_ = std::string("6"); // Plane 1 + rf_link = 6; + break; + case 9: + block_ = std::string("-2"); // Plane 2 + rf_link = -2; + break; + case 10: + block_ = std::string("-7"); // Plane 2 + rf_link = -7; + break; + case 11: + block_ = std::string("0"); // Plane 2 + rf_link = 0; + break; + case 12: + block_ = std::string("-1"); // Plane 2 + rf_link = -1; + break; + case 13: + block_ = std::string("-2"); // Plane 2 + rf_link = -2; + break; + case 14: + block_ = std::string("-7"); // Plane 2 + rf_link = -7; + break; + case 15: + block_ = std::string("0"); // Plane 2 + rf_link = 0; + break; + case 16: + block_ = std::string("-1"); // Plane 2 + rf_link = -1; + break; + case 17: + block_ = std::string("4"); // Plane 3 + rf_link = 4; + break; + case 18: + block_ = std::string("-3"); // Plane 3 + rf_link = -3; + break; + case 19: + block_ = std::string("3"); // Plane 3 + rf_link = 3; + break; + case 20: + block_ = std::string("2"); // Plane 3 + rf_link = 2; + break; + case 21: + block_ = std::string("4"); // Plane 3 + rf_link = 4; + break; + case 22: + block_ = std::string("-3"); // Plane 3 + rf_link = -3; + break; + case 23: + block_ = std::string("3"); // Plane 3 + rf_link = 3; + break; + case 24: + block_ = std::string("2"); // Plane 3 + rf_link = 2; + break; + default: + block_ = std::string("Unknown"); + } } - if (system_.compare("SBAS") == 0) + if (system_ == "SBAS") { - switch ( PRN_ ) - { - case 122 : - block_ = std::string("WAAS"); // WAAS Inmarsat 3F4 (AOR-W) - break; - case 134 : - block_ = std::string("WAAS"); // WAAS Inmarsat 3F3 (POR) - break; - case 120 : - block_ = std::string("EGNOS"); // EGNOS AOR-E Broadcast satellite http://www.egnos-pro.esa.int/index.html - break; - case 124 : - block_ = std::string("EGNOS"); // EGNOS ESA ARTEMIS used for EGNOS Operations - break; - case 126 : - block_ = std::string("EGNOS"); // EGNOS IOR-W currently used by Industry to perform various tests on the system. - break; - default: - block_ = std::string("Unknown"); - } + switch (PRN_) + { + case 120: + block_ = std::string("EGNOS Test Platform"); // Inmarsat 3-F2 (Atlantic Ocean Region-East) + break; + case 123: + block_ = std::string("EGNOS"); // EGNOS Operational Platform. Astra 5B + break; + case 131: + block_ = std::string("WAAS"); // WAAS Eutelsat 117 West B + break; + case 135: + block_ = std::string("WAAS"); // WAAS Galaxy 15 + break; + case 136: + block_ = std::string("EGNOS"); // EGNOS Operational Platform. SES-5 (a.k.a. Sirius 5 or Astra 4B) + break; + case 138: + block_ = std::string("WAAS"); // WAAS Anik F1R + break; + default: + block_ = std::string("Unknown"); + } } - if (system_.compare("Galileo") == 0) + if (system_ == "Galileo") { - // Check http://en.wikipedia.org/wiki/List_of_Galileo_satellites - switch ( PRN_ ) - { - case 1: - block_ = std::string("FOC-FM10"); // Galileo Full Operational Capability (FOC) satellite FM10 / GSAT-0210, launched on May 24, 2016 - break; - case 2: - block_ = std::string("FOC-FM11"); // Galileo Full Operational Capability (FOC) satellite FM11 / GSAT-0211, launched on May 24, 2016 - break; - case 3: - block_ = std::string("FOC-FM12"); // Galileo Full Operational Capability (FOC) satellite FM12 / GSAT-0212, launched on November 17, 2016 - break; - case 4: - block_ = std::string("FOC-FM13"); // Galileo Full Operational Capability (FOC) satellite FM13 / GSAT-0213, launched on November 17, 2016 - break; - case 5: - block_ = std::string("FOC-FM14"); // Galileo Full Operational Capability (FOC) satellite FM14 / GSAT-0214, launched on November 17, 2016 - break; - case 7: - block_ = std::string("FOC-FM7"); // Galileo Full Operational Capability (FOC) satellite FM7 / GSAT-0207, launched on November 17, 2016 - break; - case 8: - block_ = std::string("FOC-FM8"); // Galileo Full Operational Capability (FOC) satellite FM8 / GSAT0208, launched on December 17, 2015 - break; - case 9: - block_ = std::string("FOC-FM9"); // Galileo Full Operational Capability (FOC) satellite FM9 / GSAT0209, launched on December 17, 2015 - break; - case 11 : - block_ = std::string("IOV-PFM"); // PFM, the ProtoFlight Model / GSAT0101, launched from French Guiana at 10:30 GMT on October 21, 2011 - break; - case 12 : - block_ = std::string("IOV-FM2**"); // Galileo In-Orbit Validation (IOV) satellite FM2 (Flight Model 2) also known as GSAT0102, from French Guiana at 10:30 GMT on October 21, 2011 - break; - case 14 : - block_ = std::string("FOC-FM2*"); // Galileo Full Operational Capability (FOC) satellite FM2 / GSAT0202, launched into incorrect orbit on August 22, 2014. Moved to usable orbit in March, 2015. - break; - case 18 : - block_ = std::string("FOC-FM1*"); // Galileo Full Operational Capability (FOC) satellite FM1 / GSAT0201, launched into incorrect orbit on August 22, 2014. Moved to usable orbit in December, 2014. - break; - case 19 : - block_ = std::string("IOV-FM3"); // Galileo In-Orbit Validation (IOV) satellite FM3 (Flight Model 3) / GSAT0103, launched on October 12, 2012 - break; - case 20 : - block_ = std::string("IOV-FM4**"); // Galileo In-Orbit Validation (IOV) satellite FM4 (Flight Model 4) / GSAT0104, launched on October 12, 2012. Partially unavailable: Payload power problem beginning May 27, 2014 led to permanent loss of E5 and E6 transmissions, E1 transmission restored. - break; - case 22 : - block_ = std::string("FOC-FM4"); // Galileo Full Operational Capability (FOC) satellite FM4 / GSAT0204, launched on March 27, 2015. - break; - case 24 : - block_ = std::string("FOC-FM5"); // Galileo Full Operational Capability (FOC) satellite FM5 / GSAT0205, launched on Sept. 11, 2015. - break; - case 26 : - block_ = std::string("FOC-FM3"); // Galileo Full Operational Capability (FOC) satellite FM3 / GSAT0203, launched on March 27, 2015. - break; - case 30 : - block_ = std::string("FOC-FM6"); // Galileo Full Operational Capability (FOC) satellite FM6 / GSAT0206, launched on Sept. 11, 2015. - break; - default: - block_ = std::string("Unknown(Simulated)"); - } + // Check http://en.wikipedia.org/wiki/List_of_Galileo_satellites and https://www.gsc-europa.eu/system-status/Constellation-Information + switch (PRN_) + { + case 1: + block_ = std::string("FOC-FM10"); // Galileo Full Operational Capability (FOC) satellite FM10 / GSAT-0210, launched on May 24, 2016. + break; + case 2: + block_ = std::string("FOC-FM11"); // Galileo Full Operational Capability (FOC) satellite FM11 / GSAT-0211, launched on May 24, 2016. + break; + case 3: + block_ = std::string("FOC-FM12"); // Galileo Full Operational Capability (FOC) satellite FM12 / GSAT-0212, launched on November 17, 2016. + break; + case 4: + block_ = std::string("FOC-FM13"); // Galileo Full Operational Capability (FOC) satellite FM13 / GSAT-0213, launched on November 17, 2016. + break; + case 5: + block_ = std::string("FOC-FM14"); // Galileo Full Operational Capability (FOC) satellite FM14 / GSAT-0214, launched on November 17, 2016. + break; + case 7: + block_ = std::string("FOC-FM7"); // Galileo Full Operational Capability (FOC) satellite FM7 / GSAT-0207, launched on November 17, 2016. + break; + case 8: + block_ = std::string("FOC-FM8"); // Galileo Full Operational Capability (FOC) satellite FM8 / GSAT0208, launched on December 17, 2015. + break; + case 9: + block_ = std::string("FOC-FM9"); // Galileo Full Operational Capability (FOC) satellite FM9 / GSAT0209, launched on December 17, 2015. + break; + case 11: + block_ = std::string("IOV-PFM"); // PFM, the ProtoFlight Model / GSAT0101, launched from French Guiana at 10:30 GMT on October 21, 2011. + break; + case 12: + block_ = std::string("IOV-FM2"); // Galileo In-Orbit Validation (IOV) satellite FM2 (Flight Model 2) also known as GSAT0102, from French Guiana at 10:30 GMT on October 21, 2011. + break; + case 13: + block_ = std::string("FOC-FM20"); // Galileo Full Operational Capability (FOC) satellite FM20 / GSAT0220, launched on Jul. 25, 2018. UNDER COMMISSIONING. + break; + case 14: + block_ = std::string("FOC-FM2*"); // Galileo Full Operational Capability (FOC) satellite FM2 / GSAT0202, launched into incorrect orbit on August 22, 2014. Moved to usable orbit in March, 2015. UNDER TESTING. + break; + case 15: + block_ = std::string("FOC-FM21"); // Galileo Full Operational Capability (FOC) satellite FM21 / GSAT0221, launched on Jul. 25, 2018. UNDER COMMISSIONING. + break; + case 18: + block_ = std::string("FOC-FM1*"); // Galileo Full Operational Capability (FOC) satellite FM1 / GSAT0201, launched into incorrect orbit on August 22, 2014. Moved to usable orbit in December, 2014. UNDER TESTING. + break; + case 19: + block_ = std::string("IOV-FM3"); // Galileo In-Orbit Validation (IOV) satellite FM3 (Flight Model 3) / GSAT0103, launched on October 12, 2012. + break; + case 20: + block_ = std::string("IOV-FM4**"); // Galileo In-Orbit Validation (IOV) satellite FM4 (Flight Model 4) / GSAT0104, launched on October 12, 2012. Payload power problem beginning May 27, 2014 led to permanent loss of E5 and E6 transmissions, E1 transmission restored. UNAVAILABLE FROM 2014-05-27 UNTIL FURTHER NOTICE + break; + case 21: + block_ = std::string("FOC-FM15"); // Galileo Full Operational Capability (FOC) satellite FM15 / GSAT0215, launched on Dec. 12, 2017. UNDER COMMISSIONING. + break; + case 22: + block_ = std::string("FOC-FM4**"); // Galileo Full Operational Capability (FOC) satellite FM4 / GSAT0204, launched on March 27, 2015. REMOVED FROM ACTIVE SERVICE ON 2017-12-08 UNTIL FURTHER NOTICE FOR CONSTELLATION MANAGEMENT PURPOSES. + break; + case 24: + block_ = std::string("FOC-FM5"); // Galileo Full Operational Capability (FOC) satellite FM5 / GSAT0205, launched on Sept. 11, 2015. + break; + case 25: + block_ = std::string("FOC-FM16"); // Galileo Full Operational Capability (FOC) satellite FM16 / GSAT0216, launched on Dec. 12, 2017. UNDER COMMISSIONING. + break; + case 26: + block_ = std::string("FOC-FM3"); // Galileo Full Operational Capability (FOC) satellite FM3 / GSAT0203, launched on March 27, 2015. + break; + case 27: + block_ = std::string("FOC-FM17"); // Galileo Full Operational Capability (FOC) satellite FM17 / GSAT0217, launched on Dec. 12, 2017. UNDER COMMISSIONING. + break; + case 30: + block_ = std::string("FOC-FM6"); // Galileo Full Operational Capability (FOC) satellite FM6 / GSAT0206, launched on Sept. 11, 2015. + break; + case 31: + block_ = std::string("FOC-FM18"); // Galileo Full Operational Capability (FOC) satellite FM18 / GSAT0218, launched on Dec. 12, 2017. UNDER COMMISSIONING. + break; + case 33: + block_ = std::string("FOC-FM22"); // Galileo Full Operational Capability (FOC) satellite FM22 / GSAT0222, launched on Jul. 25, 2018. UNDER COMMISSIONING. + break; + case 36: + block_ = std::string("FOC-FM19"); // Galileo Full Operational Capability (FOC) satellite FM19 / GSAT0219, launched on Jul. 25, 2018. UNDER COMMISSIONING. + break; + default: + block_ = std::string("Unknown(Simulated)"); + } } return block_; } -void Gnss_Satellite::set_block(const std::string& system_, unsigned int PRN_) +void Gnss_Satellite::set_block(const std::string& system_, uint32_t PRN_) { block = what_block(system_, PRN_); } - - - diff --git a/src/core/system_parameters/gnss_satellite.h b/src/core/system_parameters/gnss_satellite.h index cfdf1369f..519deb671 100644 --- a/src/core/system_parameters/gnss_satellite.h +++ b/src/core/system_parameters/gnss_satellite.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,10 +32,10 @@ #ifndef GNSS_SDR_GNSS_SATELLITE_H_ #define GNSS_SDR_GNSS_SATELLITE_H_ -#include -#include -#include +#include #include +#include +#include /*! @@ -47,27 +47,29 @@ class Gnss_Satellite { public: - Gnss_Satellite(); //!< Default Constructor. - Gnss_Satellite(const std::string& system_, unsigned int PRN_); //!< Concrete GNSS satellite Constructor. - ~Gnss_Satellite(); //!< Default Destructor. - unsigned int get_PRN() const; //!< Gets satellite's PRN - std::string get_system() const; //!< Gets the satellite system {"GPS", "GLONASS", "SBAS", "Galileo", "Beidou"} - std::string get_system_short() const; //!< Gets the satellite system {"G", "R", "SBAS", "E", "C"} - std::string get_block() const; //!< Gets the satellite block. If GPS, returns {"IIA", "IIR", "IIR-M", "IIF"} - std::string what_block(const std::string& system_, unsigned int PRN_); //!< Gets the block of a given satellite - friend bool operator== (const Gnss_Satellite &, const Gnss_Satellite &); //!< operator== for comparison - friend std::ostream& operator<<(std::ostream &, const Gnss_Satellite &); //!< operator<< for pretty printing + Gnss_Satellite(); //!< Default Constructor. + Gnss_Satellite(const std::string& system_, uint32_t PRN_); //!< Concrete GNSS satellite Constructor. + ~Gnss_Satellite(); //!< Default Destructor. + void update_PRN(uint32_t PRN); //!< Updates the PRN Number when information is decoded, only applies to GLONASS GNAV messages + uint32_t get_PRN() const; //!< Gets satellite's PRN + int32_t get_rf_link() const; //!< Gets the satellite's rf link + std::string get_system() const; //!< Gets the satellite system {"GPS", "GLONASS", "SBAS", "Galileo", "Beidou"} + std::string get_system_short() const; //!< Gets the satellite system {"G", "R", "SBAS", "E", "C"} + std::string get_block() const; //!< Gets the satellite block. If GPS, returns {"IIA", "IIR", "IIR-M", "IIF"} + std::string what_block(const std::string& system_, uint32_t PRN_); //!< Gets the block of a given satellite + friend bool operator==(const Gnss_Satellite&, const Gnss_Satellite&); //!< operator== for comparison + friend std::ostream& operator<<(std::ostream&, const Gnss_Satellite&); //!< operator<< for pretty printing //Gnss_Satellite& operator=(const Gnss_Satellite &); private: - unsigned int PRN; + uint32_t PRN; std::string system; - std::map satelliteSystem; + std::map satelliteSystem; std::string block; - signed int rf_link; + int32_t rf_link; void set_system(const std::string& system); // Sets the satellite system {"GPS", "GLONASS", "SBAS", "Galileo", "Beidou"}. - void set_PRN(unsigned int PRN); // Sets satellite's PRN - void set_block(const std::string& system_, unsigned int PRN_ ); - std::set system_set; // = {"GPS", "GLONASS", "SBAS", "Galileo", "Compass"}; + void set_PRN(uint32_t PRN); // Sets satellite's PRN + void set_block(const std::string& system_, uint32_t PRN_); + std::set system_set; // = {"GPS", "GLONASS", "SBAS", "Galileo", "Compass"}; void reset(); }; #endif diff --git a/src/core/system_parameters/gnss_signal.cc b/src/core/system_parameters/gnss_signal.cc index aaeb1a71b..0c25a7841 100644 --- a/src/core/system_parameters/gnss_signal.cc +++ b/src/core/system_parameters/gnss_signal.cc @@ -6,7 +6,7 @@ * Javier Arribas, 2012. jarribas(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -36,11 +36,13 @@ Gnss_Signal::Gnss_Signal() this->signal = ""; } + Gnss_Signal::Gnss_Signal(const std::string& signal_) { this->signal = signal_; } + Gnss_Signal::Gnss_Signal(const Gnss_Satellite& satellite_, const std::string& signal_) { this->satellite = satellite_; @@ -48,8 +50,7 @@ Gnss_Signal::Gnss_Signal(const Gnss_Satellite& satellite_, const std::string& si } -Gnss_Signal::~Gnss_Signal() -{} +Gnss_Signal::~Gnss_Signal() = default; std::string Gnss_Signal::get_signal_str() const @@ -64,24 +65,23 @@ Gnss_Satellite Gnss_Signal::get_satellite() const } -std::ostream& operator<<(std::ostream &out, const Gnss_Signal &sig) // output +std::ostream& operator<<(std::ostream& out, const Gnss_Signal& sig) // output { out << sig.get_satellite() << " Signal " << sig.get_signal_str(); return out; } -bool operator==(const Gnss_Signal &sig1, const Gnss_Signal &sig2) +bool operator==(const Gnss_Signal& sig1, const Gnss_Signal& sig2) { bool equal = false; if (sig1.get_satellite() == sig2.get_satellite()) { - if (sig1.get_signal_str().compare(sig1.get_signal_str()) == 0) + if (sig1.get_signal_str() == sig1.get_signal_str()) { equal = true; } } return equal; } - diff --git a/src/core/system_parameters/gnss_signal.h b/src/core/system_parameters/gnss_signal.h index 4922e5399..2b739c633 100644 --- a/src/core/system_parameters/gnss_signal.h +++ b/src/core/system_parameters/gnss_signal.h @@ -6,7 +6,7 @@ * Javier Arribas, 2012. jarribas(at)cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -46,15 +46,16 @@ class Gnss_Signal private: Gnss_Satellite satellite; std::string signal; + public: Gnss_Signal(); Gnss_Signal(const std::string& signal_); Gnss_Signal(const Gnss_Satellite& satellite_, const std::string& signal_); ~Gnss_Signal(); - std::string get_signal_str() const; //!< Get the satellite signal {"1C" for GPS L1 C/A, "2S" for GPS L2C (M), "1B" for Galileo E1B, "5X" for Galileo E5a} - Gnss_Satellite get_satellite() const; //!< Get the Gnss_Satellite associated to the signal - friend bool operator== (const Gnss_Signal &, const Gnss_Signal &); //!< operator== for comparison - friend std::ostream& operator<<(std::ostream &, const Gnss_Signal &); //!< operator<< for pretty printing + std::string get_signal_str() const; //!< Get the satellite signal {"1C" for GPS L1 C/A, "2S" for GPS L2C (M), "L5" for GPS L5, "1G" for GLONASS L1 C/A, "1B" for Galileo E1B, "5X" for Galileo E5a. + Gnss_Satellite get_satellite() const; //!< Get the Gnss_Satellite associated to the signal + friend bool operator==(const Gnss_Signal&, const Gnss_Signal&); //!< operator== for comparison + friend std::ostream& operator<<(std::ostream&, const Gnss_Signal&); //!< operator<< for pretty printing }; #endif diff --git a/src/core/system_parameters/gnss_synchro.h b/src/core/system_parameters/gnss_synchro.h index 62974e73f..117bdda7e 100644 --- a/src/core/system_parameters/gnss_synchro.h +++ b/src/core/system_parameters/gnss_synchro.h @@ -4,9 +4,10 @@ * \author * Luis Esteve, 2012. luis(at)epsilon-formacion.com * Javier Arribas, 2012. jarribas(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,59 +25,102 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #ifndef GNSS_SDR_GNSS_SYNCHRO_H_ #define GNSS_SDR_GNSS_SYNCHRO_H_ #include "gnss_signal.h" - +#include +#include /*! * \brief This is the class that contains the information that is shared * by the processing blocks. */ -class Gnss_Synchro +class Gnss_Synchro { public: // Satellite and signal info - char System; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) - char Signal[3]; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) - unsigned int PRN; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) - int Channel_ID; //!< Set by Channel constructor + char System; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) + char Signal[3]; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) + uint32_t PRN; //!< Set by Channel::set_signal(Gnss_Signal gnss_signal) + int32_t Channel_ID; //!< Set by Channel constructor + // Acquisition - double Acq_delay_samples; //!< Set by Acquisition processing block - double Acq_doppler_hz; //!< Set by Acquisition processing block - unsigned long int Acq_samplestamp_samples; //!< Set by Acquisition processing block - bool Flag_valid_acquisition; //!< Set by Acquisition processing block - //Tracking - double Prompt_I; //!< Set by Tracking processing block - double Prompt_Q; //!< Set by Tracking processing block - double CN0_dB_hz; //!< Set by Tracking processing block - double Carrier_Doppler_hz; //!< Set by Tracking processing block - double Carrier_phase_rads; //!< Set by Tracking processing block - double Tracking_timestamp_secs; //!< Set by Tracking processing block - double Rem_code_phase_secs; //!< Set by Tracking processing block + double Acq_delay_samples; //!< Set by Acquisition processing block + double Acq_doppler_hz; //!< Set by Acquisition processing block + uint64_t Acq_samplestamp_samples; //!< Set by Acquisition processing block + uint32_t Acq_doppler_step; //!< Set by Acquisition processing block + bool Flag_valid_acquisition; //!< Set by Acquisition processing block - bool Flag_valid_symbol_output; //!< Set by Tracking processing block - int correlation_length_ms; //!< Set by Tracking processing block + // Tracking + int64_t fs; //!< Set by Tracking processing block + double Prompt_I; //!< Set by Tracking processing block + double Prompt_Q; //!< Set by Tracking processing block + double CN0_dB_hz; //!< Set by Tracking processing block + double Carrier_Doppler_hz; //!< Set by Tracking processing block + double Carrier_phase_rads; //!< Set by Tracking processing block + double Code_phase_samples; //!< Set by Tracking processing block + uint64_t Tracking_sample_counter; //!< Set by Tracking processing block + bool Flag_valid_symbol_output; //!< Set by Tracking processing block + int32_t correlation_length_ms; //!< Set by Tracking processing block - //Telemetry Decoder - double Prn_timestamp_ms; //!< Set by Telemetry Decoder processing block - double Prn_timestamp_at_preamble_ms; //!< Set by Telemetry Decoder processing block + // Telemetry Decoder + bool Flag_valid_word; //!< Set by Telemetry Decoder processing block + uint32_t TOW_at_current_symbol_ms; //!< Set by Telemetry Decoder processing block - bool Flag_valid_word; //!< Set by Telemetry Decoder processing block - bool Flag_preamble; //!< Set by Telemetry Decoder processing block - double d_TOW; //!< Set by Telemetry Decoder processing block - double d_TOW_at_current_symbol; - double d_TOW_hybrid_at_current_symbol; //Galileo TOW is expressed in the GPS time scale (it will be the same for any other constellation) + // Observables + double Pseudorange_m; //!< Set by Observables processing block + double RX_time; //!< Set by Observables processing block + bool Flag_valid_pseudorange; //!< Set by Observables processing block + double interp_TOW_ms; //!< Set by Observables processing block - // Pseudorange - double Pseudorange_m; - bool Flag_valid_pseudorange; + /*! + * \brief This member function serializes and restores + * Gnss_Synchro objects from a byte stream. + */ + template + + void serialize(Archive& ar, const unsigned int version) + { + if (version) + { + }; + // Satellite and signal info + ar& BOOST_SERIALIZATION_NVP(System); + ar& BOOST_SERIALIZATION_NVP(Signal); + ar& BOOST_SERIALIZATION_NVP(PRN); + ar& BOOST_SERIALIZATION_NVP(Channel_ID); + // Acquisition + ar& BOOST_SERIALIZATION_NVP(Acq_delay_samples); + ar& BOOST_SERIALIZATION_NVP(Acq_doppler_hz); + ar& BOOST_SERIALIZATION_NVP(Acq_samplestamp_samples); + ar& BOOST_SERIALIZATION_NVP(Acq_doppler_step); + ar& BOOST_SERIALIZATION_NVP(Flag_valid_acquisition); + // Tracking + ar& BOOST_SERIALIZATION_NVP(fs); + ar& BOOST_SERIALIZATION_NVP(Prompt_I); + ar& BOOST_SERIALIZATION_NVP(Prompt_Q); + ar& BOOST_SERIALIZATION_NVP(CN0_dB_hz); + ar& BOOST_SERIALIZATION_NVP(Carrier_Doppler_hz); + ar& BOOST_SERIALIZATION_NVP(Carrier_phase_rads); + ar& BOOST_SERIALIZATION_NVP(Code_phase_samples); + ar& BOOST_SERIALIZATION_NVP(Tracking_sample_counter); + ar& BOOST_SERIALIZATION_NVP(Flag_valid_symbol_output); + ar& BOOST_SERIALIZATION_NVP(correlation_length_ms); + // Telemetry Decoder + ar& BOOST_SERIALIZATION_NVP(Flag_valid_word); + ar& BOOST_SERIALIZATION_NVP(TOW_at_current_symbol_ms); + // Observables + ar& BOOST_SERIALIZATION_NVP(Pseudorange_m); + ar& BOOST_SERIALIZATION_NVP(RX_time); + ar& BOOST_SERIALIZATION_NVP(Flag_valid_pseudorange); + ar& BOOST_SERIALIZATION_NVP(interp_TOW_ms); + } }; #endif - diff --git a/src/core/system_parameters/gps_acq_assist.cc b/src/core/system_parameters/gps_acq_assist.cc index 67b800d2f..128772316 100644 --- a/src/core/system_parameters/gps_acq_assist.cc +++ b/src/core/system_parameters/gps_acq_assist.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -34,7 +34,7 @@ Gps_Acq_Assist::Gps_Acq_Assist() { - i_satellite_PRN = 0; + i_satellite_PRN = 0U; d_TOW = 0.0; d_Doppler0 = 0.0; d_Doppler1 = 0.0; @@ -46,4 +46,3 @@ Gps_Acq_Assist::Gps_Acq_Assist() Azimuth = 0.0; Elevation = 0.0; } - diff --git a/src/core/system_parameters/gps_acq_assist.h b/src/core/system_parameters/gps_acq_assist.h index 5ccebae8c..5083aca44 100644 --- a/src/core/system_parameters/gps_acq_assist.h +++ b/src/core/system_parameters/gps_acq_assist.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,7 +32,7 @@ #ifndef GNSS_SDR_GPS_ACQ_ASSIST_H_ #define GNSS_SDR_GPS_ACQ_ASSIST_H_ - +#include /*! * \brief This class is a storage for the GPS GSM RRLL acquisition assistance data as described in @@ -45,17 +45,17 @@ class Gps_Acq_Assist { public: - unsigned int i_satellite_PRN; //!< SV PRN NUMBER - double d_TOW; //!< Time Of Week assigned to the acquisition data - double d_Doppler0; //!< Doppler (0 order term) [Hz] - double d_Doppler1; //!< Doppler (1 order term) [Hz] - double dopplerUncertainty; //!< Doppler Uncertainty [Hz] - double Code_Phase; //!< Code phase [chips] - double Code_Phase_int; //!< Integer Code Phase [1 C/A code period] - double GPS_Bit_Number; //!< GPS Bit Number - double Code_Phase_window; //!< Code Phase search window [chips] - double Azimuth; //!< Satellite Azimuth [deg] - double Elevation; //!< Satellite Elevation [deg] + uint32_t i_satellite_PRN; //!< SV PRN NUMBER + double d_TOW; //!< Time Of Week assigned to the acquisition data + double d_Doppler0; //!< Doppler (0 order term) [Hz] + double d_Doppler1; //!< Doppler (1 order term) [Hz] + double dopplerUncertainty; //!< Doppler Uncertainty [Hz] + double Code_Phase; //!< Code phase [chips] + double Code_Phase_int; //!< Integer Code Phase [1 C/A code period] + double GPS_Bit_Number; //!< GPS Bit Number + double Code_Phase_window; //!< Code Phase search window [chips] + double Azimuth; //!< Satellite Azimuth [deg] + double Elevation; //!< Satellite Elevation [deg] /*! * Default constructor diff --git a/src/core/system_parameters/gps_almanac.cc b/src/core/system_parameters/gps_almanac.cc index 805b262bc..ec0bd828a 100644 --- a/src/core/system_parameters/gps_almanac.cc +++ b/src/core/system_parameters/gps_almanac.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,18 +25,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_almanac.h" -Gps_Almanac::Gps_Almanac() +Gps_Almanac::Gps_Almanac() { - i_satellite_PRN = 0; + i_satellite_PRN = 0U; d_Delta_i = 0.0; - d_Toa = 0.0; + i_Toa = 0; + i_WNa = 0; d_M_0 = 0.0; d_e_eccentricity = 0.0; d_sqrt_A = 0.0; @@ -44,7 +45,7 @@ Gps_Almanac::Gps_Almanac() d_OMEGA = 0.0; d_OMEGA_DOT = 0.0; i_SV_health = 0; + i_AS_status = 0; d_A_f0 = 0.0; d_A_f1 = 0.0; } - diff --git a/src/core/system_parameters/gps_almanac.h b/src/core/system_parameters/gps_almanac.h index 47dec1eec..71175a8bd 100644 --- a/src/core/system_parameters/gps_almanac.h +++ b/src/core/system_parameters/gps_almanac.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,6 +32,8 @@ #ifndef GNSS_SDR_GPS_ALMANAC_H_ #define GNSS_SDR_GPS_ALMANAC_H_ +#include +#include /*! * \brief This class is a storage for the GPS SV ALMANAC data as described in IS-GPS-200E @@ -41,23 +43,48 @@ class Gps_Almanac { public: - unsigned int i_satellite_PRN; //!< SV PRN NUMBER - double d_Delta_i; - double d_Toa; //!< Almanac data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] - double d_e_eccentricity; //!< Eccentricity [dimensionless] - double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] - double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double d_OMEGA; //!< Argument of Perigee [semi-cicles] - double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] - int i_SV_health; // SV Health - double d_A_f0; //!< Coefficient 0 of code phase offset model [s] - double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] + uint32_t i_satellite_PRN; //!< SV PRN NUMBER + double d_Delta_i; //!< Inclination Angle at Reference Time (relative to i_0 = 0.30 semi-circles) + int32_t i_Toa; //!< Almanac data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + int32_t i_WNa; //!< Almanac week number + double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] + double d_e_eccentricity; //!< Eccentricity [dimensionless] + double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] + double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + double d_OMEGA; //!< Argument of Perigee [semi-cicles] + double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] + int32_t i_SV_health; //!< SV Health + int32_t i_AS_status; //!< Anti-Spoofing Flags and SV Configuration + double d_A_f0; //!< Coefficient 0 of code phase offset model [s] + double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] /*! * Default constructor */ Gps_Almanac(); + + template + + void serialize(Archive& ar, const unsigned int version) + { + if (version) + { + }; + ar& BOOST_SERIALIZATION_NVP(i_satellite_PRN); + ar& BOOST_SERIALIZATION_NVP(d_Delta_i); + ar& BOOST_SERIALIZATION_NVP(i_Toa); + ar& BOOST_SERIALIZATION_NVP(i_WNa); + ar& BOOST_SERIALIZATION_NVP(d_M_0); + ar& BOOST_SERIALIZATION_NVP(d_e_eccentricity); + ar& BOOST_SERIALIZATION_NVP(d_sqrt_A); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA0); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA); + ar& BOOST_SERIALIZATION_NVP(d_OMEGA_DOT); + ar& BOOST_SERIALIZATION_NVP(i_SV_health); + ar& BOOST_SERIALIZATION_NVP(i_AS_status); + ar& BOOST_SERIALIZATION_NVP(d_A_f0); + ar& BOOST_SERIALIZATION_NVP(d_A_f1); + } }; #endif diff --git a/src/core/system_parameters/gps_cnav_ephemeris.cc b/src/core/system_parameters/gps_cnav_ephemeris.cc index 310980151..cb96a8a73 100644 --- a/src/core/system_parameters/gps_cnav_ephemeris.cc +++ b/src/core/system_parameters/gps_cnav_ephemeris.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,45 +25,44 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_cnav_ephemeris.h" #include -#include "GPS_L2C.h" Gps_CNAV_Ephemeris::Gps_CNAV_Ephemeris() { - i_satellite_PRN = 0; + i_satellite_PRN = 0U; d_Toe1 = -1; d_Toe2 = -1; d_TOW = 0; - d_Crs = 0; - d_M_0 = 0; - d_Cuc = 0; - d_e_eccentricity = 0; - d_Cus = 0; + d_Crs = 0.0; + d_M_0 = 0.0; + d_Cuc = 0.0; + d_e_eccentricity = 0.0; + d_Cus = 0.0; d_Toc = 0; - d_Cic = 0; - d_OMEGA0 = 0; - d_Cis = 0; - d_i_0 = 0; - d_Crc = 0; - d_OMEGA = 0; - d_IDOT = 0; + d_Cic = 0.0; + d_OMEGA0 = 0.0; + d_Cis = 0.0; + d_i_0 = 0.0; + d_Crc = 0.0; + d_OMEGA = 0.0; + d_IDOT = 0.0; i_GPS_week = 0; - d_TGD = 0; // Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + d_TGD = 0.0; // Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] - d_A_f0 = 0; // Coefficient 0 of code phase offset model [s] - d_A_f1 = 0; // Coefficient 1 of code phase offset model [s/s] - d_A_f2 = 0; // Coefficient 2 of code phase offset model [s/s^2] + d_A_f0 = 0.0; // Coefficient 0 of code phase offset model [s] + d_A_f1 = 0.0; // Coefficient 1 of code phase offset model [s/s] + d_A_f2 = 0.0; // Coefficient 2 of code phase offset model [s/s^2] b_integrity_status_flag = false; b_alert_flag = false; // If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. @@ -80,7 +79,7 @@ Gps_CNAV_Ephemeris::Gps_CNAV_Ephemeris() i_URA = 0; i_signal_health = 0; - d_Top = 0.0; + d_Top = 0; d_DELTA_A = 0.0; d_A_DOT = 0.0; d_Delta_n = 0.0; @@ -96,10 +95,11 @@ Gps_CNAV_Ephemeris::Gps_CNAV_Ephemeris() b_l2c_phasing_flag = false; } + double Gps_CNAV_Ephemeris::check_t(double time) { double corrTime; - double half_week = 302400.0; // seconds + double half_week = 302400.0; // seconds corrTime = time; if (time > half_week) { @@ -119,6 +119,10 @@ double Gps_CNAV_Ephemeris::sv_clock_drift(double transmitTime) double dt; dt = check_t(transmitTime - d_Toc); d_satClkDrift = d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt) + sv_clock_relativistic_term(transmitTime); + + // Correct satellite group delay + d_satClkDrift -= d_TGD; + return d_satClkDrift; } @@ -135,8 +139,8 @@ double Gps_CNAV_Ephemeris::sv_clock_relativistic_term(double transmitTime) double dE; double M; const double GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] - const double F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] - const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 163 + const double F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] + const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 163 double d_sqrt_A = sqrt(A_REF + d_DELTA_A); // Restore semi-major axis @@ -153,17 +157,17 @@ double Gps_CNAV_Ephemeris::sv_clock_relativistic_term(double transmitTime) M = d_M_0 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2.0 * GPS_L2_PI), (2.0 * GPS_L2_PI)); + //M = fmod((M + 2.0 * GPS_L2_PI), (2.0 * GPS_L2_PI)); // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + d_e_eccentricity * sin(E); - dE = fmod(E - E_old, 2.0 * GPS_L2_PI); + E_old = E; + E = M + d_e_eccentricity * sin(E); + dE = fmod(E - E_old, 2.0 * PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -177,7 +181,7 @@ double Gps_CNAV_Ephemeris::sv_clock_relativistic_term(double transmitTime) } -void Gps_CNAV_Ephemeris::satellitePosition(double transmitTime) +double Gps_CNAV_Ephemeris::satellitePosition(double transmitTime) { double tk; double a; @@ -193,41 +197,47 @@ void Gps_CNAV_Ephemeris::satellitePosition(double transmitTime) double r; double i; double Omega; - const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 163 + + const double A_REF = 26559710.0; // See IS-GPS-200H, pp. 170 double d_sqrt_A = sqrt(A_REF + d_DELTA_A); - const double GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] - const double OMEGA_DOT_REF = -2.6e-9; // semicircles / s, see IS-GPS-200H pp. 164 - double d_OMEGA_DOT = OMEGA_DOT_REF + d_DELTA_OMEGA_DOT; + + const double GM = 3.986005e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] + const double OMEGA_DOT_REF = -2.6e-9; // semicircles / s, see IS-GPS-200H pp. 164 const double OMEGA_EARTH_DOT = 7.2921151467e-5; //!< Earth rotation rate, [rad/s] // Find satellite's position ---------------------------------------------- // Restore semi-major axis - a = d_sqrt_A*d_sqrt_A; + a = d_sqrt_A * d_sqrt_A; // Time from ephemeris reference epoch tk = check_t(transmitTime - d_Toe1); // Computed mean motion - n0 = sqrt(GM / (a*a*a)); + n0 = sqrt(GM / (a * a * a)); + + // Mean motion difference from computed value + + double delta_n_a = d_Delta_n + 0.5 * d_DELTA_DOT_N * tk; // Corrected mean motion - n = n0 + d_Delta_n; + n = n0 + delta_n_a; // Mean anomaly M = d_M_0 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2 * GPS_L2_PI), (2 * GPS_L2_PI)); + //M = fmod((M + 2 * GPS_L2_PI), (2 * GPS_L2_PI)); + // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + d_e_eccentricity * sin(E); - dE = fmod(E - E_old, 2 * GPS_L2_PI); + E_old = E; + E = M + d_e_eccentricity * sin(E); + dE = fmod(E - E_old, 2 * PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -244,22 +254,23 @@ void Gps_CNAV_Ephemeris::satellitePosition(double transmitTime) phi = nu + d_OMEGA; // Reduce phi to between 0 and 2*pi rad - phi = fmod((phi), (2*GPS_L2_PI)); + //phi = fmod((phi), (2*GPS_L2_PI)); // Correct argument of latitude - u = phi + d_Cuc * cos(2*phi) + d_Cus * sin(2*phi); + u = phi + d_Cuc * cos(2 * phi) + d_Cus * sin(2 * phi); // Correct radius - r = a * (1 - d_e_eccentricity*cos(E)) + d_Crc * cos(2*phi) + d_Crs * sin(2*phi); + r = a * (1 - d_e_eccentricity * cos(E)) + d_Crc * cos(2 * phi) + d_Crs * sin(2 * phi); // Correct inclination - i = d_i_0 + d_IDOT * tk + d_Cic * cos(2*phi) + d_Cis * sin(2*phi); + i = d_i_0 + d_IDOT * tk + d_Cic * cos(2 * phi) + d_Cis * sin(2 * phi); // Compute the angle between the ascending node and the Greenwich meridian - Omega = d_OMEGA0 + (d_OMEGA_DOT - OMEGA_EARTH_DOT)*tk - OMEGA_EARTH_DOT * d_Toe1; + double d_OMEGA_DOT = OMEGA_DOT_REF * PI + d_DELTA_OMEGA_DOT; + Omega = d_OMEGA0 + (d_OMEGA_DOT - OMEGA_EARTH_DOT) * tk - OMEGA_EARTH_DOT * d_Toe1; // Reduce to between 0 and 2*pi rad - Omega = fmod((Omega + 2*GPS_L2_PI), (2*GPS_L2_PI)); + //Omega = fmod((Omega + 2*GPS_L2_PI), (2*GPS_L2_PI)); // --- Compute satellite coordinates in Earth-fixed coordinates d_satpos_X = cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega); @@ -268,7 +279,17 @@ void Gps_CNAV_Ephemeris::satellitePosition(double transmitTime) // Satellite's velocity. Can be useful for Vector Tracking loops double Omega_dot = d_OMEGA_DOT - OMEGA_EARTH_DOT; - d_satvel_X = - Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); + d_satvel_X = -Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); d_satvel_Y = Omega_dot * (cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega)) + d_satpos_X * sin(Omega) + d_satpos_Y * cos(i) * cos(Omega); d_satvel_Z = d_satpos_Y * sin(i); + + // Time from ephemeris reference clock + tk = check_t(transmitTime - d_Toc); + + double dtr_s = d_A_f0 + d_A_f1 * tk + d_A_f2 * tk * tk; + + /* relativity correction */ + dtr_s -= 2.0 * sqrt(GM * a) * d_e_eccentricity * sin(E) / (SPEED_OF_LIGHT * SPEED_OF_LIGHT); + + return dtr_s; } diff --git a/src/core/system_parameters/gps_cnav_ephemeris.h b/src/core/system_parameters/gps_cnav_ephemeris.h index 46e94cb5d..5f39454ea 100644 --- a/src/core/system_parameters/gps_cnav_ephemeris.h +++ b/src/core/system_parameters/gps_cnav_ephemeris.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,7 +32,8 @@ #ifndef GNSS_SDR_GPS_CNAV_EPHEMERIS_H_ #define GNSS_SDR_GPS_CNAV_EPHEMERIS_H_ -#include "boost/assign.hpp" +#include "GPS_CNAV.h" +#include #include @@ -45,55 +46,53 @@ class Gps_CNAV_Ephemeris { private: double check_t(double time); + public: - unsigned int i_satellite_PRN; // SV PRN NUMBER + uint32_t i_satellite_PRN; // SV PRN NUMBER - //Message Types 10 and 11 Parameters (1 of 2) - int i_GPS_week; //!< GPS week number, aka WN [week] - int i_URA; //!< ED Accuracy Index - int i_signal_health; //!< Signal health (L1/L2/L5) - double d_Top; //!< Data predict time of week - double d_DELTA_A; //!< Semi-major axis difference at reference time - double d_A_DOT; //!< Change rate in semi-major axis - double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] - double d_DELTA_DOT_N; //!< Rate of mean motion difference from computed value - double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] - double d_e_eccentricity; //!< Eccentricity - double d_OMEGA; //!< Argument of Perigee [semi-cicles] - double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-cicles] - double d_Toe1; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - double d_Toe2; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - double d_DELTA_OMEGA_DOT; //!< Rate of Right Ascension difference [semi-circles/s] - double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] - double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] - double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] - double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] - double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] - double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] - double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] - double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] + // Message Types 10 and 11 Parameters (1 of 2) + int32_t i_GPS_week; //!< GPS week number, aka WN [week] + int32_t i_URA; //!< ED Accuracy Index + int32_t i_signal_health; //!< Signal health (L1/L2/L5) + int32_t d_Top; //!< Data predict time of week + double d_DELTA_A; //!< Semi-major axis difference at reference time + double d_A_DOT; //!< Change rate in semi-major axis + double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] + double d_DELTA_DOT_N; //!< Rate of mean motion difference from computed value + double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] + double d_e_eccentricity; //!< Eccentricity + double d_OMEGA; //!< Argument of Perigee [semi-cicles] + double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-cicles] + int32_t d_Toe1; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + int32_t d_Toe2; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + double d_DELTA_OMEGA_DOT; //!< Rate of Right Ascension difference [semi-circles/s] + double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] + double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] + double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] + double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] + double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] + double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] + double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] + double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] - //Clock Correction and Accuracy Parameters - double d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] - double d_A_f0; //!< Coefficient 0 of code phase offset model [s] - double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] - double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] + // Clock Correction and Accuracy Parameters + int32_t d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] + double d_A_f0; //!< Coefficient 0 of code phase offset model [s] + double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] + double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] - double d_URA0; //! + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const uint32_t version) { using boost::serialization::make_nvp; - if(version){}; + if (version) + { + }; - archive & make_nvp("i_satellite_PRN", i_satellite_PRN); // SV PRN NUMBER - archive & make_nvp("d_TOW", d_TOW); //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] - archive & make_nvp("d_Crs", d_Crs); //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] - archive & make_nvp("d_M_0", d_M_0); //!< Mean Anomaly at Reference Time [semi-circles] - archive & make_nvp("d_Cuc", d_Cuc); //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] - archive & make_nvp("d_e_eccentricity", d_e_eccentricity); //!< Eccentricity [dimensionless] - archive & make_nvp("d_Cus", d_Cus); //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] - archive & make_nvp("d_Toe1", d_Toe1); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - archive & make_nvp("d_Toe2", d_Toe2); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - archive & make_nvp("d_Toc", d_Toc); //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] - archive & make_nvp("d_Cic", d_Cic); //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] - archive & make_nvp("d_OMEGA0", d_OMEGA0); //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - archive & make_nvp("d_Cis", d_Cis); //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] - archive & make_nvp("d_i_0", d_i_0); //!< Inclination Angle at Reference Time [semi-circles] - archive & make_nvp("d_Crc", d_Crc); //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] - archive & make_nvp("d_OMEGA", d_OMEGA); //!< Argument of Perigee [semi-cicles] - archive & make_nvp("d_IDOT", d_IDOT); //!< Rate of Inclination Angle [semi-circles/s] - archive & make_nvp("i_GPS_week", i_GPS_week); //!< GPS week number, aka WN [week] - archive & make_nvp("d_TGD", d_TGD); //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("i_satellite_PRN", i_satellite_PRN); // SV PRN NUMBER + archive& make_nvp("d_TOW", d_TOW); //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + archive& make_nvp("d_Crs", d_Crs); //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] + archive& make_nvp("d_M_0", d_M_0); //!< Mean Anomaly at Reference Time [semi-circles] + archive& make_nvp("d_Cuc", d_Cuc); //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] + archive& make_nvp("d_e_eccentricity", d_e_eccentricity); //!< Eccentricity [dimensionless] + archive& make_nvp("d_Cus", d_Cus); //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] + archive& make_nvp("d_Toe1", d_Toe1); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + archive& make_nvp("d_Toe2", d_Toe2); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + archive& make_nvp("d_Toc", d_Toc); //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] + archive& make_nvp("d_Cic", d_Cic); //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] + archive& make_nvp("d_OMEGA0", d_OMEGA0); //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + archive& make_nvp("d_Cis", d_Cis); //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] + archive& make_nvp("d_i_0", d_i_0); //!< Inclination Angle at Reference Time [semi-circles] + archive& make_nvp("d_Crc", d_Crc); //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] + archive& make_nvp("d_OMEGA", d_OMEGA); //!< Argument of Perigee [semi-cicles] + archive& make_nvp("d_IDOT", d_IDOT); //!< Rate of Inclination Angle [semi-circles/s] + archive& make_nvp("i_GPS_week", i_GPS_week); //!< GPS week number, aka WN [week] + archive& make_nvp("d_TGD", d_TGD); //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_ISCL1", d_ISCL1); //!< Estimated Group Delay Differential: L1P(Y)-L1C/A correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_ISCL2", d_ISCL2); //!< Estimated Group Delay Differential: L1P(Y)-L2C correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_ISCL5I", d_ISCL5I); //!< Estimated Group Delay Differential: L1P(Y)-L5i correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_ISCL5Q", d_ISCL5Q); //!< Estimated Group Delay Differential: L1P(Y)-L5q correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_DELTA_A", d_DELTA_A); //!< Semi-major axis difference at reference time [m] + archive& make_nvp("d_A_DOT", d_A_DOT); //!< Change rate in semi-major axis [m/s] + archive& make_nvp("d_DELTA_OMEGA_DOT", d_DELTA_OMEGA_DOT); //!< Rate of Right Ascension difference [semi-circles/s] + archive& make_nvp("d_A_f0", d_A_f0); //!< Coefficient 0 of code phase offset model [s] + archive& make_nvp("d_A_f1", d_A_f1); //!< Coefficient 1 of code phase offset model [s/s] + archive& make_nvp("d_A_f2", d_A_f2); //!< Coefficient 2 of code phase offset model [s/s^2] - archive & make_nvp("d_A_f0", d_A_f0); //!< Coefficient 0 of code phase offset model [s] - archive & make_nvp("d_A_f1", d_A_f1); //!< Coefficient 1 of code phase offset model [s/s] - archive & make_nvp("d_A_f2", d_A_f2); //!< Coefficient 2 of code phase offset model [s/s^2] - - archive & make_nvp("b_integrity_status_flag", b_integrity_status_flag); - archive & make_nvp("b_alert_flag", b_alert_flag); //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. - archive & make_nvp("b_antispoofing_flag", b_antispoofing_flag); //!< If true, the AntiSpoofing mode is ON in that SV + archive& make_nvp("b_integrity_status_flag", b_integrity_status_flag); + archive& make_nvp("b_alert_flag", b_alert_flag); //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. + archive& make_nvp("b_antispoofing_flag", b_antispoofing_flag); //!< If true, the AntiSpoofing mode is ON in that SV } /*! * \brief Compute the ECEF SV coordinates and ECEF velocity * Implementation of Table 20-IV (IS-GPS-200E) */ - void satellitePosition(double transmitTime); + double satellitePosition(double transmitTime); /*! * \brief Sets (\a d_satClkDrift)and returns the clock drift in seconds according to the User Algorithm for SV Clock Correction diff --git a/src/core/system_parameters/gps_cnav_iono.cc b/src/core/system_parameters/gps_cnav_iono.cc index 8a7e3fd03..0e24c9dbe 100644 --- a/src/core/system_parameters/gps_cnav_iono.cc +++ b/src/core/system_parameters/gps_cnav_iono.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -44,4 +44,3 @@ Gps_CNAV_Iono::Gps_CNAV_Iono() d_beta2 = 0.0; d_beta3 = 0.0; } - diff --git a/src/core/system_parameters/gps_cnav_iono.h b/src/core/system_parameters/gps_cnav_iono.h index 67c1757ae..fa60b6a9b 100644 --- a/src/core/system_parameters/gps_cnav_iono.h +++ b/src/core/system_parameters/gps_cnav_iono.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,7 +33,7 @@ #define GNSS_SDR_GPS_CNAV_IONO_H_ -#include "boost/assign.hpp" +#include #include @@ -45,36 +45,38 @@ class Gps_CNAV_Iono { public: - bool valid; //!< Valid flag + bool valid; //!< Valid flag // Ionospheric parameters - double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] - double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] - double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] - double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] - double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] - double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] - double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] - double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] + double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] + double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] + double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] + double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] + double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] + double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] + double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] + double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] - Gps_CNAV_Iono(); //!< Default constructor + Gps_CNAV_Iono(); //!< Default constructor - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const unsigned int version) const { using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("d_alpha0",d_alpha0); - archive & make_nvp("d_alpha1",d_alpha1); - archive & make_nvp("d_alpha2",d_alpha2); - archive & make_nvp("d_alpha3",d_alpha3); - archive & make_nvp("d_beta0",d_beta0); - archive & make_nvp("d_beta1",d_beta1); - archive & make_nvp("d_beta2",d_beta2); - archive & make_nvp("d_beta3",d_beta3); + if (version) + { + }; + archive& make_nvp("d_alpha0", d_alpha0); + archive& make_nvp("d_alpha1", d_alpha1); + archive& make_nvp("d_alpha2", d_alpha2); + archive& make_nvp("d_alpha3", d_alpha3); + archive& make_nvp("d_beta0", d_beta0); + archive& make_nvp("d_beta1", d_beta1); + archive& make_nvp("d_beta2", d_beta2); + archive& make_nvp("d_beta3", d_beta3); } }; diff --git a/src/core/system_parameters/gps_cnav_navigation_message.cc b/src/core/system_parameters/gps_cnav_navigation_message.cc index dcfc582c8..ea1d10782 100644 --- a/src/core/system_parameters/gps_cnav_navigation_message.cc +++ b/src/core/system_parameters/gps_cnav_navigation_message.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,13 +25,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_cnav_navigation_message.h" -#include #include "gnss_satellite.h" @@ -40,22 +39,23 @@ void Gps_CNAV_Navigation_Message::reset() b_flag_ephemeris_1 = false; b_flag_ephemeris_2 = false; b_flag_iono_valid = false; + b_flag_utc_valid = false; // satellite positions - d_satpos_X = 0; - d_satpos_Y = 0; - d_satpos_Z = 0; + d_satpos_X = 0.0; + d_satpos_Y = 0.0; + d_satpos_Z = 0.0; // info i_channel_ID = 0; - i_satellite_PRN = 0; + i_satellite_PRN = 0U; // Satellite velocity - d_satvel_X = 0; - d_satvel_Y = 0; - d_satvel_Z = 0; + d_satvel_X = 0.0; + d_satvel_Y = 0.0; + d_satvel_Z = 0.0; - d_TOW = 0.0; + d_TOW = 0; } @@ -63,27 +63,20 @@ Gps_CNAV_Navigation_Message::Gps_CNAV_Navigation_Message() { reset(); Gnss_Satellite gnss_satellite_ = Gnss_Satellite(); - for(unsigned int prn_ = 1; prn_ < 33; prn_++) + for (uint32_t prn_ = 1; prn_ < 33; prn_++) { satelliteBlock[prn_] = gnss_satellite_.what_block("GPS", prn_); } b_flag_iono_valid = false; + b_flag_utc_valid = false; } -void Gps_CNAV_Navigation_Message::print_gps_word_bytes(unsigned int GPS_word) -{ - std::cout << " Word ="; - std::cout << std::bitset<32>(GPS_word); - std::cout << std::endl; -} - - -bool Gps_CNAV_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector> parameter) +bool Gps_CNAV_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector>& parameter) { bool value; - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[0].first] == 1) + if (static_cast(bits[GPS_CNAV_DATA_PAGE_BITS - parameter[0].first]) == 1) { value = true; } @@ -95,18 +88,18 @@ bool Gps_CNAV_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector> parameter) +uint64_t Gps_CNAV_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector>& parameter) { - unsigned long int value = 0; - int num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) + uint64_t value = 0ULL; + int32_t num_of_slices = parameter.size(); + for (int32_t i = 0; i < num_of_slices; i++) { - for (int j = 0; j < parameter[i].second; j++) + for (int32_t j = 0; j < parameter[i].second; j++) { - value <<= 1; //shift left - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[i].first - j] == 1) + value <<= 1; // shift left + if (static_cast(bits[GPS_CNAV_DATA_PAGE_BITS - parameter[i].first - j]) == 1) { - value += 1; // insert the bit + value += 1ULL; // insert the bit } } } @@ -114,59 +107,30 @@ unsigned long int Gps_CNAV_Navigation_Message::read_navigation_unsigned(std::bit } -signed long int Gps_CNAV_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector> parameter) +int64_t Gps_CNAV_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector>& parameter) { - signed long int value = 0; - int num_of_slices = parameter.size(); - // Discriminate between 64 bits and 32 bits compiler - int long_int_size_bytes = sizeof(signed long int); - if (long_int_size_bytes == 8) // if a long int takes 8 bytes, we are in a 64 bits system - { - // read the MSB and perform the sign extension - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFFFFFFFFFF; //64 bits variable - } - else - { - value &= 0; - } + int64_t value = 0LL; + int32_t num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) - { - for (int j = 0; j < parameter[i].second; j++) - { - value <<= 1; //shift left - value &= 0xFFFFFFFFFFFFFFFE; //reset the corresponding bit (for the 64 bits variable) - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } - } - } + // read the MSB and perform the sign extension + if (static_cast(bits[GPS_CNAV_DATA_PAGE_BITS - parameter[0].first]) == 1) + { + value ^= 0xFFFFFFFFFFFFFFFFLL; // 64 bits variable } - else // we assume we are in a 32 bits system + else { - // read the MSB and perform the sign extension - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFF; - } - else - { - value &= 0; - } + value &= 0LL; + } - for (int i = 0; i < num_of_slices; i++) + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 0; j < parameter[i].second; j++) { - for (int j = 0; j < parameter[i].second; j++) + value <<= 1; // shift left + value &= 0xFFFFFFFFFFFFFFFELL; // reset the corresponding bit (for the 64 bits variable) + if (static_cast(bits[GPS_CNAV_DATA_PAGE_BITS - parameter[i].first - j]) == 1) { - value <<= 1; //shift left - value &= 0xFFFFFFFE; //reset the corresponding bit - if (bits[GPS_L2_CNAV_DATA_PAGE_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } + value += 1LL; // insert the bit } } } @@ -174,168 +138,207 @@ signed long int Gps_CNAV_Navigation_Message::read_navigation_signed(std::bitset< } -void Gps_CNAV_Navigation_Message::decode_page(std::vector data) +void Gps_CNAV_Navigation_Message::decode_page(std::bitset data_bits) { - std::bitset data_bits; - - try - { - for(int i = 0; i < GPS_L2_CNAV_DATA_PAGE_BITS; i++) - { - data_bits[i] = static_cast(data[GPS_L2_CNAV_DATA_PAGE_BITS - i - 1]); - } - - } - catch(std::exception &e) - { - std::cout << "Exception converting to bitset " << e.what() << std::endl; - return; - } - - int PRN; - int page_type; - + int32_t PRN; + int32_t page_type; bool alert_flag; // common to all messages - PRN = static_cast(read_navigation_unsigned(data_bits, CNAV_PRN)); + PRN = static_cast(read_navigation_unsigned(data_bits, CNAV_PRN)); ephemeris_record.i_satellite_PRN = PRN; - d_TOW = static_cast(read_navigation_unsigned(data_bits, CNAV_TOW)); - d_TOW = d_TOW * CNAV_TOW_LSB; + d_TOW = static_cast(read_navigation_unsigned(data_bits, CNAV_TOW)); + d_TOW *= CNAV_TOW_LSB; ephemeris_record.d_TOW = d_TOW; alert_flag = static_cast(read_navigation_bool(data_bits, CNAV_ALERT_FLAG)); ephemeris_record.b_alert_flag = alert_flag; - page_type = static_cast(read_navigation_unsigned(data_bits, CNAV_MSG_TYPE)); + page_type = static_cast(read_navigation_unsigned(data_bits, CNAV_MSG_TYPE)); - std::cout << "PRN=" << PRN << " TOW=" << d_TOW << " alert_flag=" << alert_flag << " page_type= " << page_type << std::endl; - switch(page_type) - { - case 10: // Ephemeris 1/2 - ephemeris_record.i_GPS_week = static_cast(read_navigation_unsigned(data_bits, CNAV_WN)); - ephemeris_record.i_signal_health = static_cast(read_navigation_unsigned(data_bits, CNAV_HEALTH)); - ephemeris_record.d_Top = static_cast(read_navigation_unsigned(data_bits, CNAV_TOP1)); - ephemeris_record.d_Top = ephemeris_record.d_Top * CNAV_TOP1_LSB; - ephemeris_record.d_URA0 = static_cast(read_navigation_signed(data_bits, CNAV_URA)); - ephemeris_record.d_Toe1 = static_cast(read_navigation_unsigned(data_bits, CNAV_TOE1)); - ephemeris_record.d_Toe1 = ephemeris_record.d_Toe1 * CNAV_TOE1_LSB; - ephemeris_record.d_DELTA_A = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_A)); - ephemeris_record.d_DELTA_A = ephemeris_record.d_DELTA_A * CNAV_DELTA_A_LSB; - ephemeris_record.d_A_DOT = static_cast(read_navigation_signed(data_bits, CNAV_A_DOT)); - ephemeris_record.d_A_DOT = ephemeris_record.d_A_DOT * CNAV_A_DOT_LSB; - ephemeris_record.d_Delta_n = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_N0)); - ephemeris_record.d_Delta_n = ephemeris_record.d_Delta_n * CNAV_DELTA_N0_LSB; - ephemeris_record.d_DELTA_DOT_N = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_N0_DOT)); - ephemeris_record.d_DELTA_DOT_N = ephemeris_record.d_DELTA_DOT_N * CNAV_DELTA_N0_DOT_LSB; - ephemeris_record.d_M_0 = static_cast(read_navigation_signed(data_bits, CNAV_M0)); - ephemeris_record.d_M_0 = ephemeris_record.d_M_0 * CNAV_M0_LSB; - ephemeris_record.d_e_eccentricity = static_cast(read_navigation_signed(data_bits, CNAV_E_ECCENTRICITY)); - ephemeris_record.d_e_eccentricity = ephemeris_record.d_e_eccentricity * CNAV_E_ECCENTRICITY_LSB; - ephemeris_record.d_OMEGA = static_cast(read_navigation_signed(data_bits, CNAV_OMEGA)); - ephemeris_record.d_OMEGA = ephemeris_record.d_OMEGA * CNAV_OMEGA_LSB; + switch (page_type) + { + case 10: // Ephemeris 1/2 + ephemeris_record.i_GPS_week = static_cast(read_navigation_unsigned(data_bits, CNAV_WN)); + ephemeris_record.i_signal_health = static_cast(read_navigation_unsigned(data_bits, CNAV_HEALTH)); + ephemeris_record.d_Top = static_cast(read_navigation_unsigned(data_bits, CNAV_TOP1)); + ephemeris_record.d_Top *= CNAV_TOP1_LSB; + ephemeris_record.d_URA0 = static_cast(read_navigation_signed(data_bits, CNAV_URA)); + ephemeris_record.d_Toe1 = static_cast(read_navigation_unsigned(data_bits, CNAV_TOE1)); + ephemeris_record.d_Toe1 *= CNAV_TOE1_LSB; + ephemeris_record.d_DELTA_A = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_A)); + ephemeris_record.d_DELTA_A *= CNAV_DELTA_A_LSB; + ephemeris_record.d_A_DOT = static_cast(read_navigation_signed(data_bits, CNAV_A_DOT)); + ephemeris_record.d_A_DOT *= CNAV_A_DOT_LSB; + ephemeris_record.d_Delta_n = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_N0)); + ephemeris_record.d_Delta_n *= CNAV_DELTA_N0_LSB; + ephemeris_record.d_DELTA_DOT_N = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_N0_DOT)); + ephemeris_record.d_DELTA_DOT_N *= CNAV_DELTA_N0_DOT_LSB; + ephemeris_record.d_M_0 = static_cast(read_navigation_signed(data_bits, CNAV_M0)); + ephemeris_record.d_M_0 *= CNAV_M0_LSB; + ephemeris_record.d_e_eccentricity = static_cast(read_navigation_unsigned(data_bits, CNAV_E_ECCENTRICITY)); + ephemeris_record.d_e_eccentricity *= CNAV_E_ECCENTRICITY_LSB; + ephemeris_record.d_OMEGA = static_cast(read_navigation_signed(data_bits, CNAV_OMEGA)); + ephemeris_record.d_OMEGA *= CNAV_OMEGA_LSB; - ephemeris_record.b_integrity_status_flag = static_cast(read_navigation_bool(data_bits, CNAV_INTEGRITY_FLAG)); - ephemeris_record.b_l2c_phasing_flag = static_cast(read_navigation_bool(data_bits, CNAV_L2_PHASING_FLAG)); + ephemeris_record.b_integrity_status_flag = static_cast(read_navigation_bool(data_bits, CNAV_INTEGRITY_FLAG)); + ephemeris_record.b_l2c_phasing_flag = static_cast(read_navigation_bool(data_bits, CNAV_L2_PHASING_FLAG)); - b_flag_ephemeris_1 = true; - break; - case 11: // Ephemeris 2/2 - ephemeris_record.d_Toe2 = static_cast(read_navigation_unsigned(data_bits, CNAV_TOE2)); - ephemeris_record.d_Toe2 = ephemeris_record.d_Toe2 * CNAV_TOE2_LSB; - ephemeris_record.d_OMEGA0 = static_cast(read_navigation_signed(data_bits, CNAV_OMEGA0)); - ephemeris_record.d_OMEGA0 = ephemeris_record.d_OMEGA0 * CNAV_OMEGA0_LSB; - ephemeris_record.d_DELTA_OMEGA_DOT = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_OMEGA_DOT)); - ephemeris_record.d_DELTA_OMEGA_DOT = ephemeris_record.d_DELTA_OMEGA_DOT * CNAV_DELTA_OMEGA_DOT_LSB; - ephemeris_record.d_i_0 = static_cast(read_navigation_signed(data_bits, CNAV_I0)); - ephemeris_record.d_i_0 = ephemeris_record.d_i_0 * CNAV_I0_LSB; - ephemeris_record.d_IDOT = static_cast(read_navigation_signed(data_bits, CNAV_I0_DOT)); - ephemeris_record.d_IDOT = ephemeris_record.d_IDOT * CNAV_I0_DOT_LSB; - ephemeris_record.d_Cis = static_cast(read_navigation_signed(data_bits, CNAV_CIS)); - ephemeris_record.d_Cis = ephemeris_record.d_Cis * CNAV_CIS_LSB; - ephemeris_record.d_Cic = static_cast(read_navigation_signed(data_bits, CNAV_CIC)); - ephemeris_record.d_Cic = ephemeris_record.d_Cic * CNAV_CIC_LSB; - ephemeris_record.d_Crs = static_cast(read_navigation_signed(data_bits, CNAV_CRS)); - ephemeris_record.d_Crs = ephemeris_record.d_Crs * CNAV_CRS_LSB; - ephemeris_record.d_Crc = static_cast(read_navigation_signed(data_bits, CNAV_CRC)); - ephemeris_record.d_Cic = ephemeris_record.d_Cic * CNAV_CRC_LSB; - ephemeris_record.d_Cus = static_cast(read_navigation_signed(data_bits, CNAV_CUS)); - ephemeris_record.d_Cus = ephemeris_record.d_Cus * CNAV_CUS_LSB; - ephemeris_record.d_Cuc = static_cast(read_navigation_signed(data_bits, CNAV_CUC)); - ephemeris_record.d_Cuc = ephemeris_record.d_Cuc * CNAV_CUS_LSB; - b_flag_ephemeris_2 = true; - break; - case 30: // (CLOCK, IONO, GRUP DELAY) - //clock - ephemeris_record.d_Toc = static_cast(read_navigation_unsigned(data_bits, CNAV_TOC)); - ephemeris_record.d_Toc = ephemeris_record.d_Toc * CNAV_TOC_LSB; - ephemeris_record.d_URA0 = static_cast(read_navigation_signed(data_bits, CNAV_URA_NED0)); - ephemeris_record.d_URA1 = static_cast(read_navigation_unsigned(data_bits, CNAV_URA_NED1)); - ephemeris_record.d_URA2 = static_cast(read_navigation_unsigned(data_bits, CNAV_URA_NED2)); - ephemeris_record.d_A_f0 = static_cast(read_navigation_signed(data_bits, CNAV_AF0)); - ephemeris_record.d_A_f0 = ephemeris_record.d_A_f0 * CNAV_AF0_LSB; - ephemeris_record.d_A_f1 = static_cast(read_navigation_signed(data_bits, CNAV_AF1)); - ephemeris_record.d_A_f1 = ephemeris_record.d_A_f1 * CNAV_AF1_LSB; - ephemeris_record.d_A_f2 = static_cast(read_navigation_signed(data_bits, CNAV_AF2)); - ephemeris_record.d_A_f2 = ephemeris_record.d_A_f2 * CNAV_AF2_LSB; - //group delays - ephemeris_record.d_TGD = static_cast(read_navigation_signed(data_bits, CNAV_TGD)); - ephemeris_record.d_TGD = ephemeris_record.d_TGD * CNAV_TGD_LSB; - ephemeris_record.d_ISCL1 = static_cast(read_navigation_signed(data_bits, CNAV_ISCL1)); - ephemeris_record.d_ISCL1 = ephemeris_record.d_ISCL1 * CNAV_ISCL1_LSB; - ephemeris_record.d_ISCL2 = static_cast(read_navigation_signed(data_bits, CNAV_ISCL2)); - ephemeris_record.d_ISCL2 = ephemeris_record.d_ISCL2 * CNAV_ISCL2_LSB; - ephemeris_record.d_ISCL5I = static_cast(read_navigation_signed(data_bits, CNAV_ISCL5I)); - ephemeris_record.d_ISCL5I = ephemeris_record.d_ISCL5I * CNAV_ISCL5I_LSB; - ephemeris_record.d_ISCL5Q = static_cast(read_navigation_signed(data_bits, CNAV_ISCL5Q)); - ephemeris_record.d_ISCL5Q = ephemeris_record.d_ISCL5Q * CNAV_ISCL5Q_LSB; - //iono - iono_record.d_alpha0 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA0)); - iono_record.d_alpha0 = iono_record.d_alpha0 * CNAV_ALPHA0_LSB; - iono_record.d_alpha1 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA1)); - iono_record.d_alpha1 = iono_record.d_alpha1 * CNAV_ALPHA1_LSB; - iono_record.d_alpha2 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA2)); - iono_record.d_alpha2 = iono_record.d_alpha2 * CNAV_ALPHA2_LSB; - iono_record.d_alpha3 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA3)); - iono_record.d_alpha3 = iono_record.d_alpha3 * CNAV_ALPHA3_LSB; - iono_record.d_beta0 = static_cast(read_navigation_signed(data_bits, CNAV_BETA0)); - iono_record.d_beta0 = iono_record.d_beta0 * CNAV_BETA0_LSB; - iono_record.d_beta1 = static_cast(read_navigation_signed(data_bits, CNAV_BETA1)); - iono_record.d_beta1 = iono_record.d_beta1 * CNAV_BETA1_LSB; - iono_record.d_beta2 = static_cast(read_navigation_signed(data_bits, CNAV_BETA2)); - iono_record.d_beta2 = iono_record.d_beta2 * CNAV_BETA2_LSB; - iono_record.d_beta3 = static_cast(read_navigation_signed(data_bits, CNAV_BETA3)); - iono_record.d_beta3 = iono_record.d_beta3 * CNAV_BETA3_LSB; - b_flag_iono_valid = true; - break; - default: - break; - } + b_flag_ephemeris_1 = true; + break; + case 11: // Ephemeris 2/2 + ephemeris_record.d_Toe2 = static_cast(read_navigation_unsigned(data_bits, CNAV_TOE2)); + ephemeris_record.d_Toe2 *= CNAV_TOE2_LSB; + ephemeris_record.d_OMEGA0 = static_cast(read_navigation_signed(data_bits, CNAV_OMEGA0)); + ephemeris_record.d_OMEGA0 *= CNAV_OMEGA0_LSB; + ephemeris_record.d_DELTA_OMEGA_DOT = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_OMEGA_DOT)); + ephemeris_record.d_DELTA_OMEGA_DOT *= CNAV_DELTA_OMEGA_DOT_LSB; + ephemeris_record.d_i_0 = static_cast(read_navigation_signed(data_bits, CNAV_I0)); + ephemeris_record.d_i_0 *= CNAV_I0_LSB; + ephemeris_record.d_IDOT = static_cast(read_navigation_signed(data_bits, CNAV_I0_DOT)); + ephemeris_record.d_IDOT *= CNAV_I0_DOT_LSB; + ephemeris_record.d_Cis = static_cast(read_navigation_signed(data_bits, CNAV_CIS)); + ephemeris_record.d_Cis *= CNAV_CIS_LSB; + ephemeris_record.d_Cic = static_cast(read_navigation_signed(data_bits, CNAV_CIC)); + ephemeris_record.d_Cic *= CNAV_CIC_LSB; + ephemeris_record.d_Crs = static_cast(read_navigation_signed(data_bits, CNAV_CRS)); + ephemeris_record.d_Crs *= CNAV_CRS_LSB; + ephemeris_record.d_Crc = static_cast(read_navigation_signed(data_bits, CNAV_CRC)); + ephemeris_record.d_Crc *= CNAV_CRC_LSB; + ephemeris_record.d_Cus = static_cast(read_navigation_signed(data_bits, CNAV_CUS)); + ephemeris_record.d_Cus *= CNAV_CUS_LSB; + ephemeris_record.d_Cuc = static_cast(read_navigation_signed(data_bits, CNAV_CUC)); + ephemeris_record.d_Cuc *= CNAV_CUC_LSB; + b_flag_ephemeris_2 = true; + break; + case 30: // (CLOCK, IONO, GRUP DELAY) + //clock + ephemeris_record.d_Toc = static_cast(read_navigation_unsigned(data_bits, CNAV_TOC)); + ephemeris_record.d_Toc *= CNAV_TOC_LSB; + ephemeris_record.d_URA0 = static_cast(read_navigation_signed(data_bits, CNAV_URA_NED0)); + ephemeris_record.d_URA1 = static_cast(read_navigation_unsigned(data_bits, CNAV_URA_NED1)); + ephemeris_record.d_URA2 = static_cast(read_navigation_unsigned(data_bits, CNAV_URA_NED2)); + ephemeris_record.d_A_f0 = static_cast(read_navigation_signed(data_bits, CNAV_AF0)); + ephemeris_record.d_A_f0 *= CNAV_AF0_LSB; + ephemeris_record.d_A_f1 = static_cast(read_navigation_signed(data_bits, CNAV_AF1)); + ephemeris_record.d_A_f1 *= CNAV_AF1_LSB; + ephemeris_record.d_A_f2 = static_cast(read_navigation_signed(data_bits, CNAV_AF2)); + ephemeris_record.d_A_f2 *= CNAV_AF2_LSB; + //group delays + // Check if the grup delay values are not available. See IS-GPS-200, Table 30-IV. + //Bit string "1000000000000" is -4096 in 2 complement + ephemeris_record.d_TGD = static_cast(read_navigation_signed(data_bits, CNAV_TGD)); + if (ephemeris_record.d_TGD < -4095.9) + { + ephemeris_record.d_TGD = 0.0; + } + ephemeris_record.d_TGD *= CNAV_TGD_LSB; + + ephemeris_record.d_ISCL1 = static_cast(read_navigation_signed(data_bits, CNAV_ISCL1)); + if (ephemeris_record.d_ISCL1 < -4095.9) + { + ephemeris_record.d_ISCL1 = 0.0; + } + ephemeris_record.d_ISCL1 *= CNAV_ISCL1_LSB; + + ephemeris_record.d_ISCL2 = static_cast(read_navigation_signed(data_bits, CNAV_ISCL2)); + if (ephemeris_record.d_ISCL2 < -4095.9) + { + ephemeris_record.d_ISCL2 = 0.0; + } + ephemeris_record.d_ISCL2 *= CNAV_ISCL2_LSB; + + ephemeris_record.d_ISCL5I = static_cast(read_navigation_signed(data_bits, CNAV_ISCL5I)); + if (ephemeris_record.d_ISCL5I < -4095.9) + { + ephemeris_record.d_ISCL5I = 0.0; + } + ephemeris_record.d_ISCL5I *= CNAV_ISCL5I_LSB; + + ephemeris_record.d_ISCL5Q = static_cast(read_navigation_signed(data_bits, CNAV_ISCL5Q)); + if (ephemeris_record.d_ISCL5Q < -4095.9) + { + ephemeris_record.d_ISCL5Q = 0.0; + } + ephemeris_record.d_ISCL5Q *= CNAV_ISCL5Q_LSB; + //iono + iono_record.d_alpha0 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA0)); + iono_record.d_alpha0 = iono_record.d_alpha0 * CNAV_ALPHA0_LSB; + iono_record.d_alpha1 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA1)); + iono_record.d_alpha1 = iono_record.d_alpha1 * CNAV_ALPHA1_LSB; + iono_record.d_alpha2 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA2)); + iono_record.d_alpha2 = iono_record.d_alpha2 * CNAV_ALPHA2_LSB; + iono_record.d_alpha3 = static_cast(read_navigation_signed(data_bits, CNAV_ALPHA3)); + iono_record.d_alpha3 = iono_record.d_alpha3 * CNAV_ALPHA3_LSB; + iono_record.d_beta0 = static_cast(read_navigation_signed(data_bits, CNAV_BETA0)); + iono_record.d_beta0 = iono_record.d_beta0 * CNAV_BETA0_LSB; + iono_record.d_beta1 = static_cast(read_navigation_signed(data_bits, CNAV_BETA1)); + iono_record.d_beta1 = iono_record.d_beta1 * CNAV_BETA1_LSB; + iono_record.d_beta2 = static_cast(read_navigation_signed(data_bits, CNAV_BETA2)); + iono_record.d_beta2 = iono_record.d_beta2 * CNAV_BETA2_LSB; + iono_record.d_beta3 = static_cast(read_navigation_signed(data_bits, CNAV_BETA3)); + iono_record.d_beta3 = iono_record.d_beta3 * CNAV_BETA3_LSB; + b_flag_iono_valid = true; + break; + case 33: // (CLOCK & UTC) + ephemeris_record.d_Top = static_cast(read_navigation_unsigned(data_bits, CNAV_TOP1)); + ephemeris_record.d_Top = ephemeris_record.d_Top * CNAV_TOP1_LSB; + ephemeris_record.d_Toc = static_cast(read_navigation_unsigned(data_bits, CNAV_TOC)); + ephemeris_record.d_Toc = ephemeris_record.d_Toc * CNAV_TOC_LSB; + ephemeris_record.d_A_f0 = static_cast(read_navigation_signed(data_bits, CNAV_AF0)); + ephemeris_record.d_A_f0 = ephemeris_record.d_A_f0 * CNAV_AF0_LSB; + ephemeris_record.d_A_f1 = static_cast(read_navigation_signed(data_bits, CNAV_AF1)); + ephemeris_record.d_A_f1 = ephemeris_record.d_A_f1 * CNAV_AF1_LSB; + ephemeris_record.d_A_f2 = static_cast(read_navigation_signed(data_bits, CNAV_AF2)); + ephemeris_record.d_A_f2 = ephemeris_record.d_A_f2 * CNAV_AF2_LSB; + + utc_model_record.d_A0 = static_cast(read_navigation_signed(data_bits, CNAV_A0)); + utc_model_record.d_A0 = utc_model_record.d_A0 * CNAV_A0_LSB; + utc_model_record.d_A1 = static_cast(read_navigation_signed(data_bits, CNAV_A1)); + utc_model_record.d_A1 = utc_model_record.d_A1 * CNAV_A1_LSB; + utc_model_record.d_A2 = static_cast(read_navigation_signed(data_bits, CNAV_A2)); + utc_model_record.d_A2 = utc_model_record.d_A2 * CNAV_A2_LSB; + + utc_model_record.d_DeltaT_LS = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_TLS)); + utc_model_record.d_DeltaT_LS = utc_model_record.d_DeltaT_LS * CNAV_DELTA_TLS_LSB; + + utc_model_record.d_t_OT = static_cast(read_navigation_signed(data_bits, CNAV_TOT)); + utc_model_record.d_t_OT = utc_model_record.d_t_OT * CNAV_TOT_LSB; + + utc_model_record.i_WN_T = static_cast(read_navigation_signed(data_bits, CNAV_WN_OT)); + utc_model_record.i_WN_T = utc_model_record.i_WN_T * CNAV_WN_OT_LSB; + + utc_model_record.i_WN_LSF = static_cast(read_navigation_signed(data_bits, CNAV_WN_LSF)); + utc_model_record.i_WN_LSF = utc_model_record.i_WN_LSF * CNAV_WN_LSF_LSB; + + utc_model_record.i_DN = static_cast(read_navigation_signed(data_bits, CNAV_DN)); + utc_model_record.i_DN = utc_model_record.i_DN * CNAV_DN_LSB; + + utc_model_record.d_DeltaT_LSF = static_cast(read_navigation_signed(data_bits, CNAV_DELTA_TLSF)); + utc_model_record.d_DeltaT_LSF = utc_model_record.d_DeltaT_LSF * CNAV_DELTA_TLSF_LSB; + b_flag_utc_valid = true; + break; + default: + break; + } } -bool Gps_CNAV_Navigation_Message::have_new_ephemeris() //Check if we have a new ephemeris stored in the galileo navigation class +bool Gps_CNAV_Navigation_Message::have_new_ephemeris() // Check if we have a new ephemeris stored in the galileo navigation class { if (b_flag_ephemeris_1 == true and b_flag_ephemeris_2 == true) { - if (ephemeris_record.d_Toe1 == ephemeris_record.d_Toe2) + if (ephemeris_record.d_Toe1 == ephemeris_record.d_Toe2) // and ephemeris_record.d_Toe1==ephemeris_record.d_Toc) { - //if all ephemeris pages have the same TOE, then they belong to the same block + // if all ephemeris pages have the same TOE, then they belong to the same block // std::cout << "Ephemeris (1, 2) have been received and belong to the same batch" << std::endl; - b_flag_ephemeris_1 = false;// clear the flag - b_flag_ephemeris_2 = false;// clear the flag + b_flag_ephemeris_1 = false; // clear the flag + b_flag_ephemeris_2 = false; // clear the flag return true; } - else - { - return false; - } - } - else - { - return false; } + return false; } @@ -345,17 +348,14 @@ Gps_CNAV_Ephemeris Gps_CNAV_Navigation_Message::get_ephemeris() } -bool Gps_CNAV_Navigation_Message::have_new_iono() //Check if we have a new iono data stored in the galileo navigation class +bool Gps_CNAV_Navigation_Message::have_new_iono() // Check if we have a new iono data stored in the galileo navigation class { if (b_flag_iono_valid == true) { - b_flag_iono_valid = false;// clear the flag + b_flag_iono_valid = false; // clear the flag return true; } - else - { - return false; - } + return false; } @@ -365,7 +365,19 @@ Gps_CNAV_Iono Gps_CNAV_Navigation_Message::get_iono() } +bool Gps_CNAV_Navigation_Message::have_new_utc_model() // Check if we have a new iono data stored in the galileo navigation class +{ + if (b_flag_utc_valid == true) + { + b_flag_utc_valid = false; // clear the flag + return true; + } + return false; +} + + Gps_CNAV_Utc_Model Gps_CNAV_Navigation_Message::get_utc_model() { + utc_model_record.valid = true; return utc_model_record; } diff --git a/src/core/system_parameters/gps_cnav_navigation_message.h b/src/core/system_parameters/gps_cnav_navigation_message.h index 0fe71123a..62fc6fbc1 100644 --- a/src/core/system_parameters/gps_cnav_navigation_message.h +++ b/src/core/system_parameters/gps_cnav_navigation_message.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,20 +33,21 @@ #define GNSS_SDR_GPS_CNAV_NAVIGATION_MESSAGE_H_ -#include -#include -#include -#include -#include -#include "GPS_L2C.h" +#include "GPS_CNAV.h" #include "gps_cnav_ephemeris.h" #include "gps_cnav_iono.h" #include "gps_cnav_utc_model.h" +#include +#include +#include +#include +#include +#include + //TODO: Create GPS CNAV almanac //#include "gps_almanac.h" - /*! * \brief This class decodes a GPS CNAV Data message as described in IS-GPS-200H * @@ -55,49 +56,52 @@ class Gps_CNAV_Navigation_Message { private: - unsigned long int read_navigation_unsigned(std::bitset bits, const std::vector> parameter); - signed long int read_navigation_signed(std::bitset bits, const std::vector> parameter); - bool read_navigation_bool(std::bitset bits, const std::vector> parameter); - void print_gps_word_bytes(unsigned int GPS_word); + uint64_t read_navigation_unsigned(std::bitset bits, const std::vector>& parameter); + int64_t read_navigation_signed(std::bitset bits, const std::vector>& parameter); + bool read_navigation_bool(std::bitset bits, const std::vector>& parameter); Gps_CNAV_Ephemeris ephemeris_record; Gps_CNAV_Iono iono_record; Gps_CNAV_Utc_Model utc_model_record; public: - double d_TOW; + int32_t d_TOW; bool b_flag_ephemeris_1; bool b_flag_ephemeris_2; - bool b_flag_iono_valid; //!< If set, it indicates that the ionospheric parameters are filled (page 18 has arrived and decoded) + bool b_flag_iono_valid; //!< If set, it indicates that the ionospheric parameters are filled and are not yet read by the get_iono + bool b_flag_utc_valid; //!< If set, it indicates that the utc parameters are filled and are not yet read by the get_utc_model - std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus + std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus // satellite positions - double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. - double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. - double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). + double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. + double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. + double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). // satellite identification info - int i_channel_ID; - unsigned int i_satellite_PRN; + int32_t i_channel_ID; + uint32_t i_satellite_PRN; // Satellite velocity - double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] - double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] - double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] + double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] + double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] + double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] // public functions void reset(); - void decode_page(std::vector data); + void decode_page(std::bitset data_bits); + /*! * \brief Obtain a GPS SV Ephemeris class filled with current SV data */ Gps_CNAV_Ephemeris get_ephemeris(); + /*! - * \brief Check if we have a new iono record stored in the galileo navigation class + * \brief Check if we have a new iono record stored in the GPS ephemeris class */ bool have_new_iono(); + /*! * \brief Obtain a GPS ionospheric correction parameters class filled with current SV data */ @@ -109,7 +113,12 @@ public: Gps_CNAV_Utc_Model get_utc_model(); /*! - * \brief Check if we have a new ephemeris stored in the galileo navigation class + * \briefCheck if we have a new GPS UTC model record stored in the GPS ephemeris class + */ + bool have_new_utc_model(); + + /*! + * \brief Check if we have a new ephemeris stored in the GPS ephemeris class */ bool have_new_ephemeris(); diff --git a/src/core/system_parameters/gps_cnav_utc_model.cc b/src/core/system_parameters/gps_cnav_utc_model.cc index 748b0c306..673329f31 100644 --- a/src/core/system_parameters/gps_cnav_utc_model.cc +++ b/src/core/system_parameters/gps_cnav_utc_model.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,19 +23,20 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_cnav_utc_model.h" - +#include Gps_CNAV_Utc_Model::Gps_CNAV_Utc_Model() { valid = false; - d_A1 = 0; - d_A0 = 0; + d_A2 = 0.0; + d_A1 = 0.0; + d_A0 = 0.0; d_t_OT = 0; i_WN_T = 0; d_DeltaT_LS = 0; @@ -43,3 +44,71 @@ Gps_CNAV_Utc_Model::Gps_CNAV_Utc_Model() i_DN = 0; d_DeltaT_LSF = 0; } + + +double Gps_CNAV_Utc_Model::utc_time(double gpstime_corrected, int32_t i_GPS_week) +{ + double t_utc; + double t_utc_daytime; + double Delta_t_UTC = d_DeltaT_LS + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); + + // Determine if the effectivity time of the leap second event is in the past + int32_t weeksToLeapSecondEvent = i_WN_LSF - i_GPS_week; + + if (weeksToLeapSecondEvent >= 0) // is not in the past + { + // Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s + int32_t secondOfLeapSecondEvent = i_DN * 24 * 60 * 60; + if (weeksToLeapSecondEvent > 0) + { + t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); + } + else // we are in the same week than the leap second event + { + if (std::abs(gpstime_corrected - secondOfLeapSecondEvent) > 21600) + { + /* 20.3.3.5.2.4a + * Whenever the effectivity time indicated by the WN_LSF and the DN values + * is not in the past (relative to the user's present time), and the user's + * present time does not fall in the time span which starts at six hours prior + * to the effectivity time and ends at six hours after the effectivity time, + * the UTC/GPS-time relationship is given by + */ + t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); + } + else + { + /* 20.3.3.5.2.4b + * Whenever the user's current time falls within the time span of six hours + * prior to the effectivity time to six hours after the effectivity time, + * proper accommodation of the leap second event with a possible week number + * transition is provided by the following expression for UTC: + */ + int32_t W = static_cast(fmod(gpstime_corrected - Delta_t_UTC - 43200, 86400)) + 43200; + t_utc_daytime = fmod(W, 86400 + d_DeltaT_LSF - d_DeltaT_LS); + // implement something to handle a leap second event! + } + if ((gpstime_corrected - secondOfLeapSecondEvent) > 21600) + { + Delta_t_UTC = d_DeltaT_LSF + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); + t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); + } + } + } + else // the effectivity time is in the past + { + /* 20.3.3.5.2.4c + * Whenever the effectivity time of the leap second event, as indicated by the + * WNLSF and DN values, is in the "past" (relative to the user's current time), + * and the user's current time does not fall in the time span as given above + * in 20.3.3.5.2.4b,*/ + /* FOR CNAV: Replace the 20.3.3.5.2.4c with 30.3.3.6.2 UTC and GPS Time as follows */ + double tmp_d = (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); + Delta_t_UTC = d_DeltaT_LSF + d_A0 + d_A1 * tmp_d + d_A2 * tmp_d * tmp_d; + t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); + } + + double secondsOfWeekBeforeToday = 86400 * floor(gpstime_corrected / 86400); + t_utc = secondsOfWeekBeforeToday + t_utc_daytime; + return t_utc; +} diff --git a/src/core/system_parameters/gps_cnav_utc_model.h b/src/core/system_parameters/gps_cnav_utc_model.h index 80ff61eb7..555c7c640 100644 --- a/src/core/system_parameters/gps_cnav_utc_model.h +++ b/src/core/system_parameters/gps_cnav_utc_model.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,9 @@ #ifndef GNSS_SDR_GPS_CNAV_UTC_MODEL_H_ #define GNSS_SDR_GPS_CNAV_UTC_MODEL_H_ -#include "boost/assign.hpp" +#include #include - +#include /*! * \brief This class is a storage for the GPS UTC MODEL data as described in in IS-GPS-200H @@ -46,39 +46,47 @@ class Gps_CNAV_Utc_Model public: bool valid; // UTC parameters - double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200H) [s/s] - double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200H) [s] - double d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200H) [s] - int i_WN_T; //!< UTC reference week number [weeks] - double d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. - int i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] - int i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] - double d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] + double d_A2; //!< 2nd order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200H) [s/s] + double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200H) [s/s] + double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200H) [s] + int32_t d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200H) [s] + int32_t i_WN_T; //!< UTC reference week number [weeks] + int32_t d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. + int32_t i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] + int32_t i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] + int32_t d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] /*! * Default constructor */ Gps_CNAV_Utc_Model(); - template + /*! + * \brief Computes the Coordinated Universal Time (UTC) and + * returns it in [s] (IS-GPS-200E, 20.3.3.5.2.4 + 30.3.3.6.2) + */ + double utc_time(double gpstime_corrected, int32_t i_GPS_week); + + template /* * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const uint32_t version) { using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("valid",valid); - archive & make_nvp("d_A1",d_A1); - archive & make_nvp("d_A0",d_A0); - archive & make_nvp("d_t_OT",d_t_OT); - archive & make_nvp("i_WN_T",i_WN_T); - archive & make_nvp("d_DeltaT_LS",d_DeltaT_LS); - archive & make_nvp("i_WN_LSF",i_WN_LSF); - archive & make_nvp("i_DN",i_DN); - archive & make_nvp("d_DeltaT_LSF",d_DeltaT_LSF); + if (version) + { + }; + archive& make_nvp("valid", valid); + archive& make_nvp("d_A1", d_A1); + archive& make_nvp("d_A0", d_A0); + archive& make_nvp("d_t_OT", d_t_OT); + archive& make_nvp("i_WN_T", i_WN_T); + archive& make_nvp("d_DeltaT_LS", d_DeltaT_LS); + archive& make_nvp("i_WN_LSF", i_WN_LSF); + archive& make_nvp("i_DN", i_DN); + archive& make_nvp("d_DeltaT_LSF", d_DeltaT_LSF); } - }; #endif diff --git a/src/core/system_parameters/gps_ephemeris.cc b/src/core/system_parameters/gps_ephemeris.cc index 36ed12346..c6e181815 100644 --- a/src/core/system_parameters/gps_ephemeris.cc +++ b/src/core/system_parameters/gps_ephemeris.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,37 +25,37 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_ephemeris.h" -#include #include "GPS_L1_CA.h" #include "gnss_satellite.h" +#include Gps_Ephemeris::Gps_Ephemeris() { - i_satellite_PRN = 0; + i_satellite_PRN = 0U; d_TOW = 0; - d_Crs = 0; - d_Delta_n = 0; - d_M_0 = 0; - d_Cuc = 0; - d_e_eccentricity = 0; - d_Cus = 0; - d_sqrt_A = 0; + d_Crs = 0.0; + d_Delta_n = 0.0; + d_M_0 = 0.0; + d_Cuc = 0.0; + d_e_eccentricity = 0.0; + d_Cus = 0.0; + d_sqrt_A = 0.0; d_Toe = 0; d_Toc = 0; - d_Cic = 0; - d_OMEGA0 = 0; - d_Cis = 0; - d_i_0 = 0; - d_Crc = 0; - d_OMEGA = 0; - d_OMEGA_DOT = 0; - d_IDOT = 0; + d_Cic = 0.0; + d_OMEGA0 = 0.0; + d_Cis = 0.0; + d_i_0 = 0.0; + d_Crc = 0.0; + d_OMEGA = 0.0; + d_OMEGA_DOT = 0.0; + d_IDOT = 0.0; i_code_on_L2 = 0; i_GPS_week = 0; b_L2_P_data_flag = false; @@ -63,25 +63,25 @@ Gps_Ephemeris::Gps_Ephemeris() i_SV_health = 0; d_IODE_SF2 = 0; d_IODE_SF3 = 0; - d_TGD = 0; // Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] - d_IODC = 0; // Issue of Data, Clock - i_AODO = 0; // Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] + d_TGD = 0.0; // Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + d_IODC = 0; // Issue of Data, Clock + i_AODO = 0; // Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] - b_fit_interval_flag = false; // indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. - d_spare1 = 0; - d_spare2 = 0; + b_fit_interval_flag = false; // indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. + d_spare1 = 0.0; + d_spare2 = 0.0; - d_A_f0 = 0; // Coefficient 0 of code phase offset model [s] - d_A_f1 = 0; // Coefficient 1 of code phase offset model [s/s] - d_A_f2 = 0; // Coefficient 2 of code phase offset model [s/s^2] + d_A_f0 = 0.0; // Coefficient 0 of code phase offset model [s] + d_A_f1 = 0.0; // Coefficient 1 of code phase offset model [s/s] + d_A_f2 = 0.0; // Coefficient 2 of code phase offset model [s/s^2] b_integrity_status_flag = false; b_alert_flag = false; // If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. b_antispoofing_flag = false; // If true, the AntiSpoofing mode is ON in that SV auto gnss_sat = Gnss_Satellite(); - std::string _system ("GPS"); - for(unsigned int i = 1; i < 33; i++) + std::string _system("GPS"); + for (uint32_t i = 1; i < 33; i++) { satelliteBlock[i] = gnss_sat.what_block(_system, i); } @@ -100,7 +100,7 @@ Gps_Ephemeris::Gps_Ephemeris() double Gps_Ephemeris::check_t(double time) { double corrTime; - double half_week = 302400.0; // seconds + double half_week = 302400.0; // seconds corrTime = time; if (time > half_week) { @@ -117,14 +117,21 @@ double Gps_Ephemeris::check_t(double time) // 20.3.3.3.3.1 User Algorithm for SV Clock Correction. double Gps_Ephemeris::sv_clock_drift(double transmitTime) { + // double dt; + // dt = check_t(transmitTime - d_Toc); + // + // for (int32_t i = 0; i < 2; i++) + // { + // dt -= d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt); + // } + // d_satClkDrift = d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt); + + double dt; dt = check_t(transmitTime - d_Toc); - - for (int i = 0; i < 2; i++) - { - dt -= d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt); - } - d_satClkDrift = d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt); + d_satClkDrift = d_A_f0 + d_A_f1 * dt + d_A_f2 * (dt * dt) + sv_clock_relativistic_term(transmitTime); + //Correct satellite group delay + d_satClkDrift -= d_TGD; return d_satClkDrift; } @@ -156,17 +163,17 @@ double Gps_Ephemeris::sv_clock_relativistic_term(double transmitTime) M = d_M_0 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2.0 * GPS_PI), (2.0 * GPS_PI)); + //M = fmod((M + 2.0 * GPS_PI), (2.0 * GPS_PI)); // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + d_e_eccentricity * sin(E); - dE = fmod(E - E_old, 2.0 * GPS_PI); + E_old = E; + E = M + d_e_eccentricity * sin(E); + dE = fmod(E - E_old, 2.0 * GPS_PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -215,17 +222,17 @@ double Gps_Ephemeris::satellitePosition(double transmitTime) M = d_M_0 + n * tk; // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2.0 * GPS_PI), (2.0 * GPS_PI)); + //M = fmod((M + 2.0 * GPS_PI), (2.0 * GPS_PI)); // Initial guess of eccentric anomaly E = M; // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) + for (int32_t ii = 1; ii < 20; ii++) { - E_old = E; - E = M + d_e_eccentricity * sin(E); - dE = fmod(E - E_old, 2.0 * GPS_PI); + E_old = E; + E = M + d_e_eccentricity * sin(E); + dE = fmod(E - E_old, 2.0 * GPS_PI); if (fabs(dE) < 1e-12) { //Necessary precision is reached, exit from the loop @@ -242,22 +249,22 @@ double Gps_Ephemeris::satellitePosition(double transmitTime) phi = nu + d_OMEGA; // Reduce phi to between 0 and 2*pi rad - phi = fmod((phi), (2.0 * GPS_PI)); + //phi = fmod((phi), (2.0 * GPS_PI)); // Correct argument of latitude - u = phi + d_Cuc * cos(2.0 * phi) + d_Cus * sin(2.0 * phi); + u = phi + d_Cuc * cos(2.0 * phi) + d_Cus * sin(2.0 * phi); // Correct radius - r = a * (1.0 - d_e_eccentricity*cos(E)) + d_Crc * cos(2.0 * phi) + d_Crs * sin(2.0 * phi); + r = a * (1.0 - d_e_eccentricity * cos(E)) + d_Crc * cos(2.0 * phi) + d_Crs * sin(2.0 * phi); // Correct inclination i = d_i_0 + d_IDOT * tk + d_Cic * cos(2.0 * phi) + d_Cis * sin(2.0 * phi); // Compute the angle between the ascending node and the Greenwich meridian - Omega = d_OMEGA0 + (d_OMEGA_DOT - OMEGA_EARTH_DOT)*tk - OMEGA_EARTH_DOT * d_Toe; + Omega = d_OMEGA0 + (d_OMEGA_DOT - OMEGA_EARTH_DOT) * tk - OMEGA_EARTH_DOT * d_Toe; // Reduce to between 0 and 2*pi rad - Omega = fmod((Omega + 2.0 * GPS_PI), (2.0 * GPS_PI)); + //Omega = fmod((Omega + 2.0 * GPS_PI), (2.0 * GPS_PI)); // --- Compute satellite coordinates in Earth-fixed coordinates d_satpos_X = cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega); @@ -266,7 +273,7 @@ double Gps_Ephemeris::satellitePosition(double transmitTime) // Satellite's velocity. Can be useful for Vector Tracking loops double Omega_dot = d_OMEGA_DOT - OMEGA_EARTH_DOT; - d_satvel_X = - Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); + d_satvel_X = -Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); d_satvel_Y = Omega_dot * (cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega)) + d_satpos_X * sin(Omega) + d_satpos_Y * cos(i) * cos(Omega); d_satvel_Z = d_satpos_Y * sin(i); diff --git a/src/core/system_parameters/gps_ephemeris.h b/src/core/system_parameters/gps_ephemeris.h index c71fde0b6..683eb9135 100644 --- a/src/core/system_parameters/gps_ephemeris.h +++ b/src/core/system_parameters/gps_ephemeris.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,11 +33,12 @@ #define GNSS_SDR_GPS_EPHEMERIS_H_ +#include +#include +#include +#include #include #include -#include "boost/assign.hpp" -#include - /*! @@ -56,44 +57,45 @@ private: * \param[out] - corrected time, in seconds */ double check_t(double time); -public: - unsigned int i_satellite_PRN; // SV PRN NUMBER - double d_TOW; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] - double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] - double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] - double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] - double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] - double d_e_eccentricity; //!< Eccentricity [dimensionless] - double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] - double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] - double d_Toe; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - double d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] - double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] - double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] - double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] - double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] - double d_OMEGA; //!< Argument of Perigee [semi-cicles] - double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] - double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] - int i_code_on_L2; //!< If 1, P code ON in L2; if 2, C/A code ON in L2; - int i_GPS_week; //!< GPS week number, aka WN [week] - bool b_L2_P_data_flag; //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel - int i_SV_accuracy; //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) - int i_SV_health; - double d_TGD; //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] - double d_IODC; //!< Issue of Data, Clock - double d_IODE_SF2; //!< Issue of Data, Ephemeris (IODE), subframe 2 - double d_IODE_SF3; //!< Issue of Data, Ephemeris(IODE), subframe 3 - int i_AODO; //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] - bool b_fit_interval_flag;//!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. +public: + uint32_t i_satellite_PRN; // SV PRN NUMBER + int32_t d_TOW; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] + double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] + double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] + double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] + double d_e_eccentricity; //!< Eccentricity [dimensionless] + double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] + double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] + int32_t d_Toe; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + int32_t d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] + double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] + double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] + double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] + double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] + double d_OMEGA; //!< Argument of Perigee [semi-cicles] + double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] + double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] + int32_t i_code_on_L2; //!< If 1, P code ON in L2; if 2, C/A code ON in L2; + int32_t i_GPS_week; //!< GPS week number, aka WN [week] + bool b_L2_P_data_flag; //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel + int32_t i_SV_accuracy; //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) + int32_t i_SV_health; + double d_TGD; //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + int32_t d_IODC; //!< Issue of Data, Clock + int32_t d_IODE_SF2; //!< Issue of Data, Ephemeris (IODE), subframe 2 + int32_t d_IODE_SF3; //!< Issue of Data, Ephemeris(IODE), subframe 3 + int32_t i_AODO; //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] + + bool b_fit_interval_flag; //!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. double d_spare1; double d_spare2; - double d_A_f0; //!< Coefficient 0 of code phase offset model [s] - double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] - double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] + double d_A_f0; //!< Coefficient 0 of code phase offset model [s] + double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] + double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] // Flags @@ -109,75 +111,77 @@ public: */ bool b_integrity_status_flag; bool b_alert_flag; //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. - bool b_antispoofing_flag; //!< If true, the AntiSpoofing mode is ON in that SV + bool b_antispoofing_flag; //!< If true, the AntiSpoofing mode is ON in that SV // clock terms derived from ephemeris data - double d_satClkDrift; //!< GPS clock error - double d_dtr; //!< relativistic clock correction term + double d_satClkDrift; //!< GPS clock error + double d_dtr; //!< relativistic clock correction term // satellite positions - double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. - double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. - double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). + double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. + double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. + double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). // Satellite velocity - double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] - double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] - double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] + double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] + double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] + double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] - std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus + std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const uint32_t version) { using boost::serialization::make_nvp; - if(version){}; + if (version) + { + }; - archive & make_nvp("i_satellite_PRN", i_satellite_PRN); // SV PRN NUMBER - archive & make_nvp("d_TOW", d_TOW); //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] - archive & make_nvp("d_IODE_SF2", d_IODE_SF2); - archive & make_nvp("d_IODE_SF3", d_IODE_SF3); - archive & make_nvp("d_Crs", d_Crs); //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] - archive & make_nvp("d_Delta_n", d_Delta_n); //!< Mean Motion Difference From Computed Value [semi-circles/s] - archive & make_nvp("d_M_0", d_M_0); //!< Mean Anomaly at Reference Time [semi-circles] - archive & make_nvp("d_Cuc", d_Cuc); //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] - archive & make_nvp("d_e_eccentricity", d_e_eccentricity); //!< Eccentricity [dimensionless] - archive & make_nvp("d_Cus", d_Cus); //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] - archive & make_nvp("d_sqrt_A", d_sqrt_A); //!< Square Root of the Semi-Major Axis [sqrt(m)] - archive & make_nvp("d_Toe", d_Toe); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - archive & make_nvp("d_Toc", d_Toe); //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] - archive & make_nvp("d_Cic", d_Cic); //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] - archive & make_nvp("d_OMEGA0", d_OMEGA0); //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - archive & make_nvp("d_Cis", d_Cis); //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] - archive & make_nvp("d_i_0", d_i_0); //!< Inclination Angle at Reference Time [semi-circles] - archive & make_nvp("d_Crc", d_Crc); //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] - archive & make_nvp("d_OMEGA", d_OMEGA); //!< Argument of Perigee [semi-cicles] - archive & make_nvp("d_OMEGA_DOT", d_OMEGA_DOT); //!< Rate of Right Ascension [semi-circles/s] - archive & make_nvp("d_IDOT", d_IDOT); //!< Rate of Inclination Angle [semi-circles/s] - archive & make_nvp("i_code_on_L2", i_code_on_L2); //!< If 1, P code ON in L2; if 2, C/A code ON in L2; - archive & make_nvp("i_GPS_week", i_GPS_week); //!< GPS week number, aka WN [week] - archive & make_nvp("b_L2_P_data_flag", b_L2_P_data_flag); //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel - archive & make_nvp("i_SV_accuracy", i_SV_accuracy); //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) - archive & make_nvp("i_SV_health", i_SV_health); - archive & make_nvp("d_TGD", d_TGD); //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] - archive & make_nvp("d_IODC", d_IODC); //!< Issue of Data, Clock - archive & make_nvp("i_AODO", i_AODO); //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] + archive& make_nvp("i_satellite_PRN", i_satellite_PRN); // SV PRN NUMBER + archive& make_nvp("d_TOW", d_TOW); //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + archive& make_nvp("d_IODE_SF2", d_IODE_SF2); + archive& make_nvp("d_IODE_SF3", d_IODE_SF3); + archive& make_nvp("d_Crs", d_Crs); //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] + archive& make_nvp("d_Delta_n", d_Delta_n); //!< Mean Motion Difference From Computed Value [semi-circles/s] + archive& make_nvp("d_M_0", d_M_0); //!< Mean Anomaly at Reference Time [semi-circles] + archive& make_nvp("d_Cuc", d_Cuc); //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] + archive& make_nvp("d_e_eccentricity", d_e_eccentricity); //!< Eccentricity [dimensionless] + archive& make_nvp("d_Cus", d_Cus); //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] + archive& make_nvp("d_sqrt_A", d_sqrt_A); //!< Square Root of the Semi-Major Axis [sqrt(m)] + archive& make_nvp("d_Toe", d_Toe); //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + archive& make_nvp("d_Toc", d_Toc); //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] + archive& make_nvp("d_Cic", d_Cic); //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] + archive& make_nvp("d_OMEGA0", d_OMEGA0); //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + archive& make_nvp("d_Cis", d_Cis); //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] + archive& make_nvp("d_i_0", d_i_0); //!< Inclination Angle at Reference Time [semi-circles] + archive& make_nvp("d_Crc", d_Crc); //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] + archive& make_nvp("d_OMEGA", d_OMEGA); //!< Argument of Perigee [semi-cicles] + archive& make_nvp("d_OMEGA_DOT", d_OMEGA_DOT); //!< Rate of Right Ascension [semi-circles/s] + archive& make_nvp("d_IDOT", d_IDOT); //!< Rate of Inclination Angle [semi-circles/s] + archive& make_nvp("i_code_on_L2", i_code_on_L2); //!< If 1, P code ON in L2; if 2, C/A code ON in L2; + archive& make_nvp("i_GPS_week", i_GPS_week); //!< GPS week number, aka WN [week] + archive& make_nvp("b_L2_P_data_flag", b_L2_P_data_flag); //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel + archive& make_nvp("i_SV_accuracy", i_SV_accuracy); //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) + archive& make_nvp("i_SV_health", i_SV_health); + archive& make_nvp("d_TGD", d_TGD); //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + archive& make_nvp("d_IODC", d_IODC); //!< Issue of Data, Clock + archive& make_nvp("i_AODO", i_AODO); //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] - archive & make_nvp("b_fit_interval_flag", b_fit_interval_flag);//!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. - archive & make_nvp("d_spare1", d_spare1); - archive & make_nvp("d_spare2", d_spare2); + archive& make_nvp("b_fit_interval_flag", b_fit_interval_flag); //!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. + archive& make_nvp("d_spare1", d_spare1); + archive& make_nvp("d_spare2", d_spare2); - archive & make_nvp("d_A_f0", d_A_f0); //!< Coefficient 0 of code phase offset model [s] - archive & make_nvp("d_A_f1", d_A_f1); //!< Coefficient 1 of code phase offset model [s/s] - archive & make_nvp("d_A_f2", d_A_f2); //!< Coefficient 2 of code phase offset model [s/s^2] + archive& make_nvp("d_A_f0", d_A_f0); //!< Coefficient 0 of code phase offset model [s] + archive& make_nvp("d_A_f1", d_A_f1); //!< Coefficient 1 of code phase offset model [s/s] + archive& make_nvp("d_A_f2", d_A_f2); //!< Coefficient 2 of code phase offset model [s/s^2] - archive & make_nvp("b_integrity_status_flag", b_integrity_status_flag); - archive & make_nvp("b_alert_flag", b_alert_flag); //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. - archive & make_nvp("b_antispoofing_flag", b_antispoofing_flag); //!< If true, the AntiSpoofing mode is ON in that SV + archive& make_nvp("b_integrity_status_flag", b_integrity_status_flag); + archive& make_nvp("b_alert_flag", b_alert_flag); //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. + archive& make_nvp("b_antispoofing_flag", b_antispoofing_flag); //!< If true, the AntiSpoofing mode is ON in that SV } /*! @@ -199,7 +203,6 @@ public: */ double sv_clock_relativistic_term(double transmitTime); - /*! * Default constructor */ diff --git a/src/core/system_parameters/gps_iono.cc b/src/core/system_parameters/gps_iono.cc index 48b2b127a..05f17339a 100644 --- a/src/core/system_parameters/gps_iono.cc +++ b/src/core/system_parameters/gps_iono.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -44,4 +44,3 @@ Gps_Iono::Gps_Iono() d_beta2 = 0.0; d_beta3 = 0.0; } - diff --git a/src/core/system_parameters/gps_iono.h b/src/core/system_parameters/gps_iono.h index 0544c90a2..8a87e21d4 100644 --- a/src/core/system_parameters/gps_iono.h +++ b/src/core/system_parameters/gps_iono.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,7 +33,7 @@ #define GNSS_SDR_GPS_IONO_H_ -#include "boost/assign.hpp" +#include #include @@ -45,36 +45,38 @@ class Gps_Iono { public: - bool valid; //!< Valid flag + bool valid; //!< Valid flag // Ionospheric parameters - double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] - double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] - double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] - double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] - double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] - double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] - double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] - double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] + double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] + double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] + double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] + double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] + double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] + double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] + double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] + double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] - Gps_Iono(); //!< Default constructor + Gps_Iono(); //!< Default constructor - template + template /*! * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const unsigned int version) { using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("d_alpha0",d_alpha0); - archive & make_nvp("d_alpha1",d_alpha1); - archive & make_nvp("d_alpha2",d_alpha2); - archive & make_nvp("d_alpha3",d_alpha3); - archive & make_nvp("d_beta0",d_beta0); - archive & make_nvp("d_beta1",d_beta1); - archive & make_nvp("d_beta2",d_beta2); - archive & make_nvp("d_beta3",d_beta3); + if (version) + { + }; + archive& make_nvp("d_alpha0", d_alpha0); + archive& make_nvp("d_alpha1", d_alpha1); + archive& make_nvp("d_alpha2", d_alpha2); + archive& make_nvp("d_alpha3", d_alpha3); + archive& make_nvp("d_beta0", d_beta0); + archive& make_nvp("d_beta1", d_beta1); + archive& make_nvp("d_beta2", d_beta2); + archive& make_nvp("d_beta3", d_beta3); } }; diff --git a/src/core/system_parameters/gps_navigation_message.cc b/src/core/system_parameters/gps_navigation_message.cc index bc42aeecf..e38f6bdb2 100644 --- a/src/core/system_parameters/gps_navigation_message.cc +++ b/src/core/system_parameters/gps_navigation_message.cc @@ -7,7 +7,7 @@ m * \file gps_navigation_message.cc * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,15 +25,15 @@ m * \file gps_navigation_message.cc * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "gps_navigation_message.h" +#include "gnss_satellite.h" #include #include -#include void Gps_Navigation_Message::reset() @@ -47,57 +47,57 @@ void Gps_Navigation_Message::reset() d_TOW_SF5 = 0; d_IODE_SF2 = 0; d_IODE_SF3 = 0; - d_Crs = 0; - d_Delta_n = 0; - d_M_0 = 0; - d_Cuc = 0; - d_e_eccentricity = 0; - d_Cus = 0; - d_sqrt_A = 0; + d_Crs = 0.0; + d_Delta_n = 0.0; + d_M_0 = 0.0; + d_Cuc = 0.0; + d_e_eccentricity = 0.0; + d_Cus = 0.0; + d_sqrt_A = 0.0; d_Toe = 0; d_Toc = 0; - d_Cic = 0; - d_OMEGA0 = 0; - d_Cis = 0; - d_i_0 = 0; - d_Crc = 0; - d_OMEGA = 0; - d_OMEGA_DOT = 0; - d_IDOT = 0; + d_Cic = 0.0; + d_OMEGA0 = 0.0; + d_Cis = 0.0; + d_i_0 = 0.0; + d_Crc = 0.0; + d_OMEGA = 0.0; + d_OMEGA_DOT = 0.0; + d_IDOT = 0.0; i_code_on_L2 = 0; i_GPS_week = 0; b_L2_P_data_flag = false; i_SV_accuracy = 0; i_SV_health = 0; - d_TGD = 0; + d_TGD = 0.0; d_IODC = -1; i_AODO = 0; b_fit_interval_flag = false; - d_spare1 = 0; - d_spare2 = 0; + d_spare1 = 0.0; + d_spare2 = 0.0; - d_A_f0 = 0; - d_A_f1 = 0; - d_A_f2 = 0; + d_A_f0 = 0.0; + d_A_f1 = 0.0; + d_A_f2 = 0.0; //clock terms //d_master_clock=0; - d_dtr = 0; - d_satClkCorr = 0; - d_satClkDrift = 0; + d_dtr = 0.0; + d_satClkCorr = 0.0; + d_satClkDrift = 0.0; // satellite positions - d_satpos_X = 0; - d_satpos_Y = 0; - d_satpos_Z = 0; + d_satpos_X = 0.0; + d_satpos_Y = 0.0; + d_satpos_Z = 0.0; // info i_channel_ID = 0; - i_satellite_PRN = 0; + i_satellite_PRN = 0U; // time synchro - d_subframe_timestamp_ms = 0; + d_subframe_timestamp_ms = 0.0; // flags b_alert_flag = false; @@ -107,54 +107,52 @@ void Gps_Navigation_Message::reset() // Ionosphere and UTC flag_iono_valid = false; flag_utc_model_valid = false; - d_alpha0 = 0; - d_alpha1 = 0; - d_alpha2 = 0; - d_alpha3 = 0; - d_beta0 = 0; - d_beta1 = 0; - d_beta2 = 0; - d_beta3 = 0; - d_A1 = 0; - d_A0 = 0; + d_alpha0 = 0.0; + d_alpha1 = 0.0; + d_alpha2 = 0.0; + d_alpha3 = 0.0; + d_beta0 = 0.0; + d_beta1 = 0.0; + d_beta2 = 0.0; + d_beta3 = 0.0; + d_A1 = 0.0; + d_A0 = 0.0; d_t_OT = 0; i_WN_T = 0; d_DeltaT_LS = 0; i_WN_LSF = 0; i_DN = 0; - d_DeltaT_LSF= 0; + d_DeltaT_LSF = 0; - //Almanac - d_Toa = 0; + // Almanac + i_Toa = 0; i_WN_A = 0; - for (int i=1; i < 32; i++ ) + for (int32_t i = 1; i < 32; i++) { almanacHealth[i] = 0; } // Satellite velocity - d_satvel_X = 0; - d_satvel_Y = 0; - d_satvel_Z = 0; + d_satvel_X = 0.0; + d_satvel_Y = 0.0; + d_satvel_Z = 0.0; auto gnss_sat = Gnss_Satellite(); - std::string _system ("GPS"); - for(unsigned int i = 1; i < 33; i++) + std::string _system("GPS"); + for (uint32_t i = 1; i < 33; i++) { satelliteBlock[i] = gnss_sat.what_block(_system, i); } } - Gps_Navigation_Message::Gps_Navigation_Message() { reset(); } - -void Gps_Navigation_Message::print_gps_word_bytes(unsigned int GPS_word) +void Gps_Navigation_Message::print_gps_word_bytes(uint32_t GPS_word) { std::cout << " Word ="; std::cout << std::bitset<32>(GPS_word); @@ -162,12 +160,11 @@ void Gps_Navigation_Message::print_gps_word_bytes(unsigned int GPS_word) } - -bool Gps_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector> parameter) +bool Gps_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector>& parameter) { bool value; - if (bits[GPS_SUBFRAME_BITS - parameter[0].first] == 1) + if (static_cast(bits[GPS_SUBFRAME_BITS - parameter[0].first]) == 1) { value = true; } @@ -179,20 +176,18 @@ bool Gps_Navigation_Message::read_navigation_bool(std::bitset } - - -unsigned long int Gps_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector> parameter) +uint64_t Gps_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector>& parameter) { - unsigned long int value = 0; - int num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) + uint64_t value = 0ULL; + int32_t num_of_slices = parameter.size(); + for (int32_t i = 0; i < num_of_slices; i++) { - for (int j = 0; j < parameter[i].second; j++) + for (int32_t j = 0; j < parameter[i].second; j++) { - value <<= 1; //shift left - if (bits[GPS_SUBFRAME_BITS - parameter[i].first - j] == 1) + value <<= 1; // shift left + if (static_cast(bits[GPS_SUBFRAME_BITS - parameter[i].first - j]) == 1) { - value += 1; // insert the bit + value += 1ULL; // insert the bit } } } @@ -200,62 +195,30 @@ unsigned long int Gps_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector> parameter) +int64_t Gps_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector>& parameter) { - signed long int value = 0; - int num_of_slices = parameter.size(); - // Discriminate between 64 bits and 32 bits compiler - int long_int_size_bytes = sizeof(signed long int); - if (long_int_size_bytes == 8) // if a long int takes 8 bytes, we are in a 64 bits system - { - // read the MSB and perform the sign extension - if (bits[GPS_SUBFRAME_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFFFFFFFFFF; //64 bits variable - } - else - { - value &= 0; - } + int64_t value = 0LL; + int32_t num_of_slices = parameter.size(); - for (int i = 0; i < num_of_slices; i++) - { - for (int j = 0; j < parameter[i].second; j++) - { - value <<= 1; //shift left - value &= 0xFFFFFFFFFFFFFFFE; //reset the corresponding bit (for the 64 bits variable) - if (bits[GPS_SUBFRAME_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } - } - } + // read the MSB and perform the sign extension + if (static_cast(bits[GPS_SUBFRAME_BITS - parameter[0].first]) == 1) + { + value ^= 0xFFFFFFFFFFFFFFFFLL; // 64 bits variable } - else // we assume we are in a 32 bits system + else { - // read the MSB and perform the sign extension - if (bits[GPS_SUBFRAME_BITS - parameter[0].first] == 1) - { - value ^= 0xFFFFFFFF; - } - else - { - value &= 0; - } + value &= 0LL; + } - for (int i = 0; i < num_of_slices; i++) + for (int32_t i = 0; i < num_of_slices; i++) + { + for (int32_t j = 0; j < parameter[i].second; j++) { - for (int j = 0; j < parameter[i].second; j++) + value <<= 1; // shift left + value &= 0xFFFFFFFFFFFFFFFELL; // reset the corresponding bit (for the 64 bits variable) + if (static_cast(bits[GPS_SUBFRAME_BITS - parameter[i].first - j]) == 1) { - value <<= 1; //shift left - value &= 0xFFFFFFFE; //reset the corresponding bit - if (bits[GPS_SUBFRAME_BITS - parameter[i].first - j] == 1) - { - value += 1; // insert the bit - } + value += 1LL; // insert the bit } } } @@ -263,411 +226,272 @@ signed long int Gps_Navigation_Message::read_navigation_signed(std::bitset half_week) - { - corrTime = time - 2 * half_week; - } - else if (time < -half_week) - { - corrTime = time + 2 * half_week; - } - return corrTime; -} - - - - -// 20.3.3.3.3.1 User Algorithm for SV Clock Correction. -double Gps_Navigation_Message::sv_clock_correction(double transmitTime) -{ - double dt; - dt = check_t(transmitTime - d_Toc); - d_satClkCorr = (d_A_f2 * dt + d_A_f1) * dt + d_A_f0 + d_dtr; - double correctedTime = transmitTime - d_satClkCorr; - return correctedTime; -} - - - - - -void Gps_Navigation_Message::satellitePosition(double transmitTime) -{ - double tk; - double a; - double n; - double n0; - double M; - double E; - double E_old; - double dE; - double nu; - double phi; - double u; - double r; - double i; - double Omega; - - // Find satellite's position ---------------------------------------------- - - // Restore semi-major axis - a = d_sqrt_A * d_sqrt_A; - - // Time from ephemeris reference epoch - tk = check_t(transmitTime - d_Toe); - - // Computed mean motion - n0 = sqrt(GM / (a * a * a)); - - // Corrected mean motion - n = n0 + d_Delta_n; - - // Mean anomaly - M = d_M_0 + n * tk; - - // Reduce mean anomaly to between 0 and 2pi - M = fmod((M + 2 * GPS_PI), (2 * GPS_PI)); - - // Initial guess of eccentric anomaly - E = M; - - // --- Iteratively compute eccentric anomaly ---------------------------- - for (int ii = 1; ii < 20; ii++) - { - E_old = E; - E = M + d_e_eccentricity * sin(E); - dE = fmod(E - E_old, 2 * GPS_PI); - if (fabs(dE) < 1e-12) - { - //Necessary precision is reached, exit from the loop - break; - } - } - - // Compute relativistic correction term - d_dtr = F * d_e_eccentricity * d_sqrt_A * sin(E); - - // Compute the true anomaly - double tmp_Y = sqrt(1.0 - d_e_eccentricity * d_e_eccentricity) * sin(E); - double tmp_X = cos(E) - d_e_eccentricity; - nu = atan2(tmp_Y, tmp_X); - - // Compute angle phi (argument of Latitude) - phi = nu + d_OMEGA; - - // Reduce phi to between 0 and 2*pi rad - phi = fmod((phi), (2 * GPS_PI)); - - // Correct argument of latitude - u = phi + d_Cuc * cos(2 * phi) + d_Cus * sin(2 * phi); - - // Correct radius - r = a * (1 - d_e_eccentricity * cos(E)) + d_Crc * cos(2 * phi) + d_Crs * sin(2 * phi); - - // Correct inclination - i = d_i_0 + d_IDOT * tk + d_Cic * cos(2 * phi) + d_Cis * sin(2 * phi); - - // Compute the angle between the ascending node and the Greenwich meridian - Omega = d_OMEGA0 + (d_OMEGA_DOT - OMEGA_EARTH_DOT) * tk - OMEGA_EARTH_DOT * d_Toe; - - // Reduce to between 0 and 2*pi rad - Omega = fmod((Omega + 2 * GPS_PI), (2 * GPS_PI)); - - // --- Compute satellite coordinates in Earth-fixed coordinates - d_satpos_X = cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega); - d_satpos_Y = cos(u) * r * sin(Omega) + sin(u) * r * cos(i) * cos(Omega); - d_satpos_Z = sin(u) * r * sin(i); - - // Satellite's velocity. Can be useful for Vector Tracking loops - double Omega_dot = d_OMEGA_DOT - OMEGA_EARTH_DOT; - d_satvel_X = - Omega_dot * (cos(u) * r + sin(u) * r * cos(i)) + d_satpos_X * cos(Omega) - d_satpos_Y * cos(i) * sin(Omega); - d_satvel_Y = Omega_dot * (cos(u) * r * cos(Omega) - sin(u) * r * cos(i) * sin(Omega)) + d_satpos_X * sin(Omega) + d_satpos_Y * cos(i) * cos(Omega); - d_satvel_Z = d_satpos_Y * sin(i); -} - - - - - -int Gps_Navigation_Message::subframe_decoder(char *subframe) -{ - int subframe_ID = 0; - - //double tmp_TOW; - - unsigned int gps_word; + int32_t subframe_ID = 0; + uint32_t gps_word; // UNPACK BYTES TO BITS AND REMOVE THE CRC REDUNDANCE std::bitset subframe_bits; std::bitset word_bits; - for (int i = 0; i < 10; i++) + for (int32_t i = 0; i < 10; i++) { memcpy(&gps_word, &subframe[i * 4], sizeof(char) * 4); - word_bits = std::bitset<(GPS_WORD_BITS + 2) > (gps_word); - for (int j = 0; j < GPS_WORD_BITS; j++) + word_bits = std::bitset<(GPS_WORD_BITS + 2)>(gps_word); + for (int32_t j = 0; j < GPS_WORD_BITS; j++) { subframe_bits[GPS_WORD_BITS * (9 - i) + j] = word_bits[j]; } } - subframe_ID = static_cast(read_navigation_unsigned(subframe_bits, SUBFRAME_ID)); + subframe_ID = static_cast(read_navigation_unsigned(subframe_bits, SUBFRAME_ID)); // Decode all 5 sub-frames switch (subframe_ID) - { - //--- Decode the sub-frame id ------------------------------------------ - // ICD (IS-GPS-200E Appendix II). http://www.losangeles.af.mil/shared/media/document/AFD-100813-045.pdf - case 1: - //--- It is subframe 1 ------------------------------------- - // Compute the time of week (TOW) of the first sub-frames in the array ==== - // The transmitted TOW is actual TOW of the next subframe - // (the variable subframe at this point contains bits of the last subframe). - //TOW = bin2dec(subframe(31:47)) * 6; - d_TOW_SF1 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); - //we are in the first subframe (the transmitted TOW is the start time of the next subframe) ! - d_TOW_SF1 = d_TOW_SF1 * 6; - d_TOW = d_TOW_SF1; // Set transmission time - b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); - b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); - b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); - i_GPS_week = static_cast(read_navigation_unsigned(subframe_bits, GPS_WEEK)); - i_SV_accuracy = static_cast(read_navigation_unsigned(subframe_bits, SV_ACCURACY)); // (20.3.3.3.1.3) - i_SV_health = static_cast(read_navigation_unsigned(subframe_bits, SV_HEALTH)); - b_L2_P_data_flag = read_navigation_bool(subframe_bits, L2_P_DATA_FLAG); // - i_code_on_L2 = static_cast(read_navigation_unsigned(subframe_bits, CA_OR_P_ON_L2)); - d_TGD = static_cast(read_navigation_signed(subframe_bits, T_GD)); - d_TGD = d_TGD * T_GD_LSB; - d_IODC = static_cast(read_navigation_unsigned(subframe_bits, IODC)); - d_Toc = static_cast(read_navigation_unsigned(subframe_bits, T_OC)); - d_Toc = d_Toc * T_OC_LSB; - d_A_f0 = static_cast(read_navigation_signed(subframe_bits, A_F0)); - d_A_f0 = d_A_f0 * A_F0_LSB; - d_A_f1 = static_cast(read_navigation_signed(subframe_bits, A_F1)); - d_A_f1 = d_A_f1 * A_F1_LSB; - d_A_f2 = static_cast(read_navigation_signed(subframe_bits, A_F2)); - d_A_f2 = d_A_f2 * A_F2_LSB; + { + //--- Decode the sub-frame id ------------------------------------------ + // ICD (IS-GPS-200E Appendix II). http://www.losangeles.af.mil/shared/media/document/AFD-100813-045.pdf + case 1: + //--- It is subframe 1 ------------------------------------- + // Compute the time of week (TOW) of the first sub-frames in the array ==== + // The transmitted TOW is actual TOW of the next subframe + // (the variable subframe at this point contains bits of the last subframe). + //TOW = bin2dec(subframe(31:47)) * 6; + d_TOW_SF1 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); + //we are in the first subframe (the transmitted TOW is the start time of the next subframe) ! + d_TOW_SF1 = d_TOW_SF1 * 6; + d_TOW = d_TOW_SF1; // Set transmission time + b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); + b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); + b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); + i_GPS_week = static_cast(read_navigation_unsigned(subframe_bits, GPS_WEEK)); + i_SV_accuracy = static_cast(read_navigation_unsigned(subframe_bits, SV_ACCURACY)); // (20.3.3.3.1.3) + i_SV_health = static_cast(read_navigation_unsigned(subframe_bits, SV_HEALTH)); + b_L2_P_data_flag = read_navigation_bool(subframe_bits, L2_P_DATA_FLAG); // + i_code_on_L2 = static_cast(read_navigation_unsigned(subframe_bits, CA_OR_P_ON_L2)); + d_TGD = static_cast(read_navigation_signed(subframe_bits, T_GD)); + d_TGD = d_TGD * T_GD_LSB; + d_IODC = static_cast(read_navigation_unsigned(subframe_bits, IODC)); + d_Toc = static_cast(read_navigation_unsigned(subframe_bits, T_OC)); + d_Toc = d_Toc * T_OC_LSB; + d_A_f0 = static_cast(read_navigation_signed(subframe_bits, A_F0)); + d_A_f0 = d_A_f0 * A_F0_LSB; + d_A_f1 = static_cast(read_navigation_signed(subframe_bits, A_F1)); + d_A_f1 = d_A_f1 * A_F1_LSB; + d_A_f2 = static_cast(read_navigation_signed(subframe_bits, A_F2)); + d_A_f2 = d_A_f2 * A_F2_LSB; + break; - break; + case 2: //--- It is subframe 2 ------------------- + d_TOW_SF2 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); + d_TOW_SF2 = d_TOW_SF2 * 6; + d_TOW = d_TOW_SF2; // Set transmission time + b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); + b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); + b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); + d_IODE_SF2 = static_cast(read_navigation_unsigned(subframe_bits, IODE_SF2)); + d_Crs = static_cast(read_navigation_signed(subframe_bits, C_RS)); + d_Crs = d_Crs * C_RS_LSB; + d_Delta_n = static_cast(read_navigation_signed(subframe_bits, DELTA_N)); + d_Delta_n = d_Delta_n * DELTA_N_LSB; + d_M_0 = static_cast(read_navigation_signed(subframe_bits, M_0)); + d_M_0 = d_M_0 * M_0_LSB; + d_Cuc = static_cast(read_navigation_signed(subframe_bits, C_UC)); + d_Cuc = d_Cuc * C_UC_LSB; + d_e_eccentricity = static_cast(read_navigation_unsigned(subframe_bits, E)); + d_e_eccentricity = d_e_eccentricity * E_LSB; + d_Cus = static_cast(read_navigation_signed(subframe_bits, C_US)); + d_Cus = d_Cus * C_US_LSB; + d_sqrt_A = static_cast(read_navigation_unsigned(subframe_bits, SQRT_A)); + d_sqrt_A = d_sqrt_A * SQRT_A_LSB; + d_Toe = static_cast(read_navigation_unsigned(subframe_bits, T_OE)); + d_Toe = d_Toe * T_OE_LSB; + b_fit_interval_flag = read_navigation_bool(subframe_bits, FIT_INTERVAL_FLAG); + i_AODO = static_cast(read_navigation_unsigned(subframe_bits, AODO)); + i_AODO = i_AODO * AODO_LSB; + break; - case 2: //--- It is subframe 2 ------------------- - d_TOW_SF2 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); - d_TOW_SF2 = d_TOW_SF2 * 6; - d_TOW = d_TOW_SF2; // Set transmission time - b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); - b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); - b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); - d_IODE_SF2 = static_cast(read_navigation_unsigned(subframe_bits, IODE_SF2)); - d_Crs = static_cast(read_navigation_signed(subframe_bits, C_RS)); - d_Crs = d_Crs * C_RS_LSB; - d_Delta_n = static_cast(read_navigation_signed(subframe_bits, DELTA_N)); - d_Delta_n = d_Delta_n * DELTA_N_LSB; - d_M_0 = static_cast(read_navigation_signed(subframe_bits, M_0)); - d_M_0 = d_M_0 * M_0_LSB; - d_Cuc = static_cast(read_navigation_signed(subframe_bits, C_UC)); - d_Cuc = d_Cuc * C_UC_LSB; - d_e_eccentricity = static_cast(read_navigation_unsigned(subframe_bits, E)); - d_e_eccentricity = d_e_eccentricity * E_LSB; - d_Cus = static_cast(read_navigation_signed(subframe_bits, C_US)); - d_Cus = d_Cus * C_US_LSB; - d_sqrt_A = static_cast(read_navigation_unsigned(subframe_bits, SQRT_A)); - d_sqrt_A = d_sqrt_A * SQRT_A_LSB; - d_Toe = static_cast(read_navigation_unsigned(subframe_bits, T_OE)); - d_Toe = d_Toe * T_OE_LSB; - b_fit_interval_flag = read_navigation_bool(subframe_bits, FIT_INTERVAL_FLAG); - i_AODO = static_cast(read_navigation_unsigned(subframe_bits, AODO)); - i_AODO = i_AODO * AODO_LSB; + case 3: // --- It is subframe 3 ------------------------------------- + d_TOW_SF3 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); + d_TOW_SF3 = d_TOW_SF3 * 6; + d_TOW = d_TOW_SF3; // Set transmission time + b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); + b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); + b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); + d_Cic = static_cast(read_navigation_signed(subframe_bits, C_IC)); + d_Cic = d_Cic * C_IC_LSB; + d_OMEGA0 = static_cast(read_navigation_signed(subframe_bits, OMEGA_0)); + d_OMEGA0 = d_OMEGA0 * OMEGA_0_LSB; + d_Cis = static_cast(read_navigation_signed(subframe_bits, C_IS)); + d_Cis = d_Cis * C_IS_LSB; + d_i_0 = static_cast(read_navigation_signed(subframe_bits, I_0)); + d_i_0 = d_i_0 * I_0_LSB; + d_Crc = static_cast(read_navigation_signed(subframe_bits, C_RC)); + d_Crc = d_Crc * C_RC_LSB; + d_OMEGA = static_cast(read_navigation_signed(subframe_bits, OMEGA)); + d_OMEGA = d_OMEGA * OMEGA_LSB; + d_OMEGA_DOT = static_cast(read_navigation_signed(subframe_bits, OMEGA_DOT)); + d_OMEGA_DOT = d_OMEGA_DOT * OMEGA_DOT_LSB; + d_IODE_SF3 = static_cast(read_navigation_unsigned(subframe_bits, IODE_SF3)); + d_IDOT = static_cast(read_navigation_signed(subframe_bits, I_DOT)); + d_IDOT = d_IDOT * I_DOT_LSB; + break; - break; + case 4: // --- It is subframe 4 ---------- Almanac, ionospheric model, UTC parameters, SV health (PRN: 25-32) + int32_t SV_data_ID; + int32_t SV_page; + d_TOW_SF4 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); + d_TOW_SF4 = d_TOW_SF4 * 6; + d_TOW = d_TOW_SF4; // Set transmission time + b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); + b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); + b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); + SV_data_ID = static_cast(read_navigation_unsigned(subframe_bits, SV_DATA_ID)); + SV_page = static_cast(read_navigation_unsigned(subframe_bits, SV_PAGE)); + if (SV_page > 24 && SV_page < 33) // Page 4 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) + { + //! \TODO read almanac + if (SV_data_ID != 0) + { + } + } - case 3: // --- It is subframe 3 ------------------------------------- - d_TOW_SF3 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); - d_TOW_SF3 = d_TOW_SF3 * 6; - d_TOW = d_TOW_SF3; // Set transmission time - b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); - b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); - b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); - d_Cic = static_cast(read_navigation_signed(subframe_bits, C_IC)); - d_Cic = d_Cic * C_IC_LSB; - d_OMEGA0 = static_cast(read_navigation_signed(subframe_bits, OMEGA_0)); - d_OMEGA0 = d_OMEGA0 * OMEGA_0_LSB; - d_Cis = static_cast(read_navigation_signed(subframe_bits, C_IS)); - d_Cis = d_Cis * C_IS_LSB; - d_i_0 = static_cast(read_navigation_signed(subframe_bits, I_0)); - d_i_0 = d_i_0 * I_0_LSB; - d_Crc = static_cast(read_navigation_signed(subframe_bits, C_RC)); - d_Crc = d_Crc * C_RC_LSB; - d_OMEGA = static_cast(read_navigation_signed(subframe_bits, OMEGA)); - d_OMEGA = d_OMEGA * OMEGA_LSB; - d_OMEGA_DOT = static_cast(read_navigation_signed(subframe_bits, OMEGA_DOT)); - d_OMEGA_DOT = d_OMEGA_DOT * OMEGA_DOT_LSB; - d_IODE_SF3 = static_cast(read_navigation_unsigned(subframe_bits, IODE_SF3)); - d_IDOT = static_cast(read_navigation_signed(subframe_bits, I_DOT)); - d_IDOT = d_IDOT * I_DOT_LSB; + if (SV_page == 52) // Page 13 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) + { + //! \TODO read Estimated Range Deviation (ERD) values + } - break; + if (SV_page == 56) // Page 18 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) + { + // Page 18 - Ionospheric and UTC data + d_alpha0 = static_cast(read_navigation_signed(subframe_bits, ALPHA_0)); + d_alpha0 = d_alpha0 * ALPHA_0_LSB; + d_alpha1 = static_cast(read_navigation_signed(subframe_bits, ALPHA_1)); + d_alpha1 = d_alpha1 * ALPHA_1_LSB; + d_alpha2 = static_cast(read_navigation_signed(subframe_bits, ALPHA_2)); + d_alpha2 = d_alpha2 * ALPHA_2_LSB; + d_alpha3 = static_cast(read_navigation_signed(subframe_bits, ALPHA_3)); + d_alpha3 = d_alpha3 * ALPHA_3_LSB; + d_beta0 = static_cast(read_navigation_signed(subframe_bits, BETA_0)); + d_beta0 = d_beta0 * BETA_0_LSB; + d_beta1 = static_cast(read_navigation_signed(subframe_bits, BETA_1)); + d_beta1 = d_beta1 * BETA_1_LSB; + d_beta2 = static_cast(read_navigation_signed(subframe_bits, BETA_2)); + d_beta2 = d_beta2 * BETA_2_LSB; + d_beta3 = static_cast(read_navigation_signed(subframe_bits, BETA_3)); + d_beta3 = d_beta3 * BETA_3_LSB; + d_A1 = static_cast(read_navigation_signed(subframe_bits, A_1)); + d_A1 = d_A1 * A_1_LSB; + d_A0 = static_cast(read_navigation_signed(subframe_bits, A_0)); + d_A0 = d_A0 * A_0_LSB; + d_t_OT = static_cast(read_navigation_unsigned(subframe_bits, T_OT)); + d_t_OT = d_t_OT * T_OT_LSB; + i_WN_T = static_cast(read_navigation_unsigned(subframe_bits, WN_T)); + d_DeltaT_LS = static_cast(read_navigation_signed(subframe_bits, DELTAT_LS)); + i_WN_LSF = static_cast(read_navigation_unsigned(subframe_bits, WN_LSF)); + i_DN = static_cast(read_navigation_unsigned(subframe_bits, DN)); // Right-justified ? + d_DeltaT_LSF = static_cast(read_navigation_signed(subframe_bits, DELTAT_LSF)); + flag_iono_valid = true; + flag_utc_model_valid = true; + } + if (SV_page == 57) + { + // Reserved + } - case 4: // --- It is subframe 4 ---------- Almanac, ionospheric model, UTC parameters, SV health (PRN: 25-32) - int SV_data_ID; - int SV_page; - d_TOW_SF4 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); - d_TOW_SF4 = d_TOW_SF4 * 6; - d_TOW = d_TOW_SF4; // Set transmission time - b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); - b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); - b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); - SV_data_ID = static_cast(read_navigation_unsigned(subframe_bits, SV_DATA_ID)); - SV_page = static_cast(read_navigation_unsigned(subframe_bits, SV_PAGE)); - if (SV_page > 24 && SV_page < 33) // Page 4 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) - { - //! \TODO read almanac - if(SV_data_ID){} - } + if (SV_page == 63) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) + { + // Page 25 Anti-Spoofing, SV config and almanac health (PRN: 25-32) + //! \TODO Read Anti-Spoofing, SV config + almanacHealth[25] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV25)); + almanacHealth[26] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV26)); + almanacHealth[27] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV27)); + almanacHealth[28] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV28)); + almanacHealth[29] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV29)); + almanacHealth[30] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV30)); + almanacHealth[31] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV31)); + almanacHealth[32] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV32)); + } + break; - if (SV_page == 52) // Page 13 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) - { - //! \TODO read Estimated Range Deviation (ERD) values - } + case 5: //--- It is subframe 5 -----------------almanac health (PRN: 1-24) and Almanac reference week number and time. + int32_t SV_data_ID_5; + int32_t SV_page_5; + d_TOW_SF5 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); + d_TOW_SF5 = d_TOW_SF5 * 6; + d_TOW = d_TOW_SF5; // Set transmission time + b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); + b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); + b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); + SV_data_ID_5 = static_cast(read_navigation_unsigned(subframe_bits, SV_DATA_ID)); + SV_page_5 = static_cast(read_navigation_unsigned(subframe_bits, SV_PAGE)); + if (SV_page_5 < 25) + { + //! \TODO read almanac + if (SV_data_ID_5 != 0) + { + } + } + if (SV_page_5 == 51) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) + { + i_Toa = static_cast(read_navigation_unsigned(subframe_bits, T_OA)); + i_Toa = i_Toa * T_OA_LSB; + i_WN_A = static_cast(read_navigation_unsigned(subframe_bits, WN_A)); + almanacHealth[1] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV1)); + almanacHealth[2] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV2)); + almanacHealth[3] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV3)); + almanacHealth[4] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV4)); + almanacHealth[5] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV5)); + almanacHealth[6] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV6)); + almanacHealth[7] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV7)); + almanacHealth[8] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV8)); + almanacHealth[9] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV9)); + almanacHealth[10] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV10)); + almanacHealth[11] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV11)); + almanacHealth[12] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV12)); + almanacHealth[13] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV13)); + almanacHealth[14] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV14)); + almanacHealth[15] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV15)); + almanacHealth[16] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV16)); + almanacHealth[17] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV17)); + almanacHealth[18] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV18)); + almanacHealth[19] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV19)); + almanacHealth[20] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV20)); + almanacHealth[21] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV21)); + almanacHealth[22] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV22)); + almanacHealth[23] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV23)); + almanacHealth[24] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV24)); + } + break; - if (SV_page == 56) // Page 18 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) - { - // Page 18 - Ionospheric and UTC data - d_alpha0 = static_cast(read_navigation_signed(subframe_bits, ALPHA_0)); - d_alpha0 = d_alpha0 * ALPHA_0_LSB; - d_alpha1 = static_cast(read_navigation_signed(subframe_bits, ALPHA_1)); - d_alpha1 = d_alpha1 * ALPHA_1_LSB; - d_alpha2 = static_cast(read_navigation_signed(subframe_bits, ALPHA_2)); - d_alpha2 = d_alpha2 * ALPHA_2_LSB; - d_alpha3 = static_cast(read_navigation_signed(subframe_bits, ALPHA_3)); - d_alpha3 = d_alpha3 * ALPHA_3_LSB; - d_beta0 = static_cast(read_navigation_signed(subframe_bits, BETA_0)); - d_beta0 = d_beta0 * BETA_0_LSB; - d_beta1 = static_cast(read_navigation_signed(subframe_bits, BETA_1)); - d_beta1 = d_beta1 * BETA_1_LSB; - d_beta2 = static_cast(read_navigation_signed(subframe_bits, BETA_2)); - d_beta2 = d_beta2 * BETA_2_LSB; - d_beta3 = static_cast(read_navigation_signed(subframe_bits, BETA_3)); - d_beta3 = d_beta3 * BETA_3_LSB; - d_A1 = static_cast(read_navigation_signed(subframe_bits, A_1)); - d_A1 = d_A1 * A_1_LSB; - d_A0 = static_cast(read_navigation_signed(subframe_bits, A_0)); - d_A0 = d_A0 * A_0_LSB; - d_t_OT = static_cast(read_navigation_unsigned(subframe_bits, T_OT)); - d_t_OT = d_t_OT * T_OT_LSB; - i_WN_T = static_cast(read_navigation_unsigned(subframe_bits, WN_T)); - d_DeltaT_LS = static_cast(read_navigation_signed(subframe_bits, DELTAT_LS)); - i_WN_LSF = static_cast(read_navigation_unsigned(subframe_bits, WN_LSF)); - i_DN = static_cast(read_navigation_unsigned(subframe_bits, DN)); // Right-justified ? - d_DeltaT_LSF = static_cast(read_navigation_signed(subframe_bits, DELTAT_LSF)); - flag_iono_valid = true; - flag_utc_model_valid = true; - } - if (SV_page == 57) - { - // Reserved - } - - if (SV_page == 63) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) - { - // Page 25 Anti-Spoofing, SV config and almanac health (PRN: 25-32) - //! \TODO Read Anti-Spoofing, SV config - almanacHealth[25] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV25)); - almanacHealth[26] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV26)); - almanacHealth[27] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV27)); - almanacHealth[28] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV28)); - almanacHealth[29] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV29)); - almanacHealth[30] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV30)); - almanacHealth[31] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV31)); - almanacHealth[32] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV32)); - } - - break; - - case 5://--- It is subframe 5 -----------------almanac health (PRN: 1-24) and Almanac reference week number and time. - int SV_data_ID_5; - int SV_page_5; - d_TOW_SF5 = static_cast(read_navigation_unsigned(subframe_bits, TOW)); - d_TOW_SF5 = d_TOW_SF5 * 6; - d_TOW = d_TOW_SF5; // Set transmission time - b_integrity_status_flag = read_navigation_bool(subframe_bits, INTEGRITY_STATUS_FLAG); - b_alert_flag = read_navigation_bool(subframe_bits, ALERT_FLAG); - b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG); - SV_data_ID_5 = static_cast(read_navigation_unsigned(subframe_bits, SV_DATA_ID)); - SV_page_5 = static_cast(read_navigation_unsigned(subframe_bits, SV_PAGE)); - if (SV_page_5 < 25) - { - //! \TODO read almanac - if(SV_data_ID_5){} - } - if (SV_page_5 == 51) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200H, page 110) - { - d_Toa = static_cast(read_navigation_unsigned(subframe_bits, T_OA)); - d_Toa = d_Toa * T_OA_LSB; - i_WN_A = static_cast(read_navigation_unsigned(subframe_bits, WN_A)); - almanacHealth[1] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV1)); - almanacHealth[2] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV2)); - almanacHealth[3] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV3)); - almanacHealth[4] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV4)); - almanacHealth[5] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV5)); - almanacHealth[6] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV6)); - almanacHealth[7] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV7)); - almanacHealth[8] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV8)); - almanacHealth[9] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV9)); - almanacHealth[10] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV10)); - almanacHealth[11] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV11)); - almanacHealth[12] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV12)); - almanacHealth[13] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV13)); - almanacHealth[14] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV14)); - almanacHealth[15] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV15)); - almanacHealth[16] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV16)); - almanacHealth[17] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV17)); - almanacHealth[18] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV18)); - almanacHealth[19] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV19)); - almanacHealth[20] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV20)); - almanacHealth[21] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV21)); - almanacHealth[22] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV22)); - almanacHealth[23] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV23)); - almanacHealth[24] = static_cast(read_navigation_unsigned(subframe_bits, HEALTH_SV24)); - } - break; - - default: - break; - } // switch subframeID ... + default: + break; + } // switch subframeID ... return subframe_ID; } - - double Gps_Navigation_Message::utc_time(const double gpstime_corrected) const { double t_utc; double t_utc_daytime; - double Delta_t_UTC = d_DeltaT_LS + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast((i_GPS_week - i_WN_T))); + double Delta_t_UTC = d_DeltaT_LS + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast((i_GPS_week - i_WN_T))); // Determine if the effectivity time of the leap second event is in the past - int weeksToLeapSecondEvent = i_WN_LSF - i_GPS_week; + int32_t weeksToLeapSecondEvent = i_WN_LSF - i_GPS_week; - if ((weeksToLeapSecondEvent) >= 0) // is not in the past + if ((weeksToLeapSecondEvent) >= 0) // is not in the past { //Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s - int secondOfLeapSecondEvent = i_DN * 24 * 60 * 60; + int32_t secondOfLeapSecondEvent = i_DN * 24 * 60 * 60; if (weeksToLeapSecondEvent > 0) { t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); } - else //we are in the same week than the leap second event + else //we are in the same week than the leap second event { - if (std::abs(gpstime_corrected - secondOfLeapSecondEvent) > 21600) + if (std::abs(gpstime_corrected - secondOfLeapSecondEvent) > 21600) { /* 20.3.3.5.2.4a * Whenever the effectivity time indicated by the WN_LSF and the DN values @@ -686,18 +510,18 @@ double Gps_Navigation_Message::utc_time(const double gpstime_corrected) const * proper accommodation of the leap second event with a possible week number * transition is provided by the following expression for UTC: */ - int W = fmod(gpstime_corrected - Delta_t_UTC - 43200, 86400) + 43200; + int32_t W = static_cast(fmod(gpstime_corrected - Delta_t_UTC - 43200, 86400)) + 43200; t_utc_daytime = fmod(W, 86400 + d_DeltaT_LSF - d_DeltaT_LS); //implement something to handle a leap second event! } - if ( (gpstime_corrected - secondOfLeapSecondEvent) > 21600) + if ((gpstime_corrected - secondOfLeapSecondEvent) > 21600) { Delta_t_UTC = d_DeltaT_LSF + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast((i_GPS_week - i_WN_T))); t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); } } } - else // the effectivity time is in the past + else // the effectivity time is in the past { /* 20.3.3.5.2.4c * Whenever the effectivity time of the leap second event, as indicated by the @@ -714,7 +538,6 @@ double Gps_Navigation_Message::utc_time(const double gpstime_corrected) const } - Gps_Ephemeris Gps_Navigation_Message::get_ephemeris() { Gps_Ephemeris ephemeris; @@ -781,7 +604,7 @@ Gps_Iono Gps_Navigation_Message::get_iono() iono.d_beta2 = d_beta2; iono.d_beta3 = d_beta3; iono.valid = flag_iono_valid; - //WARNING: We clear flag_utc_model_valid in order to not re-send the same information to the ionospheric parameters queue + // WARNING: We clear flag_utc_model_valid in order to not re-send the same information to the ionospheric parameters queue flag_iono_valid = false; return iono; } @@ -814,9 +637,9 @@ bool Gps_Navigation_Message::satellite_validation() // First Step: // check Issue Of Ephemeris Data (IODE IODC..) to find a possible interrupted reception // and check if the data have been filled (!=0) - if (d_TOW_SF1 != 0 and d_TOW_SF2 != 0 and d_TOW_SF3 != 0) + if (d_TOW_SF1 != 0.0 and d_TOW_SF2 != 0.0 and d_TOW_SF3 != 0.0) { - if (d_IODE_SF2 == d_IODE_SF3 and d_IODC == d_IODE_SF2 and d_IODC!= -1) + if (d_IODE_SF2 == d_IODE_SF3 and d_IODC == d_IODE_SF2 and d_IODC != -1.0) { flag_data_valid = true; b_valid_ephemeris_set_flag = true; diff --git a/src/core/system_parameters/gps_navigation_message.h b/src/core/system_parameters/gps_navigation_message.h index aaded71a1..1e79a02c9 100644 --- a/src/core/system_parameters/gps_navigation_message.h +++ b/src/core/system_parameters/gps_navigation_message.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,17 +33,17 @@ #define GNSS_SDR_GPS_NAVIGATION_MESSAGE_H_ +#include "GPS_L1_CA.h" +#include "gps_almanac.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_utc_model.h" #include +#include #include #include #include #include -#include "GPS_L1_CA.h" -#include "gps_ephemeris.h" -#include "gps_iono.h" -#include "gps_almanac.h" -#include "gps_utc_model.h" - /*! @@ -54,78 +54,66 @@ class Gps_Navigation_Message { private: - unsigned long int read_navigation_unsigned(std::bitset bits, const std::vector> parameter); - signed long int read_navigation_signed(std::bitset bits, const std::vector> parameter); - bool read_navigation_bool(std::bitset bits, const std::vector> parameter); - void print_gps_word_bytes(unsigned int GPS_word); - /* - * Accounts for the beginning or end of week crossover - * - * See paragraph 20.3.3.3.3.1 (IS-GPS-200E) - * \param[in] - time in seconds - * \param[out] - corrected time, in seconds - */ - double check_t(double time); + uint64_t read_navigation_unsigned(std::bitset bits, const std::vector>& parameter); + int64_t read_navigation_signed(std::bitset bits, const std::vector>& parameter); + bool read_navigation_bool(std::bitset bits, const std::vector>& parameter); + void print_gps_word_bytes(uint32_t GPS_word); public: - bool b_valid_ephemeris_set_flag; // flag indicating that this ephemeris set have passed the validation check - //broadcast orbit 1 - double d_TOW; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] - double d_TOW_SF1; //!< Time of GPS Week from HOW word of Subframe 1 [s] - double d_TOW_SF2; //!< Time of GPS Week from HOW word of Subframe 2 [s] - double d_TOW_SF3; //!< Time of GPS Week from HOW word of Subframe 3 [s] - double d_TOW_SF4; //!< Time of GPS Week from HOW word of Subframe 4 [s] - double d_TOW_SF5; //!< Time of GPS Week from HOW word of Subframe 5 [s] - - double d_IODE_SF2; - double d_IODE_SF3; - double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] - double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] - double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] - //broadcast orbit 2 - double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] - double d_e_eccentricity; //!< Eccentricity [dimensionless] - double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] - double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] - //broadcast orbit 3 - double d_Toe; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] - double d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] - double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] - double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] - //broadcast orbit 4 - double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] - double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] - double d_OMEGA; //!< Argument of Perigee [semi-cicles] - double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] - //broadcast orbit 5 - double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] - int i_code_on_L2; //!< If 1, P code ON in L2; if 2, C/A code ON in L2; - int i_GPS_week; //!< GPS week number, aka WN [week] - bool b_L2_P_data_flag; //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel - //broadcast orbit 6 - int i_SV_accuracy; //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) - int i_SV_health; - double d_TGD; //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] - double d_IODC; //!< Issue of Data, Clock - //broadcast orbit 7 - int i_AODO; //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] - - bool b_fit_interval_flag;//!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. + bool b_valid_ephemeris_set_flag; // flag indicating that this ephemeris set have passed the validation check + // broadcast orbit 1 + int32_t d_TOW; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + int32_t d_TOW_SF1; //!< Time of GPS Week from HOW word of Subframe 1 [s] + int32_t d_TOW_SF2; //!< Time of GPS Week from HOW word of Subframe 2 [s] + int32_t d_TOW_SF3; //!< Time of GPS Week from HOW word of Subframe 3 [s] + int32_t d_TOW_SF4; //!< Time of GPS Week from HOW word of Subframe 4 [s] + int32_t d_TOW_SF5; //!< Time of GPS Week from HOW word of Subframe 5 [s] + int32_t d_IODE_SF2; + int32_t d_IODE_SF3; + double d_Crs; //!< Amplitude of the Sine Harmonic Correction Term to the Orbit Radius [m] + double d_Delta_n; //!< Mean Motion Difference From Computed Value [semi-circles/s] + double d_M_0; //!< Mean Anomaly at Reference Time [semi-circles] + // broadcast orbit 2 + double d_Cuc; //!< Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude [rad] + double d_e_eccentricity; //!< Eccentricity [dimensionless] + double d_Cus; //!< Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude [rad] + double d_sqrt_A; //!< Square Root of the Semi-Major Axis [sqrt(m)] + // broadcast orbit 3 + int32_t d_Toe; //!< Ephemeris data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200E) [s] + int32_t d_Toc; //!< clock data reference time (Ref. 20.3.3.3.3.1 IS-GPS-200E) [s] + double d_Cic; //!< Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination [rad] + double d_OMEGA0; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + double d_Cis; //!< Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination [rad] + // broadcast orbit 4 + double d_i_0; //!< Inclination Angle at Reference Time [semi-circles] + double d_Crc; //!< Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius [m] + double d_OMEGA; //!< Argument of Perigee [semi-cicles] + double d_OMEGA_DOT; //!< Rate of Right Ascension [semi-circles/s] + // broadcast orbit 5 + double d_IDOT; //!< Rate of Inclination Angle [semi-circles/s] + int32_t i_code_on_L2; //!< If 1, P code ON in L2; if 2, C/A code ON in L2; + int32_t i_GPS_week; //!< GPS week number, aka WN [week] + bool b_L2_P_data_flag; //!< When true, indicates that the NAV data stream was commanded OFF on the P-code of the L2 channel + // broadcast orbit 6 + int32_t i_SV_accuracy; //!< User Range Accuracy (URA) index of the SV (reference paragraph 6.2.1) for the standard positioning service user (Ref 20.3.3.3.1.3 IS-GPS-200E) + int32_t i_SV_health; + double d_TGD; //!< Estimated Group Delay Differential: L1-L2 correction term only for the benefit of "L1 P(Y)" or "L2 P(Y)" s users [s] + int32_t d_IODC; //!< Issue of Data, Clock + // broadcast orbit 7 + int32_t i_AODO; //!< Age of Data Offset (AODO) term for the navigation message correction table (NMCT) contained in subframe 4 (reference paragraph 20.3.3.5.1.9) [s] + bool b_fit_interval_flag; //!< indicates the curve-fit interval used by the CS (Block II/IIA/IIR/IIR-M/IIF) and SS (Block IIIA) in determining the ephemeris parameters, as follows: 0 = 4 hours, 1 = greater than 4 hours. double d_spare1; double d_spare2; - - double d_A_f0; //!< Coefficient 0 of code phase offset model [s] - double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] - double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] - + double d_A_f0; //!< Coefficient 0 of code phase offset model [s] + double d_A_f1; //!< Coefficient 1 of code phase offset model [s/s] + double d_A_f2; //!< Coefficient 2 of code phase offset model [s/s^2] // Almanac - double d_Toa; //!< Almanac reference time [s] - int i_WN_A; //!< Modulo 256 of the GPS week number to which the almanac reference time (d_Toa) is referenced - std::map almanacHealth; //!< Map that stores the health information stored in the almanac + int32_t i_Toa; //!< Almanac reference time [s] + int32_t i_WN_A; //!< Modulo 256 of the GPS week number to which the almanac reference time (i_Toa) is referenced + std::map almanacHealth; //!< Map that stores the health information stored in the almanac - std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus + std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus // Flags @@ -140,53 +128,54 @@ public: * accompanying alert, is less than 1E-8 per hour. */ bool b_integrity_status_flag; - bool b_alert_flag; //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. + bool b_alert_flag; //!< If true, indicates that the SV URA may be worse than indicated in d_SV_accuracy, use that SV at our own risk. bool b_antispoofing_flag; //!< If true, the AntiSpoofing mode is ON in that SV // clock terms //double d_master_clock; // GPS transmission time - double d_satClkCorr; // GPS clock error - double d_dtr; // relativistic clock correction term + double d_satClkCorr; // GPS clock error + double d_dtr; // relativistic clock correction term double d_satClkDrift; // satellite positions - double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. - double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. - double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). + double d_satpos_X; //!< Earth-fixed coordinate x of the satellite [m]. Intersection of the IERS Reference Meridian (IRM) and the plane passing through the origin and normal to the Z-axis. + double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite [m]. Completes a right-handed, Earth-Centered, Earth-Fixed orthogonal coordinate system. + double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite [m]. The direction of the IERS (International Earth Rotation and Reference Systems Service) Reference Pole (IRP). // satellite identification info - int i_channel_ID; - unsigned int i_satellite_PRN; + int32_t i_channel_ID; + uint32_t i_satellite_PRN; // time synchro - double d_subframe_timestamp_ms; //[ms] + double d_subframe_timestamp_ms; // [ms] // Ionospheric parameters - bool flag_iono_valid; //!< If set, it indicates that the ionospheric parameters are filled (page 18 has arrived and decoded) - double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] - double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] - double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] - double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] - double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] - double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] - double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] - double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] + bool flag_iono_valid; //!< If set, it indicates that the ionospheric parameters are filled (page 18 has arrived and decoded) + double d_alpha0; //!< Coefficient 0 of a cubic equation representing the amplitude of the vertical delay [s] + double d_alpha1; //!< Coefficient 1 of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] + double d_alpha2; //!< Coefficient 2 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^2] + double d_alpha3; //!< Coefficient 3 of a cubic equation representing the amplitude of the vertical delay [s(semi-circle)^3] + double d_beta0; //!< Coefficient 0 of a cubic equation representing the period of the model [s] + double d_beta1; //!< Coefficient 1 of a cubic equation representing the period of the model [s/semi-circle] + double d_beta2; //!< Coefficient 2 of a cubic equation representing the period of the model [s(semi-circle)^2] + double d_beta3; //!< Coefficient 3 of a cubic equation representing the period of the model [s(semi-circle)^3] // UTC parameters - bool flag_utc_model_valid; //!< If set, it indicates that the UTC model parameters are filled - double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] - double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s] - double d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200E) [s] - int i_WN_T; //!< UTC reference week number [weeks] - double d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. - int i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] - int i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] - double d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] + bool flag_utc_model_valid; //!< If set, it indicates that the UTC model parameters are filled + double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s] + double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] + double d_A2; //!< 2nd order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] + int32_t d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200E) [s] + int32_t i_WN_T; //!< UTC reference week number [weeks] + int32_t d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. + int32_t i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] + int32_t i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] + int32_t d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] // Satellite velocity - double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] - double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] - double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] + double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite [m] + double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite [m] + double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite [m] // public functions void reset(); @@ -210,20 +199,7 @@ public: /*! * \brief Decodes the GPS NAV message */ - int subframe_decoder(char *subframe); - - /*! - * \brief Computes the position of the satellite - * - * Implementation of Table 20-IV (IS-GPS-200E) - */ - void satellitePosition(double transmitTime); - - /*! - * \brief Sets (\a d_satClkCorr) according to the User Algorithm for SV Clock Correction - * and returns the corrected clock (IS-GPS-200E, 20.3.3.3.3.1) - */ - double sv_clock_correction(double transmitTime); + int32_t subframe_decoder(char* subframe); /*! * \brief Computes the Coordinated Universal Time (UTC) and diff --git a/src/core/system_parameters/gps_utc_model.cc b/src/core/system_parameters/gps_utc_model.cc index 2548b5ab9..5641186b4 100644 --- a/src/core/system_parameters/gps_utc_model.cc +++ b/src/core/system_parameters/gps_utc_model.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,11 +31,13 @@ #include "gps_utc_model.h" #include + Gps_Utc_Model::Gps_Utc_Model() { valid = false; - d_A1 = 0; - d_A0 = 0; + d_A0 = 0.0; + d_A1 = 0.0; + d_A2 = 0.0; d_t_OT = 0; i_WN_T = 0; d_DeltaT_LS = 0; @@ -44,26 +46,27 @@ Gps_Utc_Model::Gps_Utc_Model() d_DeltaT_LSF = 0; } -double Gps_Utc_Model::utc_time(double gpstime_corrected, int i_GPS_week) + +double Gps_Utc_Model::utc_time(double gpstime_corrected, int32_t i_GPS_week) { double t_utc; double t_utc_daytime; - double Delta_t_UTC = d_DeltaT_LS + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); + double Delta_t_UTC = d_DeltaT_LS + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); // Determine if the effectivity time of the leap second event is in the past - int weeksToLeapSecondEvent = i_WN_LSF - i_GPS_week; + int32_t weeksToLeapSecondEvent = i_WN_LSF - i_GPS_week; - if (weeksToLeapSecondEvent >= 0) // is not in the past + if (weeksToLeapSecondEvent >= 0) // is not in the past { - //Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s - int secondOfLeapSecondEvent = i_DN * 24 * 60 * 60; + // Detect if the effectivity time and user's time is within six hours = 6 * 60 *60 = 21600 s + int32_t secondOfLeapSecondEvent = i_DN * 24 * 60 * 60; if (weeksToLeapSecondEvent > 0) { t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); } - else //we are in the same week than the leap second event + else // we are in the same week than the leap second event { - if (std::abs(gpstime_corrected - secondOfLeapSecondEvent) > 21600) + if (std::abs(gpstime_corrected - secondOfLeapSecondEvent) > 21600) { /* 20.3.3.5.2.4a * Whenever the effectivity time indicated by the WN_LSF and the DN values @@ -82,23 +85,23 @@ double Gps_Utc_Model::utc_time(double gpstime_corrected, int i_GPS_week) * proper accommodation of the leap second event with a possible week number * transition is provided by the following expression for UTC: */ - int W = fmod(gpstime_corrected - Delta_t_UTC - 43200, 86400) + 43200; + int32_t W = static_cast(fmod(gpstime_corrected - Delta_t_UTC - 43200, 86400)) + 43200; t_utc_daytime = fmod(W, 86400 + d_DeltaT_LSF - d_DeltaT_LS); - //implement something to handle a leap second event! + // implement something to handle a leap second event! } - if ( (gpstime_corrected - secondOfLeapSecondEvent) > 21600) + if ((gpstime_corrected - secondOfLeapSecondEvent) > 21600) { Delta_t_UTC = d_DeltaT_LSF + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); } } } - else // the effectivity time is in the past + else // the effectivity time is in the past { /* 20.3.3.5.2.4c * Whenever the effectivity time of the leap second event, as indicated by the * WNLSF and DN values, is in the "past" (relative to the user's current time), - * and the user�s current time does not fall in the time span as given above + * and the user's current time does not fall in the time span as given above * in 20.3.3.5.2.4b,*/ Delta_t_UTC = d_DeltaT_LSF + d_A0 + d_A1 * (gpstime_corrected - d_t_OT + 604800 * static_cast(i_GPS_week - i_WN_T)); t_utc_daytime = fmod(gpstime_corrected - Delta_t_UTC, 86400); @@ -108,4 +111,3 @@ double Gps_Utc_Model::utc_time(double gpstime_corrected, int i_GPS_week) t_utc = secondsOfWeekBeforeToday + t_utc_daytime; return t_utc; } - diff --git a/src/core/system_parameters/gps_utc_model.h b/src/core/system_parameters/gps_utc_model.h index 54df8b1bf..43283d30d 100644 --- a/src/core/system_parameters/gps_utc_model.h +++ b/src/core/system_parameters/gps_utc_model.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,8 @@ #ifndef GNSS_SDR_GPS_UTC_MODEL_H_ #define GNSS_SDR_GPS_UTC_MODEL_H_ -#include "boost/assign.hpp" #include - +#include /*! * \brief This class is a storage for the GPS UTC MODEL data as described in IS-GPS-200E @@ -46,44 +45,47 @@ class Gps_Utc_Model public: bool valid; // UTC parameters - double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] - double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s] - double d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200E) [s] - int i_WN_T; //!< UTC reference week number [weeks] - double d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. - int i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] - int i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] - double d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] + double d_A0; //!< Constant of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s] + double d_A1; //!< 1st order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] + double d_A2; //!< 2nd order term of a model that relates GPS and UTC time (ref. 20.3.3.5.2.4 IS-GPS-200E) [s/s] + int32_t d_t_OT; //!< Reference time for UTC data (reference 20.3.4.5 and 20.3.3.5.2.4 IS-GPS-200E) [s] + int32_t i_WN_T; //!< UTC reference week number [weeks] + int32_t d_DeltaT_LS; //!< delta time due to leap seconds [s]. Number of leap seconds since 6-Jan-1980 as transmitted by the GPS almanac. + int32_t i_WN_LSF; //!< Week number at the end of which the leap second becomes effective [weeks] + int32_t i_DN; //!< Day number (DN) at the end of which the leap second becomes effective [days] + int32_t d_DeltaT_LSF; //!< Scheduled future or recent past (relative to NAV message upload) value of the delta time due to leap seconds [s] /*! * Default constructor */ Gps_Utc_Model(); - template + template /* * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. */ - void serialize(Archive& archive, const unsigned int version) + inline void serialize(Archive& archive, const uint32_t version) { using boost::serialization::make_nvp; - if(version){}; - archive & make_nvp("valid",valid); - archive & make_nvp("d_A1",d_A1); - archive & make_nvp("d_A0",d_A0); - archive & make_nvp("d_t_OT",d_t_OT); - archive & make_nvp("i_WN_T",i_WN_T); - archive & make_nvp("d_DeltaT_LS",d_DeltaT_LS); - archive & make_nvp("i_WN_LSF",i_WN_LSF); - archive & make_nvp("i_DN",i_DN); - archive & make_nvp("d_DeltaT_LSF",d_DeltaT_LSF); + if (version) + { + }; + archive& make_nvp("valid", valid); + archive& make_nvp("d_A1", d_A1); + archive& make_nvp("d_A0", d_A0); + archive& make_nvp("d_t_OT", d_t_OT); + archive& make_nvp("i_WN_T", i_WN_T); + archive& make_nvp("d_DeltaT_LS", d_DeltaT_LS); + archive& make_nvp("i_WN_LSF", i_WN_LSF); + archive& make_nvp("i_DN", i_DN); + archive& make_nvp("d_DeltaT_LSF", d_DeltaT_LSF); } /*! * \brief Computes the Coordinated Universal Time (UTC) and * returns it in [s] (IS-GPS-200E, 20.3.3.5.2.4) */ - double utc_time(double gpstime_corrected, int i_GPS_week); + double utc_time(double gpstime_corrected, int32_t i_GPS_week); }; #endif diff --git a/src/core/system_parameters/rtcm.cc b/src/core/system_parameters/rtcm.cc index 7f1eaa8ad..31640ce0a 100644 --- a/src/core/system_parameters/rtcm.cc +++ b/src/core/system_parameters/rtcm.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,61 +23,61 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "rtcm.h" +#include "GPS_L2C.h" +#include "Galileo_E1.h" +#include // for to_upper_copy +#include +#include +#include +#include #include // for std::reverse #include // std::chrono::seconds #include // for std::fmod #include // for strtol #include // for std::stringstream #include -#include // for to_upper_copy -#include -#include -#include -#include -#include "Galileo_E1.h" using google::LogMessage; -Rtcm::Rtcm(unsigned short port) +Rtcm::Rtcm(uint16_t port) { RTCM_port = port; preamble = std::bitset<8>("11010011"); reserved_field = std::bitset<6>("000000"); - rtcm_message_queue = std::make_shared< concurrent_queue >(); + rtcm_message_queue = std::make_shared >(); boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), RTCM_port); - servers.emplace_back(io_service, endpoint); + servers.emplace_back(io_context, endpoint); server_is_running = false; } Rtcm::~Rtcm() { - if(server_is_running) + if (server_is_running) { try - { + { stop_server(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { + } + catch (const std::exception& ex) + { LOG(WARNING) << "STD exception: " << ex.what(); - } + } } } - // ***************************************************************************************************** // // TCP Server helper classes @@ -85,33 +85,33 @@ Rtcm::~Rtcm() // ***************************************************************************************************** void Rtcm::run_server() { - std::cout << "Starting a TCP Server on port " << RTCM_port << std::endl; + std::cout << "Starting a TCP/IP server of RTCM messages on port " << RTCM_port << std::endl; try - { - std::thread tq([&]{ std::make_shared(io_service, rtcm_message_queue, RTCM_port)->do_read_queue(); }); + { + std::thread tq([&] { std::make_shared(io_context, rtcm_message_queue, RTCM_port)->do_read_queue(); }); tq.detach(); - std::thread t([&]{ io_service.run(); }); + std::thread t([&] { io_context.run(); }); server_is_running = true; t.detach(); - } - catch (std::exception& e) - { + } + catch (const std::exception& e) + { std::cerr << "Exception: " << e.what() << "\n"; - } + } } void Rtcm::stop_service() { - io_service.stop(); + io_context.stop(); } void Rtcm::stop_server() { - std::cout << "Stopping TCP Server on port " << RTCM_port << std::endl; - rtcm_message_queue->push("Goodbye"); // this terminates tq + std::cout << "Stopping TCP/IP server on port " << RTCM_port << std::endl; + rtcm_message_queue->push("Goodbye"); // this terminates tq Rtcm::stop_service(); servers.front().close_server(); std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -119,7 +119,7 @@ void Rtcm::stop_server() } -void Rtcm::send_message(const std::string & msg) +void Rtcm::send_message(const std::string& msg) { rtcm_message_queue->push(msg); } @@ -137,13 +137,13 @@ bool Rtcm::is_server_running() const // // ***************************************************************************************************** -std::string Rtcm::add_CRC (const std::string & message_without_crc) const +std::string Rtcm::add_CRC(const std::string& message_without_crc) const { // ****** Computes Qualcomm CRC-24Q ****** boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_RTCM; - // 1) Converts the string to a vector of unsigned char: - boost::dynamic_bitset frame_bits(message_without_crc); - std::vector bytes; + // 1) Converts the string to a vector of uint8_t: + boost::dynamic_bitset frame_bits(message_without_crc); + std::vector bytes; boost::to_block_range(frame_bits, std::back_inserter(bytes)); std::reverse(bytes.begin(), bytes.end()); @@ -157,63 +157,63 @@ std::string Rtcm::add_CRC (const std::string & message_without_crc) const } -bool Rtcm::check_CRC(const std::string & message) const +bool Rtcm::check_CRC(const std::string& message) const { boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_RTCM_CHECK; // Convert message to binary std::string message_bin = Rtcm::binary_data_to_bin(message); // Check CRC std::string crc = message_bin.substr(message_bin.length() - 24, 24); - std::bitset<24> read_crc = std::bitset<24>(crc); + std::bitset<24> read_crc = std::bitset<24>(crc); std::string msg_without_crc = message_bin.substr(0, message_bin.length() - 24); - boost::dynamic_bitset frame_bits(msg_without_crc); - std::vector bytes; + boost::dynamic_bitset frame_bits(msg_without_crc); + std::vector bytes; boost::to_block_range(frame_bits, std::back_inserter(bytes)); std::reverse(bytes.begin(), bytes.end()); CRC_RTCM_CHECK.process_bytes(bytes.data(), bytes.size()); std::bitset<24> computed_crc = std::bitset<24>(CRC_RTCM_CHECK.checksum()); - if(read_crc == computed_crc) + if (read_crc == computed_crc) { return true; } - else - { - return false; - } + + return false; } std::string Rtcm::bin_to_binary_data(const std::string& s) const { std::string s_aux; - int remainder = static_cast(std::fmod(s.length(), 8)); - unsigned char c[s.length()]; - unsigned int k = 0; + int32_t remainder = static_cast(std::fmod(s.length(), 8)); + std::vector c; + c.reserve(s.length()); + + uint32_t k = 0; if (remainder != 0) { - s_aux.assign(s, 0 , remainder); + s_aux.assign(s, 0, remainder); boost::dynamic_bitset<> rembits(s_aux); - unsigned long int n = rembits.to_ulong(); - c[0] = static_cast(n); + uint64_t n = rembits.to_ulong(); + c[0] = static_cast(n); k++; } - unsigned int start = std::max(remainder, 0); - for(unsigned int i = start; i < s.length() - 1; i = i + 8) + uint32_t start = std::max(remainder, 0); + for (uint32_t i = start; i < s.length() - 1; i = i + 8) { s_aux.assign(s, i, 4); std::bitset<4> bs(s_aux); - unsigned n = bs.to_ulong(); - s_aux.assign(s, i + 4 , 4); + uint32_t n = bs.to_ulong(); + s_aux.assign(s, i + 4, 4); std::bitset<4> bs2(s_aux); - unsigned n2 = bs2.to_ulong(); - c[k] = static_cast(n * 16) + static_cast(n2); + uint32_t n2 = bs2.to_ulong(); + c[k] = static_cast(n * 16) + static_cast(n2); k++; } - std::string ret(c, c + k / sizeof(c[0])); + std::string ret(c.begin(), c.begin() + k); return ret; } @@ -223,9 +223,9 @@ std::string Rtcm::binary_data_to_bin(const std::string& s) const std::string s_aux; std::stringstream ss; - for(unsigned int i = 0; i < s.length(); i++) + for (char i : s) { - unsigned char val = static_cast(s.at(i)); + auto val = static_cast(i); std::bitset<8> bs(val); ss << bs; } @@ -239,22 +239,22 @@ std::string Rtcm::bin_to_hex(const std::string& s) const { std::string s_aux; std::stringstream ss; - int remainder = static_cast(std::fmod(s.length(), 4)); + int32_t remainder = static_cast(std::fmod(s.length(), 4)); if (remainder != 0) { - s_aux.assign(s, 0 , remainder); + s_aux.assign(s, 0, remainder); boost::dynamic_bitset<> rembits(s_aux); - unsigned n = rembits.to_ulong(); + uint32_t n = rembits.to_ulong(); ss << std::hex << n; } - unsigned int start = std::max(remainder, 0); - for(unsigned int i = start; i < s.length() - 1; i = i + 4) + uint32_t start = std::max(remainder, 0); + for (uint32_t i = start; i < s.length() - 1; i = i + 4) { s_aux.assign(s, i, 4); std::bitset<4> bs(s_aux); - unsigned n = bs.to_ulong(); + uint32_t n = bs.to_ulong(); ss << std::hex << n; } return boost::to_upper_copy(ss.str()); @@ -268,10 +268,10 @@ std::string Rtcm::hex_to_bin(const std::string& s) const std::stringstream ss; ss << s; std::string s_lower = boost::to_upper_copy(ss.str()); - for(unsigned int i = 0; i < s.length(); i++) + for (uint32_t i = 0; i < s.length(); i++) { - unsigned long int n; - std::istringstream(s_lower.substr(i,1)) >> std::hex >> n; + uint64_t n; + std::istringstream(s_lower.substr(i, 1)) >> std::hex >> n; std::bitset<4> bs(n); s_aux += bs.to_string(); } @@ -279,67 +279,102 @@ std::string Rtcm::hex_to_bin(const std::string& s) const } -unsigned long int Rtcm::bin_to_uint(const std::string& s) const +uint32_t Rtcm::bin_to_uint(const std::string& s) const { - if(s.length() > 32) + if (s.length() > 32) { - LOG(WARNING) << "Cannot convert to a unsigned long int"; + LOG(WARNING) << "Cannot convert to a uint32_t"; return 0; } - unsigned long int reading = strtoul(s.c_str(), NULL, 2); + uint32_t reading = strtoul(s.c_str(), nullptr, 2); return reading; } -long int Rtcm::bin_to_int(const std::string& s) const +int32_t Rtcm::bin_to_int(const std::string& s) const { - if(s.length() > 32) + if (s.length() > 32) { - LOG(WARNING) << "Cannot convert to a long int"; + LOG(WARNING) << "Cannot convert to a int32_t"; return 0; } - long int reading; + int32_t reading; // Handle negative numbers - if(s.substr(0,1).compare("0")) + if (s.substr(0, 1) != "0") { // Computing two's complement boost::dynamic_bitset<> original_bitset(s); original_bitset.flip(); - reading = - (original_bitset.to_ulong() + 1); + reading = -(original_bitset.to_ulong() + 1); } else { - reading = strtol(s.c_str(), NULL, 2); + reading = strtol(s.c_str(), nullptr, 2); } return reading; } +int32_t Rtcm::bin_to_sint(const std::string& s) const +{ + if (s.length() > 32) + { + LOG(WARNING) << "Cannot convert to a int32_t"; + return 0; + } + int32_t reading; + int32_t sign; + + // Check for sign bit as defined RTCM doc + if (s.substr(0, 1) != "0") + { + sign = 1; + // Get the magnitude of the value + reading = strtol((s.substr(1)).c_str(), nullptr, 2); + } + else + { + sign = -1; + // Get the magnitude of the value + reading = strtol((s.substr(1)).c_str(), nullptr, 2); + } + return sign * reading; +} + +// Find the sign for glonass data fields (neg = 1, pos = 0) +static inline uint64_t glo_sgn(double val) +{ + if (val < 0) return 1; // If value is negative return 1 + if (val == 0) return 0; // Positive or equal to zero return 0 + return 0; +} + + double Rtcm::bin_to_double(const std::string& s) const { double reading; - if(s.length() > 64) + if (s.length() > 64) { LOG(WARNING) << "Cannot convert to a double"; return 0; } - long long int reading_int; + int64_t reading_int; // Handle negative numbers - if(s.substr(0,1).compare("0")) + if (s.substr(0, 1) != "0") { // Computing two's complement boost::dynamic_bitset<> original_bitset(s); original_bitset.flip(); std::string aux; to_string(original_bitset, aux); - reading_int = - (strtoll(aux.c_str(), NULL, 2) + 1); + reading_int = -(strtoll(aux.c_str(), nullptr, 2) + 1); } else { - reading_int = strtoll(s.c_str(), NULL, 2); + reading_int = strtoll(s.c_str(), nullptr, 2); } reading = static_cast(reading_int); @@ -347,47 +382,46 @@ double Rtcm::bin_to_double(const std::string& s) const } -unsigned long int Rtcm::hex_to_uint(const std::string& s) const +uint64_t Rtcm::hex_to_uint(const std::string& s) const { - if(s.length() > 32) + if (s.length() > 32) { - LOG(WARNING) << "Cannot convert to a unsigned long int"; + LOG(WARNING) << "Cannot convert to a uint64_t"; return 0; } - unsigned long int reading = strtoul(s.c_str(), NULL, 16); + uint64_t reading = strtoul(s.c_str(), nullptr, 16); return reading; } -long int Rtcm::hex_to_int(const std::string& s) const +int64_t Rtcm::hex_to_int(const std::string& s) const { - if(s.length() > 32) + if (s.length() > 32) { - LOG(WARNING) << "Cannot convert to a long int"; + LOG(WARNING) << "Cannot convert to a int64_t"; return 0; } - long int reading = strtol(s.c_str(), NULL, 16); + int64_t reading = strtol(s.c_str(), nullptr, 16); return reading; } -std::string Rtcm::build_message(const std::string & data) const +std::string Rtcm::build_message(const std::string& data) const { - unsigned int msg_length_bits = data.length(); - unsigned int msg_length_bytes = std::ceil(static_cast(msg_length_bits) / 8.0); + uint32_t msg_length_bits = data.length(); + uint32_t msg_length_bytes = std::ceil(static_cast(msg_length_bits) / 8.0); std::bitset<10> message_length = std::bitset<10>(msg_length_bytes); - unsigned int zeros_to_fill = 8 * msg_length_bytes - msg_length_bits; + uint32_t zeros_to_fill = 8 * msg_length_bytes - msg_length_bits; std::string b(zeros_to_fill, '0'); std::string msg_content = data + b; std::string msg_without_crc = preamble.to_string() + - reserved_field.to_string() + - message_length.to_string() + - msg_content; + reserved_field.to_string() + + message_length.to_string() + + msg_content; return Rtcm::add_CRC(msg_without_crc); } - // ***************************************************************************************************** // // MESSAGES AS DEFINED AT RTCM STANDARD 10403.2 @@ -395,21 +429,20 @@ std::string Rtcm::build_message(const std::string & data) const // ***************************************************************************************************** - // ******************************************************** // // MESSAGE TYPE 1001 (GPS L1 OBSERVATIONS) // // ******************************************************** -std::bitset<64> Rtcm::get_MT1001_4_header(unsigned int msg_number, double obs_time, const std::map & observables, - unsigned int ref_id, unsigned int smooth_int, bool sync_flag, bool divergence_free) +std::bitset<64> Rtcm::get_MT1001_4_header(uint32_t msg_number, double obs_time, const std::map& observables, + uint32_t ref_id, uint32_t smooth_int, bool sync_flag, bool divergence_free) { - unsigned int reference_station_id = ref_id; // Max: 4095 - const std::map observables_ = observables; + uint32_t reference_station_id = ref_id; // Max: 4095 + const std::map observables_ = observables; bool synchronous_GNSS_flag = sync_flag; bool divergence_free_smoothing_indicator = divergence_free; - unsigned int smoothing_interval = smooth_int; + uint32_t smoothing_interval = smooth_int; Rtcm::set_DF002(msg_number); Rtcm::set_DF003(reference_station_id); Rtcm::set_DF004(obs_time); @@ -419,74 +452,74 @@ std::bitset<64> Rtcm::get_MT1001_4_header(unsigned int msg_number, double obs_ti Rtcm::set_DF008(smoothing_interval); std::string header = DF002.to_string() + - DF003.to_string() + - DF004.to_string() + - DF005.to_string() + - DF006.to_string() + - DF007.to_string() + - DF008.to_string(); + DF003.to_string() + + DF004.to_string() + + DF005.to_string() + + DF006.to_string() + + DF007.to_string() + + DF008.to_string(); std::bitset<64> header_msg(header); return header_msg; } -std::bitset<58> Rtcm::get_MT1001_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +std::bitset<58> Rtcm::get_MT1001_sat_content(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF009(gnss_synchro); - Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF011(gnss_synchro); Rtcm::set_DF012(gnss_synchro); Rtcm::set_DF013(eph, obs_time, gnss_synchro); std::string content = DF009.to_string() + - DF010.to_string() + - DF011.to_string() + - DF012.to_string() + - DF013.to_string(); + DF010.to_string() + + DF011.to_string() + + DF012.to_string() + + DF013.to_string(); std::bitset<58> content_msg(content); return content_msg; } -std::string Rtcm::print_MT1001(const Gps_Ephemeris & gps_eph, double obs_time, const std::map & observables, unsigned short station_id) +std::string Rtcm::print_MT1001(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables, uint16_t station_id) { - unsigned int ref_id = static_cast(station_id); - unsigned int smooth_int = 0; + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; bool sync_flag = false; bool divergence_free = false; //Get a map with GPS L1 only observations - std::map observablesL1; - std::map::const_iterator observables_iter; + std::map observablesL1; + std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) { - observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); } } std::bitset<64> header = Rtcm::get_MT1001_4_header(1001, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); std::string data = header.to_string(); - for(observables_iter = observablesL1.begin(); - observables_iter != observablesL1.end(); - observables_iter++) + for (observables_iter = observablesL1.cbegin(); + observables_iter != observablesL1.cend(); + observables_iter++) { std::bitset<58> content = Rtcm::get_MT1001_sat_content(gps_eph, obs_time, observables_iter->second); data += content.to_string(); } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -494,49 +527,48 @@ std::string Rtcm::print_MT1001(const Gps_Ephemeris & gps_eph, double obs_time, c } - // ******************************************************** // // MESSAGE TYPE 1002 (EXTENDED GPS L1 OBSERVATIONS) // // ******************************************************** -std::string Rtcm::print_MT1002(const Gps_Ephemeris & gps_eph, double obs_time, const std::map & observables, unsigned short station_id) +std::string Rtcm::print_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables, uint16_t station_id) { - unsigned int ref_id = static_cast(station_id); - unsigned int smooth_int = 0; + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; bool sync_flag = false; bool divergence_free = false; //Get a map with GPS L1 only observations - std::map observablesL1; - std::map::const_iterator observables_iter; + std::map observablesL1; + std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) { - observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); } } std::bitset<64> header = Rtcm::get_MT1001_4_header(1002, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); std::string data = header.to_string(); - for(observables_iter = observablesL1.begin(); - observables_iter != observablesL1.end(); - observables_iter++) + for (observables_iter = observablesL1.cbegin(); + observables_iter != observablesL1.cend(); + observables_iter++) { std::bitset<74> content = Rtcm::get_MT1002_sat_content(gps_eph, obs_time, observables_iter->second); data += content.to_string(); } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -544,86 +576,85 @@ std::string Rtcm::print_MT1002(const Gps_Ephemeris & gps_eph, double obs_time, c } -std::bitset<74> Rtcm::get_MT1002_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +std::bitset<74> Rtcm::get_MT1002_sat_content(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF009(gnss_synchro); - Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF011(gnss_synchro); Rtcm::set_DF012(gnss_synchro); Rtcm::set_DF013(eph, obs_time, gnss_synchro); std::string content = DF009.to_string() + - DF010.to_string() + - DF011.to_string() + - DF012.to_string() + - DF013.to_string() + - DF014.to_string() + - DF015.to_string(); + DF010.to_string() + + DF011.to_string() + + DF012.to_string() + + DF013.to_string() + + DF014.to_string() + + DF015.to_string(); std::bitset<74> content_msg(content); return content_msg; } - // ******************************************************** // // MESSAGE TYPE 1003 (GPS L1 & L2 OBSERVATIONS) // // ******************************************************** -std::string Rtcm::print_MT1003(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id) +std::string Rtcm::print_MT1003(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id) { - unsigned int ref_id = static_cast(station_id); - unsigned int smooth_int = 0; + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; bool sync_flag = false; bool divergence_free = false; //Get maps with GPS L1 and L2 observations - std::map observablesL1; - std::map observablesL2; - std::map::const_iterator observables_iter; - std::map::const_iterator observables_iter2; + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) { - observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("G") == 0) && (sig_.compare("2S") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("2S") == 0)) { - observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); } } // Get common observables - std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables; - std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter; - std::map observablesL1_with_L2; + std::vector > common_observables; + std::vector >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; - for(observables_iter = observablesL1.begin(); - observables_iter != observablesL1.end(); - observables_iter++) + for (observables_iter = observablesL1.cbegin(); + observables_iter != observablesL1.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; - for(observables_iter2 = observablesL2.begin(); - observables_iter2 != observablesL2.end(); - observables_iter2++) + uint32_t prn_ = observables_iter->second.PRN; + for (observables_iter2 = observablesL2.cbegin(); + observables_iter2 != observablesL2.cend(); + observables_iter2++) { - if(observables_iter2->second.PRN == prn_) + if (observables_iter2->second.PRN == prn_) { std::pair p; Gnss_Synchro pr1 = observables_iter->second; Gnss_Synchro pr2 = observables_iter2->second; p = std::make_pair(pr1, pr2); common_observables.push_back(p); - observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); } } } @@ -631,16 +662,16 @@ std::string Rtcm::print_MT1003(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephem std::bitset<64> header = Rtcm::get_MT1001_4_header(1003, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); std::string data = header.to_string(); - for(common_observables_iter = common_observables.begin(); - common_observables_iter != common_observables.end(); - common_observables_iter++) + for (common_observables_iter = common_observables.cbegin(); + common_observables_iter != common_observables.cend(); + common_observables_iter++) { std::bitset<101> content = Rtcm::get_MT1003_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); data += content.to_string(); } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -648,92 +679,91 @@ std::string Rtcm::print_MT1003(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephem } -std::bitset<101> Rtcm::get_MT1003_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +std::bitset<101> Rtcm::get_MT1003_sat_content(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) { - bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF009(gnss_synchroL1); - Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF011(gnss_synchroL1); Rtcm::set_DF012(gnss_synchroL1); Rtcm::set_DF013(ephL1, obs_time, gnss_synchroL1); - std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y Rtcm::set_DF017(gnss_synchroL1, gnss_synchroL2); Rtcm::set_DF018(gnss_synchroL1, gnss_synchroL2); Rtcm::set_DF019(ephL2, obs_time, gnss_synchroL2); std::string content = DF009.to_string() + - DF010.to_string() + - DF011.to_string() + - DF012.to_string() + - DF013.to_string() + - DF016_.to_string() + - DF017.to_string() + - DF018.to_string() + - DF019.to_string(); + DF010.to_string() + + DF011.to_string() + + DF012.to_string() + + DF013.to_string() + + DF016_.to_string() + + DF017.to_string() + + DF018.to_string() + + DF019.to_string(); std::bitset<101> content_msg(content); return content_msg; } - // ****************************************************************** // // MESSAGE TYPE 1004 (EXTENDED GPS L1 & L2 OBSERVATIONS) // // ****************************************************************** -std::string Rtcm::print_MT1004(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id) +std::string Rtcm::print_MT1004(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id) { - unsigned int ref_id = static_cast(station_id); - unsigned int smooth_int = 0; + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; bool sync_flag = false; bool divergence_free = false; //Get maps with GPS L1 and L2 observations - std::map observablesL1; - std::map observablesL2; - std::map::const_iterator observables_iter; - std::map::const_iterator observables_iter2; + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string system_(&observables_iter->second.System, 1); std::string sig_(observables_iter->second.Signal); - if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) { - observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); } - if((system_.compare("G") == 0) && (sig_.compare("2S") == 0)) + if ((system_.compare("G") == 0) && (sig_.compare("2S") == 0)) { - observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); } } // Get common observables - std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables; - std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter; - std::map observablesL1_with_L2; + std::vector > common_observables; + std::vector >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; - for(observables_iter = observablesL1.begin(); - observables_iter != observablesL1.end(); - observables_iter++) + for (observables_iter = observablesL1.cbegin(); + observables_iter != observablesL1.cend(); + observables_iter++) { - unsigned int prn_ = observables_iter->second.PRN; - for(observables_iter2 = observablesL2.begin(); - observables_iter2 != observablesL2.end(); - observables_iter2++) + uint32_t prn_ = observables_iter->second.PRN; + for (observables_iter2 = observablesL2.cbegin(); + observables_iter2 != observablesL2.cend(); + observables_iter2++) { - if(observables_iter2->second.PRN == prn_) + if (observables_iter2->second.PRN == prn_) { std::pair p; Gnss_Synchro pr1 = observables_iter->second; Gnss_Synchro pr2 = observables_iter2->second; p = std::make_pair(pr1, pr2); common_observables.push_back(p); - observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); } } } @@ -741,16 +771,16 @@ std::string Rtcm::print_MT1004(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephem std::bitset<64> header = Rtcm::get_MT1001_4_header(1004, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); std::string data = header.to_string(); - for(common_observables_iter = common_observables.begin(); - common_observables_iter != common_observables.end(); - common_observables_iter++) + for (common_observables_iter = common_observables.cbegin(); + common_observables_iter != common_observables.cend(); + common_observables_iter++) { std::bitset<125> content = Rtcm::get_MT1004_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); data += content.to_string(); } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -758,41 +788,40 @@ std::string Rtcm::print_MT1004(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephem } -std::bitset<125> Rtcm::get_MT1004_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +std::bitset<125> Rtcm::get_MT1004_sat_content(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) { - bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF009(gnss_synchroL1); - Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct Rtcm::set_DF011(gnss_synchroL1); Rtcm::set_DF012(gnss_synchroL1); Rtcm::set_DF013(ephL1, obs_time, gnss_synchroL1); Rtcm::set_DF014(gnss_synchroL1); Rtcm::set_DF015(gnss_synchroL1); - std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y Rtcm::set_DF017(gnss_synchroL1, gnss_synchroL2); Rtcm::set_DF018(gnss_synchroL1, gnss_synchroL2); Rtcm::set_DF019(ephL2, obs_time, gnss_synchroL2); Rtcm::set_DF020(gnss_synchroL2); std::string content = DF009.to_string() + - DF010.to_string() + - DF011.to_string() + - DF012.to_string() + - DF013.to_string() + - DF014.to_string() + - DF015.to_string() + - DF016_.to_string() + - DF017.to_string() + - DF018.to_string() + - DF019.to_string() + - DF020.to_string(); + DF010.to_string() + + DF011.to_string() + + DF012.to_string() + + DF013.to_string() + + DF014.to_string() + + DF015.to_string() + + DF016_.to_string() + + DF017.to_string() + + DF018.to_string() + + DF019.to_string() + + DF020.to_string(); std::bitset<125> content_msg(content); return content_msg; } - // ******************************************************** // // MESSAGE TYPE 1005 (STATION DESCRIPTION) @@ -809,52 +838,52 @@ std::bitset<125> Rtcm::get_MT1004_sat_content(const Gps_Ephemeris & ephL1, const Expected output: D3 00 13 3E D7 D3 02 02 98 0E DE EF 34 B4 BD 62 AC 09 41 98 6F 33 36 0B 98 */ -std::bitset<152> Rtcm::get_MT1005_test () +std::bitset<152> Rtcm::get_MT1005_test() { - unsigned int mt1005 = 1005; - unsigned int reference_station_id = 2003; // Max: 4095 - double ECEF_X = 1114104.5999; // units: m - double ECEF_Y = -4850729.7108; // units: m - double ECEF_Z = 3975521.4643; // units: m + uint32_t mt1005 = 1005; + uint32_t reference_station_id = 2003; // Max: 4095 + double ECEF_X = 1114104.5999; // units: m + double ECEF_Y = -4850729.7108; // units: m + double ECEF_Z = 3975521.4643; // units: m std::bitset<1> DF001_; Rtcm::set_DF002(mt1005); Rtcm::set_DF003(reference_station_id); Rtcm::set_DF021(); - Rtcm::set_DF022(true); // GPS - Rtcm::set_DF023(false); // Glonass - Rtcm::set_DF024(false); // Galileo - DF141 = std::bitset<1>("0"); // 0: Real, physical reference station - DF001_ = std::bitset<1>("0"); // Reserved, set to 0 + Rtcm::set_DF022(true); // GPS + Rtcm::set_DF023(false); // Glonass + Rtcm::set_DF024(false); // Galileo + DF141 = std::bitset<1>("0"); // 0: Real, physical reference station + DF001_ = std::bitset<1>("0"); // Reserved, set to 0 Rtcm::set_DF025(ECEF_X); - DF142 = std::bitset<1>("0"); // Single Receiver Oscillator Indicator + DF142 = std::bitset<1>("0"); // Single Receiver Oscillator Indicator Rtcm::set_DF026(ECEF_Y); - DF364 = std::bitset<2>("00"); // Quarter Cycle Indicator + DF364 = std::bitset<2>("00"); // Quarter Cycle Indicator Rtcm::set_DF027(ECEF_Z); std::string message = DF002.to_string() + - DF003.to_string() + - DF021.to_string() + - DF022.to_string() + - DF023.to_string() + - DF024.to_string() + - DF141.to_string() + - DF025.to_string() + - DF142.to_string() + - DF001_.to_string() + - DF026.to_string() + - DF364.to_string() + - DF027.to_string() ; + DF003.to_string() + + DF021.to_string() + + DF022.to_string() + + DF023.to_string() + + DF024.to_string() + + DF141.to_string() + + DF025.to_string() + + DF142.to_string() + + DF001_.to_string() + + DF026.to_string() + + DF364.to_string() + + DF027.to_string(); std::bitset<152> test_msg(message); return test_msg; } -std::string Rtcm::print_MT1005( unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator) +std::string Rtcm::print_MT1005(uint32_t ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, uint32_t quarter_cycle_indicator) { - unsigned int msg_number = 1005; + uint32_t msg_number = 1005; std::bitset<1> DF001_; Rtcm::set_DF002(msg_number); @@ -872,21 +901,21 @@ std::string Rtcm::print_MT1005( unsigned int ref_id, double ecef_x, double ecef_ Rtcm::set_DF027(ecef_z); std::string data = DF002.to_string() + - DF003.to_string() + - DF021.to_string() + - DF022.to_string() + - DF023.to_string() + - DF024.to_string() + - DF141.to_string() + - DF025.to_string() + - DF142.to_string() + - DF001_.to_string() + - DF026.to_string() + - DF364.to_string() + - DF027.to_string() ; + DF003.to_string() + + DF021.to_string() + + DF022.to_string() + + DF023.to_string() + + DF024.to_string() + + DF141.to_string() + + DF025.to_string() + + DF142.to_string() + + DF001_.to_string() + + DF026.to_string() + + DF364.to_string() + + DF027.to_string(); std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -894,23 +923,23 @@ std::string Rtcm::print_MT1005( unsigned int ref_id, double ecef_x, double ecef_ } -int Rtcm::read_MT1005(const std::string & message, unsigned int & ref_id, double & ecef_x, double & ecef_y, double & ecef_z, bool & gps, bool & glonass, bool & galileo) +int32_t Rtcm::read_MT1005(const std::string& message, uint32_t& ref_id, double& ecef_x, double& ecef_y, double& ecef_z, bool& gps, bool& glonass, bool& galileo) { // Convert message to binary std::string message_bin = Rtcm::binary_data_to_bin(message); - if(!Rtcm::check_CRC(message) ) + if (!Rtcm::check_CRC(message)) { LOG(WARNING) << " Bad CRC detected in RTCM message MT1005"; return 1; } // Check than the message number is correct - unsigned int preamble_length = 8; - unsigned int reserved_field_length = 6; - unsigned int index = preamble_length + reserved_field_length; + uint32_t preamble_length = 8; + uint32_t reserved_field_length = 6; + uint32_t index = preamble_length + reserved_field_length; - unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + uint32_t read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); index += 10; if (read_message_length != 19) { @@ -918,7 +947,7 @@ int Rtcm::read_MT1005(const std::string & message, unsigned int & ref_id, double return 1; } - unsigned int msg_number = 1005; + uint32_t msg_number = 1005; Rtcm::set_DF002(msg_number); std::bitset<12> read_msg_number(message_bin.substr(index, 12)); index += 12; @@ -933,7 +962,7 @@ int Rtcm::read_MT1005(const std::string & message, unsigned int & ref_id, double ref_id = Rtcm::bin_to_uint(message_bin.substr(index, 12)); index += 12; - index += 6; // ITRF year + index += 6; // ITRF year gps = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); index += 1; @@ -943,18 +972,18 @@ int Rtcm::read_MT1005(const std::string & message, unsigned int & ref_id, double galileo = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); index += 1; - index += 1; // ref_station_indicator + index += 1; // ref_station_indicator ecef_x = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0; index += 38; - index += 1; // single rx oscillator - index += 1; // reserved + index += 1; // single rx oscillator + index += 1; // reserved ecef_y = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0; index += 38; - index += 2; // quarter cycle indicator + index += 2; // quarter cycle indicator ecef_z = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0; return 0; @@ -973,9 +1002,9 @@ std::string Rtcm::print_MT1005_test() // // ******************************************************** -std::string Rtcm::print_MT1006(unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator, double height) +std::string Rtcm::print_MT1006(uint32_t ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, uint32_t quarter_cycle_indicator, double height) { - unsigned int msg_number = 1006; + uint32_t msg_number = 1006; std::bitset<1> DF001_; Rtcm::set_DF002(msg_number); @@ -994,22 +1023,22 @@ std::string Rtcm::print_MT1006(unsigned int ref_id, double ecef_x, double ecef_y Rtcm::set_DF028(height); std::string data = DF002.to_string() + - DF003.to_string() + - DF021.to_string() + - DF022.to_string() + - DF023.to_string() + - DF024.to_string() + - DF141.to_string() + - DF025.to_string() + - DF142.to_string() + - DF001_.to_string() + - DF026.to_string() + - DF364.to_string() + - DF027.to_string() + - DF028.to_string(); + DF003.to_string() + + DF021.to_string() + + DF022.to_string() + + DF023.to_string() + + DF024.to_string() + + DF141.to_string() + + DF025.to_string() + + DF142.to_string() + + DF001_.to_string() + + DF026.to_string() + + DF364.to_string() + + DF027.to_string() + + DF028.to_string(); std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -1022,13 +1051,13 @@ std::string Rtcm::print_MT1006(unsigned int ref_id, double ecef_x, double ecef_y // MESSAGE TYPE 1008 (ANTENNA DESCRIPTOR & SERIAL NUMBER) // // ******************************************************** -std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_descriptor, unsigned int antenna_setup_id, const std::string & antenna_serial_number) +std::string Rtcm::print_MT1008(uint32_t ref_id, const std::string& antenna_descriptor, uint32_t antenna_setup_id, const std::string& antenna_serial_number) { - unsigned int msg_number = 1008; + uint32_t msg_number = 1008; std::bitset<12> DF002_ = std::bitset<12>(msg_number); Rtcm::set_DF003(ref_id); std::string ant_descriptor = antenna_descriptor; - unsigned int len = ant_descriptor.length(); + uint32_t len = ant_descriptor.length(); if (len > 31) { ant_descriptor = ant_descriptor.substr(0, 31); @@ -1037,7 +1066,7 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ DF029 = std::bitset<8>(len); std::string DF030_str_; - for(auto it = ant_descriptor.begin(); it != ant_descriptor.end(); it++) + for (auto it = ant_descriptor.cbegin(); it != ant_descriptor.cend(); it++) { char c = *it; std::bitset<8> character = std::bitset<8>(c); @@ -1047,7 +1076,7 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ Rtcm::set_DF031(antenna_setup_id); std::string ant_sn(antenna_serial_number); - unsigned int len2 = ant_sn.length(); + uint32_t len2 = ant_sn.length(); if (len2 > 31) { ant_sn = ant_sn.substr(0, 31); @@ -1056,7 +1085,7 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ DF032 = std::bitset<8>(len2); std::string DF033_str_; - for(auto it = ant_sn.begin(); it != ant_sn.end(); it++) + for (auto it = ant_sn.cbegin(); it != ant_sn.cend(); it++) { char c = *it; std::bitset<8> character = std::bitset<8>(c); @@ -1064,15 +1093,15 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ } std::string data = DF002_.to_string() + - DF003.to_string() + - DF029.to_string() + - DF030_str_ + - DF031.to_string() + - DF032.to_string() + - DF033_str_; + DF003.to_string() + + DF029.to_string() + + DF030_str_ + + DF031.to_string() + + DF032.to_string() + + DF033_str_; std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -1080,15 +1109,417 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ } +// ******************************************************** +// +// MESSAGE TYPE 1009 (GLONASS L1 Basic RTK Observables) +// +// ******************************************************** +std::bitset<61> Rtcm::get_MT1009_12_header(uint32_t msg_number, double obs_time, const std::map& observables, + uint32_t ref_id, uint32_t smooth_int, bool sync_flag, bool divergence_free) +{ + uint32_t reference_station_id = ref_id; // Max: 4095 + const std::map observables_ = observables; + bool synchronous_GNSS_flag = sync_flag; + bool divergence_free_smoothing_indicator = divergence_free; + uint32_t smoothing_interval = smooth_int; + Rtcm::set_DF002(msg_number); + Rtcm::set_DF003(reference_station_id); + Rtcm::set_DF034(obs_time); + Rtcm::set_DF005(synchronous_GNSS_flag); + Rtcm::set_DF035(observables_); + Rtcm::set_DF036(divergence_free_smoothing_indicator); + Rtcm::set_DF037(smoothing_interval); + + std::string header = DF002.to_string() + + DF003.to_string() + + DF034.to_string() + + DF005.to_string() + + DF035.to_string() + + DF036.to_string() + + DF037.to_string(); + + std::bitset<61> header_msg(header); + return header_msg; +} + + +std::bitset<64> Rtcm::get_MT1009_sat_content(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchro); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(eph.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchro); + Rtcm::set_DF042(gnss_synchro); + Rtcm::set_DF043(eph, obs_time, gnss_synchro); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string(); + + std::bitset<64> content_msg(content); + return content_msg; +} + + +std::string Rtcm::print_MT1009(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables, uint16_t station_id) +{ + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get a map with GLONASS L1 only observations + std::map observablesL1; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1009, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for (observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + std::bitset<64> content = Rtcm::get_MT1009_sat_content(glonass_gnav_eph, obs_time, observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if (server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +// ******************************************************** +// +// MESSAGE TYPE 1010 (EXTENDED GLONASS L1 OBSERVATIONS) +// +// ******************************************************** + +std::string Rtcm::print_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables, uint16_t station_id) +{ + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get a map with GPS L1 only observations + std::map observablesL1; + std::map::const_iterator observables_iter; + + for (observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1010, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for (observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + std::bitset<79> content = Rtcm::get_MT1010_sat_content(glonass_gnav_eph, obs_time, observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if (server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<79> Rtcm::get_MT1010_sat_content(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchro); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(eph.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchro); + Rtcm::set_DF042(gnss_synchro); + Rtcm::set_DF043(eph, obs_time, gnss_synchro); + Rtcm::set_DF044(gnss_synchro); + Rtcm::set_DF045(gnss_synchro); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF044.to_string() + + DF045.to_string(); + + std::bitset<79> content_msg(content); + return content_msg; +} + + +// ******************************************************** +// +// MESSAGE TYPE 1011 (GLONASS L1 & L2 OBSERVATIONS) +// +// ******************************************************** + +std::string Rtcm::print_MT1011(const Glonass_Gnav_Ephemeris& ephL1, const Glonass_Gnav_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id) +{ + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get maps with GPS L1 and L2 observations + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; + + for (observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_.compare("R") == 0) && (sig_.compare("2C") == 0)) + { + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + // Get common observables + std::vector > common_observables; + std::vector >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; + + for (observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + for (observables_iter2 = observablesL2.begin(); + observables_iter2 != observablesL2.end(); + observables_iter2++) + { + if (observables_iter2->second.PRN == prn_) + { + std::pair p; + Gnss_Synchro pr1 = observables_iter->second; + Gnss_Synchro pr2 = observables_iter2->second; + p = std::make_pair(pr1, pr2); + common_observables.push_back(p); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1011, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for (common_observables_iter = common_observables.begin(); + common_observables_iter != common_observables.end(); + common_observables_iter++) + { + std::bitset<107> content = Rtcm::get_MT1011_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if (server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<107> Rtcm::get_MT1011_sat_content(const Glonass_Gnav_Ephemeris& ephL1, const Glonass_Gnav_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchroL1); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(ephL1.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchroL1); + Rtcm::set_DF042(gnss_synchroL1); + Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1); + std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF046_.to_string() + + DF047.to_string() + + DF048.to_string() + + DF049.to_string(); + + std::bitset<107> content_msg(content); + return content_msg; +} + + +// ****************************************************************** +// +// MESSAGE TYPE 1004 (EXTENDED GLONASS L1 & L2 OBSERVATIONS) +// +// ****************************************************************** + +std::string Rtcm::print_MT1012(const Glonass_Gnav_Ephemeris& ephL1, const Glonass_Gnav_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id) +{ + auto ref_id = static_cast(station_id); + uint32_t smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get maps with GLONASS L1 and L2 observations + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; + + for (observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if ((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if ((system_.compare("R") == 0) && (sig_.compare("2C") == 0)) + { + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + // Get common observables + std::vector > common_observables; + std::vector >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; + + for (observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + uint32_t prn_ = observables_iter->second.PRN; + for (observables_iter2 = observablesL2.begin(); + observables_iter2 != observablesL2.end(); + observables_iter2++) + { + if (observables_iter2->second.PRN == prn_) + { + std::pair p; + Gnss_Synchro pr1 = observables_iter->second; + Gnss_Synchro pr2 = observables_iter2->second; + p = std::make_pair(pr1, pr2); + common_observables.push_back(p); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1012, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for (common_observables_iter = common_observables.begin(); + common_observables_iter != common_observables.end(); + common_observables_iter++) + { + std::bitset<130> content = Rtcm::get_MT1012_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if (server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<130> Rtcm::get_MT1012_sat_content(const Glonass_Gnav_Ephemeris& ephL1, const Glonass_Gnav_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchroL1); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(ephL1.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchroL1); + Rtcm::set_DF042(gnss_synchroL1); + Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1); + Rtcm::set_DF044(gnss_synchroL1); + Rtcm::set_DF045(gnss_synchroL1); + std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2); + Rtcm::set_DF050(gnss_synchroL2); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF044.to_string() + + DF045.to_string() + + DF046_.to_string() + + DF047.to_string() + + DF048.to_string() + + DF049.to_string() + + DF050.to_string(); + + std::bitset<130> content_msg(content); + return content_msg; +} + + // ******************************************************** // // MESSAGE TYPE 1019 (GPS EPHEMERIS) // // ******************************************************** -std::string Rtcm::print_MT1019(const Gps_Ephemeris & gps_eph) +std::string Rtcm::print_MT1019(const Gps_Ephemeris& gps_eph) { - unsigned int msg_number = 1019; + uint32_t msg_number = 1019; Rtcm::set_DF002(msg_number); Rtcm::set_DF009(gps_eph); @@ -1125,44 +1556,44 @@ std::string Rtcm::print_MT1019(const Gps_Ephemeris & gps_eph) std::string data; data.clear(); data = DF002.to_string() + - DF009.to_string() + - DF076.to_string() + - DF077.to_string() + - DF078.to_string() + - DF079.to_string() + - DF071.to_string() + - DF081.to_string() + - DF082.to_string() + - DF083.to_string() + - DF084.to_string() + - DF085.to_string() + - DF086.to_string() + - DF087.to_string() + - DF088.to_string() + - DF089.to_string() + - DF090.to_string() + - DF091.to_string() + - DF092.to_string() + - DF093.to_string() + - DF094.to_string() + - DF095.to_string() + - DF096.to_string() + - DF097.to_string() + - DF098.to_string() + - DF099.to_string() + - DF100.to_string() + - DF101.to_string() + - DF102.to_string() + - DF103.to_string() + - DF137.to_string(); + DF009.to_string() + + DF076.to_string() + + DF077.to_string() + + DF078.to_string() + + DF079.to_string() + + DF071.to_string() + + DF081.to_string() + + DF082.to_string() + + DF083.to_string() + + DF084.to_string() + + DF085.to_string() + + DF086.to_string() + + DF087.to_string() + + DF088.to_string() + + DF089.to_string() + + DF090.to_string() + + DF091.to_string() + + DF092.to_string() + + DF093.to_string() + + DF094.to_string() + + DF095.to_string() + + DF096.to_string() + + DF097.to_string() + + DF098.to_string() + + DF099.to_string() + + DF100.to_string() + + DF101.to_string() + + DF102.to_string() + + DF103.to_string() + + DF137.to_string(); if (data.length() != 488) { - LOG(WARNING) << "Bad-formatted RTCM MT1019 (488 bits expected, found " << data.length() << ")"; + LOG(WARNING) << "Bad-formatted RTCM MT1019 (488 bits expected, found " << data.length() << ")"; } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -1170,22 +1601,22 @@ std::string Rtcm::print_MT1019(const Gps_Ephemeris & gps_eph) } -int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) +int32_t Rtcm::read_MT1019(const std::string& message, Gps_Ephemeris& gps_eph) { // Convert message to binary std::string message_bin = Rtcm::binary_data_to_bin(message); - if(!Rtcm::check_CRC(message) ) + if (!Rtcm::check_CRC(message)) { LOG(WARNING) << " Bad CRC detected in RTCM message MT1019"; return 1; } - unsigned int preamble_length = 8; - unsigned int reserved_field_length = 6; - unsigned int index = preamble_length + reserved_field_length; + uint32_t preamble_length = 8; + uint32_t reserved_field_length = 6; + uint32_t index = preamble_length + reserved_field_length; - unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + uint32_t read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); index += 10; if (read_message_length != 61) @@ -1195,7 +1626,7 @@ int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) } // Check than the message number is correct - unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); + uint32_t read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); index += 12; if (1019 != read_msg_number) @@ -1205,16 +1636,16 @@ int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) } // Fill Gps Ephemeris with message data content - gps_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); + gps_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); index += 6; - gps_eph.i_GPS_week = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + gps_eph.i_GPS_week = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); index += 10; - gps_eph.i_SV_accuracy = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4))); + gps_eph.i_SV_accuracy = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4))); index += 4; - gps_eph.i_code_on_L2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + gps_eph.i_code_on_L2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); index += 2; gps_eph.d_IDOT = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 14))) * I_DOT_LSB; @@ -1287,7 +1718,7 @@ int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) gps_eph.d_TGD = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 8))) * T_GD_LSB; index += 8; - gps_eph.i_SV_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); + gps_eph.i_SV_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); index += 6; gps_eph.b_L2_P_data_flag = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); @@ -1299,40 +1730,305 @@ int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) } +// ******************************************************** +// +// MESSAGE TYPE 1020 (GLONASS EPHEMERIS) +// +// ******************************************************** + +std::string Rtcm::print_MT1020(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + uint32_t msg_number = 1020; + uint32_t glonass_gnav_alm_health = 0; + uint32_t glonass_gnav_alm_health_ind = 0; + uint32_t fifth_str_additional_data_ind = 1; + + Rtcm::set_DF002(msg_number); + Rtcm::set_DF038(glonass_gnav_eph); + Rtcm::set_DF040(glonass_gnav_eph); + Rtcm::set_DF104(glonass_gnav_alm_health); + Rtcm::set_DF105(glonass_gnav_alm_health_ind); + Rtcm::set_DF106(glonass_gnav_eph); + Rtcm::set_DF107(glonass_gnav_eph); + Rtcm::set_DF108(glonass_gnav_eph); + Rtcm::set_DF109(glonass_gnav_eph); + Rtcm::set_DF110(glonass_gnav_eph); + Rtcm::set_DF111(glonass_gnav_eph); + Rtcm::set_DF112(glonass_gnav_eph); + Rtcm::set_DF113(glonass_gnav_eph); + Rtcm::set_DF114(glonass_gnav_eph); + Rtcm::set_DF115(glonass_gnav_eph); + Rtcm::set_DF116(glonass_gnav_eph); + Rtcm::set_DF117(glonass_gnav_eph); + Rtcm::set_DF118(glonass_gnav_eph); + Rtcm::set_DF119(glonass_gnav_eph); + Rtcm::set_DF120(glonass_gnav_eph); + Rtcm::set_DF121(glonass_gnav_eph); + Rtcm::set_DF122(glonass_gnav_eph); + Rtcm::set_DF123(glonass_gnav_eph); + Rtcm::set_DF124(glonass_gnav_eph); + Rtcm::set_DF125(glonass_gnav_eph); + Rtcm::set_DF126(glonass_gnav_eph); + Rtcm::set_DF127(glonass_gnav_eph); + Rtcm::set_DF128(glonass_gnav_eph); + Rtcm::set_DF129(glonass_gnav_eph); + Rtcm::set_DF130(glonass_gnav_eph); + Rtcm::set_DF131(fifth_str_additional_data_ind); + Rtcm::set_DF132(glonass_gnav_utc_model); + Rtcm::set_DF133(glonass_gnav_utc_model); + Rtcm::set_DF134(glonass_gnav_utc_model); + Rtcm::set_DF135(glonass_gnav_utc_model); + Rtcm::set_DF136(glonass_gnav_eph); + + std::string data; + data.clear(); + data = DF002.to_string() + + DF038.to_string() + + DF040.to_string() + + DF104.to_string() + + DF105.to_string() + + DF106.to_string() + + DF107.to_string() + + DF108.to_string() + + DF109.to_string() + + DF110.to_string() + + DF111.to_string() + + DF112.to_string() + + DF113.to_string() + + DF114.to_string() + + DF115.to_string() + + DF116.to_string() + + DF117.to_string() + + DF118.to_string() + + DF119.to_string() + + DF120.to_string() + + DF121.to_string() + + DF122.to_string() + + DF123.to_string() + + DF124.to_string() + + DF125.to_string() + + DF126.to_string() + + DF127.to_string() + + DF128.to_string() + + DF129.to_string() + + DF130.to_string() + + DF131.to_string() + + DF132.to_string() + + DF133.to_string() + + DF134.to_string() + + DF135.to_string() + + DF136.to_string() + + std::bitset<7>().to_string(); // Reserved bits + + if (data.length() != 360) + { + LOG(WARNING) << "Bad-formatted RTCM MT1020 (360 bits expected, found " << data.length() << ")"; + } + + std::string msg = build_message(data); + if (server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +int32_t Rtcm::read_MT1020(const std::string& message, Glonass_Gnav_Ephemeris& glonass_gnav_eph, Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + // Convert message to binary + std::string message_bin = Rtcm::binary_data_to_bin(message); + int32_t glonass_gnav_alm_health = 0; + int32_t glonass_gnav_alm_health_ind = 0; + int32_t fifth_str_additional_data_ind = 0; + + if (!Rtcm::check_CRC(message)) + { + LOG(WARNING) << " Bad CRC detected in RTCM message MT1020"; + return 1; + } + + uint32_t preamble_length = 8; + uint32_t reserved_field_length = 6; + uint32_t index = preamble_length + reserved_field_length; + + uint32_t read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + index += 10; + + if (read_message_length != 45) // 360 bits = 45 bytes + { + LOG(WARNING) << " Message MT1020 seems too long (61 bytes expected, " << read_message_length << " received)"; + return 1; + } + + // Check than the message number is correct + uint32_t read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); + index += 12; + + if (1020 != read_msg_number) + { + LOG(WARNING) << " This is not a MT1020 message"; + return 1; + } + + // Fill Gps Ephemeris with message data content + glonass_gnav_eph.i_satellite_slot_number = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); + index += 6; + + glonass_gnav_eph.i_satellite_freq_channel = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5)) - 7.0); + index += 5; + + glonass_gnav_alm_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + if (glonass_gnav_alm_health) + { + } //Avoid comiler warning + + glonass_gnav_alm_health_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + if (glonass_gnav_alm_health_ind) + { + } //Avoid comiler warning + + glonass_gnav_eph.d_P_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + glonass_gnav_eph.d_P_1 = (glonass_gnav_eph.d_P_1 + 1) * 15; + index += 2; + + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 5))) * 3600; + index += 5; + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 6))) * 60; + index += 6; + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 1))) * 30; + index += 1; + + glonass_gnav_eph.d_B_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_P_2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_t_b = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 7))) * 15 * 60.0; + index += 7; + + // TODO Check for type spec for intS24 + glonass_gnav_eph.d_VXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24))) * TWO_N20; + index += 24; + + glonass_gnav_eph.d_Xn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27))) * TWO_N11; + index += 27; + + glonass_gnav_eph.d_AXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5))) * TWO_N30; + index += 5; + + glonass_gnav_eph.d_VYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24))) * TWO_N20; + index += 24; + + glonass_gnav_eph.d_Yn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27))) * TWO_N11; + index += 27; + + glonass_gnav_eph.d_AYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5))) * TWO_N30; + index += 5; + + glonass_gnav_eph.d_VZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24))) * TWO_N20; + index += 24; + + glonass_gnav_eph.d_Zn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27))) * TWO_N11; + index += 27; + + glonass_gnav_eph.d_AZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5))) * TWO_N30; + index += 5; + + glonass_gnav_eph.d_P_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_gamma_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 11))) * TWO_N30; + index += 11; + + glonass_gnav_eph.d_P = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + index += 2; + + glonass_gnav_eph.d_l3rd_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22))) * TWO_N30; + index += 22; + + glonass_gnav_eph.d_Delta_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5))) * TWO_N30; + index += 5; + + glonass_gnav_eph.d_E_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5))); + index += 5; + + glonass_gnav_eph.d_P_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_F_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4))); + index += 4; + + glonass_gnav_eph.d_N_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11))); + index += 11; + + glonass_gnav_eph.d_M = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + index += 2; + + fifth_str_additional_data_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + if (fifth_str_additional_data_ind == true) + { + glonass_gnav_utc_model.d_N_A = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11))); + index += 11; + + glonass_gnav_utc_model.d_tau_c = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 32))) * TWO_N31; + index += 32; + + glonass_gnav_utc_model.d_N_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5))); + index += 5; + + glonass_gnav_utc_model.d_tau_gps = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22))) * TWO_N30; + index += 22; + + glonass_gnav_eph.d_l5th_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + } + + return 0; +} + + // ******************************************************** // // MESSAGE TYPE 1029 (UNICODE TEXT STRING) // // ******************************************************** -std::string Rtcm::print_MT1029(unsigned int ref_id, const Gps_Ephemeris & gps_eph, double obs_time, const std::string & message) +std::string Rtcm::print_MT1029(uint32_t ref_id, const Gps_Ephemeris& gps_eph, double obs_time, const std::string& message) { - unsigned int msg_number = 1029; + uint32_t msg_number = 1029; Rtcm::set_DF002(msg_number); Rtcm::set_DF003(ref_id); Rtcm::set_DF051(gps_eph, obs_time); Rtcm::set_DF052(gps_eph, obs_time); - unsigned int i = 0; + uint32_t i = 0; bool first = true; std::string text_binary; - for(auto it = message.begin(); it != message.end(); it++) + for (auto it = message.cbegin(); it != message.cend(); it++) { char c = *it; - if(isgraph(c)) + if (isgraph(c)) { i++; first = true; } - else if(c == ' ') + else if (c == ' ') { i++; first = true; } else { - if(!first) + if (!first) { i++; first = true; @@ -1350,15 +2046,15 @@ std::string Rtcm::print_MT1029(unsigned int ref_id, const Gps_Ephemeris & gps_ep std::bitset<8> DF139_ = std::bitset<8>(message.length()); std::string data = DF002.to_string() + - DF003.to_string() + - DF051.to_string() + - DF052.to_string() + - DF138_.to_string() + - DF139_.to_string() + - text_binary; + DF003.to_string() + + DF051.to_string() + + DF052.to_string() + + DF138_.to_string() + + DF139_.to_string() + + text_binary; std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -1372,9 +2068,9 @@ std::string Rtcm::print_MT1029(unsigned int ref_id, const Gps_Ephemeris & gps_ep // // ******************************************************** -std::string Rtcm::print_MT1045(const Galileo_Ephemeris & gal_eph) +std::string Rtcm::print_MT1045(const Galileo_Ephemeris& gal_eph) { - unsigned int msg_number = 1045; + uint32_t msg_number = 1045; Rtcm::set_DF002(msg_number); Rtcm::set_DF252(gal_eph); @@ -1403,48 +2099,48 @@ std::string Rtcm::print_MT1045(const Galileo_Ephemeris & gal_eph) Rtcm::set_DF312(gal_eph); Rtcm::set_DF314(gal_eph); Rtcm::set_DF315(gal_eph); - unsigned int seven_zero = 0; + uint32_t seven_zero = 0; std::bitset<7> DF001_ = std::bitset<7>(seven_zero); std::string data; data.clear(); data = DF002.to_string() + - DF252.to_string() + - DF289.to_string() + - DF290.to_string() + - DF291.to_string() + - DF292.to_string() + - DF293.to_string() + - DF294.to_string() + - DF295.to_string() + - DF296.to_string() + - DF297.to_string() + - DF298.to_string() + - DF299.to_string() + - DF300.to_string() + - DF301.to_string() + - DF302.to_string() + - DF303.to_string() + - DF304.to_string() + - DF305.to_string() + - DF306.to_string() + - DF307.to_string() + - DF308.to_string() + - DF309.to_string() + - DF310.to_string() + - DF311.to_string() + - DF312.to_string() + - DF314.to_string() + - DF315.to_string() + - DF001_.to_string(); + DF252.to_string() + + DF289.to_string() + + DF290.to_string() + + DF291.to_string() + + DF292.to_string() + + DF293.to_string() + + DF294.to_string() + + DF295.to_string() + + DF296.to_string() + + DF297.to_string() + + DF298.to_string() + + DF299.to_string() + + DF300.to_string() + + DF301.to_string() + + DF302.to_string() + + DF303.to_string() + + DF304.to_string() + + DF305.to_string() + + DF306.to_string() + + DF307.to_string() + + DF308.to_string() + + DF309.to_string() + + DF310.to_string() + + DF311.to_string() + + DF312.to_string() + + DF314.to_string() + + DF315.to_string() + + DF001_.to_string(); if (data.length() != 496) { - LOG(WARNING) << "Bad-formatted RTCM MT1045 (496 bits expected, found " << data.length() << ")"; + LOG(WARNING) << "Bad-formatted RTCM MT1045 (496 bits expected, found " << data.length() << ")"; } std::string msg = build_message(data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(msg); } @@ -1452,22 +2148,22 @@ std::string Rtcm::print_MT1045(const Galileo_Ephemeris & gal_eph) } -int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) +int32_t Rtcm::read_MT1045(const std::string& message, Galileo_Ephemeris& gal_eph) { // Convert message to binary std::string message_bin = Rtcm::binary_data_to_bin(message); - if(!Rtcm::check_CRC(message) ) + if (!Rtcm::check_CRC(message)) { LOG(WARNING) << " Bad CRC detected in RTCM message MT1045"; return 1; } - unsigned int preamble_length = 8; - unsigned int reserved_field_length = 6; - unsigned int index = preamble_length + reserved_field_length; + uint32_t preamble_length = 8; + uint32_t reserved_field_length = 6; + uint32_t index = preamble_length + reserved_field_length; - unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + uint32_t read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); index += 10; if (read_message_length != 62) @@ -1477,7 +2173,7 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) } // Check than the message number is correct - unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); + uint32_t read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); index += 12; if (1045 != read_msg_number) @@ -1487,16 +2183,16 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) } // Fill Galileo Ephemeris with message data content - gal_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); + gal_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); index += 6; gal_eph.WN_5 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 12))); index += 12; - gal_eph.IOD_nav_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + gal_eph.IOD_nav_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); index += 10; - gal_eph.SISA_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 8))); + gal_eph.SISA_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 8))); index += 8; gal_eph.iDot_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 14))) * iDot_2_LSB; @@ -1544,7 +2240,7 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) gal_eph.OMEGA_0_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * OMEGA_0_2_LSB; index += 32; - gal_eph.C_is_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_is_4_LSB; + gal_eph.C_is_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_is_4_LSB; index += 16; gal_eph.i_0_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * i_0_2_LSB; @@ -1562,7 +2258,7 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) gal_eph.BGD_E1E5a_5 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 10))); index += 10; - gal_eph.E5a_HS = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + gal_eph.E5a_HS = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); index += 2; gal_eph.E5a_DVS = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); @@ -1571,49 +2267,49 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) } - - // ********************************************************************************************** // // MESSAGE TYPE MSM1 (COMPACT observables) // // ********************************************************************************************** -std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_1(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1071; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1071; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1091; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1071; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1071; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1081; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1091; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1071; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables); @@ -1621,7 +2317,7 @@ std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph, std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -1630,21 +2326,24 @@ std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_header(unsigned int msg_number, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::get_MSM_header(uint32_t msg_number, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { + // Find first element in observables block and define type of message + std::map::const_iterator observables_iter = observables.begin(); + std::string sys(observables_iter->second.System, 1); + Rtcm::set_DF002(msg_number); Rtcm::set_DF003(ref_id); - Rtcm::set_DF004(obs_time); Rtcm::set_DF393(more_messages); - Rtcm::set_DF409(0); // Issue of Data Station. 0: not utilized + Rtcm::set_DF409(0); // Issue of Data Station. 0: not utilized std::bitset<7> DF001_ = std::bitset<7>("0000000"); Rtcm::set_DF411(clock_steering_indicator); Rtcm::set_DF412(external_clock_indicator); @@ -1655,52 +2354,65 @@ std::string Rtcm::get_MSM_header(unsigned int msg_number, Rtcm::set_DF395(observables); std::string header = DF002.to_string() + DF003.to_string(); - header += DF004.to_string(); + // GNSS Epoch Time Specific to each constellation + if ((sys == "R")) + { + // GLONASS Epoch Time + Rtcm::set_DF034(obs_time); + header += DF034.to_string(); + } + else + { + // GPS, Galileo Epoch Time + Rtcm::set_DF004(obs_time); + header += DF004.to_string(); + } + header = header + DF393.to_string() + - DF409.to_string() + - DF001_.to_string() + - DF411.to_string() + - DF417.to_string() + - DF412.to_string() + - DF418.to_string() + - DF394.to_string() + - DF395.to_string() + - Rtcm::set_DF396(observables); + DF409.to_string() + + DF001_.to_string() + + DF411.to_string() + + DF417.to_string() + + DF412.to_string() + + DF418.to_string() + + DF394.to_string() + + DF395.to_string() + + Rtcm::set_DF396(observables); return header; } -std::string Rtcm::get_MSM_1_content_sat_data(const std::map & observables) +std::string Rtcm::get_MSM_1_content_sat_data(const std::map& observables) { std::string sat_data; sat_data.clear(); Rtcm::set_DF394(observables); - unsigned int num_satellites = DF394.count(); + uint32_t num_satellites = DF394.count(); - std::vector > observables_vector; - std::map::const_iterator gnss_synchro_iter; - std::vector pos; - std::vector::iterator it; + std::vector > observables_vector; + std::map::const_iterator gnss_synchro_iter; + std::vector pos; + std::vector::iterator it; - for(gnss_synchro_iter = observables.begin(); - gnss_synchro_iter != observables.end(); - gnss_synchro_iter++) + for (gnss_synchro_iter = observables.cbegin(); + gnss_synchro_iter != observables.cend(); + gnss_synchro_iter++) { it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN); - if(it == pos.end()) + if (it == pos.end()) { pos.push_back(65 - gnss_synchro_iter->second.PRN); observables_vector.push_back(*gnss_synchro_iter); } } - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); - for(unsigned int nsat = 0; nsat < num_satellites; nsat++) + for (uint32_t nsat = 0; nsat < num_satellites; nsat++) { - Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second ); + Rtcm::set_DF398(ordered_by_PRN_pos.at(nsat).second); sat_data += DF398.to_string(); } @@ -1708,31 +2420,31 @@ std::string Rtcm::get_MSM_1_content_sat_data(const std::map & } -std::string Rtcm::get_MSM_1_content_signal_data(const std::map & observables) +std::string Rtcm::get_MSM_1_content_signal_data(const std::map& observables) { std::string signal_data; signal_data.clear(); - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) - { - Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); - signal_data += DF400.to_string(); - } + for (uint32_t cell = 0; cell < Ncells; cell++) + { + Rtcm::set_DF400(ordered_by_PRN_pos.at(cell).second); + signal_data += DF400.to_string(); + } return signal_data; } @@ -1744,48 +2456,50 @@ std::string Rtcm::get_MSM_1_content_signal_data(const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_2(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1072; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1072; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1092; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1072; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1072; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1082; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1092; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1072; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_2_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_2_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -1794,34 +2508,39 @@ std::string Rtcm::print_MSM_2( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; std::string second_data_type; std::string third_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF401(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); first_data_type += DF401.to_string(); second_data_type += DF402.to_string(); third_data_type += DF420.to_string(); @@ -1832,55 +2551,56 @@ std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, co } - // ********************************************************************************************** // // MESSAGE TYPE MSM3 (COMPACT PSEUDORANGES AND PHASERANGES) // // ********************************************************************************************** -std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_3(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1073; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1073; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1093; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1073; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1073; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1083; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1093; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1073; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_3_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_3_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -1889,7 +2609,12 @@ std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; @@ -1897,28 +2622,28 @@ std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string third_data_type; std::string fourth_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF400(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF401(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); first_data_type += DF400.to_string(); second_data_type += DF401.to_string(); third_data_type += DF402.to_string(); @@ -1936,48 +2661,50 @@ std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, co // // ********************************************************************************************** -std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_4(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1074; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1074; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1094; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1074; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1074; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1084; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1094; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1074; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_4_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_4_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -1986,38 +2713,38 @@ std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_4_content_sat_data(const std::map & observables) +std::string Rtcm::get_MSM_4_content_sat_data(const std::map& observables) { std::string sat_data; std::string first_data_type; std::string second_data_type; Rtcm::set_DF394(observables); - unsigned int num_satellites = DF394.count(); + uint32_t num_satellites = DF394.count(); - std::vector > observables_vector; - std::map::const_iterator gnss_synchro_iter; - std::vector pos; - std::vector::iterator it; + std::vector > observables_vector; + std::map::const_iterator gnss_synchro_iter; + std::vector pos; + std::vector::iterator it; - for(gnss_synchro_iter = observables.begin(); - gnss_synchro_iter != observables.end(); - gnss_synchro_iter++) + for (gnss_synchro_iter = observables.cbegin(); + gnss_synchro_iter != observables.cend(); + gnss_synchro_iter++) { it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN); - if(it == pos.end()) + if (it == pos.end()) { pos.push_back(65 - gnss_synchro_iter->second.PRN); observables_vector.push_back(*gnss_synchro_iter); } } - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); - for(unsigned int nsat = 0; nsat < num_satellites; nsat++) + for (uint32_t nsat = 0; nsat < num_satellites; nsat++) { - Rtcm::set_DF397( ordered_by_PRN_pos.at(nsat).second ); - Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second ); + Rtcm::set_DF397(ordered_by_PRN_pos.at(nsat).second); + Rtcm::set_DF398(ordered_by_PRN_pos.at(nsat).second); first_data_type += DF397.to_string(); second_data_type += DF398.to_string(); } @@ -2026,7 +2753,12 @@ std::string Rtcm::get_MSM_4_content_sat_data(const std::map & } -std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; @@ -2035,29 +2767,29 @@ std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string fourth_data_type; std::string fifth_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF400(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF401(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF403(ordered_by_PRN_pos.at(cell).second); first_data_type += DF400.to_string(); second_data_type += DF401.to_string(); third_data_type += DF402.to_string(); @@ -2076,48 +2808,50 @@ std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, co // // ********************************************************************************************** -std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_5(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1075; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1075; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1095; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1075; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1075; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1085; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1095; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1075; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_5_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_5_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -2126,7 +2860,7 @@ std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_5_content_sat_data(const std::map & observables) +std::string Rtcm::get_MSM_5_content_sat_data(const std::map& observables) { std::string sat_data; std::string first_data_type; @@ -2135,32 +2869,32 @@ std::string Rtcm::get_MSM_5_content_sat_data(const std::map & std::string fourth_data_type; Rtcm::set_DF394(observables); - unsigned int num_satellites = DF394.count(); + uint32_t num_satellites = DF394.count(); - std::vector > observables_vector; - std::map::const_iterator gnss_synchro_iter; - std::vector pos; - std::vector::iterator it; + std::vector > observables_vector; + std::map::const_iterator gnss_synchro_iter; + std::vector pos; + std::vector::iterator it; - for(gnss_synchro_iter = observables.begin(); - gnss_synchro_iter != observables.end(); - gnss_synchro_iter++) + for (gnss_synchro_iter = observables.cbegin(); + gnss_synchro_iter != observables.cend(); + gnss_synchro_iter++) { it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN); - if(it == pos.end()) + if (it == pos.end()) { pos.push_back(65 - gnss_synchro_iter->second.PRN); observables_vector.push_back(*gnss_synchro_iter); } } - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector); - for(unsigned int nsat = 0; nsat < num_satellites; nsat++) + for (uint32_t nsat = 0; nsat < num_satellites; nsat++) { - Rtcm::set_DF397( ordered_by_PRN_pos.at(nsat).second ); - Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second ); - Rtcm::set_DF399( ordered_by_PRN_pos.at(nsat).second ); + Rtcm::set_DF397(ordered_by_PRN_pos.at(nsat).second); + Rtcm::set_DF398(ordered_by_PRN_pos.at(nsat).second); + Rtcm::set_DF399(ordered_by_PRN_pos.at(nsat).second); std::bitset<4> reserved = std::bitset<4>("0000"); first_data_type += DF397.to_string(); second_data_type += reserved.to_string(); @@ -2172,7 +2906,12 @@ std::string Rtcm::get_MSM_5_content_sat_data(const std::map & } -std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; @@ -2182,30 +2921,30 @@ std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string fifth_data_type; std::string sixth_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF404(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF400(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF401(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF403(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF404(ordered_by_PRN_pos.at(cell).second); first_data_type += DF400.to_string(); second_data_type += DF401.to_string(); third_data_type += DF402.to_string(); @@ -2219,55 +2958,56 @@ std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, co } - // ********************************************************************************************** // // MESSAGE TYPE MSM6 (FULL PSEUDORANGES AND PHASERANGES PLUS CNR, HIGH RESOLUTION) // // ********************************************************************************************** -std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_6(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1076; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1076; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1096; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1076; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1076; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1086; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1096; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1076; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_6_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_6_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -2276,7 +3016,12 @@ std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; @@ -2285,29 +3030,29 @@ std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string fourth_data_type; std::string fifth_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF405(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF406(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF408(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF405(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF406(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF408(ordered_by_PRN_pos.at(cell).second); first_data_type += DF405.to_string(); second_data_type += DF406.to_string(); third_data_type += DF407.to_string(); @@ -2320,55 +3065,56 @@ std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, co } - // ********************************************************************************************** // // MESSAGE TYPE MSM7 (FULL PSEUDORANGES, PHASERANGES, PHASERANGERATE AND CNR, HIGH RESOLUTION) // // ********************************************************************************************** -std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages) +std::string Rtcm::print_MSM_7(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages) { - unsigned int msg_number = 0; - if(gps_eph.i_satellite_PRN != 0) msg_number = 1077; - if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1077; - if(gal_eph.i_satellite_PRN != 0) msg_number = 1097; - if(((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + uint32_t msg_number = 0; + if (gps_eph.i_satellite_PRN != 0) msg_number = 1077; + if (gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1077; + if (glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1087; + if (gal_eph.i_satellite_PRN != 0) msg_number = 1097; + if (((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0)) && (glo_gnav_eph.i_satellite_PRN != 0) && (gal_eph.i_satellite_PRN != 0)) { - LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? + LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } - if(msg_number == 0) + if (msg_number == 0) { LOG(WARNING) << "Invalid ephemeris provided"; msg_number = 1076; } std::string header = Rtcm::get_MSM_header(msg_number, - obs_time, - observables, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + obs_time, + observables, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_7_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_7_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); - if(server_is_running) + if (server_is_running) { rtcm_message_queue->push(message); } @@ -2377,7 +3123,12 @@ std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris& ephNAV, + const Gps_CNAV_Ephemeris& ephCNAV, + const Galileo_Ephemeris& ephFNAV, + const Glonass_Gnav_Ephemeris& ephGNAV, + double obs_time, + const std::map& observables) { std::string signal_data; std::string first_data_type; @@ -2387,30 +3138,30 @@ std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string fifth_data_type; std::string sixth_data_type; - unsigned int Ncells = observables.size(); + uint32_t Ncells = observables.size(); - std::vector > observables_vector; - std::map::const_iterator map_iter; + std::vector > observables_vector; + std::map::const_iterator map_iter; - for(map_iter = observables.begin(); - map_iter != observables.end(); - map_iter++) + for (map_iter = observables.cbegin(); + map_iter != observables.cend(); + map_iter++) { observables_vector.push_back(*map_iter); } - std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); + std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector); std::reverse(ordered_by_signal.begin(), ordered_by_signal.end()); - std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); + std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal); - for(unsigned int cell = 0; cell < Ncells ; cell++) + for (uint32_t cell = 0; cell < Ncells; cell++) { - Rtcm::set_DF405(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF406(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF408(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF404(ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF405(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF406(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF420(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF408(ordered_by_PRN_pos.at(cell).second); + Rtcm::set_DF404(ordered_by_PRN_pos.at(cell).second); first_data_type += DF405.to_string(); second_data_type += DF406.to_string(); third_data_type += DF407.to_string(); @@ -2424,30 +3175,30 @@ std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, co } - // ***************************************************************************************************** // Some utilities // ***************************************************************************************************** -std::vector > Rtcm::sort_by_PRN_mask(const std::vector > & synchro_map) const +std::vector > Rtcm::sort_by_PRN_mask(const std::vector >& synchro_map) const { - std::vector >::const_iterator synchro_map_iter; - std::vector > my_vec; - struct { - bool operator()(const std::pair & a, const std::pair & b) + std::vector >::const_iterator synchro_map_iter; + std::vector > my_vec; + struct + { + bool operator()(const std::pair& a, const std::pair& b) { - unsigned int value_a = 64 - a.second.PRN; - unsigned int value_b = 64 - b.second.PRN; + uint32_t value_a = 64 - a.second.PRN; + uint32_t value_b = 64 - b.second.PRN; return value_a < value_b; } } has_lower_pos; - for(synchro_map_iter = synchro_map.begin(); - synchro_map_iter != synchro_map.end(); - synchro_map_iter++) + for (synchro_map_iter = synchro_map.cbegin(); + synchro_map_iter != synchro_map.cend(); + synchro_map_iter++) { - std::pair p(synchro_map_iter->first, synchro_map_iter->second); + std::pair p(synchro_map_iter->first, synchro_map_iter->second); my_vec.push_back(p); } @@ -2457,39 +3208,40 @@ std::vector > Rtcm::sort_by_PRN_mask(const std::vec } -std::vector > Rtcm::sort_by_signal(const std::vector > & synchro_map) const +std::vector > Rtcm::sort_by_signal(const std::vector >& synchro_map) const { - std::vector >::const_iterator synchro_map_iter; - std::vector > my_vec; + std::vector >::const_iterator synchro_map_iter; + std::vector > my_vec; - struct { - bool operator()(const std::pair & a, const std::pair & b) + struct + { + bool operator()(const std::pair& a, const std::pair& b) { - unsigned int value_a = 0; - unsigned int value_b = 0; + uint32_t value_a = 0; + uint32_t value_b = 0; std::string system_a(&a.second.System, 1); std::string system_b(&b.second.System, 1); std::string sig_a_(a.second.Signal); - std::string sig_a = sig_a_.substr(0,2); + std::string sig_a = sig_a_.substr(0, 2); std::string sig_b_(b.second.Signal); - std::string sig_b = sig_b_.substr(0,2); + std::string sig_b = sig_b_.substr(0, 2); - if(system_a.compare("G") == 0) + if (system_a == "G") { value_a = gps_signal_map.at(sig_a); } - if(system_a.compare("E") == 0) + if (system_a == "E") { value_a = galileo_signal_map.at(sig_a); } - if(system_b.compare("G") == 0) + if (system_b == "G") { value_b = gps_signal_map.at(sig_b); } - if(system_b.compare("E") == 0) + if (system_b == "E") { value_b = galileo_signal_map.at(sig_b); } @@ -2499,12 +3251,12 @@ std::vector > Rtcm::sort_by_signal(const std::vecto } has_lower_signalID; - for(synchro_map_iter = synchro_map.begin(); - synchro_map_iter != synchro_map.end(); - synchro_map_iter++) + for (synchro_map_iter = synchro_map.cbegin(); + synchro_map_iter != synchro_map.cend(); + synchro_map_iter++) { - std::pair p(synchro_map_iter->first, synchro_map_iter->second); + std::pair p(synchro_map_iter->first, synchro_map_iter->second); my_vec.push_back(p); } @@ -2513,8 +3265,7 @@ std::vector > Rtcm::sort_by_signal(const std::vecto } -std::map Rtcm::gps_signal_map = [] -{ +std::map Rtcm::gps_signal_map = [] { std::map gps_signal_map_; // Table 3.5-91 gps_signal_map_["1C"] = 2; @@ -2533,8 +3284,7 @@ std::map Rtcm::gps_signal_map = [] }(); -std::map Rtcm::galileo_signal_map = [] -{ +std::map Rtcm::galileo_signal_map = [] { std::map galileo_signal_map_; // Table 3.5-100 galileo_signal_map_["1C"] = 2; @@ -2560,145 +3310,196 @@ std::map Rtcm::galileo_signal_map = [] }(); -boost::posix_time::ptime Rtcm::compute_GPS_time(const Gps_Ephemeris & eph, double obs_time) const +boost::posix_time::ptime Rtcm::compute_GPS_time(const Gps_Ephemeris& eph, double obs_time) const { const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } -boost::posix_time::ptime Rtcm::compute_GPS_time(const Gps_CNAV_Ephemeris & eph, double obs_time) const +boost::posix_time::ptime Rtcm::compute_GPS_time(const Gps_CNAV_Ephemeris& eph, double obs_time) const { const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } -boost::posix_time::ptime Rtcm::compute_Galileo_time(const Galileo_Ephemeris & eph, double obs_time) const +boost::posix_time::ptime Rtcm::compute_Galileo_time(const Galileo_Ephemeris& eph, double obs_time) const { double galileo_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((galileo_t + 604800 * static_cast(eph.WN_5)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((galileo_t + 604800 * static_cast(eph.WN_5)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); return p_time; } -unsigned int Rtcm::lock_time(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +boost::posix_time::ptime Rtcm::compute_GLONASS_time(const Glonass_Gnav_Ephemeris& eph, double obs_time) const { - unsigned int lock_time_in_seconds; + boost::posix_time::ptime p_time = eph.compute_GLONASS_time(obs_time); + return p_time; +} + + +uint32_t Rtcm::lock_time(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + uint32_t lock_time_in_seconds; boost::posix_time::ptime current_time = Rtcm::compute_GPS_time(eph, obs_time); boost::posix_time::ptime last_lock_time = Rtcm::gps_L1_last_lock_time[65 - gnss_synchro.PRN]; - if(last_lock_time.is_not_a_date_time() )// || CHECK LLI!!......) + if (last_lock_time.is_not_a_date_time()) // || CHECK LLI!!......) { Rtcm::gps_L1_last_lock_time[65 - gnss_synchro.PRN] = current_time; } boost::posix_time::time_duration lock_duration = current_time - Rtcm::gps_L1_last_lock_time[65 - gnss_synchro.PRN]; - lock_time_in_seconds = static_cast(lock_duration.total_seconds()); + lock_time_in_seconds = static_cast(lock_duration.total_seconds()); // Debug: // std::cout << "lock time PRN " << gnss_synchro.PRN << ": " << lock_time_in_seconds << " current time: " << current_time << std::endl; return lock_time_in_seconds; } -unsigned int Rtcm::lock_time(const Gps_CNAV_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +uint32_t Rtcm::lock_time(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_in_seconds; + uint32_t lock_time_in_seconds; boost::posix_time::ptime current_time = Rtcm::compute_GPS_time(eph, obs_time); boost::posix_time::ptime last_lock_time = Rtcm::gps_L2_last_lock_time[65 - gnss_synchro.PRN]; - if(last_lock_time.is_not_a_date_time() )// || CHECK LLI!!......) + if (last_lock_time.is_not_a_date_time()) // || CHECK LLI!!......) { Rtcm::gps_L2_last_lock_time[65 - gnss_synchro.PRN] = current_time; } boost::posix_time::time_duration lock_duration = current_time - Rtcm::gps_L2_last_lock_time[65 - gnss_synchro.PRN]; - lock_time_in_seconds = static_cast(lock_duration.total_seconds()); + lock_time_in_seconds = static_cast(lock_duration.total_seconds()); return lock_time_in_seconds; } -unsigned int Rtcm::lock_time(const Galileo_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +uint32_t Rtcm::lock_time(const Galileo_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_in_seconds; + uint32_t lock_time_in_seconds; boost::posix_time::ptime current_time = Rtcm::compute_Galileo_time(eph, obs_time); boost::posix_time::ptime last_lock_time; std::string sig_(gnss_synchro.Signal); - if(sig_.compare("1B") == 0) + if (sig_.compare("1B") == 0) { last_lock_time = Rtcm::gal_E1_last_lock_time[65 - gnss_synchro.PRN]; } - if((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0) ) + if ((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0)) { last_lock_time = Rtcm::gal_E5_last_lock_time[65 - gnss_synchro.PRN]; } - if(last_lock_time.is_not_a_date_time() )// || CHECK LLI!!......) + if (last_lock_time.is_not_a_date_time()) // || CHECK LLI!!......) { - if(sig_.compare("1B") == 0) + if (sig_.compare("1B") == 0) { Rtcm::gal_E1_last_lock_time[65 - gnss_synchro.PRN] = current_time; } - if((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0) ) + if ((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0)) { Rtcm::gal_E5_last_lock_time[65 - gnss_synchro.PRN] = current_time; } } boost::posix_time::time_duration lock_duration = current_time - current_time; - if(sig_.compare("1B") == 0) + if (sig_.compare("1B") == 0) { lock_duration = current_time - Rtcm::gal_E1_last_lock_time[65 - gnss_synchro.PRN]; } - if((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0) ) + if ((sig_.compare("5X") == 0) || (sig_.compare("8X") == 0) || (sig_.compare("7X") == 0)) { lock_duration = current_time - Rtcm::gal_E5_last_lock_time[65 - gnss_synchro.PRN]; } - lock_time_in_seconds = static_cast(lock_duration.total_seconds()); + lock_time_in_seconds = static_cast(lock_duration.total_seconds()); return lock_time_in_seconds; } -unsigned int Rtcm::lock_time_indicator(unsigned int lock_time_period_s) +uint32_t Rtcm::lock_time(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + uint32_t lock_time_in_seconds; + boost::posix_time::ptime current_time = Rtcm::compute_GLONASS_time(eph, obs_time); + + boost::posix_time::ptime last_lock_time; + std::string sig_(gnss_synchro.Signal); + if (sig_.compare("1C") == 0) + { + last_lock_time = Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN]; + } + if (sig_.compare("2C") == 0) + { + last_lock_time = Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN]; + } + + if (last_lock_time.is_not_a_date_time()) // || CHECK LLI!!......) + { + if (sig_.compare("1C") == 0) + { + Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN] = current_time; + } + if (sig_.compare("2C") == 0) + { + Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN] = current_time; + } + } + + boost::posix_time::time_duration lock_duration = current_time - current_time; + if (sig_.compare("1C") == 0) + { + lock_duration = current_time - Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN]; + } + if (sig_.compare("2C") == 0) + { + lock_duration = current_time - Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN]; + } + + lock_time_in_seconds = static_cast(lock_duration.total_seconds()); + return lock_time_in_seconds; +} + + +uint32_t Rtcm::lock_time_indicator(uint32_t lock_time_period_s) { // Table 3.4-2 - if(lock_time_period_s <= 0 ) return 0; - if(lock_time_period_s < 24 ) return lock_time_period_s; - if(lock_time_period_s < 72 ) return (lock_time_period_s + 24 ) / 2; - if(lock_time_period_s < 168) return (lock_time_period_s + 120 ) / 4; - if(lock_time_period_s < 360) return (lock_time_period_s + 408 ) / 8; - if(lock_time_period_s < 744) return (lock_time_period_s + 1176) / 16; - if(lock_time_period_s < 937) return (lock_time_period_s + 3096) / 32; + if (lock_time_period_s <= 0) return 0; + if (lock_time_period_s < 24) return lock_time_period_s; + if (lock_time_period_s < 72) return (lock_time_period_s + 24) / 2; + if (lock_time_period_s < 168) return (lock_time_period_s + 120) / 4; + if (lock_time_period_s < 360) return (lock_time_period_s + 408) / 8; + if (lock_time_period_s < 744) return (lock_time_period_s + 1176) / 16; + if (lock_time_period_s < 937) return (lock_time_period_s + 3096) / 32; return 127; } -unsigned int Rtcm::msm_lock_time_indicator(unsigned int lock_time_period_s) +uint32_t Rtcm::msm_lock_time_indicator(uint32_t lock_time_period_s) { // Table 3.5-74 - if(lock_time_period_s < 32 ) return 0; - if(lock_time_period_s < 64 ) return 1; - if(lock_time_period_s < 128 ) return 2; - if(lock_time_period_s < 256 ) return 3; - if(lock_time_period_s < 512 ) return 4; - if(lock_time_period_s < 1024 ) return 5; - if(lock_time_period_s < 2048 ) return 6; - if(lock_time_period_s < 4096 ) return 7; - if(lock_time_period_s < 8192 ) return 8; - if(lock_time_period_s < 16384 ) return 9; - if(lock_time_period_s < 32768 ) return 10; - if(lock_time_period_s < 65536 ) return 11; - if(lock_time_period_s < 131072) return 12; - if(lock_time_period_s < 262144) return 13; - if(lock_time_period_s < 524288) return 14; + if (lock_time_period_s < 32) return 0; + if (lock_time_period_s < 64) return 1; + if (lock_time_period_s < 128) return 2; + if (lock_time_period_s < 256) return 3; + if (lock_time_period_s < 512) return 4; + if (lock_time_period_s < 1024) return 5; + if (lock_time_period_s < 2048) return 6; + if (lock_time_period_s < 4096) return 7; + if (lock_time_period_s < 8192) return 8; + if (lock_time_period_s < 16384) return 9; + if (lock_time_period_s < 32768) return 10; + if (lock_time_period_s < 65536) return 11; + if (lock_time_period_s < 131072) return 12; + if (lock_time_period_s < 262144) return 13; + if (lock_time_period_s < 524288) return 14; return 15; } -unsigned int Rtcm::msm_extended_lock_time_indicator(unsigned int lock_time_period_s) +// clang-format off +uint32_t Rtcm::msm_extended_lock_time_indicator(uint32_t lock_time_period_s) { // Table 3.5-75 if( lock_time_period_s < 64 ) return ( lock_time_period_s ); @@ -2725,7 +3526,7 @@ unsigned int Rtcm::msm_extended_lock_time_indicator(unsigned int lock_time_perio if( 67108864 <= lock_time_period_s ) return (704 ); return 1023; // will never happen } - +// clang-format on // ***************************************************************************************************** // @@ -2733,7 +3534,7 @@ unsigned int Rtcm::msm_extended_lock_time_indicator(unsigned int lock_time_perio // // ***************************************************************************************************** -int Rtcm::set_DF002(unsigned int message_number) +int32_t Rtcm::set_DF002(uint32_t message_number) { if (message_number > 4095) { @@ -2744,9 +3545,9 @@ int Rtcm::set_DF002(unsigned int message_number) } -int Rtcm::set_DF003(unsigned int ref_station_ID) +int32_t Rtcm::set_DF003(uint32_t ref_station_ID) { - //unsigned int station_ID = ref_station_ID; + //uint32_t station_ID = ref_station_ID; if (ref_station_ID > 4095) { LOG(WARNING) << "RTCM reference station ID must be between 0 and 4095, but it has been set to " << ref_station_ID; @@ -2756,11 +3557,11 @@ int Rtcm::set_DF003(unsigned int ref_station_ID) } -int Rtcm::set_DF004(double obs_time) +int32_t Rtcm::set_DF004(double obs_time) { // TOW in milliseconds from the beginning of the GPS week, measured in GPS time - unsigned long int tow = static_cast(std::round(obs_time * 1000)); - if(tow > 604799999) + auto tow = static_cast(std::round(obs_time * 1000)); + if (tow > 604799999) { LOG(WARNING) << "To large TOW! Set to the last millisecond of the week"; tow = 604799999; @@ -2770,7 +3571,7 @@ int Rtcm::set_DF004(double obs_time) } -int Rtcm::set_DF005(bool sync_flag) +int32_t Rtcm::set_DF005(bool sync_flag) { // 0 - No further GNSS observables referenced to the same Epoch Time will be transmitted. This enables the receiver to begin processing // the data immediately after decoding the message. @@ -2780,14 +3581,14 @@ int Rtcm::set_DF005(bool sync_flag) } -int Rtcm::set_DF006(const std::map & observables) +int32_t Rtcm::set_DF006(const std::map& observables) { //Number of satellites observed in current epoch - unsigned short int nsats = 0; - std::map::const_iterator observables_iter; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + uint16_t nsats = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { nsats++; } @@ -2801,7 +3602,7 @@ int Rtcm::set_DF006(const std::map & observables) } -int Rtcm::set_DF007(bool divergence_free_smoothing_indicator) +int32_t Rtcm::set_DF007(bool divergence_free_smoothing_indicator) { // 0 - Divergence-free smoothing not used 1 - Divergence-free smoothing used DF007 = std::bitset<1>(divergence_free_smoothing_indicator); @@ -2809,128 +3610,128 @@ int Rtcm::set_DF007(bool divergence_free_smoothing_indicator) } -int Rtcm::set_DF008(short int smoothing_interval) +int32_t Rtcm::set_DF008(int16_t smoothing_interval) { DF008 = std::bitset<3>(smoothing_interval); return 0; } -int Rtcm::set_DF009(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF009(const Gnss_Synchro& gnss_synchro) { - unsigned int prn_ = gnss_synchro.PRN; - if(prn_ > 31) + uint32_t prn_ = gnss_synchro.PRN; + if (prn_ > 32) { - LOG(WARNING) << "GPS satellite ID must be between 0 and 31, but PRN " << prn_ << " was found"; + LOG(WARNING) << "GPS satellite ID must be between 1 and 32, but PRN " << prn_ << " was found"; } DF009 = std::bitset<6>(prn_); return 0; } -int Rtcm::set_DF009(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF009(const Gps_Ephemeris& gps_eph) { - unsigned int prn_ = gps_eph.i_satellite_PRN; - if(prn_ > 31) + uint32_t prn_ = gps_eph.i_satellite_PRN; + if (prn_ > 32) { - LOG(WARNING) << "GPS satellite ID must be between 0 and 31, but PRN " << prn_ << " was found"; + LOG(WARNING) << "GPS satellite ID must be between 1 and 32, but PRN " << prn_ << " was found"; } DF009 = std::bitset<6>(prn_); return 0; } -int Rtcm::set_DF010(bool code_indicator) +int32_t Rtcm::set_DF010(bool code_indicator) { DF010 = std::bitset<1>(code_indicator); return 0; } -int Rtcm::set_DF011(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF011(const Gnss_Synchro& gnss_synchro) { - double ambiguity = std::floor( gnss_synchro.Pseudorange_m / 299792.458 ); - unsigned long int gps_L1_pseudorange = static_cast(std::round(( gnss_synchro.Pseudorange_m - ambiguity * 299792.458) / 0.02 )); + double ambiguity = std::floor(gnss_synchro.Pseudorange_m / 299792.458); + auto gps_L1_pseudorange = static_cast(std::round((gnss_synchro.Pseudorange_m - ambiguity * 299792.458) / 0.02)); DF011 = std::bitset<24>(gps_L1_pseudorange); return 0; } -int Rtcm::set_DF012(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF012(const Gnss_Synchro& gnss_synchro) { const double lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; - double ambiguity = std::floor( gnss_synchro.Pseudorange_m / 299792.458 ); - double gps_L1_pseudorange = std::round(( gnss_synchro.Pseudorange_m - ambiguity * 299792.458) / 0.02 ); + double ambiguity = std::floor(gnss_synchro.Pseudorange_m / 299792.458); + double gps_L1_pseudorange = std::round((gnss_synchro.Pseudorange_m - ambiguity * 299792.458) / 0.02); double gps_L1_pseudorange_c = gps_L1_pseudorange * 0.02 + ambiguity * 299792.458; double L1_phaserange_c = gnss_synchro.Carrier_phase_rads / GPS_TWO_PI; double L1_phaserange_c_r = std::fmod(L1_phaserange_c - gps_L1_pseudorange_c / lambda + 1500.0, 3000.0) - 1500.0; - long int gps_L1_phaserange_minus_L1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda / 0.0005 )); + auto gps_L1_phaserange_minus_L1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda / 0.0005)); DF012 = std::bitset<20>(gps_L1_phaserange_minus_L1_pseudorange); return 0; } -int Rtcm::set_DF013(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF013(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_indicator; - unsigned int lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + uint32_t lock_time_indicator; + uint32_t lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); DF013 = std::bitset<7>(lock_time_indicator); return 0; } -int Rtcm::set_DF014(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF014(const Gnss_Synchro& gnss_synchro) { - unsigned int gps_L1_pseudorange_ambiguity = static_cast(std::floor(gnss_synchro.Pseudorange_m / 299792.458)); + auto gps_L1_pseudorange_ambiguity = static_cast(std::floor(gnss_synchro.Pseudorange_m / 299792.458)); DF014 = std::bitset<8>(gps_L1_pseudorange_ambiguity); return 0; } -int Rtcm::set_DF015(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF015(const Gnss_Synchro& gnss_synchro) { double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; if (CN0_dB_Hz_est > 63.75) { CN0_dB_Hz_est = 63.75; } - unsigned int CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25 )); + auto CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25)); DF015 = std::bitset<8>(CN0_dB_Hz); return 0; } -int Rtcm::set_DF017(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +int32_t Rtcm::set_DF017(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) { - double ambiguity = std::floor( gnss_synchroL1.Pseudorange_m / 299792.458 ); - double gps_L1_pseudorange = std::round(( gnss_synchroL1.Pseudorange_m - ambiguity * 299792.458) / 0.02 ); + double ambiguity = std::floor(gnss_synchroL1.Pseudorange_m / 299792.458); + double gps_L1_pseudorange = std::round((gnss_synchroL1.Pseudorange_m - ambiguity * 299792.458) / 0.02); double gps_L1_pseudorange_c = gps_L1_pseudorange * 0.02 + ambiguity * 299792.458; double l2_l1_pseudorange = gnss_synchroL2.Pseudorange_m - gps_L1_pseudorange_c; - int pseudorange_difference = 0xFFFFE000; // invalid value; - if(std::fabs(l2_l1_pseudorange) <= 163.82) + int32_t pseudorange_difference = 0xFFFFE000; // invalid value; + if (std::fabs(l2_l1_pseudorange) <= 163.82) { - pseudorange_difference = static_cast(std::round(l2_l1_pseudorange / 0.02)); + pseudorange_difference = static_cast(std::round(l2_l1_pseudorange / 0.02)); } DF017 = std::bitset<14>(pseudorange_difference); return 0; } -int Rtcm::set_DF018(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +int32_t Rtcm::set_DF018(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) { const double lambda2 = GPS_C_m_s / GPS_L2_FREQ_HZ; - int l2_phaserange_minus_l1_pseudorange = 0xFFF80000; - double ambiguity = std::floor( gnss_synchroL1.Pseudorange_m / 299792.458 ); - double gps_L1_pseudorange = std::round(( gnss_synchroL1.Pseudorange_m - ambiguity * 299792.458) / 0.02 ); + int32_t l2_phaserange_minus_l1_pseudorange = 0xFFF80000; + double ambiguity = std::floor(gnss_synchroL1.Pseudorange_m / 299792.458); + double gps_L1_pseudorange = std::round((gnss_synchroL1.Pseudorange_m - ambiguity * 299792.458) / 0.02); double gps_L1_pseudorange_c = gps_L1_pseudorange * 0.02 + ambiguity * 299792.458; double L2_phaserange_c = gnss_synchroL2.Carrier_phase_rads / GPS_TWO_PI; double L1_phaserange_c_r = std::fmod(L2_phaserange_c - gps_L1_pseudorange_c / lambda2 + 1500.0, 3000.0) - 1500.0; - if (std::fabs(L1_phaserange_c_r * lambda2) <= 262.1435 ) + if (std::fabs(L1_phaserange_c_r * lambda2) <= 262.1435) { - l2_phaserange_minus_l1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda2 / 0.0005)); + l2_phaserange_minus_l1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda2 / 0.0005)); } DF018 = std::bitset<20>(l2_phaserange_minus_l1_pseudorange); @@ -2938,370 +3739,905 @@ int Rtcm::set_DF018(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gn } -int Rtcm::set_DF019(const Gps_CNAV_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF019(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_indicator; - unsigned int lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + uint32_t lock_time_indicator; + uint32_t lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); DF019 = std::bitset<7>(lock_time_indicator); return 0; } -int Rtcm::set_DF020(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF020(const Gnss_Synchro& gnss_synchro) { double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; if (CN0_dB_Hz_est > 63.75) { CN0_dB_Hz_est = 63.75; } - unsigned int CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25 )); + auto CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25)); DF020 = std::bitset<8>(CN0_dB_Hz); return 0; } -int Rtcm::set_DF021() +int32_t Rtcm::set_DF021() { - unsigned short int itfr_year = 0; + uint16_t itfr_year = 0; DF021 = std::bitset<6>(itfr_year); return 0; } -int Rtcm::set_DF022(bool gps_indicator) +int32_t Rtcm::set_DF022(bool gps_indicator) { DF022 = std::bitset<1>(gps_indicator); return 0; } -int Rtcm::set_DF023(bool glonass_indicator) +int32_t Rtcm::set_DF023(bool glonass_indicator) { DF023 = std::bitset<1>(glonass_indicator); return 0; } -int Rtcm::set_DF024(bool galileo_indicator) +int32_t Rtcm::set_DF024(bool galileo_indicator) { DF024 = std::bitset<1>(galileo_indicator); return 0; } -int Rtcm::set_DF025(double antenna_ECEF_X_m) +int32_t Rtcm::set_DF025(double antenna_ECEF_X_m) { - long long int ant_ref_x = static_cast(std::round( antenna_ECEF_X_m * 10000)); + auto ant_ref_x = static_cast(std::round(antenna_ECEF_X_m * 10000)); DF025 = std::bitset<38>(ant_ref_x); return 0; } -int Rtcm::set_DF026(double antenna_ECEF_Y_m) +int32_t Rtcm::set_DF026(double antenna_ECEF_Y_m) { - long long int ant_ref_y = static_cast(std::round( antenna_ECEF_Y_m * 10000)); + auto ant_ref_y = static_cast(std::round(antenna_ECEF_Y_m * 10000)); DF026 = std::bitset<38>(ant_ref_y); return 0; } -int Rtcm::set_DF027(double antenna_ECEF_Z_m) +int32_t Rtcm::set_DF027(double antenna_ECEF_Z_m) { - long long int ant_ref_z = static_cast(std::round( antenna_ECEF_Z_m * 10000)); + auto ant_ref_z = static_cast(std::round(antenna_ECEF_Z_m * 10000)); DF027 = std::bitset<38>(ant_ref_z); return 0; } -int Rtcm::set_DF028(double height) +int32_t Rtcm::set_DF028(double height) { - unsigned int h_ = static_cast(std::round( height * 10000)); + auto h_ = static_cast(std::round(height * 10000)); DF028 = std::bitset<16>(h_); return 0; } -int Rtcm::set_DF031(unsigned int antenna_setup_id) +int32_t Rtcm::set_DF031(uint32_t antenna_setup_id) { DF031 = std::bitset<8>(antenna_setup_id); return 0; } -int Rtcm::set_DF051(const Gps_Ephemeris & gps_eph, double obs_time) +int32_t Rtcm::set_DF034(double obs_time) +{ + // TOW in milliseconds from the beginning of the GLONASS day, measured in GLONASS time + auto tk = static_cast(std::round(obs_time * 1000)); + if (tk > 86400999) + { + LOG(WARNING) << "To large GLONASS Epoch Time (tk)! Set to the last millisecond of the day"; + tk = 86400999; + } + DF034 = std::bitset<27>(tk); + return 0; +} + + +int32_t Rtcm::set_DF035(const std::map& observables) +{ + //Number of satellites observed in current epoch + uint16_t nsats = 0; + std::map::const_iterator observables_iter; + for (observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + nsats++; + } + if (nsats > 31) + { + LOG(WARNING) << "The number of processed GLONASS satellites must be between 0 and 31, but it seems that you are processing " << nsats; + nsats = 31; + } + DF035 = std::bitset<5>(nsats); + return 0; +} + + +int32_t Rtcm::set_DF036(bool divergence_free_smoothing_indicator) +{ + // 0 - Divergence-free smoothing not used 1 - Divergence-free smoothing used + DF036 = std::bitset<1>(divergence_free_smoothing_indicator); + return 0; +} + + +int32_t Rtcm::set_DF037(int16_t smoothing_interval) +{ + DF037 = std::bitset<3>(smoothing_interval); + return 0; +} + + +int32_t Rtcm::set_DF038(const Gnss_Synchro& gnss_synchro) +{ + uint32_t prn_ = gnss_synchro.PRN; + if (prn_ > 24) + { + LOG(WARNING) << "GLONASS satellite ID (Slot Number) must be between 1 and 24, but PRN " << prn_ << " was found"; + } + DF038 = std::bitset<6>(prn_); + return 0; +} + + +int32_t Rtcm::set_DF038(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t prn_ = glonass_gnav_eph.i_satellite_slot_number; + if (prn_ > 24) + { + LOG(WARNING) << "GLONASS satellite ID (Slot Number) must be between 0 and 24, but PRN " << prn_ << " was found"; + } + DF038 = std::bitset<6>(prn_); + return 0; +} + + +int32_t Rtcm::set_DF039(bool code_indicator) +{ + DF039 = std::bitset<1>(code_indicator); + return 0; +} + + +int32_t Rtcm::set_DF040(int32_t frequency_channel_number) +{ + uint32_t freq_ = frequency_channel_number + 7; + if (freq_ > 20) + { + LOG(WARNING) << "GLONASS Satellite Frequency Number Conversion Error." + << "Value must be between 0 and 20, but converted channel" + << "frequency number " << freq_ << " was found"; + } + + DF040 = std::bitset<5>(freq_); + return 0; +} + + +int32_t Rtcm::set_DF040(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t freq_ = glonass_gnav_eph.i_satellite_freq_channel + 7; + if (freq_ > 20) + { + LOG(WARNING) << "GLONASS Satellite Frequency Number Conversion Error." + << "Value must be between 0 and 20, but converted channel" + << "frequency number " << freq_ << " was found"; + } + + DF040 = std::bitset<5>(freq_); + return 0; +} + + +int32_t Rtcm::set_DF041(const Gnss_Synchro& gnss_synchro) +{ + double ambiguity = std::floor(gnss_synchro.Pseudorange_m / 599584.92); + auto glonass_L1_pseudorange = static_cast(std::round((gnss_synchro.Pseudorange_m - ambiguity * 599584.92) / 0.02)); + DF041 = std::bitset<25>(glonass_L1_pseudorange); + return 0; +} + + +int32_t Rtcm::set_DF042(const Gnss_Synchro& gnss_synchro) +{ + const double lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + double ambiguity = std::floor(gnss_synchro.Pseudorange_m / 599584.92); + double glonass_L1_pseudorange = std::round((gnss_synchro.Pseudorange_m - ambiguity * 599584.92) / 0.02); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 299792.458; + double L1_phaserange_c = gnss_synchro.Carrier_phase_rads / GLONASS_TWO_PI; + double L1_phaserange_c_r = std::fmod(L1_phaserange_c - glonass_L1_pseudorange_c / lambda + 1500.0, 3000.0) - 1500.0; + auto glonass_L1_phaserange_minus_L1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda / 0.0005)); + DF042 = std::bitset<20>(glonass_L1_phaserange_minus_L1_pseudorange); + return 0; +} + + +int32_t Rtcm::set_DF043(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + uint32_t lock_time_indicator; + uint32_t lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); + DF043 = std::bitset<7>(lock_time_indicator); + return 0; +} + + +int32_t Rtcm::set_DF044(const Gnss_Synchro& gnss_synchro) +{ + auto glonass_L1_pseudorange_ambiguity = static_cast(std::floor(gnss_synchro.Pseudorange_m / 599584.916)); + DF044 = std::bitset<7>(glonass_L1_pseudorange_ambiguity); + return 0; +} + + +int32_t Rtcm::set_DF045(const Gnss_Synchro& gnss_synchro) +{ + double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; + if (CN0_dB_Hz_est > 63.75) + { + LOG(WARNING) << "GLONASS L1 CNR must be between 0 and 63.75, but CNR " << CN0_dB_Hz_est << " was found. Setting to 63.75 dB-Hz"; + CN0_dB_Hz_est = 63.75; + } + auto CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25)); + DF045 = std::bitset<8>(CN0_dB_Hz); + return 0; +} + + +int32_t Rtcm::set_DF047(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) +{ + double ambiguity = std::floor(gnss_synchroL1.Pseudorange_m / 599584.92); + double glonass_L1_pseudorange = std::round((gnss_synchroL1.Pseudorange_m - ambiguity * 599584.92) / 0.02); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 599584.92; + + double l2_l1_pseudorange = gnss_synchroL2.Pseudorange_m - glonass_L1_pseudorange_c; + int32_t pseudorange_difference = 0xFFFFE000; // invalid value; + if (std::fabs(l2_l1_pseudorange) <= 163.82) + { + pseudorange_difference = static_cast(std::round(l2_l1_pseudorange / 0.02)); + } + DF047 = std::bitset<14>(pseudorange_difference); + return 0; +} + +//TODO Need to consider frequency channel in this fields +int32_t Rtcm::set_DF048(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2) +{ + const double lambda2 = GLONASS_C_m_s / GLONASS_L2_CA_FREQ_HZ; + int32_t l2_phaserange_minus_l1_pseudorange = 0xFFF80000; + double ambiguity = std::floor(gnss_synchroL1.Pseudorange_m / 599584.92); + double glonass_L1_pseudorange = std::round((gnss_synchroL1.Pseudorange_m - ambiguity * 599584.92) / 0.02); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 599584.92; + double L2_phaserange_c = gnss_synchroL2.Carrier_phase_rads / GLONASS_TWO_PI; + double L1_phaserange_c_r = std::fmod(L2_phaserange_c - glonass_L1_pseudorange_c / lambda2 + 1500.0, 3000.0) - 1500.0; + + if (std::fabs(L1_phaserange_c_r * lambda2) <= 262.1435) + { + l2_phaserange_minus_l1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda2 / 0.0005)); + } + + DF048 = std::bitset<20>(l2_phaserange_minus_l1_pseudorange); + return 0; +} + + +int32_t Rtcm::set_DF049(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro) +{ + uint32_t lock_time_indicator; + uint32_t lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); + DF049 = std::bitset<7>(lock_time_indicator); + return 0; +} + + +int32_t Rtcm::set_DF050(const Gnss_Synchro& gnss_synchro) +{ + double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; + if (CN0_dB_Hz_est > 63.75) + { + CN0_dB_Hz_est = 63.75; + } + auto CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25)); + DF050 = std::bitset<8>(CN0_dB_Hz); + return 0; +} + + +int32_t Rtcm::set_DF051(const Gps_Ephemeris& gps_eph, double obs_time) { const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(gps_eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(gps_eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); std::string now_ptime = to_iso_string(p_time); std::string today_ptime = now_ptime.substr(0, 8); boost::gregorian::date d(boost::gregorian::from_undelimited_string(today_ptime)); - unsigned int mjd = d.modjulian_day(); + uint32_t mjd = d.modjulian_day(); DF051 = std::bitset<16>(mjd); return 0; } -int Rtcm::set_DF052(const Gps_Ephemeris & gps_eph, double obs_time) +int32_t Rtcm::set_DF052(const Gps_Ephemeris& gps_eph, double obs_time) { const double gps_t = obs_time; - boost::posix_time::time_duration t = boost::posix_time::millisec((gps_t + 604800 * static_cast(gps_eph.i_GPS_week % 1024)) * 1000); + boost::posix_time::time_duration t = boost::posix_time::milliseconds(static_cast((gps_t + 604800 * static_cast(gps_eph.i_GPS_week % 1024)) * 1000)); boost::posix_time::ptime p_time(boost::gregorian::date(1999, 8, 22), t); std::string now_ptime = to_iso_string(p_time); std::string hours = now_ptime.substr(9, 2); std::string minutes = now_ptime.substr(11, 2); std::string seconds = now_ptime.substr(13, 8); //boost::gregorian::date d(boost::gregorian::from_undelimited_string(today_ptime)); - long unsigned int seconds_of_day = boost::lexical_cast(hours) * 60 * 60 + boost::lexical_cast(minutes) * 60 + boost::lexical_cast(seconds); + uint32_t seconds_of_day = boost::lexical_cast(hours) * 60 * 60 + boost::lexical_cast(minutes) * 60 + boost::lexical_cast(seconds); DF052 = std::bitset<17>(seconds_of_day); return 0; } -int Rtcm::set_DF071(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF071(const Gps_Ephemeris& gps_eph) { - unsigned int iode = static_cast(gps_eph.d_IODE_SF2); + auto iode = static_cast(gps_eph.d_IODE_SF2); DF071 = std::bitset<8>(iode); return 0; } -int Rtcm::set_DF076(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF076(const Gps_Ephemeris& gps_eph) { - unsigned int week_number = static_cast(gps_eph.i_GPS_week); + auto week_number = static_cast(gps_eph.i_GPS_week); DF076 = std::bitset<10>(week_number); return 0; } -int Rtcm::set_DF077(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF077(const Gps_Ephemeris& gps_eph) { - unsigned short int ura = static_cast(gps_eph.i_SV_accuracy); + auto ura = static_cast(gps_eph.i_SV_accuracy); DF077 = std::bitset<4>(ura); return 0; } -int Rtcm::set_DF078(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF078(const Gps_Ephemeris& gps_eph) { - unsigned short int code_on_L2 = static_cast(gps_eph.i_code_on_L2); + auto code_on_L2 = static_cast(gps_eph.i_code_on_L2); DF078 = std::bitset<2>(code_on_L2); return 0; } -int Rtcm::set_DF079(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF079(const Gps_Ephemeris& gps_eph) { - unsigned int idot = static_cast(std::round(gps_eph.d_IDOT / I_DOT_LSB )); + auto idot = static_cast(std::round(gps_eph.d_IDOT / I_DOT_LSB)); DF079 = std::bitset<14>(idot); return 0; } -int Rtcm::set_DF080(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF080(const Gps_Ephemeris& gps_eph) { - unsigned short int iode = static_cast(gps_eph.d_IODE_SF2); + auto iode = static_cast(gps_eph.d_IODE_SF2); DF080 = std::bitset<8>(iode); return 0; } -int Rtcm::set_DF081(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF081(const Gps_Ephemeris& gps_eph) { - unsigned int toc = static_cast(std::round(gps_eph.d_Toc / T_OC_LSB )); + auto toc = static_cast(std::round(gps_eph.d_Toc / T_OC_LSB)); DF081 = std::bitset<16>(toc); return 0; } -int Rtcm::set_DF082(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF082(const Gps_Ephemeris& gps_eph) { - short int af2 = static_cast(std::round(gps_eph.d_A_f2 / A_F2_LSB )); + auto af2 = static_cast(std::round(gps_eph.d_A_f2 / A_F2_LSB)); DF082 = std::bitset<8>(af2); return 0; } -int Rtcm::set_DF083(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF083(const Gps_Ephemeris& gps_eph) { - int af1 = static_cast(std::round(gps_eph.d_A_f1 / A_F1_LSB )); + auto af1 = static_cast(std::round(gps_eph.d_A_f1 / A_F1_LSB)); DF083 = std::bitset<16>(af1); return 0; } -int Rtcm::set_DF084(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF084(const Gps_Ephemeris& gps_eph) { - long int af0 = static_cast(std::round(gps_eph.d_A_f0 / A_F0_LSB )); + auto af0 = static_cast(std::round(gps_eph.d_A_f0 / A_F0_LSB)); DF084 = std::bitset<22>(af0); return 0; } -int Rtcm::set_DF085(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF085(const Gps_Ephemeris& gps_eph) { - unsigned int iodc = static_cast(gps_eph.d_IODC); + auto iodc = static_cast(gps_eph.d_IODC); DF085 = std::bitset<10>(iodc); return 0; } -int Rtcm::set_DF086(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF086(const Gps_Ephemeris& gps_eph) { - int crs = static_cast(std::round(gps_eph.d_Crs / C_RS_LSB )); + auto crs = static_cast(std::round(gps_eph.d_Crs / C_RS_LSB)); DF086 = std::bitset<16>(crs); return 0; } -int Rtcm::set_DF087(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF087(const Gps_Ephemeris& gps_eph) { - int delta_n = static_cast(std::round(gps_eph.d_Delta_n / DELTA_N_LSB )); + auto delta_n = static_cast(std::round(gps_eph.d_Delta_n / DELTA_N_LSB)); DF087 = std::bitset<16>(delta_n); return 0; } -int Rtcm::set_DF088(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF088(const Gps_Ephemeris& gps_eph) { - long int m0 = static_cast(std::round(gps_eph.d_M_0 / M_0_LSB )); + auto m0 = static_cast(std::round(gps_eph.d_M_0 / M_0_LSB)); DF088 = std::bitset<32>(m0); return 0; } -int Rtcm::set_DF089(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF089(const Gps_Ephemeris& gps_eph) { - int cuc = static_cast(std::round(gps_eph.d_Cuc / C_UC_LSB )); + auto cuc = static_cast(std::round(gps_eph.d_Cuc / C_UC_LSB)); DF089 = std::bitset<16>(cuc); return 0; } -int Rtcm::set_DF090(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF090(const Gps_Ephemeris& gps_eph) { - unsigned long int ecc = static_cast(std::round(gps_eph.d_e_eccentricity / E_LSB )); + auto ecc = static_cast(std::round(gps_eph.d_e_eccentricity / E_LSB)); DF090 = std::bitset<32>(ecc); return 0; } -int Rtcm::set_DF091(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF091(const Gps_Ephemeris& gps_eph) { - int cus = static_cast(std::round(gps_eph.d_Cus / C_US_LSB )); + auto cus = static_cast(std::round(gps_eph.d_Cus / C_US_LSB)); DF091 = std::bitset<16>(cus); return 0; } -int Rtcm::set_DF092(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF092(const Gps_Ephemeris& gps_eph) { - unsigned long int sqr_a = static_cast(std::round(gps_eph.d_sqrt_A / SQRT_A_LSB )); + auto sqr_a = static_cast(std::round(gps_eph.d_sqrt_A / SQRT_A_LSB)); DF092 = std::bitset<32>(sqr_a); return 0; } -int Rtcm::set_DF093(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF093(const Gps_Ephemeris& gps_eph) { - unsigned int toe = static_cast(std::round(gps_eph.d_Toe / T_OE_LSB )); + auto toe = static_cast(std::round(gps_eph.d_Toe / T_OE_LSB)); DF093 = std::bitset<16>(toe); return 0; } -int Rtcm::set_DF094(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF094(const Gps_Ephemeris& gps_eph) { - int cic = static_cast(std::round(gps_eph.d_Cic / C_IC_LSB )); + auto cic = static_cast(std::round(gps_eph.d_Cic / C_IC_LSB)); DF094 = std::bitset<16>(cic); return 0; } -int Rtcm::set_DF095(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF095(const Gps_Ephemeris& gps_eph) { - long int Omega0 = static_cast(std::round(gps_eph.d_OMEGA0 / OMEGA_0_LSB )); + auto Omega0 = static_cast(std::round(gps_eph.d_OMEGA0 / OMEGA_0_LSB)); DF095 = std::bitset<32>(Omega0); return 0; } -int Rtcm::set_DF096(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF096(const Gps_Ephemeris& gps_eph) { - int cis = static_cast(std::round(gps_eph.d_Cis / C_IS_LSB )); + auto cis = static_cast(std::round(gps_eph.d_Cis / C_IS_LSB)); DF096 = std::bitset<16>(cis); return 0; } -int Rtcm::set_DF097(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF097(const Gps_Ephemeris& gps_eph) { - long int i0 = static_cast(std::round(gps_eph.d_i_0 / I_0_LSB )); + auto i0 = static_cast(std::round(gps_eph.d_i_0 / I_0_LSB)); DF097 = std::bitset<32>(i0); return 0; } -int Rtcm::set_DF098(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF098(const Gps_Ephemeris& gps_eph) { - int crc = static_cast(std::round(gps_eph.d_Crc / C_RC_LSB )); + auto crc = static_cast(std::round(gps_eph.d_Crc / C_RC_LSB)); DF098 = std::bitset<16>(crc); return 0; } -int Rtcm::set_DF099(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF099(const Gps_Ephemeris& gps_eph) { - long int omega = static_cast(std::round(gps_eph.d_OMEGA / OMEGA_LSB )); + auto omega = static_cast(std::round(gps_eph.d_OMEGA / OMEGA_LSB)); DF099 = std::bitset<32>(omega); return 0; } -int Rtcm::set_DF100(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF100(const Gps_Ephemeris& gps_eph) { - long int omegadot = static_cast(std::round(gps_eph.d_OMEGA_DOT / OMEGA_DOT_LSB )); + auto omegadot = static_cast(std::round(gps_eph.d_OMEGA_DOT / OMEGA_DOT_LSB)); DF100 = std::bitset<24>(omegadot); return 0; } -int Rtcm::set_DF101(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF101(const Gps_Ephemeris& gps_eph) { - short int tgd = static_cast(std::round(gps_eph.d_TGD / T_GD_LSB )); + auto tgd = static_cast(std::round(gps_eph.d_TGD / T_GD_LSB)); DF101 = std::bitset<8>(tgd); return 0; } -int Rtcm::set_DF102(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF102(const Gps_Ephemeris& gps_eph) { - unsigned short int sv_heath = static_cast(gps_eph.i_SV_health); + auto sv_heath = static_cast(gps_eph.i_SV_health); DF102 = std::bitset<6>(sv_heath); return 0; } -int Rtcm::set_DF103(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF103(const Gps_Ephemeris& gps_eph) { DF103 = std::bitset<1>(gps_eph.b_L2_P_data_flag); return 0; } +int32_t Rtcm::set_DF104(uint32_t glonass_gnav_alm_health) +{ + DF104 = std::bitset<1>(glonass_gnav_alm_health); + return 0; +} -int Rtcm::set_DF137(const Gps_Ephemeris & gps_eph) +int32_t Rtcm::set_DF105(uint32_t glonass_gnav_alm_health_ind) +{ + DF105 = std::bitset<1>(glonass_gnav_alm_health_ind); + return 0; +} + + +int32_t Rtcm::set_DF106(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + // Convert the value from (15, 30, 45, 60) to (00, 01, 10, 11) + auto P_1 = static_cast(std::round(glonass_gnav_eph.d_P_1 / 15.0 - 1.0)); + DF106 = std::bitset<2>(P_1); + return 0; +} + + +int32_t Rtcm::set_DF107(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t hrs = 0; + uint32_t min = 0; + uint32_t sec = 0; + uint32_t tk = 0; + tk = static_cast(glonass_gnav_eph.d_t_k); + hrs = tk / 3600; + min = (tk - hrs * 3600) / 60; + sec = (tk - hrs * 3600 - min * 60) / 60; + + std::string _hrs = std::bitset<5>(hrs).to_string(); // string conversion + std::string _min = std::bitset<6>(min).to_string(); // string conversion + std::string _sec = std::bitset<1>(sec).to_string(); // string conversion + + // Set hrs, min, sec in designed bit positions + DF107 = std::bitset<12>(_hrs + _min + _sec); + + return 0; +} + + +int32_t Rtcm::set_DF108(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + DF108 = std::bitset<1>(glonass_gnav_eph.d_B_n); + return 0; +} + + +int32_t Rtcm::set_DF109(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + DF109 = std::bitset<1>(glonass_gnav_eph.d_P_2); + return 0; +} + + +int32_t Rtcm::set_DF110(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto t_b = static_cast(std::round(glonass_gnav_eph.d_t_b / (15 * 60))); + DF110 = std::bitset<7>(t_b); + return 0; +} + + +int32_t Rtcm::set_DF111(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto VXn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VXn / TWO_N20))); + uint32_t VXn_sgn = glo_sgn(glonass_gnav_eph.d_VXn); + + DF111 = std::bitset<24>(VXn_mag); + DF111.set(23, VXn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF112(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto Xn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Xn / TWO_N11))); + uint32_t Xn_sgn = glo_sgn(glonass_gnav_eph.d_Xn); + + DF112 = std::bitset<27>(Xn_mag); + DF112.set(26, Xn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF113(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto AXn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AXn / TWO_N30))); + uint32_t AXn_sgn = glo_sgn(glonass_gnav_eph.d_AXn); + + DF113 = std::bitset<5>(AXn_mag); + DF113.set(4, AXn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF114(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto VYn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VYn / TWO_N20))); + uint32_t VYn_sgn = glo_sgn(glonass_gnav_eph.d_VYn); + + DF114 = std::bitset<24>(VYn_mag); + DF114.set(23, VYn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF115(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto Yn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Yn / TWO_N11))); + uint32_t Yn_sgn = glo_sgn(glonass_gnav_eph.d_Yn); + + DF115 = std::bitset<27>(Yn_mag); + DF115.set(26, Yn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF116(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto AYn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AYn / TWO_N30))); + uint32_t AYn_sgn = glo_sgn(glonass_gnav_eph.d_AYn); + + DF116 = std::bitset<5>(AYn_mag); + DF116.set(4, AYn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF117(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto VZn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VZn / TWO_N20))); + uint32_t VZn_sgn = glo_sgn(glonass_gnav_eph.d_VZn); + + DF117 = std::bitset<24>(VZn_mag); + DF117.set(23, VZn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF118(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto Zn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Zn / TWO_N11))); + uint32_t Zn_sgn = glo_sgn(glonass_gnav_eph.d_Zn); + + DF118 = std::bitset<27>(Zn_mag); + DF118.set(26, Zn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF119(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto AZn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AZn / TWO_N30))); + uint32_t AZn_sgn = glo_sgn(glonass_gnav_eph.d_AZn); + + DF119 = std::bitset<5>(AZn_mag); + DF119.set(4, AZn_sgn); + return 0; +} + + +int32_t Rtcm::set_DF120(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t P3 = static_cast(std::round(glonass_gnav_eph.d_P_3)); + DF120 = std::bitset<1>(P3); + return 0; +} + + +int32_t Rtcm::set_DF121(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto gamma_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_gamma_n / TWO_N40))); + uint32_t gamma_sgn = glo_sgn(glonass_gnav_eph.d_gamma_n); + + DF121 = std::bitset<11>(gamma_mag); + DF121.set(10, gamma_sgn); + return 0; +} + + +int32_t Rtcm::set_DF122(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto P = static_cast(std::round(glonass_gnav_eph.d_P)); + DF122 = std::bitset<2>(P); + return 0; +} + + +int32_t Rtcm::set_DF123(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto ln = static_cast((glonass_gnav_eph.d_l3rd_n)); + DF123 = std::bitset<1>(ln); + return 0; +} + + +int32_t Rtcm::set_DF124(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto tau_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_tau_n / TWO_N30))); + uint32_t tau_sgn = glo_sgn(glonass_gnav_eph.d_tau_n); + + DF124 = std::bitset<22>(tau_mag); + DF124.set(21, tau_sgn); + return 0; +} + + +int32_t Rtcm::set_DF125(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto delta_tau_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Delta_tau_n / TWO_N30))); + uint32_t delta_tau_sgn = glo_sgn(glonass_gnav_eph.d_Delta_tau_n); + + DF125 = std::bitset<5>(delta_tau_mag); + DF125.set(4, delta_tau_sgn); + return 0; +} + + +int32_t Rtcm::set_DF126(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto ecc = static_cast(std::round(glonass_gnav_eph.d_E_n)); + DF126 = std::bitset<5>(ecc); + return 0; +} + + +int32_t Rtcm::set_DF127(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t P4 = static_cast(std::round(glonass_gnav_eph.d_P_4)); + DF127 = std::bitset<1>(P4); + return 0; +} + + +int32_t Rtcm::set_DF128(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto F_t = static_cast(std::round(glonass_gnav_eph.d_F_T)); + DF128 = std::bitset<4>(F_t); + return 0; +} + + +int32_t Rtcm::set_DF129(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto N_t = static_cast(std::round(glonass_gnav_eph.d_N_T)); + DF129 = std::bitset<11>(N_t); + return 0; +} + + +int32_t Rtcm::set_DF130(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + auto M = static_cast(std::round(glonass_gnav_eph.d_M)); + DF130 = std::bitset<2>(M); + return 0; +} + + +int32_t Rtcm::set_DF131(uint32_t fifth_str_additional_data_ind) +{ + auto fith_str_data = static_cast(fifth_str_additional_data_ind); + DF131 = std::bitset<1>(fith_str_data); + return 0; +} + + +int32_t Rtcm::set_DF132(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + auto N_A = static_cast(std::round(glonass_gnav_utc_model.d_N_A)); + DF132 = std::bitset<11>(N_A); + return 0; +} + + +int32_t Rtcm::set_DF133(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + auto tau_c = static_cast(std::round(glonass_gnav_utc_model.d_tau_c / TWO_N31)); + DF133 = std::bitset<32>(tau_c); + return 0; +} + + +int32_t Rtcm::set_DF134(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + auto N_4 = static_cast(std::round(glonass_gnav_utc_model.d_N_4)); + DF134 = std::bitset<5>(N_4); + return 0; +} + + +int32_t Rtcm::set_DF135(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model) +{ + auto tau_gps = static_cast(std::round(glonass_gnav_utc_model.d_tau_gps) / TWO_N30); + DF135 = std::bitset<22>(tau_gps); + return 0; +} + + +int32_t Rtcm::set_DF136(const Glonass_Gnav_Ephemeris& glonass_gnav_eph) +{ + uint32_t l_n = static_cast(std::round(glonass_gnav_eph.d_l5th_n)); + DF136 = std::bitset<1>(l_n); + return 0; +} + + +int32_t Rtcm::set_DF137(const Gps_Ephemeris& gps_eph) { DF137 = std::bitset<1>(gps_eph.b_fit_interval_flag); return 0; } -int Rtcm::set_DF248(double obs_time) +int32_t Rtcm::set_DF248(double obs_time) { // TOW in milliseconds from the beginning of the Galileo week, measured in Galileo time - unsigned long int tow = static_cast(std::round(obs_time * 1000)); - if(tow > 604799999) + auto tow = static_cast(std::round(obs_time * 1000)); + if (tow > 604799999) { LOG(WARNING) << "To large TOW! Set to the last millisecond of the week"; tow = 604799999; @@ -3311,10 +4647,10 @@ int Rtcm::set_DF248(double obs_time) } -int Rtcm::set_DF252(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF252(const Galileo_Ephemeris& gal_eph) { - unsigned int prn_ = gal_eph.i_satellite_PRN; - if(prn_ > 63) + uint32_t prn_ = gal_eph.i_satellite_PRN; + if (prn_ > 63) { LOG(WARNING) << "Galileo satellite ID must be between 0 and 63, but PRN " << prn_ << " was found"; } @@ -3323,10 +4659,10 @@ int Rtcm::set_DF252(const Galileo_Ephemeris & gal_eph) } -int Rtcm::set_DF289(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF289(const Galileo_Ephemeris& gal_eph) { - unsigned int galileo_week_number = static_cast(gal_eph.WN_5); - if(galileo_week_number > 4095) + auto galileo_week_number = static_cast(gal_eph.WN_5); + if (galileo_week_number > 4095) { LOG(WARNING) << "Error decoding Galileo week number (it has a 4096 roll-off, but " << galileo_week_number << " was detected)"; } @@ -3335,10 +4671,10 @@ int Rtcm::set_DF289(const Galileo_Ephemeris & gal_eph) } -int Rtcm::set_DF290(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF290(const Galileo_Ephemeris& gal_eph) { - unsigned int iod_nav = static_cast(gal_eph.IOD_nav_1); - if(iod_nav > 1023) + auto iod_nav = static_cast(gal_eph.IOD_nav_1); + if (iod_nav > 1023) { LOG(WARNING) << "Error decoding Galileo IODnav (it has a max of 1023, but " << iod_nav << " was detected)"; } @@ -3347,29 +4683,27 @@ int Rtcm::set_DF290(const Galileo_Ephemeris & gal_eph) } -int Rtcm::set_DF291(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF291(const Galileo_Ephemeris& gal_eph) { - unsigned short int SISA = static_cast(gal_eph.SISA_3); + auto SISA = static_cast(gal_eph.SISA_3); //SISA = 0; // SIS Accuracy, data content definition not given in Galileo OS SIS ICD, Issue 1.1, Sept 2010 DF291 = std::bitset<8>(SISA); return 0; } -int Rtcm::set_DF292(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF292(const Galileo_Ephemeris& gal_eph) { - - int idot = static_cast(std::round(gal_eph.iDot_2 / FNAV_idot_2_LSB)); + auto idot = static_cast(std::round(gal_eph.iDot_2 / FNAV_idot_2_LSB)); DF292 = std::bitset<14>(idot); return 0; } -int Rtcm::set_DF293(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF293(const Galileo_Ephemeris& gal_eph) { - - unsigned int toc = static_cast(gal_eph.t0c_4); - if(toc > 604740) + auto toc = static_cast(gal_eph.t0c_4); + if (toc > 604740) { LOG(WARNING) << "Error decoding Galileo ephemeris time (max of 604740, but " << toc << " was detected)"; } @@ -3378,197 +4712,196 @@ int Rtcm::set_DF293(const Galileo_Ephemeris & gal_eph) } -int Rtcm::set_DF294(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF294(const Galileo_Ephemeris& gal_eph) { - short int af2 = static_cast(std::round(gal_eph.af2_4 / FNAV_af2_1_LSB)); + auto af2 = static_cast(std::round(gal_eph.af2_4 / FNAV_af2_1_LSB)); DF294 = std::bitset<6>(af2); return 0; } -int Rtcm::set_DF295(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF295(const Galileo_Ephemeris& gal_eph) { - long int af1 = static_cast(std::round(gal_eph.af1_4 / FNAV_af1_1_LSB)); + auto af1 = static_cast(std::round(gal_eph.af1_4 / FNAV_af1_1_LSB)); DF295 = std::bitset<21>(af1); return 0; } -int Rtcm::set_DF296(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF296(const Galileo_Ephemeris& gal_eph) { - long int af0 = static_cast(std::round(gal_eph.af0_4 / FNAV_af0_1_LSB)); + int64_t af0 = static_cast(std::round(gal_eph.af0_4 / FNAV_af0_1_LSB)); DF296 = std::bitset<31>(af0); return 0; } -int Rtcm::set_DF297(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF297(const Galileo_Ephemeris& gal_eph) { - int crs = static_cast(std::round(gal_eph.C_rs_3 / FNAV_Crs_3_LSB)); + auto crs = static_cast(std::round(gal_eph.C_rs_3 / FNAV_Crs_3_LSB)); DF297 = std::bitset<16>(crs); return 0; } -int Rtcm::set_DF298(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF298(const Galileo_Ephemeris& gal_eph) { - int delta_n = static_cast(std::round(gal_eph.delta_n_3 / FNAV_deltan_3_LSB)); + auto delta_n = static_cast(std::round(gal_eph.delta_n_3 / FNAV_deltan_3_LSB)); DF298 = std::bitset<16>(delta_n); return 0; } -int Rtcm::set_DF299(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF299(const Galileo_Ephemeris& gal_eph) { - long int m0 = static_cast(std::round(gal_eph.M0_1 / FNAV_M0_2_LSB)); + auto m0 = static_cast(std::round(gal_eph.M0_1 / FNAV_M0_2_LSB)); DF299 = std::bitset<32>(m0); return 0; } -int Rtcm::set_DF300(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF300(const Galileo_Ephemeris& gal_eph) { - int cuc = static_cast(std::round(gal_eph.C_uc_3 / FNAV_Cuc_3_LSB)); + int32_t cuc = static_cast(std::round(gal_eph.C_uc_3 / FNAV_Cuc_3_LSB)); DF300 = std::bitset<16>(cuc); return 0; } -int Rtcm::set_DF301(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF301(const Galileo_Ephemeris& gal_eph) { - unsigned long int ecc = static_cast(std::round(gal_eph.e_1 / FNAV_e_2_LSB)); + auto ecc = static_cast(std::round(gal_eph.e_1 / FNAV_e_2_LSB)); DF301 = std::bitset<32>(ecc); return 0; } -int Rtcm::set_DF302(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF302(const Galileo_Ephemeris& gal_eph) { - int cus = static_cast(std::round(gal_eph.C_us_3 / FNAV_Cus_3_LSB)); + auto cus = static_cast(std::round(gal_eph.C_us_3 / FNAV_Cus_3_LSB)); DF302 = std::bitset<16>(cus); return 0; } -int Rtcm::set_DF303(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF303(const Galileo_Ephemeris& gal_eph) { - unsigned long int sqr_a = static_cast(std::round(gal_eph.A_1 / FNAV_a12_2_LSB)); + auto sqr_a = static_cast(std::round(gal_eph.A_1 / FNAV_a12_2_LSB)); DF303 = std::bitset<32>(sqr_a); return 0; } -int Rtcm::set_DF304(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF304(const Galileo_Ephemeris& gal_eph) { - unsigned int toe = static_cast(std::round(gal_eph.t0e_1 / FNAV_t0e_3_LSB)); + auto toe = static_cast(std::round(gal_eph.t0e_1 / FNAV_t0e_3_LSB)); DF304 = std::bitset<14>(toe); return 0; } -int Rtcm::set_DF305(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF305(const Galileo_Ephemeris& gal_eph) { - int cic = static_cast(std::round(gal_eph.C_ic_4 / FNAV_Cic_4_LSB)); + auto cic = static_cast(std::round(gal_eph.C_ic_4 / FNAV_Cic_4_LSB)); DF305 = std::bitset<16>(cic); return 0; } -int Rtcm::set_DF306(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF306(const Galileo_Ephemeris& gal_eph) { - long int Omega0 = static_cast(std::round(gal_eph.OMEGA_0_2 / FNAV_omega0_2_LSB)); + auto Omega0 = static_cast(std::round(gal_eph.OMEGA_0_2 / FNAV_omega0_2_LSB)); DF306 = std::bitset<32>(Omega0); return 0; } -int Rtcm::set_DF307(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF307(const Galileo_Ephemeris& gal_eph) { - int cis = static_cast(std::round(gal_eph.C_is_4 / FNAV_Cis_4_LSB)); + auto cis = static_cast(std::round(gal_eph.C_is_4 / FNAV_Cis_4_LSB)); DF307 = std::bitset<16>(cis); return 0; } -int Rtcm::set_DF308(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF308(const Galileo_Ephemeris& gal_eph) { - long int i0 = static_cast(std::round(gal_eph.i_0_2 / FNAV_i0_3_LSB)); + auto i0 = static_cast(std::round(gal_eph.i_0_2 / FNAV_i0_3_LSB)); DF308 = std::bitset<32>(i0); return 0; } -int Rtcm::set_DF309(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF309(const Galileo_Ephemeris& gal_eph) { - int crc = static_cast(std::round(gal_eph.C_rc_3 / FNAV_Crc_3_LSB)); + int32_t crc = static_cast(std::round(gal_eph.C_rc_3 / FNAV_Crc_3_LSB)); DF309 = std::bitset<16>(crc); return 0; } -int Rtcm::set_DF310(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF310(const Galileo_Ephemeris& gal_eph) { - int omega = static_cast(std::round(gal_eph.omega_2 / FNAV_omega0_2_LSB)); + auto omega = static_cast(std::round(gal_eph.omega_2 / FNAV_omega0_2_LSB)); DF310 = std::bitset<32>(omega); return 0; } -int Rtcm::set_DF311(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF311(const Galileo_Ephemeris& gal_eph) { - long int Omegadot = static_cast(std::round(gal_eph.OMEGA_dot_3 / FNAV_omegadot_2_LSB)); + auto Omegadot = static_cast(std::round(gal_eph.OMEGA_dot_3 / FNAV_omegadot_2_LSB)); DF311 = std::bitset<24>(Omegadot); return 0; } -int Rtcm::set_DF312(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF312(const Galileo_Ephemeris& gal_eph) { - int bdg_E1_E5a = static_cast(std::round(gal_eph.BGD_E1E5a_5 / FNAV_BGD_1_LSB)); + auto bdg_E1_E5a = static_cast(std::round(gal_eph.BGD_E1E5a_5 / FNAV_BGD_1_LSB)); DF312 = std::bitset<10>(bdg_E1_E5a); return 0; } -int Rtcm::set_DF313(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF313(const Galileo_Ephemeris& gal_eph) { - unsigned int bdg_E5b_E1 = static_cast(std::round(gal_eph.BGD_E1E5b_5 )); + auto bdg_E5b_E1 = static_cast(std::round(gal_eph.BGD_E1E5b_5)); //bdg_E5b_E1 = 0; //reserved DF313 = std::bitset<10>(bdg_E5b_E1); return 0; } -int Rtcm::set_DF314(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF314(const Galileo_Ephemeris& gal_eph) { DF314 = std::bitset<2>(gal_eph.E5a_HS); return 0; } -int Rtcm::set_DF315(const Galileo_Ephemeris & gal_eph) +int32_t Rtcm::set_DF315(const Galileo_Ephemeris& gal_eph) { DF315 = std::bitset<1>(gal_eph.E5a_DVS); return 0; } - -int Rtcm::set_DF393(bool more_messages) +int32_t Rtcm::set_DF393(bool more_messages) { DF393 = std::bitset<1>(more_messages); return 0; } -int Rtcm::set_DF394(const std::map & gnss_synchro) +int32_t Rtcm::set_DF394(const std::map& gnss_synchro) { DF394.reset(); - std::map::const_iterator gnss_synchro_iter; - unsigned int mask_position; - for(gnss_synchro_iter = gnss_synchro.begin(); - gnss_synchro_iter != gnss_synchro.end(); - gnss_synchro_iter++) + std::map::const_iterator gnss_synchro_iter; + uint32_t mask_position; + for (gnss_synchro_iter = gnss_synchro.cbegin(); + gnss_synchro_iter != gnss_synchro.cend(); + gnss_synchro_iter++) { mask_position = 64 - gnss_synchro_iter->second.PRN; DF394.set(mask_position, true); @@ -3577,71 +4910,81 @@ int Rtcm::set_DF394(const std::map & gnss_synchro) } -int Rtcm::set_DF395(const std::map & gnss_synchro) +int32_t Rtcm::set_DF395(const std::map& gnss_synchro) { DF395.reset(); - if(gnss_synchro.size() == 0) + if (gnss_synchro.size() == 0) { return 1; } - std::map::const_iterator gnss_synchro_iter; + std::map::const_iterator gnss_synchro_iter; std::string sig; - unsigned int mask_position; - for(gnss_synchro_iter = gnss_synchro.begin(); - gnss_synchro_iter != gnss_synchro.end(); - gnss_synchro_iter++) + uint32_t mask_position; + for (gnss_synchro_iter = gnss_synchro.cbegin(); + gnss_synchro_iter != gnss_synchro.cend(); + gnss_synchro_iter++) { std::string sig_(gnss_synchro_iter->second.Signal); - sig = sig_.substr(0,2); + sig = sig_.substr(0, 2); std::string sys(&gnss_synchro_iter->second.System, 1); - if ((sig.compare("1C") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("1C") == 0) && (sys.compare("G") == 0)) { mask_position = 32 - 2; DF395.set(mask_position, true); } - if ((sig.compare("2S") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("2S") == 0) && (sys.compare("G") == 0)) { mask_position = 32 - 15; DF395.set(mask_position, true); } - if ((sig.compare("5X") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("5X") == 0) && (sys.compare("G") == 0)) { mask_position = 32 - 24; DF395.set(mask_position, true); } - if ((sig.compare("1B") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("1B") == 0) && (sys.compare("E") == 0)) { mask_position = 32 - 4; DF395.set(mask_position, true); } - if ((sig.compare("5X") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("5X") == 0) && (sys.compare("E") == 0)) { mask_position = 32 - 24; DF395.set(mask_position, true); } - if ((sig.compare("7X") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("7X") == 0) && (sys.compare("E") == 0)) { mask_position = 32 - 16; DF395.set(mask_position, true); } + if ((sig.compare("1C") == 0) && (sys.compare("R") == 0)) + { + mask_position = 32 - 2; + DF395.set(mask_position, true); + } + if ((sig.compare("2C") == 0) && (sys.compare("R") == 0)) + { + mask_position = 32 - 8; + DF395.set(mask_position, true); + } } return 0; } -std::string Rtcm::set_DF396(const std::map & observables) +std::string Rtcm::set_DF396(const std::map& observables) { std::string DF396; - std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter; Rtcm::set_DF394(observables); Rtcm::set_DF395(observables); - unsigned int num_signals = DF395.count(); - unsigned int num_satellites = DF394.count(); + uint32_t num_signals = DF395.count(); + uint32_t num_satellites = DF394.count(); if ((num_signals == 0) || (num_satellites == 0)) { @@ -3651,97 +4994,97 @@ std::string Rtcm::set_DF396(const std::map & observables) std::vector > matrix(num_signals, std::vector()); std::string sig; - std::vector list_of_sats; + std::vector list_of_sats; std::vector list_of_signals; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { list_of_sats.push_back(observables_iter->second.PRN); std::string sig_(observables_iter->second.Signal); - sig = sig_.substr(0,2); + sig = sig_.substr(0, 2); std::string sys(&observables_iter->second.System, 1); - if ((sig.compare("1C") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("1C") == 0) && (sys.compare("G") == 0)) { list_of_signals.push_back(32 - 2); } - if ((sig.compare("2S") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("2S") == 0) && (sys.compare("G") == 0)) { list_of_signals.push_back(32 - 15); } - if ((sig.compare("5X") == 0) && (sys.compare("G") == 0 ) ) + if ((sig.compare("5X") == 0) && (sys.compare("G") == 0)) { list_of_signals.push_back(32 - 24); } - if ((sig.compare("1B") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("1B") == 0) && (sys.compare("E") == 0)) { list_of_signals.push_back(32 - 4); } - if ((sig.compare("5X") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("5X") == 0) && (sys.compare("E") == 0)) { list_of_signals.push_back(32 - 24); } - if ((sig.compare("7X") == 0) && (sys.compare("E") == 0 ) ) + if ((sig.compare("7X") == 0) && (sys.compare("E") == 0)) { list_of_signals.push_back(32 - 16); } } - std::sort( list_of_sats.begin(), list_of_sats.end() ); - list_of_sats.erase( std::unique( list_of_sats.begin(), list_of_sats.end() ), list_of_sats.end() ); + std::sort(list_of_sats.begin(), list_of_sats.end()); + list_of_sats.erase(std::unique(list_of_sats.begin(), list_of_sats.end()), list_of_sats.end()); - std::sort( list_of_signals.begin(), list_of_signals.end() ); + std::sort(list_of_signals.begin(), list_of_signals.end()); std::reverse(list_of_signals.begin(), list_of_signals.end()); - list_of_signals.erase( std::unique( list_of_signals.begin(), list_of_signals.end() ), list_of_signals.end() ); + list_of_signals.erase(std::unique(list_of_signals.begin(), list_of_signals.end()), list_of_signals.end()); // fill the matrix bool value; - for(unsigned int row = 0; row < num_signals; row++) + for (uint32_t row = 0; row < num_signals; row++) { - for(unsigned int sat = 0; sat < num_satellites; sat++) + for (uint32_t sat = 0; sat < num_satellites; sat++) { value = false; - for(observables_iter = observables.begin(); - observables_iter != observables.end(); - observables_iter++) + for (observables_iter = observables.cbegin(); + observables_iter != observables.cend(); + observables_iter++) { std::string sig_(observables_iter->second.Signal); - sig = sig_.substr(0,2); + sig = sig_.substr(0, 2); std::string sys(&observables_iter->second.System, 1); - if ((sig.compare("1C") == 0) && (sys.compare("G") == 0 ) && (list_of_signals.at(row) == 32 - 2) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("1C") == 0) && (sys.compare("G") == 0) && (list_of_signals.at(row) == 32 - 2) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } - if ((sig.compare("2S") == 0) && (sys.compare("G") == 0 ) && (list_of_signals.at(row) == 32 - 15) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("2S") == 0) && (sys.compare("G") == 0) && (list_of_signals.at(row) == 32 - 15) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } - if ((sig.compare("5X") == 0) && (sys.compare("G") == 0 ) && (list_of_signals.at(row) == 32 - 24) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("5X") == 0) && (sys.compare("G") == 0) && (list_of_signals.at(row) == 32 - 24) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } - if ((sig.compare("1B") == 0) && (sys.compare("E") == 0 ) && (list_of_signals.at(row) == 32 - 4) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("1B") == 0) && (sys.compare("E") == 0) && (list_of_signals.at(row) == 32 - 4) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } - if ((sig.compare("5X") == 0) && (sys.compare("E") == 0 ) && (list_of_signals.at(row) == 32 - 24) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("5X") == 0) && (sys.compare("E") == 0) && (list_of_signals.at(row) == 32 - 24) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } - if ((sig.compare("7X") == 0) && (sys.compare("E") == 0 ) && (list_of_signals.at(row) == 32 - 16) && (observables_iter->second.PRN == list_of_sats.at(sat) ) ) + if ((sig.compare("7X") == 0) && (sys.compare("E") == 0) && (list_of_signals.at(row) == 32 - 16) && (observables_iter->second.PRN == list_of_sats.at(sat))) { value = true; } @@ -3752,12 +5095,12 @@ std::string Rtcm::set_DF396(const std::map & observables) // write the matrix column-wise DF396.clear(); - for(unsigned int col = 0; col < num_satellites; col++) + for (uint32_t col = 0; col < num_satellites; col++) { - for(unsigned int row = 0; row < num_signals; row++) + for (uint32_t row = 0; row < num_signals; row++) { std::string ss; - if(matrix[row].at(col)) + if (matrix[row].at(col)) { ss = "1"; } @@ -3772,24 +5115,24 @@ std::string Rtcm::set_DF396(const std::map & observables) } -int Rtcm::set_DF397(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF397(const Gnss_Synchro& gnss_synchro) { double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_s = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; - unsigned int int_ms = 0; + uint32_t int_ms = 0; if (rough_range_s == 0.0) { int_ms = 255; } - else if((rough_range_s < 0.0) || (rough_range_s > meters_to_miliseconds * 255.0)) + else if ((rough_range_s < 0.0) || (rough_range_s > meters_to_miliseconds * 255.0)) { int_ms = 255; } else { - int_ms = static_cast(std::floor(rough_range_s / meters_to_miliseconds / TWO_N10) + 0.5) >> 10; + int_ms = static_cast(std::floor(rough_range_s / meters_to_miliseconds / TWO_N10) + 0.5) >> 10; } DF397 = std::bitset<8>(int_ms); @@ -3797,66 +5140,66 @@ int Rtcm::set_DF397(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF398(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF398(const Gnss_Synchro& gnss_synchro) { double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_m = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; - unsigned int rr_mod_ms; - if((rough_range_m <= 0.0) || (rough_range_m > meters_to_miliseconds * 255.0)) + uint32_t rr_mod_ms; + if ((rough_range_m <= 0.0) || (rough_range_m > meters_to_miliseconds * 255.0)) { rr_mod_ms = 0; } else { - rr_mod_ms = static_cast(std::floor(rough_range_m / meters_to_miliseconds / TWO_N10) + 0.5) & 0x3FFu; + rr_mod_ms = static_cast(std::floor(rough_range_m / meters_to_miliseconds / TWO_N10) + 0.5) & 0x3FFu; } DF398 = std::bitset<10>(rr_mod_ms); return 0; } -int Rtcm::set_DF399(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF399(const Gnss_Synchro& gnss_synchro) { double lambda = 0.0; std::string sig_(gnss_synchro.Signal); - std::string sig = sig_.substr(0,2); + std::string sig = sig_.substr(0, 2); - if (sig.compare("1C") == 0 ) + if (sig == "1C") { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if (sig == "2S") { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if (sig == "5X") { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if (sig == "1B") { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if (sig == "7X") { - lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; + lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } - double rough_phase_range_rate_ms = std::round(- gnss_synchro.Carrier_Doppler_hz * lambda ); - if(rough_phase_range_rate_ms < - 8191) rough_phase_range_rate_ms = -8192; - if(rough_phase_range_rate_ms > 8191) rough_phase_range_rate_ms = -8192; + double rough_phase_range_rate_ms = std::round(-gnss_synchro.Carrier_Doppler_hz * lambda); + if (rough_phase_range_rate_ms < -8191) rough_phase_range_rate_ms = -8192; + if (rough_phase_range_rate_ms > 8191) rough_phase_range_rate_ms = -8192; - DF399 = std::bitset<14>(static_cast(rough_phase_range_rate_ms)); + DF399 = std::bitset<14>(static_cast(rough_phase_range_rate_ms)); return 0; } -int Rtcm::set_DF400(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF400(const Gnss_Synchro& gnss_synchro) { double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_m = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; double psrng_s; - int fine_pseudorange; + int32_t fine_pseudorange; psrng_s = gnss_synchro.Pseudorange_m - rough_range_m; @@ -3864,13 +5207,13 @@ int Rtcm::set_DF400(const Gnss_Synchro & gnss_synchro) { fine_pseudorange = -16384; } - else if(std::fabs(psrng_s) > 292.7) + else if (std::fabs(psrng_s) > 292.7) { - fine_pseudorange = -16384; // 4000h: invalid value + fine_pseudorange = -16384; // 4000h: invalid value } else { - fine_pseudorange = static_cast(std::round(psrng_s / meters_to_miliseconds / TWO_N24)); + fine_pseudorange = static_cast(std::round(psrng_s / meters_to_miliseconds / TWO_N24)); } DF400 = std::bitset<15>(fine_pseudorange); @@ -3878,60 +5221,70 @@ int Rtcm::set_DF400(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF401(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF401(const Gnss_Synchro& gnss_synchro) { double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_m = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; double phrng_m; - long int fine_phaserange; + int64_t fine_phaserange; double lambda = 0.0; std::string sig_(gnss_synchro.Signal); - std::string sig = sig_.substr(0,2); + std::string sig = sig_.substr(0, 2); + std::string sys(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig == "1C") && (sys == "G")) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig.compare("2S")) == 0 && (sys == "G")) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig.compare("5X")) == 0 && (sys == "E")) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig.compare("1B")) == 0 && (sys == "E")) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig.compare("7X")) == 0 && (sys == "E")) { - lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; + lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; + } + if ((sig == "1C") && (sys == "R")) + { + lambda = GLONASS_C_m_s / ((GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN)))); + } + if ((sig == "2C") && (sys == "R")) + { + // TODO Need to add slot number and freq number to gnss_syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_CA_FREQ_HZ); } - phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI ) * lambda - rough_range_m; + phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI) * lambda - rough_range_m; - /* Substract phase - pseudorange integer cycle offset */ + /* Subtract phase - pseudorange integer cycle offset */ /* TODO: check LLI! */ - double cp = gnss_synchro.Carrier_phase_rads / GPS_TWO_PI; // ? - if(std::fabs(phrng_m - cp) > 1171.0) + double cp = gnss_synchro.Carrier_phase_rads / GPS_TWO_PI; // ? + if (std::fabs(phrng_m - cp) > 1171.0) { cp = std::round(phrng_m / lambda) * lambda; } phrng_m -= cp; - if(phrng_m == 0.0) + if (phrng_m == 0.0) { - fine_phaserange = - 2097152; + fine_phaserange = -2097152; } - else if(std::fabs(phrng_m) > 1171.0) + else if (std::fabs(phrng_m) > 1171.0) { - fine_phaserange = - 2097152; + fine_phaserange = -2097152; } else { - fine_phaserange = static_cast(std::round(phrng_m / meters_to_miliseconds / TWO_N29)); + fine_phaserange = static_cast(std::round(phrng_m / meters_to_miliseconds / TWO_N29)); } DF401 = std::bitset<22>(fine_phaserange); @@ -3939,167 +5292,194 @@ int Rtcm::set_DF401(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF402(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_period_s = 0; - unsigned int lock_time_indicator; + uint32_t lock_time_period_s = 0; + uint32_t lock_time_indicator; std::string sig_(gnss_synchro.Signal); - if(sig_.compare("1C")) + std::string sys(&gnss_synchro.System, 1); + if ((sig_.compare("1C") == 0) && (sys.compare("G") == 0)) { lock_time_period_s = Rtcm::lock_time(ephNAV, obs_time, gnss_synchro); } - if(sig_.compare("2S")) + if ((sig_.compare("2S") == 0) && (sys.compare("G") == 0)) { lock_time_period_s = Rtcm::lock_time(ephCNAV, obs_time, gnss_synchro); } - if(sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) + // TODO Should add system for galileo satellites + if (sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) { lock_time_period_s = Rtcm::lock_time(ephFNAV, obs_time, gnss_synchro); } + if ((sig_.compare("1C") == 0) && (sys.compare("R") == 0)) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } + if ((sig_.compare("2C") == 0) && (sys.compare("R") == 0)) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } lock_time_indicator = Rtcm::msm_lock_time_indicator(lock_time_period_s); DF402 = std::bitset<4>(lock_time_indicator); return 0; } -int Rtcm::set_DF403(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF403(const Gnss_Synchro& gnss_synchro) { - unsigned int cnr_dB_Hz; - cnr_dB_Hz = static_cast(std::round(gnss_synchro.CN0_dB_hz)); + uint32_t cnr_dB_Hz; + cnr_dB_Hz = static_cast(std::round(gnss_synchro.CN0_dB_hz)); DF403 = std::bitset<6>(cnr_dB_Hz); return 0; } -int Rtcm::set_DF404(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF404(const Gnss_Synchro& gnss_synchro) { double lambda = 0.0; std::string sig_(gnss_synchro.Signal); - std::string sig = sig_.substr(0,2); - int fine_phaserange_rate; + std::string sig = sig_.substr(0, 2); + int32_t fine_phaserange_rate; + std::string sys_(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig_.compare("1C") == 0) && (sys_.compare("G") == 0)) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig_.compare("2S") == 0) && (sys_.compare("G") == 0)) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig_.compare("5X") == 0) && (sys_.compare("E") == 0)) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig_.compare("1B") == 0) && (sys_.compare("E") == 0)) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig_.compare("7X") == 0) && (sys_.compare("E") == 0)) { - lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; + lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0)) + { + lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0)) + { + //TODO Need to add slot number and freq number to gnss syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_CA_FREQ_HZ); + } + double rough_phase_range_rate = std::round(-gnss_synchro.Carrier_Doppler_hz * lambda); + double phrr = (-gnss_synchro.Carrier_Doppler_hz * lambda - rough_phase_range_rate); - double rough_phase_range_rate = std::round(- gnss_synchro.Carrier_Doppler_hz * lambda ); - double phrr = (- gnss_synchro.Carrier_Doppler_hz * lambda - rough_phase_range_rate); - - if(phrr == 0.0) - { - fine_phaserange_rate = -16384; - } - else if(std::fabs(phrr) > 1.6384) - { - fine_phaserange_rate = -16384; - } - else - { - fine_phaserange_rate = static_cast(std::round(phrr / 0.0001)); - } + if (phrr == 0.0) + { + fine_phaserange_rate = -16384; + } + else if (std::fabs(phrr) > 1.6384) + { + fine_phaserange_rate = -16384; + } + else + { + fine_phaserange_rate = static_cast(std::round(phrr / 0.0001)); + } DF404 = std::bitset<15>(fine_phaserange_rate); return 0; } -int Rtcm::set_DF405(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF405(const Gnss_Synchro& gnss_synchro) { double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_m = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; double psrng_s; - long int fine_pseudorange; + int64_t fine_pseudorange; psrng_s = gnss_synchro.Pseudorange_m - rough_range_m; - if(psrng_s == 0.0) + if (psrng_s == 0.0) { - fine_pseudorange = - 524288; + fine_pseudorange = -524288; } - else if(std::fabs(psrng_s) > 292.7) + else if (std::fabs(psrng_s) > 292.7) { - fine_pseudorange = - 524288; + fine_pseudorange = -524288; } else { - fine_pseudorange = static_cast(std::round(psrng_s / meters_to_miliseconds / TWO_N29)); + fine_pseudorange = static_cast(std::round(psrng_s / meters_to_miliseconds / TWO_N29)); } DF405 = std::bitset<20>(fine_pseudorange); return 0; - } -int Rtcm::set_DF406(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF406(const Gnss_Synchro& gnss_synchro) { - long int fine_phaserange_ex; + int64_t fine_phaserange_ex; double meters_to_miliseconds = GPS_C_m_s * 0.001; double rough_range_m = std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10; double phrng_m; double lambda = 0.0; std::string sig_(gnss_synchro.Signal); - std::string sig = sig_.substr(0,2); + sig_ = sig_.substr(0, 2); + std::string sys_(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig_.compare("1C") == 0) && (sys_.compare("G") == 0)) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig_.compare("2S") == 0) && (sys_.compare("G") == 0)) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig_.compare("5X") == 0) && (sys_.compare("E") == 0)) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig_.compare("1B") == 0) && (sys_.compare("E") == 0)) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig_.compare("7X") == 0) && (sys_.compare("E") == 0)) { - lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; + lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0)) + { + lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0)) + { + //TODO Need to add slot number and freq number to gnss syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_CA_FREQ_HZ); + } + phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI) * lambda - rough_range_m; - phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI ) * lambda - rough_range_m; - - /* Substract phase - pseudorange integer cycle offset */ + /* Subtract phase - pseudorange integer cycle offset */ /* TODO: check LLI! */ - double cp = gnss_synchro.Carrier_phase_rads / GPS_TWO_PI; // ? - if(std::fabs(phrng_m - cp) > 1171.0) + double cp = gnss_synchro.Carrier_phase_rads / GPS_TWO_PI; // ? + if (std::fabs(phrng_m - cp) > 1171.0) { cp = std::round(phrng_m / lambda) * lambda; } phrng_m -= cp; - if(phrng_m == 0.0) + if (phrng_m == 0.0) { - fine_phaserange_ex = - 8388608; + fine_phaserange_ex = -8388608; } - else if(std::fabs(phrng_m) > 1171.0) + else if (std::fabs(phrng_m) > 1171.0) { - fine_phaserange_ex = - 8388608; + fine_phaserange_ex = -8388608; } else { - fine_phaserange_ex = static_cast(std::round(phrng_m / meters_to_miliseconds / TWO_N31)); + fine_phaserange_ex = static_cast(std::round(phrng_m / meters_to_miliseconds / TWO_N31)); } DF406 = std::bitset<24>(fine_phaserange_ex); @@ -4107,96 +5487,105 @@ int Rtcm::set_DF406(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF407(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro) { - unsigned int lock_time_indicator; - unsigned int lock_time_period_s = 0; + uint32_t lock_time_indicator; + uint32_t lock_time_period_s = 0; std::string sig_(gnss_synchro.Signal); - if(sig_.compare("1C")) + std::string sys_(&gnss_synchro.System, 1); + if ((sig_.compare("1C")) && (sys_.compare("G") == 0)) { lock_time_period_s = Rtcm::lock_time(ephNAV, obs_time, gnss_synchro); } - if(sig_.compare("2S")) + if ((sig_.compare("2S")) && (sys_.compare("G") == 0)) { lock_time_period_s = Rtcm::lock_time(ephCNAV, obs_time, gnss_synchro); } - if(sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) + if ((sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) && (sys_.compare("E") == 0)) { lock_time_period_s = Rtcm::lock_time(ephFNAV, obs_time, gnss_synchro); } + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0)) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0)) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } lock_time_indicator = Rtcm::msm_extended_lock_time_indicator(lock_time_period_s); DF407 = std::bitset<10>(lock_time_indicator); return 0; } -int Rtcm::set_DF408(const Gnss_Synchro & gnss_synchro) +int32_t Rtcm::set_DF408(const Gnss_Synchro& gnss_synchro) { - unsigned int cnr_dB_Hz; - cnr_dB_Hz = static_cast(std::round(gnss_synchro.CN0_dB_hz / 0.0625)); + uint32_t cnr_dB_Hz; + cnr_dB_Hz = static_cast(std::round(gnss_synchro.CN0_dB_hz / 0.0625)); DF408 = std::bitset<10>(cnr_dB_Hz); return 0; } -int Rtcm::set_DF409(unsigned int iods) +int32_t Rtcm::set_DF409(uint32_t iods) { DF409 = std::bitset<3>(iods); return 0; } -int Rtcm::set_DF411(unsigned int clock_steering_indicator) +int32_t Rtcm::set_DF411(uint32_t clock_steering_indicator) { DF411 = std::bitset<2>(clock_steering_indicator); return 0; } -int Rtcm::set_DF412(unsigned int external_clock_indicator) +int32_t Rtcm::set_DF412(uint32_t external_clock_indicator) { DF412 = std::bitset<2>(external_clock_indicator); return 0; } -int Rtcm::set_DF417(bool using_divergence_free_smoothing) +int32_t Rtcm::set_DF417(bool using_divergence_free_smoothing) { DF417 = std::bitset<1>(using_divergence_free_smoothing); return 0; } -int Rtcm::set_DF418(int carrier_smoothing_interval_s) +int32_t Rtcm::set_DF418(int32_t carrier_smoothing_interval_s) { - if(carrier_smoothing_interval_s < 0) + if (carrier_smoothing_interval_s < 0) { DF418 = std::bitset<3>("111"); } else { - if(carrier_smoothing_interval_s == 0) + if (carrier_smoothing_interval_s == 0) { DF418 = std::bitset<3>("000"); } - else if(carrier_smoothing_interval_s < 30) + else if (carrier_smoothing_interval_s < 30) { DF418 = std::bitset<3>("001"); } - else if(carrier_smoothing_interval_s < 60) + else if (carrier_smoothing_interval_s < 60) { DF418 = std::bitset<3>("010"); } - else if(carrier_smoothing_interval_s < 120) + else if (carrier_smoothing_interval_s < 120) { DF418 = std::bitset<3>("011"); } - else if(carrier_smoothing_interval_s < 240) + else if (carrier_smoothing_interval_s < 240) { DF418 = std::bitset<3>("100"); } - else if(carrier_smoothing_interval_s < 480) + else if (carrier_smoothing_interval_s < 480) { DF418 = std::bitset<3>("101"); } @@ -4209,7 +5598,7 @@ int Rtcm::set_DF418(int carrier_smoothing_interval_s) } -int Rtcm::set_DF420(const Gnss_Synchro & gnss_synchro __attribute__((unused))) +int32_t Rtcm::set_DF420(const Gnss_Synchro& gnss_synchro __attribute__((unused))) { // todo: read the value from gnss_synchro bool half_cycle_ambiguity_indicator = true; diff --git a/src/core/system_parameters/rtcm.h b/src/core/system_parameters/rtcm.h index 37cdab1f4..77696cf88 100644 --- a/src/core/system_parameters/rtcm.h +++ b/src/core/system_parameters/rtcm.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,7 +33,17 @@ #define GNSS_SDR_RTCM_H_ +#include "concurrent_queue.h" +#include "galileo_fnav_message.h" +#include "glonass_gnav_navigation_message.h" +#include "gnss_synchro.h" +#include "gps_cnav_navigation_message.h" +#include "gps_navigation_message.h" +#include +#include +#include #include +#include #include #include #include @@ -42,13 +52,6 @@ #include #include #include -#include -#include -#include "concurrent_queue.h" -#include "gnss_synchro.h" -#include "galileo_fnav_message.h" -#include "gps_navigation_message.h" -#include "gps_cnav_navigation_message.h" /*! @@ -56,7 +59,7 @@ * defined in the RTCM 3.2 Standard, plus some utilities to handle messages. * * Generation of the following Message Types: - * 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1019, 1029, 1045 + * 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1019, 1020, 1029, 1045 * * Decoding of the following Message Types: * 1019, 1045 @@ -83,280 +86,438 @@ class Rtcm { public: - Rtcm(unsigned short port = 2101); // & observables, unsigned short station_id); + std::string print_MT1001(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables, uint16_t station_id); /*! * \brief Prints message type 1002 (Extended L1-Only GPS RTK Observables) */ - std::string print_MT1002(const Gps_Ephemeris & gps_eph, double obs_time, const std::map & observables, unsigned short station_id); + std::string print_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map& observables, uint16_t station_id); /*! * \brief Prints message type 1003 (L1 & L2 GPS RTK Observables) */ - std::string print_MT1003(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id); + std::string print_MT1003(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id); /*! * \brief Prints message type 1004 (Extended L1 & L2 GPS RTK Observables) */ - std::string print_MT1004(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id); + std::string print_MT1004(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const std::map& observables, uint16_t station_id); /*! * \brief Prints message type 1005 (Stationary Antenna Reference Point) */ - std::string print_MT1005(unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator); + std::string print_MT1005(uint32_t ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, uint32_t quarter_cycle_indicator); /*! * \brief Verifies and reads messages of type 1005 (Stationary Antenna Reference Point). Returns 1 if anything goes wrong, 0 otherwise. */ - int read_MT1005(const std::string & message, unsigned int & ref_id, double & ecef_x, double & ecef_y, double & ecef_z, bool & gps, bool & glonass, bool & galileo); + int32_t read_MT1005(const std::string& message, uint32_t& ref_id, double& ecef_x, double& ecef_y, double& ecef_z, bool& gps, bool& glonass, bool& galileo); /*! * \brief Prints message type 1006 (Stationary Antenna Reference Point, with Height Information) */ - std::string print_MT1006(unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator, double height); + std::string print_MT1006(uint32_t ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, uint32_t quarter_cycle_indicator, double height); std::string print_MT1005_test(); //& observables, uint16_t station_id); + /*! + * \brief Prints Extended L1-Only GLONASS RTK Observables + * \details This GLONASS message type is used when only L1 data is present and bandwidth is very tight, often 1012 is used in such cases. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map& observables, uint16_t station_id); + /*! + * \brief Prints L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables, uint16_t station_id); + /*! + * \brief Prints Extended L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is the most common observational message type, with L1/L2/SNR content. This is one of the most common messages found. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map& observables, uint16_t station_id); /*! * \brief Prints message type 1019 (GPS Ephemeris), should be broadcast in the event that * the IODC does not match the IODE, and every 2 minutes. */ - std::string print_MT1019(const Gps_Ephemeris & gps_eph); + std::string print_MT1019(const Gps_Ephemeris& gps_eph); /*! * \brief Verifies and reads messages of type 1019 (GPS Ephemeris). Returns 1 if anything goes wrong, 0 otherwise. */ - int read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph); + int32_t read_MT1019(const std::string& message, Gps_Ephemeris& gps_eph); + + /*! + * \brief Prints message type 1020 (GLONASS Ephemeris). + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param glonass_gnav_utc_model GLONASS GNAV Clock Information + * \return Returns message type as a string type + */ + std::string print_MT1020(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); + + /*! + * \brief Verifies and reads messages of type 1020 (GLONASS Ephemeris). + * \note Code added as part of GSoC 2017 program + * \param message Message to read as a string type + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param glonass_gnav_utc_model GLONASS GNAV Clock Information + * \return Returns 1 if anything goes wrong, 0 otherwise. + */ + int32_t read_MT1020(const std::string& message, Glonass_Gnav_Ephemeris& glonass_gnav_eph, Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); /*! * \brief Prints message type 1029 (Unicode Text String) */ - std::string print_MT1029(unsigned int ref_id, const Gps_Ephemeris & gps_eph, double obs_time, const std::string & message); + std::string print_MT1029(uint32_t ref_id, const Gps_Ephemeris& gps_eph, double obs_time, const std::string& message); /*! * \brief Prints message type 1045 (Galileo Ephemeris), should be broadcast every 2 minutes */ - std::string print_MT1045(const Galileo_Ephemeris & gal_eph); + std::string print_MT1045(const Galileo_Ephemeris& gal_eph); /*! * \brief Verifies and reads messages of type 1045 (Galileo Ephemeris). Returns 1 if anything goes wrong, 0 otherwise. */ - int read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph); + int32_t read_MT1045(const std::string& message, Galileo_Ephemeris& gal_eph); /*! * \brief Prints messages of type MSM1 (Compact GNSS observables) */ - std::string print_MSM_1( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_1(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM2 (Compact GNSS phaseranges) */ - std::string print_MSM_2( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_2(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM3 (Compact GNSS pseudoranges and phaseranges) */ - std::string print_MSM_3( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_3(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM4 (Full GNSS pseudoranges and phaseranges plus CNR) */ - std::string print_MSM_4( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_4(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM5 (Full GNSS pseudoranges, phaseranges, phaserange rate and CNR) */ - std::string print_MSM_5( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_5(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM6 (Full GNSS pseudoranges and phaseranges plus CNR, high resolution) */ - std::string print_MSM_6( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_6(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); /*! * \brief Prints messages of type MSM7 (Full GNSS pseudoranges, phaseranges, phaserange rate and CNR, high resolution) */ - std::string print_MSM_7( const Gps_Ephemeris & gps_eph, - const Gps_CNAV_Ephemeris & gps_cnav_eph, - const Galileo_Ephemeris & gal_eph, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + std::string print_MSM_7(const Gps_Ephemeris& gps_eph, + const Gps_CNAV_Ephemeris& gps_cnav_eph, + const Galileo_Ephemeris& gal_eph, + const Glonass_Gnav_Ephemeris& glo_gnav_eph, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); - unsigned int lock_time(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); // get_MT1001_4_header(unsigned int msg_number, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int smooth_int, - bool sync_flag, - bool divergence_free); + std::bitset<64> get_MT1001_4_header(uint32_t msg_number, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t smooth_int, + bool sync_flag, + bool divergence_free); - std::bitset<58> get_MT1001_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); - std::bitset<74> get_MT1002_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); - std::bitset<101> get_MT1003_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); - std::bitset<125> get_MT1004_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + std::bitset<58> get_MT1001_sat_content(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); + std::bitset<74> get_MT1002_sat_content(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); + std::bitset<101> get_MT1003_sat_content(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); + std::bitset<125> get_MT1004_sat_content(const Gps_Ephemeris& ephL1, const Gps_CNAV_Ephemeris& ephL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); std::bitset<152> get_MT1005_test(); - std::string get_MSM_header(unsigned int msg_number, - double obs_time, - const std::map & observables, - unsigned int ref_id, - unsigned int clock_steering_indicator, - unsigned int external_clock_indicator, - int smooth_int, - bool divergence_free, - bool more_messages); + /*! + * \brief Generates contents of message header for types 1009, 1010, 1011 and 1012. GLONASS RTK Message + * \note Code added as part of GSoC 2017 program + * \param msg_number Message type number, acceptable options include 1009 to 1012 + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \param ref_id + * \param smooth_int + * \param divergence_free + * \return Returns the message header content as set of bits + */ + std::bitset<61> get_MT1009_12_header(uint32_t msg_number, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t smooth_int, + bool sync_flag, + bool divergence_free); - std::string get_MSM_1_content_sat_data(const std::map & observables); - std::string get_MSM_4_content_sat_data(const std::map & observables); - std::string get_MSM_5_content_sat_data(const std::map & observables); + /*! + * \brief Get the contents of the satellite specific portion of a type 1009 Message (GLONASS Basic RTK, L1 Only) + * \details Contents generated for each satellite. See table 3.5-11 + * \note Code added as part of GSoC 2017 program + * \param ephGNAV Ephemeris for GLONASS GNAV in L1 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchro Information generated by channels while processing the satellite + * \return Returns the message content as set of bits + */ + std::bitset<64> get_MT1009_sat_content(const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro); + /*! + * \brief Get the contents of the satellite specific portion of a type 1010 Message (GLONASS Extended RTK, L1 Only) + * \details Contents generated for each satellite. See table 3.5-12 + * \note Code added as part of GSoC 2017 program + * \param ephGNAV Ephemeris for GLONASS GNAV in L1 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchro Information generated by channels while processing the satellite + * \return Returns the message content as set of bits + */ + std::bitset<79> get_MT1010_sat_content(const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro); + /*! + * \brief Get the contents of the satellite specific portion of a type 1011 Message (GLONASS Basic RTK, L1 & L2) + * \details Contents generated for each satellite. See table 3.5-13 + * \note Code added as part of GSoC 2017 program + * \param ephGNAVL1 Ephemeris for GLONASS GNAV in L1 satellites + * \param ephGNAVL2 Ephemeris for GLONASS GNAV in L2 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchroL1 Information generated by channels while processing the GLONASS GNAV L1 satellite + * \param gnss_synchroL2 Information generated by channels while processing the GLONASS GNAV L2 satellite + * \return Returns the message content as set of bits + */ + std::bitset<107> get_MT1011_sat_content(const Glonass_Gnav_Ephemeris& ephGNAVL1, const Glonass_Gnav_Ephemeris& ephGNAVL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); + /*! + * \brief Get the contents of the satellite specific portion of a type 1012 Message (GLONASS Extended RTK, L1 & L2) + * \details Contents generated for each satellite. See table 3.5-14 + * \note Code added as part of GSoC 2017 program + * \param ephGNAVL1 Ephemeris for GLONASS GNAV in L1 satellites + * \param ephGNAVL2 Ephemeris for GLONASS GNAV in L2 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchroL1 Information generated by channels while processing the GLONASS GNAV L1 satellite + * \param gnss_synchroL2 Information generated by channels while processing the GLONASS GNAV L2 satellite + * \return Returns the message content as set of bits + */ + std::bitset<130> get_MT1012_sat_content(const Glonass_Gnav_Ephemeris& ephGNAVL1, const Glonass_Gnav_Ephemeris& ephGNAVL2, double obs_time, const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); - std::string get_MSM_1_content_signal_data(const std::map & observables); - std::string get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); + std::string get_MSM_header(uint32_t msg_number, + double obs_time, + const std::map& observables, + uint32_t ref_id, + uint32_t clock_steering_indicator, + uint32_t external_clock_indicator, + int32_t smooth_int, + bool divergence_free, + bool more_messages); + + std::string get_MSM_1_content_sat_data(const std::map& observables); + std::string get_MSM_4_content_sat_data(const std::map& observables); + std::string get_MSM_5_content_sat_data(const std::map& observables); + + std::string get_MSM_1_content_signal_data(const std::map& observables); + std::string get_MSM_2_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); + std::string get_MSM_3_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); + std::string get_MSM_4_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); + std::string get_MSM_5_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); + std::string get_MSM_6_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); + std::string get_MSM_7_content_signal_data(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const std::map& observables); // // Utilities // static std::map galileo_signal_map; static std::map gps_signal_map; - std::vector > sort_by_signal(const std::vector > & synchro_map) const; - std::vector > sort_by_PRN_mask(const std::vector > & synchro_map) const; + std::vector > sort_by_signal(const std::vector >& synchro_map) const; + std::vector > sort_by_PRN_mask(const std::vector >& synchro_map) const; boost::posix_time::ptime compute_GPS_time(const Gps_Ephemeris& eph, double obs_time) const; - boost::posix_time::ptime compute_GPS_time(const Gps_CNAV_Ephemeris & eph, double obs_time) const; + boost::posix_time::ptime compute_GPS_time(const Gps_CNAV_Ephemeris& eph, double obs_time) const; boost::posix_time::ptime compute_Galileo_time(const Galileo_Ephemeris& eph, double obs_time) const; + boost::posix_time::ptime compute_GLONASS_time(const Glonass_Gnav_Ephemeris& eph, double obs_time) const; boost::posix_time::ptime gps_L1_last_lock_time[64]; boost::posix_time::ptime gps_L2_last_lock_time[64]; boost::posix_time::ptime gal_E1_last_lock_time[64]; boost::posix_time::ptime gal_E5_last_lock_time[64]; - unsigned int lock_time_indicator(unsigned int lock_time_period_s); - unsigned int msm_lock_time_indicator(unsigned int lock_time_period_s); - unsigned int msm_extended_lock_time_indicator(unsigned int lock_time_period_s); + boost::posix_time::ptime glo_L1_last_lock_time[64]; + boost::posix_time::ptime glo_L2_last_lock_time[64]; + uint32_t lock_time_indicator(uint32_t lock_time_period_s); + uint32_t msm_lock_time_indicator(uint32_t lock_time_period_s); + uint32_t msm_extended_lock_time_indicator(uint32_t lock_time_period_s); // // Classes for TCP communication // - unsigned short RTCM_port; - //unsigned short RTCM_Station_ID; + uint16_t RTCM_port; + //uint16_t RTCM_Station_ID; class Rtcm_Message { public: - enum { header_length = 6 }; - enum { max_body_length = 1029 }; + enum + { + header_length = 6 + }; + enum + { + max_body_length = 1029 + }; Rtcm_Message() - : body_length_(0) - { } + : body_length_(0) + { + } const char* data() const { @@ -368,7 +529,7 @@ private: return data_; } - std::size_t length() const + inline std::size_t length() const { return header_length + body_length_; } @@ -395,19 +556,19 @@ private: body_length_ = max_body_length; } - bool decode_header() + inline bool decode_header() { char header[header_length + 1] = ""; std::strncat(header, data_, header_length); - if(header[0] != 'G' || header[1] != 'S') + if (header[0] != 'G' || header[1] != 'S') { return false; } char header2_[header_length - 1] = ""; - std::strncat(header2_, data_ + 2 , header_length - 2); + std::strncat(header2_, data_ + 2, header_length - 2); body_length_ = std::atoi(header2_); - if(body_length_ == 0) + if (body_length_ == 0) { return false; } @@ -420,7 +581,7 @@ private: return true; } - void encode_header() + inline void encode_header() { char header[header_length + 1] = ""; std::sprintf(header, "GS%4d", static_cast(body_length_)); @@ -436,57 +597,59 @@ private: class Rtcm_Listener { public: - virtual ~Rtcm_Listener() {} - virtual void deliver(const Rtcm_Message & msg) = 0; + virtual ~Rtcm_Listener() = default; + virtual void deliver(const Rtcm_Message& msg) = 0; }; class Rtcm_Listener_Room { public: - void join(std::shared_ptr participant) + inline void join(std::shared_ptr participant) { participants_.insert(participant); - for (auto msg: recent_msgs_) + for (auto msg : recent_msgs_) participant->deliver(msg); } - void leave(std::shared_ptr participant) + inline void leave(std::shared_ptr participant) { participants_.erase(participant); } - void deliver(const Rtcm_Message & msg) + inline void deliver(const Rtcm_Message& msg) { recent_msgs_.push_back(msg); while (recent_msgs_.size() > max_recent_msgs) recent_msgs_.pop_front(); - for (auto participant: participants_) + for (auto participant : participants_) participant->deliver(msg); } private: std::set > participants_; - enum { max_recent_msgs = 1 }; + enum + { + max_recent_msgs = 1 + }; std::deque recent_msgs_; }; class Rtcm_Session - : public Rtcm_Listener, - public std::enable_shared_from_this + : public Rtcm_Listener, + public std::enable_shared_from_this { public: - Rtcm_Session(boost::asio::ip::tcp::socket socket, Rtcm_Listener_Room & room) : socket_(std::move(socket)), room_(room) { } - - void start() + Rtcm_Session(boost::asio::ip::tcp::socket socket, Rtcm_Listener_Room& room) : socket_(std::move(socket)), room_(room) {} + inline void start() { room_.join(shared_from_this()); do_read_message_header(); } - void deliver(const Rtcm_Message & msg) + inline void deliver(const Rtcm_Message& msg) { bool write_in_progress = !write_msgs_.empty(); write_msgs_.push_back(msg); @@ -497,89 +660,86 @@ private: } private: - void do_read_message_header() + inline void do_read_message_header() { auto self(shared_from_this()); boost::asio::async_read(socket_, - boost::asio::buffer(read_msg_.data(), Rtcm_Message::header_length), - [this, self](boost::system::error_code ec, std::size_t /*length*/) - { - if (!ec && read_msg_.decode_header()) - { - do_read_message_body(); - } - else if(!ec && !read_msg_.decode_header()) - { - client_says += read_msg_.data(); - bool first = true; - while(client_says.length() >= 80) - { - if(first == true) - { - std::cout << "Client from " << socket_.remote_endpoint().address() << " says "; - first = false; - } - std::cout << client_says.substr(0, 80) << std::endl; - client_says = client_says.substr(80, client_says.length() - 80); - } - do_read_message_header(); - } - else - { - std::cout << "Closing connection with client from " << socket_.remote_endpoint().address() << std::endl; - room_.leave(shared_from_this()); - } - }); + boost::asio::buffer(read_msg_.data(), Rtcm_Message::header_length), + [this, self](boost::system::error_code ec, std::size_t /*length*/) { + if (!ec and read_msg_.decode_header()) + { + do_read_message_body(); + } + else if (!ec and !read_msg_.decode_header()) + { + client_says += read_msg_.data(); + bool first = true; + while (client_says.length() >= 80) + { + if (first == true) + { + LOG(INFO) << "Client says:"; + first = false; + } + LOG(INFO) << client_says; + client_says = client_says.substr(80, client_says.length() - 80); + } + do_read_message_header(); + } + else + { + std::cout << "Closing connection with RTCM client" << std::endl; + room_.leave(shared_from_this()); + } + }); } - void do_read_message_body() + inline void do_read_message_body() { auto self(shared_from_this()); boost::asio::async_read(socket_, - boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), - [this, self](boost::system::error_code ec, std::size_t /*length*/) - { - if (!ec) - { - room_.deliver(read_msg_); - //std::cout << "Delivered message (session): "; - //std::cout.write(read_msg_.body(), read_msg_.body_length()); - //std::cout << std::endl; - do_read_message_header(); - } - else - { - std::cout << "Closing connection with client from " << socket_.remote_endpoint().address() << std::endl; - room_.leave(shared_from_this()); - } - }); + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + [this, self](boost::system::error_code ec, std::size_t /*length*/) { + if (!ec) + { + room_.deliver(read_msg_); + //std::cout << "Delivered message (session): "; + //std::cout.write(read_msg_.body(), read_msg_.body_length()); + //std::cout << std::endl; + do_read_message_header(); + } + else + { + std::cout << "Closing connection with RTCM client" << std::endl; + room_.leave(shared_from_this()); + } + }); } - void do_write() + inline void do_write() { auto self(shared_from_this()); boost::asio::async_write(socket_, - boost::asio::buffer(write_msgs_.front().body(), - write_msgs_.front().body_length()), [this, self](boost::system::error_code ec, std::size_t /*length*/) - { - if(!ec) - { - write_msgs_.pop_front(); - if(!write_msgs_.empty()) - { - do_write(); - } - } - else - { - std::cout << "Closing connection with client from " << socket_.remote_endpoint().address() << std::endl; - room_.leave(shared_from_this()); - } - }); + boost::asio::buffer(write_msgs_.front().body(), write_msgs_.front().body_length()), + [this, self](boost::system::error_code ec, std::size_t /*length*/) { + if (!ec) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + do_write(); + } + } + else + { + std::cout << "Closing connection with RTCM client" << std::endl; + room_.leave(shared_from_this()); + } + }); } boost::asio::ip::tcp::socket socket_; - Rtcm_Listener_Room & room_; + Rtcm_Listener_Room& room_; Rtcm_Message read_msg_; std::deque write_msgs_; std::string client_says; @@ -587,93 +747,88 @@ private: class Tcp_Internal_Client - : public std::enable_shared_from_this + : public std::enable_shared_from_this { public: - Tcp_Internal_Client(boost::asio::io_service& io_service, - boost::asio::ip::tcp::resolver::iterator endpoint_iterator) - : io_service_(io_service), socket_(io_service) - { - do_connect(endpoint_iterator); - } - - void close() + Tcp_Internal_Client(boost::asio::io_service& io_context, + boost::asio::ip::tcp::resolver::iterator endpoint_iterator) + : io_context_(io_context), socket_(io_context) { - io_service_.post([this]() { socket_.close(); }); + do_connect(endpoint_iterator); } - void write(const Rtcm_Message & msg) + inline void close() { - io_service_.post( - [this, msg]() - { - bool write_in_progress = !write_msgs_.empty(); - write_msgs_.push_back(msg); - if (!write_in_progress) - { - do_write(); - } - }); + io_context_.post([this]() { socket_.close(); }); + } + + inline void write(const Rtcm_Message& msg) + { + io_context_.post( + [this, msg]() { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.push_back(msg); + if (!write_in_progress) + { + do_write(); + } + }); } private: - void do_connect(boost::asio::ip::tcp::resolver::iterator endpoint_iterator) + inline void do_connect(boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { boost::asio::async_connect(socket_, endpoint_iterator, - [this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator) - { - if (!ec) - { - do_read_message(); - } - else - { - std::cout << "Server is down." << std::endl; - } - }); + [this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator) { + if (!ec) + { + do_read_message(); + } + else + { + std::cout << "Server is down." << std::endl; + } + }); } - void do_read_message() + inline void do_read_message() { boost::asio::async_read(socket_, - boost::asio::buffer(read_msg_.data(), 1029), - [this](boost::system::error_code ec, std::size_t /*length*/) - { - if (!ec ) - { - do_read_message(); - } - else - { - std::cout << "Error in client" << std::endl; - socket_.close(); - } - }); + boost::asio::buffer(read_msg_.data(), 1029), + [this](boost::system::error_code ec, std::size_t /*length*/) { + if (!ec) + { + do_read_message(); + } + else + { + std::cout << "Error in client" << std::endl; + socket_.close(); + } + }); } - void do_write() + inline void do_write() { - boost::asio::async_write(socket_, - boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), - [this](boost::system::error_code ec, std::size_t /*length*/) - { - if (!ec) - { - write_msgs_.pop_front(); - if (!write_msgs_.empty()) - { - do_write(); - } - } - else - { - socket_.close(); - } - }); + boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), + [this](boost::system::error_code ec, std::size_t /*length*/) { + if (!ec) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + do_write(); + } + } + else + { + socket_.close(); + } + }); } - boost::asio::io_service& io_service_; + boost::asio::io_service& io_context_; boost::asio::ip::tcp::socket socket_; Rtcm_Message read_msg_; std::deque write_msgs_; @@ -683,92 +838,106 @@ private: class Queue_Reader { public: - Queue_Reader(boost::asio::io_service& io_service, std::shared_ptr< concurrent_queue > & queue, int port) : queue_(queue) - { - boost::asio::ip::tcp::resolver resolver(io_service); + Queue_Reader(boost::asio::io_service& io_context, std::shared_ptr >& queue, int32_t port) : queue_(queue) + { + boost::asio::ip::tcp::resolver resolver(io_context); std::string host("localhost"); std::string port_str = std::to_string(port); - auto queue_endpoint_iterator = resolver.resolve({ host.c_str(), port_str.c_str() }); - c = std::make_shared(io_service, queue_endpoint_iterator); - } + auto queue_endpoint_iterator = resolver.resolve({host.c_str(), port_str.c_str()}); + c = std::make_shared(io_context, queue_endpoint_iterator); + } - void do_read_queue() + inline void do_read_queue() { - for(;;) + for (;;) { std::string message; Rtcm_Message msg; - queue_->wait_and_pop(message); //message += '\n'; - if(message.compare("Goodbye") == 0) break; - const char *char_msg = message.c_str(); + queue_->wait_and_pop(message); //message += '\n'; + if (message == "Goodbye") break; + const char* char_msg = message.c_str(); msg.body_length(message.length()); std::memcpy(msg.body(), char_msg, msg.body_length()); msg.encode_header(); c->write(msg); } } + private: std::shared_ptr c; - std::shared_ptr< concurrent_queue > & queue_; + std::shared_ptr >& queue_; }; class Tcp_Server { public: - Tcp_Server(boost::asio::io_service& io_service, const boost::asio::ip::tcp::endpoint& endpoint) - : io_service_(io_service), acceptor_(io_service), socket_(io_service) - { + Tcp_Server(boost::asio::io_service& io_context, const boost::asio::ip::tcp::endpoint& endpoint) + : acceptor_(io_context), socket_(io_context) + { acceptor_.open(endpoint.protocol()); acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); acceptor_.bind(endpoint); acceptor_.listen(); do_accept(); - } + } - void close_server() + inline void close_server() { socket_.close(); acceptor_.close(); } private: - void do_accept() + inline void do_accept() { - acceptor_.async_accept(socket_, [this](boost::system::error_code ec) - { + acceptor_.async_accept(socket_, [this](boost::system::error_code ec) { if (!ec) { - if(first_client) + if (first_client) { - std::cout << "The TCP Server is up and running. Accepting connections ..." << std::endl; + std::cout << "The TCP/IP server of RTCM messages is up and running. Accepting connections ..." << std::endl; first_client = false; } else { - std::cout << "Starting RTCM TCP server session..." << std::endl; - std::cout << "Serving client from " << socket_.remote_endpoint().address() << std::endl; + std::cout << "Starting RTCM TCP/IP server session..." << std::endl; + boost::system::error_code ec2; + boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(ec2); + if (ec2) + { + // Error creating remote_endpoint + std::cout << "Error getting remote IP address, closing session." << std::endl; + LOG(INFO) << "Error getting remote IP address"; + start_session = false; + } + else + { + std::string remote_addr = endpoint.address().to_string(); + std::cout << "Serving client from " << remote_addr << std::endl; + LOG(INFO) << "Serving client from " << remote_addr; + } } - std::make_shared(std::move(socket_), room_)->start(); + if (start_session) std::make_shared(std::move(socket_), room_)->start(); } else { std::cout << "Error when invoking a RTCM session. " << ec << std::endl; } + start_session = true; do_accept(); - }); + }); } - boost::asio::io_service& io_service_; boost::asio::ip::tcp::acceptor acceptor_; boost::asio::ip::tcp::socket socket_; Rtcm_Listener_Room room_; bool first_client = true; + bool start_session = true; }; - - boost::asio::io_service io_service; - std::shared_ptr< concurrent_queue > rtcm_message_queue; + boost::asio::io_service io_context; + std::shared_ptr > rtcm_message_queue; std::thread t; std::thread tq; std::list servers; @@ -780,357 +949,515 @@ private: // std::bitset<8> preamble; std::bitset<6> reserved_field; - std::string add_CRC(const std::string & m) const; - std::string build_message(const std::string & data) const; // adds 0s to complete a byte and adds the CRC + std::string add_CRC(const std::string& m) const; + std::string build_message(const std::string& data) const; // adds 0s to complete a byte and adds the CRC // // Data Fields // std::bitset<12> DF002; - int set_DF002(unsigned int message_number); + int32_t set_DF002(uint32_t message_number); std::bitset<12> DF003; - int set_DF003(unsigned int ref_station_ID); + int32_t set_DF003(uint32_t ref_station_ID); std::bitset<30> DF004; - int set_DF004(double obs_time); + int32_t set_DF004(double obs_time); std::bitset<1> DF005; - int set_DF005(bool sync_flag); + int32_t set_DF005(bool sync_flag); std::bitset<5> DF006; - int set_DF006(const std::map & observables); + int32_t set_DF006(const std::map& observables); std::bitset<1> DF007; - int set_DF007(bool divergence_free_smoothing_indicator); // 0 - Divergence-free smoothing not used 1 - Divergence-free smoothing used + int32_t set_DF007(bool divergence_free_smoothing_indicator); // 0 - Divergence-free smoothing not used 1 - Divergence-free smoothing used std::bitset<3> DF008; - int set_DF008(short int smoothing_interval); + int32_t set_DF008(int16_t smoothing_interval); std::bitset<6> DF009; - int set_DF009(const Gnss_Synchro & gnss_synchro); - int set_DF009(const Gps_Ephemeris & gps_eph); + int32_t set_DF009(const Gnss_Synchro& gnss_synchro); + int32_t set_DF009(const Gps_Ephemeris& gps_eph); std::bitset<1> DF010; - int set_DF010(bool code_indicator); + int32_t set_DF010(bool code_indicator); std::bitset<24> DF011; - int set_DF011(const Gnss_Synchro & gnss_synchro); + int32_t set_DF011(const Gnss_Synchro& gnss_synchro); std::bitset<20> DF012; - int set_DF012(const Gnss_Synchro & gnss_synchro); + int32_t set_DF012(const Gnss_Synchro& gnss_synchro); std::bitset<7> DF013; - int set_DF013(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); + int32_t set_DF013(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); std::bitset<8> DF014; - int set_DF014(const Gnss_Synchro & gnss_synchro); + int32_t set_DF014(const Gnss_Synchro& gnss_synchro); std::bitset<8> DF015; - int set_DF015(const Gnss_Synchro & gnss_synchro); + int32_t set_DF015(const Gnss_Synchro& gnss_synchro); std::bitset<14> DF017; - int set_DF017(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + int32_t set_DF017(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); std::bitset<20> DF018; - int set_DF018(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + int32_t set_DF018(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); std::bitset<7> DF019; - int set_DF019(const Gps_CNAV_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); + int32_t set_DF019(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); std::bitset<8> DF020; - int set_DF020(const Gnss_Synchro & gnss_synchro); + int32_t set_DF020(const Gnss_Synchro& gnss_synchro); std::bitset<6> DF021; - int set_DF021(); + int32_t set_DF021(); std::bitset<1> DF022; - int set_DF022(bool gps_indicator); + int32_t set_DF022(bool gps_indicator); std::bitset<1> DF023; - int set_DF023(bool glonass_indicator); + int32_t set_DF023(bool glonass_indicator); std::bitset<1> DF024; - int set_DF024(bool galileo_indicator); + int32_t set_DF024(bool galileo_indicator); std::bitset<38> DF025; - int set_DF025(double antenna_ECEF_X_m); + int32_t set_DF025(double antenna_ECEF_X_m); std::bitset<38> DF026; - int set_DF026(double antenna_ECEF_Y_m); + int32_t set_DF026(double antenna_ECEF_Y_m); std::bitset<38> DF027; - int set_DF027(double antenna_ECEF_Z_m); + int32_t set_DF027(double antenna_ECEF_Z_m); std::bitset<16> DF028; - int set_DF028(double height); + int32_t set_DF028(double height); std::bitset<8> DF029; std::bitset<8> DF031; - int set_DF031(unsigned int antenna_setup_id); + int32_t set_DF031(uint32_t antenna_setup_id); std::bitset<8> DF032; + /*! + * \brief Sets the Data Field value + * \note Code added as part of GSoC 2017 program + * \param obs_time Time of observation at the moment of printing + * \return returns 0 upon success + */ + int32_t set_DF034(double obs_time); + std::bitset<27> DF034; //!< GLONASS Epoch Time (tk) + + std::bitset<5> DF035; //!< No. of GLONASS Satellite Signals Processed + int32_t set_DF035(const std::map& observables); + + std::bitset<1> DF036; //!< GLONASS Divergence-free Smoothing Indicator + int32_t set_DF036(bool divergence_free_smoothing_indicator); + + std::bitset<3> DF037; //!< GLONASS Smoothing Interval + int32_t set_DF037(int16_t smoothing_interval); + + std::bitset<6> DF038; //!< GLONASS Satellite ID (Satellite Slot Number) + int32_t set_DF038(const Gnss_Synchro& gnss_synchro); + int32_t set_DF038(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF039; //!< GLONASS L1 Code Indicator + int32_t set_DF039(bool code_indicator); + + std::bitset<5> DF040; //!< GLONASS Satellite Frequency Number + int32_t set_DF040(int32_t frequency_channel_number); + int32_t set_DF040(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<25> DF041; //!< GLONASS L1 Pseudorange + int32_t set_DF041(const Gnss_Synchro& gnss_synchro); + + std::bitset<20> DF042; //!< GLONASS L1 PhaseRange - L1 Pseudorange + int32_t set_DF042(const Gnss_Synchro& gnss_synchro); + + std::bitset<7> DF043; //!< GLONASS L1 Lock Time Indicator + int32_t set_DF043(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); + + std::bitset<7> DF044; //!< GLONASS Integer L1 Pseudorange Modulus Ambiguity + int32_t set_DF044(const Gnss_Synchro& gnss_synchro); + + std::bitset<8> DF045; //!< GLONASS L1 CNR + int32_t set_DF045(const Gnss_Synchro& gnss_synchro); + + std::bitset<2> DF046; //!< GLONASS L2 code indicator + int32_t set_DF046(uint16_t code_indicator); + + std::bitset<14> DF047; //!< GLONASS L2 - L1 Pseudorange Difference + int32_t set_DF047(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); + + std::bitset<20> DF048; //!< GLONASS L2 PhaseRange - L1 Pseudorange + int32_t set_DF048(const Gnss_Synchro& gnss_synchroL1, const Gnss_Synchro& gnss_synchroL2); + + std::bitset<7> DF049; //!< GLONASS L2 Lock Time Indicator + int32_t set_DF049(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro& gnss_synchro); + + std::bitset<8> DF050; //!< GLONASS L2 CNR + int32_t set_DF050(const Gnss_Synchro& gnss_synchro); + std::bitset<16> DF051; - int set_DF051(const Gps_Ephemeris & gps_eph, double obs_time); + int32_t set_DF051(const Gps_Ephemeris& gps_eph, double obs_time); std::bitset<17> DF052; - int set_DF052(const Gps_Ephemeris & gps_eph, double obs_time); + int32_t set_DF052(const Gps_Ephemeris& gps_eph, double obs_time); // Contents of GPS Satellite Ephemeris Data, Message Type 1019 std::bitset<8> DF071; - int set_DF071(const Gps_Ephemeris & gps_eph); + int32_t set_DF071(const Gps_Ephemeris& gps_eph); std::bitset<10> DF076; - int set_DF076(const Gps_Ephemeris & gps_eph); + int32_t set_DF076(const Gps_Ephemeris& gps_eph); std::bitset<4> DF077; - int set_DF077(const Gps_Ephemeris & gps_eph); + int32_t set_DF077(const Gps_Ephemeris& gps_eph); std::bitset<2> DF078; - int set_DF078(const Gps_Ephemeris & gps_eph); + int32_t set_DF078(const Gps_Ephemeris& gps_eph); std::bitset<14> DF079; - int set_DF079(const Gps_Ephemeris & gps_eph); + int32_t set_DF079(const Gps_Ephemeris& gps_eph); std::bitset<8> DF080; - int set_DF080(const Gps_Ephemeris & gps_eph); + int32_t set_DF080(const Gps_Ephemeris& gps_eph); std::bitset<16> DF081; - int set_DF081(const Gps_Ephemeris & gps_eph); + int32_t set_DF081(const Gps_Ephemeris& gps_eph); std::bitset<8> DF082; - int set_DF082(const Gps_Ephemeris & gps_eph); + int32_t set_DF082(const Gps_Ephemeris& gps_eph); std::bitset<16> DF083; - int set_DF083(const Gps_Ephemeris & gps_eph); + int32_t set_DF083(const Gps_Ephemeris& gps_eph); std::bitset<22> DF084; - int set_DF084(const Gps_Ephemeris & gps_eph); + int32_t set_DF084(const Gps_Ephemeris& gps_eph); std::bitset<10> DF085; - int set_DF085(const Gps_Ephemeris & gps_eph); + int32_t set_DF085(const Gps_Ephemeris& gps_eph); std::bitset<16> DF086; - int set_DF086(const Gps_Ephemeris & gps_eph); + int32_t set_DF086(const Gps_Ephemeris& gps_eph); std::bitset<16> DF087; - int set_DF087(const Gps_Ephemeris & gps_eph); + int32_t set_DF087(const Gps_Ephemeris& gps_eph); std::bitset<32> DF088; - int set_DF088(const Gps_Ephemeris & gps_eph); + int32_t set_DF088(const Gps_Ephemeris& gps_eph); std::bitset<16> DF089; - int set_DF089(const Gps_Ephemeris & gps_eph); + int32_t set_DF089(const Gps_Ephemeris& gps_eph); std::bitset<32> DF090; - int set_DF090(const Gps_Ephemeris & gps_eph); + int32_t set_DF090(const Gps_Ephemeris& gps_eph); std::bitset<16> DF091; - int set_DF091(const Gps_Ephemeris & gps_eph); + int32_t set_DF091(const Gps_Ephemeris& gps_eph); std::bitset<32> DF092; - int set_DF092(const Gps_Ephemeris & gps_eph); + int32_t set_DF092(const Gps_Ephemeris& gps_eph); std::bitset<16> DF093; - int set_DF093(const Gps_Ephemeris & gps_eph); + int32_t set_DF093(const Gps_Ephemeris& gps_eph); std::bitset<16> DF094; - int set_DF094(const Gps_Ephemeris & gps_eph); + int32_t set_DF094(const Gps_Ephemeris& gps_eph); std::bitset<32> DF095; - int set_DF095(const Gps_Ephemeris & gps_eph); + int32_t set_DF095(const Gps_Ephemeris& gps_eph); std::bitset<16> DF096; - int set_DF096(const Gps_Ephemeris & gps_eph); + int32_t set_DF096(const Gps_Ephemeris& gps_eph); std::bitset<32> DF097; - int set_DF097(const Gps_Ephemeris & gps_eph); + int32_t set_DF097(const Gps_Ephemeris& gps_eph); std::bitset<16> DF098; - int set_DF098(const Gps_Ephemeris & gps_eph); + int32_t set_DF098(const Gps_Ephemeris& gps_eph); std::bitset<32> DF099; - int set_DF099(const Gps_Ephemeris & gps_eph); + int32_t set_DF099(const Gps_Ephemeris& gps_eph); std::bitset<24> DF100; - int set_DF100(const Gps_Ephemeris & gps_eph); + int32_t set_DF100(const Gps_Ephemeris& gps_eph); std::bitset<8> DF101; - int set_DF101(const Gps_Ephemeris & gps_eph); + int32_t set_DF101(const Gps_Ephemeris& gps_eph); std::bitset<6> DF102; - int set_DF102(const Gps_Ephemeris & gps_eph); + int32_t set_DF102(const Gps_Ephemeris& gps_eph); std::bitset<1> DF103; - int set_DF103(const Gps_Ephemeris & gps_eph); + int32_t set_DF103(const Gps_Ephemeris& gps_eph); + + std::bitset<1> DF104; //!< GLONASS Almanac Health + int32_t set_DF104(uint32_t glonass_gnav_alm_health); + + std::bitset<1> DF105; //!< GLONASS Almanac Health Availability Indicator + int32_t set_DF105(uint32_t glonass_gnav_alm_health_ind); + + std::bitset<2> DF106; //!< GLONASS P1 Word + int32_t set_DF106(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<12> DF107; //!< GLONASS Epoch (tk) + int32_t set_DF107(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF108; //!< GLONASS MSB of Bn Word + int32_t set_DF108(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF109; //!< GLONASS P2 Word + int32_t set_DF109(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<7> DF110; //!< GLONASS Ephmeris Epoch (tb) + int32_t set_DF110(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<24> DF111; //!< GLONASS Xn first derivative + int32_t set_DF111(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<27> DF112; //!< GLONASS Xn + int32_t set_DF112(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<5> DF113; //!< GLONASS Xn second derivative + int32_t set_DF113(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<24> DF114; //!< GLONASS Yn first derivative + int32_t set_DF114(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<27> DF115; //!< GLONASS Yn + int32_t set_DF115(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<5> DF116; //!< GLONASS Yn second derivative + int32_t set_DF116(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<24> DF117; //!< GLONASS Zn first derivative + int32_t set_DF117(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<27> DF118; //!< GLONASS Zn + int32_t set_DF118(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<5> DF119; //!< GLONASS Zn second derivative + int32_t set_DF119(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF120; //!< GLONASS P3 + int32_t set_DF120(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<11> DF121; //!< GLONASS GAMMA_N + int32_t set_DF121(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<2> DF122; //!< GLONASS P + int32_t set_DF122(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF123; //!< GLONASS ln (third string) + int32_t set_DF123(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<22> DF124; //!< GLONASS TAU_N + int32_t set_DF124(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<5> DF125; //!< GLONASS DELTA_TAU_N + int32_t set_DF125(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<5> DF126; //!< GLONASS Eccentricity + int32_t set_DF126(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF127; //!< GLONASS P4 + int32_t set_DF127(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<4> DF128; //!< GLONASS F_T + int32_t set_DF128(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<11> DF129; //!< GLONASS N_T + int32_t set_DF129(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<2> DF130; //!< GLONASS M + int32_t set_DF130(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); + + std::bitset<1> DF131; //!< GLONASS Availability of additional data + int32_t set_DF131(uint32_t fifth_str_additional_data_ind); + + std::bitset<11> DF132; //!< GLONASS N_A + int32_t set_DF132(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); + + std::bitset<32> DF133; //!< GLONASS TAU_C + int32_t set_DF133(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); + + std::bitset<5> DF134; //!< GLONASS N_4 + int32_t set_DF134(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); + + std::bitset<22> DF135; //!< GLONASS TAU_GPS + int32_t set_DF135(const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model); + + std::bitset<1> DF136; //!< GLONASS L_N (FIFTH STRING) + int32_t set_DF136(const Glonass_Gnav_Ephemeris& glonass_gnav_eph); std::bitset<1> DF137; - int set_DF137(const Gps_Ephemeris & gps_eph); + int32_t set_DF137(const Gps_Ephemeris& gps_eph); std::bitset<1> DF141; - int set_DF141(const Gps_Ephemeris & gps_eph); + int32_t set_DF141(const Gps_Ephemeris& gps_eph); std::bitset<1> DF142; - int set_DF142(const Gps_Ephemeris & gps_eph); + int32_t set_DF142(const Gps_Ephemeris& gps_eph); std::bitset<30> DF248; - int set_DF248(double obs_time); + int32_t set_DF248(double obs_time); // Contents of Galileo F/NAV Satellite Ephemeris Data, Message Type 1045 std::bitset<6> DF252; - int set_DF252(const Galileo_Ephemeris & gal_eph); + int32_t set_DF252(const Galileo_Ephemeris& gal_eph); std::bitset<12> DF289; - int set_DF289(const Galileo_Ephemeris & gal_eph); + int32_t set_DF289(const Galileo_Ephemeris& gal_eph); std::bitset<10> DF290; - int set_DF290(const Galileo_Ephemeris & gal_eph); + int32_t set_DF290(const Galileo_Ephemeris& gal_eph); std::bitset<8> DF291; - int set_DF291(const Galileo_Ephemeris & gal_eph); + int32_t set_DF291(const Galileo_Ephemeris& gal_eph); std::bitset<14> DF292; - int set_DF292(const Galileo_Ephemeris & gal_eph); + int32_t set_DF292(const Galileo_Ephemeris& gal_eph); std::bitset<14> DF293; - int set_DF293(const Galileo_Ephemeris & gal_eph); + int32_t set_DF293(const Galileo_Ephemeris& gal_eph); std::bitset<6> DF294; - int set_DF294(const Galileo_Ephemeris & gal_eph); + int32_t set_DF294(const Galileo_Ephemeris& gal_eph); std::bitset<21> DF295; - int set_DF295(const Galileo_Ephemeris & gal_eph); + int32_t set_DF295(const Galileo_Ephemeris& gal_eph); std::bitset<31> DF296; - int set_DF296(const Galileo_Ephemeris & gal_eph); + int32_t set_DF296(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF297; - int set_DF297(const Galileo_Ephemeris & gal_eph); + int32_t set_DF297(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF298; - int set_DF298(const Galileo_Ephemeris & gal_eph); + int32_t set_DF298(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF299; - int set_DF299(const Galileo_Ephemeris & gal_eph); + int32_t set_DF299(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF300; - int set_DF300(const Galileo_Ephemeris & gal_eph); + int32_t set_DF300(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF301; - int set_DF301(const Galileo_Ephemeris & gal_eph); + int32_t set_DF301(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF302; - int set_DF302(const Galileo_Ephemeris & gal_eph); + int32_t set_DF302(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF303; - int set_DF303(const Galileo_Ephemeris & gal_eph); + int32_t set_DF303(const Galileo_Ephemeris& gal_eph); std::bitset<14> DF304; - int set_DF304(const Galileo_Ephemeris & gal_eph); + int32_t set_DF304(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF305; - int set_DF305(const Galileo_Ephemeris & gal_eph); + int32_t set_DF305(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF306; - int set_DF306(const Galileo_Ephemeris & gal_eph); + int32_t set_DF306(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF307; - int set_DF307(const Galileo_Ephemeris & gal_eph); + int32_t set_DF307(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF308; - int set_DF308(const Galileo_Ephemeris & gal_eph); + int32_t set_DF308(const Galileo_Ephemeris& gal_eph); std::bitset<16> DF309; - int set_DF309(const Galileo_Ephemeris & gal_eph); + int32_t set_DF309(const Galileo_Ephemeris& gal_eph); std::bitset<32> DF310; - int set_DF310(const Galileo_Ephemeris & gal_eph); + int32_t set_DF310(const Galileo_Ephemeris& gal_eph); std::bitset<24> DF311; - int set_DF311(const Galileo_Ephemeris & gal_eph); + int32_t set_DF311(const Galileo_Ephemeris& gal_eph); std::bitset<10> DF312; - int set_DF312(const Galileo_Ephemeris & gal_eph); + int32_t set_DF312(const Galileo_Ephemeris& gal_eph); std::bitset<10> DF313; - int set_DF313(const Galileo_Ephemeris & gal_eph); + int32_t set_DF313(const Galileo_Ephemeris& gal_eph); std::bitset<2> DF314; - int set_DF314(const Galileo_Ephemeris & gal_eph); + int32_t set_DF314(const Galileo_Ephemeris& gal_eph); std::bitset<1> DF315; - int set_DF315(const Galileo_Ephemeris & gal_eph); + int32_t set_DF315(const Galileo_Ephemeris& gal_eph); std::bitset<2> DF364; // Content of message header for MSM1, MSM2, MSM3, MSM4, MSM5, MSM6 and MSM7 std::bitset<1> DF393; - int set_DF393(bool more_messages); //1 indicates that more MSMs follow for given physical time and reference station ID + int32_t set_DF393(bool more_messages); //1 indicates that more MSMs follow for given physical time and reference station ID std::bitset<64> DF394; - int set_DF394(const std::map & observables); + int32_t set_DF394(const std::map& observables); std::bitset<32> DF395; - int set_DF395(const std::map & observables); + int32_t set_DF395(const std::map& observables); - std::string set_DF396(const std::map & observables); + std::string set_DF396(const std::map& observables); std::bitset<8> DF397; - int set_DF397(const Gnss_Synchro & gnss_synchro); + int32_t set_DF397(const Gnss_Synchro& gnss_synchro); std::bitset<10> DF398; - int set_DF398(const Gnss_Synchro & gnss_synchro); + int32_t set_DF398(const Gnss_Synchro& gnss_synchro); std::bitset<14> DF399; - int set_DF399(const Gnss_Synchro & gnss_synchro); + int32_t set_DF399(const Gnss_Synchro& gnss_synchro); std::bitset<15> DF400; - int set_DF400(const Gnss_Synchro & gnss_synchro); + int32_t set_DF400(const Gnss_Synchro& gnss_synchro); std::bitset<22> DF401; - int set_DF401(const Gnss_Synchro & gnss_synchro); + int32_t set_DF401(const Gnss_Synchro& gnss_synchro); std::bitset<4> DF402; - int set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + int32_t set_DF402(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro); std::bitset<6> DF403; - int set_DF403(const Gnss_Synchro & gnss_synchro); + int32_t set_DF403(const Gnss_Synchro& gnss_synchro); std::bitset<15> DF404; - int set_DF404(const Gnss_Synchro & gnss_synchro); + int32_t set_DF404(const Gnss_Synchro& gnss_synchro); std::bitset<20> DF405; - int set_DF405(const Gnss_Synchro & gnss_synchro); + int32_t set_DF405(const Gnss_Synchro& gnss_synchro); std::bitset<24> DF406; - int set_DF406(const Gnss_Synchro & gnss_synchro); + int32_t set_DF406(const Gnss_Synchro& gnss_synchro); std::bitset<10> DF407; - int set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + int32_t set_DF407(const Gps_Ephemeris& ephNAV, const Gps_CNAV_Ephemeris& ephCNAV, const Galileo_Ephemeris& ephFNAV, const Glonass_Gnav_Ephemeris& ephGNAV, double obs_time, const Gnss_Synchro& gnss_synchro); std::bitset<10> DF408; - int set_DF408(const Gnss_Synchro & gnss_synchro); + int32_t set_DF408(const Gnss_Synchro& gnss_synchro); std::bitset<3> DF409; - int set_DF409(unsigned int iods); + int32_t set_DF409(uint32_t iods); std::bitset<2> DF411; - int set_DF411(unsigned int clock_steering_indicator); + int32_t set_DF411(uint32_t clock_steering_indicator); std::bitset<2> DF412; - int set_DF412(unsigned int external_clock_indicator); + int32_t set_DF412(uint32_t external_clock_indicator); std::bitset<1> DF417; - int set_DF417(bool using_divergence_free_smoothing); + int32_t set_DF417(bool using_divergence_free_smoothing); std::bitset<3> DF418; - int set_DF418(int carrier_smoothing_interval_s); + int32_t set_DF418(int32_t carrier_smoothing_interval_s); std::bitset<1> DF420; - int set_DF420(const Gnss_Synchro & gnss_synchro); + int32_t set_DF420(const Gnss_Synchro& gnss_synchro); }; #endif diff --git a/src/core/system_parameters/sbas_ephemeris.cc b/src/core/system_parameters/sbas_ephemeris.cc index 3e3dea64e..df7328f7d 100644 --- a/src/core/system_parameters/sbas_ephemeris.cc +++ b/src/core/system_parameters/sbas_ephemeris.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,25 +24,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include #include "sbas_ephemeris.h" void Sbas_Ephemeris::print(std::ostream &out) { out << "<> PRN" << i_prn << ":"; - out << " d_t0=" << i_t0; - out << " d_tof=" << d_tof; - out << " i_sv_ura=" << i_sv_ura; - out << " b_sv_do_not_use=" << b_sv_do_not_use; + out << " d_t0=" << i_t0; + out << " d_tof=" << d_tof; + out << " i_sv_ura=" << i_sv_ura; + out << " b_sv_do_not_use=" << b_sv_do_not_use; out << " d_pos=(x=" << d_pos[0] << ", y=" << d_pos[1] << ", z=" << d_pos[2] << ")"; out << " d_vel=(x=" << d_vel[0] << ", y=" << d_vel[1] << ", z=" << d_vel[2] << ")"; out << " d_acc=(x=" << d_acc[0] << ", y=" << d_acc[1] << ", z=" << d_acc[2] << ")"; - out << " d_af0=" << d_af0; - out << " d_af1=" << d_af1; + out << " d_af0=" << d_af0; + out << " d_af1=" << d_af1; } diff --git a/src/core/system_parameters/sbas_ephemeris.h b/src/core/system_parameters/sbas_ephemeris.h index a0e9e91c7..61749b482 100644 --- a/src/core/system_parameters/sbas_ephemeris.h +++ b/src/core/system_parameters/sbas_ephemeris.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,6 +32,8 @@ #ifndef GNSS_SDR_SBAS_EPHEMERIS_H_ #define GNSS_SDR_SBAS_EPHEMERIS_H_ +#include + /*! * \brief This class stores SBAS SV ephemeris data * @@ -40,18 +42,18 @@ class Sbas_Ephemeris { public: void print(std::ostream &out); - int i_prn; //!< PRN number + int i_prn; //!< PRN number //gtime_t t0; // reference epoch time (GPST) int i_t0; //gtime_t tof; // time of message frame (GPST) double d_tof; - int i_sv_ura; //!< SV accuracy (URA index), not standardized - bool b_sv_do_not_use; //!< Health status (false:do not use / true:usable) - double d_pos[3]; //!< Satellite position (m) (ECEF) - double d_vel[3]; //!< Satellite velocity (m/s) (ECEF) - double d_acc[3]; //!< Satellite acceleration (m/s^2) (ECEF) - double d_af0; //!< Satellite clock-offset (s) - double d_af1; //!< Satellite drift (s/s) + int i_sv_ura; //!< SV accuracy (URA index), not standardized + bool b_sv_do_not_use; //!< Health status (false:do not use / true:usable) + double d_pos[3]; //!< Satellite position (m) (ECEF) + double d_vel[3]; //!< Satellite velocity (m/s) (ECEF) + double d_acc[3]; //!< Satellite acceleration (m/s^2) (ECEF) + double d_af0; //!< Satellite clock-offset (s) + double d_af1; //!< Satellite drift (s/s) }; diff --git a/src/core/system_parameters/sbas_ionospheric_correction.cc b/src/core/system_parameters/sbas_ionospheric_correction.cc deleted file mode 100644 index 3243c32ed..000000000 --- a/src/core/system_parameters/sbas_ionospheric_correction.cc +++ /dev/null @@ -1,467 +0,0 @@ -/*! - * \file sbas_ionospheric_correction.cc - * \brief Implementation of the SBAS ionosphere correction set based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "sbas_ionospheric_correction.h" -#include -#include -#include - - -enum V_Log_Level {EVENT = 2, // logs important events which don't occur every update() call - FLOW = 3, // logs the function calls of block processing functions - MORE = 4}; // very detailed stuff - - -void Sbas_Ionosphere_Correction::print(std::ostream &out) -{ - for(std::vector::const_iterator it_band = d_bands.begin(); it_band != d_bands.end(); ++it_band) - { - int band = it_band - d_bands.begin(); - out << "<> Band" << band << ":" << std::endl; - for(std::vector::const_iterator it_igp = it_band->d_igps.begin(); it_igp != it_band->d_igps.end(); ++it_igp) - { - int igp = it_igp-it_band->d_igps.begin(); - out << "<> -IGP" << igp << ":"; - //std::cout << " valid=" << it_igp->d_valid; - out << " t0=" << it_igp->t0; - out << " lat=" << it_igp->d_latitude; - out << " lon=" << it_igp->d_longitude; - out << " give=" << it_igp->d_give; - out << " delay=" << it_igp->d_delay; - out << std::endl; - } - } -} - - -/* Applies SBAS ionosphric delay correction - * \param[out] delay Slant ionospheric delay (L1) (m) - * \param[out] var Variance of ionospheric delay (m^2) - * \param[in] sample_stamp Sample stamp of observable on which the correction will be applied - * \param[in] longitude_d Receiver's longitude in terms of WGS84 (degree) - * \param[in] latitude_d Receiver's latitude in terms of WGS84 (degree) - * \param[in] azimuth_d Satellite azimuth/elavation angle (rad). Azimuth is the angle of - * the satellite from the user�s location measured clockwise from north - * \param[in] elevation_d Elevation is the angle of the satellite from the user's location measured - * with respect to the local-tangent-plane - */ -bool Sbas_Ionosphere_Correction::apply(double sample_stamp, - double latitude_d, - double longitude_d, - double azimut_d, - double elevation_d, - double &delay, - double &var) -{ - const double GPS_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E - int result; - double pos[3]; - double azel[2]; - - // convert receiver position from degrees to rad - pos[0] = latitude_d * GPS_PI / 180.0; - pos[1] = longitude_d * GPS_PI / 180.0; - pos[2] = 0; // is not used by sbsioncorr, for ionocorrection is a fixed earth radius assumed - - // convert satellite azimut and elevation from degrees to rad , use topocent to obtain it in pvt block - azel[0] = azimut_d * GPS_PI / 180.0; - azel[1] = elevation_d * GPS_PI / 180.0; - - result = sbsioncorr(sample_stamp, pos, azel, &delay, &var); - return (bool)result; -} - - - -/* geometric distance ---------------------------------------------------------- -* compute geometric distance and receiver-to-satellite unit vector -* args : double *rs I satellilte position (ecef at transmission) (m) -* double *rr I receiver position (ecef at reception) (m) -* double *e O line-of-sight vector (ecef) -* return : geometric distance (m) (0>:error/no satellite position) -* notes : distance includes sagnac effect correction -*-----------------------------------------------------------------------------*/ -//extern double geodist(const double *rs, const double *rr, double *e) -//{ -// double r; -// int i; -// -// if (norm(rs,3)= 0) c += a[n]*b[n]; - return c; -} - - - - -/* multiply matrix -----------------------------------------------------------*/ -void Sbas_Ionosphere_Correction::matmul(const char *tr, int n, int k, int m, double alpha, - const double *A, const double *B, double beta, double *C) -{ - double d; - int i, j, x, f = tr[0] == 'N' ? (tr[1] == 'N' ? 1 : 2) : (tr[1] == 'N' ? 3 : 4); - - for (i = 0; i < n; i++) for (j = 0; j < k; j++) - { - d = 0.0; - switch (f) - { - case 1: for (x = 0; x < m; x++) d += A[i + x*n]*B[x + j*m]; break; - case 2: for (x = 0; x < m; x++) d += A[i + x*n]*B[j + x*k]; break; - case 3: for (x = 0; x < m; x++) d += A[x + i*m]*B[x + j*m]; break; - case 4: for (x = 0; x < m; x++) d += A[x + i*m]*B[j + x*k]; break; - } - if (beta == 0.0) - { - C[i + j*n] = alpha*d; - } - else - { - C[i + j*n] = alpha*d + beta*C[i + j*n]; - } - } -} - - -/* ecef to local coordinate transfromation matrix ------------------------------ -* compute ecef to local coordinate transfromation matrix -* args : double *pos I geodetic position {lat,lon} (rad) -* double *E O ecef to local coord transformation matrix (3x3) -* return : none -* notes : matrix stored by column-major order (fortran convention) -*-----------------------------------------------------------------------------*/ -void Sbas_Ionosphere_Correction::xyz2enu(const double *pos, double *E) -{ - double sinp = sin(pos[0]), cosp = cos(pos[0]), sinl = sin(pos[1]), cosl = cos(pos[1]); - E[0] = -sinl; E[3] = cosl; E[6] = 0.0; - E[1] = -sinp*cosl; E[4] = -sinp*sinl; E[7] = cosp; - E[2] = cosp*cosl; E[5] = cosp*sinl; E[8] = sinp; -} - - -/* transform ecef vector to local tangential coordinate ------------------------- -* transform ecef vector to local tangential coordinate -* args : double *pos I geodetic position {lat,lon} (rad) -* double *r I vector in ecef coordinate {x,y,z} -* double *e O vector in local tangental coordinate {e,n,u} -* return : none -*-----------------------------------------------------------------------------*/ -void Sbas_Ionosphere_Correction::ecef2enu(const double *pos, const double *r, double *e) -{ - double E[9]; - xyz2enu(pos, E); - matmul("NN", 3, 1, 3, 1.0, E, r, 0.0, e); -} - - - -const double PI = 3.1415926535897932; /* pi */ - - - -/* satellite azimuth/elevation angle ------------------------------------------- -* compute satellite azimuth/elevation angle -* args : double *pos I geodetic position {lat,lon,h} (rad,m) -* double *e I receiver-to-satellilte unit vevtor (ecef) -* double *azel IO azimuth/elevation {az,el} (rad) (NULL: no output) -* (0.0<=azel[0]<2*pi,-pi/2<=azel[1]<=pi/2) -* return : elevation angle (rad) -*-----------------------------------------------------------------------------*/ -double Sbas_Ionosphere_Correction::satazel(const double *pos, const double *e, double *azel) -{ - const double RE_WGS84 = 6378137.0; /* earth semimajor axis (WGS84) (m) */ - - double az = 0.0, el = PI/2.0, enu[3]; - - if (pos[2] > -RE_WGS84) - { - ecef2enu(pos, e, enu); - az = dot(enu, enu, 2) < 1E-12 ? 0.0 : atan2(enu[0], enu[1]); - if (az < 0.0) az += 2*PI; - el = asin(enu[2]); - } - if (azel) - { - azel[0] = az; - azel[1] = el; - } - return el; -} - -/* debug trace function -----------------------------------------------------*/ -void Sbas_Ionosphere_Correction::trace(int level, const char *format, ...) -{ - va_list ap; - char str[1000]; - - va_start(ap,format); vsprintf(str,format,ap); va_end(ap); - VLOG(FLOW) << "<> " << std::string(str); -} - -/* ionospheric pierce point position ------------------------------------------- -* compute ionospheric pierce point (ipp) position and slant factor -* args : double *pos I receiver position {lat,lon,h} (rad,m) -* double *azel I azimuth/elevation angle {az,el} (rad) -* double re I earth radius (km) -* double hion I altitude of ionosphere (km) -* double *posp O pierce point position {lat,lon,h} (rad,m) -* return : slant factor -* notes : see ref [2], only valid on the earth surface -* fixing bug on ref [2] A.4.4.10.1 A-22,23 -*-----------------------------------------------------------------------------*/ -double Sbas_Ionosphere_Correction::ionppp(const double *pos, const double *azel, - double re, double hion, double *posp) -{ - double cosaz, rp, ap, sinap, tanap; - const double D2R = (PI/180.0); /* deg to rad */ - - rp = re/(re + hion)*cos(azel[1]); - ap = PI/2.0 - azel[1] - asin(rp); - sinap = sin(ap); - tanap = tan(ap); - cosaz = cos(azel[0]); - posp[0] = asin(sin(pos[0])*cos(ap) + cos(pos[0])*sinap*cosaz); - - if ((pos[0] > 70.0*D2R && tanap*cosaz > tan(PI/2.0 - pos[0])) || - (pos[0] < -70.0*D2R && - tanap*cosaz > tan(PI/2.0 + pos[0]))) - { - posp[1] = pos[1] + PI - asin(sinap*sin(azel[0])/cos(posp[0])); - } - else - { - posp[1] = pos[1] + asin(sinap*sin(azel[0])/cos(posp[0])); - } - return 1.0 / sqrt(1.0 - rp*rp); -} - - -/* variance of ionosphere correction (give=GIVEI) --------------------------*/ -double Sbas_Ionosphere_Correction::varicorr(int give) -{ - const double var[15]={ - 0.0084, 0.0333, 0.0749, 0.1331, 0.2079, 0.2994, 0.4075, 0.5322, 0.6735, 0.8315, - 1.1974, 1.8709, 3.326, 20.787, 187.0826 - }; - return 0 <= give && give < 15 ? var[give]:0.0; -} - - -/* search igps ---------------------------------------------------------------*/ -void Sbas_Ionosphere_Correction::searchigp(const double *pos, const Igp **igp, double *x, double *y) -{ - int i; - int latp[2]; - int lonp[4]; - const double R2D = (180.0/PI); /* rad to deg */ - - double lat = pos[0]*R2D; - double lon = pos[1]*R2D; - - trace(4,"searchigp: pos=%.3f %.3f",pos[0]*R2D, pos[1]*R2D); - - // round the pierce point position to the next IGP grid point - if (lon >= 180.0) lon -= 360.0; - if (-55.0 <= lat && lat < 55.0) - { - latp[0] = (int)floor(lat/5.0)*5; - latp[1] = latp[0] + 5; - lonp[0] = lonp[1] = (int)floor(lon/5.0)*5; - lonp[2] = lonp[3] = lonp[0] + 5; - *x = (lon - lonp[0])/5.0; - *y = (lat - latp[0])/5.0; - } - else - { - latp[0] = (int)floor((lat-5.0)/10.0)*10+5; - latp[1] = latp[0] + 10; - lonp[0] = lonp[1] = (int)floor(lon/10.0)*10; - lonp[2] = lonp[3] = lonp[0] + 10; - *x = (lon - lonp[0])/10.0; - *y = (lat - latp[0])/10.0; - if (75.0 <= lat && lat < 85.0) - { - lonp[1] = (int)floor(lon/90.0)*90; - lonp[3] = lonp[1] + 90; - } - else if (-85.0 <= lat && lat < -75.0) - { - lonp[0] = (int)floor((lon - 50.0)/90.0)*90 + 40; - lonp[2] = lonp[0] + 90; - } - else if (lat >= 85.0) - { - for (i = 0; i < 4; i++) lonp[i] = (int)floor(lon/90.0)*90; - } - else if (lat <- 85.0) - { - for (i = 0; i < 4; i++) lonp[i] = (int)floor((lon - 50.0)/90.0)*90 + 40; - } - } - - for (i = 0; i < 4; i++) if (lonp[i] == 180) lonp[i] = -180; - - // find the correction data for the grid points in latp[] and lonp[] - // iterate over bands - for (std::vector::const_iterator band_it = this->d_bands.begin(); band_it != d_bands.end(); ++band_it) - { - //VLOG(MORE) << "band=" << band_it-d_bands.begin() << std::endl; - // iterate over IGPs in band_it - for (std::vector::const_iterator igp_it = band_it->d_igps.begin(); igp_it != band_it->d_igps.end(); ++igp_it) - { - std::stringstream ss; - int give = igp_it->d_give; - ss << "IGP: give=" << give; - if(give < 15) // test if valid correction data is sent for current IGP - { - int lat = igp_it->d_latitude; - int lon = igp_it->d_longitude; - ss << " lat=" << lat << " lon=" << lon; - if (lat == latp[0] && lon == lonp[0]) igp[0] = igp_it.base(); - else if (lat == latp[1] && lon == lonp[1]) igp[1] = igp_it.base(); - else if (lat == latp[0] && lon == lonp[2]) igp[2] = igp_it.base(); - else if (lat == latp[1] && lon == lonp[3]) igp[3] = igp_it.base(); - } - //VLOG(MORE) << ss.str(); - } - } - //VLOG(MORE) << "igp[0:3]={" << igp[0] << "," << igp[1] << "," << igp[2] << "," << igp[3] << "}"; -} - - - -/* sbas ionospheric delay correction ------------------------------------------- -* compute sbas ionosphric delay correction -* args : long sample_stamp I sample stamp of observable on which the correction will be applied -* sbsion_t *ion I ionospheric correction data (implicit) -* double *pos I receiver position {lat,lon,height} (rad/m) -* double *azel I satellite azimuth/elavation angle (rad) -* double *delay O slant ionospheric delay (L1) (m) -* double *var O variance of ionospheric delay (m^2) -* return : status (1:ok, 0:no correction) -* notes : before calling the function, sbas ionosphere correction parameters -* in navigation data (nav->sbsion) must be set by calling -* sbsupdatecorr() -*-----------------------------------------------------------------------------*/ -int Sbas_Ionosphere_Correction::sbsioncorr(const double sample_stamp, const double *pos, - const double *azel, double *delay, double *var) -{ - const double re = 6378.1363; - const double hion = 350.0; - int err = 0; - double fp; - double posp[2]; - double x = 0.0; - double y = 0.0; - double t; - double w[4] = {0}; - const Igp *igp[4] = {0}; /* {ws,wn,es,en} */ - const double R2D = (180.0/PI); /* rad to deg */ - - trace(4, "sbsioncorr: pos=%.3f %.3f azel=%.3f %.3f", pos[0]*R2D, pos[1]*R2D, azel[0]*R2D, azel[1]*R2D); - - *delay = *var = 0.0; - if (pos[2] < -100.0 || azel[1] <= 0) return 1; - - /* ipp (ionospheric pierce point) position */ - fp = ionppp(pos, azel, re, hion, posp); - - /* search igps around ipp */ - searchigp(posp, igp, &x, &y); - - VLOG(FLOW) << "<> SBAS iono correction:" << " igp[0]=" << igp[0] << " igp[1]=" << igp[1] - << " igp[2]=" << igp[2] << " igp[3]=" << igp[3] << " x=" << x << " y=" << y; - - /* weight of igps */ - if (igp[0] && igp[1] && igp[2] && igp[3]) - { - w[0] = (1.0 - x)*(1.0 - y); - w[1] = (1.0 - x)*y; - w[2] = x*(1.0 - y); - w[3] = x*y; - } - else if (igp[0] && igp[1] && igp[2]) - { - w[1] = y; - w[2] = x; - if ((w[0] = 1.0 - w[1] - w[2]) < 0.0) err = 1; - } - else if (igp[0] && igp[2] && igp[3]) - { - w[0] = 1.0 - x; - w[3] = y; - if ((w[2] = 1.0 - w[0] -w[3]) < 0.0) err = 1; - } - else if (igp[0] && igp[1] && igp[3]) - { - w[0] = 1.0 - y; - w[3] = x; - if ((w[1] = 1.0 - w[0] - w[3]) < 0.0) err = 1; - } - else if (igp[1]&&igp[2]&&igp[3]) - { - w[1] = 1.0 - x; - w[2] = 1.0 - y; - if ((w[3] = 1.0 - w[1] - w[2]) < 0.0) err = 1; - } - else err = 1; - - if (err) - { - trace(2, "no sbas iono correction: lat=%3.0f lon=%4.0f", posp[0]*R2D, posp[1]*R2D); - return 0; - } - for (int i = 0; i <4 ; i++) - { - if (!igp[i]) continue; - t = (sample_stamp - igp[i]->t0); // time diff between now and reception of the igp data in seconds - *delay += w[i]*igp[i]->d_delay; - *var += w[i] * varicorr(igp[i]->d_give) * 9E-8 * fabs(t); - } - *delay *= fp; - *var *= fp*fp; - - trace(5, "sbsioncorr: dion=%7.2f sig=%7.2f", *delay, sqrt(*var)); - return 1; -} diff --git a/src/core/system_parameters/sbas_ionospheric_correction.h b/src/core/system_parameters/sbas_ionospheric_correction.h deleted file mode 100644 index e2988fa18..000000000 --- a/src/core/system_parameters/sbas_ionospheric_correction.h +++ /dev/null @@ -1,203 +0,0 @@ -/*! - * \file sbas_ionospheric_correction.h - * \brief Interface of the SBAS ionosphere correction set based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef SBAS_IONOSPHERIC_CORRECTION_H_ -#define SBAS_IONOSPHERIC_CORRECTION_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/*! - * \brief Struct that represents a Ionospheric Grid Point (IGP) - */ -struct Igp -{ -public: - //bool d_valid; // valid==true indicates that the IGP can be used for corrections. it is set to false when a new IGP mask (MT18) has been received but no corresponding delays (MT26) - double t0; // time of reception, time of correction - int d_latitude; - int d_longitude; - int d_give; - double d_delay; -private: - friend class boost::serialization::access; - template - void serialize(Archive& ar, const unsigned int version) - { - ar & t0; - ar & d_latitude; - ar & d_longitude; - ar & d_give; - ar & d_delay; - } -}; - - -/*! - * \brief Struct that represents the band of a Ionospheric Grid Point (IGP) - */ -struct Igp_Band -{ - //int d_iodi; - //int d_nigp; // number if IGPs in this band (defined by IGP mask from MT18) - std::vector d_igps; -private: - friend class boost::serialization::access; - template - void serialize(Archive& ar, const unsigned int version) - { - ar & d_igps; - } -}; - - - -/*! - * \brief Class that handles valid SBAS ionospheric correction for GPS - */ -class Sbas_Ionosphere_Correction -{ -private: - /* Inner product of vectors - * params : double *a,*b I vector a,b (n x 1) - * int n I size of vector a,b - * return : a'*b - */ - double dot(const double *a, const double *b, int n); - - /* Multiply matrix */ - void matmul(const char *tr, int n, int k, int m, double alpha, - const double *A, const double *B, double beta, double *C); - - /* EFEC to local coordinate transfomartion matrix - * Compute ecef to local coordinate transfomartion matrix - * params : double *pos I geodetic position {lat,lon} (rad) - * double *E O ecef to local coord transformation matrix (3x3) - * return : none - * notes : matrix stored by column-major order (fortran convention) - */ - void xyz2enu(const double *pos, double *E); - - /* Transforms ECEF vector into local tangential coordinates - * params : double *pos I geodetic position {lat,lon} (rad) - * double *r I vector in ecef coordinate {x,y,z} - * double *e O vector in local tangental coordinate {e,n,u} - * return : none - */ - void ecef2enu(const double *pos, const double *r, double *e); - - /* Compute satellite azimuth/elevation angle - * params : double *pos I geodetic position {lat,lon,h} (rad,m) - * double *e I receiver-to-satellilte unit vevtor (ecef) - * double *azel IO azimuth/elevation {az,el} (rad) (NULL: no output) - * (0.0 <= azel[0] < 2*pi, -pi/2 <= azel[1] <= pi/2) - * return : elevation angle (rad) - */ - double satazel(const double *pos, const double *e, double *azel); - - /* Debug trace functions */ - void trace(int level, const char *format, ...); - - /* time difference ------------------------------------------------------------- - * difference between gtime_t structs - * args : gtime_t t1,t2 I gtime_t structs - * return : time difference (t1-t2) (s) - *-----------------------------------------------------------------------------*/ - //double timediff(gtime_t t1, gtime_t t2); - - /* Compute Ionospheric Pierce Point (IPP) position and slant factor - * params : double *pos I receiver position {lat,lon,h} (rad,m) - * double *azel I azimuth/elevation angle {az,el} (rad) - * double re I earth radius (km) - * double hion I altitude of ionosphere (km) - * double *posp O pierce point position {lat,lon,h} (rad,m) - * return : slant factor - * notes : see ref [2], only valid on the earth surface - * fixing bug on ref [2] A.4.4.10.1 A-22,23 - *-----------------------------------------------------------------------------*/ - double ionppp(const double *pos, const double *azel, double re, - double hion, double *posp); - - /* Variance of ionosphere correction (give = GIVEI + 1) */ - double varicorr(int give); - - /* Search igps */ - void searchigp(const double *pos, const Igp **igp, double *x, double *y); - - /* Compute sbas ionospheric delay correction - * params : long sample_stamp I sample stamp of observable on which the correction will be applied - * sbsion_t *ion I ionospheric correction data (implicit) - * double *pos I receiver position {lat,lon,height} (rad/m) - * double *azel I satellite azimuth/elavation angle (rad) - * double *delay O slant ionospheric delay (L1) (m) - * double *var O variance of ionospheric delay (m^2) - * return : status (1:ok, 0:no correction) - * notes : before calling the function, sbas ionosphere correction parameters - * in navigation data (nav->sbsion) must be set by callig - * sbsupdatecorr() - */ - int sbsioncorr(const double sample_stamp, const double *pos, - const double *azel, double *delay, double *var); - - friend class boost::serialization::access; - template - void serialize(Archive& ar, const unsigned int version){ar & d_bands;} - -public: - std::vector d_bands; - void print(std::ostream &out); - - /*! - * \brief Computes SBAS ionospheric delay correction. - * - * \param[out] delay Slant ionospheric delay (L1) (m) - * \param[out] var Variance of ionospheric delay (m^2) - * \param[in] sample_stamp Sample stamp of observable on which the correction will be applied - * \param[in] longitude_d Receiver's longitude in terms of WGS84 (degree) - * \param[in] latitude_d Receiver's latitude in terms of WGS84 (degree) - * \param[in] azimuth_d Satellite azimuth/elavation angle (rad). Azimuth is the angle of - * the satellite from the user's location measured clockwise from north - * \param[in] elevation_d Elevation is the angle of the satellite from the user's location measured - * with respect to the local-tangent-plane - */ - bool apply(double sample_stamp, double latitude_d, double longitude_d, - double azimut_d, double evaluation_d, double &delay, double &var); - -}; - - -#endif /* SBAS_IONOSPHERIC_CORRECTION_H_ */ diff --git a/src/core/system_parameters/sbas_satellite_correction.cc b/src/core/system_parameters/sbas_satellite_correction.cc deleted file mode 100644 index 106992364..000000000 --- a/src/core/system_parameters/sbas_satellite_correction.cc +++ /dev/null @@ -1,296 +0,0 @@ -/*! - * \file sbas_satellite_correction.cc - * \brief Implementation of the SBAS satellite correction set based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "sbas_satellite_correction.h" -#include -#include -#include -#include -#include - - -#define EVENT 2 // logs important events which don't occur every update() call -#define FLOW 3 // logs the function calls of block processing functions - -#define CLIGHT 299792458.0 /* speed of light (m/s) */ -#define MAXSBSAGEF 30.0 /* max age of SBAS fast correction (s) */ -#define MAXSBSAGEL 1800.0 /* max age of SBAS long term corr (s) */ - - -void Sbas_Satellite_Correction::print(std::ostream &out) -{ - out << "<> Sbas satellite corrections for PRN" << d_prn << ":" << std::endl; - print_fast_correction(out); - print_long_term_correction(out); -} - - -void Sbas_Satellite_Correction::print_fast_correction(std::ostream &out) -{ - Fast_Correction fcorr = d_fast_correction; - out << "<> Fast PRN" << d_prn << ":"; - if(fcorr.d_tof.is_related()) - { - int gps_week; - double gps_sec; - fcorr.d_tof.get_gps_time(gps_week, gps_sec); - out << " d_t0=(week=" << gps_week << ",sec=" << gps_sec << ")"; - } - else - { - out << " d_t0=" << fcorr.d_tof.get_time_stamp(); - } - out << " d_prc=" << fcorr.d_prc; - out << " d_rrc=" << fcorr.d_rrc; - out << " d_dt=" << fcorr.d_dt; - out << " d_udre=" << fcorr.d_udre; - out << " d_ai=" << fcorr.d_ai; - out << " d_tlat=" << fcorr.d_tlat; -} - - -void Sbas_Satellite_Correction::print_long_term_correction(std::ostream &out) -{ - Long_Term_Correction lcorr = d_long_term_correction; - out << "<> Long PRN" << d_prn << ":"; - out << " d_trx=" << lcorr.d_trx; - out << " i_tapp=" << lcorr.i_tapp; - out << " i_vel=" << lcorr.i_vel; - double *p = lcorr.d_dpos; - out << " d_dpos=(x=" << p[0] << ", y=" << p[1] << ", z=" << p[2] << ")" ; - double *v = lcorr.d_dvel; - out << " d_dvel=(x=" << v[0] << ", y=" << v[1] << ", z=" << v[2] << ")" ; - out << " d_daf0=" << lcorr.d_daf0; - out << " d_daf1=" << lcorr.d_daf1; -} - - -int Sbas_Satellite_Correction::apply_fast(double sample_stamp, double &pr, double &var) -{ - int result; - double prc = 0; // pseudo range correction - result = sbsfastcorr(sample_stamp, &prc, &var); - pr += prc; - VLOG(FLOW) << "<> fast correction applied: sample_stamp=" << sample_stamp << " prc=" << prc << " corr. pr=" << pr; - return result; -} - - - -int Sbas_Satellite_Correction::apply_long_term_sv_pos(double sample_stamp, double sv_pos[], double &var) -{ - int result; - double drs[3] = {0}; - double ddts = 0; - result = sbslongcorr(sample_stamp, drs, &ddts); - for (int i = 0; i < 3; i++) sv_pos[i] += drs[i]; - VLOG(FLOW) << "<> long term sv pos correction applied: sample_stamp=" << sample_stamp << " drs=(x=" << drs[0] << " y=" << drs[1] << " z=" << drs[2] << ")"; - return result; -} - - - -int Sbas_Satellite_Correction::apply_long_term_sv_clk(double sample_stamp, double &dts, double &var) -{ - int result; - double drs[3] = {0}; - double ddts = 0; - result = sbslongcorr(sample_stamp, drs, &ddts); - dts += ddts; - VLOG(FLOW) << "<> long term sv clock correction correction applied: sample_stamp=" << sample_stamp << " ddts=" << ddts; - return result; -} - - -bool Sbas_Satellite_Correction::alarm() -{ - return this->d_fast_correction.d_udre == 16; -} - - - -/* debug trace function -----------------------------------------------------*/ -void Sbas_Satellite_Correction::trace(int level, const char *format, ...) -{ - va_list ap; - char str[1000]; - va_start(ap,format); - vsprintf(str,format,ap); - va_end(ap); - VLOG(FLOW) << "<> " << std::string(str); -} - - -/* variance of fast correction (udre=UDRE+1) ---------------------------------*/ -double Sbas_Satellite_Correction::varfcorr(int udre) -{ - const double var[14] = { - 0.052, 0.0924, 0.1444, 0.283, 0.4678, 0.8315, 1.2992, 1.8709, 2.5465, 3.326, - 5.1968, 20.7870, 230.9661, 2078.695 - }; - return 0 < udre && udre <= 14 ? var[udre - 1] : 0.0; -} - - -/* fast correction degradation -----------------------------------------------*/ -double Sbas_Satellite_Correction::degfcorr(int ai) -{ - const double degf[16] = { - 0.00000, 0.00005, 0.00009, 0.00012, 0.00015, 0.00020, 0.00030, 0.00045, - 0.00060, 0.00090, 0.00150, 0.00210, 0.00270, 0.00330, 0.00460, 0.00580 - }; - return 0 < ai && ai <= 15 ? degf[ai] : 0.0058; -} - - - -/* long term correction ------------------------------------------------------*/ -int Sbas_Satellite_Correction::sbslongcorr(double time_stamp, double *drs, double *ddts) -{ - double t = 0.0; - int i; - Long_Term_Correction lcorr = d_long_term_correction; - trace(3, "sbslongcorr: prn=%2d", this->d_prn); - // if (p->sat!=sat||p->lcorr.t0.time==0) continue; - // compute time of applicability - if(d_long_term_correction.i_vel == 1) - { - // time of applicability is the one sent, i.e., tapp - // TODO: adapt for vel==1 case - // t = tow-d_long_term_correction.i_tapp; - // vel=1 -> time of applicability is sent in message, needs to be corrected for rollover which can not be done here, since the absolute gps time is unknown. see IS-GPS-200G pdf page 116 for correction - /* t = (int)getbitu(msg->msg, p + 90, 13)*16 - (int)msg->tow%86400; - if (t <= -43200) t += 86400; - else if (t > 43200) t -= 86400; - sbssat->sat[n-1].lcorr.t0 = gpst2time(msg->week, msg->tow + t);*/ - } - else - { - // time of applicability is time of reception - t = time_stamp - lcorr.d_trx; // should not have any impact if vel==0 since d_dvel and d_daf1 are zero, is only used to check outdating - } - //t=time_stamp-lcorr.d_t0; - if (fabs(t) > MAXSBSAGEL) - { - trace(2,"sbas long-term correction expired: sat=%2d time_stamp=%5.0f", d_prn, time_stamp); - return 0; - } - // sv position correction - for (i=0; i<3; i++) drs[i] = lcorr.d_dpos[i] + lcorr.d_dvel[i]*t; - // sv clock correction correction - *ddts = lcorr.d_daf0 + lcorr.d_daf1*t; - trace(5, "sbslongcorr: sat=%2d drs=%7.2f%7.2f%7.2f ddts=%7.2f", d_prn, drs[0], drs[1], drs[2], *ddts * CLIGHT); - return 1; - /* if sbas satellite without correction, no correction applied */ - //if (satsys(sat,NULL)==SYS_SBS) return 1; - //trace(2,"no sbas long-term correction: %s sat=%2d\n",time_str(time,0),sat); - //return 0; -} - - - - -/* fast correction -----------------------------------------------------------*/ -int Sbas_Satellite_Correction::sbsfastcorr(double time_stamp, double *prc, double *var) -#define RRCENA -{ - double t; - Fast_Correction fcorr = d_fast_correction; - trace(3, "sbsfastcorr: sat=%2d", this->d_prn); - //if (p->fcorr.t0.time==0) break; // time==0is only true if t0 hasn't been initialised -> it checks if the correction is valid - t = (time_stamp - fcorr.d_tof.get_time_stamp()) + fcorr.d_tlat; // delta t between now and tof - /* expire age of correction? */ - if (fabs(t) > MAXSBSAGEF) - { - trace(2, "no sbas fast correction (expired): time_stamp=%f prn=%2d", time_stamp, d_prn); - return 0; - } - /* UDRE==14 (not monitored)? */ - else if(fcorr.d_udre == 15) - { - trace(2,"no sbas fast correction (not monitored): time_stamp=%f prn=%2d", time_stamp, d_prn); - return 0; - } - else if(fcorr.d_udre == 16) - { - trace(2,"SV is marked as unhealthy: time_stamp=%f prn=%2d", time_stamp, d_prn); - return 0; - } - *prc = fcorr.d_prc; -#ifdef RRCENA - if (fcorr.d_ai > 0 && fabs(t) <= 8.0*fcorr.d_dt) - { - *prc += fcorr.d_rrc*t; - } -#endif - *var = varfcorr(fcorr.d_udre) + degfcorr(fcorr.d_ai) * t * t / 2.0; - trace(5, "sbsfastcorr: sat=%3d prc=%7.2f sig=%7.2f t=%5.0f", d_prn, *prc, sqrt(*var), t); - return 1; -} - - - -/* sbas satellite ephemeris and clock correction ------------------------------- -* correct satellite position and clock bias with sbas satellite corrections -* args : long time_stamp I reception time stamp -* double *rs IO sat position and corrected {x,y,z} (ecef) (m) -* double *dts IO sat clock bias and corrected (s) -* double *var O sat position and clock variance (m^2) -* return : status (1:ok,0:no correction) -* notes : before calling the function, sbas satellite correction parameters -* in navigation data (nav->sbssat) must be set by callig -* sbsupdatecorr(). -* satellite clock correction include long-term correction and fast -* correction. -* sbas clock correction is usually based on L1C/A code. TGD or DCB has -* to be considered for other codes -*-----------------------------------------------------------------------------*/ -int Sbas_Satellite_Correction::sbssatcorr(double time_stamp, double *rs, double *dts, double *var) -{ - double drs[3] = {0}, dclk = 0.0, prc = 0.0; - int i; - trace(3,"sbssatcorr : sat=%2d",d_prn); - /* sbas long term corrections */ - if (!sbslongcorr(time_stamp, drs, &dclk)) - { - return 0; - } - /* sbas fast corrections */ - if (!sbsfastcorr(time_stamp, &prc, var)) - { - return 0; - } - for (i = 0; i < 3; i++) rs[i] += drs[i]; - dts[0] += dclk + prc/CLIGHT; - trace(5, "sbssatcorr: sat=%2d drs=%6.3f %6.3f %6.3f dclk=%.3f %.3f var=%.3f", - d_prn, drs[0], drs[1], drs[2], dclk,prc/CLIGHT, *var); - return 1; -} - diff --git a/src/core/system_parameters/sbas_satellite_correction.h b/src/core/system_parameters/sbas_satellite_correction.h deleted file mode 100644 index 72c179594..000000000 --- a/src/core/system_parameters/sbas_satellite_correction.h +++ /dev/null @@ -1,107 +0,0 @@ -/*! - * \file sbas_satellite_correction.h - * \brief Interface of the SBAS satellite correction set based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_SBAS_SATELLITE_CORRECTION_H_ -#define GNSS_SDR_SBAS_SATELLITE_CORRECTION_H_ - -#include "sbas_time.h" - -struct Fast_Correction -{ - Sbas_Time d_tof; // for fast corrections the time of applicability (tof) is defined as the time when the corresponding message was send - double d_prc; - double d_rrc; - double d_dt; - int d_udre; // UDRE - int d_ai; - int d_tlat; -}; - - -struct Long_Term_Correction -{ - double d_trx; //!< Time when message was received - int i_tapp; //!< Time of applicability (only valid if vel=1, equals the sent t0) - int i_vel; //!< Use velocity corrections if vel=1 - int d_iode; - double d_dpos[3]; //!< position correction - double d_dvel[3]; //!< velocity correction - double d_daf0; //!< clock offset correction - double d_daf1; //!< clock drift correction -}; - - -/*! - * \brief Valid long and fast term SBAS corrections for one SV - */ -class Sbas_Satellite_Correction -{ -public: - int d_prn; - Fast_Correction d_fast_correction; - Long_Term_Correction d_long_term_correction; - void print(std::ostream &out); - void print_fast_correction(std::ostream &out); - void print_long_term_correction(std::ostream &out); - int apply_fast(double sample_stamp, double &pr, double &var); - int apply_long_term_sv_pos(double sample_stamp, double sv_pos[], double &var); - int apply_long_term_sv_clk(double sample_stamp, double &dts, double &var); - bool alarm(); -private: - /* debug trace functions -----------------------------------------------------*/ - void trace(int level, const char *format, ...); - /* variance of fast correction (udre=UDRE+1) ---------------------------------*/ - double varfcorr(int udre); - /* fast correction degradation -----------------------------------------------*/ - double degfcorr(int ai); - /* long term correction ------------------------------------------------------*/ - int sbslongcorr(double time_stamp, double *drs, double *ddts); - /* fast correction -----------------------------------------------------------*/ - int sbsfastcorr(double time_stamp, double *prc, double *var); - /* sbas satellite ephemeris and clock correction ------------------------------- - * correct satellite position and clock bias with sbas satellite corrections - * args : long time_stamp I reception time stamp - * double *rs IO sat position and corrected {x,y,z} (ecef) (m) - * double *dts IO sat clock bias and corrected (s) - * double *var O sat position and clock variance (m^2) - * return : status (1:ok,0:no correction) - * notes : before calling the function, sbas satellite correction parameters - * in navigation data (nav->sbssat) must be set by callig - * sbsupdatecorr(). - * satellite clock correction include long-term correction and fast - * correction. - * sbas clock correction is usually based on L1C/A code. TGD or DCB has - * to be considered for other codes - *-----------------------------------------------------------------------------*/ - int sbssatcorr(double time_stamp, double *rs, double *dts, double *var); -}; - - -#endif /* GNSS_SDR_SBAS_SATELLITE_CORRECTION_H_ */ diff --git a/src/core/system_parameters/sbas_telemetry_data.cc b/src/core/system_parameters/sbas_telemetry_data.cc deleted file mode 100644 index 599f03b55..000000000 --- a/src/core/system_parameters/sbas_telemetry_data.cc +++ /dev/null @@ -1,978 +0,0 @@ -/*! - * \file sbas_telemetry_data.cc - * \brief Implementation of the SBAS telemetry parser based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_satellite_correction.h" -#include "sbas_ephemeris.h" - - -// logging levels -#define EVENT 2 // logs important events which don't occur every update() call -#define FLOW 3 // logs the function calls of block processing functions -#define DETAIL 4 - - - -Sbas_Telemetry_Data::Sbas_Telemetry_Data() -{ - fp_trace = nullptr; // file pointer of trace - level_trace = 0; // level of trace - tick_trace = 0; // tick time at traceopen (ms) - - d_nav.sbssat.iodp = -1; // make sure that in any case iodp is not equal to the received one - prn_mask_changed(); // invalidate all satellite corrections - - for(size_t band = 0; band < sizeof(d_nav.sbsion)/sizeof(sbsion_t); band++) - { - d_nav.sbsion[band].iodi = -1; // make sure that in any case iodi is not equal to the received one - igp_mask_changed(band); - } -} - -Sbas_Telemetry_Data::~Sbas_Telemetry_Data() -{ - -} - - -int Sbas_Telemetry_Data::update(Sbas_Raw_Msg sbas_raw_msg) -{ - VLOG(FLOW) << "<> Sbas_Telemetry_Data.update():"; - int parsing_result; - - // if GPS time from MT12 is known (automatically handled by relate()): - // express the rx time in terms of GPS time - sbas_raw_msg.relate(mt12_time_ref); - - int mt = sbas_raw_msg.get_msg_type(); - // update internal state - if(mt == 12) parsing_result = decode_mt12(sbas_raw_msg); - //else if(mt == 9) parsing_result = parse_mt9(sbas_raw_msg); - else - { - // use RTKLIB to parse the message -> updates d_nav structure - sbsmsg_t sbas_raw_msg_rtklib; - std::vector msg_bytes = sbas_raw_msg.get_msg(); - // cast raw message to RTKLIB raw message struct - sbas_raw_msg_rtklib.prn = sbas_raw_msg.get_prn(); - //sbas_raw_msg_rtklib.tow = sbas_raw_msg.get_tow(); - //sbas_raw_msg_rtklib.week = sbas_raw_msg.get_week(); - sbas_raw_msg_rtklib.sample_stamp = sbas_raw_msg.get_sample_stamp(); - for (std::vector::const_iterator it = msg_bytes.begin(); it != msg_bytes.end() - 3; ++it) - { - int i = it - msg_bytes.begin(); - sbas_raw_msg_rtklib.msg[i] = *it; - } - parsing_result = sbsupdatecorr(&sbas_raw_msg_rtklib, &d_nav); - VLOG(FLOW) << "<> RTKLIB parsing result: " << parsing_result; - } - - // update gnss-sdr correction data sets from RTKLIB d_nav structure, emit SBAS data into queues - switch (parsing_result) - { - case -1: VLOG(FLOW) << "message parsing problem for MT" << sbas_raw_msg.get_msg_type(); break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 24: - case 25: updated_satellite_corrections(); break; - case 18: break; // new iono band mask received -> dont update iono corrections because delays are not - case 26: received_iono_correction(); break; - case 9: /*updated_sbas_ephemeris(sbas_raw_msg);*/ break; - - default: break; - } - - // send it to raw message queue - //TODO: update to new GNURadio msg queue - //if(raw_msg_queue != nullptr) raw_msg_queue->push(sbas_raw_msg); - return parsing_result; -} - - -unsigned int getbitu(const unsigned char *buff, int pos, int len); - - - -int getbits(const unsigned char *buff, int pos, int len); - - - -int Sbas_Telemetry_Data::decode_mt12(Sbas_Raw_Msg sbas_raw_msg) -{ - const double rx_delay = 38000.0/300000.0; // estimated sbas signal geosat to ground signal travel time - unsigned char * msg = sbas_raw_msg.get_msg().data(); - uint32_t gps_tow = getbitu(msg, 121, 20); - uint32_t gps_week = getbitu(msg, 141, 10) + 1024; // consider last gps time week overflow - double gps_tow_rx = double(gps_tow) + rx_delay; - mt12_time_ref = Sbas_Time_Relation(sbas_raw_msg.get_sample_stamp(), gps_week, gps_tow_rx); - VLOG(FLOW) << "<> extracted GPS time from MT12: gps_tow=" << gps_tow << " gps_week=" << gps_week; - return 12; -} - - - - -void Sbas_Telemetry_Data::updated_sbas_ephemeris(Sbas_Raw_Msg msg) -{ - VLOG(FLOW) << "<> updated_sbas_ephemeris():" << std::endl; - Sbas_Ephemeris seph; - int satidx = msg.get_prn() - MINPRNSBS; - seph_t seph_rtklib = d_nav.seph[satidx]; - // copy data - seph.i_prn = msg.get_prn(); - seph.i_t0 = seph_rtklib.t0; - seph.d_tof = seph_rtklib.tof; - seph.i_sv_ura = seph_rtklib.sva; - seph.b_sv_do_not_use = seph_rtklib.svh; - memcpy(seph.d_pos, seph_rtklib.pos, sizeof(seph.d_pos)); - memcpy(seph.d_vel, seph_rtklib.vel, sizeof(seph.d_vel)); - memcpy(seph.d_acc, seph_rtklib.acc, sizeof(seph.d_acc)); - seph.d_af0 = seph_rtklib.af0; - seph.d_af1 = seph_rtklib.af1; - // print ephemeris for debugging purposes - std::stringstream ss; - seph.print(ss); - VLOG(FLOW) << ss.str(); - - //todo_Update to new GNURadio msg queue - //if(ephemeris_queue != nullptr) ephemeris_queue->push(seph); -} - - - -void Sbas_Telemetry_Data::received_iono_correction() -{ - VLOG(FLOW) << "<> received_iono_correction():"; - std::stringstream ss; - - Sbas_Ionosphere_Correction iono_corr; - for (size_t i_band = 0; i_band < sizeof(d_nav.sbsion)/sizeof(sbsion_t); i_band++) - { - ss << "<> band=" << i_band - << " nigp=" << d_nav.sbsion[i_band].nigp << std::endl; - ss << "<> -> valid igps:"; - Igp_Band igp_band; - for (int i_igp = 0; i_igp < d_nav.sbsion[i_band].nigp; i_igp++) - { - if(d_nav.sbsion[i_band].igp[i_igp].valid) - { - // consider only valid IGPs, i.e, such ones which got updated at least once since instantiating sbas_telemtry_data - ss << " " << i_igp; - Igp igp; - igp.t0 = d_nav.sbsion[i_band].igp[i_igp].t0; - igp.d_latitude = d_nav.sbsion[i_band].igp[i_igp].lat; - igp.d_longitude = d_nav.sbsion[i_band].igp[i_igp].lon; - igp.d_give = d_nav.sbsion[i_band].igp[i_igp].give; - igp.d_delay = d_nav.sbsion[i_band].igp[i_igp].delay; - igp_band.d_igps.push_back(igp); - } - } - ss << std::endl; - iono_corr.d_bands.push_back(igp_band); - } - VLOG(DETAIL) << ss.str(); - ss.str(""); - iono_corr.print(ss); - VLOG(EVENT) << ss.str(); - - // send to SBAS ionospheric correction queue - //todo_Update to new GNURadio msg queue - //if(iono_queue != nullptr) iono_queue->push(iono_corr); -} - - -// helper for comparing two POD structures with undefined padding between members -// not guaranteed to work always properly -> don't use it for critical tasks -template -inline bool are_equal(const Struct &s1, const Struct &s2) -{ - const size_t struct_size = sizeof(Struct); - bool is_equal = true; - bool is_equal_manual = true; - std::stringstream ss; - - Struct *s1_; - Struct *s2_; - - // reserve zero initialised memory - s1_ = (Struct*) calloc (1, struct_size); - s2_ = (Struct*) calloc (1, struct_size); - - // use assignment constructor which doesn't copy paddings - *s1_ = s1; - *s2_ = s2; - - // compare struct memory byte-wise - is_equal_manual = true; - ss.str(); - ss << "\n<> compare objects of size=" << sizeof(Struct) << " (memcmp says is_equal=" << is_equal << ") :" << std::endl; - for (size_t i = 0; i < sizeof(Struct); ++i) - { - char byte1 = ((char *)s1_)[i]; - char byte2 = ((char *)s2_)[i]; - if(byte1 != byte2) is_equal_manual = false; - ss << "<> s1=" << std::hex << std::setw(4) << std::setfill('0'); - ss << (short)byte1; - ss << " s2=" << std::hex << std::setw(4) << std::setfill('0'); - ss << (short)byte2; - ss << " equal=" << is_equal_manual; - ss << std::endl; - } - - free(s1_); - free(s2_); - - return is_equal_manual; -} - - - -void Sbas_Telemetry_Data::updated_satellite_corrections() -{ - VLOG(FLOW) << "<> updated_satellite_corrections():"; - // for each satellite in the RTKLIB structure - for (int i_sat = 0; i_sat < d_nav.sbssat.nsat; i_sat++) - { - std::stringstream ss; - ss << "<> sat=" << d_nav.sbssat.sat[i_sat].sat - << " fastcorr.valid=" << d_nav.sbssat.sat[i_sat].fcorr.valid - << " lcorr.valid=" << d_nav.sbssat.sat[i_sat].lcorr.valid; - - if(is_rtklib_sat_correction_valid(i_sat)) // check if ever updated by a received message - { - int prn = d_nav.sbssat.sat[i_sat].sat; - - // get fast correction from RTKLIB structure - sbsfcorr_t fcorr_rtklib = d_nav.sbssat.sat[i_sat].fcorr; - Fast_Correction fcorr; - fcorr.d_tof = Sbas_Time(fcorr_rtklib.t0, mt12_time_ref); - fcorr.d_prc = fcorr_rtklib.prc; - fcorr.d_rrc = fcorr_rtklib.rrc; - fcorr.d_dt = fcorr_rtklib.dt; - fcorr.d_udre = fcorr_rtklib.udre; // UDRE - fcorr.d_ai = fcorr_rtklib.ai; - fcorr.d_tlat = d_nav.sbssat.tlat; - - // get long term correction from RTKLIB structure - sbslcorr_t lcorr_rtklib = d_nav.sbssat.sat[i_sat].lcorr; - Long_Term_Correction lcorr; - lcorr.d_trx = lcorr_rtklib.trx; - lcorr.i_tapp = lcorr_rtklib.tapp; - lcorr.i_vel = lcorr_rtklib.vel; - lcorr.d_iode = lcorr_rtklib.iode; - memcpy(lcorr.d_dpos, lcorr_rtklib.dpos, sizeof(lcorr.d_dpos)); - memcpy(lcorr.d_dvel, lcorr_rtklib.dvel, sizeof(lcorr.d_dvel)); - lcorr.d_daf0 = lcorr_rtklib.daf0; - lcorr.d_daf1= lcorr_rtklib.daf1; - - bool fast_correction_updated = false; - bool long_term_correction_updated = false; - - // check if fast corrections got updated - std::map::iterator it_old_fcorr = emitted_fast_corrections.find(prn); - if(it_old_fcorr == emitted_fast_corrections.end() || !are_equal < Fast_Correction>(fcorr, it_old_fcorr->second )) - { - // got updated - ss << " fast_correction_updated=" << true; - //ss << " not_found=" << (it_old_fcorr == emitted_fast_corrections.end()); - //ss << " not_equal=" << (!are_equal(fcorr, it_old_fcorr->second )); - fast_correction_updated = true; - emitted_fast_corrections[prn] = fcorr; - } - - // check if long term corrections got updated - std::map::iterator it_old_lcorr = emitted_long_term_corrections.find(prn); - if(it_old_lcorr == emitted_long_term_corrections.end() || !are_equal < Long_Term_Correction>(lcorr, it_old_lcorr->second )) - { - // got updated - ss << " long_term_correction_updated=" << true; - //ss << " not_found=" << (it_old_lcorr == emitted_long_term_corrections.end()); - //ss << " not_equal=" << (!are_equal(lcorr, it_old_lcorr->second )); - long_term_correction_updated = true; - emitted_long_term_corrections[prn] = lcorr; - } - - Sbas_Satellite_Correction sbas_satelite_correction; - sbas_satelite_correction.d_prn = prn; - sbas_satelite_correction.d_fast_correction = fcorr; - sbas_satelite_correction.d_long_term_correction = lcorr; - - if(fast_correction_updated) - { - ss << std::endl; - sbas_satelite_correction.print_fast_correction(ss << " "); - } - - if(long_term_correction_updated) - { - ss << std::endl; - sbas_satelite_correction.print_long_term_correction(ss << " "); - } - - if(fast_correction_updated || long_term_correction_updated) - { - //todo_Update to new GNURadio msg queue - //if(sat_corr_queue != nullptr) sat_corr_queue->push(sbas_satelite_correction); - } - } - VLOG(FLOW) << ss.str(); ss.str(""); - } -} - - - -const double Sbas_Telemetry_Data::gpst0[] = {1980, 1, 6, 0, 0, 0}; /* gps time reference */ - -/* debug trace function -----------------------------------------------------*/ -void Sbas_Telemetry_Data::trace(int level, const char *format, ...) -{ - va_list ap; - char str[1000]; - va_start(ap, format); - vsprintf(str, format, ap); - va_end(ap); - VLOG(FLOW) << "<> " << std::string(str); -} - - - -/* satellite system+prn/slot number to satellite number ------------------------ - * convert satellite system+prn/slot number to satellite number - * args : int sys I satellite system (SYS_GPS,SYS_GLO,...) - * int prn I satellite prn/slot number - * return : satellite number (0:error) - *-----------------------------------------------------------------------------*/ -int Sbas_Telemetry_Data::satno(int sys, int prn) -{ - if (prn <= 0) return 0; - switch (sys) - { - case SYS_GPS: - if (prn < MINPRNGPS || MAXPRNGPS < prn) return 0; - return prn - MINPRNGPS + 1; - case SYS_GLO: - if (prn < MINPRNGLO || MAXPRNGLO < prn) return 0; - return NSATGPS + prn - MINPRNGLO + 1; - case SYS_GAL: - if (prn < MINPRNGAL || MAXPRNGAL < prn) return 0; - return NSATGPS + NSATGLO + prn - MINPRNGAL + 1; - case SYS_QZS: - if (prn < MINPRNQZS || MAXPRNQZS < prn) return 0; - return NSATGPS + NSATGLO + NSATGAL + prn - MINPRNQZS + 1; - case SYS_CMP: - if (prn < MINPRNCMP || MAXPRNCMP < prn) return 0; - return NSATGPS + NSATGLO + NSATGAL + NSATQZS + prn - MINPRNCMP + 1; - case SYS_SBS: - if (prn < MINPRNSBS || MAXPRNSBS < prn) return 0; - return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + prn - MINPRNSBS + 1; - } - return 0; -} - -/*! - * \brief Extracts unsigned/signed bits from byte data - * params : unsigned char *buff I byte data - * int pos I bit position from start of data (bits) - * int len I bit length (bits) (len<=32) - * return : extracted unsigned/signed bits - */ -unsigned int Sbas_Telemetry_Data::getbitu(const unsigned char *buff, int pos, int len) -{ - unsigned int bits = 0; - int i; - for (i = pos; i < pos + len; i++) bits = (bits << 1) + ((buff[i/8] >> (7 - i % 8)) & 1u); - return bits; -} - - - -int Sbas_Telemetry_Data::getbits(const unsigned char *buff, int pos, int len) -{ - unsigned int bits = getbitu(buff,pos,len); - if (len <= 0 || 32 <= len || !(bits & (1u << (len - 1)))) return (int)bits; - return (int)(bits|(~0u << len)); /* extend sign */ -} - - - -/* convert calendar day/time to time ------------------------------------------- - * convert calendar day/time to gtime_t struct - * args : double *ep I day/time {year,month,day,hour,min,sec} - * return : gtime_t struct - * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) - *-----------------------------------------------------------------------------*/ -Sbas_Telemetry_Data::gtime_t Sbas_Telemetry_Data::epoch2time(const double *ep) -{ - const int doy[] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; - gtime_t time = gtime_t(); - int days, sec, year = (int)ep[0], mon = (int)ep[1], day = (int)ep[2]; - - if (year < 1970 || 2099 < year || mon < 1 || 12 < mon) return time; - - /* leap year if year%4==0 in 1901-2099 */ - days = (year - 1970)*365 + (year - 1969)/4 + doy[mon - 1] + day - 2 + (year % 4 == 0 && mon >= 3 ? 1 : 0); - sec = (int)floor(ep[5]); - time.time = (time_t)days*86400 + (int)ep[3]*3600 + (int)ep[4]*60 + sec; - time.sec = ep[5] - sec; - return time; -} - - - - -/* time difference ------------------------------------------------------------- - * difference between gtime_t structs - * args : gtime_t t1,t2 I gtime_t structs - * return : time difference (t1-t2) (s) - *-----------------------------------------------------------------------------*/ -double Sbas_Telemetry_Data::timediff(gtime_t t1, gtime_t t2) -{ - return difftime(t1.time, t2.time) + t1.sec - t2.sec; -} - - - -/* gps time to time ------------------------------------------------------------ - * convert week and tow in gps time to gtime_t struct - * args : int week I week number in gps time - * double sec I time of week in gps time (s) - * return : gtime_t struct - *-----------------------------------------------------------------------------*/ -Sbas_Telemetry_Data::gtime_t Sbas_Telemetry_Data::gpst2time(int week, double sec) -{ - gtime_t t = epoch2time(gpst0); - if (sec < -1E9 || 1E9 < sec) sec = 0.0; - t.time += 86400*7*week + (int)sec; - t.sec = sec - (int)sec; - return t; -} - - - -/* sbas igp definition -------------------------------------------------------*/ -const short -Sbas_Telemetry_Data::x1[] = {-75,-65,-55,-50,-45,-40,-35,-30,-25,-20,-15,-10,- 5, 0, 5, 10, 15, 20, - 25, 30, 35, 40, 45, 50, 55, 65, 75, 85}, -Sbas_Telemetry_Data::x2[] = {-55,-50,-45,-40,-35,-30,-25,-20,-15,-10, -5, 0, 5, 10, 15, 20, 25, 30, - 35, 40, 45, 50, 55}, -Sbas_Telemetry_Data::x3[] = {-75,-65,-55,-50,-45,-40,-35,-30,-25,-20,-15,-10,- 5, 0, 5, 10, 15, 20, - 25, 30, 35, 40, 45, 50, 55, 65, 75}, -Sbas_Telemetry_Data::x4[] = {-85,-75,-65,-55,-50,-45,-40,-35,-30,-25,-20,-15,-10,- 5, 0, 5, 10, 15, - 20, 25, 30, 35, 40, 45, 50, 55, 65, 75}, -Sbas_Telemetry_Data::x5[] = {-180,-175,-170,-165,-160,-155,-150,-145,-140,-135,-130,-125,-120,-115, - -110,-105,-100,- 95,- 90,- 85,- 80,- 75,- 70,- 65,- 60,- 55,- 50,- 45, - - 40,- 35,- 30,- 25,- 20,- 15,- 10,- 5, 0, 5, 10, 15, 20, 25, - 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, - 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, - 170, 175}, -Sbas_Telemetry_Data::x6[] = {-180,-170,-160,-150,-140,-130,-120,-110,-100,- 90,- 80,- 70,- 60,- 50, - -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, - 100, 110, 120, 130, 140, 150, 160, 170}, -Sbas_Telemetry_Data::x7[] = {-180,-150,-120,- 90,- 60,- 30, 0, 30, 60, 90, 120, 150}, -Sbas_Telemetry_Data::x8[] = {-170,-140,-110,- 80,- 50,- 20, 10, 40, 70, 100, 130, 160}; - -const Sbas_Telemetry_Data::sbsigpband_t Sbas_Telemetry_Data::igpband1[9][8] = { /* band 0-8 */ - {{-180,x1, 1, 28},{-175,x2, 29, 51},{-170,x3, 52, 78},{-165,x2, 79,101}, - {-160,x3,102,128},{-155,x2,129,151},{-150,x3,152,178},{-145,x2,179,201}}, - {{-140,x4, 1, 28},{-135,x2, 29, 51},{-130,x3, 52, 78},{-125,x2, 79,101}, - {-120,x3,102,128},{-115,x2,129,151},{-110,x3,152,178},{-105,x2,179,201}}, - {{-100,x3, 1, 27},{- 95,x2, 28, 50},{- 90,x1, 51, 78},{- 85,x2, 79,101}, - {- 80,x3,102,128},{- 75,x2,129,151},{- 70,x3,152,178},{- 65,x2,179,201}}, - {{- 60,x3, 1, 27},{- 55,x2, 28, 50},{- 50,x4, 51, 78},{- 45,x2, 79,101}, - {- 40,x3,102,128},{- 35,x2,129,151},{- 30,x3,152,178},{- 25,x2,179,201}}, - {{- 20,x3, 1, 27},{- 15,x2, 28, 50},{- 10,x3, 51, 77},{- 5,x2, 78,100}, - { 0,x1,101,128},{ 5,x2,129,151},{ 10,x3,152,178},{ 15,x2,179,201}}, - {{ 20,x3, 1, 27},{ 25,x2, 28, 50},{ 30,x3, 51, 77},{ 35,x2, 78,100}, - { 40,x4,101,128},{ 45,x2,129,151},{ 50,x3,152,178},{ 55,x2,179,201}}, - {{ 60,x3, 1, 27},{ 65,x2, 28, 50},{ 70,x3, 51, 77},{ 75,x2, 78,100}, - { 80,x3,101,127},{ 85,x2,128,150},{ 90,x1,151,178},{ 95,x2,179,201}}, - {{ 100,x3, 1, 27},{ 105,x2, 28, 50},{ 110,x3, 51, 77},{ 115,x2, 78,100}, - { 120,x3,101,127},{ 125,x2,128,150},{ 130,x4,151,178},{ 135,x2,179,201}}, - {{ 140,x3, 1, 27},{ 145,x2, 28, 50},{ 150,x3, 51, 77},{ 155,x2, 78,100}, - { 160,x3,101,127},{ 165,x2,128,150},{ 170,x3,151,177},{ 175,x2,178,200}} -}; - - - -const Sbas_Telemetry_Data::sbsigpband_t Sbas_Telemetry_Data::igpband2[2][5] = { /* band 9-10 */ - {{ 60,x5, 1, 72},{ 65,x6, 73,108},{ 70,x6,109,144},{ 75,x6,145,180}, - { 85,x7,181,192}}, - {{- 60,x5, 1, 72},{- 65,x6, 73,108},{- 70,x6,109,144},{- 75,x6,145,180}, - {- 85,x8,181,192}} -}; - - -/* decode type 1: prn masks --------------------------------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype1(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - int i, n, sat; - // see figure A-6: i corresponds to bit number (and for the GPS satellites is identically to the PRN), n to the PRN mask number - - trace(4, "decode_sbstype1:"); - - for (i = 1, n = 0; i <= 210 && n < MAXSAT; i++) - { - if (getbitu(msg->msg, 13 + i, 1)) - { - if (i <= 37) sat = satno(SYS_GPS, i); /* 0 - 37: gps */ - else if (i <= 61) sat = satno(SYS_GLO, i - 37); /* 38 - 61: glonass */ - else if (i <= 119) sat = 0; /* 62 - 119: future gnss */ - else if (i <= 138) sat = satno(SYS_SBS, i); /* 120 - 138: geo/waas */ - else if (i <= 182) sat = 0; /* 139 - 182: reserved */ - else if (i <= 192) sat = satno(SYS_SBS, i + 10); /* 183 - 192: qzss ref [2] */ - else if (i <= 202) sat = satno(SYS_QZS, i); /* 193 - 202: qzss ref [2] */ - else sat = 0; /* 203 - : reserved */ - sbssat->sat[n++].sat = sat; - } - } - // TODO consider the use of the old prn mask in the transition phase such that old data sets still can be used - int new_iodp = getbitu(msg->msg, 224, 2); - if (sbssat->iodp != new_iodp) prn_mask_changed(); // invalidate all satellite corrections - sbssat->iodp = new_iodp; - sbssat->nsat = n; - - trace(5, "decode_sbstype1: nprn=%d iodp=%d", n, sbssat->iodp); - return 1; -} - - -/* decode type 2-5,0: fast corrections ---------------------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype2(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - int i, j, iodf, type, udrei; - double prc, dt; - double t0_past; - - trace(4,"decode_sbstype2:"); - - if (sbssat->iodp != (int)getbitu(msg->msg, 16, 2)) return 0; - - type = getbitu(msg->msg, 8, 6); - iodf = getbitu(msg->msg, 14, 2); - - for (i=0; i<13; i++) - { - if ((j = 13*((type == 0 ? 2 : type) - 2) + i) >= sbssat->nsat) break; - udrei = getbitu(msg->msg, 174 + 4*i, 4); - t0_past = sbssat->sat[j].fcorr.t0; - prc = sbssat->sat[j].fcorr.prc; - sbssat->sat[j].fcorr.t0 = msg->sample_stamp; - sbssat->sat[j].fcorr.prc = getbits(msg->msg, 18 + i*12, 12)*0.125f; - sbssat->sat[j].fcorr.udre = udrei + 1; - dt = sbssat->sat[j].fcorr.t0 - t0_past; - if (!sbssat->sat[j].fcorr.valid || dt <= 0.0 || 18.0 < dt || sbssat->sat[j].fcorr.ai == 0) - { - sbssat->sat[j].fcorr.rrc = 0.0; - sbssat->sat[j].fcorr.dt = 0.0; - } - else - { - sbssat->sat[j].fcorr.rrc = (sbssat->sat[j].fcorr.prc - prc)/dt; - sbssat->sat[j].fcorr.dt = dt; - } - sbssat->sat[j].fcorr.valid = true; - sbssat->sat[j].fcorr.iodf = iodf; - } - trace(5, "decode_sbstype2: type=%d iodf=%d", type, iodf); - return 1; -} - - - - -/* decode type 6: integrity info ---------------------------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype6(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - int i, iodf[4], udrei; - - trace(4, "decode_sbstype6:"); - - if(sbssat->iodp < 0) return 0; - - for (i=0; i<4; i++) - { - iodf[i] = getbitu(msg->msg, 14 + i*2, 2); - } - for (i=0; i < sbssat->nsat && i < MAXSAT; i++) - { - if (!sbssat->sat[i].fcorr.valid || sbssat->sat[i].fcorr.iodf != iodf[i/13]) continue; - udrei = getbitu(msg->msg, 22 + i*4, 4); - sbssat->sat[i].fcorr.udre = udrei + 1; - } - trace(5, "decode_sbstype6: iodf=%d %d %d %d", iodf[0], iodf[1], iodf[2], iodf[3]); - return 1; -} - - - -/* decode type 7: fast correction degradation factor -------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype7(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - int i; - trace(4,"decode_sbstype7"); - if (sbssat->iodp != (int)getbitu(msg->msg, 18, 2)) return 0; - sbssat->tlat = getbitu(msg->msg, 14, 4); - for (i=0; i < sbssat->nsat && i < MAXSAT; i++) - { - sbssat->sat[i].fcorr.ai = getbitu(msg->msg, 22 + i*4, 4); - } - return 1; -} - - - -/* decode type 9: geo navigation message -------------------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype9(const sbsmsg_t *msg, nav_t *nav) -{ - seph_t seph; - int i; - int sat; - - trace(4,"decode_sbstype9:"); - - if (!(sat = satno(SYS_SBS, msg->prn))) - { - trace(2, "invalid prn in sbas type 9: prn=%3d", msg->prn); - return 0; - } - /*t=(int)getbitu(msg->msg,22,13)*16-(int)msg->tow%86400; - if (t<=-43200) t+=86400; - else if (t> 43200) t-=86400;*/ - //seph.t0 =gpst2time(msg->week,msg->tow+t); - seph.sat = sat; - seph.t0 = getbitu(msg->msg, 22, 13)*16; - seph.tof = msg->sample_stamp; - seph.sva = getbitu(msg->msg, 35, 4); - seph.svh = seph.sva == 15 ? 1 : 0; /* unhealthy if ura==15 */ - - seph.pos[0] = getbits(msg->msg, 39, 30)*0.08; - seph.pos[1] = getbits(msg->msg, 69, 30)*0.08; - seph.pos[2] = getbits(msg->msg, 99, 25)*0.4; - seph.vel[0] = getbits(msg->msg, 124, 17)*0.000625; - seph.vel[1] = getbits(msg->msg, 141, 17)*0.000625; - seph.vel[2] = getbits(msg->msg, 158, 18)*0.004; - seph.acc[0] = getbits(msg->msg, 176, 10)*0.0000125; - seph.acc[1] = getbits(msg->msg, 186, 10)*0.0000125; - seph.acc[2] = getbits(msg->msg, 196, 10)*0.0000625; - - seph.af0 = getbits(msg->msg, 206, 12)*P2_31; - seph.af1 = getbits(msg->msg, 218, 8)*P2_39/2.0; - - i = msg->prn-MINPRNSBS; - if (std::abs(nav->seph[i].t0 - seph.t0) < 1E-3) - { /* not change */ - VLOG(FLOW) << "<> no change in ephemeris -> won't parse"; - return 0; - } - nav->seph[NSATSBS + i] = nav->seph[i]; /* previous */ - nav->seph[i] = seph; /* current */ - - trace(5, "decode_sbstype9: prn=%d", msg->prn); - return 1; -} - - - -/* decode type 18: ionospheric grid point masks ------------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype18(const sbsmsg_t *msg, sbsion_t *sbsion) -{ - const sbsigpband_t *p; - int i, j, n, m, band = getbitu(msg->msg, 18, 4); - - trace(4, "decode_sbstype18:"); - - if (0 <= band && band <= 8) {p = igpband1[band]; m = 8;} - else if (9 <= band && band <= 10) {p = igpband2[band - 9]; m = 5;} - else return 0; - - short iodi_new = (short)getbitu(msg->msg, 22, 2); - if(sbsion[band].iodi != iodi_new) - { - // IGP mask changed -> invalidate all IGPs in this band - igp_mask_changed(band); - } - sbsion[band].iodi = iodi_new; - - for (i=1, n=0; i <= 201; i++) - { - if (!getbitu(msg->msg, 23 + i, 1)) continue; - for (j = 0; j < m; j++) - { - if (i < p[j].bits || p[j].bite < i) continue; - sbsion[band].igp[n].lat = band <= 8 ? p[j].y[i - p[j].bits] : p[j].x; - sbsion[band].igp[n++].lon = band <= 8 ? p[j].x : p[j].y[i - p[j].bits]; - break; - } - } - sbsion[band].nigp = n; - - trace(5, "decode_sbstype18: band=%d nigp=%d", band, n); - return 1; -} - - - - -/* decode half long term correction (vel code=0) -----------------------------*/ -int Sbas_Telemetry_Data::decode_longcorr0(const sbsmsg_t *msg, int p, sbssat_t *sbssat) -{ - int i, n = getbitu(msg->msg, p, 6); - - trace(4, "decode_longcorr0:"); - - if (n == 0 || n > MAXSAT) return 0; - - sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8); - - for (i = 0; i < 3; i++) - { - sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + 9*i, 9)*0.125; - sbssat->sat[n - 1].lcorr.dvel[i] = 0.0; - } - sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 41, 10)*P2_31; - sbssat->sat[n - 1].lcorr.daf1 = 0.0; - //sbssat->sat[n-1].lcorr.t0=gpst2time(msg->week,msg->tow); - sbssat->sat[n - 1].lcorr.trx = msg->sample_stamp; // vel=0 -> time of applicability is reception time - sbssat->sat[n - 1].lcorr.tapp = 0; - sbssat->sat[n - 1].lcorr.valid = true; - - trace(5, "decode_longcorr0:sat=%2d", sbssat->sat[n - 1].sat); - return 1; -} - - - -/* decode half long term correction (vel code=1) -----------------------------*/ -int Sbas_Telemetry_Data::decode_longcorr1(const sbsmsg_t *msg, int p, sbssat_t *sbssat) -{ - int i; - int n = getbitu(msg->msg, p, 6); - - trace(4,"decode_longcorr1:"); - - if (n == 0 || n > MAXSAT) return 0; - - sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8); - - for (i=0; i<3; i++) - { - sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + i*11, 11)*0.125; - sbssat->sat[n - 1].lcorr.dvel[i] = getbits(msg->msg, p + 58 + i*8, 8)*P2_11; - } - sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 47, 11)*P2_31; - sbssat->sat[n - 1].lcorr.daf1 = getbits(msg->msg, p + 82, 8)*P2_39; - // vel=1 -> time of applicability is sent in message, needs to be corrected for rollover which can not be done here, since the absolute gps time is unknown. see IS-GPS-200G pdf page 116 for correction - /*t=(int)getbitu(msg->msg,p+90,13)*16-(int)msg->tow%86400; - if (t<=-43200) t+=86400; - else if (t> 43200) t-=86400; - sbssat->sat[n-1].lcorr.t0=gpst2time(msg->week,msg->tow+t);*/ - sbssat->sat[n - 1].lcorr.trx = msg->sample_stamp; - sbssat->sat[n - 1].lcorr.tapp = (int)getbitu(msg->msg, p + 90, 13)*16; - sbssat->sat[n - 1].lcorr.vel = 1; - sbssat->sat[n - 1].lcorr.valid = true; - trace(5, "decode_longcorr1: sat=%2d", sbssat->sat[n - 1].sat); - return 1; -} - - - - -/* decode half long term correction ------------------------------------------*/ -int Sbas_Telemetry_Data::decode_longcorrh(const sbsmsg_t *msg, int p, sbssat_t *sbssat) -{ - trace(4,"decode_longcorrh:"); - - if (getbitu(msg->msg, p, 1) == 0 ) - { - /* vel code=0 */ - if (sbssat->iodp == (int)getbitu(msg->msg, p + 103, 2)) - { - return decode_longcorr0(msg, p + 1, sbssat) && decode_longcorr0(msg, p + 52, sbssat); - } - } - else if (sbssat->iodp == (int)getbitu(msg->msg, p + 104, 2)) - { - return decode_longcorr1(msg, p + 1, sbssat); - } - return 0; -} - - - - -/* decode type 24: mixed fast/long term correction ---------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype24(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - int i, j, iodf, blk, udre; - - trace(4, "decode_sbstype24:"); - - if (sbssat->iodp != (int)getbitu(msg->msg, 110, 2)) return 0; /* check IODP */ - - blk = getbitu(msg->msg, 112, 2); - iodf =getbitu(msg->msg, 114, 2); - - for (i=0; i<6; i++) - { - if ((j = 13*blk+i) >= sbssat->nsat) break; - udre = getbitu(msg->msg, 86 + 4*i, 4); - - //sbssat->sat[j].fcorr.t0 =gpst2time(msg->week,msg->tow); - sbssat->sat[j].fcorr.t0 = msg->sample_stamp; - sbssat->sat[j].fcorr.prc = getbits(msg->msg, 14 + i*12, 12)*0.125f; - sbssat->sat[j].fcorr.udre = udre + 1; - sbssat->sat[j].fcorr.iodf = iodf; - } - return decode_longcorrh(msg, 120, sbssat); -} - - - - -/* decode type 25: long term satellite error correction ----------------------*/ -int Sbas_Telemetry_Data::decode_sbstype25(const sbsmsg_t *msg, sbssat_t *sbssat) -{ - trace(4,"decode_sbstype25:"); - return decode_longcorrh(msg, 14, sbssat) && decode_longcorrh(msg, 120, sbssat); -} - - - - -/* decode type 26: ionospheric delay corrections -----------------------------*/ -int Sbas_Telemetry_Data::decode_sbstype26(const sbsmsg_t *msg, sbsion_t *sbsion) -{ - int i, j, block, delay, give, band = getbitu(msg->msg, 14, 4); - - trace(4, "decode_sbstype26:"); - - if (band > MAXBAND || sbsion[band].iodi != (int)getbitu(msg->msg, 217, 2)) return 0; - - block = getbitu(msg->msg, 18, 4); - - for (i = 0; i < 15; i++) - { - if ((j = block*15 + i) >= sbsion[band].nigp) continue; - give = getbitu(msg->msg, 2 + i*13 + 9, 4); - delay = getbitu(msg->msg, 22 + i*13, 9); - //sbsion[band].igp[j].t0=gpst2time(msg->week,msg->tow); - sbsion[band].igp[j].t0 = msg->sample_stamp; - sbsion[band].igp[j].valid = true; - sbsion[band].igp[j].delay = delay == 0x1FF ? 0.0f : delay*0.125f; - sbsion[band].igp[j].give = give; - - if(sbsion[band].igp[j].give > 15) sbsion[band].igp[j].give = 15; // give is not higher than 15, but to be sure - } - trace(5, "decode_sbstype26: band=%d block=%d", band, block); - return 1; -} - - - - -/* update sbas corrections ----------------------------------------------------- - * update sbas correction parameters in navigation data with a sbas message - * args : sbsmg_t *msg I sbas message - * nav_t *nav IO navigation data - * return : message type (-1: error or not supported type) - * notes : nav->seph must point to seph[NSATSBS*2] (array of seph_t) - * seph[prn-MINPRNSBS+1] : sat prn current epehmeris - * seph[prn-MINPRNSBS+1+MAXPRNSBS]: sat prn previous epehmeris - *-----------------------------------------------------------------------------*/ -int Sbas_Telemetry_Data::sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav) -{ - int type = getbitu(msg->msg, 8, 6), stat = -1; - - trace(3,"sbsupdatecorr: type=%d",type); - - //if (msg->week==0) return -1; - - switch (type) - { - case 0: stat = decode_sbstype2(msg, &nav->sbssat); break; - case 1: stat = decode_sbstype1(msg, &nav->sbssat); break; - case 2: - case 3: - case 4: - case 5: stat = decode_sbstype2(msg, &nav->sbssat); break; - case 6: stat = decode_sbstype6(msg, &nav->sbssat); break; - case 7: stat = decode_sbstype7(msg, &nav->sbssat); break; - case 9: stat = decode_sbstype9(msg, nav); break; - case 10: trace(2, "unsupported sbas message: type=%d", type); break; - case 12: trace(2, "unsupported sbas message: type=%d", type); break; - case 17: trace(2, "unsupported sbas message: type=%d", type); break; - case 18: stat = decode_sbstype18(msg, nav ->sbsion); break; - case 24: stat = decode_sbstype24(msg, &nav->sbssat); break; - case 25: stat = decode_sbstype25(msg, &nav->sbssat); break; - case 26: stat = decode_sbstype26(msg, nav ->sbsion); break; - case 63: break; /* null message */ - - default: trace(2, "Unsupported SBAS message: type=%d", type); break; - } - return stat ? type : -1; -} - - -void Sbas_Telemetry_Data::prn_mask_changed() -{ - d_nav.sbssat.tlat = -1; - // for each satellite in the RTKLIB structure - for (int i_sat = 0; i_sat < d_nav.sbssat.nsat; i_sat++) - { - d_nav.sbssat.sat[i_sat].fcorr.valid = false; - d_nav.sbssat.sat[i_sat].lcorr.valid = false; - } -} - - -bool Sbas_Telemetry_Data::is_rtklib_sat_correction_valid(int sat) -{ - return d_nav.sbssat.tlat > -1 - && d_nav.sbssat.sat[sat].fcorr.valid - && d_nav.sbssat.sat[sat].lcorr.valid; -} - - -void Sbas_Telemetry_Data::igp_mask_changed(int band) -{ - for(int i_igp = 0; i_igp < d_nav.sbsion[band].nigp; i_igp++) - d_nav.sbsion[band].igp[i_igp].valid = false; -} diff --git a/src/core/system_parameters/sbas_telemetry_data.h b/src/core/system_parameters/sbas_telemetry_data.h deleted file mode 100644 index 9f75dee07..000000000 --- a/src/core/system_parameters/sbas_telemetry_data.h +++ /dev/null @@ -1,492 +0,0 @@ -/*! - * \file sbas_telemetry_data.h - * \brief Interface of the SBAS telemetry parser based on SBAS RTKLIB functions - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_SBAS_TELEMETRY_DATA_H_ -#define GNSS_SDR_SBAS_TELEMETRY_DATA_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "boost/assign.hpp" -#include "concurrent_queue.h" -#include "sbas_time.h" - - -class Sbas_Ionosphere_Correction; -class Sbas_Satellite_Correction; -struct Fast_Correction; -struct Long_Term_Correction; -class Sbas_Ephemeris; - - -/*! - * \brief Represents a raw SBAS message of 250cbits + 6 bits padding - * (8b preamble + 6b message type + 212b data + 24b CRC + 6b zero padding) - */ -class Sbas_Raw_Msg -{ -public: - Sbas_Raw_Msg(){ rx_time = Sbas_Time(0); i_prn = -1; }; - Sbas_Raw_Msg(double sample_stamp, int prn, const std::vector msg) : rx_time(sample_stamp), i_prn(prn), d_msg(msg) {} - double get_sample_stamp() { return rx_time.get_time_stamp(); } //!< Time of reception sample stamp (first sample of preample) - void relate(Sbas_Time_Relation time_relation) - { - rx_time.relate(time_relation); - } - Sbas_Time get_rx_time_obj() const { return rx_time; } - int get_prn() const { return i_prn; } - std::vector get_msg() const { return d_msg; } - int get_preamble() - { - return d_msg[0]; - } - int get_msg_type() const - { - return d_msg[1] >> 2; - } - int get_crc() - { - unsigned char crc_last_byte = (d_msg[30] << 2) && (d_msg[31] >> 6); - unsigned char crc_middle_byte = (d_msg[29] << 2) && (d_msg[30] >> 6); - unsigned char crc_first_byte = (d_msg[28] << 2) && (d_msg[29] >> 6); - return ((unsigned int)(crc_first_byte) << 16) && ((unsigned int)(crc_middle_byte) << 8) && crc_last_byte; - } -private: - Sbas_Time rx_time; - int i_prn; /* SBAS satellite PRN number */ - std::vector d_msg; /* SBAS message (226 bit) padded by 0 */ -}; - - - - -/* - * \brief Holds an updated set of the telemetry data received from SBAS - */ -class Sbas_Telemetry_Data -{ -public: - int update(Sbas_Raw_Msg sbas_raw_msg); - - /*! - * Default constructor - */ - Sbas_Telemetry_Data(); - /*! - * Default deconstructor - */ - ~Sbas_Telemetry_Data(); - -private: - std::map emitted_fast_corrections; - std::map emitted_long_term_corrections; - - Sbas_Time_Relation mt12_time_ref; - - int decode_mt12(Sbas_Raw_Msg sbas_raw_msg); - - void updated_sbas_ephemeris(Sbas_Raw_Msg msg); - void received_iono_correction(); - void updated_satellite_corrections(); - - /////// rtklib.h - -#define SYS_NONE 0x00 /* navigation system: none */ -#define SYS_GPS 0x01 /* navigation system: GPS */ -#define SYS_SBS 0x02 /* navigation system: SBAS */ -#define SYS_GLO 0x04 /* navigation system: GLONASS */ -#define SYS_GAL 0x08 /* navigation system: Galileo */ -#define SYS_QZS 0x10 /* navigation system: QZSS */ -#define SYS_CMP 0x20 /* navigation system: BeiDou */ -#define SYS_ALL 0xFF /* navigation system: all */ - -#define TSYS_GPS 0 /* time system: GPS time */ -#define TSYS_UTC 1 /* time system: UTC */ -#define TSYS_GLO 2 /* time system: GLONASS time */ -#define TSYS_GAL 3 /* time system: Galileo time */ -#define TSYS_QZS 4 /* time system: QZSS time */ -#define TSYS_CMP 5 /* time system: BeiDou time */ - -#ifndef NFREQ -#define NFREQ 3 /* number of carrier frequencies */ -#endif -#define NFREQGLO 2 /* number of carrier frequencies of GLONASS */ - -#ifndef NEXOBS -#define NEXOBS 0 /* number of extended obs codes */ -#endif - -#define MINPRNGPS 1 /* min satellite PRN number of GPS */ -#define MAXPRNGPS 32 /* max satellite PRN number of GPS */ -#define NSATGPS (MAXPRNGPS-MINPRNGPS+1) /* number of GPS satellites */ -#define NSYSGPS 1 - -#ifdef ENAGLO -#define MINPRNGLO 1 /* min satellite slot number of GLONASS */ -#define MAXPRNGLO 24 /* max satellite slot number of GLONASS */ -#define NSATGLO (MAXPRNGLO-MINPRNGLO+1) /* number of GLONASS satellites */ -#define NSYSGLO 1 -#else -#define MINPRNGLO 0 -#define MAXPRNGLO 0 -#define NSATGLO 0 -#define NSYSGLO 0 -#endif -#ifdef ENAGAL -#define MINPRNGAL 1 /* min satellite PRN number of Galileo */ -#define MAXPRNGAL 27 /* max satellite PRN number of Galileo */ -#define NSATGAL (MAXPRNGAL-MINPRNGAL+1) /* number of Galileo satellites */ -#define NSYSGAL 1 -#else -#define MINPRNGAL 0 -#define MAXPRNGAL 0 -#define NSATGAL 0 -#define NSYSGAL 0 -#endif -#ifdef ENAQZS -#define MINPRNQZS 193 /* min satellite PRN number of QZSS */ -#define MAXPRNQZS 195 /* max satellite PRN number of QZSS */ -#define MINPRNQZS_S 183 /* min satellite PRN number of QZSS SAIF */ -#define MAXPRNQZS_S 185 /* max satellite PRN number of QZSS SAIF */ -#define NSATQZS (MAXPRNQZS-MINPRNQZS+1) /* number of QZSS satellites */ -#define NSYSQZS 1 -#else -#define MINPRNQZS 0 -#define MAXPRNQZS 0 -#define NSATQZS 0 -#define NSYSQZS 0 -#endif -#ifdef ENACMP -#define MINPRNCMP 1 /* min satellite sat number of BeiDou */ -#define MAXPRNCMP 35 /* max satellite sat number of BeiDou */ -#define NSATCMP (MAXPRNCMP-MINPRNCMP+1) /* number of BeiDou satellites */ -#define NSYSCMP 1 -#else -#define MINPRNCMP 0 -#define MAXPRNCMP 0 -#define NSATCMP 0 -#define NSYSCMP 0 -#endif -#define NSYS (NSYSGPS+NSYSGLO+NSYSGAL+NSYSQZS+NSYSCMP) /* number of systems */ - -#define MINPRNSBS 120 /* min satellite PRN number of SBAS */ -#define MAXPRNSBS 142 /* max satellite PRN number of SBAS */ -#define NSATSBS (MAXPRNSBS-MINPRNSBS+1) /* number of SBAS satellites */ - -#define MAXSAT (NSATGPS+NSATGLO+NSATGAL+NSATQZS+NSATCMP+NSATSBS) - /* max satellite number (1 to MAXSAT) */ -#ifndef MAXOBS -#define MAXOBS 64 /* max number of obs in an epoch */ -#endif -#define MAXRCV 64 /* max receiver number (1 to MAXRCV) */ -#define MAXOBSTYPE 64 /* max number of obs type in RINEX */ -#define DTTOL 0.005 /* tolerance of time difference (s) */ -#if 0 -#define MAXDTOE 10800.0 /* max time difference to ephem Toe (s) for GPS */ -#else -#define MAXDTOE 7200.0 /* max time difference to ephem Toe (s) for GPS */ -#endif -#define MAXDTOE_GLO 1800.0 /* max time difference to GLONASS Toe (s) */ -#define MAXDTOE_SBS 360.0 /* max time difference to SBAS Toe (s) */ -#define MAXDTOE_S 86400.0 /* max time difference to ephem toe (s) for other */ -#define MAXGDOP 300.0 /* max GDOP */ - - //#define MAXSBSAGEF 30.0 /* max age of SBAS fast correction (s) */ - //#define MAXSBSAGEL 1800.0 /* max age of SBAS long term corr (s) */ - //#define MAXSBSURA 8 /* max URA of SBAS satellite */ -#define MAXBAND 10 /* max SBAS band of IGP */ -#define MAXNIGP 201 /* max number of IGP in SBAS band */ - //#define MAXNGEO 4 /* max number of GEO satellites */ - - -#define P2_11 4.882812500000000E-04 /* 2^-11 */ -#define P2_31 4.656612873077393E-10 /* 2^-31 */ -#define P2_39 1.818989403545856E-12 /* 2^-39 */ - - /* type definitions ----------------------------------------------------------*/ - - typedef struct { /* time struct */ - time_t time; /* time (s) expressed by standard time_t */ - double sec; /* fraction of second under 1 s */ - } gtime_t; - - typedef struct { /* SBAS message type */ - //int week,tow; /* receiption time */ - double sample_stamp; - int prn; /* SBAS satellite PRN number */ - unsigned char msg[29]; /* SBAS message (226bit) padded by 0 */ - } sbsmsg_t; - - typedef struct { /* SBAS messages type */ - int n,nmax; /* number of SBAS messages/allocated */ - sbsmsg_t *msgs; /* SBAS messages */ - } sbs_t; - - typedef struct { /* SBAS fast correction type */ - //gtime_t t0; /* time of applicability (TOF) */ - double t0; - bool valid; - double prc; /* pseudorange correction (PRC) (m) */ - double rrc; /* range-rate correction (RRC) (m/s) */ - double dt; /* range-rate correction delta-time (s) */ - int iodf; /* IODF (issue of date fast corr) */ - short udre; /* UDRE+1 */ - short ai; /* degradation factor indicator */ - } sbsfcorr_t; - - typedef struct { /* SBAS long term satellite error correction type */ - //gtime_t t0; /* correction time */ - double trx; /* time when message was received */ - int tapp; /* time of applicability (when vel=1 sent as t0) */ - int vel; /* use velocity if vel=1 */ - bool valid; - int iode; /* IODE (issue of date ephemeris) */ - double dpos[3]; /* delta position (m) (ecef) */ - double dvel[3]; /* delta velocity (m/s) (ecef) */ - double daf0,daf1; /* delta clock-offset/drift (s,s/s) */ - } sbslcorr_t; - - typedef struct { /* SBAS satellite correction type */ - int sat; /* satellite number */ - sbsfcorr_t fcorr; /* fast correction */ - sbslcorr_t lcorr; /* long term correction */ - } sbssatp_t; - - typedef struct { /* SBAS satellite corrections type */ - int iodp; /* IODP (issue of date mask) */ - int nsat; /* number of satellites */ - int tlat; /* system latency (s) */ - sbssatp_t sat[MAXSAT]; /* satellite correction */ - } sbssat_t; - - typedef struct { /* SBAS ionospheric correction type */ - //gtime_t t0; /* correction time */ - double t0; - bool valid; - short lat,lon; /* latitude/longitude (deg) */ - short give; /* GIVI+1 */ - float delay; /* vertical delay estimate (m) */ - } sbsigp_t; - - typedef struct { /* IGP band type */ - short x; /* longitude/latitude (deg) */ - const short *y; /* latitudes/longitudes (deg) */ - unsigned char bits; /* IGP mask start bit */ - unsigned char bite; /* IGP mask end bit */ - } sbsigpband_t; - - typedef struct { /* SBAS ionospheric corrections type */ - int iodi; /* IODI (issue of date ionos corr) */ - int nigp; /* number of igps */ - sbsigp_t igp[MAXNIGP]; /* ionospheric correction */ - } sbsion_t; - - /* - * indicators - */ - - typedef struct { /* SBAS ephemeris type */ - int sat = 0; /* satellite number */ - //gtime_t t0; /* reference epoch time (GPST) */ - int t0 = 0; - //gtime_t tof; /* time of message frame (GPST) */ - double tof = 0; - int sva = 0; /* SV accuracy (URA index) */ - int svh = 0; /* SV health (0:ok) */ - double pos[3] = {0, 0, 0}; /* satellite position (m) (ecef) */ - double vel[3] = {0, 0, 0}; /* satellite velocity (m/s) (ecef) */ - double acc[3] = {0, 0, 0}; /* satellite acceleration (m/s^2) (ecef) */ - double af0 = 0; - double af1 = 0; /* satellite clock-offset/drift (s,s/s) */ - } seph_t; - - typedef struct { /* navigation data type */ - //int n,nmax; /* number of broadcast ephemeris */ - //int ng,ngmax; /* number of glonass ephemeris */ - //int ns,nsmax; /* number of sbas ephemeris */ - //int ne,nemax; /* number of precise ephemeris */ - //int nc,ncmax; /* number of precise clock */ - //int na,namax; /* number of almanac data */ - //int nt,ntmax; /* number of tec grid data */ - //int nn,nnmax; /* number of stec grid data */ - //eph_t *eph; /* GPS/QZS/GAL ephemeris */ - //geph_t *geph; /* GLONASS ephemeris */ - seph_t seph[2*NSATSBS]; /* SBAS ephemeris */ - // peph_t *peph; /* precise ephemeris */ - // pclk_t *pclk; /* precise clock */ - // alm_t *alm; /* almanac data */ - // tec_t *tec; /* tec grid data */ - // stec_t *stec; /* stec grid data */ - // erp_t erp; /* earth rotation parameters */ - - //double utc_gps[4]; /* GPS delta-UTC parameters {A0,A1,T,W} */ - //double utc_glo[4]; /* GLONASS UTC GPS time parameters */ - //double utc_gal[4]; /* Galileo UTC GPS time parameters */ - //double utc_qzs[4]; /* QZS UTC GPS time parameters */ - //double utc_cmp[4]; /* BeiDou UTC parameters */ - //double utc_sbs[4]; /* SBAS UTC parameters */ - //double ion_gps[8]; /* GPS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ - //double ion_gal[4]; /* Galileo iono model parameters {ai0,ai1,ai2,0} */ - //double ion_qzs[8]; /* QZSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ - //double ion_cmp[8]; /* BeiDou iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ - //int leaps; /* leap seconds (s) */ - //double lam[MAXSAT][NFREQ]; /* carrier wave lengths (m) */ - //double cbias[MAXSAT][3]; /* code bias (0:p1-p2,1:p1-c1,2:p2-c2) (m) */ - //double wlbias[MAXSAT]; /* wide-lane bias (cycle) */ - //double glo_cpbias[4]; /* glonass code-phase bias {1C,1P,2C,2P} (m) */ - //char glo_fcn[MAXPRNGLO+1]; /* glonass frequency channel number + 8 */ - // pcv_t pcvs[MAXSAT]; /* satellite antenna pcv */ - sbssat_t sbssat; /* SBAS satellite corrections */ - sbsion_t sbsion[MAXBAND+1]; /* SBAS ionosphere corrections */ - // dgps_t dgps[MAXSAT]; /* DGPS corrections */ - // ssr_t ssr[MAXSAT]; /* SSR corrections */ - // lexeph_t lexeph[MAXSAT]; /* LEX ephemeris */ - // lexion_t lexion; /* LEX ionosphere correction */ - } nav_t; - - //// common - - static const double gpst0[]; /* gps time reference */ - - /* debug trace functions -----------------------------------------------------*/ - - FILE *fp_trace; /* file pointer of trace */ - int level_trace; /* level of trace */ - unsigned int tick_trace; /* tick time at traceopen (ms) */ - - void trace(int level, const char *format, ...); - - /* satellite system+prn/slot number to satellite number ------------------------ - * convert satellite system+prn/slot number to satellite number - * args : int sys I satellite system (SYS_GPS,SYS_GLO,...) - * int prn I satellite prn/slot number - * return : satellite number (0:error) - *-----------------------------------------------------------------------------*/ - int satno(int sys, int prn); - - /* extract unsigned/signed bits ------------------------------------------------ - * extract unsigned/signed bits from byte data - * args : unsigned char *buff I byte data - * int pos I bit position from start of data (bits) - * int len I bit length (bits) (len<=32) - * return : extracted unsigned/signed bits - *-----------------------------------------------------------------------------*/ - unsigned int getbitu(const unsigned char *buff, int pos, int len); - - int getbits(const unsigned char *buff, int pos, int len); - - /* convert calendar day/time to time ------------------------------------------- - * convert calendar day/time to gtime_t struct - * args : double *ep I day/time {year,month,day,hour,min,sec} - * return : gtime_t struct - * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) - *-----------------------------------------------------------------------------*/ - gtime_t epoch2time(const double *ep); - - /* time difference ------------------------------------------------------------- - * difference between gtime_t structs - * args : gtime_t t1,t2 I gtime_t structs - * return : time difference (t1-t2) (s) - *-----------------------------------------------------------------------------*/ - double timediff(gtime_t t1, gtime_t t2); - - /* gps time to time ------------------------------------------------------------ - * convert week and tow in gps time to gtime_t struct - * args : int week I week number in gps time - * double sec I time of week in gps time (s) - * return : gtime_t struct - *-----------------------------------------------------------------------------*/ - gtime_t gpst2time(int week, double sec); - - - ////// sbas.c - - /* sbas igp definition -------------------------------------------------------*/ - static const short - x1[], - x2[], - x3[], - x4[], - x5[], - x6[], - x7[], - x8[]; - - static const sbsigpband_t igpband1[9][8]; /* band 0-8 */ - static const sbsigpband_t igpband2[2][5]; /* band 9-10 */ - - /* decode type 1: prn masks --------------------------------------------------*/ - int decode_sbstype1(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 2-5,0: fast corrections ---------------------------------------*/ - int decode_sbstype2(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 6: integrity info ---------------------------------------------*/ - int decode_sbstype6(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 7: fast correction degradation factor -------------------------*/ - int decode_sbstype7(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 9: geo navigation message -------------------------------------*/ - int decode_sbstype9(const sbsmsg_t *msg, nav_t *nav); - /* decode type 18: ionospheric grid point masks ------------------------------*/ - int decode_sbstype18(const sbsmsg_t *msg, sbsion_t *sbsion); - /* decode half long term correction (vel code=0) -----------------------------*/ - int decode_longcorr0(const sbsmsg_t *msg, int p, sbssat_t *sbssat); - /* decode half long term correction (vel code=1) -----------------------------*/ - int decode_longcorr1(const sbsmsg_t *msg, int p, sbssat_t *sbssat); - /* decode half long term correction ------------------------------------------*/ - int decode_longcorrh(const sbsmsg_t *msg, int p, sbssat_t *sbssat); - /* decode type 24: mixed fast/long term correction ---------------------------*/ - int decode_sbstype24(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 25: long term satellite error correction ----------------------*/ - int decode_sbstype25(const sbsmsg_t *msg, sbssat_t *sbssat); - /* decode type 26: ionospheric deley corrections -----------------------------*/ - int decode_sbstype26(const sbsmsg_t *msg, sbsion_t *sbsion); - /* update sbas corrections ----------------------------------------------------- - * update sbas correction parameters in navigation data with a sbas message - * args : sbsmg_t *msg I sbas message - * nav_t *nav IO navigation data - * return : message type (-1: error or not supported type) - * notes : nav->seph must point to seph[NSATSBS*2] (array of seph_t) - * seph[prn-MINPRNSBS+1] : sat prn current epehmeris - * seph[prn-MINPRNSBS+1+MAXPRNSBS]: sat prn previous epehmeris - *-----------------------------------------------------------------------------*/ - int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav); - - void prn_mask_changed(); - bool is_rtklib_sat_correction_valid(int sat); - void igp_mask_changed(int band); - - // RTKLIB SBAS telemetry data representation - nav_t d_nav; -}; - -#endif diff --git a/src/core/system_parameters/sbas_time.h b/src/core/system_parameters/sbas_time.h deleted file mode 100644 index 3c86efa11..000000000 --- a/src/core/system_parameters/sbas_time.h +++ /dev/null @@ -1,193 +0,0 @@ -/*! - * \file sbas_time.h - * \brief Interface and implementation of classes to handle and relate sample stamp and GPS time based time scales - * \author Daniel Fehr 2013. daniel.co(at)bluewin.ch - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_SBAS_TIME_H_ -#define GNSS_SDR_SBAS_TIME_H_ - -#include -#include -#include - -#define EVENT 2 // logs important events which don't occur every update() call -#define FLOW 3 // logs the function calls of block processing functions - -class Sbas_Time_Relation -{ -public: - Sbas_Time_Relation() - { - i_gps_week = 0; - d_delta_sec = 0; - b_valid = false; - VLOG(FLOW) << "<> new invalid time relation: i_gps_week=" << i_gps_week << " d_delta_sec=" << d_delta_sec; - } - - Sbas_Time_Relation(double time_stamp_sec, int gps_week, double gps_sec) - { - i_gps_week = gps_week; - d_delta_sec = gps_sec - time_stamp_sec; - b_valid = true; - VLOG(FLOW) << "<> new time relation: i_gps_week=" << i_gps_week << " d_delta_sec=" << d_delta_sec; - } - - bool to_gps_time(double time_stamp_sec, int &gps_week, double &gps_sec) - { - int delta_weeks = int(trunc(time_stamp_sec + d_delta_sec))/604800; - gps_sec = time_stamp_sec + d_delta_sec - delta_weeks*604800; - gps_week = i_gps_week + delta_weeks; - VLOG(FLOW) << "<> to gps time: time_stamp_sec=" << time_stamp_sec << " gps_week=" << gps_week << " gps_sec=" << gps_sec; - return b_valid; - } - - bool to_sample_stamp(int gps_week, double gps_sec, double &time_stamp_sec) - { - time_stamp_sec = (gps_sec - d_delta_sec) + (gps_week - i_gps_week)*604800; - VLOG(FLOW) << "<> to gps time: gps_week=" << gps_week << " gps_sec=" << gps_sec << " time_stamp_sec=" << time_stamp_sec; - return b_valid; - } - - bool is_valid() - { - return b_valid; - } - -private: - int i_gps_week; - double d_delta_sec; - bool b_valid; -}; - - -/*! - * \brief Sbas_Time relates the relative sample stamp time scale with the absolute GPS time scale. - * There are three different states for a Sbas_Time object: - * - only relative time (sample stamp) is known - * - only absolute time (gps time) is known - * - absolute and relative time and their relation is known - */ -class Sbas_Time -{ -public: - enum Sbas_Time_State {RELATIVE, /*ABSOLUTE,*/ RELATED, UNDEFINED}; - - Sbas_Time() - { - e_state = UNDEFINED; - i_gps_week = 0; - d_gps_sec = 0; - d_time_stamp_sec = 0; - } - - Sbas_Time(double time_stamp_sec) - { - d_time_stamp_sec = time_stamp_sec; - i_gps_week = 0; - d_gps_sec = 0; - e_state = RELATIVE; - } - /* - Sbas_Time(int gps_week, double gps_sec) - { - i_gps_week = gps_week; - d_gps_sec = gps_sec; - d_time_stamp_sec = 0; - e_state = ABSOLUTE; - }*/ - Sbas_Time(double time_stamp_sec, Sbas_Time_Relation relation) - { - if(relation.is_valid()) - { // construct a RELATED object - d_time_stamp_sec = time_stamp_sec; - relation.to_gps_time(d_time_stamp_sec, i_gps_week, d_gps_sec); - e_state = RELATED; - } - else - { // construct a RELATIVE object - *this = Sbas_Time(time_stamp_sec); - VLOG(FLOW) << "<> create RELATIVE time (invalid relation): time_stamp_sec=" << time_stamp_sec; - } - } - /*Sbas_Time(int gps_week, double gps_sec, Sbas_Time_Relation relation) - { - i_gps_week = gps_week; - d_gps_sec = gps_sec; - relation.to_sample_stamp(gps_week, gps_sec, d_time_stamp_sec); - e_state = RELATED; - }*/ - - void relate(Sbas_Time_Relation sbas_time_realtion) - { - switch (e_state) - { - case RELATIVE: *this = Sbas_Time(d_time_stamp_sec, sbas_time_realtion); - break; - - //case ABSOLUTE: return Sbas_Time(i_gps_week, d_gps_sec, sbas_time_realtion); - break; - - case RELATED: LOG(INFO) << "Relating an already related Sbas_Time object is not possible"; - break; - - case UNDEFINED: std::cerr << "Sbas_Time object state undefined" << std::endl; - break; - - default: std::cerr << "Sbas_Time object state not known" << std::endl; - break; - } - return; - } - - double get_time_stamp() - { - return d_time_stamp_sec; - //return (e_state == RELATIVE || e_state == RELATED); - } - - bool get_gps_time(int &gps_week, double &gps_sec) - { - gps_week = i_gps_week; - gps_sec = d_gps_sec; - return (/*e_state == ABSOLUTE ||*/ e_state == RELATED); - } - - bool is_only_relativ() { return e_state == RELATIVE; } - //bool is_only_absolute() {return e_state == ABSOLUTE;} - bool is_related() { return e_state == RELATED; } - Sbas_Time_State get_state() { return e_state; } - -private: - Sbas_Time_State e_state; - double d_time_stamp_sec; - int i_gps_week; - double d_gps_sec; -}; - - -#endif /* GNSS_SDR_SBAS_TIME_H_ */ diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index f8ef0b376..85b250e91 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,109 +13,107 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # - set(GNSS_SDR_OPTIONAL_LIBS "") set(GNSS_SDR_OPTIONAL_HEADERS "") if(ENABLE_GPERFTOOLS) if(GPERFTOOLS_FOUND) - #set(GNSS_SDR_OPTIONAL_LIBS "${GNSS_SDR_OPTIONAL_LIBS};${GPERFTOOLS_LIBRARIES}") set(GNSS_SDR_OPTIONAL_LIBS "${GNSS_SDR_OPTIONAL_LIBS};${GPERFTOOLS_PROFILER};${GPERFTOOLS_TCMALLOC}") set(GNSS_SDR_OPTIONAL_HEADERS "${GNSS_SDR_OPTIONAL_HEADERS};${GPERFTOOLS_INCLUDE_DIR}") - endif(GPERFTOOLS_FOUND) -endif(ENABLE_GPERFTOOLS) + endif() +endif() -if(ENABLE_UHD) +if(ENABLE_UHD AND GNURADIO_UHD_LIBRARIES_gnuradio-uhd) set(GNSS_SDR_OPTIONAL_LIBS ${GNSS_SDR_OPTIONAL_LIBS} ${UHD_LIBRARIES} ${GNURADIO_UHD_LIBRARIES}) set(GNSS_SDR_OPTIONAL_HEADERS ${GNSS_SDR_OPTIONAL_HEADERS} ${UHD_INCLUDE_DIRS}) -endif(ENABLE_UHD) +endif() if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() if(ENABLE_CUDA) add_definitions(-DCUDA_GPU_ACCEL=1) set(GNSS_SDR_OPTIONAL_LIBS ${GNSS_SDR_OPTIONAL_LIBS} ${CUDA_LIBRARIES}) set(GNSS_SDR_OPTIONAL_HEADERS ${GNSS_SDR_OPTIONAL_HEADERS} ${CUDA_INCLUDE_DIRS}) -endif(ENABLE_CUDA) +endif() if(ORC_FOUND) set(GNSS_SDR_OPTIONAL_LIBS ${GNSS_SDR_OPTIONAL_LIBS} ${ORC_LIBRARIES}) set(GNSS_SDR_OPTIONAL_HEADERS ${GNSS_SDR_OPTIONAL_HEADERS} ${ORC_INCLUDE_DIRS}) -endif(ORC_FOUND) - +endif() include_directories( - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/core/libs - ${CMAKE_SOURCE_DIR}/src/core/libs/supl - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${ARMADILLO_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${GNSS_SDR_OPTIONAL_HEADERS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} - ${OPT_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/core/monitor + ${CMAKE_SOURCE_DIR}/src/core/libs + ${CMAKE_SOURCE_DIR}/src/core/libs/supl + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${PUGIXML_INCLUDE_DIR} + ${GNSS_SDR_OPTIONAL_HEADERS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${OPT_GNSSSDR_INCLUDE_DIRS} ) -add_definitions( -DGNSS_SDR_VERSION="${VERSION}" ) +add_definitions(-DGNSS_SDR_VERSION="${VERSION}") if(OS_IS_MACOSX) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(MAC_LIBRARIES "-stdlib=libc++ -std=c++11 -framework Accelerate -lc++") - endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") -endif(OS_IS_MACOSX) - + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(MAC_LIBRARIES "-framework Accelerate -lc++") + endif() +endif() add_executable(gnss-sdr ${CMAKE_CURRENT_SOURCE_DIR}/main.cc) -add_custom_command(TARGET gnss-sdr POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_SOURCE_DIR}/install/$ - ) - -target_link_libraries(gnss-sdr ${MAC_LIBRARIES} - ${Boost_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${ARMADILLO_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} - ${GNSS_SDR_OPTIONAL_LIBS} - gnss_sp_libs - gnss_rx - ) +add_custom_command(TARGET gnss-sdr + POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$ +) +target_link_libraries(gnss-sdr + ${MAC_LIBRARIES} + ${THREAD_LIBRARIES} + ${Boost_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} + ${GNSS_SDR_OPTIONAL_LIBS} + gnss_sp_libs + gnss_sdr_flags + gnss_rx +) install(TARGETS gnss-sdr - RUNTIME DESTINATION bin - COMPONENT "gnss-sdr" - ) + RUNTIME DESTINATION bin + COMPONENT "gnss-sdr") install(DIRECTORY ${CMAKE_SOURCE_DIR}/conf DESTINATION share/gnss-sdr - FILES_MATCHING PATTERN "*.conf" - ) + FILES_MATCHING PATTERN "*.conf") install(FILES ${CMAKE_SOURCE_DIR}/conf/gnss-sdr.conf DESTINATION share/gnss-sdr/conf - RENAME default.conf) + RENAME default.conf) -if(NOT VOLK_GNSSSDR_FOUND) +if(NOT VOLKGNSSSDR_FOUND) install(PROGRAMS ${CMAKE_BINARY_DIR}/volk_gnsssdr_module/build/apps/volk_gnsssdr_profile DESTINATION bin COMPONENT "volk_gnsssdr") install(PROGRAMS ${CMAKE_BINARY_DIR}/volk_gnsssdr_module/build/apps/volk_gnsssdr-config-info DESTINATION bin COMPONENT "volk_gnsssdr") -endif(NOT VOLK_GNSSSDR_FOUND) - +endif() find_program(GZIP gzip @@ -125,18 +123,24 @@ find_program(GZIP /opt/local/bin /sbin ) + if(NOT GZIP_NOTFOUND) execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/docs/manpage/gnss-sdr-manpage - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/gnss-sdr.1.gz") + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/gnss-sdr.1.gz") - install(FILES ${CMAKE_BINARY_DIR}/gnss-sdr.1.gz DESTINATION share/man/man1) - if(NOT VOLK_GNSSSDR_FOUND) - execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/volk_gnsssdr_profile.1.gz") - execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/volk_gnsssdr-config-info.1.gz") - - install(FILES ${CMAKE_BINARY_DIR}/volk_gnsssdr_profile.1.gz DESTINATION share/man/man1) - install(FILES ${CMAKE_BINARY_DIR}/volk_gnsssdr-config-info.1.gz DESTINATION share/man/man1) - endif(NOT VOLK_GNSSSDR_FOUND) -endif(NOT GZIP_NOTFOUND) + install(FILES ${CMAKE_BINARY_DIR}/gnss-sdr.1.gz DESTINATION share/man/man1) + + execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/docs/changelog + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/changelog.gz") + + install(FILES ${CMAKE_BINARY_DIR}/changelog.gz DESTINATION share/doc/gnss-sdr) + + if(NOT VOLKGNSSSDR_FOUND) + execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr_profile-manpage + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/volk_gnsssdr_profile.1.gz") + execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Packaging/volk_gnsssdr-config-info-manpage + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/volk_gnsssdr-config-info.1.gz") + install(FILES ${CMAKE_BINARY_DIR}/volk_gnsssdr_profile.1.gz DESTINATION share/man/man1) + install(FILES ${CMAKE_BINARY_DIR}/volk_gnsssdr-config-info.1.gz DESTINATION share/man/man1) + endif() +endif() diff --git a/src/main/main.cc b/src/main/main.cc index 59d92d01a..9b8354276 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -8,7 +8,7 @@ * * ------------------------------------------------------------------------- * -* Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) +* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,39 +26,45 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License -* along with GNSS-SDR. If not, see . +* along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ + #ifndef GNSS_SDR_VERSION -#define GNSS_SDR_VERSION "0.0.9" +#define GNSS_SDR_VERSION "0.0.10" #endif #ifndef GOOGLE_STRIP_LOG #define GOOGLE_STRIP_LOG 0 #endif -#include -#include -#include +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "control_thread.h" +#include "gnss_sdr_flags.h" +#include "gps_acq_assist.h" #include -#include -#include +#include // for exception +#include // for create_directories, exists +#include // for path, operator<< +#include // for error_code #include #include -#include "control_thread.h" -#include "concurrent_queue.h" -#include "concurrent_map.h" +#include +#include +#include +#include +#include #if CUDA_GPU_ACCEL - // For the CUDA runtime routines (prefixed with "cuda_") - #include +// For the CUDA runtime routines (prefixed with "cuda_") +#include #endif using google::LogMessage; -DECLARE_string(log_dir); /* * Concurrent queues that communicates the Telemetry Decoder @@ -72,13 +78,10 @@ concurrent_map global_gps_acq_assist_map; int main(int argc, char** argv) { const std::string intro_help( - std::string("\nGNSS-SDR is an Open Source GNSS Software Defined Receiver\n") - + - "Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors)\n" - + - "This program comes with ABSOLUTELY NO WARRANTY;\n" - + - "See COPYING file to see a copy of the General Public License\n \n"); + std::string("\nGNSS-SDR is an Open Source GNSS Software Defined Receiver\n") + + "Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)\n" + + "This program comes with ABSOLUTELY NO WARRANTY;\n" + + "See COPYING file to see a copy of the General Public License\n \n"); const std::string gnss_sdr_version(GNSS_SDR_VERSION); google::SetUsageMessage(intro_help); @@ -86,23 +89,23 @@ int main(int argc, char** argv) google::ParseCommandLineFlags(&argc, &argv, true); std::cout << "Initializing GNSS-SDR v" << gnss_sdr_version << " ... Please wait." << std::endl; - #if CUDA_GPU_ACCEL - // Reset the device - // cudaDeviceReset causes the driver to clean up all state. While - // not mandatory in normal operation, it is good practice. It is also - // needed to ensure correct operation when the application is being - // profiled. Calling cudaDeviceReset causes all profile data to be - // flushed before the application exits - cudaDeviceReset(); - std::cout << "Reset CUDA device done " << std::endl; - #endif +#if CUDA_GPU_ACCEL + // Reset the device + // cudaDeviceReset causes the driver to clean up all state. While + // not mandatory in normal operation, it is good practice. It is also + // needed to ensure correct operation when the application is being + // profiled. Calling cudaDeviceReset causes all profile data to be + // flushed before the application exits + cudaDeviceReset(); + std::cout << "Reset CUDA device done " << std::endl; +#endif - if(GOOGLE_STRIP_LOG == 0) + if (GOOGLE_STRIP_LOG == 0) { google::InitGoogleLogging(argv[0]); if (FLAGS_log_dir.empty()) { - std::cout << "Logging will be done at " + std::cout << "Logging will be written at " << boost::filesystem::temp_directory_path() << std::endl << "Use gnss-sdr --log_dir=/path/to/log to change that." @@ -110,7 +113,7 @@ int main(int argc, char** argv) } else { - const boost::filesystem::path p (FLAGS_log_dir); + const boost::filesystem::path p(FLAGS_log_dir); if (!boost::filesystem::exists(p)) { std::cout << "The path " @@ -118,49 +121,77 @@ int main(int argc, char** argv) << " does not exist, attempting to create it." << std::endl; boost::system::error_code ec; - boost::filesystem::create_directory(p, ec); - if(ec != 0) + if (!boost::filesystem::create_directory(p, ec)) { std::cout << "Could not create the " << FLAGS_log_dir << " folder. GNSS-SDR program ended." << std::endl; google::ShutDownCommandLineFlags(); - std::exit(0); + return 1; } } - std::cout << "Logging with be done at " << FLAGS_log_dir << std::endl; + std::cout << "Logging will be written at " << FLAGS_log_dir << std::endl; } } std::unique_ptr control_thread(new ControlThread()); // record startup time - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); + int return_code; try - { - control_thread->run(); - } - catch( boost::exception & e ) - { - LOG(FATAL) << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - LOG(FATAL) << "STD exception: " << ex.what(); - } - catch(...) - { - LOG(INFO) << "Unexpected catch"; - } + { + return_code = control_thread->run(); + } + catch (const boost::exception& e) + { + if (GOOGLE_STRIP_LOG == 0) + { + LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); + } + else + { + std::cerr << "Boost exception: " << boost::diagnostic_information(e) << std::endl; + } + google::ShutDownCommandLineFlags(); + return 1; + } + catch (const std::exception& ex) + { + if (GOOGLE_STRIP_LOG == 0) + { + LOG(WARNING) << "C++ Standard Library exception: " << ex.what(); + } + else + { + std::cerr << "C++ Standard Library exception: " << ex.what() << std::endl; + } + google::ShutDownCommandLineFlags(); + return 1; + } + catch (...) + { + if (GOOGLE_STRIP_LOG == 0) + { + LOG(WARNING) << "Unexpected catch. This should not happen."; + } + else + { + std::cerr << "Unexpected catch. This should not happen." << std::endl; + } + google::ShutDownCommandLineFlags(); + return 1; + } + // report the elapsed time - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Total GNSS-SDR run time " - << (static_cast(end - begin)) / 1000000.0 + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + + std::cout << "Total GNSS-SDR run time: " + << elapsed_seconds.count() << " [seconds]" << std::endl; google::ShutDownCommandLineFlags(); std::cout << "GNSS-SDR program ended." << std::endl; - return 0; + return return_code; } diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index e0b3db5ba..de39387b7 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,88 +13,105 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(unit-tests/signal-processing-blocks/libs) +add_subdirectory(system-tests/libs) ################################################################################ # Google Test - https://github.com/google/googletest ################################################################################ if(EXISTS $ENV{GTEST_DIR}) - set(GTEST_DIR_LOCAL $ENV{GTEST_DIR}) -endif(EXISTS $ENV{GTEST_DIR}) + set(GTEST_DIR_LOCAL $ENV{GTEST_DIR}) +endif() if(GTEST_DIR) set(GTEST_DIR_LOCAL ${GTEST_DIR}) -endif(GTEST_DIR) +endif() if(NOT GTEST_DIR_LOCAL) set(GTEST_DIR_LOCAL false) else() set(GTEST_DIR_LOCAL true) -endif(NOT GTEST_DIR_LOCAL) +endif() if(GTEST_INCLUDE_DIRS) set(GTEST_DIR_LOCAL true) -endif(GTEST_INCLUDE_DIRS) +endif() set(GTEST_COMPILER -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}) set(TOOLCHAIN_ARG "") +if(EXISTS $ENV{OECORE_TARGET_SYSROOT}) + set(GTEST_COMPILER "") + set(TOOLCHAIN_ARG "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/Toolchains/oe-sdk_cross.cmake") +endif() if(NOT ${GTEST_DIR_LOCAL}) - # if GTEST_DIR is not defined, we download and build it - set(gtest_RELEASE 1.8.0) + # if GTEST_DIR is not defined, we download and build it + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add( + gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/google/googletest + GIT_TAG release-${GNSSSDR_GTEST_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + CMAKE_ARGS ${GTEST_COMPILER} -DINSTALL_GTEST=OFF -DBUILD_GMOCK=OFF ${TOOLCHAIN_ARG} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add( + gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/google/googletest + GIT_TAG release-${GNSSSDR_GTEST_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${GNSSSDR_GTEST_LOCAL_VERSION} + CMAKE_ARGS ${GTEST_COMPILER} -DINSTALL_GTEST=OFF -DBUILD_GMOCK=OFF ${TOOLCHAIN_ARG} + UPDATE_COMMAND "" + PATCH_COMMAND "" + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${GNSSSDR_GTEST_LOCAL_VERSION}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${CMAKE_STATIC_LIBRARY_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${GNSSSDR_GTEST_LOCAL_VERSION}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX} + INSTALL_COMMAND "" + ) + endif() - if(EXISTS $ENV{OECORE_TARGET_SYSROOT}) - set(GTEST_COMPILER "") - set(TOOLCHAIN_ARG -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/Toolchains/oe-sdk_cross.cmake) - endif(EXISTS $ENV{OECORE_TARGET_SYSROOT}) - - ExternalProject_Add( - gtest-${gtest_RELEASE} - GIT_REPOSITORY https://github.com/google/googletest - GIT_TAG release-${gtest_RELEASE} - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gtest/gtest-${gtest_RELEASE} - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${gtest_RELEASE} - CMAKE_ARGS ${GTEST_COMPILER} -DBUILD_GTEST=ON -DBUILD_GMOCK=OFF ${TOOLCHAIN_ARG} - UPDATE_COMMAND "" - PATCH_COMMAND "" - INSTALL_COMMAND "" - ) - # Set up variables - # Set recently downloaded and build Googletest root folder - set(GTEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gtest/gtest-${gtest_RELEASE}/googletest") - # Source code - ExternalProject_Get_Property(gtest-${gtest_RELEASE} source_dir) - set(GTEST_INCLUDE_DIR ${source_dir}/googletest/include) - set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src) - # Library - ExternalProject_Get_Property(gtest-${gtest_RELEASE} binary_dir) - if(OS_IS_MACOSX) - if(CMAKE_GENERATOR STREQUAL Xcode) - set(binary_dir "${binary_dir}/Debug") - endif(CMAKE_GENERATOR STREQUAL Xcode) - endif(OS_IS_MACOSX) - set(GTEST_LIBRARY_PATH "${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a;${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main.a") - set(GTEST_LIBRARY gtest-${gtest_RELEASE}) - set(GTEST_LIBRARIES - ${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a - ${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main.a - ) - set(GTEST_LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${gtest_RELEASE}/googletest") -else(NOT ${GTEST_DIR_LOCAL}) - if(GTEST_INCLUDE_DIRS) - set(GTEST_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIRS} ${LIBGTEST_DEV_DIR}) - add_library(gtest ${LIBGTEST_DEV_DIR}/src/gtest-all.cc ${LIBGTEST_DEV_DIR}/src/gtest_main.cc) - set(GTEST_LIBRARIES gtest) - else(GTEST_INCLUDE_DIRS) - # If the variable GTEST_DIR is defined, we use the existing Googletest - set(GTEST_DIR $ENV{GTEST_DIR}) - set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src) - add_library(gtest ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc) - set(GTEST_LIBRARIES gtest) - endif(GTEST_INCLUDE_DIRS) -endif(NOT ${GTEST_DIR_LOCAL}) + # Set up variables + # Set recently downloaded and build Googletest root folder + set(GTEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION}/googletest") + # Source code + ExternalProject_Get_Property(gtest-${GNSSSDR_GTEST_LOCAL_VERSION} source_dir) + set(GTEST_INCLUDE_DIR ${source_dir}/googletest/include) + set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src) + # Library + ExternalProject_Get_Property(gtest-${GNSSSDR_GTEST_LOCAL_VERSION} binary_dir) + if(OS_IS_MACOSX) + if(CMAKE_GENERATOR STREQUAL Xcode) + set(FINAL_D "d") + set(ADD_DEBUG "Debug/") + endif() + endif() + set(GTEST_LIBRARY_PATH "${binary_dir}/googletest/${ADD_DEBUG}${CMAKE_FIND_LIBRARY_PREFIXES}gtest${FINAL_D}${CMAKE_STATIC_LIBRARY_SUFFIX};${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main${FINAL_D}${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_LIBRARY gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) + set(GTEST_LIBRARIES + ${binary_dir}/googletest/${ADD_DEBUG}${CMAKE_FIND_LIBRARY_PREFIXES}gtest${FINAL_D}${CMAKE_STATIC_LIBRARY_SUFFIX} + ${binary_dir}/googletest/${ADD_DEBUG}${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main${FINAL_D}${CMAKE_STATIC_LIBRARY_SUFFIX} + ${THREAD_LIBRARIES}) + set(GTEST_LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}/../../gtest-${GNSSSDR_GTEST_LOCAL_VERSION}/googletest") +else() + if(GTEST_INCLUDE_DIRS) + set(GTEST_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIRS} ${LIBGTEST_DEV_DIR}) + add_library(gtest ${LIBGTEST_DEV_DIR}/src/gtest-all.cc ${LIBGTEST_DEV_DIR}/src/gtest_main.cc) + set(GTEST_LIBRARIES gtest) + else() + # If the variable GTEST_DIR is defined, we use the existing Googletest + set(GTEST_DIR $ENV{GTEST_DIR}) + set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src) + add_library(gtest ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc) + set(GTEST_LIBRARIES gtest) + endif() + target_link_libraries(gtest ${THREAD_LIBRARIES}) +endif() @@ -107,160 +124,256 @@ set(GNSS_SDR_TEST_OPTIONAL_HEADERS "") if(ENABLE_CUDA) set(GNSS_SDR_TEST_OPTIONAL_HEADERS ${GNSS_SDR_TEST_OPTIONAL_HEADERS} ${CUDA_INCLUDE_DIRS}) set(GNSS_SDR_TEST_OPTIONAL_LIBS ${GNSS_SDR_TEST_OPTIONAL_LIBS} ${CUDA_LIBRARIES}) -endif(ENABLE_CUDA) +endif() if(ENABLE_GPERFTOOLS) if(GPERFTOOLS_FOUND) set(GNSS_SDR_TEST_OPTIONAL_LIBS "${GNSS_SDR_TEST_OPTIONAL_LIBS};${GPERFTOOLS_LIBRARIES}") set(GNSS_SDR_TEST_OPTIONAL_HEADERS "${GNSS_SDR_TEST_OPTIONAL_HEADERS};${GPERFTOOLS_INCLUDE_DIR}") - endif(GPERFTOOLS_FOUND) -endif(ENABLE_GPERFTOOLS) + endif() +endif() if(Boost_VERSION LESS 105000) - add_definitions(-DOLD_BOOST=1) -endif(Boost_VERSION LESS 105000) + add_definitions(-DOLD_BOOST=1) +endif() + +if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.13.4") + add_definitions(-DGR_GREATER_38=1) +endif() + +if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.15") + add_definitions(-DGR_GREATER_38=1) +endif() if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CLANG_FLAGS "-stdlib=libc++ -std=c++11 -lc++") -endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(OS_IS_MACOSX) + set(CLANG_FLAGS "-stdlib=libc++ -lc++") + endif() +endif() if(OPENCL_FOUND) add_definitions(-DOPENCL_BLOCKS_TEST=1) -endif(OPENCL_FOUND) +endif() + +if(ENABLE_CUDA) + add_definitions(-DCUDA_BLOCKS_TEST=1) +endif() + +if(ENABLE_FPGA) + add_definitions(-DFPGA_BLOCKS_TEST=1) +endif() + +find_package(Gnuplot) +if(GNUPLOT_FOUND) + add_definitions(-DGNUPLOT_EXECUTABLE="${GNUPLOT_EXECUTABLE}") +endif() + +if(ENABLE_UNIT_TESTING_MINIMAL) + add_definitions(-DUNIT_TESTING_MINIMAL=1) +endif() -if (ENABLE_CUDA) - add_definitions(-DCUDA_BLOCKS_TEST=1) -endif(ENABLE_CUDA) ################################################################################ # Optional generator ################################################################################ -if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA) - ExternalProject_Add( - gnss-sim - GIT_REPOSITORY https://bitbucket.org/jarribas/gnss-simulator - GIT_TAG master - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gnss-sim - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gnss-sim - CMAKE_ARGS ${GTEST_COMPILER} ${TOOLCHAIN_ARG} - UPDATE_COMMAND "" - PATCH_COMMAND "" - INSTALL_COMMAND "" - ) - set(SW_GENERATOR_BIN ${CMAKE_CURRENT_BINARY_DIR}/../../gnss-sim/gnss_sim) - add_definitions(-DSW_GENERATOR_BIN="${SW_GENERATOR_BIN}") - add_definitions(-DDEFAULT_RINEX_NAV="${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/brdc3540.14n") - add_definitions(-DDEFAULT_POSITION_FILE="${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/circle.csv") +option(ENABLE_GNSS_SIM_INSTALL "Enable the installation of gnss_sim on the fly" ON) +if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA OR ENABLE_FPGA) + if(ENABLE_FPGA) + set(CROSS_INSTALL_DIR "-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") + if(EXISTS $ENV{OECORE_TARGET_SYSROOT}) + set(CROSS_INSTALL_DIR "${CROSS_INSTALL_DIR} -DBOOST_ROOT=$ENV{OECORE_TARGET_SYSROOT}/usr") + endif() + else() + set(CROSS_INSTALL_DIR "") + endif() + find_package(GNSSSIMULATOR QUIET) + if(GNSSSIMULATOR_FOUND OR NOT ENABLE_GNSS_SIM_INSTALL) + add_definitions(-DSW_GENERATOR_BIN="${SW_GENERATOR_BIN}") + add_definitions(-DDEFAULT_RINEX_NAV="${CMAKE_INSTALL_PREFIX}/share/gnss-sim/brdc3540.14n") + add_definitions(-DDEFAULT_POSITION_FILE="${CMAKE_INSTALL_PREFIX}/share/gnss-sim/circle.csv") + else() + ExternalProject_Add( + gnss-sim + GIT_REPOSITORY https://bitbucket.org/jarribas/gnss-simulator + GIT_TAG ${GNSSSDR_GNSS_SIM_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gnss-sim + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gnss-sim + CMAKE_ARGS ${GTEST_COMPILER} ${TOOLCHAIN_ARG} ${CROSS_INSTALL_DIR} + UPDATE_COMMAND "" + PATCH_COMMAND "" + INSTALL_COMMAND "" + ) + if(ENABLE_INSTALL_TESTS) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/../../gnss-sim/gnss_sim DESTINATION bin) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/brdc3540.14n DESTINATION share/gnss-sim) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/circle.csv DESTINATION share/gnss-sim) + set(SW_GENERATOR_BIN ${CMAKE_INSTALL_PREFIX}/bin/gnss_sim) + add_definitions(-DSW_GENERATOR_BIN="${SW_GENERATOR_BIN}") + add_definitions(-DDEFAULT_RINEX_NAV="${CMAKE_INSTALL_PREFIX}/share/gnss-sim/brdc3540.14n") + add_definitions(-DDEFAULT_POSITION_FILE="${CMAKE_INSTALL_PREFIX}/share/gnss-sim/circle.csv") + else() + set(SW_GENERATOR_BIN ${CMAKE_CURRENT_BINARY_DIR}/../../gnss-sim/gnss_sim) + add_definitions(-DSW_GENERATOR_BIN="${SW_GENERATOR_BIN}") + add_definitions(-DDEFAULT_RINEX_NAV="${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/brdc3540.14n") + add_definitions(-DDEFAULT_POSITION_FILE="${CMAKE_CURRENT_BINARY_DIR}/../../../thirdparty/gnss-sim/circle.csv") + endif() + endif() - ################################################################################ - # Local installation of GPSTk http://www.gpstk.org/ - ################################################################################ - find_package(GPSTK) - if(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) - set(gpstk_RELEASE "2.9") - ExternalProject_Add( - gpstk-${gpstk_RELEASE} - GIT_REPOSITORY https://github.com/SGL-UT/GPSTk - GIT_TAG v${gpstk_RELEASE} - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${gpstk_RELEASE} - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gpstk-${gpstk_RELEASE} - CMAKE_ARGS ${GTEST_COMPILER} ${TOOLCHAIN_ARG} -DCMAKE_INSTALL_PREFIX=${CMAKE_SOURCE_DIR}/thirdparty/gpstk-${gpstk_RELEASE}/install -DBUILD_EXT=OFF -DBUILD_PYTHON=OFF - UPDATE_COMMAND "" - PATCH_COMMAND "" - ) - set(GPSTK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${gpstk_RELEASE}/install/include CACHE PATH "Local GPSTK headers") - add_library(gpstk UNKNOWN IMPORTED) - set_property(TARGET gpstk PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${gpstk_RELEASE}/install/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gpstk${CMAKE_SHARED_LIBRARY_SUFFIX}) - add_dependencies(gpstk gpstk-${gpstk_RELEASE}) - set(GPSTK_BINDIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${gpstk_RELEASE}/install/bin/ ) + ################################################################################ + # Local installation of GPSTk http://www.gpstk.org/ + ################################################################################ + find_package(GPSTK) + if(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) + message(STATUS "GPSTk v${GNSSSDR_GPSTK_LOCAL_VERSION} will be automatically downloaded and built when doing 'make'.") + if("${TOOLCHAIN_ARG}" STREQUAL "") + set(TOOLCHAIN_ARG "-DCMAKE_CXX_FLAGS=\"-Wno-deprecated\"") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated") + endif() + include(GNUInstallDirs) + string(REGEX REPLACE /[^/]*$ "" LIBDIR ${CMAKE_INSTALL_LIBDIR}) + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add( + gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/SGL-UT/GPSTk + GIT_TAG v${GNSSSDR_GPSTK_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + CMAKE_ARGS ${GTEST_COMPILER} ${TOOLCHAIN_ARG} -DCMAKE_INSTALL_PREFIX=${CMAKE_SOURCE_DIR}/thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install -DBUILD_EXT=OFF -DBUILD_PYTHON=OFF + UPDATE_COMMAND "" + PATCH_COMMAND "" + ) + else() + ExternalProject_Add( + gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/SGL-UT/GPSTk + GIT_TAG v${GNSSSDR_GPSTK_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION} + CMAKE_ARGS ${GTEST_COMPILER} ${TOOLCHAIN_ARG} -DCMAKE_INSTALL_PREFIX=${CMAKE_SOURCE_DIR}/thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install -DBUILD_EXT=OFF -DBUILD_PYTHON=OFF + BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/${LIBDIR}/${CMAKE_FIND_LIBRARY_PREFIXES}gpstk${CMAKE_SHARED_LIBRARY_SUFFIX} + UPDATE_COMMAND "" + PATCH_COMMAND "" + ) + endif() + set(GPSTK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/include CACHE PATH "Local GPSTK headers") + set(GPSTK_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/${LIBDIR}/${CMAKE_FIND_LIBRARY_PREFIXES}gpstk${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(GPSTK_BINDIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/bin/) add_definitions(-DGPSTK_BINDIR="${GPSTK_BINDIR}") - set(gpstk_libs gpstk) - else(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) - set(gpstk_libs ${GPSTK_LIBRARIES}) - set(GPSTK_INCLUDE_DIRS ${GPSTK_INCLUDE_DIR}) - set(GPSTK_BINDIR ${GPSTK_LIBRARY}/../bin/ ) - add_definitions(-DGPSTK_BINDIR="${GPSTK_BINDIR}") - endif(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) -endif(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA) + set(OWN_GPSTK True) + else() + set(GPSTK_INCLUDE_DIRS ${GPSTK_INCLUDE_DIR}) + set(GPSTK_BINDIR ${GPSTK_LIBRARY}/../bin/) + add_definitions(-DGPSTK_BINDIR="${GPSTK_BINDIR}") + endif() +endif() if(ENABLE_UNIT_TESTING_EXTRA) - add_definitions(-DEXTRA_TESTS) - if(NOT EXISTS ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat) + set(GNSS_SDR_TEST_OPTIONAL_LIBS ${GNSS_SDR_TEST_OPTIONAL_LIBS} ${GPSTK_LIBRARY}) + set(GNSS_SDR_TEST_OPTIONAL_HEADERS ${GNSS_SDR_TEST_OPTIONAL_HEADERS} ${GPSTK_INCLUDE_DIRS} ${GPSTK_INCLUDE_DIRS}/gpstk) +endif() + +if(ENABLE_UNIT_TESTING_EXTRA) + add_definitions(-DEXTRA_TESTS) + if(NOT EXISTS ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat) message(STATUS "Downloading some data files for testing...") file(DOWNLOAD https://sourceforge.net/projects/gnss-sdr/files/data/gps_l2c_m_prn7_5msps.dat ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat - SHOW_PROGRESS - EXPECTED_HASH MD5=a6fcbefe155137945d3c33c5ef7bd0f9 ) - endif(NOT EXISTS ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat) -endif(ENABLE_UNIT_TESTING_EXTRA) -file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) -file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/Galileo_E1_ID_1_Fs_4Msps_8ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) -file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) + SHOW_PROGRESS + EXPECTED_HASH MD5=a6fcbefe155137945d3c33c5ef7bd0f9) + endif() + if(NOT EXISTS ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples/Glonass_L1_CA_SIM_Fs_62Msps_4ms.dat) + message(STATUS "Downloading some data files for testing...") + file(DOWNLOAD https://sourceforge.net/projects/gnss-sdr/files/data/Glonass_L1_CA_SIM_Fs_62Msps_4ms.dat ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/signal_samples/Glonass_L1_CA_SIM_Fs_62Msps_4ms.dat + SHOW_PROGRESS + EXPECTED_HASH MD5=ffb72fc63c116be58d5e5ccb1daaed3a) + endif() + if(ENABLE_INSTALL_TESTS) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat DESTINATION share/gnss-sdr/signal_samples) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/signal_samples/Glonass_L1_CA_SIM_Fs_62Msps_4ms.dat DESTINATION share/gnss-sdr/signal_samples) + endif() +endif() -add_definitions(-DTEST_PATH="${CMAKE_SOURCE_DIR}/thirdparty/") +if(ENABLE_INSTALL_TESTS) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat DESTINATION share/gnss-sdr/signal_samples) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/Galileo_E1_ID_1_Fs_4Msps_8ms.dat DESTINATION share/gnss-sdr/signal_samples) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat DESTINATION share/gnss-sdr/signal_samples) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin DESTINATION share/gnss-sdr/signal_samples) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/data/rtklib_test/obs_test1.xml DESTINATION share/gnss-sdr/data/rtklib_test) + install(FILES ${CMAKE_SOURCE_DIR}/src/tests/data/rtklib_test/eph_GPS_L1CA_test1.xml DESTINATION share/gnss-sdr/data/rtklib_test) + add_definitions(-DTEST_PATH="${CMAKE_INSTALL_PREFIX}/share/gnss-sdr/") +else() + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/Galileo_E1_ID_1_Fs_4Msps_8ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/signal_samples) + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/data/rtklib_test/obs_test1.xml DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/data/rtklib_test) + file(COPY ${CMAKE_SOURCE_DIR}/src/tests/data/rtklib_test/eph_GPS_L1CA_test1.xml DESTINATION ${CMAKE_SOURCE_DIR}/thirdparty/data/rtklib_test) + add_definitions(-DTEST_PATH="${CMAKE_SOURCE_DIR}/thirdparty/") +endif() -include_directories( - ${GTEST_INCLUDE_DIRECTORIES} - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/core/libs - ${CMAKE_SOURCE_DIR}/src/core/libs/supl - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl - ${CMAKE_SOURCE_DIR}/src/algorithms/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters - ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks - ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs - ${CMAKE_SOURCE_DIR}/src/tests/unit-tests/signal-processing-blocks/libs - ${CMAKE_SOURCE_DIR}/src/tests/common-files - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${ARMADILLO_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} - ${GNSS_SDR_TEST_OPTIONAL_HEADERS} - ${GNSS_SDR_TEST_OPTIONAL_HEADERS} +set(LIST_INCLUDE_DIRS + ${GTEST_INCLUDE_DIRECTORIES} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/core/libs + ${CMAKE_SOURCE_DIR}/src/core/libs/supl + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl + ${CMAKE_SOURCE_DIR}/src/core/monitor + ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib + ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/resampler/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/channel/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/telemetry_decoder/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/observables/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/observables/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/signal_generator/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/input_filter/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/libs + ${CMAKE_SOURCE_DIR}/src/tests/unit-tests/signal-processing-blocks/libs + ${CMAKE_SOURCE_DIR}/src/tests/system-tests/libs + ${CMAKE_SOURCE_DIR}/src/tests/common-files + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} + ${PUGIXML_INCLUDE_DIR} + ${GNSS_SDR_TEST_OPTIONAL_HEADERS} ) - +include_directories(${LIST_INCLUDE_DIRS}) ################################################################################ # Unit testing ################################################################################ if(ENABLE_UNIT_TESTING) - if( ${ARMADILLO_VERSION_STRING} STRGREATER "5.300") # make sure interp1 is present - add_definitions(-DMODERN_ARMADILLO) - endif( ${ARMADILLO_VERSION_STRING} STRGREATER "5.300") add_executable(run_tests ${CMAKE_CURRENT_SOURCE_DIR}/test_main.cc) - add_custom_command(TARGET run_tests POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_SOURCE_DIR}/install/$) - target_link_libraries(run_tests ${CLANG_FLAGS} ${Boost_LIBRARIES} ${GFlags_LIBS} @@ -280,14 +393,136 @@ if(ENABLE_UNIT_TESTING) signal_generator_adapters pvt_gr_blocks signal_processing_testing_lib + system_testing_lib ${VOLK_GNSSSDR_LIBRARIES} + ${MATIO_LIBRARIES} ${GNSS_SDR_TEST_OPTIONAL_LIBS} ) if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(run_tests gtest-${gtest_RELEASE}) - endif(NOT ${GTEST_DIR_LOCAL}) -endif(ENABLE_UNIT_TESTING) + add_dependencies(run_tests gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) + endif() + if(ENABLE_INSTALL_TESTS) + if(EXISTS ${CMAKE_SOURCE_DIR}/install/run_tests) + file(REMOVE ${CMAKE_SOURCE_DIR}/install/run_tests) + endif() + install(TARGETS run_tests RUNTIME DESTINATION bin COMPONENT "run_tests") + else() + add_custom_command(TARGET run_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$) + endif() +endif() + +if(ENABLE_FPGA) + add_executable(gps_l1_ca_dll_pll_tracking_test_fpga + ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc + ) + target_link_libraries(gps_l1_ca_dll_pll_tracking_test_fpga + ${Boost_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${VOLK_LIBRARIES} + ${MATIO_LIBRARIES} + channel_fsm + gnss_sp_libs + gnss_rx + gnss_system_parameters + signal_processing_testing_lib + ) + install(TARGETS gps_l1_ca_dll_pll_tracking_test_fpga + RUNTIME DESTINATION bin + COMPONENT "fpga-test" + ) +endif() + + + +################################################################################ +# System testing +################################################################################ +function(add_system_test executable) + ## Please call this function with variables OPT_INCLUDES_ and OPT_LIBS_ + ## already defined. + set(SYSTEM_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/system-tests/${executable}.cc) + # Ensure that executable is rebuilt if it was previously built and then removed + if(NOT EXISTS ${CMAKE_SOURCE_DIR}/install/${executable}) + execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${SYSTEM_TEST_SOURCES}) + endif() + add_executable(${executable} ${SYSTEM_TEST_SOURCES}) + + if(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(${executable} gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) + else() + add_dependencies(${executable} gtest) + endif() + + include_directories(${OPT_INCLUDES_}) + target_link_libraries(${executable} ${OPT_LIBS_}) + + if(ENABLE_INSTALL_TESTS) + if(EXISTS ${CMAKE_SOURCE_DIR}/install/${executable}) + file(REMOVE ${CMAKE_SOURCE_DIR}/install/${executable}) + endif() + install(TARGETS ${executable} RUNTIME DESTINATION bin COMPONENT "${executable}_test") + else() + add_custom_command(TARGET ${executable} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$) + endif() +endfunction() + + +if(ENABLE_SYSTEM_TESTING) + set(HOST_SYSTEM "Unknown") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(HOST_SYSTEM "GNU/Linux ${LINUX_DISTRIBUTION} ${LINUX_VER} ${ARCH_}") + string(REPLACE "\n" "" HOST_SYSTEM "${HOST_SYSTEM}") + string(REPLACE "\"" "" HOST_SYSTEM "${HOST_SYSTEM}") + endif() + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(HOST_SYSTEM "MacOS") + endif() + add_definitions(-DHOST_SYSTEM="${HOST_SYSTEM}") + + #### TTFF + set(OPT_LIBS_ ${Boost_LIBRARIES} ${THREAD_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} ${GTEST_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} gnss_sp_libs + gnss_rx gnss_system_parameters) + + add_system_test(ttff) + + if(ENABLE_SYSTEM_TESTING_EXTRA) + #### POSITION_TEST + set(OPT_LIBS_ ${Boost_LIBRARIES} ${THREAD_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} ${VOLK_GNSSSDR_LIBRARIES} + gnss_sp_libs gnss_rx gnss_system_parameters + system_testing_lib) + add_system_test(position_test) + else() + # Avoid working with old executables if they were switched ON and then OFF + if(EXISTS ${CMAKE_SOURCE_DIR}/install/position_test) + file(REMOVE ${CMAKE_SOURCE_DIR}/install/position_test) + endif() + endif() +else() + # Avoid working with old executables if they were switched ON and then OFF + if(EXISTS ${CMAKE_SOURCE_DIR}/install/ttff) + file(REMOVE ${CMAKE_SOURCE_DIR}/install/ttff) + endif() + if(EXISTS ${CMAKE_SOURCE_DIR}/install/position_test) + file(REMOVE ${CMAKE_SOURCE_DIR}/install/position_test) + endif() +endif() ######################################################### @@ -296,234 +531,204 @@ endif(ENABLE_UNIT_TESTING) set(CMAKE_CTEST_COMMAND ctest -V) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) -add_executable(control_thread_test - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/control_message_factory_test.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/control_thread_test.cc -) -if(NOT ${ENABLE_PACKAGING}) - set_property(TARGET control_thread_test PROPERTY EXCLUDE_FROM_ALL TRUE) -endif(NOT ${ENABLE_PACKAGING}) - -target_link_libraries(control_thread_test ${Boost_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - gnss_sp_libs - gnss_system_parameters - gnss_rx - ${VOLK_GNSSSDR_LIBRARIES} - ) - -add_test(control_thread_test control_thread_test) -if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(control_thread_test gtest-${gtest_RELEASE}) -else(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(control_thread_test gtest) -endif(NOT ${GTEST_DIR_LOCAL}) -set_property(TEST control_thread_test PROPERTY TIMEOUT 30) - -add_executable(flowgraph_test - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/gnss_flowgraph_test.cc -) -if(NOT ${ENABLE_PACKAGING}) - set_property(TARGET flowgraph_test PROPERTY EXCLUDE_FROM_ALL TRUE) -endif(NOT ${ENABLE_PACKAGING}) +add_executable(flowgraph_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/gnss_flowgraph_test.cc) target_link_libraries(flowgraph_test ${Boost_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - gnss_sp_libs - gnss_rx - gnss_system_parameters - ${VOLK_GNSSSDR_LIBRARIES} - ) + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GTEST_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + ${VOLK_GNSSSDR_LIBRARIES} +) add_test(flowgraph_test flowgraph_test) if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(flowgraph_test gtest-${gtest_RELEASE}) -else(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(flowgraph_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) +else() add_dependencies(flowgraph_test gtest) -endif(NOT ${GTEST_DIR_LOCAL}) +endif() set_property(TEST flowgraph_test PROPERTY TIMEOUT 30) -add_executable(gnss_block_test - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/gnss_block_factory_test.cc +######################################################### + +add_executable(gnss_block_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/adapter/adapter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/gnss_block_factory_test.cc ) -if(NOT ${ENABLE_PACKAGING}) - set_property(TARGET gnss_block_test PROPERTY EXCLUDE_FROM_ALL TRUE) -endif(NOT ${ENABLE_PACKAGING}) - target_link_libraries(gnss_block_test ${Boost_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GNURADIO_ANALOG_LIBRARIES} - gnss_sp_libs - gnss_rx - gnss_system_parameters - # signal_generator_blocks - ${VOLK_GNSSSDR_LIBRARIES} - ) - + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + ${VOLK_GNSSSDR_LIBRARIES} +) add_test(gnss_block_test gnss_block_test) if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(gnss_block_test gtest-${gtest_RELEASE}) -else(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(gnss_block_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) +else() add_dependencies(gnss_block_test gtest) -endif(NOT ${GTEST_DIR_LOCAL}) +endif() +set_property(TEST gnss_block_test PROPERTY TIMEOUT 60) -add_executable(gnuradio_block_test - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc +######################################################### + +add_executable(gnuradio_block_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc ) -if(NOT ${ENABLE_PACKAGING}) - set_property(TARGET gnuradio_block_test PROPERTY EXCLUDE_FROM_ALL TRUE) -endif(NOT ${ENABLE_PACKAGING}) - target_link_libraries(gnuradio_block_test ${Boost_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GNURADIO_ANALOG_LIBRARIES} - gnss_sp_libs - gnss_rx - gnss_system_parameters - # signal_generator_blocks - ${VOLK_GNSSSDR_LIBRARIES} - ) - + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + ${VOLK_GNSSSDR_LIBRARIES} +) add_test(gnuradio_block_test gnuradio_block_test) if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(gnuradio_block_test gtest-${gtest_RELEASE}) -else(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(gnuradio_block_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) +else() add_dependencies(gnuradio_block_test gtest) -endif(NOT ${GTEST_DIR_LOCAL}) +endif() +set_property(TEST gnuradio_block_test PROPERTY TIMEOUT 30) -# add_executable(acq_test ${EXCLUDE} -# ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc -# ${CMAKE_CURRENT_SOURCE_DIR}/gnss_block/gps_l1_ca_pcps_acquisition_test.cc -# ${CMAKE_CURRENT_SOURCE_DIR}/gnss_block/galileo_e1_pcps_ambiguous_acquisition_test.cc -# ) -# target_link_libraries(acq_test ${Boost_LIBRARIES} -# ${GFlags_LIBS} -# ${GLOG_LIBRARIES} -# ${GTEST_LIBRARIES} -# ${GNURADIO_RUNTIME_LIBRARIES} -# ${GNURADIO_BLOCKS_LIBRARIES} -# ${GNURADIO_FILTER_LIBRARIES} -# ${GNURADIO_ANALOG_LIBRARIES} -# gnss_sp_libs -# gnss_rx -# gnss_system_parameters -# signal_generator_blocks -# ${VOLK_GNSSSDR_LIBRARIES} -# ) -# add_test(acq_test acq_test) +######################################################### -add_executable(trk_test - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc - ) +add_executable(matio_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/arithmetic/matio_test.cc +) +target_link_libraries(matio_test ${Boost_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${MATIO_LIBRARIES} + gnss_system_parameters +) +add_test(matio_test matio_test) +if(NOT ${GTEST_DIR_LOCAL}) + if(MATIO_FOUND) + add_dependencies(matio_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) + else() + add_dependencies(matio_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION} matio-${GNSSSDR_MATIO_LOCAL_VERSION}) + endif() +else() + if(MATIO_FOUND) + add_dependencies(matio_test gtest) + else() + add_dependencies(matio_test gtest matio-${GNSSSDR_MATIO_LOCAL_VERSION}) + endif() +endif() +set_property(TEST matio_test PROPERTY TIMEOUT 30) -if(NOT ${ENABLE_PACKAGING}) - set_property(TARGET trk_test PROPERTY EXCLUDE_FROM_ALL TRUE) -endif(NOT ${ENABLE_PACKAGING}) +######################################################### + +add_executable(acq_test + ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc) +target_link_libraries(acq_test ${Boost_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + signal_generator_blocks + signal_processing_testing_lib + ${VOLK_GNSSSDR_LIBRARIES}) +add_test(acq_test acq_test) +if(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(acq_test acq_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) +else() + add_dependencies(acq_test acq_test gtest) +endif() +set_property(TEST acq_test PROPERTY TIMEOUT 30) + +######################################################### + +add_executable(trk_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_real_codes_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/tracking/bayesian_estimation_test.cc +) target_link_libraries(trk_test ${Boost_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GNURADIO_ANALOG_LIBRARIES} - gnss_sp_libs - gnss_rx - gnss_system_parameters - signal_generator_blocks - ${VOLK_GNSSSDR_LIBRARIES} - ) + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + signal_generator_blocks + ${VOLK_GNSSSDR_LIBRARIES} +) add_test(trk_test trk_test) if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(trk_test gtest-${gtest_RELEASE}) -else(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(trk_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) +else() add_dependencies(trk_test gtest) -endif(NOT ${GTEST_DIR_LOCAL}) - -add_dependencies(check control_thread_test flowgraph_test gnss_block_test - gnuradio_block_test trk_test) +endif() +set_property(TEST trk_test PROPERTY TIMEOUT 30) +######################################################### -################################################################################ -# System testing -################################################################################ -if(ENABLE_SYSTEM_TESTING) - set(HOST_SYSTEM "Unknown") - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(HOST_SYSTEM "GNU/Linux ${LINUX_DISTRIBUTION} ${LINUX_VER} ${ARCH_}") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(HOST_SYSTEM "MacOS") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DHOST_SYSTEM="${HOST_SYSTEM}") - add_executable(ttff - ${CMAKE_CURRENT_SOURCE_DIR}/system-tests/ttff_gps_l1.cc ) - if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(ttff gtest-${gtest_RELEASE}) - else(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(ttff gtest) - endif(NOT ${GTEST_DIR_LOCAL}) - target_link_libraries(ttff - ${Boost_LIBRARIES} +if(NOT ENABLE_PACKAGING) + add_executable(control_thread_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/control_message_factory_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/control_thread_test.cc + ) + + target_link_libraries(control_thread_test ${Boost_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${GTEST_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GNURADIO_ANALOG_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} - gnss_sp_libs gnss_rx - gnss_system_parameters - ) - add_custom_command(TARGET ttff POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_SOURCE_DIR}/install/$ ) - if(ENABLE_SYSTEM_TESTING_EXTRA) - add_executable(obs_gps_l1_system_test ${CMAKE_CURRENT_SOURCE_DIR}/system-tests/obs_gps_l1_system_test.cc) - if(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(obs_gps_l1_system_test gtest-${gtest_RELEASE} ) - else(NOT ${GTEST_DIR_LOCAL}) - add_dependencies(obs_gps_l1_system_test gtest) - endif(NOT ${GTEST_DIR_LOCAL}) - include_directories(${GPSTK_INCLUDE_DIRS}) - target_link_libraries(obs_gps_l1_system_test ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${GTEST_LIBRARIES} - gnss_sp_libs - gnss_rx - ${gpstk_libs}) - add_custom_command(TARGET obs_gps_l1_system_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_SOURCE_DIR}/install/$ - ) - endif(ENABLE_SYSTEM_TESTING_EXTRA) -endif(ENABLE_SYSTEM_TESTING) + add_test(control_thread_test control_thread_test) + if(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(control_thread_test gtest-${GNSSSDR_GTEST_LOCAL_VERSION}) + else() + add_dependencies(control_thread_test gtest) + endif() + set_property(TEST control_thread_test PROPERTY TIMEOUT 30) +endif() + +######################################################### + +if(ENABLE_PACKAGING) + add_dependencies(check flowgraph_test gnss_block_test + gnuradio_block_test acq_test trk_test matio_test) +else() + add_dependencies(check control_thread_test flowgraph_test gnss_block_test + gnuradio_block_test acq_test trk_test matio_test) +endif() diff --git a/src/tests/common-files/gnuplot_i.h b/src/tests/common-files/gnuplot_i.h new file mode 100644 index 000000000..7a971f02e --- /dev/null +++ b/src/tests/common-files/gnuplot_i.h @@ -0,0 +1,2165 @@ +/*! + * \file gnuplot_i.h + * \brief A C++ interface to gnuplot. + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * Original source code found at https://code.google.com/archive/p/gnuplot-cpp/ + * by Jeremy Conlin jeremit0(at)gmail.com + * + * Version history: + * 0. C interface + * by N. Devillard (27/01/03) + * 1. C++ interface: direct translation from the C interface + * by Rajarshi Guha (07/03/03) + * 2. corrections for Win32 compatibility + * by V. Chyzhdzenka (20/05/03) + * 3. some member functions added, corrections for Win32 and Linux + * compatibility + * by M. Burgis (10/03/08) + * 4. Some fixes and improvements for Linux and macOS + * by C. Fernandez (22/10/17) + * ------------------------------------------------------------------------- + * + * Copyright (C) 2013-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GNUPLOT_I_H_ +#define GNSS_SDR_GNUPLOT_I_H_ + +#include +#include +#include +#include // for getenv() +#include // for strncpy +#include +#include +#include // for std::list +#include // for std::ostringstream +#include +#include +#include +#include + +DEFINE_bool(show_plots, true, "Show plots on screen. Disable for non-interactive testing."); + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +//defined for 32 and 64-bit environments +#include // for _access(), _mktemp() +#define GP_MAX_TMP_FILES 27 // 27 temporary files it's Microsoft restriction +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) +//all UNIX-like OSs (Linux, *BSD, MacOSX, Solaris, ...) +#include // for access(), mkstemp() +#define GP_MAX_TMP_FILES 1024 +#else +#error unsupported or unknown operating system +#endif + +//declare classes in global namespace + + +class GnuplotException : public std::runtime_error +{ +public: + GnuplotException(const std::string &msg) : std::runtime_error(msg) {} +}; + + +class Gnuplot +{ +private: + //---------------------------------------------------------------------------------- + // member data + ///\brief pointer to the stream that can be used to write to the pipe + FILE *gnucmd; + ///\brief validation of gnuplot session + bool valid; + ///\brief true = 2d, false = 3d + bool two_dim; + ///\brief number of plots in session + int nplots; + ///\brief functions and data are displayed in a defined styles + std::string pstyle; + ///\brief interpolate and approximate data in defined styles (e.g. spline) + std::string smooth; + ///\brief list of created tmpfiles + std::vector tmpfile_list; + + //---------------------------------------------------------------------------------- + // static data + ///\brief number of all tmpfiles (number of tmpfiles restricted) + static int tmpfile_num; + ///\brief name of executed GNUPlot file + static std::string m_sGNUPlotFileName; + ///\brief gnuplot path + static std::string m_sGNUPlotPath; + ///\brief standard terminal, used by showonscreen + static std::string terminal_std; + + //---------------------------------------------------------------------------------- + // member functions (auxiliary functions) + // --------------------------------------------------- + ///\brief get_program_path(); and popen(); + /// + /// \param --> void + /// + /// \return <-- void + // --------------------------------------------------- + void init(); + + // --------------------------------------------------- + ///\brief creates tmpfile and returns its name + /// + /// \param tmp --> points to the tempfile + /// + /// \return <-- the name of the tempfile + // --------------------------------------------------- + std::string create_tmpfile(std::ofstream &tmp); + + //---------------------------------------------------------------------------------- + ///\brief gnuplot path found? + /// + /// \param --- + /// + /// \return <-- found the gnuplot path (yes == true, no == false) + // --------------------------------------------------------------------------------- + static bool get_program_path(); + + // --------------------------------------------------------------------------------- + ///\brief checks if file is available + /// + /// \param filename --> the filename + /// \param mode --> the mode [optional,default value = 0] + /// + /// \return file exists (yes == true, no == false) + // --------------------------------------------------------------------------------- + bool file_available(const std::string &filename); + + // --------------------------------------------------------------------------------- + ///\brief checks if file exists + /// + /// \param filename --> the filename + /// \param mode --> the mode [optional,default value = 0] + /// + /// \return file exists (yes == true, no == false) + // --------------------------------------------------------------------------------- + static bool file_exists(const std::string &filename, int mode = 0); + +public: + // ---------------------------------------------------------------------------- + /// \brief optional function: set Gnuplot path manual + /// attention: for windows: path with slash '/' not backslash '\' + /// + /// \param path --> the gnuplot path + /// + /// \return true on success, false otherwise + // ---------------------------------------------------------------------------- + static bool set_GNUPlotPath(const std::string &path); + + // ---------------------------------------------------------------------------- + /// optional: set standard terminal, used by showonscreen + /// defaults: Windows - win, Linux - x11, Mac - aqua + /// + /// \param type --> the terminal type + /// + /// \return --- + // ---------------------------------------------------------------------------- + static void set_terminal_std(const std::string &type); + + //----------------------------------------------------------------------------- + // constructors + // ---------------------------------------------------------------------------- + + ///\brief set a style during construction + Gnuplot(const std::string &style = "points"); + + /// plot a single std::vector at one go + Gnuplot(const std::vector &x, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y"); + + /// plot pairs std::vector at one go + Gnuplot(const std::vector &x, + const std::vector &y, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y"); + + /// plot triples std::vector at one go + Gnuplot(const std::vector &x, + const std::vector &y, + const std::vector &z, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y", + const std::string &labelz = "z"); + + + /// destructor: needed to delete temporary files + ~Gnuplot(); + + //---------------------------------------------------------------------------------- + + /// send a command to gnuplot + Gnuplot &cmd(const std::string &cmdstr); + + // --------------------------------------------------------------------------------- + ///\brief Sends a command to an active gnuplot session, identical to cmd() + /// send a command to gnuplot using the << operator + /// + /// \param cmdstr --> the command string + /// + /// \return <-- a reference to the gnuplot object + // --------------------------------------------------------------------------------- + inline Gnuplot &operator<<(const std::string &cmdstr) + { + cmd(cmdstr); + return (*this); + } + + //---------------------------------------------------------------------------------- + // show on screen or write to file + + /// sets terminal type to terminal_std + Gnuplot &showonscreen(); // window output is set by default (win/x11/aqua) + + /// sets terminal type to unknown (disable the screen output) + Gnuplot &disablescreen(); + + /// saves a gnuplot session to a postscript file, filename without extension + Gnuplot &savetops(const std::string &filename = "gnuplot_output"); + + /// saves a gnuplot session to a pdf file, filename without extension + Gnuplot &savetopdf(const std::string &filename = "gnuplot_output", unsigned int font_size = 12); + + //---------------------------------------------------------------------------------- + // set and unset + + /// set line style (some of these styles require additional information): + /// lines, points, linespoints, impulses, dots, steps, fsteps, histeps, + /// boxes, histograms, filledcurves + Gnuplot &set_style(const std::string &stylestr = "points"); + + /// interpolation and approximation of data, arguments: + /// csplines, bezier, acsplines (for data values > 0), sbezier, unique, frequency + /// (works only with plot_x, plot_xy, plotfile_x, plotfile_xy + /// (if smooth is set, set_style has no effect on data plotting) + Gnuplot &set_smooth(const std::string &stylestr = "csplines"); + + // ---------------------------------------------------------------------- + /// \brief unset smooth + /// attention: smooth is not set by default + /// + /// \param --- + /// + /// \return <-- a reference to a gnuplot object + // ---------------------------------------------------------------------- + inline Gnuplot &unset_smooth() + { + smooth = ""; + return *this; + }; + + /// scales the size of the points used in plots + Gnuplot &set_pointsize(const double pointsize = 1.0); + + /// turns grid on/off + inline Gnuplot &set_grid() + { + cmd("set grid"); + return *this; + }; + /// grid is not set by default + inline Gnuplot &unset_grid() + { + cmd("unset grid"); + return *this; + }; + + // ----------------------------------------------- + /// set the mulitplot mode + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &set_multiplot(int rows, int cols) + { + cmd("set multiplot layout " + std::to_string(rows) + "," + std::to_string(cols)); //+ " rowfirst"); + return *this; + }; + + // ----------------------------------------------- + /// unsets the mulitplot mode + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &unset_multiplot() + { + cmd("unset multiplot"); + return *this; + }; + + /// set sampling rate of functions, or for interpolating data + Gnuplot &set_samples(const int samples = 100); + /// set isoline density (grid) for plotting functions as surfaces (for 3d plots) + Gnuplot &set_isosamples(const int isolines = 10); + + // -------------------------------------------------------------------------- + /// enables/disables hidden line removal for surface plotting (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // -------------------------------------------------------------------------- + Gnuplot &set_hidden3d() + { + cmd("set hidden3d"); + return *this; + }; + + // --------------------------------------------------------------------------- + /// hidden3d is not set by default + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // --------------------------------------------------------------------------- + inline Gnuplot &unset_hidden3d() + { + cmd("unset hidden3d"); + return *this; + }; + + /// enables/disables contour drawing for surfaces (for 3d plot) + /// base, surface, both + Gnuplot &set_contour(const std::string &position = "base"); + // -------------------------------------------------------------------------- + /// contour is not set by default, it disables contour drawing for surfaces + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot &unset_contour() + { + cmd("unset contour"); + return *this; + }; + + // ------------------------------------------------------------ + /// enables/disables the display of surfaces (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot &set_surface() + { + cmd("set surface"); + return *this; + }; + + // ---------------------------------------------------------- + /// surface is set by default, + /// it disables the display of surfaces (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot &unset_surface() + { + cmd("unset surface"); + return *this; + } + + + /// switches legend on/off + /// position: inside/outside, left/center/right, top/center/bottom, nobox/box + Gnuplot &set_legend(const std::string &position = "default"); + + // ------------------------------------------------------------------ + /// \brief Switches legend off + /// attention:legend is set by default + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot &unset_legend() + { + cmd("unset key"); + return *this; + } + + // ----------------------------------------------------------------------- + /// \brief sets and clears the title of a gnuplot session + /// + /// \param title --> the title of the plot [optional, default == ""] + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------------------------------- + inline Gnuplot &set_title(const std::string &title = "") + { + std::string cmdstr; + cmdstr = "set title \""; + cmdstr += title; + cmdstr += "\""; + *this << cmdstr; + return *this; + } + + //---------------------------------------------------------------------------------- + ///\brief Clears the title of a gnuplot session + /// The title is not set by default. + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // --------------------------------------------------------------------------------- + inline Gnuplot &unset_title() + { + this->set_title(); + return *this; + } + + /// set x axis label + Gnuplot &set_ylabel(const std::string &label = "x"); + /// set y axis label + Gnuplot &set_xlabel(const std::string &label = "y"); + /// set z axis label + Gnuplot &set_zlabel(const std::string &label = "z"); + + /// set axis - ranges + Gnuplot &set_xrange(const double iFrom, const double iTo); + /// set y-axis - ranges + Gnuplot &set_yrange(const double iFrom, const double iTo); + /// set z-axis - ranges + Gnuplot &set_zrange(const double iFrom, const double iTo); + + /// autoscale axis (set by default) of xaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &set_xautoscale() + { + cmd("set xrange restore"); + cmd("set autoscale x"); + return *this; + }; + + // ----------------------------------------------- + /// autoscale axis (set by default) of yaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &set_yautoscale() + { + cmd("set yrange restore"); + cmd("set autoscale y"); + return *this; + }; + + // ----------------------------------------------- + /// autoscale axis (set by default) of zaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &set_zautoscale() + { + cmd("set zrange restore"); + cmd("set autoscale z"); + return *this; + }; + + /// turns on/off log scaling for the specified xaxis (logscale is not set by default) + Gnuplot &set_xlogscale(const double base = 10); + /// turns on/off log scaling for the specified yaxis (logscale is not set by default) + Gnuplot &set_ylogscale(const double base = 10); + /// turns on/off log scaling for the specified zaxis (logscale is not set by default) + Gnuplot &set_zlogscale(const double base = 10); + + // ----------------------------------------------- + /// turns off log scaling for the x axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &unset_xlogscale() + { + cmd("unset logscale x"); + return *this; + }; + + // ----------------------------------------------- + /// turns off log scaling for the y axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &unset_ylogscale() + { + cmd("unset logscale y"); + return *this; + }; + + // ----------------------------------------------- + /// turns off log scaling for the z axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot &unset_zlogscale() + { + cmd("unset logscale z"); + return *this; + }; + + /// set palette range (autoscale by default) + Gnuplot &set_cbrange(const double iFrom, const double iTo); + + //---------------------------------------------------------------------------------- + // plot + + /// plot a single std::vector: x + /// from file + Gnuplot &plotfile_x(const std::string &filename, + const unsigned int column = 1, + const std::string &title = ""); + + /// from std::vector + template + Gnuplot &plot_x(const X &x, const std::string &title = ""); + + /// plot x,y pairs: x y + /// from file + Gnuplot &plotfile_xy(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const std::string &title = "", + const unsigned int decimate = 1); + /// from data + template + Gnuplot &plot_xy(const X &x, const Y &y, + const std::string &title = "", + const unsigned int decimate = 1); + + /// plot x,y pairs with dy errorbars: x y dy + /// from file + Gnuplot &plotfile_xy_err(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const unsigned int column_dy = 3, + const std::string &title = ""); + /// from data + template + Gnuplot &plot_xy_err(const X &x, const Y &y, const E &dy, + const std::string &title = ""); + + template + Gnuplot &plot_grid3d(const X &x, const Y &y, const E &mag, + const std::string &title = ""); + + /// plot x,y,z triples: x y z + /// from file + Gnuplot &plotfile_xyz(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const unsigned int column_z = 3, + const std::string &title = ""); + /// from std::vector + template + Gnuplot &plot_xyz(const X &x, + const Y &y, + const Z &z, + const std::string &title = ""); + + /// plot an equation of the form: y = ax + b, you supply a and b + Gnuplot &plot_slope(const double a, + const double b, + const std::string &title = ""); + + /// plot an equation supplied as a std::string y=f(x), write only the function f(x) not y= + /// the independent variable has to be x + /// binary operators: ** exponentiation, * multiply, / divide, + add, - subtract, % modulo + /// unary operators: - minus, ! factorial + /// elementary functions: rand(x), abs(x), sgn(x), ceil(x), floor(x), int(x), imag(x), real(x), arg(x), + /// sqrt(x), exp(x), log(x), log10(x), sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x), + /// sinh(x), cosh(x), tanh(x), asinh(x), acosh(x), atanh(x) + /// special functions: erf(x), erfc(x), inverf(x), gamma(x), igamma(a,x), lgamma(x), ibeta(p,q,x), + /// besj0(x), besj1(x), besy0(x), besy1(x), lambertw(x) + /// statistical functions: norm(x), invnorm(x) + Gnuplot &plot_equation(const std::string &equation, const std::string &title = ""); + + /// plot an equation supplied as a std::string z=f(x,y), write only the function f(x,y) not z= + /// the independent variables have to be x and y + Gnuplot &plot_equation3d(const std::string &equation, const std::string &title = ""); + + /// plot image + Gnuplot &plot_image(const unsigned char *ucPicBuf, + const unsigned int iWidth, + const unsigned int iHeight, + const std::string &title = ""); + + /// plot circle + Gnuplot &plot_circle(double east, double north, double radius, const std::string &label = ""); + + //---------------------------------------------------------------------------------- + ///\brief replot repeats the last plot or splot command. + /// this can be useful for viewing a plot with different set options, + /// or when generating the same plot for several devices (showonscreen, savetops) + /// + /// \param --- + /// + /// \return --- + //---------------------------------------------------------------------------------- + inline Gnuplot &replot(void) + { + if (nplots > 0) cmd("replot"); + return *this; + }; + + /// resets a gnuplot session (next plot will erase previous ones) + Gnuplot &reset_plot(); + + /// resets a gnuplot session and sets all variables to default + Gnuplot &reset_all(); + + /// deletes temporary files + void remove_tmpfiles(); + + // ------------------------------------------------------------------- + /// \brief Is the gnuplot session valid ?? + /// + /// + /// \param --- + /// + /// \return true if valid, false if not + // ------------------------------------------------------------------- + inline bool is_valid() { return (valid); }; +}; + + +//------------------------------------------------------------------------------ +// +// initialize static data +// +int Gnuplot::tmpfile_num = 0; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +std::string Gnuplot::m_sGNUPlotFileName = "pgnuplot.exe"; +std::string Gnuplot::m_sGNUPlotPath = "C:/program files/gnuplot/bin/"; +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) +std::string Gnuplot::m_sGNUPlotFileName = "gnuplot"; +std::string Gnuplot::m_sGNUPlotPath = "/usr/local/bin/"; +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +std::string Gnuplot::terminal_std = "windows"; +#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) +std::string Gnuplot::terminal_std = "x11"; +#elif defined(__APPLE__) +std::string Gnuplot::terminal_std = "aqua"; +#endif + +//------------------------------------------------------------------------------ +// +// constructor: set a style during construction +// +inline Gnuplot::Gnuplot(const std::string &style) + : gnucmd(nullptr), valid(false), two_dim(false), nplots(0) + +{ + init(); + set_style(style); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely) + : gnucmd(nullptr), valid(false), two_dim(false), nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + + plot_x(x, title); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x,y) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::vector &y, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely) + : gnucmd(nullptr), valid(false), two_dim(false), nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + + plot_xy(x, y, title); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x,y,z) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::vector &y, + const std::vector &z, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely, + const std::string &labelz) + : gnucmd(nullptr), valid(false), two_dim(false), nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + set_zlabel(labelz); + + plot_xyz(x, y, z, title); +} + + +//------------------------------------------------------------------------------ +// +/// Plots a 2d graph from a list of doubles: x +// +template +Gnuplot &Gnuplot::plot_x(const X &x, const std::string &title) +{ + if (x.size() == 0) + { + throw GnuplotException("std::vector too small"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << std::endl; + + tmp.flush(); + tmp.close(); + + plotfile_x(name, 1, title); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +/// Plots a 2d graph from a list of doubles: x y +// +template +Gnuplot &Gnuplot::plot_xy(const X &x, const Y &y, const std::string &title, const unsigned int decimate) +{ + if (x.size() == 0 || y.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << std::endl; + + tmp.flush(); + tmp.close(); + + plotfile_xy(name, 1, 2, title, decimate); + + return *this; +} + + +///----------------------------------------------------------------------------- +/// +/// plot x,y pairs with dy errorbars +/// +template +Gnuplot &Gnuplot::plot_xy_err(const X &x, + const Y &y, + const E &dy, + const std::string &title) +{ + if (x.size() == 0 || y.size() == 0 || dy.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size() || y.size() != dy.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << " " << dy[i] << std::endl; + + tmp.flush(); + tmp.close(); + + // Do the actual plot + plotfile_xy_err(name, 1, 2, 3, title); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 3d grid +// +template +Gnuplot &Gnuplot::plot_grid3d(const X &x, + const Y &y, + const E &mag, + const std::string &title) +{ + if (x.size() == 0 || y.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + { + for (unsigned int k = 0; k < y.size(); k++) + { + tmp << static_cast(x.at(i)) << " " << static_cast(y.at(k)) << " " << mag.at(i).at(k) << std::endl; + } + tmp.flush(); + } + + tmp.close(); + + std::ostringstream cmdstr; + cmdstr << "set ticslevel 0\n"; + cmdstr << "set hidden3d\n"; + cmdstr << "unset colorbox\n"; + cmdstr << "set border 5\n"; + cmdstr << "unset ztics\n"; + + cmdstr << " splot \"" << name << "\" u 1:2:3"; + + if (title == "") + cmdstr << " notitle with " << pstyle << " palette"; + else + cmdstr << " title \"" << title << "\" with " << pstyle << " palette"; + cmdstr << "\n"; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + +//------------------------------------------------------------------------------ +// +// Plots a 3d graph from a list of doubles: x y z +// +template +Gnuplot &Gnuplot::plot_xyz(const X &x, + const Y &y, + const Z &z, + const std::string &title) +{ + if (x.size() == 0 || y.size() == 0 || z.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size() || x.size() != z.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << " " << z[i] << std::endl; + + tmp.flush(); + tmp.close(); + + plotfile_xyz(name, 1, 2, 3, title); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// define static member function: set Gnuplot path manual +// for windows: path with slash '/' not backslash '\' +// +bool Gnuplot::set_GNUPlotPath(const std::string &path) +{ + std::string tmp = path + "/" + Gnuplot::m_sGNUPlotFileName; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (Gnuplot::file_exists(tmp, 0)) // check existence +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (Gnuplot::file_exists(tmp, 1)) // check existence and execution permission +#endif + { + Gnuplot::m_sGNUPlotPath = path; + return true; + } + + Gnuplot::m_sGNUPlotPath.clear(); + return false; +} + + +//------------------------------------------------------------------------------ +// +// define static member function: set standard terminal, used by showonscreen +// defaults: Windows - win, Linux - x11, Mac - aqua +// +void Gnuplot::set_terminal_std(const std::string &type) +{ +#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (type.find("x11") != std::string::npos && std::getenv("DISPLAY") == nullptr) + { + throw GnuplotException("Can't find DISPLAY variable"); + } +#endif + + Gnuplot::terminal_std = type; + return; +} + + +//------------------------------------------------------------------------------ +// +// A string tokenizer taken from http://www.sunsite.ualberta.ca/Documentation/ +// /Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt +// +template +void stringtok(Container &container, + std::string const &in, + const char *const delimiters = " \t\n") +{ + const std::string::size_type len = in.length(); + std::string::size_type i = 0; + + while (i < len) + { + // eat leading whitespace + i = in.find_first_not_of(delimiters, i); + + if (i == std::string::npos) + return; // nothing left but white space + + // find the end of the token + std::string::size_type j = in.find_first_of(delimiters, i); + + // push token + if (j == std::string::npos) + { + container.push_back(in.substr(i)); + return; + } + + container.push_back(in.substr(i, j - i)); + + // set up for next loop + i = j + 1; + } + + return; +} + + +//------------------------------------------------------------------------------ +// +// Destructor: needed to delete temporary files +// +Gnuplot::~Gnuplot() +{ +// remove_tmpfiles(); + +// A stream opened by popen() should be closed by pclose() +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_pclose(gnucmd) == -1) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (pclose(gnucmd) == -1) +#endif + // throw GnuplotException("Problem closing communication to gnuplot"); + std::cout << "Gnuplot window left open." << std::endl; +} + + +//------------------------------------------------------------------------------ +// +// Resets a gnuplot session (next plot will erase previous ones) +// +Gnuplot &Gnuplot::reset_plot() +{ + // remove_tmpfiles(); + nplots = 0; + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// resets a gnuplot session and sets all variables to default +// +Gnuplot &Gnuplot::reset_all() +{ + // remove_tmpfiles(); + nplots = 0; + cmd("reset"); + cmd("clear"); + pstyle = "points"; + smooth = ""; + showonscreen(); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Change the plotting style of a gnuplot session +// +Gnuplot &Gnuplot::set_style(const std::string &stylestr) +{ + if (stylestr.find("lines") == std::string::npos && + stylestr.find("points") == std::string::npos && + stylestr.find("linespoints") == std::string::npos && + stylestr.find("impulses") == std::string::npos && + stylestr.find("dots") == std::string::npos && + stylestr.find("steps") == std::string::npos && + stylestr.find("fsteps") == std::string::npos && + stylestr.find("histeps") == std::string::npos && + stylestr.find("boxes") == std::string::npos && // 1-4 columns of data are required + stylestr.find("filledcurves") == std::string::npos && + stylestr.find("histograms") == std::string::npos) //only for one data column + // stylestr.find("labels") == std::string::npos && // 3 columns of data are required + // stylestr.find("xerrorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("xerrorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("errorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("errorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("yerrorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("yerrorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("boxerrorbars") == std::string::npos && // 3-5 columns of data are required + // stylestr.find("xyerrorbars") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("xyerrorlines") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("boxxyerrorbars") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("financebars") == std::string::npos && // 5 columns of data are required + // stylestr.find("candlesticks") == std::string::npos && // 5 columns of data are required + // stylestr.find("vectors") == std::string::npos && + // stylestr.find("image") == std::string::npos && + // stylestr.find("rgbimage") == std::string::npos && + // stylestr.find("pm3d") == std::string::npos ) + { + pstyle = std::string("points"); + } + else + { + pstyle = stylestr; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// smooth: interpolation and approximation of data +// +Gnuplot &Gnuplot::set_smooth(const std::string &stylestr) +{ + if (stylestr.find("unique") == std::string::npos && + stylestr.find("frequency") == std::string::npos && + stylestr.find("csplines") == std::string::npos && + stylestr.find("acsplines") == std::string::npos && + stylestr.find("bezier") == std::string::npos && + stylestr.find("sbezier") == std::string::npos) + { + smooth = ""; + } + else + { + smooth = stylestr; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Disable screen output +// +Gnuplot &Gnuplot::disablescreen() +{ + cmd("set output"); + cmd("set terminal unknown"); + return *this; +} + +//------------------------------------------------------------------------------ +// +// sets terminal type to windows / x11 +// +Gnuplot &Gnuplot::showonscreen() +{ + std::string persist(" persist"); +#ifdef __APPLE__ + persist = ""; +#endif + cmd("set output"); + cmd("set terminal " + Gnuplot::terminal_std + persist); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// saves a gnuplot session to a pdf file +// +Gnuplot &Gnuplot::savetopdf(const std::string &filename, unsigned int font_size) +{ + std::ostringstream cmdstr; + cmdstr << "set term pdfcairo enhanced color font \"Times-New-Roman," + std::to_string(font_size) + "\"\n"; + cmdstr << "set output \"" << filename << ".pdf\"\n"; + cmdstr << "replot"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// saves a gnuplot session to a postscript file +// +Gnuplot &Gnuplot::savetops(const std::string &filename) +{ + std::ostringstream cmdstr; + cmdstr << "set term postscript landscape enhanced color dashed \"Times-Roman\" 18\n"; + cmdstr << "set output \"" << filename << ".ps\"\n"; + cmdstr << "replot"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Switches legend on +// +Gnuplot &Gnuplot::set_legend(const std::string &position) +{ + std::ostringstream cmdstr; + cmdstr << "set key " << position; + + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the x axis +// +Gnuplot &Gnuplot::set_xlogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale x " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the y axis +// +Gnuplot &Gnuplot::set_ylogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale y " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the z axis +// +Gnuplot &Gnuplot::set_zlogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale z " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// scales the size of the points used in plots +// +Gnuplot &Gnuplot::set_pointsize(const double pointsize) +{ + std::ostringstream cmdstr; + cmdstr << "set pointsize " << pointsize; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set isoline density (grid) for plotting functions as surfaces +// +Gnuplot &Gnuplot::set_samples(const int samples) +{ + std::ostringstream cmdstr; + cmdstr << "set samples " << samples; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set isoline density (grid) for plotting functions as surfaces +// +Gnuplot &Gnuplot::set_isosamples(const int isolines) +{ + std::ostringstream cmdstr; + cmdstr << "set isosamples " << isolines; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// enables contour drawing for surfaces set contour {base | surface | both} +// +Gnuplot &Gnuplot::set_contour(const std::string &position) +{ + if (position.find("base") == std::string::npos && + position.find("surface") == std::string::npos && + position.find("both") == std::string::npos) + { + cmd("set contour base"); + } + else + { + cmd("set contour " + position); + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set labels +// +// set the xlabel +Gnuplot &Gnuplot::set_xlabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the ylabel +// +Gnuplot &Gnuplot::set_ylabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set ylabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the zlabel +// +Gnuplot &Gnuplot::set_zlabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set zlabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set range +// +// set the xrange +Gnuplot &Gnuplot::set_xrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set xrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the yrange +// +Gnuplot &Gnuplot::set_yrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set yrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the zrange +// +Gnuplot &Gnuplot::set_zrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set zrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set the palette range +// +Gnuplot &Gnuplot::set_cbrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set cbrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a linear equation y=ax+b (where you supply the +// slope a and intercept b) +// +Gnuplot &Gnuplot::plot_slope(const double a, + const double b, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << a << " * x + " << b << " title \""; + + if (title == "") + cmdstr << "f(x) = " << a << " * x + " << b; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plot an equation supplied as a std::string y=f(x) (only f(x) expected) +// +Gnuplot &Gnuplot::plot_equation(const std::string &equation, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << equation << " title \""; + + if (title == "") + cmdstr << "f(x) = " << equation; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// plot an equation supplied as a std::string y=(x) +// +Gnuplot &Gnuplot::plot_equation3d(const std::string &equation, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == false) + cmdstr << "replot "; + else + cmdstr << "splot "; + + cmdstr << equation << " title \""; + + if (title == "") + cmdstr << "f(x,y) = " << equation; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph from a list of doubles (x) saved in a file +// +Gnuplot &Gnuplot::plotfile_x(const std::string &filename, + const unsigned int column, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " << column; + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + if (smooth == "") + cmdstr << "with " << pstyle; + else + cmdstr << "smooth " << smooth; + + // + // Do the actual plot + // + cmd(cmdstr.str()); //nplots++; two_dim = true; already in cmd(); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph from a list of doubles (x y) saved in a file +// +Gnuplot &Gnuplot::plotfile_xy(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const std::string &title, + const unsigned int decimate) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y << " every " << std::to_string(decimate); + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + if (smooth == "") + cmdstr << "with " << pstyle; + else + cmdstr << "smooth " << smooth; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph with errorbars from a list of doubles (x y dy) in a file +// +Gnuplot &Gnuplot::plotfile_xy_err(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const unsigned int column_dy, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " + << column_x << ":" << column_y << ":" << column_dy + << " with errorbars "; + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 3d graph from a list of doubles (x y z) saved in a file +// +Gnuplot &Gnuplot::plotfile_xyz(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const unsigned int column_z, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == false) + cmdstr << "replot "; + else + cmdstr << "splot "; + + cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y + << ":" << column_z; + + if (title == "") + cmdstr << " notitle with " << pstyle; + else + cmdstr << " title \"" << title << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +/// * note that this function is not valid for versions of GNUPlot below 4.2 +// +Gnuplot &Gnuplot::plot_image(const unsigned char *ucPicBuf, + const unsigned int iWidth, + const unsigned int iHeight, + const std::string &title) +{ + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + int iIndex = 0; + for (unsigned int iRow = 0; iRow < iHeight; iRow++) + { + for (unsigned int iColumn = 0; iColumn < iWidth; iColumn++) + { + tmp << iColumn << " " << iRow << " " + << static_cast(ucPicBuf[iIndex++]) << std::endl; + } + } + + tmp.flush(); + tmp.close(); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + if (title == "") + cmdstr << "\"" << name << "\" with image"; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with image"; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +Gnuplot &Gnuplot::plot_circle(double east, double north, double radius, const std::string &label) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + cmdstr << "set object circle at " + std::to_string(east) + "," + std::to_string(north) + " size " + + std::to_string(radius) + " back\n"; + + if (label != "") + { + double east_label = (std::cos(M_PI / 3.0) * radius) * 1.1 + east; + double north_label = (std::sin(M_PI / 3.0) * radius) * 1.1 + north; + cmdstr << "set label \"" + label + "\" at first " + std::to_string(east_label) + + ", " + std::to_string(north_label) + " norotate back nopoint offset 0,0\n"; + } + if (nplots > 0) + cmdstr << "replot "; + else + cmdstr << "plot "; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Sends a command to an active gnuplot session +// +Gnuplot &Gnuplot::cmd(const std::string &cmdstr) +{ + if (!(valid)) + { + return *this; + } + + // int fputs ( const char * str, FILE * stream ); + // writes the string str to the stream. + // The function begins copying from the address specified (str) until it + // reaches the terminating null character ('\0'). This final + // null-character is not copied to the stream. + fputs((cmdstr + "\n").c_str(), gnucmd); + + // int fflush ( FILE * stream ); + // If the given stream was open for writing and the last i/o operation was + // an output operation, any unwritten data in the output buffer is written + // to the file. If the argument is a null pointer, all open files are + // flushed. The stream remains open after this call. + fflush(gnucmd); + + if (cmdstr.find("replot") != std::string::npos) + { + return *this; + } + if (cmdstr.find("splot") != std::string::npos) + { + two_dim = false; + nplots++; + } + else if (cmdstr.find("plot") != std::string::npos) + { + two_dim = true; + nplots++; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Opens up a gnuplot session, ready to receive commands +// +void Gnuplot::init() +{ +// char * getenv ( const char * name ); get value of environment variable +// Retrieves a C string containing the value of the environment variable +// whose name is specified as argument. If the requested variable is not +// part of the environment list, the function returns a NULL pointer. +#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) + if (std::getenv("DISPLAY") == NULL) + { + valid = false; + throw GnuplotException("Can't find DISPLAY variable"); + } +#endif + + // if gnuplot not available + if (!Gnuplot::get_program_path()) + { + valid = false; + throw GnuplotException("Can't find gnuplot"); + } + + // + // open pipe + // + std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + + Gnuplot::m_sGNUPlotFileName; + +// FILE *popen(const char *command, const char *mode); +// The popen() function shall execute the command specified by the string +// command, create a pipe between the calling program and the executed +// command, and return a pointer to a stream that can be used to either read +// from or write to the pipe. +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + gnucmd = _popen(tmp.c_str(), "w"); +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + gnucmd = popen(tmp.c_str(), "w"); +#endif + + // popen() shall return a pointer to an open stream that can be used to read + // or write to the pipe. Otherwise, it shall return a null pointer and may + // set errno to indicate the error. + if (!gnucmd) + { + valid = false; + throw GnuplotException("Couldn't open connection to gnuplot"); + } + + nplots = 0; + valid = true; + smooth = ""; + + //set terminal type + showonscreen(); + + return; +} + + +//------------------------------------------------------------------------------ +// +// Find out if a command lives in m_sGNUPlotPath or in PATH +// +bool Gnuplot::get_program_path() +{ + // + // first look in m_sGNUPlotPath for Gnuplot + // + std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + + Gnuplot::m_sGNUPlotFileName; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (Gnuplot::file_exists(tmp, 0)) // check existence +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (Gnuplot::file_exists(tmp, 1)) // check existence and execution permission +#endif + { + return true; + } + + // + // second look in PATH for Gnuplot + // + const char *path; + // Retrieves a C string containing the value of environment variable PATH + path = std::getenv("PATH"); + std::stringstream s; + s << path; + if (s.fail()) + { + throw GnuplotException("Path is not set"); + } + std::string path_str = s.str(); + + std::list ls; + +//split path (one long string) into list ls of strings +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + stringtok(ls, path_str, ";"); +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + stringtok(ls, path_str, ":"); +#endif + + // scan list for Gnuplot program files + for (std::list::const_iterator i = ls.begin(); + i != ls.end(); ++i) + { + tmp = (*i) + "/" + Gnuplot::m_sGNUPlotFileName; +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (Gnuplot::file_exists(tmp, 0)) // check existence +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (Gnuplot::file_exists(tmp, 1)) // check existence and execution permission +#endif + { + Gnuplot::m_sGNUPlotPath = *i; // set m_sGNUPlotPath + return true; + } + } + + tmp = "Can't find gnuplot neither in PATH nor in \"" + + Gnuplot::m_sGNUPlotPath + "\""; + Gnuplot::m_sGNUPlotPath = ""; + throw GnuplotException(tmp); +} + + +//------------------------------------------------------------------------------ +// +// check if file exists +// +bool Gnuplot::file_exists(const std::string &filename, int mode) +{ + if (mode < 0 || mode > 7) + { + throw std::runtime_error( + "In function \"Gnuplot::file_exists\": mode\ + has to be an integer between 0 and 7"); + return false; + } + +// int _access(const char *path, int mode); +// returns 0 if the file has the given mode, +// it returns -1 if the named file does not exist or is not accessible in +// the given mode +// mode = 0 (F_OK) (default): checks file for existence only +// mode = 1 (X_OK): execution permission +// mode = 2 (W_OK): write permission +// mode = 4 (R_OK): read permission +// mode = 6 : read and write permission +// mode = 7 : read, write and execution permission +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_access(filename.c_str(), mode) == 0) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (access(filename.c_str(), mode) == 0) +#endif + { + return true; + } + return false; +} + + +bool Gnuplot::file_available(const std::string &filename) +{ + std::ostringstream except; + if (Gnuplot::file_exists(filename, 0)) // check existence + { + if (!(Gnuplot::file_exists(filename, 4))) + { // check read permission + except << "No read permission for File \"" << filename << "\""; + throw GnuplotException(except.str()); + return false; + } + } + else + { + except << "File \"" << filename << "\" does not exist"; + throw GnuplotException(except.str()); + return false; + } + return true; +} + + +//------------------------------------------------------------------------------ +// +// Opens a temporary file +// +std::string Gnuplot::create_tmpfile(std::ofstream &tmp) +{ +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + char name[] = "gnuplotiXXXXXX"; //tmp file in working directory +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + char name[] = "/tmp/gnuplotiXXXXXX"; // tmp file in /tmp +#endif + + // + // check if maximum number of temporary files reached + // + if (Gnuplot::tmpfile_num == GP_MAX_TMP_FILES - 1) + { + std::ostringstream except; + except << "Maximum number of temporary files reached (" + << GP_MAX_TMP_FILES << "): cannot open more files" << std::endl; + + throw GnuplotException(except.str()); + } + + // int mkstemp(char *name); + // shall replace the contents of the string pointed to by "name" by a unique + // filename, and return a file descriptor for the file open for reading and + // writing. Otherwise, -1 shall be returned if no suitable file could be + // created. The string in template should look like a filename with six + // trailing 'X' s; mkstemp() replaces each 'X' with a character from the + // portable filename character set. The characters are chosen such that the + // resulting name does not duplicate the name of an existing file at the + // time of a call to mkstemp() + + // + // open temporary files for output + // + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_mktemp(name) == NULL) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); + if (mkstemp(name) == -1) +#endif + { + std::ostringstream except; + except << "Cannot create temporary file \"" << name << "\""; +#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + umask(mask); +#endif + throw GnuplotException(except.str()); + } +#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + umask(mask); +#endif + tmp.open(name); + if (tmp.bad()) + { + std::ostringstream except; + except << "Cannot create temporary file \"" << name << "\""; + throw GnuplotException(except.str()); + } + + // + // Save the temporary filename + // + tmpfile_list.emplace_back(name); + Gnuplot::tmpfile_num++; + + return name; +} + + +void Gnuplot::remove_tmpfiles() +{ + if ((tmpfile_list).size() > 0) + { + for (auto &i : tmpfile_list) + if (remove(i.c_str()) != 0) + std::cout << "Problem closing files" << std::endl; + + Gnuplot::tmpfile_num -= tmpfile_list.size(); + } +} + + +#endif diff --git a/src/tests/common-files/observable_tests_flags.h b/src/tests/common-files/observable_tests_flags.h new file mode 100644 index 000000000..37d2bab99 --- /dev/null +++ b/src/tests/common-files/observable_tests_flags.h @@ -0,0 +1,42 @@ +/*! + * \file tracking_tests_flags.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_OBSERVABLE_TESTS_FLAGS_H_ +#define GNSS_SDR_OBSERVABLE_TESTS_FLAGS_H_ + +#include +#include + +DEFINE_double(skip_obs_transitory_s, 30.0, "Skip the initial observable outputs to avoid transitory results [s]"); +DEFINE_bool(compute_single_diffs, false, "Compute also the single difference errors for Accumulated Carrier Phase and Carrier Doppler (requires LO synchronization between receivers)"); +DEFINE_bool(compare_with_5X, false, "Compare the E5a Doppler and Carrier Phases with the E5 full bw in RINEX (expect discrepancy due to the center frequencies differences"); +DEFINE_bool(duplicated_satellites_test, false, "Enable special observable test mode where the scenario contains duplicated satellite orbits"); +DEFINE_string(duplicated_satellites_prns, "1,2,3,4", "List of duplicated satellites PRN pairs (i.e. 1,2,3,4 indicates that the PRNs 1,2 share the same orbit. The same applies for PRNs 3,4)"); +#endif diff --git a/src/tests/common-files/signal_generator_flags.h b/src/tests/common-files/signal_generator_flags.h index 07a01a511..b5e737adc 100644 --- a/src/tests/common-files/signal_generator_flags.h +++ b/src/tests/common-files/signal_generator_flags.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,17 +32,20 @@ #define GNSS_SDR_SIGNAL_GENERATOR_FLAGS_H_ #include +#include - +DEFINE_bool(disable_generator, false, "Disable the signal generator (a external signal file must be available for the test)"); DEFINE_string(generator_binary, std::string(SW_GENERATOR_BIN), "Path of software-defined signal generator binary"); DEFINE_string(rinex_nav_file, std::string(DEFAULT_RINEX_NAV), "Input RINEX navigation file"); DEFINE_int32(duration, 100, "Duration of the experiment [in seconds, max = 300]"); -DEFINE_string(static_position, "30.286502,120.032669,100", "Static receiver position [log,lat,height]"); +DEFINE_string(static_position, "30.286502,120.032669,100", "Static receiver position [latitude,longitude,height]"); DEFINE_string(dynamic_position, "", "Observer positions file, in .csv or .nmea format"); DEFINE_string(filename_rinex_obs, "sim.16o", "Filename of output RINEX navigation file"); DEFINE_string(filename_raw_data, "signal_out.bin", "Filename of output raw data file"); -DEFINE_int32(fs_gen_hz, 2600000, "Samppling frequency [Hz]"); +DEFINE_int32(fs_gen_sps, 2600000, "Sampling frequency [sps]"); DEFINE_int32(test_satellite_PRN, 1, "PRN of the satellite under test (must be visible during the observation time)"); - +DEFINE_int32(test_satellite_PRN2, 2, "PRN of the satellite under test (must be visible during the observation time)"); +DEFINE_string(test_satellite_PRN_list, "1,2,3,6,9,10,12,17,20,23,28", "List of PRN of the satellites under test (must be visible during the observation time)"); +DEFINE_double(CN0_dBHz, std::numeric_limits::infinity(), "Enable noise generator and set the CN0 [dB-Hz]"); #endif diff --git a/src/tests/common-files/test_flags.h b/src/tests/common-files/test_flags.h new file mode 100644 index 000000000..1d2cb3818 --- /dev/null +++ b/src/tests/common-files/test_flags.h @@ -0,0 +1,45 @@ +/*! + * \file test_flags.h + * \brief Helper file for unit testing + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_TEST_FLAGS_H_ +#define GNSS_SDR_TEST_FLAGS_H_ + +#include + +#if defined GNUPLOT_EXECUTABLE +DEFINE_string(gnuplot_executable, std::string(GNUPLOT_EXECUTABLE), "Gnuplot binary path"); +#elif !defined GNUPLOT_EXECUTABLE +DEFINE_string(gnuplot_executable, "", "Gnuplot binary path"); +#endif + +DEFINE_bool(plot_acq_grid, false, "Plots acquisition grid with gnuplot"); +DEFINE_int32(plot_decimate, 1, "Decimate plots"); + +#endif diff --git a/src/tests/common-files/tracking_tests_flags.h b/src/tests/common-files/tracking_tests_flags.h new file mode 100644 index 000000000..1724fcf68 --- /dev/null +++ b/src/tests/common-files/tracking_tests_flags.h @@ -0,0 +1,91 @@ +/*! + * \file tracking_tests_flags.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_TRACKING_TESTS_FLAGS_H_ +#define GNSS_SDR_TRACKING_TESTS_FLAGS_H_ + +#include +#include + + +DEFINE_string(trk_test_implementation, std::string("GPS_L1_CA_DLL_PLL_Tracking"), "Tracking block implementation under test, defaults to GPS_L1_CA_DLL_PLL_Tracking"); +// Input signal configuration +DEFINE_bool(enable_external_signal_file, false, "Use an external signal file capture instead of the software-defined signal generator"); +DEFINE_double(external_signal_acquisition_threshold, 2.5, "Threshold for satellite acquisition when external file is used"); +DEFINE_int32(external_signal_acquisition_dwells, 5, "Maximum dwells count for satellite acquisition when external file is used"); +DEFINE_double(external_signal_acquisition_doppler_max_hz, 5000.0, "Doppler max for satellite acquisition when external file is used"); +DEFINE_double(external_signal_acquisition_doppler_step_hz, 125.0, "Doppler step for satellite acquisition when external file is used"); +DEFINE_bool(use_acquisition_resampler, false, "Reduce the sampling rate of the input signal for the acquisition in order to optimize the SNR and decrease the processor load"); + +DEFINE_string(signal_file, std::string("signal_out.bin"), "Path of the external signal capture file"); +DEFINE_double(CN0_dBHz_start, std::numeric_limits::infinity(), "Enable noise generator and set the CN0 start sweep value [dB-Hz]"); +DEFINE_double(CN0_dBHz_stop, std::numeric_limits::infinity(), "Enable noise generator and set the CN0 stop sweep value [dB-Hz]"); +DEFINE_double(CN0_dB_step, 3.0, "Noise generator CN0 sweep step value [dB]"); + +DEFINE_double(PLL_bw_hz_start, 20.0, "PLL Wide configuration start sweep value [Hz]"); +DEFINE_double(PLL_bw_hz_stop, 20.0, "PLL Wide configuration stop sweep value [Hz]"); +DEFINE_double(PLL_bw_hz_step, 5.0, "PLL Wide configuration sweep step value [Hz]"); + +DEFINE_double(DLL_bw_hz_start, 1.0, "DLL Wide configuration start sweep value [Hz]"); +DEFINE_double(DLL_bw_hz_stop, 1.0, "DLL Wide configuration stop sweep value [Hz]"); +DEFINE_double(DLL_bw_hz_step, 0.25, "DLL Wide configuration sweep step value [Hz]"); + +DEFINE_double(PLL_narrow_bw_hz, 5.0, "PLL Narrow configuration value [Hz]"); +DEFINE_double(DLL_narrow_bw_hz, 0.75, "DLL Narrow configuration value [Hz]"); + +DEFINE_double(acq_Doppler_error_hz_start, 1000.0, "Acquisition Doppler error start sweep value [Hz]"); +DEFINE_double(acq_Doppler_error_hz_stop, -1000.0, "Acquisition Doppler error stop sweep value [Hz]"); +DEFINE_double(acq_Doppler_error_hz_step, -50.0, "Acquisition Doppler error sweep step value [Hz]"); + +DEFINE_double(acq_Delay_error_chips_start, 2.0, "Acquisition Code Delay error start sweep value [Chips]"); +DEFINE_double(acq_Delay_error_chips_stop, -2.0, "Acquisition Code Delay error stop sweep value [Chips]"); +DEFINE_double(acq_Delay_error_chips_step, -0.1, "Acquisition Code Delay error sweep step value [Chips]"); + +DEFINE_double(acq_to_trk_delay_s, 0.0, "Acquisition to Tracking delay value [s]"); + + +DEFINE_int64(skip_samples, 0, "Skip an initial transitory in the processed signal file capture [samples]"); + +DEFINE_int32(plot_detail_level, 0, "Specify the desired plot detail (0,1,2): 0 - Minimum plots (default) 2 - Plot all tracking parameters"); + +DEFINE_double(skip_trk_transitory_s, 1.0, "Skip the initial tracking output signal to avoid transitory results [s]"); + +//Emulated acquisition configuration + +//Tracking configuration +DEFINE_int32(extend_correlation_symbols, 1, "Set the tracking coherent correlation to N symbols (up to 20 for GPS L1 C/A)"); +DEFINE_int32(smoother_length, 10, "Set the moving average size for the carrier phase and code phase in case of high dynamics"); +DEFINE_bool(high_dyn, false, "Activates the code resampler and NCO generator for high dynamics"); + +//Test output configuration +DEFINE_bool(plot_gps_l1_tracking_test, false, "Plots results of GpsL1CADllPllTrackingTest with gnuplot"); + + +#endif diff --git a/src/tests/data/rtklib_test/eph_GPS_L1CA_test1.xml b/src/tests/data/rtklib_test/eph_GPS_L1CA_test1.xml new file mode 100644 index 000000000..4dcc2564d --- /dev/null +++ b/src/tests/data/rtklib_test/eph_GPS_L1CA_test1.xml @@ -0,0 +1,481 @@ + + + + + 11 + 0 + + 1 + + 1 + 5.18448000000000000e+05 + 9.20000000000000000e+01 + 9.20000000000000000e+01 + 1.83125000000000000e+01 + 4.86413118201646669e-09 + 2.06468198930943725e+00 + 9.42498445510864258e-07 + 3.73082922305911736e-03 + 5.76488673686981201e-06 + 5.15366174697875977e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -5.40167093276977539e-08 + 9.52167247599200905e-01 + 1.86264514923095703e-08 + 9.61377026423456127e-01 + 2.66968750000000000e+02 + 4.44935333708291858e-01 + -8.14641075927847669e-09 + 4.15017287135849497e-10 + 0 + 799 + 0 + 2 + 0 + 5.12227416038513184e-09 + 9.20000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + -1.09937973320484161e-05 + 3.41060513164847988e-13 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 2 + + 2 + 5.18448000000000000e+05 + 5.50000000000000000e+01 + 5.50000000000000000e+01 + 2.22812500000000000e+01 + 5.12771358985317661e-09 + 2.75926302782053146e+00 + 1.10082328319549561e-06 + 1.40569622162729484e-02 + 6.26407563686370850e-06 + 5.15372654151916504e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -1.86264514923095703e-08 + 9.18037446344556307e-01 + -2.16066837310791016e-07 + 9.39991586696909520e-01 + 2.45468750000000000e+02 + -2.35598690357981555e+00 + -8.07140763509730069e-09 + 5.25736184736635464e-10 + 0 + 799 + 0 + 2 + 0 + -2.00234353542327881e-08 + 5.50000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 5.36850653588771820e-04 + 2.16004991671070416e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 3 + + 3 + 5.18448000000000000e+05 + 7.00000000000000000e+01 + 7.00000000000000000e+01 + -2.04375000000000000e+01 + 4.75769817722603366e-09 + -1.78871492992227910e+00 + -1.30012631416320801e-06 + 9.70319728367030512e-04 + 8.26455652713775635e-06 + 5.15378153991699219e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + 7.82310962677001953e-08 + 1.99297660614955263e+00 + -1.11758708953857422e-08 + 9.59058451948379909e-01 + 2.19593750000000000e+02 + -3.00536842405812843e+00 + -8.02712007605698577e-09 + -5.17164399115929480e-10 + 0 + 799 + 0 + 2 + 0 + 5.12227416038513184e-09 + 7.00000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 8.80691222846508026e-05 + 2.89901436190120811e-11 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 6 + + 6 + 5.18448000000000000e+05 + 2.30000000000000000e+01 + 2.30000000000000000e+01 + 1.63750000000000000e+01 + 4.76305554323897445e-09 + -1.28531071631616522e+00 + 9.12696123123168945e-07 + 5.50022465176880251e-04 + 6.24358654022216797e-06 + 5.15365166282653809e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -1.30385160446166992e-08 + 9.43624288779246867e-01 + -1.86264514923095703e-09 + 9.61292940818096020e-01 + 2.58406250000000000e+02 + 2.29191014519991665e+00 + -8.08069373618639861e-09 + 4.79305679291144535e-10 + 0 + 799 + 0 + 2 + 0 + 4.65661287307739258e-09 + 2.30000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 3.07881273329257965e-05 + 8.18545231595635253e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 9 + + 9 + 5.18448000000000000e+05 + 4.70000000000000000e+01 + 4.70000000000000000e+01 + 1.12906250000000000e+02 + 4.37911097897818463e-09 + -2.75253879947800195e+00 + 5.85243105888366699e-06 + 2.16206186451017829e-04 + 1.16303563117980957e-05 + 5.15369471168518066e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + 1.67638063430786133e-08 + 3.03742251571970812e+00 + -1.11758708953857422e-08 + 9.59160503650671514e-01 + 1.56125000000000000e+02 + 2.60662251530764344e+00 + -7.85854162551643464e-09 + -3.46443002170201364e-11 + 0 + 799 + 0 + 2 + 0 + 4.65661287307739258e-10 + 4.70000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + -3.18535603582859039e-05 + -9.66338120633736091e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 10 + + 10 + 5.18448000000000000e+05 + 5.80000000000000000e+01 + 5.80000000000000000e+01 + -2.72500000000000000e+01 + 5.27093384126580581e-09 + -8.86982818851813737e-01 + -1.17719173431396484e-06 + 1.44534236751496774e-02 + 7.90506601333618164e-06 + 5.15363725471496582e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + 1.45286321640014648e-07 + 2.00408517949479270e+00 + 2.40281224250793457e-07 + 9.41160112993577269e-01 + 2.15406250000000000e+02 + 9.09732121011562200e-01 + -8.42213653007785350e-09 + -5.42879755978047536e-10 + 0 + 799 + 0 + 2 + 0 + -2.79396772384643555e-09 + 5.80000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + -1.54968351125717163e-04 + -1.59161572810262401e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 12 + + 12 + 5.18448000000000000e+05 + 1.06000000000000000e+02 + 1.06000000000000000e+02 + -1.17468750000000000e+02 + 3.94516433192994276e-09 + 1.11631735294997192e+00 + -6.15417957305908203e-06 + 5.05860964767634782e-03 + 4.52436506748199463e-06 + 5.15376680946350098e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -5.40167093276977539e-08 + -1.10425023618040785e+00 + 4.09781932830810547e-08 + 9.88803748742243305e-01 + 3.07187500000000000e+02 + 5.00154452274795935e-01 + -7.97176062725659211e-09 + -4.18231706743614228e-10 + 0 + 799 + 0 + 2 + 0 + -1.16415321826934814e-08 + 1.06000000000000000e+02 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 2.54871323704719543e-04 + 2.72848410531878391e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 17 + + 17 + 5.18448000000000000e+05 + 2.60000000000000000e+01 + 2.60000000000000000e+01 + -5.91250000000000000e+01 + 3.88194741297723567e-09 + -1.94252959218893162e+00 + -3.04728746414184570e-06 + 9.88844956737011498e-03 + 1.18296593427658081e-05 + 5.15369299888610840e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + 2.03028321266174316e-07 + -5.68690999805671268e-02 + -7.63684511184692383e-08 + 9.71201777972365177e-01 + 1.56531250000000000e+02 + -2.06928329237789344e+00 + -7.44602444251995675e-09 + 4.40375486263771432e-10 + 0 + 799 + 0 + 2 + 0 + -1.07102096080780029e-08 + 2.60000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + -1.44933816045522690e-04 + -2.27373675443232019e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 20 + + 20 + 5.18448000000000000e+05 + 1.17000000000000000e+02 + 1.17000000000000000e+02 + -2.58437500000000000e+01 + 5.60380484953655626e-09 + 1.28625710142833249e-01 + -1.52923166751861572e-06 + 5.80669869668781671e-03 + 7.51018524169921875e-06 + 5.15578671264648438e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -2.23517417907714844e-08 + 1.92543994118208528e+00 + 4.65661287307739258e-08 + 9.26021286652122910e-01 + 2.18031250000000000e+02 + 1.23365536128043107e+00 + -8.54892752571746483e-09 + -5.16450083647537340e-10 + 0 + 799 + 0 + 2 + 0 + -8.38190317153930664e-09 + 1.17000000000000000e+02 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 2.69209500402212143e-04 + 4.20641299569979229e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 23 + + 23 + 5.18448000000000000e+05 + 4.10000000000000000e+01 + 4.10000000000000000e+01 + 1.20250000000000000e+02 + 4.45161399901998963e-09 + 3.04794581942897569e+00 + 6.13741576671600342e-06 + 9.67817602213471954e-03 + 1.14180147647857666e-05 + 5.15370163154602051e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -6.14672899246215820e-08 + 3.04748172476042711e+00 + -1.04308128356933594e-07 + 9.50229191282804808e-01 + 1.56000000000000000e+02 + -2.71676891930177256e+00 + -7.78032408172749087e-09 + -2.75011455330984601e-11 + 0 + 799 + 0 + 2 + 0 + -1.95577740669250488e-08 + 4.10000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + -7.56788067519664764e-05 + -2.72848410531878391e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + 28 + + 28 + 5.18448000000000000e+05 + 3.30000000000000000e+01 + 3.30000000000000000e+01 + -1.27750000000000000e+02 + 4.04302555109966970e-09 + -1.16607683198628931e+00 + -6.37024641036987305e-06 + 1.97223023278638686e-02 + 5.66989183425903320e-06 + 5.15368548965454102e+03 + 5.18400000000000000e+05 + 5.18400000000000000e+05 + -1.37835741043090820e-07 + -1.08006546321039543e+00 + 4.35858964920043945e-07 + 9.87961552655681530e-01 + 2.84718750000000000e+02 + -1.69047108635756738e+00 + -8.17855495535612472e-09 + -4.44661379074124424e-10 + 0 + 799 + 0 + 2 + 0 + -1.11758708953857422e-08 + 3.30000000000000000e+01 + 27900 + 0 + 0.00000000000000000e+00 + 0.00000000000000000e+00 + 4.06486913561820984e-04 + 2.61479726759716828e-12 + 0.00000000000000000e+00 + 0 + 0 + 0 + + + + diff --git a/src/tests/data/rtklib_test/obs_test1.xml b/src/tests/data/rtklib_test/obs_test1.xml new file mode 100644 index 000000000..8c96fc2ff --- /dev/null +++ b/src/tests/data/rtklib_test/obs_test1.xml @@ -0,0 +1,358 @@ + + + + + 10 + 0 + + 0 + + 71 + + 3 + 49 + 67 + 0 + + 1 + 0 + 2.28200000000000000e+03 + -2.50000000000000000e+03 + 10791 + 0 + 0 + 2600000 + -3.85959140625000000e+04 + -9.03592163085937500e+02 + 5.96898384094238281e+01 + -2.57914688873291016e+03 + 8.35350813421410858e+05 + 3.31084377635761484e-01 + 133923691 + 1 + 1 + 1 + 518451424 + 2.28178186234515086e+07 + 5.18451500000000000e+05 + 1 + 5.18451423887949765e+08 + + + + 1 + + 71 + + 3 + 49 + 67 + 0 + + 3 + 1 + 2.38500000000000000e+03 + -3.00000000000000000e+03 + 68450858 + 0 + 0 + 2600000 + -4.34972734375000000e+04 + 4.21364685058593750e+02 + 5.16798934936523438e+01 + -3.12509065246582031e+03 + 4.93910706686261110e+05 + 7.36033200862493686e-01 + 133923971 + 1 + 1 + 1 + 518451431 + 2.07516033774388395e+07 + 5.18451500000000000e+05 + 1 + 5.18451430780101955e+08 + + + + 2 + + 71 + + 3 + 49 + 67 + 0 + + 28 + 2 + 1.52700000000000000e+03 + -3.00000000000000000e+03 + 1350770 + 0 + 0 + 2600000 + 4.46268046875000000e+04 + -3.98811938476562500e+03 + 5.25376167297363281e+01 + -2.92984253692626953e+03 + 9.35704822809229488e+05 + 9.30327007595224131e-01 + 133923941 + 1 + 1 + 1 + 518451436 + 1.92492043561209217e+07 + 5.18451500000000000e+05 + 1 + 5.18451435791565657e+08 + + + + 4 + + 71 + + 3 + 49 + 67 + 0 + + 23 + 4 + 1.13100000000000000e+03 + 1.00000000000000000e+03 + 994247 + 0 + 0 + 2600000 + 3.98655546875000000e+04 + -8.63781860351562500e+02 + 5.24684982299804688e+01 + 1.09281750951009121e+03 + -3.54128275530727289e+05 + 4.08304036132904002e-01 + 133922883 + 1 + 1 + 1 + 518451429 + 2.12256989876578376e+07 + 5.18451500000000000e+05 + 1 + 5.18451429198689222e+08 + + + + 5 + + 71 + + 3 + 49 + 67 + 0 + + 2 + 5 + 5.38000000000000000e+02 + 1.75000000000000000e+03 + 4917751 + 0 + 0 + 2600000 + -4.72456406250000000e+04 + -2.63723022460937500e+02 + 4.89446220397949219e+01 + 1.83319645690917969e+03 + -5.72184006019302527e+05 + 5.89544135488722532e-01 + 133922337 + 1 + 1 + 1 + 518451430 + 2.08629709015843943e+07 + 5.18451500000000000e+05 + 1 + 5.18451430408619881e+08 + + + + 6 + + 71 + + 3 + 49 + 67 + 0 + + 17 + 6 + 2.21000000000000000e+02 + 2.50000000000000000e+02 + 514377 + 0 + 0 + 2600000 + 4.27717460937500000e+04 + -9.45822082519531250e+02 + 5.38986015319824219e+01 + 2.73018497467041016e+02 + -9.09813659855529113e+04 + 6.57473345280777721e-01 + 133923172 + 1 + 1 + 1 + 518451440 + 1.79613337841309197e+07 + 5.18451500000000000e+05 + 1 + 5.18451440087439477e+08 + + + + 7 + + 71 + + 3 + 49 + 67 + 0 + + 9 + 7 + 1.56900000000000000e+03 + 2.25000000000000000e+03 + 7365787 + 0 + 0 + 2600000 + -3.96159960937500000e+04 + -5.03847460937500000e+03 + 5.33032913208007812e+01 + 2.30021731185913086e+03 + -7.04913853936602012e+05 + 3.21518194999043772e-01 + 133922169 + 1 + 1 + 1 + 518451430 + 2.08435687343175523e+07 + 5.18451500000000000e+05 + 1 + 5.18451430473338544e+08 + + + + 8 + + 71 + + 3 + 49 + 67 + 0 + + 10 + 8 + 2.12600000000000000e+03 + 2.75000000000000000e+03 + 2173576 + 0 + 0 + 2600000 + 4.00322539062500000e+04 + -3.88590087890625000e+02 + 4.85561523437500000e+01 + 2.81225794982910156e+03 + -8.99142229977656389e+05 + 1.02370741655249731e-01 + 133922664 + 1 + 1 + 1 + 518451438 + 1.85022797143675610e+07 + 5.18451500000000000e+05 + 1 + 5.18451438283038080e+08 + + + + 9 + + 71 + + 3 + 49 + 67 + 0 + + 12 + 9 + 2.13000000000000000e+02 + 3.00000000000000000e+03 + 7464974 + 0 + 0 + 2600000 + -4.03654140625000000e+04 + 3.92351245117187500e+03 + 5.17314453125000000e+01 + 3.03019989013671875e+03 + -9.28340507655202877e+05 + 5.73995602361264901e-01 + 133923741 + 1 + 1 + 1 + 518451427 + 2.19242346189941987e+07 + 5.18451500000000000e+05 + 1 + 5.18451426868625164e+08 + + + + 10 + + 71 + + 3 + 49 + 67 + 0 + + 6 + 10 + 4.70000000000000000e+01 + 5.00000000000000000e+02 + 1859813 + 0 + 0 + 2600000 + 3.87814335937500000e+04 + 2.13637329101562500e+03 + 6.00463027954101562e+01 + 5.54514957427978516e+02 + -1.78723083774703584e+05 + 3.47952294631795667e-01 + 133924211 + 1 + 1 + 1 + 518451439 + 1.83808922785463184e+07 + 5.18451500000000000e+05 + 1 + 5.18451438687942982e+08 + + + + diff --git a/src/tests/signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin b/src/tests/signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin new file mode 100644 index 000000000..bba434e4c Binary files /dev/null and b/src/tests/signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin differ diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index 25afe3bd8..66a8ab7de 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,44 +24,60 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#include "agnss_ref_location.h" +#include "agnss_ref_time.h" +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "galileo_navigation_message.h" +#include "gps_acq_assist.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include "gps_ephemeris.h" +#include "gps_navigation_message.h" +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include "concurrent_queue.h" -#include "concurrent_map.h" -#include "gps_navigation_message.h" -#include "gps_ephemeris.h" -#include "gps_cnav_ephemeris.h" -#include "gps_cnav_iono.h" -#include "gps_acq_assist.h" -#include "gps_ref_location.h" -#include "gps_ref_time.h" -#include "galileo_navigation_message.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_telemetry_data.h" -#include "sbas_ephemeris.h" -#include "sbas_satellite_correction.h" + concurrent_queue global_gps_acq_assist_queue; concurrent_map global_gps_acq_assist_map; +using google::LogMessage; + +DECLARE_string(log_dir); int main(int argc, char **argv) { google::ParseCommandLineFlags(&argc, &argv, true); - testing::InitGoogleTest(&argc, argv); + try + { + testing::InitGoogleTest(&argc, argv); + } + catch (...) + { + } // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest google::InitGoogleLogging(argv[0]); - return RUN_ALL_TESTS(); + int res = 0; + try + { + res = RUN_ALL_TESTS(); + } + catch (...) + { + LOG(WARNING) << "Unexpected catch"; + } + google::ShutDownCommandLineFlags(); + return res; } diff --git a/src/tests/system-tests/libs/CMakeLists.txt b/src/tests/system-tests/libs/CMakeLists.txt new file mode 100644 index 000000000..178f83479 --- /dev/null +++ b/src/tests/system-tests/libs/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + + +set(SYSTEM_TESTING_LIB_SOURCES + spirent_motion_csv_dump_reader.cc + rtklib_solver_dump_reader.cc +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} + ${ARMADILLO_INCLUDE_DIRS} +) + +file(GLOB SYSTEM_TESTING_LIB_HEADERS "*.h") +list(SORT SYSTEM_TESTING_LIB_HEADERS) + +add_library(system_testing_lib + ${SYSTEM_TESTING_LIB_SOURCES} + ${SYSTEM_TESTING_LIB_HEADERS} +) + +source_group(Headers FILES ${SYSTEM_TESTING_LIB_HEADERS}) + +if(NOT MATIO_FOUND) + add_dependencies(system_testing_lib + armadillo-${armadillo_RELEASE} + matio-${GNSSSDR_MATIO_LOCAL_VERSION} + ) +else() + add_dependencies(system_testing_lib armadillo-${armadillo_RELEASE}) +endif() diff --git a/src/tests/system-tests/libs/position_test_flags.h b/src/tests/system-tests/libs/position_test_flags.h new file mode 100644 index 000000000..1ebe296e6 --- /dev/null +++ b/src/tests/system-tests/libs/position_test_flags.h @@ -0,0 +1,50 @@ +/*! + * \file signal_generator_flags.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_POSITION_TEST_FLAGS_H_ +#define GNSS_SDR_POSITION_TEST_FLAGS_H_ + +#include +#include + +DEFINE_string(config_file_ptest, std::string(""), "File containing the configuration parameters for the position test."); +DEFINE_bool(plot_position_test, false, "Plots results of with gnuplot"); +DEFINE_bool(static_scenario, true, "Compute figures of merit for static user position (DRMS, CEP, etc..)"); +DEFINE_bool(use_ref_motion_file, false, "Enable or disable the use of a reference file containing the true receiver position, velocity and acceleration."); +DEFINE_int32(ref_motion_file_type, 1, "Type of reference motion file: 1- Spirent CSV motion file"); +DEFINE_string(ref_motion_filename, std::string("motion.csv"), "Path and filename for the reference motion file"); +DEFINE_string(pvt_solver_dump_filename, std::string("PVT.dat"), "Path and filename for the PVT solver binary dump file"); +DEFINE_double(static_2D_error_m, 2.0, "Static scenario 2D (East, North) positioning error threshold [meters]"); +DEFINE_double(static_3D_error_m, 5.0, "Static scenario 3D (East, North, Up) positioning error threshold [meters]"); +DEFINE_double(accuracy_CEP, 2.0, "Static scenario 2D (East, North) accuracy Circular Error Position (CEP) threshold [meters]"); +DEFINE_double(precision_SEP, 10.0, "Static scenario 3D (East, North, Up) precision Spherical Error Position (SEP) threshold [meters]"); +DEFINE_double(dynamic_3D_position_RMSE, 10.0, "Dynamic scenario 3D (ECEF) accuracy RMSE threshold [meters]"); +DEFINE_double(dynamic_3D_velocity_RMSE, 5.0, "Dynamic scenario 3D (ECEF) velocity accuracy RMSE threshold [meters/second]"); +#endif diff --git a/src/tests/system-tests/libs/rtklib_solver_dump_reader.cc b/src/tests/system-tests/libs/rtklib_solver_dump_reader.cc new file mode 100644 index 000000000..a2c25debc --- /dev/null +++ b/src/tests/system-tests/libs/rtklib_solver_dump_reader.cc @@ -0,0 +1,133 @@ +/*! + * \file rtklib_solver_dump_reader.cc + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "rtklib_solver_dump_reader.h" +#include +#include + +bool rtklib_solver_dump_reader::read_binary_obs() +{ + try + { + d_dump_file.read(reinterpret_cast(&TOW_at_current_symbol_ms), sizeof(uint32_t)); + d_dump_file.read(reinterpret_cast(&week), sizeof(uint32_t)); + d_dump_file.read(reinterpret_cast(&RX_time), sizeof(double)); + d_dump_file.read(reinterpret_cast(&clk_offset_s), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[0]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[1]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[2]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[3]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[4]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&rr[5]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[0]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[1]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[2]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[3]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[4]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&qr[5]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&latitude), sizeof(double)); + d_dump_file.read(reinterpret_cast(&longitude), sizeof(double)); + d_dump_file.read(reinterpret_cast(&height), sizeof(double)); + d_dump_file.read(reinterpret_cast(&ns), sizeof(uint8_t)); + d_dump_file.read(reinterpret_cast(&status), sizeof(uint8_t)); + d_dump_file.read(reinterpret_cast(&type), sizeof(uint8_t)); + d_dump_file.read(reinterpret_cast(&AR_ratio), sizeof(float)); + d_dump_file.read(reinterpret_cast(&AR_thres), sizeof(float)); + d_dump_file.read(reinterpret_cast(&dop[0]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&dop[1]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&dop[2]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&dop[3]), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + return false; + } + return true; +} + + +bool rtklib_solver_dump_reader::restart() +{ + if (d_dump_file.is_open()) + { + d_dump_file.clear(); + d_dump_file.seekg(0, std::ios::beg); + return true; + } + return false; +} + + +int64_t rtklib_solver_dump_reader::num_epochs() +{ + std::ifstream::pos_type size; + int epoch_size_bytes = 2 * sizeof(uint32_t) + 21 * sizeof(double) + 3 * sizeof(uint8_t) + 2 * sizeof(float); + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + if (tmpfile.is_open()) + { + size = tmpfile.tellg(); + int64_t nepoch = size / epoch_size_bytes; + return nepoch; + } + return 0; +} + + +bool rtklib_solver_dump_reader::open_obs_file(std::string out_file) +{ + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); + return true; + } + catch (const std::ifstream::failure &e) + { + std::cout << "Problem opening rtklib_solver dump Log file: " << d_dump_filename.c_str() << std::endl; + return false; + } + } + else + { + return false; + } +} + + +rtklib_solver_dump_reader::~rtklib_solver_dump_reader() +{ + if (d_dump_file.is_open() == true) + { + d_dump_file.close(); + } +} diff --git a/src/tests/system-tests/libs/rtklib_solver_dump_reader.h b/src/tests/system-tests/libs/rtklib_solver_dump_reader.h new file mode 100644 index 000000000..5006482dd --- /dev/null +++ b/src/tests/system-tests/libs/rtklib_solver_dump_reader.h @@ -0,0 +1,88 @@ +/*! + * \file rtklib_solver_dump_reader.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_RTKLIB_SOLVER_DUMP_READER_H +#define GNSS_SDR_RTKLIB_SOLVER_DUMP_READER_H + +#include +#include +#include +#include + +class rtklib_solver_dump_reader +{ +public: + ~rtklib_solver_dump_reader(); + bool read_binary_obs(); + bool restart(); + int64_t num_epochs(); + bool open_obs_file(std::string out_file); + + // rtklib_solver dump variables + // TOW + uint32_t TOW_at_current_symbol_ms; + // WEEK + uint32_t week; + // PVT GPS time + double RX_time; + // User clock offset [s] + double clk_offset_s; + // ECEF POS X,Y,X [m] + ECEF VEL X,Y,X [m/s] (6 x double) + double rr[6]; + // position variance/covariance (m^2) {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} (6 x double) + double qr[6]; + + // GEO user position Latitude [deg] + double latitude; + // GEO user position Longitude [deg] + double longitude; + // GEO user position Height [m] + double height; + + // NUMBER OF VALID SATS + uint8_t ns; + // RTKLIB solution status + uint8_t status; + // RTKLIB solution type (0:xyz-ecef,1:enu-baseline) + uint8_t type; + // AR ratio factor for validation + float AR_ratio; + // AR ratio threshold for validation + float AR_thres; + + // GDOP / PDOP / HDOP / VDOP + double dop[4]; + +private: + std::string d_dump_filename; + std::ifstream d_dump_file; +}; + +#endif //GNSS_SDR_RTKLIB_SOLVER_DUMP_READER_H diff --git a/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.cc b/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.cc new file mode 100644 index 000000000..1082fb233 --- /dev/null +++ b/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.cc @@ -0,0 +1,245 @@ +/*! + * \file spirent_motion_csv_dump_reader.cc + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "spirent_motion_csv_dump_reader.h" +#include +#include +#include + + +spirent_motion_csv_dump_reader::spirent_motion_csv_dump_reader() +{ + header_lines = 2; + TOW_ms = 0.0; + Pos_X = 0.0; + Pos_Y = 0.0; + Pos_Z = 0.0; + Vel_X = 0.0; + Vel_Y = 0.0; + Vel_Z = 0.0; + Acc_X = 0.0; + Acc_Y = 0.0; + Acc_Z = 0.0; + Jerk_X = 0.0; + Jerk_Y = 0.0; + Jerk_Z = 0.0; + Lat = 0.0; + Long = 0.0; + Height = 0.0; + Heading = 0.0; + Elevation = 0.0; + Bank = 0.0; + Ang_vel_X = 0.0; + Ang_vel_Y = 0.0; + Ang_vel_Z = 0.0; + Ang_acc_X = 0.0; + Ang_acc_Y = 0.0; + Ang_acc_Z = 0.0; + Ant1_Pos_X = 0.0; + Ant1_Pos_Y = 0.0; + Ant1_Pos_Z = 0.0; + Ant1_Vel_X = 0.0; + Ant1_Vel_Y = 0.0; + Ant1_Vel_Z = 0.0; + Ant1_Acc_X = 0.0; + Ant1_Acc_Y = 0.0; + Ant1_Acc_Z = 0.0; + Ant1_Lat = 0.0; + Ant1_Long = 0.0; + Ant1_Height = 0.0; + Ant1_DOP = 0.0; +} + + +spirent_motion_csv_dump_reader::~spirent_motion_csv_dump_reader() +{ + if (d_dump_file.is_open() == true) + { + d_dump_file.close(); + } +} + + +bool spirent_motion_csv_dump_reader::read_csv_obs() +{ + try + { + std::vector vec; + std::string line; + if (getline(d_dump_file, line)) + { + boost::tokenizer> tk( + line, boost::escaped_list_separator('\\', ',', '\"')); + for (boost::tokenizer>::iterator i( + tk.begin()); + i != tk.end(); ++i) + { + try + { + vec.push_back(std::stod(*i)); + } + catch (const std::exception &ex) + { + vec.push_back(0.0); + } + } + parse_vector(vec); + } + } + catch (const std::ifstream::failure &e) + { + return false; + } + return true; +} + + +bool spirent_motion_csv_dump_reader::parse_vector(std::vector &vec) +{ + try + { + int n = 0; + TOW_ms = vec.at(n++); + Pos_X = vec.at(n++); + Pos_Y = vec.at(n++); + Pos_Z = vec.at(n++); + Vel_X = vec.at(n++); + Vel_Y = vec.at(n++); + Vel_Z = vec.at(n++); + Acc_X = vec.at(n++); + Acc_Y = vec.at(n++); + Acc_Z = vec.at(n++); + Jerk_X = vec.at(n++); + Jerk_Y = vec.at(n++); + Jerk_Z = vec.at(n++); + Lat = vec.at(n++); + Long = vec.at(n++); + Height = vec.at(n++); + Heading = vec.at(n++); + Elevation = vec.at(n++); + Bank = vec.at(n++); + Ang_vel_X = vec.at(n++); + Ang_vel_Y = vec.at(n++); + Ang_vel_Z = vec.at(n++); + Ang_acc_X = vec.at(n++); + Ang_acc_Y = vec.at(n++); + Ang_acc_Z = vec.at(n++); + Ant1_Pos_X = vec.at(n++); + Ant1_Pos_Y = vec.at(n++); + Ant1_Pos_Z = vec.at(n++); + Ant1_Vel_X = vec.at(n++); + Ant1_Vel_Y = vec.at(n++); + Ant1_Vel_Z = vec.at(n++); + Ant1_Acc_X = vec.at(n++); + Ant1_Acc_Y = vec.at(n++); + Ant1_Acc_Z = vec.at(n++); + Ant1_Lat = vec.at(n++); + Ant1_Long = vec.at(n++); + Ant1_Height = vec.at(n++); + Ant1_DOP = vec.at(n++); + return true; + } + catch (const std::exception &ex) + { + return false; + } +} + + +bool spirent_motion_csv_dump_reader::restart() +{ + if (d_dump_file.is_open()) + { + d_dump_file.clear(); + d_dump_file.seekg(0, std::ios::beg); + std::string line; + for (int n = 0; n < header_lines; n++) + { + getline(d_dump_file, line); + } + return true; + } + return false; +} + + +int64_t spirent_motion_csv_dump_reader::num_epochs() +{ + int64_t nepoch = 0LL; + std::string line; + std::ifstream tmpfile(d_dump_filename.c_str()); + if (tmpfile.is_open()) + { + while (std::getline(tmpfile, line)) + { + ++nepoch; + } + return nepoch - header_lines; + } + return 0; +} + + +bool spirent_motion_csv_dump_reader::open_obs_file(std::string out_file) +{ + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str()); + std::string line; + for (int n = 0; n < header_lines; n++) + { + getline(d_dump_file, line); + } + return true; + } + catch (const std::ifstream::failure &e) + { + std::cout << "Problem opening Spirent CSV dump Log file: " << d_dump_filename.c_str() << std::endl; + return false; + } + } + else + { + return false; + } +} + + +void spirent_motion_csv_dump_reader::close_obs_file() +{ + if (d_dump_file.is_open() == false) + { + d_dump_file.close(); + } +} diff --git a/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.h b/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.h new file mode 100644 index 000000000..b08beb6e0 --- /dev/null +++ b/src/tests/system-tests/libs/spirent_motion_csv_dump_reader.h @@ -0,0 +1,97 @@ +/*! + * \file spirent_motion_csv_dump_reader.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_SPIRENT_MOTION_CSV_DUMP_READER_H +#define GNSS_SDR_SPIRENT_MOTION_CSV_DUMP_READER_H + +#include +#include +#include +#include + +class spirent_motion_csv_dump_reader +{ +public: + spirent_motion_csv_dump_reader(); + ~spirent_motion_csv_dump_reader(); + bool read_csv_obs(); + bool restart(); + int64_t num_epochs(); + bool open_obs_file(std::string out_file); + void close_obs_file(); + + int header_lines; + // dump variables + double TOW_ms; + double Pos_X; + double Pos_Y; + double Pos_Z; + double Vel_X; + double Vel_Y; + double Vel_Z; + double Acc_X; + double Acc_Y; + double Acc_Z; + double Jerk_X; + double Jerk_Y; + double Jerk_Z; + double Lat; + double Long; + double Height; + double Heading; + double Elevation; + double Bank; + double Ang_vel_X; + double Ang_vel_Y; + double Ang_vel_Z; + double Ang_acc_X; + double Ang_acc_Y; + double Ang_acc_Z; + double Ant1_Pos_X; + double Ant1_Pos_Y; + double Ant1_Pos_Z; + double Ant1_Vel_X; + double Ant1_Vel_Y; + double Ant1_Vel_Z; + double Ant1_Acc_X; + double Ant1_Acc_Y; + double Ant1_Acc_Z; + double Ant1_Lat; + double Ant1_Long; + double Ant1_Height; + double Ant1_DOP; + +private: + std::string d_dump_filename; + std::ifstream d_dump_file; + bool parse_vector(std::vector &vec); +}; + +#endif // GNSS_SDR_SPIRENT_MOTION_CSV_DUMP_READER_H diff --git a/src/tests/system-tests/obs_gps_l1_system_test.cc b/src/tests/system-tests/obs_gps_l1_system_test.cc deleted file mode 100644 index 4eff21d75..000000000 --- a/src/tests/system-tests/obs_gps_l1_system_test.cc +++ /dev/null @@ -1,722 +0,0 @@ -/*! - * \file obs_gps_l1_system_test.cc - * \brief This class implements a test for the validation of generated observables. - * \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "RinexUtilities.hpp" -#include "Rinex3ObsBase.hpp" -#include "Rinex3ObsData.hpp" -#include "Rinex3ObsHeader.hpp" -#include "Rinex3ObsStream.hpp" -#include "concurrent_map.h" -#include "concurrent_queue.h" -#include "control_thread.h" -#include "in_memory_configuration.h" -#include "signal_generator_flags.h" - - -// For GPS NAVIGATION (L1) -concurrent_queue global_gps_acq_assist_queue; -concurrent_map global_gps_acq_assist_map; - -class Obs_Gps_L1_System_Test: public ::testing::Test -{ -public: - std::string generator_binary; - std::string p1; - std::string p2; - std::string p3; - std::string p4; - std::string p5; - - const double baseband_sampling_freq = 2.6e6; - - std::string filename_rinex_obs = FLAGS_filename_rinex_obs; - std::string filename_raw_data = FLAGS_filename_raw_data; - - int configure_generator(); - int generate_signal(); - int configure_receiver(); - int run_receiver(); - void check_results(); - bool check_valid_rinex_nav(std::string filename); // return true if the file is a valid Rinex navigation file. - bool check_valid_rinex_obs(std::string filename); // return true if the file is a valid Rinex observation file. - double compute_stdev(const std::vector & vec); - - std::shared_ptr config; - std::string generated_rinex_obs; -}; - - -bool Obs_Gps_L1_System_Test::check_valid_rinex_nav(std::string filename) -{ - bool res = false; - res = gpstk::isRinexNavFile(filename); - return res; -} - - -double Obs_Gps_L1_System_Test::compute_stdev(const std::vector & vec) -{ - double sum__ = std::accumulate(vec.begin(), vec.end(), 0.0); - double mean__ = sum__ / vec.size(); - double accum__ = 0.0; - std::for_each (std::begin(vec), std::end(vec), [&](const double d) { - accum__ += (d - mean__) * (d - mean__); - }); - double stdev__ = std::sqrt(accum__ / (vec.size() - 1)); - return stdev__; -} - - -bool Obs_Gps_L1_System_Test::check_valid_rinex_obs(std::string filename) -{ - bool res = false; - res = gpstk::isRinexObsFile(filename); - return res; -} - - -int Obs_Gps_L1_System_Test::configure_generator() -{ - // Configure signal generator - generator_binary = FLAGS_generator_binary; - - p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; - if(FLAGS_dynamic_position.empty()) - { - p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(std::min(FLAGS_duration * 10, 3000)); - if(FLAGS_duration > 300) std::cout << "WARNING: Duration has been set to its maximum value of 300 s" << std::endl; - } - else - { - p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); - } - p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output - p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples - p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] - return 0; -} - - -int Obs_Gps_L1_System_Test::generate_signal() -{ - pid_t wait_result; - int child_status; - - char *const parmList[] = { &generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL }; - - int pid; - if ((pid = fork()) == -1) - perror("fork error"); - else if (pid == 0) - { - execv(&generator_binary[0], parmList); - std::cout << "Return not expected. Must be an execv error." << std::endl; - std::terminate(); - } - - wait_result = waitpid(pid, &child_status, 0); - if (wait_result == -1) perror("waitpid error"); - EXPECT_EQ(true, check_valid_rinex_obs(filename_rinex_obs)); - std::cout << "Signal and Observables RINEX files created." << std::endl; - return 0; -} - - -int Obs_Gps_L1_System_Test::configure_receiver() -{ - config = std::make_shared(); - - const int sampling_rate_internal = baseband_sampling_freq; - - const int number_of_taps = 11; - const int number_of_bands = 2; - const float band1_begin = 0.0; - const float band1_end = 0.48; - const float band2_begin = 0.52; - const float band2_end = 1.0; - const float ampl1_begin = 1.0; - const float ampl1_end = 1.0; - const float ampl2_begin = 0.0; - const float ampl2_end = 0.0; - const float band1_error = 1.0; - const float band2_error = 1.0; - const int grid_density = 16; - const int decimation_factor = 1; - - const float zero = 0.0; - const int number_of_channels = 8; - const int in_acquisition = 1; - - const float threshold = 0.01; - const float doppler_max = 8000.0; - const float doppler_step = 500.0; - const int max_dwells = 1; - const int tong_init_val = 2; - const int tong_max_val = 10; - const int tong_max_dwells = 30; - const int coherent_integration_time_ms = 1; - - const float pll_bw_hz = 30.0; - const float dll_bw_hz = 4.0; - const float early_late_space_chips = 0.5; - const float pll_bw_narrow_hz = 20.0; - const float dll_bw_narrow_hz = 2.0; - const int extend_correlation_ms = 1; - - const int display_rate_ms = 500; - const int output_rate_ms = 1000; - const int averaging_depth = 1; - - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(sampling_rate_internal)); - - // Set the assistance system parameters - config->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); - config->set_property("GNSS-SDR.SUPL_gps_enabled", "false"); - config->set_property("GNSS-SDR.SUPL_gps_ephemeris_server", "supl.google.com"); - config->set_property("GNSS-SDR.SUPL_gps_ephemeris_port", std::to_string(7275)); - config->set_property("GNSS-SDR.SUPL_gps_acquisition_server", "supl.google.com"); - config->set_property("GNSS-SDR.SUPL_gps_acquisition_port", std::to_string(7275)); - config->set_property("GNSS-SDR.SUPL_MCC", std::to_string(244)); - config->set_property("GNSS-SDR.SUPL_MNS", std::to_string(5)); - config->set_property("GNSS-SDR.SUPL_LAC", "0x59e2"); - config->set_property("GNSS-SDR.SUPL_CI", "0x31b0"); - - // Set the Signal Source - config->set_property("SignalSource.implementation", "File_Signal_Source"); - config->set_property("SignalSource.filename", "./" + filename_raw_data); - config->set_property("SignalSource.sampling_frequency", std::to_string(sampling_rate_internal)); - config->set_property("SignalSource.item_type", "ibyte"); - config->set_property("SignalSource.samples", std::to_string(zero)); - - // Set the Signal Conditioner - config->set_property("SignalConditioner.implementation", "Signal_Conditioner"); - config->set_property("DataTypeAdapter.implementation", "Ibyte_To_Complex"); - config->set_property("InputFilter.implementation", "Fir_Filter"); - config->set_property("InputFilter.dump", "false"); - config->set_property("InputFilter.input_item_type", "gr_complex"); - config->set_property("InputFilter.output_item_type", "gr_complex"); - config->set_property("InputFilter.taps_item_type", "float"); - config->set_property("InputFilter.number_of_taps", std::to_string(number_of_taps)); - config->set_property("InputFilter.number_of_bands", std::to_string(number_of_bands)); - config->set_property("InputFilter.band1_begin", std::to_string(band1_begin)); - config->set_property("InputFilter.band1_end", std::to_string(band1_end)); - config->set_property("InputFilter.band2_begin", std::to_string(band2_begin)); - config->set_property("InputFilter.band2_end", std::to_string(band2_end)); - config->set_property("InputFilter.ampl1_begin", std::to_string(ampl1_begin)); - config->set_property("InputFilter.ampl1_end", std::to_string(ampl1_end)); - config->set_property("InputFilter.ampl2_begin", std::to_string(ampl2_begin)); - config->set_property("InputFilter.ampl2_end", std::to_string(ampl2_end)); - config->set_property("InputFilter.band1_error", std::to_string(band1_error)); - config->set_property("InputFilter.band2_error", std::to_string(band2_error)); - config->set_property("InputFilter.filter_type", "bandpass"); - config->set_property("InputFilter.grid_density", std::to_string(grid_density)); - config->set_property("InputFilter.sampling_frequency", std::to_string(sampling_rate_internal)); - config->set_property("InputFilter.IF", std::to_string(zero)); - config->set_property("Resampler.implementation", "Pass_Through"); - config->set_property("Resampler.dump", "false"); - config->set_property("Resampler.item_type", "gr_complex"); - config->set_property("Resampler.sample_freq_in", std::to_string(sampling_rate_internal)); - config->set_property("Resampler.sample_freq_out", std::to_string(sampling_rate_internal)); - - // Set the number of Channels - config->set_property("Channels_1C.count", std::to_string(number_of_channels)); - config->set_property("Channels.in_acquisition", std::to_string(in_acquisition)); - config->set_property("Channel.signal", "1C"); - - // Set Acquisition - config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); - config->set_property("Acquisition_1C.item_type", "gr_complex"); - config->set_property("Acquisition_1C.if", std::to_string(zero)); - config->set_property("Acquisition_1C.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms)); - config->set_property("Acquisition_1C.threshold", std::to_string(threshold)); - config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max)); - config->set_property("Acquisition_1C.doppler_step", std::to_string(doppler_step)); - config->set_property("Acquisition_1C.bit_transition_flag", "false"); - config->set_property("Acquisition_1C.max_dwells", std::to_string(max_dwells)); - config->set_property("Acquisition_1C.tong_init_val", std::to_string(tong_init_val)); - config->set_property("Acquisition_1C.tong_max_val", std::to_string(tong_max_val)); - config->set_property("Acquisition_1C.tong_max_dwells", std::to_string(tong_max_dwells)); - - // Set Tracking - config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); - //config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_C_Aid_Tracking"); - config->set_property("Tracking_1C.item_type", "gr_complex"); - config->set_property("Tracking_1C.if", std::to_string(zero)); - config->set_property("Tracking_1C.dump", "false"); - config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); - config->set_property("Tracking_1C.pll_bw_hz", std::to_string(pll_bw_hz)); - config->set_property("Tracking_1C.dll_bw_hz", std::to_string(dll_bw_hz)); - config->set_property("Tracking_1C.early_late_space_chips", std::to_string(early_late_space_chips)); - - config->set_property("Tracking_1C.pll_bw_narrow_hz", std::to_string(pll_bw_narrow_hz)); - config->set_property("Tracking_1C.dll_bw_narrow_hz", std::to_string(dll_bw_narrow_hz)); - config->set_property("Tracking_1C.extend_correlation_ms", std::to_string(extend_correlation_ms)); - - // Set Telemetry - config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C.dump", "false"); - config->set_property("TelemetryDecoder_1C.decimation_factor", std::to_string(decimation_factor)); - - // Set Observables - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); - config->set_property("Observables.dump", "false"); - config->set_property("Observables.dump_filename", "./observables.dat"); - config->set_property("Observables.averaging_depth", std::to_string(100)); - - // Set PVT - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); - config->set_property("PVT.averaging_depth", std::to_string(averaging_depth)); - config->set_property("PVT.flag_averaging", "true"); - config->set_property("PVT.output_rate_ms", std::to_string(output_rate_ms)); - config->set_property("PVT.display_rate_ms", std::to_string(display_rate_ms)); - config->set_property("PVT.dump_filename", "./PVT"); - config->set_property("PVT.nmea_dump_filename", "./gnss_sdr_pvt.nmea"); - config->set_property("PVT.flag_nmea_tty_port", "false"); - config->set_property("PVT.nmea_dump_devname", "/dev/pts/4"); - config->set_property("PVT.flag_rtcm_server", "false"); - config->set_property("PVT.flag_rtcm_tty_port", "false"); - config->set_property("PVT.rtcm_dump_devname", "/dev/pts/1"); - config->set_property("PVT.dump", "false"); - config->set_property("PVT.rinex_version", std::to_string(2)); - - return 0; -} - - -int Obs_Gps_L1_System_Test::run_receiver() -{ - std::shared_ptr control_thread; - control_thread = std::make_shared(config); - // start receiver - try - { - control_thread->run(); - } - catch( boost::exception & e ) - { - std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } - // Get the name of the RINEX obs file generated by the receiver - FILE *fp; - std::string argum2 = std::string("/bin/ls *O | grep GSDR | tail -1"); - char buffer[1035]; - fp = popen(&argum2[0], "r"); - if (fp == NULL) - { - std::cout << "Failed to run command: " << argum2 << std::endl; - return -1; - } - char * without_trailing = (char*)"0"; - while (fgets(buffer, sizeof(buffer), fp) != NULL) - { - std::string aux = std::string(buffer); - without_trailing = strtok(&aux[0], "\n"); - } - generated_rinex_obs = std::string(without_trailing); - pclose(fp); - - return 0; -} - - -void Obs_Gps_L1_System_Test::check_results() -{ - std::vector> > pseudorange_ref(33); - std::vector> > carrierphase_ref(33); - std::vector> > doppler_ref(33); - - std::vector> > pseudorange_meas(33); - std::vector> > carrierphase_meas(33); - std::vector> > doppler_meas(33); - - // Open and read reference RINEX observables file - try - { - gpstk::Rinex3ObsStream r_ref(FLAGS_filename_rinex_obs); - r_ref.exceptions(std::ios::failbit); - gpstk::Rinex3ObsData r_ref_data; - gpstk::Rinex3ObsHeader r_ref_header; - - gpstk::RinexDatum dataobj; - - r_ref >> r_ref_header; - - while (r_ref >> r_ref_data) - { - for (int myprn = 1; myprn < 33; myprn++) - { - gpstk::SatID prn( myprn, gpstk::SatID::systemGPS ); - gpstk::CommonTime time = r_ref_data.time; - double sow(static_cast(time).sow); - - gpstk::Rinex3ObsData::DataMap::iterator pointer = r_ref_data.obs.find(prn); - if( pointer == r_ref_data.obs.end() ) - { - // PRN not present; do nothing - } - else - { - dataobj = r_ref_data.getObs(prn, "C1C", r_ref_header); - double P1 = dataobj.data; - std::pair pseudo(sow,P1); - pseudorange_ref.at(myprn).push_back(pseudo); - - dataobj = r_ref_data.getObs(prn, "L1C", r_ref_header); - double L1 = dataobj.data; - std::pair carrier(sow, L1); - carrierphase_ref.at(myprn).push_back(carrier); - - dataobj = r_ref_data.getObs(prn, "D1C", r_ref_header); - double D1 = dataobj.data; - std::pair doppler(sow, D1); - doppler_ref.at(myprn).push_back(doppler); - } // End of 'if( pointer == roe.obs.end() )' - } // end for - } // end while - } // End of 'try' block - catch(gpstk::FFStreamError& e) - { - std::cout << e; - exit(1); - } - catch(gpstk::Exception& e) - { - std::cout << e; - exit(1); - } - catch (...) - { - std::cout << "unknown error. I don't feel so well..." << std::endl; - exit(1); - } - - try - { - std::string arg2_gen = std::string("./") + generated_rinex_obs; - gpstk::Rinex3ObsStream r_meas(arg2_gen); - r_meas.exceptions(std::ios::failbit); - gpstk::Rinex3ObsData r_meas_data; - gpstk::Rinex3ObsHeader r_meas_header; - gpstk::RinexDatum dataobj; - - r_meas >> r_meas_header; - - while (r_meas >> r_meas_data) - { - for (int myprn = 1; myprn < 33; myprn++) - { - gpstk::SatID prn( myprn, gpstk::SatID::systemGPS ); - gpstk::CommonTime time = r_meas_data.time; - double sow(static_cast(time).sow); - - gpstk::Rinex3ObsData::DataMap::iterator pointer = r_meas_data.obs.find(prn); - if( pointer == r_meas_data.obs.end() ) - { - // PRN not present; do nothing - } - else - { - dataobj = r_meas_data.getObs(prn, "C1C", r_meas_header); - double P1 = dataobj.data; - std::pair pseudo(sow, P1); - pseudorange_meas.at(myprn).push_back(pseudo); - - dataobj = r_meas_data.getObs(prn, "L1C", r_meas_header); - double L1 = dataobj.data; - std::pair carrier(sow, L1); - carrierphase_meas.at(myprn).push_back(carrier); - - dataobj = r_meas_data.getObs(prn, "D1C", r_meas_header); - double D1 = dataobj.data; - std::pair doppler(sow, D1); - doppler_meas.at(myprn).push_back(doppler); - } // End of 'if( pointer == roe.obs.end() )' - } // end for - } // end while - } // End of 'try' block - catch(gpstk::FFStreamError& e) - { - std::cout << e; - exit(1); - } - catch(gpstk::Exception& e) - { - std::cout << e; - exit(1); - } - catch (...) - { - std::cout << "unknown error. I don't feel so well..." << std::endl; - exit(1); - } - - // Time alignment - std::vector> > pseudorange_ref_aligned(33); - std::vector> > carrierphase_ref_aligned(33); - std::vector> > doppler_ref_aligned(33); - - std::vector> >::iterator iter; - std::vector>::iterator it; - std::vector>::iterator it2; - - std::vector> pr_diff(33); - std::vector> cp_diff(33); - std::vector> doppler_diff(33); - - std::vector>::iterator iter_diff; - std::vector::iterator iter_v; - - int prn_id = 0; - for(iter = pseudorange_ref.begin(); iter != pseudorange_ref.end(); iter++) - { - for(it = iter->begin(); it != iter->end(); it++) - { - // If a measure exists for this sow, store it - for(it2 = pseudorange_meas.at(prn_id).begin(); it2 != pseudorange_meas.at(prn_id).end(); it2++) - { - if(std::abs(it->first - it2->first) < 0.01) // store measures closer than 10 ms. - { - pseudorange_ref_aligned.at(prn_id).push_back(*it); - pr_diff.at(prn_id).push_back(it->second - it2->second ); - //std::cout << "Sat " << prn_id << ": " << "PR_ref=" << it->second << " PR_meas=" << it2->second << " Diff:" << it->second - it2->second << std::endl; - } - } - } - prn_id++; - } - - prn_id = 0; - for(iter = carrierphase_ref.begin(); iter != carrierphase_ref.end(); iter++) - { - for(it = iter->begin(); it != iter->end(); it++) - { - // If a measure exists for this sow, store it - for(it2 = carrierphase_meas.at(prn_id).begin(); it2 != carrierphase_meas.at(prn_id).end(); it2++) - { - if(std::abs(it->first - it2->first) < 0.01) // store measures closer than 10 ms. - { - carrierphase_ref_aligned.at(prn_id).push_back(*it); - cp_diff.at(prn_id).push_back(it->second - it2->second ); - // std::cout << "Sat " << prn_id << ": " << "Carrier_ref=" << it->second << " Carrier_meas=" << it2->second << " Diff:" << it->second - it2->second << std::endl; - } - } - } - prn_id++; - } - prn_id = 0; - for(iter = doppler_ref.begin(); iter != doppler_ref.end(); iter++) - { - for(it = iter->begin(); it != iter->end(); it++) - { - // If a measure exists for this sow, store it - for(it2 = doppler_meas.at(prn_id).begin(); it2 != doppler_meas.at(prn_id).end(); it2++) - { - if(std::abs(it->first - it2->first) < 0.01) // store measures closer than 10 ms. - { - doppler_ref_aligned.at(prn_id).push_back(*it); - doppler_diff.at(prn_id).push_back(it->second - it2->second ); - } - } - } - prn_id++; - } - - // Compute pseudorange error - prn_id = 0; - std::vector mean_pr_diff_v; - for(iter_diff = pr_diff.begin(); iter_diff != pr_diff.end(); iter_diff++) - { - // For each satellite with reference and measurements aligned in time - int number_obs = 0; - double mean_diff = 0.0; - for(iter_v = iter_diff->begin(); iter_v != iter_diff->end(); iter_v++) - { - mean_diff = mean_diff + *iter_v; - number_obs = number_obs + 1; - } - if(number_obs > 0) - { - mean_diff = mean_diff / number_obs; - mean_pr_diff_v.push_back(mean_diff); - std::cout << "-- Mean pseudorange difference for sat " << prn_id << ": " << mean_diff; - double stdev_ = compute_stdev(*iter_diff); - std::cout << " +/- " << stdev_ ; - std::cout << " [m]" << std::endl; - } - else - { - mean_diff = 0.0; - } - - prn_id++; - } - double stdev_pr = compute_stdev(mean_pr_diff_v); - std::cout << "Pseudorange diff error stdev = " << stdev_pr << " [m]" << std::endl; - ASSERT_LT(stdev_pr, 1.0); - - // Compute carrier phase error - prn_id = 0; - std::vector mean_cp_diff_v; - for(iter_diff = cp_diff.begin(); iter_diff != cp_diff.end(); iter_diff++) - { - // For each satellite with reference and measurements aligned in time - int number_obs = 0; - double mean_diff = 0.0; - for(iter_v = iter_diff->begin(); iter_v != iter_diff->end(); iter_v++) - { - mean_diff = mean_diff + *iter_v; - number_obs = number_obs + 1; - } - if(number_obs > 0) - { - mean_diff = mean_diff / number_obs; - mean_cp_diff_v.push_back(mean_diff); - std::cout << "-- Mean carrier phase difference for sat " << prn_id << ": " << mean_diff; - double stdev_pr_ = compute_stdev(*iter_diff); - std::cout << " +/- " << stdev_pr_ << " whole cycles (19 cm)" << std::endl; - } - else - { - mean_diff = 0.0; - } - - prn_id++; - } - - // Compute Doppler error - prn_id = 0; - std::vector mean_doppler_v; - for(iter_diff = doppler_diff.begin(); iter_diff != doppler_diff.end(); iter_diff++) - { - // For each satellite with reference and measurements aligned in time - int number_obs = 0; - double mean_diff = 0.0; - for(iter_v = iter_diff->begin(); iter_v != iter_diff->end(); iter_v++) - { - //std::cout << *iter_v << std::endl; - mean_diff = mean_diff + *iter_v; - number_obs = number_obs + 1; - } - if(number_obs > 0) - { - mean_diff = mean_diff / number_obs; - mean_doppler_v.push_back(mean_diff); - std::cout << "-- Mean Doppler difference for sat " << prn_id << ": " << mean_diff << " [Hz]" << std::endl; - } - else - { - mean_diff = 0.0; - } - - prn_id++; - } - - double stdev_dp = compute_stdev(mean_doppler_v); - std::cout << "Doppler error stdev = " << stdev_dp << " [Hz]" << std::endl; - ASSERT_LT(stdev_dp, 1.0); -} - - -TEST_F(Obs_Gps_L1_System_Test, Observables_system_test) -{ - std::cout << "Validating input RINEX nav file: " << FLAGS_rinex_nav_file << " ..." << std::endl; - bool is_rinex_nav_valid = check_valid_rinex_nav(FLAGS_rinex_nav_file); - EXPECT_EQ(true, is_rinex_nav_valid) << "The RINEX navigation file " << FLAGS_rinex_nav_file << " is not well formed."; - std::cout << "The file is valid." << std::endl; - - // Configure the signal generator - configure_generator(); - - // Generate signal raw signal samples and observations RINEX file - generate_signal(); - - std::cout << "Validating generated reference RINEX obs file: " << FLAGS_filename_rinex_obs << " ..." << std::endl; - bool is_gen_rinex_obs_valid = check_valid_rinex_obs( "./" + FLAGS_filename_rinex_obs); - EXPECT_EQ(true, is_gen_rinex_obs_valid) << "The RINEX observation file " << FLAGS_filename_rinex_obs << ", generated by gnss-sim, is not well formed."; - std::cout << "The file is valid." << std::endl; - - // Configure receiver - configure_receiver(); - - // Run the receiver - EXPECT_EQ( run_receiver(), 0) << "Problem executing the software-defined signal generator"; - - std::cout << "Validating RINEX obs file obtained by GNSS-SDR: " << generated_rinex_obs << " ..." << std::endl; - is_gen_rinex_obs_valid = check_valid_rinex_obs( "./" + generated_rinex_obs); - EXPECT_EQ(true, is_gen_rinex_obs_valid) << "The RINEX observation file " << generated_rinex_obs << ", generated by GNSS-SDR, is not well formed."; - std::cout << "The file is valid." << std::endl; - - // Check results - check_results(); -} - - -int main(int argc, char **argv) -{ - std::cout << "Running Observables validation test..." << std::endl; - int res = 0; - try - { - testing::InitGoogleTest(&argc, argv); - } - catch(...) {} // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest - - google::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - // Run the Tests - try - { - res = RUN_ALL_TESTS(); - } - catch(...) - { - LOG(WARNING) << "Unexpected catch"; - } - google::ShutDownCommandLineFlags(); - return res; -} diff --git a/src/tests/system-tests/position_test.cc b/src/tests/system-tests/position_test.cc new file mode 100644 index 000000000..b719dba55 --- /dev/null +++ b/src/tests/system-tests/position_test.cc @@ -0,0 +1,975 @@ +/*! + * \file position_test.cc + * \brief This class implements a test for the validation of computed position. + * \authors
        + *
      • Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es + *
      • Javier Arribas, 2018. jarribas(at)cttc.es + *
      + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "MATH_CONSTANTS.h" +#include "acquisition_msg_rx.h" +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "control_thread.h" +#include "file_configuration.h" +#include "geofunctions.h" +#include "gnuplot_i.h" +#include "in_memory_configuration.h" +#include "position_test_flags.h" +#include "rtklib_solver_dump_reader.h" +#include "signal_generator_flags.h" +#include "spirent_motion_csv_dump_reader.h" +#include "test_flags.h" +#include "tracking_tests_flags.h" //acquisition resampler +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// For GPS NAVIGATION (L1) +concurrent_queue global_gps_acq_assist_queue; +concurrent_map global_gps_acq_assist_map; + +class PositionSystemTest : public ::testing::Test +{ +public: + int configure_generator(); + int generate_signal(); + int configure_receiver(); + int run_receiver(); + void check_results(); + bool save_mat_xy(std::vector* x, std::vector* y, std::string filename); + bool save_mat_x(std::vector* x, std::string filename); + std::string config_filename_no_extension; + +private: + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + + const double baseband_sampling_freq = static_cast(FLAGS_fs_gen_sps); + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_filename_raw_data; + + void print_results(const arma::mat& R_eb_enu); + std::shared_ptr config; + std::shared_ptr config_f; + std::string generated_kml_file; +}; + + +int PositionSystemTest::configure_generator() +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(std::min(FLAGS_duration * 10, 3000)); + if (FLAGS_duration > 300) std::cout << "WARNING: Duration has been set to its maximum value of 300 s" << std::endl; + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + return 0; +} + + +int PositionSystemTest::generate_signal() +{ + pid_t wait_result; + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], nullptr}; + + int pid; + if ((pid = fork()) == -1) + perror("fork error"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv error." << std::endl; + std::terminate(); + } + + wait_result = waitpid(pid, &child_status, 0); + if (wait_result == -1) perror("waitpid error"); + return 0; +} + + +int PositionSystemTest::configure_receiver() +{ + if (FLAGS_config_file_ptest.empty()) + { + config = std::make_shared(); + const int sampling_rate_internal = baseband_sampling_freq; + + const int number_of_taps = 11; + const int number_of_bands = 2; + const float band1_begin = 0.0; + const float band1_end = 0.48; + const float band2_begin = 0.52; + const float band2_end = 1.0; + const float ampl1_begin = 1.0; + const float ampl1_end = 1.0; + const float ampl2_begin = 0.0; + const float ampl2_end = 0.0; + const float band1_error = 1.0; + const float band2_error = 1.0; + const int grid_density = 16; + + const float zero = 0.0; + const int number_of_channels = 11; + const int in_acquisition = 1; + + const float threshold = 2.5; + const float doppler_max = 5000.0; + const float doppler_step = 250.0; + const int max_dwells = 10; + const int tong_init_val = 2; + const int tong_max_val = 10; + const int tong_max_dwells = 30; + const int coherent_integration_time_ms = 1; + + const float pll_bw_hz = 35.0; + const float dll_bw_hz = 1.5; + const float early_late_space_chips = 0.5; + const float pll_bw_narrow_hz = 1.0; + const float dll_bw_narrow_hz = 0.1; + const int extend_correlation_ms = 1; + + const int display_rate_ms = 500; + const int output_rate_ms = 100; + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(sampling_rate_internal)); + // Enable automatic resampler for the acquisition, if required + if (FLAGS_use_acquisition_resampler == true) + { + config->set_property("GNSS-SDR.use_acquisition_resampler", "true"); + } + + // Set the assistance system parameters + config->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); + config->set_property("GNSS-SDR.SUPL_gps_enabled", "false"); + config->set_property("GNSS-SDR.SUPL_gps_ephemeris_server", "supl.google.com"); + config->set_property("GNSS-SDR.SUPL_gps_ephemeris_port", std::to_string(7275)); + config->set_property("GNSS-SDR.SUPL_gps_acquisition_server", "supl.google.com"); + config->set_property("GNSS-SDR.SUPL_gps_acquisition_port", std::to_string(7275)); + config->set_property("GNSS-SDR.SUPL_MCC", std::to_string(244)); + config->set_property("GNSS-SDR.SUPL_MNC", std::to_string(5)); + config->set_property("GNSS-SDR.SUPL_LAC", "0x59e2"); + config->set_property("GNSS-SDR.SUPL_CI", "0x31b0"); + + // Set the Signal Source + config->set_property("SignalSource.implementation", "File_Signal_Source"); + config->set_property("SignalSource.filename", "./" + filename_raw_data); + config->set_property("SignalSource.sampling_frequency", std::to_string(sampling_rate_internal)); + config->set_property("SignalSource.item_type", "ibyte"); + config->set_property("SignalSource.samples", std::to_string(zero)); + + // Set the Signal Conditioner + config->set_property("SignalConditioner.implementation", "Signal_Conditioner"); + config->set_property("DataTypeAdapter.implementation", "Ibyte_To_Complex"); + config->set_property("InputFilter.implementation", "Freq_Xlating_Fir_Filter"); + config->set_property("InputFilter.dump", "false"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", std::to_string(number_of_taps)); + config->set_property("InputFilter.number_of_bands", std::to_string(number_of_bands)); + config->set_property("InputFilter.band1_begin", std::to_string(band1_begin)); + config->set_property("InputFilter.band1_end", std::to_string(band1_end)); + config->set_property("InputFilter.band2_begin", std::to_string(band2_begin)); + config->set_property("InputFilter.band2_end", std::to_string(band2_end)); + config->set_property("InputFilter.ampl1_begin", std::to_string(ampl1_begin)); + config->set_property("InputFilter.ampl1_end", std::to_string(ampl1_end)); + config->set_property("InputFilter.ampl2_begin", std::to_string(ampl2_begin)); + config->set_property("InputFilter.ampl2_end", std::to_string(ampl2_end)); + config->set_property("InputFilter.band1_error", std::to_string(band1_error)); + config->set_property("InputFilter.band2_error", std::to_string(band2_error)); + config->set_property("InputFilter.filter_type", "lowpass"); + config->set_property("InputFilter.grid_density", std::to_string(grid_density)); + config->set_property("InputFilter.sampling_frequency", std::to_string(sampling_rate_internal)); + config->set_property("InputFilter.IF", std::to_string(zero)); + config->set_property("Resampler.implementation", "Pass_Through"); + config->set_property("Resampler.dump", "false"); + config->set_property("Resampler.item_type", "gr_complex"); + config->set_property("Resampler.sample_freq_in", std::to_string(sampling_rate_internal)); + config->set_property("Resampler.sample_freq_out", std::to_string(sampling_rate_internal)); + + // Set the number of Channels + config->set_property("Channels_1C.count", std::to_string(number_of_channels)); + config->set_property("Channels.in_acquisition", std::to_string(in_acquisition)); + config->set_property("Channel.signal", "1C"); + + // Set Acquisition + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms)); + config->set_property("Acquisition_1C.threshold", std::to_string(threshold)); + config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition_1C.doppler_step", std::to_string(doppler_step)); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.max_dwells", std::to_string(max_dwells)); + config->set_property("Acquisition_1C.tong_init_val", std::to_string(tong_init_val)); + config->set_property("Acquisition_1C.tong_max_val", std::to_string(tong_max_val)); + config->set_property("Acquisition_1C.tong_max_dwells", std::to_string(tong_max_dwells)); + config->set_property("Acquisition_1C.dump", "false"); + config->set_property("Acquisition_1C.dump_filename", "./acquisition"); + config->set_property("Acquisition_1C.dump_channel", "1"); + config->set_property("Acquisition_1C.blocking", "true"); + + // Set Tracking + config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); + config->set_property("Tracking_1C.item_type", "gr_complex"); + config->set_property("Tracking_1C.dump", "false"); + config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); + config->set_property("Tracking_1C.pll_bw_hz", std::to_string(pll_bw_hz)); + config->set_property("Tracking_1C.dll_bw_hz", std::to_string(dll_bw_hz)); + config->set_property("Tracking_1C.early_late_space_chips", std::to_string(early_late_space_chips)); + + config->set_property("Tracking_1C.pll_bw_narrow_hz", std::to_string(pll_bw_narrow_hz)); + config->set_property("Tracking_1C.dll_bw_narrow_hz", std::to_string(dll_bw_narrow_hz)); + config->set_property("Tracking_1C.extend_correlation_symbols", std::to_string(extend_correlation_ms)); + //config->set_property("Tracking_1C.high_dyn", "true"); + //config->set_property("Tracking_1C.smoother_length", "200"); + + // Set Telemetry + config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); + config->set_property("TelemetryDecoder_1C.dump", "false"); + + // Set Observables + config->set_property("Observables.implementation", "Hybrid_Observables"); + config->set_property("Observables.dump", "false"); + config->set_property("Observables.dump_filename", "./observables.dat"); + + // Set PVT + config->set_property("PVT.implementation", "RTKLIB_PVT"); + config->set_property("PVT.positioning_mode", "PPP_Static"); + config->set_property("PVT.output_rate_ms", std::to_string(output_rate_ms)); + config->set_property("PVT.display_rate_ms", std::to_string(display_rate_ms)); + config->set_property("PVT.dump_filename", "./PVT"); + config->set_property("PVT.nmea_dump_filename", "./gnss_sdr_pvt.nmea"); + config->set_property("PVT.flag_nmea_tty_port", "false"); + config->set_property("PVT.nmea_dump_devname", "/dev/pts/4"); + config->set_property("PVT.flag_rtcm_server", "false"); + config->set_property("PVT.flag_rtcm_tty_port", "false"); + config->set_property("PVT.rtcm_dump_devname", "/dev/pts/1"); + config->set_property("PVT.dump", "true"); + config->set_property("PVT.rinex_version", std::to_string(2)); + config->set_property("PVT.iono_model", "OFF"); + config->set_property("PVT.trop_model", "OFF"); + config->set_property("PVT.AR_GPS", "PPP-AR"); + config->set_property("PVT.elevation_mask", std::to_string(15)); + + config_f = 0; + } + else + { + config_f = std::make_shared(FLAGS_config_file_ptest); + config = 0; + } + return 0; +} + + +int PositionSystemTest::run_receiver() +{ + std::shared_ptr control_thread; + if (FLAGS_config_file_ptest.empty()) + { + control_thread = std::make_shared(config); + } + else + { + control_thread = std::make_shared(config_f); + } + + // start receiver + try + { + control_thread->run(); + } + catch (const boost::exception& e) + { + std::cout << "Boost exception: " << boost::diagnostic_information(e); + } + catch (const std::exception& ex) + { + std::cout << "STD exception: " << ex.what(); + } + + // Get the name of the KML file generated by the receiver + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + FILE* fp; + std::string argum2 = std::string("/bin/ls *kml | tail -1"); + char buffer[1035]; + fp = popen(&argum2[0], "r"); + if (fp == nullptr) + { + std::cout << "Failed to run command: " << argum2 << std::endl; + return -1; + } + while (fgets(buffer, sizeof(buffer), fp) != nullptr) + { + std::string aux = std::string(buffer); + EXPECT_EQ(aux.empty(), false); + PositionSystemTest::generated_kml_file = aux.erase(aux.length() - 1, 1); + } + pclose(fp); + EXPECT_EQ(PositionSystemTest::generated_kml_file.empty(), false); + return 0; +} + + +bool PositionSystemTest::save_mat_xy(std::vector* x, std::vector* y, std::string filename) +{ + try + { + // WRITE MAT FILE + mat_t* matfp; + matvar_t* matvar; + filename.append(".mat"); + std::cout << "save_mat_xy write " << filename << std::endl; + matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT5); + if (reinterpret_cast(matfp) != NULL) + { + size_t dims[2] = {1, x->size()}; + matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + else + { + std::cout << "save_mat_xy: error creating file" << std::endl; + } + Mat_Close(matfp); + return true; + } + catch (const std::exception& ex) + { + std::cout << "save_mat_xy: " << ex.what() << std::endl; + return false; + } +} + +bool PositionSystemTest::save_mat_x(std::vector* x, std::string filename) +{ + try + { + // WRITE MAT FILE + mat_t* matfp; + matvar_t* matvar; + filename.append(".mat"); + std::cout << "save_mat_x write " << filename << std::endl; + matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT5); + if (reinterpret_cast(matfp) != NULL) + { + size_t dims[2] = {1, x->size()}; + matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + else + { + std::cout << "save_mat_x: error creating file" << std::endl; + } + Mat_Close(matfp); + return true; + } + catch (const std::exception& ex) + { + std::cout << "save_mat_x: " << ex.what() << std::endl; + return false; + } +} + +void PositionSystemTest::check_results() +{ + arma::mat R_eb_e; //ECEF position (x,y,z) estimation in the Earth frame (Nx3) + arma::mat R_eb_enu; //ENU position (N,E,U) estimation in UTM (Nx3) + arma::mat V_eb_e; //ECEF velocity (x,y,z) estimation in the Earth frame (Nx3) + arma::mat LLH; //Geodetic coordinates (latitude, longitude, height) estimation in WGS84 datum + arma::vec receiver_time_s; + + arma::mat ref_R_eb_e; //ECEF position (x,y,z) reference in the Earth frame (Nx3) + arma::mat ref_V_eb_e; //ECEF velocity (x,y,z) reference in the Earth frame (Nx3) + arma::mat ref_LLH; //Geodetic coordinates (latitude, longitude, height) reference in WGS84 datum + arma::vec ref_time_s; + + std::istringstream iss2(FLAGS_static_position); + std::string str_aux; + std::getline(iss2, str_aux, ','); + double ref_lat = std::stod(str_aux); + std::getline(iss2, str_aux, ','); + double ref_long = std::stod(str_aux); + std::getline(iss2, str_aux, '\n'); + double ref_h = std::stod(str_aux); + int utm_zone = findUtmZone(ref_lat, ref_long); + + arma::vec v_eb_n = {0.0, 0.0, 0.0}; + arma::vec true_r_eb_e = {0.0, 0.0, 0.0}; + arma::vec true_v_eb_e = {0.0, 0.0, 0.0}; + pv_Geo_to_ECEF(degtorad(ref_lat), degtorad(ref_long), ref_h, v_eb_n, true_r_eb_e, true_v_eb_e); + ref_R_eb_e.insert_cols(0, true_r_eb_e); + arma::vec ref_r_enu = {0, 0, 0}; + cart2utm(true_r_eb_e, utm_zone, ref_r_enu); + + rtklib_solver_dump_reader pvt_reader; + pvt_reader.open_obs_file(FLAGS_pvt_solver_dump_filename); + int64_t n_epochs = pvt_reader.num_epochs(); + R_eb_e = arma::zeros(3, n_epochs); + V_eb_e = arma::zeros(3, n_epochs); + LLH = arma::zeros(3, n_epochs); + receiver_time_s = arma::zeros(n_epochs, 1); + int64_t current_epoch = 0; + while (pvt_reader.read_binary_obs()) + { + receiver_time_s(current_epoch) = pvt_reader.RX_time - pvt_reader.clk_offset_s; + R_eb_e(0, current_epoch) = pvt_reader.rr[0]; + R_eb_e(1, current_epoch) = pvt_reader.rr[1]; + R_eb_e(2, current_epoch) = pvt_reader.rr[2]; + V_eb_e(0, current_epoch) = pvt_reader.rr[3]; + V_eb_e(1, current_epoch) = pvt_reader.rr[4]; + V_eb_e(2, current_epoch) = pvt_reader.rr[5]; + LLH(0, current_epoch) = pvt_reader.latitude; + LLH(1, current_epoch) = pvt_reader.longitude; + LLH(2, current_epoch) = pvt_reader.height; + + arma::vec tmp_r_enu = {0, 0, 0}; + cart2utm(R_eb_e.col(current_epoch), utm_zone, tmp_r_enu); + R_eb_enu.insert_cols(current_epoch, tmp_r_enu); + + // debug check + // std::cout << "t1: " << pvt_reader.RX_time << std::endl; + // std::cout << "t2: " << pvt_reader.TOW_at_current_symbol_ms << std::endl; + // std::cout << "offset: " << pvt_reader.clk_offset_s << std::endl; + // getchar(); + current_epoch++; + } + ASSERT_FALSE(current_epoch == 0) << "PVT dump is empty"; + + // compute results + if (FLAGS_static_scenario) + { + double sigma_E_2_precision = arma::var(R_eb_enu.row(0)); + double sigma_N_2_precision = arma::var(R_eb_enu.row(1)); + double sigma_U_2_precision = arma::var(R_eb_enu.row(2)); + + arma::rowvec error_east_m; + error_east_m = R_eb_enu.row(0) - ref_r_enu(0); + double sigma_E_2_accuracy = arma::as_scalar(error_east_m * error_east_m.t()); + sigma_E_2_accuracy = sigma_E_2_accuracy / error_east_m.n_elem; + + arma::rowvec error_north_m; + error_north_m = R_eb_enu.row(1) - ref_r_enu(1); + double sigma_N_2_accuracy = arma::as_scalar(error_north_m * error_north_m.t()); + sigma_N_2_accuracy = sigma_N_2_accuracy / error_north_m.n_elem; + + arma::rowvec error_up_m; + error_up_m = R_eb_enu.row(2) - ref_r_enu(2); + double sigma_U_2_accuracy = arma::as_scalar(error_up_m * error_up_m.t()); + sigma_U_2_accuracy = sigma_U_2_accuracy / error_up_m.n_elem; + + // arma::mat error_enu_mat = arma::zeros(3, error_east_m.n_elem); + // error_enu_mat.row(0) = error_east_m; + // error_enu_mat.row(1) = error_north_m; + // error_enu_mat.row(2) = error_up_m; + // + // arma::vec error_2D_m = arma::zeros(error_enu_mat.n_cols, 1); + // arma::vec error_3D_m = arma::zeros(error_enu_mat.n_cols, 1); + // for (uint64_t n = 0; n < error_enu_mat.n_cols; n++) + // { + // error_2D_m(n) = arma::norm(error_enu_mat.submat(0, n, 1, n)); + // error_3D_m(n) = arma::norm(error_enu_mat.col(n)); + // } + + double static_2D_error_m = sqrt(pow(arma::mean(error_east_m), 2.0) + pow(arma::mean(error_north_m), 2.0)); + double static_3D_error_m = sqrt(pow(arma::mean(error_east_m), 2.0) + pow(arma::mean(error_north_m), 2.0) + pow(arma::mean(error_up_m), 2.0)); + + std::stringstream stm; + std::ofstream position_test_file; + if (!FLAGS_config_file_ptest.empty()) + { + stm << "Configuration file: " << FLAGS_config_file_ptest << std::endl; + } + + stm << "---- STATIC ACCURACY ----" << std::endl; + stm << "2DRMS = " << 2 * sqrt(sigma_E_2_accuracy + sigma_N_2_accuracy) << " [m]" << std::endl; + stm << "DRMS = " << sqrt(sigma_E_2_accuracy + sigma_N_2_accuracy) << " [m]" << std::endl; + stm << "CEP = " << 0.62 * sqrt(sigma_N_2_accuracy) + 0.56 * sqrt(sigma_E_2_accuracy) << " [m]" << std::endl; + stm << "99% SAS = " << 1.122 * (sigma_E_2_accuracy + sigma_N_2_accuracy + sigma_U_2_accuracy) << " [m]" << std::endl; + stm << "90% SAS = " << 0.833 * (sigma_E_2_accuracy + sigma_N_2_accuracy + sigma_U_2_accuracy) << " [m]" << std::endl; + stm << "MRSE = " << sqrt(sigma_E_2_accuracy + sigma_N_2_accuracy + sigma_U_2_accuracy) << " [m]" << std::endl; + stm << "SEP = " << 0.51 * (sigma_E_2_accuracy + sigma_N_2_accuracy + sigma_U_2_accuracy) << " [m]" << std::endl; + stm << "Static Bias 2D = " << static_2D_error_m << " [m]" << std::endl; + stm << "Static Bias 3D = " << static_3D_error_m << " [m]" << std::endl; + stm << std::endl; + + stm << "---- STATIC PRECISION ----" << std::endl; + stm << "2DRMS = " << 2 * sqrt(sigma_E_2_precision + sigma_N_2_precision) << " [m]" << std::endl; + stm << "DRMS = " << sqrt(sigma_E_2_precision + sigma_N_2_precision) << " [m]" << std::endl; + stm << "CEP = " << 0.62 * sqrt(sigma_N_2_precision) + 0.56 * sqrt(sigma_E_2_precision) << " [m]" << std::endl; + stm << "99% SAS = " << 1.122 * (sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision) << " [m]" << std::endl; + stm << "90% SAS = " << 0.833 * (sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision) << " [m]" << std::endl; + stm << "MRSE = " << sqrt(sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision) << " [m]" << std::endl; + stm << "SEP = " << 0.51 * (sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision) << " [m]" << std::endl; + + std::cout << stm.rdbuf(); + std::string output_filename = "position_test_output_" + PositionSystemTest::generated_kml_file.erase(PositionSystemTest::generated_kml_file.length() - 3, 3) + "txt"; + position_test_file.open(output_filename.c_str()); + if (position_test_file.is_open()) + { + position_test_file << stm.str(); + position_test_file.close(); + } + + // Sanity Check + double accuracy_CEP = 0.62 * sqrt(sigma_N_2_accuracy) + 0.56 * sqrt(sigma_E_2_accuracy); + double precision_SEP = 0.51 * (sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision); + + EXPECT_LT(static_2D_error_m, FLAGS_static_2D_error_m); + EXPECT_LT(static_2D_error_m, FLAGS_static_2D_error_m); + ASSERT_LT(accuracy_CEP, FLAGS_accuracy_CEP); + ASSERT_LT(precision_SEP, FLAGS_precision_SEP); + + if (FLAGS_plot_position_test == true) + { + print_results(R_eb_enu); + } + } + else + { + //dynamic position + spirent_motion_csv_dump_reader ref_reader; + ref_reader.open_obs_file(FLAGS_ref_motion_filename); + int64_t n_epochs = ref_reader.num_epochs(); + ref_R_eb_e = arma::zeros(3, n_epochs); + ref_V_eb_e = arma::zeros(3, n_epochs); + ref_LLH = arma::zeros(3, n_epochs); + ref_time_s = arma::zeros(n_epochs, 1); + int64_t current_epoch = 0; + while (ref_reader.read_csv_obs()) + { + ref_time_s(current_epoch) = ref_reader.TOW_ms / 1000.0; + ref_R_eb_e(0, current_epoch) = ref_reader.Pos_X; + ref_R_eb_e(1, current_epoch) = ref_reader.Pos_Y; + ref_R_eb_e(2, current_epoch) = ref_reader.Pos_Z; + ref_V_eb_e(0, current_epoch) = ref_reader.Vel_X; + ref_V_eb_e(1, current_epoch) = ref_reader.Vel_Y; + ref_V_eb_e(2, current_epoch) = ref_reader.Vel_Z; + ref_LLH(0, current_epoch) = ref_reader.Lat; + ref_LLH(1, current_epoch) = ref_reader.Long; + ref_LLH(2, current_epoch) = ref_reader.Height; + current_epoch++; + } + //interpolation of reference data to receiver epochs timestamps + arma::mat ref_interp_R_eb_e = arma::zeros(3, R_eb_e.n_cols); + arma::mat ref_interp_V_eb_e = arma::zeros(3, V_eb_e.n_cols); + arma::mat ref_interp_LLH = arma::zeros(3, LLH.n_cols); + arma::vec tmp_vector; + for (int n = 0; n < 3; n++) + { + arma::interp1(ref_time_s, ref_R_eb_e.row(n), receiver_time_s, tmp_vector); + ref_interp_R_eb_e.row(n) = tmp_vector.t(); + arma::interp1(ref_time_s, ref_V_eb_e.row(n), receiver_time_s, tmp_vector); + ref_interp_V_eb_e.row(n) = tmp_vector.t(); + arma::interp1(ref_time_s, ref_LLH.row(n), receiver_time_s, tmp_vector); + ref_interp_LLH.row(n) = tmp_vector.t(); + } + + //compute error vectors + arma::mat error_R_eb_e = arma::zeros(3, R_eb_e.n_cols); + arma::mat error_V_eb_e = arma::zeros(3, V_eb_e.n_cols); + arma::mat error_LLH = arma::zeros(3, LLH.n_cols); + error_R_eb_e = R_eb_e - ref_interp_R_eb_e; + error_V_eb_e = V_eb_e - ref_interp_V_eb_e; + error_LLH = LLH - ref_interp_LLH; + arma::vec error_module_R_eb_e = arma::zeros(R_eb_e.n_cols, 1); + arma::vec error_module_V_eb_e = arma::zeros(V_eb_e.n_cols, 1); + for (uint64_t n = 0; n < R_eb_e.n_cols; n++) + { + error_module_R_eb_e(n) = arma::norm(error_R_eb_e.col(n)); + error_module_V_eb_e(n) = arma::norm(error_V_eb_e.col(n)); + } + + //Error statistics + arma::vec tmp_vec; + //RMSE, Mean, Variance and peaks + tmp_vec = arma::square(error_module_R_eb_e); + double rmse_R_eb_e = sqrt(arma::mean(tmp_vec)); + double error_mean_R_eb_e = arma::mean(error_module_R_eb_e); + double error_var_R_eb_e = arma::var(error_module_R_eb_e); + double max_error_R_eb_e = arma::max(error_module_R_eb_e); + double min_error_R_eb_e = arma::min(error_module_R_eb_e); + + tmp_vec = arma::square(error_module_V_eb_e); + double rmse_V_eb_e = sqrt(arma::mean(tmp_vec)); + double error_mean_V_eb_e = arma::mean(error_module_V_eb_e); + double error_var_V_eb_e = arma::var(error_module_V_eb_e); + double max_error_V_eb_e = arma::max(error_module_V_eb_e); + double min_error_V_eb_e = arma::min(error_module_V_eb_e); + + //report + std::cout << "----- Position and Velocity 3D ECEF error statistics -----" << std::endl; + if (!FLAGS_config_file_ptest.empty()) + { + std::cout << "---- Configuration file: " << FLAGS_config_file_ptest << std::endl; + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "---- 3D ECEF Position RMSE = " + << rmse_R_eb_e << ", mean = " << error_mean_R_eb_e + << ", stdev = " << sqrt(error_var_R_eb_e) + << " (max,min) = " << max_error_R_eb_e + << "," << min_error_R_eb_e + << " [m]" << std::endl; + std::cout << "---- 3D ECEF Velocity RMSE = " + << rmse_V_eb_e << ", mean = " << error_mean_V_eb_e + << ", stdev = " << sqrt(error_var_V_eb_e) + << " (max,min) = " << max_error_V_eb_e + << "," << min_error_V_eb_e + << " [m/s]" << std::endl; + std::cout.precision(ss); + + // plots + if (FLAGS_plot_position_test == true) + { + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (!gnuplot_executable.empty()) + { + Gnuplot g1("points"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("3D ECEF error coordinates"); + g1.set_grid(); + //conversion between arma::vec and std:vector + arma::rowvec arma_vec_error_x = error_R_eb_e.row(0); + arma::rowvec arma_vec_error_y = error_R_eb_e.row(1); + arma::rowvec arma_vec_error_z = error_R_eb_e.row(2); + + std::vector X(arma_vec_error_x.colptr(0), arma_vec_error_x.colptr(0) + arma_vec_error_x.n_rows); + std::vector Y(arma_vec_error_y.colptr(0), arma_vec_error_y.colptr(0) + arma_vec_error_y.n_rows); + std::vector Z(arma_vec_error_z.colptr(0), arma_vec_error_z.colptr(0) + arma_vec_error_z.n_rows); + + g1.cmd("set key box opaque"); + g1.plot_xyz(X, Y, Z, "ECEF 3D error"); + g1.set_legend(); + if (FLAGS_config_file_ptest.empty()) + { + g1.savetops("ECEF_3d_error"); + } + else + { + g1.savetops("ECEF_3d_error_" + config_filename_no_extension); + } + arma::vec time_vector_from_start_s = receiver_time_s - receiver_time_s(0); + Gnuplot g3("linespoints"); + if (FLAGS_show_plots) + { + g3.showonscreen(); // window output + } + else + { + g3.disablescreen(); + } + g3.set_title("3D Position estimation error module [m]"); + g3.set_grid(); + g3.set_xlabel("Receiver epoch time from first valid PVT [s]"); + g3.set_ylabel("3D Position error [m]"); + //conversion between arma::vec and std:vector + std::vector error_vec(error_module_R_eb_e.colptr(0), error_module_R_eb_e.colptr(0) + error_module_R_eb_e.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector_from_start_s, error_vec, "Position 3D error"); + double mean3d = std::accumulate(error_vec.begin(), error_vec.end(), 0.0) / error_vec.size(); + std::vector error_mean(error_module_R_eb_e.n_rows, mean3d); + g3.set_style("lines"); + g3.plot_xy(time_vector_from_start_s, error_mean, "Mean"); + g3.set_legend(); + if (FLAGS_config_file_ptest.empty()) + { + g3.savetops("Position_3d_error"); + } + else + { + g3.savetops("Position_3d_error_" + config_filename_no_extension); + } + + Gnuplot g4("linespoints"); + if (FLAGS_show_plots) + { + g4.showonscreen(); // window output + } + else + { + g4.disablescreen(); + } + g4.set_title("3D Velocity estimation error module [m/s]"); + g4.set_grid(); + g4.set_xlabel("Receiver epoch time from first valid PVT [s]"); + g4.set_ylabel("3D Velocity error [m/s]"); + //conversion between arma::vec and std:vector + std::vector error_vec2(error_module_V_eb_e.colptr(0), error_module_V_eb_e.colptr(0) + error_module_V_eb_e.n_rows); + g4.cmd("set key box opaque"); + g4.plot_xy(time_vector_from_start_s, error_vec2, "Velocity 3D error"); + double mean3dv = std::accumulate(error_vec2.begin(), error_vec2.end(), 0.0) / error_vec2.size(); + std::vector error_mean_v(error_module_V_eb_e.n_rows, mean3dv); + g4.set_style("lines"); + g4.plot_xy(time_vector_from_start_s, error_mean_v, "Mean"); + g4.set_legend(); + if (FLAGS_config_file_ptest.empty()) + { + g4.savetops("Velocity_3d_error"); + } + else + { + g4.savetops("Velocity_3d_error_" + config_filename_no_extension); + } + } + } + + //ERROR CHECK + //todo: reduce the error tolerance or enable the option to pass the error tolerance by parameter + EXPECT_LT(rmse_R_eb_e, FLAGS_dynamic_3D_position_RMSE); //3D RMS positioning error less than 10 meters + EXPECT_LT(rmse_V_eb_e, FLAGS_dynamic_3D_velocity_RMSE); //3D RMS speed error less than 5 meters/s (18 km/h) + } +} + + +void PositionSystemTest::print_results(const arma::mat& R_eb_enu) +{ + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_position_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + double sigma_E_2_precision = arma::var(R_eb_enu.row(0)); + double sigma_N_2_precision = arma::var(R_eb_enu.row(1)); + double sigma_U_2_precision = arma::var(R_eb_enu.row(2)); + + double mean_east = arma::mean(R_eb_enu.row(0)); + double mean_north = arma::mean(R_eb_enu.row(1)); + double mean_up = arma::mean(R_eb_enu.row(2)); + + double it_max_east = arma::max(R_eb_enu.row(0) - mean_east); + double it_min_east = arma::min(R_eb_enu.row(0) - mean_east); + + double it_max_north = arma::max(R_eb_enu.row(1) - mean_north); + double it_min_north = arma::min(R_eb_enu.row(1) - mean_north); + + double it_max_up = arma::max(R_eb_enu.row(2) - mean_up); + double it_min_up = arma::min(R_eb_enu.row(2) - mean_up); + + double east_range = std::max(it_max_east, std::abs(it_min_east)); + double north_range = std::max(it_max_north, std::abs(it_min_north)); + double up_range = std::max(it_max_up, std::abs(it_min_up)); + + double range = std::max(east_range, north_range) * 1.1; + double range_3d = std::max(std::max(east_range, north_range), up_range) * 1.1; + + double two_drms = 2 * sqrt(sigma_E_2_precision + sigma_N_2_precision); + double ninty_sas = 0.833 * (sigma_E_2_precision + sigma_N_2_precision + sigma_U_2_precision); + arma::rowvec arma_east = R_eb_enu.row(0) - mean_east; + arma::rowvec arma_north = R_eb_enu.row(1) - mean_north; + arma::rowvec arma_up = R_eb_enu.row(2) - mean_up; + + std::vector east(arma_east.colptr(0), arma_east.row(0).colptr(0) + arma_east.row(0).n_cols); + std::vector north(arma_north.colptr(0), arma_north.colptr(0) + arma_north.n_cols); + std::vector up(arma_up.colptr(0), arma_up.colptr(0) + arma_up.n_cols); + + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + const std::string& gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("points"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("2D precision"); + g1.set_xlabel("East [m]"); + g1.set_ylabel("North [m]"); + g1.cmd("set size ratio -1"); + g1.cmd("set xrange [-" + std::to_string(range) + ":" + std::to_string(range) + "]"); + g1.cmd("set yrange [-" + std::to_string(range) + ":" + std::to_string(range) + "]"); + + + g1.plot_xy(east, north, "2D Position Fixes"); + g1.set_style("lines").plot_circle(mean_east, mean_north, two_drms, "2DRMS"); + g1.set_style("lines").plot_circle(mean_east, mean_north, two_drms / 2.0, "DRMS"); + + g1.cmd("set grid front"); + g1.cmd("replot"); + if (FLAGS_config_file_ptest.empty()) + { + g1.savetops("Position_test_2D"); + g1.savetopdf("Position_test_2D", 18); + } + else + { + g1.savetops("Position_test_2D_" + config_filename_no_extension); + g1.savetopdf("Position_test_2D_" + config_filename_no_extension, 18); + } + + Gnuplot g2("points"); + if (FLAGS_show_plots) + { + g2.showonscreen(); // window output + } + else + { + g2.disablescreen(); + } + g2.set_title("3D precision"); + g2.set_xlabel("East [m]"); + g2.set_ylabel("North [m]"); + g2.set_zlabel("Up [m]"); + g2.cmd("set size ratio -1"); + g2.cmd("set xrange [-" + std::to_string(range_3d) + ":" + std::to_string(range_3d) + "]"); + g2.cmd("set yrange [-" + std::to_string(range_3d) + ":" + std::to_string(range_3d) + "]"); + g2.cmd("set zrange [-" + std::to_string(range_3d) + ":" + std::to_string(range_3d) + "]"); + g2.cmd("set view equal xyz"); + g2.cmd("set ticslevel 0"); + + g2.cmd("set style fill transparent solid 0.30 border\n set parametric\n set urange [0:2.0*pi]\n set vrange [-pi/2:pi/2]\n r = " + + std::to_string(ninty_sas) + + "\n fx(v,u) = r*cos(v)*cos(u)\n fy(v,u) = r*cos(v)*sin(u)\n fz(v) = r*sin(v) \n splot fx(v,u),fy(v,u),fz(v) title \"90\%-SAS\" lt rgb \"gray\"\n"); + g2.plot_xyz(east, north, up, "3D Position Fixes"); + if (FLAGS_config_file_ptest.empty()) + { + g2.savetops("Position_test_3D"); + g2.savetopdf("Position_test_3D"); + } + else + { + g2.savetops("Position_test_3D_" + config_filename_no_extension); + g2.savetopdf("Position_test_3D_" + config_filename_no_extension); + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } +} + +TEST_F(PositionSystemTest /*unused*/, Position_system_test /*unused*/) +{ + if (FLAGS_config_file_ptest.empty()) + { + // Configure the signal generator + configure_generator(); + + // Generate signal raw signal samples and observations RINEX file + if (!FLAGS_disable_generator) + { + generate_signal(); + } + } + else + { + config_filename_no_extension = FLAGS_config_file_ptest.substr(FLAGS_config_file_ptest.find_last_of("/\\") + 1); + config_filename_no_extension = config_filename_no_extension.erase(config_filename_no_extension.length() - 5); + } + + // Configure receiver + configure_receiver(); + + // Run the receiver + EXPECT_EQ(run_receiver(), 0) << "Problem executing GNSS-SDR"; + + // Check results + check_results(); +} + + +int main(int argc, char** argv) +{ + std::cout << "Running Position precision test..." << std::endl; + int res = 0; + try + { + testing::InitGoogleTest(&argc, argv); + } + catch (...) + { + } // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest + + google::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + // Run the Tests + try + { + res = RUN_ALL_TESTS(); + } + catch (...) + { + LOG(WARNING) << "Unexpected catch"; + } + google::ShutDownCommandLineFlags(); + return res; +} diff --git a/src/tests/system-tests/ttff_gps_l1.cc b/src/tests/system-tests/ttff.cc similarity index 69% rename from src/tests/system-tests/ttff_gps_l1.cc rename to src/tests/system-tests/ttff.cc index e42274117..e9a51e762 100644 --- a/src/tests/system-tests/ttff_gps_l1.cc +++ b/src/tests/system-tests/ttff.cc @@ -1,5 +1,5 @@ /*! - * \file ttff_gps_l1.cc + * \file ttff.cc * \brief This class implements a test for measuring * the Time-To-First-Fix * \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,33 +25,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "concurrent_map.h" #include "concurrent_queue.h" #include "control_thread.h" #include "file_configuration.h" -#include "in_memory_configuration.h" #include "gnss_flowgraph.h" #include "gps_acq_assist.h" +#include "in_memory_configuration.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include DEFINE_int32(fs_in, 4000000, "Sampling rate, in Samples/s"); @@ -66,20 +66,20 @@ concurrent_queue global_gps_acq_assist_queue; concurrent_map global_gps_acq_assist_map; std::vector TTFF_v; -const int decimation_factor = 1; -typedef struct { - long mtype; // required by SysV message +typedef struct +{ + long mtype; // required by SysV message double ttff; } ttff_msgbuf; -class TTFF_GPS_L1_CA_Test: public ::testing::Test +class TtffTest : public ::testing::Test { public: void config_1(); void config_2(); - void print_TTFF_report(const std::vector & ttff_v, std::shared_ptr config_); + void print_TTFF_report(const std::vector &ttff_v, std::shared_ptr config_); std::shared_ptr config; std::shared_ptr config2; @@ -123,11 +123,11 @@ public: }; -void TTFF_GPS_L1_CA_Test::config_1() +void TtffTest::config_1() { config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(FLAGS_fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(FLAGS_fs_in)); // Set the assistance system parameters config->set_property("GNSS-SDR.SUPL_gps_ephemeris_server", "supl.google.com"); @@ -135,7 +135,7 @@ void TTFF_GPS_L1_CA_Test::config_1() config->set_property("GNSS-SDR.SUPL_gps_acquisition_server", "supl.google.com"); config->set_property("GNSS-SDR.SUPL_gps_acquisition_port", std::to_string(7275)); config->set_property("GNSS-SDR.SUPL_MCC", std::to_string(244)); - config->set_property("GNSS-SDR.SUPL_MNS", std::to_string(5)); + config->set_property("GNSS-SDR.SUPL_MNC", std::to_string(5)); config->set_property("GNSS-SDR.SUPL_LAC", "0x59e2"); config->set_property("GNSS-SDR.SUPL_CI", "0x31b0"); @@ -188,7 +188,6 @@ void TTFF_GPS_L1_CA_Test::config_1() // Set Acquisition config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); config->set_property("Acquisition_1C.item_type", "gr_complex"); - config->set_property("Acquisition_1C.if", std::to_string(zero)); config->set_property("Acquisition_1C.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms)); config->set_property("Acquisition_1C.threshold", std::to_string(threshold)); config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max)); @@ -202,7 +201,6 @@ void TTFF_GPS_L1_CA_Test::config_1() // Set Tracking config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); config->set_property("Tracking_1C.item_type", "gr_complex"); - config->set_property("Tracking_1C.if", std::to_string(zero)); config->set_property("Tracking_1C.dump", "false"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); config->set_property("Tracking_1C.pll_bw_hz", std::to_string(pll_bw_hz)); @@ -212,17 +210,15 @@ void TTFF_GPS_L1_CA_Test::config_1() // Set Telemetry config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); config->set_property("TelemetryDecoder_1C.dump", "false"); - config->set_property("TelemetryDecoder_1C.decimation_factor", std::to_string(decimation_factor)); // Set Observables - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + config->set_property("Observables.implementation", "Hybrid_Observables"); config->set_property("Observables.dump", "false"); config->set_property("Observables.dump_filename", "./observables.dat"); // Set PVT - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); - config->set_property("PVT.averaging_depth", std::to_string(averaging_depth)); - config->set_property("PVT.flag_averaging", "true"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); + config->set_property("PVT.positioning_mode", "Single"); config->set_property("PVT.output_rate_ms", std::to_string(output_rate_ms)); config->set_property("PVT.display_rate_ms", std::to_string(display_rate_ms)); config->set_property("PVT.dump_filename", "./PVT"); @@ -236,9 +232,9 @@ void TTFF_GPS_L1_CA_Test::config_1() } -void TTFF_GPS_L1_CA_Test::config_2() +void TtffTest::config_2() { - if(FLAGS_config_file_ttff.empty()) + if (FLAGS_config_file_ttff.empty()) { std::string path = std::string(TEST_PATH); std::string filename = path + "../../conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf"; @@ -250,7 +246,7 @@ void TTFF_GPS_L1_CA_Test::config_2() } int d_sampling_rate; - d_sampling_rate = config2->property("GNSS-SDR.internal_fs_hz", FLAGS_fs_in); + d_sampling_rate = config2->property("GNSS-SDR.internal_fs_sps", FLAGS_fs_in); config2->set_property("SignalSource.samples", std::to_string(d_sampling_rate * FLAGS_max_measurement_duration)); } @@ -269,25 +265,29 @@ void receive_msg() key_t key_stop = 1102; bool leave = false; - while(!leave) + while (!leave) { // wait for the queue to be created - while((msqid = msgget(key, 0644)) == -1){} + while ((msqid = msgget(key, 0644)) == -1) + { + } if (msgrcv(msqid, &msg, msgrcv_size, 1, 0) != -1) { ttff_msg = msg.ttff; - if( (ttff_msg != 0) && (ttff_msg != -1)) + if ((ttff_msg != 0) && (ttff_msg != -1)) { - TTFF_v.push_back(ttff_msg / (1000.0 / decimation_factor) ); - LOG(INFO) << "Valid Time-To-First-Fix: " << ttff_msg / (1000.0 / decimation_factor ) << "[s]"; + TTFF_v.push_back(ttff_msg); + LOG(INFO) << "Valid Time-To-First-Fix: " << ttff_msg << "[s]"; // Stop the receiver - while(((msqid_stop = msgget(key_stop, 0644))) == -1){} + while (((msqid_stop = msgget(key_stop, 0644))) == -1) + { + } double msgsend_size = sizeof(msg_stop.ttff); msgsnd(msqid_stop, &msg_stop, msgsend_size, IPC_NOWAIT); } - if( std::abs(ttff_msg - (-1.0) ) < 10 * std::numeric_limits::epsilon() ) + if (std::abs(ttff_msg - (-1.0)) < 10 * std::numeric_limits::epsilon()) { leave = true; } @@ -297,53 +297,51 @@ void receive_msg() } -void TTFF_GPS_L1_CA_Test::print_TTFF_report(const std::vector & ttff_v, std::shared_ptr config_) +void TtffTest::print_TTFF_report(const std::vector &ttff_v, std::shared_ptr config_) { std::ofstream ttff_report_file; std::string filename = "ttff_report"; std::string filename_; - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); + boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); + tm timeinfo = boost::posix_time::to_tm(pt); std::stringstream strm0; - const int year = timeinfo->tm_year - 100; + const int year = timeinfo.tm_year - 100; strm0 << year; - const int month = timeinfo->tm_mon + 1; - if(month < 10) + const int month = timeinfo.tm_mon + 1; + if (month < 10) { strm0 << "0"; } strm0 << month; - const int day = timeinfo->tm_mday; - if(day < 10) + const int day = timeinfo.tm_mday; + if (day < 10) { strm0 << "0"; } strm0 << day << "_"; - const int hour = timeinfo->tm_hour; - if(hour < 10) - { + const int hour = timeinfo.tm_hour; + if (hour < 10) + { strm0 << "0"; } strm0 << hour; - const int min = timeinfo->tm_min; + const int min = timeinfo.tm_min; - if(min < 10) + if (min < 10) { strm0 << "0"; } strm0 << min; - const int sec = timeinfo->tm_sec; - if(sec < 10) + const int sec = timeinfo.tm_sec; + if (sec < 10) { strm0 << "0"; } strm0 << sec; - filename_ = filename + "_" + strm0.str() + ".txt"; + filename_ = filename + "_" + strm0.str() + ".txt"; ttff_report_file.open(filename_.c_str()); @@ -363,100 +361,63 @@ void TTFF_GPS_L1_CA_Test::print_TTFF_report(const std::vector & ttff_v, std::string default_str = "default"; source = config_->property("SignalSource.implementation", default_str); - if (ttff_report_file.is_open()) - { - ttff_report_file << "---------------------------" << std::endl; - ttff_report_file << " Time-To-First-Fix Report" << std::endl; - ttff_report_file << "---------------------------" << std::endl; - ttff_report_file << "Initial receiver status: "; - if (read_ephemeris) - { - ttff_report_file << "Hot start." << std::endl; - } - else - { - ttff_report_file << "Cold start." << std::endl; - } - ttff_report_file << "A-GNSS: "; - if (agnss && read_ephemeris) - { - ttff_report_file << "Enabled." << std::endl; - } - else - { - ttff_report_file << "Disabled." << std::endl; - } - ttff_report_file << "Valid measurements (" << ttff.size() << "/" << FLAGS_num_measurements << "): "; - for(double ttff_ : ttff) ttff_report_file << ttff_ << " "; - ttff_report_file << std::endl; - ttff_report_file << "TTFF mean: " << mean << " [s]" << std::endl; - if (ttff.size() > 0) - { - ttff_report_file << "TTFF max: " << *max_ttff << " [s]" << std::endl; - ttff_report_file << "TTFF min: " << *min_ttff << " [s]" << std::endl; - } - ttff_report_file << "TTFF stdev: " << stdev << " [s]" << std::endl; - ttff_report_file << "Operating System: " << std::string(HOST_SYSTEM) << std::endl; - ttff_report_file << "Navigation mode: " << "3D" << std::endl; + std::stringstream stm; - if(source.compare("UHD_Signal_Source")) - { - ttff_report_file << "Source: File" << std::endl; - } - else - { - ttff_report_file << "Source: Live" << std::endl; - } - ttff_report_file << "---------------------------" << std::endl; - } - ttff_report_file.close(); - std::cout << "---------------------------" << std::endl; - std::cout << " Time-To-First-Fix Report" << std::endl; - std::cout << "---------------------------" << std::endl; - std::cout << "Initial receiver status: "; + stm << "---------------------------" << std::endl; + stm << " Time-To-First-Fix Report" << std::endl; + stm << "---------------------------" << std::endl; + stm << "Initial receiver status: "; if (read_ephemeris) { - std::cout << "Hot start." << std::endl; + stm << "Hot start." << std::endl; } else { - std::cout << "Cold start." << std::endl; + stm << "Cold start." << std::endl; } - std::cout << "A-GNSS: "; + stm << "A-GNSS: "; if (agnss && read_ephemeris) { - std::cout << "Enabled." << std::endl; + stm << "Enabled." << std::endl; } else { - std::cout << "Disabled." << std::endl; + stm << "Disabled." << std::endl; } - std::cout << "Valid measurements (" << ttff.size() << "/" << FLAGS_num_measurements << "): "; - for(double ttff_ : ttff) std::cout << ttff_ << " "; - std::cout << std::endl; - std::cout << "TTFF mean: " << mean << " [s]" << std::endl; + stm << "Valid measurements (" << ttff.size() << "/" << FLAGS_num_measurements << "): "; + for (double ttff_ : ttff) stm << ttff_ << " "; + stm << std::endl; + stm << "TTFF mean: " << mean << " [s]" << std::endl; if (ttff.size() > 0) { - std::cout << "TTFF max: " << *max_ttff << " [s]" << std::endl; - std::cout << "TTFF min: " << *min_ttff << " [s]" << std::endl; + stm << "TTFF max: " << *max_ttff << " [s]" << std::endl; + stm << "TTFF min: " << *min_ttff << " [s]" << std::endl; } - std::cout << "TTFF stdev: " << stdev << " [s]" << std::endl; - std::cout << "Operating System: " << std::string(HOST_SYSTEM) << std::endl; - std::cout << "Navigation mode: " << "3D" << std::endl; + stm << "TTFF stdev: " << stdev << " [s]" << std::endl; + stm << "Operating System: " << std::string(HOST_SYSTEM) << std::endl; + stm << "Navigation mode: " + << "3D" << std::endl; - if(source.compare("UHD_Signal_Source")) + if (source != "UHD_Signal_Source") { - std::cout << "Source: File" << std::endl; + stm << "Source: File" << std::endl; } else { - std::cout << "Source: Live" << std::endl; + stm << "Source: Live" << std::endl; + } + stm << "---------------------------" << std::endl; + + std::cout << stm.rdbuf(); + if (ttff_report_file.is_open()) + { + ttff_report_file << stm.str(); + ttff_report_file.close(); } - std::cout << "---------------------------" << std::endl; } -TEST_F(TTFF_GPS_L1_CA_Test, ColdStart) +TEST_F(TtffTest /*unused*/, ColdStart /*unused*/) { unsigned int num_measurements = 0; @@ -471,11 +432,11 @@ TEST_F(TTFF_GPS_L1_CA_Test, ColdStart) config2->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); config2->set_property("PVT.flag_rtcm_server", "false"); - for(int n = 0; n < FLAGS_num_measurements; n++) + for (int n = 0; n < FLAGS_num_measurements; n++) { // Create a new ControlThread object with a smart pointer std::shared_ptr control_thread; - if(FLAGS_config_file_ttff.empty()) + if (FLAGS_config_file_ttff.empty()) { control_thread = std::make_shared(config); } @@ -485,50 +446,49 @@ TEST_F(TTFF_GPS_L1_CA_Test, ColdStart) } // record startup time - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Starting measurement " << num_measurements + 1 << " / " << FLAGS_num_measurements << std::endl; - + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); // start receiver try - { + { control_thread->run(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception &e) + { std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } + } + catch (const std::exception &ex) + { + std::cout << "STD exception: " << ex.what(); + } // stop clock - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - double ttff = static_cast(end - begin) / 1000000.0; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + double ttff = elapsed_seconds.count(); std::shared_ptr flowgraph = control_thread->flowgraph(); EXPECT_FALSE(flowgraph->running()); num_measurements = num_measurements + 1; std::cout << "Just finished measurement " << num_measurements << ", which took " << ttff << " seconds." << std::endl; - if(n < FLAGS_num_measurements - 1) + if (n < FLAGS_num_measurements - 1) { - std::srand(std::time(0)); // use current time as seed for random generator - int random_variable = std::rand(); - float random_variable_0_1 = static_cast(random_variable) / static_cast( RAND_MAX ); + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_real_distribution uniform_dist(0, 1); + float random_variable_0_1 = uniform_dist(e1); int random_delay_s = static_cast(random_variable_0_1 * 25.0); std::cout << "Waiting a random amount of time (from 5 to 30 s) to start a new measurement... " << std::endl; - std::cout << "This time will wait " << random_delay_s + 5 << " s." << std::endl << std::endl; + std::cout << "This time will wait " << random_delay_s + 5 << " s." << std::endl + << std::endl; std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5) + std::chrono::seconds(random_delay_s)); } } // Print TTFF report - if(FLAGS_config_file_ttff.empty()) + if (FLAGS_config_file_ttff.empty()) { print_TTFF_report(TTFF_v, config); } @@ -536,11 +496,11 @@ TEST_F(TTFF_GPS_L1_CA_Test, ColdStart) { print_TTFF_report(TTFF_v, config2); } - std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5)); //let the USRP some time to rest before the next test + std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5)); //let the USRP some time to rest before the next test } -TEST_F(TTFF_GPS_L1_CA_Test, HotStart) +TEST_F(TtffTest /*unused*/, HotStart /*unused*/) { unsigned int num_measurements = 0; TTFF_v.clear(); @@ -556,11 +516,11 @@ TEST_F(TTFF_GPS_L1_CA_Test, HotStart) config2->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "true"); config2->set_property("PVT.flag_rtcm_server", "false"); - for(int n = 0; n < FLAGS_num_measurements; n++) + for (int n = 0; n < FLAGS_num_measurements; n++) { // Create a new ControlThread object with a smart pointer std::shared_ptr control_thread; - if(FLAGS_config_file_ttff.empty()) + if (FLAGS_config_file_ttff.empty()) { control_thread = std::make_shared(config); } @@ -569,50 +529,50 @@ TEST_F(TTFF_GPS_L1_CA_Test, HotStart) control_thread = std::make_shared(config2); } // record startup time - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Starting measurement " << num_measurements + 1 << " / " << FLAGS_num_measurements << std::endl; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); // start receiver try - { + { control_thread->run(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception &e) + { std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } + } + catch (const std::exception &ex) + { + std::cout << "STD exception: " << ex.what(); + } // stop clock - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - double ttff = static_cast(end - begin) / 1000000.0; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + double ttff = elapsed_seconds.count(); std::shared_ptr flowgraph = control_thread->flowgraph(); EXPECT_FALSE(flowgraph->running()); num_measurements = num_measurements + 1; std::cout << "Just finished measurement " << num_measurements << ", which took " << ttff << " seconds." << std::endl; - if(n < FLAGS_num_measurements - 1) + if (n < FLAGS_num_measurements - 1) { - std::srand(std::time(0)); // use current time as seed for random generator - int random_variable = std::rand(); - float random_variable_0_1 = static_cast(random_variable) / static_cast( RAND_MAX ); + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_real_distribution uniform_dist(0, 1); + float random_variable_0_1 = uniform_dist(e1); int random_delay_s = static_cast(random_variable_0_1 * 25.0); std::cout << "Waiting a random amount of time (from 5 to 30 s) to start new measurement... " << std::endl; - std::cout << "This time will wait " << random_delay_s + 5 << " s." << std::endl << std::endl; + std::cout << "This time will wait " << random_delay_s + 5 << " s." << std::endl + << std::endl; std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5) + std::chrono::seconds(random_delay_s)); } } // Print TTFF report - if(FLAGS_config_file_ttff.empty()) + if (FLAGS_config_file_ttff.empty()) { print_TTFF_report(TTFF_v, config); } @@ -629,10 +589,12 @@ int main(int argc, char **argv) int res = 0; TTFF_v.clear(); try - { + { testing::InitGoogleTest(&argc, argv); - } - catch(...) {} // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest + } + catch (...) + { + } // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest google::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); @@ -642,24 +604,24 @@ int main(int argc, char **argv) // Run the Tests try - { + { res = RUN_ALL_TESTS(); - } - catch(...) - { + } + catch (...) + { LOG(WARNING) << "Unexpected catch"; - } + } // Terminate the queue thread key_t sysv_msg_key; int sysv_msqid; sysv_msg_key = 1101; int msgflg = IPC_CREAT | 0666; - if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) - { - std::cout << "GNSS-SDR can not create message queues!" << std::endl; - exit(1); - } + if ((sysv_msqid = msgget(sysv_msg_key, msgflg)) == -1) + { + std::cout << "GNSS-SDR can not create message queues!" << std::endl; + return 1; + } ttff_msgbuf msg; msg.mtype = 1; msg.ttff = -1; diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index d97af1e8c..6a96003fd 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * -* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -16,7 +16,7 @@ * GNSS-SDR is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. +* (at your option) any later version. * * GNSS-SDR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,113 +24,150 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License -* along with GNSS-SDR. If not, see . +* along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "control_thread.h" +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" +#include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_navigation_message.h" +#include "gps_utc_model.h" +#include "sbas_ephemeris.h" #include +#include +#include #include #include #include #include -#include "concurrent_queue.h" -#include "concurrent_map.h" -#include "control_thread.h" -#include "gps_navigation_message.h" - -#include "gps_ephemeris.h" -#include "gps_cnav_ephemeris.h" -#include "gps_almanac.h" -#include "gps_iono.h" -#include "gps_cnav_iono.h" -#include "gps_utc_model.h" - -#include "galileo_ephemeris.h" -#include "galileo_almanac.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" - -#include "sbas_ephemeris.h" -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_satellite_correction.h" -#include "sbas_time.h" - +#include +#include +#include +#include using google::LogMessage; DECLARE_string(log_dir); +#if UNIT_TESTING_MINIMAL + +#include "unit-tests/arithmetic/matio_test.cc" +#if EXTRA_TESTS +#include "unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc" +#if ENABLE_FPGA +#include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc" +#endif +#include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc" +#endif + + +#else + +#include "unit-tests/arithmetic/matio_test.cc" +#include "unit-tests/arithmetic/code_generation_test.cc" #include "unit-tests/arithmetic/complex_carrier_test.cc" #include "unit-tests/arithmetic/conjugate_test.cc" +#include "unit-tests/arithmetic/fft_length_test.cc" +#include "unit-tests/arithmetic/fft_speed_test.cc" #include "unit-tests/arithmetic/magnitude_squared_test.cc" #include "unit-tests/arithmetic/multiply_test.cc" -#include "unit-tests/arithmetic/code_generation_test.cc" -#include "unit-tests/arithmetic/fft_length_test.cc" - -#include "unit-tests/control-plane/file_configuration_test.cc" -#include "unit-tests/control-plane/in_memory_configuration_test.cc" #include "unit-tests/control-plane/control_message_factory_test.cc" #include "unit-tests/control-plane/control_thread_test.cc" -#include "unit-tests/control-plane/gnss_flowgraph_test.cc" -#include "unit-tests/control-plane/string_converter_test.cc" +#include "unit-tests/control-plane/file_configuration_test.cc" #include "unit-tests/control-plane/gnss_block_factory_test.cc" - -#include "unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc" -#include "unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc" - -#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" - -#include "unit-tests/signal-processing-blocks/filter/fir_filter_test.cc" - -#include "unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc" - -#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc" +#include "unit-tests/control-plane/gnss_flowgraph_test.cc" +#include "unit-tests/control-plane/in_memory_configuration_test.cc" +#include "unit-tests/control-plane/string_converter_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc" -#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc" -//#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_multithread_acquisition_gsoc2013_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc" +#include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc" +#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" +#include "unit-tests/signal-processing-blocks/filter/fir_filter_test.cc" +#include "unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc" +#include "unit-tests/signal-processing-blocks/filter/notch_filter_test.cc" +#include "unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc" +#include "unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc" +#include "unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc" +#include "unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc" +#include "unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc" +#include "unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc" +// #include "unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc" + #if OPENCL_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc" #endif +#include "unit-tests/signal-processing-blocks/tracking/bayesian_estimation_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_real_codes_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc" #include "unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc" -#include "unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc" #if CUDA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/tracking/gpu_multicorrelator_test.cc" #endif -#include "unit-tests/signal-processing-blocks/pvt/rtcm_test.cc" -#include "unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc" +#if FPGA_BLOCKS_TEST +#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc" +#include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc" +#endif + +#include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" +#include "unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc" +#include "unit-tests/signal-processing-blocks/pvt/rtcm_test.cc" +#include "unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc" +#include "unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc" +#include "unit-tests/system-parameters/glonass_gnav_nav_message_test.cc" + #if EXTRA_TESTS +#include "unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc" +#include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc" -#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" -#if MODERN_ARMADILLO +#include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc" +#if ENABLE_FPGA +#include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc" +#endif +#include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc" #include "unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc" #endif -#endif + +#endif // UNIT_TESTING_MINIMAL // For GPS NAVIGATION (L1) concurrent_queue global_gps_acq_assist_queue; @@ -141,20 +178,22 @@ int main(int argc, char **argv) std::cout << "Running GNSS-SDR Tests..." << std::endl; int res = 0; try - { + { testing::InitGoogleTest(&argc, argv); - } - catch(...) {} // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest + } + catch (...) + { + } // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest google::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); try - { + { res = RUN_ALL_TESTS(); - } - catch(...) - { + } + catch (...) + { LOG(WARNING) << "Unexpected catch"; - } + } google::ShutDownCommandLineFlags(); return res; } diff --git a/src/tests/unit-tests/arithmetic/code_generation_test.cc b/src/tests/unit-tests/arithmetic/code_generation_test.cc index 204947e5e..d89b03365 100644 --- a/src/tests/unit-tests/arithmetic/code_generation_test.cc +++ b/src/tests/unit-tests/arithmetic/code_generation_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,20 +24,18 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include "gps_sdr_signal_processing.h" #include "gnss_signal_processing.h" +#include "gps_sdr_signal_processing.h" +#include +#include - -TEST(CodeGenGPSL1_Test, CodeGeneration) +TEST(CodeGenerationTest, CodeGenGPSL1Test) { std::complex* _dest = new std::complex[1023]; signed int _prn = 1; @@ -45,138 +43,75 @@ TEST(CodeGenGPSL1_Test, CodeGeneration) int iterations = 1000; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < iterations; i++) + for (int i = 0; i < iterations; i++) { - gps_l1_ca_code_gen_complex( _dest, _prn, _chip_shift); + gps_l1_ca_code_gen_complex(_dest, _prn, _chip_shift); } + + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + delete[] _dest; - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - ASSERT_LE(0, end - begin); - std::cout << "Generation completed in " << (end - begin) << " microseconds" << std::endl; - - - - /* std::complex* _dest2 = new std::complex[1023];gettimeofday(&tv, NULL); - long long int begin2 = tv.tv_sec * 1000000 + tv.tv_usec; - - for(int i = 0; i < iterations; i++) - { - gps_l1_ca_code_gen_complex2( _dest2, _prn, _chip_shift); - } - - gettimeofday(&tv, NULL); - long long int end2 = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Generation 2 completed in " << (end2 - begin2) << " microseconds" << std::endl; - - for (int j=0; j<1023;j++) - { - if(_dest[j] != _dest2[j]) std::cout << "Error!" << std::endl; - } - delete _dest2; */ + ASSERT_LE(0, elapsed_seconds.count()); + std::cout << "Generation completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - - -TEST(CodeGenGPSL1Sampled_Test, CodeGeneration) +TEST(CodeGenerationTest, CodeGenGPSL1SampledTest) { signed int _prn = 1; unsigned int _chip_shift = 4; - double _fs = 8000000; - const signed int _codeFreqBasis = 1023000; //Hz + double _fs = 8000000.0; + const signed int _codeFreqBasis = 1023000; //Hz const signed int _codeLength = 1023; - int _samplesPerCode = round(_fs / (double)(_codeFreqBasis / _codeLength)); + int _samplesPerCode = round(_fs / static_cast(_codeFreqBasis / _codeLength)); std::complex* _dest = new std::complex[_samplesPerCode]; int iterations = 1000; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < iterations; i++) + for (int i = 0; i < iterations; i++) { - gps_l1_ca_code_gen_complex_sampled( _dest, _prn, _fs, _chip_shift); + gps_l1_ca_code_gen_complex_sampled(_dest, _prn, _fs, _chip_shift); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + delete[] _dest; - ASSERT_LE(0, end - begin); - std::cout << "Generation completed in " << (end - begin) << " microseconds" << std::endl; - - - /* std::complex* _dest2 = new std::complex[_samplesPerCode]; - gettimeofday(&tv, NULL); - long long int begin2 = tv.tv_sec * 1000000 + tv.tv_usec; - - for(int i = 0; i < iterations; i++) - { - gps_l1_ca_code_gen_complex_sampled2( _dest2, _prn, _fs, _chip_shift); - } - - gettimeofday(&tv, NULL); - long long int end2 = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Generation completed in " << (end2 - begin2) << " microseconds (New)" << std::endl; - - for (int j=0; j<_samplesPerCode;j++) - { - if(_dest[j] != _dest2[j]) std::cout << "Error!" << std::endl; - } - delete[] _dest2; */ + ASSERT_LE(0, elapsed_seconds.count()); + std::cout << "Generation completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } -TEST(ComplexCarrier_Test, CodeGeneration) +TEST(CodeGenerationTest, ComplexConjugateTest) { - double _fs = 8000000; - double _f = 4000; - const signed int _codeFreqBasis = 1023000; //Hz + double _fs = 8000000.0; + double _f = 4000.0; + const signed int _codeFreqBasis = 1023000; //Hz const signed int _codeLength = 1023; - int _samplesPerCode = round(_fs / (double)(_codeFreqBasis / _codeLength)); + int _samplesPerCode = round(_fs / static_cast(_codeFreqBasis / _codeLength)); std::complex* _dest = new std::complex[_samplesPerCode]; int iterations = 1000; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < iterations; i++) + for (int i = 0; i < iterations; i++) { - complex_exp_gen_conj( _dest, _f, _fs, _samplesPerCode); + complex_exp_gen_conj(_dest, _f, _fs, _samplesPerCode); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - delete[] _dest; - ASSERT_LE(0, end - begin); - std::cout << "Carrier generation completed in " << (end - begin) << " microseconds" << std::endl; - - /* std::complex* _dest2 = new std::complex[_samplesPerCode]; - gettimeofday(&tv, NULL); - long long int begin2 = tv.tv_sec * 1000000 + tv.tv_usec; - - for(int i = 0; i < iterations; i++) - { - complex_exp_gen_conj2( _dest2, _f, _fs, _samplesPerCode); - } - - gettimeofday(&tv, NULL); - long long int end2 = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Carrier generation completed in " << (end2 - begin2) << " microseconds (New)" << std::endl; - - for (int j=0; j<_samplesPerCode;j++) - { - if(std::abs(_dest[j] - _dest2[j]) > 0.1) std::cout << "Error!" << std::endl; - } - - std::cout << _dest[10] << "and " << _dest2[10] << std::endl; - delete[] _dest2;*/ + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + delete[] _dest; + ASSERT_LE(0, elapsed_seconds.count()); + std::cout << "Generation completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } diff --git a/src/tests/unit-tests/arithmetic/complex_carrier_test.cc b/src/tests/unit-tests/arithmetic/complex_carrier_test.cc index a472ba367..3cac38fbe 100644 --- a/src/tests/unit-tests/arithmetic/complex_carrier_test.cc +++ b/src/tests/unit-tests/arithmetic/complex_carrier_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,88 +24,86 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include #include "gnss_signal_processing.h" +#include +#include +#include DEFINE_int32(size_carrier_test, 100000, "Size of the arrays used for complex carrier testing"); -TEST(ComplexCarrier_Test, StandardComplexImplementation) +TEST(ComplexCarrierTest, StandardComplexImplementation) { // Dynamic allocation creates new usable space on the program STACK // (an area of RAM specifically allocated to the program) std::complex* output = new std::complex[FLAGS_size_carrier_test]; - const double _f = 2000; - const double _fs = 2000000; - const double phase_step = (double)((GPS_TWO_PI * _f) / _fs); - double phase = 0; + const double _f = 2000.0; + const double _fs = 2000000.0; + const double phase_step = static_cast((GPS_TWO_PI * _f) / _fs); + double phase = 0.0; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < FLAGS_size_carrier_test; i++) - { - output[i] = std::complex(cos(phase), sin(phase)); - phase += phase_step; - } - - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "A " << FLAGS_size_carrier_test - << "-length complex carrier in standard C++ (dynamic allocation) generated in " << (end - begin) - << " microseconds" << std::endl; - - std::complex expected(1,0); - std::vector> mag(FLAGS_size_carrier_test); - for(int i = 0; i < FLAGS_size_carrier_test; i++) - { - mag[i] = output[i] * std::conj(output[i]); - } - delete[] output; - for(int i = 0; i < FLAGS_size_carrier_test; i++) - { - ASSERT_FLOAT_EQ(std::norm(expected), std::norm(mag[i])); - } - - ASSERT_LE(0, end - begin); -} - - -TEST(ComplexCarrier_Test, C11ComplexImplementation) -{ - // declaration: load data onto the program data segment - std::vector> output(FLAGS_size_carrier_test); - const double _f = 2000; - const double _fs = 2000000; - const double phase_step = (double)((GPS_TWO_PI * _f) / _fs); - double phase = 0; - - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; for (int i = 0; i < FLAGS_size_carrier_test; i++) { output[i] = std::complex(cos(phase), sin(phase)); phase += phase_step; } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "A " << FLAGS_size_carrier_test - << "-length complex carrier in standard C++ (declaration) generated in " << (end - begin) + << "-length complex carrier in standard C++ (dynamic allocation) generated in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); - std::complex expected(1,0); + + std::complex expected(1, 0); std::vector> mag(FLAGS_size_carrier_test); - for(int i = 0; i < FLAGS_size_carrier_test; i++) + for (int i = 0; i < FLAGS_size_carrier_test; i++) + { + mag[i] = output[i] * std::conj(output[i]); + } + delete[] output; + for (int i = 0; i < FLAGS_size_carrier_test; i++) + { + ASSERT_FLOAT_EQ(std::norm(expected), std::norm(mag[i])); + } + + ASSERT_LE(0, elapsed_seconds.count() * 1e6); +} + + +TEST(ComplexCarrierTest, C11ComplexImplementation) +{ + // declaration: load data onto the program data segment + std::vector> output(FLAGS_size_carrier_test); + const double _f = 2000.0; + const double _fs = 2000000.0; + const double phase_step = static_cast((GPS_TWO_PI * _f) / _fs); + double phase = 0.0; + + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); + + for (int i = 0; i < FLAGS_size_carrier_test; i++) + { + output[i] = std::complex(cos(phase), sin(phase)); + phase += phase_step; + } + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + std::cout << "A " << FLAGS_size_carrier_test + << "-length complex carrier in standard C++ (declaration) generated in " << elapsed_seconds.count() * 1e6 + << " microseconds" << std::endl; + ASSERT_LE(0, elapsed_seconds.count() * 1e6); + std::complex expected(1, 0); + std::vector> mag(FLAGS_size_carrier_test); + for (int i = 0; i < FLAGS_size_carrier_test; i++) { mag[i] = output[i] * std::conj(output[i]); ASSERT_FLOAT_EQ(std::norm(expected), std::norm(mag[i])); @@ -113,35 +111,32 @@ TEST(ComplexCarrier_Test, C11ComplexImplementation) } - - -TEST(ComplexCarrier_Test, OwnComplexImplementation) +TEST(ComplexCarrierTest, OwnComplexImplementation) { std::complex* output = new std::complex[FLAGS_size_carrier_test]; - double _f = 2000; - double _fs = 2000000; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + double _f = 2000.0; + double _fs = 2000000.0; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - complex_exp_gen(output, _f, _fs, (unsigned int)FLAGS_size_carrier_test); + complex_exp_gen(output, _f, _fs, static_cast(FLAGS_size_carrier_test)); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "A " << FLAGS_size_carrier_test - << "-length complex carrier using fixed point generated in " << (end - begin) + << "-length complex carrier using fixed point generated in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - std::complex expected(1,0); + std::complex expected(1, 0); std::vector> mag(FLAGS_size_carrier_test); - for(int i = 0; i < FLAGS_size_carrier_test; i++) + for (int i = 0; i < FLAGS_size_carrier_test; i++) { mag[i] = output[i] * std::conj(output[i]); } delete[] output; - for(int i = 0; i < FLAGS_size_carrier_test; i++) + for (int i = 0; i < FLAGS_size_carrier_test; i++) { ASSERT_NEAR(std::norm(expected), std::norm(mag[i]), 0.0001); } - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } diff --git a/src/tests/unit-tests/arithmetic/conjugate_test.cc b/src/tests/unit-tests/arithmetic/conjugate_test.cc index 11bf86932..1eaa4cc09 100644 --- a/src/tests/unit-tests/arithmetic/conjugate_test.cc +++ b/src/tests/unit-tests/arithmetic/conjugate_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,72 +24,68 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include #include #include #include +#include +#include +#include DEFINE_int32(size_conjugate_test, 100000, "Size of the arrays used for conjugate testing"); - -TEST(Conjugate_Test, StandardCComplexImplementation) +TEST(ConjugateTest, StandardCComplexImplementation) { std::complex* input = new std::complex[FLAGS_size_conjugate_test]; std::complex* output = new std::complex[FLAGS_size_conjugate_test]; - memset(input, 0, sizeof(std::complex) * FLAGS_size_conjugate_test); + std::fill_n(input, FLAGS_size_conjugate_test, std::complex(0.0, 0.0)); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < FLAGS_size_conjugate_test; i++) + for (int i = 0; i < FLAGS_size_conjugate_test; i++) { output[i] = std::conj(input[i]); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Conjugate of a " << FLAGS_size_conjugate_test - << "-length complex float vector in standard C finished in " << (end - begin) + << "-length complex float vector in standard C finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; delete[] input; delete[] output; - ASSERT_LE(0, end - begin); - + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } -TEST(Conjugate_Test, C11ComplexImplementation) +TEST(ConjugateTest, C11ComplexImplementation) { const std::vector> input(FLAGS_size_conjugate_test); std::vector> output(FLAGS_size_conjugate_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); int pos = 0; - for (const auto &item : input) + for (const auto& item : input) { output[pos++] = std::conj(item); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Conjugate of a " << FLAGS_size_conjugate_test - << " complex vector (C++11-style) finished in " << (end - begin) + << " complex vector (C++11-style) finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); - std::complex expected(0,0); - std::complex result(0,0); - for (const auto &item : output) + std::complex expected(0, 0); + std::complex result(0, 0); + for (const auto& item : output) { result += item; } @@ -97,44 +93,42 @@ TEST(Conjugate_Test, C11ComplexImplementation) } -TEST(Conjugate_Test, ArmadilloComplexImplementation) +TEST(ConjugateTest, ArmadilloComplexImplementation) { arma::cx_fvec input(FLAGS_size_conjugate_test, arma::fill::zeros); arma::cx_fvec output(FLAGS_size_conjugate_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); output = arma::conj(input); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Conjugate of a " << FLAGS_size_conjugate_test - << "-length complex float Armadillo vector finished in " << (end - begin) + << "-length complex float Armadillo vector finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } -TEST(Conjugate_Test, VolkComplexImplementation) +TEST(ConjugateTest, VolkComplexImplementation) { std::complex* input = static_cast*>(volk_gnsssdr_malloc(FLAGS_size_conjugate_test * sizeof(std::complex), volk_gnsssdr_get_alignment())); std::complex* output = static_cast*>(volk_gnsssdr_malloc(FLAGS_size_conjugate_test * sizeof(std::complex), volk_gnsssdr_get_alignment())); - memset(input, 0, sizeof(std::complex) * FLAGS_size_conjugate_test); + std::fill_n(input, FLAGS_size_conjugate_test, std::complex(0.0, 0.0)); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); volk_32fc_conjugate_32fc(output, input, FLAGS_size_conjugate_test); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "Conjugate of a "<< FLAGS_size_conjugate_test - << "-length complex float vector using VOLK finished in " << (end - begin) + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + std::cout << "Conjugate of a " << FLAGS_size_conjugate_test + << "-length complex float vector using VOLK finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); volk_gnsssdr_free(input); volk_gnsssdr_free(output); } diff --git a/src/tests/unit-tests/arithmetic/fft_length_test.cc b/src/tests/unit-tests/arithmetic/fft_length_test.cc index 649cd7a90..3e75c4285 100644 --- a/src/tests/unit-tests/arithmetic/fft_length_test.cc +++ b/src/tests/unit-tests/arithmetic/fft_length_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,43 +24,139 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include +#include "gnuplot_i.h" +#include "test_flags.h" +#include #include +#include +#include +#include +#include DEFINE_int32(fft_iterations_test, 1000, "Number of averaged iterations in FFT length timing test"); +DEFINE_bool(plot_fft_length_test, false, "Plots results of FFTLengthTest with gnuplot"); -TEST(FFT_Length_Test, MeasureExecutionTime) +// Note from FFTW documentation: the standard FFTW distribution works most efficiently for arrays whose +// size can be factored into small primes (2, 3, 5, and 7), and otherwise it uses a slower general-purpose routine. + +TEST(FFTLengthTest, MeasureExecutionTime) { + unsigned int fft_sizes[] = {512, 1000, 1024, 1100, 1297, 1400, 1500, 1960, 2000, 2048, 2221, 2500, 3000, 3500, 4000, + 4096, 4200, 4500, 4725, 5000, 5500, 6000, 6500, 7000, 7500, 8000, 8192, 8500, 9000, 9500, 10000, 10368, 11000, + 12000, 15000, 16000, 16384, 27000, 32768, 50000, 65536}; + + std::chrono::time_point start, end; + + std::random_device r; + std::default_random_engine e1(r()); + std::default_random_engine e2(r()); + std::uniform_real_distribution uniform_dist(-1, 1); + auto func = [](float a, float b) { return gr_complex(a, b); }; // Helper lambda function that returns a gr_complex + auto random_number1 = std::bind(uniform_dist, e1); + auto random_number2 = std::bind(uniform_dist, e2); + auto gen = std::bind(func, random_number1, random_number2); // Function that returns a random gr_complex + + std::vector fft_sizes_v(fft_sizes, fft_sizes + sizeof(fft_sizes) / sizeof(unsigned int)); + std::sort(fft_sizes_v.begin(), fft_sizes_v.end()); + std::vector::const_iterator it; unsigned int d_fft_size; - struct timeval tv; + std::vector execution_times; + std::vector powers_of_two; + std::vector execution_times_powers_of_two; - unsigned int fft_sizes [18] = { 1000, 1024, 1960, 2000, 2048, 4000, 4096, 4725, 8000, 8192, 10368, 12000, 16000, 16384, 27000, 32768, 50000, 65536 }; - double execution_times [18]; EXPECT_NO_THROW( - for(int i = 0; i < 18; i++) - { - gr::fft::fft_complex* d_fft; - d_fft_size = fft_sizes[i]; - d_fft = new gr::fft::fft_complex(d_fft_size, true); - std::fill_n( d_fft->get_inbuf(), d_fft_size, gr_complex( 0.0, 0.0 ) ); + for (it = fft_sizes_v.cbegin(); it != fft_sizes_v.cend(); ++it) { + gr::fft::fft_complex* d_fft; + d_fft_size = *it; + d_fft = new gr::fft::fft_complex(d_fft_size, true); - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; - for(int k = 0; k < FLAGS_fft_iterations_test; k++) - { - d_fft->execute(); - } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - execution_times[i] = static_cast(end - begin) / (1000000.0 * static_cast(FLAGS_fft_iterations_test)); - std::cout << "FFT execution time for length=" << d_fft_size << " : " << execution_times[i] << " [s]" << std::endl; - delete d_fft; + std::generate_n(d_fft->get_inbuf(), d_fft_size, gen); + + start = std::chrono::system_clock::now(); + for (int k = 0; k < FLAGS_fft_iterations_test; k++) + { + d_fft->execute(); } - ); + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + double exec_time = elapsed_seconds.count() / static_cast(FLAGS_fft_iterations_test); + execution_times.push_back(exec_time * 1e3); + std::cout << "FFT execution time for length=" << d_fft_size << " : " << exec_time << " [s]" << std::endl; + delete d_fft; + + if ((d_fft_size & (d_fft_size - 1)) == 0) // if it is a power of two + { + powers_of_two.push_back(d_fft_size); + execution_times_powers_of_two.push_back(exec_time / 1e-3); + } + }); + + if (FLAGS_plot_fft_length_test == true) + { + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_fft_length_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("linespoints"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("FFT execution times for different lengths"); + g1.set_grid(); + g1.set_xlabel("FFT length"); + g1.set_ylabel("Execution time [ms]"); + g1.plot_xy(fft_sizes_v, execution_times, "FFT execution time (averaged over " + std::to_string(FLAGS_fft_iterations_test) + " iterations)"); + g1.set_style("points").plot_xy(powers_of_two, execution_times_powers_of_two, "Power of 2"); + g1.savetops("FFT_execution_times_extended"); + g1.savetopdf("FFT_execution_times_extended", 18); + + Gnuplot g2("linespoints"); + if (FLAGS_show_plots) + { + g2.showonscreen(); // window output + } + else + { + g2.disablescreen(); + } + g2.set_title("FFT execution times for different lengths (up to 2^{14}=16384)"); + g2.set_grid(); + g2.set_xlabel("FFT length"); + g2.set_ylabel("Execution time [ms]"); + g2.set_xrange(0, 16384); + g2.plot_xy(fft_sizes_v, execution_times, "FFT execution time (averaged over " + std::to_string(FLAGS_fft_iterations_test) + " iterations)"); + g2.set_style("points").plot_xy(powers_of_two, execution_times_powers_of_two, "Power of 2"); + g2.savetops("FFT_execution_times"); + g2.savetopdf("FFT_execution_times", 18); + if (FLAGS_show_plots) g2.showonscreen(); // window output + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } } diff --git a/src/tests/unit-tests/arithmetic/fft_speed_test.cc b/src/tests/unit-tests/arithmetic/fft_speed_test.cc new file mode 100644 index 000000000..009b40838 --- /dev/null +++ b/src/tests/unit-tests/arithmetic/fft_speed_test.cc @@ -0,0 +1,79 @@ +/*! + * \file fft_speed_test.cc + * \brief This file implements timing tests for the Armadillo + * and GNU Radio FFT implementations + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +DEFINE_int32(fft_speed_iterations_test, 100, "Number of averaged iterations in FFT length timing test"); + +TEST(FFTSpeedTest, ArmadilloVSGNURadioExecutionTime) +{ + unsigned int d_fft_size; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + + unsigned int fft_sizes[19] = {16, 25, 32, 45, 64, 95, 128, 195, 256, 325, 512, 785, 1024, 1503, 2048, 3127, 4096, 6349, 8192}; + double d_execution_time; + EXPECT_NO_THROW( + for (int i = 0; i < 19; i++) { + d_fft_size = fft_sizes[i]; + gr::fft::fft_complex* d_gr_fft; + d_gr_fft = new gr::fft::fft_complex(d_fft_size, true); + arma::arma_rng::set_seed_random(); + arma::cx_fvec d_arma_fft = arma::cx_fvec(d_fft_size).randn() + gr_complex(0.0, 1.0) * arma::cx_fvec(d_fft_size).randn(); + arma::cx_fvec d_arma_fft_result(d_fft_size); + memcpy(d_gr_fft->get_inbuf(), d_arma_fft.memptr(), sizeof(gr_complex) * d_fft_size); + + start = std::chrono::system_clock::now(); + for (int k = 0; k < FLAGS_fft_speed_iterations_test; k++) + { + d_gr_fft->execute(); + } + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + d_execution_time = elapsed_seconds.count() / static_cast(FLAGS_fft_speed_iterations_test); + std::cout << "GNU Radio FFT execution time for length = " << d_fft_size << " : " << d_execution_time * 1e6 << " [us]" << std::endl; + delete d_gr_fft; + + start = std::chrono::system_clock::now(); + for (int k = 0; k < FLAGS_fft_speed_iterations_test; k++) + { + d_arma_fft_result = arma::fft(d_arma_fft); + } + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + d_execution_time = elapsed_seconds.count() / static_cast(FLAGS_fft_speed_iterations_test); + std::cout << "Armadillo FFT execution time for length = " << d_fft_size << " : " << d_execution_time * 1e6 << " [us]" << std::endl; + }); +} diff --git a/src/tests/unit-tests/arithmetic/magnitude_squared_test.cc b/src/tests/unit-tests/arithmetic/magnitude_squared_test.cc index 08cde0527..5a51b32be 100644 --- a/src/tests/unit-tests/arithmetic/magnitude_squared_test.cc +++ b/src/tests/unit-tests/arithmetic/magnitude_squared_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,69 +25,68 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include #include #include #include +#include +#include +#include DEFINE_int32(size_magnitude_test, 100000, "Size of the arrays used for magnitude testing"); -TEST(MagnitudeSquared_Test, StandardCComplexImplementation) +TEST(MagnitudeSquaredTest, StandardCComplexImplementation) { std::complex* input = new std::complex[FLAGS_size_magnitude_test]; float* output = new float[FLAGS_size_magnitude_test]; unsigned int number = 0; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(number = 0; number < (unsigned int)FLAGS_size_magnitude_test; number++) + for (number = 0; number < static_cast(FLAGS_size_magnitude_test); number++) { output[number] = (input[number].real() * input[number].real()) + (input[number].imag() * input[number].imag()); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test - << "-length vector in standard C computed in " << (end - begin) + << "-length vector in standard C computed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; delete[] input; delete[] output; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } -TEST(MagnitudeSquared_Test, C11ComplexImplementation) + +TEST(MagnitudeSquaredTest, C11ComplexImplementation) { const std::vector> input(FLAGS_size_magnitude_test); std::vector output(FLAGS_size_magnitude_test); - struct timeval tv; int pos = 0; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for (const auto &item : input) + for (const auto& item : input) { output[pos++] = std::norm(item); } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test - << " complex vector (C++11-style) finished in " << (end - begin) + << " complex vector (C++11-style) finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); - std::complex expected(0,0); - std::complex result(0,0); - for (const auto &item : output) + std::complex expected(0, 0); + std::complex result(0, 0); + for (const auto& item : output) { result += item; } @@ -95,46 +94,42 @@ TEST(MagnitudeSquared_Test, C11ComplexImplementation) } -TEST(MagnitudeSquared_Test, ArmadilloComplexImplementation) +TEST(MagnitudeSquaredTest, ArmadilloComplexImplementation) { arma::cx_fvec input(FLAGS_size_magnitude_test, arma::fill::zeros); arma::fvec output(FLAGS_size_magnitude_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); output = arma::abs(arma::square(input)); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test - << "-length vector using Armadillo computed in " << (end - begin) + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test + << "-length vector using Armadillo computed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } - -TEST(MagnitudeSquared_Test, VolkComplexImplementation) +TEST(MagnitudeSquaredTest, VolkComplexImplementation) { std::complex* input = static_cast*>(volk_gnsssdr_malloc(FLAGS_size_magnitude_test * sizeof(std::complex), volk_gnsssdr_get_alignment())); - memset(input, 0, sizeof(std::complex) * FLAGS_size_magnitude_test); + std::fill_n(input, FLAGS_size_magnitude_test, std::complex(0.0, 0.0)); float* output = static_cast(volk_gnsssdr_malloc(FLAGS_size_magnitude_test * sizeof(float), volk_gnsssdr_get_alignment())); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); volk_32fc_magnitude_squared_32f(output, input, static_cast(FLAGS_size_magnitude_test)); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test - << "-length vector using VOLK computed in " << (end - begin) + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + std::cout << "The squared magnitude of a " << FLAGS_size_magnitude_test + << "-length vector using VOLK computed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; volk_gnsssdr_free(input); volk_gnsssdr_free(output); - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); } // volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size); - diff --git a/src/tests/unit-tests/arithmetic/matio_test.cc b/src/tests/unit-tests/arithmetic/matio_test.cc new file mode 100644 index 000000000..681aa8a94 --- /dev/null +++ b/src/tests/unit-tests/arithmetic/matio_test.cc @@ -0,0 +1,160 @@ +/*! + * \file matio_test.cc + * \brief This file implements tests for the matio library + * in long arrays. + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +TEST(MatioTest, WriteAndReadDoubles) +{ + // Write a .mat file + mat_t *matfp; + matvar_t *matvar; + std::string filename = "./test.mat"; + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + ASSERT_FALSE(reinterpret_cast(matfp) == nullptr) << "Error creating .mat file"; + + double x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + size_t dims[2] = {10, 1}; + matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, x, 0); + ASSERT_FALSE(reinterpret_cast(matvar) == nullptr) << "Error creating variable for ’x’"; + + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + Mat_Close(matfp); + + // Read a .mat file + mat_t *matfp_read; + matvar_t *matvar_read; + + matfp_read = Mat_Open(filename.c_str(), MAT_ACC_RDONLY); + ASSERT_FALSE(reinterpret_cast(matfp_read) == nullptr) << "Error reading .mat file"; + + matvar_read = Mat_VarReadInfo(matfp_read, "x"); + ASSERT_FALSE(reinterpret_cast(matvar_read) == nullptr) << "Error reading variable in .mat file"; + + matvar_read = Mat_VarRead(matfp_read, "x"); + auto *x_read = reinterpret_cast(matvar_read->data); + Mat_Close(matfp_read); + + for (int i = 0; i < 10; i++) + { + EXPECT_DOUBLE_EQ(x[i], x_read[i]); + } + Mat_VarFree(matvar_read); + ASSERT_EQ(remove(filename.c_str()), 0); +} + + +TEST(MatioTest, WriteAndReadGrComplex) +{ + // Write a .mat file + mat_t *matfp; + matvar_t *matvar1; + std::string filename = "./test3.mat"; + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT73); + ASSERT_FALSE(reinterpret_cast(matfp) == nullptr) << "Error creating .mat file"; + + std::vector x_v = {{1, 10}, {2, 9}, {3, 8}, {4, 7}, {5, 6}, {6, -5}, {7, -4}, {8, 3}, {9, 2}, {10, 1}}; + const unsigned int size = x_v.size(); + float x_real[size]; + float x_imag[size]; + unsigned int i = 0; + for (auto it : x_v) + { + x_real[i] = it.real(); + x_imag[i] = it.imag(); + i++; + } + + struct mat_complex_split_t x = {x_real, x_imag}; + size_t dims[2] = {static_cast(size), 1}; + matvar1 = Mat_VarCreate("x", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, &x, MAT_F_COMPLEX); + ASSERT_FALSE(reinterpret_cast(matvar1) == nullptr) << "Error creating variable for ’x’"; + + std::vector x2 = {{1.1, -10}, {2, -9}, {3, -8}, {4, -7}, {5, 6}, {6, -5}, {7, -4}, {8, 3}, {9, 2}, {10, 1}}; + const unsigned int size_y = x2.size(); + float y_real[size_y]; + float y_imag[size_y]; + i = 0; + for (auto it : x2) + { + y_real[i] = it.real(); + y_imag[i] = it.imag(); + i++; + } + + struct mat_complex_split_t y = {y_real, y_imag}; + size_t dims_y[2] = {static_cast(size_y), 1}; + matvar_t *matvar2; + matvar2 = Mat_VarCreate("y", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims_y, &y, MAT_F_COMPLEX); + ASSERT_FALSE(reinterpret_cast(matvar2) == nullptr) << "Error creating variable for ’y’"; + + Mat_VarWrite(matfp, matvar1, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarWrite(matfp, matvar2, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar1); + Mat_VarFree(matvar2); + + Mat_Close(matfp); + + // Read a .mat file + mat_t *matfp_read; + matvar_t *matvar_read; + + matfp_read = Mat_Open(filename.c_str(), MAT_ACC_RDONLY); + ASSERT_FALSE(reinterpret_cast(matfp_read) == nullptr) << "Error reading .mat file"; + + matvar_read = Mat_VarReadInfo(matfp_read, "x"); + ASSERT_FALSE(reinterpret_cast(matvar_read) == nullptr) << "Error reading variable in .mat file"; + + matvar_read = Mat_VarRead(matfp_read, "x"); + auto *x_read_st = reinterpret_cast(matvar_read->data); + auto *x_read_real = reinterpret_cast(x_read_st->Re); + auto *x_read_imag = reinterpret_cast(x_read_st->Im); + std::vector x_v_read; + for (unsigned int i = 0; i < size; i++) + { + x_v_read.emplace_back(x_read_real[i], x_read_imag[i]); + } + + Mat_Close(matfp_read); + Mat_VarFree(matvar_read); + + for (unsigned int i = 0; i < size; i++) + { + EXPECT_FLOAT_EQ(x_v[i].real(), x_v_read[i].real()); + EXPECT_FLOAT_EQ(x_v[i].imag(), x_v_read[i].imag()); + } + ASSERT_EQ(remove(filename.c_str()), 0); +} diff --git a/src/tests/unit-tests/arithmetic/multiply_test.cc b/src/tests/unit-tests/arithmetic/multiply_test.cc index 64e9e4a90..f4747431f 100644 --- a/src/tests/unit-tests/arithmetic/multiply_test.cc +++ b/src/tests/unit-tests/arithmetic/multiply_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,180 +25,170 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include #include #include #include +#include +#include +#include +#include DEFINE_int32(size_multiply_test, 100000, "Size of the arrays used for multiply testing"); -TEST(Multiply_Test, StandardCDoubleImplementation) +TEST(MultiplyTest, StandardCDoubleImplementation) { double* input = new double[FLAGS_size_multiply_test]; double* output = new double[FLAGS_size_multiply_test]; - memset(input, 0, sizeof(double) * FLAGS_size_multiply_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::fill_n(input, FLAGS_size_multiply_test, 0.0); + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < FLAGS_size_multiply_test; i++) + for (int i = 0; i < FLAGS_size_multiply_test; i++) { output[i] = input[i] * input[i]; } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << " doubles in standard C finished in " << (end - begin) + << " doubles in standard C finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; double acc = 0; double expected = 0; - for(int i = 0; i < FLAGS_size_multiply_test; i++) + for (int i = 0; i < FLAGS_size_multiply_test; i++) { acc += output[i]; } delete[] input; delete[] output; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); ASSERT_EQ(expected, acc); } -TEST(Multiply_Test, ArmadilloImplementation) +TEST(MultiplyTest, ArmadilloImplementation) { arma::vec input(FLAGS_size_multiply_test, arma::fill::zeros); arma::vec output(FLAGS_size_multiply_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); output = input % input; - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << "-length double Armadillo vectors finished in " << (end - begin) + << "-length double Armadillo vectors finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); - ASSERT_EQ(0, arma::norm(output,2)); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); + ASSERT_EQ(0, arma::norm(output, 2)); } - -TEST(Multiply_Test, StandardCComplexImplementation) +TEST(MultiplyTest, StandardCComplexImplementation) { std::complex* input = new std::complex[FLAGS_size_multiply_test]; std::complex* output = new std::complex[FLAGS_size_multiply_test]; - memset(input, 0, sizeof(std::complex) * FLAGS_size_multiply_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::fill_n(input, FLAGS_size_multiply_test, std::complex(0.0, 0.0)); + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); - for(int i = 0; i < FLAGS_size_multiply_test; i++) + for (int i = 0; i < FLAGS_size_multiply_test; i++) { output[i] = input[i] * input[i]; } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << " complex in standard C finished in " << (end - begin) + << " complex in standard C finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - std::complex expected(0,0); - std::complex result(0,0); - for(int i = 0; i < FLAGS_size_multiply_test; i++) - { - result += output[i]; - } + std::complex expected(0, 0); + std::complex result(0, 0); + for (int i = 0; i < FLAGS_size_multiply_test; i++) + { + result += output[i]; + } delete[] input; delete[] output; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); ASSERT_EQ(expected, result); } - -TEST(Multiply_Test, C11ComplexImplementation) +TEST(MultiplyTest, C11ComplexImplementation) { const std::vector> input(FLAGS_size_multiply_test); std::vector> output(FLAGS_size_multiply_test); int pos = 0; - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); // Trying a range-based for - for (const auto &item : input) + for (const auto& item : input) { output[pos++] = item * item; } - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << " complex vector (C++11-style) finished in " << (end - begin) + << " complex vector (C++11-style) finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); - std::complex expected(0,0); + std::complex expected(0, 0); auto result = std::inner_product(output.begin(), output.end(), output.begin(), expected); ASSERT_EQ(expected, result); } -TEST(Multiply_Test, ArmadilloComplexImplementation) +TEST(MultiplyTest, ArmadilloComplexImplementation) { arma::cx_fvec input(FLAGS_size_multiply_test, arma::fill::zeros); arma::cx_fvec output(FLAGS_size_multiply_test); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); output = input % input; - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << "-length complex float Armadillo vectors finished in " << (end - begin) + << "-length complex float Armadillo vectors finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); - ASSERT_EQ(0, arma::norm(output,2)); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); + ASSERT_EQ(0, arma::norm(output, 2)); } - - -TEST(Multiply_Test, VolkComplexImplementation) +TEST(MultiplyTest, VolkComplexImplementation) { std::complex* input = static_cast*>(volk_gnsssdr_malloc(FLAGS_size_multiply_test * sizeof(std::complex), volk_gnsssdr_get_alignment())); std::complex* output = static_cast*>(volk_gnsssdr_malloc(FLAGS_size_multiply_test * sizeof(std::complex), volk_gnsssdr_get_alignment())); - memset(input, 0, sizeof(std::complex) * FLAGS_size_multiply_test); + std::fill_n(input, FLAGS_size_multiply_test, std::complex(0.0, 0.0)); - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); volk_32fc_x2_multiply_32fc(output, input, input, FLAGS_size_multiply_test); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; std::cout << "Element-wise multiplication of " << FLAGS_size_multiply_test - << "-length complex float vector using VOLK finished in " << (end - begin) + << "-length complex float vector using VOLK finished in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - ASSERT_LE(0, end - begin); + ASSERT_LE(0, elapsed_seconds.count() * 1e6); float* mag = static_cast(volk_gnsssdr_malloc(FLAGS_size_multiply_test * sizeof(float), volk_gnsssdr_get_alignment())); volk_32fc_magnitude_32f(mag, output, FLAGS_size_multiply_test); @@ -214,4 +204,3 @@ TEST(Multiply_Test, VolkComplexImplementation) volk_gnsssdr_free(output); volk_gnsssdr_free(mag); } - diff --git a/src/tests/unit-tests/control-plane/control_message_factory_test.cc b/src/tests/unit-tests/control-plane/control_message_factory_test.cc index a9dde3a02..7440d37f4 100644 --- a/src/tests/unit-tests/control-plane/control_message_factory_test.cc +++ b/src/tests/unit-tests/control-plane/control_message_factory_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,20 +25,18 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include #include "control_message_factory.h" +#include +#include - - -TEST(Control_Message_Factory_Test, GetQueueMessage) +TEST(ControlMessageFactoryTest, GetQueueMessage) { std::shared_ptr factory = std::make_shared(); gr::message::sptr queue_message = factory->GetQueueMessage(0, 2); @@ -51,9 +49,7 @@ TEST(Control_Message_Factory_Test, GetQueueMessage) } - - -TEST(Control_Message_Factory_Test, GetControlMessages) +TEST(ControlMessageFactoryTest, GetControlMessages) { std::shared_ptr factory = std::make_shared(); gr::message::sptr queue_message = gr::message::make(0, 0, 0, sizeof(ControlMessage)); @@ -74,7 +70,7 @@ TEST(Control_Message_Factory_Test, GetControlMessages) /* -TEST(Control_Message_Factory_Test, GetControlMessagesWrongSize) +TEST(ControlMessageFactoryTest, GetControlMessagesWrongSize) { std::shared_ptr factory = std::make_shared(); diff --git a/src/tests/unit-tests/control-plane/control_thread_test.cc b/src/tests/unit-tests/control-plane/control_thread_test.cc index 7981b4d0e..0155cb227 100644 --- a/src/tests/unit-tests/control-plane/control_thread_test.cc +++ b/src/tests/unit-tests/control-plane/control_thread_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,46 +25,46 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include +#include "control_message_factory.h" +#include "control_thread.h" +#include "in_memory_configuration.h" +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include #include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "control_thread.h" -#include "in_memory_configuration.h" -#include "control_message_factory.h" +#include -class Control_Thread_Test: public ::testing::Test +class ControlThreadTest : public ::testing::Test { public: static int stop_receiver(); - typedef struct { - long mtype; // required by SysV message + typedef struct + { + long mtype; // required by SysV message double message; } message_buffer; }; -int Control_Thread_Test::stop_receiver() +int ControlThreadTest::stop_receiver() { message_buffer msg_stop; msg_stop.mtype = 1; @@ -74,10 +74,12 @@ int Control_Thread_Test::stop_receiver() key_t key_stop = 1102; // wait for the receiver control queue to be created - while(((msqid_stop = msgget(key_stop, 0644))) == -1){ } + while (((msqid_stop = msgget(key_stop, 0644))) == -1) + { + } // wait for a couple of seconds - std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(2)); + std::this_thread::sleep_for(std::chrono::seconds(2)); // Stop the receiver msgsnd(msqid_stop, &msg_stop, msgsend_size, IPC_NOWAIT); @@ -86,14 +88,14 @@ int Control_Thread_Test::stop_receiver() } -TEST_F(Control_Thread_Test, InstantiateRunControlMessages) +TEST_F(ControlThreadTest /*unused*/, InstantiateRunControlMessages /*unused*/) { std::shared_ptr config = std::make_shared(); config->set_property("SignalSource.implementation", "File_Signal_Source"); std::string path = std::string(TEST_PATH); std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; - const char * file_name = file.c_str(); + const char* file_name = file.c_str(); config->set_property("SignalSource.filename", file_name); config->set_property("SignalSource.item_type", "gr_complex"); config->set_property("SignalSource.sampling_frequency", "4000000"); @@ -111,10 +113,11 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages) config->set_property("Tracking_1C.item_type", "gr_complex"); config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); config->set_property("TelemetryDecoder_1C.item_type", "gr_complex"); - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + config->set_property("Observables.implementation", "Hybrid_Observables"); config->set_property("Observables.item_type", "gr_complex"); - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); config->set_property("PVT.item_type", "gr_complex"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); std::shared_ptr control_thread = std::make_shared(config); @@ -122,23 +125,23 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages) std::unique_ptr control_msg_factory(new ControlMessageFactory()); - control_queue->handle(control_msg_factory->GetQueueMessage(0,0)); - control_queue->handle(control_msg_factory->GetQueueMessage(1,0)); - control_queue->handle(control_msg_factory->GetQueueMessage(200,0)); + control_queue->handle(control_msg_factory->GetQueueMessage(0, 0)); + control_queue->handle(control_msg_factory->GetQueueMessage(1, 0)); + control_queue->handle(control_msg_factory->GetQueueMessage(200, 0)); control_thread->set_control_queue(control_queue); try - { + { control_thread->run(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } + } + catch (const std::exception& ex) + { + std::cout << "STD exception: " << ex.what(); + } unsigned int expected3 = 3; unsigned int expected1 = 1; @@ -147,13 +150,13 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages) } -TEST_F(Control_Thread_Test, InstantiateRunControlMessages2) +TEST_F(ControlThreadTest /*unused*/, InstantiateRunControlMessages2 /*unused*/) { std::shared_ptr config = std::make_shared(); config->set_property("SignalSource.implementation", "File_Signal_Source"); std::string path = std::string(TEST_PATH); std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; - const char * file_name = file.c_str(); + const char* file_name = file.c_str(); config->set_property("SignalSource.filename", file_name); config->set_property("SignalSource.item_type", "gr_complex"); config->set_property("SignalSource.sampling_frequency", "4000000"); @@ -171,10 +174,11 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages2) config->set_property("Tracking_1C.item_type", "gr_complex"); config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); config->set_property("TelemetryDecoder_1C.item_type", "gr_complex"); - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + config->set_property("Observables.implementation", "Hybrid_Observables"); config->set_property("Observables.item_type", "gr_complex"); - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); config->set_property("PVT.item_type", "gr_complex"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); std::unique_ptr control_thread2(new ControlThread(config)); @@ -182,26 +186,26 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages2) std::unique_ptr control_msg_factory2(new ControlMessageFactory()); - control_queue2->handle(control_msg_factory2->GetQueueMessage(0,0)); - control_queue2->handle(control_msg_factory2->GetQueueMessage(2,0)); - control_queue2->handle(control_msg_factory2->GetQueueMessage(1,0)); - control_queue2->handle(control_msg_factory2->GetQueueMessage(3,0)); - control_queue2->handle(control_msg_factory2->GetQueueMessage(200,0)); + control_queue2->handle(control_msg_factory2->GetQueueMessage(0, 0)); + control_queue2->handle(control_msg_factory2->GetQueueMessage(2, 0)); + control_queue2->handle(control_msg_factory2->GetQueueMessage(1, 0)); + control_queue2->handle(control_msg_factory2->GetQueueMessage(3, 0)); + control_queue2->handle(control_msg_factory2->GetQueueMessage(200, 0)); control_thread2->set_control_queue(control_queue2); try - { + { control_thread2->run(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } + } + catch (const std::exception& ex) + { + std::cout << "STD exception: " << ex.what(); + } unsigned int expected5 = 5; unsigned int expected1 = 1; @@ -210,14 +214,13 @@ TEST_F(Control_Thread_Test, InstantiateRunControlMessages2) } - -TEST_F(Control_Thread_Test, StopReceiverProgrammatically) +TEST_F(ControlThreadTest /*unused*/, StopReceiverProgrammatically /*unused*/) { std::shared_ptr config = std::make_shared(); config->set_property("SignalSource.implementation", "File_Signal_Source"); std::string path = std::string(TEST_PATH); std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; - const char * file_name = file.c_str(); + const char* file_name = file.c_str(); config->set_property("SignalSource.filename", file_name); config->set_property("SignalSource.item_type", "gr_complex"); config->set_property("SignalSource.sampling_frequency", "4000000"); @@ -235,29 +238,30 @@ TEST_F(Control_Thread_Test, StopReceiverProgrammatically) config->set_property("Tracking_1C.item_type", "gr_complex"); config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); config->set_property("TelemetryDecoder_1C.item_type", "gr_complex"); - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + config->set_property("Observables.implementation", "Hybrid_Observables"); config->set_property("Observables.item_type", "gr_complex"); - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); config->set_property("PVT.item_type", "gr_complex"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); - std::unique_ptr control_thread(new ControlThread(config)); + std::shared_ptr control_thread = std::make_shared(config); gr::msg_queue::sptr control_queue = gr::msg_queue::make(0); control_thread->set_control_queue(control_queue); std::thread stop_receiver_thread(stop_receiver); try - { + { control_thread->run(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { std::cout << "Boost exception: " << boost::diagnostic_information(e); - } - catch(std::exception const& ex) - { - std::cout << "STD exception: " << ex.what(); - } + } + catch (const std::exception& ex) + { + std::cout << "STD exception: " << ex.what(); + } stop_receiver_thread.join(); } diff --git a/src/tests/unit-tests/control-plane/file_configuration_test.cc b/src/tests/unit-tests/control-plane/file_configuration_test.cc index eba589357..6f7661f30 100644 --- a/src/tests/unit-tests/control-plane/file_configuration_test.cc +++ b/src/tests/unit-tests/control-plane/file_configuration_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,19 +24,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include #include "file_configuration.h" +#include - -TEST(File_Configuration_Test, OverridedProperties) +TEST(FileConfigurationTest, OverridedProperties) { std::string path = std::string(TEST_PATH); std::string filename = path + "data/config_file_sample.txt"; @@ -51,8 +49,7 @@ TEST(File_Configuration_Test, OverridedProperties) } - -TEST(File_Configuration_Test, LoadFromNonExistentFile) +TEST(FileConfigurationTest, LoadFromNonExistentFile) { std::unique_ptr configuration(new FileConfiguration("./i_dont_exist.conf")); std::string default_value = "default_value"; @@ -61,8 +58,7 @@ TEST(File_Configuration_Test, LoadFromNonExistentFile) } - -TEST(File_Configuration_Test, PropertyDoesNotExist) +TEST(FileConfigurationTest, PropertyDoesNotExist) { std::string path = std::string(TEST_PATH); std::string filename = path + "data/config_file_sample.txt"; diff --git a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc index e5c9b473d..9eff70397 100644 --- a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc +++ b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,25 +28,25 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include "in_memory_configuration.h" -#include "gnss_block_interface.h" #include "acquisition_interface.h" -#include "tracking_interface.h" -#include "telemetry_decoder_interface.h" +#include "channel.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "in_memory_configuration.h" #include "observables_interface.h" #include "pvt_interface.h" -#include "gnss_block_factory.h" -#include "channel.h" +#include "telemetry_decoder_interface.h" +#include "tracking_interface.h" +#include +#include +#include -TEST(GNSS_Block_Factory_Test, InstantiateFileSignalSource) +TEST(GNSSBlockFactoryTest, InstantiateFileSignalSource) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("SignalSource.implementation", "File_Signal_Source"); @@ -63,7 +63,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateFileSignalSource) } -TEST(GNSS_Block_Factory_Test, InstantiateWrongSignalSource) +TEST(GNSSBlockFactoryTest, InstantiateWrongSignalSource) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("SignalSource.implementation", "Pepito"); @@ -76,7 +76,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateWrongSignalSource) } -TEST(GNSS_Block_Factory_Test, InstantiateSignalConditioner) +TEST(GNSSBlockFactoryTest, InstantiateSignalConditioner) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("SignalConditioner.implementation", "Signal_Conditioner"); @@ -87,7 +87,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateSignalConditioner) } -TEST(GNSS_Block_Factory_Test, InstantiateFIRFilter) +TEST(GNSSBlockFactoryTest, InstantiateFIRFilter) { std::shared_ptr configuration = std::make_shared(); gr::msg_queue::sptr queue = gr::msg_queue::make(0); @@ -120,7 +120,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateFIRFilter) EXPECT_STREQ("Fir_Filter", input_filter->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateFreqXlatingFIRFilter) +TEST(GNSSBlockFactoryTest, InstantiateFreqXlatingFIRFilter) { std::shared_ptr configuration = std::make_shared(); gr::msg_queue::sptr queue = gr::msg_queue::make(0); @@ -146,8 +146,8 @@ TEST(GNSS_Block_Factory_Test, InstantiateFreqXlatingFIRFilter) configuration->set_property("InputFilter.filter_type", "bandpass"); configuration->set_property("InputFilter.grid_density", "16"); - configuration->set_property("InputFilter.sampling_frequency","4000000"); - configuration->set_property("InputFilter.IF","34000"); + configuration->set_property("InputFilter.sampling_frequency", "4000000"); + configuration->set_property("InputFilter.IF", "34000"); std::unique_ptr factory; std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Freq_Xlating_Fir_Filter", 1, 1); @@ -155,7 +155,46 @@ TEST(GNSS_Block_Factory_Test, InstantiateFreqXlatingFIRFilter) EXPECT_STREQ("Freq_Xlating_Fir_Filter", input_filter->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateDirectResampler) +TEST(GNSSBlockFactoryTest, InstantiatePulseBlankingFilter) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Pulse_Blanking_Filter"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Pulse_Blanking_Filter", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Pulse_Blanking_Filter", input_filter->implementation().c_str()); +} + +TEST(GNSSBlockFactoryTest, InstantiateNotchFilter) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Notch_Filter"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Notch_Filter", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Notch_Filter", input_filter->implementation().c_str()); +} + +TEST(GNSSBlockFactoryTest, InstantiateNotchFilterLite) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Notch_Filter_Lite"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Notch_Filter_Lite", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Notch_Filter_Lite", input_filter->implementation().c_str()); +} + +TEST(GNSSBlockFactoryTest, InstantiateDirectResampler) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Resampler.implementation", "Direct_Resampler"); @@ -165,54 +204,54 @@ TEST(GNSS_Block_Factory_Test, InstantiateDirectResampler) EXPECT_STREQ("Direct_Resampler", resampler->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaPcpsAcquisition) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaPcpsAcquisition) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition"); std::unique_ptr factory; - std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "GPS_L1_CA_PCPS_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "GPS_L1_CA_PCPS_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); EXPECT_STREQ("Acquisition", acquisition->role().c_str()); EXPECT_STREQ("GPS_L1_CA_PCPS_Acquisition", acquisition->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaPcpsQuickSyncAcquisition) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaPcpsQuickSyncAcquisition) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); std::shared_ptr factory = std::make_shared(); - std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "GPS_L1_CA_PCPS_QuickSync_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "GPS_L1_CA_PCPS_QuickSync_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); EXPECT_STREQ("Acquisition", acquisition->role().c_str()); EXPECT_STREQ("GPS_L1_CA_PCPS_QuickSync_Acquisition", acquisition->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateGalileoE1PcpsQuickSyncAmbiguousAcquisition) +TEST(GNSSBlockFactoryTest, InstantiateGalileoE1PcpsQuickSyncAmbiguousAcquisition) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Acquisition.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); std::shared_ptr factory = std::make_shared(); - std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); EXPECT_STREQ("Acquisition", acquisition->role().c_str()); EXPECT_STREQ("Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", acquisition->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateGalileoE1PcpsAmbiguousAcquisition) +TEST(GNSSBlockFactoryTest, InstantiateGalileoE1PcpsAmbiguousAcquisition) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); std::unique_ptr factory; - std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(configuration, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); EXPECT_STREQ("Acquisition", acquisition->role().c_str()); EXPECT_STREQ("Galileo_E1_PCPS_Ambiguous_Acquisition", acquisition->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaDllPllCAidTracking) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaDllPllCAidTracking) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Tracking.implementation", "GPS_L1_CA_DLL_PLL_C_Aid_Tracking"); @@ -224,7 +263,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaDllPllCAidTracking) } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaDllPllTracking) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaDllPllTracking) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Tracking.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); @@ -236,7 +275,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaDllPllTracking) } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaTcpConnectorTracking) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaTcpConnectorTracking) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Tracking.implementation", "GPS_L1_CA_TCP_CONNECTOR_Tracking"); @@ -248,7 +287,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaTcpConnectorTracking) } -TEST(GNSS_Block_Factory_Test, InstantiateGalileoE1DllPllVemlTracking) +TEST(GNSSBlockFactoryTest, InstantiateGalileoE1DllPllVemlTracking) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Tracking.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking"); @@ -260,7 +299,7 @@ TEST(GNSS_Block_Factory_Test, InstantiateGalileoE1DllPllVemlTracking) } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaTelemetryDecoder) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaTelemetryDecoder) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); @@ -271,26 +310,26 @@ TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaTelemetryDecoder) } -TEST(GNSS_Block_Factory_Test, InstantiateChannels) +TEST(GNSSBlockFactoryTest, InstantiateChannels) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Channels_1C.count", "2"); configuration->set_property("Channels_1E.count", "0"); configuration->set_property("Channels.in_acquisition", "2"); - configuration->set_property("Tracking_1C.implementation","GPS_L1_CA_DLL_PLL_C_Aid_Tracking"); - configuration->set_property("TelemetryDecoder_1C.implementation","GPS_L1_CA_Telemetry_Decoder"); + configuration->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_C_Aid_Tracking"); + configuration->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); configuration->set_property("Channel0.item_type", "gr_complex"); configuration->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); configuration->set_property("Channel1.item_type", "gr_complex"); gr::msg_queue::sptr queue = gr::msg_queue::make(0); std::unique_ptr factory; - std::unique_ptr>> channels = std::move(factory->GetChannels(configuration, queue)); - EXPECT_EQ((unsigned int) 2, channels->size()); + std::unique_ptr>> channels = factory->GetChannels(configuration, queue); + EXPECT_EQ(static_cast(2), channels->size()); channels->erase(channels->begin(), channels->end()); } -TEST(GNSS_Block_Factory_Test, InstantiateObservables) +TEST(GNSSBlockFactoryTest, InstantiateObservables) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("Observables.implementation", "Pass_Through"); @@ -301,43 +340,30 @@ TEST(GNSS_Block_Factory_Test, InstantiateObservables) } -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaObservables) +TEST(GNSSBlockFactoryTest, InstantiateGpsL1CaObservables) { std::shared_ptr configuration = std::make_shared(); - configuration->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + configuration->set_property("Observables.implementation", "Hybrid_Observables"); std::unique_ptr factory; std::unique_ptr observables = factory->GetObservables(configuration); EXPECT_STREQ("Observables", observables->role().c_str()); - EXPECT_STREQ("GPS_L1_CA_Observables", observables->implementation().c_str()); + EXPECT_STREQ("Hybrid_Observables", observables->implementation().c_str()); } - - -TEST(GNSS_Block_Factory_Test, InstantiatePvt) +TEST(GNSSBlockFactoryTest, InstantiateRTKLIBPvt) { std::shared_ptr configuration = std::make_shared(); - configuration->set_property("PVT.implementation", "Pass_Through"); - std::unique_ptr factory; - auto pvt_ = factory->GetPVT(configuration); - EXPECT_STREQ("PVT", pvt_->role().c_str()); - EXPECT_STREQ("Pass_Through", pvt_->implementation().c_str()); -} - - -TEST(GNSS_Block_Factory_Test, InstantiateGpsL1CaPvt) -{ - std::shared_ptr configuration = std::make_shared(); - configuration->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + configuration->set_property("PVT.implementation", "RTKLIB_PVT"); std::unique_ptr factory; std::shared_ptr pvt_ = factory->GetPVT(configuration); std::shared_ptr pvt = std::dynamic_pointer_cast(pvt_); EXPECT_STREQ("PVT", pvt->role().c_str()); - EXPECT_STREQ("GPS_L1_CA_PVT", pvt->implementation().c_str()); + EXPECT_STREQ("RTKLIB_PVT", pvt->implementation().c_str()); } -TEST(GNSS_Block_Factory_Test, InstantiateWrongPvt) +TEST(GNSSBlockFactoryTest, InstantiateWrongPvt) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("PVT.implementation", "Pepito"); @@ -346,4 +372,3 @@ TEST(GNSS_Block_Factory_Test, InstantiateWrongPvt) std::shared_ptr pvt = std::dynamic_pointer_cast(pvt_); EXPECT_EQ(nullptr, pvt); } - diff --git a/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc b/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc index 7719dc8d1..711b49d5f 100644 --- a/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc +++ b/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,30 +25,31 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#include "acquisition_interface.h" +#include "channel.h" +#include "channel_interface.h" +#include "file_configuration.h" +#include "file_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_flowgraph.h" +#include "in_memory_configuration.h" +#include "pass_through.h" +#include "tracking_interface.h" #include #include -#include "gnss_flowgraph.h" -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "file_configuration.h" -#include "channel.h" -#include "acquisition_interface.h" -#include "tracking_interface.h" -#include "channel_interface.h" -#include "pass_through.h" -#include "file_signal_source.h" -TEST(GNSSFlowgraph, InstantiateConnectStartStopOldNotation) +TEST(GNSSFlowgraph /*unused*/, InstantiateConnectStartStopOldNotation /*unused*/) { std::shared_ptr config = std::make_shared(); config->set_property("GNSS-SDR.SUPL_gps_enabled", "false"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("SignalSource.sampling_frequency", "4000000"); config->set_property("SignalSource.implementation", "File_Signal_Source"); config->set_property("SignalSource.item_type", "gr_complex"); @@ -64,8 +65,8 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopOldNotation) config->set_property("Acquisition_1C.doppler_max", "5000"); config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("Observables.implementation", "Hybrid_Observables"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); std::shared_ptr flowgraph = std::make_shared(config, gr::msg_queue::make(0)); @@ -79,10 +80,10 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopOldNotation) } -TEST(GNSSFlowgraph, InstantiateConnectStartStop) +TEST(GNSSFlowgraph /*unused*/, InstantiateConnectStartStop /*unused*/) { std::shared_ptr config = std::make_shared(); - + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("SignalSource.sampling_frequency", "4000000"); config->set_property("SignalSource.implementation", "File_Signal_Source"); config->set_property("SignalSource.item_type", "gr_complex"); @@ -99,8 +100,8 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStop) config->set_property("Acquisition_1C.doppler_max", "5000"); config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); - config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("Observables.implementation", "Hybrid_Observables"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); std::shared_ptr flowgraph = std::make_shared(config, gr::msg_queue::make(0)); @@ -113,10 +114,10 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStop) EXPECT_FALSE(flowgraph->running()); } -TEST(GNSSFlowgraph, InstantiateConnectStartStopGalileoE1B) +TEST(GNSSFlowgraph /*unused*/, InstantiateConnectStartStopGalileoE1B /*unused*/) { std::shared_ptr config = std::make_shared(); - + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("SignalSource.sampling_frequency", "4000000"); config->set_property("SignalSource.implementation", "File_Signal_Source"); config->set_property("SignalSource.item_type", "gr_complex"); @@ -133,8 +134,8 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopGalileoE1B) config->set_property("Acquisition_1B.doppler_max", "5000"); config->set_property("Tracking_1B.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking"); config->set_property("TelemetryDecoder_1B.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("Observables.implementation", "Galileo_E1B_Observables"); - config->set_property("PVT.implementation", "GALILEO_E1_PVT"); + config->set_property("Observables.implementation", "Hybrid_Observables"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); std::shared_ptr flowgraph = std::make_shared(config, gr::msg_queue::make(0)); @@ -148,10 +149,10 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopGalileoE1B) } -TEST(GNSSFlowgraph, InstantiateConnectStartStopHybrid) +TEST(GNSSFlowgraph /*unused*/, InstantiateConnectStartStopHybrid /*unused*/) { std::shared_ptr config = std::make_shared(); - + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("SignalSource.sampling_frequency", "4000000"); config->set_property("SignalSource.implementation", "File_Signal_Source"); config->set_property("SignalSource.item_type", "gr_complex"); @@ -232,41 +233,25 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopHybrid) config->set_property("Tracking_1B15.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking"); config->set_property("TelemetryDecoder_1C0.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C0.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C1.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C1.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C2.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C2.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C3.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C3.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C4.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C4.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C5.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C5.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C6.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C6.decimation_factor", "4"); config->set_property("TelemetryDecoder_1C7.implementation", "GPS_L1_CA_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1C7.decimation_factor", "4"); config->set_property("TelemetryDecoder_1B8.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B8.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B9.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B9.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B10.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B10.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B11.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B11.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B12.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B12.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B13.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B13.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B14.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B14.decimation_factor", "1"); config->set_property("TelemetryDecoder_1B15.implementation", "Galileo_E1B_Telemetry_Decoder"); - config->set_property("TelemetryDecoder_1B15.decimation_factor", "1"); config->set_property("Observables.implementation", "Hybrid_Observables"); - config->set_property("PVT.implementation", "Hybrid_PVT"); + config->set_property("PVT.implementation", "RTKLIB_PVT"); std::shared_ptr flowgraph = std::make_shared(config, gr::msg_queue::make(0)); @@ -278,4 +263,3 @@ TEST(GNSSFlowgraph, InstantiateConnectStartStopHybrid) flowgraph->stop(); EXPECT_FALSE(flowgraph->running()); } - diff --git a/src/tests/unit-tests/control-plane/in_memory_configuration_test.cc b/src/tests/unit-tests/control-plane/in_memory_configuration_test.cc index e54871d0c..a92222623 100644 --- a/src/tests/unit-tests/control-plane/in_memory_configuration_test.cc +++ b/src/tests/unit-tests/control-plane/in_memory_configuration_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/tests/unit-tests/control-plane/string_converter_test.cc b/src/tests/unit-tests/control-plane/string_converter_test.cc index 65ceb93f7..2cd52496b 100644 --- a/src/tests/unit-tests/control-plane/string_converter_test.cc +++ b/src/tests/unit-tests/control-plane/string_converter_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,7 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -33,8 +33,7 @@ #include "string_converter.h" - -TEST(String_Converter_Test, StringToBool) +TEST(StringConverterTest, StringToBool) { std::unique_ptr converter(new StringConverter()); bool conversion_result = converter->convert("false", true); @@ -43,7 +42,7 @@ TEST(String_Converter_Test, StringToBool) } -TEST(String_Converter_Test, StringToSizeT) +TEST(StringConverterTest, StringToSizeT) { // Example using a raw pointer StringConverter* converter; @@ -55,9 +54,7 @@ TEST(String_Converter_Test, StringToSizeT) } - - -TEST(String_Converter_Test, StringToBoolFail) +TEST(StringConverterTest, StringToBoolFail) { std::unique_ptr converter(new StringConverter()); bool conversion_result = converter->convert("lse", true); @@ -66,9 +63,7 @@ TEST(String_Converter_Test, StringToBoolFail) } - - -TEST(String_Converter_Test, StringToSizeTFail) +TEST(StringConverterTest, StringToSizeTFail) { std::unique_ptr converter(new StringConverter()); size_t conversion_result = converter->convert("false", 1); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc new file mode 100644 index 000000000..8b738eebf --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc @@ -0,0 +1,1089 @@ +/*! + * \file acq_performance_test.cc + * \brief This class implements an acquisition performance test + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.cat + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "acquisition_dump_reader.h" +#include "display.h" +#include "file_configuration.h" +#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "galileo_e5a_pcps_acquisition.h" +#include "glonass_l1_ca_pcps_acquisition.h" +#include "glonass_l2_ca_pcps_acquisition.h" +#include "gnss_sdr_valve.h" +#include "gnuplot_i.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" +#include "gps_l2_m_pcps_acquisition.h" +#include "gps_l5i_pcps_acquisition.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "test_flags.h" +#include "tracking_true_obs_reader.h" +#include "true_observables_reader.h" +#include +#include +#include +#include +#include + + +DEFINE_string(config_file_ptest, std::string(""), "File containing alternative configuration parameters for the acquisition performance test."); +DEFINE_string(acq_test_input_file, std::string(""), "File containing raw signal data, must be in int8_t format. The signal generator will not be used."); +DEFINE_string(acq_test_implementation, std::string("GPS_L1_CA_PCPS_Acquisition"), "Acquisition block implementation under test. Alternatives: GPS_L1_CA_PCPS_Acquisition, GPS_L1_CA_PCPS_Acquisition_Fine_Doppler, Galileo_E1_PCPS_Ambiguous_Acquisition, GLONASS_L1_CA_PCPS_Acquisition, GLONASS_L2_CA_PCPS_Acquisition, GPS_L2_M_PCPS_Acquisition, Galileo_E5a_Pcps_Acquisition, GPS_L5i_PCPS_Acquisition"); + +DEFINE_int32(acq_test_doppler_max, 5000, "Maximum Doppler, in Hz"); +DEFINE_int32(acq_test_doppler_step, 125, "Doppler step, in Hz."); +DEFINE_int32(acq_test_coherent_time_ms, 1, "Acquisition coherent time, in ms"); +DEFINE_int32(acq_test_max_dwells, 1, "Number of non-coherent integrations."); +DEFINE_bool(acq_test_use_CFAR_algorithm, true, "Use CFAR algorithm."); +DEFINE_bool(acq_test_bit_transition_flag, false, "Bit transition flag."); +DEFINE_bool(acq_test_make_two_steps, false, "Perform second step in a thinner grid."); +DEFINE_int32(acq_test_second_nbins, 4, "If --acq_test_make_two_steps is set to true, this parameter sets the number of bins done in the acquisition refinement stage."); +DEFINE_int32(acq_test_second_doppler_step, 10, "If --acq_test_make_two_steps is set to true, this parameter sets the Doppler step applied in the acquisition refinement stage, in Hz."); + +DEFINE_int32(acq_test_signal_duration_s, 2, "Generated signal duration, in s"); +DEFINE_int32(acq_test_num_meas, 0, "Number of measurements per run. 0 means the complete file."); +DEFINE_double(acq_test_cn0_init, 30.0, "Initial CN0, in dBHz."); +DEFINE_double(acq_test_cn0_final, 45.0, "Final CN0, in dBHz."); +DEFINE_double(acq_test_cn0_step, 3.0, "CN0 step, in dB."); + +DEFINE_double(acq_test_threshold_init, 3.0, "Initial acquisition threshold"); +DEFINE_double(acq_test_threshold_final, 4.0, "Final acquisition threshold"); +DEFINE_double(acq_test_threshold_step, 0.5, "Acquisition threshold step"); + +DEFINE_double(acq_test_pfa_init, 1e-5, "Set initial threshold via probability of false alarm. Disable with -1.0"); + +DEFINE_int32(acq_test_PRN, 1, "PRN number of a present satellite"); +DEFINE_int32(acq_test_fake_PRN, 33, "PRN number of a non-present satellite"); + +DEFINE_int32(acq_test_iterations, 1, "Number of iterations (same signal, different noise realization)"); +DEFINE_bool(plot_acq_test, false, "Plots results with gnuplot, if available"); +DEFINE_int32(acq_test_skiphead, 0, "Number of samples to skip in the input file"); + +DEFINE_bool(acq_test_dump, false, "Dump the results of an acquisition block into .mat files."); + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class AcqPerfTest_msg_rx; + +typedef boost::shared_ptr AcqPerfTest_msg_rx_sptr; + +AcqPerfTest_msg_rx_sptr AcqPerfTest_msg_rx_make(concurrent_queue& queue); + +class AcqPerfTest_msg_rx : public gr::block +{ +private: + friend AcqPerfTest_msg_rx_sptr AcqPerfTest_msg_rx_make(concurrent_queue& queue); + void msg_handler_events(pmt::pmt_t msg); + AcqPerfTest_msg_rx(concurrent_queue& queue); + concurrent_queue& channel_internal_queue; + +public: + int rx_message; + ~AcqPerfTest_msg_rx(); +}; + + +AcqPerfTest_msg_rx_sptr AcqPerfTest_msg_rx_make(concurrent_queue& queue) +{ + return AcqPerfTest_msg_rx_sptr(new AcqPerfTest_msg_rx(queue)); +} + + +void AcqPerfTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + channel_internal_queue.push(rx_message); + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +AcqPerfTest_msg_rx::AcqPerfTest_msg_rx(concurrent_queue& queue) : gr::block("AcqPerfTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&AcqPerfTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +AcqPerfTest_msg_rx::~AcqPerfTest_msg_rx() +{ +} + +// ----------------------------------------- + + +class AcquisitionPerformanceTest : public ::testing::Test +{ +protected: + AcquisitionPerformanceTest() + { + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + doppler_max = static_cast(FLAGS_acq_test_doppler_max); + doppler_step = static_cast(FLAGS_acq_test_doppler_step); + stop = false; + if (FLAGS_acq_test_input_file.empty()) + { + cn0_vector.push_back(FLAGS_acq_test_cn0_init); + double aux = FLAGS_acq_test_cn0_init + FLAGS_acq_test_cn0_step; + while (aux <= FLAGS_acq_test_cn0_final) + { + cn0_vector.push_back(aux); + aux = aux + FLAGS_acq_test_cn0_step; + } + } + else + { + cn0_vector = {0.0}; + } + + if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0) + { + signal_id = "1C"; + system_id = 'G'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0) + { + signal_id = "1C"; + system_id = 'G'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0) + { + signal_id = "1B"; + system_id = 'E'; + min_integration_ms = 4; + if (FLAGS_acq_test_coherent_time_ms == 1) + { + coherent_integration_time_ms = 4; + } + else + { + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + } + } + else if (implementation.compare("GLONASS_L1_CA_PCPS_Acquisition") == 0) + { + signal_id = "1G"; + system_id = 'R'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + else if (implementation.compare("GLONASS_L2_CA_PCPS_Acquisition") == 0) + { + signal_id = "2G"; + system_id = 'R'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + else if (implementation.compare("GPS_L2_M_PCPS_Acquisition") == 0) + { + signal_id = "2S"; + system_id = 'G'; + if (FLAGS_acq_test_coherent_time_ms == 1) + { + coherent_integration_time_ms = 20; + } + else + { + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + } + min_integration_ms = 20; + } + else if (implementation.compare("Galileo_E5a_Pcps_Acquisition") == 0) + { + signal_id = "5X"; + system_id = 'E'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + else if (implementation.compare("GPS_L5i_PCPS_Acquisition") == 0) + { + signal_id = "L5"; + system_id = 'G'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + } + else + { + signal_id = "1C"; + system_id = 'G'; + coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms; + min_integration_ms = 1; + } + + init(); + + if (FLAGS_acq_test_pfa_init > 0.0) + { + pfa_vector.push_back(FLAGS_acq_test_pfa_init); + float aux = 1.0; + while ((FLAGS_acq_test_pfa_init * std::pow(10, aux)) < 1) + { + pfa_vector.push_back(FLAGS_acq_test_pfa_init * std::pow(10, aux)); + aux = aux + 1.0; + } + pfa_vector.push_back(1.0); + } + else + { + float aux = static_cast(FLAGS_acq_test_threshold_init); + pfa_vector.push_back(aux); + aux = aux + static_cast(FLAGS_acq_test_threshold_step); + while (aux <= static_cast(FLAGS_acq_test_threshold_final)) + { + pfa_vector.push_back(aux); + aux = aux + static_cast(FLAGS_acq_test_threshold_step); + } + } + + num_thresholds = pfa_vector.size(); + + int aux2 = ((generated_signal_duration_s * 1000 - (FLAGS_acq_test_coherent_time_ms * FLAGS_acq_test_max_dwells)) / (FLAGS_acq_test_coherent_time_ms * FLAGS_acq_test_max_dwells)); + if ((FLAGS_acq_test_num_meas > 0) and (FLAGS_acq_test_num_meas < aux2)) + { + num_of_measurements = static_cast(FLAGS_acq_test_num_meas); + } + else + { + num_of_measurements = static_cast(aux2); + } + + Pd.resize(cn0_vector.size()); + for (int i = 0; i < static_cast(cn0_vector.size()); i++) Pd[i].reserve(num_thresholds); + Pfa.resize(cn0_vector.size()); + for (int i = 0; i < static_cast(cn0_vector.size()); i++) Pfa[i].reserve(num_thresholds); + Pd_correct.resize(cn0_vector.size()); + for (int i = 0; i < static_cast(cn0_vector.size()); i++) Pd_correct[i].reserve(num_thresholds); + } + + ~AcquisitionPerformanceTest() + { + } + + std::vector cn0_vector; + std::vector pfa_vector; + + int N_iterations = FLAGS_acq_test_iterations; + void init(); + + int configure_generator(double cn0); + int generate_signal(); + int configure_receiver(double cn0, float pfa, unsigned int iter); + void start_queue(); + void wait_message(); + void process_message(); + void stop_queue(); + int run_receiver(); + int count_executions(const std::string& basename, unsigned int sat); + void check_results(); + void plot_results(); + + concurrent_queue channel_internal_queue; + + gr::msg_queue::sptr queue; + gr::top_block_sptr top_block; + std::shared_ptr acquisition; + std::shared_ptr config; + std::shared_ptr config_f; + Gnss_Synchro gnss_synchro; + size_t item_size; + unsigned int doppler_max; + unsigned int doppler_step; + bool stop; + + int message; + boost::thread ch_thread; + + std::string implementation = FLAGS_acq_test_implementation; + + const double baseband_sampling_freq = static_cast(FLAGS_fs_gen_sps); + int coherent_integration_time_ms; + const int in_acquisition = 1; + const int dump_channel = 0; + + int generated_signal_duration_s = FLAGS_acq_test_signal_duration_s; + unsigned int num_of_measurements; + unsigned int measurement_counter = 0; + + unsigned int observed_satellite = FLAGS_acq_test_PRN; + std::string path_str = "./acq-perf-test"; + + int num_thresholds; + unsigned int min_integration_ms; + + std::vector> Pd; + std::vector> Pfa; + std::vector> Pd_correct; + + std::string signal_id; + +private: + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + std::string p6; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_filename_raw_data; + char system_id; + + double compute_stdev_precision(const std::vector& vec); + double compute_stdev_accuracy(const std::vector& vec, double ref); +}; + + +void AcquisitionPerformanceTest::init() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = system_id; + std::string signal = signal_id; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = observed_satellite; + message = 0; + measurement_counter = 0; +} + + +void AcquisitionPerformanceTest::start_queue() +{ + stop = false; + ch_thread = boost::thread(&AcquisitionPerformanceTest::wait_message, this); +} + + +void AcquisitionPerformanceTest::wait_message() +{ + while (!stop) + { + channel_internal_queue.wait_and_pop(message); + process_message(); + } +} + + +void AcquisitionPerformanceTest::process_message() +{ + measurement_counter++; + acquisition->reset(); + acquisition->set_state(1); + std::cout << "Progress: " << round(static_cast(measurement_counter) / static_cast(num_of_measurements) * 100.0) << "% \r" << std::flush; + if (measurement_counter == num_of_measurements) + { + stop_queue(); + top_block->stop(); + } +} + + +void AcquisitionPerformanceTest::stop_queue() +{ + stop = true; +} + + +int AcquisitionPerformanceTest::configure_generator(double cn0) +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(std::min(generated_signal_duration_s * 10, 3000)); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps] + p6 = std::string("-CN0_dBHz=") + std::to_string(cn0); + return 0; +} + + +int AcquisitionPerformanceTest::generate_signal() +{ + pid_t wait_result; + int child_status; + std::cout << "Generating signal for " << p6 << "..." << std::endl; + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], NULL}; + + int pid; + if ((pid = fork()) == -1) + perror("fork error"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv error." << std::endl; + std::terminate(); + } + + wait_result = waitpid(pid, &child_status, 0); + if (wait_result == -1) perror("waitpid error"); + return 0; +} + + +int AcquisitionPerformanceTest::configure_receiver(double cn0, float pfa, unsigned int iter) +{ + if (FLAGS_config_file_ptest.empty()) + { + config = std::make_shared(); + const int sampling_rate_internal = baseband_sampling_freq; + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(sampling_rate_internal)); + + // Set Acquisition + config->set_property("Acquisition.implementation", implementation); + config->set_property("Acquisition.item_type", "gr_complex"); + config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition.doppler_min", std::to_string(-doppler_max)); + config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); + + config->set_property("Acquisition.threshold", std::to_string(pfa)); + //if (FLAGS_acq_test_pfa_init > 0.0) config->supersede_property("Acquisition.pfa", std::to_string(pfa)); + if (FLAGS_acq_test_pfa_init > 0.0) + { + config->supersede_property("Acquisition.pfa", std::to_string(pfa)); + } + if (FLAGS_acq_test_use_CFAR_algorithm) + { + config->set_property("Acquisition.use_CFAR_algorithm", "true"); + } + else + { + config->set_property("Acquisition.use_CFAR_algorithm", "false"); + } + + config->set_property("Acquisition.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms)); + if (FLAGS_acq_test_bit_transition_flag) + { + config->set_property("Acquisition.bit_transition_flag", "true"); + } + else + { + config->set_property("Acquisition.bit_transition_flag", "false"); + } + + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_acq_test_max_dwells)); + + config->set_property("Acquisition.repeat_satellite", "true"); + + config->set_property("Acquisition.blocking", "true"); + if (FLAGS_acq_test_make_two_steps) + { + config->set_property("Acquisition.make_two_steps", "true"); + config->set_property("Acquisition.second_nbins", std::to_string(FLAGS_acq_test_second_nbins)); + config->set_property("Acquisition.second_doppler_step", std::to_string(FLAGS_acq_test_second_doppler_step)); + } + else + { + config->set_property("Acquisition.make_two_steps", "false"); + } + + if (FLAGS_acq_test_dump) + { + config->set_property("Acquisition.dump", "true"); + } + else + { + config->set_property("Acquisition.dump", "false"); + } + + std::string dump_file = path_str + std::string("/acquisition_") + std::to_string(cn0) + "_" + std::to_string(iter) + "_" + std::to_string(pfa); + config->set_property("Acquisition.dump_filename", dump_file); + config->set_property("Acquisition.dump_channel", std::to_string(dump_channel)); + config->set_property("Acquisition.blocking_on_standby", "true"); + + config_f = 0; + } + else + { + config_f = std::make_shared(FLAGS_config_file_ptest); + config = 0; + } + return 0; +} + + +int AcquisitionPerformanceTest::run_receiver() +{ + std::string file; + if (FLAGS_acq_test_input_file.empty()) + { + file = "./" + filename_raw_data; + } + else + { + file = FLAGS_acq_test_input_file; + } + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + + top_block = gr::make_top_block("Acquisition test"); + boost::shared_ptr msg_rx = AcqPerfTest_msg_rx_make(channel_internal_queue); + gr::blocks::skiphead::sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), FLAGS_acq_test_skiphead); + + queue = gr::msg_queue::make(0); + gnss_synchro = Gnss_Synchro(); + init(); + + int nsamples = floor(config->property("GNSS-SDR.internal_fs_sps", 2000000) * generated_signal_duration_s); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GLONASS_L1_CA_PCPS_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GLONASS_L2_CA_PCPS_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L2_M_PCPS_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E5a_Pcps_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L5i_PCPS_Acquisition") == 0) + { + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else + { + bool aux = false; + EXPECT_EQ(true, aux); + } + + acquisition->set_gnss_synchro(&gnss_synchro); + acquisition->set_channel(0); + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); + acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); + acquisition->init(); + acquisition->set_local_code(); + + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->connect(top_block); + + acquisition->reset(); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, skiphead, 0); + top_block->connect(skiphead, 0, valve, 0); + top_block->connect(valve, 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + start_queue(); + + top_block->run(); // Start threads and wait + +#ifdef OLD_BOOST + ch_thread.timed_join(boost::posix_time::seconds(1)); +#endif +#ifndef OLD_BOOST + ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); +#endif + + return 0; +} + + +int AcquisitionPerformanceTest::count_executions(const std::string& basename, unsigned int sat) +{ + FILE* fp; + std::string argum2 = std::string("/usr/bin/find ") + path_str + std::string(" -maxdepth 1 -name ") + basename.substr(path_str.length() + 1, basename.length() - path_str.length()) + std::string("* | grep sat_") + std::to_string(sat) + std::string(" | wc -l"); + char buffer[1024]; + fp = popen(&argum2[0], "r"); + int num_executions = 1; + if (fp == NULL) + { + std::cout << "Failed to run command: " << argum2 << std::endl; + return 0; + } + while (fgets(buffer, sizeof(buffer), fp) != NULL) + { + std::string aux = std::string(buffer); + EXPECT_EQ(aux.empty(), false); + num_executions = std::stoi(aux); + } + pclose(fp); + return num_executions; +} + + +void AcquisitionPerformanceTest::plot_results() +{ + if (FLAGS_plot_acq_test == true) + { + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_gps_l1_tracking_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("linespoints"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.cmd("set font \"Times,18\""); + g1.set_title("Receiver Operating Characteristic for GPS L1 C/A acquisition"); + g1.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\""); + g1.cmd("set logscale x"); + g1.cmd("set yrange [0:1]"); + g1.cmd("set xrange[0.0001:1]"); + g1.cmd("set grid mxtics"); + g1.cmd("set grid ytics"); + g1.set_xlabel("Pfa"); + g1.set_ylabel("Pd"); + g1.set_grid(); + g1.cmd("show grid"); + for (int i = 0; i < static_cast(cn0_vector.size()); i++) + { + std::vector Pd_i; + std::vector Pfa_i; + for (int k = 0; k < num_thresholds; k++) + { + Pd_i.push_back(Pd[i][k]); + Pfa_i.push_back(Pfa[i][k]); + } + g1.plot_xy(Pfa_i, Pd_i, "CN0 = " + std::to_string(static_cast(cn0_vector[i])) + " dBHz"); + } + g1.set_legend(); + g1.savetops("ROC"); + g1.savetopdf("ROC", 18); + + Gnuplot g2("linespoints"); + if (FLAGS_show_plots) + { + g2.showonscreen(); // window output + } + else + { + g2.disablescreen(); + } + g2.cmd("set font \"Times,18\""); + g2.set_title("Receiver Operating Characteristic for GPS L1 C/A valid acquisition"); + g2.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\""); + g2.cmd("set logscale x"); + g2.cmd("set yrange [0:1]"); + g2.cmd("set xrange[0.0001:1]"); + g2.cmd("set grid mxtics"); + g2.cmd("set grid ytics"); + g2.set_xlabel("Pfa"); + g2.set_ylabel("Valid Pd"); + g2.set_grid(); + g2.cmd("show grid"); + for (int i = 0; i < static_cast(cn0_vector.size()); i++) + { + std::vector Pd_i_correct; + std::vector Pfa_i; + for (int k = 0; k < num_thresholds; k++) + { + Pd_i_correct.push_back(Pd_correct[i][k]); + Pfa_i.push_back(Pfa[i][k]); + } + g2.plot_xy(Pfa_i, Pd_i_correct, "CN0 = " + std::to_string(static_cast(cn0_vector[i])) + " dBHz"); + } + g2.set_legend(); + g2.savetops("ROC-valid-detection"); + g2.savetopdf("ROC-valid-detection", 18); + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } +} + + +TEST_F(AcquisitionPerformanceTest, ROC) +{ + tracking_true_obs_reader true_trk_data; + + if (boost::filesystem::exists(path_str)) + { + boost::filesystem::remove_all(path_str); + } + boost::system::error_code ec; + ASSERT_TRUE(boost::filesystem::create_directory(path_str, ec)) << "Could not create the " << path_str << " folder."; + + unsigned int cn0_index = 0; + for (std::vector::const_iterator it = cn0_vector.cbegin(); it != cn0_vector.cend(); ++it) + { + std::vector meas_Pd_; + std::vector meas_Pd_correct_; + std::vector meas_Pfa_; + + if (FLAGS_acq_test_input_file.empty()) std::cout << "Execution for CN0 = " << *it << " dB-Hz" << std::endl; + + // Do N_iterations of the experiment + for (int pfa_iter = 0; pfa_iter < static_cast(pfa_vector.size()); pfa_iter++) + { + if (FLAGS_acq_test_pfa_init > 0.0) + { + std::cout << "Setting threshold for Pfa = " << pfa_vector[pfa_iter] << std::endl; + } + else + { + std::cout << "Setting threshold to " << pfa_vector[pfa_iter] << std::endl; + } + + // Configure the signal generator + if (FLAGS_acq_test_input_file.empty()) configure_generator(*it); + + for (int iter = 0; iter < N_iterations; iter++) + { + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_acq_test_input_file.empty()) generate_signal(); + + for (unsigned k = 0; k < 2; k++) + { + if (k == 0) + { + observed_satellite = FLAGS_acq_test_PRN; + } + else + { + observed_satellite = FLAGS_acq_test_fake_PRN; + } + init(); + + // Configure the receiver + configure_receiver(*it, pfa_vector[pfa_iter], iter); + + // Run it + run_receiver(); + + // count executions + std::string basename = path_str + std::string("/acquisition_") + std::to_string(*it) + "_" + std::to_string(iter) + "_" + std::to_string(pfa_vector[pfa_iter]) + "_" + gnss_synchro.System + "_" + signal_id; + int num_executions = count_executions(basename, observed_satellite); + + // Read measured data + int ch = config->property("Acquisition.dump_channel", 0); + arma::vec meas_timestamp_s = arma::zeros(num_executions, 1); + arma::vec meas_doppler = arma::zeros(num_executions, 1); + arma::vec positive_acq = arma::zeros(num_executions, 1); + arma::vec meas_acq_delay_chips = arma::zeros(num_executions, 1); + + double coh_time_ms = config->property("Acquisition.coherent_integration_time_ms", 1); + + std::cout << "Num executions: " << num_executions << std::endl; + + unsigned int fft_size = 0; + unsigned int d_consumed_samples = coh_time_ms * config->property("GNSS-SDR.internal_fs_sps", 0) * 0.001; // * (config->property("Acquisition.bit_transition_flag", false) ? 2 : 1); + if (coh_time_ms == min_integration_ms) + { + fft_size = d_consumed_samples; + } + else + { + fft_size = d_consumed_samples * 2; + } + + for (int execution = 1; execution <= num_executions; execution++) + { + acquisition_dump_reader acq_dump(basename, + observed_satellite, + config->property("Acquisition.doppler_max", 0), + config->property("Acquisition.doppler_step", 0), + fft_size, + ch, + execution); + acq_dump.read_binary_acq(); + if (acq_dump.positive_acq) + { + //std::cout << "Meas acq_delay_samples: " << acq_dump.acq_delay_samples << " chips: " << acq_dump.acq_delay_samples / (baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD / GPS_L1_CA_CODE_LENGTH_CHIPS) << std::endl; + meas_timestamp_s(execution - 1) = acq_dump.sample_counter / baseband_sampling_freq; + meas_doppler(execution - 1) = acq_dump.acq_doppler_hz; + meas_acq_delay_chips(execution - 1) = acq_dump.acq_delay_samples / (baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD / GPS_L1_CA_CODE_LENGTH_CHIPS); + positive_acq(execution - 1) = acq_dump.positive_acq; + } + else + { + //std::cout << "Failed acquisition." << std::endl; + meas_timestamp_s(execution - 1) = arma::datum::inf; + meas_doppler(execution - 1) = arma::datum::inf; + meas_acq_delay_chips(execution - 1) = arma::datum::inf; + positive_acq(execution - 1) = acq_dump.positive_acq; + } + } + + // Read reference data + std::string true_trk_file = std::string("./gps_l1_ca_obs_prn"); + true_trk_file.append(std::to_string(observed_satellite)); + true_trk_file.append(".dat"); + true_trk_data.close_obs_file(); + true_trk_data.open_obs_file(true_trk_file); + + // load the true values + int64_t n_true_epochs = true_trk_data.num_epochs(); + arma::vec true_timestamp_s = arma::zeros(n_true_epochs, 1); + arma::vec true_acc_carrier_phase_cycles = arma::zeros(n_true_epochs, 1); + arma::vec true_Doppler_Hz = arma::zeros(n_true_epochs, 1); + arma::vec true_prn_delay_chips = arma::zeros(n_true_epochs, 1); + arma::vec true_tow_s = arma::zeros(n_true_epochs, 1); + + int64_t epoch_counter = 0; + int num_clean_executions = 0; + while (true_trk_data.read_binary_obs()) + { + true_timestamp_s(epoch_counter) = true_trk_data.signal_timestamp_s; + true_acc_carrier_phase_cycles(epoch_counter) = true_trk_data.acc_carrier_phase_cycles; + true_Doppler_Hz(epoch_counter) = true_trk_data.doppler_l1_hz; + true_prn_delay_chips(epoch_counter) = GPS_L1_CA_CODE_LENGTH_CHIPS - true_trk_data.prn_delay_chips; + true_tow_s(epoch_counter) = true_trk_data.tow; + epoch_counter++; + //std::cout << "True PRN_Delay chips = " << GPS_L1_CA_CODE_LENGTH_CHIPS - true_trk_data.prn_delay_chips << " at " << true_trk_data.signal_timestamp_s << std::endl; + } + + // Process results + arma::vec clean_doppler_estimation_error; + arma::vec clean_delay_estimation_error; + + if (epoch_counter > 2) + { + arma::vec true_interpolated_doppler = arma::zeros(num_executions, 1); + arma::vec true_interpolated_prn_delay_chips = arma::zeros(num_executions, 1); + interp1(true_timestamp_s, true_Doppler_Hz, meas_timestamp_s, true_interpolated_doppler); + interp1(true_timestamp_s, true_prn_delay_chips, meas_timestamp_s, true_interpolated_prn_delay_chips); + + arma::vec doppler_estimation_error = true_interpolated_doppler - meas_doppler; + arma::vec delay_estimation_error = true_interpolated_prn_delay_chips - (meas_acq_delay_chips - ((1.0 / baseband_sampling_freq) / GPS_L1_CA_CHIP_PERIOD)); // compensate 1 sample delay + + // Cut measurements without reference + for (int i = 0; i < num_executions; i++) + { + if (!std::isnan(doppler_estimation_error(i)) and !std::isnan(delay_estimation_error(i))) + { + num_clean_executions++; + } + } + clean_doppler_estimation_error = arma::zeros(num_clean_executions, 1); + clean_delay_estimation_error = arma::zeros(num_clean_executions, 1); + num_clean_executions = 0; + for (int i = 0; i < num_executions; i++) + { + if (!std::isnan(doppler_estimation_error(i)) and !std::isnan(delay_estimation_error(i))) + { + clean_doppler_estimation_error(num_clean_executions) = doppler_estimation_error(i); + clean_delay_estimation_error(num_clean_executions) = delay_estimation_error(i); + num_clean_executions++; + } + } + + /* std::cout << "Doppler estimation error [Hz]: "; + for (int i = 0; i < num_executions - 1; i++) + { + std::cout << doppler_estimation_error(i) << " "; + } + std::cout << std::endl; + + std::cout << "Delay estimation error [chips]: "; + for (int i = 0; i < num_executions - 1; i++) + { + std::cout << delay_estimation_error(i) << " "; + + } + std::cout << std::endl; */ + } + if (k == 0) + { + double detected = arma::accu(positive_acq); + double computed_Pd = detected / static_cast(num_executions); + if (num_executions > 0) + { + meas_Pd_.push_back(computed_Pd); + } + else + { + meas_Pd_.push_back(0.0); + } + std::cout << TEXT_BOLD_BLACK << "Probability of detection for channel=" << ch << ", CN0=" << *it << " dBHz" + << ": " << (num_executions > 0 ? computed_Pd : 0.0) << TEXT_RESET << std::endl; + } + if (num_clean_executions > 0) + { + arma::vec correct_acq = arma::zeros(num_executions, 1); + double correctly_detected = 0.0; + for (int i = 0; i < num_clean_executions - 1; i++) + + { + if (abs(clean_delay_estimation_error(i)) < 0.5 and abs(clean_doppler_estimation_error(i)) < static_cast(config->property("Acquisition.doppler_step", 1)) / 2.0) + { + correctly_detected = correctly_detected + 1.0; + } + } + double computed_Pd_correct = correctly_detected / static_cast(num_clean_executions); + meas_Pd_correct_.push_back(computed_Pd_correct); + std::cout << TEXT_BOLD_BLACK << "Probability of correct detection for channel=" << ch << ", CN0=" << *it << " dBHz" + << ": " << computed_Pd_correct << TEXT_RESET << std::endl; + } + else + { + //std::cout << "No reference data has been found. Maybe a non-present satellite?" << num_executions << std::endl; + if (k == 1) + { + double wrongly_detected = arma::accu(positive_acq); + double computed_Pfa = wrongly_detected / static_cast(num_executions); + if (num_executions > 0) + { + meas_Pfa_.push_back(computed_Pfa); + } + else + { + meas_Pfa_.push_back(0.0); + } + std::cout << TEXT_BOLD_BLACK << "Probability of false alarm for channel=" << ch << ", CN0=" << *it << " dBHz" + << ": " << (num_executions > 0 ? computed_Pfa : 0.0) << TEXT_RESET << std::endl; + } + } + true_trk_data.restart(); + } + } + true_trk_data.close_obs_file(); + float sum_pd = static_cast(std::accumulate(meas_Pd_.begin(), meas_Pd_.end(), 0.0)); + float sum_pd_correct = static_cast(std::accumulate(meas_Pd_correct_.begin(), meas_Pd_correct_.end(), 0.0)); + float sum_pfa = static_cast(std::accumulate(meas_Pfa_.begin(), meas_Pfa_.end(), 0.0)); + if (meas_Pd_.size() > 0 and meas_Pfa_.size() > 0) + { + Pd[cn0_index][pfa_iter] = sum_pd / static_cast(meas_Pd_.size()); + Pfa[cn0_index][pfa_iter] = sum_pfa / static_cast(meas_Pfa_.size()); + } + else + { + if (meas_Pd_.size() > 0) + { + Pd[cn0_index][pfa_iter] = sum_pd / static_cast(meas_Pd_.size()); + } + else + { + Pd[cn0_index][pfa_iter] = 0.0; + } + if (meas_Pfa_.size() > 0) + { + Pfa[cn0_index][pfa_iter] = sum_pfa / static_cast(meas_Pfa_.size()); + } + else + { + Pfa[cn0_index][pfa_iter] = 0.0; + } + } + if (meas_Pd_correct_.size() > 0) + { + Pd_correct[cn0_index][pfa_iter] = sum_pd_correct / static_cast(meas_Pd_correct_.size()); + } + else + { + Pd_correct[cn0_index][pfa_iter] = 0.0; + } + meas_Pd_.clear(); + meas_Pfa_.clear(); + meas_Pd_correct_.clear(); + } + cn0_index++; + } + + // Compute results + unsigned int aux_index = 0; + for (std::vector::const_iterator it = cn0_vector.cbegin(); it != cn0_vector.cend(); ++it) + { + std::cout << "Results for CN0 = " << *it << " dBHz:" << std::endl; + std::cout << "Pd = "; + for (int pfa_iter = 0; pfa_iter < num_thresholds; pfa_iter++) + { + std::cout << Pd[aux_index][pfa_iter] << " "; + } + std::cout << std::endl; + std::cout << "Pd_correct = "; + for (int pfa_iter = 0; pfa_iter < num_thresholds; pfa_iter++) + { + std::cout << Pd_correct[aux_index][pfa_iter] << " "; + } + std::cout << std::endl; + std::cout << "Pfa = "; + for (int pfa_iter = 0; pfa_iter < num_thresholds; pfa_iter++) + { + std::cout << Pfa[aux_index][pfa_iter] << " "; + } + std::cout << std::endl; + + aux_index++; + } + + plot_results(); +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc index 022a9b9d1..7e3be06c6 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,31 +24,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "gnss_synchro.h" +#endif +#include "fir_filter.h" #include "galileo_e1_pcps_8ms_ambiguous_acquisition.h" +#include "gen_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx; @@ -65,9 +67,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -80,21 +83,20 @@ GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1Pcps8msAmb void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); @@ -102,12 +104,13 @@ GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1Pcps8msAmbiguo } GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx::~GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test: public ::testing::Test +class GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test : public ::testing::Test { protected: GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test() @@ -121,7 +124,8 @@ protected: } ~GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test() - {} + { + } void init(); void config_1(); @@ -166,6 +170,7 @@ protected: double Pfa_a; }; + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::init() { message = 0; @@ -181,6 +186,7 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::init() Pfa_a = 0; } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_1() { gnss_synchro.Channel_ID = 0; @@ -193,14 +199,14 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_1() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -237,17 +243,17 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.2"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.threshold", "0.2"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_2() { gnss_synchro.Channel_ID = 0; @@ -260,14 +266,14 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_2() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -322,54 +328,53 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition"); - config->set_property("Acquisition.pfa", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.pfa", "0.1"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::start_queue() { stop = false; ch_thread = boost::thread(&GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::wait_message, this); } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); try - { + { channel_internal_queue.wait_and_pop(message); - } - catch( boost::exception & e ) - { - DLOG(FATAL) << "Boost exception: " << boost::diagnostic_information(e); - } + } + catch (const boost::exception& e) + { + LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); + } - gettimeofday(&tv, NULL); - end = tv.tv_sec*1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; - mean_acq_time_us += (end - begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::process_message() { if (message == 1) @@ -377,7 +382,7 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - (static_cast(gnss_synchro.Acq_delay_samples) - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -391,16 +396,16 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -409,109 +414,111 @@ void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::process_message() } } + void GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test::stop_queue() { stop = true; } + TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, Instantiate) { config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 0); } + TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0.0); config_1(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running he top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) { config_1(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 1, queue); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 0, queue); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -519,7 +526,7 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -529,20 +536,20 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); //acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); @@ -551,9 +558,8 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; if (message == 1) { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } - } else if (i == 1) { @@ -564,42 +570,43 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) } } + TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_8ms_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -607,7 +614,7 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProb signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -619,20 +626,20 @@ TEST_F(GalileoE1Pcps8msAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProb if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); //acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) { diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc index 45e8d7c3b..7f15ac400 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,30 +25,32 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "gnss_synchro.h" +#endif +#include "fir_filter.h" #include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "gen_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### @@ -62,13 +64,14 @@ GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1PcpsAmbiguous class GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx : public gr::block { private: - friend GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_make(concurrent_queue& queue ); + friend GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_make(concurrent_queue& queue); void msg_handler_events(pmt::pmt_t msg); GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -81,21 +84,20 @@ GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1PcpsAmbiguous void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); @@ -103,13 +105,14 @@ GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1PcpsAmbiguousAcqu } GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx::~GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test: public ::testing::Test +class GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test : public ::testing::Test { protected: GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test() @@ -122,7 +125,8 @@ protected: } ~GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test() - {} + { + } void init(); void config_1(); @@ -196,14 +200,14 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_1() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -215,9 +219,9 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_1() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.noise_flag", "false"); config->set_property("SignalSource.data_flag", "false"); @@ -242,17 +246,16 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.bit_transition_flag","false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.bit_transition_flag", "false"); + config->set_property("Acquisition_1B.threshold", "0.1"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } @@ -268,14 +271,14 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_2() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -287,9 +290,9 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_2() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.system_1", "E"); config->set_property("SignalSource.PRN_1", "15"); @@ -332,17 +335,16 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.bit_transition_flag","false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); - config->set_property("Acquisition.pfa", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.bit_transition_flag", "false"); + config->set_property("Acquisition_1B.pfa", "0.1"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } @@ -355,23 +357,21 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::start_queue() void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec*1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec*1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end - begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } @@ -385,7 +385,7 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - (static_cast(gnss_synchro.Acq_delay_samples) - 5) * 1023.0 / static_cast(fs_in * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -399,18 +399,18 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { - mse_delay /= (double)num_of_realizations; - mse_doppler /= (double)num_of_realizations; + mse_delay /= static_cast(num_of_realizations); + mse_doppler /= static_cast(num_of_realizations); - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); - mean_acq_time_us /= (double)num_of_realizations; + mean_acq_time_us /= static_cast(num_of_realizations); stop_queue(); top_block->stop(); @@ -427,43 +427,41 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test::stop_queue() TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, Instantiate) { config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); } TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec*1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec*1e6 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } @@ -472,37 +470,37 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -510,7 +508,7 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -520,75 +518,74 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } ch_thread.join(); } } - TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -596,7 +593,7 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProbabi signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -608,34 +605,34 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProbabi if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } ch_thread.join(); } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc index 6fe61c632..73b67416b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc @@ -17,7 +17,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -35,29 +35,31 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include +#endif +#include "galileo_e1_pcps_ambiguous_acquisition.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_signal.h" #include "gnss_synchro.h" -#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "in_memory_configuration.h" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx; @@ -74,9 +76,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx(); //!< Default destructor + ~GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx(); //!< Default destructor }; @@ -89,21 +92,20 @@ GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx_sptr GalileoE1PcpsAmbiguousAcqu void GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::msg_handler_events, this, _1)); @@ -111,13 +113,14 @@ GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::GalileoE1PcpsAmbiguousAcquisit } GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx::~GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1PcpsAmbiguousAcquisitionGSoCTest: public ::testing::Test +class GalileoE1PcpsAmbiguousAcquisitionGSoCTest : public ::testing::Test { protected: GalileoE1PcpsAmbiguousAcquisitionGSoCTest() @@ -131,7 +134,8 @@ protected: } ~GalileoE1PcpsAmbiguousAcquisitionGSoCTest() - {} + { + } void init(); void start_queue(); @@ -150,6 +154,7 @@ protected: boost::thread ch_thread; }; + void GalileoE1PcpsAmbiguousAcquisitionGSoCTest::init() { gnss_synchro.Channel_ID = 0; @@ -158,19 +163,19 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoCTest::init() signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 11; - config->set_property("GNSS-SDR.internal_fs_hz", "4000000"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", "4"); - config->set_property("Acquisition.dump", "false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "125"); - config->set_property("Acquisition.repeat_satellite", "false"); - config->set_property("Acquisition0.cboc", "true"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", "4"); + config->set_property("Acquisition_1B.dump", "false"); + config->set_property("Acquisition_1B.threshold", "0.1"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "125"); + config->set_property("Acquisition_1B.repeat_satellite", "false"); + config->set_property("Acquisition_1B.cboc", "true"); } + void GalileoE1PcpsAmbiguousAcquisitionGSoCTest::start_queue() { ch_thread = boost::thread(&GalileoE1PcpsAmbiguousAcquisitionGSoCTest::wait_message, this); @@ -182,133 +187,131 @@ void GalileoE1PcpsAmbiguousAcquisitionGSoCTest::wait_message() while (!stop) { try - { + { channel_internal_queue.wait_and_pop(message); stop_queue(); - } - catch( boost::exception & e ) - { + } + catch (const boost::exception& e) + { DLOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); - } - + } } } + void GalileoE1PcpsAmbiguousAcquisitionGSoCTest::stop_queue() { stop = true; } - TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoCTest, Instantiate) { init(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); EXPECT_STREQ("Galileo_E1_PCPS_Ambiguous_Acquisition", acquisition->implementation().c_str()); } + TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoCTest, ConnectAndRun) { int fs_in = 4000000; - int nsamples = 4*fs_in; - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = 4 * fs_in; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GalileoE1PcpsAmbiguousAcquisitionGSoCTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionGSoCTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.00001)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.00001)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 250)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 250)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ std::string path = std::string(TEST_PATH); //std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; std::string file = path + "signal_samples/Galileo_E1_ID_1_Fs_4Msps_8ms.dat"; - const char * file_name = file.c_str(); + const char* file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); top_block->connect(file_source, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ start_queue(); + acquisition->set_local_code(); acquisition->init(); acquisition->reset(); acquisition->set_state(1); - }) << "Failure starting acquisition" << std::endl; + }) << "Failure starting acquisition"; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; stop_queue(); - unsigned long int nsamples = gnss_synchro.Acq_samplestamp_samples; - std::cout << "Acquired " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + uint64_t nsamples = gnss_synchro.Acq_samplestamp_samples; + std::cout << "Acquired " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 0=ACQ STOP."; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc index 3adec6673..786bfbff7 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,31 +25,37 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include #include -#include -#include +#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include +#endif +#include "Galileo_E1.h" +#include "acquisition_dump_reader.h" +#include "galileo_e1_pcps_ambiguous_acquisition.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_signal.h" #include "gnss_synchro.h" - -#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "gnuplot_i.h" +#include "in_memory_configuration.h" +#include "test_flags.h" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx; @@ -67,7 +73,7 @@ private: public: int rx_message; - ~GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx(); //!< Default destructor + ~GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx(); //!< Default destructor }; @@ -80,20 +86,19 @@ GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx_sptr GalileoE1PcpsAmbiguousAcquisit void GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx() : - gr::block("GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx() : gr::block("GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::msg_handler_events, this, _1)); @@ -102,32 +107,39 @@ GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsAmbiguousAcquisitionT GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx::~GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1PcpsAmbiguousAcquisitionTest: public ::testing::Test +class GalileoE1PcpsAmbiguousAcquisitionTest : public ::testing::Test { protected: GalileoE1PcpsAmbiguousAcquisitionTest() -{ + { factory = std::make_shared(); config = std::make_shared(); item_size = sizeof(gr_complex); gnss_synchro = Gnss_Synchro(); -} + doppler_max = 10000; + doppler_step = 250; + } ~GalileoE1PcpsAmbiguousAcquisitionTest() - {} + { + } void init(); + void plot_grid(); gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; Gnss_Synchro gnss_synchro; size_t item_size; + unsigned int doppler_max; + unsigned int doppler_step; }; @@ -135,27 +147,98 @@ void GalileoE1PcpsAmbiguousAcquisitionTest::init() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; - std::string signal = "1C"; + std::string signal = "1B"; signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 1; - config->set_property("GNSS-SDR.internal_fs_hz", "4000000"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", "4"); - config->set_property("Acquisition.dump", "false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.0001"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.repeat_satellite", "false"); - config->set_property("Acquisition1.cboc", "true"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", "4"); + if (FLAGS_plot_acq_grid == true) + { + config->set_property("Acquisition_1B.dump", "true"); + } + else + { + config->set_property("Acquisition_1B.dump", "false"); + } + config->set_property("Acquisition_1B.dump_filename", "./tmp-acq-gal1/acquisition"); + config->set_property("Acquisition_1B.threshold", "0.0001"); + config->set_property("Acquisition_1B.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition_1B.doppler_step", std::to_string(doppler_step)); + config->set_property("Acquisition_1B.repeat_satellite", "false"); + config->set_property("Acquisition_1B.cboc", "true"); } + +void GalileoE1PcpsAmbiguousAcquisitionTest::plot_grid() +{ + //load the measured values + std::string basename = "./tmp-acq-gal1/acquisition_E_1B"; + unsigned int sat = static_cast(gnss_synchro.PRN); + + unsigned int samples_per_code = static_cast(round(4000000 / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS))); // !! + acquisition_dump_reader acq_dump(basename, sat, doppler_max, doppler_step, samples_per_code); + + if (!acq_dump.read_binary_acq()) std::cout << "Error reading files" << std::endl; + + std::vector* doppler = &acq_dump.doppler; + std::vector* samples = &acq_dump.samples; + std::vector >* mag = &acq_dump.mag; + + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_acq_grid has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + std::cout << "Plotting the acquisition grid. This can take a while..." << std::endl; + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("lines"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("Galileo E1b/c signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN)); + g1.set_xlabel("Doppler [Hz]"); + g1.set_ylabel("Sample"); + //g1.cmd("set view 60, 105, 1, 1"); + g1.plot_grid3d(*doppler, *samples, *mag); + + g1.savetops("Galileo_E1_acq_grid"); + g1.savetopdf("Galileo_E1_acq_grid"); + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + std::string data_str = "./tmp-acq-gal1"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } +} + + TEST_F(GalileoE1PcpsAmbiguousAcquisitionTest, Instantiate) { init(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); } @@ -163,108 +246,119 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionTest, Instantiate) TEST_F(GalileoE1PcpsAmbiguousAcquisitionTest, ConnectAndRun) { int fs_in = 4000000; - int nsamples = 4*fs_in; - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = 4 * fs_in; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); gr::msg_queue::sptr queue = gr::msg_queue::make(0); init(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); - top_block->msg_connect(acquisition->get_right_block(),pmt::mp("events"), msg_rx,pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec*1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec*1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Processed " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } TEST_F(GalileoE1PcpsAmbiguousAcquisitionTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); - double expected_delay_samples = 2920; //18250; + if (FLAGS_plot_acq_grid == true) + { + std::string data_str = "./tmp-acq-gal1"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } + boost::filesystem::create_directory(data_str); + } + + double expected_delay_samples = 2920; //18250; double expected_doppler_hz = -632; init(); top_block = gr::make_top_block("Acquisition test"); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsAmbiguousAcquisitionTest_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 1e-9)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 1e-9)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", doppler_max)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 250)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", doppler_step)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ std::string path = std::string(TEST_PATH); std::string file = path + "signal_samples/Galileo_E1_ID_1_Fs_4Msps_8ms.dat"; - const char * file_name = file.c_str(); + const char* file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); top_block->connect(file_source, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; + acquisition->set_local_code(); acquisition->init(); acquisition->reset(); acquisition->set_state(1); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - unsigned long int nsamples = gnss_synchro.Acq_samplestamp_samples; - std::cout << "Acquired " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + uint64_t nsamples = gnss_synchro.Acq_samplestamp_samples; + std::cout << "Acquired " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; ASSERT_EQ(1, msg_rx->rx_message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; std::cout << "Delay: " << gnss_synchro.Acq_delay_samples << std::endl; std::cout << "Doppler: " << gnss_synchro.Acq_doppler_hz << std::endl; double delay_error_samples = std::abs(expected_delay_samples - gnss_synchro.Acq_delay_samples); - float delay_error_chips = (float)(delay_error_samples * 1023 / 4000000); + float delay_error_chips = static_cast(delay_error_samples * 1023 / 4000000); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); EXPECT_LE(doppler_error_hz, 166) << "Doppler error exceeds the expected value: 166 Hz = 2/(3*integration period)"; EXPECT_LT(delay_error_chips, 0.175) << "Delay error exceeds the expected value: 0.175 chips"; -} + if (FLAGS_plot_acq_grid == true) + { + plot_grid(); + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc index 9d30c87fc..3388bf162 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,30 +25,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "gnss_synchro.h" +#endif +#include "fir_filter.h" #include "galileo_e1_pcps_cccwsr_ambiguous_acquisition.h" +#include "gen_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx; @@ -61,13 +64,14 @@ GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_sptr GalileoE1PcpsCccwsrAmbig class GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx : public gr::block { private: - friend GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_sptr GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_make(concurrent_queue& queue ); + friend GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_sptr GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_make(concurrent_queue& queue); void msg_handler_events(pmt::pmt_t msg); GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx(); //!< Default destructor + ~GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx(); //!< Default destructor }; @@ -80,21 +84,20 @@ GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_sptr GalileoE1PcpsCccwsrAmbig void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::msg_handler_events, this, _1)); @@ -102,12 +105,13 @@ GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::GalileoE1PcpsCccwsrAmbiguous } GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx::~GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1PcpsCccwsrAmbiguousAcquisitionTest: public ::testing::Test +class GalileoE1PcpsCccwsrAmbiguousAcquisitionTest : public ::testing::Test { protected: GalileoE1PcpsCccwsrAmbiguousAcquisitionTest() @@ -167,6 +171,7 @@ protected: double Pfa_a; }; + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::init() { message = 0; @@ -182,26 +187,27 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::init() Pfa_a = 0; } + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 4; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -213,9 +219,9 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_1() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.noise_flag", "false"); config->set_property("SignalSource.data_flag", "false"); @@ -240,18 +246,18 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.7"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.threshold", "0.7"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_2() { gnss_synchro.Channel_ID = 0; @@ -264,14 +270,14 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_2() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -283,9 +289,9 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_2() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.system_1", "E"); config->set_property("SignalSource.PRN_1", "15"); @@ -328,18 +334,18 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.00215"); // Pfa,a = 0.1 - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.threshold", "0.00215"); // Pfa,a = 0.1 + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::start_queue() { stop = false; @@ -349,28 +355,27 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::start_queue() void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end-begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::process_message() { if (message == 1) @@ -378,7 +383,7 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -392,16 +397,16 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -412,90 +417,92 @@ void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::process_message() } } + void GalileoE1PcpsCccwsrAmbiguousAcquisitionTest::stop_queue() { stop = true; } + TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, Instantiate) { config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); } + TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test."<< std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResults) { config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.00001)); - }) << "Failure setting threshold."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.00001)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -503,7 +510,7 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -513,11 +520,11 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_gnss_synchro(&gnss_synchro); acquisition->set_local_code(); @@ -525,75 +532,76 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResults) acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - //EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + //EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } #ifdef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.timed_join(boost::posix_time::seconds(1)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif #ifndef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif } } + TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResultsProbabilities) { config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_CCCWSR_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsCccwsrAmbiguousAcquisitionTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.00215)); - }) << "Failure setting threshold."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.00215)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -601,7 +609,7 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResultsProbabili signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -613,11 +621,11 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResultsProbabili if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_gnss_synchro(&gnss_synchro); @@ -627,23 +635,23 @@ TEST_F(GalileoE1PcpsCccwsrAmbiguousAcquisitionTest, ValidationOfResultsProbabili acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } ch_thread.join(); } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc index a35e25cf4..b4a7b4410 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,32 +25,35 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include #include #include -#include -#include #include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include +#endif +#include "fir_filter.h" +#include "galileo_e1_pcps_quicksync_ambiguous_acquisition.h" +#include "gen_signal_source.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" +#include "gnss_sdr_valve.h" #include "gnss_synchro.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" -#include "galileo_e1_pcps_quicksync_ambiguous_acquisition.h" +#include DEFINE_double(e1_value_threshold, 0.3, "Value of the threshold for the acquisition"); DEFINE_int32(e1_value_CN0_dB_0, 50, "Value for the CN0_dB_0 in channel 0"); @@ -73,9 +76,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx(); //!< Default destructor + ~GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx(); //!< Default destructor }; @@ -88,46 +92,46 @@ GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx_sptr GalileoE1Pcps void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx::GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx::GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } + GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx::~GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx() -{} +{ +} // ########################################################### -class GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test: public ::testing::Test +class GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test : public ::testing::Test { protected: GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test() -{ + { factory = std::make_shared(); item_size = sizeof(gr_complex); stop = false; message = 0; gnss_synchro = Gnss_Synchro(); init(); -} - + } ~GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test() { } @@ -172,10 +176,10 @@ protected: double mse_doppler; double mse_delay; - double Pd; // Probability of detection - double Pfa_p; // Probability of false alarm on present satellite - double Pfa_a; // Probability of false alarm on absent satellite - double Pmd; // Probability of miss detection + double Pd; // Probability of detection + double Pfa_p; // Probability of false alarm on present satellite + double Pfa_a; // Probability of false alarm on absent satellite + double Pmd; // Probability of miss detection std::ofstream pdpfafile; unsigned int miss_detection_counter; @@ -201,6 +205,7 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::init() Pmd = 0; } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_1() { gnss_synchro.Channel_ID = 0; @@ -213,14 +218,14 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_1() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -232,9 +237,9 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_1() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.noise_flag", "false"); config->set_property("SignalSource.data_flag", "false"); @@ -259,20 +264,20 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.bit_transition_flag","false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.folding_factor", "2"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.bit_transition_flag", "false"); + config->set_property("Acquisition_1B.threshold", "1"); + config->set_property("Acquisition_1Bdoppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.folding_factor", "2"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_2() { gnss_synchro.Channel_ID = 0; @@ -296,7 +301,7 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_2() config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -308,9 +313,9 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_2() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", std::to_string(FLAGS_e1_value_CN0_dB_0)); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.system_1", "E"); config->set_property("SignalSource.PRN_1", "15"); @@ -353,18 +358,17 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.bit_transition_flag","false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", std::to_string(FLAGS_e1_value_threshold)); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "125"); - config->set_property("Acquisition.folding_factor", "2"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.bit_transition_flag", "false"); + config->set_property("Acquisition_1B.threshold", std::to_string(FLAGS_e1_value_threshold)); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "125"); + config->set_property("Acquisition_1B.folding_factor", "2"); + config->set_property("Acquisition_1B.dump", "false"); } @@ -387,7 +391,7 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_3() config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -399,9 +403,9 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_3() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", std::to_string(FLAGS_e1_value_CN0_dB_0)); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.system_1", "E"); config->set_property("SignalSource.PRN_1", "15"); @@ -421,8 +425,8 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_3() config->set_property("SignalSource.doppler_Hz_3", "3000"); config->set_property("SignalSource.delay_chips_3", "300"); - config->set_property("SignalSource.noise_flag", "false");// - config->set_property("SignalSource.data_flag", "false");// + config->set_property("SignalSource.noise_flag", "false"); // + config->set_property("SignalSource.data_flag", "false"); // config->set_property("SignalSource.BW_BB", "0.97"); config->set_property("InputFilter.implementation", "Fir_Filter"); @@ -444,50 +448,50 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::config_3() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.bit_transition_flag","false"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); - config->set_property("Acquisition.threshold", "0.2"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "125"); - config->set_property("Acquisition.folding_factor", "4"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.max_dwells", "1"); + config->set_property("Acquisition_1B.bit_transition_flag", "false"); + config->set_property("Acquisition_1B.threshold", "0.2"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "125"); + config->set_property("Acquisition_1B.folding_factor", "4"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::start_queue() { stop = false; ch_thread = boost::thread(&GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::wait_message, this); } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec*1e6 + tv.tv_usec; + begin = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec*1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; - mean_acq_time_us += (end - begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::process_message() { if (message == 1) @@ -495,7 +499,7 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / ((double)fs_in * 1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -505,9 +509,8 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::process_message() { correct_estimation_counter++; } - } - else if(message == 2 && gnss_synchro.PRN == 10) + else if (message == 2 && gnss_synchro.PRN == 10) { /* if ((delay_error_chips < max_delay_error_chips) && (doppler_error_hz < max_doppler_error_hz)) @@ -520,25 +523,26 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter / num_of_realizations * 100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { - mse_delay /= (double)num_of_realizations; - mse_doppler /= (double)num_of_realizations; + mse_delay /= static_cast(num_of_realizations); + mse_doppler /= static_cast(num_of_realizations); - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter - correct_estimation_counter) / (double)num_of_realizations; - Pmd = (double)miss_detection_counter / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); + Pmd = static_cast(miss_detection_counter) / static_cast(num_of_realizations); - mean_acq_time_us /= (double)num_of_realizations; + mean_acq_time_us /= static_cast(num_of_realizations); stop_queue(); top_block->stop(); } } + void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::stop_queue() { stop = true; @@ -548,7 +552,7 @@ void GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test::stop_queue() TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, Instantiate) { config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); } @@ -556,43 +560,42 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, Instantiate) TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ConnectAndRun) { LOG(INFO) << "**Start connect and run test"; - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = - gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = - gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test."<< std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1e6 + tv.tv_usec; - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + begin = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; LOG(INFO) << "----end connect and run test-----"; LOG(INFO) << "**End connect and run test"; } + TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResults) { LOG(INFO) << "Start validation of results test"; @@ -600,38 +603,38 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(0); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 125)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 125)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(1); - }) << "Failure setting threshold."<< std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -639,7 +642,7 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible @@ -650,11 +653,11 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_gnss_synchro(&gnss_synchro); acquisition->set_local_code(); @@ -662,16 +665,16 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) { EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } else if (i == 1) { @@ -691,38 +694,38 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_step(50); - }) << "Failure setting doppler_step."<< std::endl; + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(5); - }) << "Failure setting threshold."<< std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -730,7 +733,7 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -740,11 +743,11 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_gnss_synchro(&gnss_synchro); @@ -753,15 +756,15 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) { EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } else if (i == 1) { @@ -772,43 +775,44 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul DLOG(INFO) << "End validation of results with noise+interference test"; } + TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResultsProbabilities) { config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_QuickSync_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -816,7 +820,7 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -828,11 +832,11 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_gnss_synchro(&gnss_synchro); @@ -841,9 +845,9 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); @@ -854,33 +858,31 @@ TEST_F(GalileoE1PcpsQuickSyncAmbiguousAcquisitionGSoC2014Test, ValidationOfResul std::cout << "Estimated probability of miss detection (satellite present) = " << Pmd << std::endl; std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - if(dump_test_results) + if (dump_test_results) { std::stringstream filenamepd; filenamepd.str(""); filenamepd << "../data/test_statistics_" << gnss_synchro.System - << "_" << gnss_synchro.Signal << "_sat_" - << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_e1_value_CN0_dB_0 << "_dBHz.csv"; + << "_" << gnss_synchro.Signal << "_sat_" + << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_e1_value_CN0_dB_0 << "_dBHz.csv"; pdpfafile.open(filenamepd.str().c_str(), std::ios::app | std::ios::out); pdpfafile << FLAGS_e1_value_threshold << "," << Pd << "," << Pfa_p << "," << Pmd << std::endl; pdpfafile.close(); } - - } else if (i == 1) { std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - if(dump_test_results) + if (dump_test_results) { std::stringstream filenamepf; filenamepf.str(""); filenamepf << "../data/test_statistics_" << gnss_synchro.System - << "_" << gnss_synchro.Signal << "_sat_" - << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_e1_value_CN0_dB_0 << "_dBHz.csv"; + << "_" << gnss_synchro.Signal << "_sat_" + << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_e1_value_CN0_dB_0 << "_dBHz.csv"; pdpfafile.open(filenamepf.str().c_str(), std::ios::app | std::ios::out); pdpfafile << FLAGS_e1_value_threshold << "," << Pfa_a << std::endl; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc index 35cde3a96..8fe2305a3 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,36 +25,35 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - - - -#include -#include #include -#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" +#endif #include "configuration_interface.h" -#include "gnss_synchro.h" +#include "fir_filter.h" #include "galileo_e1_pcps_tong_ambiguous_acquisition.h" +#include "gen_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx; @@ -71,9 +70,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -86,31 +86,33 @@ GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx_sptr GalileoE1PcpsTongA void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } -GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::~GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx() -{} -class GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test: public ::testing::Test +GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx::~GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx() +{ +} + + +class GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test : public ::testing::Test { protected: GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test() @@ -170,6 +172,7 @@ protected: double Pfa_a; }; + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::init() { message = 0; @@ -185,6 +188,7 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::init() Pfa_a = 0; } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_1() { gnss_synchro.Channel_ID = 0; @@ -197,14 +201,14 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_1() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -216,9 +220,9 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_1() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "44"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.noise_flag", "false"); config->set_property("SignalSource.data_flag", "false"); @@ -243,19 +247,19 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition_Galileo.item_type", "gr_complex"); - config->set_property("Acquisition_Galileo.if", "0"); - config->set_property("Acquisition_Galileo.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition_Galileo.tong_init_val", "1"); - config->set_property("Acquisition_Galileo.tong_max_val", "8"); - config->set_property("Acquisition_Galileo.implementation", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition"); - config->set_property("Acquisition_Galileo.threshold", "0.3"); - config->set_property("Acquisition_Galileo.doppler_max", "10000"); - config->set_property("Acquisition_Galileo.doppler_step", "250"); - config->set_property("Acquisition_Galileo.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.tong_init_val", "1"); + config->set_property("Acquisition_1B.tong_max_val", "8"); + config->set_property("Acquisition_1B.threshold", "0.3"); + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_2() { gnss_synchro.Channel_ID = 0; @@ -268,14 +272,14 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_2() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -287,9 +291,9 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_2() config->set_property("SignalSource.PRN_0", "10"); config->set_property("SignalSource.CN0_dB_0", "50"); config->set_property("SignalSource.doppler_Hz_0", - std::to_string(expected_doppler_hz)); + std::to_string(expected_doppler_hz)); config->set_property("SignalSource.delay_chips_0", - std::to_string(expected_delay_chips)); + std::to_string(expected_delay_chips)); config->set_property("SignalSource.system_1", "E"); config->set_property("SignalSource.PRN_1", "15"); @@ -332,49 +336,49 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition_Galileo.item_type", "gr_complex"); - config->set_property("Acquisition_Galileo.if", "0"); - config->set_property("Acquisition_Galileo.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition_Galileo.tong_init_val", "1"); - config->set_property("Acquisition_Galileo.tong_max_val", "8"); - config->set_property("Acquisition_Galileo.implementation", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition"); - config->set_property("Acquisition_Galileo.threshold", "0.00028"); // Pfa,a = 0.1 - config->set_property("Acquisition_Galileo.doppler_max", "10000"); - config->set_property("Acquisition_Galileo.doppler_step", "250"); - config->set_property("Acquisition_Galileo.dump", "false"); + config->set_property("Acquisition_1B.implementation", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition"); + config->set_property("Acquisition_1B.item_type", "gr_complex"); + config->set_property("Acquisition_1B.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1B.tong_init_val", "1"); + config->set_property("Acquisition_1B.tong_max_val", "8"); + config->set_property("Acquisition_1B.threshold", "0.00028"); // Pfa,a = 0.1 + config->set_property("Acquisition_1B.doppler_max", "10000"); + config->set_property("Acquisition_1B.doppler_step", "250"); + config->set_property("Acquisition_1B.dump", "false"); } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::start_queue() { stop = false; ch_thread = boost::thread(&GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::wait_message, this); } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end - begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::process_message() { if (message == 1) @@ -382,7 +386,7 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -396,16 +400,16 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -416,86 +420,88 @@ void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::process_message() } } + void GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test::stop_queue() { stop = true; } + TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, Instantiate) { config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); } + TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0.0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); config_1(); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1e6 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) { config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_max(5000); - }) << "Failure setting doppler_max." << std::endl; + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_step(100); - }) << "Failure setting doppler_step." << std::endl; + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(0.01); - }) << "Failure setting threshold." << std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->reset(); acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -503,7 +509,7 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -513,11 +519,11 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->reset(); acquisition->set_gnss_synchro(&gnss_synchro); @@ -525,21 +531,21 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } //std::cout << "Delay: " << gnss_synchro.Acq_delay_samples << std::endl; //std::cout << "Doppler: " << gnss_synchro.Acq_doppler_hz << std::endl; @@ -547,42 +553,43 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResults) } } + TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 1); + std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Tong_Ambiguous_Acquisition", 1, 0); acquisition = std::dynamic_pointer_cast(acq_); boost::shared_ptr msg_rx = GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1B.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1B.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.00028)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1B.threshold", 0.00028)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -590,7 +597,7 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsPro signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -602,34 +609,34 @@ TEST_F(GalileoE1PcpsTongAmbiguousAcquisitionGSoC2013Test, ValidationOfResultsPro if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } ch_thread.join(); } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc index e34961b9f..df67c7756 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,34 +24,32 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_block_factory.h" -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "configuration_interface.h" -#include "gnss_synchro.h" +#endif +#include "fir_filter.h" #include "galileo_e5a_noncoherent_iq_acquisition_caf.h" +#include "gen_signal_source.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include "pass_through.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" -#include "pass_through.h" - -#include "gnss_block_factory.h" +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### @@ -69,9 +67,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx(); //!< Default destructor + ~GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx(); //!< Default destructor }; @@ -84,32 +83,33 @@ GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx_sptr GalileoE5aPcpsAcquisi void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx::GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx(concurrent_queue& queue) : - gr::block("GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx::GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx(concurrent_queue& queue) : gr::block("GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } + GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx::~GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx() -{} +{ +} -class GalileoE5aPcpsAcquisitionGSoC2014GensourceTest: public ::testing::Test +class GalileoE5aPcpsAcquisitionGSoC2014GensourceTest : public ::testing::Test { protected: GalileoE5aPcpsAcquisitionGSoC2014GensourceTest() @@ -122,7 +122,8 @@ protected: } ~GalileoE5aPcpsAcquisitionGSoC2014GensourceTest() - {} + { + } void init(); void config_1(); @@ -136,7 +137,6 @@ protected: concurrent_queue channel_internal_queue; gr::msg_queue::sptr queue; gr::top_block_sptr top_block; - //std::shared_ptr factory = std::make_shared(); std::shared_ptr acquisition; std::shared_ptr config; @@ -183,6 +183,7 @@ protected: int sat = 0; }; + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::init() { message = 0; @@ -198,47 +199,32 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::init() Pfa_a = 0; } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; - // std::string signal = "5I"; - // std::string signal = "5Q"; std::string signal = "5X"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); - - integration_time_ms = 3; - //fs_in = 11e6; - //fs_in = 18e6; + integration_time_ms = 1; fs_in = 32e6; - //fs_in = 30.69e6; - //fs_in = 20.47e6; - // unsigned int delay_samples = (delay_chips_[sat] % codelen) - // * samples_per_code_[sat] / codelen; - expected_delay_chips = round(14000*((double)10230000/(double)fs_in)); + expected_delay_chips = round(14000.0 * 10230000.0 / static_cast(fs_in)); expected_doppler_hz = 2800; - //expected_doppler_hz = 0; expected_delay_sec = 94; - // CAF_window_hz = 3000; CAF_window_hz = 0; Zero_padding = 0; - //expected_delay_chips = 1000; - //expected_doppler_hz = 250; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - //max_doppler_error_hz = 1000; - //max_delay_error_chips = 1; - num_of_realizations = 1; config = std::make_shared(); - config->set_property("Channel.signal",signal); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("Channel.signal", signal); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); config->set_property("SignalSource.item_type", "gr_complex"); config->set_property("SignalSource.num_satellites", "1"); @@ -276,88 +262,70 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition_Galileo.item_type", "gr_complex"); - config->set_property("Acquisition_Galileo.if", "0"); - config->set_property("Acquisition_Galileo.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition_Galileo.max_dwells", "1"); - config->set_property("Acquisition_Galileo.CAF_window_hz",std::to_string(CAF_window_hz)); - config->set_property("Acquisition_Galileo.Zero_padding",std::to_string(Zero_padding)); - - config->set_property("Acquisition_Galileo.implementation", "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF"); - config->set_property("Acquisition_Galileo.pfa","0.003"); - // config->set_property("Acquisition_Galileo.threshold", "0.01"); - config->set_property("Acquisition_Galileo.doppler_max", "10000"); - config->set_property("Acquisition_Galileo.doppler_step", "250"); - // config->set_property("Acquisition_Galileo.doppler_step", "500"); - config->set_property("Acquisition_Galileo.bit_transition_flag", "false"); - config->set_property("Acquisition_Galileo.dump", "false"); + config->set_property("Acquisition_5X.implementation", "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF"); + config->set_property("Acquisition_5X.item_type", "gr_complex"); + config->set_property("Acquisition_5X.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_5X.max_dwells", "1"); + config->set_property("Acquisition_5X.CAF_window_hz", std::to_string(CAF_window_hz)); + config->set_property("Acquisition_5X.Zero_padding", std::to_string(Zero_padding)); + config->set_property("Acquisition_5X.pfa", "0.003"); + // config->set_property("Acquisition_5X.threshold", "0.01"); + config->set_property("Acquisition_5X.doppler_max", "10000"); + config->set_property("Acquisition_5X.doppler_step", "250"); + config->set_property("Acquisition_5X.bit_transition_flag", "false"); + config->set_property("Acquisition_5X.dump", "false"); config->set_property("SignalSource.dump_filename", "../data/acquisition.dat"); } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_2() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; - std::string signal = "5Q"; - //std::string signal = "5X"; - signal.copy(gnss_synchro.Signal,2,0); + std::string signal = "5X"; + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 3; - //fs_in = 10.24e6; - //fs_in = 12e6; - fs_in = 12e6; - //expected_delay_chips = 600; - //expected_doppler_hz = 750; + fs_in = 12e6; expected_delay_chips = 1000; expected_doppler_hz = 250; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - //max_doppler_error_hz = 1000; - //max_delay_error_chips = 1; - num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); - config->set_property("Acquisition_Galileo.item_type", "gr_complex"); - config->set_property("Acquisition_Galileo.if", "0"); - config->set_property("Acquisition_Galileo.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition_Galileo.max_dwells", "1"); - config->set_property("Acquisition_Galileo.implementation", "Galileo_E5a_PCPS_Acquisition"); - //config->set_property("Acquisition_Galileo.implementation", "Galileo_E5a_Pilot_3ms_Acquisition"); - //config->set_property("Acquisition_Galileo.implementation", "Galileo_E5ax_2ms_Pcps_Acquisition"); - config->set_property("Acquisition_Galileo.threshold", "0.1"); - config->set_property("Acquisition_Galileo.doppler_max", "10000"); - config->set_property("Acquisition_Galileo.doppler_step", "250"); - config->set_property("Acquisition_Galileo.bit_transition_flag", "false"); - config->set_property("Acquisition_Galileo.dump", "false"); + config->set_property("Acquisition_5X.implementation", "Galileo_E5a_PCPS_Acquisition"); + config->set_property("Acquisition_5X.item_type", "gr_complex"); + config->set_property("Acquisition_5X.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_5X.max_dwells", "1"); + config->set_property("Acquisition_5X.threshold", "0.1"); + config->set_property("Acquisition_5X.doppler_max", "10000"); + config->set_property("Acquisition_5X.doppler_step", "250"); + config->set_property("Acquisition_5X.bit_transition_flag", "false"); + config->set_property("Acquisition_5X.dump", "false"); config->set_property("SignalSource.dump_filename", "../data/acquisition.dat"); } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_3() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; //std::string signal = "5Q"; std::string signal = "5X"; - signal.copy(gnss_synchro.Signal,2,0); - + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 3; - //fs_in = 10.24e6; - //fs_in = 12e6; fs_in = 12e6; - //expected_delay_chips = 600; - //expected_doppler_hz = 750; - expected_delay_chips = 0; expected_delay_sec = 0; expected_doppler_hz = 0; @@ -371,16 +339,14 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_3() expected_delay_sec3 = 77; expected_doppler_hz3 = 5000; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - //max_doppler_error_hz = 1000; - //max_delay_error_chips = 1; num_of_realizations = 10; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -446,53 +412,50 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_3() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition_Galileo.item_type", "gr_complex"); - config->set_property("Acquisition_Galileo.if", "0"); - config->set_property("Acquisition_Galileo.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition_Galileo.max_dwells", "1"); - config->set_property("Acquisition_Galileo.implementation", "Galileo_E5a_PCPS_Acquisition"); - //config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition"); - //config->set_property("Acquisition.implementation", "Galileo_E5a_Pilot_3ms_Acquisition"); - - config->set_property("Acquisition_Galileo.threshold", "0.5"); - config->set_property("Acquisition_Galileo.doppler_max", "10000"); - config->set_property("Acquisition_Galileo.doppler_step", "250"); - config->set_property("Acquisition_Galileo.bit_transition_flag", "false"); - config->set_property("Acquisition_Galileo.dump", "false"); + config->set_property("Acquisition_5X.item_type", "gr_complex"); + config->set_property("Acquisition_5X.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_5X.max_dwells", "1"); + config->set_property("Acquisition_5X.implementation", "Galileo_E5a_PCPS_Acquisition"); + config->set_property("Acquisition_5X.threshold", "0.5"); + config->set_property("Acquisition_5X.doppler_max", "10000"); + config->set_property("Acquisition_5X.doppler_step", "250"); + config->set_property("Acquisition_5X.bit_transition_flag", "false"); + config->set_property("Acquisition_5X.dump", "false"); config->set_property("SignalSource.dump_filename", "../data/acquisition.dat"); } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::start_queue() { stop = false; ch_thread = boost::thread(&GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::wait_message, this); } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end-begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::process_message() { if (message == 1) @@ -500,27 +463,27 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::process_message() double delay_error_chips = 0.0; double doppler_error_hz = 0.0; switch (sat) - { - case 0: - delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*10230.0/((double)fs_in*1e-3)); - doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); - break; - case 1: - delay_error_chips = std::abs((double)expected_delay_chips1 - (double)(gnss_synchro.Acq_delay_samples-5)*10230.0/((double)fs_in*1e-3)); - doppler_error_hz = std::abs(expected_doppler_hz1 - gnss_synchro.Acq_doppler_hz); - break; - case 2: - delay_error_chips = std::abs((double)expected_delay_chips2 - (double)(gnss_synchro.Acq_delay_samples-5)*10230.0/((double)fs_in*1e-3)); - doppler_error_hz = std::abs(expected_doppler_hz2 - gnss_synchro.Acq_doppler_hz); - break; - case 3: - delay_error_chips = std::abs((double)expected_delay_chips3 - (double)(gnss_synchro.Acq_delay_samples-5)*10230.0/((double)fs_in*1e-3)); - doppler_error_hz = std::abs(expected_doppler_hz3 - gnss_synchro.Acq_doppler_hz); - break; - default: // case 3 - std::cout << "Error: message from unexpected acquisition channel" << std::endl; - break; - } + { + case 0: + delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 10230.0 / (static_cast(fs_in) * 1e-3)); + doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); + break; + case 1: + delay_error_chips = std::abs(static_cast(expected_delay_chips1) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 10230.0 / (static_cast(fs_in) * 1e-3)); + doppler_error_hz = std::abs(expected_doppler_hz1 - gnss_synchro.Acq_doppler_hz); + break; + case 2: + delay_error_chips = std::abs(static_cast(expected_delay_chips2) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 10230.0 / (static_cast(fs_in) * 1e-3)); + doppler_error_hz = std::abs(expected_doppler_hz2 - gnss_synchro.Acq_doppler_hz); + break; + case 3: + delay_error_chips = std::abs(static_cast(expected_delay_chips3) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 10230.0 / (static_cast(fs_in) * 1e-3)); + doppler_error_hz = std::abs(expected_doppler_hz3 - gnss_synchro.Acq_doppler_hz); + break; + default: // case 3 + std::cout << "Error: message from unexpected acquisition channel" << std::endl; + break; + } detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter @@ -540,16 +503,16 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::process_message() realization_counter++; //std::cout << correct_estimation_counter << "correct estimation counter" << std::endl; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter / num_of_realizations * 100)) << "% \r" << std::flush; //std::cout << message << "message" <(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -568,7 +531,7 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::stop_queue() TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, Instantiate) { config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_5X", 1, 0); } @@ -576,146 +539,82 @@ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ConnectAndRun) { config_1(); //int nsamples = floor(5*fs_in*integration_time_ms*1e-3); - int nsamples = 21000*3; - struct timeval tv; - long long int begin = 0; - long long int end = 0; - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + int nsamples = 21000 * 3; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + acquisition = std::make_shared(config.get(), "Acquisition_5X", 1, 0); boost::shared_ptr msg_rx = GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx_make(channel_internal_queue); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test."<< std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } -/* -TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, SOURCEValidation) -{ - config_1(); - ASSERT_NO_THROW( { - boost::shared_ptr signal_source; - SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); - FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); - signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); - signal_source->connect(top_block); - - - //top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - - }) << "Failure generating signal" << std::endl; -} - */ -/* -TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, SOURCEValidationTOFILE) -{ - config_1(); - ASSERT_NO_THROW( { - std::string filename_ = "../data/Tiered_sinknull.dat"; - boost::shared_ptr file_sink_; - - boost::shared_ptr signal_source; - SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); - FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); - signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); - //signal_source->connect(top_block); - file_sink_=gr::blocks::file_sink::make(sizeof(gr_complex), filename_.c_str()); - - top_block->connect(signal_source->get_right_block(),0,file_sink_,0); - - //top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - - }) << "Failure generating signal" << std::endl; -} - */ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ValidationOfSIM) { config_1(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_5X", 1, 0); boost::shared_ptr msg_rx = GalileoE5aPcpsAcquisitionGSoC2014GensourceTest_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(0); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition_Galileo.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_5X.doppler_max", 5000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition_Galileo.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_5X.doppler_step", 100)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition_Galileo.threshold", 0.0)); - }) << "Failure setting threshold."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_5X.threshold", 0.0001)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; - acquisition->init(); - // USING SIGNAL GENERATOR + // USING THE SIGNAL GENERATOR - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); - FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); filter->connect(top_block); signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; acquisition->reset(); acquisition->init(); - // USING SIGNAL FROM FILE SOURCE - //unsigned int skiphead_sps = 28000+32000; // 32 Msps - // unsigned int skiphead_sps = 0; - // unsigned int skiphead_sps = 84000; - - // ASSERT_NO_THROW( { - // //noiseless sim - // //std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11_long.dat"; - // // real - // std::string file = "/home/marc/E5a_acquisitions/32MS_complex.dat"; - // - // const char * file_name = file.c_str(); - // gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); - // - // gr::blocks::skiphead::sptr skip_head = gr::blocks::skiphead::make(sizeof(gr_complex), skiphead_sps); - // top_block->connect(file_source, 0, skip_head, 0); - // top_block->connect(skip_head, 0, acquisition->get_left_block(), 0); - // - // // top_block->connect(file_source, 0, acquisition->get_left_block(), 0); - // }) << "Failure connecting the blocks of acquisition test." << std::endl; - // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible for (unsigned int i = 0; i < 1; i++) @@ -723,44 +622,41 @@ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ValidationOfSIM) init(); switch (i) - { - case 0: { - gnss_synchro.PRN = 19; // present + case 0: + { + gnss_synchro.PRN = 11; // present + break; + } + case 1: + { + gnss_synchro.PRN = 19; // not present + break; + } } - case 1: - { - gnss_synchro.PRN = 11; - } - } - start_queue(); - - acquisition->reset(); - acquisition->init(); acquisition->set_gnss_synchro(&gnss_synchro); acquisition->set_local_code(); acquisition->set_state(1); + start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); ch_thread.join(); - //std::cout << gnss_synchro.Acq_delay_samples << "acq delay" <(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } - } else if (i == 1) { @@ -768,6 +664,3 @@ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ValidationOfSIM) } } } - - - diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc new file mode 100644 index 000000000..70ad8e25e --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc @@ -0,0 +1,667 @@ +/*! + * \file glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc + * \brief Tests a PCPS acquisition block for Glonass L1 C/A signals + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "configuration_interface.h" +#include "freq_xlating_fir_filter.h" +#include "gen_signal_source.h" +#include "glonass_l1_ca_pcps_acquisition.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include "pass_through.h" +#include "signal_generator.h" +#include "signal_generator_c.h" +#include "boost/shared_ptr.hpp" +#include +#include +#include + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx; + +typedef boost::shared_ptr GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_sptr; + +GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_sptr GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(concurrent_queue& queue); + + +class GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx : public gr::block +{ +private: + friend GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_sptr GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(concurrent_queue& queue); + void msg_handler_events(pmt::pmt_t msg); + GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx(concurrent_queue& queue); + concurrent_queue& channel_internal_queue; + +public: + int rx_message; + ~GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx(); //!< Default destructor +}; + + +GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_sptr GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(concurrent_queue& queue) +{ + return GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_sptr(new GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx(queue)); +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + channel_internal_queue.push(rx_message); + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx::GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx(concurrent_queue& queue) : gr::block("GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx::~GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx() +{ +} + + +// ########################################################### + +class GlonassL1CaPcpsAcquisitionGSoC2017Test : public ::testing::Test +{ +protected: + GlonassL1CaPcpsAcquisitionGSoC2017Test() + { + item_size = sizeof(gr_complex); + stop = false; + message = 0; + gnss_synchro = Gnss_Synchro(); + acquisition = 0; + init(); + } + + ~GlonassL1CaPcpsAcquisitionGSoC2017Test() + { + } + + void init(); + void config_1(); + void config_2(); + void start_queue(); + void wait_message(); + void process_message(); + void stop_queue(); + + concurrent_queue channel_internal_queue; + + gr::msg_queue::sptr queue; + gr::top_block_sptr top_block; + GlonassL1CaPcpsAcquisition* acquisition; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; + bool stop; + int message; + boost::thread ch_thread; + + unsigned int integration_time_ms = 0; + unsigned int fs_in = 0; + + double expected_delay_chips = 0.0; + double expected_doppler_hz = 0.0; + float max_doppler_error_hz = 0.0; + float max_delay_error_chips = 0.0; + + unsigned int num_of_realizations = 0; + unsigned int realization_counter; + unsigned int detection_counter; + unsigned int correct_estimation_counter; + unsigned int acquired_samples; + unsigned int mean_acq_time_us; + + double mse_doppler; + double mse_delay; + + double Pd; + double Pfa_p; + double Pfa_a; +}; + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::init() +{ + message = 0; + realization_counter = 0; + detection_counter = 0; + correct_estimation_counter = 0; + acquired_samples = 0; + mse_doppler = 0; + mse_delay = 0; + mean_acq_time_us = 0; + Pd = 0; + Pfa_p = 0; + Pfa_a = 0; +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::config_1() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "1G"; + signal.copy(gnss_synchro.Signal, 2, 0); + + integration_time_ms = 1; + fs_in = 31.75e6; + + expected_delay_chips = 255; + expected_doppler_hz = -1500; + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); + max_delay_error_chips = 0.50; + + num_of_realizations = 1; + + config = std::make_shared(); + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); + + config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); + + config->set_property("SignalSource.item_type", "gr_complex"); + + config->set_property("SignalSource.num_satellites", "1"); + + config->set_property("SignalSource.system_0", "R"); + config->set_property("SignalSource.PRN_0", "10"); + config->set_property("SignalSource.CN0_dB_0", "44"); + config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); + config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); + + config->set_property("SignalSource.noise_flag", "false"); + config->set_property("SignalSource.data_flag", "false"); + config->set_property("SignalSource.BW_BB", "0.97"); + + config->set_property("InputFilter.implementation", "Freq_Xlating_Fir_Filter"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", "11"); + config->set_property("InputFilter.number_of_bands", "2"); + config->set_property("InputFilter.band1_begin", "0.0"); + config->set_property("InputFilter.band1_end", "0.97"); + config->set_property("InputFilter.band2_begin", "0.98"); + config->set_property("InputFilter.band2_end", "1.0"); + config->set_property("InputFilter.ampl1_begin", "1.0"); + config->set_property("InputFilter.ampl1_end", "1.0"); + config->set_property("InputFilter.ampl2_begin", "0.0"); + config->set_property("InputFilter.ampl2_end", "0.0"); + config->set_property("InputFilter.band1_error", "1.0"); + config->set_property("InputFilter.band2_error", "1.0"); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", "16"); + config->set_property("InputFilter.sampling_frequency", std::to_string(fs_in)); + config->set_property("InputFilter.IF", "4000000"); + + config->set_property("Acquisition.item_type", "gr_complex"); + config->set_property("Acquisition.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition.max_dwells", "1"); + config->set_property("Acquisition.implementation", "GLONASS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition.threshold", "0.8"); + config->set_property("Acquisition.doppler_max", "10000"); + config->set_property("Acquisition.doppler_step", "250"); + config->set_property("Acquisition.bit_transition_flag", "false"); + config->set_property("Acquisition.dump", "false"); +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::config_2() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "1G"; + signal.copy(gnss_synchro.Signal, 2, 0); + + integration_time_ms = 1; + fs_in = 31.75e6; + + expected_delay_chips = 374; + expected_doppler_hz = -2000; + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); + max_delay_error_chips = 0.50; + + num_of_realizations = 100; + + config = std::make_shared(); + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); + + config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); + + config->set_property("SignalSource.item_type", "gr_complex"); + + config->set_property("SignalSource.num_satellites", "4"); + + config->set_property("SignalSource.system_0", "R"); + config->set_property("SignalSource.PRN_0", "10"); + config->set_property("SignalSource.CN0_dB_0", "44"); + config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); + config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); + + config->set_property("SignalSource.system_1", "R"); + config->set_property("SignalSource.PRN_1", "15"); + config->set_property("SignalSource.CN0_dB_1", "44"); + config->set_property("SignalSource.doppler_Hz_1", "1000"); + config->set_property("SignalSource.delay_chips_1", "100"); + + config->set_property("SignalSource.system_2", "R"); + config->set_property("SignalSource.PRN_2", "21"); + config->set_property("SignalSource.CN0_dB_2", "44"); + config->set_property("SignalSource.doppler_Hz_2", "2000"); + config->set_property("SignalSource.delay_chips_2", "200"); + + config->set_property("SignalSource.system_3", "R"); + config->set_property("SignalSource.PRN_3", "22"); + config->set_property("SignalSource.CN0_dB_3", "44"); + config->set_property("SignalSource.doppler_Hz_3", "3000"); + config->set_property("SignalSource.delay_chips_3", "300"); + + config->set_property("SignalSource.noise_flag", "true"); + config->set_property("SignalSource.data_flag", "true"); + config->set_property("SignalSource.BW_BB", "0.97"); + + config->set_property("InputFilter.implementation", "Freq_Xlating_Fir_Filter"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", "11"); + config->set_property("InputFilter.number_of_bands", "2"); + config->set_property("InputFilter.band1_begin", "0.0"); + config->set_property("InputFilter.band1_end", "0.97"); + config->set_property("InputFilter.band2_begin", "0.98"); + config->set_property("InputFilter.band2_end", "1.0"); + config->set_property("InputFilter.ampl1_begin", "1.0"); + config->set_property("InputFilter.ampl1_end", "1.0"); + config->set_property("InputFilter.ampl2_begin", "0.0"); + config->set_property("InputFilter.ampl2_end", "0.0"); + config->set_property("InputFilter.band1_error", "1.0"); + config->set_property("InputFilter.band2_error", "1.0"); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", "16"); + config->set_property("InputFilter.sampling_frequency", std::to_string(fs_in)); + config->set_property("InputFilter.IF", "4000000"); + + config->set_property("Acquisition.item_type", "gr_complex"); + config->set_property("Acquisition.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition.max_dwells", "1"); + config->set_property("Acquisition.implementation", "GLONASS_L1_CA_PCPS_Acquisition"); + //config->set_property("Acquisition.pfa", "0.1"); + config->set_property("Acquisition.doppler_max", "10000"); + config->set_property("Acquisition.doppler_step", "250"); + config->set_property("Acquisition.bit_transition_flag", "false"); + config->set_property("Acquisition.dump", "false"); +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::start_queue() +{ + stop = false; + ch_thread = boost::thread(&GlonassL1CaPcpsAcquisitionGSoC2017Test::wait_message, this); +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::wait_message() +{ + struct timeval tv; + int64_t begin = 0; + int64_t end = 0; + + while (!stop) + { + acquisition->reset(); + + gettimeofday(&tv, NULL); + begin = tv.tv_sec * 1e6 + tv.tv_usec; + + channel_internal_queue.wait_and_pop(message); + + gettimeofday(&tv, NULL); + end = tv.tv_sec * 1e6 + tv.tv_usec; + + mean_acq_time_us += (end - begin); + + process_message(); + } +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::process_message() +{ + if (message == 1) + { + detection_counter++; + + // The term -5 is here to correct the additional delay introduced by the FIR filter + // The value 511.0 must be a variable, chips/length + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - (static_cast(gnss_synchro.Acq_delay_samples) - 5.0) * 511.0 / (static_cast(fs_in) * 1e-3)); + double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); + + mse_delay += std::pow(delay_error_chips, 2); + mse_doppler += std::pow(doppler_error_hz, 2); + + if ((delay_error_chips < max_delay_error_chips) && (doppler_error_hz < max_doppler_error_hz)) + { + correct_estimation_counter++; + } + } + + realization_counter++; + + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; + + if (realization_counter == num_of_realizations) + { + mse_delay /= num_of_realizations; + mse_doppler /= num_of_realizations; + + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = (static_cast(detection_counter) - static_cast(correct_estimation_counter)) / static_cast(num_of_realizations); + + mean_acq_time_us /= num_of_realizations; + + stop_queue(); + top_block->stop(); + } +} + + +void GlonassL1CaPcpsAcquisitionGSoC2017Test::stop_queue() +{ + stop = true; +} + + +TEST_F(GlonassL1CaPcpsAcquisitionGSoC2017Test, Instantiate) +{ + config_1(); + acquisition = new GlonassL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); + delete acquisition; +} + + +TEST_F(GlonassL1CaPcpsAcquisitionGSoC2017Test, ConnectAndRun) +{ + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + + config_1(); + acquisition = new GlonassL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); + boost::shared_ptr msg_rx = GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; + + EXPECT_NO_THROW({ + begin = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; + }) << "Failure running the top_block."; + + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; + + delete acquisition; +} + + +TEST_F(GlonassL1CaPcpsAcquisitionGSoC2017Test, ValidationOfResults) +{ + config_1(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + + acquisition = new GlonassL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); + boost::shared_ptr msg_rx = GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->set_channel(1); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + acquisition->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_max(10000); + }) << "Failure setting doppler_max."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_step(500); + }) << "Failure setting doppler_step."; + + ASSERT_NO_THROW({ + acquisition->set_threshold(0.05); + }) << "Failure setting threshold."; + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting acquisition to the top_block."; + + acquisition->init(); + + ASSERT_NO_THROW({ + std::shared_ptr signal_generator = std::make_shared(config.get(), "SignalSource", 0, 1, queue); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + signal_generator->connect(top_block); + top_block->connect(signal_generator->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, acquisition->get_left_block(), 0); + }) << "Failure connecting the blocks of acquisition test."; + + // i = 0 --> satellite in acquisition is visible + // i = 1 --> satellite in acquisition is not visible + for (unsigned int i = 0; i < 2; i++) + { + init(); + + if (i == 0) + { + gnss_synchro.PRN = 10; // This satellite is visible + } + else if (i == 1) + { + gnss_synchro.PRN = 20; // This satellite is not visible + } + + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + start_queue(); + + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; + + if (i == 0) + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } + else if (i == 1) + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } +#ifdef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.timed_join(boost::posix_time::seconds(1)); + }) << "Failure while waiting the queue to stop."; +#endif +#ifndef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); + }) << "Failure while waiting the queue to stop"; +#endif + } + + delete acquisition; +} + + +TEST_F(GlonassL1CaPcpsAcquisitionGSoC2017Test, ValidationOfResultsProbabilities) +{ + config_2(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + acquisition = new GlonassL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); + boost::shared_ptr msg_rx = GlonassL1CaPcpsAcquisitionGSoC2017Test_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->set_channel(1); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + acquisition->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); + }) << "Failure setting doppler_max."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); + }) << "Failure setting doppler_step."; + + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); + }) << "Failure setting threshold."; + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting acquisition to the top_block."; + + acquisition->init(); + + ASSERT_NO_THROW({ + std::shared_ptr signal_generator = std::make_shared(config.get(), "SignalSource", 0, 1, queue); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + signal_generator->connect(top_block); + top_block->connect(signal_generator->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, acquisition->get_left_block(), 0); + }) << "Failure connecting the blocks of acquisition test."; + + std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; + + // i = 0 --> satellite in acquisition is visible (prob of detection and prob of detection with wrong estimation) + // i = 1 --> satellite in acquisition is not visible (prob of false detection) + for (unsigned int i = 0; i < 2; i++) + { + init(); + + if (i == 0) + { + gnss_synchro.PRN = 10; // This satellite is visible + } + else if (i == 1) + { + gnss_synchro.PRN = 1; // This satellite is not visible + } + + acquisition->set_local_code(); + + start_queue(); + + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block." + << std::endl; + + if (i == 0) + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } + else if (i == 1) + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } +#ifdef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.timed_join(boost::posix_time::seconds(1)); + }) << "Failure while waiting the queue to stop" + << std::endl; +#endif +#ifndef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); + }) << "Failure while waiting the queue to stop" + << std::endl; +#endif + } + + delete acquisition; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc new file mode 100644 index 000000000..9fca76da0 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc @@ -0,0 +1,287 @@ +/*! + * \file glonass_l1_ca_pcps_acquisition_test.cc + * \brief Tests a PCPS acquisition block for Glonass L1 C/A signals + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "freq_xlating_fir_filter.h" +#include "glonass_l1_ca_pcps_acquisition.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include +#include +#include + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GlonassL1CaPcpsAcquisitionTest_msg_rx; + +typedef boost::shared_ptr GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr; + +GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr GlonassL1CaPcpsAcquisitionTest_msg_rx_make(); + +class GlonassL1CaPcpsAcquisitionTest_msg_rx : public gr::block +{ +private: + friend GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr GlonassL1CaPcpsAcquisitionTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GlonassL1CaPcpsAcquisitionTest_msg_rx(); + +public: + int rx_message; + ~GlonassL1CaPcpsAcquisitionTest_msg_rx(); //!< Default destructor +}; + + +GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr GlonassL1CaPcpsAcquisitionTest_msg_rx_make() +{ + return GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr(new GlonassL1CaPcpsAcquisitionTest_msg_rx()); +} + + +void GlonassL1CaPcpsAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + std::cout << "msg_handler_telemetry Bad any cast!" << std::endl; + rx_message = 0; + } +} + + +GlonassL1CaPcpsAcquisitionTest_msg_rx::GlonassL1CaPcpsAcquisitionTest_msg_rx() : gr::block("GlonassL1CaPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GlonassL1CaPcpsAcquisitionTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +GlonassL1CaPcpsAcquisitionTest_msg_rx::~GlonassL1CaPcpsAcquisitionTest_msg_rx() +{ +} + + +// ########################################################### + +class GlonassL1CaPcpsAcquisitionTest : public ::testing::Test +{ +protected: + GlonassL1CaPcpsAcquisitionTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GlonassL1CaPcpsAcquisitionTest() + { + } + + void init(); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +void GlonassL1CaPcpsAcquisitionTest::init() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "1G"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = 1; + config->set_property("GNSS-SDR.internal_fs_sps", "62314000"); + config->set_property("InputFilter.IF", "9540000"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", "11"); + config->set_property("InputFilter.number_of_bands", "2"); + config->set_property("InputFilter.band1_begin", "0.0"); + config->set_property("InputFilter.band1_end", "0.97"); + config->set_property("InputFilter.band2_begin", "0.98"); + config->set_property("InputFilter.band2_end", "1.0"); + config->set_property("InputFilter.ampl1_begin", "1.0"); + config->set_property("InputFilter.ampl1_end", "1.0"); + config->set_property("InputFilter.ampl2_begin", "0.0"); + config->set_property("InputFilter.ampl2_end", "0.0"); + config->set_property("InputFilter.band1_error", "1.0"); + config->set_property("InputFilter.band2_error", "1.0"); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", "16"); + config->set_property("InputFilter.sampling_frequency", "62314000"); + config->set_property("Acquisition_1G.item_type", "gr_complex"); + config->set_property("Acquisition_1G.coherent_integration_time_ms", "1"); + config->set_property("Acquisition_1G.dump", "true"); + config->set_property("Acquisition_1G.dump_filename", "./acquisition"); + config->set_property("Acquisition_1G.implementation", "Glonass_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1G.threshold", "0.001"); + config->set_property("Acquisition_1G.doppler_max", "5000"); + config->set_property("Acquisition_1G.doppler_step", "500"); + config->set_property("Acquisition_1G.repeat_satellite", "false"); + //config->set_property("Acquisition_1G.pfa", "0.0"); +} + + +TEST_F(GlonassL1CaPcpsAcquisitionTest, Instantiate) +{ + init(); + boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition_1G", 1, 0); +} + + +TEST_F(GlonassL1CaPcpsAcquisitionTest, ConnectAndRun) +{ + int fs_in = 62314000; + int nsamples = 62314; + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + + top_block = gr::make_top_block("Acquisition test"); + init(); + boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition_1G", 1, 0); + boost::shared_ptr msg_rx = GlonassL1CaPcpsAcquisitionTest_msg_rx_make(); + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; + + EXPECT_NO_THROW({ + begin = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; + }) << "Failure running the top_block."; + + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(GlonassL1CaPcpsAcquisitionTest, ValidationOfResults) +{ + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Acquisition test"); + + double expected_delay_samples = 31874; + double expected_doppler_hz = -9500; + init(); + std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition_1G", 1, 0); + std::shared_ptr input_filter = std::make_shared(config.get(), "InputFilter", 1, 1); + boost::shared_ptr msg_rx = GlonassL1CaPcpsAcquisitionTest_msg_rx_make(); + + ASSERT_NO_THROW({ + acquisition->set_channel(1); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + acquisition->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + acquisition->set_threshold(0.005); + }) << "Failure setting threshold."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_max(10000); + }) << "Failure setting doppler_max."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_step(500); + }) << "Failure setting doppler_step."; + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + }) << "Failure connecting acquisition to the top_block."; + + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->init(); + + ASSERT_NO_THROW({ + std::string path = std::string(TEST_PATH); + std::string file = path + "signal_samples/Glonass_L1_CA_SIM_Fs_62Msps_4ms.dat"; + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); + top_block->connect(file_source, 0, input_filter->get_left_block(), 0); + top_block->connect(input_filter->get_right_block(), 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; + + EXPECT_NO_THROW({ + begin = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; + }) << "Failure running the top_block."; + + uint64_t nsamples = gnss_synchro.Acq_samplestamp_samples; + std::cout << "Acquired " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; + + ASSERT_EQ(1, msg_rx->rx_message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + + double delay_error_samples = std::abs(expected_delay_samples - gnss_synchro.Acq_delay_samples); + float delay_error_chips = static_cast(delay_error_samples) * 511.0 / 62316.0; + double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); + + EXPECT_LE(doppler_error_hz, 666) << "Doppler error exceeds the expected value: 666 Hz = 2/(3*integration period)"; + EXPECT_LT(delay_error_chips, 0.5) << "Delay error exceeds the expected value: 0.5 chips"; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc new file mode 100644 index 000000000..a8f668f69 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc @@ -0,0 +1,661 @@ +/*! + * \file glonass_l2_ca_pcps_acquisition_test.cc + * \brief Tests a PCPS acquisition block for Glonass L2 C/A signals + * \author Damian Miralles, 2018, dmiralles2009(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "configuration_interface.h" +#include "fir_filter.h" +#include "gen_signal_source.h" +#include "glonass_l2_ca_pcps_acquisition.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include "pass_through.h" +#include "signal_generator.h" +#include "signal_generator_c.h" +#include "boost/shared_ptr.hpp" +#include +#include +#include + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GlonassL2CaPcpsAcquisitionTest_msg_rx; + +typedef boost::shared_ptr GlonassL2CaPcpsAcquisitionTest_msg_rx_sptr; + +GlonassL2CaPcpsAcquisitionTest_msg_rx_sptr GlonassL2CaPcpsAcquisitionTest_msg_rx_make(concurrent_queue& queue); + + +class GlonassL2CaPcpsAcquisitionTest_msg_rx : public gr::block +{ +private: + friend GlonassL2CaPcpsAcquisitionTest_msg_rx_sptr GlonassL2CaPcpsAcquisitionTest_msg_rx_make(concurrent_queue& queue); + void msg_handler_events(pmt::pmt_t msg); + GlonassL2CaPcpsAcquisitionTest_msg_rx(concurrent_queue& queue); + concurrent_queue& channel_internal_queue; + +public: + int rx_message; + ~GlonassL2CaPcpsAcquisitionTest_msg_rx(); //!< Default destructor +}; + + +GlonassL2CaPcpsAcquisitionTest_msg_rx_sptr GlonassL2CaPcpsAcquisitionTest_msg_rx_make(concurrent_queue& queue) +{ + return GlonassL2CaPcpsAcquisitionTest_msg_rx_sptr(new GlonassL2CaPcpsAcquisitionTest_msg_rx(queue)); +} + + +void GlonassL2CaPcpsAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + channel_internal_queue.push(rx_message); + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +GlonassL2CaPcpsAcquisitionTest_msg_rx::GlonassL2CaPcpsAcquisitionTest_msg_rx(concurrent_queue& queue) : gr::block("GlonassL2CaPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GlonassL2CaPcpsAcquisitionTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +GlonassL2CaPcpsAcquisitionTest_msg_rx::~GlonassL2CaPcpsAcquisitionTest_msg_rx() +{ +} + + +// ########################################################### + +class GlonassL2CaPcpsAcquisitionTest : public ::testing::Test +{ +protected: + GlonassL2CaPcpsAcquisitionTest() + { + item_size = sizeof(gr_complex); + stop = false; + message = 0; + gnss_synchro = Gnss_Synchro(); + acquisition = 0; + init(); + } + + ~GlonassL2CaPcpsAcquisitionTest() + { + } + + void init(); + void config_1(); + void config_2(); + void start_queue(); + void wait_message(); + void process_message(); + void stop_queue(); + + concurrent_queue channel_internal_queue; + + gr::msg_queue::sptr queue; + gr::top_block_sptr top_block; + GlonassL2CaPcpsAcquisition* acquisition; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; + bool stop; + int message; + boost::thread ch_thread; + + unsigned int integration_time_ms = 0; + unsigned int fs_in = 0; + + double expected_delay_chips = 0.0; + double expected_doppler_hz = 0.0; + float max_doppler_error_hz = 0.0; + float max_delay_error_chips = 0.0; + + unsigned int num_of_realizations = 0; + unsigned int realization_counter; + unsigned int detection_counter; + unsigned int correct_estimation_counter; + unsigned int acquired_samples; + unsigned int mean_acq_time_us; + + double mse_doppler; + double mse_delay; + + double Pd; + double Pfa_p; + double Pfa_a; +}; + + +void GlonassL2CaPcpsAcquisitionTest::init() +{ + message = 0; + realization_counter = 0; + detection_counter = 0; + correct_estimation_counter = 0; + acquired_samples = 0; + mse_doppler = 0; + mse_delay = 0; + mean_acq_time_us = 0; + Pd = 0; + Pfa_p = 0; + Pfa_a = 0; +} + + +void GlonassL2CaPcpsAcquisitionTest::config_1() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "2G"; + signal.copy(gnss_synchro.Signal, 2, 0); + + integration_time_ms = 1; + fs_in = 31.75e6; + + expected_delay_chips = 255; + expected_doppler_hz = -1500; + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); + max_delay_error_chips = 0.50; + + num_of_realizations = 1; + + config = std::make_shared(); + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); + + config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); + + config->set_property("SignalSource.item_type", "gr_complex"); + + config->set_property("SignalSource.num_satellites", "1"); + + config->set_property("SignalSource.system_0", "R"); + config->set_property("SignalSource.PRN_0", "10"); + config->set_property("SignalSource.CN0_dB_0", "44"); + config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); + config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); + + config->set_property("SignalSource.noise_flag", "false"); + config->set_property("SignalSource.data_flag", "false"); + config->set_property("SignalSource.BW_BB", "0.97"); + + config->set_property("InputFilter.implementation", "Fir_Filter"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", "11"); + config->set_property("InputFilter.number_of_bands", "2"); + config->set_property("InputFilter.band1_begin", "0.0"); + config->set_property("InputFilter.band1_end", "0.97"); + config->set_property("InputFilter.band2_begin", "0.98"); + config->set_property("InputFilter.band2_end", "1.0"); + config->set_property("InputFilter.ampl1_begin", "1.0"); + config->set_property("InputFilter.ampl1_end", "1.0"); + config->set_property("InputFilter.ampl2_begin", "0.0"); + config->set_property("InputFilter.ampl2_end", "0.0"); + config->set_property("InputFilter.band1_error", "1.0"); + config->set_property("InputFilter.band2_error", "1.0"); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", "16"); + + config->set_property("Acquisition_2G.item_type", "gr_complex"); + config->set_property("Acquisition_2G.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_2G.max_dwells", "1"); + config->set_property("Acquisition_2G.implementation", "GLONASS_L2_CA_PCPS_Acquisition"); + config->set_property("Acquisition_2G.threshold", "0.8"); + config->set_property("Acquisition_2G.doppler_max", "10000"); + config->set_property("Acquisition_2G.doppler_step", "250"); + config->set_property("Acquisition_2G.bit_transition_flag", "false"); + config->set_property("Acquisition_2G.dump", "false"); +} + + +void GlonassL2CaPcpsAcquisitionTest::config_2() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "2G"; + signal.copy(gnss_synchro.Signal, 2, 0); + + integration_time_ms = 1; + fs_in = 31.75e6; + + expected_delay_chips = 374; + expected_doppler_hz = -2000; + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); + max_delay_error_chips = 0.50; + + num_of_realizations = 100; + + config = std::make_shared(); + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); + + config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); + + config->set_property("SignalSource.item_type", "gr_complex"); + + config->set_property("SignalSource.num_satellites", "4"); + + config->set_property("SignalSource.system_0", "R"); + config->set_property("SignalSource.PRN_0", "10"); + config->set_property("SignalSource.CN0_dB_0", "44"); + config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); + config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); + + config->set_property("SignalSource.system_1", "R"); + config->set_property("SignalSource.PRN_1", "15"); + config->set_property("SignalSource.CN0_dB_1", "44"); + config->set_property("SignalSource.doppler_Hz_1", "1000"); + config->set_property("SignalSource.delay_chips_1", "100"); + + config->set_property("SignalSource.system_2", "R"); + config->set_property("SignalSource.PRN_2", "21"); + config->set_property("SignalSource.CN0_dB_2", "44"); + config->set_property("SignalSource.doppler_Hz_2", "2000"); + config->set_property("SignalSource.delay_chips_2", "200"); + + config->set_property("SignalSource.system_3", "R"); + config->set_property("SignalSource.PRN_3", "22"); + config->set_property("SignalSource.CN0_dB_3", "44"); + config->set_property("SignalSource.doppler_Hz_3", "3000"); + config->set_property("SignalSource.delay_chips_3", "300"); + + config->set_property("SignalSource.noise_flag", "true"); + config->set_property("SignalSource.data_flag", "true"); + config->set_property("SignalSource.BW_BB", "0.97"); + + config->set_property("InputFilter.implementation", "Fir_Filter"); + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", "11"); + config->set_property("InputFilter.number_of_bands", "2"); + config->set_property("InputFilter.band1_begin", "0.0"); + config->set_property("InputFilter.band1_end", "0.97"); + config->set_property("InputFilter.band2_begin", "0.98"); + config->set_property("InputFilter.band2_end", "1.0"); + config->set_property("InputFilter.ampl1_begin", "1.0"); + config->set_property("InputFilter.ampl1_end", "1.0"); + config->set_property("InputFilter.ampl2_begin", "0.0"); + config->set_property("InputFilter.ampl2_end", "0.0"); + config->set_property("InputFilter.band1_error", "1.0"); + config->set_property("InputFilter.band2_error", "1.0"); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", "16"); + + config->set_property("Acquisition_2G.item_type", "gr_complex"); + config->set_property("Acquisition_2G.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_2G.max_dwells", "1"); + config->set_property("Acquisition_2G.implementation", "GLONASS_L2_CA_PCPS_Acquisition"); + config->set_property("Acquisition_2G.pfa", "0.01"); + config->set_property("Acquisition_2G.doppler_max", "10000"); + config->set_property("Acquisition_2G.doppler_step", "250"); + config->set_property("Acquisition_2G.bit_transition_flag", "false"); + config->set_property("Acquisition_2G.dump", "false"); +} + + +void GlonassL2CaPcpsAcquisitionTest::start_queue() +{ + stop = false; + ch_thread = boost::thread(&GlonassL2CaPcpsAcquisitionTest::wait_message, this); +} + + +void GlonassL2CaPcpsAcquisitionTest::wait_message() +{ + struct timeval tv; + int64_t begin = 0; + int64_t end = 0; + + while (!stop) + { + acquisition->reset(); + + gettimeofday(&tv, NULL); + begin = tv.tv_sec * 1e6 + tv.tv_usec; + + channel_internal_queue.wait_and_pop(message); + + gettimeofday(&tv, NULL); + end = tv.tv_sec * 1e6 + tv.tv_usec; + + mean_acq_time_us += (end - begin); + + process_message(); + } +} + + +void GlonassL2CaPcpsAcquisitionTest::process_message() +{ + if (message == 1) + { + detection_counter++; + + // The term -5 is here to correct the additional delay introduced by the FIR filter + // The value 511.0 must be a variable, chips/length + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - (static_cast(gnss_synchro.Acq_delay_samples) - 5.0) * 511.0 / (static_cast(fs_in) * 1e-3)); + double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); + + mse_delay += std::pow(delay_error_chips, 2); + mse_doppler += std::pow(doppler_error_hz, 2); + + if ((delay_error_chips < max_delay_error_chips) && (doppler_error_hz < max_doppler_error_hz)) + { + correct_estimation_counter++; + } + } + + realization_counter++; + + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; + + if (realization_counter == num_of_realizations) + { + mse_delay /= num_of_realizations; + mse_doppler /= num_of_realizations; + + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = (static_cast(detection_counter) - static_cast(correct_estimation_counter)) / static_cast(num_of_realizations); + + mean_acq_time_us /= num_of_realizations; + + stop_queue(); + top_block->stop(); + } +} + + +void GlonassL2CaPcpsAcquisitionTest::stop_queue() +{ + stop = true; +} + + +TEST_F(GlonassL2CaPcpsAcquisitionTest, Instantiate) +{ + config_1(); + acquisition = new GlonassL2CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); + delete acquisition; +} + + +TEST_F(GlonassL2CaPcpsAcquisitionTest, ConnectAndRun) +{ + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point begin, end; + std::chrono::duration elapsed_seconds(0); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + + config_1(); + acquisition = new GlonassL2CaPcpsAcquisition(config.get(), "Acquisition_2G", 1, 0); + boost::shared_ptr msg_rx = GlonassL2CaPcpsAcquisitionTest_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; + + EXPECT_NO_THROW({ + begin = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - begin; + }) << "Failure running the top_block."; + + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; + + delete acquisition; +} + + +TEST_F(GlonassL2CaPcpsAcquisitionTest, ValidationOfResults) +{ + config_1(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + + acquisition = new GlonassL2CaPcpsAcquisition(config.get(), "Acquisition_2G", 1, 0); + boost::shared_ptr msg_rx = GlonassL2CaPcpsAcquisitionTest_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->set_channel(1); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + acquisition->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_max(10000); + }) << "Failure setting doppler_max."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_step(500); + }) << "Failure setting doppler_step."; + + ASSERT_NO_THROW({ + acquisition->set_threshold(0.0005); + }) << "Failure setting threshold."; + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting acquisition to the top_block."; + + acquisition->init(); + + ASSERT_NO_THROW({ + boost::shared_ptr signal_source; + SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); + FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); + signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); + signal_source->connect(top_block); + top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); + }) << "Failure connecting the blocks of acquisition test."; + + // i = 0 --> satellite in acquisition is visible + // i = 1 --> satellite in acquisition is not visible + for (unsigned int i = 0; i < 2; i++) + { + init(); + + if (i == 0) + { + gnss_synchro.PRN = 10; // This satellite is visible + } + else if (i == 1) + { + gnss_synchro.PRN = 20; // This satellite is not visible + } + + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + start_queue(); + + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; + + if (i == 0) + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } + else if (i == 1) + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } +#ifdef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.timed_join(boost::posix_time::seconds(1)); + }) << "Failure while waiting the queue to stop."; +#endif +#ifndef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); + }) << "Failure while waiting the queue to stop"; +#endif + } + + delete acquisition; +} + + +TEST_F(GlonassL2CaPcpsAcquisitionTest, ValidationOfResultsProbabilities) +{ + config_2(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Acquisition test"); + acquisition = new GlonassL2CaPcpsAcquisition(config.get(), "Acquisition_2G", 1, 0); + boost::shared_ptr msg_rx = GlonassL2CaPcpsAcquisitionTest_msg_rx_make(channel_internal_queue); + + ASSERT_NO_THROW({ + acquisition->set_channel(1); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + acquisition->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_2G.doppler_max", 10000)); + }) << "Failure setting doppler_max."; + + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_2G.doppler_step", 500)); + }) << "Failure setting doppler_step."; + + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_2G.threshold", 0.0)); + }) << "Failure setting threshold."; + + ASSERT_NO_THROW({ + acquisition->connect(top_block); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting acquisition to the top_block."; + + acquisition->init(); + + ASSERT_NO_THROW({ + boost::shared_ptr signal_source; + SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); + FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); + signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); + signal_source->connect(top_block); + top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); + }) << "Failure connecting the blocks of acquisition test."; + + std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; + + // i = 0 --> satellite in acquisition is visible (prob of detection and prob of detection with wrong estimation) + // i = 1 --> satellite in acquisition is not visible (prob of false detection) + for (unsigned int i = 0; i < 2; i++) + { + init(); + + if (i == 0) + { + gnss_synchro.PRN = 10; // This satellite is visible + } + else if (i == 1) + { + gnss_synchro.PRN = 1; // This satellite is not visible + } + + acquisition->set_local_code(); + + start_queue(); + + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; + + if (i == 0) + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } + else if (i == 1) + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } +#ifdef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.timed_join(boost::posix_time::seconds(1)); + }) << "Failure while waiting the queue to stop"; +#endif +#ifndef OLD_BOOST + ASSERT_NO_THROW({ + ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); + }) << "Failure while waiting the queue to stop"; +#endif + } + + delete acquisition; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc index 202762ea3..af4f5b6a5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,33 +25,36 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" +#endif #include "configuration_interface.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_pcps_acquisition.h" -#include "signal_generator.h" -#include "signal_generator_c.h" #include "fir_filter.h" #include "gen_signal_source.h" +#include "gnss_block_interface.h" #include "gnss_sdr_valve.h" -#include "boost/shared_ptr.hpp" +#include "gnss_synchro.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "in_memory_configuration.h" #include "pass_through.h" +#include "signal_generator.h" +#include "signal_generator_c.h" +#include "boost/shared_ptr.hpp" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### @@ -69,9 +72,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -84,21 +88,20 @@ GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_sptr GpsL1CaPcpsAcquisitionGSoC2013Tes void GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); @@ -106,12 +109,13 @@ GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsAcquisitionGSoC2013Test_ms } GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx::~GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx() -{} +{ +} // ########################################################### -class GpsL1CaPcpsAcquisitionGSoC2013Test: public ::testing::Test +class GpsL1CaPcpsAcquisitionGSoC2013Test : public ::testing::Test { protected: GpsL1CaPcpsAcquisitionGSoC2013Test() @@ -140,7 +144,7 @@ protected: gr::msg_queue::sptr queue; gr::top_block_sptr top_block; - GpsL1CaPcpsAcquisition *acquisition; + GpsL1CaPcpsAcquisition* acquisition; std::shared_ptr config; Gnss_Synchro gnss_synchro; size_t item_size; @@ -171,6 +175,7 @@ protected: double Pfa_a; }; + void GpsL1CaPcpsAcquisitionGSoC2013Test::init() { message = 0; @@ -186,26 +191,27 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::init() Pfa_a = 0; } + void GpsL1CaPcpsAcquisitionGSoC2013Test::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 1; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -242,39 +248,39 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition"); - config->set_property("Acquisition.threshold", "0.8"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.threshold", "0.8"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsAcquisitionGSoC2013Test::config_2() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 1; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -329,49 +335,49 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition"); - config->set_property("Acquisition.pfa", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.pfa", "0.1"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsAcquisitionGSoC2013Test::start_queue() { stop = false; ch_thread = boost::thread(&GpsL1CaPcpsAcquisitionGSoC2013Test::wait_message, this); } + void GpsL1CaPcpsAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end-begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GpsL1CaPcpsAcquisitionGSoC2013Test::process_message() { if (message == 1) @@ -379,7 +385,7 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -393,16 +399,16 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter - correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -411,97 +417,99 @@ void GpsL1CaPcpsAcquisitionGSoC2013Test::process_message() } } + void GpsL1CaPcpsAcquisitionGSoC2013Test::stop_queue() { stop = true; } + TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, Instantiate) { config_1(); - acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 1); + acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 0); delete acquisition; } + TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); config_1(); - acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 1); + acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test."<< std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; delete acquisition; } + TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, ValidationOfResults) { config_1(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 1); + acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_max(10000); - }) << "Failure setting doppler_max."<< std::endl; + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_step(500); - }) << "Failure setting doppler_step."<< std::endl; + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(0.5); - }) << "Failure setting threshold."<< std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -511,92 +519,92 @@ TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); - acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->set_state(1); // Ensure that acquisition starts at the first sample start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int) 1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } #ifdef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.timed_join(boost::posix_time::seconds(1)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif #ifndef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif } delete acquisition; } + TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); - acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition", 1, 1); + acquisition = new GpsL1CaPcpsAcquisition(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold."<< std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -608,40 +616,41 @@ TEST_F(GpsL1CaPcpsAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block."<< std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } #ifdef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.timed_join(boost::posix_time::seconds(1)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif #ifndef OLD_BOOST - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ ch_thread.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50)); - }) << "Failure while waiting the queue to stop" << std::endl; + }) << "Failure while waiting the queue to stop"; #endif } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc index 23b5e42f5..d93f11918 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,37 +25,44 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include -#include +#include #include -#include -#include +#include #include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include +#endif +#include "GPS_L1_CA.h" +#include "acquisition_dump_reader.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" +#include "gnuplot_i.h" #include "gps_l1_ca_pcps_acquisition.h" +#include "in_memory_configuration.h" +#include "test_flags.h" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CaPcpsAcquisitionTest_msg_rx; -typedef boost::shared_ptr GpsL1CaPcpsAcquisitionTest_msg_rx_sptr; +using GpsL1CaPcpsAcquisitionTest_msg_rx_sptr = boost::shared_ptr; GpsL1CaPcpsAcquisitionTest_msg_rx_sptr GpsL1CaPcpsAcquisitionTest_msg_rx_make(); @@ -65,9 +72,10 @@ private: friend GpsL1CaPcpsAcquisitionTest_msg_rx_sptr GpsL1CaPcpsAcquisitionTest_msg_rx_make(); void msg_handler_events(pmt::pmt_t msg); GpsL1CaPcpsAcquisitionTest_msg_rx(); + public: int rx_message; - ~GpsL1CaPcpsAcquisitionTest_msg_rx(); //!< Default destructor + ~GpsL1CaPcpsAcquisitionTest_msg_rx(); //!< Default destructor }; @@ -80,20 +88,19 @@ GpsL1CaPcpsAcquisitionTest_msg_rx_sptr GpsL1CaPcpsAcquisitionTest_msg_rx_make() void GpsL1CaPcpsAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(std::move(msg)); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast &e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CaPcpsAcquisitionTest_msg_rx::GpsL1CaPcpsAcquisitionTest_msg_rx() : - gr::block("GpsL1CaPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +GpsL1CaPcpsAcquisitionTest_msg_rx::GpsL1CaPcpsAcquisitionTest_msg_rx() : gr::block("GpsL1CaPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CaPcpsAcquisitionTest_msg_rx::msg_handler_events, this, _1)); @@ -101,13 +108,12 @@ GpsL1CaPcpsAcquisitionTest_msg_rx::GpsL1CaPcpsAcquisitionTest_msg_rx() : } -GpsL1CaPcpsAcquisitionTest_msg_rx::~GpsL1CaPcpsAcquisitionTest_msg_rx() -{} +GpsL1CaPcpsAcquisitionTest_msg_rx::~GpsL1CaPcpsAcquisitionTest_msg_rx() = default; // ########################################################### -class GpsL1CaPcpsAcquisitionTest: public ::testing::Test +class GpsL1CaPcpsAcquisitionTest : public ::testing::Test { protected: GpsL1CaPcpsAcquisitionTest() @@ -116,18 +122,22 @@ protected: config = std::make_shared(); item_size = sizeof(gr_complex); gnss_synchro = Gnss_Synchro(); + doppler_max = 5000; + doppler_step = 100; } - ~GpsL1CaPcpsAcquisitionTest() - {} + ~GpsL1CaPcpsAcquisitionTest() = default; void init(); + void plot_grid(); gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; - Gnss_Synchro gnss_synchro; + Gnss_Synchro gnss_synchro{}; size_t item_size; + unsigned int doppler_max; + unsigned int doppler_step; }; @@ -138,133 +148,212 @@ void GpsL1CaPcpsAcquisitionTest::init() std::string signal = "1C"; signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 1; - config->set_property("GNSS-SDR.internal_fs_hz", "4000000"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", "1"); - config->set_property("Acquisition.dump", "false"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition"); - config->set_property("Acquisition.threshold", "0.001"); - config->set_property("Acquisition.doppler_max", "5000"); - config->set_property("Acquisition.doppler_step", "500"); - config->set_property("Acquisition.repeat_satellite", "false"); - config->set_property("Acquisition.pfa", "0.0"); + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", "1"); + if (FLAGS_plot_acq_grid == true) + { + config->set_property("Acquisition_1C.dump", "true"); + } + else + { + config->set_property("Acquisition_1C.dump", "false"); + } + config->set_property("Acquisition_1C.dump_filename", "./tmp-acq-gps1/acquisition"); + config->set_property("Acquisition_1C.dump_channel", "1"); + config->set_property("Acquisition_1C.threshold", "0.00001"); + config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition_1C.doppler_step", std::to_string(doppler_step)); + config->set_property("Acquisition_1C.repeat_satellite", "false"); + //config->set_property("Acquisition_1C.pfa", "0.0"); } +void GpsL1CaPcpsAcquisitionTest::plot_grid() +{ + //load the measured values + std::string basename = "./tmp-acq-gps1/acquisition_G_1C"; + auto sat = static_cast(gnss_synchro.PRN); + + auto samples_per_code = static_cast(round(4000000 / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); // !! + acquisition_dump_reader acq_dump(basename, sat, doppler_max, doppler_step, samples_per_code, 1); + + if (!acq_dump.read_binary_acq()) std::cout << "Error reading files" << std::endl; + + std::vector *doppler = &acq_dump.doppler; + std::vector *samples = &acq_dump.samples; + std::vector > *mag = &acq_dump.mag; + + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_acq_grid has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + std::cout << "Plotting the acquisition grid. This can take a while..." << std::endl; + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + const std::string &gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("lines"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("GPS L1 C/A signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN)); + g1.set_xlabel("Doppler [Hz]"); + g1.set_ylabel("Sample"); + //g1.cmd("set view 60, 105, 1, 1"); + g1.plot_grid3d(*doppler, *samples, *mag); + + g1.savetops("GPS_L1_acq_grid"); + g1.savetopdf("GPS_L1_acq_grid"); + } + catch (const GnuplotException &ge) + { + std::cout << ge.what() << std::endl; + } + } + std::string data_str = "./tmp-acq-gps1"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } +} + TEST_F(GpsL1CaPcpsAcquisitionTest, Instantiate) { init(); - boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition", 1, 1); + boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition_1C", 1, 0); } + TEST_F(GpsL1CaPcpsAcquisitionTest, ConnectAndRun) { int fs_in = 4000000; int nsamples = 4000; - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); gr::msg_queue::sptr queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); - boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition", 1, 1); + boost::shared_ptr acquisition = boost::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionTest_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of acquisition test."; - }) << "Failure connecting the blocks of acquisition test." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GpsL1CaPcpsAcquisitionTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0.0); top_block = gr::make_top_block("Acquisition test"); double expected_delay_samples = 524; double expected_doppler_hz = 1680; - init(); - std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + init(); + + if (FLAGS_plot_acq_grid == true) + { + std::string data_str = "./tmp-acq-gps1"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } + boost::filesystem::create_directory(data_str); + } + + std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionTest_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_threshold(0.1); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(0.001); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(10000); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(doppler_max); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(250); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(doppler_step); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ std::string path = std::string(TEST_PATH); - //std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; std::string file = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; - const char * file_name = file.c_str(); + const char *file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); top_block->connect(file_source, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - - acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample acquisition->init(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - - - unsigned long int nsamples = gnss_synchro.Acq_samplestamp_samples; - std::cout << "Acquired " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + uint64_t nsamples = gnss_synchro.Acq_samplestamp_samples; + std::cout << "Acquired " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; ASSERT_EQ(1, msg_rx->rx_message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; double delay_error_samples = std::abs(expected_delay_samples - gnss_synchro.Acq_delay_samples); - float delay_error_chips = (float)(delay_error_samples * 1023 / 4000); + auto delay_error_chips = static_cast(delay_error_samples * 1023 / 4000); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); EXPECT_LE(doppler_error_hz, 666) << "Doppler error exceeds the expected value: 666 Hz = 2/(3*integration period)"; EXPECT_LT(delay_error_chips, 0.5) << "Delay error exceeds the expected value: 0.5 chips"; + if (FLAGS_plot_acq_grid == true) + { + plot_grid(); + } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc new file mode 100644 index 000000000..79515988e --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc @@ -0,0 +1,393 @@ +/*! + * \file gps_l1_ca_pcps_acquisition_test_fpga.cc + * \brief This class implements an acquisition test for + * GpsL1CaPcpsAcquisitionFpga class based on some input parameters. + * \author Marc Majoral, 2017. mmajoral(at)cttc.cat + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "in_memory_configuration.h" +#include +#include +#include +#include +#include + +#define DMA_ACQ_TRANSFER_SIZE 2046 // DMA transfer size for the acquisition +#define RX_SIGNAL_MAX_VALUE 127 // 2^7 - 1 for 8-bit signed values +#define NTIMES_CYCLE_THROUGH_RX_SAMPLES_FILE 50 // number of times we cycle through the file containing the received samples +#define ONE_SECOND 1000000 // one second in microseconds +#define FLOAT_SIZE (sizeof(float)) // size of the float variable in characters + +// thread that reads the file containing the received samples, scales the samples to the dynamic range of the fixed point values, sends +// the samples to the DMA and finally it stops the top block +void thread_acquisition_send_rx_samples(gr::top_block_sptr top_block, + const char *file_name) +{ + FILE *rx_signal_file; // file descriptor + int file_length; // length of the file containing the received samples + int dma_descr; // DMA descriptor + + // sleep for 1 second to give some time to GNSS-SDR to activate the acquisition module. + // the acquisition module does not block the RX buffer before activation. + // If this process starts sending samples straight ahead without waiting it could occur that + // the first samples are lost. This is normal behaviour in a real receiver but this is not what + // we want for the test + usleep(ONE_SECOND); + + char *buffer_float; // temporary buffer to convert from binary char to float and from float to char + signed char *buffer_DMA; // temporary buffer to store the samples to be sent to the DMA + buffer_float = (char *)malloc(FLOAT_SIZE); // allocate space for the temporary buffer + if (!buffer_float) + { + fprintf(stderr, "Memory error!"); + } + + rx_signal_file = fopen(file_name, "rb"); // file containing the received signal + if (!rx_signal_file) + { + printf("Unable to open file!"); + } + + // determine the length of the file that contains the received signal + fseek(rx_signal_file, 0, SEEK_END); + file_length = ftell(rx_signal_file); + fseek(rx_signal_file, 0, SEEK_SET); + + // first step: check for the maximum value of the received signal + + float max = 0; + float *pointer_float; + pointer_float = (float *)&buffer_float[0]; + for (int k = 0; k < file_length; k = k + FLOAT_SIZE) + { + fread(buffer_float, FLOAT_SIZE, 1, rx_signal_file); + + if (fabs(pointer_float[0]) > max) + { + max = (pointer_float[0]); + } + } + + // go back to the beginning of the file containing the received samples + fseek(rx_signal_file, 0, SEEK_SET); + + // allocate memory for the samples to be transferred to the DMA + + buffer_DMA = (signed char *)malloc(DMA_ACQ_TRANSFER_SIZE); + if (!buffer_DMA) + { + fprintf(stderr, "Memory error!"); + } + + // open the DMA descriptor + dma_descr = open("/dev/loop_tx", O_WRONLY); + if (dma_descr < 0) + { + printf("can't open loop device\n"); + exit(1); + } + + // cycle through the file containing the received samples + + for (int k = 0; k < NTIMES_CYCLE_THROUGH_RX_SAMPLES_FILE; k++) + { + fseek(rx_signal_file, 0, SEEK_SET); + + int transfer_size; + int num_transferred_samples = 0; + while (num_transferred_samples < static_cast((file_length / FLOAT_SIZE))) + { + if (((file_length / FLOAT_SIZE) - num_transferred_samples) > DMA_ACQ_TRANSFER_SIZE) + { + transfer_size = DMA_ACQ_TRANSFER_SIZE; + num_transferred_samples = num_transferred_samples + DMA_ACQ_TRANSFER_SIZE; + } + else + { + transfer_size = file_length / FLOAT_SIZE - num_transferred_samples; + num_transferred_samples = file_length / FLOAT_SIZE; + } + + for (int t = 0; t < transfer_size; t++) + { + fread(buffer_float, FLOAT_SIZE, 1, rx_signal_file); + + // specify (float) (int) for a quantization maximizing the dynamic range + buffer_DMA[t] = static_cast((pointer_float[0] * (RX_SIGNAL_MAX_VALUE - 1) / max)); + } + + //send_acquisition_gps_input_samples(buffer_DMA, transfer_size, dma_descr); + assert(transfer_size == write(dma_descr, &buffer_DMA[0], transfer_size)); + } + } + fclose(rx_signal_file); + free(buffer_float); + free(buffer_DMA); + close(dma_descr); + + // when all the samples are sent stop the top block + + top_block->stop(); +} + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GpsL1CaPcpsAcquisitionTestFpga_msg_rx; + +typedef boost::shared_ptr GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr; + +GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr GpsL1CaPcpsAcquisitionTestFpga_msg_rx_make(); + +class GpsL1CaPcpsAcquisitionTestFpga_msg_rx : public gr::block +{ +private: + friend GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr GpsL1CaPcpsAcquisitionTestFpga_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GpsL1CaPcpsAcquisitionTestFpga_msg_rx(); + +public: + int rx_message; + ~GpsL1CaPcpsAcquisitionTestFpga_msg_rx(); //!< Default destructor +}; + + +GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr GpsL1CaPcpsAcquisitionTestFpga_msg_rx_make() +{ + return GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr( + new GpsL1CaPcpsAcquisitionTestFpga_msg_rx()); +} + + +void GpsL1CaPcpsAcquisitionTestFpga_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast &e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +GpsL1CaPcpsAcquisitionTestFpga_msg_rx::GpsL1CaPcpsAcquisitionTestFpga_msg_rx() : gr::block("GpsL1CaPcpsAcquisitionTestFpga_msg_rx", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), + boost::bind(&GpsL1CaPcpsAcquisitionTestFpga_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +GpsL1CaPcpsAcquisitionTestFpga_msg_rx::~GpsL1CaPcpsAcquisitionTestFpga_msg_rx() +{ +} + + +class GpsL1CaPcpsAcquisitionTestFpga : public ::testing::Test +{ +protected: + GpsL1CaPcpsAcquisitionTestFpga() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GpsL1CaPcpsAcquisitionTestFpga() + { + } + + void init(); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +void GpsL1CaPcpsAcquisitionTestFpga::init() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = 1; + config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); + config->set_property("Acquisition_1C.item_type", "cshort"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", "1"); + config->set_property("Acquisition_1C.dump", "false"); + config->set_property("Acquisition_1C.threshold", "0.001"); + config->set_property("Acquisition_1C.doppler_max", "5000"); + config->set_property("Acquisition_1C.doppler_step", "500"); + config->set_property("Acquisition_1C.repeat_satellite", "false"); + config->set_property("Acquisition_1C.pfa", "0.0"); + config->set_property("Acquisition_1C.select_queue_Fpga", "0"); + config->set_property("Acquisition_1C.devicename", "/dev/uio0"); +} + + +TEST_F(GpsL1CaPcpsAcquisitionTestFpga, Instantiate) +{ + init(); + boost::shared_ptr acquisition = + boost::make_shared(config.get(), "Acquisition_1C", 0, 1); +} + + +TEST_F(GpsL1CaPcpsAcquisitionTestFpga, ValidationOfResults) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Acquisition test"); + + double expected_delay_samples = 524; + double expected_doppler_hz = 1680; + init(); + + std::shared_ptr acquisition = + std::make_shared(config.get(), "Acquisition_1C", 0, 1); + + boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionTestFpga_msg_rx_make(); + + ASSERT_NO_THROW( + { + acquisition->set_channel(1); + }) + << "Failure setting channel."; + + ASSERT_NO_THROW( + { + acquisition->set_gnss_synchro(&gnss_synchro); + }) + << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW( + { + acquisition->set_threshold(0.1); + }) + << "Failure setting threshold."; + + ASSERT_NO_THROW( + { + acquisition->set_doppler_max(10000); + }) + << "Failure setting doppler_max."; + + ASSERT_NO_THROW( + { + acquisition->set_doppler_step(250); + }) + << "Failure setting doppler_step."; + + ASSERT_NO_THROW( + { + acquisition->connect(top_block); + }) + << "Failure connecting acquisition to the top_block."; + + // uncomment the next line to load the file from the current directory + std::string file = "./GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + + // uncomment the next two lines to load the file from the signal samples subdirectory + //std::string path = std::string(TEST_PATH); + //std::string file = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + + const char *file_name = file.c_str(); + + ASSERT_NO_THROW( + { + // for the unit test use dummy blocks to make the flowgraph work and allow the acquisition message to be sent. + // in the actual system there is a flowchart running in parallel so this is not needed + + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); + gr::blocks::null_sink::sptr null_sink = gr::blocks::null_sink::make(sizeof(gr_complex)); + gr::blocks::throttle::sptr throttle_block = gr::blocks::throttle::make(sizeof(gr_complex), 1000); + + top_block->connect(file_source, 0, throttle_block, 0); + top_block->connect(throttle_block, 0, null_sink, 0); + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) + << "Failure connecting the blocks of acquisition test."; + + acquisition->set_state(1); // Ensure that acquisition starts at the first state + acquisition->init(); + top_block->start(); // Start the top block + + // start thread that sends the DMA samples to the FPGA + boost::thread t3{thread_acquisition_send_rx_samples, top_block, file_name}; + + EXPECT_NO_THROW( + { + start = std::chrono::system_clock::now(); + acquisition->reset(); // launch the tracking process + top_block->wait(); + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) + << "Failure running the top_block."; + + t3.join(); + + std::cout << "Ran GpsL1CaPcpsAcquisitionTestFpga in " << elapsed_seconds.count() * 1e6 + << " microseconds" << std::endl; + + ASSERT_EQ(1, msg_rx->rx_message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + + double delay_error_samples = std::abs(expected_delay_samples - gnss_synchro.Acq_delay_samples); + float delay_error_chips = static_cast(delay_error_samples * 1023 / 4000); + double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); + + EXPECT_LE(doppler_error_hz, 666) << "Doppler error exceeds the expected value: 666 Hz = 2/(3*integration period)"; + EXPECT_LT(delay_error_chips, 0.5) << "Delay error exceeds the expected value: 0.5 chips"; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_multithread_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_multithread_acquisition_gsoc2013_test.cc deleted file mode 100644 index 229df9567..000000000 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_multithread_acquisition_gsoc2013_test.cc +++ /dev/null @@ -1,563 +0,0 @@ -/*! - * \file gps_l1_ca_pcps_multithread_acquisition_gsoc2013_test.cc - * \brief This class implements an acquisition test for - * GpsL1CaPcpsMultithreadAcquisition class. - * \author Marc Molina, 2013. marc.molina.pena(at)gmail.com - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" -#include "configuration_interface.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_pcps_multithread_acquisition.h" -#include "signal_generator.h" -#include "signal_generator_c.h" -#include "fir_filter.h" -#include "gen_signal_source.h" -#include "gnss_sdr_valve.h" -#include "signal_generator.h" -#include "signal_generator.cc" -#include "signal_generator_c.h" -#include "signal_generator_c.cc" - - -class GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test: public ::testing::Test -{ -protected: - GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test() - { - item_size = sizeof(gr_complex); - stop = false; - message = 0; - gnss_synchro = Gnss_Synchro(); - } - - ~GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test() - { - } - - void init(); - void config_1(); - void config_2(); - void start_queue(); - void wait_message(); - void process_message(); - void stop_queue(); - - gr::msg_queue::sptr queue; - gr::top_block_sptr top_block; - std::shared_ptr acquisition; - std::shared_ptr config; - Gnss_Synchro gnss_synchro; - size_t item_size; - bool stop; - int message; - boost::thread ch_thread; - - unsigned int integration_time_ms = 0; - unsigned int fs_in = 0; - - double expected_delay_chips = 0.0; - double expected_doppler_hz = 0.0; - float max_doppler_error_hz = 0.0; - float max_delay_error_chips = 0.0; - - unsigned int num_of_realizations = 0; - unsigned int realization_counter = 0; - unsigned int detection_counter = 0; - unsigned int correct_estimation_counter = 0; - unsigned int acquired_samples = 0; - unsigned int mean_acq_time_us = 0; - - double mse_doppler = 0.0; - double mse_delay = 0.0; - - double Pd = 0.0; - double Pfa_p = 0.0; - double Pfa_a = 0.0; -}; - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::init() -{ - message = 0; - realization_counter = 0; - detection_counter = 0; - correct_estimation_counter = 0; - acquired_samples = 0; - mse_doppler = 0; - mse_delay = 0; - mean_acq_time_us = 0; - Pd = 0; - Pfa_p = 0; - Pfa_a = 0; -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::config_1() -{ - gnss_synchro.Channel_ID = 0; - gnss_synchro.System = 'G'; - std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); - - integration_time_ms = 1; - fs_in = 4e6; - - expected_delay_chips = 600; - expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); - max_delay_error_chips = 0.50; - - num_of_realizations = 1; - - config = std::make_shared(); - - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); - - config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); - - config->set_property("SignalSource.item_type", "gr_complex"); - - config->set_property("SignalSource.num_satellites", "1"); - - config->set_property("SignalSource.system_0", "G"); - config->set_property("SignalSource.PRN_0", "10"); - config->set_property("SignalSource.CN0_dB_0", "44"); - config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); - config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); - - config->set_property("SignalSource.noise_flag", "false"); - config->set_property("SignalSource.data_flag", "false"); - config->set_property("SignalSource.BW_BB", "0.97"); - - config->set_property("InputFilter.implementation", "Fir_Filter"); - config->set_property("InputFilter.input_item_type", "gr_complex"); - config->set_property("InputFilter.output_item_type", "gr_complex"); - config->set_property("InputFilter.taps_item_type", "float"); - config->set_property("InputFilter.number_of_taps", "11"); - config->set_property("InputFilter.number_of_bands", "2"); - config->set_property("InputFilter.band1_begin", "0.0"); - config->set_property("InputFilter.band1_end", "0.97"); - config->set_property("InputFilter.band2_begin", "0.98"); - config->set_property("InputFilter.band2_end", "1.0"); - config->set_property("InputFilter.ampl1_begin", "1.0"); - config->set_property("InputFilter.ampl1_end", "1.0"); - config->set_property("InputFilter.ampl2_begin", "0.0"); - config->set_property("InputFilter.ampl2_end", "0.0"); - config->set_property("InputFilter.band1_error", "1.0"); - config->set_property("InputFilter.band2_error", "1.0"); - config->set_property("InputFilter.filter_type", "bandpass"); - config->set_property("InputFilter.grid_density", "16"); - - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Multithread_Acquisition"); - config->set_property("Acquisition.threshold", "0.8"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::config_2() -{ - gnss_synchro.Channel_ID = 0; - gnss_synchro.System = 'G'; - std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); - - integration_time_ms = 1; - fs_in = 4e6; - - expected_delay_chips = 600; - expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); - max_delay_error_chips = 0.50; - - num_of_realizations = 100; - - config = std::make_shared(); - - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); - - config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); - - config->set_property("SignalSource.item_type", "gr_complex"); - - config->set_property("SignalSource.num_satellites", "4"); - - config->set_property("SignalSource.system_0", "G"); - config->set_property("SignalSource.PRN_0", "10"); - config->set_property("SignalSource.CN0_dB_0", "44"); - config->set_property("SignalSource.doppler_Hz_0", std::to_string(expected_doppler_hz)); - config->set_property("SignalSource.delay_chips_0", std::to_string(expected_delay_chips)); - - config->set_property("SignalSource.system_1", "G"); - config->set_property("SignalSource.PRN_1", "15"); - config->set_property("SignalSource.CN0_dB_1", "44"); - config->set_property("SignalSource.doppler_Hz_1", "1000"); - config->set_property("SignalSource.delay_chips_1", "100"); - - config->set_property("SignalSource.system_2", "G"); - config->set_property("SignalSource.PRN_2", "21"); - config->set_property("SignalSource.CN0_dB_2", "44"); - config->set_property("SignalSource.doppler_Hz_2", "2000"); - config->set_property("SignalSource.delay_chips_2", "200"); - - config->set_property("SignalSource.system_3", "G"); - config->set_property("SignalSource.PRN_3", "22"); - config->set_property("SignalSource.CN0_dB_3", "44"); - config->set_property("SignalSource.doppler_Hz_3", "3000"); - config->set_property("SignalSource.delay_chips_3", "300"); - - config->set_property("SignalSource.noise_flag", "true"); - config->set_property("SignalSource.data_flag", "true"); - config->set_property("SignalSource.BW_BB", "0.97"); - - config->set_property("InputFilter.implementation", "Fir_Filter"); - config->set_property("InputFilter.input_item_type", "gr_complex"); - config->set_property("InputFilter.output_item_type", "gr_complex"); - config->set_property("InputFilter.taps_item_type", "float"); - config->set_property("InputFilter.number_of_taps", "11"); - config->set_property("InputFilter.number_of_bands", "2"); - config->set_property("InputFilter.band1_begin", "0.0"); - config->set_property("InputFilter.band1_end", "0.97"); - config->set_property("InputFilter.band2_begin", "0.98"); - config->set_property("InputFilter.band2_end", "1.0"); - config->set_property("InputFilter.ampl1_begin", "1.0"); - config->set_property("InputFilter.ampl1_end", "1.0"); - config->set_property("InputFilter.ampl2_begin", "0.0"); - config->set_property("InputFilter.ampl2_end", "0.0"); - config->set_property("InputFilter.band1_error", "1.0"); - config->set_property("InputFilter.band2_error", "1.0"); - config->set_property("InputFilter.filter_type", "bandpass"); - config->set_property("InputFilter.grid_density", "16"); - - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Multithread_Acquisition"); - config->set_property("Acquisition.pfa", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::start_queue() -{ - stop = false; - ch_thread = boost::thread(&GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::wait_message, this); -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::wait_message() -{ - struct timeval tv; - long long int begin = 0; - long long int end = 0; - - while (!stop) - { - acquisition->reset(); - - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - - channel_internal_queue.wait_and_pop(message); - - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - - mean_acq_time_us += (end-begin); - - process_message(); - } -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::process_message() -{ - if (message == 1) - { - detection_counter++; - - // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); - double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); - - mse_delay += std::pow(delay_error_chips, 2); - mse_doppler += std::pow(doppler_error_hz, 2); - - if ((delay_error_chips < max_delay_error_chips) && (doppler_error_hz < max_doppler_error_hz)) - { - correct_estimation_counter++; - } - } - - realization_counter++; - - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; - - if (realization_counter == num_of_realizations) - { - mse_delay /= num_of_realizations; - mse_doppler /= num_of_realizations; - - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; - - mean_acq_time_us /= num_of_realizations; - - stop_queue(); - top_block->stop(); - - std::cout << std::endl; - } -} - -void GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test::stop_queue() -{ - stop = true; -} - -TEST_F(GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test, Instantiate) -{ - config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); -} - -TEST_F(GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test, ConnectAndRun) -{ - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; - queue = gr::msg_queue::make(0); - top_block = gr::make_top_block("Acquisition test"); - - config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); - - ASSERT_NO_THROW( { - acquisition->connect(top_block); - boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); - boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); - top_block->connect(source, 0, valve, 0); - top_block->connect(valve, 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; - - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; -} - -TEST_F(GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test, ValidationOfResults) -{ - config_1(); - queue = gr::msg_queue::make(0); - top_block = gr::make_top_block("Acquisition test"); - - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); - - ASSERT_NO_THROW( { - acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; - - ASSERT_NO_THROW( { - acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; - - acquisition->init(); - - ASSERT_NO_THROW( { - boost::shared_ptr signal_source; - SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); - FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); - signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); - signal_source->connect(top_block); - top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; - - // i = 0 --> satellite in acquisition is visible - // i = 1 --> satellite in acquisition is not visible - for (unsigned int i = 0; i < 2; i++) - { - init(); - - if (i == 0) - { - gnss_synchro.PRN = 10; // This satellite is visible - } - else if (i == 1) - { - gnss_synchro.PRN = 20; // This satellite is not visible - } - - acquisition->set_local_code(); - - start_queue(); - - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; - - if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - - } - else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } - } -} - -TEST_F(GpsL1CaPcpsMultithreadAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) -{ - config_2(); - queue = gr::msg_queue::make(0); - top_block = gr::make_top_block("Acquisition test"); - - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); - - ASSERT_NO_THROW( { - acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; - - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; - - ASSERT_NO_THROW( { - acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; - - acquisition->init(); - - ASSERT_NO_THROW( { - boost::shared_ptr signal_source; - SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); - FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); - signal_source.reset(new GenSignalSource(signal_generator, filter, "SignalSource", queue)); - signal_source->connect(top_block); - top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); - }) << "Failure connecting the blocks of acquisition test." << std::endl; - - std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; - - // i = 0 --> satellite in acquisition is visible (prob of detection and prob of detection with wrong estimation) - // i = 1 --> satellite in acquisition is not visible (prob of false detection) - for (unsigned int i = 0; i < 2; i++) - { - init(); - - if (i == 0) - { - gnss_synchro.PRN = 10; // This satellite is visible - } - else if (i == 1) - { - gnss_synchro.PRN = 20; // This satellite is not visible - } - - acquisition->set_local_code(); - - start_queue(); - - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; - - if (i == 0) - { - std::cout << "Probability of detection = " << Pd << std::endl; - std::cout << "Probability of false alarm (satellite present) = " << Pfa_p << std::endl; -// std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } - else if (i == 1) - { - std::cout << "Probability of false alarm (satellite absent) = " << Pfa_a << std::endl; -// std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } - } - -} diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc index b66e54e5d..2fa64118b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,31 +25,34 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" +#endif #include "configuration_interface.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_pcps_opencl_acquisition.h" -#include "signal_generator.h" -#include "signal_generator_c.h" #include "fir_filter.h" #include "gen_signal_source.h" +#include "gnss_block_interface.h" #include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "gps_l1_ca_pcps_opencl_acquisition.h" +#include "in_memory_configuration.h" +#include "signal_generator.h" +#include "signal_generator_c.h" +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx; @@ -66,9 +69,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -81,21 +85,20 @@ GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx_sptr GpsL1CaPcpsOpenClAcquisitio void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); @@ -103,12 +106,13 @@ GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsOpenClAcquisitionGSo } GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx::~GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx() -{} +{ +} // ########################################################### -class GpsL1CaPcpsOpenClAcquisitionGSoC2013Test: public ::testing::Test +class GpsL1CaPcpsOpenClAcquisitionGSoC2013Test : public ::testing::Test { protected: GpsL1CaPcpsOpenClAcquisitionGSoC2013Test() @@ -123,7 +127,8 @@ protected: } ~GpsL1CaPcpsOpenClAcquisitionGSoC2013Test() - {} + { + } void init(); void config_1(); @@ -167,6 +172,7 @@ protected: double Pfa_a; }; + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::init() { message = 0; @@ -182,26 +188,27 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::init() Pfa_a = 0; } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 1; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -238,19 +245,19 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_OpenCl_Acquisition"); - config->set_property("Acquisition.threshold", "0.8"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_OpenCl_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.threshold", "0.8"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::config_2() { gnss_synchro.Channel_ID = 0; @@ -263,14 +270,14 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::config_2() expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - num_of_realizations = 10; // Change here the number of realizations + num_of_realizations = 10; // Change here the number of realizations config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -325,49 +332,49 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_OpenCl_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_OpenCl_Acquisition"); - config->set_property("Acquisition.pfa", "0.1"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.pfa", "0.1"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::start_queue() { stop = false; ch_thread = boost::thread(&GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::wait_message, this); } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end-begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::process_message() { if (message == 1) @@ -375,7 +382,7 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples- 5 )*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -389,16 +396,16 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -409,82 +416,84 @@ void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::process_message() } } + void GpsL1CaPcpsOpenClAcquisitionGSoC2013Test::stop_queue() { stop = true; } + TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, Instantiate) { config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); } + TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1e6 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResults) { config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -492,7 +501,7 @@ TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -502,71 +511,71 @@ TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } } } + TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsOpenClAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -574,7 +583,7 @@ TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResultsProbabilitie signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -586,31 +595,31 @@ TEST_F(GpsL1CaPcpsOpenClAcquisitionGSoC2013Test, ValidationOfResultsProbabilitie if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc index e67d4068c..966b33473 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,32 +25,34 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include #include -#include -#include #include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include +#endif #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" +#include "gps_l1_ca_pcps_quicksync_acquisition.h" +#include "in_memory_configuration.h" #include "signal_generator.h" #include "signal_generator_c.h" -#include "gps_l1_ca_pcps_quicksync_acquisition.h" +#include +#include +#include DEFINE_double(value_threshold, 1, "Value of the threshold for the acquisition"); DEFINE_int32(value_CN0_dB_0, 44, "Value for the CN0_dB_0 in channel 0"); @@ -72,9 +74,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx(); //!< Default destructor + ~GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx(); //!< Default destructor }; @@ -87,49 +90,49 @@ GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx_sptr GpsL1CaPcpsQuickSyncAcqu void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx::GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue) : - gr::block("GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx::GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx(concurrent_queue& queue) : gr::block("GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } + GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx::~GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test_msg_rx() -{} +{ +} // ########################################################### - - -class GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test: public ::testing::Test +class GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test : public ::testing::Test { protected: GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test() -{ + { factory = std::make_shared(); item_size = sizeof(gr_complex); stop = false; message = 0; gnss_synchro = Gnss_Synchro(); -} + } ~GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test() - {} + { + } void init(); void config_1(); @@ -198,29 +201,29 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::init() miss_detection_counter = 0; Pmd = 0; - } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 4; fs_in = 8e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); config->set_property("SignalSource.item_type", "gr_complex"); @@ -256,43 +259,43 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); - config->set_property("Acquisition.threshold", "250"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.threshold", "250"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_2() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 4; fs_in = 8e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - + /*Unset this flag to eliminates data logging for the Validation of results probabilities test*/ dump_test_results = false; - + num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -347,43 +350,43 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "1"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); - config->set_property("Acquisition.threshold", std::to_string(FLAGS_value_threshold)); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "100"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "1"); + config->set_property("Acquisition_1C.threshold", std::to_string(FLAGS_value_threshold)); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "100"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_3() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 4; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; - + /*Unset this flag to eliminates data logging for the Validation of results probabilities test*/ dump_test_results = true; - + num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -438,58 +441,57 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::config_3() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.max_dwells", "2"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); - config->set_property("Acquisition.threshold", "0.01"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.bit_transition_flag", "false"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_QuickSync_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.max_dwells", "2"); + config->set_property("Acquisition_1C.threshold", "0.01"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::start_queue() { stop = false; ch_thread = boost::thread(&GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::wait_message, this); } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1e6 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; - mean_acq_time_us += (end - begin); + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::process_message() { - if (message == 1) { detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples - 5) * 1023.0/ ((double)fs_in * 1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -500,24 +502,24 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::process_message() correct_estimation_counter++; } } - else if(message == 2 && gnss_synchro.PRN == 10) + else if (message == 2 && gnss_synchro.PRN == 10) { miss_detection_counter++; } realization_counter++; - std::cout << "Progress: " << round((float)realization_counter / num_of_realizations * 100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; - Pmd = (double)miss_detection_counter / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); + Pmd = static_cast(miss_detection_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -536,81 +538,78 @@ void GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test::stop_queue() TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, Instantiate) { config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); } + TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ConnectAndRun) { int nsamples = floor(fs_in * integration_time_ms * 1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0.0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test."<< std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1e6 + tv.tv_usec; - }) << "Failure running the top_block."<< std::endl; - - std::cout << "Processed " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResults) { config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_max(10000); - }) << "Failure setting doppler_max."<< std::endl; + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_step(250); - }) << "Failure setting doppler_step."<< std::endl; + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(100); - }) << "Failure setting threshold."<< std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -618,7 +617,7 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -629,11 +628,11 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->reset(); @@ -642,9 +641,9 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResults) acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); @@ -653,11 +652,9 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResults) EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; if (message == 1) { - - EXPECT_EQ((unsigned int)1, correct_estimation_counter) + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } - } else if (i == 1) { @@ -676,37 +673,37 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsWithNoise config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_max(10000); - }) << "Failure setting doppler_max."<< std::endl; + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_doppler_step(250); - }) << "Failure setting doppler_step."<< std::endl; + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(100); - }) << "Failure setting threshold." << std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -714,7 +711,7 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsWithNoise signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -725,11 +722,11 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsWithNoise if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } //acquisition->set_local_code(); acquisition->reset(); @@ -738,9 +735,9 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsWithNoise acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); @@ -749,9 +746,8 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsWithNoise EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; if (message == 1) { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; } - } else if (i == 1) { @@ -768,37 +764,25 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel."<< std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro."<< std::endl; + }) << "Failure setting gnss_synchro."; - /* ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max."<< std::endl; - - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step."<< std::endl; - - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold."<< std::endl; */ - - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block."<< std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); acquisition->reset(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -806,7 +790,7 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -818,11 +802,11 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->reset(); @@ -831,9 +815,9 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); @@ -844,13 +828,13 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili std::cout << "Estimated probability of miss detection (satellite present) = " << Pmd << std::endl; std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - if(dump_test_results) + if (dump_test_results) { std::stringstream filenamepd; filenamepd.str(""); filenamepd << "../data/test_statistics_" << gnss_synchro.System << "_" << gnss_synchro.Signal << "_sat_" - << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_value_CN0_dB_0 << "_dBHz.csv"; + << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_value_CN0_dB_0 << "_dBHz.csv"; pdpfafile.open(filenamepd.str().c_str(), std::ios::app | std::ios::out); pdpfafile << FLAGS_value_threshold << "," << Pd << "," << Pfa_p << "," << Pmd << std::endl; @@ -862,13 +846,13 @@ TEST_F(GpsL1CaPcpsQuickSyncAcquisitionGSoC2014Test, ValidationOfResultsProbabili std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - if(dump_test_results) + if (dump_test_results) { std::stringstream filenamepf; filenamepf.str(""); filenamepf << "../data/test_statistics_" << gnss_synchro.System << "_" << gnss_synchro.Signal << "_sat_" - << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_value_CN0_dB_0 << "_dBHz.csv"; + << gnss_synchro.PRN << "CN0_dB_0_" << FLAGS_value_CN0_dB_0 << "_dBHz.csv"; pdpfafile.open(filenamepf.str().c_str(), std::ios::app | std::ios::out); pdpfafile << FLAGS_value_threshold << "," << Pfa_a << std::endl; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc index cb7761b02..d24b4b0f7 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,33 +25,35 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include -#include "gnss_block_interface.h" -#include "in_memory_configuration.h" +#endif #include "configuration_interface.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_pcps_tong_acquisition.h" -#include "signal_generator.h" -#include "signal_generator_c.h" #include "fir_filter.h" #include "gen_signal_source.h" +#include "gnss_block_interface.h" #include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "gps_l1_ca_pcps_tong_acquisition.h" +#include "in_memory_configuration.h" +#include "signal_generator.h" +#include "signal_generator_c.h" +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx; @@ -68,9 +70,10 @@ private: void msg_handler_events(pmt::pmt_t msg); GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue); concurrent_queue& channel_internal_queue; + public: int rx_message; - ~GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor + ~GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx(); //!< Default destructor }; @@ -83,21 +86,20 @@ GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx_sptr GpsL1CaPcpsTongAcquisitionGSo void GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : - gr::block("GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) +GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx(concurrent_queue& queue) : gr::block("GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), channel_internal_queue(queue) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::msg_handler_events, this, _1)); @@ -105,12 +107,13 @@ GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::GpsL1CaPcpsTongAcquisitionGSoC201 } GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx::~GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx() -{} +{ +} // ########################################################### -class GpsL1CaPcpsTongAcquisitionGSoC2013Test: public ::testing::Test +class GpsL1CaPcpsTongAcquisitionGSoC2013Test : public ::testing::Test { protected: GpsL1CaPcpsTongAcquisitionGSoC2013Test() @@ -167,6 +170,7 @@ protected: double Pfa_a = 0.0; }; + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::init() { message = 0; @@ -182,26 +186,27 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::init() Pfa_a = 0; } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::config_1() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 1; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 1; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -238,39 +243,39 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::config_1() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); - config->set_property("Acquisition.threshold", "0.8"); - config->set_property("Acquisition.tong_init_val", "1"); - config->set_property("Acquisition.tong_max_val", "8"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.threshold", "0.8"); + config->set_property("Acquisition_1C.tong_init_val", "1"); + config->set_property("Acquisition_1C.tong_max_val", "8"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::config_2() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "1C"; - signal.copy(gnss_synchro.Signal,2,0); + signal.copy(gnss_synchro.Signal, 2, 0); integration_time_ms = 1; fs_in = 4e6; expected_delay_chips = 600; expected_doppler_hz = 750; - max_doppler_error_hz = 2/(3*integration_time_ms*1e-3); + max_doppler_error_hz = 2 / (3 * integration_time_ms * 1e-3); max_delay_error_chips = 0.50; num_of_realizations = 100; config = std::make_shared(); - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_in)); config->set_property("SignalSource.fs_hz", std::to_string(fs_in)); @@ -325,49 +330,48 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::config_2() config->set_property("InputFilter.filter_type", "bandpass"); config->set_property("InputFilter.grid_density", "16"); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.coherent_integration_time_ms", - std::to_string(integration_time_ms)); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); - config->set_property("Acquisition.threshold", "0.00108"); // Pfa,a = 0.1 - config->set_property("Acquisition.tong_init_val", "1"); - config->set_property("Acquisition.tong_max_val", "8"); - config->set_property("Acquisition.doppler_max", "10000"); - config->set_property("Acquisition.doppler_step", "250"); - config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.coherent_integration_time_ms", + std::to_string(integration_time_ms)); + config->set_property("Acquisition_1C.threshold", "0.00108"); // Pfa,a = 0.1 + config->set_property("Acquisition_1C.tong_init_val", "1"); + config->set_property("Acquisition_1C.tong_max_val", "8"); + config->set_property("Acquisition_1C.doppler_max", "10000"); + config->set_property("Acquisition_1C.doppler_step", "250"); + config->set_property("Acquisition_1C.dump", "false"); } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::start_queue() { stop = false; ch_thread = boost::thread(&GpsL1CaPcpsTongAcquisitionGSoC2013Test::wait_message, this); } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::wait_message() { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); while (!stop) { acquisition->reset(); - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; + start = std::chrono::system_clock::now(); channel_internal_queue.wait_and_pop(message); - gettimeofday(&tv, NULL); - end = tv.tv_sec*1e6 + tv.tv_usec; - - mean_acq_time_us += (end - begin); + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + mean_acq_time_us += elapsed_seconds.count() * 1e6; process_message(); } } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::process_message() { if (message == 1) @@ -375,7 +379,7 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::process_message() detection_counter++; // The term -5 is here to correct the additional delay introduced by the FIR filter - double delay_error_chips = std::abs((double)expected_delay_chips - (double)(gnss_synchro.Acq_delay_samples-5)*1023.0/((double)fs_in*1e-3)); + double delay_error_chips = std::abs(static_cast(expected_delay_chips) - static_cast(gnss_synchro.Acq_delay_samples - 5) * 1023.0 / (static_cast(fs_in) * 1e-3)); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); mse_delay += std::pow(delay_error_chips, 2); @@ -389,16 +393,16 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::process_message() realization_counter++; - std::cout << "Progress: " << round((float)realization_counter/num_of_realizations*100) << "% \r" << std::flush; + std::cout << "Progress: " << round(static_cast(realization_counter) / static_cast(num_of_realizations) * 100.0) << "% \r" << std::flush; if (realization_counter == num_of_realizations) { mse_delay /= num_of_realizations; mse_doppler /= num_of_realizations; - Pd = (double)correct_estimation_counter / (double)num_of_realizations; - Pfa_a = (double)detection_counter / (double)num_of_realizations; - Pfa_p = (double)(detection_counter-correct_estimation_counter) / (double)num_of_realizations; + Pd = static_cast(correct_estimation_counter) / static_cast(num_of_realizations); + Pfa_a = static_cast(detection_counter) / static_cast(num_of_realizations); + Pfa_p = static_cast(detection_counter - correct_estimation_counter) / static_cast(num_of_realizations); mean_acq_time_us /= num_of_realizations; @@ -409,86 +413,88 @@ void GpsL1CaPcpsTongAcquisitionGSoC2013Test::process_message() } } + void GpsL1CaPcpsTongAcquisitionGSoC2013Test::stop_queue() { stop = true; } + TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, Instantiate) { config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); } + TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ConnectAndRun) { - int nsamples = floor(fs_in*integration_time_ms*1e-3); - struct timeval tv; - long long int begin = 0; - long long int end = 0; + int nsamples = floor(fs_in * integration_time_ms * 1e-3); + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); config_1(); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1e6 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1e6 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResults) { config_1(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -496,7 +502,7 @@ TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResults) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; // i = 0 --> satellite in acquisition is visible // i = 1 --> satellite in acquisition is not visible @@ -506,11 +512,11 @@ TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResults) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); @@ -518,65 +524,65 @@ TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResults) start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; - if (message == 1) - { - EXPECT_EQ((unsigned int)1, correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; - } - - } + { + EXPECT_EQ(1, message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; + if (message == 1) + { + EXPECT_EQ(static_cast(1), correct_estimation_counter) << "Acquisition failure. Incorrect parameters estimation."; + } + } else if (i == 1) - { - EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; - } + { + EXPECT_EQ(2, message) << "Acquisition failure. Expected message: 2=ACQ FAIL."; + } ch_thread.join(); } } + TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) { config_2(); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + acquisition = std::make_shared(config.get(), "Acquisition_1C", 1, 0); boost::shared_ptr msg_rx = GpsL1CaPcpsTongAcquisitionGSoC2013Test_msg_rx_make(channel_internal_queue); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000)); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500)); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { - acquisition->set_threshold(config->property("Acquisition.threshold", 0.0)); - }) << "Failure setting threshold." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0)); + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; acquisition->init(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ boost::shared_ptr signal_source; SignalGenerator* signal_generator = new SignalGenerator(config.get(), "SignalSource", 0, 1, queue); FirFilter* filter = new FirFilter(config.get(), "InputFilter", 1, 1); @@ -584,7 +590,7 @@ TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) signal_source->connect(top_block); top_block->connect(signal_source->get_right_block(), 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; std::cout << "Probability of false alarm (target) = " << 0.1 << std::endl; @@ -596,34 +602,34 @@ TEST_F(GpsL1CaPcpsTongAcquisitionGSoC2013Test, ValidationOfResultsProbabilities) if (i == 0) { - gnss_synchro.PRN = 10; // This satellite is visible + gnss_synchro.PRN = 10; // This satellite is visible } else if (i == 1) { - gnss_synchro.PRN = 20; // This satellite is not visible + gnss_synchro.PRN = 20; // This satellite is not visible } acquisition->set_local_code(); acquisition->set_state(1); start_queue(); - EXPECT_NO_THROW( { - top_block->run(); // Start threads and wait - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + top_block->run(); // Start threads and wait + }) << "Failure running the top_block."; stop_queue(); if (i == 0) - { - std::cout << "Estimated probability of detection = " << Pd << std::endl; - std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of detection = " << Pd << std::endl; + std::cout << "Estimated probability of false alarm (satellite present) = " << Pfa_p << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } else if (i == 1) - { - std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; - std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; - } + { + std::cout << "Estimated probability of false alarm (satellite absent) = " << Pfa_a << std::endl; + std::cout << "Mean acq time = " << mean_acq_time_us << " microseconds." << std::endl; + } ch_thread.join(); } } diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc index bdfc0dd9a..f2d5e8e41 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,35 +25,38 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include +#include #include -#include -#include #include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include -#include -#include +#endif +#include "GPS_L2C.h" +#include "acquisition_dump_reader.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" +#include "gnuplot_i.h" #include "gps_l2_m_pcps_acquisition.h" -#include "GPS_L2C.h" +#include "in_memory_configuration.h" +#include "test_flags.h" +#include +#include +#include +#include +#include // ######## GNURADIO BLOCK MESSAGE RECEVER ######### @@ -72,8 +75,7 @@ private: public: int rx_message; - ~GpsL2MPcpsAcquisitionTest_msg_rx(); //!< Default destructor - + ~GpsL2MPcpsAcquisitionTest_msg_rx(); //!< Default destructor }; GpsL2MPcpsAcquisitionTest_msg_rx_sptr GpsL2MPcpsAcquisitionTest_msg_rx_make() @@ -84,19 +86,18 @@ GpsL2MPcpsAcquisitionTest_msg_rx_sptr GpsL2MPcpsAcquisitionTest_msg_rx_make() void GpsL2MPcpsAcquisitionTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast &e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL2MPcpsAcquisitionTest_msg_rx::GpsL2MPcpsAcquisitionTest_msg_rx() : - gr::block("GpsL2MPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +GpsL2MPcpsAcquisitionTest_msg_rx::GpsL2MPcpsAcquisitionTest_msg_rx() : gr::block("GpsL2MPcpsAcquisitionTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL2MPcpsAcquisitionTest_msg_rx::msg_handler_events, this, _1)); @@ -104,12 +105,13 @@ GpsL2MPcpsAcquisitionTest_msg_rx::GpsL2MPcpsAcquisitionTest_msg_rx() : } GpsL2MPcpsAcquisitionTest_msg_rx::~GpsL2MPcpsAcquisitionTest_msg_rx() -{} +{ +} // ########################################################### -class GpsL2MPcpsAcquisitionTest: public ::testing::Test +class GpsL2MPcpsAcquisitionTest : public ::testing::Test { protected: GpsL2MPcpsAcquisitionTest() @@ -117,15 +119,19 @@ protected: factory = std::make_shared(); config = std::make_shared(); item_size = sizeof(gr_complex); - sampling_freqeuncy_hz = 0; + sampling_frequency_hz = 5000000; nsamples = 0; + doppler_max = 3000; + doppler_step = 125; gnss_synchro = Gnss_Synchro(); } ~GpsL2MPcpsAcquisitionTest() - {} + { + } void init(); + void plot_grid(); gr::msg_queue::sptr queue; gr::top_block_sptr top_block; @@ -133,8 +139,10 @@ protected: std::shared_ptr config; Gnss_Synchro gnss_synchro; size_t item_size; - int sampling_freqeuncy_hz; + int sampling_frequency_hz; int nsamples; + unsigned int doppler_max; + unsigned int doppler_step; }; @@ -143,22 +151,91 @@ void GpsL2MPcpsAcquisitionTest::init() gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; std::string signal = "2S"; - //strncpy(gnss_synchro.Signal, signal.c_str(), 3); - std::memcpy((void*)gnss_synchro.Signal, signal.c_str(), 3); // copy string into synchro char array: 2 char + null - gnss_synchro.Signal[2] = 0; // make sure that string length is only two characters + std::memcpy(static_cast(gnss_synchro.Signal), signal.c_str(), 3); // copy string into synchro char array: 2 char + null + gnss_synchro.Signal[2] = 0; // make sure that string length is only two characters gnss_synchro.PRN = 7; - sampling_freqeuncy_hz = 5000000; - nsamples = round((double)sampling_freqeuncy_hz*GPS_L2_M_PERIOD)*2; - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(sampling_freqeuncy_hz)); - config->set_property("Acquisition.item_type", "gr_complex"); - config->set_property("Acquisition.if", "0"); - config->set_property("Acquisition.dump", "false"); - config->set_property("Acquisition.implementation", "GPS_L2_M_PCPS_Acquisition"); - config->set_property("Acquisition.threshold", "0.001"); - config->set_property("Acquisition.doppler_max", "5000"); - config->set_property("Acquisition.doppler_step", "100"); - config->set_property("Acquisition.repeat_satellite", "false"); + nsamples = round(static_cast(sampling_frequency_hz) * GPS_L2_M_PERIOD) * 2; + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(sampling_frequency_hz)); + config->set_property("Acquisition_2S.implementation", "GPS_L2_M_PCPS_Acquisition"); + config->set_property("Acquisition_2S.item_type", "gr_complex"); + if (FLAGS_plot_acq_grid == true) + { + config->set_property("Acquisition_2S.dump", "true"); + } + else + { + config->set_property("Acquisition_2S.dump", "false"); + } + config->set_property("Acquisition_2S.dump_filename", "./tmp-acq-gps2/acquisition_test"); + config->set_property("Acquisition_2S.dump_channel", "1"); + config->set_property("Acquisition_2S.threshold", "0.001"); + config->set_property("Acquisition_2S.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition_2S.doppler_step", std::to_string(doppler_step)); + config->set_property("Acquisition_2S.repeat_satellite", "false"); + config->set_property("Acquisition_2S.make_two_steps", "false"); +} + + +void GpsL2MPcpsAcquisitionTest::plot_grid() +{ + //load the measured values + std::string basename = "./tmp-acq-gps2/acquisition_test_G_2S"; + unsigned int sat = static_cast(gnss_synchro.PRN); + + unsigned int samples_per_code = static_cast(floor(static_cast(sampling_frequency_hz) / (GPS_L2_M_CODE_RATE_HZ / static_cast(GPS_L2_M_CODE_LENGTH_CHIPS)))); + acquisition_dump_reader acq_dump(basename, sat, doppler_max, doppler_step, samples_per_code, 1); + if (!acq_dump.read_binary_acq()) std::cout << "Error reading files" << std::endl; + + std::vector *doppler = &acq_dump.doppler; + std::vector *samples = &acq_dump.samples; + std::vector > *mag = &acq_dump.mag; + + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_acq_grid has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + std::cout << "Plotting the acquisition grid. This can take a while..." << std::endl; + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("impulses"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title("GPS L2CM signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN)); + g1.set_xlabel("Doppler [Hz]"); + g1.set_ylabel("Sample"); + //g1.cmd("set view 60, 105, 1, 1"); + g1.plot_grid3d(*doppler, *samples, *mag); + + g1.savetops("GPS_L2CM_acq_grid"); + g1.savetopdf("GPS_L2CM_acq_grid"); + } + catch (const GnuplotException &ge) + { + std::cout << ge.what() << std::endl; + } + } + std::string data_str = "./tmp-acq-gps2"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } } @@ -166,122 +243,133 @@ TEST_F(GpsL2MPcpsAcquisitionTest, Instantiate) { init(); queue = gr::msg_queue::make(0); - std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition_2S", 1, 0); } + TEST_F(GpsL2MPcpsAcquisitionTest, ConnectAndRun) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); init(); - std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition_2S", 1, 0); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - boost::shared_ptr source = gr::analog::sig_source_c::make(sampling_freqeuncy_hz, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + boost::shared_ptr source = gr::analog::sig_source_c::make(sampling_frequency_hz, gr::analog::GR_SIN_WAVE, 2000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); boost::shared_ptr msg_rx = GpsL2MPcpsAcquisitionTest_msg_rx_make(); + }) << "Failure connecting the blocks of acquisition test."; - }) << "Failure connecting the blocks of acquisition test." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } + TEST_F(GpsL2MPcpsAcquisitionTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); queue = gr::msg_queue::make(0); - double expected_delay_samples = 1;//2004; - double expected_doppler_hz = 1200;//3000; + double expected_delay_samples = 1; //2004; + double expected_doppler_hz = 1200; //3000; + + if (FLAGS_plot_acq_grid == true) + { + std::string data_str = "./tmp-acq-gps2"; + if (boost::filesystem::exists(data_str)) + { + boost::filesystem::remove_all(data_str); + } + boost::filesystem::create_directory(data_str); + } + init(); - std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition", 1, 1); + std::shared_ptr acquisition = std::make_shared(config.get(), "Acquisition_2S", 1, 0); boost::shared_ptr msg_rx = GpsL2MPcpsAcquisitionTest_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_channel(1); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->set_threshold(0.001); - }) << "Failure setting threshold." << std::endl; + }) << "Failure setting threshold."; - ASSERT_NO_THROW( { - acquisition->set_doppler_max(5000); - }) << "Failure setting doppler_max." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_max(doppler_max); + }) << "Failure setting doppler_max."; - ASSERT_NO_THROW( { - acquisition->set_doppler_step(10); - }) << "Failure setting doppler_step." << std::endl; + ASSERT_NO_THROW({ + acquisition->set_doppler_step(doppler_step); + }) << "Failure setting doppler_step."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ acquisition->connect(top_block); - }) << "Failure connecting acquisition to the top_block." << std::endl; + }) << "Failure connecting acquisition to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ std::string path = std::string(TEST_PATH); //std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; std::string file = path + "signal_samples/gps_l2c_m_prn7_5msps.dat"; //std::string file = "/datalogger/signals/Fraunhofer/L125_III1b_210s_L2_resampled.bin"; - const char * file_name = file.c_str(); + const char *file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); //gr::blocks::interleaved_short_to_complex::sptr gr_interleaved_short_to_complex_ = gr::blocks::interleaved_short_to_complex::make(); //gr::blocks::char_to_short::sptr gr_char_to_short_ = gr::blocks::char_to_short::make(); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); //top_block->connect(file_source, 0, gr_char_to_short_, 0); //top_block->connect(gr_char_to_short_, 0, gr_interleaved_short_to_complex_ , 0); - top_block->connect(file_source, 0, valve , 0); + top_block->connect(file_source, 0, valve, 0); top_block->connect(valve, 0, acquisition->get_left_block(), 0); top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of acquisition test." << std::endl; + }) << "Failure connecting the blocks of acquisition test."; - - ASSERT_NO_THROW( { - acquisition->set_state(1); // Ensure that acquisition starts at the first sample + ASSERT_NO_THROW({ + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample acquisition->init(); - }) << "Failure set_state and init acquisition test" << std::endl; + }) << "Failure set_state and init acquisition test"; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - //unsigned long int Acq_samplestamp_samples = gnss_synchro.Acq_samplestamp_samples; - std::cout << "Acquisition process runtime duration: " << (end - begin) << " microseconds" << std::endl; + std::cout << "Acquisition process runtime duration: " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; - std::cout << "gnss_synchro.Acq_doppler_hz = " << gnss_synchro.Acq_doppler_hz << " Hz" << std::endl; - std::cout << "gnss_synchro.Acq_delay_samples = " << gnss_synchro.Acq_delay_samples << " Samples" << std::endl; + std::cout << "gnss_synchro.Acq_doppler_hz = " << gnss_synchro.Acq_doppler_hz << " Hz" << std::endl; + std::cout << "gnss_synchro.Acq_delay_samples = " << gnss_synchro.Acq_delay_samples << " Samples" << std::endl; ASSERT_EQ(1, msg_rx->rx_message) << "Acquisition failure. Expected message: 1=ACQ SUCCESS."; double delay_error_samples = std::abs(expected_delay_samples - gnss_synchro.Acq_delay_samples); - float delay_error_chips = (float)(delay_error_samples * 1023 / 4000); + float delay_error_chips = static_cast(delay_error_samples * 1023 / 4000); double doppler_error_hz = std::abs(expected_doppler_hz - gnss_synchro.Acq_doppler_hz); - EXPECT_LE(doppler_error_hz, 200) << "Doppler error exceeds the expected value: 666 Hz = 2/(3*integration period)"; + EXPECT_LE(doppler_error_hz, 200) << "Doppler error exceeds the expected value: 2/(3*integration period)"; EXPECT_LT(delay_error_chips, 0.5) << "Delay error exceeds the expected value: 0.5 chips"; + if (FLAGS_plot_acq_grid == true) + { + plot_grid(); + } } diff --git a/src/tests/unit-tests/signal-processing-blocks/adapter/adapter_test.cc b/src/tests/unit-tests/signal-processing-blocks/adapter/adapter_test.cc new file mode 100644 index 000000000..89f2cd338 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/adapter/adapter_test.cc @@ -0,0 +1,406 @@ +/*! + * \file adapter_test.cc + * \brief This file implements tests for the DataTypeAdapter block + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "byte_to_short.h" +#include "ibyte_to_cbyte.h" +#include "ibyte_to_complex.h" +#include "ibyte_to_cshort.h" +#include "in_memory_configuration.h" +#include "ishort_to_complex.h" +#include "ishort_to_cshort.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class DataTypeAdapter : public ::testing::Test +{ +public: + DataTypeAdapter(); + ~DataTypeAdapter(); + int run_byte_to_short_block(); + int run_ibyte_to_cbyte_block(); + int run_ibyte_to_complex_block(); + int run_ibyte_to_cshort_block(); + int run_ishort_to_complex_block(); + int run_ishort_to_cshort_block(); + std::string file_name_input; + std::string file_name_output; + std::vector input_data_bytes; + std::vector input_data_shorts; +}; + + +DataTypeAdapter::DataTypeAdapter() +{ + file_name_input = "adapter_test_input.dat"; + file_name_output = "adapter_test_output.dat"; + int8_t input_bytes[] = {2, 23, -1, 127, -127, 0}; + int16_t input_shorts[] = {2, 23, -1, 127, -127, 0, 255, 255}; + + const std::vector input_data_bytes_(input_bytes, input_bytes + sizeof(input_bytes) / sizeof(int8_t)); + input_data_bytes = input_data_bytes_; + + const std::vector input_data_shorts_(input_shorts, input_shorts + sizeof(input_shorts) / sizeof(int16_t)); + input_data_shorts = input_data_shorts_; +} + + +DataTypeAdapter::~DataTypeAdapter() = default; + + +int DataTypeAdapter::run_ishort_to_cshort_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Ishort_To_Cshort"); + std::shared_ptr ishort_to_cshort = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Ishort_To_Cshort"; + EXPECT_EQ(expected_implementation, ishort_to_cshort->implementation()); + + std::ofstream ofs(file_name_input.c_str(), std::ofstream::binary); + for (int16_t aux : input_data_shorts) + { + ofs.write(reinterpret_cast(&aux), sizeof(int16_t)); + } + ofs.close(); + + auto top_block = gr::make_top_block("Ishort_To_Cshort test"); + auto file_source = gr::blocks::file_source::make(sizeof(int16_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(lv_16sc_t), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, ishort_to_cshort->get_left_block(), 0); + top_block->connect(ishort_to_cshort->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +int DataTypeAdapter::run_ishort_to_complex_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Ishort_To_Complex"); + std::shared_ptr ishort_to_complex = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Ishort_To_Complex"; + EXPECT_EQ(expected_implementation, ishort_to_complex->implementation()); + + std::ofstream ofs(file_name_input.c_str(), std::ofstream::binary); + for (int16_t aux : input_data_shorts) + { + ofs.write(reinterpret_cast(&aux), sizeof(int16_t)); + } + ofs.close(); + + auto top_block = gr::make_top_block("Ishort_To_Complex test"); + auto file_source = gr::blocks::file_source::make(sizeof(int16_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(gr_complex), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, ishort_to_complex->get_left_block(), 0); + top_block->connect(ishort_to_complex->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +int DataTypeAdapter::run_ibyte_to_cshort_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Ibyte_To_Cshort"); + std::shared_ptr ibyte_to_cshort = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Ibyte_To_Cshort"; + EXPECT_EQ(expected_implementation, ibyte_to_cshort->implementation()); + + std::ofstream ofs(file_name_input.c_str()); + for (signed char input_data_byte : input_data_bytes) + { + ofs << input_data_byte; + } + ofs.close(); + + auto top_block = gr::make_top_block("Ibyte_To_Cshort test"); + auto file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(lv_16sc_t), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, ibyte_to_cshort->get_left_block(), 0); + top_block->connect(ibyte_to_cshort->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +int DataTypeAdapter::run_ibyte_to_complex_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Ibyte_To_Complex"); + std::shared_ptr ibyte_to_complex = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Ibyte_To_Complex"; + EXPECT_EQ(expected_implementation, ibyte_to_complex->implementation()); + + std::ofstream ofs(file_name_input.c_str()); + for (signed char input_data_byte : input_data_bytes) + { + ofs << input_data_byte; + } + ofs.close(); + + auto top_block = gr::make_top_block("Ibyte_To_Complex test"); + auto file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(gr_complex), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, ibyte_to_complex->get_left_block(), 0); + top_block->connect(ibyte_to_complex->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +int DataTypeAdapter::run_ibyte_to_cbyte_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Ibyte_To_Cbyte"); + std::shared_ptr ibyte_to_cbyte = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Ibyte_To_Cbyte"; + EXPECT_EQ(expected_implementation, ibyte_to_cbyte->implementation()); + + std::ofstream ofs(file_name_input.c_str()); + for (signed char input_data_byte : input_data_bytes) + { + ofs << input_data_byte; + } + ofs.close(); + + auto top_block = gr::make_top_block("Ibyte_To_Cbyte test"); + auto file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(int16_t), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, ibyte_to_cbyte->get_left_block(), 0); + top_block->connect(ibyte_to_cbyte->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +int DataTypeAdapter::run_byte_to_short_block() +{ + std::shared_ptr config = std::make_shared(); + config->set_property("Test.implementation", "Byte_To_Short"); + std::shared_ptr byte_to_short = std::make_shared(config.get(), "Test", 1, 1); + std::string expected_implementation = "Byte_To_Short"; + EXPECT_EQ(expected_implementation, byte_to_short->implementation()); + + std::ofstream ofs(file_name_input.c_str()); + for (signed char input_data_byte : input_data_bytes) + { + ofs << input_data_byte; + } + ofs.close(); + + auto top_block = gr::make_top_block("Byte_To_Short test"); + auto file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name_input.c_str()); + auto sink = gr::blocks::file_sink::make(sizeof(int16_t), file_name_output.c_str(), false); + + EXPECT_NO_THROW({ + top_block->connect(file_source, 0, byte_to_short->get_left_block(), 0); + top_block->connect(byte_to_short->get_right_block(), 0, sink, 0); + top_block->run(); + }); + return 0; +} + + +TEST_F(DataTypeAdapter, ByteToShortValidationOfResults) +{ + run_byte_to_short_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + + int16_t iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(int16_t))) + { + EXPECT_EQ(input_data_bytes.at(i), static_cast(iSample / 256)); // Scale down! + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} + + +TEST_F(DataTypeAdapter, IbyteToCbyteValidationOfResults) +{ + run_ibyte_to_cbyte_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + lv_8sc_t iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(lv_8sc_t))) + { + EXPECT_EQ(input_data_bytes.at(i), iSample.real()); + i++; + EXPECT_EQ(input_data_bytes.at(i), iSample.imag()); + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} + + +TEST_F(DataTypeAdapter, IbyteToComplexValidationOfResults) +{ + run_ibyte_to_cbyte_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + gr_complex iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(gr_complex))) + { + EXPECT_EQ(input_data_bytes.at(i), static_cast(iSample.real())); + i++; + EXPECT_EQ(input_data_bytes.at(i), static_cast(iSample.imag())); + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} + + +TEST_F(DataTypeAdapter, IbyteToCshortValidationOfResults) +{ + run_ibyte_to_cshort_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + lv_16sc_t iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(lv_16sc_t))) + { + EXPECT_EQ(input_data_bytes.at(i), static_cast(iSample.real())); + i++; + EXPECT_EQ(input_data_bytes.at(i), static_cast(iSample.imag())); + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} + + +TEST_F(DataTypeAdapter, IshortToComplexValidationOfResults) +{ + run_ishort_to_complex_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + gr_complex iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(gr_complex))) + { + EXPECT_EQ(input_data_shorts.at(i), static_cast(iSample.real())); + i++; + EXPECT_EQ(input_data_shorts.at(i), static_cast(iSample.imag())); + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} + + +TEST_F(DataTypeAdapter, IshortToCshortValidationOfResults) +{ + run_ishort_to_cshort_block(); + std::ifstream ifs(file_name_output.data(), std::ifstream::binary | std::ifstream::in); + lv_16sc_t iSample; + int i = 0; + try + { + while (ifs.read(reinterpret_cast(&iSample), sizeof(lv_16sc_t))) + { + EXPECT_EQ(input_data_shorts.at(i), static_cast(iSample.real())); + i++; + EXPECT_EQ(input_data_shorts.at(i), static_cast(iSample.imag())); + i++; + } + } + catch (std::system_error& e) + { + std::cerr << e.code().message() << std::endl; + } + ifs.close(); + ASSERT_EQ(remove(file_name_input.c_str()), 0) << "Problem deleting temporary file"; + ASSERT_EQ(remove(file_name_output.c_str()), 0) << "Problem deleting temporary file"; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc b/src/tests/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc index 08429b657..e15c5d253 100644 --- a/src/tests/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,25 +25,21 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#include "in_memory_configuration.h" #include "pass_through.h" #include -#include "in_memory_configuration.h" - -TEST(Pass_Through_Test, Instantiate) +TEST(PassThroughTest, Instantiate) { std::shared_ptr config = std::make_shared(); config->set_property("Test.item_type", "gr_complex"); - config->set_property("Test.vector_size", "2"); std::shared_ptr signal_conditioner = std::make_shared(config.get(), "Test", 1, 1); EXPECT_STREQ("gr_complex", signal_conditioner->item_type().c_str()); - unsigned int expected2 = 2; - EXPECT_EQ(expected2, signal_conditioner->vector_size()); } diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc index 9a90fa4bd..9c411c862 100644 --- a/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,45 +23,47 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include +#endif +#include "file_signal_source.h" +#include "fir_filter.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" +#include "in_memory_configuration.h" #include "interleaved_byte_to_complex_byte.h" #include "interleaved_short_to_complex_short.h" -#include "fir_filter.h" -#include "file_signal_source.h" +#include +#include +#include -DEFINE_int32(filter_test_nsamples, 1000000 , "Number of samples to filter in the tests (max: 2147483647)"); +DEFINE_int32(filter_test_nsamples, 1000000, "Number of samples to filter in the tests (max: 2147483647)"); -class Fir_Filter_Test: public ::testing::Test +class FirFilterTest : public ::testing::Test { protected: - Fir_Filter_Test() + FirFilterTest() { queue = gr::msg_queue::make(0); item_size = sizeof(gr_complex); config = std::make_shared(); } - ~Fir_Filter_Test() - {} + ~FirFilterTest() = default; void init(); void configure_cbyte_cbyte(); @@ -75,7 +77,8 @@ protected: int nsamples = FLAGS_filter_test_nsamples; }; -void Fir_Filter_Test::init() + +void FirFilterTest::init() { config->set_property("InputFilter.taps_item_type", "float"); config->set_property("InputFilter.number_of_taps", "5"); @@ -99,32 +102,36 @@ void Fir_Filter_Test::init() //config->set_property("InputFilter.dump", "true"); } -void Fir_Filter_Test::configure_cbyte_cbyte() + +void FirFilterTest::configure_cbyte_cbyte() { config->set_property("InputFilter.input_item_type", "cbyte"); config->set_property("InputFilter.output_item_type", "cbyte"); } -void Fir_Filter_Test::configure_gr_complex_gr_complex() + +void FirFilterTest::configure_gr_complex_gr_complex() { config->set_property("InputFilter.input_item_type", "gr_complex"); config->set_property("InputFilter.output_item_type", "gr_complex"); } -void Fir_Filter_Test::configure_cshort_cshort() + +void FirFilterTest::configure_cshort_cshort() { config->set_property("InputFilter.input_item_type", "cshort"); config->set_property("InputFilter.output_item_type", "cshort"); } -void Fir_Filter_Test::configure_cbyte_gr_complex() + +void FirFilterTest::configure_cbyte_gr_complex() { config->set_property("InputFilter.input_item_type", "cbyte"); config->set_property("InputFilter.output_item_type", "gr_complex"); } -TEST_F(Fir_Filter_Test, Instantiate_gr_complex_gr_complex) +TEST_F(FirFilterTest, InstantiateGrComplexGrComplex) { init(); configure_gr_complex_gr_complex(); @@ -134,7 +141,7 @@ TEST_F(Fir_Filter_Test, Instantiate_gr_complex_gr_complex) ASSERT_EQ(1, res); } -TEST_F(Fir_Filter_Test, Instantiate_cshort_cshort) +TEST_F(FirFilterTest, InstantiateCshortCshort) { init(); configure_cshort_cshort(); @@ -144,7 +151,8 @@ TEST_F(Fir_Filter_Test, Instantiate_cshort_cshort) ASSERT_EQ(1, res); } -TEST_F(Fir_Filter_Test, Instantiate_cbyte_cbyte) + +TEST_F(FirFilterTest, InstantiateCbyteCbyte) { init(); configure_cbyte_cbyte(); @@ -154,7 +162,8 @@ TEST_F(Fir_Filter_Test, Instantiate_cbyte_cbyte) ASSERT_EQ(1, res); } -TEST_F(Fir_Filter_Test, Instantiate_cbyte_gr_complex) + +TEST_F(FirFilterTest, InstantiateCbyteGrComplex) { init(); configure_cbyte_gr_complex(); @@ -164,19 +173,19 @@ TEST_F(Fir_Filter_Test, Instantiate_cbyte_gr_complex) ASSERT_EQ(1, res); } -TEST_F(Fir_Filter_Test, ConnectAndRun) + +TEST_F(FirFilterTest, ConnectAndRun) { int fs_in = 4000000; - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Fir filter test"); init(); configure_gr_complex_gr_complex(); std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); item_size = sizeof(gr_complex); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ filter->connect(top_block); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); @@ -185,24 +194,22 @@ TEST_F(Fir_Filter_Test, ConnectAndRun) top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, filter->get_left_block(), 0); top_block->connect(filter->get_right_block(), 0, null_sink, 0); - }) << "Failure connecting the top_block."<< std::endl; + }) << "Failure connecting the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Filtered " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } -TEST_F(Fir_Filter_Test, ConnectAndRunGrcomplex) +TEST_F(FirFilterTest, ConnectAndRunGrcomplex) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Fir filter test"); init(); @@ -219,33 +226,31 @@ TEST_F(Fir_Filter_Test, ConnectAndRunGrcomplex) config2->set_property("Test_Source.repeat", "true"); item_size = sizeof(gr_complex); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ filter->connect(top_block); - boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); source->connect(top_block); boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); top_block->connect(filter->get_right_block(), 0, null_sink, 0); - }) << "Failure connecting the top_block."<< std::endl; + }) << "Failure connecting the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Filtered " << nsamples << " gr_complex samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } -TEST_F(Fir_Filter_Test, ConnectAndRunCshorts) +TEST_F(FirFilterTest, ConnectAndRunCshorts) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Fir filter test"); init(); @@ -262,10 +267,10 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCshorts) config2->set_property("Test_Source.repeat", "true"); item_size = sizeof(std::complex); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ filter->connect(top_block); - boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); source->connect(top_block); interleaved_short_to_complex_short_sptr ishort_to_cshort_ = make_interleaved_short_to_complex_short(); @@ -274,25 +279,22 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCshorts) top_block->connect(source->get_right_block(), 0, ishort_to_cshort_, 0); top_block->connect(ishort_to_cshort_, 0, filter->get_left_block(), 0); top_block->connect(filter->get_right_block(), 0, null_sink, 0); - }) << "Failure connecting the top_block."<< std::endl; + }) << "Failure connecting the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Filtered " << nsamples << " std::complex samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " std::complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - -TEST_F(Fir_Filter_Test, ConnectAndRunCbytes) +TEST_F(FirFilterTest, ConnectAndRunCbytes) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Fir filter test"); init(); @@ -309,10 +311,10 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCbytes) config2->set_property("Test_Source.repeat", "true"); item_size = sizeof(std::complex); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ filter->connect(top_block); - boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); source->connect(top_block); interleaved_byte_to_complex_byte_sptr ibyte_to_cbyte_ = make_interleaved_byte_to_complex_byte(); @@ -321,24 +323,22 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCbytes) top_block->connect(source->get_right_block(), 0, ibyte_to_cbyte_, 0); top_block->connect(ibyte_to_cbyte_, 0, filter->get_left_block(), 0); top_block->connect(filter->get_right_block(), 0, null_sink, 0); - }) << "Failure connecting the top_block."<< std::endl; + }) << "Failure connecting the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Filtered " << nsamples << " std::complex samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " std::complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } -TEST_F(Fir_Filter_Test, ConnectAndRunCbyteGrcomplex) +TEST_F(FirFilterTest, ConnectAndRunCbyteGrcomplex) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Fir filter test"); init(); @@ -355,10 +355,10 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCbyteGrcomplex) config2->set_property("Test_Source.repeat", "true"); item_size = sizeof(gr_complex); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ filter->connect(top_block); - boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); source->connect(top_block); interleaved_byte_to_complex_byte_sptr ibyte_to_cbyte_ = make_interleaved_byte_to_complex_byte(); @@ -367,14 +367,13 @@ TEST_F(Fir_Filter_Test, ConnectAndRunCbyteGrcomplex) top_block->connect(source->get_right_block(), 0, ibyte_to_cbyte_, 0); top_block->connect(ibyte_to_cbyte_, 0, filter->get_left_block(), 0); top_block->connect(filter->get_right_block(), 0, null_sink, 0); - }) << "Failure connecting the top_block."<< std::endl; + }) << "Failure connecting the top_block."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - std::cout << "Filtered " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc new file mode 100644 index 000000000..f23a84558 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc @@ -0,0 +1,171 @@ +/*! + * \file notch_filter_lite_test.cc + * \brief Implements Unit Test for the NotchFilterLite class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "file_signal_source.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "in_memory_configuration.h" +#include "notch_filter_lite.h" +#include +#include +#include + + +DEFINE_int32(notch_filter_lite_test_nsamples, 1000000, "Number of samples to filter in the tests (max: 2147483647)"); + +class NotchFilterLiteTest : public ::testing::Test +{ +protected: + NotchFilterLiteTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_notch_filter_lite_test_nsamples; + } + ~NotchFilterLiteTest() = default; + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void NotchFilterLiteTest::init() +{ + config->set_property("InputFilter.pfa", "0.01"); + config->set_property("InputFilter.p_c_factor", "0.9"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void NotchFilterLiteTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(NotchFilterLiteTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new NotchFilterLite(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(NotchFilterLiteTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter lite test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(NotchFilterLiteTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter lite test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc new file mode 100644 index 000000000..b3c9fbece --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc @@ -0,0 +1,171 @@ +/*! + * \file notch_filter_test.cc + * \brief Implements Unit Test for the NotchFilter class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "file_signal_source.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "in_memory_configuration.h" +#include "notch_filter.h" +#include +#include +#include + + +DEFINE_int32(notch_filter_test_nsamples, 1000000, "Number of samples to filter in the tests (max: 2147483647)"); + +class NotchFilterTest : public ::testing::Test +{ +protected: + NotchFilterTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_notch_filter_test_nsamples; + } + ~NotchFilterTest() = default; + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void NotchFilterTest::init() +{ + config->set_property("InputFilter.pfa", "0.01"); + config->set_property("InputFilter.p_c_factor", "0.9"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void NotchFilterTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(NotchFilterTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new NotchFilter(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(NotchFilterTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(NotchFilterTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc new file mode 100644 index 000000000..729ff78dd --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc @@ -0,0 +1,170 @@ +/*! + * \file pulse_blanking_filter_test.cc + * \brief Implements Unit Test for the PulseBlankingFilter class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "file_signal_source.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "in_memory_configuration.h" +#include "pulse_blanking_filter.h" +#include +#include +#include + + +DEFINE_int32(pb_filter_test_nsamples, 1000000, "Number of samples to filter in the tests (max: 2147483647)"); + +class PulseBlankingFilterTest : public ::testing::Test +{ +protected: + PulseBlankingFilterTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_pb_filter_test_nsamples; + } + ~PulseBlankingFilterTest() = default; + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void PulseBlankingFilterTest::init() +{ + config->set_property("InputFilter.pfa", "0.04"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void PulseBlankingFilterTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(PulseBlankingFilterTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new PulseBlankingFilter(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(PulseBlankingFilterTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Pulse Blanking filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(PulseBlankingFilterTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Pulse Blanking filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW({ + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 0, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/CMakeLists.txt b/src/tests/unit-tests/signal-processing-blocks/libs/CMakeLists.txt index 8b4136e7d..d0bd655d7 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/CMakeLists.txt +++ b/src/tests/unit-tests/signal-processing-blocks/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2017 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,25 +13,44 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # set(SIGNAL_PROCESSING_TESTING_LIB_SOURCES + acquisition_dump_reader.cc + acquisition_msg_rx.cc tracking_dump_reader.cc - tlm_dump_reader.cc + tlm_dump_reader.cc + observables_dump_reader.cc tracking_true_obs_reader.cc + true_observables_reader.cc ) include_directories( - $(CMAKE_CURRENT_SOURCE_DIR) - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${MATIO_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} ) file(GLOB SIGNAL_PROCESSING_TESTING_LIB_HEADERS "*.h") list(SORT SIGNAL_PROCESSING_TESTING_LIB_HEADERS) -add_library(signal_processing_testing_lib ${SIGNAL_PROCESSING_TESTING_LIB_SOURCES} ${SIGNAL_PROCESSING_TESTING_LIB_HEADERS}) + +add_library(signal_processing_testing_lib + ${SIGNAL_PROCESSING_TESTING_LIB_SOURCES} + ${SIGNAL_PROCESSING_TESTING_LIB_HEADERS} +) + source_group(Headers FILES ${SIGNAL_PROCESSING_TESTING_LIB_HEADERS}) +if(NOT MATIO_FOUND) + add_dependencies(signal_processing_testing_lib + matio-${GNSSSDR_MATIO_LOCAL_VERSION} glog-${glog_RELEASE} + ) +else() + add_dependencies(signal_processing_testing_lib glog-${glog_RELEASE}) +endif() diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.cc new file mode 100644 index 000000000..f401b1bc9 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.cc @@ -0,0 +1,237 @@ +/*! + * \file acquisition_dump_reader.cc + * \brief Helper file for unit testing + * \authors Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "acquisition_dump_reader.h" +#include +#include +#include + +bool acquisition_dump_reader::read_binary_acq() +{ + mat_t* matfile = Mat_Open(d_dump_filename.c_str(), MAT_ACC_RDONLY); + if (matfile == nullptr) + { + std::cout << "¡¡¡Unreachable Acquisition dump file!!!" << std::endl; + return false; + } + matvar_t* var_ = Mat_VarRead(matfile, "acq_grid"); + if (var_ == nullptr) + { + std::cout << "¡¡¡Unreachable grid variable into Acquisition dump file!!!" << std::endl; + Mat_Close(matfile); + return false; + } + if (var_->rank != 2) + { + std::cout << "Invalid Acquisition dump file: rank error" << std::endl; + Mat_VarFree(var_); + Mat_Close(matfile); + return false; + } + if ((var_->dims[0] != d_samples_per_code) or (var_->dims[1] != d_num_doppler_bins)) + { + std::cout << "Invalid Acquisition dump file: dimension matrix error" << std::endl; + if (var_->dims[0] != d_samples_per_code) std::cout << "Expected " << d_samples_per_code << " samples per code. Obtained " << var_->dims[0] << std::endl; + if (var_->dims[1] != d_num_doppler_bins) std::cout << "Expected " << d_num_doppler_bins << " Doppler bins. Obtained " << var_->dims[1] << std::endl; + Mat_VarFree(var_); + Mat_Close(matfile); + return false; + } + if (var_->data_type != MAT_T_SINGLE) + { + std::cout << "Invalid Acquisition dump file: data type error" << std::endl; + Mat_VarFree(var_); + Mat_Close(matfile); + return false; + } + matvar_t* var2_ = Mat_VarRead(matfile, "doppler_max"); + d_doppler_max = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "doppler_step"); + d_doppler_step = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "input_power"); + input_power = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "acq_doppler_hz"); + acq_doppler_hz = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "acq_delay_samples"); + acq_delay_samples = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "test_statistic"); + test_statistic = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "threshold"); + threshold = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "sample_counter"); + sample_counter = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "d_positive_acq"); + positive_acq = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "num_dwells"); + num_dwells = *static_cast(var2_->data); + Mat_VarFree(var2_); + + var2_ = Mat_VarRead(matfile, "PRN"); + PRN = *static_cast(var2_->data); + Mat_VarFree(var2_); + + std::vector >::iterator it1; + std::vector::iterator it2; + auto* aux = static_cast(var_->data); + int k = 0; + float normalization_factor = std::pow(d_samples_per_code, 4) * input_power; + for (it1 = mag.begin(); it1 != mag.end(); it1++) + { + for (it2 = it1->begin(); it2 != it1->end(); it2++) + { + *it2 = static_cast(aux[k]) / normalization_factor; + k++; + } + } + Mat_VarFree(var_); + Mat_Close(matfile); + + return true; +} + + +acquisition_dump_reader::acquisition_dump_reader(const std::string& basename, + int channel, + int execution) +{ + unsigned int sat_ = 0; + unsigned int doppler_max_ = 0; + unsigned int doppler_step_ = 0; + unsigned int samples_per_code_ = 0; + + mat_t* matfile = Mat_Open(d_dump_filename.c_str(), MAT_ACC_RDONLY); + if (matfile != nullptr) + { + matvar_t* var_ = Mat_VarRead(matfile, "doppler_max"); + doppler_max_ = *static_cast(var_->data); + Mat_VarFree(var_); + + var_ = Mat_VarRead(matfile, "doppler_step"); + doppler_step_ = *static_cast(var_->data); + Mat_VarFree(var_); + + var_ = Mat_VarRead(matfile, "PRN"); + sat_ = *static_cast(var_->data); + Mat_VarFree(var_); + + var_ = Mat_VarRead(matfile, "grid"); + samples_per_code_ = var_->dims[0]; + Mat_VarFree(var_); + + Mat_Close(matfile); + } + else + { + std::cout << "¡¡¡Unreachable Acquisition dump file!!!" << std::endl; + } + acq_doppler_hz = 0.0; + acq_delay_samples = 0.0; + test_statistic = 0.0; + input_power = 0.0; + threshold = 0.0; + positive_acq = 0; + sample_counter = 0; + PRN = 0; + d_sat = 0; + d_doppler_max = doppler_max_; + d_doppler_step = doppler_step_; + d_samples_per_code = samples_per_code_; + d_num_doppler_bins = 0; + num_dwells = 0; + + acquisition_dump_reader(basename, + sat_, + doppler_max_, + doppler_step_, + samples_per_code_, + channel, + execution); +} + + +acquisition_dump_reader::acquisition_dump_reader(const std::string& basename, + unsigned int sat, + unsigned int doppler_max, + unsigned int doppler_step, + unsigned int samples_per_code, + int channel, + int execution) +{ + d_basename = basename; + d_sat = sat; + d_doppler_max = doppler_max; + d_doppler_step = doppler_step; + d_samples_per_code = samples_per_code; + acq_doppler_hz = 0.0; + acq_delay_samples = 0.0; + test_statistic = 0.0; + input_power = 0.0; + threshold = 0.0; + positive_acq = 0; + sample_counter = 0; + num_dwells = 0; + PRN = 0; + if (d_doppler_step == 0) d_doppler_step = 1; + d_num_doppler_bins = static_cast(ceil(static_cast(static_cast(d_doppler_max) - static_cast(-d_doppler_max)) / static_cast(d_doppler_step))); + std::vector > mag_aux(d_num_doppler_bins, std::vector(d_samples_per_code)); + mag = mag_aux; + d_dump_filename = d_basename + "_ch_" + std::to_string(channel) + "_" + std::to_string(execution) + "_sat_" + std::to_string(d_sat) + ".mat"; + for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + doppler.push_back(-static_cast(d_doppler_max) + d_doppler_step * doppler_index); + } + for (unsigned int k = 0; k < d_samples_per_code; k++) + { + samples.push_back(k); + } +} + + +acquisition_dump_reader::~acquisition_dump_reader() = default; diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.h new file mode 100644 index 000000000..be5779f38 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_dump_reader.h @@ -0,0 +1,81 @@ +/*! + * \file acquisition_dump_reader.h + * \brief Helper file for unit testing + * \authors Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ACQUISITION_DUMP_READER_H +#define GNSS_SDR_ACQUISITION_DUMP_READER_H + +#include +#include +#include + +class acquisition_dump_reader +{ +public: + acquisition_dump_reader(const std::string& basename, + unsigned int sat, + unsigned int doppler_max, + unsigned int doppler_step, + unsigned int samples_per_code, + int channel = 0, + int execution = 1); + + acquisition_dump_reader(const std::string& basename, + int channel = 0, + int execution = 1); + + ~acquisition_dump_reader(); + + bool read_binary_acq(); + + std::vector doppler; + std::vector samples; + std::vector > mag; + float acq_doppler_hz; + float acq_delay_samples; + float test_statistic; + float input_power; + float threshold; + int positive_acq; + unsigned int PRN; + unsigned int num_dwells; + uint64_t sample_counter; + +private: + std::string d_basename; + unsigned int d_sat; + unsigned int d_doppler_max; + unsigned int d_doppler_step; + unsigned int d_samples_per_code; + unsigned int d_num_doppler_bins; + std::string d_dump_filename; +}; + +#endif // GNSS_SDR_ACQUISITION_DUMP_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.cc b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.cc new file mode 100644 index 000000000..4295a6564 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.cc @@ -0,0 +1,71 @@ +/*! + * \file acquisition_msg_rx.cc + * \brief This is a helper class to catch the asynchronous messages + * emitted by an acquisition block. + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.cat + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "acquisition_msg_rx.h" +#include +#include +#include +#include +#include + + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make() +{ + return Acquisition_msg_rx_sptr(new Acquisition_msg_rx()); +} + + +void Acquisition_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(std::move(msg)); + rx_message = message; + top_block->stop(); // stop the flowgraph + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_acquisition Bad cast!\n"; + rx_message = 0; + } +} + + +Acquisition_msg_rx::Acquisition_msg_rx() : gr::block("Acquisition_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&Acquisition_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +Acquisition_msg_rx::~Acquisition_msg_rx() = default; diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.h b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.h new file mode 100644 index 000000000..90a61a482 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/acquisition_msg_rx.h @@ -0,0 +1,62 @@ +/*! + * \file acquisition_msg_rx.h + * \brief This is a helper class to catch the asynchronous messages + * emitted by an acquisition block. + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.cat + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ACQUISITION_MSG_RX_H +#define GNSS_SDR_ACQUISITION_MSG_RX_H + +#include +#include +#include + +// ######## GNURADIO ACQUISITION BLOCK MESSAGE RECEVER ######### +class Acquisition_msg_rx; + +typedef boost::shared_ptr Acquisition_msg_rx_sptr; + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + + +class Acquisition_msg_rx : public gr::block +{ +private: + friend Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + Acquisition_msg_rx(); + +public: + int rx_message; + gr::top_block_sptr top_block; + ~Acquisition_msg_rx(); //!< Default destructor +}; + + +#endif diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.cc new file mode 100644 index 000000000..95c5ed22d --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.cc @@ -0,0 +1,143 @@ +/*! + * \file observables_dump_reader.cc + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "observables_dump_reader.h" +#include +#include + +bool observables_dump_reader::read_binary_obs() +{ + try + { + for (int i = 0; i < n_channels; i++) + { + d_dump_file.read(reinterpret_cast(&RX_time[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&TOW_at_current_symbol_s[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&Carrier_Doppler_hz[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&Acc_carrier_phase_hz[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&Pseudorange_m[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&PRN[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&valid[i]), sizeof(double)); + } + } + catch (const std::ifstream::failure &e) + { + return false; + } + return true; +} + + +bool observables_dump_reader::restart() +{ + if (d_dump_file.is_open()) + { + d_dump_file.clear(); + d_dump_file.seekg(0, std::ios::beg); + return true; + } + return false; +} + + +int64_t observables_dump_reader::num_epochs() +{ + std::ifstream::pos_type size; + int number_of_vars_in_epoch = n_channels * 7; + int epoch_size_bytes = sizeof(double) * number_of_vars_in_epoch; + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + if (tmpfile.is_open()) + { + size = tmpfile.tellg(); + int64_t nepoch = size / epoch_size_bytes; + return nepoch; + } + return 0; +} + + +bool observables_dump_reader::open_obs_file(std::string out_file) +{ + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); + return true; + } + catch (const std::ifstream::failure &e) + { + std::cout << "Problem opening TLM dump Log file: " << d_dump_filename.c_str() << std::endl; + return false; + } + } + else + { + return false; + } +} + +void observables_dump_reader::close_obs_file() +{ + if (d_dump_file.is_open() == false) + { + d_dump_file.close(); + } +} + +observables_dump_reader::observables_dump_reader(int n_channels_) +{ + n_channels = n_channels_; + RX_time = new double[n_channels]; + TOW_at_current_symbol_s = new double[n_channels]; + Carrier_Doppler_hz = new double[n_channels]; + Acc_carrier_phase_hz = new double[n_channels]; + Pseudorange_m = new double[n_channels]; + PRN = new double[n_channels]; + valid = new double[n_channels]; +} + + +observables_dump_reader::~observables_dump_reader() +{ + if (d_dump_file.is_open() == true) + { + d_dump_file.close(); + } + delete[] RX_time; + delete[] TOW_at_current_symbol_s; + delete[] Carrier_Doppler_hz; + delete[] Acc_carrier_phase_hz; + delete[] Pseudorange_m; + delete[] PRN; + delete[] valid; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.h new file mode 100644 index 000000000..9548829ac --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/observables_dump_reader.h @@ -0,0 +1,67 @@ +/*! + * \file observables_dump_reader.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_OBSERVABLES_DUMP_READER_H +#define GNSS_SDR_OBSERVABLES_DUMP_READER_H + +#include +#include +#include +#include + +class observables_dump_reader +{ +public: + observables_dump_reader(int n_channels); + ~observables_dump_reader(); + bool read_binary_obs(); + bool restart(); + int64_t num_epochs(); + bool open_obs_file(std::string out_file); + void close_obs_file(); + + + //dump variables + + double* RX_time; + double* TOW_at_current_symbol_s; + double* Carrier_Doppler_hz; + double* Acc_carrier_phase_hz; + double* Pseudorange_m; + double* PRN; + double* valid; + +private: + int n_channels; + std::string d_dump_filename; + std::ifstream d_dump_file; +}; + +#endif //GNSS_SDR_OBSERVABLES_DUMP_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.cc index 40e522f20..c8c95afd4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.cc +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,28 +23,31 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "tlm_dump_reader.h" +#include +#include bool tlm_dump_reader::read_binary_obs() { try - { - d_dump_file.read((char *) &TOW_at_current_symbol, sizeof(double)); - d_dump_file.read((char *) &Prn_timestamp_ms, sizeof(double)); - d_dump_file.read((char *) &d_TOW_at_Preamble, sizeof(double)); - } + { + d_dump_file.read(reinterpret_cast(&TOW_at_current_symbol), sizeof(double)); + d_dump_file.read(reinterpret_cast(&Tracking_sample_counter), sizeof(uint64_t)); + d_dump_file.read(reinterpret_cast(&d_TOW_at_Preamble), sizeof(double)); + } catch (const std::ifstream::failure &e) - { + { return false; - } + } return true; } + bool tlm_dump_reader::restart() { if (d_dump_file.is_open()) @@ -53,47 +56,43 @@ bool tlm_dump_reader::restart() d_dump_file.seekg(0, std::ios::beg); return true; } - else - { - return false; - } + return false; } -long int tlm_dump_reader::num_epochs() + +int64_t tlm_dump_reader::num_epochs() { std::ifstream::pos_type size; - int number_of_vars_in_epoch = 3; - int epoch_size_bytes = sizeof(double) * number_of_vars_in_epoch; - std::ifstream tmpfile( d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + int number_of_vars_in_epoch = 2; + int epoch_size_bytes = sizeof(double) * number_of_vars_in_epoch + sizeof(uint64_t); + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); if (tmpfile.is_open()) { size = tmpfile.tellg(); - long int nepoch = size / epoch_size_bytes; + int64_t nepoch = size / epoch_size_bytes; return nepoch; } - else - { - return 0; - } + return 0; } + bool tlm_dump_reader::open_obs_file(std::string out_file) { if (d_dump_file.is_open() == false) { try - { - d_dump_filename=out_file; - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); std::cout << "TLM dump enabled, Log file: " << d_dump_filename.c_str() << std::endl; return true; - } - catch (const std::ifstream::failure & e) - { + } + catch (const std::ifstream::failure &e) + { std::cout << "Problem opening TLM dump Log file: " << d_dump_filename.c_str() << std::endl; return false; - } + } } else { @@ -101,6 +100,7 @@ bool tlm_dump_reader::open_obs_file(std::string out_file) } } + tlm_dump_reader::~tlm_dump_reader() { if (d_dump_file.is_open() == true) diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.h index 7339b6e2e..43178bdc6 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.h +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tlm_dump_reader.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,7 +31,7 @@ #ifndef GNSS_SDR_TLM_DUMP_READER_H #define GNSS_SDR_TLM_DUMP_READER_H -#include +#include #include #include #include @@ -42,12 +42,12 @@ public: ~tlm_dump_reader(); bool read_binary_obs(); bool restart(); - long int num_epochs(); + int64_t num_epochs(); bool open_obs_file(std::string out_file); //telemetry decoder dump variables double TOW_at_current_symbol; - double Prn_timestamp_ms; + uint64_t Tracking_sample_counter; double d_TOW_at_Preamble; private: @@ -55,4 +55,4 @@ private: std::ifstream d_dump_file; }; -#endif //GNSS_SDR_TLM_DUMP_READER_H +#endif //GNSS_SDR_TLM_DUMP_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.cc index c410167b2..233bd8acb 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.cc +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,44 +23,50 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "tracking_dump_reader.h" +#include +#include bool tracking_dump_reader::read_binary_obs() { - try { - d_dump_file.read((char *) &abs_E, sizeof(float)); - d_dump_file.read((char *) &abs_P, sizeof(float)); - d_dump_file.read((char *) &abs_L, sizeof(float)); - d_dump_file.read((char *) &prompt_I, sizeof(float)); - d_dump_file.read((char *) &prompt_Q, sizeof(float)); - - d_dump_file.read((char *) &PRN_start_sample_count, sizeof(unsigned long int)); - - d_dump_file.read((char *) &acc_carrier_phase_rad, sizeof(double)); - d_dump_file.read((char *) &carrier_doppler_hz, sizeof(double)); - d_dump_file.read((char *) &code_freq_chips, sizeof(double)); - d_dump_file.read((char *) &carr_error_hz, sizeof(double)); - d_dump_file.read((char *) &carr_error_filt_hz, sizeof(double)); - d_dump_file.read((char *) &code_error_chips, sizeof(double)); - d_dump_file.read((char *) &code_error_filt_chips, sizeof(double)); - d_dump_file.read((char *) &CN0_SNV_dB_Hz, sizeof(double)); - d_dump_file.read((char *) &carrier_lock_test, sizeof(double)); - d_dump_file.read((char *) &aux1, sizeof(double)); - d_dump_file.read((char *) &aux2, sizeof(double)); - - } + try + { + d_dump_file.read(reinterpret_cast(&abs_VE), sizeof(float)); + d_dump_file.read(reinterpret_cast(&abs_E), sizeof(float)); + d_dump_file.read(reinterpret_cast(&abs_P), sizeof(float)); + d_dump_file.read(reinterpret_cast(&abs_L), sizeof(float)); + d_dump_file.read(reinterpret_cast(&abs_VL), sizeof(float)); + d_dump_file.read(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.read(reinterpret_cast(&prompt_Q), sizeof(float)); + d_dump_file.read(reinterpret_cast(&PRN_start_sample_count), sizeof(uint64_t)); + d_dump_file.read(reinterpret_cast(&acc_carrier_phase_rad), sizeof(float)); + d_dump_file.read(reinterpret_cast(&carrier_doppler_hz), sizeof(float)); + d_dump_file.read(reinterpret_cast(&carrier_doppler_rate_hz_s), sizeof(float)); + d_dump_file.read(reinterpret_cast(&code_freq_chips), sizeof(float)); + d_dump_file.read(reinterpret_cast(&code_freq_rate_chips), sizeof(float)); + d_dump_file.read(reinterpret_cast(&carr_error_hz), sizeof(float)); + d_dump_file.read(reinterpret_cast(&carr_error_filt_hz), sizeof(float)); + d_dump_file.read(reinterpret_cast(&code_error_chips), sizeof(float)); + d_dump_file.read(reinterpret_cast(&code_error_filt_chips), sizeof(float)); + d_dump_file.read(reinterpret_cast(&CN0_SNV_dB_Hz), sizeof(float)); + d_dump_file.read(reinterpret_cast(&carrier_lock_test), sizeof(float)); + d_dump_file.read(reinterpret_cast(&aux1), sizeof(float)); + d_dump_file.read(reinterpret_cast(&aux2), sizeof(double)); + d_dump_file.read(reinterpret_cast(&PRN), sizeof(unsigned int)); + } catch (const std::ifstream::failure &e) - { + { return false; - } + } return true; } + bool tracking_dump_reader::restart() { if (d_dump_file.is_open()) @@ -69,50 +75,46 @@ bool tracking_dump_reader::restart() d_dump_file.seekg(0, std::ios::beg); return true; } - else - { - return false; - } + return false; } -long int tracking_dump_reader::num_epochs() + +int64_t tracking_dump_reader::num_epochs() { std::ifstream::pos_type size; - int number_of_double_vars = 11; - int number_of_float_vars = 5; - int epoch_size_bytes=sizeof(unsigned long int) + - sizeof(double) * number_of_double_vars + - sizeof(float) * number_of_float_vars; - std::ifstream tmpfile( d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + int number_of_double_vars = 1; + int number_of_float_vars = 19; + int epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + + sizeof(float) * number_of_float_vars + sizeof(unsigned int); + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); if (tmpfile.is_open()) { size = tmpfile.tellg(); - long int nepoch = size / epoch_size_bytes; + int64_t nepoch = size / epoch_size_bytes; return nepoch; } - else - { - return 0; - } + + + return 0; } + bool tracking_dump_reader::open_obs_file(std::string out_file) { if (d_dump_file.is_open() == false) { try - { - d_dump_filename = out_file; - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); - std::cout << "Tracking dump enabled, Log file: " << d_dump_filename.c_str() << std::endl; return true; - } - catch (const std::ifstream::failure & e) - { + } + catch (const std::ifstream::failure &e) + { std::cout << "Problem opening Tracking dump Log file: " << d_dump_filename.c_str() << std::endl; return false; - } + } } else { @@ -120,6 +122,7 @@ bool tracking_dump_reader::open_obs_file(std::string out_file) } } + tracking_dump_reader::~tracking_dump_reader() { if (d_dump_file.is_open() == true) diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.h index 6ec71ebb2..790838a8a 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.h +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_dump_reader.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,7 +31,7 @@ #ifndef GNSS_SDR_TRACKING_DUMP_READER_H #define GNSS_SDR_TRACKING_DUMP_READER_H -#include +#include #include #include #include @@ -42,46 +42,52 @@ public: ~tracking_dump_reader(); bool read_binary_obs(); bool restart(); - long int num_epochs(); + int64_t num_epochs(); bool open_obs_file(std::string out_file); //tracking dump variables - // EPR + // VEPLVL + float abs_VE; float abs_E; float abs_P; float abs_L; + float abs_VL; // PROMPT I and Q (to analyze navigation symbols) float prompt_I; float prompt_Q; // PRN start sample stamp - unsigned long int PRN_start_sample_count; + uint64_t PRN_start_sample_count; // accumulated carrier phase - double acc_carrier_phase_rad; + float acc_carrier_phase_rad; // carrier and code frequency - double carrier_doppler_hz; - double code_freq_chips; + float carrier_doppler_hz; + float carrier_doppler_rate_hz_s; + float code_freq_chips; + float code_freq_rate_chips; // PLL commands - double carr_error_hz; - double carr_error_filt_hz; + float carr_error_hz; + float carr_error_filt_hz; // DLL commands - double code_error_chips; - double code_error_filt_chips; + float code_error_chips; + float code_error_filt_chips; // CN0 and carrier lock test - double CN0_SNV_dB_Hz; - double carrier_lock_test; + float CN0_SNV_dB_Hz; + float carrier_lock_test; // AUX vars (for debug purposes) - double aux1; + float aux1; double aux2; + unsigned int PRN; + private: std::string d_dump_filename; std::ifstream d_dump_file; }; -#endif //GNSS_SDR_TRACKING_DUMP_READER_H +#endif //GNSS_SDR_TRACKING_DUMP_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.cc index 90a31cca4..efa913404 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.cc +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,30 +23,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "tracking_true_obs_reader.h" +#include +#include bool tracking_true_obs_reader::read_binary_obs() { try - { - d_dump_file.read((char *) &signal_timestamp_s, sizeof(double)); - d_dump_file.read((char *) &acc_carrier_phase_cycles, sizeof(double)); - d_dump_file.read((char *) &doppler_l1_hz, sizeof(double)); - d_dump_file.read((char *) &prn_delay_chips, sizeof(double)); - d_dump_file.read((char *) &tow, sizeof(double)); - } + { + d_dump_file.read(reinterpret_cast(&signal_timestamp_s), sizeof(double)); + d_dump_file.read(reinterpret_cast(&acc_carrier_phase_cycles), sizeof(double)); + d_dump_file.read(reinterpret_cast(&doppler_l1_hz), sizeof(double)); + d_dump_file.read(reinterpret_cast(&prn_delay_chips), sizeof(double)); + d_dump_file.read(reinterpret_cast(&tow), sizeof(double)); + } catch (const std::ifstream::failure &e) - { + { return false; - } + } return true; } + bool tracking_true_obs_reader::restart() { if (d_dump_file.is_open()) @@ -55,47 +58,43 @@ bool tracking_true_obs_reader::restart() d_dump_file.seekg(0, std::ios::beg); return true; } - else - { - return false; - } + return false; } -long int tracking_true_obs_reader::num_epochs() + +int64_t tracking_true_obs_reader::num_epochs() { std::ifstream::pos_type size; int number_of_vars_in_epoch = 5; int epoch_size_bytes = sizeof(double) * number_of_vars_in_epoch; - std::ifstream tmpfile( d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); if (tmpfile.is_open()) { size = tmpfile.tellg(); - long int nepoch = size / epoch_size_bytes; + int64_t nepoch = size / epoch_size_bytes; return nepoch; } - else - { - return 0; - } + return 0; } + bool tracking_true_obs_reader::open_obs_file(std::string out_file) { if (d_dump_file.is_open() == false) { try - { - d_dump_filename = out_file; - d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); + { + d_dump_file.clear(); + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); - std::cout << "Observables dump enabled, Log file: " << d_dump_filename.c_str() << std::endl; return true; - } - catch (const std::ifstream::failure & e) - { - std::cout << "Problem opening Observables dump Log file: " << d_dump_filename.c_str() << std::endl; + } + catch (const std::ifstream::failure &e) + { + std::cout << "Problem opening Tracking dump Log file: " << d_dump_filename.c_str() << std::endl; return false; - } + } } else { @@ -103,6 +102,14 @@ bool tracking_true_obs_reader::open_obs_file(std::string out_file) } } +void tracking_true_obs_reader::close_obs_file() +{ + if (d_dump_file.is_open() == true) + { + d_dump_file.close(); + } +} + tracking_true_obs_reader::~tracking_true_obs_reader() { if (d_dump_file.is_open() == true) diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.h index 08b69f433..5b8990325 100644 --- a/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.h +++ b/src/tests/unit-tests/signal-processing-blocks/libs/tracking_true_obs_reader.h @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,7 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -31,7 +31,7 @@ #ifndef GNSS_SDR_TRACKING_TRUE_OBS_READER_H #define GNSS_SDR_TRACKING_TRUE_OBS_READER_H -#include +#include #include #include #include @@ -42,8 +42,9 @@ public: ~tracking_true_obs_reader(); bool read_binary_obs(); bool restart(); - long int num_epochs(); + int64_t num_epochs(); bool open_obs_file(std::string out_file); + void close_obs_file(); bool d_dump; double signal_timestamp_s; @@ -57,4 +58,4 @@ private: std::ifstream d_dump_file; }; -#endif //GNSS_SDR_RACKING_TRUE_OBS_READER_H +#endif //GNSS_SDR_RACKING_TRUE_OBS_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.cc b/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.cc new file mode 100644 index 000000000..14cd52562 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.cc @@ -0,0 +1,117 @@ +/*! + * \file true_observables_reader.cc + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "true_observables_reader.h" +#include +#include + +bool true_observables_reader::read_binary_obs() +{ + try + { + for (int i = 0; i < 12; i++) + { + d_dump_file.read(reinterpret_cast(&gps_time_sec[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&doppler_l1_hz[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&acc_carrier_phase_l1_cycles[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&dist_m[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&true_dist_m[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&carrier_phase_l1_cycles[i]), sizeof(double)); + d_dump_file.read(reinterpret_cast(&prn[i]), sizeof(double)); + } + } + catch (const std::ifstream::failure &e) + { + return false; + } + return true; +} + + +bool true_observables_reader::restart() +{ + if (d_dump_file.is_open()) + { + d_dump_file.clear(); + d_dump_file.seekg(0, std::ios::beg); + return true; + } + return false; +} + + +int64_t true_observables_reader::num_epochs() +{ + std::ifstream::pos_type size; + int number_of_vars_in_epoch = 6 * 12; + int epoch_size_bytes = sizeof(double) * number_of_vars_in_epoch; + std::ifstream tmpfile(d_dump_filename.c_str(), std::ios::binary | std::ios::ate); + if (tmpfile.is_open()) + { + size = tmpfile.tellg(); + int64_t nepoch = size / epoch_size_bytes; + return nepoch; + } + return 0; +} + + +bool true_observables_reader::open_obs_file(std::string out_file) +{ + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = std::move(out_file); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::in | std::ios::binary); + std::cout << "True observables Log file opened: " << d_dump_filename.c_str() << std::endl; + return true; + } + catch (const std::ifstream::failure &e) + { + std::cout << "Problem opening True observables Log file: " << d_dump_filename.c_str() << std::endl; + return false; + } + } + else + { + return false; + } +} + + +true_observables_reader::~true_observables_reader() +{ + if (d_dump_file.is_open() == true) + { + d_dump_file.close(); + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.h b/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.h new file mode 100644 index 000000000..86e1c868d --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/libs/true_observables_reader.h @@ -0,0 +1,61 @@ +/*! + * \file tlm_dump_reader.h + * \brief Helper file for unit testing + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_TRUE_OBSERVABLES_READER_H +#define GNSS_SDR_TRUE_OBSERVABLES_READER_H + +#include +#include +#include +#include + +class true_observables_reader +{ +public: + ~true_observables_reader(); + bool read_binary_obs(); + bool restart(); + int64_t num_epochs(); + bool open_obs_file(std::string out_file); + + double gps_time_sec[12]; + double doppler_l1_hz[12]; + double acc_carrier_phase_l1_cycles[12]; + double dist_m[12]; + double true_dist_m[12]; + double carrier_phase_l1_cycles[12]; + double prn[12]; + +private: + std::string d_dump_filename; + std::ifstream d_dump_file; +}; + +#endif //GNSS_SDR_TRUE_OBSERVABLES_READER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc new file mode 100644 index 000000000..feccb8105 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc @@ -0,0 +1,2142 @@ +/*! + * \file hybrid_observables_test.cc + * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Javier Arribas, 2015. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "acquisition_msg_rx.h" +#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "galileo_e5a_noncoherent_iq_acquisition_caf.h" +#include "galileo_e5a_pcps_acquisition.h" +#include "glonass_l1_ca_pcps_acquisition.h" +#include "glonass_l2_ca_pcps_acquisition.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_satellite.h" +#include "gnss_sdr_sample_counter.h" +#include "gnss_synchro.h" +#include "gnuplot_i.h" +#include "gps_l1_ca_dll_pll_tracking.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "gps_l2_m_pcps_acquisition.h" +#include "gps_l5i_pcps_acquisition.h" +#include "hybrid_observables.h" +#include "in_memory_configuration.h" +#include "observable_tests_flags.h" +#include "observables_dump_reader.h" +#include "signal_generator_flags.h" +#include "telemetry_decoder_interface.h" +#include "test_flags.h" +#include "tlm_dump_reader.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_tests_flags.h" +#include "tracking_true_obs_reader.h" +#include "true_observables_reader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + + +// ######## GNURADIO BLOCK MESSAGE RECEVER FOR TRACKING MESSAGES ######### +class HybridObservablesTest_msg_rx; + +typedef boost::shared_ptr HybridObservablesTest_msg_rx_sptr; + +HybridObservablesTest_msg_rx_sptr HybridObservablesTest_msg_rx_make(); + +class HybridObservablesTest_msg_rx : public gr::block +{ +private: + friend HybridObservablesTest_msg_rx_sptr HybridObservablesTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + HybridObservablesTest_msg_rx(); + +public: + int rx_message; + ~HybridObservablesTest_msg_rx(); //!< Default destructor +}; + +HybridObservablesTest_msg_rx_sptr HybridObservablesTest_msg_rx_make() +{ + return HybridObservablesTest_msg_rx_sptr(new HybridObservablesTest_msg_rx()); +} + +void HybridObservablesTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +HybridObservablesTest_msg_rx::HybridObservablesTest_msg_rx() : gr::block("HybridObservablesTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&HybridObservablesTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + +HybridObservablesTest_msg_rx::~HybridObservablesTest_msg_rx() +{ +} + + +// ########################################################### + + +// ######## GNURADIO BLOCK MESSAGE RECEVER FOR TLM MESSAGES ######### +class HybridObservablesTest_tlm_msg_rx; + +typedef boost::shared_ptr HybridObservablesTest_tlm_msg_rx_sptr; + +HybridObservablesTest_tlm_msg_rx_sptr HybridObservablesTest_tlm_msg_rx_make(); + +class HybridObservablesTest_tlm_msg_rx : public gr::block +{ +private: + friend HybridObservablesTest_tlm_msg_rx_sptr HybridObservablesTest_tlm_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + HybridObservablesTest_tlm_msg_rx(); + +public: + int rx_message; + ~HybridObservablesTest_tlm_msg_rx(); //!< Default destructor +}; + +HybridObservablesTest_tlm_msg_rx_sptr HybridObservablesTest_tlm_msg_rx_make() +{ + return HybridObservablesTest_tlm_msg_rx_sptr(new HybridObservablesTest_tlm_msg_rx()); +} + +void HybridObservablesTest_tlm_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +HybridObservablesTest_tlm_msg_rx::HybridObservablesTest_tlm_msg_rx() : gr::block("HybridObservablesTest_tlm_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&HybridObservablesTest_tlm_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + +HybridObservablesTest_tlm_msg_rx::~HybridObservablesTest_tlm_msg_rx() +{ +} + + +// ########################################################### + + +class HybridObservablesTest : public ::testing::Test +{ +public: + enum StringValue + { + evGPS_1C, + evGPS_2S, + evGPS_L5, + evSBAS_1C, + evGAL_1B, + evGAL_5X, + evGLO_1G, + evGLO_2G + }; + std::map mapStringValues_; + + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + std::string implementation = FLAGS_trk_test_implementation; + + const int baseband_sampling_freq = FLAGS_fs_gen_sps; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_filename_raw_data; + + int configure_generator(); + int generate_signal(); + bool save_mat_xy(std::vector& x, std::vector& y, std::string filename); + void check_results_carrier_phase( + arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + std::string data_title); + void check_results_carrier_phase_double_diff( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title); + void check_results_carrier_doppler(arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + std::string data_title); + void check_results_carrier_doppler_double_diff( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title); + void check_results_code_pseudorange( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title); + + void check_results_duplicated_satellite( + arma::mat& measured_sat1, + arma::mat& measured_sat2, + int ch_id, + std::string data_title); + + HybridObservablesTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + mapStringValues_["1C"] = evGPS_1C; + mapStringValues_["2S"] = evGPS_2S; + mapStringValues_["L5"] = evGPS_L5; + mapStringValues_["1B"] = evGAL_1B; + mapStringValues_["5X"] = evGAL_5X; + mapStringValues_["1G"] = evGLO_1G; + mapStringValues_["2G"] = evGLO_2G; + } + + ~HybridObservablesTest() + { + } + + bool ReadRinexObs(std::vector* obs_vec, Gnss_Synchro gnss); + + bool acquire_signal(); + void configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols, + uint32_t smoother_length, + bool high_dyn); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro_master; + std::vector gnss_synchro_vec; + size_t item_size; +}; + +int HybridObservablesTest::configure_generator() +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + return 0; +} + + +int HybridObservablesTest::generate_signal() +{ + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +bool HybridObservablesTest::acquire_signal() +{ + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) + gr::top_block_sptr top_block; + top_block = gr::make_top_block("Acquisition test"); + int SV_ID = 1; //initial sv id + // Satellite signal definition + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.Channel_ID = 0; + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + // Enable automatic resampler for the acquisition, if required + if (FLAGS_use_acquisition_resampler == true) + { + config->set_property("GNSS-SDR.use_acquisition_resampler", "true"); + } + config->set_property("Acquisition.blocking_on_standby", "true"); + config->set_property("Acquisition.blocking", "true"); + config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition.dump_filename", "./data/acquisition.dat"); + config->set_property("Acquisition.use_CFAR_algorithm", "false"); + + std::shared_ptr acquisition; + + std::string System_and_Signal; + std::string signal; + //create the correspondign acquisition block according to the desired tracking signal + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "1C"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L1 CA"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + //acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "1B"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E1B"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "2S"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L2CM"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition_5X.coherent_integration_time_ms", "1"); + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + config->set_property("Acquisition.CAF_window_hz", "0"); // **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz + config->set_property("Acquisition.Zero_padding", "0"); //**Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. + config->set_property("Acquisition.bit_transition_flag", "false"); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "L5"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L5I"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->set_channel(0); + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz)); + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz)); + acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); + acquisition->init(); + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->connect(top_block); + + gr::blocks::file_source::sptr file_source; + std::string file = FLAGS_signal_file; + const char* file_name = file.c_str(); + file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + //gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); + //top_block->connect(head_samples, 0, acquisition->get_left_block(), 0); + + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + + // Enable automatic resampler for the acquisition, if required + if (FLAGS_use_acquisition_resampler == true) + { + //create acquisition resamplers if required + double resampler_ratio = 1.0; + + double opt_fs = baseband_sampling_freq; + //find the signal associated to this channel + switch (mapStringValues_[signal]) + { + case evGPS_1C: + opt_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGPS_2S: + opt_fs = GPS_L2C_OPT_ACQ_FS_HZ; + break; + case evGPS_L5: + opt_fs = GPS_L5_OPT_ACQ_FS_HZ; + break; + case evSBAS_1C: + opt_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGAL_1B: + opt_fs = Galileo_E1_OPT_ACQ_FS_HZ; + break; + case evGAL_5X: + opt_fs = Galileo_E5a_OPT_ACQ_FS_HZ; + break; + case evGLO_1G: + opt_fs = baseband_sampling_freq; + break; + case evGLO_2G: + opt_fs = baseband_sampling_freq; + break; + } + if (opt_fs < baseband_sampling_freq) + { + resampler_ratio = baseband_sampling_freq / opt_fs; + int decimation = floor(resampler_ratio); + while (baseband_sampling_freq % decimation > 0) + { + decimation--; + }; + double acq_fs = baseband_sampling_freq / decimation; + + if (decimation > 1) + { + //create a FIR low pass filter + std::vector taps; + taps = gr::filter::firdes::low_pass(1.0, + baseband_sampling_freq, + acq_fs / 2.1, + acq_fs / 10, + gr::filter::firdes::win_type::WIN_HAMMING); + std::cout << "Enabled decimation low pass filter with " << taps.size() << " taps and decimation factor of " << decimation << std::endl; + acquisition->set_resampler_latency((taps.size() - 1) / 2); + gr::basic_block_sptr fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(decimation, taps); + top_block->connect(gr_interleaved_char_to_complex, 0, fir_filter_ccf_, 0); + top_block->connect(fir_filter_ccf_, 0, acquisition->get_left_block(), 0); + } + else + { + std::cout << "Disabled acquisition resampler because the input sampling frequency is too low\n"; + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + } + } + else + { + std::cout << "Disabled acquisition resampler because the input sampling frequency is too low\n"; + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + } + } + else + { + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + //top_block->connect(head_samples, 0, acquisition->get_left_block(), 0); + } + + + boost::shared_ptr msg_rx; + try + { + msg_rx = Acquisition_msg_rx_make(); + } + catch (const std::exception& e) + { + std::cout << "Failure connecting the message port system: " << e.what() << std::endl; + exit(0); + } + + msg_rx->top_block = top_block; + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + // 5. Run the flowgraph + // Get visible GPS satellites (positive acquisitions with Doppler measurements) + // record startup time + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + start = std::chrono::system_clock::now(); + + bool start_msg = true; + + unsigned int MAX_PRN_IDX = 0; + + switch (tmp_gnss_synchro.System) + { + case 'G': + MAX_PRN_IDX = 33; + break; + case 'E': + MAX_PRN_IDX = 37; + break; + default: + MAX_PRN_IDX = 33; + } + + for (unsigned int PRN = 1; PRN < MAX_PRN_IDX; PRN++) + { + tmp_gnss_synchro.PRN = PRN; + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->init(); + acquisition->set_local_code(); + acquisition->reset(); + acquisition->set_state(1); + msg_rx->rx_message = 0; + top_block->run(); + if (start_msg == true) + { + std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; + std::cout << "Searching for " << System_and_Signal << " Satellites..." << std::endl; + std::cout << "["; + start_msg = false; + } + while (msg_rx->rx_message == 0) + { + usleep(100000); + } + if (msg_rx->rx_message == 1) + { + std::cout << " " << PRN << " "; + gnss_synchro_vec.push_back(tmp_gnss_synchro); + } + else + { + std::cout << " . "; + } + top_block->stop(); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + std::cout.flush(); + } + std::cout << "]" << std::endl; + std::cout << "-------------------------------------------\n"; + + for (auto& x : gnss_synchro_vec) + { + std::cout << "DETECTED SATELLITE " << System_and_Signal + << " PRN: " << x.PRN + << " with Doppler: " << x.Acq_doppler_hz + << " [Hz], code phase: " << x.Acq_delay_samples + << " [samples] at signal SampleStamp " << x.Acq_samplestamp_samples << "\n"; + } + + // report the elapsed time + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + std::cout << "Total signal acquisition run time " + << elapsed_seconds.count() + << " [seconds]" << std::endl; + if (gnss_synchro_vec.size() > 0) + { + return true; + } + else + { + return false; + } +} + + +void HybridObservablesTest::configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols, + uint32_t smoother_length, + bool high_dyn) +{ + config = std::make_shared(); + config->set_property("Tracking.dump", "true"); + if (high_dyn) + config->set_property("Tracking.high_dyn", "true"); + else + config->set_property("Tracking.high_dyn", "false"); + config->set_property("Tracking.smoother_length", std::to_string(smoother_length)); + config->set_property("Tracking.dump_filename", "./tracking_ch_"); + config->set_property("Tracking.implementation", implementation); + config->set_property("Tracking.item_type", "gr_complex"); + config->set_property("Tracking.pll_bw_hz", std::to_string(PLL_wide_bw_hz)); + config->set_property("Tracking.dll_bw_hz", std::to_string(DLL_wide_bw_hz)); + config->set_property("Tracking.extend_correlation_symbols", std::to_string(extend_correlation_symbols)); + config->set_property("Tracking.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz)); + config->set_property("Tracking.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz)); + config->set_property("Observables.implementation", "Hybrid_Observables"); + config->set_property("Observables.dump", "true"); + config->set_property("TelemetryDecoder.dump", "true"); + + gnss_synchro_master.Channel_ID = 0; + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + + std::string System_and_Signal; + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + gnss_synchro_master.System = 'G'; + std::string signal = "1C"; + System_and_Signal = "GPS L1 CA"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null + + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); + + config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + gnss_synchro_master.System = 'E'; + std::string signal = "1B"; + System_and_Signal = "Galileo E1B"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null + + config->set_property("Tracking.early_late_space_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_chips", "0.6"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); + config->set_property("Tracking.track_pilot", "true"); + + config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + gnss_synchro_master.System = 'G'; + std::string signal = "2S"; + System_and_Signal = "GPS L2CM"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null + + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + + config->set_property("TelemetryDecoder.implementation", "GPS_L2C_Telemetry_Decoder"); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0 or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + gnss_synchro_master.System = 'E'; + std::string signal = "5X"; + System_and_Signal = "Galileo E5a"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null + + if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking")); + } + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + + config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + gnss_synchro_master.System = 'G'; + std::string signal = "L5"; + System_and_Signal = "GPS L5I"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null + + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + + config->set_property("TelemetryDecoder.implementation", "GPS_L5_Telemetry_Decoder"); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + std::cout << "*****************************************\n"; + std::cout << "*** Tracking configuration parameters ***\n"; + std::cout << "*****************************************\n"; + std::cout << "Signal: " << System_and_Signal << "\n"; + std::cout << "implementation: " << config->property("Tracking.implementation", std::string("undefined")) << " \n"; + std::cout << "pll_bw_hz: " << config->property("Tracking.pll_bw_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_hz: " << config->property("Tracking.dll_bw_hz", 0.0) << " Hz\n"; + std::cout << "pll_bw_narrow_hz: " << config->property("Tracking.pll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_narrow_hz: " << config->property("Tracking.dll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "extend_correlation_symbols: " << config->property("Tracking.extend_correlation_symbols", 0) << " Symbols\n"; + std::cout << "high_dyn: " << config->property("Tracking.high_dyn", false) << "\n"; + std::cout << "smoother_length: " << config->property("Tracking.smoother_length", 0) << "\n"; + std::cout << "*****************************************\n"; + std::cout << "*****************************************\n"; +} + +void HybridObservablesTest::check_results_carrier_phase( + arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + double t0 = measured_ch0(0, 0); + int size1 = measured_ch0.col(0).n_rows; + double t1 = measured_ch0(size1 - 1, 0); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + + arma::vec true_ch0_phase_interp; + arma::interp1(true_tow_s, true_ch0.col(3), t, true_ch0_phase_interp); + + arma::vec meas_ch0_phase_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(3), t, meas_ch0_phase_interp); + + //2. RMSE + arma::vec err_ch0_cycles; + + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + err_ch0_cycles = meas_ch0_phase_interp - true_ch0_phase_interp - meas_ch0_phase_interp(0) + true_ch0_phase_interp(0); + + arma::vec err2_ch0 = arma::square(err_ch0_cycles); + double rmse_ch0 = sqrt(arma::mean(err2_ch0)); + + //3. Mean err and variance + double error_mean_ch0 = arma::mean(err_ch0_cycles); + double error_var_ch0 = arma::var(err_ch0_cycles); + + // 4. Peaks + double max_error_ch0 = arma::max(err_ch0_cycles); + double min_error_ch0 = arma::min(err_ch0_cycles); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << " Accumulated Carrier phase RMSE = " + << rmse_ch0 << ", mean = " << error_mean_ch0 + << ", stdev = " << sqrt(error_var_ch0) + << " (max,min) = " << max_error_ch0 + << "," << min_error_ch0 + << " [cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Accumulated Carrier phase error [cycles]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Phase error [cycles]"); + //conversion between arma::vec and std:vector + std::vector error_vec(err_ch0_cycles.colptr(0), err_ch0_cycles.colptr(0) + err_ch0_cycles.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, error_vec, + "Carrier Phase error"); + g3.set_legend(); + g3.savetops(data_title + "Carrier_phase_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(rmse_ch0, 0.25); + ASSERT_LT(error_mean_ch0, 0.2); + ASSERT_GT(error_mean_ch0, -0.2); + ASSERT_LT(error_var_ch0, 0.5); + ASSERT_LT(max_error_ch0, 0.5); + ASSERT_GT(min_error_ch0, -0.5); +} + + +void HybridObservablesTest::check_results_carrier_phase_double_diff( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + double t0 = std::max(measured_ch0(0, 0), measured_ch1(0, 0)); + int size1 = measured_ch0.col(0).n_rows; + int size2 = measured_ch1.col(0).n_rows; + double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); + + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + + + arma::vec true_ch0_carrier_phase_interp; + arma::vec true_ch1_carrier_phase_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(3), t, true_ch0_carrier_phase_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(3), t, true_ch1_carrier_phase_interp); + + arma::vec meas_ch0_carrier_phase_interp; + arma::vec meas_ch1_carrier_phase_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(3), t, meas_ch0_carrier_phase_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(3), t, meas_ch1_carrier_phase_interp); + + // generate double difference accumulated carrier phases + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + arma::vec delta_true_carrier_phase_cycles = (true_ch0_carrier_phase_interp - true_ch0_carrier_phase_interp(0)) - (true_ch1_carrier_phase_interp - true_ch1_carrier_phase_interp(0)); + arma::vec delta_measured_carrier_phase_cycles = (meas_ch0_carrier_phase_interp - meas_ch0_carrier_phase_interp(0)) - (meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp(0)); + + //2. RMSE + arma::vec err; + + err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Carrier Phase RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [Cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Carrier Phase error [Cycles]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Carrier Phase error [Cycles]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Carrier Phase error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_carrier_phase_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(rmse, 0.25); + ASSERT_LT(error_mean, 0.2); + ASSERT_GT(error_mean, -0.2); + ASSERT_LT(error_var, 0.5); + ASSERT_LT(max_error, 0.5); + ASSERT_GT(min_error, -0.5); +} + + +void HybridObservablesTest::check_results_carrier_doppler_double_diff( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + double t0 = std::max(measured_ch0(0, 0), measured_ch1(0, 0)); + int size1 = measured_ch0.col(0).n_rows; + int size2 = measured_ch1.col(0).n_rows; + double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); + + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + + + arma::vec true_ch0_carrier_doppler_interp; + arma::vec true_ch1_carrier_doppler_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(2), t, true_ch0_carrier_doppler_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(2), t, true_ch1_carrier_doppler_interp); + + arma::vec meas_ch0_carrier_doppler_interp; + arma::vec meas_ch1_carrier_doppler_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_carrier_doppler_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(2), t, meas_ch1_carrier_doppler_interp); + + // generate double difference carrier Doppler + arma::vec delta_true_carrier_doppler_cycles = true_ch0_carrier_doppler_interp - true_ch1_carrier_doppler_interp; + arma::vec delta_measured_carrier_doppler_cycles = meas_ch0_carrier_doppler_interp - meas_ch1_carrier_doppler_interp; + + //2. RMSE + arma::vec err; + + err = delta_measured_carrier_doppler_cycles - delta_true_carrier_doppler_cycles; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Carrier Doppler RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(error_mean, 5); + ASSERT_GT(error_mean, -5); + //assuming PLL BW=35 + ASSERT_LT(error_var, 250); + ASSERT_LT(max_error, 100); + ASSERT_GT(min_error, -100); + ASSERT_LT(rmse, 30); +} + + +void HybridObservablesTest::check_results_carrier_doppler( + arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + double t0 = measured_ch0(0, 0); + int size1 = measured_ch0.col(0).n_rows; + double t1 = measured_ch0(size1 - 1, 0); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + + arma::vec true_ch0_doppler_interp; + arma::interp1(true_tow_s, true_ch0.col(2), t, true_ch0_doppler_interp); + + arma::vec meas_ch0_doppler_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_doppler_interp); + + //2. RMSE + arma::vec err_ch0_hz; + + //compute error + err_ch0_hz = meas_ch0_doppler_interp - true_ch0_doppler_interp; + + arma::vec err2_ch0 = arma::square(err_ch0_hz); + double rmse_ch0 = sqrt(arma::mean(err2_ch0)); + + //3. Mean err and variance + double error_mean_ch0 = arma::mean(err_ch0_hz); + double error_var_ch0 = arma::var(err_ch0_hz); + + // 4. Peaks + double max_error_ch0 = arma::max(err_ch0_hz); + double min_error_ch0 = arma::min(err_ch0_hz); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " + << rmse_ch0 << ", mean = " << error_mean_ch0 + << ", stdev = " << sqrt(error_var_ch0) + << " (max,min) = " << max_error_ch0 + << "," << min_error_ch0 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, error_vec, + "Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "Carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(error_mean_ch0, 5); + ASSERT_GT(error_mean_ch0, -5); + //assuming PLL BW=35 + ASSERT_LT(error_var_ch0, 250); + ASSERT_LT(max_error_ch0, 100); + ASSERT_GT(min_error_ch0, -100); + ASSERT_LT(rmse_ch0, 30); +} + +void HybridObservablesTest::check_results_duplicated_satellite( + arma::mat& measured_sat1, + arma::mat& measured_sat2, + int ch_id, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + //define the common measured time interval + double t0_sat1 = measured_sat1(0, 0); + int size1 = measured_sat1.col(0).n_rows; + double t1_sat1 = measured_sat1(size1 - 1, 0); + + double t0_sat2 = measured_sat2(0, 0); + int size2 = measured_sat2.col(0).n_rows; + double t1_sat2 = measured_sat2(size2 - 1, 0); + + double t0; + double t1; + if (t0_sat1 > t0_sat2) + { + t0 = t0_sat1; + } + else + { + t0 = t0_sat2; + } + + if (t1_sat1 > t1_sat2) + { + t1 = t1_sat2; + } + else + { + t1 = t1_sat1; + } + + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + //Doppler + arma::vec meas_sat1_doppler_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(2), t, meas_sat1_doppler_interp); + arma::vec meas_sat2_doppler_interp; + arma::interp1(measured_sat2.col(0), measured_sat2.col(2), t, meas_sat2_doppler_interp); + + //Carrier Phase + arma::vec meas_sat1_carrier_phase_interp; + arma::vec meas_sat2_carrier_phase_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(3), t, meas_sat1_carrier_phase_interp); + arma::interp1(measured_sat2.col(0), measured_sat2.col(3), t, meas_sat2_carrier_phase_interp); + + // generate double difference accumulated carrier phases + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + arma::vec delta_measured_carrier_phase_cycles = (meas_sat1_carrier_phase_interp - meas_sat1_carrier_phase_interp(0)) - (meas_sat2_carrier_phase_interp - meas_sat2_carrier_phase_interp(0)); + + //Pseudoranges + arma::vec meas_sat1_dist_interp; + arma::vec meas_sat2_dist_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(4), t, meas_sat1_dist_interp); + arma::interp1(measured_sat2.col(0), measured_sat2.col(4), t, meas_sat2_dist_interp); + // generate delta pseudoranges + arma::vec delta_measured_dist_m = meas_sat1_dist_interp - meas_sat2_dist_interp; + + //Carrier Doppler error + //2. RMSE + arma::vec err_ch0_hz; + + //compute error + err_ch0_hz = meas_sat1_doppler_interp - meas_sat2_doppler_interp; + + //save matlab file for further analysis + std::vector tmp_vector_common_time_s(t.colptr(0), + t.colptr(0) + t.n_rows); + + std::vector tmp_vector_err_ch0_hz(err_ch0_hz.colptr(0), + err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_ch0_hz, std::string("measured_doppler_error_ch_" + std::to_string(ch_id))); + + //compute statistics + arma::vec err2_ch0 = arma::square(err_ch0_hz); + double rmse_ch0 = sqrt(arma::mean(err2_ch0)); + + //3. Mean err and variance + double error_mean_ch0 = arma::mean(err_ch0_hz); + double error_var_ch0 = arma::var(err_ch0_hz); + + // 4. Peaks + double max_error_ch0 = arma::max(err_ch0_hz); + double min_error_ch0 = arma::min(err_ch0_hz); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " + << rmse_ch0 << ", mean = " << error_mean_ch0 + << ", stdev = " << sqrt(error_var_ch0) + << " (max,min) = " << max_error_ch0 + << "," << min_error_ch0 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, error_vec, + "Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "Carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(error_mean_ch0, 5); + EXPECT_GT(error_mean_ch0, -5); + //assuming PLL BW=35 + EXPECT_LT(error_var_ch0, 250); + EXPECT_LT(max_error_ch0, 100); + EXPECT_GT(min_error_ch0, -100); + EXPECT_LT(rmse_ch0, 30); + + //Carrier Phase error + //2. RMSE + arma::vec err_carrier_phase; + + err_carrier_phase = delta_measured_carrier_phase_cycles; + + //save matlab file for further analysis + std::vector tmp_vector_err_carrier_phase(err_carrier_phase.colptr(0), + err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_carrier_phase, std::string("measured_carrier_phase_error_ch_" + std::to_string(ch_id))); + + + arma::vec err2_carrier_phase = arma::square(err_carrier_phase); + double rmse_carrier_phase = sqrt(arma::mean(err2_carrier_phase)); + + //3. Mean err and variance + double error_mean_carrier_phase = arma::mean(err_carrier_phase); + double error_var_carrier_phase = arma::var(err_carrier_phase); + + // 4. Peaks + double max_error_carrier_phase = arma::max(err_carrier_phase); + double min_error_carrier_phase = arma::min(err_carrier_phase); + + //5. report + ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Phase RMSE = " + << rmse_carrier_phase << ", mean = " << error_mean_carrier_phase + << ", stdev = " << sqrt(error_var_carrier_phase) + << " (max,min) = " << max_error_carrier_phase + << "," << min_error_carrier_phase + << " [Cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Phase error [Cycles]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Phase error [Cycles]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err_carrier_phase.colptr(0), err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Carrier Phase error"); + g3.set_legend(); + g3.savetops(data_title + "duplicated_satellite_carrier_phase_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(rmse_carrier_phase, 0.25); + EXPECT_LT(error_mean_carrier_phase, 0.2); + EXPECT_GT(error_mean_carrier_phase, -0.2); + EXPECT_LT(error_var_carrier_phase, 0.5); + EXPECT_LT(max_error_carrier_phase, 0.5); + EXPECT_GT(min_error_carrier_phase, -0.5); + + //Pseudorange error + //2. RMSE + arma::vec err_pseudorange; + + err_pseudorange = delta_measured_dist_m; + + //save matlab file for further analysis + std::vector tmp_vector_err_pseudorange(err_pseudorange.colptr(0), + err_pseudorange.colptr(0) + err_pseudorange.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_pseudorange, std::string("measured_pr_error_ch_" + std::to_string(ch_id))); + + arma::vec err2_pseudorange = arma::square(err_pseudorange); + double rmse_pseudorange = sqrt(arma::mean(err2_pseudorange)); + + //3. Mean err and variance + double error_mean_pseudorange = arma::mean(err_pseudorange); + double error_var_pseudorange = arma::var(err_pseudorange); + + // 4. Peaks + double max_error_pseudorange = arma::max(err_pseudorange); + double min_error_pseudorange = arma::min(err_pseudorange); + + //5. report + ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Pseudorange RMSE = " + << rmse_pseudorange << ", mean = " << error_mean_pseudorange + << ", stdev = " << sqrt(error_var_pseudorange) + << " (max,min) = " << max_error_pseudorange + << "," << min_error_pseudorange + << " [meters]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Pseudorange error [m]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Pseudorange error [m]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err_pseudorange.colptr(0), err_pseudorange.colptr(0) + err_pseudorange.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Pseudorrange error"); + g3.set_legend(); + g3.savetops(data_title + "duplicated_satellite_pseudorrange_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(rmse_pseudorange, 3.0); + EXPECT_LT(error_mean_pseudorange, 1.0); + EXPECT_GT(error_mean_pseudorange, -1.0); + EXPECT_LT(error_var_pseudorange, 10.0); + EXPECT_LT(max_error_pseudorange, 10.0); + EXPECT_GT(min_error_pseudorange, -10.0); +} + +bool HybridObservablesTest::save_mat_xy(std::vector& x, std::vector& y, std::string filename) +{ + try + { + // WRITE MAT FILE + mat_t* matfp; + matvar_t* matvar; + filename.append(".mat"); + std::cout << "save_mat_xy write " << filename << std::endl; + matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT5); + if (reinterpret_cast(matfp) != NULL) + { + size_t dims[2] = {1, x.size()}; + matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + else + { + std::cout << "save_mat_xy: error creating file" << std::endl; + } + Mat_Close(matfp); + return true; + } + catch (const std::exception& ex) + { + std::cout << "save_mat_xy: " << ex.what() << std::endl; + return false; + } +} + +void HybridObservablesTest::check_results_code_pseudorange( + arma::mat& true_ch0, + arma::mat& true_ch1, + arma::vec& true_tow_ch0_s, + arma::vec& true_tow_ch1_s, + arma::mat& measured_ch0, + arma::mat& measured_ch1, + std::string data_title) +{ + //1. True value interpolation to match the measurement times + + double t0 = std::max(measured_ch0(0, 0), measured_ch1(0, 0)); + int size1 = measured_ch0.col(0).n_rows; + int size2 = measured_ch1.col(0).n_rows; + double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); + + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + + + arma::vec true_ch0_dist_interp; + arma::vec true_ch1_dist_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(1), t, true_ch0_dist_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(1), t, true_ch1_dist_interp); + + arma::vec meas_ch0_dist_interp; + arma::vec meas_ch1_dist_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(4), t, meas_ch0_dist_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(4), t, meas_ch1_dist_interp); + + // generate delta pseudoranges + arma::vec delta_true_dist_m = true_ch0_dist_interp - true_ch1_dist_interp; + arma::vec delta_measured_dist_m = meas_ch0_dist_interp - meas_ch1_dist_interp; + + //2. RMSE + arma::vec err; + + err = delta_measured_dist_m - delta_true_dist_m; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Pseudorange RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [meters]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Pseudorange error [m]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Pseudorange error [m]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Pseudorrange error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_pseudorrange_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(rmse, 3.0); + ASSERT_LT(error_mean, 1.0); + ASSERT_GT(error_mean, -1.0); + ASSERT_LT(error_var, 10.0); + ASSERT_LT(max_error, 10.0); + ASSERT_GT(min_error, -10.0); +} + +bool HybridObservablesTest::ReadRinexObs(std::vector* obs_vec, Gnss_Synchro gnss) +{ + // Open and read reference RINEX observables file + try + { + gpstk::Rinex3ObsStream r_ref(FLAGS_filename_rinex_obs); + r_ref.exceptions(std::ios::failbit); + gpstk::Rinex3ObsData r_ref_data; + gpstk::Rinex3ObsHeader r_ref_header; + + gpstk::RinexDatum dataobj; + + r_ref >> r_ref_header; + + std::vector first_row; + gpstk::SatID prn; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + first_row.push_back(true); + obs_vec->push_back(arma::zeros(1, 4)); + } + while (r_ref >> r_ref_data) + { + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + int myprn = gnss_synchro_vec.at(n).PRN; + + switch (gnss.System) + { + case 'G': + prn = gpstk::SatID(myprn, gpstk::SatID::systemGPS); + break; + case 'E': + prn = gpstk::SatID(myprn, gpstk::SatID::systemGalileo); + break; + default: + prn = gpstk::SatID(myprn, gpstk::SatID::systemGPS); + } + + gpstk::CommonTime time = r_ref_data.time; + double sow(static_cast(time).sow); + + gpstk::Rinex3ObsData::DataMap::iterator pointer = r_ref_data.obs.find(prn); + if (pointer == r_ref_data.obs.end()) + { + // PRN not present; do nothing + } + else + { + if (first_row.at(n) == false) + { + //insert next column + obs_vec->at(n).insert_rows(obs_vec->at(n).n_rows, 1); + } + else + { + first_row.at(n) = false; + } + if (strcmp("1C\0", gnss.Signal) == 0) + { + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 0) = sow; + dataobj = r_ref_data.getObs(prn, "C1C", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; //C1C P1 (psudorange L1) + dataobj = r_ref_data.getObs(prn, "D1C", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; //D1C Carrier Doppler + dataobj = r_ref_data.getObs(prn, "L1C", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; //L1C Carrier Phase + } + else if (strcmp("1B\0", gnss.Signal) == 0) + { + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 0) = sow; + dataobj = r_ref_data.getObs(prn, "C1B", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "D1B", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "L1B", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; + } + else if (strcmp("2S\0", gnss.Signal) == 0) //L2M + { + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 0) = sow; + dataobj = r_ref_data.getObs(prn, "C2S", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "D2S", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "L2S", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; + } + else if (strcmp("L5\0", gnss.Signal) == 0) + { + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 0) = sow; + dataobj = r_ref_data.getObs(prn, "C5I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "D5I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "L5I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; + } + else if (strcmp("5X\0", gnss.Signal) == 0) //Simulator gives RINEX with E5a+E5b. Doppler and accumulated Carrier phase WILL differ + { + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 0) = sow; + dataobj = r_ref_data.getObs(prn, "C8I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "D8I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; + dataobj = r_ref_data.getObs(prn, "L8I", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; + } + else + { + std::cout << "ReadRinexObs unknown signal requested: " << gnss.Signal << std::endl; + return false; + } + } + } + } // end while + } // End of 'try' block + catch (const gpstk::FFStreamError& e) + { + std::cout << e; + return false; + } + catch (const gpstk::Exception& e) + { + std::cout << e; + return false; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what(); + std::cout << "unknown error. I don't feel so well..." << std::endl; + return false; + } + std::cout << "ReadRinexObs info:" << std::endl; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + std::cout << "SAT PRN " << gnss_synchro_vec.at(n).PRN << " RINEX epoch readed: " << obs_vec->at(n).n_rows << std::endl; + } + return true; +} +TEST_F(HybridObservablesTest, ValidationOfResults) +{ + // Configure the signal generator + configure_generator(); + + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + + // use generator or use an external capture file + if (FLAGS_enable_external_signal_file) + { + //create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + ASSERT_EQ(acquire_signal(), true); + } + else + { + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + + std::istringstream ss(FLAGS_test_satellite_PRN_list); + std::string token; + + while (std::getline(ss, token, ',')) + { + tmp_gnss_synchro.PRN = boost::lexical_cast(token); + gnss_synchro_vec.push_back(tmp_gnss_synchro); + } + } + + + configure_receiver(FLAGS_PLL_bw_hz_start, + FLAGS_DLL_bw_hz_start, + FLAGS_PLL_narrow_bw_hz, + FLAGS_DLL_narrow_bw_hz, + FLAGS_extend_correlation_symbols, + FLAGS_smoother_length, + FLAGS_high_dyn); + + + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + //setup the signal synchronization, simulating an acquisition + if (!FLAGS_enable_external_signal_file) + { + //based on true observables metadata (for custom sdr generator) + //open true observables log file written by the simulator or based on provided RINEX obs + std::vector> true_reader_vec; + //read true data from the generator logs + true_reader_vec.push_back(std::make_shared()); + std::cout << "Loading true observable data for PRN " << gnss_synchro_vec.at(n).PRN << std::endl; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(gnss_synchro_vec.at(n).PRN)); + true_obs_file.append(".dat"); + ASSERT_NO_THROW({ + if (true_reader_vec.back()->open_obs_file(true_obs_file) == false) + { + throw std::exception(); + }; + }) << "Failure opening true observables file"; + + // load acquisition data based on the first epoch of the true observations + ASSERT_NO_THROW({ + if (true_reader_vec.back()->read_binary_obs() == false) + { + throw std::exception(); + }; + }) << "Failure reading true observables file"; + + //restart the epoch counter + true_reader_vec.back()->restart(); + + std::cout << "Initial Doppler [Hz]=" << true_reader_vec.back()->doppler_l1_hz << " Initial code delay [Chips]=" + << true_reader_vec.back()->prn_delay_chips << std::endl; + gnss_synchro_vec.at(n).Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_reader_vec.back()->prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD; + gnss_synchro_vec.at(n).Acq_doppler_hz = true_reader_vec.back()->doppler_l1_hz; + gnss_synchro_vec.at(n).Acq_samplestamp_samples = 0; + } + else + { + //based on the signal acquisition process + std::cout << "Estimated Initial Doppler " << gnss_synchro_vec.at(n).Acq_doppler_hz + << " [Hz], estimated Initial code delay " << gnss_synchro_vec.at(n).Acq_delay_samples << " [Samples]" + << " Acquisition SampleStamp is " << gnss_synchro_vec.at(n).Acq_samplestamp_samples << std::endl; + gnss_synchro_vec.at(n).Acq_samplestamp_samples = 0; + } + } + + std::vector> tracking_ch_vec; + std::vector> tlm_ch_vec; + + std::vector null_sink_vec; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + //set channels ids + gnss_synchro_vec.at(n).Channel_ID = n; + + //create the tracking channels and create the telemetry decoders + + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", config->property("Tracking.implementation", std::string("undefined")), 1, 1); + tracking_ch_vec.push_back(std::dynamic_pointer_cast(trk_)); + std::shared_ptr tlm_ = factory->GetBlock(config, "TelemetryDecoder", config->property("TelemetryDecoder.implementation", std::string("undefined")), 1, 1); + tlm_ch_vec.push_back(std::dynamic_pointer_cast(tlm_)); + + //create null sinks for observables output + null_sink_vec.push_back(gr::blocks::null_sink::make(sizeof(Gnss_Synchro))); + + ASSERT_NO_THROW({ + tlm_ch_vec.back()->set_channel(gnss_synchro_vec.at(n).Channel_ID); + + switch (gnss_synchro_master.System) + { + case 'G': + tlm_ch_vec.back()->set_satellite(Gnss_Satellite(std::string("GPS"), gnss_synchro_vec.at(n).PRN)); + break; + case 'E': + tlm_ch_vec.back()->set_satellite(Gnss_Satellite(std::string("Galileo"), gnss_synchro_vec.at(n).PRN)); + break; + default: + tlm_ch_vec.back()->set_satellite(Gnss_Satellite(std::string("GPS"), gnss_synchro_vec.at(n).PRN)); + } + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking_ch_vec.back()->set_channel(gnss_synchro_vec.at(n).Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking_ch_vec.back()->set_gnss_synchro(&gnss_synchro_vec.at(n)); + }) << "Failure setting gnss_synchro."; + } + + top_block = gr::make_top_block("Telemetry_Decoder test"); + boost::shared_ptr dummy_msg_rx_trk = HybridObservablesTest_msg_rx_make(); + boost::shared_ptr dummy_tlm_msg_rx = HybridObservablesTest_tlm_msg_rx_make(); + //Observables + std::shared_ptr observables(new HybridObservables(config.get(), "Observables", tracking_ch_vec.size() + 1, tracking_ch_vec.size())); + + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + ASSERT_NO_THROW({ + tracking_ch_vec.at(n)->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + } + + + ASSERT_NO_THROW({ + std::string file; + if (!FLAGS_enable_external_signal_file) + { + file = "./" + filename_raw_data; + } + else + { + file = FLAGS_signal_file; + } + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + int observable_interval_ms = 20; + gnss_sdr_sample_counter_sptr samp_counter = gnss_sdr_make_sample_counter(static_cast(baseband_sampling_freq), observable_interval_ms, sizeof(gr_complex)); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, samp_counter, 0); + + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + top_block->connect(gr_interleaved_char_to_complex, 0, tracking_ch_vec.at(n)->get_left_block(), 0); + top_block->connect(tracking_ch_vec.at(n)->get_right_block(), 0, tlm_ch_vec.at(n)->get_left_block(), 0); + top_block->connect(tlm_ch_vec.at(n)->get_right_block(), 0, observables->get_left_block(), n); + top_block->msg_connect(tracking_ch_vec.at(n)->get_right_block(), pmt::mp("events"), dummy_msg_rx_trk, pmt::mp("events")); + top_block->connect(observables->get_right_block(), n, null_sink_vec.at(n), 0); + } + //connect sample counter and timmer to the last channel in observables block (extra channel) + top_block->connect(samp_counter, 0, observables->get_left_block(), tracking_ch_vec.size()); + + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + }) << "Failure connecting the blocks."; + + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + tracking_ch_vec.at(n)->start_tracking(); + } + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + + //check results + // Matrices for storing columnwise true GPS time, Range, Doppler and Carrier phase + std::vector true_obs_vec; + + if (!FLAGS_enable_external_signal_file) + { + //load the true values + true_observables_reader true_observables; + ASSERT_NO_THROW({ + if (true_observables.open_obs_file(std::string("./obs_out.bin")) == false) + { + throw std::exception(); + } + }) << "Failure opening true observables file"; + + unsigned int nepoch = static_cast(true_observables.num_epochs()); + + std::cout << "True observation epochs = " << nepoch << std::endl; + + true_observables.restart(); + int64_t epoch_counter = 0; + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + true_obs_vec.push_back(arma::zeros(nepoch, 4)); + } + + ASSERT_NO_THROW({ + while (true_observables.read_binary_obs()) + { + for (unsigned int n = 0; n < true_obs_vec.size(); n++) + { + if (round(true_observables.prn[n]) != gnss_synchro_vec.at(n).PRN) + { + std::cout << "True observables SV PRN does not match measured ones: " + << round(true_observables.prn[n]) << " vs. " << gnss_synchro_vec.at(n).PRN << std::endl; + throw std::exception(); + } + true_obs_vec.at(n)(epoch_counter, 0) = true_observables.gps_time_sec[n]; + true_obs_vec.at(n)(epoch_counter, 1) = true_observables.dist_m[n]; + true_obs_vec.at(n)(epoch_counter, 2) = true_observables.doppler_l1_hz[n]; + true_obs_vec.at(n)(epoch_counter, 3) = true_observables.acc_carrier_phase_l1_cycles[n]; + } + epoch_counter++; + } + }); + } + else + { + if (!FLAGS_duplicated_satellites_test) + { + ASSERT_EQ(ReadRinexObs(&true_obs_vec, gnss_synchro_master), true) + << "Failure reading RINEX file"; + } + } + //read measured values + observables_dump_reader estimated_observables(tracking_ch_vec.size()); + ASSERT_NO_THROW({ + if (estimated_observables.open_obs_file(std::string("./observables.dat")) == false) + { + throw std::exception(); + } + }) << "Failure opening dump observables file"; + + unsigned int nepoch = static_cast(estimated_observables.num_epochs()); + std::cout << "Measured observations epochs = " << nepoch << std::endl; + + // Matrices for storing columnwise measured RX_time, TOW, Doppler, Carrier phase and Pseudorange + std::vector measured_obs_vec; + std::vector epoch_counters_vec; + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + measured_obs_vec.push_back(arma::zeros(nepoch, 5)); + epoch_counters_vec.push_back(0); + } + + estimated_observables.restart(); + while (estimated_observables.read_binary_obs()) + { + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + if (static_cast(estimated_observables.valid[n])) + { + measured_obs_vec.at(n)(epoch_counters_vec.at(n), 0) = estimated_observables.RX_time[n]; + measured_obs_vec.at(n)(epoch_counters_vec.at(n), 1) = estimated_observables.TOW_at_current_symbol_s[n]; + measured_obs_vec.at(n)(epoch_counters_vec.at(n), 2) = estimated_observables.Carrier_Doppler_hz[n]; + measured_obs_vec.at(n)(epoch_counters_vec.at(n), 3) = estimated_observables.Acc_carrier_phase_hz[n]; + measured_obs_vec.at(n)(epoch_counters_vec.at(n), 4) = estimated_observables.Pseudorange_m[n]; + epoch_counters_vec.at(n)++; + } + } + } + + //Cut measurement tail zeros + arma::uvec index; + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + index = arma::find(measured_obs_vec.at(n).col(0) > 0.0, 1, "last"); + if ((index.size() > 0) and index(0) < (nepoch - 1)) + { + measured_obs_vec.at(n).shed_rows(index(0) + 1, nepoch - 1); + } + } + + //Cut measurement initial transitory of the measurements + double initial_transitory_s = FLAGS_skip_obs_transitory_s; + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + index = arma::find(measured_obs_vec.at(n).col(0) >= (measured_obs_vec.at(n)(0, 0) + initial_transitory_s), 1, "first"); + if ((index.size() > 0) and (index(0) > 0)) + { + measured_obs_vec.at(n).shed_rows(0, index(0)); + } + + if (!FLAGS_duplicated_satellites_test) + { + index = arma::find(measured_obs_vec.at(n).col(0) >= true_obs_vec.at(n)(0, 0), 1, "first"); + if ((index.size() > 0) and (index(0) > 0)) + { + measured_obs_vec.at(n).shed_rows(0, index(0)); + } + } + } + + + if (FLAGS_duplicated_satellites_test) + { + //special test mode for duplicated satellites + std::vector prn_pairs; + std::stringstream ss(FLAGS_duplicated_satellites_prns); + unsigned int i; + while (ss >> i) + { + prn_pairs.push_back(i); + if (ss.peek() == ',') + ss.ignore(); + } + + if (prn_pairs.size() % 2 != 0) + { + std::cout << "Test settings error: duplicated_satellites_prns are even\n"; + } + else + { + for (unsigned int n = 0; n < prn_pairs.size(); n = n + 2) + { + int sat1_ch_id = -1; + int sat2_ch_id = -1; + for (unsigned int ch = 0; ch < measured_obs_vec.size(); ch++) + { + if (epoch_counters_vec.at(ch) > 10) //discard non-valid channels + { + if (gnss_synchro_vec.at(ch).PRN == prn_pairs.at(n)) + { + sat1_ch_id = ch; + } + if (gnss_synchro_vec.at(ch).PRN == prn_pairs.at(n + 1)) + { + sat2_ch_id = ch; + } + } + } + if (sat1_ch_id != -1 and sat2_ch_id != -1) + { + //compute single differences for the duplicated satellite + + check_results_duplicated_satellite( + measured_obs_vec.at(sat1_ch_id), + measured_obs_vec.at(sat2_ch_id), + sat1_ch_id, + "Duplicated sat [CH " + std::to_string(sat1_ch_id) + "," + std::to_string(sat2_ch_id) + "] PRNs " + std::to_string(gnss_synchro_vec.at(sat1_ch_id).PRN) + "," + std::to_string(gnss_synchro_vec.at(sat2_ch_id).PRN) + " "); + } + else + { + std::cout << "Satellites PRNs " << prn_pairs.at(n) << "and " << prn_pairs.at(n) << " not found\n"; + } + } + } + } + else + { + //normal mode + + //Correct the clock error using true values (it is not possible for a receiver to correct + //the receiver clock offset error at the observables level because it is required the + //decoding of the ephemeris data and solve the PVT equations) + + //Find the reference satellite (the nearest) and compute the receiver time offset at observable level + double min_pr = std::numeric_limits::max(); + unsigned int min_pr_ch_id = 0; + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + if (epoch_counters_vec.at(n) > 10) //discard non-valid channels + { + { + if (measured_obs_vec.at(n)(0, 4) < min_pr) + { + min_pr = measured_obs_vec.at(n)(0, 4); + min_pr_ch_id = n; + } + } + } + else + { + std::cout << "PRN " << gnss_synchro_vec.at(n).PRN << " has NO observations!\n"; + } + } + + arma::vec receiver_time_offset_ref_channel_s; + receiver_time_offset_ref_channel_s = (true_obs_vec.at(min_pr_ch_id).col(1)(0) - measured_obs_vec.at(min_pr_ch_id).col(4)(0)) / GPS_C_m_s; + std::cout << "Ref. channel initial Receiver time offset " << receiver_time_offset_ref_channel_s(0) * 1e3 << " [ms]" << std::endl; + + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + //debug save to .mat + std::vector tmp_vector_x(true_obs_vec.at(n).col(0).colptr(0), + true_obs_vec.at(n).col(0).colptr(0) + true_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y(true_obs_vec.at(n).col(1).colptr(0), + true_obs_vec.at(n).col(1).colptr(0) + true_obs_vec.at(n).col(1).n_rows); + save_mat_xy(tmp_vector_x, tmp_vector_y, std::string("true_pr_ch_" + std::to_string(n))); + + std::vector tmp_vector_x2(measured_obs_vec.at(n).col(0).colptr(0), + measured_obs_vec.at(n).col(0).colptr(0) + measured_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y2(measured_obs_vec.at(n).col(4).colptr(0), + measured_obs_vec.at(n).col(4).colptr(0) + measured_obs_vec.at(n).col(4).n_rows); + save_mat_xy(tmp_vector_x2, tmp_vector_y2, std::string("measured_pr_ch_" + std::to_string(n))); + + std::vector tmp_vector_x3(true_obs_vec.at(n).col(0).colptr(0), + true_obs_vec.at(n).col(0).colptr(0) + true_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y3(true_obs_vec.at(n).col(2).colptr(0), + true_obs_vec.at(n).col(2).colptr(0) + true_obs_vec.at(n).col(2).n_rows); + save_mat_xy(tmp_vector_x3, tmp_vector_y3, std::string("true_doppler_ch_" + std::to_string(n))); + + std::vector tmp_vector_x4(measured_obs_vec.at(n).col(0).colptr(0), + measured_obs_vec.at(n).col(0).colptr(0) + measured_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y4(measured_obs_vec.at(n).col(2).colptr(0), + measured_obs_vec.at(n).col(2).colptr(0) + measured_obs_vec.at(n).col(2).n_rows); + save_mat_xy(tmp_vector_x4, tmp_vector_y4, std::string("measured_doppler_ch_" + std::to_string(n))); + + std::vector tmp_vector_x5(true_obs_vec.at(n).col(0).colptr(0), + true_obs_vec.at(n).col(0).colptr(0) + true_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y5(true_obs_vec.at(n).col(3).colptr(0), + true_obs_vec.at(n).col(3).colptr(0) + true_obs_vec.at(n).col(3).n_rows); + save_mat_xy(tmp_vector_x5, tmp_vector_y5, std::string("true_cp_ch_" + std::to_string(n))); + + std::vector tmp_vector_x6(measured_obs_vec.at(n).col(0).colptr(0), + measured_obs_vec.at(n).col(0).colptr(0) + measured_obs_vec.at(n).col(0).n_rows); + std::vector tmp_vector_y6(measured_obs_vec.at(n).col(3).colptr(0), + measured_obs_vec.at(n).col(3).colptr(0) + measured_obs_vec.at(n).col(3).n_rows); + save_mat_xy(tmp_vector_x6, tmp_vector_y6, std::string("measured_cp_ch_" + std::to_string(n))); + + + if (epoch_counters_vec.at(n) > 10) //discard non-valid channels + { + arma::vec true_TOW_ref_ch_s = true_obs_vec.at(min_pr_ch_id).col(0) - receiver_time_offset_ref_channel_s(0); + arma::vec true_TOW_ch_s = true_obs_vec.at(n).col(0) - receiver_time_offset_ref_channel_s(0); + //Compare measured observables + if (min_pr_ch_id != n) + { + check_results_code_pseudorange(true_obs_vec.at(n), + true_obs_vec.at(min_pr_ch_id), + true_TOW_ch_s, + true_TOW_ref_ch_s, + measured_obs_vec.at(n), + measured_obs_vec.at(min_pr_ch_id), + "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); + + //Do not compare E5a with E5 RINEX due to the Doppler frequency discrepancy caused by the different center frequencies + //E5a_fc=1176.45e6, E5b_fc=1207.14e6, E5_fc=1191.795e6; + if (strcmp("5X\0", gnss_synchro_vec.at(n).Signal) != 0 or FLAGS_compare_with_5X) + { + check_results_carrier_phase_double_diff(true_obs_vec.at(n), + true_obs_vec.at(min_pr_ch_id), + true_TOW_ch_s, + true_TOW_ref_ch_s, + measured_obs_vec.at(n), + measured_obs_vec.at(min_pr_ch_id), + "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); + + check_results_carrier_doppler_double_diff(true_obs_vec.at(n), + true_obs_vec.at(min_pr_ch_id), + true_TOW_ch_s, + true_TOW_ref_ch_s, + measured_obs_vec.at(n), + measured_obs_vec.at(min_pr_ch_id), + "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); + } + } + else + { + std::cout << "[CH " << std::to_string(n) << "] PRN " << std::to_string(gnss_synchro_vec.at(n).PRN) << " is the reference satellite" << std::endl; + } + if (FLAGS_compute_single_diffs) + { + check_results_carrier_phase(true_obs_vec.at(n), + true_TOW_ch_s, + measured_obs_vec.at(n), + "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); + check_results_carrier_doppler(true_obs_vec.at(n), + true_TOW_ch_s, + measured_obs_vec.at(n), + "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); + } + } + else + { + std::cout << "PRN " << gnss_synchro_vec.at(n).PRN << " has NO observations!\n"; + } + } + } + std::cout << "Test completed in " << elapsed_seconds.count() << " [s]" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc new file mode 100644 index 000000000..074deea05 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc @@ -0,0 +1,200 @@ +/*! + * \file nma_printer_test.cc + * \brief Implements Unit Tests for the Nmea_Printer class. + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "nmea_printer.h" +#include +#include +#include + + +class NmeaPrinterTest : public ::testing::Test +{ +protected: + NmeaPrinterTest() + { + this->conf(); + } + ~NmeaPrinterTest() + { + } + void conf(); + rtk_t rtk; +}; + +void NmeaPrinterTest::conf() +{ + snrmask_t snrmask = {{}, {{}, {}}}; + int positioning_mode = 0; // Single + int number_of_frequencies = 1; + double elevation_mask = 5; + int navigation_system = 1; // GPS + int integer_ambiguity_resolution_gps = 0; + int integer_ambiguity_resolution_glo = 0; + int integer_ambiguity_resolution_bds = 0; + int outage_reset_ambiguity = 5; + int min_lock_to_fix_ambiguity = 0; + int iono_model = 0; + int trop_model = 0; + int dynamics_model = 0; + int earth_tide = 0; + int number_filter_iter = 1; + double code_phase_error_ratio_l1 = 100.0; + double code_phase_error_ratio_l2 = 100.0; + double code_phase_error_ratio_l5 = 100.0; + double carrier_phase_error_factor_a = 0.003; + double carrier_phase_error_factor_b = 0.003; + double bias_0 = 30.0; + double iono_0 = 0.03; + double trop_0 = 0.3; + double sigma_bias = 1e-4; + double sigma_iono = 1e-3; + double sigma_trop = 1e-4; + double sigma_acch = 1e-1; + double sigma_accv = 1e-2; + double sigma_pos = 0.0; + double min_ratio_to_fix_ambiguity = 3.0; + double min_elevation_to_fix_ambiguity = 0.0; + double slip_threshold = 0.05; + double threshold_reject_innovation = 30.0; + double threshold_reject_gdop = 30.0; + int sat_PCV = 0; + int rec_PCV = 0; + int phwindup = 0; + int reject_GPS_IIA = 0; + int raim_fde = 0; + + prcopt_t rtklib_configuration_options = { + positioning_mode, /* positioning mode (PMODE_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + 0, /* solution type (0:forward,1:backward,2:combined) */ + number_of_frequencies, /* number of frequencies (1:L1, 2:L1+L2, 3:L1+L2+L5)*/ + navigation_system, /* navigation system */ + elevation_mask * D2R, /* elevation mask angle (degrees) */ + snrmask, /* snrmask_t snrmask SNR mask */ + 0, /* satellite ephemeris/clock (EPHOPT_XXX) */ + integer_ambiguity_resolution_gps, /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + integer_ambiguity_resolution_glo, /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */ + integer_ambiguity_resolution_bds, /* BeiDou AR mode (0:off,1:on) */ + outage_reset_ambiguity, /* obs outage count to reset bias */ + min_lock_to_fix_ambiguity, /* min lock count to fix ambiguity */ + 10, /* min fix count to hold ambiguity */ + 1, /* max iteration to resolve ambiguity */ + iono_model, /* ionosphere option (IONOOPT_XXX) */ + trop_model, /* troposphere option (TROPOPT_XXX) */ + dynamics_model, /* dynamics model (0:none, 1:velocity, 2:accel) */ + earth_tide, /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */ + number_filter_iter, /* number of filter iteration */ + 0, /* code smoothing window size (0:none) */ + 0, /* interpolate reference obs (for post mission) */ + 0, /* sbssat_t sbssat SBAS correction options */ + 0, /* sbsion_t sbsion[MAXBAND+1] SBAS satellite selection (0:all) */ + 0, /* rover position for fixed mode */ + 0, /* base position for relative mode */ + /* 0:pos in prcopt, 1:average of single pos, */ + /* 2:read from file, 3:rinex header, 4:rtcm pos */ + {code_phase_error_ratio_l1, code_phase_error_ratio_l2, code_phase_error_ratio_l5}, /* eratio[NFREQ] code/phase error ratio */ + {100.0, carrier_phase_error_factor_a, carrier_phase_error_factor_b, 0.0, 1.0}, /* err[5]: measurement error factor [0]:reserved, [1-3]:error factor a/b/c of phase (m) , [4]:doppler frequency (hz) */ + {bias_0, iono_0, trop_0}, /* std[3]: initial-state std [0]bias,[1]iono [2]trop*/ + {sigma_bias, sigma_iono, sigma_trop, sigma_acch, sigma_accv, sigma_pos}, /* prn[6] process-noise std */ + 5e-12, /* sclkstab: satellite clock stability (sec/sec) */ + {min_ratio_to_fix_ambiguity, 0.9999, 0.25, 0.1, 0.05, 0.0, 0.0, 0.0}, /* thresar[8]: AR validation threshold */ + min_elevation_to_fix_ambiguity, /* elevation mask of AR for rising satellite (deg) */ + 0.0, /* elevation mask to hold ambiguity (deg) */ + slip_threshold, /* slip threshold of geometry-free phase (m) */ + 30.0, /* max difference of time (sec) */ + threshold_reject_innovation, /* reject threshold of innovation (m) */ + threshold_reject_gdop, /* reject threshold of gdop */ + {}, /* double baseline[2] baseline length constraint {const,sigma} (m) */ + {}, /* double ru[3] rover position for fixed mode {x,y,z} (ecef) (m) */ + {}, /* double rb[3] base position for relative mode {x,y,z} (ecef) (m) */ + {"", ""}, /* char anttype[2][MAXANT] antenna types {rover,base} */ + {{}, {}}, /* double antdel[2][3] antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */ + {}, /* pcv_t pcvr[2] receiver antenna parameters {rov,base} */ + {}, /* unsigned char exsats[MAXSAT] excluded satellites (1:excluded, 2:included) */ + 0, /* max averaging epoches */ + 0, /* initialize by restart */ + 1, /* output single by dgps/float/fix/ppp outage */ + {"", ""}, /* char rnxopt[2][256] rinex options {rover,base} */ + {sat_PCV, rec_PCV, phwindup, reject_GPS_IIA, raim_fde}, /* posopt[6] positioning options [0]: satellite and receiver antenna PCV model; [1]: interpolate antenna parameters; [2]: apply phase wind-up correction for PPP modes; [3]: exclude measurements of GPS Block IIA satellites satellite [4]: RAIM FDE (fault detection and exclusion) [5]: handle day-boundary clock jump */ + 0, /* solution sync mode (0:off,1:on) */ + {{}, {}}, /* odisp[2][6*11] ocean tide loading parameters {rov,base} */ + {{}, {{}, {}}, {{}, {}}, {}, {}}, /* exterr_t exterr extended receiver error model */ + 0, /* disable L2-AR */ + {} /* char pppopt[256] ppp option "-GAP_RESION=" default gap to reset iono parameters (ep) */ + }; + + rtkinit(&rtk, &rtklib_configuration_options); +} + + +TEST_F(NmeaPrinterTest, PrintLine) +{ + std::string filename("nmea_test.nmea"); + std::shared_ptr pvt_solution = std::make_shared(12, "filename", false, false, rtk); + + boost::posix_time::ptime pt(boost::gregorian::date(1994, boost::date_time::Nov, 19), + boost::posix_time::hours(22) + boost::posix_time::minutes(54) + boost::posix_time::seconds(46)); + std::time_t tim = (pt - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); + gtime_t gtime; + gtime.time = tim; + gtime.sec = 0.0; + + pvt_solution->pvt_sol.rr[0] = -2282104.0; //49.27416667; + pvt_solution->pvt_sol.rr[1] = -3489369.0; //-123.18533333; + pvt_solution->pvt_sol.rr[2] = 4810507.0; // 0 + pvt_solution->pvt_sol.rr[3] = 0.0; + pvt_solution->pvt_sol.rr[4] = 0.0; + pvt_solution->pvt_sol.rr[5] = 0.0; + pvt_solution->pvt_sol.stat = 1; // SOLQ_FIX + pvt_solution->pvt_sol.time = gtime; + + bool flag_nmea_output_file = true; + ASSERT_NO_THROW({ + std::shared_ptr nmea_printer = std::make_shared(filename, flag_nmea_output_file, false, ""); + nmea_printer->Print_Nmea_Line(pvt_solution, false); + }) << "Failure printing NMEA messages."; + + std::ifstream test_file(filename); + std::string line; + std::string GPRMC("$GPRMC"); + if (test_file.is_open()) + { + while (getline(test_file, line)) + { + std::size_t found = line.find(GPRMC); + if (found != std::string::npos) + { + EXPECT_EQ(line, "$GPRMC,225436.00,A,4916.4497617,N,12311.1202744,W,0.00,0.00,191194,0.0,E,D*21\r"); + } + } + test_file.close(); + } + EXPECT_EQ(0, remove(filename.c_str())) << "Failure deleting a temporary file."; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc index dfd62d5dd..c4a559448 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,17 +23,16 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include #include "rinex_printer.h" +#include -TEST(Rinex_Printer_Test, GalileoObsHeader) +TEST(RinexPrinterTest, GalileoObsHeader) { std::string line_aux; std::string line_str; @@ -45,10 +44,10 @@ TEST(Rinex_Printer_Test, GalileoObsHeader) rp1->rinex_obs_header(rp1->obsFile, eph, 0.0); rp1->obsFile.seekp(0); - while(!rp1->obsFile.eof()) + while (!rp1->obsFile.eof()) { std::getline(rp1->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) { @@ -59,7 +58,7 @@ TEST(Rinex_Printer_Test, GalileoObsHeader) } std::string expected_str("E 4 C1B L1B D1B S1B SYS / # / OBS TYPES "); EXPECT_EQ(0, expected_str.compare(line_aux)); - if(remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; line_aux.clear(); std::shared_ptr rp2; @@ -68,10 +67,10 @@ TEST(Rinex_Printer_Test, GalileoObsHeader) rp2->rinex_obs_header(rp2->obsFile, eph, 0.0, bands); rp2->obsFile.seekp(0); no_more_finds = false; - while(!rp2->obsFile.eof()) + while (!rp2->obsFile.eof()) { std::getline(rp2->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) { @@ -83,13 +82,43 @@ TEST(Rinex_Printer_Test, GalileoObsHeader) std::string expected_str2("E 12 C1B L1B D1B S1B C5X L5X D5X S5X C7X L7X D7X S7X SYS / # / OBS TYPES "); EXPECT_EQ(0, expected_str2.compare(line_aux)); - if(remove(rp2->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp2->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } +TEST(RinexPrinterTest, GlonassObsHeader) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph = Glonass_Gnav_Ephemeris(); + + std::shared_ptr rp1; + rp1 = std::make_shared(3); + const std::string bands = "1G"; + rp1->rinex_obs_header(rp1->obsFile, eph, 0.0, bands); + rp1->obsFile.seekp(0); + + while (!rp1->obsFile.eof()) + { + std::getline(rp1->obsFile, line_str); + if (!no_more_finds) + { + if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + std::string expected_str("R 4 C1C L1C D1C S1C SYS / # / OBS TYPES "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + if (remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + line_aux.clear(); +} -TEST(Rinex_Printer_Test, MixedObsHeader) +TEST(RinexPrinterTest, MixedObsHeader) { std::string line_aux; std::string line_aux2; @@ -104,19 +133,19 @@ TEST(Rinex_Printer_Test, MixedObsHeader) rp1->obsFile.seekp(0); int systems_found = 0; - while(!rp1->obsFile.eof()) + while (!rp1->obsFile.eof()) { std::getline(rp1->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) { systems_found++; - if(systems_found == 1) + if (systems_found == 1) { line_aux = std::string(line_str); } - if(systems_found == 2) + if (systems_found == 2) { line_aux2 = std::string(line_str); no_more_finds = true; @@ -129,11 +158,55 @@ TEST(Rinex_Printer_Test, MixedObsHeader) std::string expected_str2("E 8 C1B L1B D1B S1B C5X L5X D5X S5X SYS / # / OBS TYPES "); EXPECT_EQ(0, expected_str.compare(line_aux)); EXPECT_EQ(0, expected_str2.compare(line_aux2)); - if(remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } -TEST(Rinex_Printer_Test, GalileoObsLog) +TEST(RinexPrinterTest, MixedObsHeaderGpsGlo) +{ + std::string line_aux; + std::string line_aux2; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph_glo = Glonass_Gnav_Ephemeris(); + const Gps_Ephemeris eph_gps = Gps_Ephemeris(); + + std::shared_ptr rp1; + rp1 = std::make_shared(); + rp1->rinex_obs_header(rp1->obsFile, eph_gps, eph_glo, 0.0, "1G"); + rp1->obsFile.seekp(0); + int systems_found = 0; + + while (!rp1->obsFile.eof()) + { + std::getline(rp1->obsFile, line_str); + if (!no_more_finds) + { + if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) + { + systems_found++; + if (systems_found == 1) + { + line_aux = std::string(line_str); + } + if (systems_found == 2) + { + line_aux2 = std::string(line_str); + no_more_finds = true; + } + } + } + } + + std::string expected_str("G 4 C1C L1C D1C S1C SYS / # / OBS TYPES "); + std::string expected_str2("R 4 C1C L1C D1C S1C SYS / # / OBS TYPES "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + EXPECT_EQ(0, expected_str2.compare(line_aux2)); + if (remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} + + +TEST(RinexPrinterTest, GalileoObsLog) { std::string line_aux; std::string line_str; @@ -144,7 +217,7 @@ TEST(Rinex_Printer_Test, GalileoObsLog) rp = std::make_shared(); rp->rinex_obs_header(rp->obsFile, eph, 0.0); - std::map gnss_pseudoranges_map; + std::map gnss_pseudoranges_map; Gnss_Synchro gs1 = Gnss_Synchro(); Gnss_Synchro gs2 = Gnss_Synchro(); @@ -158,6 +231,74 @@ TEST(Rinex_Printer_Test, GalileoObsLog) gs4.System = *sys.c_str(); std::string sig = "1B"; + std::memcpy(static_cast(gs1.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs2.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs3.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs4.Signal), sig.c_str(), 3); + + gs1.PRN = 3; + gs2.PRN = 8; + gs3.PRN = 10; + gs4.PRN = 22; + + gs4.Pseudorange_m = 22000000; + gs4.Carrier_phase_rads = 23.4; + gs4.Carrier_Doppler_hz = 1534; + gs4.CN0_dB_hz = 42; + + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); + + rp->log_rinex_obs(rp->obsFile, eph, 0.0, gnss_pseudoranges_map); + rp->obsFile.seekp(0); + + while (!rp->obsFile.eof()) + { + std::getline(rp->obsFile, line_str); + if (!no_more_finds) + { + if (line_str.find("E22", 0) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + + std::string expected_str("E22 22000000.000 7 3.724 7 1534.000 7 42.000 "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} + + +TEST(RinexPrinterTest, GlonassObsLog) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph = Glonass_Gnav_Ephemeris(); + + std::shared_ptr rp; + rp = std::make_shared(); + rp->rinex_obs_header(rp->obsFile, eph, 0.0); + + std::map gnss_pseudoranges_map; + + Gnss_Synchro gs1 = Gnss_Synchro(); + Gnss_Synchro gs2 = Gnss_Synchro(); + Gnss_Synchro gs3 = Gnss_Synchro(); + Gnss_Synchro gs4 = Gnss_Synchro(); + + std::string sys = "R"; + gs1.System = *sys.c_str(); + gs2.System = *sys.c_str(); + gs3.System = *sys.c_str(); + gs4.System = *sys.c_str(); + + std::string sig = "1C"; std::memcpy((void*)gs1.Signal, sig.c_str(), 3); std::memcpy((void*)gs2.Signal, sig.c_str(), 3); std::memcpy((void*)gs3.Signal, sig.c_str(), 3); @@ -173,20 +314,20 @@ TEST(Rinex_Printer_Test, GalileoObsLog) gs4.Carrier_Doppler_hz = 1534; gs4.CN0_dB_hz = 42; - gnss_pseudoranges_map.insert( std::pair(1,gs1) ); - gnss_pseudoranges_map.insert( std::pair(2,gs2) ); - gnss_pseudoranges_map.insert( std::pair(3,gs3) ); - gnss_pseudoranges_map.insert( std::pair(4,gs4) ); + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); rp->log_rinex_obs(rp->obsFile, eph, 0.0, gnss_pseudoranges_map); rp->obsFile.seekp(0); - while(!rp->obsFile.eof()) + while (!rp->obsFile.eof()) { std::getline(rp->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { - if (line_str.find("E22", 0) != std::string::npos) + if (line_str.find("R22", 0) != std::string::npos) { no_more_finds = true; line_aux = std::string(line_str); @@ -194,14 +335,14 @@ TEST(Rinex_Printer_Test, GalileoObsLog) } } - std::string expected_str("E22 22000000.000 7 3.724 7 1534.000 7 42.000 "); + std::string expected_str("R22 22000000.000 7 3.724 7 1534.000 7 42.000 "); EXPECT_EQ(0, expected_str.compare(line_aux)); - if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } -TEST(Rinex_Printer_Test, GpsObsLogDualBand) +TEST(RinexPrinterTest, GpsObsLogDualBand) { std::string line_aux; std::string line_str; @@ -213,7 +354,7 @@ TEST(Rinex_Printer_Test, GpsObsLogDualBand) rp = std::make_shared(); rp->rinex_obs_header(rp->obsFile, eph_gps, eph_cnav, 0.0); - std::map gnss_pseudoranges_map; + std::map gnss_pseudoranges_map; Gnss_Synchro gs1 = Gnss_Synchro(); Gnss_Synchro gs2 = Gnss_Synchro(); @@ -227,12 +368,12 @@ TEST(Rinex_Printer_Test, GpsObsLogDualBand) gs4.System = *sys.c_str(); std::string sig = "1C"; - std::memcpy((void*)gs1.Signal, sig.c_str(), 3); - std::memcpy((void*)gs2.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs1.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs2.Signal), sig.c_str(), 3); sig = "2S"; - std::memcpy((void*)gs3.Signal, sig.c_str(), 3); - std::memcpy((void*)gs4.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs3.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs4.Signal), sig.c_str(), 3); gs1.PRN = 3; gs2.PRN = 8; @@ -254,18 +395,18 @@ TEST(Rinex_Printer_Test, GpsObsLogDualBand) gs3.Carrier_Doppler_hz = -1534; gs3.CN0_dB_hz = 47; - gnss_pseudoranges_map.insert( std::pair(1,gs1) ); - gnss_pseudoranges_map.insert( std::pair(2,gs2) ); - gnss_pseudoranges_map.insert( std::pair(3,gs3) ); - gnss_pseudoranges_map.insert( std::pair(4,gs4) ); + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); rp->log_rinex_obs(rp->obsFile, eph_gps, eph_cnav, 0.0, gnss_pseudoranges_map); rp->obsFile.seekp(0); - while(!rp->obsFile.eof()) + while (!rp->obsFile.eof()) { std::getline(rp->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { if (line_str.find("G08", 0) != std::string::npos) { @@ -278,12 +419,11 @@ TEST(Rinex_Printer_Test, GpsObsLogDualBand) std::string expected_str("G08 22000002.100 6 7.226 6 321.000 6 39.000 22000000.000 7 3.724 7 1534.000 7 42.000"); EXPECT_EQ(0, expected_str.compare(line_aux)); - if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; - + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } -TEST(Rinex_Printer_Test, GalileoObsLogDualBand) +TEST(RinexPrinterTest, GalileoObsLogDualBand) { std::string line_aux; std::string line_str; @@ -295,7 +435,7 @@ TEST(Rinex_Printer_Test, GalileoObsLogDualBand) std::string bands("1B 5X"); rp->rinex_obs_header(rp->obsFile, eph, 0.0, bands); - std::map gnss_pseudoranges_map; + std::map gnss_pseudoranges_map; Gnss_Synchro gs1 = Gnss_Synchro(); Gnss_Synchro gs2 = Gnss_Synchro(); @@ -309,12 +449,12 @@ TEST(Rinex_Printer_Test, GalileoObsLogDualBand) gs4.System = *sys.c_str(); std::string sig = "1B"; - std::memcpy((void*)gs1.Signal, sig.c_str(), 3); - std::memcpy((void*)gs2.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs1.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs2.Signal), sig.c_str(), 3); sig = "5X"; - std::memcpy((void*)gs3.Signal, sig.c_str(), 3); - std::memcpy((void*)gs4.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gs3.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs4.Signal), sig.c_str(), 3); gs1.PRN = 3; gs2.PRN = 8; @@ -336,18 +476,18 @@ TEST(Rinex_Printer_Test, GalileoObsLogDualBand) gs4.Carrier_Doppler_hz = 1534; gs4.CN0_dB_hz = 42; - gnss_pseudoranges_map.insert( std::pair(1,gs1) ); - gnss_pseudoranges_map.insert( std::pair(2,gs2) ); - gnss_pseudoranges_map.insert( std::pair(3,gs3) ); - gnss_pseudoranges_map.insert( std::pair(4,gs4) ); + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); rp->log_rinex_obs(rp->obsFile, eph, 0.0, gnss_pseudoranges_map, bands); rp->obsFile.seekp(0); - while(!rp->obsFile.eof()) + while (!rp->obsFile.eof()) { std::getline(rp->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { if (line_str.find("E08", 0) != std::string::npos) { @@ -360,12 +500,11 @@ TEST(Rinex_Printer_Test, GalileoObsLogDualBand) std::string expected_str("E08 22000002.100 6 7.226 6 321.000 6 39.000 22000000.000 7 3.724 7 1534.000 7 42.000"); EXPECT_EQ(0, expected_str.compare(line_aux)); - if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } - -TEST(Rinex_Printer_Test, MixedObsLog) +TEST(RinexPrinterTest, MixedObsLog) { std::string line_aux; std::string line_str; @@ -377,7 +516,7 @@ TEST(Rinex_Printer_Test, MixedObsLog) rp = std::make_shared(); rp->rinex_obs_header(rp->obsFile, eph_gps, eph_gal, 0.0, "1B 5X"); - std::map gnss_pseudoranges_map; + std::map gnss_pseudoranges_map; Gnss_Synchro gs1 = Gnss_Synchro(); Gnss_Synchro gs2 = Gnss_Synchro(); @@ -400,17 +539,125 @@ TEST(Rinex_Printer_Test, MixedObsLog) gs7.System = *sys.c_str(); gs8.System = *sys.c_str(); + std::string sig = "1C"; + std::memcpy(static_cast(gs1.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs2.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs3.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs4.Signal), sig.c_str(), 3); + + sig = "5X"; + std::memcpy(static_cast(gs5.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs6.Signal), sig.c_str(), 3); + + sig = "1B"; + std::memcpy(static_cast(gs7.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gs8.Signal), sig.c_str(), 3); + + gs1.PRN = 3; + gs2.PRN = 8; + gs3.PRN = 14; + gs4.PRN = 16; + gs5.PRN = 3; + gs6.PRN = 16; + gs7.PRN = 14; + gs8.PRN = 16; + + gs2.Pseudorange_m = 22000002.1; + gs2.Carrier_phase_rads = 45.4; + gs2.Carrier_Doppler_hz = 321; + gs2.CN0_dB_hz = 39; + + gs4.Pseudorange_m = 22000000; + gs4.Carrier_phase_rads = 23.4; + gs4.Carrier_Doppler_hz = -1534; + gs4.CN0_dB_hz = 40; + + gs6.Pseudorange_m = 22000000; + gs6.Carrier_phase_rads = 52.1; + gs6.Carrier_Doppler_hz = 1534; + gs6.CN0_dB_hz = 41; + + gs8.Pseudorange_m = 22000000; + gs8.Carrier_phase_rads = 0.8; + gs8.Carrier_Doppler_hz = -20; + gs8.CN0_dB_hz = 42; + + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); + gnss_pseudoranges_map.insert(std::pair(5, gs5)); + gnss_pseudoranges_map.insert(std::pair(6, gs6)); + gnss_pseudoranges_map.insert(std::pair(7, gs7)); + gnss_pseudoranges_map.insert(std::pair(8, gs8)); + + rp->log_rinex_obs(rp->obsFile, eph_gps, eph_gal, 0.0, gnss_pseudoranges_map); + + rp->obsFile.seekp(0); + + while (!rp->obsFile.eof()) + { + std::getline(rp->obsFile, line_str); + if (!no_more_finds) + { + if (line_str.find("E16", 0) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + std::string expected_str("E16 22000000.000 7 0.127 7 -20.000 7 42.000 22000000.000 6 8.292 6 1534.000 6 41.000"); + EXPECT_EQ(0, expected_str.compare(line_aux)); + + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} + + +TEST(RinexPrinterTest, MixedObsLogGpsGlo) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph_glo = Glonass_Gnav_Ephemeris(); + const Gps_Ephemeris eph_gps = Gps_Ephemeris(); + + std::shared_ptr rp; + rp = std::make_shared(); + rp->rinex_obs_header(rp->obsFile, eph_gps, eph_glo, 0.0, "1G"); + + std::map gnss_pseudoranges_map; + + Gnss_Synchro gs1 = Gnss_Synchro(); + Gnss_Synchro gs2 = Gnss_Synchro(); + Gnss_Synchro gs3 = Gnss_Synchro(); + Gnss_Synchro gs4 = Gnss_Synchro(); + Gnss_Synchro gs5 = Gnss_Synchro(); + Gnss_Synchro gs6 = Gnss_Synchro(); + Gnss_Synchro gs7 = Gnss_Synchro(); + Gnss_Synchro gs8 = Gnss_Synchro(); + + std::string sys = "G"; + gs1.System = *sys.c_str(); + gs2.System = *sys.c_str(); + gs3.System = *sys.c_str(); + gs4.System = *sys.c_str(); + + sys = "R"; + gs5.System = *sys.c_str(); + gs6.System = *sys.c_str(); + gs7.System = *sys.c_str(); + gs8.System = *sys.c_str(); + std::string sig = "1C"; std::memcpy((void*)gs1.Signal, sig.c_str(), 3); std::memcpy((void*)gs2.Signal, sig.c_str(), 3); std::memcpy((void*)gs3.Signal, sig.c_str(), 3); std::memcpy((void*)gs4.Signal, sig.c_str(), 3); - sig = "5X"; + sig = "1G"; std::memcpy((void*)gs5.Signal, sig.c_str(), 3); std::memcpy((void*)gs6.Signal, sig.c_str(), 3); - - sig = "1B"; std::memcpy((void*)gs7.Signal, sig.c_str(), 3); std::memcpy((void*)gs8.Signal, sig.c_str(), 3); @@ -443,33 +690,34 @@ TEST(Rinex_Printer_Test, MixedObsLog) gs8.Carrier_Doppler_hz = -20; gs8.CN0_dB_hz = 42; - gnss_pseudoranges_map.insert( std::pair(1,gs1) ); - gnss_pseudoranges_map.insert( std::pair(2,gs2) ); - gnss_pseudoranges_map.insert( std::pair(3,gs3) ); - gnss_pseudoranges_map.insert( std::pair(4,gs4) ); - gnss_pseudoranges_map.insert( std::pair(5,gs5) ); - gnss_pseudoranges_map.insert( std::pair(6,gs6) ); - gnss_pseudoranges_map.insert( std::pair(7,gs7) ); - gnss_pseudoranges_map.insert( std::pair(8,gs8) ); + gnss_pseudoranges_map.insert(std::pair(1, gs1)); + gnss_pseudoranges_map.insert(std::pair(2, gs2)); + gnss_pseudoranges_map.insert(std::pair(3, gs3)); + gnss_pseudoranges_map.insert(std::pair(4, gs4)); + gnss_pseudoranges_map.insert(std::pair(5, gs5)); + gnss_pseudoranges_map.insert(std::pair(6, gs6)); + gnss_pseudoranges_map.insert(std::pair(7, gs7)); + gnss_pseudoranges_map.insert(std::pair(8, gs8)); - rp->log_rinex_obs(rp->obsFile, eph_gps, eph_gal, 0.0, gnss_pseudoranges_map); + rp->log_rinex_obs(rp->obsFile, eph_gps, eph_glo, 0.0, gnss_pseudoranges_map); rp->obsFile.seekp(0); - while(!rp->obsFile.eof()) + while (!rp->obsFile.eof()) { std::getline(rp->obsFile, line_str); - if(!no_more_finds) + if (!no_more_finds) { - if (line_str.find("E16", 0) != std::string::npos) + if (line_str.find("R16", 0) != std::string::npos) { no_more_finds = true; line_aux = std::string(line_str); } } } - std::string expected_str("E16 22000000.000 7 0.127 7 -20.000 7 42.000 22000000.000 6 8.292 6 1534.000 6 41.000"); + + std::string expected_str("R16 22000000.000 6 8.292 6 1534.000 6 41.000 22000000.000 7 0.127 7 -20.000 7 42.000"); EXPECT_EQ(0, expected_str.compare(line_aux)); - if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + if (remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc index 268c05630..a1e52190d 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc @@ -5,7 +5,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -23,71 +23,53 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -//#include -//#include -#include -//#include -//#include + #include "rtcm_printer.h" -//#include "gps_ephemeris.h" +#include -TEST(Rtcm_Printer_Test, Instantiate) +TEST(RtcmPrinterTest, Instantiate) { std::string filename = "hello.rtcm"; bool flag_rtcm_tty_port = false; std::string rtcm_dump_devname = "/dev/pts/4"; bool flag_rtcm_server = false; + bool rtcm_file_output_enabled = false; unsigned short rtcm_tcp_port = 2101; unsigned short rtcm_station_id = 1234; - std::unique_ptr RTCM_printer(new Rtcm_Printer(filename, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_dump_devname)); + std::unique_ptr RTCM_printer(new Rtcm_Printer(filename, rtcm_file_output_enabled, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_dump_devname)); } -TEST(Rtcm_Printer_Test, Run) +TEST(RtcmPrinterTest, Run) { - // std::string file_name = "./gps_ephemeris_rx.xml"; - // std::map gps_ephemeris_map; - // try - // { - // std::ifstream ifs(file_name.c_str(), std::ifstream::binary | std::ifstream::in); - // boost::archive::xml_iarchive xml(ifs); - // gps_ephemeris_map.clear(); - // xml >> boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", gps_ephemeris_map); - // ifs.close(); - // } - // catch (std::exception& e) - // { - // //LOG(WARNING) << e.what() << "File: " << file_name; - // //std::cout << "File not found" << std::endl; - // } - std::string filename = "test.rtcm"; bool flag_rtcm_tty_port = false; + bool rtcm_file_output_enabled = false; std::string rtcm_dump_devname = "/dev/pts/4"; bool flag_rtcm_server = false; unsigned short rtcm_tcp_port = 2101; unsigned short rtcm_station_id = 1234; - std::unique_ptr RTCM_printer(new Rtcm_Printer(filename, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_dump_devname)); + std::unique_ptr RTCM_printer(new Rtcm_Printer(filename, rtcm_file_output_enabled, flag_rtcm_server, flag_rtcm_tty_port, rtcm_tcp_port, rtcm_station_id, rtcm_dump_devname)); std::string reference_msg = "D300133ED7D30202980EDEEF34B4BD62AC0941986F33360B98"; /* Convert the reference message to binary data */ std::string reference_msg_binary; unsigned char c[1]; - for(unsigned int i = 0; i < reference_msg.length(); i = i + 2) + for (unsigned int i = 0; i < reference_msg.length(); i = i + 2) { - unsigned long int n, n2; - std::istringstream(reference_msg.substr(i,1)) >> std::hex >> n; + uint64_t n, n2; + std::istringstream(reference_msg.substr(i, 1)) >> std::hex >> n; std::istringstream(reference_msg.substr(i + 1, 1)) >> std::hex >> n2; - c[0] = static_cast(n * 16) + static_cast(n2); - std::string ret(c, c+1); + c[0] = static_cast(n * 16) + static_cast(n2); + std::string ret(c, c + 1); reference_msg_binary += ret; } @@ -95,6 +77,3 @@ TEST(Rtcm_Printer_Test, Run) EXPECT_EQ(0, reference_msg_binary.compare(testing_msg)); } - - - diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc index 0680dbfc7..cd8771880 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,17 +24,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ +#include "Galileo_E1.h" +#include "rtcm.h" #include #include -#include "rtcm.h" -#include "Galileo_E1.h" -TEST(Rtcm_Test, Hex_to_bin) +TEST(RtcmTest, HexToBin) { auto rtcm = std::make_shared(); @@ -64,7 +64,7 @@ TEST(Rtcm_Test, Hex_to_bin) } -TEST(Rtcm_Test, Bin_to_hex) +TEST(RtcmTest, BinToHex) { auto rtcm = std::make_shared(); @@ -98,33 +98,32 @@ TEST(Rtcm_Test, Bin_to_hex) } - -TEST(Rtcm_Test, Hex_to_int) +TEST(RtcmTest, HexToInt) { auto rtcm = std::make_shared(); std::string test1 = "2A"; - long int test1_int = rtcm->hex_to_int(test1); - long int expected1 = 42; + int64_t test1_int = rtcm->hex_to_int(test1); + int64_t expected1 = 42; EXPECT_EQ(expected1, test1_int); } -TEST(Rtcm_Test, Hex_to_uint) +TEST(RtcmTest, HexToUint) { auto rtcm = std::make_shared(); - long unsigned int expected1 = 42; - EXPECT_EQ(expected1, rtcm->hex_to_uint(rtcm->bin_to_hex("00101010"))); + uint64_t expected1 = 42; + EXPECT_EQ(expected1, rtcm->hex_to_uint(rtcm->bin_to_hex("00101010"))); } -TEST(Rtcm_Test, Bin_to_double) +TEST(RtcmTest, BinToDouble) { auto rtcm = std::make_shared(); std::bitset<4> test1(5); - long int test1_int = static_cast(rtcm->bin_to_double(test1.to_string())); - long int expected1 = 5; + int64_t test1_int = static_cast(rtcm->bin_to_double(test1.to_string())); + int64_t expected1 = 5; EXPECT_EQ(expected1, test1_int); std::bitset<4> test2(-5); @@ -135,33 +134,33 @@ TEST(Rtcm_Test, Bin_to_double) } -TEST(Rtcm_Test, Bin_to_uint) +TEST(RtcmTest, BinToUint) { auto rtcm = std::make_shared(); - long unsigned int expected1 = 42; + uint32_t expected1 = 42; EXPECT_EQ(expected1, rtcm->bin_to_uint("00101010")); - long unsigned int expected2 = 214; + uint32_t expected2 = 214; EXPECT_EQ(expected2, rtcm->bin_to_uint("11010110")); } -TEST(Rtcm_Test, Bin_to_int) +TEST(RtcmTest, BinToInt) { auto rtcm = std::make_shared(); - long unsigned int expected1 = 42; + int32_t expected1 = 42; EXPECT_EQ(expected1, rtcm->bin_to_int("00101010")); - long unsigned int expected2 = -42; + int32_t expected2 = -42; EXPECT_EQ(expected2, rtcm->bin_to_int("11010110")); } -TEST(Rtcm_Test, Bin_to_binary_data) +TEST(RtcmTest, BinToBinaryData) { auto rtcm = std::make_shared(); std::string bin_str("1101101011010110"); std::string data_str = rtcm->bin_to_binary_data(bin_str); - std::string test_binary = data_str.substr(0,1); + std::string test_binary = data_str.substr(0, 1); std::string test_bin = rtcm->binary_data_to_bin(test_binary); std::string test_hex = rtcm->bin_to_hex(test_bin); EXPECT_EQ(0, test_hex.compare("DA")); @@ -171,7 +170,7 @@ TEST(Rtcm_Test, Bin_to_binary_data) } -TEST(Rtcm_Test, Check_CRC) +TEST(RtcmTest, CheckCRC) { auto rtcm = std::make_shared(); bool expected_true = true; @@ -186,7 +185,7 @@ TEST(Rtcm_Test, Check_CRC) } -TEST(Rtcm_Test, MT1001) +TEST(RtcmTest, MT1001) { auto rtcm = std::make_shared(); Gps_Ephemeris gps_eph = Gps_Ephemeris(); @@ -198,7 +197,7 @@ TEST(Rtcm_Test, MT1001) std::string sig = "1C"; gnss_synchro.System = *sys.c_str(); - std::memcpy((void*)gnss_synchro.Signal, sig.c_str(), 3); + std::memcpy(static_cast(gnss_synchro.Signal), sig.c_str(), 3); gnss_synchro.Pseudorange_m = 20000000.0; double obs_time = 25.0; std::map pseudoranges; @@ -209,7 +208,7 @@ TEST(Rtcm_Test, MT1001) } -TEST(Rtcm_Test, MT1005) +TEST(RtcmTest, MT1005) { auto rtcm = std::make_shared(); std::string reference_msg = rtcm->print_MT1005_test(); @@ -232,7 +231,7 @@ TEST(Rtcm_Test, MT1005) EXPECT_EQ(expected_false, glonass); EXPECT_EQ(expected_false, galileo); - EXPECT_EQ(2003, ref_id); + EXPECT_EQ(static_cast(2003), ref_id); EXPECT_DOUBLE_EQ(1114104.5999, ecef_x); EXPECT_DOUBLE_EQ(-4850729.7108, ecef_y); EXPECT_DOUBLE_EQ(3975521.4643, ecef_z); @@ -246,15 +245,14 @@ TEST(Rtcm_Test, MT1005) EXPECT_EQ(expected_false, glonass); EXPECT_EQ(expected_false, galileo); - EXPECT_EQ(2003, ref_id); + EXPECT_EQ(static_cast(2003), ref_id); EXPECT_DOUBLE_EQ(1114104.5999, ecef_x); EXPECT_DOUBLE_EQ(-4850729.7108, ecef_y); EXPECT_DOUBLE_EQ(3975521.4643, ecef_z); } - -TEST(Rtcm_Test, MT1019) +TEST(RtcmTest, MT1019) { auto rtcm = std::make_shared(); bool expected_true = true; @@ -269,22 +267,56 @@ TEST(Rtcm_Test, MT1019) std::string tx_msg = rtcm->print_MT1019(gps_eph); EXPECT_EQ(0, rtcm->read_MT1019(tx_msg, gps_eph_read)); - EXPECT_EQ(3, gps_eph_read.i_satellite_PRN); + EXPECT_EQ(static_cast(3), gps_eph_read.i_satellite_PRN); EXPECT_DOUBLE_EQ(4, gps_eph_read.d_IODC); - EXPECT_DOUBLE_EQ( 2.0 * E_LSB, gps_eph_read.d_e_eccentricity); + EXPECT_DOUBLE_EQ(2.0 * E_LSB, gps_eph_read.d_e_eccentricity); EXPECT_EQ(expected_true, gps_eph_read.b_fit_interval_flag); EXPECT_EQ(1, rtcm->read_MT1019(rtcm->bin_to_binary_data(rtcm->hex_to_bin("FFFFFFFFFFF")), gps_eph_read)); } -TEST(Rtcm_Test, MT1029) +TEST(RtcmTest, MT1020) +{ + auto rtcm = std::make_shared(); + + // Objects to populate the ephemeris and utc fields + Glonass_Gnav_Ephemeris gnav_ephemeris = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model gnav_utc_model = Glonass_Gnav_Utc_Model(); + // Objects read, used for comparison + Glonass_Gnav_Ephemeris gnav_ephemeris_read = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model gnav_utc_model_read = Glonass_Gnav_Utc_Model(); + + // Perform data read and print of special values types + gnav_ephemeris.d_P_1 = 15; + // Bit distribution per fields + gnav_ephemeris.d_t_k = 7560; + // Glonass signed values + gnav_ephemeris.d_VXn = -0.490900039672852; + // Bit distribution per fields dependent on other factors + gnav_ephemeris.d_t_b = 8100; + // Binary flag representation + gnav_ephemeris.d_P_3 = 1; + + std::string tx_msg = rtcm->print_MT1020(gnav_ephemeris, gnav_utc_model); + + EXPECT_EQ(0, rtcm->read_MT1020(tx_msg, gnav_ephemeris_read, gnav_utc_model_read)); + EXPECT_EQ(gnav_ephemeris.d_P_1, gnav_ephemeris_read.d_P_1); + EXPECT_TRUE(gnav_ephemeris.d_t_b - gnav_ephemeris_read.d_t_b < FLT_EPSILON); + EXPECT_TRUE(gnav_ephemeris.d_VXn - gnav_ephemeris_read.d_VXn < FLT_EPSILON); + EXPECT_TRUE(gnav_ephemeris.d_t_k - gnav_ephemeris.d_t_k < FLT_EPSILON); + EXPECT_EQ(gnav_ephemeris.d_P_3, gnav_ephemeris_read.d_P_3); + EXPECT_EQ(1, rtcm->read_MT1020(rtcm->bin_to_binary_data(rtcm->hex_to_bin("FFFFFFFFFFF")), gnav_ephemeris_read, gnav_utc_model_read)); +} + + +TEST(RtcmTest, MT1029) { auto rtcm = std::make_shared(); std::string s_test("UTF-8 проверка wörter"); unsigned int ref_id = 23; double obs_time = 0; Gps_Ephemeris gps_eph = Gps_Ephemeris(); - std::string m1029 = rtcm->bin_to_hex(rtcm->binary_data_to_bin(rtcm->print_MT1029(ref_id, gps_eph, obs_time, s_test))); + std::string m1029 = rtcm->bin_to_hex(rtcm->binary_data_to_bin(rtcm->print_MT1029(ref_id, gps_eph, obs_time, s_test))); std::string encoded_text = m1029.substr(24, 60); std::string expected_encoded_text("5554462D3820D0BFD180D0BED0B2D0B5D180D0BAD0B02077C3B672746572"); EXPECT_EQ(0, expected_encoded_text.compare(encoded_text)); @@ -295,7 +327,7 @@ TEST(Rtcm_Test, MT1029) } -TEST(Rtcm_Test, MT1045) +TEST(RtcmTest, MT1045) { auto rtcm = std::make_shared(); bool expected_true = true; @@ -311,17 +343,18 @@ TEST(Rtcm_Test, MT1045) EXPECT_EQ(0, rtcm->read_MT1045(tx_msg, gal_eph_read)); EXPECT_EQ(expected_true, gal_eph_read.E5a_DVS); - EXPECT_DOUBLE_EQ( 53.0 * OMEGA_dot_3_LSB, gal_eph_read.OMEGA_dot_3); - EXPECT_EQ(5, gal_eph_read.i_satellite_PRN); + EXPECT_DOUBLE_EQ(53.0 * OMEGA_dot_3_LSB, gal_eph_read.OMEGA_dot_3); + EXPECT_EQ(static_cast(5), gal_eph_read.i_satellite_PRN); EXPECT_EQ(1, rtcm->read_MT1045(rtcm->bin_to_binary_data(rtcm->hex_to_bin("FFFFFFFFFFF")), gal_eph_read)); } -TEST(Rtcm_Test, MSMCell) +TEST(RtcmTest, MSMCell) { auto rtcm = std::make_shared(); Gps_Ephemeris gps_eph = Gps_Ephemeris(); Galileo_Ephemeris gal_eph = Galileo_Ephemeris(); + //Glonass_Gnav_Ephemeris glo_gnav_eph = Glonass_Gnav_Ephemeris(); std::map pseudoranges; Gnss_Synchro gnss_synchro; @@ -329,15 +362,18 @@ TEST(Rtcm_Test, MSMCell) Gnss_Synchro gnss_synchro3; Gnss_Synchro gnss_synchro4; Gnss_Synchro gnss_synchro5; + Gnss_Synchro gnss_synchro6; gnss_synchro.PRN = 4; gnss_synchro2.PRN = 8; gnss_synchro3.PRN = 32; gnss_synchro4.PRN = 10; gnss_synchro5.PRN = 10; + gnss_synchro6.PRN = 10; std::string gps = "G"; std::string gal = "E"; + std::string glo = "R"; std::string c1 = "1C"; std::string s2 = "2S"; @@ -348,24 +384,28 @@ TEST(Rtcm_Test, MSMCell) gnss_synchro3.System = *gps.c_str(); gnss_synchro4.System = *gal.c_str(); gnss_synchro5.System = *gps.c_str(); + gnss_synchro6.System = *glo.c_str(); std::memcpy((void*)gnss_synchro.Signal, x5.c_str(), 3); std::memcpy((void*)gnss_synchro2.Signal, s2.c_str(), 3); std::memcpy((void*)gnss_synchro3.Signal, c1.c_str(), 3); std::memcpy((void*)gnss_synchro4.Signal, x5.c_str(), 3); std::memcpy((void*)gnss_synchro5.Signal, c1.c_str(), 3); + std::memcpy((void*)gnss_synchro6.Signal, c1.c_str(), 3); gnss_synchro.Pseudorange_m = 20000000.0; gnss_synchro2.Pseudorange_m = 20001010.0; gnss_synchro3.Pseudorange_m = 24002020.0; gnss_synchro4.Pseudorange_m = 20003010.1; gnss_synchro5.Pseudorange_m = 22003010.1; + gnss_synchro6.Pseudorange_m = 22003010.1; pseudoranges.insert(std::pair(1, gnss_synchro)); pseudoranges.insert(std::pair(2, gnss_synchro2)); pseudoranges.insert(std::pair(3, gnss_synchro3)); pseudoranges.insert(std::pair(4, gnss_synchro4)); pseudoranges.insert(std::pair(5, gnss_synchro5)); + pseudoranges.insert(std::pair(6, gnss_synchro5)); unsigned int ref_id = 1234; unsigned int clock_steering_indicator = 0; @@ -377,76 +417,82 @@ TEST(Rtcm_Test, MSMCell) gps_eph.i_satellite_PRN = gnss_synchro2.PRN; gal_eph.i_satellite_PRN = gnss_synchro.PRN; + //glo_gnav_eph.i_satellite_PRN = gnss_synchro.PRN; std::string MSM1 = rtcm->print_MSM_1(gps_eph, - {}, - gal_eph, - obs_time, - pseudoranges, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + {}, + gal_eph, + {}, + obs_time, + pseudoranges, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string MSM1_bin = rtcm->binary_data_to_bin(MSM1); unsigned int Nsat = 4; unsigned int Nsig = 3; unsigned int size_header = 14; unsigned int size_msg_length = 10; - EXPECT_EQ(0, MSM1_bin.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010101100")); // check cell mask + EXPECT_EQ(0, MSM1_bin.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010101100")); // check cell mask std::map pseudoranges2; + pseudoranges2.insert(std::pair(1, gnss_synchro6)); pseudoranges2.insert(std::pair(1, gnss_synchro5)); pseudoranges2.insert(std::pair(2, gnss_synchro4)); pseudoranges2.insert(std::pair(3, gnss_synchro3)); pseudoranges2.insert(std::pair(4, gnss_synchro2)); pseudoranges2.insert(std::pair(5, gnss_synchro)); + pseudoranges2.insert(std::pair(6, gnss_synchro)); std::string MSM1_2 = rtcm->print_MSM_1(gps_eph, - {}, - gal_eph, - obs_time, - pseudoranges2, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + {}, + gal_eph, + {}, + obs_time, + pseudoranges2, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string MSM1_bin_2 = rtcm->binary_data_to_bin(MSM1_2); - EXPECT_EQ(0, MSM1_bin_2.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010101100")); // check cell mask + EXPECT_EQ(0, MSM1_bin_2.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010001100")); // check cell mask - Gnss_Synchro gnss_synchro6; - gnss_synchro6.PRN = 10; - gnss_synchro6.System = *gps.c_str(); - std::memcpy((void*)gnss_synchro6.Signal, s2.c_str(), 3); - gnss_synchro6.Pseudorange_m = 24000000.0; + Gnss_Synchro gnss_synchro7; + gnss_synchro7.PRN = 10; + gnss_synchro7.System = *gps.c_str(); + std::memcpy((void*)gnss_synchro7.Signal, s2.c_str(), 3); + gnss_synchro7.Pseudorange_m = 24000000.0; std::map pseudoranges3; pseudoranges3.insert(std::pair(1, gnss_synchro)); pseudoranges3.insert(std::pair(2, gnss_synchro2)); - pseudoranges3.insert(std::pair(3, gnss_synchro6)); + pseudoranges3.insert(std::pair(3, gnss_synchro7)); pseudoranges3.insert(std::pair(4, gnss_synchro4)); pseudoranges3.insert(std::pair(5, gnss_synchro5)); std::string MSM1_3 = rtcm->print_MSM_1(gps_eph, - {}, - gal_eph, - obs_time, - pseudoranges3, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + {}, + gal_eph, + {}, + obs_time, + pseudoranges3, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string MSM1_bin_3 = rtcm->binary_data_to_bin(MSM1_3); - EXPECT_EQ(0, MSM1_bin_3.substr(size_header + size_msg_length + 169, (Nsat-1) * Nsig).compare("001010111")); // check cell mask + EXPECT_EQ(0, MSM1_bin_3.substr(size_header + size_msg_length + 169, (Nsat - 1) * Nsig).compare("001010111")); // check cell mask } -TEST(Rtcm_Test, MSM1) +TEST(RtcmTest, MSM1) { auto rtcm = std::make_shared(); bool expected_true = true; @@ -473,10 +519,10 @@ TEST(Rtcm_Test, MSM1) gnss_synchro3.System = *sys.c_str(); gnss_synchro4.System = *sys.c_str(); - std::memcpy((void*)gnss_synchro.Signal, sig.c_str(), 3); - std::memcpy((void*)gnss_synchro2.Signal, sig.c_str(), 3); - std::memcpy((void*)gnss_synchro3.Signal, sig2.c_str(), 3); - std::memcpy((void*)gnss_synchro4.Signal, sig2.c_str(), 3); + std::memcpy(static_cast(gnss_synchro.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gnss_synchro2.Signal), sig.c_str(), 3); + std::memcpy(static_cast(gnss_synchro3.Signal), sig2.c_str(), 3); + std::memcpy(static_cast(gnss_synchro4.Signal), sig2.c_str(), 3); gnss_synchro.Pseudorange_m = 20000000.0; gnss_synchro2.Pseudorange_m = 20001010.0; @@ -499,15 +545,15 @@ TEST(Rtcm_Test, MSM1) gps_eph.i_satellite_PRN = gnss_synchro.PRN; std::string MSM1 = rtcm->print_MSM_1(gps_eph, - {}, {}, - obs_time, - pseudoranges, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + {}, {}, {}, + obs_time, + pseudoranges, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); EXPECT_EQ(expected_true, rtcm->check_CRC(MSM1)); @@ -521,23 +567,23 @@ TEST(Rtcm_Test, MSM1) unsigned int data_size = MSM1_bin.length() - size_header - size_msg_length - size_crc; EXPECT_EQ(expected_true, upper_bound >= data_size); EXPECT_EQ(0, MSM1_bin.substr(0, size_header).compare("11010011000000")); - EXPECT_EQ(ref_id, rtcm->bin_to_uint( MSM1_bin.substr(size_header + size_msg_length + 12, 12))); - EXPECT_EQ(0, MSM1_bin.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("101101")); // check cell mask + EXPECT_EQ(ref_id, rtcm->bin_to_uint(MSM1_bin.substr(size_header + size_msg_length + 12, 12))); + EXPECT_EQ(0, MSM1_bin.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("101101")); // check cell mask double meters_to_miliseconds = GPS_C_m_s * 0.001; unsigned int rough_range_1 = static_cast(std::floor(std::round(gnss_synchro.Pseudorange_m / meters_to_miliseconds / TWO_N10)) + 0.5) & 0x3FFu; unsigned int rough_range_2 = static_cast(std::floor(std::round(gnss_synchro2.Pseudorange_m / meters_to_miliseconds / TWO_N10)) + 0.5) & 0x3FFu; unsigned int rough_range_4 = static_cast(std::floor(std::round(gnss_synchro3.Pseudorange_m / meters_to_miliseconds / TWO_N10)) + 0.5) & 0x3FFu; - unsigned int read_pseudorange_1 = rtcm->bin_to_uint( MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig , 10)); - unsigned int read_pseudorange_2 = rtcm->bin_to_uint( MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig + 10, 10)); - unsigned int read_pseudorange_4 = rtcm->bin_to_uint( MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig + 20, 10)); + unsigned int read_pseudorange_1 = rtcm->bin_to_uint(MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig, 10)); + unsigned int read_pseudorange_2 = rtcm->bin_to_uint(MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig + 10, 10)); + unsigned int read_pseudorange_4 = rtcm->bin_to_uint(MSM1_bin.substr(size_header + size_msg_length + 169 + Nsat * Nsig + 20, 10)); EXPECT_EQ(rough_range_1, read_pseudorange_1); EXPECT_EQ(rough_range_2, read_pseudorange_2); EXPECT_EQ(rough_range_4, read_pseudorange_4); - int psrng4_s = static_cast(std::round( (gnss_synchro3.Pseudorange_m - std::round(gnss_synchro3.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10)/ meters_to_miliseconds / TWO_N24)); - int read_psrng4_s = rtcm->bin_to_int( MSM1_bin.substr(size_header + size_msg_length + 169 + (Nsat * Nsig) + 30 + 15 * 3, 15)); + int psrng4_s = static_cast(std::round((gnss_synchro3.Pseudorange_m - std::round(gnss_synchro3.Pseudorange_m / meters_to_miliseconds / TWO_N10) * meters_to_miliseconds * TWO_N10) / meters_to_miliseconds / TWO_N24)); + int read_psrng4_s = rtcm->bin_to_int(MSM1_bin.substr(size_header + size_msg_length + 169 + (Nsat * Nsig) + 30 + 15 * 3, 15)); EXPECT_EQ(psrng4_s, read_psrng4_s); std::map pseudoranges2; @@ -546,22 +592,22 @@ TEST(Rtcm_Test, MSM1) pseudoranges2.insert(std::pair(3, gnss_synchro2)); pseudoranges2.insert(std::pair(4, gnss_synchro)); std::string MSM1_2 = rtcm->print_MSM_1(gps_eph, - {}, {}, - obs_time, - pseudoranges2, - ref_id, - clock_steering_indicator, - external_clock_indicator, - smooth_int, - divergence_free, - more_messages); + {}, {}, {}, + obs_time, + pseudoranges2, + ref_id, + clock_steering_indicator, + external_clock_indicator, + smooth_int, + divergence_free, + more_messages); std::string MSM1_bin2 = rtcm->binary_data_to_bin(MSM1_2); - int read_psrng4_s_2 = rtcm->bin_to_int( MSM1_bin2.substr(size_header + size_msg_length + 169 + (Nsat * Nsig) + 30 + 15 * 3, 15)); + int read_psrng4_s_2 = rtcm->bin_to_int(MSM1_bin2.substr(size_header + size_msg_length + 169 + (Nsat * Nsig) + 30 + 15 * 3, 15)); EXPECT_EQ(psrng4_s, read_psrng4_s_2); } -TEST(Rtcm_Test, InstantiateServer) +TEST(RtcmTest, InstantiateServer) { auto rtcm = std::make_shared(); rtcm->run_server(); @@ -574,7 +620,7 @@ TEST(Rtcm_Test, InstantiateServer) std::string test6 = "0011"; std::string test6_hex = rtcm->bin_to_hex(test6); EXPECT_EQ(0, test6_hex.compare("3")); - long unsigned int expected1 = 42; + uint64_t expected1 = 42; EXPECT_EQ(expected1, rtcm->bin_to_uint("00101010")); rtcm->run_server(); std::string test4_bin = rtcm->hex_to_bin(test3); @@ -585,7 +631,7 @@ TEST(Rtcm_Test, InstantiateServer) } -TEST(Rtcm_Test, InstantiateServerWithoutClosing) +TEST(RtcmTest, InstantiateServerWithoutClosing) { auto rtcm = std::make_shared(); rtcm->run_server(); @@ -595,7 +641,3 @@ TEST(Rtcm_Test, InstantiateServerWithoutClosing) std::string test3_bin = rtcm->hex_to_bin(test3); EXPECT_EQ(0, test3_bin.compare("11111111")); } - - - - diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc new file mode 100644 index 000000000..d4ae24ba8 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc @@ -0,0 +1,462 @@ +/*! + * \file rtklib_solver_test.cc + * \brief Implements Unit Test for the rtklib PVT solver class. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "geofunctions.h" +#include "gnss_sdr_supl_client.h" +#include "in_memory_configuration.h" +#include "rtklib_solver.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +rtk_t configure_rtklib_options() +{ + std::shared_ptr configuration; + configuration = std::make_shared(); + std::string role = "rtklib_solver"; + // custom options + configuration->set_property("rtklib_solver.positioning_mode", "Single"); + configuration->set_property("rtklib_solver.elevation_mask", "0"); + configuration->set_property("rtklib_solver.iono_model", "OFF"); + configuration->set_property("rtklib_solver.trop_model", "OFF"); + //RTKLIB PVT solver options + + // Settings 1 + int positioning_mode = -1; + std::string default_pos_mode("Single"); + std::string positioning_mode_str = configuration->property(role + ".positioning_mode", default_pos_mode); /* (PMODE_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + if (positioning_mode_str.compare("Single") == 0) positioning_mode = PMODE_SINGLE; + if (positioning_mode_str.compare("Static") == 0) positioning_mode = PMODE_STATIC; + if (positioning_mode_str.compare("Kinematic") == 0) positioning_mode = PMODE_KINEMA; + if (positioning_mode_str.compare("PPP_Static") == 0) positioning_mode = PMODE_PPP_STATIC; + if (positioning_mode_str.compare("PPP_Kinematic") == 0) positioning_mode = PMODE_PPP_KINEMA; + + if (positioning_mode == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of positioning mode." << std::endl; + std::cout << "positioning_mode possible values: Single / Static / Kinematic / PPP_Static / PPP_Kinematic" << std::endl; + std::cout << "positioning_mode specified value: " << positioning_mode_str << std::endl; + std::cout << "Setting positioning_mode to Single" << std::endl; + positioning_mode = PMODE_SINGLE; + } + + int num_bands = 1; + + // if ((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) num_bands = 1; + // if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gps_2S_count > 0) || (glo_2G_count > 0))) num_bands = 2; + // if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0) || (gps_L5_count > 0))) num_bands = 2; + // if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gps_2S_count > 0) || (glo_2G_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0) || (gps_L5_count > 0))) num_bands = 3; + + int number_of_frequencies = configuration->property(role + ".num_bands", num_bands); /* (1:L1, 2:L1+L2, 3:L1+L2+L5) */ + if ((number_of_frequencies < 1) || (number_of_frequencies > 3)) + { + //warn user and set the default + number_of_frequencies = num_bands; + } + + double elevation_mask = configuration->property(role + ".elevation_mask", 15.0); + if ((elevation_mask < 0.0) || (elevation_mask > 90.0)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Elevation Mask. Setting to default value of 15.0 degrees"; + elevation_mask = 15.0; + } + + int dynamics_model = configuration->property(role + ".dynamics_model", 0); /* dynamics model (0:none, 1:velocity, 2:accel) */ + if ((dynamics_model < 0) || (dynamics_model > 2)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Dynamics Model configuration. Setting to default value of (0:none)"; + dynamics_model = 0; + } + + std::string default_iono_model("OFF"); + std::string iono_model_str = configuration->property(role + ".iono_model", default_iono_model); /* (IONOOPT_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + int iono_model = -1; + if (iono_model_str.compare("OFF") == 0) iono_model = IONOOPT_OFF; + if (iono_model_str.compare("Broadcast") == 0) iono_model = IONOOPT_BRDC; + if (iono_model_str.compare("SBAS") == 0) iono_model = IONOOPT_SBAS; + if (iono_model_str.compare("Iono-Free-LC") == 0) iono_model = IONOOPT_IFLC; + if (iono_model_str.compare("Estimate_STEC") == 0) iono_model = IONOOPT_EST; + if (iono_model_str.compare("IONEX") == 0) iono_model = IONOOPT_TEC; + if (iono_model == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of ionospheric model." << std::endl; + std::cout << "iono_model possible values: OFF / Broadcast / SBAS / Iono-Free-LC / Estimate_STEC / IONEX" << std::endl; + std::cout << "iono_model specified value: " << iono_model_str << std::endl; + std::cout << "Setting iono_model to OFF" << std::endl; + iono_model = IONOOPT_OFF; /* 0: ionosphere option: correction off */ + } + + std::string default_trop_model("OFF"); + int trop_model = -1; + std::string trop_model_str = configuration->property(role + ".trop_model", default_trop_model); /* (TROPOPT_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + if (trop_model_str.compare("OFF") == 0) trop_model = TROPOPT_OFF; + if (trop_model_str.compare("Saastamoinen") == 0) trop_model = TROPOPT_SAAS; + if (trop_model_str.compare("SBAS") == 0) trop_model = TROPOPT_SBAS; + if (trop_model_str.compare("Estimate_ZTD") == 0) trop_model = TROPOPT_EST; + if (trop_model_str.compare("Estimate_ZTD_Grad") == 0) trop_model = TROPOPT_ESTG; + if (trop_model == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of tropospheric model." << std::endl; + std::cout << "trop_model possible values: OFF / Saastamoinen / SBAS / Estimate_ZTD / Estimate_ZTD_Grad" << std::endl; + std::cout << "trop_model specified value: " << trop_model_str << std::endl; + std::cout << "Setting trop_model to OFF" << std::endl; + trop_model = TROPOPT_OFF; + } + + /* RTKLIB positioning options */ + int sat_PCV = 0; /* Set whether the satellite antenna PCV (phase center variation) model is used or not. This feature requires a Satellite Antenna PCV File. */ + int rec_PCV = 0; /* Set whether the receiver antenna PCV (phase center variation) model is used or not. This feature requires a Receiver Antenna PCV File. */ + + /* Set whether the phase windup correction for PPP modes is applied or not. Only applicable to PPP‐* modes.*/ + int phwindup = configuration->property(role + ".phwindup", 0); + + /* Set whether the GPS Block IIA satellites in eclipse are excluded or not. + The eclipsing Block IIA satellites often degrade the PPP solutions due to unpredicted behavior of yaw‐attitude. Only applicable to PPP‐* modes.*/ + int reject_GPS_IIA = configuration->property(role + ".reject_GPS_IIA", 0); + + /* Set whether RAIM (receiver autonomous integrity monitoring) FDE (fault detection and exclusion) feature is enabled or not. + In case of RAIM FDE enabled, a satellite is excluded if SSE (sum of squared errors) of residuals is over a threshold. + The excluded satellite is selected to indicate the minimum SSE. */ + int raim_fde = configuration->property(role + ".raim_fde", 0); + + int earth_tide = configuration->property(role + ".earth_tide", 0); + + int nsys = SYS_GPS; + // if ((gps_1C_count > 0) || (gps_2S_count > 0) || (gps_L5_count > 0)) nsys += SYS_GPS; + // if ((gal_1B_count > 0) || (gal_E5a_count > 0) || (gal_E5b_count > 0)) nsys += SYS_GAL; + // if ((glo_1G_count > 0) || (glo_2G_count > 0)) nsys += SYS_GLO; + int navigation_system = configuration->property(role + ".navigation_system", nsys); /* (SYS_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + if ((navigation_system < 1) || (navigation_system > 255)) /* GPS: 1 SBAS: 2 GPS+SBAS: 3 Galileo: 8 Galileo+GPS: 9 GPS+SBAS+Galileo: 11 All: 255 */ + { + //warn user and set the default + LOG(WARNING) << "Erroneous Navigation System. Setting to default value of (0:none)"; + navigation_system = nsys; + } + + // Settings 2 + std::string default_gps_ar("Continuous"); + std::string integer_ambiguity_resolution_gps_str = configuration->property(role + ".AR_GPS", default_gps_ar); /* Integer Ambiguity Resolution mode for GPS (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + int integer_ambiguity_resolution_gps = -1; + if (integer_ambiguity_resolution_gps_str.compare("OFF") == 0) integer_ambiguity_resolution_gps = ARMODE_OFF; + if (integer_ambiguity_resolution_gps_str.compare("Continuous") == 0) integer_ambiguity_resolution_gps = ARMODE_CONT; + if (integer_ambiguity_resolution_gps_str.compare("Instantaneous") == 0) integer_ambiguity_resolution_gps = ARMODE_INST; + if (integer_ambiguity_resolution_gps_str.compare("Fix-and-Hold") == 0) integer_ambiguity_resolution_gps = ARMODE_FIXHOLD; + if (integer_ambiguity_resolution_gps_str.compare("PPP-AR") == 0) integer_ambiguity_resolution_gps = ARMODE_PPPAR; + if (integer_ambiguity_resolution_gps == -1) + { + //warn user and set the default + std::cout << "WARNING: Bad specification of GPS ambiguity resolution method." << std::endl; + std::cout << "AR_GPS possible values: OFF / Continuous / Instantaneous / Fix-and-Hold / PPP-AR" << std::endl; + std::cout << "AR_GPS specified value: " << integer_ambiguity_resolution_gps_str << std::endl; + std::cout << "Setting AR_GPS to OFF" << std::endl; + integer_ambiguity_resolution_gps = ARMODE_OFF; + } + + int integer_ambiguity_resolution_glo = configuration->property(role + ".AR_GLO", 1); /* Integer Ambiguity Resolution mode for GLONASS (0:off,1:on,2:auto cal,3:ext cal) */ + if ((integer_ambiguity_resolution_glo < 0) || (integer_ambiguity_resolution_glo > 3)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for GLONASS . Setting to default value of (1:on)"; + integer_ambiguity_resolution_glo = 1; + } + + int integer_ambiguity_resolution_bds = configuration->property(role + ".AR_DBS", 1); /* Integer Ambiguity Resolution mode for BEIDOU (0:off,1:on) */ + if ((integer_ambiguity_resolution_bds < 0) || (integer_ambiguity_resolution_bds > 1)) + { + //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for BEIDOU . Setting to default value of (1:on)"; + integer_ambiguity_resolution_bds = 1; + } + + double min_ratio_to_fix_ambiguity = configuration->property(role + ".min_ratio_to_fix_ambiguity", 3.0); /* Set the integer ambiguity validation threshold for ratio‐test, + which uses the ratio of squared residuals of the best integer vector to the second‐best vector. */ + + int min_lock_to_fix_ambiguity = configuration->property(role + ".min_lock_to_fix_ambiguity", 0); /* Set the minimum lock count to fix integer ambiguity. + If the lock count is less than the value, the ambiguity is excluded from the fixed integer vector. */ + + double min_elevation_to_fix_ambiguity = configuration->property(role + ".min_elevation_to_fix_ambiguity", 0.0); /* Set the minimum elevation (deg) to fix integer ambiguity. + If the elevation of the satellite is less than the value, the ambiguity is excluded from the fixed integer vector. */ + + int outage_reset_ambiguity = configuration->property(role + ".outage_reset_ambiguity", 5); /* Set the outage count to reset ambiguity. If the data outage count is over the value, the estimated ambiguity is reset to the initial value. */ + + double slip_threshold = configuration->property(role + ".slip_threshold", 0.05); /* set the cycle‐slip threshold (m) of geometry‐free LC carrier‐phase difference between epochs */ + + double threshold_reject_gdop = configuration->property(role + ".threshold_reject_gdop", 30.0); /* reject threshold of GDOP. If the GDOP is over the value, the observable is excluded for the estimation process as an outlier. */ + + double threshold_reject_innovation = configuration->property(role + ".threshold_reject_innovation", 30.0); /* reject threshold of innovation (m). If the innovation is over the value, the observable is excluded for the estimation process as an outlier. */ + + int number_filter_iter = configuration->property(role + ".number_filter_iter", 1); /* Set the number of iteration in the measurement update of the estimation filter. + If the baseline length is very short like 1 m, the iteration may be effective to handle + the nonlinearity of measurement equation. */ + + /// Statistics + double bias_0 = configuration->property(role + ".bias_0", 30.0); + + double iono_0 = configuration->property(role + ".iono_0", 0.03); + + double trop_0 = configuration->property(role + ".trop_0", 0.3); + + double sigma_bias = configuration->property(role + ".sigma_bias", 1e-4); /* Set the process noise standard deviation of carrier‐phase + bias (ambiguity) (cycle/sqrt(s)) */ + + double sigma_iono = configuration->property(role + ".sigma_iono", 1e-3); /* Set the process noise standard deviation of vertical ionospheric delay per 10 km baseline (m/sqrt(s)). */ + + double sigma_trop = configuration->property(role + ".sigma_trop", 1e-4); /* Set the process noise standard deviation of zenith tropospheric delay (m/sqrt(s)). */ + + double sigma_acch = configuration->property(role + ".sigma_acch", 1e-1); /* Set the process noise standard deviation of the receiver acceleration as + the horizontal component. (m/s2/sqrt(s)). If Receiver Dynamics is set to OFF, they are not used. */ + + double sigma_accv = configuration->property(role + ".sigma_accv", 1e-2); /* Set the process noise standard deviation of the receiver acceleration as + the vertical component. (m/s2/sqrt(s)). If Receiver Dynamics is set to OFF, they are not used. */ + + double sigma_pos = configuration->property(role + ".sigma_pos", 0.0); + + double code_phase_error_ratio_l1 = configuration->property(role + ".code_phase_error_ratio_l1", 100.0); + double code_phase_error_ratio_l2 = configuration->property(role + ".code_phase_error_ratio_l2", 100.0); + double code_phase_error_ratio_l5 = configuration->property(role + ".code_phase_error_ratio_l5", 100.0); + double carrier_phase_error_factor_a = configuration->property(role + ".carrier_phase_error_factor_a", 0.003); + double carrier_phase_error_factor_b = configuration->property(role + ".carrier_phase_error_factor_b", 0.003); + + snrmask_t snrmask = {{}, {{}, {}}}; + + prcopt_t rtklib_configuration_options = { + positioning_mode, /* positioning mode (PMODE_XXX) see src/algorithms/libs/rtklib/rtklib.h */ + 0, /* solution type (0:forward,1:backward,2:combined) */ + number_of_frequencies, /* number of frequencies (1:L1, 2:L1+L2, 3:L1+L2+L5)*/ + navigation_system, /* navigation system */ + elevation_mask * D2R, /* elevation mask angle (degrees) */ + snrmask, /* snrmask_t snrmask SNR mask */ + 0, /* satellite ephemeris/clock (EPHOPT_XXX) */ + integer_ambiguity_resolution_gps, /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + integer_ambiguity_resolution_glo, /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */ + integer_ambiguity_resolution_bds, /* BeiDou AR mode (0:off,1:on) */ + outage_reset_ambiguity, /* obs outage count to reset bias */ + min_lock_to_fix_ambiguity, /* min lock count to fix ambiguity */ + 10, /* min fix count to hold ambiguity */ + 1, /* max iteration to resolve ambiguity */ + iono_model, /* ionosphere option (IONOOPT_XXX) */ + trop_model, /* troposphere option (TROPOPT_XXX) */ + dynamics_model, /* dynamics model (0:none, 1:velocity, 2:accel) */ + earth_tide, /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */ + number_filter_iter, /* number of filter iteration */ + 0, /* code smoothing window size (0:none) */ + 0, /* interpolate reference obs (for post mission) */ + 0, /* sbssat_t sbssat SBAS correction options */ + 0, /* sbsion_t sbsion[MAXBAND+1] SBAS satellite selection (0:all) */ + 0, /* rover position for fixed mode */ + 0, /* base position for relative mode */ + /* 0:pos in prcopt, 1:average of single pos, */ + /* 2:read from file, 3:rinex header, 4:rtcm pos */ + {code_phase_error_ratio_l1, code_phase_error_ratio_l2, code_phase_error_ratio_l5}, /* eratio[NFREQ] code/phase error ratio */ + {100.0, carrier_phase_error_factor_a, carrier_phase_error_factor_b, 0.0, 1.0}, /* err[5]: measurement error factor [0]:reserved, [1-3]:error factor a/b/c of phase (m) , [4]:doppler frequency (hz) */ + {bias_0, iono_0, trop_0}, /* std[3]: initial-state std [0]bias,[1]iono [2]trop*/ + {sigma_bias, sigma_iono, sigma_trop, sigma_acch, sigma_accv, sigma_pos}, /* prn[6] process-noise std */ + 5e-12, /* sclkstab: satellite clock stability (sec/sec) */ + {min_ratio_to_fix_ambiguity, 0.9999, 0.25, 0.1, 0.05, 0.0, 0.0, 0.0}, /* thresar[8]: AR validation threshold */ + min_elevation_to_fix_ambiguity, /* elevation mask of AR for rising satellite (deg) */ + 0.0, /* elevation mask to hold ambiguity (deg) */ + slip_threshold, /* slip threshold of geometry-free phase (m) */ + 30.0, /* max difference of time (sec) */ + threshold_reject_innovation, /* reject threshold of innovation (m) */ + threshold_reject_gdop, /* reject threshold of gdop */ + {}, /* double baseline[2] baseline length constraint {const,sigma} (m) */ + {}, /* double ru[3] rover position for fixed mode {x,y,z} (ecef) (m) */ + {}, /* double rb[3] base position for relative mode {x,y,z} (ecef) (m) */ + {"", ""}, /* char anttype[2][MAXANT] antenna types {rover,base} */ + {{}, {}}, /* double antdel[2][3] antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */ + {}, /* pcv_t pcvr[2] receiver antenna parameters {rov,base} */ + {}, /* unsigned char exsats[MAXSAT] excluded satellites (1:excluded, 2:included) */ + 0, /* max averaging epoches */ + 0, /* initialize by restart */ + 1, /* output single by dgps/float/fix/ppp outage */ + {"", ""}, /* char rnxopt[2][256] rinex options {rover,base} */ + {sat_PCV, rec_PCV, phwindup, reject_GPS_IIA, raim_fde}, /* posopt[6] positioning options [0]: satellite and receiver antenna PCV model; [1]: interpolate antenna parameters; [2]: apply phase wind-up correction for PPP modes; [3]: exclude measurements of GPS Block IIA satellites satellite [4]: RAIM FDE (fault detection and exclusion) [5]: handle day-boundary clock jump */ + 0, /* solution sync mode (0:off,1:on) */ + {{}, {}}, /* odisp[2][6*11] ocean tide loading parameters {rov,base} */ + {{}, {{}, {}}, {{}, {}}, {}, {}}, /* exterr_t exterr extended receiver error model */ + 0, /* disable L2-AR */ + {} /* char pppopt[256] ppp option "-GAP_RESION=" default gap to reset iono parameters (ep) */ + }; + + rtk_t rtk; + rtkinit(&rtk, &rtklib_configuration_options); + return rtk; +} + + +//todo: add test cases for Galileo E1, E5 and GPS L5 +TEST(RTKLibSolverTest, test1) +{ + //test case #1: GPS L1 CA simulated with gnss-sim + std::string path = std::string(TEST_PATH); + int nchannels = 8; + std::string dump_filename = ".rtklib_solver_dump.dat"; + bool flag_dump_to_file = false; + bool save_to_mat = false; + rtk_t rtk = configure_rtklib_options(); + + std::unique_ptr d_ls_pvt(new rtklib_solver(nchannels, dump_filename, flag_dump_to_file, save_to_mat, rtk)); + d_ls_pvt->set_averaging_depth(1); + + // load ephemeris + std::string eph_xml_filename = path + "data/rtklib_test/eph_GPS_L1CA_test1.xml"; + gnss_sdr_supl_client supl_client_ephemeris_; + + std::cout << "SUPL: Try read GPS ephemeris from XML file " << eph_xml_filename << std::endl; + if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename) == true) + { + std::map::const_iterator gps_eph_iter; + for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.cbegin(); + gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.cend(); + gps_eph_iter++) + { + std::cout << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first << std::endl; + std::shared_ptr tmp_obj = std::make_shared(gps_eph_iter->second); + // update/insert new ephemeris record to the global ephemeris map + d_ls_pvt->gps_ephemeris_map[gps_eph_iter->first] = *tmp_obj; + } + } + else + { + std::cout << "ERROR: SUPL client error reading XML" << std::endl; + } + + // insert observables epoch + std::map gnss_synchro_map; + // Gnss_Synchro tmp_obs; + // tmp_obs.System = 'G'; + // std::string signal = "1C"; + // const char* str = signal.c_str(); // get a C style null terminated string + // std::memcpy(static_cast(tmp_obs.Signal), str, 3); // copy string into synchro char array: 2 char + null + // + // gnss_synchro_map[0] = tmp_obs; + // gnss_synchro_map[0].PRN = 1; + + //load from xml (boost serialize) + std::string file_name = path + "data/rtklib_test/obs_test1.xml"; + + std::ifstream ifs; + try + { + ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); + boost::archive::xml_iarchive xml(ifs); + gnss_synchro_map.clear(); + xml >> boost::serialization::make_nvp("GNSS-SDR_gnss_synchro_map", gnss_synchro_map); + std::cout << "Loaded gnss_synchro map data with " << gnss_synchro_map.size() << " pseudoranges" << std::endl; + } + catch (std::exception& e) + { + std::cout << e.what() << "File: " << file_name; + } + ifs.close(); + + // solve + bool pvt_valid = false; + if (d_ls_pvt->get_PVT(gnss_synchro_map, false)) + { + // DEBUG MESSAGE: Display position in console output + if (d_ls_pvt->is_valid_position()) + { + std::streamsize ss = std::cout.precision(); // save current precision + std::cout.setf(std::ios::fixed, std::ios::floatfield); + + auto facet = new boost::posix_time::time_facet("%Y-%b-%d %H:%M:%S.%f %z"); + std::cout.imbue(std::locale(std::cout.getloc(), facet)); + + std::cout << "Position at " << d_ls_pvt->get_position_UTC_time() + << " UTC using " << d_ls_pvt->get_num_valid_observations() + << std::fixed << std::setprecision(9) + << " observations is Lat = " << d_ls_pvt->get_latitude() << " [deg], Long = " << d_ls_pvt->get_longitude() + << std::fixed << std::setprecision(3) + << " [deg], Height = " << d_ls_pvt->get_height() << " [m]" << std::endl; + std::cout << std::setprecision(ss); + std::cout << "RX clock offset: " << d_ls_pvt->get_time_offset_s() << "[s]" << std::endl; + + // boost::posix_time::ptime p_time; + // gtime_t rtklib_utc_time = gpst2time(adjgpsweek(d_ls_pvt->gps_ephemeris_map.cbegin()->second.i_GPS_week), d_rx_time); + // p_time = boost::posix_time::from_time_t(rtklib_utc_time.time); + // p_time += boost::posix_time::microseconds(round(rtklib_utc_time.sec * 1e6)); + // std::cout << TEXT_MAGENTA << "Observable RX time (GPST) " << boost::posix_time::to_simple_string(p_time) << TEXT_RESET << std::endl; + + std::cout << "RTKLIB Position at RX TOW = " << gnss_synchro_map.begin()->second.RX_time + << " in ECEF (X,Y,Z,t[meters]) = " << std::fixed << std::setprecision(16) + << d_ls_pvt->pvt_sol.rr[0] << "," + << d_ls_pvt->pvt_sol.rr[1] << "," + << d_ls_pvt->pvt_sol.rr[2] << std::endl; + /* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_ls_pvt->get_position_UTC_time()) + << " UTC using "<< d_ls_pvt->get_num_valid_observations() <<" observations is HDOP = " << d_ls_pvt->get_hdop() << " VDOP = " + << d_ls_pvt->get_vdop() + << " GDOP = " << d_ls_pvt->get_gdop() << std::endl; */ + + //todo: check here the positioning error against the reference position generated with gnss-sim + //reference position on in WGS84: Lat (deg), Long (deg) , H (m): 30.286502,120.032669,100 + arma::vec LLH = {30.286502, 120.032669, 100}; //ref position for this scenario + + double error_LLH_m = great_circle_distance(LLH(0), LLH(1), d_ls_pvt->get_latitude(), d_ls_pvt->get_longitude()); + std::cout << "Lat, Long, H error: " << d_ls_pvt->get_latitude() - LLH(0) + << "," << d_ls_pvt->get_longitude() - LLH(1) + << "," << d_ls_pvt->get_height() - LLH(2) << " [deg,deg,meters]" << std::endl; + + std::cout << "Haversine Great Circle error LLH distance: " << error_LLH_m << " [meters]" << std::endl; + + arma::vec v_eb_n = {0.0, 0.0, 0.0}; + arma::vec true_r_eb_e; + arma::vec true_v_eb_e; + pv_Geo_to_ECEF(degtorad(LLH(0)), degtorad(LLH(1)), LLH(2), v_eb_n, true_r_eb_e, true_v_eb_e); + + arma::vec measured_r_eb_e = {d_ls_pvt->pvt_sol.rr[0], d_ls_pvt->pvt_sol.rr[1], d_ls_pvt->pvt_sol.rr[2]}; + + arma::vec error_r_eb_e = measured_r_eb_e - true_r_eb_e; + + std::cout << "ECEF position error vector: " << error_r_eb_e << " [meters]" << std::endl; + + double error_3d_m = arma::norm(error_r_eb_e, 2); + + std::cout << "3D positioning error: " << error_3d_m << " [meters]" << std::endl; + + //check results against the test tolerance + ASSERT_LT(error_3d_m, 0.2); + pvt_valid = true; + } + } + + EXPECT_EQ(true, pvt_valid); +} diff --git a/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc b/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc index 017d7bace..d8ce67450 100644 --- a/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc @@ -1,4 +1,3 @@ - /*! * \file direct_resampler_conditioner_cc_test.cc * \brief Executes a resampler based on some input parameters. @@ -8,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -26,35 +25,37 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include #include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include -#include -#include -#include "gnss_sdr_valve.h" +#endif #include "direct_resampler_conditioner_cc.h" +#include "gnss_sdr_valve.h" +#include +#include -TEST(Direct_Resampler_Conditioner_Cc_Test, InstantiationAndRunTest) +TEST(DirectResamplerConditionerCcTest, InstantiationAndRunTest) { - double fs_in = 8000000.0; // Input sampling frequency in Hz - double fs_out = 4000000.0; // sampling freuqncy of the resampled signal in Hz - struct timeval tv; - int nsamples = 1000000; //Number of samples to be computed + double fs_in = 8000000.0; // Input sampling frequency in Hz + double fs_out = 4000000.0; // sampling freuqncy of the resampled signal in Hz + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int nsamples = 1000000; //Number of samples to be computed gr::msg_queue::sptr queue = gr::msg_queue::make(0); gr::top_block_sptr top_block = gr::make_top_block("direct_resampler_conditioner_cc_test"); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); - long long int begin = 0; - long long int end = 0; EXPECT_NO_THROW({ direct_resampler_conditioner_cc_sptr resampler = direct_resampler_make_conditioner_cc(fs_in, fs_out); @@ -63,20 +64,19 @@ TEST(Direct_Resampler_Conditioner_Cc_Test, InstantiationAndRunTest) direct_resampler_conditioner_cc_sptr resampler = direct_resampler_make_conditioner_cc(fs_in, fs_out); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(gr_complex)); - EXPECT_NO_THROW( { + EXPECT_NO_THROW({ top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, resampler, 0); top_block->connect(resampler, 0, sink, 0); }) << "Connection failure of direct_resampler_conditioner."; - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1000000 + tv.tv_usec; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; top_block->stop(); }) << "Failure running direct_resampler_conditioner."; - std::cout << "Resampled " << nsamples << " samples in " << (end-begin) << " microseconds" << std::endl; + std::cout << "Resampled " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } diff --git a/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc b/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc new file mode 100644 index 000000000..2bc26b8b4 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc @@ -0,0 +1,124 @@ +/*! + * \file mmse_resampler_test.cc + * \brief Executes a resampler based on some input parameters. + * \author Carles Fernandez-Prades 2018 cfernandez (at) cttc.cat + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif +#include "gnss_sdr_valve.h" +#include "mmse_resampler_conditioner.h" +#include +#include + +TEST(MmseResamplerTest, InstantiationAndRunTestWarning) +{ + double fs_in = 8000000.0; // Input sampling frequency in Hz + double fs_out = 4000000.0; // sampling freuqncy of the resampled signal in Hz + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int nsamples = 1000000; //Number of samples to be computed + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + gr::top_block_sptr top_block = gr::make_top_block("mmse_resampler_conditioner_cc_test"); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + + std::shared_ptr config; + config = std::make_shared(); + + config->set_property("Resampler.sample_freq_in", std::to_string(fs_in)); + config->set_property("Resampler.sample_freq_out", std::to_string(fs_out)); + + std::shared_ptr resampler = std::make_shared(config.get(), "Resampler", 1, 1); + + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(gr_complex)); + + EXPECT_NO_THROW({ + resampler->connect(top_block); + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, resampler->get_left_block(), 0); + top_block->connect(resampler->get_right_block(), 0, sink, 0); + }) << "Connection failure of direct_resampler_conditioner."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + top_block->stop(); + }) << "Failure running direct_resampler_conditioner."; + + std::cout << "Resampled " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST(MmseResamplerTest, InstantiationAndRunTest2) +{ + double fs_in = 8000000.0; // Input sampling frequency in Hz + double fs_out = 4000000.0; // sampling freuqncy of the resampled signal in Hz + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int nsamples = 1000000; //Number of samples to be computed + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + gr::top_block_sptr top_block = gr::make_top_block("mmse_resampler_conditioner_cc_test"); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + + std::shared_ptr config; + config = std::make_shared(); + + config->set_property("Resampler.sample_freq_in", std::to_string(fs_in)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(fs_out)); + + std::shared_ptr resampler = std::make_shared(config.get(), "Resampler", 1, 1); + + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(gr_complex)); + + EXPECT_NO_THROW({ + resampler->connect(top_block); + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, resampler->get_left_block(), 0); + top_block->connect(resampler->get_right_block(), 0, sink, 0); + }) << "Connection failure of direct_resampler_conditioner."; + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + top_block->stop(); + }) << "Failure running direct_resampler_conditioner."; + + std::cout << "Resampled " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc b/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc index 90171f1e5..344d1c1bc 100644 --- a/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,18 +24,18 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include #include "file_signal_source.h" #include "in_memory_configuration.h" +#include +#include +#include +#include +#include TEST(FileSignalSource, Instantiate) { @@ -50,7 +50,7 @@ TEST(FileSignalSource, Instantiate) config->set_property("Test.item_type", "gr_complex"); config->set_property("Test.repeat", "false"); - std::unique_ptr signal_source(new FileSignalSource(config.get(), "Test", 1, 1, queue)); + std::unique_ptr signal_source(new FileSignalSource(config.get(), "Test", 0, 1, queue)); EXPECT_STREQ("gr_complex", signal_source->item_type().c_str()); EXPECT_TRUE(signal_source->repeat() == false); @@ -67,5 +67,5 @@ TEST(FileSignalSource, InstantiateFileNotExists) config->set_property("Test.item_type", "gr_complex"); config->set_property("Test.repeat", "false"); - EXPECT_THROW({auto uptr = std::make_shared(config.get(), "Test", 1, 1, queue);}, std::exception); + EXPECT_THROW({ auto uptr = std::make_shared(config.get(), "Test", 0, 1, queue); }, std::exception); } diff --git a/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc b/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc index 55886c56c..02e1b09df 100644 --- a/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,20 +25,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include #include +#include +#ifdef GR_GREATER_38 +#include +#else #include +#endif +#include "gnss_sdr_valve.h" #include #include -#include "gnss_sdr_valve.h" -TEST(Valve_Test, CheckEventSentAfter100Samples) +TEST(ValveTest, CheckEventSentAfter100Samples) { gr::msg_queue::sptr queue = gr::msg_queue::make(0); diff --git a/src/tests/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc b/src/tests/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc index 9d7dfefed..7fc787352 100644 --- a/src/tests/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/sources/unpack_2bit_samples_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,91 +25,93 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include #include +#include +#ifdef GR_GREATER_38 +#include +#include +#else +#include #include #include -#include -#include +#endif #include "unpack_2bit_samples.h" +#include -std::vector< uint8_t > packData( std::vector< int8_t > const & raw_data, - bool big_endian ) +std::vector packData(std::vector const &raw_data, + bool big_endian) { - std::vector< uint8_t > packed_data( raw_data.size()/4 ); + std::vector packed_data(raw_data.size() / 4); - int shift = ( big_endian ? 6 : 0 ); + int shift = (big_endian ? 6 : 0); unsigned int j = 0; - for( unsigned int i = 0; i < raw_data.size(); ++i ) - { - unsigned val = static_cast< unsigned >( (raw_data[i] - 1 )/2 & 0x03 ); - - packed_data[j] |= val << shift; - - if( big_endian ) + for (signed char i : raw_data) { - shift -= 2; - if( shift < 0 ) - { - shift = 6; - j++; - } - } - else - { - shift += 2; - if( shift > 6 ) - { - shift = 0; - j++; - } + auto val = static_cast((i - 1) / 2 & 0x03); - } + packed_data[j] |= val << shift; - } + if (big_endian) + { + shift -= 2; + if (shift < 0) + { + shift = 6; + j++; + } + } + else + { + shift += 2; + if (shift > 6) + { + shift = 0; + j++; + } + } + } return packed_data; - } -TEST(Unpack_2bit_Samples_Test, CheckBigEndianByte) +TEST(Unpack2bitSamplesTest, CheckBigEndianByte) { bool big_endian_bytes = true; size_t item_size = 1; bool big_endian_items = false; - std::vector< int8_t > raw_data = { -1, 3, 1, -1, -3, 1, 3, 1 }; - std::vector< uint8_t > packed_data = packData( raw_data, big_endian_bytes ); - std::vector< uint8_t > unpacked_data; + std::vector raw_data = {-1, 3, 1, -1, -3, 1, 3, 1}; + std::vector packed_data = packData(raw_data, big_endian_bytes); + std::vector unpacked_data; - gr::top_block_sptr top_block = gr::make_top_block("unpack_2bit_samples_test"); + gr::top_block_sptr top_block = gr::make_top_block("Unpack2bitSamplesTest"); - gr::blocks::vector_source_b::sptr source = - gr::blocks::vector_source_b::make( packed_data ); + gr::blocks::vector_source_b::sptr source = + gr::blocks::vector_source_b::make(packed_data); - - boost::shared_ptr unpacker = + + boost::shared_ptr unpacker = make_unpack_2bit_samples(big_endian_bytes, - item_size, - big_endian_items ); + item_size, + big_endian_items); gr::blocks::stream_to_vector::sptr stov = - gr::blocks::stream_to_vector::make( item_size, raw_data.size() ); + gr::blocks::stream_to_vector::make(item_size, raw_data.size()); - gr::blocks::vector_sink_b::sptr sink = - gr::blocks::vector_sink_b::make( raw_data.size() ); + gr::blocks::vector_sink_b::sptr sink = + gr::blocks::vector_sink_b::make(raw_data.size()); top_block->connect(source, 0, unpacker, 0); - top_block->connect(unpacker, 0, stov, 0 ); + top_block->connect(unpacker, 0, stov, 0); top_block->connect(stov, 0, sink, 0); top_block->run(); @@ -117,46 +119,45 @@ TEST(Unpack_2bit_Samples_Test, CheckBigEndianByte) unpacked_data = sink->data(); - EXPECT_EQ( raw_data.size(), unpacked_data.size() ); - - for( unsigned int i = 0; i < raw_data.size(); ++i ) - { - EXPECT_EQ( raw_data[i], static_cast< int8_t >( unpacked_data[i] ) ); - } + EXPECT_EQ(raw_data.size(), unpacked_data.size()); + for (unsigned int i = 0; i < raw_data.size(); ++i) + { + EXPECT_EQ(raw_data[i], static_cast(unpacked_data[i])); + } } -TEST(Unpack_2bit_Samples_Test, CheckLittleEndianByte) +TEST(Unpack2bitSamplesTest, CheckLittleEndianByte) { bool big_endian_bytes = false; size_t item_size = 1; bool big_endian_items = false; - std::vector< int8_t > raw_data = { -1, 3, 1, -1, -3, 1, 3, 1 }; - std::vector< uint8_t > packed_data = packData( raw_data, big_endian_bytes ); - std::vector< uint8_t > unpacked_data; + std::vector raw_data = {-1, 3, 1, -1, -3, 1, 3, 1}; + std::vector packed_data = packData(raw_data, big_endian_bytes); + std::vector unpacked_data; - gr::top_block_sptr top_block = gr::make_top_block("unpack_2bit_samples_test"); + gr::top_block_sptr top_block = gr::make_top_block("Unpack2bitSamplesTest"); - gr::blocks::vector_source_b::sptr source = - gr::blocks::vector_source_b::make( packed_data ); + gr::blocks::vector_source_b::sptr source = + gr::blocks::vector_source_b::make(packed_data); - - boost::shared_ptr unpacker = + + boost::shared_ptr unpacker = make_unpack_2bit_samples(big_endian_bytes, - item_size, - big_endian_items ); + item_size, + big_endian_items); gr::blocks::stream_to_vector::sptr stov = - gr::blocks::stream_to_vector::make( item_size, raw_data.size() ); + gr::blocks::stream_to_vector::make(item_size, raw_data.size()); - gr::blocks::vector_sink_b::sptr sink = - gr::blocks::vector_sink_b::make( raw_data.size() ); + gr::blocks::vector_sink_b::sptr sink = + gr::blocks::vector_sink_b::make(raw_data.size()); top_block->connect(source, 0, unpacker, 0); - top_block->connect(unpacker, 0, stov, 0 ); + top_block->connect(unpacker, 0, stov, 0); top_block->connect(stov, 0, sink, 0); top_block->run(); @@ -164,67 +165,65 @@ TEST(Unpack_2bit_Samples_Test, CheckLittleEndianByte) unpacked_data = sink->data(); - EXPECT_EQ( raw_data.size(), unpacked_data.size() ); - - for( unsigned int i = 0; i < raw_data.size(); ++i ) - { - EXPECT_EQ( raw_data[i], static_cast< int8_t >( unpacked_data[i] ) ); - } + EXPECT_EQ(raw_data.size(), unpacked_data.size()); + for (unsigned int i = 0; i < raw_data.size(); ++i) + { + EXPECT_EQ(raw_data[i], static_cast(unpacked_data[i])); + } } -TEST(Unpack_2bit_Samples_Test, CheckBigEndianShortBigEndianByte) +TEST(Unpack2bitSamplesTest, CheckBigEndianShortBigEndianByte) { bool big_endian_bytes = true; size_t item_size = 2; bool big_endian_items = true; - std::vector< int8_t > raw_data = { -1, 3, 1, -1, -3, 1, 3, 1 }; - std::vector< uint8_t > packed_data = packData( raw_data, big_endian_bytes ); + std::vector raw_data = {-1, 3, 1, -1, -3, 1, 3, 1}; + std::vector packed_data = packData(raw_data, big_endian_bytes); // change the order of each pair of bytes: - for( unsigned int ii = 0; ii < packed_data.size(); ii+=item_size ) - { - unsigned int kk = ii + item_size - 1; - unsigned int jj = ii; - while( kk > jj ) + for (unsigned int ii = 0; ii < packed_data.size(); ii += item_size) { - uint8_t tmp = packed_data[jj]; - packed_data[jj] = packed_data[kk]; - packed_data[kk] = tmp; - --kk; - ++jj; + unsigned int kk = ii + item_size - 1; + unsigned int jj = ii; + while (kk > jj) + { + uint8_t tmp = packed_data[jj]; + packed_data[jj] = packed_data[kk]; + packed_data[kk] = tmp; + --kk; + ++jj; + } } - } // Now create a new big endian buffer: - std::vector< int16_t > packed_data_short( - reinterpret_cast< int16_t *>( &packed_data[0] ), - reinterpret_cast< int16_t * >( &packed_data[0] ) - + packed_data.size()/item_size); - - std::vector< uint8_t > unpacked_data; + std::vector packed_data_short( + reinterpret_cast(&packed_data[0]), + reinterpret_cast(&packed_data[0]) + packed_data.size() / item_size); - gr::top_block_sptr top_block = gr::make_top_block("unpack_2bit_samples_test"); + std::vector unpacked_data; - gr::blocks::vector_source_s::sptr source = - gr::blocks::vector_source_s::make( packed_data_short ); + gr::top_block_sptr top_block = gr::make_top_block("Unpack2bitSamplesTest"); - - boost::shared_ptr unpacker = + gr::blocks::vector_source_s::sptr source = + gr::blocks::vector_source_s::make(packed_data_short); + + + boost::shared_ptr unpacker = make_unpack_2bit_samples(big_endian_bytes, - item_size, - big_endian_items ); + item_size, + big_endian_items); gr::blocks::stream_to_vector::sptr stov = - gr::blocks::stream_to_vector::make( 1, raw_data.size() ); + gr::blocks::stream_to_vector::make(1, raw_data.size()); - gr::blocks::vector_sink_b::sptr sink = - gr::blocks::vector_sink_b::make( raw_data.size() ); + gr::blocks::vector_sink_b::sptr sink = + gr::blocks::vector_sink_b::make(raw_data.size()); top_block->connect(source, 0, unpacker, 0); - top_block->connect(unpacker, 0, stov, 0 ); + top_block->connect(unpacker, 0, stov, 0); top_block->connect(stov, 0, sink, 0); top_block->run(); @@ -232,67 +231,65 @@ TEST(Unpack_2bit_Samples_Test, CheckBigEndianShortBigEndianByte) unpacked_data = sink->data(); - EXPECT_EQ( raw_data.size(), unpacked_data.size() ); - - for( unsigned int i = 0; i < raw_data.size(); ++i ) - { - EXPECT_EQ( raw_data[i], static_cast< int8_t >( unpacked_data[i] ) ); - } + EXPECT_EQ(raw_data.size(), unpacked_data.size()); + for (unsigned int i = 0; i < raw_data.size(); ++i) + { + EXPECT_EQ(raw_data[i], static_cast(unpacked_data[i])); + } } -TEST(Unpack_2bit_Samples_Test, CheckBigEndianShortLittleEndianByte) +TEST(Unpack2bitSamplesTest, CheckBigEndianShortLittleEndianByte) { bool big_endian_bytes = false; size_t item_size = 2; bool big_endian_items = true; - std::vector< int8_t > raw_data = { -1, 3, 1, -1, -3, 1, 3, 1 }; - std::vector< uint8_t > packed_data = packData( raw_data, big_endian_bytes ); + std::vector raw_data = {-1, 3, 1, -1, -3, 1, 3, 1}; + std::vector packed_data = packData(raw_data, big_endian_bytes); // change the order of each pair of bytes: - for( unsigned int ii = 0; ii < packed_data.size(); ii+=item_size ) - { - unsigned int kk = ii + item_size - 1; - unsigned int jj = ii; - while( kk > jj ) + for (unsigned int ii = 0; ii < packed_data.size(); ii += item_size) { - uint8_t tmp = packed_data[jj]; - packed_data[jj] = packed_data[kk]; - packed_data[kk] = tmp; - --kk; - ++jj; + unsigned int kk = ii + item_size - 1; + unsigned int jj = ii; + while (kk > jj) + { + uint8_t tmp = packed_data[jj]; + packed_data[jj] = packed_data[kk]; + packed_data[kk] = tmp; + --kk; + ++jj; + } } - } // Now create a new big endian buffer: - std::vector< int16_t > packed_data_short( - reinterpret_cast< int16_t *>( &packed_data[0] ), - reinterpret_cast< int16_t * >( &packed_data[0] ) - + packed_data.size()/item_size); - - std::vector< uint8_t > unpacked_data; + std::vector packed_data_short( + reinterpret_cast(&packed_data[0]), + reinterpret_cast(&packed_data[0]) + packed_data.size() / item_size); - gr::top_block_sptr top_block = gr::make_top_block("unpack_2bit_samples_test"); + std::vector unpacked_data; - gr::blocks::vector_source_s::sptr source = - gr::blocks::vector_source_s::make( packed_data_short ); + gr::top_block_sptr top_block = gr::make_top_block("Unpack2bitSamplesTest"); - - boost::shared_ptr unpacker = + gr::blocks::vector_source_s::sptr source = + gr::blocks::vector_source_s::make(packed_data_short); + + + boost::shared_ptr unpacker = make_unpack_2bit_samples(big_endian_bytes, - item_size, - big_endian_items ); + item_size, + big_endian_items); gr::blocks::stream_to_vector::sptr stov = - gr::blocks::stream_to_vector::make( 1, raw_data.size() ); + gr::blocks::stream_to_vector::make(1, raw_data.size()); - gr::blocks::vector_sink_b::sptr sink = - gr::blocks::vector_sink_b::make( raw_data.size() ); + gr::blocks::vector_sink_b::sptr sink = + gr::blocks::vector_sink_b::make(raw_data.size()); top_block->connect(source, 0, unpacker, 0); - top_block->connect(unpacker, 0, stov, 0 ); + top_block->connect(unpacker, 0, stov, 0); top_block->connect(stov, 0, sink, 0); top_block->run(); @@ -300,11 +297,10 @@ TEST(Unpack_2bit_Samples_Test, CheckBigEndianShortLittleEndianByte) unpacked_data = sink->data(); - EXPECT_EQ( raw_data.size(), unpacked_data.size() ); - - for( unsigned int i = 0; i < raw_data.size(); ++i ) - { - EXPECT_EQ( raw_data[i], static_cast< int8_t >( unpacked_data[i] ) ); - } + EXPECT_EQ(raw_data.size(), unpacked_data.size()); + for (unsigned int i = 0; i < raw_data.size(); ++i) + { + EXPECT_EQ(raw_data[i], static_cast(unpacked_data[i])); + } } diff --git a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc new file mode 100644 index 000000000..748811a20 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc @@ -0,0 +1,288 @@ +/*! + * \file galileo_fnav_inav_decoder_test.cc + * \brief This class implements the unit test for the Galileo FNAV and INAV frames + * according to the Galileo ICD + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "convolutional.h" +#include "galileo_fnav_message.h" +#include "galileo_navigation_message.h" +#include +#include +#include +#include +#include +#include +#include + + +class Galileo_FNAV_INAV_test : public ::testing::Test +{ +public: + Galileo_Navigation_Message INAV_decoder; + Galileo_Fnav_Message FNAV_decoder; + // vars for Viterbi decoder + int32_t *out0, *out1, *state0, *state1; + int32_t g_encoder[2]; + const int32_t nn = 2; // Coding rate 1/n + const int32_t KK = 7; // Constraint Length + int32_t mm = KK - 1; + int32_t flag_even_word_arrived; + void viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits, int32_t _datalength) + { + Viterbi(page_part_bits, out0, state0, out1, state1, + page_part_symbols, KK, nn, _datalength); + } + + + void deinterleaver(int32_t rows, int32_t cols, double *in, double *out) + { + for (int32_t r = 0; r < rows; r++) + { + for (int32_t c = 0; c < cols; c++) + { + out[c * rows + r] = in[r * cols + c]; + } + } + } + + + bool decode_INAV_word(double *page_part_symbols, int32_t frame_length) + { + // 1. De-interleave + double *page_part_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180º + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_part_symbols_deint[i] = -page_part_symbols_deint[i]; + } + } + + int32_t *page_part_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + + const int32_t CodeLength = 240; + int32_t DataLength = (CodeLength / nn) - mm; + viterbi_decoder(page_part_symbols_deint, page_part_bits, DataLength); + volk_gnsssdr_free(page_part_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < (frame_length / 2); i++) + { + if (page_part_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + + bool crc_ok = false; + if (page_part_bits[0] == 1) + { + // DECODE COMPLETE WORD (even + odd) and TEST CRC + INAV_decoder.split_page(page_String, flag_even_word_arrived); + if (INAV_decoder.flag_CRC_test == true) + { + std::cout << "Galileo E1 INAV PAGE CRC correct \n"; + //std::cout << "Galileo E1 CRC correct on channel " << d_channel << " from satellite " << d_satellite << std::endl; + crc_ok = true; + } + flag_even_word_arrived = 0; + } + else + { + // STORE HALF WORD (even page) + INAV_decoder.split_page(page_String.c_str(), flag_even_word_arrived); + flag_even_word_arrived = 1; + } + volk_gnsssdr_free(page_part_bits); + return crc_ok; + } + + bool decode_FNAV_word(double *page_symbols, int32_t frame_length) + { + // 1. De-interleave + double *page_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_FNAV_INTERLEAVER_ROWS, GALILEO_FNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180 + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_symbols_deint[i] = -page_symbols_deint[i]; + } + } + int32_t *page_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + + const int32_t CodeLength = 488; + int32_t DataLength = (CodeLength / nn) - mm; + viterbi_decoder(page_symbols_deint, page_bits, DataLength); + + volk_gnsssdr_free(page_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < frame_length; i++) + { + if (page_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + volk_gnsssdr_free(page_bits); + + // DECODE COMPLETE WORD (even + odd) and TEST CRC + FNAV_decoder.split_page(page_String); + if (FNAV_decoder.flag_CRC_test == true) + { + std::cout << "Galileo E5a FNAV PAGE CRC correct \n"; + return true; + } + else + { + return false; + } + } + + Galileo_FNAV_INAV_test() + { + // vars for Viterbi decoder + int32_t max_states = 1 << mm; // 2^mm + g_encoder[0] = 121; // Polynomial G1 + g_encoder[1] = 91; // Polynomial G2 + out0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + out1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + // create appropriate transition matrices + nsc_transit(out0, state0, 0, g_encoder, KK, nn); + nsc_transit(out1, state1, 1, g_encoder, KK, nn); + flag_even_word_arrived = 0; + } + + ~Galileo_FNAV_INAV_test() + { + volk_gnsssdr_free(out0); + volk_gnsssdr_free(out1); + volk_gnsssdr_free(state0); + volk_gnsssdr_free(state1); + } +}; + +TEST_F(Galileo_FNAV_INAV_test, ValidationOfResults) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + start = std::chrono::system_clock::now(); + int repetitions = 10; + // FNAV FULLY ENCODED FRAME + double FNAV_frame[488] = {-1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, + -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, + -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, + -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, + -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, + -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, + -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, + 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, + -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, + 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, + -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, + 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, + 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1}; + + ASSERT_NO_THROW({ + for (int n = 0; n < repetitions; n++) + { + EXPECT_EQ(decode_FNAV_word(&FNAV_frame[0], 488), true); + } + }) << "Exception during FNAV frame decoding"; + + + // INAV FULLY ENCODED FRAME + double INAV_frame_even[240] = {-1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, + -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, + 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, + -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1}; + + double INAV_frame_odd[240] = {1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, + 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, + -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, + 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, + -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, + 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, + -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, + -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, + 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1}; + + ASSERT_NO_THROW({ + for (int n = 0; n < repetitions; n++) + { + decode_INAV_word(&INAV_frame_even[0], 240); + EXPECT_EQ(decode_INAV_word(&INAV_frame_odd[0], 240), true); + } + }) << "Exception during INAV frame decoding"; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + std::cout << "Galileo FNAV/INAV Test completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc index 798728ef6..4f5da024e 100644 --- a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc @@ -1,13 +1,13 @@ /*! * \file gps_l1_ca_dll_pll_tracking_test.cc - * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * \brief This class implements a telemetry decoder test for GPS_L1_CA_Telemetry_Decoder * implementation based on some input parameters. * \author Javier Arribas, 2015. jarribas(at)cttc.es * * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,43 +25,42 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else #include +#endif +#include "GPS_L1_CA.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_synchro.h" +#include "gps_l1_ca_dll_pll_c_aid_tracking.h" +#include "gps_l1_ca_dll_pll_tracking.h" +#include "gps_l1_ca_telemetry_decoder.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "telemetry_decoder_interface.h" +#include "tlm_dump_reader.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_true_obs_reader.h" #include #include #include #include -#include "GPS_L1_CA.h" -#include "gnss_block_factory.h" -#include "gnss_block_interface.h" -#include "tracking_interface.h" -#include "telemetry_decoder_interface.h" -#include "in_memory_configuration.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_telemetry_decoder.h" -#include "tracking_true_obs_reader.h" -#include "tracking_dump_reader.h" -#include "tlm_dump_reader.h" -#include "gps_l1_ca_dll_pll_tracking.h" -#include "gps_l1_ca_dll_pll_c_aid_tracking.h" -#include "signal_generator_flags.h" // ######## GNURADIO BLOCK MESSAGE RECEVER FOR TRACKING MESSAGES ######### @@ -80,8 +79,7 @@ private: public: int rx_message; - ~GpsL1CADllPllTelemetryDecoderTest_msg_rx(); //!< Default destructor - + ~GpsL1CADllPllTelemetryDecoderTest_msg_rx(); //!< Default destructor }; GpsL1CADllPllTelemetryDecoderTest_msg_rx_sptr GpsL1CADllPllTelemetryDecoderTest_msg_rx_make() @@ -92,19 +90,18 @@ GpsL1CADllPllTelemetryDecoderTest_msg_rx_sptr GpsL1CADllPllTelemetryDecoderTest_ void GpsL1CADllPllTelemetryDecoderTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CADllPllTelemetryDecoderTest_msg_rx::GpsL1CADllPllTelemetryDecoderTest_msg_rx() : - gr::block("GpsL1CADllPllTelemetryDecoderTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +GpsL1CADllPllTelemetryDecoderTest_msg_rx::GpsL1CADllPllTelemetryDecoderTest_msg_rx() : gr::block("GpsL1CADllPllTelemetryDecoderTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CADllPllTelemetryDecoderTest_msg_rx::msg_handler_events, this, _1)); @@ -112,7 +109,8 @@ GpsL1CADllPllTelemetryDecoderTest_msg_rx::GpsL1CADllPllTelemetryDecoderTest_msg_ } GpsL1CADllPllTelemetryDecoderTest_msg_rx::~GpsL1CADllPllTelemetryDecoderTest_msg_rx() -{} +{ +} // ########################################################### @@ -134,8 +132,7 @@ private: public: int rx_message; - ~GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx(); //!< Default destructor - + ~GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx(); //!< Default destructor }; GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_sptr GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_make() @@ -146,19 +143,18 @@ GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_sptr GpsL1CADllPllTelemetryDecoderT void GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx() : - gr::block("GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx() : gr::block("GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::msg_handler_events, this, _1)); @@ -166,15 +162,15 @@ GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::GpsL1CADllPllTelemetryDecoderTest_ } GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx::~GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx() -{} +{ +} // ########################################################### -class GpsL1CATelemetryDecoderTest: public ::testing::Test +class GpsL1CATelemetryDecoderTest : public ::testing::Test { - public: std::string generator_binary; std::string p1; @@ -183,17 +179,17 @@ public: std::string p4; std::string p5; - const int baseband_sampling_freq = FLAGS_fs_gen_hz; + const int baseband_sampling_freq = FLAGS_fs_gen_sps; std::string filename_rinex_obs = FLAGS_filename_rinex_obs; std::string filename_raw_data = FLAGS_filename_raw_data; int configure_generator(); int generate_signal(); - void check_results(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value); + void check_results(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value); GpsL1CATelemetryDecoderTest() { @@ -204,7 +200,8 @@ public: } ~GpsL1CATelemetryDecoderTest() - {} + { + } void configure_receiver(); @@ -215,13 +212,14 @@ public: size_t item_size; }; + int GpsL1CATelemetryDecoderTest::configure_generator() { // Configure signal generator generator_binary = FLAGS_generator_binary; p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; - if(FLAGS_dynamic_position.empty()) + if (FLAGS_dynamic_position.empty()) { p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); } @@ -229,9 +227,9 @@ int GpsL1CATelemetryDecoderTest::configure_generator() { p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); } - p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output - p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples - p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] return 0; } @@ -240,7 +238,7 @@ int GpsL1CATelemetryDecoderTest::generate_signal() { int child_status; - char *const parmList[] = { &generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL }; + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL}; int pid; if ((pid = fork()) == -1) @@ -254,7 +252,7 @@ int GpsL1CATelemetryDecoderTest::generate_signal() waitpid(pid, &child_status, 0); - std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; return 0; } @@ -267,36 +265,40 @@ void GpsL1CATelemetryDecoderTest::configure_receiver() signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = FLAGS_test_satellite_PRN; - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(baseband_sampling_freq)); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); // Set Tracking config->set_property("Tracking_1C.item_type", "gr_complex"); - config->set_property("Tracking_1C.if", "0"); config->set_property("Tracking_1C.dump", "true"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); config->set_property("Tracking_1C.pll_bw_hz", "20.0"); config->set_property("Tracking_1C.dll_bw_hz", "1.5"); config->set_property("Tracking_1C.early_late_space_chips", "0.5"); - - config->set_property("TelemetryDecoder_1C.dump","true"); - config->set_property("TelemetryDecoder_1C.decimation_factor","1"); - + config->set_property("Tracking_1C.unified", "true"); + config->set_property("TelemetryDecoder_1C.dump", "true"); } -void GpsL1CATelemetryDecoderTest::check_results(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value) + +void GpsL1CATelemetryDecoderTest::check_results(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value) { //1. True value interpolation to match the measurement times - arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); //2. RMSE - arma::vec err; + //arma::vec err = meas_value - true_value_interp + 0.001; + arma::vec err = meas_value - true_value_interp; // - 0.001; - err = meas_value - true_value_interp; arma::vec err2 = arma::square(err); double rmse = sqrt(arma::mean(err2)); @@ -309,24 +311,37 @@ void GpsL1CATelemetryDecoderTest::check_results(arma::vec true_time_s, double min_error = arma::min(err); //5. report - + std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(10) << "TLM TOW RMSE=" << rmse << ", mean=" << error_mean - << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Chips]" << std::endl; + << ", stdev=" << sqrt(error_var) + << " (max,min)=" << max_error + << "," << min_error + << " [Seconds]" << std::endl; + std::cout.precision(ss); + ASSERT_LT(rmse, 0.3E-6); + ASSERT_LT(error_mean, 0.3E-6); + ASSERT_GT(error_mean, -0.3E-6); + ASSERT_LT(error_var, 0.3E-6); + ASSERT_LT(max_error, 0.5E-6); + ASSERT_GT(min_error, -0.5E-6); } + TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) { // Configure the signal generator configure_generator(); // Generate signal raw signal samples and observations RINEX file - generate_signal(); + if (FLAGS_disable_generator == false) + { + generate_signal(); + } - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); configure_receiver(); @@ -342,7 +357,7 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) { throw std::exception(); }; - }) << "Failure opening true observables file" << std::endl; + }) << "Failure opening true observables file"; top_block = gr::make_top_block("Telemetry_Decoder test"); std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); @@ -353,10 +368,10 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) // load acquisition data based on the first epoch of the true observations ASSERT_NO_THROW({ if (true_obs_data.read_binary_obs() == false) - { - throw std::exception(); - }; - })<< "Failure reading true observables file" << std::endl; + { + throw std::exception(); + }; + }) << "Failure reading true observables file"; //restart the epoch counter true_obs_data.restart(); @@ -366,49 +381,48 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz; gnss_synchro.Acq_samplestamp_samples = 0; - std::shared_ptr tlm(new GpsL1CaTelemetryDecoder(config.get(), "TelemetryDecoder_1C",1, 1)); + std::shared_ptr tlm(new GpsL1CaTelemetryDecoder(config.get(), "TelemetryDecoder_1C", 1, 1)); tlm->set_channel(0); boost::shared_ptr tlm_msg_rx = GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_make(); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->connect(top_block); - }) << "Failure connecting tracking to the top_block." << std::endl; + }) << "Failure connecting tracking to the top_block."; - ASSERT_NO_THROW( { - std::string file = "./" + filename_raw_data; - const char * file_name = file.c_str(); + ASSERT_NO_THROW({ + std::string file = "./" + filename_raw_data; + const char* file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); - gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, tlm->get_left_block(), 0); top_block->connect(tlm->get_right_block(), 0, sink, 0); top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks." << std::endl; + }) << "Failure connecting the blocks."; tracking->start_tracking(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; //check results //load the true values - long int nepoch = true_obs_data.num_epochs(); + int64_t nepoch = true_obs_data.num_epochs(); std::cout << "True observation epochs=" << nepoch << std::endl; arma::vec true_timestamp_s = arma::zeros(nepoch, 1); @@ -417,16 +431,16 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1); arma::vec true_tow_s = arma::zeros(nepoch, 1); - long int epoch_counter = 0; - while(true_obs_data.read_binary_obs()) - { - true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; - true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; - true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; - true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; - true_tow_s(epoch_counter) = true_obs_data.tow; - epoch_counter++; - } + int64_t epoch_counter = 0; + while (true_obs_data.read_binary_obs()) + { + true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; + true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; + true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; + true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; + true_tow_s(epoch_counter) = true_obs_data.tow; + epoch_counter++; + } //load the measured values tlm_dump_reader tlm_dump; @@ -435,7 +449,7 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) { throw std::exception(); }; - }) << "Failure opening telemetry dump file" << std::endl; + }) << "Failure opening telemetry dump file"; nepoch = tlm_dump.num_epochs(); std::cout << "Measured observation epochs=" << nepoch << std::endl; @@ -445,22 +459,21 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) arma::vec tlm_tow_s = arma::zeros(nepoch, 1); epoch_counter = 0; - while(tlm_dump.read_binary_obs()) - { - tlm_timestamp_s(epoch_counter) = tlm_dump.Prn_timestamp_ms / 1000.0; - tlm_TOW_at_Preamble(epoch_counter) = tlm_dump.d_TOW_at_Preamble; - tlm_tow_s(epoch_counter) = tlm_dump.TOW_at_current_symbol; - epoch_counter++; - } + while (tlm_dump.read_binary_obs()) + { + tlm_timestamp_s(epoch_counter) = static_cast(tlm_dump.Tracking_sample_counter) / static_cast(baseband_sampling_freq); + tlm_TOW_at_Preamble(epoch_counter) = tlm_dump.d_TOW_at_Preamble; + tlm_tow_s(epoch_counter) = tlm_dump.TOW_at_current_symbol; + epoch_counter++; + } //Cut measurement initial transitory of the measurements arma::uvec initial_meas_point = arma::find(tlm_tow_s >= true_tow_s(0), 1, "first"); - + ASSERT_EQ(initial_meas_point.is_empty(), false); tlm_timestamp_s = tlm_timestamp_s.subvec(initial_meas_point(0), tlm_timestamp_s.size() - 1); tlm_tow_s = tlm_tow_s.subvec(initial_meas_point(0), tlm_tow_s.size() - 1); check_results(true_timestamp_s, true_tow_s, tlm_timestamp_s, tlm_tow_s); - std::cout << "Test completed in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Test completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/bayesian_estimation_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/bayesian_estimation_test.cc new file mode 100644 index 000000000..dd7d0398b --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/bayesian_estimation_test.cc @@ -0,0 +1,69 @@ +/*! + * \file bayesian_estimation_positivity_test.cc + * \brief This file implements timing tests for the Bayesian covariance estimator + * \author Gerald LaMountain, 20168. gerald(at)ece.neu.edu + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "bayesian_estimation.h" +#include +#include +#include + +#define BAYESIAN_TEST_N_TRIALS 100 +#define BAYESIAN_TEST_ITER 10000 + +TEST(BayesianEstimationPositivityTest, BayesianPositivityTest) +{ + Bayesian_estimator bayes; + arma::vec bayes_mu = arma::zeros(1, 1); + int bayes_nu = 0; + int bayes_kappa = 0; + arma::mat bayes_Psi = arma::ones(1, 1); + arma::vec input = arma::zeros(1, 1); + + //--- Perform initializations ------------------------------ + + std::random_device r; + std::default_random_engine e1(r()); + std::normal_distribution normal_dist(0, 5); + + for (int k = 0; k < BAYESIAN_TEST_N_TRIALS; k++) + { + bayes.init(bayes_mu, bayes_kappa, bayes_nu, bayes_Psi); + + for (int n = 0; n < BAYESIAN_TEST_ITER; n++) + { + input(0) = static_cast(normal_dist(e1)); + bayes.update_sequential(input); + + arma::mat output = bayes.get_Psi_est(); + double output0 = output(0, 0); + ASSERT_EQ(output0 > 0.0, true); + } + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_real_codes_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_real_codes_test.cc new file mode 100644 index 000000000..68eae1518 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_real_codes_test.cc @@ -0,0 +1,174 @@ +/*! + * \file cpu_multicorrelator_real_codes_test.cc + * \brief This file implements timing tests for the FFT. + * \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "cpu_multicorrelator_real_codes.h" +#include "gps_sdr_signal_processing.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +DEFINE_int32(cpu_multicorrelator_real_codes_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test"); +DEFINE_int32(cpu_multicorrelator_real_codes_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test"); + +void run_correlator_cpu_real_codes(cpu_multicorrelator_real_codes* correlator, + float d_rem_carrier_phase_rad, + float d_carrier_phase_step_rad, + float d_code_phase_step_chips, + float d_code_phase_rate_step_chips, + float d_rem_code_phase_chips, + int correlation_size) +{ + for (int k = 0; k < FLAGS_cpu_multicorrelator_real_codes_iterations_test; k++) + { + correlator->Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_code_phase_step_chips, + d_rem_code_phase_chips, + d_code_phase_rate_step_chips, + correlation_size); + } +} + + +TEST(CpuMulticorrelatorRealCodesTest, MeasureExecutionTime) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int max_threads = FLAGS_cpu_multicorrelator_real_codes_max_threads_test; + std::vector thread_pool; + cpu_multicorrelator_real_codes* correlator_pool[max_threads]; + unsigned int correlation_sizes[3] = {2048, 4096, 8192}; + double execution_times[3]; + + float* d_ca_code; + gr_complex* in_cpu; + gr_complex* d_correlator_outs; + + int d_n_correlator_taps = 3; + int d_vector_length = correlation_sizes[2]; //max correlation size to allocate all the necessary memory + float* d_local_code_shift_chips; + + //allocate host memory + // Get space for a vector with the C/A code replica sampled 1x/chip + d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment())); + in_cpu = static_cast(volk_gnsssdr_malloc(2 * d_vector_length * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + // Set TAPs delay values [chips] + float d_early_late_spc_chips = 0.5; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + //--- Perform initializations ------------------------------ + + //local code resampler on GPU + // generate local reference (1 sample per chip) + gps_l1_ca_code_gen_float(d_ca_code, 1, 0); + // generate inut signal + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_real_distribution uniform_dist(0, 1); + for (int n = 0; n < 2 * d_vector_length; n++) + { + in_cpu[n] = std::complex(uniform_dist(e1), uniform_dist(e1)); + } + + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n] = new cpu_multicorrelator_real_codes(); + correlator_pool[n]->init(d_vector_length, d_n_correlator_taps); + correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_cpu); + correlator_pool[n]->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + } + + float d_rem_carrier_phase_rad = 0.0; + float d_carrier_phase_step_rad = 0.1; + float d_code_phase_step_chips = 0.3; + float d_code_phase_rate_step_chips = 0.00001; + float d_rem_code_phase_chips = 0.4; + + EXPECT_NO_THROW( + for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) { + for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++) + { + std::cout << "Running " << current_max_threads << " concurrent correlators" << std::endl; + start = std::chrono::system_clock::now(); + //create the concurrent correlator threads + for (int current_thread = 0; current_thread < current_max_threads; current_thread++) + { + thread_pool.push_back(std::thread(run_correlator_cpu_real_codes, + correlator_pool[current_thread], + d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_code_phase_step_chips, + d_code_phase_rate_step_chips, + d_rem_code_phase_chips, + correlation_sizes[correlation_sizes_idx])); + } + //wait the threads to finish they work and destroy the thread objects + for (auto& t : thread_pool) + { + t.join(); + } + thread_pool.clear(); + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast(FLAGS_cpu_multicorrelator_real_codes_iterations_test); + std::cout << "CPU Multicorrelator (real codes) execution time for length=" << correlation_sizes[correlation_sizes_idx] + << " : " << execution_times[correlation_sizes_idx] << " [s]" << std::endl; + } + }); + + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + volk_gnsssdr_free(d_ca_code); + volk_gnsssdr_free(in_cpu); + + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n]->free(); + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc index e567953c5..706c6fe45 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/cpu_multicorrelator_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,55 +24,61 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include +#include "GPS_L1_CA.h" #include "cpu_multicorrelator.h" #include "gps_sdr_signal_processing.h" -#include "GPS_L1_CA.h" +#include +#include +#include +#include +#include +#include +#include +#include -DEFINE_int32(cpu_multicorrelator_iterations_test, 1000, "Number of averaged iterations in CPU multicorrelator test timing test"); +DEFINE_int32(cpu_multicorrelator_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test"); DEFINE_int32(cpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test"); void run_correlator_cpu(cpu_multicorrelator* correlator, - float d_rem_carrier_phase_rad, - float d_carrier_phase_step_rad, - float d_code_phase_step_chips, - float d_rem_code_phase_chips, - int correlation_size) + float d_rem_carrier_phase_rad, + float d_carrier_phase_step_rad, + float d_code_phase_step_chips, + float d_rem_code_phase_chips, + int correlation_size) { - for(int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++) - { - correlator->Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, - d_carrier_phase_step_rad, - d_code_phase_step_chips, - d_rem_code_phase_chips, - correlation_size); - } + for (int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++) + { + correlator->Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_code_phase_step_chips, + d_rem_code_phase_chips, + correlation_size); + } } -TEST(CPU_multicorrelator_test, MeasureExecutionTime) + +TEST(CpuMulticorrelatorTest, MeasureExecutionTime) { - struct timeval tv; - int max_threads=FLAGS_cpu_multicorrelator_max_threads_test; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int max_threads = FLAGS_cpu_multicorrelator_max_threads_test; std::vector thread_pool; cpu_multicorrelator* correlator_pool[max_threads]; - unsigned int correlation_sizes [3] = { 2048, 4096, 8192}; - double execution_times [3]; + unsigned int correlation_sizes[3] = {2048, 4096, 8192}; + double execution_times[3]; gr_complex* d_ca_code; gr_complex* in_cpu; gr_complex* d_correlator_outs; - int d_n_correlator_taps=3; - int d_vector_length=correlation_sizes[2]; //max correlation size to allocate all the necessary memory + int d_n_correlator_taps = 3; + int d_vector_length = correlation_sizes[2]; //max correlation size to allocate all the necessary memory float* d_local_code_shift_chips; //allocate host memory @@ -81,16 +87,16 @@ TEST(CPU_multicorrelator_test, MeasureExecutionTime) in_cpu = static_cast(volk_gnsssdr_malloc(2 * d_vector_length * sizeof(gr_complex), volk_gnsssdr_get_alignment())); // correlator outputs (scalar) - d_n_correlator_taps = 3; // Early, Prompt, and Late - d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); for (int n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0,0); - } - d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps*sizeof(float), volk_gnsssdr_get_alignment())); + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); // Set TAPs delay values [chips] - float d_early_late_spc_chips=0.5; - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + float d_early_late_spc_chips = 0.5; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; @@ -100,65 +106,65 @@ TEST(CPU_multicorrelator_test, MeasureExecutionTime) // generate local reference (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, 1, 0); // generate inut signal - for (int n=0;n<2*d_vector_length;n++) - { - in_cpu[n]=std::complex(static_cast (rand())/static_cast(RAND_MAX),static_cast (rand())/static_cast(RAND_MAX)); - } + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_real_distribution uniform_dist(0, 1); + for (int n = 0; n < 2 * d_vector_length; n++) + { + in_cpu[n] = std::complex(uniform_dist(e1), uniform_dist(e1)); + } - for (int n=0;ninit(d_vector_length, d_n_correlator_taps); - correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_cpu); - correlator_pool[n]->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); - } + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n] = new cpu_multicorrelator(); + correlator_pool[n]->init(d_vector_length, d_n_correlator_taps); + correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_cpu); + correlator_pool[n]->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips); + } - float d_rem_carrier_phase_rad=0.0; - float d_carrier_phase_step_rad=0.1; - float d_code_phase_step_chips=0.3; - float d_rem_code_phase_chips=0.4; + float d_rem_carrier_phase_rad = 0.0; + float d_carrier_phase_step_rad = 0.1; + float d_code_phase_step_chips = 0.3; + float d_rem_code_phase_chips = 0.4; EXPECT_NO_THROW( - for(int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) - { - for(int current_max_threads=1; current_max_threads<(max_threads+1); current_max_threads++) - { - std::cout<<"Running "<(FLAGS_cpu_multicorrelator_iterations_test); + std::cout << "CPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx] + << " : " << execution_times[correlation_sizes_idx] << " [s]" << std::endl; } - //wait the threads to finish they work and destroy the thread objects - for(auto &t : thread_pool){ - t.join(); - } - thread_pool.clear(); - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; - execution_times[correlation_sizes_idx] = static_cast(end - begin) / (1000000.0 * static_cast(FLAGS_cpu_multicorrelator_iterations_test)); - std::cout << "CPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx] << " : " << execution_times[correlation_sizes_idx] << " [s]" << std::endl; - - } - } - ); - + }); volk_gnsssdr_free(d_local_code_shift_chips); volk_gnsssdr_free(d_correlator_outs); volk_gnsssdr_free(d_ca_code); volk_gnsssdr_free(in_cpu); - for (int n=0;nfree(); - } + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n]->free(); + } } diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc index 14470d985..897257b93 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,31 +25,33 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "galileo_e1_dll_pll_veml_tracking.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" -#include "galileo_e1_dll_pll_veml_tracking.h" +#include "in_memory_configuration.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif - -class GalileoE1DllPllVemlTrackingInternalTest: public ::testing::Test +class GalileoE1DllPllVemlTrackingInternalTest : public ::testing::Test { protected: GalileoE1DllPllVemlTrackingInternalTest() @@ -62,8 +64,7 @@ protected: gnss_synchro = Gnss_Synchro(); } - ~GalileoE1DllPllVemlTrackingInternalTest() - {} + ~GalileoE1DllPllVemlTrackingInternalTest() = default; void init(); @@ -71,7 +72,7 @@ protected: gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; - Gnss_Synchro gnss_synchro; + Gnss_Synchro gnss_synchro{}; size_t item_size; bool stop; int message; @@ -86,24 +87,22 @@ void GalileoE1DllPllVemlTrackingInternalTest::init() signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 11; - config->set_property("GNSS-SDR.internal_fs_hz", "8000000"); - config->set_property("Tracking_Galileo.item_type", "gr_complex"); - config->set_property("Tracking_Galileo.dump", "false"); - config->set_property("Tracking_Galileo.dump_filename", "../data/veml_tracking_ch_"); - config->set_property("Tracking_Galileo.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking"); - config->set_property("Tracking_Galileo.early_late_space_chips", "0.15"); - config->set_property("Tracking_Galileo.very_early_late_space_chips", "0.6"); - config->set_property("Tracking_Galileo.pll_bw_hz", "30.0"); - config->set_property("Tracking_Galileo.dll_bw_hz", "2.0"); + config->set_property("GNSS-SDR.internal_fs_sps", "8000000"); + config->set_property("Tracking_1B.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking"); + config->set_property("Tracking_1B.item_type", "gr_complex"); + config->set_property("Tracking_1B.dump", "false"); + config->set_property("Tracking_1B.dump_filename", "../data/veml_tracking_ch_"); + config->set_property("Tracking_1B.early_late_space_chips", "0.15"); + config->set_property("Tracking_1B.very_early_late_space_chips", "0.6"); + config->set_property("Tracking_1B.pll_bw_hz", "30.0"); + config->set_property("Tracking_1B.dll_bw_hz", "2.0"); } - TEST_F(GalileoE1DllPllVemlTrackingInternalTest, Instantiate) { - init(); - auto tracking = factory->GetBlock(config, "Tracking", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); + auto tracking = factory->GetBlock(config, "Tracking_1B", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); EXPECT_STREQ("Galileo_E1_DLL_PLL_VEML_Tracking", tracking->implementation().c_str()); } @@ -112,26 +111,25 @@ TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ConnectAndRun) { int fs_in = 8000000; int nsamples = 40000000; - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); init(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Tracking test"); // Example using smart pointers and the block factory - std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_1B", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->connect(top_block); gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); @@ -139,64 +137,60 @@ TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ConnectAndRun) top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, sink, 0); - - }) << "Failure connecting the blocks of tracking test." << std::endl; + }) << "Failure connecting the blocks of tracking test."; tracking->start_tracking(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1000000 + tv.tv_usec; - top_block->run(); //Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); //Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Processed " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); // int num_samples = 40000000; // 4 Msps // unsigned int skiphead_sps = 24000000; // 4 Msps - int num_samples = 80000000; // 8 Msps - unsigned int skiphead_sps = 8000000; // 8 Msps + int num_samples = 80000000; // 8 Msps + unsigned int skiphead_sps = 8000000; // 8 Msps init(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Tracking test"); // Example using smart pointers and the block factory - std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_1B", "Galileo_E1_DLL_PLL_VEML_Tracking", 1, 1); std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); // gnss_synchro.Acq_delay_samples = 1753; // 4 Msps // gnss_synchro.Acq_doppler_hz = -9500; // 4 Msps - gnss_synchro.Acq_delay_samples = 17256; // 8 Msps - gnss_synchro.Acq_doppler_hz = -8750; // 8 Msps + gnss_synchro.Acq_delay_samples = 17256; // 8 Msps + gnss_synchro.Acq_doppler_hz = -8750; // 8 Msps gnss_synchro.Acq_samplestamp_samples = 0; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->connect(top_block); - }) << "Failure connecting tracking to the top_block." << std::endl; + }) << "Failure connecting tracking to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ std::string path = std::string(TEST_PATH); std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat"; - const char * file_name = file.c_str(); - gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex),file_name,false); + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); gr::blocks::skiphead::sptr skip_head = gr::blocks::skiphead::make(sizeof(gr_complex), skiphead_sps); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), num_samples, queue); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); @@ -204,17 +198,16 @@ TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ValidationOfResults) top_block->connect(skip_head, 0, valve, 0); top_block->connect(valve, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, sink, 0); - }) << "Failure connecting the blocks of tracking test." << std::endl; + }) << "Failure connecting the blocks of tracking test."; tracking->start_tracking(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Tracked " << num_samples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Tracked " << num_samples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc index 1ff2478b5..29ffe6edd 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,30 +25,34 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "galileo_e5a_dll_pll_tracking.h" #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" -#include "galileo_e5a_dll_pll_tracking.h" +#include "in_memory_configuration.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif -class GalileoE5aTrackingTest: public ::testing::Test +class GalileoE5aTrackingTest : public ::testing::Test { protected: GalileoE5aTrackingTest() @@ -62,7 +66,8 @@ protected: } ~GalileoE5aTrackingTest() - {} + { + } void init(); @@ -81,78 +86,75 @@ void GalileoE5aTrackingTest::init() { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'E'; - std::string signal = "5Q"; + std::string signal = "5X"; signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 11; - config->set_property("GNSS-SDR.internal_fs_hz", "32000000"); - config->set_property("Tracking_Galileo.item_type", "gr_complex"); - config->set_property("Tracking_Galileo.dump", "false"); - config->set_property("Tracking_Galileo.dump_filename", "../data/e5a_tracking_ch_"); - config->set_property("Tracking_Galileo.implementation", "Galileo_E5a_DLL_PLL_Tracking"); - config->set_property("Tracking_Galileo.early_late_space_chips", "0.5"); - config->set_property("Tracking_Galileo.order", "2"); - config->set_property("Tracking_Galileo.pll_bw_hz_init","20.0"); - config->set_property("Tracking_Galileo.pll_bw_hz", "5"); - config->set_property("Tracking_Galileo.dll_bw_hz_init","2.0"); - config->set_property("Tracking_Galileo.dll_bw_hz", "2"); - config->set_property("Tracking_Galileo.ti_ms", "1"); + config->set_property("GNSS-SDR.internal_fs_sps", "32000000"); + config->set_property("Tracking_5X.implementation", "Galileo_E5a_DLL_PLL_Tracking"); + config->set_property("Tracking_5X.item_type", "gr_complex"); + config->set_property("Tracking_5X.dump", "false"); + config->set_property("Tracking_5X.dump_filename", "../data/e5a_tracking_ch_"); + config->set_property("Tracking_5X.early_late_space_chips", "0.5"); + config->set_property("Tracking_5X.order", "2"); + config->set_property("Tracking_5X.pll_bw_hz", "20.0"); + config->set_property("Tracking_5X.dll_bw_hz", "5.0"); + config->set_property("Tracking_5X.pll_bw_narrow_hz", "2.0"); + config->set_property("Tracking_5X.pll_bw_narrow_hz", "2.0"); + config->set_property("Tracking_5X.ti_ms", "1"); } + TEST_F(GalileoE5aTrackingTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); int fs_in = 32000000; - int nsamples = 32000000*5; + int nsamples = 32000000 * 5; init(); queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Tracking test"); // Example using smart pointers and the block factory - std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", "Galileo_E5a_DLL_PLL_Tracking", 1, 1); + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_5X", "Galileo_E5a_DLL_PLL_Tracking", 1, 1); std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); //REAL - gnss_synchro.Acq_delay_samples = 10; // 32 Msps + gnss_synchro.Acq_delay_samples = 10; // 32 Msps // gnss_synchro.Acq_doppler_hz = 3500; // 32 Msps - gnss_synchro.Acq_doppler_hz = 2000; // 500 Hz resolution + gnss_synchro.Acq_doppler_hz = 2000; // 500 Hz resolution // gnss_synchro.Acq_samplestamp_samples = 98000; gnss_synchro.Acq_samplestamp_samples = 0; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->connect(top_block); - }) << "Failure connecting tracking to the top_block." << std::endl; + }) << "Failure connecting tracking to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); top_block->connect(source, 0, valve, 0); top_block->connect(valve, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, sink, 0); - - }) << "Failure connecting the blocks of tracking test." << std::endl; + }) << "Failure connecting the blocks of tracking test."; tracking->start_tracking(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; - std::cout << "Tracked " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc new file mode 100644 index 000000000..64c6df3b5 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc @@ -0,0 +1,209 @@ +/*! + * \file glonass_l1_ca_dll_pll_c_aid_tracking_test.cc + * \brief This class implements a tracking test for GLONASS_L1_CA_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_dll_pll_c_aid_tracking.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include "tracking_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GlonassL1CaDllPllCAidTrackingTest_msg_rx; + +typedef boost::shared_ptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr; + +GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make(); + +class GlonassL1CaDllPllCAidTrackingTest_msg_rx : public gr::block +{ +private: + friend GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GlonassL1CaDllPllCAidTrackingTest_msg_rx(); + +public: + int rx_message; + ~GlonassL1CaDllPllCAidTrackingTest_msg_rx(); //!< Default destructor +}; + +GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make() +{ + return GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr(new GlonassL1CaDllPllCAidTrackingTest_msg_rx()); +} + +void GlonassL1CaDllPllCAidTrackingTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +GlonassL1CaDllPllCAidTrackingTest_msg_rx::GlonassL1CaDllPllCAidTrackingTest_msg_rx() : gr::block("GlonassL1CaDllPllCAidTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GlonassL1CaDllPllCAidTrackingTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + +GlonassL1CaDllPllCAidTrackingTest_msg_rx::~GlonassL1CaDllPllCAidTrackingTest_msg_rx() +{ +} + + +// ########################################################### + + +class GlonassL1CaDllPllCAidTrackingTest : public ::testing::Test +{ +protected: + GlonassL1CaDllPllCAidTrackingTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GlonassL1CaDllPllCAidTrackingTest() + { + } + + void init(); + + gr::msg_queue::sptr queue; + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +void GlonassL1CaDllPllCAidTrackingTest::init() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "1G"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = 11; + + config->set_property("GNSS-SDR.internal_fs_sps", "6625000"); + config->set_property("Tracking_1G.implementation", "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking"); + config->set_property("Tracking_1G.item_type", "gr_complex"); + config->set_property("Tracking_1G.dump", "false"); + config->set_property("Tracking_1G.dump_filename", "./tracking_ch_"); + config->set_property("Tracking_1G.early_late_space_chips", "0.5"); + config->set_property("Tracking_1G.order", "2"); + config->set_property("Tracking_1G.pll_bw_hz", "2"); + config->set_property("Tracking_1G.dll_bw_hz", "0.5"); +} + + +TEST_F(GlonassL1CaDllPllCAidTrackingTest, ValidationOfResults) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int fs_in = 6625000; + int nsamples = fs_in * 4e-3 * 2; + + init(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Tracking test"); + std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1G", 1, 1); + boost::shared_ptr msg_rx = GlonassL1CaDllPllCAidTrackingTest_msg_rx_make(); + + gnss_synchro.Acq_delay_samples = 1343; + gnss_synchro.Acq_doppler_hz = -2750; + // gnss_synchro.Acq_doppler_hz = -2750; + gnss_synchro.Acq_samplestamp_samples = 0; + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + ASSERT_NO_THROW({ + gr::analog::sig_source_c::sptr sin_source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + std::string path = std::string(TEST_PATH); + std::string file = path + "signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin"; + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(file_source, 0, valve, 0); + top_block->connect(valve, 0, tracking->get_left_block(), 0); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of tracking test."; + + tracking->start_tracking(); + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + + // TODO: Verify tracking results + std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc new file mode 100644 index 000000000..2bf4f8938 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc @@ -0,0 +1,209 @@ +/*! + * \file glonass_l1_ca_dll_pll_tracking_test.cc + * \brief This class implements a tracking test for GLONASS_L1_CA_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com + * \author Luis Esteve, 2017. luis(at)epsilon-formacion.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_dll_pll_tracking.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "gnss_synchro.h" +#include "in_memory_configuration.h" +#include "tracking_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GlonassL1CaDllPllTrackingTest_msg_rx; + +typedef boost::shared_ptr GlonassL1CaDllPllTrackingTest_msg_rx_sptr; + +GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make(); + +class GlonassL1CaDllPllTrackingTest_msg_rx : public gr::block +{ +private: + friend GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GlonassL1CaDllPllTrackingTest_msg_rx(); + +public: + int rx_message; + ~GlonassL1CaDllPllTrackingTest_msg_rx(); //!< Default destructor +}; + +GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make() +{ + return GlonassL1CaDllPllTrackingTest_msg_rx_sptr(new GlonassL1CaDllPllTrackingTest_msg_rx()); +} + +void GlonassL1CaDllPllTrackingTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +GlonassL1CaDllPllTrackingTest_msg_rx::GlonassL1CaDllPllTrackingTest_msg_rx() : gr::block("GlonassL1CaDllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GlonassL1CaDllPllTrackingTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + +GlonassL1CaDllPllTrackingTest_msg_rx::~GlonassL1CaDllPllTrackingTest_msg_rx() +{ +} + + +// ########################################################### + + +class GlonassL1CaDllPllTrackingTest : public ::testing::Test +{ +protected: + GlonassL1CaDllPllTrackingTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GlonassL1CaDllPllTrackingTest() + { + } + + void init(); + + gr::msg_queue::sptr queue; + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +void GlonassL1CaDllPllTrackingTest::init() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'R'; + std::string signal = "1G"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = 11; + + config->set_property("GNSS-SDR.internal_fs_sps", "6625000"); + config->set_property("Tracking_1G.implementation", "GLONASS_L1_CA_DLL_PLL_Tracking"); + config->set_property("Tracking_1G.item_type", "gr_complex"); + config->set_property("Tracking_1G.dump", "false"); + config->set_property("Tracking_1G.dump_filename", "./tracking_ch_"); + config->set_property("Tracking_1G.early_late_space_chips", "0.5"); + config->set_property("Tracking_1G.order", "2"); + config->set_property("Tracking_1G.pll_bw_hz", "2"); + config->set_property("Tracking_1G.dll_bw_hz", "0.5"); +} + +TEST_F(GlonassL1CaDllPllTrackingTest, ValidationOfResults) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int fs_in = 6625000; + int nsamples = fs_in * 4e-3 * 2; + + init(); + queue = gr::msg_queue::make(0); + top_block = gr::make_top_block("Tracking test"); + std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1G", 1, 1); + boost::shared_ptr msg_rx = GlonassL1CaDllPllTrackingTest_msg_rx_make(); + + gnss_synchro.Acq_delay_samples = 1343; + gnss_synchro.Acq_doppler_hz = -2750; + // gnss_synchro.Acq_doppler_hz = -2750; + gnss_synchro.Acq_samplestamp_samples = 0; + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + ASSERT_NO_THROW({ + gr::analog::sig_source_c::sptr sin_source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); + std::string path = std::string(TEST_PATH); + std::string file = path + "signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin"; + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(file_source, 0, valve, 0); + top_block->connect(valve, 0, tracking->get_left_block(), 0); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of tracking test."; + + tracking->start_tracking(); + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + + // TODO: Verify tracking results + std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc index baf372d6f..58fd52407 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc @@ -1,13 +1,13 @@ /*! * \file gps_l1_ca_dll_pll_tracking_test.cc - * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * \brief This class implements a tracking test for GPS_L1_CA_DLL_PLL_Tracking * implementation based on some input parameters. * \author Javier Arribas, 2017. jarribas(at)cttc.es * * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,36 +25,39 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ - -#include -#include -#include +#include "GPS_L1_CA.h" +#include "gnss_block_factory.h" +#include "gnuplot_i.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "test_flags.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_tests_flags.h" +#include "tracking_true_obs_reader.h" #include -#include -#include +#include #include -#include +#include #include #include #include +#include #include -#include -#include "GPS_L1_CA.h" -#include "gnss_block_factory.h" -#include "gnss_block_interface.h" -#include "tracking_interface.h" -#include "in_memory_configuration.h" -#include "gnss_synchro.h" -#include "gps_l1_ca_dll_pll_tracking.h" -#include "tracking_true_obs_reader.h" -#include "tracking_dump_reader.h" -#include "signal_generator_flags.h" - +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CADllPllTrackingTest_msg_rx; @@ -72,46 +75,49 @@ private: public: int rx_message; - ~GpsL1CADllPllTrackingTest_msg_rx(); //!< Default destructor + ~GpsL1CADllPllTrackingTest_msg_rx(); //!< Default destructor }; + GpsL1CADllPllTrackingTest_msg_rx_sptr GpsL1CADllPllTrackingTest_msg_rx_make() { return GpsL1CADllPllTrackingTest_msg_rx_sptr(new GpsL1CADllPllTrackingTest_msg_rx()); } + void GpsL1CADllPllTrackingTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); - rx_message = message; - } - catch(boost::bad_any_cast& e) - { + { + int64_t message = pmt::to_long(msg); + rx_message = message; //3 -> loss of lock + //std::cout << "Received trk message: " << rx_message << std::endl; + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL1CADllPllTrackingTest_msg_rx::GpsL1CADllPllTrackingTest_msg_rx() : - gr::block("GpsL1CADllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) + +GpsL1CADllPllTrackingTest_msg_rx::GpsL1CADllPllTrackingTest_msg_rx() : gr::block("GpsL1CADllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CADllPllTrackingTest_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } + GpsL1CADllPllTrackingTest_msg_rx::~GpsL1CADllPllTrackingTest_msg_rx() -{} +{ +} // ########################################################### - -class GpsL1CADllPllTrackingTest: public ::testing::Test +class GpsL1CADllPllTrackingTest : public ::testing::Test { - public: std::string generator_binary; std::string p1; @@ -119,27 +125,39 @@ public: std::string p3; std::string p4; std::string p5; + std::string p6; + std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking"; //"GPS_L1_CA_DLL_PLL_C_Aid_Tracking"; - const int baseband_sampling_freq = FLAGS_fs_gen_hz; + const int baseband_sampling_freq = FLAGS_fs_gen_sps; std::string filename_rinex_obs = FLAGS_filename_rinex_obs; std::string filename_raw_data = FLAGS_filename_raw_data; - int configure_generator(); + int configure_generator(double CN0_dBHz, int file_idx); int generate_signal(); - void check_results_doppler(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value); - void check_results_acc_carrier_phase(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value); - void check_results_codephase(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value); + std::vector check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse); + std::vector check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse); + std::vector check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse); + bool save_mat_xy(std::vector& x, std::vector& y, std::string filename); GpsL1CADllPllTrackingTest() { factory = std::make_shared(); @@ -149,9 +167,14 @@ public: } ~GpsL1CADllPllTrackingTest() - {} + { + } - void configure_receiver(); + void configure_receiver(double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols); gr::top_block_sptr top_block; std::shared_ptr factory; @@ -161,13 +184,13 @@ public: }; -int GpsL1CADllPllTrackingTest::configure_generator() +int GpsL1CADllPllTrackingTest::configure_generator(double CN0_dBHz, int file_idx) { // Configure signal generator generator_binary = FLAGS_generator_binary; p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; - if(FLAGS_dynamic_position.empty()) + if (FLAGS_dynamic_position.empty()) { p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); } @@ -175,9 +198,10 @@ int GpsL1CADllPllTrackingTest::configure_generator() { p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); } - p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output - p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples - p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data + std::to_string(file_idx); // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + p6 = std::string("-CN0_dBHz=") + std::to_string(CN0_dBHz); // Signal generator CN0 return 0; } @@ -186,7 +210,7 @@ int GpsL1CADllPllTrackingTest::generate_signal() { int child_status; - char *const parmList[] = { &generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL }; + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], NULL}; int pid; if ((pid = fork()) == -1) @@ -200,12 +224,17 @@ int GpsL1CADllPllTrackingTest::generate_signal() waitpid(pid, &child_status, 0); - std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; return 0; } -void GpsL1CADllPllTrackingTest::configure_receiver() +void GpsL1CADllPllTrackingTest::configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols) { gnss_synchro.Channel_ID = 0; gnss_synchro.System = 'G'; @@ -213,268 +242,946 @@ void GpsL1CADllPllTrackingTest::configure_receiver() signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = FLAGS_test_satellite_PRN; - config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(baseband_sampling_freq)); + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); // Set Tracking - config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); + config->set_property("Tracking_1C.implementation", implementation); config->set_property("Tracking_1C.item_type", "gr_complex"); - config->set_property("Tracking_1C.if", "0"); + config->set_property("Tracking_1C.pll_bw_hz", std::to_string(PLL_wide_bw_hz)); + config->set_property("Tracking_1C.dll_bw_hz", std::to_string(DLL_wide_bw_hz)); + config->set_property("Tracking_1C.early_late_space_chips", "0.5"); + config->set_property("Tracking_1C.extend_correlation_symbols", std::to_string(extend_correlation_symbols)); + config->set_property("Tracking_1C.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz)); + config->set_property("Tracking_1C.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz)); + config->set_property("Tracking_1C.early_late_space_narrow_chips", "0.5"); config->set_property("Tracking_1C.dump", "true"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); - config->set_property("Tracking_1C.pll_bw_hz", "30.0"); - config->set_property("Tracking_1C.dll_bw_hz", "2.0"); - config->set_property("Tracking_1C.early_late_space_chips", "0.5"); + + std::cout << "*****************************************\n"; + std::cout << "*** Tracking configuration parameters ***\n"; + std::cout << "*****************************************\n"; + std::cout << "pll_bw_hz: " << config->property("Tracking_1C.pll_bw_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_hz: " << config->property("Tracking_1C.dll_bw_hz", 0.0) << " Hz\n"; + std::cout << "pll_bw_narrow_hz: " << config->property("Tracking_1C.pll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_narrow_hz: " << config->property("Tracking_1C.dll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "extend_correlation_symbols: " << config->property("Tracking_1C.extend_correlation_symbols", 0) << " Symbols\n"; + std::cout << "*****************************************\n"; + std::cout << "*****************************************\n"; } -void GpsL1CADllPllTrackingTest::check_results_doppler(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value) -{ - //1. True value interpolation to match the measurement times +std::vector GpsL1CADllPllTrackingTest::check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse) +{ + // 1. True value interpolation to match the measurement times arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); - //2. RMSE + // 2. RMSE arma::vec err; err = meas_value - true_value_interp; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); - //3. Mean err and variance + //conversion between arma::vec and std:vector + std::vector err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows); + + arma::vec err2 = arma::square(err); + rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance double error_mean = arma::mean(err); double error_var = arma::var(err); - // 5. Peaks - double max_error = arma::max(err); - double min_error = arma::min(err); - - //5. report - - std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse - << ", mean=" << error_mean - << ", stdev="<< sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]" << std::endl; - -} - -void GpsL1CADllPllTrackingTest::check_results_acc_carrier_phase(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value) -{ - //1. True value interpolation to match the measurement times - - arma::vec true_value_interp; - arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); - - //2. RMSE - arma::vec err; - - err = meas_value - true_value_interp; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); - - //3. Mean err and variance - double error_mean = arma::mean(err); - double error_var = arma::var(err); + mean_error = error_mean; + std_dev_error = sqrt(error_var); // 4. Peaks double max_error = arma::max(err); double min_error = arma::min(err); - //5. report + // 5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse + << ", mean=" << error_mean + << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]" << std::endl; + std::cout.precision(ss); + return err_std_vector; +} + +std::vector GpsL1CADllPllTrackingTest::check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse) +{ + // 1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + // 2. RMSE + arma::vec err; + //it is required to remove the initial offset in the accumulated carrier phase error + err = (meas_value - meas_value(0)) - (true_value_interp - true_value_interp(0)); + arma::vec err2 = arma::square(err); + //conversion between arma::vec and std:vector + std::vector err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows); + + rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + mean_error = error_mean; + std_dev_error = sqrt(error_var); + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + // 5. report + std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(10) << "TRK acc carrier phase RMSE=" << rmse << ", mean=" << error_mean << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]" << std::endl; - + std::cout.precision(ss); + return err_std_vector; } -void GpsL1CADllPllTrackingTest::check_results_codephase(arma::vec true_time_s, - arma::vec true_value, - arma::vec meas_time_s, - arma::vec meas_value) -{ - //1. True value interpolation to match the measurement times +std::vector GpsL1CADllPllTrackingTest::check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error, + double& rmse) +{ + // 1. True value interpolation to match the measurement times arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); - //2. RMSE + // 2. RMSE arma::vec err; err = meas_value - true_value_interp; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); + //conversion between arma::vec and std:vector + std::vector err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows); - //3. Mean err and variance + arma::vec err2 = arma::square(err); + rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance double error_mean = arma::mean(err); double error_var = arma::var(err); + mean_error = error_mean; + std_dev_error = sqrt(error_var); + // 4. Peaks double max_error = arma::max(err); double min_error = arma::min(err); - //5. report - + // 5. report + std::streamsize ss = std::cout.precision(); std::cout << std::setprecision(10) << "TRK code phase RMSE=" << rmse << ", mean=" << error_mean << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Chips]" << std::endl; - + std::cout.precision(ss); + return err_std_vector; } + TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults) { - // Configure the signal generator - configure_generator(); + //************************************************* + //***** STEP 2: Prepare the parameters sweep ****** + //************************************************* - // Generate signal raw signal samples and observations RINEX file - generate_signal(); + std::vector generator_CN0_values; - struct timeval tv; - long long int begin = 0; - long long int end = 0; - configure_receiver(); + //data containers for config param sweep + std::vector> mean_doppler_error_sweep; //swep config param and cn0 sweep + std::vector> std_dev_doppler_error_sweep; //swep config param and cn0 sweep + std::vector> rmse_doppler_sweep; //swep config param and cn0 sweep - //open true observables log file written by the simulator + std::vector> mean_code_phase_error_sweep; //swep config param and cn0 sweep + std::vector> std_dev_code_phase_error_sweep; //swep config param and cn0 sweep + std::vector> rmse_code_phase_sweep; //swep config param and cn0 sweep + + std::vector> mean_carrier_phase_error_sweep; //swep config param and cn0 sweep + std::vector> std_dev_carrier_phase_error_sweep; //swep config param and cn0 sweep + std::vector> rmse_carrier_phase_sweep; //swep config param and cn0 sweep + + std::vector> trk_valid_timestamp_s_sweep; + std::vector> generator_CN0_values_sweep_copy; + + int test_satellite_PRN = 0; + double acq_delay_samples = 0.0; + double acq_doppler_hz = 0.0; tracking_true_obs_reader true_obs_data; - int test_satellite_PRN = FLAGS_test_satellite_PRN; - std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; - std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); - true_obs_file.append(std::to_string(test_satellite_PRN)); - true_obs_file.append(".dat"); - ASSERT_NO_THROW({ - if (true_obs_data.open_obs_file(true_obs_file) == false) - { - throw std::exception(); - }; - }) << "Failure opening true observables file" << std::endl; - top_block = gr::make_top_block("Tracking test"); - std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); - //std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); - boost::shared_ptr msg_rx = GpsL1CADllPllTrackingTest_msg_rx_make(); + // CONFIG PARAM SWEEP LOOP + std::vector PLL_wide_bw_values; + std::vector DLL_wide_bw_values; - // load acquisition data based on the first epoch of the true observations - ASSERT_NO_THROW({ - if (true_obs_data.read_binary_obs() == false) - { - throw std::exception(); - }; - }) << "Failure reading true observables file" << std::endl; - //restart the epoch counter - true_obs_data.restart(); + //*********************************************************** + //***** STEP 2: Tracking configuration parameters sweep ***** + //*********************************************************** - std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz << " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << std::endl; - gnss_synchro.Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD; - gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz; - gnss_synchro.Acq_samplestamp_samples = 0; - - ASSERT_NO_THROW( { - tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; - - ASSERT_NO_THROW( { - tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; - - ASSERT_NO_THROW( { - tracking->connect(top_block); - }) << "Failure connecting tracking to the top_block." << std::endl; - - ASSERT_NO_THROW( { - std::string file = "./" + filename_raw_data; - const char * file_name = file.c_str(); - gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); - gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); - gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); - top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); - top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0); - top_block->connect(tracking->get_right_block(), 0, sink, 0); - top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of tracking test." << std::endl; - - tracking->start_tracking(); - - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec * 1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec * 1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; - - //check results - //load the true values - long int nepoch = true_obs_data.num_epochs(); - std::cout << "True observation epochs=" << nepoch << std::endl; - - arma::vec true_timestamp_s = arma::zeros(nepoch, 1); - arma::vec true_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); - arma::vec true_Doppler_Hz = arma::zeros(nepoch, 1); - arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1); - arma::vec true_tow_s = arma::zeros(nepoch, 1); - - long int epoch_counter = 0; - while(true_obs_data.read_binary_obs()) + if (FLAGS_PLL_bw_hz_start == FLAGS_PLL_bw_hz_stop) { - true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; - true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; - true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; - true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; - true_tow_s(epoch_counter) = true_obs_data.tow; - epoch_counter++; + if (FLAGS_DLL_bw_hz_start == FLAGS_DLL_bw_hz_stop) + { + //NO PLL/DLL BW sweep + PLL_wide_bw_values.push_back(FLAGS_PLL_bw_hz_start); + DLL_wide_bw_values.push_back(FLAGS_DLL_bw_hz_start); + } + else + { + //DLL BW Sweep + for (double dll_bw = FLAGS_DLL_bw_hz_start; dll_bw >= FLAGS_DLL_bw_hz_stop; dll_bw = dll_bw - FLAGS_DLL_bw_hz_step) + { + PLL_wide_bw_values.push_back(FLAGS_PLL_bw_hz_start); + DLL_wide_bw_values.push_back(dll_bw); + } + } + } + else + { + //PLL BW Sweep + for (double pll_bw = FLAGS_PLL_bw_hz_start; pll_bw >= FLAGS_PLL_bw_hz_stop; pll_bw = pll_bw - FLAGS_PLL_bw_hz_step) + { + PLL_wide_bw_values.push_back(pll_bw); + DLL_wide_bw_values.push_back(FLAGS_DLL_bw_hz_start); + } } - //load the measured values - tracking_dump_reader trk_dump; - ASSERT_NO_THROW({ - if (trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")) == false) - { - throw std::exception(); - }; - }) << "Failure opening tracking dump file" << std::endl; + //********************************************* + //***** STEP 3: Generate the input signal ***** + //********************************************* - nepoch = trk_dump.num_epochs(); - std::cout << "Measured observation epochs=" << nepoch << std::endl; - arma::vec trk_timestamp_s = arma::zeros(nepoch, 1); - arma::vec trk_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); - arma::vec trk_Doppler_Hz = arma::zeros(nepoch, 1); - arma::vec trk_prn_delay_chips = arma::zeros(nepoch, 1); - - epoch_counter = 0; - while(trk_dump.read_binary_obs()) + std::vector cno_vector; + if (FLAGS_CN0_dBHz_start == FLAGS_CN0_dBHz_stop) { - trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); - trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; - trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; - - double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - - GPS_L1_CA_CODE_LENGTH_CHIPS - * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) /1.0e-3); - - trk_prn_delay_chips(epoch_counter) = delay_chips; - epoch_counter++; + generator_CN0_values.push_back(FLAGS_CN0_dBHz_start); + } + else + { + for (double cn0 = FLAGS_CN0_dBHz_start; cn0 > FLAGS_CN0_dBHz_stop; cn0 = cn0 - FLAGS_CN0_dB_step) + { + generator_CN0_values.push_back(cn0); + } } - //Align initial measurements and cut the tracking pull-in transitory - double pull_in_offset_s = 1.0; - arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first"); + // use generator or use an external capture file + if (FLAGS_enable_external_signal_file) + { + //todo: create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + } + else + { + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + // Configure the signal generator + configure_generator(generator_CN0_values.at(current_cn0_idx), current_cn0_idx); + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + // open true observables log file written by the simulator + } + } - trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1); - trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1); - trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1); - trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1); + //************************************************************ + //***** STEP 4: Configure the signal tracking parameters ***** + //************************************************************ + for (unsigned int config_idx = 0; config_idx < PLL_wide_bw_values.size(); config_idx++) + { + //CN0 LOOP + // data containers for CN0 sweep + std::vector> prompt_sweep; + std::vector> early_sweep; + std::vector> late_sweep; + std::vector> promptI_sweep; + std::vector> promptQ_sweep; + std::vector> CN0_dBHz_sweep; + std::vector> trk_timestamp_s_sweep; - check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz); - check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips); - check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles); + std::vector> doppler_error_sweep; + std::vector> code_phase_error_sweep; + std::vector> code_phase_error_meters_sweep; + std::vector> acc_carrier_phase_error_sweep; - std::cout << "Signal tracking completed in " << (end - begin) << " microseconds" << std::endl; + std::vector mean_doppler_error; + std::vector std_dev_doppler_error; + std::vector rmse_doppler; + std::vector mean_code_phase_error; + std::vector std_dev_code_phase_error; + std::vector rmse_code_phase; + std::vector mean_carrier_phase_error; + std::vector std_dev_carrier_phase_error; + std::vector rmse_carrier_phase; + std::vector valid_CN0_values; + + configure_receiver(PLL_wide_bw_values.at(config_idx), + DLL_wide_bw_values.at(config_idx), + FLAGS_PLL_narrow_bw_hz, + FLAGS_DLL_narrow_bw_hz, + FLAGS_extend_correlation_symbols); + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + //****************************************************************************************** + //***** Obtain the initial signal sinchronization parameters (emulating an acquisition) **** + //****************************************************************************************** + if (!FLAGS_enable_external_signal_file) + { + test_satellite_PRN = FLAGS_test_satellite_PRN; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(test_satellite_PRN)); + true_obs_file.append(".dat"); + true_obs_data.close_obs_file(); + ASSERT_EQ(true_obs_data.open_obs_file(true_obs_file), true) << "Failure opening true observables file"; + // load acquisition data based on the first epoch of the true observations + ASSERT_EQ(true_obs_data.read_binary_obs(), true) + << "Failure reading true tracking dump file." << std::endl + << "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) + + " is not available?"; + std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; + std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz << " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << std::endl; + acq_doppler_hz = true_obs_data.doppler_l1_hz; + acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * static_cast(baseband_sampling_freq) * GPS_L1_CA_CODE_PERIOD; + // restart the epoch counter + true_obs_data.restart(); + } + + + std::chrono::time_point start, end; + + top_block = gr::make_top_block("Tracking test"); + + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_1C", implementation, 1, 1); + std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); + + boost::shared_ptr msg_rx = GpsL1CADllPllTrackingTest_msg_rx_make(); + + gnss_synchro.Acq_delay_samples = acq_delay_samples; + gnss_synchro.Acq_doppler_hz = acq_doppler_hz; + gnss_synchro.Acq_samplestamp_samples = 0; + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + ASSERT_NO_THROW({ + std::string file = "./" + filename_raw_data + std::to_string(current_cn0_idx); + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of tracking test."; + + + //******************************************************************** + //***** STEP 5: Perform the signal tracking and read the results ***** + //******************************************************************** + std::cout << "------------ START TRACKING -------------" << std::endl; + tracking->start_tracking(); + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + }) << "Failure running the top_block."; + + std::chrono::duration elapsed_seconds = end - start; + std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds" << std::endl; + + int tracking_last_msg = msg_rx->rx_message; //save last aasynchronous tracking message in order to detect a loss of lock + + //check results + //load the measured values + tracking_dump_reader trk_dump; + ASSERT_EQ(trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")), true) + << "Failure opening tracking dump file"; + + int64_t n_measured_epochs = trk_dump.num_epochs(); + //std::cout << "Measured observation epochs=" << n_measured_epochs << std::endl; + + arma::vec trk_timestamp_s = arma::zeros(n_measured_epochs, 1); + arma::vec trk_acc_carrier_phase_cycles = arma::zeros(n_measured_epochs, 1); + arma::vec trk_Doppler_Hz = arma::zeros(n_measured_epochs, 1); + arma::vec trk_prn_delay_chips = arma::zeros(n_measured_epochs, 1); + + int64_t epoch_counter = 0; + + std::vector timestamp_s; + std::vector prompt; + std::vector early; + std::vector late; + std::vector promptI; + std::vector promptQ; + std::vector CN0_dBHz; + while (trk_dump.read_binary_obs()) + { + trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); + trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; + trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; + double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) / 1.0e-3); + + trk_prn_delay_chips(epoch_counter) = delay_chips; + + timestamp_s.push_back(trk_timestamp_s(epoch_counter)); + prompt.push_back(trk_dump.abs_P); + early.push_back(trk_dump.abs_E); + late.push_back(trk_dump.abs_L); + promptI.push_back(trk_dump.prompt_I); + promptQ.push_back(trk_dump.prompt_Q); + CN0_dBHz.push_back(trk_dump.CN0_SNV_dB_Hz); + + epoch_counter++; + } + trk_timestamp_s_sweep.push_back(timestamp_s); + prompt_sweep.push_back(prompt); + early_sweep.push_back(early); + late_sweep.push_back(late); + promptI_sweep.push_back(promptI); + promptQ_sweep.push_back(promptQ); + CN0_dBHz_sweep.push_back(CN0_dBHz); + + //*********************************************************** + //***** STEP 6: Compare with true values (if available) ***** + //*********************************************************** + if (!FLAGS_enable_external_signal_file) + { + std::vector doppler_error_hz; + std::vector code_phase_error_chips; + std::vector code_phase_error_meters; + std::vector acc_carrier_phase_hz; + + try + { + // load the true values + int64_t n_true_epochs = true_obs_data.num_epochs(); + //std::cout << "True observation epochs=" << n_true_epochs << std::endl; + + arma::vec true_timestamp_s = arma::zeros(n_true_epochs, 1); + arma::vec true_acc_carrier_phase_cycles = arma::zeros(n_true_epochs, 1); + arma::vec true_Doppler_Hz = arma::zeros(n_true_epochs, 1); + arma::vec true_prn_delay_chips = arma::zeros(n_true_epochs, 1); + arma::vec true_tow_s = arma::zeros(n_true_epochs, 1); + + int64_t epoch_counter = 0; + while (true_obs_data.read_binary_obs()) + { + true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; + true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; + true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; + true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; + true_tow_s(epoch_counter) = true_obs_data.tow; + epoch_counter++; + } + // Align initial measurements and cut the tracking pull-in transitory + double pull_in_offset_s = FLAGS_skip_trk_transitory_s; + + arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first"); + if (initial_meas_point.size() > 0 and tracking_last_msg != 3) + { + trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1); + trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1); + trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1); + trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1); + + + double mean_error; + double std_dev_error; + double rmse; + + valid_CN0_values.push_back(generator_CN0_values.at(current_cn0_idx)); //save the current cn0 value (valid tracking) + + doppler_error_hz = check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz, mean_error, std_dev_error, rmse); + mean_doppler_error.push_back(mean_error); + std_dev_doppler_error.push_back(std_dev_error); + rmse_doppler.push_back(rmse); + + code_phase_error_chips = check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips, mean_error, std_dev_error, rmse); + for (unsigned int ii = 0; ii < code_phase_error_chips.size(); ii++) + { + code_phase_error_meters.push_back(GPS_L1_CA_CHIP_PERIOD * code_phase_error_chips.at(ii) * GPS_C_m_s); + } + mean_code_phase_error.push_back(mean_error); + std_dev_code_phase_error.push_back(std_dev_error); + rmse_code_phase.push_back(rmse); + + acc_carrier_phase_hz = check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles, mean_error, std_dev_error, rmse); + mean_carrier_phase_error.push_back(mean_error); + std_dev_carrier_phase_error.push_back(std_dev_error); + rmse_carrier_phase.push_back(rmse); + + //save tracking measurement timestamps to std::vector + std::vector vector_trk_timestamp_s(trk_timestamp_s.colptr(0), trk_timestamp_s.colptr(0) + trk_timestamp_s.n_rows); + trk_valid_timestamp_s_sweep.push_back(vector_trk_timestamp_s); + + doppler_error_sweep.push_back(doppler_error_hz); + code_phase_error_sweep.push_back(code_phase_error_chips); + code_phase_error_meters_sweep.push_back(code_phase_error_meters); + acc_carrier_phase_error_sweep.push_back(acc_carrier_phase_hz); + } + else + { + std::cout << "Tracking output could not be used, possible loss of lock " << std::endl; + } + } + catch (const std::exception& ex) + { + std::cout << "Tracking output could not be used, possible loss of lock " << ex.what() << std::endl; + } + } + + } //CN0 LOOP + + if (!FLAGS_enable_external_signal_file) + { + mean_doppler_error_sweep.push_back(mean_doppler_error); + std_dev_doppler_error_sweep.push_back(std_dev_doppler_error); + rmse_doppler_sweep.push_back(rmse_doppler); + + mean_code_phase_error_sweep.push_back(mean_code_phase_error); + std_dev_code_phase_error_sweep.push_back(std_dev_code_phase_error); + rmse_code_phase_sweep.push_back(rmse_code_phase); + + mean_carrier_phase_error_sweep.push_back(mean_carrier_phase_error); + std_dev_carrier_phase_error_sweep.push_back(std_dev_carrier_phase_error); + rmse_carrier_phase_sweep.push_back(rmse_carrier_phase); + + //make a copy of the CN0 vector for each configuration parameter in order to filter the loss of lock events + generator_CN0_values_sweep_copy.push_back(valid_CN0_values); + } + + //******************************** + //***** STEP 7: Plot results ***** + //******************************** + if (FLAGS_plot_gps_l1_tracking_test == true) + { + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_gps_l1_tracking_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + unsigned int decimate = static_cast(FLAGS_plot_decimate); + + if (FLAGS_plot_detail_level >= 2) + { + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + Gnuplot g1("linespoints"); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz" + "GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g1.set_grid(); + g1.set_xlabel("Time [s]"); + g1.set_ylabel("Correlators' output"); + //g1.cmd("set key box opaque"); + g1.plot_xy(trk_timestamp_s_sweep.at(current_cn0_idx), prompt_sweep.at(current_cn0_idx), "Prompt", decimate); + g1.plot_xy(trk_timestamp_s_sweep.at(current_cn0_idx), early_sweep.at(current_cn0_idx), "Early", decimate); + g1.plot_xy(trk_timestamp_s_sweep.at(current_cn0_idx), late_sweep.at(current_cn0_idx), "Late", decimate); + g1.set_legend(); + g1.savetops("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx))); + g1.savetopdf("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx)), 18); + } + Gnuplot g2("points"); + if (FLAGS_show_plots) + { + g2.showonscreen(); // window output + } + else + { + g2.disablescreen(); + } + g2.set_multiplot(ceil(static_cast(generator_CN0_values.size()) / 2.0), + ceil(static_cast(generator_CN0_values.size()) / 2)); + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + g2.reset_plot(); + g2.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz" + "GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g2.set_grid(); + g2.set_xlabel("Inphase"); + g2.set_ylabel("Quadrature"); + //g2.cmd("set size ratio -1"); + g2.plot_xy(promptI_sweep.at(current_cn0_idx), promptQ_sweep.at(current_cn0_idx)); + } + g2.unset_multiplot(); + g2.savetops("Constellation"); + g2.savetopdf("Constellation", 18); + + Gnuplot g3("linespoints"); + g3.set_title("GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Reported CN0 [dB-Hz]"); + g3.cmd("set key box opaque"); + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + g3.plot_xy(trk_timestamp_s_sweep.at(current_cn0_idx), CN0_dBHz_sweep.at(current_cn0_idx), + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + } + g3.set_legend(); + g3.savetops("CN0_output"); + g3.savetopdf("CN0_output", 18); + if (FLAGS_show_plots) + { + g3.showonscreen(); // window output + } + else + { + g3.disablescreen(); + } + } + + //PLOT ERROR FIGURES (only if it is used the signal generator) + if (!FLAGS_enable_external_signal_file) + { + if (FLAGS_plot_detail_level >= 1) + { + Gnuplot g5("points"); + if (FLAGS_show_plots) + { + g5.showonscreen(); // window output + } + else + { + g5.disablescreen(); + } + g5.set_title("Code delay error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g5.set_grid(); + g5.set_xlabel("Time [s]"); + g5.set_ylabel("Code delay error [Chips]"); + + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++) + { + try + { + g5.plot_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), code_phase_error_sweep.at(current_cn0_idx), + std::to_string(static_cast(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz]", decimate); + } + catch (const GnuplotException& ge) + { + } + save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), + code_phase_error_sweep.at(current_cn0_idx), + "Code_error_chips" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) + + std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx))); + } + g5.set_legend(); + g5.set_legend(); + g5.savetops("Code_error_chips"); + g5.savetopdf("Code_error_chips", 18); + + Gnuplot g5b("points"); + if (FLAGS_show_plots) + { + g5b.showonscreen(); // window output + } + else + { + g5b.disablescreen(); + } + g5b.set_title("Code delay error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g5b.set_grid(); + g5b.set_xlabel("Time [s]"); + g5b.set_ylabel("Code delay error [meters]"); + + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++) + { + try + { + g5b.plot_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), code_phase_error_meters_sweep.at(current_cn0_idx), + std::to_string(static_cast(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz]", decimate); + } + catch (const GnuplotException& ge) + { + } + save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), + code_phase_error_sweep.at(current_cn0_idx), + "Code_error_meters" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) + + std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx))); + } + g5b.set_legend(); + g5b.set_legend(); + g5b.savetops("Code_error_meters"); + g5b.savetopdf("Code_error_meters", 18); + + + Gnuplot g6("points"); + if (FLAGS_show_plots) + { + g6.showonscreen(); // window output + } + else + { + g6.disablescreen(); + } + g6.set_title("Accumulated carrier phase error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g6.set_grid(); + g6.set_xlabel("Time [s]"); + g6.set_ylabel("Accumulated carrier phase error [Cycles]"); + + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++) + { + try + { + g6.plot_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), acc_carrier_phase_error_sweep.at(current_cn0_idx), + std::to_string(static_cast(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz]", decimate); + } + catch (const GnuplotException& ge) + { + } + save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), + acc_carrier_phase_error_sweep.at(current_cn0_idx), + "Carrier_phase_error" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) + + std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx))); + } + g6.set_legend(); + g6.set_legend(); + g6.savetops("Acc_carrier_phase_error_cycles"); + g6.savetopdf("Acc_carrier_phase_error_cycles", 18); + + Gnuplot g4("points"); + if (FLAGS_show_plots) + { + g4.showonscreen(); // window output + } + else + { + g4.disablescreen(); + } + g4.set_multiplot(ceil(static_cast(generator_CN0_values.size()) / 2.0), + ceil(static_cast(generator_CN0_values.size()) / 2)); + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++) + { + g4.reset_plot(); + g4.set_title("Dopper error" + std::to_string(static_cast(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz], PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g4.set_grid(); + //g4.cmd("set key box opaque"); + g4.set_xlabel("Time [s]"); + g4.set_ylabel("Dopper error [Hz]"); + try + { + g4.plot_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), doppler_error_sweep.at(current_cn0_idx), + std::to_string(static_cast(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz]", decimate); + } + catch (const GnuplotException& ge) + { + } + + save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), + doppler_error_sweep.at(current_cn0_idx), + "Doppler_error" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) + + std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx))); + } + g4.unset_multiplot(); + g4.savetops("Doppler_error_hz"); + g4.savetopdf("Doppler_error_hz", 18); + } + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } + } + + if (FLAGS_plot_gps_l1_tracking_test == true) + { + std::cout << "Ploting performance metrics..." << std::endl; + try + { + if (generator_CN0_values.size() > 1) + { + //plot metrics + + Gnuplot g7("linespoints"); + if (FLAGS_show_plots) + { + g7.showonscreen(); // window output + } + else + { + g7.disablescreen(); + } + g7.set_title("Doppler error metrics (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g7.set_grid(); + g7.set_xlabel("CN0 [dB-Hz]"); + g7.set_ylabel("Doppler error [Hz]"); + g7.set_pointsize(2); + g7.cmd("set termoption lw 2"); + g7.cmd("set key box opaque"); + for (unsigned int config_sweep_idx = 0; config_sweep_idx < mean_doppler_error_sweep.size(); config_sweep_idx++) + { + g7.plot_xy_err(generator_CN0_values_sweep_copy.at(config_sweep_idx), + mean_doppler_error_sweep.at(config_sweep_idx), + std_dev_doppler_error_sweep.at(config_sweep_idx), + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz"); + + //matlab save + save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx), + rmse_doppler_sweep.at(config_sweep_idx), + "RMSE_Doppler_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx))); + } + g7.savetops("Doppler_error_metrics"); + g7.savetopdf("Doppler_error_metrics", 18); + + + Gnuplot g8("linespoints"); + g8.set_title("Accumulated carrier phase error metrics (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g8.set_grid(); + g8.set_xlabel("CN0 [dB-Hz]"); + g8.set_ylabel("Accumulated Carrier Phase error [Cycles]"); + g8.cmd("set key box opaque"); + g8.cmd("set termoption lw 2"); + g8.set_pointsize(2); + for (unsigned int config_sweep_idx = 0; config_sweep_idx < mean_doppler_error_sweep.size(); config_sweep_idx++) + { + g8.plot_xy_err(generator_CN0_values_sweep_copy.at(config_sweep_idx), + mean_carrier_phase_error_sweep.at(config_sweep_idx), + std_dev_carrier_phase_error_sweep.at(config_sweep_idx), + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz"); + //matlab save + save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx), + rmse_carrier_phase_sweep.at(config_sweep_idx), + "RMSE_Carrier_Phase_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx))); + } + g8.savetops("Carrier_error_metrics"); + g8.savetopdf("Carrier_error_metrics", 18); + + Gnuplot g9("linespoints"); + g9.set_title("Code Phase error metrics (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g9.set_grid(); + g9.set_xlabel("CN0 [dB-Hz]"); + g9.set_ylabel("Code Phase error [Chips]"); + g9.cmd("set key box opaque"); + g9.cmd("set termoption lw 2"); + g9.set_pointsize(2); + for (unsigned int config_sweep_idx = 0; config_sweep_idx < mean_doppler_error_sweep.size(); config_sweep_idx++) + { + g9.plot_xy_err(generator_CN0_values_sweep_copy.at(config_sweep_idx), + mean_code_phase_error_sweep.at(config_sweep_idx), + std_dev_code_phase_error_sweep.at(config_sweep_idx), + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz"); + //matlab save + save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx), + rmse_code_phase_sweep.at(config_sweep_idx), + "RMSE_Code_Phase_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) + + +"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx))); + } + g9.savetops("Code_error_metrics"); + g9.savetopdf("Code_error_metrics", 18); + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } } +bool GpsL1CADllPllTrackingTest::save_mat_xy(std::vector& x, std::vector& y, std::string filename) +{ + try + { + // WRITE MAT FILE + mat_t* matfp; + matvar_t* matvar; + filename.erase(filename.length() - 4, 4); + filename.append(".mat"); + matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT73); + if (reinterpret_cast(matfp) != NULL) + { + size_t dims[2] = {1, x.size()}; + matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + } + Mat_Close(matfp); + return true; + } + catch (const std::exception& ex) + { + return false; + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc new file mode 100644 index 000000000..ffaeffc76 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc @@ -0,0 +1,616 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking_test.cc + * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Marc Majoral, 2017. mmajoral(at)cttc.cat + * \author Javier Arribas, 2017. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_synchro.h" +#include "gps_l1_ca_dll_pll_tracking_fpga.h" +#include "in_memory_configuration.h" +#include "interleaved_byte_to_complex_short.h" +#include "signal_generator_flags.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_true_obs_reader.h" +#include +#include // to test the FPGA we have to create a simultaneous task to send the samples using the DMA and stop the test +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // FPGA read input file +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + +#define DMA_TRACK_TRANSFER_SIZE 2046 // DMA transfer size for tracking +#define MIN_SAMPLES_REMAINING 20000 // number of remaining samples in the DMA that causes the CPU to stop the flowgraph (it has to be a bit alrger than 2x max packet size) +#define FIVE_SECONDS 5000000 // five seconds in microseconds + +void send_tracking_gps_input_samples(FILE *rx_signal_file, + int num_remaining_samples, const gr::top_block_sptr& top_block) +{ + int num_samples_transferred = 0; // number of samples that have been transferred to the DMA so far + static int flowgraph_stopped = 0; // flag to indicate if the flowgraph is stopped already + char *buffer_DMA; // temporary buffer to store the samples to be sent to the DMA + int dma_descr; // DMA descriptor + dma_descr = open("/dev/loop_tx", O_WRONLY); + if (dma_descr < 0) + { + printf("can't open loop device\n"); + exit(1); + } + + buffer_DMA = (char *)malloc(DMA_TRACK_TRANSFER_SIZE); + if (!buffer_DMA) + { + fprintf(stderr, "Memory error!"); + } + + while (num_remaining_samples > 0) + { + if (num_remaining_samples < MIN_SAMPLES_REMAINING) + { + if (flowgraph_stopped == 0) + { + // stop top module + top_block->stop(); + flowgraph_stopped = 1; + } + } + if (num_remaining_samples > DMA_TRACK_TRANSFER_SIZE) + { + fread(buffer_DMA, DMA_TRACK_TRANSFER_SIZE, 1, rx_signal_file); + + assert(DMA_TRACK_TRANSFER_SIZE == write(dma_descr, &buffer_DMA[0], DMA_TRACK_TRANSFER_SIZE)); + num_remaining_samples = num_remaining_samples - DMA_TRACK_TRANSFER_SIZE; + num_samples_transferred = num_samples_transferred + DMA_TRACK_TRANSFER_SIZE; + } + else + { + fread(buffer_DMA, num_remaining_samples, 1, rx_signal_file); + + assert(num_remaining_samples == write(dma_descr, &buffer_DMA[0], num_remaining_samples)); + num_samples_transferred = num_samples_transferred + num_remaining_samples; + num_remaining_samples = 0; + } + } + + free(buffer_DMA); + close(dma_descr); +} + + +// thread that sends the samples to the FPGA +void sending_thread(gr::top_block_sptr top_block, const char *file_name) +{ + // file descriptor + FILE *rx_signal_file; // file descriptor + int file_length; // length of the file containing the received samples + + rx_signal_file = fopen(file_name, "rb"); + if (!rx_signal_file) + { + printf("Unable to open file!"); + } + + fseek(rx_signal_file, 0, SEEK_END); + file_length = ftell(rx_signal_file); + fseek(rx_signal_file, 0, SEEK_SET); + + usleep(FIVE_SECONDS); // wait for some time to give time to the other thread to program the device + + //send_tracking_gps_input_samples(dma_descr, rx_signal_file, file_length); + send_tracking_gps_input_samples(rx_signal_file, file_length, std::move(top_block)); + + fclose(rx_signal_file); +} + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GpsL1CADllPllTrackingTestFpga_msg_rx; + +using GpsL1CADllPllTrackingTestFpga_msg_rx_sptr = boost::shared_ptr; + +GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make(); + + +class GpsL1CADllPllTrackingTestFpga_msg_rx : public gr::block +{ +private: + friend GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GpsL1CADllPllTrackingTestFpga_msg_rx(); + +public: + int rx_message; + ~GpsL1CADllPllTrackingTestFpga_msg_rx(); //!< Default destructor +}; + + +GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make() +{ + return GpsL1CADllPllTrackingTestFpga_msg_rx_sptr( + new GpsL1CADllPllTrackingTestFpga_msg_rx()); +} + + +void GpsL1CADllPllTrackingTestFpga_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(std::move(msg)); + rx_message = message; + } + catch (boost::bad_any_cast &e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +GpsL1CADllPllTrackingTestFpga_msg_rx::GpsL1CADllPllTrackingTestFpga_msg_rx() : gr::block("GpsL1CADllPllTrackingTestFpga_msg_rx", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), + boost::bind( + &GpsL1CADllPllTrackingTestFpga_msg_rx::msg_handler_events, + this, _1)); + rx_message = 0; +} + + +GpsL1CADllPllTrackingTestFpga_msg_rx::~GpsL1CADllPllTrackingTestFpga_msg_rx() = default; + + +// ########################################################### + +class GpsL1CADllPllTrackingTestFpga : public ::testing::Test +{ +public: + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + + const int baseband_sampling_freq = FLAGS_fs_gen_sps; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_filename_raw_data; + + int configure_generator(); + int generate_signal(); + void check_results_doppler(arma::vec &true_time_s, arma::vec &true_value, + arma::vec &meas_time_s, arma::vec &meas_value); + void check_results_acc_carrier_phase(arma::vec &true_time_s, + arma::vec &true_value, arma::vec &meas_time_s, arma::vec &meas_value); + void check_results_codephase(arma::vec &true_time_s, arma::vec &true_value, + arma::vec &meas_time_s, arma::vec &meas_value); + + GpsL1CADllPllTrackingTestFpga() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GpsL1CADllPllTrackingTestFpga() = default; + + void configure_receiver(); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +int GpsL1CADllPllTrackingTestFpga::configure_generator() +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + return 0; +} + + +int GpsL1CADllPllTrackingTestFpga::generate_signal() +{ + int child_status; + + char *const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], + &p4[0], &p5[0], nullptr}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +void GpsL1CADllPllTrackingTestFpga::configure_receiver() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = FLAGS_test_satellite_PRN; + + config->set_property("GNSS-SDR.internal_fs_sps", + std::to_string(baseband_sampling_freq)); + // Set Tracking + //config->set_property("Tracking_1C.implementation", + // "GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga"); + config->set_property("Tracking_1C.implementation", + "GPS_L1_CA_DLL_PLL_Tracking_Fpga"); + config->set_property("Tracking_1C.item_type", "cshort"); + config->set_property("Tracking_1C.dump", "true"); + config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); + config->set_property("Tracking_1C.pll_bw_hz", "30.0"); + config->set_property("Tracking_1C.dll_bw_hz", "2.0"); + config->set_property("Tracking_1C.early_late_space_chips", "0.5"); + config->set_property("Tracking_1C.devicename", "/dev/uio"); + config->set_property("Tracking_1C.device_base", "1"); +} + + +void GpsL1CADllPllTrackingTestFpga::check_results_doppler(arma::vec &true_time_s, + arma::vec &true_value, arma::vec &meas_time_s, arma::vec &meas_value) +{ + //1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + //2. RMSE + arma::vec err; + + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 5. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse + << ", mean=" << error_mean << ", stdev=" << sqrt(error_var) + << " (max,min)=" << max_error << "," << min_error << " [Hz]" + << std::endl; + std::cout.precision(ss); +} + + +void GpsL1CADllPllTrackingTestFpga::check_results_acc_carrier_phase( + arma::vec &true_time_s, arma::vec &true_value, arma::vec &meas_time_s, + arma::vec &meas_value) +{ + //1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + //2. RMSE + arma::vec err; + + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK acc carrier phase RMSE=" << rmse + << ", mean=" << error_mean << ", stdev=" << sqrt(error_var) + << " (max,min)=" << max_error << "," << min_error << " [Hz]" + << std::endl; + std::cout.precision(ss); +} + + +void GpsL1CADllPllTrackingTestFpga::check_results_codephase( + arma::vec &true_time_s, arma::vec &true_value, arma::vec &meas_time_s, + arma::vec &meas_value) +{ + //1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + //2. RMSE + arma::vec err; + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK code phase RMSE=" << rmse + << ", mean=" << error_mean << ", stdev=" << sqrt(error_var) + << " (max,min)=" << max_error << "," << min_error << " [Chips]" + << std::endl; + std::cout.precision(ss); +} + + +TEST_F(GpsL1CADllPllTrackingTestFpga, ValidationOfResultsFpga) +{ + configure_generator(); + + // DO not generate signal raw signal samples and observations RINEX file by default + //generate_signal(); + + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + + configure_receiver(); + + //open true observables log file written by the simulator + tracking_true_obs_reader true_obs_data; + int test_satellite_PRN = FLAGS_test_satellite_PRN; + std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(test_satellite_PRN)); + true_obs_file.append(".dat"); + ASSERT_NO_THROW( + { + if (true_obs_data.open_obs_file(true_obs_file) == false) + { + throw std::exception(); + }; + }) + << "Failure opening true observables file"; + + top_block = gr::make_top_block("Tracking test"); + //std::shared_ptr tracking = std::make_shared (config.get(), "Tracking_1C", 1, 1); + std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); + + boost::shared_ptr msg_rx = GpsL1CADllPllTrackingTestFpga_msg_rx_make(); + + // load acquisition data based on the first epoch of the true observations + ASSERT_NO_THROW( + { + if (true_obs_data.read_binary_obs() == false) + { + throw std::exception(); + }; + }) + << "Failure reading true observables file"; + + //restart the epoch counter + true_obs_data.restart(); + + std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz + << " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips + << std::endl; + + gnss_synchro.Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD; + gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz; + gnss_synchro.Acq_samplestamp_samples = 0; + + ASSERT_NO_THROW( + { + tracking->set_channel(gnss_synchro.Channel_ID); + }) + << "Failure setting channel."; + + ASSERT_NO_THROW( + { + tracking->set_gnss_synchro(&gnss_synchro); + }) + << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW( + { + tracking->connect(top_block); + }) + << "Failure connecting tracking to the top_block."; + + ASSERT_NO_THROW( + { + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) + << "Failure connecting the blocks of tracking test."; + + tracking->start_tracking(); + + // assemble again the file name in a null terminated string (not available by default in the main program flow) + std::string file = "./" + filename_raw_data; + const char *file_name = file.c_str(); + + // start thread that sends the DMA samples to the FPGA + boost::thread t{sending_thread, top_block, file_name}; + + EXPECT_NO_THROW( + { + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + //tracking->reset();// unlock the channel + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) + << "Failure running the top_block."; + + // wait until child thread terminates + t.join(); + + //check results + //load the true values + int64_t nepoch = true_obs_data.num_epochs(); + std::cout << "True observation epochs=" << nepoch << std::endl; + + arma::vec true_timestamp_s = arma::zeros(nepoch, 1); + arma::vec true_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); + arma::vec true_Doppler_Hz = arma::zeros(nepoch, 1); + arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1); + arma::vec true_tow_s = arma::zeros(nepoch, 1); + + int64_t epoch_counter = 0; + while (true_obs_data.read_binary_obs()) + { + true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; + true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; + true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; + true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; + true_tow_s(epoch_counter) = true_obs_data.tow; + epoch_counter++; + } + + //load the measured values + tracking_dump_reader trk_dump; + ASSERT_NO_THROW( + { + if (trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")) == false) + { + throw std::exception(); + }; + }) + << "Failure opening tracking dump file"; + + nepoch = trk_dump.num_epochs(); + std::cout << "Measured observation epochs=" << nepoch << std::endl; + + arma::vec trk_timestamp_s = arma::zeros(nepoch, 1); + arma::vec trk_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); + arma::vec trk_Doppler_Hz = arma::zeros(nepoch, 1); + arma::vec trk_prn_delay_chips = arma::zeros(nepoch, 1); + + epoch_counter = 0; + while (trk_dump.read_binary_obs()) + { + trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); + trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; + trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; + + double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) / 1.0e-3); + + trk_prn_delay_chips(epoch_counter) = delay_chips; + epoch_counter++; + } + + //Align initial measurements and cut the tracking pull-in transitory + double pull_in_offset_s = 1.0; + arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first"); + + trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1); + trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1); + trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1); + trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1); + + check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz); + check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips); + check_results_acc_carrier_phase(true_timestamp_s, + true_acc_carrier_phase_cycles, trk_timestamp_s, + trk_acc_carrier_phase_cycles); + + std::cout << "Signal tracking completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc new file mode 100644 index 000000000..96c84302f --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc @@ -0,0 +1,586 @@ +/*! + * \file gps_l1_ca_kf_tracking_test.cc + * \brief This class implements a tracking test for GPS_L1_CA_KF_Tracking + * implementation based on some input parameters. + * \author Carles Fernandez, 2018 + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "gnss_block_factory.h" +#include "gnss_sdr_flags.h" +#include "gnuplot_i.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "test_flags.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_true_obs_reader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + +DEFINE_bool(plot_gps_l1_kf_tracking_test, false, "Plots results of GpsL1CAKfTrackingTest with gnuplot"); + + +// ######## GNURADIO BLOCK MESSAGE RECEVER ######### +class GpsL1CAKfTrackingTest_msg_rx; + +typedef boost::shared_ptr GpsL1CAKfTrackingTest_msg_rx_sptr; + +GpsL1CAKfTrackingTest_msg_rx_sptr GpsL1CAKfTrackingTest_msg_rx_make(); + +class GpsL1CAKfTrackingTest_msg_rx : public gr::block +{ +private: + friend GpsL1CAKfTrackingTest_msg_rx_sptr GpsL1CAKfTrackingTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + GpsL1CAKfTrackingTest_msg_rx(); + +public: + int rx_message; + ~GpsL1CAKfTrackingTest_msg_rx(); //!< Default destructor +}; + + +GpsL1CAKfTrackingTest_msg_rx_sptr GpsL1CAKfTrackingTest_msg_rx_make() +{ + return GpsL1CAKfTrackingTest_msg_rx_sptr(new GpsL1CAKfTrackingTest_msg_rx()); +} + + +void GpsL1CAKfTrackingTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + long int message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + + +GpsL1CAKfTrackingTest_msg_rx::GpsL1CAKfTrackingTest_msg_rx() : gr::block("GpsL1CAKfTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CAKfTrackingTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +GpsL1CAKfTrackingTest_msg_rx::~GpsL1CAKfTrackingTest_msg_rx() +{ +} + + +// ########################################################### + +class GpsL1CAKfTrackingTest : public ::testing::Test +{ +public: + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + + std::string implementation = "GPS_L1_CA_KF_Tracking"; + + const int baseband_sampling_freq = FLAGS_fs_gen_sps; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_filename_raw_data; + + int configure_generator(); + int generate_signal(); + void check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value); + void check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value); + void check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value); + + GpsL1CAKfTrackingTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~GpsL1CAKfTrackingTest() + { + } + + void configure_receiver(); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +int GpsL1CAKfTrackingTest::configure_generator() +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps] + return 0; +} + + +int GpsL1CAKfTrackingTest::generate_signal() +{ + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], NULL}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +void GpsL1CAKfTrackingTest::configure_receiver() +{ + gnss_synchro.Channel_ID = 0; + gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(gnss_synchro.Signal, 2, 0); + gnss_synchro.PRN = FLAGS_test_satellite_PRN; + + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + // Set Tracking + config->set_property("Tracking_1C.implementation", implementation); + config->set_property("Tracking_1C.item_type", "gr_complex"); + if (FLAGS_dll_bw_hz != 0.0) + { + config->set_property("Tracking_1C.dll_bw_hz", std::to_string(FLAGS_dll_bw_hz)); + } + else + { + config->set_property("Tracking_1C.dll_bw_hz", "2.0"); + } + config->set_property("Tracking_1C.early_late_space_chips", "0.5"); + config->set_property("Tracking_1C.extend_correlation_ms", "1"); + config->set_property("Tracking_1C.dump", "true"); + config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); +} + + +void GpsL1CAKfTrackingTest::check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value) +{ + // 1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + // 2. RMSE + arma::vec err; + + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + // 5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse + << ", mean=" << error_mean + << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]" << std::endl; + std::cout.precision(ss); +} + + +void GpsL1CAKfTrackingTest::check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value) +{ + // 1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + // 2. RMSE + arma::vec err; + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + // 5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK acc carrier phase RMSE=" << rmse + << ", mean=" << error_mean + << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]" << std::endl; + std::cout.precision(ss); +} + + +void GpsL1CAKfTrackingTest::check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value) +{ + // 1. True value interpolation to match the measurement times + arma::vec true_value_interp; + arma::uvec true_time_s_valid = find(true_time_s > 0); + true_time_s = true_time_s(true_time_s_valid); + true_value = true_value(true_time_s_valid); + arma::uvec meas_time_s_valid = find(meas_time_s > 0); + meas_time_s = meas_time_s(meas_time_s_valid); + meas_value = meas_value(meas_time_s_valid); + + arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp); + + // 2. RMSE + arma::vec err; + + err = meas_value - true_value_interp; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + // 3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + // 5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << "TRK code phase RMSE=" << rmse + << ", mean=" << error_mean + << ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Chips]" << std::endl; + std::cout.precision(ss); +} + + +TEST_F(GpsL1CAKfTrackingTest, ValidationOfResults) +{ + // Configure the signal generator + configure_generator(); + + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + + std::chrono::time_point start, end; + + configure_receiver(); + + // open true observables log file written by the simulator + tracking_true_obs_reader true_obs_data; + int test_satellite_PRN = FLAGS_test_satellite_PRN; + std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(test_satellite_PRN)); + true_obs_file.append(".dat"); + ASSERT_EQ(true_obs_data.open_obs_file(true_obs_file), true) << "Failure opening true observables file"; + + top_block = gr::make_top_block("Tracking test"); + + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_1C", implementation, 1, 1); + std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); //std::make_shared(config.get(), "Tracking_1C", 1, 1); + + boost::shared_ptr msg_rx = GpsL1CAKfTrackingTest_msg_rx_make(); + + // load acquisition data based on the first epoch of the true observations + ASSERT_EQ(true_obs_data.read_binary_obs(), true) + << "Failure reading true tracking dump file." << std::endl + << "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) + + " is not available?"; + + // restart the epoch counter + true_obs_data.restart(); + + std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz << " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << std::endl; + gnss_synchro.Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD; + gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz; + gnss_synchro.Acq_samplestamp_samples = 0; + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + ASSERT_NO_THROW({ + std::string file = "./" + filename_raw_data; + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + }) << "Failure connecting the blocks of tracking test."; + + tracking->start_tracking(); + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + }) << "Failure running the top_block."; + + // check results + // load the true values + long int nepoch = true_obs_data.num_epochs(); + std::cout << "True observation epochs=" << nepoch << std::endl; + + arma::vec true_timestamp_s = arma::zeros(nepoch, 1); + arma::vec true_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); + arma::vec true_Doppler_Hz = arma::zeros(nepoch, 1); + arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1); + arma::vec true_tow_s = arma::zeros(nepoch, 1); + + long int epoch_counter = 0; + while (true_obs_data.read_binary_obs()) + { + true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s; + true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles; + true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz; + true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips; + true_tow_s(epoch_counter) = true_obs_data.tow; + epoch_counter++; + } + + //load the measured values + tracking_dump_reader trk_dump; + + ASSERT_EQ(trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")), true) + << "Failure opening tracking dump file"; + + nepoch = trk_dump.num_epochs(); + std::cout << "Measured observation epochs=" << nepoch << std::endl; + //trk_dump.restart(); + + arma::vec trk_timestamp_s = arma::zeros(nepoch, 1); + arma::vec trk_acc_carrier_phase_cycles = arma::zeros(nepoch, 1); + arma::vec trk_Doppler_Hz = arma::zeros(nepoch, 1); + arma::vec trk_prn_delay_chips = arma::zeros(nepoch, 1); + + std::vector prompt; + std::vector early; + std::vector late; + std::vector promptI; + std::vector promptQ; + + epoch_counter = 0; + while (trk_dump.read_binary_obs()) + { + trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); + trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; + trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; + double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) / 1.0e-3); + + trk_prn_delay_chips(epoch_counter) = delay_chips; + epoch_counter++; + prompt.push_back(trk_dump.abs_P); + early.push_back(trk_dump.abs_E); + late.push_back(trk_dump.abs_L); + promptI.push_back(trk_dump.prompt_I); + promptQ.push_back(trk_dump.prompt_Q); + } + + // Align initial measurements and cut the tracking pull-in transitory + double pull_in_offset_s = 1.0; + arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first"); + + trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1); + trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1); + trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1); + trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1); + + check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz); + check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips); + check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles); + + std::chrono::duration elapsed_seconds = end - start; + std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds." << std::endl; + + if (FLAGS_plot_gps_l1_kf_tracking_test == true) + { + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag plot_gps_l1_tracking_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + std::vector timevec; + double t = 0.0; + for (auto it = prompt.begin(); it != prompt.end(); it++) + { + timevec.push_back(t); + t = t + GPS_L1_CA_CODE_PERIOD; + } + Gnuplot g1("linespoints"); + g1.set_title("GPS L1 C/A signal tracking correlators' output (satellite PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g1.set_grid(); + g1.set_xlabel("Time [s]"); + g1.set_ylabel("Correlators' output"); + g1.cmd("set key box opaque"); + unsigned int decimate = static_cast(FLAGS_plot_decimate); + g1.plot_xy(timevec, prompt, "Prompt", decimate); + g1.plot_xy(timevec, early, "Early", decimate); + g1.plot_xy(timevec, late, "Late", decimate); + g1.savetops("Correlators_outputs"); + g1.savetopdf("Correlators_outputs", 18); + if (FLAGS_show_plots) + { + g1.showonscreen(); // window output + } + else + { + g1.disablescreen(); + } + + Gnuplot g2("points"); + g2.set_title("Constellation diagram (satellite PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g2.set_grid(); + g2.set_xlabel("Inphase"); + g2.set_ylabel("Quadrature"); + g2.cmd("set size ratio -1"); + g2.plot_xy(promptI, promptQ); + g2.savetops("Constellation"); + g2.savetopdf("Constellation", 18); + if (FLAGS_show_plots) + { + g2.showonscreen(); // window output + } + else + { + g2.disablescreen(); + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc index 372c8c5e6..d56f2f3ab 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc @@ -7,7 +7,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -25,29 +25,32 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "gnss_block_factory.h" #include "gnss_block_interface.h" -#include "tracking_interface.h" -#include "in_memory_configuration.h" #include "gnss_sdr_valve.h" #include "gnss_synchro.h" #include "gps_l2_m_dll_pll_tracking.h" +#include "in_memory_configuration.h" +#include "tracking_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif // ######## GNURADIO BLOCK MESSAGE RECEVER ######### @@ -66,45 +69,47 @@ private: public: int rx_message; - ~GpsL2MDllPllTrackingTest_msg_rx(); //!< Default destructor - + ~GpsL2MDllPllTrackingTest_msg_rx(); //!< Default destructor }; + GpsL2MDllPllTrackingTest_msg_rx_sptr GpsL2MDllPllTrackingTest_msg_rx_make() { return GpsL2MDllPllTrackingTest_msg_rx_sptr(new GpsL2MDllPllTrackingTest_msg_rx()); } + void GpsL2MDllPllTrackingTest_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(msg); rx_message = message; - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; rx_message = 0; - } + } } -GpsL2MDllPllTrackingTest_msg_rx::GpsL2MDllPllTrackingTest_msg_rx() : - gr::block("GpsL2MDllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) + +GpsL2MDllPllTrackingTest_msg_rx::GpsL2MDllPllTrackingTest_msg_rx() : gr::block("GpsL2MDllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL2MDllPllTrackingTest_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } + GpsL2MDllPllTrackingTest_msg_rx::~GpsL2MDllPllTrackingTest_msg_rx() -{} +{ +} // ########################################################### - -class GpsL2MDllPllTrackingTest: public ::testing::Test +class GpsL2MDllPllTrackingTest : public ::testing::Test { protected: GpsL2MDllPllTrackingTest() @@ -116,7 +121,8 @@ protected: } ~GpsL2MDllPllTrackingTest() - {} + { + } void init(); @@ -137,7 +143,7 @@ void GpsL2MDllPllTrackingTest::init() signal.copy(gnss_synchro.Signal, 2, 0); gnss_synchro.PRN = 7; - config->set_property("GNSS-SDR.internal_fs_hz", "5000000"); + config->set_property("GNSS-SDR.internal_fs_sps", "5000000"); config->set_property("Tracking_2S.item_type", "gr_complex"); config->set_property("Tracking_2S.dump", "false"); config->set_property("Tracking_2S.dump_filename", "../data/L2m_tracking_ch_"); @@ -148,13 +154,13 @@ void GpsL2MDllPllTrackingTest::init() config->set_property("Tracking_2S.dll_bw_hz", "0.5"); } + TEST_F(GpsL2MDllPllTrackingTest, ValidationOfResults) { - struct timeval tv; - long long int begin = 0; - long long int end = 0; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0.0); int fs_in = 5000000; - int nsamples = fs_in*9; + int nsamples = fs_in * 9; init(); queue = gr::msg_queue::make(0); @@ -166,23 +172,23 @@ TEST_F(GpsL2MDllPllTrackingTest, ValidationOfResults) gnss_synchro.Acq_doppler_hz = 1200; gnss_synchro.Acq_samplestamp_samples = 0; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); - }) << "Failure setting channel." << std::endl; + }) << "Failure setting channel."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->set_gnss_synchro(&gnss_synchro); - }) << "Failure setting gnss_synchro." << std::endl; + }) << "Failure setting gnss_synchro."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ tracking->connect(top_block); - }) << "Failure connecting tracking to the top_block." << std::endl; + }) << "Failure connecting tracking to the top_block."; - ASSERT_NO_THROW( { + ASSERT_NO_THROW({ //gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0)); std::string path = std::string(TEST_PATH); - std::string file = path + "signal_samples/gps_l2c_m_prn7_5msps.dat"; - const char * file_name = file.c_str(); + std::string file = path + "signal_samples/gps_l2c_m_prn7_5msps.dat"; + const char* file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); @@ -190,19 +196,17 @@ TEST_F(GpsL2MDllPllTrackingTest, ValidationOfResults) top_block->connect(valve, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, sink, 0); top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); - }) << "Failure connecting the blocks of tracking test." << std::endl; + }) << "Failure connecting the blocks of tracking test."; tracking->start_tracking(); - EXPECT_NO_THROW( { - gettimeofday(&tv, NULL); - begin = tv.tv_sec *1000000 + tv.tv_usec; - top_block->run(); // Start threads and wait - gettimeofday(&tv, NULL); - end = tv.tv_sec *1000000 + tv.tv_usec; - }) << "Failure running the top_block." << std::endl; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; // TODO: Verify tracking results - std::cout << "Tracked " << nsamples << " samples in " << (end - begin) << " microseconds" << std::endl; + std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gpu_multicorrelator_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gpu_multicorrelator_test.cc index 17fcdb68f..5048fe638 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gpu_multicorrelator_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gpu_multicorrelator_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,112 +24,112 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ -#include -#include -#include -#include -#include -#include +#include "GPS_L1_CA.h" #include "cuda_multicorrelator.h" #include "gps_sdr_signal_processing.h" -#include "GPS_L1_CA.h" +#include +#include +#include +#include +#include +#include DEFINE_int32(gpu_multicorrelator_iterations_test, 1000, "Number of averaged iterations in GPU multicorrelator test timing test"); DEFINE_int32(gpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in GPU multicorrelator test timing test"); void run_correlator_gpu(cuda_multicorrelator* correlator, - float d_rem_carrier_phase_rad, - float d_carrier_phase_step_rad, - float d_code_phase_step_chips, - float d_rem_code_phase_chips, - int correlation_size, - int d_n_correlator_taps) + float d_rem_carrier_phase_rad, + float d_carrier_phase_step_rad, + float d_code_phase_step_chips, + float d_rem_code_phase_chips, + int correlation_size, + int d_n_correlator_taps) { - for(int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++) - { - correlator->Carrier_wipeoff_multicorrelator_resampler_cuda(d_rem_carrier_phase_rad, - d_carrier_phase_step_rad, - d_code_phase_step_chips, - d_rem_code_phase_chips, - correlation_size, - d_n_correlator_taps); - } + for (int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++) + { + correlator->Carrier_wipeoff_multicorrelator_resampler_cuda(d_rem_carrier_phase_rad, + d_carrier_phase_step_rad, + d_code_phase_step_chips, + d_rem_code_phase_chips, + correlation_size, + d_n_correlator_taps); + } } -TEST(GPU_multicorrelator_test, MeasureExecutionTime) + +TEST(GpuMulticorrelatorTest, MeasureExecutionTime) { - struct timeval tv; - int max_threads=FLAGS_gpu_multicorrelator_max_threads_test; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + int max_threads = FLAGS_gpu_multicorrelator_max_threads_test; std::vector thread_pool; cuda_multicorrelator* correlator_pool[max_threads]; - unsigned int correlation_sizes [3] = { 2048, 4096, 8192}; - double execution_times [3]; + unsigned int correlation_sizes[3] = {2048, 4096, 8192}; + double execution_times[3]; gr_complex* d_ca_code; gr_complex* in_gpu; gr_complex* d_correlator_outs; - int d_n_correlator_taps=3; - int d_vector_length=correlation_sizes[2]; //max correlation size to allocate all the necessary memory + int d_n_correlator_taps = 3; + int d_vector_length = correlation_sizes[2]; //max correlation size to allocate all the necessary memory float* d_local_code_shift_chips; // Set GPU flags cudaSetDeviceFlags(cudaDeviceMapHost); //allocate host memory //pinned memory mode - use special function to get OS-pinned memory - d_n_correlator_taps = 3; // Early, Prompt, and Late + d_n_correlator_taps = 3; // Early, Prompt, and Late // Get space for a vector with the C/A code replica sampled 1x/chip - cudaHostAlloc((void**)&d_ca_code, (static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS)* sizeof(gr_complex)), cudaHostAllocMapped | cudaHostAllocWriteCombined); + cudaHostAlloc((void**)&d_ca_code, (static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex)), cudaHostAllocMapped | cudaHostAllocWriteCombined); // Get space for the resampled early / prompt / late local replicas - cudaHostAlloc((void**)&d_local_code_shift_chips, d_n_correlator_taps * sizeof(float), cudaHostAllocMapped | cudaHostAllocWriteCombined); + cudaHostAlloc((void**)&d_local_code_shift_chips, d_n_correlator_taps * sizeof(float), cudaHostAllocMapped | cudaHostAllocWriteCombined); cudaHostAlloc((void**)&in_gpu, 2 * d_vector_length * sizeof(gr_complex), cudaHostAllocMapped | cudaHostAllocWriteCombined); // correlator outputs (scalar) - cudaHostAlloc((void**)&d_correlator_outs ,sizeof(gr_complex)*d_n_correlator_taps, cudaHostAllocMapped | cudaHostAllocWriteCombined ); + cudaHostAlloc((void**)&d_correlator_outs, sizeof(gr_complex) * d_n_correlator_taps, cudaHostAllocMapped | cudaHostAllocWriteCombined); //--- Perform initializations ------------------------------ //local code resampler on GPU // generate local reference (1 sample per chip) gps_l1_ca_code_gen_complex(d_ca_code, 1, 0); // generate inut signal - for (int n=0;n<2*d_vector_length;n++) - { - in_gpu[n]=std::complex(static_cast (rand())/static_cast(RAND_MAX),static_cast (rand())/static_cast(RAND_MAX)); - } + for (int n = 0; n < 2 * d_vector_length; n++) + { + in_gpu[n] = std::complex(static_cast(rand()) / static_cast(RAND_MAX), static_cast(rand()) / static_cast(RAND_MAX)); + } // Set TAPs delay values [chips] - float d_early_late_spc_chips=0.5; - d_local_code_shift_chips[0] = - d_early_late_spc_chips; + float d_early_late_spc_chips = 0.5; + d_local_code_shift_chips[0] = -d_early_late_spc_chips; d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = d_early_late_spc_chips; - for (int n=0;ninit_cuda_integrated_resampler(d_vector_length, GPS_L1_CA_CODE_LENGTH_CHIPS, d_n_correlator_taps); - correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_gpu); - } + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n] = new cuda_multicorrelator(); + correlator_pool[n]->init_cuda_integrated_resampler(d_vector_length, GPS_L1_CA_CODE_LENGTH_CHIPS, d_n_correlator_taps); + correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_gpu); + } - float d_rem_carrier_phase_rad=0.0; - float d_carrier_phase_step_rad=0.1; - float d_code_phase_step_chips=0.3; - float d_rem_code_phase_chips=0.4; + float d_rem_carrier_phase_rad = 0.0; + float d_carrier_phase_step_rad = 0.1; + float d_code_phase_step_chips = 0.3; + float d_rem_code_phase_chips = 0.4; EXPECT_NO_THROW( - for(int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) - { - for(int current_max_threads=1; current_max_threads<(max_threads+1); current_max_threads++) + for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) { + for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++) { - std::cout<<"Running "<(end - begin) / (1000000.0 * static_cast(FLAGS_gpu_multicorrelator_iterations_test)); + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast(FLAGS_gpu_multicorrelator_iterations_test); std::cout << "GPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx] << " : " << execution_times[correlation_sizes_idx] << " [s]" << std::endl; - } - } - ); + }); cudaFreeHost(in_gpu); cudaFreeHost(d_correlator_outs); cudaFreeHost(d_local_code_shift_chips); cudaFreeHost(d_ca_code); - for (int n=0;nfree_cuda(); - } - - - + for (int n = 0; n < max_threads; n++) + { + correlator_pool[n]->free_cuda(); + } } diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc index a240ac09d..f59a87a1c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_loop_filter_test.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -39,28 +39,28 @@ TEST(TrackingLoopFilterTest, FirstOrderLoop) float update_interval = 0.001; bool include_last_integrator = false; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float g1 = noise_bandwidth * 4.0; float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_FLOAT_EQ( result, sample_data[i]*g1 ); - } + for (float i : sample_data) + { + result = theFilter.apply(i); + EXPECT_FLOAT_EQ(result, i * g1); + } } @@ -71,31 +71,30 @@ TEST(TrackingLoopFilterTest, FirstOrderLoopWithLastIntegrator) float update_interval = 0.001; bool include_last_integrator = true; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; - std::vector< float > expected_out = { 0.0, 0.0, 0.01, 0.02, 0.02, 0.02 }; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; + std::vector expected_out = {0.0, 0.0, 0.01, 0.02, 0.02, 0.02}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_NEAR( result, expected_out[i], 1e-4 ); - } + for (unsigned int i = 0; i < sample_data.size(); ++i) + { + result = theFilter.apply(sample_data[i]); + EXPECT_NEAR(result, expected_out[i], 1e-4); + } } - TEST(TrackingLoopFilterTest, SecondOrderLoop) { int loop_order = 2; @@ -103,27 +102,27 @@ TEST(TrackingLoopFilterTest, SecondOrderLoop) float update_interval = 0.001; bool include_last_integrator = false; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; - std::vector< float > expected_out = { 0.0, 0.0, 13.37778, 0.0889, 0.0889, 0.0889 }; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; + std::vector expected_out = {0.0, 0.0, 13.37778, 0.0889, 0.0889, 0.0889}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_NEAR( result, expected_out[i], 1e-4 ); - } + for (unsigned int i = 0; i < sample_data.size(); ++i) + { + result = theFilter.apply(sample_data[i]); + EXPECT_NEAR(result, expected_out[i], 1e-4); + } } @@ -134,27 +133,27 @@ TEST(TrackingLoopFilterTest, SecondOrderLoopWithLastIntegrator) float update_interval = 0.001; bool include_last_integrator = true; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; - std::vector< float > expected_out = { 0.0, 0.0, 0.006689, 0.013422, 0.013511, 0.013600 }; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; + std::vector expected_out = {0.0, 0.0, 0.006689, 0.013422, 0.013511, 0.013600}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_NEAR( result, expected_out[i], 1e-4 ); - } + for (unsigned int i = 0; i < sample_data.size(); ++i) + { + result = theFilter.apply(sample_data[i]); + EXPECT_NEAR(result, expected_out[i], 1e-4); + } } @@ -165,27 +164,27 @@ TEST(TrackingLoopFilterTest, ThirdOrderLoop) float update_interval = 0.001; bool include_last_integrator = false; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; - std::vector< float > expected_out = { 0.0, 0.0, 15.31877, 0.04494, 0.04520, 0.04546}; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; + std::vector expected_out = {0.0, 0.0, 15.31877, 0.04494, 0.04520, 0.04546}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_NEAR( result, expected_out[i], 1e-4 ); - } + for (unsigned int i = 0; i < sample_data.size(); ++i) + { + result = theFilter.apply(sample_data[i]); + EXPECT_NEAR(result, expected_out[i], 1e-4); + } } @@ -196,27 +195,25 @@ TEST(TrackingLoopFilterTest, ThirdOrderLoopWithLastIntegrator) float update_interval = 0.001; bool include_last_integrator = true; - Tracking_loop_filter theFilter( update_interval, - noise_bandwidth, - loop_order, - include_last_integrator ); + Tracking_loop_filter theFilter(update_interval, + noise_bandwidth, + loop_order, + include_last_integrator); - EXPECT_EQ( theFilter.get_noise_bandwidth(), noise_bandwidth ); - EXPECT_EQ( theFilter.get_update_interval(), update_interval ); - EXPECT_EQ( theFilter.get_include_last_integrator(), include_last_integrator ); - EXPECT_EQ( theFilter.get_order(), loop_order ); + EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth); + EXPECT_EQ(theFilter.get_update_interval(), update_interval); + EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator); + EXPECT_EQ(theFilter.get_order(), loop_order); - std::vector< float > sample_data = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }; - std::vector< float > expected_out = { 0.0, 0.0, 0.007659, 0.015341, 0.015386, 0.015432}; + std::vector sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0}; + std::vector expected_out = {0.0, 0.0, 0.007659, 0.015341, 0.015386, 0.015432}; - theFilter.initialize( 0.0 ); + theFilter.initialize(0.0); float result = 0.0; - for( unsigned int i = 0; i < sample_data.size(); ++i ) - { - result = theFilter.apply( sample_data[i] ); - EXPECT_NEAR( result, expected_out[i], 1e-4 ); - } + for (unsigned int i = 0; i < sample_data.size(); ++i) + { + result = theFilter.apply(sample_data[i]); + EXPECT_NEAR(result, expected_out[i], 1e-4); + } } - - diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc new file mode 100644 index 000000000..2d9861d6f --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc @@ -0,0 +1,1135 @@ +/*! + * \file tracking_test.cc + * \brief This class implements a tracking Pull-In test for GPS_L1_CA_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "Galileo_E1.h" +#include "Galileo_E5a.h" +#include "acquisition_msg_rx.h" +#include "control_message_factory.h" +#include "galileo_e1_pcps_ambiguous_acquisition.h" +#include "galileo_e5a_noncoherent_iq_acquisition_caf.h" +#include "galileo_e5a_pcps_acquisition.h" +#include "gnss_block_factory.h" +#include "gnss_sdr_valve.h" +#include "gnuplot_i.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" +#include "gps_l2_m_pcps_acquisition.h" +#include "gps_l5i_pcps_acquisition.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "test_flags.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_tests_flags.h" +#include "tracking_true_obs_reader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GR_GREATER_38 +#include +#else +#include +#endif + + +// ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER ######### +class TrackingPullInTest_msg_rx; + +typedef boost::shared_ptr TrackingPullInTest_msg_rx_sptr; + +TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make(); + +class TrackingPullInTest_msg_rx : public gr::block +{ +private: + friend TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + TrackingPullInTest_msg_rx(); + +public: + int rx_message; + ~TrackingPullInTest_msg_rx(); //!< Default destructor +}; + + +TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make() +{ + return TrackingPullInTest_msg_rx_sptr(new TrackingPullInTest_msg_rx()); +} + + +void TrackingPullInTest_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; //3 -> loss of lock + //std::cout << "Received trk message: " << rx_message << std::endl; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_tracking Bad cast!"; + rx_message = 0; + } +} + + +TrackingPullInTest_msg_rx::TrackingPullInTest_msg_rx() : gr::block("TrackingPullInTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&TrackingPullInTest_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +TrackingPullInTest_msg_rx::~TrackingPullInTest_msg_rx() +{ +} + + +// ########################################################### + +class TrackingPullInTest : public ::testing::Test +{ +public: + enum StringValue + { + evGPS_1C, + evGPS_2S, + evGPS_L5, + evSBAS_1C, + evGAL_1B, + evGAL_5X, + evGLO_1G, + evGLO_2G + }; + std::map mapStringValues_; + + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + std::string p6; + std::string implementation = FLAGS_trk_test_implementation; + + const int baseband_sampling_freq = FLAGS_fs_gen_sps; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_signal_file; + + std::map doppler_measurements_map; + std::map code_delay_measurements_map; + std::map acq_samplestamp_map; + + int configure_generator(double CN0_dBHz, int file_idx); + int generate_signal(); + std::vector check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + std::vector check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + std::vector check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + + TrackingPullInTest() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + mapStringValues_["1C"] = evGPS_1C; + mapStringValues_["2S"] = evGPS_2S; + mapStringValues_["L5"] = evGPS_L5; + mapStringValues_["1B"] = evGAL_1B; + mapStringValues_["5X"] = evGAL_5X; + mapStringValues_["1G"] = evGLO_1G; + mapStringValues_["2G"] = evGLO_2G; + } + + ~TrackingPullInTest() + { + } + + void configure_receiver(double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols); + + bool acquire_signal(int SV_ID); + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; + + gr::msg_queue::sptr queue; +}; + + +int TrackingPullInTest::configure_generator(double CN0_dBHz, int file_idx) +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_signal_file + std::to_string(file_idx); // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + p6 = std::string("-CN0_dBHz=") + std::to_string(CN0_dBHz); // Signal generator CN0 + return 0; +} + + +int TrackingPullInTest::generate_signal() +{ + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], NULL}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +void TrackingPullInTest::configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols) +{ + config = std::make_shared(); + config->set_property("Tracking.dump", "true"); + config->set_property("Tracking.dump_filename", "./tracking_ch_"); + config->set_property("Tracking.implementation", implementation); + config->set_property("Tracking.item_type", "gr_complex"); + config->set_property("Tracking.pll_bw_hz", std::to_string(PLL_wide_bw_hz)); + config->set_property("Tracking.dll_bw_hz", std::to_string(DLL_wide_bw_hz)); + config->set_property("Tracking.extend_correlation_symbols", std::to_string(extend_correlation_symbols)); + config->set_property("Tracking.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz)); + config->set_property("Tracking.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz)); + gnss_synchro.PRN = FLAGS_test_satellite_PRN; + gnss_synchro.Channel_ID = 0; + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + + std::string System_and_Signal; + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "1C"; + System_and_Signal = "GPS L1 CA"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + gnss_synchro.System = 'E'; + std::string signal = "1B"; + System_and_Signal = "Galileo E1B"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_chips", "0.6"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); + config->set_property("Tracking.track_pilot", "true"); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "2S"; + System_and_Signal = "GPS L2CM"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0 or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + gnss_synchro.System = 'E'; + std::string signal = "5X"; + System_and_Signal = "Galileo E5a"; + signal.copy(gnss_synchro.Signal, 2, 0); + if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking")); + } + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "L5"; + System_and_Signal = "GPS L5I"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + std::cout << "*****************************************\n"; + std::cout << "*** Tracking configuration parameters ***\n"; + std::cout << "*****************************************\n"; + std::cout << "Signal: " << System_and_Signal << "\n"; + std::cout << "implementation: " << config->property("Tracking.implementation", std::string("undefined")) << " \n"; + std::cout << "pll_bw_hz: " << config->property("Tracking.pll_bw_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_hz: " << config->property("Tracking.dll_bw_hz", 0.0) << " Hz\n"; + std::cout << "pll_bw_narrow_hz: " << config->property("Tracking.pll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_narrow_hz: " << config->property("Tracking.dll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "extend_correlation_symbols: " << config->property("Tracking.extend_correlation_symbols", 0) << " Symbols\n"; + std::cout << "*****************************************\n"; + std::cout << "*****************************************\n"; +} + + +bool TrackingPullInTest::acquire_signal(int SV_ID) +{ + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) + gr::top_block_sptr top_block; + top_block = gr::make_top_block("Acquisition test"); + + // Satellite signal definition + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.Channel_ID = 0; + + + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + // Enable automatic resampler for the acquisition, if required + if (FLAGS_use_acquisition_resampler == true) + { + config->set_property("GNSS-SDR.use_acquisition_resampler", "true"); + } + config->set_property("Acquisition.blocking_on_standby", "true"); + config->set_property("Acquisition.blocking", "true"); + config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition.dump_filename", "./data/acquisition.dat"); + config->set_property("Acquisition.use_CFAR_algorithm", "false"); + + std::shared_ptr acquisition; + + std::string System_and_Signal; + std::string signal; + //create the correspondign acquisition block according to the desired tracking signal + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "1C"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L1 CA"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + //acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "1B"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E1B"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "2S"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L2CM"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition_5X.coherent_integration_time_ms", "1"); + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + config->set_property("Acquisition.CAF_window_hz", "0"); // **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz + config->set_property("Acquisition.Zero_padding", "0"); //**Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. + config->set_property("Acquisition.bit_transition_flag", "false"); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + signal = "L5"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L5I"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->set_channel(0); + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz)); + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz)); + acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); + acquisition->init(); + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->connect(top_block); + + gr::blocks::file_source::sptr file_source; + std::string file = FLAGS_signal_file; + const char* file_name = file.c_str(); + file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + file_source->seek(2 * FLAGS_skip_samples, SEEK_SET); //skip head. ibyte, two bytes per complex sample + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + //gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); + + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + + // Enable automatic resampler for the acquisition, if required + if (FLAGS_use_acquisition_resampler == true) + { + //create acquisition resamplers if required + double resampler_ratio = 1.0; + + double opt_fs = baseband_sampling_freq; + //find the signal associated to this channel + switch (mapStringValues_[signal]) + { + case evGPS_1C: + opt_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGPS_2S: + opt_fs = GPS_L2C_OPT_ACQ_FS_HZ; + break; + case evGPS_L5: + opt_fs = GPS_L5_OPT_ACQ_FS_HZ; + break; + case evSBAS_1C: + opt_fs = GPS_L1_CA_OPT_ACQ_FS_HZ; + break; + case evGAL_1B: + opt_fs = Galileo_E1_OPT_ACQ_FS_HZ; + break; + case evGAL_5X: + opt_fs = Galileo_E5a_OPT_ACQ_FS_HZ; + break; + case evGLO_1G: + opt_fs = baseband_sampling_freq; + break; + case evGLO_2G: + opt_fs = baseband_sampling_freq; + break; + } + if (opt_fs < baseband_sampling_freq) + { + resampler_ratio = baseband_sampling_freq / opt_fs; + int decimation = floor(resampler_ratio); + while (baseband_sampling_freq % decimation > 0) + { + decimation--; + }; + double acq_fs = baseband_sampling_freq / decimation; + + if (decimation > 1) + { + //create a FIR low pass filter + std::vector taps; + taps = gr::filter::firdes::low_pass(1.0, + baseband_sampling_freq, + acq_fs / 2.1, + acq_fs / 10, + gr::filter::firdes::win_type::WIN_HAMMING); + std::cout << "Enabled decimation low pass filter with " << taps.size() << " taps and decimation factor of " << decimation << std::endl; + acquisition->set_resampler_latency((taps.size() - 1) / 2); + gr::basic_block_sptr fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(decimation, taps); + top_block->connect(gr_interleaved_char_to_complex, 0, fir_filter_ccf_, 0); + top_block->connect(fir_filter_ccf_, 0, acquisition->get_left_block(), 0); + } + else + { + std::cout << "Disabled acquisition resampler because the input sampling frequency is too low\n"; + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + } + } + else + { + std::cout << "Disabled acquisition resampler because the input sampling frequency is too low\n"; + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + } + } + else + { + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + //top_block->connect(head_samples, 0, acquisition->get_left_block(), 0); + } + + + boost::shared_ptr msg_rx; + try + { + msg_rx = Acquisition_msg_rx_make(); + } + catch (const std::exception& e) + { + std::cout << "Failure connecting the message port system: " << e.what() << std::endl; + exit(0); + } + + msg_rx->top_block = top_block; + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + // 5. Run the flowgraph + // Get visible GPS satellites (positive acquisitions with Doppler measurements) + // record startup time + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + start = std::chrono::system_clock::now(); + + bool start_msg = true; + + doppler_measurements_map.clear(); + code_delay_measurements_map.clear(); + acq_samplestamp_map.clear(); + + unsigned int MAX_PRN_IDX = 0; + + switch (tmp_gnss_synchro.System) + { + case 'G': + MAX_PRN_IDX = 33; + break; + case 'E': + MAX_PRN_IDX = 37; + break; + default: + MAX_PRN_IDX = 33; + } + + for (unsigned int PRN = 1; PRN < MAX_PRN_IDX; PRN++) + { + tmp_gnss_synchro.PRN = PRN; + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->init(); + acquisition->set_local_code(); + acquisition->reset(); + acquisition->set_state(1); + msg_rx->rx_message = 0; + top_block->run(); + if (start_msg == true) + { + std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; + std::cout << "Searching for " << System_and_Signal << " Satellites..." << std::endl; + std::cout << "["; + start_msg = false; + } + while (msg_rx->rx_message == 0) + { + usleep(100000); + } + if (msg_rx->rx_message == 1) + { + std::cout << " " << PRN << " "; + doppler_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_doppler_hz)); + code_delay_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_delay_samples)); + acq_samplestamp_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_samplestamp_samples)); + } + else + { + std::cout << " . "; + } + top_block->stop(); + file_source->seek(2 * FLAGS_skip_samples, SEEK_SET); //skip head. ibyte, two bytes per complex sample + std::cout.flush(); + } + std::cout << "]" << std::endl; + std::cout << "-------------------------------------------\n"; + + for (auto& x : doppler_measurements_map) + { + std::cout << "DETECTED SATELLITE " << System_and_Signal << " PRN: " << x.first << " with Doppler: " << x.second << " [Hz], code phase: " << code_delay_measurements_map.at(x.first) << " [samples] at signal SampleStamp " << acq_samplestamp_map.at(x.first) << "\n"; + } + + // report the elapsed time + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + std::cout << "Total signal acquisition run time " + << elapsed_seconds.count() + << " [seconds]" << std::endl; + return true; +} + +TEST_F(TrackingPullInTest, ValidationOfResults) +{ + //************************************************* + //***** STEP 1: Prepare the parameters sweep ****** + //************************************************* + std::vector + acq_doppler_error_hz_values; + std::vector> acq_delay_error_chips_values; //vector of vector + + for (double doppler_hz = FLAGS_acq_Doppler_error_hz_start; doppler_hz >= FLAGS_acq_Doppler_error_hz_stop; doppler_hz = doppler_hz + FLAGS_acq_Doppler_error_hz_step) + { + acq_doppler_error_hz_values.push_back(doppler_hz); + std::vector tmp_vector; + //Code Delay Sweep + for (double code_delay_chips = FLAGS_acq_Delay_error_chips_start; code_delay_chips >= FLAGS_acq_Delay_error_chips_stop; code_delay_chips = code_delay_chips + FLAGS_acq_Delay_error_chips_step) + { + tmp_vector.push_back(code_delay_chips); + } + acq_delay_error_chips_values.push_back(tmp_vector); + } + + + //*********************************************************** + //***** STEP 2: Generate the input signal (if required) ***** + //*********************************************************** + std::vector generator_CN0_values; + if (FLAGS_enable_external_signal_file) + { + generator_CN0_values.push_back(999); // an external input signal capture is selected, no CN0 information available + } + else + { + if (FLAGS_CN0_dBHz_start == FLAGS_CN0_dBHz_stop) + { + generator_CN0_values.push_back(FLAGS_CN0_dBHz_start); + } + else + { + for (double cn0 = FLAGS_CN0_dBHz_start; cn0 > FLAGS_CN0_dBHz_stop; cn0 = cn0 - FLAGS_CN0_dB_step) + { + generator_CN0_values.push_back(cn0); + } + } + } + + // use generator or use an external capture file + if (FLAGS_enable_external_signal_file) + { + //create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + ASSERT_EQ(acquire_signal(FLAGS_test_satellite_PRN), true); + bool found_satellite = doppler_measurements_map.find(FLAGS_test_satellite_PRN) != doppler_measurements_map.end(); + EXPECT_TRUE(found_satellite) << "Error: satellite SV: " << FLAGS_test_satellite_PRN << " is not acquired"; + if (!found_satellite) return; + } + else + { + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + // Configure the signal generator + configure_generator(generator_CN0_values.at(current_cn0_idx), current_cn0_idx); + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + } + } + + + configure_receiver(FLAGS_PLL_bw_hz_start, + FLAGS_DLL_bw_hz_start, + FLAGS_PLL_narrow_bw_hz, + FLAGS_DLL_narrow_bw_hz, + FLAGS_extend_correlation_symbols); + + //****************************************************************************************** + //***** Obtain the initial signal sinchronization parameters (emulating an acquisition) **** + //****************************************************************************************** + int test_satellite_PRN = 0; + double true_acq_doppler_hz = 0.0; + double true_acq_delay_samples = 0.0; + uint64_t acq_samplestamp_samples = 0; + + tracking_true_obs_reader true_obs_data; + if (!FLAGS_enable_external_signal_file) + { + test_satellite_PRN = FLAGS_test_satellite_PRN; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(test_satellite_PRN)); + true_obs_file.append(".dat"); + true_obs_data.close_obs_file(); + ASSERT_EQ(true_obs_data.open_obs_file(true_obs_file), true) << "Failure opening true observables file"; + // load acquisition data based on the first epoch of the true observations + ASSERT_EQ(true_obs_data.read_binary_obs(), true) + << "Failure reading true tracking dump file." << std::endl + << "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) + + " is not available?"; + std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; + std::cout << "True Initial Doppler " << true_obs_data.doppler_l1_hz << " [Hz], true Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << "[Chips]" << std::endl; + true_acq_doppler_hz = true_obs_data.doppler_l1_hz; + true_acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * static_cast(baseband_sampling_freq) * GPS_L1_CA_CODE_PERIOD; + acq_samplestamp_samples = 0; + } + else + { + true_acq_doppler_hz = doppler_measurements_map.find(FLAGS_test_satellite_PRN)->second; + true_acq_delay_samples = code_delay_measurements_map.find(FLAGS_test_satellite_PRN)->second; + acq_samplestamp_samples = 0; + std::cout << "Estimated Initial Doppler " << true_acq_doppler_hz + << " [Hz], estimated Initial code delay " << true_acq_delay_samples << " [Samples]" + << " Acquisition SampleStamp is " << acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second << std::endl; + } + + // create the msg queue for valve + + queue = gr::msg_queue::make(0); + boost::shared_ptr reseteable_valve; + long long int acq_to_trk_delay_samples = ceil(static_cast(FLAGS_fs_gen_sps) * FLAGS_acq_to_trk_delay_s); + boost::shared_ptr resetable_valve_(new gnss_sdr_valve(sizeof(gr_complex), acq_to_trk_delay_samples, queue, false)); + + std::shared_ptr control_message_factory_; + std::shared_ptr>> control_messages_; + + + //CN0 LOOP + std::vector> pull_in_results_v_v; + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + std::vector pull_in_results_v; + for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) + { + for (unsigned int current_acq_code_error_idx = 0; current_acq_code_error_idx < acq_delay_error_chips_values.at(current_acq_doppler_error_idx).size(); current_acq_code_error_idx++) + { + gnss_synchro.Acq_samplestamp_samples = acq_samplestamp_samples; + //simulate a Doppler error in acquisition + gnss_synchro.Acq_doppler_hz = true_acq_doppler_hz + acq_doppler_error_hz_values.at(current_acq_doppler_error_idx); + //simulate Code Delay error in acquisition + gnss_synchro.Acq_delay_samples = true_acq_delay_samples + (acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) / GPS_L1_CA_CODE_RATE_HZ) * static_cast(baseband_sampling_freq); + + //create flowgraph + top_block = gr::make_top_block("Tracking test"); + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", config->property("Tracking.implementation", std::string("undefined")), 1, 1); + std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); + boost::shared_ptr msg_rx = TrackingPullInTest_msg_rx_make(); + + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + std::string file; + ASSERT_NO_THROW({ + if (!FLAGS_enable_external_signal_file) + { + file = "./" + filename_raw_data + std::to_string(current_cn0_idx); + } + else + { + file = FLAGS_signal_file; + } + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, head_samples, 0); + if (acq_to_trk_delay_samples > 0) + { + top_block->connect(head_samples, 0, resetable_valve_, 0); + top_block->connect(resetable_valve_, 0, tracking->get_left_block(), 0); + } + else + { + top_block->connect(head_samples, 0, tracking->get_left_block(), 0); + } + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + }) << "Failure connecting the blocks of tracking test."; + + + //******************************************************************** + //***** STEP 5: Perform the signal tracking and read the results ***** + //******************************************************************** + std::cout << "--- START TRACKING WITH PULL-IN ERROR: " << acq_doppler_error_hz_values.at(current_acq_doppler_error_idx) << " [Hz] and " << acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) << " [Chips] ---" << std::endl; + std::chrono::time_point start, end; + if (acq_to_trk_delay_samples > 0) + { + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + std::cout << "--- SIMULATING A PULL-IN DELAY OF " << FLAGS_acq_to_trk_delay_s << " SECONDS ---\n"; + top_block->start(); + std::cout << " Waiting for valve...\n"; + //wait the valve message indicating the circulation of the amount of samples of the delay + gr::message::sptr queue_message = queue->delete_head(); + if (queue_message != 0) + { + control_messages_ = control_message_factory_->GetControlMessages(queue_message); + } + else + { + control_messages_->clear(); + } + std::cout << " Starting tracking...\n"; + tracking->start_tracking(); + resetable_valve_->open_valve(); + std::cout << " Waiting flowgraph..\n"; + top_block->wait(); + end = std::chrono::system_clock::now(); + }) << "Failure running the top_block."; + } + else + { + tracking->start_tracking(); + std::chrono::time_point start, end; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + }) << "Failure running the top_block."; + } + + std::chrono::duration elapsed_seconds = end - start; + std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds" << std::endl; + + pull_in_results_v.push_back(msg_rx->rx_message != 3); //save last asynchronous tracking message in order to detect a loss of lock + + //******************************** + //***** STEP 7: Plot results ***** + //******************************** + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) + { + //load the measured values + tracking_dump_reader trk_dump; + ASSERT_EQ(trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")), true) + << "Failure opening tracking dump file"; + + int64_t n_measured_epochs = trk_dump.num_epochs(); + //todo: use vectors instead + arma::vec trk_timestamp_s = arma::zeros(n_measured_epochs, 1); + arma::vec trk_acc_carrier_phase_cycles = arma::zeros(n_measured_epochs, 1); + arma::vec trk_Doppler_Hz = arma::zeros(n_measured_epochs, 1); + arma::vec trk_prn_delay_chips = arma::zeros(n_measured_epochs, 1); + std::vector timestamp_s; + std::vector prompt; + std::vector early; + std::vector late; + std::vector v_early; + std::vector v_late; + std::vector promptI; + std::vector promptQ; + std::vector CN0_dBHz; + std::vector Doppler; + int64_t epoch_counter = 0; + while (trk_dump.read_binary_obs()) + { + trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); + trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; + trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; + double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) / 1.0e-3); + + trk_prn_delay_chips(epoch_counter) = delay_chips; + + timestamp_s.push_back(trk_timestamp_s(epoch_counter)); + prompt.push_back(trk_dump.abs_P); + early.push_back(trk_dump.abs_E); + late.push_back(trk_dump.abs_L); + v_early.push_back(trk_dump.abs_VE); + v_late.push_back(trk_dump.abs_VL); + promptI.push_back(trk_dump.prompt_I); + promptQ.push_back(trk_dump.prompt_Q); + CN0_dBHz.push_back(trk_dump.CN0_SNV_dB_Hz); + Doppler.push_back(trk_dump.carrier_doppler_hz); + epoch_counter++; + } + + + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag show_plots has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + unsigned int decimate = static_cast(FLAGS_plot_decimate); + + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) + { + Gnuplot g1("linespoints"); + g1.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g1.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g1.set_grid(); + g1.set_xlabel("Time [s]"); + g1.set_ylabel("Correlators' output"); + //g1.cmd("set key box opaque"); + g1.plot_xy(trk_timestamp_s, prompt, "Prompt", decimate); + g1.plot_xy(trk_timestamp_s, early, "Early", decimate); + g1.plot_xy(trk_timestamp_s, late, "Late", decimate); + if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + g1.plot_xy(trk_timestamp_s, v_early, "Very Early", decimate); + g1.plot_xy(trk_timestamp_s, v_late, "Very Late", decimate); + } + g1.set_legend(); + g1.savetops("Correlators_outputs"); + + Gnuplot g2("points"); + g2.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g2.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g2.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g2.set_grid(); + g2.set_xlabel("Inphase"); + g2.set_ylabel("Quadrature"); + //g2.cmd("set size ratio -1"); + g2.plot_xy(promptI, promptQ); + g2.savetops("Constellation"); + + Gnuplot g3("linespoints"); + if (!FLAGS_enable_external_signal_file) + { + g3.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g3.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips] PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Reported CN0 [dB-Hz]"); + g3.cmd("set key box opaque"); + + g3.plot_xy(trk_timestamp_s, CN0_dBHz, + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + + g3.set_legend(); + g3.savetops("CN0_output"); + + g3.showonscreen(); // window output + + Gnuplot g4("linespoints"); + if (!FLAGS_enable_external_signal_file) + { + g4.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g4.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips] PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g4.set_grid(); + g4.set_xlabel("Time [s]"); + g4.set_ylabel("Estimated Doppler [Hz]"); + g4.cmd("set key box opaque"); + + g4.plot_xy(trk_timestamp_s, Doppler, + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + + g4.set_legend(); + g4.savetops("Doppler"); + + g4.showonscreen(); // window output + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } //end plot + + } //end acquisition Delay errors loop + } //end acquisition Doppler errors loop + pull_in_results_v_v.push_back(pull_in_results_v); + + + } //end CN0 LOOP + //build the mesh grid + std::vector doppler_error_mesh; + std::vector code_delay_error_mesh; + for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) + { + for (unsigned int current_acq_code_error_idx = 0; current_acq_code_error_idx < acq_delay_error_chips_values.at(current_acq_doppler_error_idx).size(); current_acq_code_error_idx++) + { + doppler_error_mesh.push_back(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)); + code_delay_error_mesh.push_back(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)); + } + } + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + std::vector pull_in_result_mesh; + pull_in_result_mesh = pull_in_results_v_v.at(current_cn0_idx); + //plot grid + Gnuplot g4("points palette pointsize 2 pointtype 7"); + if (FLAGS_show_plots) + { + g4.showonscreen(); // window output + } + else + { + g4.disablescreen(); + } + g4.cmd("set palette defined ( 0 \"black\", 1 \"green\" )"); + g4.cmd("set key off"); + g4.cmd("set view map"); + std::string title; + if (!FLAGS_enable_external_signal_file) + { + title = std::string("Tracking Pull-in result grid at CN0:" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + " [dB-Hz], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz]."); + } + else + { + title = std::string("Tracking Pull-in result grid, PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g4.set_title(title); + g4.set_grid(); + g4.set_xlabel("Acquisition Doppler error [Hz]"); + g4.set_ylabel("Acquisition Code Delay error [Chips]"); + g4.cmd("set cbrange[0:1]"); + g4.plot_xyz(doppler_error_mesh, + code_delay_error_mesh, + pull_in_result_mesh); + g4.set_legend(); + if (!FLAGS_enable_external_signal_file) + { + g4.savetops("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx))))); + g4.savetopdf("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))), 12); + } + else + { + g4.savetops("trk_pull_in_grid_external_file"); + g4.savetopdf("trk_pull_in_grid_external_file", 12); + } + } +} diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc new file mode 100644 index 000000000..0c4683d7a --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc @@ -0,0 +1,1018 @@ +/*! + * \file tracking_test.cc + * \brief This class implements a tracking Pull-In test for GPS_L1_CA_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "GPS_L1_CA.h" +#include "galileo_e5a_noncoherent_iq_acquisition_caf.h" +#include "galileo_e5a_pcps_acquisition.h" +#include "gnss_block_factory.h" +#include "gnuplot_i.h" +#include "gps_l1_ca_pcps_acquisition.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" +#include "gps_l2_m_pcps_acquisition.h" +#include "gps_l5i_pcps_acquisition.h" +#include "in_memory_configuration.h" +#include "signal_generator_flags.h" +#include "test_flags.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_tests_flags.h" +#include "tracking_true_obs_reader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// ######## GNURADIO ACQUISITION BLOCK MESSAGE RECEVER ######### +class Acquisition_msg_rx; + +typedef boost::shared_ptr Acquisition_msg_rx_sptr; + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + + +class Acquisition_msg_rx : public gr::block +{ +private: + friend Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + Acquisition_msg_rx(); + +public: + int rx_message; + gr::top_block_sptr top_block; + ~Acquisition_msg_rx(); //!< Default destructor +}; + + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make() +{ + return Acquisition_msg_rx_sptr(new Acquisition_msg_rx()); +} + + +void Acquisition_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; + top_block->stop(); //stop the flowgraph + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_acquisition Bad cast!\n"; + rx_message = 0; + } +} + + +Acquisition_msg_rx::Acquisition_msg_rx() : gr::block("Acquisition_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&Acquisition_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +Acquisition_msg_rx::~Acquisition_msg_rx() {} +// ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER ######### +class TrackingPullInTestFpga_msg_rx; + +typedef boost::shared_ptr TrackingPullInTestFpga_msg_rx_sptr; + +TrackingPullInTestFpga_msg_rx_sptr TrackingPullInTestFpga_msg_rx_make(); + +class TrackingPullInTestFpga_msg_rx : public gr::block +{ +private: + friend TrackingPullInTestFpga_msg_rx_sptr TrackingPullInTestFpga_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + TrackingPullInTestFpga_msg_rx(); + +public: + int rx_message; + ~TrackingPullInTestFpga_msg_rx(); //!< Default destructor +}; + + +TrackingPullInTestFpga_msg_rx_sptr TrackingPullInTestFpga_msg_rx_make() +{ + return TrackingPullInTestFpga_msg_rx_sptr(new TrackingPullInTestFpga_msg_rx()); +} + + +void TrackingPullInTestFpga_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(msg); + rx_message = message; //3 -> loss of lock + //std::cout << "Received trk message: " << rx_message << std::endl; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_tracking Bad cast!"; + rx_message = 0; + } +} + + +TrackingPullInTestFpga_msg_rx::TrackingPullInTestFpga_msg_rx() : gr::block("TrackingPullInTestFpga_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&TrackingPullInTestFpga_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +TrackingPullInTestFpga_msg_rx::~TrackingPullInTestFpga_msg_rx() +{ +} + + +// ########################################################### + +class TrackingPullInTestFpga : public ::testing::Test +{ +public: + std::string generator_binary; + std::string p1; + std::string p2; + std::string p3; + std::string p4; + std::string p5; + std::string p6; + std::string implementation = FLAGS_trk_test_implementation; + + const int baseband_sampling_freq = FLAGS_fs_gen_sps; + + std::string filename_rinex_obs = FLAGS_filename_rinex_obs; + std::string filename_raw_data = FLAGS_signal_file; + + std::map doppler_measurements_map; + std::map code_delay_measurements_map; + std::map acq_samplestamp_map; + + int configure_generator(double CN0_dBHz, int file_idx); + int generate_signal(); + std::vector check_results_doppler(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + std::vector check_results_acc_carrier_phase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + std::vector check_results_codephase(arma::vec& true_time_s, + arma::vec& true_value, + arma::vec& meas_time_s, + arma::vec& meas_value, + double& mean_error, + double& std_dev_error); + + TrackingPullInTestFpga() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + gnss_synchro = Gnss_Synchro(); + } + + ~TrackingPullInTestFpga() + { + } + + void configure_receiver(double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols); + + bool acquire_signal(int SV_ID); + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro; + size_t item_size; +}; + + +int TrackingPullInTestFpga::configure_generator(double CN0_dBHz, int file_idx) +{ + // Configure signal generator + generator_binary = FLAGS_generator_binary; + + p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file; + if (FLAGS_dynamic_position.empty()) + { + p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10); + } + else + { + p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position); + } + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_signal_file + std::to_string(file_idx); // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + p6 = std::string("-CN0_dBHz=") + std::to_string(CN0_dBHz); // Signal generator CN0 + return 0; +} + + +int TrackingPullInTestFpga::generate_signal() +{ + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], NULL}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +void TrackingPullInTestFpga::configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols) +{ + config = std::make_shared(); + config->set_property("Tracking.dump", "true"); + config->set_property("Tracking.dump_filename", "./tracking_ch_"); + config->set_property("Tracking.implementation", implementation); + config->set_property("Tracking.item_type", "gr_complex"); + config->set_property("Tracking.pll_bw_hz", std::to_string(PLL_wide_bw_hz)); + config->set_property("Tracking.dll_bw_hz", std::to_string(DLL_wide_bw_hz)); + config->set_property("Tracking.extend_correlation_symbols", std::to_string(extend_correlation_symbols)); + config->set_property("Tracking.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz)); + config->set_property("Tracking.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz)); + gnss_synchro.PRN = FLAGS_test_satellite_PRN; + gnss_synchro.Channel_ID = 0; + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + + std::string System_and_Signal; + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "1C"; + System_and_Signal = "GPS L1 CA"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + gnss_synchro.System = 'E'; + std::string signal = "1B"; + System_and_Signal = "Galileo E1B"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_chips", "0.6"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); + config->set_property("Tracking.track_pilot", "true"); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "2S"; + System_and_Signal = "GPS L2CM"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "false"); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0 or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + gnss_synchro.System = 'E'; + std::string signal = "5X"; + System_and_Signal = "Galileo E5a"; + signal.copy(gnss_synchro.Signal, 2, 0); + if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking")); + } + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "false"); + config->set_property("Tracking.order", "2"); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + gnss_synchro.System = 'G'; + std::string signal = "L5"; + System_and_Signal = "GPS L5I"; + signal.copy(gnss_synchro.Signal, 2, 0); + config->set_property("Tracking.early_late_space_chips", "0.5"); + config->set_property("Tracking.track_pilot", "false"); + config->set_property("Tracking.order", "2"); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + std::cout << "*****************************************\n"; + std::cout << "*** Tracking configuration parameters ***\n"; + std::cout << "*****************************************\n"; + std::cout << "Signal: " << System_and_Signal << "\n"; + std::cout << "implementation: " << config->property("Tracking.implementation", std::string("undefined")) << " \n"; + std::cout << "pll_bw_hz: " << config->property("Tracking.pll_bw_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_hz: " << config->property("Tracking.dll_bw_hz", 0.0) << " Hz\n"; + std::cout << "pll_bw_narrow_hz: " << config->property("Tracking.pll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "dll_bw_narrow_hz: " << config->property("Tracking.dll_bw_narrow_hz", 0.0) << " Hz\n"; + std::cout << "extend_correlation_symbols: " << config->property("Tracking.extend_correlation_symbols", 0) << " Symbols\n"; + std::cout << "*****************************************\n"; + std::cout << "*****************************************\n"; +} + + +bool TrackingPullInTestFpga::acquire_signal(int SV_ID) +{ + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) + gr::top_block_sptr top_block; + top_block = gr::make_top_block("Acquisition test"); + + // Satellite signal definition + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.Channel_ID = 0; + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + config->set_property("Acquisition.blocking_on_standby", "true"); + config->set_property("Acquisition.blocking", "true"); + config->set_property("Acquisition.dump", "false"); + config->set_property("Acquisition.dump_filename", "./data/acquisition.dat"); + config->set_property("Acquisition.use_CFAR_algorithm", "false"); + + std::shared_ptr acquisition; + + std::string System_and_Signal; + //create the correspondign acquisition block according to the desired tracking signal + if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + std::string signal = "1C"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L1 CA"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + //acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + std::string signal = "1B"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E1B"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + std::string signal = "2S"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L2CM"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + tmp_gnss_synchro.System = 'E'; + std::string signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition_5X.coherent_integration_time_ms", "1"); + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + config->set_property("Acquisition.CAF_window_hz", "0"); // **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz + config->set_property("Acquisition.Zero_padding", "0"); //**Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. + config->set_property("Acquisition.bit_transition_flag", "false"); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + + else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'E'; + std::string signal = "5X"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + { + tmp_gnss_synchro.System = 'G'; + std::string signal = "L5"; + const char* str = signal.c_str(); // get a C style null terminated string + std::memcpy(static_cast(tmp_gnss_synchro.Signal), str, 3); // copy string into synchro char array: 2 char + null + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L5I"; + config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); + acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->set_channel(0); + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz)); + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz)); + acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); + acquisition->init(); + acquisition->set_local_code(); + acquisition->set_state(1); // Ensure that acquisition starts at the first sample + acquisition->connect(top_block); + + gr::blocks::file_source::sptr file_source; + std::string file = FLAGS_signal_file; + const char* file_name = file.c_str(); + file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + //gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); + + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + //top_block->connect(head_samples, 0, acquisition->get_left_block(), 0); + + boost::shared_ptr msg_rx; + try + { + msg_rx = Acquisition_msg_rx_make(); + } + catch (const std::exception& e) + { + std::cout << "Failure connecting the message port system: " << e.what() << std::endl; + exit(0); + } + + msg_rx->top_block = top_block; + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + // 5. Run the flowgraph + // Get visible GPS satellites (positive acquisitions with Doppler measurements) + // record startup time + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + start = std::chrono::system_clock::now(); + + bool start_msg = true; + + doppler_measurements_map.clear(); + code_delay_measurements_map.clear(); + acq_samplestamp_map.clear(); + + unsigned int MAX_PRN_IDX = 0; + + switch (tmp_gnss_synchro.System) + { + case 'G': + MAX_PRN_IDX = 33; + break; + case 'E': + MAX_PRN_IDX = 37; + break; + default: + MAX_PRN_IDX = 33; + } + + for (unsigned int PRN = 1; PRN < MAX_PRN_IDX; PRN++) + { + tmp_gnss_synchro.PRN = PRN; + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->init(); + acquisition->set_local_code(); + acquisition->reset(); + acquisition->set_state(1); + msg_rx->rx_message = 0; + top_block->run(); + if (start_msg == true) + { + std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; + std::cout << "Searching for " << System_and_Signal << " Satellites..." << std::endl; + std::cout << "["; + start_msg = false; + } + while (msg_rx->rx_message == 0) + { + usleep(100000); + } + if (msg_rx->rx_message == 1) + { + std::cout << " " << PRN << " "; + doppler_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_doppler_hz)); + code_delay_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_delay_samples)); + acq_samplestamp_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_samplestamp_samples)); + } + else + { + std::cout << " . "; + } + top_block->stop(); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + std::cout.flush(); + } + std::cout << "]" << std::endl; + std::cout << "-------------------------------------------\n"; + + for (auto& x : doppler_measurements_map) + { + std::cout << "DETECTED SATELLITE " << System_and_Signal << " PRN: " << x.first << " with Doppler: " << x.second << " [Hz], code phase: " << code_delay_measurements_map.at(x.first) << " [samples] at signal SampleStamp " << acq_samplestamp_map.at(x.first) << "\n"; + } + + // report the elapsed time + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + std::cout << "Total signal acquisition run time " + << elapsed_seconds.count() + << " [seconds]" << std::endl; + return true; +} + +TEST_F(TrackingPullInTestFpga, ValidationOfResults) +{ + //************************************************* + //***** STEP 1: Prepare the parameters sweep ****** + //************************************************* + std::vector + acq_doppler_error_hz_values; + std::vector> acq_delay_error_chips_values; //vector of vector + + for (double doppler_hz = FLAGS_acq_Doppler_error_hz_start; doppler_hz >= FLAGS_acq_Doppler_error_hz_stop; doppler_hz = doppler_hz + FLAGS_acq_Doppler_error_hz_step) + { + acq_doppler_error_hz_values.push_back(doppler_hz); + std::vector tmp_vector; + //Code Delay Sweep + for (double code_delay_chips = FLAGS_acq_Delay_error_chips_start; code_delay_chips >= FLAGS_acq_Delay_error_chips_stop; code_delay_chips = code_delay_chips + FLAGS_acq_Delay_error_chips_step) + { + tmp_vector.push_back(code_delay_chips); + } + acq_delay_error_chips_values.push_back(tmp_vector); + } + + + //*********************************************************** + //***** STEP 2: Generate the input signal (if required) ***** + //*********************************************************** + std::vector generator_CN0_values; + if (FLAGS_enable_external_signal_file) + { + generator_CN0_values.push_back(999); // an external input signal capture is selected, no CN0 information available + } + else + { + if (FLAGS_CN0_dBHz_start == FLAGS_CN0_dBHz_stop) + { + generator_CN0_values.push_back(FLAGS_CN0_dBHz_start); + } + else + { + for (double cn0 = FLAGS_CN0_dBHz_start; cn0 > FLAGS_CN0_dBHz_stop; cn0 = cn0 - FLAGS_CN0_dB_step) + { + generator_CN0_values.push_back(cn0); + } + } + } + + // use generator or use an external capture file + if (FLAGS_enable_external_signal_file) + { + //create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + ASSERT_EQ(acquire_signal(FLAGS_test_satellite_PRN), true); + bool found_satellite = doppler_measurements_map.find(FLAGS_test_satellite_PRN) != doppler_measurements_map.end(); + EXPECT_TRUE(found_satellite) << "Error: satellite SV: " << FLAGS_test_satellite_PRN << " is not acquired"; + if (!found_satellite) return; + } + else + { + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + // Configure the signal generator + configure_generator(generator_CN0_values.at(current_cn0_idx), current_cn0_idx); + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + } + } + + + configure_receiver(FLAGS_PLL_bw_hz_start, + FLAGS_DLL_bw_hz_start, + FLAGS_PLL_narrow_bw_hz, + FLAGS_DLL_narrow_bw_hz, + FLAGS_extend_correlation_symbols); + + //****************************************************************************************** + //***** Obtain the initial signal sinchronization parameters (emulating an acquisition) **** + //****************************************************************************************** + int test_satellite_PRN = 0; + double true_acq_doppler_hz = 0.0; + double true_acq_delay_samples = 0.0; + uint64_t acq_samplestamp_samples = 0; + + tracking_true_obs_reader true_obs_data; + if (!FLAGS_enable_external_signal_file) + { + test_satellite_PRN = FLAGS_test_satellite_PRN; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(test_satellite_PRN)); + true_obs_file.append(".dat"); + true_obs_data.close_obs_file(); + ASSERT_EQ(true_obs_data.open_obs_file(true_obs_file), true) << "Failure opening true observables file"; + // load acquisition data based on the first epoch of the true observations + ASSERT_EQ(true_obs_data.read_binary_obs(), true) + << "Failure reading true tracking dump file." << std::endl + << "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) + + " is not available?"; + std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; + std::cout << "True Initial Doppler " << true_obs_data.doppler_l1_hz << " [Hz], true Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << "[Chips]" << std::endl; + true_acq_doppler_hz = true_obs_data.doppler_l1_hz; + true_acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * static_cast(baseband_sampling_freq) * GPS_L1_CA_CODE_PERIOD; + acq_samplestamp_samples = 0; + } + else + { + true_acq_doppler_hz = doppler_measurements_map.find(FLAGS_test_satellite_PRN)->second; + true_acq_delay_samples = code_delay_measurements_map.find(FLAGS_test_satellite_PRN)->second; + acq_samplestamp_samples = 0; + std::cout << "Estimated Initial Doppler " << true_acq_doppler_hz + << " [Hz], estimated Initial code delay " << true_acq_delay_samples << " [Samples]" + << " Acquisition SampleStamp is " << acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second << std::endl; + } + //CN0 LOOP + std::vector> pull_in_results_v_v; + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + std::vector pull_in_results_v; + for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) + { + for (unsigned int current_acq_code_error_idx = 0; current_acq_code_error_idx < acq_delay_error_chips_values.at(current_acq_doppler_error_idx).size(); current_acq_code_error_idx++) + { + gnss_synchro.Acq_samplestamp_samples = acq_samplestamp_samples; + //simulate a Doppler error in acquisition + gnss_synchro.Acq_doppler_hz = true_acq_doppler_hz + acq_doppler_error_hz_values.at(current_acq_doppler_error_idx); + //simulate Code Delay error in acquisition + gnss_synchro.Acq_delay_samples = true_acq_delay_samples + (acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) / GPS_L1_CA_CODE_RATE_HZ) * static_cast(baseband_sampling_freq); + + //create flowgraph + top_block = gr::make_top_block("Tracking test"); + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", config->property("Tracking.implementation", std::string("undefined")), 1, 1); + std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); + boost::shared_ptr msg_rx = TrackingPullInTestFpga_msg_rx_make(); + + + ASSERT_NO_THROW({ + tracking->set_channel(gnss_synchro.Channel_ID); + }) << "Failure setting channel."; + + ASSERT_NO_THROW({ + tracking->set_gnss_synchro(&gnss_synchro); + }) << "Failure setting gnss_synchro."; + + ASSERT_NO_THROW({ + tracking->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + + std::string file; + ASSERT_NO_THROW({ + if (!FLAGS_enable_external_signal_file) + { + file = "./" + filename_raw_data + std::to_string(current_cn0_idx); + } + else + { + file = FLAGS_signal_file; + } + const char* file_name = file.c_str(); + gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, head_samples, 0); + top_block->connect(head_samples, 0, tracking->get_left_block(), 0); + top_block->connect(tracking->get_right_block(), 0, sink, 0); + top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + }) << "Failure connecting the blocks of tracking test."; + + + //******************************************************************** + //***** STEP 5: Perform the signal tracking and read the results ***** + //******************************************************************** + std::cout << "--- START TRACKING WITH PULL-IN ERROR: " << acq_doppler_error_hz_values.at(current_acq_doppler_error_idx) << " [Hz] and " << acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) << " [Chips] ---" << std::endl; + tracking->start_tracking(); + std::chrono::time_point start, end; + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + }) << "Failure running the top_block."; + + std::chrono::duration elapsed_seconds = end - start; + std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds" << std::endl; + + + pull_in_results_v.push_back(msg_rx->rx_message != 3); //save last asynchronous tracking message in order to detect a loss of lock + + //******************************** + //***** STEP 7: Plot results ***** + //******************************** + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) + { + //load the measured values + tracking_dump_reader trk_dump; + ASSERT_EQ(trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")), true) + << "Failure opening tracking dump file"; + + int64_t n_measured_epochs = trk_dump.num_epochs(); + //todo: use vectors instead + arma::vec trk_timestamp_s = arma::zeros(n_measured_epochs, 1); + arma::vec trk_acc_carrier_phase_cycles = arma::zeros(n_measured_epochs, 1); + arma::vec trk_Doppler_Hz = arma::zeros(n_measured_epochs, 1); + arma::vec trk_prn_delay_chips = arma::zeros(n_measured_epochs, 1); + std::vector timestamp_s; + std::vector prompt; + std::vector early; + std::vector late; + std::vector v_early; + std::vector v_late; + std::vector promptI; + std::vector promptQ; + std::vector CN0_dBHz; + std::vector Doppler; + int64_t epoch_counter = 0; + while (trk_dump.read_binary_obs()) + { + trk_timestamp_s(epoch_counter) = static_cast(trk_dump.PRN_start_sample_count) / static_cast(baseband_sampling_freq); + trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / GPS_TWO_PI; + trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz; + double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast(baseband_sampling_freq), 1.0e-3) / 1.0e-3); + + trk_prn_delay_chips(epoch_counter) = delay_chips; + + timestamp_s.push_back(trk_timestamp_s(epoch_counter)); + prompt.push_back(trk_dump.abs_P); + early.push_back(trk_dump.abs_E); + late.push_back(trk_dump.abs_L); + v_early.push_back(trk_dump.abs_VE); + v_late.push_back(trk_dump.abs_VL); + promptI.push_back(trk_dump.prompt_I); + promptQ.push_back(trk_dump.prompt_Q); + CN0_dBHz.push_back(trk_dump.CN0_SNV_dB_Hz); + Doppler.push_back(trk_dump.carrier_doppler_hz); + epoch_counter++; + } + + + const std::string gnuplot_executable(FLAGS_gnuplot_executable); + if (gnuplot_executable.empty()) + { + std::cout << "WARNING: Although the flag show_plots has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { + try + { + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + unsigned int decimate = static_cast(FLAGS_plot_decimate); + + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) + { + Gnuplot g1("linespoints"); + g1.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g1.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g1.set_grid(); + g1.set_xlabel("Time [s]"); + g1.set_ylabel("Correlators' output"); + //g1.cmd("set key box opaque"); + g1.plot_xy(trk_timestamp_s, prompt, "Prompt", decimate); + g1.plot_xy(trk_timestamp_s, early, "Early", decimate); + g1.plot_xy(trk_timestamp_s, late, "Late", decimate); + if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + { + g1.plot_xy(trk_timestamp_s, v_early, "Very Early", decimate); + g1.plot_xy(trk_timestamp_s, v_late, "Very Late", decimate); + } + g1.set_legend(); + g1.savetops("Correlators_outputs"); + + Gnuplot g2("points"); + g2.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g2.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g2.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g2.set_grid(); + g2.set_xlabel("Inphase"); + g2.set_ylabel("Quadrature"); + //g2.cmd("set size ratio -1"); + g2.plot_xy(promptI, promptQ); + g2.savetops("Constellation"); + + Gnuplot g3("linespoints"); + if (!FLAGS_enable_external_signal_file) + { + g3.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g3.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips] PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Reported CN0 [dB-Hz]"); + g3.cmd("set key box opaque"); + + g3.plot_xy(trk_timestamp_s, CN0_dBHz, + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + + g3.set_legend(); + g3.savetops("CN0_output"); + + g3.showonscreen(); // window output + + Gnuplot g4("linespoints"); + if (!FLAGS_enable_external_signal_file) + { + g4.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g4.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips] PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g4.set_grid(); + g4.set_xlabel("Time [s]"); + g4.set_ylabel("Estimated Doppler [Hz]"); + g4.cmd("set key box opaque"); + + g4.plot_xy(trk_timestamp_s, Doppler, + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + + g4.set_legend(); + g4.savetops("Doppler"); + + g4.showonscreen(); // window output + } + } + catch (const GnuplotException& ge) + { + std::cout << ge.what() << std::endl; + } + } + } //end plot + + } //end acquisition Delay errors loop + } //end acquisition Doppler errors loop + pull_in_results_v_v.push_back(pull_in_results_v); + + + } //end CN0 LOOP + //build the mesh grid + std::vector doppler_error_mesh; + std::vector code_delay_error_mesh; + for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) + { + for (unsigned int current_acq_code_error_idx = 0; current_acq_code_error_idx < acq_delay_error_chips_values.at(current_acq_doppler_error_idx).size(); current_acq_code_error_idx++) + { + doppler_error_mesh.push_back(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)); + code_delay_error_mesh.push_back(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)); + } + } + + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) + { + std::vector pull_in_result_mesh; + pull_in_result_mesh = pull_in_results_v_v.at(current_cn0_idx); + //plot grid + Gnuplot g4("points palette pointsize 2 pointtype 7"); + if (FLAGS_show_plots) + { + g4.showonscreen(); // window output + } + else + { + g4.disablescreen(); + } + g4.cmd("set palette defined ( 0 \"black\", 1 \"green\" )"); + g4.cmd("set key off"); + g4.cmd("set view map"); + std::string title; + if (!FLAGS_enable_external_signal_file) + { + title = std::string("Tracking Pull-in result grid at CN0:" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + " [dB-Hz], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz]."); + } + else + { + title = std::string("Tracking Pull-in result grid, PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + + g4.set_title(title); + g4.set_grid(); + g4.set_xlabel("Acquisition Doppler error [Hz]"); + g4.set_ylabel("Acquisition Code Delay error [Chips]"); + g4.cmd("set cbrange[0:1]"); + g4.plot_xyz(doppler_error_mesh, + code_delay_error_mesh, + pull_in_result_mesh); + g4.set_legend(); + if (!FLAGS_enable_external_signal_file) + { + g4.savetops("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx))))); + g4.savetopdf("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))), 12); + } + else + { + g4.savetops("trk_pull_in_grid_external_file"); + g4.savetopdf("trk_pull_in_grid_external_file", 12); + } + } +} diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc new file mode 100644 index 000000000..b69c8fd15 --- /dev/null +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc @@ -0,0 +1,140 @@ +/*! + * \file glonass_gnav_ephemeris_test.cc.cc + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_gnav_ephemeris.h" +#include "gnss_signal_processing.h" + + +TEST(GlonassGnavEphemerisTest, ComputeGlonassTime) +{ + Glonass_Gnav_Ephemeris gnav_eph; + gnav_eph.d_yr = 2016; + gnav_eph.d_N_T = 367; + boost::posix_time::time_duration t(0, 0, 7560); + boost::gregorian::date d(gnav_eph.d_yr, 1, 1); + boost::gregorian::days d2(gnav_eph.d_N_T); + d = d + d2; + + boost::gregorian::date expected_gdate; + boost::posix_time::time_duration expected_gtime; + + boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560); + expected_gdate = gtime.date(); + expected_gtime = gtime.time_of_day(); + + // Perform assertions of decoded fields + ASSERT_TRUE(expected_gdate.year() - d.year() < FLT_EPSILON); + ASSERT_TRUE(expected_gdate.month() - d.month() < FLT_EPSILON); + ASSERT_TRUE(expected_gdate.day() - d.day() < FLT_EPSILON); + ASSERT_TRUE(expected_gtime.hours() - t.hours() < FLT_EPSILON); + ASSERT_TRUE(expected_gtime.minutes() - t.minutes() < FLT_EPSILON); + ASSERT_TRUE(expected_gtime.seconds() - t.seconds() < FLT_EPSILON); +} + + +/*! + * \brief Testing conversion from GLONASST to GPST + * \test Tests scenario for N_T when greater than 365 days. Possible values here from 1 to 365*4 + */ +TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT1) +{ + Glonass_Gnav_Ephemeris gnav_eph; + gnav_eph.d_yr = 2004; + gnav_eph.d_N_T = 366 + 28; + + double glo2utc = 3600 * 3; + double tod = 48600; + double week = 0.0; + double tow = 0.0; + double true_leap_sec = 13; + double true_week = 1307; + double true_tow = 480600 + true_leap_sec; + + gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow); + + // Perform assertions of decoded fields + ASSERT_TRUE(week - true_week < FLT_EPSILON); + ASSERT_TRUE(tow - true_tow < FLT_EPSILON); +} + + +/*! + * \brief Testing conversion from GLONASST to GPST + * \test This version tests the conversion for offsets greater than 30 in a leap year + */ +TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT2) +{ + Glonass_Gnav_Ephemeris gnav_eph; + gnav_eph.d_yr = 2016; + gnav_eph.d_N_T = 268; + + double glo2utc = 3600 * 3; + double tod = 7560; + double week = 0.0; + double tow = 0.0; + double true_leap_sec = 17; + double true_week = 1915; + double true_tow = 518400 + true_leap_sec + tod; + + gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow); + + // Perform assertions of decoded fields + ASSERT_TRUE(week - true_week < FLT_EPSILON); + ASSERT_TRUE(tow - true_tow < FLT_EPSILON); +} + + +/*! + * \brief Testing conversion from GLONASST to GPST + * \test This version tests the conversion around the vicinity of February 29 days when in leap year + */ +TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT3) +{ + Glonass_Gnav_Ephemeris gnav_eph; + gnav_eph.d_yr = 2016; + gnav_eph.d_N_T = 62; + + double glo2utc = 3600 * 3; + double tod = 7560; + double week = 0.0; + double tow = 0.0; + double true_leap_sec = 17; + double true_week = 1886; + double true_tow = 259200 + true_leap_sec + tod; + + gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow); + + // Perform assertions of decoded fields + ASSERT_TRUE(week - true_week < FLT_EPSILON); + ASSERT_TRUE(tow - true_tow < FLT_EPSILON); +} diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc new file mode 100644 index 000000000..3b91be0e6 --- /dev/null +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc @@ -0,0 +1,268 @@ +/*! + * \file glonass_gnav_navigation_message_test.cc + * \brief This file implements tests for the decoding of the GLONASS GNAV navigation message + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_navigation_message.h" +#include "gnss_signal_processing.h" + +/*! + * \brief Testing CRC computation for GLONASS GNAV data bits of a string + * \test The provided string was generated with a version of MATLAB GNSS-SDR that + * the author coded to perform proper decoding of GLONASS GNAV signals. + */ +TEST(GlonassGnavNavigationMessageTest, CRCTestSuccess) +{ + // Variables declarations in code + bool test_result; + std::bitset string_bits(std::string("0010100100001100000000000000000000000000110011110001100000000000000001100100011000000")); + Glonass_Gnav_Navigation_Message gnav_nav_message; + gnav_nav_message.reset(); + + // Call function to test + test_result = gnav_nav_message.CRC_test(string_bits); + + // Check results in unit test assetions + ASSERT_TRUE(test_result); +} + + +/*! + * \brief Testing CRC computation for GLONASS GNAV data bits of a string + * \test The provided string was generated with a version of MATLAB GNSS-SDR that + * the author coded to perform proper decoding of GLONASS GNAV signals. + */ +TEST(GlonassGnavNavigationMessageTest, CRCTestFailure) +{ + // Variables declarations in code + bool test_result; + // Constructor of string to bitset will flip the order of the bits. Needed for CRC computation + std::bitset string_bits(std::string("0111100100001100000000000000000000000000110011110001100000000000000001100100011000000")); + Glonass_Gnav_Navigation_Message gnav_nav_message; + gnav_nav_message.reset(); + + // Call function to test + test_result = gnav_nav_message.CRC_test(string_bits); + + // Check results in unit test assetions + ASSERT_FALSE(test_result); +} + + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String1Decoder) +{ + // Variable declarations + std::string str1("0000100000001000011001000011111011010101110100000010101011000100011010101011000101111"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_P_1 = 15; + gnav_ephemeris.d_t_k = 7560; + gnav_ephemeris.d_VXn = -0.490900039672852; + gnav_ephemeris.d_AXn = 0; + gnav_ephemeris.d_Xn = -11025.6669921875; + + // Call target test method + gnav_nav_message.string_decoder(str1); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_P_1 - gnav_nav_message.gnav_ephemeris.d_P_1 < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_t_k - gnav_nav_message.gnav_ephemeris.d_t_k < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_VXn - gnav_nav_message.gnav_ephemeris.d_VXn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_AXn - gnav_nav_message.gnav_ephemeris.d_AXn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_Xn - gnav_nav_message.gnav_ephemeris.d_Xn < FLT_EPSILON); +} + + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String2Decoder) +{ + // Variable declarations + std::string str2("0001000010001001000001010101100001011001011000000010101100110000001011110000110011110"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_B_n = 0; + gnav_ephemeris.d_P_2 = 1; + gnav_ephemeris.d_t_b = 8100; + gnav_ephemeris.d_VYn = -2.69022750854492; + gnav_ephemeris.d_AYn = 0; + gnav_ephemeris.d_Yn = -11456.7348632812; + + // Call target test method + gnav_nav_message.flag_ephemeris_str_1 = true; + gnav_nav_message.gnav_ephemeris.d_P_1 = 15; + gnav_nav_message.string_decoder(str2); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_B_n - gnav_nav_message.gnav_ephemeris.d_B_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_P_2 - gnav_nav_message.gnav_ephemeris.d_P_2 < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_t_b - gnav_nav_message.gnav_ephemeris.d_t_b < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_VYn - gnav_nav_message.gnav_ephemeris.d_VYn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_AYn - gnav_nav_message.gnav_ephemeris.d_AYn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_Yn - gnav_nav_message.gnav_ephemeris.d_Yn < FLT_EPSILON); +} + + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String3Decoder) +{ + // Variable declarations + std::string str3("0001110000000001001101001110100011111011010011001101001101110110010011110011100100011"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_P_3 = 1; + gnav_ephemeris.d_gamma_n = 1.81898940354586e-12; + gnav_ephemeris.d_P = 3; + gnav_ephemeris.d_l3rd_n = 0; + gnav_ephemeris.d_VZn = -1.82016849517822; + gnav_ephemeris.d_AZn = -2.79396772384644e-09; + gnav_ephemeris.d_Zn = 19929.2377929688; + + // Call target test method + gnav_nav_message.flag_ephemeris_str_2 = true; + gnav_nav_message.string_decoder(str3); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_P_3 - gnav_nav_message.gnav_ephemeris.d_P_3 < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_gamma_n - gnav_nav_message.gnav_ephemeris.d_gamma_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_P - gnav_nav_message.gnav_ephemeris.d_P < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_l3rd_n - gnav_nav_message.gnav_ephemeris.d_l3rd_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_VZn - gnav_nav_message.gnav_ephemeris.d_VZn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_AZn - gnav_nav_message.gnav_ephemeris.d_AZn < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_Zn - gnav_nav_message.gnav_ephemeris.d_Zn < FLT_EPSILON); +} + + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String4Decoder) +{ + // Variable declarations + std::string str4("0010010000101011100100000100000100000000000000000000011000100100001100101010100011101"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_tau_n = -8.30907374620438e-05; + gnav_ephemeris.d_Delta_tau_n = 9.31322574615479e-10; + gnav_ephemeris.d_E_n = 0; + gnav_ephemeris.d_P_4 = 0; + gnav_ephemeris.d_F_T = 6; + gnav_ephemeris.d_N_T = 268; + gnav_ephemeris.d_n = 21; + gnav_ephemeris.d_M = 1; + + // Call target test method + gnav_nav_message.flag_ephemeris_str_3 = true; + gnav_nav_message.string_decoder(str4); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_tau_n - gnav_nav_message.gnav_ephemeris.d_tau_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_Delta_tau_n - gnav_nav_message.gnav_ephemeris.d_Delta_tau_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_E_n - gnav_nav_message.gnav_ephemeris.d_E_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_P_4 - gnav_nav_message.gnav_ephemeris.d_P_4 < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_F_T - gnav_nav_message.gnav_ephemeris.d_F_T < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_N_T - gnav_nav_message.gnav_ephemeris.d_N_T < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_n - gnav_nav_message.gnav_ephemeris.d_n < FLT_EPSILON); + ASSERT_TRUE(gnav_ephemeris.d_M - gnav_nav_message.gnav_ephemeris.d_M < FLT_EPSILON); +} + + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String5Decoder) +{ + // Variable declarations + std::string str5("0010100100001100000000000000000000000000110011110001100000000000000001100100011000000"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Utc_Model gnav_utc_model; + + // Fill out ephemeris values for truth + gnav_utc_model.d_N_A = 268; + gnav_utc_model.d_tau_c = 9.6391886472702e-08; + gnav_utc_model.d_N_4 = 6; + gnav_utc_model.d_tau_gps = 9.313225746154785e-08; + + // Call target test method + gnav_nav_message.flag_ephemeris_str_4 = true; + gnav_nav_message.string_decoder(str5); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_utc_model.d_N_A - gnav_nav_message.gnav_utc_model.d_N_A < FLT_EPSILON); + ASSERT_TRUE(gnav_utc_model.d_tau_c - gnav_nav_message.gnav_utc_model.d_tau_c < FLT_EPSILON); + ASSERT_TRUE(gnav_utc_model.d_N_4 - gnav_nav_message.gnav_utc_model.d_N_4 < FLT_EPSILON); + ASSERT_TRUE(gnav_utc_model.d_tau_gps - gnav_nav_message.gnav_utc_model.d_tau_gps < FLT_EPSILON); +} + +std::string str6("0011010100110100001100111100011100001101011000000110101111001000000101100011111011001"); +std::string str7("0011101101010001000010000110101111110000101101001011111110101110100010111100010001101"); +std::string str8("0100010100111000000001111110001101000000110000001000100111011100001010101111010011010"); +std::string str9("0100111010001001011100010000010100010101111101001011111110101011100010100101000110101"); +std::string str10("0101010101000000000011101111111101111001011000001000101010001100001111000110101111110"); +std::string str11("0101110111011011011100011001111011101111001101001011111111000110100100000110010001111"); +std::string str12("0110010101001100000011110110100110100100010100001000111110000100001110001010111000001"); +std::string str13("0110111011100100111110100001000110100010011101001011111110100100101010011010001101001"); +std::string str14("0111010101010000000100011000011110100110111100001110110100001000001111001101010000101"); +std::string str15("0111101110101010001110101010100111101100001101001011111111100010101010011001010011101"); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index ed785f695..c68294b45 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,7 +13,11 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # add_subdirectory(front-end-cal) + +if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA OR ENABLE_FPGA) + add_subdirectory(rinex2assist) +endif() diff --git a/src/utils/front-end-cal/CMakeLists.txt b/src/utils/front-end-cal/CMakeLists.txt index ce1457bd3..16dfa40be 100644 --- a/src/utils/front-end-cal/CMakeLists.txt +++ b/src/utils/front-end-cal/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2015 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -13,15 +13,16 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNSS-SDR. If not, see . +# along with GNSS-SDR. If not, see . # if(OPENSSL_FOUND) - add_definitions( -DUSE_OPENSSL_FALLBACK=1 ) -endif(OPENSSL_FOUND) + add_definitions(-DUSE_OPENSSL_FALLBACK=1) +endif() set(FRONT_END_CAL_SOURCES front_end_cal.cc) +set(FRONT_END_CAL_HEADERS front_end_cal.h) include_directories( ${CMAKE_SOURCE_DIR}/src/core/system_parameters @@ -30,89 +31,86 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core/libs ${CMAKE_SOURCE_DIR}/src/core/libs/supl ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp - ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl - ${CMAKE_SOURCE_DIR}/src/algorithms/libs + ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs + ${CMAKE_SOURCE_DIR}/src/algorithms/libs ${GLOG_INCLUDE_DIRS} ${GFlags_INCLUDE_DIRS} ${GNURADIO_RUNTIME_INCLUDE_DIRS} ${GNURADIO_BLOCKS_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} + ${PUGIXML_INCLUDE_DIR} ${VOLK_GNSSSDR_INCLUDE_DIRS} ) -file(GLOB FRONT_END_CAL_HEADERS "*.h") -list(SORT FRONT_END_CAL_HEADERS) add_library(front_end_cal_lib ${FRONT_END_CAL_SOURCES} ${FRONT_END_CAL_HEADERS}) source_group(Headers FILES ${FRONT_END_CAL_HEADERS}) -target_link_libraries(front_end_cal_lib ${MAC_LIBRARIES} - ${Boost_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${ARMADILLO_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} - ${GNSS_SDR_OPTIONAL_LIBS} - rx_core_lib - gnss_rx - channel_fsm - gnss_sp_libs +target_link_libraries(front_end_cal_lib + ${MAC_LIBRARIES} + ${THREAD_LIBRARIES} + ${Boost_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + ${GNSS_SDR_OPTIONAL_LIBS} + rx_core_lib + gnss_sdr_flags + gnss_rx + channel_fsm ) - + add_dependencies(front_end_cal_lib glog-${glog_RELEASE} armadillo-${armadillo_RELEASE}) -add_definitions( -DGNSS_SDR_VERSION="${VERSION}" ) -add_definitions( -DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}" ) +add_definitions(-DGNSS_SDR_VERSION="${VERSION}") +add_definitions(-DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}") add_executable(front-end-cal ${CMAKE_CURRENT_SOURCE_DIR}/main.cc) add_custom_command(TARGET front-end-cal POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_SOURCE_DIR}/install/$) + COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$) - -target_link_libraries(front-end-cal ${MAC_LIBRARIES} - ${Boost_LIBRARIES} - ${GNURADIO_RUNTIME_LIBRARIES} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${GFlags_LIBS} - ${GLOG_LIBRARIES} - ${ARMADILLO_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} - ${GNSS_SDR_OPTIONAL_LIBS} - rx_core_lib - gnss_rx - gnss_sp_libs - front_end_cal_lib +target_link_libraries(front-end-cal + ${MAC_LIBRARIES} + ${Boost_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GFlags_LIBS} + ${GLOG_LIBRARIES} + ${ARMADILLO_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + ${GNSS_SDR_OPTIONAL_LIBS} + rx_core_lib + gnss_rx + front_end_cal_lib ) - install(TARGETS front-end-cal - RUNTIME DESTINATION bin - COMPONENT "front-end-cal" + RUNTIME DESTINATION bin + COMPONENT "front-end-cal" ) find_program(GZIP gzip - /bin - /usr/bin - /usr/local/bin - /opt/local/bin - /sbin - ) + /bin + /usr/bin + /usr/local/bin + /opt/local/bin + /sbin +) if(NOT GZIP_NOTFOUND) execute_process(COMMAND gzip -9 -c ${CMAKE_SOURCE_DIR}/docs/manpage/front-end-cal-manpage - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/front-end-cal.1.gz") - + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_FILE "${CMAKE_BINARY_DIR}/front-end-cal.1.gz") install(FILES ${CMAKE_BINARY_DIR}/front-end-cal.1.gz DESTINATION share/man/man1) -endif(NOT GZIP_NOTFOUND) - - +endif() diff --git a/src/utils/front-end-cal/front_end_cal.cc b/src/utils/front-end-cal/front_end_cal.cc index a3d0cf04d..9fd80f772 100644 --- a/src/utils/front-end-cal/front_end_cal.cc +++ b/src/utils/front-end-cal/front_end_cal.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,30 +24,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ #include "front_end_cal.h" -#include -#include -#include -#include +#include "gnss_sdr_supl_client.h" +#include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_navigation_message.h" +#include "gps_utc_model.h" #include -#include -#include +#include #include #include -#include -#include "gps_navigation_message.h" -#include "gps_ephemeris.h" -#include "gps_cnav_ephemeris.h" -#include "gps_almanac.h" -#include "gps_iono.h" -#include "gps_cnav_iono.h" -#include "gps_utc_model.h" -#include "gnss_sdr_supl_client.h" +#include +#include +#include +#include +#include extern concurrent_map global_gps_ephemeris_map; extern concurrent_map global_gps_iono_map; @@ -55,11 +54,9 @@ extern concurrent_map global_gps_utc_model_map; extern concurrent_map global_gps_almanac_map; extern concurrent_map global_gps_acq_assist_map; -FrontEndCal::FrontEndCal() -{} +FrontEndCal::FrontEndCal() = default; -FrontEndCal::~FrontEndCal() -{} +FrontEndCal::~FrontEndCal() = default; bool FrontEndCal::read_assistance_from_XML() { @@ -69,10 +66,10 @@ bool FrontEndCal::read_assistance_from_XML() LOG(INFO) << "SUPL: Trying to read GPS ephemeris from XML file " << eph_xml_filename; if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename) == true) { - std::map::iterator gps_eph_iter; - for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); - gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); - gps_eph_iter++) + std::map::iterator gps_eph_iter; + for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); + gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); + gps_eph_iter++) { std::cout << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first << std::endl; LOG(INFO) << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first; @@ -81,23 +78,21 @@ bool FrontEndCal::read_assistance_from_XML() } return true; } - else - { - std::cout << "ERROR: SUPL client error reading XML" << std::endl; - LOG(WARNING) << "ERROR: SUPL client error reading XML"; - return false; - } + std::cout << "ERROR: SUPL client error reading XML" << std::endl; + LOG(WARNING) << "ERROR: SUPL client error reading XML"; + return false; } + int FrontEndCal::Get_SUPL_Assist() { //######### GNSS Assistance ################################# gnss_sdr_supl_client supl_client_acquisition_; gnss_sdr_supl_client supl_client_ephemeris_; - int supl_mcc; // Current network MCC (Mobile country code), 3 digits. - int supl_mns; //Current network MNC (Mobile Network code), 2 or 3 digits. - int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values. - int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values). + int supl_mcc; // Current network MCC (Mobile country code), 3 digits. + int supl_mns; //Current network MNC (Mobile Network code), 2 or 3 digits. + int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values. + int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values). // GNSS Assistance configuration int error = 0; @@ -113,26 +108,26 @@ int FrontEndCal::Get_SUPL_Assist() supl_client_ephemeris_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_port", 7275); supl_client_acquisition_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_acquisition_port", 7275); supl_mcc = configuration_->property("GNSS-SDR.SUPL_MCC", 244); - supl_mns = configuration_->property("GNSS-SDR.SUPL_MNS", 5); + supl_mns = configuration_->property("GNSS-SDR.SUPL_MNC", 5); std::string default_lac = "0x59e2"; std::string default_ci = "0x31b0"; try - { + { supl_lac = boost::lexical_cast(configuration_->property("GNSS-SDR.SUPL_LAC", default_lac)); - } - catch(boost::bad_lexical_cast &) - { + } + catch (boost::bad_lexical_cast &) + { supl_lac = 0x59e2; - } + } try - { + { supl_ci = boost::lexical_cast(configuration_->property("GNSS-SDR.SUPL_CI", default_ci)); - } - catch(boost::bad_lexical_cast &) - { + } + catch (boost::bad_lexical_cast &) + { supl_ci = 0x31b0; - } + } bool SUPL_read_gps_assistance_xml = configuration_->property("GNSS-SDR.SUPL_read_gps_assistance_xml", false); if (SUPL_read_gps_assistance_xml == true) @@ -149,21 +144,21 @@ int FrontEndCal::Get_SUPL_Assist() error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_eph_iter; - for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); - gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); - gps_eph_iter++) + std::map::iterator gps_eph_iter; + for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin(); + gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end(); + gps_eph_iter++) { - LOG(INFO) << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first; + LOG(INFO) << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first; std::cout << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first << std::endl; - LOG(INFO) << "New Ephemeris record inserted with Toe=" << gps_eph_iter->second.d_Toe << " and GPS Week=" << gps_eph_iter->second.i_GPS_week; + LOG(INFO) << "New Ephemeris record inserted with Toe=" << gps_eph_iter->second.d_Toe << " and GPS Week=" << gps_eph_iter->second.i_GPS_week; global_gps_ephemeris_map.write(gps_eph_iter->second.i_satellite_PRN, gps_eph_iter->second); } //Save ephemeris to XML file std::string eph_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename); if (supl_client_ephemeris_.save_ephemeris_map_xml(eph_xml_filename, supl_client_ephemeris_.gps_ephemeris_map) == true) { - LOG(INFO) << "SUPL: XML Ephemeris file created."; + LOG(INFO) << "SUPL: XML Ephemeris file created."; } } else @@ -178,10 +173,10 @@ int FrontEndCal::Get_SUPL_Assist() error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_alm_iter; - for(gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.begin(); - gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.end(); - gps_alm_iter++) + std::map::iterator gps_alm_iter; + for (gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.begin(); + gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.end(); + gps_alm_iter++) { LOG(INFO) << "SUPL: Received Almanac for GPS SV " << gps_alm_iter->first; std::cout << "SUPL: Received Almanac for GPS SV " << gps_alm_iter->first << std::endl; @@ -191,11 +186,11 @@ int FrontEndCal::Get_SUPL_Assist() { LOG(INFO) << "SUPL: Received GPS Iono"; std::cout << "SUPL: Received GPS Iono" << std::endl; - global_gps_iono_map.write(0,supl_client_ephemeris_.gps_iono); + global_gps_iono_map.write(0, supl_client_ephemeris_.gps_iono); } if (supl_client_ephemeris_.gps_utc.valid == true) { - LOG(INFO) << "SUPL: Received GPS UTC Model"; + LOG(INFO) << "SUPL: Received GPS UTC Model"; std::cout << "SUPL: Received GPS UTC Model" << std::endl; global_gps_utc_model_map.write(0, supl_client_ephemeris_.gps_utc); } @@ -214,10 +209,10 @@ int FrontEndCal::Get_SUPL_Assist() error = supl_client_acquisition_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci); if (error == 0) { - std::map::iterator gps_acq_iter; - for(gps_acq_iter = supl_client_acquisition_.gps_acq_map.begin(); - gps_acq_iter != supl_client_acquisition_.gps_acq_map.end(); - gps_acq_iter++) + std::map::iterator gps_acq_iter; + for (gps_acq_iter = supl_client_acquisition_.gps_acq_map.begin(); + gps_acq_iter != supl_client_acquisition_.gps_acq_map.end(); + gps_acq_iter++) { LOG(INFO) << "SUPL: Received Acquisition assistance for GPS SV " << gps_acq_iter->first; std::cout << "SUPL: Received Acquisition assistance for GPS SV " << gps_acq_iter->first << std::endl; @@ -238,7 +233,7 @@ int FrontEndCal::Get_SUPL_Assist() void FrontEndCal::set_configuration(std::shared_ptr configuration) { - configuration_ = configuration; + configuration_ = std::move(configuration); } @@ -248,7 +243,7 @@ bool FrontEndCal::get_ephemeris() if (read_ephemeris_from_xml == true) { - std::cout << "Trying to read ephemeris from XML file..." << std::endl; + std::cout << "Trying to read ephemeris from XML file..." << std::endl; LOG(INFO) << "Trying to read ephemeris from XML file..."; if (read_assistance_from_XML() == false) { @@ -258,33 +253,22 @@ bool FrontEndCal::get_ephemeris() { return true; } - else - { - return false; - } - } - else - { - return true; - } - } - else - { - std::cout << "Trying to read ephemeris from SUPL server..." << std::endl; - LOG(INFO) << "Trying to read ephemeris from SUPL server..."; - if (Get_SUPL_Assist() == 0) - { - return true; - } - else - { return false; } + return true; } + + std::cout << "Trying to read ephemeris from SUPL server..." << std::endl; + LOG(INFO) << "Trying to read ephemeris from SUPL server..."; + if (Get_SUPL_Assist() == 0) + { + return true; + } + return false; } -arma::vec FrontEndCal::lla2ecef(const arma::vec & lla) +arma::vec FrontEndCal::lla2ecef(const arma::vec &lla) { // WGS84 flattening double f = 1.0 / 298.257223563; @@ -297,7 +281,7 @@ arma::vec FrontEndCal::lla2ecef(const arma::vec & lla) double lambda = (lla(1) / 360.0) * GPS_TWO_PI; ellipsoid(0) = R; - ellipsoid(1) = sqrt(1.0 - (1.0 - f)*(1.0 - f)); + ellipsoid(1) = sqrt(1.0 - (1.0 - f) * (1.0 - f)); arma::vec ecef = "0.0 0.0 0.0 0.0"; ecef = geodetic2ecef(phi, lambda, lla(3), ellipsoid); @@ -306,18 +290,18 @@ arma::vec FrontEndCal::lla2ecef(const arma::vec & lla) } -arma::vec FrontEndCal::geodetic2ecef(double phi, double lambda, double h, const arma::vec & ellipsoid) +arma::vec FrontEndCal::geodetic2ecef(double phi, double lambda, double h, const arma::vec &ellipsoid) { double a = ellipsoid(0); - double e2 = ellipsoid(1)*ellipsoid(1); + double e2 = ellipsoid(1) * ellipsoid(1); double sinphi = sin(phi); double cosphi = cos(phi); - double N = a / sqrt(1.0 - e2 * sinphi*sinphi); + double N = a / sqrt(1.0 - e2 * sinphi * sinphi); arma::vec ecef = "0.0 0.0 0.0 0.0"; ecef(0) = (N + h) * cosphi * cos(lambda); ecef(1) = (N + h) * cosphi * sin(lambda); - ecef(2) = (N*(1.0 - e2) + h) * sinphi; + ecef(2) = (N * (1.0 - e2) + h) * sinphi; return ecef; } @@ -337,22 +321,22 @@ double FrontEndCal::estimate_doppler_from_eph(unsigned int PRN, double TOW, doub obs_ecef = lla2ecef(lla); // Satellite positions ECEF - std::map eph_map; + std::map eph_map; eph_map = global_gps_ephemeris_map.get_map_copy(); - std::map::iterator eph_it; + std::map::iterator eph_it; eph_it = eph_map.find(PRN); - if (eph_it!=eph_map.end()) + if (eph_it != eph_map.end()) { arma::vec SV_pos_ecef = "0.0 0.0 0.0 0.0"; double obs_time_start, obs_time_stop; - obs_time_start = TOW - num_secs/2; - obs_time_stop = TOW + num_secs/2; - int n_points = round((obs_time_stop - obs_time_start)/step_secs); + obs_time_start = TOW - num_secs / 2; + obs_time_stop = TOW + num_secs / 2; + int n_points = round((obs_time_stop - obs_time_start) / step_secs); arma::vec ranges = arma::zeros(n_points, 1); double obs_time = obs_time_start; - for (int i=0; isecond.satellitePosition(obs_time); SV_pos_ecef(0) = eph_it->second.d_satpos_X; @@ -366,7 +350,7 @@ double FrontEndCal::estimate_doppler_from_eph(unsigned int PRN, double TOW, doub // Numeric derivative: Positive slope means that the distance from obs to // satellite is increasing arma::vec obs_to_sat_velocity; - obs_to_sat_velocity = (ranges.subvec(1, (n_points - 1)) - ranges.subvec(0, (n_points - 2)))/step_secs; + obs_to_sat_velocity = (ranges.subvec(1, (n_points - 1)) - ranges.subvec(0, (n_points - 2))) / step_secs; // Doppler equations are formulated accounting for positive velocities if the // tx and rx are approaching to each other. So, the satellite velocity must // be redefined as: @@ -374,15 +358,12 @@ double FrontEndCal::estimate_doppler_from_eph(unsigned int PRN, double TOW, doub //Doppler estimation arma::vec Doppler_Hz; - Doppler_Hz = (obs_to_sat_velocity/GPS_C_m_s)*GPS_L1_FREQ_HZ; + Doppler_Hz = (obs_to_sat_velocity / GPS_C_m_s) * GPS_L1_FREQ_HZ; double mean_Doppler_Hz; mean_Doppler_Hz = arma::mean(Doppler_Hz); return mean_Doppler_Hz; } - else - { - throw(1); - } + throw(1); } @@ -396,22 +377,20 @@ void FrontEndCal::GPS_L1_front_end_model_E4000(double f_bb_true_Hz, double f_bb_ const double R = 2.0; // Obtained RF center frequency - double f_rf_pll = (f_osc_n * (N + X / Y)) /R; + double f_rf_pll = (f_osc_n * (N + X / Y)) / R; // RF frequency error caused by fractional PLL roundings double f_bb_err_pll = GPS_L1_FREQ_HZ - f_rf_pll; // Measured F_rf error double f_rf_err = (f_bb_meas_Hz - f_bb_true_Hz) - f_bb_err_pll; - double f_osc_err_hz = (f_rf_err*R)/(N+X/Y); + double f_osc_err_hz = (f_rf_err * R) / (N + X / Y); // OJO,segun los datos gnss, la IF positiva hace disminuir la fs!! f_osc_err_hz = -f_osc_err_hz; - *f_osc_err_ppm = f_osc_err_hz/(f_osc_n/1e6); + *f_osc_err_ppm = f_osc_err_hz / (f_osc_n / 1e6); - double frac = fs_nominal_hz/f_osc_n; - *estimated_fs_Hz = frac*(f_osc_n + f_osc_err_hz); + double frac = fs_nominal_hz / f_osc_n; + *estimated_fs_Hz = frac * (f_osc_n + f_osc_err_hz); *estimated_f_if_Hz = f_rf_err; } - - diff --git a/src/utils/front-end-cal/front_end_cal.h b/src/utils/front-end-cal/front_end_cal.h index 51581b6b4..261043461 100644 --- a/src/utils/front-end-cal/front_end_cal.h +++ b/src/utils/front-end-cal/front_end_cal.h @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,9 +32,9 @@ #ifndef GNSS_SDR_FRONT_END_CAL_H_ #define GNSS_SDR_FRONT_END_CAL_H_ -#include -#include "file_configuration.h" #include "concurrent_map.h" +#include "file_configuration.h" +#include class FrontEndCal @@ -49,7 +49,7 @@ private: * coordinates, P. LLA is in [degrees degrees meters]. P is in meters. * The default ellipsoid planet is WGS84. Original copyright (c) by Kai Borre. */ - arma::vec lla2ecef(const arma::vec & lla); + arma::vec lla2ecef(const arma::vec &lla); /*! * GEODETIC2ECEF Convert geodetic to geocentric (ECEF) coordinates * [X, Y, Z] = GEODETIC2ECEF(PHI, LAMBDA, H, ELLIPSOID) converts geodetic @@ -80,7 +80,7 @@ private: * Paul R. Wolf and Bon A. Dewitt, "Elements of Photogrammetry with * Applications in GIS," 3rd Ed., McGraw-Hill, 2000 (Appendix F-3). */ - arma::vec geodetic2ecef(double phi, double lambda, double h, const arma::vec & ellipsoid); + arma::vec geodetic2ecef(double phi, double lambda, double h, const arma::vec &ellipsoid); /*! * \brief Reads the ephemeris data from an external XML file * @@ -132,7 +132,7 @@ public: * Front-end TUNER Elonics E4000 + RTL2832 sampler For GPS L1 1575.42 MHz * */ - void GPS_L1_front_end_model_E4000(double f_bb_true_Hz,double f_bb_meas_Hz,double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm ); + void GPS_L1_front_end_model_E4000(double f_bb_true_Hz, double f_bb_meas_Hz, double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm); FrontEndCal(); ~FrontEndCal(); diff --git a/src/utils/front-end-cal/main.cc b/src/utils/front-end-cal/main.cc index 9a445ff2b..b1680d51f 100644 --- a/src/utils/front-end-cal/main.cc +++ b/src/utils/front-end-cal/main.cc @@ -6,7 +6,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -24,7 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -32,62 +32,55 @@ #define FRONT_END_CAL_VERSION "0.0.1" #endif -#include -#include -#include -#include -#include +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "file_configuration.h" +#include "front_end_cal.h" +#include "galileo_almanac.h" +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" +#include "gnss_block_factory.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_supl_client.h" +#include "gnss_signal.h" +#include "gnss_synchro.h" +#include "gps_almanac.h" +#include "gps_cnav_ephemeris.h" +#include "gps_cnav_iono.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" +#include "gps_navigation_message.h" +#include "gps_utc_model.h" +#include "sbas_ephemeris.h" +#include #include #include #include -#include -#include #include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include "concurrent_map.h" -#include "file_configuration.h" -#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" -#include "gnss_signal.h" -#include "gnss_synchro.h" -#include "gnss_block_factory.h" -#include "gps_navigation_message.h" -#include "gps_ephemeris.h" -#include "gps_cnav_ephemeris.h" -#include "gps_almanac.h" -#include "gps_iono.h" -#include "gps_cnav_iono.h" -#include "gps_utc_model.h" -#include "galileo_ephemeris.h" -#include "galileo_almanac.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" -#include "sbas_telemetry_data.h" -#include "sbas_ionospheric_correction.h" -#include "sbas_satellite_correction.h" -#include "sbas_ephemeris.h" -#include "sbas_time.h" -#include "gnss_sdr_supl_client.h" +#include +#include +#include +#include +#include +#include // for ctime +#include +#include +#include +#include +#include -#include "front_end_cal.h" - using google::LogMessage; DECLARE_string(log_dir); -std::string s1_(GNSSSDR_INSTALL_DIR); -std::string s2_("/share/gnss-sdr/conf/front-end-cal.conf"); -std::string s3_ = s1_ + s2_; - -DEFINE_string(config_file, s3_, - "Path to the file containing the configuration parameters"); - concurrent_map global_gps_ephemeris_map; concurrent_map global_gps_iono_map; concurrent_map global_gps_utc_model_map; @@ -96,15 +89,15 @@ concurrent_map global_gps_acq_assist_map; bool stop; concurrent_queue channel_internal_queue; -GpsL1CaPcpsAcquisitionFineDoppler *acquisition; -Gnss_Synchro *gnss_synchro; +GpsL1CaPcpsAcquisitionFineDoppler* acquisition; +Gnss_Synchro* gnss_synchro; std::vector gnss_sync_vector; // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class FrontEndCal_msg_rx; -typedef boost::shared_ptr FrontEndCal_msg_rx_sptr; +using FrontEndCal_msg_rx_sptr = boost::shared_ptr; FrontEndCal_msg_rx_sptr FrontEndCal_msg_rx_make(); @@ -118,7 +111,7 @@ private: public: int rx_message; - ~FrontEndCal_msg_rx(); //!< Default destructor + ~FrontEndCal_msg_rx(); //!< Default destructor }; @@ -131,31 +124,29 @@ FrontEndCal_msg_rx_sptr FrontEndCal_msg_rx_make() void FrontEndCal_msg_rx::msg_handler_events(pmt::pmt_t msg) { try - { - long int message = pmt::to_long(msg); + { + int64_t message = pmt::to_long(std::move(msg)); rx_message = message; channel_internal_queue.push(rx_message); - } - catch(boost::bad_any_cast& e) - { + } + catch (boost::bad_any_cast& e) + { LOG(WARNING) << "msg_handler_telemetry Bad any cast!\n"; rx_message = 0; - } + } } -FrontEndCal_msg_rx::FrontEndCal_msg_rx() : - gr::block("FrontEndCal_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +FrontEndCal_msg_rx::FrontEndCal_msg_rx() : gr::block("FrontEndCal_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); this->set_msg_handler(pmt::mp("events"), boost::bind(&FrontEndCal_msg_rx::msg_handler_events, this, _1)); rx_message = 0; } -FrontEndCal_msg_rx::~FrontEndCal_msg_rx() -{} -// ########################################################### +FrontEndCal_msg_rx::~FrontEndCal_msg_rx() = default; + void wait_message() { @@ -163,73 +154,72 @@ void wait_message() { int message; channel_internal_queue.wait_and_pop(message); - //std::cout<<"Acq mesage rx="< source; try - { + { source = block_factory.GetSignalSource(configuration, queue); - } - catch(const boost::exception_ptr & e) - { + } + catch (const boost::exception_ptr& e) + { std::cout << "Exception caught in creating source " << e << std::endl; - return 0; - } + return false; + } std::shared_ptr conditioner; try - { + { conditioner = block_factory.GetSignalConditioner(configuration); - } - catch(const boost::exception_ptr & e) - { + } + catch (const boost::exception_ptr& e) + { std::cout << "Exception caught in creating signal conditioner " << e << std::endl; - return 0; - } + return false; + } gr::block_sptr sink; sink = gr::blocks::file_sink::make(sizeof(gr_complex), "tmp_capture.dat"); //--- Find number of samples per spreading code --- - long fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - int samples_per_code = round(fs_in_ - / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000); + int samples_per_code = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); int nsamples = samples_per_code * 50; - int skip_samples = fs_in_ * 5; // skip 5 seconds + int skip_samples = fs_in_ * 5; // skip 5 seconds gr::block_sptr head = gr::blocks::head::make(sizeof(gr_complex), nsamples); gr::block_sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), skip_samples); try - { + { source->connect(top_block); conditioner->connect(top_block); top_block->connect(source->get_right_block(), 0, conditioner->get_left_block(), 0); @@ -237,20 +227,19 @@ bool front_end_capture(std::shared_ptr configuration) top_block->connect(skiphead, 0, head, 0); top_block->connect(head, 0, sink, 0); top_block->run(); - } - catch(const std::exception & e) - { + } + catch (const std::exception& e) + { std::cout << "Failure connecting the GNU Radio blocks " << e.what() << std::endl; return false; - } + } - //delete conditioner; - //delete source; return true; } -static time_t utc_time(int week, long tow) { +static time_t utc_time(int week, int64_t tow) +{ time_t t; /* Jan 5/6 midnight 1980 - beginning of GPS time as Unix time */ @@ -269,13 +258,10 @@ static time_t utc_time(int week, long tow) { int main(int argc, char** argv) { const std::string intro_help( - std::string("\n RTL-SDR E4000 RF front-end center frequency and sampling rate calibration tool that uses GPS signals\n") - + - "Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors)\n" - + - "This program comes with ABSOLUTELY NO WARRANTY;\n" - + - "See COPYING file to see a copy of the General Public License\n \n"); + std::string("\n RTL-SDR E4000 RF front-end center frequency and sampling rate calibration tool that uses GPS signals\n") + + "Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)\n" + + "This program comes with ABSOLUTELY NO WARRANTY;\n" + + "See COPYING file to see a copy of the General Public License\n \n"); google::SetUsageMessage(intro_help); google::SetVersionString(FRONT_END_CAL_VERSION); @@ -287,15 +273,14 @@ int main(int argc, char** argv) if (FLAGS_log_dir.empty()) { std::cout << "Logging will be done at " - - << "/tmp" - << std::endl - << "Use front-end-cal --log_dir=/path/to/log to change that." - << std::endl; + << "/tmp" + << std::endl + << "Use front-end-cal --log_dir=/path/to/log to change that." + << std::endl; } else { - const boost::filesystem::path p (FLAGS_log_dir); + const boost::filesystem::path p(FLAGS_log_dir); if (!boost::filesystem::exists(p)) { std::cout << "The path " @@ -308,30 +293,33 @@ int main(int argc, char** argv) << FLAGS_log_dir << std::endl; } - // 0. Instantiate the FrontEnd Calibration class FrontEndCal front_end_cal; // 1. Load configuration parameters from config file - std::shared_ptr configuration = std::make_shared(FLAGS_config_file); - front_end_cal.set_configuration(configuration); - // 2. Get SUPL information from server: Ephemeris record, assistance info and TOW - if (front_end_cal.get_ephemeris() == true) + try { - std::cout << "SUPL data received OK!" << std::endl; + if (front_end_cal.get_ephemeris() == true) + { + std::cout << "SUPL data received OK!" << std::endl; + } + else + { + std::cout << "Failure connecting to SUPL server" << std::endl; + } } - else + catch (const boost::exception& e) { - std::cout << "Failure connecting to SUPL server" < Acquisition_10m) gr::top_block_sptr top_block; @@ -362,70 +354,75 @@ int main(int argc, char** argv) signal.copy(gnss_synchro->Signal, 2, 0); gnss_synchro->PRN = 1; - long fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000); + configuration->set_property("Acquisition.max_dwells", "10"); GNSSBlockFactory block_factory; acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(configuration.get(), "Acquisition", 1, 1); acquisition->set_channel(1); acquisition->set_gnss_synchro(gnss_synchro); - acquisition->set_threshold(configuration->property("Acquisition.threshold", 0.0)); + acquisition->set_threshold(configuration->property("Acquisition.threshold", 2.0)); acquisition->set_doppler_max(configuration->property("Acquisition.doppler_max", 10000)); acquisition->set_doppler_step(configuration->property("Acquisition.doppler_step", 250)); gr::block_sptr source; source = gr::blocks::file_source::make(sizeof(gr_complex), "tmp_capture.dat"); - - boost::shared_ptr msg_rx = FrontEndCal_msg_rx_make(); - - //gr_basic_block_sptr head = gr_make_head(sizeof(gr_complex), nsamples); - //gr_head_sptr head_sptr = boost::dynamic_pointer_cast(head); - //head_sptr->set_length(nsamples); - //head_sptr->reset(); + boost::shared_ptr msg_rx; + try + { + msg_rx = FrontEndCal_msg_rx_make(); + } + catch (const std::exception& e) + { + std::cout << "Failure connecting the message port system: " << e.what() << std::endl; + exit(0); + } try - { + { acquisition->connect(top_block); top_block->connect(source, 0, acquisition->get_left_block(), 0); - top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx,pmt::mp("events")); - } - catch(const std::exception & e) - { + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + } + catch (const std::exception& e) + { std::cout << "Failure connecting the GNU Radio blocks: " << e.what() << std::endl; - } + } // 5. Run the flowgraph // Get visible GPS satellites (positive acquisitions with Doppler measurements) // Compute Doppler estimations //todo: Fix the front-end cal to support new channel internal message system (no more external queues) - std::map doppler_measurements_map; - std::map cn0_measurements_map; + std::map doppler_measurements_map; + std::map cn0_measurements_map; boost::thread ch_thread; // record startup time - struct timeval tv; - gettimeofday(&tv, NULL); - long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds{}; + start = std::chrono::system_clock::now(); bool start_msg = true; - for (unsigned int PRN=1; PRN<33; PRN++) + for (unsigned int PRN = 1; PRN < 33; PRN++) { gnss_synchro->PRN = PRN; acquisition->set_gnss_synchro(gnss_synchro); acquisition->init(); + acquisition->set_local_code(); acquisition->reset(); stop = false; try - { + { ch_thread = boost::thread(wait_message); - } - catch(const boost::thread_resource_error & e) - { + } + catch (const boost::thread_resource_error& e) + { LOG(INFO) << "Exception caught (thread resource error)"; - } + } top_block->run(); if (start_msg == true) { @@ -433,30 +430,37 @@ int main(int argc, char** argv) std::cout << "["; start_msg = false; } - if (gnss_sync_vector.size()>0) + if (!gnss_sync_vector.empty()) { std::cout << " " << PRN << " "; double doppler_measurement_hz = 0; - for (std::vector::iterator it = gnss_sync_vector.begin() ; it != gnss_sync_vector.end(); ++it) + for (auto& it : gnss_sync_vector) { - doppler_measurement_hz += (*it).Acq_doppler_hz; + doppler_measurement_hz += it.Acq_doppler_hz; } - doppler_measurement_hz = doppler_measurement_hz/gnss_sync_vector.size(); - doppler_measurements_map.insert(std::pair(PRN, doppler_measurement_hz)); + doppler_measurement_hz = doppler_measurement_hz / gnss_sync_vector.size(); + doppler_measurements_map.insert(std::pair(PRN, doppler_measurement_hz)); } else { std::cout << " . "; } - channel_internal_queue.push(3); try - { + { + channel_internal_queue.push(3); + } + catch (const boost::exception& e) + { + LOG(INFO) << "Exception caught while pushing to the internal queue."; + } + try + { ch_thread.join(); - } - catch(const boost::thread_resource_error & e) - { + } + catch (const boost::thread_resource_error& e) + { LOG(INFO) << "Exception caught while joining threads."; - } + } gnss_sync_vector.clear(); boost::dynamic_pointer_cast(source)->seek(0, 0); std::cout.flush(); @@ -464,32 +468,43 @@ int main(int argc, char** argv) std::cout << "]" << std::endl; // report the elapsed time - gettimeofday(&tv, NULL); - long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; std::cout << "Total signal acquisition run time " - << ((double)(end - begin))/1000000.0 + << elapsed_seconds.count() << " [seconds]" << std::endl; - //6. find TOW from SUPL assistance - + // 6. find TOW from SUPL assistance double current_TOW = 0; - if (global_gps_ephemeris_map.size() > 0) + try { - std::map Eph_map; - Eph_map = global_gps_ephemeris_map.get_map_copy(); - current_TOW = Eph_map.begin()->second.d_TOW; + if (global_gps_ephemeris_map.size() > 0) + { + std::map Eph_map; + Eph_map = global_gps_ephemeris_map.get_map_copy(); + current_TOW = Eph_map.begin()->second.d_TOW; - time_t t = utc_time(Eph_map.begin()->second.i_GPS_week, (long int)current_TOW); + time_t t = utc_time(Eph_map.begin()->second.i_GPS_week, static_cast(current_TOW)); - fprintf(stdout, "Reference Time:\n"); - fprintf(stdout, " GPS Week: %d\n", Eph_map.begin()->second.i_GPS_week); - fprintf(stdout, " GPS TOW: %ld %lf\n", (long int)current_TOW, (long int)current_TOW*0.08); - fprintf(stdout, " ~ UTC: %s", ctime(&t)); - std::cout << "Current TOW obtained from SUPL assistance = " << current_TOW << std::endl; + std::cout << "Reference Time:" << std::endl; + std::cout << " GPS Week: " << Eph_map.begin()->second.i_GPS_week << std::endl; + std::cout << " GPS TOW: " << static_cast(current_TOW) << " " << static_cast(current_TOW) * 0.08 << std::endl; + std::cout << " ~ UTC: " << ctime(&t) << std::endl; + std::cout << "Current TOW obtained from SUPL assistance = " << current_TOW << std::endl; + } + else + { + std::cout << "Unable to get Ephemeris SUPL assistance. TOW is unknown!" << std::endl; + delete acquisition; + delete gnss_synchro; + google::ShutDownCommandLineFlags(); + std::cout << "GNSS-SDR Front-end calibration program ended." << std::endl; + return 0; + } } - else + catch (const boost::exception& e) { - std::cout << "Unable to get Ephemeris SUPL assistance. TOW is unknown!" << std::endl; + std::cout << "Exception in getting Global ephemeris map" << std::endl; delete acquisition; delete gnss_synchro; google::ShutDownCommandLineFlags(); @@ -497,18 +512,18 @@ int main(int argc, char** argv) return 0; } - //Get user position from config file (or from SUPL using GSM Cell ID) + // Get user position from config file (or from SUPL using GSM Cell ID) double lat_deg = configuration->property("GNSS-SDR.init_latitude_deg", 41.0); double lon_deg = configuration->property("GNSS-SDR.init_longitude_deg", 2.0); double altitude_m = configuration->property("GNSS-SDR.init_altitude_m", 100); std::cout << "Reference location (defined in config file):" << std::endl; - std::cout << "Latitude=" << lat_deg << " [�]" << std::endl; - std::cout << "Longitude=" << lon_deg << " [�]" << std::endl; + std::cout << "Latitude=" << lat_deg << " [º]" << std::endl; + std::cout << "Longitude=" << lon_deg << " [º]" << std::endl; std::cout << "Altitude=" << altitude_m << " [m]" << std::endl; - if (doppler_measurements_map.size() == 0) + if (doppler_measurements_map.empty()) { std::cout << "Sorry, no GPS satellites detected in the front-end capture, please check the antenna setup..." << std::endl; delete acquisition; @@ -518,43 +533,42 @@ int main(int argc, char** argv) return 0; } - std::map f_if_estimation_Hz_map; - std::map f_fs_estimation_Hz_map; - std::map f_ppm_estimation_Hz_map; + std::map f_if_estimation_Hz_map; + std::map f_fs_estimation_Hz_map; + std::map f_ppm_estimation_Hz_map; - std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << - "Doppler analysis results:" << std::endl; + std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << "Doppler analysis results:" << std::endl; std::cout << "SV ID Measured [Hz] Predicted [Hz]" << std::endl; - for (std::map::iterator it = doppler_measurements_map.begin() ; it != doppler_measurements_map.end(); ++it) + for (auto& it : doppler_measurements_map) { try - { + { double doppler_estimated_hz; - doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it->first, current_TOW, lat_deg, lon_deg, altitude_m); - std::cout << " " << it->first << " " << it->second << " " << doppler_estimated_hz << std::endl; + doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it.first, current_TOW, lat_deg, lon_deg, altitude_m); + std::cout << " " << it.first << " " << it.second << " " << doppler_estimated_hz << std::endl; // 7. Compute front-end IF and sampling frequency estimation // Compare with the measurements and compute clock drift using FE model double estimated_fs_Hz, estimated_f_if_Hz, f_osc_err_ppm; - front_end_cal.GPS_L1_front_end_model_E4000(doppler_estimated_hz, it->second,fs_in_, &estimated_fs_Hz, &estimated_f_if_Hz, &f_osc_err_ppm ); + front_end_cal.GPS_L1_front_end_model_E4000(doppler_estimated_hz, it.second, fs_in_, &estimated_fs_Hz, &estimated_f_if_Hz, &f_osc_err_ppm); - f_if_estimation_Hz_map.insert(std::pair(it->first,estimated_f_if_Hz)); - f_fs_estimation_Hz_map.insert(std::pair(it->first,estimated_fs_Hz)); - f_ppm_estimation_Hz_map.insert(std::pair(it->first,f_osc_err_ppm)); - } - catch(const std::logic_error & e) - { + f_if_estimation_Hz_map.insert(std::pair(it.first, estimated_f_if_Hz)); + f_fs_estimation_Hz_map.insert(std::pair(it.first, estimated_fs_Hz)); + f_ppm_estimation_Hz_map.insert(std::pair(it.first, f_osc_err_ppm)); + } + catch (const std::logic_error& e) + { std::cout << "Logic error caught: " << e.what() << std::endl; - } - catch(const boost::lock_error & e) - { + } + catch (const boost::lock_error& e) + { std::cout << "Exception caught while reading ephemeris" << std::endl; - } - catch(int ex) - { - std::cout << " " << it->first << " " << it->second << " (Eph not found)" << std::endl; - } + } + catch (int ex) + { + std::cout << " " << it.first << " " << it.second << " (Eph not found)" << std::endl; + } } // FINAL FE estimations @@ -563,11 +577,11 @@ int main(int argc, char** argv) double mean_osc_err_ppm = 0; int n_elements = f_if_estimation_Hz_map.size(); - for (std::map::iterator it = f_if_estimation_Hz_map.begin() ; it != f_if_estimation_Hz_map.end(); ++it) + for (auto& it : f_if_estimation_Hz_map) { - mean_f_if_Hz += (*it).second; - mean_fs_Hz += f_fs_estimation_Hz_map.find((*it).first)->second; - mean_osc_err_ppm += f_ppm_estimation_Hz_map.find((*it).first)->second; + mean_f_if_Hz += it.second; + mean_fs_Hz += f_fs_estimation_Hz_map.find(it.first)->second; + mean_osc_err_ppm += f_ppm_estimation_Hz_map.find(it.first)->second; } mean_f_if_Hz /= n_elements; @@ -584,31 +598,28 @@ int main(int argc, char** argv) << "Corrected Doppler vs. Predicted" << std::endl; std::cout << "SV ID Corrected [Hz] Predicted [Hz]" << std::endl; - for (std::map::iterator it = doppler_measurements_map.begin() ; it != doppler_measurements_map.end(); ++it) + for (auto& it : doppler_measurements_map) { try - { + { double doppler_estimated_hz; - doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it->first, current_TOW, lat_deg, lon_deg, altitude_m); - std::cout << " " << it->first << " " << it->second - mean_f_if_Hz << " " << doppler_estimated_hz << std::endl; - } - catch(const std::logic_error & e) - { + doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it.first, current_TOW, lat_deg, lon_deg, altitude_m); + std::cout << " " << it.first << " " << it.second - mean_f_if_Hz << " " << doppler_estimated_hz << std::endl; + } + catch (const std::logic_error& e) + { std::cout << "Logic error caught: " << e.what() << std::endl; - } - catch(const boost::lock_error & e) - { + } + catch (const boost::lock_error& e) + { std::cout << "Exception caught while reading ephemeris" << std::endl; - } - catch(int ex) - { - std::cout << " " << it->first << " " << it->second - mean_f_if_Hz << " (Eph not found)" << std::endl; - } + } + catch (int ex) + { + std::cout << " " << it.first << " " << it.second - mean_f_if_Hz << " (Eph not found)" << std::endl; + } } - // 8. Generate GNSS-SDR config file. - - delete acquisition; delete gnss_synchro; diff --git a/src/utils/gnuplot/4_GPS_3_GAL.plt b/src/utils/gnuplot/4_GPS_3_GAL.plt deleted file mode 100644 index 5a59f2aff..000000000 --- a/src/utils/gnuplot/4_GPS_3_GAL.plt +++ /dev/null @@ -1,41 +0,0 @@ -#set terminal pdf color font "Bold,14" -#set output "IFEN_accuracy.pdf" - -set terminal jpeg font "Helvetica, 14" -set output "4_GPS_3_GAL_accuracy_precision.jpeg" - -set grid -set xrange [-10:10] -set yrange [-5:15] -set ylabel "North [m]" -set xlabel "East [m]" - -set key Left left -set title "IFEN simulated data, 4 GPS, 8 Gal - Accuracy and Precision" -#file1="8_GPS_GNSS_SDR_solutions.txt" -#file2="8_GAL_GNSS_SDR_solutions.txt" -file3="4_GPS_3_GAL_GNSS_SDR_solutions.txt" - -#values to copy from statistic file -DRMS= 3.077806456 -DUE_DRMS= 6.155612912 -CEP= 2.565164055 - - -#difference with respect to the reference position -#values to copy from statistic file -delta_E= -1.812 # combined -delta_N= 3.596 # combined - -set parametric -#dummy variable is t for curves, u/v for surfaces -set size square -set angle degree -set trange [0:360] -#radius_6_GPS=6 - -plot file3 u 9:10 with points pointsize 0.3 lc rgb "green" notitle,\ -DRMS*sin(t)+delta_E,DRMS*cos(t)+delta_N lw 3 lc rgb "black" title "DRMS",\ -DUE_DRMS*sin(t)+delta_E,DUE_DRMS*cos(t)+delta_N lw 2 lc rgb "gray" title "2DRMS",\ -CEP*sin(t)+delta_E,CEP*cos(t)+delta_N lw 1 lc rgb "black" title "CEP" - diff --git a/src/utils/gnuplot/4_GPS_3_GAL_GNSS_SDR_solutions.txt b/src/utils/gnuplot/4_GPS_3_GAL_GNSS_SDR_solutions.txt deleted file mode 100644 index 8e4462747..000000000 --- a/src/utils/gnuplot/4_GPS_3_GAL_GNSS_SDR_solutions.txt +++ /dev/null @@ -1,1001 +0,0 @@ - time X [m] Y [m] Z [m] Long [deg] Lat [deg] h [m] E(Acc) [m] N(Acc) [m] Up(Acc) [m] E(Pre) [m] N(Pre) [m] Up(Pre) [m] Tot Sat Gal GPS GDOP -2013-Sep-20 09:11:16 4171693.97233 872117.53398 4730015.03429 11.80796 48.17154 533.09677 -3.02276 4.40094 8.50611 -1.20980 0.80488 -0.48942 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.33830 872116.34933 4730014.33700 11.80795 48.17154 532.00164 -4.05260 4.57900 7.41098 -2.23964 0.98294 -1.58455 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.05315 872118.15688 4730014.15668 11.80798 48.17154 531.92781 -2.22494 4.39110 7.33715 -0.41198 0.79504 -1.65838 7 3 4 2.38 -2013-Sep-20 09:11:16 4171692.12670 872118.20356 4730011.97295 11.80798 48.17153 529.70220 -1.98967 3.60338 5.11154 -0.17671 0.00732 -3.88399 7 3 4 2.38 -2013-Sep-20 09:11:16 4171696.84323 872121.85875 4730020.07446 11.80801 48.17154 539.31673 0.62302 5.00884 14.72607 2.43598 1.41277 5.73054 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.35432 872119.69457 4730016.43049 11.80800 48.17155 534.02857 -0.78142 5.45339 9.43792 1.03154 1.85733 0.44238 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.12694 872119.79577 4730015.98216 11.80800 48.17155 533.55988 -0.63583 5.30481 8.96922 1.17713 1.70875 -0.02631 7 3 4 2.38 -2013-Sep-20 09:11:16 4171696.96879 872121.82141 4730019.17596 11.80801 48.17154 538.72409 0.56077 4.32373 14.13343 2.37373 0.72767 5.13790 7 3 4 2.38 -2013-Sep-20 09:11:16 4171694.15949 872120.93965 4730016.49439 11.80801 48.17154 534.77171 0.27255 4.71888 10.18105 2.08550 1.12282 1.18552 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.75614 872120.79377 4730017.69730 11.80801 48.17155 535.38484 0.21229 5.83754 10.79418 2.02525 2.24148 1.79865 7 3 4 2.38 -2013-Sep-20 09:11:16 4171695.61533 872122.42037 4730020.91833 11.80802 48.17156 539.22062 1.42402 6.38158 14.62996 3.23698 2.78552 5.63443 7 3 4 2.38 -2013-Sep-20 09:11:16 4171694.88778 872121.15270 4730019.60309 11.80801 48.17155 537.59264 0.33206 6.22839 13.00198 2.14502 2.63233 4.00645 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.43914 872118.88386 4730017.86310 11.80798 48.17156 535.04081 -1.59233 6.47055 10.45015 0.22063 2.87448 1.45462 7 3 4 2.38 -2013-Sep-20 09:11:16 4171692.22580 872118.12648 4730014.50631 11.80798 48.17154 531.64410 -2.08540 5.23236 7.05344 -0.27244 1.63630 -1.94209 7 3 4 2.38 -2013-Sep-20 09:11:16 4171694.15704 872116.07742 4730015.59062 11.80795 48.17154 533.43313 -4.48630 4.85933 8.84247 -2.67334 1.26327 -0.15306 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.05163 872116.15088 4730014.39550 11.80795 48.17154 531.83101 -4.18818 4.85737 7.24035 -2.37522 1.26131 -1.75518 7 3 4 2.38 -2013-Sep-20 09:11:16 4171691.44820 872115.16638 4730012.34165 11.80794 48.17154 529.11954 -4.82374 4.80727 4.52888 -3.01078 1.21121 -4.46665 7 3 4 2.38 -2013-Sep-20 09:11:16 4171685.37039 872113.72974 4730008.72245 11.80794 48.17156 522.25911 -4.98626 7.04568 -2.33155 -3.17330 3.44962 -11.32708 7 3 4 2.38 -2013-Sep-20 09:11:16 4171690.06034 872116.43183 4730013.82510 11.80796 48.17156 529.49163 -3.30106 6.61590 4.90098 -1.48811 3.01984 -4.09455 7 3 4 2.38 -2013-Sep-20 09:11:16 4171691.23714 872116.64891 4730014.88922 11.80796 48.17156 531.08239 -3.32939 6.43413 6.49173 -1.51643 2.83807 -2.50380 7 3 4 2.38 -2013-Sep-20 09:11:16 4171693.21171 872117.89698 4730015.57287 11.80797 48.17154 533.05111 -2.51180 5.25955 8.46046 -0.69884 1.66349 -0.53507 7 3 4 2.38 -2013-Sep-20 09:11:16 4171690.94846 872116.12466 4730012.76005 11.80795 48.17155 529.23586 -3.78347 5.30468 4.64520 -1.97051 1.70861 -4.35033 7 3 4 2.38 -2013-Sep-20 09:11:16 4171691.01303 872116.67548 4730012.29188 11.80796 48.17154 529.00432 -3.25752 4.86136 4.41366 -1.44456 1.26530 -4.58187 7 3 4 2.38 -2013-Sep-20 09:11:17 4171686.92529 872115.59058 4730009.79479 11.80796 48.17155 524.32713 -3.48298 6.34298 -0.26352 -1.67003 2.74693 -9.25905 7 3 4 2.38 -2013-Sep-20 09:11:17 4171689.09965 872117.40230 4730013.21592 11.80798 48.17156 528.54302 -2.15454 6.76235 3.95236 -0.34158 3.16630 -5.04317 7 3 4 2.38 -2013-Sep-20 09:11:17 4171693.82864 872118.34509 4730017.17592 11.80798 48.17155 534.70949 -2.19941 5.81033 10.11883 -0.38645 2.21427 1.12330 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.85980 872118.16204 4730017.17833 11.80798 48.17156 533.40107 -1.97569 7.27587 8.81041 -0.16274 3.67981 -0.18512 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.77791 872117.74707 4730016.15426 11.80797 48.17156 532.52790 -2.36513 6.71592 7.93724 -0.55217 3.11986 -1.05829 7 3 4 2.38 -2013-Sep-20 09:11:17 4171690.71021 872117.27718 4730014.77869 11.80797 48.17156 530.74179 -2.60659 6.64895 6.15114 -0.79363 3.05288 -2.84440 7 3 4 2.38 -2013-Sep-20 09:11:17 4171689.81704 872118.53772 4730015.06359 11.80799 48.17156 530.54306 -1.18995 7.29820 5.95240 0.62301 3.70214 -3.04313 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.55376 872116.79531 4730016.19778 11.80796 48.17156 532.28412 -3.25088 7.05356 7.69347 -1.43793 3.45749 -1.30207 7 3 4 2.38 -2013-Sep-20 09:11:17 4171693.82776 872118.45535 4730018.91249 11.80798 48.17156 536.01796 -2.09131 6.95229 11.42730 -0.27835 3.35622 2.43177 7 3 4 2.38 -2013-Sep-20 09:11:17 4171694.19655 872118.91481 4730019.87640 11.80798 48.17156 537.03965 -1.71703 7.25607 12.44900 0.09593 3.66001 3.45347 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.86539 872117.99083 4730016.02995 11.80798 48.17156 532.52565 -2.14443 6.53204 7.93499 -0.33147 2.93598 -1.06054 7 3 4 2.38 -2013-Sep-20 09:11:17 4171693.15533 872117.98759 4730017.59780 11.80797 48.17156 534.53554 -2.41156 6.63729 9.94488 -0.59860 3.04122 0.94935 7 3 4 2.38 -2013-Sep-20 09:11:17 4171692.18121 872115.90348 4730016.83466 11.80795 48.17156 533.04657 -4.25223 7.15664 8.45591 -2.43927 3.56057 -0.53962 7 3 4 2.38 -2013-Sep-20 09:11:17 4171688.42657 872114.52355 4730012.03638 11.80794 48.17156 526.83185 -4.83464 6.90560 2.24119 -3.02169 3.30954 -6.75434 7 3 4 2.38 -2013-Sep-20 09:11:17 4171686.83368 872114.31800 4730010.30785 11.80794 48.17156 524.47597 -4.70988 6.94600 -0.11468 -2.89693 3.34994 -9.11022 7 3 4 2.38 -2013-Sep-20 09:11:17 4171689.01630 872114.65818 4730011.81674 11.80794 48.17155 527.07153 -4.82353 6.30846 2.48087 -3.01057 2.71240 -6.51466 7 3 4 2.38 -2013-Sep-20 09:11:17 4171689.59940 872113.40135 4730012.50944 11.80792 48.17156 527.79681 -6.17309 6.53677 3.20615 -4.36014 2.94071 -5.78938 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.49667 872115.40807 4730015.71094 11.80794 48.17156 531.69477 -4.59708 6.98205 7.10411 -2.78412 3.38598 -1.89142 7 3 4 2.38 -2013-Sep-20 09:11:17 4171690.13679 872116.03487 4730014.42512 11.80796 48.17156 529.93447 -3.70527 7.02083 5.34381 -1.89231 3.42477 -3.65172 7 3 4 2.38 -2013-Sep-20 09:11:17 4171688.48177 872115.80343 4730011.69753 11.80796 48.17156 526.79005 -3.59313 6.44420 2.19940 -1.78018 2.84814 -6.79613 7 3 4 2.38 -2013-Sep-20 09:11:17 4171691.34954 872115.59222 4730014.29031 11.80795 48.17155 530.56528 -4.38672 6.11386 5.97463 -2.57377 2.51780 -3.02091 7 3 4 2.38 -2013-Sep-20 09:11:17 4171692.31645 872117.07132 4730015.85773 11.80796 48.17155 532.56628 -3.13678 6.22840 7.97562 -1.32382 2.63234 -1.01991 7 3 4 2.38 -2013-Sep-20 09:11:17 4171693.22291 872119.00896 4730017.72048 11.80799 48.17156 534.81045 -1.42563 6.51407 10.21980 0.38733 2.91801 1.22427 7 3 4 2.38 -2013-Sep-20 09:11:17 4171692.72321 872118.13057 4730016.70730 11.80798 48.17155 533.60942 -2.18318 6.33679 9.01876 -0.37022 2.74073 0.02323 7 3 4 2.38 -2013-Sep-20 09:11:17 4171693.24503 872117.69714 4730017.55960 11.80797 48.17156 534.52598 -2.71422 6.59068 9.93533 -0.90126 2.99461 0.93980 7 3 4 2.38 -2013-Sep-20 09:11:18 4171691.08816 872116.06995 4730015.06700 11.80795 48.17156 531.03859 -3.86561 6.74964 6.44794 -2.05265 3.15358 -2.54760 7 3 4 2.38 -2013-Sep-20 09:11:18 4171690.44418 872115.43965 4730013.68149 11.80795 48.17156 529.49979 -4.35079 6.39145 4.90913 -2.53783 2.79539 -4.08640 7 3 4 2.38 -2013-Sep-20 09:11:18 4171698.43425 872119.48630 4730014.15842 11.80798 48.17150 535.62326 -2.02481 0.26471 11.03261 -0.21185 -3.33135 2.03707 7 3 4 2.38 -2013-Sep-20 09:11:18 4171699.68595 872120.78596 4730016.26269 11.80799 48.17150 538.18571 -1.00878 0.55692 13.59506 0.80418 -3.03914 4.59952 7 3 4 2.38 -2013-Sep-20 09:11:18 4171697.25383 872120.30384 4730014.30052 11.80799 48.17151 535.07014 -0.98301 1.09579 10.47949 0.82995 -2.50027 1.48396 7 3 4 2.38 -2013-Sep-20 09:11:18 4171693.89224 872119.29061 4730011.05323 11.80799 48.17151 530.31775 -1.28691 1.53652 5.72710 0.52605 -2.05954 -3.26844 7 3 4 2.38 -2013-Sep-20 09:11:18 4171693.99654 872119.23313 4730012.34424 11.80799 48.17152 531.33999 -1.36451 2.33020 6.74933 0.44845 -1.26586 -2.24620 7 3 4 2.38 -2013-Sep-20 09:11:18 4171695.13076 872120.86904 4730013.19185 11.80801 48.17151 532.93524 0.00468 1.81875 8.34458 1.81764 -1.77731 -0.65095 7 3 4 2.38 -2013-Sep-20 09:11:18 4171694.40997 872119.59890 4730012.76392 11.80799 48.17152 531.97250 -1.09109 2.25276 7.38185 0.72187 -1.34330 -1.61369 7 3 4 2.38 -2013-Sep-20 09:11:18 4171691.49595 872119.36997 4730010.96923 11.80800 48.17153 528.70172 -0.71887 3.21620 4.11107 1.09409 -0.37986 -4.88447 7 3 4 2.38 -2013-Sep-20 09:11:18 4171694.91929 872120.89919 4730015.36048 11.80801 48.17153 534.41725 0.07747 3.41466 9.82660 1.89042 -0.18140 0.83106 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.49958 872120.85127 4730016.56994 11.80800 48.17153 536.34353 -0.29282 3.07593 11.75288 1.52014 -0.52013 2.75734 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.90910 872121.40991 4730017.29374 11.80801 48.17153 537.22644 0.17019 3.17476 12.63578 1.98315 -0.42131 3.64025 7 3 4 2.38 -2013-Sep-20 09:11:18 4171697.26759 872120.99996 4730017.00067 11.80800 48.17152 537.18613 -0.30445 2.78034 12.59547 1.50851 -0.81572 3.59994 7 3 4 2.38 -2013-Sep-20 09:11:18 4171698.17413 872122.27525 4730017.12289 11.80802 48.17152 538.04303 0.75835 2.00619 13.45237 2.57131 -1.58987 4.45684 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.15179 872121.89065 4730015.37314 11.80802 48.17152 535.36656 0.79573 2.37297 10.77590 2.60869 -1.22309 1.78037 7 3 4 2.38 -2013-Sep-20 09:11:18 4171695.18910 872122.07684 4730014.71611 11.80802 48.17152 534.27394 1.17498 2.60857 9.68329 2.98794 -0.98750 0.68775 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.78909 872120.50855 4730013.65031 11.80800 48.17151 534.31021 -0.68753 0.96992 9.71955 1.12543 -2.62614 0.72402 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.91691 872120.01392 4730013.44362 11.80799 48.17151 534.17213 -1.19785 0.81427 9.58148 0.61511 -2.78179 0.58594 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.73519 872120.20544 4730013.29070 11.80799 48.17151 533.96569 -0.97320 0.81562 9.37504 0.83976 -2.78044 0.37950 7 3 4 2.38 -2013-Sep-20 09:11:18 4171695.42505 872121.01961 4730012.32164 11.80801 48.17151 532.49947 0.09184 1.00080 7.90881 1.90480 -2.59526 -1.08672 7 3 4 2.38 -2013-Sep-20 09:11:18 4171695.87389 872120.48848 4730014.33209 11.80800 48.17152 534.21805 -0.51990 2.09519 9.62740 1.29306 -1.50088 0.63186 7 3 4 2.38 -2013-Sep-20 09:11:18 4171695.90048 872119.75316 4730013.94614 11.80799 48.17152 533.84748 -1.24511 1.93053 9.25682 0.56785 -1.66553 0.26129 7 3 4 2.38 -2013-Sep-20 09:11:18 4171696.74939 872120.68241 4730014.13398 11.80800 48.17151 534.66842 -0.50923 1.29492 10.07776 1.30373 -2.30114 1.08223 7 3 4 2.38 -2013-Sep-20 09:11:18 4171690.28984 872120.16318 4730010.86429 11.80801 48.17153 527.94444 0.30436 3.90497 3.35378 2.11732 0.30891 -5.64175 7 3 4 2.38 -2013-Sep-20 09:11:19 4171689.17640 872120.49096 4730009.94144 11.80802 48.17153 526.57467 0.85305 4.05166 1.98401 2.66601 0.45560 -7.01152 7 3 4 2.38 -2013-Sep-20 09:11:19 4171695.08288 872120.24787 4730014.08012 11.80800 48.17152 533.48111 -0.59355 2.54078 8.89045 1.21941 -1.05528 -0.10508 7 3 4 2.38 -2013-Sep-20 09:11:19 4171697.78397 872121.75338 4730016.49995 11.80801 48.17152 537.25293 0.32736 1.95490 12.66228 2.14032 -1.64116 3.66674 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.86836 872122.35693 4730016.35705 11.80802 48.17152 536.63112 1.10551 2.43539 12.04046 2.91847 -1.16067 3.04493 7 3 4 2.38 -2013-Sep-20 09:11:19 4171697.83682 872122.88929 4730018.34490 11.80802 48.17152 538.81720 1.42842 2.97356 14.22655 3.24138 -0.62251 5.23101 7 3 4 2.38 -2013-Sep-20 09:11:19 4171694.71701 872121.43601 4730015.63471 11.80801 48.17153 534.56280 0.64432 3.66323 9.97215 2.45728 0.06717 0.97662 7 3 4 2.38 -2013-Sep-20 09:11:19 4171691.80256 872117.66279 4730011.39013 11.80797 48.17153 528.98252 -2.45267 3.53357 4.39187 -0.63971 -0.06249 -4.60366 7 3 4 2.38 -2013-Sep-20 09:11:19 4171690.41152 872117.25164 4730010.27956 11.80797 48.17153 527.19082 -2.57046 3.87022 2.60016 -0.75750 0.27416 -6.39537 7 3 4 2.38 -2013-Sep-20 09:11:19 4171692.07568 872117.33262 4730011.41932 11.80797 48.17153 529.13751 -2.83174 3.40418 4.54685 -1.01878 -0.19188 -4.44868 7 3 4 2.38 -2013-Sep-20 09:11:19 4171691.61815 872117.65543 4730010.80166 11.80797 48.17153 528.42265 -2.42214 3.27675 3.83199 -0.60918 -0.31931 -5.16354 7 3 4 2.38 -2013-Sep-20 09:11:19 4171695.46147 872118.75829 4730013.87402 11.80798 48.17152 533.37139 -2.12908 2.35433 8.78073 -0.31612 -1.24173 -0.21480 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.08218 872120.66208 4730014.38537 11.80800 48.17152 534.41743 -0.39260 1.95233 9.82677 1.42036 -1.64374 0.83124 7 3 4 2.38 -2013-Sep-20 09:11:19 4171691.21510 872119.56773 4730011.98245 11.80800 48.17153 529.30036 -0.46783 4.06661 4.70971 1.34513 0.47055 -4.28582 7 3 4 2.38 -2013-Sep-20 09:11:19 4171693.34029 872120.71321 4730015.51992 11.80801 48.17154 533.47992 0.21853 4.70103 8.88926 2.03149 1.10497 -0.10627 7 3 4 2.38 -2013-Sep-20 09:11:19 4171695.08296 872120.74421 4730017.59124 11.80800 48.17154 536.16518 -0.10773 4.80661 11.57453 1.70523 1.21055 2.57900 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.95736 872120.77579 4730018.50428 11.80800 48.17153 538.07343 -0.46038 4.04356 13.48277 1.35258 0.44750 4.48724 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.21489 872120.63733 4730016.75060 11.80800 48.17153 536.26311 -0.44398 3.43668 11.67245 1.36898 -0.15938 2.67692 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.08334 872121.02813 4730015.74784 11.80801 48.17152 535.48337 -0.03454 2.80430 10.89271 1.77843 -0.79177 1.89718 7 3 4 2.38 -2013-Sep-20 09:11:19 4171699.46538 872122.79974 4730018.14445 11.80802 48.17151 539.71873 1.00751 1.66569 15.12807 2.82047 -1.93037 6.13254 7 3 4 2.38 -2013-Sep-20 09:11:19 4171697.17088 872121.27785 4730016.31399 11.80801 48.17152 536.64924 -0.01264 2.35056 12.05859 1.80032 -1.24550 3.06306 7 3 4 2.38 -2013-Sep-20 09:11:19 4171695.44672 872120.32287 4730016.13813 11.80800 48.17153 535.26237 -0.59460 3.63646 10.67171 1.21836 0.04040 1.67618 7 3 4 2.38 -2013-Sep-20 09:11:19 4171693.00983 872119.13721 4730014.84526 11.80799 48.17154 532.54640 -1.25649 4.73244 7.95575 0.55647 1.13638 -1.03979 7 3 4 2.38 -2013-Sep-20 09:11:19 4171692.70593 872118.50845 4730013.09221 11.80798 48.17153 530.95594 -1.80977 3.88085 6.36528 0.00319 0.28479 -2.63025 7 3 4 2.38 -2013-Sep-20 09:11:19 4171695.84252 872119.33060 4730015.73359 11.80798 48.17153 535.08389 -1.64686 3.22929 10.49323 0.16610 -0.36678 1.49770 7 3 4 2.38 -2013-Sep-20 09:11:19 4171696.51959 872119.93155 4730015.12635 11.80799 48.17152 535.15540 -1.19717 2.23884 10.56474 0.61579 -1.35723 1.56921 7 3 4 2.38 -2013-Sep-20 09:11:20 4171692.85378 872119.16464 4730012.29481 11.80799 48.17153 530.54783 -1.19771 3.14118 5.95717 0.61525 -0.45488 -3.03836 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.07850 872117.72466 4730010.22010 11.80798 48.17153 526.99367 -2.03931 4.00134 2.40302 -0.22635 0.40528 -6.59252 7 3 4 2.38 -2013-Sep-20 09:11:20 4171692.98867 872118.92389 4730013.65917 11.80799 48.17153 531.61967 -1.46097 3.98939 7.02901 0.35199 0.39333 -1.96652 7 3 4 2.38 -2013-Sep-20 09:11:20 4171694.02280 872118.47920 4730015.30830 11.80798 48.17154 533.46290 -2.10787 4.40274 8.87224 -0.29491 0.80667 -0.12329 7 3 4 2.38 -2013-Sep-20 09:11:20 4171694.02652 872119.35278 4730016.01707 11.80799 48.17154 534.11268 -1.25353 4.73951 9.52202 0.55943 1.14345 0.52649 7 3 4 2.38 -2013-Sep-20 09:11:20 4171693.98481 872119.32145 4730016.08920 11.80799 48.17154 534.13492 -1.27567 4.82281 9.54427 0.53729 1.22674 0.54873 7 3 4 2.38 -2013-Sep-20 09:11:20 4171694.41452 872119.07699 4730014.83638 11.80798 48.17153 533.44854 -1.60288 3.71115 8.85788 0.21008 0.11509 -0.13765 7 3 4 2.38 -2013-Sep-20 09:11:20 4171695.54442 872118.07932 4730016.21266 11.80797 48.17153 535.07550 -2.81066 3.95700 10.48485 -0.99770 0.36093 1.48931 7 3 4 2.38 -2013-Sep-20 09:11:20 4171692.77379 872115.55724 4730014.29761 11.80794 48.17154 531.49568 -4.71240 5.08525 6.90502 -2.89945 1.48919 -2.09051 7 3 4 2.38 -2013-Sep-20 09:11:20 4171691.63001 872116.29920 4730015.24560 11.80796 48.17156 531.55668 -3.75209 6.43858 6.96602 -1.93914 2.84252 -2.02951 7 3 4 2.38 -2013-Sep-20 09:11:20 4171692.43177 872117.84749 4730015.60467 11.80797 48.17155 532.55892 -2.40063 5.85717 7.96826 -0.58767 2.26111 -1.02727 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.93293 872117.88614 4730015.00514 11.80798 48.17156 531.13903 -2.05609 6.54467 6.54837 -0.24314 2.94861 -2.44716 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.12255 872117.31940 4730013.31246 11.80797 48.17155 529.27138 -2.44500 6.09331 4.68072 -0.63204 2.49725 -4.31481 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.57084 872117.32037 4730013.29541 11.80797 48.17155 529.55145 -2.53579 5.75482 4.96079 -0.72283 2.15876 -4.03474 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.32708 872117.65406 4730012.80684 11.80798 48.17155 529.07380 -2.15928 5.55590 4.48315 -0.34632 1.95984 -4.51239 7 3 4 2.38 -2013-Sep-20 09:11:20 4171690.74432 872118.59802 4730013.31712 11.80799 48.17155 529.85524 -1.32068 5.44794 5.26458 0.49228 1.85188 -3.73095 7 3 4 2.38 -2013-Sep-20 09:11:20 4171695.46123 872119.99967 4730019.08700 11.80799 48.17155 537.42506 -0.91393 5.64177 12.83440 0.89903 2.04570 3.83887 7 3 4 2.38 -2013-Sep-20 09:11:20 4171697.78958 872121.40278 4730020.58578 11.80801 48.17154 540.25328 -0.01696 4.72912 15.66262 1.79600 1.13305 6.66709 7 3 4 2.38 -2013-Sep-20 09:11:20 4171697.65886 872120.73541 4730021.23065 11.80800 48.17155 540.55739 -0.64346 5.35629 15.96673 1.16950 1.76022 6.97120 7 3 4 2.38 -2013-Sep-20 09:11:20 4171694.20680 872119.75356 4730016.29950 11.80799 48.17154 534.49551 -0.89813 4.73525 9.90485 0.91483 1.13919 0.90932 7 3 4 2.38 -2013-Sep-20 09:11:20 4171693.00595 872120.15279 4730016.85468 11.80800 48.17155 534.17978 -0.26161 5.92050 9.58912 1.55135 2.32444 0.59359 7 3 4 2.38 -2013-Sep-20 09:11:20 4171695.73142 872121.45594 4730019.20489 11.80801 48.17155 537.88803 0.45624 5.30127 13.29737 2.26920 1.70521 4.30184 7 3 4 2.38 -2013-Sep-20 09:11:20 4171693.12915 872119.60495 4730015.58147 11.80799 48.17154 533.23671 -0.82307 5.06507 8.64605 0.98989 1.46901 -0.34948 7 3 4 2.38 -2013-Sep-20 09:11:20 4171688.46031 872118.71115 4730011.75505 11.80800 48.17155 527.21572 -0.74256 6.05485 2.62506 1.07040 2.45879 -6.37047 7 3 4 2.38 -2013-Sep-20 09:11:20 4171691.32987 872118.55563 4730014.88759 11.80799 48.17155 531.40192 -1.48199 6.07467 6.81126 0.33097 2.47861 -2.18427 7 3 4 2.38 -2013-Sep-20 09:11:21 4171689.56331 872118.20704 4730013.19481 11.80799 48.17155 528.93978 -1.46171 6.28739 4.34912 0.35125 2.69133 -4.64641 7 3 4 2.38 -2013-Sep-20 09:11:21 4171685.92672 872117.71725 4730010.60163 11.80799 48.17156 524.56671 -1.19697 7.28512 -0.02395 0.61598 3.68906 -9.01948 7 3 4 2.38 -2013-Sep-20 09:11:21 4171689.55584 872117.74212 4730015.45929 11.80798 48.17157 530.55883 -1.91527 7.87392 5.96817 -0.10231 4.27786 -3.02736 7 3 4 2.38 -2013-Sep-20 09:11:21 4171691.81410 872118.12623 4730017.71418 11.80798 48.17157 533.76564 -2.00139 7.67202 9.17498 -0.18843 4.07596 0.17945 7 3 4 2.38 -2013-Sep-20 09:11:21 4171689.64397 872116.59344 4730014.84388 11.80796 48.17157 530.00103 -3.05767 7.57438 5.41037 -1.24471 3.97832 -3.58516 7 3 4 2.38 -2013-Sep-20 09:11:21 4171691.95807 872115.89947 4730014.75436 11.80795 48.17155 531.35024 -4.21050 5.93264 6.75958 -2.39754 2.33658 -2.23595 7 3 4 2.38 -2013-Sep-20 09:11:21 4171694.41446 872116.84871 4730015.87431 11.80795 48.17154 533.91781 -3.78400 4.74316 9.32715 -1.97104 1.14710 0.33162 7 3 4 2.38 -2013-Sep-20 09:11:21 4171692.43479 872115.10007 4730014.47253 11.80794 48.17155 531.34234 -5.09053 5.51887 6.75168 -3.27757 1.92281 -2.24385 7 3 4 2.38 -2013-Sep-20 09:11:21 4171689.58404 872113.24592 4730011.76733 11.80792 48.17155 527.21260 -6.32209 6.07676 2.62194 -4.50913 2.48070 -6.37360 7 3 4 2.38 -2013-Sep-20 09:11:21 4171687.85016 872113.63447 4730009.92018 11.80793 48.17155 524.75737 -5.58695 6.05030 0.16671 -3.77399 2.45424 -8.82882 7 3 4 2.38 -2013-Sep-20 09:11:21 4171691.22319 872115.50950 4730013.20333 11.80795 48.17155 529.66156 -4.44183 5.49372 5.07090 -2.62888 1.89766 -3.92463 7 3 4 2.38 -2013-Sep-20 09:11:21 4171693.69204 872115.61457 4730015.27022 11.80794 48.17154 532.82767 -4.84420 5.05539 8.23701 -3.03124 1.45933 -0.75852 7 3 4 2.38 -2013-Sep-20 09:11:21 4171693.07652 872115.21531 4730014.89055 11.80794 48.17155 532.08847 -5.10905 5.31202 7.49781 -3.29610 1.71595 -1.49772 7 3 4 2.38 -2013-Sep-20 09:11:21 4171695.51663 872117.05085 4730017.93873 11.80795 48.17155 536.20318 -3.81168 5.28522 11.61252 -1.99872 1.68915 2.61699 7 3 4 2.38 -2013-Sep-20 09:11:21 4171696.10233 872118.79374 4730020.28856 11.80798 48.17155 538.57433 -2.22552 6.15937 13.98367 -0.41256 2.56330 4.98814 7 3 4 2.38 -2013-Sep-20 09:11:21 4171693.70936 872116.51201 4730016.36786 11.80795 48.17155 533.77935 -3.96929 5.63794 9.18869 -2.15633 2.04187 0.19316 7 3 4 2.38 -2013-Sep-20 09:11:21 4171695.52706 872116.89264 4730019.52815 11.80795 48.17155 537.37275 -3.96867 6.36172 12.78209 -2.15571 2.76566 3.78656 7 3 4 2.38 -2013-Sep-20 09:11:21 4171694.44896 872118.09480 4730017.13388 11.80797 48.17155 535.04895 -2.57134 5.36801 10.45830 -0.75838 1.77195 1.46276 7 3 4 2.38 -2013-Sep-20 09:11:21 4171691.96117 872116.26242 4730014.94807 11.80795 48.17155 531.54614 -3.85586 6.00422 6.95548 -2.04291 2.40816 -2.04005 7 3 4 2.38 -2013-Sep-20 09:11:21 4171692.04492 872115.02243 4730015.45873 11.80794 48.17156 531.81210 -5.08675 6.47277 7.22144 -3.27379 2.87671 -1.77409 7 3 4 2.38 -2013-Sep-20 09:11:21 4171690.01681 872114.32817 4730014.17249 11.80793 48.17156 529.43499 -5.35130 7.20009 4.84433 -3.53835 3.60403 -4.15120 7 3 4 2.38 -2013-Sep-20 09:11:21 4171690.92253 872114.53345 4730015.36082 11.80793 48.17156 530.93973 -5.33570 7.30068 6.34907 -3.52275 3.70462 -2.64646 7 3 4 2.38 -2013-Sep-20 09:11:21 4171688.97339 872114.44988 4730013.49620 11.80794 48.17157 528.26653 -5.01865 7.49156 3.67587 -3.20569 3.89550 -5.31966 7 3 4 2.38 -2013-Sep-20 09:11:21 4171690.74024 872115.51489 4730015.40365 11.80795 48.17156 530.98658 -4.33773 7.31256 6.39592 -2.52477 3.71649 -2.59961 7 3 4 2.38 -2013-Sep-20 09:11:21 4171688.97210 872115.14013 4730013.87611 11.80795 48.17157 528.64297 -4.34274 7.64062 4.05231 -2.52978 4.04456 -4.94322 7 3 4 2.38 -2013-Sep-20 09:11:22 4171688.32594 872114.70694 4730017.04771 11.80794 48.17159 530.52536 -4.63454 10.29311 5.93469 -2.82158 6.69705 -3.06084 7 3 4 2.38 -2013-Sep-20 09:11:22 4171686.97520 872114.42977 4730012.67178 11.80794 48.17157 526.34508 -4.62944 8.40225 1.75442 -2.81648 4.80619 -7.24111 7 3 4 2.38 -2013-Sep-20 09:11:22 4171693.30293 872116.44529 4730018.38098 11.80795 48.17156 535.00500 -3.95143 7.28711 10.41434 -2.13847 3.69105 1.41881 7 3 4 2.38 -2013-Sep-20 09:11:22 4171692.15763 872116.48477 4730017.47188 11.80796 48.17157 533.58533 -3.67842 7.51016 8.99467 -1.86546 3.91410 -0.00086 7 3 4 2.38 -2013-Sep-20 09:11:22 4171689.71754 872114.78005 4730014.66291 11.80794 48.17157 529.66673 -4.84774 7.67653 5.07607 -3.03478 4.08047 -3.91946 7 3 4 2.38 -2013-Sep-20 09:11:22 4171688.12062 872115.53051 4730014.92965 11.80795 48.17158 528.92545 -3.78638 8.90475 4.33479 -1.97343 5.30869 -4.66074 7 3 4 2.38 -2013-Sep-20 09:11:22 4171692.01243 872116.52714 4730016.72361 11.80796 48.17156 532.93876 -3.60724 7.11059 8.34810 -1.79428 3.51452 -0.64743 7 3 4 2.38 -2013-Sep-20 09:11:22 4171688.32605 872114.48080 4730011.21123 11.80794 48.17156 526.14554 -4.85592 6.43514 1.55488 -3.04296 2.83908 -7.44065 7 3 4 2.38 -2013-Sep-20 09:11:22 4171693.82006 872115.87957 4730015.88761 11.80794 48.17155 533.40745 -4.61100 5.33335 8.81679 -2.79804 1.73729 -0.17874 7 3 4 2.38 -2013-Sep-20 09:11:22 4171693.99055 872115.07751 4730018.31302 11.80793 48.17156 535.21657 -5.43097 6.94882 10.62591 -3.61801 3.35275 1.63038 7 3 4 2.38 -2013-Sep-20 09:11:22 4171690.26858 872114.65413 4730016.10207 11.80794 48.17157 531.08165 -5.08376 8.25360 6.49099 -3.27080 4.65754 -2.50454 7 3 4 2.38 -2013-Sep-20 09:11:22 4171692.16940 872116.63112 4730016.93195 11.80796 48.17156 533.21066 -3.53757 7.11918 8.62000 -1.72461 3.52312 -0.37553 7 3 4 2.38 -2013-Sep-20 09:11:22 4171691.79160 872116.37251 4730016.01418 11.80796 48.17156 532.24487 -3.71340 6.82211 7.65421 -1.90044 3.22605 -1.34132 7 3 4 2.38 -2013-Sep-20 09:11:22 4171689.71748 872115.07017 4730014.27800 11.80794 48.17156 529.41947 -4.56375 7.37564 4.82881 -2.75079 3.77958 -4.16672 7 3 4 2.38 -2013-Sep-20 09:11:22 4171691.78194 872116.39084 4730017.56959 11.80796 48.17157 533.40007 -3.69348 7.86367 8.80941 -1.88053 4.26761 -0.18612 7 3 4 2.38 -2013-Sep-20 09:11:22 4171691.89938 872114.84708 4730015.13309 11.80794 48.17156 531.45052 -5.22861 6.38850 6.85986 -3.41565 2.79244 -2.13567 7 3 4 2.38 -2013-Sep-20 09:11:22 4171689.87221 872113.72188 4730013.12886 11.80793 48.17156 528.48020 -5.91517 6.70201 3.88954 -4.10221 3.10595 -5.10599 7 3 4 2.38 -2013-Sep-20 09:11:22 4171689.10012 872113.31458 4730014.50949 11.80792 48.17157 528.94937 -6.15586 8.24800 4.35871 -4.34290 4.65194 -4.63682 7 3 4 2.38 -2013-Sep-20 09:11:22 4171687.89357 872112.65870 4730013.17745 11.80792 48.17157 527.07968 -6.55096 8.33970 2.48902 -4.73800 4.74364 -6.50651 7 3 4 2.38 -2013-Sep-20 09:11:22 4171690.62468 872115.64810 4730016.32879 11.80795 48.17157 531.61869 -4.18369 7.99351 7.02803 -2.37073 4.39745 -1.96750 7 3 4 2.38 -2013-Sep-20 09:11:22 4171689.75297 872115.64942 4730014.07272 11.80795 48.17156 529.36873 -4.00402 7.12453 4.77807 -2.19106 3.52847 -4.21746 7 3 4 2.38 -2013-Sep-20 09:11:22 4171693.28810 872116.93910 4730017.31292 11.80796 48.17156 534.26684 -3.46504 6.51033 9.67619 -1.65208 2.91427 0.68065 7 3 4 2.38 -2013-Sep-20 09:11:22 4171695.98563 872118.16653 4730021.78172 11.80797 48.17156 539.52518 -2.81558 7.33592 14.93452 -1.00262 3.73985 5.93899 7 3 4 2.38 -2013-Sep-20 09:11:22 4171697.11783 872120.37174 4730022.28911 11.80799 48.17156 540.94329 -0.88873 6.51224 16.35263 0.92423 2.91618 7.35710 7 3 4 2.38 -2013-Sep-20 09:11:22 4171695.48569 872119.38854 4730020.67335 11.80799 48.17156 538.53969 -1.51712 6.77505 13.94903 0.29584 3.17899 4.95350 7 3 4 2.38 -2013-Sep-20 09:11:23 4171695.47061 872118.34524 4730020.12538 11.80797 48.17156 537.97915 -2.53527 6.57970 13.38849 -0.72231 2.98364 4.39296 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.81562 872117.25637 4730018.29186 11.80796 48.17156 534.73117 -3.05779 7.45944 10.14051 -1.24483 3.86337 1.14498 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.16092 872114.76973 4730016.10991 11.80793 48.17156 532.33857 -5.35784 6.86097 7.74791 -3.54488 3.26491 -1.24762 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.87697 872114.47291 4730017.48267 11.80793 48.17156 533.78839 -5.79490 7.29946 9.19773 -3.98195 3.70340 0.20220 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.86069 872116.07764 4730017.23552 11.80795 48.17156 533.81260 -4.22081 6.90182 9.22194 -2.40785 3.30575 0.22641 7 3 4 2.38 -2013-Sep-20 09:11:23 4171693.87686 872118.40258 4730018.95306 11.80798 48.17156 536.07304 -2.15301 6.95157 11.48238 -0.34005 3.35551 2.48685 7 3 4 2.38 -2013-Sep-20 09:11:23 4171694.98367 872119.17613 4730019.43245 11.80798 48.17155 537.25834 -1.62231 6.34605 12.66768 0.19065 2.74998 3.67215 7 3 4 2.38 -2013-Sep-20 09:11:23 4171695.21549 872119.60786 4730019.65619 11.80799 48.17155 537.63531 -1.24716 6.26035 13.04465 0.56580 2.66428 4.04912 7 3 4 2.38 -2013-Sep-20 09:11:23 4171695.99088 872119.06174 4730019.64147 11.80798 48.17155 538.05598 -1.94039 5.76825 13.46532 -0.12743 2.17219 4.46979 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.45117 872118.44593 4730017.51592 11.80798 48.17156 534.07741 -1.81883 7.02639 9.48675 -0.00587 3.43033 0.49122 7 3 4 2.38 -2013-Sep-20 09:11:23 4171687.29885 872117.29525 4730012.83925 11.80798 48.17157 527.07219 -1.89082 7.84095 2.48153 -0.07787 4.24489 -6.51400 7 3 4 2.38 -2013-Sep-20 09:11:23 4171683.14258 872114.63254 4730008.28239 11.80796 48.17157 520.60012 -3.64668 8.23945 -3.99054 -1.83372 4.64339 -12.98607 7 3 4 2.38 -2013-Sep-20 09:11:23 4171686.28035 872115.76735 4730009.89013 11.80796 48.17156 524.00129 -3.17797 6.85001 -0.58937 -1.36501 3.25395 -9.58490 7 3 4 2.38 -2013-Sep-20 09:11:23 4171687.67267 872117.00778 4730014.37423 11.80798 48.17158 528.42077 -2.24871 8.63580 3.83011 -0.43575 5.03974 -5.16542 7 3 4 2.38 -2013-Sep-20 09:11:23 4171687.19397 872117.35970 4730014.17360 11.80798 48.17158 528.00680 -1.80628 8.79749 3.41614 0.00668 5.20143 -5.57939 7 3 4 2.38 -2013-Sep-20 09:11:23 4171688.80661 872116.60744 4730014.62659 11.80797 48.17157 529.29440 -2.87262 8.03808 4.70374 -1.05966 4.44202 -4.29179 7 3 4 2.38 -2013-Sep-20 09:11:23 4171688.60392 872118.37171 4730014.15304 11.80799 48.17157 529.04999 -1.10420 7.60108 4.45934 0.70876 4.00502 -4.53620 7 3 4 2.38 -2013-Sep-20 09:11:23 4171688.03548 872117.48240 4730014.82352 11.80798 48.17158 529.05717 -1.85837 8.59844 4.46651 -0.04542 5.00238 -4.52902 7 3 4 2.38 -2013-Sep-20 09:11:23 4171691.45022 872117.54123 4730019.00948 11.80797 48.17158 534.41345 -2.49956 8.89047 9.82279 -0.68660 5.29441 0.82726 7 3 4 2.38 -2013-Sep-20 09:11:23 4171688.58405 872116.29982 4730014.90400 11.80796 48.17157 529.31385 -3.12818 8.43232 4.72319 -1.31523 4.83626 -4.27234 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.02985 872117.87410 4730018.06185 11.80797 48.17157 534.13113 -2.29234 7.78497 9.54047 -0.47938 4.18890 0.54494 7 3 4 2.38 -2013-Sep-20 09:11:23 4171690.47194 872116.45149 4730016.02004 11.80796 48.17157 531.39856 -3.36604 7.77650 6.80790 -1.55309 4.18044 -2.18763 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.92686 872118.76633 4730018.34805 11.80798 48.17156 535.05172 -1.60255 7.18553 10.46106 0.21041 3.58947 1.46553 7 3 4 2.38 -2013-Sep-20 09:11:23 4171694.75491 872120.57368 4730019.23097 11.80800 48.17155 537.14960 -0.20752 6.16543 12.55894 1.60544 2.56937 3.56341 7 3 4 2.38 -2013-Sep-20 09:11:23 4171692.01646 872118.24976 4730016.57278 11.80798 48.17156 533.06409 -1.92189 6.74439 8.47343 -0.10893 3.14832 -0.52210 7 3 4 2.38 -2013-Sep-20 09:11:24 4171691.01468 872116.28329 4730014.34412 11.80796 48.17155 530.48109 -3.64175 6.28861 5.89043 -1.82879 2.69255 -3.10510 7 3 4 2.38 -2013-Sep-20 09:11:24 4171689.06716 872114.68632 4730012.29307 11.80794 48.17156 527.46351 -4.80640 6.58474 2.87285 -2.99344 2.98868 -6.12268 7 3 4 2.38 -2013-Sep-20 09:11:24 4171694.73608 872119.44056 4730010.88709 11.80799 48.17150 530.76527 -1.31281 0.78738 6.17462 0.50015 -2.80868 -2.82092 7 3 4 2.38 -2013-Sep-20 09:11:24 4171693.72087 872119.68492 4730011.32274 11.80799 48.17151 530.46052 -0.86588 1.78113 5.86987 0.94708 -1.81493 -3.12567 7 3 4 2.38 -2013-Sep-20 09:11:24 4171693.94370 872118.06655 4730011.54638 11.80797 48.17152 530.55176 -2.49560 2.01452 5.96111 -0.68264 -1.58154 -3.03442 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.12249 872117.40179 4730009.68968 11.80797 48.17152 527.88867 -2.77361 2.20599 3.29802 -0.96065 -1.39007 -5.69752 7 3 4 2.38 -2013-Sep-20 09:11:24 4171693.86774 872119.69170 4730012.79420 11.80799 48.17152 531.65378 -0.88929 2.65430 7.06312 0.92367 -0.94177 -1.93241 7 3 4 2.38 -2013-Sep-20 09:11:24 4171693.32531 872117.33516 4730012.51212 11.80796 48.17153 530.76789 -3.08496 3.22113 6.17724 -1.27201 -0.37493 -2.81830 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.47192 872117.94517 4730010.57339 11.80797 48.17152 528.84942 -2.31323 2.45762 4.25877 -0.50027 -1.13844 -4.73676 7 3 4 2.38 -2013-Sep-20 09:11:24 4171695.01986 872119.00377 4730014.00965 11.80798 48.17152 533.21767 -1.79843 2.72945 8.62701 0.01453 -0.86661 -0.36852 7 3 4 2.38 -2013-Sep-20 09:11:24 4171694.88813 872120.33154 4730015.53964 11.80800 48.17153 534.45295 -0.47180 3.64342 9.86229 1.34116 0.04736 0.86676 7 3 4 2.38 -2013-Sep-20 09:11:24 4171695.65854 872119.35883 4730015.62841 11.80798 48.17153 534.88926 -1.58158 3.28902 10.29861 0.23138 -0.30704 1.30307 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.29963 872117.57776 4730012.46967 11.80797 48.17153 530.09982 -2.63762 3.90394 5.50916 -0.82466 0.30788 -3.48637 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.03831 872116.55714 4730014.60814 11.80796 48.17155 531.38342 -3.58316 5.67631 6.79276 -1.77020 2.08025 -2.20277 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.67337 872117.02064 4730013.77478 11.80796 48.17154 531.24026 -3.25943 4.58668 6.64960 -1.44647 0.99062 -2.34593 7 3 4 2.38 -2013-Sep-20 09:11:24 4171695.89232 872118.66842 4730018.17083 11.80797 48.17154 536.84212 -2.30521 4.91933 12.25146 -0.49225 1.32327 3.25593 7 3 4 2.38 -2013-Sep-20 09:11:24 4171693.74490 872118.23743 4730015.79962 11.80797 48.17154 533.61459 -2.28765 4.96996 9.02394 -0.47470 1.37390 0.02841 7 3 4 2.38 -2013-Sep-20 09:11:24 4171694.70598 872117.25327 4730014.62039 11.80796 48.17153 533.22897 -3.44766 3.63261 8.63832 -1.63470 0.03655 -0.35722 7 3 4 2.38 -2013-Sep-20 09:11:24 4171692.92441 872118.47677 4730011.63261 11.80798 48.17152 530.00662 -1.88548 2.75292 5.41597 -0.07253 -0.84314 -3.57956 7 3 4 2.38 -2013-Sep-20 09:11:24 4171691.52667 872118.87196 4730011.44362 11.80799 48.17153 529.00730 -1.21263 3.58611 4.41665 0.60032 -0.00995 -4.57889 7 3 4 2.38 -2013-Sep-20 09:11:24 4171694.25462 872121.51872 4730015.11176 11.80802 48.17153 533.88257 0.81989 3.63911 9.29192 2.63285 0.04305 0.29638 7 3 4 2.38 -2013-Sep-20 09:11:24 4171696.05999 872118.78231 4730016.87878 11.80798 48.17153 536.00435 -2.22805 3.91800 11.41370 -0.41509 0.32194 2.41816 7 3 4 2.38 -2013-Sep-20 09:11:24 4171691.43406 872115.78258 4730012.57313 11.80795 48.17154 529.36688 -4.21768 4.87799 4.77623 -2.40472 1.28193 -4.21931 7 3 4 2.38 -2013-Sep-20 09:11:24 4171689.02374 872114.43196 4730010.05337 11.80794 48.17154 525.73154 -5.04649 5.16153 1.14088 -3.23353 1.56547 -7.85465 7 3 4 2.38 -2013-Sep-20 09:11:24 4171689.82579 872114.00495 4730009.74249 11.80793 48.17154 525.96520 -5.62860 4.43432 1.37454 -3.81564 0.83826 -7.62099 7 3 4 2.38 -2013-Sep-20 09:11:25 4171692.94276 872114.53020 4730013.00038 11.80793 48.17154 530.49920 -5.75229 4.25348 5.90855 -3.93933 0.65742 -3.08698 7 3 4 2.38 -2013-Sep-20 09:11:25 4171696.43597 872116.98179 4730015.20824 11.80795 48.17152 534.75928 -4.06741 2.80422 10.16862 -2.25445 -0.79184 1.17309 7 3 4 2.38 -2013-Sep-20 09:11:25 4171697.42899 872118.36885 4730017.32999 11.80797 48.17153 537.17781 -2.91290 3.28345 12.58716 -1.09994 -0.31262 3.59163 7 3 4 2.38 -2013-Sep-20 09:11:25 4171697.33026 872116.57227 4730016.99697 11.80794 48.17153 536.62004 -4.65126 3.40731 12.02938 -2.83830 -0.18876 3.03385 7 3 4 2.38 -2013-Sep-20 09:11:25 4171696.09689 872117.06043 4730016.70701 11.80795 48.17153 535.66546 -3.92104 4.03909 11.07481 -2.10808 0.44302 2.07928 7 3 4 2.38 -2013-Sep-20 09:11:25 4171696.46879 872118.51743 4730018.06942 11.80797 48.17154 537.12226 -2.57098 4.45426 12.53161 -0.75802 0.85820 3.53608 7 3 4 2.38 -2013-Sep-20 09:11:25 4171693.42590 872118.06426 4730015.15919 11.80797 48.17154 532.90551 -2.39188 4.80193 8.31486 -0.57892 1.20587 -0.68067 7 3 4 2.38 -2013-Sep-20 09:11:25 4171690.58025 872116.64729 4730012.69413 11.80796 48.17155 529.01769 -3.19656 5.44958 4.42704 -1.38360 1.85352 -4.56850 7 3 4 2.38 -2013-Sep-20 09:11:25 4171691.12781 872116.15449 4730011.72512 11.80795 48.17154 528.58583 -3.79098 4.47912 3.99518 -1.97802 0.88306 -5.00036 7 3 4 2.38 -2013-Sep-20 09:11:25 4171691.82827 872116.67823 4730011.86627 11.80796 48.17153 529.21974 -3.42165 3.98249 4.62908 -1.60869 0.38643 -4.36645 7 3 4 2.38 -2013-Sep-20 09:11:25 4171693.99266 872119.22471 4730014.41203 11.80799 48.17153 532.87711 -1.37197 3.71332 8.28645 0.44099 0.11726 -0.70908 7 3 4 2.38 -2013-Sep-20 09:11:25 4171692.83202 872118.52777 4730016.42282 11.80798 48.17155 533.52267 -1.81665 6.00714 8.93202 -0.00369 2.41108 -0.06352 7 3 4 2.38 -2013-Sep-20 09:11:25 4171698.55650 872121.22407 4730021.03271 11.80800 48.17154 541.06256 -0.34883 4.49505 16.47190 1.46413 0.89899 7.47637 7 3 4 2.38 -2013-Sep-20 09:11:25 4171695.04048 872119.56744 4730016.57388 11.80799 48.17154 535.21878 -1.25090 4.33855 10.62813 0.56206 0.74249 1.63259 7 3 4 2.38 -2013-Sep-20 09:11:25 4171695.90497 872120.45805 4730017.43063 11.80800 48.17153 536.54305 -0.55605 4.14358 11.95240 1.25691 0.54751 2.95686 7 3 4 2.38 -2013-Sep-20 09:11:25 4171696.09424 872119.26173 4730016.89450 11.80798 48.17153 536.10385 -1.76578 3.83040 11.51320 0.04718 0.23433 2.51766 7 3 4 2.38 -2013-Sep-20 09:11:25 4171692.61374 872118.10090 4730013.36178 11.80798 48.17154 531.04101 -2.18982 4.19002 6.45035 -0.37686 0.59396 -2.54518 7 3 4 2.38 -2013-Sep-20 09:11:25 4171694.36270 872118.03702 4730015.73834 11.80797 48.17154 533.94487 -2.61025 4.50905 9.35422 -0.79729 0.91298 0.35868 7 3 4 2.38 -2013-Sep-20 09:11:25 4171697.04059 872118.20076 4730017.98789 11.80797 48.17153 537.39156 -2.99795 4.03113 12.80091 -1.18499 0.43506 3.80537 7 3 4 2.38 -2013-Sep-20 09:11:25 4171696.55999 872119.84549 4730019.06078 11.80799 48.17154 538.10175 -1.28968 4.84638 13.51109 0.52328 1.25032 4.51556 7 3 4 2.38 -2013-Sep-20 09:11:25 4171695.29187 872119.57062 4730017.30793 11.80799 48.17154 535.93029 -1.29924 4.64425 11.33963 0.51372 1.04819 2.34410 7 3 4 2.38 -2013-Sep-20 09:11:25 4171693.87880 872117.74562 4730015.08127 11.80797 48.17154 533.09961 -2.79646 4.46822 8.50896 -0.98350 0.87216 -0.48657 7 3 4 2.38 -2013-Sep-20 09:11:25 4171695.65525 872119.19908 4730016.35068 11.80798 48.17153 535.40351 -1.73728 3.79747 10.81285 0.07568 0.20140 1.81732 7 3 4 2.38 -2013-Sep-20 09:11:25 4171699.08051 872120.38503 4730018.46706 11.80799 48.17152 539.37834 -1.27734 2.52976 14.78769 0.53562 -1.06631 5.79215 7 3 4 2.38 -2013-Sep-20 09:11:25 4171698.36821 872119.86609 4730016.97570 11.80798 48.17152 537.73126 -1.63954 2.13383 13.14061 0.17342 -1.46224 4.14507 7 3 4 2.38 -2013-Sep-20 09:11:26 4171695.45471 872119.69750 4730014.47563 11.80799 48.17152 533.94343 -1.20836 2.61727 9.35278 0.60460 -0.97879 0.35725 7 3 4 2.38 -2013-Sep-20 09:11:26 4171691.42837 872117.31443 4730011.78606 11.80797 48.17153 528.98574 -2.71708 4.12367 4.39509 -0.90412 0.52761 -4.60044 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.71907 872121.11664 4730009.75732 11.80800 48.17148 531.44664 -0.07799 -1.66798 6.85599 1.73497 -5.26404 -2.13955 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.53243 872121.77257 4730011.51404 11.80801 48.17149 532.72333 0.60225 -0.46030 8.13268 2.41521 -4.05636 -0.86286 7 3 4 2.38 -2013-Sep-20 09:11:26 4171697.99796 872122.74733 4730013.99782 11.80802 48.17150 535.66382 1.25649 -0.02142 11.07316 3.06945 -3.61748 2.07763 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.37638 872121.71039 4730011.34412 11.80801 48.17149 532.48636 0.57332 -0.45033 7.89571 2.38628 -4.04639 -1.09983 7 3 4 2.38 -2013-Sep-20 09:11:26 4171698.35090 872122.14956 4730013.71091 11.80801 48.17149 535.59885 0.59915 -0.37904 11.00820 2.41211 -3.97510 2.01266 7 3 4 2.38 -2013-Sep-20 09:11:26 4171703.46376 872123.87039 4730019.69749 11.80802 48.17149 543.63218 1.23731 -0.37817 19.04153 3.05027 -3.97423 10.04599 7 3 4 2.38 -2013-Sep-20 09:11:26 4171700.56430 872122.35069 4730016.45134 11.80801 48.17150 539.11320 0.34309 -0.19650 14.52254 2.15606 -3.79257 5.52701 7 3 4 2.38 -2013-Sep-20 09:11:26 4171698.23291 872121.53889 4730013.56136 11.80801 48.17149 535.32705 0.02555 -0.29960 10.73639 1.83851 -3.89566 1.74086 7 3 4 2.38 -2013-Sep-20 09:11:26 4171697.16465 872121.43782 4730013.15708 11.80801 48.17150 534.31466 0.14522 0.22536 9.72400 1.95818 -3.37070 0.72847 7 3 4 2.38 -2013-Sep-20 09:11:26 4171698.34796 872120.87849 4730014.23452 11.80800 48.17150 535.81363 -0.64442 0.16612 11.22297 1.16854 -3.42995 2.22744 7 3 4 2.38 -2013-Sep-20 09:11:26 4171695.76204 872118.60876 4730013.18849 11.80797 48.17151 533.03637 -2.33696 1.70071 8.44571 -0.52400 -1.89535 -0.54982 7 3 4 2.38 -2013-Sep-20 09:11:26 4171699.44609 872120.90827 4730017.97351 11.80799 48.17151 539.32063 -0.83998 1.85417 14.72997 0.97298 -1.74189 5.73444 7 3 4 2.38 -2013-Sep-20 09:11:26 4171698.64752 872119.43110 4730014.89668 11.80798 48.17150 536.30506 -2.12248 0.60993 11.71440 -0.30952 -2.98614 2.71887 7 3 4 2.38 -2013-Sep-20 09:11:26 4171697.55984 872120.17978 4730014.86997 11.80799 48.17151 535.67731 -1.16707 1.27128 11.08665 0.64589 -2.32479 2.09112 7 3 4 2.38 -2013-Sep-20 09:11:26 4171697.01947 872118.31837 4730015.09299 11.80797 48.17152 535.23671 -2.87851 2.09797 10.64606 -1.06555 -1.49809 1.65052 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.65306 872117.98772 4730014.86804 11.80796 48.17152 534.78477 -3.12718 2.26563 10.19412 -1.31422 -1.33044 1.19859 7 3 4 2.38 -2013-Sep-20 09:11:26 4171697.36222 872119.83651 4730014.54769 11.80799 48.17151 535.26130 -1.46263 1.25283 10.67065 0.35033 -2.34323 1.67512 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.52404 872118.30901 4730013.17213 11.80797 48.17151 533.48070 -2.78630 1.17972 8.89004 -0.97334 -2.41634 -0.10549 7 3 4 2.38 -2013-Sep-20 09:11:26 4171698.86385 872121.33989 4730017.74518 11.80800 48.17152 538.82931 -0.29835 2.06076 14.23865 1.51461 -1.53531 5.24312 7 3 4 2.38 -2013-Sep-20 09:11:26 4171696.58909 872119.79233 4730014.38210 11.80799 48.17151 534.62719 -1.34768 1.71304 10.03654 0.46528 -1.88303 1.04100 7 3 4 2.38 -2013-Sep-20 09:11:26 4171700.46335 872121.06357 4730017.83751 11.80799 48.17151 539.90455 -0.89613 0.99783 15.31389 0.91683 -2.59824 6.31836 7 3 4 2.38 -2013-Sep-20 09:11:26 4171700.66830 872121.68466 4730017.35859 11.80800 48.17150 539.76623 -0.33013 0.43424 15.17557 1.48283 -3.16182 6.18004 7 3 4 2.38 -2013-Sep-20 09:11:26 4171700.85203 872122.99020 4730019.80879 11.80802 48.17151 541.89009 0.91019 1.73522 17.29943 2.72315 -1.86085 8.30390 7 3 4 2.38 -2013-Sep-20 09:11:27 4171698.23027 872122.52875 4730017.15334 11.80802 48.17152 538.13696 0.99500 1.94689 13.54630 2.80797 -1.64917 4.55077 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.75157 872120.64933 4730014.79814 11.80800 48.17151 535.16023 -0.54206 1.74131 10.56957 1.27090 -1.85475 1.57404 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.76416 872119.87706 4730013.78979 11.80799 48.17151 534.31169 -1.30056 1.17741 9.72103 0.51240 -2.41865 0.72550 7 3 4 2.38 -2013-Sep-20 09:11:27 4171698.92258 872120.43430 4730016.84209 11.80799 48.17151 538.07113 -1.19680 1.55373 13.48048 0.61616 -2.04234 4.48494 7 3 4 2.38 -2013-Sep-20 09:11:27 4171699.32516 872119.95899 4730019.37041 11.80798 48.17152 540.15303 -1.74442 3.01872 15.56238 0.06854 -0.57735 6.56684 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.62232 872119.48749 4730015.38510 11.80798 48.17152 535.35466 -1.65286 2.40418 10.76401 0.16010 -1.19188 1.76847 7 3 4 2.38 -2013-Sep-20 09:11:27 4171695.82406 872119.99204 4730012.96060 11.80799 48.17151 533.09582 -0.99563 1.29258 8.50517 0.81733 -2.30348 -0.49037 7 3 4 2.38 -2013-Sep-20 09:11:27 4171697.16384 872120.84539 4730013.40883 11.80800 48.17150 534.42087 -0.43451 0.48418 9.83022 1.37845 -3.11188 0.83468 7 3 4 2.38 -2013-Sep-20 09:11:27 4171694.88333 872120.47935 4730010.82835 11.80800 48.17150 530.95939 -0.32614 0.48241 6.36873 1.48682 -3.11365 -2.62680 7 3 4 2.38 -2013-Sep-20 09:11:27 4171697.97785 872121.99028 4730014.31845 11.80801 48.17150 535.78629 0.51958 0.32252 11.19563 2.33254 -3.27354 2.20010 7 3 4 2.38 -2013-Sep-20 09:11:27 4171698.45984 872122.18730 4730016.08542 11.80801 48.17151 537.44446 0.61380 1.11932 12.85381 2.42676 -2.47674 3.85827 7 3 4 2.38 -2013-Sep-20 09:11:27 4171701.78809 872123.72444 4730018.20614 11.80802 48.17150 541.40713 1.43735 -0.12830 16.81648 3.25031 -3.72436 7.82094 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.37122 872121.62406 4730011.62400 11.80801 48.17150 532.67977 0.48988 -0.24675 8.08911 2.30284 -3.84281 -0.90642 7 3 4 2.38 -2013-Sep-20 09:11:27 4171695.20851 872120.51676 4730010.85522 11.80800 48.17150 531.19679 -0.35606 0.25745 6.60614 1.45690 -3.33861 -2.38940 7 3 4 2.38 -2013-Sep-20 09:11:27 4171697.02880 872121.39072 4730013.54692 11.80801 48.17150 534.51004 0.12691 0.59162 9.91939 1.93988 -3.00445 0.92385 7 3 4 2.38 -2013-Sep-20 09:11:27 4171698.35699 872122.09135 4730015.74924 11.80801 48.17151 537.11373 0.54092 0.98476 12.52307 2.35388 -2.61130 3.52754 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.79047 872123.00365 4730015.42316 11.80803 48.17151 535.97264 1.75448 1.77078 11.38198 3.56744 -1.82529 2.38645 7 3 4 2.38 -2013-Sep-20 09:11:27 4171695.26064 872122.85392 4730013.27502 11.80803 48.17151 533.35288 1.92098 1.47683 8.76223 3.73394 -2.11923 -0.23331 7 3 4 2.38 -2013-Sep-20 09:11:27 4171698.51176 872122.27968 4730016.83279 11.80801 48.17151 538.04786 0.69360 1.56578 13.45721 2.50656 -2.03028 4.46167 7 3 4 2.38 -2013-Sep-20 09:11:27 4171697.06947 872120.76356 4730013.38628 11.80800 48.17150 534.33130 -0.49530 0.55045 9.74065 1.31766 -3.04561 0.74511 7 3 4 2.38 -2013-Sep-20 09:11:27 4171699.70373 872120.05775 4730016.30475 11.80798 48.17150 538.12928 -1.72522 0.68304 13.53862 0.08774 -2.91303 4.54309 7 3 4 2.38 -2013-Sep-20 09:11:27 4171696.10559 872119.77345 4730013.66015 11.80799 48.17151 533.77103 -1.26721 1.58710 9.18038 0.54575 -2.00896 0.18485 7 3 4 2.38 -2013-Sep-20 09:11:27 4171699.19207 872119.76258 4730016.24054 11.80798 48.17151 537.70715 -1.90945 1.05842 13.11649 -0.09649 -2.53764 4.12096 7 3 4 2.38 -2013-Sep-20 09:11:27 4171694.38017 872117.19225 4730010.17298 11.80796 48.17151 529.69399 -3.44071 0.91355 5.10334 -1.62775 -2.68251 -3.89220 7 3 4 2.38 -2013-Sep-20 09:11:27 4171694.22234 872117.85273 4730011.09932 11.80797 48.17151 530.37136 -2.76191 1.54574 5.78070 -0.94896 -2.05032 -3.21483 7 3 4 2.38 -2013-Sep-20 09:11:28 4171695.11148 872119.04029 4730014.07009 11.80798 48.17152 533.32750 -1.78143 2.69736 8.73684 0.03153 -0.89870 -0.25869 7 3 4 2.38 -2013-Sep-20 09:11:28 4171698.15677 872119.96893 4730018.03728 11.80799 48.17152 538.39830 -1.49561 2.98033 13.80764 0.31735 -0.61574 4.81211 7 3 4 2.38 -2013-Sep-20 09:11:28 4171692.57672 872118.00723 4730011.52180 11.80798 48.17152 529.63301 -2.27394 3.00422 5.04235 -0.46098 -0.59184 -3.95318 7 3 4 2.38 -2013-Sep-20 09:11:28 4171695.70734 872120.86786 4730014.12594 11.80800 48.17152 534.00749 -0.11447 2.02133 9.41684 1.69849 -1.57473 0.42130 7 3 4 2.38 -2013-Sep-20 09:11:28 4171697.26853 872120.68400 4730015.72391 11.80800 48.17152 536.19225 -0.61391 1.97637 11.60160 1.19905 -1.61969 2.60607 7 3 4 2.38 -2013-Sep-20 09:11:28 4171694.52444 872120.43586 4730012.73190 11.80800 48.17152 532.13760 -0.29526 2.02030 7.54694 1.51769 -1.57576 -1.44859 7 3 4 2.38 -2013-Sep-20 09:11:28 4171692.39192 872118.57243 4730011.27480 11.80798 48.17152 529.40545 -1.68288 2.88810 4.81480 0.13008 -0.70796 -4.18073 7 3 4 2.38 -2013-Sep-20 09:11:28 4171692.78390 872117.78744 4730010.16343 11.80797 48.17152 528.72607 -2.53147 1.98071 4.13542 -0.71851 -1.61535 -4.86012 7 3 4 2.38 -2013-Sep-20 09:11:28 4171691.87487 872117.15786 4730009.97550 11.80797 48.17152 527.90672 -2.96171 2.61440 3.31606 -1.14875 -0.98165 -5.67947 7 3 4 2.38 -2013-Sep-20 09:11:28 4171699.73964 872121.31398 4730017.51368 11.80800 48.17151 539.22498 -0.50293 1.27154 14.63432 1.31003 -2.32453 5.63879 7 3 4 2.38 -2013-Sep-20 09:11:28 4171696.61637 872120.95475 4730015.62866 11.80800 48.17152 535.73250 -0.21543 2.34723 11.14185 1.59753 -1.24883 2.14631 7 3 4 2.38 -2013-Sep-20 09:11:28 4171699.45129 872122.06901 4730018.32541 11.80801 48.17151 539.74464 0.29513 1.90808 15.15399 2.10809 -1.68799 6.15845 7 3 4 2.38 -2013-Sep-20 09:11:28 4171697.16364 872119.64857 4730015.64253 11.80798 48.17152 535.92184 -1.60596 2.15647 11.33118 0.20700 -1.43959 2.33565 7 3 4 2.38 -2013-Sep-20 09:11:28 4171693.87384 872118.79801 4730011.97069 11.80798 48.17152 530.92216 -1.76532 2.23691 6.33150 0.04764 -1.35915 -2.66403 7 3 4 2.38 -2013-Sep-20 09:11:28 4171690.82398 872118.69498 4730010.21216 11.80799 48.17153 527.60682 -1.24207 3.30434 3.01617 0.57089 -0.29171 -5.97937 7 3 4 2.38 -2013-Sep-20 09:11:28 4171691.81943 872118.46771 4730010.90035 11.80798 48.17153 528.73842 -1.66823 3.07190 4.14777 0.14473 -0.52416 -4.84776 7 3 4 2.38 -2013-Sep-20 09:11:28 4171695.31081 872120.55540 4730015.15712 11.80800 48.17153 534.47438 -0.33917 3.04589 9.88373 1.47379 -0.55017 0.88819 7 3 4 2.38 -2013-Sep-20 09:11:28 4171696.57652 872120.27903 4730016.16587 11.80799 48.17152 536.01457 -0.86870 2.83759 11.42392 0.94426 -0.75847 2.42838 7 3 4 2.38 -2013-Sep-20 09:11:28 4171698.61181 872122.98260 4730016.69875 11.80802 48.17151 538.10922 1.36117 1.29624 13.51857 3.17413 -2.29982 4.52303 7 3 4 2.38 -2013-Sep-20 09:11:28 4171695.15391 872121.11126 4730014.38076 11.80801 48.17152 533.86931 0.23703 2.55782 9.27866 2.04999 -1.03825 0.28312 7 3 4 2.38 -2013-Sep-20 09:11:28 4171694.64640 872120.83946 4730012.58297 11.80801 48.17151 532.16131 0.07484 1.77048 7.57066 1.88780 -1.82558 -1.42488 7 3 4 2.38 -2013-Sep-20 09:11:28 4171691.63031 872119.31195 4730011.21968 11.80799 48.17153 528.96813 -0.80316 3.29407 4.37747 1.00980 -0.30198 -4.61806 7 3 4 2.38 -2013-Sep-20 09:11:28 4171689.25703 872118.79877 4730009.74856 11.80799 48.17153 526.25265 -0.81983 4.12224 1.66199 0.99313 0.52619 -7.33354 7 3 4 2.38 -2013-Sep-20 09:11:28 4171689.90162 872120.13573 4730011.28216 11.80801 48.17154 527.99864 0.35694 4.47099 3.40798 2.16989 0.87493 -5.58755 7 3 4 2.38 -2013-Sep-20 09:11:28 4171691.77881 872120.72587 4730012.57524 11.80801 48.17153 530.26812 0.55045 3.87419 5.67746 2.36341 0.27813 -3.31807 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.45743 872120.72748 4730014.45920 11.80801 48.17154 532.11516 0.41316 4.63540 7.52450 2.22612 1.03934 -1.47103 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.88042 872119.50118 4730013.40565 11.80799 48.17153 531.43888 -0.87374 3.81125 6.84823 0.93922 0.21519 -2.14731 7 3 4 2.38 -2013-Sep-20 09:11:29 4171693.25078 872118.94429 4730013.69045 11.80799 48.17153 531.81687 -1.49464 3.81597 7.22621 0.31832 0.21990 -1.76932 7 3 4 2.38 -2013-Sep-20 09:11:29 4171689.33849 872117.64902 4730011.45198 11.80798 48.17155 527.41821 -1.96192 5.37416 2.82756 -0.14896 1.77810 -6.16797 7 3 4 2.38 -2013-Sep-20 09:11:29 4171691.67619 872118.95441 4730014.83285 11.80799 48.17155 531.64162 -1.16252 5.72476 7.05096 0.65043 2.12870 -1.94457 7 3 4 2.38 -2013-Sep-20 09:11:29 4171690.74721 872117.78260 4730015.28347 11.80798 48.17156 531.21106 -2.11943 6.88154 6.62040 -0.30648 3.28548 -2.37513 7 3 4 2.38 -2013-Sep-20 09:11:29 4171693.06028 872118.23964 4730018.20147 11.80798 48.17156 534.95771 -2.14540 7.07077 10.36705 -0.33244 3.47471 1.37152 7 3 4 2.38 -2013-Sep-20 09:11:29 4171695.36513 872118.22820 4730018.55966 11.80797 48.17155 536.72763 -2.62825 5.63029 12.13698 -0.81529 2.03422 3.14145 7 3 4 2.38 -2013-Sep-20 09:11:29 4171694.87433 872119.42778 4730018.09010 11.80799 48.17155 536.22106 -1.35362 5.49221 11.63041 0.45934 1.89615 2.63488 7 3 4 2.38 -2013-Sep-20 09:11:29 4171698.50407 872122.34864 4730022.07376 11.80802 48.17154 541.95753 0.76268 5.05610 17.36688 2.57564 1.46003 8.37135 7 3 4 2.38 -2013-Sep-20 09:11:29 4171699.62995 872122.88747 4730024.16930 11.80802 48.17155 544.32751 1.05971 5.55027 19.73685 2.87267 1.95421 10.74132 7 3 4 2.38 -2013-Sep-20 09:11:29 4171696.84794 872121.87700 4730020.45151 11.80801 48.17154 539.60325 0.63992 5.25408 15.01260 2.45288 1.65801 6.01707 7 3 4 2.38 -2013-Sep-20 09:11:29 4171699.64875 872122.48073 4730022.82808 11.80801 48.17154 543.28487 0.65774 4.70412 18.69421 2.47070 1.10805 9.69868 7 3 4 2.38 -2013-Sep-20 09:11:29 4171695.56689 872120.80957 4730017.99886 11.80800 48.17154 536.79375 -0.14278 4.71553 12.20309 1.67018 1.11946 3.20756 7 3 4 2.38 -2013-Sep-20 09:11:29 4171694.09739 872120.41500 4730016.23289 11.80800 48.17154 534.46472 -0.22830 4.66978 9.87407 1.58466 1.07371 0.87853 7 3 4 2.38 -2013-Sep-20 09:11:29 4171689.51731 872117.48823 4730013.34802 11.80798 48.17156 528.92582 -2.15590 6.53273 4.33516 -0.34294 2.93667 -4.66037 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.20834 872119.52321 4730015.80457 11.80800 48.17155 532.79070 -0.71465 5.89794 8.20004 1.09831 2.30188 -0.79549 7 3 4 2.38 -2013-Sep-20 09:11:29 4171690.26954 872116.58989 4730011.80842 11.80796 48.17154 528.14705 -3.18916 5.09428 3.55640 -1.37621 1.49822 -5.43914 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.63805 872117.70373 4730014.79942 11.80797 48.17154 532.07393 -2.58356 5.19162 7.48327 -0.77060 1.59555 -1.51226 7 3 4 2.38 -2013-Sep-20 09:11:29 4171695.05242 872117.86474 4730016.05879 11.80797 48.17154 534.61039 -2.92001 4.24596 10.01973 -1.10706 0.64990 1.02420 7 3 4 2.38 -2013-Sep-20 09:11:29 4171696.28618 872119.29977 4730017.75940 11.80798 48.17154 536.87882 -1.76782 4.26141 12.28816 0.04514 0.66534 3.29263 7 3 4 2.38 -2013-Sep-20 09:11:29 4171696.24372 872119.42877 4730018.64861 11.80798 48.17154 537.53129 -1.63286 4.86573 12.94064 0.18010 1.26966 3.94510 7 3 4 2.38 -2013-Sep-20 09:11:29 4171694.47531 872120.14495 4730017.91560 11.80800 48.17155 535.92844 -0.56997 5.55751 11.33778 1.24299 1.96145 2.34225 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.02413 872118.75371 4730015.57320 11.80799 48.17155 532.39304 -1.43017 5.99533 7.80238 0.38279 2.39927 -1.19315 7 3 4 2.38 -2013-Sep-20 09:11:29 4171692.68112 872118.02196 4730015.16433 11.80797 48.17155 532.41738 -2.28088 5.35504 7.82672 -0.46792 1.75898 -1.16881 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.26892 872120.32798 4730019.17740 11.80799 48.17153 539.37006 -1.16711 3.60414 14.77941 0.64585 0.00807 5.78387 7 3 4 2.38 -2013-Sep-20 09:11:30 4171693.83005 872119.05864 4730014.08610 11.80799 48.17153 532.50543 -1.50125 3.63988 7.91478 0.31171 0.04382 -1.08076 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.20908 872122.93997 4730015.33242 11.80802 48.17150 536.82239 1.40186 0.68527 12.23174 3.21482 -2.91079 3.23620 7 3 4 2.38 -2013-Sep-20 09:11:30 4171695.97666 872120.12333 4730013.88632 11.80799 48.17151 533.90315 -0.89835 1.77862 9.31250 0.91461 -1.81744 0.31696 7 3 4 2.38 -2013-Sep-20 09:11:30 4171696.92966 872121.12356 4730013.16645 11.80800 48.17150 534.12535 -0.11430 0.45093 9.53470 1.69866 -3.14513 0.53916 7 3 4 2.38 -2013-Sep-20 09:11:30 4171697.32508 872121.12276 4730014.01853 11.80800 48.17150 535.01829 -0.19600 0.73090 10.42764 1.61696 -2.86517 1.43211 7 3 4 2.38 -2013-Sep-20 09:11:30 4171696.65321 872122.10532 4730013.16538 11.80802 48.17150 534.07807 0.90325 0.50214 9.48742 2.71621 -3.09392 0.49188 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.16121 872123.04957 4730013.98422 11.80803 48.17150 535.80150 1.51893 -0.19564 11.21084 3.33190 -3.79170 2.21531 7 3 4 2.38 -2013-Sep-20 09:11:30 4171699.64704 872122.89464 4730015.46791 11.80802 48.17150 537.85585 1.06324 -0.26627 13.26520 2.87620 -3.86233 4.26966 7 3 4 2.38 -2013-Sep-20 09:11:30 4171700.85327 872122.27936 4730017.03292 11.80801 48.17150 539.72546 0.21413 -0.00854 15.13481 2.02710 -3.60461 6.13927 7 3 4 2.38 -2013-Sep-20 09:11:30 4171696.34753 872120.12522 4730014.30993 11.80799 48.17151 534.46116 -0.97240 1.79033 9.87050 0.84056 -1.80573 0.87497 7 3 4 2.38 -2013-Sep-20 09:11:30 4171700.59557 872122.80469 4730018.34648 11.80802 48.17151 540.60772 0.78109 0.97533 16.01707 2.59405 -2.62073 7.02153 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.96544 872121.46834 4730015.70480 11.80800 48.17150 537.39278 -0.19341 0.60633 12.80212 1.61955 -2.98973 3.80659 7 3 4 2.38 -2013-Sep-20 09:11:30 4171692.62677 872118.77648 4730009.87217 11.80799 48.17151 528.54145 -1.53120 1.75027 3.95080 0.28176 -1.84579 -5.04474 7 3 4 2.38 -2013-Sep-20 09:11:30 4171693.56977 872118.49947 4730009.84089 11.80798 48.17151 529.09592 -1.99532 1.08384 4.50526 -0.18236 -2.51222 -4.49027 7 3 4 2.38 -2013-Sep-20 09:11:30 4171696.54106 872121.05589 4730014.78581 11.80800 48.17151 535.06910 -0.10102 1.82464 10.47844 1.71194 -1.77142 1.48291 7 3 4 2.38 -2013-Sep-20 09:11:30 4171699.28641 872121.68572 4730017.28730 11.80801 48.17151 538.81116 -0.04631 1.39445 14.22051 1.76665 -2.20161 5.22497 7 3 4 2.38 -2013-Sep-20 09:11:30 4171697.35350 872120.28275 4730015.59475 11.80799 48.17151 536.09672 -1.02406 1.88944 11.50606 0.78890 -1.70663 2.51053 7 3 4 2.38 -2013-Sep-20 09:11:30 4171697.41420 872120.14113 4730014.05201 11.80799 48.17151 534.96746 -1.17510 0.83790 10.37680 0.63786 -2.75817 1.38127 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.63958 872121.94094 4730017.48684 11.80801 48.17152 538.57243 0.33587 1.96040 13.98178 2.14883 -1.63566 4.98624 7 3 4 2.38 -2013-Sep-20 09:11:30 4171694.74321 872121.15456 4730014.74022 11.80801 48.17153 533.87498 0.36346 3.09049 9.28432 2.17642 -0.50557 0.28879 7 3 4 2.38 -2013-Sep-20 09:11:30 4171697.29040 872123.02076 4730016.70891 11.80803 48.17152 537.25940 1.66893 2.26100 12.66875 3.48189 -1.33506 3.67321 7 3 4 2.38 -2013-Sep-20 09:11:30 4171694.96024 872122.44852 4730013.85495 11.80803 48.17152 533.53358 1.58563 2.14450 8.94293 3.39859 -1.45156 -0.05261 7 3 4 2.38 -2013-Sep-20 09:11:30 4171693.89942 872122.01331 4730011.53162 11.80802 48.17151 531.05048 1.37670 1.43517 6.45982 3.18966 -2.16089 -2.53571 7 3 4 2.38 -2013-Sep-20 09:11:30 4171698.12185 872124.00491 4730015.22298 11.80804 48.17150 536.82924 2.46211 0.51352 12.23859 4.27507 -3.08254 3.24305 7 3 4 2.38 -2013-Sep-20 09:11:31 4171701.76915 872124.39407 4730017.25623 11.80803 48.17149 540.77833 2.09668 -0.85009 16.18767 3.90964 -4.44615 7.19214 7 3 4 2.38 -2013-Sep-20 09:11:31 4171701.62926 872123.10073 4730015.49390 11.80802 48.17148 539.19732 0.85934 -1.72614 14.60667 2.67230 -5.32221 5.61113 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.83396 872120.51495 4730012.08727 11.80800 48.17150 533.17567 -0.69045 -0.10618 8.58502 1.12251 -3.70224 -0.41052 7 3 4 2.38 -2013-Sep-20 09:11:31 4171697.41331 872121.31794 4730013.75052 11.80801 48.17150 534.90282 -0.02301 0.45804 10.31216 1.78996 -3.13802 1.31663 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.98600 872120.95555 4730013.18712 11.80800 48.17150 534.15461 -0.29029 0.44923 9.56395 1.52267 -3.14683 0.56842 7 3 4 2.38 -2013-Sep-20 09:11:31 4171694.04482 872120.43889 4730011.38615 11.80800 48.17151 530.82213 -0.19415 1.47217 6.23148 1.61881 -2.12389 -2.76405 7 3 4 2.38 -2013-Sep-20 09:11:31 4171698.00385 872123.47444 4730014.18133 11.80803 48.17150 535.90363 1.96702 -0.01420 11.31297 3.77998 -3.61026 2.31744 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.78061 872121.42378 4730014.12273 11.80801 48.17151 534.78159 0.21006 1.15161 10.19094 2.02302 -2.44446 1.19540 7 3 4 2.38 -2013-Sep-20 09:11:31 4171695.68997 872120.95522 4730012.45193 11.80801 48.17151 532.76070 -0.02540 0.90428 8.17005 1.78756 -2.69178 -0.82549 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.79229 872123.24570 4730012.80506 11.80803 48.17150 534.05600 1.99103 -0.01348 9.46534 3.80400 -3.60954 0.46981 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.84384 872123.37869 4730012.15739 11.80803 48.17149 533.62519 2.11066 -0.50329 9.03454 3.92362 -4.09935 0.03900 7 3 4 2.38 -2013-Sep-20 09:11:31 4171700.89634 872123.35249 4730017.20702 11.80802 48.17150 540.02976 1.25575 -0.08748 15.43911 3.06871 -3.68354 6.44357 7 3 4 2.38 -2013-Sep-20 09:11:31 4171697.98251 872119.90541 4730014.38778 11.80799 48.17150 535.55647 -1.52212 0.68326 10.96581 0.29084 -2.91281 1.97028 7 3 4 2.38 -2013-Sep-20 09:11:31 4171697.69756 872121.97965 4730014.15532 11.80801 48.17150 535.48031 0.56653 0.41978 10.88966 2.37949 -3.17628 1.89412 7 3 4 2.38 -2013-Sep-20 09:11:31 4171700.52680 872122.92218 4730016.59934 11.80802 48.17150 539.27699 0.91016 -0.15759 14.68633 2.72312 -3.75365 5.69080 7 3 4 2.38 -2013-Sep-20 09:11:31 4171698.39552 872121.11229 4730014.63178 11.80800 48.17150 536.17260 -0.42530 0.36071 11.58194 1.38766 -3.23535 2.58641 7 3 4 2.38 -2013-Sep-20 09:11:31 4171699.86931 872122.24930 4730015.30119 11.80801 48.17149 537.78865 0.38606 -0.44118 13.19799 2.19902 -4.03724 4.20246 7 3 4 2.38 -2013-Sep-20 09:11:31 4171698.03849 872122.27009 4730013.20913 11.80802 48.17149 535.03745 0.78106 -0.50419 10.44680 2.59402 -4.10025 1.45126 7 3 4 2.38 -2013-Sep-20 09:11:31 4171699.01237 872121.03175 4730015.15030 11.80800 48.17150 536.95066 -0.63036 0.26888 12.36000 1.18260 -3.32718 3.36447 7 3 4 2.38 -2013-Sep-20 09:11:31 4171700.38797 872122.29167 4730016.49317 11.80801 48.17150 539.02120 0.32141 -0.03100 14.43055 2.13437 -3.62706 5.43501 7 3 4 2.38 -2013-Sep-20 09:11:31 4171699.84155 872123.17397 4730018.40310 11.80802 48.17151 540.20808 1.29684 1.50675 15.61743 3.10981 -2.08931 6.62190 7 3 4 2.38 -2013-Sep-20 09:11:31 4171696.45219 872121.13268 4730015.80448 11.80801 48.17152 535.78062 -0.00767 2.55710 11.18997 1.80529 -1.03896 2.19443 7 3 4 2.38 -2013-Sep-20 09:11:31 4171697.41566 872121.08123 4730017.47779 11.80800 48.17152 537.64941 -0.25519 2.97815 13.05875 1.55777 -0.61792 4.06322 7 3 4 2.38 -2013-Sep-20 09:11:31 4171698.47013 872122.57172 4730018.46835 11.80802 48.17152 539.27927 0.98798 2.64238 14.68861 2.80094 -0.95369 5.69308 7 3 4 2.38 -2013-Sep-20 09:11:31 4171699.76482 872122.20683 4730018.91852 11.80801 48.17152 540.41008 0.36587 2.05393 15.81942 2.17883 -1.54214 6.82389 7 3 4 2.38 -2013-Sep-20 09:11:32 4171699.67571 872122.06987 4730017.84856 11.80801 48.17151 539.53594 0.25005 1.42624 14.94529 2.06301 -2.16982 5.94975 7 3 4 2.38 -2013-Sep-20 09:11:32 4171700.17402 872121.07050 4730017.18905 11.80799 48.17150 539.23342 -0.83014 0.77534 14.64277 0.98282 -2.82072 5.64723 7 3 4 2.38 -2013-Sep-20 09:11:32 4171699.94684 872120.69430 4730017.57383 11.80799 48.17151 539.32050 -1.15189 1.25502 14.72985 0.66107 -2.34105 5.73431 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.86171 872120.08078 4730012.05899 11.80799 48.17150 532.46068 -0.91648 0.65030 7.87002 0.89648 -2.94576 -1.12551 7 3 4 2.38 -2013-Sep-20 09:11:32 4171692.74376 872119.90583 4730009.63812 11.80800 48.17151 528.59753 -0.44970 1.33665 4.00688 1.36326 -2.25941 -4.98866 7 3 4 2.38 -2013-Sep-20 09:11:32 4171693.11802 872121.32357 4730009.95869 11.80802 48.17151 529.27420 0.86146 1.06128 4.68355 2.67442 -2.53478 -4.31199 7 3 4 2.38 -2013-Sep-20 09:11:32 4171694.62019 872121.63663 4730011.20999 11.80802 48.17150 531.22992 0.86051 0.75239 6.63927 2.67347 -2.84367 -2.35627 7 3 4 2.38 -2013-Sep-20 09:11:32 4171693.08701 872120.82783 4730010.58198 11.80801 48.17151 529.65074 0.38255 1.57516 5.06009 2.19551 -2.02090 -3.93544 7 3 4 2.38 -2013-Sep-20 09:11:32 4171693.56567 872120.52789 4730013.26995 11.80801 48.17153 531.92520 -0.00899 3.06439 7.33454 1.80397 -0.53167 -1.66099 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.48776 872121.01770 4730013.87497 11.80801 48.17152 533.69760 0.07713 1.99127 9.10694 1.89009 -1.60479 0.11141 7 3 4 2.38 -2013-Sep-20 09:11:32 4171696.54161 872120.89515 4730015.08405 11.80800 48.17152 535.26976 -0.25847 2.04764 10.67910 1.55449 -1.54842 1.68357 7 3 4 2.38 -2013-Sep-20 09:11:32 4171698.14005 872121.86835 4730014.99570 11.80801 48.17150 536.38018 0.36704 0.67446 11.78952 2.18000 -2.92160 2.79399 7 3 4 2.38 -2013-Sep-20 09:11:32 4171696.95949 872121.14289 4730014.46102 11.80800 48.17151 535.11211 -0.10149 1.28957 10.52145 1.71147 -2.30649 1.52592 7 3 4 2.38 -2013-Sep-20 09:11:32 4171696.00914 872119.82210 4730013.46721 11.80799 48.17151 533.57095 -1.19985 1.52136 8.98029 0.61311 -2.07470 -0.01524 7 3 4 2.38 -2013-Sep-20 09:11:32 4171701.40291 872121.95208 4730017.87108 11.80800 48.17150 540.66415 -0.21869 0.19944 16.07349 1.59427 -3.39662 7.07796 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.65275 872121.52404 4730015.60274 11.80801 48.17152 535.16185 0.53900 2.94598 10.57119 2.35196 -0.65009 1.57566 7 3 4 2.38 -2013-Sep-20 09:11:32 4171697.42165 872120.31319 4730016.56531 11.80799 48.17152 536.86857 -1.00820 2.48235 12.27791 0.80476 -1.11371 3.28238 7 3 4 2.38 -2013-Sep-20 09:11:32 4171698.96464 872121.97876 4730017.99457 11.80801 48.17152 539.16812 0.30637 2.05615 14.57747 2.11933 -1.53992 5.58194 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.54423 872120.87815 4730017.16218 11.80800 48.17154 536.16486 -0.07102 4.16361 11.57421 1.74194 0.56755 2.57867 7 3 4 2.38 -2013-Sep-20 09:11:32 4171690.17505 872117.83562 4730010.78609 11.80798 48.17154 527.49359 -1.95045 4.29145 2.90293 -0.13749 0.69540 -6.09260 7 3 4 2.38 -2013-Sep-20 09:11:32 4171692.12620 872119.79749 4730013.83103 11.80800 48.17154 531.30394 -0.42937 4.59987 6.71328 1.38359 1.00380 -2.28225 7 3 4 2.38 -2013-Sep-20 09:11:32 4171691.00390 872118.66875 4730012.66655 11.80799 48.17154 529.54957 -1.30456 4.81397 4.95891 0.50839 1.21791 -4.03662 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.61142 872119.94615 4730017.12012 11.80799 48.17154 536.05020 -0.99704 4.22866 11.45954 0.81592 0.63260 2.46401 7 3 4 2.38 -2013-Sep-20 09:11:32 4171697.07143 872119.70939 4730017.66332 11.80799 48.17153 537.37573 -1.52756 3.56213 12.78507 0.28540 -0.03393 3.78954 7 3 4 2.38 -2013-Sep-20 09:11:32 4171695.53907 872118.93159 4730014.25243 11.80798 48.17152 533.72766 -1.97533 2.52366 9.13700 -0.16237 -1.07240 0.14147 7 3 4 2.38 -2013-Sep-20 09:11:33 4171693.38314 872116.17409 4730011.24903 11.80795 48.17152 529.70601 -4.23330 2.51364 5.11535 -2.42034 -1.08242 -3.88018 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.17525 872118.25789 4730014.26288 11.80797 48.17153 532.75322 -2.35569 3.62810 8.16256 -0.54273 0.03204 -0.83297 7 3 4 2.38 -2013-Sep-20 09:11:33 4171696.14932 872119.23864 4730016.09468 11.80798 48.17153 535.54067 -1.79966 3.26034 10.95002 0.01330 -0.33572 1.95448 7 3 4 2.38 -2013-Sep-20 09:11:33 4171695.66794 872118.17743 4730016.54258 11.80797 48.17153 535.41536 -2.73990 4.07197 10.82470 -0.92694 0.47591 1.82917 7 3 4 2.38 -2013-Sep-20 09:11:33 4171692.65960 872117.00697 4730014.22706 11.80796 48.17154 531.56642 -3.26999 4.90043 6.97576 -1.45703 1.30437 -2.01977 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.86981 872118.65044 4730015.24167 11.80798 48.17153 533.98953 -2.11358 3.71441 9.39888 -0.30062 0.11834 0.40335 7 3 4 2.38 -2013-Sep-20 09:11:33 4171696.18617 872118.65764 4730015.63173 11.80797 48.17152 535.14048 -2.37590 3.01331 10.54982 -0.56294 -0.58275 1.55429 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.95458 872117.40193 4730013.79240 11.80796 48.17152 532.79457 -3.35301 2.87643 8.20391 -1.54005 -0.71963 -0.79162 7 3 4 2.38 -2013-Sep-20 09:11:33 4171695.80329 872119.19935 4730016.04300 11.80798 48.17153 535.27092 -1.76730 3.48426 10.68026 0.04566 -0.11181 1.68473 7 3 4 2.38 -2013-Sep-20 09:11:33 4171697.16613 872119.18397 4730018.03988 11.80798 48.17153 537.64643 -2.06124 3.82431 13.05578 -0.24828 0.22824 4.06025 7 3 4 2.38 -2013-Sep-20 09:11:33 4171695.34082 872118.39122 4730017.32410 11.80797 48.17154 535.81334 -2.46370 4.79916 11.22268 -0.65074 1.20310 2.22715 7 3 4 2.38 -2013-Sep-20 09:11:33 4171697.92042 872119.02717 4730019.71352 11.80797 48.17154 539.36453 -2.36908 4.41421 14.77388 -0.55612 0.81814 5.77835 7 3 4 2.38 -2013-Sep-20 09:11:33 4171696.31809 872117.99340 4730017.19117 11.80796 48.17153 536.29795 -3.05308 4.05837 11.70730 -1.24012 0.46231 2.71176 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.49039 872117.01224 4730014.71444 11.80796 48.17153 533.12542 -3.63947 3.88932 8.53477 -1.82651 0.29326 -0.46076 7 3 4 2.38 -2013-Sep-20 09:11:33 4171692.15456 872116.40968 4730011.34855 11.80796 48.17153 529.01031 -3.75129 3.44018 4.41966 -1.93833 -0.15588 -4.57588 7 3 4 2.38 -2013-Sep-20 09:11:33 4171693.74161 872117.77649 4730014.38891 11.80797 48.17153 532.49836 -2.73817 4.10184 7.90770 -0.92521 0.50578 -1.08783 7 3 4 2.38 -2013-Sep-20 09:11:33 4171691.32930 872116.91961 4730011.11749 11.80796 48.17153 528.36901 -3.08327 3.81026 3.77835 -1.27031 0.21420 -5.21718 7 3 4 2.38 -2013-Sep-20 09:11:33 4171689.40517 872115.46055 4730007.98031 11.80795 48.17153 524.57618 -4.11772 3.34396 -0.01447 -2.30476 -0.25210 -9.01001 7 3 4 2.38 -2013-Sep-20 09:11:33 4171691.52175 872117.27570 4730011.72622 11.80797 48.17153 528.99682 -2.77411 4.02156 4.40617 -0.96115 0.42550 -4.58937 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.24856 872118.10446 4730013.56436 11.80797 48.17153 532.25964 -2.52088 3.13217 7.66899 -0.70792 -0.46389 -1.32655 7 3 4 2.38 -2013-Sep-20 09:11:33 4171695.03155 872118.08511 4730015.18106 11.80797 48.17153 533.97281 -2.70004 3.64222 9.38215 -0.88708 0.04616 0.38662 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.44460 872119.92811 4730015.27935 11.80800 48.17153 533.91440 -0.77593 3.85485 9.32375 1.03703 0.25879 0.32821 7 3 4 2.38 -2013-Sep-20 09:11:33 4171692.51924 872117.20533 4730012.79137 11.80796 48.17153 530.43206 -3.04711 4.01510 5.84141 -1.23415 0.41904 -3.15413 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.14532 872118.05045 4730014.36843 11.80797 48.17153 532.78402 -2.55262 3.75195 8.19337 -0.73966 0.15589 -0.80217 7 3 4 2.38 -2013-Sep-20 09:11:33 4171694.60358 872119.09435 4730015.78673 11.80798 48.17154 534.28247 -1.62459 4.20440 9.69182 0.18837 0.60834 0.69629 7 3 4 2.38 -2013-Sep-20 09:11:34 4171697.71712 872118.76036 4730018.49023 11.80797 48.17153 538.28388 -2.58864 3.78735 13.69322 -0.77567 0.19129 4.69769 7 3 4 2.38 -2013-Sep-20 09:11:34 4171698.50526 872120.06490 4730020.36119 11.80799 48.17154 540.37053 -1.47298 4.26134 15.77987 0.33998 0.66527 6.78434 7 3 4 2.38 -2013-Sep-20 09:11:34 4171700.01562 872119.60757 4730020.38900 11.80798 48.17153 541.31480 -2.22970 3.24800 16.72414 -0.41674 -0.34807 7.72861 7 3 4 2.38 -2013-Sep-20 09:11:34 4171703.02134 872119.88652 4730021.20011 11.80797 48.17151 543.91936 -2.57172 1.55410 19.32871 -0.75876 -2.04197 10.33317 7 3 4 2.38 -2013-Sep-20 09:11:34 4171700.68918 872119.11903 4730020.19398 11.80797 48.17152 541.54250 -2.84574 2.70115 16.95185 -1.03278 -0.89491 7.95631 7 3 4 2.38 -2013-Sep-20 09:11:34 4171695.91369 872118.29525 4730016.78767 11.80797 48.17153 535.77449 -2.67486 4.03822 11.18383 -0.86190 0.44215 2.18830 7 3 4 2.38 -2013-Sep-20 09:11:34 4171692.19223 872116.24494 4730011.91046 11.80795 48.17153 529.43112 -3.92026 3.81256 4.84047 -2.10730 0.21650 -4.15507 7 3 4 2.38 -2013-Sep-20 09:11:34 4171692.60351 872115.67836 4730012.42184 11.80794 48.17153 530.00333 -4.55901 3.94003 5.41268 -2.74605 0.34397 -3.58286 7 3 4 2.38 -2013-Sep-20 09:11:34 4171692.30553 872116.47974 4730011.77706 11.80796 48.17153 529.43772 -3.71361 3.60516 4.84707 -1.90065 0.00910 -4.14847 7 3 4 2.38 -2013-Sep-20 09:11:34 4171692.75250 872116.39083 4730014.49148 11.80795 48.17154 531.74001 -3.89211 5.10296 7.14935 -2.07915 1.50690 -1.84618 7 3 4 2.38 -2013-Sep-20 09:11:34 4171693.38938 872117.92347 4730014.57571 11.80797 48.17154 532.42768 -2.52222 4.46091 7.83702 -0.70926 0.86485 -1.15851 7 3 4 2.38 -2013-Sep-20 09:11:34 4171693.41935 872118.32627 4730013.77584 11.80798 48.17153 531.90619 -2.13408 3.84420 7.31554 -0.32112 0.24814 -1.67999 7 3 4 2.38 -2013-Sep-20 09:11:34 4171693.32380 872117.47642 4730014.12891 11.80797 48.17154 531.99093 -2.94639 4.27895 7.40027 -1.13343 0.68288 -1.59526 7 3 4 2.38 -2013-Sep-20 09:11:34 4171692.65694 872118.51198 4730013.90922 11.80798 48.17154 531.53323 -1.79628 4.46092 6.94258 0.01668 0.86486 -2.05296 7 3 4 2.38 -2013-Sep-20 09:11:34 4171691.90780 872118.74806 4730013.12016 11.80799 48.17154 530.48846 -1.41189 4.44509 5.89780 0.40106 0.84903 -3.09773 7 3 4 2.38 -2013-Sep-20 09:11:34 4171691.70153 872117.98405 4730014.60682 11.80798 48.17155 531.35731 -2.11753 5.70350 6.76666 -0.30458 2.10744 -2.22888 7 3 4 2.38 -2013-Sep-20 09:11:34 4171694.24309 872119.02442 4730017.39279 11.80798 48.17155 535.23435 -1.61927 5.54908 10.64369 0.19369 1.95302 1.64816 7 3 4 2.38 -2013-Sep-20 09:11:34 4171693.32101 872117.94897 4730015.87242 11.80797 48.17155 533.35276 -2.48327 5.37167 8.76210 -0.67031 1.77561 -0.23343 7 3 4 2.38 -2013-Sep-20 09:11:34 4171696.72265 872120.43472 4730018.33754 11.80800 48.17154 537.74942 -0.74620 4.15556 13.15877 1.06676 0.55950 4.16324 7 3 4 2.38 -2013-Sep-20 09:11:34 4171695.24415 872118.29192 4730016.16456 11.80797 48.17153 534.87266 -2.54111 4.11152 10.28200 -0.72815 0.51546 1.28647 7 3 4 2.38 -2013-Sep-20 09:11:34 4171697.46090 872121.11818 4730018.27307 11.80800 48.17153 538.27658 -0.22828 3.46990 13.68593 1.58469 -0.12617 4.69039 7 3 4 2.38 -2013-Sep-20 09:11:34 4171698.36143 872121.15813 4730019.08653 11.80800 48.17153 539.47604 -0.37345 3.34948 14.88538 1.43951 -0.24659 5.88985 7 3 4 2.38 -2013-Sep-20 09:11:34 4171698.97376 872121.73982 4730018.37301 11.80801 48.17152 539.42346 0.07062 2.33831 14.83281 1.88358 -1.25775 5.83728 7 3 4 2.38 -2013-Sep-20 09:11:34 4171695.05377 872118.90064 4730014.60167 11.80798 48.17153 533.66687 -1.90632 3.11526 9.07622 -0.09336 -0.48080 0.08068 7 3 4 2.38 -2013-Sep-20 09:11:34 4171693.98799 872119.37912 4730015.20478 11.80799 48.17154 533.48585 -1.21987 4.22187 8.89519 0.59309 0.62581 -0.10034 7 3 4 2.38 -2013-Sep-20 09:11:35 4171691.59768 872118.10163 4730013.07446 11.80798 48.17154 530.16374 -1.98119 4.73938 5.57308 -0.16823 1.14332 -3.42245 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.69617 872117.92132 4730012.70509 11.80797 48.17153 530.58098 -2.38247 3.71933 5.99033 -0.56951 0.12327 -3.00521 7 3 4 2.38 -2013-Sep-20 09:11:35 4171688.53303 872116.05191 4730008.85767 11.80796 48.17154 524.74133 -3.36041 4.47502 0.15067 -1.54745 0.87896 -8.84486 7 3 4 2.38 -2013-Sep-20 09:11:35 4171691.67697 872117.48426 4730012.70439 11.80797 48.17154 529.85549 -2.60172 4.52888 5.26483 -0.78876 0.93282 -3.73070 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.43862 872117.97018 4730014.46605 11.80797 48.17154 531.73169 -2.28194 5.07412 7.14103 -0.46898 1.47806 -1.85450 7 3 4 2.38 -2013-Sep-20 09:11:35 4171694.64348 872118.29297 4730016.79061 11.80797 48.17154 534.94719 -2.41717 4.96698 10.35653 -0.60421 1.37092 1.36100 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.44947 872117.08023 4730013.09106 11.80796 48.17154 530.59275 -3.15528 4.28492 6.00210 -1.34232 0.68886 -2.99343 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.69437 872116.96410 4730013.10921 11.80796 48.17153 530.75030 -3.31907 4.13611 6.15964 -1.50611 0.54005 -2.83589 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.00709 872116.98460 4730014.64964 11.80796 48.17155 531.45229 -3.15836 5.66159 6.86163 -1.34540 2.06552 -2.13390 7 3 4 2.38 -2013-Sep-20 09:11:35 4171693.38478 872118.56309 4730016.72597 11.80798 48.17155 534.11422 -1.89519 5.80075 9.52356 -0.08223 2.20469 0.52803 7 3 4 2.38 -2013-Sep-20 09:11:35 4171691.92834 872116.68487 4730015.17580 11.80796 48.17155 531.75205 -3.43563 6.11562 7.16139 -1.62268 2.51956 -1.83414 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.17088 872116.15307 4730016.47838 11.80795 48.17156 532.80841 -4.00581 6.88851 8.21775 -2.19285 3.29245 -0.77778 7 3 4 2.38 -2013-Sep-20 09:11:35 4171691.32198 872116.78377 4730013.64684 11.80796 48.17155 530.23042 -3.21475 5.52314 5.63976 -1.40179 1.92708 -3.35577 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.39347 872118.10994 4730015.52382 11.80798 48.17155 532.50948 -2.13590 5.79117 7.91883 -0.32294 2.19511 -1.07670 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.04443 872118.25264 4730015.06071 11.80798 48.17155 531.95602 -1.92479 5.71514 7.36537 -0.11183 2.11908 -1.63016 7 3 4 2.38 -2013-Sep-20 09:11:35 4171694.27706 872119.00306 4730015.56449 11.80798 48.17154 533.89126 -1.64712 4.30827 9.30060 0.16584 0.71220 0.30507 7 3 4 2.38 -2013-Sep-20 09:11:35 4171693.83391 872118.08116 4730015.68319 11.80797 48.17154 533.56462 -2.45884 4.85122 8.97396 -0.64588 1.25516 -0.02157 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.03784 872117.65284 4730014.08187 11.80797 48.17154 531.14049 -2.51055 5.15861 6.54983 -0.69760 1.56255 -2.44570 7 3 4 2.38 -2013-Sep-20 09:11:35 4171689.29288 872116.72334 4730011.77685 11.80797 48.17155 527.50418 -2.85867 5.76523 2.91352 -1.04571 2.16917 -6.08201 7 3 4 2.38 -2013-Sep-20 09:11:35 4171689.57005 872117.26138 4730012.39955 11.80797 48.17155 528.22254 -2.38874 5.89631 3.63189 -0.57578 2.30026 -5.36364 7 3 4 2.38 -2013-Sep-20 09:11:35 4171690.50515 872117.27741 4730012.22343 11.80797 48.17154 528.70393 -2.56440 5.09437 4.11327 -0.75144 1.49831 -4.88226 7 3 4 2.38 -2013-Sep-20 09:11:35 4171692.20620 872117.64868 4730014.79210 11.80797 48.17155 531.77905 -2.54908 5.51011 7.18840 -0.73612 1.91405 -1.80714 7 3 4 2.38 -2013-Sep-20 09:11:35 4171691.46176 872116.40297 4730014.09906 11.80796 48.17155 530.60667 -3.61609 5.78084 6.01602 -1.80313 2.18478 -2.97952 7 3 4 2.38 -2013-Sep-20 09:11:35 4171688.67955 872114.80607 4730010.46651 11.80794 48.17155 525.86577 -4.60986 5.63106 1.27511 -2.79690 2.03500 -7.72042 7 3 4 2.38 -2013-Sep-20 09:11:35 4171685.65827 872113.70093 4730005.62804 11.80794 48.17154 520.13733 -5.07336 4.77643 -4.45333 -3.26041 1.18037 -13.44886 7 3 4 2.38 -2013-Sep-20 09:11:36 4171687.42392 872115.84245 4730007.08054 11.80796 48.17153 522.66450 -3.33847 4.13074 -1.92616 -1.52552 0.53468 -10.92169 7 3 4 2.38 -2013-Sep-20 09:11:36 4171691.85291 872116.53905 4730011.65024 11.80796 48.17153 529.05585 -3.56293 3.84167 4.46519 -1.74998 0.24561 -4.53034 7 3 4 2.38 -2013-Sep-20 09:11:36 4171702.17441 872123.29327 4730015.12890 11.80802 48.17148 539.30748 0.93624 -2.39654 14.71683 2.74920 -5.99261 5.72129 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.34949 872123.48151 4730013.28926 11.80803 48.17148 536.77109 1.49394 -2.32106 12.18044 3.30690 -5.91712 3.18490 7 3 4 2.38 -2013-Sep-20 09:11:36 4171698.36269 872122.64152 4730011.34768 11.80802 48.17148 533.91274 1.07829 -2.03869 9.32208 2.89125 -5.63476 0.32654 7 3 4 2.38 -2013-Sep-20 09:11:36 4171696.60207 872121.53814 4730010.82027 11.80801 48.17149 532.21984 0.35854 -0.93803 7.62919 2.17150 -4.53409 -1.36635 7 3 4 2.38 -2013-Sep-20 09:11:36 4171697.57430 872122.02479 4730010.79413 11.80801 48.17148 532.90144 0.63594 -1.73879 8.31078 2.44890 -5.33485 -0.68475 7 3 4 2.38 -2013-Sep-20 09:11:36 4171696.69283 872121.57935 4730009.73856 11.80801 48.17148 531.47868 0.38030 -1.73190 6.88803 2.19326 -5.32796 -2.10751 7 3 4 2.38 -2013-Sep-20 09:11:36 4171703.24765 872124.67207 4730015.28909 11.80803 48.17147 540.31562 2.06625 -3.28275 15.72496 3.87921 -6.87882 6.72943 7 3 4 2.38 -2013-Sep-20 09:11:36 4171698.26339 872123.31328 4730011.79445 11.80803 48.17148 534.27249 1.75615 -1.77075 9.68184 3.56911 -5.36681 0.68630 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.81223 872123.77116 4730015.44258 11.80803 48.17149 538.71723 1.68277 -1.26668 14.12657 3.49573 -4.86274 5.13103 7 3 4 2.38 -2013-Sep-20 09:11:36 4171699.70693 872123.18767 4730014.44119 11.80802 48.17149 537.16989 1.33781 -1.03936 12.57923 3.15077 -4.63542 3.58370 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.16685 872123.40235 4730013.89245 11.80803 48.17148 537.09052 1.45383 -1.77351 12.49987 3.26679 -5.36957 3.50433 7 3 4 2.38 -2013-Sep-20 09:11:36 4171701.92191 872123.96064 4730015.45634 11.80803 48.17148 539.47772 1.64116 -2.09577 14.88707 3.45413 -5.69183 5.89153 7 3 4 2.38 -2013-Sep-20 09:11:36 4171703.21904 872122.72662 4730016.09006 11.80801 48.17148 540.62828 0.16782 -2.43107 16.03763 1.98078 -6.02713 7.04209 7 3 4 2.38 -2013-Sep-20 09:11:36 4171699.46488 872120.20662 4730011.84254 11.80799 48.17148 534.66868 -1.53063 -2.14131 10.07803 0.28233 -5.73737 1.08249 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.06437 872120.75578 4730013.49475 11.80799 48.17148 536.36610 -1.11577 -1.56043 11.77544 0.69720 -5.15650 2.77991 7 3 4 2.38 -2013-Sep-20 09:11:36 4171698.39779 872122.36705 4730012.19598 11.80802 48.17148 534.53029 0.80245 -1.45671 9.93964 2.61541 -5.05277 0.94410 7 3 4 2.38 -2013-Sep-20 09:11:36 4171698.10795 872122.13058 4730011.03036 11.80801 48.17148 533.44027 0.63029 -1.98661 8.84961 2.44325 -5.58267 -0.14593 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.57115 872121.69513 4730012.42067 11.80800 48.17147 536.02477 -0.29999 -2.78961 11.43412 1.51297 -6.38568 2.43858 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.93226 872123.28020 4730013.87904 11.80802 48.17148 537.56352 1.17763 -2.32209 12.97286 2.99059 -5.91815 3.97733 7 3 4 2.38 -2013-Sep-20 09:11:36 4171700.75112 872123.91081 4730014.83915 11.80803 48.17148 538.24674 1.83197 -1.64583 13.65609 3.64493 -5.24190 4.66055 7 3 4 2.38 -2013-Sep-20 09:11:36 4171699.17370 872122.97452 4730014.21297 11.80802 48.17149 536.62265 1.23828 -0.77014 12.03199 3.05124 -4.36620 3.03646 7 3 4 2.38 -2013-Sep-20 09:11:36 4171697.49318 872121.43767 4730013.31685 11.80801 48.17150 534.64815 0.07784 0.09232 10.05750 1.89081 -3.50374 1.06196 7 3 4 2.38 -2013-Sep-20 09:11:36 4171698.70603 872122.24915 4730016.39227 11.80801 48.17151 537.84226 0.62396 1.13496 13.25161 2.43692 -2.46110 4.25607 7 3 4 2.38 -2013-Sep-20 09:11:37 4171699.64980 872124.38108 4730017.70586 11.80804 48.17151 539.72811 2.51766 0.99756 15.13745 4.33062 -2.59851 6.14192 7 3 4 2.38 -2013-Sep-20 09:11:37 4171701.49619 872124.71381 4730018.21005 11.80804 48.17150 541.35452 2.46551 -0.06365 16.76386 4.27847 -3.65971 7.76833 7 3 4 2.38 -2013-Sep-20 09:11:37 4171698.10948 872121.94558 4730013.16343 11.80801 48.17149 535.00546 0.44889 -0.53696 10.41481 2.26185 -4.13303 1.41927 7 3 4 2.38 -2013-Sep-20 09:11:37 4171700.34254 872122.31617 4730013.71245 11.80801 48.17148 536.92285 0.35468 -1.85607 12.33220 2.16765 -5.45213 3.33666 7 3 4 2.38 -2013-Sep-20 09:11:37 4171697.29126 872120.77181 4730009.92721 11.80800 48.17148 531.89969 -0.53261 -1.91944 7.30904 1.28036 -5.51550 -1.68650 7 3 4 2.38 -2013-Sep-20 09:11:37 4171696.36468 872121.95418 4730012.70064 11.80802 48.17150 533.52280 0.81436 0.42570 8.93214 2.62732 -3.17036 -0.06339 7 3 4 2.38 -2013-Sep-20 09:11:37 4171693.52071 872120.35141 4730010.85368 11.80800 48.17151 530.07130 -0.17253 1.51267 5.48065 1.64043 -2.08338 -3.51489 7 3 4 2.38 -2013-Sep-20 09:11:37 4171694.21808 872119.87618 4730012.26684 11.80800 48.17152 531.51469 -0.78041 2.01894 6.92404 1.03255 -1.57712 -2.07149 7 3 4 2.38 -2013-Sep-20 09:11:37 4171699.64725 872121.47435 4730016.27362 11.80800 48.17150 538.26253 -0.32705 0.48747 13.67188 1.48592 -3.10859 4.67634 7 3 4 2.38 -2013-Sep-20 09:11:37 4171698.45869 872121.37156 4730013.69074 11.80800 48.17149 535.54801 -0.18444 -0.35247 10.95735 1.62852 -3.94854 1.96182 7 3 4 2.38 -2013-Sep-20 09:11:37 4171701.44532 872124.96146 4730017.51253 11.80804 48.17149 540.83535 2.71833 -0.52948 16.24470 4.53129 -4.12554 7.24916 7 3 4 2.38 -2013-Sep-20 09:11:37 4171702.43442 872123.59979 4730019.67027 11.80802 48.17150 542.90302 1.18308 0.39572 18.31237 2.99604 -3.20034 9.31683 7 3 4 2.38 -2013-Sep-20 09:11:37 4171702.96263 872122.89897 4730018.84735 11.80801 48.17149 542.53900 0.38899 -0.43148 17.94835 2.20195 -4.02755 8.95281 7 3 4 2.38 -2013-Sep-20 09:11:37 4171698.45328 872122.05874 4730015.58370 11.80801 48.17150 537.04878 0.48930 0.80911 12.45813 2.30226 -2.78696 3.46259 7 3 4 2.38 -2013-Sep-20 09:11:37 4171694.86074 872120.85417 4730011.98381 11.80801 48.17151 531.85678 0.04538 1.21232 7.26613 1.85834 -2.38374 -1.72940 7 3 4 2.38 -2013-Sep-20 09:11:37 4171698.16079 872123.11351 4730014.34445 11.80803 48.17150 536.07837 1.58161 0.03515 11.48772 3.39457 -3.56091 2.49218 7 3 4 2.38 -2013-Sep-20 09:11:37 4171697.67216 872122.75126 4730012.57389 11.80802 48.17149 534.39064 1.32701 -0.73402 9.79999 3.13997 -4.33008 0.80445 7 3 4 2.38 -2013-Sep-20 09:11:37 4171694.36918 872121.78246 4730010.44551 11.80802 48.17150 530.51632 1.05461 0.40340 5.92567 2.86757 -3.19266 -3.06987 7 3 4 2.38 -2013-Sep-20 09:11:37 4171697.53091 872123.01992 4730013.18609 11.80803 48.17150 534.79128 1.61889 -0.26367 10.20062 3.43185 -3.85973 1.20509 7 3 4 2.38 -2013-Sep-20 09:11:37 4171692.58084 872120.04686 4730007.38116 11.80800 48.17150 526.82867 -0.27831 -0.07120 2.23801 1.53465 -3.66726 -6.75752 7 3 4 2.38 -2013-Sep-20 09:11:37 4171697.22903 872123.06997 4730013.30691 11.80803 48.17150 534.69107 1.72966 0.02946 10.10042 3.54262 -3.56661 1.10488 7 3 4 2.38 -2013-Sep-20 09:11:37 4171702.00159 872124.81621 4730018.74878 11.80804 48.17150 542.09984 2.46232 -0.08861 17.50919 4.27528 -3.68467 8.51365 7 3 4 2.38 -2013-Sep-20 09:11:37 4171699.03849 872122.26550 4730014.44172 11.80801 48.17149 536.60808 0.57194 -0.41085 12.01742 2.38490 -4.00691 3.02189 7 3 4 2.38 -2013-Sep-20 09:11:37 4171698.33644 872122.90021 4730015.37846 11.80802 48.17150 536.93441 1.33687 0.62915 12.34376 3.14983 -2.96691 3.34822 7 3 4 2.38 -2013-Sep-20 09:11:37 4171696.92941 872120.61157 4730013.48427 11.80800 48.17150 534.29215 -0.61541 0.74113 9.70149 1.19755 -2.85493 0.70596 7 3 4 2.38 -2013-Sep-20 09:11:38 4171694.83003 872120.11307 4730012.00876 11.80800 48.17151 531.75419 -0.67375 1.36436 7.16353 1.13921 -2.23170 -1.83200 7 3 4 2.38 -2013-Sep-20 09:11:38 4171694.29561 872119.66756 4730012.90690 11.80799 48.17152 532.01377 -1.00048 2.42105 7.42311 0.81248 -1.17501 -1.57242 7 3 4 2.38 -2013-Sep-20 09:11:38 4171695.78459 872120.74693 4730014.06901 11.80800 48.17152 533.99900 -0.24865 1.94546 9.40834 1.56431 -1.65060 0.41281 7 3 4 2.38 -2013-Sep-20 09:11:38 4171695.17829 872121.34806 4730014.52255 11.80801 48.17152 534.02320 0.46383 2.59849 9.43255 2.27679 -0.99757 0.43701 7 3 4 2.38 -2013-Sep-20 09:11:38 4171695.80358 872122.35036 4730013.77441 11.80802 48.17151 534.01070 1.31697 1.49064 9.42004 3.12993 -2.10542 0.42451 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.41036 872121.69219 4730014.61764 11.80800 48.17149 536.90368 -0.06534 -0.47734 12.31303 1.74763 -4.07340 3.31749 7 3 4 2.38 -2013-Sep-20 09:11:38 4171700.28814 872122.43242 4730014.60054 11.80801 48.17149 537.56496 0.47960 -1.24185 12.97430 2.29256 -4.83791 3.97877 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.79749 872122.58613 4730014.21584 11.80802 48.17149 536.97899 0.73046 -1.16398 12.38834 2.54343 -4.76004 3.39280 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.66989 872122.71737 4730015.47941 11.80802 48.17150 537.85515 0.88504 -0.24824 13.26449 2.69800 -3.84431 4.26896 7 3 4 2.38 -2013-Sep-20 09:11:38 4171697.21377 872123.15776 4730014.82130 11.80803 48.17151 535.82153 1.81871 1.03715 11.23087 3.63167 -2.55892 2.23534 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.69550 872122.49414 4730015.72594 11.80801 48.17150 538.02510 0.66129 -0.06847 13.43445 2.47426 -3.66453 4.43891 7 3 4 2.38 -2013-Sep-20 09:11:38 4171697.25407 872120.78000 4730013.58386 11.80800 48.17150 534.60127 -0.51698 0.54507 10.01062 1.29598 -3.05099 1.01508 7 3 4 2.38 -2013-Sep-20 09:11:38 4171698.16324 872120.67313 4730016.30488 11.80799 48.17151 537.20774 -0.80763 1.71289 12.61709 1.00533 -1.88317 3.62155 7 3 4 2.38 -2013-Sep-20 09:11:38 4171697.97309 872120.26700 4730015.56609 11.80799 48.17151 536.47768 -1.16626 1.42081 11.88703 0.64670 -2.17525 2.89149 7 3 4 2.38 -2013-Sep-20 09:11:38 4171698.82470 872120.58311 4730015.21194 11.80799 48.17150 536.81285 -1.03111 0.51528 12.22219 0.78185 -3.08078 3.22666 7 3 4 2.38 -2013-Sep-20 09:11:38 4171694.43013 872119.04176 4730011.61351 11.80798 48.17151 531.05241 -1.64056 1.55579 6.46176 0.17240 -2.04027 -2.53378 7 3 4 2.38 -2013-Sep-20 09:11:38 4171695.84638 872119.56749 4730012.40505 11.80799 48.17151 532.63849 -1.41578 0.97053 8.04783 0.39718 -2.62553 -0.94770 7 3 4 2.38 -2013-Sep-20 09:11:38 4171697.41641 872119.98976 4730016.13799 11.80799 48.17152 536.50260 -1.32372 2.25051 11.91194 0.48924 -1.34555 2.91641 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.76849 872120.99660 4730019.67286 11.80799 48.17152 540.80940 -0.81950 2.73886 16.21875 0.99346 -0.85720 7.22322 7 3 4 2.38 -2013-Sep-20 09:11:38 4171694.59151 872118.85066 4730013.62077 11.80798 48.17152 532.62738 -1.86064 2.80588 8.03673 -0.04768 -0.79018 -0.95880 7 3 4 2.38 -2013-Sep-20 09:11:38 4171694.13454 872119.45492 4730012.78140 11.80799 48.17152 531.78609 -1.17566 2.48726 7.19543 0.63730 -1.10880 -1.80010 7 3 4 2.38 -2013-Sep-20 09:11:38 4171696.24993 872121.46734 4730014.67759 11.80801 48.17151 534.85456 0.36130 1.90207 10.26391 2.17426 -1.69400 1.26837 7 3 4 2.38 -2013-Sep-20 09:11:38 4171699.76420 872121.32297 4730017.51433 11.80800 48.17151 539.24273 -0.49915 1.25269 14.65208 1.31381 -2.34337 5.65654 7 3 4 2.38 -2013-Sep-20 09:11:38 4171698.01040 872122.58019 4730017.73545 11.80802 48.17152 538.43420 1.09035 2.48763 13.84354 2.90331 -1.10843 4.84801 7 3 4 2.38 -2013-Sep-20 09:11:38 4171697.67112 872121.11745 4730014.13566 11.80800 48.17150 535.33073 -0.27201 0.55742 10.74008 1.54095 -3.03864 1.74454 7 3 4 2.38 -2013-Sep-20 09:11:39 4171693.79715 872119.40079 4730011.39850 11.80799 48.17151 530.52799 -1.15961 1.81934 5.93734 0.65335 -1.77672 -3.05820 7 3 4 2.38 -2013-Sep-20 09:11:39 4171692.08147 872118.93678 4730010.56863 11.80799 48.17152 528.72632 -1.26271 2.58803 4.13566 0.55024 -1.00803 -4.85987 7 3 4 2.38 -2013-Sep-20 09:11:39 4171690.16639 872119.31617 4730010.17264 11.80800 48.17153 527.23288 -0.49946 3.66290 2.64223 1.31350 0.06685 -6.35331 7 3 4 2.38 -2013-Sep-20 09:11:39 4171692.21881 872119.84399 4730011.10044 11.80800 48.17152 529.33606 -0.40281 2.70419 4.74540 1.41015 -0.89187 -4.25013 7 3 4 2.38 -2013-Sep-20 09:11:39 4171691.87990 872117.85327 4730010.63123 11.80797 48.17152 528.49351 -2.28204 2.94201 3.90285 -0.46909 -0.65405 -5.09268 7 3 4 2.38 -2013-Sep-20 09:11:39 4171696.55132 872119.18229 4730014.96199 11.80798 48.17152 534.95139 -1.93707 2.22034 10.36073 -0.12411 -1.37572 1.36520 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.05237 872118.76362 4730013.87209 11.80798 48.17152 533.10361 -2.04015 2.65062 8.51296 -0.22719 -0.94545 -0.48258 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.87467 872119.95571 4730014.95823 11.80799 48.17152 534.61243 -1.04156 2.59343 10.02177 0.77140 -1.00263 1.02624 7 3 4 2.38 -2013-Sep-20 09:11:39 4171694.16429 872117.99137 4730012.43457 11.80797 48.17152 531.34734 -2.61433 2.45743 6.75668 -0.80137 -1.13863 -2.23885 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.76512 872119.78539 4730014.68413 11.80799 48.17152 534.31342 -1.18585 2.51651 9.72277 0.62711 -1.07955 0.72724 7 3 4 2.38 -2013-Sep-20 09:11:39 4171696.20366 872119.20794 4730013.69935 11.80798 48.17151 533.78709 -1.84083 1.62794 9.19644 -0.02787 -1.96813 0.20090 7 3 4 2.38 -2013-Sep-20 09:11:39 4171698.78340 872120.28432 4730018.09366 11.80799 48.17152 538.89241 -1.31512 2.51279 14.30176 0.49784 -1.08328 5.30622 7 3 4 2.38 -2013-Sep-20 09:11:39 4171693.86027 872118.25440 4730012.53331 11.80797 48.17152 531.25835 -2.29466 2.70491 6.66769 -0.48170 -0.89115 -2.32784 7 3 4 2.38 -2013-Sep-20 09:11:39 4171694.06245 872118.48650 4730013.59975 11.80798 48.17153 532.21666 -2.10883 3.23327 7.62600 -0.29587 -0.36279 -1.36953 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.31115 872119.04283 4730015.42568 11.80798 48.17153 534.46830 -1.81980 3.45539 9.87764 -0.00684 -0.14067 0.88211 7 3 4 2.38 -2013-Sep-20 09:11:39 4171693.04180 872118.02664 4730012.21014 11.80797 48.17153 530.45217 -2.35010 3.12109 5.86151 -0.53714 -0.47497 -3.13402 7 3 4 2.38 -2013-Sep-20 09:11:39 4171692.17508 872118.54262 4730012.68151 11.80798 48.17153 530.30803 -1.66769 3.98894 5.71738 0.14527 0.39288 -3.27816 7 3 4 2.38 -2013-Sep-20 09:11:39 4171694.61132 872119.91889 4730015.43289 11.80799 48.17153 534.13639 -0.81908 3.83706 9.54573 0.99388 0.24100 0.55020 7 3 4 2.38 -2013-Sep-20 09:11:39 4171696.15203 872119.93442 4730016.20250 11.80799 48.17153 535.71774 -1.11915 3.22418 11.12709 0.69381 -0.37188 2.13155 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.44371 872117.84380 4730014.88587 11.80797 48.17153 533.98897 -3.02059 3.18153 9.39831 -1.20763 -0.41453 0.40278 7 3 4 2.38 -2013-Sep-20 09:11:39 4171696.30208 872118.95604 4730014.86039 11.80798 48.17152 534.68210 -2.10753 2.36886 10.09145 -0.29457 -1.22720 1.09592 7 3 4 2.38 -2013-Sep-20 09:11:39 4171698.60622 872120.97748 4730017.56997 11.80800 48.17152 538.48111 -0.60038 2.18708 13.89046 1.21259 -1.40898 4.89493 7 3 4 2.38 -2013-Sep-20 09:11:39 4171697.45801 872118.92845 4730016.51467 11.80797 48.17152 536.66559 -2.37108 2.63321 12.07494 -0.55812 -0.96286 3.07941 7 3 4 2.38 -2013-Sep-20 09:11:39 4171695.72625 872119.64693 4730013.85104 11.80799 48.17152 533.64838 -1.31343 2.01038 9.05773 0.49953 -1.58568 0.06219 7 3 4 2.38 -2013-Sep-20 09:11:39 4171696.32005 872120.51919 4730013.86689 11.80800 48.17151 534.16686 -0.58114 1.45484 9.57620 1.23182 -2.14122 0.58067 7 3 4 2.38 -2013-Sep-20 09:11:40 4171695.33687 872118.75088 4730013.43363 11.80798 48.17152 532.96088 -2.11084 2.15264 8.37023 -0.29788 -1.44342 -0.62531 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.68260 872118.20552 4730014.53494 11.80797 48.17153 533.27999 -2.51078 3.44747 8.68934 -0.69782 -0.14859 -0.30620 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.06620 872117.71535 4730014.07924 11.80797 48.17153 532.47115 -2.86444 3.66789 7.88050 -1.05148 0.07183 -1.11503 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.39674 872117.51677 4730014.24135 11.80796 48.17153 532.78062 -3.12645 3.56520 8.18997 -1.31350 -0.03086 -0.80557 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.80846 872118.27311 4730015.16754 11.80797 48.17153 533.84276 -2.47036 3.76725 9.25210 -0.65740 0.17119 0.25657 7 3 4 2.38 -2013-Sep-20 09:11:40 4171693.79398 872118.40667 4730015.70730 11.80798 48.17154 533.60094 -2.13204 4.84680 9.01028 -0.31908 1.25073 0.01475 7 3 4 2.38 -2013-Sep-20 09:11:40 4171691.52330 872117.94043 4730013.40438 11.80798 48.17154 530.33902 -2.12376 5.03824 5.74836 -0.31080 1.44218 -3.24717 7 3 4 2.38 -2013-Sep-20 09:11:40 4171687.46651 872116.76168 4730010.21652 11.80797 48.17155 525.15451 -2.44741 6.05091 0.56385 -0.63445 2.45486 -8.43168 7 3 4 2.38 -2013-Sep-20 09:11:40 4171688.87934 872117.39717 4730010.33489 11.80798 48.17154 526.25172 -2.11448 5.00247 1.66106 -0.30152 1.40641 -7.33447 7 3 4 2.38 -2013-Sep-20 09:11:40 4171691.57456 872117.85122 4730012.30358 11.80798 48.17154 529.54006 -2.22157 4.28033 4.94940 -0.40861 0.68427 -4.04613 7 3 4 2.38 -2013-Sep-20 09:11:40 4171692.99793 872119.69936 4730013.52572 11.80800 48.17153 531.63210 -0.70381 3.77540 7.04145 1.10915 0.17934 -1.95409 7 3 4 2.38 -2013-Sep-20 09:11:40 4171695.73595 872119.86307 4730015.18328 11.80799 48.17152 534.67692 -1.10385 2.85882 10.08627 0.70911 -0.73724 1.09073 7 3 4 2.38 -2013-Sep-20 09:11:40 4171697.73933 872120.51530 4730018.24373 11.80799 48.17153 538.35420 -0.87538 3.33917 13.76355 0.93758 -0.25689 4.76801 7 3 4 2.38 -2013-Sep-20 09:11:40 4171698.66937 872121.08516 4730017.61373 11.80800 48.17152 538.56965 -0.50790 2.15379 13.97899 1.30507 -1.44228 4.98346 7 3 4 2.38 -2013-Sep-20 09:11:40 4171699.90232 872120.94129 4730018.61923 11.80799 48.17152 540.10411 -0.90102 1.94701 15.51346 0.91194 -1.64906 6.51792 7 3 4 2.38 -2013-Sep-20 09:11:40 4171695.14191 872119.32307 4730013.24628 11.80799 48.17152 532.77210 -1.51086 2.08265 8.18145 0.30210 -1.51341 -0.81409 7 3 4 2.38 -2013-Sep-20 09:11:40 4171693.83963 872117.89918 4730011.28914 11.80797 48.17152 530.26931 -2.63813 1.94439 5.67866 -0.82517 -1.65167 -3.31688 7 3 4 2.38 -2013-Sep-20 09:11:40 4171693.45120 872117.75738 4730012.00099 11.80797 48.17152 530.52683 -2.69744 2.72405 5.93617 -0.88449 -0.87201 -3.05936 7 3 4 2.38 -2013-Sep-20 09:11:40 4171696.17673 872119.11094 4730016.47948 11.80798 48.17153 535.82787 -1.93026 3.51645 11.23721 -0.11730 -0.07961 2.24168 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.28757 872118.42380 4730013.85877 11.80798 48.17153 532.54806 -2.21628 3.25137 7.95741 -0.40332 -0.34469 -1.03812 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.33180 872119.00660 4730017.03950 11.80798 48.17154 535.02657 -1.65486 5.25149 10.43592 0.15810 1.65543 1.44039 7 3 4 2.38 -2013-Sep-20 09:11:40 4171696.78354 872119.58199 4730017.33727 11.80798 48.17153 536.92745 -1.59335 3.57409 12.33679 0.21961 -0.02197 3.34126 7 3 4 2.38 -2013-Sep-20 09:11:40 4171695.68705 872119.92995 4730014.88622 11.80799 48.17152 534.43277 -1.02838 2.68618 9.84212 0.78458 -0.90989 0.84658 7 3 4 2.38 -2013-Sep-20 09:11:40 4171694.22509 872117.83827 4730013.24941 11.80797 48.17152 531.97331 -2.77663 2.97985 7.38266 -0.96367 -0.61622 -1.61287 7 3 4 2.38 -2013-Sep-20 09:11:40 4171689.96012 872116.83412 4730008.65859 11.80797 48.17153 525.63132 -2.88678 3.18209 1.04066 -1.07382 -0.41396 -7.95487 7 3 4 2.38 -2013-Sep-20 09:11:41 4171691.38027 872116.65118 4730010.70121 11.80796 48.17153 528.05545 -3.35645 3.53639 3.46480 -1.54350 -0.05967 -5.53073 7 3 4 2.38 -2013-Sep-20 09:11:41 4171694.48496 872118.35256 4730014.77576 11.80797 48.17153 533.35049 -2.32640 3.72981 8.75983 -0.51344 0.13375 -0.23570 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.15594 872119.22320 4730014.74376 11.80798 48.17153 533.88346 -1.61149 3.08631 9.29281 0.20147 -0.50975 0.29728 7 3 4 2.38 -2013-Sep-20 09:11:41 4171694.36281 872118.11227 4730012.24363 11.80797 48.17152 531.35115 -2.53661 2.16685 6.76050 -0.72365 -1.42921 -2.23504 7 3 4 2.38 -2013-Sep-20 09:11:41 4171697.55286 872117.95070 4730015.08511 11.80796 48.17151 535.52886 -3.34756 1.75974 10.93820 -1.53459 -1.83632 1.94267 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.39658 872118.61666 4730013.68242 11.80798 48.17152 533.16693 -2.25444 2.29548 8.57627 -0.44148 -1.30059 -0.41926 7 3 4 2.38 -2013-Sep-20 09:11:41 4171696.61744 872118.19582 4730016.00506 11.80797 48.17152 535.63716 -2.91620 3.01815 11.04651 -1.10324 -0.57791 2.05097 7 3 4 2.38 -2013-Sep-20 09:11:41 4171697.99483 872117.76112 4730017.54330 11.80796 48.17153 537.62320 -3.62356 3.10565 13.03255 -1.81060 -0.49041 4.03701 7 3 4 2.38 -2013-Sep-20 09:11:41 4171697.22129 872118.55258 4730015.78005 11.80797 48.17152 535.91237 -2.69055 2.37326 11.32171 -0.87759 -1.22280 2.32618 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.01079 872117.79503 4730017.05893 11.80797 48.17154 535.31895 -2.97973 4.95395 10.72829 -1.16677 1.35788 1.73276 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.93041 872119.29437 4730016.21431 11.80798 48.17153 535.49452 -1.70031 3.49130 10.90386 0.11265 -0.10476 1.90833 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.56906 872119.77451 4730017.03642 11.80799 48.17154 535.93675 -1.15638 4.22991 11.34609 0.65658 0.63385 2.35056 7 3 4 2.38 -2013-Sep-20 09:11:41 4171693.12963 872118.09894 4730014.50123 11.80797 48.17154 532.22656 -2.29731 4.57394 7.63590 -0.48435 0.97788 -1.35963 7 3 4 2.38 -2013-Sep-20 09:11:41 4171696.52198 872120.82464 4730016.38005 11.80800 48.17152 536.21302 -0.32347 2.93702 11.62237 1.48949 -0.65904 2.62684 7 3 4 2.38 -2013-Sep-20 09:11:41 4171691.34314 872119.34149 4730010.42458 11.80800 48.17152 528.19223 -0.71548 2.96876 3.60158 1.09748 -0.62729 -5.39395 7 3 4 2.38 -2013-Sep-20 09:11:41 4171690.38503 872117.03700 4730009.77749 11.80797 48.17153 526.77012 -2.77514 3.58744 2.17947 -0.96218 -0.00862 -6.81607 7 3 4 2.38 -2013-Sep-20 09:11:41 4171689.38901 872116.05489 4730009.12805 11.80796 48.17153 525.50198 -3.53265 4.03055 0.91132 -1.71970 0.43450 -8.08421 7 3 4 2.38 -2013-Sep-20 09:11:41 4171692.10762 872115.88953 4730012.13024 11.80795 48.17153 529.49116 -4.25083 4.07504 4.90050 -2.43787 0.47898 -4.09503 7 3 4 2.38 -2013-Sep-20 09:11:41 4171693.73028 872116.71035 4730012.32584 11.80795 48.17152 530.80818 -3.77943 2.89680 6.21752 -1.96647 -0.69926 -2.77801 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.88788 872117.94738 4730015.89837 11.80797 48.17153 535.04751 -3.01009 3.51701 10.45686 -1.19713 -0.07906 1.46132 7 3 4 2.38 -2013-Sep-20 09:11:41 4171696.59137 872116.51166 4730015.39974 11.80794 48.17152 534.93926 -4.55938 2.89029 10.34860 -2.74642 -0.70578 1.35307 7 3 4 2.38 -2013-Sep-20 09:11:41 4171694.75802 872117.46824 4730015.97118 11.80796 48.17154 534.29881 -3.24789 4.46272 9.70816 -1.43493 0.86665 0.71262 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.06116 872118.25049 4730016.81629 11.80797 48.17154 535.23318 -2.54422 4.68594 10.64252 -0.73126 1.08988 1.64699 7 3 4 2.38 -2013-Sep-20 09:11:41 4171695.29744 872117.66510 4730016.27334 11.80796 48.17154 534.90296 -3.16558 4.24077 10.31230 -1.35262 0.64471 1.31677 7 3 4 2.38 -2013-Sep-20 09:11:41 4171692.03997 872115.19745 4730012.67715 11.80794 48.17154 529.76008 -4.91442 4.59465 5.16942 -3.10146 0.99859 -3.82611 7 3 4 2.38 -2013-Sep-20 09:11:42 4171691.69622 872114.23758 4730012.73861 11.80793 48.17154 529.45048 -5.78363 5.03273 4.85982 -3.97067 1.43667 -4.13571 7 3 4 2.38 -2013-Sep-20 09:11:42 4171695.00838 872115.54893 4730015.26337 11.80794 48.17153 533.67290 -5.17781 4.10073 9.08224 -3.36485 0.50467 0.08671 7 3 4 2.38 -2013-Sep-20 09:11:42 4171699.50719 872122.00144 4730017.06109 11.80801 48.17151 538.82981 0.21755 1.03442 14.23916 2.03051 -2.56164 5.24362 7 3 4 2.38 -2013-Sep-20 09:11:42 4171700.05510 872123.05700 4730014.20350 11.80802 48.17148 537.20222 1.13865 -1.43190 12.61157 2.95161 -5.02796 3.61603 7 3 4 2.38 -2013-Sep-20 09:11:42 4171702.86397 872123.27704 4730016.61287 11.80802 48.17148 540.86118 0.77925 -1.90735 16.27053 2.59221 -5.50342 7.27499 7 3 4 2.38 -2013-Sep-20 09:11:42 4171702.46330 872123.85432 4730016.19581 11.80802 48.17148 540.36764 1.42631 -1.98128 15.77699 3.23927 -5.57735 6.78145 7 3 4 2.38 -2013-Sep-20 09:11:42 4171702.92321 872124.25454 4730017.67412 11.80803 48.17149 541.82404 1.72394 -1.39186 17.23339 3.53691 -4.98793 8.23785 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.55279 872121.74361 4730012.80693 11.80801 48.17149 535.00164 0.16048 -1.06726 10.41099 1.97344 -4.66332 1.41545 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.56858 872122.85636 4730014.22743 11.80802 48.17149 536.22229 1.24645 -0.30111 11.63163 3.05941 -3.89718 2.63610 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.63660 872122.01350 4730013.73672 11.80801 48.17149 535.78601 0.40750 -0.54946 11.19536 2.22047 -4.14552 2.19982 7 3 4 2.38 -2013-Sep-20 09:11:42 4171695.47402 872120.96570 4730010.91597 11.80801 48.17150 531.47665 0.02905 0.03585 6.88600 1.84201 -3.56021 -2.10954 7 3 4 2.38 -2013-Sep-20 09:11:42 4171699.36836 872123.58556 4730014.99974 11.80803 48.17149 537.41937 1.79656 -0.48059 12.82872 3.60952 -4.07665 3.83318 7 3 4 2.38 -2013-Sep-20 09:11:42 4171697.58076 872122.67576 4730013.87027 11.80802 48.17150 535.28666 1.27181 0.20873 10.69601 3.08478 -3.38733 1.70047 7 3 4 2.38 -2013-Sep-20 09:11:42 4171696.03990 872120.80185 4730012.23244 11.80800 48.17150 532.80465 -0.24713 0.52606 8.21399 1.56583 -3.07000 -0.78154 7 3 4 2.38 -2013-Sep-20 09:11:42 4171694.05788 872120.73886 4730009.97158 11.80801 48.17150 529.81754 0.09680 0.47353 5.22689 1.90976 -3.12253 -3.76865 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.53561 872123.88715 4730014.99414 11.80804 48.17150 536.91274 2.26217 0.07708 12.32209 4.07513 -3.51898 3.32655 7 3 4 2.38 -2013-Sep-20 09:11:42 4171695.42063 872120.97375 4730009.95379 11.80801 48.17149 530.72593 0.04785 -0.56811 6.13528 1.86081 -4.16417 -2.86026 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.07027 872120.71496 4730013.70568 11.80800 48.17150 535.21598 -0.74767 0.04091 10.62532 1.06529 -3.55515 1.62979 7 3 4 2.38 -2013-Sep-20 09:11:42 4171701.26008 872121.99655 4730019.84528 11.80800 48.17151 542.04805 -0.14594 1.61344 17.45739 1.66703 -1.98263 8.46186 7 3 4 2.38 -2013-Sep-20 09:11:42 4171699.49519 872120.46778 4730015.50319 11.80799 48.17150 537.45182 -1.28120 0.23806 12.86117 0.53177 -3.35801 3.86564 7 3 4 2.38 -2013-Sep-20 09:11:42 4171697.62291 872119.52208 4730012.74119 11.80798 48.17150 534.04247 -1.82376 -0.09413 9.45181 -0.01080 -3.69019 0.45628 7 3 4 2.38 -2013-Sep-20 09:11:42 4171694.62236 872117.78011 4730012.59924 11.80797 48.17152 531.74024 -2.91485 2.26535 7.14958 -1.10190 -1.33071 -1.84595 7 3 4 2.38 -2013-Sep-20 09:11:42 4171693.65536 872120.88448 4730012.01297 11.80801 48.17152 531.09578 0.32171 2.10632 6.50513 2.13467 -1.48974 -2.49041 7 3 4 2.38 -2013-Sep-20 09:11:42 4171698.21532 872121.54179 4730013.42874 11.80801 48.17149 535.21714 0.03199 -0.37566 10.62649 1.84495 -3.97172 1.63095 7 3 4 2.38 -2013-Sep-20 09:11:42 4171697.70221 872121.88561 4730014.48438 11.80801 48.17150 535.71571 0.47353 0.65018 11.12506 2.28649 -2.94588 2.12952 7 3 4 2.38 -2013-Sep-20 09:11:43 4171698.97632 872123.21397 4730017.21291 11.80803 48.17151 538.76187 1.51305 1.33799 14.17122 3.32602 -2.25808 5.17568 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.85572 872122.71205 4730013.22186 11.80803 48.17150 534.33515 1.45570 0.29960 9.74450 3.26866 -3.29646 0.74896 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.42934 872121.11511 4730013.79256 11.80801 48.17151 534.26414 -0.02019 1.23469 9.67348 1.79277 -2.36137 0.67795 7 3 4 2.38 -2013-Sep-20 09:11:43 4171698.56946 872121.85359 4730017.01072 11.80801 48.17151 538.15996 0.26472 1.70734 13.56931 2.07768 -1.88873 4.57377 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.55399 872121.21738 4730013.93058 11.80801 48.17151 534.46232 0.05440 1.22023 9.87166 1.86736 -2.37584 0.87613 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.31907 872121.98156 4730013.79148 11.80802 48.17151 534.30960 0.85049 1.18228 9.71894 2.66345 -2.41378 0.72341 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.80005 872123.09704 4730014.63144 11.80803 48.17151 535.40169 1.84394 1.22155 10.81104 3.65690 -2.37451 1.81550 7 3 4 2.38 -2013-Sep-20 09:11:43 4171693.03799 872122.24869 4730010.30908 11.80803 48.17151 529.60930 1.78338 1.21226 5.01864 3.59634 -2.38380 -3.97689 7 3 4 2.38 -2013-Sep-20 09:11:43 4171693.81796 872120.83701 4730010.44067 11.80801 48.17151 530.02385 0.24197 0.94639 5.43320 2.05493 -2.64967 -3.56233 7 3 4 2.38 -2013-Sep-20 09:11:43 4171694.21596 872120.72049 4730010.56374 11.80801 48.17150 530.35948 0.04647 0.75594 5.76882 1.85943 -2.84012 -3.22671 7 3 4 2.38 -2013-Sep-20 09:11:43 4171692.16679 872119.68621 4730009.92033 11.80800 48.17152 528.40121 -0.54660 1.97917 3.81056 1.26636 -1.61689 -5.18498 7 3 4 2.38 -2013-Sep-20 09:11:43 4171692.27281 872120.21499 4730009.08908 11.80800 48.17151 527.92318 -0.05070 1.26685 3.33253 1.76226 -2.32921 -5.66301 7 3 4 2.38 -2013-Sep-20 09:11:43 4171695.36635 872121.38607 4730012.84612 11.80801 48.17151 532.90197 0.46255 1.33751 8.31132 2.27551 -2.25855 -0.68422 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.26085 872123.52719 4730014.68452 11.80804 48.17151 535.14796 2.37532 1.58464 10.55731 4.18828 -2.01142 1.56177 7 3 4 2.38 -2013-Sep-20 09:11:43 4171697.76869 872122.52374 4730015.07427 11.80802 48.17151 536.28575 1.08456 0.89779 11.69510 2.89752 -2.69828 2.69956 7 3 4 2.38 -2013-Sep-20 09:11:43 4171700.38135 872122.61149 4730017.36812 11.80801 48.17150 539.71249 0.63581 0.50857 15.12184 2.44878 -3.08749 6.12630 7 3 4 2.38 -2013-Sep-20 09:11:43 4171698.41908 872121.91985 4730015.78451 11.80801 48.17151 537.15713 0.36035 0.98915 12.56648 2.17331 -2.60691 3.57094 7 3 4 2.38 -2013-Sep-20 09:11:43 4171697.57350 872121.72657 4730015.50262 11.80801 48.17151 536.36872 0.34419 1.44738 11.77806 2.15715 -2.14869 2.78253 7 3 4 2.38 -2013-Sep-20 09:11:43 4171697.19139 872121.37009 4730014.50789 11.80801 48.17151 535.32942 0.07345 1.11704 10.73876 1.88641 -2.47902 1.74323 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.55256 872120.62970 4730012.92228 11.80800 48.17150 533.62984 -0.52055 0.63844 9.03919 1.29241 -2.95762 0.04366 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.00737 872121.68610 4730013.47920 11.80801 48.17151 533.83310 0.62506 1.24642 9.24245 2.43802 -2.34964 0.24691 7 3 4 2.38 -2013-Sep-20 09:11:43 4171698.02769 872122.71453 4730016.32578 11.80802 48.17151 537.41342 1.21831 1.51442 12.82276 3.03127 -2.08164 3.82723 7 3 4 2.38 -2013-Sep-20 09:11:43 4171695.51216 872121.87054 4730013.65028 11.80802 48.17151 533.66248 0.90693 1.69358 9.07183 2.71989 -1.90248 0.07630 7 3 4 2.38 -2013-Sep-20 09:11:43 4171694.11996 872121.87562 4730013.28058 11.80802 48.17152 532.47889 1.19679 2.46169 7.88823 3.00975 -1.13437 -1.10730 7 3 4 2.38 -2013-Sep-20 09:11:43 4171696.32565 872122.41884 4730016.65483 11.80802 48.17152 536.50717 1.27716 3.02038 11.91652 3.09012 -0.57568 2.92098 7 3 4 2.38 -2013-Sep-20 09:11:44 4171701.72617 872123.74264 4730020.76439 11.80803 48.17151 543.27546 1.46783 1.62019 18.68481 3.28079 -1.97587 9.68927 7 3 4 2.38 -2013-Sep-20 09:11:44 4171699.69382 872123.25741 4730017.85349 11.80802 48.17151 539.71350 1.40876 1.23524 15.12284 3.22172 -2.36082 6.12731 7 3 4 2.38 -2013-Sep-20 09:11:44 4171699.96868 872123.80145 4730018.80916 11.80803 48.17151 540.67928 1.88503 1.58915 16.08862 3.69800 -2.00692 7.09309 7 3 4 2.38 -2013-Sep-20 09:11:44 4171698.46443 872122.88125 4730017.60887 11.80802 48.17152 538.67736 1.29212 2.02615 14.08670 3.10509 -1.56992 5.09117 7 3 4 2.38 -2013-Sep-20 09:11:44 4171699.82504 872121.57159 4730018.33994 11.80800 48.17151 539.93157 -0.26825 1.72100 15.34092 1.54471 -1.87506 6.34538 7 3 4 2.38 -2013-Sep-20 09:11:44 4171700.84983 872122.18664 4730018.04104 11.80801 48.17150 540.46176 0.12408 0.68043 15.87110 1.93704 -2.91564 6.87557 7 3 4 2.38 -2013-Sep-20 09:11:44 4171700.02603 872122.20930 4730017.32739 11.80801 48.17150 539.39531 0.31484 0.80189 14.80465 2.12780 -2.79417 5.80912 7 3 4 2.38 -2013-Sep-20 09:11:44 4171700.88321 872123.24985 4730018.35492 11.80802 48.17150 540.86252 1.15796 0.70329 16.27187 2.97093 -2.89277 7.27633 7 3 4 2.38 -2013-Sep-20 09:11:44 4171699.83229 872121.74728 4730019.16219 11.80800 48.17152 540.57298 -0.09775 2.23729 15.98232 1.71521 -1.35877 6.98679 7 3 4 2.38 -2013-Sep-20 09:11:44 4171700.22968 872121.74100 4730019.46993 11.80800 48.17152 541.06084 -0.18523 2.15363 16.47019 1.62774 -1.44243 7.47465 7 3 4 2.38 -2013-Sep-20 09:11:44 4171697.28353 872121.38206 4730016.80158 11.80801 48.17152 537.10033 0.06631 2.57768 12.50967 1.87927 -1.01838 3.51414 7 3 4 2.38 -2013-Sep-20 09:11:44 4171696.66765 872122.03823 4730016.49416 11.80802 48.17152 536.55877 0.83462 2.72182 11.96811 2.64758 -0.87424 2.97258 7 3 4 2.38 -2013-Sep-20 09:11:44 4171693.19642 872120.51544 4730014.10717 11.80801 48.17153 532.30631 0.05439 3.89396 7.71565 1.86734 0.29790 -1.27988 7 3 4 2.38 -2013-Sep-20 09:11:44 4171692.61581 872119.70169 4730012.42552 11.80800 48.17153 530.56317 -0.62333 3.32002 5.97252 1.18963 -0.27604 -3.02302 7 3 4 2.38 -2013-Sep-20 09:11:44 4171697.69682 872121.49580 4730017.11493 11.80801 48.17152 537.61914 0.09307 2.46787 13.02848 1.90603 -1.12819 4.03295 7 3 4 2.38 -2013-Sep-20 09:11:44 4171698.44362 872120.94650 4730015.41258 11.80800 48.17151 536.76318 -0.59743 0.87163 12.17253 1.21553 -2.72444 3.17700 7 3 4 2.38 -2013-Sep-20 09:11:44 4171697.33366 872119.76933 4730013.73028 11.80799 48.17150 534.62440 -1.52255 0.73877 10.03375 0.29041 -2.85729 1.03821 7 3 4 2.38 -2013-Sep-20 09:11:44 4171694.84682 872118.06826 4730012.21083 11.80797 48.17151 531.63666 -2.67873 1.79867 7.04600 -0.86578 -1.79739 -1.94953 7 3 4 2.38 -2013-Sep-20 09:11:44 4171698.92932 872121.20174 4730017.61631 11.80800 48.17152 538.75717 -0.44698 1.94812 14.16651 1.36598 -1.64794 5.17098 7 3 4 2.38 -2013-Sep-20 09:11:44 4171697.31480 872120.42952 4730013.96343 11.80799 48.17150 534.87592 -0.87247 0.80734 10.28527 0.94049 -2.78872 1.28973 7 3 4 2.38 -2013-Sep-20 09:11:44 4171695.54700 872119.09827 4730011.73559 11.80798 48.17151 531.88018 -1.81379 0.81398 7.28952 -0.00083 -2.78208 -1.70601 7 3 4 2.38 -2013-Sep-20 09:11:44 4171695.92415 872119.30021 4730011.71264 11.80798 48.17150 532.13684 -1.69331 0.49279 7.54618 0.11965 -3.10327 -1.44935 7 3 4 2.38 -2013-Sep-20 09:11:44 4171696.75421 872120.61532 4730012.83664 11.80800 48.17150 533.69571 -0.57588 0.43644 9.10506 1.23708 -3.15962 0.10952 7 3 4 2.38 -2013-Sep-20 09:11:44 4171697.18058 872119.80199 4730015.06296 11.80799 48.17151 535.52198 -1.45926 1.73421 10.93132 0.35370 -1.86185 1.93579 7 3 4 2.38 -2013-Sep-20 09:11:44 4171695.47432 872118.56029 4730015.20119 11.80797 48.17153 534.34169 -2.32552 3.26025 9.75103 -0.51256 -0.33582 0.75550 7 3 4 2.38 -2013-Sep-20 09:11:45 4171696.92106 872118.97485 4730014.38560 11.80798 48.17151 534.73494 -2.21579 1.59789 10.14429 -0.40283 -1.99818 1.14876 7 3 4 2.38 -2013-Sep-20 09:11:45 4171700.65103 872119.72245 4730018.41479 11.80798 48.17151 540.27419 -2.24728 1.45042 15.68353 -0.43432 -2.14564 6.68800 7 3 4 2.38 -2013-Sep-20 09:11:45 4171699.00412 872118.91495 4730015.80963 11.80797 48.17151 537.14768 -2.70068 1.03738 12.55703 -0.88772 -2.55868 3.56149 7 3 4 2.38 -2013-Sep-20 09:11:45 4171695.14395 872117.65192 4730012.45209 11.80796 48.17151 531.95358 -3.14707 1.80633 7.36292 -1.33411 -1.78973 -1.63261 7 3 4 2.38 -2013-Sep-20 09:11:45 4171695.72429 872117.61892 4730013.84708 11.80796 48.17152 533.36738 -3.29812 2.31840 8.77673 -1.48516 -1.27766 -0.21880 7 3 4 2.38 -2013-Sep-20 09:11:45 4171692.99613 872116.43126 4730011.66933 11.80795 48.17152 529.80166 -3.90238 3.03700 5.21100 -2.08942 -0.55906 -3.78453 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.67503 872117.79312 4730014.50836 11.80797 48.17154 532.54617 -2.70826 4.22753 7.95551 -0.89530 0.63147 -1.04002 7 3 4 2.38 -2013-Sep-20 09:11:45 4171692.48662 872117.98010 4730012.96774 11.80797 48.17153 530.64792 -2.28205 4.03837 6.05726 -0.46909 0.44231 -2.93827 7 3 4 2.38 -2013-Sep-20 09:11:45 4171692.44667 872118.05416 4730014.36462 11.80798 48.17154 531.67283 -2.20138 4.98780 7.08218 -0.38843 1.39174 -1.91336 7 3 4 2.38 -2013-Sep-20 09:11:45 4171695.24201 872118.44845 4730017.21097 11.80797 48.17154 535.67235 -2.38746 4.78706 11.08169 -0.57450 1.19100 2.08616 7 3 4 2.38 -2013-Sep-20 09:11:45 4171696.04418 872118.28056 4730016.91440 11.80797 48.17153 535.95210 -2.71594 4.02979 11.36144 -0.90298 0.43373 2.36591 7 3 4 2.38 -2013-Sep-20 09:11:45 4171694.47708 872119.30626 4730017.63950 11.80799 48.17155 535.60940 -1.39127 5.49997 11.01874 0.42169 1.90391 2.02321 7 3 4 2.38 -2013-Sep-20 09:11:45 4171696.35878 872116.78607 4730016.71307 11.80795 48.17153 535.80350 -4.24319 3.89395 11.21284 -2.43023 0.29789 2.21731 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.48997 872116.69908 4730015.98826 11.80796 48.17155 533.37880 -3.74129 5.51627 8.78814 -1.92833 1.92021 -0.20739 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.77693 872115.78824 4730015.74331 11.80794 48.17155 533.25930 -4.69157 5.28251 8.66865 -2.87861 1.68644 -0.32688 7 3 4 2.38 -2013-Sep-20 09:11:45 4171695.04067 872115.25115 4730016.09580 11.80793 48.17154 534.27362 -5.47590 4.67773 9.68296 -3.66294 1.08167 0.68743 7 3 4 2.38 -2013-Sep-20 09:11:45 4171695.11661 872115.64506 4730016.33873 11.80794 48.17154 534.55797 -5.10586 4.72429 9.96731 -3.29290 1.12823 0.97178 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.90853 872116.71688 4730015.53304 11.80795 48.17154 533.31527 -3.80951 4.90469 8.72461 -1.99655 1.30862 -0.27092 7 3 4 2.38 -2013-Sep-20 09:11:45 4171689.58510 872114.57640 4730009.33773 11.80794 48.17154 525.58446 -5.01998 4.25280 0.99380 -3.20702 0.65674 -8.00173 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.83445 872116.27714 4730013.86054 11.80795 48.17153 531.96063 -4.22478 3.91037 7.36998 -2.41182 0.31431 -1.62555 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.08298 872116.17766 4730014.45916 11.80795 48.17154 531.90257 -4.16838 4.87286 7.31191 -2.35543 1.27680 -1.68362 7 3 4 2.38 -2013-Sep-20 09:11:45 4171699.66080 872119.51994 4730019.51757 11.80798 48.17152 540.42188 -2.24287 2.93900 15.83122 -0.42991 -0.65707 6.83569 7 3 4 2.38 -2013-Sep-20 09:11:45 4171694.41608 872117.01813 4730015.70995 11.80796 48.17154 533.81952 -3.61850 4.60654 9.22886 -1.80554 1.01048 0.23333 7 3 4 2.38 -2013-Sep-20 09:11:45 4171693.77605 872114.30763 4730015.24612 11.80792 48.17154 532.68620 -6.14067 5.17733 8.09554 -4.32771 1.58127 -0.89999 7 3 4 2.38 -2013-Sep-20 09:11:45 4171697.20011 872117.04643 4730020.44194 11.80795 48.17155 539.16679 -4.16050 5.72740 14.57613 -2.34754 2.13133 5.58060 7 3 4 2.38 -2013-Sep-20 09:11:46 4171697.12070 872116.79851 4730020.87803 11.80795 48.17155 539.40607 -4.38692 6.11395 14.81541 -2.57396 2.51788 5.81988 7 3 4 2.38 -2013-Sep-20 09:11:46 4171694.73166 872116.52792 4730018.25628 11.80795 48.17155 535.85601 -4.16292 6.14927 11.26535 -2.34996 2.55320 2.26982 7 3 4 2.38 -2013-Sep-20 09:11:46 4171690.49338 872113.93585 4730014.10998 11.80793 48.17156 529.64597 -5.83284 6.87063 5.05531 -4.01988 3.27457 -3.94022 7 3 4 2.38 -2013-Sep-20 09:11:46 4171690.57820 872114.69383 4730015.26692 11.80794 48.17156 530.66687 -5.10826 7.46475 6.07621 -3.29530 3.86869 -2.91932 7 3 4 2.38 -2013-Sep-20 09:11:46 4171690.23836 872115.37738 4730013.71589 11.80795 48.17156 529.38257 -4.36963 6.57401 4.79191 -2.55667 2.97795 -4.20362 7 3 4 2.38 -2013-Sep-20 09:11:46 4171692.10423 872115.81241 4730015.94300 11.80795 48.17156 532.31948 -4.32562 6.63202 7.72882 -2.51266 3.03596 -1.26671 7 3 4 2.38 -2013-Sep-20 09:11:46 4171695.46646 872116.88487 4730018.42845 11.80795 48.17155 536.51269 -3.96388 5.67372 11.92203 -2.15092 2.07765 2.92650 7 3 4 2.38 -2013-Sep-20 09:11:46 4171697.54324 872117.66769 4730020.00643 11.80796 48.17154 539.15105 -3.62260 5.09196 14.56039 -1.80964 1.49589 5.56486 7 3 4 2.38 -2013-Sep-20 09:11:46 4171695.03344 872117.76110 4730017.28683 11.80797 48.17154 535.49892 -3.01758 5.09458 10.90826 -1.20462 1.49852 1.91273 7 3 4 2.38 -2013-Sep-20 09:11:46 4171689.54412 872116.02111 4730011.78724 11.80796 48.17155 527.58010 -3.59746 5.69599 2.98944 -1.78450 2.09993 -6.00609 7 3 4 2.38 -2013-Sep-20 09:11:46 4171689.48613 872115.32541 4730010.69518 11.80795 48.17154 526.63356 -4.26656 5.11606 2.04291 -2.45361 1.52000 -6.95263 7 3 4 2.38 -2013-Sep-20 09:11:46 4171693.23548 872117.08600 4730014.57851 11.80796 48.17154 532.21501 -3.31048 4.70273 7.62435 -1.49752 1.10667 -1.37118 7 3 4 2.38 -2013-Sep-20 09:11:46 4171691.70133 872117.74483 4730013.08448 11.80797 48.17154 530.19018 -2.35165 4.72487 5.59952 -0.53869 1.12881 -3.39601 7 3 4 2.38 -2013-Sep-20 09:11:46 4171691.47294 872118.64957 4730012.90322 11.80799 48.17154 530.02949 -1.41931 4.63262 5.43883 0.39364 1.03656 -3.55670 7 3 4 2.38 -2013-Sep-20 09:11:46 4171695.69404 872119.79656 4730016.92255 11.80799 48.17153 535.93649 -1.16038 4.05945 11.34583 0.65258 0.46339 2.35030 7 3 4 2.38 -2013-Sep-20 09:11:46 4171693.37434 872119.48021 4730016.03558 11.80799 48.17154 533.71813 -0.99534 5.20810 9.12747 0.81762 1.61204 0.13194 7 3 4 2.38 -2013-Sep-20 09:11:46 4171689.11622 872116.91119 4730012.31483 11.80797 48.17155 527.81537 -2.63865 6.22423 3.22472 -0.82569 2.62817 -5.77082 7 3 4 2.38 -2013-Sep-20 09:11:46 4171691.05673 872116.23852 4730012.20286 11.80796 48.17154 528.90688 -3.69418 4.83675 4.31623 -1.88122 1.24069 -4.67930 7 3 4 2.38 -2013-Sep-20 09:11:46 4171687.08951 872113.62082 4730006.48254 11.80793 48.17154 521.69741 -5.44466 4.31460 -2.89324 -3.63170 0.71854 -11.88878 7 3 4 2.38 -2013-Sep-20 09:11:46 4171690.26826 872114.92558 4730010.28529 11.80794 48.17154 526.78414 -4.81799 4.33322 2.19348 -3.00503 0.73716 -6.80205 7 3 4 2.38 -2013-Sep-20 09:11:46 4171693.27401 872116.30711 4730014.21569 11.80795 48.17154 531.86351 -4.08076 4.55143 7.27285 -2.26781 0.95537 -1.72268 7 3 4 2.38 -2013-Sep-20 09:11:46 4171692.45740 872117.10685 4730011.34158 11.80796 48.17153 529.29794 -3.13085 3.10835 4.70729 -1.31789 -0.48771 -4.28824 7 3 4 2.38 -2013-Sep-20 09:11:46 4171696.82856 872118.37766 4730015.96814 11.80797 48.17152 535.77228 -2.78141 2.81182 11.18163 -0.96845 -0.78424 2.18610 7 3 4 2.38 -2013-Sep-20 09:11:46 4171695.06796 872117.24465 4730014.73665 11.80796 48.17153 533.55072 -3.53016 3.44744 8.96007 -1.71720 -0.14863 -0.03546 7 3 4 2.38 -2013-Sep-20 09:11:46 4171693.40375 872117.89376 4730013.65089 11.80797 48.17153 531.74387 -2.55424 3.83820 7.15322 -0.74128 0.24214 -1.84231 7 3 4 2.38 -2013-Sep-20 09:11:47 4171690.98939 872116.75487 4730013.46748 11.80796 48.17155 529.87572 -3.17497 5.65052 5.28506 -1.36201 2.05445 -3.71047 7 3 4 2.38 -2013-Sep-20 09:11:47 4171693.70057 872118.08841 4730015.47165 11.80797 48.17154 533.32093 -2.42445 4.80629 8.73028 -0.61149 1.21023 -0.26526 7 3 4 2.38 -2013-Sep-20 09:11:47 4171694.65632 872118.68334 4730016.61781 11.80798 48.17154 534.88008 -2.03768 4.78286 10.28942 -0.22472 1.18679 1.29389 7 3 4 2.38 -2013-Sep-20 09:11:47 4171695.13273 872119.09675 4730017.61723 11.80798 48.17154 535.99221 -1.73051 5.03885 11.40156 0.08245 1.44279 2.40602 7 3 4 2.38 -2013-Sep-20 09:11:47 4171695.76351 872119.75086 4730017.44981 11.80799 48.17154 536.36849 -1.21932 4.36739 11.77784 0.59364 0.77132 2.78231 7 3 4 2.38 -2013-Sep-20 09:11:47 4171688.74263 872115.93827 4730010.16230 11.80796 48.17154 525.83478 -3.51453 5.20953 1.24412 -1.70158 1.61347 -7.75141 7 3 4 2.38 -2013-Sep-20 09:11:47 4171692.87624 872116.89737 4730013.33047 11.80796 48.17154 531.02479 -3.42160 4.16119 6.43414 -1.60864 0.56513 -2.56140 7 3 4 2.38 -2013-Sep-20 09:11:47 4171694.70101 872116.03797 4730013.68317 11.80794 48.17153 532.36151 -4.63622 3.19651 7.77086 -2.82326 -0.39955 -1.22467 7 3 4 2.38 -2013-Sep-20 09:11:47 4171693.80431 872117.50124 4730014.65832 11.80797 48.17154 532.70248 -3.02043 4.27775 8.11182 -1.20747 0.68169 -0.88371 7 3 4 2.38 -2013-Sep-20 09:11:47 4171695.18654 872118.38732 4730016.21216 11.80797 48.17154 534.88354 -2.43594 4.17073 10.29289 -0.62298 0.57466 1.29735 7 3 4 2.38 -2013-Sep-20 09:11:47 4171693.64297 872117.00661 4730016.10385 11.80796 48.17155 533.60678 -3.47157 5.43488 9.01612 -1.65861 1.83882 0.02059 7 3 4 2.38 -2013-Sep-20 09:11:47 4171697.91174 872119.55583 4730020.38997 11.80798 48.17154 539.93507 -1.84982 4.79106 15.34441 -0.03686 1.19499 6.34888 7 3 4 2.38 -2013-Sep-20 09:11:47 4171695.89818 872117.83302 4730017.46794 11.80796 48.17154 536.20819 -3.12414 4.57369 11.61753 -1.31118 0.97762 2.62200 7 3 4 2.38 -2013-Sep-20 09:11:47 4171692.66435 872117.87699 4730015.50583 11.80797 48.17155 532.64111 -2.41935 5.61712 8.05046 -0.60639 2.02106 -0.94508 7 3 4 2.38 -2013-Sep-20 09:11:47 4171690.61610 872116.25976 4730012.31716 11.80796 48.17154 528.70731 -3.58322 5.23113 4.11665 -1.77027 1.63507 -4.87888 7 3 4 2.38 -2013-Sep-20 09:11:47 4171691.78895 872116.15843 4730015.51246 11.80795 48.17156 531.84007 -3.92240 6.52208 7.24941 -2.10945 2.92602 -1.74612 7 3 4 2.38 -2013-Sep-20 09:11:47 4171689.92838 872115.73951 4730011.57532 11.80795 48.17155 527.63460 -3.95173 5.31733 3.04394 -2.13877 1.72127 -5.95159 7 3 4 2.38 -2013-Sep-20 09:11:47 4171689.76279 872114.81080 4730012.01678 11.80794 48.17155 527.72872 -4.82690 5.87412 3.13806 -3.01395 2.27806 -5.85747 7 3 4 2.38 -2013-Sep-20 09:11:47 4171693.97631 872117.04790 4730016.44802 11.80796 48.17155 534.08648 -3.49937 5.41498 9.49582 -1.68641 1.81892 0.50029 7 3 4 2.38 -2013-Sep-20 09:11:47 4171693.08580 872117.06716 4730016.84567 11.80796 48.17155 533.80409 -3.29828 6.32675 9.21343 -1.48533 2.73069 0.21790 7 3 4 2.38 -2013-Sep-20 09:11:47 4171694.63630 872118.22336 4730017.54640 11.80797 48.17155 535.49617 -2.48384 5.48688 10.90551 -0.67088 1.89082 1.90998 7 3 4 2.38 -2013-Sep-20 09:11:47 4171694.59244 872117.66422 4730017.34097 11.80796 48.17155 535.23817 -3.02217 5.46712 10.64751 -1.20921 1.87106 1.65198 7 3 4 2.38 -2013-Sep-20 09:11:47 4171692.89093 872116.27044 4730016.17331 11.80795 48.17155 533.06715 -4.03827 6.14197 8.47649 -2.22531 2.54591 -0.51904 7 3 4 2.38 -2013-Sep-20 09:11:47 4171689.08251 872116.36285 4730013.17182 11.80796 48.17156 528.35712 -3.16849 6.90395 3.76646 -1.35553 3.30789 -5.22907 7 3 4 2.38 -2013-Sep-20 09:11:47 4171689.00221 872116.96672 4730012.74135 11.80797 48.17156 528.06635 -2.56096 6.58336 3.47569 -0.74800 2.98730 -5.51984 7 3 4 2.38 -2013-Sep-20 09:11:48 4171690.27934 872118.28668 4730014.53656 11.80799 48.17156 530.41787 -1.53028 6.64781 5.82721 0.28267 3.05175 -3.16832 7 3 4 2.38 -2013-Sep-20 09:11:48 4171689.61503 872117.12584 4730012.29829 11.80797 48.17155 528.15796 -2.53062 5.81664 3.56730 -0.71766 2.22058 -5.42823 7 3 4 2.38 -2013-Sep-20 09:11:48 4171697.69484 872121.83809 4730013.51198 11.80801 48.17150 534.97984 0.42852 0.01431 10.38918 2.24148 -3.58175 1.39365 7 3 4 2.38 -2013-Sep-20 09:11:48 4171699.41323 872123.69735 4730016.94187 11.80803 48.17150 538.91109 1.89680 0.76485 14.32043 3.70976 -2.83121 5.32490 7 3 4 2.38 -2013-Sep-20 09:11:48 4171697.23671 872121.16590 4730014.83677 11.80800 48.17151 535.57620 -0.13569 1.33446 10.98554 1.67727 -2.26160 1.99001 7 3 4 2.38 -2013-Sep-20 09:11:48 4171696.11857 872121.32280 4730013.75751 11.80801 48.17151 534.06349 0.24669 1.40631 9.47284 2.05965 -2.18975 0.47730 7 3 4 2.38 -2013-Sep-20 09:11:48 4171693.93048 872120.74206 4730009.50335 11.80801 48.17150 529.38591 0.12600 0.25369 4.79526 1.93896 -3.34237 -4.20028 7 3 4 2.38 -2013-Sep-20 09:11:48 4171691.22392 872118.98947 4730008.27636 11.80799 48.17151 526.46563 -1.03566 1.67674 1.87498 0.77730 -1.91931 -7.12055 7 3 4 2.38 -2013-Sep-20 09:11:48 4171692.62390 872118.99280 4730010.34910 11.80799 48.17152 528.92448 -1.31888 2.03744 4.33382 0.49408 -1.55862 -4.66171 7 3 4 2.38 -2013-Sep-20 09:11:48 4171695.67185 872120.23092 4730011.82413 11.80800 48.17150 532.18222 -0.73067 0.60925 7.59157 1.08229 -2.98681 -1.40397 7 3 4 2.38 -2013-Sep-20 09:11:48 4171697.26857 872121.23280 4730013.48790 11.80800 48.17150 534.60103 -0.07672 0.40145 10.01037 1.73624 -3.19461 1.01484 7 3 4 2.38 -2013-Sep-20 09:11:48 4171696.38356 872119.30156 4730013.56797 11.80798 48.17151 533.81941 -1.78600 1.39483 9.22876 0.02696 -2.20123 0.23322 7 3 4 2.38 -2013-Sep-20 09:11:48 4171696.99760 872119.95043 4730012.74478 11.80799 48.17150 533.69540 -1.27651 0.29904 9.10474 0.53645 -3.29702 0.10921 7 3 4 2.38 -2013-Sep-20 09:11:48 4171699.47353 872121.03693 4730016.38304 11.80800 48.17150 538.17097 -0.71966 0.75385 13.58031 1.09330 -2.84222 4.58478 7 3 4 2.38 -2013-Sep-20 09:11:48 4171700.83789 872121.89492 4730016.81861 11.80800 48.17150 539.50327 -0.15902 -0.08163 14.91261 1.65394 -3.67769 5.91708 7 3 4 2.38 -2013-Sep-20 09:11:48 4171700.21047 872121.18047 4730016.26686 11.80800 48.17150 538.58505 -0.72996 0.11698 13.99440 1.08300 -3.47909 4.99886 7 3 4 2.38 -2013-Sep-20 09:11:48 4171698.07341 872122.61021 4730017.05131 11.80802 48.17152 537.96965 1.10684 1.98084 13.37900 2.91980 -1.61522 4.38346 7 3 4 2.38 -2013-Sep-20 09:11:48 4171695.61837 872120.94942 4730015.36464 11.80801 48.17152 534.88356 -0.01643 2.89988 10.29290 1.79653 -0.69618 1.29737 7 3 4 2.38 -2013-Sep-20 09:11:48 4171696.03979 872122.28542 4730016.25204 11.80802 48.17152 536.00223 1.20507 2.98060 11.41157 3.01803 -0.61547 2.41604 7 3 4 2.38 -2013-Sep-20 09:11:48 4171698.28626 872123.80253 4730016.93000 11.80804 48.17151 538.18092 2.23037 1.56288 13.59026 4.04333 -2.03318 4.59473 7 3 4 2.38 -2013-Sep-20 09:11:48 4171698.84194 872122.23112 4730016.23664 11.80801 48.17151 537.81256 0.57850 0.93479 13.22190 2.39146 -2.66127 4.22637 7 3 4 2.38 -2013-Sep-20 09:11:48 4171697.44208 872121.25846 4730015.52416 11.80800 48.17151 536.23510 -0.08712 1.62898 11.64445 1.72584 -1.96709 2.64891 7 3 4 2.38 -2013-Sep-20 09:11:48 4171693.20144 872117.82225 4730012.34069 11.80797 48.17153 530.62577 -2.58284 3.12288 6.03511 -0.76989 -0.47318 -2.96042 7 3 4 2.38 -2013-Sep-20 09:11:48 4171694.69339 872117.78625 4730012.08336 11.80797 48.17151 531.40304 -2.92337 1.86857 6.81238 -1.11041 -1.72749 -2.18315 7 3 4 2.38 -2013-Sep-20 09:11:48 4171692.48650 872117.23476 4730009.59715 11.80797 48.17151 528.03455 -3.01159 1.90425 3.44390 -1.19863 -1.69181 -5.55163 7 3 4 2.38 -2013-Sep-20 09:11:49 4171694.63009 872117.83856 4730013.18767 11.80797 48.17152 532.19173 -2.85922 2.64323 7.60107 -1.04626 -0.95283 -1.39446 7 3 4 2.38 -2013-Sep-20 09:11:49 4171695.74003 872117.84020 4730015.05488 11.80796 48.17153 534.30784 -3.08475 3.07867 9.71719 -1.27179 -0.51740 0.72165 7 3 4 2.38 -2013-Sep-20 09:11:49 4171696.17236 872118.73918 4730015.00220 11.80797 48.17152 534.67350 -2.29326 2.59113 10.08284 -0.48030 -1.00494 1.08731 7 3 4 2.38 -2013-Sep-20 09:11:49 4171695.14836 872118.29528 4730015.81412 11.80797 48.17153 534.54946 -2.51822 3.94717 9.95880 -0.70526 0.35110 0.96327 7 3 4 2.38 -2013-Sep-20 09:11:49 4171697.09466 872120.86564 4730017.06207 11.80800 48.17152 537.10067 -0.40054 2.96791 12.51001 1.41243 -0.62815 3.51448 7 3 4 2.38 -2013-Sep-20 09:11:49 4171694.39566 872119.69092 4730013.92643 11.80799 48.17152 532.84197 -0.99809 3.02444 8.25131 0.81487 -0.57162 -0.74422 7 3 4 2.38 -2013-Sep-20 09:11:49 4171695.22683 872120.00869 4730014.99482 11.80799 48.17153 534.22401 -0.85713 3.08227 9.63336 0.95583 -0.51379 0.63783 7 3 4 2.38 -2013-Sep-20 09:11:49 4171698.17039 872119.79034 4730016.98170 11.80798 48.17152 537.59625 -1.67321 2.29366 13.00560 0.13975 -1.30240 4.01006 7 3 4 2.38 -2013-Sep-20 09:11:49 4171700.00517 872121.16161 4730019.98118 11.80800 48.17152 541.21617 -0.70641 2.74668 16.62552 1.10655 -0.84938 7.62998 7 3 4 2.38 -2013-Sep-20 09:11:49 4171696.70779 872119.77758 4730015.76720 11.80799 48.17152 535.73477 -1.38640 2.55244 11.14411 0.42656 -1.04362 2.14858 7 3 4 2.38 -2013-Sep-20 09:11:49 4171696.66262 872119.97368 4730016.26361 11.80799 48.17152 536.10194 -1.18520 2.88654 11.51129 0.62776 -0.70952 2.51575 7 3 4 2.38 -2013-Sep-20 09:11:49 4171694.37549 872117.67545 4730012.91449 11.80797 48.17152 531.79970 -2.96678 2.67161 7.20905 -1.15382 -0.92445 -1.78648 7 3 4 2.38 -2013-Sep-20 09:11:49 4171692.78864 872120.42133 4730012.62848 11.80801 48.17153 530.92544 0.04571 3.21959 6.33478 1.85867 -0.37647 -2.66075 7 3 4 2.38 -2013-Sep-20 09:11:49 4171691.67008 872119.95033 4730012.44513 11.80800 48.17153 529.99435 -0.18642 3.98498 5.40370 1.62654 0.38893 -3.59184 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.85862 872119.59939 4730014.13942 11.80799 48.17153 532.63761 -0.97779 3.57215 8.04695 0.83517 -0.02391 -0.94858 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.43125 872119.70259 4730014.30431 11.80800 48.17153 532.49557 -0.78931 3.97809 7.90492 1.02365 0.38203 -1.09061 7 3 4 2.38 -2013-Sep-20 09:11:49 4171692.15580 872118.33429 4730011.81589 11.80798 48.17153 529.62201 -1.86766 3.45748 5.03135 -0.05470 -0.13858 -3.96418 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.77406 872119.05065 4730014.29676 11.80799 48.17153 532.62477 -1.49761 3.82243 8.03411 0.31535 0.22637 -0.96142 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.03195 872117.05363 4730012.14337 11.80796 48.17153 530.26319 -3.30051 3.23211 5.67254 -1.48755 -0.36395 -3.32300 7 3 4 2.38 -2013-Sep-20 09:11:49 4171697.31607 872120.67877 4730017.74234 11.80800 48.17153 537.72659 -0.62876 3.28858 13.13594 1.18420 -0.30748 4.14040 7 3 4 2.38 -2013-Sep-20 09:11:49 4171694.36044 872119.19236 4730013.68970 11.80799 48.17152 532.57454 -1.47889 2.96828 7.98388 0.33407 -0.62778 -1.01165 7 3 4 2.38 -2013-Sep-20 09:11:49 4171692.59801 872115.73907 4730012.36764 11.80795 48.17153 529.96764 -4.49845 3.89863 5.37699 -2.68550 0.30257 -3.61855 7 3 4 2.38 -2013-Sep-20 09:11:49 4171689.94758 872115.41950 4730009.77543 11.80795 48.17154 526.26228 -4.26890 4.15177 1.67163 -2.45594 0.55571 -7.32391 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.74943 872117.74347 4730013.76650 11.80797 48.17153 532.03517 -2.77209 3.68609 7.44451 -0.95913 0.09002 -1.55102 7 3 4 2.38 -2013-Sep-20 09:11:49 4171693.95887 872116.76591 4730014.97435 11.80795 48.17154 532.93851 -3.77182 4.48790 8.34785 -1.95886 0.89184 -0.64768 7 3 4 2.38 -2013-Sep-20 09:11:50 4171697.75983 872117.97296 4730016.75180 11.80796 48.17152 536.90892 -3.36812 2.71690 12.31827 -1.55516 -0.87916 3.32274 7 3 4 2.38 -2013-Sep-20 09:11:50 4171700.12216 872119.45928 4730020.01987 11.80797 48.17152 541.08905 -2.39666 2.94673 16.49840 -0.58370 -0.64933 7.50286 7 3 4 2.38 -2013-Sep-20 09:11:50 4171696.75390 872120.02024 4730016.38795 11.80799 48.17152 536.26053 -1.15831 2.89578 11.66987 0.65465 -0.70028 2.67434 7 3 4 2.38 -2013-Sep-20 09:11:50 4171696.62038 872120.59208 4730017.36975 11.80800 48.17153 536.98299 -0.57125 3.56074 12.39234 1.24171 -0.03532 3.39681 7 3 4 2.38 -2013-Sep-20 09:11:50 4171696.76241 872119.51678 4730017.25801 11.80798 48.17153 536.84570 -1.65286 3.54659 12.25505 0.16010 -0.04947 3.25951 7 3 4 2.38 -2013-Sep-20 09:11:50 4171695.56478 872119.08565 4730016.07613 11.80798 48.17153 535.12439 -1.82979 3.69765 10.53373 -0.01683 0.10159 1.53820 7 3 4 2.38 -2013-Sep-20 09:11:50 4171698.53396 872119.98790 4730018.83850 11.80798 48.17153 539.24414 -1.55422 3.23665 14.65348 0.25874 -0.35941 5.65795 7 3 4 2.38 -2013-Sep-20 09:11:50 4171695.87045 872116.53449 4730013.98515 11.80795 48.17152 533.41769 -4.38952 2.46923 8.82703 -2.57656 -1.12683 -0.16850 7 3 4 2.38 -2013-Sep-20 09:11:50 4171697.97419 872117.72189 4730017.39427 11.80796 48.17152 537.49332 -3.65773 3.02731 12.90267 -1.84477 -0.56876 3.90713 7 3 4 2.38 -2013-Sep-20 09:11:50 4171695.07700 872116.24279 4730014.04631 11.80794 48.17153 532.90550 -4.51267 3.13321 8.31484 -2.69972 -0.46285 -0.68069 7 3 4 2.38 -2013-Sep-20 09:11:50 4171690.26871 872114.89262 4730008.97535 11.80794 48.17153 525.80384 -4.85034 3.46430 1.21318 -3.03738 -0.13176 -7.78235 7 3 4 2.38 -2013-Sep-20 09:11:50 4171692.75955 872114.89066 4730013.60601 11.80793 48.17154 530.88007 -5.36197 4.73605 6.28942 -3.54901 1.13999 -2.70612 7 3 4 2.38 -2013-Sep-20 09:11:50 4171691.95948 872114.55133 4730013.66356 11.80793 48.17155 530.35437 -5.53039 5.40972 5.76372 -3.71744 1.81366 -3.23182 7 3 4 2.38 -2013-Sep-20 09:11:50 4171695.09852 872116.36994 4730016.05607 11.80795 48.17154 534.43446 -4.39263 4.43844 9.84380 -2.57967 0.84238 0.84827 7 3 4 2.38 -2013-Sep-20 09:11:50 4171695.34463 872117.88389 4730016.13615 11.80797 48.17153 534.86140 -2.96107 4.08150 10.27074 -1.14811 0.48543 1.27521 7 3 4 2.38 -2013-Sep-20 09:11:50 4171697.40948 872116.71951 4730016.92576 11.80794 48.17153 536.63879 -4.52335 3.27958 12.04813 -2.71039 -0.31648 3.05260 7 3 4 2.38 -2013-Sep-20 09:11:50 4171694.45550 872115.82908 4730014.01599 11.80794 48.17153 532.42074 -4.79045 3.62939 7.83009 -2.97749 0.03332 -1.16545 7 3 4 2.38 -2013-Sep-20 09:11:50 4171692.99165 872115.24509 4730014.73675 11.80794 48.17155 531.92252 -5.06254 5.26681 7.33186 -3.24958 1.67075 -1.66367 7 3 4 2.38 -2013-Sep-20 09:11:50 4171691.74799 872114.79843 4730012.34905 11.80794 48.17154 529.27054 -5.24525 4.64965 4.67988 -3.43229 1.05359 -4.31565 7 3 4 2.38 -2013-Sep-20 09:11:50 4171693.02877 872116.02999 4730016.51231 11.80795 48.17155 533.37692 -4.30184 6.30418 8.78626 -2.48888 2.70812 -0.20927 7 3 4 2.38 -2013-Sep-20 09:11:50 4171694.68827 872114.31880 4730015.55856 11.80792 48.17154 533.51602 -6.31641 4.71864 8.92536 -4.50345 1.12257 -0.07017 7 3 4 2.38 -2013-Sep-20 09:11:50 4171693.77761 872115.95720 4730015.67837 11.80794 48.17154 533.23442 -4.52632 5.21293 8.64376 -2.71336 1.61687 -0.35177 7 3 4 2.38 -2013-Sep-20 09:11:50 4171694.19630 872116.39989 4730015.12616 11.80795 48.17154 533.15667 -4.17868 4.47178 8.56601 -2.36572 0.87572 -0.42952 7 3 4 2.38 -2013-Sep-20 09:11:50 4171696.24240 872117.91645 4730019.78765 11.80796 48.17155 538.17280 -3.11291 5.85692 13.58214 -1.29995 2.26085 4.58661 7 3 4 2.38 -2013-Sep-20 09:11:50 4171694.55237 872117.87145 4730016.31592 11.80797 48.17154 534.47647 -2.81112 4.78114 9.88582 -0.99816 1.18508 0.89029 7 3 4 2.38 -2013-Sep-20 09:11:51 4171698.37532 872118.47241 4730019.27226 11.80797 48.17153 539.25698 -3.00518 3.87273 14.66632 -1.19222 0.27666 5.67079 7 3 4 2.38 -2013-Sep-20 09:11:51 4171695.64513 872116.77343 4730017.51389 11.80795 48.17154 535.93263 -4.10953 4.95047 11.34198 -2.29657 1.35441 2.34645 7 3 4 2.38 -2013-Sep-20 09:11:51 4171697.24627 872118.24946 4730017.71783 11.80797 48.17153 537.33124 -2.99237 3.69357 12.74059 -1.17941 0.09751 3.74506 7 3 4 2.38 -2013-Sep-20 09:11:51 4171694.97997 872117.37612 4730016.79286 11.80796 48.17154 535.04340 -3.38347 4.86285 10.45274 -1.57051 1.26679 1.45721 7 3 4 2.38 -2013-Sep-20 09:11:51 4171697.09886 872117.20407 4730018.29927 11.80795 48.17154 537.52560 -3.98547 4.34826 12.93495 -2.17251 0.75219 3.93941 7 3 4 2.38 -2013-Sep-20 09:11:51 4171696.40555 872118.35142 4730018.90254 11.80797 48.17154 537.67912 -2.72053 5.08132 13.08847 -0.90757 1.48525 4.09293 7 3 4 2.38 -2013-Sep-20 09:11:51 4171696.82261 872116.98598 4730016.79506 11.80795 48.17153 536.19465 -4.14242 3.57984 11.60400 -2.32946 -0.01623 2.60847 7 3 4 2.38 -2013-Sep-20 09:11:51 4171695.04422 872116.60407 4730017.14060 11.80795 48.17154 535.23910 -4.15233 5.16563 10.64844 -2.33937 1.56957 1.65291 7 3 4 2.38 -2013-Sep-20 09:11:51 4171696.83739 872117.80959 4730018.86994 11.80796 48.17154 537.86279 -3.33927 4.82721 13.27213 -1.52631 1.23115 4.27660 7 3 4 2.38 -2013-Sep-20 09:11:51 4171696.88781 872118.11252 4730019.84086 11.80796 48.17155 538.66052 -3.05306 5.39176 14.06986 -1.24010 1.79569 5.07433 7 3 4 2.38 -2013-Sep-20 09:11:51 4171698.31688 872119.10025 4730020.39935 11.80797 48.17154 540.14435 -2.37867 4.57128 15.55370 -0.56571 0.97521 6.55816 7 3 4 2.38 -2013-Sep-20 09:11:51 4171695.78621 872118.04903 4730016.47168 11.80797 48.17153 535.42222 -2.88978 3.95801 10.83156 -1.07682 0.36194 1.83603 7 3 4 2.38 -2013-Sep-20 09:11:51 4171692.38286 872118.07919 4730014.09759 11.80798 48.17154 531.43561 -2.16383 4.85244 6.84496 -0.35087 1.25638 -2.15058 7 3 4 2.38 -2013-Sep-20 09:11:51 4171692.35887 872118.42735 4730013.38822 11.80798 48.17154 530.93888 -1.81813 4.34377 6.34822 -0.00517 0.74771 -2.64731 7 3 4 2.38 -2013-Sep-20 09:11:51 4171692.60829 872118.53458 4730015.06669 11.80798 48.17155 532.36704 -1.76420 5.26488 7.77639 0.04875 1.66881 -1.21914 7 3 4 2.38 -2013-Sep-20 09:11:51 4171693.86023 872119.67146 4730015.99694 11.80799 48.17154 534.03262 -0.90757 4.79877 9.44196 0.90539 1.20271 0.44643 7 3 4 2.38 -2013-Sep-20 09:11:51 4171693.24262 872118.83673 4730016.25767 11.80798 48.17155 533.70981 -1.59826 5.55040 9.11915 0.21470 1.95434 0.12362 7 3 4 2.38 -2013-Sep-20 09:11:51 4171689.72170 872117.48003 4730010.70157 11.80798 48.17154 527.08614 -2.20574 4.61997 2.49548 -0.39279 1.02391 -6.50005 7 3 4 2.38 -2013-Sep-20 09:11:51 4171692.52581 872118.33884 4730014.59485 11.80798 48.17154 531.93489 -1.93892 5.04021 7.34423 -0.12596 1.44415 -1.65130 7 3 4 2.38 -2013-Sep-20 09:11:51 4171693.43458 872119.60432 4730017.75909 11.80799 48.17155 535.05865 -0.88619 6.29465 10.46799 0.92677 2.69859 1.47246 7 3 4 2.38 -2013-Sep-20 09:11:51 4171690.49018 872116.37434 4730013.42103 11.80796 48.17155 529.46330 -3.44530 6.04167 4.87264 -1.63234 2.44561 -4.12289 7 3 4 2.38 -2013-Sep-20 09:11:51 4171689.25240 872116.47891 4730013.04403 11.80796 48.17156 528.38864 -3.08965 6.67711 3.79798 -1.27669 3.08106 -5.19755 7 3 4 2.38 -2013-Sep-20 09:11:51 4171690.69340 872117.89639 4730013.86928 11.80798 48.17155 530.13768 -1.99704 5.96031 5.54703 -0.18408 2.36425 -3.44850 7 3 4 2.38 -2013-Sep-20 09:11:51 4171687.90866 872116.38325 4730011.14049 11.80797 48.17156 526.07998 -2.90831 6.40231 1.48933 -1.09536 2.80625 -7.50620 7 3 4 2.38 -2013-Sep-20 09:11:51 4171689.50675 872118.23332 4730012.14242 11.80799 48.17155 528.12227 -1.42441 5.62280 3.53161 0.38855 2.02674 -5.46392 7 3 4 2.38 -2013-Sep-20 09:11:52 4171690.09269 872116.77902 4730012.74738 11.80797 48.17155 528.75707 -2.96784 5.82063 4.16642 -1.15488 2.22457 -4.82912 7 3 4 2.38 -2013-Sep-20 09:11:52 4171692.00020 872117.10328 4730016.50027 11.80796 48.17156 532.84299 -3.04078 6.88271 8.25233 -1.22782 3.28664 -0.74320 7 3 4 2.38 -2013-Sep-20 09:11:52 4171689.01089 872115.62661 4730011.29080 11.80795 48.17155 526.80825 -3.87450 5.81399 2.21759 -2.06154 2.21794 -6.77794 7 3 4 2.38 -2013-Sep-20 09:11:52 4171687.99712 872116.24031 4730010.84236 11.80796 48.17155 525.89607 -3.06633 6.16077 1.30542 -1.25337 2.56471 -7.69011 7 3 4 2.38 -2013-Sep-20 09:11:52 4171686.24000 872115.26520 4730009.72699 11.80796 48.17156 523.78486 -3.66124 6.84721 -0.80580 -1.84828 3.25115 -9.80133 7 3 4 2.38 -2013-Sep-20 09:11:52 4171692.85561 872117.24077 4730015.10000 11.80796 48.17155 532.37674 -3.08124 5.30399 7.78609 -1.26828 1.70792 -1.20945 7 3 4 2.38 -2013-Sep-20 09:11:52 4171693.22025 872118.15040 4730017.42974 11.80798 48.17156 534.47490 -2.26548 6.45304 9.88424 -0.45253 2.85697 0.88871 7 3 4 2.38 -2013-Sep-20 09:11:52 4171693.55565 872117.16666 4730015.95114 11.80796 48.17155 533.45783 -3.29704 5.37232 8.86718 -1.48408 1.77626 -0.12835 7 3 4 2.38 -2013-Sep-20 09:11:52 4171690.96482 872116.76181 4730016.21891 11.80796 48.17157 531.91084 -3.16315 7.50231 7.32018 -1.35020 3.90625 -1.67535 7 3 4 2.38 -2013-Sep-20 09:11:52 4171691.23538 872117.56932 4730016.96099 11.80797 48.17157 532.75062 -2.42810 7.67674 8.15996 -0.61514 4.08068 -0.83557 7 3 4 2.38 -2013-Sep-20 09:11:52 4171690.59725 872115.76944 4730017.40408 11.80795 48.17158 532.41859 -4.05930 8.71213 7.82793 -2.24634 5.11607 -1.16760 7 3 4 2.38 -2013-Sep-20 09:11:52 4171690.85914 872115.78250 4730015.10104 11.80795 48.17156 530.87523 -4.10012 6.98321 6.28457 -2.28716 3.38715 -2.71096 7 3 4 2.38 -2013-Sep-20 09:11:52 4171687.57249 872115.36900 4730011.85321 11.80795 48.17156 526.25320 -3.83231 7.27748 1.66254 -2.01936 3.68142 -7.33299 7 3 4 2.38 -2013-Sep-20 09:11:52 4171689.60871 872116.13960 4730012.73699 11.80796 48.17155 528.34614 -3.49469 6.26420 3.75548 -1.68173 2.66815 -5.24005 7 3 4 2.38 -2013-Sep-20 09:11:52 4171687.40524 872116.51402 4730012.25067 11.80797 48.17157 526.59645 -2.67729 7.48994 2.00579 -0.86433 3.89388 -6.98974 7 3 4 2.38 -2013-Sep-20 09:11:52 4171689.07301 872115.14207 4730012.66794 11.80795 48.17156 527.80886 -4.36149 6.76098 3.21820 -2.54854 3.16492 -5.77733 7 3 4 2.38 -2013-Sep-20 09:11:52 4171688.24740 872115.72461 4730013.02406 11.80796 48.17157 527.61476 -3.62233 7.51183 3.02410 -1.80937 3.91577 -5.97143 7 3 4 2.38 -2013-Sep-20 09:11:52 4171689.64800 872115.67283 4730012.14075 11.80795 48.17155 527.86380 -3.95963 5.90909 3.27314 -2.14667 2.31303 -5.72239 7 3 4 2.38 -2013-Sep-20 09:11:52 4171691.27013 872116.01790 4730015.52910 11.80795 48.17156 531.49462 -3.95380 6.93302 6.90396 -2.14084 3.33696 -2.09157 7 3 4 2.38 -2013-Sep-20 09:11:52 4171692.17933 872116.72878 4730015.28157 11.80796 48.17155 532.00070 -3.44402 5.99640 7.41004 -1.63106 2.40034 -1.58549 7 3 4 2.38 -2013-Sep-20 09:11:52 4171696.95168 872118.42600 4730019.89214 11.80797 48.17155 538.78320 -2.75929 5.33158 14.19254 -0.94633 1.73551 5.19701 7 3 4 2.38 -2013-Sep-20 09:11:52 4171695.79975 872118.53080 4730018.78050 11.80797 48.17155 537.21720 -2.42099 5.41443 12.62654 -0.60803 1.81837 3.63101 7 3 4 2.38 -2013-Sep-20 09:11:52 4171693.44918 872117.45165 4730015.12135 11.80797 48.17154 532.80890 -2.99629 4.85313 8.21825 -1.18333 1.25707 -0.77729 7 3 4 2.38 -2013-Sep-20 09:11:52 4171696.91616 872119.35273 4730018.88611 11.80798 48.17154 538.13685 -1.84490 4.54525 13.54619 -0.03194 0.94919 4.55066 7 3 4 2.38 -2013-Sep-20 09:11:52 4171697.77986 872120.40746 4730020.41721 11.80799 48.17154 539.98549 -0.98923 4.77555 15.39484 0.82373 1.17948 6.39931 7 3 4 2.38 -2013-Sep-20 09:11:53 4171694.80653 872117.67543 4730020.27882 11.80796 48.17156 537.56857 -3.05501 7.26852 12.97791 -1.24205 3.67246 3.98238 7 3 4 2.38 -2013-Sep-20 09:11:53 4171694.05497 872116.07051 4730019.09673 11.80795 48.17156 535.97811 -4.47217 7.27307 11.38745 -2.65921 3.67700 2.39192 7 3 4 2.38 -2013-Sep-20 09:11:53 4171693.48086 872116.46808 4730017.50238 11.80795 48.17156 534.46957 -3.96553 6.56792 9.87891 -2.15258 2.97185 0.88338 7 3 4 2.38 -2013-Sep-20 09:11:53 4171693.55370 872117.95188 4730017.84278 11.80797 48.17156 534.97327 -2.52803 6.51555 10.38261 -0.71507 2.91949 1.38708 7 3 4 2.38 -2013-Sep-20 09:11:53 4171694.24129 872118.36007 4730017.03530 11.80798 48.17155 534.87613 -2.26918 5.41328 10.28547 -0.45623 1.81722 1.28994 7 3 4 2.38 -2013-Sep-20 09:11:53 4171689.65452 872114.76628 4730013.47883 11.80794 48.17156 528.74141 -4.84832 6.93493 4.15075 -3.03536 3.33887 -4.84478 7 3 4 2.38 -2013-Sep-20 09:11:53 4171687.60106 872114.30672 4730012.83696 11.80794 48.17157 526.85992 -4.87795 8.07469 2.26926 -3.06499 4.47863 -6.72627 7 3 4 2.38 -2013-Sep-20 09:11:53 4171687.25192 872114.90764 4730011.57511 11.80795 48.17156 525.77375 -4.21830 7.39617 1.18309 -2.40535 3.80011 -7.81244 7 3 4 2.38 -2013-Sep-20 09:11:53 4171687.71972 872114.85189 4730011.84202 11.80795 48.17156 526.27041 -4.36860 7.24148 1.67975 -2.55564 3.64542 -7.31578 7 3 4 2.38 -2013-Sep-20 09:11:53 4171688.12430 872115.33868 4730012.68062 11.80795 48.17156 527.22582 -3.97491 7.43143 2.63516 -2.16195 3.83537 -6.36037 7 3 4 2.38 -2013-Sep-20 09:11:53 4171689.03967 872115.23753 4730013.41406 11.80795 48.17156 528.35608 -4.26123 7.26834 3.76542 -2.44827 3.67228 -5.23011 7 3 4 2.38 -2013-Sep-20 09:11:53 4171690.64438 872115.56369 4730013.94193 11.80795 48.17156 529.84147 -4.27035 6.40021 5.25081 -2.45739 2.80414 -3.74472 7 3 4 2.38 -2013-Sep-20 09:11:53 4171692.71611 872114.69113 4730015.46940 11.80793 48.17155 532.21299 -5.54839 6.04085 7.62233 -3.73543 2.44479 -1.37320 7 3 4 2.38 -2013-Sep-20 09:11:53 4171691.22275 872114.73262 4730015.42079 11.80794 48.17156 531.20758 -5.20218 7.09134 6.61692 -3.38922 3.49527 -2.37861 7 3 4 2.38 -2013-Sep-20 09:11:53 4171690.08443 872114.56734 4730014.62927 11.80794 48.17156 529.85215 -5.13103 7.41893 5.26148 -3.31807 3.82287 -3.73404 7 3 4 2.38 -2013-Sep-20 09:11:53 4171690.84764 872115.02594 4730017.08521 11.80794 48.17157 532.24297 -4.83832 8.43021 7.65231 -3.02536 4.83415 -1.34322 7 3 4 2.38 -2013-Sep-20 09:11:53 4171692.57768 872115.43641 4730018.09924 11.80794 48.17157 534.18394 -4.79055 7.78203 9.59328 -2.97759 4.18597 0.59775 7 3 4 2.38 -2013-Sep-20 09:11:53 4171686.42411 872112.06870 4730011.60333 11.80791 48.17157 524.86696 -6.82777 8.45167 0.27630 -5.01482 4.85561 -8.71923 7 3 4 2.38 -2013-Sep-20 09:11:53 4171686.46206 872112.35102 4730012.68539 11.80792 48.17158 525.73656 -6.55919 9.10257 1.14590 -4.74624 5.50651 -7.84963 7 3 4 2.38 -2013-Sep-20 09:11:53 4171688.75169 872112.40442 4730015.91620 11.80791 48.17158 529.64592 -6.97546 9.57906 5.05525 -5.16250 5.98300 -3.94027 7 3 4 2.38 -2013-Sep-20 09:11:53 4171689.42812 872114.48165 4730016.45616 11.80794 48.17158 530.77331 -5.08060 9.12905 6.18265 -3.26764 5.53299 -2.81288 7 3 4 2.38 -2013-Sep-20 09:11:53 4171688.31794 872114.85852 4730015.25997 11.80795 48.17158 529.20869 -4.48453 9.08359 4.61803 -2.67157 5.48753 -4.37750 7 3 4 2.38 -2013-Sep-20 09:11:53 4171686.67064 872113.32616 4730013.89299 11.80793 48.17158 526.90563 -5.64737 9.60710 2.31497 -3.83441 6.01104 -6.68056 7 3 4 2.38 -2013-Sep-20 09:11:53 4171687.62632 872113.30638 4730013.45230 11.80793 48.17158 527.19841 -5.86230 8.61916 2.60775 -4.04934 5.02311 -6.38778 7 3 4 2.38 -2013-Sep-20 09:11:53 4171687.54589 872111.64922 4730012.96994 11.80791 48.17158 526.56033 -7.46793 8.60882 1.96967 -5.65498 5.01277 -7.02586 7 3 4 2.38 -2013-Sep-20 09:11:54 4171691.51168 872114.32802 4730017.48494 11.80793 48.17157 532.87906 -5.65734 8.31888 8.28840 -3.84439 4.72282 -0.70713 7 3 4 2.38 -2013-Sep-20 09:11:54 4171691.82504 872114.51984 4730017.95495 11.80793 48.17157 533.46002 -5.53371 8.37453 8.86936 -3.72075 4.77846 -0.12617 7 3 4 2.38 -2013-Sep-20 09:11:54 4171695.55088 872118.26611 4730015.58240 11.80797 48.17153 534.63557 -2.62914 3.50349 10.04492 -0.81618 -0.09258 1.04939 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.67499 872119.86523 4730017.70657 11.80799 48.17153 537.17043 -1.29390 3.85636 12.57977 0.51906 0.26030 3.58424 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.06520 872118.54670 4730018.58839 11.80797 48.17154 537.24951 -2.45974 5.09027 12.65885 -0.64678 1.49421 3.66332 7 3 4 2.38 -2013-Sep-20 09:11:54 4171697.44169 872118.51567 4730016.78197 11.80797 48.17152 536.79779 -2.77179 2.88632 12.20713 -0.95883 -0.70975 3.21160 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.18880 872118.12150 4730016.40404 11.80797 48.17153 535.64451 -2.90123 3.60821 11.05385 -1.08827 0.01214 2.05832 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.77683 872119.67325 4730018.08203 11.80799 48.17153 537.49048 -1.50265 4.06176 12.89982 0.31031 0.46570 3.90429 7 3 4 2.38 -2013-Sep-20 09:11:54 4171699.02001 872120.06924 4730019.85566 11.80798 48.17153 540.33046 -1.57407 3.54810 15.73981 0.23889 -0.04797 6.74427 7 3 4 2.38 -2013-Sep-20 09:11:54 4171698.82588 872120.41467 4730019.60166 11.80799 48.17153 540.06160 -1.19622 3.46762 15.47095 0.61674 -0.12844 6.47541 7 3 4 2.38 -2013-Sep-20 09:11:54 4171697.29935 872120.15303 4730017.94527 11.80799 48.17153 537.79515 -1.13995 3.51628 13.20449 0.67301 -0.07978 4.20896 7 3 4 2.38 -2013-Sep-20 09:11:54 4171694.66465 872117.64772 4730013.33391 11.80796 48.17152 532.29721 -3.05310 2.74465 7.70656 -1.24014 -0.85141 -1.28898 7 3 4 2.38 -2013-Sep-20 09:11:54 4171692.11116 872116.62846 4730011.91759 11.80796 48.17153 529.43585 -3.52826 3.81797 4.84519 -1.71530 0.22191 -4.15034 7 3 4 2.38 -2013-Sep-20 09:11:54 4171693.99142 872117.41529 4730014.03835 11.80796 48.17153 532.35092 -3.14284 3.74092 7.76027 -1.32988 0.14486 -1.23527 7 3 4 2.38 -2013-Sep-20 09:11:54 4171691.72624 872116.29942 4730011.10037 11.80795 48.17153 528.53073 -3.77157 3.60389 3.94008 -1.95861 0.00783 -5.05545 7 3 4 2.38 -2013-Sep-20 09:11:54 4171695.11009 872118.59125 4730018.09022 11.80798 48.17155 536.26089 -2.22069 5.44788 11.67024 -0.40773 1.85182 2.67471 7 3 4 2.38 -2013-Sep-20 09:11:54 4171694.25695 872117.25575 4730016.38096 11.80796 48.17154 534.24807 -3.35334 5.13387 9.65741 -1.54038 1.53781 0.66188 7 3 4 2.38 -2013-Sep-20 09:11:54 4171693.02937 872116.83171 4730014.57371 11.80796 48.17154 532.04218 -3.51721 4.88864 7.45152 -1.70425 1.29257 -1.54401 7 3 4 2.38 -2013-Sep-20 09:11:54 4171691.02841 872116.92619 4730010.81756 11.80797 48.17153 527.95000 -3.01526 3.82869 3.35934 -1.20231 0.23263 -5.63619 7 3 4 2.38 -2013-Sep-20 09:11:54 4171692.96774 872117.52886 4730011.19043 11.80797 48.17152 529.57606 -2.82219 2.57096 4.98540 -1.00924 -1.02510 -4.01013 7 3 4 2.38 -2013-Sep-20 09:11:54 4171693.60390 872117.65830 4730013.73263 11.80797 48.17153 531.90331 -2.82567 3.78262 7.31265 -1.01271 0.18656 -1.68288 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.10904 872118.55041 4730016.02482 11.80797 48.17153 535.36840 -2.46507 3.34808 10.77775 -0.65211 -0.24798 1.78222 7 3 4 2.38 -2013-Sep-20 09:11:54 4171693.62821 872117.58298 4730016.42395 11.80797 48.17155 533.91432 -2.90438 5.57123 9.32367 -1.09142 1.97517 0.32814 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.74863 872117.80728 4730016.31728 11.80796 48.17153 535.90243 -3.32336 3.18993 11.31177 -1.51040 -0.40613 2.31624 7 3 4 2.38 -2013-Sep-20 09:11:54 4171696.73840 872119.19594 4730018.25690 11.80798 48.17154 537.53056 -1.96199 4.27919 12.93990 -0.14903 0.68313 3.94437 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.85869 872119.28301 4730015.82901 11.80799 48.17154 533.85347 -1.28748 4.74714 9.26281 0.52547 1.15108 0.26728 7 3 4 2.38 -2013-Sep-20 09:11:55 4171692.22913 872118.76933 4730014.20304 11.80799 48.17154 531.50802 -1.45683 4.92966 6.91736 0.35613 1.33360 -2.07817 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.70261 872119.31345 4730015.79369 11.80799 48.17154 533.72941 -1.22575 4.83278 9.13876 0.58720 1.23672 0.14322 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.19882 872119.82288 4730014.85422 11.80800 48.17154 532.77002 -0.62401 4.49602 8.17937 1.18895 0.89996 -0.81616 7 3 4 2.38 -2013-Sep-20 09:11:55 4171692.32530 872118.05042 4730012.73710 11.80798 48.17153 530.38036 -2.18021 3.99150 5.78970 -0.36725 0.39544 -3.20583 7 3 4 2.38 -2013-Sep-20 09:11:55 4171696.58322 872119.06658 4730017.54688 11.80798 48.17153 536.88253 -2.05686 3.93858 12.29188 -0.24390 0.34252 3.29635 7 3 4 2.38 -2013-Sep-20 09:11:55 4171694.54147 872118.56212 4730014.96255 11.80798 48.17153 533.55516 -2.13284 3.78121 8.96450 -0.31988 0.18515 -0.03103 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.85205 872117.08864 4730013.83536 11.80796 48.17153 532.06411 -3.43407 3.75701 7.47345 -1.62111 0.16094 -1.52208 7 3 4 2.38 -2013-Sep-20 09:11:55 4171694.94468 872116.72352 4730015.78012 11.80795 48.17154 534.17666 -4.01505 4.31271 9.58601 -2.20209 0.71665 0.59048 7 3 4 2.38 -2013-Sep-20 09:11:55 4171695.16755 872118.14930 4730016.69910 11.80797 48.17154 535.20150 -2.66504 4.54562 10.61084 -0.85208 0.94955 1.61531 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.61509 872117.19836 4730016.43394 11.80796 48.17155 533.86071 -3.27818 5.64611 9.27006 -1.46522 2.05005 0.27452 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.09688 872117.15469 4730014.25086 11.80796 48.17154 531.88976 -3.21488 4.57484 7.29910 -1.40192 0.97878 -1.69643 7 3 4 2.38 -2013-Sep-20 09:11:55 4171693.16336 872118.85560 4730015.04595 11.80798 48.17154 532.75774 -1.56356 4.79724 8.16708 0.24939 1.20117 -0.82845 7 3 4 2.38 -2013-Sep-20 09:11:55 4171691.17820 872116.93284 4730013.18172 11.80796 48.17155 529.81033 -3.03940 5.29509 5.21967 -1.22644 1.69903 -3.77586 7 3 4 2.38 -2013-Sep-20 09:11:55 4171696.49781 872119.37470 4730018.74999 11.80798 48.17154 537.76532 -1.73779 4.75625 13.17466 0.07517 1.16019 4.17913 7 3 4 2.38 -2013-Sep-20 09:11:55 4171694.73266 872118.56638 4730016.69162 11.80798 48.17154 534.96896 -2.16780 4.79423 10.37830 -0.35484 1.19817 1.38277 7 3 4 2.38 -2013-Sep-20 09:11:55 4171691.58568 872117.19325 4730013.85910 11.80797 48.17155 530.61661 -2.86789 5.40993 6.02595 -1.05493 1.81387 -2.96958 7 3 4 2.38 -2013-Sep-20 09:11:55 4171691.02426 872116.64629 4730013.51827 11.80796 48.17155 529.92150 -3.28839 5.67551 5.33085 -1.47543 2.07945 -3.66469 7 3 4 2.38 -2013-Sep-20 09:11:55 4171691.44401 872116.22770 4730013.94906 11.80795 48.17155 530.45940 -3.78401 5.72048 5.86874 -1.97106 2.12442 -3.12679 7 3 4 2.38 -2013-Sep-20 09:11:55 4171690.78676 872117.59316 4730015.54571 11.80797 48.17156 531.40642 -2.31296 7.05647 6.81577 -0.50000 3.46041 -2.17977 7 3 4 2.38 -2013-Sep-20 09:11:55 4171688.22556 872116.06109 4730011.55007 11.80796 48.17156 526.54808 -3.28850 6.49345 1.95743 -1.47554 2.89739 -7.03811 7 3 4 2.38 -2013-Sep-20 09:11:55 4171689.65593 872115.23434 4730014.26024 11.80795 48.17156 529.38846 -4.39046 7.38365 4.79780 -2.57750 3.78759 -4.19773 7 3 4 2.38 -2013-Sep-20 09:11:55 4171689.83049 872114.17239 4730013.38866 11.80793 48.17156 528.70804 -5.46566 6.83700 4.11738 -3.65270 3.24094 -4.87815 7 3 4 2.38 -2013-Sep-20 09:11:55 4171691.12185 872113.74860 4730014.77388 11.80792 48.17156 530.52538 -6.14473 6.88354 5.93472 -4.33177 3.28748 -3.06081 7 3 4 2.38 -2013-Sep-20 09:11:55 4171694.18539 872116.30189 4730019.20345 11.80795 48.17156 536.17434 -4.27238 7.21383 11.58368 -2.45942 3.61777 2.58815 7 3 4 2.38 -2013-Sep-20 09:11:56 4171699.19494 872117.78896 4730022.47860 11.80795 48.17155 542.08794 -3.84189 5.51745 17.49728 -2.02893 1.92138 8.50175 7 3 4 2.38 -2013-Sep-20 09:11:56 4171696.77203 872117.52171 4730019.27596 11.80796 48.17154 538.08338 -3.60768 5.18956 13.49272 -1.79472 1.59350 4.49719 7 3 4 2.38 diff --git a/src/utils/gnuplot/4_GPS_3_GAL_accuracy_precision.jpeg b/src/utils/gnuplot/4_GPS_3_GAL_accuracy_precision.jpeg deleted file mode 100644 index c76d689f7..000000000 Binary files a/src/utils/gnuplot/4_GPS_3_GAL_accuracy_precision.jpeg and /dev/null differ diff --git a/src/utils/gnuplot/8_GALILEO_accuracy_precision.jpeg b/src/utils/gnuplot/8_GALILEO_accuracy_precision.jpeg deleted file mode 100644 index ef45b9140..000000000 Binary files a/src/utils/gnuplot/8_GALILEO_accuracy_precision.jpeg and /dev/null differ diff --git a/src/utils/gnuplot/8_GAL_GNSS_SDR_solutions.txt b/src/utils/gnuplot/8_GAL_GNSS_SDR_solutions.txt deleted file mode 100644 index 25314d167..000000000 --- a/src/utils/gnuplot/8_GAL_GNSS_SDR_solutions.txt +++ /dev/null @@ -1,1001 +0,0 @@ - time X [m] Y [m] Z [m] Long [deg] Lat [deg] h [m] E(Acc) [m] N(Acc) [m] Up(Acc) [m] E(Pre) [m] N(Pre) [m] Up(Pre) [m] Tot Sat Gal GPS GDOP -2013-Sep-20 09:11:06 4171690.09174 872117.69124 4730009.42695 11.80798 48.17153 526.40674 -2.07473 3.46782 1.81609 -3.26635 1.54475 -11.95848 8 8 0 1.77 -2013-Sep-20 09:11:06 4171695.90195 872122.87945 4730017.22237 11.80803 48.17153 536.71635 1.81473 3.63768 12.12569 0.62312 1.71460 -1.64887 8 8 0 1.77 -2013-Sep-20 09:11:06 4171695.87749 872123.03123 4730016.66439 11.80803 48.17153 536.30532 1.96830 3.26026 11.71466 0.77668 1.33718 -2.05990 8 8 0 1.77 -2013-Sep-20 09:11:06 4171695.91773 872123.24279 4730016.35685 11.80803 48.17152 536.13130 2.16715 2.99355 11.54064 0.97554 1.07047 -2.23392 8 8 0 1.77 -2013-Sep-20 09:11:06 4171695.80487 872123.64854 4730016.04804 11.80804 48.17152 535.88289 2.58741 2.80805 11.29223 1.39580 0.88497 -2.48233 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.04572 872123.57449 4730016.18529 11.80804 48.17152 536.13228 2.46564 2.73520 11.54162 1.27403 0.81213 -2.23294 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.85509 872123.52515 4730015.79008 11.80804 48.17151 536.35940 2.25173 1.88882 11.76875 1.06011 -0.03425 -2.00582 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.91214 872123.33123 4730015.96118 11.80803 48.17152 536.49768 2.05024 1.99089 11.90702 0.85862 0.06781 -1.86754 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.23707 872123.07517 4730016.02781 11.80803 48.17152 536.07170 1.93773 2.56675 11.48104 0.74612 0.64368 -2.29352 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.58685 872123.30575 4730016.13060 11.80803 48.17152 536.40809 2.09185 2.34502 11.81744 0.90024 0.42194 -1.95712 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.87751 872123.33042 4730016.34070 11.80803 48.17152 536.75776 2.05653 2.26937 12.16711 0.86491 0.34630 -1.60746 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.53195 872123.66688 4730015.87975 11.80804 48.17152 536.23462 2.45658 2.16271 11.64396 1.26497 0.23963 -2.13060 8 8 0 1.77 -2013-Sep-20 09:11:06 4171696.57287 872123.68392 4730016.09343 11.80804 48.17152 536.42288 2.46489 2.27277 11.83222 1.27327 0.34969 -1.94234 8 8 0 1.77 -2013-Sep-20 09:11:06 4171697.02839 872123.70216 4730016.50696 11.80804 48.17152 537.03087 2.38953 2.21352 12.44021 1.19791 0.29045 -1.33435 8 8 0 1.77 -2013-Sep-20 09:11:06 4171697.69570 872123.58690 4730016.57371 11.80803 48.17151 537.50049 2.14015 1.78890 12.90984 0.94853 -0.13418 -0.86472 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.06350 872123.88883 4730016.53937 11.80804 48.17151 537.75620 2.36043 1.45168 13.16555 1.16882 -0.47139 -0.60902 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.67387 872123.60070 4730016.87180 11.80803 48.17151 538.36303 1.95350 1.27213 13.77238 0.76188 -0.65094 -0.00219 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.33898 872123.79140 4730016.61963 11.80804 48.17151 537.98254 2.20869 1.31914 13.39188 1.01707 -0.60393 -0.38268 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.10171 872124.16670 4730016.64385 11.80804 48.17151 537.89692 2.62460 1.45112 13.30627 1.43298 -0.47195 -0.46830 8 8 0 1.77 -2013-Sep-20 09:11:06 4171699.18887 872124.09479 4730017.20895 11.80804 48.17151 539.01787 2.33174 1.04601 14.42722 1.14013 -0.87707 0.65266 8 8 0 1.77 -2013-Sep-20 09:11:06 4171699.46096 872124.18783 4730017.06175 11.80804 48.17150 539.09851 2.36714 0.73520 14.50785 1.17552 -1.18787 0.73329 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.71337 872124.28852 4730016.47044 11.80804 48.17151 538.18362 2.61867 0.87078 13.59296 1.42705 -1.05230 -0.18160 8 8 0 1.77 -2013-Sep-20 09:11:06 4171698.84586 872124.44077 4730016.25661 11.80804 48.17150 538.13154 2.74060 0.60832 13.54089 1.54898 -1.31475 -0.23367 8 8 0 1.77 -2013-Sep-20 09:11:06 4171699.23296 872124.29130 4730016.74645 11.80804 48.17150 538.72885 2.51508 0.67544 14.13819 1.32346 -1.24763 0.36363 8 8 0 1.77 -2013-Sep-20 09:11:07 4171699.85309 872124.00482 4730016.76314 11.80803 48.17150 539.10700 2.10775 0.27795 14.51634 0.91614 -1.64512 0.74178 8 8 0 1.77 -2013-Sep-20 09:11:07 4171700.44920 872124.15646 4730016.95920 11.80803 48.17150 539.66292 2.13420 -0.04921 15.07227 0.94259 -1.97229 1.29770 8 8 0 1.77 -2013-Sep-20 09:11:07 4171700.84145 872124.12219 4730016.95783 11.80803 48.17149 539.91328 2.02039 -0.33099 15.32263 0.82877 -2.25407 1.54807 8 8 0 1.77 -2013-Sep-20 09:11:07 4171702.64676 872123.97936 4730018.00266 11.80803 48.17149 541.85083 1.51116 -0.92916 17.26017 0.31954 -2.85224 3.48561 8 8 0 1.77 -2013-Sep-20 09:11:07 4171702.80212 872124.05742 4730018.23628 11.80803 48.17149 542.13698 1.55577 -0.89858 17.54633 0.36415 -2.82166 3.77176 8 8 0 1.77 -2013-Sep-20 09:11:07 4171703.15548 872123.78902 4730019.14642 11.80802 48.17149 543.00921 1.22074 -0.50841 18.41855 0.02912 -2.43149 4.64399 8 8 0 1.77 -2013-Sep-20 09:11:07 4171703.66010 872123.52228 4730019.83110 11.80802 48.17149 543.81240 0.85639 -0.37918 19.22175 -0.33523 -2.30225 5.44719 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.12674 872123.19999 4730020.13818 11.80801 48.17149 544.30186 0.44543 -0.46560 19.71120 -0.74619 -2.38868 5.93664 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.39919 872123.03315 4730020.38764 11.80801 48.17149 544.64283 0.22637 -0.47251 20.05217 -0.96525 -2.39559 6.27761 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.36739 872123.08830 4730021.07685 11.80801 48.17150 545.14315 0.28685 0.00191 20.55250 -0.90477 -1.92117 6.77793 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.35253 872123.27179 4730020.94373 11.80801 48.17150 545.05931 0.46950 -0.10401 20.46865 -0.72212 -2.02709 6.69409 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.28703 872123.16709 4730021.26569 11.80801 48.17149 545.89495 0.17579 -0.55493 21.30429 -1.01583 -2.47801 7.52973 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.61945 872123.31400 4730020.46477 11.80801 48.17149 544.88241 0.45619 -0.62455 20.29176 -0.73542 -2.54763 6.51719 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.22865 872123.19679 4730020.98194 11.80801 48.17149 545.64946 0.21681 -0.70612 21.05881 -0.97481 -2.62920 7.28424 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.29153 872123.10987 4730021.28873 11.80801 48.17149 545.90725 0.11886 -0.53412 21.31659 -1.07276 -2.45720 7.54203 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.32056 872122.86269 4730021.39416 11.80800 48.17149 545.97103 -0.12903 -0.44730 21.38038 -1.32065 -2.37038 7.60581 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.21878 872122.83842 4730021.27904 11.80800 48.17149 545.81550 -0.13196 -0.44614 21.22484 -1.32357 -2.36922 7.45028 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.29993 872122.69109 4730021.34134 11.80800 48.17149 545.89478 -0.29278 -0.44130 21.30413 -1.48439 -2.36438 7.52956 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.12943 872122.44827 4730021.42910 11.80800 48.17150 545.81573 -0.49556 -0.22140 21.22508 -1.68718 -2.14448 7.45052 8 8 0 1.77 -2013-Sep-20 09:11:07 4171705.27132 872122.20763 4730021.06649 11.80800 48.17149 545.60532 -0.76015 -0.53002 21.01467 -1.95177 -2.45310 7.24010 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.46387 872122.19636 4730020.56629 11.80800 48.17150 544.70397 -0.60595 -0.27295 20.11331 -1.79757 -2.19603 6.33875 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.09102 872122.00552 4730019.84640 11.80800 48.17149 543.89811 -0.71645 -0.45200 19.30745 -1.90807 -2.37508 5.53289 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.03068 872122.16931 4730020.09435 11.80800 48.17150 544.06583 -0.54379 -0.26761 19.47518 -1.73541 -2.19068 5.70061 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.54052 872121.95102 4730019.91054 11.80799 48.17149 544.23189 -0.86179 -0.72877 19.64124 -2.05341 -2.65185 5.86667 8 8 0 1.77 -2013-Sep-20 09:11:07 4171704.52586 872121.68599 4730020.07563 11.80799 48.17149 544.30918 -1.11820 -0.56757 19.71852 -2.30982 -2.49064 5.94396 8 8 0 1.77 -2013-Sep-20 09:11:08 4171703.46781 872121.59008 4730019.42381 11.80799 48.17150 543.11970 -0.99558 -0.21592 18.52905 -2.18720 -2.13900 4.75448 8 8 0 1.77 -2013-Sep-20 09:11:08 4171703.56751 872121.39341 4730019.33126 11.80799 48.17149 543.08898 -1.20849 -0.32038 18.49832 -2.40010 -2.24346 4.72376 8 8 0 1.77 -2013-Sep-20 09:11:08 4171703.78695 872121.17941 4730019.32935 11.80799 48.17149 543.20160 -1.46286 -0.44908 18.61094 -2.65448 -2.37215 4.83638 8 8 0 1.77 -2013-Sep-20 09:11:08 4171702.38976 872121.19839 4730018.61087 11.80799 48.17150 541.75675 -1.15838 0.08795 17.16609 -2.34999 -1.83513 3.39153 8 8 0 1.77 -2013-Sep-20 09:11:08 4171701.44190 872120.89196 4730017.97117 11.80799 48.17150 540.61951 -1.26436 0.39941 16.02885 -2.45597 -1.52367 2.25429 8 8 0 1.77 -2013-Sep-20 09:11:08 4171701.17321 872120.84805 4730017.55023 11.80799 48.17150 540.12445 -1.25236 0.32134 15.53380 -2.44397 -1.60173 1.75923 8 8 0 1.77 -2013-Sep-20 09:11:08 4171700.64844 872120.79280 4730016.99803 11.80799 48.17150 539.36288 -1.19905 0.34426 14.77222 -2.39066 -1.57882 0.99766 8 8 0 1.77 -2013-Sep-20 09:11:08 4171700.72657 872120.72234 4730016.68361 11.80799 48.17150 539.16998 -1.28400 0.08833 14.57933 -2.47562 -1.83475 0.80476 8 8 0 1.77 -2013-Sep-20 09:11:08 4171700.51847 872120.71210 4730016.79140 11.80799 48.17150 539.11306 -1.25145 0.31356 14.52240 -2.44306 -1.60951 0.74784 8 8 0 1.77 -2013-Sep-20 09:11:08 4171699.59564 872120.58738 4730016.39961 11.80799 48.17150 538.20168 -1.18468 0.74438 13.61102 -2.37630 -1.17869 -0.16354 8 8 0 1.77 -2013-Sep-20 09:11:08 4171699.69147 872120.74568 4730015.50668 11.80799 48.17150 537.62047 -1.04934 0.05485 13.02982 -2.24096 -1.86823 -0.74475 8 8 0 1.77 -2013-Sep-20 09:11:08 4171699.67028 872120.96928 4730015.08224 11.80799 48.17150 537.32089 -0.82614 -0.24684 12.73023 -2.01776 -2.16992 -1.04433 8 8 0 1.77 -2013-Sep-20 09:11:08 4171699.13180 872120.92148 4730014.75810 11.80800 48.17150 536.72132 -0.76274 -0.06298 12.13066 -1.95436 -1.98605 -1.64390 8 8 0 1.77 -2013-Sep-20 09:11:08 4171698.54056 872120.79994 4730014.87738 11.80800 48.17150 536.40766 -0.76072 0.46634 11.81700 -1.95233 -1.45674 -1.95756 8 8 0 1.77 -2013-Sep-20 09:11:08 4171698.50011 872120.78189 4730014.88532 11.80800 48.17150 536.38471 -0.77011 0.50389 11.79405 -1.96173 -1.41919 -1.98051 8 8 0 1.77 -2013-Sep-20 09:11:08 4171698.01279 872120.82226 4730014.73284 11.80800 48.17150 535.95848 -0.63087 0.75149 11.36783 -1.82249 -1.17158 -2.40674 8 8 0 1.77 -2013-Sep-20 09:11:08 4171697.64538 872120.79023 4730014.75466 11.80800 48.17151 535.73052 -0.58704 1.03890 11.13987 -1.77865 -0.88417 -2.63470 8 8 0 1.77 -2013-Sep-20 09:11:08 4171697.90082 872120.86625 4730014.52607 11.80800 48.17150 535.73732 -0.56490 0.68855 11.14666 -1.75652 -1.23452 -2.62790 8 8 0 1.77 -2013-Sep-20 09:11:08 4171696.84326 872120.98850 4730014.35915 11.80800 48.17151 534.93926 -0.22883 1.32995 10.34860 -1.42044 -0.59312 -3.42596 8 8 0 1.77 -2013-Sep-20 09:11:08 4171695.60891 872120.90577 4730014.10071 11.80800 48.17152 533.92962 -0.05722 2.07051 9.33896 -1.24884 0.14744 -4.43560 8 8 0 1.77 -2013-Sep-20 09:11:08 4171695.08337 872120.85036 4730013.77167 11.80801 48.17152 533.33381 -0.00391 2.24285 8.74315 -1.19553 0.31977 -5.03141 8 8 0 1.77 -2013-Sep-20 09:11:08 4171694.09677 872120.84585 4730013.32604 11.80801 48.17152 532.35709 0.19357 2.66594 7.76644 -0.99805 0.74287 -6.00813 8 8 0 1.77 -2013-Sep-20 09:11:08 4171694.13998 872120.97457 4730013.49489 11.80801 48.17152 532.52867 0.31072 2.72741 7.93802 -0.88090 0.80433 -5.83655 8 8 0 1.77 -2013-Sep-20 09:11:08 4171693.90878 872120.92639 4730013.89902 11.80801 48.17153 532.67231 0.31087 3.17290 8.08166 -0.88075 1.24983 -5.69290 8 8 0 1.77 -2013-Sep-20 09:11:08 4171693.35721 872120.96302 4730013.44275 11.80801 48.17153 531.97727 0.45959 3.26532 7.38661 -0.73202 1.34225 -6.38795 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.26965 872120.98206 4730013.41088 11.80801 48.17153 531.89896 0.49615 3.30504 7.30831 -0.69546 1.38196 -6.46625 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.42279 872120.46546 4730013.89642 11.80801 48.17153 532.29022 -0.04085 3.59593 7.69957 -1.23247 1.67285 -6.07499 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.28081 872120.22254 4730013.87537 11.80800 48.17153 532.14870 -0.24958 3.72248 7.55805 -1.44119 1.79940 -6.21652 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.05769 872120.19556 4730014.09385 11.80800 48.17153 532.16217 -0.23033 4.03504 7.57151 -1.42195 2.11197 -6.20305 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.16991 872120.29757 4730014.99737 11.80800 48.17154 532.92260 -0.15345 4.54019 8.33194 -1.34506 2.61712 -5.44262 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.51563 872120.33168 4730015.60656 11.80800 48.17154 533.60687 -0.19080 4.68910 9.01622 -1.38242 2.76602 -4.75834 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.82702 872120.32165 4730015.89222 11.80800 48.17154 534.02164 -0.26435 4.65402 9.43098 -1.45596 2.73095 -4.34358 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.23686 872120.22858 4730015.86014 11.80800 48.17154 533.59978 -0.23468 5.07726 9.00913 -1.42629 3.15419 -4.76544 8 8 0 1.77 -2013-Sep-20 09:11:09 4171693.91039 872119.99872 4730016.40519 11.80800 48.17154 534.41423 -0.59750 4.98456 9.82357 -1.78911 3.06148 -3.95099 8 8 0 1.77 -2013-Sep-20 09:11:09 4171694.67842 872119.82583 4730017.41799 11.80799 48.17154 535.64668 -0.92389 5.12616 11.05602 -2.11551 3.20309 -2.71854 8 8 0 1.77 -2013-Sep-20 09:11:09 4171695.38824 872119.66040 4730018.64519 11.80799 48.17155 537.00190 -1.23108 5.45209 12.41124 -2.42269 3.52902 -1.36332 8 8 0 1.77 -2013-Sep-20 09:11:09 4171696.14748 872119.48348 4730019.58292 11.80798 48.17155 538.17213 -1.55962 5.55068 13.58147 -2.75124 3.62760 -0.19309 8 8 0 1.77 -2013-Sep-20 09:11:09 4171696.35202 872119.75902 4730020.40644 11.80799 48.17155 538.95689 -1.33176 5.90868 14.36624 -2.52338 3.98561 0.59167 8 8 0 1.77 -2013-Sep-20 09:11:09 4171696.88313 872119.57599 4730020.96384 11.80798 48.17155 539.69397 -1.61960 5.92094 15.10331 -2.81122 3.99786 1.32875 8 8 0 1.77 -2013-Sep-20 09:11:09 4171696.74152 872119.83100 4730021.09193 11.80799 48.17155 539.73177 -1.34102 6.07077 15.14111 -2.53263 4.14769 1.36655 8 8 0 1.77 -2013-Sep-20 09:11:09 4171697.49636 872119.43551 4730021.60929 11.80798 48.17155 540.55606 -1.88260 5.92553 15.96540 -3.07421 4.00246 2.19084 8 8 0 1.77 -2013-Sep-20 09:11:09 4171698.55101 872119.63121 4730022.17056 11.80798 48.17155 541.68946 -1.90686 5.50077 17.09880 -3.09848 3.57770 3.32424 8 8 0 1.77 -2013-Sep-20 09:11:09 4171698.65235 872119.79319 4730022.74501 11.80798 48.17155 542.20576 -1.76904 5.78526 17.61510 -2.96066 3.86219 3.84054 8 8 0 1.77 -2013-Sep-20 09:11:09 4171699.15523 872119.98931 4730023.14050 11.80798 48.17155 542.85551 -1.67998 5.65232 18.26485 -2.87160 3.72925 4.49029 8 8 0 1.77 -2013-Sep-20 09:11:09 4171699.69836 872120.06239 4730022.99798 11.80798 48.17154 543.11383 -1.71959 5.14999 18.52317 -2.91121 3.22692 4.74861 8 8 0 1.77 -2013-Sep-20 09:11:09 4171700.43395 872120.14453 4730023.06653 11.80798 48.17154 543.65630 -1.78971 4.64665 19.06565 -2.98132 2.72358 5.29108 8 8 0 1.77 -2013-Sep-20 09:11:09 4171700.99916 872120.20326 4730023.33523 11.80798 48.17154 544.23351 -1.84789 4.40465 19.64285 -3.03950 2.48157 5.86829 8 8 0 1.77 -2013-Sep-20 09:11:09 4171701.38000 872120.19520 4730023.24155 11.80798 48.17153 544.41120 -1.93370 4.06563 19.82055 -3.12532 2.14255 6.04598 8 8 0 1.77 -2013-Sep-20 09:11:09 4171701.05789 872120.68972 4730022.56067 11.80799 48.17153 543.76107 -1.38374 3.77108 19.17041 -2.57536 1.84800 5.39585 8 8 0 1.77 -2013-Sep-20 09:11:09 4171701.46908 872120.91525 4730022.18295 11.80799 48.17153 543.77882 -1.24712 3.18488 19.18816 -2.43874 1.26180 5.41360 8 8 0 1.77 -2013-Sep-20 09:11:10 4171701.58023 872120.93919 4730022.09128 11.80799 48.17153 543.78632 -1.24643 3.03902 19.19567 -2.43805 1.11595 5.42111 8 8 0 1.77 -2013-Sep-20 09:11:10 4171701.80771 872120.92451 4730022.17428 11.80799 48.17152 543.99467 -1.30735 2.93070 19.40402 -2.49897 1.00762 5.62945 8 8 0 1.77 -2013-Sep-20 09:11:10 4171702.10623 872120.94227 4730021.68139 11.80799 48.17152 543.82469 -1.35106 2.38154 19.23404 -2.54268 0.45847 5.45947 8 8 0 1.77 -2013-Sep-20 09:11:10 4171701.70547 872121.06963 4730021.31991 11.80799 48.17152 543.31111 -1.14438 2.41336 18.72045 -2.33600 0.49028 4.94589 8 8 0 1.77 -2013-Sep-20 09:11:10 4171701.29361 872121.27502 4730020.42354 11.80799 48.17152 542.40235 -0.85906 2.08465 17.81169 -2.05068 0.16157 4.03713 8 8 0 1.77 -2013-Sep-20 09:11:10 4171702.15788 872121.29444 4730020.53918 11.80799 48.17151 543.05535 -1.01690 1.52843 18.46470 -2.20852 -0.39465 4.69013 8 8 0 1.77 -2013-Sep-20 09:11:10 4171701.31166 872121.48948 4730019.49044 11.80800 48.17151 541.74810 -0.65283 1.41649 17.15744 -1.84445 -0.50658 3.38288 8 8 0 1.77 -2013-Sep-20 09:11:10 4171700.67722 872121.69934 4730018.88083 11.80800 48.17151 540.90834 -0.31758 1.44069 16.31769 -1.50920 -0.48239 2.54312 8 8 0 1.77 -2013-Sep-20 09:11:10 4171700.47169 872121.57520 4730019.02829 11.80800 48.17151 540.86711 -0.39704 1.70787 16.27645 -1.58866 -0.21521 2.50189 8 8 0 1.77 -2013-Sep-20 09:11:10 4171700.26985 872121.78261 4730018.47553 11.80800 48.17151 540.35177 -0.15272 1.45482 15.76112 -1.34433 -0.46826 1.98656 8 8 0 1.77 -2013-Sep-20 09:11:10 4171699.73759 872122.01538 4730018.01140 11.80801 48.17151 539.69024 0.18405 1.49802 15.09959 -1.00757 -0.42506 1.32502 8 8 0 1.77 -2013-Sep-20 09:11:10 4171700.16240 872121.76984 4730017.92161 11.80800 48.17151 539.86713 -0.14323 1.16572 15.27648 -1.33484 -0.75735 1.50191 8 8 0 1.77 -2013-Sep-20 09:11:10 4171699.29143 872121.89182 4730017.54829 11.80801 48.17151 539.03704 0.15440 1.53343 14.44639 -1.03722 -0.38965 0.67183 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.64043 872122.24875 4730016.64809 11.80801 48.17151 537.99001 0.63700 1.35347 13.39936 -0.55462 -0.56960 -0.37521 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.18542 872122.54080 4730015.68603 11.80802 48.17151 537.01597 1.01597 0.99921 12.42531 -0.17564 -0.92386 -1.34925 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.10300 872123.04312 4730016.01069 11.80803 48.17151 537.27263 1.52453 1.19926 12.68198 0.33292 -0.72382 -1.09259 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.38702 872122.90404 4730016.09107 11.80802 48.17151 537.49895 1.33027 1.06691 12.90830 0.13866 -0.85616 -0.86627 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.97352 872122.98792 4730016.08821 11.80802 48.17150 537.89112 1.29236 0.62443 13.30047 0.10075 -1.29864 -0.47409 8 8 0 1.77 -2013-Sep-20 09:11:10 4171699.03122 872123.03134 4730016.27658 11.80802 48.17150 538.07508 1.32306 0.70135 13.48443 0.13144 -1.22173 -0.29014 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.24631 872123.17208 4730015.22339 11.80803 48.17150 536.79713 1.62143 0.55001 12.20648 0.42982 -1.37307 -1.56809 8 8 0 1.77 -2013-Sep-20 09:11:10 4171698.34021 872123.15179 4730015.39629 11.80803 48.17150 536.98449 1.58236 0.59992 12.39384 0.39074 -1.32315 -1.38073 8 8 0 1.77 -2013-Sep-20 09:11:10 4171697.25542 872123.30277 4730015.09553 11.80803 48.17151 536.07285 1.95213 1.16755 11.48219 0.76052 -0.75553 -2.29237 8 8 0 1.77 -2013-Sep-20 09:11:10 4171696.98971 872123.22913 4730014.99540 11.80803 48.17151 535.81474 1.93442 1.30580 11.22408 0.74281 -0.61728 -2.55048 8 8 0 1.77 -2013-Sep-20 09:11:10 4171697.24527 872123.46579 4730014.80902 11.80803 48.17151 535.87498 2.11377 0.95902 11.28432 0.92216 -0.96406 -2.49024 8 8 0 1.77 -2013-Sep-20 09:11:10 4171697.63081 872123.46298 4730014.65850 11.80803 48.17150 536.01411 2.03214 0.57786 11.42346 0.84052 -1.34521 -2.35111 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.58770 872123.52009 4730014.77275 11.80803 48.17150 536.07890 2.09685 0.67678 11.48824 0.90524 -1.24629 -2.28632 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.37301 872123.46831 4730014.35261 11.80803 48.17150 535.61862 2.09010 0.56108 11.02797 0.89849 -1.36199 -2.74660 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.62418 872123.51841 4730014.53636 11.80803 48.17150 535.92634 2.08774 0.49279 11.33569 0.89612 -1.43029 -2.43888 8 8 0 1.77 -2013-Sep-20 09:11:11 4171698.05794 872123.35000 4730014.81075 11.80803 48.17150 536.39097 1.83414 0.38508 11.80032 0.64252 -1.53800 -1.97425 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.76922 872123.72142 4730014.69968 11.80804 48.17150 536.17041 2.25678 0.46496 11.57976 1.06516 -1.45812 -2.19480 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.49693 872124.08241 4730014.27280 11.80804 48.17150 535.72385 2.66585 0.32383 11.13320 1.47423 -1.59924 -2.64137 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.43463 872124.09685 4730013.67977 11.80804 48.17150 535.24326 2.69273 -0.02843 10.65260 1.50111 -1.95150 -3.12196 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.89277 872124.38960 4730013.65462 11.80804 48.17149 535.56354 2.88553 -0.42399 10.97289 1.69392 -2.34707 -2.80168 8 8 0 1.77 -2013-Sep-20 09:11:11 4171696.87298 872124.47881 4730012.99203 11.80805 48.17150 534.41628 3.18155 -0.13567 9.82563 1.98993 -2.05874 -3.94894 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.14707 872124.58215 4730013.49125 11.80805 48.17150 534.98130 3.22661 -0.01841 10.39064 2.03499 -1.94149 -3.38392 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.36153 872124.61276 4730012.93030 11.80805 48.17149 534.70748 3.21268 -0.55359 10.11682 2.02107 -2.47667 -3.65774 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.74458 872124.69070 4730013.17259 11.80805 48.17149 535.14871 3.21059 -0.68328 10.55805 2.01897 -2.60636 -3.21651 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.43006 872124.96244 4730013.10714 11.80805 48.17149 534.93171 3.54094 -0.53897 10.34105 2.34933 -2.46204 -3.43351 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.89405 872125.08445 4730013.57194 11.80805 48.17149 535.59759 3.56543 -0.58602 11.00694 2.37381 -2.50910 -2.76763 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.76316 872125.18967 4730013.17045 11.80806 48.17149 535.22734 3.69520 -0.77434 10.63668 2.50358 -2.69742 -3.13788 8 8 0 1.77 -2013-Sep-20 09:11:11 4171698.11365 872125.17006 4730013.59261 11.80805 48.17149 535.76803 3.60429 -0.74546 11.17738 2.41267 -2.66853 -2.59719 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.03236 872125.23536 4730013.06559 11.80806 48.17149 534.67837 3.88947 -0.31822 10.08772 2.69785 -2.24129 -3.68685 8 8 0 1.77 -2013-Sep-20 09:11:11 4171696.70714 872125.55944 4730012.24128 11.80806 48.17149 533.89608 4.27324 -0.68016 9.30542 3.08162 -2.60324 -4.46914 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.00094 872125.50340 4730012.20750 11.80806 48.17149 534.05504 4.15827 -0.90844 9.46439 2.96665 -2.83151 -4.31018 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.67318 872125.34472 4730012.12995 11.80806 48.17148 534.41444 3.86539 -1.42628 9.82378 2.67377 -3.34935 -3.95078 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.01248 872125.23489 4730011.74546 11.80806 48.17149 533.68165 3.89307 -1.18404 9.09100 2.70146 -3.10712 -4.68357 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.11120 872124.97548 4730011.18131 11.80805 48.17148 533.29032 3.61895 -1.59272 8.69966 2.42734 -3.51580 -5.07490 8 8 0 1.77 -2013-Sep-20 09:11:11 4171697.03702 872124.95784 4730010.96111 11.80805 48.17148 533.07541 3.61687 -1.68279 8.48475 2.42525 -3.60586 -5.28981 8 8 0 1.77 -2013-Sep-20 09:11:11 4171696.45357 872124.92561 4730010.43556 11.80806 48.17148 532.29853 3.70472 -1.60280 7.70787 2.51310 -3.52588 -6.06669 8 8 0 1.77 -2013-Sep-20 09:11:11 4171696.91253 872124.74980 4730011.04404 11.80805 48.17148 533.02755 3.43871 -1.50496 8.43689 2.24709 -3.42803 -5.33767 8 8 0 1.77 -2013-Sep-20 09:11:12 4171697.48545 872124.56586 4730011.42133 11.80805 48.17148 533.65757 3.14142 -1.64317 9.06692 1.94980 -3.56624 -4.70765 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.54723 872124.67524 4730011.11138 11.80805 48.17149 532.82908 3.44048 -1.18224 8.23842 2.24886 -3.10531 -5.53614 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.43289 872124.31922 4730011.00900 11.80805 48.17149 532.62957 3.11539 -1.11283 8.03891 1.92377 -3.03590 -5.73565 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.02901 872124.19992 4730011.12240 11.80805 48.17149 532.43413 3.08126 -0.72443 7.84348 1.88964 -2.64751 -5.93109 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.93339 872124.10071 4730011.09896 11.80805 48.17149 532.34072 3.00372 -0.65519 7.75006 1.81210 -2.57827 -6.02450 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.67926 872123.79863 4730011.38134 11.80804 48.17150 532.34401 2.76003 -0.23545 7.75335 1.56841 -2.15853 -6.02121 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.41879 872123.66780 4730011.16299 11.80804 48.17150 531.99342 2.68527 -0.17115 7.40276 1.49365 -2.09422 -6.37180 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.30856 872123.72314 4730011.51216 11.80804 48.17150 532.18919 2.76199 0.13368 7.59854 1.57038 -1.78939 -6.17603 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.28496 872123.58033 4730011.37221 11.80804 48.17150 532.05001 2.62703 0.07933 7.45936 1.43542 -1.84374 -6.31521 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.59007 872123.70800 4730011.84700 11.80804 48.17150 532.62040 2.68957 0.15397 8.02975 1.49796 -1.76911 -5.74482 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.85486 872123.86528 4730012.08200 11.80804 48.17150 532.98983 2.78934 0.09357 8.39917 1.59772 -1.82950 -5.37539 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.37295 872123.74779 4730012.72629 11.80804 48.17150 533.79208 2.56831 0.16329 9.20143 1.37670 -1.75979 -4.57314 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.98598 872123.76908 4730014.43584 11.80804 48.17151 535.46903 2.46371 0.85301 10.87838 1.27209 -1.07006 -2.89619 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.63440 872124.14644 4730014.26565 11.80804 48.17151 535.16421 2.90503 0.93841 10.57355 1.71341 -0.98466 -3.20101 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.57511 872123.89087 4730013.64608 11.80804 48.17151 533.97616 2.87163 1.33681 9.38551 1.68001 -0.58627 -4.38906 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.74185 872123.78821 4730014.52518 11.80804 48.17151 534.72606 2.73702 1.81711 10.13540 1.54540 -0.10596 -3.63916 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.89201 872124.11853 4730015.45391 11.80805 48.17152 535.56120 3.02963 2.27660 10.97054 1.83801 0.35352 -2.80402 8 8 0 1.77 -2013-Sep-20 09:11:12 4171695.93631 872124.20820 4730015.76936 11.80805 48.17152 535.83741 3.10834 2.44099 11.24676 1.91672 0.51791 -2.52780 8 8 0 1.77 -2013-Sep-20 09:11:12 4171696.33357 872124.18666 4730016.35551 11.80805 48.17152 536.53057 3.00595 2.54543 11.93991 1.81434 0.62235 -1.83465 8 8 0 1.77 -2013-Sep-20 09:11:12 4171697.09059 872124.12562 4730017.11472 11.80804 48.17152 537.58213 2.79129 2.50891 12.99147 1.59968 0.58583 -0.78309 8 8 0 1.77 -2013-Sep-20 09:11:12 4171698.16713 872123.87417 4730017.85965 11.80804 48.17152 538.80565 2.32488 2.25884 14.21499 1.13326 0.33576 0.44043 8 8 0 1.77 -2013-Sep-20 09:11:12 4171698.28094 872123.56217 4730018.14339 11.80803 48.17152 539.04879 1.99619 2.41263 14.45814 0.80457 0.48956 0.68358 8 8 0 1.77 -2013-Sep-20 09:11:12 4171697.80614 872123.80347 4730017.99993 11.80804 48.17152 538.66488 2.32954 2.62646 14.07423 1.13793 0.70339 0.29966 8 8 0 1.77 -2013-Sep-20 09:11:12 4171697.94351 872123.90236 4730018.20429 11.80804 48.17152 538.92033 2.39823 2.64748 14.32968 1.20661 0.72441 0.55511 8 8 0 1.77 -2013-Sep-20 09:11:12 4171697.61721 872123.47607 4730018.19930 11.80803 48.17152 538.64543 2.04773 2.94715 14.05477 0.85611 1.02408 0.28021 8 8 0 1.77 -2013-Sep-20 09:11:13 4171697.82659 872123.35474 4730019.40804 11.80803 48.17153 539.66624 1.88612 3.61905 15.07558 0.69450 1.69597 1.30102 8 8 0 1.77 -2013-Sep-20 09:11:13 4171697.62176 872123.44606 4730019.62303 11.80803 48.17153 539.70519 2.01742 3.89790 15.11454 0.82581 1.97482 1.33997 8 8 0 1.77 -2013-Sep-20 09:11:13 4171698.87431 872122.93110 4730020.42684 11.80802 48.17153 541.05152 1.25705 3.59891 16.46086 0.06543 1.67583 2.68630 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.44533 872122.87079 4730020.60214 11.80802 48.17153 541.54667 1.08116 3.30852 16.95601 -0.11045 1.38544 3.18145 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.59584 872123.03366 4730020.57068 11.80802 48.17153 541.64370 1.20979 3.15293 17.05304 0.01817 1.22985 3.27848 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.73775 872123.35389 4730020.38648 11.80803 48.17152 541.64279 1.49420 2.87775 17.05213 0.30259 0.95467 3.27757 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.64311 872123.35640 4730020.46653 11.80803 48.17152 541.64100 1.51603 2.99977 17.05034 0.32441 1.07670 3.27578 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.21712 872123.75488 4730020.29000 11.80803 48.17153 541.28576 1.99324 3.13200 16.69510 0.80162 1.20892 2.92054 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.25337 872123.79198 4730020.93678 11.80803 48.17152 542.44922 1.81751 2.80187 17.85856 0.62589 0.87879 4.08400 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.02449 872123.86560 4730020.94229 11.80803 48.17152 542.31395 1.93640 2.96125 17.72330 0.74479 1.03818 3.94874 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.96229 872124.35053 4730020.88645 11.80804 48.17152 542.29792 2.42380 2.89543 17.70727 1.23218 0.97236 3.93271 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.94223 872124.13060 4730020.96577 11.80804 48.17152 542.31392 2.21263 2.99650 17.72326 1.02101 1.07342 3.94870 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.95551 872124.62050 4730021.65044 11.80804 48.17153 542.89963 2.68944 3.36872 18.30897 1.49783 1.44564 4.53441 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.47702 872124.58482 4730021.68841 11.80804 48.17152 543.26349 2.54781 3.01911 18.67283 1.35619 1.09603 4.89827 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.28095 872124.73247 4730021.54846 11.80804 48.17153 543.05136 2.73245 3.04627 18.46070 1.54083 1.12319 4.68614 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.07464 872125.24764 4730021.22221 11.80805 48.17152 542.74389 3.27894 2.90062 18.15324 2.08732 0.97754 4.37867 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.91011 872125.33933 4730021.13579 11.80805 48.17152 542.58460 3.40235 2.94901 17.99394 2.21074 1.02593 4.21938 8 8 0 1.77 -2013-Sep-20 09:11:13 4171700.21068 872125.31471 4730021.20773 11.80805 48.17152 542.83105 3.31675 2.78151 18.24040 2.12514 0.85843 4.46583 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.77136 872125.25646 4730021.13332 11.80805 48.17153 542.48087 3.34963 3.06120 17.89022 2.15802 1.13812 4.11566 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.25129 872124.96823 4730020.66025 11.80805 48.17153 541.74954 3.17392 3.16899 17.15888 1.98230 1.24591 3.38432 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.53066 872124.82540 4730021.16397 11.80805 48.17153 542.28776 2.97695 3.32293 17.69710 1.78533 1.39985 3.92254 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.40051 872124.60406 4730020.82907 11.80804 48.17153 541.92305 2.78693 3.22826 17.33239 1.59531 1.30519 3.55783 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.47454 872124.44292 4730020.92136 11.80804 48.17153 542.01815 2.61405 3.26039 17.42749 1.42243 1.33731 3.65293 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.49669 872124.20162 4730020.61892 11.80804 48.17153 541.77431 2.37332 3.07932 17.18366 1.18170 1.15625 3.40910 8 8 0 1.77 -2013-Sep-20 09:11:13 4171699.25102 872124.01342 4730020.01884 11.80804 48.17152 541.14111 2.23937 2.88701 16.55046 1.04776 0.96394 2.77589 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.91414 872124.18026 4730020.25250 11.80804 48.17153 541.11808 2.47162 3.26311 16.52742 1.28000 1.34004 2.75286 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.94558 872124.04481 4730020.46691 11.80804 48.17153 541.27989 2.33261 3.40383 16.68923 1.14099 1.48076 2.91467 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.48767 872123.97380 4730021.01330 11.80803 48.17153 542.03121 2.15217 3.38366 17.44055 0.96055 1.46058 3.66599 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.71391 872124.02221 4730021.77278 11.80803 48.17153 542.75143 2.15326 3.71776 18.16078 0.96164 1.79468 4.38621 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.66049 872123.79173 4730020.83737 11.80803 48.17153 541.98809 1.93859 3.16804 17.39743 0.74697 1.24496 3.62287 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.78546 872123.84826 4730021.08573 11.80803 48.17153 542.26244 1.96835 3.23390 17.67178 0.77673 1.31082 3.89722 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.12684 872123.52202 4730020.45431 11.80803 48.17153 541.31748 1.78378 3.34294 16.72683 0.59217 1.41986 2.95226 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.18592 872123.65229 4730020.31277 11.80803 48.17153 541.26836 1.89921 3.18559 16.67770 0.70759 1.26251 2.90314 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.46715 872123.57610 4730019.81331 11.80803 48.17153 540.41658 1.97172 3.38836 15.82592 0.78010 1.46529 2.05136 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.03759 872123.49818 4730018.52927 11.80803 48.17152 539.16874 1.98334 2.85722 14.57809 0.79173 0.93415 0.80353 8 8 0 1.77 -2013-Sep-20 09:11:14 4171697.72851 872123.34570 4730018.02089 11.80803 48.17152 538.56735 1.89734 2.76687 13.97669 0.70572 0.84379 0.20213 8 8 0 1.77 -2013-Sep-20 09:11:14 4171697.60037 872123.14062 4730017.86697 11.80803 48.17152 538.34102 1.72282 2.78896 13.75037 0.53121 0.86588 -0.02420 8 8 0 1.77 -2013-Sep-20 09:11:14 4171696.84702 872122.94029 4730016.92208 11.80803 48.17152 537.11782 1.68089 2.73883 12.52717 0.48927 0.81575 -1.24740 8 8 0 1.77 -2013-Sep-20 09:11:14 4171696.87150 872123.04146 4730016.81693 11.80803 48.17152 537.06926 1.77491 2.63542 12.47860 0.58329 0.71234 -1.29596 8 8 0 1.77 -2013-Sep-20 09:11:14 4171697.51058 872122.74303 4730016.72694 11.80802 48.17152 537.37867 1.35202 2.15478 12.78801 0.16040 0.23170 -0.98655 8 8 0 1.77 -2013-Sep-20 09:11:14 4171697.26988 872122.55436 4730016.04608 11.80802 48.17151 536.68845 1.21659 1.90504 12.09779 0.02498 -0.01804 -1.67677 8 8 0 1.77 -2013-Sep-20 09:11:14 4171697.45279 872122.67920 4730016.10089 11.80802 48.17151 536.86573 1.30137 1.78915 12.27507 0.10975 -0.13393 -1.49949 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.38837 872122.65631 4730016.78045 11.80802 48.17151 537.97971 1.08751 1.56345 13.38906 -0.10411 -0.35963 -0.38551 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.62159 872122.57993 4730016.27659 11.80802 48.17151 537.74609 0.96503 1.06897 13.15543 -0.22659 -0.85411 -0.61913 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.47894 872122.27335 4730015.74495 11.80801 48.17151 537.21498 0.69412 0.86520 12.62432 -0.49749 -1.05788 -1.15024 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.10468 872122.29384 4730016.13299 11.80801 48.17150 537.91540 0.58613 0.66447 13.32474 -0.60549 -1.25861 -0.44982 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.96387 872122.26785 4730016.47982 11.80801 48.17151 538.07837 0.58950 1.00243 13.48771 -0.60211 -0.92064 -0.28685 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.90590 872122.05418 4730016.57869 11.80801 48.17151 538.08504 0.39222 1.14323 13.49438 -0.79939 -0.77985 -0.28018 8 8 0 1.77 -2013-Sep-20 09:11:14 4171699.10318 872121.94893 4730016.31025 11.80801 48.17151 537.99943 0.24882 0.83636 13.40878 -0.94279 -1.08671 -0.36579 8 8 0 1.77 -2013-Sep-20 09:11:14 4171698.64134 872122.04454 4730015.84442 11.80801 48.17151 537.36388 0.43692 0.84798 12.77323 -0.75469 -1.07509 -1.00133 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.08289 872121.82727 4730015.71550 11.80801 48.17151 536.87361 0.33853 1.20246 12.28296 -0.85309 -0.72062 -1.49160 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.99540 872121.67586 4730015.42812 11.80801 48.17151 536.58170 0.20823 1.09770 11.99104 -0.98339 -0.82537 -1.78352 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.96687 872121.49693 4730015.25202 11.80801 48.17151 536.40744 0.03891 1.02836 11.81678 -1.15270 -0.89472 -1.95778 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.49630 872121.24046 4730015.59721 11.80800 48.17151 536.97526 -0.32046 0.91152 12.38461 -1.51208 -1.01156 -1.38996 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.77450 872121.25695 4730015.85827 11.80800 48.17151 537.35364 -0.36125 0.88019 12.76299 -1.55287 -1.04289 -1.01157 8 8 0 1.77 -2013-Sep-20 09:11:15 4171699.38934 872120.96868 4730016.41940 11.80800 48.17151 538.13379 -0.76924 0.84992 13.54313 -1.96086 -1.07316 -0.23143 8 8 0 1.77 -2013-Sep-20 09:11:15 4171699.05633 872121.06619 4730016.09198 11.80800 48.17151 537.68573 -0.60564 0.85957 13.09508 -1.79726 -1.06350 -0.67949 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.63755 872121.10071 4730016.74233 11.80800 48.17151 537.90168 -0.48616 1.59348 13.31102 -1.67778 -0.32959 -0.46354 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.89157 872121.33224 4730016.92079 11.80800 48.17151 538.23207 -0.31151 1.49192 13.64142 -1.50313 -0.43116 -0.13315 8 8 0 1.77 -2013-Sep-20 09:11:15 4171699.08367 872121.74411 4730017.22679 11.80801 48.17151 538.64170 0.05233 1.49307 14.05104 -1.13928 -0.43000 0.27648 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.79269 872121.52569 4730017.46809 11.80800 48.17151 538.60174 -0.10192 1.89953 14.01109 -1.29353 -0.02355 0.23652 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.52361 872121.65880 4730017.45044 11.80801 48.17152 538.43111 0.08343 2.06373 13.84045 -1.10818 0.14065 0.06589 8 8 0 1.77 -2013-Sep-20 09:11:15 4171699.44786 872121.63614 4730018.24048 11.80800 48.17151 539.62005 -0.12788 1.91993 15.02939 -1.31950 -0.00314 1.25483 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.45350 872121.91485 4730017.62102 11.80801 48.17152 538.54739 0.34842 2.18958 13.95673 -0.84320 0.26650 0.18217 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.39682 872121.99148 4730017.57517 11.80801 48.17152 538.48668 0.43502 2.18866 13.89603 -0.75660 0.26559 0.12146 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.42624 872121.98868 4730017.76592 11.80801 48.17152 538.64764 0.42626 2.29484 14.05698 -0.76536 0.37176 0.28242 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.30969 872122.48771 4730017.39076 11.80802 48.17152 538.36011 0.93857 2.05356 13.76946 -0.25304 0.13048 -0.00511 8 8 0 1.77 -2013-Sep-20 09:11:15 4171698.20917 872122.47823 4730016.57935 11.80802 48.17151 537.68858 0.94987 1.58719 13.09792 -0.24174 -0.33588 -0.67664 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.79002 872122.42314 4730016.23356 11.80802 48.17151 537.14978 0.98172 1.67070 12.55913 -0.20990 -0.25237 -1.21544 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.66796 872122.72080 4730016.34959 11.80802 48.17151 537.19719 1.29805 1.79172 12.60653 0.10644 -0.13135 -1.16803 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.40522 872123.39023 4730016.18432 11.80803 48.17151 536.99388 2.00708 1.77107 12.40322 0.81547 -0.15201 -1.37134 8 8 0 1.77 -2013-Sep-20 09:11:15 4171697.07807 872123.45260 4730015.62570 11.80803 48.17151 536.37257 2.13508 1.62762 11.78192 0.94347 -0.29545 -1.99264 8 8 0 1.77 -2013-Sep-20 09:11:15 4171696.71097 872123.70059 4730014.69900 11.80804 48.17151 535.47625 2.45295 1.23955 10.88560 1.26133 -0.68353 -2.88897 8 8 0 1.77 -2013-Sep-20 09:11:15 4171696.56606 872123.80873 4730014.77274 11.80804 48.17151 535.45136 2.58845 1.37793 10.86071 1.39683 -0.54515 -2.91385 8 8 0 1.77 -2013-Sep-20 09:11:15 4171696.23405 872123.72735 4730014.17300 11.80804 48.17151 534.77663 2.57673 1.23253 10.18597 1.38511 -0.69055 -3.58859 8 8 0 1.77 -2013-Sep-20 09:11:16 4171695.76749 872123.87198 4730014.16296 11.80804 48.17151 534.48432 2.81377 1.54408 9.89367 1.62215 -0.37900 -3.88090 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.02416 872123.73185 4730014.57571 11.80804 48.17151 534.94030 2.62409 1.65350 10.34965 1.43247 -0.26958 -3.42491 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.60945 872124.01511 4730014.61794 11.80804 48.17151 535.39250 2.78158 1.21157 10.80185 1.58996 -0.71150 -2.97272 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.07045 872123.98186 4730014.75445 11.80804 48.17151 535.79062 2.65470 0.97145 11.19997 1.46309 -0.95163 -2.57460 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.87884 872124.23799 4730014.68182 11.80805 48.17151 535.64637 2.94462 1.02370 11.05572 1.75300 -0.89937 -2.71885 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.17294 872124.09537 4730014.96779 11.80804 48.17151 536.03199 2.74483 1.02166 11.44133 1.55322 -0.90141 -2.33323 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.89121 872124.15618 4730014.37905 11.80804 48.17151 535.41768 2.86201 0.82524 10.82702 1.67040 -1.09784 -2.94754 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.35878 872123.86389 4730015.25049 11.80804 48.17151 536.33236 2.48022 1.10994 11.74170 1.28861 -0.81314 -2.03286 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.65807 872123.73390 4730015.20797 11.80804 48.17151 536.47831 2.29174 0.88311 11.88766 1.10013 -1.03997 -1.88691 8 8 0 1.77 -2013-Sep-20 09:11:16 4171698.26866 872123.51200 4730015.81205 11.80803 48.17151 537.29675 1.94959 0.87445 12.70609 0.75798 -1.04862 -1.06847 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.98163 872123.30488 4730016.09369 11.80803 48.17151 537.29097 1.80558 1.30322 12.70032 0.61397 -0.61986 -1.07424 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.03311 872123.38044 4730016.50152 11.80803 48.17152 536.98599 2.07364 2.25551 12.39534 0.88203 0.33243 -1.37922 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.89834 872123.51321 4730017.03412 11.80804 48.17152 537.31300 2.23119 2.68875 12.72235 1.03957 0.76568 -1.05221 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.71739 872123.30362 4730016.89129 11.80803 48.17152 537.05984 2.06306 2.75744 12.46919 0.87145 0.83437 -1.30538 8 8 0 1.77 -2013-Sep-20 09:11:16 4171696.76905 872123.05492 4730017.10611 11.80803 48.17152 537.21970 1.80905 2.90095 12.62905 0.61743 0.97787 -1.14552 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.67359 872122.75588 4730017.65716 11.80802 48.17152 538.17997 1.33124 2.65429 13.58932 0.13962 0.73122 -0.18525 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.08714 872122.79009 4730017.15099 11.80803 48.17152 537.42464 1.48473 2.73925 12.83399 0.29312 0.81617 -0.94057 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.52809 872122.85648 4730017.25585 11.80803 48.17152 537.79969 1.45949 2.47744 13.20903 0.26787 0.55436 -0.56553 8 8 0 1.77 -2013-Sep-20 09:11:16 4171697.67236 872122.69889 4730017.77907 11.80802 48.17152 538.26224 1.27571 2.74518 13.67158 0.08409 0.82211 -0.10298 8 8 0 1.77 -2013-Sep-20 09:11:16 4171698.07733 872122.47063 4730018.44767 11.80802 48.17152 538.99365 0.96941 2.93050 14.40300 -0.22220 1.00742 0.62843 8 8 0 1.77 -2013-Sep-20 09:11:16 4171698.77564 872122.35047 4730018.48478 11.80802 48.17152 539.46075 0.70889 2.46424 14.87009 -0.48272 0.54117 1.09553 8 8 0 1.77 -2013-Sep-20 09:11:16 4171698.93202 872122.39536 4730018.96685 11.80802 48.17152 539.92818 0.72083 2.66483 15.33753 -0.47078 0.74175 1.56296 8 8 0 1.77 -2013-Sep-20 09:11:16 4171699.04167 872122.35148 4730018.76417 11.80801 48.17152 539.84274 0.65544 2.45638 15.25208 -0.53618 0.53331 1.47752 8 8 0 1.77 -2013-Sep-20 09:11:16 4171699.40684 872122.21730 4730019.11357 11.80801 48.17152 540.32316 0.44938 2.44351 15.73251 -0.74224 0.52044 1.95794 8 8 0 1.77 -2013-Sep-20 09:11:16 4171699.73210 872122.37134 4730019.90582 11.80801 48.17152 541.14684 0.53360 2.71113 16.55619 -0.65802 0.78806 2.78163 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.25783 872122.75230 4730020.46281 11.80802 48.17152 541.95707 0.79891 2.64105 17.36641 -0.39270 0.71798 3.59185 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.30094 872123.07921 4730020.17611 11.80802 48.17152 541.81619 1.11009 2.36855 17.22553 -0.08153 0.44548 3.45097 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.35673 872123.27467 4730019.86431 11.80802 48.17152 541.64694 1.29000 2.09012 17.05629 0.09838 0.16705 3.28173 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.64590 872123.00329 4730020.80627 11.80802 48.17152 542.50058 0.96518 2.54878 17.90993 -0.22644 0.62571 4.13536 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.78272 872122.85819 4730020.82988 11.80802 48.17152 542.58769 0.79516 2.48686 17.99703 -0.39646 0.56378 4.22247 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.25994 872122.80094 4730021.24616 11.80801 48.17152 543.20158 0.64147 2.42514 18.61093 -0.55015 0.50206 4.83636 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.62909 872122.50823 4730021.47266 11.80801 48.17152 543.57139 0.27941 2.35158 18.98074 -0.91221 0.42850 5.20618 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.71174 872122.49782 4730021.63640 11.80801 48.17152 543.74594 0.25231 2.40208 19.15528 -0.93931 0.47900 5.38072 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.59630 872122.19521 4730021.49558 11.80801 48.17152 543.52435 -0.02028 2.43851 18.93369 -1.21189 0.51543 5.15913 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.10367 872122.06529 4730021.15545 11.80800 48.17152 542.93158 -0.04665 2.59080 18.34093 -1.23826 0.66772 4.56636 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.63756 872121.95665 4730021.86297 11.80800 48.17152 543.79248 -0.26223 2.68980 19.20182 -1.45385 0.76673 5.42726 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.48390 872121.87848 4730021.77785 11.80800 48.17152 543.61808 -0.30731 2.75703 19.02742 -1.49893 0.83395 5.25286 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.98971 872121.83147 4730021.39755 11.80800 48.17152 543.00568 -0.25220 2.87102 18.41502 -1.44382 0.94795 4.64046 8 8 0 1.77 -2013-Sep-20 09:11:17 4171701.19113 872121.70623 4730021.67298 11.80800 48.17152 543.32531 -0.41600 2.92690 18.73465 -1.60762 1.00382 4.96009 8 8 0 1.77 -2013-Sep-20 09:11:17 4171700.60881 872121.66760 4730021.76511 11.80800 48.17153 543.00855 -0.33466 3.41896 18.41790 -1.52627 1.49588 4.64334 8 8 0 1.77 -2013-Sep-20 09:11:17 4171699.71756 872121.37757 4730020.94067 11.80800 48.17153 541.77285 -0.43616 3.56342 17.18220 -1.62778 1.64034 3.40763 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.26359 872121.47589 4730020.37559 11.80801 48.17154 540.41606 -0.04240 4.23206 15.82541 -1.23401 2.30898 2.05085 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.54233 872121.69538 4730020.06529 11.80801 48.17153 540.39675 0.11541 3.78835 15.80610 -1.07620 1.86527 2.03154 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.96231 872121.86345 4730019.68954 11.80801 48.17153 540.41386 0.19399 3.20581 15.82321 -0.99763 1.28273 2.04865 8 8 0 1.77 -2013-Sep-20 09:11:17 4171699.68697 872122.10618 4730019.81008 11.80801 48.17152 541.00986 0.28328 2.72064 16.41921 -0.90834 0.79756 2.64465 8 8 0 1.77 -2013-Sep-20 09:11:17 4171699.05737 872122.54860 4730019.02664 11.80802 48.17152 540.07547 0.84518 2.58992 15.48481 -0.34643 0.66684 1.71025 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.57757 872122.69473 4730018.73724 11.80802 48.17152 539.56656 1.08640 2.72458 14.97590 -0.10522 0.80151 1.20134 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.39753 872123.19964 4730017.91848 11.80803 48.17152 538.90784 1.61747 2.23288 14.31718 0.42586 0.30980 0.54262 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.07742 872123.38382 4730017.83518 11.80803 48.17152 538.66194 1.86325 2.38272 14.07128 0.67164 0.45965 0.29672 8 8 0 1.77 -2013-Sep-20 09:11:17 4171698.59805 872123.36775 4730018.14870 11.80803 48.17152 539.23322 1.74099 2.21452 14.64257 0.54937 0.29145 0.86800 8 8 0 1.77 -2013-Sep-20 09:11:18 4171699.01191 872123.35087 4730018.56290 11.80803 48.17152 539.80973 1.63978 2.19147 15.21907 0.44816 0.26839 1.44451 8 8 0 1.77 -2013-Sep-20 09:11:18 4171698.97188 872123.26281 4730018.28279 11.80803 48.17152 539.56285 1.56177 2.04728 14.97220 0.37016 0.12421 1.19763 8 8 0 1.77 -2013-Sep-20 09:11:18 4171698.71650 872123.36825 4730017.93564 11.80803 48.17152 539.15186 1.71724 1.98596 14.56120 0.52563 0.06289 0.78664 8 8 0 1.77 -2013-Sep-20 09:11:18 4171698.65601 872123.28131 4730018.10186 11.80803 48.17152 539.22436 1.64452 2.15419 14.63371 0.45290 0.23112 0.85915 8 8 0 1.77 -2013-Sep-20 09:11:18 4171698.48721 872123.23660 4730017.66980 11.80803 48.17152 538.78612 1.63530 1.99599 14.19547 0.44368 0.07291 0.42091 8 8 0 1.77 -2013-Sep-20 09:11:18 4171697.89940 872123.48445 4730017.12269 11.80803 48.17152 538.02855 1.99818 2.02206 13.43790 0.80657 0.09899 -0.33667 8 8 0 1.77 -2013-Sep-20 09:11:18 4171697.78241 872123.34420 4730016.62738 11.80803 48.17151 537.56397 1.88485 1.79845 12.97331 0.69323 -0.12463 -0.80125 8 8 0 1.77 -2013-Sep-20 09:11:18 4171697.27070 872123.21238 4730016.31093 11.80803 48.17152 536.97613 1.86052 1.98074 12.38548 0.66891 0.05767 -1.38908 8 8 0 1.77 -2013-Sep-20 09:11:18 4171697.04476 872123.45873 4730015.62691 11.80803 48.17151 536.35257 2.14789 1.65179 11.76191 0.95628 -0.27129 -2.01265 8 8 0 1.77 -2013-Sep-20 09:11:18 4171696.81462 872123.53696 4730015.41589 11.80804 48.17151 536.05578 2.27156 1.66699 11.46512 1.07995 -0.25608 -2.30944 8 8 0 1.77 -2013-Sep-20 09:11:18 4171696.73928 872123.68661 4730015.23713 11.80804 48.17151 535.89381 2.43347 1.57991 11.30315 1.24185 -0.34316 -2.47141 8 8 0 1.77 -2013-Sep-20 09:11:18 4171696.86044 872123.69440 4730015.14403 11.80804 48.17151 535.90459 2.41629 1.42827 11.31394 1.22468 -0.49481 -2.46063 8 8 0 1.77 -2013-Sep-20 09:11:18 4171696.12220 872123.86922 4730014.99001 11.80804 48.17151 535.33177 2.73849 1.83735 10.74111 1.54688 -0.08573 -3.03345 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.43422 872124.19819 4730014.59030 11.80805 48.17152 534.62971 3.20127 2.02241 10.03906 2.00966 0.09933 -3.73551 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.57757 872124.52787 4730014.86230 11.80805 48.17152 534.97097 3.49464 2.04898 10.38031 2.30303 0.12591 -3.39425 8 8 0 1.77 -2013-Sep-20 09:11:18 4171694.92657 872124.73326 4730014.20356 11.80806 48.17152 534.08317 3.82891 2.05317 9.49251 2.63730 0.13010 -4.28205 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.32272 872124.78485 4730014.57097 11.80806 48.17152 534.62258 3.79835 2.00139 10.03193 2.60673 0.07831 -3.74264 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.05832 872124.92389 4730014.45829 11.80806 48.17152 534.38500 3.98855 2.09789 9.79435 2.79693 0.17482 -3.98022 8 8 0 1.77 -2013-Sep-20 09:11:18 4171694.64429 872124.85934 4730014.41449 11.80806 48.17152 534.07328 4.01008 2.38051 9.48263 2.81847 0.45743 -4.29194 8 8 0 1.77 -2013-Sep-20 09:11:18 4171694.60342 872124.97553 4730014.06059 11.80806 48.17152 533.79875 4.13218 2.15658 9.20809 2.94056 0.23351 -4.56647 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.56341 872124.83096 4730014.66618 11.80806 48.17151 534.85695 3.79422 1.88230 10.26629 2.60260 -0.04077 -3.50827 8 8 0 1.77 -2013-Sep-20 09:11:18 4171696.13787 872124.72235 4730014.93275 11.80805 48.17151 535.41575 3.57036 1.65764 10.82510 2.37874 -0.26544 -2.94947 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.76128 872124.58792 4730014.67370 11.80805 48.17151 534.95855 3.51584 1.78006 10.36789 2.32422 -0.14302 -3.40667 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.60814 872124.58599 4730014.91591 11.80805 48.17152 535.03880 3.54529 2.05357 10.44814 2.35367 0.13050 -3.32642 8 8 0 1.77 -2013-Sep-20 09:11:18 4171695.36035 872124.32980 4730014.99277 11.80805 48.17152 534.89935 3.34522 2.32463 10.30870 2.15360 0.40155 -3.46587 8 8 0 1.77 -2013-Sep-20 09:11:19 4171695.33369 872124.19849 4730014.79623 11.80805 48.17152 534.71758 3.22214 2.23302 10.12692 2.03053 0.30994 -3.64764 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.14726 872124.20623 4730015.45887 11.80805 48.17152 535.74348 3.06323 2.08036 11.15283 1.87162 0.15728 -2.62173 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.53708 872123.99906 4730015.14245 11.80804 48.17151 535.73390 2.78068 1.61661 11.14325 1.58906 -0.30647 -2.63131 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.21012 872123.84261 4730015.34223 11.80804 48.17152 535.64799 2.69445 2.01217 11.05733 1.50283 0.08910 -2.71723 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.94605 872123.86905 4730016.27008 11.80804 48.17152 536.82338 2.56973 2.09015 12.23273 1.37811 0.16708 -1.54184 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.97450 872123.66022 4730016.09887 11.80804 48.17152 536.68588 2.35950 1.98706 12.09522 1.16788 0.06399 -1.67934 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.29007 872123.59244 4730016.21878 11.80804 48.17151 536.97198 2.22858 1.84720 12.38132 1.03696 -0.07588 -1.39324 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.07984 872123.65501 4730015.82226 11.80804 48.17151 536.54781 2.33284 1.72656 11.95716 1.14123 -0.19652 -1.81741 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.15030 872123.32240 4730016.46139 11.80803 48.17152 537.02467 1.99286 2.15212 12.43401 0.80124 0.22904 -1.34055 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.19098 872123.03451 4730016.30652 11.80803 48.17152 536.89653 1.70273 2.06307 12.30588 0.51111 0.13999 -1.46869 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.51756 872122.69345 4730016.31784 11.80802 48.17151 537.07161 1.30207 1.88442 12.48096 0.11045 -0.03865 -1.29361 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.70450 872122.76573 4730016.13499 11.80803 48.17152 536.41448 1.53919 2.34448 11.82382 0.34757 0.42141 -1.95074 8 8 0 1.77 -2013-Sep-20 09:11:19 4171696.87494 872122.64814 4730016.40702 11.80802 48.17152 536.71238 1.38921 2.41951 12.12173 0.19759 0.49644 -1.65283 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.31212 872122.47654 4730017.33342 11.80802 48.17152 537.66466 1.13178 2.74462 13.07400 -0.05983 0.82155 -0.70056 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.29013 872122.52262 4730017.32786 11.80802 48.17152 537.65245 1.18138 2.74993 13.06179 -0.01023 0.82686 -0.71277 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.10639 872122.33574 4730017.40037 11.80802 48.17152 537.56103 1.03606 2.96080 12.97037 -0.15555 1.03773 -0.80419 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.30020 872122.29259 4730017.58092 11.80802 48.17152 537.81619 0.95416 2.94643 13.22554 -0.23746 1.02335 -0.54903 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.20801 872122.53025 4730017.62047 11.80802 48.17152 537.81792 1.20566 3.00380 13.22726 0.01404 1.08073 -0.54730 8 8 0 1.77 -2013-Sep-20 09:11:19 4171698.01302 872122.35572 4730018.02466 11.80802 48.17152 538.62078 0.87009 2.71282 14.03013 -0.32153 0.78975 0.25556 8 8 0 1.77 -2013-Sep-20 09:11:19 4171697.90360 872122.47092 4730017.42859 11.80802 48.17152 538.12092 1.00524 2.37754 13.53026 -0.18637 0.45447 -0.24430 8 8 0 1.77 -2013-Sep-20 09:11:19 4171698.30651 872122.71175 4730018.19742 11.80802 48.17152 538.98969 1.15852 2.55969 14.39904 -0.03309 0.63661 0.62447 8 8 0 1.77 -2013-Sep-20 09:11:19 4171698.75000 872122.58293 4730018.09188 11.80802 48.17152 539.18297 0.94168 2.18547 14.59231 -0.24993 0.26239 0.81775 8 8 0 1.77 -2013-Sep-20 09:11:19 4171698.96093 872122.61433 4730018.01857 11.80802 48.17152 539.27032 0.92925 1.97795 14.67967 -0.26237 0.05488 0.90510 8 8 0 1.77 -2013-Sep-20 09:11:19 4171699.16651 872122.51885 4730018.41188 11.80802 48.17152 539.68457 0.79373 2.10485 15.09391 -0.39789 0.18178 1.31935 8 8 0 1.77 -2013-Sep-20 09:11:19 4171699.27467 872122.63642 4730018.51296 11.80802 48.17152 539.84654 0.88668 2.07545 15.25589 -0.30494 0.15238 1.48132 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.27310 872122.82630 4730018.51648 11.80802 48.17152 539.87405 1.07286 2.04999 15.28339 -0.11875 0.12691 1.50883 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.52307 872122.59839 4730018.68419 11.80802 48.17152 540.13109 0.79862 2.01427 15.54043 -0.39300 0.09119 1.76587 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.39555 872122.52276 4730018.53608 11.80802 48.17152 539.92716 0.75068 2.02003 15.33651 -0.44094 0.09696 1.56194 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.66411 872122.59066 4730019.46820 11.80802 48.17152 540.80631 0.76220 2.43544 16.21566 -0.42942 0.51236 2.44109 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.08064 872122.48064 4730019.46887 11.80802 48.17152 540.41091 0.77390 2.87823 15.82025 -0.41772 0.95515 2.04569 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.20437 872122.70883 4730019.42476 11.80802 48.17152 540.48995 0.97194 2.72377 15.89929 -0.21968 0.80069 2.12473 8 8 0 1.77 -2013-Sep-20 09:11:20 4171699.66187 872122.30732 4730020.19524 11.80801 48.17152 541.30792 0.48531 2.96514 16.71727 -0.70631 1.04206 2.94271 8 8 0 1.77 -2013-Sep-20 09:11:20 4171698.79254 872122.23258 4730019.96085 11.80801 48.17153 540.55558 0.59004 3.45428 15.96493 -0.60158 1.53121 2.19036 8 8 0 1.77 -2013-Sep-20 09:11:20 4171698.76187 872122.62245 4730019.44329 11.80802 48.17153 540.20311 0.97793 3.07205 15.61246 -0.21368 1.14897 1.83789 8 8 0 1.77 -2013-Sep-20 09:11:20 4171698.06897 872122.92318 4730018.43003 11.80802 48.17152 539.03681 1.41410 2.85583 14.44616 0.22248 0.93275 0.67159 8 8 0 1.77 -2013-Sep-20 09:11:20 4171697.94739 872122.73810 4730018.12768 11.80802 48.17152 538.70689 1.25781 2.77109 14.11624 0.06619 0.84801 0.34167 8 8 0 1.77 -2013-Sep-20 09:11:20 4171697.60251 872122.55050 4730017.81273 11.80802 48.17152 538.22147 1.14475 2.84120 13.63081 -0.04687 0.91812 -0.14375 8 8 0 1.77 -2013-Sep-20 09:11:20 4171697.59018 872122.39367 4730017.83808 11.80802 48.17152 538.21091 0.99377 2.89102 13.62025 -0.19785 0.96794 -0.15431 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.56053 872122.37574 4730017.29676 11.80802 48.17153 537.13296 1.18691 3.28374 12.54230 -0.00471 1.36067 -1.23226 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.92326 872122.08773 4730017.79658 11.80802 48.17153 537.70287 0.83077 3.39643 13.11222 -0.36085 1.47335 -0.66235 8 8 0 1.77 -2013-Sep-20 09:11:20 4171697.09465 872122.07369 4730017.42650 11.80802 48.17152 537.53707 0.78195 3.02675 12.94642 -0.40966 1.10367 -0.82815 8 8 0 1.77 -2013-Sep-20 09:11:20 4171697.31264 872122.04105 4730017.32319 11.80802 48.17152 537.59794 0.70540 2.80383 13.00728 -0.48622 0.88076 -0.76728 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.76097 872122.21946 4730016.73529 11.80802 48.17152 536.82410 0.99293 2.78693 12.23344 -0.19869 0.86386 -1.54112 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.84017 872121.85219 4730016.96757 11.80801 48.17152 536.99876 0.61722 2.94008 12.40810 -0.57440 1.01700 -1.36646 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.89973 872121.78744 4730017.09349 11.80801 48.17152 537.12263 0.54165 2.99048 12.53197 -0.64997 1.06741 -1.24259 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.25761 872122.04883 4730016.56199 11.80802 48.17153 536.34309 0.92890 3.06451 11.75244 -0.26271 1.14144 -2.02213 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.65603 872122.07354 4730017.12168 11.80802 48.17153 537.02359 0.87156 3.14341 12.43294 -0.32005 1.22033 -1.34162 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.16724 872122.19517 4730016.77955 11.80802 48.17153 536.46617 1.09064 3.25320 11.87552 -0.10097 1.33013 -1.89905 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.12766 872122.35818 4730017.13923 11.80802 48.17153 536.73060 1.25830 3.49708 12.13994 0.06669 1.57401 -1.63462 8 8 0 1.77 -2013-Sep-20 09:11:20 4171696.51123 872122.29424 4730017.32557 11.80802 48.17153 537.11111 1.11723 3.35135 12.52046 -0.07438 1.42827 -1.25411 8 8 0 1.77 -2013-Sep-20 09:11:21 4171697.04976 872122.26342 4730017.57212 11.80802 48.17153 537.64217 0.97686 3.12768 13.05152 -0.21476 1.20461 -0.72305 8 8 0 1.77 -2013-Sep-20 09:11:21 4171697.23816 872122.07833 4730017.34295 11.80802 48.17152 537.56913 0.75713 2.86565 12.97847 -0.43449 0.94258 -0.79609 8 8 0 1.77 -2013-Sep-20 09:11:21 4171697.53900 872122.18451 4730016.85821 11.80802 48.17152 537.41881 0.79951 2.30676 12.82815 -0.39211 0.38369 -0.94641 8 8 0 1.77 -2013-Sep-20 09:11:21 4171697.65847 872122.30906 4730016.48693 11.80802 48.17152 537.23714 0.89697 1.95302 12.64648 -0.29465 0.02994 -1.12808 8 8 0 1.77 -2013-Sep-20 09:11:21 4171697.52556 872122.12433 4730017.09298 11.80802 48.17152 537.57676 0.74335 2.48230 12.98610 -0.44827 0.55923 -0.78846 8 8 0 1.77 -2013-Sep-20 09:11:21 4171698.01397 872121.97372 4730017.35973 11.80801 48.17152 538.07380 0.49598 2.32693 13.48314 -0.69564 0.40385 -0.29142 8 8 0 1.77 -2013-Sep-20 09:11:21 4171698.80231 872122.14655 4730018.06228 11.80801 48.17152 539.13551 0.50383 2.19412 14.54485 -0.68779 0.27104 0.77029 8 8 0 1.77 -2013-Sep-20 09:11:21 4171698.71250 872122.29870 4730017.98215 11.80801 48.17152 539.03794 0.67114 2.18298 14.44728 -0.52047 0.25991 0.67272 8 8 0 1.77 -2013-Sep-20 09:11:21 4171699.10729 872122.07044 4730018.73306 11.80801 48.17152 539.82404 0.36692 2.43062 15.23338 -0.82469 0.50755 1.45882 8 8 0 1.77 -2013-Sep-20 09:11:21 4171698.28009 872122.26908 4730018.27515 11.80802 48.17152 538.96995 0.73064 2.69829 14.37930 -0.46098 0.77522 0.60473 8 8 0 1.77 -2013-Sep-20 09:11:21 4171699.19818 872122.29725 4730019.24244 11.80801 48.17152 540.29389 0.57034 2.66945 15.70323 -0.62128 0.74638 1.92867 8 8 0 1.77 -2013-Sep-20 09:11:21 4171700.69256 872121.82900 4730020.69249 11.80800 48.17152 542.28600 -0.19381 2.61793 17.69534 -1.38543 0.69485 3.92078 8 8 0 1.77 -2013-Sep-20 09:11:21 4171700.84964 872121.86280 4730021.03791 11.80800 48.17152 542.65054 -0.19286 2.72857 18.05989 -1.38448 0.80549 4.28532 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.16657 872122.08856 4730021.73122 11.80801 48.17152 543.40486 -0.03674 2.92535 18.81420 -1.22835 1.00228 5.03964 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.22798 872122.45284 4730021.79066 11.80801 48.17152 543.53895 0.30726 2.86466 18.94829 -0.88435 0.94158 5.17373 8 8 0 1.77 -2013-Sep-20 09:11:21 4171700.68390 872122.55199 4730021.56941 11.80801 48.17153 543.03244 0.51566 3.09883 18.44179 -0.67596 1.17575 4.66722 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.10633 872122.77780 4730021.66301 11.80801 48.17152 543.40876 0.65025 2.81871 18.81811 -0.54137 0.89563 5.04354 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.53388 872122.88169 4730022.32459 11.80801 48.17152 544.19502 0.66444 2.93223 19.60436 -0.52717 1.00915 5.82980 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.08281 872122.95332 4730022.42754 11.80802 48.17153 543.98705 0.82687 3.31896 19.39639 -0.36475 1.39588 5.62183 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.69585 872123.01475 4730022.72729 11.80802 48.17153 544.61897 0.76155 3.06236 20.02832 -0.43007 1.13929 6.25376 8 8 0 1.77 -2013-Sep-20 09:11:21 4171702.00964 872123.02682 4730023.12507 11.80802 48.17153 545.12187 0.70915 3.09693 20.53121 -0.48247 1.17385 6.75665 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.62224 872123.11548 4730023.00444 11.80802 48.17153 544.79118 0.87521 3.28552 20.20053 -0.31641 1.36245 6.42596 8 8 0 1.77 -2013-Sep-20 09:11:21 4171702.21595 872122.67510 4730023.60782 11.80801 48.17153 545.56826 0.32266 3.32203 20.97761 -0.86896 1.39895 7.20305 8 8 0 1.77 -2013-Sep-20 09:11:21 4171701.83706 872122.66981 4730023.60130 11.80801 48.17153 545.31534 0.39501 3.59485 20.72469 -0.79661 1.67177 6.95013 8 8 0 1.77 -2013-Sep-20 09:11:21 4171702.58636 872122.56318 4730024.14919 11.80801 48.17153 546.19819 0.13731 3.42997 21.60753 -1.05431 1.50690 7.83297 8 8 0 1.77 -2013-Sep-20 09:11:22 4171701.95182 872122.43491 4730023.93596 11.80801 48.17153 545.60757 0.14160 3.77015 21.01692 -1.05002 1.84707 7.24235 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.41310 872122.48657 4730023.94704 11.80801 48.17153 545.92400 0.09777 3.43321 21.33334 -1.09385 1.51013 7.55878 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.44279 872122.27459 4730023.48950 11.80800 48.17153 545.57352 -0.11580 3.13874 20.98286 -1.30742 1.21567 7.20830 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.64826 872122.07543 4730023.73818 11.80800 48.17153 545.86577 -0.35279 3.18509 21.27512 -1.54441 1.26201 7.50056 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.62559 872122.13798 4730023.36697 11.80800 48.17152 545.58290 -0.28693 2.94453 20.99224 -1.47855 1.02145 7.21768 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.27410 872122.14048 4730023.04507 11.80800 48.17152 545.11393 -0.21255 2.98584 20.52327 -1.40417 1.06277 6.74871 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.33847 872122.02619 4730022.91413 11.80800 48.17152 545.04279 -0.33759 2.86899 20.45213 -1.52921 0.94592 6.67757 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.47646 872122.03247 4730022.58428 11.80800 48.17152 544.88794 -0.35969 2.54741 20.29728 -1.55130 0.62433 6.52272 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.70174 872121.61386 4730022.82344 11.80799 48.17152 545.15608 -0.81554 2.60642 20.56542 -2.00716 0.68335 6.79086 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.77318 872121.79219 4730022.32239 11.80800 48.17152 544.85370 -0.65560 2.19297 20.26304 -1.84722 0.26990 6.48848 8 8 0 1.77 -2013-Sep-20 09:11:22 4171702.31283 872121.63760 4730021.65430 11.80800 48.17152 544.03427 -0.71272 2.10676 19.44361 -1.90433 0.18368 5.66905 8 8 0 1.77 -2013-Sep-20 09:11:22 4171701.63536 872121.75914 4730020.71023 11.80800 48.17152 542.90513 -0.45511 1.95275 18.31448 -1.64673 0.02968 4.53992 8 8 0 1.77 -2013-Sep-20 09:11:22 4171701.14263 872121.72429 4730020.32085 11.80800 48.17152 542.28858 -0.38840 2.05778 17.69792 -1.58002 0.13470 3.92336 8 8 0 1.77 -2013-Sep-20 09:11:22 4171701.04761 872121.94644 4730019.95171 11.80800 48.17151 541.98181 -0.15151 1.84703 17.39116 -1.34313 -0.07605 3.61659 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.80880 872121.67336 4730019.72100 11.80800 48.17151 541.61674 -0.36994 1.90899 17.02608 -1.56156 -0.01409 3.25152 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.89026 872121.57862 4730019.80591 11.80800 48.17151 541.72026 -0.47934 1.92064 17.12960 -1.67096 -0.00243 3.35504 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.47474 872121.47160 4730019.61736 11.80800 48.17152 541.29391 -0.49907 2.11429 16.70325 -1.69069 0.19121 2.92869 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.55331 872121.65886 4730018.80111 11.80800 48.17151 540.76253 -0.33185 1.48407 16.17188 -1.52347 -0.43901 2.39731 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.61488 872121.44608 4730018.76201 11.80800 48.17151 540.74454 -0.55273 1.44553 16.15389 -1.74434 -0.47754 2.37933 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.49863 872121.68465 4730018.66708 11.80800 48.17151 540.63048 -0.29541 1.43063 16.03982 -1.48703 -0.49244 2.26526 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.72713 872121.53659 4730019.24872 11.80800 48.17151 541.19285 -0.48710 1.67445 16.60219 -1.67872 -0.24863 2.82763 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.89901 872121.26161 4730018.92592 11.80799 48.17151 541.02698 -0.79143 1.37573 16.43632 -1.98305 -0.54734 2.66176 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.38213 872121.58721 4730018.76743 11.80800 48.17151 540.61591 -0.36695 1.59738 16.02525 -1.55857 -0.32569 2.25069 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.48126 872122.01041 4730018.68470 11.80801 48.17151 540.67673 0.02700 1.40538 16.08607 -1.16462 -0.51770 2.31151 8 8 0 1.77 -2013-Sep-20 09:11:22 4171700.42981 872122.09768 4730018.93777 11.80801 48.17151 540.84362 0.12296 1.59838 16.25297 -1.06866 -0.32470 2.47840 8 8 0 1.77 -2013-Sep-20 09:11:23 4171700.25674 872122.04299 4730018.60865 11.80801 48.17151 540.47794 0.10484 1.51346 15.88729 -1.08678 -0.40962 2.11272 8 8 0 1.77 -2013-Sep-20 09:11:23 4171699.16549 872122.38864 4730018.10177 11.80801 48.17151 539.43505 0.66648 1.91864 14.84440 -0.52513 -0.00443 1.06983 8 8 0 1.77 -2013-Sep-20 09:11:23 4171698.90923 872122.50577 4730017.52694 11.80802 48.17151 538.85542 0.83357 1.70434 14.26477 -0.35805 -0.21874 0.49021 8 8 0 1.77 -2013-Sep-20 09:11:23 4171698.87469 872122.60967 4730017.19972 11.80802 48.17151 538.60323 0.94234 1.49546 14.01257 -0.24928 -0.42762 0.23801 8 8 0 1.77 -2013-Sep-20 09:11:23 4171698.74918 872123.04708 4730016.52811 11.80802 48.17151 538.08054 1.39618 1.07241 13.48989 0.20456 -0.85066 -0.28468 8 8 0 1.77 -2013-Sep-20 09:11:23 4171698.16746 872123.30345 4730016.20370 11.80803 48.17151 537.49406 1.76616 1.24126 12.90341 0.57454 -0.68181 -0.87116 8 8 0 1.77 -2013-Sep-20 09:11:23 4171697.47430 872123.78172 4730015.50247 11.80804 48.17151 536.58432 2.37615 1.20625 11.99367 1.18453 -0.71682 -1.78090 8 8 0 1.77 -2013-Sep-20 09:11:23 4171696.86109 872123.68251 4730014.85597 11.80804 48.17151 535.68875 2.40452 1.23749 11.09810 1.21291 -0.68558 -2.67647 8 8 0 1.77 -2013-Sep-20 09:11:23 4171696.35236 872123.75839 4730015.45932 11.80804 48.17152 535.81660 2.58291 1.99936 11.22594 1.39129 0.07628 -2.54862 8 8 0 1.77 -2013-Sep-20 09:11:23 4171695.94794 872124.22422 4730015.25092 11.80805 48.17152 535.46088 3.12163 2.08432 10.87022 1.93001 0.16124 -2.90434 8 8 0 1.77 -2013-Sep-20 09:11:23 4171695.41651 872124.31269 4730015.18146 11.80805 48.17152 535.07428 3.31698 2.41211 10.48362 2.12537 0.48904 -3.29094 8 8 0 1.77 -2013-Sep-20 09:11:23 4171695.64186 872124.48128 4730015.07744 11.80805 48.17152 535.16689 3.43589 2.15267 10.57623 2.24427 0.22960 -3.19833 8 8 0 1.77 -2013-Sep-20 09:11:23 4171695.99033 872124.18767 4730015.78382 11.80805 48.17152 535.88065 3.07719 2.41436 11.28999 1.88557 0.49129 -2.48457 8 8 0 1.77 -2013-Sep-20 09:11:23 4171695.50380 872124.63646 4730014.95546 11.80805 48.17152 535.00705 3.61603 2.14836 10.41639 2.42442 0.22528 -3.35817 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.98197 872124.64948 4730014.60006 11.80806 48.17152 534.40335 3.73556 2.28997 9.81270 2.54395 0.36689 -3.96187 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.31828 872124.71684 4730014.54467 11.80806 48.17152 533.93802 3.93731 2.72684 9.34736 2.74570 0.80376 -4.42720 8 8 0 1.77 -2013-Sep-20 09:11:23 4171693.73938 872124.89906 4730014.04188 11.80806 48.17152 533.21034 4.23413 2.78598 8.61968 3.04252 0.86290 -5.15488 8 8 0 1.77 -2013-Sep-20 09:11:23 4171693.33447 872124.85972 4730013.39787 11.80806 48.17152 532.46076 4.27848 2.65781 7.87011 3.08687 0.73474 -5.90445 8 8 0 1.77 -2013-Sep-20 09:11:23 4171693.33025 872124.94481 4730013.19497 11.80806 48.17152 532.31843 4.36264 2.51260 7.72778 3.17102 0.58953 -6.04679 8 8 0 1.77 -2013-Sep-20 09:11:23 4171693.53122 872124.97490 4730013.15073 11.80806 48.17152 532.42077 4.35096 2.33193 7.83011 3.15935 0.40885 -5.94445 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.08680 872125.12819 4730013.06252 11.80806 48.17151 532.73863 4.38732 1.84449 8.14798 3.19571 -0.07858 -5.62659 8 8 0 1.77 -2013-Sep-20 09:11:23 4171693.49335 872125.31109 4730012.56778 11.80807 48.17151 532.00754 4.68779 1.91951 7.41688 3.49618 -0.00356 -6.35768 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.23364 872125.33371 4730012.45002 11.80807 48.17151 532.40613 4.55845 1.29758 7.81548 3.36683 -0.62549 -5.95909 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.78063 872124.95911 4730012.82499 11.80806 48.17151 532.99149 4.07984 1.20581 8.40084 2.88822 -0.71727 -5.37373 8 8 0 1.77 -2013-Sep-20 09:11:23 4171694.84330 872125.01134 4730012.54997 11.80806 48.17151 532.83460 4.11814 0.96872 8.24395 2.92652 -0.95436 -5.53062 8 8 0 1.77 -2013-Sep-20 09:11:24 4171694.78080 872124.89122 4730012.57800 11.80806 48.17151 532.79829 4.01336 1.05132 8.20763 2.82174 -0.87176 -5.56693 8 8 0 1.77 -2013-Sep-20 09:11:24 4171694.55134 872124.87342 4730012.17800 11.80806 48.17151 532.34801 4.04288 0.95463 7.75736 2.85127 -0.96845 -6.01721 8 8 0 1.77 -2013-Sep-20 09:11:24 4171694.40329 872124.59192 4730012.24326 11.80806 48.17151 532.26158 3.79764 1.14906 7.67092 2.60602 -0.77401 -6.10364 8 8 0 1.77 -2013-Sep-20 09:11:24 4171694.72814 872124.31088 4730012.39862 11.80805 48.17151 532.55105 3.45607 1.05859 7.96039 2.26445 -0.86449 -5.81417 8 8 0 1.77 -2013-Sep-20 09:11:24 4171695.27170 872124.30449 4730012.36729 11.80805 48.17150 532.88166 3.33858 0.64221 8.29101 2.14697 -1.28087 -5.48356 8 8 0 1.77 -2013-Sep-20 09:11:24 4171695.59018 872124.22692 4730012.68059 11.80805 48.17150 533.31243 3.19748 0.63069 8.72178 2.00587 -1.29239 -5.05279 8 8 0 1.77 -2013-Sep-20 09:11:24 4171695.61785 872124.16338 4730012.64843 11.80805 48.17150 533.29786 3.12963 0.59875 8.70721 1.93801 -1.32433 -5.06736 8 8 0 1.77 -2013-Sep-20 09:11:24 4171695.56272 872124.27940 4730012.24025 11.80805 48.17150 532.97356 3.25447 0.34905 8.38290 2.06285 -1.57403 -5.39166 8 8 0 1.77 -2013-Sep-20 09:11:24 4171695.98208 872123.84131 4730012.65562 11.80804 48.17150 533.49703 2.73984 0.38699 8.90638 1.54823 -1.53608 -4.86819 8 8 0 1.77 -2013-Sep-20 09:11:24 4171696.40650 872123.93324 4730012.83200 11.80804 48.17150 533.91807 2.74298 0.18104 9.32741 1.55136 -1.74204 -4.44715 8 8 0 1.77 -2013-Sep-20 09:11:24 4171697.01401 872123.56027 4730013.64619 11.80804 48.17150 534.87043 2.25358 0.33779 10.27978 1.06197 -1.58528 -3.49479 8 8 0 1.77 -2013-Sep-20 09:11:24 4171697.78434 872123.37628 4730014.04490 11.80803 48.17150 535.64528 1.91585 0.06988 11.05463 0.72423 -1.85319 -2.71994 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.57004 872123.35096 4730014.80813 11.80803 48.17150 536.72344 1.73029 0.00967 12.13279 0.53867 -1.91340 -1.64177 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.63797 872123.40502 4730015.23920 11.80803 48.17150 537.09637 1.76930 0.23936 12.50572 0.57769 -1.68371 -1.26885 8 8 0 1.77 -2013-Sep-20 09:11:24 4171699.46071 872123.29389 4730016.27388 11.80803 48.17150 538.38927 1.49216 0.34626 13.79862 0.30055 -1.57682 0.02406 8 8 0 1.77 -2013-Sep-20 09:11:24 4171699.00394 872123.28348 4730016.64307 11.80803 48.17151 538.36477 1.57544 0.92722 13.77412 0.38382 -0.99585 -0.00045 8 8 0 1.77 -2013-Sep-20 09:11:24 4171699.14968 872123.07268 4730017.00955 11.80802 48.17151 538.70422 1.33928 1.09747 14.11357 0.14767 -0.82561 0.33900 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.67452 872123.06323 4730016.30640 11.80802 48.17151 537.86881 1.42726 0.97654 13.27815 0.23564 -0.94653 -0.49641 8 8 0 1.77 -2013-Sep-20 09:11:24 4171697.86922 872123.34143 4730016.19643 11.80803 48.17151 537.29913 1.86437 1.44815 12.70848 0.67275 -0.47492 -1.06608 8 8 0 1.77 -2013-Sep-20 09:11:24 4171697.95299 872123.63161 4730016.52621 11.80803 48.17151 537.63916 2.13127 1.56274 13.04850 0.93965 -0.36034 -0.72606 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.30013 872123.37775 4730017.15193 11.80803 48.17151 538.29737 1.81174 1.76555 13.70672 0.62013 -0.15753 -0.06785 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.61127 872123.27377 4730017.20090 11.80803 48.17151 538.52278 1.64629 1.58712 13.93213 0.45467 -0.33595 0.15756 8 8 0 1.77 -2013-Sep-20 09:11:24 4171698.70536 872123.09196 4730017.81255 11.80803 48.17152 539.01516 1.44907 1.95413 14.42450 0.25746 0.03106 0.64994 8 8 0 1.77 -2013-Sep-20 09:11:24 4171699.32078 872123.10792 4730018.75535 11.80802 48.17152 540.12159 1.33877 2.13158 15.53094 0.14715 0.20850 1.75638 8 8 0 1.77 -2013-Sep-20 09:11:24 4171700.44214 872122.69263 4730019.56567 11.80802 48.17151 541.40074 0.70279 1.91741 16.81009 -0.48882 -0.00567 3.03552 8 8 0 1.77 -2013-Sep-20 09:11:25 4171700.87047 872122.61229 4730020.08077 11.80801 48.17152 542.05321 0.53650 1.96078 17.46256 -0.65512 0.03770 3.68800 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.04694 872122.35947 4730020.86237 11.80801 48.17151 543.36910 0.04828 1.66248 18.77845 -1.14333 -0.26060 5.00388 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.17856 872122.18386 4730020.40536 11.80800 48.17151 543.09052 -0.15054 1.28848 18.49986 -1.34216 -0.63460 4.72530 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.82370 872122.51184 4730020.74153 11.80801 48.17151 543.80692 0.03848 0.99212 19.21626 -1.15313 -0.93096 5.44170 8 8 0 1.77 -2013-Sep-20 09:11:25 4171703.32821 872122.39124 4730021.23514 11.80800 48.17151 544.48761 -0.18281 0.97171 19.89695 -1.37442 -0.95137 6.12239 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.96839 872122.67505 4730020.93220 11.80801 48.17151 544.06572 0.16863 0.98885 19.47506 -1.02299 -0.93423 5.70050 8 8 0 1.77 -2013-Sep-20 09:11:25 4171703.49831 872122.59217 4730021.58466 11.80801 48.17151 544.88651 -0.02094 1.05010 20.29586 -1.21255 -0.87298 6.52129 8 8 0 1.77 -2013-Sep-20 09:11:25 4171703.58810 872122.25336 4730021.80658 11.80800 48.17151 545.06425 -0.37094 1.18428 20.47359 -1.56256 -0.73880 6.69903 8 8 0 1.77 -2013-Sep-20 09:11:25 4171703.50841 872122.21588 4730022.54002 11.80800 48.17151 545.55364 -0.39132 1.73725 20.96298 -1.58294 -0.18583 7.18842 8 8 0 1.77 -2013-Sep-20 09:11:25 4171703.34375 872122.34164 4730022.80422 11.80800 48.17152 545.66017 -0.23453 2.01437 21.06951 -1.42615 0.09129 7.29495 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.78201 872122.25393 4730023.00194 11.80800 48.17152 545.42884 -0.20544 2.56932 20.83819 -1.39705 0.64624 7.06362 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.77401 872122.25906 4730022.45941 11.80800 48.17152 545.02005 -0.19878 2.21256 20.42939 -1.39040 0.28948 6.65483 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.61148 872122.29617 4730022.39868 11.80800 48.17152 544.87376 -0.12919 2.28494 20.28310 -1.32081 0.36187 6.50854 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.43756 872122.22809 4730021.98278 11.80800 48.17152 544.44103 -0.16024 2.14481 19.85037 -1.35186 0.22173 6.07581 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.41514 872122.17541 4730021.44668 11.80800 48.17151 544.01974 -0.20722 1.81167 19.42908 -1.39884 -0.11141 5.65452 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.02984 872122.18943 4730021.14974 11.80800 48.17151 543.54887 -0.11466 1.89253 18.95821 -1.30628 -0.03055 5.18365 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.26815 872121.97079 4730021.35574 11.80800 48.17151 543.82809 -0.37744 1.88943 19.23744 -1.56905 -0.03364 5.46288 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.70269 872122.03374 4730021.52410 11.80800 48.17151 544.24580 -0.40474 1.67517 19.65515 -1.59636 -0.24791 5.88058 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.39376 872122.50537 4730020.78404 11.80801 48.17151 543.55705 0.12013 1.33504 18.96639 -1.07149 -0.58804 5.19183 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.54888 872122.53675 4730020.89914 11.80801 48.17151 543.74835 0.11911 1.29387 19.15770 -1.07251 -0.62921 5.38314 8 8 0 1.77 -2013-Sep-20 09:11:25 4171702.35316 872122.91499 4730020.73096 11.80801 48.17151 543.54689 0.52940 1.26679 18.95624 -0.66222 -0.65628 5.18167 8 8 0 1.77 -2013-Sep-20 09:11:25 4171701.88670 872123.24296 4730020.01185 11.80802 48.17151 542.75131 0.94587 1.07742 18.16065 -0.24575 -0.84565 4.38609 8 8 0 1.77 -2013-Sep-20 09:11:25 4171701.13527 872123.05459 4730019.83813 11.80802 48.17151 542.10563 0.91526 1.53837 17.51498 -0.27636 -0.38470 3.74042 8 8 0 1.77 -2013-Sep-20 09:11:25 4171700.10440 872123.37547 4730018.53072 11.80802 48.17151 540.50227 1.44030 1.36942 15.91161 0.24868 -0.55365 2.13705 8 8 0 1.77 -2013-Sep-20 09:11:25 4171700.31801 872123.36362 4730018.74722 11.80802 48.17151 540.80142 1.38499 1.35981 16.21076 0.19337 -0.56327 2.43620 8 8 0 1.77 -2013-Sep-20 09:11:26 4171699.92813 872123.31133 4730018.90982 11.80802 48.17151 540.66093 1.41359 1.76059 16.07028 0.22197 -0.16249 2.29572 8 8 0 1.77 -2013-Sep-20 09:11:26 4171686.25644 872113.04668 4730002.40583 11.80793 48.17152 518.03750 -5.83618 2.29100 -6.55316 -7.02779 0.36793 -20.32772 8 8 0 1.77 -2013-Sep-20 09:11:26 4171699.56855 872122.88902 4730018.11974 11.80802 48.17151 539.77984 1.07379 1.56035 15.18919 -0.11783 -0.36273 1.41462 8 8 0 1.77 -2013-Sep-20 09:11:26 4171698.95488 872122.83635 4730017.57470 11.80802 48.17151 538.96593 1.14782 1.65249 14.37527 -0.04380 -0.27059 0.60071 8 8 0 1.77 -2013-Sep-20 09:11:26 4171698.52139 872122.91328 4730017.74223 11.80802 48.17152 538.81828 1.31183 2.06866 14.22762 0.12021 0.14558 0.45306 8 8 0 1.77 -2013-Sep-20 09:11:26 4171698.33324 872122.83087 4730017.73504 11.80802 48.17152 538.67886 1.26966 2.21366 14.08820 0.07805 0.29058 0.31364 8 8 0 1.77 -2013-Sep-20 09:11:26 4171698.57027 872122.78294 4730017.69385 11.80802 48.17152 538.79635 1.17424 2.02062 14.20570 -0.01738 0.09754 0.43113 8 8 0 1.77 -2013-Sep-20 09:11:26 4171697.87094 872122.80878 4730017.20228 11.80802 48.17152 537.97707 1.34264 2.19892 13.38641 0.15102 0.27584 -0.38815 8 8 0 1.77 -2013-Sep-20 09:11:26 4171697.41115 872122.56544 4730016.69303 11.80802 48.17152 537.26425 1.19853 2.23177 12.67360 0.00692 0.30870 -1.10097 8 8 0 1.77 -2013-Sep-20 09:11:26 4171696.96020 872122.58784 4730016.48740 11.80802 48.17152 536.81971 1.31274 2.42013 12.22905 0.12113 0.49705 -1.54551 8 8 0 1.77 -2013-Sep-20 09:11:26 4171696.33252 872122.42855 4730015.88985 11.80802 48.17152 535.94297 1.28526 2.50372 11.35232 0.09364 0.58065 -2.42225 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.66835 872122.30662 4730015.53695 11.80802 48.17152 535.22980 1.30183 2.77139 10.63914 0.11021 0.84832 -3.13542 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.62194 872121.98928 4730016.07159 11.80802 48.17153 535.55458 1.00070 3.21019 10.96393 -0.19092 1.28711 -2.81064 8 8 0 1.77 -2013-Sep-20 09:11:26 4171696.08143 872121.75290 4730016.38898 11.80801 48.17153 536.05877 0.67529 3.12275 11.46812 -0.51632 1.19968 -2.30645 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.52989 872121.73778 4730016.13000 11.80802 48.17153 535.50369 0.77335 3.35463 10.91303 -0.41826 1.43155 -2.86153 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.65018 872121.48345 4730016.54054 11.80801 48.17153 535.85342 0.49980 3.57946 11.26276 -0.69182 1.65638 -2.51180 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.38313 872121.29255 4730016.04228 11.80801 48.17153 535.28177 0.36758 3.47105 10.69111 -0.82403 1.54798 -3.08345 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.83768 872121.01103 4730015.58530 11.80801 48.17152 535.19955 -0.00100 2.87769 10.60890 -1.19262 0.95461 -3.16567 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.82594 872120.89886 4730015.42913 11.80800 48.17152 535.06021 -0.10840 2.79920 10.46956 -1.30001 0.87613 -3.30500 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.59724 872120.81960 4730015.20978 11.80800 48.17152 534.73666 -0.13918 2.83181 10.14600 -1.33079 0.90874 -3.62856 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.12172 872120.87485 4730014.56353 11.80801 48.17152 533.95223 0.01221 2.73923 9.36158 -1.17941 0.81616 -4.41299 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.14789 872120.86452 4730013.94300 11.80801 48.17152 533.50552 -0.00326 2.30789 8.91486 -1.19487 0.38481 -4.85970 8 8 0 1.77 -2013-Sep-20 09:11:26 4171695.18999 872120.81862 4730014.02310 11.80800 48.17152 533.58642 -0.05680 2.33760 8.99577 -1.24841 0.41453 -4.77879 8 8 0 1.77 -2013-Sep-20 09:11:26 4171694.99597 872120.81405 4730014.03766 11.80801 48.17152 533.47000 -0.02157 2.48952 8.87934 -1.21318 0.56645 -4.89522 8 8 0 1.77 -2013-Sep-20 09:11:26 4171694.89505 872121.09917 4730013.41178 11.80801 48.17152 532.97666 0.27817 2.10225 8.38600 -0.91345 0.17918 -5.38856 8 8 0 1.77 -2013-Sep-20 09:11:27 4171694.66456 872121.03217 4730013.18248 11.80801 48.17152 532.64619 0.25975 2.12766 8.05553 -0.93186 0.20458 -5.71903 8 8 0 1.77 -2013-Sep-20 09:11:27 4171695.13153 872121.16667 4730013.53852 11.80801 48.17152 533.23468 0.29585 2.00400 8.64403 -0.89577 0.08093 -5.13054 8 8 0 1.77 -2013-Sep-20 09:11:27 4171695.21893 872121.08356 4730013.02197 11.80801 48.17151 532.89549 0.19662 1.60844 8.30483 -0.99500 -0.31464 -5.46973 8 8 0 1.77 -2013-Sep-20 09:11:27 4171695.34719 872121.08913 4730013.23862 11.80801 48.17151 533.14141 0.17582 1.65852 8.55076 -1.01579 -0.26456 -5.22381 8 8 0 1.77 -2013-Sep-20 09:11:27 4171695.78405 872121.08917 4730013.08218 11.80801 48.17151 533.31002 0.08647 1.23555 8.71936 -1.10515 -0.68753 -5.05520 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.51473 872121.19700 4730012.97371 11.80801 48.17150 533.72090 0.04249 0.61383 9.13024 -1.14913 -1.30925 -4.64432 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.41898 872121.58683 4730013.01542 11.80801 48.17150 533.74267 0.44366 0.65204 9.15201 -0.74796 -1.27104 -4.62255 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.78157 872121.55351 4730013.08254 11.80801 48.17150 534.02483 0.33685 0.43742 9.43418 -0.85476 -1.48566 -4.34039 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.94521 872121.43326 4730013.19378 11.80801 48.17150 534.19814 0.18566 0.41058 9.60748 -1.00596 -1.51249 -4.16708 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.34722 872121.53376 4730013.01959 11.80801 48.17150 533.69169 0.40640 0.71525 9.10104 -0.78522 -1.20782 -4.67353 8 8 0 1.77 -2013-Sep-20 09:11:27 4171695.80649 872121.63805 4730013.15818 11.80801 48.17151 533.45621 0.61913 1.18618 8.86555 -0.57248 -0.73690 -4.90901 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.26694 872121.68348 4730013.63981 11.80801 48.17151 534.12187 0.56938 1.16460 9.53121 -0.62224 -0.75847 -4.24335 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.86514 872121.65469 4730014.17177 11.80801 48.17151 534.90483 0.41878 1.08745 10.31418 -0.77283 -0.83562 -3.46039 8 8 0 1.77 -2013-Sep-20 09:11:27 4171696.64572 872121.63862 4730014.60878 11.80801 48.17151 535.08503 0.44796 1.54138 10.49438 -0.74366 -0.38169 -3.28019 8 8 0 1.77 -2013-Sep-20 09:11:27 4171697.26958 872121.42909 4730014.98613 11.80801 48.17151 535.74487 0.11520 1.36996 11.15422 -1.07641 -0.55312 -2.62034 8 8 0 1.77 -2013-Sep-20 09:11:27 4171697.71455 872121.25431 4730015.45913 11.80800 48.17151 536.36394 -0.14694 1.38750 11.77329 -1.33855 -0.53558 -2.00127 8 8 0 1.77 -2013-Sep-20 09:11:27 4171697.93379 872121.15119 4730015.58951 11.80800 48.17151 536.59014 -0.29274 1.33027 11.99948 -1.48436 -0.59281 -1.77508 8 8 0 1.77 -2013-Sep-20 09:11:27 4171697.93831 872121.03476 4730015.93374 11.80800 48.17151 536.83370 -0.40763 1.57429 12.24304 -1.59924 -0.34878 -1.53152 8 8 0 1.77 -2013-Sep-20 09:11:27 4171698.05693 872120.81900 4730016.72257 11.80800 48.17152 537.46948 -0.64309 2.04674 12.87883 -1.83471 0.12367 -0.89573 8 8 0 1.77 -2013-Sep-20 09:11:27 4171698.85061 872120.85197 4730017.58196 11.80800 48.17152 538.63247 -0.77324 2.03596 14.04181 -1.96486 0.11288 0.26725 8 8 0 1.77 -2013-Sep-20 09:11:27 4171699.06065 872120.99495 4730018.08383 11.80800 48.17152 539.16305 -0.67627 2.19566 14.57240 -1.86788 0.27258 0.79783 8 8 0 1.77 -2013-Sep-20 09:11:27 4171700.12481 872120.98896 4730018.58090 11.80799 48.17151 540.22729 -0.89989 1.75190 15.63664 -2.09151 -0.17118 1.86207 8 8 0 1.77 -2013-Sep-20 09:11:27 4171700.76326 872121.27936 4730019.54425 11.80800 48.17151 541.40154 -0.74628 1.88441 16.81088 -1.93790 -0.03866 3.03632 8 8 0 1.77 -2013-Sep-20 09:11:27 4171700.78941 872121.59183 4730019.72916 11.80800 48.17152 541.59903 -0.44578 1.94100 17.00838 -1.63740 0.01793 3.23381 8 8 0 1.77 -2013-Sep-20 09:11:27 4171701.07459 872121.92558 4730020.12946 11.80800 48.17152 542.12903 -0.17744 1.94908 17.53837 -1.36906 0.02600 3.76381 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.52982 872122.32645 4730019.99796 11.80801 48.17152 541.73013 0.32642 2.19759 17.13947 -0.86520 0.27452 3.36491 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.65498 872122.59203 4730020.40760 11.80801 48.17152 542.15331 0.56077 2.33899 17.56266 -0.63085 0.41592 3.78810 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.02892 872122.65950 4730020.58537 11.80801 48.17152 542.53909 0.55029 2.17452 17.94844 -0.64133 0.25145 4.17387 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.34994 872123.10874 4730021.06532 11.80802 48.17152 543.16759 0.92433 2.19196 18.57693 -0.26729 0.26888 4.80237 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.41566 872123.29479 4730021.36912 11.80802 48.17152 543.46225 1.09300 2.31826 18.87160 -0.09862 0.39518 5.09704 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.99465 872123.57060 4730021.46935 11.80803 48.17152 543.29975 1.44912 2.65012 18.70909 0.25751 0.72704 4.93453 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.32391 872123.59479 4730022.26359 11.80802 48.17152 544.10981 1.40542 2.93596 19.51915 0.21380 1.01288 5.74459 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.51905 872123.74322 4730021.91649 11.80803 48.17152 543.99881 1.51078 2.53952 19.40816 0.31916 0.61644 5.63360 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.22378 872124.03588 4730021.56745 11.80803 48.17152 543.58592 1.85767 2.47748 18.99526 0.66605 0.55440 5.22070 8 8 0 1.77 -2013-Sep-20 09:11:28 4171701.17356 872124.18506 4730021.49768 11.80803 48.17152 543.52150 2.01397 2.44483 18.93085 0.82236 0.52176 5.15629 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.87815 872124.61377 4730021.22935 11.80804 48.17152 543.18723 2.49405 2.41597 18.59657 1.30244 0.49290 4.82201 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.53020 872124.46603 4730021.13499 11.80804 48.17152 542.86961 2.42065 2.62936 18.27895 1.22903 0.70628 4.50439 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.38751 872124.54003 4730021.76693 11.80804 48.17153 543.25745 2.52228 3.14359 18.66680 1.33066 1.22052 4.89224 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.48210 872124.29544 4730021.57373 11.80804 48.17152 543.14186 2.26351 2.98304 18.55120 1.07189 1.05997 4.77664 8 8 0 1.77 -2013-Sep-20 09:11:28 4171700.38441 872124.59308 4730020.93156 11.80804 48.17152 542.64020 2.57484 2.58065 18.04954 1.38322 0.65757 4.27498 8 8 0 1.77 -2013-Sep-20 09:11:28 4171699.43415 872124.94705 4730020.89155 11.80805 48.17153 542.03837 3.11577 3.19309 17.44771 1.92416 1.27001 3.67315 8 8 0 1.77 -2013-Sep-20 09:11:28 4171698.99007 872124.84567 4730020.49424 11.80805 48.17153 541.43860 3.10742 3.26748 16.84794 1.91580 1.34441 3.07338 8 8 0 1.77 -2013-Sep-20 09:11:28 4171698.59860 872124.96994 4730019.99661 11.80805 48.17153 540.82920 3.30916 3.20220 16.23854 2.11754 1.27912 2.46398 8 8 0 1.77 -2013-Sep-20 09:11:28 4171697.72330 872125.14159 4730019.33605 11.80805 48.17153 539.78902 3.65630 3.37392 15.19836 2.46468 1.45084 1.42380 8 8 0 1.77 -2013-Sep-20 09:11:28 4171697.44527 872125.13166 4730019.44510 11.80806 48.17153 539.68743 3.70347 3.65094 15.09677 2.51186 1.72787 1.32221 8 8 0 1.77 -2013-Sep-20 09:11:28 4171697.46512 872125.25487 4730019.99327 11.80806 48.17153 540.12566 3.82001 3.98325 15.53501 2.62839 2.06017 1.76045 8 8 0 1.77 -2013-Sep-20 09:11:28 4171697.81560 872125.36560 4730019.87160 11.80806 48.17153 540.27890 3.85668 3.62960 15.68824 2.66506 1.70652 1.91368 8 8 0 1.77 -2013-Sep-20 09:11:28 4171696.76963 872125.46839 4730018.63366 11.80806 48.17153 538.68769 4.17133 3.55124 14.09703 2.97971 1.62816 0.32247 8 8 0 1.77 -2013-Sep-20 09:11:28 4171696.98464 872125.66989 4730019.32905 11.80806 48.17153 539.37372 4.32457 3.82746 14.78306 3.13295 1.90438 1.00850 8 8 0 1.77 -2013-Sep-20 09:11:28 4171697.18226 872125.51418 4730019.42882 11.80806 48.17153 539.55581 4.13171 3.77359 14.96515 2.94010 1.85051 1.19059 8 8 0 1.77 -2013-Sep-20 09:11:29 4171696.78888 872125.47161 4730019.05047 11.80806 48.17153 539.01128 4.17055 3.81468 14.42062 2.97893 1.89160 0.64606 8 8 0 1.77 -2013-Sep-20 09:11:29 4171696.21747 872125.23603 4730018.43986 11.80806 48.17153 538.15112 4.05688 3.86016 13.56046 2.86526 1.93709 -0.21410 8 8 0 1.77 -2013-Sep-20 09:11:29 4171696.76275 872125.09584 4730018.79972 11.80806 48.17153 538.75610 3.80807 3.72381 14.16544 2.61646 1.80074 0.39088 8 8 0 1.77 -2013-Sep-20 09:11:29 4171696.28458 872125.11895 4730018.54831 11.80806 48.17153 538.25977 3.92854 3.90139 13.66911 2.73693 1.97832 -0.10545 8 8 0 1.77 -2013-Sep-20 09:11:29 4171695.51510 872125.05115 4730018.12311 11.80806 48.17154 537.43137 4.01964 4.18940 12.84071 2.82802 2.26632 -0.93385 8 8 0 1.77 -2013-Sep-20 09:11:29 4171695.70442 872124.86531 4730017.79648 11.80806 48.17153 537.28621 3.79899 3.86183 12.69555 2.60738 1.93875 -1.07901 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.02534 872124.68272 4730018.82343 11.80805 48.17153 538.88880 3.34996 3.61109 14.29814 2.15834 1.68802 0.52358 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.56713 872124.37971 4730019.39175 11.80805 48.17153 539.62460 2.94249 3.64114 15.03394 1.75087 1.71807 1.25938 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.12832 872123.99445 4730020.12268 11.80804 48.17153 540.48301 2.45055 3.77803 15.89236 1.25893 1.85495 2.11779 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.23677 872123.78912 4730019.90767 11.80804 48.17153 540.36557 2.22737 3.58684 15.77492 1.03576 1.66376 2.00036 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.12558 872123.42339 4730019.83102 11.80803 48.17153 540.18596 1.89214 3.67259 15.59531 0.70052 1.74952 1.82074 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.66725 872123.35494 4730019.71138 11.80803 48.17153 539.78828 1.91892 3.93753 15.19763 0.72731 2.01446 1.42306 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.75030 872123.45811 4730019.76202 11.80803 48.17153 539.89431 2.00291 3.89500 15.30365 0.81129 1.97192 1.52909 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.37489 872123.34486 4730019.00344 11.80803 48.17153 539.06854 1.96888 3.68019 14.47789 0.77727 1.75711 0.70332 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.56450 872122.96377 4730019.47053 11.80803 48.17153 539.48836 1.55705 3.91150 14.89771 0.36543 1.98843 1.12314 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.72707 872122.88434 4730019.91797 11.80803 48.17153 539.91705 1.44604 4.10344 15.32639 0.25443 2.18036 1.55183 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.24957 872122.89020 4730020.15076 11.80802 48.17153 540.43239 1.34485 3.87669 15.84174 0.15324 1.95362 2.06718 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.09813 872122.65932 4730020.01098 11.80802 48.17153 540.19787 1.14985 3.92914 15.60721 -0.04177 2.00606 1.83265 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.08833 872122.36723 4730019.75361 11.80802 48.17153 539.95984 0.86594 3.80918 15.36918 -0.32567 1.88611 1.59462 8 8 0 1.77 -2013-Sep-20 09:11:29 4171698.52223 872122.17729 4730019.92730 11.80801 48.17153 540.34658 0.59124 3.63750 15.75593 -0.60038 1.71442 1.98136 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.58285 872122.02297 4730019.52427 11.80801 48.17153 539.41199 0.63241 4.07741 14.82133 -0.55920 2.15434 1.04677 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.63924 872121.73716 4730019.17442 11.80801 48.17153 539.14910 0.34110 3.84655 14.55844 -0.85051 1.92347 0.78388 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.53461 872121.25933 4730018.70900 11.80800 48.17153 538.66879 -0.10520 3.68533 14.07814 -1.29681 1.76225 0.30357 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.81185 872121.15231 4730018.70755 11.80800 48.17153 538.83408 -0.26668 3.49847 14.24343 -1.45830 1.57539 0.46886 8 8 0 1.77 -2013-Sep-20 09:11:29 4171697.67496 872120.88634 4730018.42482 11.80800 48.17153 538.49775 -0.49902 3.45032 13.90709 -1.69064 1.52724 0.13253 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.95798 872120.75057 4730018.08811 11.80800 48.17153 538.41308 -0.68983 3.04004 13.82242 -1.88145 1.11697 0.04786 8 8 0 1.77 -2013-Sep-20 09:11:30 4171698.55581 872120.51012 4730017.92941 11.80799 48.17152 538.65226 -1.04753 2.53482 14.06161 -2.23915 0.61175 0.28704 8 8 0 1.77 -2013-Sep-20 09:11:30 4171698.69187 872120.08389 4730017.76410 11.80799 48.17152 538.55974 -1.49258 2.39033 13.96908 -2.68420 0.46726 0.19452 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.87169 872120.29824 4730017.38550 11.80799 48.17152 537.77148 -1.11493 2.70337 13.18082 -2.30654 0.78030 -0.59374 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.64076 872120.39637 4730017.21192 11.80799 48.17152 537.50477 -0.97163 2.74108 12.91412 -2.16324 0.81801 -0.86045 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.03278 872120.41985 4730016.60230 11.80799 48.17152 536.65684 -0.82423 2.77439 12.06618 -2.01585 0.85131 -1.70838 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.94921 872120.34663 4730016.54590 11.80799 48.17152 536.55027 -0.87880 2.80890 11.95961 -2.07041 0.88583 -1.81495 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.46511 872120.31730 4730016.54024 11.80799 48.17152 536.87882 -1.01307 2.43331 12.28817 -2.20469 0.51023 -1.48640 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.87515 872120.54066 4730015.97554 11.80800 48.17152 536.10340 -0.67371 2.45295 11.51274 -1.86533 0.52988 -2.26182 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.25109 872120.60664 4730016.19866 11.80800 48.17152 536.52407 -0.68606 2.31749 11.93341 -1.87768 0.39442 -1.84115 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.34559 872120.99690 4730015.52703 11.80800 48.17151 536.13855 -0.32339 1.74114 11.54790 -1.51501 -0.18193 -2.22667 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.94952 872121.11802 4730015.65610 11.80800 48.17151 536.64550 -0.32842 1.36827 12.05485 -1.52004 -0.55481 -1.71972 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.68473 872121.41412 4730015.38473 11.80801 48.17151 536.31085 0.01560 1.33527 11.72020 -1.17602 -0.58781 -2.05437 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.64638 872121.41032 4730014.74579 11.80801 48.17151 535.80919 0.01973 0.93771 11.21854 -1.17189 -0.98537 -2.55603 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.52681 872121.37284 4730014.26884 11.80801 48.17150 535.37063 0.00750 0.71256 10.77998 -1.18412 -1.21052 -2.99459 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.39677 872121.46519 4730014.27092 11.80801 48.17150 535.29989 0.12451 0.79471 10.70923 -1.06711 -1.12837 -3.06533 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.91048 872121.42730 4730014.21534 11.80801 48.17151 534.93586 0.18693 1.11811 10.34521 -1.00469 -0.80497 -3.42936 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.34401 872121.38274 4730014.32130 11.80801 48.17151 535.29174 0.05460 0.87936 10.70108 -1.13701 -1.04371 -3.07348 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.62437 872121.42704 4730014.61503 11.80801 48.17151 535.69967 0.04060 0.86401 11.10902 -1.15102 -1.05907 -2.66555 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.43824 872121.28637 4730014.15853 11.80800 48.17150 535.21881 -0.05902 0.71677 10.62815 -1.25063 -1.20630 -3.14641 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.18703 872121.33246 4730013.94351 11.80801 48.17150 534.90090 0.03751 0.74958 10.31024 -1.15411 -1.17350 -3.46432 8 8 0 1.77 -2013-Sep-20 09:11:30 4171697.04976 872121.55004 4730013.39163 11.80801 48.17150 534.42975 0.27858 0.44847 9.83909 -0.91304 -1.47461 -3.93547 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.25762 872121.59170 4730012.69762 11.80801 48.17150 533.40119 0.48145 0.55705 8.81054 -0.71016 -1.36602 -4.96403 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.09445 872121.84912 4730012.59140 11.80802 48.17150 533.25066 0.76682 0.56597 8.66000 -0.42480 -1.35710 -5.11456 8 8 0 1.77 -2013-Sep-20 09:11:30 4171696.35468 872122.09316 4730012.61714 11.80802 48.17150 533.47301 0.95244 0.35612 8.88236 -0.23918 -1.56696 -4.89220 8 8 0 1.77 -2013-Sep-20 09:11:31 4171695.57440 872122.03615 4730011.71188 11.80802 48.17150 532.28133 1.05630 0.33020 7.69067 -0.13531 -1.59287 -6.08389 8 8 0 1.77 -2013-Sep-20 09:11:31 4171695.30311 872122.12372 4730011.76943 11.80802 48.17150 532.15907 1.19754 0.55311 7.56841 0.00592 -1.36997 -6.20615 8 8 0 1.77 -2013-Sep-20 09:11:31 4171695.80571 872122.02064 4730012.13599 11.80802 48.17150 532.74624 0.99379 0.44670 8.15558 -0.19783 -1.47637 -5.61898 8 8 0 1.77 -2013-Sep-20 09:11:31 4171695.80804 872122.12795 4730012.24496 11.80802 48.17150 532.84360 1.09835 0.50131 8.25294 -0.09326 -1.42176 -5.52162 8 8 0 1.77 -2013-Sep-20 09:11:31 4171695.58737 872122.15744 4730012.18541 11.80802 48.17150 532.65920 1.17238 0.61806 8.06854 -0.01924 -1.30501 -5.70602 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.08043 872122.35230 4730012.01069 11.80802 48.17150 532.87746 1.26221 0.11219 8.28681 0.07060 -1.81089 -5.48776 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.60004 872122.11846 4730012.39081 11.80802 48.17150 533.46799 0.92699 0.02236 8.87733 -0.26463 -1.90071 -4.89723 8 8 0 1.77 -2013-Sep-20 09:11:31 4171697.05806 872122.17982 4730012.93349 11.80802 48.17150 534.17973 0.89332 0.04085 9.58908 -0.29829 -1.88222 -4.18549 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.98371 872122.24762 4730012.53119 11.80802 48.17150 533.84068 0.97491 -0.18355 9.25002 -0.21671 -2.10662 -4.52454 8 8 0 1.77 -2013-Sep-20 09:11:31 4171697.39306 872122.65016 4730012.35033 11.80802 48.17149 534.02806 1.28516 -0.66412 9.43741 0.09355 -2.58719 -4.33715 8 8 0 1.77 -2013-Sep-20 09:11:31 4171697.07385 872122.65968 4730012.33553 11.80802 48.17149 533.80995 1.35980 -0.44261 9.21930 0.16819 -2.36569 -4.55526 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.89636 872122.75231 4730012.64118 11.80803 48.17150 533.93449 1.48680 -0.12344 9.34383 0.29518 -2.04652 -4.43073 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.90097 872122.83998 4730012.49885 11.80803 48.17150 533.84341 1.57167 -0.23510 9.25275 0.38005 -2.15817 -4.52181 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.56988 872122.77570 4730012.12547 11.80803 48.17150 533.34028 1.57650 -0.23282 8.74962 0.38488 -2.15589 -5.02494 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.90638 872123.16968 4730012.90867 11.80803 48.17150 534.19731 1.89328 -0.01601 9.60665 0.70167 -1.93908 -4.16791 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.93262 872123.23397 4730013.37515 11.80803 48.17150 534.57081 1.95084 0.26615 9.98015 0.75922 -1.65692 -3.79441 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.44547 872123.11676 4730013.84584 11.80803 48.17151 534.58753 1.93580 0.95325 9.99688 0.74418 -0.96983 -3.77768 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.91712 872123.00276 4730014.14716 11.80803 48.17151 535.10440 1.72770 0.82757 10.51374 0.53608 -1.09551 -3.26082 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.90946 872122.96311 4730014.27723 11.80803 48.17151 535.19091 1.69045 0.92595 10.60025 0.49884 -0.99713 -3.17431 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.85995 872123.14457 4730014.79767 11.80803 48.17151 535.57116 1.87821 1.28147 10.98050 0.68659 -0.64161 -2.79406 8 8 0 1.77 -2013-Sep-20 09:11:31 4171697.06111 872122.99213 4730014.87195 11.80803 48.17151 535.73701 1.68782 1.20753 11.14636 0.49620 -0.71555 -2.62821 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.82169 872122.98291 4730014.50520 11.80803 48.17151 535.30618 1.72779 1.13897 10.71552 0.53618 -0.78410 -3.05904 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.27066 872123.20205 4730014.31034 11.80803 48.17151 534.83118 2.05506 1.37752 10.24053 0.86344 -0.54555 -3.53403 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.66869 872123.31062 4730014.51046 11.80803 48.17151 535.25494 2.07988 1.20411 10.66429 0.88827 -0.71896 -3.11027 8 8 0 1.77 -2013-Sep-20 09:11:31 4171696.89869 872123.13147 4730014.82167 11.80803 48.17151 535.61254 1.85745 1.27122 11.02188 0.66583 -0.65186 -2.75268 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.32813 872123.31435 4730014.33550 11.80803 48.17151 534.90277 2.15322 1.33526 10.31211 0.96160 -0.58782 -3.46245 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.18633 872123.20310 4730014.74184 11.80803 48.17151 535.09780 2.07334 1.72663 10.50715 0.88173 -0.19644 -3.26742 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.27298 872123.10448 4730014.63518 11.80803 48.17151 535.06143 1.95908 1.60734 10.47078 0.76746 -0.31573 -3.30379 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.10210 872123.03634 4730014.64304 11.80803 48.17151 534.94644 1.92734 1.74760 10.35579 0.73573 -0.17547 -3.41877 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.45372 872123.10537 4730014.93485 11.80803 48.17151 535.40283 1.92296 1.67523 10.81218 0.73135 -0.24785 -2.96238 8 8 0 1.77 -2013-Sep-20 09:11:32 4171695.86908 872123.18824 4730014.32371 11.80803 48.17151 534.57711 2.12371 1.68144 9.98646 0.93209 -0.24163 -3.78811 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.20607 872123.06401 4730014.80380 11.80803 48.17151 535.13787 1.93315 1.77477 10.54722 0.74153 -0.14831 -3.22735 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.15347 872123.13235 4730015.53661 11.80803 48.17152 535.65892 2.01081 2.29142 11.06826 0.81920 0.36835 -2.70630 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.10099 872122.91880 4730015.59920 11.80803 48.17152 535.64215 1.81252 2.40401 11.05150 0.62090 0.48093 -2.72306 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.24578 872122.51715 4730016.02501 11.80802 48.17152 535.99915 1.38974 2.64362 11.40849 0.19812 0.72055 -2.36607 8 8 0 1.77 -2013-Sep-20 09:11:32 4171696.72054 872122.33254 4730017.07891 11.80802 48.17152 537.06919 1.11189 3.02834 12.47853 -0.07973 1.10526 -1.29603 8 8 0 1.77 -2013-Sep-20 09:11:32 4171697.13285 872122.48619 4730018.29592 11.80802 48.17153 538.26615 1.17791 3.51581 13.67550 -0.01371 1.59273 -0.09907 8 8 0 1.77 -2013-Sep-20 09:11:32 4171697.43301 872122.61570 4730018.73323 11.80802 48.17153 538.80562 1.24326 3.56877 14.21497 0.05164 1.64570 0.44040 8 8 0 1.77 -2013-Sep-20 09:11:32 4171697.83279 872122.26746 4730019.24052 11.80802 48.17153 539.39708 0.82058 3.66860 14.80642 -0.37104 1.74552 1.03186 8 8 0 1.77 -2013-Sep-20 09:11:32 4171698.11794 872122.37574 4730020.06919 11.80802 48.17153 540.21547 0.86822 3.99675 15.62482 -0.32340 2.07367 1.85026 8 8 0 1.77 -2013-Sep-20 09:11:32 4171698.54136 872122.49566 4730021.03681 11.80802 48.17154 541.22926 0.89895 4.31494 16.63861 -0.29266 2.39186 2.86404 8 8 0 1.77 -2013-Sep-20 09:11:32 4171699.86273 872122.11376 4730022.35947 11.80801 48.17154 543.02530 0.25474 4.29148 18.43464 -0.93688 2.36841 4.66008 8 8 0 1.77 -2013-Sep-20 09:11:32 4171699.80268 872122.20783 4730021.88027 11.80801 48.17153 542.64186 0.35911 4.00136 18.05121 -0.83251 2.07828 4.27664 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.62569 872122.20454 4730022.52266 11.80801 48.17153 543.65734 0.18747 3.82999 19.06668 -1.00415 1.90691 5.29212 8 8 0 1.77 -2013-Sep-20 09:11:32 4171701.64625 872122.16838 4730023.30237 11.80800 48.17153 544.89961 -0.05677 3.61112 20.30895 -1.24838 1.68804 6.53439 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.59443 872122.18177 4730022.93324 11.80801 48.17153 543.93976 0.17158 4.13008 19.34910 -1.02004 2.20700 5.57454 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.74012 872122.23819 4730022.31783 11.80801 48.17153 543.58400 0.19700 3.60479 18.99334 -0.99462 1.68171 5.21878 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.60245 872122.27861 4730021.57296 11.80801 48.17153 542.94461 0.26473 3.20228 18.35395 -0.92688 1.27921 4.57939 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.09069 872122.54839 4730020.67258 11.80801 48.17152 541.97645 0.63353 2.93395 17.38579 -0.55809 1.01087 3.61123 8 8 0 1.77 -2013-Sep-20 09:11:32 4171700.17827 872122.49543 4730021.07262 11.80801 48.17153 542.32447 0.56377 3.14493 17.73382 -0.62785 1.22186 3.95925 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.52122 872122.39584 4730021.11704 11.80801 48.17152 542.56786 0.39610 2.93960 17.97721 -0.79551 1.01652 4.20264 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.50160 872122.53942 4730021.07448 11.80801 48.17152 542.54293 0.54066 2.90364 17.95227 -0.65095 0.98056 4.17771 8 8 0 1.77 -2013-Sep-20 09:11:33 4171699.96097 872122.36479 4730020.57774 11.80801 48.17152 541.79604 0.48036 2.99331 17.20539 -0.71126 1.07023 3.43082 8 8 0 1.77 -2013-Sep-20 09:11:33 4171699.87708 872122.52914 4730020.89270 11.80801 48.17153 541.99839 0.65840 3.23948 17.40774 -0.53322 1.31640 3.63318 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.39593 872122.36514 4730020.89595 11.80801 48.17152 542.31713 0.39169 2.88823 17.72648 -0.79993 0.96515 3.95192 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.84997 872122.28805 4730021.13728 11.80801 48.17152 542.78284 0.22332 2.72975 18.19218 -0.96829 0.80668 4.41762 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.80172 872122.66262 4730021.11873 11.80801 48.17152 542.78863 0.59983 2.69546 18.19798 -0.59178 0.77238 4.42341 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.20726 872122.54494 4730020.99090 11.80801 48.17152 542.94205 0.40166 2.33236 18.35139 -0.78996 0.40929 4.57683 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.79912 872122.61896 4730021.71637 11.80801 48.17152 543.87909 0.35300 2.37321 19.28844 -0.83862 0.45013 5.51387 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.92734 872122.66132 4730021.76378 11.80801 48.17152 544.00391 0.36823 2.30484 19.41325 -0.82339 0.38176 5.63869 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.71728 872122.99727 4730021.38595 11.80802 48.17152 543.63109 0.74005 2.15486 19.04043 -0.45157 0.23178 5.26587 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.13521 872123.10929 4730020.58580 11.80802 48.17152 542.67018 0.96881 2.02870 18.07952 -0.22281 0.10562 4.30496 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.32333 872123.10249 4730020.89961 11.80802 48.17152 543.02589 0.92366 2.10181 18.43523 -0.26796 0.17873 4.66067 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.64359 872122.60096 4730021.57231 11.80801 48.17151 544.32055 0.16257 1.66394 19.72990 -1.02904 -0.25914 5.95534 8 8 0 1.77 -2013-Sep-20 09:11:33 4171703.18094 872122.57524 4730021.77828 11.80801 48.17151 544.82130 0.02744 1.41329 20.23065 -1.16418 -0.50979 6.45608 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.50049 872122.75788 4730020.47607 11.80801 48.17151 543.43170 0.34545 1.01330 18.84105 -0.84616 -0.90978 5.06648 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.93086 872122.77874 4730020.11851 11.80801 48.17151 542.79626 0.48244 1.18713 18.20561 -0.70918 -0.73594 4.43104 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.33724 872122.68858 4730020.69325 11.80801 48.17151 543.47750 0.31103 1.28778 18.88685 -0.88059 -0.63530 5.11229 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.47075 872122.84113 4730019.74234 11.80801 48.17150 542.87691 0.43303 0.53297 18.28625 -0.75859 -1.39010 4.51169 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.13286 872123.00777 4730018.89500 11.80801 48.17150 542.04769 0.66528 0.18891 17.45704 -0.52633 -1.73416 3.68247 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.76657 872123.10940 4730019.35636 11.80801 48.17150 542.81902 0.63509 0.01889 18.22837 -0.55653 -1.90419 4.45380 8 8 0 1.77 -2013-Sep-20 09:11:33 4171702.42018 872123.04641 4730019.25701 11.80801 48.17150 542.51027 0.64431 0.21489 17.91962 -0.54731 -1.70819 4.14505 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.84028 872123.36614 4730018.86866 11.80802 48.17150 541.88597 1.07595 0.33011 17.29532 -0.11567 -1.59297 3.52075 8 8 0 1.77 -2013-Sep-20 09:11:33 4171701.14808 872123.15131 4730018.74197 11.80802 48.17150 541.31039 1.00731 0.78325 16.71974 -0.18431 -1.13982 2.94517 8 8 0 1.77 -2013-Sep-20 09:11:33 4171700.53555 872123.31218 4730017.57763 11.80802 48.17150 540.06489 1.29012 0.42898 15.47424 0.09850 -1.49410 1.69967 8 8 0 1.77 -2013-Sep-20 09:11:34 4171700.42117 872123.25576 4730017.54686 11.80802 48.17150 539.95960 1.25829 0.50049 15.36895 0.06668 -1.42258 1.59438 8 8 0 1.77 -2013-Sep-20 09:11:34 4171700.20457 872123.16736 4730017.03642 11.80802 48.17150 539.42579 1.21609 0.33154 14.83514 0.02448 -1.59154 1.06057 8 8 0 1.77 -2013-Sep-20 09:11:34 4171699.48898 872123.38902 4730016.53228 11.80803 48.17150 538.61325 1.57949 0.48346 14.02260 0.38788 -1.43962 0.24803 8 8 0 1.77 -2013-Sep-20 09:11:34 4171699.10423 872123.31378 4730016.40570 11.80803 48.17150 538.25750 1.58458 0.69115 13.66685 0.39297 -1.23193 -0.10772 8 8 0 1.77 -2013-Sep-20 09:11:34 4171698.53020 872123.35368 4730015.91311 11.80803 48.17150 537.52118 1.74110 0.77523 12.93052 0.54948 -1.14785 -0.84404 8 8 0 1.77 -2013-Sep-20 09:11:34 4171698.50153 872123.20864 4730015.82793 11.80803 48.17150 537.41920 1.60500 0.76146 12.82854 0.41338 -1.16162 -0.94602 8 8 0 1.77 -2013-Sep-20 09:11:34 4171698.36186 872122.83570 4730016.44436 11.80802 48.17151 537.73645 1.26853 1.33130 13.14580 0.07692 -0.59178 -0.62876 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.86285 872123.10170 4730016.43915 11.80803 48.17151 537.44312 1.63102 1.65122 12.85246 0.43940 -0.27185 -0.92210 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.51138 872123.13143 4730016.77232 11.80803 48.17152 537.46601 1.73204 2.12524 12.87535 0.54042 0.20216 -0.89921 8 8 0 1.77 -2013-Sep-20 09:11:34 4171696.91445 872123.48157 4730016.67884 11.80804 48.17152 537.05446 2.19692 2.44489 12.46381 1.00530 0.52182 -1.31076 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.26836 872123.33992 4730016.78699 11.80803 48.17152 537.34675 1.98584 2.28048 12.75610 0.79423 0.35741 -1.01847 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.49048 872123.06464 4730017.13771 11.80803 48.17152 537.71552 1.67093 2.39435 13.12486 0.47932 0.47127 -0.64970 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.48935 872122.81882 4730017.21277 11.80802 48.17152 537.73716 1.43055 2.48271 13.14650 0.23894 0.55963 -0.62806 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.29650 872122.92735 4730017.19523 11.80803 48.17152 537.61301 1.57625 2.59512 13.02235 0.38463 0.67205 -0.75221 8 8 0 1.77 -2013-Sep-20 09:11:34 4171696.80407 872122.82700 4730016.90491 11.80803 48.17152 537.06153 1.57879 2.77598 12.47088 0.38718 0.85290 -1.30368 8 8 0 1.77 -2013-Sep-20 09:11:34 4171696.78524 872122.99113 4730016.45835 11.80803 48.17152 536.73889 1.74330 2.46688 12.14823 0.55168 0.54380 -1.62633 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.30776 872123.19322 4730017.55162 11.80803 48.17152 537.92221 1.83418 2.78404 13.33155 0.64257 0.86097 -0.44301 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.26132 872123.54045 4730017.62032 11.80803 48.17152 537.99047 2.18358 2.81079 13.39981 0.99196 0.88772 -0.37475 8 8 0 1.77 -2013-Sep-20 09:11:34 4171696.82780 872124.11133 4730017.34288 11.80804 48.17152 537.57865 2.83109 2.85492 12.98799 1.63947 0.93184 -0.78657 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.46836 872124.32511 4730018.39105 11.80804 48.17153 538.80701 2.90926 3.05414 14.21635 1.71765 1.13106 0.44179 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.55276 872124.50549 4730018.71691 11.80805 48.17153 539.12953 3.06855 3.18239 14.53887 1.87694 1.25931 0.76431 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.55168 872124.51393 4730018.39441 11.80805 48.17152 538.88967 3.07703 2.96681 14.29902 1.88542 1.04373 0.52445 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.36481 872124.89308 4730018.29105 11.80805 48.17152 538.74240 3.48640 2.97637 14.15175 2.29478 1.05329 0.37719 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.26694 872125.02011 4730018.57381 11.80805 48.17153 538.90656 3.63077 3.21696 14.31590 2.43915 1.29388 0.54134 8 8 0 1.77 -2013-Sep-20 09:11:34 4171697.67706 872125.05021 4730019.04317 11.80805 48.17153 539.52812 3.57632 3.22625 14.93747 2.38470 1.30317 1.16291 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.65767 872124.80853 4730019.75907 11.80805 48.17152 540.66873 3.13908 3.02531 16.07807 1.94747 1.10223 2.30351 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.51682 872124.76603 4730019.92156 11.80805 48.17153 540.69206 3.12630 3.24288 16.10141 1.93468 1.31981 2.32684 8 8 0 1.77 -2013-Sep-20 09:11:35 4171697.78674 872124.63825 4730019.06154 11.80805 48.17153 539.55719 3.15063 3.22132 14.96653 1.95901 1.29824 1.19197 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.29502 872124.37519 4730019.82941 11.80804 48.17153 540.42526 2.78912 3.40280 15.83461 1.59751 1.47972 2.06004 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.28081 872124.54475 4730020.08474 11.80805 48.17153 540.62939 2.95800 3.55760 16.03873 1.76638 1.63452 2.26417 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.43010 872124.68264 4730019.54760 11.80805 48.17153 540.34542 3.06242 3.06946 15.75476 1.87080 1.14638 1.98020 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.61533 872124.57665 4730018.99425 11.80804 48.17152 540.03954 2.92077 2.58148 15.44889 1.72915 0.65841 1.67433 8 8 0 1.77 -2013-Sep-20 09:11:35 4171697.52985 872124.81035 4730017.96036 11.80805 48.17152 538.59245 3.37165 2.64807 14.00179 2.18004 0.72499 0.22723 8 8 0 1.77 -2013-Sep-20 09:11:35 4171697.44892 872124.28273 4730018.19984 11.80804 48.17152 538.64606 2.87175 2.94726 14.05540 1.68014 1.02419 0.28084 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.84425 872124.24928 4730018.11610 11.80805 48.17153 538.18437 2.96275 3.33755 13.59371 1.77114 1.41447 -0.18085 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.05476 872124.25250 4730017.70527 11.80805 48.17153 537.36331 3.12746 3.63891 12.77265 1.93584 1.71583 -1.00191 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.41720 872123.98307 4730017.99384 11.80804 48.17153 537.77816 2.78956 3.60808 13.18751 1.59794 1.68501 -0.58706 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.64325 872124.03123 4730018.07510 11.80804 48.17153 537.99286 2.79044 3.49006 13.40220 1.59882 1.56698 -0.37236 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.50813 872123.77058 4730017.61193 11.80804 48.17153 537.52395 2.56296 3.31946 12.93330 1.37135 1.39639 -0.84127 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.75877 872123.80649 4730017.11835 11.80804 48.17152 537.32468 2.54682 2.80200 12.73402 1.35521 0.87893 -1.04054 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.93473 872123.61640 4730017.06774 11.80804 48.17152 537.37588 2.32474 2.66890 12.78523 1.13313 0.74583 -0.98933 8 8 0 1.77 -2013-Sep-20 09:11:35 4171697.01026 872123.53990 4730016.75921 11.80804 48.17152 537.18485 2.23441 2.41972 12.59420 1.04280 0.49664 -1.18037 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.75450 872123.48011 4730017.12431 11.80804 48.17152 537.28179 2.22822 2.85887 12.69113 1.03660 0.93579 -1.08343 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.56156 872123.46089 4730017.25945 11.80804 48.17153 537.25391 2.24889 3.09265 12.66326 1.05728 1.16957 -1.11130 8 8 0 1.77 -2013-Sep-20 09:11:35 4171696.60040 872123.20806 4730017.40097 11.80803 48.17153 537.35022 1.99347 3.19725 12.75956 0.80185 1.27418 -1.01500 8 8 0 1.77 -2013-Sep-20 09:11:35 4171697.69286 872123.10255 4730017.47997 11.80803 48.17152 538.10783 1.66663 2.46920 13.51717 0.47501 0.54613 -0.25739 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.61452 872123.20546 4730017.82572 11.80803 48.17152 538.98116 1.57876 2.01186 14.39051 0.38714 0.08878 0.61594 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.81027 872122.96455 4730017.84947 11.80802 48.17151 539.09376 1.30289 1.92165 14.50311 0.11127 -0.00142 0.72854 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.94150 872122.88799 4730017.67845 11.80802 48.17151 539.04155 1.20110 1.72356 14.45089 0.00949 -0.19951 0.67633 8 8 0 1.77 -2013-Sep-20 09:11:35 4171698.78644 872122.53563 4730017.48346 11.80802 48.17151 538.74695 0.88792 1.76035 14.15629 -0.30369 -0.16273 0.38173 8 8 0 1.77 -2013-Sep-20 09:11:36 4171698.71258 872122.54555 4730017.47869 11.80802 48.17151 538.69653 0.91275 1.80952 14.10587 -0.27887 -0.11355 0.33131 8 8 0 1.77 -2013-Sep-20 09:11:36 4171692.08780 872117.62066 4730009.36614 11.80797 48.17152 527.65481 -2.55228 1.98215 3.06416 -3.74389 0.05907 -10.71041 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.42295 872122.68150 4730017.67368 11.80802 48.17151 539.32410 0.90046 1.40071 14.73344 -0.29116 -0.52237 0.95888 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.34739 872122.74404 4730017.51190 11.80802 48.17151 539.16276 0.97714 1.33839 14.57211 -0.21448 -0.58469 0.79754 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.57788 872122.43968 4730017.96182 11.80801 48.17151 539.60694 0.63205 1.51674 15.01629 -0.55957 -0.40634 1.24173 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.82119 872122.31826 4730018.04019 11.80801 48.17151 539.80760 0.46341 1.41005 15.21694 -0.72820 -0.51302 1.44238 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.93691 872122.20019 4730019.23629 11.80801 48.17152 540.75829 0.32416 2.14134 16.16764 -0.86746 0.21826 2.39307 8 8 0 1.77 -2013-Sep-20 09:11:36 4171700.21565 872122.29495 4730019.22303 11.80801 48.17151 540.94331 0.35987 1.91474 16.35265 -0.83175 -0.00833 2.57809 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.68289 872122.42175 4730019.28578 11.80801 48.17152 540.65959 0.59301 2.32583 16.06893 -0.59860 0.40276 2.29437 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.17586 872122.30296 4730018.98768 11.80801 48.17152 540.09026 0.58049 2.51496 15.49961 -0.61113 0.59189 1.72504 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.55863 872122.33378 4730019.24155 11.80801 48.17152 540.53350 0.53234 2.40038 15.94285 -0.65928 0.47731 2.16828 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.30149 872122.11525 4730018.45649 11.80801 48.17152 539.75084 0.37105 2.09770 15.16018 -0.82057 0.17462 1.38562 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.50347 872121.95051 4730018.67473 11.80801 48.17152 540.02283 0.16846 2.12105 15.43217 -1.02315 0.19797 1.65761 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.93110 872122.07347 4730018.97306 11.80801 48.17152 540.54106 0.20131 1.98935 15.95041 -0.99031 0.06627 2.17584 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.81615 872122.02527 4730018.75454 11.80801 48.17152 540.29662 0.17765 1.93481 15.70597 -1.01396 0.01173 1.93141 8 8 0 1.77 -2013-Sep-20 09:11:36 4171700.26621 872121.83560 4730018.56130 11.80800 48.17151 540.42053 -0.10010 1.50659 15.82988 -1.29172 -0.41648 2.05531 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.54501 872122.00064 4730018.16401 11.80801 48.17151 539.67623 0.20902 1.74250 15.08557 -0.98259 -0.18058 1.31101 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.70760 872122.10430 4730018.18608 11.80801 48.17151 539.81296 0.27722 1.62283 15.22230 -0.91439 -0.30025 1.44774 8 8 0 1.77 -2013-Sep-20 09:11:36 4171700.17929 872121.62729 4730018.70168 11.80800 48.17151 540.43997 -0.28622 1.69537 15.84931 -1.47783 -0.22770 2.07475 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.92479 872121.77983 4730017.85113 11.80800 48.17151 539.66087 -0.08482 1.29051 15.07022 -1.27644 -0.63256 1.29565 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.19856 872121.68303 4730017.00367 11.80801 48.17151 538.54211 -0.03096 1.26979 13.95145 -1.22258 -0.65329 0.17689 8 8 0 1.77 -2013-Sep-20 09:11:36 4171699.05166 872121.68371 4730017.12761 11.80801 48.17151 538.53865 -0.00024 1.45949 13.94800 -1.19186 -0.46359 0.17343 8 8 0 1.77 -2013-Sep-20 09:11:36 4171698.83178 872121.65585 4730017.32318 11.80801 48.17151 538.53704 0.01749 1.75454 13.94639 -1.17413 -0.16854 0.17183 8 8 0 1.77 -2013-Sep-20 09:11:36 4171697.67544 872121.59601 4730016.92800 11.80801 48.17152 537.47957 0.19554 2.34352 12.88891 -0.99608 0.42044 -0.88565 8 8 0 1.77 -2013-Sep-20 09:11:36 4171696.75381 872121.63033 4730015.94438 11.80801 48.17152 536.14968 0.41772 2.35452 11.55902 -0.77389 0.43145 -2.21554 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.68678 872121.53815 4730015.90502 11.80801 48.17152 536.06401 0.34121 2.39122 11.47336 -0.85041 0.46814 -2.30121 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.78946 872121.23712 4730015.64127 11.80801 48.17152 535.89343 0.02555 2.18634 11.30278 -1.16607 0.26326 -2.47179 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.27050 872121.29362 4730015.79515 11.80801 48.17152 535.67703 0.18705 2.65885 11.08638 -1.00457 0.73578 -2.68819 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.15309 872121.44701 4730015.43961 11.80801 48.17152 535.35639 0.36122 2.48399 10.76574 -0.83040 0.56092 -3.00883 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.02501 872121.40946 4730015.47945 11.80801 48.17152 535.29734 0.35067 2.60971 10.70669 -0.84095 0.68664 -3.06788 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.34332 872121.48162 4730015.55857 11.80801 48.17152 535.57393 0.35616 2.41930 10.98328 -0.83545 0.49622 -2.79128 8 8 0 1.77 -2013-Sep-20 09:11:37 4171697.09687 872121.37504 4730015.67203 11.80801 48.17152 536.13585 0.09764 1.96160 11.54519 -1.09397 0.03852 -2.22937 8 8 0 1.77 -2013-Sep-20 09:11:37 4171697.42386 872121.49349 4730015.68264 11.80801 48.17151 536.37337 0.14667 1.71211 11.78272 -1.04495 -0.21096 -1.99185 8 8 0 1.77 -2013-Sep-20 09:11:37 4171697.25907 872121.47626 4730015.53919 11.80801 48.17151 536.15656 0.16353 1.73926 11.56590 -1.02809 -0.18381 -2.20866 8 8 0 1.77 -2013-Sep-20 09:11:37 4171697.41257 872121.73226 4730016.38176 11.80801 48.17152 536.91953 0.38269 2.15019 12.32888 -0.80892 0.22711 -1.44569 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.66260 872121.97635 4730016.02795 11.80802 48.17152 536.19963 0.77509 2.42402 11.60897 -0.41653 0.50094 -2.16559 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.52940 872122.07884 4730015.80709 11.80802 48.17152 535.96209 0.90267 2.35825 11.37144 -0.28895 0.43518 -2.40313 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.42724 872122.07034 4730015.85008 11.80802 48.17152 535.92628 0.91525 2.46273 11.33562 -0.27636 0.53966 -2.43894 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.03158 872122.19825 4730015.86903 11.80802 48.17152 535.69957 1.12142 2.74445 11.10891 -0.07020 0.82137 -2.66565 8 8 0 1.77 -2013-Sep-20 09:11:37 4171696.52098 872122.29289 4730015.90855 11.80802 48.17152 536.06141 1.11391 2.39942 11.47075 -0.07770 0.47635 -2.30381 8 8 0 1.77 -2013-Sep-20 09:11:37 4171695.43143 872122.56906 4730014.70352 11.80803 48.17152 534.48993 1.60719 2.34836 9.89927 0.41558 0.42529 -3.87529 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.98794 872122.92920 4730013.97303 11.80803 48.17152 533.70525 2.05046 2.12975 9.11460 0.85885 0.20668 -4.65997 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.79285 872122.92647 4730013.76788 11.80803 48.17152 533.42466 2.08771 2.13565 8.83401 0.89609 0.21257 -4.94056 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.28728 872122.93402 4730013.96065 11.80804 48.17152 533.23931 2.19856 2.63181 8.64865 1.00694 0.70873 -5.12591 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.60212 872123.07678 4730014.43498 11.80804 48.17152 533.81775 2.27387 2.69673 9.22710 1.08225 0.77366 -4.54747 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.59957 872123.41621 4730014.86278 11.80804 48.17152 534.18118 2.60664 2.93214 9.59052 1.41502 1.00907 -4.18404 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.71925 872123.65836 4730015.04824 11.80804 48.17152 534.43054 2.81918 2.93161 9.83989 1.62756 1.00853 -3.93467 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.40657 872123.74338 4730014.91773 11.80805 48.17153 534.14079 2.96638 3.05967 9.55014 1.77477 1.13659 -4.22443 8 8 0 1.77 -2013-Sep-20 09:11:37 4171693.82276 872123.87665 4730014.40044 11.80805 48.17153 533.39241 3.21631 3.12018 8.80176 2.02469 1.19711 -4.97281 8 8 0 1.77 -2013-Sep-20 09:11:37 4171694.43490 872123.87789 4730014.61609 11.80805 48.17152 533.95287 3.09225 2.81734 9.36222 1.90063 0.89426 -4.41234 8 8 0 1.77 -2013-Sep-20 09:11:38 4171694.56204 872123.70075 4730015.20182 11.80804 48.17153 534.44815 2.89285 3.14223 9.85749 1.70123 1.21916 -3.91707 8 8 0 1.77 -2013-Sep-20 09:11:38 4171694.88830 872123.56695 4730015.54855 11.80804 48.17153 534.90123 2.69511 3.15590 10.31057 1.50350 1.23283 -3.46399 8 8 0 1.77 -2013-Sep-20 09:11:38 4171694.40509 872123.47126 4730015.61395 11.80804 48.17153 534.62147 2.70033 3.56655 10.03081 1.50871 1.64348 -3.74375 8 8 0 1.77 -2013-Sep-20 09:11:38 4171694.81287 872123.60448 4730015.55851 11.80804 48.17153 534.86454 2.74728 3.21184 10.27389 1.55567 1.28876 -3.50068 8 8 0 1.77 -2013-Sep-20 09:11:38 4171695.06552 872123.69697 4730015.22353 11.80804 48.17152 534.79248 2.78612 2.79006 10.20182 1.59450 0.86699 -3.57274 8 8 0 1.77 -2013-Sep-20 09:11:38 4171695.13714 872123.96936 4730015.17086 11.80805 48.17152 534.83716 3.03809 2.66117 10.24650 1.84647 0.73809 -3.52806 8 8 0 1.77 -2013-Sep-20 09:11:38 4171695.53773 872123.96143 4730015.20964 11.80805 48.17152 535.12647 2.94835 2.39605 10.53582 1.75673 0.47298 -3.23874 8 8 0 1.77 -2013-Sep-20 09:11:38 4171695.58338 872124.17985 4730015.02429 11.80805 48.17152 535.04797 3.15280 2.20584 10.45731 1.96118 0.28277 -3.31725 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.24390 872124.05151 4730015.98736 11.80804 48.17152 536.17926 2.89202 2.38592 11.58861 1.70040 0.46284 -2.18596 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.13432 872124.13431 4730016.24343 11.80805 48.17152 536.30983 2.99549 2.62399 11.71918 1.80387 0.70091 -2.05539 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.63458 872124.14825 4730016.13636 11.80804 48.17152 536.55853 2.90676 2.18558 11.96787 1.71515 0.26251 -1.80669 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.17818 872123.87674 4730016.26463 11.80804 48.17152 536.31912 2.73439 2.64542 11.72846 1.54278 0.72234 -2.04610 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.47039 872123.99945 4730016.03400 11.80804 48.17152 536.35476 2.79471 2.25976 11.76410 1.60309 0.33669 -2.01046 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.72307 872123.89857 4730016.65270 11.80804 48.17152 536.96696 2.64425 2.50346 12.37630 1.45264 0.58038 -1.39826 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.48511 872124.07841 4730016.49433 11.80804 48.17152 536.71816 2.86898 2.54399 12.12750 1.67737 0.62091 -1.64706 8 8 0 1.77 -2013-Sep-20 09:11:38 4171696.77053 872123.91100 4730017.14859 11.80804 48.17152 537.36915 2.64671 2.79766 12.77849 1.45509 0.87458 -0.99607 8 8 0 1.77 -2013-Sep-20 09:11:38 4171697.76226 872124.02423 4730017.93984 11.80804 48.17152 538.62159 2.55460 2.58474 14.03094 1.36299 0.66166 0.25637 8 8 0 1.77 -2013-Sep-20 09:11:38 4171697.80503 872124.02244 4730018.57734 11.80804 48.17152 539.12429 2.54410 2.97897 14.53363 1.35249 1.05589 0.75907 8 8 0 1.77 -2013-Sep-20 09:11:38 4171698.31009 872123.51650 4730019.21589 11.80803 48.17153 539.86076 1.94552 3.11359 15.27010 0.75391 1.19051 1.49554 8 8 0 1.77 -2013-Sep-20 09:11:38 4171698.69098 872123.15931 4730019.58334 11.80803 48.17153 540.33445 1.51794 3.13529 15.74380 0.32632 1.21222 1.96924 8 8 0 1.77 -2013-Sep-20 09:11:38 4171698.72521 872122.93230 4730019.69460 11.80802 48.17153 540.40872 1.28873 3.21914 15.81807 0.09711 1.29606 2.04351 8 8 0 1.77 -2013-Sep-20 09:11:38 4171698.66931 872122.71251 4730019.83349 11.80802 48.17153 540.44574 1.08503 3.38605 15.85508 -0.10658 1.46298 2.08052 8 8 0 1.77 -2013-Sep-20 09:11:38 4171699.00295 872122.78526 4730020.35876 11.80802 48.17153 541.06486 1.08797 3.48191 16.47420 -0.10364 1.55884 2.69964 8 8 0 1.77 -2013-Sep-20 09:11:38 4171700.11472 872122.80642 4730020.88670 11.80802 48.17152 542.18689 0.88117 3.01987 17.59624 -0.31044 1.09680 3.82167 8 8 0 1.77 -2013-Sep-20 09:11:38 4171699.80387 872122.80827 4730020.90225 11.80802 48.17153 541.99581 0.94660 3.25669 17.40515 -0.24502 1.33361 3.63059 8 8 0 1.77 -2013-Sep-20 09:11:39 4171699.70984 872122.81727 4730021.22894 11.80802 48.17153 542.17908 0.97465 3.54177 17.58843 -0.21697 1.61869 3.81387 8 8 0 1.77 -2013-Sep-20 09:11:39 4171699.82524 872122.89495 4730021.46017 11.80802 48.17153 542.43733 1.02707 3.59996 17.84667 -0.16454 1.67688 4.07211 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.08447 872122.55080 4730021.35202 11.80801 48.17153 542.47899 0.63716 3.39124 17.88833 -0.55446 1.46816 4.11377 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.84119 872122.18652 4730021.89322 11.80801 48.17153 543.32654 0.12574 3.25578 18.73588 -1.06588 1.33270 4.96132 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.05830 872122.04611 4730022.34280 11.80800 48.17153 543.78410 -0.05613 3.41866 19.19344 -1.24775 1.49558 5.41888 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.75315 872122.03694 4730022.10137 11.80801 48.17153 543.40375 -0.00266 3.48161 18.81310 -1.19428 1.55854 5.03853 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.56624 872121.96730 4730022.35195 11.80801 48.17153 543.45895 -0.03259 3.79568 18.86829 -1.22420 1.87260 5.09373 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.19361 872121.94916 4730022.99533 11.80800 48.17153 544.34543 -0.17872 3.76992 19.75477 -1.37034 1.84684 5.98021 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.96928 872121.74727 4730022.88855 11.80800 48.17153 544.09187 -0.33043 3.89311 19.50121 -1.52205 1.97003 5.72665 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.42617 872121.82050 4730022.90283 11.80800 48.17153 544.41076 -0.35225 3.55823 19.82010 -1.54387 1.63516 6.04554 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.53088 872121.64036 4730022.80282 11.80800 48.17153 544.38000 -0.55000 3.44263 19.78935 -1.74162 1.51955 6.01479 8 8 0 1.77 -2013-Sep-20 09:11:39 4171702.34254 872121.67101 4730022.76349 11.80800 48.17152 544.88472 -0.68609 2.81972 20.29407 -1.87771 0.89664 6.51950 8 8 0 1.77 -2013-Sep-20 09:11:39 4171702.28366 872121.18544 4730023.27272 11.80799 48.17153 545.15947 -1.14934 3.27631 20.56881 -2.34096 1.35323 6.79425 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.47633 872121.32373 4730022.14251 11.80799 48.17153 543.80916 -0.84877 3.09033 19.21850 -2.04039 1.16726 5.44394 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.83881 872121.33110 4730021.77560 11.80800 48.17153 543.12059 -0.71110 3.30951 18.52994 -1.90271 1.38643 4.75538 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.43604 872121.04586 4730021.69105 11.80799 48.17153 542.75574 -0.90788 3.59039 18.16509 -2.09949 1.66731 4.39053 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.98825 872120.91235 4730021.57206 11.80799 48.17153 543.00933 -1.15157 3.12862 18.41868 -2.34319 1.20554 4.64412 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.84387 872121.02627 4730021.07622 11.80799 48.17152 542.56116 -1.01051 2.88588 17.97050 -2.20212 0.96281 4.19594 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.81682 872121.15354 4730021.32315 11.80799 48.17152 543.39766 -1.08503 2.32151 18.80701 -2.27665 0.39843 5.03244 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.24723 872121.27623 4730020.62791 11.80799 48.17152 542.52452 -0.84838 2.25458 17.93387 -2.04000 0.33151 4.15930 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.65371 872121.36783 4730020.99764 11.80799 48.17152 543.07787 -0.84190 2.19072 18.48721 -2.03352 0.26764 4.71265 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.85918 872121.70263 4730020.19240 11.80800 48.17152 542.00488 -0.35160 2.18216 17.41422 -1.54322 0.25908 3.63966 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.56389 872121.70693 4730020.33065 11.80800 48.17152 541.91572 -0.28696 2.48907 17.32507 -1.47858 0.56600 3.55050 8 8 0 1.77 -2013-Sep-20 09:11:39 4171700.47592 872121.79982 4730019.85935 11.80800 48.17152 541.51979 -0.17803 2.22477 16.92913 -1.36965 0.30169 3.15457 8 8 0 1.77 -2013-Sep-20 09:11:39 4171701.35448 872121.62620 4730019.94851 11.80800 48.17151 542.13604 -0.52777 1.66990 17.54539 -1.71939 -0.25317 3.77082 8 8 0 1.77 -2013-Sep-20 09:11:40 4171701.03147 872121.56844 4730020.26469 11.80800 48.17152 542.15291 -0.51820 2.12517 17.56225 -1.70982 0.20209 3.78769 8 8 0 1.77 -2013-Sep-20 09:11:40 4171700.45478 872121.84957 4730019.54638 11.80800 48.17152 541.27957 -0.12501 2.02387 16.68891 -1.31663 0.10080 2.91435 8 8 0 1.77 -2013-Sep-20 09:11:40 4171699.17139 872121.87706 4730018.49289 11.80801 48.17152 539.66053 0.16452 2.25319 15.06988 -1.02710 0.33011 1.29531 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.92280 872122.10891 4730017.84977 11.80801 48.17152 538.39789 0.64697 2.69962 13.80723 -0.54465 0.77655 0.03267 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.14621 872122.20402 4730016.86091 11.80802 48.17152 537.16707 0.89897 2.59208 12.57642 -0.29264 0.66900 -1.19815 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.13207 872122.23190 4730016.85570 11.80802 48.17152 537.15776 0.92916 2.59467 12.56711 -0.26245 0.67159 -1.20746 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.40063 872122.34713 4730016.74587 11.80802 48.17152 537.26696 0.98700 2.30797 12.67631 -0.20461 0.38489 -1.09826 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.22457 872122.32399 4730016.24064 11.80802 48.17152 536.77241 1.00038 2.10297 12.18176 -0.19124 0.17989 -1.59281 8 8 0 1.77 -2013-Sep-20 09:11:40 4171698.06326 872122.22972 4730016.51706 11.80802 48.17151 537.51300 0.73648 1.68997 12.92235 -0.45514 -0.23311 -0.85222 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.48522 872122.40385 4730015.81532 11.80802 48.17151 536.63653 1.02521 1.61704 12.04588 -0.16641 -0.30604 -1.72869 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.33030 872122.67752 4730014.96153 11.80802 48.17151 535.93655 1.32479 1.11890 11.34590 0.13318 -0.80417 -2.42867 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.92837 872122.58276 4730016.00451 11.80802 48.17151 537.09120 1.10965 1.39270 12.50055 -0.08197 -0.53037 -1.27402 8 8 0 1.77 -2013-Sep-20 09:11:40 4171697.86454 872122.85176 4730015.72676 11.80802 48.17151 536.87928 1.38602 1.21301 12.28862 0.19440 -0.71007 -1.48594 8 8 0 1.77 -2013-Sep-20 09:11:40 4171698.36123 872122.55819 4730016.22885 11.80802 48.17151 537.53759 0.99702 1.23034 12.94693 -0.19459 -0.69274 -0.82763 8 8 0 1.77 -2013-Sep-20 09:11:40 4171698.45215 872122.84936 4730016.21352 11.80802 48.17151 537.62525 1.26343 1.10940 13.03460 0.07181 -0.81367 -0.73997 8 8 0 1.77 -2013-Sep-20 09:11:40 4171698.63720 872123.07349 4730016.28996 11.80803 48.17151 537.83359 1.44494 0.99124 13.24294 0.25333 -0.93184 -0.53163 8 8 0 1.77 -2013-Sep-20 09:11:40 4171698.94598 872123.06790 4730016.21553 11.80802 48.17150 537.97894 1.37628 0.71723 13.38828 0.18466 -1.20584 -0.38628 8 8 0 1.77 -2013-Sep-20 09:11:40 4171699.18545 872123.28182 4730016.61339 11.80803 48.17150 538.46092 1.53667 0.77529 13.87027 0.34506 -1.14779 0.09570 8 8 0 1.77 -2013-Sep-20 09:11:40 4171699.13623 872123.21815 4730016.21580 11.80803 48.17150 538.12384 1.48443 0.55574 13.53318 0.29281 -1.36733 -0.24138 8 8 0 1.77 -2013-Sep-20 09:11:40 4171699.18814 872123.46754 4730016.66122 11.80803 48.17150 538.52366 1.71792 0.77690 13.93301 0.52630 -1.14617 0.15844 8 8 0 1.77 -2013-Sep-20 09:11:40 4171699.92052 872123.45256 4730017.32933 11.80803 48.17150 539.49755 1.55339 0.69057 14.90689 0.36177 -1.23250 1.13233 8 8 0 1.77 -2013-Sep-20 09:11:40 4171700.45994 872123.61056 4730017.19824 11.80803 48.17150 539.77355 1.59765 0.18562 15.18290 0.40604 -1.73746 1.40834 8 8 0 1.77 -2013-Sep-20 09:11:40 4171700.16570 872123.75511 4730016.66704 11.80803 48.17150 539.20538 1.79936 0.02393 14.61473 0.60775 -1.89915 0.84016 8 8 0 1.77 -2013-Sep-20 09:11:40 4171700.52505 872123.76365 4730016.45094 11.80803 48.17149 539.28010 1.73419 -0.38360 14.68945 0.54257 -2.30667 0.91488 8 8 0 1.77 -2013-Sep-20 09:11:40 4171700.59958 872123.87449 4730016.61073 11.80803 48.17149 539.46295 1.82742 -0.34829 14.87229 0.63581 -2.27137 1.09773 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.03977 872123.41506 4730016.06913 11.80803 48.17150 538.63125 1.49228 -0.23112 14.04059 0.30066 -2.15419 0.26603 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.78730 872123.52751 4730016.16879 11.80803 48.17149 539.20883 1.44938 -0.72703 14.61818 0.25776 -2.65011 0.84361 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.15722 872123.53886 4730015.89908 11.80802 48.17149 539.25089 1.38479 -1.17844 14.66023 0.19317 -3.10152 0.88567 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.28142 872123.70878 4730016.07576 11.80803 48.17149 539.48680 1.52570 -1.17712 14.89615 0.33408 -3.10019 1.12158 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.25351 872123.61063 4730016.14594 11.80802 48.17149 539.50748 1.43533 -1.09499 14.91682 0.24372 -3.01806 1.14226 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.62854 872123.76804 4730015.83873 11.80803 48.17148 539.54487 1.51267 -1.59741 14.95422 0.32106 -3.52048 1.17965 8 8 0 1.77 -2013-Sep-20 09:11:41 4171702.32314 872123.47508 4730016.69252 11.80802 48.17148 540.59451 1.08378 -1.48997 16.00386 -0.10784 -3.41305 2.22929 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.64336 872123.25849 4730016.32060 11.80802 48.17149 539.84406 1.01088 -1.20916 15.25341 -0.18074 -3.13224 1.47884 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.58960 872123.25338 4730016.73460 11.80802 48.17149 540.11676 1.01687 -0.89307 15.52611 -0.17474 -2.81614 1.75154 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.89835 872123.10856 4730016.94835 11.80802 48.17149 540.45783 0.81194 -0.95363 15.86717 -0.37968 -2.87671 2.09261 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.05306 872123.13763 4730016.73245 11.80802 48.17149 539.74912 1.01336 -0.48552 15.15846 -0.17826 -2.40859 1.38390 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.24597 872123.32675 4730017.45947 11.80802 48.17150 540.44259 1.15900 -0.17020 15.85194 -0.03262 -2.09328 2.07737 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.42575 872123.33472 4730017.53661 11.80802 48.17150 540.61851 1.13002 -0.25110 16.02786 -0.06160 -2.17418 2.25329 8 8 0 1.77 -2013-Sep-20 09:11:41 4171701.23715 872123.28572 4730017.21918 11.80802 48.17149 540.25219 1.12065 -0.31776 15.66153 -0.07097 -2.24084 1.88697 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.90322 872122.88576 4730017.09056 11.80802 48.17150 539.88377 0.79749 -0.09900 15.29312 -0.39413 -2.02207 1.51855 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.84970 872122.84441 4730017.12197 11.80802 48.17150 539.86660 0.76796 -0.03271 15.27595 -0.42366 -1.95578 1.50138 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.57522 872122.55720 4730017.15672 11.80801 48.17150 539.67412 0.54299 0.23446 15.08346 -0.64862 -1.68862 1.30890 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.39594 872122.45672 4730017.03241 11.80801 48.17150 539.45074 0.48133 0.29764 14.86008 -0.71029 -1.62543 1.08552 8 8 0 1.77 -2013-Sep-20 09:11:41 4171700.80498 872122.29960 4730017.06307 11.80801 48.17150 539.71916 0.24383 0.04370 15.12851 -0.94779 -1.87937 1.35394 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.89102 872122.15259 4730016.48617 11.80801 48.17150 538.67260 0.28696 0.34800 14.08195 -0.90466 -1.57507 0.30739 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.47421 872122.10703 4730016.29735 11.80801 48.17150 538.25360 0.32766 0.53304 13.66294 -0.86396 -1.39004 -0.11162 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.66850 872122.11360 4730016.59772 11.80801 48.17150 538.60515 0.29433 0.59064 14.01449 -0.89729 -1.33244 0.23993 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.84307 872122.07987 4730016.22762 11.80801 48.17150 538.43872 0.22559 0.22164 13.84807 -0.96602 -1.70144 0.07350 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.30994 872121.99757 4730016.22422 11.80801 48.17150 538.07694 0.25413 0.62077 13.48628 -0.93749 -1.30230 -0.28828 8 8 0 1.77 -2013-Sep-20 09:11:41 4171699.01634 872121.81703 4730016.78096 11.80801 48.17151 538.27549 0.13749 1.23373 13.68483 -1.05413 -0.68934 -0.08973 8 8 0 1.77 -2013-Sep-20 09:11:42 4171698.67867 872121.85800 4730016.70871 11.80801 48.17151 538.00681 0.24669 1.42559 13.41616 -0.94493 -0.49748 -0.35841 8 8 0 1.77 -2013-Sep-20 09:11:42 4171697.93864 872121.93373 4730016.51253 11.80801 48.17151 537.38789 0.47225 1.82297 12.79723 -0.71937 -0.10010 -0.97733 8 8 0 1.77 -2013-Sep-20 09:11:42 4171698.65654 872121.82911 4730016.87767 11.80801 48.17151 538.11433 0.22294 1.55882 13.52367 -0.96867 -0.36425 -0.25089 8 8 0 1.77 -2013-Sep-20 09:11:42 4171698.25166 872121.75893 4730016.31071 11.80801 48.17151 537.41798 0.23710 1.48672 12.82732 -0.95452 -0.43635 -0.94724 8 8 0 1.77 -2013-Sep-20 09:11:42 4171698.08372 872121.74390 4730016.11703 11.80801 48.17151 537.16198 0.25675 1.48234 12.57132 -0.93487 -0.44073 -1.20324 8 8 0 1.77 -2013-Sep-20 09:11:42 4171698.19400 872121.69853 4730015.64966 11.80801 48.17151 536.87952 0.18977 1.09714 12.28886 -1.00184 -0.82594 -1.48570 8 8 0 1.77 -2013-Sep-20 09:11:42 4171697.44883 872121.90197 4730014.68147 11.80801 48.17151 535.69940 0.54139 0.96393 11.10875 -0.65022 -0.95914 -2.66582 8 8 0 1.77 -2013-Sep-20 09:11:42 4171697.60936 872121.97606 4730014.99269 11.80801 48.17151 536.04621 0.58106 1.04311 11.45555 -0.61055 -0.87997 -2.31901 8 8 0 1.77 -2013-Sep-20 09:11:42 4171697.30997 872121.94969 4730014.80540 11.80801 48.17151 535.70761 0.61652 1.14059 11.11696 -0.57510 -0.78248 -2.65760 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.67498 872122.30815 4730014.21412 11.80802 48.17151 534.90143 1.09734 1.15475 10.31078 -0.09428 -0.76832 -3.46379 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.14737 872122.25976 4730013.48930 11.80802 48.17151 534.01031 1.15793 1.06357 9.41965 -0.03369 -0.85951 -4.35491 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.58820 872122.25426 4730013.30308 11.80802 48.17151 533.50578 1.26698 1.34806 8.91513 0.07536 -0.57501 -4.85944 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.46016 872122.52534 4730013.66225 11.80803 48.17151 533.72681 1.55852 1.63965 9.13616 0.36690 -0.28343 -4.63840 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.53818 872122.49507 4730013.68190 11.80803 48.17151 533.78826 1.51292 1.60046 9.19761 0.32131 -0.32261 -4.57696 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.59275 872122.49625 4730014.22604 11.80803 48.17151 534.22952 1.50292 1.92337 9.63886 0.31130 0.00029 -4.13570 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.10915 872122.43456 4730014.12230 11.80803 48.17152 533.82810 1.54149 2.21632 9.23745 0.34988 0.29325 -4.53712 8 8 0 1.77 -2013-Sep-20 09:11:42 4171694.77850 872122.56472 4730013.90581 11.80803 48.17152 533.46870 1.73656 2.29326 8.87805 0.54494 0.37019 -4.89652 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.47456 872122.64284 4730014.93579 11.80803 48.17152 534.70123 1.67058 2.46055 10.11057 0.47897 0.53748 -3.66399 8 8 0 1.77 -2013-Sep-20 09:11:42 4171694.86781 872122.86137 4730014.62148 11.80803 48.17152 534.10077 2.00866 2.66017 9.51011 0.81704 0.73710 -4.26445 8 8 0 1.77 -2013-Sep-20 09:11:42 4171695.25746 872122.98096 4730015.01290 11.80803 48.17152 534.66311 2.04598 2.61878 10.07245 0.85436 0.69570 -3.70211 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.01647 872122.67914 4730015.99900 11.80803 48.17152 535.85218 1.59522 2.76882 11.26152 0.40361 0.84574 -2.51304 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.45623 872122.47580 4730015.98330 11.80802 48.17152 536.09980 1.30620 2.46861 11.50915 0.11458 0.54554 -2.26542 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.67520 872122.25393 4730015.74760 11.80802 48.17152 536.03684 1.04421 2.18554 11.44618 -0.14740 0.26247 -2.32838 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.35253 872122.63876 4730015.55226 11.80803 48.17152 535.73316 1.48693 2.23194 11.14251 0.29532 0.30886 -2.63206 8 8 0 1.77 -2013-Sep-20 09:11:42 4171696.71857 872123.03119 4730015.30768 11.80803 48.17151 535.84342 1.79615 1.74201 11.25277 0.60453 -0.18107 -2.52180 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.97698 872122.77646 4730015.99104 11.80803 48.17152 536.48654 1.49393 2.04810 11.89589 0.30231 0.12503 -1.87868 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.76492 872122.85934 4730015.55238 11.80803 48.17151 536.03255 1.61845 1.89759 11.44190 0.42684 -0.02548 -2.33267 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.84952 872123.24895 4730015.54934 11.80803 48.17151 536.13869 1.98251 1.77446 11.54803 0.79089 -0.14862 -2.22653 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.47072 872123.17954 4730015.01982 11.80803 48.17151 535.48737 1.99208 1.70819 10.89671 0.80047 -0.21489 -2.87785 8 8 0 1.77 -2013-Sep-20 09:11:43 4171697.03787 872123.03775 4730015.53349 11.80803 48.17151 536.22101 1.73724 1.65871 11.63035 0.54562 -0.26437 -2.14421 8 8 0 1.77 -2013-Sep-20 09:11:43 4171697.07897 872122.98161 4730015.23720 11.80803 48.17151 536.01940 1.67387 1.43969 11.42875 0.48226 -0.48338 -2.34582 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.47623 872123.03652 4730015.33817 11.80803 48.17152 535.70866 1.85096 1.93829 11.11801 0.65934 0.01521 -2.65656 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.14654 872123.00641 4730015.18816 11.80803 48.17152 535.37756 1.88895 2.08330 10.78691 0.69734 0.16022 -2.98766 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.39420 872123.38656 4730015.14689 11.80804 48.17151 535.56036 2.21038 1.81717 10.96970 1.01877 -0.10590 -2.80486 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.61796 872123.54419 4730015.24727 11.80804 48.17151 535.80273 2.31889 1.69688 11.21207 1.12727 -0.22620 -2.56249 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.02291 872123.50783 4730014.90679 11.80804 48.17151 535.15562 2.40507 1.90937 10.56497 1.21345 -0.01370 -3.20960 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.04014 872123.78410 4730014.70349 11.80804 48.17151 535.05308 2.67196 1.71909 10.46243 1.48035 -0.20399 -3.31213 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.70521 872123.71814 4730014.36057 11.80804 48.17151 534.56992 2.67593 1.74475 9.97926 1.48432 -0.17833 -3.79530 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.43152 872123.86969 4730015.06849 11.80804 48.17151 535.59223 2.67565 1.66399 11.00158 1.48403 -0.25908 -2.77299 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.31613 872123.79782 4730014.34803 11.80804 48.17151 534.97025 2.62892 1.27864 10.37959 1.43730 -0.64443 -3.39497 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.50031 872123.68029 4730014.81575 11.80804 48.17151 535.42296 2.47618 1.47415 10.83230 1.28456 -0.44892 -2.94226 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.49082 872123.61267 4730014.66764 11.80804 48.17151 535.29718 2.41194 1.39261 10.70653 1.22032 -0.53046 -3.06804 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.80851 872123.90828 4730015.06081 11.80804 48.17151 535.83787 2.63628 1.37803 11.24722 1.44467 -0.54505 -2.52735 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.68423 872124.27510 4730015.10958 11.80805 48.17151 535.84314 3.02076 1.44526 11.25249 1.82915 -0.47781 -2.52207 8 8 0 1.77 -2013-Sep-20 09:11:43 4171696.19785 872124.03702 4730014.73344 11.80804 48.17151 535.21287 2.88726 1.58548 10.62221 1.69564 -0.33760 -3.15235 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.80435 872124.33822 4730014.77271 11.80805 48.17151 535.02636 3.26260 1.85274 10.43571 2.07099 -0.07033 -3.33886 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.51952 872124.29262 4730014.48981 11.80805 48.17151 534.62341 3.27625 1.87878 10.03275 2.08464 -0.04430 -3.74181 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.94955 872124.34511 4730015.05820 11.80805 48.17152 535.33482 3.23964 1.93618 10.74416 2.04802 0.01310 -3.03040 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.70147 872124.15836 4730014.66480 11.80805 48.17151 534.85425 3.10760 1.88324 10.26360 1.91598 -0.03984 -3.51097 8 8 0 1.77 -2013-Sep-20 09:11:43 4171695.55169 872123.99272 4730014.04912 11.80805 48.17151 534.27510 2.97612 1.60715 9.68445 1.78450 -0.31593 -4.09012 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.33438 872123.95169 4730014.32146 11.80805 48.17152 534.33058 2.98043 1.95353 9.73992 1.78881 0.03045 -4.03464 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.74072 872123.80592 4730014.69438 11.80804 48.17152 534.85382 2.75459 1.92808 10.26317 1.56297 0.00501 -3.51140 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.29452 872123.79905 4730014.35097 11.80804 48.17152 534.30571 2.83918 2.02556 9.71505 1.64756 0.10248 -4.05951 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.54611 872123.99294 4730014.27107 11.80805 48.17151 534.43687 2.97748 1.75920 9.84622 1.78586 -0.16387 -3.92834 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.96067 872124.12538 4730014.37722 11.80805 48.17151 534.80466 3.02229 1.50743 10.21401 1.83067 -0.41564 -3.56056 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.28197 872124.16881 4730013.77999 11.80805 48.17151 533.92252 3.20368 1.59754 9.33186 2.01206 -0.32554 -4.44270 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.25290 872124.19400 4730013.19159 11.80805 48.17151 533.46854 3.23428 1.22250 8.87788 2.04266 -0.70057 -4.89668 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.24055 872123.97978 4730013.54071 11.80805 48.17151 533.69138 3.02712 1.49699 9.10073 1.83550 -0.42608 -4.67383 8 8 0 1.77 -2013-Sep-20 09:11:44 4171695.74913 872123.62641 4730014.70238 11.80804 48.17152 534.84077 2.57715 1.95466 10.25012 1.38554 0.03158 -3.52445 8 8 0 1.77 -2013-Sep-20 09:11:44 4171696.64552 872123.35533 4730015.13090 11.80803 48.17151 535.70824 2.12838 1.62797 11.11758 0.93676 -0.29511 -2.65698 8 8 0 1.77 -2013-Sep-20 09:11:44 4171696.89713 872123.09716 4730014.54717 11.80803 48.17151 535.40229 1.82418 1.09452 10.81164 0.63257 -0.82855 -2.96292 8 8 0 1.77 -2013-Sep-20 09:11:44 4171696.80211 872122.99782 4730014.37511 11.80803 48.17151 535.19849 1.74639 1.06423 10.60784 0.55477 -0.85885 -3.16672 8 8 0 1.77 -2013-Sep-20 09:11:44 4171697.00485 872122.87860 4730014.09844 11.80803 48.17150 535.10841 1.58821 0.75002 10.51776 0.39660 -1.17305 -3.25680 8 8 0 1.77 -2013-Sep-20 09:11:44 4171697.08717 872122.87208 4730013.87906 11.80803 48.17150 534.99779 1.56498 0.54467 10.40714 0.37336 -1.37841 -3.36742 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.47976 872122.72102 4730014.79958 11.80802 48.17150 536.57216 1.13215 0.16588 11.98151 -0.05947 -1.75720 -1.79305 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.43171 872122.56928 4730014.74034 11.80802 48.17150 536.47595 0.99345 0.18455 11.88530 -0.19817 -1.73852 -1.88927 8 8 0 1.77 -2013-Sep-20 09:11:44 4171699.10059 872122.19448 4730015.49516 11.80801 48.17150 537.42389 0.48972 0.25723 12.83324 -0.70190 -1.66584 -0.94133 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.68942 872122.44197 4730014.83165 11.80802 48.17150 536.69485 0.81610 0.07689 12.10419 -0.37551 -1.84618 -1.67037 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.48407 872122.73722 4730014.64980 11.80802 48.17150 536.46559 1.14712 0.06038 11.87493 -0.04449 -1.86270 -1.89963 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.56808 872122.70679 4730014.58921 11.80802 48.17150 536.47112 1.10015 -0.03667 11.88047 -0.09147 -1.95975 -1.89410 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.33519 872122.54320 4730014.29899 11.80802 48.17150 536.08052 0.98768 -0.03541 11.48986 -0.20394 -1.95849 -2.28470 8 8 0 1.77 -2013-Sep-20 09:11:44 4171698.06374 872122.36906 4730014.63007 11.80802 48.17150 536.12626 0.87276 0.40993 11.53560 -0.31885 -1.51314 -2.23896 8 8 0 1.77 -2013-Sep-20 09:11:44 4171697.35527 872122.20393 4730014.00595 11.80802 48.17150 535.17618 0.85611 0.53563 10.58552 -0.33551 -1.38745 -3.18904 8 8 0 1.77 -2013-Sep-20 09:11:44 4171696.96537 872122.23825 4730013.39245 11.80802 48.17150 534.46919 0.96950 0.40563 9.87853 -0.22212 -1.51744 -3.89603 8 8 0 1.77 -2013-Sep-20 09:11:44 4171697.14564 872122.31418 4730013.87948 11.80802 48.17150 534.96014 1.00693 0.58737 10.36949 -0.18469 -1.33571 -3.40508 8 8 0 1.77 -2013-Sep-20 09:11:45 4171697.20998 872122.45729 4730014.24081 11.80802 48.17150 535.29091 1.13384 0.75959 10.70025 -0.05777 -1.16348 -3.07431 8 8 0 1.77 -2013-Sep-20 09:11:45 4171697.55810 872122.46251 4730014.32625 11.80802 48.17150 535.58254 1.06772 0.56186 10.99189 -0.12390 -1.36122 -2.78268 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.02675 872122.31732 4730014.72367 11.80802 48.17150 536.16479 0.82969 0.50723 11.57414 -0.36192 -1.41585 -2.20042 8 8 0 1.77 -2013-Sep-20 09:11:45 4171697.85735 872122.22972 4730014.88644 11.80802 48.17150 536.16354 0.77861 0.75269 11.57289 -0.41301 -1.17038 -2.20168 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.19975 872122.30750 4730015.69228 11.80802 48.17151 536.99814 0.78468 1.02850 12.40748 -0.40694 -0.89457 -1.36708 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.11828 872122.01721 4730016.26904 11.80801 48.17151 537.33511 0.51720 1.51684 12.74445 -0.67441 -0.40624 -1.03011 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.36364 872122.02906 4730016.60572 11.80801 48.17151 537.74777 0.47859 1.56060 13.15712 -0.71302 -0.36247 -0.61745 8 8 0 1.77 -2013-Sep-20 09:11:45 4171697.97003 872122.03509 4730016.96931 11.80801 48.17152 537.76258 0.56504 2.08925 13.17192 -0.62657 0.16618 -0.60264 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.11150 872121.74281 4730017.74519 11.80801 48.17152 538.39318 0.25000 2.54807 13.80252 -0.94162 0.62500 0.02796 8 8 0 1.77 -2013-Sep-20 09:11:45 4171698.51446 872121.53447 4730018.09510 11.80801 48.17152 538.88852 -0.03639 2.51929 14.29787 -1.22801 0.59621 0.52330 8 8 0 1.77 -2013-Sep-20 09:11:45 4171699.49571 872121.44185 4730018.38053 11.80800 48.17152 539.72913 -0.32785 2.00806 15.13847 -1.51946 0.08498 1.36391 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.30319 872121.34912 4730019.28864 11.80800 48.17152 540.92026 -0.58386 2.03887 16.32961 -1.77547 0.11579 2.55505 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.18771 872121.38148 4730019.42828 11.80800 48.17152 540.95334 -0.52854 2.21129 16.36269 -1.72016 0.28821 2.58812 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.31261 872121.53254 4730019.50423 11.80800 48.17152 541.11208 -0.40624 2.14781 16.52142 -1.59786 0.22473 2.74686 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.89777 872121.61524 4730019.60038 11.80800 48.17151 541.57700 -0.44503 1.77252 16.98635 -1.63665 -0.15056 3.21178 8 8 0 1.77 -2013-Sep-20 09:11:45 4171701.43846 872121.50501 4730019.69455 11.80800 48.17151 541.98509 -0.66358 1.45776 17.39444 -1.85520 -0.46532 3.61987 8 8 0 1.77 -2013-Sep-20 09:11:45 4171701.49240 872121.42833 4730019.58022 11.80800 48.17151 541.92464 -0.74968 1.35386 17.33399 -1.94129 -0.56922 3.55943 8 8 0 1.77 -2013-Sep-20 09:11:45 4171701.07004 872121.33254 4730019.00074 11.80800 48.17151 541.20407 -0.75701 1.29007 16.61341 -1.94863 -0.63300 2.83885 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.97352 872121.32348 4730019.12476 11.80800 48.17151 541.23223 -0.74613 1.44457 16.64157 -1.93774 -0.47851 2.86701 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.89373 872121.23329 4730018.86608 11.80799 48.17151 540.97509 -0.81807 1.34399 16.38444 -2.00969 -0.57908 2.60987 8 8 0 1.77 -2013-Sep-20 09:11:45 4171701.37283 872121.32846 4730019.41306 11.80799 48.17151 541.70840 -0.82296 1.34482 17.11775 -2.01458 -0.57826 3.34319 8 8 0 1.77 -2013-Sep-20 09:11:45 4171701.83106 872120.93870 4730020.08757 11.80799 48.17151 542.45695 -1.29824 1.51987 17.86629 -2.48986 -0.40321 4.09173 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.94903 872120.81950 4730019.50724 11.80799 48.17151 541.43247 -1.23442 1.79435 16.84181 -2.42604 -0.12873 3.06725 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.77325 872120.83683 4730019.85572 11.80799 48.17152 541.57976 -1.18149 2.15232 16.98910 -2.37311 0.22925 3.21454 8 8 0 1.77 -2013-Sep-20 09:11:45 4171700.20884 872121.00436 4730018.81691 11.80799 48.17151 540.46011 -0.90200 1.84566 15.86946 -2.09362 -0.07742 2.09489 8 8 0 1.77 -2013-Sep-20 09:11:46 4171699.72112 872121.43452 4730018.67812 11.80800 48.17152 540.09702 -0.38115 2.04324 15.50636 -1.57277 0.12016 1.73180 8 8 0 1.77 diff --git a/src/utils/gnuplot/8_GPS.plt b/src/utils/gnuplot/8_GPS.plt deleted file mode 100644 index 7ff4e6bd5..000000000 --- a/src/utils/gnuplot/8_GPS.plt +++ /dev/null @@ -1,40 +0,0 @@ -#set terminal pdf color font "Bold,14" -#set output "IFEN_accuracy.pdf" - -set terminal jpeg font "Helvetica, 14" -set output "8_GPS_accuracy_precision.jpeg" - -set grid -set xrange [-8:8] -set yrange [-8:8] -set ylabel "North [m]" -set xlabel "East [m]" - -set key Left left -set title "IFEN simulated data, 8 GPS - Accuracy and Precision" -file1="8_GPS_GNSS_SDR_solutions.txt" -#file2="8_GAL_GNSS_SDR_solutions.txt" -#file3="8_GPS_GNSS_SDR_solutions.txt" - -#values to copy from statistic file -DRMS= 2.034509899 -DUE_DRMS= 4.069019799 -CEP= 1.678044871 - -#difference with respect to the reference position -#values to copy from statistic file -delta_E=-0.560 #gps -delta_N=1.323 #gps - -set parametric -#dummy variable is t for curves, u/v for surfaces -set size square -set angle degree -set trange [0:360] -#radius_6_GPS=6 - -plot file1 u 9:10 with points pointsize 0.3 lc rgb "red" notitle,\ -DRMS*sin(t)+delta_E,DRMS*cos(t)+delta_N lw 3 lc rgb "black" title "DRMS",\ -DUE_DRMS*sin(t)+delta_E,DUE_DRMS*cos(t)+delta_N lw 2 lc rgb "gray" title "2DRMS",\ -CEP*sin(t)+delta_E,CEP*cos(t)+delta_N lw 1 lc rgb "black" title "CEP" - diff --git a/src/utils/gnuplot/8_GPS_GNSS_SDR_solutions.txt b/src/utils/gnuplot/8_GPS_GNSS_SDR_solutions.txt deleted file mode 100644 index 78744a067..000000000 --- a/src/utils/gnuplot/8_GPS_GNSS_SDR_solutions.txt +++ /dev/null @@ -1,1001 +0,0 @@ - time X [m] Y [m] Z [m] Long [deg] Lat [deg] h [m] E(Acc) [m] N(Acc) [m] Up(Acc) [m] E(Pre) [m] N(Pre) [m] Up(Pre) [m] Tot Sat Gal GPS GDOP -1999-Aug-27 09:09:17 4171696.06632 872121.00018 4730014.78492 11.80800 48.17152 534.75093 -0.05841 2.17880 10.16027 0.50199 0.85511 -0.63258 8 0 8 2.00 -1999-Aug-27 09:09:17 4171695.88605 872119.68584 4730014.82036 11.80799 48.17152 534.48029 -1.30804 2.53433 9.88964 -0.74764 1.21065 -0.90322 8 0 8 2.00 -1999-Aug-27 09:09:18 4171696.40670 872119.79288 4730014.34609 11.80799 48.17151 534.48137 -1.30981 1.82197 9.89072 -0.74941 0.49829 -0.90214 8 0 8 2.00 -1999-Aug-27 09:09:18 4171698.20885 872120.51947 4730014.34802 11.80799 48.17150 535.75840 -0.96738 0.39802 11.16774 -0.40698 -0.92567 0.37488 8 0 8 2.00 -1999-Aug-27 09:09:18 4171702.27793 872120.49428 4730015.18457 11.80798 48.17148 539.03457 -1.82470 -2.00813 14.44391 -1.26430 -3.33182 3.65105 8 0 8 2.00 -1999-Aug-27 09:09:18 4171699.74782 872120.39698 4730014.70421 11.80799 48.17149 537.01172 -1.40220 -0.46825 12.42107 -0.84180 -1.79194 1.62821 8 0 8 2.00 -1999-Aug-27 09:09:18 4171699.15761 872121.32123 4730014.44286 11.80800 48.17149 536.55782 -0.37673 -0.35299 11.96717 0.18367 -1.67667 1.17431 8 0 8 2.00 -1999-Aug-27 09:09:18 4171695.94636 872120.49857 4730012.84683 11.80800 48.17151 533.16001 -0.52485 1.05026 8.56935 0.03555 -0.27343 -2.22350 8 0 8 2.00 -1999-Aug-27 09:09:18 4171695.25129 872119.76318 4730014.45124 11.80799 48.17152 533.80143 -1.10245 2.73935 9.21077 -0.54205 1.41567 -1.58208 8 0 8 2.00 -1999-Aug-27 09:09:18 4171695.16469 872121.05173 4730014.78341 11.80801 48.17152 534.16826 0.17655 2.82756 9.57760 0.73695 1.50387 -1.21525 8 0 8 2.00 -1999-Aug-27 09:09:18 4171696.64867 872121.19256 4730016.40527 11.80801 48.17152 536.36473 0.01073 2.80533 11.77407 0.57113 1.48165 0.98122 8 0 8 2.00 -1999-Aug-27 09:09:18 4171692.76552 872120.73763 4730014.38277 11.80801 48.17154 532.26070 0.36005 4.35816 7.67005 0.92045 3.03448 -3.12281 8 0 8 2.00 -1999-Aug-27 09:09:18 4171695.49138 872121.53628 4730018.18595 11.80801 48.17154 536.98304 0.58400 4.78456 12.39238 1.14439 3.46088 1.59952 8 0 8 2.00 -1999-Aug-27 09:09:18 4171696.93316 872121.12598 4730017.43636 11.80800 48.17153 537.30967 -0.11265 3.29562 12.71901 0.44775 1.97193 1.92616 8 0 8 2.00 -1999-Aug-27 09:09:18 4171697.35095 872121.67098 4730018.84384 11.80801 48.17153 538.70555 0.33532 3.84645 14.11490 0.89572 2.52276 3.32204 8 0 8 2.00 -1999-Aug-27 09:09:18 4171698.89293 872121.22674 4730019.31976 11.80800 48.17153 540.00615 -0.41506 3.10689 15.41549 0.14534 1.78320 4.62263 8 0 8 2.00 -1999-Aug-27 09:09:18 4171699.15121 872121.54749 4730016.54754 11.80800 48.17151 538.15281 -0.15395 1.02080 13.56216 0.40645 -0.30289 2.76930 8 0 8 2.00 -1999-Aug-27 09:09:18 4171694.90892 872119.71605 4730013.67957 11.80799 48.17152 532.99650 -1.07852 2.48162 8.40584 -0.51812 1.15794 -2.38701 8 0 8 2.00 -1999-Aug-27 09:09:18 4171692.41588 872119.13610 4730013.11721 11.80799 48.17153 530.87088 -1.13603 4.01338 6.28022 -0.57564 2.68970 -4.51264 8 0 8 2.00 -1999-Aug-27 09:09:18 4171699.63356 872120.55401 4730014.57715 11.80799 48.17149 536.86388 -1.22511 -0.49359 12.27323 -0.66471 -1.81728 1.48037 8 0 8 2.00 -1999-Aug-27 09:09:18 4171700.85643 872120.06378 4730014.86843 11.80798 48.17149 537.81230 -1.95520 -1.11652 13.22165 -1.39481 -2.44020 2.42879 8 0 8 2.00 -1999-Aug-27 09:09:18 4171701.89475 872121.33150 4730013.76763 11.80799 48.17147 537.84287 -0.92679 -2.80127 13.25221 -0.36639 -4.12496 2.45935 8 0 8 2.00 -1999-Aug-27 09:09:18 4171700.18412 872122.62597 4730012.58046 11.80801 48.17147 536.01822 0.69034 -2.54268 11.42757 1.25074 -3.86637 0.63471 8 0 8 2.00 -1999-Aug-27 09:09:18 4171697.57154 872120.46629 4730014.33879 11.80799 48.17151 535.32823 -0.88901 0.86481 10.73758 -0.32862 -0.45887 -0.05528 8 0 8 2.00 -1999-Aug-27 09:09:18 4171700.00459 872121.36077 4730014.31739 11.80800 48.17149 537.02263 -0.51135 -1.06045 12.43197 0.04905 -2.38414 1.63911 8 0 8 2.00 -1999-Aug-27 09:09:18 4171700.83364 872121.75541 4730014.81654 11.80800 48.17149 537.98962 -0.29471 -1.39244 13.39896 0.26568 -2.71613 2.60610 8 0 8 2.00 -1999-Aug-27 09:09:18 4171691.05768 872120.37346 4730013.62547 11.80801 48.17154 530.53186 0.35307 5.15431 5.94120 0.91347 3.83062 -4.85166 8 0 8 2.00 -1999-Aug-27 09:09:19 4171687.50657 872118.91940 4730009.49557 11.80800 48.17154 524.93791 -0.34355 5.21187 0.34725 0.21684 3.88819 -10.44560 8 0 8 2.00 -1999-Aug-27 09:09:19 4171696.71721 872119.36081 4730014.10628 11.80798 48.17151 534.44641 -1.79628 1.50144 9.85576 -1.23588 0.17775 -0.93710 8 0 8 2.00 -1999-Aug-27 09:09:19 4171696.31779 872118.42098 4730013.93628 11.80797 48.17151 533.93074 -2.63448 1.82270 9.34009 -2.07409 0.49901 -1.45277 8 0 8 2.00 -1999-Aug-27 09:09:19 4171694.85857 872119.19354 4730014.00161 11.80798 48.17152 533.13229 -1.57967 2.81279 8.54163 -1.01927 1.48911 -2.25122 8 0 8 2.00 -1999-Aug-27 09:09:19 4171696.32786 872120.53001 4730015.60726 11.80800 48.17152 535.47026 -0.57214 2.60815 10.87961 -0.01175 1.28447 0.08675 8 0 8 2.00 -1999-Aug-27 09:09:19 4171695.06688 872120.80667 4730013.61388 11.80801 48.17152 533.19951 -0.04331 2.15630 8.60885 0.51709 0.83262 -2.18401 8 0 8 2.00 -1999-Aug-27 09:09:19 4171697.29174 872119.77460 4730011.88774 11.80799 48.17149 533.22480 -1.50881 -0.46025 8.63414 -0.94842 -1.78393 -2.15871 8 0 8 2.00 -1999-Aug-27 09:09:19 4171695.80482 872120.06301 4730012.41930 11.80799 48.17151 532.68960 -0.92223 0.93480 8.09895 -0.36184 -0.38889 -2.69391 8 0 8 2.00 -1999-Aug-27 09:09:19 4171697.11970 872119.96889 4730013.32425 11.80799 48.17150 534.20942 -1.28343 0.59362 9.61877 -0.72304 -0.73007 -1.17409 8 0 8 2.00 -1999-Aug-27 09:09:19 4171697.39820 872120.76331 4730013.51870 11.80800 48.17150 534.64452 -0.56281 0.39903 10.05387 -0.00241 -0.92465 -0.73899 8 0 8 2.00 -1999-Aug-27 09:09:19 4171699.71186 872120.40542 4730015.27760 11.80799 48.17150 537.41665 -1.38658 -0.06091 12.82600 -0.82618 -1.38460 2.03314 8 0 8 2.00 -1999-Aug-27 09:09:19 4171699.30564 872122.12980 4730014.83518 11.80801 48.17149 537.05714 0.38444 -0.32261 12.46649 0.94483 -1.64630 1.67363 8 0 8 2.00 -1999-Aug-27 09:09:19 4171692.43846 872120.33396 4730012.61079 11.80801 48.17153 530.67173 0.03185 3.47653 6.08108 0.59224 2.15285 -4.71178 8 0 8 2.00 -1999-Aug-27 09:09:19 4171693.21098 872121.69044 4730014.32957 11.80802 48.17153 532.64189 1.20155 3.85249 8.05123 1.76194 2.52881 -2.74162 8 0 8 2.00 -1999-Aug-27 09:09:19 4171693.86721 872120.18962 4730014.45907 11.80800 48.17153 532.96195 -0.40181 3.68906 8.37129 0.15859 2.36538 -2.42157 8 0 8 2.00 -1999-Aug-27 09:09:19 4171698.71781 872121.40717 4730017.22188 11.80800 48.17151 538.35323 -0.20261 1.80803 13.76257 0.35779 0.48434 2.96971 8 0 8 2.00 -1999-Aug-27 09:09:19 4171699.98798 872122.00531 4730015.74601 11.80801 48.17150 538.16428 0.12295 -0.19387 13.57362 0.68335 -1.51756 2.78076 8 0 8 2.00 -1999-Aug-27 09:09:19 4171702.23571 872124.12091 4730017.33868 11.80803 48.17149 541.10706 1.73383 -1.09374 16.51640 2.29422 -2.41743 5.72354 8 0 8 2.00 -1999-Aug-27 09:09:19 4171703.66160 872123.93996 4730017.05561 11.80802 48.17148 541.80224 1.26492 -2.29494 17.21159 1.82532 -3.61863 6.41873 8 0 8 2.00 -1999-Aug-27 09:09:19 4171700.17890 872122.19994 4730016.23255 11.80801 48.17150 538.67801 0.27440 -0.03833 14.08736 0.83480 -1.36202 3.29450 8 0 8 2.00 -1999-Aug-27 09:09:19 4171697.52445 872121.64690 4730017.13141 11.80801 48.17152 537.53952 0.27625 2.58154 12.94886 0.83665 1.25786 2.15601 8 0 8 2.00 -1999-Aug-27 09:09:19 4171694.37948 872120.48604 4730017.31347 11.80800 48.17154 535.46375 -0.21648 5.17383 10.87310 0.34392 3.85015 0.08024 8 0 8 2.00 -1999-Aug-27 09:09:19 4171694.72972 872120.10541 4730015.28313 11.80800 48.17153 534.12754 -0.66073 3.62238 9.53688 -0.10034 2.29869 -1.25598 8 0 8 2.00 -1999-Aug-27 09:09:19 4171698.19767 872120.41898 4730017.15531 11.80799 48.17152 537.82923 -1.06345 2.29369 13.23857 -0.50305 0.97000 2.44571 8 0 8 2.00 -1999-Aug-27 09:09:19 4171698.26754 872119.74055 4730014.76840 11.80798 48.17150 536.00365 -1.74182 0.75434 11.41300 -1.18143 -0.56935 0.62014 8 0 8 2.00 -1999-Aug-27 09:09:20 4171696.99939 872121.56118 4730012.25156 11.80801 48.17150 533.54887 0.29979 -0.27681 8.95822 0.86018 -1.60050 -1.83464 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.21647 872121.07300 4730009.54888 11.80801 48.17150 529.65169 0.39141 0.02501 5.06104 0.95181 -1.29868 -5.73182 8 0 8 2.00 -1999-Aug-27 09:09:20 4171695.44362 872121.88269 4730012.56076 11.80802 48.17151 532.80755 0.93286 1.01512 8.21690 1.49325 -0.30857 -2.57596 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.83915 872119.52523 4730014.96864 11.80799 48.17153 533.88546 -1.25103 3.42129 9.29480 -0.69063 2.09761 -1.49805 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.83635 872120.68506 4730014.91086 11.80800 48.17153 533.99886 -0.11517 3.20795 9.40820 0.44523 1.88427 -1.38466 8 0 8 2.00 -1999-Aug-27 09:09:20 4171695.79298 872121.03515 4730014.69556 11.80801 48.17152 534.51068 0.03176 2.31324 9.92002 0.59216 0.98955 -0.87283 8 0 8 2.00 -1999-Aug-27 09:09:20 4171697.75683 872120.14324 4730014.16804 11.80799 48.17150 535.27786 -1.24315 0.66505 10.68721 -0.68275 -0.65863 -0.10565 8 0 8 2.00 -1999-Aug-27 09:09:20 4171700.33516 872120.56118 4730015.29096 11.80799 48.17149 537.85475 -1.36166 -0.53037 13.26410 -0.80127 -1.85406 2.47124 8 0 8 2.00 -1999-Aug-27 09:09:20 4171698.18473 872117.92565 4730013.18441 11.80796 48.17150 534.52161 -3.50137 0.03510 9.93096 -2.94097 -1.28858 -0.86190 8 0 8 2.00 -1999-Aug-27 09:09:20 4171695.52019 872119.15720 4730014.94197 11.80798 48.17152 534.25993 -1.75063 2.96289 9.66928 -1.19023 1.63920 -1.12358 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.88506 872120.08880 4730014.02193 11.80800 48.17152 533.28690 -0.70877 2.67051 8.69625 -0.14838 1.34683 -2.09661 8 0 8 2.00 -1999-Aug-27 09:09:20 4171693.82362 872120.37903 4730015.57385 11.80800 48.17154 533.79001 -0.20749 4.43542 9.19936 0.35291 3.11174 -1.59350 8 0 8 2.00 -1999-Aug-27 09:09:20 4171693.83316 872119.22015 4730012.33073 11.80799 48.17152 531.22150 -1.34380 2.44232 6.63084 -0.78340 1.11864 -4.16201 8 0 8 2.00 -1999-Aug-27 09:09:20 4171695.12240 872119.82948 4730012.90829 11.80799 48.17151 532.57663 -1.01118 1.79425 7.98597 -0.45078 0.47057 -2.80689 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.42510 872119.73886 4730013.51030 11.80799 48.17152 532.55765 -0.95718 2.71815 7.96699 -0.39679 1.39446 -2.82587 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.96146 872121.56456 4730012.63614 11.80802 48.17151 532.50555 0.72013 1.46557 7.91490 1.28052 0.14189 -2.87796 8 0 8 2.00 -1999-Aug-27 09:09:20 4171697.88040 872121.63481 4730016.04733 11.80801 48.17151 536.96243 0.19158 1.60079 12.37178 0.75197 0.27711 1.57892 8 0 8 2.00 -1999-Aug-27 09:09:20 4171700.17713 872123.03665 4730015.94819 11.80802 48.17149 538.57915 1.09376 -0.35426 13.98849 1.65416 -1.67795 3.19564 8 0 8 2.00 -1999-Aug-27 09:09:20 4171699.17846 872122.03655 4730016.34697 11.80801 48.17150 538.08789 0.31919 0.79259 13.49724 0.87959 -0.53110 2.70438 8 0 8 2.00 -1999-Aug-27 09:09:20 4171696.47075 872121.42370 4730014.25602 11.80801 48.17151 534.67863 0.27339 1.46651 10.08797 0.83378 0.14283 -0.70489 8 0 8 2.00 -1999-Aug-27 09:09:20 4171693.84722 872120.90043 4730014.86401 11.80801 48.17153 533.34764 0.29806 3.86531 8.75699 0.85845 2.54163 -2.03587 8 0 8 2.00 -1999-Aug-27 09:09:20 4171694.34839 872120.49578 4730014.82261 11.80800 48.17153 533.58873 -0.20059 3.53386 8.99808 0.35981 2.21018 -1.79478 8 0 8 2.00 -1999-Aug-27 09:09:20 4171695.56278 872121.11545 4730015.15883 11.80801 48.17152 534.71657 0.15747 2.77786 10.12591 0.71787 1.45417 -0.66694 8 0 8 2.00 -1999-Aug-27 09:09:20 4171688.86834 872119.94660 4730011.78669 11.80801 48.17155 527.67426 0.38325 5.58996 3.08361 0.94364 4.26627 -7.70925 8 0 8 2.00 -1999-Aug-27 09:09:20 4171693.87341 872120.97816 4730013.78871 11.80801 48.17153 532.57410 0.36878 3.11724 7.98344 0.92918 1.79355 -2.80942 8 0 8 2.00 -1999-Aug-27 09:09:21 4171692.49418 872120.61323 4730013.68775 11.80801 48.17153 531.54871 0.29381 4.11153 6.95805 0.85421 2.78785 -3.83480 8 0 8 2.00 -1999-Aug-27 09:09:21 4171688.04342 872120.08485 4730011.73852 11.80801 48.17155 527.11874 0.68739 6.13843 2.52808 1.24778 4.81474 -8.26478 8 0 8 2.00 -1999-Aug-27 09:09:21 4171690.26676 872119.77888 4730014.50173 11.80800 48.17156 530.58734 -0.06708 6.40623 5.99669 0.49332 5.08254 -4.79617 8 0 8 2.00 -1999-Aug-27 09:09:21 4171694.50317 872122.32494 4730017.54632 11.80803 48.17154 535.96895 1.55819 4.95851 11.37829 2.11859 3.63482 0.58544 8 0 8 2.00 -1999-Aug-27 09:09:21 4171692.79089 872120.98460 4730014.29909 11.80801 48.17154 532.24862 0.59660 4.24619 7.65797 1.15700 2.92251 -3.13489 8 0 8 2.00 -1999-Aug-27 09:09:21 4171698.76090 872120.39522 4730016.70553 11.80799 48.17151 537.85850 -1.20196 1.58654 13.26785 -0.64156 0.26285 2.47499 8 0 8 2.00 -1999-Aug-27 09:09:21 4171704.29728 872123.80645 4730017.80307 11.80802 48.17148 542.75595 1.00416 -2.23975 18.16530 1.56455 -3.56344 7.37244 8 0 8 2.00 -1999-Aug-27 09:09:21 4171700.64259 872121.02241 4730014.97815 11.80799 48.17149 537.88529 -0.97311 -1.03355 13.29464 -0.41271 -2.35724 2.50178 8 0 8 2.00 -1999-Aug-27 09:09:21 4171699.25135 872119.95723 4730013.41049 11.80798 48.17149 535.66361 -1.73104 -0.90187 11.07296 -1.17065 -2.22555 0.28010 8 0 8 2.00 -1999-Aug-27 09:09:21 4171698.28300 872120.98618 4730012.00275 11.80800 48.17149 534.12293 -0.52571 -1.29130 9.53228 0.03468 -2.61499 -1.26058 8 0 8 2.00 -1999-Aug-27 09:09:21 4171702.41054 872122.20164 4730014.76464 11.80800 48.17147 539.04123 -0.18061 -2.64525 14.45057 0.37979 -3.96893 3.65772 8 0 8 2.00 -1999-Aug-27 09:09:21 4171700.92649 872119.24980 4730014.63659 11.80797 48.17149 537.57420 -2.76630 -1.19811 12.98354 -2.20590 -2.52180 2.19068 8 0 8 2.00 -1999-Aug-27 09:09:21 4171700.93647 872120.16346 4730016.75805 11.80798 48.17150 539.28620 -1.87401 0.07010 14.69555 -1.31362 -1.25359 3.90269 8 0 8 2.00 -1999-Aug-27 09:09:21 4171699.13405 872119.61011 4730016.43377 11.80798 48.17151 537.79244 -2.04682 1.25285 13.20179 -1.48642 -0.07084 2.40893 8 0 8 2.00 -1999-Aug-27 09:09:21 4171698.23324 872120.78051 4730018.54953 11.80800 48.17153 538.94068 -0.71685 3.14243 14.35002 -0.15646 1.81874 3.55716 8 0 8 2.00 -1999-Aug-27 09:09:21 4171698.42739 872119.73233 4730014.62931 11.80798 48.17150 536.00324 -1.78258 0.54624 11.41259 -1.22218 -0.77745 0.61973 8 0 8 2.00 -1999-Aug-27 09:09:21 4171701.24371 872121.23133 4730018.80060 11.80799 48.17151 541.15449 -0.89161 1.04536 16.56383 -0.33121 -0.27833 5.77098 8 0 8 2.00 -1999-Aug-27 09:09:21 4171700.03882 872122.95815 4730015.46396 11.80802 48.17149 538.11733 1.04523 -0.56435 13.52667 1.60563 -1.88804 2.73381 8 0 8 2.00 -1999-Aug-27 09:09:21 4171697.74177 872121.47863 4730014.30574 11.80801 48.17150 535.55288 0.06707 0.56424 10.96223 0.62746 -0.75944 0.16937 8 0 8 2.00 -1999-Aug-27 09:09:21 4171702.02315 872123.14743 4730015.99199 11.80802 48.17148 539.83197 0.82444 -1.68839 15.24132 1.38484 -3.01208 4.44846 8 0 8 2.00 -1999-Aug-27 09:09:21 4171700.00113 872122.42775 4730015.48313 11.80801 48.17149 538.03462 0.53377 -0.44320 13.44397 1.09416 -1.76689 2.65111 8 0 8 2.00 -1999-Aug-27 09:09:21 4171701.16441 872122.64495 4730018.18176 11.80801 48.17150 540.83451 0.50832 0.47494 16.24386 1.06872 -0.84874 5.45100 8 0 8 2.00 -1999-Aug-27 09:09:21 4171697.28530 872121.05176 4730015.79983 11.80800 48.17152 536.30996 -0.25736 1.95869 11.71931 0.30304 0.63500 0.92645 8 0 8 2.00 -1999-Aug-27 09:09:21 4171694.86685 872119.29764 4730013.91022 11.80799 48.17152 533.08380 -1.47947 2.72993 8.49315 -0.91907 1.40625 -2.29971 8 0 8 2.00 -1999-Aug-27 09:09:21 4171693.51569 872119.52601 4730012.67172 11.80799 48.17152 531.31009 -0.97944 2.85465 6.71943 -0.41904 1.53096 -4.07343 8 0 8 2.00 -1999-Aug-27 09:09:22 4171690.88592 872118.61848 4730013.90752 11.80799 48.17155 530.39040 -1.32963 5.73528 5.79974 -0.76923 4.41160 -4.99312 8 0 8 2.00 -1999-Aug-27 09:09:22 4171692.52746 872119.09683 4730010.59881 11.80799 48.17152 529.06178 -1.19732 2.25845 4.47113 -0.63692 0.93477 -6.32173 8 0 8 2.00 -1999-Aug-27 09:09:22 4171697.96983 872119.63185 4730016.19910 11.80798 48.17152 536.86055 -1.78730 1.94219 12.26990 -1.22691 0.61851 1.47704 8 0 8 2.00 -1999-Aug-27 09:09:22 4171697.50798 872121.03459 4730016.00991 11.80800 48.17152 536.60952 -0.31974 1.93899 12.01887 0.24066 0.61531 1.22601 8 0 8 2.00 -1999-Aug-27 09:09:22 4171694.63478 872119.17111 4730013.22461 11.80798 48.17152 532.40416 -1.55583 2.46125 7.81351 -0.99543 1.13757 -2.97935 8 0 8 2.00 -1999-Aug-27 09:09:22 4171692.49931 872121.27124 4730014.45843 11.80802 48.17154 532.21613 0.93684 4.52143 7.62548 1.49724 3.19774 -3.16738 8 0 8 2.00 -1999-Aug-27 09:09:22 4171696.61631 872121.17587 4730014.55722 11.80801 48.17151 534.96426 0.00102 1.59900 10.37361 0.56142 0.27532 -0.41925 8 0 8 2.00 -1999-Aug-27 09:09:22 4171693.90220 872119.54058 4730010.59889 11.80799 48.17151 530.01982 -1.04427 1.18815 5.42917 -0.48387 -0.13554 -5.36369 8 0 8 2.00 -1999-Aug-27 09:09:22 4171700.29891 872120.23397 4730014.91080 11.80798 48.17149 537.50316 -1.67453 -0.70757 12.91250 -1.11414 -2.03126 2.11964 8 0 8 2.00 -1999-Aug-27 09:09:22 4171700.73872 872120.07867 4730017.23077 11.80798 48.17150 539.49778 -1.91654 0.54252 14.90713 -1.35614 -0.78117 4.11427 8 0 8 2.00 -1999-Aug-27 09:09:22 4171695.39060 872119.68205 4730016.46018 11.80799 48.17153 535.37825 -1.21037 3.98988 10.78760 -0.64998 2.66620 -0.00526 8 0 8 2.00 -1999-Aug-27 09:09:22 4171696.15920 872120.45485 4730016.73467 11.80800 48.17153 536.18998 -0.61120 3.49450 11.59933 -0.05081 2.17081 0.80647 8 0 8 2.00 -1999-Aug-27 09:09:22 4171698.77574 872122.62338 4730016.30861 11.80802 48.17151 537.87650 0.97601 0.97126 13.28584 1.53641 -0.35243 2.49299 8 0 8 2.00 -1999-Aug-27 09:09:22 4171696.06143 872121.09773 4730012.70430 11.80801 48.17150 533.21068 0.03809 0.77992 8.62003 0.59848 -0.54377 -2.17283 8 0 8 2.00 -1999-Aug-27 09:09:22 4171698.80745 872123.16248 4730015.52177 11.80803 48.17150 537.38446 1.49721 0.34119 12.79381 2.05760 -0.98250 2.00095 8 0 8 2.00 -1999-Aug-27 09:09:22 4171699.80683 872120.87722 4730013.81195 11.80799 48.17149 536.45092 -0.94420 -1.17957 11.86026 -0.38380 -2.50325 1.06740 8 0 8 2.00 -1999-Aug-27 09:09:22 4171699.60136 872121.34962 4730012.32373 11.80800 48.17148 535.27231 -0.43975 -2.09423 10.68166 0.12065 -3.41792 -0.11120 8 0 8 2.00 -1999-Aug-27 09:09:22 4171698.11557 872121.29054 4730015.23191 11.80800 48.17151 536.46136 -0.19353 0.93796 11.87070 0.36686 -0.38573 1.07785 8 0 8 2.00 -1999-Aug-27 09:09:22 4171694.36863 872118.16382 4730013.70923 11.80797 48.17153 532.45407 -2.48734 3.13217 7.86341 -1.92695 1.80848 -2.92945 8 0 8 2.00 -1999-Aug-27 09:09:22 4171695.40431 872120.65352 4730014.23353 11.80800 48.17152 533.86060 -0.26226 2.34679 9.26994 0.29813 1.02310 -1.52291 8 0 8 2.00 -1999-Aug-27 09:09:22 4171695.10118 872120.16780 4730013.76995 11.80800 48.17152 533.25100 -0.67567 2.33278 8.66034 -0.11528 1.00910 -2.13251 8 0 8 2.00 -1999-Aug-27 09:09:22 4171695.19665 872118.89598 4730012.49401 11.80798 48.17151 532.18899 -1.94012 1.60615 7.59834 -1.37972 0.28247 -3.19452 8 0 8 2.00 -1999-Aug-27 09:09:22 4171697.01626 872120.78139 4730015.94960 11.80800 48.17152 536.20904 -0.46696 2.29603 11.61839 0.09344 0.97235 0.82553 8 0 8 2.00 -1999-Aug-27 09:09:22 4171700.27502 872124.36651 4730017.07026 11.80804 48.17150 539.66064 2.37545 0.11987 15.06998 2.93585 -1.20381 4.27713 8 0 8 2.00 -1999-Aug-27 09:09:22 4171701.59082 872125.47747 4730017.55732 11.80805 48.17149 541.03412 3.19364 -0.68442 16.44347 3.75404 -2.00810 5.65061 8 0 8 2.00 -1999-Aug-27 09:09:23 4171701.74377 872123.61169 4730019.27097 11.80802 48.17150 542.15626 1.33605 0.63136 17.56561 1.89645 -0.69233 6.77275 8 0 8 2.00 -1999-Aug-27 09:09:23 4171700.40382 872123.79576 4730017.35293 11.80803 48.17150 539.87746 1.79042 0.30147 15.28681 2.35082 -1.02222 4.49395 8 0 8 2.00 -1999-Aug-27 09:09:23 4171703.87978 872122.47863 4730016.16442 11.80800 48.17147 541.08118 -0.21013 -2.82560 16.49052 0.35026 -4.14928 5.69766 8 0 8 2.00 -1999-Aug-27 09:09:23 4171703.45808 872121.08026 4730017.96397 11.80799 48.17149 541.95598 -1.49262 -1.10466 17.36532 -0.93222 -2.42835 6.57246 8 0 8 2.00 -1999-Aug-27 09:09:23 4171699.72388 872119.98180 4730016.06592 11.80798 48.17150 537.95410 -1.80369 0.52065 13.36344 -1.24329 -0.80304 2.57059 8 0 8 2.00 -1999-Aug-27 09:09:23 4171698.59992 872121.33310 4730016.93166 11.80800 48.17151 538.04990 -0.25099 1.71176 13.45925 0.30941 0.38808 2.66639 8 0 8 2.00 -1999-Aug-27 09:09:23 4171699.67899 872121.41363 4730016.82641 11.80800 48.17151 538.68688 -0.39298 0.84224 14.09623 0.16742 -0.48145 3.30337 8 0 8 2.00 -1999-Aug-27 09:09:23 4171699.62290 872121.08301 4730015.76318 11.80800 48.17150 537.81288 -0.70512 0.22449 13.22223 -0.14473 -1.09920 2.42937 8 0 8 2.00 -1999-Aug-27 09:09:23 4171701.67451 872120.80703 4730017.63286 11.80799 48.17150 540.50767 -1.39509 0.01707 15.91701 -0.83469 -1.30662 5.12415 8 0 8 2.00 -1999-Aug-27 09:09:23 4171698.45889 872121.17270 4730015.58554 11.80800 48.17151 536.93290 -0.37913 0.94135 12.34224 0.18126 -0.38234 1.54938 8 0 8 2.00 -1999-Aug-27 09:09:23 4171695.25417 872121.71540 4730013.26065 11.80802 48.17151 533.18257 0.80787 1.64556 8.59191 1.36826 0.32188 -2.20094 8 0 8 2.00 -1999-Aug-27 09:09:23 4171692.27569 872119.24784 4730009.88592 11.80799 48.17152 528.38683 -0.99798 1.94364 3.79618 -0.43758 0.61995 -6.99668 8 0 8 2.00 -1999-Aug-27 09:09:23 4171696.59465 872120.55718 4730009.69348 11.80800 48.17148 531.24150 -0.60015 -1.53450 6.65084 -0.03975 -2.85818 -4.14201 8 0 8 2.00 -1999-Aug-27 09:09:23 4171693.87027 872119.94491 4730011.79914 11.80800 48.17152 530.94852 -0.64196 1.95023 6.35786 -0.08156 0.62655 -4.43499 8 0 8 2.00 -1999-Aug-27 09:09:23 4171693.62076 872121.21537 4730013.03881 11.80801 48.17152 531.88275 0.65267 2.76523 7.29210 1.21307 1.44154 -3.50076 8 0 8 2.00 -1999-Aug-27 09:09:23 4171697.10208 872120.62247 4730013.05306 11.80800 48.17150 534.08503 -0.64007 0.32595 9.49438 -0.07967 -0.99774 -1.29848 8 0 8 2.00 -1999-Aug-27 09:09:23 4171697.20198 872122.82017 4730012.92004 11.80803 48.17150 534.35104 1.49068 -0.17073 9.76039 2.05107 -1.49442 -1.03247 8 0 8 2.00 -1999-Aug-27 09:09:23 4171696.20403 872120.73201 4730014.99257 11.80800 48.17152 534.95895 -0.34908 2.25773 10.36830 0.21132 0.93405 -0.42456 8 0 8 2.00 -1999-Aug-27 09:09:23 4171697.55230 872119.45140 4730016.34870 11.80798 48.17152 536.67484 -1.87850 2.37401 12.08418 -1.31810 1.05032 1.29133 8 0 8 2.00 -1999-Aug-27 09:09:23 4171697.71616 872120.74176 4730013.67756 11.80800 48.17150 534.96751 -0.64897 0.27635 10.37686 -0.08857 -1.04734 -0.41600 8 0 8 2.00 -1999-Aug-27 09:09:23 4171698.65261 872119.76049 4730014.52523 11.80798 48.17150 536.07655 -1.80110 0.30827 11.48589 -1.24071 -1.01542 0.69304 8 0 8 2.00 -1999-Aug-27 09:09:23 4171700.77057 872121.23510 4730016.35719 11.80799 48.17150 539.02545 -0.79110 -0.23964 14.43479 -0.23070 -1.56332 3.64193 8 0 8 2.00 -1999-Aug-27 09:09:23 4171698.88396 872119.69364 4730016.07676 11.80798 48.17151 537.37456 -1.91388 1.18444 12.78391 -1.35349 -0.13925 1.99105 8 0 8 2.00 -1999-Aug-27 09:09:23 4171700.76840 872121.17525 4730016.74354 11.80799 48.17150 539.30375 -0.84924 0.02873 14.71310 -0.28884 -1.29496 3.92024 8 0 8 2.00 -1999-Aug-27 09:09:23 4171700.63138 872121.42159 4730014.53158 11.80800 48.17149 537.59969 -0.58008 -1.38406 13.00904 -0.01968 -2.70774 2.21618 8 0 8 2.00 -1999-Aug-27 09:09:24 4171702.35156 872120.64068 4730012.37503 11.80798 48.17146 537.00910 -1.69646 -3.95786 12.41844 -1.13606 -5.28154 1.62559 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.91282 872119.01307 4730012.09608 11.80797 48.17148 534.98714 -2.79059 -2.11694 10.39648 -2.23020 -3.44063 -0.39637 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.94506 872119.81074 4730012.63023 11.80798 48.17148 535.51505 -2.01639 -1.90586 10.92440 -1.45600 -3.22955 0.13154 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.74207 872121.95179 4730014.54873 11.80801 48.17149 537.10430 0.12089 -0.80482 12.51364 0.68129 -2.12851 1.72079 8 0 8 2.00 -1999-Aug-27 09:09:24 4171700.57314 872120.42580 4730014.39324 11.80798 48.17149 537.32270 -1.54287 -1.28200 12.73204 -0.98248 -2.60569 1.93918 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.33310 872120.32239 4730014.09684 11.80799 48.17149 536.27823 -1.39034 -0.55944 11.68758 -0.82994 -1.88313 0.89472 8 0 8 2.00 -1999-Aug-27 09:09:24 4171697.14398 872120.86363 4730014.82407 11.80800 48.17151 535.46495 -0.41259 1.43971 10.87430 0.14780 0.11603 0.08144 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.48700 872120.47236 4730015.31533 11.80799 48.17150 537.30711 -1.27504 0.11805 12.71646 -0.71464 -1.20563 1.92360 8 0 8 2.00 -1999-Aug-27 09:09:24 4171696.15722 872119.33904 4730012.33941 11.80798 48.17150 532.76131 -1.70300 0.73488 8.17066 -1.14260 -0.58881 -2.62220 8 0 8 2.00 -1999-Aug-27 09:09:24 4171698.98685 872121.23890 4730014.84026 11.80800 48.17150 536.73124 -0.42238 0.04914 12.14059 0.13802 -1.27455 1.34773 8 0 8 2.00 -1999-Aug-27 09:09:24 4171695.07266 872120.95475 4730015.36847 11.80801 48.17153 534.53090 0.10046 3.29965 9.94025 0.66086 1.97596 -0.85261 8 0 8 2.00 -1999-Aug-27 09:09:24 4171698.78133 872121.41440 4730014.84369 11.80800 48.17150 536.62358 -0.20853 0.17457 12.03293 0.35187 -1.14911 1.24007 8 0 8 2.00 -1999-Aug-27 09:09:24 4171697.30593 872121.39355 4730013.75679 11.80801 48.17150 534.84771 0.07297 0.52901 10.25706 0.63337 -0.79467 -0.53580 8 0 8 2.00 -1999-Aug-27 09:09:24 4171697.12391 872121.11386 4730017.80195 11.80800 48.17153 537.70495 -0.16355 3.40215 13.11430 0.39685 2.07847 2.32144 8 0 8 2.00 -1999-Aug-27 09:09:24 4171696.56955 872120.23107 4730016.81837 11.80799 48.17153 536.48968 -0.91422 3.28515 11.89903 -0.35382 1.96146 1.10617 8 0 8 2.00 -1999-Aug-27 09:09:24 4171695.11351 872119.49595 4730017.40023 11.80799 48.17154 535.87245 -1.33583 4.84729 11.28179 -0.77543 3.52360 0.48893 8 0 8 2.00 -1999-Aug-27 09:09:24 4171694.78969 872119.62586 4730014.84672 11.80799 48.17153 533.77606 -1.14240 3.36072 9.18540 -0.58200 2.03703 -1.60745 8 0 8 2.00 -1999-Aug-27 09:09:24 4171700.33633 872120.75391 4730015.46899 11.80799 48.17149 538.01448 -1.17325 -0.44189 13.42382 -0.61285 -1.76557 2.63097 8 0 8 2.00 -1999-Aug-27 09:09:24 4171697.01167 872121.58222 4730011.88278 11.80801 48.17149 533.28496 0.31787 -0.53492 8.69431 0.87827 -1.85860 -2.09855 8 0 8 2.00 -1999-Aug-27 09:09:24 4171693.64754 872120.65812 4730011.90250 11.80801 48.17152 530.97747 0.10174 2.07286 6.38682 0.66213 0.74918 -4.40604 8 0 8 2.00 -1999-Aug-27 09:09:24 4171692.26081 872120.67325 4730011.57983 11.80801 48.17152 529.83386 0.40032 2.86681 5.24321 0.96071 1.54313 -5.54965 8 0 8 2.00 -1999-Aug-27 09:09:24 4171698.53981 872121.11428 4730015.80070 11.80800 48.17151 537.13807 -0.45288 1.03472 12.54742 0.10752 -0.28896 1.75456 8 0 8 2.00 -1999-Aug-27 09:09:24 4171696.26879 872119.69321 4730015.05164 11.80799 48.17152 534.90348 -1.37915 2.40829 10.31283 -0.81876 1.08460 -0.48003 8 0 8 2.00 -1999-Aug-27 09:09:24 4171694.69933 872118.71916 4730012.08588 11.80798 48.17151 531.53610 -2.01143 1.72366 6.94545 -1.45103 0.39998 -3.84741 8 0 8 2.00 -1999-Aug-27 09:09:24 4171699.58368 872120.67641 4730013.31263 11.80799 48.17149 535.90577 -1.09509 -1.31918 11.31512 -0.53469 -2.64287 0.52226 8 0 8 2.00 -1999-Aug-27 09:09:25 4171700.17170 872118.91897 4730014.17365 11.80797 48.17149 536.69138 -2.93567 -0.90588 12.10072 -2.37528 -2.22957 1.30786 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.64183 872119.60517 4730013.82382 11.80797 48.17148 537.48403 -2.56483 -2.31610 12.89338 -2.00443 -3.63978 2.10052 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.59558 872122.11899 4730016.02328 11.80800 48.17149 539.43582 -0.09474 -1.19885 14.84517 0.46566 -2.52253 4.05231 8 0 8 2.00 -1999-Aug-27 09:09:25 4171703.61990 872121.01985 4730016.76083 11.80798 48.17148 541.15686 -1.58486 -2.01586 16.56621 -1.02447 -3.33954 5.77335 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.09578 872121.60515 4730014.09368 11.80800 48.17148 537.60160 -0.49543 -2.04280 13.01094 0.06497 -3.36649 2.21808 8 0 8 2.00 -1999-Aug-27 09:09:25 4171699.76782 872122.63650 4730016.47835 11.80802 48.17150 538.65239 0.78584 0.35887 14.06174 1.34623 -0.96482 3.26888 8 0 8 2.00 -1999-Aug-27 09:09:25 4171694.37645 872120.50463 4730013.87324 11.80800 48.17152 532.90084 -0.19767 2.87892 8.31018 0.36273 1.55523 -2.48267 8 0 8 2.00 -1999-Aug-27 09:09:25 4171690.96030 872118.32459 4730011.48687 11.80798 48.17153 528.59510 -1.63252 4.11150 4.00445 -1.07213 2.78782 -6.78841 8 0 8 2.00 -1999-Aug-27 09:09:25 4171692.31018 872117.40922 4730011.46359 11.80797 48.17153 529.33403 -2.80474 3.25098 4.74337 -2.24435 1.92730 -6.04948 8 0 8 2.00 -1999-Aug-27 09:09:25 4171695.52334 872118.85459 4730011.18502 11.80798 48.17150 531.42122 -2.04748 0.50122 6.83057 -1.48708 -0.82247 -3.96229 8 0 8 2.00 -1999-Aug-27 09:09:25 4171696.07825 872121.17335 4730012.55148 11.80801 48.17150 533.11811 0.10865 0.65421 8.52745 0.66905 -0.66948 -2.26540 8 0 8 2.00 -1999-Aug-27 09:09:25 4171693.49768 872120.90121 4730014.34574 11.80801 48.17153 532.73339 0.37035 3.77451 8.14273 0.93075 2.45083 -2.65013 8 0 8 2.00 -1999-Aug-27 09:09:25 4171700.52163 872123.50052 4730019.02947 11.80803 48.17151 541.16334 1.47733 1.37866 16.57268 2.03772 0.05497 5.77982 8 0 8 2.00 -1999-Aug-27 09:09:25 4171696.76605 872121.18363 4730015.45778 11.80801 48.17152 535.73412 -0.02203 2.08920 11.14347 0.53837 0.76551 0.35061 8 0 8 2.00 -1999-Aug-27 09:09:25 4171693.76606 872119.32232 4730012.61168 11.80799 48.17152 531.40098 -1.23005 2.66305 6.81033 -0.66965 1.33937 -3.98253 8 0 8 2.00 -1999-Aug-27 09:09:25 4171696.20759 872119.57829 4730013.34626 11.80799 48.17151 533.57709 -1.47911 1.33312 8.98644 -0.91872 0.00943 -1.80642 8 0 8 2.00 -1999-Aug-27 09:09:25 4171697.28282 872122.01346 4730014.67278 11.80801 48.17151 535.59977 0.68449 1.06222 11.00912 1.24489 -0.26147 0.21626 8 0 8 2.00 -1999-Aug-27 09:09:25 4171697.38868 872120.59481 4730014.87393 11.80800 48.17151 535.62516 -0.72580 1.33548 11.03451 -0.16540 0.01179 0.24165 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.47703 872121.73941 4730015.89576 11.80800 48.17149 539.21161 -0.44202 -1.13954 14.62096 0.11837 -2.46322 3.82810 8 0 8 2.00 -1999-Aug-27 09:09:25 4171698.56067 872121.95165 4730015.61104 11.80801 48.17150 537.12465 0.36251 0.76535 12.53399 0.92290 -0.55834 1.74113 8 0 8 2.00 -1999-Aug-27 09:09:25 4171696.65831 872120.93186 4730015.95828 11.80800 48.17152 536.00237 -0.24642 2.53995 11.41171 0.31398 1.21627 0.61886 8 0 8 2.00 -1999-Aug-27 09:09:25 4171698.12161 872120.99480 4730015.67877 11.80800 48.17151 536.75791 -0.48425 1.27665 12.16726 0.07614 -0.04704 1.37440 8 0 8 2.00 -1999-Aug-27 09:09:25 4171699.22246 872122.04848 4730015.70174 11.80801 48.17150 537.63745 0.32186 0.32837 13.04680 0.88225 -0.99532 2.25394 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.82105 872121.33286 4730013.71505 11.80799 48.17147 537.75576 -0.91038 -2.78278 13.16510 -0.34998 -4.10647 2.37224 8 0 8 2.00 -1999-Aug-27 09:09:25 4171701.09452 872120.15846 4730011.31476 11.80798 48.17146 535.33265 -1.91125 -3.67456 10.74200 -1.35085 -4.99825 -0.05086 8 0 8 2.00 -1999-Aug-27 09:09:26 4171699.31797 872121.96160 4730011.33167 11.80801 48.17147 534.43161 0.21727 -2.64246 9.84096 0.77767 -3.96615 -0.95190 8 0 8 2.00 -1999-Aug-27 09:09:26 4171696.40654 872120.50838 4730010.91995 11.80800 48.17149 532.02594 -0.60942 -0.57192 7.43528 -0.04903 -1.89560 -3.35757 8 0 8 2.00 -1999-Aug-27 09:09:26 4171697.43050 872120.78032 4730011.77655 11.80800 48.17149 533.36978 -0.55277 -0.78897 8.77913 0.00763 -2.11265 -2.01373 8 0 8 2.00 -1999-Aug-27 09:09:26 4171694.44315 872121.78184 4730012.10140 11.80802 48.17151 531.79840 1.03887 1.45386 7.20774 1.59927 0.13018 -3.58511 8 0 8 2.00 -1999-Aug-27 09:09:26 4171694.10709 872121.73487 4730015.54433 11.80802 48.17153 534.13810 1.06166 4.00224 9.54744 1.62205 2.67856 -1.24541 8 0 8 2.00 -1999-Aug-27 09:09:26 4171695.71266 872121.88653 4730013.82285 11.80802 48.17151 533.92414 0.88156 1.65999 9.33349 1.44196 0.33631 -1.45937 8 0 8 2.00 -1999-Aug-27 09:09:26 4171699.38466 872123.23049 4730016.78694 11.80803 48.17150 538.71327 1.44566 0.75356 14.12262 2.00606 -0.57013 3.32976 8 0 8 2.00 -1999-Aug-27 09:09:26 4171704.47493 872124.91527 4730020.86486 11.80803 48.17149 545.30472 2.05316 -0.49648 20.71407 2.61356 -1.82017 9.92121 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.20851 872122.02322 4730018.07017 11.80801 48.17151 540.04252 0.09536 1.19254 15.45186 0.65576 -0.13115 4.65900 8 0 8 2.00 -1999-Aug-27 09:09:26 4171697.04585 872120.19022 4730015.12500 11.80799 48.17151 535.53323 -1.05167 1.81466 10.94257 -0.49127 0.49097 0.14972 8 0 8 2.00 -1999-Aug-27 09:09:26 4171694.95298 872119.67251 4730012.73626 11.80799 48.17151 532.31642 -1.13015 1.82703 7.72577 -0.56976 0.50334 -3.06709 8 0 8 2.00 -1999-Aug-27 09:09:26 4171698.15175 872120.05774 4730012.81519 11.80799 48.17149 534.51593 -1.40765 -0.51218 9.92528 -0.84725 -1.83586 -0.86758 8 0 8 2.00 -1999-Aug-27 09:09:26 4171695.77711 872118.64724 4730013.51632 11.80797 48.17151 533.29574 -2.30238 1.90249 8.70508 -1.74198 0.57881 -2.08777 8 0 8 2.00 -1999-Aug-27 09:09:26 4171698.30525 872120.50803 4730015.75047 11.80799 48.17151 536.86479 -0.99830 1.26475 12.27414 -0.43790 -0.05894 1.48128 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.05296 872120.23959 4730013.14219 11.80798 48.17148 536.02550 -1.61870 -1.70852 11.43485 -1.05830 -3.03221 0.64199 8 0 8 2.00 -1999-Aug-27 09:09:26 4171698.90391 872121.40123 4730014.81886 11.80800 48.17150 536.68330 -0.24650 0.07061 12.09265 0.31389 -1.25307 1.29979 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.93193 872120.91958 4730017.11237 11.80799 48.17150 539.65044 -1.13297 0.19442 15.05979 -0.57257 -1.12927 4.26693 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.82144 872120.99287 4730016.40920 11.80799 48.17150 539.06436 -1.03861 -0.20512 14.47370 -0.47822 -1.52881 3.68084 8 0 8 2.00 -1999-Aug-27 09:09:26 4171698.73942 872121.03495 4730015.08746 11.80800 48.17150 536.72608 -0.57138 0.42556 12.13543 -0.01098 -0.89812 1.34257 8 0 8 2.00 -1999-Aug-27 09:09:26 4171699.28037 872120.15913 4730013.84183 11.80798 48.17149 536.03151 -1.53936 -0.66616 11.44086 -0.97896 -1.98984 0.64800 8 0 8 2.00 -1999-Aug-27 09:09:26 4171699.43631 872122.97877 4730017.68419 11.80802 48.17151 539.38122 1.18870 1.35265 14.79056 1.74910 0.02896 3.99771 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.04339 872122.73179 4730014.54631 11.80802 48.17149 537.40564 0.82272 -1.14515 12.81498 1.38312 -2.46884 2.02213 8 0 8 2.00 -1999-Aug-27 09:09:26 4171701.70405 872121.34926 4730016.74069 11.80799 48.17149 539.93616 -0.87037 -0.68214 15.34550 -0.30998 -2.00583 4.55265 8 0 8 2.00 -1999-Aug-27 09:09:26 4171700.49068 872120.89603 4730015.81358 11.80799 48.17149 538.39140 -1.06572 -0.34633 13.80075 -0.50533 -1.67001 3.00789 8 0 8 2.00 -1999-Aug-27 09:09:26 4171699.41637 872121.95778 4730019.48264 11.80801 48.17152 540.56897 0.19340 2.72227 15.97832 0.75380 1.39858 5.18546 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.45920 872121.56947 4730015.54654 11.80801 48.17152 535.65261 0.41844 2.31336 11.06195 0.97884 0.98968 0.26910 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.05996 872119.35928 4730012.55507 11.80798 48.17151 532.86128 -1.66328 0.94655 8.27063 -1.10289 -0.37714 -2.52223 8 0 8 2.00 -1999-Aug-27 09:09:27 4171697.99070 872119.45592 4730014.78302 11.80798 48.17151 535.79498 -1.96378 1.00941 11.20433 -1.40338 -0.31428 0.41147 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.46530 872117.33389 4730015.60471 11.80796 48.17152 535.12191 -3.72876 2.99355 10.53125 -3.16836 1.66987 -0.26161 8 0 8 2.00 -1999-Aug-27 09:09:27 4171697.96490 872118.64645 4730018.65970 11.80797 48.17153 538.55637 -2.75084 3.73702 13.96571 -2.19044 2.41334 3.17285 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.15191 872118.71406 4730015.46478 11.80797 48.17152 535.00141 -2.31366 2.91836 10.41075 -1.75327 1.59467 -0.38210 8 0 8 2.00 -1999-Aug-27 09:09:27 4171695.06855 872119.28133 4730013.36696 11.80798 48.17152 532.80844 -1.53671 2.22300 8.21779 -0.97631 0.89931 -2.57507 8 0 8 2.00 -1999-Aug-27 09:09:27 4171694.93976 872119.04421 4730012.44017 11.80798 48.17151 532.00141 -1.74245 1.73501 7.41076 -1.18206 0.41132 -3.38210 8 0 8 2.00 -1999-Aug-27 09:09:27 4171693.96270 872120.09494 4730011.79726 11.80800 48.17151 531.02793 -0.51402 1.85868 6.43728 0.04637 0.53500 -4.35558 8 0 8 2.00 -1999-Aug-27 09:09:27 4171695.67092 872120.01580 4730015.35043 11.80799 48.17152 534.77987 -0.94104 2.99443 10.18921 -0.38064 1.67075 -0.60365 8 0 8 2.00 -1999-Aug-27 09:09:27 4171695.51089 872119.89420 4730015.16401 11.80799 48.17152 534.51989 -1.02733 3.00537 9.92924 -0.46693 1.68168 -0.86362 8 0 8 2.00 -1999-Aug-27 09:09:27 4171698.79940 872119.96533 4730016.72082 11.80798 48.17151 537.83636 -1.63064 1.63421 13.24570 -1.07024 0.31052 2.45284 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.28314 872120.13448 4730013.15202 11.80799 48.17151 533.55758 -0.95015 1.06367 8.96693 -0.38976 -0.26001 -1.82593 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.37664 872120.81522 4730012.71253 11.80800 48.17150 533.38403 -0.30296 0.59858 8.79338 0.25744 -0.72511 -1.99948 8 0 8 2.00 -1999-Aug-27 09:09:27 4171698.21921 872121.44258 4730014.95401 11.80800 48.17150 536.34269 -0.06592 0.65384 11.75203 0.49448 -0.66984 0.95917 8 0 8 2.00 -1999-Aug-27 09:09:27 4171697.67009 872121.57648 4730015.44628 11.80801 48.17151 536.36931 0.17752 1.36224 11.77865 0.73792 0.03855 0.98580 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.21850 872123.88290 4730015.26992 11.80804 48.17152 535.60507 2.73217 1.95169 11.01441 3.29257 0.62800 0.22156 8 0 8 2.00 -1999-Aug-27 09:09:27 4171693.60003 872122.60285 4730013.26021 11.80803 48.17152 532.22354 2.01503 2.71644 7.63289 2.57543 1.39275 -3.15997 8 0 8 2.00 -1999-Aug-27 09:09:27 4171696.14842 872121.04628 4730016.20840 11.80801 48.17153 535.87151 -0.03009 3.06121 11.28086 0.53031 1.73752 0.48800 8 0 8 2.00 -1999-Aug-27 09:09:27 4171697.47505 872120.07692 4730012.68315 11.80799 48.17150 533.97842 -1.25040 -0.10959 9.38777 -0.69000 -1.43328 -1.40509 8 0 8 2.00 -1999-Aug-27 09:09:27 4171702.50503 872120.68762 4730016.92825 11.80798 48.17149 540.50850 -1.68192 -1.04039 15.91784 -1.12152 -2.36408 5.12498 8 0 8 2.00 -1999-Aug-27 09:09:27 4171698.63401 872120.95423 4730016.25924 11.80800 48.17151 537.51940 -0.62882 1.29623 12.92874 -0.06842 -0.02746 2.13589 8 0 8 2.00 -1999-Aug-27 09:09:27 4171701.02259 872119.93443 4730017.69381 11.80798 48.17150 540.00843 -2.11581 0.66627 15.41778 -1.55542 -0.65742 4.62492 8 0 8 2.00 -1999-Aug-27 09:09:27 4171699.32600 872119.42852 4730013.73535 11.80798 48.17149 535.88225 -2.26385 -0.65904 11.29160 -1.70345 -1.98273 0.49874 8 0 8 2.00 -1999-Aug-27 09:09:27 4171698.68327 872120.18889 4730015.34896 11.80799 48.17150 536.76883 -1.38804 0.76992 12.17817 -0.82764 -0.55376 1.38531 8 0 8 2.00 -1999-Aug-27 09:09:28 4171697.81165 872120.76137 4730018.39320 11.80800 48.17153 538.54636 -0.64931 3.34859 13.95571 -0.08891 2.02490 3.16285 8 0 8 2.00 -1999-Aug-27 09:09:28 4171700.60618 872121.04086 4730021.54642 11.80799 48.17153 542.75835 -0.94759 3.37060 18.16769 -0.38720 2.04691 7.37484 8 0 8 2.00 -1999-Aug-27 09:09:28 4171696.55047 872120.56249 4730016.21715 11.80800 48.17152 536.07446 -0.58591 2.84757 11.48381 -0.02551 1.52388 0.69095 8 0 8 2.00 -1999-Aug-27 09:09:28 4171694.77522 872120.24503 4730015.14350 11.80800 48.17153 534.07225 -0.53337 3.47478 9.48160 0.02702 2.15109 -1.31126 8 0 8 2.00 -1999-Aug-27 09:09:28 4171696.01890 872119.72846 4730014.84175 11.80799 48.17152 534.58876 -1.29351 2.44520 9.99811 -0.73311 1.12152 -0.79475 8 0 8 2.00 -1999-Aug-27 09:09:28 4171692.69495 872118.97234 4730011.15892 11.80799 48.17152 529.57150 -1.35344 2.52881 4.98084 -0.79304 1.20512 -5.81202 8 0 8 2.00 -1999-Aug-27 09:09:28 4171692.84649 872118.15827 4730012.32221 11.80798 48.17153 530.42615 -2.18130 3.31822 5.83549 -1.62090 1.99453 -4.95736 8 0 8 2.00 -1999-Aug-27 09:09:28 4171696.33167 872118.55329 4730012.19501 11.80797 48.17150 532.66036 -2.50781 0.63114 8.06970 -1.94742 -0.69254 -2.72315 8 0 8 2.00 -1999-Aug-27 09:09:28 4171695.04953 872118.10498 4730012.07460 11.80797 48.17151 531.67249 -2.68428 1.55437 7.08184 -2.12388 0.23068 -3.71102 8 0 8 2.00 -1999-Aug-27 09:09:28 4171699.57214 872119.16545 4730015.97531 11.80797 48.17150 537.67612 -2.57171 0.69537 13.08547 -2.01132 -0.62831 2.29261 8 0 8 2.00 -1999-Aug-27 09:09:28 4171695.58995 872119.68773 4730014.33659 11.80799 48.17152 533.92678 -1.24560 2.42738 9.33613 -0.68520 1.10370 -1.45673 8 0 8 2.00 -1999-Aug-27 09:09:28 4171697.64843 872119.82537 4730015.04305 11.80799 48.17151 535.81574 -1.53211 1.37613 11.22508 -0.97171 0.05245 0.43223 8 0 8 2.00 -1999-Aug-27 09:09:28 4171701.31873 872121.92283 4730014.67684 11.80800 48.17148 538.22503 -0.23009 -1.86494 13.63438 0.33030 -3.18863 2.84152 8 0 8 2.00 -1999-Aug-27 09:09:28 4171698.23280 872121.40446 4730011.13211 11.80800 48.17148 533.49849 -0.10601 -1.89910 8.90784 0.45438 -3.22278 -1.88502 8 0 8 2.00 -1999-Aug-27 09:09:28 4171694.48574 872121.28277 4730010.63185 11.80801 48.17150 530.66307 0.54164 0.51885 6.07241 1.10204 -0.80483 -4.72045 8 0 8 2.00 -1999-Aug-27 09:09:28 4171696.98661 872121.61651 4730012.85476 11.80801 48.17150 533.99754 0.35656 0.12635 9.40689 0.91696 -1.19733 -1.38597 8 0 8 2.00 -1999-Aug-27 09:09:28 4171694.55711 872118.29822 4730012.32549 11.80797 48.17152 531.56436 -2.39436 2.05138 6.97371 -1.83396 0.72769 -3.81915 8 0 8 2.00 -1999-Aug-27 09:09:28 4171697.21519 872118.78904 4730014.14288 11.80797 48.17151 534.72073 -2.45785 1.24983 10.13008 -1.89746 -0.07386 -0.66278 8 0 8 2.00 -1999-Aug-27 09:09:28 4171698.48884 872120.82997 4730014.59317 11.80800 48.17150 536.16621 -0.72074 0.30995 11.57556 -0.16034 -1.01374 0.78270 8 0 8 2.00 -1999-Aug-27 09:09:28 4171697.02598 872120.55191 4730014.79281 11.80800 48.17151 535.32210 -0.69357 1.55246 10.73144 -0.13317 0.22878 -0.06142 8 0 8 2.00 -1999-Aug-27 09:09:28 4171700.54880 872121.67153 4730015.83830 11.80800 48.17149 538.55359 -0.31852 -0.49048 13.96294 0.24187 -1.81416 3.17008 8 0 8 2.00 -1999-Aug-27 09:09:28 4171696.20338 872119.55454 4730013.78848 11.80799 48.17151 533.90062 -1.50150 1.63473 9.30996 -0.94110 0.31105 -1.48289 8 0 8 2.00 -1999-Aug-27 09:09:28 4171691.21962 872118.09963 4730010.26796 11.80798 48.17153 527.82542 -1.90578 3.14377 3.23476 -1.34538 1.82008 -7.55809 8 0 8 2.00 -1999-Aug-27 09:09:28 4171692.95673 872120.63511 4730013.86484 11.80801 48.17153 531.98560 0.22058 3.88892 7.39494 0.78097 2.56524 -3.39791 8 0 8 2.00 -1999-Aug-27 09:09:28 4171694.66149 872120.50710 4730012.95803 11.80800 48.17152 532.40528 -0.25358 2.06027 7.81463 0.30682 0.73659 -2.97823 8 0 8 2.00 -1999-Aug-27 09:09:29 4171693.61758 872120.41291 4730015.09486 11.80800 48.17154 533.30322 -0.13215 4.26110 8.71257 0.42824 2.93742 -2.08029 8 0 8 2.00 -1999-Aug-27 09:09:29 4171697.51818 872120.61940 4730014.24136 11.80800 48.17151 535.24169 -0.72823 0.81540 10.65104 -0.16783 -0.50828 -0.14182 8 0 8 2.00 -1999-Aug-27 09:09:29 4171697.58106 872119.94106 4730013.36511 11.80799 48.17150 534.53723 -1.40508 0.28861 9.94658 -0.84468 -1.03508 -0.84628 8 0 8 2.00 -1999-Aug-27 09:09:29 4171696.05111 872121.86420 4730014.46920 11.80802 48.17151 534.62366 0.79044 1.84759 10.03300 1.35084 0.52390 -0.75986 8 0 8 2.00 -1999-Aug-27 09:09:29 4171695.85753 872121.21044 4730014.27483 11.80801 48.17152 534.26324 0.19013 1.95885 9.67259 0.75052 0.63516 -1.12027 8 0 8 2.00 -1999-Aug-27 09:09:29 4171692.62293 872118.65308 4730013.37197 11.80798 48.17153 531.12995 -1.65121 4.10591 6.53930 -1.09081 2.78223 -4.25356 8 0 8 2.00 -1999-Aug-27 09:09:29 4171695.36568 872119.93707 4730017.84636 11.80799 48.17154 536.42969 -0.95565 4.89362 11.83903 -0.39525 3.56993 1.04617 8 0 8 2.00 -1999-Aug-27 09:09:29 4171697.22642 872118.70625 4730016.93136 11.80797 48.17153 536.79459 -2.54118 3.11390 12.20394 -1.98079 1.79022 1.41108 8 0 8 2.00 -1999-Aug-27 09:09:29 4171695.95607 872119.34787 4730015.31159 11.80798 48.17152 534.84592 -1.65319 2.86240 10.25526 -1.09280 1.53871 -0.53759 8 0 8 2.00 -1999-Aug-27 09:09:29 4171698.15542 872121.46849 4730016.73285 11.80801 48.17151 537.63008 -0.02751 1.88273 13.03942 0.53289 0.55905 2.24657 8 0 8 2.00 -1999-Aug-27 09:09:29 4171701.43723 872124.23937 4730020.38486 11.80803 48.17151 542.87182 2.01317 1.50209 18.28117 2.57357 0.17840 7.48831 8 0 8 2.00 -1999-Aug-27 09:09:29 4171700.96003 872124.10109 4730019.91533 11.80803 48.17151 542.19158 1.97547 1.55810 17.60092 2.53587 0.23442 6.80807 8 0 8 2.00 -1999-Aug-27 09:09:29 4171702.38031 872123.37573 4730020.69746 11.80802 48.17151 543.60253 0.97482 1.15439 19.01187 1.53522 -0.16930 8.21901 8 0 8 2.00 -1999-Aug-27 09:09:29 4171698.58910 872122.10236 4730016.36782 11.80801 48.17151 537.72768 0.50421 1.22632 13.13702 1.06460 -0.09737 2.34417 8 0 8 2.00 -1999-Aug-27 09:09:29 4171696.50006 872121.11585 4730014.25520 11.80801 48.17151 534.65514 -0.03394 1.49153 10.06448 0.52646 0.16784 -0.72837 8 0 8 2.00 -1999-Aug-27 09:09:29 4171693.65296 872119.99769 4730013.74967 11.80800 48.17153 532.26729 -0.54583 3.40149 7.67664 0.01457 2.07781 -3.11622 8 0 8 2.00 -1999-Aug-27 09:09:29 4171696.20766 872122.53795 4730015.28874 11.80802 48.17152 535.42847 1.41790 2.17723 10.83782 1.97829 0.85355 0.04496 8 0 8 2.00 -1999-Aug-27 09:09:29 4171696.57512 872120.04048 4730014.10466 11.80799 48.17151 534.44520 -1.10192 1.50036 9.85455 -0.54152 0.17667 -0.93831 8 0 8 2.00 -1999-Aug-27 09:09:29 4171697.90060 872120.73898 4730015.98371 11.80800 48.17151 536.80596 -0.68943 1.68023 12.21530 -0.12903 0.35654 1.42245 8 0 8 2.00 -1999-Aug-27 09:09:29 4171700.46014 872120.72117 4730014.75355 11.80799 48.17149 537.55772 -1.23063 -1.00433 12.96707 -0.67023 -2.32801 2.17421 8 0 8 2.00 -1999-Aug-27 09:09:29 4171700.57415 872121.85123 4730013.63979 11.80800 48.17148 536.95645 -0.14781 -2.00256 12.36580 0.41258 -3.32625 1.57294 8 0 8 2.00 -1999-Aug-27 09:09:29 4171699.25826 872121.05627 4730015.58189 11.80800 48.17150 537.43611 -0.65668 0.37363 12.84546 -0.09628 -0.95006 2.05260 8 0 8 2.00 -1999-Aug-27 09:09:29 4171695.72956 872121.47831 4730013.70623 11.80801 48.17151 533.79256 0.47852 1.63214 9.20191 1.03891 0.30845 -1.59095 8 0 8 2.00 -1999-Aug-27 09:09:29 4171694.17733 872120.59947 4730012.70734 11.80800 48.17152 531.91503 -0.06409 2.23214 7.32438 0.49631 0.90846 -3.46848 8 0 8 2.00 -1999-Aug-27 09:09:29 4171696.88305 872121.03559 4730013.59697 11.80800 48.17150 534.40372 -0.19087 0.78544 9.81306 0.36952 -0.53824 -0.97979 8 0 8 2.00 -1999-Aug-27 09:09:30 4171701.64269 872122.38415 4730015.59587 11.80801 48.17148 539.18428 0.15517 -1.55868 14.59363 0.71557 -2.88236 3.80077 8 0 8 2.00 -1999-Aug-27 09:09:30 4171699.24056 872122.70098 4730014.06409 11.80802 48.17149 536.51803 0.95685 -0.87648 11.92737 1.51725 -2.20016 1.13452 8 0 8 2.00 -1999-Aug-27 09:09:30 4171694.70063 872121.52782 4730015.74840 11.80802 48.17153 534.64936 0.73753 3.73700 10.05871 1.29793 2.41331 -0.73415 8 0 8 2.00 -1999-Aug-27 09:09:30 4171694.29301 872120.14778 4730015.58621 11.80800 48.17153 534.07408 -0.52989 4.13657 9.48342 0.03050 2.81289 -1.30943 8 0 8 2.00 -1999-Aug-27 09:09:30 4171696.63353 872120.91509 4730013.77828 11.80800 48.17151 534.35949 -0.25777 1.10673 9.76884 0.30263 -0.21695 -1.02402 8 0 8 2.00 -1999-Aug-27 09:09:30 4171697.17595 872121.12871 4730014.31358 11.80800 48.17151 535.14161 -0.15966 1.03552 10.55095 0.40074 -0.28816 -0.24190 8 0 8 2.00 -1999-Aug-27 09:09:30 4171695.34992 872121.92875 4730013.10972 11.80802 48.17151 533.16173 0.99712 1.44254 8.57107 1.55751 0.11885 -2.22178 8 0 8 2.00 -1999-Aug-27 09:09:30 4171697.38489 872122.19903 4730014.86162 11.80802 48.17151 535.83244 0.84525 1.08542 11.24179 1.40565 -0.23827 0.44893 8 0 8 2.00 -1999-Aug-27 09:09:30 4171699.23888 872121.79720 4730017.57226 11.80801 48.17151 539.00769 0.07254 1.60216 14.41703 0.63294 0.27848 3.62418 8 0 8 2.00 -1999-Aug-27 09:09:30 4171699.17776 872120.17996 4730017.82589 11.80799 48.17152 538.93608 -1.49797 2.06249 14.34542 -0.93758 0.73881 3.55257 8 0 8 2.00 -1999-Aug-27 09:09:30 4171695.51540 872119.58019 4730016.51864 11.80799 48.17153 535.48938 -1.33561 3.95337 10.89872 -0.77521 2.62968 0.10587 8 0 8 2.00 -1999-Aug-27 09:09:30 4171697.54801 872120.21206 4730019.09315 11.80799 48.17153 538.82086 -1.13305 4.09143 14.23021 -0.57265 2.76775 3.43735 8 0 8 2.00 -1999-Aug-27 09:09:30 4171696.67689 872119.21265 4730015.34537 11.80798 48.17152 535.32317 -1.93305 2.37980 10.73252 -1.37265 1.05611 -0.06034 8 0 8 2.00 -1999-Aug-27 09:09:30 4171692.89505 872118.40925 4730012.50340 11.80798 48.17153 530.62711 -1.94556 3.36536 6.03645 -1.38516 2.04168 -4.75641 8 0 8 2.00 -1999-Aug-27 09:09:30 4171695.08675 872118.05343 4730010.81661 11.80797 48.17150 530.75237 -2.74235 0.69612 6.16171 -2.18195 -0.62756 -4.63115 8 0 8 2.00 -1999-Aug-27 09:09:30 4171696.36912 872120.50320 4730015.79200 11.80800 48.17152 535.63119 -0.60683 2.70535 11.04054 -0.04643 1.38167 0.24768 8 0 8 2.00 -1999-Aug-27 09:09:30 4171701.01218 872121.86039 4730021.49231 11.80800 48.17152 543.09490 -0.22848 2.91342 18.50425 0.33192 1.58973 7.71139 8 0 8 2.00 -1999-Aug-27 09:09:30 4171697.22442 872119.82387 4730017.16852 11.80799 48.17153 537.12252 -1.44681 3.10311 12.53186 -0.88641 1.77942 1.73900 8 0 8 2.00 -1999-Aug-27 09:09:30 4171700.43027 872121.72800 4730016.55302 11.80800 48.17150 539.01649 -0.23899 0.06401 14.42583 0.32140 -1.25967 3.63298 8 0 8 2.00 -1999-Aug-27 09:09:30 4171699.07333 872122.59923 4730019.15486 11.80802 48.17152 540.18834 0.89148 2.65606 15.59768 1.45187 1.33238 4.80483 8 0 8 2.00 -1999-Aug-27 09:09:30 4171692.73917 872121.47573 4730015.60356 11.80802 48.17154 533.25390 1.08792 5.07898 8.66325 1.64832 3.75530 -2.12961 8 0 8 2.00 -1999-Aug-27 09:09:30 4171692.60237 872120.97868 4730015.80892 11.80801 48.17155 533.24979 0.62938 5.39151 8.65914 1.18978 4.06782 -2.13372 8 0 8 2.00 -1999-Aug-27 09:09:30 4171690.60725 872121.56083 4730013.58654 11.80803 48.17155 530.37085 1.60749 5.27582 5.78019 2.16788 3.95213 -5.01267 8 0 8 2.00 -1999-Aug-27 09:09:30 4171688.60919 872119.24947 4730009.20002 11.80800 48.17154 525.48251 -0.24610 4.16022 0.89185 0.31430 2.83654 -9.90101 8 0 8 2.00 -1999-Aug-27 09:09:30 4171692.56569 872119.97236 4730012.02702 11.80800 48.17153 530.27045 -0.34813 3.04954 5.67980 0.21227 1.72586 -5.11306 8 0 8 2.00 -1999-Aug-27 09:09:31 4171697.72143 872120.52088 4730014.62973 11.80799 48.17151 535.65032 -0.86626 0.94119 11.05966 -0.30586 -0.38250 0.26681 8 0 8 2.00 -1999-Aug-27 09:09:31 4171701.15804 872120.80975 4730014.24601 11.80799 48.17148 537.64720 -1.28674 -1.86534 13.05655 -0.72634 -3.18903 2.26369 8 0 8 2.00 -1999-Aug-27 09:09:31 4171697.07844 872119.06255 4730011.97287 11.80798 48.17150 533.05182 -2.16215 -0.13933 8.46117 -1.60175 -1.46301 -2.33169 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.66382 872119.86198 4730011.95801 11.80799 48.17150 532.22639 -1.09016 0.76066 7.63574 -0.52976 -0.56303 -3.15712 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.86800 872120.08411 4730012.87469 11.80799 48.17150 533.72584 -1.11914 0.45982 9.13519 -0.55874 -0.86387 -1.65767 8 0 8 2.00 -1999-Aug-27 09:09:31 4171693.62714 872120.05147 4730011.93252 11.80800 48.17152 530.90373 -0.48790 2.20027 6.31308 0.07249 0.87658 -4.47978 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.07608 872122.50109 4730014.29490 11.80802 48.17151 534.59699 1.40875 1.61603 10.00634 1.96914 0.29234 -0.78652 8 0 8 2.00 -1999-Aug-27 09:09:31 4171697.83145 872122.55249 4730018.26177 11.80802 48.17152 538.70579 1.09985 2.97338 14.11513 1.66025 1.64969 3.32227 8 0 8 2.00 -1999-Aug-27 09:09:31 4171697.66400 872122.31454 4730017.84333 11.80802 48.17152 538.25221 0.90120 2.85274 13.66156 1.46160 1.52905 2.86870 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.66755 872122.91343 4730016.86073 11.80803 48.17153 536.29850 1.89596 3.56228 11.70785 2.45635 2.23860 0.91499 8 0 8 2.00 -1999-Aug-27 09:09:31 4171694.01567 872121.70181 4730015.01432 11.80802 48.17153 533.67897 1.04800 3.72050 9.08832 1.60840 2.39681 -1.70454 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.68720 872120.51201 4730018.08785 11.80800 48.17153 537.55077 -0.66330 4.00311 12.96012 -0.10290 2.67942 2.16726 8 0 8 2.00 -1999-Aug-27 09:09:31 4171698.63840 872120.13718 4730016.25562 11.80799 48.17151 537.40807 -1.42947 1.41519 12.81741 -0.86908 0.09150 2.02456 8 0 8 2.00 -1999-Aug-27 09:09:31 4171694.42403 872119.46304 4730014.68014 11.80799 48.17153 533.39101 -1.22695 3.54116 8.80035 -0.66656 2.21747 -1.99250 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.14758 872119.90882 4730014.70763 11.80799 48.17152 534.59745 -1.14330 2.23440 10.00679 -0.58291 0.91071 -0.78607 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.38179 872119.79404 4730013.91005 11.80799 48.17151 534.14036 -1.30358 1.54916 9.54971 -0.74318 0.22547 -1.24315 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.71602 872119.75736 4730013.90662 11.80799 48.17151 534.35098 -1.40788 1.30869 9.76033 -0.84748 -0.01499 -1.03253 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.07836 872119.44341 4730012.17439 11.80799 48.17151 531.94832 -1.38007 1.39580 7.35767 -0.81967 0.07211 -3.43519 8 0 8 2.00 -1999-Aug-27 09:09:31 4171698.26005 872119.83954 4730014.42735 11.80798 48.17150 535.75814 -1.64340 0.51726 11.16748 -1.08300 -0.80643 0.37462 8 0 8 2.00 -1999-Aug-27 09:09:31 4171700.50436 872121.49937 4730016.69636 11.80800 48.17150 539.14046 -0.47795 0.14043 14.54981 0.08244 -1.18326 3.75695 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.76335 872122.03322 4730017.33534 11.80802 48.17153 537.24735 0.81014 3.21377 12.65670 1.37053 1.89008 1.86384 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.66942 872122.27058 4730016.34227 11.80802 48.17153 535.82566 1.26632 3.31318 11.23501 1.82672 1.98949 0.44215 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.55052 872121.58596 4730017.65062 11.80801 48.17154 536.62952 0.62052 4.37684 12.03887 1.18092 3.05315 1.24601 8 0 8 2.00 -1999-Aug-27 09:09:31 4171695.18186 872121.93718 4730018.07277 11.80802 48.17154 536.75136 1.03975 4.87370 12.16070 1.60015 3.55002 1.36785 8 0 8 2.00 -1999-Aug-27 09:09:31 4171696.97378 872121.52652 4730016.88373 11.80801 48.17152 536.97906 0.27110 2.83636 12.38840 0.83150 1.51267 1.59554 8 0 8 2.00 -1999-Aug-27 09:09:32 4171697.21127 872121.30171 4730016.57533 11.80801 48.17152 536.87361 0.00245 2.49176 12.28295 0.56285 1.16807 1.49010 8 0 8 2.00 -1999-Aug-27 09:09:32 4171702.00213 872121.22742 4730019.01515 11.80799 48.17150 541.80891 -1.05063 0.63586 17.21826 -0.49024 -0.68783 6.42540 8 0 8 2.00 -1999-Aug-27 09:09:32 4171699.91229 872119.79111 4730017.20794 11.80798 48.17151 538.90204 -2.02890 1.17393 14.31138 -1.46850 -0.14976 3.51853 8 0 8 2.00 -1999-Aug-27 09:09:32 4171696.78514 872120.07854 4730012.13567 11.80799 48.17150 533.12032 -1.10764 0.02825 8.52967 -0.54724 -1.29543 -2.26319 8 0 8 2.00 -1999-Aug-27 09:09:32 4171694.50918 872121.14374 4730010.13249 11.80801 48.17150 530.28730 0.40075 0.18993 5.69665 0.96115 -1.13376 -5.09621 8 0 8 2.00 -1999-Aug-27 09:09:32 4171690.82123 872120.15686 4730008.30173 11.80801 48.17151 526.38098 0.18943 1.80937 1.79033 0.74983 0.48569 -9.00253 8 0 8 2.00 -1999-Aug-27 09:09:32 4171694.96114 872121.10898 4730011.62040 11.80801 48.17151 531.68630 0.27424 0.85787 7.09565 0.83464 -0.46581 -3.69721 8 0 8 2.00 -1999-Aug-27 09:09:32 4171693.94699 872121.56118 4730011.79999 11.80802 48.17151 531.21980 0.92441 1.64839 6.62915 1.48480 0.32470 -4.16371 8 0 8 2.00 -1999-Aug-27 09:09:32 4171692.86553 872120.49465 4730012.77481 11.80801 48.17153 531.09467 0.10175 3.24991 6.50401 0.66215 1.92623 -4.28884 8 0 8 2.00 -1999-Aug-27 09:09:32 4171695.47049 872120.50442 4730012.46803 11.80800 48.17151 532.56791 -0.42175 1.14383 7.97725 0.13865 -0.17985 -2.81560 8 0 8 2.00 -1999-Aug-27 09:09:32 4171696.65905 872120.46183 4730013.36098 11.80800 48.17151 534.00335 -0.70666 0.87893 9.41269 -0.14626 -0.44475 -1.38017 8 0 8 2.00 -1999-Aug-27 09:09:32 4171699.24414 872120.41123 4730013.99637 11.80799 48.17149 536.15743 -1.28518 -0.57511 11.56677 -0.72478 -1.89879 0.77392 8 0 8 2.00 -1999-Aug-27 09:09:32 4171698.00759 872120.14192 4730013.39024 11.80799 48.17150 534.86181 -1.29575 -0.03636 10.27115 -0.73535 -1.36004 -0.52171 8 0 8 2.00 -1999-Aug-27 09:09:32 4171698.83099 872120.17939 4730014.34490 11.80799 48.17150 536.11579 -1.42757 -0.00598 11.52513 -0.86717 -1.32966 0.73227 8 0 8 2.00 -1999-Aug-27 09:09:32 4171701.98181 872119.91313 4730015.72577 11.80797 48.17149 539.16523 -2.33295 -1.34260 14.57457 -1.77255 -2.66629 3.78172 8 0 8 2.00 -1999-Aug-27 09:09:32 4171694.15948 872119.82836 4730013.69402 11.80799 48.17152 532.53337 -0.81522 3.02076 7.94271 -0.25483 1.69708 -2.85015 8 0 8 2.00 -1999-Aug-27 09:09:32 4171698.92632 872119.53374 4730014.11297 11.80798 48.17150 535.91709 -2.07906 -0.13174 11.32643 -1.51866 -1.45543 0.53358 8 0 8 2.00 -1999-Aug-27 09:09:32 4171698.76445 872120.87921 4730014.03623 11.80800 48.17150 535.93785 -0.72894 -0.27001 11.34720 -0.16854 -1.59370 0.55434 8 0 8 2.00 -1999-Aug-27 09:09:32 4171696.84013 872122.10972 4730015.42929 11.80802 48.17151 535.88764 0.86931 1.87495 11.29698 1.42970 0.55127 0.50413 8 0 8 2.00 -1999-Aug-27 09:09:32 4171694.69114 872121.20485 4730013.63208 11.80801 48.17152 533.02213 0.42334 2.38178 8.43147 0.98373 1.05810 -2.36139 8 0 8 2.00 -1999-Aug-27 09:09:32 4171693.53303 872121.67741 4730014.34000 11.80802 48.17153 532.85811 1.12288 3.62654 8.26745 1.68328 2.30285 -2.52540 8 0 8 2.00 -1999-Aug-27 09:09:32 4171693.42338 872120.81205 4730013.56786 11.80801 48.17153 532.09308 0.29827 3.32353 7.50242 0.85867 1.99984 -3.29044 8 0 8 2.00 -1999-Aug-27 09:09:32 4171697.62425 872121.90305 4730015.77275 11.80801 48.17151 536.62722 0.50656 1.56360 12.03657 1.06695 0.23992 1.24371 8 0 8 2.00 -1999-Aug-27 09:09:32 4171699.26241 872121.29853 4730015.65849 11.80800 48.17150 537.52896 -0.42039 0.38475 12.93831 0.14001 -0.93894 2.14545 8 0 8 2.00 -1999-Aug-27 09:09:32 4171697.72917 872119.77985 4730013.72279 11.80798 48.17150 534.87844 -1.59319 0.44370 10.28779 -1.03279 -0.87999 -0.50507 8 0 8 2.00 -1999-Aug-27 09:09:33 4171699.42492 872118.90979 4730012.88667 11.80797 48.17149 535.24365 -2.79184 -1.21809 10.65300 -2.23144 -2.54177 -0.13986 8 0 8 2.00 -1999-Aug-27 09:09:33 4171697.62183 872120.39743 4730015.52709 11.80799 48.17151 536.23712 -0.96671 1.63111 11.64647 -0.40632 0.30743 0.85361 8 0 8 2.00 -1999-Aug-27 09:09:33 4171699.40322 872121.44393 4730018.48316 11.80800 48.17152 539.74551 -0.30688 2.14365 15.15486 0.25352 0.81997 4.36200 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.50861 872119.38235 4730016.40788 11.80798 48.17153 536.02821 -1.73251 3.18525 11.43755 -1.17211 1.86156 0.64470 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.11959 872120.27620 4730014.58602 11.80800 48.17152 534.53869 -0.77796 2.11769 9.94804 -0.21757 0.79400 -0.84482 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.40658 872120.88844 4730013.44628 11.80800 48.17151 533.96032 -0.23741 1.05491 9.36966 0.32299 -0.26877 -1.42319 8 0 8 2.00 -1999-Aug-27 09:09:33 4171699.03437 872121.01847 4730014.50770 11.80800 48.17150 536.48437 -0.64786 -0.17369 11.89371 -0.08746 -1.49738 1.10086 8 0 8 2.00 -1999-Aug-27 09:09:33 4171698.43446 872119.72760 4730014.16714 11.80798 48.17150 535.66283 -1.78866 0.23358 11.07217 -1.22826 -1.09011 0.27932 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.15422 872119.94071 4730014.97729 11.80799 48.17152 534.80707 -1.11344 2.40453 10.21642 -0.55305 1.08084 -0.57644 8 0 8 2.00 -1999-Aug-27 09:09:33 4171698.66145 872119.94665 4730016.04554 11.80798 48.17151 537.24057 -1.62069 1.28733 12.64991 -1.06029 -0.03636 1.85706 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.09688 872119.97978 4730016.50487 11.80799 48.17153 535.91324 -1.06346 3.45914 11.32258 -0.50307 2.13546 0.52973 8 0 8 2.00 -1999-Aug-27 09:09:33 4171697.51299 872119.10364 4730016.67140 11.80798 48.17152 536.84218 -2.21085 2.67092 12.25152 -1.65046 1.34723 1.45866 8 0 8 2.00 -1999-Aug-27 09:09:33 4171698.41183 872119.91092 4730016.51625 11.80798 48.17151 537.42350 -1.60458 1.78876 12.83284 -1.04419 0.46508 2.03999 8 0 8 2.00 -1999-Aug-27 09:09:33 4171698.25962 872119.88862 4730014.19551 11.80798 48.17150 535.59180 -1.59526 0.35547 11.00115 -1.03486 -0.96821 0.20829 8 0 8 2.00 -1999-Aug-27 09:09:33 4171697.02705 872120.28396 4730012.93128 11.80799 48.17150 533.89911 -0.95607 0.35108 9.30846 -0.39567 -0.97260 -1.48440 8 0 8 2.00 -1999-Aug-27 09:09:33 4171695.25583 872120.07197 4730015.60515 11.80799 48.17153 534.70636 -0.80112 3.45850 10.11571 -0.24072 2.13482 -0.67715 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.28938 872121.51344 4730014.75455 11.80801 48.17151 534.94396 0.39835 1.91759 10.35330 0.95874 0.59390 -0.43955 8 0 8 2.00 -1999-Aug-27 09:09:33 4171695.16030 872120.62723 4730011.53066 11.80800 48.17150 531.68370 -0.23806 0.72622 7.09304 0.32234 -0.59746 -3.69982 8 0 8 2.00 -1999-Aug-27 09:09:33 4171695.02384 872120.64595 4730011.62648 11.80800 48.17151 531.66857 -0.19182 0.88680 7.07792 0.36858 -0.43688 -3.71494 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.91601 872120.80654 4730012.17926 11.80800 48.17150 533.33758 -0.42182 -0.14914 8.74692 0.13858 -1.47282 -2.04594 8 0 8 2.00 -1999-Aug-27 09:09:33 4171697.64558 872120.78756 4730015.07505 11.80800 48.17151 535.96903 -0.58970 1.25284 11.37837 -0.02930 -0.07085 0.58552 8 0 8 2.00 -1999-Aug-27 09:09:33 4171693.61085 872122.11651 4730014.53447 11.80803 48.17153 533.11374 1.53678 3.63252 8.52309 2.09717 2.30883 -2.26977 8 0 8 2.00 -1999-Aug-27 09:09:33 4171694.72678 872120.98541 4730013.18655 11.80801 48.17152 532.68346 0.20125 2.09212 8.09281 0.76165 0.76844 -2.70005 8 0 8 2.00 -1999-Aug-27 09:09:33 4171696.76980 872121.56196 4730014.40681 11.80801 48.17151 535.00507 0.34753 1.32788 10.41442 0.90793 0.00419 -0.37844 8 0 8 2.00 -1999-Aug-27 09:09:33 4171693.59671 872120.25449 4730013.51466 11.80800 48.17153 532.09050 -0.28296 3.24664 7.49985 0.27744 1.92295 -3.29301 8 0 8 2.00 -1999-Aug-27 09:09:34 4171699.28132 872120.50191 4730017.23875 11.80799 48.17151 538.61011 -1.20403 1.54630 14.01946 -0.64363 0.22262 3.22660 8 0 8 2.00 -1999-Aug-27 09:09:34 4171699.86172 872122.52524 4730018.26593 11.80801 48.17151 540.03051 0.65772 1.49948 15.43986 1.21812 0.17579 4.64700 8 0 8 2.00 -1999-Aug-27 09:09:34 4171701.12598 872120.55104 4730018.00306 11.80799 48.17150 540.39051 -1.53342 0.70308 15.79985 -0.97302 -0.62061 5.00700 8 0 8 2.00 -1999-Aug-27 09:09:34 4171708.37147 872121.90570 4730019.72723 11.80798 48.17146 546.58993 -1.69009 -3.63832 21.99927 -1.12969 -4.96200 11.20641 8 0 8 2.00 -1999-Aug-27 09:09:34 4171703.20144 872119.61693 4730019.04888 11.80797 48.17150 542.39717 -2.87247 0.02918 17.80651 -2.31207 -1.29450 7.01365 8 0 8 2.00 -1999-Aug-27 09:09:34 4171700.15044 872121.29836 4730016.95583 11.80800 48.17150 539.07533 -0.60228 0.60226 14.48468 -0.04188 -0.72143 3.69182 8 0 8 2.00 -1999-Aug-27 09:09:34 4171697.86516 872120.21669 4730011.43870 11.80799 48.17149 533.32486 -1.19342 -1.24537 8.73420 -0.63302 -2.56905 -2.05866 8 0 8 2.00 -1999-Aug-27 09:09:34 4171697.96791 872119.69143 4730013.95733 11.80798 48.17150 535.19699 -1.72859 0.43946 10.60634 -1.16820 -0.88422 -0.18652 8 0 8 2.00 -1999-Aug-27 09:09:34 4171698.80346 872121.07641 4730013.12718 11.80800 48.17149 535.31286 -0.54390 -0.93479 10.72220 0.01650 -2.25847 -0.07066 8 0 8 2.00 -1999-Aug-27 09:09:34 4171697.68479 872120.31293 4730015.46101 11.80799 48.17151 536.21745 -1.06230 1.55400 11.62680 -0.50191 0.23032 0.83394 8 0 8 2.00 -1999-Aug-27 09:09:34 4171698.08641 872121.24988 4730015.79887 11.80800 48.17151 536.85924 -0.22736 1.34353 12.26858 0.33303 0.01984 1.47572 8 0 8 2.00 -1999-Aug-27 09:09:34 4171696.75518 872120.52645 4730014.06298 11.80800 48.17151 534.59801 -0.66307 1.26714 10.00736 -0.10268 -0.05655 -0.78550 8 0 8 2.00 -1999-Aug-27 09:09:34 4171694.69008 872118.20352 4730012.43216 11.80797 48.17152 531.71773 -2.51426 2.03997 7.12707 -1.95386 0.71629 -3.66578 8 0 8 2.00 -1999-Aug-27 09:09:34 4171693.92961 872120.24470 4730013.62039 11.80800 48.17153 532.38526 -0.36065 3.07583 7.79461 0.19974 1.75215 -2.99825 8 0 8 2.00 -1999-Aug-27 09:09:34 4171693.22238 872120.36607 4730013.27242 11.80800 48.17153 531.68086 -0.09714 3.34110 7.09021 0.46326 2.01742 -3.70265 8 0 8 2.00 -1999-Aug-27 09:09:34 4171692.05442 872119.12393 4730014.20866 11.80799 48.17154 531.44655 -1.07399 5.00677 6.85590 -0.51359 3.68309 -3.93696 8 0 8 2.00 -1999-Aug-27 09:09:34 4171694.53114 872121.02153 4730015.22175 11.80801 48.17153 534.07719 0.27664 3.58659 9.48654 0.83703 2.26291 -1.30632 8 0 8 2.00 -1999-Aug-27 09:09:34 4171695.81222 872120.57806 4730015.25614 11.80800 48.17152 534.87858 -0.41960 2.74276 10.28792 0.14080 1.41908 -0.50493 8 0 8 2.00 -1999-Aug-27 09:09:34 4171698.06618 872121.46356 4730016.26816 11.80801 48.17151 537.22488 -0.01407 1.63867 12.63423 0.54633 0.31498 1.84137 8 0 8 2.00 -1999-Aug-27 09:09:34 4171699.01732 872119.70030 4730014.69030 11.80798 48.17150 536.42942 -1.93465 0.16151 11.83876 -1.37426 -1.16217 1.04591 8 0 8 2.00 -1999-Aug-27 09:09:34 4171699.82202 872121.16891 4730015.59563 11.80800 48.17150 537.82974 -0.66178 -0.04558 13.23909 -0.10139 -1.36927 2.44623 8 0 8 2.00 -1999-Aug-27 09:09:34 4171702.86784 872122.43685 4730017.59790 11.80801 48.17149 541.48304 -0.04395 -1.12515 16.89239 0.51645 -2.44883 6.09953 8 0 8 2.00 -1999-Aug-27 09:09:34 4171702.63297 872122.24502 4730015.66322 11.80800 48.17148 539.86193 -0.18366 -2.21483 15.27127 0.37674 -3.53852 4.47841 8 0 8 2.00 -1999-Aug-27 09:09:34 4171698.66254 872119.63600 4730012.37379 11.80798 48.17149 534.46291 -1.92499 -1.11480 9.87225 -1.36459 -2.43848 -0.92061 8 0 8 2.00 -1999-Aug-27 09:09:34 4171697.02897 872120.82942 4730013.20924 11.80800 48.17150 534.18193 -0.42254 0.45188 9.59128 0.13786 -0.87181 -1.20158 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.35413 872121.80375 4730013.32505 11.80801 48.17150 534.61345 0.46463 0.14338 10.02280 1.02502 -1.18031 -0.77006 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.44597 872120.61282 4730010.72912 11.80800 48.17149 531.92374 -0.51526 -0.74387 7.33308 0.04514 -2.06755 -3.45977 8 0 8 2.00 -1999-Aug-27 09:09:35 4171695.36594 872120.34733 4730010.99191 11.80800 48.17150 531.37829 -0.55412 0.25962 6.78763 0.00627 -1.06407 -4.00522 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.56324 872120.79878 4730013.25491 11.80800 48.17151 533.90775 -0.35723 0.82670 9.31709 0.20316 -0.49698 -1.47577 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.56720 872121.50942 4730014.70388 11.80801 48.17151 535.73980 0.13293 0.95240 11.14915 0.69332 -0.37128 0.35629 8 0 8 2.00 -1999-Aug-27 09:09:35 4171698.25006 872119.86835 4730015.70630 11.80798 48.17151 536.70856 -1.61315 1.37308 12.11790 -1.05275 0.04940 1.32504 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.47598 872118.83529 4730014.64227 11.80797 48.17151 535.26940 -2.46594 1.38560 10.67875 -1.90555 0.06191 -0.11411 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.04959 872118.55109 4730013.83247 11.80797 48.17151 534.34886 -2.65688 1.19987 9.75820 -2.09648 -0.12381 -1.03465 8 0 8 2.00 -1999-Aug-27 09:09:35 4171695.95069 872119.19402 4730015.53952 11.80798 48.17153 534.99125 -1.80269 3.04179 10.40059 -1.24229 1.71810 -0.39227 8 0 8 2.00 -1999-Aug-27 09:09:35 4171693.49292 872119.03925 4730013.07133 11.80799 48.17153 531.52655 -1.45124 3.21198 6.93590 -0.89084 1.88830 -3.85696 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.83615 872119.88164 4730015.95728 11.80799 48.17152 535.97439 -1.31081 2.56971 11.38374 -0.75041 1.24602 0.59088 8 0 8 2.00 -1999-Aug-27 09:09:35 4171699.58061 872121.46155 4730017.91961 11.80800 48.17151 539.44378 -0.32594 1.63574 14.85313 0.23446 0.31205 4.06027 8 0 8 2.00 -1999-Aug-27 09:09:35 4171699.45612 872122.39307 4730016.47007 11.80801 48.17150 538.40953 0.61135 0.61781 13.81887 1.17174 -0.70588 3.02602 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.32487 872121.59922 4730015.67403 11.80801 48.17151 536.31677 0.27042 1.76245 11.72611 0.83082 0.43877 0.93326 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.42957 872121.86201 4730016.07882 11.80801 48.17151 536.72260 0.50622 1.91597 12.13194 1.06662 0.59229 1.33908 8 0 8 2.00 -1999-Aug-27 09:09:35 4171700.22852 872122.23658 4730017.06909 11.80801 48.17150 539.33874 0.30011 0.47778 14.74809 0.86050 -0.84590 3.95523 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.45064 872119.53000 4730015.17631 11.80798 48.17152 535.09282 -1.57612 2.38368 10.50216 -1.01572 1.06000 -0.29070 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.00356 872120.28397 4730014.02726 11.80800 48.17151 534.04766 -0.74662 1.82850 9.45700 -0.18622 0.50481 -1.33586 8 0 8 2.00 -1999-Aug-27 09:09:35 4171694.99100 872120.59367 4730012.82991 11.80800 48.17151 532.53673 -0.23626 1.72129 7.94607 0.32413 0.39760 -2.84678 8 0 8 2.00 -1999-Aug-27 09:09:35 4171696.60258 872121.95214 4730014.89366 11.80802 48.17151 535.31193 0.76367 1.71503 10.72128 1.32407 0.39135 -0.07158 8 0 8 2.00 -1999-Aug-27 09:09:35 4171697.87955 872121.40642 4730013.75240 11.80801 48.17150 535.22065 -0.03181 0.10574 10.62999 0.52858 -1.21795 -0.16286 8 0 8 2.00 -1999-Aug-27 09:09:35 4171695.59892 872119.39685 4730013.44616 11.80799 48.17151 533.22944 -1.53216 1.87137 8.63878 -0.97177 0.54768 -2.15408 8 0 8 2.00 -1999-Aug-27 09:09:35 4171695.48999 872118.37937 4730014.52699 11.80797 48.17152 533.82485 -2.50582 2.82677 9.23420 -1.94543 1.50308 -1.55866 8 0 8 2.00 -1999-Aug-27 09:09:35 4171695.51946 872118.63294 4730012.25455 11.80798 48.17151 532.18540 -2.26364 1.25112 7.59474 -1.70325 -0.07257 -3.19811 8 0 8 2.00 -1999-Aug-27 09:09:35 4171692.90271 872117.84713 4730007.24512 11.80797 48.17150 526.63722 -2.49735 -0.06127 2.04657 -1.93696 -1.38496 -8.74629 8 0 8 2.00 -1999-Aug-27 09:09:36 4171691.49051 872117.25739 4730005.97369 11.80797 48.17150 524.68747 -2.78563 0.21076 0.09681 -2.22523 -1.11293 -10.69605 8 0 8 2.00 -1999-Aug-27 09:09:36 4171697.11850 872119.03844 4730011.99926 11.80798 48.17150 533.09434 -2.19394 -0.14727 8.50369 -1.63354 -1.47096 -2.28917 8 0 8 2.00 -1999-Aug-27 09:09:36 4171697.22326 872118.14427 4730016.65148 11.80796 48.17152 536.50728 -3.09063 3.01525 11.91662 -2.53023 1.69156 1.12377 8 0 8 2.00 -1999-Aug-27 09:09:36 4171694.39669 872118.54398 4730013.78273 11.80798 48.17153 532.57904 -2.12097 3.10274 7.98838 -1.56057 1.77906 -2.80447 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.58184 872119.94928 4730014.06818 11.80799 48.17152 533.75717 -0.98793 2.21442 9.16652 -0.42753 0.89073 -1.62634 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.00566 872120.37772 4730014.92336 11.80800 48.17153 534.07675 -0.45065 3.13966 9.48609 0.10975 1.81597 -1.30676 8 0 8 2.00 -1999-Aug-27 09:09:36 4171692.81014 872119.18421 4730010.99778 11.80799 48.17152 529.55553 -1.16963 2.30502 4.96488 -0.60923 0.98134 -5.82798 8 0 8 2.00 -1999-Aug-27 09:09:36 4171694.52287 872120.36450 4730010.80079 11.80800 48.17150 530.68787 -0.36479 0.74446 6.09722 0.19560 -0.57922 -4.69564 8 0 8 2.00 -1999-Aug-27 09:09:36 4171700.30752 872122.07606 4730015.60292 11.80801 48.17149 538.27590 0.12682 -0.53315 13.68524 0.68721 -1.85684 2.89238 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.65064 872121.76281 4730014.43641 11.80802 48.17152 534.32396 0.77315 2.13328 9.73331 1.33355 0.80959 -1.05955 8 0 8 2.00 -1999-Aug-27 09:09:36 4171696.32540 872121.31633 4730014.93405 11.80801 48.17152 535.07432 0.19803 2.04108 10.48367 0.75843 0.71740 -0.30919 8 0 8 2.00 -1999-Aug-27 09:09:36 4171694.08971 872119.52159 4730015.00622 11.80799 48.17153 533.42373 -1.10123 3.99353 8.83307 -0.54083 2.66985 -1.95978 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.52061 872120.24332 4730013.64967 11.80800 48.17152 533.44548 -0.68758 1.93513 8.85483 -0.12719 0.61144 -1.93803 8 0 8 2.00 -1999-Aug-27 09:09:36 4171696.71569 872121.29610 4730014.41147 11.80801 48.17151 534.93694 0.09837 1.41099 10.34629 0.65876 0.08730 -0.44657 8 0 8 2.00 -1999-Aug-27 09:09:36 4171702.27376 872122.19924 4730017.69220 11.80800 48.17149 541.13307 -0.15496 -0.59272 16.54242 0.40543 -1.91641 5.74956 8 0 8 2.00 -1999-Aug-27 09:09:36 4171698.50649 872119.52753 4730012.80096 11.80798 48.17149 534.66454 -1.99923 -0.69956 10.07388 -1.43884 -2.02324 -0.71898 8 0 8 2.00 -1999-Aug-27 09:09:36 4171699.07462 872121.56962 4730015.98739 11.80800 48.17150 537.68845 -0.11661 0.69972 13.09779 0.44379 -0.62396 2.30494 8 0 8 2.00 -1999-Aug-27 09:09:36 4171696.67511 872122.50627 4730012.84038 11.80802 48.17150 533.90491 1.29123 0.20830 9.31426 1.85163 -1.11539 -1.47860 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.56946 872120.59019 4730012.13965 11.80800 48.17151 532.39952 -0.35804 0.83957 7.80887 0.20235 -0.48411 -2.98399 8 0 8 2.00 -1999-Aug-27 09:09:36 4171699.98802 872121.31653 4730013.55023 11.80800 48.17148 536.43413 -0.55126 -1.55325 11.84347 0.00914 -2.87693 1.05062 8 0 8 2.00 -1999-Aug-27 09:09:36 4171697.80250 872121.74640 4730013.03644 11.80801 48.17149 534.68325 0.31674 -0.36738 10.09260 0.87714 -1.69106 -0.70026 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.93696 872121.90295 4730012.09481 11.80802 48.17150 532.78516 0.85173 0.34145 8.19451 1.41212 -0.98223 -2.59835 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.84480 872121.69328 4730012.81016 11.80801 48.17151 533.22943 0.66536 0.91771 8.63877 1.22576 -0.40597 -2.15408 8 0 8 2.00 -1999-Aug-27 09:09:36 4171695.04357 872120.42302 4730014.05958 11.80800 48.17152 533.46404 -0.41406 2.52904 8.87339 0.14633 1.20536 -1.91947 8 0 8 2.00 -1999-Aug-27 09:09:36 4171696.24344 872121.06228 4730015.90457 11.80801 48.17152 535.70933 -0.03386 2.78685 11.11867 0.52653 1.46316 0.32582 8 0 8 2.00 -1999-Aug-27 09:09:37 4171693.44263 872120.98042 4730016.16529 11.80801 48.17154 534.06409 0.45914 5.01605 9.47344 1.01954 3.69236 -1.31942 8 0 8 2.00 -1999-Aug-27 09:09:37 4171696.02366 872120.58354 4730015.12274 11.80800 48.17152 534.91794 -0.45750 2.49873 10.32729 0.10290 1.17505 -0.46557 8 0 8 2.00 -1999-Aug-27 09:09:37 4171694.70894 872119.55184 4730013.01137 11.80799 48.17152 532.34564 -1.19834 2.20690 7.75499 -0.63794 0.88321 -3.03787 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.88447 872119.98281 4730014.36359 11.80798 48.17150 536.13780 -1.63093 -0.00255 11.54715 -1.07053 -1.32624 0.75429 8 0 8 2.00 -1999-Aug-27 09:09:37 4171695.60032 872118.64288 4730010.78624 11.80798 48.17150 531.14543 -2.27047 0.21140 6.55478 -1.71007 -1.11228 -4.23808 8 0 8 2.00 -1999-Aug-27 09:09:37 4171694.08106 872121.09215 4730013.98530 11.80801 48.17153 532.87169 0.43786 3.07951 8.28103 0.99826 1.75582 -2.51183 8 0 8 2.00 -1999-Aug-27 09:09:37 4171691.22538 872120.25457 4730011.31036 11.80801 48.17153 528.90000 0.20237 3.50616 4.30935 0.76277 2.18248 -6.48351 8 0 8 2.00 -1999-Aug-27 09:09:37 4171691.54630 872119.61168 4730014.47011 11.80800 48.17155 531.37623 -0.49258 5.47737 6.78558 0.06782 4.15369 -4.00728 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.60869 872120.75929 4730018.34504 11.80799 48.17152 539.03049 -0.81445 2.73545 14.43984 -0.25405 1.41176 3.64698 8 0 8 2.00 -1999-Aug-27 09:09:37 4171697.69976 872120.98344 4730015.73357 11.80800 48.17151 536.52182 -0.40905 1.62262 11.93117 0.15135 0.29893 1.13831 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.39017 872122.76095 4730016.81731 11.80802 48.17151 538.02263 1.18957 1.57076 13.43198 1.74997 0.24708 2.63912 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.57029 872121.02755 4730018.49718 11.80800 48.17152 539.15540 -0.54401 2.82401 14.56475 0.01639 1.50033 3.77189 8 0 8 2.00 -1999-Aug-27 09:09:37 4171701.32647 872121.50722 4730019.29340 11.80800 48.17151 541.61337 -0.63849 1.27158 17.02271 -0.07810 -0.05211 6.22986 8 0 8 2.00 -1999-Aug-27 09:09:37 4171696.84721 872122.07441 4730016.42916 11.80802 48.17152 536.63249 0.83330 2.54198 12.04183 1.39370 1.21830 1.24898 8 0 8 2.00 -1999-Aug-27 09:09:37 4171695.87386 872122.40752 4730013.79443 11.80802 48.17151 534.07930 1.35853 1.44402 9.48864 1.91893 0.12034 -1.30422 8 0 8 2.00 -1999-Aug-27 09:09:37 4171696.67947 872122.63915 4730015.50826 11.80802 48.17152 535.91385 1.42042 1.96407 11.32320 1.98081 0.64039 0.53034 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.55431 872122.32682 4730014.70746 11.80802 48.17150 536.49839 0.73103 0.11017 11.90774 1.29143 -1.21351 1.11488 8 0 8 2.00 -1999-Aug-27 09:09:37 4171693.80849 872121.01035 4730011.17499 11.80801 48.17151 530.58851 0.41357 1.41658 5.99786 0.97397 0.09290 -4.79500 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.04244 872122.43226 4730012.95954 11.80802 48.17149 534.87619 0.93899 -0.69825 10.28553 1.49939 -2.02194 -0.50733 8 0 8 2.00 -1999-Aug-27 09:09:37 4171694.64738 872120.26629 4730008.96003 11.80800 48.17149 529.38412 -0.48640 -0.55899 4.79346 0.07399 -1.88268 -5.99940 8 0 8 2.00 -1999-Aug-27 09:09:37 4171697.85162 872123.05508 4730012.88843 11.80803 48.17149 534.78362 1.58768 -0.70146 10.19297 2.14808 -2.02515 -0.59989 8 0 8 2.00 -1999-Aug-27 09:09:37 4171700.61563 872123.27596 4730017.18426 11.80802 48.17150 539.81911 1.23828 0.11376 15.22845 1.79868 -1.20992 4.43559 8 0 8 2.00 -1999-Aug-27 09:09:37 4171698.43581 872121.05763 4730014.89759 11.80800 48.17150 536.38951 -0.48705 0.51693 11.79885 0.07334 -0.80676 1.00599 8 0 8 2.00 -1999-Aug-27 09:09:37 4171694.77402 872119.84318 4730015.80402 11.80799 48.17153 534.50881 -0.92648 3.97744 9.91815 -0.36608 2.65375 -0.87470 8 0 8 2.00 -1999-Aug-27 09:09:37 4171696.48262 872119.07398 4730013.67040 11.80798 48.17151 533.92934 -2.02903 1.42559 9.33869 -1.46864 0.10190 -1.45417 8 0 8 2.00 -1999-Aug-27 09:09:38 4171694.93509 872119.07012 4730015.93280 11.80798 48.17153 534.60441 -1.71614 4.06372 10.01375 -1.15574 2.74003 -0.77910 8 0 8 2.00 -1999-Aug-27 09:09:38 4171693.15885 872118.95806 4730014.34136 11.80799 48.17154 532.24376 -1.46235 4.31501 7.65310 -0.90195 2.99132 -3.13976 8 0 8 2.00 -1999-Aug-27 09:09:38 4171693.98307 872119.36781 4730014.46331 11.80799 48.17153 532.92859 -1.22994 3.73270 8.33794 -0.66954 2.40901 -2.45492 8 0 8 2.00 -1999-Aug-27 09:09:38 4171692.82103 872120.59896 4730015.13101 11.80801 48.17154 532.83557 0.21295 4.83783 8.24492 0.77335 3.51414 -2.54794 8 0 8 2.00 -1999-Aug-27 09:09:38 4171692.07555 872120.59957 4730012.61332 11.80801 48.17153 530.47297 0.36610 3.70241 5.88232 0.92650 2.37873 -4.91054 8 0 8 2.00 -1999-Aug-27 09:09:38 4171697.83623 872120.02916 4730011.72810 11.80799 48.17149 533.49603 -1.37106 -1.00267 8.90537 -0.81067 -2.32636 -1.88748 8 0 8 2.00 -1999-Aug-27 09:09:38 4171698.75223 872119.55535 4730012.51049 11.80798 48.17149 534.61231 -2.02229 -1.07676 10.02165 -1.46189 -2.40044 -0.77120 8 0 8 2.00 -1999-Aug-27 09:09:38 4171697.35350 872119.44372 4730012.59464 11.80798 48.17150 533.74670 -1.84532 0.01658 9.15605 -1.28493 -1.30710 -1.63681 8 0 8 2.00 -1999-Aug-27 09:09:38 4171696.89799 872120.30768 4730013.37937 11.80799 48.17150 534.15199 -0.90644 0.74043 9.56134 -0.34604 -0.58326 -1.23152 8 0 8 2.00 -1999-Aug-27 09:09:38 4171693.99146 872122.16907 4730011.68825 11.80803 48.17151 531.24853 1.51033 1.44874 6.65788 2.07073 0.12506 -4.13498 8 0 8 2.00 -1999-Aug-27 09:09:38 4171699.06929 872120.92377 4730013.77041 11.80800 48.17149 535.94486 -0.74771 -0.67642 11.35421 -0.18731 -2.00011 0.56135 8 0 8 2.00 -1999-Aug-27 09:09:38 4171698.09780 872120.89598 4730012.04552 11.80800 48.17149 534.02159 -0.57611 -1.11394 9.43094 -0.01571 -2.43762 -1.36192 8 0 8 2.00 -1999-Aug-27 09:09:38 4171697.62832 872120.08453 4730014.48188 11.80799 48.17151 535.41982 -1.27432 0.97703 10.82917 -0.71392 -0.34665 0.03631 8 0 8 2.00 -1999-Aug-27 09:09:38 4171698.37965 872120.21252 4730014.80919 11.80799 48.17150 536.17164 -1.30279 0.62780 11.58099 -0.74239 -0.69589 0.78813 8 0 8 2.00 -1999-Aug-27 09:09:38 4171700.21005 872120.77261 4730013.85652 11.80799 48.17148 536.73307 -1.12910 -1.42799 12.14242 -0.56870 -2.75167 1.34956 8 0 8 2.00 -1999-Aug-27 09:09:38 4171696.37267 872120.32939 4730013.50859 11.80800 48.17151 533.90832 -0.77769 1.20646 9.31766 -0.21730 -0.11723 -1.47520 8 0 8 2.00 -1999-Aug-27 09:09:38 4171695.67572 872118.84021 4730010.94539 11.80798 48.17150 531.34018 -2.09273 0.23245 6.74952 -1.53234 -1.09123 -4.04334 8 0 8 2.00 -1999-Aug-27 09:09:38 4171697.02986 872120.00599 4730015.83543 11.80799 48.17152 536.02703 -1.22873 2.32820 11.43637 -0.66833 1.00452 0.64352 8 0 8 2.00 -1999-Aug-27 09:09:38 4171697.45395 872119.42408 4730016.50221 11.80798 48.17152 536.72130 -1.88510 2.55228 12.13064 -1.32471 1.22860 1.33779 8 0 8 2.00 -1999-Aug-27 09:09:38 4171696.55617 872120.85156 4730014.43792 11.80800 48.17151 534.79185 -0.30412 1.61276 10.20120 0.25628 0.28907 -0.59166 8 0 8 2.00 -1999-Aug-27 09:09:38 4171694.89435 872120.71952 4730013.86291 11.80800 48.17152 533.26055 -0.09331 2.46151 8.66989 0.46709 1.13783 -2.12296 8 0 8 2.00 -1999-Aug-27 09:09:38 4171692.49716 872119.92798 4730011.62320 11.80800 48.17152 529.91875 -0.37755 2.83699 5.32810 0.18285 1.51331 -5.46476 8 0 8 2.00 -1999-Aug-27 09:09:38 4171698.75757 872120.40647 4730013.36202 11.80799 48.17149 535.36646 -1.19027 -0.64254 10.77581 -0.62987 -1.96623 -0.01705 8 0 8 2.00 -1999-Aug-27 09:09:38 4171693.40070 872121.00298 4730014.59494 11.80801 48.17153 532.86966 0.48981 3.99592 8.27900 1.05020 2.67223 -2.51386 8 0 8 2.00 -1999-Aug-27 09:09:38 4171698.66517 872121.52431 4730012.70301 11.80800 48.17149 534.96764 -0.07718 -1.18509 10.37698 0.48322 -2.50877 -0.41587 8 0 8 2.00 -1999-Aug-27 09:09:39 4171695.15203 872119.94455 4730011.12579 11.80799 48.17150 531.28345 -0.90461 0.56633 6.69279 -0.34421 -0.75735 -4.10007 8 0 8 2.00 -1999-Aug-27 09:09:39 4171692.91222 872119.42413 4730011.31360 11.80799 48.17152 529.89024 -0.95567 2.40461 5.29959 -0.39527 1.08092 -5.49327 8 0 8 2.00 -1999-Aug-27 09:09:39 4171691.15859 872120.87789 4730012.05457 11.80802 48.17153 529.49601 0.82617 3.95615 4.90536 1.38657 2.63247 -5.88750 8 0 8 2.00 -1999-Aug-27 09:09:39 4171694.41977 872121.57805 4730012.54706 11.80802 48.17151 532.08741 0.84417 1.79920 7.49675 1.40457 0.47552 -3.29610 8 0 8 2.00 -1999-Aug-27 09:09:39 4171695.59139 872120.43760 4730013.39115 11.80800 48.17151 533.32556 -0.51190 1.68148 8.73491 0.04850 0.35779 -2.05795 8 0 8 2.00 -1999-Aug-27 09:09:39 4171698.53769 872120.26984 4730013.58251 11.80799 48.17149 535.36858 -1.27901 -0.31429 10.77792 -0.71862 -1.63797 -0.01493 8 0 8 2.00 -1999-Aug-27 09:09:39 4171697.70969 872120.31103 4730014.25080 11.80799 48.17150 535.33166 -1.06926 0.72904 10.74100 -0.50886 -0.59465 -0.05185 8 0 8 2.00 -1999-Aug-27 09:09:39 4171697.38095 872120.39417 4730013.71053 11.80799 48.17150 534.72583 -0.92061 0.59583 10.13518 -0.36022 -0.72786 -0.65768 8 0 8 2.00 -1999-Aug-27 09:09:39 4171697.79485 872119.28249 4730013.74564 11.80798 48.17150 534.87047 -2.09346 0.48687 10.27982 -1.53307 -0.83682 -0.51304 8 0 8 2.00 -1999-Aug-27 09:09:39 4171698.91720 872120.86233 4730015.57009 11.80800 48.17150 537.17821 -0.77672 0.64409 12.58755 -0.21632 -0.67960 1.79470 8 0 8 2.00 -1999-Aug-27 09:09:39 4171701.18089 872121.54729 4730017.43251 11.80800 48.17150 540.13718 -0.56948 0.13061 15.54652 -0.00909 -1.19307 4.75366 8 0 8 2.00 -1999-Aug-27 09:09:39 4171699.74052 872120.27928 4730018.48044 11.80799 48.17152 539.80473 -1.51591 2.07340 15.21407 -0.95551 0.74972 4.42121 8 0 8 2.00 -1999-Aug-27 09:09:39 4171697.18499 872119.92802 4730015.13635 11.80799 48.17151 535.59673 -1.33680 1.76072 11.00608 -0.77640 0.43703 0.21322 8 0 8 2.00 -1999-Aug-27 09:09:39 4171698.09297 872120.62413 4730017.00237 11.80799 48.17152 537.67491 -0.84121 2.23678 13.08425 -0.28082 0.91309 2.29140 8 0 8 2.00 -1999-Aug-27 09:09:39 4171698.66033 872120.96833 4730017.92186 11.80800 48.17152 538.77741 -0.62041 2.38368 14.18675 -0.06001 1.06000 3.39390 8 0 8 2.00 -1999-Aug-27 09:09:39 4171695.45422 872120.14946 4730014.57213 11.80800 48.17152 534.07669 -0.76587 2.61306 9.48604 -0.20547 1.28938 -1.30682 8 0 8 2.00 -1999-Aug-27 09:09:39 4171693.42354 872120.62029 4730014.16050 11.80801 48.17153 532.50862 0.11054 3.74788 7.91797 0.67094 2.42419 -2.87489 8 0 8 2.00 -1999-Aug-27 09:09:39 4171693.89426 872121.81613 4730014.25517 11.80802 48.17153 533.04964 1.18475 3.28535 8.45898 1.74514 1.96166 -2.33387 8 0 8 2.00 -1999-Aug-27 09:09:39 4171699.41413 872124.10661 4730017.58392 11.80804 48.17151 539.44595 2.29721 1.12998 14.85529 2.85761 -0.19371 4.06243 8 0 8 2.00 -1999-Aug-27 09:09:39 4171700.18274 872122.32864 4730016.98796 11.80801 48.17150 539.26096 0.39959 0.44303 14.67031 0.95998 -0.88066 3.87745 8 0 8 2.00 -1999-Aug-27 09:09:39 4171700.09325 872121.95425 4730015.39756 11.80801 48.17149 537.96638 0.05143 -0.49525 13.37573 0.61182 -1.81894 2.58287 8 0 8 2.00 -1999-Aug-27 09:09:39 4171698.81576 872121.40443 4730015.00241 11.80800 48.17150 536.76297 -0.22534 0.25683 12.17231 0.33506 -1.06686 1.37945 8 0 8 2.00 -1999-Aug-27 09:09:39 4171699.28642 872120.20719 4730013.81204 11.80799 48.17149 536.01982 -1.49355 -0.69776 11.42917 -0.93315 -2.02145 0.63631 8 0 8 2.00 -1999-Aug-27 09:09:39 4171696.96069 872119.79952 4730011.42593 11.80799 48.17149 532.66798 -1.41668 -0.53058 8.07732 -0.85628 -1.85426 -2.71554 8 0 8 2.00 -1999-Aug-27 09:09:39 4171697.55229 872120.85111 4730011.75205 11.80800 48.17149 533.44069 -0.50840 -0.90494 8.85003 0.05200 -2.22862 -1.94283 8 0 8 2.00 -1999-Aug-27 09:09:40 4171695.29267 872118.67825 4730010.71330 11.80798 48.17150 530.89508 -2.17288 0.38176 6.30442 -1.61249 -0.94193 -4.48843 8 0 8 2.00 -1999-Aug-27 09:09:40 4171695.24319 872119.38763 4730012.20358 11.80799 48.17151 532.07006 -1.46839 1.30355 7.47941 -0.90799 -0.02014 -3.31345 8 0 8 2.00 -1999-Aug-27 09:09:40 4171694.72579 872118.38037 4730012.24280 11.80797 48.17151 531.62407 -2.34846 1.86067 7.03341 -1.78806 0.53699 -3.75944 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.67452 872119.33485 4730013.52711 11.80798 48.17150 534.63623 -2.01759 0.42091 10.04558 -1.45719 -0.90277 -0.74728 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.82608 872120.05972 4730012.91180 11.80799 48.17150 534.37559 -1.33907 -0.21051 9.78494 -0.77867 -1.53420 -1.00792 8 0 8 2.00 -1999-Aug-27 09:09:40 4171695.80533 872119.69099 4730014.86321 11.80799 48.17152 534.46023 -1.28648 2.62100 9.86957 -0.72609 1.29731 -0.92328 8 0 8 2.00 -1999-Aug-27 09:09:40 4171692.67895 872119.11809 4730011.72434 11.80799 48.17152 530.00226 -1.20750 2.89534 5.41161 -0.64710 1.57165 -5.38125 8 0 8 2.00 -1999-Aug-27 09:09:40 4171691.45664 872121.35897 4730013.68363 11.80802 48.17154 530.97012 1.23609 4.75183 6.37947 1.79648 3.42815 -4.41339 8 0 8 2.00 -1999-Aug-27 09:09:40 4171691.16821 872120.76859 4730011.61072 11.80802 48.17153 529.15664 0.71722 3.66979 4.56599 1.27762 2.34611 -6.22687 8 0 8 2.00 -1999-Aug-27 09:09:40 4171694.84555 872121.34840 4730012.36005 11.80801 48.17151 532.19466 0.53225 1.39895 7.60401 1.09265 0.07527 -3.18885 8 0 8 2.00 -1999-Aug-27 09:09:40 4171695.86518 872122.37059 4730013.40839 11.80802 48.17151 533.78094 1.32417 1.19853 9.19028 1.88456 -0.12515 -1.60257 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.45617 872121.03581 4730013.19940 11.80800 48.17150 534.48163 -0.30794 0.10226 9.89098 0.25246 -1.22142 -0.90188 8 0 8 2.00 -1999-Aug-27 09:09:40 4171698.48020 872121.60317 4730016.10076 11.80801 48.17151 537.38947 0.03786 1.20377 12.79881 0.59826 -0.11991 2.00595 8 0 8 2.00 -1999-Aug-27 09:09:40 4171700.74658 872122.11860 4730015.66166 11.80801 48.17149 538.61208 0.07861 -0.82071 14.02143 0.63901 -2.14439 3.22857 8 0 8 2.00 -1999-Aug-27 09:09:40 4171700.82095 872121.21961 4730016.15657 11.80799 48.17149 538.90673 -0.81658 -0.40781 14.31608 -0.25618 -1.73150 3.52322 8 0 8 2.00 -1999-Aug-27 09:09:40 4171699.66718 872122.36392 4730014.94434 11.80801 48.17149 537.40644 0.53962 -0.54921 12.81578 1.10002 -1.87289 2.02292 8 0 8 2.00 -1999-Aug-27 09:09:40 4171698.11038 872120.88128 4730012.24206 11.80800 48.17149 534.17425 -0.59307 -0.98979 9.58359 -0.03268 -2.31348 -1.20926 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.60006 872121.74786 4730012.09196 11.80801 48.17149 533.84753 0.35960 -0.84983 9.25688 0.91999 -2.17351 -1.53598 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.60014 872121.18845 4730014.26184 11.80800 48.17150 535.38812 -0.18799 0.68251 10.79746 0.37241 -0.64117 0.00460 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.91842 872121.73975 4730013.75973 11.80801 48.17150 535.29698 0.28651 0.03145 10.70632 0.84691 -1.29223 -0.08653 8 0 8 2.00 -1999-Aug-27 09:09:40 4171695.15522 872122.21755 4730015.22631 11.80802 48.17152 534.65120 1.31964 2.95207 10.06055 1.88004 1.62839 -0.73231 8 0 8 2.00 -1999-Aug-27 09:09:40 4171697.37458 872120.47847 4730014.81229 11.80799 48.17151 535.55415 -0.83679 1.32239 10.96349 -0.27639 -0.00130 0.17064 8 0 8 2.00 -1999-Aug-27 09:09:40 4171699.01698 872122.98577 4730013.90137 11.80802 48.17149 536.28969 1.28136 -0.86535 11.69904 1.84176 -2.18903 0.90618 8 0 8 2.00 -1999-Aug-27 09:09:40 4171698.97986 872121.44571 4730014.16573 11.80800 48.17149 536.25228 -0.21851 -0.42714 11.66162 0.34188 -1.75083 0.86876 8 0 8 2.00 -1999-Aug-27 09:09:40 4171694.18912 872120.61192 4730011.25548 11.80800 48.17151 530.84259 -0.05431 1.25339 6.25193 0.50608 -0.07030 -4.54093 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.15714 872121.60191 4730014.40438 11.80801 48.17151 535.26157 0.30738 1.03765 10.67091 0.86777 -0.28604 -0.12194 8 0 8 2.00 -1999-Aug-27 09:09:41 4171700.23085 872123.47530 4730018.63114 11.80803 48.17151 540.67326 1.51214 1.32894 16.08261 2.07254 0.00526 5.28975 8 0 8 2.00 -1999-Aug-27 09:09:41 4171699.59723 872122.87076 4730017.97253 11.80802 48.17151 539.68638 1.05005 1.44404 15.09573 1.61044 0.12035 4.30287 8 0 8 2.00 -1999-Aug-27 09:09:41 4171698.65007 872121.55394 4730015.03897 11.80801 48.17150 536.70246 -0.04508 0.37926 12.11181 0.51531 -0.94442 1.31895 8 0 8 2.00 -1999-Aug-27 09:09:41 4171701.61508 872120.26873 4730015.52614 11.80798 48.17149 538.82561 -1.90984 -1.26248 14.23495 -1.34944 -2.58616 3.44209 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.30997 872120.60706 4730013.70212 11.80800 48.17150 534.70228 -0.69770 0.60953 10.11163 -0.13730 -0.71415 -0.68123 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.72924 872120.32060 4730014.46824 11.80799 48.17151 535.50775 -1.06390 0.85834 10.91710 -0.50350 -0.46535 0.12424 8 0 8 2.00 -1999-Aug-27 09:09:41 4171696.97215 872118.37119 4730016.35866 11.80797 48.17152 536.15613 -2.81713 2.96852 11.56548 -2.25673 1.64483 0.77262 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.03364 872119.39636 4730015.43828 11.80798 48.17152 535.65036 -1.82623 2.15354 11.05971 -1.26583 0.82985 0.26685 8 0 8 2.00 -1999-Aug-27 09:09:41 4171695.27896 872120.73886 4730018.24424 11.80800 48.17154 536.77898 -0.15308 5.09995 12.18832 0.40731 3.77627 1.39547 8 0 8 2.00 -1999-Aug-27 09:09:41 4171692.97992 872119.35118 4730014.80335 11.80799 48.17154 532.52485 -1.04093 4.69367 7.93419 -0.48054 3.36999 -2.85866 8 0 8 2.00 -1999-Aug-27 09:09:41 4171692.78364 872120.66451 4730014.54407 11.80801 48.17154 532.38275 0.28477 4.46367 7.79210 0.84517 3.13999 -3.00076 8 0 8 2.00 -1999-Aug-27 09:09:41 4171693.71699 872120.52385 4730014.08167 11.80801 48.17153 532.62828 -0.04391 3.49598 8.03763 0.51649 2.17230 -2.75523 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.27466 872122.78262 4730014.37126 11.80802 48.17150 535.47473 1.43905 0.74981 10.88408 1.99945 -0.57388 0.09122 8 0 8 2.00 -1999-Aug-27 09:09:41 4171692.98978 872121.83057 4730011.10906 11.80802 48.17151 530.11687 1.38397 1.84469 5.52621 1.94437 0.52100 -5.26664 8 0 8 2.00 -1999-Aug-27 09:09:41 4171694.65876 872120.61319 4730010.27301 11.80800 48.17150 530.41725 -0.14917 0.25544 5.82659 0.41123 -1.06824 -4.96626 8 0 8 2.00 -1999-Aug-27 09:09:41 4171695.18119 872120.98903 4730010.73617 11.80801 48.17150 531.15470 0.11181 0.12597 6.56404 0.67220 -1.19772 -4.22881 8 0 8 2.00 -1999-Aug-27 09:09:41 4171696.43156 872118.89827 4730013.28241 11.80798 48.17151 533.58292 -2.19058 1.23088 8.99226 -1.63018 -0.09281 -1.80060 8 0 8 2.00 -1999-Aug-27 09:09:41 4171698.44302 872120.09438 4730013.71737 11.80799 48.17150 535.38332 -1.43139 -0.12854 10.79267 -0.87099 -1.45223 -0.00019 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.89623 872120.56540 4730014.62135 11.80799 48.17150 535.76426 -0.85845 0.80132 11.17360 -0.29805 -0.52237 0.38075 8 0 8 2.00 -1999-Aug-27 09:09:41 4171700.53650 872119.58913 4730014.18655 11.80797 48.17149 537.03058 -2.35434 -1.26554 12.43992 -1.79395 -2.58922 1.64707 8 0 8 2.00 -1999-Aug-27 09:09:41 4171697.10785 872120.46373 4730016.27228 11.80799 48.17152 536.46592 -0.79664 2.49286 11.87527 -0.23624 1.16917 1.08241 8 0 8 2.00 -1999-Aug-27 09:09:41 4171696.72246 872121.25712 4730017.58308 11.80801 48.17153 537.29935 0.05883 3.52715 12.70870 0.61923 2.20346 1.91584 8 0 8 2.00 -1999-Aug-27 09:09:41 4171696.54422 872120.37505 4730017.40870 11.80800 48.17153 536.93268 -0.76810 3.67536 12.34203 -0.20771 2.35168 1.54917 8 0 8 2.00 -1999-Aug-27 09:09:41 4171696.85513 872120.19941 4730014.86649 11.80799 48.17151 535.21736 -1.00365 1.77996 10.62671 -0.44325 0.45628 -0.16615 8 0 8 2.00 -1999-Aug-27 09:09:42 4171697.36181 872118.39137 4730014.55079 11.80797 48.17151 535.06613 -2.87711 1.47555 10.47548 -2.31671 0.15187 -0.31738 8 0 8 2.00 -1999-Aug-27 09:09:42 4171700.29486 872119.08585 4730016.15221 11.80797 48.17150 538.26886 -2.79752 0.29835 13.67821 -2.23713 -1.02533 2.88535 8 0 8 2.00 -1999-Aug-27 09:09:42 4171695.78933 872120.46729 4730017.56443 11.80800 48.17154 536.56853 -0.52334 4.31575 11.97787 0.03706 2.99206 1.18501 8 0 8 2.00 -1999-Aug-27 09:09:42 4171696.17197 872120.84306 4730013.57114 11.80800 48.17151 533.89401 -0.23382 1.31623 9.30336 0.32657 -0.00746 -1.48950 8 0 8 2.00 -1999-Aug-27 09:09:42 4171699.61109 872120.96823 4730015.46169 11.80799 48.17150 537.56485 -0.81505 0.04954 12.97420 -0.25465 -1.27414 2.18134 8 0 8 2.00 -1999-Aug-27 09:09:42 4171697.76346 872119.98697 4730014.17450 11.80799 48.17150 535.26569 -1.39747 0.68835 10.67503 -0.83707 -0.63534 -0.11783 8 0 8 2.00 -1999-Aug-27 09:09:42 4171696.89494 872120.19906 4730015.53561 11.80799 48.17152 535.74189 -1.01214 2.19721 11.15123 -0.45174 0.87353 0.35838 8 0 8 2.00 -1999-Aug-27 09:09:42 4171695.81978 872120.13971 4730012.97252 11.80799 48.17151 533.12206 -0.85022 1.28113 8.53141 -0.28982 -0.04255 -2.26145 8 0 8 2.00 -1999-Aug-27 09:09:42 4171695.33620 872120.60644 4730014.72257 11.80800 48.17152 534.17412 -0.29441 2.72979 9.58347 0.26599 1.40611 -1.20939 8 0 8 2.00 -1999-Aug-27 09:09:42 4171697.47775 872120.60978 4730014.41898 11.80800 48.17151 535.34634 -0.72937 0.96482 10.75568 -0.16897 -0.35886 -0.03717 8 0 8 2.00 -1999-Aug-27 09:09:42 4171694.40429 872120.32412 4730012.28650 11.80800 48.17151 531.71203 -0.38005 1.82793 7.12137 0.18034 0.50424 -3.67148 8 0 8 2.00 -1999-Aug-27 09:09:42 4171694.16059 872120.54094 4730013.42581 11.80800 48.17152 532.43148 -0.11795 2.73242 7.84082 0.44244 1.40874 -2.95203 8 0 8 2.00 -1999-Aug-27 09:09:42 4171695.09491 872121.20464 4730014.25094 11.80801 48.17152 533.74681 0.34051 2.50003 9.15616 0.90091 1.17635 -1.63670 8 0 8 2.00 -1999-Aug-27 09:09:42 4171696.53188 872120.87809 4730012.84100 11.80800 48.17150 533.58967 -0.27318 0.56144 8.99902 0.28721 -0.76224 -1.79384 8 0 8 2.00 -1999-Aug-27 09:09:42 4171692.26677 872119.67148 4730009.25792 11.80800 48.17151 527.97088 -0.58148 1.46673 3.38023 -0.02108 0.14304 -7.41263 8 0 8 2.00 -1999-Aug-27 09:09:42 4171694.33169 872121.20333 4730013.59550 11.80801 48.17152 532.76001 0.49541 2.61980 8.16936 1.05581 1.29611 -2.62350 8 0 8 2.00 -1999-Aug-27 09:09:42 4171695.44890 872119.90931 4730011.23702 11.80799 48.17150 531.55531 -0.99985 0.42937 6.96466 -0.43945 -0.89432 -3.82820 8 0 8 2.00 -1999-Aug-27 09:09:42 4171697.73081 872119.89397 4730014.03555 11.80799 48.17150 535.12814 -1.48181 0.63368 10.53748 -0.92142 -0.69001 -0.25537 8 0 8 2.00 -1999-Aug-27 09:09:42 4171696.98295 872118.64507 4730017.03042 11.80797 48.17153 536.70112 -2.55126 3.36688 12.11046 -1.99086 2.04319 1.31760 8 0 8 2.00 -1999-Aug-27 09:09:42 4171699.30286 872117.80808 4730014.86369 11.80795 48.17150 536.48678 -3.84525 0.35741 11.89612 -3.28486 -0.96628 1.10326 8 0 8 2.00 -1999-Aug-27 09:09:42 4171701.19840 872119.03803 4730014.54529 11.80796 48.17148 537.65477 -3.02923 -1.42504 13.06412 -2.46883 -2.74873 2.27126 8 0 8 2.00 -1999-Aug-27 09:09:42 4171696.85464 872118.25789 4730015.04906 11.80797 48.17152 535.08812 -2.90398 2.19812 10.49747 -2.34358 0.87444 -0.29539 8 0 8 2.00 -1999-Aug-27 09:09:42 4171693.75820 872120.79611 4730013.82056 11.80801 48.17153 532.49777 0.21416 3.25027 7.90712 0.77455 1.92659 -2.88574 8 0 8 2.00 -1999-Aug-27 09:09:42 4171698.08504 872120.14797 4730013.75417 11.80799 48.17150 535.18438 -1.30567 0.14893 10.59372 -0.74528 -1.17476 -0.19913 8 0 8 2.00 -1999-Aug-27 09:09:42 4171697.28623 872120.46076 4730015.77416 11.80799 48.17152 536.21079 -0.83605 2.03101 11.62013 -0.27565 0.70732 0.82728 8 0 8 2.00 -1999-Aug-27 09:09:43 4171694.90418 872119.59313 4730016.13852 11.80799 48.17153 534.80891 -1.19787 4.14371 10.21825 -0.63747 2.82002 -0.57461 8 0 8 2.00 -1999-Aug-27 09:09:43 4171695.13206 872119.77124 4730013.35911 11.80799 48.17152 532.91091 -1.07016 2.09674 8.32025 -0.50976 0.77305 -2.47260 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.16571 872119.67096 4730016.35857 11.80798 48.17152 536.45980 -1.58447 2.62908 11.86915 -1.02408 1.30540 1.07629 8 0 8 2.00 -1999-Aug-27 09:09:43 4171699.18934 872120.57076 4730020.42699 11.80799 48.17153 540.93516 -1.11781 3.72913 16.34450 -0.55742 2.40545 5.55165 8 0 8 2.00 -1999-Aug-27 09:09:43 4171698.40631 872121.04109 4730016.66561 11.80800 48.17151 537.68542 -0.49720 1.72007 13.09477 0.06320 0.39638 2.30191 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.09965 872121.75081 4730016.22639 11.80801 48.17152 536.60202 0.46489 2.27198 12.01137 1.02529 0.94829 1.21851 8 0 8 2.00 -1999-Aug-27 09:09:43 4171696.06521 872122.54206 4730014.89379 11.80803 48.17152 535.04175 1.45108 2.01711 10.45109 2.01147 0.69343 -0.34176 8 0 8 2.00 -1999-Aug-27 09:09:43 4171691.94580 872120.91463 4730010.15318 11.80802 48.17152 528.59810 0.70105 2.10833 4.00745 1.26144 0.78465 -6.78541 8 0 8 2.00 -1999-Aug-27 09:09:43 4171695.93370 872120.36779 4730011.31158 11.80800 48.17150 531.98991 -0.65028 0.05558 7.39926 -0.08988 -1.26810 -3.39360 8 0 8 2.00 -1999-Aug-27 09:09:43 4171696.30528 872120.33452 4730012.07169 11.80800 48.17150 532.79433 -0.75888 0.29655 8.20368 -0.19848 -1.02714 -2.58918 8 0 8 2.00 -1999-Aug-27 09:09:43 4171693.65256 872119.78578 4730011.38595 11.80800 48.17151 530.47679 -0.75318 1.85773 5.88614 -0.19278 0.53404 -4.90672 8 0 8 2.00 -1999-Aug-27 09:09:43 4171694.42287 872120.92124 4730011.78981 11.80801 48.17151 531.43554 0.20062 1.39208 6.84489 0.76102 0.06840 -3.94797 8 0 8 2.00 -1999-Aug-27 09:09:43 4171696.60174 872121.72687 4730014.02268 11.80801 48.17151 534.63164 0.54334 1.16913 10.04098 1.10374 -0.15455 -0.75187 8 0 8 2.00 -1999-Aug-27 09:09:43 4171693.45936 872121.25458 4730013.20758 11.80802 48.17152 531.90850 0.72408 2.98953 7.31785 1.28447 1.66585 -3.47501 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.21918 872120.93450 4730015.08153 11.80800 48.17151 535.71556 -0.35861 1.54576 11.12490 0.20179 0.22207 0.33204 8 0 8 2.00 -1999-Aug-27 09:09:43 4171699.70612 872120.97369 4730016.30520 11.80799 48.17150 538.25617 -0.82916 0.54194 13.66551 -0.26877 -0.78175 2.87266 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.02645 872119.64872 4730014.70587 11.80798 48.17151 535.13435 -1.57775 1.63186 10.54369 -1.01735 0.30817 -0.24916 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.43101 872120.36149 4730015.65495 11.80799 48.17151 536.20292 -0.96284 1.86105 11.61227 -0.40245 0.53736 0.81941 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.65205 872120.19559 4730014.62481 11.80799 48.17151 535.55697 -1.17046 1.03812 10.96631 -0.61007 -0.28557 0.17346 8 0 8 2.00 -1999-Aug-27 09:09:43 4171697.43022 872119.32991 4730013.03915 11.80798 48.17150 534.11248 -1.97243 0.27442 9.52182 -1.41204 -1.04926 -1.27103 8 0 8 2.00 -1999-Aug-27 09:09:43 4171699.35400 872122.87431 4730015.32937 11.80802 48.17150 537.55855 1.10330 -0.14183 12.96790 1.66370 -1.46552 2.17504 8 0 8 2.00 -1999-Aug-27 09:09:43 4171699.09081 872121.87906 4730015.75238 11.80801 48.17150 537.56612 0.18297 0.48399 12.97547 0.74336 -0.83969 2.18261 8 0 8 2.00 -1999-Aug-27 09:09:43 4171696.97064 872121.97089 4730013.05812 11.80802 48.17150 534.18702 0.70671 0.21959 9.59637 1.26711 -1.10410 -1.19649 8 0 8 2.00 -1999-Aug-27 09:09:43 4171691.76096 872120.49415 4730010.54077 11.80801 48.17152 528.70887 0.32729 2.56575 4.11822 0.88769 1.24206 -6.67464 8 0 8 2.00 -1999-Aug-27 09:09:43 4171694.40816 872120.57044 4730015.12435 11.80800 48.17153 533.86277 -0.13974 3.68012 9.27212 0.42066 2.35644 -1.52074 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.06843 872120.29562 4730018.88993 11.80799 48.17152 539.67335 -1.36238 2.83421 15.08269 -0.80199 1.51052 4.28984 8 0 8 2.00 -1999-Aug-27 09:09:44 4171698.37365 872120.56215 4730017.82042 11.80799 48.17152 538.45924 -0.95933 2.58707 13.86858 -0.39893 1.26338 3.07573 8 0 8 2.00 -1999-Aug-27 09:09:44 4171701.47020 872123.13160 4730020.47978 11.80802 48.17151 542.81290 0.92210 1.71026 18.22224 1.48249 0.38657 7.42939 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.29855 872122.01117 4730017.12211 11.80801 48.17151 538.74041 0.26977 1.22581 14.14976 0.83017 -0.09787 3.35690 8 0 8 2.00 -1999-Aug-27 09:09:44 4171702.56294 872121.88352 4730018.06390 11.80800 48.17149 541.55573 -0.52318 -0.50760 16.96507 0.03721 -1.83129 6.17221 8 0 8 2.00 -1999-Aug-27 09:09:44 4171704.68765 872122.90472 4730017.94736 11.80801 48.17148 542.99524 0.04162 -2.29076 18.40459 0.60202 -3.61445 7.61173 8 0 8 2.00 -1999-Aug-27 09:09:44 4171702.83030 872121.20817 4730017.33164 11.80799 48.17149 541.09245 -1.23895 -1.08798 16.50180 -0.67855 -2.41167 5.70894 8 0 8 2.00 -1999-Aug-27 09:09:44 4171701.68100 872121.80029 4730017.50136 11.80800 48.17150 540.54947 -0.42417 -0.22681 15.95882 0.13623 -1.55050 5.16596 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.47589 872120.18938 4730018.56309 11.80798 48.17152 539.68129 -1.54976 2.33525 15.09064 -0.98936 1.01156 4.29778 8 0 8 2.00 -1999-Aug-27 09:09:44 4171701.41488 872121.11101 4730017.12194 11.80799 48.17150 539.99896 -1.04441 -0.18065 15.40831 -0.48402 -1.50434 4.61545 8 0 8 2.00 -1999-Aug-27 09:09:44 4171698.91621 872121.45153 4730016.78209 11.80800 48.17151 538.16109 -0.19979 1.36326 13.57043 0.36061 0.03957 2.77758 8 0 8 2.00 -1999-Aug-27 09:09:44 4171696.42893 872122.07185 4730016.33541 11.80802 48.17152 536.28923 0.91639 2.78494 11.69857 1.47679 1.46126 0.90572 8 0 8 2.00 -1999-Aug-27 09:09:44 4171694.12929 872121.94016 4730014.87283 11.80802 48.17153 533.68024 1.25806 3.50692 9.08959 1.81846 2.18323 -1.70327 8 0 8 2.00 -1999-Aug-27 09:09:44 4171694.98531 872121.97854 4730014.82167 11.80802 48.17152 534.20615 1.12046 2.84259 9.61550 1.68086 1.51891 -1.17736 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.38040 872123.51326 4730018.79199 11.80803 48.17152 540.24313 1.72333 2.05072 15.65248 2.28373 0.72703 4.85962 8 0 8 2.00 -1999-Aug-27 09:09:44 4171701.19544 872122.96775 4730018.29576 11.80802 48.17150 540.98376 0.81794 0.47912 16.39311 1.37834 -0.84457 5.60025 8 0 8 2.00 -1999-Aug-27 09:09:44 4171701.04734 872122.46032 4730017.28098 11.80801 48.17150 540.06168 0.35156 -0.01224 15.47103 0.91196 -1.33593 4.67817 8 0 8 2.00 -1999-Aug-27 09:09:44 4171697.30626 872119.66767 4730015.12546 11.80798 48.17151 535.63225 -1.61646 1.70471 11.04160 -1.05606 0.38102 0.24874 8 0 8 2.00 -1999-Aug-27 09:09:44 4171696.58641 872120.45964 4730015.83831 11.80800 48.17152 535.80160 -0.69393 2.58439 11.21094 -0.13354 1.26070 0.41808 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.06365 872122.05055 4730013.29856 11.80801 48.17149 535.74335 0.35639 -1.15880 11.15270 0.91678 -2.48249 0.35984 8 0 8 2.00 -1999-Aug-27 09:09:44 4171698.47305 872121.47685 4730012.28886 11.80800 48.17149 534.52715 -0.08432 -1.31392 9.93649 0.47608 -2.63761 -0.85636 8 0 8 2.00 -1999-Aug-27 09:09:44 4171700.71606 872123.14928 4730013.23811 11.80802 48.17147 536.92693 1.09373 -2.57188 12.33627 1.65412 -3.89556 1.54342 8 0 8 2.00 -1999-Aug-27 09:09:44 4171699.04219 872122.27915 4730012.47326 11.80801 48.17148 535.14557 0.58454 -1.72840 10.55491 1.14494 -3.05209 -0.23794 8 0 8 2.00 -1999-Aug-27 09:09:44 4171698.24141 872121.46138 4730015.72522 11.80800 48.17151 536.93440 -0.05206 1.14911 12.34375 0.50834 -0.17458 1.55089 8 0 8 2.00 -1999-Aug-27 09:09:44 4171697.49344 872120.87994 4730016.53134 11.80800 48.17152 536.96747 -0.46814 2.32092 12.37681 0.09226 0.99723 1.58396 8 0 8 2.00 -1999-Aug-27 09:09:45 4171699.18831 872120.17549 4730015.08552 11.80799 48.17150 536.90038 -1.50451 0.22792 12.30972 -0.94411 -1.09577 1.51686 8 0 8 2.00 -1999-Aug-27 09:09:45 4171704.46175 872122.36491 4730019.01793 11.80800 48.17149 543.57184 -0.44054 -1.32971 18.98118 0.11986 -2.65340 8.18833 8 0 8 2.00 -1999-Aug-27 09:09:45 4171701.72981 872120.24864 4730016.43186 11.80798 48.17149 539.57265 -1.95298 -0.73907 14.98200 -1.39258 -2.06276 4.18914 8 0 8 2.00 -1999-Aug-27 09:09:45 4171697.81022 872118.62691 4730012.58844 11.80797 48.17150 533.92875 -2.73831 -0.19612 9.33810 -2.17792 -1.51980 -1.45476 8 0 8 2.00 -1999-Aug-27 09:09:45 4171699.80723 872119.88539 4730015.50479 11.80798 48.17150 537.57723 -1.91511 0.10034 12.98658 -1.35472 -1.22335 2.19372 8 0 8 2.00 -1999-Aug-27 09:09:45 4171696.82076 872119.03727 4730013.47561 11.80798 48.17151 533.99992 -2.13416 1.05465 9.40926 -1.57376 -0.26904 -1.38359 8 0 8 2.00 -1999-Aug-27 09:09:45 4171697.46345 872121.56220 4730015.32490 11.80801 48.17151 536.14203 0.20582 1.43419 11.55137 0.76622 0.11050 0.75852 8 0 8 2.00 -1999-Aug-27 09:09:45 4171694.11260 872120.23086 4730013.93035 11.80800 48.17153 532.73379 -0.41165 3.15119 8.14313 0.14875 1.82750 -2.64972 8 0 8 2.00 -1999-Aug-27 09:09:45 4171696.16397 872121.93282 4730016.21624 11.80802 48.17152 536.00849 0.83451 2.91992 11.41784 1.39491 1.59623 0.62498 8 0 8 2.00 -1999-Aug-27 09:09:45 4171697.53226 872121.09103 4730016.18361 11.80800 48.17152 536.76251 -0.26946 2.02852 12.17186 0.29094 0.70483 1.37900 8 0 8 2.00 -1999-Aug-27 09:09:45 4171697.90088 872119.82757 4730015.35138 11.80798 48.17151 536.21058 -1.58162 1.39729 11.61993 -1.02122 0.07360 0.82707 8 0 8 2.00 -1999-Aug-27 09:09:45 4171693.52498 872120.84335 4730015.38593 11.80801 48.17154 533.51840 0.30813 4.45712 8.92775 0.86852 3.13343 -1.86511 8 0 8 2.00 -1999-Aug-27 09:09:45 4171699.05497 872119.19116 4730014.74349 11.80797 48.17150 536.42414 -2.44072 0.24716 11.83349 -1.88032 -1.07653 1.04063 8 0 8 2.00 -1999-Aug-27 09:09:45 4171696.27166 872120.70632 4730015.52805 11.80800 48.17152 535.39861 -0.38807 2.56943 10.80796 0.17233 1.24575 0.01510 8 0 8 2.00 -1999-Aug-27 09:09:45 4171698.72052 872121.41552 4730015.58134 11.80800 48.17150 537.13369 -0.19499 0.71069 12.54304 0.36540 -0.61299 1.75018 8 0 8 2.00 -1999-Aug-27 09:09:45 4171699.72092 872119.54123 4730017.03135 11.80798 48.17151 538.61143 -2.23433 1.23383 14.02078 -1.67394 -0.08985 3.22792 8 0 8 2.00 -1999-Aug-27 09:09:45 4171698.28179 872118.67400 4730016.30588 11.80797 48.17152 537.01305 -2.78872 1.93192 12.42239 -2.22833 0.60823 1.62953 8 0 8 2.00 -1999-Aug-27 09:09:45 4171696.62529 872120.23990 4730015.59155 11.80799 48.17152 535.61312 -0.91698 2.42497 11.02247 -0.35659 1.10129 0.22961 8 0 8 2.00 -1999-Aug-27 09:09:45 4171695.16861 872119.86765 4730010.69115 11.80799 48.17150 530.95990 -0.98327 0.27611 6.36925 -0.42287 -1.04758 -4.42361 8 0 8 2.00 -1999-Aug-27 09:09:45 4171699.00666 872121.15480 4730014.91196 11.80800 48.17150 536.78612 -0.50875 0.09534 12.19547 0.05165 -1.22835 1.40261 8 0 8 2.00 -1999-Aug-27 09:09:45 4171698.73384 872121.76362 4730016.54584 11.80801 48.17151 537.90859 0.14302 1.29113 13.31793 0.70341 -0.03255 2.52507 8 0 8 2.00 -1999-Aug-27 09:09:45 4171703.25851 872122.89099 4730017.88546 11.80801 48.17149 542.01432 0.32064 -1.28757 17.42366 0.88104 -2.61125 6.63081 8 0 8 2.00 -1999-Aug-27 09:09:45 4171698.81633 872122.43844 4730014.93906 11.80802 48.17150 536.85724 0.78667 0.05649 12.26659 1.34707 -1.26719 1.47373 8 0 8 2.00 -1999-Aug-27 09:09:45 4171698.94009 872119.86354 4730015.85412 11.80798 48.17151 537.26849 -1.75907 0.96910 12.67783 -1.19867 -0.35458 1.88498 8 0 8 2.00 -1999-Aug-27 09:09:45 4171701.15538 872122.56765 4730019.56439 11.80801 48.17151 541.84833 0.43450 1.41540 17.25767 0.99490 0.09171 6.46482 8 0 8 2.00 -1999-Aug-27 09:09:46 4171701.68031 872122.94086 4730021.07828 11.80801 48.17152 543.37000 0.69240 1.98524 18.77934 1.25280 0.66155 7.98648 8 0 8 2.00 -1999-Aug-27 09:09:46 4171701.39892 872124.24117 4730019.56615 11.80803 48.17151 542.23701 2.02278 0.98376 17.64636 2.58317 -0.33993 6.85350 8 0 8 2.00 -1999-Aug-27 09:09:46 4171696.99921 872120.13765 4730013.75659 11.80799 48.17151 534.47595 -1.09358 0.94409 9.88530 -0.53318 -0.37959 -0.90756 8 0 8 2.00 -1999-Aug-27 09:09:46 4171696.75308 872120.21404 4730013.80959 11.80799 48.17151 534.36520 -0.96845 1.14731 9.77454 -0.40805 -0.17637 -1.01831 8 0 8 2.00 -1999-Aug-27 09:09:46 4171695.58049 872120.50575 4730013.18151 11.80800 48.17151 533.17153 -0.44296 1.53923 8.58088 0.11744 0.21554 -2.21198 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.66598 872120.63455 4730015.09356 11.80800 48.17151 535.97526 -0.74364 1.27363 11.38460 -0.18324 -0.05006 0.59174 8 0 8 2.00 -1999-Aug-27 09:09:46 4171699.37208 872119.76836 4730016.07145 11.80798 48.17150 537.69944 -1.94063 0.81348 13.10879 -1.38023 -0.51021 2.31593 8 0 8 2.00 -1999-Aug-27 09:09:46 4171702.60860 872120.54463 4730017.82704 11.80798 48.17149 541.22632 -1.84309 -0.49472 16.63566 -1.28269 -1.81841 5.84281 8 0 8 2.00 -1999-Aug-27 09:09:46 4171698.15320 872119.74798 4730016.63325 11.80798 48.17152 537.31961 -1.71115 2.08028 12.72896 -1.15075 0.75659 1.93610 8 0 8 2.00 -1999-Aug-27 09:09:46 4171695.80354 872121.03971 4730013.61087 11.80801 48.17151 533.70995 0.03406 1.58146 9.11929 0.59445 0.25778 -1.67356 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.41529 872120.94586 4730011.73169 11.80800 48.17149 533.34901 -0.38762 -0.83304 8.75836 0.17277 -2.15672 -2.03450 8 0 8 2.00 -1999-Aug-27 09:09:46 4171698.94488 872121.23758 4730014.49183 11.80800 48.17150 536.44403 -0.41508 -0.15241 11.85337 0.14532 -1.47610 1.06052 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.59621 872121.91489 4730014.12868 11.80801 48.17150 535.38546 0.52389 0.48581 10.79481 1.08428 -0.83787 0.00195 8 0 8 2.00 -1999-Aug-27 09:09:46 4171695.53847 872121.58187 4730014.81530 11.80801 48.17152 534.50837 0.61899 2.49537 9.91772 1.17939 1.17168 -0.87514 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.46972 872120.87346 4730016.66034 11.80800 48.17152 537.04722 -0.46962 2.42524 12.45657 0.09077 1.10155 1.66371 8 0 8 2.00 -1999-Aug-27 09:09:46 4171693.80967 872120.40914 4730015.51110 11.80800 48.17154 533.73826 -0.17516 4.39917 9.14761 0.38524 3.07548 -1.64525 8 0 8 2.00 -1999-Aug-27 09:09:46 4171692.89894 872120.43015 4730015.04162 11.80801 48.17154 532.79679 0.03177 4.74712 8.20613 0.59217 3.42344 -2.58673 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.23779 872120.68836 4730015.01526 11.80800 48.17151 535.64473 -0.60335 1.52552 11.05408 -0.04296 0.20183 0.26122 8 0 8 2.00 -1999-Aug-27 09:09:46 4171695.08164 872118.59333 4730009.80918 11.80798 48.17150 530.07203 -2.21283 -0.05434 5.48137 -1.65243 -1.37802 -5.31148 8 0 8 2.00 -1999-Aug-27 09:09:46 4171698.12805 872120.28739 4730012.56566 11.80799 48.17149 534.34586 -1.17801 -0.69632 9.75521 -0.61762 -2.02000 -1.03765 8 0 8 2.00 -1999-Aug-27 09:09:46 4171699.31309 872120.61188 4730016.26125 11.80799 48.17151 537.91748 -1.10288 0.85446 13.32682 -0.54248 -0.46922 2.53396 8 0 8 2.00 -1999-Aug-27 09:09:46 4171700.52951 872122.43808 4730014.90380 11.80801 48.17149 537.94928 0.43575 -1.21652 13.35862 0.99615 -2.54020 2.56576 8 0 8 2.00 -1999-Aug-27 09:09:46 4171702.46530 872121.46955 4730015.96240 11.80799 48.17148 539.86958 -0.90841 -1.77477 15.27892 -0.34801 -3.09845 4.48606 8 0 8 2.00 -1999-Aug-27 09:09:46 4171701.48111 872120.31638 4730015.77507 11.80798 48.17149 538.93014 -1.83578 -1.00601 14.33949 -1.27538 -2.32970 3.54663 8 0 8 2.00 -1999-Aug-27 09:09:46 4171697.04983 872119.32552 4730013.62044 11.80798 48.17151 534.29671 -1.89889 0.94021 9.70606 -1.33849 -0.38348 -1.08680 8 0 8 2.00 -1999-Aug-27 09:09:47 4171693.39212 872118.26803 4730012.21691 11.80798 48.17152 530.71884 -2.18552 2.83329 6.12819 -1.62512 1.50960 -4.66467 8 0 8 2.00 -1999-Aug-27 09:09:47 4171696.50159 872119.96726 4730015.15385 11.80799 48.17152 535.16901 -1.15854 2.26486 10.57835 -0.59815 0.94118 -0.21450 8 0 8 2.00 -1999-Aug-27 09:09:47 4171696.39982 872119.26228 4730016.09353 11.80798 48.17153 535.70657 -1.82778 3.07326 11.11591 -1.26738 1.74958 0.32306 8 0 8 2.00 -1999-Aug-27 09:09:47 4171696.30165 872120.01182 4730015.18970 11.80799 48.17152 535.07129 -1.07400 2.42781 10.48063 -0.51361 1.10412 -0.31223 8 0 8 2.00 -1999-Aug-27 09:09:47 4171697.59902 872120.38681 4730014.63843 11.80799 48.17151 535.55860 -0.97244 1.05672 10.96795 -0.41204 -0.26697 0.17509 8 0 8 2.00 -1999-Aug-27 09:09:47 4171693.88640 872119.29736 4730012.08050 11.80799 48.17152 531.08033 -1.27911 2.22484 6.48967 -0.71871 0.90116 -4.30318 8 0 8 2.00 -1999-Aug-27 09:09:47 4171698.02314 872119.12096 4730013.90452 11.80797 48.17150 535.11584 -2.29829 0.45094 10.52518 -1.73789 -0.87274 -0.26768 8 0 8 2.00 -1999-Aug-27 09:09:47 4171703.09006 872120.32763 4730015.06462 11.80798 48.17147 539.45260 -2.15401 -2.65507 14.86194 -1.59362 -3.97875 4.06908 8 0 8 2.00 -1999-Aug-27 09:09:47 4171699.85682 872120.86545 4730015.72944 11.80799 48.17150 537.91075 -0.96595 0.06454 13.32009 -0.40555 -1.25914 2.52724 8 0 8 2.00 -1999-Aug-27 09:09:47 4171700.59110 872121.95550 4730015.33521 11.80800 48.17149 538.24508 -0.04922 -0.90014 13.65443 0.51118 -2.22383 2.86157 8 0 8 2.00 -1999-Aug-27 09:09:47 4171700.52317 872121.92729 4730016.67951 11.80800 48.17150 539.19858 -0.06293 0.05023 14.60793 0.49746 -1.27346 3.81507 8 0 8 2.00 -1999-Aug-27 09:09:47 4171703.54971 872124.01203 4730019.50536 11.80802 48.17149 543.56446 1.35837 -0.59058 18.97381 1.91876 -1.91427 8.18095 8 0 8 2.00 -1999-Aug-27 09:09:47 4171703.39844 872123.18357 4730016.96111 11.80801 48.17148 541.45681 0.57838 -2.05069 16.86616 1.13878 -3.37438 6.07330 8 0 8 2.00 -1999-Aug-27 09:09:47 4171699.26239 872123.45521 4730015.23582 11.80803 48.17150 537.50832 1.69065 -0.22598 12.91766 2.25105 -1.54966 2.12481 8 0 8 2.00 -1999-Aug-27 09:09:47 4171698.44764 872122.50948 4730014.65877 11.80802 48.17150 536.41741 0.93166 0.12765 11.82676 1.49205 -1.19603 1.03390 8 0 8 2.00 -1999-Aug-27 09:09:47 4171697.00072 872120.81062 4730015.89677 11.80800 48.17152 536.16352 -0.43516 2.26767 11.57286 0.12523 0.94399 0.78001 8 0 8 2.00 -1999-Aug-27 09:09:47 4171695.85051 872120.24647 4730013.65841 11.80800 48.17151 533.66778 -0.75201 1.69986 9.07712 -0.19161 0.37617 -1.71573 8 0 8 2.00 -1999-Aug-27 09:09:47 4171696.10124 872119.92189 4730014.01141 11.80799 48.17151 534.05019 -1.12102 1.80190 9.45954 -0.56063 0.47821 -1.33332 8 0 8 2.00 -1999-Aug-27 09:09:47 4171698.37700 872120.38939 4730016.31107 11.80799 48.17151 537.31317 -1.12911 1.60437 12.72251 -0.56871 0.28069 1.92966 8 0 8 2.00 -1999-Aug-27 09:09:47 4171698.75589 872121.90718 4730016.98626 11.80801 48.17151 538.27075 0.27903 1.54687 13.68010 0.83942 0.22318 2.88724 8 0 8 2.00 -1999-Aug-27 09:09:47 4171700.26448 872122.60285 4730018.15516 11.80801 48.17151 540.22148 0.65127 1.12001 15.63083 1.21167 -0.20368 4.83797 8 0 8 2.00 -1999-Aug-27 09:09:47 4171700.20644 872121.73939 4730017.56083 11.80800 48.17151 539.62290 -0.18205 0.89765 15.03224 0.37835 -0.42604 4.23939 8 0 8 2.00 -1999-Aug-27 09:09:47 4171698.85392 872120.49649 4730016.15512 11.80799 48.17151 537.52291 -1.12187 1.13619 12.93225 -0.56147 -0.18750 2.13939 8 0 8 2.00 -1999-Aug-27 09:09:47 4171692.54528 872120.05363 4730012.07594 11.80800 48.17153 530.30467 -0.26440 3.08467 5.71401 0.29600 1.76098 -5.07884 8 0 8 2.00 -1999-Aug-27 09:09:47 4171692.81701 872120.65564 4730012.03679 11.80801 48.17152 530.53504 0.26927 2.76857 5.94438 0.82966 1.44489 -4.84847 8 0 8 2.00 -1999-Aug-27 09:09:48 4171692.34585 872120.69000 4730013.10348 11.80801 48.17153 531.02700 0.39931 3.81836 6.43634 0.95971 2.49467 -4.35651 8 0 8 2.00 -1999-Aug-27 09:09:48 4171693.17136 872120.08749 4730010.89196 11.80800 48.17151 529.83575 -0.35938 1.83325 5.24510 0.20101 0.50957 -5.54776 8 0 8 2.00 -1999-Aug-27 09:09:48 4171696.89069 872119.83396 4730014.71300 11.80799 48.17151 535.07633 -1.36864 1.70739 10.48567 -0.80824 0.38370 -0.30718 8 0 8 2.00 -1999-Aug-27 09:09:48 4171697.43848 872122.22212 4730018.09870 11.80802 48.17153 538.28267 0.85688 3.20162 13.69201 1.41728 1.87794 2.89916 8 0 8 2.00 -1999-Aug-27 09:09:48 4171695.70438 872120.10322 4730015.44187 11.80799 48.17152 534.88178 -0.86233 3.01768 10.29112 -0.30193 1.69400 -0.50174 8 0 8 2.00 -1999-Aug-27 09:09:48 4171695.07286 872120.78931 4730014.85072 11.80800 48.17152 534.12265 -0.06152 2.97944 9.53200 0.49887 1.65576 -1.26086 8 0 8 2.00 -1999-Aug-27 09:09:48 4171692.24402 872118.97366 4730008.80821 11.80799 48.17151 527.52570 -1.25988 1.28981 2.93505 -0.69948 -0.03387 -7.85781 8 0 8 2.00 -1999-Aug-27 09:09:48 4171692.00807 872119.70585 4730011.48778 11.80800 48.17153 529.46825 -0.49489 3.13728 4.87760 0.06550 1.81359 -5.91526 8 0 8 2.00 -1999-Aug-27 09:09:48 4171694.40315 872120.56424 4730010.76085 11.80800 48.17150 530.60723 -0.14478 0.77468 6.01657 0.41562 -0.54900 -4.77629 8 0 8 2.00 -1999-Aug-27 09:09:48 4171696.64634 872119.57362 4730012.24942 11.80798 48.17150 533.04557 -1.57347 0.28234 8.45492 -1.01307 -1.04135 -2.33794 8 0 8 2.00 -1999-Aug-27 09:09:48 4171699.33930 872121.22358 4730014.54619 11.80800 48.17149 536.74010 -0.50949 -0.40171 12.14944 0.05090 -1.72539 1.35659 8 0 8 2.00 -1999-Aug-27 09:09:48 4171701.05397 872120.99469 4730016.20892 11.80799 48.17149 539.06716 -1.08442 -0.50856 14.47651 -0.52402 -1.83225 3.68365 8 0 8 2.00 -1999-Aug-27 09:09:48 4171700.97163 872121.24429 4730015.32153 11.80799 48.17149 538.38624 -0.82324 -1.07837 13.79558 -0.26285 -2.40205 3.00273 8 0 8 2.00 -1999-Aug-27 09:09:48 4171699.58707 872119.75490 4730017.86644 11.80798 48.17151 539.17548 -1.99780 1.85581 14.58482 -1.43740 0.53212 3.79197 8 0 8 2.00 -1999-Aug-27 09:09:48 4171700.20093 872120.34760 4730017.04549 11.80798 48.17150 539.04535 -1.54326 0.77020 14.45470 -0.98286 -0.55349 3.66184 8 0 8 2.00 -1999-Aug-27 09:09:48 4171698.90964 872119.13461 4730015.19794 11.80797 48.17150 536.66019 -2.46633 0.66485 12.06953 -1.90594 -0.65883 1.27667 8 0 8 2.00 -1999-Aug-27 09:09:48 4171694.76704 872120.30830 4730014.11786 11.80800 48.17152 533.31129 -0.46977 2.78709 8.72064 0.09063 1.46341 -2.07222 8 0 8 2.00 -1999-Aug-27 09:09:48 4171693.94766 872121.02047 4730014.42168 11.80801 48.17153 533.09999 0.39500 3.47876 8.50934 0.95540 2.15508 -2.28352 8 0 8 2.00 -1999-Aug-27 09:09:48 4171695.44767 872123.38205 4730018.21088 11.80804 48.17154 537.22497 2.39966 4.55163 12.63431 2.96006 3.22794 1.84146 8 0 8 2.00 -1999-Aug-27 09:09:48 4171697.14426 872124.28247 4730015.94800 11.80805 48.17151 536.76920 2.93385 1.66775 12.17854 3.49424 0.34406 1.38569 8 0 8 2.00 -1999-Aug-27 09:09:48 4171697.95950 872121.38226 4730014.19699 11.80800 48.17150 535.60083 -0.07182 0.34761 11.01018 0.48858 -0.97608 0.21732 8 0 8 2.00 -1999-Aug-27 09:09:48 4171697.15445 872121.15556 4730013.71186 11.80800 48.17150 534.68287 -0.12898 0.64582 10.09221 0.43142 -0.67786 -0.70064 8 0 8 2.00 -1999-Aug-27 09:09:48 4171696.41619 872119.96715 4730015.21261 11.80799 48.17152 535.15703 -1.14117 2.36636 10.56638 -0.58077 1.04267 -0.22648 8 0 8 2.00 -1999-Aug-27 09:09:48 4171699.98465 872120.25053 4730014.02060 11.80798 48.17149 536.63695 -1.59401 -1.07456 12.04629 -1.03361 -2.39825 1.25343 8 0 8 2.00 -1999-Aug-27 09:09:48 4171696.53809 872119.16140 4730010.95459 11.80798 48.17149 531.95380 -1.95481 -0.43938 7.36315 -1.39441 -1.76306 -3.42971 8 0 8 2.00 -1999-Aug-27 09:09:49 4171698.21589 872120.63006 4730013.44774 11.80799 48.17150 535.10725 -0.86057 -0.22437 10.51659 -0.30017 -1.54806 -0.27626 8 0 8 2.00 -1999-Aug-27 09:09:49 4171700.16306 872120.57705 4730016.04850 11.80799 48.17150 538.30905 -1.31091 0.09794 13.71839 -0.75051 -1.22574 2.92553 8 0 8 2.00 -1999-Aug-27 09:09:49 4171699.25356 872119.72042 4730015.75642 11.80798 48.17150 537.38079 -1.96330 0.69714 12.79014 -1.40290 -0.62654 1.99728 8 0 8 2.00 -1999-Aug-27 09:09:49 4171696.61861 872118.83876 4730015.60215 11.80797 48.17152 535.42544 -2.28710 2.65056 10.83479 -1.72670 1.32688 0.04193 8 0 8 2.00 -1999-Aug-27 09:09:49 4171698.53630 872122.04610 4730016.93435 11.80801 48.17151 538.10768 0.45994 1.65123 13.51703 1.02034 0.32754 2.72417 8 0 8 2.00 -1999-Aug-27 09:09:49 4171697.06156 872121.20830 4730014.54500 11.80800 48.17151 535.25024 -0.05835 1.26116 10.65959 0.50204 -0.06252 -0.13327 8 0 8 2.00 -1999-Aug-27 09:09:49 4171699.05235 872122.14843 4730017.06118 11.80801 48.17151 538.55303 0.45451 1.34382 13.96237 1.01490 0.02013 3.16951 8 0 8 2.00 -1999-Aug-27 09:09:49 4171701.39029 872121.03000 4730015.57490 11.80799 48.17149 538.81908 -1.11868 -1.18209 14.22843 -0.55828 -2.50577 3.43557 8 0 8 2.00 -1999-Aug-27 09:09:49 4171703.40345 872122.75532 4730018.38870 11.80801 48.17149 542.46540 0.15818 -1.03698 17.87475 0.71858 -2.36066 7.08189 8 0 8 2.00 -1999-Aug-27 09:09:49 4171701.87405 872122.03830 4730015.66548 11.80800 48.17148 539.33998 -0.23071 -1.62827 14.74932 0.32969 -2.95195 3.95647 8 0 8 2.00 -1999-Aug-27 09:09:49 4171698.74167 872120.58419 4730016.71836 11.80799 48.17151 537.88129 -1.01306 1.58031 13.29064 -0.45266 0.25663 2.49778 8 0 8 2.00 -1999-Aug-27 09:09:49 4171697.85404 872118.80103 4730014.58622 11.80797 48.17151 535.46976 -2.57685 1.07769 10.87911 -2.01645 -0.24599 0.08625 8 0 8 2.00 -1999-Aug-27 09:09:49 4171693.88898 872121.47559 4730012.31102 11.80802 48.17152 531.55105 0.85249 2.04456 6.96039 1.41289 0.72087 -3.83247 8 0 8 2.00 -1999-Aug-27 09:09:49 4171692.73549 872122.13360 4730013.69224 11.80803 48.17153 531.91707 1.73262 3.70669 7.32641 2.29302 2.38300 -3.46645 8 0 8 2.00 -1999-Aug-27 09:09:49 4171694.74505 872121.15787 4730014.22837 11.80801 48.17152 533.49523 0.36633 2.74730 8.90457 0.92672 1.42361 -1.88828 8 0 8 2.00 -1999-Aug-27 09:09:49 4171694.12421 872121.61855 4730013.26923 11.80802 48.17152 532.43812 0.94429 2.49023 7.84746 1.50469 1.16654 -2.94539 8 0 8 2.00 -1999-Aug-27 09:09:49 4171691.91409 872118.56063 4730010.82041 11.80798 48.17152 528.75333 -1.59665 2.93538 4.16268 -1.03625 1.61170 -6.63018 8 0 8 2.00 -1999-Aug-27 09:09:49 4171692.34124 872119.63168 4730012.07041 11.80800 48.17153 530.10977 -0.63567 3.29414 5.51911 -0.07527 1.97045 -5.27375 8 0 8 2.00 -1999-Aug-27 09:09:49 4171693.95044 872118.92806 4730011.36352 11.80798 48.17151 530.53748 -1.65370 1.75629 5.94683 -1.09331 0.43261 -4.84603 8 0 8 2.00 -1999-Aug-27 09:09:49 4171698.77478 872123.61826 4730017.23896 11.80803 48.17151 538.70489 1.95004 1.44072 14.11424 2.51043 0.11703 3.32138 8 0 8 2.00 -1999-Aug-27 09:09:49 4171696.31690 872121.93855 4730014.79278 11.80802 48.17151 535.04842 0.80883 1.85819 10.45776 1.36923 0.53451 -0.33509 8 0 8 2.00 -1999-Aug-27 09:09:49 4171699.93122 872122.13353 4730014.69305 11.80801 48.17149 537.36011 0.26008 -0.87425 12.76946 0.82048 -2.19794 1.97660 8 0 8 2.00 -1999-Aug-27 09:09:49 4171692.71934 872119.44921 4730010.43797 11.80799 48.17152 529.11529 -0.89166 1.95751 4.52463 -0.33126 0.63382 -6.26822 8 0 8 2.00 -1999-Aug-27 09:09:49 4171694.34623 872120.27288 4730012.52534 11.80800 48.17152 531.84511 -0.41833 2.03737 7.25445 0.14207 0.71369 -3.53841 8 0 8 2.00 -1999-Aug-27 09:09:49 4171698.31933 872121.58324 4730015.96913 11.80801 48.17151 537.18365 0.05127 1.23636 12.59299 0.61167 -0.08733 1.80014 8 0 8 2.00 -1999-Aug-27 09:09:50 4171702.84287 872121.41183 4730016.87196 11.80799 48.17148 540.78592 -1.04217 -1.43477 16.19527 -0.48177 -2.75846 5.40241 8 0 8 2.00 -1999-Aug-27 09:09:50 4171702.01651 872120.77607 4730015.78666 11.80799 48.17148 539.35102 -1.49537 -1.45889 14.76036 -0.93498 -2.78258 3.96750 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.96665 872121.42282 4730014.00941 11.80801 48.17150 535.47126 -0.03358 0.21111 10.88061 0.52682 -1.11258 0.08775 8 0 8 2.00 -1999-Aug-27 09:09:50 4171698.06741 872123.27025 4730014.87056 11.80803 48.17150 536.43084 1.75413 0.43023 11.84018 2.31453 -0.89346 1.04732 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.47715 872122.11285 4730014.55863 11.80802 48.17151 535.65513 0.74202 0.82920 11.06447 1.30241 -0.49449 0.27162 8 0 8 2.00 -1999-Aug-27 09:09:50 4171695.93099 872121.53096 4730013.84107 11.80801 48.17151 534.03172 0.48884 1.56712 9.44106 1.04923 0.24343 -1.35179 8 0 8 2.00 -1999-Aug-27 09:09:50 4171698.33345 872121.06300 4730016.19552 11.80800 48.17151 537.29057 -0.46085 1.45637 12.69991 0.09955 0.13268 1.90706 8 0 8 2.00 -1999-Aug-27 09:09:50 4171698.99778 872119.04693 4730014.73850 11.80797 48.17150 536.36341 -2.57019 0.30753 11.77275 -2.00980 -1.01615 0.97990 8 0 8 2.00 -1999-Aug-27 09:09:50 4171700.49335 872120.52372 4730016.15343 11.80799 48.17150 538.59557 -1.43070 -0.06486 14.00492 -0.87031 -1.38854 3.21206 8 0 8 2.00 -1999-Aug-27 09:09:50 4171698.95491 872119.42953 4730014.64769 11.80798 48.17150 536.31997 -2.18692 0.21990 11.72931 -1.62652 -1.10378 0.93646 8 0 8 2.00 -1999-Aug-27 09:09:50 4171694.91363 872119.32794 4730011.01302 11.80799 48.17150 530.95964 -1.45938 0.75904 6.36899 -0.89899 -0.56465 -4.42387 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.82660 872120.73732 4730015.03615 11.80800 48.17151 536.05135 -0.67591 1.10252 11.46070 -0.11552 -0.22117 0.66784 8 0 8 2.00 -1999-Aug-27 09:09:50 4171694.91545 872119.66285 4730015.21448 11.80799 48.17153 534.13723 -1.13193 3.50861 9.54657 -0.57153 2.18492 -1.24628 8 0 8 2.00 -1999-Aug-27 09:09:50 4171696.86850 872120.26149 4730015.84651 11.80799 48.17152 535.96481 -0.94562 2.41432 11.37416 -0.38522 1.09064 0.58130 8 0 8 2.00 -1999-Aug-27 09:09:50 4171696.36160 872121.23412 4730014.59953 11.80801 48.17151 534.83747 0.11016 1.80412 10.24682 0.67055 0.48044 -0.54604 8 0 8 2.00 -1999-Aug-27 09:09:50 4171701.56924 872120.98524 4730016.67753 11.80799 48.17149 539.75141 -1.19911 -0.57044 15.16076 -0.63871 -1.89412 4.36790 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.96372 872120.36959 4730014.86898 11.80799 48.17151 535.96612 -1.06392 0.94709 11.37546 -0.50353 -0.37659 0.58261 8 0 8 2.00 -1999-Aug-27 09:09:50 4171695.67864 872120.24905 4730015.51454 11.80800 48.17153 534.93902 -0.71431 3.06268 10.34836 -0.15392 1.73900 -0.44449 8 0 8 2.00 -1999-Aug-27 09:09:50 4171695.61797 872119.66446 4730012.14034 11.80799 48.17151 532.30537 -1.27411 0.94581 7.71471 -0.71372 -0.37788 -3.07814 8 0 8 2.00 -1999-Aug-27 09:09:50 4171694.70504 872120.00385 4730015.66271 11.80800 48.17153 534.38041 -0.75509 3.90900 9.78976 -0.19469 2.58532 -1.00310 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.96362 872117.63495 4730013.26957 11.80796 48.17150 534.40106 -3.74068 0.29750 9.81040 -3.18028 -1.02619 -0.98246 8 0 8 2.00 -1999-Aug-27 09:09:50 4171695.31041 872119.53022 4730015.41819 11.80799 48.17153 534.52875 -1.34258 3.37662 9.93810 -0.78218 2.05293 -0.85476 8 0 8 2.00 -1999-Aug-27 09:09:50 4171697.58165 872120.93185 4730014.07771 11.80800 48.17150 535.20383 -0.43538 0.61233 10.61317 0.12502 -0.71135 -0.17969 8 0 8 2.00 -1999-Aug-27 09:09:50 4171696.51831 872120.99038 4730016.69091 11.80800 48.17153 536.46489 -0.16049 3.12174 11.87423 0.39990 1.79805 1.08138 8 0 8 2.00 -1999-Aug-27 09:09:50 4171693.97586 872119.92486 4730014.49029 11.80800 48.17153 533.02001 -0.68320 3.67101 8.42935 -0.12280 2.34732 -2.36350 8 0 8 2.00 -1999-Aug-27 09:09:51 4171698.83160 872120.75418 4730016.64600 11.80799 48.17151 537.90928 -0.86506 1.44054 13.31863 -0.30467 0.11686 2.52577 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.18843 872119.27186 4730016.09547 11.80798 48.17153 535.57133 -1.77514 3.22728 10.98067 -1.21475 1.90360 0.18781 8 0 8 2.00 -1999-Aug-27 09:09:51 4171697.89322 872120.01620 4730016.28941 11.80799 48.17152 536.93029 -1.39541 1.99969 12.33964 -0.83501 0.67600 1.54678 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.38829 872121.01874 4730015.74659 11.80800 48.17152 535.68023 -0.10612 2.58247 11.08957 0.45427 1.25879 0.29672 8 0 8 2.00 -1999-Aug-27 09:09:51 4171700.25159 872121.10186 4730018.51246 11.80799 48.17151 540.27446 -0.81532 1.59657 15.68381 -0.25493 0.27288 4.89095 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.90037 872120.36655 4730016.36339 11.80799 48.17152 536.38510 -0.84930 2.71977 11.79445 -0.28890 1.39608 1.00159 8 0 8 2.00 -1999-Aug-27 09:09:51 4171701.64901 872119.70392 4730014.45594 11.80797 48.17148 537.97323 -2.46964 -1.91482 13.38257 -1.90924 -3.23851 2.58971 8 0 8 2.00 -1999-Aug-27 09:09:51 4171700.20246 872120.82816 4730016.33308 11.80799 48.17150 538.58109 -1.07318 0.22070 13.99043 -0.51278 -1.10299 3.19758 8 0 8 2.00 -1999-Aug-27 09:09:51 4171702.14608 872122.16969 4730017.91153 11.80800 48.17149 541.20912 -0.15776 -0.34881 16.61847 0.40263 -1.67250 5.82561 8 0 8 2.00 -1999-Aug-27 09:09:51 4171702.41600 872123.04642 4730018.46547 11.80801 48.17149 541.91773 0.64518 -0.30995 17.32708 1.20558 -1.63364 6.53422 8 0 8 2.00 -1999-Aug-27 09:09:51 4171701.52501 872121.15522 4730017.63574 11.80799 48.17150 540.45975 -1.02367 0.07494 15.86909 -0.46328 -1.24875 5.07623 8 0 8 2.00 -1999-Aug-27 09:09:51 4171702.39338 872121.07577 4730015.33413 11.80799 48.17148 539.30073 -1.27914 -2.08126 14.71008 -0.71874 -3.40495 3.91722 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.73145 872121.04089 4730012.73463 11.80800 48.17150 533.66292 -0.15467 0.32012 9.07226 0.40573 -1.00357 -1.72059 8 0 8 2.00 -1999-Aug-27 09:09:51 4171697.67677 872122.41218 4730013.72534 11.80802 48.17150 535.20537 0.99416 0.08223 10.61471 1.55456 -1.24145 -0.17814 8 0 8 2.00 -1999-Aug-27 09:09:51 4171695.86896 872121.72592 4730014.85420 11.80801 48.17152 534.77276 0.69237 2.25829 10.18210 1.25276 0.93461 -0.61075 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.10789 872122.22229 4730013.55864 11.80802 48.17151 534.03109 1.12933 1.14432 9.44044 1.68973 -0.17937 -1.35242 8 0 8 2.00 -1999-Aug-27 09:09:51 4171695.48384 872121.78626 4730016.30946 11.80802 48.17153 535.61398 0.83023 3.50051 11.02332 1.39063 2.17682 0.23046 8 0 8 2.00 -1999-Aug-27 09:09:51 4171691.53135 872119.74984 4730009.87138 11.80800 48.17152 527.95861 -0.35429 2.40029 3.36795 0.20611 1.07661 -7.42490 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.37945 872122.22381 4730014.64761 11.80802 48.17151 535.02001 1.07525 1.67226 10.42935 1.63565 0.34857 -0.36350 8 0 8 2.00 -1999-Aug-27 09:09:51 4171695.04039 872121.88908 4730015.95157 11.80802 48.17153 535.07184 1.02162 3.56959 10.48119 1.58201 2.24590 -0.31167 8 0 8 2.00 -1999-Aug-27 09:09:51 4171696.23661 872119.92847 4730013.67553 11.80799 48.17151 533.88918 -1.14229 1.47815 9.29853 -0.58189 0.15447 -1.49433 8 0 8 2.00 -1999-Aug-27 09:09:51 4171692.28530 872118.72674 4730012.67859 11.80799 48.17153 530.40294 -1.51002 3.87852 5.81228 -0.94962 2.55484 -4.98057 8 0 8 2.00 -1999-Aug-27 09:09:51 4171693.05010 872119.25337 4730012.77064 11.80799 48.17153 531.04265 -1.15103 3.30178 6.45200 -0.59064 1.97810 -4.34086 8 0 8 2.00 -1999-Aug-27 09:09:51 4171691.22178 872118.53771 4730012.43732 11.80799 48.17154 529.50310 -1.47742 4.52215 4.91244 -0.91702 3.19847 -5.88041 8 0 8 2.00 -1999-Aug-27 09:09:51 4171692.09931 872120.21916 4730013.08458 11.80801 48.17153 530.78771 -0.01112 4.05737 6.19706 0.54928 2.73369 -4.59580 8 0 8 2.00 -1999-Aug-27 09:09:52 4171695.04379 872119.92570 4730015.55920 11.80799 48.17153 534.51374 -0.90091 3.60481 9.92309 -0.34051 2.28113 -0.86977 8 0 8 2.00 -1999-Aug-27 09:09:52 4171693.23156 872118.99750 4730013.93497 11.80799 48.17153 531.99378 -1.43862 3.98494 7.40313 -0.87822 2.66126 -3.38973 8 0 8 2.00 -1999-Aug-27 09:09:52 4171695.03156 872120.49094 4730012.72603 11.80800 48.17151 532.47177 -0.34513 1.63810 7.88112 0.21527 0.31441 -2.91174 8 0 8 2.00 -1999-Aug-27 09:09:52 4171692.44555 872120.19115 4730011.21601 11.80800 48.17152 529.61756 -0.10939 2.56295 5.02691 0.45101 1.23926 -5.76595 8 0 8 2.00 -1999-Aug-27 09:09:52 4171694.96610 872122.50465 4730013.16719 11.80803 48.17151 533.03259 1.63937 1.67300 8.44193 2.19976 0.34932 -2.35093 8 0 8 2.00 -1999-Aug-27 09:09:52 4171699.52572 872122.18187 4730015.95146 11.80801 48.17150 538.03970 0.39037 0.25338 13.44904 0.95077 -1.07030 2.65619 8 0 8 2.00 -1999-Aug-27 09:09:52 4171699.39159 872123.42002 4730017.00027 11.80803 48.17151 538.90262 1.62977 0.86188 14.31197 2.19016 -0.46181 3.51911 8 0 8 2.00 -1999-Aug-27 09:09:52 4171700.85857 872121.23598 4730014.03652 11.80799 48.17148 537.35377 -0.80825 -1.85162 12.76312 -0.24785 -3.17530 1.97026 8 0 8 2.00 -1999-Aug-27 09:09:52 4171695.99802 872121.62962 4730015.63340 11.80801 48.17152 535.42448 0.57169 2.69849 10.83383 1.13209 1.37480 0.04097 8 0 8 2.00 -1999-Aug-27 09:09:52 4171696.81760 872122.02495 4730014.47354 11.80802 48.17151 535.14919 0.79094 1.26692 10.55853 1.35134 -0.05677 -0.23432 8 0 8 2.00 -1999-Aug-27 09:09:52 4171696.77624 872121.03798 4730015.86061 11.80800 48.17152 536.02106 -0.16667 2.37262 11.43041 0.39372 1.04893 0.63755 8 0 8 2.00 -1999-Aug-27 09:09:52 4171697.54798 872121.26017 4730014.07443 11.80800 48.17150 535.22421 -0.10711 0.58464 10.63355 0.45329 -0.73904 -0.15931 8 0 8 2.00 -1999-Aug-27 09:09:52 4171693.40606 872120.75431 4730012.00122 11.80801 48.17152 530.90653 0.24531 2.30017 6.31587 0.80570 0.97648 -4.47699 8 0 8 2.00 -1999-Aug-27 09:09:52 4171698.56341 872122.08972 4730014.39904 11.80801 48.17150 536.24216 0.49709 -0.06599 11.65150 1.05749 -1.38968 0.85864 8 0 8 2.00 -1999-Aug-27 09:09:52 4171693.73627 872121.18501 4730013.50677 11.80801 48.17152 532.30271 0.59932 2.99770 7.71205 1.15972 1.67401 -3.08080 8 0 8 2.00 -1999-Aug-27 09:09:52 4171696.12716 872120.24567 4730014.87457 11.80799 48.17152 534.75448 -0.80940 2.30926 10.16382 -0.24900 0.98558 -0.62904 8 0 8 2.00 -1999-Aug-27 09:09:52 4171693.65943 872120.62653 4730013.27054 11.80801 48.17152 532.00031 0.06838 2.98136 7.40966 0.62877 1.65767 -3.38320 8 0 8 2.00 -1999-Aug-27 09:09:52 4171695.65975 872119.17529 4730010.79326 11.80798 48.17150 531.26212 -1.76148 0.09155 6.67146 -1.20109 -1.23213 -4.12139 8 0 8 2.00 -1999-Aug-27 09:09:52 4171697.36064 872119.74163 4730016.60157 11.80798 48.17152 536.77776 -1.55518 2.63819 12.18711 -0.99478 1.31451 1.39425 8 0 8 2.00 -1999-Aug-27 09:09:52 4171698.10737 872120.08051 4730014.83040 11.80799 48.17151 535.99169 -1.37628 0.86067 11.40103 -0.81589 -0.46302 0.60817 8 0 8 2.00 -1999-Aug-27 09:09:52 4171699.43396 872119.52246 4730015.30587 11.80798 48.17150 537.13581 -2.19398 0.29527 12.54516 -1.63359 -1.02841 1.75230 8 0 8 2.00 -1999-Aug-27 09:09:52 4171698.65651 872119.95153 4730014.43009 11.80798 48.17150 536.03427 -1.61490 0.21284 11.44361 -1.05451 -1.11085 0.65075 8 0 8 2.00 -1999-Aug-27 09:09:52 4171698.85831 872120.69157 4730013.06029 11.80799 48.17149 535.24630 -0.93181 -0.96071 10.65564 -0.37142 -2.28440 -0.13722 8 0 8 2.00 -1999-Aug-27 09:09:52 4171702.09735 872123.13976 4730015.91420 11.80802 48.17148 539.82139 0.80175 -1.79321 15.23074 1.36215 -3.11690 4.43788 8 0 8 2.00 -1999-Aug-27 09:09:52 4171702.62734 872123.95096 4730018.75188 11.80803 48.17149 542.39255 1.48733 -0.41100 17.80190 2.04773 -1.73469 7.00904 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.55810 872122.98705 4730018.84565 11.80802 48.17152 540.32731 1.17189 2.03714 15.73665 1.73229 0.71345 4.94380 8 0 8 2.00 -1999-Aug-27 09:09:53 4171702.58397 872123.63153 4730018.69268 11.80802 48.17149 542.27653 1.18353 -0.37015 17.68588 1.74393 -1.69384 6.89302 8 0 8 2.00 -1999-Aug-27 09:09:53 4171700.84003 872121.91546 4730015.96144 11.80800 48.17149 538.86875 -0.13936 -0.65797 14.27810 0.42104 -1.98165 3.48524 8 0 8 2.00 -1999-Aug-27 09:09:53 4171698.83605 872121.90151 4730015.09620 11.80801 48.17150 536.91394 0.25708 0.22878 12.32328 0.81747 -1.09491 1.53043 8 0 8 2.00 -1999-Aug-27 09:09:53 4171700.53178 872121.94771 4730014.08790 11.80801 48.17148 537.27587 -0.04471 -1.68753 12.68522 0.51569 -3.01121 1.89236 8 0 8 2.00 -1999-Aug-27 09:09:53 4171695.59403 872118.37755 4730013.28540 11.80797 48.17151 532.96736 -2.52889 1.92315 8.37670 -1.96850 0.59946 -2.41616 8 0 8 2.00 -1999-Aug-27 09:09:53 4171695.48056 872119.79763 4730013.15611 11.80799 48.17151 532.99074 -1.11564 1.70314 8.40008 -0.55524 0.37946 -2.39278 8 0 8 2.00 -1999-Aug-27 09:09:53 4171692.67114 872119.28211 4730009.45309 11.80799 48.17151 528.32714 -1.04535 1.36132 3.73649 -0.48496 0.03764 -7.05637 8 0 8 2.00 -1999-Aug-27 09:09:53 4171694.87757 872120.03120 4730011.45064 11.80800 48.17151 531.35817 -0.76362 0.96996 6.76751 -0.20323 -0.35373 -4.02534 8 0 8 2.00 -1999-Aug-27 09:09:53 4171696.40916 872121.56224 4730012.62425 11.80801 48.17150 533.44143 0.42160 0.40208 8.85078 0.98200 -0.92160 -1.94208 8 0 8 2.00 -1999-Aug-27 09:09:53 4171697.17786 872121.32476 4730013.35249 11.80801 48.17150 534.45346 0.03185 0.36328 9.86281 0.59224 -0.96040 -0.93005 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.43371 872120.90242 4730012.49127 11.80799 48.17148 535.22669 -0.84317 -1.79203 10.63603 -0.28278 -3.11572 -0.15683 8 0 8 2.00 -1999-Aug-27 09:09:53 4171703.10351 872120.89149 4730014.17359 11.80798 48.17147 538.87438 -1.60484 -3.34508 14.28373 -1.04444 -4.66876 3.49087 8 0 8 2.00 -1999-Aug-27 09:09:53 4171701.43138 872120.85068 4730013.92046 11.80799 48.17148 537.58864 -1.30260 -2.28806 12.99798 -0.74221 -3.61175 2.20513 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.00645 872119.88430 4730014.06178 11.80798 48.17150 535.97909 -1.75232 -0.27777 11.38844 -1.19192 -1.60145 0.59558 8 0 8 2.00 -1999-Aug-27 09:09:53 4171698.56922 872120.59969 4730016.07177 11.80799 48.17151 537.28904 -0.96259 1.27252 12.69838 -0.40220 -0.05117 1.90553 8 0 8 2.00 -1999-Aug-27 09:09:53 4171702.77367 872122.96953 4730017.52657 11.80801 48.17149 541.44111 0.49672 -1.18525 16.85045 1.05712 -2.50894 6.05760 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.57639 872121.08073 4730013.42677 11.80800 48.17149 536.04124 -0.69784 -1.29940 11.45059 -0.13744 -2.62309 0.65773 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.06515 872120.17241 4730014.85069 11.80799 48.17150 536.64458 -1.48231 0.16160 12.05393 -0.92192 -1.16208 1.26107 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.00560 872118.70622 4730015.36338 11.80797 48.17150 536.78764 -2.90530 0.77052 12.19699 -2.34490 -0.55317 1.40413 8 0 8 2.00 -1999-Aug-27 09:09:53 4171697.49105 872120.49015 4730015.94210 11.80799 48.17152 536.47364 -0.84919 1.98914 11.88299 -0.28880 0.66545 1.09013 8 0 8 2.00 -1999-Aug-27 09:09:53 4171696.04833 872120.90365 4730013.70680 11.80800 48.17151 533.92266 -0.14921 1.48764 9.33200 0.41119 0.16396 -1.46086 8 0 8 2.00 -1999-Aug-27 09:09:53 4171697.41805 872121.32736 4730014.77169 11.80801 48.17151 535.66812 -0.01476 1.13417 11.07747 0.54564 -0.18952 0.28461 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.20192 872120.79325 4730013.27143 11.80799 48.17149 535.64181 -0.90260 -1.08603 11.05116 -0.34221 -2.40972 0.25830 8 0 8 2.00 -1999-Aug-27 09:09:53 4171699.87114 872118.81715 4730014.46100 11.80797 48.17149 536.69540 -2.97383 -0.47950 12.10474 -2.41344 -1.80319 1.31188 8 0 8 2.00 -1999-Aug-27 09:09:54 4171699.56085 872118.02418 4730015.71985 11.80796 48.17150 537.32264 -3.68653 0.70727 12.73199 -3.12613 -0.61642 1.93913 8 0 8 2.00 -1999-Aug-27 09:09:54 4171701.47217 872120.01082 4730017.82587 11.80798 48.17150 540.41074 -2.13305 0.41478 15.82009 -1.57265 -0.90891 5.02723 8 0 8 2.00 -1999-Aug-27 09:09:54 4171697.52389 872118.48211 4730015.10330 11.80797 48.17151 535.59601 -2.82146 1.71197 11.00536 -2.26106 0.38829 0.21250 8 0 8 2.00 -1999-Aug-27 09:09:54 4171695.57627 872118.56208 4730016.61309 11.80797 48.17153 535.46055 -2.34463 4.12721 10.86989 -1.78423 2.80352 0.07703 8 0 8 2.00 -1999-Aug-27 09:09:54 4171695.92575 872119.17136 4730017.70129 11.80798 48.17154 536.58271 -1.81976 4.50513 11.99205 -1.25936 3.18144 1.19919 8 0 8 2.00 -1999-Aug-27 09:09:54 4171700.06956 872119.83335 4730014.76660 11.80798 48.17149 537.19132 -2.01974 -0.57537 12.60066 -1.45934 -1.89906 1.80780 8 0 8 2.00 -1999-Aug-27 09:09:54 4171700.15925 872120.16104 4730016.04578 11.80798 48.17150 538.24776 -1.71733 0.16234 13.65710 -1.15694 -1.16135 2.86425 8 0 8 2.00 -1999-Aug-27 09:09:54 4171698.98515 872121.26475 4730016.88240 11.80800 48.17151 538.25534 -0.39673 1.40834 13.66469 0.16367 0.08466 2.87183 8 0 8 2.00 -1999-Aug-27 09:09:54 4171700.97122 872119.93400 4730018.34293 11.80798 48.17151 540.45853 -2.10573 1.13671 15.86788 -1.54533 -0.18698 5.07502 8 0 8 2.00 -1999-Aug-27 09:09:54 4171701.80741 872121.47275 4730019.56718 11.80800 48.17151 542.12663 -0.77065 1.10864 17.53597 -0.21025 -0.21505 6.74311 8 0 8 2.00 -1999-Aug-27 09:09:54 4171699.27688 872120.96832 4730016.71036 11.80800 48.17151 538.27714 -0.74658 1.12603 13.68648 -0.18618 -0.19766 2.89363 8 0 8 2.00 -1999-Aug-27 09:09:54 4171699.35165 872119.53223 4730013.59905 11.80798 48.17149 535.81159 -2.16758 -0.78447 11.22093 -1.60718 -2.10816 0.42808 8 0 8 2.00 -1999-Aug-27 09:09:54 4171696.04914 872118.70755 4730012.16756 11.80797 48.17150 532.47653 -2.29901 0.79538 7.88587 -1.73861 -0.52830 -2.90699 8 0 8 2.00 -1999-Aug-27 09:09:54 4171697.64791 872120.01524 4730013.29576 11.80799 48.17150 534.53933 -1.34615 0.18228 9.94867 -0.78576 -1.14140 -0.84419 8 0 8 2.00 -1999-Aug-27 09:09:54 4171698.50860 872121.40987 4730013.76595 11.80800 48.17149 535.64185 -0.15716 -0.34456 11.05120 0.40324 -1.66825 0.25834 8 0 8 2.00 -1999-Aug-27 09:09:54 4171697.76601 872122.01250 4730018.21739 11.80801 48.17153 538.55630 0.58468 3.07385 13.96565 1.14508 1.75017 3.17279 8 0 8 2.00 -1999-Aug-27 09:09:54 4171697.87418 872121.62715 4730016.09601 11.80801 48.17151 536.99360 0.18535 1.63896 12.40295 0.74575 0.31528 1.61009 8 0 8 2.00 -1999-Aug-27 09:09:54 4171695.00694 872119.78269 4730014.73859 11.80799 48.17153 533.85871 -1.03335 3.10623 9.26805 -0.47295 1.78255 -1.52480 8 0 8 2.00 -1999-Aug-27 09:09:54 4171692.98447 872119.03661 4730010.52806 11.80799 48.17151 529.29918 -1.34977 1.88712 4.70852 -0.78938 0.56343 -6.08433 8 0 8 2.00 -1999-Aug-27 09:09:54 4171696.08776 872119.17869 4730010.66490 11.80798 48.17149 531.44633 -1.84574 -0.30675 6.85568 -1.28535 -1.63044 -3.93718 8 0 8 2.00 -1999-Aug-27 09:09:54 4171696.88518 872119.27883 4730013.87921 11.80798 48.17151 534.37567 -1.91090 1.24000 9.78502 -1.35050 -0.08369 -1.00784 8 0 8 2.00 -1999-Aug-27 09:09:54 4171700.50795 872120.62964 4730015.40532 11.80799 48.17149 538.06210 -1.33001 -0.59057 13.47145 -0.76961 -1.91426 2.67859 8 0 8 2.00 -1999-Aug-27 09:09:54 4171696.69454 872120.26372 4730015.92500 11.80799 48.17152 535.91004 -0.90784 2.59321 11.31939 -0.34744 1.26953 0.52653 8 0 8 2.00 -1999-Aug-27 09:09:54 4171699.74691 872119.07327 4730013.60269 11.80797 48.17149 536.00969 -2.69771 -1.00035 11.41903 -2.13732 -2.32404 0.62617 8 0 8 2.00 -1999-Aug-27 09:09:54 4171698.25774 872120.25479 4730015.86336 11.80799 48.17151 536.88334 -1.23646 1.41330 12.29269 -0.67607 0.08962 1.49983 8 0 8 2.00 -1999-Aug-27 09:09:55 4171694.66342 872121.26232 4730013.93001 11.80801 48.17152 533.23387 0.48527 2.59193 8.64322 1.04566 1.26825 -2.14964 8 0 8 2.00 -1999-Aug-27 09:09:55 4171691.13996 872117.89442 4730013.14412 11.80798 48.17154 529.88857 -2.09035 5.15129 5.29791 -1.52996 3.82760 -5.49494 8 0 8 2.00 -1999-Aug-27 09:09:55 4171691.61574 872117.93210 4730010.55596 11.80798 48.17153 528.27575 -2.15082 3.07246 3.68509 -1.59043 1.74878 -7.10777 8 0 8 2.00 -1999-Aug-27 09:09:55 4171692.44866 872119.74001 4730011.37280 11.80800 48.17152 529.67486 -0.55162 2.73404 5.08420 0.00878 1.41035 -5.70865 8 0 8 2.00 -1999-Aug-27 09:09:55 4171695.43700 872120.46172 4730011.32902 11.80800 48.17150 531.69148 -0.45669 0.41516 7.10083 0.10370 -0.90852 -3.69203 8 0 8 2.00 -1999-Aug-27 09:09:55 4171698.73703 872120.82502 4730015.16480 11.80800 48.17150 536.75351 -0.77637 0.51090 12.16285 -0.21598 -0.81279 1.36999 8 0 8 2.00 -1999-Aug-27 09:09:55 4171698.44296 872121.33724 4730014.26434 11.80800 48.17150 535.96047 -0.21481 0.04677 11.36981 0.34558 -1.27692 0.57696 8 0 8 2.00 -1999-Aug-27 09:09:55 4171700.47405 872120.81030 4730014.41915 11.80799 48.17149 537.32979 -1.14623 -1.25108 12.73913 -0.58584 -2.57476 1.94628 8 0 8 2.00 -1999-Aug-27 09:09:55 4171700.63064 872120.06416 4730016.11262 11.80798 48.17150 538.59206 -1.90863 -0.12214 14.00141 -1.34823 -1.44582 3.20855 8 0 8 2.00 -1999-Aug-27 09:09:55 4171698.84239 872120.93929 4730016.47208 11.80800 48.17151 537.81200 -0.68609 1.28846 13.22134 -0.12569 -0.03523 2.42848 8 0 8 2.00 -1999-Aug-27 09:09:55 4171695.09195 872118.84721 4730014.58941 11.80798 48.17153 533.67537 -1.96643 3.08738 9.08472 -1.40603 1.76369 -1.70814 8 0 8 2.00 -1999-Aug-27 09:09:55 4171697.29848 872120.51168 4730012.46125 11.80800 48.17150 533.75714 -0.78871 -0.19508 9.16648 -0.22831 -1.51876 -1.62637 8 0 8 2.00 -1999-Aug-27 09:09:55 4171695.89876 872121.66594 4730013.12868 11.80801 48.17151 533.49827 0.62755 1.09495 8.90761 1.18795 -0.22873 -1.88524 8 0 8 2.00 -1999-Aug-27 09:09:55 4171694.73702 872121.00956 4730012.93178 11.80801 48.17151 532.50360 0.22280 1.91106 7.91294 0.78319 0.58737 -2.87992 8 0 8 2.00 -1999-Aug-27 09:09:55 4171697.63379 872120.12947 4730017.11196 11.80799 48.17152 537.38932 -1.23145 2.72020 12.79866 -0.67105 1.39652 2.00581 8 0 8 2.00 -1999-Aug-27 09:09:55 4171697.68904 872120.92572 4730014.98815 11.80800 48.17151 535.95150 -0.46335 1.14212 11.36084 0.09704 -0.18157 0.56799 8 0 8 2.00 -1999-Aug-27 09:09:55 4171696.62000 872121.40895 4730015.03597 11.80801 48.17151 535.35521 0.22841 1.88006 10.76456 0.78881 0.55637 -0.02830 8 0 8 2.00 -1999-Aug-27 09:09:55 4171696.80247 872122.90648 4730015.18747 11.80803 48.17151 535.79159 1.65692 1.61966 11.20094 2.21731 0.29597 0.40808 8 0 8 2.00 -1999-Aug-27 09:09:55 4171696.34658 872121.43321 4730014.71267 11.80801 48.17151 534.93914 0.30811 1.86018 10.34848 0.86850 0.53649 -0.44437 8 0 8 2.00 -1999-Aug-27 09:09:55 4171694.29667 872122.67858 4730015.04264 11.80803 48.17153 534.01681 1.94661 3.38549 9.42615 2.50700 2.06180 -1.36670 8 0 8 2.00 -1999-Aug-27 09:09:55 4171692.13831 872120.65659 4730012.69678 11.80801 48.17153 530.58391 0.40908 3.70360 5.99326 0.96947 2.37992 -4.79960 8 0 8 2.00 -1999-Aug-27 09:09:55 4171694.23194 872120.44410 4730014.42863 11.80800 48.17153 533.21209 -0.22734 3.36393 8.62143 0.33305 2.04025 -2.17142 8 0 8 2.00 -1999-Aug-27 09:09:55 4171698.32126 872121.37567 4730014.16697 11.80800 48.17150 535.81371 -0.15230 0.06473 11.22306 0.40810 -1.25895 0.43020 8 0 8 2.00 -1999-Aug-27 09:09:55 4171700.76351 872121.36473 4730014.66514 11.80800 48.17149 537.77771 -0.66277 -1.38269 13.18705 -0.10237 -2.70638 2.39420 8 0 8 2.00 -1999-Aug-27 09:09:55 4171698.49522 872121.81732 4730017.24078 11.80801 48.17151 538.27798 0.24441 1.92044 13.68732 0.80481 0.59675 2.89446 8 0 8 2.00 -1999-Aug-27 09:09:56 4171702.81391 872120.88969 4730019.62976 11.80798 48.17150 542.75072 -1.54733 0.50516 18.16006 -0.98694 -0.81853 7.36721 8 0 8 2.00 -1999-Aug-27 09:09:56 4171701.38777 872121.82179 4730016.31742 11.80800 48.17149 539.47878 -0.34312 -0.80579 14.88813 0.21728 -2.12947 4.09527 8 0 8 2.00 -1999-Aug-27 09:09:56 4171698.54403 872121.95492 4730016.61772 11.80801 48.17151 537.86435 0.36911 1.44834 13.27369 0.92950 0.12465 2.48084 8 0 8 2.00 -1999-Aug-27 09:09:56 4171697.17901 872121.11271 4730014.63374 11.80800 48.17151 535.37999 -0.17595 1.24925 10.78934 0.38444 -0.07443 -0.00352 8 0 8 2.00 -1999-Aug-27 09:09:56 4171697.09264 872121.25042 4730015.91479 11.80801 48.17152 536.29696 -0.02348 2.14559 11.70631 0.53691 0.82190 0.91345 8 0 8 2.00 -1999-Aug-27 09:09:56 4171699.59055 872121.84221 4730017.91063 11.80801 48.17151 539.49553 0.04463 1.56446 14.90488 0.60503 0.24077 4.11202 8 0 8 2.00 -1999-Aug-27 09:09:56 4171698.84582 872123.26530 4730017.29305 11.80803 48.17151 538.74340 1.59001 1.47880 14.15275 2.15040 0.15511 3.35989 8 0 8 2.00 -1999-Aug-27 09:09:56 4171699.81090 872122.81339 4730017.99797 11.80802 48.17151 539.83699 0.95017 1.31390 15.24634 1.51057 -0.00979 4.45348 8 0 8 2.00 -1999-Aug-27 09:09:56 4171695.03670 872121.57796 4730013.48874 11.80802 48.17152 533.19182 0.71784 1.97725 8.60116 1.27823 0.65357 -2.19169 8 0 8 2.00 -1999-Aug-27 09:09:56 4171695.04848 872121.21140 4730012.33657 11.80801 48.17151 532.29094 0.35663 1.25617 7.70029 0.91702 -0.06751 -3.09257 8 0 8 2.00 -1999-Aug-27 09:09:56 4171696.40730 872120.50518 4730012.20451 11.80800 48.17150 532.98318 -0.61271 0.28470 8.39253 -0.05231 -1.03899 -2.40033 8 0 8 2.00 -1999-Aug-27 09:09:56 4171698.72748 872122.45637 4730013.79140 11.80802 48.17149 535.94652 0.82241 -0.64680 11.35587 1.38280 -1.97049 0.56301 8 0 8 2.00 -1999-Aug-27 09:09:56 4171703.96739 872123.84066 4730015.02347 11.80802 48.17146 540.47407 1.10515 -3.85808 15.88342 1.66555 -5.18176 5.09056 8 0 8 2.00 -1999-Aug-27 09:09:56 4171703.16871 872124.16891 4730018.17486 11.80803 48.17149 542.34574 1.58989 -1.22392 17.75508 2.15029 -2.54761 6.96222 8 0 8 2.00 -1999-Aug-27 09:09:56 4171703.21681 872124.67995 4730017.42717 11.80803 48.17148 541.88974 2.08027 -1.83557 17.29909 2.64067 -3.15925 6.50623 8 0 8 2.01 -1999-Aug-27 09:09:56 4171698.14915 872123.13212 4730014.62054 11.80803 48.17150 536.27904 1.60220 0.22493 11.68838 2.16260 -1.09876 0.89552 8 0 8 2.01 -1999-Aug-27 09:09:56 4171695.66717 872121.19840 4730014.80982 11.80801 48.17152 534.53597 0.21730 2.45632 9.94532 0.77769 1.13263 -0.84754 8 0 8 2.01 -1999-Aug-27 09:09:56 4171692.34626 872121.02784 4730013.88176 11.80802 48.17154 531.65330 0.72991 4.28558 7.06264 1.29031 2.96190 -3.73022 8 0 8 2.01 -1999-Aug-27 09:09:56 4171692.34564 872120.26465 4730012.93450 11.80801 48.17153 530.84290 -0.01700 3.77068 6.25224 0.54340 2.44699 -4.54062 8 0 8 2.01 -1999-Aug-27 09:09:56 4171693.95977 872120.82300 4730013.50194 11.80801 48.17152 532.39561 0.19923 2.88666 7.80495 0.75963 1.56298 -2.98790 8 0 8 2.01 -1999-Aug-27 09:09:56 4171695.05282 872119.83008 4730012.62738 11.80799 48.17151 532.32197 -0.99635 1.65757 7.73131 -0.43595 0.33388 -3.06154 8 0 8 2.01 -1999-Aug-27 09:09:56 4171696.47160 872120.57611 4730013.39240 11.80800 48.17151 533.91999 -0.55644 1.01918 9.32934 0.00396 -0.30451 -1.46352 8 0 8 2.01 -1999-Aug-27 09:09:56 4171697.75946 872119.66939 4730013.00066 11.80798 48.17150 534.34505 -1.70751 -0.04315 9.75440 -1.14711 -1.36683 -1.03846 8 0 8 2.01 -1999-Aug-27 09:09:56 4171703.14076 872121.84367 4730015.53427 11.80800 48.17147 540.04255 -0.68043 -2.61000 15.45189 -0.12003 -3.93369 4.65903 8 0 8 2.01 -1999-Aug-27 09:09:56 4171698.28961 872119.68208 4730016.38749 11.80798 48.17151 537.21654 -1.80357 1.82693 12.62588 -1.24318 0.50325 1.83302 8 0 8 2.01 -1999-Aug-27 09:09:57 4171696.78284 872120.08408 4730018.16576 11.80799 48.17153 537.61286 -1.10174 4.05057 13.02221 -0.54134 2.72689 2.22935 8 0 8 2.01 -1999-Aug-27 09:09:57 4171698.09506 872121.58882 4730017.83281 11.80801 48.17152 538.42673 0.10263 2.64198 13.83607 0.66303 1.31829 3.04322 8 0 8 2.01 -1999-Aug-27 09:09:57 4171694.53161 872120.85652 4730014.14116 11.80801 48.17152 533.24979 0.11503 2.89076 8.65913 0.67542 1.56707 -2.13372 8 0 8 2.01 -1999-Aug-27 09:09:57 4171696.70845 872120.53157 4730012.67682 11.80800 48.17150 533.53531 -0.64849 0.37600 8.94466 -0.08810 -0.94768 -1.84820 8 0 8 2.01 -1999-Aug-27 09:09:57 4171694.17822 872118.68139 4730010.44278 11.80798 48.17151 529.96643 -1.94176 1.01372 5.37577 -1.38136 -0.30997 -5.41709 8 0 8 2.01 -1999-Aug-27 09:09:57 4171691.32413 872117.63219 4730011.88793 11.80797 48.17154 529.03697 -2.38472 4.21918 4.44632 -1.82432 2.89550 -6.34654 8 0 8 2.01 -1999-Aug-27 09:09:57 4171692.97155 872119.33808 4730014.66730 11.80799 48.17154 532.41622 -1.05204 4.61105 7.82556 -0.49165 3.28736 -2.96729 8 0 8 2.01 -1999-Aug-27 09:09:57 4171694.68080 872119.33214 4730014.88370 11.80799 48.17153 533.69244 -1.40763 3.50959 9.10178 -0.84723 2.18590 -1.69108 8 0 8 2.01 -1999-Aug-27 09:09:57 4171696.92551 872119.56632 4730015.31227 11.80798 48.17152 535.50907 -1.63774 2.12246 10.91842 -1.07735 0.79877 0.12556 8 0 8 2.01 -1999-Aug-27 09:09:57 4171697.91641 872121.05163 4730017.21901 11.80800 48.17152 537.77942 -0.38664 2.44485 13.18876 0.17376 1.12116 2.39591 8 0 8 2.01 -1999-Aug-27 09:09:57 4171695.03465 872121.57041 4730012.91418 11.80802 48.17151 532.76131 0.71088 1.59672 8.17066 1.27127 0.27304 -2.62220 8 0 8 2.01 -1999-Aug-27 09:09:57 4171693.25986 872122.16093 4730011.39838 11.80803 48.17151 530.55385 1.65207 1.79028 5.96319 2.21247 0.46659 -4.82967 8 0 8 2.01 -1999-Aug-27 09:09:57 4171695.93617 872120.53982 4730011.61027 11.80800 48.17150 532.23757 -0.48239 0.22674 7.64692 0.07801 -1.09694 -3.14594 8 0 8 2.01 -1999-Aug-27 09:09:57 4171696.66712 872121.13081 4730013.71981 11.80800 48.17151 534.36729 -0.05348 1.01035 9.77663 0.50692 -0.31334 -1.01622 8 0 8 2.01 -1999-Aug-27 09:09:57 4171698.03720 872121.75260 4730015.20393 11.80801 48.17151 536.45241 0.27478 0.90600 11.86175 0.83518 -0.41769 1.06890 8 0 8 2.01 -1999-Aug-27 09:09:57 4171695.58963 872119.54168 4730014.20065 11.80799 48.17152 533.80534 -1.38850 2.35923 9.21469 -0.82810 1.03554 -1.57817 8 0 8 2.01 -1999-Aug-27 09:09:57 4171693.26667 872117.91775 4730013.36182 11.80797 48.17153 531.44227 -2.50270 3.74174 6.85161 -1.94231 2.41805 -3.94124 8 0 8 2.01 -1999-Aug-27 09:09:57 4171693.04107 872118.77160 4730011.54268 11.80798 48.17152 530.05600 -1.62076 2.56290 5.46535 -1.06036 1.23921 -5.32751 8 0 8 2.01 -1999-Aug-27 09:09:57 4171691.37081 872118.97351 4730014.02342 11.80799 48.17155 530.84173 -1.08133 5.40477 6.25108 -0.52094 4.08109 -4.54178 8 0 8 2.01 -1999-Aug-27 09:09:57 4171695.89944 872120.24748 4730017.98876 11.80800 48.17154 536.92660 -0.76103 4.55194 12.33594 -0.20063 3.22825 1.54309 8 0 8 2.01 -1999-Aug-27 09:09:57 4171693.60319 872120.27540 4730015.12961 11.80800 48.17154 533.30095 -0.26381 4.31574 8.71030 0.29658 2.99206 -2.08256 8 0 8 2.01 -1999-Aug-27 09:09:57 4171694.51508 872119.88648 4730013.55454 11.80799 48.17152 532.66950 -0.83110 2.65951 8.07884 -0.27070 1.33583 -2.71401 8 0 8 2.01 -1999-Aug-27 09:09:57 4171696.62682 872119.69056 4730014.88941 11.80799 48.17152 535.01596 -1.45501 2.03936 10.42530 -0.89461 0.71568 -0.36755 8 0 8 2.01 diff --git a/src/utils/gnuplot/8_GPS_accuracy_precision.jpeg b/src/utils/gnuplot/8_GPS_accuracy_precision.jpeg deleted file mode 100644 index 46e80635b..000000000 Binary files a/src/utils/gnuplot/8_GPS_accuracy_precision.jpeg and /dev/null differ diff --git a/src/utils/gnuplot/8_Galileo.plt b/src/utils/gnuplot/8_Galileo.plt deleted file mode 100644 index 7cf992c5b..000000000 --- a/src/utils/gnuplot/8_Galileo.plt +++ /dev/null @@ -1,40 +0,0 @@ -#set terminal pdf color font "Bold,14" -#set output "IFEN_accuracy.pdf" - -set terminal jpeg font "Helvetica, 14" -set output "8_GALILEO_accuracy_precision.jpeg" - -set grid -set xrange [-8:8] -set yrange [-8:8] -set ylabel "North [m]" -set xlabel "East [m]" - -set key Left left -set title "IFEN simulated data, 8 Galileo - Accuracy and Precision" -#file1="8_GPS_GNSS_SDR_solutions.txt" -file2="8_GAL_GNSS_SDR_solutions.txt" -#file3="8_GPS_GNSS_SDR_solutions.txt" - -#values to copy from statistic file -DRMS= 1.870121081 -DUE_DRMS= 3.740242162 -CEP= 1.556390643 - -#difference with respect to the reference position -#values to copy from statistic file -delta_E=1.191 #galileo -delta_N=1.923 #galileo - -set parametric -#dummy variable is t for curves, u/v for surfaces -set size square -set angle degree -set trange [0:360] -#radius_6_GPS=6 - -plot file2 u 9:10 with points pointsize 0.3 lc rgb "blue" notitle,\ -DRMS*sin(t)+delta_E,DRMS*cos(t)+delta_N lw 3 lc rgb "black" title "DRMS",\ -DUE_DRMS*sin(t)+delta_E,DUE_DRMS*cos(t)+delta_N lw 2 lc rgb "gray" title "2DRMS",\ -CEP*sin(t)+delta_E,CEP*cos(t)+delta_N lw 1 lc rgb "black" title "CEP" - diff --git a/src/utils/gnuplot/8_sat_accuracy_precision.jpeg b/src/utils/gnuplot/8_sat_accuracy_precision.jpeg deleted file mode 100644 index 840e2bac7..000000000 Binary files a/src/utils/gnuplot/8_sat_accuracy_precision.jpeg and /dev/null differ diff --git a/src/utils/gnuplot/8_sat_accuracy_precision.plt b/src/utils/gnuplot/8_sat_accuracy_precision.plt deleted file mode 100644 index 16a4921bc..000000000 --- a/src/utils/gnuplot/8_sat_accuracy_precision.plt +++ /dev/null @@ -1,50 +0,0 @@ -#to load the file digit from terminal: -#> gnuplot 8_sat_IFEN_accuracy_precision.plt - -#set terminal pdf color font "Bold,14" -#set output "IFEN_solutions_pdf" -set terminal jpeg font "Helvetica, 14" -set output "8_sat_accuracy_precision.jpeg" - -set grid -set xrange [-15:15] -set yrange [-10:20] -set ylabel "North [m]" -set xlabel "East [m]" - -set key Left left -set title "Accuracy-Precision (with respect to CORRECT coordinates)- 2DRMS" -file1="4_GPS_3_GAL_GNSS_SDR_solutions.txt" -file2="8_GAL_GNSS_SDR_solutions.txt" -file3="8_GPS_GNSS_SDR_solutions.txt" - -#values to copy from statistic file -DRMS_1=2*3.077 #it is 2*DRMS combined -DRMS_2=2*1.87 # gal -DRMS_3=2*2.034 # gps - -#difference with respect to the reference position - -#values to copy from statistic file -delta_E_1=-1.812 #combined -delta_N_1= 3.596 #combined - -delta_E_2= 1.191 #gal -delta_N_2= 1.923 #gal - -delta_E_3= -0.560 #gps -delta_N_3= 1.323 #gps - -set parametric -#dummy variable is t for curves, u/v for surfaces -set size square -set angle degree -set trange [0:360] - -plot file1 u 9:10 with points pointsize 0.3 lc rgb "green" title "4 GPS-3 GAL",\ -file3 u 9:10 with points pointsize 0.3 lc rgb "red" title "8 GPS",\ -file2 u 9:10 with points pointsize 0.3 lc rgb "blue" title "8 GAL",\ -DRMS_1*sin(t)+delta_E_1,DRMS_1*cos(t)+delta_N_1 lw 2 lc rgb "green" notitle,\ -DRMS_3*sin(t)+delta_E_3,DRMS_3*cos(t)+delta_N_3 lw 2 lc rgb "red" notitle,\ -DRMS_2*sin(t)+delta_E_2,DRMS_2*cos(t)+delta_N_2 lw 2 lc rgb "blue" notitle - diff --git a/src/utils/gnuplot/statistics/4_GPS_3_GAL_GNSS_SDR_statitics.txt b/src/utils/gnuplot/statistics/4_GPS_3_GAL_GNSS_SDR_statitics.txt deleted file mode 100644 index 158166f50..000000000 --- a/src/utils/gnuplot/statistics/4_GPS_3_GAL_GNSS_SDR_statitics.txt +++ /dev/null @@ -1,23 +0,0 @@ -Num of GPS observation 4 -Num of GALILEO observation 3 -GDOP mean= 2.380532594 - -ENU computed at (IFEN true coordinates): ref Longitude = 11.808005630, Ref Latitude = 48.171497670 for Accuracy -ENU computed at (average coordinates) mean Longitude = 11.807981252, mean Latitude = 48.171530020 for Precision - -ACCURACY (respect true position) -East offset [m] = -1.812959237, East st. dev = 1.899085141 -Nord offset [m] = 3.596061973,Noth st. dev = 2.422058671 -Up offset [m] = 8.995532878, Up st. dev = 3.881428324 - -DRMS= 3.077806456 -DUE_DRMS= 6.155612912 -CEP= 2.565164055 -MRSE= 4.953622757 -SEP= 12.514572993 - -PRECISION (respect average solution) -East offset [m] = 0.000000000, East st. dev = 1.899086239 -Nord offset [m] = -0.000000001, ,Noth st. dev = 2.422059160 -Up offset [m]= -0.000000003, Up st. dev = 3.881427482 ----------------------------------------------------------------------------------------------- diff --git a/src/utils/gnuplot/statistics/8_GAL_GNSS_SDR_statitics.txt b/src/utils/gnuplot/statistics/8_GAL_GNSS_SDR_statitics.txt deleted file mode 100644 index 88c48dde2..000000000 --- a/src/utils/gnuplot/statistics/8_GAL_GNSS_SDR_statitics.txt +++ /dev/null @@ -1,23 +0,0 @@ -Num of GPS observation 0 -Num of GALILEO observation 8 -GDOP mean= 1.769225604 - -ENU computed at (IFEN true coordinates): ref Longitude = 11.808005630, Ref Latitude = 48.171497670 for Accuracy -ENU computed at (average coordinates) mean Longitude = 11.808021645, mean Latitude = 48.171514975 for Precision - -ACCURACY (respect true position) -East offset [m] = 1.191616778, East st. dev = 1.370472661 -Nord offset [m] = 1.923075914,Noth st. dev = 1.272461214 -Up offset [m] = 13.774563698, Up st. dev = 3.492269580 - -DRMS= 1.870121081 -DUE_DRMS= 3.740242162 -CEP= 1.556390643 -MRSE= 3.961476957 -SEP= 8.003582836 - -PRECISION (respect average solution) -East offset [m] = -0.000000002, East st. dev = 1.370472897 -Nord offset [m] = -0.000000001, ,Noth st. dev = 1.272461012 -Up offset [m]= 0.000000002, Up st. dev = 3.492269562 ----------------------------------------------------------------------------------------------- diff --git a/src/utils/gnuplot/statistics/8_GPS_GNSS_SDR_statitics.txt b/src/utils/gnuplot/statistics/8_GPS_GNSS_SDR_statitics.txt deleted file mode 100644 index a0ce5df5f..000000000 --- a/src/utils/gnuplot/statistics/8_GPS_GNSS_SDR_statitics.txt +++ /dev/null @@ -1,23 +0,0 @@ -Num of GPS observation 8 -Num of GALILEO observation 0 -GDOP mean= 2.002216944 - -ENU computed at (IFEN true coordinates): ref Longitude = 11.808005630, Ref Latitude = 48.171497670 for Accuracy -ENU computed at (average coordinates) mean Longitude = 11.807998091, mean Latitude = 48.171509585 for Precision - -ACCURACY (respect true position) -East offset [m] = -0.560396234, East st. dev = 1.105718017 -Nord offset [m] = 1.323685667,Noth st. dev = 1.707810937 -Up offset [m] = 10.792857384, Up st. dev = 3.121160956 - -DRMS= 2.034509899 -DUE_DRMS= 4.069019799 -CEP= 1.678044871 -MRSE= 3.725704798 -SEP= 7.079246885 - -PRECISION (respect average solution) -East offset [m] = 0.000000000, East st. dev = 1.105718027 -Nord offset [m] = -0.000000005, ,Noth st. dev = 1.707811217 -Up offset [m]= -0.000000005, Up st. dev = 3.121160800 ----------------------------------------------------------------------------------------------- diff --git a/src/utils/gpstk/gnsspvt/CMakeLists.txt b/src/utils/gpstk/gnsspvt/CMakeLists.txt deleted file mode 100644 index b7255c413..000000000 --- a/src/utils/gpstk/gnsspvt/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -# CMAKE for GPSTK by Javier Arribas 2012 -cmake_minimum_required (VERSION 2.6) -project (gnsspvt_project) - -include_directories(${gnsspvt_project_SOURCE_DIR}/src) - -add_library (kml_printer_gpstk ${gnsspvt_project_SOURCE_DIR}/src/kml_printer_gpstk.cpp) -add_executable(gnsspvt ${gnsspvt_project_SOURCE_DIR}/src/gnsspvt.cpp) - -target_link_libraries (gnsspvt kml_printer_gpstk) - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") - -find_package(GPSTK REQUIRED) - -if ( NOT GPSTK_FOUND ) - message(FATAL_ERROR "GPSTK library not found!") -endif( NOT GPSTK_FOUND ) - -find_package(GLOG REQUIRED) -if ( NOT GLOG_FOUND ) - message(FATAL_ERROR "GLOG library not found!") -endif( NOT GLOG_FOUND ) - -include_directories(${GLOG_INCLUDE_DIRS}) - -# IMPORTANT NOTICE: The GPSTK linking order is critical. First it is required to link agains libprocframe to avoid vtable errors -include_directories(${GPSTK_INCLUDE_DIR}/gpstk ${GEOMATICS_INCLUDE_DIR} ${PROCFRAME_INCLUDE_DIR} ${VDRAW_INCLUDE_DIR} ${VPLOT_INCLUDE_DIR} ${RXIO_INCLUDE_DIR}) -# set(LIBS ${LIBS} ${GPSTK_LIBRARIES} ${GEOMATICS_LIBRARIES} ${VDRAW_LIBRARIES} ${VPLOT_LIBRARIES} ${RXIO_LIBRARIES}) -set(LIBS ${LIBS} ${PROCFRAME_LIBRARIES} ${GPSTK_LIBRARIES} ${GEOMATICS_LIBRARIES} ${GLOG_LIBRARIES}) - - -target_link_libraries(gnsspvt ${LIBS}) - -message(STATUS "GPSTK_INCLUDE_DIR="${GLOG_LIBRARIES}) -#message(STATUS "GPSTK_LIBRARIES=${GPSTK_LIBRARIES}") -#message(STATUS "LIBS=${LIBS}") - -# debug info: print all variables -#get_cmake_property(_variableNames VARIABLES) -#foreach (_variableName ${_variableNames}) -# message(STATUS "${_variableName}=${${_variableName}}") -#endforeach() - -#get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) -#foreach(dir ${dirs}) -# message(STATUS "INCLUDE_DIRECTORIES='${dir}'") -#endforeach() - diff --git a/src/utils/gpstk/gnsspvt/CMakeModules/FindGLOG.cmake b/src/utils/gpstk/gnsspvt/CMakeModules/FindGLOG.cmake deleted file mode 100644 index c4ddbe28a..000000000 --- a/src/utils/gpstk/gnsspvt/CMakeModules/FindGLOG.cmake +++ /dev/null @@ -1,103 +0,0 @@ -# - Try to find the Google Glog library -# -# This module defines the following variables -# -# GLOG_FOUND - Was Glog found -# GLOG_INCLUDE_DIRS - the Glog include directories -# GLOG_LIBRARIES - Link to this -# -# This module accepts the following variables -# -# GLOG_ROOT - Can be set to Glog install path or Windows build path -# -#============================================================================= -# FindGlog.cmake, adapted from FindBullet.cmake which has the following -# copyright - -#----------------------------------------------------------------------------- -# Copyright 2009 Kitware, Inc. -# Copyright 2009 Philip Lowman -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (NOT DEFINED GLOG_ROOT) -set (GLOG_ROOT /usr /usr/local) -endif (NOT DEFINED GLOG_ROOT) - -if(MSVC) -set(LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/Release) -else(MSVC) -set (LIB_PATHS ${GLOG_ROOT} ${GLOG_ROOT}/lib) -endif(MSVC) - -macro(_FIND_GLOG_LIBRARIES _var) -find_library(${_var} -NAMES -${ARGN} -PATHS -${LIB_PATHS} -PATH_SUFFIXES lib -) -mark_as_advanced(${_var}) -endmacro() - -macro(_GLOG_APPEND_LIBRARIES _list _release) -set(_debug ${_release}_DEBUG) -if(${_debug}) -set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}}) -else() -set(${_list} ${${_list}} ${${_release}}) -endif() -endmacro() - -if(MSVC) -find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h -PATHS -${GLOG_ROOT}/src/windows -${GLOG_ROOT}/src/windows/glog -) -else(MSVC) -# Linux/OS X builds -find_path(GLOG_INCLUDE_DIR NAMES raw_logging.h -PATHS -${GLOG_ROOT}/include/glog -) -endif(MSVC) - -# Find the libraries -if(MSVC) -_FIND_GLOG_LIBRARIES(GLOG_LIBRARIES libglog.lib) -else(MSVC) -# Linux/OS X builds -_FIND_GLOG_LIBRARIES(GLOG_LIBRARIES libglog.so) -endif(MSVC) - -message("glog library = " ${GLOG_LIBRARIES}) - -# handle the QUIETLY and REQUIRED arguments and set GLOG_FOUND to TRUE if -# all listed variables are TRUE -include("${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake") -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Glog DEFAULT_MSG -GLOG_LIBRARIES) - -if(MSVC) -string(REGEX REPLACE "/glog$" "" VAR_WITHOUT ${GLOG_INCLUDE_DIR}) -string(REGEX REPLACE "/windows$" "" VAR_WITHOUT ${VAR_WITHOUT}) -set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS} "${VAR_WITHOUT}") -string(REGEX REPLACE "/libglog.lib" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) -else(MSVC) -# Linux/OS X builds -set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) -string(REGEX REPLACE "/libglog.so" "" GLOG_LIBRARIES_DIR ${GLOG_LIBRARIES}) -endif(MSVC) - -if(GLOG_FOUND) -# _GLOG_APPEND_LIBRARIES(GLOG GLOG_LIBRARIES) -endif() diff --git a/src/utils/gpstk/gnsspvt/CMakeModules/FindGPSTK.cmake b/src/utils/gpstk/gnsspvt/CMakeModules/FindGPSTK.cmake deleted file mode 100644 index 9529154f9..000000000 --- a/src/utils/gpstk/gnsspvt/CMakeModules/FindGPSTK.cmake +++ /dev/null @@ -1,87 +0,0 @@ -# - Find gpstk library -# Find the native gpstk includes and library -# This module defines -# GPSTK_INCLUDE_DIR, where to find tiff.h, etc. -# GPSTK_LIBRARIES, libraries to link against to use GPSTK. -# GPSTK_FOUND, If false, do not try to use GPSTK. -# also defined, but not for general use are -# GPSTK_LIBRARY, where to find the GPSTK library. - -FIND_PATH(GPSTK_INCLUDE_DIR gpstk/Matrix.hpp) -FIND_PATH(GEOMATICS_INCLUDE_DIR gpstk/random.hpp) -FIND_PATH(PROCFRAME_INCLUDE_DIR gpstk/SolverWMS.hpp) -FIND_PATH(VDRAW_INCLUDE_DIR gpstk/Layout.hpp) -FIND_PATH(VPLOT_INCLUDE_DIR gpstk/ScatterPlot.hpp) -FIND_PATH(RXIO_INCLUDE_DIR gpstk/EphReader.hpp) - -SET(GPSTK_NAMES ${GPSTK_NAMES} gpstk libgpstk) -FIND_LIBRARY(GPSTK_LIBRARY NAMES ${GPSTK_NAMES} ) - -SET(GEOMATICS_NAMES ${GEOMATICS_NAMES} geomatics libgeomatics) -FIND_LIBRARY(GEOMATICS_LIBRARY NAMES ${GEOMATICS_NAMES} ) - -SET(PROCFRAME_NAMES ${PROCFRAME_NAMES} procframe libprocframe) -FIND_LIBRARY(PROCFRAME_LIBRARY NAMES ${PROCFRAME_NAMES} ) - -SET(VDRAW_NAMES ${VDRAW_NAMES} vdraw libvdraw) -FIND_LIBRARY(VDRAW_LIBRARY NAMES ${VDRAW_NAMES} ) - -SET(VPLOT_NAMES ${VPLOT_NAMES} vplot libvplot) -FIND_LIBRARY(VPLOT_LIBRARY NAMES ${VPLOT_NAMES} ) - -SET(RXIO_NAMES ${RXIO_NAMES} rxio librxio) -FIND_LIBRARY(RXIO_LIBRARY NAMES ${RXIO_NAMES} ) - -# handle the QUIETLY and REQUIRED arguments and set GPSTK_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GPSTK DEFAULT_MSG GPSTK_LIBRARY GPSTK_INCLUDE_DIR) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GEOMATICS DEFAULT_MSG GEOMATICS_LIBRARY GEOMATICS_INCLUDE_DIR) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROCFRAME DEFAULT_MSG PROCFRAME_LIBRARY PROCFRAME_INCLUDE_DIR) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VDRAW DEFAULT_MSG VDRAW_LIBRARY VDRAW_INCLUDE_DIR) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VPLOT DEFAULT_MSG VPLOT_LIBRARY VPLOT_INCLUDE_DIR) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(RXIO DEFAULT_MSG RXIO_LIBRARY RXIO_INCLUDE_DIR) - -IF(GPSTK_FOUND) - SET( GPSTK_LIBRARIES ${GPSTK_LIBRARY} ) -ENDIF(GPSTK_FOUND) - -IF(GEOMATICS_FOUND) - SET( GEOMATICS_LIBRARIES ${GEOMATICS_LIBRARY} ) -ENDIF(GEOMATICS_FOUND) - -IF(PROCFRAME_FOUND) - SET( PROCFRAME_LIBRARIES ${PROCFRAME_LIBRARY} ) -ENDIF(PROCFRAME_FOUND) - -IF(VDRAW_FOUND) - SET( VDRAW_LIBRARIES ${VDRAW_LIBRARY} ) -ENDIF(VDRAW_FOUND) - -IF(VPLOT_FOUND) - SET( VPLOT_LIBRARIES ${VPLOT_LIBRARY} ) -ENDIF(VPLOT_FOUND) - -IF(RXIO_FOUND) - SET( RXIO_LIBRARIES ${RXIO_LIBRARY} ) -ENDIF(RXIO_FOUND) - -MARK_AS_ADVANCED(GPSTK_INCLUDE_DIR GPSTK_LIBRARY) - -MARK_AS_ADVANCED(GEOMATICS_INCLUDE_DIR GEOMATICS_LIBRARY) - -MARK_AS_ADVANCED(PROCFRAME_INCLUDE_DIR PROCFRAME_LIBRARY) - -MARK_AS_ADVANCED(VDRAW_INCLUDE_DIR VDRAW_LIBRARY) - -MARK_AS_ADVANCED(VPLOT_INCLUDE_DIR VPLOT_LIBRARY) - -MARK_AS_ADVANCED(RXIO_INCLUDE_DIR RXIO_LIBRARY) - - diff --git a/src/utils/gpstk/gnsspvt/README b/src/utils/gpstk/gnsspvt/README deleted file mode 100644 index 6360ac4be..000000000 --- a/src/utils/gpstk/gnsspvt/README +++ /dev/null @@ -1,62 +0,0 @@ -ABOUT GNSSPVT ----------------------- -This program uses the high level GpsTk classes to implement a simple PVT solver -that uses RINEX files as an input. -The output is written both in the console and in a Google Earth KML file. - -HOW TO BUILD GNSSPVT ----------------------- - -Installation in Ubuntu 11.04, 11.10, 12.04 (32 and 64 bits) ------------------------------------------------------------ - -- Install CMake through your OS's package manager or by some other means. - -- Install GpsTk: - - The following procedure will build and install the GPSTk. - - Ensure that prerequisites such as jam have been installed. - Download the GPSTk source distribution from http://www.gpstk.org/bin/view/Documentation/GPSTkDownloads - Extract the GPSTk tarball. For example, using GNU tar - - tar xvzf gpstk.tar.gz - - Change into the gpstk/dev directory (if using Subversion) or the gpstk/ directory (if using the tarball)and type - - jam - - To build the source documentation using doxygen: - - doxygen - - To install GPSTk as a system library in /usr/local, assume root privileges then execute - - jam install - - To install to a different directory, define the environment variable PREFIX to point to the root of the installation - - -- Download, unzip, configure, build and install glog, a Google's library that implements application-level logging: - -$ wget http://google-glog.googlecode.com/files/glog-0.3.2.tar.gz -$ tar xvfz glog-0.3.2.tar.gz -$ cd glog-0.3.2 -$ ./configure -$ make -$ sudo make install - -- Go to GNSSPVT root directory and compile the gnsspvt: - -$ cd gnss-sdr/src/utils/gpstk/gnsspvt/ -$ mkdir build -$ cd build -$ cmake ../ -$ make - -If everything goes well, the executable file is available in the build directory. - -USAGE ----------------------- - -./gnsspvt -i path_to_rinex_observable_file -n path_to_rinex_navigation_file -k path_to_kml_output_file diff --git a/src/utils/gpstk/gnsspvt/src/gnsspvt.cpp b/src/utils/gpstk/gnsspvt/src/gnsspvt.cpp deleted file mode 100644 index 2fc1bbcb8..000000000 --- a/src/utils/gpstk/gnsspvt/src/gnsspvt.cpp +++ /dev/null @@ -1,593 +0,0 @@ -/*! - * \file gnsspvt.cpp - * \brief Adapted version of high level gpstk PVT solver to read RINEX files, - * compute the position, velocity and time solution, and write Google Earth KML output file. - * The input Observables and Navigation files can be RINEX 2.10 or RINEX 3.00. - * It is a modified version of the example5.cpp code provided in gpstk source code. - * - * \author Javier Arribas, 2012. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -// Modified Example program Nro 5 for GPSTk -// This program shows how to use some high-level GPSTk classes - - // Basic input/output C++ class -#include - - // Classes for handling observations RINEX files (data) -#include "gpstk/Rinex3ObsData.hpp" -#include "gpstk/Rinex3ObsStream.hpp" - - // Class to easily extract data from Rinex3ObsData objects -#include "gpstk/ExtractData.hpp" - - // Classes for handling satellite navigation parameters RINEX files - // (Broadcast ephemerides) -#include "gpstk/Rinex3NavHeader.hpp" -#include "gpstk/Rinex3NavData.hpp" -#include "gpstk/Rinex3NavStream.hpp" - - // Class to store satellite broadcast navigation data -#include "gpstk/GPSEphemerisStore.hpp" - - // Class to model GPS data for a mobile receiver -#include "gpstk/ModeledPR.hpp" - -#include "gpstk/GNSSconstants.hpp" -#include "gpstk/CommonTime.hpp" -#include "gpstk/SatID.hpp" -#include "gpstk/Matrix.hpp" -#include "gpstk/XvtStore.hpp" -#include "gpstk/TropModel.hpp" - - // Class to model the tropospheric delays -#include "gpstk/TropModel.hpp" - - // Classes to model ans store ionospheric delays -#include "gpstk/IonoModel.hpp" -#include "gpstk/IonoModelStore.hpp" - - // Class to solve the equations system using a Weighted Least Mean Square method -#include "gpstk/SolverWMS.hpp" - - // Class to compute the weights to be used for each satellite -#include "gpstk/MOPSWeight.hpp" - - // Basic framework for programs in the GPSTk. The 'process()' method MUST - // be implemented -#include "gpstk/BasicFramework.hpp" - -#include "gpstk/geometry.hpp" // DEG_TO_RAD - - // Time-class year-day-second -#include "gpstk/YDSTime.hpp" - -#include "kml_printer_gpstk.h" - -using namespace std; -using namespace gpstk; - - - // A new class is declared that will handle program behaviour - // This class inherits from BasicFramework -class gpstk_solver : public BasicFramework -{ -public: - - // Constructor declaration - gpstk_solver(char* arg0); - ~gpstk_solver(); - -protected: - - // Method that will take care of processing - virtual void process(); - - // Method that hold code to be run BEFORE processing - virtual void spinUp(); - - virtual int Prepare( const CommonTime& Tr, - std::vector& Satellite, - std::vector& Pseudorange, - const XvtStore& Eph ); - virtual int Prepare2( const CommonTime& Tr, - const Vector& Satellite, - const Vector& Pseudorange, - const XvtStore& Eph ); - -private: - - // These field represent options at command line interface (CLI) - CommandOptionWithArg dataFile; - CommandOptionWithArg navFile; - CommandOptionWithArg kmlFile; - - Kml_Printer_gpstk kml_printer; - - // If you want to share objects and variables among methods, you'd - // better declare them here - Rinex3ObsStream rObsFile; // Object to read Rinex observation data files - Rinex3ObsData rData; // Object to store Rinex observation data - Rinex3NavStream rNavFile; // Object to read Rinex navigation data files - Rinex3NavData rNavData; // Object to store Rinex navigation data - Rinex3NavHeader rNavHeader; // Object to read the header of Rinex - // navigation data files - IonoModelStore ionoStore; // Object to store ionospheric models - GPSEphemerisStore bceStore; // Object to store ephemeris - ModeledPR modelPR; // Declare a ModeledReferencePR object - MOPSTropModel mopsTM; // Declare a MOPSTropModel object - ExtractData obsC1; // Declare an ExtractData object - int indexC1; // Index to "C1" observation - bool useFormerPos; // Flag indicating if we have an a priori - // position - Position formerPosition; // Object to store the former position - IonoModel ioModel; // Declare a Ionospheric Model object - SolverWMS solver; // Declare an object to apply WMS method - MOPSWeight mopsWeights; // Object to compute satellites' weights - -}; - - - // Let's implement constructor details -gpstk_solver::gpstk_solver(char* arg0) - : BasicFramework(arg0, "\nProgram to print the position solution in ECEF " - "and longitude, latitude, height, based in C1 and " - "given a RINEX observations file and a RINEX " - "broadcast navigation file.\n\n" - "The output is: \n" - " Time(sec) X(m) Y(m) Z(m) Lon(deg) " - " Lat(deg) Height(m)\n"), - // Option initialization. "true" means a mandatory option - dataFile(CommandOption::stdType, 'i', "datainput", - " [-i|--datainput] Name of RINEX observations file.", true), - navFile(CommandOption::stdType, 'n', "navinput", - " [-n|--navinput] Name of RINEX broadcast navigation file.", true), - kmlFile(CommandOption::stdType, 'k', "kmloutput", - " [-n|--navinput] Name of KML output file.", true) -{ - // These options may appear just once at CLI - dataFile.setMaxCount(1); - navFile.setMaxCount(1); - kmlFile.setMaxCount(1); -} // End of constructor details - - - - /* Method to set an a priori position of receiver using - * Bancroft's method. - * - * @param Tr Time of observation - * @param Satellite std::vector of satellites in view - * @param Pseudorange std::vector of pseudoranges measured from - * rover station to satellites - * @param Eph Satellites Ephemeris - * - * @return - * 0 if OK - * -1 if problems arose - */ - int gpstk_solver::Prepare( const CommonTime& Tr, - std::vector& Satellite, - std::vector& Pseudorange, - const XvtStore& Eph ) - { - - Matrix SVP; - Bancroft Ban; - Vector vPos; - PRSolution2 raimObj; - - try - { - cerr << "Tr=" <::iterator it = Satellite.begin() ; it != Satellite.end(); ++it) - { - cerr << "SatID=" << *it<& Satellite, - const Vector& Pseudorange, - const XvtStore& Eph ) - { - - int i; - std::vector vSat; - std::vector vPR; - - // Convert from gpstk::Vector to std::vector - for (i = 0; i < (int)Satellite.size(); i++) - { - vSat.push_back(Satellite[i]); - } - - for (i = 0; i < (int)Pseudorange.size(); i++) - { - vPR.push_back(Pseudorange[i]); - } - - return Prepare(Tr, vSat, vPR, Eph); - - } // End of method 'ModeledPR::Prepare()' - - - // Method that will be executed AFTER initialization but BEFORE processing -void gpstk_solver::spinUp() -{ - - - //open KML output file - if (kml_printer.set_headers(kmlFile.getValue()[0].c_str())!=true) - { - cerr << "Problem creating the kml file "<> roh; - - // We need the index pointing to C1-type observations - try - { - indexC1 = roh.getObsIndex( "C1" ); - } - catch(...) - { - cerr << "The observation file doesn't have C1 pseudoranges." << endl; - exit(1); - } - - - // Activate failbit to enable exceptions - rNavFile.exceptions(ios::failbit); - - // Read nav file and store unique list of ephemerides - try - { - rNavFile.open(navFile.getValue()[0].c_str(), std::ios::in); - } - catch(...) - { - cerr << "Problem opening file " << navFile.getValue()[0].c_str() << endl; - cerr << "Maybe it doesn't exist or you don't have proper read " - << "permissions." << endl; - - exit (-1); - } - - // We will need to read ionospheric parameters (Klobuchar model) from - // the file header - rNavFile >> rNavHeader; - - // Let's feed the ionospheric model (Klobuchar type) from data in the - // navigation (ephemeris) file header. First, we must check if there are - // valid ionospheric correction parameters in the header - if(rNavHeader.valid & Rinex3NavHeader::validIonoCorrGPS) - { - // Extract the Alpha and Beta parameters from the header - double* ionAlpha = rNavHeader.mapIonoCorr["GPSA"].param; - double* ionBeta = rNavHeader.mapIonoCorr["GPSB"].param; - - // Feed the ionospheric model with the parameters - ioModel.setModel(ionAlpha, ionBeta); - } - else - { - cerr << "WARNING: Navigation file " << navFile.getValue()[0].c_str() - << " doesn't have valid ionospheric correction parameters." << endl; - } - - // WARNING-WARNING-WARNING: In this case, the same model will be used - // for the full data span - ionoStore.addIonoModel(CommonTime::BEGINNING_OF_TIME, ioModel); - - // Storing the ephemeris in "bceStore" - while (rNavFile >> rNavData) - { - bceStore.addEphemeris(rNavData); - rNavData.dump(cerr); - cerr<> rData ) - { - - // Begin usable data with enough number of satellites - if( (rData.epochFlag == 0 || rData.epochFlag == 1) && - (rData.numSVs > 3) ) - { - - // Number of satellites with valid data in this epoch - int validSats = 0; - int prepareResult; - double rxAltitude; // Receiver altitude for tropospheric model - double rxLatitude; // Receiver latitude for tropospheric model - - // We need to extract C1 data from this epoch. Skip epoch if not - // enough data (4 SV at least) is available - if( obsC1.getData(rData, indexC1) < 4 ) - { - // The former position will not be valid next time - useFormerPos = false; - continue; - } - - - // If possible, use former position as a priori - if( useFormerPos ) - { - - prepareResult = modelPR.Prepare(formerPosition); - - // We need to seed this kind of tropospheric model with - // receiver altitude - rxAltitude = formerPosition.getAltitude(); - rxLatitude = formerPosition.getGeodeticLatitude(); - - } - else - { - // Use Bancroft method is no a priori position is available - cerr << "Bancroft method was used at epoch " - << static_cast(rData.time).sod << endl; - - Prepare2( rData.time,obsC1.availableSV,obsC1.obsData,bceStore ); - prepareResult = modelPR.Prepare( rData.time, - obsC1.availableSV, - obsC1.obsData, - bceStore ); - - // We need to seed this kind of tropospheric model with - // receiver altitude - rxAltitude = modelPR.rxPos.getAltitude(); - rxLatitude = modelPR.rxPos.getGeodeticLatitude(); - } - - // If there were problems with Prepare(), skip this epoch - if( prepareResult ) - { - // The former position will not be valid next time - useFormerPos = false; - continue; - } - - // If there were no problems, let's feed the tropospheric model - mopsTM.setReceiverHeight(rxAltitude); - mopsTM.setReceiverLatitude(rxLatitude); - mopsTM.setDayOfYear(static_cast(rData.time).doy); - - - // Now, let's compute the GPS model for our observable (C1) - validSats = modelPR.Compute( rData.time, - obsC1.availableSV, - obsC1.obsData, - bceStore, - &mopsTM, - &ionoStore ); - - // Only get into further computations if there are enough - // satellites - if( validSats >= 4 ) - { - - // Now let's solve the navigation equations using the WMS method - try - { - // First, compute the satellites' weights - int goodSv = mopsWeights.getWeights( rData.time, - modelPR.availableSV, - bceStore, - modelPR.ionoCorrections, - modelPR.elevationSV, - modelPR.azimuthSV, - modelPR.rxPos ); - - // Some minimum checking is in order - if ( goodSv != (int)modelPR.prefitResiduals.size() ) continue; - - // Then, solve the system - solver.Compute( modelPR.prefitResiduals, - modelPR.geoMatrix, - mopsWeights.weightsVector ); - - } - catch( InvalidSolver& e ) - { - cerr << "Couldn't solve equations system at epoch " - << static_cast(rData.time).sod << endl; - cerr << e << endl; - - // The former position will not be valid next time - useFormerPos = false; - continue; - } - - // With "solver", we got the difference vector between the - // a priori position and the computed, 'real' position. Then, - // let's convert the solution to a Position object - Position solPos( (modelPR.rxPos.X() + solver.solution[0]), - (modelPR.rxPos.Y() + solver.solution[1]), - (modelPR.rxPos.Z() + solver.solution[2]) ); - - // Print results - cout << static_cast(rData.time).sod - << " "; // Output field #1 - cout << "X="<= 4 )' - else - { - // The former position will not be valid next time - useFormerPos = false; - } - - } // End of 'if( (rData.epochFlag == 0 || rData.epochFlag == 1) &&...' - else - { - // The former position will not be valid next time - useFormerPos = false; - } - - } // End of 'while( rObsFile >> rData )' - - return; - -} // End of 'gpstk_solver::process()' - -gpstk_solver::~gpstk_solver() -{ - kml_printer.close_file(); -} - // Main function -int main(int argc, char* argv[]) -{ - - try - { - gpstk_solver program(argv[0]); - if (!program.initialize(argc, argv)) - return 0; - if (!program.run()) - return 1; - - return 0; - } - catch(Exception& e) - { - cout << "Problem: " << e << endl; - return 1; - } - catch(...) - { - cout << "Unknown error." << endl; - return 1; - } - - return 0; - -} // End of 'main()' diff --git a/src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.cpp b/src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.cpp deleted file mode 100644 index 44c00fb42..000000000 --- a/src/utils/gpstk/gnsspvt/src/kml_printer_gpstk.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/*! - * \file kml_printer.cc - * \brief Implementation of a class that prints PVT information to a kml file - * for GPSTK data structures - * \author Javier Arribas, 2012. jarribas(at)cttc.es - * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "kml_printer_gpstk.h" -#include -#include -#include - -bool Kml_Printer_gpstk::set_headers(std::string filename) -{ - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); - kml_file.open(filename.c_str()); - if (kml_file.is_open()) - { - DLOG(INFO) << "KML printer writing on " << filename.c_str(); - // Set iostream numeric format and precision - kml_file.setf(kml_file.fixed,kml_file.floatfield); - kml_file << std::setprecision(14); - kml_file << "" << std::endl - << "" << std::endl - << " " << std::endl - << " GNSS Track" << std::endl - << " GNSS-SDR Receiver position log file created at " << asctime (timeinfo) - << " " << std::endl - << "" << std::endl - << "" << std::endl - << "GNSS-SDR PVT" << std::endl - << "GNSS-SDR position log" << std::endl - << "#yellowLineGreenPoly" << std::endl - << "" << std::endl - << "0" << std::endl - << "1" << std::endl - << "absolute" << std::endl - << "" << std::endl; - return true; - } - else - { - return false; - } -} - - - -bool Kml_Printer_gpstk::print_position(gpstk::Position position) -{ - double latitude; - double longitude; - double height; - latitude = position.geodeticLatitude(); - longitude = position.getLongitude(); - if (longitude>190) - { - longitude=longitude-360; - } - height = position.getHeight(); - - if (kml_file.is_open()) - { - kml_file << longitude << "," << latitude << "," << height << std::endl; - return true; - } - else - { - return false; - } -} - - - -bool Kml_Printer_gpstk::close_file() -{ - if (kml_file.is_open()) - { - kml_file << "" << std::endl - << "" << std::endl - << "" << std::endl - << "" << std::endl - << ""; - kml_file.close(); - return true; - } - else - { - return false; - } -} - - - -Kml_Printer_gpstk::Kml_Printer_gpstk () {} - - - -Kml_Printer_gpstk::~Kml_Printer_gpstk () {} - diff --git a/src/utils/matlab/dll_pll_veml_plot_sample.m b/src/utils/matlab/dll_pll_veml_plot_sample.m new file mode 100644 index 000000000..011044a9f --- /dev/null +++ b/src/utils/matlab/dll_pll_veml_plot_sample.m @@ -0,0 +1,83 @@ +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% Antonio Ramos, 2018. antonio.ramos(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('dll_pll_veml_read_tracking_dump.m', 'file') + addpath('./libs') +end + +samplingFreq = 5000000; %[Hz] +coherent_integration_time_ms = 20; %[ms] +channels = 5; % Number of channels +first_channel = 0; % Number of the first channel + +path = '/dump_dir/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'track_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE track_ch_ BY YOUR dump_filename + GNSS_tracking(N) = dll_pll_veml_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).P.'; + trackResults(N).Q_P = zeros(1,length(GNSS_tracking(N).P)); + + trackResults(N).I_VE = GNSS_tracking(N).VE.'; + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).I_VL = GNSS_tracking(N).VL.'; + trackResults(N).Q_VE = zeros(1,length(GNSS_tracking(N).VE)); + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).L)); + trackResults(N).Q_VL = zeros(1,length(GNSS_tracking(N).VL)); + trackResults(N).data_I = GNSS_tracking(N).prompt_I.'; + trackResults(N).data_Q = GNSS_tracking(N).prompt_Q.'; + trackResults(N).PRN = GNSS_tracking(N).PRN.'; + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E) * coherent_integration_time_ms; + plotVEMLTracking(N, trackResults, settings) +end + + + diff --git a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m new file mode 100644 index 000000000..08223b8d0 --- /dev/null +++ b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m @@ -0,0 +1,79 @@ +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('dll_pll_veml_read_tracking_dump.m', 'file') + addpath('./libs') +end + +samplingFreq = 5000000; %[Hz] +channels = 7; % Number of channels +first_channel = 0; % Number of the first channel + +path = '/Users/carlesfernandez/git/cttc/build/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'track_ch' num2str(N+first_channel-1) '.dat']; %% CHANGE track_ch BY YOUR dump_filename + GNSS_tracking(N) = dll_pll_veml_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; + + trackResults(N).I_VE = GNSS_tracking(N).VE.'; + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).I_VL = GNSS_tracking(N).VL.'; + trackResults(N).Q_VE = zeros(1,length(GNSS_tracking(N).VE)); + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).L)); + trackResults(N).Q_VL = zeros(1,length(GNSS_tracking(N).VL)); + trackResults(N).PRN = GNSS_tracking(N).PRN.'; + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E)*4; + plotVEMLTracking(N, trackResults, settings) +end + + + diff --git a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_32bits.m b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_32bits.m deleted file mode 100644 index 6acbc3268..000000000 --- a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_32bits.m +++ /dev/null @@ -1,93 +0,0 @@ -% /*! -% * \file galileo_l1_ca_dll_pll_vml_plot_sample_64bits.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -close all; -clear all; -samplingFreq = 20480000/4; %[Hz] -channels=8; -%path='/home/javier/workspace/gnss-sdr/trunk/install/'; -path='/home/gnss/workspace/gnss-sdr/trunk/data/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - tracking_log_path=[path 'veml_tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= galileo_e1_dll_pll_veml_read_tracking_dump_32bits(tracking_log_path); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver - -for N=1:1:channels - trackResults(N).status = 'T'; %fake track - trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; - trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; - trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; - trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; - trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; - trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; - - trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; - trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; - - trackResults(N).I_VE = GNSS_tracking(N).VE.'; - trackResults(N).I_E = GNSS_tracking(N).E.'; - trackResults(N).I_L = GNSS_tracking(N).L.'; - trackResults(N).I_VL = GNSS_tracking(N).VL.'; - trackResults(N).Q_VE = zeros(1,length(GNSS_tracking(N).VE)); - trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).L)); - trackResults(N).Q_VL = zeros(1,length(GNSS_tracking(N).VL)); - trackResults(N).PRN = N; %fake PRN - - % Use original MATLAB tracking plot function - settings.numberOfChannels = channels; - settings.msToProcess = length(GNSS_tracking(N).E)*4; - plotVEMLTracking(N,trackResults,settings) -end - -% for N=1:1:channels -% % figure; -% % plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% % title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% % figure; -% % plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% % title(['Navigation constellation plot for channel ' num2str(N)]); -% % figure; -% % -% % plot(GNSS_tracking(N).prompt_Q,'r'); -% % hold on; -% % plot(GNSS_tracking(N).prompt_I); -% % title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% % -% figure; -% t=0:4:length(GNSS_tracking(N).carrier_doppler_hz)*4-1; -% t=t/1000; -% plot(t,GNSS_tracking(N).carrier_doppler_hz/1000); -% xlabel('Time(s)');ylabel('Doppler(KHz)');title(['Doppler frequency channel ' num2str(N)]); -% end - - diff --git a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_64bits.m b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_64bits.m deleted file mode 100644 index 798b5f30b..000000000 --- a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample_64bits.m +++ /dev/null @@ -1,93 +0,0 @@ -% /*! -% * \file galileo_l1_ca_dll_pll_vml_plot_sample_64bits.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -close all; -clear all; -samplingFreq = 64e6/8; %[Hz] -channels=1; -%path='/home/javier/workspace/gnss-sdr/trunk/install/'; -path='/home/luis/dev/gnss-sdr/trunk/data/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - tracking_log_path=[path 'veml_tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= galileo_e1_dll_pll_veml_read_tracking_dump(tracking_log_path); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver - -for N=1:1:channels - trackResults(N).status='T'; %fake track - trackResults(N).codeFreq=GNSS_tracking(N).code_freq_hz.'; - trackResults(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz.'; - trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; - trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; - trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; - trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; - - trackResults(N).I_P=GNSS_tracking(N).prompt_I.'; - trackResults(N).Q_P=GNSS_tracking(N).prompt_Q.'; - - trackResults(N).I_VE= GNSS_tracking(N).VE.'; - trackResults(N).I_E= GNSS_tracking(N).E.'; - trackResults(N).I_L = GNSS_tracking(N).L.'; - trackResults(N).I_VL = GNSS_tracking(N).VL.'; - trackResults(N).Q_VE = zeros(1,length(GNSS_tracking(N).VE)); - trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).Q_L =zeros(1,length(GNSS_tracking(N).L)); - trackResults(N).Q_VL =zeros(1,length(GNSS_tracking(N).VL)); - trackResults(N).PRN=N; %fake PRN - - % Use original MATLAB tracking plot function - settings.numberOfChannels=channels; - settings.msToProcess=length(GNSS_tracking(N).E)*4; - plotVEMLTracking(N,trackResults,settings) -end - -% for N=1:1:channels -% % figure; -% % plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% % title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% % figure; -% % plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% % title(['Navigation constellation plot for channel ' num2str(N)]); -% % figure; -% % -% % plot(GNSS_tracking(N).prompt_Q,'r'); -% % hold on; -% % plot(GNSS_tracking(N).prompt_I); -% % title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% % -% figure; -% t=0:4:length(GNSS_tracking(N).carrier_doppler_hz)*4-1; -% t=t/1000; -% plot(t,GNSS_tracking(N).carrier_doppler_hz/1000); -% xlabel('Time(s)');ylabel('Doppler(KHz)');title(['Doppler frequency channel ' num2str(N)]); -% end - - diff --git a/src/utils/matlab/galileo_e1b_observables_plot_sample.m b/src/utils/matlab/galileo_e1b_observables_plot_sample.m deleted file mode 100644 index 604be3fe3..000000000 --- a/src/utils/matlab/galileo_e1b_observables_plot_sample.m +++ /dev/null @@ -1,22 +0,0 @@ -% Read observables dump - -clear all; -close all; - -%IFEN NSR Sampler Fs=20480000 -% GNSS-SDR decimation factor 8 -samplingFreq = 20480000/8; %[Hz] -channels=4; -path='/home/gnss/workspace/gnss-sdr/trunk/install/'; -observables_log_path=[path 'observables.dat']; -GNSS_observables= gps_l1_ca_read_observables_dump(channels,observables_log_path); - - -skip=9000; -ref_channel=1; -plot(GNSS_observables.d_TOW_at_current_symbol(ref_channel,skip:end),GNSS_observables.Pseudorange_m(:,skip:end).') -title('psudoranges'); -figure -plot(GNSS_observables.d_TOW_at_current_symbol(ref_channel,skip:end),GNSS_observables.Prn_timestamp_ms(:,skip:end).') -title('Prn_timestamps'); - \ No newline at end of file diff --git a/src/utils/matlab/galileo_e5a_dll_pll_plot_sample.m b/src/utils/matlab/galileo_e5a_dll_pll_plot_sample.m new file mode 100644 index 000000000..925e709c0 --- /dev/null +++ b/src/utils/matlab/galileo_e5a_dll_pll_plot_sample.m @@ -0,0 +1,95 @@ +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, Marc Sales 2014. jarribas(at)cttc.es, marcsales92@gmail.com +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('gps_l1_ca_dll_pll_read_tracking_dump.m','file') + addpath('./libs') +end + + +samplingFreq = 5000000; %[Hz] +channels = 1; +first_channel = 30; + +path = '/Users/carlesfernandez/git/cttc/build/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE tracking_ch_ BY YOUR dump_filename + GNSS_tracking(N) = gps_l1_ca_dll_pll_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_PN = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_PN = GNSS_tracking(N).prompt_Q.'; + trackResults(N).Q_P = zeros(1,length(GNSS_tracking(N).P)); + trackResults(N).I_P = GNSS_tracking(N).P.'; + + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).PRN = GNSS_tracking(N).PRN.'; + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E); + plotTrackingE5a(N, trackResults, settings) +end + +for N=1:1:channels + % figure; + % plot([GNSS_tracking(N).E, GNSS_tracking(N).P, GNSS_tracking(N).L],'-*'); + % title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); + % figure; + % plot(GNSS_tracking(N).prompt_I, GNSS_tracking(N).prompt_Q, '+'); + % title(['Navigation constellation plot for channel ' num2str(N)]); + % figure; + % + % plot(GNSS_tracking(N).prompt_Q,'r'); + % hold on; + % plot(GNSS_tracking(N).prompt_I); + % title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); + % + figure; + t = 0:length(GNSS_tracking(N).carrier_doppler_hz)-1; + t = t/1000; + plot(t, GNSS_tracking(N).carrier_doppler_hz / 1000); + xlabel('Time(s)'); ylabel('Doppler(KHz)'); title(['Doppler frequency channel ' num2str(N)]); +end diff --git a/src/utils/matlab/galileo_e5a_dll_pll_plot_sample_64bits.m b/src/utils/matlab/galileo_e5a_dll_pll_plot_sample_64bits.m deleted file mode 100644 index 6a4c993e3..000000000 --- a/src/utils/matlab/galileo_e5a_dll_pll_plot_sample_64bits.m +++ /dev/null @@ -1,90 +0,0 @@ -% /*! -% * \file galileo_e5a_dll_pll_plot_sample_64bits.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, Marc Sales 2014. jarribas(at)cttc.es -% marcsales92@gmail.com -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -close all; -clear all; -samplingFreq = 64e6/32; %[Hz] -channels=1; -%path='/home/javier/workspace/gnss-sdr/trunk/install/'; -path='/home/marc/git/gnss-sdr/data/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - tracking_log_path=[path 'e5a_tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= gps_l1_ca_dll_pll_read_tracking_dump_64bits(tracking_log_path); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver - -for N=1:1:channels - trackResults(N).status='T'; %fake track - trackResults(N).codeFreq=GNSS_tracking(N).code_freq_hz.'; - trackResults(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz.'; - trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; - trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; - trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; - trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; - - trackResults(N).I_PN=GNSS_tracking(N).prompt_I.'; - trackResults(N).Q_PN=GNSS_tracking(N).prompt_Q.'; - trackResults(N).Q_P=zeros(1,length(GNSS_tracking(N).P)); - trackResults(N).I_P=GNSS_tracking(N).P.'; - - trackResults(N).I_E= GNSS_tracking(N).E.'; - trackResults(N).I_L = GNSS_tracking(N).L.'; - trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).Q_L =zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).PRN=N; %fake PRN - - % Use original MATLAB tracking plot function - settings.numberOfChannels=channels; - settings.msToProcess=length(GNSS_tracking(N).E); - plotTrackingE5a(N,trackResults,settings) -end - -for N=1:1:channels -% figure; -% plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% figure; -% plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% title(['Navigation constellation plot for channel ' num2str(N)]); -% figure; -% -% plot(GNSS_tracking(N).prompt_Q,'r'); -% hold on; -% plot(GNSS_tracking(N).prompt_I); -% title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% - figure; - t=0:length(GNSS_tracking(N).carrier_doppler_hz)-1; - t=t/1000; - plot(t,GNSS_tracking(N).carrier_doppler_hz/1000); - xlabel('Time(s)');ylabel('Doppler(KHz)');title(['Doppler frequency channel ' num2str(N)]); -end \ No newline at end of file diff --git a/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m b/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m new file mode 100644 index 000000000..a0018286b --- /dev/null +++ b/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m @@ -0,0 +1,73 @@ +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Damian Miralles, 2017. dmiralles2009(at)gmail.com +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('dll_pll_veml_read_tracking_dump.m', 'file') + addpath('./libs') +end + + +samplingFreq = 6625000; %[Hz] +channels = 5; +first_channel = 0; + +path = '/archive/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'glo_tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE glo_tracking_ch_ BY YOUR dump_filename + GNSS_tracking(N) = dll_pll_veml_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_freq_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; + + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + trackResults(N).PRN = ones(1,length(GNSS_tracking(N).E)); + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E); + plotTracking(N, trackResults, settings) +end diff --git a/src/utils/matlab/gps_l1_ca_dll_fll_pll_plot_sample.m b/src/utils/matlab/gps_l1_ca_dll_fll_pll_plot_sample.m deleted file mode 100644 index 155bc5cf0..000000000 --- a/src/utils/matlab/gps_l1_ca_dll_fll_pll_plot_sample.m +++ /dev/null @@ -1,88 +0,0 @@ -% /*! -% * \file gps_l1_ca_dll_fll_pll_plot_sample.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -%close all; -%clear all; -samplingFreq = 64e6/16; %[Hz] -channels=4; -path='/home/javier/workspace/gnss-sdr-ref/trunk/install/'; -for N=1:1:channels - tracking_log_path=[path 'tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= gps_l1_ca_dll_fll_pll_read_tracking_dump(tracking_log_path,samplingFreq); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver -channel_PRN_ID=[32,14,20,11]; -tracking_loop_start=1;%10001; -tracking_loop_end=70000; -for N=1:1:channels - trackResults_sdr(N).status='T'; %fake track - trackResults_sdr(N).codeFreq=GNSS_tracking(N).code_freq_hz(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).dllDiscr = GNSS_tracking(N).code_error_chips(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).dllDiscrFilt = GNSS_tracking(N).code_phase_samples(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).pllDiscr = GNSS_tracking(N).PLL_discriminator_hz(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).pllDiscrFilt = GNSS_tracking(N).carr_nco(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).absoluteSample = (GNSS_tracking(N).var2(tracking_loop_start:tracking_loop_end)+GNSS_tracking(N).var1(tracking_loop_start:tracking_loop_end)).'; - - trackResults_sdr(N).prn_delay_ms = 1000*trackResults_sdr(N).absoluteSample/samplingFreq; - %trackResults_sdr(N).absoluteSample = (GNSS_tracking(N).PRN_start_sample(tracking_loop_start:tracking_loop_end)+GNSS_tracking(N).var1(tracking_loop_start:tracking_loop_end)).'; - - trackResults_sdr(N).I_P=GNSS_tracking(N).prompt_I(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).Q_P=GNSS_tracking(N).prompt_Q(tracking_loop_start:tracking_loop_end).'; - - trackResults_sdr(N).I_E= GNSS_tracking(N).E(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).I_L = GNSS_tracking(N).L(tracking_loop_start:tracking_loop_end).'; - trackResults_sdr(N).Q_E = zeros(1,tracking_loop_end-tracking_loop_start+1); - trackResults_sdr(N).Q_L =zeros(1,tracking_loop_end-tracking_loop_start+1); - trackResults_sdr(N).PRN=channel_PRN_ID(N); - - % Use original MATLAB tracking plot function - settings.numberOfChannels=channels; - settings.msToProcess=tracking_loop_end-tracking_loop_start+1; - %plotTracking(N,trackResults_sdr,settings) -end - - -% for N=1:1:channels -% figure; -% plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% figure; -% plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% title(['Navigation constellation plot for channel ' num2str(N)]); -% figure; -% -% plot(GNSS_tracking(N).prompt_Q,'r'); -% hold on; -% plot(GNSS_tracking(N).prompt_I); -% title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% end - - diff --git a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m b/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m index faf136e42..e2f1f544b 100644 --- a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m +++ b/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m @@ -1,82 +1,75 @@ -% /*! -% * \file gps_l1_ca_dll_pll_plot_sample.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -close all; -clear all; -samplingFreq = 64e6/16; %[Hz] -channels=4; -path='/home/javier/workspace/gnss-sdr/trunk/install/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - tracking_log_path=[path 'tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= gps_l1_ca_dll_pll_read_tracking_dump(tracking_log_path); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver - -for N=1:1:channels - trackResults(N).status='T'; %fake track - trackResults(N).codeFreq=GNSS_tracking(N).code_freq_hz.'; - trackResults(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz.'; - trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; - trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; - trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; - trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; - - trackResults(N).I_P=GNSS_tracking(N).prompt_I.'; - trackResults(N).Q_P=GNSS_tracking(N).prompt_Q.'; - - trackResults(N).I_E= GNSS_tracking(N).E.'; - trackResults(N).I_L = GNSS_tracking(N).L.'; - trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).Q_L =zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).PRN=N; %fake PRN - - % Use original MATLAB tracking plot function - settings.numberOfChannels=channels; - settings.msToProcess=length(GNSS_tracking(N).E); - plotTracking(N,trackResults,settings) -end - -% for N=1:1:channels -% figure; -% plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% figure; -% plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% title(['Navigation constellation plot for channel ' num2str(N)]); -% figure; -% -% plot(GNSS_tracking(N).prompt_Q,'r'); -% hold on; -% plot(GNSS_tracking(N).prompt_I); -% title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% end - - +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('dll_pll_veml_read_tracking_dump.m', 'file') + addpath('./libs') +end + + +samplingFreq = 6625000; %[Hz] +channels = 5; +first_channel = 0; + +path = '/archive/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'epl_tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE epl_tracking_ch_ BY YOUR dump_filename + GNSS_tracking(N) = dll_pll_veml_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; + + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).PRN = ones(1,length(GNSS_tracking(N).E)); + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E); + plotTracking(N, trackResults, settings) +end + + diff --git a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample_64bits.m b/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample_64bits.m deleted file mode 100644 index b3ed5ca33..000000000 --- a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample_64bits.m +++ /dev/null @@ -1,89 +0,0 @@ -% /*! -% * \file gps_l1_ca_dll_pll_plot_sample_64bits.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -close all; -clear all; -samplingFreq = 64e6/32; %[Hz] -channels=1; -%path='/home/javier/workspace/gnss-sdr/trunk/install/'; -path='/home/luis/dev/gnss-sdr/trunk/data/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - tracking_log_path=[path 'tracking_ch_' num2str(N-1) '.dat']; - GNSS_tracking(N)= gps_l1_ca_dll_pll_read_tracking_dump_64bits(tracking_log_path); -end - -% GNSS-SDR format conversion to MATLAB GPS receiver - -for N=1:1:channels - trackResults(N).status='T'; %fake track - trackResults(N).codeFreq=GNSS_tracking(N).code_freq_hz.'; - trackResults(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz.'; - trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; - trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; - trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; - trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; - - trackResults(N).I_P=GNSS_tracking(N).prompt_I.'; - trackResults(N).Q_P=GNSS_tracking(N).prompt_Q.'; - - trackResults(N).I_E= GNSS_tracking(N).E.'; - trackResults(N).I_L = GNSS_tracking(N).L.'; - trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).Q_L =zeros(1,length(GNSS_tracking(N).E)); - trackResults(N).PRN=N; %fake PRN - - % Use original MATLAB tracking plot function - settings.numberOfChannels=channels; - settings.msToProcess=length(GNSS_tracking(N).E); - plotTracking(N,trackResults,settings) -end - -for N=1:1:channels -% figure; -% plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*'); -% title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']); -% figure; -% plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+'); -% title(['Navigation constellation plot for channel ' num2str(N)]); -% figure; -% -% plot(GNSS_tracking(N).prompt_Q,'r'); -% hold on; -% plot(GNSS_tracking(N).prompt_I); -% title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]); -% - figure; - t=0:length(GNSS_tracking(N).carrier_doppler_hz)-1; - t=t/1000; - plot(t,GNSS_tracking(N).carrier_doppler_hz/1000); - xlabel('Time(s)');ylabel('Doppler(KHz)');title(['Doppler frequency channel ' num2str(N)]); -end - - diff --git a/src/utils/matlab/gps_l1_ca_kf_plot_sample.m b/src/utils/matlab/gps_l1_ca_kf_plot_sample.m new file mode 100644 index 000000000..f8fcb0ed7 --- /dev/null +++ b/src/utils/matlab/gps_l1_ca_kf_plot_sample.m @@ -0,0 +1,93 @@ +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +close all; +clear all; + +if ~exist('dll_pll_veml_read_tracking_dump.m', 'file') + addpath('./libs') +end + + +samplingFreq = 6625000; %[Hz] +channels = 8; +first_channel = 0; +code_period = 0.001; + +path = '/archive/'; %% CHANGE THIS PATH +figpath = [path]; + +for N=1:1:channels + tracking_log_path = [path 'epl_tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE epl_tracking_ch_ BY YOUR dump_filename + GNSS_tracking(N) = gps_l1_ca_kf_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_doppler_hz.'; + trackResults(N).carrFreqRate = GNSS_tracking(N).carrier_dopplerrate_hz2.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; + + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).PRN = GNSS_tracking(N).PRN.'; + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + + + kalmanResults(N).PRN = GNSS_tracking(N).PRN.'; + kalmanResults(N).innovation = GNSS_tracking(N).carr_error.'; + kalmanResults(N).state1 = GNSS_tracking(N).carr_nco.'; + kalmanResults(N).state2 = GNSS_tracking(N).carrier_doppler_hz.'; + kalmanResults(N).state3 = GNSS_tracking(N).carrier_dopplerrate_hz2.'; + kalmanResults(N).r_noise_cov = GNSS_tracking(N).carr_noise_sigma2.'; + kalmanResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E); + settings.codePeriod = code_period; + settings.timeStartInSeconds = 20; + + %plotTracking(N, trackResults, settings) + plotKalman(N, kalmanResults, settings) + + saveas(gcf, [figpath 'epl_tracking_ch_' num2str(N) '_PRN_' num2str(trackResults(N).PRN(end)) '.png'], 'png') +end + + diff --git a/src/utils/matlab/gps_l1_ca_observables_plot_sample.m b/src/utils/matlab/gps_l1_ca_observables_plot_sample.m deleted file mode 100644 index c7a85a60f..000000000 --- a/src/utils/matlab/gps_l1_ca_observables_plot_sample.m +++ /dev/null @@ -1,9 +0,0 @@ -% Read observables dump - -%clear all; - -samplingFreq = 64e6/16; %[Hz] -channels=4; -path='/home/gnss/workspace/gnss-sdr/trunk/install/'; -observables_log_path=[path 'observables.dat']; -GNSS_observables= gps_l1_ca_read_observables_dump(channels,observables_log_path); diff --git a/src/utils/matlab/gps_l1_ca_pvt_plot_sample_agilent_cap2.m b/src/utils/matlab/gps_l1_ca_pvt_plot_sample_agilent_cap2.m index aa26c38ae..e4dcc91d2 100644 --- a/src/utils/matlab/gps_l1_ca_pvt_plot_sample_agilent_cap2.m +++ b/src/utils/matlab/gps_l1_ca_pvt_plot_sample_agilent_cap2.m @@ -1,32 +1,30 @@ -% /*! -% * \file gps_l1_ca_pvt_plot_sample.m -% * \brief Read GNSS-SDR PVT dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ +% Reads GNSS-SDR PVT dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% close all; clear all; @@ -63,17 +61,17 @@ h=35; [X, Y, Z]=geo2cart(lat, long, h, 5); % geographical to cartesian conversion %=== Convert to UTM coordinate system ============================= -utmZone = findUtmZone(lat_deg, long_deg); +utmZone = findUtmZone(lat_deg, long_deg); - [settings.truePosition.E, ... - settings.truePosition.N, ... - settings.truePosition.U] = cart2utm(X, Y, Z, utmZone); +[settings.truePosition.E, ... + settings.truePosition.N, ... + settings.truePosition.U] = cart2utm(X, Y, Z, utmZone); for k=1:1:length(navSolutions.X) [navSolutions.E(k), ... - navSolutions.N(k), ... - navSolutions.U(k)]=cart2utm(navSolutions.X(k), navSolutions.Y(k), navSolutions.Z(k), utmZone); + navSolutions.N(k), ... + navSolutions.U(k)]=cart2utm(navSolutions.X(k), navSolutions.Y(k), navSolutions.Z(k), utmZone); end plot_skyplot=0; diff --git a/src/utils/matlab/gps_l1_ca_pvt_raw_plot_sample.m b/src/utils/matlab/gps_l1_ca_pvt_raw_plot_sample.m index 74f620a36..8dd572ba1 100644 --- a/src/utils/matlab/gps_l1_ca_pvt_raw_plot_sample.m +++ b/src/utils/matlab/gps_l1_ca_pvt_raw_plot_sample.m @@ -1,4 +1,28 @@ % Read PVG raw dump +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% %clear all; @@ -6,4 +30,4 @@ samplingFreq = 64e6/16; %[Hz] channels=4; path='/home/javier/workspace/gnss-sdr-ref/trunk/install/'; pvt_raw_log_path=[path 'PVT_raw.dat']; -GNSS_PVT_raw= gps_l1_ca_read_pvt_raw_dump(channels,pvt_raw_log_path); +GNSS_PVT_raw= gps_l1_ca_read_pvt_raw_dump(channels,pvt_raw_log_path); diff --git a/src/utils/matlab/gps_l1_ca_telemetry_plot_sample.m b/src/utils/matlab/gps_l1_ca_telemetry_plot_sample.m index b5e60acc1..f25ab5d21 100644 --- a/src/utils/matlab/gps_l1_ca_telemetry_plot_sample.m +++ b/src/utils/matlab/gps_l1_ca_telemetry_plot_sample.m @@ -1,40 +1,39 @@ -% /*! -% * \file gps_l1_ca_dll_fll_pll_plot_sample.m -% * \brief Read GNSS-SDR Tracking dump binary file using the provided -% function and plot some internal variables -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -%close all; -%clear all; -samplingFreq = 64e6/16; %[Hz] -channels=4; -path='/home/javier/workspace/gnss-sdr-ref/trunk/install/'; -clear PRN_absolute_sample_start; -for N=1:1:channels - telemetry_log_path=[path 'telemetry' num2str(N-1) '.dat']; - GNSS_telemetry(N)= gps_l1_ca_read_telemetry_dump(telemetry_log_path); -end - +% Reads GNSS-SDR Tracking dump binary file using the provided +% function and plots some internal variables +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +%close all; +%clear all; +samplingFreq = 64e6/16; %[Hz] +channels=4; +path='/home/javier/workspace/gnss-sdr-ref/trunk/install/'; +clear PRN_absolute_sample_start; +for N=1:1:channels + telemetry_log_path=[path 'telemetry' num2str(N-1) '.dat']; + GNSS_telemetry(N)= gps_l1_ca_read_telemetry_dump(telemetry_log_path); +end + diff --git a/src/utils/matlab/help_script1.m b/src/utils/matlab/help_script1.m index 2c08a8d91..575641bcf 100644 --- a/src/utils/matlab/help_script1.m +++ b/src/utils/matlab/help_script1.m @@ -1,3 +1,28 @@ +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + %help script to compare GNSS-SDR Preambles starts channel=3; % From GNSS_SDR telemetry decoder @@ -25,9 +50,9 @@ error_ms=preambles_timestamp_sdr_ms(common_start_index:(common_start_index+lengt % figure % stem(tracking_loop_start+javi_subFrameStart_sample(channel,:),1000*trackResults_sdr(channel).absoluteSample(javi_subFrameStart_sample(channel,:))/settings.samplingFreq); -% +% % hold on; -% +% % plot(GNSS_observables.preamble_delay_ms(channel,:)); -% -% plot(GNSS_observables.prn_delay_ms(channel,:),'r') \ No newline at end of file +% +% plot(GNSS_observables.prn_delay_ms(channel,:),'r') diff --git a/src/utils/matlab/help_script2.m b/src/utils/matlab/help_script2.m index 4be6bfbb8..8f9cd12bd 100644 --- a/src/utils/matlab/help_script2.m +++ b/src/utils/matlab/help_script2.m @@ -1,4 +1,29 @@ -% compare pseudoranges +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +% compare pseudoranges close all; % GNSS SDR diff --git a/src/utils/matlab/hybrid_observables_plot_sample.m b/src/utils/matlab/hybrid_observables_plot_sample.m new file mode 100644 index 000000000..9105c5bbd --- /dev/null +++ b/src/utils/matlab/hybrid_observables_plot_sample.m @@ -0,0 +1,141 @@ +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +% Read observables dump + +%clear all; +clearvars; +close all; +addpath('./libs'); +samplingFreq = 6625000; %[Hz] +channels=5; +path='/archive/'; +observables_log_path=[path 'glo_observables.dat']; +GNSS_observables= read_hybrid_observables_dump(channels,observables_log_path); + +%% +%optional: +%search all channels having good satellite simultaneously +min_idx=1; +for n=1:1:channels + idx=find(GNSS_observables.valid(n,:)>0,1,'first'); + if min_idx. +% +% ------------------------------------------------------------------------- +% + +function [GNSS_tracking] = dll_pll_veml_read_tracking_dump (filename, count) + +m = nargchk (1,2,nargin); + +num_float_vars = 19; +num_unsigned_long_int_vars = 1; +num_double_vars = 1; +num_unsigned_int_vars = 1; + +if(~isempty(strfind(computer('arch'), '64'))) + % 64-bit computer + double_size_bytes = 8; + unsigned_long_int_size_bytes = 8; + float_size_bytes = 4; + unsigned_int_size_bytes = 4; +else + double_size_bytes = 8; + unsigned_long_int_size_bytes = 4; + float_size_bytes = 4; + unsigned_int_size_bytes = 4; +end + +skip_bytes_each_read = float_size_bytes * num_float_vars + unsigned_long_int_size_bytes * num_unsigned_long_int_vars + ... + double_size_bytes * num_double_vars + num_unsigned_int_vars*unsigned_int_size_bytes; + +bytes_shift = 0; + +if (m) + usage (m); +end + +if (nargin < 2) + count = Inf; +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + v1 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v2 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v3 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v4 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v5 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v6 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v7 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v8 = fread (f, count, 'long', skip_bytes_each_read - unsigned_long_int_size_bytes); + bytes_shift = bytes_shift + unsigned_long_int_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v9 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v10 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v11 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v12 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v13 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v14 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v15 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v16 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v17 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v18 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v19 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v20 = fread (f, count, 'float', skip_bytes_each_read-float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next double + v21 = fread (f, count, 'double', skip_bytes_each_read - double_size_bytes); + bytes_shift = bytes_shift + double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next unsigned int + v22 = fread (f, count, 'uint', skip_bytes_each_read - unsigned_int_size_bytes); + fclose (f); + + GNSS_tracking.VE = v1; + GNSS_tracking.E = v2; + GNSS_tracking.P = v3; + GNSS_tracking.L = v4; + GNSS_tracking.VL = v5; + GNSS_tracking.prompt_I = v6; + GNSS_tracking.prompt_Q = v7; + GNSS_tracking.PRN_start_sample = v8; + GNSS_tracking.acc_carrier_phase_rad = v9; + GNSS_tracking.carrier_doppler_hz = v10; + GNSS_tracking.carrier_doppler_rate_hz_s = v11; + GNSS_tracking.code_freq_hz = v12; + GNSS_tracking.code_freq_rate_hz_s = v13; + GNSS_tracking.carr_error = v14; + GNSS_tracking.carr_nco = v15; + GNSS_tracking.code_error = v16; + GNSS_tracking.code_nco = v17; + GNSS_tracking.CN0_SNV_dB_Hz = v18; + GNSS_tracking.carrier_lock_test = v19; + GNSS_tracking.var1 = v20; + GNSS_tracking.var2 = v21; + GNSS_tracking.PRN = v22; +end + diff --git a/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump.m b/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump.m deleted file mode 100644 index 4be05dd3a..000000000 --- a/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump.m +++ /dev/null @@ -1,192 +0,0 @@ -% /*! -% * \file galileo_e1_dll_pll_veml_read_tracking_dump.m -% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. -% * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -function [GNSS_tracking] = galileo_e1_dll_pll_veml_read_tracking_dump (filename, count) - - %% usage: galileo_e1_dll_pll_veml_read_tracking_dump (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,2,nargin); - num_float_vars=17; - num_unsigned_long_int_vars=1; - num_double_vars=1; - double_size_bytes=8; - unsigned_long_int_size_bytes=8; - float_size_bytes=4; - skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 2) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v6 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v7 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v8 = fread (f, count, 'uint64',skip_bytes_each_read-unsigned_long_int_size_bytes); - bytes_shift=bytes_shift+unsigned_long_int_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v9 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v10 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v11 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v12 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v13 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v14 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v15 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v16 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v17 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v18 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v19 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - fclose (f); - - %%%%%%%% output vars %%%%%%%% - -% // EPR -% d_dump_file.write((char*)&tmp_VE, sizeof(float)); -% d_dump_file.write((char*)&tmp_E, sizeof(float)); -% d_dump_file.write((char*)&tmp_P, sizeof(float)); -% d_dump_file.write((char*)&tmp_L, sizeof(float)); -% d_dump_file.write((char*)&tmp_VL, sizeof(float)); -% // PROMPT I and Q (to analyze navigation symbols) -% d_dump_file.write((char*)&prompt_I, sizeof(float)); -% d_dump_file.write((char*)&prompt_Q, sizeof(float)); -% // PRN start sample stamp -% //tmp_float=(float)d_sample_counter; -% d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); -% // accumulated carrier phase -% d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); -% -% // carrier and code frequency -% d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); -% d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); -% -% //PLL commands -% d_dump_file.write((char*)&carr_error, sizeof(float)); -% d_dump_file.write((char*)&carr_nco, sizeof(float)); -% -% //DLL commands -% d_dump_file.write((char*)&code_error, sizeof(float)); -% d_dump_file.write((char*)&code_nco, sizeof(float)); -% -% // CN0 and carrier lock test -% d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); -% d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); -% -% // AUX vars (for debug purposes) -% tmp_float = d_rem_code_phase_samples; -% d_dump_file.write((char*)&tmp_float, sizeof(float)); -% tmp_double=(double)(d_sample_counter+d_current_prn_length_samples); -% d_dump_file.write((char*)&tmp_double, sizeof(double)); - - VE=v1; - E=v2; - P=v3; - L=v4; - VL=v5; - prompt_I=v6; - prompt_Q=v7; - PRN_start_sample=v8; - acc_carrier_phase_rad=v9; - carrier_doppler_hz=v10; - code_freq_hz=v11; - carr_error=v12; - carr_nco=v13; - code_error=v14; - code_nco=v15; - CN0_SNV_dB_Hz=v16; - carrier_lock_test=v17; - var1=v18; - var2=v19; - - GNSS_tracking.VE=VE; - GNSS_tracking.E=E; - GNSS_tracking.P=P; - GNSS_tracking.L=L; - GNSS_tracking.VL=VL; - GNSS_tracking.prompt_I=prompt_I; - GNSS_tracking.prompt_Q=prompt_Q; - GNSS_tracking.PRN_start_sample=PRN_start_sample; - GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; - GNSS_tracking.carrier_doppler_hz=carrier_doppler_hz; - GNSS_tracking.code_freq_hz=code_freq_hz; - GNSS_tracking.carr_error=carr_error; - GNSS_tracking.carr_nco=carr_nco; - GNSS_tracking.code_error=code_error; - GNSS_tracking.code_nco=code_nco; - GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; - GNSS_tracking.carrier_lock_test=carrier_lock_test; - GNSS_tracking.var1=var1; - GNSS_tracking.var2=var2; - end - diff --git a/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump_32bits.m b/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump_32bits.m deleted file mode 100644 index f7dab9fc3..000000000 --- a/src/utils/matlab/libs/galileo_e1_dll_pll_veml_read_tracking_dump_32bits.m +++ /dev/null @@ -1,192 +0,0 @@ -% /*! -% * \file galileo_e1_dll_pll_veml_read_tracking_dump.m -% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. -% * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -function [GNSS_tracking] = galileo_e1_dll_pll_veml_read_tracking_dump_32bits (filename, count) - - %% usage: galileo_e1_dll_pll_veml_read_tracking_dump (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,2,nargin); - num_float_vars=17; - num_unsigned_long_int_vars=1; - num_double_vars=1; - double_size_bytes=8; - unsigned_long_int_size_bytes=4; - float_size_bytes=4; - skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 2) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v6 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v7 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v8 = fread (f, count, 'uint32',skip_bytes_each_read-unsigned_long_int_size_bytes); - bytes_shift=bytes_shift+unsigned_long_int_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v9 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v10 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v11 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v12 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v13 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v14 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v15 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v16 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v17 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v18 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v19 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - fclose (f); - - %%%%%%%% output vars %%%%%%%% - -% // EPR -% d_dump_file.write((char*)&tmp_VE, sizeof(float)); -% d_dump_file.write((char*)&tmp_E, sizeof(float)); -% d_dump_file.write((char*)&tmp_P, sizeof(float)); -% d_dump_file.write((char*)&tmp_L, sizeof(float)); -% d_dump_file.write((char*)&tmp_VL, sizeof(float)); -% // PROMPT I and Q (to analyze navigation symbols) -% d_dump_file.write((char*)&prompt_I, sizeof(float)); -% d_dump_file.write((char*)&prompt_Q, sizeof(float)); -% // PRN start sample stamp -% //tmp_float=(float)d_sample_counter; -% d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); -% // accumulated carrier phase -% d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); -% -% // carrier and code frequency -% d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); -% d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); -% -% //PLL commands -% d_dump_file.write((char*)&carr_error, sizeof(float)); -% d_dump_file.write((char*)&carr_nco, sizeof(float)); -% -% //DLL commands -% d_dump_file.write((char*)&code_error, sizeof(float)); -% d_dump_file.write((char*)&code_nco, sizeof(float)); -% -% // CN0 and carrier lock test -% d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); -% d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); -% -% // AUX vars (for debug purposes) -% tmp_float = d_rem_code_phase_samples; -% d_dump_file.write((char*)&tmp_float, sizeof(float)); -% tmp_double=(double)(d_sample_counter+d_current_prn_length_samples); -% d_dump_file.write((char*)&tmp_double, sizeof(double)); - - VE=v1; - E=v2; - P=v3; - L=v4; - VL=v5; - prompt_I=v6; - prompt_Q=v7; - PRN_start_sample=v8; - acc_carrier_phase_rad=v9; - carrier_doppler_hz=v10; - code_freq_hz=v11; - carr_error=v12; - carr_nco=v13; - code_error=v14; - code_nco=v15; - CN0_SNV_dB_Hz=v16; - carrier_lock_test=v17; - var1=v18; - var2=v19; - - GNSS_tracking.VE=VE; - GNSS_tracking.E=E; - GNSS_tracking.P=P; - GNSS_tracking.L=L; - GNSS_tracking.VL=VL; - GNSS_tracking.prompt_I=prompt_I; - GNSS_tracking.prompt_Q=prompt_Q; - GNSS_tracking.PRN_start_sample=PRN_start_sample; - GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; - GNSS_tracking.carrier_doppler_hz=carrier_doppler_hz; - GNSS_tracking.code_freq_hz=code_freq_hz; - GNSS_tracking.carr_error=carr_error; - GNSS_tracking.carr_nco=carr_nco; - GNSS_tracking.code_error=code_error; - GNSS_tracking.code_nco=code_nco; - GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; - GNSS_tracking.carrier_lock_test=carrier_lock_test; - GNSS_tracking.var1=var1; - GNSS_tracking.var2=var2; - end - diff --git a/src/utils/matlab/libs/geoFunctions/cart2geo.m b/src/utils/matlab/libs/geoFunctions/cart2geo.m index 99888b12e..324a226c1 100644 --- a/src/utils/matlab/libs/geoFunctions/cart2geo.m +++ b/src/utils/matlab/libs/geoFunctions/cart2geo.m @@ -1,60 +1,58 @@ -function [phi, lambda, h] = cart2geo(X, Y, Z, i) -%CART2GEO Conversion of Cartesian coordinates (X,Y,Z) to geographical -%coordinates (phi, lambda, h) on a selected reference ellipsoid. -% -%[phi, lambda, h] = cart2geo(X, Y, Z, i); -% -% Choices i of Reference Ellipsoid for Geographical Coordinates -% 1. International Ellipsoid 1924 -% 2. International Ellipsoid 1967 -% 3. World Geodetic System 1972 -% 4. Geodetic Reference System 1980 -% 5. World Geodetic System 1984 - -%Kai Borre 10-13-98 -%Copyright (c) by Kai Borre -%Revision: 1.0 Date: 1998/10/23 -% -% CVS record: -% $Id: cart2geo.m,v 1.1.2.3 2007/01/29 15:22:49 dpl Exp $ -%========================================================================== - -a = [6378388 6378160 6378135 6378137 6378137]; -f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563]; - -lambda = atan2(Y,X); -ex2 = (2-f(i))*f(i)/((1-f(i))^2); -c = a(i)*sqrt(1+ex2); -phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i)))*f(i)))); - -h = 0.1; oldh = 0; -iterations = 0; -while abs(h-oldh) > 1.e-12 - oldh = h; - N = c/sqrt(1+ex2*cos(phi)^2); - phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i))*f(i)*N/(N+h))))); - h = sqrt(X^2+Y^2)/cos(phi)-N; - - iterations = iterations + 1; - if iterations > 100 - fprintf('Failed to approximate h with desired precision. h-oldh: %e.\n', h-oldh); - break; - end -end - -phi = phi*180/pi; -% b = zeros(1,3); -% b(1,1) = fix(phi); -% b(2,1) = fix(rem(phi,b(1,1))*60); -% b(3,1) = (phi-b(1,1)-b(1,2)/60)*3600; - -lambda = lambda*180/pi; -% l = zeros(1,3); -% l(1,1) = fix(lambda); -% l(2,1) = fix(rem(lambda,l(1,1))*60); -% l(3,1) = (lambda-l(1,1)-l(1,2)/60)*3600; - -%fprintf('\n phi =%3.0f %3.0f %8.5f',b(1),b(2),b(3)) -%fprintf('\n lambda =%3.0f %3.0f %8.5f',l(1),l(2),l(3)) -%fprintf('\n h =%14.3f\n',h) -%%%%%%%%%%%%%% end cart2geo.m %%%%%%%%%%%%%%%%%%% +function [phi, lambda, h] = cart2geo(X, Y, Z, i) +% CART2GEO Conversion of Cartesian coordinates (X,Y,Z) to geographical +% coordinates (phi, lambda, h) on a selected reference ellipsoid. +% +% [phi, lambda, h] = cart2geo(X, Y, Z, i); +% +% Choices i of Reference Ellipsoid for Geographical Coordinates +% 1. International Ellipsoid 1924 +% 2. International Ellipsoid 1967 +% 3. World Geodetic System 1972 +% 4. Geodetic Reference System 1980 +% 5. World Geodetic System 1984 + +% Kai Borre 10-13-98 +% Copyright (c) by Kai Borre +% Revision: 1.0 Date: 1998/10/23 +%========================================================================== + +a = [6378388 6378160 6378135 6378137 6378137]; +f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563]; + +lambda = atan2(Y,X); +ex2 = (2-f(i))*f(i)/((1-f(i))^2); +c = a(i)*sqrt(1+ex2); +phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i)))*f(i)))); + +h = 0.1; oldh = 0; +iterations = 0; +while abs(h-oldh) > 1.e-12 + oldh = h; + N = c/sqrt(1+ex2*cos(phi)^2); + phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i))*f(i)*N/(N+h))))); + h = sqrt(X^2+Y^2)/cos(phi)-N; + + iterations = iterations + 1; + if iterations > 100 + fprintf('Failed to approximate h with desired precision. h-oldh: %e.\n', h-oldh); + break; + end +end + +phi = phi*180/pi; +% b = zeros(1,3); +% b(1,1) = fix(phi); +% b(2,1) = fix(rem(phi,b(1,1))*60); +% b(3,1) = (phi-b(1,1)-b(1,2)/60)*3600; + +lambda = lambda*180/pi; +% l = zeros(1,3); +% l(1,1) = fix(lambda); +% l(2,1) = fix(rem(lambda,l(1,1))*60); +% l(3,1) = (lambda-l(1,1)-l(1,2)/60)*3600; + +%fprintf('\n phi =%3.0f %3.0f %8.5f',b(1),b(2),b(3)) +%fprintf('\n lambda =%3.0f %3.0f %8.5f',l(1),l(2),l(3)) +%fprintf('\n h =%14.3f\n',h) + +%%%%%%%%%%%%%% end cart2geo.m %%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/cart2utm.m b/src/utils/matlab/libs/geoFunctions/cart2utm.m index b3bec8969..3a6034230 100644 --- a/src/utils/matlab/libs/geoFunctions/cart2utm.m +++ b/src/utils/matlab/libs/geoFunctions/cart2utm.m @@ -1,176 +1,173 @@ -function [E, N, U] = cart2utm(X, Y, Z, zone) -%CART2UTM Transformation of (X,Y,Z) to (N,E,U) in UTM, zone 'zone'. -% -%[E, N, U] = cart2utm(X, Y, Z, zone); -% -% Inputs: -% X,Y,Z - Cartesian coordinates. Coordinates are referenced -% with respect to the International Terrestrial Reference -% Frame 1996 (ITRF96) -% zone - UTM zone of the given position -% -% Outputs: -% E, N, U - UTM coordinates (Easting, Northing, Uping) - -%Kai Borre -11-1994 -%Copyright (c) by Kai Borre -% -% CVS record: -% $Id: cart2utm.m,v 1.1.1.1.2.6 2007/01/30 09:45:12 dpl Exp $ - -%This implementation is based upon -%O. Andersson & K. Poder (1981) Koordinattransformationer -% ved Geod\ae{}tisk Institut. Landinspekt\oe{}ren -% Vol. 30: 552--571 and Vol. 31: 76 -% -%An excellent, general reference (KW) is -%R. Koenig & K.H. Weise (1951) Mathematische Grundlagen der -% h\"oheren Geod\"asie und Kartographie. -% Erster Band, Springer Verlag - -% Explanation of variables used: -% f flattening of ellipsoid -% a semi major axis in m -% m0 1 - scale at central meridian; for UTM 0.0004 -% Q_n normalized meridian quadrant -% E0 Easting of central meridian -% L0 Longitude of central meridian -% bg constants for ellipsoidal geogr. to spherical geogr. -% gb constants for spherical geogr. to ellipsoidal geogr. -% gtu constants for ellipsoidal N, E to spherical N, E -% utg constants for spherical N, E to ellipoidal N, E -% tolutm tolerance for utm, 1.2E-10*meridian quadrant -% tolgeo tolerance for geographical, 0.00040 second of arc - -% B, L refer to latitude and longitude. Southern latitude is negative -% International ellipsoid of 1924, valid for ED50 - -a = 6378388; -f = 1/297; -ex2 = (2-f)*f / ((1-f)^2); -c = a * sqrt(1+ex2); -vec = [X; Y; Z-4.5]; -alpha = .756e-6; -R = [ 1 -alpha 0; - alpha 1 0; - 0 0 1]; -trans = [89.5; 93.8; 127.6]; -scale = 0.9999988; -v = scale*R*vec + trans; % coordinate vector in ED50 -L = atan2(v(2), v(1)); -N1 = 6395000; % preliminary value -B = atan2(v(3)/((1-f)^2*N1), norm(v(1:2))/N1); % preliminary value -U = 0.1; oldU = 0; - -iterations = 0; -while abs(U-oldU) > 1.e-4 - oldU = U; - N1 = c/sqrt(1+ex2*(cos(B))^2); - B = atan2(v(3)/((1-f)^2*N1+U), norm(v(1:2))/(N1+U) ); - U = norm(v(1:2))/cos(B)-N1; - - iterations = iterations + 1; - if iterations > 100 - fprintf('Failed to approximate U with desired precision. U-oldU: %e.\n', U-oldU); - break; - end -end - -%Normalized meridian quadrant, KW p. 50 (96), p. 19 (38b), p. 5 (21) -m0 = 0.0004; -n = f / (2-f); -m = n^2 * (1/4 + n*n/64); -w = (a*(-n-m0+m*(1-m0))) / (1+n); -Q_n = a + w; - -%Easting and longitude of central meridian -E0 = 500000; -L0 = (zone-30)*6 - 3; - -%Check tolerance for reverse transformation -tolutm = pi/2 * 1.2e-10 * Q_n; -tolgeo = 0.000040; - -%Coefficients of trigonometric series - -%ellipsoidal to spherical geographical, KW p. 186--187, (51)-(52) -% bg[1] = n*(-2 + n*(2/3 + n*(4/3 + n*(-82/45)))); -% bg[2] = n^2*(5/3 + n*(-16/15 + n*(-13/9))); -% bg[3] = n^3*(-26/15 + n*34/21); -% bg[4] = n^4*1237/630; - -%spherical to ellipsoidal geographical, KW p. 190--191, (61)-(62) -% gb[1] = n*(2 + n*(-2/3 + n*(-2 + n*116/45))); -% gb[2] = n^2*(7/3 + n*(-8/5 + n*(-227/45))); -% gb[3] = n^3*(56/15 + n*(-136/35)); -% gb[4] = n^4*4279/630; - -%spherical to ellipsoidal N, E, KW p. 196, (69) -% gtu[1] = n*(1/2 + n*(-2/3 + n*(5/16 + n*41/180))); -% gtu[2] = n^2*(13/48 + n*(-3/5 + n*557/1440)); -% gtu[3] = n^3*(61/240 + n*(-103/140)); -% gtu[4] = n^4*49561/161280; - -%ellipsoidal to spherical N, E, KW p. 194, (65) -% utg[1] = n*(-1/2 + n*(2/3 + n*(-37/96 + n*1/360))); -% utg[2] = n^2*(-1/48 + n*(-1/15 + n*437/1440)); -% utg[3] = n^3*(-17/480 + n*37/840); -% utg[4] = n^4*(-4397/161280); - -%With f = 1/297 we get - -bg = [-3.37077907e-3; - 4.73444769e-6; - -8.29914570e-9; - 1.58785330e-11]; - -gb = [ 3.37077588e-3; - 6.62769080e-6; - 1.78718601e-8; - 5.49266312e-11]; - -gtu = [ 8.41275991e-4; - 7.67306686e-7; - 1.21291230e-9; - 2.48508228e-12]; - -utg = [-8.41276339e-4; - -5.95619298e-8; - -1.69485209e-10; - -2.20473896e-13]; - -%Ellipsoidal latitude, longitude to spherical latitude, longitude -neg_geo = 'FALSE'; - -if B < 0 - neg_geo = 'TRUE '; -end - -Bg_r = abs(B); -[res_clensin] = clsin(bg, 4, 2*Bg_r); -Bg_r = Bg_r + res_clensin; -L0 = L0*pi / 180; -Lg_r = L - L0; - -%Spherical latitude, longitude to complementary spherical latitude -% i.e. spherical N, E -cos_BN = cos(Bg_r); -Np = atan2(sin(Bg_r), cos(Lg_r)*cos_BN); -Ep = atanh(sin(Lg_r) * cos_BN); - -%Spherical normalized N, E to ellipsoidal N, E -Np = 2 * Np; -Ep = 2 * Ep; -[dN, dE] = clksin(gtu, 4, Np, Ep); -Np = Np/2; -Ep = Ep/2; -Np = Np + dN; -Ep = Ep + dE; -N = Q_n * Np; -E = Q_n*Ep + E0; - -if neg_geo == 'TRUE ' - N = -N + 20000000; -end; - -%%%%%%%%%%%%%%%%%%%% end cart2utm.m %%%%%%%%%%%%%%%%%%%% \ No newline at end of file +function [E, N, U] = cart2utm(X, Y, Z, zone) +% CART2UTM Transformation of (X,Y,Z) to (N,E,U) in UTM, zone 'zone'. +% +% [E, N, U] = cart2utm(X, Y, Z, zone); +% +% Inputs: +% X,Y,Z - Cartesian coordinates. Coordinates are referenced +% with respect to the International Terrestrial Reference +% Frame 1996 (ITRF96) +% zone - UTM zone of the given position +% +% Outputs: +% E, N, U - UTM coordinates (Easting, Northing, Uping) + +% Kai Borre -11-1994 +% Copyright (c) by Kai Borre + +% This implementation is based upon +% O. Andersson & K. Poder (1981) Koordinattransformationer +% ved Geod\ae{}tisk Institut. Landinspekt\oe{}ren +% Vol. 30: 552--571 and Vol. 31: 76 +% +% An excellent, general reference (KW) is +% R. Koenig & K.H. Weise (1951) Mathematische Grundlagen der +% h\"oheren Geod\"asie und Kartographie. +% Erster Band, Springer Verlag + +% Explanation of variables used: +% f flattening of ellipsoid +% a semi major axis in m +% m0 1 - scale at central meridian; for UTM 0.0004 +% Q_n normalized meridian quadrant +% E0 Easting of central meridian +% L0 Longitude of central meridian +% bg constants for ellipsoidal geogr. to spherical geogr. +% gb constants for spherical geogr. to ellipsoidal geogr. +% gtu constants for ellipsoidal N, E to spherical N, E +% utg constants for spherical N, E to ellipoidal N, E +% tolutm tolerance for utm, 1.2E-10*meridian quadrant +% tolgeo tolerance for geographical, 0.00040 second of arc + +% B, L refer to latitude and longitude. Southern latitude is negative +% International ellipsoid of 1924, valid for ED50 + +a = 6378388; +f = 1/297; +ex2 = (2-f)*f / ((1-f)^2); +c = a * sqrt(1+ex2); +vec = [X; Y; Z-4.5]; +alpha = .756e-6; +R = [ 1 -alpha 0; + alpha 1 0; + 0 0 1]; +trans = [89.5; 93.8; 127.6]; +scale = 0.9999988; +v = scale*R*vec + trans; % coordinate vector in ED50 +L = atan2(v(2), v(1)); +N1 = 6395000; % preliminary value +B = atan2(v(3)/((1-f)^2*N1), norm(v(1:2))/N1); % preliminary value +U = 0.1; oldU = 0; + +iterations = 0; +while abs(U-oldU) > 1.e-4 + oldU = U; + N1 = c/sqrt(1+ex2*(cos(B))^2); + B = atan2(v(3)/((1-f)^2*N1+U), norm(v(1:2))/(N1+U) ); + U = norm(v(1:2))/cos(B)-N1; + + iterations = iterations + 1; + if iterations > 100 + fprintf('Failed to approximate U with desired precision. U-oldU: %e.\n', U-oldU); + break; + end +end + +% Normalized meridian quadrant, KW p. 50 (96), p. 19 (38b), p. 5 (21) +m0 = 0.0004; +n = f / (2-f); +m = n^2 * (1/4 + n*n/64); +w = (a*(-n-m0+m*(1-m0))) / (1+n); +Q_n = a + w; + +% Easting and longitude of central meridian +E0 = 500000; +L0 = (zone-30)*6 - 3; + +% Check tolerance for reverse transformation +tolutm = pi/2 * 1.2e-10 * Q_n; +tolgeo = 0.000040; + +% Coefficients of trigonometric series + +% ellipsoidal to spherical geographical, KW p. 186--187, (51)-(52) +% bg[1] = n*(-2 + n*(2/3 + n*(4/3 + n*(-82/45)))); +% bg[2] = n^2*(5/3 + n*(-16/15 + n*(-13/9))); +% bg[3] = n^3*(-26/15 + n*34/21); +% bg[4] = n^4*1237/630; + +% spherical to ellipsoidal geographical, KW p. 190--191, (61)-(62) +% gb[1] = n*(2 + n*(-2/3 + n*(-2 + n*116/45))); +% gb[2] = n^2*(7/3 + n*(-8/5 + n*(-227/45))); +% gb[3] = n^3*(56/15 + n*(-136/35)); +% gb[4] = n^4*4279/630; + +% spherical to ellipsoidal N, E, KW p. 196, (69) +% gtu[1] = n*(1/2 + n*(-2/3 + n*(5/16 + n*41/180))); +% gtu[2] = n^2*(13/48 + n*(-3/5 + n*557/1440)); +% gtu[3] = n^3*(61/240 + n*(-103/140)); +% gtu[4] = n^4*49561/161280; + +% ellipsoidal to spherical N, E, KW p. 194, (65) +% utg[1] = n*(-1/2 + n*(2/3 + n*(-37/96 + n*1/360))); +% utg[2] = n^2*(-1/48 + n*(-1/15 + n*437/1440)); +% utg[3] = n^3*(-17/480 + n*37/840); +% utg[4] = n^4*(-4397/161280); + +% With f = 1/297 we get + +bg = [-3.37077907e-3; + 4.73444769e-6; + -8.29914570e-9; + 1.58785330e-11]; + +gb = [ 3.37077588e-3; + 6.62769080e-6; + 1.78718601e-8; + 5.49266312e-11]; + +gtu = [ 8.41275991e-4; + 7.67306686e-7; + 1.21291230e-9; + 2.48508228e-12]; + +utg = [-8.41276339e-4; + -5.95619298e-8; + -1.69485209e-10; + -2.20473896e-13]; + +% Ellipsoidal latitude, longitude to spherical latitude, longitude +neg_geo = 'FALSE'; + +if B < 0 + neg_geo = 'TRUE '; +end + +Bg_r = abs(B); +[res_clensin] = clsin(bg, 4, 2*Bg_r); +Bg_r = Bg_r + res_clensin; +L0 = L0*pi / 180; +Lg_r = L - L0; + +% Spherical latitude, longitude to complementary spherical latitude +% i.e. spherical N, E +cos_BN = cos(Bg_r); +Np = atan2(sin(Bg_r), cos(Lg_r)*cos_BN); +Ep = atanh(sin(Lg_r) * cos_BN); + +%Spherical normalized N, E to ellipsoidal N, E +Np = 2 * Np; +Ep = 2 * Ep; +[dN, dE] = clksin(gtu, 4, Np, Ep); +Np = Np/2; +Ep = Ep/2; +Np = Np + dN; +Ep = Ep + dE; +N = Q_n * Np; +E = Q_n*Ep + E0; + +if neg_geo == 'TRUE ' + N = -N + 20000000; +end; + +%%%%%%%%%%%%%%%%%%%% end cart2utm.m %%%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/check_t.m b/src/utils/matlab/libs/geoFunctions/check_t.m index 9d503c3e9..1b3ed323c 100644 --- a/src/utils/matlab/libs/geoFunctions/check_t.m +++ b/src/utils/matlab/libs/geoFunctions/check_t.m @@ -1,28 +1,26 @@ -function corrTime = check_t(time) -%CHECK_T accounting for beginning or end of week crossover. -% -%corrTime = check_t(time); -% -% Inputs: -% time - time in seconds -% -% Outputs: -% corrTime - corrected time (seconds) - -%Kai Borre 04-01-96 -%Copyright (c) by Kai Borre -% -% CVS record: -% $Id: check_t.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -half_week = 302400; % seconds - -corrTime = time; - -if time > half_week - corrTime = time - 2*half_week; -elseif time < -half_week - corrTime = time + 2*half_week; -end -%%%%%%% end check_t.m %%%%%%%%%%%%%%%%% \ No newline at end of file +function corrTime = check_t(time) +% CHECK_T accounting for beginning or end of week crossover. +% +% corrTime = check_t(time); +% +% Inputs: +% time - time in seconds +% +% Outputs: +% corrTime - corrected time (seconds) + +% Kai Borre 04-01-96 +% Copyright (c) by Kai Borre +%========================================================================== + +half_week = 302400; % seconds + +corrTime = time; + +if time > half_week + corrTime = time - 2*half_week; +elseif time < -half_week + corrTime = time + 2*half_week; +end + +%%%%%%% end check_t.m %%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/clksin.m b/src/utils/matlab/libs/geoFunctions/clksin.m index 7ccd4726f..f6f600c19 100644 --- a/src/utils/matlab/libs/geoFunctions/clksin.m +++ b/src/utils/matlab/libs/geoFunctions/clksin.m @@ -1,38 +1,36 @@ -function [re, im] = clksin(ar, degree, arg_real, arg_imag) -%Clenshaw summation of sinus with complex argument -%[re, im] = clksin(ar, degree, arg_real, arg_imag); - -% Written by Kai Borre -% December 20, 1995 -% -% See also WGS2UTM or CART2UTM -% -% CVS record: -% $Id: clksin.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -sin_arg_r = sin(arg_real); -cos_arg_r = cos(arg_real); -sinh_arg_i = sinh(arg_imag); -cosh_arg_i = cosh(arg_imag); - -r = 2 * cos_arg_r * cosh_arg_i; -i =-2 * sin_arg_r * sinh_arg_i; - -hr1 = 0; hr = 0; hi1 = 0; hi = 0; - -for t = degree : -1 : 1 - hr2 = hr1; - hr1 = hr; - hi2 = hi1; - hi1 = hi; - z = ar(t) + r*hr1 - i*hi - hr2; - hi = i*hr1 + r*hi1 - hi2; - hr = z; -end - -r = sin_arg_r * cosh_arg_i; -i = cos_arg_r * sinh_arg_i; - -re = r*hr - i*hi; -im = r*hi + i*hr; +function [re, im] = clksin(ar, degree, arg_real, arg_imag) +% Clenshaw summation of sinus with complex argument +% [re, im] = clksin(ar, degree, arg_real, arg_imag); + +% Written by Kai Borre +% December 20, 1995 +% +% See also WGS2UTM or CART2UTM +% +%========================================================================== + +sin_arg_r = sin(arg_real); +cos_arg_r = cos(arg_real); +sinh_arg_i = sinh(arg_imag); +cosh_arg_i = cosh(arg_imag); + +r = 2 * cos_arg_r * cosh_arg_i; +i =-2 * sin_arg_r * sinh_arg_i; + +hr1 = 0; hr = 0; hi1 = 0; hi = 0; + +for t = degree : -1 : 1 + hr2 = hr1; + hr1 = hr; + hi2 = hi1; + hi1 = hi; + z = ar(t) + r*hr1 - i*hi - hr2; + hi = i*hr1 + r*hi1 - hi2; + hr = z; +end + +r = sin_arg_r * cosh_arg_i; +i = cos_arg_r * sinh_arg_i; + +re = r*hr - i*hi; +im = r*hi + i*hr; diff --git a/src/utils/matlab/libs/geoFunctions/clsin.m b/src/utils/matlab/libs/geoFunctions/clsin.m index d499e8598..46cf32524 100644 --- a/src/utils/matlab/libs/geoFunctions/clsin.m +++ b/src/utils/matlab/libs/geoFunctions/clsin.m @@ -1,26 +1,24 @@ -function result = clsin(ar, degree, argument) -%Clenshaw summation of sinus of argument. -% -%result = clsin(ar, degree, argument); - -% Written by Kai Borre -% December 20, 1995 -% -% See also WGS2UTM or CART2UTM -% -% CVS record: -% $Id: clsin.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -cos_arg = 2 * cos(argument); -hr1 = 0; -hr = 0; - -for t = degree : -1 : 1 - hr2 = hr1; - hr1 = hr; - hr = ar(t) + cos_arg*hr1 - hr2; -end - -result = hr * sin(argument); -%%%%%%%%%%%%%%%%%%%%%%% end clsin.m %%%%%%%%%%%%%%%%%%%%% \ No newline at end of file +function result = clsin(ar, degree, argument) +% Clenshaw summation of sinus of argument. +% +% result = clsin(ar, degree, argument); + +% Written by Kai Borre +% December 20, 1995 +% +% See also WGS2UTM or CART2UTM +%========================================================================== + +cos_arg = 2 * cos(argument); +hr1 = 0; +hr = 0; + +for t = degree : -1 : 1 + hr2 = hr1; + hr1 = hr; + hr = ar(t) + cos_arg*hr1 - hr2; +end + +result = hr * sin(argument); + +%%%%%%%%%%%%%%%%%%%%%%% end clsin.m %%%%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/deg2dms.m b/src/utils/matlab/libs/geoFunctions/deg2dms.m index 56ce6ae90..948e885db 100644 --- a/src/utils/matlab/libs/geoFunctions/deg2dms.m +++ b/src/utils/matlab/libs/geoFunctions/deg2dms.m @@ -1,43 +1,43 @@ -function dmsOutput = deg2dms(deg) -%DEG2DMS Conversion of degrees to degrees, minutes, and seconds. -%The output format (dms format) is: (degrees*100 + minutes + seconds/100) - -% Written by Kai Borre -% February 7, 2001 -% Updated by Darius Plausinaitis - -%%% Save the sign for later processing -neg_arg = false; -if deg < 0 - % Only positive numbers should be used while spliting into deg/min/sec - deg = -deg; - neg_arg = true; -end - -%%% Split degrees minutes and seconds -int_deg = floor(deg); -decimal = deg - int_deg; -min_part = decimal*60; -min = floor(min_part); -sec_part = min_part - floor(min_part); -sec = sec_part*60; - -%%% Check for overflow -if sec == 60 - min = min + 1; - sec = 0; -end -if min == 60 - int_deg = int_deg + 1; - min = 0; -end - -%%% Construct the output -dmsOutput = int_deg * 100 + min + sec/100; - -%%% Correct the sign -if neg_arg == true - dmsOutput = -dmsOutput; -end - -%%%%%%%%%%%%%%%%%%% end deg2dms.m %%%%%%%%%%%%%%%% \ No newline at end of file +function dmsOutput = deg2dms(deg) +% DEG2DMS Conversion of degrees to degrees, minutes, and seconds. +% The output format (dms format) is: (degrees*100 + minutes + seconds/100) + +% Written by Kai Borre +% February 7, 2001 +% Updated by Darius Plausinaitis + +%%% Save the sign for later processing +neg_arg = false; +if deg < 0 + % Only positive numbers should be used while splitting into deg/min/sec + deg = -deg; + neg_arg = true; +end + +%%% Split degrees minutes and seconds +int_deg = floor(deg); +decimal = deg - int_deg; +min_part = decimal*60; +min = floor(min_part); +sec_part = min_part - floor(min_part); +sec = sec_part*60; + +%%% Check for overflow +if sec == 60 + min = min + 1; + sec = 0; +end +if min == 60 + int_deg = int_deg + 1; + min = 0; +end + +%%% Construct the output +dmsOutput = int_deg * 100 + min + sec/100; + +%%% Correct the sign +if neg_arg == true + dmsOutput = -dmsOutput; +end + +%%%%%%%%%%%%%%%%%%% end deg2dms.m %%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/dms2deg.m b/src/utils/matlab/libs/geoFunctions/dms2deg.m index 077fc8639..a8e99f9a6 100644 --- a/src/utils/matlab/libs/geoFunctions/dms2deg.m +++ b/src/utils/matlab/libs/geoFunctions/dms2deg.m @@ -1,12 +1,12 @@ - -function deg = dms2deg(dms) -%DMS2DEG Conversion of degrees, minutes, and seconds to degrees. - -% Written by Javier Arribas 2011 -% December 7, 2011 - -%if (dms(1)>=0) - deg=dms(1)+dms(2)/60+dms(3)/3600; -%else - %deg=dms(1)-dms(2)/60-dms(3)/3600; -%end + +function deg = dms2deg(dms) +% DMS2DEG Conversion of degrees, minutes, and seconds to degrees. + +% Written by Javier Arribas 2011 +% December 7, 2011 + +%if (dms(1)>=0) +deg=dms(1)+dms(2)/60+dms(3)/3600; +%else +%deg=dms(1)-dms(2)/60-dms(3)/3600; +%end diff --git a/src/utils/matlab/libs/geoFunctions/dms2mat.m b/src/utils/matlab/libs/geoFunctions/dms2mat.m index da17b590b..6cafb2488 100644 --- a/src/utils/matlab/libs/geoFunctions/dms2mat.m +++ b/src/utils/matlab/libs/geoFunctions/dms2mat.m @@ -1,104 +1,103 @@ -function [dout,mout,sout] = dms2mat(dms,n) - -%DMS2MAT Converts a dms vector format to a [deg min sec] matrix -% -% [d,m,s] = DMS2MAT(dms) converts a dms vector format to a -% deg:min:sec matrix. The vector format is dms = 100*deg + min + sec/100. -% This allows compressed dms data to be expanded to a d,m,s triple, -% for easier reporting and viewing of the data. -% -% [d,m,s] = DMS2MAT(dms,n) uses n digits in the accuracy of the -% seconds calculation. n = -2 uses accuracy in the hundredths position, -% n = 0 uses accuracy in the units position. Default is n = -5. -% For further discussion of the input n, see ROUNDN. -% -% mat = DMS2MAT(...) returns a single output argument of mat = [d m s]. -% This is useful only if the input dms is a single column vector. -% -% See also MAT2DMS - -% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. -% Written by: E. Byrns, E. Brown -% $Revision: 1.10 $ $Date: 2002/03/20 21:25:06 $ - - -if nargin == 0 - error('Incorrect number of arguments') -elseif nargin == 1 - n = -5; -end - -% Test for empty arguments - -if isempty(dms); dout = []; mout = []; sout = []; return; end - -% Test for complex arguments - -if ~isreal(dms) - warning('Imaginary parts of complex ANGLE argument ignored') - dms = real(dms); -end - -% Don't let seconds be rounded beyond the tens place. -% If you did, then 55 seconds rounds to 100, which is not good. - -if n == 2; n = 1; end - -% Construct a sign vector which has +1 when dms >= 0 and -1 when dms < 0. - -signvec = sign(dms); -signvec = signvec + (signvec == 0); % Ensure +1 when dms = 0 - -% Decompress the dms data vector - -dms = abs(dms); -d = fix(dms/100); % Degrees -m = fix(dms) - abs(100*d); % Minutes -[s,msg] = roundn(100*rem(dms,1),n); % Seconds: Truncate to roundoff error -if ~isempty(msg); error(msg); end - -% Adjust for 60 seconds or 60 minutes. -% Test for seconds > 60 to allow for round-off from roundn, -% Test for minutes > 60 as a ripple effect from seconds > 60 - - -indx = find(s >= 60); -if ~isempty(indx); m(indx) = m(indx) + 1; s(indx) = s(indx) - 60; end -indx = find(m >= 60); -if ~isempty(indx); d(indx) = d(indx) + 1; m(indx) = m(indx) - 60; end - -% Data consistency checks - -if any(m > 59) | any (m < 0) - error('Minutes must be >= 0 and <= 59') - -elseif any(s >= 60) | any( s < 0) - error('Seconds must be >= 0 and < 60') -end - -% Determine where to store the sign of the angle. It should be -% associated with the largest nonzero component of d:m:s. - -dsign = signvec .* (d~=0); -msign = signvec .* (d==0 & m~=0); -ssign = signvec .* (d==0 & m==0 & s~=0); - -% In the application of signs below, the comparison with 0 is used so that -% the sign vector contains only +1 and -1. Any zero occurances causes -% data to be lost when the sign has been applied to a higher component -% of d:m:s. Use fix function to eliminate potential round-off errors. - -d = ((dsign==0) + dsign).*fix(d); % Apply signs to the degrees -m = ((msign==0) + msign).*fix(m); % Apply signs to minutes -s = ((ssign==0) + ssign).*s; % Apply signs to seconds - -% Set the output arguments - -if nargout <= 1 - dout = [d m s]; -elseif nargout == 3 - dout = d; mout = m; sout = s; -else - error('Invalid number of output arguments') -end - +function [dout,mout,sout] = dms2mat(dms,n) + +% DMS2MAT Converts a dms vector format to a [deg min sec] matrix +% +% [d,m,s] = DMS2MAT(dms) converts a dms vector format to a +% deg:min:sec matrix. The vector format is dms = 100*deg + min + sec/100. +% This allows compressed dms data to be expanded to a d,m,s triple, +% for easier reporting and viewing of the data. +% +% [d,m,s] = DMS2MAT(dms,n) uses n digits in the accuracy of the +% seconds calculation. n = -2 uses accuracy in the hundredths position, +% n = 0 uses accuracy in the units position. Default is n = -5. +% For further discussion of the input n, see ROUNDN. +% +% mat = DMS2MAT(...) returns a single output argument of mat = [d m s]. +% This is useful only if the input dms is a single column vector. +% +% See also MAT2DMS + +% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. +% Written by: E. Byrns, E. Brown +% Revision: 1.10 $Date: 2002/03/20 21:25:06 + + +if nargin == 0 + error('Incorrect number of arguments') +elseif nargin == 1 + n = -5; +end + +% Test for empty arguments + +if isempty(dms); dout = []; mout = []; sout = []; return; end + +% Test for complex arguments + +if ~isreal(dms) + warning('Imaginary parts of complex ANGLE argument ignored') + dms = real(dms); +end + +% Don't let seconds be rounded beyond the tens place. +% If you did, then 55 seconds rounds to 100, which is not good. + +if n == 2; n = 1; end + +% Construct a sign vector which has +1 when dms >= 0 and -1 when dms < 0. + +signvec = sign(dms); +signvec = signvec + (signvec == 0); % Ensure +1 when dms = 0 + +% Decompress the dms data vector + +dms = abs(dms); +d = fix(dms/100); % Degrees +m = fix(dms) - abs(100*d); % Minutes +[s,msg] = roundn(100*rem(dms,1),n); % Seconds: Truncate to roundoff error +if ~isempty(msg); error(msg); end + +% Adjust for 60 seconds or 60 minutes. +% Test for seconds > 60 to allow for round-off from roundn, +% Test for minutes > 60 as a ripple effect from seconds > 60 + + +indx = find(s >= 60); +if ~isempty(indx); m(indx) = m(indx) + 1; s(indx) = s(indx) - 60; end +indx = find(m >= 60); +if ~isempty(indx); d(indx) = d(indx) + 1; m(indx) = m(indx) - 60; end + +% Data consistency checks + +if any(m > 59) | any (m < 0) + error('Minutes must be >= 0 and <= 59') + +elseif any(s >= 60) | any( s < 0) + error('Seconds must be >= 0 and < 60') +end + +% Determine where to store the sign of the angle. It should be +% associated with the largest nonzero component of d:m:s. + +dsign = signvec .* (d~=0); +msign = signvec .* (d==0 & m~=0); +ssign = signvec .* (d==0 & m==0 & s~=0); + +% In the application of signs below, the comparison with 0 is used so that +% the sign vector contains only +1 and -1. Any zero occurrences causes +% data to be lost when the sign has been applied to a higher component +% of d:m:s. Use fix function to eliminate potential round-off errors. + +d = ((dsign==0) + dsign).*fix(d); % Apply signs to the degrees +m = ((msign==0) + msign).*fix(m); % Apply signs to minutes +s = ((ssign==0) + ssign).*s; % Apply signs to seconds + +% Set the output arguments + +if nargout <= 1 + dout = [d m s]; +elseif nargout == 3 + dout = d; mout = m; sout = s; +else + error('Invalid number of output arguments') +end diff --git a/src/utils/matlab/libs/geoFunctions/e_r_corr.m b/src/utils/matlab/libs/geoFunctions/e_r_corr.m index 974b233ba..b668a714a 100644 --- a/src/utils/matlab/libs/geoFunctions/e_r_corr.m +++ b/src/utils/matlab/libs/geoFunctions/e_r_corr.m @@ -1,34 +1,31 @@ -function X_sat_rot = e_r_corr(traveltime, X_sat) -%E_R_CORR Returns rotated satellite ECEF coordinates due to Earth -%rotation during signal travel time -% -%X_sat_rot = e_r_corr(traveltime, X_sat); -% -% Inputs: -% travelTime - signal travel time -% X_sat - satellite's ECEF coordinates -% -% Outputs: -% X_sat_rot - rotated satellite's coordinates (ECEF) - -%Written by Kai Borre -%Copyright (c) by Kai Borre -% -% CVS record: -% $Id: e_r_corr.m,v 1.1.1.1.2.6 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -Omegae_dot = 7.292115147e-5; % rad/sec - -%--- Find rotation angle -------------------------------------------------- -omegatau = Omegae_dot * traveltime; - -%--- Make a rotation matrix ----------------------------------------------- -R3 = [ cos(omegatau) sin(omegatau) 0; - -sin(omegatau) cos(omegatau) 0; - 0 0 1]; - -%--- Do the rotation ------------------------------------------------------ -X_sat_rot = R3 * X_sat; - -%%%%%%%% end e_r_corr.m %%%%%%%%%%%%%%%%%%%% \ No newline at end of file +function X_sat_rot = e_r_corr(traveltime, X_sat) +% E_R_CORR Returns rotated satellite ECEF coordinates due to Earth +% rotation during signal travel time +% +% X_sat_rot = e_r_corr(traveltime, X_sat); +% +% Inputs: +% travelTime - signal travel time +% X_sat - satellite's ECEF coordinates +% +% Outputs: +% X_sat_rot - rotated satellite's coordinates (ECEF) + +% Written by Kai Borre +% Copyright (c) by Kai Borre +%========================================================================== + +Omegae_dot = 7.292115147e-5; % rad/sec + +%--- Find rotation angle -------------------------------------------------- +omegatau = Omegae_dot * traveltime; + +%--- Make a rotation matrix ----------------------------------------------- +R3 = [ cos(omegatau) sin(omegatau) 0; + -sin(omegatau) cos(omegatau) 0; + 0 0 1]; + +%--- Do the rotation ------------------------------------------------------ +X_sat_rot = R3 * X_sat; + +%%%%%%%% end e_r_corr.m %%%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/findUtmZone.m b/src/utils/matlab/libs/geoFunctions/findUtmZone.m index 7630bf8e1..e5717d635 100644 --- a/src/utils/matlab/libs/geoFunctions/findUtmZone.m +++ b/src/utils/matlab/libs/geoFunctions/findUtmZone.m @@ -1,72 +1,69 @@ -function utmZone = findUtmZone(latitude, longitude) -%Function finds the UTM zone number for given longitude and latitude. -%The longitude value must be between -180 (180 degree West) and 180 (180 -%degree East) degree. The latitude must be within -80 (80 degree South) and -%84 (84 degree North). -% -%utmZone = findUtmZone(latitude, longitude); -% -%Latitude and longitude must be in decimal degrees (e.g. 15.5 degrees not -%15 deg 30 min). - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -% -% Copyright (C) Darius Plausinaitis -% Written by Darius Plausinaitis -%-------------------------------------------------------------------------- -%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, write to the Free Software -%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -%USA. -%========================================================================== - -%CVS record: -%$Id: findUtmZone.m,v 1.1.2.2 2006/08/22 13:45:59 dpl Exp $ - -%% Check value bounds ===================================================== - -if ((longitude > 180) || (longitude < -180)) - error('Longitude value exceeds limits (-180:180).'); -end - -if ((latitude > 84) || (latitude < -80)) - error('Latitude value exceeds limits (-80:84).'); -end - -%% Find zone ============================================================== - -% Start at 180 deg west = -180 deg - -utmZone = fix((180 + longitude)/ 6) + 1; - -%% Correct zone numbers for particular areas ============================== - -if (latitude > 72) - % Corrections for zones 31 33 35 37 - if ((longitude >= 0) && (longitude < 9)) - utmZone = 31; - elseif ((longitude >= 9) && (longitude < 21)) - utmZone = 33; - elseif ((longitude >= 21) && (longitude < 33)) - utmZone = 35; - elseif ((longitude >= 33) && (longitude < 42)) - utmZone = 37; - end - -elseif ((latitude >= 56) && (latitude < 64)) - % Correction for zone 32 - if ((longitude >= 3) && (longitude < 12)) - utmZone = 32; - end -end \ No newline at end of file +function utmZone = findUtmZone(latitude, longitude) +% Function finds the UTM zone number for given longitude and latitude. +% The longitude value must be between -180 (180 degree West) and 180 (180 +% degree East) degree. The latitude must be within -80 (80 degree South) and +% 84 (84 degree North). +% +% utmZone = findUtmZone(latitude, longitude); +% +% Latitude and longitude must be in decimal degrees (e.g. 15.5 degrees not +% 15 deg 30 min). + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +% +% Copyright (C) Darius Plausinaitis +% Written by Darius Plausinaitis +%-------------------------------------------------------------------------- +%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, write to the Free Software +%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +%USA. +%========================================================================== + +%% Check value bounds ===================================================== + +if ((longitude > 180) || (longitude < -180)) + error('Longitude value exceeds limits (-180:180).'); +end + +if ((latitude > 84) || (latitude < -80)) + error('Latitude value exceeds limits (-80:84).'); +end + +%% Find zone ============================================================== + +% Start at 180 deg west = -180 deg + +utmZone = fix((180 + longitude)/ 6) + 1; + +%% Correct zone numbers for particular areas ============================== + +if (latitude > 72) + % Corrections for zones 31 33 35 37 + if ((longitude >= 0) && (longitude < 9)) + utmZone = 31; + elseif ((longitude >= 9) && (longitude < 21)) + utmZone = 33; + elseif ((longitude >= 21) && (longitude < 33)) + utmZone = 35; + elseif ((longitude >= 33) && (longitude < 42)) + utmZone = 37; + end + +elseif ((latitude >= 56) && (latitude < 64)) + % Correction for zone 32 + if ((longitude >= 3) && (longitude < 12)) + utmZone = 32; + end +end diff --git a/src/utils/matlab/libs/geoFunctions/geo2cart.m b/src/utils/matlab/libs/geoFunctions/geo2cart.m index 02f0d5768..90cd6a10f 100644 --- a/src/utils/matlab/libs/geoFunctions/geo2cart.m +++ b/src/utils/matlab/libs/geoFunctions/geo2cart.m @@ -1,48 +1,46 @@ -function [X, Y, Z] = geo2cart(phi, lambda, h, i) -%GEO2CART Conversion of geographical coordinates (phi, lambda, h) to -%Cartesian coordinates (X, Y, Z). -% -%[X, Y, Z] = geo2cart(phi, lambda, h, i); -% -%Format for phi and lambda: [degrees minutes seconds]. -%h, X, Y, and Z are in meters. -% -%Choices i of Reference Ellipsoid -% 1. International Ellipsoid 1924 -% 2. International Ellipsoid 1967 -% 3. World Geodetic System 1972 -% 4. Geodetic Reference System 1980 -% 5. World Geodetic System 1984 -% -% Inputs: -% phi - geocentric latitude (format [degrees minutes seconds]) -% lambda - geocentric longitude (format [degrees minutes seconds]) -% h - height -% i - reference ellipsoid type -% -% Outputs: -% X, Y, Z - Cartesian coordinates (meters) - -%Kai Borre 10-13-98 -%Copyright (c) by Kai Borre -% -% CVS record: -% $Id: geo2cart.m,v 1.1.2.7 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -b = phi(1) + phi(2)/60 + phi(3)/3600; -b = b*pi / 180; -l = lambda(1) + lambda(2)/60 + lambda(3)/3600; -l = l*pi / 180; - -a = [6378388 6378160 6378135 6378137 6378137]; -f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563]; - -ex2 = (2-f(i))*f(i) / ((1-f(i))^2); -c = a(i) * sqrt(1+ex2); -N = c / sqrt(1 + ex2*cos(b)^2); - -X = (N+h) * cos(b) * cos(l); -Y = (N+h) * cos(b) * sin(l); -Z = ((1-f(i))^2*N + h) * sin(b); -%%%%%%%%%%%%%% end geo2cart.m %%%%%%%%%%%%%%%%%%%%%%%% +function [X, Y, Z] = geo2cart(phi, lambda, h, i) +% GEO2CART Conversion of geographical coordinates (phi, lambda, h) to +% Cartesian coordinates (X, Y, Z). +% +% [X, Y, Z] = geo2cart(phi, lambda, h, i); +% +% Format for phi and lambda: [degrees minutes seconds]. +% h, X, Y, and Z are in meters. +% +% Choices i of Reference Ellipsoid +% 1. International Ellipsoid 1924 +% 2. International Ellipsoid 1967 +% 3. World Geodetic System 1972 +% 4. Geodetic Reference System 1980 +% 5. World Geodetic System 1984 +% +% Inputs: +% phi - geocentric latitude (format [degrees minutes seconds]) +% lambda - geocentric longitude (format [degrees minutes seconds]) +% h - height +% i - reference ellipsoid type +% +% Outputs: +% X, Y, Z - Cartesian coordinates (meters) + +% Kai Borre 10-13-98 +% Copyright (c) by Kai Borre +%========================================================================== + +b = phi(1) + phi(2)/60 + phi(3)/3600; +b = b*pi / 180; +l = lambda(1) + lambda(2)/60 + lambda(3)/3600; +l = l*pi / 180; + +a = [6378388 6378160 6378135 6378137 6378137]; +f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563]; + +ex2 = (2-f(i))*f(i) / ((1-f(i))^2); +c = a(i) * sqrt(1+ex2); +N = c / sqrt(1 + ex2*cos(b)^2); + +X = (N+h) * cos(b) * cos(l); +Y = (N+h) * cos(b) * sin(l); +Z = ((1-f(i))^2*N + h) * sin(b); + +%%%%%%%%%%%%%% end geo2cart.m %%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/leastSquarePos.m b/src/utils/matlab/libs/geoFunctions/leastSquarePos.m index 07d04f080..dee7e2180 100644 --- a/src/utils/matlab/libs/geoFunctions/leastSquarePos.m +++ b/src/utils/matlab/libs/geoFunctions/leastSquarePos.m @@ -1,114 +1,111 @@ -function [pos, el, az, dop] = leastSquarePos(satpos, obs, settings) -%Function calculates the Least Square Solution. -% -%[pos, el, az, dop] = leastSquarePos(satpos, obs, settings); -% -% Inputs: -% satpos - Satellites positions (in ECEF system: [X; Y; Z;] - -% one column per satellite) -% obs - Observations - the pseudorange measurements to each -% satellite: -% (e.g. [20000000 21000000 .... .... .... .... ....]) -% settings - receiver settings -% -% Outputs: -% pos - receiver position and receiver clock error -% (in ECEF system: [X, Y, Z, dt]) -% el - Satellites elevation angles (degrees) -% az - Satellites azimuth angles (degrees) -% dop - Dilutions Of Precision ([GDOP PDOP HDOP VDOP TDOP]) - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -%-------------------------------------------------------------------------- -%Based on Kai Borre -%Copyright (c) by Kai Borre -%Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen -% -% CVS record: -% $Id: leastSquarePos.m,v 1.1.2.12 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -%=== Initialization ======================================================= -nmbOfIterations = 7; - -dtr = pi/180; -pos = zeros(4, 1); -X = satpos; -nmbOfSatellites = size(satpos, 2); - -A = zeros(nmbOfSatellites, 4); -omc = zeros(nmbOfSatellites, 1); -az = zeros(1, nmbOfSatellites); -el = az; - -%=== Iteratively find receiver position =================================== -for iter = 1:nmbOfIterations - - for i = 1:nmbOfSatellites - if iter == 1 - %--- Initialize variables at the first iteration -------------- - Rot_X = X(:, i); - trop = 2; - else - %--- Update equations ----------------------------------------- - rho2 = (X(1, i) - pos(1))^2 + (X(2, i) - pos(2))^2 + ... - (X(3, i) - pos(3))^2; - traveltime = sqrt(rho2) / settings.c ; - - %--- Correct satellite position (do to earth rotation) -------- - Rot_X = e_r_corr(traveltime, X(:, i)); - - %--- Find the elevation angel of the satellite ---------------- - [az(i), el(i), dist] = topocent(pos(1:3, :), Rot_X - pos(1:3, :)); - - if (settings.useTropCorr == 1) - %--- Calculate tropospheric correction -------------------- - trop = tropo(sin(el(i) * dtr), ... - 0.0, 1013.0, 293.0, 50.0, 0.0, 0.0, 0.0); - else - % Do not calculate or apply the tropospheric corrections - trop = 0; - end - end % if iter == 1 ... ... else - - %--- Apply the corrections ---------------------------------------- - omc(i) = (obs(i) - norm(Rot_X - pos(1:3), 'fro') - pos(4) - trop); - - %--- Construct the A matrix --------------------------------------- - A(i, :) = [ (-(Rot_X(1) - pos(1))) / obs(i) ... - (-(Rot_X(2) - pos(2))) / obs(i) ... - (-(Rot_X(3) - pos(3))) / obs(i) ... - 1 ]; - end % for i = 1:nmbOfSatellites - - % These lines allow the code to exit gracefully in case of any errors - if rank(A) ~= 4 - pos = zeros(1, 4); - return - end - - %--- Find position update --------------------------------------------- - x = A \ omc; - - %--- Apply position update -------------------------------------------- - pos = pos + x; - -end % for iter = 1:nmbOfIterations - -pos = pos'; - -%=== Calculate Dilution Of Precision ====================================== -if nargout == 4 - %--- Initialize output ------------------------------------------------ - dop = zeros(1, 5); - - %--- Calculate DOP ---------------------------------------------------- - Q = inv(A'*A); - - dop(1) = sqrt(trace(Q)); % GDOP - dop(2) = sqrt(Q(1,1) + Q(2,2) + Q(3,3)); % PDOP - dop(3) = sqrt(Q(1,1) + Q(2,2)); % HDOP - dop(4) = sqrt(Q(3,3)); % VDOP - dop(5) = sqrt(Q(4,4)); % TDOP -end +function [pos, el, az, dop] = leastSquarePos(satpos, obs, settings) +% Function calculates the Least Square Solution. +% +% [pos, el, az, dop] = leastSquarePos(satpos, obs, settings); +% +% Inputs: +% satpos - Satellites positions (in ECEF system: [X; Y; Z;] - +% one column per satellite) +% obs - Observations - the pseudorange measurements to each +% satellite: +% (e.g. [20000000 21000000 .... .... .... .... ....]) +% settings - receiver settings +% +% Outputs: +% pos - receiver position and receiver clock error +% (in ECEF system: [X, Y, Z, dt]) +% el - Satellites elevation angles (degrees) +% az - Satellites azimuth angles (degrees) +% dop - Dilutions Of Precision ([GDOP PDOP HDOP VDOP TDOP]) + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +%-------------------------------------------------------------------------- +%Based on Kai Borre +%Copyright (c) by Kai Borre +%Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen +%========================================================================== + +%=== Initialization ======================================================= +nmbOfIterations = 7; + +dtr = pi/180; +pos = zeros(4, 1); +X = satpos; +nmbOfSatellites = size(satpos, 2); + +A = zeros(nmbOfSatellites, 4); +omc = zeros(nmbOfSatellites, 1); +az = zeros(1, nmbOfSatellites); +el = az; + +%=== Iteratively find receiver position =================================== +for iter = 1:nmbOfIterations + + for i = 1:nmbOfSatellites + if iter == 1 + %--- Initialize variables at the first iteration -------------- + Rot_X = X(:, i); + trop = 2; + else + %--- Update equations ----------------------------------------- + rho2 = (X(1, i) - pos(1))^2 + (X(2, i) - pos(2))^2 + ... + (X(3, i) - pos(3))^2; + traveltime = sqrt(rho2) / settings.c ; + + %--- Correct satellite position (do to earth rotation) -------- + Rot_X = e_r_corr(traveltime, X(:, i)); + + %--- Find the elevation angel of the satellite ---------------- + [az(i), el(i), dist] = topocent(pos(1:3, :), Rot_X - pos(1:3, :)); + + if (settings.useTropCorr == 1) + %--- Calculate tropospheric correction -------------------- + trop = tropo(sin(el(i) * dtr), ... + 0.0, 1013.0, 293.0, 50.0, 0.0, 0.0, 0.0); + else + % Do not calculate or apply the tropospheric corrections + trop = 0; + end + end % if iter == 1 ... ... else + + %--- Apply the corrections ---------------------------------------- + omc(i) = (obs(i) - norm(Rot_X - pos(1:3), 'fro') - pos(4) - trop); + + %--- Construct the A matrix --------------------------------------- + A(i, :) = [ (-(Rot_X(1) - pos(1))) / obs(i) ... + (-(Rot_X(2) - pos(2))) / obs(i) ... + (-(Rot_X(3) - pos(3))) / obs(i) ... + 1 ]; + end % for i = 1:nmbOfSatellites + + % These lines allow the code to exit gracefully in case of any errors + if rank(A) ~= 4 + pos = zeros(1, 4); + return + end + + %--- Find position update --------------------------------------------- + x = A \ omc; + + %--- Apply position update -------------------------------------------- + pos = pos + x; + +end % for iter = 1:nmbOfIterations + +pos = pos'; + +%=== Calculate Dilution Of Precision ====================================== +if nargout == 4 + %--- Initialize output ------------------------------------------------ + dop = zeros(1, 5); + + %--- Calculate DOP ---------------------------------------------------- + Q = inv(A'*A); + + dop(1) = sqrt(trace(Q)); % GDOP + dop(2) = sqrt(Q(1,1) + Q(2,2) + Q(3,3)); % PDOP + dop(3) = sqrt(Q(1,1) + Q(2,2)); % HDOP + dop(4) = sqrt(Q(3,3)); % VDOP + dop(5) = sqrt(Q(4,4)); % TDOP +end diff --git a/src/utils/matlab/libs/geoFunctions/mat2dms.m b/src/utils/matlab/libs/geoFunctions/mat2dms.m index 839a0a62a..fad0eca81 100644 --- a/src/utils/matlab/libs/geoFunctions/mat2dms.m +++ b/src/utils/matlab/libs/geoFunctions/mat2dms.m @@ -1,125 +1,124 @@ -function dmsvec = mat2dms(d,m,s,n) - -%MAT2DMS Converts a [deg min sec] matrix to vector format -% -% dms = MAT2DMS(d,m,s) converts a deg:min:sec matrix into a vector -% format. The vector format is dms = 100*deg + min + sec/100. -% This allows d,m,s triple to be compressed into a single value, -% which can then be employed similar to a degree or radian vector. -% The inputs d, m and s must be of equal size. Minutes and -% second must be between 0 and 60. -% -% dms = MAT2DMS(mat) assumes and input matrix of [d m s]. This is -% useful only for single column vectors for d, m and s. -% -% dms = MAT2DMS(d,m) and dms = MAT2DMS([d m]) assume that seconds -% are zero, s = 0. -% -% dms = MAT2DMS(d,m,s,n) uses n as the accuracy of the seconds -% calculation. n = -2 uses accuracy in the hundredths position, -% n = 0 uses accuracy in the units position. Default is n = -5. -% For further discussion of the input n, see ROUNDN. -% -% See also DMS2MAT - -% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. -% Written by: E. Byrns, E. Brown -% $Revision: 1.10 $ $Date: 2002/03/20 21:25:51 $ - - -if nargin == 0 - error('Incorrect number of arguments') - -elseif nargin==1 - if size(d,2)== 3 - s = d(:,3); m = d(:,2); d = d(:,1); - elseif size(d,2)== 2 - m = d(:,2); d = d(:,1); s = zeros(size(d)); - elseif size(d,2) == 0 - d = []; m = []; s = []; - else - error('Single input matrices must be n-by-2 or n-by-3.'); - end - n = -5; - -elseif nargin == 2 - s = zeros(size(d)); - n = -5; - -elseif nargin == 3 - n = -5; -end - -% Test for empty arguments - -if isempty(d) & isempty(m) & isempty(s); dmsvec = []; return; end - -% Don't let seconds be rounded beyond the tens place. -% If you did, then 55 seconds rounds to 100, which is not good. - -if n == 2; n = 1; end - -% Complex argument tests - -if any([~isreal(d) ~isreal(m) ~isreal(s)]) - warning('Imaginary parts of complex ANGLE argument ignored') - d = real(d); m = real(m); s = real(s); -end - -% Dimension and value tests - -if ~isequal(size(d),size(m),size(s)) - error('Inconsistent dimensions for input arguments') -elseif any(rem(d(~isnan(d)),1) ~= 0 | rem(m(~isnan(m)),1) ~= 0) - error('Degrees and minutes must be integers') -end - -if any(abs(m) > 60) | any (abs(m) < 0) % Actually algorithm allows for - error('Minutes must be >= 0 and < 60') % up to exactly 60 seconds or - % 60 minutes, but the error message -elseif any(abs(s) > 60) | any(abs(s) < 0) % doesn't reflect this so that angst - error('Seconds must be >= 0 and < 60') % is minimized in the user docs -end - -% Ensure that only one negative sign is present and at the correct location - -if any((s<0 & m<0) | (s<0 & d<0) | (m<0 & d<0) ) - error('Multiple negative entries in a DMS specification') -elseif any((s<0 & (m~=0 | d~= 0)) | (m<0 & d~=0)) - error('Incorrect negative DMS specification') -end - -% Construct a sign vector which has +1 when -% angle >= 0 and -1 when angle < 0. Note that the sign of the -% angle is associated with the largest nonzero component of d:m:s - -negvec = (d<0) | (m<0) | (s<0); -signvec = ~negvec - negvec; - -% Convert to all positive numbers. Allows for easier -% adjusting at 60 seconds and 60 minutes - -d = abs(d); m = abs(m); s = abs(s); - -% Truncate seconds to a specified accuracy to eliminate round-off errors - -[s,msg] = roundn(s,n); -if ~isempty(msg); error(msg); end - -% Adjust for 60 seconds or 60 minutes. If s > 60, this can only be -% from round-off during roundn since s > 60 is already tested above. -% This round-off effect has happened though. - -indx = find(s >= 60); -if ~isempty(indx); m(indx) = m(indx) + 1; s(indx) = 0; end - -% The user can not put minutes > 60 as input. However, the line -% above may create minutes > 60 (since the user can put in m == 60), -% thus, the test below includes the greater than condition. - -indx = find(m >= 60); -if ~isempty(indx); d(indx) = d(indx) + 1; m(indx) = m(indx)-60; end - -% Construct the dms vector format - -dmsvec = signvec .* (100*d + m + s/100); +function dmsvec = mat2dms(d,m,s,n) +% MAT2DMS Converts a [deg min sec] matrix to vector format +% +% dms = MAT2DMS(d,m,s) converts a deg:min:sec matrix into a vector +% format. The vector format is dms = 100*deg + min + sec/100. +% This allows d,m,s triple to be compressed into a single value, +% which can then be employed similar to a degree or radian vector. +% The inputs d, m and s must be of equal size. Minutes and +% second must be between 0 and 60. +% +% dms = MAT2DMS(mat) assumes and input matrix of [d m s]. This is +% useful only for single column vectors for d, m and s. +% +% dms = MAT2DMS(d,m) and dms = MAT2DMS([d m]) assume that seconds +% are zero, s = 0. +% +% dms = MAT2DMS(d,m,s,n) uses n as the accuracy of the seconds +% calculation. n = -2 uses accuracy in the hundredths position, +% n = 0 uses accuracy in the units position. Default is n = -5. +% For further discussion of the input n, see ROUNDN. +% +% See also DMS2MAT + +% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. +% Written by: E. Byrns, E. Brown +% Revision: 1.10 Date: 2002/03/20 21:25:51 + + +if nargin == 0 + error('Incorrect number of arguments') + +elseif nargin==1 + if size(d,2)== 3 + s = d(:,3); m = d(:,2); d = d(:,1); + elseif size(d,2)== 2 + m = d(:,2); d = d(:,1); s = zeros(size(d)); + elseif size(d,2) == 0 + d = []; m = []; s = []; + else + error('Single input matrices must be n-by-2 or n-by-3.'); + end + n = -5; + +elseif nargin == 2 + s = zeros(size(d)); + n = -5; + +elseif nargin == 3 + n = -5; +end + +% Test for empty arguments + +if isempty(d) & isempty(m) & isempty(s); dmsvec = []; return; end + +% Don't let seconds be rounded beyond the tens place. +% If you did, then 55 seconds rounds to 100, which is not good. + +if n == 2; n = 1; end + +% Complex argument tests + +if any([~isreal(d) ~isreal(m) ~isreal(s)]) + warning('Imaginary parts of complex ANGLE argument ignored') + d = real(d); m = real(m); s = real(s); +end + +% Dimension and value tests + +if ~isequal(size(d),size(m),size(s)) + error('Inconsistent dimensions for input arguments') +elseif any(rem(d(~isnan(d)),1) ~= 0 | rem(m(~isnan(m)),1) ~= 0) + error('Degrees and minutes must be integers') +end + +if any(abs(m) > 60) | any (abs(m) < 0) % Actually algorithm allows for + error('Minutes must be >= 0 and < 60') % up to exactly 60 seconds or + % 60 minutes, but the error message +elseif any(abs(s) > 60) | any(abs(s) < 0) % doesn't reflect this so that angst + error('Seconds must be >= 0 and < 60') % is minimized in the user docs +end + +% Ensure that only one negative sign is present and at the correct location + +if any((s<0 & m<0) | (s<0 & d<0) | (m<0 & d<0) ) + error('Multiple negative entries in a DMS specification') +elseif any((s<0 & (m~=0 | d~= 0)) | (m<0 & d~=0)) + error('Incorrect negative DMS specification') +end + +% Construct a sign vector which has +1 when +% angle >= 0 and -1 when angle < 0. Note that the sign of the +% angle is associated with the largest nonzero component of d:m:s + +negvec = (d<0) | (m<0) | (s<0); +signvec = ~negvec - negvec; + +% Convert to all positive numbers. Allows for easier +% adjusting at 60 seconds and 60 minutes + +d = abs(d); m = abs(m); s = abs(s); + +% Truncate seconds to a specified accuracy to eliminate round-off errors + +[s,msg] = roundn(s,n); +if ~isempty(msg); error(msg); end + +% Adjust for 60 seconds or 60 minutes. If s > 60, this can only be +% from round-off during roundn since s > 60 is already tested above. +% This round-off effect has happened though. + +indx = find(s >= 60); +if ~isempty(indx); m(indx) = m(indx) + 1; s(indx) = 0; end + +% The user can not put minutes > 60 as input. However, the line +% above may create minutes > 60 (since the user can put in m == 60), +% thus, the test below includes the greater than condition. + +indx = find(m >= 60); +if ~isempty(indx); d(indx) = d(indx) + 1; m(indx) = m(indx)-60; end + +% Construct the dms vector format + +dmsvec = signvec .* (100*d + m + s/100); diff --git a/src/utils/matlab/libs/geoFunctions/roundn.m b/src/utils/matlab/libs/geoFunctions/roundn.m index 936e114a5..ca2eb8998 100644 --- a/src/utils/matlab/libs/geoFunctions/roundn.m +++ b/src/utils/matlab/libs/geoFunctions/roundn.m @@ -1,46 +1,46 @@ -function [x,msg] = roundn(x,n) - -%ROUNDN Rounds input data at specified power of 10 -% -% y = ROUNDN(x) rounds the input data x to the nearest hundredth. -% -% y = ROUNDN(x,n) rounds the input data x at the specified power -% of tens position. For example, n = -2 rounds the input data to -% the 10E-2 (hundredths) position. -% -% [y,msg] = ROUNDN(...) returns the text of any error condition -% encountered in the output variable msg. -% -% See also ROUND - -% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. -% Written by: E. Byrns, E. Brown -% $Revision: 1.9 $ $Date: 2002/03/20 21:26:19 $ - -msg = []; % Initialize output - -if nargin == 0 - error('Incorrect number of arguments') -elseif nargin == 1 - n = -2; -end - -% Test for scalar n - -if max(size(n)) ~= 1 - msg = 'Scalar accuracy required'; - if nargout < 2; error(msg); end - return -elseif ~isreal(n) - warning('Imaginary part of complex N argument ignored') - n = real(n); -end - -% Compute the exponential factors for rounding at specified -% power of 10. Ensure that n is an integer. - -factors = 10 ^ (fix(-n)); - -% Set the significant digits for the input data - -x = round(x * factors) / factors; \ No newline at end of file +function [x,msg] = roundn(x,n) + +% ROUNDN Rounds input data at specified power of 10 +% +% y = ROUNDN(x) rounds the input data x to the nearest hundredth. +% +% y = ROUNDN(x,n) rounds the input data x at the specified power +% of tens position. For example, n = -2 rounds the input data to +% the 10E-2 (hundredths) position. +% +% [y,msg] = ROUNDN(...) returns the text of any error condition +% encountered in the output variable msg. +% +% See also ROUND + +% Copyright 1996-2002 Systems Planning and Analysis, Inc. and The MathWorks, Inc. +% Written by: E. Byrns, E. Brown +% Revision: 1.9 Date: 2002/03/20 21:26:19 + +msg = []; % Initialize output + +if nargin == 0 + error('Incorrect number of arguments') +elseif nargin == 1 + n = -2; +end + +% Test for scalar n + +if max(size(n)) ~= 1 + msg = 'Scalar accuracy required'; + if nargout < 2; error(msg); end + return +elseif ~isreal(n) + warning('Imaginary part of complex N argument ignored') + n = real(n); +end + +% Compute the exponential factors for rounding at specified +% power of 10. Ensure that n is an integer. + +factors = 10 ^ (fix(-n)); + +% Set the significant digits for the input data + +x = round(x * factors) / factors; diff --git a/src/utils/matlab/libs/geoFunctions/satpos.m b/src/utils/matlab/libs/geoFunctions/satpos.m index 14adf6570..e359a5df1 100644 --- a/src/utils/matlab/libs/geoFunctions/satpos.m +++ b/src/utils/matlab/libs/geoFunctions/satpos.m @@ -1,141 +1,138 @@ -function [satPositions, satClkCorr] = satpos(transmitTime, prnList, ... - eph, settings) -%SATPOS Computation of satellite coordinates X,Y,Z at TRANSMITTIME for -%given ephemeris EPH. Coordinates are computed for each satellite in the -%list PRNLIST. -%[satPositions, satClkCorr] = satpos(transmitTime, prnList, eph, settings); -% -% Inputs: -% transmitTime - transmission time -% prnList - list of PRN-s to be processed -% eph - ephemerides of satellites -% settings - receiver settings -% -% Outputs: -% satPositions - position of satellites (in ECEF system [X; Y; Z;]) -% satClkCorr - correction of satellite clocks - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -%-------------------------------------------------------------------------- -%Based on Kai Borre 04-09-96 -%Copyright (c) by Kai Borre -%Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen -% -% CVS record: -% $Id: satpos.m,v 1.1.2.17 2007/01/30 09:45:12 dpl Exp $ - -%% Initialize constants =================================================== -numOfSatellites = size(prnList, 2); - -% GPS constatns - -gpsPi = 3.1415926535898; % Pi used in the GPS coordinate - % system - -%--- Constants for satellite position calculation ------------------------- -Omegae_dot = 7.2921151467e-5; % Earth rotation rate, [rad/s] -GM = 3.986005e14; % Universal gravitational constant times - % the mass of the Earth, [m^3/s^2] -F = -4.442807633e-10; % Constant, [sec/(meter)^(1/2)] - -%% Initialize results ===================================================== -satClkCorr = zeros(1, numOfSatellites); -satPositions = zeros(3, numOfSatellites); - -%% Process each satellite ================================================= - -for satNr = 1 : numOfSatellites - - prn = prnList(satNr); - -%% Find initial satellite clock correction -------------------------------- - - %--- Find time difference --------------------------------------------- - dt = check_t(transmitTime - eph(prn).t_oc); - - %--- Calculate clock correction --------------------------------------- - satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ... - eph(prn).a_f0 - ... - eph(prn).T_GD; - - time = transmitTime - satClkCorr(satNr); - -%% Find satellite's position ---------------------------------------------- - - %Restore semi-major axis - a = eph(prn).sqrtA * eph(prn).sqrtA; - - %Time correction - tk = check_t(time - eph(prn).t_oe); - - %Initial mean motion - n0 = sqrt(GM / a^3); - %Mean motion - n = n0 + eph(prn).deltan; - - %Mean anomaly - M = eph(prn).M_0 + n * tk; - %Reduce mean anomaly to between 0 and 360 deg - M = rem(M + 2*gpsPi, 2*gpsPi); - - %Initial guess of eccentric anomaly - E = M; - - %--- Iteratively compute eccentric anomaly ---------------------------- - for ii = 1:10 - E_old = E; - E = M + eph(prn).e * sin(E); - dE = rem(E - E_old, 2*gpsPi); - - if abs(dE) < 1.e-12 - % Necessary precision is reached, exit from the loop - break; - end - end - - %Reduce eccentric anomaly to between 0 and 360 deg - E = rem(E + 2*gpsPi, 2*gpsPi); - - %Compute relativistic correction term - dtr = F * eph(prn).e * eph(prn).sqrtA * sin(E); - - %Calculate the true anomaly - nu = atan2(sqrt(1 - eph(prn).e^2) * sin(E), cos(E)-eph(prn).e); - - %Compute angle phi - phi = nu + eph(prn).omega; - %Reduce phi to between 0 and 360 deg - phi = rem(phi, 2*gpsPi); - - %Correct argument of latitude - u = phi + ... - eph(prn).C_uc * cos(2*phi) + ... - eph(prn).C_us * sin(2*phi); - %Correct radius - r = a * (1 - eph(prn).e*cos(E)) + ... - eph(prn).C_rc * cos(2*phi) + ... - eph(prn).C_rs * sin(2*phi); - %Correct inclination - i = eph(prn).i_0 + eph(prn).iDot * tk + ... - eph(prn).C_ic * cos(2*phi) + ... - eph(prn).C_is * sin(2*phi); - - %Compute the angle between the ascending node and the Greenwich meridian - Omega = eph(prn).omega_0 + (eph(prn).omegaDot - Omegae_dot)*tk - ... - Omegae_dot * eph(prn).t_oe; - %Reduce to between 0 and 360 deg - Omega = rem(Omega + 2*gpsPi, 2*gpsPi); - - %--- Compute satellite coordinates ------------------------------------ - satPositions(1, satNr) = cos(u)*r * cos(Omega) - sin(u)*r * cos(i)*sin(Omega); - satPositions(2, satNr) = cos(u)*r * sin(Omega) + sin(u)*r * cos(i)*cos(Omega); - satPositions(3, satNr) = sin(u)*r * sin(i); - - -%% Include relativistic correction in clock correction -------------------- - satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ... - eph(prn).a_f0 - ... - eph(prn).T_GD + dtr; - -end % for satNr = 1 : numOfSatellites +function [satPositions, satClkCorr] = satpos(transmitTime, prnList, ... + eph, settings) +% SATPOS Computation of satellite coordinates X,Y,Z at TRANSMITTIME for +% given ephemeris EPH. Coordinates are computed for each satellite in the +% list PRNLIST. +%[ satPositions, satClkCorr] = satpos(transmitTime, prnList, eph, settings); +% +% Inputs: +% transmitTime - transmission time +% prnList - list of PRN-s to be processed +% eph - ephemerides of satellites +% settings - receiver settings +% +% Outputs: +% satPositions - position of satellites (in ECEF system [X; Y; Z;]) +% satClkCorr - correction of satellite clocks + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +%-------------------------------------------------------------------------- +% Based on Kai Borre 04-09-96 +% Copyright (c) by Kai Borre +% Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen + +%% Initialize constants =================================================== +numOfSatellites = size(prnList, 2); + +% GPS constatns + +gpsPi = 3.1415926535898; % Pi used in the GPS coordinate +% system + +%--- Constants for satellite position calculation ------------------------- +Omegae_dot = 7.2921151467e-5; % Earth rotation rate, [rad/s] +GM = 3.986005e14; % Universal gravitational constant times +% the mass of the Earth, [m^3/s^2] +F = -4.442807633e-10; % Constant, [sec/(meter)^(1/2)] + +%% Initialize results ===================================================== +satClkCorr = zeros(1, numOfSatellites); +satPositions = zeros(3, numOfSatellites); + +%% Process each satellite ================================================= + +for satNr = 1 : numOfSatellites + + prn = prnList(satNr); + + %% Find initial satellite clock correction -------------------------------- + + %--- Find time difference --------------------------------------------- + dt = check_t(transmitTime - eph(prn).t_oc); + + %--- Calculate clock correction --------------------------------------- + satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ... + eph(prn).a_f0 - ... + eph(prn).T_GD; + + time = transmitTime - satClkCorr(satNr); + + %% Find satellite's position ---------------------------------------------- + + %Restore semi-major axis + a = eph(prn).sqrtA * eph(prn).sqrtA; + + %Time correction + tk = check_t(time - eph(prn).t_oe); + + %Initial mean motion + n0 = sqrt(GM / a^3); + %Mean motion + n = n0 + eph(prn).deltan; + + %Mean anomaly + M = eph(prn).M_0 + n * tk; + %Reduce mean anomaly to between 0 and 360 deg + M = rem(M + 2*gpsPi, 2*gpsPi); + + %Initial guess of eccentric anomaly + E = M; + + %--- Iteratively compute eccentric anomaly ---------------------------- + for ii = 1:10 + E_old = E; + E = M + eph(prn).e * sin(E); + dE = rem(E - E_old, 2*gpsPi); + + if abs(dE) < 1.e-12 + % Necessary precision is reached, exit from the loop + break; + end + end + + %Reduce eccentric anomaly to between 0 and 360 deg + E = rem(E + 2*gpsPi, 2*gpsPi); + + %Compute relativistic correction term + dtr = F * eph(prn).e * eph(prn).sqrtA * sin(E); + + %Calculate the true anomaly + nu = atan2(sqrt(1 - eph(prn).e^2) * sin(E), cos(E)-eph(prn).e); + + %Compute angle phi + phi = nu + eph(prn).omega; + %Reduce phi to between 0 and 360 deg + phi = rem(phi, 2*gpsPi); + + %Correct argument of latitude + u = phi + ... + eph(prn).C_uc * cos(2*phi) + ... + eph(prn).C_us * sin(2*phi); + %Correct radius + r = a * (1 - eph(prn).e*cos(E)) + ... + eph(prn).C_rc * cos(2*phi) + ... + eph(prn).C_rs * sin(2*phi); + %Correct inclination + i = eph(prn).i_0 + eph(prn).iDot * tk + ... + eph(prn).C_ic * cos(2*phi) + ... + eph(prn).C_is * sin(2*phi); + + %Compute the angle between the ascending node and the Greenwich meridian + Omega = eph(prn).omega_0 + (eph(prn).omegaDot - Omegae_dot)*tk - ... + Omegae_dot * eph(prn).t_oe; + %Reduce to between 0 and 360 deg + Omega = rem(Omega + 2*gpsPi, 2*gpsPi); + + %--- Compute satellite coordinates ------------------------------------ + satPositions(1, satNr) = cos(u)*r * cos(Omega) - sin(u)*r * cos(i)*sin(Omega); + satPositions(2, satNr) = cos(u)*r * sin(Omega) + sin(u)*r * cos(i)*cos(Omega); + satPositions(3, satNr) = sin(u)*r * sin(i); + + + %% Include relativistic correction in clock correction -------------------- + satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ... + eph(prn).a_f0 - ... + eph(prn).T_GD + dtr; + +end % for satNr = 1 : numOfSatellites diff --git a/src/utils/matlab/libs/geoFunctions/togeod.m b/src/utils/matlab/libs/geoFunctions/togeod.m index 99a43cc2c..b9d7bbb28 100644 --- a/src/utils/matlab/libs/geoFunctions/togeod.m +++ b/src/utils/matlab/libs/geoFunctions/togeod.m @@ -1,112 +1,109 @@ -function [dphi, dlambda, h] = togeod(a, finv, X, Y, Z) -%TOGEOD Subroutine to calculate geodetic coordinates latitude, longitude, -% height given Cartesian coordinates X,Y,Z, and reference ellipsoid -% values semi-major axis (a) and the inverse of flattening (finv). -% -%[dphi, dlambda, h] = togeod(a, finv, X, Y, Z); -% -% The units of linear parameters X,Y,Z,a must all agree (m,km,mi,ft,..etc) -% The output units of angular quantities will be in decimal degrees -% (15.5 degrees not 15 deg 30 min). The output units of h will be the -% same as the units of X,Y,Z,a. -% -% Inputs: -% a - semi-major axis of the reference ellipsoid -% finv - inverse of flattening of the reference ellipsoid -% X,Y,Z - Cartesian coordinates -% -% Outputs: -% dphi - latitude -% dlambda - longitude -% h - height above reference ellipsoid - -% Copyright (C) 1987 C. Goad, Columbus, Ohio -% Reprinted with permission of author, 1996 -% Fortran code translated into MATLAB -% Kai Borre 03-30-96 -% -% CVS record: -% $Id: togeod.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -h = 0; -tolsq = 1.e-10; -maxit = 10; - -% compute radians-to-degree factor -rtd = 180/pi; - -% compute square of eccentricity -if finv < 1.e-20 - esq = 0; -else - esq = (2 - 1/finv) / finv; -end - -oneesq = 1 - esq; - -% first guess -% P is distance from spin axis -P = sqrt(X^2+Y^2); -% direct calculation of longitude - -if P > 1.e-20 - dlambda = atan2(Y,X) * rtd; -else - dlambda = 0; -end - -if (dlambda < 0) - dlambda = dlambda + 360; -end - -% r is distance from origin (0,0,0) -r = sqrt(P^2 + Z^2); - -if r > 1.e-20 - sinphi = Z/r; -else - sinphi = 0; -end - -dphi = asin(sinphi); - -% initial value of height = distance from origin minus -% approximate distance from origin to surface of ellipsoid -if r < 1.e-20 - h = 0; - return -end - -h = r - a*(1-sinphi*sinphi/finv); - -% iterate -for i = 1:maxit - sinphi = sin(dphi); - cosphi = cos(dphi); - - % compute radius of curvature in prime vertical direction - N_phi = a/sqrt(1-esq*sinphi*sinphi); - - % compute residuals in P and Z - dP = P - (N_phi + h) * cosphi; - dZ = Z - (N_phi*oneesq + h) * sinphi; - - % update height and latitude - h = h + (sinphi*dZ + cosphi*dP); - dphi = dphi + (cosphi*dZ - sinphi*dP)/(N_phi + h); - - % test for convergence - if (dP*dP + dZ*dZ < tolsq) - break; - end - - % Not Converged--Warn user - if i == maxit - fprintf([' Problem in TOGEOD, did not converge in %2.0f',... - ' iterations\n'], i); - end -end % for i = 1:maxit - -dphi = dphi * rtd; -%%%%%%%% end togeod.m %%%%%%%%%%%%%%%%%%%%%% +function [dphi, dlambda, h] = togeod(a, finv, X, Y, Z) +% TOGEOD Subroutine to calculate geodetic coordinates latitude, longitude, +% height given Cartesian coordinates X,Y,Z, and reference ellipsoid +% values semi-major axis (a) and the inverse of flattening (finv). +% +% [dphi, dlambda, h] = togeod(a, finv, X, Y, Z); +% +% The units of linear parameters X,Y,Z,a must all agree (m,km,mi,ft,..etc) +% The output units of angular quantities will be in decimal degrees +% (15.5 degrees not 15 deg 30 min). The output units of h will be the +% same as the units of X,Y,Z,a. +% +% Inputs: +% a - semi-major axis of the reference ellipsoid +% finv - inverse of flattening of the reference ellipsoid +% X,Y,Z - Cartesian coordinates +% +% Outputs: +% dphi - latitude +% dlambda - longitude +% h - height above reference ellipsoid + +% Copyright (C) 1987 C. Goad, Columbus, Ohio +% Reprinted with permission of author, 1996 +% Fortran code translated into MATLAB +% Kai Borre 03-30-96 +%========================================================================== + +h = 0; +tolsq = 1.e-10; +maxit = 10; + +% compute radians-to-degree factor +rtd = 180/pi; + +% compute square of eccentricity +if finv < 1.e-20 + esq = 0; +else + esq = (2 - 1/finv) / finv; +end + +oneesq = 1 - esq; + +% first guess +% P is distance from spin axis +P = sqrt(X^2+Y^2); +% direct calculation of longitude + +if P > 1.e-20 + dlambda = atan2(Y,X) * rtd; +else + dlambda = 0; +end + +if (dlambda < 0) + dlambda = dlambda + 360; +end + +% r is distance from origin (0,0,0) +r = sqrt(P^2 + Z^2); + +if r > 1.e-20 + sinphi = Z/r; +else + sinphi = 0; +end + +dphi = asin(sinphi); + +% initial value of height = distance from origin minus +% approximate distance from origin to surface of ellipsoid +if r < 1.e-20 + h = 0; + return +end + +h = r - a*(1-sinphi*sinphi/finv); + +% iterate +for i = 1:maxit + sinphi = sin(dphi); + cosphi = cos(dphi); + + % compute radius of curvature in prime vertical direction + N_phi = a/sqrt(1-esq*sinphi*sinphi); + + % compute residuals in P and Z + dP = P - (N_phi + h) * cosphi; + dZ = Z - (N_phi*oneesq + h) * sinphi; + + % update height and latitude + h = h + (sinphi*dZ + cosphi*dP); + dphi = dphi + (cosphi*dZ - sinphi*dP)/(N_phi + h); + + % test for convergence + if (dP*dP + dZ*dZ < tolsq) + break; + end + + % Not Converged--Warn user + if i == maxit + fprintf([' Problem in TOGEOD, did not converge in %2.0f',... + ' iterations\n'], i); + end +end % for i = 1:maxit + +dphi = dphi * rtd; +%%%%%%%% end togeod.m %%%%%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/topocent.m b/src/utils/matlab/libs/geoFunctions/topocent.m index a6f680bd1..723cb3dfb 100644 --- a/src/utils/matlab/libs/geoFunctions/topocent.m +++ b/src/utils/matlab/libs/geoFunctions/topocent.m @@ -1,57 +1,54 @@ -function [Az, El, D] = topocent(X, dx) -%TOPOCENT Transformation of vector dx into topocentric coordinate -% system with origin at X. -% Both parameters are 3 by 1 vectors. -% -%[Az, El, D] = topocent(X, dx); -% -% Inputs: -% X - vector origin corrdinates (in ECEF system [X; Y; Z;]) -% dx - vector ([dX; dY; dZ;]). -% -% Outputs: -% D - vector length. Units like units of the input -% Az - azimuth from north positive clockwise, degrees -% El - elevation angle, degrees - -%Kai Borre 11-24-96 -%Copyright (c) by Kai Borre -% -% CVS record: -% $Id: topocent.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $ -%========================================================================== - -dtr = pi/180; - -[phi, lambda, h] = togeod(6378137, 298.257223563, X(1), X(2), X(3)); - -cl = cos(lambda * dtr); -sl = sin(lambda * dtr); -cb = cos(phi * dtr); -sb = sin(phi * dtr); - -F = [-sl -sb*cl cb*cl; - cl -sb*sl cb*sl; - 0 cb sb]; - -local_vector = F' * dx; -E = local_vector(1); -N = local_vector(2); -U = local_vector(3); - -hor_dis = sqrt(E^2 + N^2); - -if hor_dis < 1.e-20 - Az = 0; - El = 90; -else - Az = atan2(E, N)/dtr; - El = atan2(U, hor_dis)/dtr; -end - -if Az < 0 - Az = Az + 360; -end - -D = sqrt(dx(1)^2 + dx(2)^2 + dx(3)^2); -%%%%%%%%% end topocent.m %%%%%%%%% \ No newline at end of file +function [Az, El, D] = topocent(X, dx) +% TOPOCENT Transformation of vector dx into topocentric coordinate +% system with origin at X. +% Both parameters are 3 by 1 vectors. +% +% [Az, El, D] = topocent(X, dx); +% +% Inputs: +% X - vector origin corrdinates (in ECEF system [X; Y; Z;]) +% dx - vector ([dX; dY; dZ;]). +% +% Outputs: +% D - vector length. Units like units of the input +% Az - azimuth from north positive clockwise, degrees +% El - elevation angle, degrees + +% Kai Borre 11-24-96 +% Copyright (c) by Kai Borre +%========================================================================== + +dtr = pi/180; + +[phi, lambda, h] = togeod(6378137, 298.257223563, X(1), X(2), X(3)); + +cl = cos(lambda * dtr); +sl = sin(lambda * dtr); +cb = cos(phi * dtr); +sb = sin(phi * dtr); + +F = [-sl -sb*cl cb*cl; + cl -sb*sl cb*sl; + 0 cb sb]; + +local_vector = F' * dx; +E = local_vector(1); +N = local_vector(2); +U = local_vector(3); + +hor_dis = sqrt(E^2 + N^2); + +if hor_dis < 1.e-20 + Az = 0; + El = 90; +else + Az = atan2(E, N)/dtr; + El = atan2(U, hor_dis)/dtr; +end + +if Az < 0 + Az = Az + 360; +end + +D = sqrt(dx(1)^2 + dx(2)^2 + dx(3)^2); +%%%%%%%%% end topocent.m %%%%%%%%% diff --git a/src/utils/matlab/libs/geoFunctions/tropo.m b/src/utils/matlab/libs/geoFunctions/tropo.m index bd14b8c52..4e1801aac 100644 --- a/src/utils/matlab/libs/geoFunctions/tropo.m +++ b/src/utils/matlab/libs/geoFunctions/tropo.m @@ -1,98 +1,95 @@ -function ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum) -%TROPO Calculation of tropospheric correction. -% The range correction ddr in m is to be subtracted from -% pseudo-ranges and carrier phases -% -%ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum); -% -% Inputs: -% sinel - sin of elevation angle of satellite -% hsta - height of station in km -% p - atmospheric pressure in mb at height hp -% tkel - surface temperature in degrees Kelvin at height htkel -% hum - humidity in % at height hhum -% hp - height of pressure measurement in km -% htkel - height of temperature measurement in km -% hhum - height of humidity measurement in km -% -% Outputs: -% ddr - range correction (meters) -% -% Reference -% Goad, C.C. & Goodman, L. (1974) A Modified Tropospheric -% Refraction Correction Model. Paper presented at the -% American Geophysical Union Annual Fall Meeting, San -% Francisco, December 12-17 - -% A Matlab reimplementation of a C code from driver. -% Kai Borre 06-28-95 -% -% CVS record: -% $Id: tropo.m,v 1.1.1.1.2.4 2006/08/22 13:46:00 dpl Exp $ -%========================================================================== - -a_e = 6378.137; % semi-major axis of earth ellipsoid -b0 = 7.839257e-5; -tlapse = -6.5; -tkhum = tkel + tlapse*(hhum-htkel); -atkel = 7.5*(tkhum-273.15) / (237.3+tkhum-273.15); -e0 = 0.0611 * hum * 10^atkel; -tksea = tkel - tlapse*htkel; -em = -978.77 / (2.8704e6*tlapse*1.0e-5); -tkelh = tksea + tlapse*hhum; -e0sea = e0 * (tksea/tkelh)^(4*em); -tkelp = tksea + tlapse*hp; -psea = p * (tksea/tkelp)^em; - -if sinel < 0 - sinel = 0; -end - -tropo = 0; -done = 'FALSE'; -refsea = 77.624e-6 / tksea; -htop = 1.1385e-5 / refsea; -refsea = refsea * psea; -ref = refsea * ((htop-hsta)/htop)^4; - -while 1 - rtop = (a_e+htop)^2 - (a_e+hsta)^2*(1-sinel^2); - - % check to see if geometry is crazy - if rtop < 0 - rtop = 0; - end - - rtop = sqrt(rtop) - (a_e+hsta)*sinel; - a = -sinel/(htop-hsta); - b = -b0*(1-sinel^2) / (htop-hsta); - rn = zeros(8,1); - - for i = 1:8 - rn(i) = rtop^(i+1); - end - - alpha = [2*a, 2*a^2+4*b/3, a*(a^2+3*b),... - a^4/5+2.4*a^2*b+1.2*b^2, 2*a*b*(a^2+3*b)/3,... - b^2*(6*a^2+4*b)*1.428571e-1, 0, 0]; - - if b^2 > 1.0e-35 - alpha(7) = a*b^3/2; - alpha(8) = b^4/9; - end - - dr = rtop; - dr = dr + alpha*rn; - tropo = tropo + dr*ref*1000; - - if done == 'TRUE ' - ddr = tropo; - break; - end - - done = 'TRUE '; - refsea = (371900.0e-6/tksea-12.92e-6)/tksea; - htop = 1.1385e-5 * (1255/tksea+0.05)/refsea; - ref = refsea * e0sea * ((htop-hsta)/htop)^4; -end; -%%%%%%%%% end tropo.m %%%%%%%%%%%%%%%%%%% +function ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum) +% TROPO Calculation of tropospheric correction. +% The range correction ddr in m is to be subtracted from +% pseudo-ranges and carrier phases +% +% ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum); +% +% Inputs: +% sinel - sin of elevation angle of satellite +% hsta - height of station in km +% p - atmospheric pressure in mb at height hp +% tkel - surface temperature in degrees Kelvin at height htkel +% hum - humidity in % at height hhum +% hp - height of pressure measurement in km +% htkel - height of temperature measurement in km +% hhum - height of humidity measurement in km +% +% Outputs: +% ddr - range correction (meters) +% +% Reference +% Goad, C.C. & Goodman, L. (1974) A Modified Tropospheric +% Refraction Correction Model. Paper presented at the +% American Geophysical Union Annual Fall Meeting, San +% Francisco, December 12-17 + +% A Matlab reimplementation of a C code from driver. +% Kai Borre 06-28-95 +%========================================================================== + +a_e = 6378.137; % semi-major axis of earth ellipsoid +b0 = 7.839257e-5; +tlapse = -6.5; +tkhum = tkel + tlapse*(hhum-htkel); +atkel = 7.5*(tkhum-273.15) / (237.3+tkhum-273.15); +e0 = 0.0611 * hum * 10^atkel; +tksea = tkel - tlapse*htkel; +em = -978.77 / (2.8704e6*tlapse*1.0e-5); +tkelh = tksea + tlapse*hhum; +e0sea = e0 * (tksea/tkelh)^(4*em); +tkelp = tksea + tlapse*hp; +psea = p * (tksea/tkelp)^em; + +if sinel < 0 + sinel = 0; +end + +tropo = 0; +done = 'FALSE'; +refsea = 77.624e-6 / tksea; +htop = 1.1385e-5 / refsea; +refsea = refsea * psea; +ref = refsea * ((htop-hsta)/htop)^4; + +while 1 + rtop = (a_e+htop)^2 - (a_e+hsta)^2*(1-sinel^2); + + % check to see if geometry is crazy + if rtop < 0 + rtop = 0; + end + + rtop = sqrt(rtop) - (a_e+hsta)*sinel; + a = -sinel/(htop-hsta); + b = -b0*(1-sinel^2) / (htop-hsta); + rn = zeros(8,1); + + for i = 1:8 + rn(i) = rtop^(i+1); + end + + alpha = [2*a, 2*a^2+4*b/3, a*(a^2+3*b),... + a^4/5+2.4*a^2*b+1.2*b^2, 2*a*b*(a^2+3*b)/3,... + b^2*(6*a^2+4*b)*1.428571e-1, 0, 0]; + + if b^2 > 1.0e-35 + alpha(7) = a*b^3/2; + alpha(8) = b^4/9; + end + + dr = rtop; + dr = dr + alpha*rn; + tropo = tropo + dr*ref*1000; + + if done == 'TRUE ' + ddr = tropo; + break; + end + + done = 'TRUE '; + refsea = (371900.0e-6/tksea-12.92e-6)/tksea; + htop = 1.1385e-5 * (1255/tksea+0.05)/refsea; + ref = refsea * e0sea * ((htop-hsta)/htop)^4; +end; +%%%%%%%%% end tropo.m %%%%%%%%%%%%%%%%%%% diff --git a/src/utils/matlab/libs/gps_l1_ca_dll_fll_pll_read_tracking_dump.m b/src/utils/matlab/libs/gps_l1_ca_dll_fll_pll_read_tracking_dump.m deleted file mode 100644 index d7f7bb58a..000000000 --- a/src/utils/matlab/libs/gps_l1_ca_dll_fll_pll_read_tracking_dump.m +++ /dev/null @@ -1,178 +0,0 @@ -% /*! -% * \file gps_l1_ca_dll_fll_pll_read_tracking_dump.m -% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -function [GNSS_tracking] = gps_l1_ca_dll_fll_pll_read_tracking_dump (filename, samplingFreq, count) - - %% usage: gps_l1_ca_dll_fll_pll_read_tracking_dump (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,3,nargin); - num_float_vars=16; - num_double_vars=1; - double_size_bytes=8; - float_size_bytes=4; - skip_bytes_each_read=float_size_bytes*num_float_vars+double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 3) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v6 = fread (f, count, 'uint32',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v7 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v8 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v9 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v10 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v11 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v12 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v13 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v14 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v15 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v16 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v17 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - fclose (f); - - %%%%%%%% output vars %%%%%%%% - -% // EPR -% d_dump_file.write((char*)&tmp_E, sizeof(float)); -% d_dump_file.write((char*)&tmp_P, sizeof(float)); -% d_dump_file.write((char*)&tmp_L, sizeof(float)); -% // PROMPT I and Q (to analyze navigation symbols) -% d_dump_file.write((char*)&prompt_I, sizeof(float)); -% d_dump_file.write((char*)&prompt_Q, sizeof(float)); -% // PRN start sample stamp -% //tmp_float=(float)d_sample_counter; -% d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); -% // accumulated carrier phase -% d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); -% -% // carrier and code frequency -% d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); -% d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); -% -% //PLL commands -% d_dump_file.write((char*)&PLL_discriminator_hz, sizeof(float)); -% d_dump_file.write((char*)&carr_nco_hz, sizeof(float)); -% -% //DLL commands -% d_dump_file.write((char*)&code_error_chips, sizeof(float)); -% d_dump_file.write((char*)&d_code_phase_samples, sizeof(float)); -% -% // CN0 and carrier lock test -% d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); -% d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); -% -% // AUX vars (for debug purposes) -% tmp_float=0; -% d_dump_file.write((char*)&tmp_float, sizeof(float)); -% d_dump_file.write((char*)&d_sample_counter_seconds, sizeof(double)); - - E=v1; - P=v2; - L=v3; - prompt_I=v4; - prompt_Q=v5; - PRN_start_sample=v6; - acc_carrier_phase_rad=v7; - carrier_doppler_hz=v8; - code_freq_hz=v9; - PLL_discriminator_hz=v10; - carr_nco_hz=v11; - code_error_chips=v12; - code_phase_samples=v13; - CN0_SNV_dB_Hz=v14; - carrier_lock_test=v15; - var1=v16; - var2=v17; - - GNSS_tracking.E=E; - GNSS_tracking.P=P; - GNSS_tracking.L=L; - GNSS_tracking.prompt_I=prompt_I; - GNSS_tracking.prompt_Q=prompt_Q; - GNSS_tracking.PRN_start_sample=PRN_start_sample; - GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; - GNSS_tracking.carrier_doppler_hz=carrier_doppler_hz; - GNSS_tracking.code_freq_hz=code_freq_hz; - GNSS_tracking.PLL_discriminator_hz=PLL_discriminator_hz; - GNSS_tracking.carr_nco=carr_nco_hz; - GNSS_tracking.code_error_chips=code_error_chips; - GNSS_tracking.code_phase_samples=code_phase_samples; - GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; - GNSS_tracking.carrier_lock_test=carrier_lock_test; - GNSS_tracking.var1=var1; - GNSS_tracking.var2=var2; - GNSS_tracking.prn_delay_ms=1000*(GNSS_tracking.var2+GNSS_tracking.var1)./samplingFreq; - end - diff --git a/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_observables_dump.m b/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_observables_dump.m deleted file mode 100644 index a5bc2adcc..000000000 --- a/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_observables_dump.m +++ /dev/null @@ -1,60 +0,0 @@ -% Javier Arribas 2011 -function [observables] = gps_l1_ca_dll_pll_read_observables_dump (channels, filename, count) - - %% usage: read_tracking_dat (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,2,nargin); - num_double_vars=5; - double_size_bytes=8; - skip_bytes_each_read=double_size_bytes*num_double_vars*channels; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 3) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - for N=1:1:channels - observables.preamble_delay_ms(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.prn_delay_ms(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.Pseudorange_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.Pseudorange_symbol_shift(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.PRN(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - end - - fclose (f); - - %%%%%%%% output vars %%%%%%%% -% for (unsigned int i=0; i. -% * -% * ------------------------------------------------------------------------- -% */ +% Usage: gps_l1_ca_dll_pll_read_tracking_dump_64bits (filename, [count]) +% +% Opens GNSS-SDR tracking binary log file .dat and returns the contents + +% Read GNSS-SDR Tracking dump binary file into MATLAB. +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + function [GNSS_tracking] = gps_l1_ca_dll_pll_read_tracking_dump (filename, count) - %% usage: gps_l1_ca_dll_pll_read_tracking_dump (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% +m = nargchk (1,2,nargin); +num_float_vars=5; +num_unsigned_long_int_vars=1; +num_double_vars=11; +num_unsigned_int_vars=1; +double_size_bytes=8; +unsigned_long_int_size_bytes=8; +float_size_bytes=4; +long_int_size_bytes=4; - m = nargchk (1,2,nargin); - num_float_vars=16; - num_double_vars=2; - double_size_bytes=8; - float_size_bytes=4; - skip_bytes_each_read=float_size_bytes*num_float_vars+double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) +skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars+long_int_size_bytes*num_unsigned_int_vars; +bytes_shift=0; +if (m) usage (m); - end +end - if (nargin < 2) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else +if (nargin < 2) + %count = Inf; + file_stats = dir(filename); + %round num bytes to read to integer number of samples (to protect the script from binary + %dump end file transitory) + count = (file_stats.bytes - mod(file_stats.bytes,skip_bytes_each_read))/skip_bytes_each_read; +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; + bytes_shift=bytes_shift+float_size_bytes; fseek(f,bytes_shift,'bof'); % move to next interleaved float v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; + bytes_shift=bytes_shift+float_size_bytes; fseek(f,bytes_shift,'bof'); % move to next interleaved float v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; + bytes_shift=bytes_shift+float_size_bytes; fseek(f,bytes_shift,'bof'); % move to next interleaved float v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; + bytes_shift=bytes_shift+float_size_bytes; fseek(f,bytes_shift,'bof'); % move to next interleaved float v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v6 = fread (f, count, 'uint32',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v7 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v8 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v9 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v10 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v11 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v12 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v13 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v14 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v15 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v16 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved unsigned_long_int + v6 = fread (f, count, 'uint64',skip_bytes_each_read-unsigned_long_int_size_bytes); + bytes_shift=bytes_shift+unsigned_long_int_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v7 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v8 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v9 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v10 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v11 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v12 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v13 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v14 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v15 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v16 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double v17 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v18 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v18 = fread (f, count, 'uint32',skip_bytes_each_read-double_size_bytes); fclose (f); %%%%%%%% output vars %%%%%%%% -% // EPR -% d_dump_file.write((char*)&tmp_E, sizeof(float)); -% d_dump_file.write((char*)&tmp_P, sizeof(float)); -% d_dump_file.write((char*)&tmp_L, sizeof(float)); -% // PROMPT I and Q (to analyze navigation symbols) -% d_dump_file.write((char*)&prompt_I, sizeof(float)); -% d_dump_file.write((char*)&prompt_Q, sizeof(float)); -% // PRN start sample stamp -% //tmp_float=(float)d_sample_counter; -% d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); -% // accumulated carrier phase -% d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); -% -% // carrier and code frequency -% d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); -% d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); -% -% //PLL commands -% d_dump_file.write((char*)&carr_error, sizeof(float)); -% d_dump_file.write((char*)&carr_nco, sizeof(float)); -% -% //DLL commands -% d_dump_file.write((char*)&code_error, sizeof(float)); -% d_dump_file.write((char*)&code_nco, sizeof(float)); -% -% // CN0 and carrier lock test -% d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); -% d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); -% -% // AUX vars (for debug purposes) -% tmp_float=0; -% d_dump_file.write((char*)&tmp_float, sizeof(float)); -% d_dump_file.write((char*)&d_sample_counter_seconds, sizeof(double)); - + % // EPR + % d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + % d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + % d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + % // PROMPT I and Q (to analyze navigation symbols) + % d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + % d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + % // PRN start sample stamp + % //tmp_float=(float)d_sample_counter; + % d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); + % // accumulated carrier phase + % d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); + % + % // carrier and code frequency + % d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); + % d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); + % + % //PLL commands + % d_dump_file.write(reinterpret_cast(&carr_phase_error_secs_Ti), sizeof(double)); + % d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); + % + % //DLL commands + % d_dump_file.write(reinterpret_cast(&code_error_chips_Ti), sizeof(double)); + % d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); + % + % // CN0 and carrier lock test + % d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); + % d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); + % + % // AUX vars (for debug purposes) + % tmp_double = d_rem_code_phase_samples; + % d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + % tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); + % d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + % // PRN + % unsigned int prn_ = d_acquisition_gnss_synchro->PRN; + % d_dump_file.write(reinterpret_cast(&prn_), sizeof(unsigned int)); E=v1; P=v2; L=v3; @@ -158,7 +168,7 @@ function [GNSS_tracking] = gps_l1_ca_dll_pll_read_tracking_dump (filename, count carrier_lock_test=v15; var1=v16; var2=v17; - var3=v18; + PRN=v18; GNSS_tracking.E=E; GNSS_tracking.P=P; @@ -171,12 +181,12 @@ function [GNSS_tracking] = gps_l1_ca_dll_pll_read_tracking_dump (filename, count GNSS_tracking.code_freq_hz=code_freq_hz; GNSS_tracking.carr_error=carr_error; GNSS_tracking.carr_nco=carr_nco; - GNSS_tracking.code_error=code_error; + GNSS_tracking.code_error=code_error GNSS_tracking.code_nco=code_nco; GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; GNSS_tracking.carrier_lock_test=carrier_lock_test; - GNSS_tracking.var1=var1; + GNSS_tracking.d_rem_code_phase_samples=var1; GNSS_tracking.var2=var2; - GNSS_tracking.var3=var3; - end - + GNSS_tracking.PRN=PRN; +end + diff --git a/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_tracking_dump_64bits.m b/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_tracking_dump_64bits.m deleted file mode 100644 index f7d0bb97a..000000000 --- a/src/utils/matlab/libs/gps_l1_ca_dll_pll_read_tracking_dump_64bits.m +++ /dev/null @@ -1,179 +0,0 @@ -% /*! -% * \file gps_l1_ca_dll_pll_read_tracking_dump.m -% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ -function [GNSS_tracking] = gps_l1_ca_dll_pll_read_tracking_dump_64bits (filename, count) - - %% usage: gps_l1_ca_dll_pll_read_tracking_dump_64bits (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,2,nargin); - num_float_vars=15; - num_unsigned_long_int_vars=1; - num_double_vars=1; - double_size_bytes=8; - unsigned_long_int_size_bytes=8; - float_size_bytes=4; - skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 2) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v6 = fread (f, count, 'uint64',skip_bytes_each_read-unsigned_long_int_size_bytes); - bytes_shift=bytes_shift+unsigned_long_int_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v7 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v8 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v9 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v10 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v11 = fread (f, count, '*float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v12 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v13 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v14 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v15 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v16 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); - bytes_shift=bytes_shift+float_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved float - v17 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - fclose (f); - - %%%%%%%% output vars %%%%%%%% - -% // EPR -% d_dump_file.write((char*)&tmp_E, sizeof(float)); -% d_dump_file.write((char*)&tmp_P, sizeof(float)); -% d_dump_file.write((char*)&tmp_L, sizeof(float)); -% // PROMPT I and Q (to analyze navigation symbols) -% d_dump_file.write((char*)&prompt_I, sizeof(float)); -% d_dump_file.write((char*)&prompt_Q, sizeof(float)); -% // PRN start sample stamp -% //tmp_float=(float)d_sample_counter; -% d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int)); -% // accumulated carrier phase -% d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float)); -% -% // carrier and code frequency -% d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float)); -% d_dump_file.write((char*)&d_code_freq_hz, sizeof(float)); -% -% //PLL commands -% d_dump_file.write((char*)&carr_error, sizeof(float)); -% d_dump_file.write((char*)&carr_nco, sizeof(float)); -% -% //DLL commands -% d_dump_file.write((char*)&code_error, sizeof(float)); -% d_dump_file.write((char*)&code_nco, sizeof(float)); -% -% // CN0 and carrier lock test -% d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float)); -% d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float)); -% -% // AUX vars (for debug purposes) -% tmp_float=0; -% d_dump_file.write((char*)&tmp_float, sizeof(float)); -% d_dump_file.write((char*)&d_sample_counter_seconds, sizeof(double)); - - E=v1; - P=v2; - L=v3; - prompt_I=v4; - prompt_Q=v5; - PRN_start_sample=v6; - acc_carrier_phase_rad=v7; - carrier_doppler_hz=v8; - code_freq_hz=v9; - carr_error=v10; - carr_nco=v11; - code_error=v12; - code_nco=v13; - CN0_SNV_dB_Hz=v14; - carrier_lock_test=v15; - var1=v16; - var2=v17; - - GNSS_tracking.E=E; - GNSS_tracking.P=P; - GNSS_tracking.L=L; - GNSS_tracking.prompt_I=prompt_I; - GNSS_tracking.prompt_Q=prompt_Q; - GNSS_tracking.PRN_start_sample=PRN_start_sample; - GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; - GNSS_tracking.carrier_doppler_hz=carrier_doppler_hz; - GNSS_tracking.code_freq_hz=code_freq_hz; - GNSS_tracking.carr_error=carr_error; - GNSS_tracking.carr_nco=carr_nco; - GNSS_tracking.code_error=code_error; - GNSS_tracking.code_nco=code_nco; - GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; - GNSS_tracking.carrier_lock_test=carrier_lock_test; - GNSS_tracking.var1=var1; - GNSS_tracking.var2=var2; - end - diff --git a/src/utils/matlab/libs/gps_l1_ca_kf_read_tracking_dump.m b/src/utils/matlab/libs/gps_l1_ca_kf_read_tracking_dump.m new file mode 100644 index 000000000..e1f1c8687 --- /dev/null +++ b/src/utils/matlab/libs/gps_l1_ca_kf_read_tracking_dump.m @@ -0,0 +1,158 @@ +% Usage: gps_l1_ca_kf_read_tracking_dump (filename, [count]) +% +% Opens GNSS-SDR tracking binary log file .dat and returns the contents + +% Read GNSS-SDR Tracking dump binary file into MATLAB. +% Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function [GNSS_tracking] = gps_l1_ca_kf_read_tracking_dump (filename, count) + +m = nargchk (1,2,nargin); + +num_float_vars = 19; +num_unsigned_long_int_vars = 1; +num_double_vars = 1; +num_unsigned_int_vars = 1; + +if(~isempty(strfind(computer('arch'), '64'))) + % 64-bit computer + double_size_bytes = 8; + unsigned_long_int_size_bytes = 8; + float_size_bytes = 4; + unsigned_int_size_bytes = 4; +else + double_size_bytes = 8; + unsigned_long_int_size_bytes = 4; + float_size_bytes = 4; + unsigned_int_size_bytes = 4; +end + +skip_bytes_each_read = float_size_bytes * num_float_vars + unsigned_long_int_size_bytes * num_unsigned_long_int_vars + ... + double_size_bytes * num_double_vars + num_unsigned_int_vars*unsigned_int_size_bytes; + +bytes_shift = 0; + +if (m) + usage (m); +end + +if (nargin < 2) + count = Inf; +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + v1 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v2 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v3 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v4 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v5 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v6 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v7 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v8 = fread (f, count, 'long', skip_bytes_each_read - unsigned_long_int_size_bytes); + bytes_shift = bytes_shift + unsigned_long_int_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v9 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v10 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v11 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v12 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v13 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v14 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v15 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v16 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v17 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v18 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v19 = fread (f, count, 'float', skip_bytes_each_read - float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next float + v20 = fread (f, count, 'float', skip_bytes_each_read-float_size_bytes); + bytes_shift = bytes_shift + float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next double + v21 = fread (f, count, 'double', skip_bytes_each_read - double_size_bytes); + bytes_shift = bytes_shift + double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next unsigned int + v22 = fread (f, count, 'uint', skip_bytes_each_read - unsigned_int_size_bytes); + fclose (f); + + GNSS_tracking.VE = v1; + GNSS_tracking.E = v2; + GNSS_tracking.P = v3; + GNSS_tracking.L = v4; + GNSS_tracking.VL = v5; + GNSS_tracking.prompt_I = v6; + GNSS_tracking.prompt_Q = v7; + GNSS_tracking.PRN_start_sample = v8; + GNSS_tracking.acc_carrier_phase_rad = v9; + GNSS_tracking.carrier_doppler_hz = v10; + GNSS_tracking.carrier_dopplerrate_hz2 = v11; + GNSS_tracking.code_freq_hz = v12; + GNSS_tracking.carr_error = v13; + GNSS_tracking.carr_noise_sigma2 = v14; + GNSS_tracking.carr_nco = v15; + GNSS_tracking.code_error = v16; + GNSS_tracking.code_nco = v17; + GNSS_tracking.CN0_SNV_dB_Hz = v18; + GNSS_tracking.carrier_lock_test = v19; + GNSS_tracking.var1 = v20; + GNSS_tracking.var2 = v21; + GNSS_tracking.PRN = v22; +end \ No newline at end of file diff --git a/src/utils/matlab/libs/gps_l1_ca_pvt_read_pvt_dump.m b/src/utils/matlab/libs/gps_l1_ca_pvt_read_pvt_dump.m index d52958a53..1f3ae07ba 100644 --- a/src/utils/matlab/libs/gps_l1_ca_pvt_read_pvt_dump.m +++ b/src/utils/matlab/libs/gps_l1_ca_pvt_read_pvt_dump.m @@ -1,39 +1,40 @@ -% /*! -% * \file gps_l1_ca_pvt_read_pvt_dump.m -% * \brief Read GNSS-SDR PVT lib dump binary file into MATLAB. The resulting +% +% \file gps_l1_ca_pvt_read_pvt_dump.m +% \brief Read GNSS-SDR PVT lib dump binary file into MATLAB. The resulting % structure is compatible with the K.Borre MATLAB-based receiver. -% * \author Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ +% \author Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + function [navSolutions] = gps_l1_ca_pvt_read_pvt_dump (filename, count) - %% usage: gps_l1_ca_pvt_read_pvt_dump (filename, [count]) - %% - %% open GNSS-SDR PVT binary log file .dat and return the contents - %% -% +%% usage: gps_l1_ca_pvt_read_pvt_dump (filename, [count]) +%% +%% open GNSS-SDR PVT binary log file .dat and return the contents +%% +% % // PVT GPS time % tmp_double=GPS_current_time; % d_dump_file.write((char*)&tmp_double, sizeof(double)); @@ -58,57 +59,56 @@ function [navSolutions] = gps_l1_ca_pvt_read_pvt_dump (filename, count) % // GEO user position Height [m] % tmp_double=d_height_m; % d_dump_file.write((char*)&tmp_double, sizeof(double)); - - m = nargchk (1,2,nargin); - num_double_vars=8; - double_size_bytes=8; - skip_bytes_each_read=double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) - usage (m); - end - if (nargin < 3) +m = nargchk (1,2,nargin); +num_double_vars=8; +double_size_bytes=8; +skip_bytes_each_read=double_size_bytes*num_double_vars; +bytes_shift=0; +if (m) + usage (m); +end + +if (nargin < 3) count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - GPS_current_time = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - ECEF_X = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - ECEF_Y = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - ECEF_Z = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - Clock_Offset = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - Lat = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - Long = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - Height = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - fclose (f); - end - - navSolutions.X=ECEF_X.'; - navSolutions.Y=ECEF_Y.'; - navSolutions.Z=ECEF_Z.'; - navSolutions.dt=Clock_Offset.'; - navSolutions.latitude=Lat.'; - navSolutions.longitude=Long.'; - navSolutions.height=Height.'; - navSolutions.TransmitTime=GPS_current_time.'; - - \ No newline at end of file +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + GPS_current_time = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + ECEF_X = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + ECEF_Y = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + ECEF_Z = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + Clock_Offset = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + Lat = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + Long = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + Height = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + fclose (f); +end + +navSolutions.X=ECEF_X.'; +navSolutions.Y=ECEF_Y.'; +navSolutions.Z=ECEF_Z.'; +navSolutions.dt=Clock_Offset.'; +navSolutions.latitude=Lat.'; +navSolutions.longitude=Long.'; +navSolutions.height=Height.'; +navSolutions.TransmitTime=GPS_current_time.'; + diff --git a/src/utils/matlab/libs/gps_l1_ca_read_observables_dump.m b/src/utils/matlab/libs/gps_l1_ca_read_observables_dump.m deleted file mode 100644 index 32c3c1eba..000000000 --- a/src/utils/matlab/libs/gps_l1_ca_read_observables_dump.m +++ /dev/null @@ -1,61 +0,0 @@ -% Javier Arribas 2011 -function [observables] = gps_l1_ca_read_observables_dump (channels, filename, count) - - %% usage: read_tracking_dat (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% - - m = nargchk (1,2,nargin); - num_double_vars=5; - double_size_bytes=8; - skip_bytes_each_read=double_size_bytes*num_double_vars*channels; - bytes_shift=0; - if (m) - usage (m); - end - - if (nargin < 3) - count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - for N=1:1:channels - observables.d_TOW_at_current_symbol(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.Prn_timestamp_ms(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.Pseudorange_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.Flag_valid_pseudorange(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - observables.PRN(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - end - - fclose (f); - - %%%%%%%% output vars %%%%%%%% -% double tmp_double; -% for (unsigned int i=0; i. +% +% ------------------------------------------------------------------------- +% +% Javier Arribas 2011 + function [pvt_raw] = gps_l1_ca_read_pvt_raw_dump (channels, filename, count) - %% usage: read_tracking_dat (filename, [count]) - %% - %% open GNSS-SDR pvt binary log file .dat and return the contents - %% +%% usage: read_tracking_dat (filename, [count]) +%% +%% open GNSS-SDR pvt binary log file .dat and return the contents +%% - m = nargchk (1,2,nargin); - num_double_vars=3; - double_size_bytes=8; - skip_bytes_each_read=double_size_bytes*num_double_vars*channels; - bytes_shift=0; - if (m) +m = nargchk (1,2,nargin); +num_double_vars=3; +double_size_bytes=8; +skip_bytes_each_read=double_size_bytes*num_double_vars*channels; +bytes_shift=0; +if (m) usage (m); - end +end - if (nargin < 3) +if (nargin < 3) count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else for N=1:1:channels pvt_raw.Pseudorange_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); bytes_shift=bytes_shift+double_size_bytes; @@ -33,17 +58,17 @@ function [pvt_raw] = gps_l1_ca_read_pvt_raw_dump (channels, filename, count) bytes_shift=bytes_shift+double_size_bytes; fseek(f,bytes_shift,'bof'); % move to next interleaved end - + fclose (f); %%%%%%%% output vars %%%%%%%% -% for (unsigned int i=0; i. +% +% ------------------------------------------------------------------------- +% +% Javier Arribas 2011 + function [telemetry] = gps_l1_ca_read_telemetry_dump (filename, count) - %% usage: read_tracking_dat (filename, [count]) - %% - %% open GNSS-SDR tracking binary log file .dat and return the contents - %% +%% usage: read_tracking_dat (filename, [count]) +%% +%% open GNSS-SDR tracking binary log file .dat and return the contents +%% - m = nargchk (1,2,nargin); - num_double_vars=3; - double_size_bytes=8; - skip_bytes_each_read=double_size_bytes*num_double_vars; - bytes_shift=0; - if (m) +m = nargchk (1,2,nargin); +num_double_vars=3; +double_size_bytes=8; +skip_bytes_each_read=double_size_bytes*num_double_vars; +bytes_shift=0; +if (m) usage (m); - end +end - if (nargin < 3) +if (nargin < 3) count = Inf; - end - %loops_counter = fread (f, count, 'uint32',4*12); - f = fopen (filename, 'rb'); - if (f < 0) - else - telemetry.preamble_delay_ms = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - telemetry.prn_delay_ms = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - telemetry.Preamble_symbol_counter = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); - bytes_shift=bytes_shift+double_size_bytes; - fseek(f,bytes_shift,'bof'); % move to next interleaved - +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + telemetry.preamble_delay_ms = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + telemetry.prn_delay_ms = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + telemetry.Preamble_symbol_counter = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + fclose (f); %%%%%%%% output vars %%%%%%%% -% { -% double tmp_double; -% tmp_double = current_synchro_data.Preamble_delay_ms; -% d_dump_file.write((char*)&tmp_double, sizeof(double)); -% tmp_double = current_synchro_data.Prn_delay_ms; -% d_dump_file.write((char*)&tmp_double, sizeof(double)); -% tmp_double = current_synchro_data.Preamble_symbol_counter; -% d_dump_file.write((char*)&tmp_double, sizeof(double)); -% } - end - + % { + % double tmp_double; + % tmp_double = current_synchro_data.Preamble_delay_ms; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_synchro_data.Prn_delay_ms; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_synchro_data.Preamble_symbol_counter; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % } +end + diff --git a/src/utils/matlab/libs/plotKalman.m b/src/utils/matlab/libs/plotKalman.m new file mode 100644 index 000000000..e05fd0d52 --- /dev/null +++ b/src/utils/matlab/libs/plotKalman.m @@ -0,0 +1,135 @@ +function plotKalman(channelList, trackResults, settings) +% This function plots the tracking results for the given channel list. +% +% plotTracking(channelList, trackResults, settings) +% +% Inputs: +% channelList - list of channels to be plotted. +% trackResults - tracking results from the tracking function. +% settings - receiver settings. + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +% +% Copyright (C) Darius Plausinaitis +% Written by Darius Plausinaitis +%-------------------------------------------------------------------------- +%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, write to the Free Software +%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +%USA. +%-------------------------------------------------------------------------- + +% Protection - if the list contains incorrect channel numbers +channelList = intersect(channelList, 1:settings.numberOfChannels); + +%=== For all listed channels ============================================== +for channelNr = channelList + + %% Select (or create) and clear the figure ================================ + % The number 200 is added just for more convenient handling of the open + % figure windows, when many figures are closed and reopened. + % Figures drawn or opened by the user, will not be "overwritten" by + % this function. + + figure(channelNr +200); + clf(channelNr +200); + set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... + ' (PRN ', ... + num2str(trackResults(channelNr).PRN(end-1)), ... + ') results']); + + timeStart = settings.timeStartInSeconds; + + %% Draw axes ============================================================== + % Row 1 + handles(1, 1) = subplot(4, 2, 1); + handles(1, 2) = subplot(4, 2, 2); + % Row 2 + handles(2, 1) = subplot(4, 2, 3); + handles(2, 2) = subplot(4, 2, 4); + % Row 3 + handles(3, 1) = subplot(4, 2, [5 6]); + % Row 4 + handles(4, 1) = subplot(4, 2, [7 8]); + + %% Plot all figures ======================================================= + + timeAxisInSeconds = (1:settings.msToProcess)/1000; + + %----- CNo for signal---------------------------------- + plot (handles(1, 1), timeAxisInSeconds, ... + trackResults(channelNr).CNo(1:settings.msToProcess), 'b'); + + grid (handles(1, 1)); + axis (handles(1, 1), 'tight'); + xlabel(handles(1, 1), 'Time (s)'); + ylabel(handles(1, 1), 'CNo (dB-Hz)'); + title (handles(1, 1), 'Carrier to Noise Ratio'); + + %----- PLL discriminator filtered---------------------------------- + plot (handles(1, 2), timeAxisInSeconds, ... + trackResults(channelNr).state1(1:settings.msToProcess), 'b'); + + grid (handles(1, 2)); + axis (handles(1, 2), 'tight'); + xlim (handles(1, 2), [timeStart, timeAxisInSeconds(end)]); + xlabel(handles(1, 2), 'Time (s)'); + ylabel(handles(1, 2), 'Phase Amplitude'); + title (handles(1, 2), 'Filtered Carrier Phase'); + + %----- Carrier Frequency -------------------------------- + plot (handles(2, 1), timeAxisInSeconds(2:end), ... + trackResults(channelNr).state2(2:settings.msToProcess), 'Color',[0.42 0.25 0.39]); + + grid (handles(2, 1)); + axis (handles(2, 1)); + xlim (handles(2, 1), [timeStart, timeAxisInSeconds(end)]); + xlabel(handles(2, 1), 'Time (s)'); + ylabel(handles(2, 1), 'Freq (hz)'); + title (handles(2, 1), 'Filtered Doppler Frequency'); + + %----- Carrier Frequency Rate -------------------------------- + plot (handles(2, 2), timeAxisInSeconds(2:end), ... + trackResults(channelNr).state3(2:settings.msToProcess), 'Color',[0.42 0.25 0.39]); + + grid (handles(2, 2)); + axis (handles(2, 2)); + xlim (handles(2, 2), [timeStart, timeAxisInSeconds(end)]); + xlabel(handles(2, 2), 'Time (s)'); + ylabel(handles(2, 2), 'Freq (hz)'); + title (handles(2, 2), 'Filtered Doppler Frequency Rate'); + + %----- PLL discriminator unfiltered-------------------------------- + plot (handles(3, 1), timeAxisInSeconds, ... + trackResults(channelNr).innovation, 'r'); + + grid (handles(3, 1)); + axis (handles(3, 1), 'auto'); + xlim (handles(3, 1), [timeStart, timeAxisInSeconds(end)]); + xlabel(handles(3, 1), 'Time (s)'); + ylabel(handles(3, 1), 'Amplitude'); + title (handles(3, 1), 'Raw PLL discriminator (Innovation)'); + + + %----- PLL discriminator covariance -------------------------------- + plot (handles(4, 1), timeAxisInSeconds, ... + trackResults(channelNr).r_noise_cov, 'r'); + + grid (handles(4, 1)); + axis (handles(4, 1), 'auto'); + xlim (handles(4, 1), [timeStart, timeAxisInSeconds(end)]); + xlabel(handles(4, 1), 'Time (s)'); + ylabel(handles(4, 1), 'Variance'); + title (handles(4, 1), 'Estimated Noise Variance'); +end % for channelNr = channelList diff --git a/src/utils/matlab/libs/plotNavigation.m b/src/utils/matlab/libs/plotNavigation.m index 057a1926d..1a74e502b 100644 --- a/src/utils/matlab/libs/plotNavigation.m +++ b/src/utils/matlab/libs/plotNavigation.m @@ -1,170 +1,166 @@ -% /*! -% * \file plotNavigation.m -% * \brief -% Functions plots variations of coordinates over time and a 3D position -% plot. It plots receiver coordinates in UTM system or coordinate offsets if -% the true UTM receiver coordinates are provided. -% * \author Darius Plausinaitis -% * Modified by Javier Arribas, 2011. jarribas(at)cttc.es -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ - -function plotNavigation(navSolutions, settings,plot_skyplot) -%Functions plots variations of coordinates over time and a 3D position -%plot. It plots receiver coordinates in UTM system or coordinate offsets if -%the true UTM receiver coordinates are provided. -% -%plotNavigation(navSolutions, settings) -% -% Inputs: -% navSolutions - Results from navigation solution function. It -% contains measured pseudoranges and receiver -% coordinates. -% settings - Receiver settings. The true receiver coordinates -% are contained in this structure. -% plot_skyplot - If ==1 then use satellite coordinates to plot the -% the satellite positions - -%% Plot results in the necessary data exists ============================== -if (~isempty(navSolutions)) - - %% If reference position is not provided, then set reference position - %% to the average postion - if isnan(settings.truePosition.E) || isnan(settings.truePosition.N) ... - || isnan(settings.truePosition.U) - - %=== Compute mean values ========================================== - % Remove NaN-s or the output of the function MEAN will be NaN. - refCoord.E = mean(navSolutions.E(~isnan(navSolutions.E))); - refCoord.N = mean(navSolutions.N(~isnan(navSolutions.N))); - refCoord.U = mean(navSolutions.U(~isnan(navSolutions.U))); - - %Also convert geodetic coordinates to deg:min:sec vector format - meanLongitude = dms2mat(deg2dms(... - mean(navSolutions.longitude(~isnan(navSolutions.longitude)))), -5); - meanLatitude = dms2mat(deg2dms(... - mean(navSolutions.latitude(~isnan(navSolutions.latitude)))), -5); - - LatLong_str=[num2str(meanLatitude(1)), 'º', ... - num2str(meanLatitude(2)), '''', ... - num2str(meanLatitude(3)), '''''', ... - ',', ... - num2str(meanLongitude(1)), 'º', ... - num2str(meanLongitude(2)), '''', ... - num2str(meanLongitude(3)), ''''''] - - - - refPointLgText = ['Mean Position\newline Lat: ', ... - num2str(meanLatitude(1)), '{\circ}', ... - num2str(meanLatitude(2)), '{\prime}', ... - num2str(meanLatitude(3)), '{\prime}{\prime}', ... - '\newline Lng: ', ... - num2str(meanLongitude(1)), '{\circ}', ... - num2str(meanLongitude(2)), '{\prime}', ... - num2str(meanLongitude(3)), '{\prime}{\prime}', ... - '\newline Hgt: ', ... - num2str(mean(navSolutions.height(~isnan(navSolutions.height))), '%+6.1f')]; - - else - % compute the mean error for static receiver - mean_position.E = mean(navSolutions.E(~isnan(navSolutions.E))); - mean_position.N = mean(navSolutions.N(~isnan(navSolutions.N))); - mean_position.U = mean(navSolutions.U(~isnan(navSolutions.U))); - refCoord.E = settings.truePosition.E; - refCoord.N = settings.truePosition.N; - refCoord.U = settings.truePosition.U; - - error_meters=sqrt((mean_position.E-refCoord.E)^2+(mean_position.N-refCoord.N)^2+(mean_position.U-refCoord.U)^2); - - refPointLgText = ['Reference Position, Mean 3D error = ' num2str(error_meters) ' [m]']; - end - - figureNumber = 300; - % The 300 is chosen for more convenient handling of the open - % figure windows, when many figures are closed and reopened. Figures - % drawn or opened by the user, will not be "overwritten" by this - % function if the auto numbering is not used. - - %=== Select (or create) and clear the figure ========================== - figure(figureNumber); - clf (figureNumber); - set (figureNumber, 'Name', 'Navigation solutions'); - - %--- Draw axes -------------------------------------------------------- - handles(1, 1) = subplot(4, 2, 1 : 4); - handles(3, 1) = subplot(4, 2, [5, 7]); - handles(3, 2) = subplot(4, 2, [6, 8]); - -%% Plot all figures ======================================================= - - %--- Coordinate differences in UTM system ----------------------------- - plot(handles(1, 1), [(navSolutions.E - refCoord.E)', ... - (navSolutions.N - refCoord.N)',... - (navSolutions.U - refCoord.U)']); - - title (handles(1, 1), 'Coordinates variations in UTM system'); - legend(handles(1, 1), 'E', 'N', 'U'); - xlabel(handles(1, 1), ['Measurement period: ', ... - num2str(settings.navSolPeriod), 'ms']); - ylabel(handles(1, 1), 'Variations (m)'); - grid (handles(1, 1)); - axis (handles(1, 1), 'tight'); - - %--- Position plot in UTM system -------------------------------------- - plot3 (handles(3, 1), navSolutions.E - refCoord.E, ... - navSolutions.N - refCoord.N, ... - navSolutions.U - refCoord.U, '+'); - hold (handles(3, 1), 'on'); - - %Plot the reference point - plot3 (handles(3, 1), 0, 0, 0, 'r+', 'LineWidth', 1.5, 'MarkerSize', 10); - hold (handles(3, 1), 'off'); - - view (handles(3, 1), 0, 90); - axis (handles(3, 1), 'equal'); - grid (handles(3, 1), 'minor'); - - legend(handles(3, 1), 'Measurements', refPointLgText); - - title (handles(3, 1), 'Positions in UTM system (3D plot)'); - xlabel(handles(3, 1), 'East (m)'); - ylabel(handles(3, 1), 'North (m)'); - zlabel(handles(3, 1), 'Upping (m)'); - - if (plot_skyplot==1) - %--- Satellite sky plot ----------------------------------------------- - skyPlot(handles(3, 2), ... - navSolutions.channel.az, ... - navSolutions.channel.el, ... - navSolutions.channel.PRN(:, 1)); - - title (handles(3, 2), ['Sky plot (mean PDOP: ', ... - num2str(mean(navSolutions.DOP(2,:))), ')']); - end - -else - disp('plotNavigation: No navigation data to plot.'); -end % if (~isempty(navSolutions)) +% Function plots variations of coordinates over time and a 3D position +% plot. It plots receiver coordinates in UTM system or coordinate offsets if +% the true UTM receiver coordinates are provided. +% +% plotNavigation(navSolutions, settings) +% +% Inputs: +% navSolutions - Results from navigation solution function. It +% contains measured pseudoranges and receiver +% coordinates. +% settings - Receiver settings. The true receiver coordinates +% are contained in this structure. +% plot_skyplot - If ==1 then use satellite coordinates to plot the +% the satellite positions + +% Darius Plausinaitis +% Modified by Javier Arribas, 2011. jarribas(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function plotNavigation(navSolutions, settings,plot_skyplot) + + +%% Plot results in the necessary data exists ============================== +if (~isempty(navSolutions)) + + %% If reference position is not provided, then set reference position + %% to the average position + if isnan(settings.truePosition.E) || isnan(settings.truePosition.N) ... + || isnan(settings.truePosition.U) + + %=== Compute mean values ========================================== + % Remove NaN-s or the output of the function MEAN will be NaN. + refCoord.E = mean(navSolutions.E(~isnan(navSolutions.E))); + refCoord.N = mean(navSolutions.N(~isnan(navSolutions.N))); + refCoord.U = mean(navSolutions.U(~isnan(navSolutions.U))); + + %Also convert geodetic coordinates to deg:min:sec vector format + meanLongitude = dms2mat(deg2dms(... + mean(navSolutions.longitude(~isnan(navSolutions.longitude)))), -5); + meanLatitude = dms2mat(deg2dms(... + mean(navSolutions.latitude(~isnan(navSolutions.latitude)))), -5); + + LatLong_str=[num2str(meanLatitude(1)), '??', ... + num2str(meanLatitude(2)), '''', ... + num2str(meanLatitude(3)), '''''', ... + ',', ... + num2str(meanLongitude(1)), '??', ... + num2str(meanLongitude(2)), '''', ... + num2str(meanLongitude(3)), ''''''] + + + + refPointLgText = ['Mean Position\newline Lat: ', ... + num2str(meanLatitude(1)), '{\circ}', ... + num2str(meanLatitude(2)), '{\prime}', ... + num2str(meanLatitude(3)), '{\prime}{\prime}', ... + '\newline Lng: ', ... + num2str(meanLongitude(1)), '{\circ}', ... + num2str(meanLongitude(2)), '{\prime}', ... + num2str(meanLongitude(3)), '{\prime}{\prime}', ... + '\newline Hgt: ', ... + num2str(mean(navSolutions.height(~isnan(navSolutions.height))), '%+6.1f')]; + + else + % compute the mean error for static receiver + mean_position.E = mean(navSolutions.E(~isnan(navSolutions.E))); + mean_position.N = mean(navSolutions.N(~isnan(navSolutions.N))); + mean_position.U = mean(navSolutions.U(~isnan(navSolutions.U))); + refCoord.E = settings.truePosition.E; + refCoord.N = settings.truePosition.N; + refCoord.U = settings.truePosition.U; + + error_meters=sqrt((mean_position.E-refCoord.E)^2+(mean_position.N-refCoord.N)^2+(mean_position.U-refCoord.U)^2); + + refPointLgText = ['Reference Position, Mean 3D error = ' num2str(error_meters) ' [m]']; + end + + figureNumber = 300; + % The 300 is chosen for more convenient handling of the open + % figure windows, when many figures are closed and reopened. Figures + % drawn or opened by the user, will not be "overwritten" by this + % function if the auto numbering is not used. + + %=== Select (or create) and clear the figure ========================== + figure(figureNumber); + clf (figureNumber); + set (figureNumber, 'Name', 'Navigation solutions'); + + %--- Draw axes -------------------------------------------------------- + handles(1, 1) = subplot(4, 2, 1 : 4); + handles(3, 1) = subplot(4, 2, [5, 7]); + handles(3, 2) = subplot(4, 2, [6, 8]); + + %% Plot all figures ======================================================= + + %--- Coordinate differences in UTM system ----------------------------- + plot(handles(1, 1), [(navSolutions.E - refCoord.E)', ... + (navSolutions.N - refCoord.N)',... + (navSolutions.U - refCoord.U)']); + + title (handles(1, 1), 'Coordinates variations in UTM system'); + legend(handles(1, 1), 'E', 'N', 'U'); + xlabel(handles(1, 1), ['Measurement period: ', ... + num2str(settings.navSolPeriod), 'ms']); + ylabel(handles(1, 1), 'Variations (m)'); + grid (handles(1, 1)); + axis (handles(1, 1), 'tight'); + + %--- Position plot in UTM system -------------------------------------- + plot3 (handles(3, 1), navSolutions.E - refCoord.E, ... + navSolutions.N - refCoord.N, ... + navSolutions.U - refCoord.U, '+'); + hold (handles(3, 1), 'on'); + + %Plot the reference point + plot3 (handles(3, 1), 0, 0, 0, 'r+', 'LineWidth', 1.5, 'MarkerSize', 10); + hold (handles(3, 1), 'off'); + + view (handles(3, 1), 0, 90); + axis (handles(3, 1), 'equal'); + grid (handles(3, 1), 'minor'); + + legend(handles(3, 1), 'Measurements', refPointLgText); + + title (handles(3, 1), 'Positions in UTM system (3D plot)'); + xlabel(handles(3, 1), 'East (m)'); + ylabel(handles(3, 1), 'North (m)'); + zlabel(handles(3, 1), 'Upping (m)'); + + if (plot_skyplot==1) + %--- Satellite sky plot ----------------------------------------------- + skyPlot(handles(3, 2), ... + navSolutions.channel.az, ... + navSolutions.channel.el, ... + navSolutions.channel.PRN(:, 1)); + + title (handles(3, 2), ['Sky plot (mean PDOP: ', ... + num2str(mean(navSolutions.DOP(2,:))), ')']); + end + +else + disp('plotNavigation: No navigation data to plot.'); +end % if (~isempty(navSolutions)) diff --git a/src/utils/matlab/libs/plotTracking.m b/src/utils/matlab/libs/plotTracking.m index 28764f3e9..b280d82aa 100644 --- a/src/utils/matlab/libs/plotTracking.m +++ b/src/utils/matlab/libs/plotTracking.m @@ -1,153 +1,187 @@ -function plotTracking(channelList, trackResults, settings) -%This function plots the tracking results for the given channel list. -% -%plotTracking(channelList, trackResults, settings) -% -% Inputs: -% channelList - list of channels to be plotted. -% trackResults - tracking results from the tracking function. -% settings - receiver settings. - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -% -% Copyright (C) Darius Plausinaitis -% Written by Darius Plausinaitis -%-------------------------------------------------------------------------- -%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, write to the Free Software -%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -%USA. -%-------------------------------------------------------------------------- - -%CVS record: -%$Id: plotTracking.m,v 1.5.2.23 2006/08/14 14:45:14 dpl Exp $ - -% Protection - if the list contains incorrect channel numbers -channelList = intersect(channelList, 1:settings.numberOfChannels); - -%=== For all listed channels ============================================== -for channelNr = channelList - -%% Select (or create) and clear the figure ================================ - % The number 200 is added just for more convenient handling of the open - % figure windows, when many figures are closed and reopened. - % Figures drawn or opened by the user, will not be "overwritten" by - % this function. - - figure(channelNr +200); - clf(channelNr +200); - set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... - ' (PRN ', ... - num2str(trackResults(channelNr).PRN), ... - ') results']); - -%% Draw axes ============================================================== - % Row 1 - handles(1, 1) = subplot(3, 3, 1); - handles(1, 2) = subplot(3, 3, [2 3]); - % Row 2 - handles(2, 1) = subplot(3, 3, 4); - handles(2, 2) = subplot(3, 3, [5 6]); - % Row 3 - handles(3, 1) = subplot(3, 3, 7); - handles(3, 2) = subplot(3, 3, 8); - handles(3, 3) = subplot(3, 3, 9); - -%% Plot all figures ======================================================= - - timeAxisInSeconds = (1:settings.msToProcess)/1000; - - %----- Discrete-Time Scatter Plot --------------------------------- - plot(handles(1, 1), trackResults(channelNr).I_P,... - trackResults(channelNr).Q_P, ... - '.'); - - grid (handles(1, 1)); - axis (handles(1, 1), 'equal'); - title (handles(1, 1), 'Discrete-Time Scatter Plot'); - xlabel(handles(1, 1), 'I prompt'); - ylabel(handles(1, 1), 'Q prompt'); - - %----- Nav bits --------------------------------------------------- - plot (handles(1, 2), timeAxisInSeconds, ... - trackResults(channelNr).I_P); - - grid (handles(1, 2)); - title (handles(1, 2), 'Bits of the navigation message'); - xlabel(handles(1, 2), 'Time (s)'); - axis (handles(1, 2), 'tight'); - - %----- PLL discriminator unfiltered-------------------------------- - plot (handles(2, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscr, 'r'); - - grid (handles(2, 1)); - axis (handles(2, 1), 'tight'); - xlabel(handles(2, 1), 'Time (s)'); - ylabel(handles(2, 1), 'Amplitude'); - title (handles(2, 1), 'Raw PLL discriminator'); - - %----- Correlation ------------------------------------------------ - plot(handles(2, 2), timeAxisInSeconds, ... - [sqrt(trackResults(channelNr).I_E.^2 + ... - trackResults(channelNr).Q_E.^2)', ... - sqrt(trackResults(channelNr).I_P.^2 + ... - trackResults(channelNr).Q_P.^2)', ... - sqrt(trackResults(channelNr).I_L.^2 + ... - trackResults(channelNr).Q_L.^2)'], ... - '-*'); - - grid (handles(2, 2)); - title (handles(2, 2), 'Correlation results'); - xlabel(handles(2, 2), 'Time (s)'); - axis (handles(2, 2), 'tight'); - - hLegend = legend(handles(2, 2), '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... - '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... - '$\sqrt{I_{L}^2 + Q_{L}^2}$'); - - %set interpreter from tex to latex. This will draw \sqrt correctly - set(hLegend, 'Interpreter', 'Latex'); - - %----- PLL discriminator filtered---------------------------------- - plot (handles(3, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscrFilt, 'b'); - - grid (handles(3, 1)); - axis (handles(3, 1), 'tight'); - xlabel(handles(3, 1), 'Time (s)'); - ylabel(handles(3, 1), 'Amplitude'); - title (handles(3, 1), 'Filtered PLL discriminator'); - - %----- DLL discriminator unfiltered-------------------------------- - plot (handles(3, 2), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscr, 'r'); - - grid (handles(3, 2)); - axis (handles(3, 2), 'tight'); - xlabel(handles(3, 2), 'Time (s)'); - ylabel(handles(3, 2), 'Amplitude'); - title (handles(3, 2), 'Raw DLL discriminator'); - - %----- DLL discriminator filtered---------------------------------- - plot (handles(3, 3), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscrFilt, 'b'); - - grid (handles(3, 3)); - axis (handles(3, 3), 'tight'); - xlabel(handles(3, 3), 'Time (s)'); - ylabel(handles(3, 3), 'Amplitude'); - title (handles(3, 3), 'Filtered DLL discriminator'); - -end % for channelNr = channelList +function plotTracking(channelList, trackResults, settings) +% This function plots the tracking results for the given channel list. +% +% plotTracking(channelList, trackResults, settings) +% +% Inputs: +% channelList - list of channels to be plotted. +% trackResults - tracking results from the tracking function. +% settings - receiver settings. + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +% +% Copyright (C) Darius Plausinaitis +% Written by Darius Plausinaitis +%-------------------------------------------------------------------------- +%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, write to the Free Software +%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +%USA. +%-------------------------------------------------------------------------- + + +% Protection - if the list contains incorrect channel numbers +channelList = intersect(channelList, 1:settings.numberOfChannels); + +%=== For all listed channels ============================================== +for channelNr = channelList + + %% Select (or create) and clear the figure ================================ + % The number 200 is added just for more convenient handling of the open + % figure windows, when many figures are closed and reopened. + % Figures drawn or opened by the user, will not be "overwritten" by + % this function. + + figure(channelNr +200); + clf(channelNr +200); + set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... + ' (PRN ', ... + num2str(trackResults(channelNr).PRN(end-1)), ... + ') results']); + + %% Draw axes ============================================================== + % Row 1 + handles(1, 1) = subplot(4, 3, 1); + handles(1, 2) = subplot(4, 3, [2 3]); + % Row 2 + handles(2, 1) = subplot(4, 3, 4); + handles(2, 2) = subplot(4, 3, [5 6]); + % Row 3 + handles(3, 1) = subplot(4, 3, 7); + handles(3, 2) = subplot(4, 3, 8); + handles(3, 3) = subplot(4, 3, 9); + % Row 4 + handles(4, 1) = subplot(4, 3, 10); + handles(4, 2) = subplot(4, 3, 11); + handles(4, 3) = subplot(4, 3, 12); + + + %% Plot all figures ======================================================= + + timeAxisInSeconds = (1:settings.msToProcess)/1000; + + %----- Discrete-Time Scatter Plot --------------------------------- + plot(handles(1, 1), trackResults(channelNr).I_P,... + trackResults(channelNr).Q_P, ... + '.'); + + grid (handles(1, 1)); + axis (handles(1, 1), 'equal'); + title (handles(1, 1), 'Discrete-Time Scatter Plot'); + xlabel(handles(1, 1), 'I prompt'); + ylabel(handles(1, 1), 'Q prompt'); + + %----- Nav bits --------------------------------------------------- + plot (handles(1, 2), timeAxisInSeconds, ... + trackResults(channelNr).I_P); + + grid (handles(1, 2)); + title (handles(1, 2), 'Bits of the navigation message'); + xlabel(handles(1, 2), 'Time (s)'); + axis (handles(1, 2), 'tight'); + + %----- PLL discriminator unfiltered-------------------------------- + plot (handles(2, 1), timeAxisInSeconds, ... + trackResults(channelNr).pllDiscr, 'r'); + + grid (handles(2, 1)); + axis (handles(2, 1), 'tight'); + xlabel(handles(2, 1), 'Time (s)'); + ylabel(handles(2, 1), 'Amplitude'); + title (handles(2, 1), 'Raw PLL discriminator'); + + %----- Correlation ------------------------------------------------ + plot(handles(2, 2), timeAxisInSeconds, ... + [sqrt(trackResults(channelNr).I_E.^2 + ... + trackResults(channelNr).Q_E.^2)', ... + sqrt(trackResults(channelNr).I_P.^2 + ... + trackResults(channelNr).Q_P.^2)', ... + sqrt(trackResults(channelNr).I_L.^2 + ... + trackResults(channelNr).Q_L.^2)'], ... + '-*'); + + grid (handles(2, 2)); + title (handles(2, 2), 'Correlation results'); + xlabel(handles(2, 2), 'Time (s)'); + axis (handles(2, 2), 'tight'); + + hLegend = legend(handles(2, 2), '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... + '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... + '$\sqrt{I_{L}^2 + Q_{L}^2}$'); + + %set interpreter from tex to latex. This will draw \sqrt correctly + set(hLegend, 'Interpreter', 'Latex'); + + %----- PLL discriminator filtered---------------------------------- + plot (handles(3, 1), timeAxisInSeconds, ... + trackResults(channelNr).pllDiscrFilt(1:settings.msToProcess), 'b'); + + grid (handles(3, 1)); + axis (handles(3, 1), 'tight'); + xlabel(handles(3, 1), 'Time (s)'); + ylabel(handles(3, 1), 'Amplitude'); + title (handles(3, 1), 'Filtered PLL discriminator'); + + %----- DLL discriminator unfiltered-------------------------------- + plot (handles(3, 2), timeAxisInSeconds, ... + trackResults(channelNr).dllDiscr, 'r'); + + grid (handles(3, 2)); + axis (handles(3, 2), 'tight'); + xlabel(handles(3, 2), 'Time (s)'); + ylabel(handles(3, 2), 'Amplitude'); + title (handles(3, 2), 'Raw DLL discriminator'); + + %----- DLL discriminator filtered---------------------------------- + plot (handles(3, 3), timeAxisInSeconds, ... + trackResults(channelNr).dllDiscrFilt, 'b'); + + grid (handles(3, 3)); + axis (handles(3, 3), 'tight'); + xlabel(handles(3, 3), 'Time (s)'); + ylabel(handles(3, 3), 'Amplitude'); + title (handles(3, 3), 'Filtered DLL discriminator'); + + %----- CNo for signal---------------------------------- + plot (handles(4, 1), timeAxisInSeconds, ... + trackResults(channelNr).CNo(1:settings.msToProcess), 'b'); + + grid (handles(4, 1)); + axis (handles(4, 1), 'tight'); + xlabel(handles(4, 1), 'Time (s)'); + ylabel(handles(4, 1), 'CNo (dB-Hz)'); + title (handles(4, 1), 'Carrier to Noise Ratio'); + + %----- Carrier Frequency -------------------------------- + plot (handles(4, 2), timeAxisInSeconds(2:end), ... + trackResults(channelNr).carrFreq(2:settings.msToProcess), 'Color',[0.42 0.25 0.39]); + + grid (handles(4, 2)); + axis (handles(4, 2)); + xlabel(handles(4, 2), 'Time (s)'); + ylabel(handles(4, 2), 'Freq (hz)'); + title (handles(4, 2), 'Carrier Freq'); + + %----- Code Frequency---------------------------------- + %--- Skip sample 0 to help with results display + plot (handles(4, 3), timeAxisInSeconds(2:end), ... + trackResults(channelNr).codeFreq(2:settings.msToProcess), 'Color',[0.2 0.3 0.49]); + + grid (handles(4, 3)); + axis (handles(4, 3), 'tight'); + xlabel(handles(4, 3), 'Time (s)'); + ylabel(handles(4, 3), 'Freq (Hz)'); + title (handles(4, 3), 'Code Freq'); + +end % for channelNr = channelList diff --git a/src/utils/matlab/libs/plotVEMLTracking.m b/src/utils/matlab/libs/plotVEMLTracking.m index da219e102..bc4e4e806 100644 --- a/src/utils/matlab/libs/plotVEMLTracking.m +++ b/src/utils/matlab/libs/plotVEMLTracking.m @@ -1,159 +1,162 @@ -function plotVEMLTracking(channelList, trackResults, settings) -%This function plots the tracking results for the given channel list. -% -%plotTracking(channelList, trackResults, settings) -% -% Inputs: -% channelList - list of channels to be plotted. -% trackResults - tracking results from the tracking function. -% settings - receiver settings. - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -% -% Copyright (C) Darius Plausinaitis -% Written by Darius Plausinaitis -%-------------------------------------------------------------------------- -%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, write to the Free Software -%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -%USA. -%-------------------------------------------------------------------------- - -%CVS record: -%$Id: plotTracking.m,v 1.5.2.23 2006/08/14 14:45:14 dpl Exp $ - -% Protection - if the list contains incorrect channel numbers -channelList = intersect(channelList, 1:settings.numberOfChannels); - -%=== For all listed channels ============================================== -for channelNr = channelList - -%% Select (or create) and clear the figure ================================ - % The number 200 is added just for more convenient handling of the open - % figure windows, when many figures are closed and reopened. - % Figures drawn or opened by the user, will not be "overwritten" by - % this function. - - figure(channelNr +200); - clf(channelNr +200); - set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... - ' (PRN ', ... - num2str(trackResults(channelNr).PRN), ... - ') results']); - -%% Draw axes ============================================================== - % Row 1 - handles(1, 1) = subplot(3, 3, 1); - handles(1, 2) = subplot(3, 3, [2 3]); - % Row 2 - handles(2, 1) = subplot(3, 3, 4); - handles(2, 2) = subplot(3, 3, [5 6]); - % Row 3 - handles(3, 1) = subplot(3, 3, 7); - handles(3, 2) = subplot(3, 3, 8); - handles(3, 3) = subplot(3, 3, 9); - -%% Plot all figures ======================================================= - - timeAxisInSeconds = (1:4:settings.msToProcess)/1000; - - %----- Discrete-Time Scatter Plot --------------------------------- - plot(handles(1, 1), trackResults(channelNr).I_P,... - trackResults(channelNr).Q_P, ... - '.'); - - grid (handles(1, 1)); - axis (handles(1, 1), 'equal'); - title (handles(1, 1), 'Discrete-Time Scatter Plot'); - xlabel(handles(1, 1), 'I prompt'); - ylabel(handles(1, 1), 'Q prompt'); - - %----- Nav bits --------------------------------------------------- - plot (handles(1, 2), timeAxisInSeconds, ... - trackResults(channelNr).I_P); - - grid (handles(1, 2)); - title (handles(1, 2), 'Bits of the navigation message'); - xlabel(handles(1, 2), 'Time (s)'); - axis (handles(1, 2), 'tight'); - - %----- PLL discriminator unfiltered-------------------------------- - plot (handles(2, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscr, 'r'); - - grid (handles(2, 1)); - axis (handles(2, 1), 'tight'); - xlabel(handles(2, 1), 'Time (s)'); - ylabel(handles(2, 1), 'Amplitude'); - title (handles(2, 1), 'Raw PLL discriminator'); - - %----- Correlation ------------------------------------------------ - plot(handles(2, 2), timeAxisInSeconds, ... - [sqrt(trackResults(channelNr).I_VE.^2 + ... - trackResults(channelNr).Q_VE.^2)', ... - sqrt(trackResults(channelNr).I_E.^2 + ... - trackResults(channelNr).Q_E.^2)', ... - sqrt(trackResults(channelNr).I_P.^2 + ... - trackResults(channelNr).Q_P.^2)', ... - sqrt(trackResults(channelNr).I_L.^2 + ... - trackResults(channelNr).Q_L.^2)', ... - sqrt(trackResults(channelNr).I_VL.^2 + ... - trackResults(channelNr).Q_VL.^2)'], ... - '-*'); - - grid (handles(2, 2)); - title (handles(2, 2), 'Correlation results'); - xlabel(handles(2, 2), 'Time (s)'); - axis (handles(2, 2), 'tight'); - - hLegend = legend(handles(2, 2), '$\sqrt{I_{VE}^2 + Q_{VE}^2}$', ... - '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... - '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... - '$\sqrt{I_{L}^2 + Q_{L}^2}$', ... - '$\sqrt{I_{VL}^2 + Q_{VL}^2}$'); - - %set interpreter from tex to latex. This will draw \sqrt correctly - set(hLegend, 'Interpreter', 'Latex'); - - %----- PLL discriminator filtered---------------------------------- - plot (handles(3, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscrFilt, 'b'); - - grid (handles(3, 1)); - axis (handles(3, 1), 'tight'); - xlabel(handles(3, 1), 'Time (s)'); - ylabel(handles(3, 1), 'Amplitude'); - title (handles(3, 1), 'Filtered PLL discriminator'); - - %----- DLL discriminator unfiltered-------------------------------- - plot (handles(3, 2), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscr, 'r'); - - grid (handles(3, 2)); - axis (handles(3, 2), 'tight'); - xlabel(handles(3, 2), 'Time (s)'); - ylabel(handles(3, 2), 'Amplitude'); - title (handles(3, 2), 'Raw DLL discriminator'); - - %----- DLL discriminator filtered---------------------------------- - plot (handles(3, 3), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscrFilt, 'b'); - - grid (handles(3, 3)); - axis (handles(3, 3), 'tight'); - xlabel(handles(3, 3), 'Time (s)'); - ylabel(handles(3, 3), 'Amplitude'); - title (handles(3, 3), 'Filtered DLL discriminator'); - -end % for channelNr = channelList +function plotVEMLTracking(channelList, trackResults, settings) +% This function plots the tracking results for the given channel list. +% +% plotTracking(channelList, trackResults, settings) +% +% Inputs: +% channelList - list of channels to be plotted. +% trackResults - tracking results from the tracking function. +% settings - receiver settings. + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +% +% Copyright (C) Darius Plausinaitis +% Written by Darius Plausinaitis +%-------------------------------------------------------------------------- +%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, write to the Free Software +%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +%USA. +%-------------------------------------------------------------------------- + +% Protection - if the list contains incorrect channel numbers +channelList = intersect(channelList, 1:settings.numberOfChannels); + +%=== For all listed channels ============================================== +for channelNr = channelList + + %% Select (or create) and clear the figure ================================ + % The number 200 is added just for more convenient handling of the open + % figure windows, when many figures are closed and reopened. + % Figures drawn or opened by the user, will not be "overwritten" by + % this function. + + figure(channelNr +200); + clf(channelNr +200); + set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... + ' (PRN ', ... + num2str(trackResults(channelNr).PRN(end-1)), ... + ') results']); + + %% Draw axes ============================================================== + % Row 1 + handles(1, 1) = subplot(3, 3, 1); + handles(1, 2) = subplot(3, 3, [2 3]); + % Row 2 + handles(2, 1) = subplot(3, 3, 4); + handles(2, 2) = subplot(3, 3, [5 6]); + % Row 3 + handles(3, 1) = subplot(3, 3, 7); + handles(3, 2) = subplot(3, 3, 8); + handles(3, 3) = subplot(3, 3, 9); + + %% Plot all figures ======================================================= + + timeAxisInSeconds = (1:4:settings.msToProcess)/1000; + + %----- Discrete-Time Scatter Plot --------------------------------- + plot(handles(1, 1), trackResults(channelNr).data_I,... + trackResults(channelNr).data_Q, ... + '.'); + + grid (handles(1, 1)); + axis (handles(1, 1), 'equal'); + title (handles(1, 1), 'Discrete-Time Scatter Plot'); + xlabel(handles(1, 1), 'I prompt'); + ylabel(handles(1, 1), 'Q prompt'); + + %----- Nav bits --------------------------------------------------- + t = (1:length(trackResults(channelNr).data_I)); + plot (handles(1, 2), t, ... + trackResults(channelNr).data_I); + + grid (handles(1, 2)); + title (handles(1, 2), 'Bits of the navigation message'); + xlabel(handles(1, 2), 'Time (s)'); + axis (handles(1, 2), 'tight'); + + %----- PLL discriminator unfiltered-------------------------------- + t = (1:length(trackResults(channelNr).pllDiscr)); + plot (handles(2, 1), t, ... + trackResults(channelNr).pllDiscr, 'r'); + + grid (handles(2, 1)); + axis (handles(2, 1), 'tight'); + xlabel(handles(2, 1), 'Time (s)'); + ylabel(handles(2, 1), 'Amplitude'); + title (handles(2, 1), 'Raw PLL discriminator'); + + %----- Correlation ------------------------------------------------ + t = (1:length(trackResults(channelNr).I_VE)); + plot(handles(2, 2), t, ... + [sqrt(trackResults(channelNr).I_VE.^2 + ... + trackResults(channelNr).Q_VE.^2)', ... + sqrt(trackResults(channelNr).I_E.^2 + ... + trackResults(channelNr).Q_E.^2)', ... + sqrt(trackResults(channelNr).I_P.^2 + ... + trackResults(channelNr).Q_P.^2)', ... + sqrt(trackResults(channelNr).I_L.^2 + ... + trackResults(channelNr).Q_L.^2)', ... + sqrt(trackResults(channelNr).I_VL.^2 + ... + trackResults(channelNr).Q_VL.^2)'], ... + '-*'); + + grid (handles(2, 2)); + title (handles(2, 2), 'Correlation results'); + xlabel(handles(2, 2), 'Time (s)'); + axis (handles(2, 2), 'tight'); + + hLegend = legend(handles(2, 2), '$\sqrt{I_{VE}^2 + Q_{VE}^2}$', ... + '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... + '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... + '$\sqrt{I_{L}^2 + Q_{L}^2}$', ... + '$\sqrt{I_{VL}^2 + Q_{VL}^2}$'); + + %set interpreter from tex to latex. This will draw \sqrt correctly + set(hLegend, 'Interpreter', 'Latex'); + + %----- PLL discriminator filtered---------------------------------- + t = (1:length(trackResults(channelNr).pllDiscrFilt)); + plot (handles(3, 1), t, ... + trackResults(channelNr).pllDiscrFilt, 'b'); + + grid (handles(3, 1)); + axis (handles(3, 1), 'tight'); + xlabel(handles(3, 1), 'Time (s)'); + ylabel(handles(3, 1), 'Amplitude'); + title (handles(3, 1), 'Filtered PLL discriminator'); + + %----- DLL discriminator unfiltered-------------------------------- + t = (1:length(trackResults(channelNr).dllDiscr)); + plot (handles(3, 2), t, ... + trackResults(channelNr).dllDiscr, 'r'); + + grid (handles(3, 2)); + axis (handles(3, 2), 'tight'); + xlabel(handles(3, 2), 'Time (s)'); + ylabel(handles(3, 2), 'Amplitude'); + title (handles(3, 2), 'Raw DLL discriminator'); + + %----- DLL discriminator filtered---------------------------------- + t = (1:length(trackResults(channelNr).dllDiscrFilt)); + plot (handles(3, 3), t, ... + trackResults(channelNr).dllDiscrFilt, 'b'); + + grid (handles(3, 3)); + axis (handles(3, 3), 'tight'); + xlabel(handles(3, 3), 'Time (s)'); + ylabel(handles(3, 3), 'Amplitude'); + title (handles(3, 3), 'Filtered DLL discriminator'); + +end % for channelNr = channelList diff --git a/src/utils/matlab/libs/read_complex_binary.m b/src/utils/matlab/libs/read_complex_binary.m new file mode 100644 index 000000000..64f51f964 --- /dev/null +++ b/src/utils/matlab/libs/read_complex_binary.m @@ -0,0 +1,61 @@ +% Usage: read_complex_binary (filename, [count], [start_sample]) +% +% Opens filename and returns the contents as a column vector, +% treating them as 32 bit complex numbers +% + +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function v = read_complex_binary (filename, count, start_sample) + +m = nargchk (1,2,nargin); +if (m) + %usage (m); +end + +if (nargin < 2) + count = Inf; + start_sample=0; +end + +if (nargin < 3) + start_sample=0; +end + +f = fopen (filename, 'rb'); +if (f < 0) + v = 0; +else + if (start_sample>0) + bytes_per_sample=4; + fseek(f,start_sample*bytes_per_sample,'bof'); + end + t = fread (f, [2, count], 'float'); + fclose (f); + v = t(1,:) + t(2,:)*i; + [r, c] = size (v); + v = reshape (v, c, r); +end diff --git a/src/utils/matlab/libs/read_complex_char_binary.m b/src/utils/matlab/libs/read_complex_char_binary.m new file mode 100644 index 000000000..be990681a --- /dev/null +++ b/src/utils/matlab/libs/read_complex_char_binary.m @@ -0,0 +1,52 @@ +% Usage: read_complex_binary (filename, [count]) +% +% Opens filename and returns the contents as a column vector, +% treating them as 32 bit complex numbers +% + +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function v = read_complex_char_binary (filename, count) + +m = nargchk (1,2,nargin); +if (m) + usage (m); +end + +if (nargin < 2) + count = Inf; +end + +f = fopen (filename, 'rb'); +if (f < 0) + v = 0; +else + t = fread (f, [2, count], 'int8'); + fclose (f); + v = t(1,:) + t(2,:)*i; + [r, c] = size (v); + v = reshape (v, c, r); +end diff --git a/src/utils/matlab/libs/read_complex_short_binary.m b/src/utils/matlab/libs/read_complex_short_binary.m new file mode 100644 index 000000000..74edcd616 --- /dev/null +++ b/src/utils/matlab/libs/read_complex_short_binary.m @@ -0,0 +1,52 @@ +% Usage: read_complex_binary (filename, [count]) +% +% Opens filename and returns the contents as a column vector, +% treating them as 32 bit complex numbers +% + +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function v = read_complex_short_binary (filename, count) + +m = nargchk (1,2,nargin); +if (m) + usage (m); +end + +if (nargin < 2) + count = Inf; +end + +f = fopen (filename, 'rb'); +if (f < 0) + v = 0; +else + t = fread (f, [2, count], 'short'); + fclose (f); + v = t(1,:) + t(2,:)*i; + [r, c] = size (v); + v = reshape (v, c, r); +end diff --git a/src/utils/matlab/libs/read_hybrid_observables_dump.m b/src/utils/matlab/libs/read_hybrid_observables_dump.m new file mode 100644 index 000000000..f8dccdd41 --- /dev/null +++ b/src/utils/matlab/libs/read_hybrid_observables_dump.m @@ -0,0 +1,96 @@ +% Usage: read_tracking_dat (filename, [count]) +% +% Opens GNSS-SDR tracking binary log file .dat and returns the contents +% + +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% +% Javier Arribas 2011 + +function [observables] = read_hybrid_observables_dump (channels, filename, count) + +m = nargchk (1,2,nargin); +num_double_vars=7; +double_size_bytes=8; +skip_bytes_each_read=double_size_bytes*num_double_vars*channels; +bytes_shift=0; +if (m) + usage (m); +end + +if (nargin < 3) + count = Inf; +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + for N=1:1:channels + observables.RX_time(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.d_TOW_at_current_symbol(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Carrier_Doppler_hz(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Carrier_phase_hz(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Pseudorange_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.PRN(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.valid(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + end + + fclose (f); + + %%%%%%%% output vars %%%%%%%% + % double tmp_double; + % for (unsigned int i = 0; i < d_nchannels; i++) + % { + % tmp_double = current_gnss_synchro[i].RX_time; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].TOW_at_current_symbol_ms; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].Carrier_Doppler_hz; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].Carrier_phase_rads/GPS_TWO_PI; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].Pseudorange_m; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].PRN; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % tmp_double = current_gnss_synchro[i].Flag_valid_pseudorange; + % d_dump_file.write((char*)&tmp_double, sizeof(double)); + % } +end + diff --git a/src/utils/matlab/libs/read_true_sim_observables_dump.m b/src/utils/matlab/libs/read_true_sim_observables_dump.m new file mode 100644 index 000000000..7f4995294 --- /dev/null +++ b/src/utils/matlab/libs/read_true_sim_observables_dump.m @@ -0,0 +1,90 @@ +% Usage: read_true_sim_observables_dump (filename, [count]) +% +% Opens gnss-sdr-sim observables dump and reads all chennels +% + +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% +% Javier Arribas 2011 + +function [observables] = read_true_sim_observables_dump (filename, count) + +m = nargchk (1,2,nargin); +channels=12; %Simulator always use 12 channels +num_double_vars=7; +double_size_bytes=8; +skip_bytes_each_read=double_size_bytes*num_double_vars*channels; +bytes_shift=0; + +if (m) + usage (m); +end + +if (nargin < 2) + count = Inf; +end +%loops_counter = fread (f, count, 'uint32',4*12); +f = fopen (filename, 'rb'); +if (f < 0) +else + for N=1:1:channels + observables.RX_time(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Carrier_Doppler_hz(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Carrier_phase_hz(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Pseudorange_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.True_range_m(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.Carrier_phase_hz_v2(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + observables.PRN(N,:) = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved + end + + fclose (f); + + % %%%%%%%% output vars %%%%%%%% + % for(int i=0;i<12;i++) + % { + % d_dump_file.read((char *) &gps_time_sec[i], sizeof(double)); + % d_dump_file.read((char *) &doppler_l1_hz, sizeof(double)); + % d_dump_file.read((char *) &acc_carrier_phase_l1_cycles[i], sizeof(double)); + % d_dump_file.read((char *) &dist_m[i], sizeof(double)); + % d_dump_file.read((char *) &true_dist_m[i], sizeof(double)); + % d_dump_file.read((char *) &carrier_phase_l1_cycles[i], sizeof(double)); + % d_dump_file.read((char *) &prn[i], sizeof(double)); + % } +end + diff --git a/src/utils/matlab/plotTrackingE5a.m b/src/utils/matlab/plotTrackingE5a.m index f8a76b7d2..e63d23162 100644 --- a/src/utils/matlab/plotTrackingE5a.m +++ b/src/utils/matlab/plotTrackingE5a.m @@ -1,153 +1,150 @@ -function plotTracking(channelList, trackResults, settings) -%This function plots the tracking results for the given channel list. -% -%plotTracking(channelList, trackResults, settings) -% -% Inputs: -% channelList - list of channels to be plotted. -% trackResults - tracking results from the tracking function. -% settings - receiver settings. - -%-------------------------------------------------------------------------- -% SoftGNSS v3.0 -% -% Copyright (C) Darius Plausinaitis -% Written by Darius Plausinaitis -%-------------------------------------------------------------------------- -%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, write to the Free Software -%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -%USA. -%-------------------------------------------------------------------------- - -%CVS record: -%$Id: plotTracking.m,v 1.5.2.23 2006/08/14 14:45:14 dpl Exp $ - -% Protection - if the list contains incorrect channel numbers -channelList = intersect(channelList, 1:settings.numberOfChannels); - -%=== For all listed channels ============================================== -for channelNr = channelList - -%% Select (or create) and clear the figure ================================ - % The number 200 is added just for more convenient handling of the open - % figure windows, when many figures are closed and reopened. - % Figures drawn or opened by the user, will not be "overwritten" by - % this function. - - figure(channelNr +200); - clf(channelNr +200); - set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... - ' (PRN ', ... - num2str(trackResults(channelNr).PRN), ... - ') results']); - -%% Draw axes ============================================================== - % Row 1 - handles(1, 1) = subplot(3, 3, 1); - handles(1, 2) = subplot(3, 3, [2 3]); - % Row 2 - handles(2, 1) = subplot(3, 3, 4); - handles(2, 2) = subplot(3, 3, [5 6]); - % Row 3 - handles(3, 1) = subplot(3, 3, 7); - handles(3, 2) = subplot(3, 3, 8); - handles(3, 3) = subplot(3, 3, 9); - -%% Plot all figures ======================================================= - - timeAxisInSeconds = (1:settings.msToProcess)/1000; - - %----- Discrete-Time Scatter Plot --------------------------------- - plot(handles(1, 1), trackResults(channelNr).I_PN,... - trackResults(channelNr).Q_PN, ... - '.'); - - grid (handles(1, 1)); - axis (handles(1, 1), 'equal'); - title (handles(1, 1), 'Discrete-Time Scatter Plot'); - xlabel(handles(1, 1), 'I prompt'); - ylabel(handles(1, 1), 'Q prompt'); - - %----- Nav bits --------------------------------------------------- - plot (handles(1, 2), timeAxisInSeconds, ... - trackResults(channelNr).I_PN); - - grid (handles(1, 2)); - title (handles(1, 2), 'Bits of the navigation message'); - xlabel(handles(1, 2), 'Time (s)'); - axis (handles(1, 2), 'tight'); - - %----- PLL discriminator unfiltered-------------------------------- - plot (handles(2, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscr, 'r'); - - grid (handles(2, 1)); - axis (handles(2, 1), 'tight'); - xlabel(handles(2, 1), 'Time (s)'); - ylabel(handles(2, 1), 'Amplitude'); - title (handles(2, 1), 'Raw PLL discriminator'); - - %----- Correlation ------------------------------------------------ - plot(handles(2, 2), timeAxisInSeconds, ... - [sqrt(trackResults(channelNr).I_E.^2 + ... - trackResults(channelNr).Q_E.^2)', ... - sqrt(trackResults(channelNr).I_P.^2 + ... - trackResults(channelNr).Q_P.^2)', ... - sqrt(trackResults(channelNr).I_L.^2 + ... - trackResults(channelNr).Q_L.^2)'], ... - '-*'); - - grid (handles(2, 2)); - title (handles(2, 2), 'Correlation results'); - xlabel(handles(2, 2), 'Time (s)'); - axis (handles(2, 2), 'tight'); - - hLegend = legend(handles(2, 2), '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... - '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... - '$\sqrt{I_{L}^2 + Q_{L}^2}$'); - - %set interpreter from tex to latex. This will draw \sqrt correctly - set(hLegend, 'Interpreter', 'Latex'); - - %----- PLL discriminator filtered---------------------------------- - plot (handles(3, 1), timeAxisInSeconds, ... - trackResults(channelNr).pllDiscrFilt, 'b'); - - grid (handles(3, 1)); - axis (handles(3, 1), 'tight'); - xlabel(handles(3, 1), 'Time (s)'); - ylabel(handles(3, 1), 'Amplitude'); - title (handles(3, 1), 'Filtered PLL discriminator'); - - %----- DLL discriminator unfiltered-------------------------------- - plot (handles(3, 2), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscr, 'r'); - - grid (handles(3, 2)); - axis (handles(3, 2), 'tight'); - xlabel(handles(3, 2), 'Time (s)'); - ylabel(handles(3, 2), 'Amplitude'); - title (handles(3, 2), 'Raw DLL discriminator'); - - %----- DLL discriminator filtered---------------------------------- - plot (handles(3, 3), timeAxisInSeconds, ... - trackResults(channelNr).dllDiscrFilt, 'b'); - - grid (handles(3, 3)); - axis (handles(3, 3), 'tight'); - xlabel(handles(3, 3), 'Time (s)'); - ylabel(handles(3, 3), 'Amplitude'); - title (handles(3, 3), 'Filtered DLL discriminator'); - -end % for channelNr = channelList +function plotTracking(channelList, trackResults, settings) +% This function plots the tracking results for the given channel list. +% +% plotTracking(channelList, trackResults, settings) +% +% Inputs: +% channelList - list of channels to be plotted. +% trackResults - tracking results from the tracking function. +% settings - receiver settings. + +%-------------------------------------------------------------------------- +% SoftGNSS v3.0 +% +% Copyright (C) Darius Plausinaitis +% Written by Darius Plausinaitis +%-------------------------------------------------------------------------- +% 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, write to the Free Software +% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +% USA. +%-------------------------------------------------------------------------- + +% Protection - if the list contains incorrect channel numbers +channelList = intersect(channelList, 1:settings.numberOfChannels); + +%=== For all listed channels ============================================== +for channelNr = channelList + + %% Select (or create) and clear the figure ================================ + % The number 200 is added just for more convenient handling of the open + % figure windows, when many figures are closed and reopened. + % Figures drawn or opened by the user, will not be "overwritten" by + % this function. + + figure(channelNr +200); + clf(channelNr +200); + set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ... + ' (PRN ', ... + num2str(trackResults(channelNr).PRN), ... + ') results']); + + %% Draw axes ============================================================== + % Row 1 + handles(1, 1) = subplot(3, 3, 1); + handles(1, 2) = subplot(3, 3, [2 3]); + % Row 2 + handles(2, 1) = subplot(3, 3, 4); + handles(2, 2) = subplot(3, 3, [5 6]); + % Row 3 + handles(3, 1) = subplot(3, 3, 7); + handles(3, 2) = subplot(3, 3, 8); + handles(3, 3) = subplot(3, 3, 9); + + %% Plot all figures ======================================================= + + timeAxisInSeconds = (1:settings.msToProcess-1)/1000; + + %----- Discrete-Time Scatter Plot --------------------------------- + plot(handles(1, 1), trackResults(channelNr).I_PN,... + trackResults(channelNr).Q_PN, ... + '.'); + + grid (handles(1, 1)); + axis (handles(1, 1), 'equal'); + title (handles(1, 1), 'Discrete-Time Scatter Plot'); + xlabel(handles(1, 1), 'I prompt'); + ylabel(handles(1, 1), 'Q prompt'); + + %----- Nav bits --------------------------------------------------- + plot (handles(1, 2), timeAxisInSeconds, ... + trackResults(channelNr).I_PN(1:settings.msToProcess-1)); + + grid (handles(1, 2)); + title (handles(1, 2), 'Bits of the navigation message'); + xlabel(handles(1, 2), 'Time (s)'); + axis (handles(1, 2), 'tight'); + + %----- PLL discriminator unfiltered-------------------------------- + plot (handles(2, 1), timeAxisInSeconds, ... + trackResults(channelNr).pllDiscr(1:settings.msToProcess-1), 'r'); + + grid (handles(2, 1)); + axis (handles(2, 1), 'tight'); + xlabel(handles(2, 1), 'Time (s)'); + ylabel(handles(2, 1), 'Amplitude'); + title (handles(2, 1), 'Raw PLL discriminator'); + + %----- Correlation ------------------------------------------------ + plot(handles(2, 2), timeAxisInSeconds, ... + [sqrt(trackResults(channelNr).I_E(1:settings.msToProcess-1).^2 + ... + trackResults(channelNr).Q_E(1:settings.msToProcess-1).^2)', ... + sqrt(trackResults(channelNr).I_P(1:settings.msToProcess-1).^2 + ... + trackResults(channelNr).Q_P(1:settings.msToProcess-1).^2)', ... + sqrt(trackResults(channelNr).I_L(1:settings.msToProcess-1).^2 + ... + trackResults(channelNr).Q_L(1:settings.msToProcess-1).^2)'], ... + '-*'); + + grid (handles(2, 2)); + title (handles(2, 2), 'Correlation results'); + xlabel(handles(2, 2), 'Time (s)'); + axis (handles(2, 2), 'tight'); + + hLegend = legend(handles(2, 2), '$\sqrt{I_{E}^2 + Q_{E}^2}$', ... + '$\sqrt{I_{P}^2 + Q_{P}^2}$', ... + '$\sqrt{I_{L}^2 + Q_{L}^2}$'); + + %set interpreter from tex to latex. This will draw \sqrt correctly + set(hLegend, 'Interpreter', 'Latex'); + + %----- PLL discriminator filtered---------------------------------- + plot (handles(3, 1), timeAxisInSeconds, ... + trackResults(channelNr).pllDiscrFilt(1:settings.msToProcess-1), 'b'); + + grid (handles(3, 1)); + axis (handles(3, 1), 'tight'); + xlabel(handles(3, 1), 'Time (s)'); + ylabel(handles(3, 1), 'Amplitude'); + title (handles(3, 1), 'Filtered PLL discriminator'); + + %----- DLL discriminator unfiltered-------------------------------- + plot (handles(3, 2), timeAxisInSeconds, ... + trackResults(channelNr).dllDiscr(1:settings.msToProcess-1), 'r'); + + grid (handles(3, 2)); + axis (handles(3, 2), 'tight'); + xlabel(handles(3, 2), 'Time (s)'); + ylabel(handles(3, 2), 'Amplitude'); + title (handles(3, 2), 'Raw DLL discriminator'); + + %----- DLL discriminator filtered---------------------------------- + plot (handles(3, 3), timeAxisInSeconds, ... + trackResults(channelNr).dllDiscrFilt(1:settings.msToProcess-1), 'b'); + + grid (handles(3, 3)); + axis (handles(3, 3), 'tight'); + xlabel(handles(3, 3), 'Time (s)'); + ylabel(handles(3, 3), 'Amplitude'); + title (handles(3, 3), 'Filtered DLL discriminator'); + +end % for channelNr = channelList diff --git a/src/utils/matlab/plot_acq_grid.m b/src/utils/matlab/plot_acq_grid.m new file mode 100644 index 000000000..86a710e76 --- /dev/null +++ b/src/utils/matlab/plot_acq_grid.m @@ -0,0 +1,115 @@ +% Reads GNSS-SDR Acquisition dump .mat file using the provided +% function and plots acquisition grid of acquisition statistic of PRN sat +% Antonio Ramos, 2017. antonio.ramos(at)cttc.es +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +%%%%%%%%% ?????? CONFIGURE !!! %%%%%%%%%%%%% + +path = '/archive/'; +file = 'acq'; + +sat = 7; + +channel = 0; +execution = 1; +% Signal: +% 1 GPS L1 +% 2 GPS L2M +% 3 GPS L5 +% 4 Gal. E1B +% 5 Gal. E5 +% 6 Glo. 1G + +signal_type = 1; + +%%% True for light grid representation +lite_view = true; + +%%% If lite_view, it sets the number of samples per chip in the graphical representation +n_samples_per_chip = 3; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +switch(signal_type) + case 1 + n_chips = 1023; + system = 'G'; + signal = '1C'; + case 2 + n_chips = 10230; + system = 'G'; + signal = '2S'; + case 3 + n_chips = 10230; + system = 'G'; + signal = 'L5'; + case 4 + n_chips = 4092; + system = 'E'; + signal = '1B'; + case 5 + n_chips = 10230; + system = 'E'; + signal = '5X'; + case 6 + n_chips = 511; + system = 'R'; + signal = '1G'; +end +filename = [path file '_' system '_' signal '_ch_' num2str(channel) '_' num2str(execution) '_sat_' num2str(sat) '.mat']; +load(filename); +[n_fft n_dop_bins] = size(grid); +[d_max f_max] = find(grid == max(max(grid))); +freq = (0 : n_dop_bins - 1) * doppler_step - doppler_max; +delay = (0 : n_fft - 1) / n_fft * n_chips; +figure(1) +if(lite_view == false) + surf(freq, delay, grid, 'FaceColor', 'interp', 'LineStyle', 'none') + ylim([min(delay) max(delay)]) +else + delay_interp = (0 : n_samples_per_chip * n_chips - 1) / n_samples_per_chip; + grid_interp = spline(delay, grid', delay_interp)'; + surf(freq, delay_interp, grid_interp, 'FaceColor', 'interp', 'LineStyle', 'none') + ylim([min(delay_interp) max(delay_interp)]) +end +xlabel('Doppler shift / Hz') +xlim([min(freq) max(freq)]) +ylabel('Code delay / chips') +zlabel('Test statistics') +figure(2) +subplot(2,1,1) +plot(freq, grid(d_max, :)) +xlim([min(freq) max(freq)]) +xlabel('Doppler shift / Hz') +ylabel('Test statistics') +title(['Fixed code delay to ' num2str((d_max - 1) / n_fft * n_chips) ' chips']) +subplot(2,1,2) +normalization = (d_samples_per_code^4) * input_power; +plot(delay, acq_grid(:, f_max)./normalization) +xlim([min(delay) max(delay)]) +xlabel('Code delay / chips') +ylabel('Test statistics') +title(['Doppler wipe-off = ' num2str((f_max - 1) * doppler_step - doppler_max) ' Hz']) diff --git a/src/utils/matlab/plot_acq_grid_gsoc.m b/src/utils/matlab/plot_acq_grid_gsoc.m index c38d5ea18..ed8ff5033 100644 --- a/src/utils/matlab/plot_acq_grid_gsoc.m +++ b/src/utils/matlab/plot_acq_grid_gsoc.m @@ -1,37 +1,35 @@ -% /*! -% * \file plot_acq_grid_gsoc.m -% * \brief Read GNSS-SDR Acquisition dump binary file using the provided -% function and plot acquisition grid of acquisition statistic of PRN sat +% Reads GNSS-SDR Acquisition dump binary file using the provided +% function and plots acquisition grid of acquisition statistic of PRN sat % -% This function analyzes a experiment performed by Luis Esteve in the framework +% This function analyzes a experiment performed by Luis Esteve in the framework % of the Google Summer of Code (GSoC) 2012, with the collaboration of Javier Arribas -% and Carles Fernández, related to the extension of GNSS-SDR to Galileo. +% and Carles Fern??ndez, related to the extension of GNSS-SDR to Galileo. +% +% Luis Esteve, 2012. luis(at)epsilon-formacion.com +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- % -% * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ function plot_acq_grid_gsoc(sat) @@ -61,7 +59,7 @@ for k=Doppler_min_Hz:Doppler_step_Hz:Doppler_max_Hz index=index+1; filename=['test_statistics_E_1C_sat_' num2str(sat) '_doppler_' num2str(k) '.dat']; acq_grid(index,:)=abs(read_complex_binary (filename)); - end +end maximum_correlation_peak = max(max(acq_grid)) diff --git a/src/utils/matlab/plot_acq_grid_gsoc_e5.m b/src/utils/matlab/plot_acq_grid_gsoc_e5.m index 2259c1b93..1801a17e1 100644 --- a/src/utils/matlab/plot_acq_grid_gsoc_e5.m +++ b/src/utils/matlab/plot_acq_grid_gsoc_e5.m @@ -1,39 +1,38 @@ -% /*! -% * \file plot_acq_grid_gsoc_e5.m -% * \brief Read GNSS-SDR Acquisition dump binary file using the provided -% function and plot acquisition grid of acquisition statistic of PRN sat. -% CAF input must be 0 or 1 depending if the user desires to read the file -% that resolves doppler ambiguity or not. +% Reads GNSS-SDR Acquisition dump binary file using the provided +% function and plot acquisition grid of acquisition statistic of PRN sat. +% CAF input must be 0 or 1 depending if the user desires to read the file +% that resolves doppler ambiguity or not. % -% This function analyzes a experiment performed by Marc Sales in the framework -% of the Google Summer of Code (GSoC) 2014, with the collaboration of Luis Esteve, Javier Arribas -% and Carles Fernández, related to the extension of GNSS-SDR to Galileo. +% This function analyzes a experiment performed by Marc Sales in the framework +% of the Google Summer of Code (GSoC) 2014, with the collaboration of Luis Esteve, Javier Arribas +% and Carles Fernandez, related to the extension of GNSS-SDR to Galileo. +% +% Marc Sales marcsales92(at)gmail.com, +% Luis Esteve, 2014. luis(at)epsilon-formacion.com +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- % -% * \author Marc Sales marcsales92(at)gmail.com, Luis Esteve, 2014. luis(at)epsilon-formacion.com -% * ------------------------------------------------------------------------- -% * -% * Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors) -% * -% * GNSS-SDR is a software defined Global Navigation -% * Satellite Systems receiver -% * -% * This file is part of GNSS-SDR. -% * -% * GNSS-SDR is free software: you can redistribute it and/or modify -% * it under the terms of the GNU General Public License as published by -% * the Free Software Foundation, either version 3 of the License, or -% * at your option) any later version. -% * -% * GNSS-SDR 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 GNSS-SDR. If not, see . -% * -% * ------------------------------------------------------------------------- -% */ function plot_acq_grid_gsoc_e5(sat,CAF) @@ -127,7 +126,7 @@ myFile = java.io.File(file); flen = length(myFile); num_samples=flen/8; % 8 bytes (2 single floats) per complex sample -for k=1:num_samples +for k=1:num_samples a(1:2) = fread(fid, 2, 'float'); x(k) = a(1) + a(2)*1i; k=k+1; diff --git a/src/utils/matlab/plot_acq_grid_gsoc_glonass.m b/src/utils/matlab/plot_acq_grid_gsoc_glonass.m new file mode 100644 index 000000000..363962532 --- /dev/null +++ b/src/utils/matlab/plot_acq_grid_gsoc_glonass.m @@ -0,0 +1,96 @@ +% Reads GNSS-SDR Acquisition dump binary file using the provided +% function and plots acquisition grid of acquisition statistic of PRN sat +% +% This function analyzes a experiment performed by Luis Esteve in the framework +% of the Google Summer of Code (GSoC) 2012, with the collaboration of Javier Arribas +% and Carles Fernandez, related to the extension of GNSS-SDR to Galileo. +% +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% + +function plot_acq_grid_gsoc_glonass(sat) + +file=['/archive/acquisition_R_1G_sat_' num2str(sat) '_doppler_0.dat']; + +% sampling_freq_Hz=62316000 +sampling_freq_Hz=6.625e6 +Doppler_max_Hz = 10000 +Doppler_min_Hz = -10000 +Doppler_step_Hz = 250 + + +% read files + +x=read_complex_binary (file); + +l_y=length(x); + +Doppler_axes=Doppler_min_Hz:Doppler_step_Hz:Doppler_max_Hz; + +l_x=length(Doppler_axes); + +acq_grid = zeros(l_x,l_y); + +index=0; + +for k=Doppler_min_Hz:Doppler_step_Hz:Doppler_max_Hz + index=index+1; + filename=['acquisition_R_1G_sat_' num2str(sat) '_doppler_' num2str(k) '.dat']; + acq_grid(index,:)=abs(read_complex_binary (filename)); +end + +acq_grid = acq_grid.^2; + +maximum_correlation_peak = max(max(acq_grid)) + +[fila,col]=find(acq_grid==max(max(acq_grid))); + +delay_error_sps = col -1 + +Doppler_error_Hz = Doppler_axes(fila) + +noise_grid=acq_grid; +delay_span=floor(3*sampling_freq_Hz/(0.511e6)); +Doppler_span=floor(500/Doppler_step_Hz); +noise_grid(fila-Doppler_span:fila+Doppler_span,col-delay_span:col+delay_span)=0; + +n=numel(noise_grid)-(2*delay_span+1)*(2*Doppler_span+1); + +noise_floor= sum(sum(noise_grid))/n + +Gain_dbs = 10*log10(maximum_correlation_peak/noise_floor) + + +%% Plot 3D FULL RESOLUTION + + +[X,Y] = meshgrid(Doppler_axes,1:1:l_y); +figure; +surf(X,Y,acq_grid'); + +xlabel('Doppler(Hz)');ylabel('Code Delay(samples)');title(['GLRT statistic of Glonass Parallel Code Phase Search Acquisition. Local replica: L1 cboc PRN ' num2str(sat)]); + + +end diff --git a/src/utils/matlab/plot_tracking_quality_indicators.m b/src/utils/matlab/plot_tracking_quality_indicators.m new file mode 100644 index 000000000..a1c263aa3 --- /dev/null +++ b/src/utils/matlab/plot_tracking_quality_indicators.m @@ -0,0 +1,18 @@ +%plot tracking quality indicators +figure; +hold on; +title('Carrier lock test output for all the channels'); +for n=1:1:length(GNSS_tracking) + plot(GNSS_tracking(n).carrier_lock_test) + plotnames{n}=['SV ' num2str(round(mean(GNSS_tracking(n).PRN)))]; +end +legend(plotnames); + +figure; +hold on; +title('Carrier CN0 output for all the channels'); +for n=1:1:length(GNSS_tracking) + plot(GNSS_tracking(n).CN0_SNV_dB_Hz) + plotnames{n}=['SV ' num2str(round(mean(GNSS_tracking(n).PRN)))]; +end +legend(plotnames); \ No newline at end of file diff --git a/src/utils/reproducibility/ieee-access18/L2-access18.conf b/src/utils/reproducibility/ieee-access18/L2-access18.conf new file mode 100644 index 000000000..e4d7b5e67 --- /dev/null +++ b/src/utils/reproducibility/ieee-access18/L2-access18.conf @@ -0,0 +1,159 @@ + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. +GNSS-SDR.internal_fs_sps=3000000 + + +;######### SIGNAL_SOURCE CONFIG ############ +;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] (experimental) +SignalSource.implementation=File_Signal_Source + +;#filename: path to file with the captured GNSS signal samples to be processed +SignalSource.filename=./data/L125_III1b_210s_L2_3Msps.bin ; <- Available at https://zenodo.org/record/1184601 + +;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version. +SignalSource.item_type=ibyte + +;#sampling_frequency: Original Signal sampling frequency in [Hz] +SignalSource.sampling_frequency=3000000 + +;#samples: Number of samples to be processed. Notice that 0 indicates the entire file. +SignalSource.samples=0 + +;#repeat: Repeat the processing file. Disable this option in this version +SignalSource.repeat=false + +;#dump: Dump the Signal source data to a file. Disable this option in this version +SignalSource.dump=false + +;#enable_throttle_control: Enabling this option tells the signal source to keep the delay between samples in post processing. +; it helps to not overload the CPU, but the processing time will be longer. +SignalSource.enable_throttle_control=false + + +;######### SIGNAL_CONDITIONER CONFIG ############ + +SignalConditioner.implementation=Signal_Conditioner + +;######### DATA_TYPE_ADAPTER CONFIG ############ + +DataTypeAdapter.implementation=Ibyte_To_Complex + +;######### INPUT_FILTER CONFIG ############ + +InputFilter.implementation=Pass_Through + + +;######### RESAMPLER CONFIG ############ + +Resampler.implementation=Pass_Through +Resampler.item_type=gr_complex + + +;######### CHANNELS GLOBAL CONFIG ############ + +Channels_2S.count=10 + +;Channels.in_acquisition=1 + +Channel0.signal=2S +Channel1.signal=2S +Channel2.signal=2S +Channel3.signal=2S +Channel4.signal=2S +Channel5.signal=2S +Channel6.signal=2S +Channel7.signal=2S +Channel8.signal=2S +Channel9.signal=2S + +;######### SPECIFIC CHANNELS CONFIG ###### + +Channel0.satellite=19 + +;######### ACQUISITION GLOBAL CONFIG ############ + +Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition + +Acquisition_2S.item_type=gr_complex + +Acquisition_2S.doppler_max=4500 + +Acquisition_2S.doppler_step=125 + +Acquisition_2S.use_CFAR_algorithm=false + +Acquisition_2S.threshold=10 + +Acquisition_2S.blocking=true + + +;######### TRACKING GLOBAL CONFIG ############ + +Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking + +Tracking_2S.item_type=gr_complex + +Tracking_2S.pll_bw_hz=4.0; + +Tracking_2S.dll_bw_hz=1; + +Tracking_2S.early_late_space_chips=0.5; + +Tracking_2S.dump=true + +Tracking_2S.dump_filename=./data/track_ch_ + + +;######### TELEMETRY DECODER CONFIG ############ + +TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder + + +;######### OBSERVABLES CONFIG ############ + +Observables.implementation=Hybrid_Observables + + +;######### PVT CONFIG ############ + +PVT.implementation=RTKLIB_PVT + +PVT.positioning_mode=Single; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=OFF; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=OFF; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad + +;#output_rate_ms: Period between two PVT outputs. Notice that the minimum period is equal to the tracking integration time [ms] +PVT.output_rate_ms=100 + +;#display_rate_ms: Position console print (std::out) interval [ms]. Notice that output_rate_ms<=display_rate_ms. +PVT.display_rate_ms=500 + +;# KML, GeoJSON, NMEA and RTCM output configuration +;#dump_filename: Log path and filename without extension. Notice that PVT will add ".dat" to the binary dump and ".kml" to GoogleEarth dump. +PVT.dump_filename=./data/access18 + +;#nmea_dump_filename: NMEA log path and filename +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea + +;#flag_nmea_tty_port: Enable or disable the NMEA log to a serial TTY port (Can be used with real hardware or virtual one) +PVT.flag_nmea_tty_port=false + +;#nmea_dump_devname: serial device descriptor for NMEA logging +PVT.nmea_dump_devname=/dev/pts/4 + +PVT.flag_rtcm_server=false + +PVT.rtcm_tcp_port=2101 + +PVT.rtcm_station_id=1234 + +PVT.flag_rtcm_tty_port=false + +PVT.rtcm_dump_devname=/dev/pts/1 + +PVT.dump=true + +PVT.elevation_mask=5 diff --git a/src/utils/reproducibility/ieee-access18/README.md b/src/utils/reproducibility/ieee-access18/README.md new file mode 100644 index 000000000..58a2350ff --- /dev/null +++ b/src/utils/reproducibility/ieee-access18/README.md @@ -0,0 +1,48 @@ +Continuous Reproducibility in GNSS Signal Processing +---------------------------------------------------- + + +This folder contains files required for the reproduction of the experiment proposed in: + +C. Fernández-Prades, J. Vilà-Valls, J. Arribas and A. Ramos, [*Continuous Reproducibility in GNSS Signal Processing*](https://ieeexplore.ieee.org/document/8331069/), IEEE Access, Vol. 6, No. 1, pp. 20451-20463, April 2018. DOI: [10.1109/ACCESS.2018.2822835](https://doi.org/10.1109/ACCESS.2018.2822835) + +The data set used in this paper is available at https://zenodo.org/record/1184601 + +The sample format is `ibyte`: Interleaved (I&Q) stream of samples of type signed integer, 8-bit two’s complement number ranging from -128 to 127. The sampling rate is 3 MSps. + +The figure appearing in that paper can be automatically generated with the pipeline available at https://gitlab.com/gnss-sdr/gnss-sdr/pipelines + +After the **Build** stage, which compiles the source code in several versions of the most popular GNU/Linux distributions, and the **Test** stage, which executes GNSS-SDR’s QA code, the **Deploy** stage creates and publishes an image of a software container ready to execute the experiment. This container is available by doing: + +``` +$ docker pull carlesfernandez/docker-gnsssdr:access18 +``` + +Then, in the **Experiment** stage, a job installs the image created in the previous step, grabs the data file, executes the experiment and produces a figure with the obtained results. + +The steps to reproduce the experiment in your own machine (with [Docker](https://www.docker.com) already installed and running) are: + +``` +$ docker pull carlesfernandez/docker-gnsssdr:access18 +$ docker run -it -v $PWD/access18:/home/access18 carlesfernandez/docker-gnsssdr:access18 +$ git clone https://github.com/gnss-sdr/gnss-sdr +$ cd gnss-sdr +$ git checkout next +$ mkdir -p exp-access18/data +$ cd exp-access18/data +$ curl https://zenodo.org/record/1184601/files/L2_signal_samples.tar.xz --output L2_signal_samples.tar.xz +$ tar xvfJ L2_signal_samples.tar.xz +$ echo "3a04c1eeb970776bb77f5e3b7eaff2df L2_signal_samples.tar.xz" > data.md5 +$ md5sum -c data.md5 +$ cd .. +$ cp ../src/utils/reproducibility/ieee-access18/L2-access18.conf . +$ cp ../src/utils/reproducibility/ieee-access18/plot_dump.m . +$ cp -r ../src/utils/matlab/libs/geoFunctions . +$ gnss-sdr --c=L2-access18.conf +$ octave --no-gui plot_dump.m +$ epspdf Figure2.eps Figure2.pdf +$ cp Figure2.pdf /home/access18/ +$ exit +``` + +You will find the file `Figure2.pdf` in a newly created folder called `access18`. diff --git a/src/utils/reproducibility/ieee-access18/plot_dump.m b/src/utils/reproducibility/ieee-access18/plot_dump.m new file mode 100644 index 000000000..11aaba424 --- /dev/null +++ b/src/utils/reproducibility/ieee-access18/plot_dump.m @@ -0,0 +1,235 @@ +% ------------------------------------------------------------------------- +% +% Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) +% +% GNSS-SDR is a software defined Global Navigation +% Satellite Systems receiver +% +% This file is part of GNSS-SDR. +% +% GNSS-SDR is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% at your option) any later version. +% +% GNSS-SDR 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 GNSS-SDR. If not, see . +% +% ------------------------------------------------------------------------- +% +% Antonio Ramos, 2018. antonio.ramos(at)cttc.es + +clear all; +clc; + +n_channel = 0; +symbol_period = 20e-3; +filename = 'track_ch_'; + +fontsize = 12; + +addpath('./data') % Path to gnss-sdr dump files (Tracking and PVT) +addpath('./geoFunctions') + +load([filename int2str(n_channel) '.mat']); +t = (0 : length(abs_P) - 1) * symbol_period; +hf = figure('visible', 'off'); +set(hf, 'paperorientation', 'landscape'); +subplot(3, 3, [1,3]) +plot(t, abs_E, t, abs_P, t, abs_L) +xlabel('Time [s]','fontname','Times','fontsize', fontsize) +ylabel('Correlation result','fontname','Times','fontsize', fontsize) +legend('Early', 'Prompt', 'Late') +grid on + + +subplot(3, 3, 7) +plot(Prompt_I./1000, Prompt_Q./1000, 'linestyle', 'none', 'marker', '.') +xlabel('I','fontname','Times','fontsize', fontsize) +ylabel('Q','fontname','Times','fontsize', fontsize) +axis equal +grid on + +subplot(3, 3, [4,6]) +plot(t, Prompt_I) +xlabel('Time [s]','fontname','Times','fontsize', fontsize) +ylabel('Navigation data bits','fontname','Times','fontsize', fontsize) +grid on + + +fileID = fopen('data/access18.dat', 'r'); +dinfo = dir('data/access18.dat'); +filesize = dinfo.bytes; +aux = 1; +while ne(ftell(fileID), filesize) + navsol.TOW_at_current_symbol_ms(aux) = fread(fileID, 1, 'uint32'); + navsol.week(aux) = fread(fileID, 1, 'uint32'); + navsol.RX_time(aux) = fread(fileID, 1, 'double'); + navsol.user_clock_offset(aux) = fread(fileID, 1, 'double'); + navsol.X(aux) = fread(fileID, 1, 'double'); + navsol.Y(aux) = fread(fileID, 1, 'double'); + navsol.Z(aux) = fread(fileID, 1, 'double'); + navsol.VX(aux) = fread(fileID, 1, 'double'); + navsol.VY(aux) = fread(fileID, 1, 'double'); + navsol.VZ(aux) = fread(fileID, 1, 'double'); + navsol.varXX(aux) = fread(fileID, 1, 'double'); + navsol.varYY(aux) = fread(fileID, 1, 'double'); + navsol.varZZ(aux) = fread(fileID, 1, 'double'); + navsol.varXY(aux) = fread(fileID, 1, 'double'); + navsol.varYZ(aux) = fread(fileID, 1, 'double'); + navsol.varZX(aux) = fread(fileID, 1, 'double'); + navsol.latitude(aux) = fread(fileID, 1, 'double'); + navsol.longitude(aux) = fread(fileID, 1, 'double'); + navsol.height(aux) = fread(fileID, 1, 'double'); + navsol.number_sats(aux) = fread(fileID, 1, 'uint8'); + navsol.solution_status(aux) = fread(fileID, 1, 'uint8'); + navsol.solution_type(aux) = fread(fileID, 1, 'uint8'); + navsol.AR_ratio_factor(aux) = fread(fileID, 1, 'float'); + navsol.AR_ratio_threshold(aux) = fread(fileID, 1, 'float'); + navsol.GDOP(aux) = fread(fileID, 1, 'double'); + navsol.PDOP(aux) = fread(fileID, 1, 'double'); + navsol.HDOP(aux) = fread(fileID, 1, 'double'); + navsol.VDOP(aux) = fread(fileID, 1, 'double'); + aux = aux + 1; +end +fclose(fileID); + + +mean_Latitude = mean(navsol.latitude); +mean_Longitude = mean(navsol.longitude); +mean_h = mean(navsol.height); +utmZone = findUtmZone(mean_Latitude, mean_Longitude); +[ref_X_cart, ref_Y_cart, ref_Z_cart] = geo2cart(dms2mat(deg2dms(mean_Latitude)), dms2mat(deg2dms(mean_Longitude)), mean_h, 5); +[mean_utm_X, mean_utm_Y, mean_utm_Z] = cart2utm(ref_X_cart, ref_Y_cart, ref_Z_cart, utmZone); + + +numPoints = length(navsol.X); +aux = 0; +for n = 1:numPoints + aux = aux+1; + [E(aux), N(aux), U(aux)] = cart2utm(navsol.X(n), navsol.Y(n), navsol.Z(n), utmZone); +end + +v_2d = [E;N].'; % 2D East Nort position vectors +v_3d = [E;N;U].'; % 2D East Nort position vectors + + +%% ACCURACY + +% 2D ------------------- + +sigma_E_accuracy = sqrt((1/(numPoints-1)) * sum((v_2d(:,1) - mean_utm_X).^2)); +sigma_N_accuracy = sqrt((1/(numPoints-1)) * sum((v_2d(:,2) - mean_utm_Y).^2)); +sigma_ratio_2d_accuracy = sigma_N_accuracy / sigma_E_accuracy + +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 65% +DRMS_accuracy = sqrt(sigma_E_accuracy^2 + sigma_N_accuracy^2) +% if sigma_ratio=1 -> Prob in circle with r=2DRMS -> 95% +TWO_DRMS_accuracy = 2 * DRMS_accuracy +% if sigma_ratio>0.3 -> Prob in circle with r=CEP -> 50% +CEP_accuracy = 0.62 * sigma_E_accuracy + 0.56 * sigma_N_accuracy + +% 3D ------------------- + +sigma_U_accuracy = sqrt((1/(numPoints-1)) * sum((v_3d(:,3) - mean_utm_Z).^2)); + +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 50% +SEP_accuracy = 0.51 * sqrt(sigma_E_accuracy^2 + sigma_N_accuracy^2 + sigma_U_accuracy^2) +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 61% +MRSE_accuracy = sqrt(sigma_E_accuracy^2 + sigma_N_accuracy^2 + sigma_U_accuracy^2) +% if sigma_ratio=1 -> Prob in circle with r=2DRMS -> 95% +TWO_MRSE_accuracy=2 * MRSE_accuracy + + + +%% PRECISION + +% 2D Mean and Variance +mean_2d = [mean(v_2d(:,1)) ; mean(v_2d(:,2))]; +sigma_2d = [sqrt(var(v_2d(:,1))) ; sqrt(var(v_2d(:,2)))]; +sigma_ratio_2d = sigma_2d(2) / sigma_2d(1) + +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 65% +DRMS = sqrt(sigma_2d(1)^2 + sigma_2d(2)^2) +% if sigma_ratio=1 -> Prob in circle with r=2DRMS -> 95% +TWO_DRMS = 2 * DRMS +% if sigma_ratio>0.3 -> Prob in circle with r=CEP -> 50% +CEP = 0.62 * sigma_2d(1) + 0.56 * sigma_2d(2) + +% 3D Mean and Variance +mean_3d = [mean(v_3d(:,1)) ; mean(v_3d(:,2)) ; mean(v_3d(:,3))]; +sigma_3d = [sqrt(var(v_3d(:,1))) ; sqrt(var(v_3d(:,2))) ; sqrt(var(v_3d(:,3)))]; + +% absolute mean error +error_2D_vec = [mean_utm_X-mean_2d(1) mean_utm_Y-mean_2d(2)]; +error_2D_m = norm(error_2D_vec) + +error_3D_vec = [mean_utm_X-mean_3d(1) mean_utm_Y-mean_3d(2) mean_utm_Z-mean_3d(3)]; +error_3D_m = norm(error_3D_vec) + +RMSE_X = sqrt(mean((v_3d(:,1)-mean_utm_X).^2)) +RMSE_Y = sqrt(mean((v_3d(:,2)-mean_utm_Y).^2)) +RMSE_Z = sqrt(mean((v_3d(:,3)-mean_utm_Z).^2)) + +RMSE_2D = sqrt(mean((v_2d(:,1)-mean_utm_X).^2 + (v_2d(:,2)-mean_utm_Y).^2)) +RMSE_3D = sqrt(mean((v_3d(:,1)-mean_utm_X).^2 + (v_3d(:,2)-mean_utm_Y).^2 + (v_3d(:,3)-mean_utm_Z).^2)) + +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 50% +SEP = 0.51 * sqrt(sigma_3d(1)^2 + sigma_3d(2)^2 + sigma_3d(3)^2) +% if sigma_ratio=1 -> Prob in circle with r=DRMS -> 61% +MRSE = sqrt(sigma_3d(1)^2 + sigma_3d(2)^2 + sigma_3d(3)^2) +% if sigma_ratio=1 -> Prob in circle with r=2DRMS -> 95% +TWO_MRSE = 2 * MRSE + + +%% SCATTER PLOT 2D +subplot(3,3,8) +scatter(v_2d(:,1)-mean_2d(1), v_2d(:,2)-mean_2d(2)); +hold on; + +plot(0, 0, 'k*'); + +[x,y,z] = cylinder([TWO_DRMS TWO_DRMS], 200); +plot(x(1,:), y(1,:), 'Color', [0 0.6 0]); +str = strcat('2DRMS=', num2str(TWO_DRMS), ' m'); +text(cosd(65)*TWO_DRMS, sind(65)*TWO_DRMS, str, 'Color', [0 0.6 0]); + +[x,y,z] = cylinder([CEP CEP], 200); +plot(x(1,:), y(1,:), 'r--'); +str = strcat('CEP=', num2str(CEP), ' m'); +text(cosd(80)*CEP, sind(80)*CEP, str, 'Color','r'); + +grid on +axis equal; +xlabel('North [m]','fontname','Times','fontsize', fontsize) +ylabel('East [m]','fontname','Times','fontsize', fontsize) + + + +%% SCATTER PLOT 3D +subplot(3,3,9) +scatter3(v_3d(:,1)-mean_3d(1), v_3d(:,2)-mean_3d(2), v_3d(:,3)-mean_3d(3)); + +hold on; + +[x,y,z] = sphere(); +hSurface = surf(MRSE*x, MRSE*y, MRSE*z); % sphere centered at origin +set(hSurface, 'facecolor', 'none', 'edgecolor', [0 0.6 0], 'edgealpha', 1, 'facealpha', 1); + +xlabel('North [m]', 'fontname', 'Times', 'fontsize', fontsize-2) +ylabel('East [m]', 'fontname', 'Times', 'fontsize', fontsize-2) +zlabel('Up [m]', 'fontname', 'Times', 'fontsize', fontsize-2) +str = strcat('MRSE=', num2str(MRSE), ' m') +text(cosd(45)*MRSE, sind(45)*MRSE, 20, str, 'Color', [0 0.6 0]); +a = gca; +set(a, 'fontsize', fontsize-6) + +hh = findall(hf, '-property', 'FontName'); +set(hh, 'FontName', 'Times'); +print(hf, 'Figure2.eps', '-depsc') +close(hf); diff --git a/src/utils/rinex2assist/CMakeLists.txt b/src/utils/rinex2assist/CMakeLists.txt new file mode 100644 index 000000000..344c0694b --- /dev/null +++ b/src/utils/rinex2assist/CMakeLists.txt @@ -0,0 +1,80 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR 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 GNSS-SDR. If not, see . +# + +find_package(GPSTK QUIET) +if(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) + include(GNUInstallDirs) + string(REGEX REPLACE /[^/]*$ "" LIBDIR ${CMAKE_INSTALL_LIBDIR}) + set(GPSTK_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/../../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/${LIBDIR}/${CMAKE_FIND_LIBRARY_PREFIXES}gpstk${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(GPSTK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../thirdparty/gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}/install/include) +endif() + +set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} ${GPSTK_INCLUDE_DIR}/gpstk) + +find_package(Boost COMPONENTS iostreams serialization QUIET) + +find_program(UNCOMPRESS_EXECUTABLE uncompress + PATHS /bin + /usr/bin + /usr/sbin +) + +if(NOT UNCOMPRESS_EXECUTABLE-NOTFOUND) + add_definitions(-DUNCOMPRESS_EXECUTABLE="${UNCOMPRESS_EXECUTABLE}") +else() + add_definitions(-DUNCOMPRESS_EXECUTABLE="") +endif() + +if(Boost_FOUND) + include_directories( + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${GPSTK_INCLUDE_DIR}/gpstk + ${GPSTK_INCLUDE_DIR} + ) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated") + + add_executable(rinex2assist ${CMAKE_CURRENT_SOURCE_DIR}/main.cc) + + target_link_libraries(rinex2assist + ${Boost_LIBRARIES} + ${GPSTK_LIBRARY} + ${GFlags_LIBS} + gnss_sp_libs + gnss_rx + ) + + if(NOT GPSTK_FOUND OR ENABLE_OWN_GPSTK) + add_dependencies(rinex2assist gpstk-${GNSSSDR_GPSTK_LOCAL_VERSION}) + endif() + + add_custom_command(TARGET rinex2assist POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$ + ) + + install(TARGETS rinex2assist + RUNTIME DESTINATION bin + COMPONENT "rinex2assist" + ) +else() + message(STATUS "Boost Iostreams library not found.") + message(STATUS "rinex2assist will not be built.") +endif() diff --git a/src/utils/rinex2assist/README.md b/src/utils/rinex2assist/README.md new file mode 100644 index 000000000..9d378d797 --- /dev/null +++ b/src/utils/rinex2assist/README.md @@ -0,0 +1,81 @@ +Rinex2assist +------------ + +This program reads data from RINEX navigation files and generates XML files that can be read by GNSS-SDR as Assisted GNSS data. + +### Building + +This program is built along with GNSS-SDR if the options `ENABLE_UNIT_TESTING_EXTRA` or `ENABLE_SYSTEM_TESTING_EXTRA` are set to `ON` when calling CMake: + +``` +$ cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. +$ make +$ sudo make intall +``` + +The last step is optional. Without it, you will get the executable at `../install/rinex2assist`. + +The building requires two extra dependencies: the Boost Iostreams library and the program `uncompress`: + + * The Boost Iostreams library can be installed through a package: + - In Debian / Ubuntu: `sudo apt-get install libboost-iostreams-dev` + - In Fedora / CentOS: `sudo yum install boost-iostreams` + - In OpenSUSE: `sudo zypper install libboost_iostreams-devel` + - In Arch Linux: included in `boost-libs` package. + - In MacOS: included in Macports / Homebrew `boost` package. + * The program `uncompress` is available by default in most UNIX and GNU/Linux systems. + - In Fedora / CentOS: `sudo yum install ncompress` + - In OpenSUSE: `sudo zypper install ncompress` + +### Usage + +The usage is as follows: + +``` +$ rinex2assist /path/to/RINEX_nav_file +``` + +The argument is mandatory (the name of the RINEX navigation file). The name `gps_ephemeris.xml` is given to the output if GPS NAV data is fould. If the RINEX file contains Galileo data, the corresponding `gal_ephemeris.xml` file will be generated. The program is also able to extract parameters of the UTC and the Ionospheric models from the RINEX header, if available. They will be called `gps_utc_model.xml`, `gps_iono.xml`, `gal_utc_model.xml` and `gal_iono.xml`. + +There are some servers available for downloading recent RINEX navigation files. For instance: + * NASA: [ftp://cddis.gsfc.nasa.gov/pub/gnss/data/hourly/](ftp://gssc.esa.int/gnss/data/hourly/) + * ESA: [ftp://gssc.esa.int/gnss/data/hourly/](ftp://gssc.esa.int/gnss/data/hourly/) + * UNAVCO: [ftp://data-out.unavco.org/pub/hourly/rinex/](ftp://data-out.unavco.org/pub/hourly/rinex/) + +Just make sure to pick up a recent file from a [station near you](http://www.igs.org/network). + +The program accepts either versions 2.xx or 3.xx for the RINEX navigation data file, as well as compressed files (ending in `.gz` or `.Z`). + +Examples: + +``` +$ rinex2assist EBRE00ESP_R_20183290400_01H_GN.rnx.gz +Generated file: gps_ephemeris.xml +Generated file: gps_utc_model.xml +Generated file: gps_iono.xml +``` + +and + +``` +$ rinex2assist EBRE00ESP_R_20183290000_01H_EN.rnx.gz +Generated file: gal_ephemeris.xml +Generated file: gal_utc_model.xml +Generated file: gal_iono.xml +``` + + +An example of GNSS-SDR configuration using ephemeris, UTC and ionospheric model parameters for GPS L1 and Galileo signals is shown below: + +``` +GNSS-SDR.AGNSS_XML_enabled=true +GNSS-SDR.AGNSS_ref_location=41.39,2.31 +GNSS-SDR.AGNSS_gps_ephemeris_xml=gps_ephemeris.xml +GNSS-SDR.AGNSS_gps_iono_xml=gps_iono.xml +GNSS-SDR.AGNSS_gps_utc_model_xml=gps_utc_model.xml +GNSS-SDR.AGNSS_gal_ephemeris_xml=gal_ephemeris.xml +GNSS-SDR.AGNSS_gal_iono_xml=gal_iono.xml +GNSS-SDR.AGNSS_gal_utc_model_xml=gal_utc_model.xml +``` + +More info about the usage of AGNSS data [here](https://gnss-sdr.org/docs/sp-blocks/global-parameters/#assisted-gnss-with-xml-files). diff --git a/src/utils/rinex2assist/main.cc b/src/utils/rinex2assist/main.cc new file mode 100644 index 000000000..f23b58ed7 --- /dev/null +++ b/src/utils/rinex2assist/main.cc @@ -0,0 +1,440 @@ +/*! + * \file main.cc + * \brief converts navigation RINEX files into XML files for Assisted GNSS. + * \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.cat + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" +#include "gps_ephemeris.h" +#include "gps_iono.h" +#include "gps_utc_model.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char** argv) +{ + const std::string intro_help( + std::string("\n rinex2assist converts navigation RINEX files into XML files for Assisted GNSS\n") + + "Copyright (C) 2018 (see AUTHORS file for a list of contributors)\n" + + "This program comes with ABSOLUTELY NO WARRANTY;\n" + + "See COPYING file to see a copy of the General Public License.\n \n" + + "Usage: \n" + + " rinex2assist "); + + google::SetUsageMessage(intro_help); + google::SetVersionString("1.0"); + google::ParseCommandLineFlags(&argc, &argv, true); + + if ((argc != 2)) + { + std::cerr << "Usage:" << std::endl; + std::cerr << " " << argv[0] + << " " + << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::string xml_filename; + + // Uncompress if RINEX file is gzipped + std::string rinex_filename(argv[1]); + std::string input_filename = rinex_filename; + std::size_t found = rinex_filename.find_last_of('.'); + if (found != std::string::npos) + { + if (rinex_filename.size() >= found + 3) + { + if ((rinex_filename.substr(found + 1, found + 3) == "gz")) + { + std::ifstream file(rinex_filename, std::ios_base::in | std::ios_base::binary); + if (file.fail()) + { + std::cerr << "Could not open file " << rinex_filename << std::endl; + return 1; + } + boost::iostreams::filtering_streambuf in; + try + { + in.push(boost::iostreams::gzip_decompressor()); + } + catch (const boost::exception& e) + { + std::cerr << "Could not decompress file " << rinex_filename << std::endl; + return 1; + } + in.push(file); + std::string rinex_filename_unzipped = rinex_filename.substr(0, found); + std::ofstream output_file(rinex_filename_unzipped.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); + if (file.fail()) + { + std::cerr << "Could not create file " << rinex_filename_unzipped << std::endl; + return 1; + } + boost::iostreams::copy(in, output_file); + input_filename = rinex_filename_unzipped; + } + } + if (rinex_filename.size() >= found + 2) + { + if ((rinex_filename.substr(found + 1, found + 2) == "Z")) + { + std::ifstream file(rinex_filename, std::ios_base::in | std::ios_base::binary); + if (file.fail()) + { + std::cerr << "Could not open file" << rinex_filename << std::endl; + return 1; + } + file.close(); + std::string uncompress_executable(UNCOMPRESS_EXECUTABLE); + if (!uncompress_executable.empty()) + { + // option k is not always available, so we save a copy of the original file + std::string argum = std::string("/bin/cp " + rinex_filename + " " + rinex_filename + ".aux"); + int s1 = std::system(argum.c_str()); + std::string argum2 = std::string(uncompress_executable + " -f " + rinex_filename); + int s2 = std::system(argum2.c_str()); + std::string argum3 = std::string("/bin/mv " + rinex_filename + +".aux" + " " + rinex_filename); + int s3 = std::system(argum3.c_str()); + input_filename = rinex_filename.substr(0, found); + if ((s1 != 0) or (s2 != 0) or (s3 != 0)) + { + std::cerr << "Failure uncompressing file." << std::endl; + return 1; + } + } + else + { + std::cerr << "uncompress program not found." << std::endl; + return 1; + } + } + } + } + + std::map eph_map; + std::map eph_gal_map; + + Gps_Utc_Model gps_utc_model; + Gps_Iono gps_iono; + Galileo_Utc_Model gal_utc_model; + Galileo_Iono gal_iono; + + int i = 0; + int j = 0; + try + { + // Read nav file + gpstk::Rinex3NavStream rnffs(input_filename.c_str()); // Open navigation data file + gpstk::Rinex3NavData rne; + gpstk::Rinex3NavHeader hdr; + + // Read header + rnffs >> hdr; + + // Check that it really is a RINEX navigation file + if (hdr.fileType.substr(0, 1) != "N") + { + std::cerr << "This is not a valid RINEX navigation file, or file not found." << std::endl; + std::cerr << "No XML file will be created." << std::endl; + return 1; + } + + // Collect UTC parameters from RINEX header + if (hdr.fileSys == "G: (GPS)" || hdr.fileSys == "MIXED") + { + gps_utc_model.valid = (hdr.valid > 2147483648) ? true : false; + gps_utc_model.d_A1 = hdr.mapTimeCorr["GPUT"].A0; + gps_utc_model.d_A0 = hdr.mapTimeCorr["GPUT"].A1; + gps_utc_model.d_t_OT = hdr.mapTimeCorr["GPUT"].refSOW; + gps_utc_model.i_WN_T = hdr.mapTimeCorr["GPUT"].refWeek; + gps_utc_model.d_DeltaT_LS = hdr.leapSeconds; + gps_utc_model.i_WN_LSF = hdr.leapWeek; + gps_utc_model.i_DN = hdr.leapDay; + gps_utc_model.d_DeltaT_LSF = hdr.leapDelta; + + // Collect iono parameters from RINEX header + gps_iono.valid = (hdr.mapIonoCorr["GPSA"].param[0] == 0) ? false : true; + gps_iono.d_alpha0 = hdr.mapIonoCorr["GPSA"].param[0]; + gps_iono.d_alpha1 = hdr.mapIonoCorr["GPSA"].param[1]; + gps_iono.d_alpha2 = hdr.mapIonoCorr["GPSA"].param[2]; + gps_iono.d_alpha3 = hdr.mapIonoCorr["GPSA"].param[3]; + gps_iono.d_beta0 = hdr.mapIonoCorr["GPSB"].param[0]; + gps_iono.d_beta1 = hdr.mapIonoCorr["GPSB"].param[1]; + gps_iono.d_beta2 = hdr.mapIonoCorr["GPSB"].param[2]; + gps_iono.d_beta3 = hdr.mapIonoCorr["GPSB"].param[3]; + } + if (hdr.fileSys == "E: (GAL)" || hdr.fileSys == "MIXED") + { + gal_utc_model.A0_6 = hdr.mapTimeCorr["GAUT"].A0; + gal_utc_model.A1_6 = hdr.mapTimeCorr["GAUT"].A1; + gal_utc_model.Delta_tLS_6 = hdr.leapSeconds; + gal_utc_model.t0t_6 = hdr.mapTimeCorr["GAUT"].refSOW; + gal_utc_model.WNot_6 = hdr.mapTimeCorr["GAUT"].refWeek; + gal_utc_model.WN_LSF_6 = hdr.leapWeek; + gal_utc_model.DN_6 = hdr.leapDay; + gal_utc_model.Delta_tLSF_6 = hdr.leapDelta; + gal_utc_model.flag_utc_model = (hdr.mapTimeCorr["GAUT"].A0 == 0.0); + gal_iono.ai0_5 = hdr.mapIonoCorr["GAL"].param[0]; + gal_iono.ai1_5 = hdr.mapIonoCorr["GAL"].param[1]; + gal_iono.ai2_5 = hdr.mapIonoCorr["GAL"].param[2]; + gal_iono.Region1_flag_5 = false; + gal_iono.Region2_flag_5 = false; + gal_iono.Region3_flag_5 = false; + gal_iono.Region4_flag_5 = false; + gal_iono.Region5_flag_5 = false; + gal_iono.TOW_5 = 0.0; + gal_iono.WN_5 = 0.0; + } + + // Read navigation data + while (rnffs >> rne) + { + if (rne.satSys == "G" or rne.satSys.empty()) + { + // Fill GPS ephemeris object + Gps_Ephemeris eph; + eph.i_satellite_PRN = rne.PRNID; + eph.d_TOW = rne.xmitTime; + eph.d_IODE_SF2 = rne.IODE; + eph.d_IODE_SF3 = rne.IODE; + eph.d_Crs = rne.Crs; + eph.d_Delta_n = rne.dn; + eph.d_M_0 = rne.M0; + eph.d_Cuc = rne.Cuc; + eph.d_e_eccentricity = rne.ecc; + eph.d_Cus = rne.Cus; + eph.d_sqrt_A = rne.Ahalf; + eph.d_Toe = rne.Toe; + eph.d_Toc = rne.Toc; + eph.d_Cic = rne.Cic; + eph.d_OMEGA0 = rne.OMEGA0; + eph.d_Cis = rne.Cis; + eph.d_i_0 = rne.i0; + eph.d_Crc = rne.Crc; + eph.d_OMEGA = rne.w; + eph.d_OMEGA_DOT = rne.OMEGAdot; + eph.d_IDOT = rne.idot; + eph.i_code_on_L2 = rne.codeflgs; // + eph.i_GPS_week = rne.weeknum; + eph.b_L2_P_data_flag = rne.L2Pdata; + eph.i_SV_accuracy = rne.accuracy; + eph.i_SV_health = rne.health; + eph.d_TGD = rne.Tgd; + eph.d_IODC = rne.IODC; + eph.i_AODO = 0; // + eph.b_fit_interval_flag = (rne.fitint > 4) ? true : false; + eph.d_spare1 = 0.0; + eph.d_spare2 = 0.0; + eph.d_A_f0 = rne.af0; + eph.d_A_f1 = rne.af1; + eph.d_A_f2 = rne.af2; + eph.b_integrity_status_flag = false; // + eph.b_alert_flag = false; // + eph.b_antispoofing_flag = false; // + eph_map[i] = eph; + i++; + } + if (rne.satSys == "E") + { + // Fill Galileo ephemeris object + Galileo_Ephemeris eph; + eph.i_satellite_PRN = rne.PRNID; + eph.M0_1 = rne.M0; + eph.e_1 = rne.ecc; + eph.A_1 = rne.Ahalf; + eph.OMEGA_0_2 = rne.OMEGA0; + eph.i_0_2 = rne.i0; + eph.omega_2 = rne.w; + eph.OMEGA_dot_3 = rne.OMEGAdot; + eph.delta_n_3 = rne.dn; + eph.iDot_2 = rne.idot; + eph.C_uc_3 = rne.Cuc; + eph.C_us_3 = rne.Cus; + eph.C_rc_3 = rne.Crc; + eph.C_rs_3 = rne.Crs; + eph.C_ic_4 = rne.Cic; + eph.C_is_4 = rne.Cis; + eph.t0e_1 = rne.Toe; + eph.t0c_4 = rne.Toc; + eph.af0_4 = rne.af0; + eph.af1_4 = rne.af1; + eph.af2_4 = rne.af2; + eph.WN_5 = rne.weeknum; + eph_gal_map[j] = eph; + j++; + } + } + } + catch (std::exception& e) + { + std::cerr << "Error reading the RINEX file: " << e.what() << std::endl; + std::cerr << "No XML file will be created." << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + + if (i == 0 and j == 0) + { + std::cerr << "No navigation data found in the RINEX file. No XML file will be created." << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + + // Write XML ephemeris + if (i != 0) + { + std::ofstream ofs; + if (xml_filename.empty()) + { + xml_filename = "gps_ephemeris.xml"; + } + try + { + ofs.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", eph_map); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + if (j != 0) + { + std::ofstream ofs2; + xml_filename = "gal_ephemeris.xml"; + try + { + ofs2.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs2); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", eph_gal_map); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + + // Write XML UTC + if (gps_utc_model.valid) + { + std::ofstream ofs3; + xml_filename = "gps_utc_model.xml"; + try + { + ofs3.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs3); + xml << boost::serialization::make_nvp("GNSS-SDR_utc_model", gps_utc_model); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + + // Write XML iono + if (gps_iono.valid) + { + std::ofstream ofs4; + xml_filename = "gps_iono.xml"; + try + { + ofs4.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs4); + xml << boost::serialization::make_nvp("GNSS-SDR_iono_model", gps_iono); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + + if (gal_utc_model.A0_6 != 0) + { + std::ofstream ofs5; + xml_filename = "gal_utc_model.xml"; + try + { + ofs5.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs5); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", gal_utc_model); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + if (gal_iono.ai0_5 != 0) + { + std::ofstream ofs7; + xml_filename = "gal_iono.xml"; + try + { + ofs7.open(xml_filename.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs7); + xml << boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", gal_iono); + } + catch (std::exception& e) + { + std::cerr << "Problem creating the XML file " << xml_filename << ": " << e.what() << std::endl; + google::ShutDownCommandLineFlags(); + return 1; + } + std::cout << "Generated file: " << xml_filename << std::endl; + } + google::ShutDownCommandLineFlags(); + return 0; +} diff --git a/src/utils/scripts/gnss-sdr-harness.sh b/src/utils/scripts/gnss-sdr-harness.sh new file mode 100755 index 000000000..b025bb07b --- /dev/null +++ b/src/utils/scripts/gnss-sdr-harness.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# GNSS-SDR shell script that enables the remote GNSS-SDR restart telecommand +# usage: ./gnss-sdr-harness.sh ./gnss-sdr -c config_file.conf +echo $@ +$@ +while [ $? -eq 42 ] +do + echo "restarting GNSS-SDR..." + $@ +done diff --git a/src/utils/simulink/Multi Thread/README_gnss_sdr_tcp_connector_parallel_tracking.txt b/src/utils/simulink/Multi Thread/README_gnss_sdr_tcp_connector_parallel_tracking.txt index 68190d4b2..dc115ecc3 100644 --- a/src/utils/simulink/Multi Thread/README_gnss_sdr_tcp_connector_parallel_tracking.txt +++ b/src/utils/simulink/Multi Thread/README_gnss_sdr_tcp_connector_parallel_tracking.txt @@ -27,7 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_parallel_tracking_start.m b/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_parallel_tracking_start.m index dc451509a..64efa4e91 100644 --- a/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_parallel_tracking_start.m +++ b/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_parallel_tracking_start.m @@ -25,7 +25,7 @@ % * GNU General Public License for more details. % * % * You should have received a copy of the GNU General Public License -% * along with GNSS-SDR. If not, see . +% * along with GNSS-SDR. If not, see . % * % * ---------------------------------------------------------------------- % */ diff --git a/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_tracking_lib.mdl b/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_tracking_lib.mdl index 161fd561e..5e3ee7a3c 100644 --- a/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_tracking_lib.mdl +++ b/src/utils/simulink/Multi Thread/gnss_sdr_tcp_connector_tracking_lib.mdl @@ -885,7 +885,7 @@ Library { "d in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * M" "ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n" " *\n * You should have received a copy of the GNU General Public License\n * along with GNSS-SDR. If not, see" - " .\n *\n * ---------------------------------------------------------------------" + " .\n *\n * ---------------------------------------------------------------------" "----\n */" MaskDisplayString "/*! \\n * \\file gnss_sdr_tcp_connector_tracking_lib.mdl\\n * \\brief gnss_sdr_tcp_c" "onnector_tracking Simulink library model. For \\n * further information, please check the README_gnss_sdr_tcp_" @@ -899,7 +899,7 @@ Library { "GNSS-SDR is distributed in the hope that it will be useful,\\n * but WITHOUT ANY WARRANTY; without even the imp" "lied warranty of\\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\\n * GNU General Public Li" "cense for more details.\\n *\\n * You should have received a copy of the GNU General Public License\\n * alon" - "g with GNSS-SDR. If not, see .\\n *\\n * ---------------------------------------" + "g with GNSS-SDR. If not, see .\\n *\\n * ---------------------------------------" "----------------------------------\\n */" HorizontalTextAlignment "Left" LeftAlignmentValue "0.02" diff --git a/src/utils/simulink/Single Thread/README_gnss_sdr_galileo_e1_tcp_connector_tracking.txt b/src/utils/simulink/Single Thread/README_gnss_sdr_galileo_e1_tcp_connector_tracking.txt index 3da3a7972..2494050ee 100644 --- a/src/utils/simulink/Single Thread/README_gnss_sdr_galileo_e1_tcp_connector_tracking.txt +++ b/src/utils/simulink/Single Thread/README_gnss_sdr_galileo_e1_tcp_connector_tracking.txt @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/utils/simulink/Single Thread/README_gnss_sdr_tcp_connector_tracking.txt b/src/utils/simulink/Single Thread/README_gnss_sdr_tcp_connector_tracking.txt index 3283a85c0..d275ac709 100644 --- a/src/utils/simulink/Single Thread/README_gnss_sdr_tcp_connector_tracking.txt +++ b/src/utils/simulink/Single Thread/README_gnss_sdr_tcp_connector_tracking.txt @@ -26,7 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ diff --git a/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_lib.mdl b/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_lib.mdl index 99f227ef7..78c4766fb 100644 --- a/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_lib.mdl +++ b/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_lib.mdl @@ -883,7 +883,7 @@ Library { "ion.\n *\n * GNSS-SDR is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; withou" "t even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Gener" "al Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n" - " * along with GNSS-SDR. If not, see .\n *\n * ---------------------------------" + " * along with GNSS-SDR. If not, see .\n *\n * ---------------------------------" "----------------------------------------\n */" MaskDisplayString "/*! \\n * \\file gnss_sdr_galileo_e1_tcp_connector_tracking_lib.mdl\\n * \\brief gns" "s_sdr_galileo_e1_tcp_connector_tracking Simulink library model. For \\n * further information, please check th" @@ -896,7 +896,7 @@ Library { "ion) any later version.\\n *\\n * GNSS-SDR is distributed in the hope that it will be useful,\\n * but WITHOU" "T ANY WARRANTY; without even the implied warranty of\\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. " " See the\\n * GNU General Public License for more details.\\n *\\n * You should have received a copy of the G" - "NU General Public License\\n * along with GNSS-SDR. If not, see .\\n *\\n * ---" + "NU General Public License\\n * along with GNSS-SDR. If not, see .\\n *\\n * ---" "----------------------------------------------------------------------\\n */" HorizontalTextAlignment "Left" LeftAlignmentValue "0.02" diff --git a/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_start.m b/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_start.m index ee9c5d613..5eee44ee8 100644 --- a/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_start.m +++ b/src/utils/simulink/Single Thread/gnss_sdr_galileo_e1_tcp_connector_tracking_start.m @@ -24,7 +24,7 @@ % * GNU General Public License for more details. % * % * You should have received a copy of the GNU General Public License -% * along with GNSS-SDR. If not, see . +% * along with GNSS-SDR. If not, see . % * % * ---------------------------------------------------------------------- % */ diff --git a/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_lib.mdl b/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_lib.mdl index 161fd561e..5e3ee7a3c 100644 --- a/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_lib.mdl +++ b/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_lib.mdl @@ -885,7 +885,7 @@ Library { "d in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * M" "ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n" " *\n * You should have received a copy of the GNU General Public License\n * along with GNSS-SDR. If not, see" - " .\n *\n * ---------------------------------------------------------------------" + " .\n *\n * ---------------------------------------------------------------------" "----\n */" MaskDisplayString "/*! \\n * \\file gnss_sdr_tcp_connector_tracking_lib.mdl\\n * \\brief gnss_sdr_tcp_c" "onnector_tracking Simulink library model. For \\n * further information, please check the README_gnss_sdr_tcp_" @@ -899,7 +899,7 @@ Library { "GNSS-SDR is distributed in the hope that it will be useful,\\n * but WITHOUT ANY WARRANTY; without even the imp" "lied warranty of\\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\\n * GNU General Public Li" "cense for more details.\\n *\\n * You should have received a copy of the GNU General Public License\\n * alon" - "g with GNSS-SDR. If not, see .\\n *\\n * ---------------------------------------" + "g with GNSS-SDR. If not, see .\\n *\\n * ---------------------------------------" "----------------------------------\\n */" HorizontalTextAlignment "Left" LeftAlignmentValue "0.02" diff --git a/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_start.m b/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_start.m index 613151bf1..1fcef0faf 100644 --- a/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_start.m +++ b/src/utils/simulink/Single Thread/gnss_sdr_tcp_connector_tracking_start.m @@ -24,7 +24,7 @@ % * GNU General Public License for more details. % * % * You should have received a copy of the GNU General Public License -% * along with GNSS-SDR. If not, see . +% * along with GNSS-SDR. If not, see . % * % * ---------------------------------------------------------------------- % */